Migrate all controllers to REST API
This commit is contained in:
@@ -4,21 +4,21 @@ import javafx.beans.property.*;
|
||||
|
||||
public class PurchaseOrderDTO {
|
||||
|
||||
private IntegerProperty purchaseOrderId;
|
||||
private LongProperty purchaseOrderId;
|
||||
private StringProperty supplierName;
|
||||
private StringProperty orderDate;
|
||||
private StringProperty status;
|
||||
|
||||
public PurchaseOrderDTO(int id, String supplierName,
|
||||
public PurchaseOrderDTO(long id, String supplierName,
|
||||
String orderDate, String status) {
|
||||
|
||||
this.purchaseOrderId = new SimpleIntegerProperty(id);
|
||||
this.purchaseOrderId = new SimpleLongProperty(id);
|
||||
this.supplierName = new SimpleStringProperty(supplierName);
|
||||
this.orderDate = new SimpleStringProperty(orderDate);
|
||||
this.status = new SimpleStringProperty(status);
|
||||
}
|
||||
|
||||
public int getPurchaseOrderId() { return purchaseOrderId.get(); }
|
||||
public long getPurchaseOrderId() { return purchaseOrderId.get(); }
|
||||
public String getSupplierName() { return supplierName.get(); }
|
||||
public String getOrderDate() { return orderDate.get(); }
|
||||
public String getStatus() { return status.get(); }
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.math.BigDecimal;
|
||||
|
||||
public class ProductSupplierResponse {
|
||||
private Long id;
|
||||
private Long productId;
|
||||
private Long supplierId;
|
||||
private String productName;
|
||||
private String supplierName;
|
||||
private BigDecimal supplierPrice;
|
||||
@@ -16,6 +18,22 @@ public class ProductSupplierResponse {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getProductId() {
|
||||
return productId;
|
||||
}
|
||||
|
||||
public void setProductId(Long productId) {
|
||||
this.productId = productId;
|
||||
}
|
||||
|
||||
public Long getSupplierId() {
|
||||
return supplierId;
|
||||
}
|
||||
|
||||
public void setSupplierId(Long supplierId) {
|
||||
this.supplierId = supplierId;
|
||||
}
|
||||
|
||||
public String getProductName() {
|
||||
return productName;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.example.petshopdesktop.controllers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
@@ -10,15 +11,16 @@ import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.api.dto.adoption.AdoptionResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.AdoptionApi;
|
||||
import org.example.petshopdesktop.controllers.dialogcontrollers.AdoptionDialogController;
|
||||
import org.example.petshopdesktop.database.AdoptionDB;
|
||||
import org.example.petshopdesktop.models.Adoption;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLIntegrityConstraintViolationException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AdoptionController {
|
||||
|
||||
@@ -35,7 +37,7 @@ public class AdoptionController {
|
||||
private TableColumn<Adoption, Integer> colAdoptionId;
|
||||
|
||||
@FXML
|
||||
private TableColumn<Adoption, Integer> colPetId;
|
||||
private TableColumn<Adoption, String> colPetId;
|
||||
|
||||
@FXML
|
||||
private TableColumn<Adoption, String> colCustomerName;
|
||||
@@ -66,7 +68,7 @@ public class AdoptionController {
|
||||
tvAdoptions.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE);
|
||||
|
||||
colAdoptionId.setCellValueFactory(new PropertyValueFactory<>("adoptionId"));
|
||||
colPetId.setCellValueFactory(new PropertyValueFactory<>("petId"));
|
||||
colPetId.setCellValueFactory(new PropertyValueFactory<>("petName"));
|
||||
colCustomerName.setCellValueFactory(new PropertyValueFactory<>("customerName"));
|
||||
colAdoptionDate.setCellValueFactory(new PropertyValueFactory<>("adoptionDate"));
|
||||
colAdoptionFee.setCellValueFactory(new PropertyValueFactory<>("adoptionFee"));
|
||||
@@ -118,47 +120,24 @@ public class AdoptionController {
|
||||
|
||||
//if confirmed, start deletion
|
||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
StringBuilder errors = new StringBuilder();
|
||||
List<Long> ids = selectedAdoptions.stream()
|
||||
.map(a -> (long) a.getAdoptionId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (Adoption adoption : selectedAdoptions) {
|
||||
try {
|
||||
int numRows = AdoptionDB.deleteAdoption(adoption.getAdoptionId());
|
||||
if (numRows > 0) {
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
catch (SQLIntegrityConstraintViolationException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionController.btnDeleteClicked",
|
||||
e,
|
||||
String.format("Attempting to delete adoption ID %d - foreign key constraint", adoption.getAdoptionId()));
|
||||
failCount++;
|
||||
errors.append("Adoption ID ").append(adoption.getAdoptionId()).append(" is referenced in another table\n");
|
||||
} catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionController.btnDeleteClicked",
|
||||
e,
|
||||
String.format("Attempting to delete adoption ID %d", adoption.getAdoptionId()));
|
||||
failCount++;
|
||||
errors.append("Failed to delete adoption ID ").append(adoption.getAdoptionId()).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
//show results
|
||||
if (failCount > 0) {
|
||||
Alert alert = new Alert(Alert.AlertType.WARNING);
|
||||
alert.setHeaderText("Delete Operation Completed with Errors");
|
||||
alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s",
|
||||
successCount, failCount, errors.toString()));
|
||||
alert.showAndWait();
|
||||
} else if (successCount > 0) {
|
||||
try {
|
||||
AdoptionApi.getInstance().deleteAdoptions(ids);
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setHeaderText("Database Operation Confirmed");
|
||||
alert.setContentText("Successfully deleted " + successCount + " adoption record(s)");
|
||||
alert.setContentText("Successfully deleted " + ids.size() + " adoption record(s)");
|
||||
alert.showAndWait();
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionController.btnDeleteClicked",
|
||||
e,
|
||||
"Deleting adoptions");
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Delete Operation Failed");
|
||||
alert.setContentText(e.getMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
@@ -181,35 +160,55 @@ public class AdoptionController {
|
||||
}
|
||||
|
||||
private void displayFilteredAdoptions(String filter) {
|
||||
data.clear();
|
||||
try {
|
||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) {
|
||||
displayAdoptions();
|
||||
} else {
|
||||
data = AdoptionDB.getFilteredAdoptions(filter);
|
||||
tvAdoptions.setItems(data);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionController.displayFilteredAdoptions",
|
||||
e,
|
||||
"Filtering adoptions with filter: " + filter);
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) {
|
||||
displayAdoptions();
|
||||
} else {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<AdoptionResponse> adoptions = AdoptionApi.getInstance().listAdoptions(filter);
|
||||
List<Adoption> adoptionList = adoptions.stream()
|
||||
.map(this::mapToAdoption)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
data.setAll(adoptionList);
|
||||
tvAdoptions.setItems(data);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionController.displayFilteredAdoptions",
|
||||
e,
|
||||
"Filtering adoptions with filter: " + filter);
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
private void displayAdoptions() {
|
||||
data.clear();
|
||||
try {
|
||||
data = AdoptionDB.getAdoptions();
|
||||
} catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionController.displayAdoptions",
|
||||
e,
|
||||
"Fetching adoption data for table display");
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
}
|
||||
tvAdoptions.setItems(data);
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<AdoptionResponse> adoptions = AdoptionApi.getInstance().listAdoptions(null);
|
||||
List<Adoption> adoptionList = adoptions.stream()
|
||||
.map(this::mapToAdoption)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
data.setAll(adoptionList);
|
||||
tvAdoptions.setItems(data);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionController.displayAdoptions",
|
||||
e,
|
||||
"Fetching adoption data for table display");
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void openDialog(Adoption adoption, String mode) {
|
||||
@@ -244,4 +243,17 @@ public class AdoptionController {
|
||||
btnEdit.setDisable(true);
|
||||
txtSearch.setText("");
|
||||
}
|
||||
|
||||
private Adoption mapToAdoption(AdoptionResponse response) {
|
||||
return new Adoption(
|
||||
response.getId().intValue(),
|
||||
0,
|
||||
0,
|
||||
response.getPetName(),
|
||||
response.getCustomerName(),
|
||||
response.getAdoptionDate() != null ? response.getAdoptionDate().toString() : "",
|
||||
0.0,
|
||||
response.getAdoptionStatus()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
package org.example.petshopdesktop.controllers;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.chart.*;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import org.example.petshopdesktop.auth.UserSession;
|
||||
import org.example.petshopdesktop.database.SaleDB;
|
||||
import org.example.petshopdesktop.models.analytics.*;
|
||||
import org.example.petshopdesktop.api.dto.analytics.DailySales;
|
||||
import org.example.petshopdesktop.api.dto.analytics.DashboardResponse;
|
||||
import org.example.petshopdesktop.api.dto.analytics.TopProduct;
|
||||
import org.example.petshopdesktop.api.dto.sale.SaleResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.AnalyticsApi;
|
||||
import org.example.petshopdesktop.api.endpoints.SaleApi;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.NumberFormat;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AnalyticsController {
|
||||
|
||||
@@ -78,79 +84,111 @@ public class AnalyticsController {
|
||||
|
||||
private void loadAnalyticsData() {
|
||||
lblError.setVisible(false);
|
||||
try {
|
||||
loadSummaryData();
|
||||
loadSalesOverTime();
|
||||
loadTopProductsByRevenue();
|
||||
loadTopProductsByQuantity();
|
||||
loadPaymentMethodDistribution();
|
||||
loadEmployeePerformance();
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException("AnalyticsController.loadAnalyticsData", e, "Loading analytics data");
|
||||
lblError.setText("Error loading analytics data. Please try again.");
|
||||
lblError.setVisible(true);
|
||||
new Thread(() -> {
|
||||
try {
|
||||
DashboardResponse dashboard = AnalyticsApi.getInstance().getDashboard(30, 10);
|
||||
List<SaleResponse> sales = SaleApi.getInstance().listSales(0, Integer.MAX_VALUE, null);
|
||||
|
||||
Platform.runLater(() -> {
|
||||
try {
|
||||
loadSummaryData(dashboard);
|
||||
loadSalesOverTime(dashboard);
|
||||
loadTopProductsByRevenue(dashboard);
|
||||
loadTopProductsByQuantity(dashboard);
|
||||
loadPaymentMethodDistribution(sales);
|
||||
loadEmployeePerformance(sales);
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException("AnalyticsController.loadAnalyticsData", e, "Loading analytics data");
|
||||
lblError.setText("Error loading analytics data. Please try again.");
|
||||
lblError.setVisible(true);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException("AnalyticsController.loadAnalyticsData", e, "Loading analytics data");
|
||||
lblError.setText("Error loading analytics data. Please try again.");
|
||||
lblError.setVisible(true);
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void loadSummaryData(DashboardResponse dashboard) throws Exception {
|
||||
if (dashboard != null) {
|
||||
BigDecimal totalRevenue = dashboard.getTotalRevenue() != null ? dashboard.getTotalRevenue() : BigDecimal.ZERO;
|
||||
Long totalSales = dashboard.getTotalSales() != null ? dashboard.getTotalSales() : 0L;
|
||||
Long totalProducts = dashboard.getTotalProducts() != null ? dashboard.getTotalProducts() : 0L;
|
||||
|
||||
lblTotalRevenue.setText(currency.format(totalRevenue));
|
||||
lblTotalTransactions.setText(wholeNumber.format(totalSales));
|
||||
|
||||
BigDecimal avgTransaction = BigDecimal.ZERO;
|
||||
if (totalSales > 0) {
|
||||
avgTransaction = totalRevenue.divide(BigDecimal.valueOf(totalSales), 2, RoundingMode.HALF_UP);
|
||||
}
|
||||
lblAvgTransaction.setText(currency.format(avgTransaction));
|
||||
lblTotalItems.setText(wholeNumber.format(totalProducts));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadSummaryData() throws Exception {
|
||||
SalesSummary summary = SaleDB.getSalesSummary();
|
||||
if (summary != null) {
|
||||
lblTotalRevenue.setText(currency.format(summary.getTotalRevenue()));
|
||||
lblTotalTransactions.setText(wholeNumber.format(summary.getTotalTransactions()));
|
||||
lblAvgTransaction.setText(currency.format(summary.getAvgTransactionValue()));
|
||||
lblTotalItems.setText(wholeNumber.format(summary.getTotalItemsSold()));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadSalesOverTime() throws Exception {
|
||||
ObservableList<DailySalesData> data = SaleDB.getDailySalesRevenue();
|
||||
private void loadSalesOverTime(DashboardResponse dashboard) throws Exception {
|
||||
List<DailySales> dailySales = dashboard.getDailySales() != null ? dashboard.getDailySales() : new ArrayList<>();
|
||||
XYChart.Series<String, Number> series = new XYChart.Series<>();
|
||||
series.setName("Daily Revenue");
|
||||
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd");
|
||||
for (DailySalesData dailySale : data) {
|
||||
for (DailySales dailySale : dailySales) {
|
||||
String dateStr = dailySale.getDate().format(formatter);
|
||||
series.getData().add(new XYChart.Data<>(dateStr, dailySale.getRevenue()));
|
||||
BigDecimal totalSales = dailySale.getTotalSales() != null ? dailySale.getTotalSales() : BigDecimal.ZERO;
|
||||
series.getData().add(new XYChart.Data<>(dateStr, totalSales));
|
||||
}
|
||||
|
||||
chartSalesOverTime.getData().clear();
|
||||
chartSalesOverTime.getData().add(series);
|
||||
}
|
||||
|
||||
private void loadTopProductsByRevenue() throws Exception {
|
||||
ObservableList<ProductSalesData> data = SaleDB.getTopProductsByRevenue(10);
|
||||
private void loadTopProductsByRevenue(DashboardResponse dashboard) throws Exception {
|
||||
List<TopProduct> topProducts = dashboard.getTopProducts() != null ? dashboard.getTopProducts() : new ArrayList<>();
|
||||
XYChart.Series<Number, String> series = new XYChart.Series<>();
|
||||
series.setName("Revenue");
|
||||
|
||||
for (ProductSalesData product : data) {
|
||||
series.getData().add(new XYChart.Data<>(product.getTotalRevenue(), product.getProductName()));
|
||||
for (TopProduct product : topProducts) {
|
||||
BigDecimal totalRevenue = product.getTotalRevenue() != null ? product.getTotalRevenue() : BigDecimal.ZERO;
|
||||
series.getData().add(new XYChart.Data<>(totalRevenue, product.getProductName()));
|
||||
}
|
||||
|
||||
chartTopRevenue.getData().clear();
|
||||
chartTopRevenue.getData().add(series);
|
||||
}
|
||||
|
||||
private void loadTopProductsByQuantity() throws Exception {
|
||||
ObservableList<ProductSalesData> data = SaleDB.getTopProductsByQuantity(10);
|
||||
private void loadTopProductsByQuantity(DashboardResponse dashboard) throws Exception {
|
||||
List<TopProduct> topProducts = dashboard.getTopProducts() != null ? dashboard.getTopProducts() : new ArrayList<>();
|
||||
XYChart.Series<Number, String> series = new XYChart.Series<>();
|
||||
series.setName("Quantity");
|
||||
|
||||
for (ProductSalesData product : data) {
|
||||
series.getData().add(new XYChart.Data<>(product.getTotalQuantity(), product.getProductName()));
|
||||
for (TopProduct product : topProducts) {
|
||||
Integer quantitySold = product.getQuantitySold() != null ? product.getQuantitySold() : 0;
|
||||
series.getData().add(new XYChart.Data<>(quantitySold, product.getProductName()));
|
||||
}
|
||||
|
||||
chartTopQuantity.getData().clear();
|
||||
chartTopQuantity.getData().add(series);
|
||||
}
|
||||
|
||||
private void loadPaymentMethodDistribution() throws Exception {
|
||||
ObservableList<PaymentMethodData> data = SaleDB.getPaymentMethodDistribution();
|
||||
private void loadPaymentMethodDistribution(List<SaleResponse> sales) throws Exception {
|
||||
Map<String, Long> paymentMethodCount = sales.stream()
|
||||
.filter(sale -> sale.getIsRefund() == null || !sale.getIsRefund())
|
||||
.collect(Collectors.groupingBy(
|
||||
sale -> sale.getPaymentMethod() != null ? sale.getPaymentMethod() : "Unknown",
|
||||
Collectors.counting()
|
||||
));
|
||||
|
||||
chartPaymentMethods.getData().clear();
|
||||
|
||||
for (PaymentMethodData payment : data) {
|
||||
for (Map.Entry<String, Long> entry : paymentMethodCount.entrySet()) {
|
||||
PieChart.Data slice = new PieChart.Data(
|
||||
payment.getPaymentMethod() + " (" + payment.getTransactionCount() + ")",
|
||||
payment.getTransactionCount()
|
||||
entry.getKey() + " (" + entry.getValue() + ")",
|
||||
entry.getValue()
|
||||
);
|
||||
chartPaymentMethods.getData().add(slice);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.example.petshopdesktop.controllers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
@@ -13,10 +14,14 @@ import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import org.example.petshopdesktop.DTOs.AppointmentDTO;
|
||||
import org.example.petshopdesktop.api.dto.appointment.AppointmentResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.AppointmentApi;
|
||||
import org.example.petshopdesktop.controllers.dialogcontrollers.AppointmentDialogController;
|
||||
import org.example.petshopdesktop.database.AppointmentDB;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AppointmentController {
|
||||
|
||||
@FXML private TableView<AppointmentDTO> tvAppointments;
|
||||
@@ -71,41 +76,50 @@ public class AppointmentController {
|
||||
}
|
||||
|
||||
private void loadAppointments(){
|
||||
try{
|
||||
appointments.setAll(AppointmentDB.getAppointmentDTOs());
|
||||
}catch(Exception e){
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AppointmentController.loadAppointments",
|
||||
e,
|
||||
"Loading appointments for table display");
|
||||
e.printStackTrace();
|
||||
}
|
||||
new Thread(() -> {
|
||||
try{
|
||||
List<AppointmentResponse> responses = AppointmentApi.getInstance().listAppointments(null);
|
||||
List<AppointmentDTO> appointmentDTOs = responses.stream()
|
||||
.map(this::mapToAppointmentDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
appointments.setAll(appointmentDTOs);
|
||||
});
|
||||
}catch(Exception e){
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AppointmentController.loadAppointments",
|
||||
e,
|
||||
"Loading appointments for table display");
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void applyFilter(String text) {
|
||||
if (filtered == null) {
|
||||
return;
|
||||
}
|
||||
String query = text == null || text.trim().isEmpty() ? null : text.trim();
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<AppointmentResponse> responses = AppointmentApi.getInstance().listAppointments(query);
|
||||
List<AppointmentDTO> appointmentDTOs = responses.stream()
|
||||
.map(this::mapToAppointmentDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
String q = text == null ? "" : text.trim().toLowerCase();
|
||||
if (q.isEmpty()) {
|
||||
filtered.setPredicate(a -> true);
|
||||
return;
|
||||
}
|
||||
|
||||
filtered.setPredicate(a ->
|
||||
String.valueOf(a.getAppointmentId()).contains(q)
|
||||
|| safe(a.getPetName()).contains(q)
|
||||
|| safe(a.getServiceName()).contains(q)
|
||||
|| safe(a.getAppointmentDate()).contains(q)
|
||||
|| safe(a.getAppointmentTime()).contains(q)
|
||||
|| safe(a.getCustomerName()).contains(q)
|
||||
|| safe(a.getAppointmentStatus()).contains(q)
|
||||
);
|
||||
}
|
||||
|
||||
private static String safe(String v) {
|
||||
return v == null ? "" : v.toLowerCase();
|
||||
Platform.runLater(() -> {
|
||||
appointments.setAll(appointmentDTOs);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AppointmentController.applyFilter",
|
||||
e,
|
||||
String.format("Filtering appointments with query: %s", query));
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -145,35 +159,24 @@ public class AppointmentController {
|
||||
|
||||
//if confirmed, start deletion
|
||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
StringBuilder errors = new StringBuilder();
|
||||
List<Long> ids = selectedAppointments.stream()
|
||||
.map(a -> (long) a.getAppointmentId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (AppointmentDTO appointment : selectedAppointments) {
|
||||
try{
|
||||
AppointmentDB.deleteAppointment(appointment.getAppointmentId());
|
||||
successCount++;
|
||||
}catch(Exception e){
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AppointmentController.btnDeleteClicked",
|
||||
e,
|
||||
String.format("Attempting to delete appointment ID %d", appointment.getAppointmentId()));
|
||||
failCount++;
|
||||
errors.append("Failed to delete appointment ID ").append(appointment.getAppointmentId()).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
//show results
|
||||
if (failCount > 0) {
|
||||
Alert alert = new Alert(Alert.AlertType.WARNING);
|
||||
alert.setHeaderText("Delete Operation Completed with Errors");
|
||||
alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s",
|
||||
successCount, failCount, errors.toString()));
|
||||
alert.showAndWait();
|
||||
} else if (successCount > 0) {
|
||||
try {
|
||||
AppointmentApi.getInstance().deleteAppointments(ids);
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setHeaderText("Database Operation Confirmed");
|
||||
alert.setContentText("Successfully deleted " + successCount + " appointment(s)");
|
||||
alert.setContentText("Successfully deleted " + ids.size() + " appointment(s)");
|
||||
alert.showAndWait();
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AppointmentController.btnDeleteClicked",
|
||||
e,
|
||||
"Deleting appointments");
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Delete Operation Failed");
|
||||
alert.setContentText(e.getMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
@@ -225,4 +228,19 @@ public class AppointmentController {
|
||||
alert.setContentText(msg);
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
private AppointmentDTO mapToAppointmentDTO(AppointmentResponse response) {
|
||||
return new AppointmentDTO(
|
||||
response.getId().intValue(),
|
||||
0,
|
||||
response.getCustomerName(),
|
||||
0,
|
||||
response.getPetNames(),
|
||||
0,
|
||||
response.getServiceName(),
|
||||
response.getAppointmentDate().toString(),
|
||||
response.getAppointmentTime().toString(),
|
||||
response.getAppointmentStatus()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.example.petshopdesktop.controllers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
@@ -10,15 +11,16 @@ import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.api.dto.inventory.InventoryResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.InventoryApi;
|
||||
import org.example.petshopdesktop.controllers.dialogcontrollers.InventoryDialogController;
|
||||
import org.example.petshopdesktop.database.InventoryDB;
|
||||
import org.example.petshopdesktop.models.Inventory;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLIntegrityConstraintViolationException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class InventoryController {
|
||||
|
||||
@@ -58,11 +60,9 @@ public class InventoryController {
|
||||
//Loads upon view bootup
|
||||
@FXML
|
||||
void initialize() {
|
||||
//Buttons disabled until row is selected
|
||||
btnEdit.setDisable(true);
|
||||
btnDelete.setDisable(true);
|
||||
//Enable multiple selection
|
||||
tvInventory.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE);
|
||||
tvInventory.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.SINGLE);
|
||||
|
||||
colInventoryId.setCellValueFactory(new PropertyValueFactory<>("inventoryId"));
|
||||
colProductId.setCellValueFactory(new PropertyValueFactory<>("prodId"));
|
||||
@@ -71,19 +71,16 @@ public class InventoryController {
|
||||
|
||||
displayInventory();
|
||||
|
||||
//Enables buttons when row is selected
|
||||
tvInventory.getSelectionModel().selectedItemProperty().addListener(
|
||||
(observable, oldValue, newValue) -> {
|
||||
btnEdit.setDisable(false);
|
||||
btnDelete.setDisable(false);
|
||||
});
|
||||
|
||||
//Filter as user types
|
||||
txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
displayFilteredInventory(newValue);
|
||||
});
|
||||
|
||||
//EventListener for DELETE key
|
||||
tvInventory.setOnKeyPressed(event -> {
|
||||
if (event.getCode() == javafx.scene.input.KeyCode.DELETE) {
|
||||
if (tvInventory.getSelectionModel().getSelectedItem() != null) {
|
||||
@@ -100,71 +97,35 @@ public class InventoryController {
|
||||
openDialog(null, mode);
|
||||
}
|
||||
|
||||
//Prompts user for confirmation prior to deletion
|
||||
@FXML
|
||||
void btnDeleteClicked(ActionEvent event) {
|
||||
//get selected inventory records
|
||||
var selectedInventory = tvInventory.getSelectionModel().getSelectedItems();
|
||||
if (selectedInventory.isEmpty()) return;
|
||||
Inventory selectedInventory = tvInventory.getSelectionModel().getSelectedItem();
|
||||
if (selectedInventory == null) return;
|
||||
|
||||
//ask user to confirm
|
||||
Alert question = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
question.setHeaderText("Please confirm delete");
|
||||
String message = selectedInventory.size() == 1
|
||||
? "Are you sure you want to delete this inventory record?"
|
||||
: "Are you sure you want to delete " + selectedInventory.size() + " inventory records?";
|
||||
question.setContentText(message);
|
||||
question.setContentText("Are you sure you want to delete this inventory record?");
|
||||
question.getDialogPane().lookupButton(ButtonType.OK).requestFocus();
|
||||
Optional<ButtonType> result = question.showAndWait();
|
||||
|
||||
//if confirmed, start deletion
|
||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
StringBuilder errors = new StringBuilder();
|
||||
|
||||
for (Inventory inventory : selectedInventory) {
|
||||
try {
|
||||
int numRows = InventoryDB.deleteInventory(inventory.getInventoryId());
|
||||
if (numRows > 0) {
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
catch (SQLIntegrityConstraintViolationException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"InventoryController.btnDeleteClicked",
|
||||
e,
|
||||
String.format("Attempting to delete inventory ID %d - foreign key constraint", inventory.getInventoryId()));
|
||||
failCount++;
|
||||
errors.append("Inventory record '").append(inventory.getProdName()).append("' is referenced in another table\n");
|
||||
}
|
||||
catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"InventoryController.btnDeleteClicked",
|
||||
e,
|
||||
String.format("Attempting to delete inventory ID %d", inventory.getInventoryId()));
|
||||
failCount++;
|
||||
errors.append("Failed to delete '").append(inventory.getProdName()).append("'\n");
|
||||
}
|
||||
}
|
||||
|
||||
//show results
|
||||
if (failCount > 0) {
|
||||
Alert alert = new Alert(Alert.AlertType.WARNING);
|
||||
alert.setHeaderText("Delete Operation Completed with Errors");
|
||||
alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s",
|
||||
successCount, failCount, errors.toString()));
|
||||
alert.showAndWait();
|
||||
} else if (successCount > 0) {
|
||||
try {
|
||||
InventoryApi.getInstance().deleteInventory((long) selectedInventory.getInventoryId());
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setHeaderText("Database Operation Confirmed");
|
||||
alert.setContentText("Successfully deleted " + successCount + " inventory record(s)");
|
||||
alert.setContentText("Successfully deleted inventory record");
|
||||
alert.showAndWait();
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"InventoryController.btnDeleteClicked",
|
||||
e,
|
||||
"Deleting inventory");
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Delete Operation Failed");
|
||||
alert.setContentText(e.getMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
//refresh display and reset inputs
|
||||
displayInventory();
|
||||
btnDelete.setDisable(true);
|
||||
btnEdit.setDisable(true);
|
||||
@@ -183,66 +144,72 @@ public class InventoryController {
|
||||
}
|
||||
}
|
||||
|
||||
//Search filter
|
||||
private void displayFilteredInventory(String filter) {
|
||||
data.clear();
|
||||
try {
|
||||
//If search box is empty, display all inventory
|
||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) {
|
||||
displayInventory();
|
||||
}
|
||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) {
|
||||
displayInventory();
|
||||
} else {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<InventoryResponse> inventories = InventoryApi.getInstance().listInventory(filter);
|
||||
List<Inventory> inventoryList = inventories.stream()
|
||||
.map(this::mapToInventory)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
else {
|
||||
data = InventoryDB.getFilteredInventory(filter);
|
||||
tvInventory.setItems(data);
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"InventoryController.displayFilteredInventory",
|
||||
e,
|
||||
"Filtering inventory with filter: " + filter);
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
Platform.runLater(() -> {
|
||||
data.setAll(inventoryList);
|
||||
tvInventory.setItems(data);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
ActivityLogger.getInstance().logException(
|
||||
"InventoryController.displayFilteredInventory",
|
||||
e,
|
||||
String.format("Filtering inventory with keyword: %s", filter));
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
//Displays all records from DB
|
||||
private void displayInventory() {
|
||||
data.clear();
|
||||
try {
|
||||
data = InventoryDB.getInventory();
|
||||
}
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<InventoryResponse> inventories = InventoryApi.getInstance().listInventory(null);
|
||||
List<Inventory> inventoryList = inventories.stream()
|
||||
.map(this::mapToInventory)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"InventoryController.displayInventory",
|
||||
e,
|
||||
"Fetching inventory data for table display");
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
}
|
||||
tvInventory.setItems(data);
|
||||
Platform.runLater(() -> {
|
||||
data.setAll(inventoryList);
|
||||
tvInventory.setItems(data);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
ActivityLogger.getInstance().logException(
|
||||
"InventoryController.displayInventory",
|
||||
e,
|
||||
"Fetching inventory data for table display");
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
//Opens inventory-dialog-view
|
||||
private void openDialog(Inventory inventory, String mode) {
|
||||
//Opens FXML
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/inventory-dialog-view.fxml"));
|
||||
Scene scene = null;
|
||||
|
||||
try {
|
||||
scene = new Scene(fxmlLoader.load());
|
||||
}
|
||||
|
||||
catch (IOException e) {
|
||||
} catch (IOException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"InventoryController.openDialog",
|
||||
e,
|
||||
"Loading inventory dialog in " + mode + " mode");
|
||||
String.format("Loading inventory dialog view in %s mode", mode));
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
//Passes data and mode to the view
|
||||
InventoryDialogController dialogController = fxmlLoader.getController();
|
||||
dialogController.setMode(mode);
|
||||
|
||||
@@ -256,10 +223,22 @@ public class InventoryController {
|
||||
dialogStage.setScene(scene);
|
||||
dialogStage.showAndWait();
|
||||
|
||||
//Refresh inventory
|
||||
displayInventory();
|
||||
btnDelete.setDisable(true);
|
||||
btnEdit.setDisable(true);
|
||||
txtSearch.setText("");
|
||||
}
|
||||
|
||||
private Inventory mapToInventory(InventoryResponse response) {
|
||||
return new Inventory(
|
||||
response.getId().intValue(),
|
||||
0,
|
||||
response.getProductName(),
|
||||
response.getCategoryName() != null ? response.getCategoryName() : "",
|
||||
0,
|
||||
response.getStoreName() != null ? response.getStoreName() : "",
|
||||
response.getStockQuantity() != null ? response.getStockQuantity() : 0,
|
||||
response.getReorderLevel() != null ? response.getReorderLevel() : 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.example.petshopdesktop.controllers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
@@ -10,19 +11,16 @@ import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.DTOs.ProductDTO;
|
||||
import org.example.petshopdesktop.DTOs.ProductSupplierDTO;
|
||||
import org.example.petshopdesktop.controllers.dialogcontrollers.ProductDialogController;
|
||||
import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.ProductSupplierApi;
|
||||
import org.example.petshopdesktop.controllers.dialogcontrollers.ProductSupplierDialogController;
|
||||
import org.example.petshopdesktop.database.ProductDB;
|
||||
import org.example.petshopdesktop.database.ProductSupplierDB;
|
||||
import org.example.petshopdesktop.models.ProductSupplier;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLIntegrityConstraintViolationException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ProductSupplierController {
|
||||
|
||||
@@ -107,22 +105,27 @@ public class ProductSupplierController {
|
||||
* Display the ProductSupplierDTO to table view
|
||||
*/
|
||||
private void displayProductSupplier() {
|
||||
//Erase old content
|
||||
data.clear();
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<ProductSupplierResponse> productSuppliers = ProductSupplierApi.getInstance().listProductSuppliers(null);
|
||||
List<ProductSupplierDTO> productSupplierDTOs = productSuppliers.stream()
|
||||
.map(this::mapToProductSupplierDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
//get ProductSupplier from database
|
||||
try{
|
||||
data = ProductSupplierDB.getProductSupplierDTO();
|
||||
} catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierController.displayProductSupplier",
|
||||
e,
|
||||
"Fetching product-supplier data for table display");
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
}
|
||||
|
||||
//put data in the table
|
||||
tvProductSuppliers.setItems(data);
|
||||
Platform.runLater(() -> {
|
||||
data.setAll(productSupplierDTOs);
|
||||
tvProductSuppliers.setItems(data);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierController.displayProductSupplier",
|
||||
e,
|
||||
"Fetching product-supplier data for table display");
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,22 +133,30 @@ public class ProductSupplierController {
|
||||
* @param filter word to filter table
|
||||
*/
|
||||
private void displayFilteredProductSupplier(String filter){
|
||||
data.clear();
|
||||
try{
|
||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
|
||||
displayProductSupplier(); //If search bar is empty just display everything
|
||||
}
|
||||
else{
|
||||
//Filter the using the keyword
|
||||
data = ProductSupplierDB.getFilteredProductSupplierDTO(filter);
|
||||
tvProductSuppliers.setItems(data);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierController.displayFilteredProductSupplier",
|
||||
e,
|
||||
"Filtering product-supplier data with filter: " + filter);
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
|
||||
displayProductSupplier();
|
||||
} else {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<ProductSupplierResponse> productSuppliers = ProductSupplierApi.getInstance().listProductSuppliers(filter);
|
||||
List<ProductSupplierDTO> productSupplierDTOs = productSuppliers.stream()
|
||||
.map(this::mapToProductSupplierDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
data.setAll(productSupplierDTOs);
|
||||
tvProductSuppliers.setItems(data);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierController.displayFilteredProductSupplier",
|
||||
e,
|
||||
"Filtering product-supplier data with filter: " + filter);
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,52 +192,24 @@ public class ProductSupplierController {
|
||||
|
||||
//if confirmed, start deletion
|
||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
StringBuilder errors = new StringBuilder();
|
||||
List<Long> ids = selectedProductSuppliers.stream()
|
||||
.map(ps -> (long) ps.getSupId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (ProductSupplierDTO productSupplier : selectedProductSuppliers) {
|
||||
try{
|
||||
int numRows = ProductSupplierDB.deleteProductSupplier(productSupplier.getSupId(), productSupplier.getProdId());
|
||||
if (numRows > 0) {
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
catch (SQLIntegrityConstraintViolationException e){
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierController.btnDeleteClicked",
|
||||
e,
|
||||
String.format("Attempting to delete product-supplier - SupID: %d, ProdID: %d - foreign key constraint",
|
||||
productSupplier.getSupId(), productSupplier.getProdId()));
|
||||
failCount++;
|
||||
errors.append(String.format("Product-Supplier '%s - %s' is referenced in another table\n",
|
||||
productSupplier.getProdName(), productSupplier.getSupCompany()));
|
||||
}
|
||||
catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierController.btnDeleteClicked",
|
||||
e,
|
||||
String.format("Attempting to delete product-supplier - SupID: %d, ProdID: %d",
|
||||
productSupplier.getSupId(), productSupplier.getProdId()));
|
||||
failCount++;
|
||||
errors.append(String.format("Failed to delete '%s - %s'\n",
|
||||
productSupplier.getProdName(), productSupplier.getSupCompany()));
|
||||
}
|
||||
}
|
||||
|
||||
//show results
|
||||
if (failCount > 0) {
|
||||
Alert alert = new Alert(Alert.AlertType.WARNING);
|
||||
alert.setHeaderText("Delete Operation Completed with Errors");
|
||||
alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s",
|
||||
successCount, failCount, errors.toString()));
|
||||
alert.showAndWait();
|
||||
} else if (successCount > 0) {
|
||||
try {
|
||||
ProductSupplierApi.getInstance().deleteProductSuppliers(ids);
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setHeaderText("Database Operation Confirmed");
|
||||
alert.setContentText("Successfully deleted " + successCount + " product-supplier(s)");
|
||||
alert.setContentText("Successfully deleted " + ids.size() + " product-supplier(s)");
|
||||
alert.showAndWait();
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierController.btnDeleteClicked",
|
||||
e,
|
||||
"Deleting product-suppliers");
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Delete Operation Failed");
|
||||
alert.setContentText(e.getMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
@@ -297,4 +280,14 @@ public class ProductSupplierController {
|
||||
txtSearch.setText("");
|
||||
}
|
||||
|
||||
private ProductSupplierDTO mapToProductSupplierDTO(ProductSupplierResponse response) {
|
||||
return new ProductSupplierDTO(
|
||||
response.getSupplierId().intValue(),
|
||||
response.getProductId().intValue(),
|
||||
response.getSupplierName(),
|
||||
response.getProductName(),
|
||||
response.getSupplierPrice().doubleValue()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.example.petshopdesktop.controllers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
@@ -7,9 +8,13 @@ import javafx.fxml.FXML;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import org.example.petshopdesktop.DTOs.PurchaseOrderDTO;
|
||||
import org.example.petshopdesktop.database.PurchaseOrderDB;
|
||||
import org.example.petshopdesktop.api.dto.purchaseorder.PurchaseOrderResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.PurchaseOrderApi;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PurchaseOrderController {
|
||||
|
||||
@FXML private Button btnRefresh;
|
||||
@@ -19,7 +24,7 @@ public class PurchaseOrderController {
|
||||
|
||||
@FXML private TableView<PurchaseOrderDTO> tvPurchaseOrders;
|
||||
|
||||
@FXML private TableColumn<PurchaseOrderDTO,Integer> colOrderId;
|
||||
@FXML private TableColumn<PurchaseOrderDTO,Long> colOrderId;
|
||||
@FXML private TableColumn<PurchaseOrderDTO,String> colSupplier;
|
||||
@FXML private TableColumn<PurchaseOrderDTO,String> colOrderDate;
|
||||
@FXML private TableColumn<PurchaseOrderDTO,String> colStatus;
|
||||
@@ -53,17 +58,28 @@ public class PurchaseOrderController {
|
||||
}
|
||||
|
||||
private void loadPurchaseOrders() {
|
||||
try {
|
||||
purchaseOrders.setAll(PurchaseOrderDB.getPurchaseOrders());
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"PurchaseOrderController.loadPurchaseOrders",
|
||||
e,
|
||||
"Loading purchase orders for table display");
|
||||
e.printStackTrace();
|
||||
new Alert(Alert.AlertType.ERROR,
|
||||
"Unable to load purchase orders").showAndWait();
|
||||
}
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<PurchaseOrderResponse> responses = PurchaseOrderApi.getInstance().listPurchaseOrders(null);
|
||||
List<PurchaseOrderDTO> dtos = responses.stream()
|
||||
.map(this::mapToPurchaseOrderDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
purchaseOrders.setAll(dtos);
|
||||
tvPurchaseOrders.setItems(filtered);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"PurchaseOrderController.loadPurchaseOrders",
|
||||
e,
|
||||
"Loading purchase orders for table display");
|
||||
new Alert(Alert.AlertType.ERROR,
|
||||
"Unable to load purchase orders").showAndWait();
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void applyFilter(String text) {
|
||||
@@ -93,4 +109,13 @@ public class PurchaseOrderController {
|
||||
void btnRefresh() {
|
||||
loadPurchaseOrders();
|
||||
}
|
||||
|
||||
private PurchaseOrderDTO mapToPurchaseOrderDTO(PurchaseOrderResponse response) {
|
||||
return new PurchaseOrderDTO(
|
||||
response.getId(),
|
||||
response.getSupplierName(),
|
||||
response.getOrderDate() != null ? response.getOrderDate().toString() : "",
|
||||
response.getOrderStatus()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -22,20 +22,25 @@ import javafx.scene.layout.VBox;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.auth.UserSession;
|
||||
import org.example.petshopdesktop.database.InventoryDB;
|
||||
import org.example.petshopdesktop.database.ProductDB;
|
||||
import org.example.petshopdesktop.database.SaleDB;
|
||||
import org.example.petshopdesktop.models.Inventory;
|
||||
import javafx.concurrent.Task;
|
||||
import org.example.petshopdesktop.api.endpoints.ProductApi;
|
||||
import org.example.petshopdesktop.api.endpoints.SaleApi;
|
||||
import org.example.petshopdesktop.api.dto.product.ProductResponse;
|
||||
import org.example.petshopdesktop.api.dto.sale.SaleItemRequest;
|
||||
import org.example.petshopdesktop.api.dto.sale.SaleItemResponse;
|
||||
import org.example.petshopdesktop.api.dto.sale.SaleRequest;
|
||||
import org.example.petshopdesktop.api.dto.sale.SaleResponse;
|
||||
import org.example.petshopdesktop.models.Product;
|
||||
import org.example.petshopdesktop.models.SaleCartItem;
|
||||
import org.example.petshopdesktop.models.SaleLineItem;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.HashMap;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class SaleController {
|
||||
|
||||
@@ -124,8 +129,8 @@ public class SaleController {
|
||||
private final ObservableList<SaleLineItem> saleItems = FXCollections.observableArrayList();
|
||||
private FilteredList<SaleLineItem> filteredSales;
|
||||
|
||||
private final Map<Integer, Integer> inventoryByProdId = new HashMap<>();
|
||||
private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA);
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
@@ -133,7 +138,6 @@ public class SaleController {
|
||||
setupCreateSale();
|
||||
applyRoleMode();
|
||||
|
||||
refreshInventory();
|
||||
refreshSales();
|
||||
}
|
||||
|
||||
@@ -170,11 +174,20 @@ public class SaleController {
|
||||
updateCartTotal();
|
||||
|
||||
try {
|
||||
cbProduct.setItems(ProductDB.getProducts());
|
||||
} catch (SQLException e) {
|
||||
List<ProductResponse> productResponses = ProductApi.getInstance().listProducts(null);
|
||||
ObservableList<Product> products = FXCollections.observableArrayList();
|
||||
for (ProductResponse pr : productResponses) {
|
||||
products.add(new Product(
|
||||
pr.getId().intValue(),
|
||||
pr.getProductName(),
|
||||
pr.getPrice().doubleValue(),
|
||||
0,
|
||||
pr.getDescription()
|
||||
));
|
||||
}
|
||||
cbProduct.setItems(products);
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException("SaleController.setupCreateSale", e, "Loading products");
|
||||
} catch (RuntimeException e) {
|
||||
ActivityLogger.getInstance().logException("SaleController.setupCreateSale", e, "Database connection");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,42 +198,59 @@ public class SaleController {
|
||||
lblModeNote.setText(isAdmin ? "(View only)" : "(Staff can create sales)");
|
||||
}
|
||||
|
||||
private void refreshInventory() {
|
||||
inventoryByProdId.clear();
|
||||
try {
|
||||
for (Inventory inv : InventoryDB.getInventory()) {
|
||||
inventoryByProdId.put(inv.getProdId(), inv.getQuantity());
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException("SaleController.refreshInventory", e, "Loading inventory");
|
||||
} catch (RuntimeException e) {
|
||||
ActivityLogger.getInstance().logException("SaleController.refreshInventory", e, "Database connection");
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshSales() {
|
||||
refreshSales(false);
|
||||
}
|
||||
|
||||
private void refreshSales(boolean showErrorDialog) {
|
||||
try {
|
||||
saleItems.setAll(SaleDB.getSaleLineItems());
|
||||
} catch (SQLException e) {
|
||||
Task<List<SaleLineItem>> task = new Task<List<SaleLineItem>>() {
|
||||
@Override
|
||||
protected List<SaleLineItem> call() throws Exception {
|
||||
List<SaleResponse> sales = SaleApi.getInstance().listSales(0, 1000, null);
|
||||
List<SaleLineItem> lineItems = new ArrayList<>();
|
||||
|
||||
for (SaleResponse sale : sales) {
|
||||
String saleDate = sale.getSaleDate() != null
|
||||
? sale.getSaleDate().format(DATE_FORMATTER)
|
||||
: "";
|
||||
|
||||
if (sale.getItems() != null && !sale.getItems().isEmpty()) {
|
||||
for (SaleItemResponse item : sale.getItems()) {
|
||||
lineItems.add(new SaleLineItem(
|
||||
sale.getId().intValue(),
|
||||
saleDate,
|
||||
sale.getEmployeeName(),
|
||||
item.getProductName(),
|
||||
item.getQuantity(),
|
||||
item.getUnitPrice().doubleValue(),
|
||||
item.getLineTotal().doubleValue(),
|
||||
sale.getPaymentMethod(),
|
||||
sale.getIsRefund() != null && sale.getIsRefund()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
return lineItems;
|
||||
}
|
||||
};
|
||||
|
||||
task.setOnSucceeded(event -> {
|
||||
saleItems.setAll(task.getValue());
|
||||
});
|
||||
|
||||
task.setOnFailed(event -> {
|
||||
Throwable e = task.getException();
|
||||
ActivityLogger.getInstance().logException("SaleController.refreshSales", e, "Loading sales");
|
||||
if (showErrorDialog) {
|
||||
showError("Sales", "Could not load sales.");
|
||||
showError("Sales", "Could not load sales: " + e.getMessage());
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
ActivityLogger.getInstance().logException("SaleController.refreshSales", e, "Database connection");
|
||||
if (showErrorDialog) {
|
||||
showError("Sales", "Database is not connected.");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
new Thread(task).start();
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnRefresh(ActionEvent event) {
|
||||
refreshInventory();
|
||||
refreshSales(true);
|
||||
}
|
||||
|
||||
@@ -244,18 +274,6 @@ public class SaleController {
|
||||
return;
|
||||
}
|
||||
|
||||
int stock = inventoryByProdId.getOrDefault(product.getProdId(), 0);
|
||||
int alreadyInCart = cartItems.stream()
|
||||
.filter(i -> i.getProdId() == product.getProdId())
|
||||
.mapToInt(SaleCartItem::getQuantity)
|
||||
.sum();
|
||||
|
||||
int available = stock - alreadyInCart;
|
||||
if (requestedQty > available) {
|
||||
showError("Create Sale", "Not enough stock. Available: " + Math.max(0, available));
|
||||
return;
|
||||
}
|
||||
|
||||
for (SaleCartItem item : cartItems) {
|
||||
if (item.getProdId() == product.getProdId()) {
|
||||
item.setQuantity(item.getQuantity() + requestedQty);
|
||||
@@ -291,9 +309,9 @@ public class SaleController {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer employeeId = UserSession.getInstance().getEmployeeId();
|
||||
if (employeeId == null || employeeId <= 0) {
|
||||
showError("Create Sale", "Employee is not set for this account.");
|
||||
Long storeId = UserSession.getInstance().getStoreId();
|
||||
if (storeId == null || storeId <= 0) {
|
||||
showError("Create Sale", "Store is not set for this account.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -309,20 +327,35 @@ public class SaleController {
|
||||
}
|
||||
|
||||
try {
|
||||
int saleId = SaleDB.createSale(employeeId, payment, cartItems);
|
||||
showInfo("Sale saved", "Sale ID " + saleId + " was created.");
|
||||
SaleRequest request = new SaleRequest();
|
||||
request.setStoreId(storeId);
|
||||
request.setPaymentMethod(payment);
|
||||
|
||||
List<SaleItemRequest> itemRequests = new ArrayList<>();
|
||||
for (SaleCartItem cartItem : cartItems) {
|
||||
SaleItemRequest itemRequest = new SaleItemRequest();
|
||||
itemRequest.setProductId((long) cartItem.getProdId());
|
||||
itemRequest.setQuantity(cartItem.getQuantity());
|
||||
itemRequest.setUnitPrice(BigDecimal.valueOf(cartItem.getUnitPrice()));
|
||||
itemRequests.add(itemRequest);
|
||||
}
|
||||
request.setItems(itemRequests);
|
||||
|
||||
SaleResponse response = SaleApi.getInstance().createSale(request);
|
||||
showInfo("Sale saved", "Sale ID " + response.getId() + " was created.");
|
||||
|
||||
cartItems.clear();
|
||||
updateCartTotal();
|
||||
|
||||
refreshInventory();
|
||||
refreshSales(true);
|
||||
} catch (SQLException e) {
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException("SaleController.btnSaveSale", e, "Creating sale");
|
||||
showError("Create Sale", e.getMessage() == null ? "Could not save the sale." : e.getMessage());
|
||||
} catch (RuntimeException e) {
|
||||
ActivityLogger.getInstance().logException("SaleController.btnSaveSale", e, "Database connection");
|
||||
showError("Create Sale", "Database is not connected.");
|
||||
String errorMsg = e.getMessage();
|
||||
if (errorMsg != null && errorMsg.contains("Insufficient inventory")) {
|
||||
showError("Create Sale", "Insufficient stock for one or more items.");
|
||||
} else {
|
||||
showError("Create Sale", errorMsg != null ? errorMsg : "Could not save the sale.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.example.petshopdesktop.controllers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
@@ -10,12 +10,17 @@ import javafx.scene.Scene;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.database.ServiceDB;
|
||||
import org.example.petshopdesktop.models.Service;
|
||||
import org.example.petshopdesktop.DTOs.ServiceDTO;
|
||||
import org.example.petshopdesktop.api.dto.service.ServiceResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.ServiceApi;
|
||||
import org.example.petshopdesktop.controllers.dialogcontrollers.ServiceDialogController;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
import javafx.stage.Modality;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class ServiceController {
|
||||
|
||||
@@ -23,22 +28,23 @@ public class ServiceController {
|
||||
@FXML private Button btnDelete;
|
||||
@FXML private Button btnEdit;
|
||||
|
||||
@FXML private TableColumn<Service, Integer> colServiceId;
|
||||
@FXML private TableColumn<Service, String> colServiceName;
|
||||
@FXML private TableColumn<Service, String> colServiceDesc;
|
||||
@FXML private TableColumn<Service, Integer> colServiceDuration;
|
||||
@FXML private TableColumn<Service, Double> colServicePrice;
|
||||
@FXML private TableColumn<ServiceDTO, Integer> colServiceId;
|
||||
@FXML private TableColumn<ServiceDTO, String> colServiceName;
|
||||
@FXML private TableColumn<ServiceDTO, String> colServiceDesc;
|
||||
@FXML private TableColumn<ServiceDTO, Integer> colServiceDuration;
|
||||
@FXML private TableColumn<ServiceDTO, Double> colServicePrice;
|
||||
|
||||
@FXML private TableView<Service> tvServices;
|
||||
@FXML private TableView<ServiceDTO> tvServices;
|
||||
|
||||
@FXML private TextField txtSearch;
|
||||
|
||||
private final ObservableList<Service> services = FXCollections.observableArrayList();
|
||||
private FilteredList<Service> filtered;
|
||||
private ObservableList<ServiceDTO> data = FXCollections.observableArrayList();
|
||||
private String mode = null;
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
//Enable multiple selection
|
||||
btnEdit.setDisable(true);
|
||||
btnDelete.setDisable(true);
|
||||
tvServices.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE);
|
||||
|
||||
colServiceId.setCellValueFactory(new PropertyValueFactory<>("serviceId"));
|
||||
@@ -47,14 +53,19 @@ public class ServiceController {
|
||||
colServiceDuration.setCellValueFactory(new PropertyValueFactory<>("serviceDuration"));
|
||||
colServicePrice.setCellValueFactory(new PropertyValueFactory<>("servicePrice"));
|
||||
|
||||
filtered = new FilteredList<>(services, s -> true);
|
||||
tvServices.setItems(filtered);
|
||||
displayServices();
|
||||
|
||||
if (txtSearch != null) {
|
||||
txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n));
|
||||
}
|
||||
tvServices.getSelectionModel().selectedItemProperty().addListener(
|
||||
(observable, oldValue, newValue) -> {
|
||||
btnEdit.setDisable(false);
|
||||
btnDelete.setDisable(false);
|
||||
}
|
||||
);
|
||||
|
||||
txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
displayFilteredServices(newValue);
|
||||
});
|
||||
|
||||
//EventListener for DELETE key
|
||||
tvServices.setOnKeyPressed(event -> {
|
||||
if (event.getCode() == javafx.scene.input.KeyCode.DELETE) {
|
||||
if (tvServices.getSelectionModel().getSelectedItem() != null) {
|
||||
@@ -62,75 +73,82 @@ public class ServiceController {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
loadServices();
|
||||
}
|
||||
|
||||
private void loadServices() {
|
||||
try {
|
||||
services.setAll(ServiceDB.getServices());
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ServiceController.loadServices",
|
||||
e,
|
||||
"Loading services for table display");
|
||||
showAlert("Database Error", "Unable to load services.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
private void displayServices() {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<ServiceResponse> services = ServiceApi.getInstance().listServices(null);
|
||||
List<ServiceDTO> serviceDTOs = services.stream()
|
||||
.map(this::mapToServiceDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
data.setAll(serviceDTOs);
|
||||
tvServices.setItems(data);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ServiceController.displayServices",
|
||||
e,
|
||||
"Fetching service data for table display");
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void applyFilter(String text) {
|
||||
if (filtered == null) {
|
||||
return;
|
||||
private void displayFilteredServices(String filter) {
|
||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) {
|
||||
displayServices();
|
||||
} else {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<ServiceResponse> services = ServiceApi.getInstance().listServices(filter);
|
||||
List<ServiceDTO> serviceDTOs = services.stream()
|
||||
.map(this::mapToServiceDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
data.setAll(serviceDTOs);
|
||||
tvServices.setItems(data);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ServiceController.displayFilteredServices",
|
||||
e,
|
||||
String.format("Filtering services with keyword: %s", filter));
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
String q = text == null ? "" : text.trim().toLowerCase();
|
||||
if (q.isEmpty()) {
|
||||
filtered.setPredicate(s -> true);
|
||||
return;
|
||||
}
|
||||
|
||||
filtered.setPredicate(s ->
|
||||
String.valueOf(s.getServiceId()).contains(q)
|
||||
|| safe(s.getServiceName()).contains(q)
|
||||
|| safe(s.getServiceDesc()).contains(q)
|
||||
|| String.valueOf(s.getServiceDuration()).contains(q)
|
||||
|| String.valueOf(s.getServicePrice()).contains(q)
|
||||
);
|
||||
}
|
||||
|
||||
private static String safe(String v) {
|
||||
return v == null ? "" : v.toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
@FXML
|
||||
void btnAddClicked(ActionEvent event) {
|
||||
openDialog(null, "Add");
|
||||
loadServices();
|
||||
mode = "Add";
|
||||
openDialog(null, mode);
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnEditClicked(ActionEvent event) {
|
||||
ServiceDTO selected = tvServices.getSelectionModel().getSelectedItem();
|
||||
|
||||
Service selected = tvServices.getSelectionModel().getSelectedItem();
|
||||
|
||||
if (selected == null) {
|
||||
showAlert("Select Service", "Please select a service to edit.");
|
||||
return;
|
||||
if (selected != null) {
|
||||
mode = "Edit";
|
||||
openDialog(selected, mode);
|
||||
}
|
||||
|
||||
openDialog(selected, "Edit");
|
||||
loadServices();
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnDeleteClicked(ActionEvent e) {
|
||||
//get selected services
|
||||
void btnDeleteClicked(ActionEvent event) {
|
||||
var selectedServices = tvServices.getSelectionModel().getSelectedItems();
|
||||
if (selectedServices.isEmpty()) return;
|
||||
|
||||
//ask user to confirm
|
||||
Alert question = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
question.setHeaderText("Please confirm delete");
|
||||
String message = selectedServices.size() == 1
|
||||
@@ -138,82 +156,78 @@ public class ServiceController {
|
||||
: "Are you sure you want to delete " + selectedServices.size() + " services?";
|
||||
question.setContentText(message);
|
||||
question.getDialogPane().lookupButton(ButtonType.OK).requestFocus();
|
||||
java.util.Optional<ButtonType> result = question.showAndWait();
|
||||
Optional<ButtonType> result = question.showAndWait();
|
||||
|
||||
//if confirmed, start deletion
|
||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
StringBuilder errors = new StringBuilder();
|
||||
List<Long> ids = selectedServices.stream()
|
||||
.map(s -> (long) s.getServiceId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (Service service : selectedServices) {
|
||||
try {
|
||||
ServiceDB.deleteService(service.getServiceId());
|
||||
successCount++;
|
||||
} catch (Exception ex) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ServiceController.btnDeleteClicked",
|
||||
ex,
|
||||
String.format("Attempting to delete service ID %d", service.getServiceId()));
|
||||
failCount++;
|
||||
errors.append("Failed to delete '").append(service.getServiceName()).append("'\n");
|
||||
}
|
||||
}
|
||||
|
||||
//show results
|
||||
if (failCount > 0) {
|
||||
Alert alert = new Alert(Alert.AlertType.WARNING);
|
||||
alert.setHeaderText("Delete Operation Completed with Errors");
|
||||
alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s",
|
||||
successCount, failCount, errors.toString()));
|
||||
alert.showAndWait();
|
||||
} else if (successCount > 0) {
|
||||
try {
|
||||
ServiceApi.getInstance().deleteServices(ids);
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setHeaderText("Database Operation Confirmed");
|
||||
alert.setContentText("Successfully deleted " + successCount + " service(s)");
|
||||
alert.setContentText("Successfully deleted " + ids.size() + " service(s)");
|
||||
alert.showAndWait();
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ServiceController.btnDeleteClicked",
|
||||
e,
|
||||
"Deleting services");
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Delete Operation Failed");
|
||||
alert.setContentText(e.getMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
//refresh display
|
||||
loadServices();
|
||||
displayServices();
|
||||
btnDelete.setDisable(true);
|
||||
btnEdit.setDisable(true);
|
||||
txtSearch.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
private void openDialog(Service service, String mode) {
|
||||
|
||||
private void openDialog(ServiceDTO service, String mode) {
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml"));
|
||||
Scene scene = null;
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(
|
||||
getClass().getResource("/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml")
|
||||
);
|
||||
|
||||
Stage stage = new Stage();
|
||||
stage.setScene(new Scene(loader.load()));
|
||||
|
||||
ServiceDialogController controller = loader.getController();
|
||||
controller.setMode(mode);
|
||||
|
||||
if (mode.equals("Edit")) {
|
||||
controller.setService(service);
|
||||
}
|
||||
|
||||
stage.initModality(Modality.APPLICATION_MODAL);
|
||||
stage.showAndWait();
|
||||
|
||||
loadServices();
|
||||
|
||||
scene = new Scene(fxmlLoader.load());
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ServiceController.openDialog",
|
||||
e,
|
||||
"Opening service dialog in " + mode + " mode");
|
||||
e.printStackTrace();
|
||||
String.format("Loading service dialog view in %s mode", mode));
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ServiceDialogController dialogController = fxmlLoader.getController();
|
||||
dialogController.setMode(mode);
|
||||
|
||||
if (mode.equals("Edit")) {
|
||||
dialogController.setService(service);
|
||||
}
|
||||
Stage dialogStage = new Stage();
|
||||
dialogStage.initModality(Modality.APPLICATION_MODAL);
|
||||
if (mode.equals("Add")) {
|
||||
dialogStage.setTitle("Add Service");
|
||||
} else {
|
||||
dialogStage.setTitle("Edit Service");
|
||||
}
|
||||
dialogStage.setScene(scene);
|
||||
dialogStage.showAndWait();
|
||||
|
||||
displayServices();
|
||||
btnDelete.setDisable(true);
|
||||
btnEdit.setDisable(true);
|
||||
txtSearch.setText("");
|
||||
}
|
||||
private void showAlert(String title, String msg) {
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setTitle(title);
|
||||
alert.setHeaderText(null);
|
||||
alert.setContentText(msg);
|
||||
alert.showAndWait();
|
||||
|
||||
private ServiceDTO mapToServiceDTO(ServiceResponse response) {
|
||||
return new ServiceDTO(
|
||||
response.getId().intValue(),
|
||||
response.getServiceName(),
|
||||
response.getDescription(),
|
||||
0,
|
||||
response.getPrice().doubleValue()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.example.petshopdesktop.controllers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
@@ -15,12 +16,16 @@ import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.api.dto.user.UserResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.UserApi;
|
||||
import org.example.petshopdesktop.auth.UserSession;
|
||||
import org.example.petshopdesktop.database.UserDB;
|
||||
import org.example.petshopdesktop.models.StaffAccount;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.ZoneId;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class StaffAccountsController {
|
||||
|
||||
@@ -107,15 +112,54 @@ public class StaffAccountsController {
|
||||
|
||||
private void refresh() {
|
||||
lblError.setText("");
|
||||
try {
|
||||
staffAccounts.setAll(UserDB.getStaffAccounts());
|
||||
} catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Loading staff accounts");
|
||||
lblError.setText("Could not load staff accounts.");
|
||||
} catch (RuntimeException e) {
|
||||
ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Database connection");
|
||||
lblError.setText("Database is not connected.");
|
||||
tvStaff.setDisable(true);
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<UserResponse> users = UserApi.getInstance().listUsers(null);
|
||||
List<StaffAccount> accounts = users.stream()
|
||||
.map(this::mapToStaffAccount)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
staffAccounts.setAll(accounts);
|
||||
tvStaff.setDisable(false);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Loading staff accounts");
|
||||
Platform.runLater(() -> {
|
||||
lblError.setText("Could not load staff accounts.");
|
||||
tvStaff.setDisable(false);
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private StaffAccount mapToStaffAccount(UserResponse user) {
|
||||
long id = user.getId() != null ? user.getId() : 0L;
|
||||
String username = user.getUsername();
|
||||
String fullName = user.getFullName() != null ? user.getFullName() : "";
|
||||
String[] names = splitFullName(fullName);
|
||||
String firstName = names[0];
|
||||
String lastName = names[1];
|
||||
String email = "";
|
||||
String phone = "";
|
||||
boolean active = user.getActive() != null ? user.getActive() : false;
|
||||
Timestamp createdAt = user.getCreatedAt() != null
|
||||
? Timestamp.from(user.getCreatedAt().atZone(ZoneId.systemDefault()).toInstant())
|
||||
: null;
|
||||
|
||||
return new StaffAccount(id, id, username, firstName, lastName, email, phone, active, createdAt);
|
||||
}
|
||||
|
||||
private String[] splitFullName(String fullName) {
|
||||
if (fullName == null || fullName.trim().isEmpty()) {
|
||||
return new String[]{"", ""};
|
||||
}
|
||||
String[] parts = fullName.trim().split("\\s+", 2);
|
||||
String firstName = parts.length > 0 ? parts[0] : "";
|
||||
String lastName = parts.length > 1 ? parts[1] : "";
|
||||
return new String[]{firstName, lastName};
|
||||
}
|
||||
|
||||
private void applyFilter(String text) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.example.petshopdesktop.controllers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
@@ -10,15 +11,16 @@ import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.api.dto.supplier.SupplierResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.SupplierApi;
|
||||
import org.example.petshopdesktop.controllers.dialogcontrollers.SupplierDialogController;
|
||||
import org.example.petshopdesktop.database.SupplierDB;
|
||||
import org.example.petshopdesktop.models.Supplier;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLIntegrityConstraintViolationException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* The controller for any operations in the supplier view
|
||||
@@ -105,19 +107,27 @@ public class SupplierController {
|
||||
* Display the suppliers to table view
|
||||
*/
|
||||
private void displaySupplier(){
|
||||
data.clear();
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<SupplierResponse> suppliers = SupplierApi.getInstance().listSuppliers(null);
|
||||
List<Supplier> supplierList = suppliers.stream()
|
||||
.map(this::mapToSupplier)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
try{
|
||||
data = SupplierDB.getSuppliers();
|
||||
} catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"SupplierController.displaySupplier",
|
||||
e,
|
||||
"Fetching supplier data for table display");
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
}
|
||||
|
||||
tvSuppliers.setItems(data);
|
||||
Platform.runLater(() -> {
|
||||
data.setAll(supplierList);
|
||||
tvSuppliers.setItems(data);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
ActivityLogger.getInstance().logException(
|
||||
"SupplierController.displaySupplier",
|
||||
e,
|
||||
"Fetching supplier data for table display");
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,22 +135,30 @@ public class SupplierController {
|
||||
* @param filter word to filter table
|
||||
*/
|
||||
private void displayFilteredSupplier(String filter){
|
||||
data.clear();
|
||||
try{
|
||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
|
||||
displaySupplier(); //If search bar is empty just display everything
|
||||
}
|
||||
else{
|
||||
//Filter the using the keyword
|
||||
data = SupplierDB.getFilteredSuppliers(filter);
|
||||
tvSuppliers.setItems(data);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"SupplierController.displayFilteredSupplier",
|
||||
e,
|
||||
"Filtering suppliers with filter: " + filter);
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
|
||||
displaySupplier();
|
||||
} else {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<SupplierResponse> suppliers = SupplierApi.getInstance().listSuppliers(filter);
|
||||
List<Supplier> supplierList = suppliers.stream()
|
||||
.map(this::mapToSupplier)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
data.setAll(supplierList);
|
||||
tvSuppliers.setItems(data);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||
ActivityLogger.getInstance().logException(
|
||||
"SupplierController.displayFilteredSupplier",
|
||||
e,
|
||||
"Filtering suppliers with filter: " + filter);
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,48 +195,24 @@ public class SupplierController {
|
||||
|
||||
//if confirmed, start deletion
|
||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
StringBuilder errors = new StringBuilder();
|
||||
List<Long> ids = selectedSuppliers.stream()
|
||||
.map(s -> (long) s.getSupId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (Supplier supplier : selectedSuppliers) {
|
||||
try{
|
||||
int numRows = SupplierDB.deleteSupplier(supplier.getSupId());
|
||||
if (numRows > 0) {
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
catch (SQLIntegrityConstraintViolationException e){
|
||||
ActivityLogger.getInstance().logException(
|
||||
"SupplierController.btnDeleteClicked",
|
||||
e,
|
||||
String.format("Attempting to delete supplier ID %d - foreign key constraint", supplier.getSupId()));
|
||||
failCount++;
|
||||
errors.append("Supplier '").append(supplier.getSupCompany()).append("' is referenced in another table\n");
|
||||
}
|
||||
catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"SupplierController.btnDeleteClicked",
|
||||
e,
|
||||
String.format("Attempting to delete supplier ID %d", supplier.getSupId()));
|
||||
failCount++;
|
||||
errors.append("Failed to delete '").append(supplier.getSupCompany()).append("'\n");
|
||||
}
|
||||
}
|
||||
|
||||
//show results
|
||||
if (failCount > 0) {
|
||||
Alert alert = new Alert(Alert.AlertType.WARNING);
|
||||
alert.setHeaderText("Delete Operation Completed with Errors");
|
||||
alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s",
|
||||
successCount, failCount, errors.toString()));
|
||||
alert.showAndWait();
|
||||
} else if (successCount > 0) {
|
||||
try {
|
||||
SupplierApi.getInstance().deleteSuppliers(ids);
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setHeaderText("Database Operation Confirmed");
|
||||
alert.setContentText("Successfully deleted " + successCount + " supplier(s)");
|
||||
alert.setContentText("Successfully deleted " + ids.size() + " supplier(s)");
|
||||
alert.showAndWait();
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"SupplierController.btnDeleteClicked",
|
||||
e,
|
||||
"Deleting suppliers");
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Delete Operation Failed");
|
||||
alert.setContentText(e.getMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
@@ -290,4 +284,20 @@ public class SupplierController {
|
||||
txtSearch.setText("");
|
||||
}
|
||||
|
||||
private Supplier mapToSupplier(SupplierResponse response) {
|
||||
String contactPerson = response.getContactPerson() != null ? response.getContactPerson() : "";
|
||||
String[] nameParts = contactPerson.split(" ", 2);
|
||||
String firstName = nameParts.length > 0 ? nameParts[0] : "";
|
||||
String lastName = nameParts.length > 1 ? nameParts[1] : "";
|
||||
|
||||
return new Supplier(
|
||||
response.getId().intValue(),
|
||||
response.getSupplierName(),
|
||||
firstName,
|
||||
lastName,
|
||||
response.getEmail(),
|
||||
response.getPhone()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.EventHandler;
|
||||
@@ -12,16 +13,15 @@ import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.util.StringConverter;
|
||||
import org.example.petshopdesktop.database.AdoptionDB;
|
||||
import org.example.petshopdesktop.database.PetDB;
|
||||
import org.example.petshopdesktop.api.dto.adoption.AdoptionRequest;
|
||||
import org.example.petshopdesktop.api.dto.common.DropdownOption;
|
||||
import org.example.petshopdesktop.api.endpoints.AdoptionApi;
|
||||
import org.example.petshopdesktop.api.endpoints.DropdownApi;
|
||||
import org.example.petshopdesktop.models.Adoption;
|
||||
import org.example.petshopdesktop.models.Customer;
|
||||
import org.example.petshopdesktop.models.Pet;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public class AdoptionDialogController {
|
||||
|
||||
@@ -36,10 +36,10 @@ public class AdoptionDialogController {
|
||||
private ComboBox<String> cbAdoptionStatus;
|
||||
|
||||
@FXML
|
||||
private ComboBox<Customer> cbCustomer;
|
||||
private ComboBox<DropdownOption> cbCustomer;
|
||||
|
||||
@FXML
|
||||
private ComboBox<Pet> cbPet;
|
||||
private ComboBox<DropdownOption> cbPet;
|
||||
|
||||
@FXML
|
||||
private DatePicker dpAdoptionDate;
|
||||
@@ -58,52 +58,47 @@ public class AdoptionDialogController {
|
||||
"Pending", "Completed", "Cancelled"
|
||||
);
|
||||
|
||||
//Loads upon boot
|
||||
@FXML
|
||||
void initialize() {
|
||||
|
||||
//Loads statusList into combo box
|
||||
cbAdoptionStatus.setItems(statusList);
|
||||
|
||||
//Pet objects are converted into readable text for combobox (PetID + PetName)
|
||||
cbPet.setConverter(new StringConverter<Pet>() {
|
||||
@Override
|
||||
public String toString(Pet pet) {
|
||||
return pet == null ? "" : pet.getPetId() + ": " + pet.getPetName();
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<DropdownOption> pets = DropdownApi.getInstance().getPets();
|
||||
Platform.runLater(() -> {
|
||||
ObservableList<DropdownOption> petsObs = FXCollections.observableArrayList(pets);
|
||||
cbPet.setItems(petsObs);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionDialogController.initialize",
|
||||
e,
|
||||
"Loading pets for combo box");
|
||||
System.out.println("Error loading pets: " + e.getMessage());
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
|
||||
//Not used
|
||||
@Override
|
||||
public Pet fromString(String string) { return null; }
|
||||
});
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<DropdownOption> customers = DropdownApi.getInstance().getCustomers();
|
||||
Platform.runLater(() -> {
|
||||
ObservableList<DropdownOption> customersObs = FXCollections.observableArrayList(customers);
|
||||
cbCustomer.setItems(customersObs);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionDialogController.initialize",
|
||||
e,
|
||||
"Loading customers for combo box");
|
||||
System.out.println("Error loading customers: " + e.getMessage());
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
|
||||
//Load pets from DB into pet combobox
|
||||
try {
|
||||
cbPet.setItems(PetDB.getPets());
|
||||
}
|
||||
|
||||
catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionDialogController.initialize",
|
||||
e,
|
||||
"Loading pets for combo box");
|
||||
System.out.println("Error loading pets: " + e.getMessage());
|
||||
}
|
||||
|
||||
//Load customers from DB into customer combobox
|
||||
try {
|
||||
cbCustomer.setItems(AdoptionDB.getCustomers());
|
||||
}
|
||||
|
||||
catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionDialogController.initialize",
|
||||
e,
|
||||
"Loading customers for combo box");
|
||||
System.out.println("Error loading customers: " + e.getMessage());
|
||||
}
|
||||
|
||||
//Save button handler
|
||||
btnSave.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
||||
@Override
|
||||
public void handle(MouseEvent mouseEvent) {
|
||||
@@ -111,7 +106,6 @@ public class AdoptionDialogController {
|
||||
}
|
||||
});
|
||||
|
||||
//Cancel button handler, closes dialog view
|
||||
btnCancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
||||
@Override
|
||||
public void handle(MouseEvent mouseEvent) {
|
||||
@@ -120,12 +114,9 @@ public class AdoptionDialogController {
|
||||
});
|
||||
}
|
||||
|
||||
//Handles logic when clicking Save
|
||||
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
||||
int numRow = 0;
|
||||
String errorMsg = "";
|
||||
|
||||
//Validation: checks if anything is missing
|
||||
if (cbPet.getSelectionModel().getSelectedItem() == null) {
|
||||
errorMsg += "Pet is required.\n";
|
||||
}
|
||||
@@ -142,60 +133,37 @@ public class AdoptionDialogController {
|
||||
errorMsg += "Status is required.\n";
|
||||
}
|
||||
|
||||
//If no errors, attempt DB operation
|
||||
if (errorMsg.isEmpty()) {
|
||||
Adoption adoption = collectAdoption();
|
||||
try {
|
||||
AdoptionRequest request = new AdoptionRequest();
|
||||
request.setPetId(cbPet.getSelectionModel().getSelectedItem().getId());
|
||||
request.setCustomerId(cbCustomer.getSelectionModel().getSelectedItem().getId());
|
||||
request.setAdoptionDate(dpAdoptionDate.getValue());
|
||||
request.setAdoptionStatus(cbAdoptionStatus.getValue());
|
||||
|
||||
//Try inserting into DB
|
||||
if (mode.equals("Add")) {
|
||||
try {
|
||||
numRow = AdoptionDB.insertAdoption(adoption);
|
||||
if (mode.equals("Add")) {
|
||||
AdoptionApi.getInstance().createAdoption(request);
|
||||
} else {
|
||||
Long adoptionId = Long.parseLong(lblAdoptionId.getText().split(": ")[1]);
|
||||
AdoptionApi.getInstance().updateAdoption(adoptionId, request);
|
||||
}
|
||||
|
||||
catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionDialogController.buttonSaveClicked",
|
||||
e,
|
||||
"Inserting new adoption record");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//Try updating adoption
|
||||
else {
|
||||
try {
|
||||
numRow = AdoptionDB.updateAdoption(adoption.getAdoptionId(), adoption);
|
||||
}
|
||||
|
||||
catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionDialogController.buttonSaveClicked",
|
||||
e,
|
||||
"Updating adoption with ID: " + adoption.getAdoptionId());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//If no rows are affected, an issue has occurred
|
||||
if (numRow == 0) {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Database Operation Error");
|
||||
alert.setContentText(mode + " failed");
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
//DB operation worked!
|
||||
else {
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setHeaderText("Saved");
|
||||
alert.setContentText(mode + " succeeded");
|
||||
alert.showAndWait();
|
||||
closeStage(mouseEvent);
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AdoptionDialogController.buttonSaveClicked",
|
||||
e,
|
||||
mode + " adoption");
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Database Operation Error");
|
||||
alert.setContentText(e.getMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
//If there are errors, display them
|
||||
else {
|
||||
} else {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Input Error");
|
||||
alert.setContentText(errorMsg);
|
||||
@@ -203,30 +171,6 @@ public class AdoptionDialogController {
|
||||
}
|
||||
}
|
||||
|
||||
//Collects user input, builds an Adoption object
|
||||
private Adoption collectAdoption() {
|
||||
int adoptionId = 0;
|
||||
|
||||
//Only grab adoption ID if in edit mode
|
||||
if (lblAdoptionId.isVisible()) {
|
||||
adoptionId = Integer.parseInt(lblAdoptionId.getText().split(": ")[1]);
|
||||
}
|
||||
|
||||
Pet selectedPet = cbPet.getSelectionModel().getSelectedItem();
|
||||
Customer selectedCustomer = cbCustomer.getSelectionModel().getSelectedItem();
|
||||
String date = dpAdoptionDate.getValue().toString();
|
||||
String status = cbAdoptionStatus.getValue();
|
||||
|
||||
return new Adoption(
|
||||
adoptionId,
|
||||
selectedPet.getPetId(),
|
||||
selectedCustomer.getCustomerId(),
|
||||
selectedCustomer.toString(),
|
||||
date,
|
||||
selectedPet.getPetPrice(),
|
||||
status
|
||||
);
|
||||
}
|
||||
|
||||
private void closeStage(MouseEvent mouseEvent) {
|
||||
Node node = (Node) mouseEvent.getSource();
|
||||
@@ -234,35 +178,28 @@ public class AdoptionDialogController {
|
||||
stage.close();
|
||||
}
|
||||
|
||||
//Edit mode
|
||||
//Inserts data into fields
|
||||
public void displayAdoptionDetails(Adoption adoption) {
|
||||
if (adoption != null) {
|
||||
//Displays adoption ID
|
||||
lblAdoptionId.setText("ID: " + adoption.getAdoptionId());
|
||||
|
||||
//Select pet
|
||||
for (Pet pet : cbPet.getItems()) {
|
||||
if (pet.getPetId() == adoption.getPetId()) {
|
||||
for (DropdownOption pet : cbPet.getItems()) {
|
||||
if (pet.getLabel().equals(adoption.getPetName())) {
|
||||
cbPet.getSelectionModel().select(pet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Select customer
|
||||
for (Customer customer : cbCustomer.getItems()) {
|
||||
if (customer.getCustomerId() == adoption.getCustomerId()) {
|
||||
for (DropdownOption customer : cbCustomer.getItems()) {
|
||||
if (customer.getLabel().equals(adoption.getCustomerName())) {
|
||||
cbCustomer.getSelectionModel().select(customer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Select adoption date
|
||||
if (adoption.getAdoptionDate() != null && !adoption.getAdoptionDate().isEmpty()) {
|
||||
dpAdoptionDate.setValue(LocalDate.parse(adoption.getAdoptionDate()));
|
||||
}
|
||||
|
||||
//Select adoption status
|
||||
for (String status : cbAdoptionStatus.getItems()) {
|
||||
if (status.equals(adoption.getAdoptionStatus())) {
|
||||
cbAdoptionStatus.getSelectionModel().select(status);
|
||||
@@ -272,8 +209,6 @@ public class AdoptionDialogController {
|
||||
}
|
||||
}
|
||||
|
||||
//Sets dialog mode
|
||||
//Also updates label and adoption ID visibility
|
||||
public void setMode(String mode) {
|
||||
this.mode = mode;
|
||||
lblMode.setText(mode + " Adoption");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.fxml.FXML;
|
||||
@@ -10,11 +11,16 @@ import javafx.stage.Stage;
|
||||
import javafx.scene.control.ListCell;
|
||||
|
||||
import org.example.petshopdesktop.DTOs.AppointmentDTO;
|
||||
import org.example.petshopdesktop.database.*;
|
||||
import org.example.petshopdesktop.models.*;
|
||||
import org.example.petshopdesktop.api.dto.appointment.AppointmentRequest;
|
||||
import org.example.petshopdesktop.api.dto.appointment.AppointmentResponse;
|
||||
import org.example.petshopdesktop.api.dto.common.DropdownOption;
|
||||
import org.example.petshopdesktop.api.endpoints.AppointmentApi;
|
||||
import org.example.petshopdesktop.api.endpoints.DropdownApi;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.sql.Time;
|
||||
import java.time.LocalTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class AppointmentDialogController {
|
||||
|
||||
@@ -25,9 +31,9 @@ public class AppointmentDialogController {
|
||||
@FXML private Button btnCancel;
|
||||
@FXML private Button btnSave;
|
||||
|
||||
@FXML private ComboBox<Service> cbService;
|
||||
@FXML private ComboBox<Customer> cbCustomer;
|
||||
@FXML private ComboBox<Pet> cbPet;
|
||||
@FXML private ComboBox<DropdownOption> cbService;
|
||||
@FXML private ComboBox<DropdownOption> cbCustomer;
|
||||
@FXML private ComboBox<DropdownOption> cbPet;
|
||||
|
||||
@FXML private ComboBox<Integer> cbHour;
|
||||
@FXML private ComboBox<Integer> cbMinute;
|
||||
@@ -67,17 +73,27 @@ public class AppointmentDialogController {
|
||||
@FXML
|
||||
public void initialize() {
|
||||
|
||||
try {
|
||||
cbService.setItems(ServiceDB.getServices());
|
||||
cbCustomer.setItems(CustomerDB.getCustomers());
|
||||
cbPet.setItems(PetDB.getPets());
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AppointmentDialogController.initialize",
|
||||
e,
|
||||
"Loading combo box data for services, customers, and pets");
|
||||
e.printStackTrace();
|
||||
}
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<DropdownOption> services = DropdownApi.getInstance().getServices();
|
||||
List<DropdownOption> customers = DropdownApi.getInstance().getCustomers();
|
||||
List<DropdownOption> pets = DropdownApi.getInstance().getPets();
|
||||
|
||||
Platform.runLater(() -> {
|
||||
cbService.setItems(FXCollections.observableArrayList(services));
|
||||
cbCustomer.setItems(FXCollections.observableArrayList(customers));
|
||||
cbPet.setItems(FXCollections.observableArrayList(pets));
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AppointmentDialogController.initialize",
|
||||
e,
|
||||
"Loading combo box data for services, customers, and pets");
|
||||
e.printStackTrace();
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
|
||||
cbAppointmentStatus.setItems(statusList);
|
||||
|
||||
@@ -88,20 +104,49 @@ public class AppointmentDialogController {
|
||||
|
||||
cbMinute.getItems().addAll(0, 15, 30, 45);
|
||||
|
||||
// Show pet name
|
||||
cbPet.setCellFactory(param -> new ListCell<>() {
|
||||
// Show dropdown labels
|
||||
cbService.setCellFactory(param -> new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(Pet pet, boolean empty) {
|
||||
super.updateItem(pet, empty);
|
||||
setText(empty || pet == null ? null : pet.getPetName());
|
||||
protected void updateItem(DropdownOption option, boolean empty) {
|
||||
super.updateItem(option, empty);
|
||||
setText(empty || option == null ? null : option.getLabel());
|
||||
}
|
||||
});
|
||||
cbService.setButtonCell(new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(DropdownOption option, boolean empty) {
|
||||
super.updateItem(option, empty);
|
||||
setText(empty || option == null ? null : option.getLabel());
|
||||
}
|
||||
});
|
||||
|
||||
cbCustomer.setCellFactory(param -> new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(DropdownOption option, boolean empty) {
|
||||
super.updateItem(option, empty);
|
||||
setText(empty || option == null ? null : option.getLabel());
|
||||
}
|
||||
});
|
||||
cbCustomer.setButtonCell(new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(DropdownOption option, boolean empty) {
|
||||
super.updateItem(option, empty);
|
||||
setText(empty || option == null ? null : option.getLabel());
|
||||
}
|
||||
});
|
||||
|
||||
cbPet.setCellFactory(param -> new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(DropdownOption option, boolean empty) {
|
||||
super.updateItem(option, empty);
|
||||
setText(empty || option == null ? null : option.getLabel());
|
||||
}
|
||||
});
|
||||
cbPet.setButtonCell(new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(Pet pet, boolean empty) {
|
||||
super.updateItem(pet, empty);
|
||||
setText(empty || pet == null ? null : pet.getPetName());
|
||||
protected void updateItem(DropdownOption option, boolean empty) {
|
||||
super.updateItem(option, empty);
|
||||
setText(empty || option == null ? null : option.getLabel());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -124,20 +169,20 @@ public class AppointmentDialogController {
|
||||
|
||||
cbAppointmentStatus.setValue(appt.getAppointmentStatus());
|
||||
|
||||
Time time = Time.valueOf(appt.getAppointmentTime());
|
||||
cbHour.setValue(time.toLocalTime().getHour());
|
||||
cbMinute.setValue(time.toLocalTime().getMinute());
|
||||
LocalTime time = LocalTime.parse(appt.getAppointmentTime());
|
||||
cbHour.setValue(time.getHour());
|
||||
cbMinute.setValue(time.getMinute());
|
||||
|
||||
cbService.getItems().forEach(s -> {
|
||||
if (s.getServiceId() == appt.getServiceId()) cbService.setValue(s);
|
||||
if (s.getId() == appt.getServiceId()) cbService.setValue(s);
|
||||
});
|
||||
|
||||
cbCustomer.getItems().forEach(c -> {
|
||||
if (c.getCustomerId() == appt.getCustomerId()) cbCustomer.setValue(c);
|
||||
if (c.getId() == appt.getCustomerId()) cbCustomer.setValue(c);
|
||||
});
|
||||
|
||||
cbPet.getItems().forEach(p -> {
|
||||
if (p.getPetId() == appt.getPetId()) cbPet.setValue(p);
|
||||
if (p.getId() == appt.getPetId()) cbPet.setValue(p);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -159,45 +204,40 @@ public class AppointmentDialogController {
|
||||
return;
|
||||
}
|
||||
|
||||
Time appointmentTime =
|
||||
Time.valueOf(String.format(
|
||||
"%02d:%02d:00",
|
||||
cbHour.getValue(),
|
||||
cbMinute.getValue()
|
||||
));
|
||||
LocalTime appointmentTime = LocalTime.of(cbHour.getValue(), cbMinute.getValue());
|
||||
|
||||
Appointment appt = new Appointment(
|
||||
selectedAppointment == null ? 0 : selectedAppointment.getAppointmentId(),
|
||||
cbService.getValue().getServiceId(),
|
||||
cbCustomer.getValue().getCustomerId(),
|
||||
dpAppointmentDate.getValue().toString(),
|
||||
appointmentTime.toString(),
|
||||
cbAppointmentStatus.getValue()
|
||||
);
|
||||
AppointmentRequest request = new AppointmentRequest();
|
||||
request.setPetIds(Collections.singletonList(cbPet.getValue().getId()));
|
||||
request.setCustomerId(cbCustomer.getValue().getId());
|
||||
request.setServiceId(cbService.getValue().getId());
|
||||
request.setAppointmentDate(dpAppointmentDate.getValue());
|
||||
request.setAppointmentTime(appointmentTime);
|
||||
request.setAppointmentStatus(cbAppointmentStatus.getValue());
|
||||
|
||||
try {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
if (mode.equals("Add")) {
|
||||
AppointmentApi.getInstance().createAppointment(request);
|
||||
} else {
|
||||
AppointmentApi.getInstance().updateAppointment(
|
||||
(long) selectedAppointment.getAppointmentId(),
|
||||
request
|
||||
);
|
||||
}
|
||||
|
||||
if (mode.equals("Add")) {
|
||||
int newId = AppointmentDB.insertAppointment(appt);
|
||||
AppointmentDB.insertAppointmentPet(newId, cbPet.getValue().getPetId());
|
||||
} else {
|
||||
AppointmentDB.updateAppointment(
|
||||
selectedAppointment.getAppointmentId(),
|
||||
appt,
|
||||
cbPet.getValue().getPetId()
|
||||
);
|
||||
Platform.runLater(() -> closeStage(e));
|
||||
|
||||
} catch (Exception ex) {
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AppointmentDialogController.buttonSaveClicked",
|
||||
ex,
|
||||
"Saving appointment in " + mode + " mode");
|
||||
ex.printStackTrace();
|
||||
showError("Error saving appointment: " + ex.getMessage());
|
||||
});
|
||||
}
|
||||
|
||||
closeStage(e);
|
||||
|
||||
} catch (Exception ex) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"AppointmentDialogController.buttonSaveClicked",
|
||||
ex,
|
||||
"Saving appointment in " + mode + " mode");
|
||||
ex.printStackTrace();
|
||||
showError("Error saving appointment");
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.EventHandler;
|
||||
@@ -10,16 +11,14 @@ import javafx.scene.input.MouseEvent;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.DTOs.ProductSupplierDTO;
|
||||
import org.example.petshopdesktop.Validator;
|
||||
import org.example.petshopdesktop.database.ProductDB;
|
||||
import org.example.petshopdesktop.database.ProductSupplierDB;
|
||||
import org.example.petshopdesktop.database.SupplierDB;
|
||||
import org.example.petshopdesktop.models.Product;
|
||||
import org.example.petshopdesktop.models.ProductSupplier;
|
||||
import org.example.petshopdesktop.models.Supplier;
|
||||
import org.example.petshopdesktop.api.dto.common.DropdownOption;
|
||||
import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierRequest;
|
||||
import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.DropdownApi;
|
||||
import org.example.petshopdesktop.api.endpoints.ProductSupplierApi;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLIntegrityConstraintViolationException;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class ProductSupplierDialogController {
|
||||
|
||||
@@ -30,10 +29,10 @@ public class ProductSupplierDialogController {
|
||||
private Button btnSave;
|
||||
|
||||
@FXML
|
||||
private ComboBox<Product> cbProduct;
|
||||
private ComboBox<DropdownOption> cbProduct;
|
||||
|
||||
@FXML
|
||||
private ComboBox<Supplier> cbSupplier;
|
||||
private ComboBox<DropdownOption> cbSupplier;
|
||||
|
||||
@FXML
|
||||
private Label lblMode;
|
||||
@@ -47,6 +46,7 @@ public class ProductSupplierDialogController {
|
||||
private String mode = null;
|
||||
private int selectedSupId = -1;
|
||||
private int selectedProdId = -1;
|
||||
private Long selectedId = null;
|
||||
|
||||
/**
|
||||
* add event listeners to buttons and set up combobox
|
||||
@@ -67,26 +67,74 @@ public class ProductSupplierDialogController {
|
||||
}
|
||||
});
|
||||
|
||||
//Set up combobox for selecting product and supplier
|
||||
try{
|
||||
ObservableList<Supplier> suppliers = FXCollections.observableArrayList(); //empty list
|
||||
ObservableList<Product> products = FXCollections.observableArrayList(); //empty list
|
||||
cbSupplier.setButtonCell(new ListCell<DropdownOption>() {
|
||||
@Override
|
||||
protected void updateItem(DropdownOption item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setText(null);
|
||||
} else {
|
||||
setText(item.getLabel());
|
||||
}
|
||||
}
|
||||
});
|
||||
cbSupplier.setCellFactory(lv -> new ListCell<DropdownOption>() {
|
||||
@Override
|
||||
protected void updateItem(DropdownOption item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setText(null);
|
||||
} else {
|
||||
setText(item.getLabel());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//get suppliers and products from DB
|
||||
suppliers = SupplierDB.getSuppliers();
|
||||
products = ProductDB.getProducts();
|
||||
cbProduct.setButtonCell(new ListCell<DropdownOption>() {
|
||||
@Override
|
||||
protected void updateItem(DropdownOption item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setText(null);
|
||||
} else {
|
||||
setText(item.getLabel());
|
||||
}
|
||||
}
|
||||
});
|
||||
cbProduct.setCellFactory(lv -> new ListCell<DropdownOption>() {
|
||||
@Override
|
||||
protected void updateItem(DropdownOption item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setText(null);
|
||||
} else {
|
||||
setText(item.getLabel());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//Populate combobox
|
||||
cbSupplier.setItems(suppliers);
|
||||
cbProduct.setItems(products);
|
||||
}
|
||||
catch(SQLException e){
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierDialogController.initialize",
|
||||
e,
|
||||
"Loading suppliers and products for combo boxes");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
new Thread(() -> {
|
||||
try {
|
||||
var suppliers = DropdownApi.getInstance().getSuppliers();
|
||||
var products = DropdownApi.getInstance().getProducts();
|
||||
|
||||
Platform.runLater(() -> {
|
||||
cbSupplier.setItems(FXCollections.observableArrayList(suppliers));
|
||||
cbProduct.setItems(FXCollections.observableArrayList(products));
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierDialogController.initialize",
|
||||
e,
|
||||
"Loading suppliers and products for combo boxes");
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Initialization Error");
|
||||
alert.setContentText("Failed to load dropdown data: " + e.getMessage());
|
||||
alert.showAndWait();
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
|
||||
}
|
||||
|
||||
@@ -96,10 +144,8 @@ public class ProductSupplierDialogController {
|
||||
* @param mouseEvent click event for save button
|
||||
*/
|
||||
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
||||
int numRows = 0;
|
||||
String errorMsg = ""; //error message for validation
|
||||
String errorMsg = "";
|
||||
|
||||
//Check Validation (input required)
|
||||
errorMsg += Validator.isPresent(txtCost.getText(), "Cost");
|
||||
if (cbProduct.getSelectionModel().getSelectedItem() == null) {
|
||||
errorMsg += "Product is required \n";
|
||||
@@ -108,82 +154,41 @@ public class ProductSupplierDialogController {
|
||||
errorMsg += "Supplier is required \n";
|
||||
}
|
||||
|
||||
//Check validation (length size)
|
||||
errorMsg += Validator.isLessThanVarChars(txtCost.getText(), "Cost", 12);
|
||||
|
||||
//Check validation (format)
|
||||
errorMsg += Validator.isNonNegativeDouble(txtCost.getText(), "Cost");
|
||||
|
||||
if(errorMsg.isEmpty()){ //no validation errors
|
||||
ProductSupplier productSupplier = collectProductSupplier(); //get productSupplier info
|
||||
if (mode.equals("Add")) { //add mode
|
||||
try{
|
||||
numRows = ProductSupplierDB.insertProductSupplier(productSupplier);
|
||||
}
|
||||
catch(SQLIntegrityConstraintViolationException e){
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierDialogController.buttonSaveClicked",
|
||||
e,
|
||||
"Inserting product-supplier (integrity constraint violation)");
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Database Operation Error");
|
||||
alert.setContentText("Add failed \n" +
|
||||
"the product-supplier link is already in the database");
|
||||
alert.showAndWait();
|
||||
numRows = -1; //Update numRow so alert only shows once
|
||||
closeStage(mouseEvent);
|
||||
}
|
||||
catch(SQLException e){
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierDialogController.buttonSaveClicked",
|
||||
e,
|
||||
"Inserting new product-supplier record");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
else { //edit
|
||||
try{
|
||||
numRows = ProductSupplierDB.updateProductSupplier(selectedSupId, selectedProdId, productSupplier);
|
||||
}
|
||||
catch(SQLIntegrityConstraintViolationException e){
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierDialogController.buttonSaveClicked",
|
||||
e,
|
||||
"Updating product-supplier (integrity constraint violation) - SupID: " + selectedSupId + ", ProdID: " + selectedProdId);
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Database Operation Error");
|
||||
alert.setContentText("Edit failed \n" +
|
||||
"the product-supplier link is already in the database");
|
||||
alert.showAndWait();
|
||||
numRows = -1; //Update numRow so alert only shows once
|
||||
closeStage(mouseEvent);
|
||||
}
|
||||
catch(SQLException e){
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierDialogController.buttonSaveClicked",
|
||||
e,
|
||||
"Updating product-supplier - SupID: " + selectedSupId + ", ProdID: " + selectedProdId);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
if(errorMsg.isEmpty()){
|
||||
ProductSupplierRequest request = collectProductSupplierRequest();
|
||||
|
||||
//if no rows were affected then there was an error (prompt user of error)
|
||||
if (numRows == 0){
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Database Operation Error");
|
||||
alert.setContentText(mode + " failed");
|
||||
alert.showAndWait();
|
||||
}
|
||||
else if (numRows > 0){
|
||||
//tell the user operation was successful
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setHeaderText("Saved");
|
||||
alert.setContentText(mode + " succeeded");
|
||||
alert.showAndWait();
|
||||
closeStage(mouseEvent);
|
||||
}
|
||||
}
|
||||
else { //Display validation errors
|
||||
new Thread(() -> {
|
||||
try {
|
||||
if (mode.equals("Add")) {
|
||||
ProductSupplierApi.getInstance().createProductSupplier(request);
|
||||
} else {
|
||||
ProductSupplierApi.getInstance().updateProductSupplier(selectedId, request);
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setHeaderText("Saved");
|
||||
alert.setContentText(mode + " succeeded");
|
||||
alert.showAndWait();
|
||||
closeStage(mouseEvent);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"ProductSupplierDialogController.buttonSaveClicked",
|
||||
e,
|
||||
mode + " product-supplier");
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Database Operation Error");
|
||||
alert.setContentText(mode + " failed: " + e.getMessage());
|
||||
alert.showAndWait();
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
} else {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Input Error");
|
||||
alert.setContentText(errorMsg);
|
||||
@@ -193,18 +198,14 @@ public class ProductSupplierDialogController {
|
||||
|
||||
/**
|
||||
* collect the data for new/updated productSupplier
|
||||
* @return productSupplier entity with data
|
||||
* @return productSupplier request with data
|
||||
*/
|
||||
private ProductSupplier collectProductSupplier() {
|
||||
ProductSupplier productSupplier = null;
|
||||
|
||||
productSupplier = new ProductSupplier(
|
||||
cbSupplier.getSelectionModel().getSelectedItem().getSupId(),
|
||||
cbProduct.getSelectionModel().getSelectedItem().getProdId(),
|
||||
Double.parseDouble(txtCost.getText())
|
||||
);
|
||||
|
||||
return productSupplier;
|
||||
private ProductSupplierRequest collectProductSupplierRequest() {
|
||||
ProductSupplierRequest request = new ProductSupplierRequest();
|
||||
request.setSupplierId(cbSupplier.getSelectionModel().getSelectedItem().getId());
|
||||
request.setProductId(cbProduct.getSelectionModel().getSelectedItem().getId());
|
||||
request.setSupplierPrice(new BigDecimal(txtCost.getText()));
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,20 +217,17 @@ public class ProductSupplierDialogController {
|
||||
txtCost.setText(productSupplier.getCost() + "");
|
||||
}
|
||||
|
||||
//Get the right combobox selection (product)
|
||||
for (Product product : cbProduct.getItems()) {
|
||||
if(product.getProdId() == productSupplier.getProdId()){
|
||||
for (DropdownOption product : cbProduct.getItems()) {
|
||||
if(product.getId() == productSupplier.getProdId()){
|
||||
cbProduct.getSelectionModel().select(product);
|
||||
}
|
||||
}
|
||||
|
||||
//Get the right combobox selection (supplier)
|
||||
for (Supplier supplier : cbSupplier.getItems()) {
|
||||
if (supplier.getSupId() == productSupplier.getSupId()) {
|
||||
for (DropdownOption supplier : cbSupplier.getItems()) {
|
||||
if (supplier.getId() == productSupplier.getSupId()) {
|
||||
cbSupplier.getSelectionModel().select(supplier);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,6 +258,7 @@ public class ProductSupplierDialogController {
|
||||
public void setSelectedIds(int supId, int prodId){
|
||||
this.selectedSupId = supId;
|
||||
this.selectedProdId = prodId;
|
||||
this.selectedId = (long) supId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,15 +7,19 @@ import javafx.fxml.FXML;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.api.dto.sale.SaleItemRequest;
|
||||
import org.example.petshopdesktop.api.dto.sale.SaleItemResponse;
|
||||
import org.example.petshopdesktop.api.dto.sale.SaleRequest;
|
||||
import org.example.petshopdesktop.api.dto.sale.SaleResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.SaleApi;
|
||||
import org.example.petshopdesktop.auth.UserSession;
|
||||
import org.example.petshopdesktop.database.SaleDB;
|
||||
import org.example.petshopdesktop.models.SaleCartItem;
|
||||
import org.example.petshopdesktop.models.SaleDetail;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.NumberFormat;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -31,19 +35,19 @@ public class RefundDialogController {
|
||||
private Label lblSaleInfo;
|
||||
|
||||
@FXML
|
||||
private TableView<SaleDetail.SaleDetailItem> tvOriginalItems;
|
||||
private TableView<SaleItemResponse> tvOriginalItems;
|
||||
|
||||
@FXML
|
||||
private TableColumn<SaleDetail.SaleDetailItem, String> colOriginalProduct;
|
||||
private TableColumn<SaleItemResponse, String> colOriginalProduct;
|
||||
|
||||
@FXML
|
||||
private TableColumn<SaleDetail.SaleDetailItem, Integer> colOriginalQuantity;
|
||||
private TableColumn<SaleItemResponse, Integer> colOriginalQuantity;
|
||||
|
||||
@FXML
|
||||
private TableColumn<SaleDetail.SaleDetailItem, Double> colOriginalUnitPrice;
|
||||
private TableColumn<SaleItemResponse, BigDecimal> colOriginalUnitPrice;
|
||||
|
||||
@FXML
|
||||
private TableColumn<SaleDetail.SaleDetailItem, Double> colOriginalTotal;
|
||||
private TableColumn<SaleItemResponse, BigDecimal> colOriginalTotal;
|
||||
|
||||
@FXML
|
||||
private Button btnAddToRefund;
|
||||
@@ -78,7 +82,7 @@ public class RefundDialogController {
|
||||
@FXML
|
||||
private Button btnCancel;
|
||||
|
||||
private SaleDetail currentSale;
|
||||
private SaleResponse currentSale;
|
||||
private final ObservableList<RefundItem> refundItems = FXCollections.observableArrayList();
|
||||
private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA);
|
||||
|
||||
@@ -94,7 +98,7 @@ public class RefundDialogController {
|
||||
colOriginalProduct.setCellValueFactory(new PropertyValueFactory<>("productName"));
|
||||
colOriginalQuantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
|
||||
colOriginalUnitPrice.setCellValueFactory(new PropertyValueFactory<>("unitPrice"));
|
||||
colOriginalTotal.setCellValueFactory(new PropertyValueFactory<>("total"));
|
||||
colOriginalTotal.setCellValueFactory(new PropertyValueFactory<>("lineTotal"));
|
||||
tvOriginalItems.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
|
||||
|
||||
colRefundProduct.setCellValueFactory(new PropertyValueFactory<>("productName"));
|
||||
@@ -113,21 +117,25 @@ public class RefundDialogController {
|
||||
return;
|
||||
}
|
||||
|
||||
int saleId;
|
||||
Long saleId;
|
||||
try {
|
||||
saleId = Integer.parseInt(saleIdText);
|
||||
saleId = Long.parseLong(saleIdText);
|
||||
} catch (NumberFormatException e) {
|
||||
showError("Load Sale", "Invalid transaction ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (SaleDB.isRefunded(saleId)) {
|
||||
List<SaleResponse> allSales = SaleApi.getInstance().listSales(0, 1000, null);
|
||||
boolean alreadyRefunded = allSales.stream()
|
||||
.anyMatch(s -> Boolean.TRUE.equals(s.getIsRefund()) && saleId.equals(s.getOriginalSaleId()));
|
||||
|
||||
if (alreadyRefunded) {
|
||||
showError("Load Sale", "This sale has already been refunded.");
|
||||
return;
|
||||
}
|
||||
|
||||
currentSale = SaleDB.getSaleById(saleId);
|
||||
currentSale = SaleApi.getInstance().getSale(saleId);
|
||||
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||
String saleInfo = String.format("Sale Date: %s | Employee: %s | Original Total: %s | Payment: %s",
|
||||
@@ -137,13 +145,13 @@ public class RefundDialogController {
|
||||
currentSale.getPaymentMethod());
|
||||
lblSaleInfo.setText(saleInfo);
|
||||
|
||||
tvOriginalItems.setItems(currentSale.getItems());
|
||||
tvOriginalItems.setItems(FXCollections.observableArrayList(currentSale.getItems()));
|
||||
cbPaymentMethod.getSelectionModel().select(currentSale.getPaymentMethod());
|
||||
|
||||
refundItems.clear();
|
||||
updateRefundTotal();
|
||||
|
||||
} catch (SQLException e) {
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException("RefundDialogController.btnLoadSaleClicked", e, "Loading sale");
|
||||
showError("Load Sale", e.getMessage() != null ? e.getMessage() : "Could not load sale.");
|
||||
}
|
||||
@@ -156,14 +164,14 @@ public class RefundDialogController {
|
||||
return;
|
||||
}
|
||||
|
||||
SaleDetail.SaleDetailItem selected = tvOriginalItems.getSelectionModel().getSelectedItem();
|
||||
SaleItemResponse selected = tvOriginalItems.getSelectionModel().getSelectedItem();
|
||||
if (selected == null) {
|
||||
showError("Add to Refund", "Select an item from the original sale.");
|
||||
return;
|
||||
}
|
||||
|
||||
int alreadyRefunded = refundItems.stream()
|
||||
.filter(r -> r.getProdId() == selected.getProdId())
|
||||
.filter(r -> r.getProductId().equals(selected.getId()))
|
||||
.mapToInt(RefundItem::getQuantity)
|
||||
.sum();
|
||||
|
||||
@@ -192,7 +200,7 @@ public class RefundDialogController {
|
||||
}
|
||||
|
||||
refundItems.add(new RefundItem(
|
||||
selected.getProdId(),
|
||||
selected.getId(),
|
||||
selected.getProductName(),
|
||||
quantity,
|
||||
selected.getUnitPrice()
|
||||
@@ -226,9 +234,9 @@ public class RefundDialogController {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer employeeId = UserSession.getInstance().getEmployeeId();
|
||||
if (employeeId == null || employeeId <= 0) {
|
||||
showError("Process Refund", "Employee is not set for this account.");
|
||||
Long storeId = UserSession.getInstance().getStoreId();
|
||||
if (storeId == null || storeId <= 0) {
|
||||
showError("Process Refund", "Store is not set for this account.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -240,7 +248,7 @@ public class RefundDialogController {
|
||||
|
||||
Alert confirm = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
confirm.setTitle("Confirm Refund");
|
||||
confirm.setHeaderText("Process refund for sale ID " + currentSale.getSaleId() + "?");
|
||||
confirm.setHeaderText("Process refund for sale ID " + currentSale.getId() + "?");
|
||||
confirm.setContentText("Refund amount: " + lblRefundTotal.getText());
|
||||
|
||||
Optional<ButtonType> confirmResult = confirm.showAndWait();
|
||||
@@ -249,22 +257,33 @@ public class RefundDialogController {
|
||||
}
|
||||
|
||||
try {
|
||||
ObservableList<SaleCartItem> cartItems = FXCollections.observableArrayList();
|
||||
for (RefundItem item : refundItems) {
|
||||
cartItems.add(new SaleCartItem(item.getProdId(), item.getProductName(), item.getQuantity(), item.getUnitPrice()));
|
||||
}
|
||||
SaleRequest request = new SaleRequest();
|
||||
request.setStoreId(storeId);
|
||||
request.setPaymentMethod(payment);
|
||||
request.setIsRefund(true);
|
||||
request.setOriginalSaleId(currentSale.getId());
|
||||
|
||||
int refundId = SaleDB.createRefund(currentSale.getSaleId(), employeeId, payment, cartItems);
|
||||
List<SaleItemRequest> items = new ArrayList<>();
|
||||
for (RefundItem item : refundItems) {
|
||||
SaleItemRequest saleItem = new SaleItemRequest();
|
||||
saleItem.setProductId(item.getProductId());
|
||||
saleItem.setQuantity(-item.getQuantity());
|
||||
saleItem.setUnitPrice(item.getUnitPrice());
|
||||
items.add(saleItem);
|
||||
}
|
||||
request.setItems(items);
|
||||
|
||||
SaleResponse refundResponse = SaleApi.getInstance().createSale(request);
|
||||
|
||||
Alert success = new Alert(Alert.AlertType.INFORMATION);
|
||||
success.setTitle("Refund Processed");
|
||||
success.setHeaderText(null);
|
||||
success.setContentText("Refund ID " + refundId + " was created successfully.");
|
||||
success.setContentText("Refund ID " + refundResponse.getId() + " was created successfully.");
|
||||
success.showAndWait();
|
||||
|
||||
closeDialog();
|
||||
|
||||
} catch (SQLException e) {
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException("RefundDialogController.btnProcessRefundClicked", e, "Processing refund");
|
||||
showError("Process Refund", e.getMessage() != null ? e.getMessage() : "Could not process refund.");
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.database.ServiceDB;
|
||||
import org.example.petshopdesktop.models.Service;
|
||||
import org.example.petshopdesktop.DTOs.ServiceDTO;
|
||||
import org.example.petshopdesktop.api.dto.service.ServiceRequest;
|
||||
import org.example.petshopdesktop.api.endpoints.ServiceApi;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ComboBox;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
|
||||
public class ServiceDialogController {
|
||||
@@ -45,7 +46,7 @@ public class ServiceDialogController {
|
||||
private ComboBox<Integer> cbMinutes;
|
||||
|
||||
private String mode;
|
||||
private Service selectedService;
|
||||
private ServiceDTO selectedService;
|
||||
|
||||
|
||||
|
||||
@@ -68,7 +69,7 @@ public class ServiceDialogController {
|
||||
}
|
||||
}
|
||||
|
||||
public void setService(Service service) {
|
||||
public void setService(ServiceDTO service) {
|
||||
this.selectedService = service;
|
||||
|
||||
lblServiceId.setText("ID: " + service.getServiceId());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Alert;
|
||||
@@ -8,11 +9,10 @@ import javafx.scene.control.Label;
|
||||
import javafx.scene.control.PasswordField;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.database.UserDB;
|
||||
import org.example.petshopdesktop.api.dto.user.UserRequest;
|
||||
import org.example.petshopdesktop.api.endpoints.UserApi;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class StaffRegisterDialogController {
|
||||
|
||||
@FXML
|
||||
@@ -48,8 +48,6 @@ public class StaffRegisterDialogController {
|
||||
|
||||
String firstName = value(txtFirstName);
|
||||
String lastName = value(txtLastName);
|
||||
String email = value(txtEmail);
|
||||
String phone = value(txtPhone);
|
||||
String username = value(txtUsername);
|
||||
String password = txtPassword.getText() == null ? "" : txtPassword.getText();
|
||||
String confirm = txtPasswordConfirm.getText() == null ? "" : txtPasswordConfirm.getText();
|
||||
@@ -58,14 +56,6 @@ public class StaffRegisterDialogController {
|
||||
lblError.setText("First name and last name are required.");
|
||||
return;
|
||||
}
|
||||
if (email.isBlank()) {
|
||||
lblError.setText("Email is required.");
|
||||
return;
|
||||
}
|
||||
if (phone.isBlank()) {
|
||||
lblError.setText("Phone is required.");
|
||||
return;
|
||||
}
|
||||
if (username.isBlank()) {
|
||||
lblError.setText("Username is required.");
|
||||
return;
|
||||
@@ -79,26 +69,41 @@ public class StaffRegisterDialogController {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
UserDB.createStaffAccount(firstName, lastName, email, phone, username, password);
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setTitle("Staff Account");
|
||||
alert.setHeaderText(null);
|
||||
alert.setContentText("Staff account created. You can log in now.");
|
||||
alert.showAndWait();
|
||||
close();
|
||||
} catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Creating staff account");
|
||||
String msg = e.getMessage() == null ? "Could not create staff account." : e.getMessage();
|
||||
if (msg.toLowerCase().contains("duplicate") || msg.toLowerCase().contains("unique")) {
|
||||
lblError.setText("Username already exists.");
|
||||
} else {
|
||||
lblError.setText(msg);
|
||||
btnCreate.setDisable(true);
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
UserRequest request = new UserRequest();
|
||||
request.setUsername(username);
|
||||
request.setPassword(password);
|
||||
request.setFirstName(firstName);
|
||||
request.setLastName(lastName);
|
||||
request.setRole("STAFF");
|
||||
request.setActive(true);
|
||||
|
||||
UserApi.getInstance().createUser(request);
|
||||
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setTitle("Staff Account");
|
||||
alert.setHeaderText(null);
|
||||
alert.setContentText("Staff account created. You can log in now.");
|
||||
alert.showAndWait();
|
||||
close();
|
||||
});
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Creating staff account");
|
||||
String msg = e.getMessage() == null ? "Could not create staff account." : e.getMessage();
|
||||
Platform.runLater(() -> {
|
||||
if (msg.toLowerCase().contains("duplicate") || msg.toLowerCase().contains("unique")) {
|
||||
lblError.setText("Username already exists.");
|
||||
} else {
|
||||
lblError.setText(msg);
|
||||
}
|
||||
btnCreate.setDisable(false);
|
||||
});
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Database connection");
|
||||
lblError.setText("Database is not connected.");
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@FXML
|
||||
|
||||
@@ -10,12 +10,12 @@ import javafx.scene.control.TextField;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.Validator;
|
||||
import org.example.petshopdesktop.database.SupplierDB;
|
||||
import org.example.petshopdesktop.api.dto.supplier.SupplierRequest;
|
||||
import org.example.petshopdesktop.api.dto.supplier.SupplierResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.SupplierApi;
|
||||
import org.example.petshopdesktop.models.Supplier;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class SupplierDialogController {
|
||||
|
||||
@FXML
|
||||
@@ -74,7 +74,6 @@ public class SupplierDialogController {
|
||||
* @param mouseEvent click event for save button
|
||||
*/
|
||||
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
||||
int numRow = 0; //how many rows affected
|
||||
String errorMsg = ""; //error message for validation
|
||||
|
||||
//Check validation (input required)
|
||||
@@ -95,44 +94,29 @@ public class SupplierDialogController {
|
||||
errorMsg += Validator.isValidPhoneNumber(txtPhone.getText(), "Phone Number");
|
||||
|
||||
if(errorMsg.isEmpty()){ //no validation errors detected
|
||||
Supplier supplier = collectSupplier(); //get supplier info
|
||||
if (mode.equals("Add")) { //add mode
|
||||
try{
|
||||
numRow = SupplierDB.insertSupplier(supplier);
|
||||
} catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"SupplierDialogController.buttonSaveClicked",
|
||||
e,
|
||||
"Inserting new supplier record");
|
||||
throw new RuntimeException(e);
|
||||
SupplierRequest request = createSupplierRequest();
|
||||
try {
|
||||
if (mode.equals("Add")) {
|
||||
SupplierApi.getInstance().createSupplier(request);
|
||||
} else {
|
||||
Long supplierId = Long.parseLong(lblSupId.getText().split(": ")[1]);
|
||||
SupplierApi.getInstance().updateSupplier(supplierId, request);
|
||||
}
|
||||
}
|
||||
else{ //edit mode
|
||||
try{
|
||||
numRow = SupplierDB.updateSupplier(supplier.getSupId(),supplier);
|
||||
} catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"SupplierDialogController.buttonSaveClicked",
|
||||
e,
|
||||
"Updating supplier with ID: " + supplier.getSupId());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//if no rows were affected then there was an error (prompt user of error)
|
||||
if (numRow == 0){
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Database Operation Error");
|
||||
alert.setContentText(mode + " failed");
|
||||
alert.showAndWait();
|
||||
}
|
||||
else {
|
||||
//tell the user operation was successful
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setHeaderText("Saved");
|
||||
alert.setContentText(mode + " succeeded");
|
||||
alert.showAndWait();
|
||||
closeStage(mouseEvent);
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException(
|
||||
"SupplierDialogController.buttonSaveClicked",
|
||||
e,
|
||||
mode.equals("Add") ? "Inserting new supplier record" : "Updating supplier record");
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setHeaderText("Database Operation Error");
|
||||
alert.setContentText(mode + " failed: " + e.getMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
}
|
||||
else{ //Display validation errors
|
||||
@@ -154,26 +138,16 @@ public class SupplierDialogController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the supplier info
|
||||
* @return supplier info with the id or the new supplier
|
||||
* Create a supplier request from the form inputs
|
||||
* @return supplier request for API call
|
||||
*/
|
||||
private Supplier collectSupplier(){
|
||||
int supId = 0;
|
||||
Supplier supplier = null;
|
||||
|
||||
if(lblSupId.isVisible()){ //Edit mode
|
||||
//get supplier id from lblId (split the string so we only get the int)
|
||||
supId = Integer.parseInt(lblSupId.getText().split(": ")[1]);
|
||||
}
|
||||
supplier = new Supplier(
|
||||
supId,
|
||||
txtCompanyName.getText(),
|
||||
txtContactFirstName.getText(),
|
||||
txtContactLastName.getText(),
|
||||
txtEmail.getText(),
|
||||
txtPhone.getText()
|
||||
);
|
||||
return supplier;
|
||||
private SupplierRequest createSupplierRequest(){
|
||||
SupplierRequest request = new SupplierRequest();
|
||||
request.setSupplierName(txtCompanyName.getText());
|
||||
request.setContactPerson(txtContactFirstName.getText() + " " + txtContactLastName.getText());
|
||||
request.setEmail(txtEmail.getText());
|
||||
request.setPhone(txtPhone.getText());
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,16 +8,17 @@ public class Adoption {
|
||||
private SimpleIntegerProperty adoptionId;
|
||||
private SimpleIntegerProperty petId;
|
||||
private SimpleIntegerProperty customerId;
|
||||
private SimpleStringProperty petName;
|
||||
private SimpleStringProperty customerName;
|
||||
private SimpleStringProperty adoptionDate;
|
||||
private SimpleDoubleProperty adoptionFee;
|
||||
private SimpleStringProperty adoptionStatus;
|
||||
|
||||
//Constructor
|
||||
public Adoption(int adoptionId, int petId, int customerId, String customerName, String adoptionDate, double adoptionFee, String adoptionStatus) {
|
||||
public Adoption(int adoptionId, int petId, int customerId, String petName, String customerName, String adoptionDate, double adoptionFee, String adoptionStatus) {
|
||||
this.adoptionId = new SimpleIntegerProperty(adoptionId);
|
||||
this.petId = new SimpleIntegerProperty(petId);
|
||||
this.customerId = new SimpleIntegerProperty(customerId);
|
||||
this.petName = new SimpleStringProperty(petName);
|
||||
this.customerName = new SimpleStringProperty(customerName);
|
||||
this.adoptionDate = new SimpleStringProperty(adoptionDate);
|
||||
this.adoptionFee = new SimpleDoubleProperty(adoptionFee);
|
||||
@@ -42,6 +43,12 @@ public class Adoption {
|
||||
|
||||
public SimpleIntegerProperty customerIdProperty() { return customerId; }
|
||||
|
||||
public String getPetName() { return petName.get(); }
|
||||
|
||||
public void setPetName(String petName) { this.petName.set(petName); }
|
||||
|
||||
public SimpleStringProperty petNameProperty() { return petName; }
|
||||
|
||||
public String getCustomerName() { return customerName.get(); }
|
||||
|
||||
public void setCustomerName(String customerName) { this.customerName.set(customerName); }
|
||||
|
||||
@@ -7,14 +7,21 @@ public class Inventory {
|
||||
private SimpleIntegerProperty inventoryId;
|
||||
private SimpleIntegerProperty prodId;
|
||||
private SimpleStringProperty prodName;
|
||||
private SimpleStringProperty categoryName;
|
||||
private SimpleIntegerProperty storeId;
|
||||
private SimpleStringProperty storeName;
|
||||
private SimpleIntegerProperty quantity;
|
||||
private SimpleIntegerProperty reorderLevel;
|
||||
|
||||
//Constructor
|
||||
public Inventory(int inventoryId, int prodId, String prodName, int quantity) {
|
||||
public Inventory(int inventoryId, int prodId, String prodName, String categoryName, int storeId, String storeName, int quantity, int reorderLevel) {
|
||||
this.inventoryId = new SimpleIntegerProperty(inventoryId);
|
||||
this.prodId = new SimpleIntegerProperty(prodId);
|
||||
this.prodName = new SimpleStringProperty(prodName);
|
||||
this.categoryName = new SimpleStringProperty(categoryName);
|
||||
this.storeId = new SimpleIntegerProperty(storeId);
|
||||
this.storeName = new SimpleStringProperty(storeName);
|
||||
this.quantity = new SimpleIntegerProperty(quantity);
|
||||
this.reorderLevel = new SimpleIntegerProperty(reorderLevel);
|
||||
}
|
||||
|
||||
public int getInventoryId() { return inventoryId.get(); }
|
||||
@@ -35,9 +42,33 @@ public class Inventory {
|
||||
|
||||
public SimpleStringProperty prodNameProperty() { return prodName; }
|
||||
|
||||
public String getCategoryName() { return categoryName.get(); }
|
||||
|
||||
public void setCategoryName(String categoryName) { this.categoryName.set(categoryName); }
|
||||
|
||||
public SimpleStringProperty categoryNameProperty() { return categoryName; }
|
||||
|
||||
public int getStoreId() { return storeId.get(); }
|
||||
|
||||
public void setStoreId(int storeId) { this.storeId.set(storeId); }
|
||||
|
||||
public SimpleIntegerProperty storeIdProperty() { return storeId; }
|
||||
|
||||
public String getStoreName() { return storeName.get(); }
|
||||
|
||||
public void setStoreName(String storeName) { this.storeName.set(storeName); }
|
||||
|
||||
public SimpleStringProperty storeNameProperty() { return storeName; }
|
||||
|
||||
public int getQuantity() { return quantity.get(); }
|
||||
|
||||
public void setQuantity(int quantity) { this.quantity.set(quantity); }
|
||||
|
||||
public SimpleIntegerProperty quantityProperty() { return quantity; }
|
||||
|
||||
public int getReorderLevel() { return reorderLevel.get(); }
|
||||
|
||||
public void setReorderLevel(int reorderLevel) { this.reorderLevel.set(reorderLevel); }
|
||||
|
||||
public SimpleIntegerProperty reorderLevelProperty() { return reorderLevel; }
|
||||
}
|
||||
|
||||
@@ -1,35 +1,52 @@
|
||||
package org.example.petshopdesktop.models;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class PurchaseOrder {
|
||||
|
||||
private int purchaseOrderId;
|
||||
private int supId;
|
||||
private String orderDate;
|
||||
private long purchaseOrderId;
|
||||
private String supplierName;
|
||||
private LocalDate orderDate;
|
||||
private LocalDate expectedDeliveryDate;
|
||||
private String status;
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
public PurchaseOrder(int purchaseOrderId,
|
||||
int supId,
|
||||
String orderDate,
|
||||
String status) {
|
||||
public PurchaseOrder(long purchaseOrderId,
|
||||
String supplierName,
|
||||
LocalDate orderDate,
|
||||
LocalDate expectedDeliveryDate,
|
||||
String status,
|
||||
BigDecimal totalAmount) {
|
||||
this.purchaseOrderId = purchaseOrderId;
|
||||
this.supId = supId;
|
||||
this.supplierName = supplierName;
|
||||
this.orderDate = orderDate;
|
||||
this.expectedDeliveryDate = expectedDeliveryDate;
|
||||
this.status = status;
|
||||
this.totalAmount = totalAmount;
|
||||
}
|
||||
|
||||
public int getPurchaseOrderId() {
|
||||
public long getPurchaseOrderId() {
|
||||
return purchaseOrderId;
|
||||
}
|
||||
|
||||
public int getSupId() {
|
||||
return supId;
|
||||
public String getSupplierName() {
|
||||
return supplierName;
|
||||
}
|
||||
|
||||
public String getOrderDate() {
|
||||
public LocalDate getOrderDate() {
|
||||
return orderDate;
|
||||
}
|
||||
|
||||
public LocalDate getExpectedDeliveryDate() {
|
||||
return expectedDeliveryDate;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalAmount() {
|
||||
return totalAmount;
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@ package org.example.petshopdesktop.models;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
public class StaffAccount {
|
||||
private final int userId;
|
||||
private final int employeeId;
|
||||
private final long userId;
|
||||
private final long employeeId;
|
||||
private final String username;
|
||||
private final String firstName;
|
||||
private final String lastName;
|
||||
@@ -13,7 +13,7 @@ public class StaffAccount {
|
||||
private final boolean active;
|
||||
private final Timestamp createdAt;
|
||||
|
||||
public StaffAccount(int userId, int employeeId, String username, String firstName, String lastName, String email, String phone, boolean active, Timestamp createdAt) {
|
||||
public StaffAccount(long userId, long employeeId, String username, String firstName, String lastName, String email, String phone, boolean active, Timestamp createdAt) {
|
||||
this.userId = userId;
|
||||
this.employeeId = employeeId;
|
||||
this.username = username;
|
||||
@@ -25,11 +25,11 @@ public class StaffAccount {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public int getUserId() {
|
||||
public long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public int getEmployeeId() {
|
||||
public long getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user