Skip to content

Supplier invoice coding workbench

The Accountify AP workbench is an exception-first operational interface over Odoo. Accountify owns intake, structured extraction/OCR suggestions, work state, review, client requests, and audit. Odoo remains the system of record for vendors, draft bills, taxes, posting, payables, payments, and attachments.

Workflow boundary

Capability Odoo models Write policy
Vendor match res.partner Read; create only through approved new-vendor review
Draft vendor bill account.move Create/write while move_type is supplier document and state = draft
Coding lines account.move.line Create/write through invoice_line_ids commands on the draft bill
Journals/accounts/taxes account.journal, account.account, account.tax Read same-company active configuration
Source file ir.attachment Create/link to the bill; optional Documents integration
Posting account.move, method action_post() Separate guarded action after review and readback
PO matching purchase.order, purchase.order.line Prefer native purchase links and methods
Receipt matching stock.picking, stock.move, stock.move.line Tenant capability; durable inventory operations

Product flow

  1. A PDF, image, or structured e-invoice arrives through Accountify, email, Odoo Documents, Peppol, or another controlled source.
  2. Accountify creates an AP task and records source/checksum metadata.
  3. For a structured e-invoice, Accountify reads the authoritative XML fields and preserves the original structured artifact. For an unstructured document, OCR/AI extracts vendor, document type, dates, reference, currency, totals, taxes, payment terms, and line hints with confidence and reasons.
  4. Deterministic and historical rules suggest vendor, account, tax, analytic distribution, deferral/asset treatment, and duplicate risk.
  5. Staff reviews the document and coding in a split workbench.
  6. Accountify validates tenant, company, field combinations, policy, duplicate handling, and user role.
  7. Backend creates or updates an Odoo draft and attaches the source document with an idempotency key.
  8. A reviewer approves when policy requires it.
  9. A permitted user deliberately posts the bill after a fresh Odoo read and strict checks.
  10. Backend reads back Odoo state, totals, residual, duplicate indicators, and attachments before completing the task.

Structured e-invoice intake

The German B2B e-invoicing contract governs XRechnung, ZUGFeRD, and Peppol intake. Structured XML is the primary accounting-data source; a PDF rendering is for human review and cannot silently override it. OCR is not required merely to re-read values already present in valid structured data.

Inbound e-invoices must retain format/profile, structured-file hash, Odoo attachment identity, message UUID when available, supplier invoice ID/type, transport, and validation result. Invalid XML, unsupported profiles, structured/rendered differences, duplicate delivery, and correction relationships become explicit AP exceptions. Receipt creates a draft/work item; it never implies tax approval, posting, or payment authorization.

Accountify task API

Endpoint Purpose
GET /ap/tasks Queue rows with client, source, vendor/amount guesses, confidence, risk, owner, SLA, task and Odoo states
GET /ap/tasks/{id} Document, extraction, suggestions/reasons, coding, validation, Odoo IDs, audit, client thread
PATCH /ap/tasks/{id}/coding Save staff coding; optionally create/update an Odoo draft; never post
POST /ap/tasks/{id}/request-info Request missing/ambiguous information and move to waiting state
POST /ap/tasks/{id}/submit-review Mark complete coding ready for reviewer/approval
POST /ap/tasks/{id}/post Re-read, authorize, validate, call action_post(), then verify
POST /ap/tasks/{id}/sync-odoo Recover from retry, timeout, or direct Odoo edits through readback

Draft bill create contract

{
  "vals_list": [
    {
      "move_type": "in_invoice",
      "partner_id": 123,
      "journal_id": 10,
      "invoice_date": "2026-06-29",
      "date": "2026-06-29",
      "ref": "SUPPLIER-INV-10045",
      "invoice_line_ids": [
        [0, 0, {
          "name": "Fulfillment services",
          "quantity": 1,
          "price_unit": 250.0,
          "account_id": 456,
          "tax_ids": [[6, 0, [789]]],
          "analytic_distribution": {"321": 100}
        }]
      ]
    }
  ]
}

Call default_get first for company, currency, journal, date, and payment-term defaults under the same context as the intended create. Do not assume UI onchange behavior will run as it does in the browser. Send explicit validated values and re-read Odoo-computed totals.

Validation before draft save

  • Tenant database, allowed company, vendor, journal, accounts, taxes, and currency are coherent.
  • Document is a supplier invoice, credit note, paid receipt, or explicitly routed exception.
  • Vendor creation, if needed, has passed policy and duplicate/vendor-master checks.
  • Bill/document date is present and acceptable for accounting/tax policy.
  • Supplier reference is present unless a documented policy permits omission.
  • At least one invoice line has description, account, quantity/price (or supported amount representation), and valid taxes.
  • Analytic/deferral/asset requirements are complete where client policy requires them.
  • Source attachment exists unless explicitly waived.
  • Duplicate checksum/vendor-reference/amount-date risk is resolved or overridden with reason.

Validation before posting

  • The Odoo move still exists in draft and its write_date matches the reviewed version.
  • Odoo totals, currency, vendor, dates, reference, taxes, and lines match the approved payload/readback hash.
  • The task has no blocking warnings or unresolved client request.
  • Reviewer/client approval thresholds and staff posting permission are satisfied.
  • Duplicate warning is cleared or explicitly overridden.
  • Lock-period and tax validation pass.
  • The source document is attached.
  • The idempotency key has not already produced a posted move.

Posting has legal and accounting consequences. A timeout after action_post() is an unknown outcome: read back by bill ID/idempotency context before retrying.

Task states

New -> Extracting -> To Code -> In Coding -> Needs Review -> Ready To Post -> Posted

Exception states: Duplicate Risk, Waiting For Client, Waiting For Approval, Blocked By Odoo, Failed Sync, and Archived/Rejected.

stateDiagram-v2 [*] --> New New --> Extracting Extracting --> ToCode ToCode --> InCoding InCoding --> NeedsReview NeedsReview --> ReadyToPost ReadyToPost --> Posted InCoding --> WaitingForClient WaitingForClient --> ToCode InCoding --> DuplicateRisk DuplicateRisk --> InCoding NeedsReview --> WaitingForApproval WaitingForApproval --> ReadyToPost ReadyToPost --> BlockedByOdoo BlockedByOdoo --> ReadyToPost Posted --> [*]

Each transition records actor, reason, before/after coding hash, Odoo operation, idempotency key, result, and readback state.

Suggestions and controls

Suggestions may use vendor history, VAT ID/IBAN/email/layout, reference and amount similarity, vendor defaults, fiscal position, tax country, past account/tax/analytic coding, payment linkage, and ecommerce-specific rules. Every suggestion must show confidence and reason, support accept/edit/reject, and record the decision. Suggestions never post silently.

Purchase and three-way matching

The current database has verified purchase.order, purchase.order.line, stock.picking, stock.move, and stock.move.line support. A controlled test confirmed the native flow:

  1. Confirm purchase order.
  2. Odoo creates incoming receipt.
  3. Validate received quantity.
  4. Odoo updates qty_received.
  5. On purchase.order, call the action_create_invoice() method.
  6. Odoo creates a draft vendor bill linked through purchase_line_id/purchase_order_id.
  7. Odoo updates qty_invoiced, qty_to_invoice, and invoice_status.

Enable this per tenant only after verifying purchase_stock, warehouse, incoming picking type, stock location, Buy route, permissions, and a controlled PO-to-receipt-to-draft-bill smoke test. Store purchase_order_supported and three_way_match_supported separately.

Completed receipts are durable inventory history. Archive disposable products and use native return/reversal flows; do not hard-delete completed stock movements.

Edge cases

Cover duplicate/split/multi-document intake, wrong client, unreadable OCR, invalid or unsupported e-invoice XML, structured/rendered mismatch, repeated Peppol delivery, correction/credit-note chains, statement/quote instead of invoice, new/duplicate/renamed vendors, mixed VAT, reverse charge, import VAT/customs/freight, non-deductible VAT, assets, deferrals, deposits/retainers, credit notes, foreign currency, analytic requirements, ecommerce settlement invoices, fulfillment charges, advertising allocation, card receipts, employee reimbursements, direct Odoo edits, lock dates, permission changes, double-click/retry, timeout after create/post, and Odoo upgrades.

Testing evidence and rollout

  • Draft AP smoke test: 17 passed, 0 failed, 0 warned; draft/vendor/attachment test data cleaned up; no bill posted.
  • Studio automation smoke test: 11 passed, 0 failed, 0 warned.
  • Final PO/receipt/draft-bill three-way test: 23 passed, 0 failed, 2 warnings; native receipt and purchase links verified; no bill posted.
  • Completed test receipt remains as expected inventory history; the test product was archived.

Production posting, advanced assets, automated complex tax, and payment/reconciliation automation require separate controlled test plans.

Design basis

This guide is the sanitized, version-controlled implementation contract derived from the restricted Incoming Supplier Invoice Coding Workbench - Odoo Online Technical and UX Design dated June 26, 2026. The Drive source folder remains the record for the full design narrative and smoke-test details.