Как интегрировать службы доставки в интернет-магазин
Практика3 минРедакция Innovialabs
Коротко
Интеграция доставки — это четыре связанных процесса через API службы: расчет цены и срока в checkout, автоматическое создание отправления после оплаты, синхронизация статусов в заказе и выбор пункта выдачи, а для нескольких служб — общий слой-адаптер в коде магазина.
Короткий ответ
Полная интеграция службы доставки закрывает четыре задачи:
- Расчет стоимости и срока прямо в checkout.
- Создание отправления через API после оплаты, без ручного ввода в кабинете службы.
- Синхронизация статусов: магазин и покупатель видят, где посылка.
- Пункты выдачи: выбор на карте и передача кода пункта в службу.
Если служб несколько, между магазином и их API ставят слой-адаптер, чтобы остальная система работала с единым форматом.
Расчет стоимости в checkout
Покупатель должен видеть цену и срок доставки до оплаты. Варианты расчета:
- Через API службы в реальном времени — точнее всего, учитывает вес, габариты и адрес.
- По своей таблице тарифов — быстрее и не зависит от доступности чужого API, но таблицу нужно обновлять.
- Гибрид: таблица как запасной вариант, если API не ответил вовремя.
Что нужно для точного расчета:
- вес и габариты у каждого товара в каталоге;
- правила упаковки: несколько товаров в одной коробке или в разных;
- склад отправки, если их несколько;
- нормализованный адрес или координаты получателя.
Кэшируйте результаты расчета на короткое время и ставьте таймаут на запрос: checkout не должен зависать из-за медленного ответа службы.
Создание отправления через API
После оплаты (или подтверждения заказа с оплатой при получении) магазин отправляет в службу заявку: получатель, адрес или пункт выдачи, состав, вес, объявленная ценность, сумма наложенного платежа.
Хорошая практика:
- очередь задач вместо синхронного вызова: если API службы недоступен, заявка повторится позже;
- идемпотентность: повтор не создает второе отправление;
- сохранение трек-номера и печать этикеток прямо из админки;
- понятная ошибка менеджеру, если служба отклонила заявку.
Синхронизация статусов
Есть два способа получать статусы:
- Webhook — служба сама присылает событие при изменении статуса. Быстро и экономно.
- Опрос (polling) — магазин по расписанию запрашивает статусы активных отправлений. Подходит, если webhook нет.
Статусы разных служб называются по-разному, поэтому их сопоставляют с внутренними: «Создан», «Передан в доставку», «В пути», «В пункте выдачи», «Доставлен», «Возврат». На смену статуса вешают действия: уведомление покупателю, закрытие заказа, запуск процесса возврата.
Пункты выдачи
- Список пунктов загружают из API службы и регулярно обновляют — пункты открываются и закрываются.
- В checkout пункты показывают на карте и списком с поиском, адресом и часами работы.
- В заказ сохраняют идентификатор пункта из системы службы, а не только адрес текстом.
- Учитывайте ограничения пункта: максимальный вес и габариты, прием наложенного платежа.
Несколько служб доставки
Чтобы добавление новой службы не превращалось в переделку магазина, опишите общий интерфейс и реализуйте его для каждой службы отдельно:
interface CarrierAdapter {
quote(order: ShipmentDraft): Promise<Quote[]>;
createShipment(order: ShipmentDraft): Promise<{ trackingNumber: string }>;
getStatus(trackingNumber: string): Promise<ShipmentStatus>;
listPickupPoints(city: string): Promise<PickupPoint[]>;
}
Тогда checkout запрашивает варианты у всех подключенных служб параллельно и показывает общий список, а правила выбора (самая дешевая, самая быстрая, приоритетная для региона) живут в одном месте.
Альтернатива — агрегатор доставки: одна интеграция дает доступ к нескольким службам. Это быстрее на старте, но добавляет посредника в цепочку и зависимость от его тарифов и API.
Частые ошибки
- В каталоге нет веса и габаритов, и расчет врет.
- Создание отправлений вручную при сотнях заказов в день.
- Нет таймаута на расчет — checkout зависает вместе с API службы.
- Статусы не синхронизируются, и поддержка отвечает на вопросы «где мой заказ» вручную.
- Возвраты через службу доставки не отражаются в остатках.