OpenXE/classes/Modules/Article/Service/PurchasePriceService.php
2021-05-21 08:49:41 +02:00

251 lines
9.2 KiB
PHP

<?php
namespace Xentral\Modules\Article\Service;
use Xentral\Components\Database\Database;
use Xentral\Modules\Article\Exception\ArticleNotFoundException;
use Xentral\Modules\Article\Exception\InvalidArgumentException;
use Xentral\Modules\Article\Gateway\ArticleGateway;
final class PurchasePriceService
{
/** @var ArticleGateway $gateway */
private $gateway;
/** @var Database $db */
private $db;
/**
* @param ArticleGateway $gateway
* @param Database $database
*/
public function __construct(ArticleGateway $gateway, Database $database)
{
$this->gateway = $gateway;
$this->db = $database;
}
/**
* @param int $articleId
* @param int|float $quantity
*
* @throws InvalidArgumentException|ArticleNotFoundException
*
* @return float
*/
public function calculateCalculatedPurchasePrice($articleId, $quantity)
{
$quantity = (float)$quantity;
$articleId = $this->ensureArticleId($articleId);
if ($quantity <= 0.0) {
throw new InvalidArgumentException(sprintf('Quantity must be greater than 0. Actual: %s', $quantity));
}
$calculatedPurchasePrice = $this->db->fetchValue(
'SELECT a.berechneterek FROM artikel AS a WHERE a.id = :article_id AND a.verwendeberechneterek = 1',
['article_id' => $articleId]
);
$calculatedPurchasePrice = (float)$calculatedPurchasePrice * $quantity;
if ($calculatedPurchasePrice > 0) {
return $calculatedPurchasePrice;
}
if (!$this->gateway->isPartsListArticle($articleId)) {
return 0;
}
$calculatedPurchasePrice = 0;
$partsListArticles = $this->db->fetchAll(
'SELECT s.artikel, s.menge FROM stueckliste AS s WHERE s.stuecklistevonartikel = :article_id',
['article_id' => $articleId]
);
foreach($partsListArticles as $articles=>$article){
$calculatedPurchasePrice += $this->calculateCalculatedPurchasePrice($article['artikel'], $article['menge']);
}
return $calculatedPurchasePrice;
}
/**
* @param int $articleId
*
* @throws InvalidArgumentException
*
* @return int
*/
private function ensureArticleId($articleId)
{
if (empty($articleId) || (int)$articleId < 1) {
throw new InvalidArgumentException('Required argument "articleId" is empty or invalid.');
}
return (int)$articleId;
}
/**
* @param int $articleId
* @param int $addressId
* @param float $price
* @param string $currencyCode
* @param float $quantityFrom
* @param string $purchaseNumber
* @param string $purchaseName
*
* @return int
*/
public function setPurchasePrice($articleId,
$addressId,
$price,
$currencyCode = 'EUR',
$quantityFrom = 1.0,
$purchaseNumber = '',
$purchaseName = '')
{
$this->ensureArticleId($articleId);
if(empty($currencyCode)) {
$currencyCode = 'EUR';
}
if($quantityFrom <= 0) {
$quantityFrom = 1.0;
}
$select = $this->db->select();
$select
->cols(['pp.id', 'pp.preis as price','IF(pp.waehrung <> \'\', pp.waehrung, \'EUR\') AS currency_code',
'pp.artikel AS article_id','pp.ab_menge AS quantity_from','pp.bestellnummer AS purchase_number',
'pp.bezeichnunglieferant AS purcase_name'
])
->from('einkaufspreise AS pp')
->where("ab_menge=:quantity_from AND adresse=:address_id AND artikel=:article_id AND waehrung = :currency_code
AND (IFNULL(gueltig_bis='0000-00-00','0000-00-00') OR gueltig_bis >= NOW()) AND geloescht!=1")
->bindValue('quantity_from', (float)$quantityFrom)
->bindValue('address_id', (int)$addressId)
->bindValue('article_id', (int)$articleId)
->bindValue('currency_code', $currencyCode);
$oldPrice = $this->db->fetchRow(
$select->getStatement(),
$select->getBindValues()
);
if(!empty($oldPrice)) {
$isPriceDifferent = round($oldPrice['price'],8) !== round($price,8);
$isNumberOrNameDiffernt = (String)$oldPrice['purchase_number'] !== (String)$purchaseNumber ||
(String)$oldPrice['purcase_name'] !== (String)$purchaseName;
if(!$isPriceDifferent && !$isNumberOrNameDiffernt) {
return $oldPrice['id'];
}
if(!$isPriceDifferent) {
return $oldPrice['id'];
}
$this->db->perform(
'UPDATE einkaufspreise SET gueltig_bis = DATE_SUB(CURDATE(), INTERVAL 1 DAY) WHERE id = :id',
['id'=>$oldPrice['id']]
);
}
$this->db->perform('INSERT INTO einkaufspreise (artikel, adresse, objekt, projekt, preis, waehrung, ab_menge,
bestellnummer, bezeichnunglieferant, nichtberechnet)
VALUES (:article_id, :address_id, :object, :project_id, :price, :currency, :quantity_from,
:purchase_number,:purchase_name, 1)',
[
'article_id' => (int)$articleId,
'address_id' => (int)$addressId,
'object' => '',
'project_id' => 0,
'price' => (float)$price,
'currency' => $currencyCode,
'quantity_from' => (float)$quantityFrom,
'purchase_number' => (String)$purchaseNumber,
'purchase_name' => (String)$purchaseName
]
);
return $this->db->lastInsertId();
}
/**
* @param array $purchasePriceArray [article_id, address_id, price, quantity_from, currency_code,purchase_number,purchase_name]
*/
public function setPurchasePriceByArray($purchasePriceArray)
{
if(empty($purchasePriceArray)) {
return;
}
$articleIds = [];
$addressIds = [];
foreach($purchasePriceArray as $purchasePrice) {
if(!in_array($purchasePrice['article_id'], $articleIds)) {
$articleIds[] = $purchasePrice['article_id'];
}
if(!in_array($purchasePrice['address_id'], $addressIds)) {
$addressIds[] = $purchasePrice['address_id'];
}
}
$select = $this->db->select();
$select
->cols(
[
'pp.id',
'pp.preis as price',
'IF(pp.waehrung <> \'\', pp.waehrung, \'EUR\') AS currency_code',
'pp.artikel AS article_id',
'pp.adresse AS address_id',
'pp.ab_menge AS quantity_from',
'pp.bestellnummer AS purchase_number',
'pp.bezeichnunglieferant AS purcase_name'
]
)
->from('einkaufspreise AS pp')
->where("adresse IN (:address) AND artikel IN (:article)
AND (IFNULL(pp.gueltig_bis,'0000-00-00')='0000-00-00' OR pp.gueltig_bis >= CURDATE()) AND pp.geloescht!=1")
->bindValue('address', $addressIds)
->bindValue('article', $articleIds);
$oldPrices = $this->db->fetchAll(
$select->getStatement(),
$select->getBindValues()
);
$priceTree = [];
foreach($oldPrices as $oldPrice) {
$articleId = (int)$oldPrice['article_id'];
$addressId = (int)$oldPrice['address_id'];
$currencyCode = $oldPrice['currency_code'];
$quantityFrom = round($oldPrice['quantity_from'],8);
$priceTree[$articleId][$addressId][$currencyCode][$quantityFrom] = $oldPrice['price'];
}
unset($oldPrices);
foreach($purchasePriceArray as $purchasePrice) {
$articleId = (int)$purchasePrice['article_id'];
$addressId = (int)$purchasePrice['address_id'];
$currencyCode = $purchasePrice['currency_code'];
$quantityFrom = round($purchasePrice['quantity_from'],8);
$price = round($purchasePrice['price'], 8);
$purchaseNumber = !empty($purchasePrice['purchase_number'])?$purchasePrice['purchase_number']:'';
$purchaseName = !empty($purchasePrice['purchase_name'])?$purchasePrice['purchase_name']:'';
$aricleExists = !empty($priceTree[$articleId]);
$addressExists = $aricleExists && !empty($priceTree[$articleId][$addressId]);
$currencyExists = $addressExists && !empty($priceTree[$articleId][$addressId][$currencyCode]);
$quantityFromExists = $currencyExists && !empty($priceTree[$articleId][$addressId][$currencyCode][$quantityFrom]);
if(!$quantityFromExists || round($oldPrice['price'],8) !== $price) {
$this->setPurchasePrice(
$articleId,
$addressId,
$price,
$currencyCode,
$quantityFrom,
$purchaseNumber,
$purchaseName
);
}
}
}
}