Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test Submission - Foyaz Hasnath #203

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 55 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,55 @@
Programming Test
========

This is a dummy application to be used as part of a software development interview.

instructions
--------

* Treat this code as if you owned this application, do whatever you feel is necessary to make this your own.
* There are several deliberate design, code quality and test issues that should be identified and resolved.
* Below is a list of the current features supported by the application; as well as some additional features that have been requested by the business owner.
* In order to work on this take a fork into your own GitHub area; make whatever changes you feel are necessary and when you are satisfied submit back via a pull request. See details on GitHub's [Fork & Pull](https://help.github.com/articles/using-pull-requests) model
* Be sure to put your name in the pull request comment so your work can be easily identied.
* The project uses maven to resolve dependencies however if you want to avoid maven configuration the only external JAR that's required is junit-4.11.
* Refactor and add features (from the below list) as you see fit; there is no need to add all the features in order to "complete" the exercise. Keep in mind that code quality is the critical measure and there should be an obvious focus on testing.
* You'll notice there is no database or UI; these are not needed - the exercise deliberately avoids these requirements.
* REMEMBER: this is YOUR code, make any changes you feel are necessary.
* You're welcome to spend as much time as you like.
* The code will be a representation of your work, so it's important that all the code--new and pre-existing--is how you want your work to be seen. Please make sure that you are happy with ALL the code.

abc-bank
--------

A dummy application for a bank; should provide various functions of a retail bank.

### Current Features

* A customer can open an account
* A customer can deposit / withdraw funds from an account
* A customer can request a statement that shows transactions and totals for each of their accounts
* Different accounts have interest calculated in different ways
* **Checking accounts** have a flat rate of 0.1%
* **Savings accounts** have a rate of 0.1% for the first $1,000 then 0.2%
* **Maxi-Savings accounts** have a rate of 2% for the first $1,000 then 5% for the next $1,000 then 10%
* A bank manager can get a report showing the list of customers and how many accounts they have
* A bank manager can get a report showing the total interest paid by the bank on all accounts

### Additional Features

* A customer can transfer between their accounts
* Change **Maxi-Savings accounts** to have an interest rate of 5% assuming no withdrawals in the past 10 days otherwise 0.1%
* Interest rates should accrue and compound daily (incl. weekends), rates above are per-annum
Programming Test
========

This is a dummy application to be used as part of a software development interview.

instructions
--------

* Treat this code as if you owned this application, do whatever you feel is necessary to make this your own.
* There are several deliberate design, code quality and test issues that should be identified and resolved.
* Below is a list of the current features supported by the application; as well as some additional features that have been requested by the business owner.
* In order to work on this take a fork into your own GitHub area; make whatever changes you feel are necessary and when you are satisfied submit back via a pull request. See details on GitHub's [Fork & Pull](https://help.github.com/articles/using-pull-requests) model
* Be sure to put your name in the pull request comment so your work can be easily identied.
* The project uses maven to resolve dependencies however if you want to avoid maven configuration the only external JAR that's required is junit-4.11.
* Refactor and add features (from the below list) as you see fit; there is no need to add all the features in order to "complete" the exercise. Keep in mind that code quality is the critical measure and there should be an obvious focus on testing.
* You'll notice there is no database or UI; these are not needed - the exercise deliberately avoids these requirements.
* REMEMBER: this is YOUR code, make any changes you feel are necessary.
* You're welcome to spend as much time as you like.
* The code will be a representation of your work, so it's important that all the code--new and pre-existing--is how you want your work to be seen. Please make sure that you are happy with ALL the code.

abc-bank
--------

A dummy application for a bank; should provide various functions of a retail bank.

### Current Features

* A customer can open an account
* A customer can deposit / withdraw funds from an account
* A customer can request a statement that shows transactions and totals for each of their accounts
* Different accounts have interest calculated in different ways
* **Checking accounts** have a flat rate of 0.1%
* **Savings accounts** have a rate of 0.1% for the first $1,000 then 0.2%
* **Maxi-Savings accounts** have a rate of 2% for the first $1,000 then 5% for the next $1,000 then 10%
* A bank manager can get a report showing the list of customers and how many accounts they have
* A bank manager can get a report showing the total interest paid by the bank on all accounts

### Additional Features

* A customer can transfer between their accounts
* Change **Maxi-Savings accounts** to have an interest rate of 5% assuming no withdrawals in the past 10 days otherwise 0.1%
* Interest rates should accrue and compound daily (incl. weekends), rates above are per-annum

### Features Implemented
* A customer can open an account
* A customer can deposit / withdraw funds from an account
* A customer can request a statement that shows transactions and totals for each of their accounts
* Different accounts have interest calculated in different ways
* **Checking accounts** have a flat rate of 0.1%
* **Savings accounts** have a rate of 0.1% for the first $1,000 then 0.2%
* **Maxi-Savings accounts** have a rate of 2% for the first $1,000 then 5% for the next $1,000 then 10%
* A bank manager can get a report showing the list of customers and how many accounts they have
* A bank manager can get a report showing the total interest paid by the bank on all accounts
* A customer can transfer between their accounts
* Interest rates should accrue and compound daily (incl. weekends), rates above are per-annum
12 changes: 12 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@
<groupId>com.abc</groupId>
<artifactId>bank</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<packaging>jar</packaging>

<name>bank</name>
Expand Down
119 changes: 103 additions & 16 deletions src/main/java/com/abc/Account.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
/*Edited by: Foyaz Hasnath*/
package com.abc;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static java.lang.Math.abs;

public class Account {

Expand All @@ -12,9 +23,14 @@ public class Account {
private final int accountType;
public List<Transaction> transactions;

private DateProvider dateProvider = new DateProvider();
private Date dateOpened;

public Account(int accountType) {
this.accountType = accountType;
this.transactions = new ArrayList<Transaction>();
this.transactions = new ArrayList<>();
dateOpened = dateProvider.now();
System.out.println("date account opened: "+dateProvider.dateFormat(dateOpened));
}

public void deposit(double amount) {
Expand All @@ -33,28 +49,99 @@ public void withdraw(double amount) {
}
}

public double interestEarned() {
public void transfer(Account to, double amount){
// boolean success = false;
try{
withdraw(amount);
to.deposit(amount);
//success=true;
}catch (Exception e){
e.printStackTrace();
//success = false;
}
// return success;
}

public double interestEarned(Date businessDate) {
double amount = sumTransactions();
DecimalFormat df = new DecimalFormat("#.##");
switch(accountType){
case SAVINGS:
if (amount <= 1000)
return amount * 0.001;
else
return 1 + (amount-1000) * 0.002;
// case SUPER_SAVINGS:
// if (amount <= 4000)
// return 20;
case SAVINGS :
double interest = 0;
if (amount <= 1000){
interest = Double.valueOf(df.format(dailyCompoundedFormula(businessDate,amount,0.001)));//0.1%
}else {
interest = Double.valueOf(df.format(dailyCompoundedFormula(businessDate,1000,0.001)));//0.1% for first 1000
interest+= Double.valueOf(df.format(dailyCompoundedFormula(businessDate,amount-1000,0.002)));//0.2% for rest
}
return Double.valueOf(df.format(interest));
case MAXI_SAVINGS:
if (amount <= 1000)
return amount * 0.02;
if (amount <= 2000)
return 20 + (amount-1000) * 0.05;
return 70 + (amount-2000) * 0.1;
double totalInterest = 0;
if (amount <= 1000){
totalInterest = Double.valueOf(df.format(dailyCompoundedFormula(businessDate,amount,0.02)));//2%
}else if (amount>1000 && amount<=2000){
totalInterest = Double.valueOf(df.format(dailyCompoundedFormula(businessDate,1000,0.02)));//2% for first 1000
totalInterest+= Double.valueOf(df.format(dailyCompoundedFormula(businessDate,amount-1000,0.05)));//5% until 2000
}else{
System.out.println("more than 2k");
totalInterest = Double.valueOf(df.format(dailyCompoundedFormula(businessDate,1000,0.02)));//2% for first 1000
totalInterest+= Double.valueOf(df.format(dailyCompoundedFormula(businessDate,1000,0.05)));//5% until 2000
totalInterest+= Double.valueOf(df.format(dailyCompoundedFormula(businessDate,amount-2000,0.10)));//10% for rest
}
return Double.valueOf(df.format(totalInterest));

//Checking Account (0.1%)
default:
return amount * 0.001;
return (Double.valueOf(df.format(dailyCompoundedFormula(businessDate,amount,0.001))));
}
}

//daily compounded interest formula
private double dailyCompoundedFormula(Date businessDate, double amount,double rate){
double x = 1 + (rate/365);

//accurately get days between two dates
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate date1 = LocalDate.parse(dateProvider.dateFormat(businessDate), formatter);
LocalDate date2 = LocalDate.parse(dateProvider.dateFormat(dateOpened), formatter);
long days = ChronoUnit.DAYS.between(date2,date1);
int daysPassed = (int) days;

System.out.println("REAL business days passed from bank opening till simulated business date: "+daysPassed+" days");
double multiplier = (Math.pow(x,daysPassed)) - 1;
return amount * multiplier;
//return Double.valueOf((amount + (amount*multiplier)));
}

/*
//TODO: daily compounded interest formula for MAXI SAVINGS
private double dailyCompoundedFormula(Date businessDate,ArrayList<Date> withdrawalDates, double amount){
double balance = 0;

double fivePercentRate = 1 + (0.05/365);
double pointOnePercentRate = 1 + (0.001/365);
Collections.sort(withdrawalDates);

Date dateFrom = dateOpened;
Date dateTo = businessDate;

for (int i=0;i<withdrawalDates.size();i++){
System.out.println("withdrawal date "+ i +" " + dateProvider.dateFormat(withdrawalDates.get(i)));
//5% from account opening until first withdrawal
long diff = dateTo.getTime() - dateFrom.getTime();
int daysPassed = (int) (TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS));
System.out.println(daysPassed);
double multiplier = (Math.pow(fivePercentRate,daysPassed)) - 1;
balance += Double.valueOf((amount + (amount*multiplier)));
}
return balance;
}
*/

private String toDollars(double d){
return String.format("$%,.2f", abs(d));
}

public double sumTransactions() {
return checkIfTransactionsExist(true);
}
Expand Down
25 changes: 24 additions & 1 deletion src/main/java/com/abc/Bank.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,36 @@
/*Edited by: Foyaz Hasnath*/
package com.abc;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class Bank {
private List<Customer> customers;

private DateProvider dateProvider = new DateProvider();
private Date bankCreationDate;
private Date businessDate;

public Bank() {
customers = new ArrayList<Customer>();
bankCreationDate = dateProvider.now();
businessDate = bankCreationDate;//business day set to creation day of bank at inception
System.out.println("date bank opened: "+dateProvider.dateFormat(bankCreationDate));
}

public Date getCurrBusinessDate(){
return businessDate;
}
//to "roll" or move forward business date to simulate some amount of time between bankCreationDate and businessDate
public void rollBusinessDate(int days){
System.out.println("before roll date: "+dateProvider.dateFormat(getCurrBusinessDate()));
Calendar cal = Calendar. getInstance();
cal.setTime(businessDate);
cal.add(Calendar.DATE, days);
businessDate=cal.getTime();
System.out.println("after roll date: "+dateProvider.dateFormat(getCurrBusinessDate()));
}

public void addCustomer(Customer customer) {
Expand All @@ -30,7 +53,7 @@ private String format(int number, String word) {
public double totalInterestPaid() {
double total = 0;
for(Customer c: customers)
total += c.totalInterestEarned();
total += c.totalInterestEarned(businessDate);
return total;
}

Expand Down
50 changes: 42 additions & 8 deletions src/main/java/com/abc/Customer.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/*Edited by: Foyaz Hasnath*/
package com.abc;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static java.lang.Math.abs;
Expand All @@ -27,26 +29,56 @@ public int getNumberOfAccounts() {
return accounts.size();
}

public double totalInterestEarned() {
public double totalInterestEarned(Date businessDate) {
double total = 0;
for (Account a : accounts)
total += a.interestEarned();
total += a.interestEarned(businessDate);
return total;
}

public String getStatement() {
public String getStatement(Bank bank) {
String statement = null;
statement = "Statement for " + name + "\n";
double total = 0.0;
for (Account a : accounts) {
statement += "\n" + statementForAccount(a) + "\n";
total += a.sumTransactions();
statement += "\n" + statementForAccount(a,bank.getCurrBusinessDate()) + "\n";
total += a.sumTransactions()+a.interestEarned(bank.getCurrBusinessDate());
}
statement += "\nTotal In All Accounts " + toDollars(total);
statement += "\nTotal In All Accounts (including interest): " + toDollars(total);
return statement;
}

private String statementForAccount(Account a) {
public String getTransactions(){

String checkingAccountTransacts = "CHECKING: ";
String savingsAccountTransacts = "SAVINGS: ";
String maxiSavingsAccountTransacts = "MAXI_SAVINGS: ";

//go through each transaction for each account and record
for (Account a:accounts) {
for (Transaction t : a.transactions) {
if(a.getAccountType()==Account.CHECKING && t.getAmount()!=0){
checkingAccountTransacts += t.getAmount() + ",";
}else if(a.getAccountType()==Account.SAVINGS && t.getAmount()!=0){
savingsAccountTransacts += t.getAmount() + ",";
}else{
if(t.getAmount()!=0) {
maxiSavingsAccountTransacts += t.getAmount() + ",";
}
}
}

}

//concat all and remove "," at end of line
String allTransacts = checkingAccountTransacts.substring(0,checkingAccountTransacts.length()-1)+"\n"
+savingsAccountTransacts.substring(0,savingsAccountTransacts.length()-1)+"\n"
+maxiSavingsAccountTransacts.substring(0,maxiSavingsAccountTransacts.length()-1);
System.out.println("all transacts:\n"+allTransacts);
return allTransacts;
}

private String statementForAccount(Account a,Date businessDate) {
String s = "";

//Translate to pretty account type
Expand All @@ -68,7 +100,9 @@ private String statementForAccount(Account a) {
s += " " + (t.amount < 0 ? "withdrawal" : "deposit") + " " + toDollars(t.amount) + "\n";
total += t.amount;
}
s += "Total " + toDollars(total);
s += "Total (less interest): " + toDollars(total) + "\n"
+ "Interest: "+ toDollars(a.interestEarned(businessDate)) +"\n"
+ "Total: " + toDollars(total+a.interestEarned(businessDate));
return s;
}

Expand Down
Loading