package com.imprimelibros.erp.presupuesto; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.Locale; import java.text.NumberFormat; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.math.BigDecimal; import java.math.RoundingMode; import com.imprimelibros.erp.configurationERP.VariableService; import com.imprimelibros.erp.presupuesto.Presupuesto.TipoCubierta; import com.imprimelibros.erp.presupuesto.classes.ImagenPresupuesto; import com.imprimelibros.erp.presupuesto.classes.PresupuestadorItems; import com.imprimelibros.erp.presupuesto.classes.PresupuestoFormatter; import com.imprimelibros.erp.presupuesto.maquetacion.MaquetacionPrecios; import com.imprimelibros.erp.presupuesto.maquetacion.MaquetacionPreciosRepository; import com.imprimelibros.erp.presupuesto.marcapaginas.Marcapaginas; import com.imprimelibros.erp.presupuesto.classes.PresupuestoMaquetacion; import com.imprimelibros.erp.presupuesto.classes.PresupuestoMarcapaginas; import com.imprimelibros.erp.presupuesto.maquetacion.MaquetacionMatricesRepository; import com.imprimelibros.erp.presupuesto.marcapaginas.MarcapaginasRepository; import com.imprimelibros.erp.externalApi.skApiClient; @Service public class PresupuestoService { @Autowired protected VariableService variableService; @Autowired protected MessageSource messageSource; @Autowired protected MaquetacionPreciosRepository maquetacionPreciosRepository; @Autowired protected MaquetacionMatricesRepository maquetacionMatricesRepository; @Autowired protected MarcapaginasRepository marcapaginasRepository; private final PresupuestadorItems presupuestadorItems; private final PresupuestoFormatter presupuestoFormatter; private final skApiClient apiClient; public PresupuestoService(PresupuestadorItems presupuestadorItems, PresupuestoFormatter presupuestoFormatter, skApiClient apiClient) { this.presupuestadorItems = presupuestadorItems; this.presupuestoFormatter = presupuestoFormatter; this.apiClient = apiClient; } public boolean validateDatosGenerales(int[] tiradas) { for (int tirada : tiradas) { if (tirada <= 0) { return false; // Invalid tirada found } } return true; } public Boolean isPOD(Presupuesto presupuesto) { int pod_value = variableService.getValorEntero("POD"); return (presupuesto.getTirada1() != null && presupuesto.getTirada1() <= pod_value) || (presupuesto.getTirada2() != null && presupuesto.getTirada2() <= pod_value) || (presupuesto.getTirada3() != null && presupuesto.getTirada3() <= pod_value) || (presupuesto.getTirada4() != null && presupuesto.getTirada4() <= pod_value); } public Map obtenerOpcionesColor(Presupuesto presupuesto, Locale locale) { List opciones = new ArrayList<>(); if (presupuesto.getPaginasColor() > 0) { if (!this.isPOD(presupuesto)) { // POD solo color foto ImagenPresupuesto opcionColor = this.presupuestadorItems.getImpresionColor(locale); opcionColor.setSelected(Presupuesto.TipoImpresion.color.equals(presupuesto.getTipoImpresion())); opciones.add(opcionColor); } ImagenPresupuesto opcionColorHq = this.presupuestadorItems.getImpresionColorPremium(locale); if (Presupuesto.TipoImpresion.colorhq.equals(presupuesto.getTipoImpresion())) opcionColorHq.setSelected(true); opciones.add(opcionColorHq); } else { ImagenPresupuesto opcionNegro = this.presupuestadorItems.getImpresionNegro(locale); if (Presupuesto.TipoImpresion.negro.equals(presupuesto.getTipoImpresion())) opcionNegro.setSelected(true); opciones.add(opcionNegro); ImagenPresupuesto opcionNegroHq = this.presupuestadorItems.getImpresionNegroPremium(locale); if (Presupuesto.TipoImpresion.negrohq.equals(presupuesto.getTipoImpresion())) opcionNegroHq.setSelected(true); opciones.add(opcionNegroHq); } boolean opcionSeleccionada = opciones.stream().anyMatch(ImagenPresupuesto::isSelected); if (!opcionSeleccionada) { opciones.get(0).setSelected(true); presupuesto.setTipoImpresion(Presupuesto.TipoImpresion.valueOf(opciones.get(0).getId())); } Map response = new HashMap<>(); response.put("opciones_color", opciones); return response; } public Map obtenerOpcionesPapelInterior(Presupuesto presupuesto, Locale locale) { List opciones = new ArrayList<>(); opciones.add(this.presupuestadorItems.getPapelOffsetBlanco(locale)); if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negro || presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.color) { opciones.add(this.presupuestadorItems.getPapelOffsetBlancoVolumen(locale)); } opciones.add(this.presupuestadorItems.getPapelOffsetAhuesado(locale)); if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negro || presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.color) { opciones.add(this.presupuestadorItems.getPapelOffsetAhuesadoVolumen(locale)); } opciones.add(this.presupuestadorItems.getPapelEstucadoMate(locale)); for (ImagenPresupuesto imagenPresupuesto : opciones) { imagenPresupuesto.setSelected( presupuesto.getPapelInteriorId() != null && imagenPresupuesto.getExtra_data().get("sk-id").equals( String.valueOf(presupuesto.getPapelInteriorId()))); } boolean yaSeleccionado = opciones.stream().anyMatch(ImagenPresupuesto::isSelected); if (!yaSeleccionado && !opciones.isEmpty()) { ImagenPresupuesto primeraOpcion = opciones.get(0); primeraOpcion.setSelected(true); presupuesto.setPapelInteriorId(Integer.parseInt(primeraOpcion.getExtra_data().get("sk-id"))); } Map response = new HashMap<>(); response.put("opciones_papel_interior", opciones); return response; } public Map obtenerOpcionesGramajeInterior(Presupuesto presupuesto) { List gramajes = new ArrayList<>(); final int BLANCO_OFFSET_ID = 3; final int BLANCO_OFFSET_VOLUMEN_ID = 7; final int AHUESADO_OFFSET_ID = 4; final int AHUESADO_OFFSET_VOLUMEN_ID = 6; final int ESTUCADO_MATE_ID = 2; if (presupuesto.getPapelInteriorId() != null && presupuesto.getPapelInteriorId() == BLANCO_OFFSET_ID) { gramajes.add("80"); gramajes.add("90"); if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negrohq || presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.colorhq) { gramajes.add("100"); gramajes.add("120"); gramajes.add("150"); gramajes.add("170"); } } else if (presupuesto.getPapelInteriorId() != null && presupuesto.getPapelInteriorId() == BLANCO_OFFSET_VOLUMEN_ID) { if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negro || presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.color) { gramajes.add("80"); } } else if (presupuesto.getPapelInteriorId() != null && presupuesto.getPapelInteriorId() == AHUESADO_OFFSET_ID) { gramajes.add("80"); gramajes.add("90"); if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negrohq || presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.colorhq) { gramajes.add("100"); } } else if (presupuesto.getPapelInteriorId() != null && presupuesto.getPapelInteriorId() == AHUESADO_OFFSET_VOLUMEN_ID) { if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negro || presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.color) { gramajes.add("70"); gramajes.add("80"); } } else if (presupuesto.getPapelInteriorId() != null && presupuesto.getPapelInteriorId() == ESTUCADO_MATE_ID) { if (presupuesto.getTipoImpresion() != Presupuesto.TipoImpresion.color) { gramajes.add("90"); } if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negrohq || presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.colorhq) { gramajes.add("100"); gramajes.add("115"); } if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negro || presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.color) { gramajes.add("120"); } if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negrohq || presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.colorhq) { gramajes.add("125"); gramajes.add("135"); gramajes.add("150"); gramajes.add("170"); gramajes.add("200"); } } Map response = new HashMap<>(); response.put("opciones_gramaje_interior", gramajes); return response; } public Map obtenerOpcionesPapelCubierta(Presupuesto presupuesto, Locale locale) { List opciones = new ArrayList<>(); if (presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaBlanda) { opciones.add(this.presupuestadorItems.getCartulinaGraficaCubierta(locale)); } opciones.add(this.presupuestadorItems.getEstucadoMateCubierta(locale)); for (ImagenPresupuesto imagenPresupuesto : opciones) { imagenPresupuesto.setSelected( presupuesto.getPapelCubiertaId() != null && imagenPresupuesto.getExtra_data().get("sk-id").equals( String.valueOf(presupuesto.getPapelCubiertaId()))); } Map response = new HashMap<>(); response.put("opciones_papel_cubierta", opciones); return response; } public Map obtenerOpcionesGramajeCubierta(Presupuesto presupuesto) { List gramajes = new ArrayList<>(); final int CARTULINA_GRAFICA_ID = 5; final int ESTUCADO_MATE_ID = 2; if (presupuesto.getPapelCubiertaId() != null && presupuesto.getPapelCubiertaId() == CARTULINA_GRAFICA_ID) { gramajes.add("240"); gramajes.add("270"); gramajes.add("300"); gramajes.add("350"); } else if (presupuesto.getPapelCubiertaId() != null && presupuesto.getPapelCubiertaId() == ESTUCADO_MATE_ID) { if (presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaBlanda) { gramajes.add("250"); gramajes.add("300"); gramajes.add("350"); } else { gramajes.add("170"); } } Map response = new HashMap<>(); response.put("opciones_gramaje_cubierta", gramajes); return response; } public Map toSkApiRequest(Presupuesto presupuesto) { final int SK_CLIENTE_ID = 1284; final int SK_PAGINAS_CUADERNILLO = 32; Map tamanio = Map.of( "ancho", presupuesto.getAncho(), "alto", presupuesto.getAlto()); Map interior = Map.of( "papelInterior", presupuesto.getPapelInteriorId(), "gramajeInterior", presupuesto.getGramajeInterior()); Map cubierta = Map.of( "tipoCubierta", presupuesto.getTipoCubierta().name(), "papelCubierta", presupuesto.getPapelCubiertaId(), "gramajeCubierta", presupuesto.getGramajeCubierta(), "carasImpresion", presupuesto.getCubiertaCaras(), "solapas", presupuesto.getSolapasCubierta() ? presupuesto.getTamanioSolapasCubierta() : 0, "acabado", presupuesto.getAcabado(), "cabezada", presupuesto.getCabezada(), "lomoRedondo", presupuesto.getTipoCubierta() == TipoCubierta.tapaDuraLomoRedondo ? 1 : 0); Map body = new HashMap<>(); body.put("tipo_impresion_id", this.getTipoImpresionId(presupuesto)); body.put("tirada", Arrays.stream(presupuesto.getTiradas()) .filter(Objects::nonNull) .collect(Collectors.toList())); body.put("tamanio", tamanio); body.put("tipo", presupuesto.getTipoEncuadernacion()); body.put("clienteId", SK_CLIENTE_ID); body.put("isColor", presupuesto.getTipoImpresion().name().contains("color") ? 1 : 0); body.put("isHq", presupuesto.getTipoImpresion().name().contains("hq") ? 1 : 0); body.put("paginas", presupuesto.getPaginasNegro() + presupuesto.getPaginasColor()); body.put("paginasColor", presupuesto.getPaginasColor()); body.put("paginasCuadernillo", SK_PAGINAS_CUADERNILLO); body.put("interior", interior); body.put("cubierta", cubierta); body.put("guardas", null); if (presupuesto.getSobrecubierta()) { Map sobrecubierta = new HashMap<>(); sobrecubierta.put("papel", presupuesto.getPapelSobrecubiertaId()); sobrecubierta.put("gramaje", presupuesto.getGramajeSobrecubierta()); sobrecubierta.put("solapas", presupuesto.getTamanioSolapasSobrecubierta()); sobrecubierta.put("acabado", presupuesto.getAcabadoSobrecubierta()); body.put("sobrecubierta", sobrecubierta); } if (presupuesto.getFaja()) { Map faja = new HashMap<>(); faja.put("papel", presupuesto.getPapelFajaId()); faja.put("gramaje", presupuesto.getGramajeFaja()); faja.put("solapas", presupuesto.getTamanioSolapasFaja()); faja.put("acabado", presupuesto.getAcabadoFaja()); faja.put("alto", presupuesto.getAltoFaja()); body.put("faja", faja); } // body.put("servicios", servicios); return body; } public Integer getTipoImpresionId(Presupuesto presupuesto) { if (presupuesto.getTipoEncuadernacion() == Presupuesto.TipoEncuadernacion.fresado) { if (presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDura || presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDuraLomoRedondo) { return 1; // Fresado tapa dura } else { return 2; // Fresado tapa blanda } } else if (presupuesto.getTipoEncuadernacion() == Presupuesto.TipoEncuadernacion.cosido) { if (presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDura || presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDuraLomoRedondo) { return 3; // Cosido tapa dura } else { return 4; // Cosido tapa blanda } } else if (presupuesto.getTipoEncuadernacion() == Presupuesto.TipoEncuadernacion.espiral) { if (presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDura || presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDuraLomoRedondo) { return 5; // Espiral tapa dura } else { return 6; // Espiral tapa blanda } } else if (presupuesto.getTipoEncuadernacion() == Presupuesto.TipoEncuadernacion.wireo) { if (presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDura || presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDuraLomoRedondo) { return 7; // Wireo tapa dura } else { return 8; // Wireo tapa blanda } } else if (presupuesto.getTipoEncuadernacion() == Presupuesto.TipoEncuadernacion.grapado) { return 21; // Grapado } else { return 0; // Default case, no valid type } } public Map obtenerOpcionesAcabadosCubierta(Presupuesto presupuesto, Locale locale) { Map resultado = new HashMap<>(); List opciones = new ArrayList<>(); opciones.add(new HashMap<>() { { put("name", messageSource.getMessage("presupuesto.acabado-ninguno", null, locale)); put("sk-id", 0); } }); opciones.add(new HashMap<>() { { put("name", messageSource.getMessage("presupuesto.acabado-plastificado-brillo-1c", null, locale)); put("sk-id", 1); } }); opciones.add(new HashMap<>() { { put("name", messageSource.getMessage("presupuesto.acabado-plastificado-mate-1c", null, locale)); put("sk-id", 5); } }); opciones.add(new HashMap<>() { { put("name", messageSource.getMessage("presupuesto.acabado-plastificado-mate-1c-antirrayado", null, locale)); put("sk-id", 8); } }); opciones.add(new HashMap<>() { { put("name", messageSource.getMessage("presupuesto.acabado-plastificado-mate-uvi", null, locale)); put("sk-id", 2); } }); opciones.add(new HashMap<>() { { put("name", messageSource.getMessage("presupuesto.acabado-plastificado-mate-uvi3d", null, locale)); put("sk-id", 3); } }); opciones.add(new HashMap<>() { { put("name", messageSource.getMessage("presupuesto.acabado-plastificado-mate-uvi-braile", null, locale)); put("sk-id", 4); } }); opciones.add(new HashMap<>() { { put("name", messageSource.getMessage("presupuesto.acabado-plastificado-sandy-1c", null, locale)); put("sk-id", 9); } }); resultado.put("opciones_acabados_cubierta", opciones); return resultado; } public Map aplicarMargenTiradas(Map data) { // implementar margenes return (Map) data; } public String obtenerPrecioRetractilado(Presupuesto presupuesto, Locale locale) { Integer[] tiradas = presupuesto.getTiradas(); Integer tirada_min = Arrays.stream(tiradas) .filter(Objects::nonNull) .min(Integer::compareTo) .orElse(0); Map requestBody = new HashMap<>(); requestBody.put("tirada", presupuesto.getSelectedTirada() != null ? presupuesto.getSelectedTirada() : tirada_min); Double precio_retractilado = apiClient.getRetractilado(requestBody); return precio_retractilado != null ? NumberFormat.getNumberInstance(locale) .format(Math.round(precio_retractilado * 100.0) / 100.0) : "0,00"; } public Map obtenerServiciosExtras(Presupuesto presupuesto, Locale locale) { List opciones = new ArrayList<>(); Double price_prototipo = this.obtenerPrototipo(presupuesto); opciones.add(new HashMap() { { put("id", "retractilado"); put("title", messageSource.getMessage("presupuesto.extras-retractilado", null, locale)); put("description", ""); put("price", obtenerPrecioRetractilado(presupuesto, locale)); put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale)); } }); opciones.add(new HashMap() { { put("id", "service-isbn"); put("title", messageSource.getMessage("presupuesto.extras-isbn", null, locale)); put("description", ""); put("price", "30"); put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale)); } }); opciones.add(new HashMap() { { put("id", "deposito-legal"); put("title", messageSource.getMessage("presupuesto.extras-deposito-legal", null, locale)); put("description", messageSource.getMessage("presupuesto.extras-deposito-legal-descripcion", null, locale)); put("price", "30"); put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale)); } }); opciones.add(new HashMap() { { put("id", "revision-archivos"); put("title", messageSource.getMessage("presupuesto.extras-revision-archivos", null, locale)); put("description", ""); put("price", "50"); put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale)); } }); opciones.add(new HashMap() { { put("id", "maquetacion-cubierta"); put("title", messageSource.getMessage("presupuesto.extras-maquetacion-cubierta", null, locale)); put("description", ""); put("price", "50"); put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale)); } }); opciones.add(new HashMap() { { put("id", "ferro-digital"); put("title", messageSource.getMessage("presupuesto.extras-ferro-digital", null, locale)); put("description", ""); put("price", "0"); put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale)); put("checked", "true"); put("allowChange", "false"); put("ribbonText", messageSource.getMessage("presupuesto.extras-ferro-digital-ribbon", null, locale)); } }); opciones.add(new HashMap() { { put("id", "ejemplar-prueba"); put("title", messageSource.getMessage("presupuesto.extras-ejemplar-prueba", null, locale)); put("description", ""); if (price_prototipo == 0.0) { put("price", messageSource.getMessage("presupuesto.consultar-soporte", null, locale)); put("priceUnit", ""); } else { put("price", NumberFormat.getNumberInstance(locale) .format(Math.round(price_prototipo * 100.0) / 100.0)); put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale)); } } }); opciones.add(new HashMap() { { put("id", "marcapaginas"); put("title", messageSource.getMessage("presupuesto.extras-marcapaginas", null, locale)); put("description", ""); put("price", messageSource.getMessage("presupuesto.extras-calcular", null, locale)); } }); opciones.add(new HashMap() { { put("id", "maquetacion"); put("title", messageSource.getMessage("presupuesto.extras-maquetacion", null, locale)); put("description", ""); put("price", messageSource.getMessage("presupuesto.extras-calcular", null, locale)); } }); Map response = new HashMap<>(); response.put("servicios_extra", opciones); return response; } private Double obtenerPrototipo(Presupuesto presupuesto) { // Obtenemos el precio de 1 unidad para el ejemplar de prueba HashMap price = new HashMap<>(); // make a copy of "presupuesto" to avoid modifying the original object Presupuesto presupuestoTemp = presupuesto.clone(); presupuestoTemp.setTirada1(1); presupuestoTemp.setTirada2(null); presupuestoTemp.setTirada3(null); presupuestoTemp.setTirada4(null); if (presupuestoTemp.getTipoImpresion() == Presupuesto.TipoImpresion.color) { presupuestoTemp.setTipoImpresion(Presupuesto.TipoImpresion.colorhq); } else if (presupuestoTemp.getTipoImpresion() == Presupuesto.TipoImpresion.negro) { presupuestoTemp.setTipoImpresion(Presupuesto.TipoImpresion.negrohq); } String priceStr = apiClient.getPrice(this.toSkApiRequest(presupuestoTemp)); Double price_prototipo = 0.0; try { price = new ObjectMapper().readValue(priceStr, new TypeReference<>() { }); price_prototipo = ((List) ((Map) price.get("data")).get("precios")).get(0); if (price_prototipo < 25) { price_prototipo = 25.0; } } catch (JsonProcessingException e) { } catch (Exception exception) { } return price_prototipo; } public HashMap getPrecioMaquetacion(PresupuestoMaquetacion presupuestoMaquetacion, Locale locale) { try { List lista = maquetacionPreciosRepository.findAll(); // helper para obtener un precio por clave java.util.function.Function price = key -> lista.stream() .filter(p -> key.equals(p.getKey())) .map(MaquetacionPrecios::getValue) .findFirst() .orElse(0.0); BigDecimal precio = BigDecimal.ZERO; // millar_maquetacion * (numCaracteres / 1000.0) BigDecimal millares = BigDecimal.valueOf(presupuestoMaquetacion.getNumCaracteres()).divide( BigDecimal.valueOf(1000), 6, RoundingMode.HALF_UP); precio = precio.add(millares.multiply(BigDecimal.valueOf(price.apply("millar_maquetacion")))); // Numero de paginas estimado int numPaginas = 0; Integer matricesPorPagina = maquetacionMatricesRepository.findMatrices( presupuestoMaquetacion.getFormato(), presupuestoMaquetacion.getCuerpoTexto()); if (matricesPorPagina != null && matricesPorPagina > 0) { numPaginas = presupuestoMaquetacion.getNumCaracteres() / matricesPorPagina; } // Precio por pagina estimado BigDecimal precioRedondeado = precio.setScale(2, RoundingMode.HALF_UP); double precioPaginaEstimado = 0.0; if (numPaginas > 0) { precioPaginaEstimado = precioRedondeado .divide(BigDecimal.valueOf(numPaginas), 2, RoundingMode.HALF_UP) .doubleValue(); } // tabla, columna, foto precio = precio .add(BigDecimal.valueOf(presupuestoMaquetacion.getNumTablas()) .multiply(BigDecimal.valueOf(price.apply("tabla")))); precio = precio.add( BigDecimal.valueOf(presupuestoMaquetacion.getNumColumnas()) .multiply(BigDecimal.valueOf(price.apply("columnas")))); precio = precio .add(BigDecimal.valueOf(presupuestoMaquetacion.getNumFotos()) .multiply(BigDecimal.valueOf(price.apply("foto")))); if (presupuestoMaquetacion.isCorreccionOrtotipografica()) { precio = precio .add(millares.multiply(BigDecimal.valueOf(price.apply("correccion_ortotipografica")))); } if (presupuestoMaquetacion.isTextoMecanografiado()) { precio = precio.add(millares.multiply(BigDecimal.valueOf(price.apply("mecanoescritura_por_millar")))); } if (presupuestoMaquetacion.isDisenioPortada()) { precio = precio.add(BigDecimal.valueOf(price.apply("disenio_portada"))); } if (presupuestoMaquetacion.isEpub()) { precio = precio.add(BigDecimal.valueOf(price.apply("epub"))); } // redondeo final precioRedondeado = precio.setScale(2, RoundingMode.HALF_UP); HashMap out = new HashMap<>(); out.put("precio", precioRedondeado.doubleValue()); out.put("numPaginasEstimadas", numPaginas); out.put("precioPaginaEstimado", precioPaginaEstimado); HashMap language = new HashMap<>(); language.put("num_paginas_estimadas", messageSource.getMessage("presupuesto.maquetacion.num-paginas-estimadas", null, locale)); language.put("precio_por_pagina_estimado", messageSource.getMessage("presupuesto.maquetacion.precio-por-pagina-estimado", null, locale)); language.put("add_to_presupuesto", messageSource.getMessage("presupuesto.add-to-presupuesto", null, locale)); language.put("cancel", messageSource.getMessage("app.cancelar", null, locale)); language.put("presupuesto_maquetacion", messageSource.getMessage("presupuesto.maquetacion", null, locale)); out.put("language", language); return out; } catch (Exception e) { System.out.println("Error procesando presupuesto maquetacion: " + e.getMessage()); } HashMap out = new HashMap<>(); out.put("precio", 0.0); out.put("numPaginasEstimadas", 0); out.put("precioPaginaEstimado", 0.0); return out; } public HashMap getPrecioMarcapaginas(PresupuestoMarcapaginas presupuestoMarcapaginas, Locale locale) { try { List m = marcapaginasRepository.findPrecios(presupuestoMarcapaginas); if (m.isEmpty() || m.get(0) == null) { HashMap out = new HashMap<>(); out.put("precio_unidad", 0.0); out.put("precio_total", 0.0); return out; } Marcapaginas marcapaginas = m.get(0); Double precio = 0.0; Double margen = 0.0; Double pvp = 0.0; BigDecimal data = BigDecimal.ZERO; if (marcapaginas.getUnidades_max() >= presupuestoMarcapaginas.getUnidades()) { precio = marcapaginas.getPrecio_unidades_min() + (presupuestoMarcapaginas.getUnidades() - marcapaginas.getUnidades_min()) * (marcapaginas.getPrecio_unidades_max() - marcapaginas.getPrecio_unidades_min()) / (marcapaginas.getUnidades_max() - marcapaginas.getUnidades_min()); data = new BigDecimal(precio); precio = data.setScale(2, RoundingMode.HALF_UP).doubleValue(); margen = 1.0 * marcapaginas.getMargen_unidades_min() + (1.0 * presupuestoMarcapaginas.getUnidades() - 1.0 * marcapaginas.getUnidades_min()) * (1.0 * marcapaginas.getMargen_unidades_max() - 1.0 * marcapaginas.getMargen_unidades_min()) / (1.0 * marcapaginas.getUnidades_max() - 1.0 * marcapaginas.getUnidades_min()); data = new BigDecimal(margen); margen = data.setScale(2, RoundingMode.HALF_UP).doubleValue(); pvp = precio + (precio * margen / 100); data = new BigDecimal(pvp); pvp = data.setScale(2, RoundingMode.HALF_UP).doubleValue(); } else { // precio unidad para el máximo de unidades precio = marcapaginas.getPrecio_unidades_max() / marcapaginas.getUnidades_max(); precio = precio * presupuestoMarcapaginas.getUnidades(); data = new BigDecimal(precio); precio = data.setScale(2, RoundingMode.HALF_UP).doubleValue(); margen = 1.0 * marcapaginas.getMargen_unidades_max(); data = new BigDecimal(margen); margen = data.setScale(2, RoundingMode.HALF_UP).doubleValue(); pvp = precio + (precio * margen / 100); data = new BigDecimal(pvp); pvp = data.setScale(2, RoundingMode.HALF_UP).doubleValue(); } Double precio_unidad = pvp / presupuestoMarcapaginas.getUnidades(); data = new BigDecimal(precio_unidad); precio_unidad = data.setScale(6, RoundingMode.HALF_UP).doubleValue(); HashMap resultado; resultado = new HashMap<>(); resultado.put("precio_unitario", precio_unidad); resultado.put("precio_total", pvp); HashMap language = new HashMap<>(); language.put("precio_unidad", messageSource.getMessage("presupuesto.marcapaginas.precio-unidad", null, locale)); language.put("precio_total", messageSource.getMessage("presupuesto.marcapaginas.precio-total", null, locale)); language.put("add_to_presupuesto", messageSource.getMessage("presupuesto.add-to-presupuesto", null, locale)); language.put("cancel", messageSource.getMessage("app.cancelar", null, locale)); language.put("presupuesto_marcapaginas", messageSource.getMessage("presupuesto.marcapaginas", null, locale)); resultado.put("language", language); return resultado; } catch (Exception e) { System.out.println("Error procesando presupuesto marcapaginas: " + e.getMessage()); } HashMap out = new HashMap<>(); out.put("precio_unidad", 0.0); out.put("precio_total", 0.0); return out; } public Map getResumen(Presupuesto presupuesto, List> servicios, Locale locale) { Map resumen = new HashMap<>(); resumen.put("titulo", presupuesto.getTitulo()); Presupuesto pressupuestoTemp = presupuesto.clone(); resumen.put("imagen", "/assets/images/imprimelibros/presupuestador/" + presupuesto.getTipoEncuadernacion() + ".png"); resumen.put("imagen_alt", messageSource.getMessage("presupuesto." + presupuesto.getTipoEncuadernacion(), null, locale)); boolean hayDepositoLegal = servicios != null && servicios.stream() .map(m -> java.util.Objects.toString(m.get("id"), "")) // null-safe -> String .map(String::trim) .anyMatch("deposito-legal"::equals); if(hayDepositoLegal){ pressupuestoTemp.setSelectedTirada(presupuesto.getSelectedTirada()+4); } HashMap precios = this.calcularPresupuesto(pressupuestoTemp, locale); if(precios.containsKey("error")){ resumen.put("error", precios.get("error")); return resumen; } HashMap linea = new HashMap<>(); Double precio_unitario = 0.0; Double precio_total = 0.0; Integer counter = 0; linea.put("descripcion", presupuestoFormatter.resumen(presupuesto, servicios, locale)); linea.put("cantidad", presupuesto.getSelectedTirada() != null ? presupuesto.getSelectedTirada() : 0); precio_unitario = ((List) ((Map) precios.get("data")).get("precios")) .get(0); precio_total = precio_unitario * presupuesto.getSelectedTirada(); linea.put("precio_unitario", precio_unitario); linea.put("precio_total", BigDecimal.valueOf(precio_total).setScale(2, RoundingMode.HALF_UP)); resumen.put("linea" + counter, linea); counter++; if(hayDepositoLegal) { linea = new HashMap<>(); linea.put("descripcion", messageSource.getMessage("presupuesto.resumen-deposito-legal", null, locale)); linea.put("cantidad", 4); linea.put("precio_unitario", precio_unitario); linea.put("precio_total", BigDecimal.valueOf(precio_unitario * 4).setScale(2, RoundingMode.HALF_UP)); resumen.put("linea" + counter, linea); counter++; } List> serviciosExtras = new ArrayList<>(); if(servicios != null){ for (Map servicio : servicios) { HashMap servicioData = new HashMap<>(); servicioData.put("descripcion", servicio.get("label")); servicioData.put("precio", servicio.get("price")); serviciosExtras.add(servicioData); } } resumen.put("servicios", serviciosExtras); return resumen; } public HashMap calcularPresupuesto(Presupuesto presupuesto, Locale locale) { HashMap price = new HashMap<>(); String priceStr = apiClient.getPrice(this.toSkApiRequest(presupuesto)); try { price = new ObjectMapper().readValue(priceStr, new TypeReference<>() { }); } catch (JsonProcessingException e) { price = new HashMap<>(); price.put("error", messageSource.getMessage("presupuesto.error-obtener-precio", null, locale)); } return price; } }