From 1675cd40e142afcc2dea62a9efa6da6878aa2b70 Mon Sep 17 00:00:00 2001 From: chowy Date: Sun, 31 Mar 2024 04:00:43 +0800 Subject: [PATCH] Added feature to set reminders for future payments. Added a quick report for when user logs in. --- src/main/java/command/AddReminderCommand.java | 37 ++++++++++++ .../java/command/DeleteReminderCommand.java | 21 +++++++ .../java/command/EditReminderCommand.java | 42 ++++++++++++++ src/main/java/command/HelpCommand.java | 16 ++++-- src/main/java/command/SetBudgetCommand.java | 21 +++++++ src/main/java/financeproject/Main.java | 5 +- .../java/financialtransactions/Inflow.java | 5 ++ .../java/financialtransactions/Outflow.java | 5 ++ .../java/financialtransactions/Reminder.java | 20 +++++++ .../financialtransactions/Transaction.java | 6 +- .../TransactionList.java | 12 +++- .../TransactionManager.java | 57 ++++++++++++++++++- src/main/java/parser/Parser.java | 25 ++++++++ src/main/java/storage/Storage.java | 12 +++- .../TransactionManagerTest.java | 14 ++++- 15 files changed, 278 insertions(+), 20 deletions(-) create mode 100644 src/main/java/command/AddReminderCommand.java create mode 100644 src/main/java/command/DeleteReminderCommand.java create mode 100644 src/main/java/command/EditReminderCommand.java create mode 100644 src/main/java/command/SetBudgetCommand.java create mode 100644 src/main/java/financialtransactions/Reminder.java diff --git a/src/main/java/command/AddReminderCommand.java b/src/main/java/command/AddReminderCommand.java new file mode 100644 index 0000000000..9e0a0164d8 --- /dev/null +++ b/src/main/java/command/AddReminderCommand.java @@ -0,0 +1,37 @@ +package command; + +import financialtransactions.Reminder; +import financialtransactions.TransactionManager; + +public class AddReminderCommand extends BaseCommand { + public AddReminderCommand(String[] commandParts) { + super(false, commandParts); + } + + public String execute(TransactionManager manager) { + String reminderName = null; + double reminderAmount = 0.0; + String reminderDate = null; + String reminderTime = null; + String reminderCategory = null; + + for (String part : commandParts) { + if (part.startsWith("n/")) { + reminderName = part.substring(2); + } else if (part.startsWith("a/")) { + reminderAmount = Double.parseDouble(part.substring(2)); + } else if (part.startsWith("d/")) { + reminderDate = part.substring(2); + } else if (part.startsWith("t/")) { + reminderTime = part.substring(2); + } else if (part.startsWith("c/")) { + reminderCategory = part.substring(2); + } + } + String reminderDateTime = reminderDate + " " + reminderTime; + Reminder reminder = new Reminder(reminderName, reminderAmount, reminderDateTime); + reminder.setCategory(Reminder.Category.valueOf(reminderCategory.toUpperCase())); + manager.addTransaction(reminder); + return "Ok. Added reminder"; + } +} diff --git a/src/main/java/command/DeleteReminderCommand.java b/src/main/java/command/DeleteReminderCommand.java new file mode 100644 index 0000000000..3502281443 --- /dev/null +++ b/src/main/java/command/DeleteReminderCommand.java @@ -0,0 +1,21 @@ +package command; + +import financialtransactions.TransactionManager; + +public class DeleteReminderCommand extends BaseCommand { + public DeleteReminderCommand(String[] commandParts) { + super(false, commandParts); + } + + public String execute(TransactionManager manager) throws Exception { + String reminderIndex = null; + for (String part : commandParts) { + if (part.startsWith("i/")) { + reminderIndex = part.substring(2); + } + } + assert reminderIndex != null : "reminderIndex should not be null"; + manager.removeReminder(Integer.parseInt(reminderIndex)); + return "Ok. Reminder deleted"; + } +} diff --git a/src/main/java/command/EditReminderCommand.java b/src/main/java/command/EditReminderCommand.java new file mode 100644 index 0000000000..b35bb2516a --- /dev/null +++ b/src/main/java/command/EditReminderCommand.java @@ -0,0 +1,42 @@ +package command; + +import financialtransactions.Reminder; +import financialtransactions.TransactionManager; + +public class EditReminderCommand extends BaseCommand { + public EditReminderCommand(String[] commandParts) { + super(false, commandParts); + } + + public String execute(TransactionManager manager) throws Exception { + int reminderIndex = -1; + String reminderName = null; + double reminderAmount = 0.0; + String reminderDate = null; + String reminderTime = null; + String reminderCategory = null; + + for (String part : commandParts) { + if (part.startsWith("i/")) { + reminderIndex = Integer.parseInt(part.substring(2)); + } else if (part.startsWith("n/")) { + reminderName = part.substring(2); + } else if (part.startsWith("a/")) { + reminderAmount = Double.parseDouble(part.substring(2)); + } else if (part.startsWith("d/")) { + reminderDate = part.substring(2); + } else if (part.startsWith("t/")) { + reminderTime = part.substring(2); + } else if (part.startsWith("c/")) { + reminderCategory = part.substring(2); + } + } + + String reminderDateTime = reminderDate + " " + reminderTime; + Reminder updatedReminder = new Reminder(reminderName, reminderAmount, reminderDateTime); + assert reminderCategory != null : "reminderCategory should not be null"; + updatedReminder.setCategory(Reminder.Category.valueOf(reminderCategory.toUpperCase())); + manager.editOutflow(reminderIndex, updatedReminder); + return "Ok. Edited reminder"; + } +} diff --git a/src/main/java/command/HelpCommand.java b/src/main/java/command/HelpCommand.java index a0d3ed134f..09deaf1750 100644 --- a/src/main/java/command/HelpCommand.java +++ b/src/main/java/command/HelpCommand.java @@ -13,12 +13,16 @@ public String execute(TransactionManager manager) throws Exception { baseString += "Here are the available commands: \n"; baseString += "1) add-inflow n/NAME a/AMOUNT d/DATE t/TIME c/CATEGORY\n"; baseString += "2) add-outflow n/NAME a/AMOUNT d/DATE t/TIME c/CATEGORY\n"; - baseString += "3) delete-inflow i/INDEX\n"; - baseString += "4) delete-outflow i/INDEX\n"; - baseString += "5) edit-inflow i/INDEX n/NAME a/AMOUNT d/DATE t/TIME c/CATEGORY\n"; - baseString += "6) edit-outflow i/INDEX n/NAME a/AMOUNT d/DATE t/TIME c/CATEGORY\n"; - baseString += "7) view-history n/NUM \n"; - baseString += "8) quit \n"; + baseString += "3) add-reminder n/NAME a/AMOUNT d/DATE t/TIME c/CATEGORY\n"; + baseString += "4) delete-inflow i/INDEX\n"; + baseString += "5) delete-outflow i/INDEX\n"; + baseString += "6) delete-reminder i/INDEX\n"; + baseString += "7) edit-inflow i/INDEX n/NAME a/AMOUNT d/DATE t/TIME c/CATEGORY\n"; + baseString += "8) edit-outflow i/INDEX n/NAME a/AMOUNT d/DATE t/TIME c/CATEGORY\n"; + baseString += "9) delete-reminder i/INDEX n/NAME a/AMOUNT d/DATE t/TIME c/CATEGORY\n"; + baseString += "10) set-budget a/AMOUNT\n"; + baseString += "11) view-history n/NUM \n"; + baseString += "12) quit \n"; baseString += "_____________"; return baseString; } diff --git a/src/main/java/command/SetBudgetCommand.java b/src/main/java/command/SetBudgetCommand.java new file mode 100644 index 0000000000..686290a3bd --- /dev/null +++ b/src/main/java/command/SetBudgetCommand.java @@ -0,0 +1,21 @@ +package command; + +import financialtransactions.TransactionManager; + +public class SetBudgetCommand extends BaseCommand{ + public SetBudgetCommand(String[] commandParts) { + super(false, commandParts); + } + + public String execute(TransactionManager manager) throws Exception{ + String budgetString = null; + for (String part : commandParts) { + if (part.startsWith("a/")) { + budgetString = part.substring(2); + } + } + double budget = Double.parseDouble(budgetString); + manager.setBudget(budget); + return "Ok. Budget set."; + } +} diff --git a/src/main/java/financeproject/Main.java b/src/main/java/financeproject/Main.java index 7ff7eb21d2..04eac2f472 100644 --- a/src/main/java/financeproject/Main.java +++ b/src/main/java/financeproject/Main.java @@ -16,8 +16,7 @@ public class Main { public static void main(String[] args) throws SecurityException, ExceededAttemptsException { Storage storage = new Storage("./data"); - TransactionManager manager = new TransactionManager(); - + UI ui = new UI(); ui.printMessage("Welcome. Enter your username and password to login."); @@ -45,6 +44,8 @@ public static void main(String[] args) throws SecurityException, ExceededAttempt } else { return; } + TransactionManager manager = storage.loadFile(user.getUsername()); + ui.printMessage(manager.generateQuickReport()); // Main program flow do { diff --git a/src/main/java/financialtransactions/Inflow.java b/src/main/java/financialtransactions/Inflow.java index 28480e8527..cdf0c52794 100644 --- a/src/main/java/financialtransactions/Inflow.java +++ b/src/main/java/financialtransactions/Inflow.java @@ -10,4 +10,9 @@ public Inflow(String name, double amount, String date) { public void setCategory(Category category) { super.category = category; } + + @Override + public String toSave() { + return super.toSave() + "|I\n"; + } } diff --git a/src/main/java/financialtransactions/Outflow.java b/src/main/java/financialtransactions/Outflow.java index 1584cc1ab9..173ab400c7 100644 --- a/src/main/java/financialtransactions/Outflow.java +++ b/src/main/java/financialtransactions/Outflow.java @@ -12,4 +12,9 @@ public Outflow(String name, double amount, String date) { public void setCategory(Category category) { this.category = category; } + + @Override + public String toSave() { + return super.toSave() + "|O\n"; + } } diff --git a/src/main/java/financialtransactions/Reminder.java b/src/main/java/financialtransactions/Reminder.java new file mode 100644 index 0000000000..b74c17e841 --- /dev/null +++ b/src/main/java/financialtransactions/Reminder.java @@ -0,0 +1,20 @@ +package financialtransactions; + +public class Reminder extends Transaction { + public enum Category { + INSTALLMENT, CREDITCARD, UTILITIES + } + + public Reminder(String name, double amount, String date) { + super(name, -1.00 * amount, date); + } + + public void setCategory(Category category) { + this.category = category; + } + + @Override + public String toSave() { + return super.toSave() + "|R\n"; + } +} diff --git a/src/main/java/financialtransactions/Transaction.java b/src/main/java/financialtransactions/Transaction.java index 644138e447..b37327af31 100644 --- a/src/main/java/financialtransactions/Transaction.java +++ b/src/main/java/financialtransactions/Transaction.java @@ -46,12 +46,12 @@ public T getCategory() { public String toString() { return String.format("Name: %s, Amount: %.2f, Date: %s", name, amount, date.toString()); } - + public String toSave() { - return String.format("%s|%.2f|%s|%s\n", name, amount, date.toString(), category); + return String.format("%s|%.2f|%s|%s", name, amount, date.toString(), category); } - protected BaseDate getDate() { + public BaseDate getDate() { return date; } } diff --git a/src/main/java/financialtransactions/TransactionList.java b/src/main/java/financialtransactions/TransactionList.java index b4e857c458..72e668ba12 100644 --- a/src/main/java/financialtransactions/TransactionList.java +++ b/src/main/java/financialtransactions/TransactionList.java @@ -1,5 +1,6 @@ package financialtransactions; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Comparator; @@ -115,5 +116,14 @@ public void sortListByName() { public void sortListByDate() { this.transactionList.sort(new DateComparator<>()); } - + + public double totalSpentInPastMonth() { + double amount = 0; + for (T transaction : transactionList) { + if (transaction.getDate().getDateTime().getMonth() == LocalDateTime.now().getMonth()) { + amount += transaction.getAmount(); + } + } + return amount; + } } diff --git a/src/main/java/financialtransactions/TransactionManager.java b/src/main/java/financialtransactions/TransactionManager.java index 049ba5946d..cb805bb5f9 100644 --- a/src/main/java/financialtransactions/TransactionManager.java +++ b/src/main/java/financialtransactions/TransactionManager.java @@ -5,13 +5,21 @@ public class TransactionManager { private TransactionList> transactionList; private TransactionList inflows; private TransactionList outflows; + private TransactionList reminders; + + private double budget = 0.00; public TransactionManager() { this.transactionList = new TransactionList<>(); this.inflows = new TransactionList<>(); this.outflows = new TransactionList<>(); + this.reminders = new TransactionList<>(); } - + + public void setBudget(double budget) { + this.budget = budget; + } + public boolean addTransaction(Transaction transaction) { transactionList.addTransaction(transaction); // transactionList.sortListByName(); @@ -25,6 +33,11 @@ public boolean addTransaction(Transaction transaction) { transactionList.setTransactionsType("Outflow"); return outflows.addTransaction(outflow); } + if (transaction instanceof Reminder) { + Reminder reminder = (Reminder) transaction; + transactionList.setTransactionsType("Reminder"); + return reminders.addTransaction(reminder); + } System.out.println("Invalid transaction type."); return false; } @@ -38,6 +51,9 @@ public boolean removeTransaction(int index) throws Exception{ if (transactionRemoved instanceof Outflow) { return outflows.removeTransactionIndex(index); } + if (transactionRemoved instanceof Reminder) { + return reminders.removeTransactionIndex(index); + } return false; } @@ -55,6 +71,13 @@ public boolean removeOutflow(int index) throws Exception { return outflows.removeTransactionIndex(numOfOutflows - index); } + public boolean removeReminder(int index) throws Exception { + int numOfReminders = reminders.getTransactionListSize(); + Transaction transactionRemoved = reminders.getNthTransaction(numOfReminders - index); + transactionList.removeTransactionIndex(transactionList.getIndexOfParticularTransaction(transactionRemoved)); + return reminders.removeTransactionIndex(numOfReminders - index); + } + public boolean editInflow(int index, Transaction updatedTransaction) throws Exception { int numOfInflows = inflows.getTransactionListSize(); Transaction transactionEdited = inflows.getNthTransaction(numOfInflows - index); @@ -71,6 +94,14 @@ public boolean editOutflow(int index, Transaction updatedTransaction) throws return outflows.editTransactionIndex(numOfOutflows - index, (Outflow) updatedTransaction); } + public boolean editReminder(int index, Transaction updatedTransaction) throws Exception { + int numOfReminders = reminders.getTransactionListSize(); + Transaction transactionEdited = reminders.getNthTransaction(numOfReminders - index); + transactionList.editTransactionIndex(transactionList.getIndexOfParticularTransaction(transactionEdited), + updatedTransaction); + return reminders.editTransactionIndex(numOfReminders - index, (Reminder) updatedTransaction); + } + public double getTotalBalance() { double inflowBalance = inflows.getBalance(); double outflowBalance = outflows.getBalance(); @@ -106,10 +137,32 @@ public String showLastNTransactions(int n) throws Exception{ index++; } } + + index = 1; + returnedText += "\nReminders:\nTransactions:\n"; + for (int i = listSize - 1; i > listSize - n - 1; i--) { + Transaction transaction = transactionList.getNthTransaction(i); + if (transaction instanceof Reminder) { + returnedText += String.format("%d) %s\n", index, transactionList.getNthTransaction(i).toString()); + index++; + } + } + return returnedText; } public String toSave() { - return inflows.toSave() + outflows.toSave(); + return String.format("%.2f\n", budget) + inflows.toSave() + outflows.toSave() + reminders.toSave(); + } + + public String generateQuickReport() { + String baseString = ""; + baseString += String.format("You have spent " + + "%.2f in the current month.\n", outflows.totalSpentInPastMonth()); + baseString += String.format("With a budget of " + + "%.2f, you have %.2f left to spend.\n", budget, budget - outflows.totalSpentInPastMonth()); + baseString += String.format("You have " + + "%d upcoming payments that require your attention", reminders.getTransactionListSize()); + return baseString; } } diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java index a42e08e048..25c5e86506 100644 --- a/src/main/java/parser/Parser.java +++ b/src/main/java/parser/Parser.java @@ -3,6 +3,7 @@ import customexceptions.IncompletePromptException; import command.AddInflowCommand; import command.AddOutflowCommand; +import command.AddReminderCommand; import command.BaseCommand; import command.DeleteOutflowCommand; import command.ExitCommand; @@ -11,6 +12,10 @@ import command.HelpCommand; import command.DeleteInflowCommand; import command.EditOutflowCommand; +import command.DeleteReminderCommand; +import command.EditReminderCommand; +import command.SetBudgetCommand; + import userinterface.UI; public class Parser { @@ -37,6 +42,11 @@ public BaseCommand parseCommand(String command) throws IncompletePromptException throw new IncompletePromptException(command); } return new AddOutflowCommand(commandParts); + case "add-reminder": + if (commandParts.length < 6) { + throw new IncompletePromptException(command); + } + return new AddReminderCommand(commandParts); case "delete-inflow": if (commandParts.length < 2) { throw new IncompletePromptException(command); @@ -47,6 +57,11 @@ public BaseCommand parseCommand(String command) throws IncompletePromptException throw new IncompletePromptException(command); } return new DeleteOutflowCommand(commandParts); + case "delete-reminder": + if (commandParts.length < 2) { + throw new IncompletePromptException(command); + } + return new DeleteReminderCommand(commandParts); case "edit-inflow": if (commandParts.length < 7) { throw new IncompletePromptException(command); @@ -57,6 +72,16 @@ public BaseCommand parseCommand(String command) throws IncompletePromptException throw new IncompletePromptException(command); } return new EditOutflowCommand(commandParts); + case "edit-reminder": + if (commandParts.length < 7) { + throw new IncompletePromptException(command); + } + return new EditReminderCommand(commandParts); + case "set-budget": + if (commandParts.length < 2) { + throw new IncompletePromptException(command); + } + return new SetBudgetCommand(commandParts); case "view-history": if (commandParts.length < 2) { throw new IncompletePromptException(command); diff --git a/src/main/java/storage/Storage.java b/src/main/java/storage/Storage.java index 4b863083c6..d9cc883ad7 100644 --- a/src/main/java/storage/Storage.java +++ b/src/main/java/storage/Storage.java @@ -2,6 +2,7 @@ import financialtransactions.Inflow; import financialtransactions.Outflow; +import financialtransactions.Reminder; import financialtransactions.TransactionManager; import user.BaseUser; @@ -54,18 +55,23 @@ public TransactionManager loadFile(String username) { TransactionManager manager = new TransactionManager(); try { Scanner sc = new Scanner(f); + manager.setBudget(Double.parseDouble(sc.nextLine())); while (sc.hasNext()) { String[] transactionInfo = sc.nextLine().split("\\|"); - assert transactionInfo.length == 4 : "Transaction info should have 4 arguments"; + assert transactionInfo.length == 5 : "Transaction info should have 5 arguments"; double amount = Double.parseDouble(transactionInfo[1]); - if (!transactionInfo[1].startsWith("-")) { + if (transactionInfo[4].equals("I")) { Inflow inflow = new Inflow(transactionInfo[0], amount, transactionInfo[2]); inflow.setCategory(Inflow.Category.valueOf(transactionInfo[3])); manager.addTransaction(inflow); - } else { + } else if (transactionInfo[4].equals("O")){ Outflow outflow = new Outflow(transactionInfo[0], -amount, transactionInfo[2]); outflow.setCategory(Outflow.Category.valueOf(transactionInfo[3])); manager.addTransaction(outflow); + } else { + Reminder reminder = new Reminder(transactionInfo[0], -amount, transactionInfo[2]); + reminder.setCategory(Reminder.Category.valueOf(transactionInfo[3])); + manager.addTransaction(reminder); } } sc.close(); diff --git a/src/test/java/financialtransactions/TransactionManagerTest.java b/src/test/java/financialtransactions/TransactionManagerTest.java index 4e423eaf28..536d6f3630 100644 --- a/src/test/java/financialtransactions/TransactionManagerTest.java +++ b/src/test/java/financialtransactions/TransactionManagerTest.java @@ -16,8 +16,16 @@ public void toSaveTest() { Outflow shopping = new Outflow("Shopping", 200, "23/05/2022 2000"); shopping.setCategory(Outflow.Category.SHOPPING); managerTest.addTransaction(shopping); - - assertEquals("Salary payment|400.00|May 23 2022 07:00PM|INCOME\n" + - "Shopping|-200.00|May 23 2022 08:00PM|SHOPPING\n", managerTest.toSave()); + + Reminder bill = new Reminder("Water bills", 64.30, "25/06/2025 1500"); + bill.setCategory(Reminder.Category.UTILITIES); + managerTest.addTransaction(bill); + + managerTest.setBudget(1500); + + assertEquals("1500.00\n" + + "Salary payment|400.00|May 23 2022 07:00PM|INCOME|I\n" + + "Shopping|-200.00|May 23 2022 08:00PM|SHOPPING|O\n" + + "Water bills|-64.30|Jun 25 2025 03:00PM|UTILITIES|R\n", managerTest.toSave()); } }