sapUtil->getItemMapping($item['Matnr']))) { // nemam produkt return; } [$productId, $variationId] = $mapping; $storeId = $this->getStoreId($item); if (!($sapDateUpdated = \DateTime::createFromFormat('YmdHis', (string) $item['Lastupd']))) { $sapDateUpdated = null; } try { $this->updateStoreItem( $storeId, $productId, $variationId, (float) $item['Dispo'], $sapDateUpdated ); } catch (ForeignKeyConstraintViolationException $e) { } } protected function getHandledFields(): array { return [ 'Items' => 'item', ]; } private function getStoreId(array $item): int { static $storeIdCache = []; $shippingPoint = $item['ShippingPoint'] ?? null; if (!$shippingPoint) { throw new SAPException('Shipping point is empty'); } if ($storeIdCache[$shippingPoint] ?? false) { return $storeIdCache[$shippingPoint]; } $storeId = sqlGetConnection()->transactional(function () use ($shippingPoint) { return $this->sapUtil->getMapping(MappingType::STORES, $shippingPoint); }); if (!$storeId) { $storeId = sqlGetConnection()->transactional(function () use ($shippingPoint) { sqlQueryBuilder() ->insert('stores') ->directValues( [ 'name' => 'Shipping point '.$shippingPoint, 'data' => json_encode(['shippingPoint' => $shippingPoint]), ] )->execute(); return (int) sqlInsertId(); }); $this->sapUtil->createMapping(MappingType::STORES, $shippingPoint, $storeId); } return $storeIdCache[$shippingPoint] = $storeId; } public function updateStoreItem(int $storeId, int $productId, ?int $variationId, float $quantity, ?\DateTime $sapDateUpdated = null): void { if (empty($productId)) { return; } $isRestocked = false; if ($storeItem = sqlQueryBuilder() ->select('id, quantity, sap_date_updated') ->from('stores_items') ->andWhere(Operator::equalsNullable( [ 'id_product' => $productId, 'id_variation' => $variationId, 'id_store' => $storeId, ])) ->sendToMaster() ->execute() ->fetchAssociative()) { if ($sapDateUpdated && ($storeItemSapDateUpdated = \DateTime::createFromFormat('Y-m-d H:i:s', $storeItem['sap_date_updated']))) { // pokud mam ulozeny spravny casovy razitko ze sapu, ale nesedi mi sklad, tak je invalidStore a budu muset udelat update $isInvalidStore = $sapDateUpdated == $storeItemSapDateUpdated && $quantity != $storeItem['quantity']; // pokud mam v databazi ($storeItemSapDateUpdated) ulozenej novejsi zaznam, nez mi aktualne prisel, tak nebudu provat update, protoze // je to neaktualni skladovost, ktera me nezajima // zaroven nesmi byt invalidStore, protoze pokud je, tak ten update proste provedu, at se to fixne if ($sapDateUpdated <= $storeItemSapDateUpdated && !$isInvalidStore) { // date_updated aktualizuju jen pri plne synchronizaci, protoze jen tehdy me zajima. Jinym zpusobem ho nevyuzivam if ($this->isFullFileImport()) { // date_updated budu aktualizovat jen pokud se jedna o full update sqlQueryBuilder() ->update('stores_items') ->set('date_updated', 'NOW()') ->where(Operator::equals(['id' => $storeItem['id']])) ->execute(); } return; } } if ($quantity <= 0) { sqlQueryBuilder() ->delete('stores_items') ->where(Operator::equals(['id' => $storeItem['id']])) ->execute(); $this->sapUtil->recalculateStores([$productId]); // produkt se vyprodal, takze zmenime jeho dostupnost $this->productAvailabilityUpdater->updateProductAvailability( ProductAvailability::UNAVAILABLE, $productId, $variationId ); return; } // pokud doslo k znovu naskladneni, tak si to oznacim if ($storeItem['quantity'] <= 0) { $isRestocked = true; } $updateQb = sqlQueryBuilder() ->update('stores_items') ->where(Operator::equals(['id' => $storeItem['id']])); $updateData = [ 'quantity' => $quantity, 'sap_date_updated' => $sapDateUpdated ? $sapDateUpdated->format('Y-m-d H:i:s') : (new \DateTime())->format('Y-m-d H:i:s'), ]; // pokud se opravdu zmenila quantity, tak nastavim sap_updated na 1 if ($quantity != $storeItem['quantity']) { $updateData['sap_updated'] = 1; } // date_updated aktualizuju jen pri plne synchronizaci, protoze jen tehdy me zajima. Jinym zpusobem ho nevyuzivam // nebo se opravdu zmenila skladovost if ($this->isFullFileImport() || $quantity != $storeItem['quantity']) { $updateQb->set('date_updated', 'NOW()'); } // nasetuju data a executnu update $updateQb ->directValues($updateData) ->execute(); } elseif ($quantity > 0) { sqlQueryBuilder() ->insert('stores_items') ->setValue('date_updated', 'NOW()') ->directValues( [ 'id_store' => $storeId, 'id_product' => $productId, 'id_variation' => $variationId, 'quantity' => $quantity, 'sap_date_updated' => $sapDateUpdated ? $sapDateUpdated->format('Y-m-d H:i:s') : (new \DateTime())->format('Y-m-d H:i:s'), 'sap_updated' => 1, ] ) ->execute(); $isRestocked = true; } if ($isRestocked) { // produkt byl naskladnen, takze provedu update dostupnosti $this->productAvailabilityUpdater->updateProductAvailability( ProductAvailability::IN_STORE, $productId, $variationId ); } } protected function postprocess(): void { // pokud je to full import a je to file import (import z JSON souboru), tak na konci importu spustim vynulovani // zaznamu, ktere nebyly aktualizovany if ($this->isFullFileImport()) { // nastavim 0 vsem polozkam, ktere nebyly aktualizovant vice jak 12 hodin sqlQueryBuilder() ->update('stores_items') ->directValues(['quantity' => 0]) ->where('TIMESTAMPDIFF(HOUR, date_updated, NOW()) > 12') ->execute(); } } private function isFullFileImport(): bool { return $this->context['importType'] === 'FULL' && ($this->context['isFileImport'] ?? false); } }