diff --git a/src/main/java/seedu/address/logic/commands/EditLoanCommand.java b/src/main/java/seedu/address/logic/commands/EditLoanCommand.java index 2cdaad6f2ba..c4c4a3c4474 100644 --- a/src/main/java/seedu/address/logic/commands/EditLoanCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditLoanCommand.java @@ -6,6 +6,7 @@ import static seedu.address.logic.parser.CliSyntax.PREFIX_START_DATE; import static seedu.address.logic.parser.CliSyntax.PREFIX_VALUE; +import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Objects; @@ -93,7 +94,7 @@ private String generateSuccessMessage(Loan editedLoan) { private LinkLoanDescriptor generateEditedLoanDetails(Loan loanToEdit, EditLoanDescriptor editedDetails) throws CommandException { - float newValue = editedDetails.getValue().orElse(loanToEdit.getValue()); + BigDecimal newValue = editedDetails.getValue().orElse(loanToEdit.getValue()); Date newStartDate = editedDetails.getStartDate().orElse(loanToEdit.getStartDate()); Date newReturnDate = editedDetails.getReturnDate().orElse(loanToEdit.getReturnDate()); requireAllNonNull(newValue, newStartDate, newReturnDate); @@ -131,7 +132,7 @@ public String toString() { * Stores the details of the loan that is edited. */ public static class EditLoanDescriptor { - private Float value = null; + private BigDecimal value = null; private Date startDate = null; private Date returnDate = null; @@ -147,11 +148,11 @@ public boolean isAnyFieldEdited() { return CollectionUtil.isAnyNonNull(value, startDate, returnDate); } - public void setValue(float value) { + public void setValue(BigDecimal value) { this.value = value; } - public Optional getValue() { + public Optional getValue() { return Optional.ofNullable(value); } diff --git a/src/main/java/seedu/address/logic/commands/LinkLoanCommand.java b/src/main/java/seedu/address/logic/commands/LinkLoanCommand.java index b9b89a9db81..430f38fc5fc 100644 --- a/src/main/java/seedu/address/logic/commands/LinkLoanCommand.java +++ b/src/main/java/seedu/address/logic/commands/LinkLoanCommand.java @@ -6,6 +6,7 @@ import static seedu.address.logic.parser.CliSyntax.PREFIX_START_DATE; import static seedu.address.logic.parser.CliSyntax.PREFIX_VALUE; +import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Objects; @@ -102,7 +103,7 @@ public String toString() { * Stores the details of the loan to be linked. */ public static class LinkLoanDescriptor { - private float value; + private BigDecimal value; private Date startDate; private Date returnDate; @@ -112,7 +113,7 @@ public static class LinkLoanDescriptor { * @param startDate The start date of the loan * @param returnDate The date which the loan must be returned by */ - public LinkLoanDescriptor(float value, Date startDate, Date returnDate) { + public LinkLoanDescriptor(BigDecimal value, Date startDate, Date returnDate) { this.value = value; this.startDate = startDate; this.returnDate = returnDate; @@ -127,11 +128,11 @@ public LinkLoanDescriptor(LinkLoanCommand.LinkLoanDescriptor toCopy) { setReturnDate(toCopy.returnDate); } - public void setValue(float value) { + public void setValue(BigDecimal value) { this.value = value; } - public float getValue() { + public BigDecimal getValue() { return value; } diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index 2065c6104f4..42f283da47b 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -3,6 +3,7 @@ import static java.util.Objects.requireNonNull; import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import java.math.BigDecimal; import java.util.Collection; import java.util.Date; import java.util.HashSet; @@ -135,7 +136,7 @@ public static Set parseTags(Collection tags) throws ParseException public static LinkLoanDescriptor parseLoan(String value, String startDate, String returnDate) throws ParseException { requireAllNonNull(value, startDate, returnDate); - float convertedValue = parseValue(value); + BigDecimal convertedValue = parseValue(value); Date convertedStartDate = parseDate(startDate); Date convertedReturnDate = parseDate(returnDate); if (!Loan.isValidDates(convertedStartDate, convertedReturnDate)) { @@ -145,14 +146,14 @@ public static LinkLoanDescriptor parseLoan(String value, String startDate, Strin } /** - * Parses loan {@code String value} into a {@code float}. + * Parses loan {@code String value} into a {@code BigDecimal}. */ - public static float parseValue(String value) throws ParseException { + public static BigDecimal parseValue(String value) throws ParseException { requireNonNull(value); String trimmedValue = value.trim(); - float convertedValue; + BigDecimal convertedValue; try { - convertedValue = Float.parseFloat(trimmedValue); + convertedValue = new BigDecimal(trimmedValue); } catch (NumberFormatException n) { // Ths is caught when the formatter is unable to parse the value correctly throw new ParseException(Loan.VALUE_CONSTRAINTS); diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 8882b430ee7..f431088f0a1 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -3,6 +3,7 @@ import static java.util.Objects.requireNonNull; import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import java.math.BigDecimal; import java.nio.file.Path; import java.util.Date; import java.util.List; @@ -261,7 +262,7 @@ public ObjectProperty getDashboardData() { @Override public void generateDashboardData(Analytics analytics) { - float impactBenchmark = this.addressBook.getUniqueLoanList().getMaxLoanValue(); + BigDecimal impactBenchmark = this.addressBook.getUniqueLoanList().getMaxLoanValue(); Date urgencyBenchmark = this.addressBook.getUniqueLoanList().getEarliestReturnDate(); dashboardData.setValue(new DashboardData(analytics, impactBenchmark, urgencyBenchmark)); } diff --git a/src/main/java/seedu/address/model/analytics/DashboardData.java b/src/main/java/seedu/address/model/analytics/DashboardData.java index 604205d7abc..16703a2ace8 100644 --- a/src/main/java/seedu/address/model/analytics/DashboardData.java +++ b/src/main/java/seedu/address/model/analytics/DashboardData.java @@ -1,5 +1,7 @@ package seedu.address.model.analytics; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.time.LocalDate; import java.time.ZoneId; import java.util.Date; @@ -15,7 +17,7 @@ */ public class DashboardData { private Analytics analytics; - private float maxLoanValue; + private BigDecimal maxLoanValue; private Date earliestReturnDate; /** @@ -25,7 +27,7 @@ public class DashboardData { * @param maxLoanValue maximum loan value of all loans * @param earliestReturnDate earliest return date of all loans (not returned and not overdue) */ - public DashboardData(Analytics analytics, float maxLoanValue, Date earliestReturnDate) { + public DashboardData(Analytics analytics, BigDecimal maxLoanValue, Date earliestReturnDate) { this.analytics = analytics; this.maxLoanValue = maxLoanValue; this.earliestReturnDate = earliestReturnDate; @@ -35,18 +37,19 @@ public Analytics getAnalytics() { return analytics; } - public float getMaxLoanValue() { + public BigDecimal getMaxLoanValue() { return maxLoanValue; } /** * Calculates the impact index of the dashboard data * Impact index is calculated as the ratio of the average loan value to the maximum loan value + * to 2 decimal places. * * @return impact index between 0 and 1 */ - public float getImpactIndex() { - return analytics.getAverageLoanValue() / maxLoanValue; + public BigDecimal getImpactIndex() { + return analytics.getAverageLoanValue().divide(maxLoanValue, 2, RoundingMode.HALF_UP); } /** diff --git a/src/main/java/seedu/address/model/person/Analytics.java b/src/main/java/seedu/address/model/person/Analytics.java index cc418dc04a4..059335fa5e4 100644 --- a/src/main/java/seedu/address/model/person/Analytics.java +++ b/src/main/java/seedu/address/model/person/Analytics.java @@ -1,5 +1,7 @@ package seedu.address.model.person; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.Date; import javafx.collections.ObservableList; @@ -16,13 +18,13 @@ public class Analytics { private float propOverdueLoans; // proportion of loans that are overdue over active loans private float propActiveLoans; // proportion of loans that are active over total loans - private float totalValueLoaned; // total value of all loans - private float totalValueOverdue; // total value of all overdue loans - private float totalValueActive; // total value of all active loans + private BigDecimal totalValueLoaned; // total value of all loans + private BigDecimal totalValueOverdue; // total value of all overdue loans + private BigDecimal totalValueActive; // total value of all active loans - private float averageLoanValue; // average loan value of all loans - private float averageOverdueValue; // average loan value of all overdue loans - private float averageActiveValue; // average loan value of all active loans + private BigDecimal averageLoanValue; // average loan value of all loans + private BigDecimal averageOverdueValue; // average loan value of all overdue loans + private BigDecimal averageActiveValue; // average loan value of all active loans private Date earliestLoanDate; // earliest loan date of all loans private Date earliestReturnDate; // earliest return date of active loans @@ -37,13 +39,13 @@ private Analytics() { this.propOverdueLoans = 0; this.propActiveLoans = 0; - this.totalValueLoaned = 0; - this.totalValueOverdue = 0; - this.totalValueActive = 0; + this.totalValueLoaned = BigDecimal.ZERO; + this.totalValueOverdue = BigDecimal.ZERO; + this.totalValueActive = BigDecimal.ZERO; - this.averageLoanValue = 0; - this.averageOverdueValue = 0; - this.averageActiveValue = 0; + this.averageLoanValue = BigDecimal.ZERO; + this.averageOverdueValue = BigDecimal.ZERO; + this.averageActiveValue = BigDecimal.ZERO; this.earliestLoanDate = null; this.earliestReturnDate = null; @@ -83,12 +85,12 @@ private void updatePropFields() { * @param loan The loan to update the fields with. */ private void updateValueFields(Loan loan) { - this.totalValueLoaned += loan.getValue(); + totalValueLoaned = totalValueLoaned.add(loan.getValue()); if (loan.isOverdue()) { - this.totalValueOverdue += loan.getValue(); + totalValueOverdue = totalValueOverdue.add(loan.getValue()); } if (loan.isActive()) { - this.totalValueActive += loan.getValue(); + totalValueActive = totalValueActive.add(loan.getValue()); } } @@ -97,14 +99,17 @@ private void updateValueFields(Loan loan) { * This method should be called after the fields that calculate the total value of various loans have been updated. */ private void updateAverageFields() { - if (this.numActiveLoans > 0) { - this.averageActiveValue = this.totalValueActive / this.numActiveLoans; + if (numActiveLoans > 0) { + averageActiveValue = totalValueActive.divide(BigDecimal.valueOf(numActiveLoans), + 2, RoundingMode.HALF_UP); } - if (this.numOverdueLoans > 0) { - this.averageOverdueValue = this.totalValueOverdue / this.numOverdueLoans; + if (numOverdueLoans > 0) { + averageOverdueValue = totalValueOverdue.divide(BigDecimal.valueOf(numOverdueLoans), + 2, RoundingMode.HALF_UP); } - if (this.numLoans > 0) { - this.averageLoanValue = this.totalValueLoaned / this.numLoans; + if (numLoans > 0) { + averageLoanValue = totalValueLoaned.divide(BigDecimal.valueOf(this.numLoans), + 2, RoundingMode.HALF_UP); } } @@ -171,27 +176,27 @@ public float getPropActiveLoans() { return propActiveLoans; } - public float getTotalValueLoaned() { + public BigDecimal getTotalValueLoaned() { return totalValueLoaned; } - public float getTotalValueOverdue() { + public BigDecimal getTotalValueOverdue() { return totalValueOverdue; } - public float getTotalValueActive() { + public BigDecimal getTotalValueActive() { return totalValueActive; } - public float getAverageLoanValue() { + public BigDecimal getAverageLoanValue() { return averageLoanValue; } - public float getAverageOverdueValue() { + public BigDecimal getAverageOverdueValue() { return averageOverdueValue; } - public float getAverageActiveValue() { + public BigDecimal getAverageActiveValue() { return averageActiveValue; } diff --git a/src/main/java/seedu/address/model/person/Loan.java b/src/main/java/seedu/address/model/person/Loan.java index ab448f199bb..c8ee318f6c3 100644 --- a/src/main/java/seedu/address/model/person/Loan.java +++ b/src/main/java/seedu/address/model/person/Loan.java @@ -2,6 +2,7 @@ import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; +import java.math.BigDecimal; import java.util.Date; import seedu.address.commons.util.DateUtil; @@ -18,7 +19,7 @@ public class Loan implements Comparable { public static final String VALUE_CONSTRAINTS = "Loan values must be a positive number."; private final int id; - private final float value; + private final BigDecimal value; private final Date startDate; private final Date returnDate; private boolean isReturned; @@ -33,7 +34,7 @@ public class Loan implements Comparable { * @param returnDate A valid return date. * @param assignee A valid assignee. */ - public Loan(int id, float value, Date startDate, Date returnDate, Person assignee) { + public Loan(int id, BigDecimal value, Date startDate, Date returnDate, Person assignee) { requireAllNonNull(id, value, startDate, returnDate, assignee); assert isValidValue(value); assert id >= 0; @@ -55,7 +56,7 @@ public Loan(int id, float value, Date startDate, Date returnDate, Person assigne * @param isReturned A valid return status. * @param assignee A valid assignee. */ - public Loan(int id, float value, Date startDate, Date returnDate, boolean isReturned, Person assignee) { + public Loan(int id, BigDecimal value, Date startDate, Date returnDate, boolean isReturned, Person assignee) { requireAllNonNull(id, value, startDate, returnDate, isReturned, assignee); assert isValidValue(value); assert id >= 0; @@ -68,10 +69,10 @@ public Loan(int id, float value, Date startDate, Date returnDate, boolean isRetu } /** - * Returns true if a given float is a valid value. + * Returns true if a given BigDecimal is a valid value. */ - public static boolean isValidValue(float value) { - return value > 0; + public static boolean isValidValue(BigDecimal value) { + return value.compareTo(BigDecimal.ZERO) > 0; } /** @@ -85,7 +86,7 @@ public int getId() { return id; } - public float getValue() { + public BigDecimal getValue() { return value; } diff --git a/src/main/java/seedu/address/model/person/UniqueLoanList.java b/src/main/java/seedu/address/model/person/UniqueLoanList.java index 86726bea839..395ae61ea27 100644 --- a/src/main/java/seedu/address/model/person/UniqueLoanList.java +++ b/src/main/java/seedu/address/model/person/UniqueLoanList.java @@ -2,6 +2,7 @@ import static java.util.Objects.requireNonNull; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; @@ -56,7 +57,7 @@ public void addLoan(Loan loan) { * @param startDate A valid start date. * @param returnDate A valid return date. */ - public Loan addLoan(float value, Date startDate, Date returnDate, Person assignee) { + public Loan addLoan(BigDecimal value, Date startDate, Date returnDate, Person assignee) { Loan loan = new Loan(nextLoanId, value, startDate, returnDate, assignee); addLoan(loan); return loan; @@ -68,7 +69,7 @@ public Loan addLoan(float value, Date startDate, Date returnDate, Person assigne * @param loanDescription A valid LinkLoanDescriptor, which contains details about the loan to be added. */ public Loan addLoan(LinkLoanDescriptor loanDescription, Person assignee) { - float value = loanDescription.getValue(); + BigDecimal value = loanDescription.getValue(); Date startDate = loanDescription.getStartDate(); Date returnDate = loanDescription.getReturnDate(); return addLoan(value, startDate, returnDate, assignee); @@ -82,7 +83,7 @@ public Loan addLoan(LinkLoanDescriptor loanDescription, Person assignee) { * @param returnDate A valid return date. * @throws IllegalValueException If the date string is not in the correct format. */ - public void addLoan(float value, String startDate, String returnDate, Person assignee) + public void addLoan(BigDecimal value, String startDate, String returnDate, Person assignee) throws IllegalValueException { try { Date start = DateUtil.parse(startDate); @@ -332,11 +333,11 @@ public void modifyLoanAssignee(Person target, Person editedPerson) { * * @return The maximum loan value of all loans. */ - public int getMaxLoanValue() { - int maxLoanValue = 0; + public BigDecimal getMaxLoanValue() { + BigDecimal maxLoanValue = BigDecimal.ZERO; for (Loan loan : internalList) { - if (loan.getValue() > maxLoanValue) { - maxLoanValue = (int) loan.getValue(); + if (loan.getValue().compareTo(maxLoanValue) > 0) { + maxLoanValue = loan.getValue(); } } return maxLoanValue; diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java index c9a19f47e15..3e6d09a6b7b 100644 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java @@ -1,5 +1,6 @@ package seedu.address.model.util; +import java.math.BigDecimal; import java.util.Arrays; import java.util.Set; import java.util.stream.Collectors; @@ -49,7 +50,8 @@ public static Person[] getSamplePersons() { public static LinkLoanCommand.LinkLoanDescriptor[] getSampleLoans() { LinkLoanCommand.LinkLoanDescriptor loanDescriptor; try { - loanDescriptor = new LinkLoanCommand.LinkLoanDescriptor(100, DateUtil.parse("2021-10-10"), + loanDescriptor = new LinkLoanCommand.LinkLoanDescriptor(BigDecimal.valueOf(100), + DateUtil.parse("2021-10-10"), DateUtil.parse("2021-12-10")); return new LinkLoanCommand.LinkLoanDescriptor[] { loanDescriptor diff --git a/src/main/java/seedu/address/storage/JsonAdaptedLoan.java b/src/main/java/seedu/address/storage/JsonAdaptedLoan.java index 300819c4a1a..7e92a66c215 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedLoan.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedLoan.java @@ -1,5 +1,7 @@ package seedu.address.storage; +import java.math.BigDecimal; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; @@ -12,7 +14,7 @@ */ public class JsonAdaptedLoan { - private final float value; + private final BigDecimal value; private final String startDate; private final String returnDate; private final int id; @@ -23,7 +25,7 @@ public class JsonAdaptedLoan { * Constructs a {@code JsonAdaptedLoan} with the given loan details. */ @JsonCreator - public JsonAdaptedLoan(@JsonProperty("value") float value, @JsonProperty("startDate") String startDate, + public JsonAdaptedLoan(@JsonProperty("value") BigDecimal value, @JsonProperty("startDate") String startDate, @JsonProperty("returnDate") String returnDate, @JsonProperty("id") int id, @JsonProperty("isReturned") boolean isReturned, @JsonProperty("assignee") JsonAdaptedPerson assignee) { diff --git a/src/main/java/seedu/address/ui/AnalyticsPanel.java b/src/main/java/seedu/address/ui/AnalyticsPanel.java index a25810b07b3..4565eab21a0 100644 --- a/src/main/java/seedu/address/ui/AnalyticsPanel.java +++ b/src/main/java/seedu/address/ui/AnalyticsPanel.java @@ -1,5 +1,7 @@ package seedu.address.ui; +import java.math.BigDecimal; + import javafx.beans.property.ObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -75,17 +77,17 @@ private void updateChart(DashboardData data) { } - if (data.getMaxLoanValue() == 0) { + if (data.getMaxLoanValue().compareTo(BigDecimal.ZERO) == 0) { impactIndex.setText("No loans to analyze"); impactChart.setVisible(false); } else { impactChart.setVisible(true); ObservableList impactData = FXCollections.observableArrayList( - new PieChart.Data("Impact Index", data.getImpactIndex()), - new PieChart.Data("", 1 - data.getImpactIndex()) + new PieChart.Data("Impact Index", data.getImpactIndex().doubleValue()), + new PieChart.Data("", 1 - data.getImpactIndex().doubleValue()) ); impactChart.setData(impactData); - impactIndex.setText(String.format("%.2f", data.getImpactIndex() * 100) + "%"); + impactIndex.setText(String.format("%.2f", data.getImpactIndex().doubleValue() * 100) + "%"); } if (data.getUrgencyIndex() == null) { urgencyIndex.setText("No due loans to analyze"); diff --git a/src/test/java/seedu/address/testutil/TypicalPersonsWithLoans.java b/src/test/java/seedu/address/testutil/TypicalPersonsWithLoans.java index 71478a4b7bc..3cdcdae2c0e 100644 --- a/src/test/java/seedu/address/testutil/TypicalPersonsWithLoans.java +++ b/src/test/java/seedu/address/testutil/TypicalPersonsWithLoans.java @@ -11,6 +11,7 @@ import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND; import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -68,11 +69,11 @@ private TypicalPersonsWithLoans() {} // prevents instantiation public static UniqueLoanList loanRecords() { UniqueLoanList uniqueLoanList = new UniqueLoanList(); try { - uniqueLoanList.addLoan(100F, DateUtil.parse("2020-01-01"), + uniqueLoanList.addLoan(BigDecimal.valueOf(100), DateUtil.parse("2020-01-01"), DateUtil.parse("2020-01-13"), ALICE); - uniqueLoanList.addLoan(200F, DateUtil.parse("2020-02-01"), + uniqueLoanList.addLoan(BigDecimal.valueOf(200), DateUtil.parse("2020-02-01"), DateUtil.parse("2020-02-13"), BENSON); - uniqueLoanList.addLoan(300F, DateUtil.parse("2020-02-13"), + uniqueLoanList.addLoan(BigDecimal.valueOf(300), DateUtil.parse("2020-02-13"), DateUtil.parse("2020-02-14"), CARL); } catch (IllegalValueException e) { e.printStackTrace();