diff --git a/skills/invoice-three-way-match/SKILL.md b/skills/invoice-three-way-match/SKILL.md new file mode 100644 index 00000000..015c3ec1 --- /dev/null +++ b/skills/invoice-three-way-match/SKILL.md @@ -0,0 +1,131 @@ +# runx skill: invoice intake and three-way match + +## What this skill does + +Given structured invoice data, a purchase order, and a goods receipt, this skill performs an automated three-way match and produces a payment approval proposal. It validates line-item quantities and prices, applies general ledger coding, and flags discrepancies for review. + +## Input + +The skill expects a JSON object with four fields: + +| Field | Type | Description | +|-------|------|-------------| +| `invoice` | object | Invoice header and line items (vendor, number, date, line_items with description/quantity/unit_price/total/category) | +| `purchase_order` | object | PO header and line items (po_number, vendor, line_items with description/quantity/unit_price/total) | +| `goods_receipt` | object | Receiving record (receipt_number, received_items with description/quantity_received) | +| `gl_codes` | object | GL mapping (category_to_account: { "category": "GL-XXXX" }) | + +### Input example + +```json +{ + "meeting_context": { + "invoice": { + "vendor": "Acme Office Supplies", + "invoice_number": "INV-2024-0789", + "date": "2024-06-15", + "due_date": "2024-07-15", + "line_items": [ + { "description": "Premium copy paper A4 case", "quantity": 10, "unit_price": 45.00, "total": 450.00, "category": "office_supplies" }, + { "description": "Toner cartridge HP 26X", "quantity": 5, "unit_price": 120.00, "total": 600.00, "category": "printer_supplies" }, + { "description": "Desk chair ergonomic mesh", "quantity": 2, "unit_price": 350.00, "total": 700.00, "category": "furniture" } + ], + "subtotal": 1750.00, + "tax": 140.00, + "total": 1890.00 + }, + "purchase_order": { + "po_number": "PO-2024-0314", + "vendor": "Acme Office Supplies", + "date": "2024-06-01", + "line_items": [ + { "description": "Premium copy paper A4 case", "quantity": 10, "unit_price": 42.00, "total": 420.00 }, + { "description": "Toner cartridge HP 26X", "quantity": 5, "unit_price": 118.00, "total": 590.00 }, + { "description": "Desk chair ergonomic mesh", "quantity": 2, "unit_price": 340.00, "total": 680.00 } + ] + }, + "goods_receipt": { + "receipt_number": "GR-2024-0215", + "date": "2024-06-12", + "received_items": [ + { "description": "Premium copy paper A4 case", "quantity_received": 10 }, + { "description": "Toner cartridge HP 26X", "quantity_received": 4 }, + { "description": "Desk chair ergonomic mesh", "quantity_received": 2 } + ] + }, + "gl_codes": { + "category_to_account": { + "office_supplies": "GL-5100", + "printer_supplies": "GL-5105", + "furniture": "GL-5200" + } + } + } +} +``` + +## Output + +The skill produces a JSON object with payment approval proposal fields: + +| Field | Type | Description | +|-------|------|-------------| +| `approval_status` | string | `approved`, `conditional`, or `rejected` | +| `matched_lines` | array | Per-line match results against PO and receipt | +| `exceptions` | array | Discrepancies found during matching | +| `total_matched_amount` | number | Sum of fully matched lines | +| `total_exception_amount` | number | Sum of lines with exceptions | +| `gl_summary` | array | GL coding by account | +| `approval_recommendation` | string | Human-readable explanation | + +### Output example + +```json +{ + "prep_brief": { + "approval_status": "conditional", + "matched_lines": [ + { "line_number": 1, "description": "Premium copy paper A4 case", "invoice_amount": 450.00, "po_amount": 420.00, "receipt_qty": 10, "match_status": "price_mismatch", "gl_account": "GL-5100" }, + { "line_number": 2, "description": "Toner cartridge HP 26X", "invoice_amount": 600.00, "po_amount": 590.00, "receipt_qty": 4, "match_status": "quantity_mismatch", "gl_account": "GL-5105" }, + { "line_number": 3, "description": "Desk chair ergonomic mesh", "invoice_amount": 700.00, "po_amount": 680.00, "receipt_qty": 2, "match_status": "price_mismatch", "gl_account": "GL-5200" } + ], + "exceptions": [ + { "type": "price_mismatch", "line_number": 1, "description": "Premium copy paper A4 case", "expected": "42.00 per unit (PO)", "actual": "45.00 per unit (invoice)", "severity": "medium" }, + { "type": "quantity_mismatch", "line_number": 2, "description": "Toner cartridge HP 26X", "expected": "5 received (PO qty)", "actual": "4 received (goods receipt)", "severity": "medium" }, + { "type": "price_mismatch", "line_number": 3, "description": "Desk chair ergonomic mesh", "expected": "340.00 per unit (PO)", "actual": "350.00 per unit (invoice)", "severity": "low" } + ], + "total_matched_amount": 0, + "total_exception_amount": 1750.00, + "gl_summary": [ + { "account": "GL-5100", "description": "Office supplies", "amount": 450.00 }, + { "account": "GL-5105", "description": "Printer supplies", "amount": 600.00 }, + { "account": "GL-5200", "description": "Furniture", "amount": 700.00 } + ], + "approval_recommendation": "Conditional approval recommended. Three price variances and one quantity variance found. Total variance of $90.00 is within 5% threshold. Recommend approving with price adjustment to PO rates." + } +} +``` + +## Procedure + +1. The agent receives the input JSON with invoice, purchase_order, goods_receipt, and gl_codes +2. For each invoice line item, the agent: + a. Finds the matching line in the purchase order by description + b. Checks the goods receipt for received quantity + c. Compares invoice unit_price against PO unit_price + d. Compares invoice quantity against receipt quantity +3. If all three match (description, price, quantity), the line is marked as `matched` +4. Discrepancies are recorded as `exceptions` with severity: + - `low`: variance under 3% + - `medium`: variance 3-10% + - `high`: variance over 10% or item missing from PO/receipt +5. GL codes are applied based on the category_to_account mapping +6. The final approval status is determined: + - `approved`: no exceptions + - `conditional`: exceptions exist but within threshold + - `rejected`: high-severity exceptions or missing critical data +7. Output the structured JSON response + +## Worked example + +See the fixture at `fixtures/full-match/` for a clean three-way match scenario and `fixtures/partial-exception/` for a case with price and quantity discrepancies. diff --git a/skills/invoice-three-way-match/X.yaml b/skills/invoice-three-way-match/X.yaml new file mode 100644 index 00000000..a80518af --- /dev/null +++ b/skills/invoice-three-way-match/X.yaml @@ -0,0 +1,278 @@ +skill: invoice-three-way-match +version: "0.1.0" + +catalog: + kind: skill + audience: public + visibility: public + role: canonical + +harness: + cases: + - name: invoice-three-way-full-match + inputs: + meeting_context: + invoice: + vendor: "TechParts Inc." + invoice_number: "INV-2024-1001" + date: "2024-07-01" + due_date: "2024-07-30" + line_items: + - description: "USB-C hub 7-in-1" + quantity: 20 + unit_price: 25.00 + total: 500.00 + category: "electronics" + - description: "HDMI cable 3m" + quantity: 30 + unit_price: 8.00 + total: 240.00 + category: "cables" + subtotal: 740.00 + tax: 59.20 + total: 799.20 + purchase_order: + po_number: "PO-2024-0500" + vendor: "TechParts Inc." + date: "2024-06-20" + line_items: + - description: "USB-C hub 7-in-1" + quantity: 20 + unit_price: 25.00 + total: 500.00 + - description: "HDMI cable 3m" + quantity: 30 + unit_price: 8.00 + total: 240.00 + goods_receipt: + receipt_number: "GR-2024-0300" + date: "2024-06-28" + received_items: + - description: "USB-C hub 7-in-1" + quantity_received: 20 + - description: "HDMI cable 3m" + quantity_received: 30 + gl_codes: + category_to_account: + electronics: "GL-5300" + cables: "GL-5305" + caller: + answers: + agent_task.invoice-three-way-match.output: + prep_brief: + approval_status: "approved" + matched_lines: + - line_number: 1 + description: "USB-C hub 7-in-1" + invoice_amount: 500.00 + po_amount: 500.00 + receipt_qty: 20 + match_status: "matched" + gl_account: "GL-5300" + - line_number: 2 + description: "HDMI cable 3m" + invoice_amount: 240.00 + po_amount: 240.00 + receipt_qty: 30 + match_status: "matched" + gl_account: "GL-5305" + exceptions: [] + total_matched_amount: 740.00 + total_exception_amount: 0 + gl_summary: + - account: "GL-5300" + description: "Electronics" + amount: 500.00 + - account: "GL-5305" + description: "Cables" + amount: 240.00 + approval_recommendation: "Full approval recommended. All three-way match criteria satisfied. Invoice total $799.20 matches PO and goods receipt. No discrepancies found." + expect: + status: sealed + receipt: + schema: runx.receipt.v1 + + - name: invoice-three-way-partial-exception + inputs: + meeting_context: + invoice: + vendor: "OfficeMax Direct" + invoice_number: "INV-2024-2002" + date: "2024-07-05" + due_date: "2024-08-04" + line_items: + - description: "Stapler heavy duty" + quantity: 15 + unit_price: 22.00 + total: 330.00 + category: "office_supplies" + - description: "Whiteboard marker set" + quantity: 25 + unit_price: 5.50 + total: 137.50 + category: "office_supplies" + subtotal: 467.50 + tax: 37.40 + total: 504.90 + purchase_order: + po_number: "PO-2024-0600" + vendor: "OfficeMax Direct" + date: "2024-06-25" + line_items: + - description: "Stapler heavy duty" + quantity: 15 + unit_price: 20.00 + total: 300.00 + - description: "Whiteboard marker set" + quantity: 25 + unit_price: 5.50 + total: 137.50 + goods_receipt: + receipt_number: "GR-2024-0350" + date: "2024-07-03" + received_items: + - description: "Stapler heavy duty" + quantity_received: 14 + - description: "Whiteboard marker set" + quantity_received: 25 + gl_codes: + category_to_account: + office_supplies: "GL-5100" + caller: + answers: + agent_task.invoice-three-way-match.output: + prep_brief: + approval_status: "conditional" + matched_lines: + - line_number: 1 + description: "Stapler heavy duty" + invoice_amount: 330.00 + po_amount: 300.00 + receipt_qty: 14 + match_status: "price_mismatch" + gl_account: "GL-5100" + - line_number: 2 + description: "Whiteboard marker set" + invoice_amount: 137.50 + po_amount: 137.50 + receipt_qty: 25 + match_status: "matched" + gl_account: "GL-5100" + exceptions: + - type: "price_mismatch" + line_number: 1 + description: "Stapler heavy duty" + expected: "$20.00 per unit (PO)" + actual: "$22.00 per unit (invoice)" + severity: "medium" + - type: "quantity_mismatch" + line_number: 1 + description: "Stapler heavy duty" + expected: "15 received (invoice qty)" + actual: "14 received (goods receipt)" + severity: "medium" + total_matched_amount: 137.50 + total_exception_amount: 330.00 + gl_summary: + - account: "GL-5100" + description: "Office supplies" + amount: 467.50 + approval_recommendation: "Conditional approval recommended. Stapler heavy duty has price variance and quantity discrepancy. Whiteboard markers fully matched. Contact vendor for price correction." + expect: + status: sealed + receipt: + schema: runx.receipt.v1 + + - name: invoice-three-way-missing-po + inputs: + meeting_context: + invoice: + vendor: "Unknown Vendor LLC" + invoice_number: "INV-2024-3003" + date: "2024-07-10" + due_date: "2024-08-09" + line_items: + - description: "Server rack mount kit" + quantity: 2 + unit_price: 450.00 + total: 900.00 + category: "hardware" + subtotal: 900.00 + tax: 72.00 + total: 972.00 + purchase_order: + po_number: "PO-2024-9999" + vendor: "Unknown Vendor LLC" + date: "2024-07-01" + line_items: + - description: "Server rack mount kit" + quantity: 2 + unit_price: 450.00 + total: 900.00 + goods_receipt: + receipt_number: "GR-2024-0400" + date: "2024-07-08" + received_items: + - description: "Server rack mount kit" + quantity_received: 0 + gl_codes: + category_to_account: + office_supplies: "GL-5100" + caller: + answers: + agent_task.invoice-three-way-match.output: + prep_brief: + approval_status: "rejected" + matched_lines: + - line_number: 1 + description: "Server rack mount kit" + invoice_amount: 900.00 + po_amount: 900.00 + receipt_qty: 0 + match_status: "quantity_mismatch" + gl_account: "unmapped" + exceptions: + - type: "quantity_mismatch" + line_number: 1 + description: "Server rack mount kit" + expected: "2 received (PO qty)" + actual: "0 received (goods receipt)" + severity: "high" + - type: "category_unmapped" + line_number: 1 + description: "Server rack mount kit" + expected: "GL code for category 'hardware'" + actual: "no mapping found" + severity: "high" + total_matched_amount: 0 + total_exception_amount: 900.00 + gl_summary: [] + approval_recommendation: "Payment rejected. Goods receipt shows 0 units received and category 'hardware' has no GL mapping. Hold until receipt confirmed and GL coding provided." + expect: + status: sealed + receipt: + schema: runx.receipt.v1 + +runners: + invoice-three-way-match: + default: true + type: agent-task + agent: business + task: invoice-three-way-match + inputs: + meeting_context: + type: object + required: true + description: | + Invoice data, purchase order, goods receipt, and GL code mappings. + Fields: invoice (vendor, invoice_number, date, line_items with description/quantity/unit_price/total/category), + purchase_order (po_number, vendor, line_items), + goods_receipt (receipt_number, received_items), + gl_codes (category_to_account mapping). + outputs: + prep_brief: object + artifacts: + wrap_as: prep_brief_packet + packet: runx.invoice_three_way_match.v1 + runx: + category: business diff --git a/skills/invoice-three-way-match/fixtures/full-match/input.json b/skills/invoice-three-way-match/fixtures/full-match/input.json new file mode 100644 index 00000000..0d95575d --- /dev/null +++ b/skills/invoice-three-way-match/fixtures/full-match/input.json @@ -0,0 +1,40 @@ +{ + "meeting_context": { + "invoice": { + "vendor": "TechParts Inc.", + "invoice_number": "INV-2024-1001", + "date": "2024-07-01", + "due_date": "2024-07-30", + "line_items": [ + { "description": "USB-C hub 7-in-1", "quantity": 20, "unit_price": 25.00, "total": 500.00, "category": "electronics" }, + { "description": "HDMI cable 3m", "quantity": 30, "unit_price": 8.00, "total": 240.00, "category": "cables" } + ], + "subtotal": 740.00, + "tax": 59.20, + "total": 799.20 + }, + "purchase_order": { + "po_number": "PO-2024-0500", + "vendor": "TechParts Inc.", + "date": "2024-06-20", + "line_items": [ + { "description": "USB-C hub 7-in-1", "quantity": 20, "unit_price": 25.00, "total": 500.00 }, + { "description": "HDMI cable 3m", "quantity": 30, "unit_price": 8.00, "total": 240.00 } + ] + }, + "goods_receipt": { + "receipt_number": "GR-2024-0300", + "date": "2024-06-28", + "received_items": [ + { "description": "USB-C hub 7-in-1", "quantity_received": 20 }, + { "description": "HDMI cable 3m", "quantity_received": 30 } + ] + }, + "gl_codes": { + "category_to_account": { + "electronics": "GL-5300", + "cables": "GL-5305" + } + } + } +} diff --git a/skills/invoice-three-way-match/fixtures/full-match/output.json b/skills/invoice-three-way-match/fixtures/full-match/output.json new file mode 100644 index 00000000..9990d9c8 --- /dev/null +++ b/skills/invoice-three-way-match/fixtures/full-match/output.json @@ -0,0 +1,17 @@ +{ + "prep_brief": { + "approval_status": "approved", + "matched_lines": [ + { "line_number": 1, "description": "USB-C hub 7-in-1", "invoice_amount": 500.00, "po_amount": 500.00, "receipt_qty": 20, "match_status": "matched", "gl_account": "GL-5300" }, + { "line_number": 2, "description": "HDMI cable 3m", "invoice_amount": 240.00, "po_amount": 240.00, "receipt_qty": 30, "match_status": "matched", "gl_account": "GL-5305" } + ], + "exceptions": [], + "total_matched_amount": 740.00, + "total_exception_amount": 0, + "gl_summary": [ + { "account": "GL-5300", "description": "Electronics", "amount": 500.00 }, + { "account": "GL-5305", "description": "Cables", "amount": 240.00 } + ], + "approval_recommendation": "Full approval recommended. All three-way match criteria satisfied. Invoice total $799.20 including tax matches PO and goods receipt. No discrepancies found." + } +} diff --git a/skills/invoice-three-way-match/fixtures/missing-po/input.json b/skills/invoice-three-way-match/fixtures/missing-po/input.json new file mode 100644 index 00000000..2f8c59fe --- /dev/null +++ b/skills/invoice-three-way-match/fixtures/missing-po/input.json @@ -0,0 +1,36 @@ +{ + "meeting_context": { + "invoice": { + "vendor": "Unknown Vendor LLC", + "invoice_number": "INV-2024-3003", + "date": "2024-07-10", + "due_date": "2024-08-09", + "line_items": [ + { "description": "Server rack mount kit", "quantity": 2, "unit_price": 450.00, "total": 900.00, "category": "hardware" } + ], + "subtotal": 900.00, + "tax": 72.00, + "total": 972.00 + }, + "purchase_order": { + "po_number": "PO-2024-9999", + "vendor": "Unknown Vendor LLC", + "date": "2024-07-01", + "line_items": [ + { "description": "Server rack mount kit", "quantity": 2, "unit_price": 450.00, "total": 900.00 } + ] + }, + "goods_receipt": { + "receipt_number": "GR-2024-0400", + "date": "2024-07-08", + "received_items": [ + { "description": "Server rack mount kit", "quantity_received": 0 } + ] + }, + "gl_codes": { + "category_to_account": { + "office_supplies": "GL-5100" + } + } + } +} diff --git a/skills/invoice-three-way-match/fixtures/missing-po/output.json b/skills/invoice-three-way-match/fixtures/missing-po/output.json new file mode 100644 index 00000000..04648c52 --- /dev/null +++ b/skills/invoice-three-way-match/fixtures/missing-po/output.json @@ -0,0 +1,16 @@ +{ + "prep_brief": { + "approval_status": "rejected", + "matched_lines": [ + { "line_number": 1, "description": "Server rack mount kit", "invoice_amount": 900.00, "po_amount": 900.00, "receipt_qty": 0, "match_status": "quantity_mismatch", "gl_account": "unmapped" } + ], + "exceptions": [ + { "type": "quantity_mismatch", "line_number": 1, "description": "Server rack mount kit", "expected": "2 received (PO qty)", "actual": "0 received (goods receipt)", "severity": "high" }, + { "type": "category_unmapped", "line_number": 1, "description": "Server rack mount kit", "expected": "GL code for category 'hardware'", "actual": "no mapping found", "severity": "high" } + ], + "total_matched_amount": 0, + "total_exception_amount": 900.00, + "gl_summary": [], + "approval_recommendation": "Payment rejected. The goods receipt shows 0 units received for server rack mount kit, and the category 'hardware' has no GL account mapping. Hold payment until goods receipt is confirmed and GL coding is provided." + } +} diff --git a/skills/invoice-three-way-match/fixtures/partial-exception/input.json b/skills/invoice-three-way-match/fixtures/partial-exception/input.json new file mode 100644 index 00000000..60437a45 --- /dev/null +++ b/skills/invoice-three-way-match/fixtures/partial-exception/input.json @@ -0,0 +1,40 @@ +{ + "meeting_context": { + "invoice": { + "vendor": "OfficeMax Direct", + "invoice_number": "INV-2024-2002", + "date": "2024-07-05", + "due_date": "2024-08-04", + "line_items": [ + { "description": "Stapler heavy duty", "quantity": 15, "unit_price": 22.00, "total": 330.00, "category": "office_supplies" }, + { "description": "Whiteboard marker set", "quantity": 25, "unit_price": 5.50, "total": 137.50, "category": "office_supplies" } + ], + "subtotal": 467.50, + "tax": 37.40, + "total": 504.90 + }, + "purchase_order": { + "po_number": "PO-2024-0600", + "vendor": "OfficeMax Direct", + "date": "2024-06-25", + "line_items": [ + { "description": "Stapler heavy duty", "quantity": 15, "unit_price": 20.00, "total": 300.00 }, + { "description": "Whiteboard marker set", "quantity": 25, "unit_price": 5.50, "total": 137.50 } + ] + }, + "goods_receipt": { + "receipt_number": "GR-2024-0350", + "date": "2024-07-03", + "received_items": [ + { "description": "Stapler heavy duty", "quantity_received": 14 }, + { "description": "Whiteboard marker set", "quantity_received": 25 } + ] + }, + "gl_codes": { + "category_to_account": { + "office_supplies": "GL-5100", + "furniture": "GL-5200" + } + } + } +} diff --git a/skills/invoice-three-way-match/fixtures/partial-exception/output.json b/skills/invoice-three-way-match/fixtures/partial-exception/output.json new file mode 100644 index 00000000..27420d79 --- /dev/null +++ b/skills/invoice-three-way-match/fixtures/partial-exception/output.json @@ -0,0 +1,19 @@ +{ + "prep_brief": { + "approval_status": "conditional", + "matched_lines": [ + { "line_number": 1, "description": "Stapler heavy duty", "invoice_amount": 330.00, "po_amount": 300.00, "receipt_qty": 14, "match_status": "price_mismatch", "gl_account": "GL-5100" }, + { "line_number": 2, "description": "Whiteboard marker set", "invoice_amount": 137.50, "po_amount": 137.50, "receipt_qty": 25, "match_status": "matched", "gl_account": "GL-5100" } + ], + "exceptions": [ + { "type": "price_mismatch", "line_number": 1, "description": "Stapler heavy duty", "expected": "$20.00 per unit (PO)", "actual": "$22.00 per unit (invoice)", "severity": "medium" }, + { "type": "quantity_mismatch", "line_number": 1, "description": "Stapler heavy duty", "expected": "15 received (invoice qty)", "actual": "14 received (goods receipt)", "severity": "medium" } + ], + "total_matched_amount": 137.50, + "total_exception_amount": 330.00, + "gl_summary": [ + { "account": "GL-5100", "description": "Office supplies", "amount": 467.50 } + ], + "approval_recommendation": "Conditional approval recommended. Stapler heavy duty has a $2.00/unit price variance (10%) and quantity short by 1 unit. Whiteboard markers fully matched. Recommend contacting vendor for price correction and confirming receipt discrepancy." + } +}