trabajando en leer datos de tipo cubierta

This commit is contained in:
2025-10-09 21:59:59 +02:00
parent 328ff509e3
commit 6c4b63daa6
17 changed files with 573 additions and 116 deletions

View File

@ -42,6 +42,8 @@ public class HomeController {
model.addAttribute("pod", variableService.getValorEntero("POD"));
model.addAttribute("ancho_alto_min", variableService.getValorEntero("ancho_alto_min"));
model.addAttribute("ancho_alto_max", variableService.getValorEntero("ancho_alto_max"));
model.addAttribute("appMode", "public");
}
else{
// empty translations for authenticated users

View File

@ -5,6 +5,7 @@ import org.springframework.ui.Model;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.List;
@ -17,6 +18,8 @@ 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.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
@ -35,7 +38,10 @@ import com.imprimelibros.erp.presupuesto.classes.ImagenPresupuesto;
import com.imprimelibros.erp.presupuesto.classes.PresupuestoMaquetacion;
import com.imprimelibros.erp.presupuesto.classes.PresupuestoMarcapaginas;
import com.imprimelibros.erp.presupuesto.dto.Presupuesto;
import com.imprimelibros.erp.presupuesto.service.PresupuestoService;
import com.imprimelibros.erp.presupuesto.validation.PresupuestoValidationGroups;
import com.imprimelibros.erp.presupuesto.service.PresupuestoFormDataMapper;
import com.imprimelibros.erp.presupuesto.service.PresupuestoFormDataMapper.PresupuestoFormDataDto;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
@ -59,15 +65,17 @@ public class PresupuestoController {
private final TranslationService translationService;
private final PresupuestoDatatableService dtService;
private final VariableService variableService;
private final PresupuestoFormDataMapper formDataMapper;
public PresupuestoController(ObjectMapper objectMapper, TranslationService translationService,
PresupuestoDatatableService dtService, PresupuestoRepository presupuestoRepository,
VariableService variableService) {
VariableService variableService, PresupuestoFormDataMapper formDataMapper) {
this.objectMapper = objectMapper;
this.translationService = translationService;
this.dtService = dtService;
this.presupuestoRepository = presupuestoRepository;
this.variableService = variableService;
this.formDataMapper = formDataMapper;
}
@PostMapping("/public/validar/datos-generales")
@ -77,12 +85,14 @@ public class PresupuestoController {
Map<String, String> 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()));
result.getFieldErrors().forEach(error -> {
String code = Objects.requireNonNullElse(error.getDefaultMessage(), "").replace("{", "").replace("}", "");
String msg = messageSource.getMessage(code, null, locale);
errores.put(error.getField(), msg);
});
result.getGlobalErrors().forEach(error -> {
errores.put("global", error.getDefaultMessage());
});
if (!errores.isEmpty()) {
return ResponseEntity.badRequest().body(errores);
}
@ -106,7 +116,12 @@ public class PresupuestoController {
Map<String, String> errores = new HashMap<>();
// errores de campos individuales
result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage()));
result.getFieldErrors().forEach(error -> {
String code = Objects.requireNonNullElse(error.getDefaultMessage(), "").replace("{", "").replace("}", "");
String msg = messageSource.getMessage(code, null, locale);
errores.put(error.getField(), msg);
});
// errores globales (@ConsistentTiradas...)
result.getGlobalErrors().forEach(error -> errores.put("global", error.getDefaultMessage()));
@ -130,7 +145,12 @@ public class PresupuestoController {
Map<String, String> errores = new HashMap<>();
// errores de campos individuales
result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage()));
result.getFieldErrors().forEach(error -> {
String code = Objects.requireNonNullElse(error.getDefaultMessage(), "").replace("{", "").replace("}", "");
String msg = messageSource.getMessage(code, null, locale);
errores.put(error.getField(), msg);
});
// errores globales (@ConsistentTiradas...)
result.getGlobalErrors().forEach(error -> errores.put("global", error.getDefaultMessage()));
@ -161,7 +181,12 @@ public class PresupuestoController {
Map<String, String> errores = new HashMap<>();
// errores de campos individuales
result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage()));
result.getFieldErrors().forEach(error -> {
String code = Objects.requireNonNullElse(error.getDefaultMessage(), "").replace("{", "").replace("}", "");
String msg = messageSource.getMessage(code, null, locale);
errores.put(error.getField(), msg);
});
// errores globales (@ConsistentTiradas...)
result.getGlobalErrors().forEach(error -> errores.put("global", error.getDefaultMessage()));
@ -188,7 +213,12 @@ public class PresupuestoController {
Map<String, String> errores = new HashMap<>();
// errores de campos individuales
result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage()));
result.getFieldErrors().forEach(error -> {
String code = Objects.requireNonNullElse(error.getDefaultMessage(), "").replace("{", "").replace("}", "");
String msg = messageSource.getMessage(code, null, locale);
errores.put(error.getField(), msg);
});
if (!errores.isEmpty()) {
return ResponseEntity.badRequest().body(errores);
@ -200,7 +230,19 @@ public class PresupuestoController {
// opciones gramaje interior
resultado.putAll(presupuestoService.obtenerOpcionesGramajeInterior(presupuesto));
List<String> opciones = new ObjectMapper().convertValue(resultado.get("opciones_papel_interior"),
List<ImagenPresupuesto> opciones_papel = new ObjectMapper().convertValue(
presupuestoService
.obtenerOpcionesPapelInterior(presupuesto, locale)
.get("opciones_papel_interior"),
new TypeReference<List<ImagenPresupuesto>>() {
});
if (opciones_papel != null && opciones_papel.stream().noneMatch(
o -> o.getExtra_data().get("sk-id").equals(String.valueOf(presupuesto.getPapelInteriorId())))) {
presupuesto.setPapelInteriorId(Integer.valueOf(opciones_papel.get(0).getExtra_data().get("sk-id")));
}
List<String> opciones = new ObjectMapper().convertValue(resultado.get("opciones_gramaje_interior"),
new TypeReference<List<String>>() {
});
@ -218,12 +260,17 @@ public class PresupuestoController {
@PostMapping("/public/get-gramaje-interior")
public ResponseEntity<?> getGramajeInterior(
@Validated(PresupuestoValidationGroups.Interior.class) Presupuesto presupuesto,
BindingResult result) {
BindingResult result, Locale locale) {
Map<String, String> errores = new HashMap<>();
// errores de campos individuales
result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage()));
result.getFieldErrors().forEach(error -> {
String code = Objects.requireNonNullElse(error.getDefaultMessage(), "").replace("{", "").replace("}", "");
String msg = messageSource.getMessage(code, null, locale);
errores.put(error.getField(), msg);
});
if (!errores.isEmpty()) {
return ResponseEntity.badRequest().body(errores);
@ -247,12 +294,17 @@ public class PresupuestoController {
@PostMapping("/public/get-max-solapas")
public ResponseEntity<?> getMaxSolapas(
@Validated(PresupuestoValidationGroups.Interior.class) Presupuesto presupuesto,
BindingResult result) {
BindingResult result, Locale locale) {
Map<String, String> errores = new HashMap<>();
// errores de campos individuales
result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage()));
result.getFieldErrors().forEach(error -> {
String code = Objects.requireNonNullElse(error.getDefaultMessage(), "").replace("{", "").replace("}", "");
String msg = messageSource.getMessage(code, null, locale);
errores.put(error.getField(), msg);
});
if (!errores.isEmpty()) {
return ResponseEntity.badRequest().body(errores);
@ -462,16 +514,6 @@ public class PresupuestoController {
// Buscar el presupuesto
Optional<Presupuesto> presupuestoOpt = presupuestoRepository.findById(id);
boolean isUser = authentication.getAuthorities().stream()
.anyMatch(a -> a.getAuthority().equals("ROLE_USER"));
if (isUser) {
// Si es usuario, solo puede ver sus propios presupuestos
String username = authentication.getName();
if (!presupuestoOpt.get().getUser().getUserName().equals(username)) {
presupuestoOpt = Optional.empty();
}
}
if (presupuestoOpt.isEmpty()) {
// Añadir mensaje flash para mostrar alerta
@ -481,11 +523,44 @@ public class PresupuestoController {
return "redirect:/presupuesto";
}
// Si existe, lo añadimos al modelo
model.addAttribute("presupuesto", presupuestoOpt.get());
if (!presupuestoService.canAccessPresupuesto(presupuestoOpt.get(), authentication)) {
// Añadir mensaje flash para mostrar alerta
redirectAttributes.addFlashAttribute("errorMessage",
messageSource.getMessage("app.errors.403", null, locale));
// Redirigir a la vista de lista
return "redirect:/presupuesto";
}
String path = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest().getRequestURI();
String mode = path.contains("/view/") ? "view" : "edit";
if (mode.equals("view")) {
model.addAttribute("appMode", "view");
} else {
model.addAttribute("appMode", "edit");
}
model.addAttribute("id", presupuestoOpt.get().getId());
return "imprimelibros/presupuestos/presupuesto-form";
}
@GetMapping(value = "/api/get", produces = "application/json")
public ResponseEntity<PresupuestoFormDataDto> getPresupuesto(
@RequestParam("id") Long id, Authentication authentication) {
Optional<Presupuesto> presupuestoOpt = presupuestoRepository.findById(id);
if (!presupuestoService.canAccessPresupuesto(presupuestoOpt.get(), authentication)) {
return ResponseEntity.status(403).build();
}
if (presupuestoOpt.isPresent()) {
PresupuestoFormDataDto vm = formDataMapper.toFormData(presupuestoOpt.get());
return ResponseEntity.ok(vm);
} else {
return ResponseEntity.notFound().build();
}
}
@GetMapping(value = "/datatable/anonimos", produces = "application/json")
@ResponseBody
public DataTablesResponse<Map<String, Object>> datatableAnonimos(

View File

@ -0,0 +1,266 @@
package com.imprimelibros.erp.presupuesto.service;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imprimelibros.erp.presupuesto.dto.Presupuesto;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Service
public class PresupuestoFormDataMapper {
public class PresupuestoFormDataDto {
public DatosGenerales datosGenerales = new DatosGenerales();
public Interior interior = new Interior();
public Cubierta cubierta = new Cubierta();
public Servicios servicios = new Servicios();
public Integer selectedTirada;
// ===== Datos Generales =====
public static class DatosGenerales {
public String titulo = "";
public String autor = "";
public String isbn = "";
public String tirada1 = "";
public String tirada2 = "";
public String tirada3 = "";
public String tirada4 = "";
public Integer ancho;
public Integer alto;
public boolean formatoPersonalizado = false;
public String paginasNegro = "";
public String paginasColor = "";
public String posicionPaginasColor = "";
public String tipoEncuadernacion = "fresado"; // enum name
}
// ===== Interior =====
public static class Interior {
public String tipoImpresion = "negro"; // enum name
public Integer papelInteriorId = 3;
public Integer gramajeInterior = 80;
}
// ===== Cubierta =====
public static class Cubierta {
public String tipoCubierta = "tapaBlanda"; // enum name
public int solapasCubierta = 0; // 0/1 para tu UI
public String tamanioSolapasCubierta = "80";
public Integer cubiertaCaras = 2;
public Integer papelGuardasId = 3;
public Integer gramajeGuardas = 170;
public Integer guardasImpresas = 0;
public String cabezada = "WHI";
public Integer papelCubiertaId = 3;
public Integer gramajeCubierta = 170;
public Integer acabado = 1;
public SobreCubierta sobrecubierta = new SobreCubierta();
public Faja faja = new Faja();
public static class SobreCubierta {
public boolean activo = false;
public Integer papelSobrecubiertaId = 2;
public Integer gramajeSobrecubierta = 170;
public Integer tamanioSolapasSobrecubierta = 80;
public Integer acabado = 0;
}
public static class Faja {
public boolean activo = false;
public Integer papelFajaId = 2;
public Integer gramajeFaja = 170;
public Integer alto = 50;
public Integer tamanioSolapasFaja = 80;
public Integer acabado = 0;
}
}
// ===== Servicios / Extras =====
public static class Servicios {
public List<String> servicios = List.of();
public DatosMarcapaginas datosMarcapaginas = new DatosMarcapaginas();
public DatosMaquetacion datosMaquetacion = new DatosMaquetacion();
public static class DatosMarcapaginas {
public Integer marcapaginas_tirada = 100;
public String tamanio_marcapaginas = "_50x140_";
public String caras_impresion = "una_cara";
public String papel_marcapaginas = "cartulina_grafica";
public Integer gramaje_marcapaginas = 300;
public String acabado_marcapaginas = "ninguno";
public Resultado resultado = new Resultado();
}
public static class DatosMaquetacion {
public Integer num_caracteres = 200000;
public String formato_maquetacion = "A5";
public String cuerpo_texto = "medium";
public Integer num_columnas = 1;
public Integer num_tablas = 0;
public Integer num_fotos = 0;
public boolean correccion_ortotipografica = false;
public boolean texto_mecanografiado = false;
public boolean disenio_portada = false;
public boolean epub = false;
public Resultado resultado = new Resultado();
}
public static class Resultado {
public Integer num_paginas_estimadas = 0; // solo para maquetación
public Integer precio_pagina_estimado = 0;
public Number precio_unitario = 0; // solo para marcapáginas
public Number precio = 0;
}
}
}
private final ObjectMapper om = new ObjectMapper();
public PresupuestoFormDataDto toFormData(Presupuesto p) {
PresupuestoFormDataDto vm = new PresupuestoFormDataDto();
// ===== Datos Generales
vm.datosGenerales.titulo = nz(p.getTitulo(), "");
vm.datosGenerales.autor = nz(p.getAutor(), "");
vm.datosGenerales.isbn = nz(p.getIsbn(), "");
vm.datosGenerales.tirada1 = nzStr(p.getTirada1());
vm.datosGenerales.tirada2 = nzStr(p.getTirada2());
vm.datosGenerales.tirada3 = nzStr(p.getTirada3());
vm.datosGenerales.tirada4 = nzStr(p.getTirada4());
vm.datosGenerales.ancho = p.getAncho();
vm.datosGenerales.alto = p.getAlto();
vm.datosGenerales.formatoPersonalizado = Boolean.TRUE.equals(p.getFormatoPersonalizado());
vm.datosGenerales.paginasNegro = nzStr(p.getPaginasNegro());
vm.datosGenerales.paginasColor = nzStr(p.getPaginasColor());
vm.datosGenerales.posicionPaginasColor = nz(p.getPosicionPaginasColor(), "");
vm.datosGenerales.tipoEncuadernacion = enumName(p.getTipoEncuadernacion(), "fresado");
// ===== Interior
vm.interior.tipoImpresion = enumName(p.getTipoImpresion(), "negro");
vm.interior.papelInteriorId = nz(p.getPapelInteriorId(), 3);
vm.interior.gramajeInterior = nz(p.getGramajeInterior(), 80);
// ===== Cubierta
vm.cubierta.tipoCubierta = enumName(p.getTipoCubierta(), "tapaBlanda");
vm.cubierta.solapasCubierta = Boolean.TRUE.equals(p.getSolapasCubierta()) ? 1 : 0;
vm.cubierta.tamanioSolapasCubierta = String.valueOf(nz(p.getTamanioSolapasCubierta(), 80));
vm.cubierta.cubiertaCaras = nz(p.getCubiertaCaras(), 2);
vm.cubierta.papelGuardasId = nz(p.getPapelGuardasId(), 3);
vm.cubierta.gramajeGuardas = nz(p.getGramajeGuardas(), 170);
vm.cubierta.guardasImpresas = nz(p.getGuardasImpresas(), 0);
vm.cubierta.cabezada = nz(p.getCabezada(), "WHI");
vm.cubierta.papelCubiertaId = nz(p.getPapelCubiertaId(), 3);
vm.cubierta.gramajeCubierta = nz(p.getGramajeCubierta(), 170);
vm.cubierta.acabado = nz(p.getAcabado(), 1);
vm.cubierta.sobrecubierta.activo = Boolean.TRUE.equals(p.getSobrecubierta());
vm.cubierta.sobrecubierta.papelSobrecubiertaId = nz(p.getPapelSobrecubiertaId(), 2);
vm.cubierta.sobrecubierta.gramajeSobrecubierta = nz(p.getGramajeSobrecubierta(), 170);
vm.cubierta.sobrecubierta.tamanioSolapasSobrecubierta = nz(p.getTamanioSolapasSobrecubierta(), 80);
vm.cubierta.sobrecubierta.acabado = nz(p.getAcabadoSobrecubierta(), 0);
vm.cubierta.faja.activo = Boolean.TRUE.equals(p.getFaja());
vm.cubierta.faja.papelFajaId = nz(p.getPapelFajaId(), 2);
vm.cubierta.faja.gramajeFaja = nz(p.getGramajeFaja(), 170);
vm.cubierta.faja.tamanioSolapasFaja = nz(p.getTamanioSolapasFaja(), 80);
vm.cubierta.faja.acabado = nz(p.getAcabadoFaja(), 0);
vm.cubierta.faja.alto = nz(p.getAltoFaja(), 50);
// ===== Selected tirada
vm.selectedTirada = p.getSelectedTirada();
// ===== Servicios desde JSONs
// servicios_json: acepta ["maquetacion","marcapaginas"] o [{id:...}, ...]
vm.servicios.servicios = parseServiciosIds(p.getServiciosJson());
// datos_maquetacion_json
PresupuestoFormDataDto.Servicios.DatosMaquetacion maq = parse(p.getDatosMaquetacionJson(),
PresupuestoFormDataDto.Servicios.DatosMaquetacion.class);
if (maq != null)
vm.servicios.datosMaquetacion = merge(vm.servicios.datosMaquetacion, maq);
// datos_marcapaginas_json
PresupuestoFormDataDto.Servicios.DatosMarcapaginas mp = parse(p.getDatosMarcapaginasJson(),
PresupuestoFormDataDto.Servicios.DatosMarcapaginas.class);
if (mp != null)
vm.servicios.datosMarcapaginas = merge(vm.servicios.datosMarcapaginas, mp);
return vm;
}
// ===== Helpers =====
private static String enumName(Enum<?> e, String def) {
return e != null ? e.name() : def;
}
private static String nz(String v, String def) {
return v != null ? v : def;
}
private static Integer nz(Integer v, Integer def) {
return v != null ? v : def;
}
private static String nzStr(Integer v) {
return v == null ? "" : String.valueOf(v);
}
private <T> T parse(String json, Class<T> type) {
try {
if (json == null || json.isBlank())
return null;
return om.readValue(json, type);
} catch (Exception e) {
return null;
}
}
private List<String> parseServiciosIds(String json) {
if (json == null || json.isBlank())
return new ArrayList<>();
try {
// 1) intentar como lista de strings
List<String> ids = om.readValue(json, new TypeReference<List<String>>() {
});
return ids != null ? ids : new ArrayList<>();
} catch (Exception ignore) {
}
try {
// 2) intentar como lista de objetos con 'id'
List<Map<String, Object>> list = om.readValue(json, new TypeReference<>() {
});
List<String> ids = new ArrayList<>();
for (Map<String, Object> it : list) {
Object id = it.get("id");
if (id != null)
ids.add(String.valueOf(id));
}
return ids;
} catch (
Exception e) {
return new ArrayList<>();
}
}
private <T> T merge(T base, T override) {
// merge muy simple: si override != null, devuélvelo; si no, base
// (si quisieras merge campo a campo, usa BeanUtils o MapStruct)
return override != null ? override : base;
}
}

View File

@ -1,4 +1,4 @@
package com.imprimelibros.erp.presupuesto;
package com.imprimelibros.erp.presupuesto.service;
import java.util.ArrayList;
import java.util.Arrays;
@ -12,6 +12,7 @@ import java.text.NumberFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -23,6 +24,8 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import com.imprimelibros.erp.configurationERP.VariableService;
import com.imprimelibros.erp.presupuesto.GeoIpService;
import com.imprimelibros.erp.presupuesto.PresupuestoRepository;
import com.imprimelibros.erp.presupuesto.classes.ImagenPresupuesto;
import com.imprimelibros.erp.presupuesto.classes.PresupuestadorItems;
import com.imprimelibros.erp.presupuesto.classes.PresupuestoFormatter;
@ -954,6 +957,21 @@ public class PresupuestoService {
return price;
}
public Boolean canAccessPresupuesto(Presupuesto presupuesto, Authentication authentication) {
boolean isUser = authentication.getAuthorities().stream()
.anyMatch(a -> a.getAuthority().equals("ROLE_USER"));
if (isUser) {
// Si es usuario, solo puede ver sus propios presupuestos
String username = authentication.getName();
if (!presupuesto.getUser().getUserName().equals(username)) {
return false;
}
}
return true;
}
// =======================================================================