ลูกค้า
เมนูลูกค้าเป็นหน้าค้นหาลูกค้า SAP และเป็นจุดเริ่มงาน operation ผู้ใช้ค้นหาลูกค้าตามสาขา ดู profile/ที่อยู่/เครดิต/คะแนน โทรหาลูกค้า เริ่มเอกสารขาย ขอเปิด/ปิดสถานะ เพิ่มที่อยู่ เปิดแผนที่ ตั้งค่าที่อยู่จัดส่งเริ่มต้น และยื่นคำขอแก้พิกัด GPS ได้ ส่วนการแก้ master ลูกค้าจะส่งต่อไปที่เมนูการจัดการลูกค้า
ทางเข้าในแอป
| App | Target |
|---|---|
| Mobile | CustomerList mode default, booking, borrow, หรือ request -> CustomerDetail |
| POS Terminal | split menu customer -> CustomerDetailForm |
Workflow ภาพรวม
ปุ่มและตัวควบคุมหน้า List
| ปุ่ม / Control | Mobile | POS Terminal |
|---|---|---|
| กลับ | navigation.goBack() จาก CustomerManagementListHeader | กลับ/ปิดอยู่ใน shell ของ HomeScreen menu/pane |
| ช่องค้นหา | เปลี่ยนค่า search; submit เรียก getCustomerSapList({ page: 1, search, shippingType, routeCode, isRequest }) | เปลี่ยน listSearch; submit เรียก loadCustomerList({ page: 1, search, shippingType, routeCode }) |
| ล้างคำค้น | ล้างค่า search เฉพาะ input แล้ว fetch ใหม่เมื่อ submit/refresh ครั้งถัดไป | ล้าง shared list search ผ่าน split-pane controls |
| ตัวกรองเส้นทาง | เปิด modal เลือกเส้นทาง เลือกแล้ว reload page 1 ด้วย routeCode | เปิด route selector ใน ListPane; เลือกแล้วล้าง detail ที่เลือกและ reload page 1 ด้วย routeCode |
| Tab ประเภทจัดส่ง | สายส่ง ส่ง shippingType: "1"; หน้าร้าน ส่ง shippingType: "2"; กด tab เดิมซ้ำเพื่อล้าง filter | behavior เดียวกันผ่าน customerShippingType; เลือกแล้ว reload page 1 และล้าง detail |
| Pull refresh | โหลด page 1 ด้วย filter ปัจจุบัน | โหลด page 1 ด้วย filter ปัจจุบัน |
| Infinite scroll | onEndReached โหลดหน้าถัดไปเมื่อ hasMore เป็นจริง | split list onLoadMore เรียก loadCustomerList() ด้วย customerPageRef.current |
| กดแถวลูกค้า | เปิด CustomerDetail พร้อม customerId, mode, origin; ถ้าไม่มี customerId จะแสดง error | เลือก row แล้วโหลด getCustomerSplitDetail(item) ไปยัง pane ขวา |
| Swipe primary action | ซ่อนใน request mode; mode ปกติจะเริ่ม action ตาม mode เช่น สร้างใบสั่งขาย ใบจองราคา หรือใบเบิกยืม โดยเช็ก blocked reason และ existing order ก่อน | ไม่มี swipe action ใน customer list; action สร้างเอกสารอยู่ใน detail pane |
| เมนูหัวหน้า: เพิ่มลูกค้าใหม่ | แสดงเมื่อ canShowCreateCustomerMenu; เปิด CustomerManagementEdit แบบ draft ใหม่ | การเพิ่มลูกค้าอยู่ในเมนู Customer Management ไม่ใช่ header ของ customer split list |
ปุ่มและ Action หน้า Detail
| ปุ่ม / Action | Mobile | POS Terminal |
|---|---|---|
| กลับ | ถ้าเปิดฟอร์มเพิ่มที่อยู่จะปิดฟอร์มก่อน ไม่เช่นนั้น navigation.goBack() | ปิด detail pane จาก shared pane header |
| Pull refresh | โหลด /customers/:customerId ใหม่ พร้อม addresses และ branches | refresh detail ผ่าน onRefreshCustomerDetail จาก HomeScreen |
| เบอร์โทร / ปุ่มโทร | เรียก callCustomer(customerId) เพื่อบันทึก /customers/:id/re-call แล้วเปิด tel:{phone} | service และ flow เดียวกัน และเช็ก customer ID ก่อนโทร |
| สร้างใบสั่งขาย | เช็กสิทธิ์สร้างเอกสารและ getSalesOrderBlockedReason() ถ้ามีใบสั่งขายวันนี้ในสาขาเดียวกันจะถามว่าจะเปิดใบเดิมหรือสร้างใหม่ | เช็ก blocked reason แล้ว HomeScreen prompt/open sales-order draft หรือสลับไป sales-order detail |
| ใบจองราคา | เช็กสิทธิ์และ blocked reason แล้วเปิด BookingPriceDetail พร้อม bookingPriceId: null และ customerId | สร้าง booking-price draft detail แล้วสลับ active menu ไป bookingPrice |
| สร้างใบเบิกดูปลา | เช็กสิทธิ์และ blocked reason แล้วเปิด BorrowDetail พร้อม borrowId: null และ customerId | สร้าง borrow-fish draft detail แล้วสลับ active menu ไป borrowFish |
| แก้ไขข้อมูล | เปิด CustomerManagementEdit ด้วย customerId ปัจจุบัน โดย guard ด้วย canEditCustomerFromDetail | HomeScreen สร้าง customer-management edit draft แล้วสลับไปฟอร์ม customer management |
| ขอปิดสถานะ | แสดงเมื่อลูกค้า ACTIVE และมีสิทธิ์ toggle status; confirm แล้วเรียก updateCustomerStatus(customerCode, { status: "INACTIVE" }) | ยืนยันใน CustomerDetailForm แล้วเรียก service เดียวกัน |
| ขอเปิดสถานะ | แสดงเมื่อลูกค้า INACTIVE และมีสิทธิ์ toggle status; confirm แล้วเรียก updateCustomerStatus(customerCode, { status: "ACTIVE" }) | ยืนยันใน CustomerDetailForm แล้วเรียก service เดียวกัน |
| เพิ่มที่อยู่ | เปิดฟอร์มเพิ่มที่อยู่เมื่อมีสิทธิ์ canManageCustomerAddresses | เปิด address modal เมื่อ canManageAddresses(user) ผ่าน |
| อนุมัติคำขอ | เฉพาะ Mobile request mode; validate ด้วย validateCustomerBeforeApproval({ customer, addresses, branches }) ก่อนเรียก approveCustomerRequest(customerCode) | การอนุมัติคำขอสถานะอยู่ในเมนู Customer Activation ไม่ใช่ normal Customer detail |
| ไม่อนุมัติคำขอ | เฉพาะ Mobile request mode; เรียก rejectCustomerRequest(customerCode) | อยู่ในเมนู Customer Activation |
| ปุ่มกลับท้ายหน้า | กลับหน้าก่อนหน้า | ไม่มีใน pane; ใช้การปิด pane/เลือกเมนู |
ปุ่มและ Action ที่อยู่
| ปุ่ม / Action | รายละเอียด |
|---|---|
| เปิดแผนที่ | ต้องมีสิทธิ์จัดการที่อยู่และมี latitude/longitude แล้ว เปิด Google Maps URL ด้วย U_BFP_Latitude,U_BFP_Longitude |
| ตั้งค่าเริ่มต้น | ใช้ได้เฉพาะ ShipTo; ถ้าเป็น default อยู่แล้วจะไม่ทำอะไร ต้องมี customerCode และ addressId, confirm แล้วเรียก setCustomerDefaultAddress(customerCode, addressId) และ reload detail |
| ปักหมุด / ขออัปเดตพิกัด | ต้องมีสิทธิ์จัดการที่อยู่และ addressId; เปิดฟอร์ม GPS request พร้อมพิกัดเดิมและ note; submit เรียก requestCustomerAddressGpsUpdate({ addressId, U_BFP_Latitude, U_BFP_Longitude, note }) แล้วรออนุมัติใน Customer Address Management |
| ประเภทที่อยู่ | BillTo คือที่อยู่เปิดบิล; ShipTo คือที่อยู่จัดส่ง; ที่อยู่ใหม่ default เป็น ShipTo |
| สาขาสำหรับนิติบุคคล | Mobile มีตัวเลือกสำนักงานใหญ่/สาขาสำหรับ BillTo; สำนักงานใหญ่ใช้ branch code 00000 และชื่อ สำนักงานใหญ่; ถ้าเลือกสาขาต้องมีทั้งรหัสและชื่อสาขา Terminal normalize payload ตามแนวคิดเดียวกัน |
| ค้นหาที่อยู่ | เปิด lookup จาก dbAddress แล้วเติมตำบล/อำเภอ/จังหวัด/รหัสไปรษณีย์/block |
| ดึงพิกัดจากอุปกรณ์ | ขอ permission ตำแหน่ง แล้วเติม latitude/longitude จาก GPS |
| เลือกจากแผนที่ | Mobile ใช้ MapPickerModal; Terminal ใช้ Google Maps WebView ใน modal แล้วนำพิกัดที่เลือกกลับมาเติม latitude/longitude |
| เลือกสายส่ง | บังคับเมื่อ customer shippingType === "1" และ address เป็น ShipTo; บันทึกเป็น U_ISS_RouteCode และ U_ISS_RouteName |
| บันทึกที่อยู่ | validate สิทธิ์, customerCode, address type, required fields, branch rule ของนิติบุคคล และ route requirement ของลูกค้าสายส่ง จากนั้นเรียก createCustomerAddressByPass(customerCode, payload), reload detail และปิดฟอร์ม |
| ยกเลิก / ปิด | ปิด modal/form และ reset state ที่ยังไม่ได้บันทึก |
ฟอร์มเพิ่มที่อยู่
| Field / Button | Mobile | POS Terminal |
|---|---|---|
| ทางเข้าเพิ่มที่อยู่ | ปุ่ม เพิ่มที่อยู่ใหม่; เรียก handleOpenAddAddress() | ปุ่ม action เพิ่มที่อยู่; เรียก handleOpenAddAddress() |
| Guard สิทธิ์ | ใช้ access.canManageCustomerAddresses; ถ้าไม่มีสิทธิ์แสดง คุณไม่มีสิทธิ์เพิ่มที่อยู่ | ใช้ canManageAddresses(user); ถ้าไม่มีสิทธิ์แสดง error เดียวกัน |
| ค่าเริ่มต้น | เปิดฟอร์มเต็มจอโดยตั้ง addressType: "ShipTo" และล้าง address search | เปิด modal โดยตั้ง addressType: "ShipTo" และล้าง address search |
| ประเภทที่อยู่ | radio: ที่อยู่ในการเปิดบิล -> BillTo, ที่อยู่สำหรับจัดส่ง -> ShipTo | ปุ่ม: เปิดบิล -> BillTo, จัดส่ง -> ShipTo |
| สาขาของนิติบุคคล | ถ้าเป็นนิติบุคคลและ BillTo Mobile แสดงตัวเลือกสำนักงานใหญ่/สาขา; สำนักงานใหญ่ตั้ง branchCode: "00000", branchName: "สำนักงานใหญ่"; ถ้าเป็นสาขาต้องมีทั้งรหัสและชื่อสาขา | Terminal normalize payload แนวเดียวกัน: ถ้าไม่ใช่นิติบุคคลหรือเป็น ShipTo จะเคลียร์ branch fields; legal-entity BillTo ที่ว่างจะ default เป็นสำนักงานใหญ่ |
| ชื่อของที่อยู่ | Required. บันทึกเป็น addressName | |
| ที่อยู่บ้านเลขที่ / หมู่บ้าน / หมู่ | Required. บันทึกเป็น street | |
| รายละเอียดเพิ่มเติม / จุดสังเกต | Optional. บันทึกเป็น checkAddressName | |
| ค้นหาที่อยู่ไทย | เปิด lookup จาก dbAddress; เมื่อเลือกจะเติม block, city, zipCode, U_BFP_Amphur, U_BFP_Tambon | |
| ตำบล / อำเภอ / จังหวัด / รหัสไปรษณีย์ | Required หลังเลือก lookup หรือกรอกเอง; Mobile แสดงเป็น disabled fields หลัง lookup ส่วน Terminal เป็น text fields ที่แก้ได้ | |
| ดึงพิกัดจากอุปกรณ์ | ปุ่ม ดึงพิกัดจากอุปกรณ์ / ดึงพิกัด; ขอ location permission แล้วเติม U_BFP_Latitude, U_BFP_Longitude | |
| เลือกจากแผนที่ | ปุ่ม เลือกจากแผนที่; Mobile เปิด MapPickerModal, Terminal เปิด Google Maps WebView; confirm แล้วเติม latitude/longitude | |
| สายส่ง | Required เฉพาะ customer shippingType === "1" และ address type เป็น ShipTo; บันทึกเป็น U_ISS_RouteCode, U_ISS_RouteName | |
| บันทึก | Mobile ปุ่ม บันทึก; Terminal ปุ่ม บันทึกที่อยู่; ทั้งคู่เรียก createCustomerAddressByPass(customerCode, payload) | |
| ยกเลิก | Mobile ปุ่ม กลับ; Terminal ปุ่ม ยกเลิก; ปิดฟอร์ม/modal และ reset state ที่ยังไม่ได้บันทึก |
Validation ตอนบันทึกที่อยู่
| Check | พฤติกรรมเมื่อไม่ผ่าน |
|---|---|
| สิทธิ์จัดการที่อยู่ | แสดง คุณไม่มีสิทธิ์เพิ่มที่อยู่ และไม่ submit |
ไม่มี customerCode | แสดง ไม่พบรหัสลูกค้า |
| ไม่เลือกประเภทที่อยู่ | แสดง กรุณาเลือกประเภทที่อยู่ |
| field required ไม่ครบ | แสดง กรุณากรอกข้อมูลที่อยู่ให้ครบ: ...; field required คือชื่อที่อยู่, street, ตำบล, อำเภอ, จังหวัด, รหัสไปรษณีย์ |
| นิติบุคคล BillTo กรอก branch ไม่ครบ | Mobile บังคับให้เลือกสำนักงานใหญ่ หรือกรอกทั้งรหัสสาขาและชื่อสาขา |
| ลูกค้าสายส่ง + ShipTo แต่ไม่เลือกสายส่ง | แสดง กรุณาเลือกสายส่งสำหรับที่อยู่นี้ |
| API สำเร็จ | ปิดฟอร์ม/modal, reload detail และแสดง เพิ่มที่อยู่เรียบร้อยแล้ว |
| API fail | คง context เดิมและแสดง ไม่สามารถเพิ่มที่อยู่ได้ หรือ error จาก API |
การบันทึก / ขออัปเดตพิกัด GPS
| Step | รายละเอียด |
|---|---|
| เปิดฟอร์มคำขอ | Mobile ปุ่ม ปักหมุดตำแหน่ง; Terminal ปุ่ม ขออัปเดตพิกัด; ทั้งคู่ preload U_BFP_Latitude และ U_BFP_Longitude เดิมถ้ามี |
| ใช้ตำแหน่งปัจจุบัน | ขอ location permission แล้วเติม latitude/longitude ในฟอร์มคำขอ |
| Map picker | Terminal toggle map picker ใน CustomerLocationForm; Mobile ใช้ map picker flow ของตัวเอง |
| หมายเหตุ | optional note ส่งเป็น note ให้ผู้อนุมัติ |
| Submit | ต้องมี addressId ที่เป็นตัวเลข และ latitude/longitude ไม่ว่าง |
| API | เรียก requestCustomerAddressGpsUpdate({ addressId, U_BFP_Latitude, U_BFP_Longitude, note }) |
| Result | แสดง ส่งคำขอสำเร็จ กรุณารอการอนุมัติ; การอนุมัติ/ปฏิเสธอยู่ในเมนูจัดการที่อยู่ลูกค้า |
การตั้งค่าที่อยู่จัดส่งเริ่มต้น
| Rule | รายละเอียด |
|---|---|
| การแสดงปุ่ม | Mobile แสดง ตั้งเป็นค่าเริ่มต้น เฉพาะ row ShipTo ใน address action area; Terminal แสดง ตั้งค่าเริ่มต้น เมื่อ address ยังไม่เป็น default และซ่อนใน default row |
| สิทธิ์ | ต้องมีสิทธิ์จัดการที่อยู่ ถ้าไม่มีจะแสดง คุณไม่มีสิทธิ์ตั้งค่าที่อยู่เริ่มต้น |
| ประเภทที่อยู่ | ตั้ง default ได้เฉพาะ ShipTo; BillTo จะได้ข้อความ ตั้งค่าเริ่มต้นได้เฉพาะที่อยู่จัดส่ง |
| เป็น default อยู่แล้ว | ไม่ยิง API ถือเป็น no-op |
| ID ที่ต้องมี | ต้องมี customerCode และ addressId; ถ้าไม่มีจะแสดง ไม่พบข้อมูลที่อยู่ที่ต้องการแก้ไข |
| API | เรียก setCustomerDefaultAddress(customerCode, addressId) |
| สำเร็จ | reload detail และแสดง ตั้งค่าที่อยู่จัดส่งเริ่มต้นเรียบร้อยแล้ว |
Data และ API Flow
| เรื่อง | รายละเอียด |
|---|---|
| List API | getCustomerSapList() เรียก /customers?page={page}&pageLimit={PAGESIZE}&search={search}&shippingType={shippingType}&branchId={branchId}&routeCode={routeCode} |
| Request-mode list | Mobile request mode เพิ่ม isRequest=1; customer list ปกติไม่ส่งค่านี้ |
| Detail API | getCustomerSapById(customerId) เรียก /customers/:customerId และต้องได้ profile fields, addresses, branches |
| Profile by code | getCustomerSapByCode(customerCode) เรียก /customers/:customerCode/profile; ใช้ใน flow อื่นที่เริ่มจาก customer code |
| Point balance | getCustomerPointBalance(customerCode) เรียก /customers/:customerCode/point-balance; ใช้ใน flow ใบสั่งขาย/สิทธิประโยชน์ที่ต้องอ่านยอดคะแนนล่าสุด |
| Re-call logging | callCustomer(customerId) post /customers/:customerId/re-call ก่อนเปิดโทรศัพท์ |
| Status request | updateCustomerStatus(customerCode, { status }) patch /customers/:customerCode/status เป็น workflow คำร้อง ไม่ใช่การเปลี่ยนสถานะเงียบ ๆ ใน UI |
| Address bypass | createCustomerAddressByPass(customerCode, payload) patch /customers/:customerCode/addresses |
| GPS update request | requestCustomerAddressGpsUpdate(payload) post /customer-draft/address-lat-lng |
| Default address | setCustomerDefaultAddress(customerCode, addressId) patch /customers/:customerCode/addresses/:addressId/default |
| อนุมัติคำขอลูกค้า | Mobile request mode เรียก approveCustomerRequest(customerCode) -> PATCH /customers/:customerCode/approve; POS Terminal ใช้ service เดียวกันใน Customer Activation |
| ปฏิเสธคำขอลูกค้า | Mobile request mode เรียก rejectCustomerRequest(customerCode) -> PATCH /customers/:customerCode/reject; POS Terminal ใช้ service เดียวกันใน Customer Activation |
| อัปเดต GPS ที่อยู่โดยตรง | updateCustomerAddressGps(customerCode, addressId, payload) patch /customers/:customerCode/addresses/:addressId; ใช้ใน flow ขนส่งที่เกี่ยวข้อง ส่วนหน้า Customer ใช้ flow ขออนุมัติด้านบน |
| คะแนน/เครดิต | detail แสดง tier, point, pointToNextTier, nextTierName, credit total, credit limit และ available credit-note amount เมื่อมีใน payload |
ตัวอย่าง Request Payload
ตัวอย่างด้านล่างตัด API host และ header Content-Type ที่ใช้ร่วมกันออก และตัด PATH ออกจาก URL เช่นเดียวกับตาราง endpoint ด้านบน ค่า ID และข้อมูลลูกค้าเป็นข้อมูลสมมติเท่านั้น สำหรับ endpoint GET จะไม่มี JSON request body โดย query string และ path parameter คือ input ของ request
รายชื่อลูกค้า
GET /customers?page=1&pageLimit=32&sort=DESC&sortBy=CreatedAt&search=%E0%B8%9A%E0%B8%A3%E0%B8%B4%E0%B8%A9%E0%B8%B1%E0%B8%97%20%E0%B9%80%E0%B8%AD&shippingType=1&branchId=101&routeCode=R001
ถ้าเป็น request mode จะเพิ่ม &isRequest=1:
GET /customers?page=1&pageLimit=32&sort=DESC&sortBy=CreatedAt&search=&shippingType=&branchId=101&routeCode=&isRequest=1
รายละเอียดลูกค้า
GET /customers/12345
Profile ลูกค้าจากรหัสลูกค้า
GET /customers/C000123/profile
ยอดคะแนนลูกค้า
GET /customers/C000123/point-balance
บันทึกการโทรซ้ำ (Re-call)
POST /customers/12345/re-call
Content-Type: application/json
{}
ขอเปลี่ยนสถานะลูกค้า
PATCH /customers/C000123/status
Content-Type: application/json
{
"status": "INACTIVE"
}
ถ้าขอเปิดลูกค้าที่ปิดอยู่ ให้ใช้ "ACTIVE"
เพิ่มที่อยู่ลูกค้า
PATCH /customers/C000123/addresses
Content-Type: application/json
{
"addressType": "ShipTo",
"branchCode": "",
"branchName": "",
"checkAddressName": "ใกล้ตลาดตัวอย่าง",
"addressName": "บ้านลูกค้าตัวอย่าง",
"street": "99/9 หมู่ 4",
"block": "ต.สุรศักดิ์ อ.ศรีราชา",
"city": "จ.ชลบุรี",
"country": "TH",
"zipCode": "20110",
"visOrder": "",
"U_BFP_Amphur": "อ.ศรีราชา",
"U_BFP_Tambon": "ต.สุรศักดิ์",
"U_ISS_RouteCode": "R001",
"U_ISS_RouteName": "สายส่งศรีราชา",
"U_BFP_Latitude": "13.173200",
"U_BFP_Longitude": "100.931500"
}
ถ้าเป็น BillTo ของนิติบุคคล ให้ส่งสาขาที่เลือกใน branchCode และ branchName; สำนักงานใหญ่ใช้ "00000" และ "สำนักงานใหญ่" และที่อยู่ BillTo ต้องล้างค่า route ส่วนลูกค้าสายส่งที่เป็น ShipTo ต้องมี U_ISS_RouteCode และ U_ISS_RouteName
ขออัปเดตพิกัด GPS ของที่อยู่
POST /customer-draft/address-lat-lng
Content-Type: application/json
{
"addressId": 9876,
"U_BFP_Latitude": "13.173200",
"U_BFP_Longitude": "100.931500",
"note": "ขอแก้พิกัดหน้าร้านจากตำแหน่งล่าสุด"
}
addressId ส่งเป็นตัวเลข ส่วน latitude และ longitude ส่งเป็น string และ note ปล่อยเป็นค่าว่างได้
ตั้งที่อยู่จัดส่งเริ่มต้น
PATCH /customers/C000123/addresses/9876/default
Content-Type: application/json
{}
อนุมัติคำขอลูกค้า
PATCH /customers/C000123/approve
Content-Type: application/json
{}
ปฏิเสธคำขอลูกค้า
PATCH /customers/C000123/reject
Content-Type: application/json
{}
อัปเดต GPS ที่อยู่โดยตรง (flow ขนส่งที่เกี่ยวข้อง)
PATCH /customers/C000123/addresses/9876
Content-Type: application/json
{
"U_BFP_Latitude": "13.173200",
"U_BFP_Longitude": "100.931500"
}
endpoint นี้ไม่ใช่เส้นทาง submit ปกติของหน้า Customer เพราะหน้า Customer จะส่งคำขอ GPS เพื่อรออนุมัติแทน
สิทธิ์และ Guard
| เรื่อง | Mobile | POS Terminal |
|---|---|---|
| สิทธิ์เข้าเมนู | customer menu ปกติใช้ CUSTOMER_MENU_DEPT_CODES: -2, 1, 2, 3, 4, 7, 8, 9, 13, 14, 16, 21, 27, 29, 30 รวม admin/full non-main warehouse access | Terminal MENU_CUSTOMER: -2, 1, 2, 3, 4, 7, 29, 21, 8, 9, 13, 14, 27, 30, 16 |
| สิทธิ์ request mode | CUSTOMER_REQUEST_DEPT_CODES: 2, 4, 7, 16, 29 รวม admin/full non-main warehouse access | เมนูแยก customerActivation ใช้ MENU_CAN_ACTIVE_CUSTOMER: 2, 4, 7, 16, 29 |
| สร้างเอกสารจากลูกค้า | Mobile ใช้ sales-order access สำหรับ primary actions และมี customer action dept codes -2, 1, 2, 4, 7, 8, 9, 13, 29 | canCreateCustomerDocument() อนุญาต admin/full non-main warehouse access หรือ dept codes -2, 1, 2, 4, 7, 8, 9, 13, 16, 21, 29 |
| ขอเปิด/ปิดสถานะ | Mobile ใช้ customer action permission และแสดงปุ่มตามสถานะ active/inactive | Terminal ใช้ CUSTOMER_ACTION_DEPT_CODES: -2, 1, 2, 4, 7, 8, 9, 13, 29 รวม admin |
| จัดการที่อยู่ | Mobile อนุญาต admin/full non-main warehouse access หรือ dept codes 13, 14, 30 | Terminal อนุญาต admin หรือ dept codes 13, 14, 30 |
| แก้จาก detail | Mobile เปิดตาม canEditCustomerFromDetail สำหรับ customer action users | Terminal แสดงแก้ไขเมื่อผ่าน status-action permission |
| ลูกค้า/เอกสารถูก block | การสร้างเอกสารเรียก getSalesOrderBlockedReason(customer, user) ก่อนเริ่ม order/booking/borrow | |
| Existing order | สร้างใบสั่งขายจะเช็ก getExistingCustomerOrderForBranch(customer, branch) แล้วถามเปิดใบเดิมหรือสร้างใหม่ |
Mobile vs POS Terminal
| เรื่อง | Mobile | POS Terminal |
|---|---|---|
| Navigation | stack screen เฉพาะและใช้ route params | HomeScreen split-pane list/detail; action สลับ active menu และโหลด draft detail |
| Customer modes | default, booking, borrow, request | normal customer menu; งาน request/activation แยกเป็น customerActivation |
| Action จาก list | กด row และ swipe primary action | กด row เท่านั้น; action อยู่ใน detail pane |
| สร้างเอกสาร | navigate ไป detail screen ของเอกสารปลายทาง | build draft detail แล้วเปลี่ยน active menu เป็นเอกสารปลายทาง |
| ฟอร์มที่อยู่ | full-screen form ภายใน CustomerDetail | modal form ใน pane ขวา |
| Map picker | ใช้ shared/native MapPickerModal | ใช้ Google Maps WebView ใน modal |
Developer Handoff Map
| Area | Code |
|---|---|
| Mobile list/detail | apps/mobile/src/screens/customerStack/customerListScreen, customerDetailScreen |
| Mobile permissions | apps/mobile/src/utils/customerPermissions.ts |
| Mobile copy/modes | apps/mobile/src/screens/customerStack/config.ts |
| Terminal detail | apps/pos-terminal/src/screens/HomeScreen/CustomerDetailForm.tsx |
| Terminal list/detail wiring | apps/pos-terminal/src/screens/HomeScreen/index.tsx, DetailPane.tsx, ListPane.tsx |
| Terminal split data | apps/pos-terminal/src/services/splitMenuData.ts -> getCustomerSplitList, getCustomerSplitDetail |
| Customer service | apps/*/src/services/customers.ts |
| Address helpers | apps/mobile/src/utils/customerAddress.ts, terminal local helpers in CustomerDetailForm.tsx |