package com.imprimelibros.erp.presupuesto; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.http.ResponseEntity; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.http.MediaType; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.core.type.TypeReference; import com.imprimelibros.erp.externalApi.skApiClient; import com.imprimelibros.erp.presupuesto.classes.ImagenPresupuesto; import com.imprimelibros.erp.presupuesto.classes.PresupuestoMaquetacion; import com.imprimelibros.erp.presupuesto.validation.PresupuestoValidationGroups; import jakarta.validation.Valid; @Controller @RequestMapping("/presupuesto") public class PresupuestoController { @Autowired protected PresupuestoService presupuestoService; @Autowired protected skApiClient apiClient; @Autowired protected MessageSource messageSource; @PostMapping("/public/validar/datos-generales") public ResponseEntity validarDatosGenerales( @Validated(PresupuestoValidationGroups.DatosGenerales.class) Presupuesto presupuesto, BindingResult result, Locale locale) { Map errores = new HashMap<>(); // errores de campos individuales result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage())); // errores globales (@ConsistentTiradas...) result.getGlobalErrors().forEach(error -> errores.put("global", error.getDefaultMessage())); if (!errores.isEmpty()) { return ResponseEntity.badRequest().body(errores); } // opciones color Map resultado = presupuestoService.obtenerOpcionesColor(presupuesto, locale); // opciones papel interior resultado.putAll(presupuestoService.obtenerOpcionesPapelInterior(presupuesto, locale)); // opciones gramaje interior resultado.putAll(presupuestoService.obtenerOpcionesGramajeInterior(presupuesto)); return ResponseEntity.ok(resultado); } @PostMapping("/public/validar/interior") public ResponseEntity validarInterior( @Validated(PresupuestoValidationGroups.Interior.class) Presupuesto presupuesto, BindingResult result, Locale locale) { Map errores = new HashMap<>(); // errores de campos individuales result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage())); // errores globales (@ConsistentTiradas...) result.getGlobalErrors().forEach(error -> errores.put("global", error.getDefaultMessage())); if (!errores.isEmpty()) { return ResponseEntity.badRequest().body(errores); } Map resultado = new HashMap<>(); resultado.put("solapas", apiClient.getMaxSolapas(presupuestoService.toSkApiRequest(presupuesto))); resultado.putAll(presupuestoService.obtenerOpcionesAcabadosCubierta(presupuesto, locale)); return ResponseEntity.ok(resultado); } @PostMapping("/public/validar/cubierta") public ResponseEntity validarCubierta( @Validated(PresupuestoValidationGroups.Cubierta.class) Presupuesto presupuesto, BindingResult result, @RequestParam(name = "calcular", defaultValue = "true") boolean calcular, Locale locale) { Map errores = new HashMap<>(); // errores de campos individuales result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage())); // errores globales (@ConsistentTiradas...) result.getGlobalErrors().forEach(error -> errores.put("global", error.getDefaultMessage())); if (!errores.isEmpty()) { return ResponseEntity.badRequest().body(errores); } if (calcular) { HashMap price = new HashMap<>(); String priceStr = apiClient.getPrice(presupuestoService.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)); } if (!price.containsKey("data")) { return ResponseEntity.badRequest() .body(messageSource.getMessage("presupuesto.error-obtener-precio", null, locale)); } return ResponseEntity.ok(price.get("data")); } return ResponseEntity.ok().build(); } @PostMapping("/public/validar/seleccion-tirada") public ResponseEntity validarSeleccionTirada( Presupuesto presupuesto, BindingResult result, Locale locale) { Map errores = new HashMap<>(); // errores de campos individuales result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage())); // errores globales (@ConsistentTiradas...) result.getGlobalErrors().forEach(error -> errores.put("global", error.getDefaultMessage())); if (!errores.isEmpty()) { return ResponseEntity.badRequest().body(errores); } Map resultado = new HashMap<>(); // servicios extra resultado.putAll(presupuestoService.obtenerServiciosExtras(presupuesto, locale, apiClient)); Map language = new HashMap<>(); language.put("calcular", messageSource.getMessage("presupuesto.calcular", null, locale)); resultado.put("language", language); return ResponseEntity.ok(resultado); } @PostMapping("/public/get-papel-interior") public ResponseEntity getPapelInterior( @Validated(PresupuestoValidationGroups.Interior.class) Presupuesto presupuesto, BindingResult result, Locale locale) { Map errores = new HashMap<>(); // errores de campos individuales result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage())); if (!errores.isEmpty()) { return ResponseEntity.badRequest().body(errores); } // opciones color Map resultado = presupuestoService.obtenerOpcionesPapelInterior(presupuesto, locale); // opciones gramaje interior resultado.putAll(presupuestoService.obtenerOpcionesGramajeInterior(presupuesto)); List opciones = (List) resultado.get("opciones_gramaje_interior"); if (opciones != null && !opciones.isEmpty()) { String gramajeActual = presupuesto.getGramajeInterior().toString(); if (!opciones.contains(gramajeActual)) { presupuesto.setGramajeInterior(Integer.parseInt(opciones.get(0))); // Asignar primera opción } } resultado.put("solapas", apiClient.getMaxSolapas(presupuestoService.toSkApiRequest(presupuesto))); return ResponseEntity.ok(resultado); } @PostMapping("/public/get-gramaje-interior") public ResponseEntity getGramajeInterior( @Validated(PresupuestoValidationGroups.Interior.class) Presupuesto presupuesto, BindingResult result) { Map errores = new HashMap<>(); // errores de campos individuales result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage())); if (!errores.isEmpty()) { return ResponseEntity.badRequest().body(errores); } Map resultado = presupuestoService.obtenerOpcionesGramajeInterior(presupuesto); List opciones = (List) resultado.get("opciones_gramaje_interior"); if (opciones != null && !opciones.isEmpty()) { String gramajeActual = presupuesto.getGramajeInterior().toString(); if (!opciones.contains(gramajeActual)) { presupuesto.setGramajeInterior(Integer.parseInt(opciones.get(0))); // Asignar primera opción } } resultado.put("solapas", apiClient.getMaxSolapas(presupuestoService.toSkApiRequest(presupuesto))); return ResponseEntity.ok(resultado); } @PostMapping("/public/get-max-solapas") public ResponseEntity getMaxSolapas( @Validated(PresupuestoValidationGroups.Interior.class) Presupuesto presupuesto, BindingResult result) { Map errores = new HashMap<>(); // errores de campos individuales result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage())); if (!errores.isEmpty()) { return ResponseEntity.badRequest().body(errores); } Map resultado = new HashMap<>(); resultado.put("solapas", apiClient.getMaxSolapas(presupuestoService.toSkApiRequest(presupuesto))); return ResponseEntity.ok(resultado); } @PostMapping("/public/get-papel-cubierta") public ResponseEntity getPapelCubierta( Presupuesto presupuesto, BindingResult result, Locale locale) { Map resultado = new HashMap<>(); Map papelesCubierta = presupuestoService.obtenerOpcionesPapelCubierta(presupuesto, locale); List opciones = (List) presupuestoService .obtenerOpcionesPapelCubierta(presupuesto, locale) .get("opciones_papel_cubierta"); if (opciones != null && opciones.stream().noneMatch( o -> o.getExtra_data().get("sk-id").equals(String.valueOf(presupuesto.getPapelCubiertaId())))) { presupuesto.setPapelCubiertaId(Integer.valueOf(opciones.get(0).getExtra_data().get("sk-id"))); } resultado.putAll(papelesCubierta); resultado.putAll(presupuestoService.obtenerOpcionesGramajeCubierta(presupuesto)); List gramajesCubierta = (List) resultado.get("opciones_gramaje_cubierta"); if (gramajesCubierta != null && !gramajesCubierta.isEmpty()) { String gramajeActual = presupuesto.getGramajeCubierta().toString(); if (!gramajesCubierta.contains(gramajeActual)) { presupuesto.setGramajeCubierta(Integer.parseInt(gramajesCubierta.get(0))); // Asignar primera opción } } return ResponseEntity.ok(resultado); } @PostMapping("/public/get-gramaje-cubierta") public ResponseEntity getGramajeCubierta( Presupuesto presupuesto, BindingResult result) { Map resultado = presupuestoService.obtenerOpcionesGramajeCubierta(presupuesto); List gramajesCubierta = (List) resultado.get("opciones_gramaje_cubierta"); if (gramajesCubierta != null && !gramajesCubierta.isEmpty()) { String gramajeActual = presupuesto.getGramajeCubierta().toString(); if (!gramajesCubierta.contains(gramajeActual)) { presupuesto.setGramajeCubierta(Integer.parseInt(gramajesCubierta.get(0))); // Asignar primera opción } } return ResponseEntity.ok(resultado); } @PostMapping("/public/get-acabados-cubierta") public ResponseEntity getAcabadosCubierta( Presupuesto presupuesto, BindingResult result, Locale locale) { Map resultado = presupuestoService.obtenerOpcionesAcabadosCubierta(presupuesto, locale); return ResponseEntity.ok(resultado); } @PostMapping("/public/get-price") public ResponseEntity getPrice( Presupuesto presupuesto, BindingResult result, Locale locale) { Map errores = new HashMap<>(); // errores de campos individuales result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage())); // errores globales (@ConsistentTiradas...) result.getGlobalErrors().forEach(error -> errores.put("global", error.getDefaultMessage())); if (!errores.isEmpty()) { return ResponseEntity.badRequest().body(errores); } String price = apiClient.getPrice(presupuestoService.toSkApiRequest(presupuesto)); if (price == null || price.isEmpty()) { return ResponseEntity.badRequest().body("No se pudo obtener el precio. Intente nuevamente."); } return ResponseEntity.ok(price); } @GetMapping(value = "/public/maquetacion/form", produces = MediaType.TEXT_HTML_VALUE) public String getMaquetacionForm(Model model) { model.addAttribute("presupuestoMaquetacion", new PresupuestoMaquetacion()); return "imprimelibros/presupuestos/presupuesto-maquetacion-form :: maquetacionForm"; } @GetMapping("/public/maquetacion") public ResponseEntity getPresupuestoMaquetacion( @Valid @ModelAttribute PresupuestoMaquetacion presupuestoMaquetacion, BindingResult result, Locale locale) { if (result.hasErrors()) { // Construimos un mapa field -> mensaje para tu AJAX Map errores = result.getFieldErrors().stream() .collect(java.util.stream.Collectors.toMap( fe -> fe.getField(), fe -> fe.getDefaultMessage(), (a, b) -> a)); return ResponseEntity.badRequest().body(errores); } Map resultado = presupuestoService.getPrecioMaquetacion(presupuestoMaquetacion, locale); if ((Double) resultado.get("precio") == 0.0 && (Integer) resultado.get("numPaginasEstimadas") == 0 && (Double) resultado.get("precioPaginaEstimado") == 0.0) { return ResponseEntity.badRequest() .body(messageSource.getMessage("presupuesto.errores.presupuesto-maquetacion", null, locale)); } return ResponseEntity.ok(resultado); } }