Configuring Multi-Supplier Order Logic in 1C-Bitrix
In dropshipping, a single customer order can contain products from different suppliers. Each supplier needs to receive only their portion. Bitrix does not split orders by suppliers automatically — the logic is implemented through event handlers and custom tables.
Implementation Options
Option 1 — unified order, separate notifications to suppliers. The order in Bitrix remains unified in b_sale_order. When the order is placed, the OnSaleOrderSaved handler determines which basket items belong to which suppliers and sends each supplier a notification containing only their products. Simpler, but does not allow tracking shipment per supplier separately.
Option 2 — splitting into child shipments. One order, but the \Bitrix\Sale\Shipment object is created separately for each supplier. This is a native Bitrix mechanism — one order can have multiple shipments with different parameters.
Option 3 — splitting into separate orders (sub-orders). When the order is placed, a parent order and multiple child orders are created based on the number of suppliers. More complex, but provides full independence of statuses.
Implementation via Separate Shipments (Option 2)
When saving an order, determine suppliers and create shipments:
AddEventHandler('sale', 'OnSaleOrderSaved', function(\Bitrix\Main\Event $event) {
$order = $event->getParameter('ENTITY');
$isNew = $event->getParameter('IS_NEW');
if (!$isNew) return;
$basket = $order->getBasket();
$supplierItems = [];
// Group basket items by supplier
foreach ($basket->getOrderableItems() as $item) {
$supplierId = getSupplierByProductId($item->getProductId());
if ($supplierId) {
$supplierItems[$supplierId][] = $item;
}
}
$shipmentCollection = $order->getShipmentCollection();
foreach ($supplierItems as $supplierId => $items) {
$shipment = $shipmentCollection->createItem();
$shipment->setField('DELIVERY_ID', getSupplierDeliveryId($supplierId));
$shipment->setField('CUSTOM_PRICE_DELIVERY', 'N');
$shipmentItemCollection = $shipment->getShipmentItemCollection();
foreach ($items as $basketItem) {
$shipmentItem = $shipmentItemCollection->createItem($basketItem);
$shipmentItem->setQuantity($basketItem->getQuantity());
}
}
$order->save();
});
The getSupplierByProductId() function reads the SUPPLIER_ID property from b_iblock_element_property.
Notifications to Suppliers
Each supplier receives an email or message containing only their products. Sending through \Bitrix\Main\Mail\Event::send() with a custom template:
foreach ($supplierItems as $supplierId => $items) {
$supplierEmail = getUserEmail($supplierId);
\Bitrix\Main\Mail\Event::send([
'EVENT_NAME' => 'SUPPLIER_ORDER_NOTIFY',
'LID' => SITE_ID,
'C_FIELDS' => [
'SUPPLIER_EMAIL' => $supplierEmail,
'ORDER_ID' => $order->getId(),
'ORDER_ITEMS' => formatItemsForEmail($items),
'BUYER_ADDRESS' => getOrderDeliveryAddress($order),
],
]);
}
The SUPPLIER_ORDER_NOTIFY template is created in "Email Events" in the administrative interface.
Status Tracking by Suppliers
The HL-block SupplierOrderStatus records the status of each order portion:
-
UF_ORDER_ID— Bitrix order ID -
UF_SUPPLIER_ID— supplier -
UF_STATUS—new/confirmed/shipped -
UF_TRACKING_NUMBER— tracking number
An agent verifies whether all suppliers have set shipped and changes the main order status:
function checkAllSuppliersShippedAgent(): string
{
// Find orders where all suppliers have shipped
$connection = \Bitrix\Main\Application::getConnection();
$orders = $connection->query("
SELECT UF_ORDER_ID
FROM b_hl_supplier_order_status
GROUP BY UF_ORDER_ID
HAVING COUNT(*) = SUM(CASE WHEN UF_STATUS = 'shipped' THEN 1 ELSE 0 END)
AND UF_ORDER_ID IN (
SELECT ID FROM b_sale_order WHERE STATUS_ID NOT IN ('F','C')
)
");
while ($row = $orders->fetch()) {
$order = \Bitrix\Sale\Order::load($row['UF_ORDER_ID']);
if ($order) {
$order->setField('STATUS_ID', 'S'); // status "Shipped"
$order->save();
}
}
return __FUNCTION__ . '();';
}
Setup takes 2–5 days depending on the chosen splitting variant and notification complexity.







