From 3f89f323cfe6479360e920526fd11b8ad200e042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Jim=C3=A9nez?= Date: Tue, 5 Aug 2025 10:07:04 +0200 Subject: [PATCH] =?UTF-8?q?a=C3=B1adidos=20los=20ficheros=20nuevos2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../erp/externalApi/AuthService.java | 41 ++++++ .../erp/externalApi/skApiClient.java | 127 ++++++++++++++++++ .../imprimelibros/erp/skApiClientTest.java | 82 +++++++++++ 3 files changed, 250 insertions(+) create mode 100644 src/main/java/com/imprimelibros/erp/externalApi/AuthService.java create mode 100644 src/main/java/com/imprimelibros/erp/externalApi/skApiClient.java create mode 100644 src/test/java/com/imprimelibros/erp/skApiClientTest.java diff --git a/src/main/java/com/imprimelibros/erp/externalApi/AuthService.java b/src/main/java/com/imprimelibros/erp/externalApi/AuthService.java new file mode 100644 index 0000000..d44fd71 --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/externalApi/AuthService.java @@ -0,0 +1,41 @@ +package com.imprimelibros.erp.externalApi; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +@Service +public class AuthService { + + @Value("${safekat.api.url}") + private String skApiUrl; + @Value("${safekat.api.email}") + private String skApiEmail; + @Value("${safekat.api.password}") + private String skApiPassword; + + private final RestTemplate restTemplate = new RestTemplate(); + private String currentToken; + + public synchronized String getToken() { + if (currentToken == null) { + currentToken = fetchNewToken(); + } + return currentToken; + } + + public synchronized void invalidateToken() { + currentToken = null; + } + + private String fetchNewToken() { + Map credentials = Map.of( + "email", this.skApiEmail, + "password", this.skApiPassword); + ResponseEntity response = restTemplate.postForEntity(this.skApiUrl + "auth/jwt", credentials, Map.class); + return (String) response.getBody().get("access_token"); + } +} diff --git a/src/main/java/com/imprimelibros/erp/externalApi/skApiClient.java b/src/main/java/com/imprimelibros/erp/externalApi/skApiClient.java new file mode 100644 index 0000000..03b9652 --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/externalApi/skApiClient.java @@ -0,0 +1,127 @@ +package com.imprimelibros.erp.externalApi; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.Map; +import java.util.HashMap; +import java.util.function.Supplier; +import java.util.List; + +@Service +public class skApiClient { + + @Value("${safekat.api.url}") + private String skApiUrl; + + private final AuthService authService; + private final RestTemplate restTemplate; + + public skApiClient(AuthService authService) { + this.authService = authService; + this.restTemplate = new RestTemplate(); + } + + public String getPrice(Map requestBody) { + + return performWithRetry(() -> { + String url = this.skApiUrl + "api/calcular"; + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setBearerAuth(authService.getToken()); + + HttpEntity> entity = new HttpEntity<>(requestBody, headers); + + ResponseEntity response = restTemplate.exchange( + url, + HttpMethod.POST, + entity, + String.class); + + return response.getBody(); + }); + } + + public Integer getMaxSolapas(Map requestBody) { + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setBearerAuth(authService.getToken()); + + Map request = new HashMap<>(requestBody); + Map data = new HashMap<>(); + + try { + String jsonResponse = performWithRetry(() -> { + + String url = this.skApiUrl + "api/calcular-solapas"; + + data.put("clienteId", request.get("clienteId")); + data.put("tamanio", (Map) request.get("tamanio")); + data.put("tirada", requestBody.get("tirada")); + data.put("paginas", request.get("paginas")); + data.put("paginasColor", request.get("paginasColor")); + data.put("papelInteriorDiferente", 0); + data.put("paginasCuadernillo", request.get("paginasCuadernillo")); + data.put("tipo", request.get("tipo")); + data.put("isColor", request.get("isColor")); + data.put("isHq", request.get("isHq")); + data.put("interior", request.get("interior")); + + HttpEntity> entity = new HttpEntity<>(data, headers); + + ResponseEntity response = restTemplate.exchange( + url, + HttpMethod.POST, + entity, + String.class); + + return response.getBody(); + }); + + ObjectMapper mapper = new ObjectMapper(); + + JsonNode root = mapper.readTree(jsonResponse); + if (root.get("data") == null || !root.get("data").isInt()) { + throw new RuntimeException("Respuesta inesperada de calcular-solapas: " + jsonResponse); + } + int solapas = root.get("data").asInt(); + return solapas; + } catch (JsonProcessingException e) { + // No se puede calcular el interior, por lo que las solapas seran el 80% del + // ancho + Map tamanio = (Map)data.get("tamanio"); + if (tamanio == null || tamanio.get("ancho") == null) + throw new RuntimeException("Tamaño no válido en la solicitud: " + data); + else { + int ancho = (int) tamanio.get("ancho"); + return (int) Math.floor(ancho * 0.8); // 80% del ancho + } + } + } + + /****************** + * PRIVATE METHODS + ******************/ + private String performWithRetry(Supplier request) { + try { + return request.get(); + } catch (HttpClientErrorException.Unauthorized e) { + // Token expirado, renovar y reintentar + authService.invalidateToken(); + try { + return request.get(); // segundo intento + } catch (HttpClientErrorException ex) { + throw new RuntimeException("La autenticación ha fallado tras renovar el token.", ex); + } + } + } +} diff --git a/src/test/java/com/imprimelibros/erp/skApiClientTest.java b/src/test/java/com/imprimelibros/erp/skApiClientTest.java new file mode 100644 index 0000000..ff74dab --- /dev/null +++ b/src/test/java/com/imprimelibros/erp/skApiClientTest.java @@ -0,0 +1,82 @@ +package com.imprimelibros.erp; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import com.imprimelibros.erp.externalApi.skApiClient; + +@SpringBootTest +class skApiClientTest { + + @Autowired + private skApiClient apiClient; + + @Test + void testPrecioCalculadoDevuelveJson() { + String resultado = this.test(); + + System.out.println("📦 Resultado de la API:"); + System.out.println(resultado); + + assertNotNull(resultado, "El resultado no debe ser null"); + assertTrue(resultado.trim().startsWith("{"), "El resultado debe comenzar con { (JSON)"); + assertTrue(resultado.trim().endsWith("}"), "El resultado debe terminar con } (JSON)"); + } + + public String test() { + + Map tamanio = Map.of("ancho", 148, "alto", 210); + Map interior = Map.of("papelInterior", "3", "gramajeInterior", 90); + Map cubierta = Map.of( + "tipoCubierta", "tapaBlanda", + "papelCubierta", "2", + "gramajeCubierta", 300, + "carasImpresion", 2, + "solapas", 0, + "acabado", "1", + "cabezada", "WHI", + "lomoRedondo", 0); + + // ✅ Corregido: usamos HashMap porque Map.of no permite null + Map sobrecubierta = new HashMap<>(); + sobrecubierta.put("papel", "2"); + sobrecubierta.put("gramaje", 170); + sobrecubierta.put("solapas", 80); + sobrecubierta.put("acabado", null); + + Map servicios = Map.of( + "retractilado", 0, + "retractilado5", 0, + "ferro", 0, + "ferroDigital", 0, + "marcapaginas", 0, + "prototipo", 0); + + Map body = new HashMap<>(); + body.put("tirada", List.of(50, 100, 150, 500)); + body.put("tamanio", tamanio); + body.put("tipo", "fresado"); + body.put("clienteId", 1284); + body.put("isColor", 1); + body.put("isHq", 0); + body.put("paginas", 112); + body.put("paginasColor", 80); + body.put("paginasCuadernillo", 32); + body.put("interior", interior); + body.put("cubierta", cubierta); + body.put("sobrecubierta", sobrecubierta); + body.put("guardas", null); + body.put("faja", false); + body.put("servicios", servicios); + + return apiClient.getPrice(body); + } + +}