# collaborator-payoneer-status-sync

Lambda function that backfills Payoneer payout statuses on `dp_payment` records.

It fetches DP payments that have a Payoneer program/payment ID but no recorded status, queries the Payoneer payout status API for each, maps the result to an internal status, and optionally writes the updates back to the database.

---

## How it works

1. Queries `dp_payment` rows where `payoneer_payment_status IS NULL` and both `payoneer_program_id` and `payoneer_payment_id` are set.
2. For each payment, calls the Payoneer payout status endpoint.
3. Maps the Payoneer status to an internal value:

   | Payoneer API status | Webhook event       | Internal status |
   |---------------------|---------------------|-----------------|
   | `Transferred`       | `payment_completed` | `complete`      |
   | `Cancelled`         | `payment_cancelled` | `rejected`      |

   `Pending` payments are **not** mapped — they are skipped and reported separately in `pending_payments` with their `reason_code` and `reason_description` for manual review.

4. If `dry_run` is `false`, bulk-updates all changed rows.
5. Returns a summary of scanned, changed, unchanged, pending, and failed payments.

---

## Event schema

```json
{
  "dp_payment_ids": [1, 2, 3],
  "abacus_statement_period_ids": [10, 11],
  "limit": 500,
  "dry_run": true,
  "request_timeout_seconds": 10
}
```

| Field                         | Type      | Default | Description                                                   |
|-------------------------------|-----------|---------|---------------------------------------------------------------|
| `dp_payment_ids`              | int[]     | `[]`    | Filter to specific DP payment IDs                             |
| `abacus_statement_period_ids` | int[]     | `[]`    | Filter to payments belonging to specific statement periods    |
| `limit`                       | int       | `500`   | Max number of payments to process (1–5000)                    |
| `dry_run`                     | bool      | `true`  | If `true`, fetches statuses but does not write to the DB      |
| `request_timeout_seconds`     | int       | `10`    | Payoneer API request timeout (1–120)                          |

If both `dp_payment_ids` and `abacus_statement_period_ids` are provided, `abacus_statement_period_ids` takes precedence. If neither is set, all eligible payments up to `limit` are processed.

---

## Running locally

```bash
# Install dependencies
make env

# Dry run (default) — fetches statuses, no DB writes
poetry run python dev.py

# Filter by specific DP payment IDs
poetry run python dev.py --dp-payment-id 123 --dp-payment-id 456

# Apply updates to the database
poetry run python dev.py --apply

# Full options
poetry run python dev.py --dp-payment-id 123 --limit 100 --apply --request-timeout-seconds 30
```

Requires a `.env` file with the following variables (see `.env.shadow`):

```
DB_COLLABORATORS_HOST=
DB_COLLABORATORS_USERNAME=
DB_COLLABORATORS_PASSWORD=

PAYONEER_API_URL=
PAYONEER_AUTH_TOKEN=
```

---

## Development

```bash
# Lint + type check + tests (what CI runs)
make unit_lint

# Tests only
make test

# Lint only
make lint

# Auto-format
make format
```

---

## Environment variables

| Variable                       | Required | Description                                                                  |
|--------------------------------|----------|------------------------------------------------------------------------------|
| `DB_COLLABORATORS_HOST`        | Yes      | MySQL host for the collaborators database                                    |
| `DB_COLLABORATORS_USERNAME`    | Yes      | MySQL username                                                               |
| `DB_COLLABORATORS_PASSWORD`    | Yes      | MySQL password (fetched from Secrets Manager in QA/prod)                     |
| `PAYONEER_API_URL`             | No       | Payoneer API base URL (default: `https://api.payoneer.com`)                  |
| `PAYONEER_AUTH_TOKEN`          | No       | Bearer token for the Payoneer API — use for local dev                        |
| `PAYONEER_AUTH_TOKEN_SECRET_ID`| No       | Secrets Manager secret ID to fetch the bearer token — used in QA/prod        |
| `ENVIRONMENT`                  | No       | Deployment environment (`qa`, `prod`). Controls secret resolution behaviour  |

In QA and prod, `PAYONEER_AUTH_TOKEN_SECRET_ID` is set by terraform and points to the `ows-payee/payoneer_auth_token` secret. For local development, set `PAYONEER_AUTH_TOKEN` directly in `.env`.
