dropshipment) { return false; } return $this->dropshipment['active'] == 1; } /** * Setup transfer before run. */ public function setup(array $dropshipment): void { $this->tempRestrictions = null; $this->dropshipment = $dropshipment; $this->configuration = $dropshipment['configuration']; } public function isValidRestrictionByTag(\SimpleXMLElement $order): bool { if ($this->tempRestrictions === null) { $drop = $this->dropshipment; if ( ($restrictions = $drop['data']['restrictions'] ?? false) && !empty($restrictions['values']) && !empty($restrictions['tagName']) ) { $values = array_map(fn ($v) => strtolower(trim($v)), explode(',', $restrictions['values'])); $this->tempRestrictions = [$restrictions['tagName'], $values]; } else { $this->tempRestrictions = false; } } if (is_array($this->tempRestrictions)) { [$tagName, $values] = $this->tempRestrictions; $tag = (string) $order->$tagName ?? ''; return !in_array(strtolower($tag), $values, true); } return true; } public function process(): void { $config = $this->getConfiguration(); // zpracovani objednavek z feedu do e-shopu $this->in($config); // zpracovani objednavek z e-shopu k externi sluzbe if ('Y' == ($config['out'] ?? 'N')) { $this->out($config); } } public function getConfiguration(): array { return $this->configuration; } public function getConfigurationVariables(): array { return []; } protected function payDropshipOrder(\Order $order): void { $pay_method = \Payment::METHOD_UNKNOWN; $delivery_type = $order->getDeliveryType(); if ($delivery_type && !empty($delivery_type->payment_class)) { $pay_method = $delivery_type->payment_class->getPayMethod(); } $order->insertPayment( $order->getTotalPrice()->getPriceWithVat(), 'Zaplaceno přes modul dropshipment', null, false, $pay_method ); } protected function findDeliveryType(?int $deliveryId, ?int $paymentId): ?\DeliveryType { $deliveryTypeId = sqlQueryBuilder() ->select('id') ->from('delivery_type') ->where(Operator::equals(['id_delivery' => $deliveryId, 'id_payment' => $paymentId])) ->execute()->fetchOne(); if (!$deliveryTypeId) { return null; } return \DeliveryType::get($deliveryTypeId, true); } protected function loadXML(): ?\SimpleXMLElement { if (!($this->dropshipment['source_url'] ?? null)) { $this->addActivityLog( 'V nastavení dropshipmentu chybí URL pro zdrojový XML soubor', $this->configuration ); return null; } try { $xml = ErrorHandler::call(fn () => simplexml_load_file($this->dropshipment['source_url'])); } catch (\Throwable $e) { if (isLocalDevelopment()) { throw $e; } $this->addActivityLog( 'Nelze stáhnout objednávkový XML feed.', ['error' => $e->getMessage()] ); return null; } return $xml ?: null; } /** * General method for creating an order. Order without items. */ protected function createDropshipOrder(\SimpleXMLElement $xml, array $data): \Order { [$externalId, $externalData] = $this->getExternalData($xml); if ($data['delivery_country'] != '') { $data['delivery_country'] = trim($data['delivery_country']); } if ($data['invoice_country'] != '') { $data['invoice_country'] = trim($data['invoice_country']); } /** @var \Order $order */ $order = sqlGetConnection()->transactional(function () use ($data, $externalId, $externalData) { sqlQueryBuilder() ->insert('orders') ->directValues(array_merge( [ 'source' => OrderInfo::ORDER_SOURCE_DROPSHIP, 'date_updated' => (new \DateTime())->format('Y-m-d H:i:s'), ], $data )) ->execute(); $orderId = (int) sqlInsertId(); // vytvorim mapovani na dropshipment sqlQueryBuilder() ->insert('order_dropshipment') ->directValues( [ 'id_order' => $orderId, 'id_dropshipment' => $this->dropshipment['id'], 'id_external' => $externalId, 'data' => json_encode($externalData), ] )->execute(); $order = \Order::get($orderId); // dispatch order created event - order no is generated in event subscriber $this->eventDispatcher->dispatch(new OrderEvent($order), OrderEvent::ORDER_CREATED); $countryContext = Contexts::get(CountryContext::class); if (!empty($data['delivery_country']) && !isset($countryContext->getAll()[$data['delivery_country']])) { addActivityLog(ActivityLog::SEVERITY_WARNING, ActivityLog::TYPE_SYNC, 'Objednávka s č. '.$order->order_no.' z dropshipmentu byla vytvořena s neznámou zemí.', ['country' => $data['delivery_country']]); } return $order; }); // zalogovat informaci o vytvoreni objednavky $order->logHistory( sprintf('[Dropshipment] %s: %s', $this->dropshipment['id'], $this->dropshipment['name'], $externalId) ); $this->eventDispatcher->dispatch(new DropshipOrderCreatedEvent($order, $this->dropshipment, $xml)); return $order; } /** * General method for updating an order. */ protected function updateDropshipOrder(\Order $order, \SimpleXMLElement $xml): void { throw new \RuntimeException('Order update not implemented'); } /** * Method for checks if order should be imported or not. */ protected function isDropshipOrderValidToImport(\SimpleXMLElement $xml): bool { return $this->isValidRestrictionByTag($xml); } protected function getProductByItem(\SimpleXMLElement $item): array { $code = (string) $item->CODE; $ean = (string) $item->EAN; return $this->getProductByCode($code, $ean); } protected function getProductByCode(?string $code, ?string $ean): array { $notFoundResult = [null, null]; $search = []; if (!empty($code)) { $search['code'] = $code; } if (!empty($ean)) { $search['ean'] = $ean; } if (empty($search)) { return $notFoundResult; } $foundItem = sqlQueryBuilder() ->select('id as id_variation, id_product') ->from('products_variations') ->where(Operator::equals($search, 'OR')) ->execute()->fetchAssociative(); if (!$foundItem) { $foundItem = sqlQueryBuilder() ->select('id as id_product, null as id_variation') ->from('products') ->where(Operator::equals($search, 'OR')) ->execute()->fetchAssociative(); } if ($foundItem) { return [$foundItem['id_product'], $foundItem['id_variation']]; } return $notFoundResult; } protected function getCurrencyInfo(string $currency): CurrencyInfo { $currencyContext = Contexts::get(CurrencyContext::class); // pokud nemam nastaveno konvertovani cen do defaultni meny, tak provadim validaci meny if (!$this->isPriceConvertionEnabled() && !($currencyObject = ($currencyContext->getAll()[$currency] ?? null))) { throw new TransferException( sprintf('Nepodařilo se naimportovat objednávku: měna "%s" není založena v e-shopu', $currency) ); } // pokud nemam currency rate, tak ho zkusim ziskat try { $currencyRate = isset($currencyObject) ? $currencyObject->getRate() : \CNB::getCurrency($currency); } catch (\Exception $e) { throw new TransferException( 'Nepodařilo se naimportovat objednávku: nepodařilo se získat kurz vůči výchozí měně', ['currencyRateError' => $e->getMessage()] ); } if (!isset($currencyObject)) { $currencyObject = $currencyContext->getDefault(); } return new CurrencyInfo($currencyObject, toDecimal($currencyRate)); } protected function convertPrice(\Decimal $price, CurrencyInfo $currencyInfo): \Decimal { // pokud mam zapnut prevod do vychozi meny if ($this->isPriceConvertionEnabled()) { $price = $price->mul($currencyInfo->rate); } return $price; } protected function modifyInsertedOrder(\Order $order, \SimpleXMLElement $orderXml): void { } protected function modifyItem(array $item, \SimpleXMLElement $xmlItem): array { return $item; } protected function getOrderByExternalId(string $externalId): ?\Order { $orderId = sqlQueryBuilder() ->select('id_order') ->from('order_dropshipment') ->where(Operator::equals(['id_external' => $externalId, 'id_dropshipment' => $this->dropshipment['id']])) ->execute()->fetchOne(); if (!$orderId) { return null; } return \Order::get((int) $orderId); } protected function isPriceConvertionEnabled(): bool { return ($this->configuration['prices_to_default_currency'] ?? 'N') === 'Y'; } protected function addActivityLog(string $message, array $data = [], string $severity = ActivityLog::SEVERITY_ERROR): void { addActivityLog( $severity, ActivityLog::TYPE_SYNC, sprintf('[Dropshipment] "%s" (ID: %s): ', $this->dropshipment['name'], $this->dropshipment['id']).$message, $data ); } protected function getLastSyncTime(): ?string { return sqlQueryBuilder() ->select('last_sync') ->from('dropshipment') ->where(Operator::equals(['id' => $this->dropshipment['id']])) ->execute() ->fetchOne(); } protected function getOrdersForUpdate(): QueryBuilder { $qb = sqlQueryBuilder() ->select('o.id as id, od.id_external as id_external') ->from('orders', 'o') ->leftJoin('o', 'order_dropshipment', 'od', 'o.id = od.id_order AND od.id_dropshipment = :dropshipment_id') ->andWhere('o.status_storno = 0') ->andWhere(Operator::not(Operator::equalsNullable(['o.package_id' => null]))) ->setParameter('dropshipment_id', $this->dropshipment['id']) ->groupBy('o.id'); return $qb; } protected function itemCreatedEvent(?\ProductBase $product, int $idVariation, \Decimal $piecePrice, int $pieces, ?array $data, \Order $order): void { if (empty($product)) { return; } $this->eventDispatcher->dispatch(new OrderItemEvent($product, $idVariation, $piecePrice, $pieces, $data, $order), OrderItemEvent::ITEM_CREATED); } /** * Prepares configuration data during save in admin. */ public function prepareConfigurationData(array $data): array { return $data; } /** * Returns array in format: [externalId, data]. */ abstract protected function getExternalData(\SimpleXMLElement $xml): array; abstract protected function getDeliveryTypeByConfiguration(\SimpleXMLElement $order): ?\DeliveryType; }