โอนสินค้าไปสาขา
เมนูโอนสินค้าไปสาขาใช้จัดสินค้าออกจากคลังต้นทางเพื่อส่งไปยังสาขาปลายทาง ผู้ใช้เปิดเอกสารจากรายการโอนออก เลือก lot/batch ให้ครบทุกสินค้า แล้วบันทึก payload โอนออก
ทางเข้าในแอป
| App | Target |
|---|---|
| Mobile | TransferOutList -> TransferOutDetail |
| POS Terminal | transferOut -> TransferOutDetailForm |
Workflow การทำงาน
กฎ Batch และจำนวน
| กฎ | รายละเอียด |
|---|---|
| Batch picker | โหลด lot ด้วย getProductLots({ itemCode, whsCode: line.warehouseCode, company }) |
| ห้ามซ้ำ | ในสินค้า 1 line เลือก batchNumber เดิมซ้ำไม่ได้ |
| ยอดคงเหลือ lot | ถ้า lot มี quantity ต้องกรอกจำนวนไม่เกินยอดคงเหลือของ lot นั้น |
| ยอดค้างเบิก | จำนวน batch ที่กรอกต้องไม่เกิน line.quantity - (line.cal - oldBatchQty) |
| จำนวนบวก | จำนวน batch ต้องมากกว่า 0 และจำนวนเบิกของ line ต้องมากกว่า 0 |
| ต้องปิด line ให้ครบ | ปิด line editor ไม่ได้ถ้า cal !== quantity; ตอน submit ก็ block line ที่ยังค้างเบิก |
| วันที่ | Mobile ใช้ shared batch date validation; Terminal form ปัจจุบันเน้นตรวจ quantity/lot และส่ง date fields ไปกับ payload |
| ไม่มี flow เพิ่มสินค้าใหม่ | Transfer Out ทำงานกับ line จากเอกสารโอนออกที่มีอยู่ ไม่ได้เพิ่ม line รับสินค้าใหม่แบบ Transfer In |
Payload ตอนบันทึก
รายละเอียด payload:
numAtCardสร้างจากdocNumของเอกสารต้นทางและ timestamp ปัจจุบันbranchCodeใช้branch.whsGrpCodeก่อน แล้ว fallback เป็นbranch.BranchCodeuserNameสร้างจากชื่อ-นามสกุล แล้ว fallback เป็น username/userCode- เรียง lines ตาม
lineNumก่อนส่ง - ส่ง
admissionDateด้วยชื่อคีย์นี้และ formatYYYY-MM-DDTHH:mm:ss
พจนานุกรมข้อมูลและแหล่งที่มา
ตารางนี้ครอบคลุม field ที่ Mobile และ POS Terminal อ่านหรือส่งใน flow โอนออก. รายการตั้งต้นมาจาก GET /transfers-out?whGrpCode={selectedWhsGrpCode} แล้วทั้งสองแอปสร้าง payload ใหม่เพื่อส่ง POST /transfer-out.
Header
| Field | คืออะไร | ได้มาจาก / กติกาก่อนส่ง |
|---|---|---|
company | รหัสบริษัท | จากเอกสารโอนออก API |
docEntry, docNum | ID และเลขเอกสารโอนต้นทาง | จาก API; docNum เป็นส่วนประกอบของ numAtCard |
docDate, docDueDate, taxDate | วันที่เอกสาร/กำหนดส่ง/ภาษี | จาก API |
cardCode, cardName | รหัสและชื่อคู่ค้า | จาก API |
toWhsCode, toWhsName | รหัสและชื่อคลังปลายทาง | จาก API |
comments | หมายเหตุเอกสาร | จาก API |
numAtCard | เลขอ้างอิงของเอกสารที่สร้าง | แอปสร้างเป็น ${docNum}_${เวลาปัจจุบัน DD-MM-YYYY HH:mm} เมื่อ submit |
branchId | ID สาขาในเอกสารต้นทาง | จาก API |
branchCode, branchName | warehouse group code/name ของสาขาที่กำลังโอนออก | เขียนทับจาก selected branch (whsGrpCode, fallback BranchCode; และ whsGrpName, fallback BranchName) |
userCode, userName | ผู้บันทึกการโอน | เขียนทับจาก user ปัจจุบัน; ชื่อ fallback เป็นค่าจากเอกสาร |
payloadBefore | snapshot JSON ก่อนแก้ไข | สร้างจากเอกสารที่เลือกใน detail screen |
Line และ batch
| Field | คืออะไร | ได้มาจาก / กติกาก่อนส่ง |
|---|---|---|
lineNum | ลำดับ line | จาก API และเรียงก่อน submit |
itemCode, itemDescription | รหัสและชื่อสินค้า | จาก line เอกสาร API |
quantity, weight | จำนวนที่โอนและน้ำหนัก | จาก line/batch editor; แปลงค่าตัวเลขก่อนส่ง และต้องปิดยอด batch ให้เท่าจำนวน line |
uomCode, uomEntry, vatGroup | หน่วยและภาษี | passthrough จาก line API |
warehouseCode | คลังต้นทางของสินค้า | จาก line API; ใช้เป็น context โหลด lot |
batchNumbers[].batchNumber | lot ที่ตัดออก | ผู้ใช้เลือกจาก getProductLots(itemCode, warehouseCode, company) |
batchNumbers[].quantity | จำนวนที่ตัดจาก lot | ผู้ใช้กรอก แล้วแปลงเป็น number; ต้องไม่เกินยอด lot และรวมเท่าจำนวน line |
batchNumbers[].admissionDate | วันที่รับเข้าของ lot | map จาก admissionDate ที่มาพร้อม lot/ผู้ใช้แก้ไข แล้วส่งเป็น YYYY-MM-DDTHH:mm:ss |
batchNumbers[].manufacturingDate, expiryDate | วันที่ผลิต/หมดอายุ lot | passthrough จาก lot หรือค่าจาก batch editor |
สิทธิ์และ guard
| เรื่อง | รายละเอียด |
|---|---|
| Terminal menu key | transferOut |
| deptCode ที่เห็นเมนู | -2, 1, 2, 3, 4, 7, 29, 21, 8, 9, 12, 22, 27, 28 |
| เงื่อนไขสาขา | allowNonMainBranch = true; ถ้าเลือกคลังสาขา non-main เมนูเปิดได้แม้ deptCode ไม่อยู่ในชุด stock menu |
| Full non-main access | ผู้ใช้ที่มีสิทธิ์ full access ของ non-main warehouse ผ่าน menu access ของกลุ่ม stock นี้ได้ |
| Context รายการ | list API ผูกกับ selected warehouse group (whGrpCode) |
Mobile vs POS Terminal
| เรื่อง | Mobile | POS Terminal |
|---|---|---|
| หน้ารายละเอียด | stack detail เต็มจอ | detail pane ด้านขวาใน HomeScreen |
| Batch picker | SelectionModal หลังโหลด lot | modal ใน detail form |
| หลังบันทึก | navigation.replace('TransferOutList') | refresh list แล้วเรียก onSaved |
| กฎหลัก | ตรวจ batch ซ้ำ, ยอด lot, ยอดค้างเบิก, line ครบ | ใช้กฎ quantity และ batch ซ้ำชุดเดียวกัน |
Developer Handoff Map
| Area | Code |
|---|---|
| Mobile detail | apps/mobile/src/screens/transferOutStack/transferOutDetailScreen/index.tsx |
| Mobile helpers | apps/mobile/src/screens/transferOutStack/helpers.ts |
| Terminal detail | apps/pos-terminal/src/screens/HomeScreen/TransferOutDetailForm.tsx |
| Mobile service | apps/mobile/src/services/transferOut.ts |
| Terminal service | apps/pos-terminal/src/services/transferOuts.ts |