Project: Codii
[Codii] is a desktop address book application specially designed for debt collectors to manage debtors in a simple manner. It has a GUI but most of the user interactions happen using a CLI (Command Line Interface).
Debt collectors can store information such as the amount owed, debt borrow date and debt cleared date in addition to debtor’s personal information.
Unique features such as an interest calculator help debt collectors manage debts more efficiently.
Codii is evolved from [AddressBook - Level 4] which is a desktop address book application used for teaching Software Engineering principles.
Code contributed: [Functional code] [Test code]
Date storing mechanism
The date storing mechanism only begins to work when an instance of the Person
class is implemented. An instance of the Date
class is created and used to store the current date that the Person
instance was created.
An example of such an implementation of this is the dateBorrow
field of Person
.
public class Person implements ReadOnlyPerson {
private ObjectProperty<Name> name;
private ObjectProperty<Phone> phone;
private ObjectProperty<Email> email;
private ObjectProperty<Address> address;
private ObjectProperty<PostalCode> postalCode;
private ObjectProperty<Cluster> cluster;
private ObjectProperty<Debt> debt;
private ObjectProperty<Interest> interest;
private ObjectProperty<DateBorrow> dateBorrow;
Such an implementation doesn’t allow for errors when creating the field as there is no room for mistakes on the user’s side. When the Person
instance is created, the following line is called:
this.dateBorrow = new SimpleObjectProperty<>(new DateBorrow());
Suppose the above line is called, the DateBorrow
class creates a new Date
with the following line:
public DateBorrow() {
Date date = new Date();
value = formatDate(date);
}
This way of implementation is rather intuitive when adding a new Person
as a new Date
can simply be created. However, whenever a Person
constructor is called, such as the following:
public Person(ReadOnlyPerson source) {
this(source.getName(), source.getPhone(), source.getEmail(), source.getAddress(), source.getPostalCode(),
source.getDebt(), source.getInterest(), source.getDeadline(), source.getTags());
This would result in inconsistencies in the code. For example, an Edit
command is implemented in such a way that it creates an editedPerson
.
This is because the above mentioned constructor was meant to make a copy of the Person
with a given source. Hence the following line was added to ensure consistency.
this.dateBorrow = new SimpleObjectProperty<>(source.getDateBorrow());
Design Considerations
Aspect: Implementation of DateBorrow
Alternative 1(current choice): Create a DateBorrow
class as such but modify the constructor to maintain consistency
Pros: Blends well with existing coding style and how the commands work.
Cons: As of now there is no problems with the implementation.
Alternative 2: Have the user manually key in the date
Pros: Implementation is very simple as the developer could just follow current coding style to create a new field.
Cons: Such an implementation would not be as user-friendly as the first alternative. Currently the amount of fields for the user to key in
is rather high. Implementing alternative 2 would be more tedious on the user’s side.
End of Extract
Listing all persons with overdue debt: overduelist
It should be noted that each time the user logs into Codii , it checks through the address book for debtors
whose deadlines have been passed and automatically adds them into the overdue list. |
If any debtor in the overdue list has cleard his/her debt, they are removed from the overdue list. |
Shows a list of all persons with overdue debt in the address book.
Format: overduelist
End of Extract
Justification
It would be more convenient for debt collectors to view all the debtors with overdue debts with a simple command.
Interest Calculator
This is only applicable to debtors with a set interest rate. For the current version, only positive whole numbers are accepted. |
Codii only checks through its list of debtors when the user logs into the application. |
At the start of each month, Codii
will check through the list of debtors and accrue their debt
if applicable. Even if the user has not logged into Codii
for many months, the application will compound
the debt accordingly.
This is convenient for debts or loans with a monthly interest rate.
End of Extract
Justification
It would be convenient for debt collectors to have their debtors' debts updated automatically. However, it should be noted that it is still a basic feature as it only accrues a debtor’s debt at the start of each month. An updated version will be included in V2.0.
Interest Calculator Mechanism
As a debt collector, it can be troublesome to manage so many debts. The task is made more tedious when the debt collector has to
consider all the debtor’s loan’s interest rates as well. Codii is able to automatically calculate a Person
's new debt based on his / her’s
interest rate. Whenever the user logs into Codii, the Model
component, which handles the event LoginAppRequestEvent
and checks every
Person
in the AddressBook
.
@Subscribe
public void handleLoginUpdateDebt(LoginAppRequestEvent event) {
// login is successful
if (event.getLoginStatus() == true) {
for (ReadOnlyPerson person : allPersons) {
if (!person.getInterest().value.equals("No interest set.")
&& (person.checkLastAccruedDate(new Date()) != 0)) {
updateDebtFromInterest(person, person.checkLastAccruedDate(new Date()));
}
}
}
}
As seen from the above if a Person
has his / her interest field defined,the event handler checks a Person
's debts last accrued date via the method:
/**
* Compares date of last accrued against current date.
* @return number of months the current date is ahead of last accrued date. Returns 0 if
* there is no need to increment debt.
*/
@Override
public int checkLastAccruedDate(Date currentDate) {
if (lastAccruedDate.before(currentDate)) {
return DateUtil.getNumberOfMonthBetweenDates(currentDate, lastAccruedDate);
} else {
return 0;
}
}
The above method returns the difference in the number of months between the last accrued date and the current date to the event handler. The event
handler than calls another method to update the Person
's debt by passing in the number of months as a parameter:
@Override
public void updateDebtFromInterest(ReadOnlyPerson person, int differenceInMonths) {
String accruedAmount = person.calcAccruedAmount(differenceInMonths);
try {
Debt amount = new Debt(accruedAmount);
addDebtToPerson(person, amount);
} catch (PersonNotFoundException pnfe) {
assert false : "Should not occur as person obtained from allPersons";
} catch (IllegalValueException ive) {
assert false : Debt.MESSAGE_DEBT_CONSTRAINTS;
}
}
From the above code, the Person
's debts accrued amount would be calculated by the line:
String accruedAmount = person.calcAccruedAmount(differenceInMonths);
Their respective debts would then be updated accordingly with the following line:
addDebtToPerson(person, amount);
Design Considerations
Aspect: When to update / check a Person’s debt
Alternative 1 (Current choice): Check through the AddressBook
in the Model
component every time the user logs in
Pros: Convenient and intuitive to implement for developer.
Cons: If user never logs out, the debt would not be accrued.
Alternative 2: Create a Refresh
command that does the checking instead of relying on the LoginAppRequestEvent
Pros: User can have the most up-to-date debt as long as he / she remembers to always enter the Refresh
command.
Cons: Not convenient for user at all. It is also unlikely that the user would remain logged in for such a long duration.
End of Extract
other contributions
Added various fields to the Person Class
-
Debt field
-
Interest field
-
Date Borrow field
-
Deadline field