trabajando con las lineas del resumen para la tabla

This commit is contained in:
2025-09-23 20:28:33 +02:00
parent c1df92b840
commit 0d205f9488
9 changed files with 131 additions and 88 deletions

View File

@ -28,7 +28,7 @@
<url /> <url />
</scm> </scm>
<properties> <properties>
<java.version>24</java.version> <java.version>21</java.version>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>

View File

@ -3,6 +3,7 @@ package com.imprimelibros.erp.presupuesto;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import java.math.BigDecimal;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -21,6 +22,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imprimelibros.erp.externalApi.skApiClient; import com.imprimelibros.erp.externalApi.skApiClient;
import com.imprimelibros.erp.presupuesto.classes.ImagenPresupuesto; import com.imprimelibros.erp.presupuesto.classes.ImagenPresupuesto;
import com.imprimelibros.erp.presupuesto.classes.PresupuestoMaquetacion; import com.imprimelibros.erp.presupuesto.classes.PresupuestoMaquetacion;
@ -42,6 +44,12 @@ public class PresupuestoController {
@Autowired @Autowired
protected MessageSource messageSource; protected MessageSource messageSource;
private final ObjectMapper objectMapper;
public PresupuestoController(ObjectMapper objectMapper){
this.objectMapper = objectMapper;
}
@PostMapping("/public/validar/datos-generales") @PostMapping("/public/validar/datos-generales")
public ResponseEntity<?> validarDatosGenerales( public ResponseEntity<?> validarDatosGenerales(
@Validated(PresupuestoValidationGroups.DatosGenerales.class) Presupuesto presupuesto, @Validated(PresupuestoValidationGroups.DatosGenerales.class) Presupuesto presupuesto,
@ -368,30 +376,13 @@ public class PresupuestoController {
// Se hace un post para no tener problemas con la longitud de la URL // Se hace un post para no tener problemas con la longitud de la URL
@PostMapping("/public/resumen") @PostMapping("/public/resumen")
public ResponseEntity<?> getResumen(@RequestBody PresupuestoRequest req, Locale locale) { public ResponseEntity<?> getResumen(@RequestBody Map<String, Object> body, Locale locale) {
Presupuesto p = req.getPresupuesto(); Presupuesto p = objectMapper.convertValue(body.get("presupuesto"), Presupuesto.class);
String[] servicios = req.getServicios() != null ? req.getServicios() : new String[0];
return ResponseEntity.ok(presupuestoService.getResumen(p, servicios, locale)); @SuppressWarnings("unchecked")
List<Map<String, Object>> serviciosList = (List<Map<String, Object>>) body.getOrDefault("servicios", List.of());
return ResponseEntity.ok(presupuestoService.getResumen(p, serviciosList, locale));
} }
public static class PresupuestoRequest {
private Presupuesto presupuesto;
private String[] servicios;
public Presupuesto getPresupuesto() {
return presupuesto;
}
public void setPresupuesto(Presupuesto p) {
this.presupuesto = p;
}
public String[] getServicios() {
return servicios;
}
public void setServicios(String[] servicios) {
this.servicios = servicios;
}
}
} }

View File

@ -6,12 +6,14 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.BiFunction;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.Locale; import java.util.Locale;
import java.text.NumberFormat; import java.text.NumberFormat;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
@ -774,13 +776,52 @@ public class PresupuestoService {
return out; return out;
} }
public Map<String, Object> getResumen(Presupuesto presupuesto, String[] servicios, Locale locale) { public Map<String, Object> getResumen(Presupuesto presupuesto, List<Map<String, Object>> servicios, Locale locale) {
Map<String, Object> resumen = new HashMap<>(); Map<String, Object> resumen = new HashMap<>();
resumen.put("titulo", presupuesto.getTitulo()); resumen.put("titulo", presupuesto.getTitulo());
resumen.put("texto", presupuestoFormatter.resumen(presupuesto, servicios, locale));
Presupuesto pressupuestoTemp = presupuesto.clone();
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<String, Object> precios = this.calcularPresupuesto(pressupuestoTemp, locale);
if(precios.containsKey("error")){
resumen.put("error", precios.get("error"));
return resumen;
}
HashMap<String, Object> 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<Double>) ((Map<String, Object>) 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++;
}
return resumen; return resumen;
} }

View File

@ -8,6 +8,8 @@ import org.springframework.context.MessageSource;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import java.util.List;
import java.util.Map;
@Component @Component
public class PresupuestoFormatter { public class PresupuestoFormatter {
@ -28,20 +30,22 @@ public class PresupuestoFormatter {
this.acabados = acabados; this.acabados = acabados;
} }
public String resumen(Presupuesto p, String[] servicios, Locale locale) { public String resumen(Presupuesto p, List<Map<String, Object>> servicios, Locale locale) {
String encuadernacion = translationService.label(p.getTipoEncuadernacion(), locale); String encuadernacion = translationService.label(p.getTipoEncuadernacion(), locale);
String tipoImpresion = translationService.label(p.getTipoImpresion(), locale); String tipoImpresion = translationService.label(p.getTipoImpresion(), locale);
String tapaCubierta = translationService.label(p.getTipoCubierta(), locale); String tapaCubierta = translationService.label(p.getTipoCubierta(), locale);
Object[] args = { Object[] args = {
Arrays.asList(servicios).contains("deposito-legal") ? p.getSelectedTirada() + 4 : p.getSelectedTirada(),
encuadernacion, p.getSelectedTirada(),
tipoImpresion, encuadernacion,
(p.getPaginasColorTotal() != null ? p.getPaginasColorTotal() : p.getPaginasColor()) + p.getPaginasNegro(), tipoImpresion,
p.getAncho(), p.getAlto(), (p.getPaginasColorTotal() != null ? p.getPaginasColorTotal() : p.getPaginasColor())
papeles.labelPapel(p.getPapelInteriorId(), locale), p.getGramajeInterior(), + p.getPaginasNegro(),
tapaCubierta, p.getAncho(), p.getAlto(),
papeles.labelPapel(p.getPapelCubiertaId(), locale), p.getGramajeCubierta(), papeles.labelPapel(p.getPapelInteriorId(), locale), p.getGramajeInterior(),
tapaCubierta,
papeles.labelPapel(p.getPapelCubiertaId(), locale), p.getGramajeCubierta(),
}; };
String textoResumen = ms.getMessage("presupuesto.resumen-texto", args, locale); String textoResumen = ms.getMessage("presupuesto.resumen-texto", args, locale);
textoResumen += "<ul>"; textoResumen += "<ul>";
@ -49,27 +53,25 @@ public class PresupuestoFormatter {
// tapa blanda // tapa blanda
if (p.getTipoCubierta() == Presupuesto.TipoCubierta.tapaBlanda) { if (p.getTipoCubierta() == Presupuesto.TipoCubierta.tapaBlanda) {
String impresionCubierta = ms.getMessage( String impresionCubierta = ms.getMessage(
"presupuesto.resumen-texto-impresion-caras-cubierta", "presupuesto.resumen-texto-impresion-caras-cubierta",
new Object[] { new Object[] {
p.getCubiertaCaras() == 2 p.getCubiertaCaras() == 2
? ms.getMessage("presupuesto.una-cara", null, locale) ? ms.getMessage("presupuesto.una-cara", null, locale)
: ms.getMessage("presupuesto.dos-caras", null, locale) : ms.getMessage("presupuesto.dos-caras", null, locale)
}, },
locale locale);
);
textoResumen += impresionCubierta; textoResumen += impresionCubierta;
if (p.getSolapasCubierta()) { if (p.getSolapasCubierta()) {
textoResumen += ms.getMessage( textoResumen += ms.getMessage(
"presupuesto.resumen-texto-solapas-cubierta", "presupuesto.resumen-texto-solapas-cubierta",
new Object[] { p.getTamanioSolapasCubierta() }, new Object[] { p.getTamanioSolapasCubierta() },
locale locale);
);
} }
} }
// tapa dura // tapa dura
else if (p.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDura else if (p.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDura
|| p.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDuraLomoRedondo) { || p.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDuraLomoRedondo) {
String textImpresionGuardas = ""; String textImpresionGuardas = "";
if (p.getGuardasImpresas() == 0) { if (p.getGuardasImpresas() == 0) {
@ -81,52 +83,48 @@ public class PresupuestoFormatter {
} }
textoResumen += ms.getMessage( textoResumen += ms.getMessage(
"presupuesto.resumen-texto-guardas-cabezada", "presupuesto.resumen-texto-guardas-cabezada",
new Object[] { new Object[] {
textImpresionGuardas, textImpresionGuardas,
papeles.labelPapel(p.getPapelGuardasId(), locale), papeles.labelPapel(p.getPapelGuardasId(), locale),
p.getGramajeGuardas(), p.getGramajeGuardas(),
papeles.labelCabezada(p.getCabezada(), locale), papeles.labelCabezada(p.getCabezada(), locale),
}, },
locale locale);
);
} }
if (p.getAcabado() != null) { if (p.getAcabado() != null) {
textoResumen += ms.getMessage( textoResumen += ms.getMessage(
"presupuesto.resumen-texto-acabado-cubierta", "presupuesto.resumen-texto-acabado-cubierta",
new Object[] { acabados.labelAcabado(p.getAcabado(), locale) }, new Object[] { acabados.labelAcabado(p.getAcabado(), locale) },
locale locale);
);
} }
textoResumen += ms.getMessage("presupuesto.resumen-texto-end", null, locale); textoResumen += ms.getMessage("presupuesto.resumen-texto-end", null, locale);
if (Boolean.TRUE.equals(p.getSobrecubierta())) { if (Boolean.TRUE.equals(p.getSobrecubierta())) {
textoResumen += ms.getMessage( textoResumen += ms.getMessage(
"presupuesto.resumen-texto-sobrecubierta", "presupuesto.resumen-texto-sobrecubierta",
new Object[] { new Object[] {
papeles.labelPapel(p.getPapelSobrecubiertaId(), locale), papeles.labelPapel(p.getPapelSobrecubiertaId(), locale),
p.getGramajeSobrecubierta(), p.getGramajeSobrecubierta(),
acabados.labelAcabado(p.getAcabadoSobrecubierta(), locale), acabados.labelAcabado(p.getAcabadoSobrecubierta(), locale),
p.getTamanioSolapasSobrecubierta() p.getTamanioSolapasSobrecubierta()
}, },
locale locale);
);
} }
if (Boolean.TRUE.equals(p.getFaja())) { if (Boolean.TRUE.equals(p.getFaja())) {
textoResumen += ms.getMessage( textoResumen += ms.getMessage(
"presupuesto.resumen-texto-faja", "presupuesto.resumen-texto-faja",
new Object[] { new Object[] {
papeles.labelPapel(p.getPapelFajaId(), locale), papeles.labelPapel(p.getPapelFajaId(), locale),
p.getGramajeFaja(), p.getGramajeFaja(),
p.getAltoFaja(), p.getAltoFaja(),
acabados.labelAcabado(p.getAcabadoFaja(), locale), acabados.labelAcabado(p.getAcabadoFaja(), locale),
p.getTamanioSolapasFaja() p.getTamanioSolapasFaja()
}, },
locale locale);
);
} }
textoResumen += ms.getMessage("presupuesto.resumen-texto-end", null, locale); textoResumen += ms.getMessage("presupuesto.resumen-texto-end", null, locale);

View File

@ -171,6 +171,7 @@ presupuesto.resumen-texto-acabado-cubierta= <li>Acabado {0}. </li>
presupuesto.resumen-texto-end=</ul> presupuesto.resumen-texto-end=</ul>
presupuesto.resumen-texto-sobrecubierta=<li>Sobrecubierta impresa en {0} {1} gr. <ul><li>Acabado {2}</li><li>Solapas: {3} mm.</li></ul></li> presupuesto.resumen-texto-sobrecubierta=<li>Sobrecubierta impresa en {0} {1} gr. <ul><li>Acabado {2}</li><li>Solapas: {3} mm.</li></ul></li>
presupuesto.resumen-texto-faja=<li>Faja impresa en {0} {1} gr. con un alto de {2} mm. <ul><li>Acabado {3}</li><li>Solapas: {4} mm.</li></ul></li> presupuesto.resumen-texto-faja=<li>Faja impresa en {0} {1} gr. con un alto de {2} mm. <ul><li>Acabado {3}</li><li>Solapas: {4} mm.</li></ul></li>
presupuesto.resumen-deposito-legal=4 ejemplares para el Depósito Legal
presupuesto.volver-extras=Volver a extras presupuesto.volver-extras=Volver a extras
# Resumen del presupuesto # Resumen del presupuesto

View File

@ -1381,6 +1381,8 @@ class PresupuestoCliente {
******************************/ ******************************/
#initExtras() { #initExtras() {
const self = this;
$(document).on('click', '.btn-change-tab-extras', (e) => { $(document).on('click', '.btn-change-tab-extras', (e) => {
const id = e.currentTarget.id; const id = e.currentTarget.id;
@ -1394,13 +1396,13 @@ class PresupuestoCliente {
$('.service-checkbox:checked').each(function () { $('.service-checkbox:checked').each(function () {
const $servicio = $(this); const $servicio = $(this);
servicios.push({ servicios.push({
id: $(`label[for="${$servicio.attr('id')}"] .service-title`).text().trim() || $servicio.attr('id'), id: $servicio.attr('id') ?? $(`label[for="${$servicio.attr('id')}"] .service-title`).text().trim(),
price: $(`label[for="${$servicio.attr('id')}"] .service-price`).text().trim() || $servicio.attr('price') price: $servicio.data('price') ?? $(`label[for="${$servicio.attr('id')}"] .service-price`).text().trim().replace(" " + self.divExtras.data('currency'), ''),
}); });
}); });
const body = { const body = {
presupuesto: this.#getPresupuestoData(), // objeto JS con campos que coincidan con la entidad presupuesto: this.#getPresupuestoData(),
servicios: servicios servicios: servicios
}; };

View File

@ -75,6 +75,9 @@ $(document).on("submit", "#maquetacionForm", function (e) {
stored.servicios.datosMaquetacion.resultado.num_paginas_estimadas = json.numPaginasEstimadas; stored.servicios.datosMaquetacion.resultado.num_paginas_estimadas = json.numPaginasEstimadas;
stored.servicios.datosMaquetacion.resultado.precio_pagina_estimado = json.precioPaginaEstimado; stored.servicios.datosMaquetacion.resultado.precio_pagina_estimado = json.precioPaginaEstimado;
stored.servicios.datosMaquetacion.resultado.precio = json.precio; stored.servicios.datosMaquetacion.resultado.precio = json.precio;
if(stored.servicios.servicios.includes("maquetacion") === false) {
stored.servicios.servicios.push("maquetacion");
}
sessionStorage.setItem("formData", JSON.stringify(stored)); sessionStorage.setItem("formData", JSON.stringify(stored));
} }
else { else {

View File

@ -73,6 +73,9 @@ $(document).on("submit", "#marcapaginasForm", function (e) {
const stored = JSON.parse(sessionStorage.getItem("formData")); const stored = JSON.parse(sessionStorage.getItem("formData"));
stored.servicios.datosMarcapaginas.resultado.precio_unitario = json.precio_unitario; stored.servicios.datosMarcapaginas.resultado.precio_unitario = json.precio_unitario;
stored.servicios.datosMarcapaginas.resultado.precio = json.precio_total; stored.servicios.datosMarcapaginas.resultado.precio = json.precio_total;
if(stored.servicios.servicios.includes("marcapaginas") === false) {
stored.servicios.servicios.push("marcapaginas");
}
sessionStorage.setItem("formData", JSON.stringify(stored)); sessionStorage.setItem("formData", JSON.stringify(stored));
} }
else { else {

View File

@ -33,7 +33,11 @@ export function formateaNumero({
export function isNumber(value) { export function isNumber(value) {
return !isNaN(Number(value)) && value.trim() !== '';
if(typeof value === 'string') {
if(value.trim() === '') return false;
}
return !isNaN(Number(value));
} }
// Aplana un objeto a "prefijo.clave" (sin arrays) // Aplana un objeto a "prefijo.clave" (sin arrays)