mirror of
https://git.imnavajas.es/jjimenez/erp-imprimelibros.git
synced 2026-01-12 16:38:48 +00:00
Compare commits
3 Commits
84a822db22
...
73676f60b9
| Author | SHA1 | Date | |
|---|---|---|---|
| 73676f60b9 | |||
| 18a43ea121 | |||
| d19cd1923c |
3232
logs/erp.log
3232
logs/erp.log
File diff suppressed because it is too large
Load Diff
@ -446,12 +446,13 @@ public class CartService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Long crearPedido(Long cartId, Locale locale) {
|
||||
public Long crearPedido(Long cartId, Long dirFactId, Locale locale) {
|
||||
|
||||
Cart cart = this.getCartById(cartId);
|
||||
List<CartItem> items = cart.getItems();
|
||||
|
||||
List<Map<String, Object>> presupuestoRequests = new ArrayList<>();
|
||||
Map<String, Object> presupuestoDireccionesRequest = new HashMap<>();
|
||||
List<Long> presupuestoIds = new ArrayList<>();
|
||||
|
||||
for (Integer i = 0; i < items.size(); i++) {
|
||||
@ -479,6 +480,8 @@ public class CartService {
|
||||
data_to_send.put("direcciones", direcciones_presupuesto.get("direcciones"));
|
||||
data_to_send.put("direccionesFP1", direcciones_presupuesto.get("direccionesFP1"));
|
||||
|
||||
presupuestoDireccionesRequest.put(p.getId().toString(), direcciones_presupuesto);
|
||||
|
||||
Map<String, Object> result = skApiClient.savePresupuesto(data_to_send);
|
||||
|
||||
if (result.containsKey("error")) {
|
||||
@ -505,7 +508,7 @@ public class CartService {
|
||||
p.setProveedorRef2(presId);
|
||||
p.setEstado(Presupuesto.Estado.aceptado);
|
||||
presupuestoRepo.save(p);
|
||||
|
||||
|
||||
presupuestoIds.add(p.getId());
|
||||
|
||||
presupuestoRequests.add(dataMap);
|
||||
@ -526,8 +529,14 @@ public class CartService {
|
||||
if (pedidoId == null) {
|
||||
throw new IllegalStateException("No se pudo crear el pedido en SK.");
|
||||
}
|
||||
Pedido pedidoInterno = pedidoService.crearPedido(presupuestoIds, this.getCartSummaryRaw(cart, locale),
|
||||
"Safekat", String.valueOf(pedidoId), cart.getUserId());
|
||||
Pedido pedidoInterno = pedidoService.crearPedido(
|
||||
presupuestoIds,
|
||||
presupuestoDireccionesRequest,
|
||||
dirFactId,
|
||||
this.getCartSummaryRaw(cart, locale),
|
||||
"Safekat",
|
||||
String.valueOf(pedidoId),
|
||||
cart.getUserId());
|
||||
return pedidoInterno.getId();
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,6 +16,8 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.imprimelibros.erp.common.Utils;
|
||||
import com.imprimelibros.erp.datatables.DataTable;
|
||||
import com.imprimelibros.erp.datatables.DataTablesParser;
|
||||
@ -98,7 +100,7 @@ public class PaymentController {
|
||||
Specification<PaymentTransaction> base = Specification.allOf(
|
||||
(root, query, cb) -> cb.equal(root.get("status"), PaymentTransactionStatus.succeeded));
|
||||
base = base.and((root, query, cb) -> cb.equal(root.get("type"), PaymentTransactionType.CAPTURE));
|
||||
|
||||
base = base.and((root, query, cb) -> cb.notEqual(root.join("payment").get("gateway"), "bank_transfer"));
|
||||
String clientSearch = dt.getColumnSearch("client");
|
||||
|
||||
// 2) Si hay filtro, traducirlo a userIds y añadirlo al Specification
|
||||
@ -229,10 +231,23 @@ public class PaymentController {
|
||||
})
|
||||
.add("transfer_id", pago -> {
|
||||
if (pago.getPayment() != null) {
|
||||
return "TRANSF-" + pago.getPayment().getOrderId();
|
||||
} else {
|
||||
return "";
|
||||
String responsePayload = pago.getResponsePayload();
|
||||
Long cartId = null;
|
||||
if (responsePayload != null && !responsePayload.isBlank()) {
|
||||
try {
|
||||
JsonNode node = new ObjectMapper().readTree(responsePayload);
|
||||
if (node.has("cartId")) {
|
||||
cartId = node.get("cartId").asLong();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
cartId = null;
|
||||
}
|
||||
}
|
||||
if (cartId != null) {
|
||||
return "TRANSF-" + cartId;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
})
|
||||
.add("order_id", pago -> {
|
||||
if (pago.getStatus() != PaymentTransactionStatus.pending) {
|
||||
|
||||
@ -47,7 +47,7 @@ public class PaymentService {
|
||||
* oficial (ApiMacSha256).
|
||||
*/
|
||||
@Transactional
|
||||
public FormPayload createRedsysPayment(Long cartId, long amountCents, String currency, String method)
|
||||
public FormPayload createRedsysPayment(Long cartId, Long dirFactId, Long amountCents, String currency, String method)
|
||||
throws Exception {
|
||||
Payment p = new Payment();
|
||||
p.setOrderId(null);
|
||||
@ -73,7 +73,7 @@ public class PaymentService {
|
||||
payRepo.save(p);
|
||||
|
||||
RedsysService.PaymentRequest req = new RedsysService.PaymentRequest(dsOrder, amountCents,
|
||||
"Compra en Imprimelibros", cartId);
|
||||
"Compra en Imprimelibros", cartId, dirFactId);
|
||||
|
||||
if ("bizum".equalsIgnoreCase(method)) {
|
||||
return redsysService.buildRedirectFormBizum(req);
|
||||
@ -213,7 +213,10 @@ public class PaymentService {
|
||||
}
|
||||
|
||||
if (authorized) {
|
||||
processOrder(notif.cartId, locale);
|
||||
Long orderId = processOrder(notif.cartId, notif.dirFactId, locale);
|
||||
if (orderId != null) {
|
||||
p.setOrderId(orderId);
|
||||
}
|
||||
}
|
||||
|
||||
payRepo.save(p);
|
||||
@ -308,15 +311,13 @@ public class PaymentService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Payment createBankTransferPayment(Long cartId, long amountCents, String currency) {
|
||||
public Payment createBankTransferPayment(Long cartId, Long dirFactId, long amountCents, String currency) {
|
||||
Payment p = new Payment();
|
||||
p.setOrderId(null);
|
||||
|
||||
Cart cart = this.cartService.findById(cartId);
|
||||
if (cart != null && cart.getUserId() != null) {
|
||||
p.setUserId(cart.getUserId());
|
||||
// En el orderId de la transferencia pendiente guardamos el ID del carrito
|
||||
p.setOrderId(cartId);
|
||||
// Se bloquea el carrito para evitar modificaciones mientras se procesa el pago
|
||||
this.cartService.lockCartById(cartId);
|
||||
}
|
||||
@ -334,6 +335,18 @@ public class PaymentService {
|
||||
tx.setStatus(PaymentTransactionStatus.pending);
|
||||
tx.setAmountCents(amountCents);
|
||||
tx.setCurrency(currency);
|
||||
String payload = "";
|
||||
if (cartId != null) {
|
||||
payload = "{\"cartId\":" + cartId + "}";
|
||||
}
|
||||
if (dirFactId != null) {
|
||||
if (!payload.isEmpty()) {
|
||||
payload = payload.substring(0, payload.length() - 1) + ",\"dirFactId\":" + dirFactId + "}";
|
||||
} else {
|
||||
payload = "{\"dirFactId\":" + dirFactId + "}";
|
||||
}
|
||||
}
|
||||
tx.setResponsePayload(payload);
|
||||
// tx.setProcessedAt(null); // la dejas nula hasta que se confirme
|
||||
txRepo.save(tx);
|
||||
|
||||
@ -374,12 +387,33 @@ public class PaymentService {
|
||||
p.setAmountCapturedCents(p.getAmountTotalCents());
|
||||
p.setCapturedAt(LocalDateTime.now());
|
||||
p.setStatus(PaymentStatus.captured);
|
||||
payRepo.save(p);
|
||||
|
||||
// 4) Procesar el pedido asociado al carrito (si existe)
|
||||
if (p.getOrderId() != null) {
|
||||
processOrder(p.getOrderId(), locale);
|
||||
Long cartId = null;
|
||||
Long dirFactId = null;
|
||||
try {
|
||||
// Intentar extraer cartId del payload de la transacción
|
||||
if (tx.getResponsePayload() != null && !tx.getResponsePayload().isBlank()) {
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
var node = om.readTree(tx.getResponsePayload());
|
||||
if (node.has("cartId")) {
|
||||
cartId = node.get("cartId").asLong();
|
||||
}
|
||||
if (node.has("dirFactId")) {
|
||||
dirFactId = node.get("dirFactId").asLong();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignorar
|
||||
}
|
||||
|
||||
// 4) Procesar el pedido asociado al carrito (si existe)
|
||||
if (cartId != null) {
|
||||
Long orderId = processOrder(cartId, dirFactId, locale);
|
||||
if (orderId != null) {
|
||||
p.setOrderId(orderId);
|
||||
}
|
||||
}
|
||||
payRepo.save(p);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -481,22 +515,23 @@ public class PaymentService {
|
||||
*
|
||||
*/
|
||||
@Transactional
|
||||
private Boolean processOrder(Long cartId, Locale locale) {
|
||||
private Long processOrder(Long cartId, Long dirFactId, Locale locale) {
|
||||
|
||||
Cart cart = this.cartService.findById(cartId);
|
||||
if (cart != null) {
|
||||
// Bloqueamos el carrito
|
||||
this.cartService.lockCartById(cart.getId());
|
||||
// Creamos el pedido
|
||||
Long orderId = this.cartService.crearPedido(cart.getId(), locale);
|
||||
Long orderId = this.cartService.crearPedido(cart.getId(), dirFactId, locale);
|
||||
if (orderId == null) {
|
||||
return false;
|
||||
return null;
|
||||
} else {
|
||||
// envio de correo de confirmacion de pedido podria ir aqui
|
||||
return orderId;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
211
src/main/java/com/imprimelibros/erp/pedidos/PedidoDireccion.java
Normal file
211
src/main/java/com/imprimelibros/erp/pedidos/PedidoDireccion.java
Normal file
@ -0,0 +1,211 @@
|
||||
package com.imprimelibros.erp.pedidos;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import com.imprimelibros.erp.direcciones.Direccion.TipoIdentificacionFiscal;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "pedidos_direcciones")
|
||||
public class PedidoDireccion {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
// FK a pedidos_lineas.id (nullable, on delete set null)
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "pedido_linea_id")
|
||||
private PedidoLinea pedidoLinea;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "pedido_id")
|
||||
private Pedido pedido;
|
||||
|
||||
@Column(name = "unidades")
|
||||
private Integer unidades;
|
||||
|
||||
@Column(name = "is_facturacion", nullable = false)
|
||||
private boolean facturacion = false;
|
||||
|
||||
@Column(name = "is_ejemplar_prueba", nullable = false)
|
||||
private boolean ejemplarPrueba = false;
|
||||
|
||||
@Column(name = "att", nullable = false, length = 150)
|
||||
private String att;
|
||||
|
||||
@Column(name = "direccion", nullable = false, length = 255)
|
||||
private String direccion;
|
||||
|
||||
@Column(name = "cp", nullable = false)
|
||||
private Integer cp;
|
||||
|
||||
@Column(name = "ciudad", nullable = false, length = 100)
|
||||
private String ciudad;
|
||||
|
||||
@Column(name = "provincia", nullable = false, length = 100)
|
||||
private String provincia;
|
||||
|
||||
@Column(name = "pais_code3", nullable = false, length = 3)
|
||||
private String paisCode3 = "esp";
|
||||
|
||||
@Column(name = "telefono", nullable = false, length = 30)
|
||||
private String telefono;
|
||||
|
||||
@Column(name = "instrucciones", length = 255)
|
||||
private String instrucciones;
|
||||
|
||||
@Column(name = "razon_social", length = 150)
|
||||
private String razonSocial;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "tipo_identificacion_fiscal", nullable = false, length = 20)
|
||||
private TipoIdentificacionFiscal tipoIdentificacionFiscal = TipoIdentificacionFiscal.DNI;
|
||||
|
||||
@Column(name = "identificacion_fiscal", length = 50)
|
||||
private String identificacionFiscal;
|
||||
|
||||
@CreationTimestamp
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
// ===== GETTERS & SETTERS =====
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public PedidoLinea getPedidoLinea() {
|
||||
return pedidoLinea;
|
||||
}
|
||||
|
||||
public void setPedidoLinea(PedidoLinea pedidoLinea) {
|
||||
this.pedidoLinea = pedidoLinea;
|
||||
}
|
||||
|
||||
public Pedido getPedido() {
|
||||
return pedido;
|
||||
}
|
||||
|
||||
public void setPedido(Pedido pedido) {
|
||||
this.pedido = pedido;
|
||||
}
|
||||
|
||||
public Integer getUnidades() {
|
||||
return unidades;
|
||||
}
|
||||
|
||||
public void setUnidades(Integer unidades) {
|
||||
this.unidades = unidades;
|
||||
}
|
||||
|
||||
public boolean isFacturacion() {
|
||||
return facturacion;
|
||||
}
|
||||
|
||||
public void setFacturacion(boolean facturacion) {
|
||||
this.facturacion = facturacion;
|
||||
}
|
||||
|
||||
public boolean isEjemplarPrueba() {
|
||||
return ejemplarPrueba;
|
||||
}
|
||||
|
||||
public void setEjemplarPrueba(boolean ejemplarPrueba) {
|
||||
this.ejemplarPrueba = ejemplarPrueba;
|
||||
}
|
||||
|
||||
public String getAtt() {
|
||||
return att;
|
||||
}
|
||||
|
||||
public void setAtt(String att) {
|
||||
this.att = att;
|
||||
}
|
||||
|
||||
public String getDireccion() {
|
||||
return direccion;
|
||||
}
|
||||
|
||||
public void setDireccion(String direccion) {
|
||||
this.direccion = direccion;
|
||||
}
|
||||
|
||||
public Integer getCp() {
|
||||
return cp;
|
||||
}
|
||||
|
||||
public void setCp(Integer cp) {
|
||||
this.cp = cp;
|
||||
}
|
||||
|
||||
public String getCiudad() {
|
||||
return ciudad;
|
||||
}
|
||||
|
||||
public void setCiudad(String ciudad) {
|
||||
this.ciudad = ciudad;
|
||||
}
|
||||
|
||||
public String getProvincia() {
|
||||
return provincia;
|
||||
}
|
||||
|
||||
public void setProvincia(String provincia) {
|
||||
this.provincia = provincia;
|
||||
}
|
||||
|
||||
public String getPaisCode3() {
|
||||
return paisCode3;
|
||||
}
|
||||
|
||||
public void setPaisCode3(String paisCode3) {
|
||||
this.paisCode3 = paisCode3;
|
||||
}
|
||||
|
||||
public String getTelefono() {
|
||||
return telefono;
|
||||
}
|
||||
|
||||
public void setTelefono(String telefono) {
|
||||
this.telefono = telefono;
|
||||
}
|
||||
|
||||
public String getInstrucciones() {
|
||||
return instrucciones;
|
||||
}
|
||||
|
||||
public void setInstrucciones(String instrucciones) {
|
||||
this.instrucciones = instrucciones;
|
||||
}
|
||||
|
||||
public String getRazonSocial() {
|
||||
return razonSocial;
|
||||
}
|
||||
|
||||
public void setRazonSocial(String razonSocial) {
|
||||
this.razonSocial = razonSocial;
|
||||
}
|
||||
|
||||
public TipoIdentificacionFiscal getTipoIdentificacionFiscal() {
|
||||
return tipoIdentificacionFiscal;
|
||||
}
|
||||
|
||||
public void setTipoIdentificacionFiscal(TipoIdentificacionFiscal tipoIdentificacionFiscal) {
|
||||
this.tipoIdentificacionFiscal = tipoIdentificacionFiscal;
|
||||
}
|
||||
|
||||
public String getIdentificacionFiscal() {
|
||||
return identificacionFiscal;
|
||||
}
|
||||
|
||||
public void setIdentificacionFiscal(String identificacionFiscal) {
|
||||
this.identificacionFiscal = identificacionFiscal;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
package com.imprimelibros.erp.pedidos;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PedidoDireccionRepository extends JpaRepository<PedidoDireccion, Long> {
|
||||
|
||||
// Todas las direcciones de una línea de pedido
|
||||
List<PedidoDireccion> findByPedidoLinea_Id(Long pedidoLineaId);
|
||||
|
||||
// Si en tu código sueles trabajar con el objeto:
|
||||
List<PedidoDireccion> findByPedidoLinea(PedidoLinea pedidoLinea);
|
||||
}
|
||||
|
||||
@ -9,6 +9,24 @@ import com.imprimelibros.erp.presupuesto.dto.Presupuesto;
|
||||
@Table(name = "pedidos_lineas")
|
||||
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");
|
||||
|
||||
private final String messageKey;
|
||||
|
||||
Estado(String messageKey) {
|
||||
this.messageKey = messageKey;
|
||||
}
|
||||
|
||||
public String getMessageKey() {
|
||||
return messageKey;
|
||||
}
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
@ -21,6 +39,13 @@ public class PedidoLinea {
|
||||
@JoinColumn(name = "presupuesto_id", nullable = false)
|
||||
private Presupuesto presupuesto;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "estado", nullable = false)
|
||||
private Estado estado = Estado.aprobado;
|
||||
|
||||
@Column(name = "estado_manual", nullable = false)
|
||||
private Boolean estadoManual;
|
||||
|
||||
@Column(name = "created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@ -53,6 +78,22 @@ public class PedidoLinea {
|
||||
this.presupuesto = presupuesto;
|
||||
}
|
||||
|
||||
public Estado getEstado() {
|
||||
return estado;
|
||||
}
|
||||
|
||||
public void setEstado(Estado estado) {
|
||||
this.estado = estado;
|
||||
}
|
||||
|
||||
public Boolean getEstadoManual() {
|
||||
return estadoManual;
|
||||
}
|
||||
|
||||
public void setEstadoManual(Boolean estadoManual) {
|
||||
this.estadoManual = estadoManual;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
package com.imprimelibros.erp.pedidos;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface PedidoRepository extends JpaRepository<Pedido, Long> {
|
||||
// aquí podrás añadir métodos tipo:
|
||||
// List<Pedido> findByDeletedFalse();
|
||||
public interface PedidoRepository extends JpaRepository<Pedido, Long>, JpaSpecificationExecutor<Pedido> {
|
||||
}
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
package com.imprimelibros.erp.pedidos;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
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.direcciones.DireccionService;
|
||||
|
||||
@Service
|
||||
public class PedidoService {
|
||||
@ -16,12 +19,17 @@ public class PedidoService {
|
||||
private final PedidoRepository pedidoRepository;
|
||||
private final PedidoLineaRepository pedidoLineaRepository;
|
||||
private final PresupuestoRepository presupuestoRepository;
|
||||
private final PedidoDireccionRepository pedidoDireccionRepository;
|
||||
private final DireccionService direccionService;
|
||||
|
||||
public PedidoService(PedidoRepository pedidoRepository, PedidoLineaRepository pedidoLineaRepository,
|
||||
PresupuestoRepository presupuestoRepository) {
|
||||
PresupuestoRepository presupuestoRepository, PedidoDireccionRepository pedidoDireccionRepository,
|
||||
DireccionService direccionService) {
|
||||
this.pedidoRepository = pedidoRepository;
|
||||
this.pedidoLineaRepository = pedidoLineaRepository;
|
||||
this.presupuestoRepository = presupuestoRepository;
|
||||
this.pedidoDireccionRepository = pedidoDireccionRepository;
|
||||
this.direccionService = direccionService;
|
||||
}
|
||||
|
||||
public int getDescuentoFidelizacion() {
|
||||
@ -52,7 +60,10 @@ public class PedidoService {
|
||||
* - usuario que crea el pedido
|
||||
*/
|
||||
@Transactional
|
||||
public Pedido crearPedido(List<Long> presupuestoIds,
|
||||
public Pedido crearPedido(
|
||||
List<Long> presupuestoIds,
|
||||
Map<String, Object> presupuestoDirecciones,
|
||||
Long direccionFacturacionId,
|
||||
Map<String, Object> cartSummaryRaw,
|
||||
String proveedor,
|
||||
String proveedorRef,
|
||||
@ -91,11 +102,124 @@ public class PedidoService {
|
||||
linea.setPresupuesto(presupuesto);
|
||||
linea.setCreatedBy(userId);
|
||||
linea.setCreatedAt(LocalDateTime.now());
|
||||
|
||||
linea.setEstado(PedidoLinea.Estado.aprobado);
|
||||
linea.setEstadoManual(false);
|
||||
pedidoLineaRepository.save(linea);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Map<String, Object>> direcciones = (Map<String, Map<String, Object>>) presupuestoDirecciones
|
||||
.get(presupuesto.getId().toString());
|
||||
if (direcciones != null) {
|
||||
saveDireccionesPedidoLinea(direcciones, saved, linea, direccionFacturacionId);
|
||||
}
|
||||
}
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
private void saveDireccionesPedidoLinea(
|
||||
Map<String, Map<String, Object>> direcciones,
|
||||
Pedido pedido,
|
||||
PedidoLinea linea, Long direccionFacturacionId) {
|
||||
// direccion prueba
|
||||
if (direcciones.containsKey("direccionesFP1")) {
|
||||
try {
|
||||
Map<String, Object> fp1 = (Map<String, Object>) direcciones.get("direccionesFP1");
|
||||
@SuppressWarnings("unchecked")
|
||||
PedidoDireccion direccion = saveDireccion(
|
||||
(HashMap<String, Object>) fp1.get("direccion"),
|
||||
pedido,
|
||||
linea, true,
|
||||
false);
|
||||
pedidoDireccionRepository.save(direccion);
|
||||
} catch (Exception e) {
|
||||
// Viene vacio
|
||||
}
|
||||
}
|
||||
if (direcciones.containsKey("direcciones")) {
|
||||
List<?> dirs = (List<?>) direcciones.get("direcciones");
|
||||
for (Object dir : dirs) {
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String, Object> direccionEnvio = (HashMap<String, Object>) ((HashMap<String, Object>) dir)
|
||||
.get("direccion");
|
||||
if (direccionEnvio.get("cantidad") != null && (Integer) direccionEnvio.get("cantidad") == 4
|
||||
&& direccionEnvio.get("att").toString().contains("Depósito Legal")) {
|
||||
continue; // Saltar la dirección de depósito legal
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
PedidoDireccion direccion = saveDireccion(
|
||||
(HashMap<String, Object>) ((HashMap<String, Object>) dir).get("direccion"),
|
||||
pedido,
|
||||
linea, false,
|
||||
false);
|
||||
pedidoDireccionRepository.save(direccion);
|
||||
}
|
||||
}
|
||||
if (direccionFacturacionId != null) {
|
||||
Direccion dirFact = direccionService.findById(direccionFacturacionId).orElse(null);
|
||||
if (dirFact != null) {
|
||||
HashMap<String, Object> dirFactMap = new HashMap<>();
|
||||
dirFactMap.put("att", dirFact.getAtt());
|
||||
dirFactMap.put("direccion", dirFact.getDireccion());
|
||||
dirFactMap.put("cp", dirFact.getCp());
|
||||
dirFactMap.put("municipio", dirFact.getCiudad());
|
||||
dirFactMap.put("provincia", dirFact.getProvincia());
|
||||
dirFactMap.put("pais_code3", dirFact.getPaisCode3());
|
||||
dirFactMap.put("telefono", dirFact.getTelefono());
|
||||
dirFactMap.put("instrucciones", dirFact.getInstrucciones());
|
||||
dirFactMap.put("razon_social", dirFact.getRazonSocial());
|
||||
dirFactMap.put("tipo_identificacion_fiscal", dirFact.getTipoIdentificacionFiscal().name());
|
||||
dirFactMap.put("identificacion_fiscal", dirFact.getIdentificacionFiscal());
|
||||
|
||||
PedidoDireccion direccion = saveDireccion(
|
||||
dirFactMap,
|
||||
pedido,
|
||||
linea, false,
|
||||
true);
|
||||
pedidoDireccionRepository.save(direccion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PedidoDireccion saveDireccion(HashMap<String, Object> dir, Pedido pedido, PedidoLinea linea,
|
||||
Boolean isEjemplarPrueba,
|
||||
Boolean isFacturacion) {
|
||||
|
||||
PedidoDireccion direccion = new PedidoDireccion();
|
||||
direccion.setPedidoLinea(isFacturacion ? null : linea);
|
||||
if (isFacturacion) {
|
||||
direccion.setUnidades(null);
|
||||
direccion.setFacturacion(true);
|
||||
direccion.setPedido(pedido);
|
||||
|
||||
} else {
|
||||
if (isEjemplarPrueba) {
|
||||
direccion.setUnidades(1);
|
||||
direccion.setEjemplarPrueba(true);
|
||||
} else {
|
||||
direccion.setUnidades((Integer) dir.getOrDefault("cantidad", 1));
|
||||
direccion.setEjemplarPrueba(false);
|
||||
}
|
||||
}
|
||||
|
||||
direccion.setFacturacion(false);
|
||||
direccion.setAtt((String) dir.getOrDefault("att", ""));
|
||||
direccion.setDireccion((String) dir.getOrDefault("direccion", ""));
|
||||
direccion.setCp((Integer) dir.getOrDefault("cp", 0));
|
||||
direccion.setCiudad((String) dir.getOrDefault("municipio", ""));
|
||||
direccion.setProvincia((String) dir.getOrDefault("provincia", ""));
|
||||
direccion.setPaisCode3((String) dir.getOrDefault("pais_code3", "esp"));
|
||||
direccion.setTelefono((String) dir.getOrDefault("telefono", ""));
|
||||
direccion.setInstrucciones((String) dir.getOrDefault("instrucciones", ""));
|
||||
direccion.setRazonSocial((String) dir.getOrDefault("razon_social", ""));
|
||||
direccion.setTipoIdentificacionFiscal(Direccion.TipoIdentificacionFiscal
|
||||
.valueOf((String) dir.getOrDefault("tipo_identificacion_fiscal",
|
||||
Direccion.TipoIdentificacionFiscal.DNI.name())));
|
||||
direccion.setIdentificacionFiscal((String) dir.getOrDefault("identificacion_fiscal", ""));
|
||||
|
||||
return direccion;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,128 @@
|
||||
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.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;
|
||||
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.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.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
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;
|
||||
|
||||
public PedidosController(PedidoRepository repoPedido, UserDao repoUser, MessageSource messageSource) {
|
||||
this.repoPedido = repoPedido;
|
||||
this.repoUser = repoUser;
|
||||
this.messageSource = messageSource;
|
||||
}
|
||||
|
||||
@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<Map<String, Object>> getDatatable(
|
||||
HttpServletRequest request,
|
||||
Principal principal,
|
||||
Locale locale) {
|
||||
|
||||
DataTablesRequest dt = DataTablesParser.from(request);
|
||||
|
||||
Boolean isAdmin = Utils.isCurrentUserAdmin();
|
||||
Long currentUserId = Utils.currentUserId(principal);
|
||||
|
||||
List<String> searchable = List.of(
|
||||
"id",
|
||||
"estado"
|
||||
// "client" no, porque lo calculas a posteriori
|
||||
);
|
||||
|
||||
// Campos ordenables
|
||||
List<String> orderable = List.of(
|
||||
"id",
|
||||
"client",
|
||||
"created_at",
|
||||
"total",
|
||||
"estado");
|
||||
|
||||
Specification<Pedido> 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");
|
||||
|
||||
// 2) Si hay filtro, traducirlo a userIds y añadirlo al Specification
|
||||
if (clientSearch != null) {
|
||||
List<Long> 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("created_by").in(userIds));
|
||||
}
|
||||
}
|
||||
Long total = repoPedido.count(base);
|
||||
|
||||
return DataTable
|
||||
.of(repoPedido, Pedido.class, dt, searchable)
|
||||
.orderable(orderable)
|
||||
.add("id", Pedido::getId)
|
||||
.add("created_at", pedido -> Utils.formatDateTime(pedido.getCreatedAt(), locale))
|
||||
.add("client", pedido -> {
|
||||
if (pedido.getCreatedBy() != null) {
|
||||
Optional<User> user = repoUser.findById(pedido.getCreatedBy());
|
||||
return user.map(User::getFullName).orElse("");
|
||||
}
|
||||
return "";
|
||||
})
|
||||
.add("total", pedido -> {
|
||||
if (pedido.getTotal() != null) {
|
||||
return Utils.formatCurrency(pedido.getTotal(), locale);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
})
|
||||
.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>";
|
||||
})
|
||||
.where(base)
|
||||
.toJson(total);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -387,6 +387,9 @@ public class Presupuesto extends AbstractAuditedEntity implements Cloneable {
|
||||
@Column(name = "proveedor_ref2")
|
||||
private Long proveedorRef2;
|
||||
|
||||
@Column(name = "is_reimpresion", nullable = false)
|
||||
private Boolean isReimpresion;
|
||||
|
||||
// ====== MÉTODOS AUX ======
|
||||
|
||||
public String resumenPresupuesto() {
|
||||
@ -965,6 +968,14 @@ public class Presupuesto extends AbstractAuditedEntity implements Cloneable {
|
||||
this.proveedorRef2 = proveedorRef2;
|
||||
}
|
||||
|
||||
public Boolean getIsReimpresion() {
|
||||
return isReimpresion;
|
||||
}
|
||||
|
||||
public void setIsReimpresion(Boolean isReimpresion) {
|
||||
this.isReimpresion = isReimpresion;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@ -50,13 +50,14 @@ public class RedsysController {
|
||||
@ResponseBody
|
||||
public ResponseEntity<byte[]> crearPago(@RequestParam("amountCents") Long amountCents,
|
||||
@RequestParam("method") String method, @RequestParam("cartId") Long cartId,
|
||||
@RequestParam(value = "dirFactId", required = false) Long dirFactId,
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response, Locale locale)
|
||||
throws Exception {
|
||||
|
||||
if ("bank-transfer".equalsIgnoreCase(method)) {
|
||||
// 1) Creamos el Payment interno SIN orderId (null)
|
||||
Payment p = paymentService.createBankTransferPayment(cartId, amountCents, "EUR");
|
||||
Payment p = paymentService.createBankTransferPayment(cartId, dirFactId, amountCents, "EUR");
|
||||
|
||||
// 1️⃣ Crear la "aplicación" web de Thymeleaf (Jakarta)
|
||||
JakartaServletWebApplication app = JakartaServletWebApplication.buildApplication(servletContext);
|
||||
@ -88,7 +89,7 @@ public class RedsysController {
|
||||
}
|
||||
|
||||
// Tarjeta o Bizum (Redsys)
|
||||
FormPayload form = paymentService.createRedsysPayment(cartId, amountCents, "EUR", method);
|
||||
FormPayload form = paymentService.createRedsysPayment(cartId, dirFactId, amountCents, "EUR", method);
|
||||
|
||||
String html = """
|
||||
<html><head><meta charset="utf-8"><title>Redirigiendo a Redsys…</title></head>
|
||||
|
||||
@ -49,7 +49,7 @@ public class RedsysService {
|
||||
|
||||
// ---------- RECORDS ----------
|
||||
// Pedido a Redsys
|
||||
public record PaymentRequest(String order, long amountCents, String description, Long cartId) {
|
||||
public record PaymentRequest(String order, long amountCents, String description, Long cartId, Long dirFactId) {
|
||||
}
|
||||
|
||||
// Payload para el formulario
|
||||
@ -84,7 +84,10 @@ public class RedsysService {
|
||||
// Si tu PaymentRequest no lo lleva todavía, puedes pasarlo en description o
|
||||
// crear otro campo.
|
||||
JSONObject ctx = new JSONObject();
|
||||
ctx.put("cartId", req.cartId()); // o req.cartId() si decides añadirlo al record
|
||||
ctx.put("cartId", req.cartId());
|
||||
if (req.dirFactId() != null) {
|
||||
ctx.put("dirFactId", req.dirFactId());
|
||||
}
|
||||
api.setParameter("DS_MERCHANT_MERCHANTDATA", ctx.toString());
|
||||
|
||||
if (req.description() != null && !req.description().isBlank()) {
|
||||
@ -195,6 +198,7 @@ public class RedsysService {
|
||||
public final long amountCents;
|
||||
public final String currency;
|
||||
public final Long cartId;
|
||||
public final Long dirFactId;
|
||||
public final String processedPayMethod; // Ds_ProcessedPayMethod
|
||||
public final String bizumIdOper; // Ds_Bizum_IdOper
|
||||
public final String authorisationCode; // Ds_AuthorisationCode
|
||||
@ -206,6 +210,7 @@ public class RedsysService {
|
||||
this.currency = str(raw.get("Ds_Currency"));
|
||||
this.amountCents = parseLongSafe(raw.get("Ds_Amount"));
|
||||
this.cartId = extractCartId(raw.get("Ds_MerchantData"));
|
||||
this.dirFactId = extractDirFactId(raw.get("Ds_MerchantData"));
|
||||
this.processedPayMethod = str(raw.get("Ds_ProcessedPayMethod"));
|
||||
this.bizumIdOper = str(raw.get("Ds_Bizum_IdOper"));
|
||||
this.authorisationCode = str(raw.get("Ds_AuthorisationCode"));
|
||||
@ -228,6 +233,24 @@ public class RedsysService {
|
||||
}
|
||||
}
|
||||
|
||||
private static Long extractDirFactId(Object merchantDataObj) {
|
||||
if (merchantDataObj == null)
|
||||
return null;
|
||||
try {
|
||||
String json = String.valueOf(merchantDataObj);
|
||||
|
||||
// 👇 DES-ESCAPAR las comillas HTML que vienen de Redsys
|
||||
json = json.replace(""", "\"");
|
||||
|
||||
org.json.JSONObject ctx = new org.json.JSONObject(json);
|
||||
long v = ctx.optLong("dirFactId", 0L);
|
||||
return v != 0L ? v : null;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(); // te ayudará si vuelve a fallar
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean authorized() {
|
||||
try {
|
||||
int r = Integer.parseInt(response);
|
||||
|
||||
@ -0,0 +1,151 @@
|
||||
databaseChangeLog:
|
||||
- changeSet:
|
||||
id: 0014-create-pedidos-direcciones
|
||||
author: jjo
|
||||
changes:
|
||||
- createTable:
|
||||
tableName: pedidos_direcciones
|
||||
columns:
|
||||
- column:
|
||||
name: id
|
||||
type: BIGINT AUTO_INCREMENT
|
||||
constraints:
|
||||
primaryKey: true
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: pedido_linea_id
|
||||
type: BIGINT
|
||||
constraints:
|
||||
nullable: true
|
||||
|
||||
- column:
|
||||
name: pedido_id
|
||||
type: BIGINT
|
||||
constraints:
|
||||
nullable: true
|
||||
|
||||
- column:
|
||||
name: unidades
|
||||
type: MEDIUMINT UNSIGNED
|
||||
constraints:
|
||||
nullable: true
|
||||
|
||||
- column:
|
||||
name: is_facturacion
|
||||
type: TINYINT(1)
|
||||
defaultValueNumeric: 0
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: is_ejemplar_prueba
|
||||
type: TINYINT(1)
|
||||
defaultValueNumeric: 0
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: att
|
||||
type: VARCHAR(150)
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: direccion
|
||||
type: VARCHAR(255)
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: cp
|
||||
type: MEDIUMINT UNSIGNED
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: ciudad
|
||||
type: VARCHAR(100)
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: provincia
|
||||
type: VARCHAR(100)
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: pais_code3
|
||||
type: CHAR(3)
|
||||
defaultValue: esp
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: telefono
|
||||
type: VARCHAR(30)
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: instrucciones
|
||||
type: VARCHAR(255)
|
||||
constraints:
|
||||
nullable: true
|
||||
|
||||
- column:
|
||||
name: razon_social
|
||||
type: VARCHAR(150)
|
||||
constraints:
|
||||
nullable: true
|
||||
|
||||
- column:
|
||||
name: tipo_identificacion_fiscal
|
||||
type: ENUM('DNI','NIE','CIF','Pasaporte','VAT_ID')
|
||||
defaultValue: DNI
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: identificacion_fiscal
|
||||
type: VARCHAR(50)
|
||||
constraints:
|
||||
nullable: true
|
||||
|
||||
- column:
|
||||
name: created_at
|
||||
type: TIMESTAMP
|
||||
defaultValueComputed: CURRENT_TIMESTAMP
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- addForeignKeyConstraint:
|
||||
baseTableName: pedidos_direcciones
|
||||
baseColumnNames: pedido_linea_id
|
||||
referencedTableName: pedidos_lineas
|
||||
referencedColumnNames: id
|
||||
constraintName: fk_pedidos_direcciones_pedido_linea
|
||||
onDelete: SET NULL
|
||||
onUpdate: CASCADE
|
||||
|
||||
- addForeignKeyConstraint:
|
||||
baseTableName: pedidos_direcciones
|
||||
baseColumnNames: pedido_id
|
||||
referencedTableName: pedidos
|
||||
referencedColumnNames: id
|
||||
constraintName: fk_pedidos_direcciones_pedidos
|
||||
onDelete: SET NULL
|
||||
onUpdate: CASCADE
|
||||
|
||||
- createIndex:
|
||||
tableName: pedidos_direcciones
|
||||
indexName: idx_pedidos_direcciones_pedido_linea_id
|
||||
columns:
|
||||
- column:
|
||||
name: pedido_linea_id
|
||||
|
||||
rollback:
|
||||
- dropTable:
|
||||
tableName: pedidos_direcciones
|
||||
cascadeConstraints: true
|
||||
@ -0,0 +1,48 @@
|
||||
databaseChangeLog:
|
||||
- changeSet:
|
||||
id: 0015-alter-pedidos-lineas-and-presupuesto-estados
|
||||
author: jjo
|
||||
changes:
|
||||
# Añadir columnas a pedidos_lineas
|
||||
- addColumn:
|
||||
tableName: pedidos_lineas
|
||||
columns:
|
||||
- column:
|
||||
name: estado
|
||||
type: "ENUM('aprobado','maquetación','haciendo_ferro','producción','terminado','cancelado')"
|
||||
defaultValue: aprobado
|
||||
constraints:
|
||||
nullable: false
|
||||
afterColumn: presupuesto_id
|
||||
|
||||
- column:
|
||||
name: estado_manual
|
||||
type: TINYINT(1)
|
||||
defaultValueNumeric: 0
|
||||
constraints:
|
||||
nullable: false
|
||||
afterColumn: estado
|
||||
|
||||
# Añadir columna a presupuesto
|
||||
- addColumn:
|
||||
tableName: presupuesto
|
||||
columns:
|
||||
- column:
|
||||
name: is_reimpresion
|
||||
type: TINYINT(1)
|
||||
defaultValueNumeric: 0
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
rollback:
|
||||
- dropColumn:
|
||||
tableName: pedidos_lineas
|
||||
columnName: estado
|
||||
|
||||
- dropColumn:
|
||||
tableName: pedidos_lineas
|
||||
columnName: estado_manual
|
||||
|
||||
- dropColumn:
|
||||
tableName: presupuesto
|
||||
columnName: is_reimpresion
|
||||
@ -24,4 +24,8 @@ databaseChangeLog:
|
||||
- include:
|
||||
file: db/changelog/changesets/0012--drop-unique-gateway-txid-2.yml
|
||||
- include:
|
||||
file: db/changelog/changesets/0013-drop-unique-refund-gateway-id.yml
|
||||
file: db/changelog/changesets/0013-drop-unique-refund-gateway-id.yml
|
||||
- include:
|
||||
file: db/changelog/changesets/0014-create-pedidos-direcciones.yml
|
||||
- include:
|
||||
file: db/changelog/changesets/0015-alter-pedidos-lineas-and-presupuesto-estados.yml
|
||||
@ -10,6 +10,7 @@ app.add=Añadir
|
||||
app.back=Volver
|
||||
app.eliminar=Eliminar
|
||||
app.imprimir=Imprimir
|
||||
app.view=Ver
|
||||
app.acciones.siguiente=Siguiente
|
||||
app.acciones.anterior=Anterior
|
||||
|
||||
@ -20,6 +21,7 @@ app.logout=Cerrar sesión
|
||||
|
||||
app.sidebar.inicio=Inicio
|
||||
app.sidebar.presupuestos=Presupuestos
|
||||
app.sidebar.pedidos=Pedidos
|
||||
app.sidebar.configuracion=Configuración
|
||||
app.sidebar.usuarios=Usuarios
|
||||
app.sidebar.direcciones=Mis Direcciones
|
||||
|
||||
@ -15,4 +15,20 @@ checkout.error.payment=Error al procesar el pago: el pago ha sido cancelado o re
|
||||
checkout.success.payment=Pago realizado con éxito. Gracias por su compra.
|
||||
|
||||
checkout.make-payment=Realizar el pago
|
||||
checkout.authorization-required=Certifico que tengo los derechos para imprimir los archivos incluidos en mi pedido y me hago responsable en caso de reclamación de los mismos
|
||||
checkout.authorization-required=Certifico que tengo los derechos para imprimir los archivos incluidos en mi pedido y me hago responsable en caso de reclamación de los mismos
|
||||
|
||||
pedido.estado.aprobado=Aprobado
|
||||
pedido.estado.maquetacion=Maquetación
|
||||
pedido.estado.haciendo_ferro=Haciendo ferro
|
||||
pedido.estado.produccion=Producción
|
||||
pedido.estado.terminado=Terminado
|
||||
pedido.estado.cancelado=Cancelado
|
||||
|
||||
pedido.module-title=Pedidos
|
||||
|
||||
pedido.table.id=Num. Pedido
|
||||
pedido.table.cliente=Cliente
|
||||
pedido.table.fecha=Fecha
|
||||
pedido.table.importe=Importe
|
||||
pedido.table.estado=Estado
|
||||
pedido.table.acciones=Acciones
|
||||
@ -140,6 +140,7 @@ $(() => {
|
||||
let uri = `/checkout/get-address/${direccionId}`;
|
||||
const response = await fetch(uri);
|
||||
if (response.ok) {
|
||||
$('#dirFactId').val(direccionId);
|
||||
const html = await response.text();
|
||||
$('#direccion-div').append(html);
|
||||
$('#addBillingAddressBtn').addClass('d-none');
|
||||
|
||||
54
src/main/resources/static/assets/js/pages/pedidos/pedidos.js
Normal file
54
src/main/resources/static/assets/js/pages/pedidos/pedidos.js
Normal file
@ -0,0 +1,54 @@
|
||||
$(() => {
|
||||
|
||||
const csrfToken = document.querySelector('meta[name="_csrf"]')?.getAttribute('content');
|
||||
const csrfHeader = document.querySelector('meta[name="_csrf_header"]')?.getAttribute('content');
|
||||
if (window.$ && csrfToken && csrfHeader) {
|
||||
$.ajaxSetup({
|
||||
beforeSend: function (xhr) {
|
||||
xhr.setRequestHeader(csrfHeader, csrfToken);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const language = document.documentElement.lang || 'es-ES';
|
||||
|
||||
const tablePedidos = $('#table-pedidos').DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
orderCellsTop: true,
|
||||
pageLength: 50,
|
||||
lengthMenu: [10, 25, 50, 100, 500],
|
||||
order: [[5, 'desc']], // Ordena por fecha por defecto
|
||||
language: { url: '/assets/libs/datatables/i18n/' + language + '.json' },
|
||||
responsive: true,
|
||||
dom: 'lBrtip',
|
||||
buttons: {
|
||||
dom: {
|
||||
button: {
|
||||
className: 'btn btn-sm btn-outline-primary me-1'
|
||||
},
|
||||
buttons: [
|
||||
{ extend: 'copy' },
|
||||
{ extend: 'csv' },
|
||||
{ extend: 'excel' },
|
||||
{ extend: 'pdf' },
|
||||
{ extend: 'print' },
|
||||
{ extend: 'colvis' }
|
||||
],
|
||||
}
|
||||
},
|
||||
ajax: {
|
||||
url: '/pedidos/datatable',
|
||||
method: 'GET',
|
||||
},
|
||||
order: [[0, 'desc']],
|
||||
columns: [
|
||||
{ data: 'id', name: 'id', orderable: true },
|
||||
{ data: 'cliente', name: 'cliente', orderable: true },
|
||||
{ data: 'created_at', name: 'created_at', orderable: true },
|
||||
{ data: 'total', name: 'total', orderable: true },
|
||||
{ data: 'actions', name: 'actions', orderable: false, searchable: false }
|
||||
|
||||
],
|
||||
});
|
||||
})
|
||||
@ -50,6 +50,7 @@
|
||||
<input type="hidden" name="amountCents" th:value="${summary.amountCents}" />
|
||||
<input type="hidden" name="method" value="card" />
|
||||
<input type="hidden" name="cartId" th:value="${summary.cartId}" />
|
||||
<input type="hidden" id="dirFactId" name="dirFactId" value="" />
|
||||
<button id="btn-checkout" type="submit" class="btn btn-secondary w-100 mt-2"
|
||||
th:text="#{checkout.make-payment}" disabled>Checkout</button>
|
||||
</form>
|
||||
|
||||
@ -43,6 +43,11 @@
|
||||
<i class="ri-file-paper-2-line"></i> <span th:text="#{app.sidebar.presupuestos}">Presupuestos</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link menu-link" href="/pedidos">
|
||||
<i class="ri-book-3-line"></i> <span th:text="#{app.sidebar.pedidos}">Pedidos</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link menu-link" href="/direcciones">
|
||||
<i class="ri-truck-line"></i>
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{imprimelibros/layout}">
|
||||
|
||||
<head>
|
||||
<th:block layout:fragment="pagetitle" />
|
||||
<th:block th:replace="~{imprimelibros/partials/head-css :: head-css}" />
|
||||
<th:block layout:fragment="pagecss">
|
||||
<link th:href="@{/assets/libs/datatables/dataTables.bootstrap5.min.css}" rel="stylesheet" />
|
||||
</th:block>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div th:replace="~{imprimelibros/partials/topbar :: topbar}" />
|
||||
<div th:replace="~{imprimelibros/partials/sidebar :: sidebar}"
|
||||
sec:authorize="isAuthenticated() and hasAnyRole('SUPERADMIN','ADMIN')">
|
||||
|
||||
<th:block layout:fragment="content">
|
||||
<div th:if="${#authorization.expression('isAuthenticated()')}">
|
||||
|
||||
<div class="container-fluid">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/"><i class="ri-home-5-fill"></i></a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page" th:text="#{pedido.module-title}">
|
||||
Pedidos</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
<table id="pagos-redsys-datatable" class="table table-striped table-nowrap responsive w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" th:text="#{pedido.table.id}">Num. Pedido</th>
|
||||
<th scope="col" th:text="#{pedido.table.cliente}">Cliente</th>
|
||||
<th scope="col" th:text="#{pedido.table.fecha}">Fecha</th>
|
||||
<th scope="col" th:text="#{pedido.table.importe}">Importe</th>
|
||||
<th scope="col" th:text="#{pedido.table.estado}">Estado</th>
|
||||
<th scope="col" th:text="#{pedido.table.acciones}">Acciones</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><input type="text" class="form-control form-control-sm input-filter" /></th>
|
||||
<th><input type="text" class="form-control form-control-sm input-filter" /></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th>
|
||||
<select class="form-control form-control-sm select-filter">
|
||||
<option value="" ></option>
|
||||
<option value="aprobado" th:text="#{pedido.estado.aprobado}">Aprobado</option>
|
||||
<option value="maquetacion" th:text="#{pedido.estado.maquetacion}">Maquetación</option>
|
||||
<option value="haciendo_ferro" th:text="#{pedido.estado.haciendo_ferro}">Haciendo ferro</option>
|
||||
<option value="produccion" th:text="#{pedido.estado.produccion}">Producción</option>
|
||||
<option value="terminado" th:text="#{pedido.estado.terminado}">Terminado</option>
|
||||
<option value="cancelado" th:text="#{pedido.estado.cancelado}">Cancelado</option>
|
||||
</select>
|
||||
</th>
|
||||
<th></th> <!-- Acciones (sin filtro) -->
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</th:block>
|
||||
|
||||
<th:block th:replace="~{theme/partials/vendor-scripts :: scripts}" />
|
||||
<th:block layout:fragment="pagejs">
|
||||
<script th:inline="javascript">
|
||||
window.languageBundle = /*[[${languageBundle}]]*/ {};
|
||||
</script>
|
||||
|
||||
<script th:src="@{/assets/libs/datatables/datatables.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/dataTables.bootstrap5.min.js}"></script>
|
||||
|
||||
<!-- JS de Buttons y dependencias -->
|
||||
<script th:src="@{/assets/libs/datatables/dataTables.buttons.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/jszip/jszip.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/pdfmake/pdfmake.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/pdfmake/vfs_fonts.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.html5.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.print.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.colVis.min.js}"></script>
|
||||
|
||||
|
||||
<script type="module" th:src="@{/assets/js/pages/imprimelibros/pedidos/pedidos.js}"></script>
|
||||
</th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -0,0 +1,83 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{imprimelibros/layout}">
|
||||
|
||||
<head>
|
||||
<th:block layout:fragment="pagetitle" />
|
||||
<th:block th:replace="~{imprimelibros/partials/head-css :: head-css}" />
|
||||
<th:block layout:fragment="pagecss">
|
||||
<link th:href="@{/assets/libs/datatables/dataTables.bootstrap5.min.css}" rel="stylesheet" />
|
||||
</th:block>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div th:replace="~{imprimelibros/partials/topbar :: topbar}" />
|
||||
<div th:replace="~{imprimelibros/partials/sidebar :: sidebar}"
|
||||
sec:authorize="isAuthenticated() and hasAnyRole('SUPERADMIN','ADMIN')">
|
||||
|
||||
<th:block layout:fragment="content">
|
||||
<div th:if="${#authorization.expression('isAuthenticated()')}">
|
||||
|
||||
<div class="container-fluid">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/"><i class="ri-home-5-fill"></i></a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page" th:text="#{pedido.module-title}">
|
||||
Pedidos</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
<table id="pagos-redsys-datatable" class="table table-striped table-nowrap responsive w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" th:text="#{pedido.table.id}">Num. Pedido</th>
|
||||
<th scope="col" th:text="#{pedido.table.cliente}">Cliente</th>
|
||||
<th scope="col" th:text="#{pedido.table.fecha}">Fecha</th>
|
||||
<th scope="col" th:text="#{pedido.table.importe}">Importe</th>
|
||||
<th scope="col" th:text="#{pedido.table.acciones}">Acciones</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><input type="text" class="form-control form-control-sm input-filter" /></th>
|
||||
<th><input type="text" class="form-control form-control-sm input-filter" /></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th> <!-- Acciones (sin filtro) -->
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</th:block>
|
||||
|
||||
<th:block th:replace="~{theme/partials/vendor-scripts :: scripts}" />
|
||||
<th:block layout:fragment="pagejs">
|
||||
<script th:inline="javascript">
|
||||
window.languageBundle = /*[[${languageBundle}]]*/ {};
|
||||
</script>
|
||||
|
||||
<script th:src="@{/assets/libs/datatables/datatables.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/dataTables.bootstrap5.min.js}"></script>
|
||||
|
||||
<!-- JS de Buttons y dependencias -->
|
||||
<script th:src="@{/assets/libs/datatables/dataTables.buttons.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/jszip/jszip.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/pdfmake/pdfmake.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/pdfmake/vfs_fonts.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.html5.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.print.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.colVis.min.js}"></script>
|
||||
|
||||
|
||||
<script type="module" th:src="@{/assets/js/pages/imprimelibros/pedidos/pedidos.js}"></script>
|
||||
</th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -18,7 +18,7 @@ public class envioCarroTest {
|
||||
void addPedido(){
|
||||
|
||||
Locale locale = Locale.forLanguageTag("es-ES");
|
||||
cartService.crearPedido(carritoId, locale);
|
||||
cartService.crearPedido(carritoId, null, locale);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ public class savePresupuestosTest {
|
||||
@Test
|
||||
void testGuardarPresupuesto() {
|
||||
Locale locale = new Locale("es", "ES");
|
||||
Long resultado = cartService.crearPedido(9L, locale);
|
||||
Long resultado = cartService.crearPedido(9L, null, locale);
|
||||
|
||||
System.out.println("📦 Presupuesto guardado:");
|
||||
System.out.println(resultado);
|
||||
|
||||
Reference in New Issue
Block a user