«Стоимость доставки уточнит менеджер» — самая дорогая фраза в корзине. Человек уже выбрал товар, ввёл адрес и упёрся в неопределённость. Часть покупателей на этом уходит, и восполнить их рекламой дороже, чем один раз настроить расчёт. Разберём, как это устроено внутри и почему подключение службы доставки почти никогда не сводится к установке модуля.
Что нужно для расчёта: не адрес, а вес и габариты
Любой калькулятор любой службы хочет на входе одно и то же: откуда, куда, сколько мест, вес и габариты каждого места, объявленная стоимость, код тарифа. Адрес — самая простая из этих величин.
Проблема в том, что вес и габариты живут в карточке товара, а в карточках их обычно нет. В каталоге из трёх тысяч позиций вес заполнен у трёхсот, габариты — ни у одной. Пока это так, честного расчёта не будет: модуль либо подставит нули и покажет минимальный тариф, либо вернёт ошибку.
Расчёт доставки — это не интеграция, а сначала работа с данными каталога. Технически подключить службу можно за день. Заполнить весогабаритные характеристики на три тысячи позиций — это недели, и делает это не разработчик.
Если характеристики ведутся в учётной системе, их нужно забрать оттуда, а не заводить в админке заново — иначе они разойдутся на второй неделе. Это обычная часть обмена с 1С: поля веса, длины, ширины и высоты добавляются в выгрузку вместе с ценами и остатками.
Объёмный вес — то, из-за чего возникают убытки
Службы считают тариф не по физическому весу, а по большей из двух величин: фактическому весу и объёмному. Объёмный считается как произведение трёх габаритов, делённое на коэффициент плотности — у большинства перевозчиков это 5000 при сантиметрах и граммах, то есть кубический сантиметр приравнивается к пяти граммам.
Практический смысл: коробка 60×40×40 весом два килограмма поедет по тарифу девятнадцати килограммов. Для подушек, светильников, упаковочных материалов и любых объёмных и легких товаров разница в стоимости — кратная. Магазин, который считает доставку «по весу из карточки», на таких заказах теряет на каждой отправке.
Отсюда второе требование к данным: габариты нужны не товара, а упаковки. Для сборных заказов нужна ещё и логика укладки — хотя бы примитивная: суммировать объёмы, добавить запас на упаковку, при превышении лимита разбивать на несколько мест. Идеального алгоритма укладки не существует, но даже грубая модель лучше одной коробки на весь заказ.
Как общаются с API служб
Детали у перевозчиков разные, принцип один. У СДЭК это API с авторизацией по схеме client credentials: аккаунт и секретный ключ меняются на токен, токен живёт около часа, его надо кешировать и обновлять заранее, а не на каждый запрос. Дальше вызывается метод расчёта по тарифу или список доступных тарифов, в теле — пункты отправления и получения и массив мест с весом и габаритами.
У Почты России отдельный сервис тарификации, где точка назначения задаётся почтовым индексом, а не городом, и отдельный сервис оформления отправлений. У Boxberry, ПЭК и Деловых линий — свои методы с той же логикой. Яндекс Доставка работает по заявке на доставку с привязкой к координатам.
Главное, что надо понять до начала: у каждой службы свой справочник населённых пунктов, и ваш город «Ростов-на-Дону» надо превратить в код этой службы. Поэтому в работающей интеграции есть слой сопоставления: адрес покупателя из справочника адресов приводится к коду города перевозчика, а не передаётся строкой.
Адрес, который служба примет
Свободный ввод адреса в поле — источник половины проблем на отправке. Человек напишет «Ростов», «г Ростов на Дону», «Ростов-на-Дону обл» — и ни один из вариантов не сопоставится автоматически.
Решение — подсказки по адресному справочнику с сохранением не только текста, но и кода адресного объекта и индекса. Тогда в заказе лежит нормализованный адрес, пригодный и для расчёта, и для создания отправления, и для чека. Поле для уточнений — квартира, подъезд, комментарий курьеру — остаётся свободным, но оно не участвует в расчёте.
Пункты выдачи: тысячи точек, которые нельзя грузить в браузер
Доставка до пункта выдачи дешевле курьерской, и выбирают её чаще. Техническая сложность в объёме: пунктов у одной службы по стране тысячи, с расписанием, ограничениями по весу и габаритам, возможностью оплаты на месте и примерки.
Правильная схема — выгружать справочник пунктов по расписанию в свою базу и отдавать карте только точки выбранного города. Живой запрос к API на каждое открытие карты — это секунды ожидания и зависимость корзины от доступности перевозчика. Обновлять справочник достаточно раз в сутки: пункты открываются и закрываются, но не каждый час.
На карте важны кластеризация и фильтр по ограничениям: показывать пункт, который не принимает посылки тяжелее пятнадцати килограммов, для заказа на двадцать — значит гарантированно получить отказ на приёмке.
Кеш и таймаут: почему корзина тормозит
Каждое изменение корзины — добавили товар, поменяли количество, выбрали город — это новый расчёт. Если каждый такой пересчёт уходит в API перевозчика, корзина начинает ждать внешний сервис на каждое действие. Два перевозчика — два ожидания подряд.
Рабочая схема состоит из трёх правил:
- Кешировать результат по ключу «служба + тариф + город + вес + габариты + объявленная стоимость» на несколько часов
- Ставить жёсткий таймаут в две-три секунды и не ждать дольше ни при каких условиях
- Иметь фолбэк: при недоступности службы показывать тариф из своей таблицы по зонам, а не пустое место
- Запрашивать расчёт асинхронно, после того как город выбран, а не блокировать отрисовку корзины
- Писать в журнал каждый неуспешный ответ — иначе о проблемах узнаете от покупателей
Фолбэк по зонам стоит завести даже при идеально работающем API. Служба доставки — внешний сервис, и у него бывают технические работы. Корзина, которая в этот момент не даёт оформить заказ, обходится дороже, чем неточный тариф на один день. Про то, как внешние запросы влияют на отзывчивость страниц, мы писали в разборе Core Web Vitals; корзина здесь — самое уязвимое место.
Коды тарифов и то, что за ними стоит
У перевозчиков расчёт идёт не «по доставке», а по конкретному коду тарифа, и коды различают режим — от двери до двери, от двери до склада, от склада до склада — и тип клиента: для физических лиц и для компаний тарифы разные. Выбрать не тот код легко, а последствия видны только в счёте в конце месяца.
Что проверить при настройке: соответствует ли код выбранному способу доставки в корзине, доступен ли он для вашего договора, поддерживает ли он наложенный платёж, если вы его обещаете, и какие в нём ограничения по весу и объявленной стоимости. Последнее особенно важно для дорогих товаров: превышение лимита объявленной стоимости означает, что при утере вы получите компенсацию по минимальной ставке.
Что показывать покупателю
Цена — это половина информации. Вторая половина — срок, и без него цена не работает: выбор между «400 рублей, 6 дней» и «900 рублей, завтра» человек делает осознанно, а между двумя ценами без срока — наугад.
- Срок в днях, с учётом того, что служба считает рабочие дни от приёма груза, а не от оформления заказа
- Адрес и часы работы выбранного пункта выдачи
- Порог бесплатной доставки и сколько не хватает до него — это работает на средний чек
- Отдельной строкой — доставка в итоге заказа, чтобы она же попала в чек
Про срок отправки стоит добавить честную поправку: если заказы собираются раз в день до полудня, а покупатель оформил вечером, к расчётному сроку надо прибавлять день. Такую поправку мало кто делает, а именно из-за неё возникают претензии.
Своя наценка и бесплатная доставка
Тариф перевозчика — себестоимость, а не цена для покупателя. Между ними обычно есть правила: округление до десятков, надбавка на упаковку, фиксированная цена по городу, бесплатная доставка от суммы заказа.
Бесплатную доставку имеет смысл делать не от суммы вообще, а с оглядкой на вес: при пороге в пять тысяч рублей заказ из одной тяжёлой позиции может съесть всю маржу. Защита — комбинированное условие: бесплатно от суммы, но при весе до определённого предела, дальше доплата. Это настройка правил, а не доработка кода, если расчёт с самого начала спроектирован как отдельный слой.
После оформления: отправление и статусы
Расчёт — только первая половина интеграции. Вторая — создание отправления в службе, получение номера накладной и печать этикетки со штрихкодом. Пока этого нет, менеджер переносит заказы в личный кабинет перевозчика руками, и экономия от расчёта в корзине съедается этой работой.
Здесь важна идемпотентность: повторное нажатие кнопки «передать в доставку» не должно создавать второе отправление. Ключ — номер заказа, и если отправление по нему уже есть, запрос не повторяется, а возвращается существующая накладная.
Статусы перевозчик умеет присылать уведомлениями или отдавать по запросу. Полезнее уведомления: они позволяют автоматически менять статус заказа и писать покупателю «посылка в пункте выдачи» без участия менеджера. Это же избавляет от большей части звонков «где мой заказ».
Чек-лист перед подключением
- Вес и габариты упаковки заполнены хотя бы у товаров, которые реально продаются
- Характеристики приходят из учётной системы, а не вводятся в админке второй раз
- Выбраны коды тарифов и проверено, что они доступны по вашему договору
- Адрес вводится подсказками и сохраняется с кодом адресного объекта и индексом
- Справочник пунктов выдачи хранится локально и обновляется по расписанию
- Есть кеш расчётов, таймаут и тариф по зонам на случай недоступности службы
- В корзине видно и цену, и срок, и порог бесплатной доставки
- Доставка уходит в заказ отдельной строкой — для чека и для учёта
- Создание отправления идемпотентно и не плодит дублей
Мы подключаем расчёт и оформление доставки в интернет-магазинах на 1С-Битрикс, WooCommerce и своих решениях: калькулятор в корзине, карта пунктов выдачи, передача отправлений и статусы. Если весогабаритные характеристики ведутся в учёте, забираем их через интеграцию с учётной системой — так данные остаются в одном месте. Когда корзина уже тормозит из-за внешних запросов, начинаем с ускорения, а не с переписывания интеграции.