{"files": {"main.py": "from core import run\nfrom policy import POLICY\ndef evaluate(payload):\n    return run(payload, POLICY)\n", "core.py": "from decimal import Decimal, ROUND_HALF_UP\nfrom helpers import line_cents, dedupe_events, order_events, apply_status_case\nimport copy\n\ndef run(payload, policy):\n    if payload is None:\n        return {\"invoices\": []}\n    if isinstance(payload, list):\n        raw_invoices = payload\n    elif isinstance(payload, dict):\n        raw_invoices = payload.get(\"invoices\")\n        if raw_invoices is None:\n            raw_invoices = payload.get(\"items\", [])\n    else:\n        return {\"invoices\": []}\n    if not raw_invoices:\n        return {\"invoices\": []}\n    data = copy.deepcopy(raw_invoices)\n    target_currency = policy.get(\"currency\")\n    rounding = policy.get(\"rounding\", \"per_line\")\n    min_invoice_cents = policy.get(\"min_invoice_cents\", 0)\n    duplicate_event = policy.get(\"duplicate_event\", \"first\")\n    refunds_first = policy.get(\"refunds_first\", False)\n    void_is_tombstone = policy.get(\"void_is_tombstone\", False)\n    max_refund_age_days = policy.get(\"max_refund_age_days\")\n    inclusive_limit = policy.get(\"inclusive_limit\", False)\n    fee_refundable = policy.get(\"fee_refundable\", False)\n    refund_overflow = policy.get(\"refund_overflow\", \"cap\")\n    status_case = policy.get(\"status_case\", \"lower\")\n    order = policy.get(\"order\", \"id\")\n    results = []\n    created_by_id = {}\n    for inv in data:\n        if not isinstance(inv, dict):\n            continue\n        if inv.get(\"currency\") != target_currency:\n            continue\n        inv_id = inv.get(\"id\")\n        created = inv.get(\"created\")\n        if created is None:\n            created = inv.get(\"created_day\", 0)\n        lines = inv.get(\"lines\") or []\n        fee = inv.get(\"fee_cents\") or 0\n        fee = int(fee)\n        if rounding == \"invoice\":\n            total = Decimal('0')\n            for line in lines:\n                total += Decimal(str(line)) * Decimal('100')\n            principal = int(total.quantize(Decimal('1'), rounding=ROUND_HALF_UP))\n        else:\n            principal = sum(line_cents(line) for line in lines)\n        charge = principal + fee\n        if charge < min_invoice_cents:\n            continue\n        events = inv.get(\"events\") or []\n        deduped = dedupe_events(events, duplicate_event)\n        ordered = order_events(deduped, refunds_first)\n        ceiling = principal + fee if fee_refundable else principal\n        refunded = 0\n        active = True\n        tombstoned = False\n        for ev in ordered:\n            if not isinstance(ev, dict):\n                continue\n            kind = ev.get(\"kind\")\n            if kind == \"void\":\n                active = False\n                if void_is_tombstone:\n                    tombstoned = True\n            elif kind == \"restore\":\n                if not tombstoned:\n                    active = True\n            elif kind == \"refund\":\n                if not active:\n                    continue\n                day = ev.get(\"day\")\n                if day is None:\n                    day = created\n                age = day - created\n                if age < 0:\n                    continue\n                if max_refund_age_days is not None:\n                    if inclusive_limit:\n                        if age > max_refund_age_days:\n                            continue\n                    else:\n                        if age >= max_refund_age_days:\n                            continue\n                cents = ev.get(\"cents\") or 0\n                cents = int(cents)\n                if cents < 0:\n                    continue\n                remaining = ceiling - refunded\n                if remaining <= 0:\n                    continue\n                if refund_overflow == \"reject\":\n                    if cents > remaining:\n                        continue\n                    refunded += cents\n                else:\n                    refunded += cents if cents <= remaining else remaining\n        if not active:\n            status_raw = \"void\"\n        elif refunded == charge:\n            status_raw = \"refunded\"\n        else:\n            status_raw = \"open\"\n        status = apply_status_case(status_raw, status_case)\n        results.append({\"id\": inv_id, \"charge\": charge, \"refunded\": refunded, \"balance\": charge - refunded, \"status\": status})\n        created_by_id[inv_id] = created\n    if order == \"created\":\n        results.sort(key=lambda r: (created_by_id.get(r[\"id\"], 0), r[\"id\"]))\n    else:\n        results.sort(key=lambda r: r[\"id\"])\n    return {\"invoices\": results}\n", "policy.py": "POLICY = {\n    \"currency\": \"USD\",\n    \"fee_refundable\": True,\n    \"min_invoice_cents\": 10,\n    \"status_case\": \"lower\",\n    \"rounding\": \"per_line\",\n    \"duplicate_event\": \"first\",\n    \"inclusive_limit\": True,\n    \"max_refund_age_days\": 30,\n    \"refunds_first\": True,\n    \"refund_overflow\": \"cap\",\n    \"void_is_tombstone\": True,\n    \"order\": \"id\",\n}\n", "helpers.py": "from decimal import Decimal, ROUND_HALF_UP\n\ndef line_cents(line):\n    value = Decimal(str(line)) * Decimal('100')\n    return int(value.quantize(Decimal('1'), rounding=ROUND_HALF_UP))\n\ndef dedupe_events(events, mode):\n    seen = {}\n    for ev in events:\n        if not isinstance(ev, dict):\n            continue\n        eid = ev.get(\"eid\")\n        if eid not in seen:\n            seen[eid] = ev\n        elif mode == \"last\":\n            seen[eid] = ev\n    return list(seen.values())\n\ndef order_events(events, refunds_first):\n    if not refunds_first:\n        return list(events)\n    refunds = [e for e in events if isinstance(e, dict) and e.get(\"kind\") == \"refund\"]\n    others = [e for e in events if not (isinstance(e, dict) and e.get(\"kind\") == \"refund\")]\n    return refunds + others\n\ndef apply_status_case(status, case):\n    if case == \"upper\":\n        return status.upper()\n    return status.lower()\n"}}