From feaef10505144cb51b889bce54d3f9c158873273 Mon Sep 17 00:00:00 2001 From: Felix Chan You Yuan Date: Fri, 29 Mar 2024 02:44:42 +0800 Subject: [PATCH] Add Budget class for Buyer class Addition of the Budget class is necessary to represent the budget attribute for Buyer objects. Implemented the Budget class to encapsulate the budget information for buyers, allowing for better organization and management of budget-related data. Using a separate class for budget ensures separation of concerns and follows the single responsibility principle, improving code readability and maintainability. This commit also includes necessary adjustments to integrate the Budget class with the Buyer class. --- .../logic/commands/AddBuyerCommand.java | 3 + .../logic/parser/AddBuyerCommandParser.java | 13 ++-- .../seedu/address/logic/parser/CliSyntax.java | 1 + .../address/logic/parser/ParserUtil.java | 16 +++++ .../seedu/address/model/person/Budget.java | 58 ++++++++++++++++ .../seedu/address/model/person/Buyer.java | 48 +++++++++++++- .../address/model/util/SampleDataUtil.java | 7 +- .../address/storage/JsonAdaptedBuyer.java | 17 ++++- .../java/seedu/address/ui/PersonCard.java | 7 ++ src/main/resources/view/PersonListCard.fxml | 1 + .../duplicatePersonAddressBook.json | 1 + .../typicalPersonsAddressBook.json | 5 +- .../logic/commands/AddBuyerCommandTest.java | 6 +- .../logic/commands/CommandTestUtil.java | 8 +++ .../logic/parser/AddressBookParserTest.java | 3 +- .../seedu/address/model/person/BuyerTest.java | 66 ++++++++++--------- .../address/storage/JsonAdaptedBuyerTest.java | 42 ++++++++++-- .../storage/JsonAddressBookStorageTest.java | 6 +- .../seedu/address/testutil/BuyerBuilder.java | 15 ++++- .../seedu/address/testutil/PersonUtil.java | 22 ++++++- .../address/testutil/TypicalPersons.java | 31 +++++++-- 21 files changed, 309 insertions(+), 67 deletions(-) create mode 100644 src/main/java/seedu/address/model/person/Budget.java diff --git a/src/main/java/seedu/address/logic/commands/AddBuyerCommand.java b/src/main/java/seedu/address/logic/commands/AddBuyerCommand.java index 63d51526c19..d3ce44e92c3 100644 --- a/src/main/java/seedu/address/logic/commands/AddBuyerCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddBuyerCommand.java @@ -1,6 +1,7 @@ package seedu.address.logic.commands; import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_BUDGET; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_HOUSING_TYPE; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; @@ -26,12 +27,14 @@ public class AddBuyerCommand extends Command { + PREFIX_PHONE + "PHONE " + PREFIX_EMAIL + "EMAIL " + PREFIX_HOUSING_TYPE + "HOUSING_TYPE " + + PREFIX_BUDGET + "BUDGET " + "[" + PREFIX_TAG + "TAG]...\n" + "Example: " + COMMAND_WORD + " " + PREFIX_NAME + "John Doe " + PREFIX_PHONE + "98765432 " + PREFIX_EMAIL + "johnd@example.com " + PREFIX_HOUSING_TYPE + "HDB " + + PREFIX_BUDGET + "99999900 " + PREFIX_TAG + "friends " + PREFIX_TAG + "owesMoney"; diff --git a/src/main/java/seedu/address/logic/parser/AddBuyerCommandParser.java b/src/main/java/seedu/address/logic/parser/AddBuyerCommandParser.java index 55f6f96577d..f339c678c70 100644 --- a/src/main/java/seedu/address/logic/parser/AddBuyerCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/AddBuyerCommandParser.java @@ -1,6 +1,7 @@ package seedu.address.logic.parser; import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_BUDGET; import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; import static seedu.address.logic.parser.CliSyntax.PREFIX_HOUSING_TYPE; import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; @@ -12,6 +13,7 @@ import seedu.address.logic.commands.AddBuyerCommand; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.person.Budget; import seedu.address.model.person.Buyer; import seedu.address.model.person.Email; import seedu.address.model.person.Name; @@ -31,21 +33,24 @@ public class AddBuyerCommandParser implements Parser { public AddBuyerCommand parse(String args) throws ParseException { ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_HOUSING_TYPE, - PREFIX_TAG); + PREFIX_BUDGET, PREFIX_TAG); - if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_HOUSING_TYPE) + if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_HOUSING_TYPE, + PREFIX_BUDGET) || !argMultimap.getPreamble().isEmpty()) { throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddBuyerCommand.MESSAGE_USAGE)); } - argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_HOUSING_TYPE); + argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_HOUSING_TYPE, + PREFIX_BUDGET); Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()); Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()); Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()); String housingType = ParserUtil.parseHousing(argMultimap.getValue(PREFIX_HOUSING_TYPE).get()); Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); + Budget budget = ParserUtil.parseBudget(argMultimap.getValue(PREFIX_BUDGET).get()); - Buyer buyer = new Buyer(name, phone, email, housingType, tagList); + Buyer buyer = new Buyer(name, phone, email, housingType, budget, tagList); return new AddBuyerCommand(buyer); } diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index 8109c14f565..8ac0fb5a365 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -16,4 +16,5 @@ public class CliSyntax { public static final Prefix PREFIX_UNITNUMBER = new Prefix("unitNo/"); public static final Prefix PREFIX_BLOCK = new Prefix("blk/"); public static final Prefix PREFIX_POSTALCODE = new Prefix("postal/"); + public static final Prefix PREFIX_BUDGET = 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 d9ecf15ec7a..5c08e3f6344 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -16,6 +16,7 @@ import seedu.address.model.house.Street; import seedu.address.model.house.UnitNumber; import seedu.address.model.person.Address; +import seedu.address.model.person.Budget; import seedu.address.model.person.Email; import seedu.address.model.person.Name; import seedu.address.model.person.Phone; @@ -217,4 +218,19 @@ public static PostalCode parsePostalCode(String postalCode) throws ParseExceptio } return new PostalCode(trimmedPostalCode); } + + /** + * Parses a {@code String budget} into an {@code Budget} + * Loading and trailing whitespaces will be trimmed + * + * @throws ParseException if the given {@code budget} is invalid + */ + public static Budget parseBudget(String budget) throws ParseException { + requireNonNull(budget); + String trimmedBudget = budget.trim(); + if (!Budget.isValidBudget(trimmedBudget)) { + throw new ParseException(Budget.MESSAGE_CONSTRAINTS); + } + return new Budget(trimmedBudget); + } } diff --git a/src/main/java/seedu/address/model/person/Budget.java b/src/main/java/seedu/address/model/person/Budget.java new file mode 100644 index 00000000000..e6fee05d058 --- /dev/null +++ b/src/main/java/seedu/address/model/person/Budget.java @@ -0,0 +1,58 @@ +package seedu.address.model.person; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.AppUtil.checkArgument; + +/** + * Represents a Buyer's budget in the address book. + * Guarantees: immutable; is valid as declared in {@link #isValidBudget(String)} + */ +public class Budget { + + public static final String MESSAGE_CONSTRAINTS = "Budget should be a positive number."; + public static final String VALIDATION_REGEX = "\\d+(\\.\\d+)?"; + public final String value; + + /** + * Constructs a {@code Budget}. + * + * @param budget A valid budget amount. + */ + public Budget(String budget) { + requireNonNull(budget); + checkArgument(isValidBudget(budget), MESSAGE_CONSTRAINTS); + value = budget; + } + + /** + * Returns true if a given string is a valid budget amount. + */ + public static boolean isValidBudget(String test) { + return test.matches(VALIDATION_REGEX) && Double.parseDouble(test) >= 0; + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof Budget)) { + return false; + } + + Budget otherBudget = (Budget) other; + return value.equals(otherBudget.value); + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/src/main/java/seedu/address/model/person/Buyer.java b/src/main/java/seedu/address/model/person/Buyer.java index ab2ae18e5ba..80fe66ed3ee 100644 --- a/src/main/java/seedu/address/model/person/Buyer.java +++ b/src/main/java/seedu/address/model/person/Buyer.java @@ -1,7 +1,9 @@ package seedu.address.model.person; +import java.util.Objects; import java.util.Set; +import seedu.address.commons.util.ToStringBuilder; import seedu.address.model.tag.Tag; /** @@ -9,6 +11,8 @@ */ public class Buyer extends Person { + private final Budget budget; + /** * Constructs a new Buyer instance without specifying a house. Default constructor. * @@ -17,8 +21,50 @@ public class Buyer extends Person { * @param email The email address of the buyer. * @param housingType The type of housing the buyer wants. * @param tags The tags associated with the buyer. + * @param budget The budget of the buyer. */ - public Buyer(Name name, Phone phone, Email email, String housingType, Set tags) { + public Buyer(Name name, Phone phone, Email email, String housingType, Budget budget, Set tags) { super(name, phone, email, housingType, tags); + this.budget = budget; + } + + public Budget getBudget() { + return budget; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof Buyer)) { + return false; + } + + if (!super.equals(other)) { + return false; + } + + Buyer buyer = (Buyer) other; + return Objects.equals(budget, buyer.budget); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), budget); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .add("name", getName()) + .add("phone", getPhone()) + .add("email", getEmail()) + .add("housingType", getHousingType()) + .add("budget", budget) + .add("tags", getTags()) + .toString(); } } diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java index 355dee4918e..0078516002b 100644 --- a/src/main/java/seedu/address/model/util/SampleDataUtil.java +++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java @@ -14,6 +14,7 @@ import seedu.address.model.house.PostalCode; import seedu.address.model.house.Street; import seedu.address.model.house.UnitNumber; +import seedu.address.model.person.Budget; import seedu.address.model.person.Buyer; import seedu.address.model.person.Email; import seedu.address.model.person.Name; @@ -28,13 +29,13 @@ public class SampleDataUtil { public static Buyer[] getSampleBuyers() { return new Buyer[] { new Buyer(new Name("Alex Yeoh"), new Phone("87438807"), - new Email("alexyeoh@example.com"), "HDB", + new Email("alexyeoh@example.com"), "HDB", new Budget("100000"), getTagSet("friends")), new Buyer(new Name("Bernice Yu"), new Phone("99272758"), - new Email("berniceyu@example.com"), "Condominium", + new Email("berniceyu@example.com"), "Condominium", new Budget("200000"), getTagSet("colleagues", "friends")), new Buyer(new Name("Charlotte Oliveiro"), new Phone("93210283"), - new Email("charlotte@example.com"), "HDB", + new Email("charlotte@example.com"), "HDB", new Budget("300000"), getTagSet("neighbours")), }; } diff --git a/src/main/java/seedu/address/storage/JsonAdaptedBuyer.java b/src/main/java/seedu/address/storage/JsonAdaptedBuyer.java index d3a85da6a4d..5af746d5404 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedBuyer.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedBuyer.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.person.Budget; import seedu.address.model.person.Buyer; import seedu.address.model.person.Person; @@ -15,6 +16,8 @@ */ public class JsonAdaptedBuyer extends JsonAdaptedPerson { + private final String budget; + /** * Constructs a {@code JsonAdaptedBuyer}, extends from JsonAdaptedPerson */ @@ -23,8 +26,10 @@ public JsonAdaptedBuyer(@JsonProperty("name") String name, @JsonProperty("phone") String phone, @JsonProperty("email") String email, @JsonProperty("housingType") String housingType, + @JsonProperty("budget") String budget, @JsonProperty("tags") List tags) { super(name, phone, email, housingType, tags); + this.budget = budget; } /** @@ -32,6 +37,7 @@ public JsonAdaptedBuyer(@JsonProperty("name") String name, */ public JsonAdaptedBuyer(Buyer source) { super(source); + budget = source.getBudget().value; } /** @@ -39,8 +45,17 @@ public JsonAdaptedBuyer(Buyer source) { */ @Override public Buyer toModelType() throws IllegalValueException { + + if (budget == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Budget.class.getSimpleName())); + } + if (!Budget.isValidBudget(budget)) { + throw new IllegalValueException(Budget.MESSAGE_CONSTRAINTS); + } + final Budget modelBudget = new Budget(budget); + Person person = super.toModelType(); return new Buyer(person.getName(), person.getPhone(), person.getEmail(), - person.getHousingType(), new HashSet<>(person.getTags())); + person.getHousingType(), modelBudget, new HashSet<>(person.getTags())); } } diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java index d677a5096d6..3d26bd3eb8a 100644 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ b/src/main/java/seedu/address/ui/PersonCard.java @@ -11,6 +11,7 @@ import seedu.address.model.house.Block; import seedu.address.model.house.Level; import seedu.address.model.house.NonLanded; +import seedu.address.model.person.Buyer; import seedu.address.model.person.Person; import seedu.address.model.person.Seller; @@ -34,6 +35,8 @@ public class PersonCard extends UiPart { @FXML private Label housingType; @FXML + private Label budget; + @FXML private Label email; @FXML private Label postalCode; @@ -59,6 +62,8 @@ public PersonCard(Person person, int displayedIndex) { // Check if person is a Seller and display houses (For now, we assume only have seller have house) if (person instanceof Seller) { + // Show no budget + budget.setVisible(false); Seller seller = (Seller) person; if (seller.getHouses() != null) { seller.getHouses().forEach(house -> { @@ -92,6 +97,8 @@ public PersonCard(Person person, int displayedIndex) { } else { // We assumed that buyer does not have a house for now housesContainer.setVisible(false); + Buyer buyer = (Buyer) person; + budget.setText("$" + buyer.getBudget().toString()); } } } diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml index acbaf5a62e0..23d255554f2 100644 --- a/src/main/resources/view/PersonListCard.fxml +++ b/src/main/resources/view/PersonListCard.fxml @@ -32,6 +32,7 @@