Booking Price
The Booking Price menu reserves customer pricing and stock before the document is converted into a real sales order. Its structure is close to Sales Order, because it uses the same customer, product, warehouse, step-price, weight, and total concepts. The difference is that a booking price does not continue to invoice/payment until the user converts it to a sales order.
The key special field is item-level currentStepPrice. It stores the step-price snapshot/fallback used by the booking item so the later sales order can keep the same step-price context.
Open workflowOpen currentStepPriceOpen conversion notes
App Entry Points
| App | Entry point | Main files |
|---|---|---|
| Mobile | Home -> BookingPriceList -> CustomerList mode booking -> BookingPriceDetail | bookingPriceListScreen, bookingPriceDetailScreen |
| POS Terminal | HomeScreen split-pane -> bookingPrice menu -> customer picker/detail panel | HomeScreen/index.tsx, BookingPriceDetailForm.tsx, BookingProductPicker.tsx |
Services And Endpoints
| Job | Endpoint / service |
|---|---|
| Load booking price list | GET /booking-price via getBookingPrices(...) |
| Load detail | GET /booking-price/{bookingPriceId} |
| Create header | POST /booking-price |
| Update header | PATCH /booking-price/{bookingPriceId} |
| Delete document | DELETE /booking-price/{bookingPriceId} |
| Add item | POST /booking-price/{bookingPriceId}/items |
| Update item | PATCH /booking-price/{bookingPriceId}/items/{itemId} |
| Delete item | DELETE /booking-price/{bookingPriceId}/items/{itemId} |
| Convert to sales order | POST /booking-price/{bookingPriceId}/convert |
| Load step price | product step-price API through getProductStepPrice(...) |
Main Workflow
Booking Price List
The list is loaded through getBookingPrices(...) with selected branch context:
branchIdfrom selected branchwhGrpCodefrom selected warehouse grouppage,pageLimit,searchbookingPriceStatususerCode- sorted
DESCbyCreatedAt
List behavior:
- rows are deduped by
bookingPriceId,bookingPriceStorageId, orbookingPriceNo - search and pagination are supported
- card color communicates document status
- Mobile uses the floating plus button to start
CustomerListmodebooking - Terminal uses the split-pane list and create action to open the customer picker
- created-day edit guards use the server business date from
GET /api/healthzwhen available, then fall back to the device date
Draft From Customer
Booking price creation starts from customer selection, using mode = booking.
Fields seeded into detail:
| Field | Source |
|---|---|
customerCode, customerName, phone1, phone2 | customer detail |
shippingType | customer / branch rule |
routeCode, routeName | customer address |
U_BFP_Latitude, U_BFP_Longitude | customer address |
branchId, whGrpCode, whGrpName | branch storage |
userCode, userResponsible | current user |
bookingPriceStatus | starts as DRAFT |
Terminal parity note: customer-seeded booking drafts use the first customer address for route and coordinates, matching the current Mobile booking-price initialization.
Add And Edit Items
Adding items is close to sales order item entry:
- open product picker
- selecting an existing product opens edit overlay instead of adding a duplicate
- validate quantity as an integer greater than
0 - check available stock from
onHand - bookingQty - weight-based amount is
qty * price * weight - normal amount is
qty * price - if
stepPriceFlagapplies and quantity qualifies, load step price before calculating price - persist in order: ensure/create booking header -> create/update item -> update totals -> reload detail
Important item payload fields:
| Field | Meaning |
|---|---|
productCode, productName | product identity |
qty, price, amount, weight, limitWeight | quantity, price, amount, and weight |
onHand, bookingQty | stock validation |
uomCode, uomName, UOMCode, UOMName, UOMEntry | UOM |
whsCode, whGrpCode, whGrpName | warehouse and warehouse group |
companyCode, companyName, taxNo, vatGroup | company/tax data |
weightBaseFlag | weight-based product |
stepPriceFlag | step-price product |
currentStepPrice | snapshot/fallback step price for this item |
editPriceBy | user who edited price |
Header Remark
The booking-price remark field is a multiline input. It starts at a minimum height of one line (about 40px) and grows or shrinks with the text content, so longer notes remain readable without leaving a large empty field on short notes. Mobile and POS Terminal use the same behavior, and the input height resets when switching booking-price documents.
currentStepPrice
currentStepPrice is an item-level field that stores the step-price data used when the booking item was created or edited. It is usually a JSON string of step-price rows, or a fallback JSON string when the step-price API has no rows.
Fallback shape:
[
{
From: 0,
Price: item.price,
BPLName: item.whGrpName || item.whsName || ''
}
]
Important behavior:
- when adding a new item, the app creates
currentStepPricethroughbuildDefaultCurrentStepPrice(product)if step-price rows are not available yet - if the item has
stepPriceFlagand quantity qualifies, the app loads step prices from the API and stores that response as JSON incurrentStepPrice - when editing an existing item, the app refreshes inventory from Firestore by
productCodebefore showing stock and booking values - for step-price items, the app reloads step price from the MST API, but
currentStepPriceis still saved as fallback data, not as the only price source - after conversion, the sales order item keeps
currentStepPriceso sales order detail can preserve the booking/step-price context
Convert To Sales Order
Conversion runs from the Convert to sales order action in detail:
After conversion:
- booking price status becomes
DONE - detail shows that the document has already been converted to a sales order
- Mobile uses
navigation.replace('OrderDetail', { orderId }) - Terminal creates/opens the order detail in the split pane and refreshes the booking list
- order detail recognizes the source by
bookingPriceIdorbookingPriceStorageId
Permissions And Guards
| Area | Condition |
|---|---|
| See Booking Price menu | MENU_BOOKING.has(deptCode) or admin/full non-main warehouse access |
| menu dept codes | -2, 1, 2, 3, 4, 7, 8, 9, 13, 16, 20, 21, 22, 23, 27, 29 |
| Home create shortcut | same create-order shortcut set (CAN_CREATE_ORDER) or full non-main warehouse access |
| Create from list/detail | must pass canCreateSalesOrder |
| Delete from list | owner of DRAFT, or DRAFT/NEW where user is admin, override user, dept 8, or dept 22 |
| delete override users | 008045, 012521, 012508, 008051, 012388, 012428, 008060 |
| Edit items in detail | same created day and owner/override rules based on status |
| Convert to sales order | booking price has id, status is DRAFT, current user is owner, and there is at least one item |
Status edit rules:
DRAFT: owner can edit items on the created dayNEW: requires override rights such asfillWeightoreditPriceDONE,CANCELED,DELETED: locked- documents past their created day disable add/edit/delete item, remark/header edit, and save
Difference From Sales Order
| Topic | Booking Price | Sales Order |
|---|---|---|
| Purpose | reserve price and stock first | create an order for invoice/payment |
| Next document | convert to order | create invoice and open payment |
| main statuses | DRAFT, NEW, DONE, CANCELED, DELETED | DRAFT, NEW, WAITING_PAYMENT, CONFIRMED, ... |
| item step price | stores currentStepPrice snapshot/fallback | receives currentStepPrice from booking or product picker |
| editing booking-origin item | edit before conversion | after conversion, quantity can be reduced; the order uses currentStepPrice for step-price matching and falls back to base price |
| historical edit | stricter created-day guard | depends on order action state/status |
| stock check | uses onHand - bookingQty | uses available stock and order item rules |
Mobile vs POS Terminal
| Topic | Mobile | POS Terminal |
|---|---|---|
| Navigation | stack: BookingPriceList -> CustomerList -> BookingPriceDetail | split-pane: menu, list/customer picker, detail |
| Product picker | Mobile picker/screen flow | full-screen modal host in BookingProductPicker |
| Add/edit item | overlay inside product picker flow | single overlay in modal host to avoid nested native modals on iOS |
| created-day guard | server date when available | GET /api/healthz, fallback device date |
| conversion | replace to OrderDetail | open order detail in panel and refresh list |
Developer Handoff Map
| Job | Mobile | POS Terminal |
|---|---|---|
| list | apps/mobile/src/screens/bookingPriceStack/bookingPriceListScreen/index.tsx | HomeScreen/index.tsx, ListPane.tsx |
| detail | apps/mobile/src/screens/bookingPriceStack/bookingPriceDetailScreen/index.tsx | BookingPriceDetailForm.tsx |
| product picker | detail screen logic | BookingProductPicker.tsx |
| payload helpers | detail screen helpers | HomeScreen/helpers.ts |
| service | apps/mobile/src/services/bookingPrice.ts | apps/pos-terminal/src/services/bookingPrice.ts |
| shared types | apps/mobile/src/types/bookingPrice.ts | packages/types/src/bookingPrice.ts |
| order receiving booking data | orderDetailScreen/index.tsx | OrderDetailForm.tsx |