preparando el imprimir

This commit is contained in:
2025-10-12 21:42:04 +02:00
parent 6641c1f077
commit 26c2ca543a
41 changed files with 1325 additions and 208 deletions

View File

@ -41,6 +41,10 @@ import com.imprimelibros.erp.presupuesto.maquetacion.MaquetacionMatricesReposito
import com.imprimelibros.erp.presupuesto.marcapaginas.MarcapaginasRepository;
import com.imprimelibros.erp.users.UserDao;
import com.imprimelibros.erp.users.UserDetailsImpl;
import jakarta.persistence.criteria.CriteriaBuilder.In;
import jakarta.servlet.http.HttpServletRequest;
import com.imprimelibros.erp.externalApi.skApiClient;
@Service
@ -448,6 +452,16 @@ public class PresupuestoService {
: "0.00";
}
private String obtenerPrecioRetractilado(Integer tirada) {
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("tirada",tirada != null ? tirada : 0);
Double precio_retractilado = apiClient.getRetractilado(requestBody);
return precio_retractilado != null
? String.valueOf(Math.round(precio_retractilado * 100.0) / 100.0)
: "0.00";
}
public Map<String, Object> obtenerServiciosExtras(Presupuesto presupuesto, Locale locale) {
List<Object> opciones = new ArrayList<>();
@ -747,13 +761,20 @@ public class PresupuestoService {
if (hayDepositoLegal) {
pressupuestoTemp.setSelectedTirada(
presupuesto.getSelectedTirada() != null ? presupuesto.getSelectedTirada() + 4 : 4);
for (Integer i = 0; i < pressupuestoTemp.getTiradas().length; i++) {
Integer tirada = pressupuestoTemp.getTiradas()[i];
if (tirada != null && tirada >= 4) {
tirada = tirada + 4;
}
pressupuestoTemp.getTiradas()[i] = tirada;
}
}
HashMap<String, Object> precios = this.calcularPresupuesto(pressupuestoTemp, locale);
if (precios.containsKey("error")) {
resumen.put("error", precios.get("error"));
return resumen;
}
resumen.put("precios", precios);
HashMap<String, Object> linea = new HashMap<>();
Double precio_unitario = 0.0;
@ -824,7 +845,7 @@ public class PresupuestoService {
if (mode.equals("public")) {
presupuesto = getDatosLocalizacion(presupuesto, sessionId, ip);
} else
presupuesto.setOrigen(Presupuesto.Origen.privado);
@ -847,7 +868,7 @@ public class PresupuestoService {
if (save != null && save) {
// Si NO es para guardar (solo calcular resumen), devolver sin persistir
this.guardarPresupuesto(presupuesto);
presupuestoRepository.saveAndFlush(presupuesto);
}
// Opcional: devolver el id guardado al frontend para que lo envíe en llamadas
@ -865,24 +886,24 @@ public class PresupuestoService {
}
public Presupuesto getDatosLocalizacion(Presupuesto presupuesto, String sessionId, String ip) {
presupuesto.setOrigen(Presupuesto.Origen.publico);
presupuesto.setSessionId(sessionId);
// IP: guarda hash y trunc (si tienes campos). Si no, guarda tal cual en
// ip_trunc/ip_hash según tu modelo.
String ipTrunc = anonymizeIp(ip);
presupuesto.setIpTrunc(ipTrunc);
presupuesto.setIpHash(Integer.toHexString(ip.hashCode()));
// ubicación (si tienes un servicio GeoIP disponible; si no, omite estas tres
// líneas)
try {
GeoIpService.GeoData geo = geoIpService.lookup(ip).orElse(null);
presupuesto.setPais(geo.getPais());
presupuesto.setRegion(geo.getRegion());
presupuesto.setCiudad(geo.getCiudad());
} catch (Exception ignore) {
}
presupuesto.setOrigen(Presupuesto.Origen.publico);
presupuesto.setSessionId(sessionId);
// IP: guarda hash y trunc (si tienes campos). Si no, guarda tal cual en
// ip_trunc/ip_hash según tu modelo.
String ipTrunc = anonymizeIp(ip);
presupuesto.setIpTrunc(ipTrunc);
presupuesto.setIpHash(Integer.toHexString(ip.hashCode()));
// ubicación (si tienes un servicio GeoIP disponible; si no, omite estas tres
// líneas)
try {
GeoIpService.GeoData geo = geoIpService.lookup(ip).orElse(null);
presupuesto.setPais(geo.getPais());
presupuesto.setRegion(geo.getRegion());
presupuesto.setCiudad(geo.getCiudad());
} catch (Exception ignore) {
}
return presupuesto;
}
@ -892,84 +913,185 @@ public class PresupuestoService {
Map<String, Object> resumen,
Locale locale) {
// Genera los totalizadores (precio unitario, total tirada, etc.) sin guardar
double precioUnit = 0.0;
int cantidad = presupuesto.getSelectedTirada() != null ? presupuesto.getSelectedTirada() : 0;
try {
@SuppressWarnings("unchecked")
List<Double> precios = (List<Double>) ((Map<String, Object>) resumen.getOrDefault("precios", Map.of()))
.getOrDefault("precios", List.of());
if (precios.isEmpty()) {
// si no venía en "resumen", recalcúlalo directamente
var preciosCalc = this.calcularPresupuesto(presupuesto, locale);
precios = (List<Double>) ((Map<String, Object>) preciosCalc.get("data")).get("precios");
}
precioUnit = precios.get(0);
// guarda el snapshot completo de precios para auditoría
presupuesto.setPreciosPorTiradaJson(new ObjectMapper().writeValueAsString(precios));
} catch (Exception ignore) {
Map<Integer, Map<String, Object>> pricing_snapshot = new HashMap<>();
@SuppressWarnings("unchecked")
Map<String, Object> preciosNode = (Map<String, Object>) resumen.getOrDefault("precios", Map.of());
@SuppressWarnings("unchecked")
Map<String, Object> data = (Map<String, Object>) preciosNode.getOrDefault("data", Map.of());
@SuppressWarnings("unchecked")
List<Integer> tiradas = (List<Integer>) data.getOrDefault("tiradas", List.of());
@SuppressWarnings("unchecked")
List<Double> precios = (List<Double>) data.getOrDefault("precios", List.of());
@SuppressWarnings("unchecked")
List<Double> pesos = (List<Double>) data.getOrDefault("peso", List.of());
if (precios.isEmpty()) {
var preciosCalc = this.calcularPresupuesto(presupuesto, locale);
precios = (List<Double>) ((Map<String, Object>) preciosCalc.get("data")).getOrDefault("precios", List.of());
}
BigDecimal precioTotalTirada = BigDecimal.valueOf(precioUnit)
.multiply(BigDecimal.valueOf(cantidad))
.setScale(2, RoundingMode.HALF_UP);
// iterate getTiradas with a foreach with not null
for (Integer tirada : presupuesto.getTiradas()) {
if (tirada == null) {
continue;
}
// servicios_total
BigDecimal serviciosTotal = BigDecimal.ZERO;
if (servicios != null) {
for (Map<String, Object> s : servicios) {
// Genera los totalizadores (precio unitario, total tirada, etc.) sin guardar
double precioUnit = 0.0;
int cantidad = tirada != null ? tirada : 0;
int index = tiradas.indexOf(tirada);
try {
if (index >= 0 && index < precios.size()) {
precioUnit = precios.get(index);
} else if (!precios.isEmpty()) {
precioUnit = precios.get(0); // fallback al primero
}
// guarda el snapshot completo de precios para auditoría
presupuesto.setPreciosPorTiradaJson(new ObjectMapper().writeValueAsString(precios));
} catch (Exception ignore) {
precioUnit = 0.0;
}
BigDecimal precioTotalTirada = BigDecimal.valueOf(precioUnit)
.multiply(BigDecimal.valueOf(cantidad))
.setScale(2, RoundingMode.HALF_UP);
// servicios_total
BigDecimal serviciosTotal = BigDecimal.ZERO;
if (servicios != null) {
for (Map<String, Object> s : servicios) {
try {
// retractilado o ejemplar-prueba: recalcular precio
if (s.get("id").equals("retractilado")) {
double precio_retractilado = obtenerPrecioRetractilado(cantidad) != null
? Double.parseDouble(obtenerPrecioRetractilado(cantidad))
: 0.0;
s.put("price", precio_retractilado);
}
double unidades = Double.parseDouble(String.valueOf(s.getOrDefault("units", 0)));
double precio = Double.parseDouble(String.valueOf(
s.get("id").equals("marcapaginas")
? (Double.parseDouble(String.valueOf(s.get("price"))) / unidades) // unidad
: s.getOrDefault("price", 0)));
serviciosTotal = serviciosTotal.add(
BigDecimal.valueOf(precio).multiply(BigDecimal.valueOf(unidades)));
} catch (Exception ignore) {
}
}
try {
double unidades = Double.parseDouble(String.valueOf(s.getOrDefault("units", 0)));
double precio = Double.parseDouble(String.valueOf(
s.get("id").equals("marcapaginas")
? (Double.parseDouble(String.valueOf(s.get("price"))) / unidades) // unidad
: s.getOrDefault("price", 0)));
serviciosTotal = serviciosTotal.add(
BigDecimal.valueOf(precio).multiply(BigDecimal.valueOf(unidades)));
presupuesto.setServiciosJson(new ObjectMapper().writeValueAsString(servicios));
} catch (Exception ignore) {
}
}
// base imponible, IVA y total (si tienes IVA configurable, úsalo; si no, 0)
BigDecimal baseImponible = precioTotalTirada.add(serviciosTotal);
BigDecimal ivaTipo = BigDecimal.ZERO;
try {
presupuesto.setServiciosJson(new ObjectMapper().writeValueAsString(servicios));
double iva = 4.0; // 0..100
ivaTipo = BigDecimal.valueOf(iva);
} catch (Exception ignore) {
}
BigDecimal ivaImporte = baseImponible.multiply(ivaTipo).divide(BigDecimal.valueOf(100), 2,
RoundingMode.HALF_UP);
BigDecimal totalConIva = baseImponible.add(ivaImporte);
// precios y totales
if (tirada == (presupuesto.getSelectedTirada() != null ? presupuesto.getSelectedTirada() : 0)) {
presupuesto.setPrecioUnitario(BigDecimal.valueOf(precioUnit).setScale(6, RoundingMode.HALF_UP));
presupuesto.setPrecioTotalTirada(precioTotalTirada);
presupuesto.setServiciosTotal(serviciosTotal);
presupuesto.setBaseImponible(baseImponible);
presupuesto.setIvaTipo(ivaTipo);
presupuesto.setIvaImporte(ivaImporte);
presupuesto.setTotalConIva(totalConIva);
}
Map<String, Object> snap = new HashMap<>();
snap.put("precio_unitario", BigDecimal.valueOf(precioUnit).setScale(6, RoundingMode.HALF_UP));
snap.put("precio_total_tirada", precioTotalTirada);
snap.put("servicios_total", serviciosTotal);
snap.put("base_imponible", baseImponible);
snap.put("iva_tipo", ivaTipo);
snap.put("iva_importe", ivaImporte);
snap.put("total_con_iva", totalConIva);
snap.put("peso", (index >= 0 && index < pesos.size()) ? pesos.get(index) : 0.0);
pricing_snapshot.put(tirada, snap);
}
// base imponible, IVA y total (si tienes IVA configurable, úsalo; si no, 0)
BigDecimal baseImponible = precioTotalTirada.add(serviciosTotal);
BigDecimal ivaTipo = BigDecimal.ZERO;
try {
double iva = 4.0; // 0..100
ivaTipo = BigDecimal.valueOf(iva);
String json = new ObjectMapper()
.writer()
.withDefaultPrettyPrinter() // opcional
.writeValueAsString(pricing_snapshot);
presupuesto.setPricingSnapshotJson(pricing_snapshot.isEmpty() ? null : json);
} catch (Exception ignore) {
}
BigDecimal ivaImporte = baseImponible.multiply(ivaTipo).divide(BigDecimal.valueOf(100), 2,
RoundingMode.HALF_UP);
BigDecimal totalConIva = baseImponible.add(ivaImporte);
// precios y totales
presupuesto.setPrecioUnitario(BigDecimal.valueOf(precioUnit).setScale(6, RoundingMode.HALF_UP));
presupuesto.setPrecioTotalTirada(precioTotalTirada);
presupuesto.setServiciosTotal(serviciosTotal);
presupuesto.setBaseImponible(baseImponible);
presupuesto.setIvaTipo(ivaTipo);
presupuesto.setIvaImporte(ivaImporte);
presupuesto.setTotalConIva(totalConIva);
return presupuesto;
}
@Transactional
public HashMap<String, Object> guardarPresupuesto(Presupuesto presupuesto) {
public HashMap<String, Object> guardarPresupuesto(
Presupuesto presupuesto,
List<Map<String, Object>> serviciosList,
Map<String, Object> datosMaquetacion,
Map<String, Object> datosMarcapaginas,
String mode,
Long cliente_id,
Long id,
HttpServletRequest request,
Locale locale) {
HashMap<String, Object> result = new HashMap<>();
try {
Presupuesto p = presupuestoRepository.saveAndFlush(presupuesto);
presupuesto.setDatosMaquetacionJson(
datosMaquetacion != null ? new ObjectMapper().writeValueAsString(datosMaquetacion) : null);
presupuesto.setDatosMarcapaginasJson(
datosMarcapaginas != null ? new ObjectMapper().writeValueAsString(datosMarcapaginas) : null);
var resumen = this.getTextosResumen(presupuesto, serviciosList, locale);
Object serviciosObj = resumen.get("servicios");
if (serviciosObj instanceof List<?> servicios && !servicios.isEmpty()) {
// serializa a JSON válido
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(servicios);
presupuesto.setServiciosJson(json);
} else {
// decide tu política: null o "[]"
presupuesto.setServiciosJson(null); // o presupuesto.setServiciosJson("[]");
}
if (cliente_id != null && !mode.equals("public")) {
presupuesto.setUser(userRepo.findById(cliente_id).orElse(null));
presupuesto.setOrigen(Presupuesto.Origen.privado);
if (id != null) {
presupuesto.setId(id);
}
}
if (mode.equals("public")) {
presupuesto.setOrigen(Presupuesto.Origen.publico);
String sessionId = request.getSession(true).getId();
String ip = request.getRemoteAddr();
presupuesto = this.getDatosLocalizacion(presupuesto, sessionId, ip);
if (id != null) {
presupuesto.setId(id); // para que actualice, no cree uno nuevo
}
}
presupuesto = this.generateTotalizadores(presupuesto, serviciosList, resumen, locale);
presupuestoRepository.saveAndFlush(presupuesto);
result.put("success", true);
result.put("presupuesto_id", p.getId());
result.put("presupuesto_id", presupuesto.getId());
return result;
} catch (Exception e) {
@ -1007,7 +1129,7 @@ public class PresupuestoService {
if (isUser) {
// Si es usuario, solo puede ver sus propios presupuestos
String username = authentication.getName();
if (!presupuesto.getUser().getUserName().equals(username)) {
if (presupuesto.getUser() == null || !presupuesto.getUser().getUserName().equals(username)) {
return false;
}
}