Files
erp-imprimelibros/src/main/java/com/imprimelibros/erp/presupuesto/service/PresupuestoService.java

1305 lines
60 KiB
Java

package com.imprimelibros.erp.presupuesto.service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
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;
import com.imprimelibros.erp.presupuesto.maquetacion.MaquetacionPrecios;
import com.imprimelibros.erp.presupuesto.maquetacion.MaquetacionPreciosRepository;
import com.imprimelibros.erp.presupuesto.marcapaginas.Marcapaginas;
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.dto.Presupuesto.TipoCubierta;
import com.imprimelibros.erp.presupuesto.maquetacion.MaquetacionMatricesRepository;
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
public class PresupuestoService {
@Autowired
protected VariableService variableService;
@Autowired
protected MessageSource messageSource;
@Autowired
protected MaquetacionPreciosRepository maquetacionPreciosRepository;
@Autowired
protected MaquetacionMatricesRepository maquetacionMatricesRepository;
@Autowired
protected MarcapaginasRepository marcapaginasRepository;
@Autowired
protected PresupuestoRepository presupuestoRepository;
private final PresupuestadorItems presupuestadorItems;
private final PresupuestoFormatter presupuestoFormatter;
private final skApiClient apiClient;
private final GeoIpService geoIpService;
private final UserDao userRepo;
public PresupuestoService(PresupuestadorItems presupuestadorItems, PresupuestoFormatter presupuestoFormatter,
skApiClient apiClient, GeoIpService geoIpService, UserDao userRepo) {
this.presupuestadorItems = presupuestadorItems;
this.presupuestoFormatter = presupuestoFormatter;
this.apiClient = apiClient;
this.geoIpService = geoIpService;
this.userRepo = userRepo;
}
public boolean validateDatosGenerales(int[] tiradas) {
for (int tirada : tiradas) {
if (tirada <= 0) {
return false; // Invalid tirada found
}
}
return true;
}
public Boolean isPOD(Presupuesto presupuesto) {
int pod_value = variableService.getValorEntero("POD");
return (presupuesto.getTirada1() != null && presupuesto.getTirada1() <= pod_value) ||
(presupuesto.getTirada2() != null && presupuesto.getTirada2() <= pod_value) ||
(presupuesto.getTirada3() != null && presupuesto.getTirada3() <= pod_value) ||
(presupuesto.getTirada4() != null && presupuesto.getTirada4() <= pod_value);
}
public Map<String, Object> obtenerOpcionesColor(Presupuesto presupuesto, Locale locale) {
List<ImagenPresupuesto> opciones = new ArrayList<>();
if (presupuesto.getPaginasColor() > 0) {
if (!this.isPOD(presupuesto)) {
// POD solo color foto
ImagenPresupuesto opcionColor = this.presupuestadorItems.getImpresionColor(locale);
opcionColor.setSelected(Presupuesto.TipoImpresion.color.equals(presupuesto.getTipoImpresion()));
opciones.add(opcionColor);
}
ImagenPresupuesto opcionColorHq = this.presupuestadorItems.getImpresionColorPremium(locale);
if (Presupuesto.TipoImpresion.colorhq.equals(presupuesto.getTipoImpresion()))
opcionColorHq.setSelected(true);
opciones.add(opcionColorHq);
} else {
ImagenPresupuesto opcionNegro = this.presupuestadorItems.getImpresionNegro(locale);
if (Presupuesto.TipoImpresion.negro.equals(presupuesto.getTipoImpresion()))
opcionNegro.setSelected(true);
opciones.add(opcionNegro);
ImagenPresupuesto opcionNegroHq = this.presupuestadorItems.getImpresionNegroPremium(locale);
if (Presupuesto.TipoImpresion.negrohq.equals(presupuesto.getTipoImpresion()))
opcionNegroHq.setSelected(true);
opciones.add(opcionNegroHq);
}
boolean opcionSeleccionada = opciones.stream().anyMatch(ImagenPresupuesto::isSelected);
if (!opcionSeleccionada) {
opciones.get(0).setSelected(true);
presupuesto.setTipoImpresion(Presupuesto.TipoImpresion.valueOf(opciones.get(0).getId()));
}
Map<String, Object> response = new HashMap<>();
response.put("opciones_color", opciones);
return response;
}
public Map<String, Object> obtenerOpcionesPapelInterior(Presupuesto presupuesto, Locale locale) {
List<ImagenPresupuesto> opciones = new ArrayList<>();
opciones.add(this.presupuestadorItems.getPapelOffsetBlanco(locale));
if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negro ||
presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.color) {
opciones.add(this.presupuestadorItems.getPapelOffsetBlancoVolumen(locale));
}
opciones.add(this.presupuestadorItems.getPapelOffsetAhuesado(locale));
if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negro ||
presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.color) {
opciones.add(this.presupuestadorItems.getPapelOffsetAhuesadoVolumen(locale));
}
opciones.add(this.presupuestadorItems.getPapelEstucadoMate(locale));
for (ImagenPresupuesto imagenPresupuesto : opciones) {
imagenPresupuesto.setSelected(
presupuesto.getPapelInteriorId() != null
&& imagenPresupuesto.getExtra_data().get("sk-id").equals(
String.valueOf(presupuesto.getPapelInteriorId())));
}
boolean yaSeleccionado = opciones.stream().anyMatch(ImagenPresupuesto::isSelected);
if (!yaSeleccionado && !opciones.isEmpty()) {
ImagenPresupuesto primeraOpcion = opciones.get(0);
primeraOpcion.setSelected(true);
presupuesto.setPapelInteriorId(Integer.parseInt(primeraOpcion.getExtra_data().get("sk-id")));
}
Map<String, Object> response = new HashMap<>();
response.put("opciones_papel_interior", opciones);
return response;
}
public Map<String, Object> obtenerOpcionesGramajeInterior(Presupuesto presupuesto) {
List<String> gramajes = new ArrayList<>();
final int BLANCO_OFFSET_ID = 3;
final int BLANCO_OFFSET_VOLUMEN_ID = 7;
final int AHUESADO_OFFSET_ID = 4;
final int AHUESADO_OFFSET_VOLUMEN_ID = 6;
final int ESTUCADO_MATE_ID = 2;
if (presupuesto.getPapelInteriorId() != null && presupuesto.getPapelInteriorId() == BLANCO_OFFSET_ID) {
gramajes.add("80");
gramajes.add("90");
if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negrohq ||
presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.colorhq) {
gramajes.add("100");
gramajes.add("120");
gramajes.add("150");
gramajes.add("170");
}
} else if (presupuesto.getPapelInteriorId() != null
&& presupuesto.getPapelInteriorId() == BLANCO_OFFSET_VOLUMEN_ID) {
if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negro ||
presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.color) {
gramajes.add("80");
}
} else if (presupuesto.getPapelInteriorId() != null && presupuesto.getPapelInteriorId() == AHUESADO_OFFSET_ID) {
gramajes.add("80");
gramajes.add("90");
if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negrohq ||
presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.colorhq) {
gramajes.add("100");
}
} else if (presupuesto.getPapelInteriorId() != null
&& presupuesto.getPapelInteriorId() == AHUESADO_OFFSET_VOLUMEN_ID) {
if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negro ||
presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.color) {
gramajes.add("70");
gramajes.add("80");
}
} else if (presupuesto.getPapelInteriorId() != null && presupuesto.getPapelInteriorId() == ESTUCADO_MATE_ID) {
if (presupuesto.getTipoImpresion() != Presupuesto.TipoImpresion.color) {
gramajes.add("90");
}
if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negrohq ||
presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.colorhq) {
gramajes.add("100");
gramajes.add("115");
}
if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negro ||
presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.color) {
gramajes.add("120");
}
if (presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.negrohq ||
presupuesto.getTipoImpresion() == Presupuesto.TipoImpresion.colorhq) {
gramajes.add("125");
gramajes.add("135");
gramajes.add("150");
gramajes.add("170");
gramajes.add("200");
}
}
Map<String, Object> response = new HashMap<>();
response.put("opciones_gramaje_interior", gramajes);
return response;
}
public Map<String, Object> obtenerOpcionesPapelCubierta(Presupuesto presupuesto, Locale locale) {
List<ImagenPresupuesto> opciones = new ArrayList<>();
if (presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaBlanda) {
opciones.add(this.presupuestadorItems.getCartulinaGraficaCubierta(locale));
}
opciones.add(this.presupuestadorItems.getEstucadoMateCubierta(locale));
for (ImagenPresupuesto imagenPresupuesto : opciones) {
imagenPresupuesto.setSelected(
presupuesto.getPapelCubiertaId() != null
&& imagenPresupuesto.getExtra_data().get("sk-id").equals(
String.valueOf(presupuesto.getPapelCubiertaId())));
}
Map<String, Object> response = new HashMap<>();
response.put("opciones_papel_cubierta", opciones);
return response;
}
public Map<String, Object> obtenerOpcionesGramajeCubierta(Presupuesto presupuesto) {
List<String> gramajes = new ArrayList<>();
final int CARTULINA_GRAFICA_ID = 5;
final int ESTUCADO_MATE_ID = 2;
if (presupuesto.getPapelCubiertaId() != null && presupuesto.getPapelCubiertaId() == CARTULINA_GRAFICA_ID) {
gramajes.add("240");
gramajes.add("270");
gramajes.add("300");
gramajes.add("350");
} else if (presupuesto.getPapelCubiertaId() != null && presupuesto.getPapelCubiertaId() == ESTUCADO_MATE_ID) {
if (presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaBlanda) {
gramajes.add("250");
gramajes.add("300");
gramajes.add("350");
} else {
gramajes.add("170");
}
}
Map<String, Object> response = new HashMap<>();
response.put("opciones_gramaje_cubierta", gramajes);
return response;
}
public Map<String, Object> toSkApiRequest(Presupuesto presupuesto) {
final int SK_CLIENTE_ID = 1284;
final int SK_PAGINAS_CUADERNILLO = 32;
Map<String, Object> tamanio = Map.of(
"ancho", presupuesto.getAncho(),
"alto", presupuesto.getAlto());
Map<String, Object> interior = Map.of(
"papelInterior", presupuesto.getPapelInteriorId(),
"gramajeInterior", presupuesto.getGramajeInterior());
Map<String, Object> cubierta = Map.of(
"tipoCubierta", presupuesto.getTipoCubierta().name(),
"papelCubierta", presupuesto.getPapelCubiertaId(),
"gramajeCubierta", presupuesto.getGramajeCubierta(),
"carasImpresion", presupuesto.getCubiertaCaras(),
"solapas", presupuesto.getSolapasCubierta() ? presupuesto.getTamanioSolapasCubierta() : 0,
"acabado", presupuesto.getAcabado(),
"cabezada", presupuesto.getCabezada(),
"lomoRedondo", presupuesto.getTipoCubierta() == TipoCubierta.tapaDuraLomoRedondo ? 1 : 0);
Map<String, Object> body = new HashMap<>();
body.put("tipo_impresion_id", this.getTipoImpresionId(presupuesto));
body.put("tirada", Arrays.stream(presupuesto.getTiradas())
.filter(Objects::nonNull)
.collect(Collectors.toList()));
body.put("tamanio", tamanio);
body.put("tipo", presupuesto.getTipoEncuadernacion());
body.put("clienteId", SK_CLIENTE_ID);
body.put("isColor", presupuesto.getTipoImpresion().name().contains("color") ? 1 : 0);
body.put("isHq", presupuesto.getTipoImpresion().name().contains("hq") ? 1 : 0);
body.put("paginas", presupuesto.getPaginasNegro() + presupuesto.getPaginasColor());
body.put("paginasColor", presupuesto.getPaginasColor());
body.put("paginasCuadernillo", SK_PAGINAS_CUADERNILLO);
body.put("interior", interior);
body.put("cubierta", cubierta);
body.put("guardas", null);
if (presupuesto.getSobrecubierta()) {
Map<String, Object> sobrecubierta = new HashMap<>();
sobrecubierta.put("papel", presupuesto.getPapelSobrecubiertaId());
sobrecubierta.put("gramaje", presupuesto.getGramajeSobrecubierta());
sobrecubierta.put("solapas", presupuesto.getTamanioSolapasSobrecubierta());
sobrecubierta.put("acabado", presupuesto.getAcabadoSobrecubierta());
body.put("sobrecubierta", sobrecubierta);
}
if (presupuesto.getFaja()) {
Map<String, Object> faja = new HashMap<>();
faja.put("papel", presupuesto.getPapelFajaId());
faja.put("gramaje", presupuesto.getGramajeFaja());
faja.put("solapas", presupuesto.getTamanioSolapasFaja());
faja.put("acabado", presupuesto.getAcabadoFaja());
faja.put("alto", presupuesto.getAltoFaja());
body.put("faja", faja);
}
// body.put("servicios", servicios);
return body;
}
public Integer getTipoImpresionId(Presupuesto presupuesto) {
if (presupuesto.getTipoEncuadernacion() == Presupuesto.TipoEncuadernacion.fresado) {
if (presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDura ||
presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDuraLomoRedondo) {
return 1; // Fresado tapa dura
} else {
return 2; // Fresado tapa blanda
}
} else if (presupuesto.getTipoEncuadernacion() == Presupuesto.TipoEncuadernacion.cosido) {
if (presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDura ||
presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDuraLomoRedondo) {
return 3; // Cosido tapa dura
} else {
return 4; // Cosido tapa blanda
}
} else if (presupuesto.getTipoEncuadernacion() == Presupuesto.TipoEncuadernacion.espiral) {
if (presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDura ||
presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDuraLomoRedondo) {
return 5; // Espiral tapa dura
} else {
return 6; // Espiral tapa blanda
}
} else if (presupuesto.getTipoEncuadernacion() == Presupuesto.TipoEncuadernacion.wireo) {
if (presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDura ||
presupuesto.getTipoCubierta() == Presupuesto.TipoCubierta.tapaDuraLomoRedondo) {
return 7; // Wireo tapa dura
} else {
return 8; // Wireo tapa blanda
}
} else if (presupuesto.getTipoEncuadernacion() == Presupuesto.TipoEncuadernacion.grapado) {
return 21; // Grapado
} else {
return 0; // Default case, no valid type
}
}
public Map<String, Object> obtenerOpcionesAcabadosCubierta(Presupuesto presupuesto, Locale locale) {
Map<String, Object> resultado = new HashMap<>();
List<Object> opciones = new ArrayList<>();
opciones.add(new HashMap<>() {
{
put("name", messageSource.getMessage("presupuesto.acabado-ninguno", null, locale));
put("sk-id", 0);
}
});
opciones.add(new HashMap<>() {
{
put("name", messageSource.getMessage("presupuesto.acabado-plastificado-brillo-1c", null, locale));
put("sk-id", 1);
}
});
opciones.add(new HashMap<>() {
{
put("name", messageSource.getMessage("presupuesto.acabado-plastificado-mate-1c", null, locale));
put("sk-id", 5);
}
});
opciones.add(new HashMap<>() {
{
put("name",
messageSource.getMessage("presupuesto.acabado-plastificado-mate-1c-antirrayado", null, locale));
put("sk-id", 8);
}
});
opciones.add(new HashMap<>() {
{
put("name", messageSource.getMessage("presupuesto.acabado-plastificado-mate-uvi", null, locale));
put("sk-id", 2);
}
});
opciones.add(new HashMap<>() {
{
put("name", messageSource.getMessage("presupuesto.acabado-plastificado-mate-uvi3d", null, locale));
put("sk-id", 3);
}
});
opciones.add(new HashMap<>() {
{
put("name", messageSource.getMessage("presupuesto.acabado-plastificado-mate-uvi-braile", null, locale));
put("sk-id", 4);
}
});
opciones.add(new HashMap<>() {
{
put("name", messageSource.getMessage("presupuesto.acabado-plastificado-sandy-1c", null, locale));
put("sk-id", 9);
}
});
resultado.put("opciones_acabados_cubierta", opciones);
return resultado;
}
public String obtenerPrecioRetractilado(Presupuesto presupuesto, Locale locale) {
Integer[] tiradas = presupuesto.getTiradas();
Integer tirada_min = Arrays.stream(tiradas)
.filter(Objects::nonNull)
.min(Integer::compareTo)
.orElse(0);
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("tirada",
presupuesto.getSelectedTirada() != null ? presupuesto.getSelectedTirada() : tirada_min);
Double precio_retractilado = apiClient.getRetractilado(requestBody);
return precio_retractilado != null
? String.valueOf(Math.round(precio_retractilado * 100.0) / 100.0)
: "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<>();
Double price_prototipo = this.obtenerPrototipo(presupuesto);
opciones.add(new HashMap<String, String>() {
{
put("id", "retractilado");
put("title", messageSource.getMessage("presupuesto.extras-retractilado", null, locale));
put("description", "");
put("price", obtenerPrecioRetractilado(presupuesto, locale));
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
}
});
opciones.add(new HashMap<String, String>() {
{
put("id", "service-isbn");
put("title", messageSource.getMessage("presupuesto.extras-isbn", null, locale));
put("description", "");
put("price", "30");
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
}
});
opciones.add(new HashMap<String, String>() {
{
put("id", "deposito-legal");
put("title", messageSource.getMessage("presupuesto.extras-deposito-legal", null, locale));
put("description",
messageSource.getMessage("presupuesto.extras-deposito-legal-descripcion", null, locale));
put("price", "30");
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
}
});
opciones.add(new HashMap<String, String>() {
{
put("id", "revision-archivos");
put("title", messageSource.getMessage("presupuesto.extras-revision-archivos", null, locale));
put("description", "");
put("price", "50");
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
}
});
opciones.add(new HashMap<String, String>() {
{
put("id", "maquetacion-cubierta");
put("title", messageSource.getMessage("presupuesto.extras-maquetacion-cubierta", null, locale));
put("description", "");
put("price", "50");
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
}
});
opciones.add(new HashMap<String, String>() {
{
put("id", "ferro-digital");
put("title", messageSource.getMessage("presupuesto.extras-ferro-digital", null, locale));
put("description", "");
put("price", "0");
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
put("checked", "true");
put("allowChange", "false");
put("ribbonText", messageSource.getMessage("presupuesto.extras-ferro-digital-ribbon", null, locale));
}
});
opciones.add(new HashMap<String, String>() {
{
put("id", "ejemplar-prueba");
put("title", messageSource.getMessage("presupuesto.extras-ejemplar-prueba", null, locale));
put("description", "");
if (price_prototipo == 0.0) {
put("price", messageSource.getMessage("presupuesto.consultar-soporte", null, locale));
put("priceUnit", "");
} else {
put("price",
String.valueOf(Math.round(price_prototipo * 100.0) / 100.0));
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
}
}
});
opciones.add(new HashMap<String, String>() {
{
put("id", "marcapaginas");
put("title", messageSource.getMessage("presupuesto.extras-marcapaginas", null, locale));
put("description", "");
put("price", messageSource.getMessage("presupuesto.extras-calcular", null, locale));
}
});
opciones.add(new HashMap<String, String>() {
{
put("id", "maquetacion");
put("title", messageSource.getMessage("presupuesto.extras-maquetacion", null, locale));
put("description", "");
put("price", messageSource.getMessage("presupuesto.extras-calcular", null, locale));
}
});
Map<String, Object> response = new HashMap<>();
response.put("servicios_extra", opciones);
return response;
}
public HashMap<String, Object> getPrecioMaquetacion(PresupuestoMaquetacion presupuestoMaquetacion, Locale locale) {
try {
List<MaquetacionPrecios> lista = maquetacionPreciosRepository.findAll();
java.util.function.Function<String, Double> price = key -> lista.stream()
.filter(p -> key.equals(p.getKey()))
.map(MaquetacionPrecios::getValue)
.findFirst()
.orElse(0.0);
BigDecimal precio = BigDecimal.ZERO;
BigDecimal millares = BigDecimal.valueOf(presupuestoMaquetacion.getNumCaracteres()).divide(
BigDecimal.valueOf(1000), 6, RoundingMode.HALF_UP);
precio = precio.add(millares.multiply(BigDecimal.valueOf(price.apply("millar_maquetacion"))));
int numPaginas = 0;
Integer matricesPorPagina = maquetacionMatricesRepository.findMatrices(
presupuestoMaquetacion.getFormato(),
presupuestoMaquetacion.getCuerpoTexto());
if (matricesPorPagina != null && matricesPorPagina > 0) {
numPaginas = presupuestoMaquetacion.getNumCaracteres() / matricesPorPagina;
}
BigDecimal precioRedondeado = precio.setScale(2, RoundingMode.HALF_UP);
double precioPaginaEstimado = 0.0;
if (numPaginas > 0) {
precioPaginaEstimado = precioRedondeado
.divide(BigDecimal.valueOf(numPaginas), 2, RoundingMode.HALF_UP)
.doubleValue();
}
precio = precio
.add(BigDecimal.valueOf(presupuestoMaquetacion.getNumTablas())
.multiply(BigDecimal.valueOf(price.apply("tabla"))));
precio = precio.add(
BigDecimal.valueOf(presupuestoMaquetacion.getNumColumnas())
.multiply(BigDecimal.valueOf(price.apply("columnas"))));
precio = precio
.add(BigDecimal.valueOf(presupuestoMaquetacion.getNumFotos())
.multiply(BigDecimal.valueOf(price.apply("foto"))));
if (presupuestoMaquetacion.isCorreccionOrtotipografica()) {
precio = precio
.add(millares.multiply(BigDecimal.valueOf(price.apply("correccion_ortotipografica"))));
}
if (presupuestoMaquetacion.isTextoMecanografiado()) {
precio = precio.add(millares.multiply(BigDecimal.valueOf(price.apply("mecanoescritura_por_millar"))));
}
if (presupuestoMaquetacion.isDisenioPortada()) {
precio = precio.add(BigDecimal.valueOf(price.apply("disenio_portada")));
}
if (presupuestoMaquetacion.isEpub()) {
precio = precio.add(BigDecimal.valueOf(price.apply("epub")));
}
precioRedondeado = precio.setScale(2, RoundingMode.HALF_UP);
HashMap<String, Object> out = new HashMap<>();
out.put("precio", precioRedondeado.doubleValue());
out.put("numPaginasEstimadas", numPaginas);
out.put("precioPaginaEstimado", precioPaginaEstimado);
HashMap<String, String> language = new HashMap<>();
language.put("num_paginas_estimadas",
messageSource.getMessage("presupuesto.maquetacion.num-paginas-estimadas", null, locale));
language.put("precio_por_pagina_estimado",
messageSource.getMessage("presupuesto.maquetacion.precio-por-pagina-estimado", null, locale));
language.put("add_to_presupuesto",
messageSource.getMessage("presupuesto.add-to-presupuesto", null, locale));
language.put("cancel", messageSource.getMessage("app.cancelar", null, locale));
language.put("presupuesto_maquetacion", messageSource.getMessage("presupuesto.maquetacion", null, locale));
out.put("language", language);
return out;
} catch (Exception e) {
System.out.println("Error procesando presupuesto maquetacion: " + e.getMessage());
}
HashMap<String, Object> out = new HashMap<>();
out.put("precio", 0.0);
out.put("numPaginasEstimadas", 0);
out.put("precioPaginaEstimado", 0.0);
return out;
}
public HashMap<String, Object> getPrecioMarcapaginas(PresupuestoMarcapaginas presupuestoMarcapaginas,
Locale locale) {
try {
List<Marcapaginas> m = marcapaginasRepository.findPrecios(presupuestoMarcapaginas);
if (m.isEmpty() || m.get(0) == null) {
HashMap<String, Object> out = new HashMap<>();
out.put("precio_unidad", 0.0);
out.put("precio_total", 0.0);
return out;
}
Marcapaginas marcapaginas = m.get(0);
Double precio = 0.0;
Double margen = 0.0;
Double pvp = 0.0;
BigDecimal data = BigDecimal.ZERO;
if (marcapaginas.getUnidades_max() >= presupuestoMarcapaginas.getUnidades()) {
precio = marcapaginas.getPrecio_unidades_min() +
(presupuestoMarcapaginas.getUnidades() - marcapaginas.getUnidades_min())
* (marcapaginas.getPrecio_unidades_max() - marcapaginas.getPrecio_unidades_min())
/ (marcapaginas.getUnidades_max() - marcapaginas.getUnidades_min());
data = new BigDecimal(precio);
precio = data.setScale(2, RoundingMode.HALF_UP).doubleValue();
margen = 1.0 * marcapaginas.getMargen_unidades_min() +
(1.0 * presupuestoMarcapaginas.getUnidades() - 1.0 * marcapaginas.getUnidades_min())
* (1.0 * marcapaginas.getMargen_unidades_max()
- 1.0 * marcapaginas.getMargen_unidades_min())
/ (1.0 * marcapaginas.getUnidades_max() - 1.0 * marcapaginas.getUnidades_min());
data = new BigDecimal(margen);
margen = data.setScale(2, RoundingMode.HALF_UP).doubleValue();
pvp = precio + (precio * margen / 100);
data = new BigDecimal(pvp);
pvp = data.setScale(2, RoundingMode.HALF_UP).doubleValue();
} else {
// precio unidad para el máximo de unidades
precio = marcapaginas.getPrecio_unidades_max() / marcapaginas.getUnidades_max();
precio = precio * presupuestoMarcapaginas.getUnidades();
data = new BigDecimal(precio);
precio = data.setScale(2, RoundingMode.HALF_UP).doubleValue();
margen = 1.0 * marcapaginas.getMargen_unidades_max();
data = new BigDecimal(margen);
margen = data.setScale(2, RoundingMode.HALF_UP).doubleValue();
pvp = precio + (precio * margen / 100);
data = new BigDecimal(pvp);
pvp = data.setScale(2, RoundingMode.HALF_UP).doubleValue();
}
Double precio_unidad = pvp / presupuestoMarcapaginas.getUnidades();
data = new BigDecimal(precio_unidad);
precio_unidad = data.setScale(6, RoundingMode.HALF_UP).doubleValue();
HashMap<String, Object> resultado;
resultado = new HashMap<>();
resultado.put("precio_unitario", precio_unidad);
resultado.put("precio_total", pvp);
HashMap<String, String> language = new HashMap<>();
language.put("precio_unidad",
messageSource.getMessage("presupuesto.marcapaginas.precio-unidad", null, locale));
language.put("precio_total",
messageSource.getMessage("presupuesto.marcapaginas.precio-total", null, locale));
language.put("add_to_presupuesto",
messageSource.getMessage("presupuesto.add-to-presupuesto", null, locale));
language.put("cancel", messageSource.getMessage("app.cancelar", null, locale));
language.put("presupuesto_marcapaginas",
messageSource.getMessage("presupuesto.marcapaginas", null, locale));
resultado.put("language", language);
return resultado;
} catch (Exception e) {
System.out.println("Error procesando presupuesto marcapaginas: " + e.getMessage());
}
HashMap<String, Object> out = new HashMap<>();
out.put("precio_unidad", 0.0);
out.put("precio_total", 0.0);
return out;
}
/**
* Calcula el resumen (SIN persistir cambios de estado).
* Mantiene firma para no romper llamadas existentes.
*/
public Map<String, Object> getTextosResumen(Presupuesto presupuesto, List<Map<String, Object>> servicios,
Locale locale) {
Map<String, Object> resumen = new HashMap<>();
resumen.put("titulo", presupuesto.getTitulo());
Presupuesto pressupuestoTemp = presupuesto.clone();
resumen.put("imagen",
"/assets/images/imprimelibros/presupuestador/" + presupuesto.getTipoEncuadernacion() + ".png");
resumen.put("imagen_alt",
messageSource.getMessage("presupuesto." + presupuesto.getTipoEncuadernacion(), null, locale));
boolean hayDepositoLegal = servicios != null && servicios.stream()
.map(m -> java.util.Objects.toString(m.get("id"), ""))
.map(String::trim)
.anyMatch("deposito-legal"::equals);
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;
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() != null ? presupuesto.getSelectedTirada() : 0);
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++;
}
List<Map<String, Object>> serviciosExtras = new ArrayList<>();
if (servicios != null) {
for (Map<String, Object> servicio : servicios) {
HashMap<String, Object> servicioData = new HashMap<>();
servicioData.put("id", servicio.get("id"));
servicioData.put("descripcion", servicio.get("label"));
servicioData.put("precio", servicio.get("id").equals("marcapaginas")
? Double.parseDouble(servicio.get("price").toString())
/ Double.parseDouble(servicio.get("units").toString())
: servicio.get("price"));
servicioData.put("unidades", servicio.get("units"));
serviciosExtras.add(servicioData);
}
}
resumen.put("servicios", serviciosExtras);
return resumen;
}
/**
* PÚBLICO: calcula el resumen y GUARDA el presupuesto completo como BORRADOR.
* Se invoca al entrar en la pestaña "Resumen" del presupuestador público.
*/
// PresupuestoService.java
public Map<String, Object> getResumen(
Presupuesto presupuesto,
List<Map<String, Object>> servicios,
Boolean save,
String mode,
Locale locale,
String sessionId,
String ip) {
// 1) Calcula el resumen (como ya haces)
Map<String, Object> resumen = getTextosResumen(presupuesto, servicios, locale);
if (resumen.containsKey("error"))
return resumen;
presupuesto = generateTotalizadores(presupuesto, servicios, resumen, locale);
// 3) Enriquecer el Presupuesto a persistir
presupuesto.setEstado(Presupuesto.Estado.borrador);
if (mode.equals("public")) {
presupuesto = getDatosLocalizacion(presupuesto, sessionId, ip);
} else
presupuesto.setOrigen(Presupuesto.Origen.privado);
// 4) UPSERT: si viene id -> actualiza; si no, reusa el último borrador de la
// sesión
Presupuesto entidad;
if (presupuesto.getId() != null) {
entidad = presupuestoRepository.findById(presupuesto.getId()).orElse(presupuesto);
} else {
entidad = presupuestoRepository
.findTopBySessionIdAndEstadoOrderByCreatedAtDesc(sessionId, Presupuesto.Estado.borrador)
.orElse(presupuesto);
// Si se reutiliza un borrador existente, copia el ID a nuestro objeto para
// hacer merge
presupuesto.setId(entidad.getId());
}
// 5) Guardar/actualizar
entidad = mergePresupuesto(entidad, presupuesto);
if (save != null && save) {
// Si NO es para guardar (solo calcular resumen), devolver sin persistir
presupuestoRepository.saveAndFlush(presupuesto);
}
// Opcional: devolver el id guardado al frontend para que lo envíe en llamadas
// siguientes
resumen.put("presupuesto_id", entidad.getId());
resumen.put("precio_unitario", presupuesto.getPrecioUnitario());
resumen.put("precio_total_tirada", presupuesto.getPrecioTotalTirada());
resumen.put("servicios_total", presupuesto.getServiciosTotal());
resumen.put("base_imponible", presupuesto.getBaseImponible());
resumen.put("iva_importe_4", presupuesto.getIvaImporte4());
resumen.put("iva_importe_21", presupuesto.getIvaImporte21());
resumen.put("total_con_iva", presupuesto.getTotalConIva());
return resumen;
}
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) {
}
return presupuesto;
}
public Presupuesto generateTotalizadores(
Presupuesto presupuesto,
List<Map<String, Object>> servicios,
Map<String, Object> resumen,
Locale locale) {
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());
boolean hayDepositoLegal = servicios != null && servicios.stream()
.map(m -> java.util.Objects.toString(m.get("id"), ""))
.map(String::trim)
.anyMatch("deposito-legal"::equals);
if (precios.isEmpty()) {
var preciosCalc = this.calcularPresupuesto(presupuesto, locale);
precios = (List<Double>) ((Map<String, Object>) preciosCalc.get("data")).getOrDefault("precios", List.of());
}
// iterate getTiradas with a foreach with not null
for (Integer tirada : presupuesto.getTiradas()) {
if (tirada == null) {
continue;
}
// 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);
if( hayDepositoLegal ){
precioTotalTirada = precioTotalTirada.add(BigDecimal.valueOf(precioUnit).multiply(BigDecimal.valueOf(4))).setScale(6, RoundingMode.HALF_UP);
}
// servicios_total
BigDecimal serviciosIva4 = BigDecimal.ZERO;
BigDecimal serviciosTotal = BigDecimal.ZERO;
if (servicios != null) {
for (Map<String, Object> s : servicios) {
try {
// retractilado: 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);
}
// si tiene protitipo, guardamos el valor para el IVA al 4%
else if (s.get("id").equals("ejemplar-prueba")) {
serviciosIva4 = BigDecimal.valueOf(
s.get("price") != null ? Double.parseDouble(String.valueOf(s.get("price"))) : 0.0);
} else if (s.get("id").equals("marcapaginas")) {
PresupuestoMarcapaginas pm = presupuesto.getDatosMarcapaginasJson() != null
? new ObjectMapper().readValue(presupuesto.getDatosMarcapaginasJson(),
PresupuestoMarcapaginas.class)
: null;
Map<String, Object> precio_marcapaginas = this.getPrecioMarcapaginas(pm, locale);
s.put("price", precio_marcapaginas.getOrDefault("precio_total", 0.0));
} else if (s.get("id").equals("maquetacion")) {
PresupuestoMaquetacion pm = presupuesto.getDatosMaquetacionJson() != null
? new ObjectMapper().readValue(presupuesto.getDatosMaquetacionJson(),
PresupuestoMaquetacion.class)
: null;
Map<String, Object> precio_maquetacion = this.getPrecioMaquetacion(pm, locale);
s.put("price", precio_maquetacion.getOrDefault("precio", 0.0));
}
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 {
presupuesto.setServiciosJson(new ObjectMapper().writeValueAsString(servicios));
} catch (Exception ignore) {
}
}
BigDecimal baseImponible = precioTotalTirada;
BigDecimal ivaImporte4 = BigDecimal.ZERO;
BigDecimal ivaImporte21 = BigDecimal.ZERO;
// Si la entrega es en peninsula, se mira el valor del iva
// Canarias y paises UE no llevan IVA
if (presupuesto.getEntregaTipo() == Presupuesto.Entrega.peninsula){
// Si el iva es reducido, el precio de la tirada y el del prototipo llevan IVA
// 4%
if (presupuesto.getIvaReducido()) {
ivaImporte4 = baseImponible.add(serviciosIva4).multiply(BigDecimal.valueOf(4)).divide(
BigDecimal.valueOf(100), 2,
RoundingMode.HALF_UP);
ivaImporte21 = serviciosTotal.subtract(serviciosIva4).multiply(BigDecimal.valueOf(21)).divide(
BigDecimal.valueOf(100), 2,
RoundingMode.HALF_UP);
} else {
ivaImporte21 = baseImponible.add(serviciosTotal).multiply(BigDecimal.valueOf(21)).divide(
BigDecimal.valueOf(100), 2,
RoundingMode.HALF_UP);
}
}
baseImponible = baseImponible.add(serviciosTotal);
BigDecimal totalConIva = baseImponible.add(ivaImporte21).add(ivaImporte4);
// 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.setIvaImporte4(ivaImporte4);
presupuesto.setIvaImporte21(ivaImporte21);
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_importe_4", ivaImporte4);
snap.put("iva_importe_21", ivaImporte21);
snap.put("total_con_iva", totalConIva);
snap.put("peso", (index >= 0 && index < pesos.size()) ? pesos.get(index) : 0.0);
pricing_snapshot.put(tirada, snap);
}
try {
String json = new ObjectMapper()
.writer()
.withDefaultPrettyPrinter() // opcional
.writeValueAsString(pricing_snapshot);
presupuesto.setPricingSnapshotJson(pricing_snapshot.isEmpty() ? null : json);
} catch (Exception ignore) {
}
return presupuesto;
}
@Transactional
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.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", presupuesto.getId());
return result;
} catch (Exception e) {
System.out.println("Error guardando presupuesto: " + e.getMessage());
result.put("success", false);
return result;
}
}
/**
* PRIVADO (futuro botón "Guardar"): persiste el presupuesto como borrador.
*/
public HashMap<String, Object> calcularPresupuesto(Presupuesto presupuesto, Locale locale) {
HashMap<String, Object> price = new HashMap<>();
String priceStr = apiClient.getPrice(this.toSkApiRequest(presupuesto), presupuesto.getTipoEncuadernacion(),
presupuesto.getTipoCubierta());
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));
}
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() == null || !presupuesto.getUser().getUserName().equals(username)) {
return false;
}
}
return true;
}
// =======================================================================
// Métodos privados
// =======================================================================
/**
* Copia de campos "actualizables" para no machacar otros (created_at, etc.)
*/
private Presupuesto mergePresupuesto(Presupuesto target, Presupuesto src) {
// Campos funcionales
target.setTitulo(src.getTitulo());
target.setTipoEncuadernacion(src.getTipoEncuadernacion());
target.setTipoCubierta(src.getTipoCubierta());
target.setTipoImpresion(src.getTipoImpresion());
target.setPaginasNegro(src.getPaginasNegro());
target.setPaginasColor(src.getPaginasColor());
target.setPaginasColorTotal(src.getPaginasColorTotal());
target.setPosicionPaginasColor(src.getPosicionPaginasColor());
target.setAncho(src.getAncho());
target.setAlto(src.getAlto());
target.setPapelInteriorId(src.getPapelInteriorId());
target.setGramajeInterior(src.getGramajeInterior());
target.setPapelCubiertaId(src.getPapelCubiertaId());
target.setGramajeCubierta(src.getGramajeCubierta());
target.setCubiertaCaras(src.getCubiertaCaras());
target.setSolapasCubierta(src.getSolapasCubierta());
target.setTamanioSolapasCubierta(src.getTamanioSolapasCubierta());
target.setSobrecubierta(src.getSobrecubierta());
target.setPapelSobrecubiertaId(src.getPapelSobrecubiertaId());
target.setGramajeSobrecubierta(src.getGramajeSobrecubierta());
target.setTamanioSolapasSobrecubierta(src.getTamanioSolapasSobrecubierta());
target.setAcabado(src.getAcabado());
target.setCabezada(src.getCabezada());
target.setTipoCubierta(src.getTipoCubierta());
target.setSelectedTirada(src.getSelectedTirada());
target.setTirada1(src.getTirada1());
target.setTirada2(src.getTirada2());
target.setTirada3(src.getTirada3());
target.setTirada4(src.getTirada4());
// Metadatos y totales
target.setEstado(Presupuesto.Estado.borrador);
target.setOrigen(src.getOrigen());
target.setSessionId(src.getSessionId());
target.setIpHash(src.getIpHash());
target.setIpTrunc(src.getIpTrunc());
target.setPais(src.getPais());
target.setRegion(src.getRegion());
target.setCiudad(src.getCiudad());
target.setServiciosJson(src.getServiciosJson());
target.setPreciosPorTiradaJson(src.getPreciosPorTiradaJson());
target.setPrecioUnitario(src.getPrecioUnitario());
target.setPrecioTotalTirada(src.getPrecioTotalTirada());
target.setServiciosTotal(src.getServiciosTotal());
target.setBaseImponible(src.getBaseImponible());
target.setIvaReducido(src.getIvaReducido());
target.setEntregaTipo(src.getEntregaTipo());
target.setIvaImporte4(src.getIvaImporte4());
target.setIvaImporte21(src.getIvaImporte21());
target.setTotalConIva(src.getTotalConIva());
target.setCreatedBy(target.getCreatedBy() == null ? src.getCreatedBy() : target.getCreatedBy()); // no pisar si
// ya existe
return target;
}
private Double obtenerPrototipo(Presupuesto presupuesto) {
// Obtenemos el precio de 1 unidad para el ejemplar de prueba
HashMap<String, Object> price = new HashMap<>();
Presupuesto presupuestoTemp = presupuesto.clone();
presupuestoTemp.setTirada1(1);
presupuestoTemp.setTirada2(null);
presupuestoTemp.setTirada3(null);
presupuestoTemp.setTirada4(null);
if (presupuestoTemp.getTipoImpresion() == Presupuesto.TipoImpresion.color) {
presupuestoTemp.setTipoImpresion(Presupuesto.TipoImpresion.colorhq);
} else if (presupuestoTemp.getTipoImpresion() == Presupuesto.TipoImpresion.negro) {
presupuestoTemp.setTipoImpresion(Presupuesto.TipoImpresion.negrohq);
}
String priceStr = apiClient.getPrice(this.toSkApiRequest(presupuestoTemp),
presupuestoTemp.getTipoEncuadernacion(), presupuestoTemp.getTipoCubierta());
Double price_prototipo = 0.0;
try {
price = new ObjectMapper().readValue(priceStr, new TypeReference<>() {
});
price_prototipo = ((List<Double>) ((Map<String, Object>) price.get("data")).get("precios")).get(0);
if (price_prototipo < 25) {
price_prototipo = 25.0;
}
} catch (JsonProcessingException e) {
} catch (Exception exception) {
}
return price_prototipo;
}
// Utilidad local (puedes moverla a una clase Utils si quieres)
private static String anonymizeIp(String ip) {
if (ip == null)
return null;
// IPv4
if (ip.contains(".") && !ip.contains(":")) {
String[] p = ip.split("\\.");
if (p.length == 4) {
return p[0] + "." + p[1] + "." + p[2] + ".0";
}
}
// IPv6: quedarnos con /64 -> primera mitad y rellenar
if (ip.contains(":")) {
String[] parts = ip.split(":", -1);
// expand no estricta, nos quedamos con primeros 4 bloques y completamos
int blocks = Math.min(parts.length, 4);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < blocks; i++) {
if (i > 0)
sb.append(":");
sb.append(parts[i].isEmpty() ? "0" : parts[i]);
}
// completar a /64 con ceros
for (int i = blocks; i < 8; i++)
sb.append(":0");
return sb.toString();
}
return ip;
}
}