Files
kupshop/bundles/External/PompoBundle/DRS/Synchronizer/POSOrderSynchronizer.php
2025-08-02 16:30:27 +02:00

828 lines
31 KiB
PHP

<?php
declare(strict_types=1);
namespace External\PompoBundle\DRS\Synchronizer;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use External\PompoBundle\Util\Configuration;
use KupShop\BonusProgramBundle\Event\UserBonusPointsUpdatedEvent;
use KupShop\BonusProgramBundle\Utils\BonusComputer;
use KupShop\I18nBundle\Entity\Currency;
use KupShop\KupShopBundle\Context\CurrencyContext;
use KupShop\KupShopBundle\Query\JsonOperator;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\KupShopBundle\Util\Database\QueryHint;
use KupShop\KupShopBundle\Util\Logging\SentryLogger;
use KupShop\KupShopBundle\Util\StringUtil;
use KupShop\OrderingBundle\Entity\Order\OrderItem;
use Query\Operator;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Service\Attribute\Required;
/**
* Synchronizuje objednavky z pokladen do e-shopu - uctenky, vypocita body zakaznika.
*/
class POSOrderSynchronizer extends AbstractSynchronizer
{
/** @required */
public Configuration $configuration;
/** @required */
public EventDispatcherInterface $eventDispatcher;
public ?BonusComputer $bonusComputer = null;
/** @required */
public SentryLogger $sentryLogger;
protected static $type = 'pos_order';
private ?int $timestamp = null;
public function process(): void
{
// nacist posledni timestamp
$this->timestamp = $this->getLastTimestamp();
// zpracovat objednavky
foreach ($this->getItems() as $index => $item) {
try {
$this->processItem($item);
} catch (UniqueConstraintViolationException $e) {
}
$this->timestamp = max((int) ($item['header']['TimeStamp'] ?? 0), 0);
if (($index % 500) == 0) {
$this->setLastTimestamp($this->timestamp);
}
}
// ulozit timestamp
if ($this->timestamp) {
$this->setLastTimestamp($this->timestamp);
}
}
/**
* Kvuli doimportovani starych objednavek z prodejen.
*/
public function processWithCustomTimestamp(int $timestamp, callable $timestampUpdate): void
{
$this->timestamp = $timestamp;
// zpracovat objednavky
foreach ($this->getItems() as $index => $item) {
try {
$this->processItem($item);
} catch (UniqueConstraintViolationException $e) {
}
$this->timestamp = max((int) ($item['header']['TimeStamp'] ?? 0), 0);
if (($index % 500) == 0) {
$timestampUpdate($this->timestamp);
}
}
}
public function processOrder(array $order, bool $force = true): void
{
if ($force) {
$order['header']['force'] = true;
}
$this->processItem($order);
}
public function processSingleItem(int $drsId, bool $force = false): void
{
if ($order = $this->drsApi->getStoreOrder($drsId)) {
if ($force) {
$order['header']['force'] = true;
}
$this->processItem($order);
}
}
/**
* Zpracuje prodejku z DRSu. Bud vytvori novou objednavku, nebo aktualizuje jiz existujici objednavku na eshopu (rezervace).
*/
protected function processItem(array $item, bool $isOldOrder = false): void
{
if (!$isOldOrder && (empty($item['header']['DocumentNumber']) || (($item['header']['DocumentTypeDesc'] ?? '') !== 'SALE'))) {
return;
}
$orderNumber = $item['header']['Description'] ?? '';
$description = explode('ESHOP:', $orderNumber);
if ($description[1] ?? false) {
$orderNumber = $description[1];
}
// Pokud Je tam jen text nebo mezery, tak to necham fallbacknout na DocumentNumber
if (!preg_match('~[0-9]+~', $orderNumber) || strpos($orderNumber, ' ') !== false) {
$orderNumber = null;
}
$oldReceiptOrderNumber = 'P'.$item['header']['DocumentNumber'];
if (empty($orderNumber)) {
$dateCreated = new \DateTime($item['header']['RecCreated']);
$orderNumber = 'P'.$dateCreated->format('ymd').'-'.$item['header']['DocumentNumber'];
}
// Objednavka z nejhracky, skipuju
if ($isOldOrder && (StringUtil::startsWith($orderNumber, '2') || StringUtil::startsWith($orderNumber, '4'))) {
return;
}
if (($item['data']['InvoiceCountryCode'] ?? 'CZ') === 'SK') {
$item['header']['CurrencyISOCode'] = 'EUR';
}
// mena objednavky
$currency = $this->getOrderCurrency($item['header']['CurrencyISOCode'] ?? '');
$orX = [Operator::equals(['order_no' => $orderNumber])];
if (StringUtil::startsWith($oldReceiptOrderNumber, 'P')) {
$orX[] = Operator::equals(['order_no' => $oldReceiptOrderNumber]);
}
$foundOrder = sqlQueryBuilder()
->select('id, order_no')
->from('orders')
->andWhere(
Operator::orX($orX)
)
->execute()->fetchAssociative();
$orderId = $foundOrder['id'] ?? null;
// import starych objednavek - muzou tam prijit novy objednavky, ktery vznikly uz u nas... a ty chci preskocit
if ($isOldOrder && (StringUtil::startsWith($orderNumber, '122') || StringUtil::startsWith($orderNumber, '322'))) {
return;
}
// objednavku uz mame v e-shopu, protoze je to rezervace provedena na e-shopu
if ($orderId) {
// pokud je to stara objednavak (ze stareho eshopu)
if ($isOldOrder) {
$this->updateOldOrder((int) $orderId, $item);
} else {
$this->updateShopOrder((int) $orderId, $item, $currency);
// Zpetna aktualizace, aby se opravili cisla objednavek
if ($foundOrder['order_no'] !== $orderNumber) {
$this->updateOrderNumber((int) $orderId, $orderNumber);
}
}
return;
}
// Vytvorim objednavku
sqlGetConnection()->transactional(function () use ($item, $orderNumber, $currency, $isOldOrder) {
// Nactu spravny deliveryType
$deliveryTypeName = strip_tags($item['data']['NameDelivery'] ?? '').' - '.strip_tags($item['data']['NamePayment'] ?? '');
$deliveryType = $this->getDeliveryType();
if ($isOldOrder) {
$deliveryType = null;
}
if ($deliveryType) {
$deliveryTypeName = $deliveryType->name ?? '';
}
// Najdu uzivatele
$userId = null;
$userName = '';
$userSurname = '';
if (!empty($item['data']['InvoiceName'])) {
$nameParts = explode(' ', $item['data']['InvoiceName']);
$userName = $nameParts[0];
unset($nameParts[0]);
$userSurname = implode(' ', $nameParts);
}
if ($item['customer']['CustomerNumber'] ?? false) {
if ($user = $this->getUser((string) $item['customer']['CustomerNumber'])) {
$userId = $user->id;
$userName = $user->name ?? $userName;
$userSurname = $user->surname ?? $userSurname;
}
}
if (empty($userName) && empty($userSurname)) {
$userName = 'Prodej';
$userSurname = 'prodejna ('.$item['header']['DocumentNumber'].')';
}
// Stav objednavky
$status = $this->getOrderStatus($item, $isOldOrder);
$dateHandle = null;
// datum vyrizeni
if ($status == $this->configuration->getOrderFinalStatus()) {
try {
$dateHandle = (new \DateTime($item['data']['DueDate'] ?? 'now'))->format('Y-m-d H:i:s');
} catch (\Throwable $e) {
$dateHandle = (new \DateTime())->format('Y-m-d H:i:s');
}
}
$sellerId = $this->getSellerByBranchId($item['header']['SourceBranch'] ?? '');
// Vytvorim objednavku
sqlQueryBuilder()
->insert('orders')
->directValues(
[
'id_user' => $userId,
'id_language' => $currency->getId() === 'EUR' ? 'sk' : 'cs',
'order_no' => $orderNumber,
'date_created' => $item['header']['RecCreated'],
'date_accept' => $dateHandle,
'date_handle' => $dateHandle,
'date_updated' => $item['header']['RecCreated'],
'currency' => $currency->getId(),
'status' => $status,
'status_storno' => ($item['header']['StornoDocument'] === '1' || ($item['data']['Status_WEB_objednavky'] ?? null) == 80) ? 1 : 0,
'status_payed' => 1,
'id_delivery' => $deliveryType ? $deliveryType->id : null,
'delivery_type' => $deliveryTypeName,
'flags' => $isOldOrder ? 'O' : 'NP',
'invoice_email' => $item['data']['Email'] ?? '',
'invoice_name' => $userName,
'invoice_surname' => $userSurname,
'invoice_country' => $item['data']['InvoiceCountryCode'] ?? 'CZ',
'note_admin' => json_encode([
'transactionPrintout' => $item['data']['TransactionPrintout'] ?? null,
'delivery_data' => [
'seller_id' => $sellerId,
],
]),
]
)->execute();
$orderId = (int) sqlInsertId();
// Vytvarim mapping do tabulky
sqlQueryBuilder()
->insert('drs_orders')
->directValues(
[
'id_drs' => $orderNumber,
'id_order' => $orderId,
'data' => json_encode(
[
'originalDocumentNumber' => $item['header']['DocumentNumber'],
'type' => 'sale',
'hasReceipt' => 1,
'completed' => 1,
'recId' => $item['header']['TimeStamp'],
]
),
]
)->execute();
// insertnu polozky objednavky
$this->insertShopOrderItems($orderId, $item, $currency);
$order = new \Order();
$order->createFromDB($orderId);
// ulozim k objednavce kupon, ktery v ni byl pouzit
$this->setOrderCoupon($order, $item, $sellerId);
// zavolam recalculate na objednavce, aby sedela total price
$order->recalculate();
if ($isOldOrder) {
$order->logHistory('Stará objednávka');
} else {
$order->logHistory('[DRS] Nákup přes pokladnu');
}
// zavolam update order, ktery prida body za objednavku
$this->updateShopOrder($orderId, $item, $currency, true);
return $order;
});
}
protected function getItems(): iterable
{
if ($this->timestamp === null) {
// od roku 2020
$this->timestamp = 38096494;
}
do {
$hasData = false;
foreach ($this->drsApi->getStoreOrders($this->timestamp) as $item) {
$hasData = true;
yield $item;
}
} while ($hasData === true);
}
private function getOrderStatus(array $item, bool $isOldOrder): int
{
if ($isOldOrder) {
switch ($item['data']['Status_WEB_objednavky'] ?? null) {
case null:
case '':
return 0;
case 10:
// Přijatá
return 1;
case 40:
// Zpracovává se
return 2;
case 50:
// Vyřízeno
return 4;
case 60:
// Připraveno k osobnímu odběru
return 5;
case 70:
// ukončená
return 6;
case 80:
// stornovaná
return 6;
case 90:
// převoz
return 3;
case 91:
// nekompletní
return 7;
}
}
return $this->configuration->getOrderFinalStatus();
}
private function getSellerByBranchId(string $branchId): ?int
{
$sellerId = sqlQueryBuilder()
->select('id')
->from('sellers')
->where(
Operator::equals(
[
JsonOperator::value('data', 'branchId') => $branchId,
]
)
)->execute()->fetchOne();
if (!$sellerId) {
return null;
}
return (int) $sellerId;
}
private function getUser(string $customerId): ?\User
{
$data = sqlQueryBuilder()
->select('u.*')
->from('drs_users', 'du')
->join('du', 'users', 'u', 'du.id_user = u.id')
->where(Operator::equals(['du.id_drs' => $customerId]))
->execute()->fetchAssociative();
if (!$data) {
return null;
}
$user = new \User();
$user->loadData($data);
return $user;
}
private function getDeliveryType(): ?\DeliveryType
{
foreach (\DeliveryType::getAll() as $deliveryType) {
if ($deliveryType->getDelivery() instanceof \OdberNaProdejne && $deliveryType->getPayment() instanceof \Hotovost) {
return $deliveryType;
}
}
return null;
}
/**
* Aktualizuje uz existujici objednavku v e-shopu.
*
* $isNewOrder - znamená, zda je to nákup vytvořený na prodejně a nebo rezervace vytvořená přes e-shop
*/
private function updateShopOrder(int $orderId, array $item, Currency $currency, bool $isNewOrder = false): void
{
$order = \Order::get($orderId);
// objednavka uz byla sesynchronizovana z pokladny
if ($order->getData('drsPos') && !($item['header']['force'] ?? false)) {
return;
}
$orderDateHandle = $order->date_handle;
// Tohle nedelam u objednavek, ktere importuju primo z DRSu (prodejky). Tuhle cast musim volat pouze u rezervaci, ktere byly
// vytvoreny pres e-shop
if (!$isNewOrder) {
// ulozim uctenku
$order->setData('transactionPrintout', $item['data']['TransactionPrintout'] ?? null);
// pokud objednavka nema uzivatele, ale na prodejne nakoupila na zakaznikou kartu, tak potrebuju k objednavce uzivatele pridat
if (!$order->id_user && !empty($item['customer']['CustomerNumber'])) {
if ($user = $this->getUser((string) $item['customer']['CustomerNumber'])) {
sqlQueryBuilder()
->update('orders')
->directValues(
[
'id_user' => $user->id,
]
)
->where(Operator::equals(['id' => $order->id]))
->execute();
$order->id_user = $user->id;
}
}
// ulozit poukaz, ktery byl pouzity na pokladne
$this->setOrderCoupon($order, $item);
// aktualizovat polozky objednavky podle dat v prodejce
$this->updateShopOrderItems($order, $item, $currency);
// zaloguju s cim to bylo sparovane
$order->logHistory(
sprintf('[DRS] Objednávka byla spárovaná s prodejkou %s', $item['header']['DocumentNumber'] ?? '')
);
// prepnu objednavku do finalniho stavu, pokud v nem jeste neni a neni to prave vytvorena objednavka
$order->changeStatus(
$this->configuration->getOrderFinalStatus(),
null,
false
);
}
// Starsim objednavkam body nechceme pricitat, protoze to jsou historicke objednavky, ktere jsme jen doimportovali do shopu
// pokud je to ale stara objednavka, ktera jeste nebyla vyrizena, tak tam ty body pricist chceme
if ($this->bonusComputer && $order->date_created > (new \DateTime('2022-10-05 00:00:00')) || (($order->getFlags()['O'] ?? false) && !$orderDateHandle) || ($item['header']['forcePoints'] ?? false)) {
$this->bonusComputer->checkBonusPointsEarningDiscount($order);
$this->bonusComputer->updateBonusPoints($order);
$discountsToDelete = array_map(fn ($action) => $action['id_order_discount'], $order->getPurchaseState()->getActions('bonus_points') ?: []);
$discounts = $order->getData('discounts');
if ($discounts && is_null($discounts['extra_bonus_points'] ?? null)) {
sqlQueryBuilder()
->delete('order_discounts_orders')
->where(Operator::equals(['id_order' => $orderId]))
->andWhere(Operator::inIntArray($discountsToDelete, 'id_order_discount'))
->execute();
}
$points = $this->bonusComputer->countBonusPoints($order->getPurchaseState());
$received = sqlQueryBuilder()
->select('bp.id')
->from('bonus_points', 'bp')
->andWhere(Operator::equals(['bp.id_order' => $order->id, 'bp.id_user' => $order->id_user]))
->andWhere('bp.points > 0')
->sendToMaster()
->execute()->fetchOne();
if ($received) {
// body byly pripsany standardne (inactive) - potrebujeme je smazat
// a pridat pomoci setOrderBonusPoints, aby byly Aktivní a s jinou poznamkou
sqlQueryBuilder()->delete('bonus_points')->where(Operator::equals(['id' => $received]))->execute();
} else {
// body nebyly pripsany, protoze viz engine/bundles/External/PompoBundle/BonusProgram/Utils/BonusComputer.php:32
}
$this->setOrderBonusPoints($order, $points, $isNewOrder);
}
// oznacim si, ze jsem objednavku uz sesynchronizoval z pokladny
$order->setData('drsPos', 1);
}
public function updateShopOrderItems(\Order $order, array $drsOrder, Currency $currency): void
{
$diff = $order->getTotalPrice()->getPriceWithVat()->sub($this->getDRSOrderTotalPrice($drsOrder, $currency))->abs()->asFloat();
// nothing changed so do not process update
if ($diff < 0.1 && empty($drsOrder['header']['force'])) {
return;
}
sqlGetConnection()->transactional(function () use ($order, $drsOrder, $currency) {
$currentItems = $order->getItems();
sqlQueryBuilder()
->delete('order_items')
->where(Operator::equals(['id_order' => $order->id]))
->execute();
$this->insertShopOrderItems($order->id, $drsOrder, $currency, $currentItems);
$order->recalculate();
$order->logHistory('[DRS] Byla provedena aktualizace položek podle prodejky '.($drsOrder['header']['DocumentNumber'] ?? ''));
});
// reload order items because items of order changed
$order->setPurchaseState(null);
$order->items = [];
QueryHint::withRouteToMaster(fn () => $order->fetchItems());
}
/**
* @param OrderItem[]|null $currentItems
*/
public function insertShopOrderItems(int $orderId, array $drsOrder, Currency $currency, ?array $currentItems = null): void
{
foreach ($drsOrder['items'] ?? [] as $orderItem) {
// polozka s 0 ks me nezajima
if (((float) $orderItem['Amount']) == 0) {
continue;
}
$info = $this->getPOSOrderItemInfo($orderItem, $currency);
$note = [
'isPOSItem' => true,
'isPOSDiscounted' => $this->isItemDiscounted($info),
];
// ulozim puvodni cenu a celkovou slevu do poznamky, aby se ta sleva zobrazila i v adminu
if ($this->isItemDiscounted($info)) {
$note['priceWithoutDiscounts'] = $info['originalPiecePriceWithVat']->asFloat();
$note['totalDiscount'] = $info['originalPiecePriceWithVat']->sub($info['piecePriceWithVat'])->asFloat();
}
$orderItemId = null;
// pokud znam aktualni polozku, tak z ni budu chtit zachovat udaje (id polozky, notu)
if ($currentItem = ($currentItems[$orderItem['EshopItemID']] ?? null)) {
$orderItemId = $currentItem->getId();
$note = array_merge($note, $currentItem->getNote());
}
$note = json_encode($note);
$insertData = [
'id_order' => $orderId,
'id_product' => $info['productId'],
'pieces' => $info['pieces'],
'piece_price' => $info['price']->div($info['pieces']),
'total_price' => $info['price'],
'tax' => $orderItem['VATPercent'] ?? getAdminVat()['value'],
'descr' => $orderItem['Description'] ?? 'Položka',
'note' => $note,
];
if ($orderItemId) {
$insertData['id'] = $orderItemId;
}
sqlQueryBuilder()
->insert('order_items')
->directValues($insertData)
->execute();
}
}
private function getDRSOrderTotalPrice(array $drsOrder, Currency $currency): \Decimal
{
$totalPrice = \DecimalConstants::zero();
foreach ($drsOrder['items'] ?? [] as $orderItem) {
// polozka s 0 ks me nezajima
if (((float) $orderItem['Amount']) == 0) {
continue;
}
$info = $this->getPOSOrderItemInfo($orderItem, $currency);
$totalPrice = $totalPrice->add($info['priceWithVat']);
}
return $totalPrice;
}
/**
* Teoreticky se bude moct jednou smazat, protoze to slouzi pouze k doimportovani starych objednavek.
*
* Aktualizace staré objednavky v e-shopu.
*/
private function updateOldOrder(int $orderId, array $item): void
{
sqlQueryBuilder()
->update('orders')
->directValues(
[
'invoice_email' => $item['data']['Email'] ?? '',
'status' => $this->getOrderStatus($item, true),
'status_storno' => ($item['header']['StornoDocument'] === '1' || ($item['data']['Status_WEB_objednavky'] ?? null) == 80) ? 1 : 0,
]
)
->andWhere(Operator::equals(['id' => $orderId]))
->andWhere(Operator::findInSet(['O'], 'flags'))
->execute();
}
private function updateOrderNumber(int $orderId, string $orderNumber): void
{
sqlQueryBuilder()
->update('orders')
->directValues(
[
'order_no' => $orderNumber,
]
)
->where(Operator::equals(['id' => $orderId]))
->execute();
}
/**
* Nastavi objednavce body podle obsahu objednavky.
*/
private function setOrderBonusPoints(\Order $order, \Decimal $points, bool $isNewOrder = false): void
{
if (!$order->id_user) {
return;
}
sqlQueryBuilder()
->insert('bonus_points')
->directValues(
[
'id_user' => $order->id_user,
'points' => $points,
'date_created' => (new \DateTime())->format('Y-m-d H:i:s'),
'note' => $isNewOrder ? 'Body za nákup na prodejně' : 'Body za vyzvednutou rezervaci',
'status' => 'active',
'id_order' => $order->id,
]
)->execute();
$this->eventDispatcher->dispatch(
new UserBonusPointsUpdatedEvent($order->id_user)
);
$order->logHistory(sprintf('Za tuto objednávku bylo na účet uživatele přičteno %s bodů', $points->asFloat()));
}
/**
* Ulozi k objednavce pouzitou slevu / kupon, a u kuponu prida objednavku, ve ktery byl uplatnen.
*/
public function setOrderCoupon(\Order $order, array $item, ?int $sellerId = null): void
{
$coupons = $item['data']['ShopVoucherNumber'] ?? [];
if (empty($coupons)) {
return;
}
$orderId = $order->id;
foreach ($coupons as $coupon) {
try {
$foundCoupon = sqlQueryBuilder()
->select('id, id_discount')
->from('discounts_coupons')
->where(
Operator::equals(
[
'code' => $coupon,
'used' => 'Y',
]
)
)->execute()->fetchAssociative();
if ($foundCoupon) {
// aktualizuje u kuponu, ze byl pouziti v tehle objednavce
sqlQueryBuilder()
->update('discounts_coupons')
->directValues(
[
'id_order_used' => $orderId,
]
)
->set('data', 'JSON_SET(COALESCE(data, "{}"), "$.sellerId", :sellerId)')
->where(Operator::equals(['id' => $foundCoupon['id']]))
->setParameter('sellerId', $sellerId)
->execute();
$usedOrderDiscountId = sqlQueryBuilder()
->select('id_order_discount')
->from('order_discounts_triggers')
->where(
Operator::equals(['JSON_VALUE(data, \'$.generate_coupon\')' => $foundCoupon['id_discount']])
)
->execute()->fetchOne();
// ulozim k objednavce, ze tam byla uplatnena sleva
if ($usedOrderDiscountId) {
sqlQueryBuilder()
->insert('order_discounts_orders')
->directValues(
[
'id_order' => $orderId,
'id_order_discount' => $usedOrderDiscountId,
]
)->execute();
}
// zaloguju do historie objednavky info o tom, ktery pouakz byl uplatneny
$order->logHistory(
comment: '[DRS] V objednávce byl uplatněný poukaz: '.$coupon
);
}
} catch (\Throwable $e) {
$this->sentryLogger->captureException($e);
}
}
}
/**
* Vrati informace o produktu v DRS prodejce, abych to byl schopny vlozit do nasi objednavky.
*/
private function getPOSOrderItemInfo(array $item, Currency $currency): array
{
$productId = (int) sqlQueryBuilder()
->select('id')
->from('products')
->where(Operator::equals(['code' => $item['VirtualArticleNumber'] ?? null]))
->execute()->fetchOne();
if (!$productId) {
// Kdyz nenajdu produkt, tak to naparuju na produkt, aby tam byla aspon nejaka vazba kvuli pocitani bodu
$productId = $this->getDummyProductId((string) ($item['VirtualArticleNumber'] ?? ''));
if (in_array($productId, ['995003', '995001', '995002'])) {
$productId = null;
}
}
$vat = toDecimal((float) ($item['VATPercent'] ?? getAdminVat()['value']));
$roundPrice = function (\Decimal $value, bool $round = true) use ($currency): \Decimal {
if (!$round) {
return $value;
}
return roundPrice($value, -1, 'DB', null, $currency);
};
$originalPriceWithVat = $roundPrice(toDecimal((float) $item['OriginalRetailPriceWithVAT'] ?? 0), false);
$priceWithVat = $roundPrice(toDecimal((float) $item['RetailPriceWithVAT'] ?? 0), false);
$originalPrice = $originalPriceWithVat->removeVat($vat);
$price = $priceWithVat->removeVat($vat);
$pieces = toDecimal((float) $item['Amount'] ?? 1);
return [
'productId' => $productId,
'originalPrice' => $originalPrice,
'originalPiecePrice' => $originalPrice->div($pieces),
'originalPriceWithVat' => $originalPriceWithVat,
'originalPiecePriceWithVat' => $originalPriceWithVat->div($pieces),
'price' => $price,
'piecePrice' => $price->div($pieces),
'priceWithVat' => $priceWithVat,
'piecePriceWithVat' => $priceWithVat->div($pieces),
'pieces' => $pieces,
'vat' => $vat,
];
}
/**
* Nektere produkty nemusi byt na e-shopu, takze jsou na e-shopu vytvorene "Dummy" produkty, ktere tyhle produkty reprezentuji. Je to primarne
* kvuli pocitani bodu, abych to mel jednodussi.
*/
private function getDummyProductId(string $code): int
{
// pokud je to lego produkt
if (StringUtil::startsWith($code, '22')) {
return 45476;
}
return 45475;
}
#[Required]
public function setBonusComputer(?BonusComputer $bonusComputer = null): void
{
$this->bonusComputer = $bonusComputer;
}
private function isItemDiscounted(array $info): bool
{
if ($info['piecePriceWithVat']->lowerThan($info['originalPiecePriceWithVat'])) {
$diff = $info['originalPiecePriceWithVat']->sub($info['piecePriceWithVat']);
if (!$diff->lowerThanOrEqual(toDecimal(0.1))) {
return true;
}
}
return false;
}
private function getOrderCurrency(string $currency): Currency
{
return Contexts::get(CurrencyContext::class)->getOrDefault($currency);
}
}