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