Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/wbs24.ozonapinew/lib/Stocks/ |
Upload File : |
<?php namespace Wbs24\Ozonapinew\Stocks; use Bitrix\Main\SystemException; use Bitrix\Main\Localization\Loc; use Wbs24\Ozonapinew\Main; use Wbs24\Ozonapinew\Wrappers; use Wbs24\Ozonapinew\Api; use Wbs24\Ozonapinew\Product; use Wbs24\Ozonapinew\Exception; use Wbs24\Ozonapinew\Products\Cache; use Wbs24\Ozonapinew\Settings; use Wbs24\Ozonapinew\Error; use Wbs24\Ozonapinew\StorageMessages; class Update { use Exception; // trait protected $entityType = 'stocks'; protected $forbiddenEntityTypes = [ 'nothing', 'prices' ]; public function __construct($objects = []) { try { $this->main = $objects['Main'] ?? new Main(); $this->moduleId = $this->main->getModuleId(); $this->wrappers = new Wrappers($objects); $this->accountIndex = $this->wrappers->Option->getAccountIndex(); $this->ApiController = $objects['ApiController'] ?? new Api\Controller(); $this->StocksHelper = $objects['StocksHelper'] ?? new Helper($objects); $this->Product = $objects['Product'] ?? new Product($objects); $this->CacheStack = $objects['CacheStack'] ?? new Cache\Stack(); $this->Settings = $objects['Settings'] ?? new Settings(); $this->Error = $objects['Error'] ?? new Error(); $this->StorageMessages = $objects['StorageMessages'] ?? new StorageMessages(); $this->marketplaceWarehouseName = trim($this->wrappers->Option->get( $this->moduleId, 'marketplaceWarehouseName' )); $this->minStock = intval($this->wrappers->Option->get( $this->moduleId, 'minStock' )); $this->resetStock = ($this->wrappers->Option->get($this->moduleId, 'resetStock') == 'Y'); $this->accountingStockFbo = ($this->wrappers->Option->get($this->moduleId, 'accountingStockFbo') == 'Y'); $this->minStockFbo = (int) $this->wrappers->Option->get($this->moduleId, 'minStockFbo'); } catch (SystemException $exception) { $this->exceptionHandler($exception); } } public function updateStocksOnMarketplace($lastId) { // Получить продукты с ОЗОНа $response = $this->ApiController->action([ 'action' => 'get_products', 'lastId' => $lastId, 'account_index' => $this->accountIndex, ]); $offerIdsToProductIds = $response['offerIdsToProductIds']; $newLastId = $response['newLastId']; if ($offerIdsToProductIds) { // Получить расширенную информацию о продуктах с ОЗОНа $offerIdsToSkus = $this->ApiController->action([ 'action' => 'get_more_products_info', 'offerIds' => $this->fixValueTypes( array_keys($offerIdsToProductIds), 'string' ), 'account_index' => $this->accountIndex, ]); if ($offerIdsToSkus) { // Получить соотношение полученных skus к остаткам по выбранному складу $response = $this->ApiController->action([ 'action' => 'get_stocks', 'skus' => $this->fixValueTypes( array_values($offerIdsToSkus), 'string' ), 'warehouseName' => $this->marketplaceWarehouseName, 'account_index' => $this->accountIndex, ]); $skusToStocks = $response['skusToStocks']; $warehouseId = $response['warehouseId']; if ($skusToStocks && $warehouseId) { // получить сопоставление offerIds к Stocks $offerIdsToStocks = $this->getOfferIdsToStocks( $offerIdsToSkus, $skusToStocks ); $resetOfferIdsToStocks = []; if ($this->accountingStockFbo) { $offerIdsToFboStocks = $this->ApiController->action([ 'action' => 'get_fbo_stocks', 'offerIds' => $this->fixValueTypes( array_keys($offerIdsToStocks), 'string' ), 'account_index' => $this->accountIndex, ]); // Получить офферы для обнуления остатков на ОЗОНе $resetOfferIdsToStocks = $this->getResetOfferIdsToStocks($offerIdsToFboStocks); if ($resetOfferIdsToStocks) { // убрать офферы для обнуления из общего массива офферов (чтобы далее для них не искались остатки) $offerIdsToStocks = $this->filterOfferIdsToStocks( $offerIdsToStocks, $resetOfferIdsToStocks ); } } // Получить остатки из Битрикс и сравнить с остатками из маркетплейса $preparedOfferIdsToStocks = $this->prepareOfferIdsToStocks($offerIdsToStocks); // Объеднить офферы обнуления с полученными остатками офферов из Битрикс $preparedOfferIdsToStocks = $preparedOfferIdsToStocks + $resetOfferIdsToStocks; // Подготовить к отправке данные $preparedStocksInfoForSend = $this->prepareStocksInfoForSend([ 'offerIdsToStocks' => $preparedOfferIdsToStocks, 'offerIdsToProductIds' => $offerIdsToProductIds, 'warehouseId' => $warehouseId ]); // Обновить остатки на маркетплейсе $updatedProducts = $this->ApiController->action([ 'action' => 'set_stocks', 'stocksForSend' => $preparedStocksInfoForSend, 'account_index' => $this->accountIndex, ]); if ($updatedProducts) { // Проверить корректность обновления товаров $this->checkStocksUpdatesSuccess($updatedProducts); } } } } return $newLastId; } protected function getOfferIdsToStocks($offerIdsToSkus, $skusToStocks) { $offerIdsToStocks = []; foreach ($skusToStocks as $sku => $stock) { $offerId = array_search($sku, $offerIdsToSkus); if (!$offerId) continue; $offerIdsToStocks[$offerId] = $stock; } return $offerIdsToStocks; } protected function prepareOfferIdsToStocks($offerIdsToStocks) { $preparedOfferIdsToStocks = []; foreach ($offerIdsToStocks as $offerId => $marketplaceStock) { $productInfo = $this->getProductInfo($offerId); $productId = $productInfo['product_id'] ?? false; $ratio = $productInfo['package_ratio'] ?? 1; $productType = $productInfo['type'] ?? false; if (!$productId) { if ($this->resetStock) { $preparedOfferIdsToStocks[$offerId] = 0; // Если не нашлось товара, обнуляем остаток на ОЗОНе } continue; } $stock = $this->StocksHelper->getStockByProductId($productId, $productType); $stockWithRatio = floor($stock / $ratio); // остаток с учетом коэффициента упаковки if ($marketplaceStock != $stockWithRatio) { if ($stockWithRatio < $this->minStock) $stockWithRatio = 0; // Обнулить остаток, если он меньше минимального остатка $preparedOfferIdsToStocks[$offerId] = $stockWithRatio; // обновляем остаток для передачи на ОЗОН } } return $preparedOfferIdsToStocks; } protected function getProductInfo($offerId) { $productInfo = []; $iblocks = $this->CacheStack->getAllIblocks([ 'accountIndex' => $this->accountIndex, 'entityType' => $this->entityType ]); foreach ($iblocks as $iblockId) { $allowedEntityType = $this->wrappers->Option->get($this->moduleId, 'entity_type_iblock_'.$iblockId); if (in_array($allowedEntityType, $this->forbiddenEntityTypes)) continue; $productInfo = $this->CacheStack->searchProduct([ 'iblockId' => $iblockId, 'offerId' => $offerId, 'accountIndex' => $this->accountIndex, 'entityType' => $this->entityType ]); if ($productInfo) break; } return $productInfo; } protected function prepareStocksInfoForSend($data) { $offerIdsToStocks = $data['offerIdsToStocks']; $offerIdsToProductIds = $data['offerIdsToProductIds']; $warehouseId = $data['warehouseId']; $stocksInfoForSend = []; foreach ($offerIdsToStocks as $offerId => $stock) { $productId = $offerIdsToProductIds[$offerId]; if (!$productId) continue; $stocksInfoForSend[] = [ 'warehouse_id' => (int) $warehouseId, 'product_id' => (int) $productId, 'offer_id' => (string) $offerId, 'stock' => (int) $stock, ]; } return $stocksInfoForSend; } protected function checkStocksUpdatesSuccess($updatedProducts) { $errorProductsUpdates = []; foreach ($updatedProducts as $updatedProduct) { if (!empty($updatedProduct['errors']) ) { $errorProductsUpdates[] = $updatedProduct; } } $suffix = strtoupper($this->moduleId); $siteId = $this->wrappers->Option->get($this->moduleId, 'siteId'); $siteInfo = $this->Settings->getSiteInfo($siteId); $offerIds = $this->getErrorOfferIds($errorProductsUpdates); $offerIdsToDetailPageUrl = $this->getOfferIdsToDetailPageUrl($offerIds, $siteInfo); foreach ($errorProductsUpdates as $errorProductUpdate) { $offerId = $errorProductUpdate['offer_id']; $errorMessage .= $this->getErrorMessage($errorProductUpdate['errors']); $this->createReport( 'stock_update_error_log.txt', $errorMessage ); $errorCodesToMessages = $this->getErrorCodesToMessages($errorProductUpdate['errors']); $prepareCodesToMessages = $this->StorageMessages->prepareCodesToMessages($errorCodesToMessages); foreach ($prepareCodesToMessages as $code => $errorDescription) { $this->Error->errorProcess([ 'siteName' => $siteInfo['siteNameHtml'], 'dateTime' => date("Y-m-d H:i:s", time()), 'errorLevel' => 'WARNING', 'errorType' => 'API', 'errorCode' => $code, 'errorMessage' => $errorMessage, 'errorDescription' => $errorDescription, 'accountId' => $this->accountIndex, 'apiUrl' => '/v2/products/stocks', 'entityId' => '<a href="'.$offerIdsToDetailPageUrl[$offerId].'">'.$offerId.'</a>', 'entityType' => 'products', 'requestBody' => '', 'responseBody' => '', 'trace' => '' ]); } } } protected function getErrorOfferIds($errorProductsUpdates) { $offerIds = []; foreach ($errorProductsUpdates as $errorProductUpdate) { $offerIds[] = $errorProductUpdate['offer_id']; } return $offerIds; } protected function getOfferIdsToDetailPageUrl($offerIds, $siteInfo) { $offerIdsToDetailPageUrl = []; foreach ($offerIds as $offerId) { $product = $this->Product->getProductInfoByOfferId($offerId); switch ((int) $product['product_type']) { case 1: case 2: case 3: $type = 'catalog'; break; case 4: $type = 'offers'; break; } $offerIdsToDetailPageUrl[$offerId] = 'http://' .$siteInfo['serverName'] .'/bitrix/admin/' .\CIBlock::GetAdminElementEditLink($product['iblock_id'], $product['id']) ; } return $offerIdsToDetailPageUrl; } protected function getErrorCodesToMessages($errors) { $errorCodes = []; foreach ($errors as $key => $error) { $errorCodes[$error['code']] = $error['message']; } return $errorCodes; } protected function getErrorMessage($errors) { $suffix = strtoupper($this->moduleId); $errorsMessage = ''; foreach ($errors as $key => $error) { $errorsMessage .= Loc::getMessage($suffix.".STOCK_UPDATE_MESSAGE_CODE") .$error['code'] .Loc::getMessage($suffix.".STOCK_UPDATE_MESSAGE_STRING") .$error['message'] ; if (!empty($errors[$key+1])) { $errorsMessage .= ', '; } } return $errorsMessage; } protected function getResetOfferIdsToStocks($offerIdsToFboStocks) { $resetOfferIdsToStocks = []; foreach ($offerIdsToFboStocks as $offerId => $fboStock) { if ($fboStock >= $this->minStockFbo) { $resetOfferIdsToStocks[$offerId] = 0; } } return $resetOfferIdsToStocks; } protected function filterOfferIdsToStocks($offerIdsToStocks, $resetOfferIdsToStocks) { foreach ($offerIdsToStocks as $offerId => $stock) { if (array_key_exists($offerId, $resetOfferIdsToStocks)) { unset($offerIdsToStocks[$offerId]); } } return $offerIdsToStocks; } protected function fixValueTypes($array, $type) { foreach ($array as $key => $value) { switch ($type) { case 'string': $array[$key] = (string) $value; break; } } return $array; } }