สมอง SML

คลังความรู้ / Process Engine

#process#stock#cost#hidden-cost#stocktools#ic_trans#transaction

ต้นทุนแฝง เฉลี่ยค่าใช้จ่ายเข้าสินค้า (Hidden Cost, เมนู 2.22)

เมนูนี้นำ "เอกสารค่าใช้จ่าย" (flag 87, 260) ไปเฉลี่ยเข้า "รายการสินค้า" ของเอกสารซื้อ (flag 12, 310, 60) ตามมูลค่าหรือจำนวน แล้วบันทึกเอกสารต้นทุนแฝง (ic_hidden_cost_process*) พร้อมใบปรับปรุงมูลค่าอย่างเดียว (ic_trans flag 66) เพื่อให้การคำนวณสต็อกบวกส่วนเฉลี่ยเข้าต้นทุนสินค้า พอร์ตจาก C# SMLERPIC/_icHiddenCost (คอมเมนต์ hidden_cost.go:15-20)

ทำงานอย่างไร

3 action (route POST /process/stocktools/{action} และ /api/v1/process/stocktools/{action})

action สิทธิ์ หน้าที่
hiddencostcalc read ปุ่ม "ประมวลผล" แสดงผลเฉลี่ยล่วงหน้า ไม่เขียนข้อมูล (HiddenCostCalc :277)
hiddencostsave write คำนวณใหม่แล้วบันทึกเอกสาร + ใบปรับปรุง ใน transaction เดียว (HiddenCostSave :323)
hiddencostdelete del ลบเอกสารต้นทุนแฝงและใบปรับปรุงของมัน (HiddenCostDelete :458)

สิทธิ์อยู่ใน permission.go:35,43,47 ดู การตรวจสิทธิ์เมนูของ route process (Process route rights)

Input (HiddenCostInput)

docNo (ว่าง = เลขถัดไป prefix AFC), oldDocNo (เมื่อแก้ไข), docDate, docTime (ว่างใช้ 08:00, ยาวเกิน 5 ตัวอักษรไม่ผ่าน), docFormatCode, branchCode, remark (<= 255 ตัวอักษร), docNoAdjust (ว่าง = เลขถัดไป prefix IA), docFormatCodeAdjust, calFrom (0 = ยอดสุทธิ, 1 = ก่อน VAT), calFollow (0 = ตามมูลค่า, 1 = ตามจำนวน), expenses[] และ purchases[] (แต่ละรายการ {refType, docNo})

ลูกค้าส่งแค่ "เลือกเอกสารไหน" ตัวเลขทุกตัวอ่านจาก ic_trans / ic_trans_detail ฝั่งเซิร์ฟเวอร์ (คอมเมนต์ :149)

ประเภทเอกสาร (hidden_cost.go:29-32)

  • ค่าใช้จ่าย: 87 -> doc_ref_type 0 (ตั้งหนี้อื่น ๆ เจ้าหนี้), 260 -> 1 (ค่าใช้จ่ายอื่น ๆ) ตามคอมเมนต์ท้ายบรรทัด
  • เอกสารซื้อ: 12 -> 0 (ซื้อสินค้า), 310 -> 1 (รับสินค้า), 60 -> 2 (รับสินค้าสำเร็จรูป)
  • refType นอกตาราง = error "ประเภท... ไม่ถูกต้อง"; ซ้ำ = "เอกสารซ้ำ"; เกิน hiddenCostRefCap = 200 ใบต่อฝั่ง = error (cleanHiddenCostRefs :125)

ลำดับคำนวณ (hiddenCostCalc :150)

  1. calFrom/calFollow ต้องเป็น 0 หรือ 1; ต้องเลือกทั้งเอกสารค่าใช้จ่ายและเอกสารซื้ออย่างน้อยอย่างละใบ
  2. hiddenCostRefRows (:202) อ่านหัวเอกสารจาก ic_trans เฉพาะ last_status = 0; ไม่พบหรือถูกยกเลิก = error "ไม่พบเอกสาร ... หรือเอกสารถูกยกเลิกแล้ว" ยอดก่อน VAT ใช้ total_before_vat แต่ถ้า vat_type > 1 (ยกเว้น VAT) ใช้ total_amount ตาม C# (คอมเมนต์ :207 ระบุ vat_type 2; โค้ดเช็ก vat_type > 1)
  3. hiddenCostItems (:241) อ่านบรรทัดสินค้าของเอกสารซื้อ เรียงตามลำดับ C#: flag 12 ก่อน 310 แล้ว 60 จากนั้น doc_no, line_number, roworder; ข้ามบรรทัดที่ไม่มี item_code; stand_value/divide_value ที่เป็น 0 ถือเป็น 1; ItemAmount = qty x price
  4. ยอดที่เฉลี่ย (spreadTotal) = ผลรวม amount หรือ amountBeforeVat ของเอกสารค่าใช้จ่ายตาม calFrom; น้ำหนักต่อบรรทัด = ItemAmount หรือ Qty ตาม calFollow
  5. allocateHiddenCost (:101): ส่วนแบ่ง = ยอดรวม x น้ำหนัก / ผลรวมน้ำหนัก ปัดแบบ HALF_UP ที่ scale 2 (hiddenCostScale); ถ้าผลรวมน้ำหนักเป็น 0 ทุกส่วนเป็น 0; เศษปัดที่เหลือให้บรรทัดแรกที่น้ำหนัก > 0 และมากกว่าทุกบรรทัดก่อนหน้า (ไม่มีน้ำหนัก > 0 เลย = บรรทัดที่ 0) เพื่อให้ผลรวมส่วนแบ่งเท่ายอดเฉลี่ยเป๊ะ (คอมเมนต์ :98-100)
  6. ผลลัพธ์ HiddenCostResult: docNo, docNoAdjust, totalAmount (ผลรวม amount ของค่าใช้จ่าย), expenseTotal (ยอดที่เฉลี่ยจริง), expenses, purchases, items[].adjustAmount

บันทึก (HiddenCostSave :323)

ทำใน inTransTx (transaction เดียว):

  1. ได้เลขเอกสารจาก nextDocNo(... "ic_hidden_cost_process", -1, ..., "AFC") ถ้า docNo ว่าง; ยาวเกิน 25 ตัวอักษรไม่ผ่าน
  2. lockHiddenCost (:285) ล็อก advisory hashtext('hiddencost:'+doc_no) ตามลำดับเรียง (ป้องกัน deadlock เมื่อแก้ไขแล้วเปลี่ยนเลข)
  3. ถ้า oldDocNo != docNo ตรวจเลขซ้ำใน ic_hidden_cost_process
  4. ถ้าเป็นการแก้ไข (oldDocNo ไม่ว่าง) dropHiddenCostTx (:299) ลบใบปรับปรุงเดิม (ic_trans flag 66 ที่ doc_ref = doc_no) ผ่าน deleteTransTx (สต็อกและ GL ถูก rebuild) แล้วลบ ic_hidden_cost_process_item/_ref/ และตารางหัว
  5. เลขใบปรับปรุงจาก nextDocNo(... "ic_trans", adjustUpFlag, ..., "IA") ถ้าไม่ระบุ (adjustUpFlag = 66 ที่ stock_lot.go:29)
  6. คำนวณใหม่ด้วย hiddenCostCalc ใน transaction เดียวกัน แล้ว insertHiddenCostRows (:410) เขียน 3 ตาราง: ic_hidden_cost_process (หัว), ic_hidden_cost_process_ref (เอกสารอ้างอิง; ฝั่งเอกสารซื้อ amount_before_vat = 0 ตาม C#), ic_hidden_cost_process_item (บรรทัด, line_number เริ่ม 0)
  7. สร้างใบปรับปรุง SaveTransInput (TransType 3, TransFlag 66, DocRef = เลขเอกสารต้นทุนแฝง) ที่แต่ละบรรทัดมี Qty "0", Price "0", SumAmount = adjustAmount (บรรทัดมูลค่าอย่างเดียว) บันทึกผ่าน buildTransArgs + saveTransTx แล้วตั้ง is_lock_record = 1 และ branch_code ของบรรทัดตามสาขาหัวเอกสาร (ตาม C#)
  8. เขียน log ผ่าน writeProcessLog ข้อความ "ประมวลผลเฉลี่ยต้นทุนแฝง" ดู กลุ่ม route workflow เมนูกระบวนการระบบ (Workflow Menus)

บันทึกซ้ำด้วยข้อมูลเดิมได้แถวเท่าเดิม เพราะการแก้ไขลบคู่เอกสารเก่าก่อนเสมอ (คอมเมนต์ :321-322)

ลบ (HiddenCostDelete :458)

ล็อกเลข -> ตรวจว่ามีใน ic_hidden_cost_process (ไม่มี = error "ไม่พบเอกสารต้นทุนแฝง") -> dropHiddenCostTx -> log "ลบเอกสารต้นทุนแฝง" คืน TransResult{DocNo}

ที่มาในโค้ด

  • backend/internal/application/process/hidden_cost.go:22-32 - ค่าคงที่ hiddenCostRefCap, hiddenCostScale และตาราง flag ค่าใช้จ่าย/เอกสารซื้อ
  • backend/internal/application/process/hidden_cost.go:101 - allocateHiddenCost (C# _recal + _rebalance)
  • backend/internal/application/process/hidden_cost.go:125 - cleanHiddenCostRefs
  • backend/internal/application/process/hidden_cost.go:150 - hiddenCostCalc; :202 hiddenCostRefRows; :241 hiddenCostItems
  • backend/internal/application/process/hidden_cost.go:285-321 - lockHiddenCost, dropHiddenCostTx
  • backend/internal/application/process/hidden_cost.go:323-408 - HiddenCostSave
  • backend/internal/application/process/hidden_cost.go:410-455 - insertHiddenCostRows
  • backend/internal/application/process/hidden_cost.go:458 - HiddenCostDelete
  • backend/internal/application/process/stock_lot.go:29 - adjustUpFlag = 66
  • backend/internal/adapter/inbound/http/process/stocktools_handler.go:120-131 - 3 action ของเมนูนี้ (body จำกัด 4 MiB)
  • backend/internal/adapter/inbound/http/process/permission.go:35,43,47 - สิทธิ์ read/write/del

ดูเพิ่ม