{"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 principal_cents, event_cents, event_kind\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 = []\n    else:\n        return {'invoices': []}\n    currency = policy.get('currency')\n    rounding = policy.get('rounding', 'invoice')\n    min_invoice_cents = policy.get('min_invoice_cents', 0)\n    duplicate_event = policy.get('duplicate_event', 'last')\n    refunds_first = policy.get('refunds_first', False)\n    void_is_tombstone = policy.get('void_is_tombstone', False)\n    inclusive_limit = policy.get('inclusive_limit', False)\n    max_refund_age_days = policy.get('max_refund_age_days')\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    processed = []\n    for invoice in raw_invoices:\n        if not isinstance(invoice, dict):\n            continue\n        if currency is not None and invoice.get('currency') != currency:\n            continue\n        inv_id = invoice.get('id')\n        created = invoice.get('created', invoice.get('created_day', 0))\n        lines = invoice.get('lines') or []\n        fee = invoice.get('fee_cents', 0)\n        try:\n            fee_cents = int(fee)\n        except Exception:\n            fee_cents = 0\n        principal = principal_cents(lines, rounding)\n        charge = principal + fee_cents\n        if charge < min_invoice_cents:\n            continue\n        events = invoice.get('events') or []\n        deduped_map = {}\n        no_eid_counter = 0\n        for event in events:\n            if not isinstance(event, dict):\n                continue\n            eid = event.get('eid', event.get('id'))\n            if eid is None:\n                key = ('__no_eid__', no_eid_counter)\n                no_eid_counter += 1\n            else:\n                key = eid\n            if duplicate_event == 'last':\n                deduped_map[key] = event\n            else:\n                if key not in deduped_map:\n                    deduped_map[key] = event\n        deduped = list(deduped_map.values())\n        if refunds_first:\n            deduped = [e for e in deduped if event_kind(e) == 'refund'] + [e for e in deduped if event_kind(e) != 'refund']\n        active = True\n        tombstoned = False\n        refunded = 0\n        ceiling = principal + (fee_cents if fee_refundable else 0)\n        for event in deduped:\n            kind = event_kind(event)\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 = event.get('day', event.get('created', created))\n                try:\n                    age = day - created\n                except Exception:\n                    continue\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 = event_cents(event)\n                if refunded + cents > ceiling:\n                    if refund_overflow == 'reject':\n                        continue\n                    else:\n                        remaining = ceiling - refunded\n                        if remaining > 0:\n                            refunded += remaining\n                else:\n                    refunded += cents\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() == 'title':\n            status = status.title()\n        else:\n            status = status.lower()\n        result = {'id': inv_id, 'charge': charge, 'refunded': refunded, 'balance': charge - refunded, 'status': status}\n        processed.append((created, inv_id, result))\n    if order == 'created':\n        processed.sort(key=lambda item: (item[0], item[1]))\n    else:\n        processed.sort(key=lambda item: item[1])\n    return {'invoices': [item[2] for item in processed]}\n", "policy.py": "POLICY = {'currency': 'CAD', 'duplicate_event': 'last', 'fee_refundable': False, 'inclusive_limit': False, 'max_refund_age_days': 45, 'min_invoice_cents': 25, 'order': 'created', 'refund_overflow': 'reject', 'refunds_first': False, 'rounding': 'invoice', 'status_case': 'upper', 'void_is_tombstone': False}\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 _round_cents(decimal_dollars):\n    return int((decimal_dollars * Decimal('100')).quantize(Decimal('1'), rounding=ROUND_HALF_UP))\n\ndef principal_cents(lines, rounding):\n    decimals = [_to_decimal(line) for line in lines]\n    if rounding == 'per_line':\n        return sum(_round_cents(d) for d in decimals)\n    total = sum(decimals, Decimal('0'))\n    return _round_cents(total)\n\ndef event_kind(event):\n    kind = event.get('kind', event.get('type', ''))\n    return str(kind).lower() if kind is not None else ''\n\ndef event_cents(event):\n    for key in ('cents', 'amount_cents', 'refund_cents', 'amount'):\n        if key in event and event.get(key) is not None:\n            try:\n                return int(event.get(key))\n            except Exception:\n                return 0\n    return 0\n"}}