Some adjustments and added finance module to API, started createinvoice in frontend
This commit is contained in:
parent
7c1adbe2b7
commit
6177976a6f
|
|
@ -60,6 +60,11 @@ public class SecurityConfig {
|
|||
.requestMatchers("/api/v1/assistances/**").hasAnyAuthority("FULL_ACCESS", "MANAGE_STUDENTS")
|
||||
.requestMatchers("/api/v1/training-sessions/**").hasAnyAuthority("FULL_ACCESS", "MANAGE_STUDENTS")
|
||||
.requestMatchers("/api/v1/training-groups/**").hasAnyAuthority("FULL_ACCESS", "MANAGE_STUDENTS")
|
||||
.requestMatchers("/api/v1/invoices/**").hasAnyAuthority("FULL_ACCESS", "MANAGE_STUDENTS")
|
||||
.requestMatchers("/api/v1/invoice-lines/**").hasAnyAuthority("FULL_ACCESS", "MANAGE_STUDENTS")
|
||||
.requestMatchers("/api/v1/payments/**").hasAnyAuthority("FULL_ACCESS", "MANAGE_STUDENTS")
|
||||
.requestMatchers("/api/v1/products-services/**").hasAnyAuthority("FULL_ACCESS", "MANAGE_STUDENTS")
|
||||
.requestMatchers("/api/v1/iva-types/**").hasAnyAuthority("FULL_ACCESS", "MANAGE_STUDENTS")
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
package com.denniseckerskorn.controllers.finance_management;
|
||||
|
||||
import com.denniseckerskorn.dtos.finance_management_dtos.IVATypeDTO;
|
||||
import com.denniseckerskorn.entities.finance.IVAType;
|
||||
import com.denniseckerskorn.exceptions.DuplicateEntityException;
|
||||
import com.denniseckerskorn.exceptions.EntityNotFoundException;
|
||||
import com.denniseckerskorn.exceptions.InvalidDataException;
|
||||
import com.denniseckerskorn.services.finance_services.IVATypeService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/iva-types")
|
||||
@Tag(name = "IVA Types", description = "Operations related to IVA type management")
|
||||
public class IVATypeController {
|
||||
|
||||
private final IVATypeService ivaTypeService;
|
||||
|
||||
public IVATypeController(IVATypeService ivaTypeService) {
|
||||
this.ivaTypeService = ivaTypeService;
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "Create a new IVA type")
|
||||
public ResponseEntity<IVATypeDTO> create(@Valid @RequestBody IVATypeDTO dto) throws DuplicateEntityException {
|
||||
IVAType saved = ivaTypeService.save(dto.toEntity());
|
||||
return new ResponseEntity<>(new IVATypeDTO(saved), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "Update an existing IVA type")
|
||||
public ResponseEntity<IVATypeDTO> update(@Valid @RequestBody IVATypeDTO dto) throws EntityNotFoundException, InvalidDataException {
|
||||
IVAType updated = ivaTypeService.update(dto.toEntity());
|
||||
return new ResponseEntity<>(new IVATypeDTO(updated), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/getById/{id}")
|
||||
@Operation(summary = "Get IVA type by ID")
|
||||
public ResponseEntity<IVATypeDTO> getById(@PathVariable Integer id) throws EntityNotFoundException, InvalidDataException {
|
||||
IVAType entity = ivaTypeService.findById(id);
|
||||
return new ResponseEntity<>(new IVATypeDTO(entity), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/getAll")
|
||||
@Operation(summary = "Get all IVA types")
|
||||
public ResponseEntity<List<IVATypeDTO>> getAll() {
|
||||
List<IVATypeDTO> dtos = ivaTypeService.findAll()
|
||||
.stream().map(IVATypeDTO::new).collect(Collectors.toList());
|
||||
return new ResponseEntity<>(dtos, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@DeleteMapping("/deleteById/{id}")
|
||||
@Operation(summary = "Delete IVA type by ID (if not in use)")
|
||||
public ResponseEntity<Void> delete(@PathVariable Integer id) throws EntityNotFoundException, InvalidDataException {
|
||||
ivaTypeService.deleteById(id);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.denniseckerskorn.controllers.finance_management;
|
||||
|
||||
|
||||
import com.denniseckerskorn.dtos.finance_management_dtos.InvoiceDTO;
|
||||
import com.denniseckerskorn.entities.finance.Invoice;
|
||||
import com.denniseckerskorn.entities.finance.InvoiceLine;
|
||||
import com.denniseckerskorn.exceptions.DuplicateEntityException;
|
||||
import com.denniseckerskorn.exceptions.EntityNotFoundException;
|
||||
import com.denniseckerskorn.exceptions.InvalidDataException;
|
||||
import com.denniseckerskorn.services.finance_services.InvoiceService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/invoices")
|
||||
@Tag(name = "Invoices", description = "Operations related to invoice management")
|
||||
public class InvoiceController {
|
||||
|
||||
private final InvoiceService invoiceService;
|
||||
|
||||
public InvoiceController(InvoiceService invoiceService) {
|
||||
this.invoiceService = invoiceService;
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "Create a new invoice")
|
||||
public ResponseEntity<InvoiceDTO> createInvoice(@Valid @RequestBody InvoiceDTO dto) throws DuplicateEntityException {
|
||||
Invoice saved = invoiceService.save(dto.toEntity());
|
||||
return new ResponseEntity<>(new InvoiceDTO(saved), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "Update an existing invoice")
|
||||
public ResponseEntity<InvoiceDTO> updateInvoice(@Valid @RequestBody InvoiceDTO dto) throws EntityNotFoundException, InvalidDataException {
|
||||
Invoice updated = invoiceService.update(dto.toEntity());
|
||||
return new ResponseEntity<>(new InvoiceDTO(updated), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/getById/{id}")
|
||||
@Operation(summary = "Get invoice by ID")
|
||||
public ResponseEntity<InvoiceDTO> getInvoiceById(@PathVariable Integer id) throws EntityNotFoundException, InvalidDataException {
|
||||
Invoice invoice = invoiceService.findById(id);
|
||||
return new ResponseEntity<>(new InvoiceDTO(invoice), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/getAll")
|
||||
@Operation(summary = "Get all invoices")
|
||||
public ResponseEntity<List<InvoiceDTO>> getAllInvoices() {
|
||||
List<InvoiceDTO> dtos = invoiceService.findAll()
|
||||
.stream().map(InvoiceDTO::new).collect(Collectors.toList());
|
||||
return new ResponseEntity<>(dtos, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@DeleteMapping("/deleteById/{id}")
|
||||
@Operation(summary = "Delete invoice by ID")
|
||||
public ResponseEntity<Void> deleteInvoice(@PathVariable Integer id) throws EntityNotFoundException, InvalidDataException {
|
||||
invoiceService.deleteById(id);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@GetMapping("/getAllInvoicesByUserId/{userId}")
|
||||
@Operation(summary = "Get all invoices by user ID")
|
||||
public ResponseEntity<List<InvoiceDTO>> getInvoicesByUserId(@PathVariable Integer userId) throws InvalidDataException {
|
||||
List<InvoiceDTO> dtos = invoiceService.findAllInvoicesByUserId(userId)
|
||||
.stream().map(InvoiceDTO::new).collect(Collectors.toList());
|
||||
return new ResponseEntity<>(dtos, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PostMapping("/addLinesByInvoiceId/{invoiceId}")
|
||||
@Operation(summary = "Add a line to an invoice by invoice ID")
|
||||
public ResponseEntity<Void> addLineToInvoice(@PathVariable Integer invoiceId, @RequestBody @Valid InvoiceLine line) {
|
||||
invoiceService.addLineToInvoiceById(invoiceId, line);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@DeleteMapping("/removeLineFromInvoiceById/{invoiceId}")
|
||||
@Operation(summary = "Remove a line from an invoice by IDs")
|
||||
public ResponseEntity<Void> removeLineFromInvoice(@PathVariable Integer invoiceId, @PathVariable Integer lineId) {
|
||||
invoiceService.removeLineFromInvoiceById(invoiceId, lineId);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@PutMapping("/recalculateTotalOfInvoiceById/{invoiceId}")
|
||||
@Operation(summary = "Recalculate the total of an invoice")
|
||||
public ResponseEntity<Void> recalculateTotal(@PathVariable Integer invoiceId) throws EntityNotFoundException, InvalidDataException {
|
||||
Invoice invoice = invoiceService.findById(invoiceId);
|
||||
invoiceService.recalculateTotal(invoice);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@DeleteMapping("/clearAllLinesFromInvoiceById/{invoiceId}")
|
||||
@Operation(summary = "Clear all invoice lines from an invoice")
|
||||
public ResponseEntity<Void> clearInvoiceLines(@PathVariable Integer invoiceId) throws EntityNotFoundException, InvalidDataException {
|
||||
Invoice invoice = invoiceService.findById(invoiceId);
|
||||
invoiceService.clearInvoiceLines(invoice);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package com.denniseckerskorn.controllers.finance_management;
|
||||
|
||||
import com.denniseckerskorn.dtos.finance_management_dtos.InvoiceLineDTO;
|
||||
import com.denniseckerskorn.entities.finance.InvoiceLine;
|
||||
import com.denniseckerskorn.exceptions.DuplicateEntityException;
|
||||
import com.denniseckerskorn.exceptions.EntityNotFoundException;
|
||||
import com.denniseckerskorn.exceptions.InvalidDataException;
|
||||
import com.denniseckerskorn.services.finance_services.InvoiceLineService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* InvoiceLineController handles operations related to invoice lines (items in invoices).
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/invoice-lines")
|
||||
@Tag(name = "Invoice Lines", description = "Operations related to invoice lines")
|
||||
public class InvoiceLineController {
|
||||
|
||||
private final InvoiceLineService invoiceLineService;
|
||||
|
||||
public InvoiceLineController(InvoiceLineService invoiceLineService) {
|
||||
this.invoiceLineService = invoiceLineService;
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "Create a new invoice line")
|
||||
public ResponseEntity<InvoiceLineDTO> create(@Valid @RequestBody InvoiceLineDTO dto) throws DuplicateEntityException {
|
||||
InvoiceLine saved = invoiceLineService.save(dto.toEntity());
|
||||
return new ResponseEntity<>(new InvoiceLineDTO(saved), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "Update an existing invoice line")
|
||||
public ResponseEntity<InvoiceLineDTO> update(@Valid @RequestBody InvoiceLineDTO dto) throws InvalidDataException, EntityNotFoundException {
|
||||
InvoiceLine updated = invoiceLineService.update(dto.toEntity());
|
||||
return new ResponseEntity<>(new InvoiceLineDTO(updated), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/getById/{id}")
|
||||
@Operation(summary = "Get invoice line by ID")
|
||||
public ResponseEntity<InvoiceLineDTO> getById(@PathVariable Integer id) throws InvalidDataException, EntityNotFoundException {
|
||||
InvoiceLine line = invoiceLineService.findById(id);
|
||||
return new ResponseEntity<>(new InvoiceLineDTO(line), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/getAll")
|
||||
@Operation(summary = "Get all invoice lines")
|
||||
public ResponseEntity<List<InvoiceLineDTO>> getAll() {
|
||||
List<InvoiceLineDTO> dtos = invoiceLineService.findAll()
|
||||
.stream().map(InvoiceLineDTO::new).collect(Collectors.toList());
|
||||
return new ResponseEntity<>(dtos, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@DeleteMapping("/deleteById/{id}")
|
||||
@Operation(summary = "Delete invoice line by ID")
|
||||
public ResponseEntity<Void> delete(@PathVariable Integer id) throws InvalidDataException, EntityNotFoundException {
|
||||
invoiceLineService.deleteById(id);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package com.denniseckerskorn.controllers.finance_management;
|
||||
|
||||
import com.denniseckerskorn.dtos.finance_management_dtos.PaymentDTO;
|
||||
import com.denniseckerskorn.entities.finance.Payment;
|
||||
import com.denniseckerskorn.exceptions.DuplicateEntityException;
|
||||
import com.denniseckerskorn.exceptions.EntityNotFoundException;
|
||||
import com.denniseckerskorn.exceptions.InvalidDataException;
|
||||
import com.denniseckerskorn.services.finance_services.PaymentService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/payments")
|
||||
@Tag(name = "Payments", description = "Operations related to payment management")
|
||||
public class PaymentController {
|
||||
|
||||
private final PaymentService paymentService;
|
||||
|
||||
public PaymentController(PaymentService paymentService) {
|
||||
this.paymentService = paymentService;
|
||||
}
|
||||
|
||||
@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());
|
||||
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());
|
||||
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 {
|
||||
Payment payment = paymentService.findById(id);
|
||||
return new ResponseEntity<>(new PaymentDTO(payment), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/getAll")
|
||||
@Operation(summary = "Get all payments")
|
||||
public ResponseEntity<List<PaymentDTO>> getAll() {
|
||||
List<PaymentDTO> dtos = paymentService.findAll()
|
||||
.stream().map(PaymentDTO::new).collect(Collectors.toList());
|
||||
return new ResponseEntity<>(dtos, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@DeleteMapping("/deleteById/{id}")
|
||||
@Operation(summary = "Remove a payment and set invoice status to NOT_PAID")
|
||||
public ResponseEntity<Void> removePayment(@PathVariable Integer id) throws EntityNotFoundException, InvalidDataException {
|
||||
paymentService.removePayment(id);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package com.denniseckerskorn.controllers.finance_management;
|
||||
|
||||
import com.denniseckerskorn.dtos.finance_management_dtos.ProductServiceDTO;
|
||||
import com.denniseckerskorn.entities.finance.ProductService;
|
||||
import com.denniseckerskorn.exceptions.DuplicateEntityException;
|
||||
import com.denniseckerskorn.exceptions.EntityNotFoundException;
|
||||
import com.denniseckerskorn.exceptions.InvalidDataException;
|
||||
import com.denniseckerskorn.services.finance_services.ProductServiceService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/products-services")
|
||||
@Tag(name = "Product Services", description = "Operations related to product/service management")
|
||||
public class ProductServiceController {
|
||||
|
||||
private final ProductServiceService productServiceService;
|
||||
|
||||
public ProductServiceController(ProductServiceService productServiceService) {
|
||||
this.productServiceService = productServiceService;
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "Create a new product/service")
|
||||
public ResponseEntity<ProductServiceDTO> create(@Valid @RequestBody ProductServiceDTO dto) throws DuplicateEntityException {
|
||||
ProductService saved = productServiceService.save(dto.toEntity());
|
||||
return new ResponseEntity<>(new ProductServiceDTO(saved), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "Update an existing product/service")
|
||||
public ResponseEntity<ProductServiceDTO> update(@Valid @RequestBody ProductServiceDTO dto) throws EntityNotFoundException, InvalidDataException {
|
||||
ProductService updated = productServiceService.update(dto.toEntity());
|
||||
return new ResponseEntity<>(new ProductServiceDTO(updated), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/getById/{id}")
|
||||
@Operation(summary = "Get product/service by ID")
|
||||
public ResponseEntity<ProductServiceDTO> getById(@PathVariable Integer id) throws EntityNotFoundException, InvalidDataException {
|
||||
ProductService entity = productServiceService.findById(id);
|
||||
return new ResponseEntity<>(new ProductServiceDTO(entity), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/getAll")
|
||||
@Operation(summary = "Get all products/services")
|
||||
public ResponseEntity<List<ProductServiceDTO>> getAll() {
|
||||
List<ProductServiceDTO> dtos = productServiceService.findAll()
|
||||
.stream().map(ProductServiceDTO::new).collect(Collectors.toList());
|
||||
return new ResponseEntity<>(dtos, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@DeleteMapping("/deleteById/{id}")
|
||||
@Operation(summary = "Delete product/service by ID")
|
||||
public ResponseEntity<Void> delete(@PathVariable Integer id) throws EntityNotFoundException, InvalidDataException {
|
||||
productServiceService.deleteById(id);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,6 @@ import java.time.LocalDateTime;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
//TODO: test
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/admins")
|
||||
@Tag(name = "Administrator Management", description = "Operations related to administrator management")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
package com.denniseckerskorn.dtos.finance_management_dtos;
|
||||
|
||||
import com.denniseckerskorn.entities.finance.IVAType;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class IVATypeDTO {
|
||||
|
||||
private Integer id;
|
||||
|
||||
@NotNull
|
||||
private BigDecimal percentage;
|
||||
|
||||
private String description;
|
||||
|
||||
public IVATypeDTO() {}
|
||||
|
||||
public IVATypeDTO(IVAType entity) {
|
||||
this.id = entity.getId();
|
||||
this.percentage = entity.getPercentage();
|
||||
this.description = entity.getDescription();
|
||||
}
|
||||
|
||||
public static IVATypeDTO fromEntity(IVAType entity) {
|
||||
return new IVATypeDTO(entity);
|
||||
}
|
||||
|
||||
public IVAType toEntity() {
|
||||
IVAType iva = new IVAType();
|
||||
iva.setId(this.id);
|
||||
iva.setPercentage(this.percentage);
|
||||
iva.setDescription(this.description);
|
||||
return iva;
|
||||
}
|
||||
|
||||
// Getters y setters...
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public BigDecimal getPercentage() {
|
||||
return percentage;
|
||||
}
|
||||
|
||||
public void setPercentage(BigDecimal percentage) {
|
||||
this.percentage = percentage;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
package com.denniseckerskorn.dtos.finance_management_dtos;
|
||||
|
||||
import com.denniseckerskorn.entities.finance.Invoice;
|
||||
import com.denniseckerskorn.enums.StatusValues;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class InvoiceDTO {
|
||||
|
||||
private Integer id;
|
||||
|
||||
@NotNull
|
||||
private Integer userId;
|
||||
|
||||
@NotNull
|
||||
private LocalDateTime date;
|
||||
|
||||
@NotNull
|
||||
private BigDecimal total;
|
||||
|
||||
@NotNull
|
||||
private StatusValues status;
|
||||
|
||||
private Integer paymentId;
|
||||
|
||||
private Set<Integer> invoiceLineIds;
|
||||
|
||||
public InvoiceDTO() {
|
||||
}
|
||||
|
||||
public InvoiceDTO(Invoice invoice) {
|
||||
this.id = invoice.getId();
|
||||
this.userId = invoice.getUser() != null ? invoice.getUser().getId() : null;
|
||||
this.date = invoice.getDate();
|
||||
this.total = invoice.getTotal();
|
||||
this.status = invoice.getStatus();
|
||||
this.paymentId = invoice.getPayment() != null ? invoice.getPayment().getId() : null;
|
||||
this.invoiceLineIds = invoice.getInvoiceLines()
|
||||
.stream()
|
||||
.map(line -> line.getId())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static InvoiceDTO fromEntity(Invoice invoice) {
|
||||
return new InvoiceDTO(invoice);
|
||||
}
|
||||
|
||||
public Invoice toEntity() {
|
||||
Invoice invoice = new Invoice();
|
||||
invoice.setId(this.id);
|
||||
invoice.setDate(this.date);
|
||||
invoice.setTotal(this.total);
|
||||
invoice.setStatus(this.status);
|
||||
return invoice;
|
||||
}
|
||||
|
||||
// Getters y setters (puedes generarlos automáticamente)
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Integer userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public LocalDateTime getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDateTime date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public BigDecimal getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(BigDecimal total) {
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public StatusValues getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(StatusValues status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Integer getPaymentId() {
|
||||
return paymentId;
|
||||
}
|
||||
|
||||
public void setPaymentId(Integer paymentId) {
|
||||
this.paymentId = paymentId;
|
||||
}
|
||||
|
||||
public Set<Integer> getInvoiceLineIds() {
|
||||
return invoiceLineIds;
|
||||
}
|
||||
|
||||
public void setInvoiceLineIds(Set<Integer> invoiceLineIds) {
|
||||
this.invoiceLineIds = invoiceLineIds;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
package com.denniseckerskorn.dtos.finance_management_dtos;
|
||||
|
||||
import com.denniseckerskorn.entities.finance.InvoiceLine;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class InvoiceLineDTO {
|
||||
|
||||
private Integer id;
|
||||
|
||||
@NotNull
|
||||
private Integer invoiceId;
|
||||
|
||||
@NotNull
|
||||
private Integer productServiceId;
|
||||
|
||||
private String description;
|
||||
|
||||
@NotNull
|
||||
private Integer quantity;
|
||||
|
||||
@NotNull
|
||||
private BigDecimal unitPrice;
|
||||
|
||||
private BigDecimal subtotal;
|
||||
|
||||
public InvoiceLineDTO() {}
|
||||
|
||||
public InvoiceLineDTO(InvoiceLine entity) {
|
||||
this.id = entity.getId();
|
||||
this.invoiceId = entity.getInvoice() != null ? entity.getInvoice().getId() : null;
|
||||
this.productServiceId = entity.getProductService() != null ? entity.getProductService().getId() : null;
|
||||
this.description = entity.getDescription();
|
||||
this.quantity = entity.getQuantity();
|
||||
this.unitPrice = entity.getUnitPrice();
|
||||
this.subtotal = entity.getSubtotal();
|
||||
}
|
||||
|
||||
public static InvoiceLineDTO fromEntity(InvoiceLine entity) {
|
||||
return new InvoiceLineDTO(entity);
|
||||
}
|
||||
|
||||
public InvoiceLine toEntity() {
|
||||
InvoiceLine entity = new InvoiceLine();
|
||||
entity.setId(this.id);
|
||||
entity.setDescription(this.description);
|
||||
entity.setQuantity(this.quantity);
|
||||
entity.setUnitPrice(this.unitPrice);
|
||||
entity.setSubtotal(this.subtotal);
|
||||
return entity;
|
||||
}
|
||||
|
||||
// Getters y setters...
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getInvoiceId() {
|
||||
return invoiceId;
|
||||
}
|
||||
|
||||
public void setInvoiceId(Integer invoiceId) {
|
||||
this.invoiceId = invoiceId;
|
||||
}
|
||||
|
||||
public Integer getProductServiceId() {
|
||||
return productServiceId;
|
||||
}
|
||||
|
||||
public void setProductServiceId(Integer productServiceId) {
|
||||
this.productServiceId = productServiceId;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Integer getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(Integer quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public BigDecimal getUnitPrice() {
|
||||
return unitPrice;
|
||||
}
|
||||
|
||||
public void setUnitPrice(BigDecimal unitPrice) {
|
||||
this.unitPrice = unitPrice;
|
||||
}
|
||||
|
||||
public BigDecimal getSubtotal() {
|
||||
return subtotal;
|
||||
}
|
||||
|
||||
public void setSubtotal(BigDecimal subtotal) {
|
||||
this.subtotal = subtotal;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.denniseckerskorn.dtos.finance_management_dtos;
|
||||
|
||||
import com.denniseckerskorn.entities.finance.Payment;
|
||||
import com.denniseckerskorn.enums.PaymentMethodValues;
|
||||
import com.denniseckerskorn.enums.StatusValues;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class PaymentDTO {
|
||||
|
||||
private Integer id;
|
||||
|
||||
@NotNull
|
||||
private Integer invoiceId;
|
||||
|
||||
@NotNull
|
||||
private LocalDateTime paymentDate;
|
||||
|
||||
@NotNull
|
||||
private BigDecimal amount;
|
||||
|
||||
@NotNull
|
||||
private PaymentMethodValues paymentMethod;
|
||||
|
||||
@NotNull
|
||||
private StatusValues status;
|
||||
|
||||
public PaymentDTO() {}
|
||||
|
||||
public PaymentDTO(Payment entity) {
|
||||
this.id = entity.getId();
|
||||
this.invoiceId = entity.getInvoice() != null ? entity.getInvoice().getId() : null;
|
||||
this.paymentDate = entity.getPaymentDate();
|
||||
this.amount = entity.getAmount();
|
||||
this.paymentMethod = entity.getPaymentMethod();
|
||||
this.status = entity.getStatus();
|
||||
}
|
||||
|
||||
public static PaymentDTO fromEntity(Payment entity) {
|
||||
return new PaymentDTO(entity);
|
||||
}
|
||||
|
||||
public Payment toEntity() {
|
||||
Payment payment = new Payment();
|
||||
payment.setId(this.id);
|
||||
payment.setPaymentDate(this.paymentDate);
|
||||
payment.setAmount(this.amount);
|
||||
payment.setPaymentMethod(this.paymentMethod);
|
||||
payment.setStatus(this.status);
|
||||
return payment;
|
||||
}
|
||||
|
||||
// Getters y setters...
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getInvoiceId() {
|
||||
return invoiceId;
|
||||
}
|
||||
|
||||
public void setInvoiceId(Integer invoiceId) {
|
||||
this.invoiceId = invoiceId;
|
||||
}
|
||||
|
||||
public LocalDateTime getPaymentDate() {
|
||||
return paymentDate;
|
||||
}
|
||||
|
||||
public void setPaymentDate(LocalDateTime paymentDate) {
|
||||
this.paymentDate = paymentDate;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public PaymentMethodValues getPaymentMethod() {
|
||||
return paymentMethod;
|
||||
}
|
||||
|
||||
public void setPaymentMethod(PaymentMethodValues paymentMethod) {
|
||||
this.paymentMethod = paymentMethod;
|
||||
}
|
||||
|
||||
public StatusValues getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(StatusValues status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
package com.denniseckerskorn.dtos.finance_management_dtos;
|
||||
|
||||
import com.denniseckerskorn.entities.finance.ProductService;
|
||||
import com.denniseckerskorn.enums.StatusValues;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class ProductServiceDTO {
|
||||
|
||||
private Integer id;
|
||||
|
||||
@NotNull
|
||||
private Integer ivaTypeId;
|
||||
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
@NotNull
|
||||
private BigDecimal price;
|
||||
|
||||
@NotNull
|
||||
private String type;
|
||||
|
||||
@NotNull
|
||||
private StatusValues status;
|
||||
|
||||
public ProductServiceDTO() {}
|
||||
|
||||
public ProductServiceDTO(ProductService entity) {
|
||||
this.id = entity.getId();
|
||||
this.ivaTypeId = entity.getIvaType() != null ? entity.getIvaType().getId() : null;
|
||||
this.name = entity.getName();
|
||||
this.description = entity.getDescription();
|
||||
this.price = entity.getPrice();
|
||||
this.type = entity.getType();
|
||||
this.status = entity.getStatus();
|
||||
}
|
||||
|
||||
public static ProductServiceDTO fromEntity(ProductService entity) {
|
||||
return new ProductServiceDTO(entity);
|
||||
}
|
||||
|
||||
public ProductService toEntity() {
|
||||
ProductService ps = new ProductService();
|
||||
ps.setId(this.id);
|
||||
ps.setName(this.name);
|
||||
ps.setDescription(this.description);
|
||||
ps.setPrice(this.price);
|
||||
ps.setType(this.type);
|
||||
ps.setStatus(this.status);
|
||||
return ps;
|
||||
}
|
||||
|
||||
// Getters y setters...
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getIvaTypeId() {
|
||||
return ivaTypeId;
|
||||
}
|
||||
|
||||
public void setIvaTypeId(Integer ivaTypeId) {
|
||||
this.ivaTypeId = ivaTypeId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public BigDecimal getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(BigDecimal price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public StatusValues getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(StatusValues status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,5 +2,6 @@
|
|||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import InvoiceLineItem from "./InvoiceLineItem";
|
||||
import api from "../../api/axiosConfig";
|
||||
|
||||
const InvoiceForm = () => {
|
||||
const [students, setStudents] = useState([]);
|
||||
const [userId, setUserId] = useState("");
|
||||
const [date, setDate] = useState(new Date().toISOString().slice(0, 16));
|
||||
const [lines, setLines] = useState([]);
|
||||
const [products, setProducts] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
api.get("/students/getAll").then((res) => setStudents(res.data));
|
||||
|
||||
api.get("/products-services/getAll").then((res) => setProducts(res.data));
|
||||
}, []);
|
||||
|
||||
const addLine = () => {
|
||||
setLines([...lines, { productServiceId: "", quantity: 1 }]);
|
||||
};
|
||||
|
||||
const updateLine = (index, updatedLine) => {
|
||||
const newLines = [...lines];
|
||||
newLines[index] = updatedLine;
|
||||
setLines(newLines);
|
||||
};
|
||||
|
||||
const removeLine = (index) => {
|
||||
setLines(lines.filter((_, i) => i !== index));
|
||||
};
|
||||
|
||||
const createInvoice = async () => {
|
||||
if (!userId || lines.length === 0) {
|
||||
alert("Selecciona un estudiante y al menos un producto.");
|
||||
return;
|
||||
}
|
||||
|
||||
const invoiceRes = await api.post("/invoices/create", {
|
||||
user: { id: parseInt(userId) },
|
||||
date,
|
||||
total: 0,
|
||||
status: "NOT_PAID",
|
||||
invoiceLineIds: [],
|
||||
});
|
||||
|
||||
const invoice = invoiceRes.data;
|
||||
|
||||
for (const line of lines) {
|
||||
const product = products.find(
|
||||
(p) => p.id === parseInt(line.productServiceId)
|
||||
);
|
||||
const subtotal = product.price * line.quantity;
|
||||
|
||||
await api.post(`/invoices/addLinesByInvoiceId/${invoice.id}`, {
|
||||
productServiceId: parseInt(line.productServiceId),
|
||||
quantity: parseInt(line.quantity),
|
||||
unitPrice: product.price,
|
||||
subtotal,
|
||||
description: product.description,
|
||||
});
|
||||
}
|
||||
|
||||
await api.put(`/invoices/recalculateTotalOfInvoiceById/${invoice.id}`);
|
||||
|
||||
alert("Factura creada correctamente.");
|
||||
setUserId("");
|
||||
setLines([]);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="content-area">
|
||||
<h2>Crear Factura</h2>
|
||||
|
||||
<label>Seleccionar estudiante:</label>
|
||||
<select
|
||||
className="form-select"
|
||||
value={userId}
|
||||
onChange={(e) => setUserId(e.target.value)}
|
||||
>
|
||||
<option value="">-- Selecciona un estudiante --</option>
|
||||
{students.map((s) =>
|
||||
s.user ? (
|
||||
<option key={s.id} value={s.user.id}>
|
||||
{s.user.name} {s.user.lastName} ({s.user.email})
|
||||
</option>
|
||||
) : null
|
||||
)}
|
||||
</select>
|
||||
|
||||
<label>Fecha de emisión:</label>
|
||||
<input
|
||||
className="form-input"
|
||||
type="datetime-local"
|
||||
value={date}
|
||||
onChange={(e) => setDate(e.target.value)}
|
||||
/>
|
||||
|
||||
<h3>Productos / Servicios</h3>
|
||||
|
||||
{lines.map((line, i) => (
|
||||
<InvoiceLineItem
|
||||
key={i}
|
||||
index={i}
|
||||
line={line}
|
||||
products={products}
|
||||
onUpdate={updateLine}
|
||||
onRemove={removeLine}
|
||||
/>
|
||||
))}
|
||||
|
||||
<div style={{ marginTop: "1rem" }}>
|
||||
<button className="btn btn-secondary" onClick={addLine}>
|
||||
+ Añadir Producto
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
onClick={createInvoice}
|
||||
style={{ marginLeft: "1rem" }}
|
||||
>
|
||||
✅ Crear Factura
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default InvoiceForm;
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// src/components/forms/InvoiceLineItem.jsx
|
||||
|
||||
import React from 'react';
|
||||
|
||||
const InvoiceLineItem = ({ index, line, products, onUpdate, onRemove }) => {
|
||||
const handleChange = (e) => {
|
||||
onUpdate(index, { ...line, [e.target.name]: e.target.value });
|
||||
};
|
||||
|
||||
const selectedProduct = products.find(p => p.id === parseInt(line.productServiceId));
|
||||
|
||||
return (
|
||||
<div className="content-area" style={{ marginBottom: "1rem", display: "flex", flexDirection: "column", gap: "0.5rem" }}>
|
||||
<select
|
||||
name="productServiceId"
|
||||
value={line.productServiceId}
|
||||
onChange={handleChange}
|
||||
className="form-select"
|
||||
>
|
||||
<option value="">Selecciona producto</option>
|
||||
{products.map(p => (
|
||||
<option key={p.id} value={p.id}>
|
||||
{p.name} - {p.price}€ ({p.type})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<input
|
||||
type="number"
|
||||
name="quantity"
|
||||
min="1"
|
||||
value={line.quantity}
|
||||
onChange={handleChange}
|
||||
className="form-input"
|
||||
placeholder="Cantidad"
|
||||
/>
|
||||
|
||||
{selectedProduct && (
|
||||
<div style={{ fontSize: '0.9rem', color: '#666' }}>
|
||||
<strong>{selectedProduct.name}</strong>: {selectedProduct.description}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button className="btn btn-danger" onClick={() => onRemove(index)}>Eliminar producto</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default InvoiceLineItem;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState } from "react";
|
||||
import api from "../../api/axiosConfig";
|
||||
import "../styles/Login.css"
|
||||
import "../styles/Login.css";
|
||||
|
||||
const LoginForm = ({ onLoginSuccess }) => {
|
||||
const [email, setEmail] = useState('');
|
||||
|
|
@ -12,8 +12,15 @@ const LoginForm = ({ onLoginSuccess }) => {
|
|||
setError('');
|
||||
try {
|
||||
const res = await api.post('/auth/login', { email, password });
|
||||
localStorage.setItem('token', res.data.token);
|
||||
console.log("Token guardado:", res.data.token);
|
||||
const token = res.data.token;
|
||||
localStorage.setItem('token', token);
|
||||
console.log("Token guardado:", token);
|
||||
|
||||
const profileRes = await api.get('/users/me');
|
||||
const roleName = profileRes.data.roleName;
|
||||
console.log("Rol del usuario:", roleName);
|
||||
localStorage.setItem('roleName', roleName);
|
||||
|
||||
onLoginSuccess();
|
||||
} catch (err) {
|
||||
console.error("Error al iniciar sesión:", err);
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ import '../styles/ContentArea.css';
|
|||
import UserForm from '../forms/UserForm';
|
||||
import StudentForm from '../forms/StudentForm';
|
||||
import TeacherForm from '../forms/TeacherForm';
|
||||
import { getRoleFromToken } from '../../utils/jwtHelper';
|
||||
|
||||
const ContentArea = ({ section, entity, action }) => {
|
||||
// Si falta info, mostramos encabezado básico
|
||||
const role = getRoleFromToken();
|
||||
|
||||
if (!section || !entity || !action) {
|
||||
return (
|
||||
<div className="content-area">
|
||||
|
|
@ -16,7 +18,26 @@ const ContentArea = ({ section, entity, action }) => {
|
|||
);
|
||||
}
|
||||
|
||||
// Sección de User Management
|
||||
// Definir qué roles tienen acceso a qué entidades
|
||||
const permissions = {
|
||||
FULL_ACCESS: ['Users', 'Students', 'Teachers', 'Admin', 'Notifications', 'Assistance', 'TrainingGroups', 'TrainingSessions', 'Memberships', 'StudentHistories'],
|
||||
MANAGE_STUDENTS: ['Students', 'Assistance', 'TrainingGroups', 'TrainingSessions'],
|
||||
VIEW_OWN_DATA: ['Assistance', 'Timetable', 'History'],
|
||||
};
|
||||
|
||||
// Validar si tiene acceso a la entidad actual
|
||||
const hasPermission = permissions[role]?.includes(entity);
|
||||
|
||||
if (!hasPermission) {
|
||||
return (
|
||||
<div className="content-area">
|
||||
<h2>Acceso denegado</h2>
|
||||
<p>No tienes permiso para acceder a esta sección.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Sección de gestión de usuarios
|
||||
if (section === 'User Management') {
|
||||
if (action === 'create') {
|
||||
switch (entity) {
|
||||
|
|
@ -42,7 +63,6 @@ const ContentArea = ({ section, entity, action }) => {
|
|||
);
|
||||
}
|
||||
|
||||
// Puedes continuar con update, delete, findById, etc.
|
||||
return (
|
||||
<div className="content-area">
|
||||
<h2>{action} {entity}</h2>
|
||||
|
|
@ -51,7 +71,6 @@ const ContentArea = ({ section, entity, action }) => {
|
|||
);
|
||||
}
|
||||
|
||||
// Si no se reconoce la sección
|
||||
return (
|
||||
<div className="content-area">
|
||||
<h2>{section}</h2>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import TrainingSessionList from '../lists/TrainingSessionList';
|
|||
import ViewTimetable from '../forms/ViewTimetable';
|
||||
import MembershipForm from '../forms/MembershipCreateForm';
|
||||
import MembershipList from '../lists/MembershipList';
|
||||
import InvoiceForm from '../forms/InvoiceForm';
|
||||
import '../styles/MainLayout.css';
|
||||
|
||||
|
||||
|
|
@ -52,6 +53,7 @@ const MainLayout = () => {
|
|||
{/* ContentArea general para secciones sin componentes específicos */}
|
||||
<Route path="/admin/user-management/*" element={<ContentArea />} />
|
||||
<Route path="/admin/class-management/*" element={<ContentArea />} />
|
||||
<Route path="/admin/finance/*" element={<ContentArea />} />
|
||||
|
||||
{/*Class Management - rutas específicas*/}
|
||||
<Route path="/admin/class-management/training-groups/create" element={<TrainingGroupForm />} />
|
||||
|
|
@ -66,12 +68,7 @@ const MainLayout = () => {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<Route path="/admin/finance/*" element={<ContentArea />} />
|
||||
<Route path="/admin/finance/invoices/create" element={<InvoiceForm />} />
|
||||
|
||||
{/* Profile Page*/}
|
||||
<Route path="/profile" element={<ProfilePage />} />
|
||||
|
|
|
|||
|
|
@ -1,77 +1,45 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { getRoleFromToken } from '../../utils/jwtHelper';
|
||||
import '../styles/Sidebar.css';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import SidebarAdmin from './SidebarAdmin';
|
||||
import SidebarTeacher from './SidebarTeacher';
|
||||
import SidebarStudent from './SidebarStudent';
|
||||
|
||||
const Sidebar = () => {
|
||||
const navigate = useNavigate();
|
||||
const role = getRoleFromToken();
|
||||
const [role, setRole] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
const storedRole = localStorage.getItem('roleName');
|
||||
if (storedRole) {
|
||||
setRole(storedRole);
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, 100); // intenta cada 100ms
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
if (!role) {
|
||||
return (
|
||||
<div className="sidebar">
|
||||
<h4>Menú</h4>
|
||||
<div className='sidebar-scroll'>
|
||||
{/* Botón común para todos: Mi Perfil */}
|
||||
<button onClick={() => navigate('/profile')}>👤 Mi Perfil</button>
|
||||
|
||||
{role === 'FULL_ACCESS' && (
|
||||
<>
|
||||
<button onClick={() => navigate('/admin/dashboard')}>🏠 Dashboard Admin</button>
|
||||
|
||||
|
||||
<div className="submenu">
|
||||
<h4>👥 Administración de Usuarios</h4>
|
||||
<button onClick={() => navigate('/admin/user-management/users/create')}>➕ Crear Usuario</button>
|
||||
<button onClick={() => navigate('/admin/user-management/users/list')}>📋 Ver Usuarios</button>
|
||||
<button onClick={() => navigate('/admin/user-management/notifications/create')}>🔔 Crear Notificación</button>
|
||||
<button onClick={() => navigate('/admin/user-management/notifications/list')}>📨 Ver Notificaciones</button>
|
||||
<button onClick={() => navigate('/admin/user-management/student-history/create')}>🕒 Crear Historial</button>
|
||||
<button onClick={() => navigate('/admin/user-management/student-history/list')}>📜 Ver Historial</button>
|
||||
</div>
|
||||
|
||||
<div className="submenu">
|
||||
<h4>📚 Administración de Clases</h4>
|
||||
<button onClick={() => navigate('/admin/class-management/training-groups/create')}>➕ Crear Grupo</button>
|
||||
<button onClick={() => navigate('/admin/class-management/training-groups/list')}>👥 Ver Grupos</button>
|
||||
<button onClick={() => navigate('/admin/class-management/training-groups/manage-students')}>🧑🏫 Administrar Grupos</button>
|
||||
<button onClick={() => navigate('/admin/class-management/training-groups/view-timetable')}>🗓️ Ver Horario</button>
|
||||
<button onClick={() => navigate('/admin/class-management/training-session/list')}>📆 Ver Sesiones</button>
|
||||
<button onClick={() => navigate('/admin/class-management/assistance/create')}>📝 Registrar Asistencia</button>
|
||||
<button onClick={() => navigate('/admin/class-management/assistance/list')}>📋 Ver Asistencias</button>
|
||||
<button onClick={() => navigate('/admin/class-management/memberships/create')}>➕ Crear Membresía</button>
|
||||
<button onClick={() => navigate('/admin/class-management/memberships/list')}>🏷️ Ver Membresías</button>
|
||||
</div>
|
||||
|
||||
<div className='submenu'>
|
||||
<h4>💵 Administración de Pagos y Facturas</h4>
|
||||
<button onClick={() => navigate('')}>🧾 Crear Factura</button>
|
||||
<button onClick={() => navigate('')}>📄 Ver Facturas</button>
|
||||
<button onClick={() => navigate('')}>💳 Nuevo Pago</button>
|
||||
<button onClick={() => navigate('')}>🛒 Añadir Productos</button>
|
||||
<button onClick={() => navigate('')}>📦 Ver Productos</button>
|
||||
<button onClick={() => navigate('')}>💱 Añadir Tipo de IVA</button>
|
||||
</div>
|
||||
|
||||
</>
|
||||
)}
|
||||
|
||||
{role === 'MANAGE_STUDENTS' && (
|
||||
<>
|
||||
<button onClick={() => navigate('/teacher/dashboard')}>🏠 Dashboard Profesor</button>
|
||||
<button onClick={() => navigate('/teacher/students')}>👨🎓 Mis Estudiantes</button>
|
||||
<button onClick={() => navigate('/teacher/classes')}>📚 Mis Clases</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{role === 'VIEW_OWN_DATA' && (
|
||||
<>
|
||||
<button onClick={() => navigate('/student/dashboard')}>🏠 Mi Panel</button>
|
||||
<button onClick={() => navigate('/student/history')}>🕒 Mi Historial</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<p>Cargando menú...</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
switch (role) {
|
||||
case 'ROLE_ADMIN':
|
||||
return <SidebarAdmin />;
|
||||
case 'ROLE_TEACHER':
|
||||
return <SidebarTeacher />;
|
||||
case 'ROLE_STUDENT':
|
||||
return <SidebarStudent />;
|
||||
default:
|
||||
return (
|
||||
<div className="sidebar">
|
||||
<p>Sin acceso</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import '../styles/Sidebar.css';
|
||||
|
||||
const SidebarAdmin = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className="sidebar">
|
||||
<h4>Menú</h4>
|
||||
<div className="sidebar-scroll">
|
||||
<button onClick={() => navigate('/profile')}>👤 Mi Perfil</button>
|
||||
<button onClick={() => navigate('/admin/dashboard')}>🏠 Dashboard Admin</button>
|
||||
|
||||
<div className="submenu">
|
||||
<h4>👥 Administración de Usuarios</h4>
|
||||
<button onClick={() => navigate('/admin/user-management/users/create')}>➕ Crear Usuario</button>
|
||||
<button onClick={() => navigate('/admin/user-management/users/list')}>📋 Ve Usuarios</button>
|
||||
<button onClick={() => navigate('/admin/user-management/notifications/create')}>🔔 Crear Notificación</button>
|
||||
<button onClick={() => navigate('/admin/user-management/notifications/list')}>📨 Ver Notificaciones</button>
|
||||
<button onClick={() => navigate('/admin/user-management/student-history/create')}>🕒 Crear Historial</button>
|
||||
<button onClick={() => navigate('/admin/user-management/student-history/list')}>📜 Ver Historial</button>
|
||||
</div>
|
||||
|
||||
<div className="submenu">
|
||||
<h4>📚 Administración de Clases</h4>
|
||||
<button onClick={() => navigate('/admin/class-management/training-groups/create')}>➕ Crear Grupo</button>
|
||||
<button onClick={() => navigate('/admin/class-management/training-groups/list')}>👥 Ver Grupos</button>
|
||||
<button onClick={() => navigate('/admin/class-management/training-groups/manage-students')}>🧑🏫 Administrar Grupos</button>
|
||||
<button onClick={() => navigate('/admin/class-management/training-groups/view-timetable')}>🗓️ Ver Horario</button>
|
||||
<button onClick={() => navigate('/admin/class-management/training-session/list')}>📆 Ver Sesiones</button>
|
||||
<button onClick={() => navigate('/admin/class-management/assistance/create')}>📝 Registrar Asistencia</button>
|
||||
<button onClick={() => navigate('/admin/class-management/assistance/list')}>📋 Ver Asistencias</button>
|
||||
<button onClick={() => navigate('/admin/class-management/memberships/create')}>➕ Crear Membresía</button>
|
||||
<button onClick={() => navigate('/admin/class-management/memberships/list')}>🏷️ Ver Membresías</button>
|
||||
</div>
|
||||
|
||||
<div className="submenu">
|
||||
<h4>💵 Finanzas</h4>
|
||||
<button onClick={() => navigate('/admin/finance/invoices/create')}>🧾 Crear Factura</button>
|
||||
<button onClick={() => navigate('/admin/finance/invoices/list')}>📄 Ver Facturas</button>
|
||||
<button onClick={() => navigate('/admin/finance/payments/create')}>💳 Nuevo Pago</button>
|
||||
<button onClick={() => navigate('/admin/finance/products/create')}>🛒 Añadir Productos</button>
|
||||
<button onClick={() => navigate('/admin/finance/products/list')}>📦 Ver Productos</button>
|
||||
<button onClick={() => navigate('/admin/finance/ivatypes/create')}>💱 Añadir Tipo de IVA</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SidebarAdmin;
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import '../styles/Sidebar.css';
|
||||
|
||||
const SidebarStudent = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className="sidebar">
|
||||
<h4>Menú</h4>
|
||||
<div className="sidebar-scroll">
|
||||
<button onClick={() => navigate('/profile')}>👤 Mi Perfil</button>
|
||||
<button onClick={() => navigate('/student/dashboard')}>🏠 Mi Panel</button>
|
||||
|
||||
<div className="submenu">
|
||||
<h4>🎓 Opciones de Estudiante</h4>
|
||||
<button onClick={() => navigate('/student/history')}>🕒 Mi Historial</button>
|
||||
<button onClick={() => navigate('/student/timetable')}>📅 Ver Horario</button>
|
||||
<button onClick={() => navigate('/student/assistance')}>📋 Ver Asistencia</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SidebarStudent;
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import '../styles/Sidebar.css';
|
||||
|
||||
const SidebarTeacher = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className="sidebar">
|
||||
<h4>Menú</h4>
|
||||
<div className="sidebar-scroll">
|
||||
<button onClick={() => navigate('/profile')}>👤 Mi Perfil</button>
|
||||
<button onClick={() => navigate('/teacher/dashboard')}>🏠 Dashboard Profesor</button>
|
||||
|
||||
<div className="submenu">
|
||||
<h4>👨🏫 Gestión del Profesor</h4>
|
||||
<button onClick={() => navigate('/teacher/students')}>👨🎓 Mis Estudiantes</button>
|
||||
<button onClick={() => navigate('/teacher/classes')}>📚 Mis Clases</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SidebarTeacher;
|
||||
|
|
@ -9,8 +9,10 @@ const Topbar = () => {
|
|||
|
||||
const handleLogout = () => {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('roleName');
|
||||
navigate('/');
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
const roleLabel = {
|
||||
FULL_ACCESS: 'Admin',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import '../../components/styles/DashboardCards.css'; // lo creamos ahora
|
||||
import '../../components/styles/DashboardCards.css';
|
||||
|
||||
const AdminDashboard = () => {
|
||||
const navigate = useNavigate();
|
||||
|
|
|
|||
|
|
@ -13,3 +13,8 @@ export const getRoleFromToken = () => {
|
|||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const getRoleFromStorage = () => {
|
||||
return localStorage.getItem('roleName');
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue