Products
Products is the branch-scoped inventory lookup used by sales orders, booking price, transfer, goods receipt, and return flows. When opened from the Products menu, both Mobile and POS Terminal are read-only lookup screens. Mobile can show an add-to-sales-order form only when ProductList/ProductDetail is opened from an existing sales-order flow with orderId or draftOrder; the normal POS Terminal product menu follows the standalone Mobile behavior and does not show that add form.
The screen is useful for developers because it shows the product shape reused by downstream documents: item identity, warehouse, SAP stock, booked stock, available stock, price, UOM, weight control, company, color, and step-price rows.
App Entry Points
| App | Target |
|---|---|
| Mobile | ProductList -> ProductDetail |
| POS Terminal | product -> ProductDetailForm |
User Workflow
Data And API Flow
| Concern | Behavior |
|---|---|
| Branch context | Both apps call getProductBranchContext(). The selected branch must contain whsGrpCode; otherwise the product menu fails with a missing branch data error. |
| Inventory refresh | syncProductInventory(context, page) triggers MST inventory refresh and fire-and-forget promotion sync to Firebase. |
| Main branch inventory API | If branchCode === whsGrpCode, refresh calls /products?...&whGrpCode={whsGrpCode}. |
| Non-main branch inventory API | If branch and warehouse group differ, refresh calls /products/sub-inventories?...&whGrpCode={branchCode}&whsCode={whsGrpCode}. |
| Firebase collection | Inventory is read from ${whsGrpCode}-inventories. |
| Warehouse codes | Both apps include whsGrpCode, PC-{whsGrpCode}, and NF-{whsGrpCode}. |
| List filters | Rows with price <= 0 are ignored, duplicate itemCode rows are deduped, and product detail/list require usable itemCode. |
| Step price | Detail loads getProductStepPrice({ itemCode, uomCode }) only when stepPriceFlag is truthy. Sales and booking screens reuse this concept when quantity changes. |
| Dummy products | Some document flows merge dummy products for operation-specific cases, but this product menu is the inventory-product lookup. |
List Behavior
| Topic | Mobile | POS Terminal |
|---|---|---|
| Loading model | Calls syncProductInventory() once, then subscribes to Firestore with subscribeProductInventory(). | Calls getProductSplitList({ page, search, bookingOnly }) and appends pages with duplicate IDs merged. |
| Search | Local in-memory search by itemName and itemCode. | Service search matches Mobile and searches only itemName and itemCode. |
| Tabs | ทั้งหมด and ติดจอง; booked tab keeps products where booking > 0. | Same tabs; ติดจอง passes bookingOnly: true to the split list service. |
| Summary | Header shows total product count and booked product count. | Split list uses the generic pane count and supports load more. |
| Refresh | Pull-to-refresh calls syncProductInventory(branchContext). | Pull-to-refresh and menu reload call the paged split list again. |
| Empty state | Shows "not found" after the first snapshot is received. | Uses the shared split-pane empty/error/loading states. |
Detail Behavior And Actions
| Action | Mobile | POS Terminal |
|---|---|---|
| Open detail | Navigates to ProductDetail with productId, itemCode, itemName, stepPriceFlag, uomCode, and optional sales-order context. | HomeScreen calls getProductSplitDetail(item), loads detail by itemCode, and passes detail.raw to ProductDetailForm. |
| Refresh detail | Pull-to-refresh reloads getProductInventoryDetail(context, productId) and step price if needed. | Detail is refreshed by selecting/reloading the split-pane detail; step prices are loaded before ProductDetailForm receives the raw record. |
| Add to sales order | Visible only when ProductList/ProductDetail was opened with orderId or draftOrder. It validates qty, creates an order first if only draftOrder exists, then calls createOrderItem(). | Not shown from the normal Products menu, matching standalone Mobile behavior. Terminal adds products through the sales-order product picker, not from this menu. |
| Quantity guard | Quantity must be greater than 0. | Quantity must be greater than 0. |
| Weight guard | Weight-based products may be added or edited in a sales order with weight 0; weight is checked again when creating an invoice. | Same guard: a weight-based product may have weight 0 in a sales order, but an invoice cannot be created until its weight is other than 0. |
| Price input | User can adjust price in the add form; default is product price. | User can adjust price in the add form; default is product price. |
| Amount preview | Weight-base: qty * price * weight; otherwise qty * price. | Same calculation. |
| Mutation boundary | The standalone Products menu does not edit product master, inventory quantities, or sales-order items. Mobile's add action belongs to the sales-order route context, not the normal menu. | Same standalone boundary. |
Important Fields For Developers
| Field | Why It Matters |
|---|---|
id | Firestore document ID used by mobile detail lookup; terminal detail resolves latest data by itemCode. |
itemCode / itemName | Primary identity used by list, detail, and every document item payload. |
whsCode / warehouseCode | Required when adding items to order, booking, transfer, and stock-in flows. Missing warehouse data usually blocks document save in downstream screens. |
price, salUomCode, salUomEntry | Used to build line price and UOM payloads. |
onHand, booking, available stock | UI displays SAP stock, booked stock, and available stock as onHand - booking. Downstream documents use these values for stock/booking validation. |
weight, weightBaseFlag | Controls whether the product is sold by counted unit or by weight. Weight-based products may have weight 0 in a sales order, but must have a weight other than 0 before invoice creation. |
stepPriceFlag / step price rows | Drives tiered price display and price selection in sales/booking quantity changes. |
color | Used by product cards/detail cards for visual grouping. Invalid hex falls back to app theme accent. |
| company fields | Document screens may use company fields to filter compatible products, but the Products menu search itself follows Mobile and uses item name/code. |
Permissions And Guards
| Topic | Behavior |
|---|---|
| Mobile menu permission | The home menu uses the same product deptCode set as terminal: -2, 1, 2, 3, 4, 7, 29, 21, 8, 9, 12, 20, 22, 23, 27, 28, 13, 16. |
| Terminal menu key | product |
| Terminal menu permission | MENU_PRODUCT uses -2, 1, 2, 3, 4, 7, 29, 21, 8, 9, 12, 20, 22, 23, 27, 28, 13, 16. |
| Branch rule | The product menu is not main-branch-only. It depends on selected branch product context and whsGrpCode. |
| Add-to-sales-order permission | Mobile shows the add form only when the screen was opened from a sales-order flow with orderId or draftOrder. POS Terminal does not expose this action from the standalone Products menu; sales-order item adding stays inside the sales-order flow. |
| Product mutation | No product master create/update/delete exists in this menu. Product quantity changes happen only through downstream document flows. |
Mobile vs POS Terminal
| Topic | Mobile | POS Terminal |
|---|---|---|
| Navigation | Dedicated product stack | HomeScreen split-pane menu key product |
| List | Snapshot-backed product list with search, tabs, summary counts, pull refresh | Paged split list with search, tabs, load more, pull refresh |
| Detail | Full-screen detail with pull refresh and optional bottom add form | Right-pane detail with optional add card |
| Add action | Only when opened from Mobile sales-order route context | Not exposed from the standalone Products menu |
| Reuse | Product picker components in document stacks | Shared product picker/detail patterns in HomeScreen |
Developer Handoff Map
| Area | Code |
|---|---|
| Mobile list/detail | apps/mobile/src/screens/productStack/productListScreen, productDetailScreen |
| Mobile home permission | apps/mobile/src/screens/homeScreen/index.tsx -> MENU_PRODUCT |
| Terminal detail | apps/pos-terminal/src/screens/HomeScreen/ProductDetailForm.tsx |
| Terminal home wiring | apps/pos-terminal/src/screens/HomeScreen/index.tsx, DetailPane.tsx, ListPane.tsx |
| Terminal split data | apps/pos-terminal/src/services/splitMenuData.ts -> getProductSplitList, getProductSplitDetail |
| Product service | apps/*/src/services/products.ts |
| Picker reuse | OrderFlowShared, BookingProductPicker, inventory transfer forms |