Skip to main content

Step 2: เงื่อนไขการวางบิล

Step นี้ใช้กำหนด “สูตรการคิดเงิน” ของสัญญา

หน้าสร้างสัญญา Step 2

เงื่อนไขสัญญามีกี่แบบ​

จากโค้ดที่ตรวจสอบพบว่าเงื่อนไขสัญญาหลักมี 9 แบบ คือ A1, A2, A3, B1, B2, C, D, E, และ F

นอกจากนี้ B1 และ B2 ยังมี groupOptionalLogic เพิ่มอีก 2 แบบ คือ

  • VEHICLE_TYPE - กำหนดตามประเภทรถ
  • PACAKGE_PRICE - กำหนดตามราคาเหมา

ใช้ทำอะไร​

  • เลือกกลุ่มเงื่อนไขจริงของสัญญา
  • แสดงฟอร์มเฉพาะตามกลุ่มที่เลือก
  • กำหนดราคาและเงื่อนไขการวางบิลของแต่ละ group
  • ตั้งค่าราคาน้ำมัน, ตารางช่วงราคา, ราคาต่อเที่ยว, ราคาต่อกิโลเมตร, ค่ารถร่วม, ค่า standby, และค่าใช้จ่ายอื่นๆ ตามที่ group นั้นต้องใช้

สรุปแต่ละกลุ่ม​

ตัวอย่างตัวเลขด้านล่างเป็นตัวอย่างเพื่ออธิบายวิธีคิดจากโค้ด ไม่ใช่ค่าจริงของระบบ

กลุ่ม A: ค่าเที่ยว​

A1: ค่าเที่ยวพื้นฐาน ราคาแน่นอน​

  • ใช้ทำอะไร: คิดค่าเที่ยวหลักแบบราคาตายตัว
  • คำนวณยังไง: backend นับ tripRecordVehicle ที่อยู่ในช่วงบิลและตรงกับ contractRoute / vehicleType แล้วคูณ pricePerRound
  • เที่ยวตีเปล่า: ถ้ามี passPrice ระบบจะสร้างรายการเพิ่ม โดยนับจากลำดับเที่ยว IN/OUT
  • ตัวอย่าง: ถ้านับได้ 120 เที่ยว และ pricePerRound = 250 บาท จะได้ 120 x 250 = 30,000 บาท
  • ตัวอย่างเที่ยวตีเปล่า: ถ้านับได้ 20 เที่ยว และ passPrice = 80 บาท จะได้ 20 x 80 = 1,600 บาท

A2: ค่าเที่ยวที่ผูกกับราคาน้ำมัน​

  • ใช้ทำอะไร: คิดค่าเที่ยวเหมือน A1 แต่ราคาถูกเลือกจากช่วงราคาน้ำมัน
  • คำนวณยังไง: backend เอา fuelPrice ของช่วงบิลไปเทียบกับ pricePerFuelRange แล้วใช้ราคาที่ตรงช่วงนั้นมาคูณจำนวนเที่ยว
  • เที่ยวตีเปล่า: ใช้หลักเดียวกัน แต่เลือกเรตราคาตามน้ำมันแทนราคาแน่นอน
  • ตัวอย่าง: ถ้า fuelPrice ตรงช่วงที่กำหนดราคาไว้ 270 บาท/เที่ยว และนับได้ 120 เที่ยว จะได้ 120 x 270 = 32,400 บาท

A3: ค่าเที่ยวที่ต้องระบุเวลาและชนิดเที่ยวเพิ่ม​

  • ใช้ทำอะไร: คิดค่าเที่ยวที่ต้องแยกตามเวลาเดินรถและชนิดเที่ยว IN/OUT
  • คำนวณยังไง: หน้าฟอร์มเก็บ tripTime, tripType, และ tripRoundPerRoute; backend จะนับเที่ยวที่ตรง contractRoute, vehicleType, ช่วงบิล และ routeRoundTripTime แล้วคูณ pricePerRound
  • ตัวอย่าง: ถ้าเที่ยวที่ตรงเงื่อนไขมี 40 เที่ยว และ pricePerRound = 300 บาท จะได้ 40 x 300 = 12,000 บาท

กลุ่ม B: เหมาจ่ายรายเดือน​

B1: เหมาจ่ายรายเดือน ไม่แปรผันตามน้ำมัน​

  • ใช้ทำอะไร: คิดแบบเหมารายเดือน โดยเลือกได้ 2 แบบผ่าน groupOptionalLogic
  • คำนวณยังไง:
    • ถ้าเป็น VEHICLE_TYPE จะคิดแยกตามประเภทรถ ใช้ vehicleAmount x pricePerRound
    • ถ้าเป็น PACAKGE_PRICE จะรวมเป็น 1 รายการ แล้วใช้ราคาจากแถวแรก
  • ตัวอย่างแบบแยกประเภทรถ: ถ้ามีรถ 3 คัน และราคา 50,000 บาท/คัน จะได้ 3 x 50,000 = 150,000 บาท
  • ตัวอย่างแบบแพ็กเกจ: ถ้าระบบรวมเป็น 1 รายการ และตั้งราคา 180,000 บาท จะได้ 180,000 บาท

B2: เหมาจ่ายรายเดือนที่ผูกกับราคาน้ำมัน​

  • ใช้ทำอะไร: โครงสร้างเหมือน B1 แต่ราคาเปลี่ยนตามช่วงน้ำมัน
  • คำนวณยังไง: ใช้ fuelPrice ไปหาเรตราคาจาก pricePerFuelRange แล้วค่อยคำนวณตาม VEHICLE_TYPE หรือ PACAKGE_PRICE
  • ตัวอย่าง: ถ้าช่วงน้ำมันปัจจุบันให้ราคา 62,000 บาท/เดือน และมี 1 แพ็กเกจ จะได้ 62,000 บาท

กลุ่ม C: ค่าตัวรถ + ระยะทาง​

  • ใช้ทำอะไร: แยกการคิดเป็น ค่าตัวรถ, ค่ากิโลเมตร, และรายการที่อ้างอิงน้ำมัน
  • คำนวณยังไงจาก backend:
    • รายการจาก contractBillingDetails ใช้ vehicleAmount x pricePerVehicle
    • รายการจาก vehicleCalculateDetails ใช้ vehicleAmount x pricePerVehicle
    • รายการจาก contractRouteCalculations ใช้ trip count x pricePerKilometer และใส่ oilRate เพื่ออ้างอิงราคาน้ำมันของรอบนั้น
  • ตัวอย่าง: ถ้ารายการสายรถมี 2,000 กม. และตั้ง pricePerKilometer = 8 บาท จะได้ 2,000 x 8 = 16,000 บาท

กลุ่ม D: Standby​

  • ใช้ทำอะไร: คิดบิลจากงาน standby จริงในฐานข้อมูล
  • คำนวณยังไง: backend เปิด/ปิดตาม switch เช่น kmEnabled, vehiclePriceEnabled, otWorkDayEnabled, weekendEnabled, driverSalaryEnabled
  • รายการที่พบในโค้ด:
    • ค่ากิโลเมตร STB
    • ค่ากิโลเมตรเกิน
    • ราคาตัวรถ
    • OT วันธรรมดา
    • OT วันหยุด
    • ค่าพนักงานขับรถรายวัน
  • ตัวอย่าง: ถ้า standby รวมได้ 120 กม. และ stbPrice = 25 บาท/กม. จะได้ 120 x 25 = 3,000 บาท

กลุ่ม E: Full-time​

  • ใช้ทำอะไร: คิดงานประจำแบบ full-time ที่มีหลายองค์ประกอบ
  • คำนวณยังไง: backend ใช้ข้อมูลจาก fullTimePricePerKmDetail, fullTimeVehicleInWeekendDetails, fullTimeTripRoundDetails, fullTimeVehicleCalculateDetails และยังคำนวณส่วน standby ต่อท้ายเหมือนกลุ่ม D
  • รายการที่พบในโค้ด:
    • ค่ากิโลเมตร
    • ค่ารถในวันหยุด
    • ค่าต่อเที่ยว
    • ค่าตัวรถ
    • Standby ต่อท้าย
  • ตัวอย่าง: ถ้ารายการ full-time คิดได้ 120 เที่ยว และตั้งราคา 100 บาท/เที่ยว จะได้ 120 x 100 = 12,000 บาท

กลุ่ม F: เงื่อนไขพิเศษ​

  • ใช้ทำอะไร: คิดส่วน partner invoice แยกจากบิลหลัก
  • คำนวณยังไง: backend ใช้ contractPartnerInvoiceDetails แล้วคำนวณตาม operationCalculationType
    • FIXED_PRICE ใช้ราคาตายตัวจากรายละเอียดที่กรอก
    • PERCENTAGE ใช้ราคาจากบิลแล้วหักตามเปอร์เซ็นต์ของ partnerCompany.operationPercentage
  • ตัวอย่างแบบราคาแน่นอน: ถ้าค่าดำเนินการ 1,000 บาท/เที่ยว และมี 10 เที่ยว จะได้ 10,000 บาท
  • ตัวอย่างแบบเปอร์เซ็นต์: ถ้าราคาตั้งต้น 1,000 บาท/เที่ยว, 10 เที่ยว รวม 10,000 บาท และหัก 10% จะเหลือ 9,000 บาท

ภาพรวมที่ควรจำ​

  • A1, A2, A3 เป็นกลุ่มค่าเที่ยว
  • B1, B2 เป็นกลุ่มเหมาจ่ายรายเดือน
  • C เป็นกลุ่มที่ผูกกับค่าตัวรถและกิโลเมตร
  • D และ E ใช้ข้อมูล standby / full-time ที่ละเอียดกว่า
  • F เป็นกรณีพิเศษที่ต้องดู contractPartnerInvoiceDetails และ operationCalculationType

ฟอร์มที่ระบบแสดงตามกลุ่ม​

  • A1 - ฟอร์มสัญญาแบบเที่ยวคงที่
  • A2 - ฟอร์มสัญญาแบบเที่ยวผูกกับราคาน้ำมัน
  • A3 - ฟอร์มสัญญาแบบเที่ยวที่มี logic เพิ่มเติม
  • B1 - ฟอร์มเหมาจ่ายรายเดือน
  • B2 - ฟอร์มเหมาจ่ายรายเดือนที่ผูกกับราคาน้ำมัน
  • C - ฟอร์มคิดตามระยะทาง
  • D - ฟอร์มงาน Standby
  • E - ฟอร์มรถประจำ/Full-time
  • F - ฟอร์มเงื่อนไขพิเศษ

สิ่งที่ควรรู้​

  • Step นี้คือจุดที่กำหนดว่ากลุ่มสัญญาจะคิดเงินแบบไหน
  • บาง group ต้องกรอกข้อมูลเพิ่ม เช่น ตารางราคาน้ำมัน, ราคาต่อ km, หรือรายละเอียดรถร่วม
  • หน้าจอจะเปลี่ยนฟิลด์อัตโนมัติตาม group ที่เลือกจาก Step 1

ระบบตรวจจริงก่อนข้ามไป Step 3​

จากโค้ดล่าสุด หน้า Create/Edit Contract จะยิง POST /contracts/validate ตอนขยับจาก Step 2 ไป Step 3 โดยไม่ได้ตรวจแค่ field ว่าง แต่ตรวจ configuration จริงเทียบกับกติกาใน backend แล้วส่ง error กลับมาเป็นกลุ่ม section

สิ่งที่ระบบตรวจเพิ่มจาก backend เช่น:

  • route ที่ถูกอ้างใน contractBillingDetails, contractPartnerInvoiceDetails, passDetail, และชุดข้อมูล Full-time ต้องอ้างถึงสายรถที่มีจริงใน Step 1
  • กลุ่ม A2, B2, และ F ต้องมี contractBillingDetails
  • กลุ่ม A3 ต้องมี passDetail
  • ถ้าเปิด pricing บางประเภทใน D หรือ E ระบบจะบังคับว่าต้องมี detail ของหมวดนั้นจริง
  • ถ้าเปิด section ของ Full-time เช่น fullTimeKm, fullTimeTripRound, fullTimeWeekend, หรือ fullTimeVehiclePrice ระบบจะตรวจว่ามีข้อมูลรองรับครบ
  • fuel price configuration ต้องครอบช่วงราคาที่ระบบใช้คำนวณจริง มิฉะนั้นจะถูก block ก่อนบันทึก

ถ้าพบปัญหา ระบบจะแสดง dialog รวม error โดยแยกหัวข้อ เช่น ข้อมูลสายรถ, ข้อมูลการวางบิล, ข้อมูลการคำนวณราคาน้ำมัน, หรือ ข้อมูลเที่ยวตีเปล่า ทำให้ผู้ดูแลระบบย้อนกลับไปแก้เฉพาะ section ที่ผิดได้เร็วกว่าเดิม

อ้างอิงโค้ดล่าสุด​

  • /Users/chanchaitasujai/Project-ATP30/atp30-tos-frontend/src/views/pages/contracts/forms/ContractMasterForm.tsx
  • /Users/chanchaitasujai/Project-ATP30/atp30-tos-frontend/src/api/contracts.ts
  • /Users/chanchaitasujai/Project-ATP30/atp30-core-api/src/contracts/contracts.controller.ts
  • /Users/chanchaitasujai/Project-ATP30/atp30-core-api/src/contracts/contracts.service.ts

สรุปสั้นๆ​

ถ้า Step 1 คือ “โครงสัญญา”
Step 2 ก็คือ “สูตรคำนวณเงิน” ที่ผูกกับสัญญานั้นโดยตรง

สิ่งที่ควรจำ​

  • Step นี้เป็นตัวกำหนดวิธีคิดเงินหลัก
  • ถ้าเลือกกลุ่มผิด ฟอร์มที่แสดงและผลคำนวณจะผิดตามไปด้วย