package com.imprimelibros.erp.redsys; import com.imprimelibros.erp.payments.PaymentService; import com.imprimelibros.erp.payments.model.Payment; import com.imprimelibros.erp.redsys.RedsysService.FormPayload; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.nio.charset.StandardCharsets; import java.util.UUID; @Controller @RequestMapping("/pagos/redsys") public class RedsysController { private final PaymentService paymentService; public RedsysController(PaymentService paymentService) { this.paymentService = paymentService; } @PostMapping(value = "/crear", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) @ResponseBody public ResponseEntity crearPago(@RequestParam("amountCents") Long amountCents, @RequestParam("method") String method) throws Exception { if ("bank-transfer".equalsIgnoreCase(method)) { // 1) Creamos el Payment interno SIN orderId (null) Payment p = paymentService.createBankTransferPayment(null, amountCents, "EUR"); // 2) Mostramos instrucciones de transferencia String html = """ Pago por transferencia

Pago por transferencia bancaria

Hemos registrado tu intención de pedido.

Importe: %s €

IBAN: ES00 1234 5678 9012 3456 7890

Concepto: TRANSF-%d

En cuanto recibamos la transferencia, procesaremos tu pedido.

Volver al resumen

""".formatted( String.format("%.2f", amountCents / 100.0), p.getId() // usamos el ID del Payment como referencia ); byte[] body = html.getBytes(StandardCharsets.UTF_8); return ResponseEntity.ok() .contentType(MediaType.TEXT_HTML) .body(body); } // Tarjeta o Bizum (Redsys) FormPayload form = paymentService.createRedsysPayment(null, amountCents, "EUR", method); String html = """ Redirigiendo a Redsys…
""".formatted( form.action(), form.signatureVersion(), form.merchantParameters(), form.signature()); byte[] body = html.getBytes(StandardCharsets.UTF_8); return ResponseEntity.ok() .contentType(MediaType.TEXT_HTML) .body(body); } // GET: cuando el usuario cae aquí sin parámetros, o Redsys redirige por GET @GetMapping("/ok") @ResponseBody public ResponseEntity okGet() { String html = """

Pago procesado

Si el pago ha sido autorizado, verás el pedido en tu área de usuario o recibirás un email de confirmación.

Volver a la tienda

"""; return ResponseEntity.ok(html); } // POST: si Redsys envía Ds_Signature y Ds_MerchantParameters (muchas // integraciones ni lo usan) @PostMapping(value = "/ok", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) @ResponseBody public ResponseEntity okPost(@RequestParam("Ds_Signature") String signature, @RequestParam("Ds_MerchantParameters") String merchantParameters) { try { // opcional: idempotente, si /notify ya ha hecho el trabajo no pasa nada paymentService.handleRedsysNotification(signature, merchantParameters); return ResponseEntity.ok("

Pago realizado correctamente

Volver"); } catch (Exception e) { return ResponseEntity.badRequest() .body("

Error validando pago

" + e.getMessage() + "
"); } } @GetMapping("/ko") @ResponseBody public ResponseEntity koGet() { return ResponseEntity.ok("

Pago cancelado o rechazado

Volver"); } @PostMapping(value = "/ko", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) @ResponseBody public ResponseEntity koPost( @RequestParam("Ds_Signature") String signature, @RequestParam("Ds_MerchantParameters") String merchantParameters) { try { // Procesamos la notificación IGUAL que en /ok y /notify paymentService.handleRedsysNotification(signature, merchantParameters); // Mensaje para el usuario (pago cancelado/rechazado) String html = "

Pago cancelado o rechazado

Volver"; return ResponseEntity.ok(html); } catch (Exception e) { // Si algo falla al validar/procesar, lo mostramos (útil en entorno de pruebas) String html = "

Error procesando notificación KO

" + e.getMessage() + "
"; return ResponseEntity.badRequest().body(html); } } @PostMapping(value = "/notify", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) @ResponseBody public String notifyRedsys(@RequestParam("Ds_Signature") String signature, @RequestParam("Ds_MerchantParameters") String merchantParameters) { try { paymentService.handleRedsysNotification(signature, merchantParameters); return "OK"; } catch (Exception e) { e.printStackTrace(); // 👈 para ver el motivo del 500 en logs return "ERROR"; } } @PostMapping(value = "/refund/{paymentId}", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) @ResponseBody public ResponseEntity refund(@PathVariable Long paymentId, @RequestParam("amountCents") Long amountCents) { try { String idem = "refund-" + paymentId + "-" + amountCents + "-" + UUID.randomUUID(); paymentService.refundViaRedsys(paymentId, amountCents, idem); return ResponseEntity.ok("Refund solicitado"); } catch (Exception e) { return ResponseEntity.badRequest().body("Error refund: " + e.getMessage()); } } }