Дублирование способов доставки при синхронизации с RetailCRM если у товаров разные поставщики

Добрый день.

У нас CS-Cart 4.12.2 RU. Используются модули поставщиков (версии 1.0) и синхронизации с RetailCRM ([Beta] версии 1.0).

Если добавить в заказ несколько товаров с разными поставщиками (допустим, разных поставщиков N штук), у которых разные способы доставки, то при каждой синхронизации (которая затронет заказ, если он в RetailCRM редактировался) количество выбранных доставок будет увеличиваться в N×количество_выбранных_способов_доставки_на_момент_перед_синхронизацией раз.

ПОЧЕМУ ЭТО ПРОИСХОДИТ

Если в заказе есть товары с разными поставщиками, создаётся несколько групп товаров [‘product_groups’], каждый со своими способами доставки [‘product_groups’][‘chosen_shippings’].

При синхронизации вызывается функция syncOrder, которая описана в файле
/app/addons/retailcrm/Tygh/Addons/Retailcrm/Service.php

В этом файле вызовом функции fn_form_cart формируется корзина заказа:

if ($order['order_id'] && !fn_form_cart($order['order_id'], $cart, $auth)) {
    $this->logger->error(
        sprintf('Order #%d not found.', $order['order_id']),
        __METHOD__
    );
    return false;
}

Чуть ниже сохраняются способы доставки в переменную $shippings:

$shippings = isset($cart[‘shipping’]) ? $cart[‘shipping’] : array();

Затем обнуляется подмассив product_groups:

$cart[‘product_groups’] = array();

Ещё ниже видим код, где каждой группе товаров прописывается значение $shippings, т.е. по сути значение $cart[‘shipping’].

 if (!isset($order['shipping_ids']) || $order['shipping_ids'] == reset($chosen_shipping_ids)) {
     $cart['shipping'] = $shippings;

     foreach ($cart['product_groups'] as &$product_group) {
         $product_group['chosen_shippings'] = $shippings;
     }
     unset($product_group);
 }

Ответвление 1: как из таблицы cscart_order_data вытаскивается значение shipping. Значение $cart[‘shipping’] появляется в функции fn_get_order_info. Путь такой: syncOrder вызывает fn_form_cart, тот вызывает fn_get_order_info. Вот код из fn_get_order_info:

// Get shipping information
if (!empty($additional_data[OrderDataTypes::SHIPPING])) {
    $order['shipping'] = unserialize($additional_data[OrderDataTypes::SHIPPING]);

Ответвление 2: вернёмся к syncOrder и проследим, как будет сохраняться OrderDataTypes::SHIPPING. Путь такой: syncOrder вызывает fn_update_order, тот fn_update_order_data, в котором есть такой код:

// Save shipping information
$chosen_shippings = array();
foreach ($cart['product_groups'] as $group) {
    $group_shipping = !empty($group['chosen_shippings']) ? $group['chosen_shippings'] : array();
        $chosen_shippings = array_merge($chosen_shippings, $group_shipping);
    }

    fn_apply_stored_shipping_rates($cart, $order_id);
    $_data[] = array (
        'order_id' => $order_id,
        'type' => OrderDataTypes::SHIPPING, //shipping information
        'data' => serialize($chosen_shippings),
    );

Как видим, в shipping попадает объединённый массив всех chosen_shippings разных групп товаров заказа.

Отмечу, что в том же fn_update_order_data отдельно прекрасно сохраняется OrderDataTypes::GROUPS, а в fn_get_order_info также прекрасно обратно вытаскивается и записывается в подмассив product_groups.

В итоге получаем такой цикл:

  1. Из базы берётся значение OrderDataTypes::SHIPPING и записывается в [‘shipping’]
  2. В список способов доставки каждой группы товаров [‘product_groups’][‘chosen_shippings’] записывается список способов доставки из [shipping].
  3. Перед сохранением в базу происходит объединение способов доставки каждой группы товаров и записывается в OrderDataTypes::SHIPPING.

На каждой итерации количество доставок вырастает в количество групп товаров раз.

КАК ВОСПРОИЗВЕСТИ ПРОБЛЕМУ

Имеет товары Т1 и Т2, поставщики П1 и П2 и способы доставки Д1 и Д2. Товару Т1 прописываем поставщика П1, к которому привязываем способ доставки Д1. Товару Т2 прописываем поставщика П2, к которому привязываем способ доставки Д2.

Способу доставки Д1 проставляем соответствие со способом доставки в RetailCRM, Д2 не проставляем.

Идём на витрину, добавляем Т1 и Т2 в корзину, выбираем способы доставки Д1 и Д2, размещаем заказ.

Заходим в RetailCRM, меняем в заказе что-нибудь (например, комментарий оператора), сохраняем.

Ждём синхронизацию или вызываем её вручную.

Наблюдаем в админке cs-cart’а у нашего заказа задвоение способов доставки.

СОБСТВЕННО, ВОПРОС

Как исправить баг? я закомментировал эту строку в orderSync:

    // $cart['product_groups'] = array();

и здесь одну:

    if (!isset($order['shipping_ids']) || $order['shipping_ids'] == reset($chosen_shipping_ids)) {
        $cart['shipping'] = $shippings;

        foreach ($cart['product_groups'] as &$product_group) {
            // $product_group['chosen_shippings'] = $shippings;
        }
        unset($product_group);
    }

Догадываюсь, что это было не просто так написано. Как исправить, чтобы работало во всех случаях без сбоев?

Здравствуйте @blzkn
Спасибо за ваше обращение.
Как я вижу, вы уже сообщили о данной проблеме в Help Desk, и моему коллеге удалось воспроизвести её. Информация была передана разработчикам. Мы сообщим вам, когда проблема будет исправлена.
Спасибо за ваш вклад в улучшение CS-Cart.