trabajando en el formulario de la factura

This commit is contained in:
2025-12-31 18:07:17 +01:00
parent d7b5dedb38
commit 9d4320db9a
20 changed files with 6431 additions and 11351 deletions

View File

@ -9,13 +9,12 @@ import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.annotations.Formula;
@Entity
@Table(
name = "facturas",
uniqueConstraints = {
@Table(name = "facturas", uniqueConstraints = {
@UniqueConstraint(name = "uq_facturas_numero_factura", columnNames = "numero_factura")
}
)
})
public class Factura extends AbstractAuditedEntitySoftTs {
@Column(name = "pedido_id")
@ -80,11 +79,15 @@ public class Factura extends AbstractAuditedEntitySoftTs {
@OneToMany(mappedBy = "factura", cascade = CascadeType.ALL, orphanRemoval = true)
private List<FacturaPago> pagos = new ArrayList<>();
@Formula("(select u.fullname from users u where u.id = cliente_id)")
private String clienteNombre;
// Helpers
public void addLinea(FacturaLinea linea) {
linea.setFactura(this);
this.lineas.add(linea);
}
public void removeLinea(FacturaLinea linea) {
this.lineas.remove(linea);
linea.setFactura(null);
@ -94,63 +97,154 @@ public class Factura extends AbstractAuditedEntitySoftTs {
pago.setFactura(this);
this.pagos.add(pago);
}
public void removePago(FacturaPago pago) {
this.pagos.remove(pago);
pago.setFactura(null);
}
// Getters/Setters
public Long getPedidoId() { return pedidoId; }
public void setPedidoId(Long pedidoId) { this.pedidoId = pedidoId; }
public Long getPedidoId() {
return pedidoId;
}
public Factura getFacturaRectificada() { return facturaRectificada; }
public void setFacturaRectificada(Factura facturaRectificada) { this.facturaRectificada = facturaRectificada; }
public void setPedidoId(Long pedidoId) {
this.pedidoId = pedidoId;
}
public Factura getFacturaRectificativa() { return facturaRectificativa; }
public void setFacturaRectificativa(Factura facturaRectificativa) { this.facturaRectificativa = facturaRectificativa; }
public Factura getFacturaRectificada() {
return facturaRectificada;
}
public User getCliente() { return cliente; }
public void setCliente(User cliente) { this.cliente = cliente; }
public void setFacturaRectificada(Factura facturaRectificada) {
this.facturaRectificada = facturaRectificada;
}
public SerieFactura getSerie() { return serie; }
public void setSerie(SerieFactura serie) { this.serie = serie; }
public Factura getFacturaRectificativa() {
return facturaRectificativa;
}
public String getNumeroFactura() { return numeroFactura; }
public void setNumeroFactura(String numeroFactura) { this.numeroFactura = numeroFactura; }
public void setFacturaRectificativa(Factura facturaRectificativa) {
this.facturaRectificativa = facturaRectificativa;
}
public EstadoFactura getEstado() { return estado; }
public void setEstado(EstadoFactura estado) { this.estado = estado; }
public User getCliente() {
return cliente;
}
public EstadoPagoFactura getEstadoPago() { return estadoPago; }
public void setEstadoPago(EstadoPagoFactura estadoPago) { this.estadoPago = estadoPago; }
public void setCliente(User cliente) {
this.cliente = cliente;
}
public TipoPago getTipoPago() { return tipoPago; }
public void setTipoPago(TipoPago tipoPago) { this.tipoPago = tipoPago; }
public SerieFactura getSerie() {
return serie;
}
public LocalDateTime getFechaEmision() { return fechaEmision; }
public void setFechaEmision(LocalDateTime fechaEmision) { this.fechaEmision = fechaEmision; }
public void setSerie(SerieFactura serie) {
this.serie = serie;
}
public BigDecimal getBaseImponible() { return baseImponible; }
public void setBaseImponible(BigDecimal baseImponible) { this.baseImponible = baseImponible; }
public String getNumeroFactura() {
return numeroFactura;
}
public BigDecimal getIva4() { return iva4; }
public void setIva4(BigDecimal iva4) { this.iva4 = iva4; }
public void setNumeroFactura(String numeroFactura) {
this.numeroFactura = numeroFactura;
}
public BigDecimal getIva21() { return iva21; }
public void setIva21(BigDecimal iva21) { this.iva21 = iva21; }
public EstadoFactura getEstado() {
return estado;
}
public BigDecimal getTotalFactura() { return totalFactura; }
public void setTotalFactura(BigDecimal totalFactura) { this.totalFactura = totalFactura; }
public void setEstado(EstadoFactura estado) {
this.estado = estado;
}
public BigDecimal getTotalPagado() { return totalPagado; }
public void setTotalPagado(BigDecimal totalPagado) { this.totalPagado = totalPagado; }
public EstadoPagoFactura getEstadoPago() {
return estadoPago;
}
public String getNotas() { return notas; }
public void setNotas(String notas) { this.notas = notas; }
public void setEstadoPago(EstadoPagoFactura estadoPago) {
this.estadoPago = estadoPago;
}
public List<FacturaLinea> getLineas() { return lineas; }
public void setLineas(List<FacturaLinea> lineas) { this.lineas = lineas; }
public TipoPago getTipoPago() {
return tipoPago;
}
public List<FacturaPago> getPagos() { return pagos; }
public void setPagos(List<FacturaPago> pagos) { this.pagos = pagos; }
public void setTipoPago(TipoPago tipoPago) {
this.tipoPago = tipoPago;
}
public LocalDateTime getFechaEmision() {
return fechaEmision;
}
public void setFechaEmision(LocalDateTime fechaEmision) {
this.fechaEmision = fechaEmision;
}
public BigDecimal getBaseImponible() {
return baseImponible;
}
public void setBaseImponible(BigDecimal baseImponible) {
this.baseImponible = baseImponible;
}
public BigDecimal getIva4() {
return iva4;
}
public void setIva4(BigDecimal iva4) {
this.iva4 = iva4;
}
public BigDecimal getIva21() {
return iva21;
}
public void setIva21(BigDecimal iva21) {
this.iva21 = iva21;
}
public BigDecimal getTotalFactura() {
return totalFactura;
}
public void setTotalFactura(BigDecimal totalFactura) {
this.totalFactura = totalFactura;
}
public BigDecimal getTotalPagado() {
return totalPagado;
}
public void setTotalPagado(BigDecimal totalPagado) {
this.totalPagado = totalPagado;
}
public String getNotas() {
return notas;
}
public void setNotas(String notas) {
this.notas = notas;
}
public List<FacturaLinea> getLineas() {
return lineas;
}
public void setLineas(List<FacturaLinea> lineas) {
this.lineas = lineas;
}
public List<FacturaPago> getPagos() {
return pagos;
}
public void setPagos(List<FacturaPago> pagos) {
this.pagos = pagos;
}
}

View File

@ -0,0 +1,146 @@
package com.imprimelibros.erp.facturacion.controller;
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.facturacion.EstadoFactura;
import com.imprimelibros.erp.facturacion.Factura;
import com.imprimelibros.erp.facturacion.SerieFactura;
import com.imprimelibros.erp.facturacion.TipoSerieFactura;
import com.imprimelibros.erp.facturacion.repo.FacturaRepository;
import com.imprimelibros.erp.facturacion.repo.SerieFacturaRepository;
import com.imprimelibros.erp.i18n.TranslationService;
import jakarta.persistence.EntityNotFoundException;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.context.MessageSource;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@Controller
@RequestMapping("/facturas")
@PreAuthorize("hasRole('SUPERADMIN') || hasRole('ADMIN')")
public class FacturasController {
private final FacturaRepository repo;
private final TranslationService translationService;
private final MessageSource messageSource;
public FacturasController(
FacturaRepository repo,
TranslationService translationService,
MessageSource messageSource) {
this.repo = repo;
this.translationService = translationService;
this.messageSource = messageSource;
}
@GetMapping
public String facturasList(Model model, Locale locale) {
List<String> keys = List.of(
"app.eliminar",
"app.cancelar",
"facturas.delete.title",
"facturas.delete.text",
"facturas.delete.ok.title",
"facturas.delete.ok.text");
Map<String, String> translations = translationService.getTranslations(locale, keys);
model.addAttribute("languageBundle", translations);
return "imprimelibros/facturas/facturas-list";
}
@GetMapping("/{id}")
public String facturaDetail(@PathVariable Long id, Model model, Locale locale) {
Factura factura = repo.findById(id)
.orElseThrow(() -> new EntityNotFoundException("Factura no encontrada con ID: " + id));
model.addAttribute("factura", factura);
return "imprimelibros/facturas/facturas-form";
}
// -----------------------------
// API: DataTables (server-side)
// -----------------------------
@GetMapping("/api/datatables")
@ResponseBody
public DataTablesResponse<Map<String, Object>> datatables(HttpServletRequest request, Locale locale) {
DataTablesRequest dt = DataTablesParser.from(request);
Specification<Factura> notDeleted = (root, q, cb) -> cb.isNull(root.get("deletedAt"));
long total = repo.count(notDeleted);
return DataTable
.of(repo, Factura.class, dt, List.of("clienteNombre", "numeroFactura", "estado", "estadoPago"))
.where(notDeleted)
.orderable(List.of("id", "clienteNombre", "numeroFactura", "estado", "estadoPago"))
.onlyAddedColumns()
.add("id", Factura::getId)
.add("cliente", f -> {
var c = f.getCliente();
return c == null ? null : c.getFullName(); // o getNombre(), etc.
})
.add("numero_factura", Factura::getNumeroFactura)
.add("estado", Factura::getEstado)
.add("estado_label", f -> {
String key = "facturas.estado." + f.getEstado().name().toLowerCase();
return messageSource.getMessage(key, null, f.getEstado().name(), locale);
})
.add("estado_pago", Factura::getEstadoPago)
.add("estado_pago_label", f -> {
String key = "facturas.estado-pago." + f.getEstadoPago().name().toLowerCase();
return messageSource.getMessage(key, null, f.getEstadoPago().name(), locale);
})
.add("total", Factura::getTotalFactura)
.add("fecha_emision", f -> {
LocalDateTime fecha = f.getFechaEmision();
return fecha == null ? null : fecha.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
})
.add("actions", f -> {
if (f.getEstado() == EstadoFactura.borrador) {
return """
<div class="hstack gap-3 flex-wrap">
<button type="button"
class="btn p-0 link-success btn-view-factura fs-15"
data-id="%d">
<i class="ri-eye-line"></i>
</button>
<button type="button"
class="btn p-0 link-danger btn-delete-factura fs-15"
data-id="%d">
<i class="ri-delete-bin-5-line"></i>
</button>
</div>
""".formatted(f.getId(), f.getId());
} else {
return """
<div class="hstack gap-3 flex-wrap">
<button type="button"
class="btn p-0 link-success btn-view-factura fs-15"
data-id="%d">
<i class="ri-eye-line"></i>
</button>
</div>
""".formatted(f.getId());
}
})
.toJson(total);
}
}

View File

@ -98,12 +98,12 @@ public class SeriesFacturacionController {
.add("actions", s -> """
<div class="hstack gap-3 flex-wrap">
<button type="button"
class="btn btn-link p-0 link-success btn-edit-serie fs-15"
class="btn p-0 link-success btn-edit-serie fs-15"
data-id="%d">
<i class="ri-edit-2-line"></i>
</button>
<button type="button"
class="btn btn-link p-0 link-danger btn-delete-serie fs-15"
class="btn p-0 link-danger btn-delete-serie fs-15"
data-id="%d">
<i class="ri-delete-bin-5-line"></i>
</button>

View File

@ -2,9 +2,10 @@ package com.imprimelibros.erp.facturacion.repo;
import com.imprimelibros.erp.facturacion.Factura;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.Optional;
public interface FacturaRepository extends JpaRepository<Factura, Long> {
public interface FacturaRepository extends JpaRepository<Factura, Long>, JpaSpecificationExecutor<Factura> {
Optional<Factura> findByNumeroFactura(String numeroFactura);
}

View File

@ -1,17 +1,31 @@
package com.imprimelibros.erp.facturacion.service;
import com.imprimelibros.erp.common.Utils;
import com.imprimelibros.erp.facturacion.*;
import com.imprimelibros.erp.facturacion.dto.FacturaLineaUpsertDto;
import com.imprimelibros.erp.facturacion.dto.FacturaPagoUpsertDto;
import com.imprimelibros.erp.facturacion.repo.FacturaPagoRepository;
import com.imprimelibros.erp.facturacion.repo.FacturaRepository;
import com.imprimelibros.erp.facturacion.repo.SerieFacturaRepository;
import com.imprimelibros.erp.pedidos.Pedido;
import com.imprimelibros.erp.pedidos.PedidoLinea;
import com.imprimelibros.erp.pedidos.PedidoLineaRepository;
import com.imprimelibros.erp.presupuesto.dto.Presupuesto;
import jakarta.persistence.EntityNotFoundException;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Locale;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Service
@ -20,21 +34,121 @@ public class FacturacionService {
private final FacturaRepository facturaRepo;
private final SerieFacturaRepository serieRepo;
private final FacturaPagoRepository pagoRepo;
private final PedidoLineaRepository pedidoLineaRepo;
private final Utils utils;
private final MessageSource messageSource;
public FacturacionService(
FacturaRepository facturaRepo,
SerieFacturaRepository serieRepo,
FacturaPagoRepository pagoRepo
) {
FacturaPagoRepository pagoRepo,
PedidoLineaRepository pedidoLineaRepo,
Utils utils,
MessageSource messageSource) {
this.facturaRepo = facturaRepo;
this.serieRepo = serieRepo;
this.pagoRepo = pagoRepo;
this.pedidoLineaRepo = pedidoLineaRepo;
this.utils = utils;
this.messageSource = messageSource;
}
public SerieFactura getDefaultSerieFactura() {
List<SerieFactura> series = serieRepo.findAll();
if (series.isEmpty()) {
throw new IllegalStateException("No hay ninguna serie de facturación configurada.");
}
// Aquí simplemente devolvemos la primera. Puedes implementar lógica más
// compleja si es necesario.
return series.get(0);
}
// -----------------------
// Nueva factura
// -----------------------
@Transactional
public Factura crearNuevaFacturaAuto(Pedido pedido, SerieFactura serie, TipoPago tipoPago, Locale locale) {
Factura factura = new Factura();
factura.setCliente(pedido.getCreatedBy());
factura.setCreatedAt(Instant.now());
factura.setUpdatedAt(Instant.now());
Boolean pedidoPendientePago = false;
List<PedidoLinea> lineasPedido = pedidoLineaRepo.findByPedidoId(pedido.getId());
for (PedidoLinea lineaPedido : lineasPedido) {
if (lineaPedido.getEstado() == PedidoLinea.Estado.pendiente_pago) {
pedidoPendientePago = true;
break;
}
}
factura.setEstado(pedidoPendientePago ? EstadoFactura.borrador : EstadoFactura.validada);
factura.setEstadoPago(pedidoPendientePago ? EstadoPagoFactura.pendiente : EstadoPagoFactura.pagada);
factura.setTipoPago(pedidoPendientePago ? TipoPago.otros : tipoPago);
factura.setPedidoId(pedido.getId());
factura.setSerie(serie);
factura.setNumeroFactura(this.getNumberFactura(serie));
factura.setFechaEmision(LocalDateTime.now());
factura.setBaseImponible(BigDecimal.valueOf(pedido.getBase()).setScale(2, RoundingMode.HALF_UP));
factura.setIva4(BigDecimal.valueOf(pedido.getIva4()).setScale(2, RoundingMode.HALF_UP));
factura.setIva21(BigDecimal.valueOf(pedido.getIva21()).setScale(2, RoundingMode.HALF_UP));
factura.setTotalFactura(BigDecimal.valueOf(pedido.getTotal()).setScale(2, RoundingMode.HALF_UP));
factura.setTotalPagado(BigDecimal.valueOf(pedido.getTotal()).setScale(2, RoundingMode.HALF_UP));
// rellenar lineas
List<FacturaLinea> lineasFactura = new ArrayList<>();
for (PedidoLinea lineaPedido : lineasPedido) {
Presupuesto p = lineaPedido.getPresupuesto();
FacturaLinea lineaFactura = new FacturaLinea();
lineaFactura.setDescripcion(this.obtenerLineaFactura(lineaPedido, locale));
lineaFactura.setCantidad(p.getSelectedTirada());
lineaFactura.setBaseLinea(p.getBaseImponible());
lineaFactura.setIva4Linea(p.getIvaImporte4());
lineaFactura.setIva21Linea(p.getIvaImporte21());
lineaFactura.setTotalLinea(p.getTotalConIva());
lineaFactura.setCreatedBy(p.getUser());
lineaFactura.setFactura(factura);
lineasFactura.add(lineaFactura);
}
factura.setLineas(lineasFactura);
factura = facturaRepo.save(factura);
if(pedidoPendientePago) {
return factura;
}
FacturaPago pago = new FacturaPago();
pago.setMetodoPago(tipoPago);
pago.setCantidadPagada(factura.getTotalFactura());
pago.setFechaPago(LocalDateTime.now());
pago.setFactura(factura);
pago.setCreatedBy(pedido.getCreatedBy());
pago.setCreatedAt(Instant.now());
pagoRepo.save(pago);
return factura;
}
// -----------------------
// Estado / Numeración
// -----------------------
@Transactional
public String getNumberFactura(SerieFactura serie) {
try {
long next = (serie.getNumeroActual() == null) ? 1L : serie.getNumeroActual();
String numeroFactura = buildNumeroFactura(serie.getPrefijo(), next);
// Incrementar contador para la siguiente
serie.setNumeroActual(next + 1);
serieRepo.save(serie);
return numeroFactura;
} catch (Exception e) {
return null;
}
}
@Transactional
public Factura validarFactura(Long facturaId) {
Factura factura = facturaRepo.findById(facturaId)
@ -56,7 +170,8 @@ public class FacturacionService {
// Si ya tiene numero_factura, no reservamos otro
if (factura.getNumeroFactura() == null || factura.getNumeroFactura().isBlank()) {
SerieFactura serieLocked = serieRepo.findByIdForUpdate(factura.getSerie().getId())
.orElseThrow(() -> new EntityNotFoundException("Serie no encontrada: " + factura.getSerie().getId()));
.orElseThrow(
() -> new EntityNotFoundException("Serie no encontrada: " + factura.getSerie().getId()));
long next = (serieLocked.getNumeroActual() == null) ? 1L : serieLocked.getNumeroActual();
String numeroFactura = buildNumeroFactura(serieLocked.getPrefijo(), next);
@ -89,7 +204,7 @@ public class FacturacionService {
private String buildNumeroFactura(String prefijo, long numero) {
String pref = (prefijo == null) ? "" : prefijo.trim();
String num = String.format("%07d", numero);
return pref.isBlank() ? num : (pref + "-" + num);
return pref.isBlank() ? num : (pref + " " + num + "/" + LocalDate.now().getYear());
}
// -----------------------
@ -191,7 +306,8 @@ public class FacturacionService {
pago.setFechaPago(dto.getFechaPago() != null ? dto.getFechaPago() : LocalDateTime.now());
pago.setNotas(dto.getNotas());
// El tipo_pago de la factura: si tiene un pago, lo reflejamos (último pago manda)
// El tipo_pago de la factura: si tiene un pago, lo reflejamos (último pago
// manda)
factura.setTipoPago(dto.getMetodoPago());
recalcularTotales(factura);
@ -254,7 +370,8 @@ public class FacturacionService {
factura.setTotalPagado(scale2(pagado));
// estado_pago
// - cancelada: si la factura está marcada como cancelada manualmente (aquí NO lo hacemos automático)
// - cancelada: si la factura está marcada como cancelada manualmente (aquí NO
// lo hacemos automático)
// - pagada: si total_pagado >= total_factura y total_factura > 0
// - pendiente: resto
if (factura.getEstadoPago() == EstadoPagoFactura.cancelada) {
@ -277,4 +394,90 @@ public class FacturacionService {
private static BigDecimal scale2(BigDecimal v) {
return (v == null ? BigDecimal.ZERO : v).setScale(2, RoundingMode.HALF_UP);
}
private String obtenerLineaFactura(PedidoLinea lineaPedido, Locale locale) {
Map<String, Object> specs = utils.getTextoPresupuesto(lineaPedido.getPresupuesto(), locale);
StringBuilder html = new StringBuilder();
html.append("<div class=\"specs-wrapper align-with-text \">")
.append("<div class=\"specs\">");
if (specs == null) {
return "<div></div>";
}
// 1) Líneas del presupuesto (HTML)
Object lineasObj = specs.get("lineas");
if (lineasObj instanceof List<?> lineasList) {
for (Object o : lineasList) {
if (!(o instanceof Map<?, ?> m))
continue;
Object descObj = m.get("descripcion");
String descripcionHtml = descObj != null ? descObj.toString() : "";
if (descripcionHtml.isBlank())
continue;
html.append("<div class=\"spec-row mb-1\">")
.append("<span class=\"spec-label\">")
.append(descripcionHtml) // OJO: esto es HTML (como th:utext)
.append("</span>")
.append("</div>");
}
}
// 2) Servicios adicionales (texto)
Object serviciosObj = specs.get("servicios");
String servicios = (serviciosObj != null) ? serviciosObj.toString().trim() : "";
if (!servicios.isBlank()) {
String label = messageSource.getMessage("pdf.servicios-adicionales", null, "Servicios adicionales", locale);
html.append("<div class=\"spec-row mb-1\">")
.append("<span>").append(escapeHtml(label)).append("</span>")
.append("<span class=\"spec-label\">").append(escapeHtml(servicios)).append("</span>")
.append("</div>");
}
// 3) Datos de maquetación (HTML)
Object datosMaqObj = specs.get("datosMaquetacion");
if (datosMaqObj != null && !datosMaqObj.toString().isBlank()) {
String label = messageSource.getMessage("pdf.datos-maquetacion", null, "Datos de maquetación:", locale);
html.append("<div class=\"spec-row mb-1\">")
.append("<span>").append(escapeHtml(label)).append("</span>")
.append("<span class=\"spec-label\">")
.append(datosMaqObj) // HTML (como th:utext)
.append("</span>")
.append("</div>");
}
// 4) Datos de marcapáginas (HTML)
Object datosMarcaObj = specs.get("datosMarcapaginas");
if (datosMarcaObj != null && !datosMarcaObj.toString().isBlank()) {
String label = messageSource.getMessage("pdf.datos-marcapaginas", null, "Datos de marcapáginas:", locale);
html.append("<div class=\"spec-row mb-1\">")
.append("<span>").append(escapeHtml(label)).append("</span>")
.append("<span class=\"spec-label\">")
.append(datosMarcaObj) // HTML (como th:utext)
.append("</span>")
.append("</div>");
}
html.append("</div></div>");
return html.toString();
}
/**
* Escape mínimo para texto plano (equivalente a th:text).
* No lo uses para fragmentos que ya son HTML (th:utext).
*/
private static String escapeHtml(String s) {
if (s == null)
return "";
return s.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;")
.replace("\"", "&quot;")
.replace("'", "&#39;");
}
}

View File

@ -3,6 +3,9 @@ package com.imprimelibros.erp.payments;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imprimelibros.erp.cart.Cart;
import com.imprimelibros.erp.cart.CartService;
import com.imprimelibros.erp.facturacion.SerieFactura;
import com.imprimelibros.erp.facturacion.TipoPago;
import com.imprimelibros.erp.facturacion.service.FacturacionService;
import com.imprimelibros.erp.payments.model.*;
import com.imprimelibros.erp.payments.repo.PaymentRepository;
import com.imprimelibros.erp.payments.repo.PaymentTransactionRepository;
@ -33,6 +36,7 @@ public class PaymentService {
private final ObjectMapper om = new ObjectMapper();
private final CartService cartService;
private final PedidoService pedidoService;
private final FacturacionService facturacionService;
public PaymentService(PaymentRepository payRepo,
PaymentTransactionRepository txRepo,
@ -40,7 +44,8 @@ public class PaymentService {
RedsysService redsysService,
WebhookEventRepository webhookEventRepo,
CartService cartService,
PedidoService pedidoService) {
PedidoService pedidoService,
FacturacionService facturacionService) {
this.payRepo = payRepo;
this.txRepo = txRepo;
this.refundRepo = refundRepo;
@ -48,6 +53,7 @@ public class PaymentService {
this.webhookEventRepo = webhookEventRepo;
this.cartService = cartService;
this.pedidoService = pedidoService;
this.facturacionService = facturacionService;
}
public Payment findFailedPaymentByOrderId(Long orderId) {
@ -253,6 +259,11 @@ public class PaymentService {
p.setCapturedAt(LocalDateTime.now());
pedidoService.setOrderAsPaid(p.getOrderId());
Pedido pedido = pedidoService.getPedidoById(p.getOrderId());
SerieFactura serie = facturacionService.getDefaultSerieFactura();
facturacionService.crearNuevaFacturaAuto(pedido, serie, notif.isBizum() ? TipoPago.tpv_bizum : TipoPago.tpv_tarjeta, locale);
} else {
p.setStatus(PaymentStatus.failed);
p.setFailedAt(LocalDateTime.now());
@ -452,6 +463,11 @@ public class PaymentService {
// 4) Procesar el pedido asociado al carrito (si existe) o marcar el pedido como pagado
if(p.getOrderId() != null) {
pedidoService.setOrderAsPaid(p.getOrderId());
Pedido pedido = pedidoService.getPedidoById(p.getOrderId());
SerieFactura serie = facturacionService.getDefaultSerieFactura();
facturacionService.crearNuevaFacturaAuto(pedido, serie, TipoPago.transferencia, locale);
}
/*else if (cartId != null) {
// Se procesa el pedido dejando el estado calculado en processOrder

View File

@ -122,27 +122,6 @@ public class PdfService {
model.put("titulo", presupuesto.getTitulo());
/*
* Map<String, Object> resumen = presupuestoService.getTextosResumen(
* presupuesto, null, model, model, null)
*/
model.put("lineas", List.of(
Map.of("descripcion", "Impresión interior B/N offset 80 g",
"meta", "300 páginas · tinta negra · papel 80 g",
"uds", 1000,
"precio", 2.15,
"dto", 0,
"importe", 2150.0),
Map.of("descripcion", "Cubierta color 300 g laminado mate",
"meta", "Lomo 15 mm · 4/0 · laminado mate",
"uds", 1000,
"precio", 0.38,
"dto", 5.0,
"importe", 361.0)));
model.put("servicios", List.of(
Map.of("descripcion", "Transporte península", "unidades", 1, "precio", 90.00)));
Map<String, Object> specs = utils.getTextoPresupuesto(presupuesto, locale);
model.put("specs", specs);

View File

@ -59,6 +59,12 @@ public class PedidoService {
this.messageSource = messageSource;
}
public Pedido getPedidoById(Long pedidoId) {
return pedidoRepository.findById(pedidoId).orElse(null);
}
@Transactional
public Pedido crearPedido(
Long cartId,