36 lines
2.6 KiB
Markdown
36 lines
2.6 KiB
Markdown
# ADR 0013: Model bank-paid, verified, and merchant-fee semantics
|
|
|
|
- Status: Accepted
|
|
- Date: 2026-08-20
|
|
|
|
## Context
|
|
|
|
The source exposes session states `Paid`, `Verified`, `Failed`, and `Reversed`, but names alone did not establish business meaning. Authoritative clarification from ZarinPal's CTO defines a two-step lifecycle: the buyer first completes payment at the bank, then the merchant calls verification. `Paid` means the bank payment succeeded and funds were deducted but merchant verification is incomplete. `Verified` means both steps completed. `Reversed` is possible but extremely rare; the dataset contains one such session.
|
|
|
|
The challenge field `adjusted_fee` was transformed/name-adjusted for participant confidentiality, but the product domain treats it as the merchant's real fee. Profiling found its value constant within every session: 150,450 repeated attempt rows and zero fee conflicts.
|
|
|
|
## Decision
|
|
|
|
Use these canonical populations:
|
|
|
|
- bank-paid: session status in (`Paid`, `Verified`);
|
|
- verified/finalized: session status `Verified`;
|
|
- unverified paid: session status `Paid`;
|
|
- unsuccessful current outcome: `Failed` or `Reversed` for the MVP success-rate denominator.
|
|
|
|
Define payment success rate as bank-paid sessions divided by sessions in (`Paid`, `Verified`, `Failed`, `Reversed`). Keep unknown future statuses out of numerator/denominator and report their coverage until explicitly classified. Define verification completion rate as `Verified / (Paid + Verified)`.
|
|
|
|
Paid amount is the session amount summed once for (`Paid`, `Verified`). Also expose verified amount and unverified-paid amount as explicit subsets. Never call `Paid` a failure.
|
|
|
|
A retried session has more than one attempt. An eventually paid retry has final session status `Paid` or `Verified` and at least one lower-`try_seq` attempt whose status is neither `Paid` nor `Verified`; CSV row order is irrelevant.
|
|
|
|
Rename source `adjusted_fee` to canonical `fee_amount_rial`, store it once on the session, and present it as a real Rial merchant fee. Paid fee totals sum it once for bank-paid sessions. Fee rate is `sum(paid session fee) / sum(paid session amount)` with numerator, denominator, period, and unit visible.
|
|
|
|
## Consequences
|
|
|
|
- Dashboard success combines `Paid` and `Verified`, while verification health separates them.
|
|
- The unverified-paid count/amount is an actionable merchant discrepancy, not a failed-payment metric.
|
|
- Retry recovery may end in either `Paid` or `Verified`.
|
|
- Fee aggregation uses session grain and cannot multiply fees by retry count.
|
|
- Unknown statuses require a metric-catalogue change rather than being guessed into success or failure.
|