From c7bff25d91352d31bd36be1cd36d30a39898e1db Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Mon, 1 Nov 2021 23:59:09 +0800 Subject: [PATCH 01/74] Refactor sort command --- .../address/logic/commands/SortOrdersCommand.java | 15 +++++---------- .../logic/parser/SortOrdersCommandParser.java | 6 +++++- .../seedu/address/model/sort/SortDescriptor.java | 6 ++++++ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/main/java/seedu/address/logic/commands/SortOrdersCommand.java b/src/main/java/seedu/address/logic/commands/SortOrdersCommand.java index f8f59cb80e7..546135c42ca 100644 --- a/src/main/java/seedu/address/logic/commands/SortOrdersCommand.java +++ b/src/main/java/seedu/address/logic/commands/SortOrdersCommand.java @@ -6,8 +6,6 @@ import seedu.address.model.Model; import seedu.address.model.sort.SortDescriptor; -import seedu.address.model.sort.SortField; -import seedu.address.model.sort.SortOrdering; /** * Sorts orders in the address book based in either ascending or descending order based on the specified field. @@ -27,22 +25,19 @@ public class SortOrdersCommand extends Command { public static final String MESSAGE_SUCCESS = "Sorted all orders"; - private final SortField sortField; - private final SortOrdering sortOrdering; + private final SortDescriptor sortDescriptor; /** - * Creates an SortOrdersCommand to sort the orders by a specified {@code SortField} and {@code SortOrdering} + * Creates an SortOrdersCommand to sort the orders by a specified {@code SortDescriptor}. */ - public SortOrdersCommand(SortField sortField, SortOrdering sortOrdering) { - this.sortField = requireNonNull(sortField); - this.sortOrdering = requireNonNull(sortOrdering); + public SortOrdersCommand(SortDescriptor sortDescriptor) { + this.sortDescriptor = requireNonNull(sortDescriptor); } @Override public CommandResult execute(Model model) { requireNonNull(model); - SortDescriptor sortDescriptor = new SortDescriptor(sortField, sortOrdering); model.sortOrderList(sortDescriptor); return new CommandResult(MESSAGE_SUCCESS, CommandResult.DisplayState.ORDER); } @@ -62,7 +57,7 @@ public boolean equals(Object other) { // state check SortOrdersCommand e = (SortOrdersCommand) other; - return sortField.equals(e.sortField) && sortOrdering.equals(e.sortOrdering); + return sortDescriptor.equals(e.sortDescriptor); } } diff --git a/src/main/java/seedu/address/logic/parser/SortOrdersCommandParser.java b/src/main/java/seedu/address/logic/parser/SortOrdersCommandParser.java index b2f46c0b4f2..59a829f8291 100644 --- a/src/main/java/seedu/address/logic/parser/SortOrdersCommandParser.java +++ b/src/main/java/seedu/address/logic/parser/SortOrdersCommandParser.java @@ -8,6 +8,7 @@ import seedu.address.logic.commands.SortOrdersCommand; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.sort.SortDescriptor; import seedu.address.model.sort.SortField; import seedu.address.model.sort.SortOrdering; @@ -30,7 +31,10 @@ public SortOrdersCommand parse(String args) throws ParseException { SortField sortField = ParserUtil.parseSortField(argMultimap.getValue(PREFIX_SORT_FIELD).get()); SortOrdering sortOrdering = ParserUtil.parseSortOrder(argMultimap.getValue(PREFIX_SORT_ORDERING) .orElse("ascending")); - return new SortOrdersCommand(sortField, sortOrdering); + + SortDescriptor sortDescriptor = new SortDescriptor(sortField, sortOrdering); + + return new SortOrdersCommand(sortDescriptor); } /** diff --git a/src/main/java/seedu/address/model/sort/SortDescriptor.java b/src/main/java/seedu/address/model/sort/SortDescriptor.java index 4c29eb30968..c299db52276 100644 --- a/src/main/java/seedu/address/model/sort/SortDescriptor.java +++ b/src/main/java/seedu/address/model/sort/SortDescriptor.java @@ -47,7 +47,13 @@ public Comparator generateComparator() { assert(orderingType.equals(DESCENDING)); return comparator.reversed(); } + } + public SortField getSortField() { + return sortField; } + public SortOrdering getSortOrdering() { + return sortOrdering; + } } From af4418b1784f5a86a6886f32fd11709a83d1c9e0 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Tue, 2 Nov 2021 06:28:49 +0800 Subject: [PATCH 02/74] adding order book storage test case --- .../address/storage/JsonAdaptedOrder.java | 6 +- .../storage/JsonSerializableOrderBook.java | 2 +- .../invalidAndValidOrdersOrderBook.json | 17 +++ .../invalidOrderOrderBook.json | 10 ++ .../notJsonFormatOrderBook.json | 1 + .../duplicateOrdersAddressBook.json | 17 +++ .../invalidOrdersOrderBook.json | 10 ++ .../typicalOrdersOrderBook.json | 25 ++++ .../address/storage/JsonAdapterOrderTest.java | 137 ++++++++++++++++++ .../storage/JsonOrderBookStorageTest.java | 95 ++++++++++++ .../JsonSerializableOrderBookTest.java | 48 ++++++ .../seedu/address/testutil/OrderBuilder.java | 8 + .../seedu/address/testutil/TypicalOrders.java | 4 +- 13 files changed, 374 insertions(+), 6 deletions(-) create mode 100644 src/test/data/JsonOrderBookStorageTest/invalidAndValidOrdersOrderBook.json create mode 100644 src/test/data/JsonOrderBookStorageTest/invalidOrderOrderBook.json create mode 100644 src/test/data/JsonOrderBookStorageTest/notJsonFormatOrderBook.json create mode 100644 src/test/data/JsonSerializableOrderBookTest/duplicateOrdersAddressBook.json create mode 100644 src/test/data/JsonSerializableOrderBookTest/invalidOrdersOrderBook.json create mode 100644 src/test/data/JsonSerializableOrderBookTest/typicalOrdersOrderBook.json create mode 100644 src/test/java/seedu/address/storage/JsonAdapterOrderTest.java create mode 100644 src/test/java/seedu/address/storage/JsonOrderBookStorageTest.java create mode 100644 src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java diff --git a/src/main/java/seedu/address/storage/JsonAdaptedOrder.java b/src/main/java/seedu/address/storage/JsonAdaptedOrder.java index 370122a5b53..d17d1cf4e73 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedOrder.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedOrder.java @@ -45,7 +45,7 @@ public JsonAdaptedOrder(@JsonProperty("id") String id, @JsonProperty("date") Str */ public JsonAdaptedOrder(Order source) { id = String.valueOf(source.getId()); - date = source.getDate().toString(); + date = source.getDate().dateString; amount = source.getAmount().toString(); customer = source.getCustomer().toString(); isComplete = String.valueOf(source.getIsComplete()); @@ -59,7 +59,7 @@ public JsonAdaptedOrder(Order source) { */ public Order toModelType() throws IllegalValueException { if (label == null) { - throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, "label")); + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Label.class.getSimpleName())); } if (!Label.isValidLabel(label)) { throw new IllegalValueException(Label.MESSAGE_CONSTRAINTS); @@ -108,7 +108,7 @@ public Order toModelType() throws IllegalValueException { } else if (isComplete.equals("false")) { // intentionally allow fall through } else { - throw new IllegalValueException("Something is wrong"); + throw new IllegalValueException("isComplete filed is not in the correct format"); } return newOrder; diff --git a/src/main/java/seedu/address/storage/JsonSerializableOrderBook.java b/src/main/java/seedu/address/storage/JsonSerializableOrderBook.java index e5e160257cd..dba02c6036c 100644 --- a/src/main/java/seedu/address/storage/JsonSerializableOrderBook.java +++ b/src/main/java/seedu/address/storage/JsonSerializableOrderBook.java @@ -57,7 +57,7 @@ public OrderBook toModelType() throws IllegalValueException { localCount = order.getId(); } if (idList.contains(order.getId())) { - throw new IllegalValueException("Order Id can not be duplicated"); + throw new IllegalValueException(MESSAGE_DUPLICATE_ORDER); } else { idList.add(order.getId()); } diff --git a/src/test/data/JsonOrderBookStorageTest/invalidAndValidOrdersOrderBook.json b/src/test/data/JsonOrderBookStorageTest/invalidAndValidOrdersOrderBook.json new file mode 100644 index 00000000000..c3157222c48 --- /dev/null +++ b/src/test/data/JsonOrderBookStorageTest/invalidAndValidOrdersOrderBook.json @@ -0,0 +1,17 @@ +{ + "orders" : [ { + "id" : "1", + "date" : "20 Aug 2021", + "amount" : "10.90", + "customer" : "Alice", + "isComplete" : "false", + "label" : "School#####uniform" + }, { + "id" : "2", + "date" : "20 Aug 2021", + "amount" : "10.90", + "customer" : "Alice", + "isComplete" : "false", + "label" : "School uniform" + }] +} diff --git a/src/test/data/JsonOrderBookStorageTest/invalidOrderOrderBook.json b/src/test/data/JsonOrderBookStorageTest/invalidOrderOrderBook.json new file mode 100644 index 00000000000..ac490f52d14 --- /dev/null +++ b/src/test/data/JsonOrderBookStorageTest/invalidOrderOrderBook.json @@ -0,0 +1,10 @@ +{ + "orders" : [ { + "id" : "1", + "date" : "19 Aug 2021", + "amount" : "10.90", + "customer" : "Alice", + "isComplete" : "false", + "label" : "School####uniform" + }] +} diff --git a/src/test/data/JsonOrderBookStorageTest/notJsonFormatOrderBook.json b/src/test/data/JsonOrderBookStorageTest/notJsonFormatOrderBook.json new file mode 100644 index 00000000000..55afc735f01 --- /dev/null +++ b/src/test/data/JsonOrderBookStorageTest/notJsonFormatOrderBook.json @@ -0,0 +1 @@ +not json file order boookkk diff --git a/src/test/data/JsonSerializableOrderBookTest/duplicateOrdersAddressBook.json b/src/test/data/JsonSerializableOrderBookTest/duplicateOrdersAddressBook.json new file mode 100644 index 00000000000..9aa00d884fc --- /dev/null +++ b/src/test/data/JsonSerializableOrderBookTest/duplicateOrdersAddressBook.json @@ -0,0 +1,17 @@ +{ + "orders" : [ { + "id" : "2021", + "date" : "2021-09-18", + "amount" : "10", + "customer" : "Josh", + "isComplete" : "false", + "label" : "Blue Shirt" + }, { + "id" : "2021", + "date" : "2021-09-19", + "amount" : "15", + "customer" : "Mac", + "isComplete" : "true", + "label" : "Blue Shirt" + }] +} diff --git a/src/test/data/JsonSerializableOrderBookTest/invalidOrdersOrderBook.json b/src/test/data/JsonSerializableOrderBookTest/invalidOrdersOrderBook.json new file mode 100644 index 00000000000..979628b3fc6 --- /dev/null +++ b/src/test/data/JsonSerializableOrderBookTest/invalidOrdersOrderBook.json @@ -0,0 +1,10 @@ +{ + "orders" : [ { + "id" : "2021", + "date" : "2021-09-18", + "amount" : "dsfsaf", + "customer" : "Josh", + "isComplete" : "false", + "label" : "Blue Shirt" + }] +} diff --git a/src/test/data/JsonSerializableOrderBookTest/typicalOrdersOrderBook.json b/src/test/data/JsonSerializableOrderBookTest/typicalOrdersOrderBook.json new file mode 100644 index 00000000000..ba313b6c978 --- /dev/null +++ b/src/test/data/JsonSerializableOrderBookTest/typicalOrdersOrderBook.json @@ -0,0 +1,25 @@ +{ + "orders" : [ { + "id" : "2021", + "date" : "2021-09-18", + "amount" : "10", + "customer" : "Josh", + "isComplete" : "false", + "label" : "Blue Shirt" + }, { + "id" : "2022", + "date" : "2021-09-19", + "amount" : "15", + "customer" : "Mac", + "isComplete" : "true", + "label" : "Blue Shirt" + }, { + "id" : "2023", + "date" : "2021-09-20", + "amount" : "20", + "customer" : "Clark", + "isComplete" : "true", + "label" : "Blue Shirt" + } ] +} + diff --git a/src/test/java/seedu/address/storage/JsonAdapterOrderTest.java b/src/test/java/seedu/address/storage/JsonAdapterOrderTest.java new file mode 100644 index 00000000000..03d9a8adcbb --- /dev/null +++ b/src/test/java/seedu/address/storage/JsonAdapterOrderTest.java @@ -0,0 +1,137 @@ +package seedu.address.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.address.storage.JsonAdaptedOrder.MISSING_FIELD_MESSAGE_FORMAT; +import static seedu.address.testutil.Assert.assertThrows; +import static seedu.address.testutil.TypicalOrders.ORDER; + +import org.junit.jupiter.api.Test; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.Date; +import seedu.address.model.Label; +import seedu.address.model.order.Amount; +import seedu.address.model.order.Customer; + + +public class JsonAdapterOrderTest { + private static final String INVALID_LABEL = "TAS$%$#"; + private static final String INVALID_DATE = "28@nextmonth"; + private static final String INVALID_AMOUNT = "not amount"; + private static final String INVALID_CUSTOMER = "ALEX##"; + private static final String INVALID_IS_COMPLETE = "true and false"; + + + private static final String VALID_LABEL = ORDER.getLabel().toString(); + private static final String VALID_DATE = ORDER.getDate().toString(); + private static final String VALID_AMOUNT = ORDER.getAmount().toString(); + private static final String VALID_ID = String.valueOf(ORDER.getId()); + private static final String VALID_CUSTOMER = ORDER.getCustomer().toString(); + private static final String VALID_IS_COMPLETE = String.valueOf(ORDER.getIsComplete()); + + @Test + public void toModelType_validOrderDetails_returnsOrder() throws Exception { + JsonAdaptedOrder order = new JsonAdaptedOrder(ORDER); + assertEquals(ORDER, order.toModelType()); + } + + @Test + public void toModelType_invalidOrderLabel_throwsIllegalValueException() { + JsonAdaptedOrder order = + new JsonAdaptedOrder(VALID_ID, VALID_DATE, VALID_AMOUNT, + VALID_CUSTOMER, VALID_IS_COMPLETE, INVALID_LABEL); + String expectedMessage = Label.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, order::toModelType); + } + + @Test + public void toModelType_nullOrderLabel_throwsIllegalValueException() { + JsonAdaptedOrder order = + new JsonAdaptedOrder(VALID_ID, VALID_DATE, VALID_AMOUNT, + VALID_CUSTOMER, VALID_IS_COMPLETE, null); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Label.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, order::toModelType); + } + + @Test + public void toModelType_invalidOrderDate_throwsIllegalValueException() { + JsonAdaptedOrder order = + new JsonAdaptedOrder(VALID_ID, INVALID_DATE, VALID_AMOUNT, + VALID_CUSTOMER, VALID_IS_COMPLETE, VALID_LABEL); + String expectedMessage = Date.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, order::toModelType); + } + + @Test + public void toModelType_nullDate_throwsIllegalValueException() { + JsonAdaptedOrder order = + new JsonAdaptedOrder(VALID_ID, null, VALID_AMOUNT, + VALID_CUSTOMER, VALID_IS_COMPLETE, VALID_LABEL); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Date.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, order::toModelType); + } + + + @Test + public void toModelType_nullOrderId_throwsIllegalValueException() { + JsonAdaptedOrder order = + new JsonAdaptedOrder(null, VALID_DATE, INVALID_AMOUNT, + VALID_CUSTOMER, VALID_IS_COMPLETE, VALID_LABEL); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, "id"); + assertThrows(IllegalValueException.class, expectedMessage, order::toModelType); + } + + @Test + public void toModelType_invalidAmount_throwsIllegalValueException() { + JsonAdaptedOrder order = + new JsonAdaptedOrder(VALID_ID, VALID_DATE, INVALID_AMOUNT, + VALID_CUSTOMER, VALID_IS_COMPLETE, VALID_LABEL); + String expectedMessage = Amount.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, order::toModelType); + } + + @Test + public void toModelType_nullAmount_throwsIllegalValueException() { + JsonAdaptedOrder order = + new JsonAdaptedOrder(VALID_ID, VALID_DATE, null, + VALID_CUSTOMER, VALID_IS_COMPLETE, VALID_LABEL); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Amount.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, order::toModelType); + } + + @Test + public void toModelType_invalidCustomer_throwsIllegalValueException() { + JsonAdaptedOrder order = + new JsonAdaptedOrder(VALID_ID, VALID_DATE, VALID_AMOUNT, + INVALID_CUSTOMER, VALID_IS_COMPLETE, VALID_LABEL); + String expectedMessage = Customer.MESSAGE_CONSTRAINTS; + assertThrows(IllegalValueException.class, expectedMessage, order::toModelType); + } + + @Test + public void toModelType_nullCustomer_throwsIllegalValueException() { + JsonAdaptedOrder order = + new JsonAdaptedOrder(VALID_ID, VALID_DATE, VALID_AMOUNT, + null, VALID_IS_COMPLETE, VALID_LABEL); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Customer.class.getSimpleName()); + assertThrows(IllegalValueException.class, expectedMessage, order::toModelType); + } + + @Test + public void toModelType_invalidIsComplete_throwsIllegalValueException() { + JsonAdaptedOrder order = + new JsonAdaptedOrder(VALID_ID, VALID_DATE, VALID_AMOUNT, + VALID_CUSTOMER, INVALID_IS_COMPLETE, VALID_LABEL); + String expectedMessage = "isComplete filed is not in the correct format"; + assertThrows(IllegalValueException.class, expectedMessage, order::toModelType); + } + + @Test + public void toModelType_nullIsComplete_throwsIllegalValueException() { + JsonAdaptedOrder order = + new JsonAdaptedOrder(VALID_ID, VALID_DATE, VALID_AMOUNT, + VALID_CUSTOMER, null, VALID_LABEL); + String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, "isComplete"); + assertThrows(IllegalValueException.class, expectedMessage, order::toModelType); + } +} diff --git a/src/test/java/seedu/address/storage/JsonOrderBookStorageTest.java b/src/test/java/seedu/address/storage/JsonOrderBookStorageTest.java new file mode 100644 index 00000000000..e3ba616bbfa --- /dev/null +++ b/src/test/java/seedu/address/storage/JsonOrderBookStorageTest.java @@ -0,0 +1,95 @@ +package seedu.address.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static seedu.address.testutil.Assert.assertThrows; +import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import seedu.address.commons.exceptions.DataConversionException; +import seedu.address.model.OrderBook; +import seedu.address.model.ReadOnlyOrderBook; + + +public class JsonOrderBookStorageTest { + private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonOrderBookStorageTest"); + + @TempDir + public Path testFolder; + + @Test + public void readOrderBook_nullFilePath_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> readOrderBook(null)); + } + + private java.util.Optional readOrderBook(String filePath) throws Exception { + return new JsonOrderBookStorage(Paths.get(filePath)).readOrderBook(addToTestDataPathIfNotNull(filePath)); + } + + private Path addToTestDataPathIfNotNull(String prefsFileInTestDataFolder) { + return prefsFileInTestDataFolder != null + ? TEST_DATA_FOLDER.resolve(prefsFileInTestDataFolder) + : null; + } + + @Test + public void readOrderBook_missingFile_emptyResult() throws Exception { + assertFalse(readOrderBook("NonExistentFile.json").isPresent()); + } + + @Test + public void readOrderBook_notJsonFormat_exceptionThrown() { + assertThrows(DataConversionException.class, () -> readOrderBook("notJsonFormatOrderBook.json")); + } + + @Test + public void readOrderBook_invalidOrderOrderBook_throwDataConversionException() { + assertThrows(DataConversionException.class, () -> readOrderBook("invalidOrderOrderBook.json")); + } + + @Test + public void readOrderBook_invalidAndValidOrdersOderBook_throwDataConversionException() { + assertThrows(DataConversionException.class, () -> readOrderBook("invalidAndValidOrdersOrderBook.json")); + } + + @Test + public void readAndSaveOrderBook_allInOrder_success() throws Exception { + Path filePath = testFolder.resolve("TempOrderBook.json"); + OrderBook original = getTypicalOrderBook(); + JsonOrderBookStorage jsonOrderBookStorage = new JsonOrderBookStorage(filePath); + + // Save in new file and read back + jsonOrderBookStorage.saveOrderBook(original, filePath); + ReadOnlyOrderBook readBack = jsonOrderBookStorage.readOrderBook(filePath).get(); + assertEquals(original, new OrderBook(readBack)); + + } + + @Test + public void saveOrderBook_nullOrderBook_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> saveOrderBook(null, "SomeFile.json")); + } + + /** + * Saves {@code orderBook} at the specified {@code filePath}. + */ + private void saveOrderBook(ReadOnlyOrderBook orderBook, String filePath) { + try { + new JsonOrderBookStorage(Paths.get(filePath)) + .saveOrderBook(orderBook, addToTestDataPathIfNotNull(filePath)); + } catch (IOException ioe) { + throw new AssertionError("There should not be an error writing to the file.", ioe); + } + } + + @Test + public void saveOrderBook_nullFilePath_throwsNullPointerException() { + assertThrows(NullPointerException.class, () -> saveOrderBook(new OrderBook(), null)); + } +} diff --git a/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java b/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java new file mode 100644 index 00000000000..6bbc5019425 --- /dev/null +++ b/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java @@ -0,0 +1,48 @@ +package seedu.address.storage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.address.testutil.Assert.assertThrows; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.jupiter.api.Test; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.commons.util.JsonUtil; +import seedu.address.model.OrderBook; +import seedu.address.testutil.TypicalOrders; + +public class JsonSerializableOrderBookTest { + + private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonSerializableOrderBookTest"); + private static final Path TYPICAL_ORDERS_FILE = TEST_DATA_FOLDER.resolve("typicalOrdersOrderBook.json"); + private static final Path INVALID_ORDERS_FILE = TEST_DATA_FOLDER.resolve("invalidOrdersOrderBook.json"); + private static final Path DUPLICATE_ORDER_FILE = TEST_DATA_FOLDER.resolve("duplicateOrdersAddressBook.json"); + + + @Test + public void toModelType_typicalOrderFile_success() throws Exception { + JsonSerializableOrderBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_ORDERS_FILE, + JsonSerializableOrderBook.class).get(); + OrderBook orderBookBookFromFile = dataFromFile.toModelType(); + OrderBook typicalOrdersOrderBook = TypicalOrders.getTypicalOrderBook(); + assertEquals(orderBookBookFromFile, typicalOrdersOrderBook); + } + + @Test + public void toModelType_invalidOrderFile_throwsIllegalValueException() throws Exception { + JsonSerializableOrderBook dataFromFile = JsonUtil.readJsonFile(INVALID_ORDERS_FILE, + JsonSerializableOrderBook.class).get(); + assertThrows(IllegalValueException.class, dataFromFile::toModelType); + } + + @Test + public void toModelType_duplicatePersons_throwsIllegalValueException() throws Exception { + JsonSerializableOrderBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_ORDER_FILE, + JsonSerializableOrderBook.class).get(); + assertThrows(IllegalValueException.class, JsonSerializableOrderBook.MESSAGE_DUPLICATE_ORDER, + dataFromFile::toModelType); + } + +} diff --git a/src/test/java/seedu/address/testutil/OrderBuilder.java b/src/test/java/seedu/address/testutil/OrderBuilder.java index 069c81224e1..365202fe7e3 100644 --- a/src/test/java/seedu/address/testutil/OrderBuilder.java +++ b/src/test/java/seedu/address/testutil/OrderBuilder.java @@ -78,6 +78,14 @@ public OrderBuilder withIsComplete(boolean isComplete) { return this; } + /** + * Increments the {@code id} of the {@code Order} that we are building. + */ + public OrderBuilder incrementId(long addId) { + this.id += addId; + return this; + } + /** * builds the Order. */ diff --git a/src/test/java/seedu/address/testutil/TypicalOrders.java b/src/test/java/seedu/address/testutil/TypicalOrders.java index a768adb2c13..4ecb8ce0ef8 100644 --- a/src/test/java/seedu/address/testutil/TypicalOrders.java +++ b/src/test/java/seedu/address/testutil/TypicalOrders.java @@ -19,9 +19,9 @@ public class TypicalOrders { public static final Order SALESORDER1 = new OrderBuilder().withCustomer("Josh") .withDate("2021-09-18").withAmount("10").build(); public static final Order SALESORDER2 = new OrderBuilder().withCustomer("Mac") - .withDate("2021-09-19").withAmount("15").withIsComplete(true).build(); + .withDate("2021-09-19").withAmount("15").withIsComplete(true).incrementId(1).build(); public static final Order SALESORDER3 = new OrderBuilder().withCustomer("Clark") - .withDate("2021-09-20").withAmount("20").withIsComplete(true).build(); + .withDate("2021-09-20").withAmount("20").withIsComplete(true).incrementId(2).build(); // Manually added - Order's details found in {@code CommandTestUtil} public static final Order ORDER = new OrderBuilder().withCustomer(VALID_CUSTOMER_SALE1) From a8cd312d1addb7fc97bf8b6079f58c7b820738de Mon Sep 17 00:00:00 2001 From: ngchisern Date: Tue, 2 Nov 2021 13:58:22 +0800 Subject: [PATCH 03/74] Create a PPP skeleton --- docs/team/ngchisern.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/team/ngchisern.md b/docs/team/ngchisern.md index 11dafaf0cee..ee485e29e50 100644 --- a/docs/team/ngchisern.md +++ b/docs/team/ngchisern.md @@ -3,9 +3,9 @@ layout: page title: Chi Sern's Project Portfolio Page --- -### Project: AddressBook Level 3 +### Project: SalesNote -AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC. +SalesNote is a desktop application that helps tailors to manage sales and keep track of a smaller, but more recurrent group of clients. While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). Given below are my contributions to the project. From 3982cb3b81dba52adadf90cf24b208f24c5b5f5b Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Tue, 2 Nov 2021 15:37:04 +0800 Subject: [PATCH 04/74] Add SortOrdersCommandTest --- .../logic/commands/SortOrdersCommandTest.java | 107 ++++++++++++++++++ .../testutil/SortDescriptorBuilder.java | 72 ++++++++++++ .../seedu/address/testutil/TypicalOrders.java | 14 ++- 3 files changed, 187 insertions(+), 6 deletions(-) create mode 100644 src/test/java/seedu/address/logic/commands/SortOrdersCommandTest.java create mode 100644 src/test/java/seedu/address/testutil/SortDescriptorBuilder.java diff --git a/src/test/java/seedu/address/logic/commands/SortOrdersCommandTest.java b/src/test/java/seedu/address/logic/commands/SortOrdersCommandTest.java new file mode 100644 index 00000000000..e780538ce5b --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/SortOrdersCommandTest.java @@ -0,0 +1,107 @@ +package seedu.address.logic.commands; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.testutil.TypicalOrders.SALESORDER1; +import static seedu.address.testutil.TypicalOrders.SALESORDER2; +import static seedu.address.testutil.TypicalOrders.SALESORDER3; +import static seedu.address.testutil.TypicalOrders.SALESORDER4; +import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; +import static seedu.address.testutil.TypicalTasks.getTypicalTaskBook; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.OrderBook; +import seedu.address.model.UserPrefs; +import seedu.address.model.order.Order; +import seedu.address.model.sort.SortDescriptor; +import seedu.address.testutil.SortDescriptorBuilder; + +class SortOrdersCommandTest { + private Model model; + private Model expectedModel; + + private final SortDescriptor dateAsc = new SortDescriptorBuilder().onDateField().inAscendingOrder().build(); + private final SortDescriptor dateDesc = new SortDescriptorBuilder().onDateField().inDescendingOrder().build(); + private final SortDescriptor amountAsc = new SortDescriptorBuilder().onAmountField().inAscendingOrder().build(); + private final SortDescriptor amountDesc = new SortDescriptorBuilder().onAmountField().inDescendingOrder().build(); + + private final SortOrdersCommand sortByDateAsc = new SortOrdersCommand(dateAsc); + private final SortOrdersCommand sortByDateDesc = new SortOrdersCommand(dateDesc); + private final SortOrdersCommand sortByAmountAsc = new SortOrdersCommand(amountAsc); + private final SortOrdersCommand sortByAmountDesc = new SortOrdersCommand(amountDesc); + + @BeforeEach + public void setUp() { + model = new ModelManager(getTypicalAddressBook(), getTypicalTaskBook(), + getTypicalOrderBook(), new UserPrefs()); + expectedModel = new ModelManager(getTypicalAddressBook(), getTypicalTaskBook(), + getTypicalOrderBook(), new UserPrefs()); + } + + @Test + public void execute_filteredList_sortsFilteredList() { + String expectedMessage = amountAsc.generateSuccessMessage(); + + OrderBook sortedOrderBook = new OrderBook(); + List sortedOrdersAmtAsc = + new ArrayList<>(Arrays.asList(SALESORDER1, SALESORDER3, SALESORDER2, SALESORDER4)); + sortedOrderBook.setOrders(sortedOrdersAmtAsc); + expectedModel.setOrderBook(sortedOrderBook); + + model.updateFilteredOrderList(Model.PREDICATE_SHOW_COMPLETED_ORDERS); + expectedModel.updateFilteredOrderList(Model.PREDICATE_SHOW_COMPLETED_ORDERS); + + assertCommandSuccess(sortByAmountAsc, model, expectedMessage, expectedModel); + } + + @Test + public void execute_unsortedList_sortsList() { + String expectedMessage = amountDesc.generateSuccessMessage(); + + List sortedOrdersAmtDesc = + new ArrayList<>(Arrays.asList(SALESORDER2, SALESORDER4, SALESORDER3, SALESORDER1)); + OrderBook sortedOrderBook = new OrderBook(); + sortedOrderBook.setOrders(sortedOrdersAmtDesc); + expectedModel.setOrderBook(sortedOrderBook); + + assertCommandSuccess(sortByAmountDesc, model, expectedMessage, expectedModel); + } + + @Test + public void execute_emptyList_success() { + String expectedMessage = amountDesc.generateSuccessMessage(); + model.setOrderBook(new OrderBook()); + expectedModel.setOrderBook(new OrderBook()); + assertCommandSuccess(sortByAmountDesc, model, expectedMessage, expectedModel); + } + + @Test + public void equals() { + // same object -> returns true + assertTrue(sortByDateAsc.equals(sortByDateAsc)); + + // same values -> returns true + SortOrdersCommand sortByDateAscCommandCopy = new SortOrdersCommand(dateAsc); + assertTrue(sortByDateAsc.equals(sortByDateAscCommandCopy)); + + // different types -> returns false + assertFalse(sortByDateAsc.equals(1)); + + // null -> returns false + assertFalse(sortByDateAsc.equals(null)); + + // different ordering -> returns false + assertFalse(sortByDateAsc.equals(sortByAmountDesc)); + + } +} diff --git a/src/test/java/seedu/address/testutil/SortDescriptorBuilder.java b/src/test/java/seedu/address/testutil/SortDescriptorBuilder.java new file mode 100644 index 00000000000..d7aa61f5dc1 --- /dev/null +++ b/src/test/java/seedu/address/testutil/SortDescriptorBuilder.java @@ -0,0 +1,72 @@ +package seedu.address.testutil; + +import seedu.address.model.sort.SortDescriptor; +import seedu.address.model.sort.SortField; +import seedu.address.model.sort.SortOrdering; + +/** + * A utility class to help with building Sort objects. + */ +public class SortDescriptorBuilder { + public static final SortField DATE_FIELD = new SortField("date"); + public static final SortField AMOUNT_FIELD = new SortField("amount"); + public static final SortOrdering ASC_ORDER = new SortOrdering("ascending"); + public static final SortOrdering DESC_ORDER = new SortOrdering("descending"); + + private SortField sortField; + private SortOrdering sortOrdering; + + + /** + * Creates a {@code SortDescriptorBuilder} with the empty fields. + */ + public SortDescriptorBuilder() { + sortField = null; + sortOrdering = null; + } + + /** + * Initializes the SortDescriptorBuilder with the data of {@code sortDescriptorToCopy}. + */ + public SortDescriptorBuilder(SortDescriptor sortDescriptorToCopy) { + sortField = sortDescriptorToCopy.getSortField(); + sortOrdering = sortDescriptorToCopy.getSortOrdering(); + } + + /** + * Initializes the {@code sortField} of the {@code SortDescriptor} that we are building to {@code DATE_FIELD}. + */ + public SortDescriptorBuilder onDateField() { + this.sortField = DATE_FIELD; + return this; + } + + /** + * Initializes the {@code sortField} of the {@code SortDescriptor} that we are building to {@code AMOUNT_FIELD}. + */ + public SortDescriptorBuilder onAmountField() { + this.sortField = AMOUNT_FIELD; + return this; + } + + /** + * Initializes the {@code SortOrdering} of the {@code SortDescriptor} that we are building to {@code ASC_ORDER}. + */ + public SortDescriptorBuilder inAscendingOrder() { + this.sortOrdering = ASC_ORDER; + return this; + } + + /** + * Initializes the {@code SortOrdering} of the {@code SortDescriptor} that we are building to {@code DESC_ORDER}. + */ + public SortDescriptorBuilder inDescendingOrder() { + this.sortOrdering = DESC_ORDER; + return this; + } + + public SortDescriptor build() { + return new SortDescriptor(sortField, sortOrdering); + } + +} diff --git a/src/test/java/seedu/address/testutil/TypicalOrders.java b/src/test/java/seedu/address/testutil/TypicalOrders.java index a768adb2c13..d2756ef764a 100644 --- a/src/test/java/seedu/address/testutil/TypicalOrders.java +++ b/src/test/java/seedu/address/testutil/TypicalOrders.java @@ -17,11 +17,13 @@ public class TypicalOrders { public static final Order SALESORDER1 = new OrderBuilder().withCustomer("Josh") - .withDate("2021-09-18").withAmount("10").build(); + .withDate("2021-09-18").withAmount("10").withIsComplete(true).build(); public static final Order SALESORDER2 = new OrderBuilder().withCustomer("Mac") - .withDate("2021-09-19").withAmount("15").withIsComplete(true).build(); + .withDate("2021-09-19").withAmount("20").withIsComplete(true).build(); public static final Order SALESORDER3 = new OrderBuilder().withCustomer("Clark") - .withDate("2021-09-20").withAmount("20").withIsComplete(true).build(); + .withDate("2021-09-20").withAmount("15").withIsComplete(true).build(); + public static final Order SALESORDER4 = new OrderBuilder().withCustomer("Justin") + .withDate("2021-09-20").withAmount("20").build(); // Manually added - Order's details found in {@code CommandTestUtil} public static final Order ORDER = new OrderBuilder().withCustomer(VALID_CUSTOMER_SALE1) @@ -34,14 +36,14 @@ public class TypicalOrders { */ public static OrderBook getTypicalOrderBook() { OrderBook sb = new OrderBook(); - for (Order order : getTypicalOrder()) { + for (Order order : getTypicalOrders()) { sb.addOrder(order); } return sb; } - public static List getTypicalOrder() { - return new ArrayList<>(Arrays.asList(SALESORDER1, SALESORDER2, SALESORDER3)); + public static List getTypicalOrders() { + return new ArrayList<>(Arrays.asList(SALESORDER1, SALESORDER2, SALESORDER3, SALESORDER4)); } } From e8cfeab6175e31930f00ffab0c23e71360bbd08c Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Tue, 2 Nov 2021 15:38:15 +0800 Subject: [PATCH 05/74] Sorting a filtered list does not reset the filter --- src/main/java/seedu/address/model/ModelManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 4d5507020a5..b54f3f00a2b 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -282,7 +282,6 @@ public void updateFilteredOrderList(Predicate predicate) { public void sortOrderList(SortDescriptor sortDescriptor) { Comparator comparator = sortDescriptor.generateComparator(); orderBook.sortOrders(comparator); - filteredOrders.setPredicate(PREDICATE_SHOW_ALL_ORDERS); } /** From 17c3e0d961b9afcace21e55c1cb53e6e61dc9373 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Tue, 2 Nov 2021 16:54:10 +0800 Subject: [PATCH 06/74] Use resetOrderView in ModelManager --- src/main/java/seedu/address/model/ModelManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index b54f3f00a2b..719b9520005 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -257,7 +257,7 @@ public void setOrder(Order target, Order editedOrder) { */ public void addOrder(Order toAdd) { orderBook.addOrder(toAdd); - updateFilteredOrderList(PREDICATE_SHOW_ALL_ORDERS); + resetOrderView(); } /** From 9f4f985847dced4739f9a912bd3783ded51b8a3a Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Tue, 2 Nov 2021 16:58:55 +0800 Subject: [PATCH 07/74] Remove fixed id for OrderBuilder --- src/test/java/seedu/address/testutil/OrderBuilder.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/test/java/seedu/address/testutil/OrderBuilder.java b/src/test/java/seedu/address/testutil/OrderBuilder.java index 069c81224e1..b3c0db50dd9 100644 --- a/src/test/java/seedu/address/testutil/OrderBuilder.java +++ b/src/test/java/seedu/address/testutil/OrderBuilder.java @@ -11,16 +11,14 @@ public class OrderBuilder { public static final String DEFAULT_LABEL = "Blue Shirt"; public static final String DEFAULT_CUSTOMER = "Johnson"; public static final String DEFAULT_AMOUNT = "99.99"; - public static final String DEFAULT_DATE = "2021-10-20"; + public static final String DEFAULT_DATE = "2021-11-06"; public static final boolean DEFAULT_IS_COMPLETE = false; - public static final long DEFAULT_ID = 2021; private Label label; private Customer customer; private Amount amount; private Date date; private boolean isComplete; - private long id; /** * Creates a {@code OrderBuilder} with the default details. @@ -31,7 +29,6 @@ public OrderBuilder() { amount = new Amount(DEFAULT_AMOUNT); date = new Date(DEFAULT_DATE); isComplete = DEFAULT_IS_COMPLETE; - id = DEFAULT_ID; } /** @@ -43,7 +40,6 @@ public OrderBuilder(Order orderToCopy) { amount = orderToCopy.getAmount(); date = orderToCopy.getDate(); isComplete = orderToCopy.getIsComplete(); - id = orderToCopy.getId(); } /** @@ -79,11 +75,10 @@ public OrderBuilder withIsComplete(boolean isComplete) { } /** - * builds the Order. + * Builds the {@code Order}. */ public Order build() { Order order = new Order(label, customer, date, amount); - order.setId(this.id); if (this.isComplete) { order.markCompleted(); } From fd1e31d7fc89973a1b958ae16ad1b03d683818b3 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Tue, 2 Nov 2021 23:31:28 +0800 Subject: [PATCH 08/74] Add IncompleteOrder, CompleteOrder sort tests --- .../commands/ShowCompletedOrdersTest.java | 18 +++++++++++++++++- .../commands/ShowIncompleteOrdersTest.java | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/test/java/seedu/address/logic/commands/ShowCompletedOrdersTest.java b/src/test/java/seedu/address/logic/commands/ShowCompletedOrdersTest.java index efa0f2e2b2d..397134ed7fa 100644 --- a/src/test/java/seedu/address/logic/commands/ShowCompletedOrdersTest.java +++ b/src/test/java/seedu/address/logic/commands/ShowCompletedOrdersTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static seedu.address.commons.core.Messages.MESSAGE_ORDERS_LISTED_OVERVIEW; import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.commands.SortOrdersCommandTest.DATE_DESC; import static seedu.address.model.Model.PREDICATE_SHOW_COMPLETED_ORDERS; import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; @@ -79,7 +80,22 @@ public void execute_typicalOrders_success() { ShowCompletedOrders command = new ShowCompletedOrders(); expectedModel.updateFilteredOrderList(PREDICATE_SHOW_COMPLETED_ORDERS); - String expectedMessage = String.format(MESSAGE_ORDERS_LISTED_OVERVIEW, 2); + String expectedMessage = String.format(MESSAGE_ORDERS_LISTED_OVERVIEW, 3); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + } + + @Test + public void execute_sortedOrders_remainsSorted() { + OrderBook typicalOrderBook = getTypicalOrderBook(); + model.setOrderBook(typicalOrderBook); + expectedModel.setOrderBook(typicalOrderBook); + + model.sortOrderList(DATE_DESC); + expectedModel.sortOrderList(DATE_DESC); + expectedModel.updateFilteredOrderList(PREDICATE_SHOW_COMPLETED_ORDERS); + + ShowCompletedOrders command = new ShowCompletedOrders(); + String expectedMessage = String.format(MESSAGE_ORDERS_LISTED_OVERVIEW, 3); assertCommandSuccess(command, model, expectedMessage, expectedModel); } diff --git a/src/test/java/seedu/address/logic/commands/ShowIncompleteOrdersTest.java b/src/test/java/seedu/address/logic/commands/ShowIncompleteOrdersTest.java index c35fc0e836d..4fe6b5b66e0 100644 --- a/src/test/java/seedu/address/logic/commands/ShowIncompleteOrdersTest.java +++ b/src/test/java/seedu/address/logic/commands/ShowIncompleteOrdersTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static seedu.address.commons.core.Messages.MESSAGE_ORDERS_LISTED_OVERVIEW; import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.commands.SortOrdersCommandTest.DATE_DESC; import static seedu.address.model.Model.PREDICATE_SHOW_INCOMPLETE_ORDERS; import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; @@ -83,5 +84,20 @@ public void execute_typicalOrders_success() { assertCommandSuccess(command, model, expectedMessage, expectedModel); } + @Test + public void execute_sortedOrders_remainsSorted() { + OrderBook typicalOrderBook = getTypicalOrderBook(); + model.setOrderBook(typicalOrderBook); + expectedModel.setOrderBook(typicalOrderBook); + + model.sortOrderList(DATE_DESC); + expectedModel.sortOrderList(DATE_DESC); + expectedModel.updateFilteredOrderList(PREDICATE_SHOW_INCOMPLETE_ORDERS); + + ShowIncompleteOrders command = new ShowIncompleteOrders(); + String expectedMessage = String.format(MESSAGE_ORDERS_LISTED_OVERVIEW, 2); + assertCommandSuccess(command, model, expectedMessage, expectedModel); + } + } From d3deea50c2e6b4b0c787eed40456c3d2a79f7abd Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Tue, 2 Nov 2021 23:32:36 +0800 Subject: [PATCH 09/74] add AddOrder sort test --- .../commands/AddOrderIntegrationTest.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/test/java/seedu/address/logic/commands/AddOrderIntegrationTest.java diff --git a/src/test/java/seedu/address/logic/commands/AddOrderIntegrationTest.java b/src/test/java/seedu/address/logic/commands/AddOrderIntegrationTest.java new file mode 100644 index 00000000000..d8fc0c48220 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/AddOrderIntegrationTest.java @@ -0,0 +1,57 @@ +package seedu.address.logic.commands; + +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.commands.SortOrdersCommandTest.DATE_DESC; +import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; +import static seedu.address.testutil.TypicalTasks.getTypicalTaskBook; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.order.Order; +import seedu.address.testutil.OrderBuilder; + +/** + * Contains integration tests (interaction with the Model) for AddOrderCommand. + */ +public class AddOrderIntegrationTest { + + private Model model; + private Model expectedModel; + + @BeforeEach + public void setUp() { + model = new ModelManager(getTypicalAddressBook(), getTypicalTaskBook(), + getTypicalOrderBook(), new UserPrefs()); + } + + @Test + public void execute_newOrder_success() { + Order validOrder = new OrderBuilder().build(); + expectedModel = new ModelManager(model.getAddressBook(), + model.getTaskBook(), model.getOrderBook(), new UserPrefs()); + + expectedModel.addOrder(validOrder); + + assertCommandSuccess(new AddOrderCommand(validOrder), model, + String.format(AddOrderCommand.MESSAGE_SUCCESS, validOrder), expectedModel); + } + + @Test + public void execute_sortedOrder_defaultOrdering() { + Order validOrder = new OrderBuilder().build(); + Model expectedModel = new ModelManager(getTypicalAddressBook(), getTypicalTaskBook(), + getTypicalOrderBook(), new UserPrefs()); + + expectedModel.addOrder(validOrder); + + model.sortOrderList(DATE_DESC); + + String expectedMessage = String.format(AddOrderCommand.MESSAGE_SUCCESS, validOrder); + assertCommandSuccess(new AddOrderCommand(validOrder), model, expectedMessage, expectedModel); + } +} From ba9ab36330c1edf473f9e647935c3e45bacc64b1 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Tue, 2 Nov 2021 23:33:26 +0800 Subject: [PATCH 10/74] fix SortField, sortOrdering imports --- src/main/java/seedu/address/model/sort/SortField.java | 4 ++-- src/main/java/seedu/address/model/sort/SortOrdering.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/address/model/sort/SortField.java b/src/main/java/seedu/address/model/sort/SortField.java index 413715d7cff..157ac710de7 100644 --- a/src/main/java/seedu/address/model/sort/SortField.java +++ b/src/main/java/seedu/address/model/sort/SortField.java @@ -1,10 +1,10 @@ package seedu.address.model.sort; -import java.util.Locale; - import static java.util.Objects.requireNonNull; import static seedu.address.commons.util.AppUtil.checkArgument; +import java.util.Locale; + enum SortFieldType { DATE, AMOUNT } diff --git a/src/main/java/seedu/address/model/sort/SortOrdering.java b/src/main/java/seedu/address/model/sort/SortOrdering.java index 1afcb37c242..f2f2d479c2c 100644 --- a/src/main/java/seedu/address/model/sort/SortOrdering.java +++ b/src/main/java/seedu/address/model/sort/SortOrdering.java @@ -1,10 +1,10 @@ package seedu.address.model.sort; -import java.util.Locale; - import static java.util.Objects.requireNonNull; import static seedu.address.commons.util.AppUtil.checkArgument; +import java.util.Locale; + enum SortOrderingType { ASCENDING, DESCENDING } From dc030abb82709d00a5744aadbcc9118fc3343cf7 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Tue, 2 Nov 2021 23:49:30 +0800 Subject: [PATCH 11/74] changing something --- .../java/seedu/address/storage/JsonSerializableTaskBookTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/seedu/address/storage/JsonSerializableTaskBookTest.java b/src/test/java/seedu/address/storage/JsonSerializableTaskBookTest.java index 0b473722525..94bc9fc30ca 100644 --- a/src/test/java/seedu/address/storage/JsonSerializableTaskBookTest.java +++ b/src/test/java/seedu/address/storage/JsonSerializableTaskBookTest.java @@ -28,7 +28,6 @@ public void toModelType_typicalTaskFile_success() throws Exception { TaskBook taskBookBookFromFile = dataFromFile.toModelType(); TaskBook typicalTasksTaskBook = TypicalTasks.getTypicalTaskBook(); assertEquals(taskBookBookFromFile, typicalTasksTaskBook); - } @Test From e8021a408c0cc3a144024911ff05a371ff429ff2 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Wed, 3 Nov 2021 00:03:20 +0800 Subject: [PATCH 12/74] Add SALESORDER5 to TypicalOrders --- .../logic/commands/AddTaskCommandTest.java | 10 ++-- .../commands/ShowIncompleteOrdersTest.java | 2 +- .../logic/commands/SortOrdersCommandTest.java | 51 ++++++++++--------- .../testutil/SortDescriptorBuilder.java | 4 +- .../seedu/address/testutil/TypicalOrders.java | 4 +- 5 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/test/java/seedu/address/logic/commands/AddTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/AddTaskCommandTest.java index c6bbc2241a3..1324b8f2ce2 100644 --- a/src/test/java/seedu/address/logic/commands/AddTaskCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/AddTaskCommandTest.java @@ -46,9 +46,11 @@ public void execute_duplicateTask_throwsCommandException() { @Test public void execute_taskWithValidTag_addSuccessful() throws Exception { - Task validTask = new TaskBuilder().withTaskTag("SO2021").build(); //based on default orderid from orderbuilder - AddTaskCommand addTaskCommand = new AddTaskCommand(validTask); - ModelStub modelStub = new ModelStubAcceptingTaskWithOrder(new OrderBuilder().build()); + Order order = new OrderBuilder().build(); + String orderId = "SO" + order.getId(); + ModelStub modelStub = new ModelStubAcceptingTaskWithOrder(order); + + Task validTask = new TaskBuilder().withTaskTag(orderId).build(); CommandResult commandResult = new AddTaskCommand(validTask).execute(modelStub); assertEquals(String.format(AddTaskCommand.MESSAGE_SUCCESS, validTask), commandResult.getFeedbackToUser()); @@ -57,7 +59,7 @@ public void execute_taskWithValidTag_addSuccessful() throws Exception { @Test public void execute_taskDeclinedByModel_throwsCommandException() { - Task validTask = new TaskBuilder().withTaskTag("SO1").build(); + Task validTask = new TaskBuilder().withTaskTag("SO19").build(); //invalid order id AddTaskCommand addTaskCommand = new AddTaskCommand(validTask); ModelStub modelStub = new ModelStubAcceptingTaskWithOrder(new OrderBuilder().build()); diff --git a/src/test/java/seedu/address/logic/commands/ShowIncompleteOrdersTest.java b/src/test/java/seedu/address/logic/commands/ShowIncompleteOrdersTest.java index 4fe6b5b66e0..07283e0cfe8 100644 --- a/src/test/java/seedu/address/logic/commands/ShowIncompleteOrdersTest.java +++ b/src/test/java/seedu/address/logic/commands/ShowIncompleteOrdersTest.java @@ -80,7 +80,7 @@ public void execute_typicalOrders_success() { ShowIncompleteOrders command = new ShowIncompleteOrders(); expectedModel.updateFilteredOrderList(PREDICATE_SHOW_INCOMPLETE_ORDERS); - String expectedMessage = String.format(MESSAGE_ORDERS_LISTED_OVERVIEW, 1); + String expectedMessage = String.format(MESSAGE_ORDERS_LISTED_OVERVIEW, 2); assertCommandSuccess(command, model, expectedMessage, expectedModel); } diff --git a/src/test/java/seedu/address/logic/commands/SortOrdersCommandTest.java b/src/test/java/seedu/address/logic/commands/SortOrdersCommandTest.java index e780538ce5b..a701d2c5add 100644 --- a/src/test/java/seedu/address/logic/commands/SortOrdersCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/SortOrdersCommandTest.java @@ -7,6 +7,7 @@ import static seedu.address.testutil.TypicalOrders.SALESORDER2; import static seedu.address.testutil.TypicalOrders.SALESORDER3; import static seedu.address.testutil.TypicalOrders.SALESORDER4; +import static seedu.address.testutil.TypicalOrders.SALESORDER5; import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; import static seedu.address.testutil.TypicalTasks.getTypicalTaskBook; @@ -26,19 +27,19 @@ import seedu.address.model.sort.SortDescriptor; import seedu.address.testutil.SortDescriptorBuilder; -class SortOrdersCommandTest { - private Model model; - private Model expectedModel; +public class SortOrdersCommandTest { + public static final SortDescriptor DATE_ASC = new SortDescriptorBuilder().onDateField().inAscOrder().build(); + public static final SortDescriptor DATE_DESC = new SortDescriptorBuilder().onDateField().inDescOrder().build(); + public static final SortDescriptor AMOUNT_ASC = new SortDescriptorBuilder().onAmountField().inAscOrder().build(); + public static final SortDescriptor AMOUNT_DESC = new SortDescriptorBuilder().onAmountField().inDescOrder().build(); - private final SortDescriptor dateAsc = new SortDescriptorBuilder().onDateField().inAscendingOrder().build(); - private final SortDescriptor dateDesc = new SortDescriptorBuilder().onDateField().inDescendingOrder().build(); - private final SortDescriptor amountAsc = new SortDescriptorBuilder().onAmountField().inAscendingOrder().build(); - private final SortDescriptor amountDesc = new SortDescriptorBuilder().onAmountField().inDescendingOrder().build(); + public static final SortOrdersCommand SORT_BY_DATE_ASC = new SortOrdersCommand(DATE_ASC); + public static final SortOrdersCommand SORT_BY_DATE_DESC = new SortOrdersCommand(DATE_DESC); + public static final SortOrdersCommand SORT_BY_AMOUNT_ASC = new SortOrdersCommand(AMOUNT_ASC); + public static final SortOrdersCommand SORT_BY_AMOUNT_DESC = new SortOrdersCommand(AMOUNT_DESC); - private final SortOrdersCommand sortByDateAsc = new SortOrdersCommand(dateAsc); - private final SortOrdersCommand sortByDateDesc = new SortOrdersCommand(dateDesc); - private final SortOrdersCommand sortByAmountAsc = new SortOrdersCommand(amountAsc); - private final SortOrdersCommand sortByAmountDesc = new SortOrdersCommand(amountDesc); + private Model model; + private Model expectedModel; @BeforeEach public void setUp() { @@ -50,58 +51,58 @@ public void setUp() { @Test public void execute_filteredList_sortsFilteredList() { - String expectedMessage = amountAsc.generateSuccessMessage(); + String expectedMessage = AMOUNT_ASC.generateSuccessMessage(); OrderBook sortedOrderBook = new OrderBook(); List sortedOrdersAmtAsc = - new ArrayList<>(Arrays.asList(SALESORDER1, SALESORDER3, SALESORDER2, SALESORDER4)); + new ArrayList<>(Arrays.asList(SALESORDER5, SALESORDER1, SALESORDER3, SALESORDER2, SALESORDER4)); sortedOrderBook.setOrders(sortedOrdersAmtAsc); expectedModel.setOrderBook(sortedOrderBook); model.updateFilteredOrderList(Model.PREDICATE_SHOW_COMPLETED_ORDERS); expectedModel.updateFilteredOrderList(Model.PREDICATE_SHOW_COMPLETED_ORDERS); - assertCommandSuccess(sortByAmountAsc, model, expectedMessage, expectedModel); + assertCommandSuccess(SORT_BY_AMOUNT_ASC, model, expectedMessage, expectedModel); } @Test public void execute_unsortedList_sortsList() { - String expectedMessage = amountDesc.generateSuccessMessage(); + String expectedMessage = AMOUNT_DESC.generateSuccessMessage(); List sortedOrdersAmtDesc = - new ArrayList<>(Arrays.asList(SALESORDER2, SALESORDER4, SALESORDER3, SALESORDER1)); + new ArrayList<>(Arrays.asList(SALESORDER2, SALESORDER4, SALESORDER3, SALESORDER1, SALESORDER5)); OrderBook sortedOrderBook = new OrderBook(); sortedOrderBook.setOrders(sortedOrdersAmtDesc); expectedModel.setOrderBook(sortedOrderBook); - assertCommandSuccess(sortByAmountDesc, model, expectedMessage, expectedModel); + assertCommandSuccess(SORT_BY_AMOUNT_DESC, model, expectedMessage, expectedModel); } @Test public void execute_emptyList_success() { - String expectedMessage = amountDesc.generateSuccessMessage(); + String expectedMessage = AMOUNT_DESC.generateSuccessMessage(); model.setOrderBook(new OrderBook()); expectedModel.setOrderBook(new OrderBook()); - assertCommandSuccess(sortByAmountDesc, model, expectedMessage, expectedModel); + assertCommandSuccess(SORT_BY_AMOUNT_DESC, model, expectedMessage, expectedModel); } @Test public void equals() { // same object -> returns true - assertTrue(sortByDateAsc.equals(sortByDateAsc)); + assertTrue(SORT_BY_DATE_ASC.equals(SORT_BY_DATE_ASC)); // same values -> returns true - SortOrdersCommand sortByDateAscCommandCopy = new SortOrdersCommand(dateAsc); - assertTrue(sortByDateAsc.equals(sortByDateAscCommandCopy)); + SortOrdersCommand sortByDateAscCommandCopy = new SortOrdersCommand(DATE_ASC); + assertTrue(SORT_BY_DATE_ASC.equals(sortByDateAscCommandCopy)); // different types -> returns false - assertFalse(sortByDateAsc.equals(1)); + assertFalse(SORT_BY_DATE_ASC.equals(1)); // null -> returns false - assertFalse(sortByDateAsc.equals(null)); + assertFalse(SORT_BY_DATE_ASC.equals(null)); // different ordering -> returns false - assertFalse(sortByDateAsc.equals(sortByAmountDesc)); + assertFalse(SORT_BY_DATE_ASC.equals(SORT_BY_AMOUNT_DESC)); } } diff --git a/src/test/java/seedu/address/testutil/SortDescriptorBuilder.java b/src/test/java/seedu/address/testutil/SortDescriptorBuilder.java index d7aa61f5dc1..e9b07f1b498 100644 --- a/src/test/java/seedu/address/testutil/SortDescriptorBuilder.java +++ b/src/test/java/seedu/address/testutil/SortDescriptorBuilder.java @@ -52,7 +52,7 @@ public SortDescriptorBuilder onAmountField() { /** * Initializes the {@code SortOrdering} of the {@code SortDescriptor} that we are building to {@code ASC_ORDER}. */ - public SortDescriptorBuilder inAscendingOrder() { + public SortDescriptorBuilder inAscOrder() { this.sortOrdering = ASC_ORDER; return this; } @@ -60,7 +60,7 @@ public SortDescriptorBuilder inAscendingOrder() { /** * Initializes the {@code SortOrdering} of the {@code SortDescriptor} that we are building to {@code DESC_ORDER}. */ - public SortDescriptorBuilder inDescendingOrder() { + public SortDescriptorBuilder inDescOrder() { this.sortOrdering = DESC_ORDER; return this; } diff --git a/src/test/java/seedu/address/testutil/TypicalOrders.java b/src/test/java/seedu/address/testutil/TypicalOrders.java index d2756ef764a..4255f8ab91c 100644 --- a/src/test/java/seedu/address/testutil/TypicalOrders.java +++ b/src/test/java/seedu/address/testutil/TypicalOrders.java @@ -24,6 +24,8 @@ public class TypicalOrders { .withDate("2021-09-20").withAmount("15").withIsComplete(true).build(); public static final Order SALESORDER4 = new OrderBuilder().withCustomer("Justin") .withDate("2021-09-20").withAmount("20").build(); + public static final Order SALESORDER5 = new OrderBuilder().withCustomer("Stuart") + .withDate("2021-09-20").withAmount("5").withIsComplete(false).build(); // Manually added - Order's details found in {@code CommandTestUtil} public static final Order ORDER = new OrderBuilder().withCustomer(VALID_CUSTOMER_SALE1) @@ -43,7 +45,7 @@ public static OrderBook getTypicalOrderBook() { } public static List getTypicalOrders() { - return new ArrayList<>(Arrays.asList(SALESORDER1, SALESORDER2, SALESORDER3, SALESORDER4)); + return new ArrayList<>(Arrays.asList(SALESORDER1, SALESORDER2, SALESORDER3, SALESORDER4, SALESORDER5)); } } From 34f7f631c1545994276b00d3fe7aa31fddb9961e Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Wed, 3 Nov 2021 00:09:53 +0800 Subject: [PATCH 13/74] fixing based on comments --- .../seedu/address/storage/JsonAdaptedOrder.java | 2 +- .../address/storage/JsonAdapterOrderTest.java | 2 +- .../storage/JsonSerializableOrderBookTest.java | 2 +- .../java/seedu/address/testutil/OrderBuilder.java | 14 +++++++++++--- .../java/seedu/address/testutil/TypicalOrders.java | 4 ++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/address/storage/JsonAdaptedOrder.java b/src/main/java/seedu/address/storage/JsonAdaptedOrder.java index d17d1cf4e73..f5b0777d3c8 100644 --- a/src/main/java/seedu/address/storage/JsonAdaptedOrder.java +++ b/src/main/java/seedu/address/storage/JsonAdaptedOrder.java @@ -108,7 +108,7 @@ public Order toModelType() throws IllegalValueException { } else if (isComplete.equals("false")) { // intentionally allow fall through } else { - throw new IllegalValueException("isComplete filed is not in the correct format"); + throw new IllegalValueException("isComplete field is not in the correct format"); } return newOrder; diff --git a/src/test/java/seedu/address/storage/JsonAdapterOrderTest.java b/src/test/java/seedu/address/storage/JsonAdapterOrderTest.java index 03d9a8adcbb..23a32bc01ec 100644 --- a/src/test/java/seedu/address/storage/JsonAdapterOrderTest.java +++ b/src/test/java/seedu/address/storage/JsonAdapterOrderTest.java @@ -122,7 +122,7 @@ public void toModelType_invalidIsComplete_throwsIllegalValueException() { JsonAdaptedOrder order = new JsonAdaptedOrder(VALID_ID, VALID_DATE, VALID_AMOUNT, VALID_CUSTOMER, INVALID_IS_COMPLETE, VALID_LABEL); - String expectedMessage = "isComplete filed is not in the correct format"; + String expectedMessage = "isComplete field is not in the correct format"; assertThrows(IllegalValueException.class, expectedMessage, order::toModelType); } diff --git a/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java b/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java index 6bbc5019425..0754f53a98e 100644 --- a/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java +++ b/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java @@ -38,7 +38,7 @@ public void toModelType_invalidOrderFile_throwsIllegalValueException() throws Ex } @Test - public void toModelType_duplicatePersons_throwsIllegalValueException() throws Exception { + public void toModelType_duplicateOrders_throwsIllegalValueException() throws Exception { JsonSerializableOrderBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_ORDER_FILE, JsonSerializableOrderBook.class).get(); assertThrows(IllegalValueException.class, JsonSerializableOrderBook.MESSAGE_DUPLICATE_ORDER, diff --git a/src/test/java/seedu/address/testutil/OrderBuilder.java b/src/test/java/seedu/address/testutil/OrderBuilder.java index 365202fe7e3..6918e8d5e71 100644 --- a/src/test/java/seedu/address/testutil/OrderBuilder.java +++ b/src/test/java/seedu/address/testutil/OrderBuilder.java @@ -79,10 +79,18 @@ public OrderBuilder withIsComplete(boolean isComplete) { } /** - * Increments the {@code id} of the {@code Order} that we are building. + * Sets the {@code Label} of the {@code Order} that we are building. */ - public OrderBuilder incrementId(long addId) { - this.id += addId; + public OrderBuilder withLabel(String label) { + this.label = new Label(label); + return this; + } + + /** + * Sets the {@code id} of the {@code Order} that we are building. + */ + public OrderBuilder withId(long id) { + this.id = id; return this; } diff --git a/src/test/java/seedu/address/testutil/TypicalOrders.java b/src/test/java/seedu/address/testutil/TypicalOrders.java index 4ecb8ce0ef8..748d7c0d3d4 100644 --- a/src/test/java/seedu/address/testutil/TypicalOrders.java +++ b/src/test/java/seedu/address/testutil/TypicalOrders.java @@ -19,9 +19,9 @@ public class TypicalOrders { public static final Order SALESORDER1 = new OrderBuilder().withCustomer("Josh") .withDate("2021-09-18").withAmount("10").build(); public static final Order SALESORDER2 = new OrderBuilder().withCustomer("Mac") - .withDate("2021-09-19").withAmount("15").withIsComplete(true).incrementId(1).build(); + .withDate("2021-09-19").withAmount("15").withIsComplete(true).withId(2022).build(); public static final Order SALESORDER3 = new OrderBuilder().withCustomer("Clark") - .withDate("2021-09-20").withAmount("20").withIsComplete(true).incrementId(2).build(); + .withDate("2021-09-20").withAmount("20").withIsComplete(true).withId(2023).build(); // Manually added - Order's details found in {@code CommandTestUtil} public static final Order ORDER = new OrderBuilder().withCustomer(VALID_CUSTOMER_SALE1) From 0f991b8200659b724abae9631cac7934ecc49ff4 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Wed, 3 Nov 2021 00:17:10 +0800 Subject: [PATCH 14/74] fixing the json file and resolving the conflict --- .../typicalOrdersOrderBook.json | 12 ++++++------ .../java/seedu/address/testutil/TypicalOrders.java | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/test/data/JsonSerializableOrderBookTest/typicalOrdersOrderBook.json b/src/test/data/JsonSerializableOrderBookTest/typicalOrdersOrderBook.json index ba313b6c978..27ecc67f838 100644 --- a/src/test/data/JsonSerializableOrderBookTest/typicalOrdersOrderBook.json +++ b/src/test/data/JsonSerializableOrderBookTest/typicalOrdersOrderBook.json @@ -1,25 +1,25 @@ { "orders" : [ { - "id" : "2021", + "id" : "1", "date" : "2021-09-18", "amount" : "10", "customer" : "Josh", "isComplete" : "false", - "label" : "Blue Shirt" + "label" : "testorder1" }, { - "id" : "2022", + "id" : "2", "date" : "2021-09-19", "amount" : "15", "customer" : "Mac", "isComplete" : "true", - "label" : "Blue Shirt" + "label" : "testorder2" }, { - "id" : "2023", + "id" : "3", "date" : "2021-09-20", "amount" : "20", "customer" : "Clark", "isComplete" : "true", - "label" : "Blue Shirt" + "label" : "testorder3" } ] } diff --git a/src/test/java/seedu/address/testutil/TypicalOrders.java b/src/test/java/seedu/address/testutil/TypicalOrders.java index 748d7c0d3d4..8ad9dcea9b6 100644 --- a/src/test/java/seedu/address/testutil/TypicalOrders.java +++ b/src/test/java/seedu/address/testutil/TypicalOrders.java @@ -17,11 +17,11 @@ public class TypicalOrders { public static final Order SALESORDER1 = new OrderBuilder().withCustomer("Josh") - .withDate("2021-09-18").withAmount("10").build(); + .withDate("2021-09-18").withAmount("10").withLabel("testorder1").withId(1).build(); public static final Order SALESORDER2 = new OrderBuilder().withCustomer("Mac") - .withDate("2021-09-19").withAmount("15").withIsComplete(true).withId(2022).build(); + .withDate("2021-09-19").withAmount("15").withIsComplete(true).withId(2).withLabel("testorder2").build(); public static final Order SALESORDER3 = new OrderBuilder().withCustomer("Clark") - .withDate("2021-09-20").withAmount("20").withIsComplete(true).withId(2023).build(); + .withDate("2021-09-20").withAmount("20").withIsComplete(true).withId(3).withLabel("testorder3").build(); // Manually added - Order's details found in {@code CommandTestUtil} public static final Order ORDER = new OrderBuilder().withCustomer(VALID_CUSTOMER_SALE1) From 6296c8a33599f9b7f00fac5f3644bddf675bb0c9 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Wed, 3 Nov 2021 00:23:32 +0800 Subject: [PATCH 15/74] fixing small errors --- .../address/storage/JsonAdapterOrderTest.java | 18 +++++++++--------- .../seedu/address/testutil/TypicalOrders.java | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/java/seedu/address/storage/JsonAdapterOrderTest.java b/src/test/java/seedu/address/storage/JsonAdapterOrderTest.java index 23a32bc01ec..f939c61c29d 100644 --- a/src/test/java/seedu/address/storage/JsonAdapterOrderTest.java +++ b/src/test/java/seedu/address/storage/JsonAdapterOrderTest.java @@ -3,7 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static seedu.address.storage.JsonAdaptedOrder.MISSING_FIELD_MESSAGE_FORMAT; import static seedu.address.testutil.Assert.assertThrows; -import static seedu.address.testutil.TypicalOrders.ORDER; +import static seedu.address.testutil.TypicalOrders.ORDER1; import org.junit.jupiter.api.Test; @@ -22,17 +22,17 @@ public class JsonAdapterOrderTest { private static final String INVALID_IS_COMPLETE = "true and false"; - private static final String VALID_LABEL = ORDER.getLabel().toString(); - private static final String VALID_DATE = ORDER.getDate().toString(); - private static final String VALID_AMOUNT = ORDER.getAmount().toString(); - private static final String VALID_ID = String.valueOf(ORDER.getId()); - private static final String VALID_CUSTOMER = ORDER.getCustomer().toString(); - private static final String VALID_IS_COMPLETE = String.valueOf(ORDER.getIsComplete()); + private static final String VALID_LABEL = ORDER1.getLabel().toString(); + private static final String VALID_DATE = ORDER1.getDate().toString(); + private static final String VALID_AMOUNT = ORDER1.getAmount().toString(); + private static final String VALID_ID = String.valueOf(ORDER1.getId()); + private static final String VALID_CUSTOMER = ORDER1.getCustomer().toString(); + private static final String VALID_IS_COMPLETE = String.valueOf(ORDER1.getIsComplete()); @Test public void toModelType_validOrderDetails_returnsOrder() throws Exception { - JsonAdaptedOrder order = new JsonAdaptedOrder(ORDER); - assertEquals(ORDER, order.toModelType()); + JsonAdaptedOrder order = new JsonAdaptedOrder(ORDER1); + assertEquals(ORDER1, order.toModelType()); } @Test diff --git a/src/test/java/seedu/address/testutil/TypicalOrders.java b/src/test/java/seedu/address/testutil/TypicalOrders.java index 8ad9dcea9b6..ac7d9757b64 100644 --- a/src/test/java/seedu/address/testutil/TypicalOrders.java +++ b/src/test/java/seedu/address/testutil/TypicalOrders.java @@ -24,7 +24,7 @@ public class TypicalOrders { .withDate("2021-09-20").withAmount("20").withIsComplete(true).withId(3).withLabel("testorder3").build(); // Manually added - Order's details found in {@code CommandTestUtil} - public static final Order ORDER = new OrderBuilder().withCustomer(VALID_CUSTOMER_SALE1) + public static final Order ORDER1 = new OrderBuilder().withCustomer(VALID_CUSTOMER_SALE1) .withDate(VALID_DATE_SEPT).withAmount(VALID_AMOUNT_SALE1).build(); public static final Order ORDER2 = new OrderBuilder().withCustomer(VALID_CUSTOMER_SALE2) .withDate(VALID_DATE_OCT).withAmount(VALID_AMOUNT_SALE2).build(); From 8ae64dab2be19164b5306be2a14698612c1d8380 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Wed, 3 Nov 2021 01:01:29 +0800 Subject: [PATCH 16/74] Update ListOrderCommand to revert to default sort --- .../java/seedu/address/logic/commands/ListOrderCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/address/logic/commands/ListOrderCommand.java b/src/main/java/seedu/address/logic/commands/ListOrderCommand.java index 41532fcb76c..c4ea333cf24 100644 --- a/src/main/java/seedu/address/logic/commands/ListOrderCommand.java +++ b/src/main/java/seedu/address/logic/commands/ListOrderCommand.java @@ -17,7 +17,7 @@ public class ListOrderCommand extends Command { @Override public CommandResult execute(Model model) { requireNonNull(model); - model.updateFilteredOrderList(PREDICATE_SHOW_ALL_ORDERS); + model.resetOrderView(); return new CommandResult(MESSAGE_SUCCESS, CommandResult.DisplayState.ORDER); } } From c1bcb1363f9932baf5dd35d6cecef6391f9e8ed4 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Wed, 3 Nov 2021 01:02:54 +0800 Subject: [PATCH 17/74] Add ListOrder, DeleteOrder tests --- .../logic/commands/ListOrderCommand.java | 1 - .../commands/DeleteOrderCommandTest.java | 34 +++++++++++- .../logic/commands/ListOrderCommandTest.java | 53 +++++++++++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 src/test/java/seedu/address/logic/commands/ListOrderCommandTest.java diff --git a/src/main/java/seedu/address/logic/commands/ListOrderCommand.java b/src/main/java/seedu/address/logic/commands/ListOrderCommand.java index c4ea333cf24..0a179909245 100644 --- a/src/main/java/seedu/address/logic/commands/ListOrderCommand.java +++ b/src/main/java/seedu/address/logic/commands/ListOrderCommand.java @@ -1,7 +1,6 @@ package seedu.address.logic.commands; import static java.util.Objects.requireNonNull; -import static seedu.address.model.Model.PREDICATE_SHOW_ALL_ORDERS; import seedu.address.model.Model; diff --git a/src/test/java/seedu/address/logic/commands/DeleteOrderCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteOrderCommandTest.java index 4e67bf65888..65d4f370ba3 100644 --- a/src/test/java/seedu/address/logic/commands/DeleteOrderCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/DeleteOrderCommandTest.java @@ -4,9 +4,15 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.commands.SortOrdersCommandTest.DATE_ASC; import static seedu.address.testutil.Assert.assertThrows; import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON; +import static seedu.address.testutil.TypicalOrders.SALESORDER2; +import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; +import static seedu.address.testutil.TypicalTasks.getTypicalTaskBook; import java.util.Arrays; import java.util.function.Predicate; @@ -19,6 +25,9 @@ import seedu.address.commons.core.Messages; import seedu.address.commons.core.index.Index; import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; import seedu.address.model.order.Order; import seedu.address.model.task.Task; import seedu.address.testutil.OrderBuilder; @@ -34,8 +43,8 @@ public void execute_validIndexDeletion_success() throws Exception { CommandResult commandResult = new DeleteOrderCommand(targetIndex).execute(modelStub); - assertEquals(String.format(DeleteOrderCommand.MESSAGE_DELETE_ORDER_SUCCESS, testOrder), - commandResult.getFeedbackToUser()); + String expectedMessage = String.format(DeleteOrderCommand.MESSAGE_DELETE_ORDER_SUCCESS, testOrder); + assertEquals(expectedMessage, commandResult.getFeedbackToUser()); assertEquals(Arrays.asList(), modelStub.listWithOneOrder); } @@ -49,6 +58,27 @@ public void execute_invalidIndexUnfilteredList_throwsCommandException() { ) -> deleteOrderCommand.execute(modelStub)); } + @Test + public void execute_sortedOrders_remainsSorted() { + Model model = new ModelManager(getTypicalAddressBook(), getTypicalTaskBook(), + getTypicalOrderBook(), new UserPrefs()); + + Model expectedModel = new ModelManager(getTypicalAddressBook(), getTypicalTaskBook(), + getTypicalOrderBook(), new UserPrefs()); + + Index toDelete = Index.fromOneBased(2); + DeleteOrderCommand deleteFirstOrder = new DeleteOrderCommand(toDelete); + + model.sortOrderList(DATE_ASC); + + expectedModel.deleteOrder(SALESORDER2); + expectedModel.sortOrderList(DATE_ASC); + + String expectedMessage = String.format(DeleteOrderCommand.MESSAGE_DELETE_ORDER_SUCCESS, SALESORDER2); + + assertCommandSuccess(deleteFirstOrder, model, expectedMessage, expectedModel); + } + @Test public void equals() { DeleteOrderCommand deleteFirstOrderCommand = new DeleteOrderCommand(INDEX_FIRST_PERSON); diff --git a/src/test/java/seedu/address/logic/commands/ListOrderCommandTest.java b/src/test/java/seedu/address/logic/commands/ListOrderCommandTest.java new file mode 100644 index 00000000000..f0326794e50 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/ListOrderCommandTest.java @@ -0,0 +1,53 @@ +package seedu.address.logic.commands; + +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.commands.SortOrdersCommandTest.DATE_DESC; +import static seedu.address.model.Model.PREDICATE_SHOW_INCOMPLETE_ORDERS; +import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; +import static seedu.address.testutil.TypicalTasks.getTypicalTaskBook; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; + +class ListOrderCommandTest { + private Model model; + private Model expectedModel; + + @BeforeEach + public void setUp() { + model = new ModelManager(getTypicalAddressBook(), getTypicalTaskBook(), + getTypicalOrderBook(), new UserPrefs()); + expectedModel = new ModelManager(model.getAddressBook(), + model.getTaskBook(), model.getOrderBook(), new UserPrefs()); + + } + + @Test + public void execute_listNotFilteredNotSorted_showsSameList() { + assertCommandSuccess(new ListOrderCommand(), model, ListOrderCommand.MESSAGE_SUCCESS, expectedModel); + } + + @Test + public void execute_listFilteredNotSorted_showsEverything() { + model.updateFilteredOrderList(PREDICATE_SHOW_INCOMPLETE_ORDERS); + assertCommandSuccess(new ListOrderCommand(), model, ListOrderCommand.MESSAGE_SUCCESS, expectedModel); + } + + @Test + public void execute_listNotFilteredSorted_showsEverything() { + model.sortOrderList(DATE_DESC); + assertCommandSuccess(new ListOrderCommand(), model, ListOrderCommand.MESSAGE_SUCCESS, expectedModel); + } + + @Test + public void execute_listFilteredSorted_showsEverything() { + model.updateFilteredOrderList(PREDICATE_SHOW_INCOMPLETE_ORDERS); + model.sortOrderList(DATE_DESC); + assertCommandSuccess(new ListOrderCommand(), model, ListOrderCommand.MESSAGE_SUCCESS, expectedModel); + } +} From 1628b6edaf93c0790b062e6f18dedd1086b50b6d Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Wed, 3 Nov 2021 02:05:00 +0800 Subject: [PATCH 18/74] Fix merge conflicts --- .../address/model/sort/SortDescriptor.java | 25 +++++++++++++++++++ .../commands/DeleteOrderCommandTest.java | 18 ++++++------- .../logic/commands/FindOrderCommandTest.java | 2 +- .../logic/parser/AddressBookParserTest.java | 8 ++++-- .../parser/SortOrdersCommandParserTest.java | 9 ++++--- .../seedu/address/testutil/OrderBuilder.java | 2 +- .../seedu/address/testutil/TypicalOrders.java | 4 +-- 7 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/main/java/seedu/address/model/sort/SortDescriptor.java b/src/main/java/seedu/address/model/sort/SortDescriptor.java index 320dd356b40..b7e76f7b095 100644 --- a/src/main/java/seedu/address/model/sort/SortDescriptor.java +++ b/src/main/java/seedu/address/model/sort/SortDescriptor.java @@ -6,6 +6,7 @@ import static seedu.address.model.sort.SortOrderingType.DESCENDING; import java.util.Comparator; +import java.util.Objects; import seedu.address.model.order.Order; @@ -63,4 +64,28 @@ public SortField getSortField() { public SortOrdering getSortOrdering() { return sortOrdering; } + + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof SortDescriptor)) { + return false; + } + + // state check + SortDescriptor e = (SortDescriptor) other; + + return sortField.equals(e.sortField) && sortOrdering.equals(e.sortOrdering); + } + + @Override + public int hashCode() { + return Objects.hash(sortField, sortOrdering); + } } diff --git a/src/test/java/seedu/address/logic/commands/DeleteOrderCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteOrderCommandTest.java index 65d4f370ba3..212133bfb8b 100644 --- a/src/test/java/seedu/address/logic/commands/DeleteOrderCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/DeleteOrderCommandTest.java @@ -5,11 +5,11 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; -import static seedu.address.logic.commands.SortOrdersCommandTest.DATE_ASC; +import static seedu.address.logic.commands.SortOrdersCommandTest.AMOUNT_ASC; import static seedu.address.testutil.Assert.assertThrows; import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON; -import static seedu.address.testutil.TypicalOrders.SALESORDER2; +import static seedu.address.testutil.TypicalOrders.SALESORDER4; import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; import static seedu.address.testutil.TypicalTasks.getTypicalTaskBook; @@ -66,17 +66,17 @@ public void execute_sortedOrders_remainsSorted() { Model expectedModel = new ModelManager(getTypicalAddressBook(), getTypicalTaskBook(), getTypicalOrderBook(), new UserPrefs()); - Index toDelete = Index.fromOneBased(2); - DeleteOrderCommand deleteFirstOrder = new DeleteOrderCommand(toDelete); + Order toDelete = SALESORDER4; + DeleteOrderCommand command = new DeleteOrderCommand(Index.fromOneBased(5)); - model.sortOrderList(DATE_ASC); + model.sortOrderList(AMOUNT_ASC); - expectedModel.deleteOrder(SALESORDER2); - expectedModel.sortOrderList(DATE_ASC); + expectedModel.deleteOrder(toDelete); + expectedModel.sortOrderList(AMOUNT_ASC); - String expectedMessage = String.format(DeleteOrderCommand.MESSAGE_DELETE_ORDER_SUCCESS, SALESORDER2); + String expectedMessage = String.format(DeleteOrderCommand.MESSAGE_DELETE_ORDER_SUCCESS, toDelete); - assertCommandSuccess(deleteFirstOrder, model, expectedMessage, expectedModel); + assertCommandSuccess(command, model, expectedMessage, expectedModel); } @Test diff --git a/src/test/java/seedu/address/logic/commands/FindOrderCommandTest.java b/src/test/java/seedu/address/logic/commands/FindOrderCommandTest.java index 6b205f7a31d..b4fd83f19c8 100644 --- a/src/test/java/seedu/address/logic/commands/FindOrderCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/FindOrderCommandTest.java @@ -74,7 +74,7 @@ public void execute_zeroKeywords_noOrderFound() { @Test public void execute_multipleKeywords_multipleOrdersFound() { String expectedMessage = String.format(MESSAGE_ORDERS_LISTED_OVERVIEW, 3); - OrderContainsKeywordsPredicate predicate = preparePredicate("Josh testorder2 2021-09-20"); + OrderContainsKeywordsPredicate predicate = preparePredicate("Josh testorder3 2021-09-19"); FindOrderCommand command = new FindOrderCommand(predicate); expectedModel.updateFilteredOrderList(predicate); assertCommandSuccess(command, model, expectedMessage, expectedModel); diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java index 3685d478298..ff07ea0e441 100644 --- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java +++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java @@ -47,6 +47,7 @@ import seedu.address.model.order.OrderContainsKeywordsPredicate; import seedu.address.model.person.NameContainsKeywordsPredicate; import seedu.address.model.person.Person; +import seedu.address.model.sort.SortDescriptor; import seedu.address.model.sort.SortField; import seedu.address.model.sort.SortOrdering; import seedu.address.model.task.Task; @@ -222,10 +223,13 @@ public void parseCommand_totalOrders() throws Exception { public void parseCommand_sortOrders() throws Exception { String sortField = "amount"; String sortOrdering = "desc"; + SortDescriptor descriptor = + new SortDescriptor(new SortField(sortField), new SortOrdering(sortOrdering)); + SortOrdersCommand expectedSortOrdersCommand = new SortOrdersCommand(descriptor); + SortOrdersCommand command = (SortOrdersCommand) parser.parseCommand( SortOrdersCommand.COMMAND_WORD + " " + OrderUtil.getSortOrdersDetails(sortField, sortOrdering)); - assertEquals(new SortOrdersCommand(new SortField(sortField), - new SortOrdering(sortOrdering)), command); + assertEquals(expectedSortOrdersCommand, command); } @Test diff --git a/src/test/java/seedu/address/logic/parser/SortOrdersCommandParserTest.java b/src/test/java/seedu/address/logic/parser/SortOrdersCommandParserTest.java index b7e62a0c125..3c9f873a7cc 100644 --- a/src/test/java/seedu/address/logic/parser/SortOrdersCommandParserTest.java +++ b/src/test/java/seedu/address/logic/parser/SortOrdersCommandParserTest.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test; import seedu.address.logic.commands.SortOrdersCommand; +import seedu.address.model.sort.SortDescriptor; import seedu.address.model.sort.SortField; import seedu.address.model.sort.SortOrdering; @@ -24,10 +25,12 @@ public void parse_emptyArg_throwsParseException() { @Test public void parse_validArgs_returnsFindCommand() { // no leading and trailing whitespaces - SortOrdersCommand expectedSortOrdersCommand = - new SortOrdersCommand(new SortField("amount"), new SortOrdering("desc")); + SortDescriptor descriptor = + new SortDescriptor(new SortField("amount"), new SortOrdering("desc")); + SortOrdersCommand expectedSortOrdersCommand = new SortOrdersCommand(descriptor); + assertParseSuccess(parser, " " + PREFIX_SORT_FIELD + "amount " + PREFIX_SORT_ORDERING + "desc", - expectedSortOrdersCommand); + expectedSortOrdersCommand); // multiple whitespaces between keywords assertParseSuccess(parser, " \n " + PREFIX_SORT_FIELD + "amount " diff --git a/src/test/java/seedu/address/testutil/OrderBuilder.java b/src/test/java/seedu/address/testutil/OrderBuilder.java index 8857a9f3b27..698526e70fc 100644 --- a/src/test/java/seedu/address/testutil/OrderBuilder.java +++ b/src/test/java/seedu/address/testutil/OrderBuilder.java @@ -96,7 +96,7 @@ public OrderBuilder withId(long id) { */ public Order build() { Order order = new Order(label, customer, date, amount); - if (this.id != null) { + if (this.id != 0) { order.setId(this.id); } if (this.isComplete) { diff --git a/src/test/java/seedu/address/testutil/TypicalOrders.java b/src/test/java/seedu/address/testutil/TypicalOrders.java index 76c3bf4b7cb..feb8a5b96be 100644 --- a/src/test/java/seedu/address/testutil/TypicalOrders.java +++ b/src/test/java/seedu/address/testutil/TypicalOrders.java @@ -19,9 +19,9 @@ public class TypicalOrders { public static final Order SALESORDER1 = new OrderBuilder().withCustomer("Josh") .withDate("2021-09-18").withAmount("10").withLabel("testorder1").withIsComplete(true).build(); public static final Order SALESORDER2 = new OrderBuilder().withCustomer("Mac") - .withDate("2021-09-19").withAmount("15").withIsComplete(true).withLabel("testorder2").build(); + .withDate("2021-09-19").withAmount("20").withIsComplete(true).withLabel("testorder2").build(); public static final Order SALESORDER3 = new OrderBuilder().withCustomer("Clark") - .withDate("2021-09-20").withAmount("20").withIsComplete(true).withLabel("testorder3").build(); + .withDate("2021-09-20").withAmount("15").withIsComplete(true).withLabel("testorder3").build(); public static final Order SALESORDER4 = new OrderBuilder().withCustomer("Justin") .withDate("2021-09-20").withAmount("20").build(); public static final Order SALESORDER5 = new OrderBuilder().withCustomer("Stuart") From d5527d576216879b28d02c3af20baf71dea1cc64 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Wed, 3 Nov 2021 02:16:37 +0800 Subject: [PATCH 19/74] Fix checkstyle issues --- src/main/java/seedu/address/model/sort/SortField.java | 2 -- src/main/java/seedu/address/model/sort/SortOrdering.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/main/java/seedu/address/model/sort/SortField.java b/src/main/java/seedu/address/model/sort/SortField.java index 173f7d2c3df..23001d99f97 100644 --- a/src/main/java/seedu/address/model/sort/SortField.java +++ b/src/main/java/seedu/address/model/sort/SortField.java @@ -3,8 +3,6 @@ import static java.util.Objects.requireNonNull; import static seedu.address.commons.util.AppUtil.checkArgument; -import java.util.Locale; - enum SortFieldType { DATE, AMOUNT } diff --git a/src/main/java/seedu/address/model/sort/SortOrdering.java b/src/main/java/seedu/address/model/sort/SortOrdering.java index e25a57e91f5..bdb37c0b813 100644 --- a/src/main/java/seedu/address/model/sort/SortOrdering.java +++ b/src/main/java/seedu/address/model/sort/SortOrdering.java @@ -3,8 +3,6 @@ import static java.util.Objects.requireNonNull; import static seedu.address.commons.util.AppUtil.checkArgument; -import java.util.Locale; - enum SortOrderingType { ASCENDING, DESCENDING } From 14415120019b7d9e48b23ca1314e34205fbaaa4c Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Wed, 3 Nov 2021 16:06:48 +0800 Subject: [PATCH 20/74] Update DeleteTaskCommandTest --- .../logic/commands/DeleteTaskCommandTest.java | 65 +++++++++++++++++-- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java index 1bdd0360692..f0a77a0f5c6 100644 --- a/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java @@ -2,7 +2,16 @@ import static java.util.Objects.requireNonNull; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.commands.CommandTestUtil.showTaskAtIndex; import static seedu.address.testutil.Assert.assertThrows; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_TASK; +import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_TASK; +import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; +import static seedu.address.testutil.TypicalTasks.getTypicalTaskBook; import java.util.Arrays; @@ -16,20 +25,26 @@ import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Date; import seedu.address.model.Label; -import seedu.address.model.tag.TaskTag; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; import seedu.address.model.task.Task; +import seedu.address.model.tag.TaskTag; class DeleteTaskCommandTest { private static final Task testTask = new Task(new Label("test label"), new Date("2001-10-12"), new TaskTag("SO100")); - //I followed the style of AddCommand test instead of DeleteCommand test since I thought using a modelStub + private Model model = new ModelManager(getTypicalAddressBook(), + getTypicalTaskBook(), getTypicalOrderBook(), new UserPrefs()); + + //I followed the style of AddCommand test instead of DeleteTaskCommand test since I thought using a modelStub //was more stylistically appropriate for testing. @Test public void execute_validIndexDeletion_success() throws Exception { Index targetIndex = Index.fromOneBased(1); - ModelStubWithOnePerson modelStub = new ModelStubWithOnePerson(); + ModelStubWithOneTask modelStub = new ModelStubWithOneTask(); CommandResult commandResult = new DeleteTaskCommand(targetIndex).execute(modelStub); @@ -42,14 +57,44 @@ public void execute_validIndexDeletion_success() throws Exception { public void execute_invalidIndexUnfilteredList_throwsCommandException() { Index outOfBoundIndex = Index.fromOneBased(2); DeleteTaskCommand deleteTaskCommand = new DeleteTaskCommand(outOfBoundIndex); - ModelStubWithOnePerson modelStub = new ModelStubWithOnePerson(); + ModelStubWithOneTask modelStub = new ModelStubWithOneTask(); assertThrows(CommandException.class, Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX, ( ) -> deleteTaskCommand.execute(modelStub)); } + @Test + public void execute_validIndexFilteredList_success() { + showTaskAtIndex(model, INDEX_FIRST_TASK); + + Task taskToDelete = model.getFilteredTaskList().get(INDEX_FIRST_TASK.getZeroBased()); + DeleteTaskCommand deleteCommand = new DeleteTaskCommand(INDEX_FIRST_TASK); - private class ModelStubWithOnePerson extends ModelStub { + String expectedMessage = String.format(DeleteTaskCommand.MESSAGE_DELETE_TASK_SUCCESS, taskToDelete); + + Model expectedModel = new ModelManager(model.getAddressBook(), + model.getTaskBook(), model.getOrderBook(), new UserPrefs()); + expectedModel.deleteTask(taskToDelete); + showNoTask(expectedModel); + + assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_invalidIndexFilteredList_throwsCommandException() { + showTaskAtIndex(model, INDEX_FIRST_TASK); + + Index outOfBoundIndex = INDEX_SECOND_TASK; + + // ensures that outOfBoundIndex is still in bounds of task book list + assertTrue(outOfBoundIndex.getZeroBased() < model.getTaskBook().getTaskList().size()); + + DeleteTaskCommand deleteCommand = new DeleteTaskCommand(outOfBoundIndex); + + assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + + private class ModelStubWithOneTask extends ModelStub { private final ObservableList listWithOneTask = FXCollections.observableArrayList(testTask); @Override @@ -64,6 +109,14 @@ public ObservableList getFilteredTaskList() { } } - //pending more tests for filtered list(?) + + /** + * Updates {@code model}'s filtered list to show no task. + */ + private void showNoTask(Model model) { + model.updateFilteredTaskList(p -> false); + + assertTrue(model.getFilteredTaskList().isEmpty()); + } } From c89aea568eee46c441f943b4f930f19bb462d4cb Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Wed, 3 Nov 2021 17:13:54 +0800 Subject: [PATCH 21/74] Add filtered tests to EditTaskCommandTest --- .../logic/commands/EditTaskCommandTest.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/test/java/seedu/address/logic/commands/EditTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/EditTaskCommandTest.java index c05f76c307d..d365a44b92d 100644 --- a/src/test/java/seedu/address/logic/commands/EditTaskCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/EditTaskCommandTest.java @@ -5,8 +5,10 @@ import static seedu.address.logic.commands.CommandTestUtil.DESC_ORDER; import static seedu.address.logic.commands.CommandTestUtil.DESC_SEW; import static seedu.address.logic.commands.CommandTestUtil.VALID_LABEL_ORDER; +import static seedu.address.logic.commands.CommandTestUtil.VALID_LABEL_SEW; import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.commands.CommandTestUtil.showTaskAtIndex; import static seedu.address.logic.commands.EditTaskCommand.MESSAGE_DUPLICATE_TASK; import static seedu.address.logic.commands.EditTaskCommand.MESSAGE_NO_CHANGES_MADE; import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_TASK; @@ -74,6 +76,25 @@ public void execute_someFieldsSpecifiedUnfilteredList_success() { assertCommandSuccess(editTaskCommand, model, expectedMessage, expectedModel); } + @Test + public void execute_filteredList_success() { + showTaskAtIndex(model, Index.fromOneBased(4)); + + Task taskInFilteredList = model.getFilteredTaskList().get(INDEX_FIRST_TASK.getZeroBased()); + Task edited = new TaskBuilder(taskInFilteredList).withLabel(VALID_LABEL_SEW).build(); + EditTaskCommand editTaskCommand = new EditTaskCommand(INDEX_FIRST_TASK, + new EditTaskDescriptorBuilder().withLabel(VALID_LABEL_SEW).build()); + + String expectedMessage = String.format(EditTaskCommand.MESSAGE_EDIT_TASK_SUCCESS, edited); + + Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), + new TaskBook(model.getTaskBook()), new OrderBook(model.getOrderBook()), + new UserPrefs()); + expectedModel.setTask(model.getFilteredTaskList().get(0), edited); + + assertCommandSuccess(editTaskCommand, model, expectedMessage, expectedModel); + } + @Test public void execute_duplicateTaskUnfilteredList_failure() { Task firstTask = model.getFilteredTaskList().get(INDEX_FIRST_TASK.getZeroBased()); @@ -83,6 +104,18 @@ public void execute_duplicateTaskUnfilteredList_failure() { assertCommandFailure(editTaskCommand, model, MESSAGE_DUPLICATE_TASK); } + @Test + public void execute_duplicateFilteredList_failure() { + showTaskAtIndex(model, INDEX_FIRST_TASK); + + // edit task in filtered list into a duplicate in task book + Task taskInList = model.getTaskBook().getTaskList().get(INDEX_SECOND_TASK.getZeroBased()); + EditTaskCommand editTaskCommand = new EditTaskCommand(INDEX_FIRST_TASK, + new EditTaskDescriptorBuilder(taskInList).build()); + + assertCommandFailure(editTaskCommand, model, EditTaskCommand.MESSAGE_DUPLICATE_TASK); + } + @Test public void execute_noChangesMadeUnfilteredList_failure() { Task firstTask = model.getFilteredTaskList().get(INDEX_FIRST_TASK.getZeroBased()); @@ -110,6 +143,24 @@ public void execute_invalidTaskIndexUnfilteredList_failure() { assertCommandFailure(editTaskCommand, model, Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); } + /** + * Edit filtered list where index is larger than size of filtered list, + * but smaller than size of task book + */ + @Test + public void execute_invalidIndexFilteredList_failure() { + showTaskAtIndex(model, INDEX_FIRST_TASK); + Index outOfBoundIndex = INDEX_SECOND_TASK; + EditTaskDescriptor descriptor = new EditTaskDescriptorBuilder().withLabel(VALID_LABEL_ORDER).build(); + + // ensures that outOfBoundIndex is still in bounds of task book list + assertTrue(outOfBoundIndex.getZeroBased() < model.getTaskBook().getTaskList().size()); + + EditTaskCommand editTaskCommand = new EditTaskCommand(outOfBoundIndex, descriptor); + + assertCommandFailure(editTaskCommand, model, Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX); + } + @Test public void equals() { final EditTaskCommand standardCommand = new EditTaskCommand(INDEX_FIRST_TASK, DESC_ORDER); From 2b157ce92f8629862c70c0e247751961db378858 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Wed, 3 Nov 2021 17:14:21 +0800 Subject: [PATCH 22/74] Add SortDescriptor equality test to SortOrdersCommandTest --- .../logic/commands/SortOrdersCommandTest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/test/java/seedu/address/logic/commands/SortOrdersCommandTest.java b/src/test/java/seedu/address/logic/commands/SortOrdersCommandTest.java index a701d2c5add..72c94941b69 100644 --- a/src/test/java/seedu/address/logic/commands/SortOrdersCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/SortOrdersCommandTest.java @@ -26,6 +26,7 @@ import seedu.address.model.order.Order; import seedu.address.model.sort.SortDescriptor; import seedu.address.testutil.SortDescriptorBuilder; +import seedu.address.testutil.TaskBuilder; public class SortOrdersCommandTest { public static final SortDescriptor DATE_ASC = new SortDescriptorBuilder().onDateField().inAscOrder().build(); @@ -103,6 +104,25 @@ public void equals() { // different ordering -> returns false assertFalse(SORT_BY_DATE_ASC.equals(SORT_BY_AMOUNT_DESC)); + } + + @Test + public void sortDescriptorEquals() { + final SortDescriptor dateDescCopy = new SortDescriptorBuilder().onDateField().inDescOrder().build();; + + // same object is equal + assertTrue(DATE_DESC.equals(DATE_DESC)); + + // same fields is equal + assertTrue(DATE_DESC.equals(dateDescCopy)); + + // not same fields is not equal + assertFalse(DATE_DESC.equals(AMOUNT_ASC)); + + // null is not equal + assertFalse(DATE_DESC.equals(null)); + // other objects are not equal + assertFalse(DATE_DESC.equals(new TaskBuilder().build())); } } From 03e7c193be7b763341a54b0f0ab921b1a4f64368 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Thu, 4 Nov 2021 12:00:15 +0800 Subject: [PATCH 23/74] Add DeleteOrderCommandIntegrationTest; Fix regressions from change in TypicalTasks --- .../typicalTasksTaskBook.json | 4 +- .../DeleteOrderCommandIntegrationTest.java | 128 ++++++++++++++++++ .../commands/DeleteOrderCommandTest.java | 30 ---- .../logic/commands/DeleteTaskCommandTest.java | 2 +- .../logic/commands/FindTaskCommandTest.java | 2 +- .../seedu/address/testutil/TypicalTasks.java | 4 +- 6 files changed, 134 insertions(+), 36 deletions(-) create mode 100644 src/test/java/seedu/address/logic/commands/DeleteOrderCommandIntegrationTest.java diff --git a/src/test/data/JsonSerializableTaskBookTest/typicalTasksTaskBook.json b/src/test/data/JsonSerializableTaskBookTest/typicalTasksTaskBook.json index d9fa06c98ee..458566f0c2b 100644 --- a/src/test/data/JsonSerializableTaskBookTest/typicalTasksTaskBook.json +++ b/src/test/data/JsonSerializableTaskBookTest/typicalTasksTaskBook.json @@ -2,7 +2,7 @@ "tasks" : [ { "label" : "Sew red buttons", "date" : "2021-09-18", - "taskTag" : "SO1", + "taskTag" : "SO10", "isDone" : "false" }, { "label" : "Buy green buttons", @@ -12,7 +12,7 @@ }, { "label" : "Make orange buttons", "date" : "2021-09-23", - "taskTag" : "SO3", + "taskTag" : "SO2", "isDone" : "true" }, { "label" : "Adjust blue buttons", diff --git a/src/test/java/seedu/address/logic/commands/DeleteOrderCommandIntegrationTest.java b/src/test/java/seedu/address/logic/commands/DeleteOrderCommandIntegrationTest.java new file mode 100644 index 00000000000..401afa8aa1d --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/DeleteOrderCommandIntegrationTest.java @@ -0,0 +1,128 @@ +package seedu.address.logic.commands; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; +import static seedu.address.logic.commands.CommandTestUtil.showOrderAtIndex; +import static seedu.address.logic.commands.SortOrdersCommandTest.AMOUNT_ASC; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_ORDER; +import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_ORDER; +import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_TASK; +import static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_TASK; +import static seedu.address.testutil.TypicalOrders.SALESORDER4; +import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; +import static seedu.address.testutil.TypicalTasks.getTypicalTaskBook; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.order.Order; +import seedu.address.model.task.Task; + + +/** + * Contains integration tests (interaction with the Model) for {@code DeleteOrderCommand}. + */ +public class DeleteOrderCommandIntegrationTest { + + private Model model; + private Model expectedModel; + + @BeforeEach + public void setUp() { + model = new ModelManager(getTypicalAddressBook(), getTypicalTaskBook(), + getTypicalOrderBook(), new UserPrefs()); + expectedModel = new ModelManager(model.getAddressBook(), + model.getTaskBook(), model.getOrderBook(), new UserPrefs()); + } + + @Test + public void execute_noLinkedOrders_success() throws Exception { + Order orderToDelete = model.getFilteredOrderList().get(INDEX_FIRST_ORDER.getZeroBased()); + DeleteOrderCommand deleteCommand = new DeleteOrderCommand(INDEX_FIRST_ORDER); + + String expectedMessage = String.format(DeleteOrderCommand.MESSAGE_DELETE_ORDER_SUCCESS, orderToDelete); + + expectedModel.deleteOrder(orderToDelete); + + assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_linkedOrders_ordersDeleted() throws Exception { + Order orderToDelete = model.getFilteredOrderList().get(INDEX_SECOND_ORDER.getZeroBased()); + DeleteOrderCommand deleteCommand = new DeleteOrderCommand(INDEX_SECOND_ORDER); + + String expectedMessage = String.format(DeleteOrderCommand.MESSAGE_DELETE_ORDER_SUCCESS, orderToDelete); + + expectedModel.deleteOrder(orderToDelete); + + //delete linked tasks + Task linkedTask1 = model.getFilteredTaskList().get(INDEX_SECOND_TASK.getZeroBased()); + Task linkedTask2 = model.getFilteredTaskList().get(INDEX_THIRD_TASK.getZeroBased()); + expectedModel.deleteTask(linkedTask1); + expectedModel.deleteTask(linkedTask2); + + assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel); + } + + @Test + public void execute_validIndexFilteredList_success() { + showOrderAtIndex(model, INDEX_FIRST_ORDER); + + Order orderToDelete = model.getFilteredOrderList().get(INDEX_FIRST_ORDER.getZeroBased()); + DeleteOrderCommand deleteCommand = new DeleteOrderCommand(INDEX_FIRST_ORDER); + + String expectedMessage = String.format(DeleteOrderCommand.MESSAGE_DELETE_ORDER_SUCCESS, orderToDelete); + + expectedModel.deleteOrder(orderToDelete); + showNoOrder(expectedModel); + + assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel); + } + + + @Test + public void execute_invalidIndexFilteredList_throwsCommandException() { + showOrderAtIndex(model, INDEX_FIRST_ORDER); + + Index outOfBoundIndex = INDEX_SECOND_TASK; + + // ensures that outOfBoundIndex is still in bounds of order book list + assertTrue(outOfBoundIndex.getZeroBased() < model.getTaskBook().getTaskList().size()); + + DeleteOrderCommand deleteCommand = new DeleteOrderCommand(outOfBoundIndex); + + assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_ORDER_DISPLAYED_INDEX); + } + + /** + * Updates {@code model}'s filtered list to show no order. + */ + private void showNoOrder(Model model) { + model.updateFilteredOrderList(p -> false); + + assertTrue(model.getFilteredOrderList().isEmpty()); + } + + @Test + public void execute_sortedOrders_remainsSorted() { + Order toDelete = SALESORDER4; + DeleteOrderCommand command = new DeleteOrderCommand(Index.fromOneBased(5)); + + model.sortOrderList(AMOUNT_ASC); + + expectedModel.deleteOrder(toDelete); + expectedModel.sortOrderList(AMOUNT_ASC); + + String expectedMessage = String.format(DeleteOrderCommand.MESSAGE_DELETE_ORDER_SUCCESS, toDelete); + + assertCommandSuccess(command, model, expectedMessage, expectedModel); + } +} diff --git a/src/test/java/seedu/address/logic/commands/DeleteOrderCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteOrderCommandTest.java index 212133bfb8b..6830c2c764c 100644 --- a/src/test/java/seedu/address/logic/commands/DeleteOrderCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/DeleteOrderCommandTest.java @@ -4,15 +4,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess; -import static seedu.address.logic.commands.SortOrdersCommandTest.AMOUNT_ASC; import static seedu.address.testutil.Assert.assertThrows; import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON; -import static seedu.address.testutil.TypicalOrders.SALESORDER4; -import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; -import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; -import static seedu.address.testutil.TypicalTasks.getTypicalTaskBook; import java.util.Arrays; import java.util.function.Predicate; @@ -25,9 +19,6 @@ import seedu.address.commons.core.Messages; import seedu.address.commons.core.index.Index; import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.Model; -import seedu.address.model.ModelManager; -import seedu.address.model.UserPrefs; import seedu.address.model.order.Order; import seedu.address.model.task.Task; import seedu.address.testutil.OrderBuilder; @@ -58,27 +49,6 @@ public void execute_invalidIndexUnfilteredList_throwsCommandException() { ) -> deleteOrderCommand.execute(modelStub)); } - @Test - public void execute_sortedOrders_remainsSorted() { - Model model = new ModelManager(getTypicalAddressBook(), getTypicalTaskBook(), - getTypicalOrderBook(), new UserPrefs()); - - Model expectedModel = new ModelManager(getTypicalAddressBook(), getTypicalTaskBook(), - getTypicalOrderBook(), new UserPrefs()); - - Order toDelete = SALESORDER4; - DeleteOrderCommand command = new DeleteOrderCommand(Index.fromOneBased(5)); - - model.sortOrderList(AMOUNT_ASC); - - expectedModel.deleteOrder(toDelete); - expectedModel.sortOrderList(AMOUNT_ASC); - - String expectedMessage = String.format(DeleteOrderCommand.MESSAGE_DELETE_ORDER_SUCCESS, toDelete); - - assertCommandSuccess(command, model, expectedMessage, expectedModel); - } - @Test public void equals() { DeleteOrderCommand deleteFirstOrderCommand = new DeleteOrderCommand(INDEX_FIRST_PERSON); diff --git a/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java index f0a77a0f5c6..8281c3ca2a3 100644 --- a/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java @@ -28,8 +28,8 @@ import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; -import seedu.address.model.task.Task; import seedu.address.model.tag.TaskTag; +import seedu.address.model.task.Task; class DeleteTaskCommandTest { private static final Task testTask = new Task(new Label("test label"), diff --git a/src/test/java/seedu/address/logic/commands/FindTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/FindTaskCommandTest.java index 3f623a83369..12eace4a84b 100644 --- a/src/test/java/seedu/address/logic/commands/FindTaskCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/FindTaskCommandTest.java @@ -75,7 +75,7 @@ public void execute_zeroKeywords_noOrderFound() { @Test public void execute_multipleKeywords_multipleOrdersFound() { String expectedMessage = String.format(MESSAGE_TASKS_LISTED_OVERVIEW, 3); - TaskContainsKeywordsPredicate predicate = preparePredicate("red 19 SO3"); + TaskContainsKeywordsPredicate predicate = preparePredicate("green 23 SO10"); FindTaskCommand command = new FindTaskCommand(predicate); expectedModel.updateFilteredTaskList(predicate); assertCommandSuccess(command, model, expectedMessage, expectedModel); diff --git a/src/test/java/seedu/address/testutil/TypicalTasks.java b/src/test/java/seedu/address/testutil/TypicalTasks.java index 21a5d256912..c17090ac35a 100644 --- a/src/test/java/seedu/address/testutil/TypicalTasks.java +++ b/src/test/java/seedu/address/testutil/TypicalTasks.java @@ -17,11 +17,11 @@ public class TypicalTasks { public static final Task TASK1 = new TaskBuilder().withLabel("Sew red buttons") - .withDate("2021-09-18").withTaskTag("SO1").build(); + .withDate("2021-09-18").withTaskTag("SO10").build(); public static final Task TASK2 = new TaskBuilder().withLabel("Buy green buttons") .withDate("2021-09-19").withIsDone(false).withTaskTag("SO2").build(); public static final Task TASK3 = new TaskBuilder().withLabel("Make orange buttons") - .withDate("2021-09-23").withIsDone(true).withTaskTag("SO3").build(); + .withDate("2021-09-23").withIsDone(true).withTaskTag("SO2").build(); public static final Task TASK4 = new TaskBuilder().withLabel("Adjust blue buttons") .withDate("2021-09-20").withIsDone(false).build(); From 5b873378442305862e7eaa6179bf9b56a9500c13 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Thu, 4 Nov 2021 15:34:33 +0800 Subject: [PATCH 24/74] Add filtered list test case to mark order, mark task tests --- .../DeleteOrderCommandIntegrationTest.java | 2 +- .../logic/commands/DeleteTaskCommandTest.java | 4 +- .../logic/commands/MarkOrderCommandTest.java | 35 ++++++++++++- .../logic/commands/MarkTaskCommandTest.java | 49 ++++++++++++++----- 4 files changed, 73 insertions(+), 17 deletions(-) diff --git a/src/test/java/seedu/address/logic/commands/DeleteOrderCommandIntegrationTest.java b/src/test/java/seedu/address/logic/commands/DeleteOrderCommandIntegrationTest.java index 401afa8aa1d..0d309a800d9 100644 --- a/src/test/java/seedu/address/logic/commands/DeleteOrderCommandIntegrationTest.java +++ b/src/test/java/seedu/address/logic/commands/DeleteOrderCommandIntegrationTest.java @@ -105,7 +105,7 @@ public void execute_invalidIndexFilteredList_throwsCommandException() { /** * Updates {@code model}'s filtered list to show no order. */ - private void showNoOrder(Model model) { + public static void showNoOrder(Model model) { model.updateFilteredOrderList(p -> false); assertTrue(model.getFilteredOrderList().isEmpty()); diff --git a/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java index 8281c3ca2a3..2d3e0890bde 100644 --- a/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/DeleteTaskCommandTest.java @@ -31,7 +31,7 @@ import seedu.address.model.tag.TaskTag; import seedu.address.model.task.Task; -class DeleteTaskCommandTest { +public class DeleteTaskCommandTest { private static final Task testTask = new Task(new Label("test label"), new Date("2001-10-12"), new TaskTag("SO100")); @@ -113,7 +113,7 @@ public ObservableList getFilteredTaskList() { /** * Updates {@code model}'s filtered list to show no task. */ - private void showNoTask(Model model) { + public static void showNoTask(Model model) { model.updateFilteredTaskList(p -> false); assertTrue(model.getFilteredTaskList().isEmpty()); diff --git a/src/test/java/seedu/address/logic/commands/MarkOrderCommandTest.java b/src/test/java/seedu/address/logic/commands/MarkOrderCommandTest.java index b2c6ea9e5c8..e08450ca203 100644 --- a/src/test/java/seedu/address/logic/commands/MarkOrderCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/MarkOrderCommandTest.java @@ -3,8 +3,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.commands.DeleteOrderCommandIntegrationTest.showNoOrder; import static seedu.address.testutil.Assert.assertThrows; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_ORDER; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; +import static seedu.address.testutil.TypicalTasks.getTypicalTaskBook; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import javafx.collections.FXCollections; @@ -13,12 +18,21 @@ import seedu.address.commons.core.Messages; import seedu.address.commons.core.index.Index; import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.OrderBook; +import seedu.address.model.UserPrefs; import seedu.address.model.order.Order; import seedu.address.testutil.OrderBuilder; class MarkOrderCommandTest { - private static final Order testOrder = new OrderBuilder().build(); + private Order testOrder; + + @BeforeEach + public void setUp() { + testOrder = new OrderBuilder().withLabel("test label").build(); + } @Test public void execute_validIndexMarkOrder_success() throws Exception { @@ -57,6 +71,25 @@ public void execute_markAlreadyCompleted_notification() throws Exception { commandResult.getFeedbackToUser()); } + @Test + public void execute_filterIncompleteOrders_removesOrder() throws Exception { + OrderBook orderBookWithIncompleteOrder = new OrderBook(); + orderBookWithIncompleteOrder.addOrder(testOrder); + + Model model = new ModelManager(getTypicalAddressBook(), + getTypicalTaskBook(), orderBookWithIncompleteOrder, new UserPrefs()); + Model expectedModel = new ModelManager(getTypicalAddressBook(), + getTypicalTaskBook(), orderBookWithIncompleteOrder, new UserPrefs()); + + model.updateFilteredOrderList(order -> !order.getIsComplete()); + showNoOrder(expectedModel); + + CommandResult commandResult = new MarkOrderCommand(INDEX_FIRST_ORDER).execute(model); + assertTrue(testOrder.getIsComplete()); + assertEquals(String.format(MarkOrderCommand.MESSAGE_MARK_ORDER_SUCCESS, testOrder), + commandResult.getFeedbackToUser()); + } + private class ModelStubWithOneOrder extends ModelStub { private final ObservableList listWithOneOrder = FXCollections.observableArrayList(testOrder); diff --git a/src/test/java/seedu/address/logic/commands/MarkTaskCommandTest.java b/src/test/java/seedu/address/logic/commands/MarkTaskCommandTest.java index eba56b6df94..9ec6a51ac14 100644 --- a/src/test/java/seedu/address/logic/commands/MarkTaskCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/MarkTaskCommandTest.java @@ -3,8 +3,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.commands.DeleteTaskCommandTest.showNoTask; import static seedu.address.testutil.Assert.assertThrows; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_TASK; +import static seedu.address.testutil.TypicalOrders.getTypicalOrderBook; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import javafx.collections.FXCollections; @@ -13,31 +18,30 @@ import seedu.address.commons.core.Messages; import seedu.address.commons.core.index.Index; import seedu.address.logic.commands.exceptions.CommandException; -import seedu.address.model.Date; -import seedu.address.model.Label; -import seedu.address.model.tag.TaskTag; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.TaskBook; +import seedu.address.model.UserPrefs; import seedu.address.model.task.Task; +import seedu.address.testutil.TaskBuilder; class MarkTaskCommandTest { private static final String TEST_DATE = "04 July 2020"; - private static final Task testTask = new Task(new Label("test label"), - new Date(TEST_DATE), new TaskTag("SO100")); + private Task testTask; - //I followed the style of AddCommand test instead of DeleteCommand test since I thought using a modelStub - //was more stylistically appropriate for testing. + @BeforeEach + public void setUp() { + testTask = new TaskBuilder().withLabel("test label") + .withDate(TEST_DATE).withTaskTag("SO100").build(); + } @Test public void execute_validIndexMarkTask_success() throws Exception { - Index targetIndex = Index.fromOneBased(1); ModelStubWithOneTask modelStub = new ModelStubWithOneTask(); assertFalse(testTask.getIsDone()); - Task secondTestTask = new Task(new Label("test label"), - new Date(TEST_DATE), new TaskTag("SO100")); - secondTestTask.markDone(); - - CommandResult commandResult = new MarkTaskCommand(targetIndex).execute(modelStub); + CommandResult commandResult = new MarkTaskCommand(INDEX_FIRST_TASK).execute(modelStub); assertTrue(testTask.getIsDone()); assertEquals(String.format(MarkTaskCommand.MESSAGE_MARK_TASK_SUCCESS, testTask), commandResult.getFeedbackToUser()); @@ -66,6 +70,25 @@ public void execute_invalidIndexUnfilteredList_throwsCommandException() { ) -> markTaskCommand.execute(modelStub)); } + @Test + public void execute_filterIncompleteTasks_removesTask() throws Exception { + TaskBook taskBookWithIncompleteTask = new TaskBook(); + taskBookWithIncompleteTask.addTask(testTask); + + Model model = new ModelManager(getTypicalAddressBook(), + taskBookWithIncompleteTask, getTypicalOrderBook(), new UserPrefs()); + Model expectedModel = new ModelManager(getTypicalAddressBook(), + taskBookWithIncompleteTask, getTypicalOrderBook(), new UserPrefs()); + + model.updateFilteredTaskList(task -> !task.getIsDone()); + showNoTask(expectedModel); + + CommandResult commandResult = new MarkTaskCommand(INDEX_FIRST_TASK).execute(model); + assertTrue(testTask.getIsDone()); + assertEquals(String.format(MarkTaskCommand.MESSAGE_MARK_TASK_SUCCESS, testTask), + commandResult.getFeedbackToUser()); + } + private class ModelStubWithOneTask extends ModelStub { private final ObservableList listWithOneTask = FXCollections.observableArrayList(testTask); From e40920ac2654b16b2a62efb2f149ea959f2b1608 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Thu, 4 Nov 2021 16:17:32 +0800 Subject: [PATCH 25/74] Fix OrderList comment --- src/main/java/seedu/address/model/order/OrderList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/address/model/order/OrderList.java b/src/main/java/seedu/address/model/order/OrderList.java index cbb367ae559..deb947cfc93 100644 --- a/src/main/java/seedu/address/model/order/OrderList.java +++ b/src/main/java/seedu/address/model/order/OrderList.java @@ -130,7 +130,7 @@ public void sort(Comparator comparator) { } /** - * Returns true if {@code orders} contains only unique tasks. + * Returns true if {@code orders} contains only unique orders. */ private boolean ordersAreUnique(List orders) { for (int i = 0; i < orders.size() - 1; i++) { From 075618dbc23a96837ec1e2d9189bc03877a0a6b9 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Fri, 5 Nov 2021 16:23:00 +0800 Subject: [PATCH 26/74] Update DG usecases --- docs/DeveloperGuide.md | 205 ++++++++++++++++++++++++++++++++++------- 1 file changed, 171 insertions(+), 34 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index a9d8d11d948..e9f877f30bd 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -418,33 +418,67 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli ### Use cases (For all use cases below, the **System** is the `SalesNote` and the **Actor** is the `user`, unless specified otherwise) +For use cases that are very similar, only the differences between them have been highlighted. #### Use case: Add a client **MSS** -1. User requests to add a specific client to the list -2. SalesNote adds the client +1. User requests to add a specific client to the client list. +2. SalesNote adds the client to the list. Use case ends. **Extensions** -* 1a. The format of the request is invalid. +* 1a. The format / details of the request are invalid. - * 1a1. SalesNote shows an error message. - - Use case ends. + * 1a1. SalesNote shows an error message. + * 1a2. User enters a new request. + * Steps 1a1-1a2 are repeated until the request is valid. + + Use case resumes from step 2. + +* 2a. The client already exists in the client list + + * 2a1. SalesNote shows an error message + + Use case resumes from step 1. + +#### Use case: Add a task + +Analogous to the use case for [adding a client](#use-case-add-a-client). + +**Extensions** + +* 2b. The specified tag for the task does not correspond to an existing sales order. + + * 2b1. SalesNote shows an error message. + + Use case resumes from step 1. +#### Use case: Add an order + +Analogous to the use case for [adding a client](#use-case-add-a-client). + +**Extensions** + +* 2b. The specified customer for the task does not correspond to an existing client. + + * 2b1. SalesNote shows an error message. + + Use case resumes from step 1. #### Use case: Delete a client **MSS** -1. User requests to list clients -2. SalesNote shows a list of clients -3. User requests to delete a specific client in the list -4. SalesNote deletes the client +1. User requests to list clients. +2. SalesNote shows a list of clients. +3. User requests to delete a specific client in the list. +4. SalesNote deletes the client. +5. SalesNote deletes the orders related to that client. +6. SalesNote deletes the tasks related to those orders. Use case ends. @@ -452,40 +486,54 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli * 2a. The list is empty. - Use case ends. + Use case ends. * 3a. The given index is invalid. * 3a1. SalesNote shows an error message. Use case resumes at step 2. + +* 5a. No related orders found. + + Use case ends. + +* 6a. No related tasks found. + + Use case ends. -#### Use case: Add a task +#### Use case: Delete a task **MSS** -1. User requests to add a specific task to the list -2. SalesNote adds the task +1. User requests to list tasks. +2. SalesNote shows a list of tasks. +3. User requests to delete a specific task in the list. +4. SalesNote deletes the task. - Use case ends. + Use case ends. **Extensions** -* 1a. The format of the request is invalid. +* 2a. The list is empty. - * 1a1. SalesNote shows an error message. + Use case ends. - Use case ends. +* 3a. The given index is invalid. + * 3a1. SalesNote shows an error message. -#### Use case: Delete a task + Use case resumes at step 2. + +#### Use case: Delete an order **MSS** -1. User requests to list tasks -2. SalesNote shows a list of tasks -3. User requests to delete a specific task in the list -4. SalesNote deletes the task +1. User requests to list orders. +2. SalesNote shows a list of orders. +3. User requests to delete a specific order in the list. +4. SalesNote deletes the order. +5. SalesNote deletes the tasks related to the order. Use case ends. @@ -500,34 +548,94 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli * 3a1. SalesNote shows an error message. Use case resumes at step 2. + +* 5a. No related tasks found. -#### Use case: Add an order + Use case ends. + +#### Use case: Edit a task **MSS** -1. User requests to add a specific order to the list -2. SalesNote adds the order +1. User requests to list tasks. +2. SalesNote shows a list of tasks. +3. User requests to edit the details of a specific task in the list. +4. SalesNote edits the details of the task. Use case ends. **Extensions** -* 1a. The format of the request is invalid. +* 2a. The list is empty. + + Use case ends. + +* 3a. The format / details of the request are invalid. - * 1a1. SalesNote shows an error message. + * 3a1. SalesNote shows an error message. + * 3a2. User enters a new request. + * Steps 3a1-3a2 are repeated until the request is valid. + + Use case resumes from step 4. + +* 4a. The user has not made any changes to the task details. + + Use case resumes at step 3. + +* 4b. A task with the edited details already exists in the task list. + + * 2b1. SalesNote shows an error message. + + Use case resumes from step 3. + + +#### Use case: Edit a client + +Analogous to the use case for [editing a task](#use-case-edit-a-client). + +**Extensions** + +* 4c. The user updates the gender of a client without updating their dimensions. + + * 4c1. SalesNote shows an error message. + + Use case resumes from step 3. + +#### Use case: Find a client + +**MSS** + +1. User requests to find clients by a given keyword. +2. SalesNote shows a list of clients whose details match at least 1 keyword. + + Use case ends. + +**Extensions** + +* 2a. None of the clients match the keyword. + + * 2a1. SalesNote displays an empty client list. Use case ends. -#### Use case: Delete an order +#### Use case: Find a task + +Analogous to the use case for [finding a client](#use-case-find-a-client). + +#### Use case: Find an order + +Analogous to the use case for [finding a client](#use-case-find-a-client). + +#### Use case: Mark a task as done **MSS** -1. User requests to list orders -2. SalesNote shows a list of orders -3. User requests to delete a specific order in the list -4. SalesNote deletes the order +1. User requests to list incomplete tasks. +2. SalesNote shows a list of incomplete tasks. +3. User requests to mark a specific task in the list as done. +4. SalesNote marks the task as done. - Use case ends. + Use case ends. **Extensions** @@ -541,6 +649,35 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli Use case resumes at step 2. +#### Use case: Mark an order as complete + +Analogous to the use case for [marking a task as done](#use-case-mark-a-task-as-done). + +#### Use case: Sort orders + +**MSS** + +1. User requests to list orders. +2. SalesNote shows a list of orders. +3. User requests to sort the orders by either the date or amount field in ascending or descending order. +4. SalesNote displays the sorted list of orders. + + Use case ends. + +**Extension** + +- 2a. The list is empty. + + Use case ends. + +* 3a. The format / details of the request are invalid + + * 3a1. SalesNote shows an error message. + * 3a2. User enters a new request. + * Steps 3a1-3a2 are repeated until the request is valid. + + Use case resumes from step 3. + *{More to be added}* From c6d1c824895df96622c6da68d819636dfa651187 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Fri, 5 Nov 2021 17:57:54 +0800 Subject: [PATCH 27/74] Make SortDescriptor implement Comparator; Update model --- src/main/java/seedu/address/model/Model.java | 4 +- .../seedu/address/model/ModelManager.java | 6 +- .../address/model/sort/SortDescriptor.java | 56 +++++++++---------- src/test/java/seedu/address/ModelStub.java | 4 +- 4 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index b6c07fdd5e7..18f0722d62e 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -1,13 +1,13 @@ package seedu.address.model; import java.nio.file.Path; +import java.util.Comparator; import java.util.function.Predicate; import javafx.collections.ObservableList; import seedu.address.commons.core.GuiSettings; import seedu.address.model.order.Order; import seedu.address.model.person.Person; -import seedu.address.model.sort.SortDescriptor; import seedu.address.model.task.Task; /** @@ -200,7 +200,7 @@ public interface Model { boolean markOrder(Order order); - void sortOrderList(SortDescriptor sortDescriptor); + void sortOrderList(Comparator comparator); /** Resets the order list to its regular ordering based on id */ void resetOrderView(); diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 98f111a0ba9..f1bd470d17f 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -15,7 +15,6 @@ import seedu.address.commons.core.LogsCenter; import seedu.address.model.order.Order; import seedu.address.model.person.Person; -import seedu.address.model.sort.SortDescriptor; import seedu.address.model.task.Task; /** @@ -279,9 +278,8 @@ public void updateFilteredOrderList(Predicate predicate) { } @Override - public void sortOrderList(SortDescriptor sortDescriptor) { - Comparator comparator = sortDescriptor.generateComparator(); - orderBook.sortOrders(comparator); + public void sortOrderList(Comparator sortDescriptor) { + orderBook.sortOrders(sortDescriptor); } /** diff --git a/src/main/java/seedu/address/model/sort/SortDescriptor.java b/src/main/java/seedu/address/model/sort/SortDescriptor.java index b7e76f7b095..ba0c643f96c 100644 --- a/src/main/java/seedu/address/model/sort/SortDescriptor.java +++ b/src/main/java/seedu/address/model/sort/SortDescriptor.java @@ -13,9 +13,9 @@ /** * Encapsulates the sortField and sortOrdering that are used to sort the orderList. */ -public class SortDescriptor { - private SortField sortField; - private SortOrdering sortOrdering; +public class SortDescriptor implements Comparator { + private final SortField sortField; + private final SortOrdering sortOrdering; /** * Constructs a {@code SortDescriptor} with the given SortField and sortOrdering. @@ -25,31 +25,6 @@ public SortDescriptor(SortField sortField, SortOrdering sortOrdering) { this.sortOrdering = sortOrdering; } - /** - * Generates a comparator using the sortField and sortOrdering. - */ - public Comparator generateComparator() { - SortFieldType fieldType = sortField.getValue(); - SortOrderingType orderingType = sortOrdering.getValue(); - - Comparator comparator = null; - - if (fieldType.equals(DATE)) { - comparator = Comparator.comparing(Order::getDate); - } else if (fieldType.equals(AMOUNT)) { - comparator = Comparator.comparing(Order::getAmount); - } - - assert(comparator != null); - - if (orderingType.equals(ASCENDING)) { - return comparator; - } else { - assert(orderingType.equals(DESCENDING)); - return comparator.reversed(); - } - } - /** * Returns a success message for the {@code SortDescriptor}. */ @@ -65,6 +40,31 @@ public SortOrdering getSortOrdering() { return sortOrdering; } + /** + * Compares the orders {@code o1} and {@code o2} based on the {@code SortField} and {@code sortOrdering}. + */ + @Override + public int compare(Order o1, Order o2) { + SortFieldType fieldType = sortField.getValue(); + SortOrderingType orderingType = sortOrdering.getValue(); + + int result = 0; + + if (fieldType.equals(DATE)) { + result = o1.getDate().compareTo(o2.getDate()); + } else { + assert(fieldType.equals(AMOUNT)); + result = o1.getAmount().compareTo(o2.getAmount()); + } + + if (orderingType.equals(ASCENDING)) { + return result; + } else { + assert(orderingType.equals(DESCENDING)); + return result * -1; + } + + } @Override public boolean equals(Object other) { diff --git a/src/test/java/seedu/address/ModelStub.java b/src/test/java/seedu/address/ModelStub.java index 0835f61d950..dede22bb640 100644 --- a/src/test/java/seedu/address/ModelStub.java +++ b/src/test/java/seedu/address/ModelStub.java @@ -1,6 +1,7 @@ package seedu.address; import java.nio.file.Path; +import java.util.Comparator; import java.util.function.Predicate; import javafx.collections.ObservableList; @@ -13,7 +14,6 @@ import seedu.address.model.ReadOnlyUserPrefs; import seedu.address.model.order.Order; import seedu.address.model.person.Person; -import seedu.address.model.sort.SortDescriptor; import seedu.address.model.task.Task; /** @@ -211,7 +211,7 @@ public void updateFilteredOrderList(Predicate predicate) { } @Override - public void sortOrderList(SortDescriptor sortDescriptor) { + public void sortOrderList(Comparator sortDescriptor) { throw new AssertionError("This method should not be called."); } From a505b0623226418e78a59a132a82f942ccb5f858 Mon Sep 17 00:00:00 2001 From: ngchisern Date: Fri, 5 Nov 2021 18:13:35 +0800 Subject: [PATCH 28/74] Update portfolio page --- docs/team/ngchisern.md | 76 ++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/docs/team/ngchisern.md b/docs/team/ngchisern.md index ee485e29e50..d062493081f 100644 --- a/docs/team/ngchisern.md +++ b/docs/team/ngchisern.md @@ -9,38 +9,50 @@ SalesNote is a desktop application that helps tailors to manage sales and keep t Given below are my contributions to the project. -* **New Feature**: Added the ability to undo/redo previous commands. - * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command. - * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them. - * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands. - * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}* +* **Code contribution**: [RepoSense link](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/?search=ngchisern&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-17&tabOpen=true&tabType=authorship&tabAuthor=ngchisern&tabRepo=AY2122S1-CS2103T-W08-3%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false) -* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys. - -* **Code contributed**: [RepoSense link]() - -* **Project management**: - * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub +* **Enhancements implemented**: + * Added gender, measurement and remark fields to the Person class and updated the existing commands to make sure of these fields [#30](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/30) [#31](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/31) [#32](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/32) + * Implemented tag for the task class [#74](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/74) + * Implemented add and delete orders functionality [#81](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/81) [#82](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/82) + * Implemented tabs' auto-switching based on the users' commands [#108](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/108) * **Enhancements to existing features**: - * Updated the GUI color scheme (Pull requests [\#33](), [\#34]()) - * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]()) - -* **Documentation**: - * User Guide: - * Added documentation for the features `delete` and `find` [\#72]() - * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]() - * Developer Guide: - * Added implementation details of the `delete` feature. - -* **Community**: - * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]() - * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]()) - * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]()) - * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]()) - -* **Tools**: - * Integrated a third party library (Natty) to the project ([\#42]()) - * Integrated a new Github plugin (CircleCI) to the team repo - -* _{you can add/remove categories in the list above}_ + * Improved GUI of the application and updated its color scheme [#53](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/53) + * Update clear command to remove all data in SalesNote [#162](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/162) + +* **Contribution to the User Guide**: + * Added documentation for commands related to tasks [#138](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/138) + * Tweaked the table of content to increase flexibility when there are many headers (of different formats) in the UG [#167](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/167) + * Rearranged the order of the commands so that it is more intuitive for the readers [#167](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/167) + * Reviewed, raised and fixed issues throughout the UG + +* **Contribution to the Developer Guide**: + * Added use cases for adding and deleting an order [#86](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/86) + * Updated the Model class diagram [#86](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/86) + * Tweaked the table of content to increase flexibility when there are many headers (of different formats) in the DG [#86](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/86) + * Updated diagrams in Logic component [#273](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/273) + * Updated acknowledgements in the DG [#260](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/260) [#273](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/273) + * Updated the Model component's description and diagrams [#273](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/273) + * Added sequence diagrams to show how changes in a person's details are updated in the task or order list [#273](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/273) + * Reviewed, raised and fixed issues throughout the DG + +* **Contributions to team-based tasks**: + * Set up the GitHub team organisation and repository + * Updated the `README.md` file to match our project + * Updated Site Wide Settings in `_config.yml`, `_base.scss` and `index.md` files + * Managed the Release for every iteration + * In charge of versioning of the code, maintaining the code repository, integrating various parts of the software to create a whole. + * Reviewed, raised and fixed issues in the repository + +* **Review/mentoring contributions**: + * Few examples of reviewed pull requests (with non-trivial comments): + [#21](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/21), + [#44](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/44), + [#45](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/45), + [#68](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/68), + [#79](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/79) + +* **Contribution beyond the project team**: + * Reviewed and reported bugs in other team's product ([link to the issues](https://github.com/ngchisern/ped/issues)) + From ba365d6ae459633166540456f149f89790f67700 Mon Sep 17 00:00:00 2001 From: ngchisern Date: Fri, 5 Nov 2021 18:18:14 +0800 Subject: [PATCH 29/74] Improve project description --- docs/team/ngchisern.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/team/ngchisern.md b/docs/team/ngchisern.md index d062493081f..b9722f01333 100644 --- a/docs/team/ngchisern.md +++ b/docs/team/ngchisern.md @@ -5,7 +5,7 @@ title: Chi Sern's Project Portfolio Page ### Project: SalesNote -SalesNote is a desktop application that helps tailors to manage sales and keep track of a smaller, but more recurrent group of clients. While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). +SalesNote is a desktop application that helps tailors to manage sales and keep track of a smaller, but more recurrent group of clients. While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). It has about 20k lines of code written in Java. Given below are my contributions to the project. From bc637c61022043f31c66a47be4a8965876adf041 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Fri, 5 Nov 2021 20:21:20 +0800 Subject: [PATCH 30/74] Added relational check to tasks/Order and order/Client --- src/main/java/seedu/address/MainApp.java | 19 +++++++++- src/main/java/seedu/address/model/Model.java | 8 ++++ .../seedu/address/model/ModelManager.java | 38 +++++++++++++++++-- src/test/java/seedu/address/ModelStub.java | 11 ++++++ 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java index a9d6eacfeae..6f9de7fa6e1 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/address/MainApp.java @@ -135,7 +135,24 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { initialOrderBook = new OrderBook(); } - return new ModelManager(initialAddressBook, initialTaskBook, initialOrderBook, userPrefs); + ModelManager modelManager = new ModelManager(initialAddressBook, initialTaskBook, initialOrderBook, userPrefs); + try { + modelManager.checkClientAndOrderRelation(); + } catch (DataConversionException e) { + logger.info("Data file not corrupted. Will be starting with a empty OrderBook"); + initialOrderBook = new OrderBook(); + modelManager = new ModelManager(initialAddressBook, initialTaskBook, initialOrderBook, userPrefs); + } + + try { + modelManager.checkTaskAndOrderRelation(); + } catch (DataConversionException e) { + logger.info("Data file not corrupted. Will be starting with a empty TaskBook"); + initialTaskBook = new TaskBook(); + modelManager = new ModelManager(initialAddressBook, initialTaskBook, initialOrderBook, userPrefs); + } + + return modelManager; } private void initLogging(Config config) { diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index 2be52a09b97..bdaee142bdd 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -5,6 +5,7 @@ import javafx.collections.ObservableList; import seedu.address.commons.core.GuiSettings; +import seedu.address.commons.exceptions.DataConversionException; import seedu.address.model.order.Order; import seedu.address.model.person.Person; import seedu.address.model.sort.SortDescriptor; @@ -217,5 +218,12 @@ public interface Model { void deleteOrderIf(Predicate toDelete); + /** Checks if any order tagged to persons that don't exist */ + void checkClientAndOrderRelation() throws DataConversionException; + + /** Checks if any tasks tagged to order that don't exist */ + void checkTaskAndOrderRelation() throws DataConversionException; + + } diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 025e21c3246..ab12da95694 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -16,6 +16,8 @@ import javafx.collections.transformation.FilteredList; import seedu.address.commons.core.GuiSettings; import seedu.address.commons.core.LogsCenter; +import seedu.address.commons.exceptions.DataConversionException; +import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.commons.util.StringUtil; import seedu.address.model.order.Customer; import seedu.address.model.order.Order; @@ -306,7 +308,6 @@ public boolean markOrder(Order order) { } /** -<<<<<<< HEAD * Delete tasks related to a given Order */ @Override @@ -326,12 +327,10 @@ public void deleteOrderIf(Predicate pred) { /** * For each person, finds orders associated with the person, and adds up the amount. * Creates a ClientTotalOrder for each person. -======= * Groups and sums up all orders according to their {@code Customer}s. * This method computes total orders based on the {@code Customer}s, * but each {@code Customer} is supposed to map to an existing {@code Person} (Client), * hence the naming of the method and local variables. ->>>>>>> 7d4603133ce879c7e267914eb92fdca0f8d42c1e * * @return an ObservableList of {@code ClientTotalOrder}. */ @@ -409,4 +408,37 @@ public void resetOrderView() { updateFilteredOrderList(PREDICATE_SHOW_ALL_ORDERS); } + //=========== AddressBook & OrderBook Relation Check ======================================================= + + /** + * Checks if any order tagged to persons that don't exist. + */ + public void checkClientAndOrderRelation() throws DataConversionException { + ObservableList orders = this.orderBook.getOrderList(); + for (Order eachOrder : orders) { + String nameOfPerson = eachOrder.getCustomer().getName(); + if (!this.addressBook.hasPersonWithName(nameOfPerson)) { + throw new DataConversionException( + new IllegalValueException("Given Client Name does not exist in Address Book")); + } + } + } + + //=========== AddressBook & OrderBook Relation Check ======================================================= + + /** + * Checks if any tasks tagged to order that don't exist. + */ + public void checkTaskAndOrderRelation() throws DataConversionException { + ObservableList tasks = this.taskBook.getTaskList(); + for (Task eachTask : tasks) { + Long id = eachTask.getTaskTag().getTagId(); + if (!this.orderBook.hasOrder(id)) { + throw new DataConversionException( + new IllegalValueException("Given Sales ID does not exist in Order Book")); + } + } + } + + } diff --git a/src/test/java/seedu/address/ModelStub.java b/src/test/java/seedu/address/ModelStub.java index 4fffc3b3025..1876c16b340 100644 --- a/src/test/java/seedu/address/ModelStub.java +++ b/src/test/java/seedu/address/ModelStub.java @@ -5,6 +5,7 @@ import javafx.collections.ObservableList; import seedu.address.commons.core.GuiSettings; +import seedu.address.commons.exceptions.DataConversionException; import seedu.address.model.ClientTotalOrder; import seedu.address.model.Model; import seedu.address.model.ReadOnlyAddressBook; @@ -230,6 +231,16 @@ public void deleteOrderIf(Predicate pred) { throw new AssertionError("This method should not be called."); } + @Override + public void checkClientAndOrderRelation() throws DataConversionException { + throw new AssertionError("This method should not be called."); + } + + @Override + public void checkTaskAndOrderRelation() throws DataConversionException { + throw new AssertionError("This method should not be called."); + } + @Override public void deleteRelatedTasks(Order order) { throw new AssertionError("This method should not be called."); From aa2e3f7e3e6923ae51698e1bc3931d6231f4b7f4 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Fri, 5 Nov 2021 21:04:02 +0800 Subject: [PATCH 31/74] Add SortOrdersCommandClassDiagram.puml --- .../SortOrdersCommandClassDiagram.puml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 docs/diagrams/SortOrdersCommandClassDiagram.puml diff --git a/docs/diagrams/SortOrdersCommandClassDiagram.puml b/docs/diagrams/SortOrdersCommandClassDiagram.puml new file mode 100644 index 00000000000..179ce3b928a --- /dev/null +++ b/docs/diagrams/SortOrdersCommandClassDiagram.puml @@ -0,0 +1,25 @@ +@startuml +'https://plantuml.com/class-diagram + +@startuml +!include style.puml +skinparam arrowThickness 1.1 +skinparam arrowColor LOGIC_COLOR_T4 +skinparam classBackgroundColor LOGIC_COLOR + +Class "{abstract}\nCommand" as Command +Interface Parser <> +Interface "Comparable" <> + + +SortCommandParser ..> SortOrdersCommand : creates > +SortCommandParser .up.|> Parser +SortOrdersCommand -up-|> Command +SortOrdersCommand *--> SortDescriptor +SortDescriptor .up.|> "Comparable" +SortDescriptor *--> SortField +SortDescriptor *--> SortOrdering + +@enduml + + From a24e722b7ea4f5fb6a20a0ff8e08fc79d1aa674c Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Sat, 6 Nov 2021 00:49:46 +0800 Subject: [PATCH 32/74] Add SortOrderCommandSequenceDiagram.puml --- .../SortOrderCommandSequenceDiagram.puml | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 docs/diagrams/SortOrderCommandSequenceDiagram.puml diff --git a/docs/diagrams/SortOrderCommandSequenceDiagram.puml b/docs/diagrams/SortOrderCommandSequenceDiagram.puml new file mode 100644 index 00000000000..642f3417a30 --- /dev/null +++ b/docs/diagrams/SortOrderCommandSequenceDiagram.puml @@ -0,0 +1,96 @@ +@startuml + +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":SortOrderCommandParser" as SortOrderCommandParser LOGIC_COLOR +participant ":SortDescriptor" as SortDescriptor LOGIC_COLOR +participant "<>\nParserUtil" as ParserUtil LOGIC_COLOR +participant "d:SortOrderCommand" as SortOrderCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("sortorder f/a o/asc") +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand("sortorder f/a o/asc") +activate AddressBookParser + +create SortOrderCommandParser +AddressBookParser -> SortOrderCommandParser +activate SortOrderCommandParser + +SortOrderCommandParser --> AddressBookParser +deactivate SortOrderCommandParser + +AddressBookParser -> SortOrderCommandParser : parse("f/a o/asc") +activate SortOrderCommandParser + + +SortOrderCommandParser -> ParserUtil : parseSortField("a") +activate ParserUtil + +ParserUtil --> SortOrderCommandParser : sortField +deactivate ParserUtil + +SortOrderCommandParser -> ParserUtil : parseSortOrdering("asc") +activate ParserUtil + +ParserUtil --> SortOrderCommandParser : sortOrdering +deactivate ParserUtil + +create SortDescriptor +SortOrderCommandParser -> SortDescriptor : SortDescriptor(sortField, sortOrdering) +activate SortDescriptor + +SortDescriptor --> SortOrderCommandParser : sortDescriptor +deactivate SortDescriptor + +create SortOrderCommand +SortOrderCommandParser -> SortOrderCommand : SortOrderCommand(sortDescriptor) +activate SortOrderCommand + +SortOrderCommand --> SortOrderCommandParser : sortOrderCommand +deactivate SortOrderCommand + +SortOrderCommandParser --> AddressBookParser : sortOrderCommand +deactivate SortOrderCommandParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +SortOrderCommandParser -[hidden]-> AddressBookParser +destroy SortOrderCommandParser + +AddressBookParser --> LogicManager : sortOrderCommand +deactivate AddressBookParser + +LogicManager -> SortOrderCommand : execute() +activate SortOrderCommand + +SortOrderCommand -> Model : sortOrderList(SortDescriptor) +activate Model + +Model --> SortOrderCommand +deactivate Model + +create CommandResult +SortOrderCommand -> CommandResult +activate CommandResult + +CommandResult --> SortOrderCommand +deactivate CommandResult + +SortOrderCommand --> LogicManager : result +deactivate SortOrderCommand + +[<--LogicManager +deactivate LogicManager +@enduml + + + + From 3684929d9fae97829c0c74210e1811a439a3a16e Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Sat, 6 Nov 2021 01:06:46 +0800 Subject: [PATCH 33/74] fixing to the comments --- src/main/java/seedu/address/MainApp.java | 12 ++---------- src/main/java/seedu/address/model/ModelManager.java | 7 ++++++- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java index 6f9de7fa6e1..f4a5b896ff0 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/address/MainApp.java @@ -138,18 +138,10 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { ModelManager modelManager = new ModelManager(initialAddressBook, initialTaskBook, initialOrderBook, userPrefs); try { modelManager.checkClientAndOrderRelation(); - } catch (DataConversionException e) { - logger.info("Data file not corrupted. Will be starting with a empty OrderBook"); - initialOrderBook = new OrderBook(); - modelManager = new ModelManager(initialAddressBook, initialTaskBook, initialOrderBook, userPrefs); - } - - try { modelManager.checkTaskAndOrderRelation(); } catch (DataConversionException e) { - logger.info("Data file not corrupted. Will be starting with a empty TaskBook"); - initialTaskBook = new TaskBook(); - modelManager = new ModelManager(initialAddressBook, initialTaskBook, initialOrderBook, userPrefs); + logger.warning("Data file not corrupted. Will be starting with a empty Data."); + modelManager = modelManager.resetModelManager(); } return modelManager; diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index ab12da95694..44c68d5e079 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -419,7 +419,7 @@ public void checkClientAndOrderRelation() throws DataConversionException { String nameOfPerson = eachOrder.getCustomer().getName(); if (!this.addressBook.hasPersonWithName(nameOfPerson)) { throw new DataConversionException( - new IllegalValueException("Given Client Name does not exist in Address Book")); + new IllegalValueException("Given customer name does not exist in Address Book")); } } } @@ -440,5 +440,10 @@ public void checkTaskAndOrderRelation() throws DataConversionException { } } + //=========== AddressBook & OrderBook Relation Check ======================================================= + + public ModelManager resetModelManager(){ + return new ModelManager(new AddressBook(), new TaskBook(), new OrderBook(), this.userPrefs); + } } From 5aa3b1138efd9e0f180adf45814e8de10f632b78 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Sat, 6 Nov 2021 01:14:11 +0800 Subject: [PATCH 34/74] fixing comment issue --- src/main/java/seedu/address/model/ModelManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 44c68d5e079..1ed260f0646 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -442,7 +442,7 @@ public void checkTaskAndOrderRelation() throws DataConversionException { //=========== AddressBook & OrderBook Relation Check ======================================================= - public ModelManager resetModelManager(){ + public ModelManager resetModelManager() { return new ModelManager(new AddressBook(), new TaskBook(), new OrderBook(), this.userPrefs); } From db37ff21f6902ddc7d974fa275d516fa5466dab4 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Sat, 6 Nov 2021 04:44:43 +0800 Subject: [PATCH 35/74] small changes to UG Storage part --- docs/DeveloperGuide.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index a9d8d11d948..efb2765f669 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -165,12 +165,16 @@ The `Model` component, The `Storage` component, -* can save address book data, task book data, sales order book data +* Saves address book data, task book data, sales order book data and user preference data in json format, and read them back into corresponding objects. -* inherits from all of `AddressBookStorage`, `TaskBookStorage`, `OrderBookStorage`, +* The main storage class inherits from all of `AddressBookStorage`, `TaskBookStorage`, `OrderBookStorage`, and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed). -* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`) - +* Each Book Storage component (`AddressBookStorage`, `TaskBookStorage`, `OrderBookStorage`) has a `JsonSerializable` class which is in charge of making converting the model's data into correct json file and retrieving the data from + the json file to convert it to a model data. +* Each `JsonSerializable` class implements its own `JsonAdapted` class which specifies methods to convert model Object + (i.e `Person`, `Task`, `Order`) into json object and vise versa. +* The `JsonSerializable` class and `JsonAdapted` class also checks the correctness of the json files format, and in the + case when any of the format is wrong, it will then throw a `IllegalValueException` and `IllegalValueException` ### Common classes Classes used by multiple components are in the `seedu.salesnote.commons` package. From f6f2cacd9868c165ee5de1b8807670b851e206f0 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 08:17:18 +0800 Subject: [PATCH 36/74] Add test --- .../java/seedu/address/model/ModelManagerTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/seedu/address/model/ModelManagerTest.java index 8cfd52a7eab..8583429dd13 100644 --- a/src/test/java/seedu/address/model/ModelManagerTest.java +++ b/src/test/java/seedu/address/model/ModelManagerTest.java @@ -99,6 +99,16 @@ public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException assertThrows(UnsupportedOperationException.class, () -> modelManager.getFilteredPersonList().remove(0)); } + @Test + public void getClientTotalOrders_emptyOrderBook_returnsEmptyList() { + AddressBook addressBook = new AddressBookBuilder().withPerson(ALICE).withPerson(BENSON).build(); + TaskBook taskBook = new TaskBookBuilder().withTask(TASK1).withTask(TASK2).build(); + OrderBook orderBook = new OrderBookBuilder().build(); + UserPrefs userPrefs = new UserPrefs(); + ModelManager modelManager = new ModelManager(addressBook, taskBook, orderBook, userPrefs); + assertEquals(0, modelManager.getClientTotalOrders().size()); + } + @Test public void equals() { AddressBook addressBook = new AddressBookBuilder().withPerson(ALICE).withPerson(BENSON).build(); From a524b3e72186aa8002cc2661a41dd1884168d049 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 08:18:23 +0800 Subject: [PATCH 37/74] Remove residue of merge conflict --- src/main/java/seedu/address/model/ModelManager.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 025e21c3246..826d9305630 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -306,7 +306,6 @@ public boolean markOrder(Order order) { } /** -<<<<<<< HEAD * Delete tasks related to a given Order */ @Override @@ -324,14 +323,10 @@ public void deleteOrderIf(Predicate pred) { } /** - * For each person, finds orders associated with the person, and adds up the amount. - * Creates a ClientTotalOrder for each person. -======= * Groups and sums up all orders according to their {@code Customer}s. * This method computes total orders based on the {@code Customer}s, * but each {@code Customer} is supposed to map to an existing {@code Person} (Client), * hence the naming of the method and local variables. ->>>>>>> 7d4603133ce879c7e267914eb92fdca0f8d42c1e * * @return an ObservableList of {@code ClientTotalOrder}. */ From 70f21d400a66b68bb7c5aa05d2cd96f881e3b4e0 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 08:25:51 +0800 Subject: [PATCH 38/74] Improve success message --- .../java/seedu/address/logic/commands/TotalOrdersCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/address/logic/commands/TotalOrdersCommand.java b/src/main/java/seedu/address/logic/commands/TotalOrdersCommand.java index 13a85c31c3d..23da6957502 100644 --- a/src/main/java/seedu/address/logic/commands/TotalOrdersCommand.java +++ b/src/main/java/seedu/address/logic/commands/TotalOrdersCommand.java @@ -14,7 +14,7 @@ public class TotalOrdersCommand extends Command { + "Example: " + COMMAND_WORD; public static final String SHOWING_TOTAL_ORDERS_MESSAGE = "Opened/Refreshed total orders window.\n" - + "You might need to click the icon on taskbar if you have minimized it."; + + "You might need to restore the window if you have minimized it."; @Override public CommandResult execute(Model model) { From 453bbfa4b0859eafe5bdd966d2d20297fea3ea2a Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 08:26:10 +0800 Subject: [PATCH 39/74] Remove residue of merge conflict --- src/main/java/seedu/address/model/ModelManager.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 025e21c3246..826d9305630 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -306,7 +306,6 @@ public boolean markOrder(Order order) { } /** -<<<<<<< HEAD * Delete tasks related to a given Order */ @Override @@ -324,14 +323,10 @@ public void deleteOrderIf(Predicate pred) { } /** - * For each person, finds orders associated with the person, and adds up the amount. - * Creates a ClientTotalOrder for each person. -======= * Groups and sums up all orders according to their {@code Customer}s. * This method computes total orders based on the {@code Customer}s, * but each {@code Customer} is supposed to map to an existing {@code Person} (Client), * hence the naming of the method and local variables. ->>>>>>> 7d4603133ce879c7e267914eb92fdca0f8d42c1e * * @return an ObservableList of {@code ClientTotalOrder}. */ From 79be16289e00398719770d785afd146fa1251917 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 08:47:49 +0800 Subject: [PATCH 40/74] Update screenshot of TotalOrdersWindow, mention rerun command to refresh --- docs/UserGuide.md | 3 +-- docs/images/TotalOrdersWindow.png | Bin 13014 -> 13014 bytes 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 00520d719b5..9f98764df02 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -408,8 +408,7 @@ Examples: Shows the total orders for each client in the application.
-:information_source: The total orders displayed are based on the clients in the application. -If the customer of an order cannot be found among the clients, the order will not be shown. +:information_source: After adding/deleting orders, you might want to run this command again to refresh the window.
![TotalOrdersWindow](images/TotalOrdersWindow.png) diff --git a/docs/images/TotalOrdersWindow.png b/docs/images/TotalOrdersWindow.png index 09b0d34067a10a29f58739b9061cb3e4956e3044..5cf1db908a14cd6cfe6c466dcd2704e0440b0f17 100644 GIT binary patch literal 13014 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 delta 8921 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 Date: Sat, 6 Nov 2021 08:51:32 +0800 Subject: [PATCH 41/74] Mention client without orders will not be displayed --- docs/UserGuide.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 9f98764df02..3e3890f40ff 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -408,7 +408,10 @@ Examples: Shows the total orders for each client in the application.
-:information_source: After adding/deleting orders, you might want to run this command again to refresh the window. +:information_source: + +* Clients without orders will not be displayed. +* After adding/deleting orders, you might want to run this command again to refresh the window.
![TotalOrdersWindow](images/TotalOrdersWindow.png) From 0c7dd73f2cd600cd791315bf773c3caa21ade021 Mon Sep 17 00:00:00 2001 From: ngchisern Date: Sat, 6 Nov 2021 10:54:54 +0800 Subject: [PATCH 42/74] Fix wrong duplicate order check --- src/main/java/seedu/address/model/order/Order.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/address/model/order/Order.java b/src/main/java/seedu/address/model/order/Order.java index f13023cccad..9f97fe660de 100644 --- a/src/main/java/seedu/address/model/order/Order.java +++ b/src/main/java/seedu/address/model/order/Order.java @@ -106,7 +106,7 @@ public double getAmountAsDouble() { } /** - * Returns true if both orders have the same customer, label and amount. + * Returns true if both orders have the same customer, date, amount and label. * This defines a weaker notion of equality between two orders. */ public boolean isSameOrder(Order otherOrder) { @@ -116,6 +116,7 @@ public boolean isSameOrder(Order otherOrder) { return otherOrder != null && otherOrder.getCustomer().equals(getCustomer()) + && otherOrder.getDate().equals(getDate()) && otherOrder.getAmount().equals(getAmount()) && otherOrder.getLabel().equals(getLabel()); } From 26aef246aed1592be1a62b690dd1381e745cb0f3 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 10:56:38 +0800 Subject: [PATCH 43/74] Explain the implementation of total orders command --- docs/DeveloperGuide.md | 24 +++++++++- .../diagrams/TotalOrdersSequenceDiagram1.puml | 42 ++++++++++++++++++ .../diagrams/TotalOrdersSequenceDiagram2.puml | 39 ++++++++++++++++ docs/images/TotalOrdersSequenceDiagram1.png | Bin 0 -> 15545 bytes docs/images/TotalOrdersSequenceDiagram2.png | Bin 0 -> 17639 bytes 5 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 docs/diagrams/TotalOrdersSequenceDiagram1.puml create mode 100644 docs/diagrams/TotalOrdersSequenceDiagram2.puml create mode 100644 docs/images/TotalOrdersSequenceDiagram1.png create mode 100644 docs/images/TotalOrdersSequenceDiagram2.png diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 2c13360ae77..4d2f58652c3 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -284,7 +284,29 @@ Order uses its `id` field to produce the default ordering of the `OrderList`. ### Display client's total orders feature -The feature displays the total orders for each client in a new window. Its mechanism is a mix of the mechanisms for `MainWindow` and `HelpWindow`. +The feature displays the total orders for all clients except those without orders in a new window. +Its mechanism is a mix of the mechanisms for `MainWindow` and `HelpWindow`. + +Similar to `help` and `exit`, `CommandResult` has a dedicated `boolean` field to indicate whether the command is a +`totalorders` command. There is also a dedicated method to handle `totalorders` command in `MainWindow` class. +By calling this method, the data of total orders is reloaded similar to loading other data (`Client/Task/Order`) in the Main Window, i.e. +through the `Logic` component. After reloading data, that method shows or focuses the total orders window similar to that of the +help window. + +#### Execution + +The sequence diagram below shows the interaction within the `UI` component when a `totalorders` command is executed. + +![Interactions Inside the Logic and Model Component for the `totalorders` Command](images/TotalOrdersSequenceDiagram2.png) + +The sequence diagram below shows the interaction within the `Logic` component when the `UI` component calls +`execute("totalorders")`. Note that there is no need to have a `TotalOrdersCommandParser`. This is because the +`SalesNoteParser` can directly create and return a `TotalOrdersCommand`, similar to that of `help` and `exit` commands. + +![Interactions Inside the Logic and Model Component for the `totalorders` Command](images/TotalOrdersSequenceDiagram1.png) + + + -------------------------------------------------------------------------------------------------------------------- diff --git a/docs/diagrams/TotalOrdersSequenceDiagram1.puml b/docs/diagrams/TotalOrdersSequenceDiagram1.puml new file mode 100644 index 00000000000..eec2a063206 --- /dev/null +++ b/docs/diagrams/TotalOrdersSequenceDiagram1.puml @@ -0,0 +1,42 @@ +@startuml +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":SalesNoteParser" as SalesNoteParser LOGIC_COLOR +participant "TotalOrdersCommand" as TotalOrdersCommand LOGIC_COLOR +participant "CommandResult" as CommandResult LOGIC_COLOR +end box + +[-> LogicManager : execute("totalorders") +activate LogicManager + +LogicManager -> SalesNoteParser : parseCommand("totalorders") +activate SalesNoteParser + +create TotalOrdersCommand +SalesNoteParser -> TotalOrdersCommand +activate TotalOrdersCommand + +TotalOrdersCommand --> SalesNoteParser +deactivate TotalOrdersCommand + +SalesNoteParser --> LogicManager +deactivate SalesNoteParser + +LogicManager -> TotalOrdersCommand : execute() +activate TotalOrdersCommand + +create CommandResult +TotalOrdersCommand -> CommandResult +activate CommandResult + +CommandResult --> TotalOrdersCommand +deactivate CommandResult + +TotalOrdersCommand --> LogicManager +deactivate TotalOrdersCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/TotalOrdersSequenceDiagram2.puml b/docs/diagrams/TotalOrdersSequenceDiagram2.puml new file mode 100644 index 00000000000..e3ec0b6b98b --- /dev/null +++ b/docs/diagrams/TotalOrdersSequenceDiagram2.puml @@ -0,0 +1,39 @@ +@startuml +!include style.puml + +box UI UI_COLOR_T1 +participant ":MainWindow" as MainWindow UI_COLOR +participant ":TotalOrdersWindow" as TotalOrdersWindow UI_COLOR +end box + +box Logic LOGIC_COLOR_T1 +participant ":Logic" as Logic LOGIC_COLOR +end box + +[-> MainWindow : executeCommand("totalorders") +activate MainWindow + +MainWindow -> Logic : execute("totalorders") +activate Logic + +Logic --> MainWindow +deactivate Logic + +MainWindow -> MainWindow : handleTotalOrders() +activate MainWindow + +MainWindow -> TotalOrdersWindow : reloadData() +activate TotalOrdersWindow + +TotalOrdersWindow -> Logic : getClientTotalOrders() +activate Logic + +Logic --> TotalOrdersWindow +deactivate Logic + +TotalOrdersWindow --> MainWindow +deactivate TotalOrdersWindow + +[<-- MainWindow +deactivate MainWindow +@enduml diff --git a/docs/images/TotalOrdersSequenceDiagram1.png b/docs/images/TotalOrdersSequenceDiagram1.png new file mode 100644 index 0000000000000000000000000000000000000000..6c1017e3ff63b15f0827ef4e4f2214a9f77d6b84 GIT binary patch literal 15545 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 literal 0 HcmV?d00001 From 001a601299fafe9d068056b16803c2f2e98d5a60 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 11:09:15 +0800 Subject: [PATCH 44/74] Update success message of help command to match that of total orders --- src/main/java/seedu/address/logic/commands/HelpCommand.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java index bfb45f5dbdc..a0040f52835 100644 --- a/src/main/java/seedu/address/logic/commands/HelpCommand.java +++ b/src/main/java/seedu/address/logic/commands/HelpCommand.java @@ -12,7 +12,8 @@ public class HelpCommand extends Command { public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows program usage instructions.\n" + "Example: " + COMMAND_WORD; - public static final String SHOWING_HELP_MESSAGE = "Opened help window."; + public static final String SHOWING_HELP_MESSAGE = "Opened/Refreshed help window.\n" + + "You might need to restore the window if you have minimized it."; @Override public CommandResult execute(Model model) { From 91df844f1317b9764a8094da9798ae6225552a36 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 11:15:34 +0800 Subject: [PATCH 45/74] Specify target user clearer --- docs/UserGuide.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 3e3890f40ff..fa582134d02 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -3,9 +3,10 @@ layout: page title: User Guide --- -SalesNote is a **desktop app for managing contacts and tasks, optimized for use via a Command Line Interface** (CLI) -while still having the benefits of a Graphical User Interface (GUI). Fast typists can get more out of the application -than from traditional GUI apps. The application and guide are based on AB3 with new added features. +SalesNote is a desktop app for Singapore-based tailors to manage local sales and clients, so that they can focus on +producing great work. SalesNote is optimized for use via a Command Line Interface (CLI) while still having the +benefits of a Graphical User Interface (GUI). Fast typists can get more out of the application than from traditional +GUI apps. This project is based on the AB3 project created by the [SE-EDU initiative](https://se-education.org). From e15b8ccf9dca82a264689a695ef049ffbba5c9d3 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 12:01:09 +0800 Subject: [PATCH 46/74] Update and add test cases to the manual testing appendix --- docs/DeveloperGuide.md | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 4d2f58652c3..a181227e46b 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -536,9 +536,10 @@ testers are expected to do more *exploratory* testing. 1. Initial launch - 1. Download the jar file and copy into an empty folder + 1. Download the jar file and copy into an empty folder. - 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum. + 1. Double-click the jar file.
+ Expected: Shows the GUI with a set of sample clients, tasks and orders. The window size may not be optimum. 1. Saving window preferences @@ -547,7 +548,9 @@ testers are expected to do more *exploratory* testing. 1. Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained. -1. _{ more test cases …​ }_ +1. Shutdown + + 1. Shut down the app using the `exit` command. ### Deleting a client @@ -555,21 +558,23 @@ testers are expected to do more *exploratory* testing. 1. Prerequisites: List all clients using the `list` command. Multiple clients in the list. - 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. + 1. Test case: `deleteclient 1`
+ Expected: First client is deleted from the list. Details of the deleted client shown in the status message. - 1. Test case: `delete 0`
+ 1. Test case: `deleteclient 0`
Expected: No client is deleted. Error details shown in the status message. Status bar remains the same. - 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
+ 1. Other incorrect delete client commands to try: `deleteclient`, `deleteclient x`, `...` (where x is larger than the list size)
Expected: Similar to previous. -1. _{ more test cases …​ }_ - ### Saving data -1. Dealing with missing/corrupted data files +1. Dealing with missing data files + + 1. Prerequisite: The folder containing the jar file contains a `data` folder. + + 1. Delete the `data` folder and launch the app by double-clicking the jar file.
+ Expected: Shows the GUI with a set of sample clients, tasks and orders. The window size may not be optimum. + - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ -1. _{ more test cases …​ }_ From b6210ce07aef3b22e2aabf824e279babbf35d53e Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 12:06:53 +0800 Subject: [PATCH 47/74] Correct sequence diagram to end the activation bar of MainWindow --- .../diagrams/TotalOrdersSequenceDiagram2.puml | 5 ++++- docs/images/TotalOrdersSequenceDiagram2.png | Bin 17639 -> 18407 bytes 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/diagrams/TotalOrdersSequenceDiagram2.puml b/docs/diagrams/TotalOrdersSequenceDiagram2.puml index e3ec0b6b98b..337cb006d99 100644 --- a/docs/diagrams/TotalOrdersSequenceDiagram2.puml +++ b/docs/diagrams/TotalOrdersSequenceDiagram2.puml @@ -34,6 +34,9 @@ deactivate Logic TotalOrdersWindow --> MainWindow deactivate TotalOrdersWindow -[<-- MainWindow +MainWindow --> MainWindow +deactivate MainWindow + +[<--MainWindow deactivate MainWindow @enduml diff --git a/docs/images/TotalOrdersSequenceDiagram2.png b/docs/images/TotalOrdersSequenceDiagram2.png index 928cea6c13429b8f89b690b3184348090b0fb2b8..81de2d1f1f7a46f7c4157340fef86cfe65b3617d 100644 GIT binary patch literal 18407 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 literal 17639 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 From c88bfd1ce8f0a8b6a408a90ba71d15355c86a4b6 Mon Sep 17 00:00:00 2001 From: ngchisern Date: Sat, 6 Nov 2021 13:26:36 +0800 Subject: [PATCH 48/74] Fix duplicate tasks bugs --- src/main/java/seedu/address/model/task/Task.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/seedu/address/model/task/Task.java b/src/main/java/seedu/address/model/task/Task.java index 4ec4c8e1d4c..52898fc4ea9 100644 --- a/src/main/java/seedu/address/model/task/Task.java +++ b/src/main/java/seedu/address/model/task/Task.java @@ -92,7 +92,8 @@ public boolean isSameTask(Task otherTask) { return otherTask != null && otherTask.getLabel().equals(getLabel()) - && otherTask.getTaskTag().equals(getTaskTag()); + && otherTask.getTaskTag().equals(getTaskTag()) + && otherTask.getDate().equals(getDate()); } /** From a7137eef2d3c3a027777f82865594c9ecbdb7c2d Mon Sep 17 00:00:00 2001 From: ngchisern Date: Sat, 6 Nov 2021 13:41:34 +0800 Subject: [PATCH 49/74] Fix failed tests --- .../JsonSerializableTaskBookTest/duplicateTaskTaskBook.json | 2 +- src/test/java/seedu/address/model/TaskBookTest.java | 4 +--- .../java/seedu/address/model/task/UniqueTaskListTest.java | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/test/data/JsonSerializableTaskBookTest/duplicateTaskTaskBook.json b/src/test/data/JsonSerializableTaskBookTest/duplicateTaskTaskBook.json index df973973bec..0507d389138 100644 --- a/src/test/data/JsonSerializableTaskBookTest/duplicateTaskTaskBook.json +++ b/src/test/data/JsonSerializableTaskBookTest/duplicateTaskTaskBook.json @@ -1,7 +1,7 @@ { "tasks" : [ { "label" : "Buy green button", - "date" : "2021-09-18", + "date" : "2021-09-19", "taskTag" : "SO1", "isDone" : "false" }, { diff --git a/src/test/java/seedu/address/model/TaskBookTest.java b/src/test/java/seedu/address/model/TaskBookTest.java index a727ff21eca..21e5c95ce62 100644 --- a/src/test/java/seedu/address/model/TaskBookTest.java +++ b/src/test/java/seedu/address/model/TaskBookTest.java @@ -3,7 +3,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.logic.commands.CommandTestUtil.VALID_DATE_SEPT; import static seedu.address.testutil.Assert.assertThrows; import static seedu.address.testutil.TypicalTasks.SEW; import static seedu.address.testutil.TypicalTasks.getTypicalTaskBook; @@ -45,8 +44,7 @@ public void resetData_withValidReadOnlyTaskBook_replacesData() { @Test public void resetData_withDuplicateTasks_throwsDuplicateTaskException() { // Two tasks with the same identity fields - Task editedSew = new TaskBuilder(SEW).withDate(VALID_DATE_SEPT) - .build(); + Task editedSew = new TaskBuilder(SEW).build(); List newTasks = Arrays.asList(SEW, editedSew); TaskBookStub newData = new TaskBookStub(newTasks); diff --git a/src/test/java/seedu/address/model/task/UniqueTaskListTest.java b/src/test/java/seedu/address/model/task/UniqueTaskListTest.java index 70f945ab9c4..2dbaf784231 100644 --- a/src/test/java/seedu/address/model/task/UniqueTaskListTest.java +++ b/src/test/java/seedu/address/model/task/UniqueTaskListTest.java @@ -3,7 +3,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.logic.commands.CommandTestUtil.VALID_DATE_OCT; import static seedu.address.logic.commands.CommandTestUtil.VALID_LABEL_SEW; import static seedu.address.testutil.Assert.assertThrows; import static seedu.address.testutil.TypicalTasks.TASK1; @@ -45,7 +44,7 @@ public void contains_taskInList_returnsTrue() { @Test public void contains_taskWithSameDateField_returnsTrue() { uniqueTaskList.add(TASK1); - Task editedTask = new TaskBuilder(TASK1).withDate(VALID_DATE_OCT).build(); + Task editedTask = new TaskBuilder(TASK1).withIsDone(true).build(); assertTrue(uniqueTaskList.hasTask(editedTask)); } From 3c869a378e4820bdae0e1f9b61b3a589d3707e9f Mon Sep 17 00:00:00 2001 From: ngchisern Date: Sat, 6 Nov 2021 13:45:48 +0800 Subject: [PATCH 50/74] Improve header comments --- src/main/java/seedu/address/model/task/Task.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/seedu/address/model/task/Task.java b/src/main/java/seedu/address/model/task/Task.java index 52898fc4ea9..9f08d4fac93 100644 --- a/src/main/java/seedu/address/model/task/Task.java +++ b/src/main/java/seedu/address/model/task/Task.java @@ -29,7 +29,7 @@ public Task(Label label, Date date, TaskTag taskTag) { } /** - * Mark a task as done by setting isDone to true. + * Marks a task as done by setting isDone to true. * @return a boolean indicating whether the value of isDone has been changed or not. */ public boolean markDone() { @@ -76,14 +76,14 @@ public TaskTag getTaskTag() { } /** - * Return the task tag id of the task + * Returns the task tag id of the task */ public long getTagId() { return taskTag.getTagId(); } /** - * Returns true if both tasks have the same label and tag. + * Returns true if both tasks have the same label, tag and date. */ public boolean isSameTask(Task otherTask) { if (otherTask == this) { From 22ecb87f96a313d831726c45432e2dff651a7740 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Sat, 6 Nov 2021 13:59:50 +0800 Subject: [PATCH 51/74] fixing the wording error --- docs/DeveloperGuide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index efb2765f669..e5d7d27ca42 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -169,12 +169,12 @@ The `Storage` component, and user preference data in json format, and read them back into corresponding objects. * The main storage class inherits from all of `AddressBookStorage`, `TaskBookStorage`, `OrderBookStorage`, and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed). -* Each Book Storage component (`AddressBookStorage`, `TaskBookStorage`, `OrderBookStorage`) has a `JsonSerializable` class which is in charge of making converting the model's data into correct json file and retrieving the data from +* Each Book Storage component (`AddressBookStorage`, `TaskBookStorage`, `OrderBookStorage`) has a `JsonSerializable` class which is in charge of converting the model's data into correct json file and retrieving the data from the json file to convert it to a model data. * Each `JsonSerializable` class implements its own `JsonAdapted` class which specifies methods to convert model Object (i.e `Person`, `Task`, `Order`) into json object and vise versa. * The `JsonSerializable` class and `JsonAdapted` class also checks the correctness of the json files format, and in the - case when any of the format is wrong, it will then throw a `IllegalValueException` and `IllegalValueException` + case when any of the format is wrong, it will then throw a `DataConversionException` and `IllegalValueException` ### Common classes Classes used by multiple components are in the `seedu.salesnote.commons` package. From 4a4feb97f406b254047f55f38fa4274d281bdb46 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Sat, 6 Nov 2021 14:06:46 +0800 Subject: [PATCH 52/74] Fixing the warining commment --- src/main/java/seedu/address/MainApp.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java index f4a5b896ff0..85263efcd9f 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/address/MainApp.java @@ -140,7 +140,7 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { modelManager.checkClientAndOrderRelation(); modelManager.checkTaskAndOrderRelation(); } catch (DataConversionException e) { - logger.warning("Data file not corrupted. Will be starting with a empty Data."); + logger.warning(e.getMessage() + ". Will be starting with a empty Data."); modelManager = modelManager.resetModelManager(); } From 8c0f44b89f085f4356bac2a7bfb51e40049a77c5 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 14:34:08 +0800 Subject: [PATCH 53/74] Draft the project description --- docs/team/gnohchengyi.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/team/gnohchengyi.md b/docs/team/gnohchengyi.md index 5ca28e3cb41..efd4bad3bfe 100644 --- a/docs/team/gnohchengyi.md +++ b/docs/team/gnohchengyi.md @@ -3,9 +3,10 @@ layout: page title: Gnoh Cheng Yi's Project Portfolio Page --- -### Project: AddressBook Level 3 +### Project: SalesNote -AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC. +AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 20 kLoC. +SalesNote is a desktop application that helps tailors to manage sales and keep track of a smaller, but more recurrent group of clients. While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). It has about 20k lines of code written in Java. Given below are my contributions to the project. From 418169f050bf86ad6fefc7d7f95dcb36dbbc182c Mon Sep 17 00:00:00 2001 From: ngchisern Date: Sat, 6 Nov 2021 14:39:53 +0800 Subject: [PATCH 54/74] Fix duplicate orders bug --- src/main/java/seedu/address/MainApp.java | 2 +- .../java/seedu/address/model/ModelManager.java | 4 ++-- .../address/storage/JsonSerializableOrderBook.java | 14 +++++++++----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java index 85263efcd9f..5a78373fd8a 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/address/MainApp.java @@ -140,7 +140,7 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) { modelManager.checkClientAndOrderRelation(); modelManager.checkTaskAndOrderRelation(); } catch (DataConversionException e) { - logger.warning(e.getMessage() + ". Will be starting with a empty Data."); + logger.warning(e.getMessage() + ". Will be starting with empty data."); modelManager = modelManager.resetModelManager(); } diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 2e670d508b1..db2b674e94e 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -417,7 +417,7 @@ public void checkClientAndOrderRelation() throws DataConversionException { String nameOfPerson = eachOrder.getCustomer().getName(); if (!this.addressBook.hasPersonWithName(nameOfPerson)) { throw new DataConversionException( - new IllegalValueException("Given customer name does not exist in Address Book")); + new IllegalValueException("Given customer name does not exist in the Address Book")); } } } @@ -433,7 +433,7 @@ public void checkTaskAndOrderRelation() throws DataConversionException { Long id = eachTask.getTaskTag().getTagId(); if (!this.orderBook.hasOrder(id)) { throw new DataConversionException( - new IllegalValueException("Given Sales ID does not exist in Order Book")); + new IllegalValueException("Given Sales ID does not exist in the Order Book")); } } } diff --git a/src/main/java/seedu/address/storage/JsonSerializableOrderBook.java b/src/main/java/seedu/address/storage/JsonSerializableOrderBook.java index e5e160257cd..b5e2dd270f2 100644 --- a/src/main/java/seedu/address/storage/JsonSerializableOrderBook.java +++ b/src/main/java/seedu/address/storage/JsonSerializableOrderBook.java @@ -20,6 +20,7 @@ class JsonSerializableOrderBook { public static final String MESSAGE_DUPLICATE_ORDER = "salesBook contains duplicate order(s)."; + public static final String MESSAGE_DUPLICATE_ORDER_ID = "salesBook contains duplicate order id(s)."; private final List orders = new ArrayList<>(); @@ -48,7 +49,6 @@ public JsonSerializableOrderBook(ReadOnlyOrderBook source) { public OrderBook toModelType() throws IllegalValueException { OrderBook orderBook = new OrderBook(); long localCount = 0; - ArrayList idList = new ArrayList<>(); for (JsonAdaptedOrder jsonAdaptedOrder : orders) { Order order = jsonAdaptedOrder.toModelType(); @@ -56,12 +56,16 @@ public OrderBook toModelType() throws IllegalValueException { if (localCount < order.getId()) { localCount = order.getId(); } - if (idList.contains(order.getId())) { - throw new IllegalValueException("Order Id can not be duplicated"); - } else { - idList.add(order.getId()); + + if (orderBook.hasOrder(order)) { + throw new IllegalValueException(MESSAGE_DUPLICATE_ORDER); + } + + if (orderBook.hasOrder(order.getId())) { + throw new IllegalValueException(MESSAGE_DUPLICATE_ORDER_ID); } } + Order.setCount(localCount + 1); return orderBook; } From d7817d578cd94ebe91d1abe1ef3565b03d91f481 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 14:45:45 +0800 Subject: [PATCH 55/74] Correct the image caption, rename image --- docs/DeveloperGuide.md | 4 ++-- ...Diagram2.png => TotalOrdersSequenceDiagram0.png} | Bin 2 files changed, 2 insertions(+), 2 deletions(-) rename docs/images/{TotalOrdersSequenceDiagram2.png => TotalOrdersSequenceDiagram0.png} (100%) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index a181227e46b..7dc1af5e97a 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -297,13 +297,13 @@ help window. The sequence diagram below shows the interaction within the `UI` component when a `totalorders` command is executed. -![Interactions Inside the Logic and Model Component for the `totalorders` Command](images/TotalOrdersSequenceDiagram2.png) +![Interactions Inside the UI Component for the `totalorders` Command](images/TotalOrdersSequenceDiagram0.png) The sequence diagram below shows the interaction within the `Logic` component when the `UI` component calls `execute("totalorders")`. Note that there is no need to have a `TotalOrdersCommandParser`. This is because the `SalesNoteParser` can directly create and return a `TotalOrdersCommand`, similar to that of `help` and `exit` commands. -![Interactions Inside the Logic and Model Component for the `totalorders` Command](images/TotalOrdersSequenceDiagram1.png) +![Interactions Inside the Logic Component for the `totalorders` Command](images/TotalOrdersSequenceDiagram1.png) diff --git a/docs/images/TotalOrdersSequenceDiagram2.png b/docs/images/TotalOrdersSequenceDiagram0.png similarity index 100% rename from docs/images/TotalOrdersSequenceDiagram2.png rename to docs/images/TotalOrdersSequenceDiagram0.png From f53bdff9981b36d15916b6332c60c98904b9c237 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 16:44:35 +0800 Subject: [PATCH 56/74] Complete Project Portfolio Page --- docs/team/gnohchengyi.md | 47 +++++++++++++++------------------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/docs/team/gnohchengyi.md b/docs/team/gnohchengyi.md index efd4bad3bfe..a0a59e6fbdb 100644 --- a/docs/team/gnohchengyi.md +++ b/docs/team/gnohchengyi.md @@ -4,44 +4,31 @@ title: Gnoh Cheng Yi's Project Portfolio Page --- ### Project: SalesNote - -AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 20 kLoC. -SalesNote is a desktop application that helps tailors to manage sales and keep track of a smaller, but more recurrent group of clients. While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface). It has about 20k lines of code written in Java. + +SalesNote is a desktop application that helps tailors to manage sales and keep track of a smaller, but more recurrent +group of clients. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, +and has about 20 kLoC. This project is based on AddressBook - Level 3. Given below are my contributions to the project. -* **New Feature**: Added the ability to undo/redo previous commands. - * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command. - * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them. - * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands. - * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}* - -* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys. - -* **Code contributed**: [RepoSense link]() +* **New Feature**: Added the ability to display client's total orders + * What it does: displays the total orders for all clients except those without orders in a new window. + * Justification: This feature improves the product significantly because a user might want to know who are the clients that contributed the most to their sales, so that the user can put more effort into engaging those clients. + * Highlights: This enhancement affects the UI component, which is usually not the case for other commands. It required an in-depth analysis of design alternatives. + * Credits: I read some Stack Overflow answers to understand the approaches and implemented them myself. -* **Project management**: - * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub +* **New Feature**: Added `Task` and `Order` tabs that allow the user to view lists of different entities (`Task` and `Order`). -* **Enhancements to existing features**: - * Updated the GUI color scheme (Pull requests [\#33](), [\#34]()) - * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]()) +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/?search=GnohChengYi&sort=groupTitle&sortWithin=title&since=2021-09-17&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=false&tabOpen=true&tabType=authorship&tabAuthor=GnohChengYi&tabRepo=AY2122S1-CS2103T-W08-3%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false) * **Documentation**: * User Guide: - * Added documentation for the features `delete` and `find` [\#72]() - * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]() + * Updated project description and quick start [\#137](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/137), [\#280](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/280) + * Added documentation for the feature `totalorders` [\#145](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/145) * Developer Guide: - * Added implementation details of the `delete` feature. + * Added implementation details of the `totalorders` feature [\#282](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/282) * **Community**: - * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]() - * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]()) - * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]()) - * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]()) - -* **Tools**: - * Integrated a third party library (Natty) to the project ([\#42]()) - * Integrated a new Github plugin (CircleCI) to the team repo - -* _{you can add/remove categories in the list above}_ + * PRs reviewed (with non-trivial review comments): [\#30](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/30), [\#48](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/48), [\#135](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/135), [\#142](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/142) + * Contributed to forum discussions (examples: [1](https://github.com/nus-cs2103-AY2122S1/forum/issues/19), [2](https://github.com/nus-cs2103-AY2122S1/forum/issues/134), [3](https://github.com/nus-cs2103-AY2122S1/forum/issues/199)) + * Reported bugs and suggestions for other teams in the class (examples: [1](https://github.com/AY2122S1-CS2103-T14-1/tp/issues/147), [2](https://github.com/AY2122S1-CS2103-T14-1/tp/issues/153), [3](https://github.com/AY2122S1-CS2103-T14-1/tp/issues/156), [4](https://github.com/AY2122S1-CS2103-T14-1/tp/issues/163), [5](https://github.com/AY2122S1-CS2103-T14-1/tp/issues/166)) From 8ce7799bf9a19b5e69fea9b4eda28e742a78c585 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Sat, 6 Nov 2021 17:17:07 +0800 Subject: [PATCH 57/74] chaning the title of bullet points --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index e5d7d27ca42..b34f8332c7a 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -164,7 +164,7 @@ The `Model` component, -The `Storage` component, +How the Storage component works: * Saves address book data, task book data, sales order book data and user preference data in json format, and read them back into corresponding objects. * The main storage class inherits from all of `AddressBookStorage`, `TaskBookStorage`, `OrderBookStorage`, From 638c7baca43284911d9b58167ca7045ccec98364 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Sat, 6 Nov 2021 18:14:42 +0800 Subject: [PATCH 58/74] first commit of PPP --- docs/team/yuifuku1118.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/team/yuifuku1118.md diff --git a/docs/team/yuifuku1118.md b/docs/team/yuifuku1118.md new file mode 100644 index 00000000000..c97c3480e30 --- /dev/null +++ b/docs/team/yuifuku1118.md @@ -0,0 +1,36 @@ +- +layout: page +title: Yuichiro Fukushima's Project Portfolio Page +--- + +### Project: SalesNote + +SalesNote is a desktop application that aims to help singapore tailors to manage clients, tasks and sales +in order to for them to have a more effect order management system and supports a smother daily work which is +developed by Java and Java FX. + + +Given below are my contributions to the project. + +* **New Feature**: Added the ability to save and retrieve order, task, clients from Json file. + * What it does: Allows users to save the newly edited data so that user exits the app, the data is saved and able to use it when user opens the app next time. + * Justification: This feature was a necessary since we have added a new component of Order and Task. + * Highlights: This implementation also enhanced the error check when there was a incorrect manipulation of data json file. + + +* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/?search=yuifuku&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-17) + + +* **Documentation**: + * User Guide: + * Added documentation for the storage related features (i.e. `exit` and `clear`) [\#139]() + + * Developer Guide: + * Added implementation details of the `storage` component.[\#135]() + * Added the all the user stories [\#35]() + +* **Community**: + * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]() + * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]()) + * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]()) + From a223f82ff193739b00ded1308fbafdeade24b498 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Sat, 6 Nov 2021 18:33:18 +0800 Subject: [PATCH 59/74] Update DG with the SortOrders implementation. --- docs/DeveloperGuide.md | 70 ++++++++++++++++--- .../SortOrdersCommandClassDiagram.puml | 7 +- .../SortOrdersModelSequenceDiagram.puml | 70 +++++++++++++++++++ .../SortOrdersParserSequenceDiagram.puml | 66 +++++++++++++++++ 4 files changed, 201 insertions(+), 12 deletions(-) create mode 100644 docs/diagrams/SortOrdersModelSequenceDiagram.puml create mode 100644 docs/diagrams/SortOrdersParserSequenceDiagram.puml diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index e9f877f30bd..98d11e8fe80 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -245,20 +245,73 @@ is below: This section describes some noteworthy details on how certain features are implemented. -### Sort orders by amount feature +### Sort Order Feature #### Implementation -The feature sorts all the orders in the addressbook by their amount in descending order. +By default, orders are sorted in ascending order of their `id`. +This arrangement is also followed when SalesNote starts up or the `listorders` command is executed. -To ensure that the orders can be sorted, both `Order` and its attribute `Amount` implement the `Comparable` interface. -Order uses its `id` field to produce the default ordering of the `OrderList`. +The `sortorders` command sorts the orders in the `OrderBook` based on a field and an ordering specified by the user. -{to be completed} +The field is represented using the `SortFieldType` enumeration which is encapsulated as a `SortField` object. +Currently, SalesNote supports sorting by the following fields, which have been adapted to implement the `Comparable` interface: +1. `Amount` - Represented by `SortFieldType.AMOUNT` +2. `Date` - Represented by `SortFieldType.DATE` +The ordering is represented using the `SortOrderingType` enumeration which is encapsulated as a `SortOrderingType` object. SalesNote supports sorting in: +1. Ascending order - Represented by `SortOrderingType.ASCENDING` +2. Descending - Represented by `SortOrderingType.DESCENDING` + + +The class structure of the feature is shown in the diagram below: + +![SortOrdersCommandClassDiagram](images/SortOrdersCommandClassDiagram.png) + +Orders are sorted using the `SortDescriptor`, which implements the `Comparator` interface. +Its `compare` method uses the `SortField` and `SortOrdering` to compare orders based on the user specified arrangement. + +#### Usage + +The Sequence Diagram below illustrates the interactions within the `Logic` component for the `parseCommand("sortorder f/a o/asc")` API call. +Details about tokenizing the user input to retrieve the field and ordering have been omitted. + +![SortOrdersParserSequenceDiagram](images/SortOrdersParserSequenceDiagram.png) +
:information_source: **Note:** The lifeline for `SortOrdersCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. +
+ + +When the `SortOrderCommand` is executed, the following interactions take place in the `Logic` and the `Model` components. + +![SortOrdersModelSequenceDiagram](images/SortOrdersModelSequenceDiagram.png) + +After the `ObservableList` has been sorted, + +Step 1. the `SortCommand` obtains the relevant success message by invoking `sortDescriptor.generateSuccessMessage()`. + +Step 2. a `CommandResult` object is then instantiated using the message, and returned to `LogicManager`. + +Step 3. the UI proceeds to display the sorted list of orders. + +#### Design choices + +* **Alternative 1:** Mutating the `OrderList`. + * Pros: Allows the sorting functionality to be less coupled with the `FilteredList` of orders. + * This allows the user the flexibility to combine various filtering and sorting commands. + * For instance, executing `incompleteorders` followed by `sortorders f/d o/desc` would list the incomplete orders sorted by their date in descending order. + * Cons: Commands that mutate the list might disrupt the ordering of the sorted list. + * For instance, adding an `Order` to an `OrderBook` simply appends it + at the end of the `OrderList`. Thus, the `OrderBook` needs be reverted to its default arrangement by calling `ModelManager.resetOrderView()` whenever an order is added. + * Note that this is not a concern for the `markorder` and `deleteorder` commands since they do not disrupt the ordering of the list. +* **Alternative 2:** Wrapping the `FilteredList` around the `SortedList`. + * Pros: + * Maintains the immutability of the order list. + * Ensures that the sorting arrangement is always preserved, even another command e.g. `addorder` mutates the underlying list. + * Cons: More difficult to implement since it entails more coupling with the `FilteredList` of orders. + ### Display client's total orders feature -#### Implementation +#### Implementation details The feature displays the total orders for each client in a new window. Its mechanism is a mix of the mechanisms for `MainWindow` and `HelpWindow`. @@ -417,8 +470,9 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli ### Use cases +For the use cases that are very similar, only the differences between them have been highlighted. + (For all use cases below, the **System** is the `SalesNote` and the **Actor** is the `user`, unless specified otherwise) -For use cases that are very similar, only the differences between them have been highlighted. #### Use case: Add a client @@ -580,7 +634,7 @@ Analogous to the use case for [adding a client](#use-case-add-a-client). * 4a. The user has not made any changes to the task details. - Use case resumes at step 3. + Use case resumes at step 3. * 4b. A task with the edited details already exists in the task list. diff --git a/docs/diagrams/SortOrdersCommandClassDiagram.puml b/docs/diagrams/SortOrdersCommandClassDiagram.puml index 179ce3b928a..c784033bdeb 100644 --- a/docs/diagrams/SortOrdersCommandClassDiagram.puml +++ b/docs/diagrams/SortOrdersCommandClassDiagram.puml @@ -9,14 +9,13 @@ skinparam classBackgroundColor LOGIC_COLOR Class "{abstract}\nCommand" as Command Interface Parser <> -Interface "Comparable" <> -SortCommandParser ..> SortOrdersCommand : creates > -SortCommandParser .up.|> Parser +SortOrdersCommandParser ..> SortOrdersCommand : creates > +SortOrdersCommandParser .up.|> Parser SortOrdersCommand -up-|> Command SortOrdersCommand *--> SortDescriptor -SortDescriptor .up.|> "Comparable" +SortDescriptor .up.|> "Comparator" SortDescriptor *--> SortField SortDescriptor *--> SortOrdering diff --git a/docs/diagrams/SortOrdersModelSequenceDiagram.puml b/docs/diagrams/SortOrdersModelSequenceDiagram.puml new file mode 100644 index 00000000000..6eaf2c4b341 --- /dev/null +++ b/docs/diagrams/SortOrdersModelSequenceDiagram.puml @@ -0,0 +1,70 @@ +@startuml + +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant "d:SortOrdersCommand" as SortOrdersCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant ":OrderBook" as OrderBook MODEL_COLOR +participant ":OrderList" as OrderList MODEL_COLOR +participant ":OrderList" as OrderList MODEL_COLOR +participant ":ObservableList" as ObservableList MODEL_COLOR +end box + + +-> SortOrdersCommand : execute() +activate SortOrdersCommand + +SortOrdersCommand -> Model : sortOrderList(sortDescriptor) +activate Model + +Model -> OrderBook : sortOrders(sortDescriptor) +activate OrderBook + +OrderBook -> OrderList : sort(sortDescriptor) + +activate OrderList + +OrderList -> ObservableList : sort(sortDescriptor) + +activate ObservableList + +ObservableList --> OrderList + +deactivate ObservableList + +OrderList --> OrderBook + +deactivate OrderList + + +OrderBook --> Model + +deactivate OrderBook + +Model --> SortOrdersCommand + +deactivate Model + + + +create CommandResult +SortOrdersCommand -> CommandResult +activate CommandResult + +CommandResult --> SortOrdersCommand : result +deactivate CommandResult + + + +[<--SortOrdersCommand : result +deactivate SortOrdersCommand +@enduml + + + + diff --git a/docs/diagrams/SortOrdersParserSequenceDiagram.puml b/docs/diagrams/SortOrdersParserSequenceDiagram.puml new file mode 100644 index 00000000000..948d29f35ad --- /dev/null +++ b/docs/diagrams/SortOrdersParserSequenceDiagram.puml @@ -0,0 +1,66 @@ +@startuml + +!include style.puml + +box Logic LOGIC_COLOR_T1 +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":SortOrdersCommandParser" as SortOrdersCommandParser LOGIC_COLOR +participant ":SortDescriptor" as SortDescriptor LOGIC_COLOR +participant "<>\nParserUtil" as ParserUtil LOGIC_COLOR +participant "d:SortOrdersCommand" as SortOrderCommand LOGIC_COLOR +end box + +-> AddressBookParser : parseCommand("sortorders f/a o/asc") +activate AddressBookParser + +create SortOrdersCommandParser +AddressBookParser -> SortOrdersCommandParser +activate SortOrdersCommandParser + +SortOrdersCommandParser --> AddressBookParser +deactivate SortOrdersCommandParser + +AddressBookParser -> SortOrdersCommandParser : parse("f/a o/asc") +activate SortOrdersCommandParser + +SortOrdersCommandParser -> ParserUtil : parseSortField("a") +activate ParserUtil + +ParserUtil --> SortOrdersCommandParser : sortField +deactivate ParserUtil + +SortOrdersCommandParser -> ParserUtil : parseSortOrdering("asc") +activate ParserUtil + +ParserUtil --> SortOrdersCommandParser : sortOrdering +deactivate ParserUtil + +create SortDescriptor +SortOrdersCommandParser -> SortDescriptor : SortDescriptor(sortField, sortOrdering) +activate SortDescriptor + +SortDescriptor --> SortOrdersCommandParser : sortDescriptor +deactivate SortDescriptor + +create SortOrderCommand +SortOrdersCommandParser -> SortOrderCommand : SortOrderCommand(sortDescriptor) +activate SortOrderCommand + +SortOrderCommand --> SortOrdersCommandParser : sortOrdersCommand +deactivate SortOrderCommand + +SortOrdersCommandParser --> AddressBookParser : sortOrdersCommand +deactivate SortOrdersCommandParser + +'Hidden arrow to position the destroy marker below the end of the activation bar. +SortOrdersCommandParser -[hidden]-> AddressBookParser +destroy SortOrdersCommandParser + +<-- AddressBookParser : sortOrdersCommand +deactivate SortOrderCommand + +@enduml + + + + From 9125beaf92f0fd02e90abc3c66652fac072816b2 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Sat, 6 Nov 2021 18:33:48 +0800 Subject: [PATCH 60/74] Include diagram images. --- docs/images/SortOrdersCommandClassDiagram.png | Bin 0 -> 16160 bytes .../images/SortOrdersCommandSequenceDiagram.png | Bin 0 -> 51727 bytes docs/images/SortOrdersModelSequenceDiagram.png | Bin 0 -> 23427 bytes docs/images/SortOrdersParserSequenceDiagram.png | Bin 0 -> 37243 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/SortOrdersCommandClassDiagram.png create mode 100644 docs/images/SortOrdersCommandSequenceDiagram.png create mode 100644 docs/images/SortOrdersModelSequenceDiagram.png create mode 100644 docs/images/SortOrdersParserSequenceDiagram.png diff --git a/docs/images/SortOrdersCommandClassDiagram.png b/docs/images/SortOrdersCommandClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..2edd0c49d2c8e91a755fe0664d08c7b9aed2dcc7 GIT binary patch literal 16160 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 PbqGvE`hA&@uFwAhcE{_l literal 0 HcmV?d00001 diff --git a/docs/images/SortOrdersCommandSequenceDiagram.png b/docs/images/SortOrdersCommandSequenceDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..7a7df2ecd889d2b96da19376fc15a5f13852febd GIT binary patch literal 51727 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 z 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 a)=wUrsrDa9x($VI5sn93?C;t7#QzK8)ZOm@ literal 0 HcmV?d00001 diff --git a/docs/images/SortOrdersParserSequenceDiagram.png b/docs/images/SortOrdersParserSequenceDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..51065eb092c6ea986273cd2c16566614e9fe20b7 GIT binary patch literal 37243 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 M1bvt#^2Fo+0V>GwoB#j- literal 0 HcmV?d00001 From bc823e97857877c8ba5ce8e3357cad39e733eaf5 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Sat, 6 Nov 2021 18:46:49 +0800 Subject: [PATCH 61/74] fixing the merge conflict --- .../seedu/address/storage/JsonSerializableOrderBookTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java b/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java index 0754f53a98e..e22014da524 100644 --- a/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java +++ b/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java @@ -41,7 +41,7 @@ public void toModelType_invalidOrderFile_throwsIllegalValueException() throws Ex public void toModelType_duplicateOrders_throwsIllegalValueException() throws Exception { JsonSerializableOrderBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_ORDER_FILE, JsonSerializableOrderBook.class).get(); - assertThrows(IllegalValueException.class, JsonSerializableOrderBook.MESSAGE_DUPLICATE_ORDER, + assertThrows(IllegalValueException.class, JsonSerializableOrderBook.MESSAGE_DUPLICATE_ORDER_ID, dataFromFile::toModelType); } From 2869cac7a273fc6053c6ae6cb8d09498785c83f5 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Sat, 6 Nov 2021 18:53:23 +0800 Subject: [PATCH 62/74] Fix tests. --- .../typicalPersonsAddressBook.json | 2 +- src/test/java/seedu/address/testutil/TypicalPersons.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json index 42bcb9ca2b6..b35e746b187 100644 --- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json @@ -55,7 +55,7 @@ "remark" : "", "tagged" : [ ] }, { - "name" : "George Best", + "name" : "Johnson", "gender": "MALE", "phone" : "9482442", "email" : "anna@example.com", diff --git a/src/test/java/seedu/address/testutil/TypicalPersons.java b/src/test/java/seedu/address/testutil/TypicalPersons.java index a4ca05f8f58..c13f91f0954 100644 --- a/src/test/java/seedu/address/testutil/TypicalPersons.java +++ b/src/test/java/seedu/address/testutil/TypicalPersons.java @@ -60,7 +60,7 @@ public class TypicalPersons { .withEmail("lydia@example.com").withAddress("little tokyo") .withMeasurement("160_50_60_70") .withRemark("").build(); - public static final Person GEORGE = new PersonBuilder().withName("George Best").withGender("MALE") + public static final Person JOHNSON = new PersonBuilder().withName("Johnson").withGender("MALE") .withPhone("9482442") .withEmail("anna@example.com").withAddress("4th street") .withMeasurement("175_90_110") @@ -103,6 +103,6 @@ public static AddressBook getTypicalAddressBook() { } public static List getTypicalPersons() { - return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE)); + return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, JOHNSON)); } } From a5c61cc43f5b60a43d988c43e72140eca01d5890 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sat, 6 Nov 2021 22:29:42 +0800 Subject: [PATCH 63/74] Add more test cases in manual testing --- docs/DeveloperGuide.md | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 7dc1af5e97a..1afe6e44909 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -546,17 +546,18 @@ testers are expected to do more *exploratory* testing. 1. Resize the window to an optimum size. Move the window to a different location. Close the window. 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained. + Expected: The most recent window size and location is retained. 1. Shutdown - 1. Shut down the app using the `exit` command. + 1. Shut down the app using the `exit` command.
+ Expected: The app shuts down. ### Deleting a client 1. Deleting a client while all clients are being shown - 1. Prerequisites: List all clients using the `list` command. Multiple clients in the list. + 1. Prerequisites: List all clients using the `listclients` command. Multiple clients in the list. 1. Test case: `deleteclient 1`
Expected: First client is deleted from the list. Details of the deleted client shown in the status message. @@ -567,14 +568,31 @@ testers are expected to do more *exploratory* testing. 1. Other incorrect delete client commands to try: `deleteclient`, `deleteclient x`, `...` (where x is larger than the list size)
Expected: Similar to previous. +1. Deleting a client while no clients are being shown + + 1. Prerequisite: Use `findclients keyword` command (where keyword matches none of the clients) to display an empty list of clients.
+ + 1. Test case: `deleteclient 1`
+ Expected: No client is deleted. Error details shown in the status message. Status bar remains the same. + + 1. Other delete client commands to try: `deleteclient`, `deleteclient x`, `...` (where x is anything)
+ Expected: Similar to previous. Note that there is no valid command because the client list is empty. + ### Saving data 1. Dealing with missing data files 1. Prerequisite: The folder containing the jar file contains a `data` folder. - 1. Delete the `data` folder and launch the app by double-clicking the jar file.
- Expected: Shows the GUI with a set of sample clients, tasks and orders. The window size may not be optimum. + 1. Delete the `data` folder then launch the app by double-clicking the jar file.
+ Expected: Shows the GUI with a set of clients, tasks and orders. The window size may not be optimum. +1. Dealing with corrupted data files + 1. Prerequisite: The folder containing the jar file contains a `data` folder, which contains `addressbook.json`, `salesBook.json` and `taskBook.json`. + 1. Test case: Corrupt the `addressbook.json` file by deleting a closing curly bracket (`}`) or any other brackets.
+ Expected: Shows the GUI with no clients, but with a previously saved set of tasks and orders. + + 1. Other files to corrupt: `salesBook.json` and `taskBook.json`
+ Expected: Similar to previous. From 9117ee117fe238f947a50fcb8a2d1abad4eba34e Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Sun, 7 Nov 2021 12:10:04 +0800 Subject: [PATCH 64/74] Fix merge tests. --- .../typicalPersonsAddressBook.json | 2 +- .../typicalOrdersOrderBook.json | 20 ++++++++++++++++--- .../JsonSerializableOrderBookTest.java | 2 +- .../seedu/address/testutil/TypicalOrders.java | 4 ++-- .../address/testutil/TypicalPersons.java | 4 ++-- 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json index 42bcb9ca2b6..b35e746b187 100644 --- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json @@ -55,7 +55,7 @@ "remark" : "", "tagged" : [ ] }, { - "name" : "George Best", + "name" : "Johnson", "gender": "MALE", "phone" : "9482442", "email" : "anna@example.com", diff --git a/src/test/data/JsonSerializableOrderBookTest/typicalOrdersOrderBook.json b/src/test/data/JsonSerializableOrderBookTest/typicalOrdersOrderBook.json index 27ecc67f838..a4d60897c98 100644 --- a/src/test/data/JsonSerializableOrderBookTest/typicalOrdersOrderBook.json +++ b/src/test/data/JsonSerializableOrderBookTest/typicalOrdersOrderBook.json @@ -4,22 +4,36 @@ "date" : "2021-09-18", "amount" : "10", "customer" : "Josh", - "isComplete" : "false", + "isComplete" : "true", "label" : "testorder1" }, { "id" : "2", "date" : "2021-09-19", - "amount" : "15", + "amount" : "20", "customer" : "Mac", "isComplete" : "true", "label" : "testorder2" }, { "id" : "3", "date" : "2021-09-20", - "amount" : "20", + "amount" : "15", "customer" : "Clark", "isComplete" : "true", "label" : "testorder3" + }, { + "id" : "4", + "date" : "2021-09-20", + "amount" : "20", + "customer" : "Justin", + "isComplete" : "false", + "label" : "testorder4" + }, { + "id" : "5", + "date" : "2021-09-20", + "amount" : "5", + "customer" : "Stuart", + "isComplete" : "false", + "label" : "testorder5" } ] } diff --git a/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java b/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java index e22014da524..14805679d7c 100644 --- a/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java +++ b/src/test/java/seedu/address/storage/JsonSerializableOrderBookTest.java @@ -23,10 +23,10 @@ public class JsonSerializableOrderBookTest { @Test public void toModelType_typicalOrderFile_success() throws Exception { + OrderBook typicalOrdersOrderBook = TypicalOrders.getTypicalOrderBook(); JsonSerializableOrderBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_ORDERS_FILE, JsonSerializableOrderBook.class).get(); OrderBook orderBookBookFromFile = dataFromFile.toModelType(); - OrderBook typicalOrdersOrderBook = TypicalOrders.getTypicalOrderBook(); assertEquals(orderBookBookFromFile, typicalOrdersOrderBook); } diff --git a/src/test/java/seedu/address/testutil/TypicalOrders.java b/src/test/java/seedu/address/testutil/TypicalOrders.java index feb8a5b96be..b043d3acbeb 100644 --- a/src/test/java/seedu/address/testutil/TypicalOrders.java +++ b/src/test/java/seedu/address/testutil/TypicalOrders.java @@ -22,9 +22,9 @@ public class TypicalOrders { .withDate("2021-09-19").withAmount("20").withIsComplete(true).withLabel("testorder2").build(); public static final Order SALESORDER3 = new OrderBuilder().withCustomer("Clark") .withDate("2021-09-20").withAmount("15").withIsComplete(true).withLabel("testorder3").build(); - public static final Order SALESORDER4 = new OrderBuilder().withCustomer("Justin") + public static final Order SALESORDER4 = new OrderBuilder().withCustomer("Justin").withLabel("testorder4") .withDate("2021-09-20").withAmount("20").build(); - public static final Order SALESORDER5 = new OrderBuilder().withCustomer("Stuart") + public static final Order SALESORDER5 = new OrderBuilder().withCustomer("Stuart").withLabel("testorder5") .withDate("2021-09-20").withAmount("5").withIsComplete(false).build(); // Manually added - Order's details found in {@code CommandTestUtil} diff --git a/src/test/java/seedu/address/testutil/TypicalPersons.java b/src/test/java/seedu/address/testutil/TypicalPersons.java index a4ca05f8f58..c13f91f0954 100644 --- a/src/test/java/seedu/address/testutil/TypicalPersons.java +++ b/src/test/java/seedu/address/testutil/TypicalPersons.java @@ -60,7 +60,7 @@ public class TypicalPersons { .withEmail("lydia@example.com").withAddress("little tokyo") .withMeasurement("160_50_60_70") .withRemark("").build(); - public static final Person GEORGE = new PersonBuilder().withName("George Best").withGender("MALE") + public static final Person JOHNSON = new PersonBuilder().withName("Johnson").withGender("MALE") .withPhone("9482442") .withEmail("anna@example.com").withAddress("4th street") .withMeasurement("175_90_110") @@ -103,6 +103,6 @@ public static AddressBook getTypicalAddressBook() { } public static List getTypicalPersons() { - return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE)); + return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, JOHNSON)); } } From 19cd859bdb6b8911f4efa134075a55db3e6ef8e7 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Sun, 7 Nov 2021 12:24:55 +0800 Subject: [PATCH 65/74] Fix SortOrdersParserSequenceDiagram.puml --- .../SortOrdersParserSequenceDiagram.puml | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/diagrams/SortOrdersParserSequenceDiagram.puml b/docs/diagrams/SortOrdersParserSequenceDiagram.puml index 948d29f35ad..1c1bcb17123 100644 --- a/docs/diagrams/SortOrdersParserSequenceDiagram.puml +++ b/docs/diagrams/SortOrdersParserSequenceDiagram.puml @@ -3,24 +3,24 @@ !include style.puml box Logic LOGIC_COLOR_T1 -participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":SalesNoteParser" as SalesNoteParser LOGIC_COLOR participant ":SortOrdersCommandParser" as SortOrdersCommandParser LOGIC_COLOR participant ":SortDescriptor" as SortDescriptor LOGIC_COLOR participant "<>\nParserUtil" as ParserUtil LOGIC_COLOR participant "d:SortOrdersCommand" as SortOrderCommand LOGIC_COLOR end box --> AddressBookParser : parseCommand("sortorders f/a o/asc") -activate AddressBookParser +-> SalesNoteParser : parseCommand("sortorders f/a o/asc") +activate SalesNoteParser create SortOrdersCommandParser -AddressBookParser -> SortOrdersCommandParser +SalesNoteParser -> SortOrdersCommandParser activate SortOrdersCommandParser -SortOrdersCommandParser --> AddressBookParser +SortOrdersCommandParser --> SalesNoteParser deactivate SortOrdersCommandParser -AddressBookParser -> SortOrdersCommandParser : parse("f/a o/asc") +SalesNoteParser -> SortOrdersCommandParser : parse("f/a o/asc") activate SortOrdersCommandParser SortOrdersCommandParser -> ParserUtil : parseSortField("a") @@ -49,15 +49,15 @@ activate SortOrderCommand SortOrderCommand --> SortOrdersCommandParser : sortOrdersCommand deactivate SortOrderCommand -SortOrdersCommandParser --> AddressBookParser : sortOrdersCommand +SortOrdersCommandParser --> SalesNoteParser : sortOrdersCommand deactivate SortOrdersCommandParser 'Hidden arrow to position the destroy marker below the end of the activation bar. -SortOrdersCommandParser -[hidden]-> AddressBookParser +SortOrdersCommandParser -[hidden]-> SalesNoteParser destroy SortOrdersCommandParser -<-- AddressBookParser : sortOrdersCommand -deactivate SortOrderCommand +<-- SalesNoteParser : sortOrdersCommand +deactivate SalesNoteParser @enduml From 877e01f46b202ec07787cc845ce67d73f5d2691e Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Sun, 7 Nov 2021 12:35:23 +0800 Subject: [PATCH 66/74] Add extension for editing the name of a client --- docs/DeveloperGuide.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index f95984c824a..181f72a8eac 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -608,13 +608,19 @@ Analogous to the use case for [adding a client](#use-case-add-a-client). #### Use case: Edit a client -Analogous to the use case for [editing a task](#use-case-edit-a-client). +Analogous to the use case for [editing a task](#use-case-edit-a-task). **Extensions** -* 4c. The user updates the gender of a client without updating their dimensions. +* 4c. The user edits the name of the client. - * 4c1. SalesNote shows an error message. + * 4d1. SalesNote updates all orders linked to the client with the new client name. + + Use case ends. + +* 4d. The user updates the gender of a client without updating their dimensions. + + * 4d1. SalesNote shows an error message. Use case resumes from step 3. From a511632428d4e127aeda67e42b4cb8a1953d1b5d Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Sun, 7 Nov 2021 12:38:22 +0800 Subject: [PATCH 67/74] Update SortOrdersParserSequenceDiagram.pngParser --- .../SortOrdersParserSequenceDiagram.png | Bin 37243 -> 37077 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/images/SortOrdersParserSequenceDiagram.png b/docs/images/SortOrdersParserSequenceDiagram.png index 51065eb092c6ea986273cd2c16566614e9fe20b7..6719039f6350f6f4cc7c9f5bc6dc7a9cd7263dd0 100644 GIT binary patch literal 37077 zcmd432T)UM*fkoki;Ac;5fDL9ssd6%QxFhPkS;YMy#xe8ul7O*0R;j|=q2>t6p$)G zYNUg7Lhl3u_YI()qi6o_pKs>gxiijaV)ou|eV+BKwch>uo`THrqi2soAdus-w{Iy! zAp2nu2r1uTQt-_!ZHfT!*A;}+eT0GaBWFt^V+2IT$jZo8A7Ny8{-N`EQv~7>l$-mJ zrM?xy9&X8HU=63ZDs&D4*_ULddLQxgdk6`*jZ@^bdcSoy|49$(f$hOjk*_49Z42Qs zSD&1Jon56Af9 zN|#PN4Q;h88+vjuv*|`ef)~A1lJg}-{maym6_4Bq-m7(Vzrb zy?T+Pbv91_bPS&g{QOzAybBf51**oWZt*#+l>vv#537{tkb1BWI?&6eBqn6`!61tep2uDb5s;KE8tbTCCe-f_r1@f@3qcO zxkdX31S!s`3@u zVP-wiBrxo*)wAvM$pvOZH4q*ScXZidsE zO2$9u4fEGCAPKo5m7EoqZS{>jjwLxlJ64;5>YgK3{aAWrBaf|pvT_FUdT7~xvk)om zgh;9BPF*|7?>x1l`HJb+CNE|9Jy_+N^)DB4>)-zB9)0AzTwT)xmRrhpm2r@4!vS9S zTel|xiLS%%Ge1EGpAcN?ofia*GMRW|{Lb=h!{0w5C~b>sUArFZ(lRYpzR=jTKsy?x zlZ(-u=SOcXiBbzr$SF9R(y<8tKUw&H}FaM*VNs#6$>to{)sir>bx!e(m zn1=GZQ!Vvwfj!)g@(QyDB(3vJ(eu$~iqT@AzCmiH&=vS$=# zs0KSLNAIRdJkypwPT_rCNJmiq*r;;&ttu94CNdMjLlbl(Z_qk+QqBXV%YAxCPw%%P zYZQ#L%jHbWbRWVm8oCeYEo6!ztS1Uicn11%XU$9Tm(^Bp7g}yMnU=_UG2+QlOd=0* z+7oA#%CV0AI{Ca84_3F`NGEr9{N~B~NcWvy|6^To1QZ+0bgJfPh)>fs8!_*+T2X{m z?Y_s|_h}fiNPL(tS#k9n9bA(Yd2}&&qo;6Pu%5oJWJd4N(}mmmY;!ilv8N!+i8(*? zA$r3r{u`K+-0L*f1d@8o8p%Pkw$o817Gu^E^P()bE+65AK)fKbw{EIB=}q+>k5sVV z+P3*p`{3PhRGwkdlFDoStJhAQ>PqU_Ona+UoO4QvzssTf&3CIrbt^Kd#;e_IZSUxO z3a`n9YF%_}KXb8KwAH70+a$6zzg1|gXw?_AfA)Dvvm5c-ZARoqkDB3$2a~}4ehkPRc*AF3HwvTsj=M}>% zt!h%P-<_vY;~y>Lj-Psc+9Ve4KAw`UfE01&7g+tez2(?aMA3cFaT*#D<|rMyIry>_ zhwaWMhg`n!ue<*6=KlH}W!?}PTrCOnaF(-|Tf24^bKI&IpTcQqvdsn~fxOx4#ol8D z-3rdHOm#cDRK9RqzcMZP5<^2yFQh#8t*ojPv;-hOaF%`uj4Z>uRJ0 zl!t+*rMcQSmKjp;;I_oe@exXF=%6yy0kZrcR2F_25%Jo!1~ z+5Tx`a-v15qJ>mWK4#(2)Oh=HVF7cye7=xbv%2VJ?sp9svc8GiNxlz^g|jz! znDE}ixXuib(dAhR6?(XD`OzO(4RpeugXo;xTPZr151n`yeO)=%k$X0LpBI_e-b2Yo zf)y85XT{wY3_sINE-W^tn>^w=2)S(be_Ua2W!}pQS?Foc(!Z}e6v<6`PiJqCAoa{g zj@eSI`nA#Gki_pF%F4V|$^^p)sb^xQCrm7iJq+jm)}7J78t8Yg<@Z(0^s-K-y-;22 zg>$kpzn?xrF>&~^^v|~ZfBs2HHi7v)i=Z&~;T8%xl8IM5-iZB>8_u_&q;DvGeLC|1 ziXUPW@6H$u*xp*1=G933?)sxDiC)-`oS~#{Tx7!zTC|8!R93NDnQ3fj63@24zLsHF z?-}=8YUWmm5(y4-#Ai489izu5MJsd$PGO21w+Z~Q%x_8eX4Y#V@f*T$I9gFmXemLQ z!1h>h!=wqbwb7q1EA2A+e)?2^4<=hY0hOlhe>bXxm(5%^K>-)9xb4zkCW3+~2N-^Q z^~%R)sH_%)S#G@|9Mmh69gyxp_pdGuv(gJK`fqO`h5a38N-%kW*;ccu!Taq;eL6ko z9+Vlfb(5lz2Vt7E8s!pDi7Uida^RgGPq3}w8R?0JJ7NQyb`VHLwIehLw~?yZzrQa! z%n^FwLSC>z3tGeh(Mp3+-nRUO1+sc$>ZjnVod#Yw<2Pbt`e>mcq z@=a*W*P~bIX(g}9F;ee?c(IF5)M9&SU<43_-n`1N9-eB_9GOVSH!&F#+n8F}nCb2* zUad)n9iz#x8Ls7w;HTHiG0oq`bd=5NtWRp(mbrWYEWY~0?~AfBo<*BNv>)$5U+9Xx z_9lURq6YUKU?&sWaGVkGSZoyQ*9;2|_Uwi;(oTC2_>(=1zJ0j6CG0-J2qW-c1JfY_ zrlZ3-j#*st>Kl4u;}}Ww!hJc0%RQ@otgC%DV%#^r&JX2V^;>PLznGfpVU6Zk!yG&! z0%G2sW%+oQ&G|HVx3Les_ME7_2XyzoIwzHm?rZ`Sk2kSR{trv|9H-vB56Tkfo?Yrl zt2uaLGrie)W$X+eVmu+p+15@`o)3?Mm8%jYUs#4lsU%=%`c=jfvR@UPk2w>tlK_mU zb{f}L$Y*!+*3L`?`qguQO$`w*u`?Te@=Eyz808D}A(}eJAP^6yv6im~DB^Yl0$X+g z4Fs||hlzVnc42SDs~X!}gFw~>k@CFMxAqog;@2M!L7u4;4m0L@b@{-~2330h=t?oQ}?>AZ|(>7ej+Fv>+OlW0YPP5M3zSA?NlZtpm?7z}@+g}< z``m-AErRpnm}hrhnse(!vrM_5^THjyzKJF=VIDBY=4o}oj%8bT?q+#7>xB#Mn8+#j zjfLR{V)*fUvwe(o{>cm3+_=xLK%ntw6gSEtoGU-4rl7FJ8hy@uddQRj!Uy{J&VYDu zHBPb_5OUvgo9C6LM8VKC;@jr#ZIpYHsNUQf*p5Ngz&zGd6p$WAZr6k5#?o}#AxI`c zaa*g!yV-MPta+}EHUDmS4odRnSF|p6dx)_+4!+b-z=5*6b*s9-24-k7mYf@F(h!Pr z$6IE=O(xsY_1tVUYW&_m?8-^+bG1%~lZbC*aWPw!IU|n|q`RBu)9=rtmij$hZyvJ~ z)eAL6kM!ML;*p9Peo7r#Q67r^ROQ_7I z%yhsBQKI6VRHoCeunwbPwhM!7Tvq;*N|rU^4?amR2jH6Vok)9Kx}D8(w3H9_-8M9&Dkh-QVJ^2TS|WuyU%%d9xrwy*c_HH$ znZxi7UpqS99Nm!KozEC8Dy;2Z^HfW|r8z@CTGQ1~%03Ks)?C;e43V;Ef?{-IU7hD@ zFXOOnOvi%#rme10Ljgltbgw2hcaXT#e@1Rh5QGt?a{CJg>bvv(HjHio$hl}87j+bvP z+)vlzVk}oWc)V*^N4{jfI=@LYUvk-P{)-Y$7^gE!zuvX`?EY$(oSReV>%`>@1N)nx zVEEnGG zlW9O!CRCHBj&u%CJFXB}P>D}Fwh++lIraTYA%y009kwhrBKOMD+HtfDUDb@1 z9Whj>jmLF1sl}h+GSB)x+9-oxA>3Nwc{Jb|M`%+Sm3fz{VF)YE`>_{@*<7Gd3tG&D z3p~bO*QBe7i(E)(9Rw)#{Gb;nIGw_Dt!B(YM&p%>HT2fC^4xyh z`drEZ+sJ}qj8dYaN-_^{Uael(-F^F zYKY6c-eM=K5n(Gp4xd_-j2B2~L+X<#OSfjGIJk#H9JhoZkb-+4UfHXSJb86WY8SPH zSm-(VK_G8Wpp(Cy0`Rbb%pj6F3P9hurzvbXx4@4UDrm-@j~#~Gm>5Vt%1Nx(O0HHr z4+@b&?m-KZCFF^Dl-tMVh@=Trm;`d;I=|!frq01LBd| z^HAaq^=O7l=FX8oF4OC%eY^;ePbhV@pqThkP%sVtYFjq;wg8r2JY9luuRTmug?3rrW zNN90vsndLD|7QIA#kM0l&G`=kSQ9<+EU?od8e)&Q_JN1(Px~5&nl0Zhvl*(kE?XaM zM#n&Oa@gHV(J4QwPDY`4yqPv(h<>4Kf5Vq%c-k*vN zb-2?-E-o^%TJBlpJh>k|u6H)rb4}Z1BENPlGnT3!DdJJt zMv8jc&8G*+s5tJ)mo2r(3-mdma{Ap@djkRj*wm79EU;G7UAfhyFUc80&nsmcH@*)4*4i_Hk3Fonn$Os_PKI1 zG2QgLxw0I+y~+CNfE)d0s%CaLKipi`w!h3hzsJ`5oL31c+Z&P1xysh~yS!a_w(cEe zQP1bK)Yb|~HP=%8C2igH$q06dh*-ayU9z&Sm6bR{!^nUYTzW#jB`xh)tu%+}gCGvk zVS=w*n}3;@sMns{9uS=s)2um8bxBcAIZ65UNWB`m7(M;7`G44T2^T6k)=&)W{&Z72RC6P;U|C$_1v8SyAMgut-VXqTyus>gQ_)dRnFU4;+tHdn@<# zJh_Fk8PaR~`W4A{CC_FkUfSf&*Ke;+_shx)L-i}}9J!5ge|>d)~3 zOQ3bY zgQh5XX`6Phbbw`%UWOkGzy7j~G}l5PV{4L4$QgG3dmP3?{GXjt($nkfw9}XDRqZVI z+~#c(vBT;*UN>v0I(xM(;)h{)Uy@2feF!_)I`GOD$EC+EhUq8|js?B+!BBB(xoxeF zNo&gmDO*~mYHhV8sk8({cW6tRbDLv396pk*L7m2eLfF)T_Fp{id>|Dmea0p<-GqKE z`!YfwOI+q@7KIG&cXbvixxL-(+auq;nJ#yH&Oy9>RDj@n^b$R- z06UASj>r0lw27)}8_Hj-$g(p_QJkRK*sLb0W@R-KDP-41p8(b_Ew8JEFN0_oKp^s= z924I&QO#C81(`O?BXfh5%aiTA&@@*Yc(H?4_j864^9B;n#YTY^Q1q)Kb1kr;VG^8E z9NpPs=_X3!zo#i4h1HWUnuy0FFTS9Io;b@l`kZGo{skB<%>q1X4^>6uI4^Q?mdGGt=Hvir$@r-lQ;e$qZPpc)UP)^pMae@UA( zhF=%3{QhWe;4^W{UVo5d+I)eFYi77ExO$a@1_`FDJIAaQ^qJ3Y^eb4ubV!){vRZGE zeZTV<(xApKE+Ii4;yPQp>hp37Fd#|fgFTM@?$QbAI)g4W=xGUZz1;21F>&#&wISP2 zXMXWBt3ahZq<)7e*DWRJ5d z7d6r6K@|WNE_@rv(PFjQT>AX0awB^3B((AD? z-JYz51Nk$@R{=|7@N1eGp@{LkZmZyn7qt>GG7QeQ^iJkx9lAVwt4Qh6t5ym}~kW3M<_85w=_OR?$!Y_!{4GqbhaK%TtR(CNFMYbnY zcc590&c!SZx$un?>dZ*>b(hsglRnFLxzY0y#Y{=r{DL3{f*;<1vb`u8d_gC+wPxUI z?VPd@;s?S$HdQIRz?<2C+nl<84O7)j#(R2I7@&Wk;>myu@BlSfmoBUCU2x$-kwQeC zTl;Wq!J9zaVQ=nf3XQndtQp0%@{p=AnV&InQ9SqI?coCVn{0y zhS64mJ(!iiY!G_ntpR0sL(><1T@6KT3(wlm>(Tomki+}KluWOLx&jV!1mPpUzOi9L zozEMC32Lx9y=!jl#{R39(B?~7-BCI2 zGp~ru;gLa}UD#LOOXJ9OHrKy25xHy}cpOmmUZ*PZd2SF9VCn)TrLsvX>|95?b9U_u za2>?!6A>%cE2-Xwm9aXzmEamL0QzosSYp1m@UZPbv6DpFKQvV7F=7~Itc(fAcI=Z1 zd++wi`3VW+-VBi(%JDfG%e-xRB!R}2%UZgnF$83~Z{1$vUc*mA@Yfg0n`DJApaV+*Y~gOJF8-uD7*Y0#5vh6jY)a zh!RaLTRcatiBQx`sM=YC-iVeY>0zu$>zA;VS1B!Z4(zWH&tjPANuoxcH(VBZ1x7h; zghmEhpS7QbiNwstSGzrprG)~>2>YF=`s*P(&>D31c|5a!@^?KCt`oSTg^$hv(4QfW z^@rg5V5C%2Sz80`C<(Ef1VVv#H*KM5ol*X4Pgrx9tITCCfVjOBh|pF``anw{h3^lx zJb!DN(;C-ZI^l{7h0JHT!35l3B_eiC)RUUl=0ejpv6UEyN#j5`$!=31-;Mx4F5i$i zFoIyoZU<`%F5qnmI7uiN8BI6#eLFP)m^~+c`Z(_XU=guCFyZlSEzPr@+b|Q>r5jLE z5&5Bp%OyU$9UkjMocRE0RRZ+xj~_rF2@8w%yd*5Vnu{%a{i^m6*QktMpBXM)pufcG z^OMD97NZ@xV9?t#UM4oQyETE9pAA?&q<3UwWj8=**9ha%JoUz^@S??F zMepLMJ5J}Te|G5Y)-w0eglL99-=*mdSwq7Y!!hDp^R20=Pe~54;NqWL+UUxg{{Hrg zaIxcdB4CvcF>dzvl{%lk%(Ck`y#HhZw!2Pb2bHoW^@hP z&gj169n9J^Jc8Vs%4Tk{=HPX8$eX5NIS=o1t1{hiRtA*@e#(5Oe(UQ` zZ_($-hIqV70?I_)_Skx_TdW|mP&;NWB`XMej=(Qz;ugxHikGEK-MJnyh;UF z$~iH0F_#If^Djncb}BQl9RmF}7lZv$9cDzf78+polf$;w|3R}gb92wWp%j;kFCwfw zF}3O7iP&CfFc5Y1Fzi-{7Gng2dyjqZSaiRT-KfAq%GV7e-P|PB=pKHv7QYkpJjD*W z+y0)GVR^X8AQF}%w{98w(5*^2IG{6qL{N|SO*1|>Z>_dmb5>?_n=?QlLT{a~qihJB z4#5s*)*O8(?L}tU>teYujI_0E;hw)k`cBKH@`dEW{t=qgh7FgQ4s7;vp|*aI$;&T*85knHx6mh!gD7LXHW3Qbxa`$tB{qGc7uuNu{3HfH-%8G_z@6q|2J z>&Ao5@N_LKoS?~2;&cEVY-%L5n*8Poo7E)}56BV`=I>V;Yyn69tWxpw0*~!bGkceeodZ z=yAcCdW&v4UpO@gHd-RXmppF?SSSRhOpLleH$CY@Z8_MCI6G^8Iv&Htr3sjc5xt20 z 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 literal 37243 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 M1bvt#^2Fo+0V>GwoB#j- From e383c4dd8fdd68def66e9f331a6e07d51f59feb5 Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Sun, 7 Nov 2021 13:51:00 +0800 Subject: [PATCH 68/74] Yuichiro PPP --- docs/team/yuifuku1118.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/team/yuifuku1118.md b/docs/team/yuifuku1118.md index c97c3480e30..38e5b3da746 100644 --- a/docs/team/yuifuku1118.md +++ b/docs/team/yuifuku1118.md @@ -1,4 +1,3 @@ -- layout: page title: Yuichiro Fukushima's Project Portfolio Page --- @@ -30,7 +29,5 @@ Given below are my contributions to the project. * Added the all the user stories [\#35]() * **Community**: - * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]() - * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]()) - * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]()) + * PRs reviewed (with non-trivial review comments): [\#119](), [\#120](), [\#51](), [\#50]() From b417cac51b190d376590cda0d697486296f2cd2c Mon Sep 17 00:00:00 2001 From: ngchisern Date: Sun, 7 Nov 2021 15:56:46 +0800 Subject: [PATCH 69/74] Fix task's 'general' tag bug --- src/main/java/seedu/address/model/ModelManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index db2b674e94e..835955a7194 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -430,8 +430,8 @@ public void checkClientAndOrderRelation() throws DataConversionException { public void checkTaskAndOrderRelation() throws DataConversionException { ObservableList tasks = this.taskBook.getTaskList(); for (Task eachTask : tasks) { - Long id = eachTask.getTaskTag().getTagId(); - if (!this.orderBook.hasOrder(id)) { + long tagId = eachTask.getTagId(); + if (tagId != -1 && !this.orderBook.hasOrder(tagId)) { throw new DataConversionException( new IllegalValueException("Given Sales ID does not exist in the Order Book")); } From 094c029cedd25e1d2b50da5fab7f362ce269b5e1 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sun, 7 Nov 2021 15:59:37 +0800 Subject: [PATCH 70/74] Update Manual Testing section to match latest behavior --- docs/DeveloperGuide.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 56e3a8e921d..0c0db1b4f24 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -742,7 +742,7 @@ testers are expected to do more *exploratory* testing. 1. Download the jar file and copy into an empty folder. 1. Double-click the jar file.
- Expected: Shows the GUI with a set of sample clients, tasks and orders. The window size may not be optimum. + Expected: Shows the GUI with sample clients, tasks and orders. The window size may not be optimum. 1. Saving window preferences @@ -788,14 +788,17 @@ testers are expected to do more *exploratory* testing. 1. Prerequisite: The folder containing the jar file contains a `data` folder. 1. Delete the `data` folder then launch the app by double-clicking the jar file.
- Expected: Shows the GUI with a set of clients, tasks and orders. The window size may not be optimum. + Expected: Shows the GUI with sample clients, tasks and orders. The window size may not be optimum. 1. Dealing with corrupted data files - 1. Prerequisite: The folder containing the jar file contains a `data` folder, which contains `addressbook.json`, `salesBook.json` and `taskBook.json`. + 1. Prerequisite: The folder containing the jar file contains a `data` folder, which contains `addressBook.json`, `taskBook.json` and `salesBook.json`. - 1. Test case: Corrupt the `addressbook.json` file by deleting a closing curly bracket (`}`) or any other brackets.
- Expected: Shows the GUI with no clients, but with a previously saved set of tasks and orders. + 1. Test case: Corrupt the `addressBook.json` file by deleting a closing curly bracket (`}`) or any other brackets.
+ Expected: Shows the GUI without any data. - 1. Other files to corrupt: `salesBook.json` and `taskBook.json`
- Expected: Similar to previous. + 1. Test case: Corrupt the `taskBook.json` file by deleting a closing curly bracket (`}`) or any other brackets.
+ Expected: Shows the GUI without any tasks, but with previously saved clients and orders. + + 1. Test case: Corrupt the `salesBook.json` file by deleting a closing curly bracket (`}`) or any other brackets.
+ Expected: Shows the GUI without any data. From 3ce91da4f2d873fb4d4db1b20ae5f55ac14e0905 Mon Sep 17 00:00:00 2001 From: Tanishq4331 <62829987+Tanishq4331@users.noreply.github.com> Date: Sun, 7 Nov 2021 16:27:58 +0800 Subject: [PATCH 71/74] Explicitly define order ids in TypicalOrders --- .../java/seedu/address/testutil/TypicalOrders.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/seedu/address/testutil/TypicalOrders.java b/src/test/java/seedu/address/testutil/TypicalOrders.java index b043d3acbeb..7ac1cd4332c 100644 --- a/src/test/java/seedu/address/testutil/TypicalOrders.java +++ b/src/test/java/seedu/address/testutil/TypicalOrders.java @@ -17,15 +17,15 @@ public class TypicalOrders { public static final Order SALESORDER1 = new OrderBuilder().withCustomer("Josh") - .withDate("2021-09-18").withAmount("10").withLabel("testorder1").withIsComplete(true).build(); + .withDate("2021-09-18").withAmount("10").withId(1).withLabel("testorder1").withIsComplete(true).build(); public static final Order SALESORDER2 = new OrderBuilder().withCustomer("Mac") - .withDate("2021-09-19").withAmount("20").withIsComplete(true).withLabel("testorder2").build(); + .withDate("2021-09-19").withAmount("20").withId(2).withIsComplete(true).withLabel("testorder2").build(); public static final Order SALESORDER3 = new OrderBuilder().withCustomer("Clark") - .withDate("2021-09-20").withAmount("15").withIsComplete(true).withLabel("testorder3").build(); + .withDate("2021-09-20").withAmount("15").withId(3).withIsComplete(true).withLabel("testorder3").build(); public static final Order SALESORDER4 = new OrderBuilder().withCustomer("Justin").withLabel("testorder4") - .withDate("2021-09-20").withAmount("20").build(); + .withDate("2021-09-20").withAmount("20").withId(4).build(); public static final Order SALESORDER5 = new OrderBuilder().withCustomer("Stuart").withLabel("testorder5") - .withDate("2021-09-20").withAmount("5").withIsComplete(false).build(); + .withDate("2021-09-20").withAmount("5").withId(5).withIsComplete(false).build(); // Manually added - Order's details found in {@code CommandTestUtil} public static final Order ORDER1 = new OrderBuilder().withCustomer(VALID_CUSTOMER_SALE1) From dbfd6eada906a424eb1e1222e94ee74ae78f3ca1 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sun, 7 Nov 2021 16:28:53 +0800 Subject: [PATCH 72/74] Update Manual Testing - Saving Data --- docs/DeveloperGuide.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 0c0db1b4f24..e45a7a8aac8 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -792,7 +792,8 @@ testers are expected to do more *exploratory* testing. 1. Dealing with corrupted data files - 1. Prerequisite: The folder containing the jar file contains a `data` folder, which contains `addressBook.json`, `taskBook.json` and `salesBook.json`. + 1. Prerequisites: The folder containing the jar file contains a `data` folder, which contains `addressBook.json`, + `taskBook.json` and `salesBook.json`. 1. Test case: Corrupt the `addressBook.json` file by deleting a closing curly bracket (`}`) or any other brackets.
Expected: Shows the GUI without any data. @@ -800,5 +801,10 @@ testers are expected to do more *exploratory* testing. 1. Test case: Corrupt the `taskBook.json` file by deleting a closing curly bracket (`}`) or any other brackets.
Expected: Shows the GUI without any tasks, but with previously saved clients and orders. - 1. Test case: Corrupt the `salesBook.json` file by deleting a closing curly bracket (`}`) or any other brackets.
- Expected: Shows the GUI without any data. + 1. Test case: Corrupt the `salesBook.json` file by deleting a closing curly bracket (`}`) or any other brackets. + + 1. Scenario: All tasks have the 'General' tag.
+ Expected: Shows the GUI with previously saved clients and tasks. + + 1. Scenario: There exists at least one task tagged with an order ID.
+ Expected: Shows the GUI without any data. From 8cfede13a7a7675c46deedd89f49a525093ce4d6 Mon Sep 17 00:00:00 2001 From: GnohChengYi Date: Sun, 7 Nov 2021 16:40:08 +0800 Subject: [PATCH 73/74] Update Manual Testing - Saving data - Dealing with corrupted data --- docs/DeveloperGuide.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index e45a7a8aac8..8b5b587ce9b 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -796,8 +796,13 @@ testers are expected to do more *exploratory* testing. `taskBook.json` and `salesBook.json`. 1. Test case: Corrupt the `addressBook.json` file by deleting a closing curly bracket (`}`) or any other brackets.
- Expected: Shows the GUI without any data. - + + 1. Scenario: There exists at least one order, or there is at least one task tagged with an order ID.
+ Expected: Shows the GUI without any data. + + 1. Scenario: There are no orders, and all tasks have the `General` tag.
+ Expected: Shows the GUI without any clients or orders, but with previously saved tasks. + 1. Test case: Corrupt the `taskBook.json` file by deleting a closing curly bracket (`}`) or any other brackets.
Expected: Shows the GUI without any tasks, but with previously saved clients and orders. From 8f4b50d4e474f6f7518fb9ef76e1b64eb23ca27b Mon Sep 17 00:00:00 2001 From: Yuichiro Fukushima Date: Sun, 7 Nov 2021 16:45:57 +0800 Subject: [PATCH 74/74] fixing the links --- docs/team/yuifuku1118.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/team/yuifuku1118.md b/docs/team/yuifuku1118.md index 38e5b3da746..e8d26625cb8 100644 --- a/docs/team/yuifuku1118.md +++ b/docs/team/yuifuku1118.md @@ -22,12 +22,13 @@ Given below are my contributions to the project. * **Documentation**: * User Guide: - * Added documentation for the storage related features (i.e. `exit` and `clear`) [\#139]() + * Added documentation for the storage related features (i.e. `exit` and `clear`) [\#139](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/139) * Developer Guide: - * Added implementation details of the `storage` component.[\#135]() - * Added the all the user stories [\#35]() + * Added implementation details of the `storage` component.[\#135](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/135) + * Added the all the user stories [\#35](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/35) * **Community**: - * PRs reviewed (with non-trivial review comments): [\#119](), [\#120](), [\#51](), [\#50]() + * PRs reviewed (with non-trivial review comments): [\#289](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/289), + [\#270](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/270), [\#79](https://github.com/AY2122S1-CS2103T-W08-3/tp/pull/79)