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;
|
package com.denniseckerskorn.controllers.finance_management;
|
||||||
|
|
||||||
import com.denniseckerskorn.dtos.finance_management_dtos.PaymentDTO;
|
import com.denniseckerskorn.dtos.finance_management_dtos.PaymentDTO;
|
||||||
|
import com.denniseckerskorn.entities.finance.Invoice;
|
||||||
import com.denniseckerskorn.entities.finance.Payment;
|
import com.denniseckerskorn.entities.finance.Payment;
|
||||||
import com.denniseckerskorn.exceptions.DuplicateEntityException;
|
import com.denniseckerskorn.exceptions.DuplicateEntityException;
|
||||||
import com.denniseckerskorn.exceptions.EntityNotFoundException;
|
import com.denniseckerskorn.exceptions.EntityNotFoundException;
|
||||||
|
|
@ -29,18 +30,28 @@ public class PaymentController {
|
||||||
|
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@Operation(summary = "Create a new payment and mark invoice as PAID")
|
@Operation(summary = "Create a new payment and mark invoice as PAID")
|
||||||
public ResponseEntity<PaymentDTO> create(@Valid @RequestBody PaymentDTO dto) throws DuplicateEntityException {
|
public ResponseEntity<PaymentDTO> create(@Valid @RequestBody PaymentDTO dto)
|
||||||
Payment saved = paymentService.save(dto.toEntity());
|
throws DuplicateEntityException, EntityNotFoundException {
|
||||||
|
|
||||||
|
Invoice invoice = paymentService.getInvoiceById(dto.getInvoiceId());
|
||||||
|
Payment saved = paymentService.save(dto.toEntityWithInvoice(invoice));
|
||||||
|
|
||||||
return new ResponseEntity<>(new PaymentDTO(saved), HttpStatus.CREATED);
|
return new ResponseEntity<>(new PaymentDTO(saved), HttpStatus.CREATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@PutMapping("/update")
|
@PutMapping("/update")
|
||||||
@Operation(summary = "Update an existing payment and adjust invoice status")
|
@Operation(summary = "Update an existing payment and adjust invoice status")
|
||||||
public ResponseEntity<PaymentDTO> update(@Valid @RequestBody PaymentDTO dto) throws EntityNotFoundException, InvalidDataException {
|
public ResponseEntity<PaymentDTO> update(@Valid @RequestBody PaymentDTO dto)
|
||||||
Payment updated = paymentService.update(dto.toEntity());
|
throws EntityNotFoundException, InvalidDataException {
|
||||||
|
|
||||||
|
Invoice invoice = paymentService.getInvoiceById(dto.getInvoiceId());
|
||||||
|
Payment updated = paymentService.update(dto.toEntityWithInvoice(invoice));
|
||||||
|
|
||||||
return new ResponseEntity<>(new PaymentDTO(updated), HttpStatus.OK);
|
return new ResponseEntity<>(new PaymentDTO(updated), HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/getById/{id}")
|
@GetMapping("/getById/{id}")
|
||||||
@Operation(summary = "Get payment by ID")
|
@Operation(summary = "Get payment by ID")
|
||||||
public ResponseEntity<PaymentDTO> getById(@PathVariable Integer id) throws EntityNotFoundException, InvalidDataException {
|
public ResponseEntity<PaymentDTO> getById(@PathVariable Integer id) throws EntityNotFoundException, InvalidDataException {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.denniseckerskorn.dtos.finance_management_dtos;
|
package com.denniseckerskorn.dtos.finance_management_dtos;
|
||||||
|
|
||||||
|
import com.denniseckerskorn.entities.finance.Invoice;
|
||||||
import com.denniseckerskorn.entities.finance.Payment;
|
import com.denniseckerskorn.entities.finance.Payment;
|
||||||
import com.denniseckerskorn.enums.PaymentMethodValues;
|
import com.denniseckerskorn.enums.PaymentMethodValues;
|
||||||
import com.denniseckerskorn.enums.StatusValues;
|
import com.denniseckerskorn.enums.StatusValues;
|
||||||
|
|
@ -27,7 +28,8 @@ public class PaymentDTO {
|
||||||
@NotNull
|
@NotNull
|
||||||
private StatusValues status;
|
private StatusValues status;
|
||||||
|
|
||||||
public PaymentDTO() {}
|
public PaymentDTO() {
|
||||||
|
}
|
||||||
|
|
||||||
public PaymentDTO(Payment entity) {
|
public PaymentDTO(Payment entity) {
|
||||||
this.id = entity.getId();
|
this.id = entity.getId();
|
||||||
|
|
@ -44,6 +46,9 @@ public class PaymentDTO {
|
||||||
|
|
||||||
public Payment toEntity() {
|
public Payment toEntity() {
|
||||||
Payment payment = new Payment();
|
Payment payment = new Payment();
|
||||||
|
if (this.id != null) {
|
||||||
|
payment.setId(this.id);
|
||||||
|
}
|
||||||
payment.setId(this.id);
|
payment.setId(this.id);
|
||||||
payment.setPaymentDate(this.paymentDate);
|
payment.setPaymentDate(this.paymentDate);
|
||||||
payment.setAmount(this.amount);
|
payment.setAmount(this.amount);
|
||||||
|
|
@ -52,6 +57,17 @@ public class PaymentDTO {
|
||||||
return payment;
|
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...
|
// Getters y setters...
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,15 +47,20 @@ public class PaymentService extends AbstractService<Payment, Integer> {
|
||||||
}
|
}
|
||||||
|
|
||||||
payment.setInvoice(invoice);
|
payment.setInvoice(invoice);
|
||||||
invoice.setPayment(payment);
|
|
||||||
|
|
||||||
|
Payment savedPayment = super.save(payment);
|
||||||
|
|
||||||
|
invoice.setPayment(savedPayment);
|
||||||
invoice.setStatus(StatusValues.PAID);
|
invoice.setStatus(StatusValues.PAID);
|
||||||
invoiceService.update(invoice);
|
invoiceService.update(invoice);
|
||||||
return super.save(payment);
|
|
||||||
|
return savedPayment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional
|
||||||
public Payment update(Payment entity) throws EntityNotFoundException, InvalidDataException {
|
public Payment update(Payment entity) throws EntityNotFoundException, InvalidDataException {
|
||||||
logger.info("Updating payment: {}", entity);
|
logger.info("Updating payment: {}", entity);
|
||||||
validate(entity);
|
validate(entity);
|
||||||
|
|
@ -97,6 +102,7 @@ public class PaymentService extends AbstractService<Payment, Integer> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
private void updateInvoiceStatus(Payment payment) {
|
private void updateInvoiceStatus(Payment payment) {
|
||||||
Invoice invoice = payment.getInvoice();
|
Invoice invoice = payment.getInvoice();
|
||||||
invoice.setStatus(StatusValues.PAID);
|
invoice.setStatus(StatusValues.PAID);
|
||||||
|
|
@ -116,4 +122,9 @@ public class PaymentService extends AbstractService<Payment, Integer> {
|
||||||
return paymentRepository.findByInvoice_User_Id(userId);
|
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) => {
|
const fetchInvoices = async (userId) => {
|
||||||
try {
|
try {
|
||||||
const res = await api.get(`/invoices/getAllInvoicesByUserId/${userId}`);
|
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);
|
setInvoices(notPaid);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
@ -48,6 +50,19 @@ const PaymentForm = () => {
|
||||||
return;
|
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 {
|
try {
|
||||||
await api.post("/payments/create", {
|
await api.post("/payments/create", {
|
||||||
invoiceId: parseInt(selectedInvoiceId),
|
invoiceId: parseInt(selectedInvoiceId),
|
||||||
|
|
@ -61,7 +76,7 @@ const PaymentForm = () => {
|
||||||
setSelectedInvoiceId("");
|
setSelectedInvoiceId("");
|
||||||
setAmount("");
|
setAmount("");
|
||||||
setPaymentMethod("CASH");
|
setPaymentMethod("CASH");
|
||||||
fetchInvoices(selectedUserId); // actualizar facturas pendientes
|
fetchInvoices(selectedUserId);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
setError("❌ Error al registrar el pago.");
|
setError("❌ Error al registrar el pago.");
|
||||||
|
|
@ -71,10 +86,14 @@ const PaymentForm = () => {
|
||||||
return (
|
return (
|
||||||
<div className="content-area">
|
<div className="content-area">
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<h2>Registrar Pago</h2>
|
<h2>Registrar Pago de una Factura</h2>
|
||||||
|
|
||||||
<label>Seleccionar estudiante:</label>
|
<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>
|
<option value="">-- Selecciona un estudiante --</option>
|
||||||
{students.map((s) =>
|
{students.map((s) =>
|
||||||
s.user ? (
|
s.user ? (
|
||||||
|
|
@ -96,13 +115,20 @@ const PaymentForm = () => {
|
||||||
<option value="">-- Selecciona una factura --</option>
|
<option value="">-- Selecciona una factura --</option>
|
||||||
{invoices.map((inv) => (
|
{invoices.map((inv) => (
|
||||||
<option key={inv.id} value={inv.id}>
|
<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>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{invoices.length === 0 && selectedUserId && (
|
||||||
|
<p style={{ marginTop: "1rem", color: "gray" }}>
|
||||||
|
No hay facturas pendientes de pago para este estudiante.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
{selectedInvoiceId && (
|
{selectedInvoiceId && (
|
||||||
<>
|
<>
|
||||||
<label>Importe pagado (€):</label>
|
<label>Importe pagado (€):</label>
|
||||||
|
|
@ -121,15 +147,18 @@ const PaymentForm = () => {
|
||||||
onChange={(e) => setPaymentMethod(e.target.value)}
|
onChange={(e) => setPaymentMethod(e.target.value)}
|
||||||
>
|
>
|
||||||
<option value="CASH">Efectivo</option>
|
<option value="CASH">Efectivo</option>
|
||||||
<option value="CARD">Tarjeta</option>
|
<option value="CREDIT_CARD">Tarjeta</option>
|
||||||
<option value="TRANSFER">Transferencia</option>
|
<option value="BANK_TRANSFER">Transferencia</option>
|
||||||
<option value="BIZUM">Bizum</option>
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<ErrorMessage message={error} type="error" />
|
<ErrorMessage message={error} type="error" />
|
||||||
<ErrorMessage message={success} type="success" />
|
<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
|
💳 Confirmar Pago
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ const PaymentList = () => {
|
||||||
return (
|
return (
|
||||||
<div className="content-area">
|
<div className="content-area">
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<h2>Listado de Pagos</h2>
|
<h2>Listado de Facturas Pagadas por Estudiante</h2>
|
||||||
|
|
||||||
<label>Seleccionar estudiante:</label>
|
<label>Seleccionar estudiante:</label>
|
||||||
<select className="form-select" value={selectedUserId} onChange={handleStudentChange}>
|
<select className="form-select" value={selectedUserId} onChange={handleStudentChange}>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue