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('
', 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'; } }