Система управління складськими залишками для e-commerce

Зазначимо: коли два покупці одночасно кладуть у кошик останній екземпляр товару, перемагає той, хто швидше натиснув «Оформити замовлення». Без системи управління залишками другий отримає повідомлення про відсутність після оплати — це **overselling**. Ми будуємо механізми, які виключають такі ситуаці

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
Система управління складськими залишками для e-commerce
Середній
~5 днів

Наші компетенції:

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1419
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1287
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    984
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1248
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    984
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    998

Зазначимо: коли два покупці одночасно кладуть у кошик останній екземпляр товару, перемагає той, хто швидше натиснув «Оформити замовлення». Без системи управління залишками другий отримає повідомлення про відсутність після оплати — це overselling. Ми будуємо механізми, які виключають такі ситуації: атомарне резервування, синхронізацію з обліковими системами та сповіщення про дефіцит. Нижче — технічні деталі, які дозволять вашій платформі працювати з реальними запасами, а не з цифрами в адмінці.

Проблеми, які вирішує система

Перша — конкурентне резервування. Якщо в момент оформлення замовлення не заблокувати одиницю, два користувачі можуть купити один товар. Друга — завислі резерви. Покинуті кошики — не рідкість, і якщо не звільняти резерви, через тиждень половина залишків буде недоступна. Третя — розсинхронізація із зовнішніми обліковими системами. Коли 1С або МійСклад оновлюють кількість, а магазин продовжує продавати за старими даними, виникають заборгованості.

Схема даних

Базова структура для PostgreSQL:

CREATE TABLE product_variants ( id BIGSERIAL PRIMARY KEY, product_id BIGINT NOT NULL REFERENCES products(id), sku VARCHAR(100) NOT NULL UNIQUE, attributes JSONB NOT NULL DEFAULT '{}', stock_qty INTEGER NOT NULL DEFAULT 0, reserved_qty INTEGER NOT NULL DEFAULT 0, low_stock_threshold INTEGER NOT NULL DEFAULT 5, CHECK (stock_qty >= 0), CHECK (reserved_qty >= 0), CHECK (stock_qty >= reserved_qty) ); CREATE TABLE stock_movements ( id BIGSERIAL PRIMARY KEY, variant_id BIGINT NOT NULL REFERENCES product_variants(id), delta INTEGER NOT NULL, type VARCHAR(50) NOT NULL, reference VARCHAR(255), created_at TIMESTAMP NOT NULL DEFAULT NOW() ); 

available_qty = stock_qty - reserved_qty обчислюється на льоту. Лог stock_movements фіксує кожну операцію для аудиту. Індекси на (product_id, sku) та (variant_id, created_at) прискорюють пошук і звітність.

Атомарне резервування без гонок

Атомарність забезпечується через UPDATE ... RETURNING:

UPDATE product_variants SET reserved_qty = reserved_qty + :qty WHERE id = :variant_id AND (stock_qty - reserved_qty) >= :qty RETURNING id, stock_qty, reserved_qty; 

Якщо рядок не повернувся — товару недостатньо. В Laravel це обгортається в транзакцію з lockForUpdate(). Для високонавантажених сценаріїв використовуйте песимістичне блокування рядка, щоб уникнути взаємоблокувань.

Чому важливо звільняти резерви?

Покинутий кошик — втрачений залишок. Два підходи: TTL через чергу (точність до хвилини) та scheduled cleanup (простіше, але ±5 хвилин). Для магазинів до 1000 замовлень на день достатньо cron-завдання кожні 5 хвилин. Порівняння методів:

Характеристика TTL через чергу Scheduled cleanup
Точність звільнення ±1 хвилина ±5 хвилин
Залежність від інфраструктури Потрібна черга (Redis/Beanstalkd) Тільки cron
Навантаження при 1000 замовлень/день Низька Низька
Як налаштувати TTL в Laravel?
// В сервіс-провайдері реєструємо job use App\Jobs\ReleaseReservation; $ttl = Carbon::now()->addMinutes(30); ReleaseReservation::dispatch($variantId, $qty)->delay($ttl); 

Якщо замовлення оформлено, job видаляється. Якщо ні — резерв автоматично зменшується.

Інтеграція з 1С та МійСклад

Залишки надходять із зовнішніх систем двома способами:

Режим Опис Коли вибрати
Webhook Склад викликає ваш endpoint при зміні Висока частота оновлень
Pull Магазин опитує систему раз на N хвилин Обмеження по безпеці

Важливе правило: при імпорті оновлюйте тільки stock_qty, не чіпаючи reserved_qty. Інакше активні резерви злетять.

Як відображати статус на вітрині?

Для покупця важливо бачити реальну наявність. Ми обчислюємо доступну кількість та відображаємо:

  • Якщо available_qty > low_stock_threshold — «В наявності».
  • Якщо 0 < available_qty ≤ low_stock_threshold — «Залишилось N шт.».
  • Якщо available_qty = 0 — «Немає в наявності».
  • Якщо налаштовано передзамовлення — «Під замовлення, 5–7 днів».

Для високонавантажених сторінок статус кешується в Redis з TTL 60 секунд.

Як налаштувати сповіщення про низький залишок?

Оповіщення менеджера закупівель тригериться при оновленні stock_qty нижче порогу. В Laravel це observer:

class ProductVariantObserver { public function updated(ProductVariant $variant): void { if ($variant->wasChanged('stock_qty') && $variant->isLowStock()) { LowStockAlert::dispatch($variant); } } } 

Алерт надсилається в email, Telegram або Slack. Додатково можна налаштувати SMS для критичних позицій.

Як оптимізувати запити для відображення залишків?

При виведенні списку товарів типова помилка — N+1 запит: для кожного варіанту вибираємо залишок окремо. Використовуйте withCount або віконні функції. Наприклад, для PostgreSQL:

SELECT p.*, SUM(sm.delta) OVER (PARTITION BY sm.variant_id) AS current_stock FROM products p LEFT JOIN stock_movements sm ON sm.variant_id = p.id WHERE ... 

Цей запит виконується за один прохід. Для великих каталогів агрегуйте дані в Redis через scheduled job.

Процес впровадження

  1. Проектування схеми даних та вибір методів резервування.
  2. Реалізація атомарних операцій з тестуванням на конкурентність.
  3. Налаштування звільнення резервів (TTL або cron).
  4. Інтеграція із зовнішніми обліковими системами (1С, МійСклад).
  5. Розробка панелі адміністрування з фільтрами та експортом.
  6. Навантажувальне тестування та деплой.

До складу робіт входить: підготовка документації по схемі даних та API, передача вихідного коду та доступів до репозиторію, навчання адміністраторів роботі з панеллю, гарантійна підтримка протягом 30 днів після деплою.

Строки реалізації

Етап Час
Базове резервування + лог 3–5 днів
Інтеграція з обліковою системою +3–5 днів
Кешування та відображення на вітрині +2 дні
Панель залишків в адмінці +2–3 дні
Разом 1–2 тижні

Правильно спроектована система залишків знижує втрати від overselling на 15–20% та виключає ручний контроль. Наприклад, для магазину з 5000 замовлень на місяць усунення overselling зберігає до 150 000 гривень виручки щомісячно. Додатково автоматизація закупівель економить до 100 000 гривень на місяць на зарплаті логіста.

Зв'яжіться з нами для аудиту поточної схеми. Отримайте консультацію з архітектури вашого складу — замовте її просто зараз.