package com.imprimelibros.erp.presupuesto; import com.imprimelibros.erp.common.Utils; import com.imprimelibros.erp.datatables.*; import com.imprimelibros.erp.presupuesto.dto.Presupuesto; import jakarta.persistence.criteria.Expression; import org.springframework.context.MessageSource; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.security.Principal; import java.time.*; import java.time.format.DateTimeFormatter; import java.util.*; @Service public class PresupuestoDatatableService { private final MessageSource messageSource; private final PresupuestoRepository repo; public PresupuestoDatatableService(MessageSource messageSource, PresupuestoRepository repo) { this.messageSource = messageSource; this.repo = repo; } @Transactional(readOnly = true) public DataTablesResponse> datatablePublicos(DataTablesRequest dt, Locale locale, Principal principal) { return commonDataTable(dt, locale, "publico", true, principal); } @Transactional(readOnly = true) public DataTablesResponse> datatablePrivados(DataTablesRequest dt, Locale locale, Principal principal) { return commonDataTable(dt, locale, "privado", false, principal); } private DataTablesResponse> commonDataTable(DataTablesRequest dt, Locale locale, String origen, boolean publico, Principal principal) { Specification base = Specification.allOf( (root, query, cb) -> cb.equal(root.get("origen"), Presupuesto.Origen.valueOf(origen))); Boolean isAdmin = Utils.isCurrentUserAdmin(); if (!isAdmin) { base = base.and((root, query, cb) -> cb.equal(root.get("user").get("id"), Utils.currentUserId(principal))); } Long count = repo.count(base); List orderable = List.of( "id", "titulo", "user.fullName", "tipoEncuadernacion", "tipoCubierta", "tipoImpresion", "selectedTirada", "estado", "totalConIva", "paginas", "pais", "region", "ciudad", "updatedAt"); return DataTable.of(repo, Presupuesto.class, dt, List.of("")) // búsqueda global solo por campos simples .orderable(orderable) .where((root, query, cb) -> cb.equal(root.get("origen"), Presupuesto.Origen.valueOf(origen))) .onlyAddedColumns() .add("id", Presupuesto::getId) .add("titulo", Presupuesto::getTitulo) .add("tipoEncuadernacion", p -> msg(p.getTipoEncuadernacion().getMessageKey(), locale)) .add("tipoCubierta", p -> msg(p.getTipoCubierta().getMessageKey(), locale)) .add("tipoImpresion", p -> msg(p.getTipoImpresion().getMessageKey(), locale)) .add("selectedTirada", Presupuesto::getSelectedTirada) .add("paginas", p -> n(p.getPaginasColor()) + n(p.getPaginasNegro())) .filter("paginas", (root, q, cb, value) -> { Expression sum = cb.sum( cb.coalesce(root.get("paginasColor"), cb.literal(0)), cb.coalesce(root.get("paginasNegro"), cb.literal(0))); Expression asStr = cb.function("CONCAT", String.class, cb.literal(""), sum); return cb.like(asStr, "%" + value.trim() + "%"); }) .orderable("paginas", (root, q, cb) -> cb.sum( cb.coalesce(root.get("paginasColor"), cb.literal(0)), cb.coalesce(root.get("paginasNegro"), cb.literal(0)))) .add("estado", p -> msg(p.getEstado().getMessageKey(), locale)) .add("totalConIva", p -> Utils.formatCurrency(p.getTotalConIva(), locale)) .addIf(publico, "pais", Presupuesto::getPais) .addIf(publico, "region", Presupuesto::getRegion) .addIf(publico, "ciudad", Presupuesto::getCiudad) .add("updatedAt", p -> formatDate(p.getUpdatedAt(), locale)) .addIf(!publico, "user", p -> p.getUser() != null ? p.getUser().getFullName() : "") .add("actions", this::generarBotones) .where(base) .toJson(count); } /* ---------- helpers ---------- */ 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 generarBotones(Presupuesto p) { boolean borrador = p.getEstado() == Presupuesto.Estado.borrador; String id = String.valueOf(p.getId()); String editBtn = ""; String deleteBtn = borrador ? "" : ""; return "
" + editBtn + deleteBtn + "
"; } }