package com.imprimelibros.erp.common; import java.math.BigDecimal; import java.math.RoundingMode; import java.security.Principal; import java.text.NumberFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.function.BiFunction; import org.springframework.context.MessageSource; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.imprimelibros.erp.datatables.DataTablesRequest; import com.imprimelibros.erp.presupuesto.classes.PresupuestoFormatter; import com.imprimelibros.erp.presupuesto.dto.Presupuesto; import com.imprimelibros.erp.presupuesto.maquetacion.MaquetacionMatrices; import com.imprimelibros.erp.presupuesto.marcapaginas.Marcapaginas; import com.imprimelibros.erp.users.User; import com.imprimelibros.erp.users.UserDetailsImpl; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Path; import jakarta.persistence.criteria.Predicate; import java.util.function.Function; @Component public class Utils { private final PresupuestoFormatter presupuestoFormatter; private final MessageSource messageSource; public Utils(PresupuestoFormatter presupuestoFormatter, MessageSource messageSource) { this.presupuestoFormatter = presupuestoFormatter; this.messageSource = messageSource; } public static Long currentUserId(Principal principal) { if (principal == null) { throw new IllegalStateException("Usuario no autenticado"); } if (principal instanceof Authentication auth) { Object principalObj = auth.getPrincipal(); if (principalObj instanceof UserDetailsImpl udi) { return udi.getId(); } else if (principalObj instanceof User u && u.getId() != null) { return u.getId(); } } throw new IllegalStateException("No se pudo obtener el ID del usuario actual"); } public static String formatCurrency(BigDecimal amount, Locale locale) { NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(locale); return currencyFormatter.format(amount); } public static String formatCurrency(Double amount, Locale locale) { NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(locale); return currencyFormatter.format(amount); } public static String formatNumber(BigDecimal amount, Locale locale) { NumberFormat numberFormatter = NumberFormat.getNumberInstance(locale); return numberFormatter.format(amount); } public static String formatNumber(Double amount, Locale locale) { NumberFormat numberFormatter = NumberFormat.getNumberInstance(locale); return numberFormatter.format(amount); } public static Optional, CriteriaBuilder, Predicate>> parseNumericFilter( DataTablesRequest dt, String colName, Locale locale) { String raw = dt.getColumnSearch(colName); // usa el "name" del DataTable (snake_case) if (raw == null || raw.isBlank()) return Optional.empty(); String s = raw.trim(); // normaliza número con coma o punto Function toBig = x -> { String t = x.replace(".", "").replace(",", "."); // 1.234,56 -> 1234.56 return new BigDecimal(t); }; try { if (s.matches("(?i)^>=?\\s*[-\\d.,]+$")) { BigDecimal v = toBig.apply(s.replace(">=", "").replace(">", "").trim()); return Optional.of((path, cb) -> cb.greaterThanOrEqualTo(path, v)); } if (s.matches("(?i)^<=?\\s*[-\\d.,]+$")) { BigDecimal v = toBig.apply(s.replace("<=", "").replace("<", "").trim()); return Optional.of((path, cb) -> cb.lessThanOrEqualTo(path, v)); } if (s.contains("-")) { // rango "a-b" String[] p = s.split("-"); if (p.length == 2) { BigDecimal a = toBig.apply(p[0].trim()); BigDecimal b = toBig.apply(p[1].trim()); BigDecimal min = a.min(b), max = a.max(b); return Optional.of((path, cb) -> cb.between(path, min, max)); } } // exacto/like numérico BigDecimal v = toBig.apply(s); return Optional.of((path, cb) -> cb.equal(path, v)); } catch (Exception ignore) { return Optional.empty(); } } public Map getTextoPresupuesto(Presupuesto presupuesto, Locale locale) { Map resumen = new HashMap<>(); resumen.put("titulo", presupuesto.getTitulo()); resumen.put("imagen", "/assets/images/imprimelibros/presupuestador/" + presupuesto.getTipoEncuadernacion() + ".png"); resumen.put("imagen_alt", messageSource.getMessage("presupuesto." + presupuesto.getTipoEncuadernacion(), null, locale)); resumen.put("presupuestoId", presupuesto.getId()); ObjectMapper mapper = new ObjectMapper(); List> servicios = new ArrayList<>(); if (presupuesto.getServiciosJson() != null && !presupuesto.getServiciosJson().isBlank()) try { servicios = mapper.readValue(presupuesto.getServiciosJson(), new TypeReference<>() { }); } catch (JsonProcessingException e) { // Manejar la excepción } boolean hayDepositoLegal = servicios != null && servicios.stream() .map(m -> java.util.Objects.toString(m.get("id"), "")) .map(String::trim) .anyMatch("deposito-legal"::equals); List> lineas = new ArrayList<>(); HashMap linea = new HashMap<>(); Double precio_unitario = 0.0; Double precio_total = 0.0; BigDecimal total = BigDecimal.ZERO; linea.put("descripcion", presupuestoFormatter.resumen(presupuesto, servicios, locale)); linea.put("cantidad", presupuesto.getSelectedTirada() != null ? presupuesto.getSelectedTirada() : 0); precio_unitario = (presupuesto.getPrecioUnitario() != null ? presupuesto.getPrecioUnitario().doubleValue() : 0.0); precio_total = (presupuesto.getPrecioTotalTirada() != null ? presupuesto.getPrecioTotalTirada().doubleValue() : 0.0); linea.put("precio_unitario", precio_unitario); linea.put("precio_total", BigDecimal.valueOf(precio_total).setScale(2, RoundingMode.HALF_UP)); total = total.add(BigDecimal.valueOf(precio_total)); lineas.add(linea); if (hayDepositoLegal) { linea = new HashMap<>(); linea.put("descripcion", messageSource.getMessage("pdf.ejemplares-deposito-legal", new Object[] { 4 }, locale)); lineas.add(linea); } String serviciosExtras = ""; if (servicios != null) { for (Map servicio : servicios) { if ("deposito-legal".equals(servicio.get("id")) || "service-isbn".equals(servicio.get("id"))) { serviciosExtras += messageSource.getMessage( "presupuesto.extras-" + servicio.get("id"), null, locale) + ", "; } else { serviciosExtras += messageSource.getMessage( "presupuesto.extras-" + servicio.get("id"), null, locale) .toLowerCase() + ", "; } } if (!serviciosExtras.isEmpty()) { serviciosExtras = serviciosExtras.substring(0, serviciosExtras.length() - 2); ; } if (servicios.stream().anyMatch(service -> "marcapaginas".equals(service.get("id")))) { ObjectMapper mapperServicio = new ObjectMapper(); Object raw = presupuesto.getDatosMarcapaginasJson(); Map datosMarcapaginas; String descripcion = ""; try { if (raw instanceof String s) { datosMarcapaginas = mapperServicio.readValue(s, new TypeReference>() { }); } else if (raw instanceof Map m) { datosMarcapaginas = mapperServicio.convertValue(m, new TypeReference>() { }); } else { throw new IllegalArgumentException( "Tipo no soportado para datosMarcapaginas: " + raw); } } catch (JsonProcessingException e) { throw new RuntimeException("Error parsing datosMarcapaginasJson", e); } descripcion += "
  • "; descripcion += Marcapaginas.Tamanios .valueOf(datosMarcapaginas.get("tamanio").toString()).getLabel() + ", "; descripcion += Marcapaginas.Caras_Impresion .valueOf(datosMarcapaginas.get("carasImpresion").toString()) .getMessageKey() + ", "; descripcion += messageSource .getMessage(Marcapaginas.Papeles .valueOf(datosMarcapaginas.get("papel") .toString()) .getMessageKey(), null, locale) + " - " + datosMarcapaginas.get("gramaje").toString() + " gr, "; descripcion += messageSource.getMessage( Marcapaginas.Acabado.valueOf( datosMarcapaginas.get("acabado").toString()) .getMessageKey(), null, locale); descripcion += "
"; resumen.put("datosMarcapaginas", descripcion); } if (servicios.stream().anyMatch(service -> "maquetacion".equals(service.get("id")))) { ObjectMapper mapperServicio = new ObjectMapper(); Object raw = presupuesto.getDatosMaquetacionJson(); Map datosMaquetacion; String descripcion = ""; try { if (raw instanceof String s) { datosMaquetacion = mapperServicio.readValue(s, new TypeReference>() { }); } else if (raw instanceof Map m) { datosMaquetacion = mapperServicio.convertValue(m, new TypeReference>() { }); } else { throw new IllegalArgumentException( "Tipo no soportado para datosMaquetacion: " + raw); } } catch (JsonProcessingException e) { throw new RuntimeException("Error parsing datosMaquetacionJson", e); } descripcion += "
  • "; descripcion += (datosMaquetacion.get("num_caracteres") + " " + messageSource.getMessage("presupuesto.maquetacion.caracteres", null, locale)) + ", "; descripcion += MaquetacionMatrices.Formato .valueOf(datosMaquetacion.get("formato_maquetacion").toString()) .getLabel() + ", "; descripcion += messageSource.getMessage(MaquetacionMatrices.FontSize .valueOf(datosMaquetacion.get("cuerpo_texto").toString()) .getMessageKey(), null, locale) + ", "; descripcion += messageSource.getMessage("presupuesto.maquetacion.num-columnas", null, locale) + ": " + datosMaquetacion.get("num_columnas").toString() + ", "; descripcion += messageSource.getMessage("presupuesto.maquetacion.num-tablas", null, locale) + ": " + datosMaquetacion.get("num_tablas").toString() + ", "; descripcion += messageSource.getMessage("presupuesto.maquetacion.num-fotos", null, locale) + ": " + datosMaquetacion.get("num_fotos").toString(); if ((boolean) datosMaquetacion.get("correccion_ortotipografica")) { descripcion += ", " + messageSource .getMessage("presupuesto.maquetacion.correccion-ortotipografica", null, locale); } if ((boolean) datosMaquetacion.get("texto_mecanografiado")) { descripcion += ", " + messageSource.getMessage( "presupuesto.maquetacion.texto-mecanografiado", null, locale); } if ((boolean) datosMaquetacion.get("disenio_portada")) { descripcion += ", " + messageSource.getMessage( "presupuesto.maquetacion.diseno-portada", null, locale); } if ((boolean) datosMaquetacion.get("epub")) { descripcion += ", " + messageSource.getMessage( "presupuesto.maquetacion.epub", null, locale); } descripcion += "
"; resumen.put("datosMaquetacion", descripcion); } } NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(locale); String formattedString = currencyFormat.format(total.setScale(2, RoundingMode.HALF_UP).doubleValue()); resumen.put("total", formattedString); resumen.put("lineas", lineas); resumen.put("servicios", serviciosExtras); return resumen; } }