From d6862bad58b90f4d00188012bd4698b7811b8271 Mon Sep 17 00:00:00 2001 From: gleemand Date: Tue, 2 Jul 2024 14:59:53 +0200 Subject: [PATCH] ref #96244 Fixed duplicating items on history sync (#222) --- CHANGELOG.md | 3 + VERSION | 2 +- retailcrm/lib/RetailcrmHistory.php | 179 +++++++++++++---------------- retailcrm/retailcrm.php | 2 +- 4 files changed, 88 insertions(+), 98 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b779468a..4b401aae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## v3.6.5 +* Исправлено дублирование товаров при обратной синхронизации + ## v3.6.4 * Добавлена передача услуг через ICML каталог diff --git a/VERSION b/VERSION index 0f44168a..d15b8b06 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.6.4 +3.6.5 diff --git a/retailcrm/lib/RetailcrmHistory.php b/retailcrm/lib/RetailcrmHistory.php index 7e219f77..dc641bbd 100755 --- a/retailcrm/lib/RetailcrmHistory.php +++ b/retailcrm/lib/RetailcrmHistory.php @@ -393,11 +393,11 @@ private static function createOrderInPrestashop($orderHistory) self::saveCarrier($prestashopOrder->id, $deliveryType, $crmOrder['delivery']['cost']); - $quantities = self::createOrderDetails($crmOrder, $prestashopOrder); + $isStockEnough = self::createOrderDetails($crmOrder, $prestashopOrder, true); - self::setOutOfStockStatusInPrestashop($crmOrder, $prestashopOrder, $quantities); + self::setOutOfStockStatusInPrestashop($crmOrder, $prestashopOrder, $isStockEnough); - self::setOutOfStockStatusInCrm($crmOrder, $prestashopOrder, $quantities); + self::setOutOfStockStatusInCrm($crmOrder, $prestashopOrder, $isStockEnough); // collect order ids for single fix request self::$orderFix[] = ['id' => $crmOrder['id'], 'externalId' => $prestashopOrder->id]; @@ -438,13 +438,13 @@ private static function updateOrderInPrestashop($crmOrder) $crmOrder = self::cleanDeletedItems($crmOrder, $prestashopOrder); - $quantities = self::createOrderDetails($crmOrder, $prestashopOrder); + $isStockEnoughForNewItems = self::createOrderDetails($crmOrder, $prestashopOrder); + $isStockEnoughForExistingItems = self::checkItemsQuantityAndDiscount($crmOrder, $prestashopOrder); + $isStockEnough = $isStockEnoughForNewItems && $isStockEnoughForExistingItems; - self::setOutOfStockStatusInPrestashop($crmOrder, $prestashopOrder, $quantities); - - self::setOutOfStockStatusInCrm($crmOrder, $prestashopOrder, $quantities); - - self::switchPrestashopOrderStatusByCrmStatus($crmOrder, $prestashopOrder, $quantities); + self::setOutOfStockStatusInPrestashop($crmOrder, $prestashopOrder, $isStockEnough); + self::setOutOfStockStatusInCrm($crmOrder, $prestashopOrder, $isStockEnough); + self::switchPrestashopOrderStatusByCrmStatus($crmOrder, $prestashopOrder, $isStockEnough); // update order number in PS if receiveOrderNumber option (CRM->PS) enabled if (isset($crmOrder['number']) && self::$receiveOrderNumber) { @@ -1137,50 +1137,45 @@ private static function createOrder($cart, $customer, $order, $deliveryType, $pa } /** + * @return bool Returns if stock of all items is enough + * * @throws PrestaShopDatabaseException * @throws PrestaShopException */ - private static function createOrderDetails($crmOrder, $prestashopOrder) + private static function createOrderDetails($crmOrder, $prestashopOrder, $isCreating = false) { $newItemsIds = []; - $quantities = []; + $isNewItemsExist = false; + $isStockEnough = true; if (empty($crmOrder['items'])) { RetailcrmLogger::writeDebug(__METHOD__, 'Empty order items'); - return $quantities; + return $isStockEnough; } - foreach ($crmOrder['items'] as $item) { - if (!isset($item['offer']['externalId'])) { + foreach ($crmOrder['items'] as $key => $item) { + if (RetailcrmOrderBuilder::isGiftItem($item)) { continue; } - $externalId = $item['offer']['externalId']; - $product = new Product((int) $externalId, false, self::$default_lang); - $product_id = $externalId; - - if (RetailcrmOrderBuilder::isGiftItem($item)) { + $isNewItem = isset($item['create']); + if (!$isNewItem && !$isCreating) { continue; } - $product_attribute_id = 0; - if (false !== strpos($externalId, '#')) { - $externalIds = explode('#', $externalId); - $product_id = $externalIds[0]; - $product_attribute_id = $externalIds[1]; - } + $parsedExtId = static::parseItemExternalId($item); + $product_id = $parsedExtId['product_id']; + $product_attribute_id = $parsedExtId['product_attribute_id']; - $orderDetail = self::createOrderDetail($item, $product, $product_attribute_id, $prestashopOrder); - $availableInStockOld = StockAvailable::getQuantityAvailableByProduct($product_id); + $product = new Product((int) $product_id, false, self::$default_lang); - $quantities[$product_id]['old'] = $availableInStockOld; + $orderDetail = self::createOrderDetail($item, $product, $parsedExtId, $prestashopOrder); - if (isset($item['initialPrice'])) { - $deltaQuantity = -1 * $orderDetail->product_quantity; - } else { - $deltaQuantity = -1 * ($item['quantity'] - $orderDetail->product_quantity); - } + $isStockEnough = $product->checkQty($orderDetail->product_quantity); + + // переменная используется для передачи разницы количества товара в метод StockAvailable::updateQuantity + $deltaQuantity = -1 * $orderDetail->product_quantity; StockAvailable::updateQuantity( $product_id, @@ -1189,37 +1184,32 @@ private static function createOrderDetails($crmOrder, $prestashopOrder) Context::getContext()->shop->id ); - $availableInStockNew = StockAvailable::getQuantityAvailableByProduct($product_id); - $quantities[$product_id]['new'] = $availableInStockNew; - - if (!isset($item['initialPrice'])) { - $orderDetail->product_quantity = $orderDetail->product_quantity - $deltaQuantity; - $orderDetail->total_price_tax_incl = $orderDetail->product_price * $orderDetail->product_quantity; - } - try { self::loadInPrestashop($orderDetail, 'save'); $newItemsIds[Db::getInstance()->Insert_ID()] = $item['id']; } catch (Exception $e) { } + + $isNewItemsExist = true; + unset($crmOrder['items'][$key]); } // update order items ids in crm - self::$newItemsIdsByOrderId[$prestashopOrder->id] = $newItemsIds; + if ($isNewItemsExist) { + self::$newItemsIdsByOrderId[$prestashopOrder->id] = $newItemsIds; + } - return $quantities; + return $isStockEnough; } - private static function switchPrestashopOrderStatusByCrmStatus($crmOrder, $prestashopOrder, $quantities) + private static function switchPrestashopOrderStatusByCrmStatus($crmOrder, $prestashopOrder, $isStockEnough) { if (!isset($crmOrder['status'])) { return; } $orderStatus = $crmOrder['status']; - $outOfStockItems = self::getOutOfStockItems($quantities); - - if (0 < count($outOfStockItems)) { + if (!$isStockEnough) { $orderStatus = self::getOutOfStockStatus($crmOrder, $prestashopOrder); } @@ -1414,19 +1404,19 @@ private static function checkPaymentType($order, $orderToUpdate) continue; } - $orderPayment = new OrderPayment(); - $paymentType = self::getPaymentType($payment); - - if ($paymentType) { - $orderToUpdate->payment = $paymentType; - $orderPayment->payment_method = $paymentType; + if (!$paymentType) { + continue; } + $orderToUpdate->payment = $paymentType; + + $orderPayment = new OrderPayment(); + $orderPayment->payment_method = $paymentType; $orderPayment->order_reference = $orderToUpdate->reference; $orderPayment->id_currency = (int) Configuration::get('PS_CURRENCY_DEFAULT'); - $orderPayment->amount = isset($payment['amount']) ? $payment['amount'] : $orderToUpdate->total_paid; - $orderPayment->date_add = isset($payment['paidAt']) ? $payment['paidAt'] : date('Y-m-d H:i:s'); + $orderPayment->amount = $payment['amount'] ?? $orderToUpdate->total_paid; + $orderPayment->date_add = $payment['paidAt'] ?? date('Y-m-d H:i:s'); RetailcrmLogger::writeDebug( __METHOD__, @@ -1577,7 +1567,7 @@ private static function cleanDeletedItems($crmOrder, $orderToUpdate) return $crmOrder; } - foreach ($crmOrder['items'] as $item) { + foreach ($crmOrder['items'] as $key => $item) { if (!isset($item['delete']) || true != $item['delete']) { continue; } @@ -1606,6 +1596,8 @@ private static function cleanDeletedItems($crmOrder, $orderToUpdate) $product_attribute_id, $id_order_detail ); + + unset($crmOrder['items'][$key]); } return $crmOrder; @@ -1613,9 +1605,16 @@ private static function cleanDeletedItems($crmOrder, $orderToUpdate) private static function checkItemsQuantityAndDiscount($crmOrder, $prestashopOrder) { - $itemQuantities = []; + $isStockEnough = true; + + if (empty($crmOrder['items'])) { + RetailcrmLogger::writeDebug(__METHOD__, 'Empty order items'); + + return $isStockEnough; + } + foreach ($prestashopOrder->getProductsDetail() as $orderItem) { - foreach ($crmOrder['items'] as $crmItem) { + foreach ($crmOrder['items'] as $key => $crmItem) { if (RetailcrmOrderBuilder::isGiftItem($crmItem)) { continue; } @@ -1625,10 +1624,16 @@ private static function checkItemsQuantityAndDiscount($crmOrder, $prestashopOrde $product_attribute_id = $parsedExtId['product_attribute_id']; $isExistingItem = !isset($crmItem['create']); - if (!$isExistingItem || $product_id != $orderItem['product_id'] || $product_attribute_id != $orderItem['product_attribute_id']) { + if ( + !$isExistingItem + || $product_id != $orderItem['product_id'] + || $product_attribute_id != $orderItem['product_attribute_id'] + ) { continue; } + $product = new Product((int) $product_id, false, self::$default_lang); + $orderDetailId = !empty($parsedExtId['id_order_detail']) ? $parsedExtId['id_order_detail'] : $orderItem['id_order_detail']; $orderDetail = new OrderDetail($orderDetailId); @@ -1645,7 +1650,7 @@ private static function checkItemsQuantityAndDiscount($crmOrder, $prestashopOrde $orderDetail->product_quantity = $crmItem['quantity']; $orderDetail->product_quantity_in_stock = $crmItem['quantity']; - $itemQuantities[$product_id] = StockAvailable::getQuantityAvailableByProduct($product_id); + $isStockEnough = 0 > $deltaQuantity || $product->checkQty(-1 * $deltaQuantity); StockAvailable::updateQuantity( $product_id, @@ -1659,10 +1664,11 @@ private static function checkItemsQuantityAndDiscount($crmOrder, $prestashopOrde ? $prestashopOrder->id_warehouse : 0; self::loadInPrestashop($orderDetail, 'update'); + unset($crmOrder['items'][$key]); } } - return $itemQuantities; + return $isStockEnough; } private static function getInternalOrderStatus($state) @@ -1761,16 +1767,15 @@ private static function changeTotals(array $infoOrder, $orderToUpdate) return $orderToUpdate; } - private static function setOutOfStockStatusInPrestashop($crmOrder, $prestashopOrder, $quantities) + private static function setOutOfStockStatusInPrestashop($crmOrder, $prestashopOrder, $isStockEnough) { if (!isset($crmOrder['items'])) { return false; } - $outOfStockItems = self::getOutOfStockItems($quantities); $newStatus = self::getOutOfStockStatus($crmOrder, $prestashopOrder); - if (0 < count($outOfStockItems) && $newStatus) { + if (!$isStockEnough && $newStatus) { self::createOrderHistory($prestashopOrder, $newStatus); $prestashopOrder->current_state = self::$statuses[$newStatus]; self::loadInPrestashop($prestashopOrder, 'save'); @@ -1865,19 +1870,13 @@ private static function addProductsToCart(Cart $cart, array $products) return $cart; } - private static function setOutOfStockStatusInCrm($crmOrder, $prestashopOrder, $quantities = null) + private static function setOutOfStockStatusInCrm($crmOrder, $prestashopOrder, $isStockEnough) { if (!isset($crmOrder['items']) || !is_array($crmOrder['items'])) { return false; } - if (null === $quantities) { - $quantities = self::checkItemsQuantityAndDiscount($crmOrder, $prestashopOrder); - } - - $outOfStockItems = self::getOutOfStockItems($quantities); - - if (0 < count($outOfStockItems)) { + if (!$isStockEnough) { $crmOrder['status'] = self::getOutOfStockStatus($crmOrder, $prestashopOrder); self::$api->ordersEdit($crmOrder, 'id'); @@ -1912,20 +1911,10 @@ private static function createOrderHistory($prestashopOrder, $orderStatus) $orderHistory->changeIdOrderState(self::$statuses[$orderStatus], $prestashopOrder->id, true); } - private static function getOutOfStockItems($quantities) + private static function createOrderDetail($item, $product, $parsedExtId, $prestashopOrder) { - return array_filter($quantities, function ($value) { - if (0 > $value['new'] || $value['new'] == $value['old']) { - return true; - } - - return false; - }); - } - - private static function createOrderDetail($item, $product, $product_attribute_id, $prestashopOrder) - { - $product_id = $item['offer']['externalId']; + $product_id = $parsedExtId['product_id']; + $product_attribute_id = $parsedExtId['product_attribute_id']; if (0 != $product_attribute_id) { $productName = htmlspecialchars( @@ -1935,16 +1924,11 @@ private static function createOrderDetail($item, $product, $product_attribute_id $productName = htmlspecialchars(strip_tags($product->name)); } - if (isset($item['initialPrice'])) { - $productPrice = round($item['initialPrice'], 2); - $orderDetail = new OrderDetail(); - $orderDetail->product_quantity = (int) $item['quantity']; - $orderDetail->product_quantity_in_stock = (int) $item['quantity']; - } else { - $parsedExtId = static::parseItemExternalId($item); - $orderDetail = new OrderDetail($parsedExtId['id_order_detail']); - $productPrice = $orderDetail->product_price; - } + $parsedExtId = static::parseItemExternalId($item); + $orderDetail = new OrderDetail($parsedExtId['id_order_detail'] ?? null); + + $orderDetail->product_quantity = (int) $item['quantity']; + $orderDetail->product_quantity_in_stock = (int) $item['quantity']; static::setOrderDetailProductName($orderDetail, $productName); @@ -1956,13 +1940,16 @@ private static function createOrderDetail($item, $product, $product_attribute_id $orderDetail->product_attribute_id = (int) $product_attribute_id; $orderDetail->product_reference = implode('', ['\'', $product->reference, '\'']); + $productPrice = $item['initialPrice']; + $orderDetail->product_price = $productPrice; $orderDetail->original_product_price = $productPrice; $orderDetail->total_price_tax_incl = $productPrice * $orderDetail->product_quantity; $orderDetail->unit_price_tax_incl = $productPrice; - $orderDetail->id_warehouse = !empty($prestashopOrder->id_warehouse) ? $prestashopOrder->id_warehouse : 0; + $orderDetail->id_warehouse = $prestashopOrder->id_warehouse ?? 0; + $orderDetail->id_order_detail = $parsedExtId['id_order_detail'] ?? null; return $orderDetail; } diff --git a/retailcrm/retailcrm.php b/retailcrm/retailcrm.php index 78da3345..a166f97a 100755 --- a/retailcrm/retailcrm.php +++ b/retailcrm/retailcrm.php @@ -48,7 +48,7 @@ class RetailCRM extends Module { - const VERSION = '3.6.4'; + const VERSION = '3.6.5'; const API_URL = 'RETAILCRM_ADDRESS'; const API_KEY = 'RETAILCRM_API_TOKEN';