Skip to content

UI portfolio logic #57

Merged
merged 8 commits into from
May 16, 2026
3 changes: 3 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt/model/player/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,8 @@ public String getStatus() {

return "Novice";
}
public BigDecimal getStartingMoney(){
return startingMoney;
}

}
27 changes: 21 additions & 6 deletions src/main/java/edu/ntnu/idi/idatt/model/portfolio/Portfolio.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,33 @@ public BigDecimal getOwnedAmount(String symbol) {
.reduce(BigDecimal.ZERO, BigDecimal::add);
}

public BigDecimal getOwnedAmount() {
return getShares().stream().map(s -> s.getQuantity())
.reduce(BigDecimal.ZERO, BigDecimal::add);
}

public BigDecimal getProfitFromStock(String symbol) {
return getShares(symbol).stream().map(s -> {
BigDecimal total = new SaleCalculator(s).calculateTotal();
BigDecimal buyPrice = s.getQuantity().multiply(s.getPurchasePrice());
return getShares(symbol).stream().map(s -> s.getProfit()).reduce(BigDecimal.ZERO, BigDecimal::add);
}

return total.subtract(buyPrice);
}).reduce(BigDecimal.ZERO, BigDecimal::add);
public BigDecimal getProfitFromStock() {
return getShares().stream().map(s -> s.getProfit()).reduce(BigDecimal.ZERO, BigDecimal::add);
}

public BigDecimal getChangeFromStock(String symbol) {
BigDecimal profitTotal = getProfitFromStock(symbol);
BigDecimal costTotal = getShares(symbol).stream().map(s -> s.getPurchasePrice().multiply(s.getQuantity()))
BigDecimal costTotal = getShares(symbol).stream().map(s -> s.getTotalPurchasePrice())
.reduce(BigDecimal.ZERO, BigDecimal::add);

if (costTotal.compareTo(BigDecimal.ZERO) <= 0)
return BigDecimal.ZERO;

return profitTotal.divide(costTotal, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
}

public BigDecimal getChangeFromStock() {
BigDecimal profitTotal = getProfitFromStock();
BigDecimal costTotal = getShares().stream().map(s -> s.getTotalPurchasePrice())
.reduce(BigDecimal.ZERO, BigDecimal::add);

if (costTotal.compareTo(BigDecimal.ZERO) <= 0)
Expand Down
12 changes: 10 additions & 2 deletions src/main/java/edu/ntnu/idi/idatt/model/portfolio/Share.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package edu.ntnu.idi.idatt.model.portfolio;

import java.math.BigDecimal;
import java.math.RoundingMode;

import edu.ntnu.idi.idatt.model.market.Stock;
import edu.ntnu.idi.idatt.service.transaction.SaleCalculator;
Expand Down Expand Up @@ -52,9 +53,16 @@ public BigDecimal getPurchasePrice() {
}

// TODO: JAVADOCS, JUNIT
public BigDecimal getTotalPurchasePrice() {
return purchasePrice.multiply(quantity);
}

public BigDecimal getProfit() {
BigDecimal totalCost = purchasePrice.multiply(quantity);
return new SaleCalculator(this).calculateGross().subtract(totalCost);
return new SaleCalculator(this).calculateGross().subtract(getTotalPurchasePrice());
}

public BigDecimal getProfitPercent() {
return getProfit().divide(getTotalPurchasePrice(), 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import edu.ntnu.idi.idatt.model.portfolio.Share;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
* SaleCalculator class
Expand Down Expand Up @@ -78,7 +79,7 @@ public BigDecimal calculateTotal() {

// TODO: Javadocs, junit
public BigDecimal calculateProfit() {
return calculateTotal().divide(purchasePrice.multiply(quantity));
return calculateGross().subtract(purchasePrice.multiply(quantity));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
import edu.ntnu.idi.idatt.model.portfolio.Portfolio;
import edu.ntnu.idi.idatt.session.UserSession;
import edu.ntnu.idi.idatt.view.components.ui.UICompositor;
import edu.ntnu.idi.idatt.view.util.CssUtils;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;

Expand All @@ -16,20 +20,28 @@ public class PlayerPortfolioComponent extends HBox {
public PlayerPortfolioComponent(Portfolio portfolio) {
this.setMaxSize(Double.MAX_VALUE, 500);
this.getStyleClass().add("light");
BigDecimal startingMoney = UserSession.getInstance().getPlayer().getStartingMoney();
BigDecimal netMoney = UserSession.getInstance().getPlayer().getNetWorth();
BigDecimal netPercentage = netMoney.divide(startingMoney)
.multiply(new BigDecimal("100"))
.setScale(2, RoundingMode.HALF_UP)
.subtract(new BigDecimal("100"));

Label userTitle = new Label(String.format("%s's Portfolio", UserSession.getInstance().getPlayer().getName()));
Label netWorth = new Label();
netWorth.textProperty().bind(
UserSession.getInstance().netWorthProperty().asString("Net Worth: %.2f $"));
Label percentageChange = new Label(
"Percentage change: " + UserSession.getInstance().netWorthProperty().get());
"Percentage change: " + netPercentage + "%");
Label playerStatus = new Label("Player status: " + UserSession.getInstance().getPlayer().getStatus());
Label totalShares = new Label(
"Total shares owned: " + UserSession.getInstance().getPlayer().getPortfolio().getShares().size());
ArrayList<Label> labels = new ArrayList<>();
Collections.addAll(labels, netWorth, percentageChange, playerStatus, totalShares);
labels.forEach(e -> e.getStyleClass().add("portfolio-box-text"));
userTitle.getStyleClass().add("portfolio-box-title");
String color = CssUtils.generateValueColors(netPercentage);
CssUtils.apply(percentageChange, color);

UICompositor playerPortfolioComponent = new UICompositor.Builder()
.parent(new HBox())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,57 @@
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

import java.util.ArrayList;
import java.util.Collections;

import java.util.List;
import java.util.function.Consumer;

public class ShareComponent extends HBox {

public ShareComponent(Share share){
this.setMaxSize(Double.MAX_VALUE, 300);
this.setPadding(new Insets(30));
this.getStyleClass().add("rowBox");

Label name = new Label(share.getStock().getCompany());
Label quantity = new Label("Owned shares: "+share.getQuantity().toString());
Label ticker = new Label("("+share.getStock().getSymbol()+")");
Label latestPrice = new Label("Latest price: "+share.getStock().getSalesPrice().toString());
Button sellButton = new Button("Sell");

ArrayList<Label> labels = new ArrayList<>();
Collections.addAll(labels, name, quantity, ticker, latestPrice);
labels.forEach(e -> e.getStyleClass().add("portfolio-box-text"));
sellButton.getStyleClass().add("button");
String color = CssUtils.generateValueColors(share.getProfit().doubleValue());
CssUtils.apply(latestPrice, color);

UICompositor shareComponent = new UICompositor.Builder()
.parent(new HBox())
.growWithAlignment(Pos.CENTER)
.addAllContent(name, ticker)
.filler()
.addContent(latestPrice)
.filler()
.addContent(quantity)
.filler()
.addContent(sellButton)
.build();

this.getChildren().add(shareComponent.makeUI());
}
private final Share share;
private Button sellButton;

public ShareComponent(Share share) {
this.share = share;

this.setMaxSize(Double.MAX_VALUE, 300);
this.setPadding(new Insets(30));
this.getStyleClass().add("rowBox");

Label title = new Label(share.getStock().toString());
Label quantity = new Label("Owned shares: " + share.getQuantity().toString());
Label latestValueLabel = new Label("Net profit:");
Label latestValue = new Label(String.format("%.2f $", share.getProfit()));
Label latestValueChange = new Label(String.format("%.2f %%", share.getProfitPercent()));

sellButton = new Button("Sell");

List<Label> labels = List.of(title, quantity, latestValueLabel, latestValue, latestValueChange);
labels.forEach(e -> e.getStyleClass().add("portfolio-box-text"));
sellButton.getStyleClass().add("button");
String color = CssUtils.generateValueColors(share.getProfit());
CssUtils.apply(latestValue, color);
CssUtils.apply(latestValueChange, color);

UICompositor shareComponent = new UICompositor.Builder()
.parent(new HBox())
.growWithAlignment(Pos.CENTER)
.addContent(title)
.filler()
.wrap(new VBox())
.addAllContent(latestValueLabel, latestValue, latestValueChange)
.unwrap()
.filler()
.addContent(quantity)
.filler()
.addContent(sellButton)
.build();

this.getChildren().add(shareComponent.makeUI());
}

public void onShareSellButton(Consumer<Share> handler) {
sellButton.setOnAction((e) -> handler.accept(share));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import edu.ntnu.idi.idatt.model.transaction.Purchase;
import edu.ntnu.idi.idatt.model.transaction.Sale;
import edu.ntnu.idi.idatt.model.transaction.Transaction;
import edu.ntnu.idi.idatt.service.transaction.PurchaseCalculator;
import edu.ntnu.idi.idatt.service.transaction.SaleCalculator;
import edu.ntnu.idi.idatt.service.transaction.TransactionCalculator;
import edu.ntnu.idi.idatt.view.components.ui.UICompositor;
Expand All @@ -20,7 +21,6 @@ public class TransactionComponent extends VBox {
public TransactionComponent(Transaction transaction) {

Stock stock = transaction.getShare().getStock();
TransactionCalculator calculator = transaction.getCalculator();

Label title;
Label name = new Label(stock.toString());
Expand All @@ -30,18 +30,20 @@ public TransactionComponent(Transaction transaction) {
Label amountOfShares;
Label saleProfit;

totalValue = new Label(String.format("Total: %.2f USD", calculator.calculateTotal()));

taxComissionValue = new Label(String.format(
"Tax & Comission: %.2f USD", calculator.calculateTax().add(calculator.calculateCommision())));

grossValue = new Label(String.format("Gross: %.2f USD", calculator.calculateGross()));

amountOfShares = new Label(
String.format("Shares: %.2f [%s]", transaction.getShare().getQuantity(), stock.getSymbol()));

if (transaction instanceof Purchase) {
title = new Label("PURCHASE");
PurchaseCalculator pCalc = (PurchaseCalculator) transaction.getCalculator();

totalValue = new Label(String.format("Total: %.2f USD", pCalc.calculateTotal()));

taxComissionValue = new Label(String.format(
"Tax & Comission: %.2f USD", pCalc.calculateTax().add(pCalc.calculateCommision())));

grossValue = new Label(String.format("Gross: %.2f USD", pCalc.calculateGross()));

saleProfit = new Label();
CssUtils.apply(title, CssUtils.GREEN);

Expand All @@ -50,9 +52,17 @@ public TransactionComponent(Transaction transaction) {
CssUtils.apply(title, CssUtils.RED);

SaleCalculator sCalc = (SaleCalculator) transaction.getCalculator();

totalValue = new Label(String.format("Total: %.2f USD", sCalc.calculateTotal()));

taxComissionValue = new Label(String.format(
"Tax & Comission: %.2f USD", sCalc.calculateTax().add(sCalc.calculateCommision())));

grossValue = new Label(String.format("Gross: %.2f USD", sCalc.calculateGross()));

saleProfit = new Label(String.format("Profit: %.2f USD", sCalc.calculateProfit()));

CssUtils.apply(saleProfit, CssUtils.generateValueColors(sCalc.calculateProfit().doubleValue()));
CssUtils.apply(saleProfit, CssUtils.generateValueColors(sCalc.calculateProfit()));
}

else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public void sortStocksBy(SortAction action) {

case LOSERS: {
stocksSorted.addAll(session.getExchange().getLosers(Integer.MAX_VALUE));
break;
}

}
Expand Down
Loading