Mobile Borrow และ Customer Management
หน้านี้ใช้บันทึก behavior ปัจจุบันของ mobile สำหรับการแก้ไขรายการในใบเบิกดูปลา และ field บนหน้าแก้ไขการจัดการลูกค้า
การค้นหาลูกค้าใน Customer List
- หน้า
CustomerListใช้CustomerManagementListHeaderสำหรับช่องค้นหา - เมื่อผู้ใช้กดค้นหาจาก keyboard ตัว header จะส่งข้อความจาก
TextInputsubmit event กลับเข้า screen โดยตรง - หน้า
CustomerListใช้ข้อความที่ submit มาเป็นค่าsearchสำหรับgetCustomerSapListทันที แล้วค่อย sync ค่าใน state/ref ของช่องค้นหา - การทำแบบนี้ป้องกันปัญหา timing ของ Thai IME ที่พิมพ์คำ เช่น
ขายแล้วกดค้นหา แต่ API ได้ค่าแค่ตัวอักษรแรก เช่นข - การค้นหายังคงใช้ filter เดิมร่วมด้วย ได้แก่ประเภทการจัดส่งและรหัสสายส่ง
ฟอร์มที่อยู่ของลูกค้าบน iOS
- หน้า
CustomerDetailไม่เปิดฟอร์มเพิ่มที่อยู่ใหม่เป็น nested modal แล้ว - เมื่อกด
เพิ่มที่อยู่ใหม่หน้าจอจะสลับจาก view รายละเอียดลูกค้าไปเป็น view ฟอร์มเพิ่มที่อยู่แบบเต็มหน้าใน screen เดิม - ปุ่ม back บน header และปุ่ม
กลับในฟอร์มจะปิดฟอร์มที่อยู่และกลับไปหน้า detail ลูกค้า - หน้า
CustomerManagementEditใช้ pattern เดียวกันสำหรับการเพิ่มและแก้ไขที่อยู่ของ customer draft - ระหว่างเปิด address editor หน้าฟอร์มหลักของลูกค้าจะถูกซ่อน เพื่อให้มี scroll owner เดียวบนหน้าจอ
- การค้นหาที่อยู่ เลือกสายส่ง และเลือกตำแหน่งจากแผนที่ยังเป็น modal/picker flow ได้ แต่เปิดจาก address form ระดับ screen ไม่ได้เปิดซ้อนจาก modal อีกชั้น
- visibility ของ modal ถูก guard ตาม view ที่กำลังใช้งาน:
- modal ค้นหาที่อยู่/แผนที่/สายส่งของ
CustomerDetailเปิดได้เฉพาะตอน address form ของหน้า detail ทำงาน - modal ค้นหาที่อยู่/แผนที่/สายส่งของ
CustomerManagementEditเปิดได้เฉพาะตอน address editor ทำงาน - selector ของฟอร์มหลักใน
CustomerManagementEditเช่น ประเภทลูกค้า, รู้จักเราจาก, สาขา, วัน, เดือน จะถูกซ่อนเมื่อ address editor เปิดอยู่
- modal ค้นหาที่อยู่/แผนที่/สายส่งของ
- การปรับนี้เลี่ยงปัญหา modal-over-modal และ scroll gesture conflict บน iOS โดยยังคง behavior การบันทึก, address payload, ตัวเลือก auto-create ShipTo, และการ reload draft เดิมไว้เหมือนเดิม
การแก้ไขรายการในใบเบิกดูปลา
- หน้า
BorrowDetailอนุญาตให้แก้ไขรายการสินค้าได้เมื่อเอกสารยังเป็นสถานะNEWและผู้ใช้ปัจจุบันเป็นเจ้าของใบเบิก - การเทียบ owner ตอนนี้ใช้การ
trim()ทั้งuser.userCodeและdetail.userCodeก่อนเปรียบเทียบ - เมื่อกดรายการสินค้าเดิมในใบเบิก ระบบจะเปิด modal แก้ไขเฉพาะรายการนั้น
- modal แก้ไขใช้หน้าตาและสไตล์เดียวกับ modal เพิ่มสินค้า แต่จะไม่แสดงรายการสินค้าอื่นและไม่แสดงช่องค้นหาสินค้า
- ตอนเข้าแก้ไข ระบบจะโหลดสินค้าปัจจุบันจาก
productCodeและถ้า item นั้นไม่อยู่ใน inventory snapshot ที่อยู่ใน memory จะไปดึงจาก inventory ก่อนเปิด modal - สิทธิ์การแก้ไขจะถูกตรวจซ้ำอีกครั้งตอนผู้ใช้กดบันทึก
พฤติกรรมการบันทึกและลบรายการในใบเบิกดูปลา
- การบันทึกรายการเดิมจะอัปเดตด้วย
itemIdและ fallback ไปใช้idเมื่อ payload ของรายการไม่มีitemId - การแก้นี้ช่วยไม่ให้ flow แก้ไขเผลอเรียก create-item API แล้วชน error สินค้าซ้ำในรายการ
- การลบรายการในใบเบิกก็ fallback ไปใช้
item.idได้เช่นกันเมื่อitem.itemIdไม่มี - ถ้าไม่พบ identifier ของรายการที่ใช้ได้ หน้าจอจะแสดง error ตรง ๆ แทนการไม่ตอบสนอง
- ทั้ง Mobile และ POS Terminal ใช้ payload shape เดียวกันสำหรับ create/update item ของใบเบิกดูปลา:
productCodeproductNameqtypriceamountweightlimitWeightUOMCodeUOMNameUOMEntrywhGrpCodewhGrpNamewhsCodeweightBaseFlagcompanyCodecompanyNametaxNovatGroupstepPriceFlageditPriceBy
editPriceByของใบเบิกดูปลาส่งเป็นnullเสมอ เพราะ flow นี้ไม่มีการแก้ไขราคา- payload ของใบเบิกดูปลาไม่ส่ง field เสริมอย่าง
onHand,bookingQty,uomCode, และuomNameเข้า create/update item API
เลือกสินค้าแปลงใบสั่งขายและคืนรายการที่เหลือ
- ใบเบิก
SPECของสาขาหลักที่รับงานแล้วและผ่าน guard สิทธิ์แปลง จะเปิด Modal เลือกสินค้าร่วมกัน แต่ละรายการแสดงเฉพาะชื่อ รหัสสินค้า และจำนวน เลือกทีละรายการหรือ เลือกทั้งหมด ได้ พร้อมเครื่องหมายถูกและจำนวนที่เลือก - ทุกครั้งที่เปิดเริ่มโดยยังไม่เลือกรายการ ต้องเลือกอย่างน้อยหนึ่งรายการแล้วกด ยืนยัน เพื่อเรียก
POST /api/borrow/{id}/convertพร้อม{ "borrowItemIds": [11, 12] }ระหว่างส่งจะล็อกการเลือก/ปิด Modal หากล้มเหลวจะแสดง error และคงการเลือกไว้ PARTIAL_CONVERTEDแสดง แปลงและรอคืน เฉพาะในสถานะนี้ สินค้าที่lotsว่าง/ไม่มี lots จะถือว่าแปลงแล้วและมีพื้นหลังแดงอ่อน ส่วนสินค้าที่มี lots ยังคืนได้ เอกสารนี้ไม่สามารถแปลงซ้ำได้- ปุ่ม ยืนยันคืน/ตัดสต๊อก เรียก
POST /api/borrow/{id}/return-itemsพร้อม ID ของทุกรายการที่lotsเป็น array ไม่ว่าง เช่น{ "borrowItemIds": [13] }โดยใช้ lots ที่อยู่ในรายการแล้ว ไม่มีขั้นตอนเลือก lots เพิ่ม - การคืนหลังแปลงบางส่วนมีลำดับก่อน
hasFailedSubBorrowหากไม่มีรายการเหลือหรือ ID ของรายการที่จะคืนไม่ถูกต้องจะไม่ยิง API สถานะอื่นที่ดำเนินการได้ยังใช้/approveหรือ/retryและใช้สถานะที่โหลดใหม่จาก backend หลังสำเร็จ - POS HomeScreen และ Storefront POS ใช้กฎเดียวกันผ่าน helper ร่วม ดูสิทธิ์ทั้งหมด ID aliases, API contract และตำแหน่งโค้ด/เทสต์ได้ที่ ใบเบิกยืม
Field บนหน้าแก้ไขการจัดการลูกค้า
- หน้า
CustomerManagementEditแยกการเก็บค่าcustomerType/customerTypeCodeและknowus/knowusCodeออกจากกันอย่างชัดเจน - หน้า
CustomerManagementEditมีช่องกรอกtaxIDแบบ optional อยู่ใต้ fieldฉายา taxIDไม่บังคับกรอกตอนบันทึก และจะถูกส่งไปใน customer draft payload เมื่อมีค่า- หน้า
CustomerManagementDetailและCustomerDetailแสดงtaxIDในส่วนข้อมูลลูกค้า โดย fallback เป็น-เมื่อไม่มีค่า - รายการตัวเลือกตอนนี้โหลดจาก source ที่ถูกต้อง:
customerTypesใช้สำหรับ selectorประเภทลูกค้าknowUsใช้สำหรับ selectorรู้จักเราจาก
- การแก้นี้ทำให้ field ทั้งสองไม่สลับกันอีกบนหน้า edit
การสร้าง customer draft, replace หน้าจอ, และรายการลูกที่ยังบันทึกไม่สำเร็จ
- การสร้างลูกค้าใหม่จากหน้า
CustomerManagementEditจะสร้าง customer draft ก่อน - หลังจากได้ draft แล้ว หน้าจอจะพยายามสร้างที่อยู่และสาขาใต้ draft id นั้นต่อ
- ถ้าที่อยู่หรือสาขาบางรายการบันทึกไม่สำเร็จ หน้าจอยังคงเก็บ
customerDraftIdที่สร้างสำเร็จไว้ และreplaceกลับเข้าหน้าแก้ไข draft เดิม - หน้าจอจะส่ง child records ที่ยังบันทึกไม่สำเร็จไปกับ route params แบบ pending แล้ว merge กลับเข้ากับ state หลังจาก reload draft detail, addresses และ branches จาก server
- ดังนั้นที่อยู่หรือสาขาที่ยังไม่ถูกบันทึกลง server จะยังแสดงอยู่บนหน้าจอหลัง reload
- เมื่อกดบันทึกครั้งถัดไป ระบบจะอัปเดต draft เดิม ไม่สร้าง draft ใหม่ซ้ำอีก
การกู้ flow เมื่ออนุมัติเข้า SAP B1 ไม่สำเร็จ
- หากอนุมัติทันทีของลูกค้าใหม่บุคคลธรรมดาไม่สำเร็จ Mobile จะแจ้ง error แล้ว
replaceจากหน้าแก้ไขไปยังหน้ารายละเอียด Draft ที่สร้างไว้ - หน้ารายละเอียดจะ reload หลังอนุมัติล้มเหลว:
DRAFTแสดงอนุมัติ/ไม่อนุมัติ ส่วนSAP_PARTIALแสดงเฉพาะส่งข้อมูลอนุมัติอีกครั้งผ่านPOST /customer-draft/:id/retry