first commit
This commit is contained in:
988
bundles/External/FlexiBeeBundle/Synchronizers/OrderSynchronizer.php
vendored
Normal file
988
bundles/External/FlexiBeeBundle/Synchronizers/OrderSynchronizer.php
vendored
Normal file
@@ -0,0 +1,988 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace External\FlexiBeeBundle\Synchronizers;
|
||||
|
||||
use AbraFlexi\ObjednavkaPrijata;
|
||||
use External\FlexiBeeBundle\Exception\FlexiBeeException;
|
||||
use KupShop\I18nBundle\Entity\Currency;
|
||||
use KupShop\KupShopBundle\Context\CurrencyContext;
|
||||
use KupShop\KupShopBundle\Util\Contexts;
|
||||
use KupShop\KupShopBundle\Util\Database\QueryHint;
|
||||
use KupShop\KupShopBundle\Util\Functional\Mapping;
|
||||
use KupShop\OrderingBundle\Entity\Order\OrderItem;
|
||||
use KupShop\OrderingBundle\Util\Order\OrderInfo;
|
||||
use Query\Operator;
|
||||
use Query\QueryBuilder;
|
||||
|
||||
class OrderSynchronizer extends BaseSynchronizer
|
||||
{
|
||||
protected static string $type = 'order';
|
||||
protected static ?string $evidenceClass = ObjednavkaPrijata::class;
|
||||
|
||||
/** @required */
|
||||
public UserSynchronizer $userSynchronizer;
|
||||
|
||||
protected array $recentlyUpdatedOrders = [];
|
||||
|
||||
public function syncSingleItem(int $id, ?int $flexiId = null): void
|
||||
{
|
||||
if ($flexiId = $this->flexiBeeUtil->getFlexiId(static::getType(), $id)) {
|
||||
$items = $this->preprocessChangedItems([$this->flexiBeeApi->getOrder($flexiId)]);
|
||||
$this->processItem(reset($items));
|
||||
}
|
||||
}
|
||||
|
||||
public function syncSingleItemToFlexi($item): bool
|
||||
{
|
||||
try {
|
||||
$order = QueryHint::withRouteToMaster(fn () => \Order::get((int) $item['id']));
|
||||
|
||||
$orderIsPaidAtStart = $order->isPaid(true);
|
||||
|
||||
try {
|
||||
$data = $this->getOrderData($order, $item['id_flexi'] ? (int) $item['id_flexi'] : null);
|
||||
$flexiId = $this->flexiBeeApi->createOrUpdateOrder($data);
|
||||
$this->logUpdate($data);
|
||||
} catch (FlexiBeeException $e) {
|
||||
$errorMessage = 'Objednávku se nepodařilo zapsat do FlexiBee';
|
||||
if ($item['id_flexi']) {
|
||||
$errorMessage = 'Objednávku se ve FlexiBee nepodařilo aktualizovat';
|
||||
}
|
||||
|
||||
// zaznamenam neuspesnou sync
|
||||
if ($errorStatus = $this->configuration->getOrderConfig()['error_status']) {
|
||||
$attemptCount = $order->getData('flexiSyncAttemptCount');
|
||||
$attemptCount = $attemptCount + 1;
|
||||
$order->setData('flexiSyncAttemptCount', $attemptCount);
|
||||
|
||||
if ($attemptCount >= 10) {
|
||||
$order->logHistory('[FlexiBee] Došlo k opakovanému problému se synchronizací objednávky, zkontrolujte Activity log');
|
||||
$order->changeStatus($errorStatus);
|
||||
}
|
||||
}
|
||||
|
||||
// zalogovani do ActivityLogu
|
||||
$this->logger->exception(
|
||||
$e,
|
||||
sprintf('[FlexiBee] Objednávka "%s": %s', $order->order_no, $errorMessage),
|
||||
[
|
||||
'orderId' => $order->id,
|
||||
'flexiBeeError' => $e->getMessage(),
|
||||
]
|
||||
);
|
||||
|
||||
// nastavim orderUpdated na 0, protoze se aktualizace nepovedla, tak aby to furt nezkouselo znova
|
||||
if ($item['id_flexi'] && !$errorStatus) {
|
||||
$this->flexiBeeUtil->setFlexiOrderData(
|
||||
(int) $order->id,
|
||||
'orderUpdated',
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pokud nemam flexiId, tak pravdepodobne nastala nejaka chyba, takze preskakuju
|
||||
if (!$flexiId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// objednavka jeste nema mapping a tudiz jsme ji ted poprve zapsali do FlexiBee
|
||||
if (!$this->flexiBeeUtil->getMapping(OrderSynchronizer::getType(), $flexiId)) {
|
||||
$this->flexiBeeUtil->createMapping(OrderSynchronizer::getType(), $flexiId, (int) $order->id);
|
||||
$order->logHistory('[FlexiBee] Objednávka byla nahrána do FlexiBee; ID: '.$flexiId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// pokud objednavka uz ma mapping, tak to musi znamenat, ze jsme provadeli update objednavky
|
||||
// takze pouze k objednavce zaloguju, ze byla objednavka ve FlexiBee aktualizovana
|
||||
$order->logHistory('[FlexiBee] Objednávka byla ve FlexiBee zaktualizována');
|
||||
// aktualizuju orderUpdated stav
|
||||
// skoro vzdy nastavuju na 0, ale pokud by se stalo, ze objednavka nebyla zaplacena a zaplaceni bylo provedeno v prubehu
|
||||
// odesilani objednavky do Flexi, tak nastavim na 1, aby se v dalsim cyklu synchronizace poslal update objednavky do Flexi
|
||||
$this->flexiBeeUtil->setFlexiOrderData(
|
||||
(int) $order->id,
|
||||
'orderUpdated',
|
||||
!$orderIsPaidAtStart && $order->isPaid(true) ? 1 : 0
|
||||
);
|
||||
// updatovanout objednavku si ulozim, abych ji v sync z flexi do shopu mohl preskocit
|
||||
$this->recentlyUpdatedOrders[] = $order->id;
|
||||
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->exception($e, '[FlexiBee] Během synchronizace objednávek se vyskytla chyba!', [
|
||||
'orderId' => $item['id'],
|
||||
]);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function process(?int $lastSyncTime = null): void
|
||||
{
|
||||
// Nahrani objednavek do FlexiBee
|
||||
$this->processToFlexiBee();
|
||||
// Zpracovani objednavek z FlexiBee
|
||||
parent::process($lastSyncTime);
|
||||
}
|
||||
|
||||
protected function processItem(array $item): void
|
||||
{
|
||||
// neznama objednavka, takze s ni nic nedelam
|
||||
if (!($orderId = QueryHint::withRouteToMaster(fn () => $this->flexiBeeUtil->getMapping(static::getType(), $item['id'])))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$order = QueryHint::withRouteToMaster(fn () => \Order::get($orderId));
|
||||
|
||||
// pokud je objednavka stornovana, tak ji neaktualizuju
|
||||
if ($order->status_storno == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// stornovani objednavky
|
||||
if ($item['stavUzivK'] === 'stavDoklObch.storno') {
|
||||
if ($order->status_storno == 0) {
|
||||
$order->logHistory('[FlexiBee] Objednávka byla stornována ve FlexiBee');
|
||||
$order->storno(false); // ORDER_STORNO event nastavi orderUpdated na 1
|
||||
// nastavim orderUpdated na 0, aby synchronizace to nezkousela znovu stornovat ve FlexiBee
|
||||
$this->flexiBeeUtil->setFlexiOrderData((int) $order->id, 'orderUpdated', 0);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// pokud mam zapnutou oboustranou synchronizaci, tak sesynchronizuju zmeny na objednavce
|
||||
if (($this->configuration->getOrderConfig()['duplex_sync'] ?? false) === 'Y') {
|
||||
$this->processOrderChanges($order, $item);
|
||||
}
|
||||
|
||||
// ulozit cislo baliku z FlexiBee k objednavce
|
||||
$this->saveOrderPackageNumber($order, $item);
|
||||
|
||||
$statuses = $this->configuration->getOrderStatusesConfig();
|
||||
// zmena stavu podle konfigurace v administraci
|
||||
if ($status = ($statuses[$item['stavUzivK']] ?? false)) {
|
||||
if (!empty($status['status']) || !empty($status['order_message'])) {
|
||||
$this->changeOrderStatus(
|
||||
$order,
|
||||
$item['stavUzivK'],
|
||||
!empty($status['status']) ? (int) $status['status'] : null,
|
||||
!empty($status['order_message']) ? $this->getOrderMessageNameById((int) $status['order_message']) : null
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function processToFlexiBee(): void
|
||||
{
|
||||
$this->processOrdersToFlexiBee();
|
||||
}
|
||||
|
||||
private function processOrdersToFlexiBee(): void
|
||||
{
|
||||
if (isLocalDevelopment()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// nacitam objednavky, ktere nejsou zapsane do FlexiBee nebo je u nich potreba provest aktualizaci
|
||||
$qb = $this->getBaseOrdersQueryBuilder()
|
||||
->andWhere(
|
||||
Operator::andX(
|
||||
Operator::orX(
|
||||
// objednavka neni vyrizena
|
||||
Operator::not(
|
||||
Operator::inIntArray(getStatuses('handled'), 'o.status')
|
||||
),
|
||||
// nebo je to objednavka z poklady - pokladna ji muze vyridit hned
|
||||
Operator::equals(['o.source' => OrderInfo::ORDER_SOURCE_POS])
|
||||
),
|
||||
Operator::orX(
|
||||
Operator::andX(
|
||||
Operator::isNull('fo.id_order'),
|
||||
Operator::equals(['o.status_storno' => 0])
|
||||
),
|
||||
'JSON_VALUE(fo.data, \'$.orderUpdated\') = 1',
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// pokud mam nastavenej error_status tak nechci porad dokola synchronizovat objednavky s chybou
|
||||
$errorStatus = $this->configuration->getOrderConfig()['error_status'];
|
||||
if ($errorStatus) {
|
||||
$qb->andWhere(
|
||||
Operator::not(
|
||||
Operator::equals(['o.status' => $errorStatus]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($qb->sendToMaster()->execute() as $item) {
|
||||
$this->syncSingleItemToFlexi($item);
|
||||
}
|
||||
}
|
||||
|
||||
public function getOrderInvoiceData(\Order $order): array
|
||||
{
|
||||
$data = [
|
||||
'formaUhradyCis' => $this->getPaymentTypeCode($order),
|
||||
'formaDopravy' => $this->getDeliveryTypeCode($order),
|
||||
'doprava' => $order->getDeliveryType()->name,
|
||||
];
|
||||
|
||||
if ($paymentStatus = $this->getPaymentStatus($order)) {
|
||||
$data['stavUhrK'] = $paymentStatus;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getOrderRealizeData(\Order $order): array
|
||||
{
|
||||
$items = [];
|
||||
foreach ($order->fetchItems() as $item) {
|
||||
$items[] = [
|
||||
'id' => $this->getItemId($order, $item),
|
||||
'mj' => $item['pieces'],
|
||||
];
|
||||
}
|
||||
|
||||
$datePaid = new \DateTime();
|
||||
|
||||
$payments = $order->getPaymentsArray();
|
||||
if ($payment = reset($payments)) {
|
||||
$datePaid = $payment['date'];
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => 'ext:OBP:'.$this->flexiBeeUtil->getOrderNumber($order),
|
||||
'realizaceObj' => [
|
||||
'@type' => 'faktura-vydana',
|
||||
'id' => 'ext:FAV:'.$this->flexiBeeUtil->getOrderNumber($order),
|
||||
'datUhr' => $datePaid->format('Y-m-d'),
|
||||
'formaUhradyCis' => $this->getPaymentTypeCode($order),
|
||||
'formaDopravy' => $this->getDeliveryTypeCode($order),
|
||||
'doprava' => $order->getDeliveryType()->name,
|
||||
'polozkyObchDokladu' => $items,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function getOrderData(\Order $order, ?int $flexiBeeId = null): array
|
||||
{
|
||||
$items = [];
|
||||
foreach ($order->getItems() as $item) {
|
||||
$items[] = $this->getOrderItemData($order, $item);
|
||||
}
|
||||
|
||||
$orderData = [
|
||||
// externi identifikator
|
||||
'id' => 'ext:'.$this->getDocumentType($order).':'.$this->flexiBeeUtil->getOrderNumber($order),
|
||||
// cislo objednavky
|
||||
'kod' => $this->getOrderNumber($order),
|
||||
'cisDosle' => $this->getOrderNumber($order),
|
||||
'typDokl' => 'code:'.$this->getDocumentType($order),
|
||||
'datVyst' => $this->getOrderDate($order),
|
||||
'stredisko' => $this->getOrderCentral($order),
|
||||
'poznam' => $this->getOrderNote($order),
|
||||
|
||||
'varSym' => $this->getOrderVariableSymbol($order),
|
||||
|
||||
'zaokrNaSumK' => $this->getOrderRounding($order),
|
||||
'zaokrJakSumK' => $this->getOrderRoundDirection($order),
|
||||
|
||||
'formaUhradyCis' => $this->getPaymentTypeCode($order),
|
||||
'formaDopravy' => $this->getDeliveryTypeCode($order),
|
||||
|
||||
'mena' => 'code:'.$order->getCurrency(),
|
||||
'kurz' => $order->currency_rate,
|
||||
'kurzMnozstvi' => 1,
|
||||
|
||||
'kontaktEmail' => $order->invoice_email,
|
||||
'kontaktJmeno' => $order->delivery_name.' '.$order->delivery_surname,
|
||||
'kontaktTel' => $order->invoice_phone,
|
||||
|
||||
'nazFirmy' => $this->getOrderFirmName($order),
|
||||
'ulice' => $order->invoice_street,
|
||||
'mesto' => $order->invoice_city,
|
||||
'psc' => $order->invoice_zip,
|
||||
'ic' => $order->invoice_ico,
|
||||
'dic' => $order->invoice_dic,
|
||||
'stat' => 'code:'.(empty($order->invoice_country) ? 'CZ' : $order->invoice_country),
|
||||
'statDph' => 'code:'.(empty($order->delivery_country) ? 'CZ' : $order->delivery_country),
|
||||
|
||||
'postovniShodna' => $this->isOrderDeliveryAddressSame($order),
|
||||
|
||||
'faNazev' => $this->getOrderFirmName($order, 'delivery'),
|
||||
'faUlice' => $order->delivery_street,
|
||||
'faMesto' => $order->delivery_city,
|
||||
'faPsc' => $order->delivery_zip,
|
||||
'faStat' => 'code:'.(empty($order->delivery_country) ? 'CZ' : $order->delivery_country),
|
||||
|
||||
'stavUzivK' => $this->getOrderStatus($order, $flexiBeeId),
|
||||
|
||||
'polozkyDokladu' => $order->status_storno == 1 ? [] : $items,
|
||||
'polozkyObchDokladu@removeAll' => true,
|
||||
];
|
||||
|
||||
if ($flexiUserId = $this->getOrderUser($order)) {
|
||||
$orderData['firma'] = $flexiUserId;
|
||||
}
|
||||
|
||||
if ($orderDescription = $this->getOrderDescription($order)) {
|
||||
$orderData['popis'] = $orderDescription;
|
||||
}
|
||||
|
||||
if (null !== ($orderFlags = $this->getOrderFlags($order))) {
|
||||
$orderData['stitky'] = $orderFlags;
|
||||
$orderData['stitky@removeAll'] = true;
|
||||
}
|
||||
|
||||
if ($pointId = $order->getDeliveryType()->getDelivery()->getPointId()) {
|
||||
$orderData['branchId'] = $pointId;
|
||||
}
|
||||
|
||||
return $orderData;
|
||||
}
|
||||
|
||||
protected function processOrderChanges(\Order $order, array $flexiOrder): void
|
||||
{
|
||||
// pokud jsem objednavku prave updatoval, tak nema smysl se snazit ji hned zpetne updatovat z flexi
|
||||
if (in_array($order->id, $this->recentlyUpdatedOrders)) {
|
||||
unset($this->recentlyUpdatedOrders[$order->id]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// pokud je objednavka ve stavu hotovo, tak zmeny na objednavce nezpracovavame
|
||||
if ($flexiOrder['stavUzivK'] === 'stavDoklObch.hotovo' || $flexiOrder['stavUzivK'] === 'stavDoklObch.storno') {
|
||||
return;
|
||||
}
|
||||
|
||||
$orderUpdate = [];
|
||||
|
||||
$invoiceDiff = array_diff(
|
||||
[$flexiOrder['ic'], $flexiOrder['dic'], $flexiOrder['ulice'], $flexiOrder['mesto'], $flexiOrder['psc']],
|
||||
[$order->invoice_ico, $order->invoice_dic, $order->invoice_street, $order->invoice_city, $order->invoice_zip]
|
||||
);
|
||||
|
||||
if (!empty($invoiceDiff)) {
|
||||
$orderUpdate = array_merge($orderUpdate, [
|
||||
'invoice_ico' => $flexiOrder['ic'],
|
||||
'invoice_dic' => $flexiOrder['dic'],
|
||||
'invoice_street' => $flexiOrder['ulice'],
|
||||
'invoice_city' => $flexiOrder['mesto'],
|
||||
'invoice_zip' => $flexiOrder['psc'],
|
||||
]);
|
||||
}
|
||||
|
||||
$deliveryDiff = array_diff(
|
||||
[$flexiOrder['faUlice'], $flexiOrder['faMesto'], $flexiOrder['faPsc']],
|
||||
[$order->delivery_street, $order->delivery_city, $order->delivery_zip]
|
||||
);
|
||||
|
||||
if (!empty($deliveryDiff)) {
|
||||
$orderUpdate = array_merge($orderUpdate, [
|
||||
'delivery_street' => $flexiOrder['faUlice'],
|
||||
'delivery_city' => $flexiOrder['faMesto'],
|
||||
'delivery_zip' => $flexiOrder['faPsc'],
|
||||
]);
|
||||
}
|
||||
|
||||
$activityLogChanges = [];
|
||||
|
||||
// pokud jsou ve FlexiBee jine fakturacni udaje, tak provadim aktualizaci
|
||||
if (!empty($orderUpdate)) {
|
||||
sqlQueryBuilder()
|
||||
->update('orders')
|
||||
->directValues($orderUpdate)
|
||||
->where(Operator::equals(['id' => $order->id]))
|
||||
->execute();
|
||||
|
||||
if (!empty($invoiceDiff)) {
|
||||
$activityLogChanges['invoice'] = [
|
||||
'old' => [
|
||||
'invoice_ico' => $order->invoice_ico,
|
||||
'invoice_dic' => $order->invoice_dic,
|
||||
'invoice_street' => $order->invoice_street,
|
||||
'invoice_city' => $order->invoice_city,
|
||||
'invoice_zip' => $order->invoice_zip,
|
||||
],
|
||||
'new' => [
|
||||
'invoice_ico' => $flexiOrder['ic'],
|
||||
'invoice_dic' => $flexiOrder['dic'],
|
||||
'invoice_street' => $flexiOrder['ulice'],
|
||||
'invoice_city' => $flexiOrder['mesto'],
|
||||
'invoice_zip' => $flexiOrder['psc'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($deliveryDiff)) {
|
||||
$activityLogChanges['delivery'] = [
|
||||
'old' => [
|
||||
'delivery_street' => $order->delivery_street,
|
||||
'delivery_city' => $order->delivery_city,
|
||||
'delivery_zip' => $order->delivery_zip,
|
||||
],
|
||||
'new' => [
|
||||
'delivery_street' => $flexiOrder['faUlice'],
|
||||
'delivery_city' => $flexiOrder['faMesto'],
|
||||
'delivery_zip' => $flexiOrder['faPsc'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$currentOrderItems = Mapping::mapKeys($order->fetchItems(), fn ($k, $v) => [$k, false]);
|
||||
foreach ($flexiOrder['items'] ?? [] as $flexiItem) {
|
||||
$externalId = !empty($flexiItem['external-ids']) ? (string) $flexiItem['external-ids'] : null;
|
||||
// pokud neni u polozky vyplnene externalId, tak je to polozka pridana ve FlexiBee
|
||||
if (!$externalId) {
|
||||
// kouknu zda ta polozka uz neni v objednavce pridana
|
||||
$externalId = $order->getData('flexiBeeItems')[$flexiItem['id']] ?? null;
|
||||
}
|
||||
|
||||
$flexiPiecePrice = \Decimal::create($flexiItem['cenaMj'])->addDiscount($flexiItem['slevaPol']);
|
||||
if ($flexiItem['typCenyDphK'] === 'typCeny.sDph') {
|
||||
$flexiPiecePrice = $flexiPiecePrice->removeVat($flexiItem['szbDph']);
|
||||
}
|
||||
|
||||
// pokud nemam externalId, tak pridavam polozku
|
||||
if (!$externalId) {
|
||||
// pokud je to polozka s 0 ks, tak ji preskocim, protoze nema smysl ji pridavat do objednavky
|
||||
if ($flexiItem['mnozMj'] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$productId = null;
|
||||
$variationId = null;
|
||||
// pridat novou polozku do objednavky
|
||||
if (!empty($flexiItem['cenik'])) {
|
||||
// zkusim polozku naparovat na produkt / variantu
|
||||
if (!empty($flexiItem['cenik']->ref)) {
|
||||
if ($flexiCenikId = $this->flexiBeeUtil->getFlexiIdFromRef($flexiItem['cenik']->ref)) {
|
||||
[$productId, $variationId] = $this->flexiBeeUtil->getItemMapping($flexiCenikId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$newItemId = sqlGetConnection()->transactional(function () use ($order, $productId, $variationId, $flexiItem, $flexiPiecePrice) {
|
||||
sqlQueryBuilder()
|
||||
->insert('order_items')
|
||||
->directValues(
|
||||
[
|
||||
'id_order' => $order->id,
|
||||
'id_product' => $productId,
|
||||
'id_variation' => $variationId,
|
||||
'pieces' => $flexiItem['mnozMj'],
|
||||
'pieces_reserved' => $flexiItem['mnozMj'],
|
||||
'piece_price' => $flexiPiecePrice,
|
||||
'total_price' => $flexiPiecePrice->mul(toDecimal($flexiItem['mnozMj'])),
|
||||
'descr' => $flexiItem['nazev'],
|
||||
'tax' => $flexiItem['szbDph'],
|
||||
]
|
||||
)->execute();
|
||||
|
||||
return (int) sqlInsertId();
|
||||
});
|
||||
|
||||
// pridam mapovani pro nove pridany item
|
||||
sqlGetConnection()->transactional(function () use ($order, $newItemId, $flexiItem) {
|
||||
$newItems = $order->getData('flexiBeeItems');
|
||||
$newItems[$flexiItem['id']] = $newItemId;
|
||||
$order->setData('flexiBeeItems', $newItems);
|
||||
});
|
||||
|
||||
$activityLogChanges['items'][$newItemId] = ['id' => $newItemId, 'name' => $flexiItem['nazev'], 'added' => true];
|
||||
continue;
|
||||
}
|
||||
|
||||
$parts = explode('-', (string) $externalId);
|
||||
$itemId = (int) end($parts);
|
||||
// pokud by tam ID nebylo, tak je to divny.. ale radsi fail-check a skipnu to
|
||||
/** @var OrderItem $item */
|
||||
if (!($item = ($order->fetchItems()[$itemId] ?? null))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// polozka je ve FlexiBee stornovana
|
||||
if ($flexiItem['storno'] === true || $flexiItem['stornoPol'] === true) {
|
||||
// pokracuju dal - tim polozku neoznacim v $currentOrderItems jako ze jsem ji nasel a timpadem bude smazana z objednavky
|
||||
continue;
|
||||
}
|
||||
|
||||
// oznacim si polozku, ze jsem ji nasel
|
||||
$currentOrderItems[$itemId] = true;
|
||||
|
||||
$itemUpdate = [];
|
||||
|
||||
// pokud se zmenil pocet kusu
|
||||
if ($item->getPieces() != $flexiItem['mnozMj']) {
|
||||
$itemUpdate['pieces'] = $flexiItem['mnozMj'];
|
||||
$itemUpdate['pieces_reserved'] = $flexiItem['mnozMj'];
|
||||
}
|
||||
|
||||
// pokud se zmenilo DPH
|
||||
if ($item->getVat() != $flexiItem['szbDph']) {
|
||||
$itemUpdate['tax'] = $flexiItem['szbDph'];
|
||||
}
|
||||
|
||||
// pokud se zmenila cena, nebo pocet kusu, tak potrebuju aktualizovat cenu
|
||||
if ($item->getItem()['value_without_vat']->round(4)->asFloat() != $flexiPiecePrice->round(4)->asFloat() || $item->getPieces() != $flexiItem['mnozMj']) {
|
||||
$itemUpdate['piece_price'] = $flexiPiecePrice->asFloat();
|
||||
$itemUpdate['total_price'] = $flexiPiecePrice->mul(toDecimal($flexiItem['mnozMj']));
|
||||
}
|
||||
|
||||
// provest aktualizaci polozky
|
||||
if (!empty($itemUpdate)) {
|
||||
sqlQueryBuilder()
|
||||
->update('order_items')
|
||||
->directValues($itemUpdate)
|
||||
->where(Operator::equals(['id' => $itemId, 'id_order' => $order->id]))
|
||||
->execute();
|
||||
|
||||
$activityLogChanges['items'][$itemId] = ['id' => $itemId, 'productId' => $item->getProductId(), 'name' => $item->getDescr(), 'updated' => true, 'changes' => $itemUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
// projdu polozky, ktere ve FlexiBee odebrali z objednavky a smazu je i v e-shopove objednavce
|
||||
$deletedItems = array_filter($currentOrderItems, fn ($x) => !$x);
|
||||
foreach ($deletedItems as $deletedItemId => $deletedItem) {
|
||||
if (!($item = ($order->fetchItems()[$deletedItemId] ?? null))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// smaznu item z objednavky
|
||||
sqlQueryBuilder()
|
||||
->delete('order_items')
|
||||
->where(Operator::equals(['id' => $deletedItemId]))
|
||||
->execute();
|
||||
|
||||
// zaloguju smazani do historie objednavky
|
||||
$order->logHistory('[FlexiBee] Odebrána položka: '.$item->getDescr());
|
||||
|
||||
$activityLogChanges['items'][$deletedItemId] = ['id' => $deletedItemId, 'productId' => $item->getProductId(), 'name' => $item->getDescr(), 'deleted' => true];
|
||||
}
|
||||
|
||||
// provest prepocitani cen, pokud se provedli nejake zmeny v polozkach
|
||||
if (!empty($activityLogChanges['items'])) {
|
||||
$order->recalculate();
|
||||
}
|
||||
|
||||
// logovani
|
||||
if (!empty($activityLogChanges)) {
|
||||
// zaloguju zmeny do activity logu
|
||||
$this->logger->activity(
|
||||
sprintf('Aktualizace objednávky "%s" z FlexiBee', $order->order_no),
|
||||
$activityLogChanges
|
||||
);
|
||||
|
||||
// udelam sumarni report, ktery zaloguju primo k objednavce
|
||||
$messages = [];
|
||||
foreach ($activityLogChanges as $type => $changes) {
|
||||
switch ($type) {
|
||||
case 'invoice':
|
||||
$messages[] = 'Provedena aktualizace fakturační adresy;';
|
||||
break;
|
||||
case 'delivery':
|
||||
$messages[] = 'Provedena aktualizace dodací adresy;';
|
||||
break;
|
||||
case 'items':
|
||||
$updated = 0;
|
||||
$added = 0;
|
||||
$deleted = 0;
|
||||
foreach ((array) $changes as $change) {
|
||||
if (($change['updated'] ?? false) === true) {
|
||||
$updated++;
|
||||
}
|
||||
|
||||
if (($change['deleted'] ?? false) === true) {
|
||||
$deleted++;
|
||||
}
|
||||
|
||||
if (($change['added'] ?? false) === true) {
|
||||
$added++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($updated || $added || $deleted) {
|
||||
$messages[] = "Změny na položkách: přidání: {$added}x; aktualizace: {$updated}x; smazání: {$deleted}x;";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($messages)) {
|
||||
$order->logChange(implode('<br>', array_merge(['[FlexiBee] Provedena aktualizace objednávky podle FlexiBee:'], $messages)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getOrderNumber(\Order $order): string
|
||||
{
|
||||
return $order->order_no;
|
||||
}
|
||||
|
||||
protected function getOrderVariableSymbol(\Order $order): string
|
||||
{
|
||||
return preg_replace('/\D*/', '', $order->order_no);
|
||||
}
|
||||
|
||||
protected function getOrderStatus(\Order $order, ?int $flexiBeeId = null): string
|
||||
{
|
||||
if ($flexiBeeId) {
|
||||
// pokud je objednavka stornovana tak stornuju i ve flexi
|
||||
if ($order->status_storno == 1) {
|
||||
return 'stavDoklObch.storno';
|
||||
}
|
||||
|
||||
// pokud je to update objednavky ve FlexiBee, tak chci zachovat stav objednavky, kterej je ve FlexiBee
|
||||
if ($flexiStatus = ($this->flexiBeeApi->getOrder($flexiBeeId)['stavUzivK'] ?? false)) {
|
||||
return $flexiStatus;
|
||||
}
|
||||
}
|
||||
|
||||
return 'stavDoklObch.nespec';
|
||||
}
|
||||
|
||||
protected function getOrderNote(\Order $order): string
|
||||
{
|
||||
return $order->note_user ?: '';
|
||||
}
|
||||
|
||||
protected function getOrderRoundDirection(\Order $order): string
|
||||
{
|
||||
$currency = Contexts::get(CurrencyContext::class)->getOrDefault($order->getCurrency());
|
||||
|
||||
return match ($currency->getPriceRoundDirection()) {
|
||||
'up' => 'zaokrJak.nahoru',
|
||||
'down' => 'zaokrJak.dolu',
|
||||
default => 'zaokrJak.matem',
|
||||
};
|
||||
}
|
||||
|
||||
protected function getOrderRounding(\Order $order): string
|
||||
{
|
||||
/** @var Currency $currency */
|
||||
$currency = Contexts::get(CurrencyContext::class)->getOrDefault($order->getCurrency());
|
||||
|
||||
switch ($currency->getPriceRoundOrder() / 100) {
|
||||
case 1:
|
||||
return 'zaokrNa.jednotky';
|
||||
case 0.01:
|
||||
return 'zaokrNa.setiny';
|
||||
case 0.001:
|
||||
return 'zaokrNa.tisiciny';
|
||||
case 0.05:
|
||||
return 'zaokrNa.5setiny';
|
||||
case 0.1:
|
||||
return 'zaokrNa.desetiny';
|
||||
case 0.5:
|
||||
return 'zaokrNa.5desetiny';
|
||||
case -0.05:
|
||||
return 'zaokrNa.5jednotky';
|
||||
case -0.1:
|
||||
return 'zaokrNa.desitky';
|
||||
}
|
||||
|
||||
return 'zaokrNa.zadne';
|
||||
}
|
||||
|
||||
protected function getOrderDescription(\Order $order): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Stitky do FlexiBee */
|
||||
protected function getOrderFlags(\Order $order): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getOrderItemData(\Order $order, OrderItem $item): array
|
||||
{
|
||||
$itemFlexiId = null;
|
||||
$itemType = 'typPolozky.obecny';
|
||||
if ($item->getProductId()) {
|
||||
// pokud mam FlexiID, tak je to katalogova polozka
|
||||
if ($itemFlexiId = $this->flexiBeeUtil->getProductFlexiId($item->getProductId(), $item->getVariationId())) {
|
||||
$itemType = 'typPolozky.katalog';
|
||||
}
|
||||
}
|
||||
|
||||
// pripravim pole s datama polozky
|
||||
$itemData = [
|
||||
'id' => $this->getItemId($order, $item),
|
||||
'typPolozkyK' => $itemType,
|
||||
'kod' => $item->getCode(),
|
||||
'eanKod' => $item->getEAN(),
|
||||
'nazev' => $item->getDescr(),
|
||||
'mnozMj' => $order->status_storno == 1 ? 0 : $item->getPieces(),
|
||||
'typCenyDphK' => 'typCeny.sDph',
|
||||
'cenaMj' => $item->getPiecePrice()->getPriceWithVat(false)->asFloat(),
|
||||
'szbDph' => $item->getVat(),
|
||||
];
|
||||
|
||||
// pokud mam flexi ID, tak doplnim vazbu na cenik, sklad a reknu, ze se ma rezervovat
|
||||
if ($itemFlexiId) {
|
||||
$itemData += $this->addFlexiBeeParams($order, $item, $itemFlexiId);
|
||||
}
|
||||
|
||||
return $itemData;
|
||||
}
|
||||
|
||||
protected function addFlexiBeeParams(\Order $order, OrderItem $item, $itemFlexiId): array
|
||||
{
|
||||
$result['cenik'] = $itemFlexiId;
|
||||
$result['sklad'] = $this->getOrderStore(
|
||||
$order,
|
||||
$item->getProductId(),
|
||||
$item->getVariationId()
|
||||
);
|
||||
if ($item->getPieces() > 0 && $order->status_storno != 1) {
|
||||
$result['rezervovat'] = true;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function saveOrderPackageNumber(\Order $order, array $item): void
|
||||
{
|
||||
if (empty($item['doprava'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$packageId = explode(';', $item['doprava']);
|
||||
$packageId = reset($packageId);
|
||||
if (!empty($packageId) && $order->package_id !== $packageId) {
|
||||
// ulozim package id na objekt - napr. kvuli naslednemu odeslani mailu
|
||||
$order->package_id = $packageId;
|
||||
// ulozim package id k objednavce v DB
|
||||
sqlQueryBuilder()
|
||||
->update('orders')
|
||||
->directValues(['package_id' => $packageId])
|
||||
->where(Operator::equals(['id' => $order->id]))
|
||||
->execute();
|
||||
// zaloguju cislo baliku k objednavce
|
||||
$order->logHistory(sprintf('[FlexiBee] Číslo balíku: %s', $packageId));
|
||||
}
|
||||
}
|
||||
|
||||
protected function changeOrderStatus(\Order $order, string $flexiStatus, ?int $status, ?string $orderMessage = null): void
|
||||
{
|
||||
// Chci odessilat jen mail, bez zmeny stavu
|
||||
if ($status === null && $orderMessage !== null) {
|
||||
$order->logHistory('[FlexiBee] Odeslání e-mailu: '.$orderMessage);
|
||||
$order->sendEmail(null, $orderMessage);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Pokud neni co menit, tak jdu pryc
|
||||
if ($status === null || $order->status == $status) {
|
||||
return;
|
||||
}
|
||||
|
||||
// zmenit stav a pripadne odeslat i mail
|
||||
$order->logHistory('[FlexiBee] Změna stavu: '.$flexiStatus);
|
||||
$order->changeStatus($status, null, null, $orderMessage);
|
||||
}
|
||||
|
||||
private function getOrderFirmName(\Order $order, string $type = 'invoice'): string
|
||||
{
|
||||
if (!empty($order->{$type.'_firm'})) {
|
||||
return $order->{$type.'_firm'};
|
||||
}
|
||||
|
||||
return $order->{$type.'_name'}.' '.$order->{$type.'_surname'};
|
||||
}
|
||||
|
||||
protected function getOrderUser(\Order $order): ?int
|
||||
{
|
||||
// registrovany uzivatel
|
||||
if ($flexiUserId = $this->getFlexiUser($order)) {
|
||||
return $flexiUserId;
|
||||
}
|
||||
|
||||
// nejaky default uzivatel ve FlexiBee pro objednavky bez registrace
|
||||
$defaultFlexiUserId = $this->configuration->getOrderConfig()['id_user'] ?? null;
|
||||
if (!empty($defaultFlexiUserId)) {
|
||||
return (int) $defaultFlexiUserId;
|
||||
}
|
||||
|
||||
// pokud nechteji pouzivat default uzivatele (napr. kvuli tomu, ze by ty udaje byly videt na fakture ve FlexiBee), tak musim
|
||||
// do FlexiBee zapsat i uzivatele bez registrace - primarne je to kvuli rezervacim, protoze bez uzivatele se ve FlexiBee neudela rezervace
|
||||
if (!($flexiUserId = $this->flexiBeeApi->getUserIdByCode('WPJ-ORDER'.$order->id))) {
|
||||
$flexiUserId = $this->userSynchronizer->processUserToFlexiBee(
|
||||
$this->userSynchronizer->getOrderUserData($order)
|
||||
);
|
||||
}
|
||||
|
||||
return $flexiUserId;
|
||||
}
|
||||
|
||||
protected function getOrderCentral(\Order $order): ?int
|
||||
{
|
||||
if ($centralId = ($this->configuration->getOrderConfig()['central'] ?? null)) {
|
||||
return (int) $centralId;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getOrderStore(\Order $order, int $productId, ?int $variationId = null): ?int
|
||||
{
|
||||
$storeId = sqlQueryBuilder()
|
||||
->select('id_store')
|
||||
->from('stores_items')
|
||||
->where(Operator::equalsNullable(['id_product' => $productId, 'id_variation' => $variationId]))
|
||||
->execute()->fetchOne();
|
||||
|
||||
if (!$storeId) {
|
||||
$storeId = sqlQueryBuilder()
|
||||
->select('id_store')
|
||||
->from('stores_items')
|
||||
->where(Operator::equalsNullable(['id_product' => $productId]))
|
||||
->execute()->fetchOne();
|
||||
}
|
||||
|
||||
if ($storeId) {
|
||||
return $this->flexiBeeUtil->getFlexiId(StoreSynchronizer::getType(), (int) $storeId);
|
||||
}
|
||||
|
||||
return $this->getDefaultStoreId($order);
|
||||
}
|
||||
|
||||
private function isOrderDeliveryAddressSame(\Order $order): bool
|
||||
{
|
||||
$invoice = [$order->invoice_firm, $order->invoice_name, $order->invoice_country, $order->invoice_street, $order->invoice_city, $order->invoice_zip];
|
||||
$delivery = [$order->delivery_firm, $order->delivery_name, $order->delivery_country, $order->delivery_street, $order->delivery_city, $order->delivery_zip];
|
||||
|
||||
return $invoice === $delivery;
|
||||
}
|
||||
|
||||
protected function getDefaultStoreId(\Order $order): ?int
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getFlexiUser(\Order $order): ?int
|
||||
{
|
||||
if ($order->id_user) {
|
||||
$flexiId = sqlQueryBuilder()
|
||||
->select('id_flexi')
|
||||
->from('flexi_users')
|
||||
->where(Operator::equals(['id_user' => $order->id_user]))
|
||||
->execute()->fetchOne();
|
||||
|
||||
if ($flexiId) {
|
||||
return (int) $flexiId;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getPaymentStatus(\Order $order): ?string
|
||||
{
|
||||
if ($deliveryType = $order->getDeliveryType()) {
|
||||
$payment = $deliveryType->getPayment();
|
||||
|
||||
if ($payment instanceof \Hotovost) {
|
||||
if ($order->isPaid()) {
|
||||
return 'stavUhr.uhrazenoRucne';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getPaymentTypeCode(\Order $order): string
|
||||
{
|
||||
if ($deliveryType = $order->getDeliveryType()) {
|
||||
if ($code = ($this->configuration->getPaymentsConfig()[$deliveryType->id_payment] ?? false)) {
|
||||
return 'code:'.$code;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function getDeliveryTypeCode(\Order $order): string
|
||||
{
|
||||
if ($deliveryType = $order->getDeliveryType()) {
|
||||
$delivery = $deliveryType->getDelivery();
|
||||
|
||||
if ($code = ($this->configuration->getDeliveriesConfig()[$delivery->id] ?? false)) {
|
||||
return 'code:'.$code;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function getBaseOrdersQueryBuilder(): QueryBuilder
|
||||
{
|
||||
return sqlQueryBuilder()
|
||||
->select('o.id, fo.id_flexi, fo.data')
|
||||
->from('orders', 'o')
|
||||
->leftJoin('o', 'flexi_orders', 'fo', 'fo.id_order = o.id');
|
||||
}
|
||||
|
||||
protected function preprocessChangedItems(array $items): array
|
||||
{
|
||||
// nafetchuju polozky objednavek pokud mam zapnutou obousmernou synchronizaci
|
||||
if (($this->configuration->getOrderConfig()['duplex_sync'] ?? false) === 'Y') {
|
||||
if (!empty($items)) {
|
||||
$orderItems = $this->flexiBeeApi->getOrdersItems(array_map(fn ($x) => $x['id'], $items));
|
||||
foreach ($items as &$item) {
|
||||
$item['items'] = $orderItems[$item['id']] ?? [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
private function getOrderMessageNameById(int $orderMessageId): ?string
|
||||
{
|
||||
static $orderMessageCache = [];
|
||||
|
||||
if (($orderMessageCache[$orderMessageId] ?? false) === false) {
|
||||
$orderMessageName = sqlQueryBuilder()
|
||||
->select('name')
|
||||
->from('emails')
|
||||
->where(Operator::equals(['id' => $orderMessageId]))
|
||||
->execute()->fetchOne();
|
||||
|
||||
if (!$orderMessageName) {
|
||||
$orderMessageName = null;
|
||||
}
|
||||
|
||||
$orderMessageCache[$orderMessageId] = $orderMessageName;
|
||||
}
|
||||
|
||||
return $orderMessageCache[$orderMessageId];
|
||||
}
|
||||
|
||||
protected function getItemId(\Order $order, OrderItem $item): string
|
||||
{
|
||||
return 'ext:OBP-POL-ESHOP:'.$order->order_no.'-'.$item->getId();
|
||||
}
|
||||
|
||||
public function getOrderDate(\Order $order): string
|
||||
{
|
||||
return $order->date_created->format('Y-m-d');
|
||||
}
|
||||
|
||||
protected function getDocumentType(\Order $order): string
|
||||
{
|
||||
return 'OBP';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user