se guardan los presupuestos publicos

This commit is contained in:
2025-10-05 17:47:42 +02:00
parent 14ca264ae2
commit b2f3ef042e
6 changed files with 122 additions and 74 deletions

View File

@ -1,35 +1,42 @@
// JpaAuditConfig.java
package com.imprimelibros.erp.config;
import java.util.Optional;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import com.imprimelibros.erp.users.User;
import java.util.Optional;
import com.imprimelibros.erp.users.UserDao;
@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorAware")
public class JpaAuditConfig {
@Bean
public AuditorAware<User> auditorAware() {
public AuditorAware<User> auditorAware(UserDao userDao) {
return () -> {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || !auth.isAuthenticated()) return Optional.empty();
var auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || !auth.isAuthenticated())
return Optional.empty();
Object principal = auth.getPrincipal();
if (principal instanceof User u) return Optional.of(u);
if (principal instanceof User u)
return Optional.of(u);
if (principal instanceof UserDetails ud) {
// Si tu principal es UserDetails y no la entidad User,
// aquí podrías cargar User por username si lo necesitas.
return Optional.empty();
return userDao.findByUserNameIgnoreCase(ud.getUsername());
}
if (principal instanceof String username && !"anonymousUser".equals(username)) {
return userDao.findByUserNameIgnoreCase(username);
}
return Optional.empty();
};
}

View File

@ -85,7 +85,7 @@ public class SecurityConfig {
.authenticationProvider(provider)
.sessionManagement(session -> session
.invalidSessionUrl("/login?expired")
//.invalidSessionUrl("/login?expired")
.maximumSessions(1))
// Ignora CSRF para tu recurso público (sin Ant/Mvc matchers)

View File

@ -17,10 +17,11 @@ import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLRestriction;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.Instant;
import com.imprimelibros.erp.users.User;
@ -336,19 +337,6 @@ public class Presupuesto extends AbstractAuditedSoftDeleteEntity implements Clon
@Column(name = "alto_faja")
private Integer altoFaja = 0;
// ====== AUDIT ======
@CreatedDate
@Column(name = "created_at", updatable = false)
private LocalDateTime createdAt;
@CreatedBy
@Column(name = "created_by", updatable = false) // BIGINT o VARCHAR: ajusta el tipo del campo
private Long createdBy; // o String si tu columna es texto
// ====== MÉTODOS AUX ======
public String resumenPresupuesto() {
@ -874,5 +862,4 @@ public class Presupuesto extends AbstractAuditedSoftDeleteEntity implements Clon
this.altoFaja = altoFaja;
}
}

View File

@ -540,35 +540,6 @@ public class PresupuestoService {
return response;
}
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;
}
public HashMap<String, Object> getPrecioMaquetacion(PresupuestoMaquetacion presupuestoMaquetacion, Locale locale) {
try {
List<MaquetacionPrecios> lista = maquetacionPreciosRepository.findAll();
@ -903,7 +874,8 @@ public class PresupuestoService {
// IP: guarda hash y trunc (si tienes campos). Si no, guarda tal cual en
// ip_trunc/ip_hash según tu modelo.
presupuesto.setIpTrunc(ip);
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
@ -957,6 +929,33 @@ public class PresupuestoService {
return resumen;
}
/**
* PRIVADO (futuro botón "Guardar"): persiste el presupuesto como borrador.
*/
@Transactional
public Presupuesto guardarPrivado(Presupuesto presupuesto) {
presupuesto.setEstado(Presupuesto.Estado.borrador);
return presupuestoRepository.saveAndFlush(presupuesto);
}
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;
}
// =======================================================================
// Métodos privados
// =======================================================================
/**
* Copia de campos "actualizables" para no machacar otros (created_at, etc.)
*/
@ -1016,27 +1015,76 @@ public class PresupuestoService {
return target;
}
/**
* PRIVADO (futuro botón "Guardar"): persiste el presupuesto como borrador.
*/
@Transactional
public Presupuesto guardarPrivado(Presupuesto presupuesto) {
presupuesto.setEstado(Presupuesto.Estado.borrador);
return presupuestoRepository.saveAndFlush(presupuesto);
}
public HashMap<String, Object> calcularPresupuesto(Presupuesto presupuesto, Locale locale) {
private Double obtenerPrototipo(Presupuesto presupuesto) {
// Obtenemos el precio de 1 unidad para el ejemplar de prueba
HashMap<String, Object> price = new HashMap<>();
String priceStr = apiClient.getPrice(this.toSkApiRequest(presupuesto), presupuesto.getTipoEncuadernacion(),
presupuesto.getTipoCubierta());
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) {
price = new HashMap<>();
price.put("error", messageSource.getMessage("presupuesto.error-obtener-precio", null, locale));
} catch (Exception exception) {
}
return price;
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;
}
private static String sha256Hex(String input) {
try {
var md = java.security.MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(input.getBytes(java.nio.charset.StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder(digest.length * 2);
for (byte b : digest)
sb.append(String.format("%02x", b));
return sb.toString();
} catch (Exception e) {
return null;
}
}
}

View File

@ -81,3 +81,9 @@ server.servlet.session.persistent=false
geoip.enabled=true
geoip.maxmind.enabled=true
geoip.http.enabled=true
#
# Hibernate Timezone
#
spring.jpa.properties.hibernate.jdbc.time_zone=UTC

View File

@ -1418,8 +1418,8 @@ class PresupuestoCliente {
data: JSON.stringify(body)
}).then((data) => {
$('#resumen-titulo').text(data.titulo);
if (resumen.presupuesto_id) {
window.PRESUPUESTO_ID = resumen.presupuesto_id;
if (data.presupuesto_id) {
window.PRESUPUESTO_ID = data.presupuesto_id;
}
body.presupuesto.id = window.PRESUPUESTO_ID || body.presupuesto.id || null;