haciendo datatables de los pagos

This commit is contained in:
2025-11-04 22:03:03 +01:00
parent dc64e40e38
commit ed32f773a4
23 changed files with 434 additions and 37 deletions

View File

@ -4,12 +4,16 @@ import com.imprimelibros.erp.payments.PaymentService;
import com.imprimelibros.erp.payments.model.Payment;
import com.imprimelibros.erp.redsys.RedsysService.FormPayload;
import org.springframework.context.MessageSource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.UUID;
@Controller
@ -17,19 +21,21 @@ import java.util.UUID;
public class RedsysController {
private final PaymentService paymentService;
private final MessageSource messageSource;
public RedsysController(PaymentService paymentService) {
public RedsysController(PaymentService paymentService, MessageSource messageSource) {
this.paymentService = paymentService;
this.messageSource = messageSource;
}
@PostMapping(value = "/crear", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@ResponseBody
public ResponseEntity<byte[]> crearPago(@RequestParam("amountCents") Long amountCents,
@RequestParam("method") String method) throws Exception {
@RequestParam("method") String method, @RequestParam("cartId") Long cartId) throws Exception {
if ("bank-transfer".equalsIgnoreCase(method)) {
// 1) Creamos el Payment interno SIN orderId (null)
Payment p = paymentService.createBankTransferPayment(null, amountCents, "EUR");
Payment p = paymentService.createBankTransferPayment(cartId, amountCents, "EUR");
// 2) Mostramos instrucciones de transferencia
String html = """
@ -55,7 +61,7 @@ public class RedsysController {
}
// Tarjeta o Bizum (Redsys)
FormPayload form = paymentService.createRedsysPayment(null, amountCents, "EUR", method);
FormPayload form = paymentService.createRedsysPayment(cartId, amountCents, "EUR", method);
String html = """
<html><head><meta charset="utf-8"><title>Redirigiendo a Redsys…</title></head>
@ -64,6 +70,7 @@ public class RedsysController {
<input type="hidden" name="Ds_SignatureVersion" value="%s"/>
<input type="hidden" name="Ds_MerchantParameters" value="%s"/>
<input type="hidden" name="Ds_Signature" value="%s"/>
<input type="hidden" name="cartId" value="%d"/>
<noscript>
<p>Haz clic en pagar para continuar</p>
<button type="submit">Pagar</button>
@ -74,7 +81,7 @@ public class RedsysController {
form.action(),
form.signatureVersion(),
form.merchantParameters(),
form.signature());
form.signature(), cartId);
byte[] body = html.getBytes(StandardCharsets.UTF_8);
return ResponseEntity.ok()
@ -84,14 +91,11 @@ public class RedsysController {
// GET: cuando el usuario cae aquí sin parámetros, o Redsys redirige por GET
@GetMapping("/ok")
@ResponseBody
public ResponseEntity<String> okGet() {
String html = """
<h2>Pago procesado</h2>
<p>Si el pago ha sido autorizado, verás el pedido en tu área de usuario o recibirás un email de confirmación.</p>
<p><a href="/cart">Volver a la tienda</a></p>
""";
return ResponseEntity.ok(html);
public String okGet(RedirectAttributes redirectAttrs, Model model, Locale locale) {
String msg = messageSource.getMessage("checkout.success.payment", null, "Pago realizado con éxito. Gracias por su compra.", locale);
model.addAttribute("successPago", msg);
redirectAttrs.addFlashAttribute("successPago", msg);
return "redirect:/cart";
}
// POST: si Redsys envía Ds_Signature y Ds_MerchantParameters (muchas
@ -111,9 +115,12 @@ public class RedsysController {
}
@GetMapping("/ko")
@ResponseBody
public ResponseEntity<String> koGet() {
return ResponseEntity.ok("<h2>Pago cancelado o rechazado</h2><a href=\"/checkout\">Volver</a>");
public String koGet(RedirectAttributes redirectAttrs, Model model, Locale locale) {
String msg = messageSource.getMessage("checkout.error.payment", null, "Error al procesar el pago: el pago ha sido cancelado o rechazado Por favor, inténtelo de nuevo.", locale);
model.addAttribute("errorPago", msg);
redirectAttrs.addFlashAttribute("errorPago", msg);
return "redirect:/cart";
}
@PostMapping(value = "/ko", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)

View File

@ -1,5 +1,6 @@
package com.imprimelibros.erp.redsys;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import sis.redsys.api.ApiMacSha256;
@ -38,7 +39,7 @@ public class RedsysService {
// ---------- RECORDS ----------
// Pedido a Redsys
public record PaymentRequest(String order, long amountCents, String description) {
public record PaymentRequest(String order, long amountCents, String description, Long cartId) {
}
// Payload para el formulario
@ -69,6 +70,13 @@ public class RedsysService {
api.setParameter("DS_MERCHANT_URLOK", urlOk);
api.setParameter("DS_MERCHANT_URLKO", urlKo);
// ✅ Añadir contexto adicional (por ejemplo, cartId)
// Si tu PaymentRequest no lo lleva todavía, puedes pasarlo en description o
// crear otro campo.
JSONObject ctx = new JSONObject();
ctx.put("cartId", req.cartId()); // o req.cartId() si decides añadirlo al record
api.setParameter("DS_MERCHANT_MERCHANTDATA", ctx.toString());
if (req.description() != null && !req.description().isBlank()) {
api.setParameter("DS_MERCHANT_PRODUCTDESCRIPTION", req.description());
}
@ -110,7 +118,7 @@ public class RedsysService {
// 1) Decodificar Ds_MerchantParameters usando la librería oficial
String json = api.decodeMerchantParameters(dsMerchantParametersB64);
// 2) Convertir a Map para tu modelo
Map<String, Object> mp = MAPPER.readValue(json, new TypeReference<>() {
});
@ -174,6 +182,7 @@ public class RedsysService {
public final String response;
public final long amountCents;
public final String currency;
public final Long cartId;
public RedsysNotification(Map<String, Object> raw) {
this.raw = raw;
@ -181,6 +190,24 @@ public class RedsysService {
this.response = str(raw.get("Ds_Response"));
this.currency = str(raw.get("Ds_Currency"));
this.amountCents = parseLongSafe(raw.get("Ds_Amount"));
this.cartId = extractCartId(raw.get("Ds_MerchantData"));
}
private static Long extractCartId(Object merchantDataObj) {
if (merchantDataObj == null)
return null;
try {
String json = String.valueOf(merchantDataObj);
// 👇 DES-ESCAPAR las comillas HTML que vienen de Redsys
json = json.replace("&#34;", "\"");
org.json.JSONObject ctx = new org.json.JSONObject(json);
return ctx.optLong("cartId", 0L);
} catch (Exception e) {
e.printStackTrace(); // te ayudará si vuelve a fallar
return null;
}
}
public boolean authorized() {