xforge · tài liệu FE

FE: module stock — tồn kho #

Phần chung (khởi tạo client, lỗi, danh sách, ngôn ngữ) ở tài liệu FE của Core: docs/fe/common.md; báo cáo, xuất / nhập, realtime: docs/fe/cms.md (bản đọc: xforge-documentation, ADR-0102 của xforge-core). Sửa file này CÙNG PR khi đổi hành vi FE thấy được của module.

Chỉ có ở CMS (XforgeClient). Menu: key stock.levels (quyền stock.read).

Số lượng là CHUỖI theo ĐƠN VỊ GỐC của sản phẩm, ≤ 4 chữ số lẻ, dạng gọn ("12", "2.5"). Đừng đổi sang Number để cộng trừ; đơn vị bán thêm do chứng từ quy đổi trước khi vào kho.

Số tồn #

listStockLevels, getStockLevel: mỗi dòng là một (kho, biến thể), mặc định ít hàng khả dụng trước. Lọc warehouse_id, variant_id, location_id, is_low, available.lte / .gt.

Số tồn chỉ đổi qua nhập / điều chỉnh / chứng từ. Mỗi lần đổi onHand sinh phiếu tự động (PN-… nhập, PX-… xuất), xem ở listStockVouchers / getStockVoucher; sổ cái ở listStockMovements (lọc reference_type + reference_id để xem biến động của một chứng từ).

Ghi #

Thao tácQuyềnGhi chú
createStockReceiptstock.receiveNhập tay, trả về phiếu PN-…
createStockAdjustmentstock.adjustqtyDelta có dấu, reason bắt buộc; trả vouchers (tối đa mỗi chiều một)
createStockSupplierReturnstock.receiveTrả nhà cung cấp, trả về phiếu PX-…
setStockTrackingstock.manage_trackingĐổi chế độ none / batch / serial
previewStockAllocationstock.readGợi ý kho xuất theo priority, chỉ đọc; shortfall là phần thiếu

Cả request trong một transaction, tối đa 200 dòng. Lỗi của một dòng mang error.at = lines.<i>, i là chỉ số trong body gửi lên: tô đúng dòng đó.

Thiếu hàng. Giảm onHand bị chặn khi tụt dưới 0 hoặc dưới phần đã giữ chỗ:

Điều chỉnh gửi allowDeficit: true thì không bị chặn: chỉ cho người dùng chọn khi đếm thật thấy thiếu, có xác nhận rõ ràng, vì tồn có thể âm.

Lô / serial #

getStockTracking trả chế độ của biến thể. Đổi chế độ chỉ khi không còn tồn / giữ chỗ / hàng đang chuyển ở mọi kho (409 stock_tracking_locked).

Chế độNhậpĐiều chỉnh, trả nhà cung cấp
noneGửi kèm lô / serial → 400 stock_not_trackedNhư trên
batchlotNumber bắt buộc (400 stock_lot_number_required), hạn dùng tuỳ chọn; lô đã có thì cộng vàoĐiều chỉnh: batchId (400 stock_batch_or_serial_required). Trả: lotNumber (404 stock_batch_not_found)
serialserialNumbers, mỗi đơn vị một số (400 stock_serial_numbers_required; trùng → 409 stock_serial_exists, details.serialNo)Điều chỉnh: serialId, ±1 (400 stock_serial_adjust_unit). Trả: serialNumbers (404 stock_serial_not_found)

Danh sách: listStockBatches (on_hand.gt=0 ẩn lô rỗng), listExpiringStockBatches (days, expiryStatus: expired, critical, warning), listStockSerials (status). Lô hết hạn vẫn nằm trong onHand nhưng không được giữ chỗ / xuất. status của serial có thể thêm giá trị: giá trị lạ thì hiện nguyên.

Giá vốn (stock.view_cost) #

Không có quyền thì unitCost đọc ra null ở mọi nơi (sổ cái, phiếu, lô), kể cả khi có giá trị thật: ẩn cột theo quyền, đừng hiện "0" hay "chưa có". Gửi unitCost khác null mà thiếu quyền → 403 field_write_forbidden, nên ẩn luôn ô nhập. currency vắng = tiền của store; nhập lô đã có giá vốn bằng tiền khác → 409 stock_batch_currency_mismatch.

Báo cáo #

Chạy qua màn báo cáo chung (listReports, runReport). Quyền stock.read; thiếu quyền thì báo cáo không có trong danh sách và runReport trả 404. Tham số warehouse là MÃ kho (không phải id), bỏ trống = mọi kho.

unitCost là giá vốn bình quân gia quyền của mọi lần nhập có giá vốn của biến thể (cả store, theo tiền của store): chuyển kho không mang giá vốn theo nên không tính theo từng kho. Đây là số tham khảo, biến thể chưa nhập có giá vốn thì null.

Tập quá 10 000 dòng → 400 report_too_large: yêu cầu lọc theo kho.

Tồn đầu kỳ: dataset stock.opening_balance #

Qua màn xuất / nhập chung (listDatasets, exportDataset, importDataset). Xuất: quyền stock.read; nhập: quyền stock.receive.

CộtNhậpGhi chú
warehouseCodeBắt buộcMã kho
skuBắt buộcSKU của biến thể
qtyBắt buộc≥ 0; 0 = bỏ qua dòng
unitCostTuỳ chọnChỉ người có stock.view_cost; xuất ra trống nếu thiếu quyền
Còn lạiBỏ quaproductName, reserved, available, tracking: chỉ xuất

Mỗi (kho, biến thể) chỉ nhập đầu kỳ MỘT lần: nhập lại cùng file không cộng hai lần, dòng đã nhập tính vào skipped kể cả khi qty đổi. Muốn sửa số thì dùng điều chỉnh. Nhập thành công sinh phiếu PN-…, mỗi kho một phiếu; sổ cái lọc được bằng reference_type=stock.opening_balance.

Tối đa 2 000 dòng mỗi file (stock_opening_balance_too_many_rows), vì cả file giữ bộ đếm phiếu nhập của store tới lúc xong. Nhiều hơn thì chia file.

Dòng lỗi huỷ cả file. Mỗi lỗi có line, column, rule, code, message (đã dịch); KHÔNG có details, nên hiện message, rẽ nhánh theo code:

Trong lúc nhập, các lần nhập kho khác của store phải chờ tới khi file xong: file lớn nên chạy nền (startDatasetImport) và ngoài giờ cao điểm.

Cảnh báo sắp hết hàng #

Ngưỡng đặt trên từng dòng tồn (lowStockThreshold, hoặc gửi kèm khi nhập). Dòng không đặt ngưỡng thì không bao giờ cảnh báo. isLow nghĩa là available ≤ ngưỡng (gồm cả bằng).

Bật ở cấu hình stock.low_stock_alert { enabled } (mặc định false, cấp account hoặc store, qua màn cấu hình chung). Khi bật, mỗi 7 giờ sáng giờ của store:

count không tính kho ngừng hoạt động, biến thể ngừng bán, sản phẩm lưu trữ, nên có thể nhỏ hơn số dòng is_low=true trong danh sách.

Màn hình dựng sẵn #

listMenu() → mục stock.levels có screen (type: "crud"): CMS chung vẽ được từ getMenuScreen({ params: { key: "stock.levels" } }) mà không cần code riêng (tài liệu FE của Core: cms.md §3.1). Có: danh sách tồn (kho, sản phẩm, SKU, vị trí, chế độ theo dõi, tồn thực / đã giữ / có thể bán, ngưỡng thấp; sắp theo có thể bán; lọc kho / biến thể / tồn thấp), sửa ngưỡng tồn thấp.

KHÔNG có (màn tay): đổi vị trí của dòng tồn (locationId chỉ nhận vị trí của kho của dòng — ô chọn phụ thuộc dữ liệu khác, chưa có trong định dạng), phiếu nhập / điều chỉnh / trả nhà cung cấp, lô / serial, sổ cái.

Quyền ngoài module mà màn hình dùng (thiếu thì CMS ẩn / rơi về ô nhập thường):

Nguồn: xforge-modules: modules/inventory/stock/FE.md