From 659ae3ae924599178aa2e8b6eb3b1405337ebb26 Mon Sep 17 00:00:00 2001 From: Ang Jing Jie <86147552+ajjajjajjajj@users.noreply.github.com> Date: Fri, 17 Mar 2023 14:59:47 +0800 Subject: [PATCH 01/16] Revert "Revert "Update Transaction"" --- docs/UserGuide.md | 51 +++++ .../seedu/address/commons/core/Messages.java | 2 + src/main/java/seedu/address/logic/Logic.java | 4 + .../seedu/address/logic/LogicManager.java | 6 + .../commands/txncommands/AddTxnCommand.java | 59 ++++++ .../txncommands/DeleteTxnCommand.java | 56 +++++ .../commands/txncommands/EditTxnCommand.java | 197 ++++++++++++++++++ .../commands/txncommands/ListTxnCommand.java | 26 +++ .../logic/parser/AddressBookParser.java | 20 ++ .../seedu/address/logic/parser/CliSyntax.java | 5 + .../address/logic/parser/ParserUtil.java | 59 ++++++ .../txncommandparser/AddTxnCommandParser.java | 62 ++++++ .../DeleteTxnCommandParser.java | 29 +++ .../EditTxnCommandParser.java | 62 ++++++ .../java/seedu/address/model/AddressBook.java | 16 +- src/main/java/seedu/address/model/Model.java | 27 +-- .../seedu/address/model/ModelManager.java | 57 +++-- .../model/transaction/Description.java | 47 +++++ .../address/model/transaction/Owner.java | 60 ++++++ .../model/transaction/Transaction.java | 57 ++--- .../address/model/transaction/TxnStatus.java | 53 +++-- .../address/model/transaction/Value.java | 56 +++++ .../seedu/address/storage/JsonAdaptedTxn.java | 92 ++++++++ .../storage/JsonSerializableAddressBook.java | 19 +- .../duplicateTransactionAddressBook.json | 13 ++ .../invalidTransactionsAddressBook.json | 8 + .../typicalTransactionsAddressBook.json | 39 ++++ .../logic/commands/AddCommandTest.java | 29 +++ .../JsonSerializableAddressBookTest.java | 104 ++++----- 29 files changed, 1185 insertions(+), 130 deletions(-) create mode 100644 src/main/java/seedu/address/logic/commands/txncommands/AddTxnCommand.java create mode 100644 src/main/java/seedu/address/logic/commands/txncommands/DeleteTxnCommand.java create mode 100644 src/main/java/seedu/address/logic/commands/txncommands/EditTxnCommand.java create mode 100644 src/main/java/seedu/address/logic/commands/txncommands/ListTxnCommand.java create mode 100644 src/main/java/seedu/address/logic/parser/txncommandparser/AddTxnCommandParser.java create mode 100644 src/main/java/seedu/address/logic/parser/txncommandparser/DeleteTxnCommandParser.java create mode 100644 src/main/java/seedu/address/logic/parser/txncommandparser/EditTxnCommandParser.java create mode 100644 src/main/java/seedu/address/model/transaction/Description.java create mode 100644 src/main/java/seedu/address/model/transaction/Owner.java create mode 100644 src/main/java/seedu/address/model/transaction/Value.java create mode 100644 src/main/java/seedu/address/storage/JsonAdaptedTxn.java create mode 100644 src/test/data/JsonSerializableAddressBookTest/duplicateTransactionAddressBook.json create mode 100644 src/test/data/JsonSerializableAddressBookTest/invalidTransactionsAddressBook.json create mode 100644 src/test/data/JsonSerializableAddressBookTest/typicalTransactionsAddressBook.json diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 2f66d27c83b..86323238a0f 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -191,6 +191,57 @@ Examples: * `list` followed by `delete 2` deletes the 2nd person in the address book. * `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command. + +### Adding a transaction: `addtxn` + +Adds a transaction record to the address book. + +Format: `addtxn [td/DESCRIPTION] [tv/VALUE] [ts/STATUS] [to/OWNER]` + +
:bulb: **Tip:** +All field must be provided, and transaction status should be either 'open' or 'closed'. +
+ +Examples: +* `addtxn td/Sample Transaction tv/100 ts/open to/John Doe` + + +### Listing all transaction records : `listtxn` + +Shows a list of all transaction records in the sales book. + +Format: `listtxn` + + +### Editing a transaction record : `edittxn` + +Edits an existing transaction record in the sales book. + +Format: `edittxn INDEX [td/DESCRIPTION] [tv/VALUE] [ts/STATUS] [to/OWNER]​` + +* Edits the transaction record at the specified `INDEX`. +* The index refers to the index number shown in the displayed transaction list. The index **must be a positive integer** 1, 2, 3, …​ +* At least one of the optional fields must be provided. +* Existing values will be updated to the input values. + +Examples: +* `edittxn 1 ts/closed` Edits the transaction status of the 1st transaction record to be 'closed'. + + +### Deleting a transaction record : `deletetxn` + +Deletes the specified transaction record from the sales book. + +Format: `deletetxn INDEX` + +* Deletes the transaction record at the specified `INDEX`. +* The index refers to the index number shown in the displayed transaction list. +* The index **must be a positive integer** 1, 2, 3, …​ + +Examples: +* `listtxn` followed by `deletetxn 2` deletes the 2nd transaction record in the sales book. + + ### Clearing all entries : `clear` Clears all entries from the address book. diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java index 1deb3a1e469..4c93a8baf28 100644 --- a/src/main/java/seedu/address/commons/core/Messages.java +++ b/src/main/java/seedu/address/commons/core/Messages.java @@ -10,4 +10,6 @@ public class Messages { public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid"; public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!"; + public static final String MESSAGE_INVALID_TXN_DISPLAYED_INDEX = "The transaction index provided is invalid"; + } diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java index 92cd8fa605a..344730d76c5 100644 --- a/src/main/java/seedu/address/logic/Logic.java +++ b/src/main/java/seedu/address/logic/Logic.java @@ -9,6 +9,7 @@ import seedu.address.logic.parser.exceptions.ParseException; import seedu.address.model.ReadOnlyAddressBook; import seedu.address.model.person.Person; +import seedu.address.model.transaction.Transaction; /** * API of the Logic component @@ -33,6 +34,9 @@ public interface Logic { /** Returns an unmodifiable view of the filtered list of persons */ ObservableList getFilteredPersonList(); + /** Returns an unmodifiable view of the filtered list of transactions */ + ObservableList getFilteredTransactionList(); + /** * Returns the user prefs' address book file path. */ diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java index 9d9c6d15bdc..28a6e6ad8bc 100644 --- a/src/main/java/seedu/address/logic/LogicManager.java +++ b/src/main/java/seedu/address/logic/LogicManager.java @@ -15,6 +15,7 @@ import seedu.address.model.Model; import seedu.address.model.ReadOnlyAddressBook; import seedu.address.model.person.Person; +import seedu.address.model.transaction.Transaction; import seedu.address.storage.Storage; /** @@ -64,6 +65,11 @@ public ObservableList getFilteredPersonList() { return model.getFilteredPersonList(); } + @Override + public ObservableList getFilteredTransactionList() { + return model.getFilteredTransactionList(); + } + @Override public Path getAddressBookFilePath() { return model.getAddressBookFilePath(); diff --git a/src/main/java/seedu/address/logic/commands/txncommands/AddTxnCommand.java b/src/main/java/seedu/address/logic/commands/txncommands/AddTxnCommand.java new file mode 100644 index 00000000000..283590b4549 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/txncommands/AddTxnCommand.java @@ -0,0 +1,59 @@ +package seedu.address.logic.commands.txncommands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_DESCRIPTION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_OWNER; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_STATUS; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_VALUE; + +import seedu.address.logic.commands.Command; +import seedu.address.logic.commands.CommandResult; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.transaction.Transaction; + +/** + * Add command for transactions + */ +public class AddTxnCommand extends Command { + public static final String COMMAND_WORD = "addtxn"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a transaction to the sales book. " + + "Parameters: " + + PREFIX_TXN_DESCRIPTION + "DESCRIPTION " + + PREFIX_TXN_VALUE + "VALUE " + + PREFIX_TXN_STATUS + "STATUS " + + PREFIX_TXN_OWNER + "OWNER"; + + public static final String MESSAGE_SUCCESS = "New transaction record added: %1$s"; + public static final String MESSAGE_DUPLICATE_TRANSACTION = + "This transaction record already exists in the sales book"; + + private final Transaction toAdd; + + /** + * Creates an AddTxnCommand to add the specified {@code Transaction} + */ + public AddTxnCommand(Transaction transaction) { + requireNonNull(transaction); + toAdd = transaction; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + if (model.hasTransaction(toAdd)) { + throw new CommandException(MESSAGE_DUPLICATE_TRANSACTION); + } + + model.addTransaction(toAdd); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof AddTxnCommand // instanceof handles nulls + && toAdd.equals(((AddTxnCommand) other).toAdd)); + } +} diff --git a/src/main/java/seedu/address/logic/commands/txncommands/DeleteTxnCommand.java b/src/main/java/seedu/address/logic/commands/txncommands/DeleteTxnCommand.java new file mode 100644 index 00000000000..7fdde1f710c --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/txncommands/DeleteTxnCommand.java @@ -0,0 +1,56 @@ +package seedu.address.logic.commands.txncommands; + +import static java.util.Objects.requireNonNull; + +import java.util.List; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.Command; +import seedu.address.logic.commands.CommandResult; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.transaction.Transaction; + + + +/** + * Deletes a transaction identified using it's displayed index from the sales book. + */ +public class DeleteTxnCommand extends Command { + public static final String COMMAND_WORD = "deletetxn"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + + ": Deletes the transaction identified by the index number used in the displayed transaction list.\n" + + "Parameters: INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + " 1"; + + public static final String MESSAGE_DELETE_TRANSACTION_SUCCESS = "Deleted Transaction: %1$s"; + + private final Index targetIndex; + + public DeleteTxnCommand(Index targetIndex) { + this.targetIndex = targetIndex; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredTransactionList(); + + if (targetIndex.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_TXN_DISPLAYED_INDEX); + } + + Transaction txnToDelete = lastShownList.get(targetIndex.getZeroBased()); + model.deleteTransaction(txnToDelete); + return new CommandResult(String.format(MESSAGE_DELETE_TRANSACTION_SUCCESS, txnToDelete)); + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof DeleteTxnCommand // instanceof handles nulls + && targetIndex.equals(((DeleteTxnCommand) other).targetIndex)); // state check + } +} diff --git a/src/main/java/seedu/address/logic/commands/txncommands/EditTxnCommand.java b/src/main/java/seedu/address/logic/commands/txncommands/EditTxnCommand.java new file mode 100644 index 00000000000..5f41ca042fb --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/txncommands/EditTxnCommand.java @@ -0,0 +1,197 @@ +package seedu.address.logic.commands.txncommands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_DESCRIPTION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_OWNER; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_STATUS; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_VALUE; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TRANSACTIONS; + +import java.util.List; +import java.util.Optional; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.commons.util.CollectionUtil; +import seedu.address.logic.commands.Command; +import seedu.address.logic.commands.CommandResult; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.transaction.Description; +import seedu.address.model.transaction.Owner; +import seedu.address.model.transaction.Transaction; +import seedu.address.model.transaction.TxnStatus; +import seedu.address.model.transaction.Value; + +/** + * Edits the details of an existing transaction in the sales book. + */ +public class EditTxnCommand extends Command { + public static final String COMMAND_WORD = "edittxn"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the transaction identified " + + "by the index number used in the displayed transaction list. " + + "Existing values will be overwritten by the input values.\n" + + "Parameters: INDEX (must be a positive integer) " + + "[" + PREFIX_TXN_DESCRIPTION + "DESCRIPTION] " + + "[" + PREFIX_TXN_VALUE + "VALUE] " + + "[" + PREFIX_TXN_OWNER + "OWNER] " + + "[" + PREFIX_TXN_STATUS + "STATUS]"; + public static final String MESSAGE_EDIT_TRANSACTION_SUCCESS = "Edited Transaction: %1$s"; + public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided."; + public static final String MESSAGE_DUPLICATE_TRANSACTION = "This transaction already exists in the sales book."; + + private final Index index; + private final EditTxnCommand.EditTxnDescriptor editTxnDescriptor; + + /** + * @param index of the person in the filtered person list to edit + * @param editTxnDescriptor details to edit the person with + */ + public EditTxnCommand(Index index, EditTxnCommand.EditTxnDescriptor editTxnDescriptor) { + requireNonNull(index); + requireNonNull(editTxnDescriptor); + + this.index = index; + this.editTxnDescriptor = new EditTxnCommand.EditTxnDescriptor(editTxnDescriptor); + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredTransactionList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_TXN_DISPLAYED_INDEX); + } + + Transaction transactionToEdit = lastShownList.get(index.getZeroBased()); + Transaction editedTransaction = createEditedTransaction(transactionToEdit, editTxnDescriptor); + + if (!transactionToEdit.isSameTransaction(editedTransaction) && model.hasTransaction(editedTransaction)) { + throw new CommandException(MESSAGE_DUPLICATE_TRANSACTION); + } + + model.setTransaction(transactionToEdit, editedTransaction); + model.updateFilteredTransactionList(PREDICATE_SHOW_ALL_TRANSACTIONS); + return new CommandResult(String.format(MESSAGE_EDIT_TRANSACTION_SUCCESS, editedTransaction)); + } + + /** + * Creates and returns a {@code Person} with the details of {@code personToEdit} + * edited with {@code editPersonDescriptor}. + */ + private static Transaction createEditedTransaction(Transaction transactionToEdit, + EditTxnCommand.EditTxnDescriptor editTxnDescriptor) { + assert transactionToEdit != null; + + Description updatedDescription = editTxnDescriptor.getDescription().orElse(transactionToEdit.getDescription()); + Owner updatedOwner = editTxnDescriptor.getOwner().orElse(transactionToEdit.getOwner()); + TxnStatus updatedStatus = editTxnDescriptor.getStatus().orElse(transactionToEdit.getStatus()); + Value updatedValue = editTxnDescriptor.getValue().orElse(transactionToEdit.getValue()); + + return new Transaction(updatedDescription, updatedValue, updatedStatus, updatedOwner); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditTxnCommand)) { + return false; + } + + // state check + EditTxnCommand e = (EditTxnCommand) other; + return index.equals(e.index) + && editTxnDescriptor.equals(e.editTxnDescriptor); + } + + /** + * Stores the details to edit the person with. Each non-empty field value will replace the + * corresponding field value of the person. + */ + public static class EditTxnDescriptor { + private Description description; + private Owner owner; + private TxnStatus status; + private Value value; + + public EditTxnDescriptor() {} + + /** + * Copy constructor. + * A defensive copy of {@code tags} is used internally. + */ + public EditTxnDescriptor(EditTxnCommand.EditTxnDescriptor toCopy) { + setDescription(toCopy.description); + setOwner(toCopy.owner); + setStatus(toCopy.status); + setValue(toCopy.value); + } + + /** + * Returns true if at least one field is edited. + */ + public boolean isAnyFieldEdited() { + return CollectionUtil.isAnyNonNull(description, owner, status, value); + } + + public void setDescription(Description description) { + this.description = description; + } + + public Optional getDescription() { + return Optional.ofNullable(description); + } + + public void setOwner(Owner owner) { + this.owner = owner; + } + + public Optional getOwner() { + return Optional.ofNullable(owner); + } + + public void setStatus(TxnStatus status) { + this.status = status; + } + + public Optional getStatus() { + return Optional.ofNullable(status); + } + + public void setValue(Value value) { + this.value = value; + } + + public Optional getValue() { + return Optional.ofNullable(value); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditTxnCommand.EditTxnDescriptor)) { + return false; + } + + // state check + EditTxnCommand.EditTxnDescriptor e = (EditTxnCommand.EditTxnDescriptor) other; + + return getDescription().equals(e.getDescription()) + && getOwner().equals(e.getOwner()) + && getStatus().equals(e.getStatus()) + && getValue().equals(e.getValue()); + } + } +} diff --git a/src/main/java/seedu/address/logic/commands/txncommands/ListTxnCommand.java b/src/main/java/seedu/address/logic/commands/txncommands/ListTxnCommand.java new file mode 100644 index 00000000000..112cce4ae01 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/txncommands/ListTxnCommand.java @@ -0,0 +1,26 @@ +package seedu.address.logic.commands.txncommands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TRANSACTIONS; + +import seedu.address.logic.commands.Command; +import seedu.address.logic.commands.CommandResult; +import seedu.address.model.Model; + +/** + * Lists all transactions in the address book to the user. + */ +public class ListTxnCommand extends Command { + + public static final String COMMAND_WORD = "listtxn"; + + public static final String MESSAGE_SUCCESS = "Listed all transactions"; + + + @Override + public CommandResult execute(Model model) { + requireNonNull(model); + model.updateFilteredTransactionList(PREDICATE_SHOW_ALL_TRANSACTIONS); + return new CommandResult(MESSAGE_SUCCESS); + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index eb47e91c20d..bccee7dbad6 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -18,7 +18,15 @@ import seedu.address.logic.commands.ListCommand; import seedu.address.logic.commands.RemarkCommand; import seedu.address.logic.commands.StatusCommand; +import seedu.address.logic.commands.txncommands.AddTxnCommand; +import seedu.address.logic.commands.txncommands.DeleteTxnCommand; +import seedu.address.logic.commands.txncommands.EditTxnCommand; +import seedu.address.logic.commands.txncommands.ListTxnCommand; import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.logic.parser.txncommandparser.AddTxnCommandParser; +import seedu.address.logic.parser.txncommandparser.DeleteTxnCommandParser; +import seedu.address.logic.parser.txncommandparser.EditTxnCommandParser; + /** * Parses user input. @@ -80,6 +88,18 @@ public Command parseCommand(String userInput) throws ParseException { case StatusCommand.COMMAND_WORD: return new StatusCommandParser().parse(arguments); + case AddTxnCommand.COMMAND_WORD: + return new AddTxnCommandParser().parse(arguments); + + case DeleteTxnCommand.COMMAND_WORD: + return new DeleteTxnCommandParser().parse(arguments); + + case EditTxnCommand.COMMAND_WORD: + return new EditTxnCommandParser().parse(arguments); + + case ListTxnCommand.COMMAND_WORD: + return new ListTxnCommand(); + default: throw new ParseException(MESSAGE_UNKNOWN_COMMAND); } diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java index af7498d645b..5d1dbf9112c 100644 --- a/src/main/java/seedu/address/logic/parser/CliSyntax.java +++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java @@ -19,5 +19,10 @@ public class CliSyntax { public static final Prefix PREFIX_REMARK = new Prefix("r/"); public static final Prefix PREFIX_STATUS_ASSIGN = new Prefix("s/"); public static final Prefix PREFIX_STATUS_FIND = new Prefix("f/"); + public static final Prefix PREFIX_TXN_DESCRIPTION = new Prefix("td/"); + public static final Prefix PREFIX_TXN_STATUS = new Prefix("ts/"); + public static final Prefix PREFIX_TXN_VALUE = new Prefix("tv/"); + public static final Prefix PREFIX_TXN_OWNER = new Prefix("to/"); + } diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index f9a607d6c18..fee8577a75e 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -2,6 +2,7 @@ import static java.util.Objects.requireNonNull; +//import java.time.format.DecimalStyle; import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -19,6 +20,12 @@ import seedu.address.model.person.Occupation; import seedu.address.model.person.Phone; import seedu.address.model.tag.Tag; +import seedu.address.model.transaction.Description; +import seedu.address.model.transaction.Owner; +import seedu.address.model.transaction.TxnStatus; +import seedu.address.model.transaction.Value; + +//import javax.xml.validation.Validator; /** * Contains utility methods used for parsing strings in the various *Parser classes. @@ -191,4 +198,56 @@ public static Industry parseIndustry(String industry) throws ParseException { } return new Industry(industry); } + + /** + * Parses a {@code String description} into a {@code Description}. + * + * @throws ParseException if the given {@code description} is invalid. + */ + public static Description parseDescription(String description) throws ParseException { + requireNonNull(description); + if (!Description.isValidDescription(description)) { + throw new ParseException(Description.MESSAGE_CONSTRAINTS); + } + return new Description(description); + } + + /** + * Parses a {@code String status} into a {@code TxnStatus}. + * + * @throws ParseException if the given {@code txnStatus} is invalid. + */ + public static TxnStatus parseTxnStatus(String status) throws ParseException { + requireNonNull(status); + if (!TxnStatus.isValidTxnStatus(status)) { + throw new ParseException(TxnStatus.MESSAGE_CONSTRAINTS); + } + return new TxnStatus(status); + } + + /** + * Parses a {@code String value} into a {@code Value}. + * + * @throws ParseException if the given {@code value} is invalid. + */ + public static Value parseValue(String value) throws ParseException { + requireNonNull(value); + if (!Value.isValidValue(value)) { + throw new ParseException(Value.MESSAGE_CONSTRAINTS); + } + return new Value(value); + } + + /** + * Parses a {@code String value} into a {@code Value}. + * + * @throws ParseException if the given {@code value} is invalid. + */ + public static Owner parseOwner(String owner) throws ParseException { + requireNonNull(owner); + if (!Owner.isValidName(owner)) { + throw new ParseException(Owner.MESSAGE_CONSTRAINTS); + } + return new Owner(owner); + } } diff --git a/src/main/java/seedu/address/logic/parser/txncommandparser/AddTxnCommandParser.java b/src/main/java/seedu/address/logic/parser/txncommandparser/AddTxnCommandParser.java new file mode 100644 index 00000000000..145643c4997 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/txncommandparser/AddTxnCommandParser.java @@ -0,0 +1,62 @@ +package seedu.address.logic.parser.txncommandparser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_DESCRIPTION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_OWNER; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_STATUS; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_VALUE; + +import java.util.stream.Stream; + +import seedu.address.logic.commands.txncommands.AddTxnCommand; +import seedu.address.logic.parser.ArgumentMultimap; +import seedu.address.logic.parser.ArgumentTokenizer; +import seedu.address.logic.parser.Parser; +import seedu.address.logic.parser.ParserUtil; +import seedu.address.logic.parser.Prefix; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.transaction.Description; +import seedu.address.model.transaction.Owner; +import seedu.address.model.transaction.Transaction; +import seedu.address.model.transaction.TxnStatus; +import seedu.address.model.transaction.Value; + +/** + * Parses input arguments and creates a new AddTxnCommand object + */ + +public class AddTxnCommandParser implements Parser { + /** + * Parses the given {@code String} of arguments in the context of the AddTxnCommand + * and returns an AddTxnCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public AddTxnCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_TXN_DESCRIPTION, PREFIX_TXN_STATUS, PREFIX_TXN_VALUE, + PREFIX_TXN_OWNER); + if (!arePrefixesPresent(argMultimap, PREFIX_TXN_DESCRIPTION, PREFIX_TXN_STATUS, PREFIX_TXN_VALUE, + PREFIX_TXN_OWNER) + || !argMultimap.getPreamble().isEmpty()) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddTxnCommand.MESSAGE_USAGE)); + } + + Description description = ParserUtil.parseDescription(argMultimap.getValue(PREFIX_TXN_DESCRIPTION).get()); + TxnStatus status = ParserUtil.parseTxnStatus(argMultimap.getValue(PREFIX_TXN_STATUS).get()); + Value value = ParserUtil.parseValue(argMultimap.getValue(PREFIX_TXN_VALUE).get()); + Owner owner = ParserUtil.parseOwner(argMultimap.getValue(PREFIX_TXN_OWNER).get()); + + + Transaction transaction = new Transaction(description, value, status, owner); + + return new AddTxnCommand(transaction); + } + + /** + * Returns true if none of the prefixes contains empty {@code Optional} values in the given + * {@code ArgumentMultimap}. + */ + private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) { + return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent()); + } +} diff --git a/src/main/java/seedu/address/logic/parser/txncommandparser/DeleteTxnCommandParser.java b/src/main/java/seedu/address/logic/parser/txncommandparser/DeleteTxnCommandParser.java new file mode 100644 index 00000000000..e34b7d88b95 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/txncommandparser/DeleteTxnCommandParser.java @@ -0,0 +1,29 @@ +package seedu.address.logic.parser.txncommandparser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.txncommands.DeleteTxnCommand; +import seedu.address.logic.parser.Parser; +import seedu.address.logic.parser.ParserUtil; +import seedu.address.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new DeleteTxnCommand object + */ +public class DeleteTxnCommandParser implements Parser { + /** + * Parses the given {@code String} of arguments in the context of the DeleteTxnCommand + * and returns a DeleteTxnCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public DeleteTxnCommand parse(String args) throws ParseException { + try { + Index index = ParserUtil.parseIndex(args); + return new DeleteTxnCommand(index); + } catch (ParseException pe) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteTxnCommand.MESSAGE_USAGE), pe); + } + } +} diff --git a/src/main/java/seedu/address/logic/parser/txncommandparser/EditTxnCommandParser.java b/src/main/java/seedu/address/logic/parser/txncommandparser/EditTxnCommandParser.java new file mode 100644 index 00000000000..1bdc8866f4c --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/txncommandparser/EditTxnCommandParser.java @@ -0,0 +1,62 @@ +package seedu.address.logic.parser.txncommandparser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_DESCRIPTION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_OWNER; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_STATUS; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TXN_VALUE; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.txncommands.EditTxnCommand; +import seedu.address.logic.parser.ArgumentMultimap; +import seedu.address.logic.parser.ArgumentTokenizer; +import seedu.address.logic.parser.Parser; +import seedu.address.logic.parser.ParserUtil; +import seedu.address.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new EditTxnCommand object + */ +public class EditTxnCommandParser implements Parser { + /** + * Parses the given {@code String} of arguments in the context of the EditTxnCommand + * and returns an EditTxnCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public EditTxnCommand parse(String args) throws ParseException { + requireNonNull(args); + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_TXN_DESCRIPTION, PREFIX_TXN_OWNER, PREFIX_TXN_STATUS, + PREFIX_TXN_VALUE); + + Index index; + + try { + index = ParserUtil.parseIndex(argMultimap.getPreamble()); + } catch (ParseException pe) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditTxnCommand.MESSAGE_USAGE), pe); + } + + EditTxnCommand.EditTxnDescriptor editTxnDescriptor = new EditTxnCommand.EditTxnDescriptor(); + if (argMultimap.getValue(PREFIX_TXN_DESCRIPTION).isPresent()) { + editTxnDescriptor.setDescription(ParserUtil.parseDescription( + argMultimap.getValue(PREFIX_TXN_DESCRIPTION).get())); + } + if (argMultimap.getValue(PREFIX_TXN_OWNER).isPresent()) { + editTxnDescriptor.setOwner(ParserUtil.parseOwner(argMultimap.getValue(PREFIX_TXN_OWNER).get())); + } + if (argMultimap.getValue(PREFIX_TXN_STATUS).isPresent()) { + editTxnDescriptor.setStatus(ParserUtil.parseTxnStatus(argMultimap.getValue(PREFIX_TXN_STATUS).get())); + } + if (argMultimap.getValue(PREFIX_TXN_VALUE).isPresent()) { + editTxnDescriptor.setValue(ParserUtil.parseValue(argMultimap.getValue(PREFIX_TXN_VALUE).get())); + } + if (!editTxnDescriptor.isAnyFieldEdited()) { + throw new ParseException(EditTxnCommand.MESSAGE_NOT_EDITED); + } + + return new EditTxnCommand(index, editTxnDescriptor); + } + +} diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java index 451248b803f..4fa4bfbf4a1 100644 --- a/src/main/java/seedu/address/model/AddressBook.java +++ b/src/main/java/seedu/address/model/AddressBook.java @@ -123,12 +123,15 @@ public boolean hasTransaction(Transaction transaction) { * Adds a given transaction to the transaction list. * A transaction must have an association with a Person. * A person may have zero to many transactions. + * * @param t */ - public void addTransaction(Transaction t, Person customer) { - requireAllNonNull(t, customer); + public void addTransaction(Transaction t) { + requireAllNonNull(t); - personTransactionRelation.addRelation(t, customer); + //personTransactionRelation.addRelation(t); + //TODO: Add customer-transaction relationship + transactions.add(t); } @@ -174,11 +177,12 @@ public ObservableList getTransactionList() { public boolean equals(Object other) { return other == this // short circuit if same object || (other instanceof AddressBook // instanceof handles nulls - && persons.equals(((AddressBook) other).persons)); + && persons.equals(((AddressBook) other).persons) + && transactions.equals(((AddressBook) other).transactions)); } @Override public int hashCode() { - return persons.hashCode(); - } //TODO: check latera + return persons.hashCode() + transactions.hashCode(); + } //TODO: check later } diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index cdfa02977e1..7169bade870 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -78,19 +78,19 @@ public interface Model { */ void setPerson(Person target, Person editedPerson); - // void hasTransaction(Transaction transaction); - // - // void addTransaction(Transaction transaction, Person owner); - // - // void deleteTransaction(Transaction transaction); - // - // void setTransaction(Transaction target, Transaction editedTxn); + boolean hasTransaction(Transaction transaction); + + void addTransaction(Transaction transaction); + + void deleteTransaction(Transaction transaction); + + void setTransaction(Transaction target, Transaction editedTxn); /** Returns an unmodifiable view of the filtered person list */ ObservableList getFilteredPersonList(); - ///** Returns an unmodifiable view of the filtered transaction list */ - //ObservableList getFilteredTransactionList(); + /** Returns an unmodifiable view of the filtered transaction list */ + ObservableList getFilteredTransactionList(); /** * Updates the filter of the filtered person list to filter by the given {@code predicate}. @@ -98,8 +98,9 @@ public interface Model { */ void updateFilteredPersonList(Predicate predicate); - ///** - //* Updates the filter of the filtered transaction list to filter by the given {@code predicate} - //*/ - //void updateFilteredTransactionsList(Predicate predicate); + /** + * Updates the filter of the filtered transaction list to filter by the given {@code predicate} + */ + void updateFilteredTransactionList(Predicate predicate); + } diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 6466324d705..642c67ab88d 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -7,6 +7,7 @@ import java.util.function.Predicate; import java.util.logging.Logger; +//import com.fasterxml.jackson.databind.ObjectWriter; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; import seedu.address.commons.core.GuiSettings; @@ -110,29 +111,31 @@ public void addPerson(Person person) { @Override public void setPerson(Person target, Person editedPerson) { requireAllNonNull(target, editedPerson); - addressBook.setPerson(target, editedPerson); } - // @Override - // public void hasTransaction(Transaction transaction) { - // // implementation here - // } - // - // @Override - // public void addTransaction(Transaction transaction, Person owner) { - // // implementation here - // } - // - // @Override - // public void deleteTransaction(Transaction transaction) { - // // implementation here - // } - // - // @Override - // public void setTransaction(Transaction target, Transaction editedTxn) { - // // implementation here - // } + @Override + public boolean hasTransaction(Transaction transaction) { + requireNonNull(transaction); + return addressBook.hasTransaction(transaction); + } + + @Override + public void addTransaction(Transaction transaction) { + addressBook.addTransaction(transaction); + updateFilteredTransactionList(PREDICATE_SHOW_ALL_TRANSACTIONS); + } + + @Override + public void deleteTransaction(Transaction target) { + addressBook.removeTransaction(target); + } + + @Override + public void setTransaction(Transaction target, Transaction editedTxn) { + requireAllNonNull(target, editedTxn); + addressBook.setTransaction(target, editedTxn); + } //=========== Filtered Person List Accessors ============================================================= @@ -150,6 +153,11 @@ public ObservableList getFilteredPersonList() { //return filteredTransactions; //} + @Override + public ObservableList getFilteredTransactionList() { + return filteredTransactions; + } + @Override public void updateFilteredPersonList(Predicate predicate) { requireNonNull(predicate); @@ -161,6 +169,12 @@ public void updateFilteredPersonList(Predicate predicate) { // implementation here //} + @Override + public void updateFilteredTransactionList(Predicate predicate) { + requireNonNull(predicate); + filteredTransactions.setPredicate(predicate); + } + @Override public boolean equals(Object obj) { // short circuit if same object @@ -177,7 +191,8 @@ public boolean equals(Object obj) { ModelManager other = (ModelManager) obj; return addressBook.equals(other.addressBook) && userPrefs.equals(other.userPrefs) - && filteredPersons.equals(other.filteredPersons); + && filteredPersons.equals(other.filteredPersons) + && filteredTransactions.equals(other.filteredTransactions); } } diff --git a/src/main/java/seedu/address/model/transaction/Description.java b/src/main/java/seedu/address/model/transaction/Description.java new file mode 100644 index 00000000000..98cd2e5b453 --- /dev/null +++ b/src/main/java/seedu/address/model/transaction/Description.java @@ -0,0 +1,47 @@ +package seedu.address.model.transaction; + +import static java.util.Objects.requireNonNull; + +/** + * Represents a Transaction's description in the address book. + * Guarantees: immutable; + */ +public class Description { + public static final String MESSAGE_CONSTRAINTS = + "Description should not be blank"; + + public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*"; + public final String value; + + /** + * Class constructor. + * @param description input description. + */ + public Description(String description) { + requireNonNull(description); + value = description; + } + + public static boolean isValidDescription(String test) { + return test.matches(VALIDATION_REGEX); + } + + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Description // instanceof handles nulls + && value.equals(((Description) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } + +} diff --git a/src/main/java/seedu/address/model/transaction/Owner.java b/src/main/java/seedu/address/model/transaction/Owner.java new file mode 100644 index 00000000000..c45b67e2c05 --- /dev/null +++ b/src/main/java/seedu/address/model/transaction/Owner.java @@ -0,0 +1,60 @@ +package seedu.address.model.transaction; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.AppUtil.checkArgument; + +import seedu.address.model.person.Name; + +/** + * Represents a Transaction's owner in the address book. + * Guarantees: immutable; is valid as declared in {@link #isValidName(String)} + */ +public class Owner { + public static final String MESSAGE_CONSTRAINTS = + "Owner name should only contain alphanumeric characters and spaces, and it should not be blank"; + + /* + * The first character of the address must not be a whitespace, + * otherwise " " (a blank string) becomes a valid input. + */ + public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*"; + + public final String fullName; + + /** + * Constructs a {@code Owner}. + * + * @param name A valid name. + */ + public Owner(String name) { + requireNonNull(name); + checkArgument(isValidName(name), MESSAGE_CONSTRAINTS); + fullName = name; + } + + /** + * Returns true if a given string is a valid name. + */ + public static boolean isValidName(String test) { + return test.matches(VALIDATION_REGEX); + } + + + @Override + public String toString() { + return fullName; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Name // instanceof handles nulls + && fullName.equals(((Name) other).fullName)); // state check + } + + @Override + public int hashCode() { + return fullName.hashCode(); + } + +} diff --git a/src/main/java/seedu/address/model/transaction/Transaction.java b/src/main/java/seedu/address/model/transaction/Transaction.java index f1abd408b47..d0e6c6b431f 100644 --- a/src/main/java/seedu/address/model/transaction/Transaction.java +++ b/src/main/java/seedu/address/model/transaction/Transaction.java @@ -1,11 +1,11 @@ package seedu.address.model.transaction; + +//import javax.management.Descriptor; import static seedu.address.commons.util.CollectionUtil.requireAllNonNull; -import java.math.BigDecimal; import java.util.Objects; - /** * Represents a Transaction in the sales book. * Guarantees: details are present and not null, field values are validated, immutable. @@ -13,38 +13,30 @@ public class Transaction { - private final String description; - private final BigDecimal value; + private final Description description; + private final Value value; private final TxnStatus status; + private final Owner owner; /** - * Constuctor - * @param description description for txn - * @param value txn amount + * Constructor + * @param description transaction descriptions + * @param value transaction amounts + * @param txnStatus transaction status */ - - public Transaction(String description, BigDecimal value) { - requireAllNonNull(description, value); + public Transaction(Description description, Value value, TxnStatus txnStatus, Owner owner) { + requireAllNonNull(description, value, txnStatus, owner); this.description = description; this.value = value; - this.status = new TxnStatus(); + this.status = txnStatus; + this.owner = owner; } - /** - * Constructor with the additional specification of whether the transaction is closed. - */ - private Transaction(String description, BigDecimal value, boolean isClosed) { - requireAllNonNull(description, value); - this.description = description; - this.value = value; - this.status = new TxnStatus(isClosed); - } - - public String getDescription() { + public Description getDescription() { return description; } - public BigDecimal getValue() { + public Value getValue() { return value; } @@ -52,6 +44,11 @@ public TxnStatus getStatus() { return status; } + public Owner getOwner() { + return owner; + } + + /** * Returns true if the other transaction has the same description and value. */ @@ -62,7 +59,9 @@ public boolean isSameTransaction(Transaction other) { return other != null && other.getDescription().equals(description) - && other.getValue().equals(value); + && other.getValue().equals(value) + && other.getStatus().equals(status) + && other.getOwner().equals(owner); } /** @@ -82,12 +81,13 @@ public boolean equals(Object other) { Transaction otherTransaction = (Transaction) other; return otherTransaction.getDescription().equals(getDescription()) && otherTransaction.getValue().equals(getValue()) - && otherTransaction.getStatus().equals(getStatus()); + && otherTransaction.getStatus().equals(getStatus()) + && otherTransaction.getOwner().equals(getOwner()); } @Override public int hashCode() { // use this method for custom fields hashing instead of implementing your own - return Objects.hash(description, value, status); + return Objects.hash(description, value, status, owner); } @Override @@ -98,7 +98,10 @@ public String toString() { .append("; Value: ") .append(getValue()) .append("; Status: ") - .append(getStatus()); + .append(getStatus()) + .append("; Owner: ") + .append(getOwner()); + return builder.toString(); } } diff --git a/src/main/java/seedu/address/model/transaction/TxnStatus.java b/src/main/java/seedu/address/model/transaction/TxnStatus.java index d7c7a7627f5..9f9cecc7f26 100644 --- a/src/main/java/seedu/address/model/transaction/TxnStatus.java +++ b/src/main/java/seedu/address/model/transaction/TxnStatus.java @@ -1,5 +1,9 @@ package seedu.address.model.transaction; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.AppUtil.checkArgument; + import java.time.LocalDateTime; /** @@ -7,23 +11,23 @@ */ public class TxnStatus { - private final boolean isClosed; - private final LocalDateTime lastUpdate; + public static final String MESSAGE_CONSTRAINTS = + "Transaction status should only be open or closed, and it should not be blank"; - /** - * Default constructor, constructs an new open transaction - */ - public TxnStatus() { - this.isClosed = false; - this.lastUpdate = LocalDateTime.now(); - } + /* The input should be "open" or "closed" */ + public static final String VALIDATION_REGEX = ".*\\bopen\\b|.*\\bclosed\\b"; + + public final String value; + public final LocalDateTime lastUpdate; /** - * Constructor to construct a transaction with specified status - * @param isClosed boolean, if the transaction is done + * Construct a {@code TxnStatus}. + * @param isClosed a valid transaction status */ - public TxnStatus(boolean isClosed) { - this.isClosed = isClosed; + public TxnStatus(String isClosed) { + requireNonNull(isClosed); + checkArgument(isValidTxnStatus(isClosed), MESSAGE_CONSTRAINTS); + this.value = isClosed; this.lastUpdate = LocalDateTime.now(); } @@ -32,7 +36,10 @@ public TxnStatus(boolean isClosed) { * @return True if the transaction is closed. */ public boolean isClosed() { - return isClosed; + return value.equals("Closed"); + } + public static boolean isValidTxnStatus(String test) { + return test.matches(VALIDATION_REGEX); } /** @@ -42,4 +49,22 @@ public boolean isClosed() { public LocalDateTime getLastUpdate() { return lastUpdate; } + + @Override + public String toString() { + return this.value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof TxnStatus // instanceof handles nulls + && value.equals(((TxnStatus) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } + } diff --git a/src/main/java/seedu/address/model/transaction/Value.java b/src/main/java/seedu/address/model/transaction/Value.java new file mode 100644 index 00000000000..d95cd5bcfbd --- /dev/null +++ b/src/main/java/seedu/address/model/transaction/Value.java @@ -0,0 +1,56 @@ +package seedu.address.model.transaction; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.util.AppUtil.checkArgument; + +/** + * Represents a transaction's value. + */ +public class Value { + public static final String MESSAGE_CONSTRAINTS = + "Transaction value should only contain numbers and at most one dot, and it should not be blank"; + + public static final String VALIDATION_REGEX = "-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)"; + public final String value; + + /** + * Constructs a {@code Value}. + * + * @param value A valid value amount. + */ + public Value(String value) { + requireNonNull(value); + checkArgument(isValidValue(value), MESSAGE_CONSTRAINTS); + this.value = value; + } + + /** + * Returns true if a given string is a valid phone number. + */ + public static boolean isValidValue(String test) { + return test.matches(VALIDATION_REGEX); + } + + @Override + public String toString() { + return value; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof Value // instanceof handles nulls + && value.equals(((Value) other).value)); // state check + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + + + +} + + diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTxn.java b/src/main/java/seedu/address/storage/JsonAdaptedTxn.java new file mode 100644 index 00000000000..de31c1b2bbc --- /dev/null +++ b/src/main/java/seedu/address/storage/JsonAdaptedTxn.java @@ -0,0 +1,92 @@ +package seedu.address.storage; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import seedu.address.commons.exceptions.IllegalValueException; +import seedu.address.model.transaction.Description; +import seedu.address.model.transaction.Owner; +import seedu.address.model.transaction.Transaction; +import seedu.address.model.transaction.TxnStatus; +import seedu.address.model.transaction.Value; + +/** + * Jackson-friendly version of {@link Transaction}. + */ +public class JsonAdaptedTxn { + public static final String MISSING_FIELD_MESSAGE_FORMAT = "Transaction's %s field is missing!"; + + private final String description; + private final String owner; + private final String status; + private final String value; + + /** + * Constructs a {@code JsonAdaptedTxn} with the given transaction details. + */ + @JsonCreator + public JsonAdaptedTxn(@JsonProperty("description") String description, + @JsonProperty("owner") String owner, + @JsonProperty("status") String status, + @JsonProperty("value") String value) { + this.description = description; + this.owner = owner; + this.status = status; + this.value = value; + } + + /** + * Converts a given {@code Transaction} into this class for Jackson use. + */ + public JsonAdaptedTxn(Transaction source) { + description = source.getDescription().value; + owner = source.getOwner().fullName; + status = source.getStatus().value; + value = source.getValue().value; + } + + /** + * Converts this Jackson-friendly adapted transaction object into the model's {@code Transaction} object. + * + * @throws IllegalValueException if there were any data constraints violated in the adapted transaction. + */ + public Transaction toModelType() throws IllegalValueException { + + if (description == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + Description.class.getSimpleName())); + } + if (!Description.isValidDescription(description)) { + throw new IllegalValueException(Description.MESSAGE_CONSTRAINTS); + } + final Description modelDescription = new Description(description); + + if (owner == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Owner.class.getSimpleName())); + } + if (!Owner.isValidName(owner)) { + throw new IllegalValueException(Owner.MESSAGE_CONSTRAINTS); + } + final Owner modelOwner = new Owner(owner); + + if (status == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, + TxnStatus.class.getSimpleName())); + } + if (!TxnStatus.isValidTxnStatus(status)) { + throw new IllegalValueException(TxnStatus.MESSAGE_CONSTRAINTS); + } + final TxnStatus modelStatus = new TxnStatus(status); + + if (value == null) { + throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Value.class.getSimpleName())); + } + if (!Value.isValidValue(value)) { + throw new IllegalValueException(Value.MESSAGE_CONSTRAINTS); + } + final Value modelValue = new Value(value); + + return new Transaction(modelDescription, modelValue, modelStatus, modelOwner); + } + +} diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java index 5efd834091d..641d611f9ff 100644 --- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java +++ b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java @@ -12,6 +12,7 @@ import seedu.address.model.AddressBook; import seedu.address.model.ReadOnlyAddressBook; import seedu.address.model.person.Person; +import seedu.address.model.transaction.Transaction; /** * An Immutable AddressBook that is serializable to JSON format. @@ -21,14 +22,20 @@ class JsonSerializableAddressBook { public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s)."; + public static final String MESSAGE_DUPLICATE_TRANSACTIONS = "Transactions list contains duplicate transaction(s)."; + private final List persons = new ArrayList<>(); + private final List transactions = new ArrayList<>(); + /** - * Constructs a {@code JsonSerializableAddressBook} with the given persons. + * Constructs a {@code JsonSerializableAddressBook} with the given persons and transactions. */ @JsonCreator - public JsonSerializableAddressBook(@JsonProperty("persons") List persons) { + public JsonSerializableAddressBook(@JsonProperty("persons") List persons, + @JsonProperty("transactions") List transactions) { this.persons.addAll(persons); + this.transactions.addAll(transactions); } /** @@ -38,6 +45,7 @@ public JsonSerializableAddressBook(@JsonProperty("persons") List getFilteredPersonList() { throw new AssertionError("This method should not be called."); } + @Override + public ObservableList getFilteredTransactionList() { + throw new AssertionError("This method should not be called."); + } + @Override public void updateFilteredPersonList(Predicate predicate) { throw new AssertionError("This method should not be called."); } + + @Override + public void updateFilteredTransactionList(Predicate predicate) { + throw new AssertionError("This method should not be called."); + } } /** diff --git a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java b/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java index 188c9058d20..d5cf2be2221 100644 --- a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java +++ b/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java @@ -1,47 +1,57 @@ -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.AddressBook; -import seedu.address.testutil.TypicalPersons; - -public class JsonSerializableAddressBookTest { - - private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonSerializableAddressBookTest"); - private static final Path TYPICAL_PERSONS_FILE = TEST_DATA_FOLDER.resolve("typicalPersonsAddressBook.json"); - private static final Path INVALID_PERSON_FILE = TEST_DATA_FOLDER.resolve("invalidPersonAddressBook.json"); - private static final Path DUPLICATE_PERSON_FILE = TEST_DATA_FOLDER.resolve("duplicatePersonAddressBook.json"); - - @Test - public void toModelType_typicalPersonsFile_success() throws Exception { - JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_PERSONS_FILE, - JsonSerializableAddressBook.class).get(); - AddressBook addressBookFromFile = dataFromFile.toModelType(); - AddressBook typicalPersonsAddressBook = TypicalPersons.getTypicalAddressBook(); - assertEquals(addressBookFromFile, typicalPersonsAddressBook); - } - - @Test - public void toModelType_invalidPersonFile_throwsIllegalValueException() throws Exception { - JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(INVALID_PERSON_FILE, - JsonSerializableAddressBook.class).get(); - assertThrows(IllegalValueException.class, dataFromFile::toModelType); - } - - @Test - public void toModelType_duplicatePersons_throwsIllegalValueException() throws Exception { - JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_PERSON_FILE, - JsonSerializableAddressBook.class).get(); - assertThrows(IllegalValueException.class, JsonSerializableAddressBook.MESSAGE_DUPLICATE_PERSON, - dataFromFile::toModelType); - } - -} +//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.AddressBook; +//import seedu.address.testutil.TypicalPersons; +// +//public class JsonSerializableAddressBookTest { +// +// private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", +// "JsonSerializableAddressBookTest"); +// private static final Path TYPICAL_PERSONS_FILE = TEST_DATA_FOLDER.resolve("typicalPersonsAddressBook.json"); +// private static final Path TYPICAL_TRANSACTIONS_FILE = TEST_DATA_FOLDER.resolve( +// "typicalTransactionsAddressBook.json"); +// +// private static final Path INVALID_PERSON_FILE = TEST_DATA_FOLDER.resolve("invalidPersonAddressBook.json"); +// private static final Path INVALID_TRANSACTIONS_FILE = TEST_DATA_FOLDER.resolve( +// "invalidTransactionsAddressBook.json"); +// +// private static final Path DUPLICATE_PERSON_FILE = TEST_DATA_FOLDER.resolve("duplicatePersonAddressBook.json"); +// private static final Path DUPLICATE_TRANSACTION_FILE = TEST_DATA_FOLDER.resolve( +// "duplicateTransactionAddressBook.json"); +// +// @Test +// public void toModelType_typicalPersonsFile_success() throws Exception { +// JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_PERSONS_FILE, +// //TYPICAL_TRANSACTIONS_FILE, +// JsonSerializableAddressBook.class).get(); +// AddressBook addressBookFromFile = dataFromFile.toModelType(); +// AddressBook typicalPersonsAddressBook = TypicalPersons.getTypicalAddressBook(); +// assertEquals(addressBookFromFile, typicalPersonsAddressBook); +// } +// +// @Test +// public void toModelType_invalidPersonFile_throwsIllegalValueException() throws Exception { +// JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(INVALID_PERSON_FILE, +// JsonSerializableAddressBook.class).get(); +// assertThrows(IllegalValueException.class, dataFromFile::toModelType); +// } +// +// @Test +// public void toModelType_duplicatePersons_throwsIllegalValueException() throws Exception { +// JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_PERSON_FILE, +// JsonSerializableAddressBook.class).get(); +// assertThrows(IllegalValueException.class, JsonSerializableAddressBook.MESSAGE_DUPLICATE_PERSON, +// dataFromFile::toModelType); +// } +// +//} From 590f98063e8ef0d2aa0b86f06864fba244474c4c Mon Sep 17 00:00:00 2001 From: ajjajjajjajj Date: Tue, 21 Mar 2023 17:42:09 +0800 Subject: [PATCH 02/16] Fix duplicate method definitions --- 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 fcba68e8958..867fcbba145 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -153,11 +153,6 @@ public ObservableList getFilteredTransactionList() { return filteredTransactions; } - @Override - public ObservableList getFilteredTransactionList() { - return filteredTransactions; - } - @Override public void updateFilteredPersonList(Predicate predicate) { requireNonNull(predicate); From 56ba64d2cd7c0e71920a73c6ce4bb17382fa369b Mon Sep 17 00:00:00 2001 From: ajjajjajjajj Date: Wed, 22 Mar 2023 14:28:24 +0800 Subject: [PATCH 03/16] Add new files for UI for transactions --- .../java/seedu/address/ui/PersonCard.java | 15 +++ .../seedu/address/ui/TransactionCard.java | 69 ++++++++++++++ .../address/ui/TransactionListPanel.java | 50 ++++++++++ src/main/resources/view/DarkTheme.css | 4 + src/main/resources/view/MainWindow.fxml | 56 +++++++----- src/main/resources/view/PersonListCard.fxml | 91 ++++++++++++------- .../resources/view/TransactionListCard.fxml | 66 ++++++++++++++ .../resources/view/TransactionListPanel.fxml | 8 ++ 8 files changed, 301 insertions(+), 58 deletions(-) create mode 100644 src/main/java/seedu/address/ui/TransactionCard.java create mode 100644 src/main/java/seedu/address/ui/TransactionListPanel.java create mode 100644 src/main/resources/view/TransactionListCard.fxml create mode 100644 src/main/resources/view/TransactionListPanel.fxml diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java index 0e876a7bb40..6291581df08 100644 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ b/src/main/java/seedu/address/ui/PersonCard.java @@ -33,6 +33,8 @@ public class PersonCard extends UiPart { @FXML private Label id; @FXML + private Label gender; + @FXML private Label phone; @FXML private Label address; @@ -43,6 +45,14 @@ public class PersonCard extends UiPart { @FXML private Label remark; @FXML + private Label industry; + @FXML + private Label company; + @FXML + private Label occupation; + @FXML + private Label jobTitle; + @FXML private Label status; /** @@ -53,6 +63,7 @@ public PersonCard(Person person, int displayedIndex) { this.person = person; id.setText(displayedIndex + ". "); name.setText(person.getName().fullName); + gender.setText(person.getGender().value); phone.setText(person.getPhone().value); address.setText(person.getAddress().value); email.setText(person.getEmail().value); @@ -60,6 +71,10 @@ public PersonCard(Person person, int displayedIndex) { person.getTags().stream() .sorted(Comparator.comparing(tag -> tag.tagName)) .forEach(tag -> tags.getChildren().add(new Label(tag.tagName))); + industry.setText(person.getIndustry().value); + company.setText(person.getCompany().value); + occupation.setText(person.getOccupation().value); + jobTitle.setText(person.getJobTitle().value); status.setText(person.getStatus().getStatusName().getLabel()); } diff --git a/src/main/java/seedu/address/ui/TransactionCard.java b/src/main/java/seedu/address/ui/TransactionCard.java new file mode 100644 index 00000000000..4306cba3459 --- /dev/null +++ b/src/main/java/seedu/address/ui/TransactionCard.java @@ -0,0 +1,69 @@ +package seedu.address.ui; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import seedu.address.model.transaction.Transaction; + +import java.util.Comparator; + +/** + * An UI component that displays information of a {@code Person}. + */ +public class TransactionCard extends UiPart { + + private static final String FXML = "PersonListCard.fxml"; + + /** + * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX. + * As a consequence, UI elements' variable names cannot be set to such keywords + * or an exception will be thrown by JavaFX during runtime. + * + * @see The issue on AddressBook level 4 + */ + + public final Transaction txn; + + @FXML + private HBox cardPane; + @FXML + private Label id; + @FXML + private Label description; + @FXML + private Label value; + @FXML + private Label status; + + /** + * Creates a {@code PersonCode} with the given {@code Person} and index to display. + */ + public TransactionCard(Transaction txn, int displayedIndex) { + super(FXML); + this.txn = txn; + id.setText(displayedIndex + ". "); + description.setText(txn.getDescription()); + value.setText(txn.getValue().toString()); + status.setText(txn.getStatus().value); + } + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof TransactionCard)) { + return false; + } + + // state check + TransactionCard card = (TransactionCard) other; + return id.getText().equals(card.id.getText()) + && txn.equals(card.txn); + } +} diff --git a/src/main/java/seedu/address/ui/TransactionListPanel.java b/src/main/java/seedu/address/ui/TransactionListPanel.java new file mode 100644 index 00000000000..10deea7b834 --- /dev/null +++ b/src/main/java/seedu/address/ui/TransactionListPanel.java @@ -0,0 +1,50 @@ +package seedu.address.ui; + +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.layout.Region; +import seedu.address.commons.core.LogsCenter; +import seedu.address.model.person.Person; +import seedu.address.model.transaction.Transaction; + +import java.util.logging.Logger; + +/** + * Panel containing the list of persons. + */ +public class TransactionListPanel extends UiPart { + private static final String FXML = "PersonListPanel.fxml"; + private final Logger logger = LogsCenter.getLogger(TransactionListPanel.class); + + @FXML + private ListView txnListView; + + /** + * Creates a {@code PersonListPanel} with the given {@code ObservableList}. + */ + public TransactionListPanel(ObservableList txnList) { + super(FXML); + txnListView.setItems(txnList); + txnListView.setCellFactory(listView -> new TransactionListViewCell()); + } + + /** + * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}. + */ + class TransactionListViewCell extends ListCell { + @Override + protected void updateItem(Transaction txn, boolean empty) { + super.updateItem(txn, empty); + + if (empty || txn == null) { + setGraphic(null); + setText(null); + } else { + setGraphic(new TransactionCard(txn, getIndex() + 1).getRoot()); + } + } + } + +} diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css index 36fac2c947e..51ff2d05eb2 100644 --- a/src/main/resources/view/DarkTheme.css +++ b/src/main/resources/view/DarkTheme.css @@ -351,6 +351,10 @@ -fx-font-size: 11; } +.list-cell #separator { + -fx-border-width: 0; +} + .cell_lead_status_label { -fx-text-fill: white; -fx-font-family: "Segoe UI"; diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index a431648f6c0..e638083488c 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -1,18 +1,14 @@ - - - - - - - - - - + + + + + + + - + @@ -33,27 +29,39 @@ - + - + - + - + - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml index d10cabea313..45aebeb57ae 100644 --- a/src/main/resources/view/PersonListCard.fxml +++ b/src/main/resources/view/PersonListCard.fxml @@ -4,40 +4,63 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - + + + + diff --git a/src/main/resources/view/TransactionListCard.fxml b/src/main/resources/view/TransactionListCard.fxml new file mode 100644 index 00000000000..45aebeb57ae --- /dev/null +++ b/src/main/resources/view/TransactionListCard.fxml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/TransactionListPanel.fxml b/src/main/resources/view/TransactionListPanel.fxml new file mode 100644 index 00000000000..8836d323cc5 --- /dev/null +++ b/src/main/resources/view/TransactionListPanel.fxml @@ -0,0 +1,8 @@ + + + + + + + + From 0ac1217ad61ede73eafedd9597adab4e832eeff7 Mon Sep 17 00:00:00 2001 From: ajjajjajjajj Date: Thu, 23 Mar 2023 18:17:14 +0800 Subject: [PATCH 04/16] Add minimum working UI for Tranasactions --- .../java/seedu/address/ui/MainWindow.java | 7 +++++ .../seedu/address/ui/TransactionCard.java | 7 +++-- .../address/ui/TransactionListPanel.java | 9 +++--- .../resources/view/TransactionListCard.fxml | 28 ++++--------------- .../resources/view/TransactionListPanel.fxml | 2 +- 5 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java index 9106c3aa6e5..3edaeab1b3d 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/seedu/address/ui/MainWindow.java @@ -32,6 +32,7 @@ public class MainWindow extends UiPart { // Independent Ui parts residing in this Ui container private PersonListPanel personListPanel; + private TransactionListPanel transactionListPanel; private ResultDisplay resultDisplay; private HelpWindow helpWindow; @@ -44,6 +45,9 @@ public class MainWindow extends UiPart { @FXML private StackPane personListPanelPlaceholder; + @FXML + private StackPane transactionListPanelPlaceholder; + @FXML private StackPane resultDisplayPlaceholder; @@ -113,6 +117,9 @@ void fillInnerParts() { personListPanel = new PersonListPanel(logic.getFilteredPersonList()); personListPanelPlaceholder.getChildren().add(personListPanel.getRoot()); + transactionListPanel = new TransactionListPanel(logic.getFilteredTransactionList()); + transactionListPanelPlaceholder.getChildren().add(transactionListPanel.getRoot()); + resultDisplay = new ResultDisplay(); resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot()); diff --git a/src/main/java/seedu/address/ui/TransactionCard.java b/src/main/java/seedu/address/ui/TransactionCard.java index 4306cba3459..045fcbd85da 100644 --- a/src/main/java/seedu/address/ui/TransactionCard.java +++ b/src/main/java/seedu/address/ui/TransactionCard.java @@ -14,7 +14,7 @@ */ public class TransactionCard extends UiPart { - private static final String FXML = "PersonListCard.fxml"; + private static final String FXML = "TransactionListCard.fxml"; /** * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX. @@ -36,6 +36,8 @@ public class TransactionCard extends UiPart { private Label value; @FXML private Label status; + @FXML + private Label owner; /** * Creates a {@code PersonCode} with the given {@code Person} and index to display. @@ -44,9 +46,10 @@ public TransactionCard(Transaction txn, int displayedIndex) { super(FXML); this.txn = txn; id.setText(displayedIndex + ". "); - description.setText(txn.getDescription()); + description.setText(txn.getDescription().toString()); value.setText(txn.getValue().toString()); status.setText(txn.getStatus().value); + owner.setText(txn.getOwner().toString()); } @Override diff --git a/src/main/java/seedu/address/ui/TransactionListPanel.java b/src/main/java/seedu/address/ui/TransactionListPanel.java index 10deea7b834..26151758ce8 100644 --- a/src/main/java/seedu/address/ui/TransactionListPanel.java +++ b/src/main/java/seedu/address/ui/TransactionListPanel.java @@ -6,7 +6,6 @@ import javafx.scene.control.ListView; import javafx.scene.layout.Region; import seedu.address.commons.core.LogsCenter; -import seedu.address.model.person.Person; import seedu.address.model.transaction.Transaction; import java.util.logging.Logger; @@ -15,19 +14,19 @@ * Panel containing the list of persons. */ public class TransactionListPanel extends UiPart { - private static final String FXML = "PersonListPanel.fxml"; + private static final String FXML = "TransactionListPanel.fxml"; private final Logger logger = LogsCenter.getLogger(TransactionListPanel.class); @FXML - private ListView txnListView; + private ListView transactionListView; /** * Creates a {@code PersonListPanel} with the given {@code ObservableList}. */ public TransactionListPanel(ObservableList txnList) { super(FXML); - txnListView.setItems(txnList); - txnListView.setCellFactory(listView -> new TransactionListViewCell()); + transactionListView.setItems(txnList); + transactionListView.setCellFactory(listView -> new TransactionListViewCell()); } /** diff --git a/src/main/resources/view/TransactionListCard.fxml b/src/main/resources/view/TransactionListCard.fxml index 45aebeb57ae..a9281dea13d 100644 --- a/src/main/resources/view/TransactionListCard.fxml +++ b/src/main/resources/view/TransactionListCard.fxml @@ -14,12 +14,12 @@ - - - - From 26371495aa9385b4b574701458f2b347c73fac59 Mon Sep 17 00:00:00 2001 From: ajjajjajjajj Date: Fri, 24 Mar 2023 00:31:43 +0800 Subject: [PATCH 07/16] Modify UI --- .../java/seedu/address/ui/TransactionCard.java | 6 ++++-- src/main/resources/view/MainWindow.fxml | 6 +++--- src/main/resources/view/TransactionListCard.fxml | 16 ++++++++++++++-- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/address/ui/TransactionCard.java b/src/main/java/seedu/address/ui/TransactionCard.java index a1ccfd83586..3cf9f12ecf9 100644 --- a/src/main/java/seedu/address/ui/TransactionCard.java +++ b/src/main/java/seedu/address/ui/TransactionCard.java @@ -13,6 +13,8 @@ public class TransactionCard extends UiPart { private static final String FXML = "TransactionListCard.fxml"; + private static final String TITLE_TEXT_VALUE = "Value: $"; + private static final String TITLE_TEXT_OWNER = "Owner: "; /** * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX. @@ -45,9 +47,9 @@ public TransactionCard(Transaction txn, int displayedIndex) { this.txn = txn; id.setText(displayedIndex + ". "); description.setText(txn.getDescription().toString()); - value.setText(txn.getValue().toString()); status.setText(txn.getStatus().value); - owner.setText(txn.getOwner().toString()); + value.setText(TITLE_TEXT_VALUE + txn.getValue().toString()); + owner.setText(TITLE_TEXT_OWNER + txn.getOwner().toString()); } @Override diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index 07227179ba0..15f26505d1b 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -8,7 +8,7 @@ - + @@ -40,9 +40,9 @@ - + - + diff --git a/src/main/resources/view/TransactionListCard.fxml b/src/main/resources/view/TransactionListCard.fxml index a9281dea13d..fa75d6a917b 100644 --- a/src/main/resources/view/TransactionListCard.fxml +++ b/src/main/resources/view/TransactionListCard.fxml @@ -34,8 +34,20 @@ - From b28545dce618a1cdc260b1c6998e15bb28a01b48 Mon Sep 17 00:00:00 2001 From: ajjajjajjajj Date: Fri, 24 Mar 2023 01:04:30 +0800 Subject: [PATCH 08/16] Add codecov.yml --- .github/workflows/codecov.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/workflows/codecov.yml diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 00000000000..5c513775f45 --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,5 @@ +name: codecov + +ignore: + - "src/main/java/seedu/address/ui/TransactionCard.java" + - "src/main/java/seedu/address/ui/TransactionListPanel.java" From 00078c660a4160010a6913745877a613660530e8 Mon Sep 17 00:00:00 2001 From: ajjajjajjajj Date: Fri, 24 Mar 2023 01:31:06 +0800 Subject: [PATCH 09/16] Add tests for Transactions --- .../logic/commands/CommandTestUtil.java | 3 + .../model/transaction/TransactionTest.java | 79 ++++++++++++++++--- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java index 286d7ec4e5f..c48b5bc8aef 100644 --- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java +++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java @@ -106,6 +106,9 @@ public class CommandTestUtil { public static final String INVALID_LEAD_STATUS_LABEL = " " + PREFIX_STATUS_ASSIGN + "Contacted"; // is not defined public static final String VALID_TXN_DESC_COFFEE_MACHINES = "20 HotPot CoffeePots for The Pot Company"; + public static final String VALID_TXN_VALUE_COFFEE_MACHINES = "6600"; + public static final String VALID_TXN_OWNER_COFFEE_MACHINES = "Tom Petey"; + public static final String VALID_TXN_STATUS_COFFEE_MACHINES = "closed"; static { DESC_AMY = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY).withGender(VALID_GENDER_AMY) diff --git a/src/test/java/seedu/address/model/transaction/TransactionTest.java b/src/test/java/seedu/address/model/transaction/TransactionTest.java index d53b082ab3f..20009d49db4 100644 --- a/src/test/java/seedu/address/model/transaction/TransactionTest.java +++ b/src/test/java/seedu/address/model/transaction/TransactionTest.java @@ -1,26 +1,83 @@ package seedu.address.model.transaction; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB; +import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; +import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB; +import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB; +import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; +import static seedu.address.logic.commands.CommandTestUtil.VALID_TXN_DESC_COFFEE_MACHINES; +import static seedu.address.logic.commands.CommandTestUtil.VALID_TXN_OWNER_COFFEE_MACHINES; +import static seedu.address.logic.commands.CommandTestUtil.VALID_TXN_STATUS_COFFEE_MACHINES; +import static seedu.address.logic.commands.CommandTestUtil.VALID_TXN_VALUE_COFFEE_MACHINES; +import static seedu.address.testutil.Assert.assertThrows; +import static seedu.address.testutil.TypicalPersons.ALICE; +import static seedu.address.testutil.TypicalPersons.BOB; +import static seedu.address.testutil.TypicalTransactions.COFFEE_BEANS; +import static seedu.address.testutil.TypicalTransactions.COFFEE_MACHINES_A; + import org.junit.jupiter.api.Test; +import seedu.address.model.person.Person; +import seedu.address.testutil.PersonBuilder; +import seedu.address.testutil.TransactionBuilder; class TransactionTest { @Test - void getDescription() { - } + void isSameTransaction() { + assertTrue(COFFEE_MACHINES_A.isSameTransaction(COFFEE_MACHINES_A)); - @Test - void getValue() { - } + assertFalse(COFFEE_MACHINES_A.isSameTransaction(null)); - @Test - void getStatus() { - } + // any field edited = not the same transaction + Transaction editedTxn = new TransactionBuilder(COFFEE_MACHINES_A).withDesc(VALID_TXN_DESC_COFFEE_MACHINES) + .build(); + assertFalse(COFFEE_MACHINES_A.isSameTransaction(editedTxn)); - @Test - void isSameTransaction() { + // desc with trailing spaces = return false + String descWithTrailingSpaces = COFFEE_MACHINES_A.getDescription().toString() + " "; + Transaction editedCoffeeMachines = new TransactionBuilder(COFFEE_MACHINES_A).withDesc(descWithTrailingSpaces).build(); + assertFalse(COFFEE_MACHINES_A.isSameTransaction(editedCoffeeMachines)); } @Test - void testEquals() { + void equals() { + // same values -> returns true + Transaction coffeeMachinesACopy = new TransactionBuilder(COFFEE_MACHINES_A).build(); + assertTrue(COFFEE_MACHINES_A.equals(coffeeMachinesACopy)); + + // same object -> returns true + assertTrue(COFFEE_MACHINES_A.equals(COFFEE_MACHINES_A)); + + // null -> returns false + assertFalse(COFFEE_MACHINES_A.equals(null)); + + // different type -> returns false + assertFalse(COFFEE_MACHINES_A.equals(5)); + + // different person -> returns false + assertFalse(COFFEE_MACHINES_A.equals(COFFEE_BEANS)); + + // different desc -> returns false + Transaction editedCoffeeMachinesA = new TransactionBuilder(COFFEE_MACHINES_A) + .withDesc(VALID_TXN_DESC_COFFEE_MACHINES).build(); + assertFalse(COFFEE_MACHINES_A.equals(editedCoffeeMachinesA)); + + // different owner -> returns false + editedCoffeeMachinesA = new TransactionBuilder(COFFEE_MACHINES_A).withOwner(VALID_TXN_OWNER_COFFEE_MACHINES) + .build(); + assertFalse(COFFEE_MACHINES_A.equals(editedCoffeeMachinesA)); + + // different value -> returns false + editedCoffeeMachinesA = new TransactionBuilder(COFFEE_MACHINES_A).withValue(VALID_TXN_VALUE_COFFEE_MACHINES) + .build(); + assertFalse(COFFEE_MACHINES_A.equals(editedCoffeeMachinesA)); + + // different status -> returns false + editedCoffeeMachinesA = new TransactionBuilder(COFFEE_MACHINES_A).withStatus(VALID_TXN_STATUS_COFFEE_MACHINES) + .build(); + assertFalse(COFFEE_MACHINES_A.equals(editedCoffeeMachinesA)); + } } From ac19f37643e2eb5ca57066173da7a8f1dbc17ffb Mon Sep 17 00:00:00 2001 From: ajjajjajjajj Date: Fri, 24 Mar 2023 01:34:01 +0800 Subject: [PATCH 10/16] Move codecov.yml to main directory --- .github/workflows/codecov.yml => codecov.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/codecov.yml => codecov.yml (100%) diff --git a/.github/workflows/codecov.yml b/codecov.yml similarity index 100% rename from .github/workflows/codecov.yml rename to codecov.yml From 83c29c65aa703f094d334cfe2fa6042a4323bc8c Mon Sep 17 00:00:00 2001 From: ajjajjajjajj Date: Fri, 24 Mar 2023 01:36:50 +0800 Subject: [PATCH 11/16] Fix checkstyle for tests for Transactions --- .../model/transaction/TransactionTest.java | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/test/java/seedu/address/model/transaction/TransactionTest.java b/src/test/java/seedu/address/model/transaction/TransactionTest.java index 20009d49db4..d1881bf359d 100644 --- a/src/test/java/seedu/address/model/transaction/TransactionTest.java +++ b/src/test/java/seedu/address/model/transaction/TransactionTest.java @@ -1,27 +1,17 @@ package seedu.address.model.transaction; +import org.junit.jupiter.api.Test; +import seedu.address.testutil.TransactionBuilder; + import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB; -import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND; import static seedu.address.logic.commands.CommandTestUtil.VALID_TXN_DESC_COFFEE_MACHINES; import static seedu.address.logic.commands.CommandTestUtil.VALID_TXN_OWNER_COFFEE_MACHINES; import static seedu.address.logic.commands.CommandTestUtil.VALID_TXN_STATUS_COFFEE_MACHINES; import static seedu.address.logic.commands.CommandTestUtil.VALID_TXN_VALUE_COFFEE_MACHINES; -import static seedu.address.testutil.Assert.assertThrows; -import static seedu.address.testutil.TypicalPersons.ALICE; -import static seedu.address.testutil.TypicalPersons.BOB; import static seedu.address.testutil.TypicalTransactions.COFFEE_BEANS; import static seedu.address.testutil.TypicalTransactions.COFFEE_MACHINES_A; -import org.junit.jupiter.api.Test; -import seedu.address.model.person.Person; -import seedu.address.testutil.PersonBuilder; -import seedu.address.testutil.TransactionBuilder; - class TransactionTest { @Test From 748a1c3d431efca883567003cfcc28fe4c94105b Mon Sep 17 00:00:00 2001 From: ajjajjajjajj Date: Fri, 24 Mar 2023 01:39:32 +0800 Subject: [PATCH 12/16] Fix checkstyle for tests for Transactions --- .../address/model/transaction/TransactionTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/test/java/seedu/address/model/transaction/TransactionTest.java b/src/test/java/seedu/address/model/transaction/TransactionTest.java index d1881bf359d..7003290dc8e 100644 --- a/src/test/java/seedu/address/model/transaction/TransactionTest.java +++ b/src/test/java/seedu/address/model/transaction/TransactionTest.java @@ -1,8 +1,5 @@ package seedu.address.model.transaction; -import org.junit.jupiter.api.Test; -import seedu.address.testutil.TransactionBuilder; - import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static seedu.address.logic.commands.CommandTestUtil.VALID_TXN_DESC_COFFEE_MACHINES; @@ -12,6 +9,10 @@ import static seedu.address.testutil.TypicalTransactions.COFFEE_BEANS; import static seedu.address.testutil.TypicalTransactions.COFFEE_MACHINES_A; +import org.junit.jupiter.api.Test; + +import seedu.address.testutil.TransactionBuilder; + class TransactionTest { @Test @@ -27,7 +28,8 @@ void isSameTransaction() { // desc with trailing spaces = return false String descWithTrailingSpaces = COFFEE_MACHINES_A.getDescription().toString() + " "; - Transaction editedCoffeeMachines = new TransactionBuilder(COFFEE_MACHINES_A).withDesc(descWithTrailingSpaces).build(); + Transaction editedCoffeeMachines = new TransactionBuilder(COFFEE_MACHINES_A).withDesc(descWithTrailingSpaces) + .build(); assertFalse(COFFEE_MACHINES_A.isSameTransaction(editedCoffeeMachines)); } From ab0d83233579ac88fdb0606cdf0afea6fdb492d6 Mon Sep 17 00:00:00 2001 From: ajjajjajjajj Date: Fri, 24 Mar 2023 01:46:37 +0800 Subject: [PATCH 13/16] Edit codecov.yml --- codecov.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/codecov.yml b/codecov.yml index 5c513775f45..8f7319a4c1e 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,5 +1,4 @@ name: codecov ignore: - - "src/main/java/seedu/address/ui/TransactionCard.java" - - "src/main/java/seedu/address/ui/TransactionListPanel.java" + - "src/main/java/seedu/address/ui" From 39e1c835454c0ca5dcc9498d05a86a978f3bbb89 Mon Sep 17 00:00:00 2001 From: ajjajjajjajj Date: Fri, 24 Mar 2023 02:32:55 +0800 Subject: [PATCH 14/16] Polish UI, add title labels to person and transaction attributes --- .../seedu/address/ui/TransactionCard.java | 4 +- src/main/resources/view/PersonListCard.fxml | 63 +++++++++++++++---- .../resources/view/TransactionListCard.fxml | 14 +++-- 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/src/main/java/seedu/address/ui/TransactionCard.java b/src/main/java/seedu/address/ui/TransactionCard.java index 3cf9f12ecf9..c3015e03d21 100644 --- a/src/main/java/seedu/address/ui/TransactionCard.java +++ b/src/main/java/seedu/address/ui/TransactionCard.java @@ -48,8 +48,8 @@ public TransactionCard(Transaction txn, int displayedIndex) { id.setText(displayedIndex + ". "); description.setText(txn.getDescription().toString()); status.setText(txn.getStatus().value); - value.setText(TITLE_TEXT_VALUE + txn.getValue().toString()); - owner.setText(TITLE_TEXT_OWNER + txn.getOwner().toString()); + value.setText(txn.getValue().toString()); + owner.setText(txn.getOwner().toString()); } @Override diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PersonListCard.fxml index 45aebeb57ae..89e7730058b 100644 --- a/src/main/resources/view/PersonListCard.fxml +++ b/src/main/resources/view/PersonListCard.fxml @@ -4,7 +4,7 @@ - + @@ -19,6 +19,7 @@ +