Files
kupshop/bundles/External/VarioBundle/Synchronizers/PriceSynchronizer.php
2025-08-02 16:30:27 +02:00

228 lines
6.7 KiB
PHP

<?php
namespace External\VarioBundle\Synchronizers;
use KupShop\PricelistBundle\Util\PriceListWorker;
use Query\Operator;
class PriceSynchronizer extends BaseSynchronizer
{
protected static $type = 'otPrice';
protected static $batch = 100;
protected static $maxBatches = 50;
protected $logging = true;
protected $fields = [
'ProductID' => 'item',
];
/** @var PriceListWorker */
protected $priceListWorker;
/** @required */
public function setPriceListWorker(PriceListWorker $priceListWorker): void
{
$this->priceListWorker = $priceListWorker;
}
public function getEshopID($objectID)
{
if (!($productId = $this->helper->getMapping('vario_products', $objectID))) {
return null;
}
return (int) $productId;
}
public function syncItem($varioProductId, $productId, $column, \stdClass $item)
{
$this->helper->addDelayedUpdate(
$this->helper->trimVarioId($varioProductId),
ProductSynchronizer::getType()
);
}
public function syncPrices(array $items, int $productId): void
{
$prices = [];
// preprocess prices
foreach ($items as $item) {
if (!($variationId = $this->getVariationId($item))) {
$variationId = 0;
}
$prices[$this->helper->trimVarioId($item->PriceID)][$variationId] = $item;
}
$priceListsConfig = $this->config->getPriceLists();
// process default price
foreach ($this->getPricesData($productId, $priceListsConfig['default'], $prices) as $variationId => [$price, $discount]) {
$this->syncGlobalPrice($productId, $variationId, $price, $discount);
}
// process price list prices
foreach ($priceListsConfig['others'] ?? [] as $config) {
[$priceListVarioId, $_] = $config;
if (!($priceListId = $this->getPriceList($priceListVarioId))) {
continue;
}
foreach ($this->getPricesData($productId, $config, $prices) as $variationId => [$price, $discount]) {
$this->priceListWorker->updatePriceList(
$priceListId,
$productId,
$variationId === 0 ? null : $variationId,
$price,
$discount
);
}
}
}
public function getPricesData(int $productId, array $config, array $prices): array
{
$priceList = $config[0];
$discountPriceList = $config[1];
$withVat = $config[2] ?? true;
$result = [];
foreach ($prices[$priceList] ?? [] as $variationId => $item) {
$price = toDecimal($item->Value);
$priceWithoutVat = $price;
if ($withVat) {
$priceWithoutVat = $price->removeVat(
$this->getProductVat($productId)
);
}
$discount = \DecimalConstants::zero();
if ($discountItem = ($prices[$discountPriceList][$variationId] ?? false)) {
$discountedPrice = toDecimal($discountItem->Value);
$discount = $price->sub($discountedPrice)->div($price)->mul(\DecimalConstants::hundred());
}
$result[$variationId] = [$priceWithoutVat, $discount];
}
return $result;
}
protected function getVariationId(\stdClass $item): ?int
{
$variationId = null;
if (!empty($item->VariantID)) {
$variationId = $this->helper->getMapping('vario_variations', $this->helper->trimVarioId($item->VariantID));
if (!$variationId) {
$variationId = null;
}
}
return $variationId ? (int) $variationId : null;
}
protected function syncGlobalPrice(int $productId, ?int $variationId, \Decimal $price, ?\Decimal $discount = null): void
{
if ($variationId) {
$this->updateSQL('products_variations', ['price' => $price], ['id' => $variationId]);
} else {
$update = ['price' => $price];
if ($discount) {
$update['discount'] = $discount;
}
$this->updateSQL('products', $update, ['id' => $productId]);
}
}
private function syncCommonPrice(int $productId, ?int $variationId, \Decimal $price): void
{
if ($variationId) {
$this->updateSQL('products_variations', ['price_common' => $price], ['id' => $variationId]);
} else {
$this->updateSQL('products', ['price_common' => $price], ['id' => $productId]);
}
}
private function calculateDiscount(\Decimal $price, ?\Decimal $priceCommon): \Decimal
{
$discount = toDecimal(0);
if ($price->isPositive() && $priceCommon && $priceCommon->isPositive()) {
if (!$price->equals($priceCommon)) {
$discount = $priceCommon->sub($price)->div($priceCommon)->mul(\DecimalConstants::hundred());
}
}
return $discount;
}
private function isPriceValid(object $price): bool
{
$now = new \DateTime();
$validFrom = new \DateTime((string) $price->ValidFrom);
$validTo = new \DateTime((string) $price->ValidTo);
if (($now >= $validFrom || empty($price->ValidFrom))
&& ($now <= $validTo || empty($price->ValidTo))) {
return true;
}
return false;
}
protected function getPriceList(string $varioId): ?int
{
static $priceLists = [];
if (!$priceLists) {
$priceLists = sqlFetchAll(sqlQueryBuilder()
->select('id_vario, id_pricelist')
->from('vario_pricelists')
->execute(),
['id_vario' => 'id_pricelist']);
}
if ($priceLists[$varioId] ?? false) {
return (int) $priceLists[$varioId];
}
return null;
}
protected function getProductVat(int $productId): float
{
static $vatCache = [];
if (!empty($vatCache[$productId])) {
return $vatCache[$productId];
}
$vat = sqlQueryBuilder()->select('v.vat')
->from('products', 'p')
->leftJoin('p', 'vats', 'v', 'v.id = p.vat')
->where(Operator::equals(['p.id' => $productId]))
->execute()->fetchColumn();
return $vatCache[$productId] = (float) ($vat ?? getVat());
}
protected function postprocess()
{
$this->helper->updateProductsPriceToMinFromVariations();
}
protected function getObjectID($item)
{
if (empty($item->Data)) {
return null;
}
return $this->helper->trimVarioId($item->Data->ProductID);
}
}