Implement refund system for sales
This commit is contained in:
@@ -5,6 +5,8 @@ import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ComboBox;
|
||||
@@ -17,6 +19,8 @@ import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.auth.UserSession;
|
||||
import org.example.petshopdesktop.database.InventoryDB;
|
||||
import org.example.petshopdesktop.database.ProductDB;
|
||||
@@ -38,6 +42,9 @@ public class SaleController {
|
||||
@FXML
|
||||
private Button btnRefresh;
|
||||
|
||||
@FXML
|
||||
private Button btnRefund;
|
||||
|
||||
@FXML
|
||||
private Label lblModeNote;
|
||||
|
||||
@@ -319,6 +326,30 @@ public class SaleController {
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnRefund(ActionEvent event) {
|
||||
openRefundDialog();
|
||||
}
|
||||
|
||||
private void openRefundDialog() {
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource(
|
||||
"/org/example/petshopdesktop/dialogviews/refund-dialog-view.fxml"));
|
||||
Stage dialog = new Stage();
|
||||
dialog.initOwner(btnRefund.getScene().getWindow());
|
||||
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||
dialog.setTitle("Process Refund");
|
||||
dialog.setScene(new Scene(loader.load()));
|
||||
dialog.setResizable(false);
|
||||
dialog.showAndWait();
|
||||
|
||||
refreshInventory();
|
||||
refreshSales(true);
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException("SaleController.openRefundDialog", e, "Opening refund dialog");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCartTotal() {
|
||||
double total = cartItems.stream().mapToDouble(SaleCartItem::getTotal).sum();
|
||||
lblCartTotal.setText(currency.format(total));
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.auth.UserSession;
|
||||
import org.example.petshopdesktop.database.SaleDB;
|
||||
import org.example.petshopdesktop.models.SaleCartItem;
|
||||
import org.example.petshopdesktop.models.SaleDetail;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.text.NumberFormat;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
public class RefundDialogController {
|
||||
|
||||
@FXML
|
||||
private TextField txtSaleId;
|
||||
|
||||
@FXML
|
||||
private Button btnLoadSale;
|
||||
|
||||
@FXML
|
||||
private Label lblSaleInfo;
|
||||
|
||||
@FXML
|
||||
private TableView<SaleDetail.SaleDetailItem> tvOriginalItems;
|
||||
|
||||
@FXML
|
||||
private TableColumn<SaleDetail.SaleDetailItem, String> colOriginalProduct;
|
||||
|
||||
@FXML
|
||||
private TableColumn<SaleDetail.SaleDetailItem, Integer> colOriginalQuantity;
|
||||
|
||||
@FXML
|
||||
private TableColumn<SaleDetail.SaleDetailItem, Double> colOriginalUnitPrice;
|
||||
|
||||
@FXML
|
||||
private TableColumn<SaleDetail.SaleDetailItem, Double> colOriginalTotal;
|
||||
|
||||
@FXML
|
||||
private Button btnAddToRefund;
|
||||
|
||||
@FXML
|
||||
private TableView<RefundItem> tvRefundItems;
|
||||
|
||||
@FXML
|
||||
private TableColumn<RefundItem, String> colRefundProduct;
|
||||
|
||||
@FXML
|
||||
private TableColumn<RefundItem, Integer> colRefundQuantity;
|
||||
|
||||
@FXML
|
||||
private TableColumn<RefundItem, Double> colRefundUnitPrice;
|
||||
|
||||
@FXML
|
||||
private TableColumn<RefundItem, Double> colRefundTotal;
|
||||
|
||||
@FXML
|
||||
private Button btnRemoveFromRefund;
|
||||
|
||||
@FXML
|
||||
private ComboBox<String> cbPaymentMethod;
|
||||
|
||||
@FXML
|
||||
private Label lblRefundTotal;
|
||||
|
||||
@FXML
|
||||
private Button btnProcessRefund;
|
||||
|
||||
@FXML
|
||||
private Button btnCancel;
|
||||
|
||||
private SaleDetail currentSale;
|
||||
private final ObservableList<RefundItem> refundItems = FXCollections.observableArrayList();
|
||||
private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA);
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
setupTables();
|
||||
cbPaymentMethod.setItems(FXCollections.observableArrayList("Cash", "Card", "Debit"));
|
||||
cbPaymentMethod.getSelectionModel().selectFirst();
|
||||
updateRefundTotal();
|
||||
}
|
||||
|
||||
private void setupTables() {
|
||||
colOriginalProduct.setCellValueFactory(new PropertyValueFactory<>("productName"));
|
||||
colOriginalQuantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
|
||||
colOriginalUnitPrice.setCellValueFactory(new PropertyValueFactory<>("unitPrice"));
|
||||
colOriginalTotal.setCellValueFactory(new PropertyValueFactory<>("total"));
|
||||
tvOriginalItems.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
|
||||
|
||||
colRefundProduct.setCellValueFactory(new PropertyValueFactory<>("productName"));
|
||||
colRefundQuantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
|
||||
colRefundUnitPrice.setCellValueFactory(new PropertyValueFactory<>("unitPrice"));
|
||||
colRefundTotal.setCellValueFactory(new PropertyValueFactory<>("total"));
|
||||
tvRefundItems.setItems(refundItems);
|
||||
tvRefundItems.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnLoadSaleClicked(ActionEvent event) {
|
||||
String saleIdText = txtSaleId.getText().trim();
|
||||
if (saleIdText.isEmpty()) {
|
||||
showError("Load Sale", "Enter a transaction ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
int saleId;
|
||||
try {
|
||||
saleId = Integer.parseInt(saleIdText);
|
||||
} catch (NumberFormatException e) {
|
||||
showError("Load Sale", "Invalid transaction ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (SaleDB.isRefunded(saleId)) {
|
||||
showError("Load Sale", "This sale has already been refunded.");
|
||||
return;
|
||||
}
|
||||
|
||||
currentSale = SaleDB.getSaleById(saleId);
|
||||
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||
String saleInfo = String.format("Sale Date: %s | Employee: %s | Original Total: %s | Payment: %s",
|
||||
currentSale.getSaleDate().format(formatter),
|
||||
currentSale.getEmployeeName(),
|
||||
currency.format(currentSale.getTotalAmount()),
|
||||
currentSale.getPaymentMethod());
|
||||
lblSaleInfo.setText(saleInfo);
|
||||
|
||||
tvOriginalItems.setItems(currentSale.getItems());
|
||||
cbPaymentMethod.getSelectionModel().select(currentSale.getPaymentMethod());
|
||||
|
||||
refundItems.clear();
|
||||
updateRefundTotal();
|
||||
|
||||
} catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException("RefundDialogController.btnLoadSaleClicked", e, "Loading sale");
|
||||
showError("Load Sale", e.getMessage() != null ? e.getMessage() : "Could not load sale.");
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnAddToRefundClicked(ActionEvent event) {
|
||||
if (currentSale == null) {
|
||||
showError("Add to Refund", "Load a sale first.");
|
||||
return;
|
||||
}
|
||||
|
||||
SaleDetail.SaleDetailItem selected = tvOriginalItems.getSelectionModel().getSelectedItem();
|
||||
if (selected == null) {
|
||||
showError("Add to Refund", "Select an item from the original sale.");
|
||||
return;
|
||||
}
|
||||
|
||||
int alreadyRefunded = refundItems.stream()
|
||||
.filter(r -> r.getProdId() == selected.getProdId())
|
||||
.mapToInt(RefundItem::getQuantity)
|
||||
.sum();
|
||||
|
||||
int available = selected.getQuantity() - alreadyRefunded;
|
||||
if (available <= 0) {
|
||||
showError("Add to Refund", "All items of this product are already in the refund list.");
|
||||
return;
|
||||
}
|
||||
|
||||
TextInputDialog dialog = new TextInputDialog(String.valueOf(available));
|
||||
dialog.setTitle("Refund Quantity");
|
||||
dialog.setHeaderText("Product: " + selected.getProductName());
|
||||
dialog.setContentText("Enter quantity to refund (max " + available + "):");
|
||||
|
||||
Optional<String> result = dialog.showAndWait();
|
||||
if (result.isPresent()) {
|
||||
try {
|
||||
int quantity = Integer.parseInt(result.get().trim());
|
||||
if (quantity <= 0) {
|
||||
showError("Add to Refund", "Quantity must be at least 1.");
|
||||
return;
|
||||
}
|
||||
if (quantity > available) {
|
||||
showError("Add to Refund", "Cannot refund more than " + available + " items.");
|
||||
return;
|
||||
}
|
||||
|
||||
refundItems.add(new RefundItem(
|
||||
selected.getProdId(),
|
||||
selected.getProductName(),
|
||||
quantity,
|
||||
selected.getUnitPrice()
|
||||
));
|
||||
updateRefundTotal();
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
showError("Add to Refund", "Invalid quantity.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnRemoveFromRefundClicked(ActionEvent event) {
|
||||
RefundItem selected = tvRefundItems.getSelectionModel().getSelectedItem();
|
||||
if (selected != null) {
|
||||
refundItems.remove(selected);
|
||||
updateRefundTotal();
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnProcessRefundClicked(ActionEvent event) {
|
||||
if (currentSale == null) {
|
||||
showError("Process Refund", "Load a sale first.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (refundItems.isEmpty()) {
|
||||
showError("Process Refund", "Add at least one item to refund.");
|
||||
return;
|
||||
}
|
||||
|
||||
Integer employeeId = UserSession.getInstance().getEmployeeId();
|
||||
if (employeeId == null || employeeId <= 0) {
|
||||
showError("Process Refund", "Employee is not set for this account.");
|
||||
return;
|
||||
}
|
||||
|
||||
String payment = cbPaymentMethod.getSelectionModel().getSelectedItem();
|
||||
if (payment == null || payment.isBlank()) {
|
||||
showError("Process Refund", "Select a payment method.");
|
||||
return;
|
||||
}
|
||||
|
||||
Alert confirm = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
confirm.setTitle("Confirm Refund");
|
||||
confirm.setHeaderText("Process refund for sale ID " + currentSale.getSaleId() + "?");
|
||||
confirm.setContentText("Refund amount: " + lblRefundTotal.getText());
|
||||
|
||||
Optional<ButtonType> confirmResult = confirm.showAndWait();
|
||||
if (confirmResult.isEmpty() || confirmResult.get() != ButtonType.OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ObservableList<SaleCartItem> cartItems = FXCollections.observableArrayList();
|
||||
for (RefundItem item : refundItems) {
|
||||
cartItems.add(new SaleCartItem(item.getProdId(), item.getProductName(), item.getQuantity(), item.getUnitPrice()));
|
||||
}
|
||||
|
||||
int refundId = SaleDB.createRefund(currentSale.getSaleId(), employeeId, payment, cartItems);
|
||||
|
||||
Alert success = new Alert(Alert.AlertType.INFORMATION);
|
||||
success.setTitle("Refund Processed");
|
||||
success.setHeaderText(null);
|
||||
success.setContentText("Refund ID " + refundId + " was created successfully.");
|
||||
success.showAndWait();
|
||||
|
||||
closeDialog();
|
||||
|
||||
} catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException("RefundDialogController.btnProcessRefundClicked", e, "Processing refund");
|
||||
showError("Process Refund", e.getMessage() != null ? e.getMessage() : "Could not process refund.");
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnCancelClicked(ActionEvent event) {
|
||||
closeDialog();
|
||||
}
|
||||
|
||||
private void updateRefundTotal() {
|
||||
double total = refundItems.stream().mapToDouble(RefundItem::getTotal).sum();
|
||||
lblRefundTotal.setText(currency.format(total));
|
||||
}
|
||||
|
||||
private void closeDialog() {
|
||||
Stage stage = (Stage) btnCancel.getScene().getWindow();
|
||||
stage.close();
|
||||
}
|
||||
|
||||
private void showError(String title, String message) {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setTitle(title);
|
||||
alert.setHeaderText(null);
|
||||
alert.setContentText(message);
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
public static class RefundItem {
|
||||
private final int prodId;
|
||||
private final String productName;
|
||||
private final int quantity;
|
||||
private final double unitPrice;
|
||||
|
||||
public RefundItem(int prodId, String productName, int quantity, double unitPrice) {
|
||||
this.prodId = prodId;
|
||||
this.productName = productName;
|
||||
this.quantity = quantity;
|
||||
this.unitPrice = unitPrice;
|
||||
}
|
||||
|
||||
public int getProdId() {
|
||||
return prodId;
|
||||
}
|
||||
|
||||
public String getProductName() {
|
||||
return productName;
|
||||
}
|
||||
|
||||
public int getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public double getUnitPrice() {
|
||||
return unitPrice;
|
||||
}
|
||||
|
||||
public double getTotal() {
|
||||
return quantity * unitPrice;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import org.example.petshopdesktop.DTOs.SaleDTO;
|
||||
import org.example.petshopdesktop.models.SaleCartItem;
|
||||
import org.example.petshopdesktop.models.SaleDetail;
|
||||
import org.example.petshopdesktop.models.SaleLineItem;
|
||||
import org.example.petshopdesktop.models.analytics.*;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
@@ -129,7 +130,8 @@ public class SaleDB {
|
||||
si.quantity,
|
||||
si.unitPrice,
|
||||
(si.quantity * si.unitPrice) as total,
|
||||
s.paymentMethod
|
||||
s.paymentMethod,
|
||||
s.isRefund
|
||||
FROM sale s
|
||||
JOIN saleItem si ON s.saleId = si.saleId
|
||||
JOIN product p ON si.prodId = p.prodId
|
||||
@@ -149,7 +151,8 @@ public class SaleDB {
|
||||
rs.getInt("quantity"),
|
||||
rs.getDouble("unitPrice"),
|
||||
rs.getDouble("total"),
|
||||
rs.getString("paymentMethod")
|
||||
rs.getString("paymentMethod"),
|
||||
rs.getBoolean("isRefund")
|
||||
));
|
||||
}
|
||||
|
||||
@@ -397,4 +400,173 @@ public class SaleDB {
|
||||
conn.close();
|
||||
return summary;
|
||||
}
|
||||
|
||||
public static SaleDetail getSaleById(int saleId) throws SQLException {
|
||||
Connection conn = ConnectionDB.getConnection();
|
||||
|
||||
String saleSql = """
|
||||
SELECT s.saleId, s.saleDate, s.totalAmount, s.paymentMethod,
|
||||
CONCAT(e.firstName, ' ', e.lastName) as employeeName,
|
||||
s.isRefund
|
||||
FROM sale s
|
||||
JOIN employee e ON s.employeeId = e.employeeId
|
||||
WHERE s.saleId = ?
|
||||
""";
|
||||
|
||||
PreparedStatement saleStmt = conn.prepareStatement(saleSql);
|
||||
saleStmt.setInt(1, saleId);
|
||||
ResultSet saleRs = saleStmt.executeQuery();
|
||||
|
||||
if (!saleRs.next()) {
|
||||
conn.close();
|
||||
throw new SQLException("Sale not found with ID: " + saleId);
|
||||
}
|
||||
|
||||
boolean isRefund = saleRs.getBoolean("isRefund");
|
||||
if (isRefund) {
|
||||
conn.close();
|
||||
throw new SQLException("Cannot refund a refund transaction");
|
||||
}
|
||||
|
||||
SaleDetail detail = new SaleDetail(
|
||||
saleRs.getInt("saleId"),
|
||||
saleRs.getTimestamp("saleDate").toLocalDateTime(),
|
||||
saleRs.getDouble("totalAmount"),
|
||||
saleRs.getString("paymentMethod"),
|
||||
saleRs.getString("employeeName"),
|
||||
FXCollections.observableArrayList()
|
||||
);
|
||||
|
||||
String itemsSql = """
|
||||
SELECT si.prodId, p.prodName, si.quantity, si.unitPrice,
|
||||
(si.quantity * si.unitPrice) as total
|
||||
FROM saleItem si
|
||||
JOIN product p ON si.prodId = p.prodId
|
||||
WHERE si.saleId = ?
|
||||
""";
|
||||
|
||||
PreparedStatement itemsStmt = conn.prepareStatement(itemsSql);
|
||||
itemsStmt.setInt(1, saleId);
|
||||
ResultSet itemsRs = itemsStmt.executeQuery();
|
||||
|
||||
while (itemsRs.next()) {
|
||||
detail.getItems().add(new SaleDetail.SaleDetailItem(
|
||||
itemsRs.getInt("prodId"),
|
||||
itemsRs.getString("prodName"),
|
||||
itemsRs.getInt("quantity"),
|
||||
itemsRs.getDouble("unitPrice"),
|
||||
itemsRs.getDouble("total")
|
||||
));
|
||||
}
|
||||
|
||||
conn.close();
|
||||
return detail;
|
||||
}
|
||||
|
||||
public static boolean isRefunded(int saleId) throws SQLException {
|
||||
Connection conn = ConnectionDB.getConnection();
|
||||
|
||||
String sql = """
|
||||
SELECT COUNT(*) as refundCount
|
||||
FROM sale
|
||||
WHERE originalSaleId = ? AND isRefund = TRUE
|
||||
""";
|
||||
|
||||
PreparedStatement pstmt = conn.prepareStatement(sql);
|
||||
pstmt.setInt(1, saleId);
|
||||
ResultSet rs = pstmt.executeQuery();
|
||||
|
||||
boolean refunded = false;
|
||||
if (rs.next()) {
|
||||
refunded = rs.getInt("refundCount") > 0;
|
||||
}
|
||||
|
||||
conn.close();
|
||||
return refunded;
|
||||
}
|
||||
|
||||
public static int createRefund(int originalSaleId, int employeeId, String paymentMethod, ObservableList<SaleCartItem> refundItems) throws SQLException {
|
||||
if (refundItems.isEmpty()) {
|
||||
throw new SQLException("Cannot create refund with empty items");
|
||||
}
|
||||
|
||||
Connection conn = ConnectionDB.getConnection();
|
||||
|
||||
SaleDetail originalSale = getSaleById(originalSaleId);
|
||||
conn = ConnectionDB.getConnection();
|
||||
|
||||
if (isRefunded(originalSaleId)) {
|
||||
throw new SQLException("This sale has already been refunded");
|
||||
}
|
||||
|
||||
conn.setAutoCommit(false);
|
||||
|
||||
try {
|
||||
double totalAmount = -refundItems.stream().mapToDouble(SaleCartItem::getTotal).sum();
|
||||
|
||||
String insertSale = """
|
||||
INSERT INTO sale (saleDate, totalAmount, paymentMethod, employeeId, storeId, isRefund, originalSaleId)
|
||||
VALUES (NOW(), ?, ?, ?, 1, TRUE, ?)
|
||||
""";
|
||||
|
||||
PreparedStatement saleStmt = conn.prepareStatement(insertSale, Statement.RETURN_GENERATED_KEYS);
|
||||
saleStmt.setDouble(1, totalAmount);
|
||||
saleStmt.setString(2, paymentMethod);
|
||||
saleStmt.setInt(3, employeeId);
|
||||
saleStmt.setInt(4, originalSaleId);
|
||||
saleStmt.executeUpdate();
|
||||
|
||||
ResultSet rs = saleStmt.getGeneratedKeys();
|
||||
if (!rs.next()) {
|
||||
throw new SQLException("Failed to get generated refund ID");
|
||||
}
|
||||
int refundId = rs.getInt(1);
|
||||
|
||||
String insertItem = """
|
||||
INSERT INTO saleItem (saleId, prodId, quantity, unitPrice)
|
||||
VALUES (?, ?, ?, ?)
|
||||
""";
|
||||
|
||||
String updateInventory = """
|
||||
UPDATE inventory
|
||||
SET quantity = quantity + ?
|
||||
WHERE prodId = ?
|
||||
""";
|
||||
|
||||
PreparedStatement itemStmt = conn.prepareStatement(insertItem);
|
||||
PreparedStatement invStmt = conn.prepareStatement(updateInventory);
|
||||
|
||||
for (SaleCartItem item : refundItems) {
|
||||
itemStmt.setInt(1, refundId);
|
||||
itemStmt.setInt(2, item.getProdId());
|
||||
itemStmt.setInt(3, -item.getQuantity());
|
||||
itemStmt.setDouble(4, item.getUnitPrice());
|
||||
itemStmt.executeUpdate();
|
||||
|
||||
invStmt.setInt(1, item.getQuantity());
|
||||
invStmt.setInt(2, item.getProdId());
|
||||
int updated = invStmt.executeUpdate();
|
||||
|
||||
if (updated == 0) {
|
||||
throw new SQLException("Failed to update inventory for product ID " + item.getProdId());
|
||||
}
|
||||
}
|
||||
|
||||
conn.commit();
|
||||
|
||||
ActivityLogger.getInstance().logInsert("sale",
|
||||
String.format("Refund ID: %d", refundId),
|
||||
String.format("Created refund for sale ID %d with %d items, total: $%.2f", originalSaleId, refundItems.size(), Math.abs(totalAmount)));
|
||||
|
||||
return refundId;
|
||||
|
||||
} catch (SQLException e) {
|
||||
conn.rollback();
|
||||
ActivityLogger.getInstance().logException("SaleDB.createRefund", e, "Creating refund");
|
||||
throw e;
|
||||
} finally {
|
||||
conn.setAutoCommit(true);
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package org.example.petshopdesktop.models;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class SaleDetail {
|
||||
private final int saleId;
|
||||
private final LocalDateTime saleDate;
|
||||
private final double totalAmount;
|
||||
private final String paymentMethod;
|
||||
private final String employeeName;
|
||||
private final ObservableList<SaleDetailItem> items;
|
||||
|
||||
public SaleDetail(int saleId, LocalDateTime saleDate, double totalAmount, String paymentMethod, String employeeName, ObservableList<SaleDetailItem> items) {
|
||||
this.saleId = saleId;
|
||||
this.saleDate = saleDate;
|
||||
this.totalAmount = totalAmount;
|
||||
this.paymentMethod = paymentMethod;
|
||||
this.employeeName = employeeName;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public int getSaleId() {
|
||||
return saleId;
|
||||
}
|
||||
|
||||
public LocalDateTime getSaleDate() {
|
||||
return saleDate;
|
||||
}
|
||||
|
||||
public double getTotalAmount() {
|
||||
return totalAmount;
|
||||
}
|
||||
|
||||
public String getPaymentMethod() {
|
||||
return paymentMethod;
|
||||
}
|
||||
|
||||
public String getEmployeeName() {
|
||||
return employeeName;
|
||||
}
|
||||
|
||||
public ObservableList<SaleDetailItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public static class SaleDetailItem {
|
||||
private final int prodId;
|
||||
private final String productName;
|
||||
private final int quantity;
|
||||
private final double unitPrice;
|
||||
private final double total;
|
||||
|
||||
public SaleDetailItem(int prodId, String productName, int quantity, double unitPrice, double total) {
|
||||
this.prodId = prodId;
|
||||
this.productName = productName;
|
||||
this.quantity = quantity;
|
||||
this.unitPrice = unitPrice;
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public int getProdId() {
|
||||
return prodId;
|
||||
}
|
||||
|
||||
public String getProductName() {
|
||||
return productName;
|
||||
}
|
||||
|
||||
public int getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public double getUnitPrice() {
|
||||
return unitPrice;
|
||||
}
|
||||
|
||||
public double getTotal() {
|
||||
return total;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,9 @@ public class SaleLineItem {
|
||||
private final double unitPrice;
|
||||
private final double total;
|
||||
private final String paymentMethod;
|
||||
private final boolean isRefund;
|
||||
|
||||
public SaleLineItem(int saleId, String saleDate, String employeeName, String itemName, int quantity, double unitPrice, double total, String paymentMethod) {
|
||||
public SaleLineItem(int saleId, String saleDate, String employeeName, String itemName, int quantity, double unitPrice, double total, String paymentMethod, boolean isRefund) {
|
||||
this.saleId = saleId;
|
||||
this.saleDate = saleDate;
|
||||
this.employeeName = employeeName;
|
||||
@@ -19,6 +20,7 @@ public class SaleLineItem {
|
||||
this.unitPrice = unitPrice;
|
||||
this.total = total;
|
||||
this.paymentMethod = paymentMethod;
|
||||
this.isRefund = isRefund;
|
||||
}
|
||||
|
||||
public int getSaleId() {
|
||||
@@ -52,4 +54,8 @@ public class SaleLineItem {
|
||||
public String getPaymentMethod() {
|
||||
return paymentMethod;
|
||||
}
|
||||
|
||||
public boolean isRefund() {
|
||||
return isRefund;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user