| """
|
| Task definitions and synthetic case templates for InvoiceGuard.
|
|
|
| Four tasks with increasing difficulty, each with fully synthetic
|
| business documents and deterministic ground truth.
|
| """
|
|
|
| from typing import Dict, List
|
|
|
| try:
|
| from ..models import (
|
| CaseData, CaseHistory, CompanyPolicy, DecisionType, Difficulty,
|
| ExceptionType, GRNLineItem, GoodsReceiptNote, GroundTruth,
|
| Invoice, InvoiceLineItem, POLineItem, PurchaseOrder,
|
| TaskID, VendorProfile,
|
| )
|
| from .hard_definitions import HARD_TASK_BUILDERS, HARD_TASK_LIST
|
| except ImportError:
|
| from models import (
|
| CaseData, CaseHistory, CompanyPolicy, DecisionType, Difficulty,
|
| ExceptionType, GRNLineItem, GoodsReceiptNote, GroundTruth,
|
| Invoice, InvoiceLineItem, POLineItem, PurchaseOrder,
|
| TaskID, VendorProfile,
|
| )
|
| from tasks.hard_definitions import HARD_TASK_BUILDERS, HARD_TASK_LIST
|
|
|
|
|
| TASK_LIST: List[TaskID] = [
|
| TaskID.task_1_clean_match,
|
| TaskID.task_2_partial_receipt,
|
| TaskID.task_3_price_variance,
|
| TaskID.task_4_duplicate_invoice,
|
| TaskID.task_5_mixed_discrepancy,
|
| TaskID.task_6_false_positive_duplicate,
|
| TaskID.task_7_retroactive_price,
|
| TaskID.task_8_split_invoice_pattern,
|
| TaskID.task_9_clean_from_risky_vendor,
|
| TaskID.task_10_rounding_false_alarm,
|
| TaskID.task_11_authorized_overship,
|
| TaskID.task_12_corrected_resubmission,
|
| ]
|
|
|
| ALL_TASKS: List[TaskID] = [
|
| TaskID.task_1_clean_match,
|
| TaskID.task_1b_multi_line_clean,
|
| TaskID.task_1c_preferred_vendor_clean,
|
| TaskID.task_2_partial_receipt,
|
| TaskID.task_2b_missing_receipt,
|
| TaskID.task_2c_over_receipt,
|
| TaskID.task_3_price_variance,
|
| TaskID.task_3b_within_tolerance,
|
| TaskID.task_3c_total_mismatch,
|
| TaskID.task_4_duplicate_invoice,
|
| TaskID.task_4b_corrected_invoice_trap,
|
| TaskID.task_4c_policy_violation,
|
| TaskID.task_5_mixed_discrepancy,
|
| TaskID.task_6_false_positive_duplicate,
|
| TaskID.task_7_retroactive_price,
|
| TaskID.task_8_split_invoice_pattern,
|
| TaskID.task_9_clean_from_risky_vendor,
|
| TaskID.task_10_rounding_false_alarm,
|
| TaskID.task_11_authorized_overship,
|
| TaskID.task_12_corrected_resubmission,
|
| *HARD_TASK_LIST,
|
| ]
|
|
|
|
|
| def get_task_case(task_id: TaskID) -> CaseData:
|
| """Return the case data for a given task (canonical or variant)."""
|
| builders: Dict[TaskID, callable] = {
|
| TaskID.task_1_clean_match: _build_task_1,
|
| TaskID.task_1b_multi_line_clean: _build_task_1b,
|
| TaskID.task_1c_preferred_vendor_clean: _build_task_1c,
|
| TaskID.task_2_partial_receipt: _build_task_2,
|
| TaskID.task_2b_missing_receipt: _build_task_2b,
|
| TaskID.task_2c_over_receipt: _build_task_2c,
|
| TaskID.task_3_price_variance: _build_task_3,
|
| TaskID.task_3b_within_tolerance: _build_task_3b,
|
| TaskID.task_3c_total_mismatch: _build_task_3c,
|
| TaskID.task_4_duplicate_invoice: _build_task_4,
|
| TaskID.task_4b_corrected_invoice_trap: _build_task_4b,
|
| TaskID.task_4c_policy_violation: _build_task_4c,
|
| TaskID.task_5_mixed_discrepancy: _build_task_5,
|
| TaskID.task_6_false_positive_duplicate: _build_task_6,
|
| TaskID.task_7_retroactive_price: _build_task_7,
|
| TaskID.task_8_split_invoice_pattern: _build_task_8,
|
| TaskID.task_9_clean_from_risky_vendor: _build_task_9,
|
| TaskID.task_10_rounding_false_alarm: _build_task_10,
|
| TaskID.task_11_authorized_overship: _build_task_11,
|
| TaskID.task_12_corrected_resubmission: _build_task_12,
|
| **HARD_TASK_BUILDERS,
|
| }
|
| return builders[task_id]()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_1() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-1001",
|
| task_id=TaskID.task_1_clean_match,
|
| difficulty=Difficulty.easy,
|
| max_steps=10,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0042",
|
| supplier_name="Apex Office Supplies",
|
| supplier_id="SUP-1001",
|
| invoice_date="2024-11-15",
|
| po_reference="PO-5500",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-A01",
|
| description="Premium Copy Paper A4 (500 sheets)",
|
| quantity_billed=100,
|
| unit_price_billed=25.00,
|
| line_total_billed=2500.00,
|
| ),
|
| ],
|
| subtotal=2500.00,
|
| tax=200.00,
|
| total_amount=2700.00,
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-5500",
|
| supplier_id="SUP-1001",
|
| order_date="2024-10-20",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-A01",
|
| description="Premium Copy Paper A4 (500 sheets)",
|
| ordered_quantity=100,
|
| unit_price_ordered=25.00,
|
| line_total_ordered=2500.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-7801",
|
| po_reference="PO-5500",
|
| receipt_date="2024-11-10",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-A01",
|
| quantity_received=100,
|
| accepted_quantity=100,
|
| ),
|
| ],
|
| warehouse_note="All items received in good condition.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-1001",
|
| supplier_name="Apex Office Supplies",
|
| risk_tier="low",
|
| preferred_vendor=True,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=100.0,
|
| ),
|
| case_history=CaseHistory(),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.approve_for_payment,
|
| correct_exception_type=ExceptionType.clean_match,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| ],
|
| key_findings=[
|
| "Quantities match across invoice, PO, and GRN",
|
| "Prices match between invoice and PO",
|
| "No discrepancies detected",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_2() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-2002",
|
| task_id=TaskID.task_2_partial_receipt,
|
| difficulty=Difficulty.moderate,
|
| max_steps=10,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0187",
|
| supplier_name="Delta Industrial Parts",
|
| supplier_id="SUP-2050",
|
| invoice_date="2024-12-01",
|
| po_reference="PO-6200",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-D10",
|
| description="Stainless Steel Bearings (Box of 50)",
|
| quantity_billed=100,
|
| unit_price_billed=50.00,
|
| line_total_billed=5000.00,
|
| ),
|
| ],
|
| subtotal=5000.00,
|
| tax=400.00,
|
| total_amount=5400.00,
|
| note="Please process payment promptly.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-6200",
|
| supplier_id="SUP-2050",
|
| order_date="2024-11-01",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-D10",
|
| description="Stainless Steel Bearings (Box of 50)",
|
| ordered_quantity=100,
|
| unit_price_ordered=50.00,
|
| line_total_ordered=5000.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-8830",
|
| po_reference="PO-6200",
|
| receipt_date="2024-11-25",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-D10",
|
| quantity_received=60,
|
| accepted_quantity=60,
|
| rejected_quantity=0,
|
| ),
|
| ],
|
| warehouse_note="Partial shipment. Remaining 40 units expected next week.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-2050",
|
| supplier_name="Delta Industrial Parts",
|
| risk_tier="medium",
|
| 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=["Supplier has had partial shipments before."],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.place_on_hold,
|
| correct_exception_type=ExceptionType.partial_receipt,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "compare_quantity",
|
| ],
|
| key_findings=[
|
| "Invoice billed 100 units but GRN shows only 60 received",
|
| "Billed quantity exceeds received quantity by 40 units (40%)",
|
| "Variance exceeds quantity tolerance of 5%",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_3() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-3003",
|
| task_id=TaskID.task_3_price_variance,
|
| difficulty=Difficulty.moderate,
|
| max_steps=10,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0315",
|
| supplier_name="Quantum Tech Solutions",
|
| supplier_id="SUP-3100",
|
| invoice_date="2024-12-10",
|
| po_reference="PO-7100",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-Q22",
|
| description="Enterprise SSD 1TB NVMe",
|
| quantity_billed=50,
|
| unit_price_billed=110.00,
|
| line_total_billed=5500.00,
|
| ),
|
| ],
|
| subtotal=5500.00,
|
| tax=440.00,
|
| total_amount=5940.00,
|
| note="Price adjusted due to component shortage surcharge.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-7100",
|
| supplier_id="SUP-3100",
|
| order_date="2024-11-15",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-Q22",
|
| description="Enterprise SSD 1TB NVMe",
|
| ordered_quantity=50,
|
| unit_price_ordered=100.00,
|
| line_total_ordered=5000.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-9150",
|
| po_reference="PO-7100",
|
| receipt_date="2024-12-05",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-Q22",
|
| quantity_received=50,
|
| accepted_quantity=50,
|
| ),
|
| ],
|
| warehouse_note="All units received and tested OK.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-3100",
|
| supplier_name="Quantum Tech Solutions",
|
| risk_tier="medium",
|
| preferred_vendor=True,
|
| escalation_threshold=5000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=200.0,
|
| high_value_threshold=50000.0,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "Supplier occasionally applies surcharges without prior notice.",
|
| ],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.escalate_for_supervisor_review,
|
| correct_exception_type=ExceptionType.price_mismatch,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_policy_rules",
|
| "compare_price",
|
| ],
|
| key_findings=[
|
| "Invoice unit price $110.00 vs PO unit price $100.00",
|
| "Price variance of 10% exceeds company tolerance of 5%",
|
| "Requires supervisor review per escalation policy",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_4() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-4004",
|
| task_id=TaskID.task_4_duplicate_invoice,
|
| difficulty=Difficulty.hard,
|
| max_steps=12,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0512",
|
| supplier_name="Redline Logistics Corp",
|
| supplier_id="SUP-4200",
|
| invoice_date="2024-12-18",
|
| po_reference="PO-8800",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-R05",
|
| description="Heavy-Duty Shipping Pallets",
|
| quantity_billed=200,
|
| unit_price_billed=30.00,
|
| line_total_billed=6000.00,
|
| ),
|
| ],
|
| subtotal=6000.00,
|
| tax=480.00,
|
| total_amount=6480.00,
|
| note="URGENT: Payment overdue. Please expedite. Ref: follow-up to INV-2024-0511.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-8800",
|
| supplier_id="SUP-4200",
|
| order_date="2024-11-20",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-R05",
|
| description="Heavy-Duty Shipping Pallets",
|
| ordered_quantity=200,
|
| unit_price_ordered=30.00,
|
| line_total_ordered=6000.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-9900",
|
| po_reference="PO-8800",
|
| receipt_date="2024-12-12",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-R05",
|
| quantity_received=200,
|
| accepted_quantity=200,
|
| ),
|
| ],
|
| warehouse_note="Full shipment received.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-4200",
|
| supplier_name="Redline Logistics Corp",
|
| risk_tier="high",
|
| duplicate_risk_count=2,
|
| preferred_vendor=False,
|
| escalation_threshold=3000.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=[
|
| "Previous duplicate submission flagged for this supplier in Q3.",
|
| "Supplier has been warned about duplicate invoicing.",
|
| ],
|
| similar_invoice_refs=["INV-2024-0511"],
|
| processed_invoice_numbers=[
|
| "INV-2024-0511",
|
| "INV-2024-0388",
|
| ],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.reject_invoice,
|
| correct_exception_type=ExceptionType.duplicate_invoice,
|
| acceptable_evidence=[
|
| "check_for_duplicate_invoice",
|
| "inspect_vendor_profile",
|
| ],
|
| key_findings=[
|
| "Previously processed INV-2024-0511 has same supplier, same PO, same total",
|
| "Current invoice INV-2024-0512 is sequential to processed INV-2024-0511",
|
| "Supplier flagged as high risk with 2 prior duplicate incidents",
|
| "Invoice note references INV-2024-0511 as 'follow-up'",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_1b() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-1002",
|
| task_id=TaskID.task_1b_multi_line_clean,
|
| difficulty=Difficulty.easy,
|
| max_steps=10,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0099",
|
| supplier_name="Summit Facility Services",
|
| supplier_id="SUP-1050",
|
| invoice_date="2024-11-20",
|
| po_reference="PO-5510",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-F01",
|
| description="Industrial Floor Cleaner 5L",
|
| quantity_billed=20,
|
| unit_price_billed=35.00,
|
| line_total_billed=700.00,
|
| ),
|
| InvoiceLineItem(
|
| item_code="ITEM-F02",
|
| description="Microfiber Mop Heads (Pack of 10)",
|
| quantity_billed=15,
|
| unit_price_billed=18.00,
|
| line_total_billed=270.00,
|
| ),
|
| InvoiceLineItem(
|
| item_code="ITEM-F03",
|
| description="Nitrile Gloves Box (100ct)",
|
| quantity_billed=50,
|
| unit_price_billed=12.00,
|
| line_total_billed=600.00,
|
| ),
|
| ],
|
| subtotal=1570.00,
|
| tax=125.60,
|
| total_amount=1695.60,
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-5510",
|
| supplier_id="SUP-1050",
|
| order_date="2024-10-25",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-F01",
|
| description="Industrial Floor Cleaner 5L",
|
| ordered_quantity=20,
|
| unit_price_ordered=35.00,
|
| line_total_ordered=700.00,
|
| ),
|
| POLineItem(
|
| item_code="ITEM-F02",
|
| description="Microfiber Mop Heads (Pack of 10)",
|
| ordered_quantity=15,
|
| unit_price_ordered=18.00,
|
| line_total_ordered=270.00,
|
| ),
|
| POLineItem(
|
| item_code="ITEM-F03",
|
| description="Nitrile Gloves Box (100ct)",
|
| ordered_quantity=50,
|
| unit_price_ordered=12.00,
|
| line_total_ordered=600.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-7820",
|
| po_reference="PO-5510",
|
| receipt_date="2024-11-15",
|
| line_items=[
|
| GRNLineItem(item_code="ITEM-F01", quantity_received=20, accepted_quantity=20),
|
| GRNLineItem(item_code="ITEM-F02", quantity_received=15, accepted_quantity=15),
|
| GRNLineItem(item_code="ITEM-F03", quantity_received=50, accepted_quantity=50),
|
| ],
|
| warehouse_note="All items received, inspected, shelved.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-1050",
|
| supplier_name="Summit Facility Services",
|
| risk_tier="low",
|
| preferred_vendor=True,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=100.0,
|
| ),
|
| case_history=CaseHistory(),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.approve_for_payment,
|
| correct_exception_type=ExceptionType.clean_match,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| ],
|
| key_findings=[
|
| "All 3 line items match across invoice, PO, and GRN",
|
| "No price or quantity discrepancies",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_1c() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-1003",
|
| task_id=TaskID.task_1c_preferred_vendor_clean,
|
| difficulty=Difficulty.easy,
|
| max_steps=10,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0155",
|
| supplier_name="BrightStar IT Solutions",
|
| supplier_id="SUP-1200",
|
| invoice_date="2024-12-02",
|
| po_reference="PO-5600",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-B10",
|
| description="Wireless Keyboard & Mouse Combo",
|
| quantity_billed=30,
|
| unit_price_billed=45.00,
|
| line_total_billed=1350.00,
|
| ),
|
| ],
|
| subtotal=1350.00,
|
| tax=108.00,
|
| total_amount=1458.00,
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-5600",
|
| supplier_id="SUP-1200",
|
| order_date="2024-11-10",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-B10",
|
| description="Wireless Keyboard & Mouse Combo",
|
| ordered_quantity=30,
|
| unit_price_ordered=45.00,
|
| line_total_ordered=1350.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-7850",
|
| po_reference="PO-5600",
|
| receipt_date="2024-11-28",
|
| line_items=[
|
| GRNLineItem(item_code="ITEM-B10", quantity_received=30, accepted_quantity=30),
|
| ],
|
| warehouse_note="Full shipment. All items functional.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-1200",
|
| supplier_name="BrightStar IT Solutions",
|
| risk_tier="low",
|
| preferred_vendor=True,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=100.0,
|
| ),
|
| case_history=CaseHistory(),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.approve_for_payment,
|
| correct_exception_type=ExceptionType.clean_match,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| ],
|
| key_findings=[
|
| "Quantities match (30 ordered, 30 billed, 30 received)",
|
| "Price matches ($45.00 agreed and billed)",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_2b() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-2003",
|
| task_id=TaskID.task_2b_missing_receipt,
|
| difficulty=Difficulty.moderate,
|
| max_steps=10,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0201",
|
| supplier_name="NorthWind Chemicals",
|
| supplier_id="SUP-2100",
|
| invoice_date="2024-12-05",
|
| po_reference="PO-6300",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-N05",
|
| description="Laboratory Grade Ethanol 1L",
|
| quantity_billed=200,
|
| unit_price_billed=22.00,
|
| line_total_billed=4400.00,
|
| ),
|
| ],
|
| subtotal=4400.00,
|
| tax=352.00,
|
| total_amount=4752.00,
|
| note="Shipment dispatched per schedule.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-6300",
|
| supplier_id="SUP-2100",
|
| order_date="2024-11-05",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-N05",
|
| description="Laboratory Grade Ethanol 1L",
|
| ordered_quantity=200,
|
| unit_price_ordered=22.00,
|
| line_total_ordered=4400.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-8850",
|
| po_reference="PO-6300",
|
| receipt_date="2024-11-30",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-N05",
|
| quantity_received=0,
|
| accepted_quantity=0,
|
| rejected_quantity=0,
|
| ),
|
| ],
|
| warehouse_note="Shipment not yet received. GRN opened pending delivery.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-2100",
|
| supplier_name="NorthWind Chemicals",
|
| risk_tier="medium",
|
| preferred_vendor=True,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=200.0,
|
| ),
|
| case_history=CaseHistory(),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.place_on_hold,
|
| correct_exception_type=ExceptionType.missing_receipt,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "compare_quantity",
|
| ],
|
| key_findings=[
|
| "GRN shows 0 units received against 200 billed",
|
| "Shipment has not been delivered or accepted",
|
| "Cannot pay before goods are received",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_2c() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-2004",
|
| task_id=TaskID.task_2c_over_receipt,
|
| difficulty=Difficulty.moderate,
|
| max_steps=10,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0220",
|
| supplier_name="Pacific Hardware Co",
|
| supplier_id="SUP-2200",
|
| invoice_date="2024-12-08",
|
| po_reference="PO-6400",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-P15",
|
| description="Stainless Steel Bolts M10x50 (Box of 100)",
|
| quantity_billed=120,
|
| unit_price_billed=8.50,
|
| line_total_billed=1020.00,
|
| ),
|
| ],
|
| subtotal=1020.00,
|
| tax=81.60,
|
| total_amount=1101.60,
|
| note="Additional 20 boxes included as courtesy stock.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-6400",
|
| supplier_id="SUP-2200",
|
| order_date="2024-11-10",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-P15",
|
| description="Stainless Steel Bolts M10x50 (Box of 100)",
|
| ordered_quantity=100,
|
| unit_price_ordered=8.50,
|
| line_total_ordered=850.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-8870",
|
| po_reference="PO-6400",
|
| receipt_date="2024-12-03",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-P15",
|
| quantity_received=100,
|
| accepted_quantity=100,
|
| ),
|
| ],
|
| warehouse_note="Received 100 boxes per PO. No extra stock delivered.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-2200",
|
| supplier_name="Pacific Hardware Co",
|
| risk_tier="medium",
|
| preferred_vendor=True,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=100.0,
|
| ),
|
| case_history=CaseHistory(),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.place_on_hold,
|
| correct_exception_type=ExceptionType.quantity_mismatch,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "compare_quantity",
|
| ],
|
| key_findings=[
|
| "Invoice bills 120 units but only 100 were ordered and received",
|
| "Overbilling of 20 units (20% over received)",
|
| "Variance far exceeds 5% quantity tolerance",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_3b() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-3004",
|
| task_id=TaskID.task_3b_within_tolerance,
|
| difficulty=Difficulty.moderate,
|
| max_steps=10,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0330",
|
| supplier_name="EcoTech Green Supplies",
|
| supplier_id="SUP-3200",
|
| invoice_date="2024-12-12",
|
| po_reference="PO-7200",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-E08",
|
| description="Recycled Paper Reams (500 sheets)",
|
| quantity_billed=80,
|
| unit_price_billed=20.40,
|
| line_total_billed=1632.00,
|
| ),
|
| ],
|
| subtotal=1632.00,
|
| tax=130.56,
|
| total_amount=1762.56,
|
| note="Slight price increase due to recycled material costs.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-7200",
|
| supplier_id="SUP-3200",
|
| order_date="2024-11-18",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-E08",
|
| description="Recycled Paper Reams (500 sheets)",
|
| ordered_quantity=80,
|
| unit_price_ordered=20.00,
|
| line_total_ordered=1600.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-9170",
|
| po_reference="PO-7200",
|
| receipt_date="2024-12-08",
|
| line_items=[
|
| GRNLineItem(item_code="ITEM-E08", quantity_received=80, accepted_quantity=80),
|
| ],
|
| warehouse_note="All reams received and stored.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-3200",
|
| supplier_name="EcoTech Green Supplies",
|
| 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(),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.approve_for_payment,
|
| correct_exception_type=ExceptionType.clean_match,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "compare_price",
|
| ],
|
| key_findings=[
|
| "Price variance of 2% is within 5% tolerance",
|
| "Quantities match (80 ordered, 80 billed, 80 received)",
|
| "Acceptable per company policy",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_3c() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-3005",
|
| task_id=TaskID.task_3c_total_mismatch,
|
| difficulty=Difficulty.moderate,
|
| max_steps=10,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0345",
|
| supplier_name="Vanguard Medical Supplies",
|
| supplier_id="SUP-3300",
|
| invoice_date="2024-12-14",
|
| po_reference="PO-7300",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-V12",
|
| description="Disposable Surgical Masks (Box of 50)",
|
| quantity_billed=500,
|
| unit_price_billed=6.00,
|
| line_total_billed=3000.00,
|
| ),
|
| ],
|
| subtotal=3500.00,
|
| tax=280.00,
|
| total_amount=3780.00,
|
| note="Bulk order -- standard pricing applied.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-7300",
|
| supplier_id="SUP-3300",
|
| order_date="2024-11-20",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-V12",
|
| description="Disposable Surgical Masks (Box of 50)",
|
| ordered_quantity=500,
|
| unit_price_ordered=6.00,
|
| line_total_ordered=3000.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-9200",
|
| po_reference="PO-7300",
|
| receipt_date="2024-12-10",
|
| line_items=[
|
| GRNLineItem(item_code="ITEM-V12", quantity_received=500, accepted_quantity=500),
|
| ],
|
| warehouse_note="Full shipment received.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-3300",
|
| supplier_name="Vanguard Medical Supplies",
|
| 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(),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.escalate_for_supervisor_review,
|
| correct_exception_type=ExceptionType.total_amount_mismatch,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "compare_totals",
|
| ],
|
| key_findings=[
|
| "Invoice subtotal $3,500 does not match line items sum $3,000",
|
| "Invoice subtotal exceeds PO total by $500 (beyond $200 tolerance)",
|
| "Possible arithmetic error or hidden charges",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_4b() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-4005",
|
| task_id=TaskID.task_4b_corrected_invoice_trap,
|
| difficulty=Difficulty.hard,
|
| max_steps=12,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0601",
|
| supplier_name="Atlas Freight Solutions",
|
| supplier_id="SUP-4300",
|
| invoice_date="2024-12-20",
|
| po_reference="PO-8900",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-A20",
|
| description="Corrugated Shipping Boxes (Large)",
|
| quantity_billed=300,
|
| unit_price_billed=4.50,
|
| line_total_billed=1350.00,
|
| ),
|
| ],
|
| subtotal=1350.00,
|
| tax=108.00,
|
| total_amount=1458.00,
|
| note="CORRECTED INVOICE -- replaces INV-2024-0600. Please disregard previous version.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-8900",
|
| supplier_id="SUP-4300",
|
| order_date="2024-11-22",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-A20",
|
| description="Corrugated Shipping Boxes (Large)",
|
| ordered_quantity=300,
|
| unit_price_ordered=4.50,
|
| line_total_ordered=1350.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-9920",
|
| po_reference="PO-8900",
|
| receipt_date="2024-12-15",
|
| line_items=[
|
| GRNLineItem(item_code="ITEM-A20", quantity_received=300, accepted_quantity=300),
|
| ],
|
| warehouse_note="All boxes received per PO.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-4300",
|
| supplier_name="Atlas Freight Solutions",
|
| risk_tier="medium",
|
| duplicate_risk_count=1,
|
| preferred_vendor=True,
|
| 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=[
|
| "INV-2024-0600 was processed and paid on 2024-12-17.",
|
| ],
|
| similar_invoice_refs=["INV-2024-0600"],
|
| processed_invoice_numbers=["INV-2024-0600"],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.reject_invoice,
|
| correct_exception_type=ExceptionType.duplicate_invoice,
|
| acceptable_evidence=[
|
| "check_for_duplicate_invoice",
|
| "inspect_vendor_profile",
|
| ],
|
| key_findings=[
|
| "INV-2024-0600 was already processed and paid",
|
| "Current invoice claims to be a 'correction' but has identical amounts",
|
| "Supplier has 1 prior duplicate incident",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_4c() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-4006",
|
| task_id=TaskID.task_4c_policy_violation,
|
| difficulty=Difficulty.hard,
|
| max_steps=12,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0700",
|
| supplier_name="TitanWorks Engineering",
|
| supplier_id="SUP-4400",
|
| invoice_date="2024-12-22",
|
| po_reference="PO-9100",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-T30",
|
| description="CNC Machined Aluminum Housing Unit",
|
| quantity_billed=100,
|
| unit_price_billed=520.00,
|
| line_total_billed=52000.00,
|
| ),
|
| ],
|
| subtotal=52000.00,
|
| tax=4160.00,
|
| total_amount=56160.00,
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-9100",
|
| supplier_id="SUP-4400",
|
| order_date="2024-12-01",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-T30",
|
| description="CNC Machined Aluminum Housing Unit",
|
| ordered_quantity=100,
|
| unit_price_ordered=520.00,
|
| line_total_ordered=52000.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-9950",
|
| po_reference="PO-9100",
|
| receipt_date="2024-12-18",
|
| line_items=[
|
| GRNLineItem(item_code="ITEM-T30", quantity_received=100, accepted_quantity=100),
|
| ],
|
| warehouse_note="All units received. Quality inspection passed.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-4400",
|
| supplier_name="TitanWorks Engineering",
|
| risk_tier="medium",
|
| preferred_vendor=True,
|
| escalation_threshold=40000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=500.0,
|
| high_value_threshold=50000.0,
|
| ),
|
| case_history=CaseHistory(),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.escalate_for_supervisor_review,
|
| correct_exception_type=ExceptionType.policy_violation,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_policy_rules",
|
| "inspect_vendor_profile",
|
| ],
|
| key_findings=[
|
| "Invoice total $56,160 exceeds high-value threshold of $50,000",
|
| "All quantities and prices match, but policy requires supervisor review",
|
| "Invoice also exceeds vendor escalation threshold of $40,000",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_5() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-5001",
|
| task_id=TaskID.task_5_mixed_discrepancy,
|
| difficulty=Difficulty.hard,
|
| max_steps=12,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0850",
|
| supplier_name="GlobalParts Manufacturing",
|
| supplier_id="SUP-5100",
|
| invoice_date="2024-12-20",
|
| po_reference="PO-9500",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-G40",
|
| description="Precision Titanium Fasteners (Box of 25)",
|
| quantity_billed=200,
|
| unit_price_billed=55.00,
|
| line_total_billed=11000.00,
|
| ),
|
| ],
|
| subtotal=11000.00,
|
| tax=880.00,
|
| total_amount=11880.00,
|
| note="Price reflects updated material costs. Partial shipment billed in full per contract terms.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-9500",
|
| supplier_id="SUP-5100",
|
| order_date="2024-11-25",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-G40",
|
| description="Precision Titanium Fasteners (Box of 25)",
|
| ordered_quantity=200,
|
| unit_price_ordered=50.00,
|
| line_total_ordered=10000.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-10200",
|
| po_reference="PO-9500",
|
| receipt_date="2024-12-15",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-G40",
|
| quantity_received=150,
|
| accepted_quantity=150,
|
| rejected_quantity=0,
|
| ),
|
| ],
|
| warehouse_note="Partial shipment. 50 boxes backordered, ETA 2 weeks.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-5100",
|
| supplier_name="GlobalParts Manufacturing",
|
| risk_tier="medium",
|
| preferred_vendor=True,
|
| escalation_threshold=8000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=300.0,
|
| high_value_threshold=50000.0,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "Supplier has a history of price adjustments on raw material orders.",
|
| ],
|
| ),
|
| 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",
|
| "compare_quantity",
|
| "compare_price",
|
| "inspect_policy_rules",
|
| ],
|
| key_findings=[
|
| "Price variance: $55 billed vs $50 PO (10%, exceeds 5% tolerance)",
|
| "Quantity discrepancy: billed 200 but only 150 received (25% short)",
|
| "Both price escalation and quantity hold conditions triggered",
|
| "Per policy, price variance exceeding tolerance requires escalation",
|
| "Escalation takes priority over hold when both apply",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_6() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-6001",
|
| task_id=TaskID.task_6_false_positive_duplicate,
|
| difficulty=Difficulty.hard,
|
| max_steps=12,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0920",
|
| supplier_name="Metro Cleaning Services",
|
| supplier_id="SUP-6100",
|
| invoice_date="2024-12-28",
|
| po_reference="PO-9700",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-M15",
|
| description="Monthly Office Cleaning Service - January",
|
| quantity_billed=1,
|
| unit_price_billed=4500.00,
|
| line_total_billed=4500.00,
|
| ),
|
| ],
|
| subtotal=4500.00,
|
| tax=360.00,
|
| total_amount=4860.00,
|
| note="Monthly service invoice -- same as last month's order.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-9700",
|
| supplier_id="SUP-6100",
|
| order_date="2024-12-15",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-M15",
|
| description="Monthly Office Cleaning Service - January",
|
| ordered_quantity=1,
|
| unit_price_ordered=4500.00,
|
| line_total_ordered=4500.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-10500",
|
| po_reference="PO-9700",
|
| receipt_date="2024-12-26",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-M15",
|
| quantity_received=1,
|
| accepted_quantity=1,
|
| ),
|
| ],
|
| warehouse_note="Service confirmed completed for January cycle.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-6100",
|
| supplier_name="Metro Cleaning Services",
|
| risk_tier="low",
|
| duplicate_risk_count=0,
|
| preferred_vendor=True,
|
| ),
|
| 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=[
|
| "Monthly recurring service contract. New PO issued each month.",
|
| ],
|
| processed_invoice_numbers=[
|
| "INV-2024-0880",
|
| ],
|
| similar_invoice_refs=[],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.approve_for_payment,
|
| correct_exception_type=ExceptionType.clean_match,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "check_for_duplicate_invoice",
|
| ],
|
| key_findings=[
|
| "Invoice references PO-9700, which is a separate order from prior PO-9600",
|
| "Prior invoice INV-2024-0880 was for a different PO (different month)",
|
| "Quantities and prices match PO exactly",
|
| "No actual duplicate -- this is a legitimate recurring service invoice",
|
| "Vendor has 0 duplicate risk incidents",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_7() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-7001",
|
| task_id=TaskID.task_7_retroactive_price,
|
| difficulty=Difficulty.hard,
|
| max_steps=12,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-1150",
|
| supplier_name="Precision Parts Ltd",
|
| supplier_id="SUP-7100",
|
| invoice_date="2024-11-10",
|
| po_reference="PO-7500",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-PP01",
|
| description="CNC Bearing Assembly Type-R",
|
| quantity_billed=200,
|
| unit_price_billed=47.50,
|
| line_total_billed=9500.00,
|
| ),
|
| InvoiceLineItem(
|
| item_code="ITEM-PP02",
|
| description="Hydraulic Seal Kit Grade-A",
|
| quantity_billed=500,
|
| unit_price_billed=12.80,
|
| line_total_billed=6400.00,
|
| ),
|
| ],
|
| subtotal=15900.00,
|
| tax=1272.00,
|
| total_amount=17172.00,
|
| note="Prices reflect updated catalog effective 2024-11-01.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-7500",
|
| supplier_id="SUP-7100",
|
| order_date="2024-10-20",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-PP01",
|
| description="CNC Bearing Assembly Type-R",
|
| ordered_quantity=200,
|
| unit_price_ordered=42.00,
|
| line_total_ordered=8400.00,
|
| ),
|
| POLineItem(
|
| item_code="ITEM-PP02",
|
| description="Hydraulic Seal Kit Grade-A",
|
| ordered_quantity=500,
|
| unit_price_ordered=11.50,
|
| line_total_ordered=5750.00,
|
| ),
|
| ],
|
| payment_terms="Net 45",
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-12500",
|
| po_reference="PO-7500",
|
| receipt_date="2024-11-05",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-PP01",
|
| quantity_received=200,
|
| accepted_quantity=200,
|
| ),
|
| GRNLineItem(
|
| item_code="ITEM-PP02",
|
| quantity_received=500,
|
| accepted_quantity=500,
|
| ),
|
| ],
|
| warehouse_note="All items received in good condition. Full order.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-7100",
|
| supplier_name="Precision Parts Ltd",
|
| risk_tier="medium",
|
| duplicate_risk_count=0,
|
| preferred_vendor=True,
|
| escalation_threshold=15000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=500.0,
|
| duplicate_check_enabled=True,
|
| high_value_threshold=50000.0,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "Vendor announced price increase effective 2024-11-01.",
|
| "PO-7500 was placed on 2024-10-20 at the old catalog prices.",
|
| "Contract terms: PO price governs unless amended before shipment.",
|
| ],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.escalate_for_supervisor_review,
|
| correct_exception_type=ExceptionType.price_mismatch,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "compare_price",
|
| "inspect_policy_rules",
|
| "inspect_vendor_profile",
|
| ],
|
| key_findings=[
|
| "ITEM-PP01 billed at $47.50 vs PO price $42.00 (13.1% variance)",
|
| "ITEM-PP02 billed at $12.80 vs PO price $11.50 (11.3% variance)",
|
| "Both exceed 5% price tolerance",
|
| "PO was issued 2024-10-20, before price change effective 2024-11-01",
|
| "Per contract terms, PO price governs unless PO is amended",
|
| "Invoice total $17,172 exceeds vendor escalation threshold $15,000",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_8() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-8001",
|
| task_id=TaskID.task_8_split_invoice_pattern,
|
| difficulty=Difficulty.hard,
|
| max_steps=12,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-2210",
|
| supplier_name="Global Tech Supplies",
|
| supplier_id="SUP-8200",
|
| invoice_date="2024-12-01",
|
| po_reference="PO-8800",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-GT10",
|
| description="Enterprise Server Rack Unit 42U",
|
| quantity_billed=3,
|
| unit_price_billed=14500.00,
|
| line_total_billed=43500.00,
|
| ),
|
| ],
|
| subtotal=43500.00,
|
| tax=3480.00,
|
| total_amount=46980.00,
|
| note="Shipment 3 of 3. Final batch for data center buildout.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-8800",
|
| supplier_id="SUP-8200",
|
| order_date="2024-11-15",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-GT10",
|
| description="Enterprise Server Rack Unit 42U",
|
| ordered_quantity=3,
|
| unit_price_ordered=14500.00,
|
| line_total_ordered=43500.00,
|
| ),
|
| ],
|
| payment_terms="Net 30",
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-15200",
|
| po_reference="PO-8800",
|
| receipt_date="2024-11-28",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-GT10",
|
| quantity_received=3,
|
| accepted_quantity=3,
|
| ),
|
| ],
|
| warehouse_note="Final batch received. All 9 rack units now in inventory.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-8200",
|
| supplier_name="Global Tech Supplies",
|
| risk_tier="high",
|
| duplicate_risk_count=4,
|
| preferred_vendor=False,
|
| escalation_threshold=40000.00,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=500.0,
|
| duplicate_check_enabled=True,
|
| high_value_threshold=50000.00,
|
| mandatory_escalation_above=100000.00,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "ALERT: Vendor SUP-8200 has submitted 3 invoices this month "
|
| "for similar items across 3 separate POs (PO-8600, PO-8700, PO-8800).",
|
| "Each invoice is just under the $50,000 auto-approval threshold.",
|
| "Combined value: $46,200 + $47,800 + $46,980 = $140,980.",
|
| "Finance team flagged potential invoice-splitting pattern.",
|
| "Vendor is non-preferred with 4 prior risk incidents.",
|
| ],
|
| similar_invoice_refs=["INV-2024-2180", "INV-2024-2195"],
|
| processed_invoice_numbers=["INV-2024-2180", "INV-2024-2195"],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.escalate_for_supervisor_review,
|
| correct_exception_type=ExceptionType.policy_violation,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "inspect_vendor_profile",
|
| "inspect_policy_rules",
|
| "check_for_duplicate_invoice",
|
| ],
|
| key_findings=[
|
| "Invoice $46,980 is just under auto-approval threshold of $50,000",
|
| "3 similar invoices from same vendor total $140,980",
|
| "Vendor is high-risk tier with 4 prior risk incidents",
|
| "Vendor is non-preferred",
|
| "Case history explicitly flags split-invoice pattern concern",
|
| "Combined value exceeds mandatory escalation threshold of $100,000",
|
| "Individual prices and quantities match PO -- no line-level discrepancy",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_9() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-9001",
|
| task_id=TaskID.task_9_clean_from_risky_vendor,
|
| difficulty=Difficulty.hard,
|
| max_steps=12,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-3300",
|
| supplier_name="Delta Industrial Components",
|
| supplier_id="SUP-9300",
|
| invoice_date="2024-12-10",
|
| po_reference="PO-9200",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-DC01",
|
| description="Steel Flanged Coupling 6-inch",
|
| quantity_billed=50,
|
| unit_price_billed=85.00,
|
| line_total_billed=4250.00,
|
| ),
|
| InvoiceLineItem(
|
| item_code="ITEM-DC02",
|
| description="Gasket Kit Industrial Grade",
|
| quantity_billed=200,
|
| unit_price_billed=12.50,
|
| line_total_billed=2500.00,
|
| ),
|
| ],
|
| subtotal=6750.00,
|
| tax=540.00,
|
| total_amount=7290.00,
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-9200",
|
| supplier_id="SUP-9300",
|
| order_date="2024-11-25",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-DC01",
|
| description="Steel Flanged Coupling 6-inch",
|
| ordered_quantity=50,
|
| unit_price_ordered=85.00,
|
| line_total_ordered=4250.00,
|
| ),
|
| POLineItem(
|
| item_code="ITEM-DC02",
|
| description="Gasket Kit Industrial Grade",
|
| ordered_quantity=200,
|
| unit_price_ordered=12.50,
|
| line_total_ordered=2500.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-16000",
|
| po_reference="PO-9200",
|
| receipt_date="2024-12-05",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-DC01",
|
| quantity_received=50,
|
| accepted_quantity=50,
|
| ),
|
| GRNLineItem(
|
| item_code="ITEM-DC02",
|
| quantity_received=200,
|
| accepted_quantity=200,
|
| ),
|
| ],
|
| warehouse_note="Full order received. Quality inspection passed.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-9300",
|
| supplier_name="Delta Industrial Components",
|
| risk_tier="high",
|
| duplicate_risk_count=5,
|
| 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=[
|
| "Vendor under enhanced monitoring due to past billing errors.",
|
| "Last 3 invoices from this vendor were all clean and processed normally.",
|
| "Risk tier remains 'high' pending annual vendor review in Q1 2025.",
|
| ],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.approve_for_payment,
|
| correct_exception_type=ExceptionType.clean_match,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "compare_quantity",
|
| "compare_price",
|
| "inspect_vendor_profile",
|
| "inspect_policy_rules",
|
| ],
|
| key_findings=[
|
| "All quantities match exactly: 50 couplings and 200 gasket kits",
|
| "All prices match PO exactly: $85.00 and $12.50",
|
| "Vendor is high-risk but no actual discrepancy exists",
|
| "Risk tier affects escalation thresholds, not clean invoices",
|
| "Last 3 invoices from this vendor were processed normally",
|
| "No policy rule mandates rejection of clean invoices from high-risk vendors",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_10() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-10001",
|
| task_id=TaskID.task_10_rounding_false_alarm,
|
| difficulty=Difficulty.hard,
|
| max_steps=12,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-4410",
|
| supplier_name="Kensington Paper & Print",
|
| supplier_id="SUP-10400",
|
| invoice_date="2024-12-15",
|
| po_reference="PO-10100",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-KP01",
|
| description="A4 Premium Copy Paper (case of 10 reams)",
|
| quantity_billed=33,
|
| unit_price_billed=42.99,
|
| line_total_billed=1418.67,
|
| ),
|
| InvoiceLineItem(
|
| item_code="ITEM-KP02",
|
| description="Color Laser Toner Cartridge Black",
|
| quantity_billed=7,
|
| unit_price_billed=189.99,
|
| line_total_billed=1329.93,
|
| ),
|
| InvoiceLineItem(
|
| item_code="ITEM-KP03",
|
| description="Binding Covers Glossy A4 (pack of 100)",
|
| quantity_billed=15,
|
| unit_price_billed=28.33,
|
| line_total_billed=424.95,
|
| ),
|
| ],
|
| subtotal=3173.55,
|
| tax=253.88,
|
| total_amount=3427.43,
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-10100",
|
| supplier_id="SUP-10400",
|
| order_date="2024-12-01",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-KP01",
|
| description="A4 Premium Copy Paper (case of 10 reams)",
|
| ordered_quantity=33,
|
| unit_price_ordered=42.99,
|
| line_total_ordered=1418.67,
|
| ),
|
| POLineItem(
|
| item_code="ITEM-KP02",
|
| description="Color Laser Toner Cartridge Black",
|
| ordered_quantity=7,
|
| unit_price_ordered=189.99,
|
| line_total_ordered=1329.93,
|
| ),
|
| POLineItem(
|
| item_code="ITEM-KP03",
|
| description="Binding Covers Glossy A4 (pack of 100)",
|
| ordered_quantity=15,
|
| unit_price_ordered=28.33,
|
| line_total_ordered=424.95,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-17500",
|
| po_reference="PO-10100",
|
| receipt_date="2024-12-10",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-KP01",
|
| quantity_received=33,
|
| accepted_quantity=33,
|
| ),
|
| GRNLineItem(
|
| item_code="ITEM-KP02",
|
| quantity_received=7,
|
| accepted_quantity=7,
|
| ),
|
| GRNLineItem(
|
| item_code="ITEM-KP03",
|
| quantity_received=15,
|
| accepted_quantity=15,
|
| ),
|
| ],
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-10400",
|
| supplier_name="Kensington Paper & Print",
|
| risk_tier="low",
|
| preferred_vendor=True,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=100.0,
|
| duplicate_check_enabled=True,
|
| ),
|
| case_history=CaseHistory(),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.approve_for_payment,
|
| correct_exception_type=ExceptionType.clean_match,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "compare_quantity",
|
| "compare_price",
|
| "compare_totals",
|
| "inspect_policy_rules",
|
| ],
|
| key_findings=[
|
| "All quantities match exactly",
|
| "All unit prices match PO exactly",
|
| "Subtotal rounding difference of $0.01 is within tolerance",
|
| "Total tolerance is $100.00 -- a $0.01 difference is negligible",
|
| "Rounding is a normal artifact of multi-line calculation",
|
| "Preferred vendor with low risk tier",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_11() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-11001",
|
| task_id=TaskID.task_11_authorized_overship,
|
| difficulty=Difficulty.hard,
|
| max_steps=12,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-5520",
|
| supplier_name="Pacific Coast Fasteners",
|
| supplier_id="SUP-11500",
|
| invoice_date="2024-12-18",
|
| po_reference="PO-11300",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-PF01",
|
| description="M8 Hex Bolt Grade 8.8 Zinc Plated (box of 100)",
|
| quantity_billed=110,
|
| unit_price_billed=24.50,
|
| line_total_billed=2695.00,
|
| ),
|
| ],
|
| subtotal=2695.00,
|
| tax=215.60,
|
| total_amount=2910.60,
|
| note="Quantity includes authorized 10% overship per PO amendment.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-11300",
|
| supplier_id="SUP-11500",
|
| order_date="2024-12-01",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-PF01",
|
| description="M8 Hex Bolt Grade 8.8 Zinc Plated (box of 100)",
|
| ordered_quantity=100,
|
| unit_price_ordered=24.50,
|
| line_total_ordered=2450.00,
|
| ),
|
| ],
|
| payment_terms="Net 30",
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-18800",
|
| po_reference="PO-11300",
|
| receipt_date="2024-12-12",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-PF01",
|
| quantity_received=110,
|
| accepted_quantity=110,
|
| ),
|
| ],
|
| warehouse_note="110 boxes received. Overship authorized per buyer memo dated 2024-12-02.",
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-11500",
|
| supplier_name="Pacific Coast Fasteners",
|
| risk_tier="low",
|
| preferred_vendor=True,
|
| ),
|
| company_policy=CompanyPolicy(
|
| quantity_tolerance_pct=5.0,
|
| price_tolerance_pct=5.0,
|
| total_tolerance_amt=500.0,
|
| duplicate_check_enabled=True,
|
| ),
|
| case_history=CaseHistory(
|
| prior_comments=[
|
| "PO-11300 Amendment 1 (2024-12-02): Authorized up to 10% overship "
|
| "at the same unit price to ensure inventory buffer for Q1.",
|
| "Buyer confirmed acceptance of up to 110 boxes at $24.50/box.",
|
| "Warehouse confirmed receipt of full 110 boxes in good condition.",
|
| ],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.approve_for_payment,
|
| correct_exception_type=ExceptionType.clean_match,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "compare_quantity",
|
| "inspect_policy_rules",
|
| ],
|
| key_findings=[
|
| "Billed 110 vs ordered 100 -- 10% overship",
|
| "PO Amendment 1 explicitly authorized up to 10% overship",
|
| "Buyer confirmed acceptance of 110 units at $24.50",
|
| "GRN confirms all 110 accepted in good condition",
|
| "Unit price matches PO exactly",
|
| "Overship is within the authorized range",
|
| ],
|
| ),
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _build_task_12() -> CaseData:
|
| return CaseData(
|
| case_id="CASE-12001",
|
| task_id=TaskID.task_12_corrected_resubmission,
|
| difficulty=Difficulty.hard,
|
| max_steps=12,
|
| invoice=Invoice(
|
| invoice_number="INV-2024-0500-R1",
|
| supplier_name="Westfield Electronics",
|
| supplier_id="SUP-12600",
|
| invoice_date="2024-12-20",
|
| po_reference="PO-12400",
|
| line_items=[
|
| InvoiceLineItem(
|
| item_code="ITEM-WE01",
|
| description="Industrial Ethernet Switch 24-Port PoE+",
|
| quantity_billed=5,
|
| unit_price_billed=1250.00,
|
| line_total_billed=6250.00,
|
| ),
|
| InvoiceLineItem(
|
| item_code="ITEM-WE02",
|
| description="SFP+ 10G Transceiver Module",
|
| quantity_billed=20,
|
| unit_price_billed=85.00,
|
| line_total_billed=1700.00,
|
| ),
|
| ],
|
| subtotal=7950.00,
|
| tax=636.00,
|
| total_amount=8586.00,
|
| note="Corrected invoice. Replaces INV-2024-0500 which was rejected for pricing error.",
|
| ),
|
| purchase_order=PurchaseOrder(
|
| po_number="PO-12400",
|
| supplier_id="SUP-12600",
|
| order_date="2024-12-01",
|
| line_items=[
|
| POLineItem(
|
| item_code="ITEM-WE01",
|
| description="Industrial Ethernet Switch 24-Port PoE+",
|
| ordered_quantity=5,
|
| unit_price_ordered=1250.00,
|
| line_total_ordered=6250.00,
|
| ),
|
| POLineItem(
|
| item_code="ITEM-WE02",
|
| description="SFP+ 10G Transceiver Module",
|
| ordered_quantity=20,
|
| unit_price_ordered=85.00,
|
| line_total_ordered=1700.00,
|
| ),
|
| ],
|
| ),
|
| goods_receipt_note=GoodsReceiptNote(
|
| grn_number="GRN-20100",
|
| po_reference="PO-12400",
|
| receipt_date="2024-12-10",
|
| line_items=[
|
| GRNLineItem(
|
| item_code="ITEM-WE01",
|
| quantity_received=5,
|
| accepted_quantity=5,
|
| ),
|
| GRNLineItem(
|
| item_code="ITEM-WE02",
|
| quantity_received=20,
|
| accepted_quantity=20,
|
| ),
|
| ],
|
| ),
|
| vendor_profile=VendorProfile(
|
| supplier_id="SUP-12600",
|
| supplier_name="Westfield Electronics",
|
| risk_tier="medium",
|
| duplicate_risk_count=1,
|
| preferred_vendor=True,
|
| ),
|
| 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-0500 was rejected on 2024-12-15: switches billed at $1,350 "
|
| "instead of PO price $1,250. Vendor acknowledged error.",
|
| "Vendor issued corrected invoice INV-2024-0500-R1 with correct pricing.",
|
| "AP team confirmed: process INV-2024-0500-R1 as the replacement invoice.",
|
| ],
|
| processed_invoice_numbers=[],
|
| similar_invoice_refs=["INV-2024-0500"],
|
| ),
|
| ground_truth=GroundTruth(
|
| correct_decision=DecisionType.approve_for_payment,
|
| correct_exception_type=ExceptionType.clean_match,
|
| acceptable_evidence=[
|
| "inspect_purchase_order",
|
| "inspect_goods_receipt_note",
|
| "compare_price",
|
| "check_for_duplicate_invoice",
|
| "inspect_policy_rules",
|
| ],
|
| key_findings=[
|
| "INV-2024-0500-R1 is the corrected version of rejected INV-2024-0500",
|
| "Original invoice was rejected for $100/unit price overcharge on switches",
|
| "Corrected invoice has the correct PO price of $1,250 per switch",
|
| "All quantities and prices now match PO exactly",
|
| "AP team explicitly approved processing the replacement invoice",
|
| "Not a duplicate -- it is a correction of a rejected invoice",
|
| ],
|
| ),
|
| )
|
|
|