'processOrder', 'ObjednavkyZmenyStavu' => 'processOrderStatusChange', 'Posta' => 'processOrderTracking', 'Doklady' => 'processOrderDocument', ]; } public function useTestConnection(): bool { return !$this->configuration->useProductionHelios(); } public function processToHelios(): void { $this->processOrdersToHelios(); $this->processPaidOrdersToHelios(); } /** * Funkce, která zaktualizuje objednávky ve stavu chyba do stavu přijatá, aby se zkusily znovu odeslat do Heliosu. * Spoouští se každou hodinu. */ public function updateOrdersInErrorState(): void { $orderList = $this->getOrderList(); $orderList->andSpec(Operator::andX( // neni v heliosu Operator::equalsNullable(['zo.id_znz' => null]), // a je ve stavu chyba Operator::equals(['o.status' => $this->configuration->getOrderErrorStatus()]) )); foreach ($orderList->getOrders() as $order) { // nastavim znzTry na 1, aby se resetoval pocet pokusu $order->setData('znzTry', 1); // zmenim stav na 0, aby se objednavka zkusila znovu zapsat $order->changeStatus( 0, '[Helios] Objednávka byla automaticky přepnuta ze stavu "chyba" do stavu "přijatá", aby se zkusila znovu zapsat do Heliosu', false ); } } public function getOrderData(\Order $order): array { $deliveryTypeInfo = $this->getOrderDeliveryTypeInfo($order); $customerId = null; $customerEmail = $order->invoice_email; if ($order->id_user) { $customerId = QueryHint::withRouteToMaster(fn () => $this->znzUtil->getZNZId(UserSynchronizer::getType(), $order->id_user)); if ($userEmail = $order->getUser()?->email) { $customerEmail = $userEmail; } } $orderLanguage = Contexts::get(LanguageContext::class)->getAll()[$order->getLanguage()] ?? null; $dropshipmentId = null; if ($order->dropshipmentInfo['dropshipment']['id'] ?? false) { $dropshipmentId = $order->dropshipmentInfo['dropshipment']['id']; } $orderData = [ 'entity_id' => (int) $order->id, 'increment_id' => $this->getOrderNumber($order), 'created_at' => $order->date_created->format('Y-m-d\TH:i:s'), 'ZabalitBezFaktury' => isset($order->getFlags()['OEI']), 'IdLanguage' => $orderLanguage?->getLocale() ?? 'cs_CZ', 'WPJ_dropshipID' => $dropshipmentId, 'WPJ_zdroj' => $order->source, 'url' => $this->getOrderUrl($order), 'store_id' => $this->getOrderStoreId($order), 'customer_is_guest' => $customerId ? 0 : 1, 'customer_email' => $customerEmail, 'customer_id' => $customerId, 'order_id_customer' => $this->getOrderCustomerNumber($order), 'order_currency_code' => $order->getCurrency(), 'shipping_method' => $this->getOrderShippingMethod($order), 'payment_method' => $this->getOrderPaymentMethod($order), 'shipping_incl_tax' => $deliveryTypeInfo['deliveryPrice'], 'shipping_description' => $order->delivery_type, 'transaction_fee' => $deliveryTypeInfo['paymentPrice'], 'total_due' => $this->getOrderTotalPrice($order, $deliveryTypeInfo), 'id_zakaznik' => null, 'id_dodaci' => null, 'customer_note' => '', 'note_public' => $order->note_user, // 'rada' => '', 'address' => $this->getOrderAddresses($order), 'item' => [], ]; /** @var OrderItem $item */ foreach ($order->fetchItems() as $item) { if ($this->orderItemInfo->getItemType($item) === OrderItemInfo::TYPE_DELIVERY) { continue; } $itemData = $this->getNonProductItemData($order, $item); $setData = $item->getNote()['setData'] ?? []; $isSet = !empty($setData); $sets = $isSet ? $this->getProductSets($item->getProduct()) : []; $orderData['item'][] = [ 'item' => [ 'order_id' => (int) $order->id, 'item_id' => $item->getId(), 'parent_id' => null, 'product_type' => $isSet ? 'bundle' : 'simple', 'sku' => $item->getCode() ?: $itemData['code'] ?? null, 'name' => $item->getDescr(), 'qty_ordered' => $item->getPieces(), 'price' => $isSet ? 0 : $this->getOrderItemPrice($item, false), 'tax_percent' => $item->getVat(), 'price_incl_tax' => $isSet ? 0 : $this->getOrderItemPrice($item), 'source_code' => $this->getOrderItemStoreId($order, $item) ?: $itemData['sourceCode'] ?? null, 'price_debug' => $this->getOrderItemPriceDebug($order, $item), ], ]; $setProductTotalPrice = \DecimalConstants::zero(); // pokud se jedna o set, tak zapisu i polozky setu, ktere maji pomerove rozpadlou cenu foreach ($setData as $setProductId => $setItem) { $piecePrice = toDecimal(toDecimal($setItem['piecePrice'])->printFloatValue(-2)); $setProduct = $sets[$setProductId] ?? null; $setProductTotalPrice = $setProductTotalPrice->add($piecePrice); // pokud je to posledni polozka if (array_key_last($setData) === $setProductId) { // pokud tam vznikl nejaky rozdil kvuli roundingu, tak ho posledni polozkou opravim $diff = $item->getPiecePrice()->getPriceWithVat()->sub($setProductTotalPrice); if (!$diff->isZero()) { $piecePrice = $piecePrice->add($diff); } } $code = $setProduct ? $setProduct->code : null; if ($setProduct instanceof \Variation && !empty($setProduct->variationCode)) { $code = $setProduct->variationCode; } $orderData['item'][] = [ 'item' => [ 'order_id' => (int) $order->id, 'item_id' => null, 'parent_id' => $item->getId(), 'product_type' => 'simple', 'sku' => $code, 'name' => $setProduct ? $setProduct->title : $item->getDescr(), 'qty_ordered' => $setItem['pieces'], 'price' => $piecePrice->removeVat($item->getVat())->asFloat(), 'tax_percent' => $item->getVat(), 'price_incl_tax' => (float) $piecePrice->printFloatValue(-2), 'source_code' => $this->getOrderItemStoreId($order, $item), ], ]; } } return $orderData; } protected function processOrdersToHelios(): void { if (isLocalDevelopment()) { return; } $orderList = $this->getOrderList(); $orderList->fetchDropshipmentInfo(); $orderList->andSpec(function () { return Operator::andX( // objednavka jeste neni nahrana do Heliosu Operator::equalsNullable(['zo.id_znz' => null]), // objednavka neni stornovana Operator::equals(['o.status_storno' => 0]), // objednavka nesmi byt ve stavu chyba Operator::not( Operator::equals(['o.status' => $this->configuration->getOrderErrorStatus()]) ) ); }); // use withRouteToMaster to avoid `Duplicate entry` errors for znz_orders table $orders = QueryHint::withRouteToMaster(fn () => $orderList->getOrders()); foreach ($orders as $order) { // pocet pokusu, kolikrat se objednavka zkusila zapsat do Heliosu if (!($try = $order->getData('znzTry'))) { $try = 1; } try { $znzId = $this->createOrderToHelios($order); } catch (\Throwable $e) { $this->logger->log($e, data: ['try' => $try]); if ($e instanceof ZNZException) { $order->setData('znzTry', ++$try); if ($try > 9) { $order->changeStatus( $this->configuration->getOrderErrorStatus(), sprintf('[Helios] Objednávku se nepodařilo zapsat do Heliosu. Chyba: %s', $e->getMessage()), false ); } } } } } public function getOrderPaymentData(\Order $order): array { $payment = $order->getDeliveryType()->getPayment(); $payments = $order->getPaymentsArray(); if (empty($payments)) { return []; } $paymentsData = []; $transactionsData = []; foreach ($payments as $paymentInfo) { $paymentData = json_decode($paymentInfo['payment_data'] ?: '', true) ?: []; // add payment data $paymentsData[] = [ 'item' => [ 'entity_id' => $paymentInfo['id'], 'method' => $payment->getCustomData()['id_znz'] ?? $payment->getName(), ], ]; // pokud je platba dokoncena, tak posilame is_closed=1, jinak je is_closed=0 $isClosed = $paymentInfo['status'] === \Payment::STATUS_FINISHED ? 1 : 0; // add transaction data $transactionsData[] = [ 'item' => [ 'transaction_id' => $paymentInfo['id'], 'payment_id' => $paymentInfo['id'], 'txn_id' => $paymentData['transactionID'] ?? $paymentData['session'] ?? $paymentInfo['id'], 'created_at' => $paymentInfo['date']->format('Y-m-d\TH:i:s'), 'is_closed' => (string) $isClosed, 'additional_information' => json_encode([ 'raw_details_info' => [ 'sum' => (float) $paymentInfo['price'], 'fee' => 0, 'currency' => $order->getCurrency(), 'transaction_date' => $paymentInfo['date']->format('Y-m-d\TH:i:s'), ], ]), ], ]; } return [ 'GUIDObjednavka' => $this->znzUtil->getZNZId(static::getType(), $order->id), 'entity_id' => (int) $order->id, 'increment_id' => $this->getOrderNumber($order), 'store_id' => $this->getOrderStoreId($order), 'customer_id' => $order->id_user ? (int) $order->id_user : null, 'customer_note' => $order->note_user, 'payment' => $paymentsData, 'transaction' => $transactionsData, ]; } public function createOrderToHelios(\Order $order): string { $znzId = $this->getZNZApi()->createOrder( $this->getOrderData($order) ); // ulozim si mapping objednavky $this->znzUtil->createMapping(static::getType(), $znzId, (int) $order->id); // zmenim stav objednavky na "potvrzena" $order->changeStatus(1, sprintf('[Helios] Objednávka byla úspěšně nahrána do Heliosu; ID: %s;', $this->getZNZIdInHex($znzId)), false); return $znzId; } protected function processPaidOrdersToHelios(): void { if (isLocalDevelopment()) { return; } $orderList = $this->getOrderList(); $orderList->andSpec(function () { return Operator::andX( // pouze platba prevodem nebo platba online Order::byPaymentMethods([\Payment::METHOD_TRANSFER, \Payment::METHOD_ONLINE]), // objednavka neni vyrizena Operator::inIntArray(getStatuses('nothandled'), 'o.status'), // objednavka je zapsana v Heliosu 'zo.id_znz IS NOT NULL', // objednavka neni stornovana Operator::equals(['o.status_storno' => 0]), // objednavka je zaplacena Operator::equals(['o.status_payed' => 1]), // objednavka jeste neni zaplacena v Heliosu 'JSON_VALUE(zo.data, "$.paidSent") IS NULL' ); }); foreach ($orderList->getOrders() as $order) { try { $paymentData = $this->getOrderPaymentData($order); // pokud nemam payment data tak je to asi importovana objednavka z Heliosu (nemam payments, ale status_payed=1) if (empty($paymentData)) { $this->setOrderMappingData($order->id, ['paidSent' => true]); continue; } $result = $this->getZNZApi()->updateOrderPaymentStatus($paymentData); if ($result) { $this->setOrderMappingData($order->id, ['paidSent' => true]); $order->logHistory('[Helios] Byla odeslána informace o zaplacení objednávky do Heliosu'); } } catch (\Throwable $e) { $this->logger->log($e, 'Nepodařilo se aktualizovat stav zaplacení u objednávky: '.$order->order_no, [ 'orderId' => $order->id, ]); } } } protected function processOrder(array $item): void { if (!($order = $this->getOrderByItem($item))) { $this->createOrderFromHelios($item); return; } $orderId = $order->id; $activityLogErrors = []; // opravit jazyk pokud je na shopu spatne u historickych objednavek spatne if ($order->source === OrderInfo::ORDER_SOURCE_IMPORT) { $language = $this->getOrderLanguageByWebsite($item); if ($order->id_language != $language) { sqlQueryBuilder() ->update('orders') ->directValues(['id_language' => $language]) ->where(Operator::equals(['id' => $orderId])) ->execute(); } } // aktualizace zpusobu doruceni $this->updateOrderDeliveryTypeByHelios($order, $item, $activityLogErrors); $update = []; $updateLog = []; $addUpdateLog = function (string $message, ?OrderItem $item = null) use (&$updateLog) { if ($item) { $message = 'Položka '.$item->getId().': '.$message; } $updateLog[] = $message; }; // detekce zmeny mailu if (!empty($item['email']) && $item['email'] !== $order->invoice_email) { $update['invoice_email'] = $item['email']; $addUpdateLog(sprintf('Aktualizace e-mailu: %s -> %s', $order->invoice_email, $item['email'])); } // detekce zmen v adrese foreach ($item['Adresy'] ?? [] as $heliosAddress) { $userName = $this->znzUtil->getUserNameParts($heliosAddress['Nazev']); // pokud je tam jen predcisli, tak to rovnou vyprazdnim if (preg_match('/^\+(\d{1,3})$/', $heliosAddress['Telefon'] ?? '')) { $heliosAddress['Telefon'] = ''; } $prefix = 'invoice_'; if ($heliosAddress['TypAdresy'] !== 'billing') { $prefix = 'delivery_'; } $heliosAddressParts = [ $prefix.'name' => $userName['name'], $prefix.'surname' => $userName['surname'], $prefix.'phone' => $heliosAddress['Telefon'] ?? '', $prefix.'firm' => $heliosAddress['DruhyNazev'], $prefix.'city' => $heliosAddress['Misto'], $prefix.'zip' => $heliosAddress['PSC'], $prefix.'street' => $heliosAddress['Ulice'], $prefix.'country' => $this->znzUtil->getCountryCodeByHelios($heliosAddress['IdZeme'] ?? Contexts::get(CountryContext::class)->getDefaultId()), ]; $shopAddressParts = [ $prefix.'name' => $order->{$prefix.'name'}, $prefix.'surname' => $order->{$prefix.'surname'}, $prefix.'phone' => $order->{$prefix.'phone'}, $prefix.'firm' => $order->{$prefix.'firm'}, $prefix.'city' => $order->{$prefix.'city'}, $prefix.'zip' => $order->{$prefix.'zip'}, $prefix.'street' => $order->{$prefix.'street'}, $prefix.'country' => $this->znzUtil->getCountryCodeByHelios($order->{$prefix.'country'}), ]; if (array_diff($shopAddressParts, $heliosAddressParts)) { $update = array_merge($update, $heliosAddressParts); $addUpdateLog( sprintf('Aktualizace adresy \'%s\': %s -> %s', $heliosAddress['TypAdresy'], implode(';', $shopAddressParts), implode(';', $heliosAddressParts)) ); } } // aktualizace polozek objednavky if ($this->updateOrderItems($order, $item)) { $addUpdateLog( 'Provedena aktualizace položek objednávky' ); } if (!empty($update)) { sqlQueryBuilder() ->update('orders') ->directValues($update) ->where(Operator::equals(['id' => $orderId])) ->execute(); } // GUID objednavky, ktera byla do tehle aktualni objednavky sloucena if (!empty($item['GUIDObjednvkaSlouceno'])) { if ($oldOrderId = $this->znzUtil->getMapping(static::getType(), $item['GUIDObjednvkaSlouceno'])) { // pokud jsme mergnuti plateb jeste neprovedli, tak ho provedeme. Ale nechceme ho provadet furt, tak to takhle ifneme if (!$this->getOrderMappingData($orderId, 'mergedWithOrder')) { $paymentIds = array_map(fn ($x) => $x['id'], sqlQueryBuilder() ->select('id') ->from('order_payments') ->where(Operator::equals(['id_order' => $oldOrderId])) ->execute()->fetchAllAssociative()); // pokud jsou u puvodni objednavky nejake platby if (!empty($paymentIds)) { // prenesu platbu od puvodni objednavky k aktualni objednavce sqlQueryBuilder() ->update('order_payments') ->directValues(['id_order' => $orderId]) ->where(Operator::equals(['id_order' => $oldOrderId])) ->execute(); $addUpdateLog('Platba: K této objednávce byla přenesena platba od objednávky '.$oldOrderId.''); $order->updatePayments(); } $this->setOrderMappingData($orderId, ['mergedWithOrder' => $oldOrderId]); } } } // detekce zaplaceni / odznaceni zaplaceni QueryHint::withRouteToMaster(fn () => $this->updateOrderPayments($order, $item)); if (!empty($updateLog)) { $order->logHistory( implode('
', array_merge( ['[Helios] Provedeny změny v objednávce'], $updateLog )) ); } if (!empty($activityLogErrors)) { $this->logger->activity( sprintf('Během aktualizace objednávky "%s" z Heliosu se vyskytly chyby: %s', $order->order_no, count($activityLogErrors)), [ 'orderId' => $orderId, 'errors' => $activityLogErrors, ] ); } } protected function processOrderStatusChange(array $item): void { if (!($order = $this->getOrderByItem($item))) { return; } $maxStatusId = $order->getData('znzStatusMaxId'); // starsi zmena, ktera nas uz nezajima, protoze mame novejsi if ($maxStatusId && $maxStatusId >= $item['meta']['id_change']) { return; } $order->setData('znzStatusMaxId', $item['meta']['id_change']); $heliosStatus = $item['StavNovy3'] ?? null; if ($heliosStatus === null) { return; } // storno objednavky je pod stavem s ID 99 if ($heliosStatus === 99) { if ($order->status_storno == 0) { $order->storno(false); $order->logHistory('[Helios] Objednávka byla stornována'); } // pokud nema nastaveny i stav "stornovana", tak ho nastavim if ($order->status != $this->configuration->getOrderStornoStatus()) { $order->changeStatus( $this->configuration->getOrderStornoStatus(), forceSendMail: false ); } return; } // ostatni ID stavu by mely odpovidat nasemu ID stavu (config.php) // pokud je to teda neznamy stav, tak nic neudelam... aspon zaloguju chybu do activity logu if ((getOrderStatuses()[$heliosStatus] ?? false) === false) { throw new ZNZException( 'Unable to update order status: Unknown status ID "'.$heliosStatus.'"!', $item ); } // pokud je stav jiny, nez mame na e-shopu, tak provedeme zmenu stavu if ($order->status != $heliosStatus) { $order->changeStatus($heliosStatus, sprintf('[Helios] Změna stavu objednavky: %s -> %s', $order->status, $heliosStatus), false); } } protected function processOrderTracking(array $item): void { if (!($order = $this->getOrderByItem($item))) { return; } // package ids that are already set on order object $packages = explode(',', $order->package_id ?: ''); // package id from Helios $packageId = $item['Znacka'] ?? null; $isStorno = ($item['JeStorno'] ?? 0) == 1; // nothing to save if (empty($packageId)) { return; } // already have the package id saved, so i dont need to save it again if (($key = array_search($packageId, $packages)) !== false) { // package id storno if ($isStorno) { // remove package id from packages unset($packages[$key]); // remove tracking URL $trackingUrls = $order->getData('znzTrackingUrls') ?: []; unset($trackingUrls[$packageId]); $order->setData('znzTrackingUrls', $trackingUrls); // update package ids $order->setPackageId(implode(',', array_filter($packages))); $order->logHistory('[Helios] Storno čísla balíku: '.$packageId); } return; } // package id storno, nothing to do if ($isStorno) { return; } $packages[] = $packageId; if (!empty($item['TrackURL'])) { $order->setData('znzTrackingUrl', $item['TrackURL']); // set package id to znzTrackingUrls array (znzTrackingUrls are not used) $trackingUrls = $order->getData('znzTrackingUrls') ?: []; $trackingUrls[$packageId] = $item['TrackURL']; $order->setData('znzTrackingUrls', $trackingUrls); } // save package id $order->setPackageId(implode(',', array_filter($packages))); $order->logHistory('[Helios] Číslo balíku: '.$packageId); } public function processOrderDocument(array $item): void { // pokud se jedna o delete message if ($this->isDeleteMessage($item)) { $documentId = $item['meta']['unique_id']; // najdu si objednavku podle ID dokladu $orderId = sqlQueryBuilder() ->select('id') ->from('orders') ->where('JSON_EXTRACT(note_admin, \'$.znzDocuments."'.$documentId.'"\') IS NOT NULL') ->execute()->fetchOne(); // pokud jsem nasel objednavku, tak provedu odebrani dokladu if ($orderId) { $order = \Order::get($orderId); $documents = $order->getData('znzDocuments') ?: []; // pokud mam ulozenej doklad, tak provedu jeho odebrani if ($documents[$documentId] ?? false) { unset($documents[$documentId]); $order->setData('znzDocuments', $documents); // zaloguju info o odebrani dokladu $order->logHistory(sprintf('[Helios] Doklad "%s" byl od objednávky odebrán', $documentId)); } } return; } if (!($order = $this->getOrderByItem($item))) { return; } $documents = $order->getData('znzDocuments'); // doklad uz existuje, takze nemusim nic delat if ($documents[$item['IdDoklad']] ?? false) { return; } $filePath = ltrim($item['URL'], '\\'); // ulozim doklad $documents[$item['IdDoklad']] = [ 'type' => $item['DruhDokladu'], 'path' => $filePath, ]; $order->setData('znzDocuments', $documents); $documentUrl = $this->contextManager->activateOrder($order, fn () => path('kupshop_orderingbundle_pdfinvoice', ['id_order' => $order->id, 'cf' => $order->getSecurityCode(), 'documentId' => $item['IdDoklad']], Router::ABSOLUTE_URL)); // zaloguju info k objednavce o dokladu $order->logHistory( sprintf( '[Helios] Doklad "%s": %s', $item['IdDoklad'], $documentUrl, $filePath ) ); if (!empty($item['Splatnost'])) { try { $dateDue = new \DateTime($item['Splatnost']); } catch (\Throwable) { $dateDue = null; } sqlQueryBuilder() ->update('orders') ->directValues(['date_due' => $dateDue?->format('Y-m-d H:i:s')]) ->where(Operator::equals(['id' => $order->id])) ->execute(); } } protected function updateOrderPayments(\Order $order, array $item): void { // pokud objednavka nema cenu, tak nemam co updatovat if ($item['Celkem'] <= 0) { return; } $orderPaymentMethod = null; // kvuli rychlosti pri vytvareni objednavek z Heliosu if ($order->getDeliveryId()) { $deliveryType = \DeliveryType::get( $order->getDeliveryId(), true ); $orderPaymentMethod = $deliveryType?->getPayment()?->getPayMethod(); } // pokud se jedna o platbu online if ($orderPaymentMethod && in_array($orderPaymentMethod, [\Payment::METHOD_TRANSFER, \Payment::METHOD_ONLINE])) { // nebudu odebirat zaplaceni, dela to akorat bordel if ($order->isPaid(true) && $item['Zaplaceno'] !== true) { return; } } // pokud se jedna o platbu online nebo prevodem a jeste nebylo do Heliosu odeslana informace o zaplaceni if ($orderPaymentMethod && in_array($orderPaymentMethod, [\Payment::METHOD_TRANSFER, \Payment::METHOD_ONLINE]) && !$this->getOrderMappingData($order->id, 'paidSent')) { // pokud prislo, ze objednavka neni zaplacena, ale na e-shopu je zaplacena, tak skocim pryc // protoze jinak se stalo to, ze zakaznik zaplatil objednavku a mezitim nez se do Heliosu odeslala informace // o zaplaceni, tak prisla zmena z Heliosu, kde nebyla zaplacena a od objednavky se tak odebrala platba if ($order->isPaid(true) && $item['Zaplaceno'] !== true) { return; } } // pokud objednavka na shopu neni zaplacena a v Heliosu ji oznacili jako zaplacenou if ($item['Zaplaceno'] === true && !$order->isPaid(true)) { sqlQueryBuilder() ->delete('order_payments') ->where(Operator::equals(['id_order' => $order->id, 'note' => 'Zaplaceno z Heliosu'])) ->execute(); $order->insertPayment($order->getTotalPrice()->getPriceWithVat(), 'Zaplaceno z Heliosu', null, true); $this->setOrderMappingData($order->id, ['paidSent' => true]); if ($order->status <= 1) { $order->changeStatus(1, '[Helios] Objednávka byla zaplacena', false); } else { $order->logHistory('[Helios] Objednávka byla zaplacena'); } } // pokud objednavka na shopu je zaplacena a v Heliosu ji oznacili jako nezaplacenou if ($item['Zaplaceno'] === false && $order->isPaid(true)) { $order->insertPayment(toDecimal($order->getPayments())->mul(\DecimalConstants::negativeOne()), 'Odebráno zaplacení z Heliosu', null, true); $order->logHistory('[Helios] Objednávce bylo odebráno zaplacení'); } } protected function getOrderItemPriceDebug(\Order $order, OrderItem $item): ?string { $keysToExport = ['priceWithoutDiscounts', 'totalDiscount', 'discounts']; $result = []; foreach ($item->getNote() as $key => $note) { if (!in_array($key, $keysToExport)) { continue; } $result[$key] = $note; } return !empty($result) ? json_encode($result) : null; } protected function getOrderTotalPrice(\Order $order, array $deliveryTypeInfo): float { return $order->getTotalPrice()->getPriceWithVat()->asFloat(); } protected function getOrderUrl(\Order $order): string { return $this->contextManager->activateOrder($order, fn (): string => $order->getUrl()); } protected function getOrderStoreId(\Order $order): ?int { $storeIds = $this->configuration->getSettings()['order']['storeId'] ?? []; $storeId = $storeIds[$order->getLanguage()] ?? null; if (!empty($storeId)) { return (int) $storeId; } return null; } protected function getOrderNumber(\Order $order): string { return $this->znzUtil->getOrderNumberWithPrefix($order); } protected function getOrderCustomerNumber(\Order $order): ?string { if (isset($order->dropshipmentInfo['external']['id'])) { return $order->dropshipmentInfo['external']['id']; } return $order->user_order_no ?: null; } protected function getNonProductItemData(\Order $order, OrderItem $item): ?array { if ($item->getProductId()) { return null; } if ($this->orderItemInfo->getItemType($item) === OrderItemInfo::TYPE_DISCOUNT) { if (!empty($item->getNote()['generated_coupon'])) { return [ 'code' => '5', 'sourceCode' => $this->getDefaultSourceCode($order), ]; } else { // fallback pokud se do objednavky dostane nejaka neproduktova polozka (sleva) return [ 'code' => '1', 'sourceCode' => $this->getDefaultSourceCode($order), ]; } } if ($this->orderItemInfo->getItemType($item) === OrderItemInfo::TYPE_CHARGE) { foreach ($order->fetchItems() as $orderItem) { if (empty($orderItem->getNote()['generated_coupon'])) { continue; } if (str_starts_with($item->getDescr(), $orderItem->getDescr())) { return [ 'code' => '5', 'sourceCode' => $this->getDefaultSourceCode($order), ]; } } } return []; } protected function getOrderItemStoreId(\Order $order, OrderItem $item): ?string { if (!$item->getProductId()) { return null; } $storeId = $this->znzOrderUtil->getOrderStoreId($order); if ($storeId && ($znzId = $this->znzUtil->getZNZId('store', $storeId))) { return $znzId; } return null; } protected function getDefaultSourceCode(\Order $order): ?string { if ($store = $this->znzUtil->getDefaultStore($order->getLanguage())) { if ($znzId = $this->znzUtil->getZNZId('store', $store['id'])) { return $znzId; } } return null; } protected function getOrderShippingMethod(\Order $order): string { $delivery = $order->getDeliveryType()->getDelivery(); $znzIdByCountry = $delivery->getCustomData()['id_znz_by_country'] ?? []; if (!empty($znzIdByCountry[$order->delivery_country])) { return $znzIdByCountry[$order->delivery_country]; } $znzIds = explode(',', $delivery->getCustomData()['id_znz'] ?? ''); if (empty($znzIds)) { return ''; } return reset($znzIds); } protected function getOrderPaymentMethod(\Order $order): string { if (!($payment = $order->getDeliveryType()->getPayment())) { return ''; } $znzIds = explode(',', $payment->getCustomData()['id_znz'] ?? ''); if (empty($znzIds)) { return ''; } return reset($znzIds); } protected function getOrderDeliveryTypeInfo(\Order $order): array { $deliveryItem = null; /** @var OrderItem $item */ foreach ($order->fetchItems() as $item) { if ($this->orderItemInfo->getItemType($item) === OrderItemInfo::TYPE_DELIVERY) { $deliveryItem = $item; break; } } $deliveryPrice = \DecimalConstants::zero(); $paymentPrice = \DecimalConstants::zero(); if ($deliveryItem) { return $this->contextManager->activateOrder($order, function () use ($order, $deliveryItem) { $deliveryType = $order->getDeliveryType(); $totalPrice = $order->getPurchaseState()->getTotalPriceForDiscounts(); $deliveryType->accept( new Price( $totalPrice->getPriceWithVat(), $totalPrice->getCurrency(), 0 ), false, $order->getPurchaseState() ); $paymentPrice = PriceCalculator::sub($deliveryItem->getTotalPrice(), $deliveryType->getDelivery()->getPrice()); $deliveryPrice = PriceCalculator::sub($deliveryItem->getTotalPrice(), $paymentPrice); $deliveryPrice = $deliveryPrice->getPriceWithVat(); // pravdepodobne chybka kvuli nejakymu jinymu kurzu meny if ($paymentPrice->getPriceWithVat()->asFloat() <= 0.2) { $paymentPrice = \DecimalConstants::zero(); } else { $paymentPrice = $paymentPrice->getPriceWithVat(); } // asi nejakej problem zaorkouhleni.. ufff rozdelovani delivery itemu na cenu dopravy a platby je trosku narocnejsi :) $diff = $deliveryItem->getTotalPrice()->getPriceWithVat()->sub($deliveryPrice->add($paymentPrice)); if (!$diff->isZero()) { if ($deliveryPrice->isPositive()) { $deliveryPrice = $deliveryPrice->add($diff); } elseif ($paymentPrice->isPositive()) { $paymentPrice = $paymentPrice->add($diff); } } return [ 'deliveryPrice' => $deliveryPrice->asFloat(), 'paymentPrice' => $paymentPrice->asFloat(), ]; }); } return [ 'deliveryPrice' => $deliveryPrice->asFloat(), 'paymentPrice' => $paymentPrice->asFloat(), ]; } protected function updateOrderItems(\Order $order, array $heliosOrder): bool { // pokud se nic nezmenilo, tak nic neprovadim if (!$this->hasHeliosOrderItemsChanged($order, $heliosOrder)) { return false; } // pokud se zmenila celkova cena objednavky, nebo se zmenil celkovy pocet polozek v objednavce, tak provedu aktualizaci polozek sqlGetConnection()->transactional(function () use ($order, $heliosOrder) { $currentItems = Mapping::mapKeys(sqlQueryBuilder() ->select('*') ->from('order_items') ->where(Operator::equals(['id_order' => $order->id])) ->execute(), fn ($k, $v) => [$v['id'], $v]); // smazu polozky objednavky sqlQueryBuilder() ->delete('order_items') ->where(Operator::equals(['id_order' => $order->id])) ->execute(); $this->insertOrderItems( $order->id, Contexts::get(CurrencyContext::class)->getOrDefault($order->getCurrency()), $heliosOrder, $currentItems ); // recalculate order kvůli zpetnemu reimportu polozek z heliosu $order->recalculate(); }); return true; } protected function getOrderAddresses(\Order $order): array { $delivery = $order->getDeliveryType()->getDelivery(); $deliveryData = $order->getData('delivery_data'); $invoiceCompany = [$order->invoice_firm]; if (!empty($order->invoice_custom_address)) { $invoiceCompany[] = $order->invoice_custom_address; } $invoiceCompany = array_unique($invoiceCompany); $deliveryCompany = [$order->delivery_firm]; if ($delivery instanceof \DHLServicePoint) { $deliveryCompany = []; } if (!empty($order->delivery_custom_address)) { $deliveryCompany[] = $order->delivery_custom_address; } elseif ($delivery instanceof \DHLServicePoint && ($deliveryData['keyword'] ?? null) === 'Postfiliale') { $order->delivery_street = "{$deliveryData['keyword']} {$deliveryData['harmonisedId']}"; } $deliveryCompany = array_unique($deliveryCompany); $pointId = null; if ($delivery->getType() === \Delivery::TYPE_POINT) { $pointId = $delivery->getPointId(); } return [ [ 'item' => [ 'address_type' => 'billing', 'firstname' => $order->invoice_name, 'middlename' => '', 'lastname' => $order->invoice_surname, 'company' => implode(',', array_filter($invoiceCompany)), 'street' => $order->invoice_street, 'popCislo' => '', 'city' => $order->invoice_city, 'postcode' => $order->invoice_zip, 'region_id' => $order->invoice_state, 'country_id' => $this->znzUtil->getCountryCodeForHelios($order->invoice_country), 'email' => $order->invoice_email, 'telephone' => $order->invoice_phone, 'helios_company_registration_number' => $order->invoice_ico, 'vat_id' => $order->invoice_dic, 'orcislo' => '', ], ], [ 'item' => [ 'address_type' => 'shipping', 'firstname' => $order->delivery_name, 'middlename' => '', 'lastname' => $order->delivery_surname, 'company' => implode(',', array_filter($deliveryCompany)), 'street' => $order->delivery_street, 'popCislo' => '', 'city' => $order->delivery_city, 'postcode' => $order->delivery_zip, 'region_id' => $order->invoice_state, 'country_id' => $this->znzUtil->getCountryCodeForHelios($order->delivery_country), 'email' => $order->invoice_email, 'telephone' => $order->delivery_phone, 'helios_company_registration_number' => '', 'vat_id' => '', 'orcislo' => '', 'pobox' => $pointId, ], ], ]; } private function hasHeliosOrderItemsChanged(\Order $order, array $heliosOrder): bool { // sortovaci fce, aby oba seznamy byly serazeny stejne $withSorted = function (array $data) { usort($data, function ($a, $b) { return $a['znzId'] <=> $b['znzId']; }); return $data; }; // vytvorim seznam polozek podle Heliosu $compareItemsHelios = $withSorted(array_map( function (array $item) { return [ 'znzId' => $item['RegCis'], 'pieces' => $item['Mnozstvi'], 'price' => $item['Celkem'], ]; }, $heliosOrder['Polozky'] ?? [] )); // vytvorim seznam polozek podle shopu $compareItemsShop = $withSorted(array_map( function (OrderItem $item) use ($order) { $itemData = $this->getNonProductItemData($order, $item); return [ 'znzId' => $item->getCode() ?: $itemData['code'] ?? null, 'pieces' => $item->getPieces(), 'price' => $this->getOrderItemPrice($item), ]; }, array_values($order->getItems()) )); // pokud to neni stejny, tak se neco muselo zmenit return $compareItemsShop != $compareItemsHelios; } private function getProductSets(\Product $product): array { $sets = $product->fetchSets(true); $result = []; foreach ($sets as $set) { $key = $set->id; if ($set instanceof \Variation) { $key .= '/'.$set->variationId; } $result[$key] = $set; } $variationIds = array_filter(array_map(fn ($x) => $x->variationId ?? null, $result)); $variationCodes = sqlQueryBuilder() ->select('id, code') ->from('products_variations') ->where(Operator::inIntArray($variationIds, 'id')) ->execute()->fetchAllAssociativeIndexed(); foreach ($result as $item) { if (!($item instanceof \Variation)) { continue; } $item->variationCode = $variationCodes[$item->variationId]['code'] ?? null; } return $result; } private function createOrderFromHelios(array $item): void { if (!$this->isOrderNumberPrefixForCurrentWebsite($item['IdObjednavka'])) { return; } $orderNumber = $item['IdObjednavka']; if ($this->getOrderByOrderNumber($orderNumber)) { return; } foreach ($this->configuration->getOrderPrefixes() as $prefix) { if (str_starts_with($orderNumber, $prefix)) { $orderNumber = str_replace($prefix, '', $orderNumber); break; } } $userId = null; if (!empty($item['IdZakaznik'])) { $userId = $this->znzUtil->getMapping(UserSynchronizer::getType(), $item['IdZakaznik']); } $data = [ 'id_language' => $this->getOrderLanguageByWebsite($item), 'source' => OrderInfo::ORDER_SOURCE_IMPORT, 'order_no' => $orderNumber, 'id_user' => $userId, 'date_created' => $item['DatumPripadu'], 'currency' => $item['Mena'], 'note_admin' => json_encode([]), 'status' => 1, ]; if (!empty($item['email'])) { $data['invoice_email'] = $item['email']; } foreach ($item['Adresy'] ?? [] as $heliosAddress) { $userName = $this->znzUtil->getUserNameParts($heliosAddress['Nazev']); // pokud je tam jen predcisli, tak to rovnou vyprazdnim if (preg_match('/^\+(\d{1,3})$/', $heliosAddress['Telefon'] ?? '')) { $heliosAddress['Telefon'] = ''; } $prefix = 'invoice_'; if ($heliosAddress['TypAdresy'] !== 'billing') { $prefix = 'delivery_'; } $heliosAddressParts = [ $prefix.'name' => $userName['name'], $prefix.'surname' => $userName['surname'], $prefix.'phone' => $heliosAddress['Telefon'] ?? '', $prefix.'firm' => $heliosAddress['DruhyNazev'], $prefix.'city' => $heliosAddress['Misto'], $prefix.'zip' => $heliosAddress['PSC'] ?? '', $prefix.'street' => $heliosAddress['Ulice'], $prefix.'country' => $this->znzUtil->getCountryCodeByHelios($heliosAddress['IdZeme'] ?? Contexts::get(CountryContext::class)->getDefaultId()), ]; $data = array_merge($data, $heliosAddressParts); } // najdu dopravu a platbu $deliveryId = null; if (!empty($item['ZpusobDopravy'])) { $deliveryId = $this->getDeliveryIdByHeliosId($item['ZpusobDopravy']); } $paymentId = null; if (!empty($item['ZpusobPlatby'])) { $paymentId = $this->getPaymentIdByHeliosId($item['ZpusobPlatby']); } if ($deliveryId && $paymentId) { $data['id_delivery'] = $this->getDeliveryTypeByDeliveryAndPayment($deliveryId, $paymentId); } $currency = Contexts::get(CurrencyContext::class)->getOrDefault($item['Mena']); $order = sqlGetConnection()->transactional(function () use ($item, $data, $currency) { sqlQueryBuilder() ->insert('orders') ->directValues($data) ->execute(); $orderId = (int) sqlInsertId(); $this->insertOrderItems($orderId, $currency, $item); $round = true; if ($currency != 'CZK') { $round = false; } $order = \Order::get($orderId); $order->recalculate(round: $round); $order->logHistory($item['VerejnaPoznamka'] ?? ''); $order->logHistory('[Helios] Vytvořeno synchronizací z Heliosu; ID: '.$this->getZNZIdInHex($item['GUIDObjednavka']).';'); $this->znzUtil->createMapping(static::getType(), $item['GUIDObjednavka'], $orderId); if ($item['Zaplaceno'] === true) { $this->setOrderMappingData($orderId, ['paidSent' => true]); } return $order; }); $this->updateOrderPayments($order, $item); } private function updateOrderDeliveryTypeByHelios(\Order $order, array $item, ?array &$activityLogErrors = null): void { // najdu dopravu a platbu $delivery = null; if (!empty($item['ZpusobDopravy'])) { if (!($delivery = $this->getDeliveryByHeliosId($item['ZpusobDopravy']))) { $activityLogErrors[] = sprintf('Nepodařilo se dohledat dopravu podle ID: %s', $item['ZpusobDopravy']); } } $deliveryId = $delivery ? (int) $delivery->id : null; $paymentId = null; if (!empty($item['ZpusobPlatby'])) { if (!($paymentId = $this->getPaymentIdByHeliosId($item['ZpusobPlatby']))) { $activityLogErrors[] = sprintf('Nepodařilo se dohledat platbu podle ID: %s', $item['ZpusobPlatby']); } } if ($deliveryId && $paymentId) { if ($deliveryTypeId = $this->getDeliveryTypeByDeliveryAndPayment($deliveryId, $paymentId)) { if ($deliveryTypeId != $order->getDeliveryId()) { $previousDeliveryTypeName = $this->getDeliveryTypeName((int) $order->getDeliveryId()); $newDeliveryTypeName = $this->getDeliveryTypeName($deliveryTypeId); sqlQueryBuilder() ->update('orders') ->directValues(['id_delivery' => $deliveryTypeId]) ->where(Operator::equals(['id' => $order->id])) ->execute(); $order->logHistory(sprintf('[Helios] Byl aktualizován způsob doručení: "%s" -> %s', $previousDeliveryTypeName, $newDeliveryTypeName)); } } else { $activityLogErrors[] = [ 'message' => sprintf('Nepodařilo se dohledat způsob doručení pro dopravu "%s" (%s) a platbu "%s" (%s)', $item['ZpusobDopravy'], $deliveryId, $item['ZpusobPlatby'], $paymentId), ]; } } } private function getDeliveryTypeName(int $deliveryTypeId): string { $types = \DeliveryType::getAll(true); if ($deliveryType = ($types[$deliveryTypeId] ?? null)) { return $deliveryType->name; } return ''; } private function insertOrderItems(int $orderId, Currency $currency, array $heliosOrder, ?array $currentItems = null): void { foreach ($heliosOrder['Polozky'] ?? [] as $orderItem) { [$productId, $variationId] = [null, null]; if ($orderItem['IdProdukt'] ?? false) { [$productId, $variationId] = $this->znzUtil->getProductMapping($orderItem['IdProdukt']); } if (!isset($orderItem['Celkem'], $orderItem['Celkem'], $orderItem['CelkemBezDPH'], $orderItem['Mnozstvi'])) { continue; } $itemId = null; $itemData = []; if ($currentItem = ($currentItems[$orderItem['IdObjednavkaPolozka']] ?? false)) { $itemId = $currentItem['id']; $itemData = json_decode($currentItem['note'] ?: '', true) ?: []; } $totalPrice = roundPrice(toDecimal($orderItem['Celkem']), currency: $currency); $totalPriceWithoutVat = toDecimal($orderItem['CelkemBezDPH']); $pieces = toDecimal($orderItem['Mnozstvi']); // pokud ma polozka 0 kusu, tak nema byt v objednavce if ($pieces->isZero()) { continue; } $vat = $this->calculateVat($totalPrice->abs(), $totalPriceWithoutVat->abs()); $insertData = [ 'id_order' => $orderId, 'id_product' => $productId, 'id_variation' => $variationId, 'pieces' => $pieces, 'pieces_reserved' => $orderItem['Mnozstvi'], 'piece_price' => $totalPriceWithoutVat->div($pieces), 'total_price' => $totalPriceWithoutVat, 'tax' => $vat->printFloatValue(2), 'descr' => $orderItem['Nazev'] ?? 'unknown item', 'note' => json_encode(array_merge($itemData, ['heliosGuid' => $orderItem['GUIDObjednavkaPolozka'] ?? null])), ]; if ($itemId) { $insertData['id'] = $itemId; } sqlQueryBuilder() ->insert('order_items') ->directValues($insertData) ->execute(); } $deliveryItem = null; foreach ($currentItems ?: [] as $currentItem) { $note = json_decode($currentItem['note'] ?? '', true) ?: []; if (($note['item_type'] ?? null) === OrderItemInfo::TYPE_DELIVERY) { $deliveryItem = $currentItem; break; } } // insertnout dopravne if (!empty($heliosOrder['DopravneCelkem']) && !empty($heliosOrder['DopravneCelkemBezDPH'])) { $deliveryItemData = [ 'id_order' => $orderId, 'id_product' => null, 'id_variation' => null, 'pieces' => 1, 'pieces_reserved' => 1, 'piece_price' => $heliosOrder['DopravneCelkemBezDPH'], 'total_price' => $heliosOrder['DopravneCelkemBezDPH'], 'tax' => $this->calculateVat(toDecimal($heliosOrder['DopravneCelkem']), toDecimal($heliosOrder['DopravneCelkemBezDPH'])), 'descr' => $deliveryItem ? $deliveryItem['descr'] : 'Dopravné', 'note' => $deliveryItem['note'] ?? '[]', ]; if ($deliveryItem) { $deliveryItemData['id'] = $deliveryItem['id']; } sqlQueryBuilder() ->insert('order_items') ->directValues($deliveryItemData) ->execute(); } } private function getOrderItemPrice(OrderItem $item, bool $withVat = true): float { $roundPrice = true; // pokud je aplikovana sleva, ktera je rozpocitana do polozek, tak chci vracet cenu bez zaorkouhleni, aby obsahovala i desetiny if (($item->getNote()['totalDiscount'] ?? false) && fmod((float) $item->getNote()['totalDiscount'], 1) !== 0.00) { $roundPrice = false; } // pokud je cena mensi jak 1, tak nechci provadet zaorkouhleni if ($item->getPiecePrice()->getPriceWithVat(false)->lowerThan(\DecimalConstants::one())) { $roundPrice = false; } if ($withVat) { return (float) $item->getPiecePrice()->getPriceWithVat($roundPrice)->printFloatValue(2); } return (float) $item->getPiecePrice()->getPriceWithoutVat($roundPrice)->printFloatValue(4); } private function calculateVat(\Decimal $priceWithVat, \Decimal $priceWithoutVat): \Decimal { $vat = \DecimalConstants::zero(); if ($priceWithoutVat->isPositive()) { $vat = $priceWithVat->div($priceWithoutVat)->sub(\DecimalConstants::one())->mul(\DecimalConstants::hundred()); } return toDecimal($vat->printFloatValue(-1)); } private function getDeliveryByHeliosId(string $heliosId): ?\Delivery { $heliosId = mb_strtolower($heliosId); foreach (\DeliveryType::getDeliveries(true) as $delivery) { $znzIds = array_map(fn ($x) => mb_strtolower(trim($x)), explode(',', $delivery->getCustomData()['id_znz'] ?? '')); if (in_array($heliosId, $znzIds)) { return $delivery; } } return null; } private function getDeliveryIdByHeliosId(string $heliosId): ?int { $heliosId = mb_strtolower($heliosId); foreach (\DeliveryType::getDeliveries(true) as $delivery) { $znzIds = array_map(fn ($x) => mb_strtolower(trim($x)), explode(',', $delivery->getCustomData()['id_znz'] ?? '')); if (in_array($heliosId, $znzIds)) { return (int) $delivery->id; } } return null; } private function getPaymentIdByHeliosId(string $heliosId): ?int { $heliosId = mb_strtolower($heliosId); foreach (\DeliveryType::getPayments(true) as $payment) { $data = json_decode($payment['data'] ?: '', true) ?: []; $znzIds = array_map(fn ($x) => mb_strtolower(trim($x)), explode(',', $data['id_znz'] ?? '')); if (in_array($heliosId, $znzIds)) { return (int) $payment['id']; } } return null; } private function getDeliveryTypeByDeliveryAndPayment(int $deliveryId, int $paymentId): ?int { foreach (\DeliveryType::getAll(true) as $deliveryType) { if ($deliveryType->id_delivery == $deliveryId && $deliveryType->id_payment == $paymentId) { return $deliveryType->id; } } return null; } /** * Obecna funkce pro ziskani `Order` objektu z dat zmeny. * * Primarne to kouka na `GUIDObjednavka` pokud existuje (postupne by melo zacit exisovat na vsech zmenach). * Pak to fallbackuje na `IdObjednavka` (postupne by melo zaniknout). */ private function getOrderByItem(array $item): ?\Order { // uprednostuju najiti objednavky podle GUID pokud ho mam v datech if (!empty($item['GUIDObjednavka'])) { if ($orderId = $this->znzUtil->getMapping(self::getType(), $item['GUIDObjednavka'])) { return \Order::get($orderId); } return null; } // fallback na pole IdObjednavka if (!empty($item['IdObjednavka'])) { return $this->getOrderByOrderNumber($item['IdObjednavka']); } // pokud v datech nemam ani jedno, tak hazim chybu at je to videt throw new ZNZException( message: 'Změnu objednávky se nepodařilo zpracovat, protože neobsahuje identifikátor pro načtení objednávky', data: $item ); } private function getOrderByOrderNumber(string $orderNumber): ?\Order { if (!$this->isOrderNumberPrefixForCurrentWebsite($orderNumber)) { return null; } foreach ($this->configuration->getOrderPrefixes() as $prefix) { if (str_starts_with($orderNumber, $prefix)) { $orderNumber = str_replace($prefix, '', $orderNumber); break; } } $orderId = sqlQueryBuilder() ->select('id') ->from('orders') ->where(Operator::equals(['order_no' => $orderNumber])) ->execute()->fetchOne(); if ($orderId) { return \Order::get((int) $orderId); } return null; } private function setOrderMappingData(int $orderId, array $data): void { $currentData = sqlQueryBuilder() ->select('data') ->from('znz_orders') ->where(Operator::equals(['id_order' => $orderId])) ->sendToMaster() ->execute()->fetchOne(); $currentData = json_decode($currentData ?: '', true) ?: []; $currentData = array_merge($currentData, $data); sqlQueryBuilder() ->update('znz_orders') ->directValues(['data' => json_encode($currentData)]) ->where(Operator::equals(['id_order' => $orderId])) ->execute(); } private function getOrderMappingData(int $orderId, string $key): mixed { $currentData = sqlQueryBuilder() ->select('data') ->from('znz_orders') ->where(Operator::equals(['id_order' => $orderId])) ->sendToMaster() ->execute()->fetchOne(); $currentData = json_decode($currentData ?: '', true) ?: []; return $currentData[$key] ?? null; } private function isOrderNumberPrefixForCurrentWebsite(string $number): bool { // pokud nema prefix, tak nekontroluju prefix a vracim true if (is_numeric($number)) { return true; } $prefixes = $this->configuration->getOrderPrefixes(); foreach ($prefixes as $prefix) { // cislo objednavky musi zacinat podporovanym prefixem if (str_starts_with($number, $prefix)) { return true; } } return false; } private function getOrderList(): OrderList { $orderList = clone $this->orderList; $orderList->fetchItems(); $orderList->andSpec(function (QueryBuilder $qb) { $qb->leftJoin('o', 'znz_orders', 'zo', 'zo.id_order = o.id'); }); return $orderList; } private function getEnabledStores(): array { return $this->znzUtil->getEnabledStores(); } private function getLanguageByCountryCode(?string $country): string { $languageContext = Contexts::get(LanguageContext::class); $websites = $this->configuration->getSupportedWebsites(); $website = reset($websites); $languageId = match ($country) { 'SK' => 'sk', 'DE' => 'de', 'FR' => 'fr', 'IT' => 'it', default => $website['language'] ?? $languageContext->getDefaultId(), }; $supported = $languageContext->getAll(); if (!isset($supported[$languageId])) { $languageId = $languageContext->getDefaultId(); } return $languageId; } private function getOrderLanguageByWebsite(array $item): string { if ($website = ($this->configuration->getSupportedWebsites()[$item['IdWebsite']] ?? false)) { $website = $this->configuration->getSupportedWebsites()[$this->configuration->getMainWebsite()]; } $language = $website['language']; // jedna domena podporuje vice jazyku if (is_array($language)) { $language = reset($language); } return $language; } private function getZNZIdInHex(string $znzId): string { return '0x'.mb_strtoupper(bin2hex(base64_decode($znzId))); } }