เวิร์กโฟลว์¶
เวิร์กโฟลว์ 1 — การลงนามอนุมัติของคณะกรรมการตรวจสอบ ปจป.¶
ผู้ใช้ Odoo ภายในสามคน (ประธาน + กรรมการ 2 ท่าน) ลงนามรายงานการตรวจสอบ ประจำปี ปจป. จากภายในแอป ตั้งแต่ต้นจนจบ กระบวนการนี้แทนที่การส่งกระดาษ ไปกลับแบบเดิมด้วยร่องรอยการตรวจสอบแบบ chained-hash ที่เหมาะสำหรับหลักฐาน HA Thailand
เงื่อนไขเบื้องต้น¶
- เรกคอร์ดการตรวจสอบอยู่ในสถานะ Submitted (คณะกรรมการลงนามได้ก็ต่อ เมื่อรายการถูกล็อกแล้วเท่านั้น)
- ประธาน + กรรมการ 1 + กรรมการ 2 ถูกตั้งค่าครบบนการตรวจสอบ
- กรรมการแต่ละท่านเป็น
hr.employeeที่มีres.usersเชื่อมโยง (เพื่อให้ สามารถจับคู่res.partnerสำหรับเรกคอร์ดผู้ลงนามได้)
ขั้นตอน¶
┌─────────────────────────────────────────────────────────────────┐
│ 1. Officer opens the submitted inspection │
│ 2. Officer clicks [ Send for Signature ] │
│ │
│ Bridge: │
│ a. Renders ปจป. PDF via the existing qweb report │
│ b. Resolves 3 partners from chair/member_1/member_2 │
│ (.user_id.partner_id) │
│ c. Creates sign.oca.request: │
│ record_ref = "hemms.asset.inspection,<id>" │
│ signer_ids = [chair, member_1, member_2] │
│ d. Opens the request form for review │
│ │
│ 3. Officer reviews signers, optionally clicks [ Configure │
│ Document ] to drag signature fields onto the PDF (the │
│ bridge does NOT pre-place fields) │
│ │
│ 4. Officer clicks [ Send ] │
│ → request.state: 1_draft → 0_sent │
│ → notification emails sent to all 3 signers │
│ │
│ 5. Chair clicks 📝 pencil icon (systray) │
│ → opens the request │
│ → reviews the PDF │
│ → clicks [ Sign ] │
│ → draws signature in canvas │
│ → submits │
│ Chair's signer record: signed_on populated, hash computed │
│ │
│ 6. Member 1 + Member 2 follow the same path (any order — no │
│ workflow ordering per OQ2) │
│ │
│ 7. As the 3rd signer submits: │
│ Upstream sign.oca.request._check_signed(): │
│ all(signer_ids.signed_on) → state := 2_signed │
│ Our Q4.5 extension fires: │
│ - inspection.roots_signed_pdf := request.data │
│ - inspection.roots_signed_pdf_filename := AI-2026-00001- │
│ signed.pdf │
│ - inspection.message_post(body="✅ Document signed by all │
│ parties...", attachments=[(filename, raw_pdf)]) │
│ Inspection.state STAYS 'submitted' (OQ3/OQ2 — no auto- │
│ advance) │
│ │
│ 8. Print the report. The signature footer now shows the green │
│ "✅ ลงนามดิจิทัลครบถ้วน" stamp pointing to the signed PDF in │
│ chatter. Filed paper printouts before this point keep the │
│ legacy 3-box signature footer. │
└─────────────────────────────────────────────────────────────────┘
การย้อนกลับ / ทำใหม่¶
หากต้องการลงนามใหม่ (เช่น เลือกคณะกรรมการผิด) ให้เปิด sign.oca.request ที่มีอยู่แล้วคลิก Cancel จากนั้นคลิก "Send for Signature" บนการตรวจสอบ อีกครั้ง บริดจ์จะสร้างคำขอใหม่; sign_request_count ของการตรวจสอบจะ สะท้อนทั้งสอง (ที่ยกเลิก + ใหม่)
ไม่มีการป้องกันคำขอที่ active ซ้ำกันโดยอัตโนมัติ — ปุ่มจะปรากฏก็ต่อเมื่อ sign_request_count == 0 แต่ถ้าคำขอก่อนหน้าทั้งหมดถูกยกเลิก ปุ่มจะปรากฏ อีกครั้ง
เวิร์กโฟลว์ 2 — การลงนามอนุมัติสัญญาบริการโดยผู้ขาย + โรงพยาบาล¶
ผู้ขายภายนอกลงนามผ่านลิงก์อีเมลพอร์ทัล; ผู้มีอำนาจลงนามฝั่งโรงพยาบาล ร่วมลงนามในระบบ รวมผู้ลงนามสองคน
เงื่อนไขเบื้องต้น¶
- พาร์ตเนอร์ผู้ขายมี ที่อยู่อีเมล ตั้งค่าไว้ (จำเป็นสำหรับลิงก์ลงนาม ผ่านพอร์ทัล)
roots_hospital_signer_idถูกตั้งค่าบนสัญญา (res.usersใด ๆ ที่มีres.partnerเชื่อมโยง)
ขั้นตอน¶
┌─────────────────────────────────────────────────────────────────┐
│ 1. BME Manager opens the contract │
│ 2. BME Manager clicks [ Send for Signature ] │
│ │
│ Bridge: │
│ a. Renders contract qweb summary PDF │
│ (report_hemms_service_contract_summary_document) │
│ b. Resolves partners: │
│ vendor signer = contract.partner_id │
│ hospital signer = roots_hospital_signer_id.partner_id │
│ c. Creates sign.oca.request with 2 signers │
│ d. Opens the request form │
│ │
│ 3. BME Manager clicks [ Configure Document ] → drags signature │
│ fields for vendor + hospital onto the PDF │
│ │
│ 4. BME Manager clicks [ Send ] │
│ → request.state: 1_draft → 0_sent │
│ → vendor receives an email with a portal link │
│ → hospital signer sees a 📝 icon in their systray │
│ │
│ 5. Vendor clicks the email link → portal page opens with the │
│ PDF preview → vendor reviews + signs + submits │
│ (No Odoo login required — portal access is granted by the │
│ per-request access_token) │
│ │
│ 6. Hospital signer opens via systray → signs │
│ (Order doesn't matter — vendor can sign first or hospital │
│ first, per OQ2) │
│ │
│ 7. As the 2nd signer submits, the Q4.5 hook fires: │
│ - contract.roots_signed_pdf := request.data │
│ - contract.roots_signed_pdf_filename := SC-2026-00001- │
│ signed.pdf │
│ - contract.message_post(body="✅ Document signed by all │
│ parties...", attachments=[...]) │
│ Contract.state UNCHANGED (OQ3 — signing is parallel to │
│ the date-driven draft/active/expired lifecycle) │
│ │
│ 8. The signed-PDF download widget appears on the contract form │
│ under "ลงนามดิจิทัล (Digital Signature)". │
└─────────────────────────────────────────────────────────────────┘
เมื่อการลงนามล้มเหลว¶
การ์ด _check_*_signers_resolvable ของบริดจ์จะยก UserError พร้อม ข้อความที่ชัดเจนซึ่งระบุช่องที่มีปัญหา:
| ข้อผิดพลาด | สาเหตุ | วิธีแก้ |
|---|---|---|
| "Committee Member N — not set" | การตรวจสอบมีกรรมการน้อยกว่า 3 ท่าน | ตั้งค่าครบทั้ง 3 ท่านบนฟอร์มการตรวจสอบ |
| "Committee Member N (name) — no linked Odoo user" | พนักงานไม่มี user_id | สร้าง res.users สำหรับพนักงานท่านนั้นและเชื่อมโยงผ่าน Employees → Related User |
| "Hospital Authorized Signer — not set" | สัญญาไม่มีผู้ลงนาม | ตั้งค่า roots_hospital_signer_id บนฟอร์มสัญญา |
| "Vendor (name) — has no email address" | พาร์ตเนอร์ผู้ขายขาด email | แก้ไขพาร์ตเนอร์ผู้ขายและเพิ่มอีเมล |
hook _check_signed เองถูกห่อด้วย try/except เชิงป้องกัน — หากการเขียน เรกคอร์ดแม่หรือการโพสต์แชตเตอร์ (chatter) ล้มเหลว (เช่น การชนกันของ ACL, ปัญหาการตั้งค่าเมล) ผู้ลงนามยังคงได้รับประสบการณ์ "signed" ที่สำเร็จ ข้อผิดพลาดจะถูกบันทึกฝั่งเซิร์ฟเวอร์; PDF ที่ลงนามแล้วยังคงพร้อมใช้งานบน เรกคอร์ด sign.oca.request เอง
สิ่งที่ตั้งใจจะ "ไม่" รวมไว้ใน V1¶
ดู หน้า index สำหรับรายการที่เลื่อนออกไปทั้งหมด ที่น่าสังเกต:
- ไม่มีการลงนามแบบเรียงลำดับ — ผู้ลงนามคนใดก็ลงนามก่อนได้ (OQ2)
- ไม่มีการควบคุมสถานะ — การลงนามไม่เลื่อนสถานะของเรกคอร์ดแม่ (OQ3)
- ไม่มีบริดจ์บน
maintenance.request— การลงนามอนุมัติรายเดือนของ BME Manager / Ward / PM ยังคงอยู่บนกระดาษสำหรับ V1 (OQ1)