intentando meter los ficheros redsys

This commit is contained in:
2025-10-29 14:10:10 +01:00
parent 5e9631073e
commit ae2904aa71
8 changed files with 190 additions and 0 deletions

35
pom.xml
View File

@ -151,6 +151,41 @@
<version>${liquibase.version}</version>
</dependency>
<!-- Redsys -->
<dependency>
<groupId>com.redsys</groupId>
<artifactId>apiSha512V2</artifactId>
<version>2.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/apiSha512V2.jar</systemPath>
</dependency>
<!-- Dependencias locales incluidas en el ZIP -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.47</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/bcprov-jdk15on-1.4.7.jar</systemPath>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.3</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/commons-codec-1.3.jar</systemPath>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/org.json.jar</systemPath>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,53 @@
package com.imprimelibros.erp.redsys;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/pagos/redsys")
public class RedsysController {
private final RedsysService service;
public RedsysController(RedsysService service) { this.service = service; }
@PostMapping("/crear")
public String crearPago(@RequestParam String order,
@RequestParam long amountCents,
Model model) {
var payReq = new RedsysService.PaymentRequest(order, amountCents, "Compra en ImprimeLibros");
var form = service.buildRedirectForm(payReq);
model.addAttribute("action", form.action());
model.addAttribute("signatureVersion", form.signatureVersion());
model.addAttribute("merchantParameters", form.merchantParameters());
model.addAttribute("signature", form.signature());
return "payments/redsys-redirect"; // Thymeleaf
}
@PostMapping("/notify")
@ResponseBody
public ResponseEntity<String> notifyRedsys(@RequestParam("Ds_Signature") String dsSig,
@RequestParam("Ds_SignatureVersion") String dsSigVer,
@RequestParam("Ds_MerchantParameters") String dsParams) throws Exception {
var notif = service.validateAndParse(dsSig, dsSigVer, dsParams);
// 1) Idempotencia: marca el pedido si aún no procesado.
// 2) Verifica importe/moneda/pedido contra tu base de datos.
// 3) Autoriza en tu sistema si notif.authorized() == true.
return ResponseEntity.ok("OK");
}
@GetMapping("/ok")
public String ok() { return "payments/success"; }
@GetMapping("/ko")
public String ko() { return "payments/failure"; }
}

View File

@ -0,0 +1,89 @@
package com.imprimelibros.erp.redsys;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class RedsysService {
@Value("${redsys.merchant-code}") private String merchantCode;
@Value("${redsys.terminal}") private String terminal;
@Value("${redsys.currency}") private String currency;
@Value("${redsys.transaction-type}") private String txType;
@Value("${redsys.secret-key}") private String secretKey;
@Value("${redsys.urls.ok}") private String urlOk;
@Value("${redsys.urls.ko}") private String urlKo;
@Value("${redsys.urls.notify}") private String urlNotify;
@Value("${redsys.environment}") private String env;
public record PaymentRequest(String order, long amountCents, String description) {}
public record FormPayload(String action, String signatureVersion, String merchantParameters, String signature) {}
public FormPayload buildRedirectForm(PaymentRequest req) {
// RedsysAPI proviene del JAR oficial
com.redsys.api.RedsysAPI api = new com.redsys.api.RedsysAPI();
Map<String, String> mp = new HashMap<>();
mp.put("DS_MERCHANT_AMOUNT", String.valueOf(req.amountCents()));
mp.put("DS_MERCHANT_ORDER", req.order());
mp.put("DS_MERCHANT_MERCHANTCODE", merchantCode);
mp.put("DS_MERCHANT_CURRENCY", currency);
mp.put("DS_MERCHANT_TRANSACTIONTYPE", txType);
mp.put("DS_MERCHANT_TERMINAL", terminal);
mp.put("DS_MERCHANT_MERCHANTNAME", "Tu Comercio");
mp.put("DS_MERCHANT_PRODUCTDESCRIPTION", req.description());
mp.put("DS_MERCHANT_URLOK", urlOk);
mp.put("DS_MERCHANT_URLKO", urlKo);
mp.put("DS_MERCHANT_MERCHANTURL", urlNotify);
String merchantParameters = api.createMerchantParameters(mp);
String signature = api.createMerchantSignature(secretKey);
String action = "test".equalsIgnoreCase(env)
? "https://sis-t.redsys.es:25443/sis/realizarPago"
: "https://sis.redsys.es/sis/realizarPago";
return new FormPayload(action, "HMAC_SHA256_V1", merchantParameters, signature);
}
// Validación de la notificación on-line (webhook).
public RedsysNotification validateAndParse(String dsSignature, String dsSignatureVersion, String dsMerchantParametersB64) {
com.redsys.api.RedsysAPI api = new com.redsys.api.RedsysAPI();
// 1) Validar firma
String calc = api.createMerchantSignatureNotif(secretKey, dsMerchantParametersB64);
if (!Objects.equals(calc, dsSignature)) {
throw new IllegalArgumentException("Firma Redsys no válida");
}
// 2) Decodificar parámetros
String json = api.decodeMerchantParameters(dsMerchantParametersB64);
Map<String, Object> params = new com.fasterxml.jackson.databind.ObjectMapper()
.readValue(json, new com.fasterxml.jackson.core.type.TypeReference<>() {});
// Campos típicos: Ds_Order, Ds_Amount, Ds_Currency, Ds_Response, etc.
return RedsysNotification.from(params);
}
public static record RedsysNotification(String order, String dsResponse, long amountCents, String currency) {
static RedsysNotification from(Map<String, Object> p) {
String order = (String) p.get("Ds_Order");
String resp = String.valueOf(p.get("Ds_Response"));
long amount = Long.parseLong((String) p.get("Ds_Amount"));
String curr = String.valueOf(p.get("Ds_Currency"));
return new RedsysNotification(order, resp, amount, curr);
}
// Éxito si 099.
public boolean authorized() {
try {
int r = Integer.parseInt(dsResponse);
return r >= 0 && r <= 99;
} catch (Exception e) { return false; }
}
}
}

View File

@ -105,3 +105,16 @@ spring.liquibase.change-log=classpath:db/changelog/master.yml
# spring.liquibase.url=jdbc:mysql://localhost:3306/imprimelibros
# spring.liquibase.user=tu_user
# spring.liquibase.password=tu_pass
# Redsys
redsys.environment=test
redsys.merchant-code=124760810
redsys.terminal=1
redsys.currency=978
redsys.transaction-type=0
redsys.secret-key=sq7HjrUOBfKmC576ILgskD5srU870gJ7
redsys.urls.ok=https://localhost:8080/pagos/redsys/ok
redsys.urls.ko=https://localhost:8080/pagos/redsys/ko
redsys.urls.notify=https://localhost:8080/pagos/redsys/notify

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.