package com.imprimelibros.erp.pedidos; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import java.security.Principal; import java.util.Comparator; import java.util.List; import java.util.Locale; import java.util.Map; import org.springframework.context.MessageSource; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Controller; import com.imprimelibros.erp.common.Utils; import com.imprimelibros.erp.datatables.DataTable; import com.imprimelibros.erp.datatables.DataTablesParser; import com.imprimelibros.erp.datatables.DataTablesRequest; import com.imprimelibros.erp.datatables.DataTablesResponse; import com.imprimelibros.erp.users.UserDao; import jakarta.persistence.criteria.Join; import jakarta.persistence.criteria.JoinType; import jakarta.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping("/pedidos") public class PedidosController { private final PedidoRepository repoPedido; private final UserDao repoUser; private final MessageSource messageSource; private final PedidoLineaRepository repoPedidoLinea; public PedidosController(PedidoRepository repoPedido, UserDao repoUser, MessageSource messageSource, PedidoLineaRepository repoPedidoLinea) { this.repoPedido = repoPedido; this.repoUser = repoUser; this.messageSource = messageSource; this.repoPedidoLinea = repoPedidoLinea; } @GetMapping public String listarPedidos() { if (Utils.isCurrentUserAdmin()) { return "imprimelibros/pedidos/pedidos-list"; } return "imprimelibros/pedidos/pedidos-list-cliente"; } @GetMapping(value = "datatable", produces = "application/json") @ResponseBody public DataTablesResponse> getDatatable( HttpServletRequest request, Principal principal, Locale locale) { DataTablesRequest dt = DataTablesParser.from(request); Boolean isAdmin = Utils.isCurrentUserAdmin(); Long currentUserId = Utils.currentUserId(principal); List searchable = List.of( "id" // "client" no, porque lo calculas a posteriori ); // Campos ordenables List orderable = List.of( "id", "createdBy.fullName", "createdAt", "total", "estado"); Specification base = (root, query, cb) -> cb.conjunction(); if (!isAdmin) { base = base.and((root, query, cb) -> cb.equal(root.get("userId"), currentUserId)); } String clientSearch = dt.getColumnSearch("cliente"); String estadoSearch = dt.getColumnSearch("estado"); // 2) Si hay filtro, traducirlo a userIds y añadirlo al Specification if (clientSearch != null) { List userIds = repoUser.findIdsByFullNameLike(clientSearch.trim()); if (userIds.isEmpty()) { // Ningún usuario coincide → forzamos 0 resultados base = base.and((root, query, cb) -> cb.disjunction()); } else { base = base.and((root, query, cb) -> root.get("createdBy").in(userIds)); } } if (estadoSearch != null && !estadoSearch.isBlank()) { try { PedidoLinea.Estado estadoEnum = PedidoLinea.Estado.valueOf(estadoSearch.trim()); base = base.and((root, query, cb) -> { // Evitar duplicados de pedidos si el provider usa joins if (Pedido.class.equals(query.getResultType())) { query.distinct(true); } Join lineas = root.join("lineas", JoinType.INNER); return cb.equal(lineas.get("estado"), estadoEnum); }); } catch (IllegalArgumentException ex) { // Valor de estado no válido → forzamos 0 resultados base = base.and((root, query, cb) -> cb.disjunction()); } } Long total = repoPedido.count(base); return DataTable .of(repoPedido, Pedido.class, dt, searchable) .orderable(orderable) .add("id", Pedido::getId) .add("created_at", pedido -> Utils.formatInstant(pedido.getCreatedAt(), locale)) .add("cliente", pedido -> { if (pedido.getCreatedBy() != null) { return pedido.getCreatedBy().getFullName(); } return ""; }) .add("total", pedido -> { if (pedido.getTotal() != null) { return Utils.formatCurrency(pedido.getTotal(), locale); } else { return ""; } }) .add("estado", pedido -> { List lineas = repoPedidoLinea.findByPedidoId(pedido.getId()); if (lineas.isEmpty()) { return ""; } // concatenar los estados de las líneas, ordenados por prioridad StringBuilder sb = new StringBuilder(); lineas.stream() .map(PedidoLinea::getEstado) .distinct() .sorted(Comparator.comparingInt(PedidoLinea.Estado::getPriority)) .forEach(estado -> { if (sb.length() > 0) { sb.append(", "); } sb.append(messageSource.getMessage(estado.getMessageKey(), null, locale)); }); String text = sb.toString(); return text; }) .add("actions", pedido -> { return "" + messageSource.getMessage("app.view", null, locale) + ""; }) .where(base) .toJson(total); } }