drivethru-payable-matching
Payable matching for BaconCo — reconcile vendor documents in Odoo's Documents app against their purchase orders and correct incorrect PO line pricing. Use for requests like "check the Purchasing folder against the POs and fix the pricing", "match the vendor invoice / order confirmation / acknowledgement to its PO", "AP price matching / invoice-to-PO matching / three-way match", "reconcile the vendor documents and mark the POs checked", or "go through the Purchasing folder". The flow: read every document in a Documents-app folder (extracting text out-of-context so large batches don't bloat the context window — falling back to a page render + OCR/vision for scanned or custom-encoded PDFs that won't extract as text), pull the PO number / line items / unit prices from each, compare to the purchase order line by line, correct any wrong `price_unit`, post a "checked" log note on the PO (internal, never a "Send message"), and FILE every document into the `Matched` or `Questions` subfolder — escalating genuine questions to a reviewer (default Zach Tucker). Also runs the buying-group payables flow: pull Sports Inc invoices from the SportsLink API (via the `sportsinc-sportslink` adapter), reconcile each to its PO, correct price variances, create the vendor bill and — when the bill total matches the invoice within tolerance — POST it, leaving any mismatch in draft for a human ("get the Sports Inc invoices and bill them", "match the SI invoices to POs and post the payables", "match the vendor invoice and post the bill if it matches"). Handles the multi-shipment case where one PO returns several Sports Inc invoices, splitting it into one vendor bill per shipment via `account.move.line` edits (the `ap_*_bill_line(s)` tools). Runs at volume on a low-cost model. Driven by the Odoo `drivethru_mcp` MCP server; complements the broader `drivethru-odoo` skill.
Rank
62
Safety
84
Downloads
1.4k
Updated
Oct 10, 2026
Version
0.10.0
Source
CLAWHUB
About
What it does, and when to use it.
Capability contract not published. No trust telemetry is available yet. 1.4K downloads reported by the source. Last updated 10/10/2026.
Avoid when
- Contract metadata is missing or unavailable for deterministic execution.
Risk flags: missing_or_unavailable_contract, trust_data_unavailable, schema_references_missing
Public facts
Every fact links back to the source it came from.
- Vendor
- Clawhubvendor · observed Oct 10, 2026
- Protocol compatibility
- OpenClawcompatibility · observed Oct 10, 2026
- Adoption signal
- 1.4K downloadsadoption · observed Oct 10, 2026
- Latest release
- 0.10.0release · observed Sep 23, 2026
- Handshake status
- UNKNOWNsecurity
Install and run
Setup complexity: low.
clawhub skill install s17fq291581evd78xzn1930b0n87bfny:drivethru-payable-matching- Install using `clawhub skill install s17fq291581evd78xzn1930b0n87bfny:drivethru-payable-matching` in an isolated environment before connecting it to live workloads.
- No published capability contract is available yet, so validate auth and request/response behavior manually.
- Review the upstream CLAWHUB listing at https://clawhub.ai/zmtucker/drivethru-payable-matching before using production credentials.
Contract: missing
curl -s "https://www.xpersona.co/api/v1/agents/clawhub-zmtucker-drivethru-payable-matching/snapshot"
Documentation
CLAWHUB
151,843 characters of source documentation, loaded on request.
Extracted files
5 files captured from the source.
SKILL.md
---
name: drivethru-payable-matching
description: >
Payable matching for BaconCo — reconcile vendor documents in Odoo's Documents
app against their purchase orders and correct incorrect PO line pricing. Use
for requests like "check the Purchasing folder against the POs and fix the
pricing", "match the vendor invoice / order confirmation / acknowledgement to
its PO", "AP price matching / invoice-to-PO matching / three-way match",
"reconcile the vendor documents and mark the POs checked", or "go through the
Purchasing folder". The flow: read every document in a Documents-app folder
(extracting text out-of-context so large batches don't bloat the context
window — falling back to a page render + OCR/vision for scanned or
custom-encoded PDFs that won't extract as text), pull the PO number / line
items / unit prices from each, compare to the purchase order line by line,
correct any wrong `price_unit`, post a "checked" log note on the PO (internal,
never a "Send message"), and FILE every document into the `Matched` or
`Questions` subfolder — escalating genuine questions to a reviewer (default
Zach Tucker). Also runs the buying-group payables flow: pull Sports Inc
invoices from the SportsLink API (via the `sportsinc-sportslink` adapter),
reconcile each to its PO, correct price variances, create the vendor bill and
— when the bill total matches the invoice within tolerance — POST it, leaving
any mismatch in draft for a human ("get the Sports Inc invoices and bill
them", "match the SI invoices to POs and post the payables", "match the vendor
invoice and post the bill if it matches"). Handles the multi-shipment case
where one PO returns several Sports Inc invoices, splitting it into one vendor
bill per shipment via `account.move.line` edits (the `ap_*_bill_line(s)`
tools). Runs at volume on a low-cost model.
Driven by the Odoo `drivethru_mcp` MCP server; complements the broader
`drivethru-odoo` skill.
version: 0.10.0
emoji: 🧾
homepage: https://www.odoo.com
metadata:
openclaw:
requires:
env: [ODOO_MCP_URL, ODOO_MCP_TOKEN]
bins: [python3, uv] # uv powers the scripts' self-bootstrap fallback
primaryEnv: ODOO_MCP_TOKEN
envVars:
ODOO_MCP_URL:
required: true
description: >
Full URL of the Odoo MCP endpoint, e.g.
`https://odoo.example.com/drivethru_mcp/v1` — the MCP server exposed by
the `drivethru_mcp` Odoo module, not the Odoo base URL.
ODOO_MCP_TOKEN:
required: true
description: >
The `drivethru.mcp_key` value from the `drivethru_mcp` module, sent as
`Authorization: Bearer`. Treat as a secret; never paste into chat.
install:
uv:
- mcp>=1.9.0
- pymupdf>=1.24 # primary local PDF text extraction + page rasterization:
# honours ToUnicode/Type3 (custom-encoded) fonts pypdf can't
# read, and renders needs_vision docs_meta.json
{
"ownerId": "kn715tnf30wegyr6mdbfa17avd87bjr6",
"slug": "drivethru-payable-matching",
"version": "0.10.0",
"publishedAt": 1790187380449
}references/matching_procedure.md
# Payable matching — full procedure, tool shapes, example, economics
Reference behind `SKILL.md`. Read it when you need the detail behind a step,
the exact field names a payload carries, or the cost model for running this at
volume.
---
## 1. Why the design is shaped this way
Two forces drive every choice:
- **Context economy.** Documents are PDFs. `documents_get` returns their bytes
as base64; a multimodal PDF reader adds a page image. Both are enormous next
to the ~300–600 characters of text that actually matter, and this runs over
many documents many times a day. So text extraction is pushed into
`scripts/paymatch.py` (`extract`), which decodes and reads the text **locally**
and returns text only. The model never sees base64 or a render. `po-lines`
likewise trims the verbose PO payload to the matchable fields. The result: a
document "match" costs the model a few thousand tokens, not tens of thousands.
Extraction runs **PyMuPDF → poppler `pdftotext -layout` → pypdf** and
quality-gates the output. PyMuPDF is first because it honours ToUnicode CMaps
and reads **Type3 / custom-encoded fonts** that pypdf returns as empty or
garbage (the failure that stranded Charles River Apparel confirmations). A
result that is empty or fails the reliability gate flags the document
`needs_vision: true`; the model then calls `render` to rasterise the page(s)
with PyMuPDF (no system poppler) and reads them with vision (plus tesseract OCR
if present) — keeping even the unreadable-text case out of a dead-end
escalation, while still never pulling raw base64 into context.
- **Judgment stays with the model.** The script does deterministic I/O (fetch,
decode, extract, apply a price, move a file). The *matching decision* — which
document line pairs to which PO line, whether a total gap is a partial
shipment, whether a freight figure is authoritative, whether something is a
genuine question — needs the model, because vendor documents vary too much for
a rigid parser. Get this division wrong in either direction and you either
bloat context (model reading raw bytes) or get brittle matches (script
guessing intent).
---
## 2. The tool surface (MCP), and the payload shapes you'll see
The skill drives the Odoo `drivethru_mcp` MCP tools. `paymatch.py` wraps the
ones below; the field names are what the tools actually return (know them so you
don't waste calls discovering them).
### Documents app
- `documents_list_folders {name?, parent_id?}` → `{folders: [{id, name, parent,
document_count}]}`. Resolve `Purchasing` → its id; list its children with
`{parent_id}` to get the `Matched` / `Questions` folder ids.
- `documents_search {folder_id, limit, offset, include_subfolders?}` →
`{documents: [{id, name, type, mimetype, file_size, folder:{id,name}, tags,
res_model, res_id, ...}], total_matched}`. Metadata only — **no bytes**.
Paginate on `total_matched`.
- `documents_get {document_id}` → the metadata **plus** `data_basreferences/sportsinc_payables.md
# Sports Inc payables — end-to-end (SportsLink → match → bill → post-on-match)
Sports Inc is a buying group that doesn't send individual vendor invoices; the
invoices live in the SportsLink API. This is the automated payables loop for
them: pull the invoices, reconcile each to its Odoo PO, correct price variances,
create the bill, **post it when its total matches the invoice** (else leave it
in draft), and mark the SI document consumed — with a human handling anything
flagged.
Three skills cooperate (this is the ports-and-adapters split in practice):
- **Source adapter** — `sportsinc-sportslink` (`sportslink.py`): fetch invoices,
mark consumed. Customer-agnostic.
- **Workflow** — this skill: reconcile invoice ↔ PO, correct/escalate, create the
draft bill. Source- and ERP-agnostic.
- **ERP adapter** — `drivethru-odoo` / `drivethru_mcp` (`paymatch.py`,
`ap_create_vendor_bill` / `ap_post_vendor_bill`): the Odoo writes.
## Configured policy (BaconCo)
- **Posting: post on match, draft on mismatch.** Create the bill, then **post it
when the bill total matches the invoice `expected_total` within tolerance**
(`paymatch.py post`, backed by the guarded `ap_post_vendor_bill`). A bill that
doesn't match is **left in draft** and escalated to the reviewer — never post a
mismatch. When a run should stay hands-off (a human reviews before posting),
skip the `post` step and leave every bill in draft.
- **On variance: auto-fix price, escalate qty/line.** A unit-price difference is
treated as the SI invoice being authoritative — correct the PO line (like the
pricing review), then bill. A **quantity / missing-line / total-structure**
variance is **not** auto-fixed — escalate it (leave the SI doc active, raise an
activity to the reviewer, create no bill). Once the reviewer **answers** the
escalation, you carry out their decision yourself — see
[Acting on the reviewer's answer](#acting-on-the-reviewers-answer-quantity-escalations).
- **Reviewer:** Zach Tucker (`reviewer_user_id: 6` in BaconCo's Odoo). Keep this
in tenant config, not hard-coded in prose.
- **Tolerance:** a small **absolute** amount (a few cents, e.g. `0.02`) for the
`expected_total` match check on both create and post — once prices are
reconciled the SI docTotal should equal the computed bill to within rounding.
- **Chatter: internal log notes only.** Every PO note or escalation this loop
posts (via `po_post_message`) is an internal Odoo **log note**, never a "Send
message" — nothing here is emailed to the vendor.
## The exactly-once loop (do not deviate)
You are creating payables — double-billing is the cardinal sin. The SportsLink
`active`/historical flag is the idempotency mechanism; the sequence is fixed:
1. **Pull the inbox.** `sportslink.py list '{"active": true, "lines": true, "ediOnly": true}'`
→ normalised invoices that are not yet imported and carry line items.
2. **Process each invoice** (below). Create the draft bill in Odoo.
3. **Mark consumeskill-card.md
## Description: Reconciles vendor payable documents and Sports Inc invoices against Odoo purchase orders, corrects supported PO price variances, routes unresolved items for review, and creates or posts vendor bills only when totals match. This skill is ready for commercial/non-commercial use. ## Publisher: [zmtucker](https://clawhub.ai/user/zmtucker) ### License/Terms of Use: MIT-0 ## Use Case: Accounting and purchasing operators use this skill to reconcile vendor confirmations, acknowledgements, and invoices against Odoo purchase orders, update clearly supported price variances, file reviewed documents, and prepare or post matched payables. ### Deployment Geography for Use: Global ## Known Risks and Mitigations: Risk: The skill can change live Odoo purchasing and accounting records, including PO pricing and vendor bill state. Mitigation: Install only where that authority is intended, use least-privilege Odoo/MCP credentials, and require human authorization for bill posting, quantity changes, dropship validation, and credential-sharing delegation. Risk: A mismatched payable could be posted if totals or invoice structure are not checked. Mitigation: Prefer draft or dry-run operation until the workflow is proven, leave mismatches in draft, and post only when the bill total matches the source invoice within tolerance. Risk: Runtime dependency bootstrapping can install Python packages into a cached environment. Mitigation: Review the dependency bootstrapping policy and preinstall or approve the declared packages before production use. ## Reference(s): - [Payable matching procedure](references/matching_procedure.md) - [Sports Inc payables procedure](references/sportsinc_payables.md) - [Odoo](https://www.odoo.com) - [ClawHub skill page](https://clawhub.ai/zmtucker/skills/drivethru-payable-matching) ## Skill Output: **Output Type(s):** [text, markdown, shell commands, configuration, guidance] **Output Format:** [Markdown guidance with JSON command payloads and concise reconciliation summaries] **Output Parameters:** [1D] **Other Properties Related to Output:** [May run Odoo MCP operations through native tools or scripts/paymatch.py; helper commands return JSON objects.] ## Skill Version(s): 0.10.0 (source: frontmatter and release evidence) ## Ethical Considerations: Users should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.
AionUi
Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!
activepieces
AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents
cherry-studio
AI productivity studio with smart chat, autonomous agents, and 300+ assistants.
CopilotKit
The Frontend for Agents & Generative UI. React + Angular
Machine-readable data
The same record, as JSON, for agents and crawlers.
{
"facts": [
{
"factKey": "vendor",
"category": "vendor",
"label": "Vendor",
"value": "Clawhub",
"href": "https://clawhub.ai/zmtucker/skills/drivethru-payable-matching",
"sourceUrl": "https://clawhub.ai/zmtucker/skills/drivethru-payable-matching",
"sourceType": "profile",
"confidence": "medium",
"observedAt": "2026-10-10T13:48:21.095Z",
"isPublic": true
},
{
"factKey": "protocols",
"category": "compatibility",
"label": "Protocol compatibility",
"value": "OpenClaw",
"href": "https://www.xpersona.co/api/v1/agents/clawhub-zmtucker-drivethru-payable-matching/contract",
"sourceUrl": "https://www.xpersona.co/api/v1/agents/clawhub-zmtucker-drivethru-payable-matching/contract",
"sourceType": "contract",
"confidence": "medium",
"observedAt": "2026-10-10T13:48:21.095Z",
"isPublic": true
},
{
"factKey": "traction",
"category": "adoption",
"label": "Adoption signal",
"value": "1.4K downloads",
"href": "https://clawhub.ai/zmtucker/drivethru-payable-matching",
"sourceUrl": "https://clawhub.ai/zmtucker/drivethru-payable-matching",
"sourceType": "profile",
"confidence": "medium",
"observedAt": "2026-10-10T13:48:21.095Z",
"isPublic": true
},
{
"factKey": "latest_release",
"category": "release",
"label": "Latest release",
"value": "0.10.0",
"href": "https://clawhub.ai/zmtucker/drivethru-payable-matching",
"sourceUrl": "https://clawhub.ai/zmtucker/drivethru-payable-matching",
"sourceType": "release",
"confidence": "medium",
"observedAt": "2026-09-23T18:16:20.449Z",
"isPublic": true
},
{
"factKey": "handshake_status",
"category": "security",
"label": "Handshake status",
"value": "UNKNOWN",
"href": "https://www.xpersona.co/api/v1/agents/clawhub-zmtucker-drivethru-payable-matching/trust",
"sourceUrl": "https://www.xpersona.co/api/v1/agents/clawhub-zmtucker-drivethru-payable-matching/trust",
"sourceType": "trust",
"confidence": "medium",
"observedAt": null,
"isPublic": true
}
],
"events": [
{
"eventType": "release",
"title": "Release 0.10.0",
"description": "Version 0.10.0 - Added significant updates across documentation and scripts. - Improved matching procedure and references for Sports Inc payables. - Enhanced the paymatch.py script for better bulk PDF extraction and processing. - Removed outdated skill-card.md file. - Miscellaneous documentation improvements for clarity and accuracy.",
"href": "https://clawhub.ai/zmtucker/drivethru-payable-matching",
"sourceUrl": "https://clawhub.ai/zmtucker/drivethru-payable-matching",
"sourceType": "release",
"confidence": "medium",
"observedAt": "2026-09-23T18:16:20.449Z",
"isPublic": true
}
]
}Record generated Oct 10, 2026.
