Đơn hàng đa kênh và tồn kho: làm sao tránh bán vượt số lượng?
Thiết kế nguồn tồn kho trung tâm, reservation ledger, idempotency, đồng bộ sự kiện và đối soát để tránh bán vượt giữa website, sàn và cửa hàng.

Để tránh bán vượt khi đơn hàng đến từ website, sàn, social và cửa hàng, doanh nghiệp cần một nguồn tồn kho có thẩm quyền cùng cơ chế reservation. Mỗi đơn hàng phải giữ chỗ tồn kho bằng thao tác atomic hoặc có kiểm soát concurrency trước khi xác nhận cho khách. Các kênh chỉ nhận projected availability; không kênh nào được tự coi bản sao tồn kho của mình là sự thật cuối cùng.
Webhook và đồng bộ gần thời gian thực vẫn có độ trễ, có thể gửi lại hoặc sai thứ tự. Vì vậy, kiến trúc phải có idempotency, trạng thái pending/confirmed/released, safety stock và reconciliation. Cố gắng “update số lượng thật nhanh” nhưng không có reservation ledger chỉ làm lỗi hiếm hơn, không loại bỏ overselling.
Xung đột
Vì sao hai kênh có thể bán cùng một sản phẩm cuối cùng?
Đọc tồn kho và trừ tồn kho là hai thời điểm khác nhau.
Website và marketplace cùng đọc available = 1. Cả hai hiển thị còn hàng, cùng nhận checkout và sau đó mới gửi event về hệ thống trung tâm. Nếu xử lý là đọc–sửa–ghi không có concurrency control, cả hai đều thành công. Tương tự, đơn bị hủy nhưng reservation không release, hàng hoàn về chưa kiểm tra, hoặc cửa hàng bán offline khi kết nối gián đoạn tạo sai lệch.
Tồn kho cũng có nhiều trạng thái: on-hand, available, committed, incoming, damaged hoặc safety stock. Shopify InventoryLevel mô hình hóa số lượng theo item và location với các state như available, on-hand, incoming và committed; xem InventoryLevel.
Doanh nghiệp cần thống nhất ý nghĩa từng state và công thức sellable quantity. Nếu mỗi kênh dùng một công thức, đồng bộ cùng một con số vẫn có thể sai.
Dấu hiệu
Hệ thống đang đồng bộ số lượng nhưng chưa quản lý tồn kho
Kiểm tra cả transaction và reconciliation.
Tồn kho âm
Đơn được confirmed sau khi available đã về 0.
Hủy đơn không trả hàng
Reservation hoặc committed quantity không được release.
Cùng event xử lý hai lần
Webhook retry làm trừ tồn kho hoặc tạo đơn lặp.
Lệch theo location
Tổng còn hàng nhưng chi nhánh fulfillment không đủ.
Kiến trúc
Dùng inventory authority và reservation ledger
Xác nhận đơn chỉ sau khi giữ chỗ thành công.
Mỗi channel adapter chuyển order về schema chung với channel, external_order_id, items, quantity, location preference và event version. Order service dùng (channel, external_order_id) làm idempotency key. Inventory service là nơi duy nhất thay đổi committed/available, thực hiện reserve bằng atomic conditional update hoặc compare-and-set.
Reservation có ID, order ID, SKU, location, quantity, expiry và state. Khi payment hoặc điều kiện xác nhận hoàn tất, reservation chuyển committed/allocated. Khi timeout, payment fail hoặc cancel, nó được release idempotently. Safety stock có thể khác theo kênh và location nhưng được quản lý trung tâm.
Inventory adjustment phải có reason và reference để audit. Shopify inventoryAdjustQuantities áp dụng delta theo location, trả adjustment group và hỗ trợ idempotency trong phiên bản API mới; xem inventory adjustment. Đây là nguyên tắc hữu ích dù doanh nghiệp dùng nền tảng nào.

Độ tin cậy
Thiết kế cho webhook gửi lại, đến trễ và mất tạm thời
Event delivery không phải transaction phân tán hoàn hảo.
Xác thực webhook, lưu event ID và raw payload có retention, acknowledge nhanh rồi xử lý qua queue. Consumer phải idempotent và kiểm tra event version hoặc source timestamp trước khi áp dụng thay đổi. Không giả định thứ tự nhận là thứ tự nghiệp vụ. Event không đủ dữ liệu nên kích hoạt fetch theo API hoặc chờ dependency, không tạo state phỏng đoán.
Dùng outbox khi phát sự kiện sau transaction nội bộ để tránh database commit thành công nhưng message không gửi. Với kênh bị gián đoạn, giới hạn quota bán bằng projected availability và safety buffer. Khi kết nối phục hồi, replay event rồi chạy reconciliation. Shopify cung cấp webhook cho thay đổi resource, nhưng webhook vẫn cần lifecycle và error handling phía consumer; xem Shopify webhooks.
Reconciliation so sánh order, reservation, inventory state và fulfillment theo watermark. Mismatch đi vào repair queue; chỉ auto-repair rule xác định, idempotent và có assertion sau sửa.
KPI
Đo tính đúng của tồn kho và trải nghiệm khách
Latency thấp nhưng oversell cao vẫn là thất bại.
Oversell rate
Đơn confirmed nhưng không thể fulfill do thiếu hàng.
Reservation expiry
Reservation hết hạn nhưng chưa release đúng thời điểm.
Inventory divergence
SKU-location lệch giữa authority và kênh vượt tolerance.
Reconciliation lag
Thời gian từ mismatch đến phát hiện và khắc phục.
FAQ
Câu hỏi thường gặp về tồn kho đa kênh
Chọn consistency phù hợp nhưng luôn giữ nguồn sự thật.
Có cần đồng bộ real-time tuyệt đối không?
Không phải lúc nào cũng khả thi. Cần reservation atomic tại authority và projected stock đủ nhanh cho kênh, kèm safety buffer.
Có thể dùng database lock không?
Có trong phạm vi một database. Kiến trúc phân tán thường cần conditional write, versioning hoặc inventory service chuyên trách.
Khi nào release reservation?
Theo payment timeout, checkout abandonment, cancel hoặc rule nghiệp vụ. Release phải idempotent và có audit.
Có nên cho từng kênh giữ tồn kho riêng?
Có thể dùng allocation quota, nhưng quota vẫn cần quản lý tập trung, điều chuyển có kiểm soát và reconciliation.
FlowNexa
Đồng bộ đơn hàng quanh một inventory authority
FlowNexa có thể hỗ trợ thiết kế order schema, reservation ledger, idempotent workflow và dashboard reconciliation cho các kênh hiện có.
Pilot SKU rủi ro cao
Bắt đầu với nhóm bán nhanh hoặc tồn kho thấp.
Đo trước khi mở rộng
Theo dõi oversell, divergence và repair backlog theo channel.



