Fixed issues with invoice, payments creation and also added validation of amount
This commit is contained in:
parent
0aadef56ed
commit
ab3485984e
Binary file not shown.
|
|
@ -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<PaymentDTO> create(@Valid @RequestBody PaymentDTO dto) throws DuplicateEntityException {
|
||||
Payment saved = paymentService.save(dto.toEntity());
|
||||
public ResponseEntity<PaymentDTO> 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<PaymentDTO> update(@Valid @RequestBody PaymentDTO dto) throws EntityNotFoundException, InvalidDataException {
|
||||
Payment updated = paymentService.update(dto.toEntity());
|
||||
public ResponseEntity<PaymentDTO> 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<PaymentDTO> getById(@PathVariable Integer id) throws EntityNotFoundException, InvalidDataException {
|
||||
|
|
|
|||
|
|
@ -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...
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -47,15 +47,20 @@ public class PaymentService extends AbstractService<Payment, Integer> {
|
|||
}
|
||||
|
||||
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<Payment, Integer> {
|
|||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
private void updateInvoiceStatus(Payment payment) {
|
||||
Invoice invoice = payment.getInvoice();
|
||||
invoice.setStatus(StatusValues.PAID);
|
||||
|
|
@ -116,4 +122,9 @@ public class PaymentService extends AbstractService<Payment, Integer> {
|
|||
return paymentRepository.findByInvoice_User_Id(userId);
|
||||
}
|
||||
|
||||
public Invoice getInvoiceById(Integer id) {
|
||||
return invoiceService.findById(id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div className="content-area">
|
||||
<div className="card">
|
||||
<h2>Registrar Pago</h2>
|
||||
<h2>Registrar Pago de una Factura</h2>
|
||||
|
||||
<label>Seleccionar estudiante:</label>
|
||||
<select className="form-select" value={selectedUserId} onChange={handleStudentChange}>
|
||||
<select
|
||||
className="form-select"
|
||||
value={selectedUserId}
|
||||
onChange={handleStudentChange}
|
||||
>
|
||||
<option value="">-- Selecciona un estudiante --</option>
|
||||
{students.map((s) =>
|
||||
s.user ? (
|
||||
|
|
@ -96,13 +115,20 @@ const PaymentForm = () => {
|
|||
<option value="">-- Selecciona una factura --</option>
|
||||
{invoices.map((inv) => (
|
||||
<option key={inv.id} value={inv.id}>
|
||||
#{inv.id} - {new Date(inv.date).toLocaleDateString()} - Total: {inv.total.toFixed(2)} €
|
||||
#{inv.id} - {new Date(inv.date).toLocaleDateString()} - Total:{" "}
|
||||
{inv.total.toFixed(2)} €
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</>
|
||||
)}
|
||||
|
||||
{invoices.length === 0 && selectedUserId && (
|
||||
<p style={{ marginTop: "1rem", color: "gray" }}>
|
||||
No hay facturas pendientes de pago para este estudiante.
|
||||
</p>
|
||||
)}
|
||||
|
||||
{selectedInvoiceId && (
|
||||
<>
|
||||
<label>Importe pagado (€):</label>
|
||||
|
|
@ -121,15 +147,18 @@ const PaymentForm = () => {
|
|||
onChange={(e) => setPaymentMethod(e.target.value)}
|
||||
>
|
||||
<option value="CASH">Efectivo</option>
|
||||
<option value="CARD">Tarjeta</option>
|
||||
<option value="TRANSFER">Transferencia</option>
|
||||
<option value="BIZUM">Bizum</option>
|
||||
<option value="CREDIT_CARD">Tarjeta</option>
|
||||
<option value="BANK_TRANSFER">Transferencia</option>
|
||||
</select>
|
||||
|
||||
<ErrorMessage message={error} type="error" />
|
||||
<ErrorMessage message={success} type="success" />
|
||||
|
||||
<button className="btn btn-primary" style={{ marginTop: "1rem" }} onClick={handleSubmit}>
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
style={{ marginTop: "1rem" }}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
💳 Confirmar Pago
|
||||
</button>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ const PaymentList = () => {
|
|||
return (
|
||||
<div className="content-area">
|
||||
<div className="card">
|
||||
<h2>Listado de Pagos</h2>
|
||||
<h2>Listado de Facturas Pagadas por Estudiante</h2>
|
||||
|
||||
<label>Seleccionar estudiante:</label>
|
||||
<select className="form-select" value={selectedUserId} onChange={handleStudentChange}>
|
||||
|
|
|
|||
Loading…
Reference in New Issue