| """
|
| Round 2 hard-mode task slice for InvoiceGuard.
|
|
|
| These 10 tasks are designed for a *strong gap* baseline (~40-55%) so that
|
| RL training improvement is visible. Each task targets one of the Round 2
|
| themes: cross-case fraud, time-dependent policy, contradictory evidence,
|
| partial observability, multi-party approvals.
|
|
|
| All tasks reuse the existing CaseData entities so no schema changes are
|
| required. Adversarial context is conveyed via:
|
| - invoice.note
|
| - po.payment_terms
|
| - grn.warehouse_note
|
| - vendor_profile fields
|
| - case_history.prior_comments (surfaced by check_for_duplicate_invoice
|
| when similar_invoice_refs is non-empty)
|
| """
|
|
|
| from typing import Dict
|
|
|
| try:
|
| from ..models import (
|
| CaseData, CaseHistory, CompanyPolicy, DecisionType, Difficulty,
|
| ExceptionType, GRNLineItem, GoodsReceiptNote, GroundTruth,
|
| Invoice, InvoiceLineItem, POLineItem, PurchaseOrder,
|
| TaskID, VendorProfile,
|
| )
|
| except ImportError:
|
| from models import (
|
| CaseData, CaseHistory, CompanyPolicy, DecisionType, Difficulty,
|
| ExceptionType, GRNLineItem, GoodsReceiptNote, GroundTruth,
|
| Invoice, InvoiceLineItem, POLineItem, PurchaseOrder,
|
| TaskID, VendorProfile,
|
| )
|
|
|
|
|
|
|
|
|
| HARD_MAX_STEPS = 12
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_h1() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-H1-001",
|
| task_id=TaskID.task_h1_phantom_grn_period,
|
| difficulty=Difficulty.hard,
|
| max_steps=HARD_MAX_STEPS,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-9101",
|
| supplier_name="Helix Industrial Supply",
|
| supplier_id="SUP-H101",
|
| invoice_date="2024-12-22",
|
| po_reference="PO-H101-DEC",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-HX01",
|
| description="Industrial Lubricant 20L Drum",
|
| quantity_billed=100,
|
| unit_price_billed=180.00,
|
| line_total_billed=18000.00,
|
| ),
|
| ],
|
| subtotal=18000.00,
|
| tax=1440.00,
|
| total_amount=19440.00,
|
| note="Q4 restocking shipment. Please process per contract.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-H101-DEC",
|
| supplier_id="SUP-H101",
|
| order_date="2024-12-01",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-HX01",
|
| description="Industrial Lubricant 20L Drum",
|
| ordered_quantity=100,
|
| unit_price_ordered=180.00,
|
| line_total_ordered=18000.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-H101-JUN",
|
| po_reference="PO-H101-DEC",
|
| receipt_date="2024-06-15",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-HX01",
|
| quantity_received=100,
|
| accepted_quantity=100,
|
| ),
|
| ],
|
| warehouse_note=(
|
| "WAREHOUSE FLAG: GRN-H101-JUN dated 2024-06-15 belongs to "
|
| "prior shipment cycle (PO-H101-JUN, already invoiced and paid). "
|
| "No fresh delivery has been logged against PO-H101-DEC. "
|
| "Linkage to PO-H101-DEC appears to be a clerical error by vendor."
|
| ),
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-H101",
|
| supplier_name="Helix Industrial Supply",
|
| risk_tier="medium",
|
| duplicate_risk_count=2,
|
| preferred_vendor=False,
|
| escalation_threshold=15000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=200.0,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "PO-H101-JUN was fully received (GRN-H101-JUN) and paid in July 2024.",
|
| "Vendor has previously attached old GRN numbers to new POs to "
|
| "accelerate payment before goods arrive.",
|
| ],
|
| similar_invoice_refs=["INV-2024-4500"],
|
| processed_invoice_numbers=["INV-2024-4500"],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.place_on_hold,
|
| correct_exception_type=ExceptionType.missing_receipt,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "check_for_duplicate_invoice",
|
| "inspect_vendor_profile",
|
| ],
|
| key_findings=[
|
| "GRN attached is dated 2024-06-15, predating PO-H101-DEC by 6 months",
|
| "GRN-H101-JUN was already consumed by prior invoice INV-2024-4500",
|
| "No fresh receipt exists for the December order",
|
| "Cannot pay before goods are actually received",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_h2() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-H2-001",
|
| task_id=TaskID.task_h2_kickback_inflated_po,
|
| difficulty=Difficulty.hard,
|
| max_steps=HARD_MAX_STEPS,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-9202",
|
| supplier_name="Crestwave Engineering Pvt Ltd",
|
| supplier_id="SUP-H202",
|
| invoice_date="2024-12-19",
|
| po_reference="PO-H202",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-CW20",
|
| description="Custom Aluminum Bracket Type-7",
|
| quantity_billed=400,
|
| unit_price_billed=85.00,
|
| line_total_billed=34000.00,
|
| ),
|
| ],
|
| subtotal=34000.00,
|
| tax=2720.00,
|
| total_amount=36720.00,
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-H202",
|
| supplier_id="SUP-H202",
|
| order_date="2024-11-10",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-CW20",
|
| description="Custom Aluminum Bracket Type-7",
|
| ordered_quantity=400,
|
| unit_price_ordered=85.00,
|
| line_total_ordered=34000.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-H202",
|
| po_reference="PO-H202",
|
| receipt_date="2024-12-12",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-CW20",
|
| quantity_received=400,
|
| accepted_quantity=400,
|
| ),
|
| ],
|
| warehouse_note="All units received and inspected.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-H202",
|
| supplier_name="Crestwave Engineering Pvt Ltd",
|
| risk_tier="medium",
|
| duplicate_risk_count=0,
|
| preferred_vendor=False,
|
| escalation_threshold=30000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=300.0,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "AUDIT FLAG (2024-12-15): PO-H202 unit price $85 is approx 30% "
|
| "above benchmarked market price of $65 for ITEM-CW20.",
|
| "Buyer who approved PO-H202 has been recused pending integrity review.",
|
| "Per policy, all invoices against PO-H202 require supervisor review "
|
| "before payment release.",
|
| ],
|
| similar_invoice_refs=["AUDIT-PO-H202"],
|
| processed_invoice_numbers=[],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.escalate_for_supervisor_review,
|
| correct_exception_type=ExceptionType.policy_violation,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "check_for_duplicate_invoice",
|
| "inspect_vendor_profile",
|
| "inspect_policy_rules",
|
| ],
|
| key_findings=[
|
| "Invoice and PO numerically match, but PO itself is under audit",
|
| "PO unit price is ~30% above market benchmark",
|
| "Approving buyer recused; mandatory supervisor review applies",
|
| "Escalation required regardless of line-level match",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_h3() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-H3-001",
|
| task_id=TaskID.task_h3_currency_silent_swap,
|
| difficulty=Difficulty.hard,
|
| max_steps=HARD_MAX_STEPS,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-9303",
|
| supplier_name="Northbridge Components GmbH",
|
| supplier_id="SUP-H303",
|
| invoice_date="2024-12-17",
|
| currency="EUR",
|
| po_reference="PO-H303",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-NB15",
|
| description="Precision Linear Actuator 200mm",
|
| quantity_billed=80,
|
| unit_price_billed=125.00,
|
| line_total_billed=10000.00,
|
| ),
|
| ],
|
| subtotal=10000.00,
|
| tax=800.00,
|
| total_amount=10800.00,
|
| note="Standard monthly invoice. EUR billing per updated contract.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-H303",
|
| supplier_id="SUP-H303",
|
| order_date="2024-11-20",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-NB15",
|
| description="Precision Linear Actuator 200mm",
|
| ordered_quantity=80,
|
| unit_price_ordered=125.00,
|
| line_total_ordered=10000.00,
|
| ),
|
| ],
|
| payment_terms="Net 30 USD",
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-H303",
|
| po_reference="PO-H303",
|
| receipt_date="2024-12-10",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-NB15",
|
| quantity_received=80,
|
| accepted_quantity=80,
|
| ),
|
| ],
|
| warehouse_note="All units received in good condition.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-H303",
|
| supplier_name="Northbridge Components GmbH",
|
| risk_tier="medium",
|
| preferred_vendor=True,
|
| escalation_threshold=12000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=200.0,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "Vendor SUP-H303 has historically invoiced in USD against this PO family.",
|
| "No contract amendment authorizing EUR billing is on file.",
|
| "Current EUR-to-USD rate would make invoiced amount ~10% higher than PO USD value.",
|
| ],
|
| similar_invoice_refs=["INV-2024-7800"],
|
| processed_invoice_numbers=["INV-2024-7800"],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.escalate_for_supervisor_review,
|
| correct_exception_type=ExceptionType.total_amount_mismatch,
|
| acceptable_evidence=[
|
| "inspect_invoice_line_items",
|
| "inspect_purchase_order",
|
| "check_for_duplicate_invoice",
|
| "compare_totals",
|
| ],
|
| key_findings=[
|
| "Invoice currency is EUR but PO is USD (no contract amendment)",
|
| "Numerical line totals match but currency differs",
|
| "USD-equivalent of EUR invoice is materially above PO total",
|
| "Currency change requires supervisor approval per contract",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_h4() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-H4-001",
|
| task_id=TaskID.task_h4_threshold_dance,
|
| difficulty=Difficulty.hard,
|
| max_steps=HARD_MAX_STEPS,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-9404",
|
| supplier_name="Vector Distribution Co",
|
| supplier_id="SUP-H404",
|
| invoice_date="2024-12-21",
|
| po_reference="PO-H404-D",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-VD30",
|
| description="Bulk Packaging Material Lot",
|
| quantity_billed=1,
|
| unit_price_billed=49950.00,
|
| line_total_billed=49950.00,
|
| ),
|
| ],
|
| subtotal=49950.00,
|
| tax=3996.00,
|
| total_amount=53946.00,
|
| note="Final delivery for Q4 packaging contract.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-H404-D",
|
| supplier_id="SUP-H404",
|
| order_date="2024-12-05",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-VD30",
|
| description="Bulk Packaging Material Lot",
|
| ordered_quantity=1,
|
| unit_price_ordered=49950.00,
|
| line_total_ordered=49950.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-H404-D",
|
| po_reference="PO-H404-D",
|
| receipt_date="2024-12-18",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-VD30",
|
| quantity_received=1,
|
| accepted_quantity=1,
|
| ),
|
| ],
|
| warehouse_note="Full lot received.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-H404",
|
| supplier_name="Vector Distribution Co",
|
| risk_tier="high",
|
| duplicate_risk_count=3,
|
| preferred_vendor=False,
|
| escalation_threshold=40000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=300.0,
|
| high_value_threshold=50000.0,
|
| mandatory_escalation_above=100000.0,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "ALERT: SUP-H404 submitted 3 invoices in past 14 days at "
|
| "$49,920 / $49,975 / $49,950 -- each just under $50k threshold.",
|
| "Combined invoiced value across 4 invoices: ~$199,795.",
|
| "PO numbering pattern (PO-H404-A/B/C/D) suggests deliberate split.",
|
| "Finance integrity team flagged for review.",
|
| ],
|
| similar_invoice_refs=["INV-2024-9401", "INV-2024-9402", "INV-2024-9403"],
|
| processed_invoice_numbers=["INV-2024-9401", "INV-2024-9402", "INV-2024-9403"],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.escalate_for_supervisor_review,
|
| correct_exception_type=ExceptionType.policy_violation,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "check_for_duplicate_invoice",
|
| "inspect_vendor_profile",
|
| "inspect_policy_rules",
|
| ],
|
| key_findings=[
|
| "Invoice $49,950 sits $50 under auto-approval threshold",
|
| "3 prior invoices from same vendor in past 14 days, all just under $50k",
|
| "Combined value ~$199,795 well above mandatory escalation",
|
| "High-risk vendor with 3 prior incidents",
|
| "Pattern consistent with deliberate threshold evasion",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_h5() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-H5-001",
|
| task_id=TaskID.task_h5_retroactive_amendment,
|
| difficulty=Difficulty.hard,
|
| max_steps=HARD_MAX_STEPS,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-9505",
|
| supplier_name="Solace Pharma Distribution",
|
| supplier_id="SUP-H505",
|
| invoice_date="2024-12-20",
|
| po_reference="PO-H505",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-SP40",
|
| description="Diagnostic Reagent Kit Pro",
|
| quantity_billed=300,
|
| unit_price_billed=100.00,
|
| line_total_billed=30000.00,
|
| ),
|
| ],
|
| subtotal=30000.00,
|
| tax=2400.00,
|
| total_amount=32400.00,
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-H505",
|
| supplier_id="SUP-H505",
|
| order_date="2024-11-05",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-SP40",
|
| description="Diagnostic Reagent Kit Pro",
|
| ordered_quantity=300,
|
| unit_price_ordered=100.00,
|
| line_total_ordered=30000.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-H505",
|
| po_reference="PO-H505",
|
| receipt_date="2024-12-12",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-SP40",
|
| quantity_received=300,
|
| accepted_quantity=300,
|
| ),
|
| ],
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-H505",
|
| supplier_name="Solace Pharma Distribution",
|
| risk_tier="medium",
|
| preferred_vendor=True,
|
| escalation_threshold=25000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=300.0,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "PO-H505 Amendment 1 (2024-12-08): unit price retroactively reduced "
|
| "from $100 to $80 per kit as part of annual rebate true-up.",
|
| "Amendment is binding for all invoices dated after 2024-12-08.",
|
| "Vendor was notified in writing on 2024-12-09 and acknowledged.",
|
| "Effective PO total is now $24,000, not $30,000.",
|
| ],
|
| similar_invoice_refs=["AMENDMENT-PO-H505"],
|
| processed_invoice_numbers=[],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.escalate_for_supervisor_review,
|
| correct_exception_type=ExceptionType.price_mismatch,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "check_for_duplicate_invoice",
|
| "compare_price",
|
| "inspect_policy_rules",
|
| ],
|
| key_findings=[
|
| "PO line items show $100, invoice shows $100 -- looks aligned",
|
| "PO Amendment 1 retroactively set agreed price to $80",
|
| "Effective overcharge: $20 x 300 = $6,000",
|
| "Supervisor must reconcile invoice against amended PO",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_h6() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-H6-001",
|
| task_id=TaskID.task_h6_returned_then_rebilled,
|
| difficulty=Difficulty.hard,
|
| max_steps=HARD_MAX_STEPS,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-9606",
|
| supplier_name="Ironclad Hardware Co",
|
| supplier_id="SUP-H606",
|
| invoice_date="2024-12-22",
|
| po_reference="PO-H606",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-IH50",
|
| description="Heavy-Duty Steel Coupling Set",
|
| quantity_billed=100,
|
| unit_price_billed=220.00,
|
| line_total_billed=22000.00,
|
| ),
|
| ],
|
| subtotal=22000.00,
|
| tax=1760.00,
|
| total_amount=23760.00,
|
| note="Full shipment billing. Per delivery receipt.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-H606",
|
| supplier_id="SUP-H606",
|
| order_date="2024-11-15",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-IH50",
|
| description="Heavy-Duty Steel Coupling Set",
|
| ordered_quantity=100,
|
| unit_price_ordered=220.00,
|
| line_total_ordered=22000.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-H606",
|
| po_reference="PO-H606",
|
| receipt_date="2024-12-05",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-IH50",
|
| quantity_received=100,
|
| accepted_quantity=100,
|
| ),
|
| ],
|
| warehouse_note=(
|
| "POST-RECEIPT NOTE (2024-12-15): 30 units returned to vendor "
|
| "due to QC failure (cracked welds). Net accepted in inventory: 70. "
|
| "Return Material Authorization RMA-H606-01 issued."
|
| ),
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-H606",
|
| supplier_name="Ironclad Hardware Co",
|
| risk_tier="medium",
|
| preferred_vendor=True,
|
| escalation_threshold=20000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=200.0,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "RMA-H606-01 (2024-12-15): 30 units of ITEM-IH50 returned for QC failure.",
|
| "Vendor acknowledged return and issued credit memo CM-H606-01.",
|
| "Net deliverable for this PO: 70 units at $220 = $15,400.",
|
| "Vendor invoiced full 100 units, ignoring credit memo.",
|
| ],
|
| similar_invoice_refs=["RMA-H606-01"],
|
| processed_invoice_numbers=[],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.place_on_hold,
|
| correct_exception_type=ExceptionType.quantity_mismatch,
|
| acceptable_evidence=[
|
| "inspect_goods_receipt_note",
|
| "check_for_duplicate_invoice",
|
| "compare_quantity",
|
| ],
|
| key_findings=[
|
| "GRN shows 100 accepted at receipt, but 30 were returned post-receipt",
|
| "Net inventory accepted is 70 units, not 100",
|
| "Vendor issued credit memo CM-H606-01 acknowledging return",
|
| "Invoice bills 100 units, ignoring the credit memo",
|
| "Hold required until vendor reissues with credit applied",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_h7() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-H7-001",
|
| task_id=TaskID.task_h7_multi_party_pending,
|
| difficulty=Difficulty.hard,
|
| max_steps=HARD_MAX_STEPS,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-9707",
|
| supplier_name="Skyline Capital Equipment",
|
| supplier_id="SUP-H707",
|
| invoice_date="2024-12-21",
|
| po_reference="PO-H707",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-SK60",
|
| description="Industrial Compressor Unit Model X",
|
| quantity_billed=1,
|
| unit_price_billed=85000.00,
|
| line_total_billed=85000.00,
|
| ),
|
| ],
|
| subtotal=85000.00,
|
| tax=6800.00,
|
| total_amount=91800.00,
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-H707",
|
| supplier_id="SUP-H707",
|
| order_date="2024-11-25",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-SK60",
|
| description="Industrial Compressor Unit Model X",
|
| ordered_quantity=1,
|
| unit_price_ordered=85000.00,
|
| line_total_ordered=85000.00,
|
| ),
|
| ],
|
| payment_terms="Net 45",
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-H707",
|
| po_reference="PO-H707",
|
| receipt_date="2024-12-15",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-SK60",
|
| quantity_received=1,
|
| accepted_quantity=1,
|
| ),
|
| ],
|
| warehouse_note="Unit installed and commissioned successfully.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-H707",
|
| supplier_name="Skyline Capital Equipment",
|
| risk_tier="low",
|
| preferred_vendor=True,
|
| escalation_threshold=70000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=500.0,
|
| high_value_threshold=50000.0,
|
| mandatory_escalation_above=80000.0,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "Capex policy: invoices >= $80,000 require BOTH supervisor and CFO sign-off.",
|
| "PO-H707 has supervisor sign-off (S. Patel, 2024-11-25).",
|
| "CFO sign-off NOT on file; capex committee meets 2024-12-28.",
|
| "Payment must wait for CFO approval per controls policy.",
|
| ],
|
| similar_invoice_refs=["CAPEX-POLICY-2024"],
|
| processed_invoice_numbers=[],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.escalate_for_supervisor_review,
|
| correct_exception_type=ExceptionType.policy_violation,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_policy_rules",
|
| "check_for_duplicate_invoice",
|
| "inspect_vendor_profile",
|
| ],
|
| key_findings=[
|
| "Invoice total $91,800 exceeds mandatory escalation threshold $80,000",
|
| "Capex policy requires both supervisor AND CFO sign-off above $80k",
|
| "Only supervisor sign-off currently on file",
|
| "Payment cannot be released until CFO approval logged",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_h8() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-H8-001",
|
| task_id=TaskID.task_h8_rush_premium_authorized,
|
| difficulty=Difficulty.hard,
|
| max_steps=HARD_MAX_STEPS,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-9808",
|
| supplier_name="Falcon Express Components",
|
| supplier_id="SUP-H808",
|
| invoice_date="2024-12-20",
|
| po_reference="PO-H808",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-FE70",
|
| description="Aviation-Grade Fastener Pack",
|
| quantity_billed=200,
|
| unit_price_billed=54.00,
|
| line_total_billed=10800.00,
|
| ),
|
| ],
|
| subtotal=10800.00,
|
| tax=864.00,
|
| total_amount=11664.00,
|
| note=(
|
| "Includes 8% rush surcharge per PO-H808 Amendment 1 dated 2024-12-05 "
|
| "(buyer-approved expedited shipping). Base price unchanged at $50.00."
|
| ),
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-H808",
|
| supplier_id="SUP-H808",
|
| order_date="2024-12-01",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-FE70",
|
| description="Aviation-Grade Fastener Pack",
|
| ordered_quantity=200,
|
| unit_price_ordered=50.00,
|
| line_total_ordered=10000.00,
|
| ),
|
| ],
|
| payment_terms="Net 30",
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-H808",
|
| po_reference="PO-H808",
|
| receipt_date="2024-12-12",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-FE70",
|
| quantity_received=200,
|
| accepted_quantity=200,
|
| ),
|
| ],
|
| warehouse_note=(
|
| "Expedited delivery received per buyer's rush request. "
|
| "8% surcharge authorized in PO-H808 Amendment 1."
|
| ),
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-H808",
|
| supplier_name="Falcon Express Components",
|
| risk_tier="low",
|
| preferred_vendor=True,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=200.0,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "PO-H808 Amendment 1 (2024-12-05): buyer authorized up to 10% rush "
|
| "surcharge for expedited delivery on this order.",
|
| "Expedited shipping was specifically requested due to production line outage.",
|
| "Surcharge of 8% is within authorized range.",
|
| ],
|
| similar_invoice_refs=["PO-H808-AMD1"],
|
| processed_invoice_numbers=[],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.approve_for_payment,
|
| correct_exception_type=ExceptionType.clean_match,
|
| acceptable_evidence=[
|
| "inspect_invoice_line_items",
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "check_for_duplicate_invoice",
|
| ],
|
| key_findings=[
|
| "Unit price $54 vs base PO $50 = 8% above PO line price",
|
| "PO Amendment 1 explicitly authorized up to 10% rush surcharge",
|
| "Surcharge applied is within authorized range",
|
| "Quantities and delivery match exactly",
|
| "Surface price variance is contractually authorized",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_h9() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-H9-001",
|
| task_id=TaskID.task_h9_supplier_id_mismatch,
|
| difficulty=Difficulty.hard,
|
| max_steps=HARD_MAX_STEPS,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-9909",
|
| supplier_name="Acme Industrial Solutions",
|
| supplier_id="SUP-H909-X",
|
| invoice_date="2024-12-22",
|
| po_reference="PO-H909",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-AI80",
|
| description="Industrial Pump Assembly",
|
| quantity_billed=10,
|
| unit_price_billed=2200.00,
|
| line_total_billed=22000.00,
|
| ),
|
| ],
|
| subtotal=22000.00,
|
| tax=1760.00,
|
| total_amount=23760.00,
|
| note="Please remit to updated bank account. Supplier ID corrected per recent re-registration.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-H909",
|
| supplier_id="SUP-H909",
|
| order_date="2024-11-20",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-AI80",
|
| description="Industrial Pump Assembly",
|
| ordered_quantity=10,
|
| unit_price_ordered=2200.00,
|
| line_total_ordered=22000.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-H909",
|
| po_reference="PO-H909",
|
| receipt_date="2024-12-12",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-AI80",
|
| quantity_received=10,
|
| accepted_quantity=10,
|
| ),
|
| ],
|
| warehouse_note="Goods received from original vendor (SUP-H909).",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-H909-X",
|
| supplier_name="Acme Industrial Solutions",
|
| risk_tier="high",
|
| duplicate_risk_count=4,
|
| preferred_vendor=False,
|
| escalation_threshold=5000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=200.0,
|
| duplicate_check_enabled=True,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "FRAUD ALERT: SUP-H909-X is a flagged shell supplier under investigation.",
|
| "Original PO-H909 was issued to legitimate supplier SUP-H909.",
|
| "Goods were received from SUP-H909 (legitimate). Invoice arrived from SUP-H909-X.",
|
| "Bank-redirect attempts have been observed for this supplier family in past 90 days.",
|
| "Reject and refer to fraud team. Do NOT pay SUP-H909-X.",
|
| ],
|
| similar_invoice_refs=["FRAUD-SUP-H909-X"],
|
| processed_invoice_numbers=[],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.reject_invoice,
|
| correct_exception_type=ExceptionType.policy_violation,
|
| acceptable_evidence=[
|
| "inspect_invoice_line_items",
|
| "inspect_purchase_order",
|
| "inspect_vendor_profile",
|
| "check_for_duplicate_invoice",
|
| ],
|
| key_findings=[
|
| "Invoice supplier_id SUP-H909-X does not match PO supplier_id SUP-H909",
|
| "Vendor profile flags SUP-H909-X as high-risk shell supplier under fraud investigation",
|
| "Goods were physically delivered by legitimate SUP-H909 (per GRN note)",
|
| "Invoice attempts to redirect payment to fraud-flagged entity",
|
| "Mandatory rejection and referral to fraud team",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_h10() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-H10-001",
|
| task_id=TaskID.task_h10_cross_case_contradiction,
|
| difficulty=Difficulty.hard,
|
| max_steps=HARD_MAX_STEPS,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-9A10",
|
| supplier_name="Ridgepoint Industrial Corp",
|
| supplier_id="SUP-HA10",
|
| invoice_date="2024-12-22",
|
| po_reference="PO-HA10",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-RP90",
|
| description="Composite Reinforcement Panel",
|
| quantity_billed=100,
|
| unit_price_billed=160.00,
|
| line_total_billed=16000.00,
|
| ),
|
| ],
|
| subtotal=16000.00,
|
| tax=1280.00,
|
| total_amount=17280.00,
|
| note="Final delivery for Q4 build-out. Please process per terms.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-HA10",
|
| supplier_id="SUP-HA10",
|
| order_date="2024-11-18",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-RP90",
|
| description="Composite Reinforcement Panel",
|
| ordered_quantity=100,
|
| unit_price_ordered=160.00,
|
| line_total_ordered=16000.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-HA10",
|
| po_reference="PO-HA10",
|
| receipt_date="2024-12-10",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-RP90",
|
| quantity_received=80,
|
| accepted_quantity=80,
|
| rejected_quantity=0,
|
| ),
|
| ],
|
| warehouse_note="Partial shipment: 20 units short. Backorder pending.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-HA10",
|
| supplier_name="Ridgepoint Industrial Corp",
|
| risk_tier="high",
|
| duplicate_risk_count=3,
|
| preferred_vendor=False,
|
| escalation_threshold=12000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=200.0,
|
| duplicate_check_enabled=True,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "INV-2024-9A05 (similar amount, same PO family) processed 2024-12-08.",
|
| "Vendor flagged for prior duplicate-resubmission incidents.",
|
| "Note: signals point in conflicting directions -- partial receipt suggests "
|
| "hold, but duplicate suspicion suggests reject. Policy escalation hierarchy: "
|
| "ESCALATE supersedes HOLD and REJECT when conflicting signals coexist.",
|
| ],
|
| similar_invoice_refs=["INV-2024-9A05"],
|
| processed_invoice_numbers=["INV-2024-9A05"],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.escalate_for_supervisor_review,
|
| correct_exception_type=ExceptionType.mixed_discrepancy,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "check_for_duplicate_invoice",
|
| "compare_quantity",
|
| "inspect_policy_rules",
|
| "inspect_vendor_profile",
|
| ],
|
| key_findings=[
|
| "Quantity discrepancy: billed 100 vs received 80 (20% short)",
|
| "Possible duplicate: similar invoice INV-2024-9A05 already processed",
|
| "Vendor is high-risk with 3 prior incidents",
|
| "Conflicting signals: hold (partial) vs reject (duplicate)",
|
| "Per policy hierarchy, escalation supersedes both",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
| HARD_TASK_LIST = [
|
| TaskID.task_h1_phantom_grn_period,
|
| TaskID.task_h2_kickback_inflated_po,
|
| TaskID.task_h3_currency_silent_swap,
|
| TaskID.task_h4_threshold_dance,
|
| TaskID.task_h5_retroactive_amendment,
|
| TaskID.task_h6_returned_then_rebilled,
|
| TaskID.task_h7_multi_party_pending,
|
| TaskID.task_h8_rush_premium_authorized,
|
| TaskID.task_h9_supplier_id_mismatch,
|
| TaskID.task_h10_cross_case_contradiction,
|
| ]
|
|
|
|
|
| HARD_TASK_BUILDERS: Dict[TaskID, callable] = {
|
| TaskID.task_h1_phantom_grn_period: _build_h1,
|
| TaskID.task_h2_kickback_inflated_po: _build_h2,
|
| TaskID.task_h3_currency_silent_swap: _build_h3,
|
| TaskID.task_h4_threshold_dance: _build_h4,
|
| TaskID.task_h5_retroactive_amendment: _build_h5,
|
| TaskID.task_h6_returned_then_rebilled: _build_h6,
|
| TaskID.task_h7_multi_party_pending: _build_h7,
|
| TaskID.task_h8_rush_premium_authorized: _build_h8,
|
| TaskID.task_h9_supplier_id_mismatch: _build_h9,
|
| TaskID.task_h10_cross_case_contradiction: _build_h10,
|
| }
|
|
|