'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)));
}
}