Перейти к содержимому

Стоимость доставки считается неверно - разбор причин

Служба доставки видна на оформлении и выбирается, но её цена расходится с тарифом перевозчика. Разбираем причины по убыванию частоты, начиная с данных, на которых платформа этот тариф считает.

С чего начать

Раскладываем доставку сохранённого заказа:

$order = \Bitrix\Sale\Order::load($orderId);
foreach ($order->getShipmentCollection()->getNotSystemItems() as $shipment) {
printf("служба=%s вес отгрузки=%s\n",
$shipment->getField('DELIVERY_NAME'), $shipment->getWeight());
}
printf("доставка=%.2f итог=%.2f %s\n", $order->getDeliveryPrice(),
$order->getPrice(), $order->getCurrency());
// вес отгрузки - единственное число, на котором работают тарифы по весу

Нулевой вес отгрузки при непустой корзине закрывает половину причин сразу. Дальше разбор уходит либо в поля торгового каталога, либо в настройки профиля самой службы.

Смотрим состав отгрузки:

foreach ($shipment->getShipmentItemCollection() as $item) {
printf("позиция=%s количество=%s\n",
$item->getField('BASKET_ID'), $item->getQuantity());
}
// вес складывается только из этих позиций, а не из всей корзины покупателя
// системная отгрузка в перебор не попадает: она держит нераспределённые позиции

Заказ с несколькими отгрузками считает доставку на каждую отдельно. В заказе при этом видна сумма, и она законно не совпадает ни с одним тарифом перевозчика.

Сверяем вес и габариты позиций:

$rows = \Bitrix\Catalog\ProductTable::getList([
'select' => ['ID', 'WEIGHT', 'WIDTH', 'HEIGHT', 'LENGTH'],
'filter' => ['@ID' => $productIds],
])->fetchAll();
foreach ($rows as $row) {
printf("%d вес=%s размеры=%sx%sx%s\n", $row['ID'], $row['WEIGHT'] ?: '-',
$row['WIDTH'], $row['HEIGHT'], $row['LENGTH']);
}
// вес хранится в граммах, габариты - в миллиметрах, пустое поле считается нулём

Свойство инфоблока с названием «Вес» службы доставки не видят вовсе. Они читают поля торгового каталога, поэтому заполненное свойство даёт ложное ощущение готового каталога.

Пересчитываем тариф руками:

$service = \Bitrix\Sale\Delivery\Services\Manager::getObjectById($deliveryId);
$calc = $service->calculateConcrete($shipment);
var_dump($calc->isSuccess());
print_r($calc); // в объекте видно цену и срок доставки
print_r($calc->getErrors()); // ошибку тарифа покупателю платформа не покажет

Ручной пересчёт отделяет данные заказа от настроек профиля. Совпал результат с ценой заказа - виноваты вес и местоположение, разошёлся - цену изменили уже после расчёта.

Смотрим шаг заказа и единицу измерения:

print_r(\Bitrix\Catalog\MeasureRatioTable::getCurrentRatio($productIds));
// ключ - товар, значение - шаг заказа, по умолчанию единица
print_r(\Bitrix\Catalog\MeasureTable::getList([
'select' => ['ID', 'SYMBOL', 'CODE', 'IS_DEFAULT'],
])->fetchAll());
// единица товара - ссылка на общий справочник установки, а не поле карточки

Кратность и единицы разобраны в статье про единицы, вес и габариты. Здесь важен один факт: шаг заказа умножает вес позиции, а вместе с ним и тариф.

Причины

  1. У товаров пустые вес и габариты примерно 30% случаев

    ПризнакДоставка одинаковая на любой заказ и совпадает с нижней ставкой тарифа.

    ПроверкаСмотрим поля веса и размеров в торговом каталоге у позиций проблемного заказа.

    Что делатьЗаполняем поля каталога: свойство инфоблока с названием «Вес» службы не читают.

  2. Вес приехал не в тех единицах или помножен на кратность примерно 22% случаев

    ПризнакПосле обмена с учётной системой доставка подорожала ровно в тысячу раз.

    ПроверкаСверяем порядок числа в поле веса и шаг заказа у той же позиции.

    Что делатьПриводим вес к граммам на стороне обмена или обработчиком события записи товара.

  3. Наценка или тариф профиля службы примерно 18% случаев

    ПризнакЦена отличается от тарифа перевозчика на устойчивый процент или фиксированную сумму.

    ПроверкаОткрываем профиль службы и смотрим наценку, тариф и порог бесплатной доставки.

    Что делатьПравим наценку в профиле: она ложится поверх ответа обработчика и в расчёте не видна.

  4. Местоположение покупателя определено неточно примерно 15% случаев

    ПризнакЦена приходит как для другого региона, хотя город в заказе выглядит верным.

    ПроверкаСмотрим значение свойства заказа с типом местоположения и его узел в дереве.

    Что делатьУточняем местоположение до города: зона тарифа берётся по узлу дерева, а не по названию.

  5. К цене прибавились дополнительные услуги примерно 9% случаев

    ПризнакВ сохранённом заказе доставка дороже, чем показывала форма оформления до отправки.

    ПроверкаСмотрим дополнительные услуги службы и отмеченные покупателем галочки в заказе.

    Что делатьРазносим услуги и перевозку: подъём на этаж и упаковка считаются отдельными строками.

  6. Расчёт идёт по корзине, а не по отгрузке примерно 6% случаев

    ПризнакСвой расчёт в карточке товара даёт ноль или число, не совпадающее с заказом.

    ПроверкаСмотрим, что подаётся на вход расчёта: собранная отгрузка или временная корзина.

    Что делатьСчитаем по отгрузке: она знает вес, состав и адрес, а временная корзина этого не знает.

Частые вопросы

Почему доставка считается по минимальной ставке?

У позиций пустой вес в полях торгового каталога. Службы считают такой вес нулевым и отдают стоимость по нижней границе тарифа.

Вес заполнен, а доставка его не видит - почему?

Значение лежит в свойстве инфоблока, а не в поле торгового каталога. Расчёт читает только поля каталога, и свойство с любым названием для него не существует.

Из 1С приехал вес с лишними нулями, где это чинить?

На стороне обмена или обработчиком события записи товара. Делить значение в шаблоне бесполезно: в отгрузку уходит поле каталога, а не то, что выведено в карточке.

Как посчитать доставку прямо в карточке товара?

Собрать отгрузку с нужным весом и адресом и вызвать расчёт службы. Пустая корзина даёт нулевую стоимость, поэтому для витрины подставляют усреднённые вес и город.

Можно ли задать свою цену доставки перед созданием заказа?

Да, в расчёте своей службы: цена ставится в объект результата. Подмена числа на стороне браузера не сохраняется, потому что платформа пересчитывает доставку заново.

Смежное

Первоисточник