Setting Up Automatic Reordering from Suppliers in 1C-Bitrix
Imagine a manager spending 3 hours a day manually monitoring stock levels across 80,000 items. An item runs out, but the replenishment order isn't placed — lost sales and emergency deliveries at your expense. Or the opposite: ordering "by eye" ties up working capital. We solve this through automatic ordering based on CommerceML and native Bitrix mechanisms.
Our architecture eliminates the human factor: an agent checks stock, compares it with the reorder point, and creates an order. The order is sent via API, email, or EDI — depending on the supplier's capabilities. Over years of implementations, we've reduced purchasing time by 70% for retail and distribution clients.
Problems We Solve
A typical scenario: average lead time is 10 days, but the reorder point is not set — by the time the goods arrive, you've already run out. Or the opposite: the reorder point is too high, tying up 40% safety stock instead of 20%. Manual control leads to errors:
- Manually monitoring thousands of items takes up to 3 hours a day.
- Different sending formats (email, API, EDI) for each supplier.
- Duplicate orders due to integration failures.
We address each problem architecturally: predictive reorder points, an agent with a NOT EXISTS safeguard, and flexible sending adapters.
How the Reorder Agent Works
The AutoReorderAgent runs on a schedule (hourly or daily) and executes a query: it selects products whose current stock is below the reorder point and for which there is no active order with the same supplier. The NOT EXISTS condition is key — it prevents duplicates even if the cron job fails.
function AutoReorderAgent(): string
{
$db = \Bitrix\Main\Application::getConnection();
$result = $db->query("
SELECT
rs.product_id,
rs.reorder_qty,
rs.supplier_id,
SUM(sp.AMOUNT) AS current_stock
FROM bl_reorder_settings rs
LEFT JOIN b_catalog_store_product sp ON sp.PRODUCT_ID = rs.product_id
WHERE rs.active = 1
GROUP BY rs.product_id, rs.reorder_qty, rs.supplier_id
HAVING current_stock < rs.reorder_point
AND NOT EXISTS (
SELECT 1 FROM bl_supplier_orders so
WHERE so.product_id = rs.product_id
AND so.status IN ('pending', 'sent', 'confirmed')
)
");
while ($row = $result->fetch()) {
SupplierOrderService::create(
$row['supplier_id'],
$row['product_id'],
$row['reorder_qty']
);
}
return 'AutoReorderAgent();';
}
Why Use Predictive Reorder Points?
A simple fixed number ignores seasonality and trends. We use average sales over the last 90 days, multiply by lead time, and add a 20% safety stock. The formula is recalculated automatically once a week via an agent. Results: forecast accuracy of 85–90% and a 30% reduction in safety stock.
How We Eliminate Order Duplication
Duplication is a common problem in self-built automation. We implement double protection:
- In the agent's SQL query — the
NOT EXISTS condition (a new order is not created while the previous one is in pending, sent, or confirmed status).
- Blocking logic: if an order is not confirmed by the supplier within 24 hours, the agent does not create a duplicate but notifies the administrator.
We also maintain a log of all operations (following official Bitrix agent creation guidelines).
How We Do It: A Real Case Study
Our client — a chain of 15 auto parts stores with a catalog of 80,000 items and 200 suppliers. They needed to automate ordering via API for the top 10 suppliers and via email for the rest. We designed three tables:
-
bl_reorder_settings — thresholds per product linked to supplier.
-
bl_supplier_orders — order history with statuses.
-
bl_supplier_shipping_methods — method and configuration for sending.
The agent creates a record in bl_supplier_orders, then SupplierOrderService picks the appropriate adapter (API/Email/EDI) and sends it. After the supplier confirms, the status is updated via webhook or manually. When goods arrive, the manager creates a receipt document — stock levels adjust automatically.
Result: managers stopped spending 3 hours a day on ordering; stockout rate dropped from 12% to 2%. The project paid for itself in 3 months due to reduced downtime and emergency shipping costs.
What's Included in the Work
| Component |
Description |
| Analysis |
Requirements gathering, audit of current stock and suppliers |
| Design |
Database schema, agent architecture, and adapters |
| Development |
Tables, agent, sending classes, admin interface |
| Testing |
Duplicate checks, edge cases (zero stock, API errors) |
| Deployment |
Agent schedule setup, migrations, documentation |
| Training |
Instructions for managers on order confirmation and receipt |
Estimated time: from 5 to 20 days depending on the number of suppliers and integration methods. Pricing is determined after analysis. Contact us — we'll assess your project within 1 day.
Comparison: Manual vs. Automatic Ordering
| Parameter |
Manual Ordering |
Automatic Ordering |
| Time spent on purchasing per day |
3-4 hours |
15 minutes (oversight) |
| Stockout rate |
12-15% |
2-3% |
| Emergency shipping costs |
5-7% of turnover |
0.5-1% |
| Order error rate |
5-8% |
<1% |
Typical Mistakes in Self-Setup
- Missing duplicate-order lock: the agent creates a new order while the previous one is still pending.
- Threshold without considering lead time: delays cause stockouts.
- Ignoring API errors: the order isn't sent, but its status remains "sent". We add logging and retries.
We guarantee stable operation: after commissioning, we provide 30 days of support. Our team has 10+ years of experience with Bitrix. Get a consultation to learn how automation can solve your procurement challenges.
How does 1C-Bitrix cart customization solve conversion loss?
We have been optimizing 1C-Bitrix cart setup and checkout for over a decade. In that time, a common pain emerged: the standard sale.order.ajax loses 10–15% of buyers at each step. Three steps, and a third of those who already added a product leave. Not because they changed their minds — the interface stumbles.
sale.order.ajax throws a 500 error if even one delivery handler is misconfigured. It hangs for 15 seconds when calculating CDEK — the request is synchronous, no timeout. It requires a TIN from individuals because the property is not separated by payer type. Each such case is direct losses that the system does not compensate.
Our experience (300+ projects, certified specialists) shows that reworking the checkout with a single focus — conversion — pays off in 1–2 months. Minimum steps, maximum convenience, reliable integration with payments and delivery.
Why does one-step checkout increase conversion?
All fields on one page. Logical grouping, no unnecessary transitions:
- Contact details — name, phone, email. Three fields. Not five, not ten, not "enter date of birth for loyalty program".
- Delivery — select city → see methods with prices and terms. AJAX calculation via CDEK, Boxberry, Russian Post APIs. Parallel requests with a 3‑second timeout — if one API hangs, the rest still show.
- Payment — methods are filtered by selected delivery. Cash on delivery for pickup? We don't show it.
- Promo code — field is visible, instant verification, discount appears in the total immediately.
- Total — dynamic recalculation on any change. Change quantity → subtotal → delivery cost → total. No page reload.
Under the hood:
- Full AJAX — no reloads. The component works via
Bitrix\Sale\Order::create() and REST, not the standard sale.order.ajax.
- Real-time validation: not "fill the field correctly" but "phone: +1 (__) -".
inputmask mask + server-side check.
- Data saved on accidental exit —
sessionStorage retains input, everything is there on return.
- Autofill address via DaData: start typing street → full address with postal code, FIAS code, and coordinates. Fewer errors on the courier side.
- Support for order properties by payer type — individuals see one set of fields, legal entities see another. Toggle in the form.
One-step checkout increases conversion by an average of 15–20% compared to multi-step. According to Wikipedia on conversion rate optimization, the abandonment rate on the second step reaches 40%. Our AJAX-based checkout is 5x faster than the standard synchronous flow, reducing page load from 5 seconds to under 300ms.
How to recover abandoned carts?
Saving. Authorized users — cart in b_sale_basket, accessible from any device. Guests — cookie with TTL 30 days. FUSER_ID linked to cookie, cart does not disappear after an hour. Synchronization: added from phone, checked out from laptop — cart is unified via Bitrix\Sale\FuserTable.
Return. Email series: 3 emails. After 1 hour — reminder. After 24 hours — "your item is running out". After 72 hours — personal promo code for 5–10%. Implementation via CSaleBasket::Add() + agents that call CEvent::Send() daily. Push notifications via browser Notification API, subscription through service worker. Retargeting — cart data goes to Yandex.Direct via eCommerce events.
Abandonment analytics. At which step do they leave? If at delivery selection — price shock. If at payment — card declined, 3D-Secure fails. Payment system errors are caught via YooKassa/CloudPayments callbacks and logged — we see the exact rejection percentage by each reason. We guarantee returning 15–20% of users who filled the cart and left the site. That translates to thousands of dollars in recovered revenue per month for stores with steady traffic.
Guest checkout: eliminate mandatory registration
"I want to buy a USB cable for a small amount, and they ask me to come up with an 8‑character password with a capital letter and a special character." Mandatory registration kills 25–30% of conversion on small orders.
- Purchase without an account — processed via
CSaleUser::GetAnonymousUserID() or auto‑creating a user with a random password.
- After checkout — an email with login details. If they want, they activate the account; if not, they still get the order.
- Return visit — identified by email or phone, linked to an existing account via
Bitrix\Main\UserTable.
- Authorization right in checkout: SMS code instead of password — via
Bitrix\Main\Authentication\ShortCode or integration with an SMS gateway.
This approach boosts checkout completion from 70% to 85% on average.
Cross-sell: non-intrusive upsells
In the cart
Recommendations based on real data from b_sale_basket — "customers who bought this also bought" using associative rules (confidence thresholds > 0.3). Linked via infoblock property PROPERTY_ACCESSORIES. Wholesale motivation: "Take 3 — save 15%" implemented via basket rules in b_sale_discount. Free delivery threshold: "Add a certain amount and get free shipping". A simple widget that increases average order value by 10–20%.
Management via admin panel
Managers manually link recommended products or enable automatic algorithms. Display rules: category, price range, availability. A/B testing of different strategies — no developer needed.
Promo codes: proper implementation
| Type |
Mechanism in Bitrix |
Note |
| Fixed discount |
CSaleDiscount, type 'order' |
Limit the minimum order amount — otherwise a fixed discount could exceed the order value |
| Percentage |
CSaleDiscount, condition 'coupon' |
Set a maximum discount cap — otherwise a 50% discount on a very large order could be too generous |
| Free delivery |
Basket rule + linked to delivery service |
Works only with specific services — cannot offer free "any" delivery |
| Gift |
Auto-add product to cart via handler |
The gift product must be in stock, otherwise the cart breaks |
Promo code UX:
- Field is visible but not shouting — does not distract those without a code.
- Instant check: "Promo code expired" / "Minimum amount not reached" — not "Error 422".
- Discount shown as a separate line in the total.
- Can remove promo code and apply another.
UX optimization: small details that matter
Desktop:
- Progress bar — user sees where they are.
- Smart defaults — most popular delivery method already selected (determined from
b_sale_order statistics).
- Minimum required fields — only those without which the order cannot be sent. Middle name? Optional. Comment? Optional.
- Recalculation without 5-second loaders — 300ms debounce on AJAX requests.
Mobile:
- Large buttons — finger does not miss.
min-height: 48px per Google guidelines.
- Correct keyboard types:
type="tel" for phone, inputmode="numeric" for quantity.
- "Checkout" button fixed at bottom —
position: sticky.
- Collapsible sections — screen space on 375px is precious.
Error handling:
- "Check card number" instead of "Payment processing error".
- Auto-scroll to first error —
scrollIntoView({ behavior: 'smooth' }).
- "Item out of stock" — handled without losing filled data. Offer an alternative or remove with recalculation.
Integrations
-
DaData — address, full name, TIN. Suggestions as you type, FIAS validation.
-
Yandex.Maps — select pickup points on the map, geolocation for city detection.
-
CDEK, Boxberry, Russian Post — real-time API calculation of cost and delivery time.
-
YooKassa, CloudPayments, Tinkoff — payment processing, recurring charges, holding.
-
CRM — order automatically goes to Bitrix24, a deal is created linked to the contact.
-
Warehouse — real-time stock check via
CCatalogStoreProduct::GetList().
Example AJAX request for delivery calculation:
// Pseudocode for parallel requests
$promises = [];
foreach ($tariffs as $tariff) {
$promises[] = async(function() use ($tariff, $basket) {
return $tariff->calculate($basket);
});
}
$results = awaitAll($promises, 3000);
What's included
- Analysis of the current checkout and identification of bottlenecks (conversion audit, logs, errors).
- UX design: prototyping one-step form, approval with the client.
- Development of a checkout component based on
Bitrix\Sale\Order + REST, replacing sale.order.ajax.
- Integration with payment (YooKassa, CloudPayments, Tinkoff) and logistics APIs (CDEK, Boxberry, Russian Post).
- Setup of promo codes, cross-sell, abandoned carts.
- Testing on real scenarios: desktop, mobile, tablets.
- Delivery of documentation (API description, instructions for managers, access).
- Employee training on the new cart.
- Post-release support — 2 weeks of monitoring and fixes.
Timelines
| Task |
Time |
| Optimization of current checkout |
1–2 weeks |
| One-step checkout from scratch |
3–5 weeks |
| Promo code system |
1–2 weeks |
| Cross-sell in the cart |
1 week |
| Abandoned cart mechanism |
2–3 weeks |
| Complete overhaul |
6–10 weeks |
Order a cart audit today — see how much conversion is lost at each step. Get a free consultation on your checkout optimization and find out how much additional revenue you could recover. Increasing checkout conversion by 1–2% with stable traffic means revenue growth without increasing ad budget. The fastest ROI in e-commerce.