{"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, event_cents\n\ndef run(payload, policy):\n    if not payload:\n        return {'invoices': []}\n    if isinstance(payload, dict):\n        invoices_in = payload.get('invoices', [])\n        if invoices_in is None:\n            invoices_in = []\n    elif isinstance(payload, list):\n        invoices_in = payload\n    else:\n        return {'invoices': []}\n    currency = policy.get('currency')\n    rounding = policy.get('rounding')\n    min_charge = policy.get('min_invoice_cents', 0)\n    if min_charge is None:\n        min_charge = 0\n    dedup_mode = policy.get('duplicate_event', 'first')\n    refunds_first = policy.get('refunds_first', False)\n    tombstone_policy = policy.get('void_is_tombstone', False)\n    max_age = policy.get('max_refund_age_days')\n    inclusive = policy.get('inclusive_limit', False)\n    fee_refundable = policy.get('fee_refundable', False)\n    overflow = policy.get('refund_overflow', 'cap')\n    order = policy.get('order', 'id')\n    status_case = policy.get('status_case', 'lower')\n    results = []\n    for inv in list(invoices_in):\n        if not isinstance(inv, dict):\n            continue\n        if currency is not None and inv.get('currency') != currency:\n            continue\n        inv_id = inv.get('id')\n        created = inv.get('created', inv.get('created_day', inv.get('day', 0)))\n        if created is None:\n            created = 0\n        created = int(created)\n        lines = inv.get('lines', []) or []\n        principal = principal_cents(list(lines), rounding)\n        fee_raw = inv.get('fee_cents', 0)\n        fee = int(fee_raw) if fee_raw is not None else 0\n        charge = principal + fee\n        if charge < min_charge:\n            continue\n        raw_events = inv.get('events', []) or []\n        deduped_map = {}\n        for idx, ev in enumerate(list(raw_events)):\n            if not isinstance(ev, dict):\n                continue\n            copied = dict(ev)\n            eid = copied.get('eid', copied.get('id'))\n            if eid is None:\n                key = ('__no_eid__', idx)\n                deduped_map[key] = copied\n            else:\n                if dedup_mode == 'last':\n                    deduped_map[eid] = copied\n                else:\n                    if eid not in deduped_map:\n                        deduped_map[eid] = copied\n        events = list(deduped_map.values())\n        if refunds_first:\n            events = [e for e in events if (e.get('kind', e.get('type')) == 'refund')] + [e for e in events if (e.get('kind', e.get('type')) != 'refund')]\n        ceiling = charge if fee_refundable else principal\n        refunded = 0\n        active = True\n        tombstoned = False\n        for ev in events:\n            kind = ev.get('kind', ev.get('type'))\n            if kind == 'void':\n                active = False\n                if tombstone_policy:\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_raw = ev.get('day')\n                if day_raw is None:\n                    continue\n                diff = int(day_raw) - created\n                if diff < 0:\n                    continue\n                if max_age is not None:\n                    if inclusive:\n                        if diff > max_age:\n                            continue\n                    else:\n                        if diff >= max_age:\n                            continue\n                cents = event_cents(ev)\n                if cents < 0:\n                    continue\n                if overflow == 'reject':\n                    if refunded + cents > ceiling:\n                        continue\n                    refunded += cents\n                else:\n                    allowable = ceiling - refunded\n                    if allowable <= 0:\n                        continue\n                    refunded += cents if cents <= allowable else allowable\n        if not active:\n            status = 'void'\n        elif refunded == charge:\n            status = 'refunded'\n        else:\n            status = 'open'\n        if isinstance(status_case, str) and status_case.lower() == 'upper':\n            status = status.upper()\n        elif isinstance(status_case, str) and status_case.lower() in ('title', 'capitalized', 'capitalize'):\n            status = status.capitalize()\n        else:\n            status = status.lower()\n        results.append((created, inv_id, {'id': inv_id, 'charge': charge, 'refunded': refunded, 'balance': charge - refunded, 'status': status}))\n    if order == 'created':\n        results.sort(key=lambda x: (x[0], x[1]))\n    else:\n        results.sort(key=lambda x: x[1])\n    return {'invoices': [r[2] for r in results]}\n", "policy.py": "POLICY = {'duplicate_event': 'first', 'inclusive_limit': True, 'max_refund_age_days': 30, 'rounding': 'per_line', 'order': 'id', 'refund_overflow': 'cap', 'refunds_first': True, 'void_is_tombstone': True, 'min_invoice_cents': 10, 'status_case': 'lower', 'currency': 'USD', 'fee_refundable': True}\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).strip())\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_dollars = Decimal('0')\n    for line in lines:\n        total_dollars += _to_decimal(line)\n    cents = (total_dollars * Decimal('100')).quantize(Decimal('1'), rounding=ROUND_HALF_UP)\n    return int(cents)\n\ndef event_cents(event):\n    raw = event.get('cents')\n    if raw is None:\n        raw = event.get('amount_cents')\n    if raw is None:\n        raw = event.get('amount')\n    if raw is None:\n        raw = event.get('value', 0)\n    if raw is None:\n        raw = 0\n    return int(raw)\n"}}