From 4140927cce5536ab7479fe175a90e200a13299da Mon Sep 17 00:00:00 2001 From: FerdiHS Date: Tue, 31 Oct 2023 17:03:06 +0800 Subject: [PATCH 1/3] Add FilterCustomerDescriptor --- docs/DeveloperGuide.md | 12 +-- docs/UserGuide.md | 10 +-- .../logic/commands/FilterCustomerCommand.java | 87 +++++++++++++++++++ .../logic/commands/FilterPropertyCommand.java | 4 +- .../parser/FilterCustomerCommandParser.java | 20 ++--- src/main/resources/view/PropertyListCard.fxml | 2 +- 6 files changed, 109 insertions(+), 26 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 40aa7ab3148..a9f0a62dd9d 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -159,7 +159,7 @@ This section describes some noteworthy details on how certain features are imple #### Motivation The property agent may want to edit the details of a customer or property after adding it to the application. For example, the property agent may want to change the budget range of a customer after adding it to PropertyMatch. -Or, the property agent may want to change the price of a property after adding it to PropertyMatch. +Or, the property agent may want to change the budget of a property after adding it to PropertyMatch. #### Implementation The `EditCustomerCommand` and `EditPropertyCommand` classes extends the `Command` class. They are used to edit the details of a customer or property, respectively. @@ -301,17 +301,17 @@ The following sequence diagram shows how the `FilterCustomerCommand` is executed [Back to top](#table-of-contents) #### Motivation -The property agent may want to see a list of properties based on their budget. For example, the property agent may want to filter properties with price less than $1000000. +The property agent may want to see a list of properties based on their budget. For example, the property agent may want to filter properties with budget less than $1000000. Or, the property agent may want to see a list of properties based on the characteristics. For example, the property agent may want to filter pink properties. -Or, the property agent may want to see a list of properties based on both price and characteristics to enhance productivity. +Or, the property agent may want to see a list of properties based on both budget and characteristics to enhance productivity. #### Implementation The `FilterPropertyCommand` class extends the `Command` class. They are used to filter properties. -The command allows the user to filter properties based on their price and/or characteristics. The commands expect at least one flag, either price or characteristics, to be used as a filter. +The command allows the user to filter properties based on their budget and/or characteristics. The commands expect at least one flag, either budget or characteristics, to be used as a filter. When the filter command is inputted, the `FilterPropertyCommandParser` class is used to parse the user input and create the respective `FilterPropertyCommand` objects. When these created command objects are executed by the `LogicManager`, the `FilterPropertyCommand#execute(Model model)` methods are called. These methods will update the filtered property list in the `model` which will eventually update the properties shown in the UI, and return a `CommandResult` object. -During this execution process, a new `PriceAndTagsInRangePredicate` object which is used as a predicate to check whether a property's price is lower and if the property has all the characteristics. +During this execution process, a new `PriceAndTagsInRangePredicate` object which is used as a predicate to check whether a property's budget is lower and if the property has all the characteristics. All properties will be tested using this `PriceAndTagsInRangePredicate`. Properties which satisfy this condition will be included into the `FilteredPropertyList` in the model. #### Design Considerations @@ -576,7 +576,7 @@ System: PropertyMatch address book Actor: Property Agent -1. Property agent fills in name, address, characteristics, number, price of property +1. Property agent fills in name, address, characteristics, number, budget of property 2. Property agent adds property to address book **Use Case: UC02 - Add customer** diff --git a/docs/UserGuide.md b/docs/UserGuide.md index a5deef2a21a..bc669b8a264 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -67,14 +67,14 @@ PropertyMatch is a desktop application for property agents who want to organise Adds a property to the application. -Format: `addprop n/NAME a/ADDRESS [c/CHARACTERISTIC] ph/number pr/price` +Format: `addprop n/NAME a/ADDRESS [c/CHARACTERISTIC] ph/number pr/budget` Parameter: * `n/NAME` : The propName of the property (String) * `a/ADDRESS` : The propAddress of the property (String) * `c/CHARACTERISTIC` (Optional) : The characteristics of the property (String) * `ph/NUMBER` : The contact number (Integer) -* `pr/PRICE` : The price of the property in psf (Number) +* `pr/PRICE` : The budget of the property in psf (Number) Examples: @@ -89,7 +89,7 @@ When command fails: * `Missing propName parameter for add properties command` for missing propName parameter * `Missing propAddress parameter for add properties command` for missing propAddress parameter * `Missing number parameter for add properties command` for missing propName parameter -* `Missing price parameter for add properties command` for missing price parameter +* `Missing budget parameter for add properties command` for missing budget parameter * `Invalid Command` for mispelling of command ### Adding a customer: `addcust` @@ -278,7 +278,7 @@ When command fails: Format: `filtercust [pr/PRICE] [c/CHARACTERISTIC]…​` Parameter: -* `pr/PRICE` (optional) : The price of the property (Integer) +* `pr/PRICE` (optional) : The budget of the property (Integer) * `c/CHARACTERISTIC` (optional) : The characteristics of the property (String) Notes: @@ -340,7 +340,7 @@ When command fails: Invalid command for misspelling of command | Action | Format, Examples | |--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **Addprop** | `addprop n/NAME a/ADDRESS [c/CHARACTERISTIC] ph/number pr/price`
e.g., `addprop n/Property a/randomAddress c/bright;sunny;big;square ph/91135235 pr/5` | +| **Addprop** | `addprop n/NAME a/ADDRESS [c/CHARACTERISTIC] ph/number pr/budget`
e.g., `addprop n/Property a/randomAddress c/bright;sunny;big;square ph/91135235 pr/5` | | **Addcust** | `addcust n/NAME p/PHONE e/EMAIL [b/BUDGET] [c/CHARACTERISTIC]`
e.g., `addcust n/Fredy p/12345678 e/fredylawrence@gmail.com b/100000` | | **Delprop** | `delprop INDEX`
e.g., `delprop 3` | | **Delcust** | `delcust INDEX`
e.g., `delcust 3` | diff --git a/src/main/java/seedu/address/logic/commands/FilterCustomerCommand.java b/src/main/java/seedu/address/logic/commands/FilterCustomerCommand.java index 09717ebebfd..23fb6416221 100644 --- a/src/main/java/seedu/address/logic/commands/FilterCustomerCommand.java +++ b/src/main/java/seedu/address/logic/commands/FilterCustomerCommand.java @@ -4,11 +4,20 @@ import static seedu.address.logic.parser.CliSyntax.PREFIX_BUDGET; import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +import seedu.address.commons.util.CollectionUtil; import seedu.address.commons.util.ToStringBuilder; import seedu.address.logic.Messages; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; +import seedu.address.model.customer.Budget; import seedu.address.model.customer.BudgetAndTagsInRangePredicate; +import seedu.address.model.tag.Tag; /** * Filter all customers in the address book to the user based on specific tags and/or budget. @@ -63,4 +72,82 @@ public String toString() { .add("predicate", predicate) .toString(); } + + /** + * Stores the details to filter the customer with budget and tags. + */ + public static class FilterCustomerDescriptor { + private Budget budget; + private Set tags; + + public FilterCustomerDescriptor() {} + + /** + * Copy constructor. + * A defensive copy of {@code tags} is used internally. + */ + public FilterCustomerDescriptor(FilterCustomerDescriptor toCopy) { + setBudget(toCopy.budget); + setTags(toCopy.tags); + } + + /** + * Returns true if at least one field is edited. + */ + public boolean isAnyFieldFiltered() { + return CollectionUtil.isAnyNonNull(budget, tags); + } + + public void setBudget(Budget budget) { + this.budget = budget; + } + + public Optional getBudget() { + return Optional.ofNullable(budget); + } + + /** + * Sets {@code tags} to this object's {@code tags}. + * A defensive copy of {@code tags} is used internally. + */ + 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(); + } + + public BudgetAndTagsInRangePredicate getPredicate() { + return new BudgetAndTagsInRangePredicate(budget, tags); + } + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof FilterCustomerDescriptor)) { + return false; + } + + FilterCustomerDescriptor otherFilterPropertyDescriptor = (FilterCustomerDescriptor) other; + return Objects.equals(budget, otherFilterPropertyDescriptor.budget) + && Objects.equals(tags, otherFilterPropertyDescriptor.tags); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .add("budget", budget) + .add("tags", tags) + .toString(); + } + } } diff --git a/src/main/java/seedu/address/logic/commands/FilterPropertyCommand.java b/src/main/java/seedu/address/logic/commands/FilterPropertyCommand.java index dcf317f74b8..4922c78a02f 100644 --- a/src/main/java/seedu/address/logic/commands/FilterPropertyCommand.java +++ b/src/main/java/seedu/address/logic/commands/FilterPropertyCommand.java @@ -77,8 +77,8 @@ public String toString() { * Stores the details to filter the property with price and tags. */ public static class FilterPropertyDescriptor { - private Price price = null; - private Set tags = null; + private Price price; + private Set tags; public FilterPropertyDescriptor() {} diff --git a/src/main/java/seedu/address/logic/parser/FilterCustomerCommandParser.java b/src/main/java/seedu/address/logic/parser/FilterCustomerCommandParser.java index 948600891f8..7162c56bd38 100644 --- a/src/main/java/seedu/address/logic/parser/FilterCustomerCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/FilterCustomerCommandParser.java @@ -1,18 +1,13 @@ package seedu.address.logic.parser; -import static java.util.Objects.isNull; import static java.util.Objects.requireNonNull; 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_TAG; -import java.util.Set; - import seedu.address.logic.commands.FilterCustomerCommand; +import seedu.address.logic.commands.FilterCustomerCommand.FilterCustomerDescriptor; import seedu.address.logic.parser.exceptions.ParseException; -import seedu.address.model.customer.Budget; -import seedu.address.model.customer.BudgetAndTagsInRangePredicate; -import seedu.address.model.tag.Tag; /** * Filters and lists all customers in address book whose budget and/or tags are selected. @@ -26,24 +21,25 @@ public class FilterCustomerCommandParser implements Parser tags; + FilterCustomerDescriptor descriptor = new FilterCustomerDescriptor(); ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_BUDGET, PREFIX_TAG); argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_BUDGET); if (argMultimap.getValue(PREFIX_BUDGET).isPresent()) { - budget = ParserUtil.parseBudget(argMultimap.getValue(PREFIX_BUDGET).get()); + descriptor.setBudget(ParserUtil.parseBudget(argMultimap.getValue(PREFIX_BUDGET).get())); } - tags = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)); + if (argMultimap.getValue(PREFIX_TAG).isPresent()) { + descriptor.setTags(ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG))); + } - if (isNull(budget) && tags.isEmpty()) { + if (!descriptor.isAnyFieldFiltered()) { throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterCustomerCommand.MESSAGE_USAGE)); } - return new FilterCustomerCommand(new BudgetAndTagsInRangePredicate(budget, tags)); + return new FilterCustomerCommand(descriptor.getPredicate()); } } diff --git a/src/main/resources/view/PropertyListCard.fxml b/src/main/resources/view/PropertyListCard.fxml index 103dce8e6dc..b77c0f1fac5 100644 --- a/src/main/resources/view/PropertyListCard.fxml +++ b/src/main/resources/view/PropertyListCard.fxml @@ -30,7 +30,7 @@