From 819bd924922271683e7356d0ffc3ee968b31f4cb Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Wed, 11 Mar 2026 14:21:40 -0600 Subject: [PATCH] Fix refund flow --- .../controllers/SaleController.java | 5 + .../RefundDialogController.java | 99 +++++++++++++++++-- 2 files changed, 97 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/controllers/SaleController.java b/src/main/java/org/example/petshopdesktop/controllers/SaleController.java index d85bffab..c3866b1e 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/SaleController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/SaleController.java @@ -372,6 +372,11 @@ public class SaleController { private void openRefundDialog() { try { SaleLineItem selectedSale = tvSales.getSelectionModel().getSelectedItem(); + if (selectedSale != null && selectedSale.isRefund()) { + showError("Refund", "Select an original sale, not an existing refund."); + return; + } + FXMLLoader loader = new FXMLLoader(getClass().getResource( "/org/example/petshopdesktop/dialogviews/refund-dialog-view.fxml")); Stage dialog = new Stage(); diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java index 581b579d..860a9921 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java @@ -86,6 +86,8 @@ public class RefundDialogController { private Button btnCancel; private SaleResponse currentSale; + private final List baseOriginalItems = new ArrayList<>(); + private final ObservableList originalItems = FXCollections.observableArrayList(); private final ObservableList refundItems = FXCollections.observableArrayList(); private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA); @@ -102,6 +104,7 @@ public class RefundDialogController { colOriginalQuantity.setCellValueFactory(new PropertyValueFactory<>("quantity")); colOriginalUnitPrice.setCellValueFactory(new PropertyValueFactory<>("unitPrice")); colOriginalTotal.setCellValueFactory(new PropertyValueFactory<>("lineTotal")); + tvOriginalItems.setItems(originalItems); tvOriginalItems.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); colRefundProduct.setCellValueFactory(new PropertyValueFactory<>("productName")); @@ -143,6 +146,11 @@ public class RefundDialogController { try { List allSales = SaleApi.getInstance().listSales(0, 1000, null); currentSale = SaleApi.getInstance().getSale(saleId); + if (Boolean.TRUE.equals(currentSale.getIsRefund())) { + clearLoadedSale(); + showError("Load Sale", "Select an original sale, not a refund record."); + return; + } List previousRefunds = allSales.stream() .filter(s -> Boolean.TRUE.equals(s.getIsRefund()) && saleId.equals(s.getOriginalSaleId())) .collect(Collectors.toList()); @@ -161,10 +169,13 @@ public class RefundDialogController { return; } - tvOriginalItems.setItems(FXCollections.observableArrayList(refundableItems)); + baseOriginalItems.clear(); + baseOriginalItems.addAll(copySaleItems(refundableItems)); + originalItems.setAll(copySaleItems(refundableItems)); cbPaymentMethod.getSelectionModel().select(currentSale.getPaymentMethod()); refundItems.clear(); + updateOriginalItemAvailability(); updateRefundTotal(); } catch (Exception e) { @@ -215,12 +226,8 @@ public class RefundDialogController { return; } - refundItems.add(new RefundItem( - selected.getProdId().intValue(), - selected.getProductName(), - quantity, - selected.getUnitPrice().doubleValue() - )); + addOrMergeRefundItem(selected, quantity); + updateOriginalItemAvailability(); updateRefundTotal(); } catch (NumberFormatException e) { @@ -234,6 +241,7 @@ public class RefundDialogController { RefundItem selected = tvRefundItems.getSelectionModel().getSelectedItem(); if (selected != null) { refundItems.remove(selected); + updateOriginalItemAvailability(); updateRefundTotal(); } } @@ -309,6 +317,83 @@ public class RefundDialogController { closeDialog(); } + private void clearLoadedSale() { + currentSale = null; + lblSaleInfo.setText(""); + baseOriginalItems.clear(); + originalItems.clear(); + refundItems.clear(); + updateRefundTotal(); + } + + private void addOrMergeRefundItem(SaleItemResponse selected, int quantity) { + for (int i = 0; i < refundItems.size(); i++) { + RefundItem existing = refundItems.get(i); + if (existing.getProdId() == selected.getProdId().intValue()) { + refundItems.set(i, new RefundItem( + existing.getProdId(), + existing.getProductName(), + existing.getQuantity() + quantity, + existing.getUnitPrice() + )); + return; + } + } + + refundItems.add(new RefundItem( + selected.getProdId().intValue(), + selected.getProductName(), + quantity, + selected.getUnitPrice().doubleValue() + )); + } + + private void updateOriginalItemAvailability() { + if (currentSale == null) { + baseOriginalItems.clear(); + originalItems.clear(); + return; + } + + Map pendingRefunds = new HashMap<>(); + for (RefundItem refundItem : refundItems) { + pendingRefunds.merge((long) refundItem.getProdId(), refundItem.getQuantity(), Integer::sum); + } + + List refreshedItems = new ArrayList<>(); + for (SaleItemResponse originalItem : baseOriginalItems) { + SaleItemResponse refreshedItem = copySaleItem(originalItem); + int pending = pendingRefunds.getOrDefault(refreshedItem.getProdId(), 0); + refreshedItem.setQuantity(Math.max(0, refreshedItem.getQuantity() - pending)); + if (refreshedItem.getQuantity() > 0) { + refreshedItems.add(refreshedItem); + } + } + + originalItems.setAll(refreshedItems); + tvOriginalItems.getSelectionModel().clearSelection(); + tvOriginalItems.refresh(); + tvRefundItems.refresh(); + } + + private List copySaleItems(List items) { + List copies = new ArrayList<>(); + for (SaleItemResponse item : items) { + copies.add(copySaleItem(item)); + } + return copies; + } + + private SaleItemResponse copySaleItem(SaleItemResponse source) { + SaleItemResponse copy = new SaleItemResponse(); + copy.setSaleItemId(source.getSaleItemId()); + copy.setProdId(source.getProdId()); + copy.setProductName(source.getProductName()); + copy.setQuantity(source.getQuantity()); + copy.setUnitPrice(source.getUnitPrice()); + return copy; + } + private void updateRefundTotal() { double total = refundItems.stream().mapToDouble(RefundItem::getTotal).sum(); lblRefundTotal.setText(currency.format(total));