Skip to content

Commit 37c8238

Browse files
authored
Merge pull request nus-cs2103-AY2324S1#117 from FerdiHS/add-filter-customer-descriptor
Add FilterCustomerDescriptor
2 parents 160b0e2 + 5c94294 commit 37c8238

File tree

13 files changed

+278
-32
lines changed

13 files changed

+278
-32
lines changed

docs/DeveloperGuide.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ This section describes some noteworthy details on how certain features are imple
159159

160160
#### Motivation
161161
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.
162-
Or, the property agent may want to change the price of a property after adding it to PropertyMatch.
162+
Or, the property agent may want to change the budget of a property after adding it to PropertyMatch.
163163

164164
#### Implementation
165165
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
301301
[Back to top](#table-of-contents)
302302

303303
#### Motivation
304-
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.
304+
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.
305305
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.
306-
Or, the property agent may want to see a list of properties based on both price and characteristics to enhance productivity.
306+
Or, the property agent may want to see a list of properties based on both budget and characteristics to enhance productivity.
307307

308308
#### Implementation
309309
The `FilterPropertyCommand` class extends the `Command` class. They are used to filter properties.
310-
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.
310+
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.
311311
When the filter command is inputted, the `FilterPropertyCommandParser` class is used to parse the user input and create the respective `FilterPropertyCommand` objects.
312312
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.
313313

314-
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.
314+
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.
315315
All properties will be tested using this `PriceAndTagsInRangePredicate`. Properties which satisfy this condition will be included into the `FilteredPropertyList` in the model.
316316

317317
#### Design Considerations
@@ -576,7 +576,7 @@ System: PropertyMatch address book
576576

577577
Actor: Property Agent
578578

579-
1. Property agent fills in name, address, characteristics, number, price of property
579+
1. Property agent fills in name, address, characteristics, number, budget of property
580580
2. Property agent adds property to address book
581581

582582
**Use Case: UC02 - Add customer**

docs/UserGuide.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,14 @@ PropertyMatch is a desktop application for property agents who want to organise
6767

6868
Adds a property to the application.
6969

70-
Format: `addprop n/NAME a/ADDRESS [c/CHARACTERISTIC] ph/number pr/price`
70+
Format: `addprop n/NAME a/ADDRESS [c/CHARACTERISTIC] ph/number pr/budget`
7171

7272
Parameter:
7373
* `n/NAME` : The propName of the property (String)
7474
* `a/ADDRESS` : The propAddress of the property (String)
7575
* `c/CHARACTERISTIC` (Optional) : The characteristics of the property (String)
7676
* `ph/NUMBER` : The contact number (Integer)
77-
* `pr/PRICE` : The price of the property in psf (Number)
77+
* `pr/PRICE` : The budget of the property in psf (Number)
7878

7979

8080
Examples:
@@ -89,7 +89,7 @@ When command fails:
8989
* `Missing propName parameter for add properties command` for missing propName parameter
9090
* `Missing propAddress parameter for add properties command` for missing propAddress parameter
9191
* `Missing number parameter for add properties command` for missing propName parameter
92-
* `Missing price parameter for add properties command` for missing price parameter
92+
* `Missing budget parameter for add properties command` for missing budget parameter
9393
* `Invalid Command` for mispelling of command
9494

9595
### Adding a customer: `addcust`
@@ -278,7 +278,7 @@ When command fails:
278278
Format: `filtercust [pr/PRICE] [c/CHARACTERISTIC]…​`
279279

280280
Parameter:
281-
* `pr/PRICE` (optional) : The price of the property (Integer)
281+
* `pr/PRICE` (optional) : The budget of the property (Integer)
282282
* `c/CHARACTERISTIC` (optional) : The characteristics of the property (String)
283283

284284
Notes:
@@ -340,7 +340,7 @@ When command fails: Invalid command for misspelling of command
340340

341341
| Action | Format, Examples |
342342
|--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
343-
| **Addprop** | `addprop n/NAME a/ADDRESS [c/CHARACTERISTIC] ph/number pr/price` <br> e.g., `addprop n/Property a/randomAddress c/bright;sunny;big;square ph/91135235 pr/5` |
343+
| **Addprop** | `addprop n/NAME a/ADDRESS [c/CHARACTERISTIC] ph/number pr/budget` <br> e.g., `addprop n/Property a/randomAddress c/bright;sunny;big;square ph/91135235 pr/5` |
344344
| **Addcust** | `addcust n/NAME p/PHONE e/EMAIL [b/BUDGET] [c/CHARACTERISTIC]` <br> e.g., `addcust n/Fredy p/12345678 e/[email protected] b/100000` |
345345
| **Delprop** | `delprop INDEX`<br> e.g., `delprop 3` |
346346
| **Delcust** | `delcust INDEX`<br> e.g., `delcust 3` |

docs/diagrams/FilterCustomerSequenceDiagram.puml

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
77
participant ":FilterCustomerCommandParser" as FilterCustomerCommandParser LOGIC_COLOR
88
participant ":Budget" as Budget LOGIC_COLOR
99
participant ":Tag" as Tag LOGIC_COLOR
10+
participant "descriptor:FilterCustomerDescriptor" as FilterCustomerDescriptor LOGIC_COLOR
1011
participant ":BudgetAndTagsInRangePredicate" as BudgetAndTagsInRangePredicate LOGIC_COLOR
1112
participant "command:FilterCustomerCommand" as FilterCustomerCommand LOGIC_COLOR
1213
participant ":CommandResult" as CommandResult LOGIC_COLOR
@@ -32,27 +33,48 @@ deactivate FilterCustomerCommandParser
3233
AddressBookParser -> FilterCustomerCommandParser : parse("b/100000 c/pink")
3334
activate FilterCustomerCommandParser
3435

36+
create FilterCustomerDescriptor
37+
FilterCustomerCommandParser -> FilterCustomerDescriptor: new FilterCustomerDescriptor
38+
activate FilterCustomerDescriptor
39+
40+
FilterCustomerDescriptor --> FilterCustomerCommandParser: descriptor
41+
deactivate FilterCustomerDescriptor
42+
3543
create Budget
3644
FilterCustomerCommandParser -> Budget: new Budget(100000)
3745
activate Budget
3846

3947
Budget --> FilterCustomerCommandParser: budget
4048
deactivate Budget
4149

50+
FilterCustomerCommandParser -> FilterCustomerDescriptor: setBudget(budget)
51+
activate FilterCustomerDescriptor
52+
deactivate FilterCustomerDescriptor
53+
4254
create Tag
4355
FilterCustomerCommandParser -> Tag: new Tag("pink")
4456
activate Tag
4557

4658
Tag --> FilterCustomerCommandParser: tag
4759
deactivate Tag
4860

61+
FilterCustomerCommandParser -> FilterCustomerDescriptor: setTags(tags)
62+
activate FilterCustomerDescriptor
63+
deactivate FilterCustomerDescriptor
64+
65+
FilterCustomerCommandParser -> FilterCustomerDescriptor: getPredicate()
66+
activate FilterCustomerDescriptor
67+
4968
create BudgetAndTagsInRangePredicate
50-
FilterCustomerCommandParser -> BudgetAndTagsInRangePredicate: new BudgetAndTagsInRangePredicate(budget, tags)
69+
FilterCustomerDescriptor -> BudgetAndTagsInRangePredicate: new BudgetAndTagsInRangePredicate(budget, tags)
5170
activate BudgetAndTagsInRangePredicate
5271

53-
BudgetAndTagsInRangePredicate --> FilterCustomerCommandParser: budgetAndTagsInRangePredicate
72+
BudgetAndTagsInRangePredicate --> FilterCustomerDescriptor: budgetAndTagsInRangePredicate
5473
deactivate BudgetAndTagsInRangePredicate
5574

75+
FilterCustomerDescriptor --> FilterCustomerCommandParser: budgetAndTagsInRangePredicate
76+
deactivate FilterCustomerDescriptor
77+
5678
create FilterCustomerCommand
5779
FilterCustomerCommandParser -> FilterCustomerCommand : new FilterCustomerCommand(budgetAndTagsInRangePredicate)
5880
activate FilterCustomerCommand
22.8 KB
Loading

src/main/java/seedu/address/logic/commands/FilterCustomerCommand.java

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,20 @@
44
import static seedu.address.logic.parser.CliSyntax.PREFIX_BUDGET;
55
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
66

7+
import java.util.Collections;
8+
import java.util.HashSet;
9+
import java.util.Objects;
10+
import java.util.Optional;
11+
import java.util.Set;
12+
13+
import seedu.address.commons.util.CollectionUtil;
714
import seedu.address.commons.util.ToStringBuilder;
815
import seedu.address.logic.Messages;
916
import seedu.address.logic.commands.exceptions.CommandException;
1017
import seedu.address.model.Model;
18+
import seedu.address.model.customer.Budget;
1119
import seedu.address.model.customer.BudgetAndTagsInRangePredicate;
20+
import seedu.address.model.tag.Tag;
1221

1322
/**
1423
* Filter all customers in the address book to the user based on specific tags and/or budget.
@@ -63,4 +72,82 @@ public String toString() {
6372
.add("predicate", predicate)
6473
.toString();
6574
}
75+
76+
/**
77+
* Stores the details to filter the customer with budget and tags.
78+
*/
79+
public static class FilterCustomerDescriptor {
80+
private Budget budget;
81+
private Set<Tag> tags;
82+
83+
public FilterCustomerDescriptor() {}
84+
85+
/**
86+
* Copy constructor.
87+
* A defensive copy of {@code tags} is used internally.
88+
*/
89+
public FilterCustomerDescriptor(FilterCustomerDescriptor toCopy) {
90+
setBudget(toCopy.budget);
91+
setTags(toCopy.tags);
92+
}
93+
94+
/**
95+
* Returns true if at least one field is edited.
96+
*/
97+
public boolean isAnyFieldFiltered() {
98+
return CollectionUtil.isAnyNonNull(budget, tags);
99+
}
100+
101+
public void setBudget(Budget budget) {
102+
this.budget = budget;
103+
}
104+
105+
public Optional<Budget> getBudget() {
106+
return Optional.ofNullable(budget);
107+
}
108+
109+
/**
110+
* Sets {@code tags} to this object's {@code tags}.
111+
* A defensive copy of {@code tags} is used internally.
112+
*/
113+
public void setTags(Set<Tag> tags) {
114+
this.tags = (tags != null) ? new HashSet<>(tags) : null;
115+
}
116+
117+
/**
118+
* Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException}
119+
* if modification is attempted.
120+
* Returns {@code Optional#empty()} if {@code tags} is null.
121+
*/
122+
public Optional<Set<Tag>> getTags() {
123+
return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
124+
}
125+
126+
public BudgetAndTagsInRangePredicate getPredicate() {
127+
return new BudgetAndTagsInRangePredicate(budget, tags);
128+
}
129+
@Override
130+
public boolean equals(Object other) {
131+
if (other == this) {
132+
return true;
133+
}
134+
135+
// instanceof handles nulls
136+
if (!(other instanceof FilterCustomerDescriptor)) {
137+
return false;
138+
}
139+
140+
FilterCustomerDescriptor otherFilterPropertyDescriptor = (FilterCustomerDescriptor) other;
141+
return Objects.equals(budget, otherFilterPropertyDescriptor.budget)
142+
&& Objects.equals(tags, otherFilterPropertyDescriptor.tags);
143+
}
144+
145+
@Override
146+
public String toString() {
147+
return new ToStringBuilder(this)
148+
.add("budget", budget)
149+
.add("tags", tags)
150+
.toString();
151+
}
152+
}
66153
}

src/main/java/seedu/address/logic/commands/FilterPropertyCommand.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ public String toString() {
7777
* Stores the details to filter the property with price and tags.
7878
*/
7979
public static class FilterPropertyDescriptor {
80-
private Price price = null;
81-
private Set<Tag> tags = null;
80+
private Price price;
81+
private Set<Tag> tags;
8282

8383
public FilterPropertyDescriptor() {}
8484

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
package seedu.address.logic.parser;
22

3-
import static java.util.Objects.isNull;
43
import static java.util.Objects.requireNonNull;
54
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
65
import static seedu.address.logic.parser.CliSyntax.PREFIX_BUDGET;
76
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
87

9-
import java.util.Set;
10-
118
import seedu.address.logic.commands.FilterCustomerCommand;
9+
import seedu.address.logic.commands.FilterCustomerCommand.FilterCustomerDescriptor;
1210
import seedu.address.logic.parser.exceptions.ParseException;
13-
import seedu.address.model.customer.Budget;
14-
import seedu.address.model.customer.BudgetAndTagsInRangePredicate;
15-
import seedu.address.model.tag.Tag;
1611

1712
/**
1813
* Filters and lists all customers in address book whose budget and/or tags are selected.
@@ -26,24 +21,25 @@ public class FilterCustomerCommandParser implements Parser<FilterCustomerCommand
2621
*/
2722
public FilterCustomerCommand parse(String args) throws ParseException {
2823
requireNonNull(args);
29-
Budget budget = null;
30-
Set<Tag> tags;
24+
FilterCustomerDescriptor descriptor = new FilterCustomerDescriptor();
3125
ArgumentMultimap argMultimap =
3226
ArgumentTokenizer.tokenize(args, PREFIX_BUDGET, PREFIX_TAG);
3327

3428
argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_BUDGET);
3529
if (argMultimap.getValue(PREFIX_BUDGET).isPresent()) {
36-
budget = ParserUtil.parseBudget(argMultimap.getValue(PREFIX_BUDGET).get());
30+
descriptor.setBudget(ParserUtil.parseBudget(argMultimap.getValue(PREFIX_BUDGET).get()));
3731
}
3832

39-
tags = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
33+
if (argMultimap.getValue(PREFIX_TAG).isPresent()) {
34+
descriptor.setTags(ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG)));
35+
}
4036

41-
if (isNull(budget) && tags.isEmpty()) {
37+
if (!descriptor.isAnyFieldFiltered()) {
4238
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
4339
FilterCustomerCommand.MESSAGE_USAGE));
4440
}
4541

46-
return new FilterCustomerCommand(new BudgetAndTagsInRangePredicate(budget, tags));
42+
return new FilterCustomerCommand(descriptor.getPredicate());
4743
}
4844

4945
}

src/main/resources/view/PropertyListCard.fxml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
<FlowPane fx:id="tags" />
3131
<Label fx:id="phone" styleClass="cell_small_label" text="\$propPhone" />
3232
<Label fx:id="address" styleClass="cell_small_label" text="\$propAddress" />
33-
<Label fx:id="price" styleClass="cell_small_label" text="\$price" />
33+
<Label fx:id="budget" styleClass="cell_small_label" text="\$budget" />
3434
</VBox>
3535
</GridPane>
3636
</HBox>

src/test/java/seedu/address/logic/commands/CommandTestUtil.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
import java.util.List;
1717

1818
import seedu.address.commons.core.index.Index;
19+
import seedu.address.logic.commands.EditCustomerCommand.EditCustomerDescriptor;
20+
import seedu.address.logic.commands.FilterCustomerCommand.FilterCustomerDescriptor;
1921
import seedu.address.logic.commands.FilterPropertyCommand.FilterPropertyDescriptor;
2022
import seedu.address.logic.commands.exceptions.CommandException;
2123
import seedu.address.model.AddressBook;
2224
import seedu.address.model.Model;
2325
import seedu.address.model.customer.Customer;
2426
import seedu.address.model.customer.NameContainsKeywordsPredicate;
2527
import seedu.address.testutil.EditCustomerDescriptorBuilder;
28+
import seedu.address.testutil.FilterCustomerDescriptorBuilder;
2629
import seedu.address.testutil.FilterPropertyDescriptorBuilder;
2730

2831
/**
@@ -62,8 +65,10 @@ public class CommandTestUtil {
6265
public static final String PREAMBLE_WHITESPACE = "\t \r \n";
6366
public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble";
6467

65-
public static final EditCustomerCommand.EditCustomerDescriptor DESC_AMY;
66-
public static final EditCustomerCommand.EditCustomerDescriptor DESC_BOB;
68+
public static final EditCustomerDescriptor DESC_AMY;
69+
public static final EditCustomerDescriptor DESC_BOB;
70+
public static final FilterCustomerDescriptor FILTER_CUSTOMER_DESCRIPTOR_AMY;
71+
public static final FilterCustomerDescriptor FILTER_CUSTOMER_DESCRIPTOR_BOB;
6772

6873
static {
6974
DESC_AMY = new EditCustomerDescriptorBuilder().withName(VALID_NAME_AMY)
@@ -72,6 +77,10 @@ public class CommandTestUtil {
7277
DESC_BOB = new EditCustomerDescriptorBuilder().withName(VALID_NAME_BOB)
7378
.withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB).withBudget(VALID_BUDGET_BOB)
7479
.withTags(VALID_TAG_BIG, VALID_TAG_SQUARE).build();
80+
FILTER_CUSTOMER_DESCRIPTOR_AMY = new FilterCustomerDescriptorBuilder().withBudget(VALID_BUDGET_AMY)
81+
.withTags(VALID_TAG_SQUARE).build();
82+
FILTER_CUSTOMER_DESCRIPTOR_BOB = new FilterCustomerDescriptorBuilder().withBudget(VALID_BUDGET_BOB)
83+
.withTags(VALID_TAG_BIG, VALID_TAG_SQUARE).build();
7584
}
7685

7786
// Properties

src/test/java/seedu/address/logic/commands/FilterCustomerCommandTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,27 @@ public void execute_withBudgetSomeTags_customerFound() {
260260
assertEquals(Arrays.asList(BENSON), model.getFilteredCustomerList());
261261
}
262262

263+
@Test
264+
public void toStringMethod() {
265+
String firstTagString = "square";
266+
String secondTagString = "garden";
267+
268+
Tag firstTag = new Tag(firstTagString);
269+
Tag secondTag = new Tag(secondTagString);
270+
271+
Set<Tag> tags = new HashSet<>();
272+
tags.add(firstTag);
273+
tags.add(secondTag);
274+
275+
String budgetString = "100000000";
276+
Budget budget = new Budget(budgetString);
277+
278+
BudgetAndTagsInRangePredicate predicate = new BudgetAndTagsInRangePredicate(budget, tags);
279+
FilterCustomerCommand filterCustomerCommand = new FilterCustomerCommand(predicate);
280+
String expected = FilterCustomerCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
281+
assertEquals(expected, filterCustomerCommand.toString());
282+
}
283+
263284
private FilterCustomerCommand preparePredicate(String message) {
264285
try {
265286
return (new FilterCustomerCommandParser()).parse(message);

0 commit comments

Comments
 (0)