Настройка автоматической передачи заказов поставщику при дропшиппинге 1С-Битрикс
Менеджер не должен вручную пересылать письмо поставщику при каждом заказе. Это замедляет обработку, порождает ошибки и не масштабируется. Автоматическая передача — обработчик события создания заказа, который без участия человека маршрутизирует позиции поставщикам.
Событие и точка вызова
Битрикс генерирует событие OnSaleOrderSaved при каждом сохранении заказа. Нас интересует только момент создания нового заказа:
// /local/php_interface/init.php
AddEventHandler(
'sale',
'OnSaleOrderSaved',
function(\Bitrix\Sale\Order $order) {
// Только новые заказы, не обновления
if ($order->isNew()) {
\Local\Dropshipping\OrderDispatcher::dispatch($order);
}
}
);
Диспетчер заказов
namespace Local\Dropshipping;
class OrderDispatcher
{
public static function dispatch(\Bitrix\Sale\Order $order): void
{
$grouped = self::groupBasketBySupplier($order->getBasket());
foreach ($grouped as $supplierId => $lines) {
$supplier = SupplierRepository::findById($supplierId);
if (!$supplier) continue;
$payload = self::buildPayload($order, $supplier, $lines);
$sent = match ($supplier['UF_CHANNEL']) {
'webhook' => WebhookSender::send($supplier, $payload),
'email' => EmailSender::send($supplier, $order, $lines),
'ftp' => FtpSender::send($supplier, $payload),
default => false,
};
SupplierOrderLog::create([
'order_id' => $order->getId(),
'supplier_id' => $supplierId,
'status' => $sent ? 'sent' : 'failed',
'payload' => json_encode($payload),
]);
}
}
private static function groupBasketBySupplier(
\Bitrix\Sale\Basket $basket
): array {
$result = [];
foreach ($basket as $item) {
$supplierId = SupplierRepository::getByProduct((int)$item->getProductId());
if ($supplierId) {
$result[$supplierId][] = $item;
}
}
return $result;
}
}
Payload для поставщика
Структура данных, которые передаются поставщику, должна однозначно идентифицировать заказ и содержать всё для сборки и отгрузки:
private static function buildPayload(
\Bitrix\Sale\Order $order,
array $supplier,
array $items
): array {
$props = $order->getPropertyCollection();
return [
'order_id' => $order->getId(),
'order_date' => $order->getDateInsert()->format('Y-m-d H:i:s'),
'delivery_address' => [
'city' => $props->getItemByOrderPropertyCode('CITY')?->getValue(),
'address' => $props->getItemByOrderPropertyCode('ADDRESS')?->getValue(),
'zip' => $props->getItemByOrderPropertyCode('ZIP')?->getValue(),
],
'recipient' => [
'name' => $props->getItemByOrderPropertyCode('NAME')?->getValue(),
'phone' => $props->getItemByOrderPropertyCode('PHONE')?->getValue(),
'email' => $props->getItemByOrderPropertyCode('EMAIL')?->getValue(),
],
'items' => array_map(fn($item) => [
'sku' => SupplierRepository::getSupplierSku($item->getProductId(), $supplier['ID']),
'name' => $item->getField('NAME'),
'quantity' => (int)$item->getQuantity(),
'price' => (float)$item->getPrice(),
], $items),
'comment' => $order->getField('USER_DESCRIPTION'),
'store_id' => $supplier['UF_STORE_ID'],
];
}
Повторные попытки при сбоях
Сетевые ошибки случаются. При неудачной передаче заказ попадает в очередь повторных попыток:
// /local/agents/retry_failed_dispatches.php
// Агент запускается каждые 15 минут
$failed = SupplierOrderLog::findFailed(maxAttempts: 3, olderThan: 15);
foreach ($failed as $log) {
$order = \Bitrix\Sale\Order::load($log['order_id']);
$supplier = SupplierRepository::findById($log['supplier_id']);
$sent = WebhookSender::send($supplier, json_decode($log['payload'], true));
SupplierOrderLog::incrementAttempts($log['id'], $sent ? 'sent' : 'failed');
}
После трёх неудачных попыток — уведомление менеджеру с деталями ошибки.
Сроки реализации
| Состав | Срок |
|---|---|
| Один поставщик, email | 2–3 дня |
| Мультипоставщик, вебхук + email + очередь | 1–1.5 недели |
| С логированием, повторами и уведомлениями менеджеру | 2 недели |







