Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop projection #60

Merged
merged 6 commits into from
Oct 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/java/seedu/address/commons/util/AppUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public static void checkArgument(Boolean condition) {
*/
public static void checkArgument(Boolean condition, String errorMessage) {
if (!condition) {
System.out.println("cond failed at checkArgument");
throw new IllegalArgumentException(errorMessage);
}
}
Expand Down
43 changes: 43 additions & 0 deletions src/main/java/seedu/address/logic/commands/ProjectCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;

import javafx.collections.ObservableList;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Date;
import seedu.address.model.Model;
import seedu.address.model.Projection;
import seedu.address.model.transaction.DateComparator;
import seedu.address.model.transaction.Transaction;

/**
* Projects user's future balance based on income/outflow history
*/
public class ProjectCommand extends Command {
public static final String COMMAND_WORD = "project";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Project future balance based on past income/outflow.\n"
+ "Parameters: "
+ PREFIX_DATE + "DATE\n"
+ "Example: " + COMMAND_WORD + " "
+ PREFIX_DATE + "12122103 09:00";

public static final String MESSAGE_SUCCESS = "Projected balance: %1$s";
public final Date date;

public ProjectCommand(Date date) {
this.date = date;
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);

ObservableList<Transaction> transactionHistory =
model.getBankAccount().getTransactionHistory().sorted(new DateComparator());

Projection projection = new Projection(transactionHistory, date, model);
return new CommandResult(String.format(MESSAGE_SUCCESS, projection.toString()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.InCommand;
// import seedu.address.logic.commands.SplitCommand;
import seedu.address.logic.commands.ProjectCommand;
import seedu.address.logic.parser.exceptions.ParseException;

/**
Expand Down Expand Up @@ -53,6 +53,9 @@ public Command parseCommand(String userInput) throws ParseException {
case ExitCommand.COMMAND_WORD:
return new ExitCommand();

case ProjectCommand.COMMAND_WORD:
return new ProjectCommandParser().parse(arguments);

default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/seedu/address/logic/parser/CliSyntax.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ public class CliSyntax {
public static final Prefix PREFIX_AMOUNT = new Prefix("$/");
public static final Prefix PREFIX_TAG = new Prefix("t/");
public static final Prefix PREFIX_DATE = new Prefix("d/");
public static final Prefix PREFIX_TIME = new Prefix("t/");
}
6 changes: 3 additions & 3 deletions src/main/java/seedu/address/logic/parser/InCommandParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;

import java.util.Date;
import java.util.Set;
import java.util.stream.Stream;

import seedu.address.logic.commands.InCommand;
import seedu.address.logic.parser.exceptions.ParseException;

import seedu.address.model.Date;
import seedu.address.model.person.Name;
import seedu.address.model.tag.Tag;
import seedu.address.model.transaction.Amount;
Expand All @@ -36,11 +36,11 @@ public InCommand parse(String args) throws ParseException {

Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
Amount amount = ParserUtil.parseAmount(argMultimap.getValue(PREFIX_AMOUNT).get());
// Date date = ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get());
Date date = ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get());

Set<Tag> tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));

Transaction transaction = new InTransaction(amount, new Date(System.currentTimeMillis()));
Transaction transaction = new InTransaction(amount, date);

return new InCommand(transaction);

Expand Down
17 changes: 17 additions & 0 deletions src/main/java/seedu/address/logic/parser/ParserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.StringUtil;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.Date;
import seedu.address.model.person.Address;
import seedu.address.model.person.Email;
import seedu.address.model.person.Name;
Expand Down Expand Up @@ -81,6 +82,22 @@ public static Address parseAddress(String address) throws ParseException {
return new Address(trimmedAddress);
}


/**
* Parses a {@code String date} into an {@code Date}.
* Leading and trailing whitespaces will be trimmed.
*
* @throws ParseException if the given {@code date} is invalid.
*/
public static Date parseDate(String date) throws ParseException {
requireNonNull(date);
String trimmedDate = date.trim();
if (!Date.isValidDate(trimmedDate) && !Date.isValidDate(trimmedDate)) {
throw new ParseException(Date.MESSAGE_CONSTRAINTS);
}
return new Date(trimmedDate);
}

/**
* Parses a {@code String email} into an {@code Email}.
* Leading and trailing whitespaces will be trimmed.
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/seedu/address/logic/parser/ProjectCommandParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package seedu.address.logic.parser;

import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE;

import java.util.stream.Stream;

import seedu.address.logic.commands.ProjectCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.Date;

/**
* Parses input arguments and creates a new ProjectCommand object
*/
public class ProjectCommandParser implements Parser<ProjectCommand> {

@Override
public ProjectCommand parse(String userInput) throws ParseException {
ArgumentMultimap argMultimap =
ArgumentTokenizer.tokenize(userInput, PREFIX_DATE);

if (!arePrefixesPresent(argMultimap, PREFIX_DATE)
|| !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ProjectCommand.MESSAGE_USAGE));
}

Date date = ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get());

return new ProjectCommand(date);
}

/**
* Returns true if none of the prefixes contains empty {@code Optional} values in the given
* {@code ArgumentMultimap}.
*/
private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
}
}
4 changes: 4 additions & 0 deletions src/main/java/seedu/address/model/BankAccount.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ public ObservableList<Transaction> getTransactionHistory() {
return transactions.asUnmodifiableObservableList();
}

public Amount getBalance() {
return this.balance;
}

@Override
public boolean equals(Object other) {
if (other == this) {
Expand Down
61 changes: 61 additions & 0 deletions src/main/java/seedu/address/model/Date.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package seedu.address.model;

import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

/**
* Represents a date within PalPay.
* Guarantees: immutable; is valid as declared in {@link #isValidDate(String)}
*/
public class Date {

public static final String MESSAGE_CONSTRAINTS = "Date objects must adhere to the format: DDMMYYYY\n";

public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("ddMMyyyy");

public final LocalDate date;

public Date (String value) {
requireNonNull(value);
checkArgument(isValidDate(value), MESSAGE_CONSTRAINTS);
this.date = LocalDate.parse(value, DATE_FORMATTER);
}

/**
* Returns true if a given string is a valid date.
*/
public static boolean isValidDate(String test) {
try {
DATE_FORMATTER.parse(test);
return true;
} catch (DateTimeParseException e) {
return false;
}
}


@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof Time // instanceof handles nulls
&& date.equals(((Time) other).time)); // state check
}

@Override
public int hashCode() {
return this.date.format(DATE_FORMATTER).hashCode();
}

@Override
public String toString() {
return this.date.format(DATE_FORMATTER);
}

public LocalDate toLocalDate() {
return this.date;
}
}
51 changes: 51 additions & 0 deletions src/main/java/seedu/address/model/Projection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package seedu.address.model;

import static java.time.temporal.ChronoUnit.DAYS;

import java.time.LocalDate;

import javafx.collections.ObservableList;
import seedu.address.model.transaction.Amount;
import seedu.address.model.transaction.Transaction;

/**
* Represents a projection of user's balance at a set date in the future
*/
public class Projection {

public final ObservableList<Transaction> transactionHistory;
public final Date date;
public final Model model;
private Amount projection;

public Projection(ObservableList<Transaction> transactionHistory, Date date, Model model) {
this.transactionHistory = transactionHistory;
this.date = date;
this.model = model;
this.project();
}

/**
* Computes projection for specified date based on transactionHistory
*/
public void project() {
Amount totalPrev = new Amount(0);
int totalDaysElapsed = (int) DAYS.between(transactionHistory.get(0)
.getDate().toLocalDate(), LocalDate.now());
System.out.println(totalDaysElapsed);
for (Transaction transaction : transactionHistory) {
totalPrev = totalPrev.addAmount(transaction.getAmount());
}
int daysAfter = (int) DAYS.between(LocalDate.now(), date.toLocalDate());
projection = new Amount((totalPrev.getAmount() / totalDaysElapsed) * daysAfter
+ this.model.getBankAccount().getBalance().getAmount());
}

public Amount getProjection() {
return this.projection;
}

public String toString() {
return this.projection.toString();
}
}
2 changes: 2 additions & 0 deletions src/main/java/seedu/address/model/ReadOnlyBankAccount.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package seedu.address.model;

import javafx.collections.ObservableList;
import seedu.address.model.transaction.Amount;
import seedu.address.model.transaction.Transaction;

/**
Expand All @@ -14,4 +15,5 @@ public interface ReadOnlyBankAccount {
*/
ObservableList<Transaction> getTransactionHistory();

Amount getBalance();
}
58 changes: 58 additions & 0 deletions src/main/java/seedu/address/model/Time.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package seedu.address.model;

import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

/**
* Represents point in time within PalPay.
* Guarantees: immutable; is valid as declared in {@link #isValidTime(String)}
*/
public class Time {

public static final String MESSAGE_CONSTRAINTS = "Time objects must adhere to the format: HHmm\n";

public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HHmm");

public final LocalDate time;

public Time(String value) {
requireNonNull(value);
checkArgument(isValidTime(value), MESSAGE_CONSTRAINTS);
this.time = LocalDate.parse(value, TIME_FORMATTER);
}

/**
* Returns true if a given string is a valid date.
*/
public static boolean isValidTime(String test) {
try {
TIME_FORMATTER.parse(test);
return true;
} catch (DateTimeParseException e) {
return false;
}
}


@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof Time // instanceof handles nulls
&& time.equals(((Time) other).time)); // state check
}

@Override
public int hashCode() {
return this.time.format(TIME_FORMATTER).hashCode();
}

@Override
public String toString() {
return this.time.format(TIME_FORMATTER);
}

}
2 changes: 1 addition & 1 deletion src/main/java/seedu/address/model/person/Address.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public Address(String address) {
}

/**
* Returns true if a given string is a valid email.
* Returns true if a given string is a valid address.
*/
public static boolean isValidAddress(String test) {
return test.matches(VALIDATION_REGEX);
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/seedu/address/model/transaction/DateComparator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package seedu.address.model.transaction;

import java.util.Comparator;

/**
* Comparator class for sorting Transactions in ascending order of date
*/
public class DateComparator implements Comparator<Transaction> {
@Override
public int compare(Transaction o1, Transaction o2) {
return o1.getDate().toLocalDate().compareTo(o2.getDate().toLocalDate());
}
}
Loading