Refandos parciales y completos
TL; DR
Refand es la operación inversa de la cantidad capturada. El completo cierra la transacción en su totalidad, el parcial devuelve la parte (puede haber una serie parcial hasta el completo). Crítico: refund-to-source, idempotencia estricta, revista de causas, y orquestación con webhooks/retraídas. Medimos Refund Rate, TtR p95, Refund Error y eliminamos las tomas/inconsistencias a través de las conciliaciones automáticas.
1) Términos y diferencias de principios
Full Refund: devuelve toda la cantidad fijada ('refund _ amount = capture_amount').
Refund parcial: devuelve una parte ('0 <refund_amount <capture_amount'), permite el resto de la parte hasta el' capture _ amount 'total.
Refund to Source (Refund to Source): devuelve el método/raíles de pago original (preferiblemente/obligatorio).
Void - Cancelar hasta capture (si está soportado por raíles), no se considera un refando.
Reversal/Chargeback - mecánica bancaria/ferroviaria fuera de su iniciativa (disputas, charjbacks) - no confundir con refand.
2) Cuándo emitir completo vs parcial
Completo (Full):- Cancelación del pedido/servicio en su totalidad, cargo duplicado, error del sistema.
- Obligatorio en la prestación fallida del servicio (según las normas del consumidor/regulador).
- Cancelación parcial del servicio, ajustes proporcionales (descuentos, compensación por retraso).
- Los límites técnicos del riel (suma máxima por operación) son una serie parcial.
- La retención de comisiones post-factum (donde se permite regulativamente) es menos frecuente en iGaming.
3) Políticas y límites
Refund-to-source = true por defecto; excepciones - a través de MLRO/casos de cumplimiento (lógico).
Cut-off: los refandos se permiten N días desde el momento de la captura (por método/jurisdicción).
Max Partial Count: no más de K parcial en pago (típicamente K ≤ 5).
Min Parcial Amount: no por debajo del mínimo técnico de riel/PSP.
- Agente de sapport: parcial ≤ X, full ≤ Y.
- Gestor/finanzas: más de límites, excepciones de método cruzado.
- Cooling-off para volver a intentarlo (anti-drebesg).
4) Arquitectura y flujo de eventos
Componentes:- Payment Orchestrator es la fuente de la verdad de los estados.
- Servicio de Refundición - API, idempotencia, orquestación de retrés, revista.
- Adaptadores PSP - Integraciones por métodos.
- Reconciliation - auto-conciliación, DLQ, correcciones.
- Ledger/Accounting - cableado, defer, alineación con compensación.
- Risk/Compliance - verificaciones de sanciones/SoF en escenarios controvertidos.
1. `Refund. Crear '(API) → validación (límites, residuo, política, KYC/SoF si es necesario).
2. Генерация idempotency_key (`hash(payment_id + refund_amount + reason + nonce)`).
3. La llamada PSP → el estado 'PENDING'.
4. Webhook/polling → 'SUCCESS'/' FAILED'; en tiempo de espera, retrés con la misma clave.
5. Publicación del evento en Kafka → Ledger, BI, alertas.
6. Conciliación automática: correlación de 'provider _ refund _ id' con el registro.
5) Idempotencia y anti-toma
El mismo refando no puede ser acreditado dos veces: toda la lógica a través del almacenamiento idempotency (KV/Redis + TTL).
Las claves de payment_id × amount × reason (y, si es necesario, 'partial _ index').
Los retraídos usan la misma clave.
Las partes paralelas están protegidas por la versión row-level locks/optimistic en sumas 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) Modelo de datos (mínimo suficiente)
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) Características de los carriles de pago
Tarjetas (Visa/Mastercard)
Admiten full/partial; a menudo varias partes; TtR depende del banco del cliente (T + 1... T + 5 b.d.).
Los webhooks sobre el éxito llegan rápidamente, pero la inscripción en el extracto puede retrasarse → explicarse en las plantillas de sapport.
A2A/Open Banking/RTP
A menudo, devoluciones instantáneas (reversal/credit push); algunos proveedores sólo admiten full o 1 parte.
Vinculación estricta a la cuenta de origen; refund-to-source es obligatorio.
Monederos
Full/partial normal; TtR por minutos; límites en el número de partes y la cantidad mínima.
Vales/Prepaid
Por lo general, refund-to-source no está disponible → política: devolver a la cartera interna o re-issue el cupón (si el proveedor sabe). Requiere reservas de cumplimiento.
Los rieles son volátiles; preferiblemente no utilizar como método de refando. Si se permite: devoluciones a la misma dirección/intercambio con tasa y comisiones documentadas; Detección de AML.
8) Contabilidad, conciliación y finanzas
Ledger: cableado 'DR Revenue/CR Cash' durante la captura; con refund - entradas inversas. Parte se refleja proporcionalmente.
Reconocimiento: en iGaming, el refando reduce el GGR del período correspondiente (política contable).
Reconciliation: las conciliaciones diarias 'merchant _ refund _ id ↔ provider_refund_id', estados, sumas, cursos FX.
FX: fijar la lógica de los cursos (en el momento de la captura o en el momento de la refundición), cuando corresponda; sostenga la rejilla de spreads.
9) KPI, objetivos y alertas (Refund Health)
Refund Rate = 'Refundado _ Tx/ Captured_Tx' (segmentar: por razones).
Refund Amount Ratio = `Refunded_Amount / Captured_Amount`.
TtR p95 = p95 ('credited _ at - created_at') por método.
Refund Error Rate = `Failed / Attempted` (<0. 3%).
Refund-to-Source% ≥ 95% (donde está disponible).
Double Refund Incidents = 0.
- 'TtR p95' por encima de SLO por el método de → P2.
- Spikes por 'Refund Rate' en un proveedor/BIN → P1 (comprobar capturas/tomas).
- Cualquier 'Doble Refund> 0' → P0 (congelación inmediata de los refundidos automáticos).
10) Cortes SQL
10. 1 Perfil de refundición
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 Control de residuos para la parte
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 y sapport
Plantillas de mensajes por método: las tarjetas explican el posible retraso en el extracto, A2A - casi instantáneamente.
Los estados en el gabinete son: 'Formalizado → En el procesamiento → Devuelto'; mostrar la fecha de inscripción esperada.
Causas (reason_code) - Humanidades: 'Duplicación de cargo', 'Cancelación del servicio', 'Compensación parcial'.
Parte de autoservicio: seguro sólo con límites y reglas claras.
12) Riesgo y cumplimiento
Anti-lavado: el refando no debe convertirse en una derivación a un canal alternativo; fijar las excepciones con la aprobación MLRO.
Sanciones/RR: en devoluciones iniciadas a cuentas/datos «rojos» - verificación obligatoria.
DSAR/Retention: almacene los rastros de refundición como parte de la política de retención de datos.
Reglas locales: los plazos y el orden de las devoluciones (por ejemplo, las regulaciones de consumo) - se reflejan en la política.
13) Errores frecuentes y cómo evitarlos
Doble refando debido a la falta de idempotencia y repetidos webhooks → almacenar la clave/estado idem, comprobar el resto.
Parte> residuo → row-lock/optimistic version y controles estrictos.
Refundición de método cruzado sin resolución de cumplimiento → infringe refund-to-source.
La mezcla de void y refund en los informes → distorsión de KPI.
No hay auto-soldadura → «agujeros negros» entre PSP y su guardabosques.
14) Playbucks
Un aumento de las devoluciones por proveedor → comprobar fallos de autorización/capturas de toma, activar el failover, contacto PSP.
Las compensaciones parciales masivas (campaña) → elevar el límite parcial, habilitar las operaciones grupales, reforzar las conciliaciones.
Error webhooks → cambiar a polling, aumentar la idempotencia TTL, posponer auto-refundiciones.
La excepción refund-to-source (raramente) → la escalada MLRO, el pago documentado y la etiqueta 'amb _ approved = true'.
15) Casos de prueba (UAT/Prod)
1. Full refund después de una captura → anula correctamente el resto.
2. Serie parcial (3 ×) → suma ≤ capture; luego full por el resto.
3. Idempotencia: repetición de la misma consulta → 1 resultado.
4. Webhook-drebezg: 3 notificaciones idénticas → un cargo/matrícula.
5. Conciliaciones: mismatch artificial → alerta y autocorrección.
6. Restricción de derechos: el agente no puede exceder el límite parcial.
7. Cut-off: intento de refundición tardía → fallo correcto y lógica.
16) Lista de comprobación de implementación
- Políticas full/partial + refund-to-source sobre jurisdicciones/métodos.
- Idempotencia, retraídas, webhooks y polling, DLQ.
- Modelo de datos con saldo de retorno y reason_code.
- Ledger y simulacros diarios.
- KPI/dashboard: Refund Rate, TtR, Error, Double Refund = 0.
- Derechos y matriz appruve, patrones de sapport.
- Casos de prueba UAT y alertas de nivel prod.
Resumen
La gestión de refundidos es una estricta disciplina de procesos: refund-to-source, idempotencia, modelo de datos transparente, auto-conciliación y políticas comprensibles de partes/full. Con tales fundamentos se mantiene bajo el TtR, los errores están en cero, las tomas no son posibles y el cumplimiento y las finanzas están sincronizados con los objetivos comerciales.