diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java index af058a2..10775cc 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/engine/Exchange.java @@ -298,7 +298,7 @@ public Transaction sell(BigDecimal amount, List matchingShares = player.getPortfolio().getShares(stockSymbol); if (matchingShares.isEmpty()) { - throw new IllegalArgumentException("Player does not own any shares of this stock!"); + throw new IllegalArgumentException("No owned shares found of this stock!"); } BigDecimal totalOwned = matchingShares.stream() diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardController.java index 0fa8f8c..52f005c 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardController.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardController.java @@ -1,6 +1,7 @@ package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.dashboard; import edu.ntnu.idi.idatt2003.g40.mappe.engine.Exchange; +import edu.ntnu.idi.idatt2003.g40.mappe.exceptions.NotEnoughMoneyException; import edu.ntnu.idi.idatt2003.g40.mappe.model.*; import edu.ntnu.idi.idatt2003.g40.mappe.service.PurchaseCalculator; import edu.ntnu.idi.idatt2003.g40.mappe.service.SaleCalculator; @@ -244,14 +245,19 @@ protected void initInteractions() { if (Validator.NOT_EMPTY.isValid(getViewElement().getQuantityInputField().getText()) && Float.parseFloat(getViewElement().getQuantityInputField().getText()) > 0) { BigDecimal amountToBuy = new BigDecimal(getViewElement().getQuantityInputField().getText()); - Transaction purchase = exchange.buy( - getViewElement().getCurrentStock().getSymbol(), - amountToBuy, - player - ); - if (purchase.isCommited()) { - getViewElement().addOwnedShares(purchase.getShare().getQuantity().floatValue()); - updatePreviews(); + try { + Transaction purchase = exchange.buy( + getViewElement().getCurrentStock().getSymbol(), + amountToBuy, + player + ); + if (purchase.isCommited()) { + getViewElement().addOwnedShares(purchase.getShare().getQuantity().floatValue()); + displayTransactionReport(purchase, "Purchase successful!", null); + updatePreviews(); + } + } catch (NotEnoughMoneyException e) { + displayTransactionReport(null, "Purchase failed!", e.getMessage()); } } }); @@ -259,14 +265,19 @@ protected void initInteractions() { getViewElement().setOnAction(DashBoardActions.SELL_SHARES, () -> { if (Validator.NOT_EMPTY.isValid(getViewElement().getQuantityInputField().getText()) && Float.parseFloat(getViewElement().getQuantityInputField().getText()) > 0) { - Transaction sale = exchange.sell( - new BigDecimal(getViewElement().getQuantityInputField().getText()), - getViewElement().getCurrentStock().getSymbol(), - player); + try { + Transaction sale = exchange.sell( + new BigDecimal(getViewElement().getQuantityInputField().getText()), + getViewElement().getCurrentStock().getSymbol(), + player); if(sale.isCommited()) { getViewElement().addOwnedShares(-sale.getShare().getQuantity().floatValue()); + displayTransactionReport(sale, "Sale successful!", null); updatePreviews(); + } + } catch (IllegalArgumentException e) { + displayTransactionReport(null, "Sale failed!", e.getMessage()); } } }); @@ -379,7 +390,33 @@ public void handleEvent(final EventData data) { player.getPortfolio().getTotalShareQuantityBySymbol(s.getSymbol()).floatValue() ); } - updatePreviews(); } + + /** + * Method for displaying a report after performing a transaction attempt (buy/sell). + * + * @param transaction the transaction that occurred, or null if an error stopped execution. + * @param title the title header of the dialog window. + * @param errorMsg the error message to show if the transaction failed. + * */ + public void displayTransactionReport(final Transaction transaction, final String title, final String errorMsg) { + if (transaction != null && transaction.isCommited()) { + var calc = transaction.getCalculator(); + float tax = calc.calculateTax().floatValue(); + + getViewElement().showTransactionReport( + title, + transaction.getShare().getStock().getSymbol(), + transaction.getShare().getQuantity().floatValue(), + calc.calculateGross().floatValue(), + calc.calculateCommission().floatValue(), + tax, + calc.calculateTotal().floatValue(), + null + ); + } else { + getViewElement().showTransactionReport(title, "", 0f, 0f, 0f, 0f, 0f, errorMsg); + } + } } diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardView.java index dd69d82..e9eb1c0 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardView.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/dashboard/DashBoardView.java @@ -12,7 +12,10 @@ import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; import javafx.scene.control.ComboBox; +import javafx.scene.control.Dialog; +import javafx.scene.control.DialogPane; import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.control.Separator; @@ -662,4 +665,65 @@ private String formatShares(final float amount) { String formatted = String.format(java.util.Locale.US, "%.3f", amount); return formatted.replaceAll("0+$", "").replaceAll("\\.$", ""); } + + /** + * Displays a clean transaction report pop-up detailing the financial breakdown. + * + * @param title The title of the dialog box + * (e.g., "Purchase Confirmed"). + * @param symbol The stock ticker symbol. + * @param qty The amount of shares processed. + * @param gross The gross value of the transaction. + * @param commission The commission fee charged. + * @param tax The capital gains tax charged. + * @param total The net total amount. + * @param errorMessage Optional error message if transaction did not + * succesfully commit. + */ + public void showTransactionReport(final String title, + final String symbol, + final float qty, + final float gross, + final float commission, + final float tax, + final float total, + final String errorMessage) { + Dialog dialog = new Dialog<>(); + dialog.setTitle(title); + + DialogPane dialogPane = dialog.getDialogPane(); + dialogPane.getButtonTypes().add(ButtonType.CLOSE); + + //NOTE: Requires hard coding styling due to DialogPane behavior. + VBox container = new VBox(10); + container.setStyle("-fx-padding: 20; -fx-min-width: 320;"); + + if (errorMessage != null && !errorMessage.isEmpty()) { + Label errorLabel = new Label(errorMessage); + errorLabel.setStyle("-fx-text-fill: red; -fx-font-weight: bold; -fx-font-size: 14px;"); + container.getChildren().add(errorLabel); + } else { + Label headerLabel = new Label(symbol + " Transaction Summary"); + headerLabel.setStyle("-fx-font-weight: bold; -fx-font-size: 14px;"); + container.getChildren().addAll(headerLabel, new Separator()); + + String[][] rows = { + {"Quantity:", String.format("%.3f", qty)}, + {"Gross:", String.format("%.2f NOK", gross)}, + {"Tax:", String.format("%.2f NOK", tax)}, + {"Commission fee:", String.format("%.2f NOK", commission)}, + {"Total:", String.format("%.2f NOK", total)} + }; + + for (String[] rowData : rows) { + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + HBox row = new HBox(new Label(rowData[0]), spacer, new Label(rowData[1])); + container.getChildren().add(row); + } + } + + dialogPane.setContent(container); + dialog.showAndWait(); + } }