listado de pedidos admin hecho

This commit is contained in:
2025-11-17 10:35:04 +01:00
parent 73676f60b9
commit 6ff5250d1b
12 changed files with 3307 additions and 2646 deletions

View File

@ -4,7 +4,9 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.Principal;
import java.text.NumberFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
@ -12,6 +14,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import org.springframework.context.MessageSource;
@ -357,4 +360,54 @@ public class Utils {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm", locale);
return dateTime.format(formatter);
}
public static String formatInstant(Instant instant, Locale locale) {
if (instant == null) {
return "";
}
ZoneId zone = zoneIdForLocale(locale);
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("dd/MM/yyyy HH:mm", locale)
.withZone(zone);
return formatter.format(instant);
}
/*********************
* Metodos auxiliares
*/
private static ZoneId zoneIdForLocale(Locale locale) {
if (locale == null || locale.getCountry().isEmpty()) {
return ZoneId.of("UTC");
}
// Buscar timezones cuyo ID termine con el country code
// Ej: ES -> Europe/Madrid
String country = locale.getCountry();
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
for (String id : zoneIds) {
// TimeZone# getID() no funciona por país, pero sí el prefijo + país
if (id.endsWith("/" + country) || id.contains("/" + country)) {
return ZoneId.of(id);
}
}
// fallback por regiones comunes (manual pero muy útil)
Map<String, String> fallback = Map.of(
"ES", "Europe/Madrid",
"MX", "America/Mexico_City",
"AR", "America/Argentina/Buenos_Aires",
"US", "America/New_York",
"GB", "Europe/London",
"FR", "Europe/Paris");
if (fallback.containsKey(country)) {
return ZoneId.of(fallback.get(country));
}
return ZoneId.systemDefault(); // último fallback
}
}

View File

@ -1,11 +1,15 @@
package com.imprimelibros.erp.pedidos;
import jakarta.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import com.imprimelibros.erp.common.jpa.AbstractAuditedEntity;
@Entity
@Table(name = "pedidos")
public class Pedido {
public class Pedido extends AbstractAuditedEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@ -37,27 +41,8 @@ public class Pedido {
@Column(name = "proveedor_ref", length = 100)
private String proveedorRef;
// Auditoría básica (coincidiendo con las columnas que se ven en la captura)
@Column(name = "created_by")
private Long createdBy;
@Column(name = "updated_by")
private Long updatedBy;
@Column(name = "deleted_by")
private Long deletedBy;
@Column(name = "deleted", nullable = false)
private boolean deleted = false;
@Column(name = "created_at", updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Column(name = "deleted_at")
private LocalDateTime deletedAt;
@OneToMany(mappedBy = "pedido", cascade = CascadeType.ALL, orphanRemoval = false)
private List<PedidoLinea> lineas = new ArrayList<>();
// --- Getters y setters ---
@ -132,60 +117,4 @@ public class Pedido {
public void setProveedorRef(String proveedorRef) {
this.proveedorRef = proveedorRef;
}
public Long getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Long createdBy) {
this.createdBy = createdBy;
}
public Long getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(Long updatedBy) {
this.updatedBy = updatedBy;
}
public Long getDeletedBy() {
return deletedBy;
}
public void setDeletedBy(Long deletedBy) {
this.deletedBy = deletedBy;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
public LocalDateTime getDeletedAt() {
return deletedAt;
}
public void setDeletedAt(LocalDateTime deletedAt) {
this.deletedAt = deletedAt;
}
}

View File

@ -10,21 +10,27 @@ import com.imprimelibros.erp.presupuesto.dto.Presupuesto;
public class PedidoLinea {
public enum Estado {
aprobado("pedido.estado.aprobado"),
maquetacion("pedido.estado.maquetacion"),
haciendo_ferro("pedido.estado.haciendo_ferro"),
produccion("pedido.estado.produccion"),
cancelado("pedido.estado.cancelado");
aprobado("pedido.estado.aprobado", 1),
maquetacion("pedido.estado.maquetacion", 2),
haciendo_ferro("pedido.estado.haciendo_ferro", 3),
produccion("pedido.estado.produccion", 4),
cancelado("pedido.estado.cancelado", 5);
private final String messageKey;
private final int priority;
Estado(String messageKey) {
Estado(String messageKey, int priority) {
this.messageKey = messageKey;
this.priority = priority;
}
public String getMessageKey() {
return messageKey;
}
public int getPriority() {
return priority;
}
}
@Id

View File

@ -1,5 +1,6 @@
package com.imprimelibros.erp.pedidos;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
@ -11,6 +12,7 @@ import org.springframework.transaction.annotation.Transactional;
import com.imprimelibros.erp.direcciones.Direccion;
import com.imprimelibros.erp.presupuesto.PresupuestoRepository;
import com.imprimelibros.erp.presupuesto.dto.Presupuesto;
import com.imprimelibros.erp.users.UserService;
import com.imprimelibros.erp.direcciones.DireccionService;
@Service
@ -21,15 +23,17 @@ public class PedidoService {
private final PresupuestoRepository presupuestoRepository;
private final PedidoDireccionRepository pedidoDireccionRepository;
private final DireccionService direccionService;
private final UserService userService;
public PedidoService(PedidoRepository pedidoRepository, PedidoLineaRepository pedidoLineaRepository,
PresupuestoRepository presupuestoRepository, PedidoDireccionRepository pedidoDireccionRepository,
DireccionService direccionService) {
DireccionService direccionService, UserService userService) {
this.pedidoRepository = pedidoRepository;
this.pedidoLineaRepository = pedidoLineaRepository;
this.presupuestoRepository = presupuestoRepository;
this.pedidoDireccionRepository = pedidoDireccionRepository;
this.direccionService = direccionService;
this.userService = userService;
}
public int getDescuentoFidelizacion() {
@ -84,11 +88,11 @@ public class PedidoService {
pedido.setProveedorRef(proveedorRef);
// Auditoría mínima
pedido.setCreatedBy(userId);
pedido.setCreatedAt(LocalDateTime.now());
pedido.setCreatedBy(userService.findById(userId));
pedido.setCreatedAt(Instant.now());
pedido.setDeleted(false);
pedido.setUpdatedAt(LocalDateTime.now());
pedido.setUpdatedBy(userId);
pedido.setUpdatedAt(Instant.now());
pedido.setUpdatedBy(userService.findById(userId));
// Guardamos el pedido
Pedido saved = pedidoRepository.save(pedido);

View File

@ -4,10 +4,10 @@ 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 java.util.Optional;
import org.springframework.context.MessageSource;
import org.springframework.data.jpa.domain.Specification;
@ -18,16 +18,12 @@ 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.payments.model.Payment;
import com.imprimelibros.erp.payments.model.PaymentTransaction;
import com.imprimelibros.erp.payments.model.PaymentTransactionStatus;
import com.imprimelibros.erp.payments.model.PaymentTransactionType;
import com.imprimelibros.erp.users.User;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@ -37,11 +33,14 @@ 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) {
public PedidosController(PedidoRepository repoPedido, UserDao repoUser, MessageSource messageSource,
PedidoLineaRepository repoPedidoLinea) {
this.repoPedido = repoPedido;
this.repoUser = repoUser;
this.messageSource = messageSource;
this.repoPedidoLinea = repoPedidoLinea;
}
@GetMapping
@ -65,16 +64,15 @@ public class PedidosController {
Long currentUserId = Utils.currentUserId(principal);
List<String> searchable = List.of(
"id",
"estado"
"id"
// "client" no, porque lo calculas a posteriori
);
// Campos ordenables
List<String> orderable = List.of(
"id",
"client",
"created_at",
"createdBy.fullName",
"createdAt",
"total",
"estado");
@ -83,6 +81,7 @@ public class PedidosController {
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) {
@ -92,7 +91,26 @@ public class PedidosController {
// Ningún usuario coincide → forzamos 0 resultados
base = base.and((root, query, cb) -> cb.disjunction());
} else {
base = base.and((root, query, cb) -> root.get("created_by").in(userIds));
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<Pedido, PedidoLinea> 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);
@ -101,11 +119,10 @@ public class PedidosController {
.of(repoPedido, Pedido.class, dt, searchable)
.orderable(orderable)
.add("id", Pedido::getId)
.add("created_at", pedido -> Utils.formatDateTime(pedido.getCreatedAt(), locale))
.add("client", pedido -> {
.add("created_at", pedido -> Utils.formatInstant(pedido.getCreatedAt(), locale))
.add("cliente", pedido -> {
if (pedido.getCreatedBy() != null) {
Optional<User> user = repoUser.findById(pedido.getCreatedBy());
return user.map(User::getFullName).orElse("");
return pedido.getCreatedBy().getFullName();
}
return "";
})
@ -116,9 +133,30 @@ public class PedidosController {
return "";
}
})
.add("estado", pedido -> {
List<PedidoLinea> 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 "<span class=\'badge bg-success btn-view \' data-id=\'" + pedido.getId() + "\' style=\'cursor: pointer;\'>"
+ messageSource.getMessage("app.view", null, locale) + "</span>";
return "<span class=\'badge bg-success btn-view \' data-id=\'" + pedido.getId()
+ "\' style=\'cursor: pointer;\'>"
+ messageSource.getMessage("app.view", null, locale) + "</span>";
})
.where(base)
.toJson(total);

View File

@ -17,4 +17,5 @@ public interface UserService extends UserDetailsService {
* @return página de usuarios
*/
Page<User> findByRoleAndSearch(String role, String query, Pageable pageable);
User findById(Long id);
}

View File

@ -31,4 +31,8 @@ public class UserServiceImpl implements UserService {
if (query == null || query.isBlank()) query = null;
return userDao.searchUsers(role, query, pageable);
}
public User findById(Long id) {
return userDao.findById(id).orElse(null);
}
}