package com.imprimelibros.erp.externalApi; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.MessageSource; 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.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.imprimelibros.erp.configuracion.margenes_presupuestos.MargenPresupuesto; import com.imprimelibros.erp.configuracion.margenes_presupuestos.MargenPresupuestoDao; import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoCubierta; import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoEncuadernacion; import java.util.Map; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.HashMap; import java.util.List; import java.util.function.Supplier; import java.util.Locale; @Service public class skApiClient { @Value("${safekat.api.url}") private String skApiUrl; private final AuthService authService; private final RestTemplate restTemplate; private final MargenPresupuestoDao margenPresupuestoDao; private final MessageSource messageSource; public skApiClient(AuthService authService, MargenPresupuestoDao margenPresupuestoDao, MessageSource messageSource) { this.authService = authService; this.restTemplate = new RestTemplate(); this.margenPresupuestoDao = margenPresupuestoDao; this.messageSource = messageSource; } public String getPrice(Map requestBody, TipoEncuadernacion tipoEncuadernacion, TipoCubierta tipoCubierta) { 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); try { Map responseBody = new ObjectMapper().readValue( response.getBody(), new TypeReference>() { }); ObjectMapper mapper = new ObjectMapper(); if (responseBody.get("error") == null) { Object dataObj = responseBody.get("data"); if (dataObj instanceof Map) { @SuppressWarnings("unchecked") Map data = (Map) dataObj; List tiradas = mapper.convertValue( data.get("tiradas"), new TypeReference>() { }); List precios = mapper.convertValue( data.get("precios"), new TypeReference>() { }); for (int i = 0; i < precios.size(); i++) { BigDecimal importe = new BigDecimal(precios.get(i)); BigDecimal importeTotal = importe.multiply(BigDecimal.valueOf(tiradas.get(i))); MargenPresupuesto margen = margenPresupuestoDao .findByImporte(importeTotal).orElse(null); if (margen != null) { BigDecimal margenValue = calcularMargen( importeTotal, margen.getImporteMin(), margen.getImporteMax(), margen.getMargenMax(), margen.getMargenMin()); BigDecimal nuevoPrecio = new BigDecimal(precios.get(i)).multiply(BigDecimal.ONE .add(margenValue.divide(BigDecimal.valueOf(100), RoundingMode.HALF_UP))); precios.set(i, nuevoPrecio.setScale(4, RoundingMode.HALF_UP).doubleValue()); // redondear // a 4 // decimales } else { System.out.println("No se encontró margen para importe " + importe); } } // <-- Clave: sustituir la lista en el map que se devuelve data.put("precios", precios); // (tiradas no cambia, pero si la modificases: data.put("tiradas", tiradas);) } return mapper.writeValueAsString(Map.of("data", responseBody.get("data"))); } else { return "{\"error\": 1}"; } } catch (JsonProcessingException e) { e.printStackTrace(); return "{\"error\": 1}"; } }); } public Integer getMaxSolapas(Map requestBody, Locale locale) { try { String jsonResponse = performWithRetry(() -> { String url = this.skApiUrl + "api/calcular-solapas"; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setBearerAuth(authService.getToken()); // token actualizado Map data = new HashMap<>(); data.put("clienteId", requestBody.get("clienteId")); data.put("tamanio", requestBody.get("tamanio")); data.put("tirada", requestBody.get("tirada")); data.put("paginas", requestBody.get("paginas")); data.put("paginasColor", requestBody.get("paginasColor")); data.put("papelInteriorDiferente", 0); data.put("paginasCuadernillo", requestBody.get("paginasCuadernillo")); data.put("tipo", requestBody.get("tipo")); data.put("isColor", requestBody.get("isColor")); data.put("isHq", requestBody.get("isHq")); data.put("interior", requestBody.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( messageSource.getMessage("presupuesto.errores.error-interior", new Object[] { 1 }, locale)); } return root.get("data").asInt(); } catch (JsonProcessingException e) { // Fallback al 80% del ancho Map tamanio = new ObjectMapper().convertValue( requestBody.get("tamanio"), new TypeReference>() { }); if (tamanio == null || tamanio.get("ancho") == null) throw new RuntimeException("Tamaño no válido en la solicitud: " + requestBody); else { int ancho = (int) tamanio.get("ancho"); return (int) Math.floor(ancho * 0.8); // 80% del ancho } } } public Double getRetractilado(Map requestBody) { String value = performWithRetry(() -> { String url = this.skApiUrl + "api/calcular-retractilado"; 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); try { Map responseBody = new ObjectMapper().readValue( response.getBody(), new TypeReference>() { }); return responseBody.get("data").toString(); } catch (JsonProcessingException e) { e.printStackTrace(); return "0.0"; // Fallback en caso de error } }); try { return Double.parseDouble(value); } catch (NumberFormatException e) { throw new RuntimeException("Error al parsear el valor de retractilado: " + value, e); } } /****************** * 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); } } } private static BigDecimal calcularMargen( BigDecimal importe, BigDecimal importeMin, BigDecimal importeMax, BigDecimal margenMax, BigDecimal margenMin) { if (importe.compareTo(importeMin) <= 0) return margenMax; if (importe.compareTo(importeMax) >= 0) return margenMin; return margenMax.subtract(margenMax.subtract(margenMin) .multiply(importe.subtract(importeMin) .divide(importeMax.subtract(importeMin), RoundingMode.HALF_UP))); } }