{"files": {"main.py": "from core import run\nfrom policy import POLICY\ndef evaluate(payload):\n    return run(payload, POLICY)\n", "core.py": "from helpers import principal_cents, deduplicate_events, order_refund_events, format_status\n\ndef run(payload, policy):\n    if not payload:\n        return {\"invoices\": []}\n    if isinstance(payload, dict):\n        invoices_in = payload.get(\"invoices\", [])\n    elif isinstance(payload, (list, tuple)):\n        invoices_in = list(payload)\n    else:\n        return {\"invoices\": []}\n    if not invoices_in:\n        return {\"invoices\": []}\n    currency = policy.get(\"currency\", \"CAD\")\n    rounding = policy.get(\"rounding\", \"invoice\")\n    duplicate_event = policy.get(\"duplicate_event\", \"last\")\n    inclusive_limit = policy.get(\"inclusive_limit\", False)\n    max_refund_age_days = policy.get(\"max_refund_age_days\", 45)\n    refunds_first = policy.get(\"refunds_first\", False)\n    refund_overflow = policy.get(\"refund_overflow\", \"reject\")\n    void_is_tombstone = policy.get(\"void_is_tombstone\", False)\n    fee_refundable = policy.get(\"fee_refundable\", False)\n    min_invoice_cents = policy.get(\"min_invoice_cents\", 25)\n    status_case = policy.get(\"status_case\", \"upper\")\n    order = policy.get(\"order\", \"created\")\n    results = []\n    for inv in invoices_in:\n        if not isinstance(inv, dict):\n            continue\n        if inv.get(\"currency\") != currency:\n            continue\n        lines = inv.get(\"lines\", []) or []\n        fee = inv.get(\"fee_cents\", 0) or 0\n        fee = int(fee)\n        principal = principal_cents(lines, rounding)\n        charge = principal + fee\n        if charge < min_invoice_cents:\n            continue\n        created = inv.get(\"created\", 0)\n        events = inv.get(\"events\", []) or []\n        deduped = deduplicate_events(events, duplicate_event)\n        ordered = order_refund_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\", 0)\n                try:\n                    age = day - created\n                except Exception:\n                    continue\n                if age < 0:\n                    continue\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 = int(ev.get(\"cents\", 0) or 0)\n                if refunded + cents > ceiling:\n                    if refund_overflow == \"cap\":\n                        refunded = ceiling\n                    else:\n                        continue\n                else:\n                    refunded += cents\n        if not active:\n            status_raw = \"void\"\n        elif refunded == charge:\n            status_raw = \"refunded\"\n        else:\n            status_raw = \"open\"\n        status = format_status(status_raw, status_case)\n        record = {\"id\": inv.get(\"id\"), \"charge\": charge, \"refunded\": refunded, \"balance\": charge - refunded, \"status\": status}\n        results.append((created, record))\n    if order == \"id\":\n        results.sort(key=lambda x: x[1][\"id\"])\n    else:\n        results.sort(key=lambda x: (x[0], x[1][\"id\"]))\n    return {\"invoices\": [r for _, r in results]}\n", "policy.py": "POLICY = {\n    \"currency\": \"CAD\",\n    \"rounding\": \"invoice\",\n    \"duplicate_event\": \"last\",\n    \"inclusive_limit\": False,\n    \"max_refund_age_days\": 45,\n    \"refunds_first\": False,\n    \"refund_overflow\": \"reject\",\n    \"void_is_tombstone\": False,\n    \"fee_refundable\": False,\n    \"min_invoice_cents\": 25,\n    \"status_case\": \"upper\",\n    \"order\": \"created\",\n}\n", "helpers.py": "from decimal import Decimal, ROUND_HALF_UP\n\ndef _to_decimal(value):\n    if isinstance(value, Decimal):\n        return value\n    return Decimal(str(value))\n\ndef principal_cents(lines, rounding):\n    if rounding == \"per_line\":\n        total = 0\n        for line in lines:\n            cents = (_to_decimal(line) * Decimal(\"100\")).quantize(Decimal(\"1\"), rounding=ROUND_HALF_UP)\n            total += int(cents)\n        return total\n    total = Decimal(\"0\")\n    for line in lines:\n        total += _to_decimal(line)\n    cents = (total * Decimal(\"100\")).quantize(Decimal(\"1\"), rounding=ROUND_HALF_UP)\n    return int(cents)\n\ndef deduplicate_events(events, duplicate_event):\n    seen = {}\n    order = []\n    anonymous = []\n    for ev in events:\n        if not isinstance(ev, dict) or \"eid\" not in ev:\n            anonymous.append(ev)\n            continue\n        eid = ev[\"eid\"]\n        if eid not in seen:\n            order.append(eid)\n            seen[eid] = ev\n        else:\n            if duplicate_event == \"last\":\n                seen[eid] = ev\n    result = [seen[eid] for eid in order]\n    return result + anonymous\n\ndef order_refund_events(events, refunds_first):\n    copied = list(events)\n    if not refunds_first:\n        return copied\n    refunds = [e for e in copied if isinstance(e, dict) and e.get(\"kind\") == \"refund\"]\n    others = [e for e in copied if not (isinstance(e, dict) and e.get(\"kind\") == \"refund\")]\n    return refunds + others\n\ndef format_status(status, status_case):\n    if status_case == \"upper\":\n        return status.upper()\n    if status_case == \"lower\":\n        return status.lower()\n    return status\n"}}