from typing import Any from . import config, db, payoneer from .schemas import FailureItem, PendingItem, ResponseSchema, UpdateItem PAYONEER_TO_INTERNAL_STATUS: dict[str, str] = { "Transferred": "complete", "Cancelled": "rejected", } def run(event: dict[str, Any]) -> ResponseSchema: dp_payment_ids = event.get("dp_payment_ids", []) abacus_sp_ids = event.get("abacus_statement_period_ids", []) limit = event["limit"] dry_run = event["dry_run"] request_timeout_seconds = event["request_timeout_seconds"] auth_token = config.get_payoneer_auth_token() payments = db.fetch_target_payments( dp_payment_ids=dp_payment_ids, abacus_sp_ids=abacus_sp_ids, limit=limit ) updates: list[UpdateItem] = [] pending_payments: list[PendingItem] = [] failures: list[FailureItem] = [] unchanged = 0 changed = 0 for payment in payments: dp_payment_id = int(payment["dp_payment_id"]) try: payout_result = payoneer.fetch_payout_status( api_url=config.PAYONEER_API_URL, auth_token=auth_token, program_id=str(payment["payoneer_program_id"]), client_reference_id=str(payment["payoneer_payment_id"]), timeout_seconds=request_timeout_seconds, ) payout_status = payout_result["status"] if payout_status == "Pending": pending_payments.append( PendingItem( dp_payment_id=dp_payment_id, reason_code=payout_result["reason_code"], reason_description=payout_result["reason_description"], ) ) continue internal_status = PAYONEER_TO_INTERNAL_STATUS.get(payout_status) if internal_status is None: raise ValueError(f"Unknown Payoneer status: {payout_status!r}") row_changed = payment["payoneer_payment_status"] != internal_status if row_changed: changed += 1 updates.append( { "dp_payment_id": dp_payment_id, "old_status": payment["payoneer_payment_status"], "payoneer_status": internal_status, "changed": row_changed, "reason": payout_result["reason_description"], } ) else: unchanged += 1 except Exception as exc: # noqa: BLE001 failures.append( FailureItem( dp_payment_id=dp_payment_id, program_id=payment["payoneer_program_id"], client_reference_id=payment["payoneer_payment_id"], payoneer_request_url=f"{config.PAYONEER_API_URL.rstrip('/')}/v4/programs/{payment['payoneer_program_id']}/payouts/{payment['payoneer_payment_id']}/status", reason=str(exc), ) ) if not dry_run and updates: update_tuples = [ (update["dp_payment_id"], update["payoneer_status"], update["reason"]) for update in updates if update["changed"] ] if update_tuples: changed = db.update_payoneer_status_bulk(update_tuples) response: ResponseSchema = { "dry_run": dry_run, "scanned": len(payments), "changed": changed, "unchanged": unchanged, "pending": len(pending_payments), "failed": len(failures), "updates": updates, } if pending_payments: response["pending_payments"] = pending_payments if failures: response["failures"] = failures return response