FE: module purchase_order — đơn mua hàng #
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; mẫu in: 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 purchase_order.orders (quyền
purchase_order.read). listPurchaseOrders lọc status, supplier_id,
warehouse_id; q tìm số đơn.
Vòng đời #
draft → ordered → partial → received → closed. Từ partial đóng được
luôn (chốt thiếu). draft / ordered → cancelled. Trả hàng làm đơn lùi về
partial hoặc ordered.
Mỗi đơn có actions (danh sách + chi tiết): thao tác người gọi làm được lúc
này, đã xét cả trạng thái lẫn quyền (superuser thấy hết). Bật / tắt nút theo đó,
đừng tự suy từ status. actions là chuỗi, giá trị lạ thì bỏ qua.
actions | Gọi | Trạng thái | Quyền |
|---|---|---|---|
place | placePurchaseOrder | draft | purchase_order.update |
receive | receivePurchaseOrder | ordered, partial | purchase_order.receive + stock.view_cost |
return | returnPurchaseOrderItems | partial, received | purchase_order.receive |
close | closePurchaseOrder | received | purchase_order.update |
short_close | shortClosePurchaseOrder | partial | purchase_order.update |
cancel | cancelPurchaseOrder | draft, ordered | purchase_order.update |
delete | deletePurchaseOrder | draft | purchase_order.delete |
Gọi sai trạng thái (đơn vừa đổi ở tab khác) → 409
purchase_order_invalid_status (details.status, details.action): đọc lại
đơn.
Tạo #
createPurchaseOrder (quyền purchase_order.create). Dòng chốt từ lúc tạo: sai
thì huỷ rồi tạo lại. Mỗi dòng theo ĐƠN VỊ MUA (uomId: đơn vị gốc hoặc đơn vị
thêm của sản phẩm; response null = đơn vị gốc), unitCost theo đơn vị mua. Hệ
số chụp lúc tạo vào factor, baseQtyOrdered là số vào kho khi nhận đủ.
Lỗi theo dòng (error.at = lines.<i>):
- 400
purchase_order_variant_invalid,purchase_order_uom_invalid; - 400
purchase_order_qty_not_exact:qty × factorlẻ quá 4 chữ số ở đơn vị gốc.
Lỗi của đơn: 400 purchase_order_supplier_invalid (kể cả nhà cung cấp ngừng
giao dịch), purchase_order_warehouse_invalid.
Nhận hàng, trả hàng #
receivePurchaseOrder:
lines: [{ itemId, qty, lotNumber?, expiryDate?,
manufactureDate?, serialNumbers? }].
itemId là items[].id của đơn, qty theo đơn vị mua. Cả lần nhận vào MỘT
phiếu PN-…, giá vốn mỗi đơn vị gốc = unitCost / factor. Nhận nhiều lần được.
returnPurchaseOrderItems:
lines: [{ itemId, qty, lotNumber?, serialNumbers? }], reason?, note?. Ra
MỘT phiếu PX-…, giảm qtyReceived.
Lỗi theo dòng (error.at = lines.<i>, i là chỉ số trong body):
- 404
purchase_order_item_not_found; - 409
purchase_order_receive_exceeds_ordered(details.remaining, theo đơn vị mua); - 409
purchase_order_return_exceeds_received(details.received); - thiếu hàng khi trả: 409
stock_insufficient_on_hand(details.onHand),stock_exceeds_reserved(hàng đã bị giữ chỗ cho đơn bán); - lỗi lô / serial của kho, xem FE của
stock.
Lô / serial. Biến thể theo lô cần lotNumber (400
stock_lot_number_required); theo serial cần một số serial mỗi đơn vị GỐC,
không phải đơn vị mua: 2 thùng 24 cái là 48 số (400
stock_serial_numbers_required; trùng → 409 stock_serial_exists). Biết chế độ
qua getStockTracking. Trả hàng theo lô / serial phải nêu đúng lô / số đã nhận.
Giá vốn #
unitCost, lineTotal, itemsTotal của đơn là giá mua, người có
purchase_order.read đều đọc được. Nhận hàng thì cần thêm stock.view_cost vì
giá đi vào sổ kho: thiếu thì 403 và actions không có receive.
Mẫu in: purchase_order.receipt #
printDocument({ params: { name: "purchase_order.receipt", id } }), quyền
purchase_order.read. Phiếu nhập hàng: số đã đặt + đã nhận của từng dòng, in
được ở mọi trạng thái. Đơn giá, thành tiền, tổng chỉ có khi người in có
stock.view_cost; thiếu quyền thì bản in không có các cột đó. Không gửi email.
Thiếu quyền, sai id hay phiếu của store khác đều trả 404.