diff --git a/memberflow-api/libs/memberflow-data-1.0-SNAPSHOT.jar b/memberflow-api/libs/memberflow-data-1.0-SNAPSHOT.jar index ba35941..ec84b55 100644 Binary files a/memberflow-api/libs/memberflow-data-1.0-SNAPSHOT.jar and b/memberflow-api/libs/memberflow-data-1.0-SNAPSHOT.jar differ diff --git a/memberflow-api/src/main/java/com/denniseckerskorn/controllers/finance_management/PaymentController.java b/memberflow-api/src/main/java/com/denniseckerskorn/controllers/finance_management/PaymentController.java index a88a92b..a53b52f 100644 --- a/memberflow-api/src/main/java/com/denniseckerskorn/controllers/finance_management/PaymentController.java +++ b/memberflow-api/src/main/java/com/denniseckerskorn/controllers/finance_management/PaymentController.java @@ -1,6 +1,7 @@ package com.denniseckerskorn.controllers.finance_management; import com.denniseckerskorn.dtos.finance_management_dtos.PaymentDTO; +import com.denniseckerskorn.entities.finance.Invoice; import com.denniseckerskorn.entities.finance.Payment; import com.denniseckerskorn.exceptions.DuplicateEntityException; import com.denniseckerskorn.exceptions.EntityNotFoundException; @@ -29,18 +30,28 @@ public class PaymentController { @PostMapping("/create") @Operation(summary = "Create a new payment and mark invoice as PAID") - public ResponseEntity create(@Valid @RequestBody PaymentDTO dto) throws DuplicateEntityException { - Payment saved = paymentService.save(dto.toEntity()); + public ResponseEntity create(@Valid @RequestBody PaymentDTO dto) + throws DuplicateEntityException, EntityNotFoundException { + + Invoice invoice = paymentService.getInvoiceById(dto.getInvoiceId()); + Payment saved = paymentService.save(dto.toEntityWithInvoice(invoice)); + return new ResponseEntity<>(new PaymentDTO(saved), HttpStatus.CREATED); } + @PutMapping("/update") @Operation(summary = "Update an existing payment and adjust invoice status") - public ResponseEntity update(@Valid @RequestBody PaymentDTO dto) throws EntityNotFoundException, InvalidDataException { - Payment updated = paymentService.update(dto.toEntity()); + public ResponseEntity update(@Valid @RequestBody PaymentDTO dto) + throws EntityNotFoundException, InvalidDataException { + + Invoice invoice = paymentService.getInvoiceById(dto.getInvoiceId()); + Payment updated = paymentService.update(dto.toEntityWithInvoice(invoice)); + return new ResponseEntity<>(new PaymentDTO(updated), HttpStatus.OK); } + @GetMapping("/getById/{id}") @Operation(summary = "Get payment by ID") public ResponseEntity getById(@PathVariable Integer id) throws EntityNotFoundException, InvalidDataException { diff --git a/memberflow-api/src/main/java/com/denniseckerskorn/dtos/finance_management_dtos/PaymentDTO.java b/memberflow-api/src/main/java/com/denniseckerskorn/dtos/finance_management_dtos/PaymentDTO.java index f53606a..0690699 100644 --- a/memberflow-api/src/main/java/com/denniseckerskorn/dtos/finance_management_dtos/PaymentDTO.java +++ b/memberflow-api/src/main/java/com/denniseckerskorn/dtos/finance_management_dtos/PaymentDTO.java @@ -1,5 +1,6 @@ package com.denniseckerskorn.dtos.finance_management_dtos; +import com.denniseckerskorn.entities.finance.Invoice; import com.denniseckerskorn.entities.finance.Payment; import com.denniseckerskorn.enums.PaymentMethodValues; import com.denniseckerskorn.enums.StatusValues; @@ -27,7 +28,8 @@ public class PaymentDTO { @NotNull private StatusValues status; - public PaymentDTO() {} + public PaymentDTO() { + } public PaymentDTO(Payment entity) { this.id = entity.getId(); @@ -44,6 +46,9 @@ public class PaymentDTO { public Payment toEntity() { Payment payment = new Payment(); + if (this.id != null) { + payment.setId(this.id); + } payment.setId(this.id); payment.setPaymentDate(this.paymentDate); payment.setAmount(this.amount); @@ -52,6 +57,17 @@ public class PaymentDTO { return payment; } + public Payment toEntityWithInvoice(Invoice invoice) { + Payment payment = new Payment(); + payment.setPaymentDate(this.paymentDate); + payment.setAmount(this.amount); + payment.setPaymentMethod(this.paymentMethod); + payment.setStatus(this.status); + payment.setInvoice(invoice); + return payment; + } + + // Getters y setters... diff --git a/memberflow-data/src/main/java/com/denniseckerskorn/services/finance_services/PaymentService.java b/memberflow-data/src/main/java/com/denniseckerskorn/services/finance_services/PaymentService.java index e2626be..4fb78fe 100644 --- a/memberflow-data/src/main/java/com/denniseckerskorn/services/finance_services/PaymentService.java +++ b/memberflow-data/src/main/java/com/denniseckerskorn/services/finance_services/PaymentService.java @@ -47,15 +47,20 @@ public class PaymentService extends AbstractService { } payment.setInvoice(invoice); - invoice.setPayment(payment); + Payment savedPayment = super.save(payment); + + invoice.setPayment(savedPayment); invoice.setStatus(StatusValues.PAID); invoiceService.update(invoice); - return super.save(payment); + + return savedPayment; } + @Override + @Transactional public Payment update(Payment entity) throws EntityNotFoundException, InvalidDataException { logger.info("Updating payment: {}", entity); validate(entity); @@ -97,6 +102,7 @@ public class PaymentService extends AbstractService { } } + @Transactional private void updateInvoiceStatus(Payment payment) { Invoice invoice = payment.getInvoice(); invoice.setStatus(StatusValues.PAID); @@ -116,4 +122,9 @@ public class PaymentService extends AbstractService { return paymentRepository.findByInvoice_User_Id(userId); } + public Invoice getInvoiceById(Integer id) { + return invoiceService.findById(id); + } + + } diff --git a/memberflow-frontend/src/components/forms/PaymentForm.jsx b/memberflow-frontend/src/components/forms/PaymentForm.jsx index a86ec68..3b463d7 100644 --- a/memberflow-frontend/src/components/forms/PaymentForm.jsx +++ b/memberflow-frontend/src/components/forms/PaymentForm.jsx @@ -20,7 +20,9 @@ const PaymentForm = () => { const fetchInvoices = async (userId) => { try { const res = await api.get(`/invoices/getAllInvoicesByUserId/${userId}`); - const notPaid = res.data.filter((invoice) => invoice.status === "NOT_PAID"); + const notPaid = res.data.filter( + (invoice) => invoice.status === "NOT_PAID" + ); setInvoices(notPaid); } catch (err) { console.error(err); @@ -48,6 +50,19 @@ const PaymentForm = () => { return; } + const selectedInvoice = invoices.find( + (inv) => inv.id === parseInt(selectedInvoiceId) + ); + if (!selectedInvoice) { + setError("Factura no encontrada."); + return; + } + + if (parseFloat(amount) < selectedInvoice.total) { + setError("El importe pagado no puede ser menor al total de la factura."); + return; + } + try { await api.post("/payments/create", { invoiceId: parseInt(selectedInvoiceId), @@ -61,7 +76,7 @@ const PaymentForm = () => { setSelectedInvoiceId(""); setAmount(""); setPaymentMethod("CASH"); - fetchInvoices(selectedUserId); // actualizar facturas pendientes + fetchInvoices(selectedUserId); } catch (err) { console.error(err); setError("❌ Error al registrar el pago."); @@ -71,10 +86,14 @@ const PaymentForm = () => { return (
-

Registrar Pago

+

Registrar Pago de una Factura

- {students.map((s) => s.user ? ( @@ -96,13 +115,20 @@ const PaymentForm = () => { {invoices.map((inv) => ( ))} )} + {invoices.length === 0 && selectedUserId && ( +

+ No hay facturas pendientes de pago para este estudiante. +

+ )} + {selectedInvoiceId && ( <> @@ -121,15 +147,18 @@ const PaymentForm = () => { onChange={(e) => setPaymentMethod(e.target.value)} > - - - + + - diff --git a/memberflow-frontend/src/components/lists/PaymentList.jsx b/memberflow-frontend/src/components/lists/PaymentList.jsx index 3168e01..ea1d3a5 100644 --- a/memberflow-frontend/src/components/lists/PaymentList.jsx +++ b/memberflow-frontend/src/components/lists/PaymentList.jsx @@ -48,7 +48,7 @@ const PaymentList = () => { return (
-

Listado de Pagos

+

Listado de Facturas Pagadas por Estudiante