Mobile Transport And Vehicles
This page documents the mobile transport-detail and vehicle-status workflows.
Scope
This page is based on:
apps/mobile/src/screens/transportStack/transportDetailScreen/index.tsxapps/mobile/src/screens/vehicleStack/vehicleListScreen/index.tsxapps/mobile/src/services/common.tsapps/mobile/src/services/googleRoutes.tsapps/mobile/src/navigation/RootNavigator.tsxapps/mobile/src/screens/homeScreen/index.tsx
Vehicle menu entry
The Home screen now includes a ยานพาหนะ menu item in the ข้อมูล group.
- It uses
menus.menu11. - It is placed after
ผู้ใช้ทั้งหมด. - It uses the same visibility permission as
ผู้ใช้ทั้งหมด, which isMENU_EMPLOYEE.has(deptCode). - It navigates to
VehicleList. - It has no create shortcut.
Vehicle list screen
VehicleList is registered in RootNavigator and renders vehicleStack/vehicleListScreen.
The screen:
- loads vehicle data with
getVehicles({ search })fromservices/common - supports search through the same header/search pattern used by list screens such as
invoiceListScreen - refreshes the list after status updates
- uses
licensePlateas the list identity when available
Each vehicle card displays the same core fields used by the vehicle picker in transportDetailScreen:
- license plate with vehicle status label
- vehicle type name
- max payload capacity in kilograms
Card background color is status-based:
vehicleStatus | Card tone |
|---|---|
UNCHECKED | light red |
NOT_READY | light yellow |
READY | light green |
Vehicle status update modal
Pressing a vehicle card opens a status modal.
The modal includes:
- a three-option radio group:
UNCHECKED:ยังไม่ตรวจสอบREADY:พร้อมใช้งานNOT_READY:ยังไม่พร้อมใช้งาน
vehicleStatusNoteas a multiline text areaยกเลิกandบันทึกactions
The active radio style is theme-aware so the selected text remains readable in dark mode.
Saving calls:
PATCH api/vehicles/{licensePlate}/vehicle-status
Payload:
{
"vehicleStatus": "READY",
"vehicleStatusNote": "ตรวจสอบแล้ว พร้อมใช้งาน"
}
The update uses the same mstApi domain/base URL as getVehicles.
Transport delivery finalization
transportDetailScreen can finalize delivery sheets by updating each delivery to:
{
"deliveryStatus": "FINISHED"
}
The finalize permission is controlled by canFinalizeTransportDeliveries.
It is true only when:
- the screen is not in create mode
- the current user can edit the transport
- the transport has not started yet (
detail.startedAtis empty) canFinalizeShippingSheet(user)allows the user's department
canFinalizeShippingSheet(user) currently allows department codes:
-2, 1, 2, 4, 7, 8, 9, 13, 16, 29
Bottom approve-all action
The transport-detail bottom bar now supports an approve-all action beside the existing save action.
When visible:
- left button:
อนุมัติใบจัดทั้งหมด - right button: existing primary action, such as
บันทึก
The approve-all button is shown only when:
- the user is on the delivery-list step
canFinalizeTransportDeliveriesis true- at least one delivery item has
deliveryStatusasnullor an empty string
Pressing อนุมัติใบจัดทั้งหมด opens a confirmation alert before any API calls are made. After confirmation, the screen loops through all pending delivery items, finalizes each one, then refreshes the current transport detail by transportId.
Transport start requirements
The เริ่มการขนส่ง action in transportDetailScreen can start a trip only when every delivery item in the transport has a non-empty deliveryStatus.
A delivery item is treated as not ready to start when:
deliveryStatusisnulldeliveryStatusis empty aftertrim()
If any delivery item has no status, the screen stops the flow before opening the start-trip modal. The same guard also runs before submitting the start-trip action so a stale open modal cannot bypass the requirement.
Google route customer sorting
The transport-detail sort planner supports a Google-based route sort action.
The sort modal footer now has two rows:
- first row:
เคลียร์รายชื่อจัดเรียง, the name toggle (แสดงชื่อเดิม/แสดงชื่อย่อ), close, and save - second row: a full-width
จัดเรียงลูกค้าตามพิกัดด้วย Googlebutton
Pressing จัดเรียงลูกค้าตามพิกัดด้วย Google shows a confirmation alert. After confirmation:
- the screen reads the device's current GPS location with
Geolocation.getCurrentPosition - that current location is used as the route
origin - customers with valid
U_BFP_LatitudeandU_BFP_Longitudeare used as route points - the customer farthest from the current location is used as the Google Routes
destination - the remaining customers with GPS coordinates are sent as
intermediates services/googleRoutes.optimizeGoogleRoute(...)calls Google RoutescomputeRouteswithoptimizeWaypointOrder: true- the screen reads
routes.optimizedIntermediateWaypointIndexfrom the response and reorders the sort planner list - customers without valid GPS coordinates stay in the payload and are appended after the optimized GPS customers in their existing order
After the route is sorted, the screen shows เรียงเสร็จสิ้นแล้ว.
This action only updates the sort planner state. It does not save to the backend immediately. Users must still press the modal save action, which persists the current order through the existing sortTransportCustomers({ transportId, customerCodes }) flow.
Operational notes:
- The Google API key is read from
constants/config.tsasGOOGLE_ROUTE_API_KEY. - Because the origin is the device's current GPS location, the route starts from wherever the device is when the user confirms the action. If the driver should start from a warehouse, the device should be physically at that warehouse or the flow must be changed to use a stored warehouse coordinate.
- The current implementation limits Google route sorting to 26 customers with valid GPS coordinates per run.
Header print actions
The transport-detail header menu no longer exposes ยืนยันใบจัดสายส่งทั้งหมด. Delivery finalization now lives in the bottom approve-all action.
The header menu now exposes print actions only when:
- the screen is not in create mode
transportIdis available- the transport has at least one delivery item
- every delivery item has
deliveryStatusthat is notnulland not an empty string
When those conditions are met, the header menu shows:
พิมพ์ใบแจ้งหนี้ทั้งหมดพิมพ์ใบจัดสินค้า
Both actions load invoice data through:
GET api/transports/{transportId}/invoices
This is implemented as getTransportCustomerInvoices(transportId) in services/transport.
Print all invoices
พิมพ์ใบแจ้งหนี้ทั้งหมด uses the response from getTransportCustomerInvoices(transportId) directly.
- The response is grouped by customer.
- Each customer can contain multiple invoices.
- The screen flattens all customer invoices in customer
sortorder. - It calls
printInvoice(invoice, { printIndex })directly, so it does not callgetInvoiceDetailagain. - The invoice print template is the same invoice template used elsewhere by
printInvoice.
To reduce native print instability when printing many invoices in sequence, the loop waits for React Native interactions to finish and then waits 800ms after each print job before starting the next one.
Print delivery product summary
พิมพ์ใบจัดสินค้า also uses getTransportCustomerInvoices(transportId).
- The screen flattens every invoice from every customer.
- It maps each invoice's
itemsinto theproductsshape used by the shipping screen. - It combines all products with
buildGroupedProducts. - It prints through
printShippingProductSummary(...), using the same product-summary template asshippingDetailScreen.
Other customer payment handling
On the customer delivery step, selecting payment type อื่นๆ (OTHER) uses the exception-payment flow for cases such as partial item receipt, no receipt, or split payment.
Main validation rules:
รายละเอียดเพิ่มเติมis required every time.รูปส่งของis required.- Customer signature is required because
OTHERis notTRANSFERorBILL_PAYMENT. - If
ไม่รับสินค้าis selected, the screen does not validate collected amount, and submit sendscash = 0andtransfer = 0. - If
ไม่รับสินค้าis not selected, the screen validatescash + transferagainstgrandAmount. cash + transfermust never exceedgrandAmount, includingรับสินค้าบางรายการandแบ่งชำระ.- If
รับสินค้าบางรายการis not selected,cash + transfermust also be at leastgrandAmount. - If
รับสินค้าบางรายการis selected,cash + transfermay be less thangrandAmount, but still may not exceedgrandAmount.
On submit, OTHER appends a system note after the user's note with the cash amount, transfer amount, and selected flags such as รับสินค้าบางรายการ, ไม่รับสินค้า, or แบ่งชำระ for warehouse/finance review.
Maintenance notes
- Keep the Home menu documentation in
workflows/home-menu-and-permissionsaligned withVehicleListrouting and permissions. - Keep vehicle status API calls on
mstApiunless the backend route moves away from the MST domain. - If the finalize permission model changes in shipping, re-check
transportDetailScreenbecause it reusescanFinalizeShippingSheet(user). - Keep transport print actions aligned with
shippingDetailScreenprint helpers and templates.