Skip to content

Workflows

Workflow 1 — ปจป. inspection committee sign-off

Three internal Odoo users (chair + 2 members) sign the annual ปจป. inspection report from inside the app. End-to-end this replaces the old paper round-trip with a chained-hash audit trail suitable for HA Thailand evidence.

Preconditions

  • Inspection record is in state Submitted (committee can only sign after the lines are locked)
  • Chair + Member 1 + Member 2 are all set on the inspection
  • Each committee member is an hr.employee with a linked res.users (so a res.partner can be resolved for the signer record)

Steps

┌─────────────────────────────────────────────────────────────────┐
│ 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.                                 │
└─────────────────────────────────────────────────────────────────┘

Roll-back / re-do

To re-do the signing (e.g. wrong committee picked), open the existing sign.oca.request and Cancel, then click "Send for Signature" again on the inspection. The bridge will create a new request; the inspection's sign_request_count will reflect both (cancelled + new).

There's no automatic prevention of duplicate-active requests — the button stays visible only while sign_request_count == 0, but if all prior requests are cancelled it reappears.

Workflow 2 — Service contract vendor + hospital sign-off

External vendor signs via portal email link; hospital authorized signer co-signs in-app. Two signers total.

Preconditions

  • Vendor partner has an email address set (required for the portal sign link)
  • roots_hospital_signer_id is set on the contract (any res.users with a linked res.partner)

Steps

┌─────────────────────────────────────────────────────────────────┐
│ 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)".                       │
└─────────────────────────────────────────────────────────────────┘

When signing fails

The bridge's _check_*_signers_resolvable guards raise UserError with a clear message naming the offending slot:

Error Cause Fix
"Committee Member N — not set" Inspection has fewer than 3 committee members assigned Set all 3 on the inspection form
"Committee Member N (name) — no linked Odoo user" The employee has no user_id Create a res.users for that employee and link it via Employees → Related User
"Hospital Authorized Signer — not set" Contract has no signer Set roots_hospital_signer_id on the contract form
"Vendor (name) — has no email address" Vendor partner is missing email Edit the vendor partner and add an email

The _check_signed hook itself is wrapped in a defensive try/except — if the parent write or chatter post fails (e.g. ACL collision, mail config issue), the signer still gets a successful "signed" experience. The error is logged server-side; the signed PDF remains available on the sign.oca.request record itself.

What's intentionally NOT in V1

See the index page for the full deferral list. Notably:

  • No sequential signing — any signer can sign first (OQ2)
  • No state gating — signing does not advance the parent's state (OQ3)
  • No bridge on maintenance.request — BME Manager / Ward / PM monthly sign-offs stay on paper for V1 (OQ1)