Borrow Fish
Borrow Fish manages fish/product borrowing before the normal sales-order flow. It is close to Sales Orders because it starts with a customer, branch/warehouse context, product lines, quantities, and later can become a sales order. The important differences are borrow type, pickup/license-plate rules for non-main SPEC borrows, expected purchase quantity, acceptance/stock-cut workflow, retry handling, and conversion to sales order.
App Entry Points
| App | Target |
|---|---|
| Mobile | BorrowList -> BorrowDetail |
| POS Terminal | borrowFish -> BorrowDetailForm in HomeScreen |
Borrow Types
| Type | Label |
|---|---|
SPEC | Customer sample/inspection |
MARKET | Market visit |
VIDEO | Video shooting |
SEMINAR | Seminar |
DESTROY | Destroy |
LAB | Research/lab |
The type must be selected before products can be added. For a non-main branch, changing a borrow to SPEC is blocked when the document already has product items; users must remove items first because SPEC adds required pickup and customer-license-plate rules.
Lifecycle
End-To-End Workflow
Header Rules
| Topic | Behavior |
|---|---|
| Customer | Borrow starts from a selected customer and stores customer code/name context. |
| Branch and warehouse group | Payload carries branchId, whGrpCode, and whGrpName from selected branch/document context. |
| Borrow type | Required before adding products or confirming. |
| Notes | Stored in notes and can be updated while the draft is editable. |
dateOfPickup | Sent only for SPEC; non-SPEC payload clears it to null. |
| Customer license plate | Required before adding items for non-main SPEC; kept in customerLicensePlate. |
| Pickup date edit lock | For non-main SPEC, pickup date cannot be changed after items exist. |
| Past pickup date | Mobile blocks pickup dates before the current day. |
Product And Quantity Rules
Important item rules:
| Rule | Main Branch | Non-main Branch |
|---|---|---|
| Expected purchase quantity | Not required; payload sends 0/undefined. | Required and must be a number greater than 0. |
| Quantity per line | SPEC (customer sample/inspection) only: maximum 3. Other borrow types have no per-line quantity cap. | Maximum 5 for every borrow type. |
| Number of product rows | SPEC only: maximum 3 rows. Other borrow types have no row-count cap. | No 3-row cap in the UI guard. |
| SPEC pickup/license plate | Not required by the branch-specific guard. | Required before adding product. |
| Quantity format | Positive integer only. | Positive integer only. |
| Stock guard | Add checks onHand - booking; edit allows available stock plus the original item quantity. | Same. |
The item payload is built from product inventory data, including product code/name, quantity, expected quantity, price, amount, weight, warehouse, company, tax/VAT, UOM, weight-base flag, step-price flag, and editPriceBy = null.
Editing Existing Items
Existing item edits are allowed only while the document is an editable draft. On edit, the app reloads the current product inventory by product code and calculates maxEditableStock = availableStock + originalQty for the same product. This lets the user keep or reduce an existing reservation while still preventing the final quantity from exceeding stock.
For non-main branch edits, expectedQty remains required and must be greater than 0. The per-line quantity cap remains 5 for every non-main borrow type. On the main branch, the cap is 3 only for SPEC; other borrow types have no per-line cap. All types still require a positive integer quantity and available stock.
Product Picker And First-Item Persistence
- When an existing borrow has a
borrowId, adding products does not show a blocking full-screen loading state. The product picker remains open after a successful add so the operator can continue adding products. - A new draft follows a two-stage persistence flow: create the borrow header first, use the returned
borrowIdas the item-create identity, then create the first item. borrowNois a display/document number and is not used as a substitute forborrowIdwhen creating the item.- After the first item is created, the app refreshes the borrow detail/list and synchronizes the route with the returned borrow identity. The header and first item therefore appear immediately instead of only after a second item is added.
- Mobile and POS Terminal follow the same persistence behavior.
Confirm, Accept, Complete, Retry
Confirm saves the latest header first, then calls confirmBorrow. After confirmation, direct draft editing is locked by status. Completion uses approveBorrow when the document has no failed sub-borrow. If hasFailedSubBorrow is true, the complete action becomes a retry action and calls retryBorrow.
Convert To Sales Order
The convert button is shown when all of these are true:
| Condition | Required Value |
|---|---|
| Branch | Non-main branch |
| Borrow type | SPEC |
| Status | DONE |
Conversion calls convertBorrow(borrowId). The converted document should carry customer, branch/warehouse, product, quantity, expected quantity, and pricing context into the Sales Order flow. After conversion, the borrow status becomes CONVERTED.
Print Rules
Two print paths are exposed:
| Behavior | |
|---|---|
| Borrow pack | Prints customer/borrow/product packing document. |
| Borrow storage | Prints warehouse/storage-facing borrow document. |
Both print actions require at least one product item. Printing does not change business status by itself.
Permissions And Guards
| Permission | Rule |
|---|---|
| Terminal menu key | borrowFish |
| Menu deptCode set | -2, 1, 2, 3, 4, 7, 29, 21, 8, 9, 12, 13, 14, 30, 16, 20, 22, 23, 27, 28 |
| Create borrow | Admin, or dept -2, 1, 2, 4, 7, 8, 9, 13, 16, 21, 29 |
| Cancel/delete borrow | Admin; owner when status NEW; or allowed cancel depts/users while status is NEW or WAITING |
| Cancel departments | -2, 1, 2, 4, 9; dept 8 and 22 also override for NEW/WAITING |
| Cancel override user codes | 008045, 012521, 012508, 008051, 012388, 012428, 008060 |
| B1 processing | Admin, or dept 2, 8, 12, 22, 28 |
| Owner processing | The document owner can process if borrow type is not DESTROY |
| Main branch processing | Main branch requires B1 processing permission |
| Draft editing | Status must be NEW and current user must own the draft, or the draft is not persisted yet |
| Borrow type editing | Allowed before persistence or by the document owner |
Mobile vs POS Terminal
| Topic | Mobile | POS Terminal |
|---|---|---|
| Navigation | Full borrow stack list/detail | HomeScreen split-pane menu borrowFish |
| Product flow | Borrow detail screen and product-flow hook | Borrow detail form, panels, and product picker |
| Header save | Saves through borrow service when existing detail changes | Saves raw detail through HomeScreen handlers |
| Validation | Same business rules in mobile components | Same business rules in HomeScreen handlers |
| Printing | printBorrowPack, printBorrowStorage | Same print utilities |
| Conversion | Calls convertBorrow and refreshes detail | Calls convertBorrow and refreshes split list/detail |
API And Data Map
| Operation | Service |
|---|---|
| List | getBorrows |
| Detail | getBorrowDetail(borrowId) |
| Create/update/delete header | createBorrow, updateBorrow, deleteBorrow |
| Item CRUD | createBorrowItem, updateBorrowItem, deleteBorrowItem |
| Confirm | confirmBorrow |
| Accept | acceptBorrow |
| Complete/cut stock | approveBorrow |
| Retry failed sub-borrow | retryBorrow |
| Convert to sales order | convertBorrow |
Developer Handoff Map
| Area | Code |
|---|---|
| Mobile permissions/helpers | apps/mobile/src/utils/borrow.ts |
| Mobile list/detail | apps/mobile/src/screens/borrowStack/borrowListScreen, borrowDetailScreen |
| Mobile product flow | apps/mobile/src/screens/borrowStack/borrowDetailScreen/useBorrowProductFlow.ts |
| Terminal permissions/panels | apps/pos-terminal/src/screens/HomeScreen/BorrowPanels.tsx |
| Terminal detail | apps/pos-terminal/src/screens/HomeScreen/BorrowDetailForm.tsx |
| Terminal handlers | apps/pos-terminal/src/screens/HomeScreen/index.tsx |
| Services | apps/*/src/services/borrow.ts |
| Converted target | Sales Order docs and order services |