tabla anonimos terminado

This commit is contained in:
2025-10-08 21:35:20 +02:00
parent 389ac22b68
commit 2b53579a48
8 changed files with 270 additions and 177 deletions

View File

@ -0,0 +1,233 @@
package com.imprimelibros.erp.presupuesto;
import jakarta.persistence.criteria.Predicate;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.domain.*;
import java.math.BigDecimal;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Service;
import com.imprimelibros.erp.datatables.*;
import java.text.NumberFormat;
import com.imprimelibros.erp.presupuesto.dto.Presupuesto;
@Service
public class PresupuestoDatatableService {
private final MessageSource messageSource;
private final PresupuestoRepository repo;
public PresupuestoDatatableService(MessageSource messageSource, PresupuestoRepository repo) {
this.messageSource = messageSource;
this.repo = repo;
}
/* ---------- API pública ---------- */
public DataTablesResponse<Map<String, Object>> datatableAnonimos(DataTablesRequest dt, Locale locale) {
String term = extractSearch(dt);
Pageable pageable = pageableFrom(dt);
EnumMatches matches = buildEnumMatches(term, locale);
Specification<Presupuesto> spec = baseSpec(term, matches, dt);
Page<Presupuesto> page = repo.findAll(spec, pageable);
var rows = page.getContent().stream()
.map(p -> mapAnonimoRow(p, locale)) // 👈 mapper específico “anonimos”
.toList();
return new DataTablesResponse<>(dt.draw, repo.count(), page.getTotalElements(), rows);
}
public DataTablesResponse<Map<String, Object>> datatableNoAnonimos(DataTablesRequest dt, Locale locale) {
String term = extractSearch(dt);
Pageable pageable = pageableFrom(dt);
EnumMatches matches = buildEnumMatches(term, locale);
Specification<Presupuesto> spec = baseSpec(term, matches, dt);
Page<Presupuesto> page = repo.findAll(spec, pageable);
var rows = page.getContent().stream()
.map(p -> mapNoAnonimoRow(p, locale)) // 👈 otro mapper con más/otros campos
.toList();
return new DataTablesResponse<>(dt.draw, repo.count(), page.getTotalElements(), rows);
}
/* ---------- Helpers reutilizables ---------- */
private String extractSearch(DataTablesRequest dt) {
return (dt.search != null && dt.search.value != null) ? dt.search.value.trim().toLowerCase() : "";
}
private Pageable pageableFrom(DataTablesRequest dt) {
int page = dt.length > 0 ? dt.start / dt.length : 0;
List<Sort.Order> orders = new ArrayList<>();
for (var o : dt.order) {
String field = dt.columns.get(o.column).name; // usa columns[i][name] en el front
if (field == null || field.isBlank())
continue;
orders.add(
new Sort.Order("desc".equalsIgnoreCase(o.dir) ? Sort.Direction.DESC : Sort.Direction.ASC, field));
}
Sort sort = orders.isEmpty() ? Sort.by(Sort.Order.desc("updatedAt")) : Sort.by(orders);
return dt.length > 0 ? PageRequest.of(page, dt.length, sort) : Pageable.unpaged();
}
private EnumMatches buildEnumMatches(String term, Locale locale) {
Function<String, String> tr = key -> {
try {
return messageSource.getMessage(key, null, locale).toLowerCase();
} catch (Exception e) {
return key.toLowerCase();
}
};
var enc = Arrays.stream(Presupuesto.TipoEncuadernacion.values())
.filter(e -> tr.apply(e.getMessageKey()).contains(term))
.collect(() -> EnumSet.noneOf(Presupuesto.TipoEncuadernacion.class), EnumSet::add, EnumSet::addAll);
var cub = Arrays.stream(Presupuesto.TipoCubierta.values())
.filter(e -> tr.apply(e.getMessageKey()).contains(term))
.collect(() -> EnumSet.noneOf(Presupuesto.TipoCubierta.class), EnumSet::add, EnumSet::addAll);
var imp = Arrays.stream(Presupuesto.TipoImpresion.values())
.filter(e -> tr.apply(e.getMessageKey()).contains(term))
.collect(() -> EnumSet.noneOf(Presupuesto.TipoImpresion.class), EnumSet::add, EnumSet::addAll);
var est = Arrays.stream(Presupuesto.Estado.values())
.filter(e -> tr.apply(e.getMessageKey()).contains(term))
.collect(() -> EnumSet.noneOf(Presupuesto.Estado.class), EnumSet::add, EnumSet::addAll);
return new EnumMatches(enc, cub, imp, est);
}
/**
* WHERE + ORDER dinámico (paginas/estado) reutilizable para ambos datatables
*/
private Specification<Presupuesto> baseSpec(String term, EnumMatches m, DataTablesRequest dt) {
return (root, query, cb) -> {
List<Predicate> ors = new ArrayList<>();
if (!term.isBlank()) {
String like = "%" + term + "%";
ors.add(cb.like(cb.lower(root.get("titulo")), like));
ors.add(cb.like(cb.lower(root.get("ciudad")), like));
ors.add(cb.like(cb.lower(root.get("region")), like));
ors.add(cb.like(cb.lower(root.get("pais")), like));
}
if (!m.enc.isEmpty())
ors.add(root.get("tipoEncuadernacion").in(m.enc));
if (!m.cub.isEmpty())
ors.add(root.get("tipoCubierta").in(m.cub));
if (!m.imp.isEmpty())
ors.add(root.get("tipoImpresion").in(m.imp));
if (!m.est.isEmpty())
ors.add(root.get("estado").in(m.est));
// ORDER BY especial si en columns[i][name] viene 'paginas' o 'estado'
if (query != null && !query.getOrderList().isEmpty()) {
var jpaOrders = new ArrayList<jakarta.persistence.criteria.Order>();
for (var ob : query.getOrderList()) {
String prop = ob.getExpression().toString();
boolean asc = ob.isAscending();
if ("paginas".equals(prop)) {
var totalPag = cb.sum(cb.coalesce(root.get("paginasColor"), 0),
cb.coalesce(root.get("paginasNegro"), 0));
jpaOrders.add(asc ? cb.asc(totalPag) : cb.desc(totalPag));
} else if ("estado".equals(prop)) {
var estadoStr = cb.function("str", String.class, root.get("estado"));
jpaOrders.add(asc ? cb.asc(estadoStr) : cb.desc(estadoStr));
} else {
jpaOrders.add(asc ? cb.asc(root.get(prop)) : cb.desc(root.get(prop)));
}
}
query.orderBy(jpaOrders);
}
return ors.isEmpty() ? cb.conjunction() : cb.or(ors.toArray(new Predicate[0]));
};
}
/* ---------- Mappers de filas (puedes tener tantos como vistas) ---------- */
private Map<String, Object> mapAnonimoRow(Presupuesto p, Locale locale) {
int paginas = n(p.getPaginasColor()) + n(p.getPaginasNegro());
Map<String, Object> m = new HashMap<>();
m.put("id", p.getId());
m.put("titulo", p.getTitulo());
m.put("tipoEncuadernacion", msg(p.getTipoEncuadernacion().getMessageKey(), locale));
m.put("tipoCubierta", msg(p.getTipoCubierta().getMessageKey(), locale));
m.put("tipoImpresion", msg(p.getTipoImpresion().getMessageKey(), locale));
m.put("tirada", p.getSelectedTirada());
m.put("paginas", paginas);
m.put("estado", msg(p.getEstado().getMessageKey(), locale));
m.put("totalConIva", formatCurrency(p.getTotalConIva(), locale));
m.put("pais", p.getPais());
m.put("region", p.getRegion());
m.put("ciudad", p.getCiudad());
m.put("updatedAt", formatDate(p.getUpdatedAt(), locale));
m.put("actions",
"<div class=\"hstack gap-3 flex-wrap\">" +
"<a href=\"javascript:void(0);\" data-id=\"" + p.getId()
+ "\" class=\"link-success btn-edit-anonimo fs-15\"><i class=\"ri-edit-2-line\"></i></a>" +
"<a href=\"javascript:void(0);\" data-id=\"" + p.getId()
+ "\" class=\"link-danger btn-delete-anonimo fs-15\"><i class=\"ri-delete-bin-5-line\"></i></a>"
+
"</div>");
return m;
}
private Map<String, Object> mapNoAnonimoRow(Presupuesto p, Locale locale) {
Map<String, Object> m = mapAnonimoRow(p, locale); // base común
// añade/remueve campos específicos de “no anónimos”
// m.put("cliente", p.getCliente().getNombre()); // ejemplo
return m;
}
/* ---------- utilidades ---------- */
private String msg(String key, Locale locale) {
try {
return messageSource.getMessage(key, null, locale);
} catch (Exception e) {
return key;
}
}
private int n(Integer v) {
return v == null ? 0 : v;
}
private String formatDate(Instant instant, Locale locale) {
if (instant == null)
return "";
ZoneId zone = (locale != null && locale.getCountry() != null && !locale.getCountry().isEmpty())
? TimeZone.getTimeZone(locale.toLanguageTag()).toZoneId()
: ZoneId.systemDefault();
var df = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm").withZone(zone);
return df.format(instant);
}
private String formatCurrency(BigDecimal value, Locale locale) {
if (value == null)
return "";
NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
return nf.format(value);
}
/* record para agrupar matches */
private record EnumMatches(
EnumSet<Presupuesto.TipoEncuadernacion> enc,
EnumSet<Presupuesto.TipoCubierta> cub,
EnumSet<Presupuesto.TipoImpresion> imp,
EnumSet<Presupuesto.Estado> est) {
}
}