Ішінара және толық рефандтар
TL; DR
Рефанд - бұл captured сомасы бойынша кері операция. Толық транзакцияны толық жабады, ішінара бөлігін қайтарады (толық дейін partial сериясы болуы мүмкін). Сыни: refund-to-source, қатаң демпотенттілік, себептерді тіркеу және вебхукпен/ретрамен оркестрлеу. Біз Refund Rate, TtR p95, Refund Error өлшейміз және авто-салыстыру арқылы екі/сәйкессіздіктерді жоямыз.
1) Терминдер мен принциптік айырмашылықтар
Full Refund - барлық тіркелген соманы қайтару ('refund _ amount = capture_amount').
Partial Refund - ('0 <refund_amount <capture_amount') бөлігін қайтару, қалған partial жиынтық' capture _ amount 'дейін рұқсат етеді.
Refund to Source - төлемнің бастапқы әдісіне/рельстеріне қайтару (реттеушілік тұрғыдан дұрыс/міндетті).
Void - capture дейін болдырмау (егер рельстермен қолдау көрсетілсе) рефанд болып есептелмейді.
Reversal/Chargeback - сіздің бастамаңыздан тыс банктік/рельстік механиктер (даулар, чарджбэктер) - рефандамен шатастырмау керек.
2) Толық vs ішінара қашан беру
Толық (Full):- Тапсырысты/қызметті тұтастай алып тастау, қайталанатын есептен шығару, жүйелік қате.
- Қызмет көрсетілмеген жағдайда міндетті (тұтынушының/реттеушінің ережелері бойынша).
- Қызметтің ішінара күшін жою, барабар түзетулер (жеңілдіктер, кешіктірулердің өтемақылары).
- Рельстің техникалық лимиттері (бір операция үшін ең көп сома) - partial сериясы.
- Постфактум комиссияларды ұстап қалу (реттеушілік рұқсат етілген) - iGaming-те сирек.
3) Саясат пен лимиттер
Әдепкі бойынша refund-to-source = true; ерекшеліктер - МLRO/комплаенс-кейстер арқылы (логикаланады).
Cut-off: рефандаларға capture сәтінен бастап N күн рұқсат етіледі (әдіс/юрисдикция бойынша).
Max Partial Count: payment үшін K partial артық емес (типтік K ≤ 5).
Min Partial Amount: рельс/PSP техникалық минимумынан төмен емес.
- Саппорт агенті: partial ≤ X, full ≤ Y.
- Менеджер/қаржы: лимиттерден жоғары, кросс-әдістемелік ерекшеліктер.
- Cooling-off қайта әрекеттер (анти-дребезг).
4) Сәулет және оқиғалар ағыны
Компоненттер:- Payment Orchestrator - мәртебелердің ақиқат көзі.
- Refund Service - API, іспеттілік, ретрайлерді оркестрлеу, журналдау.
- PSP Adapters - әдістер бойынша интеграция.
- Reconciliation - авто-салыстыру, DLQ, түзету.
- Ledger/Accounting - сымдар, деферлер, клирингтермен тегістеу.
- Risk/Compliance - даулы сценарийлер кезінде санкцияларға/SoF-ке тексерулер.
1. `Refund. Create '(API) → валидация (лимиттер, қалдық, policy, KYC/SoF қажет болған жағдайда).
2. Генерация idempotency_key (`hash(payment_id + refund_amount + reason + nonce)`).
3. PSP → 'PENDING' мәртебесін шақыру.
4. Вебхук/поллинг → 'SUCCESS '/' FAILED'; тайм-аутта - сол кілтпен ретра.
5. Кафкадағы оқиғаны жариялау → Ledger, BI, алерта.
6. Автосалыстыру: 'provider _ refund _ id' дегенді тізіліммен салыстыру.
5) Іспеттестік және анти-дубли
Бір рефанд екі рет есептелмейді: барлық логика idempotency storage (KV/Redis + TTL) арқылы.
Кілттер payment_id × amount × reason (және қажет болған жағдайда 'partial _ index').
Ретрайлер сол кілтті пайдаланады.
Параллель partial row-level locks/optimistic version aggregate сомасына қорғалады.
python def refund(payment_id, amount, reason, idem_key):
if idem_store. exists(idem_key): return idem_store. get(idem_key)
with tx():
p = db. get_payment(payment_id, for_update=True)
assert p. captured_amount - p. refunded_amount >= amount > 0 r = p. create_refund(amount, reason, status='PENDING', idem_key=idem_key)
resp = psp. refund(p. provider_txid, amount, idem_key)
return finalize(r, resp. status, resp. ext_id)
6) Деректер моделі (ең аз жеткілікті)
json
{
"payment_id": "pay_123",
"captured_amount": 150. 00,
"currency": "EUR",
"refunded_amount": 40. 00,
"refunds": [
{
"refund_id": "rf_001",
"type": "partial full",
"amount": 20. 00,
"reason_code": "PARTIAL_SERVICE",
"idempotency_key": "idem_a1",
"status": "PENDING SUCCESS FAILED",
"provider_refund_id": "psp_rf_9xz",
"created_at": "2025-11-03T12:00:00Z",
"credited_at": "2025-11-03T15:05:00Z",
"notes": "ticket #456"
}
],
"flags": {
"refund_to_source": true,
"jurisdiction": "EEA",
"kyc_tier_required": "tier2"
}
}
7) Төлем рельстері бойынша ерекшеліктер
Карталар (Visa/Mastercard)
full/partial; жиі бірнеше partial; TtR клиенттің банкіне байланысты (T + 1... T + 5 б.д.).
Сәттілік туралы веб-хаттар тез келеді, бірақ шығарылым кешігуі мүмкін → саппорт үлгілерінде түсіндіріледі.
A2A/Open Banking/RTP
Жиі жедел қайтару (reversal/credit push); кейбір провайдерлер тек full немесе 1 partial қызметін қолдайды.
Бастапқы шотқа қатаң байланыстыру; refund-to-source міндетті.
Электрондық әмияндар
Қалыпты full/partial; TtR минутпен; partial саны және ең төменгі сома бойынша шектеулер.
Ваучерлер/Prepaid
Әдетте refund-to-source қол жетімді емес → саясат: ішкі әмиянға немесе re-issue ваучеріне қайтару (егер провайдер мүмкін болса). Комплаенс-ескертпелерді талап етеді.
Крипто
Рельстер - құбылмалы; рефанд әдісі ретінде пайдаланбаған дұрыс. Егер рұқсат етілсе: құжатталған бағамы және комиссиялары бар сол мекенжайға/биржаға қайтару; AML скринингі.
8) Есеп, салыстырып тексеру және қаржы
Ledger: 'DR Revenue/CR Cash' сымдары capture кезінде; refund кезінде - кері жазбалар. Partial пропорционалды түрде көрсетіледі.
Recognition: iGaming рефандында тиісті кезеңнің GGR азайтады (есеп саясаты).
Reconciliation: күнделікті салыстыру 'merchant _ refund _ id provider_refund_id', мәртебесі, сомасы, FX курстары.
FX: курстардың логикасын (capture сәтінде немесе refund сәтінде) қолдануға болатын жерде белгілеңіз; спредтердің торын ұстаңыз.
9) KPI, мақсаттар және тәуекелдер (Refund Health)
Refund Rate = 'Refunded _ Tx/ Captured_Tx' (саралау: себептер бойынша).
Refund Amount Ratio = `Refunded_Amount / Captured_Amount`.
TtR p95 = p95 ('credited _ at - created_at') әдісі бойынша.
Refund Error Rate = `Failed / Attempted` (<0. 3%).
Refund-to-Source% ≥ 95% (қол жетімді жерде).
Double Refund Incidents = 0.
- 'TtR p95' SLO-дан → P2 әдісі бойынша жоғары.
- «Refund Rate» бойынша Spikes бір провайдерде/BIN → P1 (қармау/дубликаттарды тексеру).
- Кез келген 'Double Refund> 0' → P0 (авто-рефандтарды дереу мұздату).
10) SQL кесінділері
10. 1 Рефанд профилі
sql
SELECT
DATE_TRUNC('day', r. created_at) AS d,
method_code, provider,
COUNT() FILTER (WHERE r. status='SUCCESS') AS refunds_ok,
COUNT() FILTER (WHERE r. status='FAILED') AS refunds_fail,
SUM(r. amount) AS refunded_amount,
PERCENTILE_CONT(0. 95) WITHIN GROUP (ORDER BY EXTRACT(EPOCH FROM (r. credited_at - r. created_at))) AS ttr_p95_sec
FROM refunds r
JOIN payments p ON p. payment_id = r. payment_id
GROUP BY 1,2,3;
10. 2 Partial үшін қалдықты бақылау
sql
SELECT p. payment_id,
p. captured_amount,
SUM(r. amount) AS refunded_sum,
(p. captured_amount - SUM(r. amount)) AS refundable_left
FROM payments p
LEFT JOIN refunds r ON r. payment_id = p. payment_id AND r. status IN ('SUCCESS','PENDING')
GROUP BY 1,2
HAVING (p. captured_amount - SUM(r. amount)) < 0;
11) UX және саппорт
Әдістер бойынша хабарламалардың үлгілері: карталар бойынша үзіндідегі мүмкін болатын кідірісті түсіндіреміз, A2A - бір сәтте.
Кабинеттегі мәртебелер: 'Ресімделген → Өңдеуде → Қайтарылған'; күтілетін қабылдау күнін көрсету.
Себептер (reason_code) - адам оқитын: «Есептен шығаруды қайталау», «Қызметтің күшін жою», «Ішінара өтемақы».
Self-service partial - лимиттермен және нақты ережелермен ғана қауіпсіз.
12) Тәуекел және комплаенс
Жууға қарсы: рефанд баламалы арнаға шықпауы тиіс; МLRO мақұлдауымен ерекшеліктерді белгілеңіз.
Санкциялар/ТШ: «қызыл» шоттарға бастамашылық жасалған қайтарулар кезінде/деректемелер - міндетті тексеру.
DSAR/Retention: деректерді сақтау саясаты аясында рефандалардың іздерін сақтаңыз.
Жергілікті ережелер: қайтару мерзімдері мен тәртібі (мысалы, тұтыну регламенттері) - policy-де көрсетеміз.
13) Жиі қателер және оларды болдырмау
Қосарланған рефанд демпотенттік және қайталанған вебхуктардың жоқтығынан → idem-кілтті/мәртебені сақтау, қалдықты тексеру.
Partial> қалдық → row-lock/optimistic version және қатаң тексерулер.
Комплаенс рұқсатсыз cross-method refund → refund-to-source бұзады.
void және refund араластыру → KPI бұрмалау.
PSP мен сіздің леджеріңіз арасында «қара тесіктер» жоқ.
14) Ойнатқыштар
Провайдер бойынша қайтарымдардың өсуі → авторизациялық ақауларды/capture дублдерін тексеру, фейловерді қосу, PSP-мен байланыс.
Жаппай partial-өтемақы (кампания) → partial лимитін көтеру, топтық операцияларды қосу, салыстыруларды күшейту.
Вебхуктар қатесі → поллингке ауысу, TTL сәйкестігін ұлғайту, авто-рефанданы кейінге қалдыру.
refund-to-source ерекшелігі (сирек) → MLRO эскалациясы, құжатталған төлем және 'comp _ approved = true' белгісі.
15) Тест-кейстер (UAT/Prod)
1. Бір capture → кейін Full refund қалдықты дұрыс нөлдейді.
2. partial сериясы (3 ×) → capture ≤ сомасы; содан кейін қалдыққа full.
3. Теңсіздік: бір сұрауды қайталау → 1 нәтиже.
4. Вебхук-дребезг: 3 бірдей хабарлама → бір есептен шығару/қабылдау.
5. Салыстыру: жасанды mismatch → алерт және автоматты түзету.
6. Құқықтарды шектеу: агент partial лимитінен аспайды.
7. Cut-off: кеш рефанданың әрекеті → дұрыс бас тарту және логизация.
16) Енгізудің бақылау чек-парағы
- Юрисдикциялар/әдістер бойынша full/partial + refund-to-source саясаты.
- Идемпотенттік, ретрайлер, вебхукилер және поллинг, DLQ.
- Қайтару және reason_code қалдығы бар деректер моделі.
- Леджер және күнделікті авто-салыстыру.
- KPI/дашборд: Refund Rate, TtR, Error, Double Refund = 0.
- Құқықтар мен аппрув-матрица, саппорт үлгілері.
- UAT тест-кейстері және прод-деңгейдегі алерталар.
Түйіндеме
Рефандтарды басқару - бұл процестердің қатаң тәртібі: refund-to-source, іспеттілік, деректердің мөлдір моделі, авто-салыстыру және partial/full түсінікті саясаты. Мұндай негіздермен сіз TtR-ді төмен ұстайсыз, қателіктер - нөлде, екеуінде - мүмкін емес, ал комплаенс пен қаржы - бизнес мақсаттарымен үйлестірілген.