Initial xentral_oss_20.3.c9ffacf
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge;
|
||||
|
||||
use ApplicationCore;
|
||||
use Xentral\Core\DependencyInjection\ContainerInterface;
|
||||
use Xentral\Modules\CopperSurcharge\Service\DocumentGateway;
|
||||
use Xentral\Modules\CopperSurcharge\Service\PurchasePriceGateway;
|
||||
use Xentral\Modules\CopperSurcharge\Service\DocumentService;
|
||||
use Xentral\Modules\CopperSurcharge\Service\RawMaterialGateway;
|
||||
use Xentral\Modules\CopperSurcharge\Wrapper\CompanyDataWrapper;
|
||||
use Xentral\Modules\CopperSurcharge\Wrapper\DocumentPositionWrapper;
|
||||
|
||||
|
||||
final class Bootstrap
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function registerServices(): array
|
||||
{
|
||||
return [
|
||||
'CopperSurchargeCalculatorFactory' => 'onInitCopperSurchargeCalculatorFactory',
|
||||
'CopperSurchargeService' => 'onInitCopperSurchargeService',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return CopperSurchargeCalculatorFactory
|
||||
*/
|
||||
public static function onInitCopperSurchargeCalculatorFactory(ContainerInterface $container
|
||||
): CopperSurchargeCalculatorFactory {
|
||||
return new CopperSurchargeCalculatorFactory(
|
||||
self::onInitPurchasePriceGateway($container),
|
||||
self::onInitRawMaterialGateway($container),
|
||||
self::onInitDocumentPositionWrapper($container),
|
||||
self::onInitDocumentService($container),
|
||||
self::onInitDocumentGateway($container)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return CopperSurchargeService
|
||||
*/
|
||||
public static function onInitCopperSurchargeService(ContainerInterface $container
|
||||
): CopperSurchargeService {
|
||||
return new CopperSurchargeService(
|
||||
$container->get('SystemConfigModule'),
|
||||
self::onInitCompanyDataWrapper($container)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return PurchasePriceGateway
|
||||
*/
|
||||
private static function onInitPurchasePriceGateway(ContainerInterface $container
|
||||
): PurchasePriceGateway {
|
||||
return new PurchasePriceGateway(
|
||||
$container->get('Database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return RawMaterialGateway
|
||||
*/
|
||||
private static function onInitRawMaterialGateway(ContainerInterface $container
|
||||
): RawMaterialGateway {
|
||||
return new RawMaterialGateway(
|
||||
$container->get('Database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return DocumentPositionWrapper
|
||||
*/
|
||||
private static function onInitDocumentPositionWrapper(ContainerInterface $container
|
||||
): DocumentPositionWrapper {
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new DocumentPositionWrapper($app->erp, $container->get('Database'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return CompanyDataWrapper
|
||||
*/
|
||||
private static function onInitCompanyDataWrapper(ContainerInterface $container
|
||||
): CompanyDataWrapper {
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new CompanyDataWrapper($app->erp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return DocumentService
|
||||
*/
|
||||
private static function onInitDocumentService(ContainerInterface $container): DocumentService
|
||||
{
|
||||
return new DocumentService($container->get('Database'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return DocumentGateway
|
||||
*/
|
||||
private static function onInitDocumentGateway(ContainerInterface $container): DocumentGateway
|
||||
{
|
||||
return new DocumentGateway($container->get('Database'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge;
|
||||
|
||||
use Xentral\Modules\CopperSurcharge\Data\CopperSurchargeData;
|
||||
use Xentral\Modules\CopperSurcharge\Service\CopperSurchargeCalculator;
|
||||
use Xentral\Modules\CopperSurcharge\Service\DocumentGateway;
|
||||
use Xentral\Modules\CopperSurcharge\Service\PurchasePriceGateway;
|
||||
use Xentral\Modules\CopperSurcharge\Service\DocumentService;
|
||||
use Xentral\Modules\CopperSurcharge\Service\RawMaterialGateway;
|
||||
use Xentral\Modules\CopperSurcharge\Wrapper\DocumentPositionWrapper;
|
||||
use Xentral\Modules\CopperSurcharge\Wrapper\DocumentPositionWrapperInterface;
|
||||
|
||||
final class CopperSurchargeCalculatorFactory
|
||||
{
|
||||
|
||||
/** @var RawMaterialGateway $rawMaterialGateway */
|
||||
private $rawMaterialGateway;
|
||||
|
||||
/** @var PurchasePriceGateway $purchasePriceGateway */
|
||||
private $purchasePriceGateway;
|
||||
|
||||
/** @var DocumentPositionWrapper $documentPositionWrapper */
|
||||
private $documentPositionWrapper;
|
||||
|
||||
/** @var DocumentService $documentPositionService */
|
||||
private $documentService;
|
||||
|
||||
/** @var DocumentGateway $documentGateway */
|
||||
private $documentGateway;
|
||||
|
||||
/**
|
||||
* @param PurchasePriceGateway $purchasePriceGateway
|
||||
* @param RawMaterialGateway $rawMaterialGateway
|
||||
* @param DocumentPositionWrapperInterface $documentPositionWrapper
|
||||
* @param DocumentService $documentService
|
||||
* @param DocumentGateway $documentGateway
|
||||
*/
|
||||
public function __construct(
|
||||
PurchasePriceGateway $purchasePriceGateway,
|
||||
RawMaterialGateway $rawMaterialGateway,
|
||||
DocumentPositionWrapperInterface $documentPositionWrapper,
|
||||
DocumentService $documentService,
|
||||
DocumentGateway $documentGateway
|
||||
) {
|
||||
$this->purchasePriceGateway = $purchasePriceGateway;
|
||||
$this->rawMaterialGateway = $rawMaterialGateway;
|
||||
$this->documentPositionWrapper = $documentPositionWrapper;
|
||||
$this->documentService = $documentService;
|
||||
$this->documentGateway = $documentGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CopperSurchargeData $configData
|
||||
*
|
||||
* @return CopperSurchargeCalculator
|
||||
*/
|
||||
public function createCopperSurchargeCalculator(CopperSurchargeData $configData): CopperSurchargeCalculator
|
||||
{
|
||||
return new CopperSurchargeCalculator(
|
||||
$this->purchasePriceGateway,
|
||||
$this->rawMaterialGateway,
|
||||
$this->documentPositionWrapper,
|
||||
$this->documentService,
|
||||
$this->documentGateway,
|
||||
$configData
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge;
|
||||
|
||||
use Xentral\Modules\CopperSurcharge\Data\CopperSurchargeData;
|
||||
use Xentral\Modules\CopperSurcharge\Wrapper\CompanyDataWrapper;
|
||||
use Xentral\Modules\SystemConfig\Exception\ConfigurationKeyNotFoundException;
|
||||
use Xentral\Modules\SystemConfig\Exception\InvalidArgumentException;
|
||||
use Xentral\Modules\SystemConfig\Exception\ValueTooLargeException;
|
||||
use Xentral\Modules\SystemConfig\SystemConfigModule;
|
||||
|
||||
final class CopperSurchargeService
|
||||
{
|
||||
|
||||
/** @var string */
|
||||
private const NAMESPACE = 'coppersurcharge';
|
||||
|
||||
/** @var SystemConfigModule $systemConfig */
|
||||
private $systemConfig;
|
||||
|
||||
/** @var CompanyDataWrapper $companyDataWrapper */
|
||||
private $companyDataWrapper;
|
||||
|
||||
/**
|
||||
* @param SystemConfigModule $systemConfig
|
||||
* @param CompanyDataWrapper $companyDataWrapper
|
||||
*/
|
||||
public function __construct(SystemConfigModule $systemConfig, CompanyDataWrapper $companyDataWrapper)
|
||||
{
|
||||
$this->systemConfig = $systemConfig;
|
||||
$this->companyDataWrapper = $companyDataWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CopperSurchargeData|null
|
||||
*/
|
||||
public function findConfigurationData(): ?CopperSurchargeData
|
||||
{
|
||||
try {
|
||||
$articleId = (int)$this->systemConfig->getValue(
|
||||
self::NAMESPACE,
|
||||
'articleid'
|
||||
);
|
||||
$surchargePositionType = (int)$this->systemConfig->getValue(
|
||||
self::NAMESPACE,
|
||||
'surchargepositiontype'
|
||||
);
|
||||
$surchargeDocumentConversion = (int)$this->systemConfig->getValue(
|
||||
self::NAMESPACE,
|
||||
'surchargedocumentconversion'
|
||||
);
|
||||
$surchargeInvoice = (int)$this->systemConfig->getValue(
|
||||
self::NAMESPACE,
|
||||
'surchargeinvoice'
|
||||
);
|
||||
$surchargeDeliveryCosts = (float)$this->systemConfig->getValue(
|
||||
self::NAMESPACE,
|
||||
'surchargedeliverycosts'
|
||||
);
|
||||
$surchargeCopperBase = (string)$this->systemConfig->getValue(
|
||||
self::NAMESPACE,
|
||||
'surchargecopperbase'
|
||||
);
|
||||
$surchargeCopperBaseStandard = (float)$this->systemConfig->getValue(
|
||||
self::NAMESPACE,
|
||||
'surchargecopperbasestandard'
|
||||
);
|
||||
$copperNumberOption = (string)$this->systemConfig->getValue(
|
||||
self::NAMESPACE,
|
||||
'coppernumberoption'
|
||||
);
|
||||
$surchargeMaintenanceType = (int)$this->systemConfig->getValue(
|
||||
self::NAMESPACE,
|
||||
'surchargemaintenancetype'
|
||||
);
|
||||
} catch (ConfigurationKeyNotFoundException $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new CopperSurchargeData(
|
||||
$articleId,
|
||||
$surchargePositionType,
|
||||
$surchargeDocumentConversion,
|
||||
$surchargeInvoice,
|
||||
$surchargeDeliveryCosts,
|
||||
$surchargeCopperBase,
|
||||
$surchargeCopperBaseStandard,
|
||||
$surchargeMaintenanceType,
|
||||
$copperNumberOption
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CopperSurchargeData $copperSurchargeData
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws ValueTooLargeException
|
||||
*/
|
||||
public function setConfigurationData(CopperSurchargeData $copperSurchargeData)
|
||||
{
|
||||
$this->systemConfig->setValue(
|
||||
self::NAMESPACE,
|
||||
'articleid',
|
||||
(string)$copperSurchargeData->getCopperSurchargeArticleId()
|
||||
);
|
||||
$this->systemConfig->setValue(
|
||||
self::NAMESPACE,
|
||||
'surchargepositiontype',
|
||||
(string)$copperSurchargeData->getSurchargePositionType()
|
||||
);
|
||||
$this->systemConfig->setValue(
|
||||
self::NAMESPACE,
|
||||
'surchargedocumentconversion',
|
||||
(string)$copperSurchargeData->getSurchargeDocumentConversion()
|
||||
);
|
||||
$this->systemConfig->setValue(
|
||||
self::NAMESPACE,
|
||||
'surchargeinvoice',
|
||||
(string)$copperSurchargeData->getSurchargeInvoice()
|
||||
);
|
||||
$this->systemConfig->setValue(
|
||||
self::NAMESPACE,
|
||||
'surchargedeliverycosts',
|
||||
(string)$copperSurchargeData->getSurchargeDeliveryCosts()
|
||||
);
|
||||
$this->systemConfig->setValue(
|
||||
self::NAMESPACE,
|
||||
'surchargecopperbase',
|
||||
(string)$copperSurchargeData->getSurchargeCopperBase()
|
||||
);
|
||||
$this->systemConfig->setValue(
|
||||
self::NAMESPACE,
|
||||
'surchargecopperbasestandard',
|
||||
(string)$copperSurchargeData->getSurchargeCopperBaseStandard()
|
||||
);
|
||||
$this->systemConfig->setValue(
|
||||
self::NAMESPACE,
|
||||
'coppernumberoption',
|
||||
$copperSurchargeData->getCopperNumberOption()
|
||||
);
|
||||
$this->systemConfig->setValue(
|
||||
self::NAMESPACE,
|
||||
'surchargemaintenancetype',
|
||||
(string)$copperSurchargeData->getSurchargeMaintenanceType()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function findCompanyData(string $field): string
|
||||
{
|
||||
return $this->companyDataWrapper->getCompanyData($field);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Data;
|
||||
|
||||
use Xentral\Modules\CopperSurcharge\Exception\ValidationFailedException;
|
||||
|
||||
final class CopperSurchargeData
|
||||
{
|
||||
/**
|
||||
* a surcharge position gets added to every copper article
|
||||
*/
|
||||
public const POSITION_TYPE_ALWAYS = 0;
|
||||
/**
|
||||
* only one surcharge position gets added for all copper articles
|
||||
*/
|
||||
public const POSITION_TYPE_ONETIME = 1;
|
||||
|
||||
/**
|
||||
* a surcharge position gets added to all position groups
|
||||
*/
|
||||
public const POSITION_TYPE_GROUP = 2;
|
||||
|
||||
/**
|
||||
* calculation base is the date from the offer of the order
|
||||
*/
|
||||
public const DOCUMENT_CONVERSION_FROM_OFFER = 0;
|
||||
//public const DOCUMENT_CONVERSION_CREATE_NEW = 1;
|
||||
|
||||
/**
|
||||
* calculation base is the date from the order of the invoice
|
||||
*/
|
||||
public const INVOICE_CREATE_POS_BY_ORDER_DATE = 0;
|
||||
|
||||
/**
|
||||
* calculation base is the delivery date of the invoice
|
||||
*/
|
||||
public const INVOICE_CREATE_POS_BY_DELIVERY_DATE = 1;
|
||||
|
||||
/**
|
||||
* calculation base is the date from the invoice
|
||||
*/
|
||||
public const INVOICE_CREATE_POS_BY_INVOICE_DATE = 2;
|
||||
|
||||
/**
|
||||
* calculation base is the date from the offer of the invoice
|
||||
*/
|
||||
public const INVOICE_CREATE_POS_BY_OFFER_DATE = 3;
|
||||
|
||||
/**
|
||||
* data gets managed in the app raw materials
|
||||
*/
|
||||
public const SURCHARGE_MAINTENANCE_TYPE_APP = 0;
|
||||
|
||||
/**
|
||||
* data gets managed in the additional fields of the copper article
|
||||
*/
|
||||
public const SURCHARGE_MAINTENANCE_TYPE_ARTICLE = 1;
|
||||
|
||||
/** @var int $copperSurchargeArticleId */
|
||||
private $copperSurchargeArticleId;
|
||||
|
||||
/** @var int $surchargePositionType */
|
||||
private $surchargePositionType;
|
||||
|
||||
/** @var int $surchargeDocumentConversion */
|
||||
private $surchargeDocumentConversion;
|
||||
|
||||
/** @var int $surchargeInvoice */
|
||||
private $surchargeInvoice;
|
||||
|
||||
/** @var float $surchargeDeliveryCosts */
|
||||
private $surchargeDeliveryCosts;
|
||||
|
||||
/** @var string $surchargeCopperBase */
|
||||
private $surchargeCopperBase;
|
||||
|
||||
/** @var float $surchargeCopperBaseStandard */
|
||||
private $surchargeCopperBaseStandard;
|
||||
|
||||
/** @var int $copperNumberOption */
|
||||
private $copperNumberOption;
|
||||
|
||||
/** @var int $surchargeMaintenaceType */
|
||||
private $surchargeMaintenanceType;
|
||||
|
||||
/**
|
||||
* @param int $articleId
|
||||
* @param int $surchargePositionType
|
||||
* @param int $surchargeDocumentConversion
|
||||
* @param int $surchargeInvoice
|
||||
* @param float $surchargeDeliveryCosts
|
||||
* @param string $surchargeCopperBase
|
||||
* @param float $surchargeCopperBaseStandard
|
||||
* @param int $surchargeMaintenanceType
|
||||
* @param string $copperNumberOption
|
||||
*
|
||||
*/
|
||||
public function __construct(
|
||||
int $articleId,
|
||||
int $surchargePositionType,
|
||||
int $surchargeDocumentConversion,
|
||||
int $surchargeInvoice,
|
||||
float $surchargeDeliveryCosts,
|
||||
string $surchargeCopperBase,
|
||||
float $surchargeCopperBaseStandard,
|
||||
int $surchargeMaintenanceType,
|
||||
string $copperNumberOption
|
||||
) {
|
||||
$this->validate(
|
||||
$articleId,
|
||||
$surchargeDeliveryCosts,
|
||||
$surchargeCopperBaseStandard,
|
||||
$surchargeMaintenanceType,
|
||||
$copperNumberOption
|
||||
);
|
||||
|
||||
$this->copperSurchargeArticleId = $articleId;
|
||||
$this->surchargePositionType = $surchargePositionType;
|
||||
$this->surchargeDocumentConversion = $surchargeDocumentConversion;
|
||||
$this->surchargeInvoice = $surchargeInvoice;
|
||||
$this->surchargeDeliveryCosts = $surchargeDeliveryCosts;
|
||||
$this->surchargeCopperBase = $surchargeCopperBase;
|
||||
$this->surchargeCopperBaseStandard = $surchargeCopperBaseStandard;
|
||||
$this->copperNumberOption = $copperNumberOption;
|
||||
$this->surchargeMaintenanceType = $surchargeMaintenanceType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $articleId
|
||||
* @param float $surchargeDeliveryCosts
|
||||
* @param float $surchargeCopperBaseStandard
|
||||
*
|
||||
* @param int $surchargeMaintenanceType
|
||||
* @param string $copperNumberOption
|
||||
*/
|
||||
private function validate(
|
||||
int $articleId,
|
||||
float $surchargeDeliveryCosts,
|
||||
float $surchargeCopperBaseStandard,
|
||||
int $surchargeMaintenanceType,
|
||||
string $copperNumberOption
|
||||
) {
|
||||
if (empty($articleId)) {
|
||||
throw new ValidationFailedException('copper surcharge article is missing');
|
||||
}
|
||||
|
||||
if (empty($surchargeDeliveryCosts)) {
|
||||
throw new ValidationFailedException('surcharge delivery costs are missing');
|
||||
}
|
||||
|
||||
if (empty($surchargeCopperBaseStandard)) {
|
||||
throw new ValidationFailedException('surcharge copper base standard is missing');
|
||||
}
|
||||
|
||||
if ($surchargeMaintenanceType === self::SURCHARGE_MAINTENANCE_TYPE_ARTICLE && empty($copperNumberOption)) {
|
||||
throw new ValidationFailedException('copper number option is missing');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int article id of the surcharge article
|
||||
*/
|
||||
public function getCopperSurchargeArticleId(): int
|
||||
{
|
||||
return $this->copperSurchargeArticleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 0 = add always a surcharge position to every copper article,
|
||||
* 1 = add only one surcharge position for all copper articles,
|
||||
* 2 = add a surcharge position in every position group
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSurchargePositionType(): int
|
||||
{
|
||||
return $this->surchargePositionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* decides which date is the base if a surcharge positions is added to an order
|
||||
* 0 = date of offer (fallback current date)
|
||||
* 1 = date of the order
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSurchargeDocumentConversion(): int
|
||||
{
|
||||
return $this->surchargeDocumentConversion;
|
||||
}
|
||||
|
||||
/**
|
||||
* decides which date is the base if a surcharge positions is added to an invoice
|
||||
* 0 = from the order (fallback current date)
|
||||
* 1 = delivery date (fallback current date)
|
||||
* 2 = from the invoice
|
||||
* 3 = from the offer (fallback current date)
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSurchargeInvoice(): int
|
||||
{
|
||||
return $this->surchargeInvoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* part of the calculation, default 1, in percent
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getSurchargeDeliveryCosts(): float
|
||||
{
|
||||
return $this->surchargeDeliveryCosts;
|
||||
}
|
||||
|
||||
/**
|
||||
* can be used instead of surchargeCopperBaseStandard for specific articles, EUR/100kg
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSurchargeCopperBase(): string
|
||||
{
|
||||
return $this->surchargeCopperBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* part of the the calculation, default 150, EUR/100kg
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getSurchargeCopperBaseStandard(): float
|
||||
{
|
||||
return $this->surchargeCopperBaseStandard;
|
||||
}
|
||||
|
||||
/**
|
||||
* describes which additional field in the article contains the weight,
|
||||
* only useful with surchargeMaintenanceType = 1
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCopperNumberOption(): string
|
||||
{
|
||||
return $this->copperNumberOption;
|
||||
}
|
||||
|
||||
/**
|
||||
* choice how copper articles should hold their necessary infos
|
||||
* 0 = with the app 'raw materials'
|
||||
* 1 = with additional article fields
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSurchargeMaintenanceType(): int
|
||||
{
|
||||
return $this->surchargeMaintenanceType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Data;
|
||||
|
||||
final class DocumentPositionData
|
||||
{
|
||||
|
||||
/** @var int $positionId */
|
||||
private $positionId;
|
||||
|
||||
/** @var int $articleId */
|
||||
private $articleId;
|
||||
|
||||
/** @var string $currency */
|
||||
private $currency;
|
||||
|
||||
/**
|
||||
* @param int $positionId
|
||||
* @param int $articleId
|
||||
* @param string $currency
|
||||
*/
|
||||
public function __construct(
|
||||
int $positionId,
|
||||
int $articleId,
|
||||
string $currency
|
||||
) {
|
||||
$this->positionId = $positionId;
|
||||
$this->articleId = $articleId;
|
||||
$this->currency = $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getPositionId(): int
|
||||
{
|
||||
return $this->positionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getArticleId(): int
|
||||
{
|
||||
return $this->articleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCurrency(): string
|
||||
{
|
||||
return $this->currency;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Exception;
|
||||
|
||||
use Xentral\Core\Exception\ModuleExceptionInterface;
|
||||
|
||||
interface CopperSurchargeExceptionInterface extends ModuleExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
final class EmptyResultException extends RuntimeException implements CopperSurchargeExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
final class InvalidDateFormatException extends InvalidArgumentException implements CopperSurchargeExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
final class ValidationFailedException extends InvalidArgumentException implements CopperSurchargeExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,933 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Service;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Xentral\Modules\CopperSurcharge\Data\CopperSurchargeData;
|
||||
use Xentral\Modules\CopperSurcharge\Data\DocumentPositionData;
|
||||
use Xentral\Modules\CopperSurcharge\Exception\InvalidDateFormatException;
|
||||
use Xentral\Modules\CopperSurcharge\Wrapper\DocumentPositionWrapper;
|
||||
use Xentral\Modules\CopperSurcharge\Wrapper\DocumentPositionWrapperInterface;
|
||||
|
||||
final class CopperSurchargeCalculator
|
||||
{
|
||||
/** @var RawMaterialGateway $rawMaterialGateway */
|
||||
private $rawMaterialGateway;
|
||||
|
||||
/** @var PurchasePriceGateway $purchasePriceGateway */
|
||||
private $purchasePriceGateway;
|
||||
|
||||
/** @var DocumentPositionWrapper $documentPositionWrapper */
|
||||
private $documentPositionWrapper;
|
||||
|
||||
/** @var CopperSurchargeData $config */
|
||||
private $config;
|
||||
|
||||
/** @var DocumentService $documentService */
|
||||
private $documentService;
|
||||
|
||||
/** @var DocumentGateway $documentGateway */
|
||||
private $documentGateway;
|
||||
|
||||
/**
|
||||
* @param PurchasePriceGateway $purchasePriceGateway
|
||||
* @param RawMaterialGateway $rawMaterialGateway
|
||||
* @param DocumentPositionWrapperInterface $documentPositionWrapper
|
||||
* @param DocumentService $documentService
|
||||
* @param DocumentGateway $documentGateway
|
||||
* @param CopperSurchargeData $copperSurchargeConfig
|
||||
*/
|
||||
public function __construct(
|
||||
PurchasePriceGateway $purchasePriceGateway,
|
||||
RawMaterialGateway $rawMaterialGateway,
|
||||
DocumentPositionWrapperInterface $documentPositionWrapper,
|
||||
DocumentService $documentService,
|
||||
DocumentGateway $documentGateway,
|
||||
CopperSurchargeData $copperSurchargeConfig
|
||||
) {
|
||||
$this->purchasePriceGateway = $purchasePriceGateway;
|
||||
$this->rawMaterialGateway = $rawMaterialGateway;
|
||||
$this->documentPositionWrapper = $documentPositionWrapper;
|
||||
$this->documentService = $documentService;
|
||||
$this->config = $copperSurchargeConfig;
|
||||
$this->documentGateway = $documentGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
* @param array|DocumentPositionData[] $possibleCopperPositions
|
||||
* @param array $copperPositionsInPartsList
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handleCopperSurchargePositions(
|
||||
string $docType,
|
||||
int $docId,
|
||||
array $possibleCopperPositions,
|
||||
array $copperPositionsInPartsList
|
||||
): int {
|
||||
$calcDate = $this->evaluateCalcDate($docType, $docId);
|
||||
|
||||
if ($this->config->getSurchargePositionType() === CopperSurchargeData::POSITION_TYPE_ALWAYS) {
|
||||
$this->createManyPositions(
|
||||
$docType,
|
||||
$docId,
|
||||
$possibleCopperPositions,
|
||||
$copperPositionsInPartsList,
|
||||
$calcDate
|
||||
);
|
||||
|
||||
return 0;
|
||||
} elseif ($this->config->getSurchargePositionType() === CopperSurchargeData::POSITION_TYPE_ONETIME) {
|
||||
$this->createSinglePosition(
|
||||
$docType,
|
||||
$docId,
|
||||
$possibleCopperPositions,
|
||||
$copperPositionsInPartsList,
|
||||
$calcDate
|
||||
);
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
$this->createGroupPositions($docType, $docId, $copperPositionsInPartsList, $calcDate);
|
||||
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Because there is no connection between positions,
|
||||
* all surcharge positions get deleted and recreated in the next step
|
||||
*
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
*/
|
||||
public function resetDocument(string $docType, int $docId): void
|
||||
{
|
||||
$this->resetBetweenPositions($docId, $docType, $this->config->getCopperSurchargeArticleId());
|
||||
$this->documentService->deleteCopperSurchargePositions(
|
||||
$docType,
|
||||
$docId,
|
||||
$this->config->getCopperSurchargeArticleId()
|
||||
);
|
||||
$this->documentService->updatePositionSorts($docType, $docId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
* @param array|DocumentPositionData[] $copperPositions
|
||||
* @param array $copperPositionsInPartsList
|
||||
* @param DateTimeInterface $calcDate
|
||||
*
|
||||
*/
|
||||
private function createManyPositions(
|
||||
string $docType,
|
||||
int $docId,
|
||||
array $copperPositions,
|
||||
array $copperPositionsInPartsList,
|
||||
DateTimeInterface $calcDate
|
||||
): void {
|
||||
foreach ($copperPositions as $position) {
|
||||
$amount = $this->calcAmount($docType, $position->getPositionId(), $position->getArticleId());
|
||||
$copperBase = $this->getCopperBase($position->getArticleId());
|
||||
|
||||
$price = $this->calculateCopperSurchargePrice(
|
||||
$copperBase,
|
||||
$amount,
|
||||
$calcDate
|
||||
);
|
||||
|
||||
$newPosId = $this->addCopperSurchargePosition(
|
||||
$docType,
|
||||
$docId,
|
||||
$price,
|
||||
$amount,
|
||||
$copperBase,
|
||||
$position->getCurrency(),
|
||||
$calcDate
|
||||
);
|
||||
|
||||
$this->documentService->updatePositionSort($docType, $docId, $position->getPositionId(), $newPosId);
|
||||
}
|
||||
|
||||
if (empty($copperPositionsInPartsList)) {
|
||||
return;
|
||||
}
|
||||
foreach ($copperPositionsInPartsList as $partListPosition) {
|
||||
$partListData = $this->evaluateSurchargeDataForPartList(
|
||||
$partListPosition['article_id'],
|
||||
$partListPosition['pos_id'],
|
||||
$calcDate,
|
||||
$docType,
|
||||
$partListPosition['amount']
|
||||
);
|
||||
|
||||
$newPosId = $this->addCopperSurchargePosition(
|
||||
$docType,
|
||||
$docId,
|
||||
$partListData['price'],
|
||||
$partListData['amount'],
|
||||
$partListData['copper_base'],
|
||||
$partListPosition['currency'],
|
||||
$calcDate
|
||||
);
|
||||
|
||||
$this->documentService->updatePositionSort($docType, $docId, $partListData['position_id'], $newPosId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $partListHeadId
|
||||
* @param int $positionId
|
||||
* @param DateTimeInterface $calcDate
|
||||
* @param string $docType
|
||||
* @param float $partListPositionAmount
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function evaluateSurchargeDataForPartList(
|
||||
int $partListHeadId,
|
||||
int $positionId,
|
||||
DateTimeInterface $calcDate,
|
||||
string $docType,
|
||||
float $partListPositionAmount
|
||||
): array {
|
||||
$copperArticles =
|
||||
$this->getCopperArticlesFromPartList(
|
||||
$partListHeadId,
|
||||
$this->config->getSurchargeMaintenanceType(),
|
||||
$this->config->getCopperNumberOption(),
|
||||
$this->config->getCopperSurchargeArticleId()
|
||||
);
|
||||
$amount = 0;
|
||||
$price = 0.0;
|
||||
$copperBase = 0.0;
|
||||
|
||||
foreach ($copperArticles as $copperArticle) {
|
||||
$amount += $copperArticle['amount'];
|
||||
$copperBase = $this->getCopperBase($copperArticle['article_id']);
|
||||
|
||||
$price += $this->calculateCopperSurchargePrice(
|
||||
$copperBase,
|
||||
$amount,
|
||||
$calcDate
|
||||
);
|
||||
}
|
||||
|
||||
return [
|
||||
'amount' => $amount * $partListPositionAmount,
|
||||
'price' => $price * $partListPositionAmount,
|
||||
'copper_base' => $copperBase,
|
||||
'position_id' => $this->documentGateway->evaluatePartListLastPositionId($docType, $positionId),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
* @param float $price
|
||||
* @param float $amount
|
||||
* @param float $copperBase
|
||||
* @param $currency
|
||||
* @param DateTimeInterface $calcDate
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function addCopperSurchargePosition(
|
||||
string $docType,
|
||||
int $docId,
|
||||
float $price,
|
||||
float $amount,
|
||||
float $copperBase,
|
||||
$currency,
|
||||
DateTimeInterface $calcDate
|
||||
): int {
|
||||
$copperSurchargeArticleId = $this->config->getCopperSurchargeArticleId();
|
||||
$articleData = $this->documentGateway->getArticleData($copperSurchargeArticleId);
|
||||
$description = $this->findCopperSurchargeArticleDescription(
|
||||
$amount,
|
||||
$copperBase,
|
||||
$price,
|
||||
$articleData,
|
||||
$calcDate
|
||||
);
|
||||
|
||||
return $this->documentPositionWrapper->addPositionManuallyWithPrice(
|
||||
$docType,
|
||||
$docId,
|
||||
$copperSurchargeArticleId,
|
||||
$articleData,
|
||||
1,
|
||||
$price,
|
||||
$currency,
|
||||
$description
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $amount
|
||||
* @param float $copperBase
|
||||
* @param float $price
|
||||
* @param array $articleData
|
||||
* @param DateTimeInterface $calcDate
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function findCopperSurchargeArticleDescription(
|
||||
float $amount,
|
||||
float $copperBase,
|
||||
float $price,
|
||||
array $articleData,
|
||||
DateTimeInterface $calcDate
|
||||
): string {
|
||||
$description = $articleData['description'];
|
||||
|
||||
$delPrice = $this->purchasePriceGateway->getDelCopperPriceByDate(
|
||||
$calcDate,
|
||||
$this->config->getCopperSurchargeArticleId()
|
||||
);
|
||||
|
||||
$price = number_format($price, 2, ",", ".");
|
||||
$delPrice = number_format($delPrice, 2, ",", ".");
|
||||
$copperBase = number_format($copperBase, 2, ",", ".");
|
||||
$amount = str_replace('.', ',', $amount);
|
||||
|
||||
$description = str_replace('{NETPRICE}', $price, $description);
|
||||
$description = str_replace('{ARTIKELNUMMER}', $articleData['number'], $description);
|
||||
$description = str_replace('{ARTIKELNAME}', $articleData['name_de'], $description);
|
||||
$description = str_replace('{COPPERBASIS}', $copperBase, $description);
|
||||
$description = str_replace('{COPPERNUMBER}', $amount, $description);
|
||||
$description = str_replace('{DELVALUE}', $delPrice, $description);
|
||||
|
||||
return $description;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
* @param array|DocumentPositionData[] $copperPositions
|
||||
* @param array $copperPositionsInPartsList
|
||||
* @param DateTimeInterface $calcDate
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function createSinglePosition(
|
||||
string $docType,
|
||||
int $docId,
|
||||
array $copperPositions,
|
||||
array $copperPositionsInPartsList,
|
||||
DateTimeInterface $calcDate
|
||||
): int {
|
||||
$price = 0.0;
|
||||
$totalAmount = 0.0;
|
||||
$currency = 'EUR';
|
||||
$copperBase = 0.0;
|
||||
foreach ($copperPositions as $position) {
|
||||
$currency = $position->getCurrency();
|
||||
$amount = $this->calcAmount($docType, $position->getPositionId(), $position->getArticleId());
|
||||
$totalAmount += $amount;
|
||||
$copperBase = $this->getCopperBase($position->getArticleId());
|
||||
$price += $this->calculateCopperSurchargePrice(
|
||||
$copperBase,
|
||||
$amount,
|
||||
$calcDate
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($copperPositionsInPartsList)) {
|
||||
foreach ($copperPositionsInPartsList as $position) {
|
||||
$partListData = $this->evaluateSurchargeDataForPartList(
|
||||
$position['article_id'],
|
||||
$position['pos_id'],
|
||||
$calcDate,
|
||||
$docType,
|
||||
$position['amount']
|
||||
);
|
||||
|
||||
$totalAmount += $partListData['amount'];
|
||||
$price += $partListData['price'];
|
||||
$copperBase = $partListData['copper_base'];
|
||||
}
|
||||
}
|
||||
|
||||
$newPosId = 0;
|
||||
if ($price > 0) {
|
||||
$newPosId = $this->addCopperSurchargePosition(
|
||||
$docType,
|
||||
$docId,
|
||||
$price,
|
||||
$totalAmount,
|
||||
$copperBase,
|
||||
$currency,
|
||||
$calcDate
|
||||
);
|
||||
}
|
||||
|
||||
return $newPosId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
* @param array $copperPositionsInPartsList
|
||||
* @param DateTimeInterface $calcDate
|
||||
*/
|
||||
private function createGroupPositions(
|
||||
string $docType,
|
||||
int $docId,
|
||||
array $copperPositionsInPartsList,
|
||||
DateTimeInterface $calcDate
|
||||
): void {
|
||||
if ($this->config->getSurchargeMaintenanceType() === CopperSurchargeData::SURCHARGE_MAINTENANCE_TYPE_APP) {
|
||||
$positions = $this->rawMaterialGateway->findAllPositionsForGrouped(
|
||||
$docType,
|
||||
$docId,
|
||||
$this->config->getCopperSurchargeArticleId()
|
||||
);
|
||||
} else {
|
||||
$positions = $this->documentGateway->findAllPositionsForGrouped(
|
||||
$docType,
|
||||
$docId,
|
||||
$this->config->getCopperNumberOption()
|
||||
);
|
||||
}
|
||||
|
||||
$price = 0.0;
|
||||
$totalAmount = 0.0;
|
||||
$currency = 'EUR';
|
||||
$prev = null;
|
||||
$copperBase = 0.0;
|
||||
$lastSort = 0;
|
||||
|
||||
foreach ($positions as $key => $position) {
|
||||
if ((bool)$position['is_copper']) {
|
||||
$amount = $this->calcAmount($docType, (int)$position['pos_id'], (int)$position['article_id']);
|
||||
$copperBase = $this->getCopperBase($position['article_id']);
|
||||
$price += $this->calculateCopperSurchargePrice(
|
||||
$copperBase,
|
||||
$amount,
|
||||
$calcDate
|
||||
);
|
||||
$currency = $position['currency'];
|
||||
$totalAmount += $amount;
|
||||
}
|
||||
|
||||
if ($position['between_type'] === 'gruppe') {
|
||||
if (!empty($copperPositionsInPartsList)) {
|
||||
$partListElements = $this->getElementsFromPartListBetweenSorts(
|
||||
$copperPositionsInPartsList,
|
||||
$lastSort,
|
||||
$position['sort']
|
||||
);
|
||||
|
||||
foreach ($partListElements as $partListElement) {
|
||||
$partListKey = $partListElement['part_list_key'];
|
||||
$partListData = $this->evaluateSurchargeDataForPartList(
|
||||
$partListElement['article_id'],
|
||||
$position['pos_id'],
|
||||
$calcDate,
|
||||
$docType,
|
||||
$partListElement['amount']
|
||||
);
|
||||
$totalAmount += $partListData['amount'];
|
||||
$price += $partListData['price'];
|
||||
$copperBase = $partListData['copper_base'];
|
||||
unset($copperPositionsInPartsList[$partListKey]);
|
||||
}
|
||||
}
|
||||
if ($price > 0.0) {
|
||||
$newPosId = $this->addCopperSurchargePosition(
|
||||
$docType,
|
||||
$docId,
|
||||
$price,
|
||||
$totalAmount,
|
||||
$copperBase,
|
||||
$currency,
|
||||
$calcDate
|
||||
);
|
||||
if (!empty($prev)) {
|
||||
$this->documentService->updatePositionSort($docType, $docId, (int)$prev['pos_id'], $newPosId);
|
||||
}
|
||||
$price = 0.0;
|
||||
$totalAmount = 0.0;
|
||||
$lastSort = $position['sort'];
|
||||
}
|
||||
}
|
||||
|
||||
$prev = $position;
|
||||
}
|
||||
|
||||
if (!empty($copperPositionsInPartsList)) {
|
||||
foreach ($copperPositionsInPartsList as $partListElement) {
|
||||
$partListData = $this->evaluateSurchargeDataForPartList(
|
||||
$partListElement['article_id'],
|
||||
$partListElement['pos_id'],
|
||||
$calcDate,
|
||||
$docType,
|
||||
$partListElement['amount']
|
||||
);
|
||||
$totalAmount += $partListData['amount'];
|
||||
$price += $partListData['price'];
|
||||
$copperBase = $partListData['copper_base'];
|
||||
}
|
||||
}
|
||||
if ($price > 0.0) {
|
||||
$this->addCopperSurchargePosition(
|
||||
$docType,
|
||||
$docId,
|
||||
$price,
|
||||
$totalAmount,
|
||||
$copperBase,
|
||||
$currency,
|
||||
$calcDate
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $copperBase
|
||||
* @param float $amount
|
||||
* @param DateTimeInterface $calcDate
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function calculateCopperSurchargePrice(
|
||||
float $copperBase,
|
||||
float $amount,
|
||||
DateTimeInterface $calcDate
|
||||
): float {
|
||||
$delPrice = $this->purchasePriceGateway->getDelCopperPriceByDate(
|
||||
$calcDate,
|
||||
$this->config->getCopperSurchargeArticleId()
|
||||
);
|
||||
$perCent = $this->config->getSurchargeDeliveryCosts() / 100;
|
||||
|
||||
return (($delPrice + ($delPrice * $perCent)) - $copperBase) * $amount / 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $positionId
|
||||
* @param int $positionArticleId
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function calcAmount(string $docType, int $positionId, int $positionArticleId): float
|
||||
{
|
||||
if ($this->config->getSurchargeMaintenanceType() === CopperSurchargeData::SURCHARGE_MAINTENANCE_TYPE_APP) {
|
||||
$amount = $this->rawMaterialGateway->getRawMaterialAmount(
|
||||
$positionArticleId,
|
||||
$this->config->getCopperSurchargeArticleId()
|
||||
);
|
||||
} else {
|
||||
$articleId = $this->documentGateway->getArticleIdByPositionId($docType, $positionId);
|
||||
$amount = $this->documentGateway->getArticleCopperNumber(
|
||||
$articleId,
|
||||
$this->config->getCopperNumberOption()
|
||||
);
|
||||
}
|
||||
|
||||
$documentAmount = $this->documentGateway->getPositionAmount($docType, $positionId);
|
||||
|
||||
$amount *= $documentAmount;
|
||||
|
||||
return (float)$amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $positionArticleId
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function getCopperBase(int $positionArticleId): float
|
||||
{
|
||||
$copperBase = $this->config->getSurchargeCopperBaseStandard();
|
||||
|
||||
$articleCopperBaseField = $this->config->getSurchargeCopperBase();
|
||||
if (!empty($articleCopperBaseField)) {
|
||||
$copperBaseTemp = $this->documentGateway->getArticleCopperBase($positionArticleId, $articleCopperBaseField);
|
||||
if (!empty($copperBaseTemp)) {
|
||||
$copperBase = $copperBaseTemp;
|
||||
}
|
||||
}
|
||||
|
||||
return $copperBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $doctype
|
||||
* @param int $docId
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
* @return DateTimeInterface
|
||||
*/
|
||||
private function evaluateCalcDate(string $doctype, int $docId): DateTimeInterface
|
||||
{
|
||||
$orderOfferId = 0;
|
||||
if ($doctype === 'auftrag') {
|
||||
$orderOfferId = $this->documentGateway->findOrderOfferId($docId);
|
||||
}
|
||||
|
||||
if (
|
||||
$doctype === 'rechnung' &&
|
||||
$this->config->getSurchargeInvoice() === CopperSurchargeData::INVOICE_CREATE_POS_BY_DELIVERY_DATE
|
||||
) {
|
||||
$calcDate = $this->documentGateway->findDeliveryDate($docId);
|
||||
if (empty($calcDate)) {
|
||||
$calcDate = new DateTimeImmutable();
|
||||
}
|
||||
} elseif (
|
||||
$doctype === 'rechnung' &&
|
||||
$this->config->getSurchargeInvoice() === CopperSurchargeData::INVOICE_CREATE_POS_BY_ORDER_DATE
|
||||
) {
|
||||
$orderId = $this->documentGateway->findInvoiceOrderId($docId);
|
||||
if (empty($orderId)) {
|
||||
$calcDate = new DateTimeImmutable();
|
||||
} else {
|
||||
$calcDate = $this->documentGateway->getCalcDate('auftrag', $orderId);
|
||||
}
|
||||
} elseif ($doctype === 'rechnung' &&
|
||||
$this->config->getSurchargeInvoice() === CopperSurchargeData::INVOICE_CREATE_POS_BY_INVOICE_DATE) {
|
||||
$calcDate = $this->documentGateway->getCalcDate($doctype, $docId);
|
||||
} elseif ($doctype === 'rechnung' &&
|
||||
$this->config->getSurchargeInvoice() === CopperSurchargeData::INVOICE_CREATE_POS_BY_OFFER_DATE) {
|
||||
$offerId = $this->documentGateway->findInvoiceOfferId($docId);
|
||||
if (!empty($offerId)) {
|
||||
$calcDate = $this->documentGateway->getCalcDate('angebot', $offerId);
|
||||
} else {
|
||||
$calcDate = new DateTimeImmutable();
|
||||
}
|
||||
} elseif (
|
||||
$doctype === 'auftrag' &&
|
||||
$orderOfferId !== 0 &&
|
||||
$this->config->getSurchargeDocumentConversion() === CopperSurchargeData::DOCUMENT_CONVERSION_FROM_OFFER
|
||||
) {
|
||||
$calcDate = $this->documentGateway->getCalcDate('angebot', $orderOfferId);
|
||||
} else {
|
||||
$calcDate = new DateTimeImmutable();
|
||||
}
|
||||
|
||||
return $calcDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $docId
|
||||
* @param string $docType
|
||||
* @param int $copperSurchargeArticleId
|
||||
*/
|
||||
private function resetBetweenPositions(int $docId, string $docType, int $copperSurchargeArticleId): void
|
||||
{
|
||||
if ($this->config->getSurchargeMaintenanceType() === CopperSurchargeData::SURCHARGE_MAINTENANCE_TYPE_APP) {
|
||||
$positions = $this->rawMaterialGateway->findAllPositionsForGrouped(
|
||||
$docType,
|
||||
$docId,
|
||||
$copperSurchargeArticleId
|
||||
);
|
||||
} else {
|
||||
$positions = $this->documentGateway->findAllPositionsForGrouped(
|
||||
$docType,
|
||||
$docId,
|
||||
$this->config->getCopperNumberOption()
|
||||
);
|
||||
}
|
||||
|
||||
$offset = 0;
|
||||
foreach ($positions as $position) {
|
||||
if ((int)$position['article_id'] === $copperSurchargeArticleId) {
|
||||
$offset--;
|
||||
}
|
||||
|
||||
if ((int)$position['pos_type'] === 2 && $offset < 0) {
|
||||
$this->documentService->updateBetweenSort(
|
||||
(int)$position['between_id'],
|
||||
(int)$position['sort'] + $offset
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
*/
|
||||
public function deleteRemainingCopperSurchargeArticles(string $docType, int $docId): void
|
||||
{
|
||||
if ($this->config->getSurchargeMaintenanceType() === CopperSurchargeData::SURCHARGE_MAINTENANCE_TYPE_ARTICLE) {
|
||||
$hasCopperArticles =
|
||||
$this->documentGateway->hasCopperArticles(
|
||||
$docType,
|
||||
$docId,
|
||||
$this->config->getCopperNumberOption()
|
||||
);
|
||||
} else {
|
||||
$hasCopperArticles =
|
||||
$this->rawMaterialGateway->hasCopperArticles(
|
||||
$docType,
|
||||
$docId,
|
||||
$this->config->getCopperSurchargeArticleId()
|
||||
);
|
||||
}
|
||||
|
||||
if (!$hasCopperArticles) {
|
||||
$this->documentService->deleteCopperSurchargePositions(
|
||||
$docType,
|
||||
$docId,
|
||||
$this->config->getCopperSurchargeArticleId()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $posId
|
||||
*/
|
||||
public function updatePositionContributionMargin(string $docType, int $posId)
|
||||
{
|
||||
$this->documentService->updatePositionContributionMargin($docType, $posId, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $posId
|
||||
*/
|
||||
public function updatePositionPurchasePrice(string $docType, int $posId)
|
||||
{
|
||||
$this->documentService->updatePositionPurchasePrice($docType, $posId, 0.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
*
|
||||
* @param int $docTypeId
|
||||
*
|
||||
* @return array|DocumentPositionData[]
|
||||
*/
|
||||
public function findPositionsForMaintenanceApp(string $docType, int $docTypeId): array
|
||||
{
|
||||
$data = $this->rawMaterialGateway->findPositions(
|
||||
$docType,
|
||||
$docTypeId,
|
||||
$this->config->getCopperSurchargeArticleId()
|
||||
);
|
||||
|
||||
return $this->transformToDocumentPositionData($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
*
|
||||
* @param int $docTypeId
|
||||
*
|
||||
* @return array|DocumentPositionData[]
|
||||
*/
|
||||
public function findPositionsForMaintenanceArticle(string $docType, int $docTypeId): array
|
||||
{
|
||||
$data = $this->documentGateway->findPositions(
|
||||
$docType,
|
||||
$docTypeId,
|
||||
$this->config->getCopperNumberOption()
|
||||
);
|
||||
|
||||
return $this->transformToDocumentPositionData($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $copperPositionsRaw
|
||||
*
|
||||
* @return array|DocumentPositionData[]
|
||||
*/
|
||||
private function transformToDocumentPositionData(array $copperPositionsRaw): array
|
||||
{
|
||||
$documentPositions = [];
|
||||
foreach ($copperPositionsRaw as $position) {
|
||||
$data = new DocumentPositionData(
|
||||
(int)$position['pos_id'],
|
||||
(int)$position['article_id'],
|
||||
(string)$position['currency']
|
||||
);
|
||||
$documentPositions[] = $data;
|
||||
}
|
||||
|
||||
return $documentPositions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $doctypeId
|
||||
* @param string $doctype
|
||||
*/
|
||||
public function updateCopperSurchargeArticles(int $doctypeId, string $doctype)
|
||||
{
|
||||
$copperSurchargeArticleId = $this->config->getCopperSurchargeArticleId();
|
||||
$surchargePositions = $this->documentGateway->findCopperSurchargeArticlePositionIds(
|
||||
$doctype,
|
||||
$doctypeId,
|
||||
$copperSurchargeArticleId
|
||||
);
|
||||
|
||||
if (!empty($surchargePositions)) {
|
||||
foreach ($surchargePositions as $surchargePosition) {
|
||||
$this->updatePositionContributionMargin($doctype, (int)$surchargePosition['pos_id']);
|
||||
$this->updatePositionPurchasePrice($doctype, (int)$surchargePosition['pos_id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $copperPositionsInPartsList
|
||||
* @param int $lastSort
|
||||
* @param int $nextSort
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getElementsFromPartListBetweenSorts(
|
||||
array $copperPositionsInPartsList,
|
||||
int $lastSort,
|
||||
int $nextSort
|
||||
): array {
|
||||
$result = [];
|
||||
foreach ($copperPositionsInPartsList as $partListKey => $position) {
|
||||
$currentSort = $position['sort'];
|
||||
if ($currentSort > $lastSort && $currentSort <= $nextSort) {
|
||||
$position['part_list_key'] = $partListKey;
|
||||
$result[] = $position;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $partListHeadId
|
||||
* @param int $surchargeMaintenanceType
|
||||
* @param string $copperNumberOption
|
||||
* @param int $copperArticleId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getCopperArticlesFromPartList(
|
||||
int $partListHeadId,
|
||||
int $surchargeMaintenanceType,
|
||||
string $copperNumberOption,
|
||||
int $copperArticleId
|
||||
): array {
|
||||
$result = [];
|
||||
$childElements = $this->documentGateway->getAllPartListChildElements($partListHeadId);
|
||||
|
||||
foreach ($childElements as $childElement) {
|
||||
if ($surchargeMaintenanceType === CopperSurchargeData::SURCHARGE_MAINTENANCE_TYPE_ARTICLE) {
|
||||
$possibleArticle = $this->documentGateway->findPossibleCopperArticle(
|
||||
$childElement['id'],
|
||||
$copperNumberOption
|
||||
);
|
||||
} else {
|
||||
$possibleArticle = $this->rawMaterialGateway->findPossibleCopperArticle(
|
||||
$childElement['id'],
|
||||
$copperArticleId
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($possibleArticle)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result[] = [
|
||||
'article_id' => $possibleArticle['article_id'],
|
||||
'amount' => $possibleArticle['amount'] * $childElement['amount'],
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docTypeId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findPositionsForMaintenanceAppInPartsList(
|
||||
string $docType,
|
||||
int $docTypeId
|
||||
): array {
|
||||
$result = [];
|
||||
|
||||
$copperArticleId = $this->config->getCopperSurchargeArticleId();
|
||||
|
||||
$headArticles = $this->documentGateway->findPartListHeadArticles($docType, $docTypeId);
|
||||
|
||||
foreach ($headArticles as $headArticle) {
|
||||
$childElements = $this->documentGateway->getAllPartListChildElements($headArticle['id']);
|
||||
$hasCopper = false;
|
||||
foreach ($childElements as $childElement) {
|
||||
if (!$hasCopper) {
|
||||
$hasCopper = !empty(
|
||||
$this->rawMaterialGateway->findPossibleCopperArticle(
|
||||
$childElement['id'],
|
||||
$copperArticleId
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($hasCopper) {
|
||||
$result[] = [
|
||||
'article_id' => $headArticle['id'],
|
||||
'sort' => $headArticle['sort'],
|
||||
'pos_id' => $headArticle['pos_id'],
|
||||
'currency' => $headArticle['currency'],
|
||||
'amount' => (float)$headArticle['amount'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docTypeId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findPositionsForMaintenanceArticleInPartsList(
|
||||
string $docType,
|
||||
int $docTypeId
|
||||
): array {
|
||||
$result = [];
|
||||
|
||||
$copperNumberOption = $this->config->getCopperNumberOption();
|
||||
|
||||
$headArticles = $this->documentGateway->findPartListHeadArticles($docType, $docTypeId);
|
||||
|
||||
foreach ($headArticles as $headArticle) {
|
||||
$childElements = $this->documentGateway->getAllPartListChildElements((int)$headArticle['id']);
|
||||
$hasCopper = false;
|
||||
foreach ($childElements as $childElement) {
|
||||
if (!$hasCopper) {
|
||||
$hasCopper = !empty(
|
||||
$this->documentGateway->findPossibleCopperArticle(
|
||||
$childElement['id'],
|
||||
$copperNumberOption
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($hasCopper) {
|
||||
$result[] = [
|
||||
'article_id' => $headArticle['id'],
|
||||
'sort' => $headArticle['sort'],
|
||||
'pos_id' => $headArticle['pos_id'],
|
||||
'currency' => $headArticle['currency'],
|
||||
'amount' => (float)$headArticle['amount'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,470 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Service;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Exception;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\CopperSurcharge\Exception\EmptyResultException;
|
||||
use Xentral\Modules\CopperSurcharge\Exception\InvalidDateFormatException;
|
||||
|
||||
final class DocumentGateway
|
||||
{
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $orderId
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function findOrderOfferId(int $orderId): int
|
||||
{
|
||||
$sql =
|
||||
"SELECT a.angebotid
|
||||
FROM `auftrag` AS `a`
|
||||
WHERE id = :order_id";
|
||||
|
||||
return (int)$this->db->fetchValue($sql, ['order_id' => $orderId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $doctype
|
||||
* @param int $documentId
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function getCalcDate(string $doctype, int $documentId): DateTimeImmutable
|
||||
{
|
||||
$sql =
|
||||
"SELECT b.datum AS `date`
|
||||
FROM `" . $doctype . "` AS `b`
|
||||
WHERE b.id = :document_id";
|
||||
|
||||
$result = $this->db->fetchValue($sql, ['document_id' => $documentId]);
|
||||
|
||||
try {
|
||||
return new DateTimeImmutable($result);
|
||||
} catch (Exception $e) {
|
||||
throw new InvalidDateFormatException('Could not convert date: ' . $result['date']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $documentId
|
||||
*
|
||||
* @throws InvalidDateFormatException
|
||||
*
|
||||
* @return DateTimeImmutable|null
|
||||
*/
|
||||
public function findDeliveryDate(int $documentId): ?DateTimeImmutable
|
||||
{
|
||||
$sql =
|
||||
"SELECT b.lieferdatum AS `delivery_date`
|
||||
FROM `rechnung` AS `b`
|
||||
WHERE b.id = :document_id";
|
||||
|
||||
$result = $this->db->fetchValue($sql, ['document_id' => $documentId]);
|
||||
|
||||
if ($result === '0000-00-00') {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return new DateTimeImmutable($result);
|
||||
} catch (Exception $e) {
|
||||
throw new InvalidDateFormatException('Could not convert date: ' . $result['date']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $articleId
|
||||
* @param string $articleCopperBaseField
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getArticleCopperBase(int $articleId, string $articleCopperBaseField): float
|
||||
{
|
||||
$copperBase = 0.0;
|
||||
$sql =
|
||||
"SELECT a.{$articleCopperBaseField} AS `copper_base`
|
||||
FROM `artikel` AS `a`
|
||||
WHERE a.id = :article_id";
|
||||
|
||||
$result = $this->db->fetchValue($sql, ['article_id' => $articleId]);
|
||||
|
||||
if (!empty($result)) {
|
||||
$copperBase = $this->formatToFloat($result);
|
||||
}
|
||||
|
||||
return $copperBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function formatToFloat(string $string): float
|
||||
{
|
||||
$string = str_replace(',', '.', $string);
|
||||
|
||||
return (float)$string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
* @param string $freeField
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findAllPositionsForGrouped(
|
||||
string $docType,
|
||||
int $docId,
|
||||
string $freeField
|
||||
): array {
|
||||
$sql =
|
||||
"SELECT * FROM(
|
||||
SELECT
|
||||
pos.id AS `pos_id`,
|
||||
pos.artikel AS `article_id`,
|
||||
pos.waehrung AS `currency`,
|
||||
pos.sort AS `sort`,
|
||||
IF(a.{$freeField} = '', 0, 1) AS `is_copper`,
|
||||
1 AS `pos_type`,
|
||||
'' AS `between_type`,
|
||||
0 AS `between_id`
|
||||
FROM `" . $docType . "_position` AS `pos`
|
||||
INNER JOIN `artikel` AS `a` ON a.id = pos.artikel
|
||||
WHERE " . $docType . " = :doc_id
|
||||
UNION
|
||||
SELECT
|
||||
0 AS `pos_id`,
|
||||
0 AS `article_id`,
|
||||
'' AS `currency`,
|
||||
z.pos AS `sort`,
|
||||
0 AS `is_copper`,
|
||||
2 AS `pos_type`,
|
||||
z.postype AS `between_type`,
|
||||
z.id AS `between_id`
|
||||
FROM `beleg_zwischenpositionen` AS `z`
|
||||
WHERE z.doctype = :doc_type
|
||||
AND z.doctypeid = :doc_id
|
||||
) AS `data`
|
||||
ORDER BY data.sort, data.pos_type";
|
||||
|
||||
return $this->db->fetchAll(
|
||||
$sql,
|
||||
[
|
||||
'doc_id' => $docId,
|
||||
'doc_type' => $docType,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $positionArticleId
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPositionAmount(string $docType, int $positionArticleId): int
|
||||
{
|
||||
$sql =
|
||||
"SELECT pos.menge
|
||||
FROM `" . $docType . "_position` AS `pos`
|
||||
WHERE pos.id = :pos_id";
|
||||
|
||||
return (int)$this->db->fetchValue($sql, ['pos_id' => $positionArticleId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $docId
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function findInvoiceOrderId(int $docId): int
|
||||
{
|
||||
$sql =
|
||||
"SELECT r.auftragid
|
||||
FROM `rechnung` AS `r`
|
||||
WHERE id = :doc_id";
|
||||
|
||||
return (int)$this->db->fetchValue($sql, ['doc_id' => $docId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
* @param string $copperNumberOption
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasCopperArticles(
|
||||
string $docType,
|
||||
int $docId,
|
||||
string $copperNumberOption
|
||||
): bool {
|
||||
$sql = "SELECT pos.id
|
||||
FROM `" . $docType . "_position` AS `pos`
|
||||
INNER JOIN `artikel` AS `a` ON a.id = pos.artikel
|
||||
WHERE pos." . $docType . " = :doc_id
|
||||
AND a.{$copperNumberOption} != ''";
|
||||
|
||||
return !empty($this->db->fetchAll($sql, ['doc_id' => $docId]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $articleId
|
||||
*
|
||||
* @throws EmptyResultException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getArticleData($articleId): array
|
||||
{
|
||||
$sql =
|
||||
"SELECT
|
||||
a.name_de,
|
||||
a.anabregs_text AS `description`,
|
||||
a.umsatzsteuer AS `vat`,
|
||||
a.rabatt AS `discount`,
|
||||
a.projekt AS `project`,
|
||||
a.nummer AS `number`
|
||||
FROM `artikel` AS `a`
|
||||
WHERE a.id = :article_id
|
||||
";
|
||||
$articleData = $this->db->fetchRow($sql, ['article_id' => $articleId]);
|
||||
if (empty($articleData)) {
|
||||
throw new EmptyResultException('No article found for id: ' . $articleId);
|
||||
}
|
||||
|
||||
return $articleData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $positionId
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getArticleIdByPositionId(string $docType, int $positionId): int
|
||||
{
|
||||
$sql =
|
||||
"SELECT pos.artikel
|
||||
FROM `{$docType}_position` AS `pos`
|
||||
WHERE pos.id = :position_id";
|
||||
|
||||
return $this->db->fetchValue($sql, ['position_id' => $positionId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $docId
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function findInvoiceOfferId(int $docId): int
|
||||
{
|
||||
$sql =
|
||||
"SELECT a.angebotid
|
||||
FROM `rechnung` AS `r`
|
||||
INNER JOIN `auftrag` AS `a` ON a.id = r.auftragid
|
||||
WHERE r.id = :doc_id";
|
||||
|
||||
return (int)$this->db->fetchValue($sql, ['doc_id' => $docId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docTypeId
|
||||
* @param string $copperNumberOption
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findPositions(
|
||||
string $docType,
|
||||
int $docTypeId,
|
||||
string $copperNumberOption
|
||||
): array {
|
||||
$explodedColumnName = 'explodiert_parent';
|
||||
if ($docType === 'rechnung') {
|
||||
$explodedColumnName = 'explodiert_parent_artikel';
|
||||
}
|
||||
|
||||
$sql = "SELECT
|
||||
beleg_pos.id AS `pos_id`,
|
||||
a.id AS `article_id`,
|
||||
beleg_pos.waehrung AS `currency`
|
||||
FROM `{$docType}_position` AS `beleg_pos`
|
||||
INNER JOIN `{$docType}` AS `beleg` ON beleg.id = beleg_pos.{$docType}
|
||||
INNER JOIN `artikel` AS `a` ON a.id = beleg_pos.artikel
|
||||
WHERE beleg_pos.{$docType} = :doc_type_id
|
||||
AND a.{$copperNumberOption} != ''
|
||||
AND beleg.schreibschutz = 0
|
||||
AND beleg_pos.{$explodedColumnName} = 0
|
||||
ORDER BY beleg_pos.sort";
|
||||
|
||||
$result = $this->db->fetchAll($sql, ['doc_type_id' => $docTypeId]);
|
||||
if (!empty($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $doctypeId
|
||||
* @param int $copperSurchargeArticleId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findCopperSurchargeArticlePositionIds(
|
||||
string $docType,
|
||||
int $doctypeId,
|
||||
int $copperSurchargeArticleId
|
||||
): array {
|
||||
$sql =
|
||||
"SELECT
|
||||
beleg_pos.id AS `pos_id`
|
||||
FROM `{$docType}_position` AS `beleg_pos`
|
||||
WHERE beleg_pos.{$docType} = :doc_type_id
|
||||
AND beleg_pos.artikel = :copper_surcharge_article_id";
|
||||
|
||||
return $this->db->fetchAll(
|
||||
$sql,
|
||||
['doc_type_id' => $doctypeId, 'copper_surcharge_article_id' => $copperSurchargeArticleId]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $copperArticleId
|
||||
* @param string $copperNumberOption
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findPossibleCopperArticle(int $copperArticleId, string $copperNumberOption): array
|
||||
{
|
||||
$sql =
|
||||
"SELECT art.id AS `article_id`, art.{$copperNumberOption} AS `copper_number`
|
||||
FROM `artikel` AS `art`
|
||||
WHERE art.id = :copper_article_id
|
||||
AND art.{$copperNumberOption} != ''";
|
||||
|
||||
$result = $this->db->fetchAll($sql, ['copper_article_id' => $copperArticleId]);
|
||||
if (!empty($result)) {
|
||||
return [
|
||||
'article_id' => $result[0]['article_id'],
|
||||
'amount' => $this->formatToFloat($result[0]['copper_number']),
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docTypeId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findPartListHeadArticles(string $docType, int $docTypeId): array
|
||||
{
|
||||
$sql =
|
||||
"SELECT art.id, pos.sort, pos.id AS `pos_id`, pos.waehrung AS `currency`, pos.menge AS `amount`
|
||||
FROM `{$docType}_position` AS `pos`
|
||||
INNER JOIN artikel AS `art` ON art.id = pos.artikel
|
||||
WHERE pos.{$docType} = :doc_type_id
|
||||
AND art.stueckliste = 1";
|
||||
|
||||
return $this->db->fetchAll($sql, ['doc_type_id' => $docTypeId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $headArticleId
|
||||
* @param float $amount
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAllPartListChildElements($headArticleId, float $amount = 1.0): array
|
||||
{
|
||||
$result = [];
|
||||
$sql =
|
||||
"SELECT art.id, art.stueckliste, partlist.menge AS `amount`
|
||||
FROM `artikel` AS `art`
|
||||
INNER JOIN `stueckliste` AS `partlist` ON art.id = partlist.artikel
|
||||
WHERE partlist.stuecklistevonartikel = :head_article_id";
|
||||
|
||||
$datas = $this->db->fetchAll($sql, ['head_article_id' => $headArticleId]);
|
||||
|
||||
foreach ($datas as $data) {
|
||||
if (!empty($data['stueckliste'])) {
|
||||
$result = array_merge(
|
||||
$result,
|
||||
$this->getAllPartListChildElements((int)$data['id'], (float)$data['amount'])
|
||||
);
|
||||
} else {
|
||||
$result[] = [
|
||||
'id' => $data['id'],
|
||||
'amount' => $data['amount'] * $amount,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $articleId
|
||||
* @param string $copperNumberOption
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getArticleCopperNumber(int $articleId, string $copperNumberOption): float
|
||||
{
|
||||
$sql =
|
||||
"SELECT a.{$copperNumberOption}
|
||||
FROM `artikel` AS `a`
|
||||
WHERE a.id = :article_id";
|
||||
|
||||
return (float)str_replace(',', '.', $this->db->fetchValue($sql, ['article_id' => $articleId]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $positionId
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function evaluatePartListLastPositionId(string $docType, int $positionId): int
|
||||
{
|
||||
$explodedColumnName = 'explodiert_parent';
|
||||
if ($docType === 'rechnung') {
|
||||
$explodedColumnName = 'explodiert_parent_artikel';
|
||||
}
|
||||
|
||||
$sql =
|
||||
"SELECT MAX(id) AS `pos_id`
|
||||
FROM `{$docType}_position` AS `pos`
|
||||
WHERE pos.{$explodedColumnName} = :pos_id";
|
||||
$result = $this->db->fetchValue($sql, ['pos_id' => $positionId]);
|
||||
if (!empty($result)) {
|
||||
return (int)$result;
|
||||
}
|
||||
|
||||
return $positionId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
|
||||
final class DocumentService
|
||||
{
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
* @param int $precedingPositionId
|
||||
* @param int $followingPositionId
|
||||
*/
|
||||
public function updatePositionSort(
|
||||
string $docType,
|
||||
int $docId,
|
||||
int $precedingPositionId,
|
||||
int $followingPositionId
|
||||
): void {
|
||||
$sql =
|
||||
"SELECT `sort`
|
||||
FROM `" . $docType . "_position`
|
||||
WHERE `id` = :preceding_position_id
|
||||
LIMIT 1";
|
||||
|
||||
$precedingSort = $this->db->fetchValue($sql, ['preceding_position_id' => $precedingPositionId]);
|
||||
|
||||
$this->db->perform(
|
||||
"UPDATE `" . $docType . "_position`
|
||||
SET `sort` = `sort` + 1
|
||||
WHERE `sort` > :preceding_sort
|
||||
AND " . $docType . " = :doc_id",
|
||||
['preceding_sort' => $precedingSort, 'doc_id' => $docId]
|
||||
);
|
||||
|
||||
$this->db->perform(
|
||||
"UPDATE `beleg_zwischenpositionen`
|
||||
SET `pos` = `pos` + 1
|
||||
WHERE `doctype` = :doc_type
|
||||
AND `doctypeid` = :doc_id
|
||||
AND `pos` >= :preceding_sort",
|
||||
[
|
||||
'doc_type' => $docType,
|
||||
'doc_id' => $docId,
|
||||
'preceding_sort' => $precedingSort,
|
||||
]
|
||||
);
|
||||
|
||||
$this->db->perform(
|
||||
"UPDATE `" . $docType . "_position`
|
||||
SET `sort` = :preceding_sort + 1
|
||||
WHERE `id` = :following_position_id",
|
||||
['following_position_id' => $followingPositionId, 'preceding_sort' => $precedingSort]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $betweenId
|
||||
* @param int $betweenSort
|
||||
*/
|
||||
public function updateBetweenSort(int $betweenId, int $betweenSort): void
|
||||
{
|
||||
$this->db->perform(
|
||||
"UPDATE `beleg_zwischenpositionen`
|
||||
SET `pos` = :between_pos
|
||||
WHERE `id` = :between_id",
|
||||
[
|
||||
'between_pos' => $betweenSort,
|
||||
'between_id' => $betweenId,
|
||||
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
* @param int $copperSurchargeArticleId
|
||||
*/
|
||||
public function deleteCopperSurchargePositions(string $docType, int $docId, int $copperSurchargeArticleId): void
|
||||
{
|
||||
$sql =
|
||||
"DELETE
|
||||
FROM `" . $docType . "_position`
|
||||
WHERE `artikel` = :copper_surcharge_article_id
|
||||
AND `" . $docType . "` = :doc_id";
|
||||
|
||||
$this->db->perform($sql, ['copper_surcharge_article_id' => $copperSurchargeArticleId, 'doc_id' => $docId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
*/
|
||||
public function updatePositionSorts(string $docType, int $docId): void
|
||||
{
|
||||
$sql =
|
||||
"SELECT pos.id, pos.sort
|
||||
FROM `" . $docType . "_position` AS pos
|
||||
WHERE " . $docType . " = :doc_id
|
||||
ORDER BY pos.sort";
|
||||
$positions = $this->db->fetchAll($sql, ['doc_id' => $docId]);
|
||||
if (!empty($positions)) {
|
||||
foreach ($positions as $key => $position) {
|
||||
$sql =
|
||||
"UPDATE `" . $docType . "_position` SET `sort` = :sort WHERE `id` = :pos_id";
|
||||
$this->db->perform($sql, ['sort' => $key + 1, 'pos_id' => $position['id']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param $positionId
|
||||
* @param float $contributionMargin
|
||||
*/
|
||||
public function updatePositionContributionMargin(string $docType, $positionId, float $contributionMargin)
|
||||
{
|
||||
$sql =
|
||||
"UPDATE `" . $docType . "_position`
|
||||
SET `deckungsbeitrag` = :contribution_margin
|
||||
WHERE `id` = :position_id";
|
||||
|
||||
$this->db->perform($sql, ['contribution_margin' => $contributionMargin, 'position_id' => $positionId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $posId
|
||||
* @param float $purchasePrice
|
||||
*/
|
||||
public function updatePositionPurchasePrice(string $docType, int $posId, float $purchasePrice): void
|
||||
{
|
||||
$sql =
|
||||
"UPDATE `" . $docType . "_position`
|
||||
SET `einkaufspreis` = :purchase_price
|
||||
WHERE `id` = :position_id";
|
||||
|
||||
$this->db->perform($sql, ['purchase_price' => $purchasePrice, 'position_id' => $posId]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Service;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\CopperSurcharge\Exception\EmptyResultException;
|
||||
|
||||
final class PurchasePriceGateway
|
||||
{
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTimeInterface $calcDate
|
||||
* @param int $copperArticleId
|
||||
*
|
||||
* @throws EmptyResultException
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getDelCopperPriceByDate(DateTimeInterface $calcDate, int $copperArticleId): float
|
||||
{
|
||||
$sql =
|
||||
"SELECT data.price, data.valid_to FROM(
|
||||
SELECT
|
||||
e.preis AS `price`,
|
||||
IF(
|
||||
e.gueltig_bis = '0000-00-00',
|
||||
CURDATE(),
|
||||
e.gueltig_bis
|
||||
) AS `valid_to`
|
||||
FROM `einkaufspreise` AS `e`
|
||||
WHERE e.artikel = :copper_article_id
|
||||
) AS `data`
|
||||
WHERE data.valid_to <= :calc_date
|
||||
ORDER BY data.valid_to DESC
|
||||
LIMIT 1";
|
||||
|
||||
$result = $this->db->fetchAll(
|
||||
$sql,
|
||||
[
|
||||
'copper_article_id' => $copperArticleId,
|
||||
'calc_date' => $calcDate->format('Y-m-d'),
|
||||
]
|
||||
);
|
||||
|
||||
if (empty($result)) {
|
||||
$sql =
|
||||
"SELECT
|
||||
e.preis AS `price`
|
||||
FROM `einkaufspreise` AS `e`
|
||||
WHERE id = (
|
||||
SELECT
|
||||
MIN(e2.id)
|
||||
FROM `einkaufspreise` AS `e2`
|
||||
WHERE e2.artikel = :copper_article_id
|
||||
)";
|
||||
|
||||
$result = $this->db->fetchAll(
|
||||
$sql,
|
||||
[
|
||||
'copper_article_id' => $copperArticleId,
|
||||
]
|
||||
);
|
||||
|
||||
if (empty($result)) {
|
||||
throw new EmptyResultException('No prices found for article: ' . $copperArticleId);
|
||||
}
|
||||
}
|
||||
|
||||
return (float)$result[0]['price'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\CopperSurcharge\Exception\EmptyResultException;
|
||||
|
||||
final class RawMaterialGateway
|
||||
{
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $articleId
|
||||
* @param int $copperArticleId
|
||||
*
|
||||
* @throws EmptyResultException
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getRawMaterialAmount(int $articleId, int $copperArticleId): float
|
||||
{
|
||||
$sql =
|
||||
"SELECT r.menge
|
||||
FROM `rohstoffe` AS `r`
|
||||
WHERE r.rohstoffvonartikel = :article_id
|
||||
AND r.artikel = :copper_article_id
|
||||
LIMIT 1";
|
||||
|
||||
$result = $this->db->fetchValue($sql, ['article_id' => $articleId, 'copper_article_id' => $copperArticleId]);
|
||||
|
||||
if (empty($result)) {
|
||||
throw new EmptyResultException('No raw material amount found for articleId: ' . $articleId);
|
||||
}
|
||||
|
||||
return (float)$result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $copperArticleId
|
||||
* @param int $copperSurchargeArticleId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findPossibleCopperArticle(int $copperArticleId, int $copperSurchargeArticleId): array
|
||||
{
|
||||
$sql =
|
||||
"SELECT art.id AS `article_id`, r.menge AS `amount`
|
||||
FROM `artikel` AS `art`
|
||||
INNER JOIN `rohstoffe` AS `r` ON r.rohstoffvonartikel = art.id
|
||||
WHERE r.rohstoffvonartikel = :copper_article_id
|
||||
AND r.artikel = :copper_surcharge_article_id
|
||||
AND art.rohstoffe = 1";
|
||||
$result = $this->db->fetchAll(
|
||||
$sql,
|
||||
[
|
||||
'copper_article_id' => $copperArticleId,
|
||||
'copper_surcharge_article_id' => $copperSurchargeArticleId,
|
||||
]
|
||||
);
|
||||
if (!empty($result)) {
|
||||
return [
|
||||
'article_id' => $result[0]['article_id'],
|
||||
'amount' => (float)$result[0]['amount'],
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docTypeId
|
||||
* @param int $copperSurchargeArticleId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findPositions(
|
||||
string $docType,
|
||||
int $docTypeId,
|
||||
int $copperSurchargeArticleId
|
||||
): array {
|
||||
$explodedColumnName = 'explodiert_parent';
|
||||
if ($docType === 'rechnung') {
|
||||
$explodedColumnName = 'explodiert_parent_artikel';
|
||||
}
|
||||
|
||||
$sql = "SELECT DISTINCT
|
||||
beleg_pos.id AS `pos_id`,
|
||||
a.id AS `article_id`,
|
||||
beleg_pos.waehrung AS `currency`
|
||||
FROM `{$docType}_position` AS `beleg_pos`
|
||||
INNER JOIN `{$docType}` AS `beleg` ON beleg.id = beleg_pos.{$docType}
|
||||
INNER JOIN `artikel` AS `a` ON a.id = beleg_pos.artikel
|
||||
LEFT JOIN `rohstoffe` AS `r`
|
||||
ON r.rohstoffvonartikel = beleg_pos.artikel
|
||||
AND r.artikel = :copper_surcharge_article_id
|
||||
WHERE beleg_pos.{$docType} = :doc_type_id
|
||||
AND a.rohstoffe = 1
|
||||
AND beleg.schreibschutz = 0
|
||||
AND beleg_pos.{$explodedColumnName} = 0
|
||||
AND r.id IS NOT NULL
|
||||
ORDER BY beleg_pos.sort";
|
||||
|
||||
$result = $this->db->fetchAll(
|
||||
$sql,
|
||||
[
|
||||
'copper_surcharge_article_id' => $copperSurchargeArticleId,
|
||||
'doc_type_id' => $docTypeId,
|
||||
]
|
||||
);
|
||||
if (!empty($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
* @param int $copperSurchargeArticleId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasCopperArticles(
|
||||
string $docType,
|
||||
int $docId,
|
||||
int $copperSurchargeArticleId
|
||||
): bool {
|
||||
$sql = "SELECT pos.id
|
||||
FROM `" . $docType . "_position` AS `pos`
|
||||
INNER JOIN `rohstoffe` AS `raw`
|
||||
ON raw.rohstoffvonartikel = pos.artikel
|
||||
AND raw.artikel = :copper_surcharge_article_id
|
||||
WHERE pos." . $docType . " = :doc_id";
|
||||
|
||||
return !empty(
|
||||
$this->db->fetchAll(
|
||||
$sql,
|
||||
[
|
||||
'doc_id' => $docId,
|
||||
'copper_surcharge_article_id' => $copperSurchargeArticleId,
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $docType
|
||||
* @param int $docId
|
||||
* @param int $copperSurchargeArticleId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findAllPositionsForGrouped(
|
||||
string $docType,
|
||||
int $docId,
|
||||
int $copperSurchargeArticleId
|
||||
): array {
|
||||
$sql =
|
||||
"SELECT * FROM(
|
||||
SELECT
|
||||
pos.id AS `pos_id`,
|
||||
pos.artikel AS `article_id`,
|
||||
pos.waehrung AS `currency`,
|
||||
pos.sort AS `sort`,
|
||||
IF(raw.id IS NULL,0,1) AS `is_copper`,
|
||||
1 AS `pos_type`,
|
||||
'' AS `between_type`,
|
||||
0 AS `between_id`
|
||||
FROM `" . $docType . "_position` AS `pos`
|
||||
LEFT JOIN `rohstoffe` AS `raw`
|
||||
ON raw.rohstoffvonartikel = pos.artikel
|
||||
AND raw.artikel = :copper_surcharge_article_id
|
||||
WHERE " . $docType . " = :doc_id
|
||||
UNION
|
||||
SELECT
|
||||
0 AS `pos_id`,
|
||||
0 AS `article_id`,
|
||||
'' AS `currency`,
|
||||
z.pos AS `sort`,
|
||||
0 AS `is_copper`,
|
||||
2 AS `pos_type`,
|
||||
z.postype AS `between_type`,
|
||||
z.id AS `between_id`
|
||||
FROM `beleg_zwischenpositionen` AS `z`
|
||||
WHERE z.doctype = :doc_type
|
||||
AND z.doctypeid = :doc_id
|
||||
) AS `data`
|
||||
ORDER BY data.sort, data.pos_type";
|
||||
|
||||
return $this->db->fetchAll(
|
||||
$sql,
|
||||
[
|
||||
'doc_id' => $docId,
|
||||
'doc_type' => $docType,
|
||||
'copper_surcharge_article_id' => $copperSurchargeArticleId,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Wrapper;
|
||||
|
||||
use erpAPI;
|
||||
|
||||
|
||||
final class CompanyDataWrapper
|
||||
{
|
||||
/** @var erpAPI $erp */
|
||||
private $erp;
|
||||
|
||||
/**
|
||||
* @param erpAPI $erp
|
||||
*/
|
||||
public function __construct(erpAPI $erp)
|
||||
{
|
||||
$this->erp = $erp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fieldName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCompanyData(string $fieldName): string
|
||||
{
|
||||
return (string)$this->erp->Firmendaten($fieldName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Wrapper;
|
||||
|
||||
use erpAPI;
|
||||
use Xentral\Components\Database\Database;
|
||||
|
||||
|
||||
final class DocumentPositionWrapper implements DocumentPositionWrapperInterface
|
||||
{
|
||||
|
||||
/** @var erpAPI $erp */
|
||||
private $erp;
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param erpAPI $erp
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(erpAPI $erp, Database $db)
|
||||
{
|
||||
$this->erp = $erp;
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $doctype
|
||||
* @param int $docId
|
||||
* @param int $articleId
|
||||
* @param array $articleData
|
||||
* @param float $amount
|
||||
* @param float $price
|
||||
* @param string $currency
|
||||
* @param string $description
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function addPositionManuallyWithPrice(
|
||||
string $doctype,
|
||||
int $docId,
|
||||
int $articleId,
|
||||
array $articleData,
|
||||
float $amount,
|
||||
float $price,
|
||||
string $currency = 'EUR',
|
||||
string $description = ''
|
||||
|
||||
): int {
|
||||
$posId = $this->erp->AddPositionManuellPreis(
|
||||
$doctype,
|
||||
$docId,
|
||||
$articleId,
|
||||
$amount,
|
||||
$articleData['name_de'],
|
||||
$price,
|
||||
$articleData['vat'],
|
||||
$articleData['discount'],
|
||||
$currency,
|
||||
$description
|
||||
);
|
||||
|
||||
if (empty($posId)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int)$posId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\CopperSurcharge\Wrapper;
|
||||
|
||||
interface DocumentPositionWrapperInterface
|
||||
{
|
||||
/**
|
||||
* @param string $doctype
|
||||
* @param int $docId
|
||||
* @param int $articleId
|
||||
* @param array $articleData
|
||||
* @param float $amount
|
||||
* @param float $price
|
||||
* @param string $currency
|
||||
* @param string $description
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function addPositionManuallyWithPrice(
|
||||
string $doctype,
|
||||
int $docId,
|
||||
int $articleId,
|
||||
array $articleData,
|
||||
float $amount,
|
||||
float $price,
|
||||
string $currency = 'EUR',
|
||||
string $description = ''
|
||||
): int;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
###To find under Apps -> Master data -> Kupferzuschlag
|
||||
|
||||
The modul adds extra positions to business documents which contain articles with copper.
|
||||
The purchase prices of these surcharge articles can be edited quickly with the module 'Tagespreise' (index.php?module=tagespreise)
|
||||
Theses purchase prices represent the DEL-values (DEL stands for Deutsches Elektrolytkupfer für Leitzwecke)
|
||||
|
||||
###Preparation:
|
||||
|
||||
The following values get mangaged in the module:
|
||||
|
||||
- copper surcharge article (Kupferzuschlagsartikel)
|
||||
an article which gets addes as surcharge position in all business documents
|
||||
|
||||
- Add position (Position einfügen)
|
||||
There are three posibilities how surcharge articles can be added as positions:
|
||||
- a position gets added for every article which is a copper article
|
||||
- only one position gets added for all copper articles
|
||||
- for every group a surcharge position gets added
|
||||
|
||||
- Copper surcharge - offer to order (Kupferzuschlag - Angebot zu Auftrag)
|
||||
two posibilities:
|
||||
- DEL from offer date: if an offer exists the date from it will be used to evaluate the DEL. If there is no offer the present day is used
|
||||
- DEL from order date: the date from the order is used
|
||||
|
||||
- coppersurcharge - create invoice (Kupferzuschlag Rechnung erstellen)
|
||||
four posibilities:
|
||||
- DEL from order date: date from order, if not found present day
|
||||
- DEL from order delivery date: delivery date, if not found present day
|
||||
- DEL from invoice date: date from invoice
|
||||
- DEL from offer date: offer date, if not found present day
|
||||
|
||||
- Where should the values get specified (Wie sollen die Daten gespeichert werden?)
|
||||
There are two posibilities to save the data needed to specify a copper article:
|
||||
By the app raw materials (Rohstoffe) or with additional fields in articles (managed in (Grundeinstellungen -> Freifelder))
|
||||
|
||||
- article specific copper number (kg/km) (Artikelspezifische Kupferzahl (kg/km))
|
||||
this field only appears when 'with additional article fields is seleted'. Only fields which are already set in the 'Grundeinstellungen' appear
|
||||
|
||||
- delivery costs (in percent) (Bezugskosten (in Prozent))
|
||||
The current calculation includes always a delivery cost addition. Normally this is 1% for all articles
|
||||
|
||||
- standard copper base (Standard Kupferbasis (in EUR pro 100kg))
|
||||
The current calculation also includes this value, default is 150
|
||||
|
||||
- article specific copper base (Artikelspezifische Kupferbasis (in EUR pro 100kg))
|
||||
if the value from the field before differs in an article another additional field in the article can be assigned here
|
||||
|
||||
####Create copper surcharge article:
|
||||
|
||||
New surcharge positions need an article as base. Therefore an new one must be created.
|
||||
This article must be marked as daily price article (the checkbox 'Daily prices'(Tagespreise))
|
||||
In Artikelbeschreibung (DE) several placeholders can be used to get replaced in the position:
|
||||
{ARTIKELNUMMER}, {ARTIKELNAME}, {NETPRICE} the net price for the surcharge, {COPPERBASIS} the copper base (see calculation), {COPPERNUMBER} the copper weight (kg/km) (see calculation), {DELVALUE} the DEL value
|
||||
|
||||
####Mark an Article as copper base:
|
||||
|
||||
Dependinfg on how the module should work (raw materials or additional article fields) the article must be marked as 'Raw material list' (Rohstoffliste) or the additional field(s) must be filled
|
||||
If raw materials are used, switch to teh slider 'raw materials' (Rohstoffe) and create a new entry with the surcharge article as article and amount as copper weight (kg/km)
|
||||
|
||||
####Daily Prices:
|
||||
|
||||
in the module daily prices (Tagespreise - index.php?module=tagespreise ), in the slider configuration select the surcharge article in one of the seven possible rows and add a name
|
||||
In the slider 'overview' (Übersicht) you now can add the newest DEL values every day. DEL values can be found here: http://www.del-notiz.org/ - neu ausgegeben
|
||||
If a new daily price is added an an older one is existing the old will be changed to invalid and the new one gets added
|
||||
|
||||
####Price calculation:
|
||||
|
||||
Copper surcharge EUR/km = (copper weight (kg/km) * (DEL + 1% delivery costs)) - copper base / 100
|
||||
|
||||
Example:
|
||||
|
||||
copper weight/km: 13,00 kg
|
||||
copper base: 150,00 EUR/100 kg
|
||||
DEL: 550,00 EUR/100 kg
|
||||
|
||||
13 * ((550,00 + (550,00 * 0.01)) - 150,00) / 100 = 52,72 EUR/km
|
||||
|
||||
###How the code works:
|
||||
|
||||
The logic starts its work by calling the hooks 'ANABREGSNeuberechnen_1' (adding positions)
|
||||
and 'ANABREGSNeuberechnenEnde' (updating some unneccesary values which are filled between the hooks).
|
||||
|
||||
Because there is no relation between different positions of on business document, I always delete all
|
||||
surcharge positions and create new ones. Time will show if this is not too much and if it wouldn't be better
|
||||
to add a relation table for positions and their dependencies.
|
||||
|
||||
After deleting these positions the code starts collecting all necessary copper positions.
|
||||
It differentiates between regular articles and part list articles.
|
||||
The main difference between these types of articles is, that part list elements with copper get always grouped.
|
||||
|
||||
After that the prices get calculated and depending on the settings the positions get added.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
var CopperSurcharge = (function ($) {
|
||||
'use strict';
|
||||
|
||||
var me = {
|
||||
isInitialized: false,
|
||||
|
||||
selector: {
|
||||
optional: '.surcharge-optional',
|
||||
maintenanceType: 'surcharge-maintenance-type'
|
||||
|
||||
}
|
||||
|
||||
, init: function (){
|
||||
me.checkOptional();
|
||||
me.registerEvents();
|
||||
}
|
||||
|
||||
, registerEvents: function () {
|
||||
$('input[name=\''+me.selector.maintenanceType+'\']').on('click', me.selector.clickClass,
|
||||
function (event) {
|
||||
let maintenanceType = $(this).val();
|
||||
me.showHideOptional(maintenanceType);
|
||||
});
|
||||
}
|
||||
|
||||
, checkOptional: function (){
|
||||
let maintenanceType = $('input[name=\''+me.selector.maintenanceType+'\']:checked').val();
|
||||
me.showHideOptional(maintenanceType);
|
||||
|
||||
}
|
||||
|
||||
,showHideOptional: function(maintenanceType){
|
||||
if(maintenanceType === '1'){
|
||||
$(me.selector.optional).show();
|
||||
}
|
||||
else {
|
||||
$(me.selector.optional).hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
init: me.init
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
||||
$(document).ready(function () {
|
||||
CopperSurcharge.init();
|
||||
});
|
||||
Reference in New Issue
Block a user