Skip to content

Commit

Permalink
Merge pull request #218 from jasraa/jasra_updateDG_PPP_UG
Browse files Browse the repository at this point in the history
Update PPP
  • Loading branch information
jasraa authored Apr 13, 2024
2 parents c6e1e1f + 34ce76c commit ca9a368
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 67 deletions.
1 change: 0 additions & 1 deletion data/SavingsFile.txt
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
Salary | 200.00
10 changes: 8 additions & 2 deletions docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -462,20 +462,26 @@ Format: `print budget`
* This feature provides an overview of the expenses distribution across different categories.
* A horizontal bar graph showing the percentage of total expenses attributed to each category.
* It highlights the category with the highest expenses, the one with the lowest (excluding categories with no expenses),
* and lists any categories where no expenses have been recorded.
and lists any categories where no expenses have been recorded.
* Categories are Housing, Groceries, Utility, Transport, Entertainment, and Others.

Example of usage: `get expenses insights`

Example of Expected Output:
![GetExpenseInsights.png](userguideimages%2FGetExpenseInsights.png)

### Get Graphical Insights for savings: `get savings insights`
* This feature offers a comprehensive look at how your savings are allocated across various categories.
* A horizontal bar graph showing the percentage of total savings attributed to each category.
* It highlights the category with the highest savings, the one with the lowest (excluding categories with no savings),
* and lists any categories where no savings have been added.
and lists any categories where no savings have been added.
* Categories are Salary, Investments, Gifts, and Others

Example of Usage: `get savings insights`

Example of Expected Output:
![GetSavingsInsights.png](userguideimages%2FGetSavingsInsights.png)


### Saving the data

Expand Down
15 changes: 12 additions & 3 deletions docs/team/jasraa.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,19 @@ within the command line interface, eliminating the need for external tools or vi
[RepoSense Link](https://nus-cs2113-ay2324s2.github.io/tp-dashboard/?search=jasraa&breakdown=true&sort=groupTitle%20dsc&sortWithin=title&since=2024-02-23&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)

#### Enhancements to existing features
(to be updated)
1. Wrote Junit tests for Edit Expenses, Edit Savings, Get Expenses Insight and Get Savings Insights
2. Implemented Bug fixes for "Edit Expenses", "Edit Savings", "Storage", "Get Expenses Insights" and
"Get Savings Insights"

#### Contributions to the UG
(to be updated)
Added documentation for the features `edit expense`, `edit savings`, `get expenses insight`
and `get savings insights`

#### Contributions to the DG
(to be updated)
Added diagrams and documentation for the features `edit expense`, `edit savings`, `get expenses insight`
and `get savings insights`

#### Community
1. Communicated with teammates for ideation and enhancement of existing features.
2. Provided DG Peer Review Comments for another team. [CS2113-T15-3 SplitLiang](https://github.com/nus-cs2113-AY2324S2/tp/pull/47)
3. Reported bugs for another team during PE-D. [CS2113-T15-1 LongAh](https://github.com/AY2324S2-CS2113-T15-1/tp/releases)
Binary file added docs/userguideimages/GetExpenseInsights.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/userguideimages/GetSavingsInsights.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
133 changes: 72 additions & 61 deletions src/main/java/seedu/budgetbuddy/commons/SavingList.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Collections;

import seedu.budgetbuddy.Ui;
import seedu.budgetbuddy.exception.BudgetBuddyException;
Expand Down Expand Up @@ -251,65 +251,91 @@ public void reduceSavings(int index, double amount) {
}
}

public double calculateTotalSavings() {
double totalSavings = 0;
try {
for (Saving saving : savings) {
if (saving.getAmount() < 0) {
throw new IllegalArgumentException("Savings should not be negative");
}
totalSavings += saving.getAmount();
}
} catch (IllegalArgumentException e) {
LOGGER.log(Level.WARNING, "Negative savings amount detected", e);
}

assert totalSavings >= 0 : "Total savings should be non-negative";

return totalSavings;
}

/**
* Analyzes and displays insights into the saved amounts across different categories.
* It prints out the highest and lowest savings categories and lists categories with no savings.
* A bar graph representing the distribution of savings is also displayed.
*/
public void getSavingsInsights() {
findTotalSavings(); // Make sure total savings are updated

if (initialAmount == 0) {
double totalSavings = calculateTotalSavings();
if (totalSavings == 0) {
System.out.println("No savings to display.");
return;
}

printSavingsDistribution();
Map<String, Double> sumsByCategory = calculateSumsByCategory();

// Calculate the highest savings value
double highestSavings = savings.stream()
.mapToDouble(Saving::getAmount)
.max().orElse(0);
// Calculate the highest savings
double highestSavings = Collections.max(sumsByCategory.values());
// Calculate the lowest savings
double lowestSavings = sumsByCategory.values().stream()
.filter(amount -> amount > 0)
.min(Double::compare)
.orElse(0.0);

// Identify the categories with the highest savings
List<String> highestCategories = savings.stream()
.filter(s -> s.getAmount() == highestSavings)
.map(Saving::getCategory)
.collect(Collectors.toList());
List<String> highestCategories = getSavingsCategoriesByAmount(sumsByCategory, highestSavings);
List<String> lowestCategories = getSavingsCategoriesByAmount(sumsByCategory, lowestSavings);

// Calculate the lowest savings value excluding the highest if it's the only value
double lowestSavings = savings.stream()
.filter(s -> !highestCategories.contains(s.getCategory()))
.mapToDouble(Saving::getAmount)
.min().orElse(0);
// Print the distribution graph
ui.printDivider();
printSavingsDistribution(sumsByCategory, totalSavings);
ui.printDivider();

// Identify the categories with the lowest savings, excluding those with no savings
List<String> lowestCategories = savings.stream()
.filter(s -> s.getAmount() == lowestSavings && lowestSavings != 0)
.map(Saving::getCategory)
.collect(Collectors.toList());
// Print insights
System.out.println("Highest Savings Category: " + formatCategoryList(highestCategories));
System.out.println("Lowest Savings Category: " + formatCategoryList(lowestCategories));
System.out.println("Categories with no savings added: " +
formatCategoryList(getNoSavingsCategories(sumsByCategory)));
ui.printDivider();
}

// If lowestSavings is 0, then this list should be empty
if (lowestSavings == 0) {
lowestCategories.clear();
}
private List<String> getSavingsCategoriesByAmount(Map<String, Double> sumsByCategory, double amount) {
return sumsByCategory.entrySet().stream()
.filter(entry -> entry.getValue() == amount)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}

// Identify categories with no savings
List<String> noSavingsCategories = categories.stream()
.filter(c -> savings.stream().noneMatch(s -> s.getCategory().equals(c)))
private List<String> getNoSavingsCategories(Map<String, Double> sumsByCategory) {
return categories.stream()
.filter(category -> !sumsByCategory.containsKey(category) || sumsByCategory.get(category) == 0)
.collect(Collectors.toList());
}

// Add categories with zero amount saved
noSavingsCategories.addAll(savings.stream()
.filter(s -> s.getAmount() == 0)
.map(Saving::getCategory)
.collect(Collectors.toList()));
/**
* Prints a distribution of savings as a horizontal bar graph.
* Each category's bar length is proportional to its percentage of the total savings.
*/
private void printSavingsDistribution(Map<String, Double> sumsByCategory, double totalSavings) {
double maxPercentage = sumsByCategory.values().stream()
.mapToDouble(amount -> (amount / totalSavings) * 100)
.max()
.orElse(100);

ui.printDivider();
System.out.println("Highest Savings Category: " + formatCategoryList(highestCategories));
System.out.println("Lowest Savings Category: " + formatCategoryList(lowestCategories));
System.out.println("Categories with no savings added: " + formatCategoryList(noSavingsCategories));
ui.printDivider();
for (String category : categories) {
double percentage = (sumsByCategory.getOrDefault(category, 0.0) / totalSavings) * 100;
int barLength = (int) (percentage / (maxPercentage / 50));
String bar = "[" + "#".repeat(Math.max(0, barLength)) + "]";
System.out.println(String.format("%-15s: %6.2f%% %s", category, percentage, bar));
}
}

/**
Expand Down Expand Up @@ -337,26 +363,11 @@ private Map<String, Double> calculateSumsByCategory() {
private String formatCategoryList(List<String> categories) {
if (categories.isEmpty()) {
return "None";
} else if (categories.size() == 1) {
return categories.get(0);
} else {
return String.join(", ", categories.subList(0, categories.size() - 1))
+ (categories.size() > 1 ? " and " : "") + categories.get(categories.size() - 1);
}
}

/**
* Prints a distribution of savings as a horizontal bar graph.
* Each category's bar length is proportional to its percentage of the total savings.
*/
private void printSavingsDistribution() {
Map<String, Double> sumsByCategory = calculateSumsByCategory();
double totalSavings = sumsByCategory.values().stream().mapToDouble(Double::doubleValue).sum();

for (String category : categories) {
Double sum = sumsByCategory.getOrDefault(category, 0.0);
double percentage = (sum / totalSavings) * 100;
int barLength = (int) (percentage / (100.0 / 50)); // Assuming a bar max length of 50 characters
String bar = "[" + "#".repeat(Math.max(0, barLength)) + "]";
System.out.println(String.format("%-15s: %6.2f%% %s", category, percentage, bar));
String allButLast = String.join(", ", categories.subList(0, categories.size() - 1));
return allButLast + " and " + categories.get(categories.size() - 1);
}
}

Expand Down

0 comments on commit ca9a368

Please sign in to comment.