diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java index 5b47ed1dd5a..f9c9e1aa5c6 100644 --- a/src/main/java/seedu/address/logic/commands/AddCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddCommand.java @@ -4,6 +4,7 @@ import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_BIRTHDAY; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.address.logic.parser.CliSyntax.PREFIX_MONEY_OWED; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; @@ -28,12 +29,14 @@ public class AddCommand extends Command { + PREFIX_EMAIL + "EMAIL " + PREFIX_ADDRESS + "ADDRESS " + "[" + PREFIX_BIRTHDAY + "BIRTHDAY]" + + PREFIX_MONEY_OWED + "AMOUNT_OWED" + "[" + PREFIX_TAG + "TAG]...\n" + "Example: " + COMMAND_WORD + " " + PREFIX_NAME + "John Doe " + PREFIX_PHONE + "98765432 " + PREFIX_EMAIL + "johnd@example.com " + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 " + + PREFIX_MONEY_OWED + "24.50 " + PREFIX_TAG + "friends " + PREFIX_TAG + "owesMoney"; diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java index 83474540c45..48393fa415a 100644 --- a/src/main/java/seedu/address/logic/commands/EditCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -24,6 +24,7 @@ import seedu.address.model.person.Address; import seedu.address.model.person.Birthday; import seedu.address.model.person.Email; +import seedu.address.model.person.MoneyOwed; import seedu.address.model.person.Name; import seedu.address.model.person.Person; import seedu.address.model.person.Phone; @@ -58,7 +59,7 @@ public class EditCommand extends Command { private final EditPersonDescriptor editPersonDescriptor; /** - * @param index of the person in the filtered person list to edit + * @param index of the person in the filtered person list to edit * @param editPersonDescriptor details to edit the person with */ public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) { @@ -83,9 +84,10 @@ private static Person createEditedPerson(Person personToEdit, EditPersonDescript Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags()); Remark updatedRemark = personToEdit.getRemark(); // edit command does not allow editing remarks Birthday updatedBirthday = editPersonDescriptor.getBirthday().orElse(personToEdit.getBirthday()); + MoneyOwed updatedMoneyOwed = editPersonDescriptor.getMoneyOwed().orElse(personToEdit.getMoneyOwed()); return new Person(updatedName, updatedPhone, updatedEmail, - updatedAddress, updatedRemark, updatedTags, updatedBirthday); + updatedAddress, updatedRemark, updatedTags, updatedBirthday, updatedMoneyOwed); } @Override @@ -144,6 +146,7 @@ public static class EditPersonDescriptor { private Address address; private Set tags; private Birthday birthday; + private MoneyOwed moneyOwed; public EditPersonDescriptor() { } @@ -159,6 +162,7 @@ public EditPersonDescriptor(EditPersonDescriptor toCopy) { setAddress(toCopy.address); setTags(toCopy.tags); setBirthday(toCopy.birthday); + setMoneyOwed(toCopy.moneyOwed); } public Optional getBirthday() { @@ -176,22 +180,22 @@ public boolean isAnyFieldEdited() { return CollectionUtil.isAnyNonNull(name, phone, email, address, tags, birthday); } - public Optional getName() { - return Optional.ofNullable(name); - } - public void setName(Name name) { this.name = name; } - public Optional getPhone() { - return Optional.ofNullable(phone); + public Optional getName() { + return Optional.ofNullable(name); } public void setPhone(Phone phone) { this.phone = phone; } + public Optional getPhone() { + return Optional.ofNullable(phone); + } + public Optional getEmail() { return Optional.ofNullable(email); } @@ -208,13 +212,12 @@ public void setAddress(Address address) { this.address = address; } - /** - * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException} - * if modification is attempted. - * Returns {@code Optional#empty()} if {@code tags} is null. - */ - public Optional> getTags() { - return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty(); + public void setMoneyOwed(MoneyOwed moneyOwed) { + this.moneyOwed = moneyOwed; + } + + public Optional getMoneyOwed() { + return Optional.ofNullable(moneyOwed); } /** @@ -225,6 +228,15 @@ public void setTags(Set tags) { this.tags = (tags != null) ? new HashSet<>(tags) : null; } + /** + * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException} + * if modification is attempted. + * Returns {@code Optional#empty()} if {@code tags} is null. + */ + public Optional> getTags() { + return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty(); + } + @Override public boolean equals(Object other) { if (other == this) { diff --git a/src/main/java/seedu/address/logic/commands/RemarkCommand.java b/src/main/java/seedu/address/logic/commands/RemarkCommand.java index b69e80da6aa..7b549c24867 100644 --- a/src/main/java/seedu/address/logic/commands/RemarkCommand.java +++ b/src/main/java/seedu/address/logic/commands/RemarkCommand.java @@ -59,8 +59,8 @@ public CommandResult execute(Model model) throws CommandException { Person personToEdit = lastShownList.get(index.getZeroBased()); Person editedPerson = new Person( - personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(), - personToEdit.getAddress(), remark, personToEdit.getTags(), personToEdit.getBirthday()); + personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(), personToEdit.getAddress(), + remark, personToEdit.getTags(), personToEdit.getBirthday(), personToEdit.getMoneyOwed()); model.setPerson(personToEdit, editedPerson); model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java index d3a270a04c8..9ddd030fbe9 100644 --- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java @@ -4,6 +4,7 @@ import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; import static seedu.address.logic.parser.CliSyntax.PREFIX_BIRTHDAY; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.address.logic.parser.CliSyntax.PREFIX_MONEY_OWED; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; @@ -16,6 +17,7 @@ import seedu.address.model.person.Address; import seedu.address.model.person.Birthday; import seedu.address.model.person.Email; +import seedu.address.model.person.MoneyOwed; import seedu.address.model.person.Name; import seedu.address.model.person.Person; import seedu.address.model.person.Phone; @@ -27,14 +29,6 @@ */ public class AddCommandParser implements Parser { - /** - * 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()); - } - /** * Parses the given {@code String} of arguments in the context of the AddCommand * and returns an AddCommand object for execution. @@ -44,7 +38,7 @@ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Pre public AddCommand parse(String args) throws ParseException { ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG, - PREFIX_BIRTHDAY); + PREFIX_BIRTHDAY, PREFIX_MONEY_OWED); if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL) || !argMultimap.getPreamble().isEmpty()) { @@ -59,10 +53,19 @@ public AddCommand parse(String args) throws ParseException { Remark remark = new Remark(""); // add command does not allow adding remarks straight away Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); Birthday birthday = ParserUtil.parseBirthday(argMultimap.getValue(PREFIX_BIRTHDAY).orElse("")); + MoneyOwed moneyOwed = ParserUtil.parseMoneyOwed(argMultimap.getValue(PREFIX_MONEY_OWED).orElse("0")); - Person person = new Person(name, phone, email, address, remark, tagList, birthday); + Person person = new Person(name, phone, email, address, remark, tagList, birthday, moneyOwed); return new AddCommand(person); } + /** + * 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()); + } + } diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index 6cfb57db06e..1d5f8ea1997 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -10,9 +10,9 @@ public class CliSyntax { public static final Prefix PREFIX_PHONE = new Prefix("p/"); public static final Prefix PREFIX_EMAIL = new Prefix("e/"); public static final Prefix PREFIX_ADDRESS = new Prefix("a/"); + public static final Prefix PREFIX_MONEY_OWED = new Prefix("$/"); public static final Prefix PREFIX_TAG = new Prefix("t/"); public static final Prefix PREFIX_REMARK = new Prefix("r/"); - public static final Prefix PREFIX_BIRTHDAY = new Prefix("b/"); } diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index dfce025ce43..df790da3a73 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -12,6 +12,7 @@ import seedu.address.model.person.Address; import seedu.address.model.person.Birthday; import seedu.address.model.person.Email; +import seedu.address.model.person.MoneyOwed; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; @@ -97,6 +98,21 @@ public static Email parseEmail(String email) throws ParseException { return new Email(trimmedEmail); } + /** + * Parses a {@code String moneyOwed} into a {@code MoneyOwed}. + * Leading and trailing whitespaces will be trimmed. + * + * @throws ParseException if the given {@code MoneyOwed} is invalid. + */ + public static MoneyOwed parseMoneyOwed(String moneyOwed) throws ParseException { + requireNonNull(moneyOwed); + String trimmedMoneyOwed = moneyOwed.trim(); + if (!MoneyOwed.isValidMoney(trimmedMoneyOwed)) { + throw new ParseException(MoneyOwed.MESSAGE_CONSTRAINTS); + } + return new MoneyOwed(trimmedMoneyOwed); + } + /** * Parses a {@code String tag} into a {@code Tag}. * Leading and trailing whitespaces will be trimmed. diff --git a/src/main/java/seedu/address/model/person/MoneyOwed.java b/src/main/java/seedu/address/model/person/MoneyOwed.java new file mode 100644 index 00000000000..1a674502bae --- /dev/null +++ b/src/main/java/seedu/address/model/person/MoneyOwed.java @@ -0,0 +1,84 @@ +package seedu.address.model.person; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.AppUtil.checkArgument; + +/** + * Represents a Person's money owed in the address book. + * Guarantees: immutable; is valid as declared in {@link #isValidMoney(String)} + */ +public class MoneyOwed { + + public static final String MESSAGE_CONSTRAINTS = + "Money Owed should be at most 2 decimal places in the following format 'xxx.xx' or '-xxx.xx'. "; + public static final String VALIDATION_REGEX = "^(?:-)?\\d+(\\.\\d{0,2})?"; + + public final Float moneyOwed; + + /** + * Constructs a {@code MoneyOwed}. + * + * @param money A valid amount of money owed. + */ + public MoneyOwed(String money) { + requireNonNull(money); + checkArgument(isValidMoney(money), MESSAGE_CONSTRAINTS); + moneyOwed = Float.parseFloat(money); + } + + /** + * Returns true if a given string is a valid money amount. + */ + public static boolean isValidMoney(String test) { + if (test == null) { + return true; + } + return test.matches(VALIDATION_REGEX); + } + + /** + * Returns true if a moneyOwed is negative. + */ + public boolean isNegativeMoney() { + return (moneyOwed < 0); + } + + /** + * Returns message to display on UI in String. + */ + public String getMessage() { + if (moneyOwed == 0) { + return String.format("You don't owe each other anything"); + } + if (isNegativeMoney()) { + return String.format("You owe $" + toString().substring(1)); + } else { + return String.format("Owes you $" + this); + } + } + + @Override + public String toString() { + return String.format("%.2f", moneyOwed); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof MoneyOwed)) { + return false; + } + + MoneyOwed otherName = (MoneyOwed) other; + return moneyOwed.equals(otherName.moneyOwed); + } + + @Override + public int hashCode() { + return moneyOwed.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java index fa5f887dbc5..40b460d1ef6 100644 --- a/src/main/java/seedu/address/model/person/Person.java +++ b/src/main/java/seedu/address/model/person/Person.java @@ -26,12 +26,13 @@ public class Person { private final Remark remark; private final Set tags = new HashSet<>(); private final Birthday birthday; + private final MoneyOwed moneyOwed; /** * Every field must be present and not null. */ - public Person(Name name, Phone phone, Email email, - Address address, Remark remark, Set tags, Birthday birthday) { + public Person(Name name, Phone phone, Email email, Address address, + Remark remark, Set tags, Birthday birthday, MoneyOwed moneyOwed) { requireAllNonNull(name, phone, email, address, tags); this.name = name; this.phone = phone; @@ -40,6 +41,7 @@ public Person(Name name, Phone phone, Email email, this.remark = remark; this.tags.addAll(tags); this.birthday = birthday; + this.moneyOwed = moneyOwed; } public Name getName() { @@ -54,6 +56,10 @@ public Email getEmail() { return email; } + public MoneyOwed getMoneyOwed() { + return moneyOwed; + } + public Address getAddress() { return address; } @@ -108,7 +114,8 @@ public boolean equals(Object other) { && email.equals(otherPerson.email) && address.equals(otherPerson.address) && tags.equals(otherPerson.tags) - && birthday.equals(otherPerson.birthday); + && birthday.equals(otherPerson.birthday) + && moneyOwed.equals(otherPerson.moneyOwed); } @Override @@ -127,6 +134,7 @@ public String toString() { .add("remark", remark) .add("tags", tags) .add("birthday", birthday) + .add("moneyOwed", moneyOwed) .toString(); } diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java index 4a1f72c14bb..07866b4876d 100644 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java @@ -9,6 +9,7 @@ import seedu.address.model.person.Address; import seedu.address.model.person.Birthday; import seedu.address.model.person.Email; +import seedu.address.model.person.MoneyOwed; import seedu.address.model.person.Name; import seedu.address.model.person.Person; import seedu.address.model.person.Phone; @@ -25,22 +26,22 @@ public static Person[] getSamplePersons() { return new Person[] { new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"), new Address("Blk 30 Geylang Street 29, #06-40"), EMPTY_REMARK, - getTagSet("friends"), new Birthday("")), + getTagSet("friends"), new Birthday(""), new MoneyOwed("0")), new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"), new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"), EMPTY_REMARK, - getTagSet("colleagues", "friends"), new Birthday("")), + getTagSet("colleagues", "friends"), new Birthday(""), new MoneyOwed("0")), new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"), new Address("Blk 11 Ang Mo Kio Street 74, #11-04"), EMPTY_REMARK, - getTagSet("neighbours"), new Birthday("")), + getTagSet("neighbours"), new Birthday(""), new MoneyOwed("0")), new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"), new Address("Blk 436 Serangoon Gardens Street 26, #16-43"), EMPTY_REMARK, - getTagSet("family"), new Birthday("")), + getTagSet("family"), new Birthday(""), new MoneyOwed("0")), new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"), new Address("Blk 47 Tampines Street 20, #17-35"), EMPTY_REMARK, - getTagSet("classmates"), new Birthday("")), + getTagSet("classmates"), new Birthday(""), new MoneyOwed("0")), new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"), new Address("Blk 45 Aljunied Street 85, #11-31"), EMPTY_REMARK, - getTagSet("colleagues"), new Birthday("")) + getTagSet("colleagues"), new Birthday(""), new MoneyOwed("0")) }; } diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java index 98eb2e6b8b1..4a37f4eba03 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java @@ -14,6 +14,7 @@ import seedu.address.model.person.Address; import seedu.address.model.person.Birthday; import seedu.address.model.person.Email; +import seedu.address.model.person.MoneyOwed; import seedu.address.model.person.Name; import seedu.address.model.person.Person; import seedu.address.model.person.Phone; @@ -34,6 +35,7 @@ class JsonAdaptedPerson { private final String remark; private final List tags = new ArrayList<>(); private final String birthday; + private final String moneyOwed; /** * Constructs a {@code JsonAdaptedPerson} with the given person details. @@ -43,7 +45,8 @@ public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone @JsonProperty("email") String email, @JsonProperty("address") String address, @JsonProperty("remark") String remark, @JsonProperty("tags") List tags, - @JsonProperty("birthday") String birthday) { + @JsonProperty("birthday") String birthday, + @JsonProperty("moneyOwed") String moneyOwed) { this.name = name; this.phone = phone; this.email = email; @@ -53,6 +56,7 @@ public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone this.tags.addAll(tags); } this.birthday = birthday; + this.moneyOwed = moneyOwed; } /** @@ -68,6 +72,7 @@ public JsonAdaptedPerson(Person source) { .map(JsonAdaptedTag::new) .collect(Collectors.toList())); birthday = source.getBirthday().toString(); + moneyOwed = source.getMoneyOwed().toString(); } /** @@ -122,8 +127,13 @@ public Person toModelType() throws IllegalValueException { throw new IllegalValueException(Birthday.BIRTHDAY_CONSTRAINTS); } final Birthday modelBirthday = new Birthday(Optional.ofNullable(birthday).orElse("")); + if (!MoneyOwed.isValidMoney(moneyOwed)) { + throw new IllegalValueException(MoneyOwed.MESSAGE_CONSTRAINTS); + } + final MoneyOwed modelMoneyOwed = new MoneyOwed(Optional.ofNullable(moneyOwed).orElse("0")); - return new Person(modelName, modelPhone, modelEmail, modelAddress, modelRemark, modelTags, modelBirthday); + return new Person(modelName, modelPhone, modelEmail, modelAddress, modelRemark, + modelTags, modelBirthday, modelMoneyOwed); } } diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java index 7cef23b2733..66f669422b5 100644 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ b/src/main/java/seedu/address/ui/PersonCard.java @@ -46,6 +46,8 @@ public class PersonCard extends UiPart { private Label birthday; @FXML private Label remark; + @FXML + private Label moneyOwed; /** * Creates a {@code PersonCode} with the given {@code Person} and index to display. @@ -63,5 +65,6 @@ public PersonCard(Person person, int displayedIndex) { .sorted(Comparator.comparing(tag -> tag.tagName)) .forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); birthday.setText(Optional.ofNullable(person.getBirthday()).orElse(new Birthday("")).toString()); + moneyOwed.setText(person.getMoneyOwed().getMessage()); } } diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml index aa749aa4deb..662b003a28b 100644 --- a/src/main/resources/view/PersonListCard.fxml +++ b/src/main/resources/view/PersonListCard.fxml @@ -32,6 +32,7 @@