Goods Receipt Workflow
This page documents the current mobile รับสินค้าเข้าตรง flow in apps/mobile/src/screens/goodsReceiptStack.
Scope
- Screen entry:
GoodsReceiptList - Detail screen:
goodsReceiptDetailScreen - Submit service:
createGoodsReceiptStockIn(...)
Current behavior
- The detail screen loads line items from the selected goods-receipt document and normalizes each line into editable mobile state.
- Operators assign received quantities through Lot/Batch rows. The line-level received total is stored as
cal, which is the sum of every batch quantity on that line. - The app now allows both partial receipt and over receipt on each line.
- The app no longer blocks submit when a line's received quantity differs from the document quantity.
- On submit, the mobile app sends every line, including lines whose actual received quantity is
0. - For each submitted line, the payload
quantityis the received quantity fromcal, not the original document quantity. - When operators add a product from the picker, the new line's
warehouseCodeprefers the selected productwhsCodebefore falling back to the selected branch fields.
Operator flow
Line quantity rules
line.quantityremains the original document quantity shown on screen for operator reference.line.calis the actual received quantity entered from Lot/Batch rows.- A line may be:
- under received:
cal < quantity - exact received:
cal === quantity - over received:
cal > quantity
- under received:
- The UI allows
0for line and Lot/Batch quantities, but blank values are not allowed. - Negative line and Lot/Batch quantities are blocked.
- Duplicate batch numbers on the same line are still blocked.
Submit rules
- The screen still blocks submit when there are no lines at all.
- The screen blocks submit when any line quantity is blank or negative.
- The screen blocks submit when any Lot/Batch quantity is blank or negative.
- The screen no longer blocks submit when every line has
cal === 0. - Submitted payload lines are not filtered by
cal; all lines are sent. - Submitted payload line quantity is mapped from
cal.
Warehouse code rules
When a product is added from the picker, goodsReceiptDetailScreen sets the new line warehouseCode with this fallback order:
selectedProduct.whsCodebranch.BranchCodebranch.whsGrpCode- empty string
This keeps the stock-in payload aligned with the warehouse code carried by the selected inventory item when that value is available.
Lot/Batch code generation
When an operator adds a new Lot/Batch row in goodsReceiptDetailScreen, the initial batchNumber comes from generateBatchCode(...) in @bsr/utils.
The same shared helper is also used by transferInDetailScreen for dummy-product auto batch creation, and should be reused by POS Terminal when it needs the same code rule.
Generation rules:
- Trim
itemCode. - Remove a leading
BT-prefix case-insensitively. - If the normalized code is shorter than 4 characters, return an empty string.
- Build
first character + YYMMDD + last three characters. - Append
-batchCountwhenbatchCountis greater than0.
Example: BT-ABC123 on 2026-05-21 becomes A260521123.
Shared dummy products
The product picker can append dummy products to the live inventory list. The shared dummy-product helper now lives at:
packages/utils/src/dummyProducts.ts, exported asbuildDummyProductsfrom@bsr/utils
App-local files may keep compatibility re-exports, but Mobile and POS Terminal stock screens should call the shared @bsr/utils boundary so the dummy-product rule does not drift.
It is used by:
goodsReceiptDetailScreen
transferWarehouseDetailScreen no longer appends dummy products; it uses only live product inventory.
The helper chooses the dummy product set by company:
BFPDBreturns the three BFP dummy rows used by goods receipt.- Any other company returns the NFF dummy product set.
BFPDB dummy products
itemCode | itemName |
|---|---|
dummy0001 | DUMMY0001 |
dummy0002 | DUMMY0002 |
dummy0003 | DUMMY0003 |
Non-BFPDB dummy products
itemCode | itemName |
|---|---|
nff-dummy001 | NFF-DUMMY001 |
nff-dummy002 | NFF-DUMMY002 |
nff-dummy003 | NFF-DUMMY003 |
The dummy helper fills standard inventory fields such as unit, zero price, zero stock, company, branch warehouse code, and branch warehouse name so the goods receipt picker receives the same product shape as live inventory rows.
Why this matters
- The backend receives the quantity that was actually received for every line, including
0, which keeps skipped or zero-receipt lines explicit in the payload. - Operators can complete receipt work without being forced to match the original PO quantity exactly.
- Original document quantity remains visible for comparison without forcing the operator to receive that exact amount.