terminado pagos

This commit is contained in:
2025-11-06 13:49:15 +01:00
parent 62396eb7a7
commit f13eeb940c
18 changed files with 3552 additions and 12 deletions

View File

@ -312,7 +312,7 @@ public class PaymentService {
tx.setCurrency(currency);
// tx.setProcessedAt(null); // la dejas nula hasta que se confirme
txRepo.save(tx);
return p;
}
@ -358,6 +358,84 @@ public class PaymentService {
}
}
/**
* Devuelve (total o parcialmente) un pago hecho por transferencia bancaria.
* - Solo permite gateway = "bank_transfer".
* - Crea un Refund + PaymentTransaction de tipo REFUND.
* - Actualiza amountRefundedCents y el estado del Payment.
*/
@Transactional
public Refund refundBankTransfer(Long paymentId, long amountCents) {
Payment p = payRepo.findById(paymentId)
.orElseThrow(() -> new IllegalArgumentException("Payment no encontrado: " + paymentId));
if (!"bank_transfer".equals(p.getGateway())) {
throw new IllegalStateException("El Payment " + paymentId + " no es de tipo bank_transfer");
}
if (amountCents <= 0) {
throw new IllegalArgumentException("El importe de devolución debe ser > 0");
}
// Solo tiene sentido devolver si está capturado o ya parcialmente devuelto
if (p.getStatus() != PaymentStatus.captured
&& p.getStatus() != PaymentStatus.partially_refunded) {
throw new IllegalStateException(
"El Payment " + paymentId + " no está capturado; estado actual: " + p.getStatus());
}
long maxRefundable = p.getAmountCapturedCents() - p.getAmountRefundedCents();
if (amountCents > maxRefundable) {
throw new IllegalStateException(
"Importe de devolución supera lo todavía reembolsable. " +
"maxRefundable=" + maxRefundable + " requested=" + amountCents);
}
LocalDateTime now = LocalDateTime.now();
// 1) Crear Refund (para transferencias lo marcamos como SUCCEEDED directamente)
Refund refund = new Refund();
refund.setPayment(p);
refund.setAmountCents(amountCents);
// reason usa el valor por defecto (customer_request); si quieres otro, cámbialo
// aquí
refund.setStatus(RefundStatus.succeeded);
refund.setRequestedAt(now);
refund.setProcessedAt(now);
// requestedByUserId, notes, metadata -> opcionales, déjalos en null si no los
// usas
refund = refundRepo.save(refund);
// 2) Crear transacción de tipo REFUND
PaymentTransaction tx = new PaymentTransaction();
tx.setPayment(p);
tx.setType(PaymentTransactionType.REFUND);
tx.setStatus(PaymentTransactionStatus.succeeded);
tx.setAmountCents(amountCents);
tx.setCurrency(p.getCurrency());
tx.setProcessedAt(now);
// gatewayTransactionId lo dejamos null → el índice UNIQUE permite múltiples
// NULL
tx = txRepo.save(tx);
// Vincular el Refund con la transacción
refund.setTransaction(tx);
refundRepo.save(refund);
// 3) Actualizar Payment: total devuelto y estado
p.setAmountRefundedCents(p.getAmountRefundedCents() + amountCents);
if (p.getAmountRefundedCents().equals(p.getAmountCapturedCents())) {
p.setStatus(PaymentStatus.refunded);
} else {
p.setStatus(PaymentStatus.partially_refunded);
}
payRepo.save(p);
return refund;
}
private boolean isRedsysAuthorized(RedsysService.RedsysNotification notif) {
if (notif.response == null) {
return false;