diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java index d31785be..e139450c 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java @@ -35,6 +35,12 @@ public class AdoptionController { @FXML private Button btnEdit; + @FXML + private Button btnRefresh; + + @FXML + private Label lblStatus; + @FXML private TableColumn colAdoptionId; @@ -103,6 +109,14 @@ public class AdoptionController { }); } + @FXML + void btnRefresh(ActionEvent event) { + txtSearch.clear(); + tvAdoptions.getSortOrder().clear(); + displayAdoptions(); + TableViewSupport.flashStatus(lblStatus, "Refreshed"); + } + @FXML void btnAddClicked(ActionEvent event) { mode = "Add"; diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java index 60d14e7f..040cf0d5 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java @@ -6,6 +6,8 @@ import javafx.fxml.FXML; import javafx.scene.chart.*; import javafx.scene.control.Button; import javafx.scene.control.Label; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; import org.example.petshopdesktop.api.dto.analytics.DailySales; import org.example.petshopdesktop.api.dto.analytics.DashboardResponse; import org.example.petshopdesktop.api.dto.analytics.TopProduct; @@ -15,6 +17,7 @@ import org.example.petshopdesktop.api.endpoints.AnalyticsApi; import org.example.petshopdesktop.api.endpoints.SaleApi; import org.example.petshopdesktop.auth.UserSession; import org.example.petshopdesktop.util.ActivityLogger; +import org.example.petshopdesktop.util.TableViewSupport; import java.math.BigDecimal; import java.math.RoundingMode; @@ -32,6 +35,9 @@ public class AnalyticsController { @FXML private Button btnRefresh; + @FXML + private Label lblStatus; + @FXML private Label lblError; @@ -65,6 +71,9 @@ public class AnalyticsController { @FXML private BarChart chartEmployeePerformance; + @FXML + private TabPane tabPane; + private static final String SALES_COLOR = "#ff6b35"; private static final String REVENUE_COLOR = "#4ecdc4"; private static final String QUANTITY_COLOR = "#ff9f1c"; @@ -79,6 +88,13 @@ public class AnalyticsController { @FXML public void initialize() { configureCharts(); + if (tabPane != null) { + tabPane.getSelectionModel().selectedItemProperty().addListener((obs, oldTab, newTab) -> { + if (oldTab != newTab && newTab != null) { + loadAnalyticsData(); + } + }); + } loadAnalyticsData(); } @@ -126,6 +142,9 @@ public class AnalyticsController { private void loadAnalyticsData() { lblError.setVisible(false); + if (lblStatus != null) { + lblStatus.setVisible(false); + } new Thread(() -> { try { DashboardResponse dashboard = AnalyticsApi.getInstance().getDashboard(30, 10); @@ -472,5 +491,6 @@ public class AnalyticsController { @FXML void handleRefresh(ActionEvent event) { loadAnalyticsData(); + TableViewSupport.flashStatus(lblStatus, "Refreshed"); } } diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java index 3b19567c..3cc4a904 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java @@ -40,6 +40,9 @@ public class AppointmentController { @FXML private Button btnAdd; @FXML private Button btnEdit; @FXML private Button btnDelete; + @FXML private Button btnRefresh; + + @FXML private Label lblStatus; @FXML private TextField txtSearch; @@ -135,6 +138,14 @@ public class AppointmentController { }).start(); } + @FXML + void btnRefresh(ActionEvent event) { + txtSearch.clear(); + tvAppointments.getSortOrder().clear(); + loadAppointments(); + TableViewSupport.flashStatus(lblStatus, "Refreshed"); + } + @FXML void btnAddClicked(ActionEvent event){ openDialog(null, "Add"); diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java index d889237d..c5e6cd96 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java @@ -35,6 +35,12 @@ public class InventoryController { @FXML private Button btnEdit; + @FXML + private Button btnRefresh; + + @FXML + private Label lblStatus; + @FXML private TableColumn colInventoryId; @@ -94,6 +100,14 @@ public class InventoryController { } //Opens dialog in add mode + @FXML + void btnRefresh(ActionEvent event) { + txtSearch.clear(); + tvInventory.getSortOrder().clear(); + displayInventory(); + TableViewSupport.flashStatus(lblStatus, "Refreshed"); + } + @FXML void btnAddClicked(ActionEvent event) { mode = "Add"; diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/PetController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/PetController.java index fbe2df24..fa091671 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/PetController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/PetController.java @@ -40,6 +40,12 @@ public class PetController { @FXML private Button btnEdit; + @FXML + private Button btnRefresh; + + @FXML + private Label lblStatus; + @FXML private TableColumn colPetAge; @@ -82,6 +88,20 @@ public class PetController { @FXML private TextField txtSearch; + @FXML + void btnRefresh(ActionEvent event) { + txtSearch.clear(); + if (cbSpeciesFilter != null) { + cbSpeciesFilter.getSelectionModel().selectFirst(); + } + if (cbStatusFilter != null) { + cbStatusFilter.getSelectionModel().selectFirst(); + } + tvPets.getSortOrder().clear(); + displayPets(); + TableViewSupport.flashStatus(lblStatus, "Refreshed"); + } + @FXML void btnAddClicked(ActionEvent event) { mode = "Add"; diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/ProductController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/ProductController.java index c27974b2..25f1bf14 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/ProductController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/ProductController.java @@ -44,6 +44,12 @@ public class ProductController { @FXML private Button btnEdit; + @FXML + private Button btnRefresh; + + @FXML + private Label lblStatus; + @FXML private TableColumn colProductCategory; @@ -156,6 +162,17 @@ public class ProductController { * open a new dialog for adding a product * @param event click event for button */ + @FXML + void btnRefresh(ActionEvent event) { + txtSearch.clear(); + if (cbCategoryFilter != null) { + cbCategoryFilter.getSelectionModel().selectFirst(); + } + tvProducts.getSortOrder().clear(); + displayProduct(); + TableViewSupport.flashStatus(lblStatus, "Refreshed"); + } + @FXML void btnAddClicked(ActionEvent event) { mode = "Add"; diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java index 4a632a1a..8060a68f 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java @@ -34,6 +34,12 @@ public class ProductSupplierController { @FXML private Button btnEdit; + @FXML + private Button btnRefresh; + + @FXML + private Label lblStatus; + @FXML private TableColumn colCost; @@ -167,6 +173,14 @@ public class ProductSupplierController { * open a new dialog for adding a productSupplier * @param event click event for button */ + @FXML + void btnRefresh(ActionEvent event) { + txtSearch.clear(); + tvProductSuppliers.getSortOrder().clear(); + displayProductSupplier(); + TableViewSupport.flashStatus(lblStatus, "Refreshed"); + } + @FXML void btnAddClicked(ActionEvent event) { mode = "Add"; diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java index de8334ab..19cb952f 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java @@ -5,14 +5,21 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; import org.example.petshopdesktop.DTOs.PurchaseOrderDTO; import org.example.petshopdesktop.api.dto.purchaseorder.PurchaseOrderResponse; import org.example.petshopdesktop.api.endpoints.PurchaseOrderApi; +import org.example.petshopdesktop.controllers.dialogcontrollers.PurchaseOrderDetailsDialogController; import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.TableViewSupport; +import javafx.stage.Modality; +import javafx.stage.Stage; + +import java.io.IOException; import java.util.List; import java.util.Comparator; import java.util.stream.Collectors; @@ -21,6 +28,8 @@ public class PurchaseOrderController { @FXML private Button btnRefresh; + @FXML private Label lblStatus; + @FXML private TextField txtSearch; @@ -51,6 +60,7 @@ public class PurchaseOrderController { filtered = new FilteredList<>(purchaseOrders, p -> true); TableViewSupport.bindSortedItems(tvPurchaseOrders, filtered); + TableViewSupport.installDoubleClickAction(tvPurchaseOrders, this::openDetailsDialog); if (txtSearch != null) { txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n)); @@ -109,7 +119,34 @@ public class PurchaseOrderController { @FXML void btnRefresh() { + if (txtSearch != null) { + txtSearch.clear(); + } + TableViewSupport.clearSort(tvPurchaseOrders); loadPurchaseOrders(); + TableViewSupport.flashStatus(lblStatus, "Refreshed"); + } + + private void openDetailsDialog(PurchaseOrderDTO selected) { + try { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/purchase-order-details-dialog-view.fxml")); + Stage dialog = new Stage(); + dialog.initModality(Modality.APPLICATION_MODAL); + dialog.setTitle("Purchase Order Details"); + dialog.setScene(new Scene(loader.load())); + PurchaseOrderDetailsDialogController controller = loader.getController(); + controller.displayPurchaseOrder(selected); + controller.setCloseAction(() -> dialog.close()); + dialog.initOwner(tvPurchaseOrders.getScene().getWindow()); + dialog.setResizable(false); + dialog.showAndWait(); + } catch (IOException e) { + ActivityLogger.getInstance().logException( + "PurchaseOrderController.openDetailsDialog", + e, + "Opening purchase order details"); + new Alert(Alert.AlertType.ERROR, "Unable to open purchase order details").showAndWait(); + } } private PurchaseOrderDTO mapToPurchaseOrderDTO(PurchaseOrderResponse response) { diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/SaleController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/SaleController.java index e0436bf5..7e6573de 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/SaleController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/SaleController.java @@ -51,6 +51,9 @@ public class SaleController { @FXML private Button btnRefresh; + @FXML + private Label lblStatus; + @FXML private Button btnRefund; @@ -292,7 +295,10 @@ public class SaleController { @FXML void btnRefresh(ActionEvent event) { - refreshSales(true); + txtSearch.clear(); + TableViewSupport.clearSort(tvSales); + refreshSales(false); + TableViewSupport.flashStatus(lblStatus, "Refreshed"); } @FXML @@ -425,10 +431,11 @@ public class SaleController { @FXML void btnRefund(ActionEvent event) { - openRefundDialog(); + SaleLineItem selectedSale = tvSales.getSelectionModel().getSelectedItem(); + openRefundDialog(selectedSale != null ? (long) selectedSale.getSaleId() : null); } - private void openRefundDialog() { + private void openRefundDialog(Long saleId) { try { SaleLineItem selectedSale = tvSales.getSelectionModel().getSelectedItem(); if (selectedSale != null && selectedSale.isRefund()) { @@ -444,8 +451,8 @@ public class SaleController { dialog.setTitle("Process Refund"); dialog.setScene(new Scene(loader.load())); var controller = loader.getController(); - if (selectedSale != null) { - controller.prefillSale((long) selectedSale.getSaleId()); + if (saleId != null) { + controller.prefillSale(saleId); } dialog.setMinWidth(860); dialog.setMinHeight(680); @@ -477,6 +484,8 @@ public class SaleController { dialog.setTitle("Sale Details"); dialog.setScene(new Scene(loader.load())); var controller = (org.example.petshopdesktop.controllers.dialogcontrollers.SaleDetailDialogController) loader.getController(); + controller.setSaleId((long) sale.getSaleId()); + controller.setRefundAction(this::openRefundDialog); controller.displaySaleDetails(mapToSaleDetail(sale)); dialog.setResizable(false); dialog.showAndWait(); @@ -520,6 +529,7 @@ public class SaleController { sale.getTotalAmount() != null ? sale.getTotalAmount().doubleValue() : 0.0, sale.getPaymentMethod(), sale.getEmployeeName(), + Boolean.TRUE.equals(sale.getIsRefund()), items ); } diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java index dce27137..04a72dba 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java @@ -28,6 +28,9 @@ public class ServiceController { @FXML private Button btnAdd; @FXML private Button btnDelete; @FXML private Button btnEdit; + @FXML private Button btnRefresh; + + @FXML private Label lblStatus; @FXML private TableColumn colServiceId; @FXML private TableColumn colServiceName; @@ -131,6 +134,14 @@ public class ServiceController { } + @FXML + void btnRefresh(ActionEvent event) { + txtSearch.clear(); + tvServices.getSortOrder().clear(); + displayServices(); + TableViewSupport.flashStatus(lblStatus, "Refreshed"); + } + @FXML void btnAddClicked(ActionEvent event) { mode = "Add"; diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/StaffAccountsController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/StaffAccountsController.java index fbd3bd87..251d9a69 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/StaffAccountsController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/StaffAccountsController.java @@ -58,6 +58,12 @@ public class StaffAccountsController { @FXML private Label lblError; + @FXML + private Label lblStatus; + + @FXML + private Button btnRefresh; + @FXML private Button btnCreateAccount; @@ -107,7 +113,10 @@ public class StaffAccountsController { @FXML void btnRefreshClicked(ActionEvent event) { + txtSearch.clear(); + TableViewSupport.clearSort(tvStaff); refresh(); + TableViewSupport.flashStatus(lblStatus, "Refreshed"); } @FXML diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java index b31070d3..c6120d15 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java @@ -37,6 +37,12 @@ public class SupplierController { @FXML private Button btnEdit; + @FXML + private Button btnRefresh; + + @FXML + private Label lblStatus; + @FXML private TableColumn colContactPerson; @@ -170,6 +176,14 @@ public class SupplierController { * open a new dialog for adding a supplier * @param event click event for button */ + @FXML + void btnRefresh(ActionEvent event) { + txtSearch.clear(); + tvSuppliers.getSortOrder().clear(); + displaySupplier(); + TableViewSupport.flashStatus(lblStatus, "Refreshed"); + } + @FXML void btnAddClicked(ActionEvent event) { mode = "Add"; diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AdoptionDialogController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AdoptionDialogController.java index 015c02ac..21a89e31 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AdoptionDialogController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AdoptionDialogController.java @@ -265,6 +265,7 @@ public class AdoptionDialogController { if (adoption != null) { selectedAdoption = adoption; lblAdoptionId.setText("ID: " + adoption.getAdoptionId()); + ensureSelectedEmployeeOption(cbEmployee.getItems()); applySelectedPet(); applySelectedCustomer(); applySelectedEmployee(); diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java index acff3799..8e2ef094 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java @@ -19,7 +19,9 @@ import org.example.petshopdesktop.api.endpoints.ProductSupplierApi; import org.example.petshopdesktop.util.ActivityLogger; import java.math.BigDecimal; +import java.util.HashSet; import java.util.List; +import java.util.Set; public class ProductSupplierDialogController { @@ -49,6 +51,10 @@ public class ProductSupplierDialogController { private int selectedProdId = -1; private Long pendingSupplierId = null; private Long pendingProductId = null; + private boolean updatingChoices = false; + private ObservableList baseSuppliers = FXCollections.observableArrayList(); + private ObservableList baseProducts = FXCollections.observableArrayList(); + private List relations = List.of(); /** * add event listeners to buttons and set up combobox @@ -115,20 +121,39 @@ public class ProductSupplierDialogController { } }); + cbProduct.valueProperty().addListener((obs, oldValue, newValue) -> { + if (updatingChoices) { + return; + } + filterSuppliersByProduct(newValue != null ? newValue.getId() : null); + }); + + cbSupplier.valueProperty().addListener((obs, oldValue, newValue) -> { + if (updatingChoices) { + return; + } + filterProductsBySupplier(newValue != null ? newValue.getId() : null); + }); + new Thread(() -> { try { + var productSupplierLinks = ProductSupplierApi.getInstance().listProductSuppliers(null); var suppliers = DropdownApi.getInstance().getSuppliers(); var products = DropdownApi.getInstance().getProducts(); Platform.runLater(() -> { + relations = productSupplierLinks != null ? productSupplierLinks : List.of(); if (suppliers != null) { - cbSupplier.setItems(FXCollections.observableArrayList(suppliers)); + baseSuppliers = FXCollections.observableArrayList(suppliers); + cbSupplier.setItems(FXCollections.observableArrayList(baseSuppliers)); applyPendingSupplierSelection(); } if (products != null) { - cbProduct.setItems(FXCollections.observableArrayList(products)); + baseProducts = FXCollections.observableArrayList(products); + cbProduct.setItems(FXCollections.observableArrayList(baseProducts)); applyPendingProductSelection(); } + applyCurrentFilters(); }); } catch (Exception e) { Platform.runLater(() -> { @@ -271,7 +296,10 @@ public class ProductSupplierDialogController { } DropdownOption product = findOptionById(cbProduct.getItems(), pendingProductId); if (product != null) { + updatingChoices = true; cbProduct.getSelectionModel().select(product); + updatingChoices = false; + filterSuppliersByProduct(product.getId()); pendingProductId = null; } } @@ -282,11 +310,73 @@ public class ProductSupplierDialogController { } DropdownOption supplier = findOptionById(cbSupplier.getItems(), pendingSupplierId); if (supplier != null) { + updatingChoices = true; cbSupplier.getSelectionModel().select(supplier); + updatingChoices = false; + filterProductsBySupplier(supplier.getId()); pendingSupplierId = null; } } + private void applyCurrentFilters() { + DropdownOption selectedProduct = cbProduct.getSelectionModel().getSelectedItem(); + DropdownOption selectedSupplier = cbSupplier.getSelectionModel().getSelectedItem(); + filterSuppliersByProduct(selectedProduct != null ? selectedProduct.getId() : null); + filterProductsBySupplier(selectedSupplier != null ? selectedSupplier.getId() : null); + } + + private void filterSuppliersByProduct(Long productId) { + updatingChoices = true; + try { + if (productId == null) { + cbSupplier.setItems(FXCollections.observableArrayList(baseSuppliers)); + return; + } + Set allowedSupplierIds = new HashSet<>(); + for (ProductSupplierResponse relation : relations) { + if (relation.getProductId() != null && relation.getProductId().equals(productId) && relation.getSupplierId() != null) { + allowedSupplierIds.add(relation.getSupplierId()); + } + } + ObservableList filtered = FXCollections.observableArrayList( + baseSuppliers.stream().filter(option -> option.getId() != null && allowedSupplierIds.contains(option.getId())).toList() + ); + cbSupplier.setItems(filtered); + DropdownOption selectedSupplier = cbSupplier.getSelectionModel().getSelectedItem(); + if (selectedSupplier != null && !allowedSupplierIds.contains(selectedSupplier.getId())) { + cbSupplier.getSelectionModel().clearSelection(); + } + } finally { + updatingChoices = false; + } + } + + private void filterProductsBySupplier(Long supplierId) { + updatingChoices = true; + try { + if (supplierId == null) { + cbProduct.setItems(FXCollections.observableArrayList(baseProducts)); + return; + } + Set allowedProductIds = new HashSet<>(); + for (ProductSupplierResponse relation : relations) { + if (relation.getSupplierId() != null && relation.getSupplierId().equals(supplierId) && relation.getProductId() != null) { + allowedProductIds.add(relation.getProductId()); + } + } + ObservableList filtered = FXCollections.observableArrayList( + baseProducts.stream().filter(option -> option.getId() != null && allowedProductIds.contains(option.getId())).toList() + ); + cbProduct.setItems(filtered); + DropdownOption selectedProduct = cbProduct.getSelectionModel().getSelectedItem(); + if (selectedProduct != null && !allowedProductIds.contains(selectedProduct.getId())) { + cbProduct.getSelectionModel().clearSelection(); + } + } finally { + updatingChoices = false; + } + } + private DropdownOption findOptionById(List options, Long id) { if (options == null || id == null) { return null; diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PurchaseOrderDetailsDialogController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PurchaseOrderDetailsDialogController.java new file mode 100644 index 00000000..ff597d36 --- /dev/null +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PurchaseOrderDetailsDialogController.java @@ -0,0 +1,40 @@ +package org.example.petshopdesktop.controllers.dialogcontrollers; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.stage.Stage; +import org.example.petshopdesktop.DTOs.PurchaseOrderDTO; + +public class PurchaseOrderDetailsDialogController { + + @FXML private Label lblOrderId; + @FXML private Label lblSupplier; + @FXML private Label lblOrderDate; + @FXML private Label lblStatus; + + private Runnable closeAction; + + public void displayPurchaseOrder(PurchaseOrderDTO order) { + if (order == null) { + return; + } + lblOrderId.setText(String.valueOf(order.getPurchaseOrderId())); + lblSupplier.setText(order.getSupplierName() != null ? order.getSupplierName() : ""); + lblOrderDate.setText(order.getOrderDate() != null ? order.getOrderDate() : ""); + lblStatus.setText(order.getStatus() != null ? order.getStatus() : ""); + } + + public void setCloseAction(Runnable closeAction) { + this.closeAction = closeAction; + } + + @FXML + void btnCloseClicked() { + if (closeAction != null) { + closeAction.run(); + return; + } + Stage stage = (Stage) lblOrderId.getScene().getWindow(); + stage.close(); + } +} diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SaleDetailDialogController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SaleDetailDialogController.java index 3a0c67cc..abeb3355 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SaleDetailDialogController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SaleDetailDialogController.java @@ -2,11 +2,19 @@ package org.example.petshopdesktop.controllers.dialogcontrollers; import javafx.fxml.FXML; import javafx.scene.control.Label; +import javafx.scene.control.Button; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; import javafx.stage.Stage; import org.example.petshopdesktop.models.SaleDetail; +import org.example.petshopdesktop.controllers.dialogcontrollers.RefundDialogController; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.stage.Modality; +import org.example.petshopdesktop.util.ActivityLogger; + +import java.util.function.Consumer; import java.text.NumberFormat; import java.time.format.DateTimeFormatter; @@ -19,6 +27,7 @@ public class SaleDetailDialogController { @FXML private Label lblEmployee; @FXML private Label lblPayment; @FXML private Label lblTotal; + @FXML private Button btnRefund; @FXML private TableView tvItems; @FXML private TableColumn colProduct; @FXML private TableColumn colQuantity; @@ -27,6 +36,8 @@ public class SaleDetailDialogController { private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA); private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + private Long saleId; + private Consumer refundAction; @FXML public void initialize() { @@ -38,12 +49,48 @@ public class SaleDetailDialogController { } public void displaySaleDetails(SaleDetail sale) { + saleId = (long) sale.getSaleId(); lblSaleId.setText(String.valueOf(sale.getSaleId())); lblSaleDate.setText(sale.getSaleDate() != null ? sale.getSaleDate().format(DATE_FORMATTER) : ""); lblEmployee.setText(sale.getEmployeeName() != null ? sale.getEmployeeName() : ""); lblPayment.setText(sale.getPaymentMethod() != null ? sale.getPaymentMethod() : ""); lblTotal.setText(currency.format(sale.getTotalAmount())); tvItems.setItems(sale.getItems()); + if (btnRefund != null) { + btnRefund.setDisable(sale.isRefund()); + } + } + + public void setSaleId(Long saleId) { + this.saleId = saleId; + } + + public void setRefundAction(Consumer refundAction) { + this.refundAction = refundAction; + } + + @FXML + void btnRefundClicked() { + if (saleId == null) { + return; + } + if (refundAction != null) { + refundAction.accept(saleId); + return; + } + try { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/refund-dialog-view.fxml")); + Stage dialog = new Stage(); + dialog.initOwner(tvItems.getScene().getWindow()); + dialog.initModality(Modality.APPLICATION_MODAL); + dialog.setTitle("Process Refund"); + dialog.setScene(new Scene(loader.load())); + RefundDialogController controller = loader.getController(); + controller.prefillSale(saleId); + dialog.showAndWait(); + } catch (Exception e) { + ActivityLogger.getInstance().logException("SaleDetailDialogController.btnRefundClicked", e, "Opening refund dialog"); + } } @FXML diff --git a/desktop/src/main/java/org/example/petshopdesktop/models/SaleDetail.java b/desktop/src/main/java/org/example/petshopdesktop/models/SaleDetail.java index 8ed6e291..c3ff719e 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/models/SaleDetail.java +++ b/desktop/src/main/java/org/example/petshopdesktop/models/SaleDetail.java @@ -9,14 +9,16 @@ public class SaleDetail { private final double totalAmount; private final String paymentMethod; private final String employeeName; + private final boolean refund; private final ObservableList items; - public SaleDetail(int saleId, LocalDateTime saleDate, double totalAmount, String paymentMethod, String employeeName, ObservableList items) { + public SaleDetail(int saleId, LocalDateTime saleDate, double totalAmount, String paymentMethod, String employeeName, boolean refund, ObservableList items) { this.saleId = saleId; this.saleDate = saleDate; this.totalAmount = totalAmount; this.paymentMethod = paymentMethod; this.employeeName = employeeName; + this.refund = refund; this.items = items; } @@ -40,6 +42,10 @@ public class SaleDetail { return employeeName; } + public boolean isRefund() { + return refund; + } + public ObservableList getItems() { return items; } diff --git a/desktop/src/main/java/org/example/petshopdesktop/util/TableViewSupport.java b/desktop/src/main/java/org/example/petshopdesktop/util/TableViewSupport.java index 9d5d327c..bd18548e 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/util/TableViewSupport.java +++ b/desktop/src/main/java/org/example/petshopdesktop/util/TableViewSupport.java @@ -2,9 +2,12 @@ package org.example.petshopdesktop.util; import javafx.collections.transformation.FilteredList; import javafx.collections.transformation.SortedList; +import javafx.animation.PauseTransition; +import javafx.scene.control.Label; import javafx.scene.control.TableRow; import javafx.scene.control.TableView; import javafx.scene.input.MouseButton; +import javafx.util.Duration; import java.util.function.Consumer; @@ -19,6 +22,25 @@ public final class TableViewSupport { tableView.setItems(sortedItems); } + public static void clearSort(TableView tableView) { + tableView.getSortOrder().clear(); + } + + public static void flashStatus(Label label, String message) { + if (label == null) { + return; + } + label.setText(message); + label.setVisible(true); + label.setManaged(true); + PauseTransition delay = new PauseTransition(Duration.seconds(1.5)); + delay.setOnFinished(event -> { + label.setVisible(false); + label.setManaged(false); + }); + delay.playFromStart(); + } + public static void installDoubleClickAction(TableView tableView, Consumer action) { tableView.setRowFactory(tv -> { TableRow row = new TableRow<>(); diff --git a/desktop/src/main/resources/org/example/petshopdesktop/dialogviews/purchase-order-details-dialog-view.fxml b/desktop/src/main/resources/org/example/petshopdesktop/dialogviews/purchase-order-details-dialog-view.fxml new file mode 100644 index 00000000..f209eefb --- /dev/null +++ b/desktop/src/main/resources/org/example/petshopdesktop/dialogviews/purchase-order-details-dialog-view.fxml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + @@ -65,6 +73,12 @@ + + diff --git a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/analytics-view.fxml b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/analytics-view.fxml index dec7a883..215211b9 100644 --- a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/analytics-view.fxml +++ b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/analytics-view.fxml @@ -10,6 +10,7 @@ + @@ -25,6 +26,7 @@ + + + - + diff --git a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/appointment-view.fxml b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/appointment-view.fxml index 8e920be0..a508f9c0 100644 --- a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/appointment-view.fxml +++ b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/appointment-view.fxml @@ -51,6 +51,14 @@ + @@ -65,6 +73,12 @@ + + diff --git a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/inventory-view.fxml b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/inventory-view.fxml index 18e9ad5a..81eb71ba 100644 --- a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/inventory-view.fxml +++ b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/inventory-view.fxml @@ -51,6 +51,14 @@ + @@ -65,6 +73,12 @@ + + diff --git a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/pet-view.fxml b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/pet-view.fxml index d599e010..5aa0acdb 100644 --- a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/pet-view.fxml +++ b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/pet-view.fxml @@ -53,6 +53,14 @@ + @@ -69,6 +77,12 @@ + + diff --git a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/product-supplier-view.fxml b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/product-supplier-view.fxml index 19817faa..7d5afc4c 100644 --- a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/product-supplier-view.fxml +++ b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/product-supplier-view.fxml @@ -51,6 +51,14 @@ + @@ -65,6 +73,12 @@ + + diff --git a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/product-view.fxml b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/product-view.fxml index eeff74b4..641ba665 100644 --- a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/product-view.fxml +++ b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/product-view.fxml @@ -52,6 +52,14 @@ + @@ -67,6 +75,12 @@ + + diff --git a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/purchase-order-view.fxml b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/purchase-order-view.fxml index 74a00e6d..ab9276c4 100644 --- a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/purchase-order-view.fxml +++ b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/purchase-order-view.fxml @@ -55,6 +55,12 @@ + + diff --git a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/sale-view.fxml b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/sale-view.fxml index 3a3c9608..abf0df77 100644 --- a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/sale-view.fxml +++ b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/sale-view.fxml @@ -89,6 +89,11 @@ + diff --git a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/service-view.fxml b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/service-view.fxml index 5353b0e6..3a4ae448 100644 --- a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/service-view.fxml +++ b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/service-view.fxml @@ -51,6 +51,14 @@ + @@ -65,6 +73,12 @@ + + diff --git a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/staff-accounts-view.fxml b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/staff-accounts-view.fxml index 9619e374..da15274d 100644 --- a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/staff-accounts-view.fxml +++ b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/staff-accounts-view.fxml @@ -76,6 +76,12 @@ + + diff --git a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/supplier-view.fxml b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/supplier-view.fxml index 9c6d75cc..ade4b18d 100644 --- a/desktop/src/main/resources/org/example/petshopdesktop/modelviews/supplier-view.fxml +++ b/desktop/src/main/resources/org/example/petshopdesktop/modelviews/supplier-view.fxml @@ -51,6 +51,14 @@ + @@ -65,6 +73,12 @@ + +