From cdcd1aefec33b4f90d86f85d9694caca61a39b47 Mon Sep 17 00:00:00 2001 From: devkale Date: Thu, 31 Dec 2020 19:09:11 +0530 Subject: [PATCH] Initial version with running code. Few validations are needed. --- src/main/java/Driver.java | 65 ++++++++++++++++++ src/main/java/business/Ledger.java | 84 ++++++++++++++++++++++++ src/main/java/models/Balance.java | 54 +++++++++++++++ src/main/java/models/EqualExpense.java | 25 +++++++ src/main/java/models/ExactExpense.java | 25 +++++++ src/main/java/models/Expense.java | 30 +++++++++ src/main/java/models/PercentExpense.java | 27 ++++++++ src/main/java/models/User.java | 31 +++++++++ src/main/java/models/Users.java | 24 +++++++ 9 files changed, 365 insertions(+) create mode 100644 src/main/java/Driver.java create mode 100644 src/main/java/business/Ledger.java create mode 100644 src/main/java/models/Balance.java create mode 100644 src/main/java/models/EqualExpense.java create mode 100644 src/main/java/models/ExactExpense.java create mode 100644 src/main/java/models/Expense.java create mode 100644 src/main/java/models/PercentExpense.java create mode 100644 src/main/java/models/User.java create mode 100644 src/main/java/models/Users.java diff --git a/src/main/java/Driver.java b/src/main/java/Driver.java new file mode 100644 index 0000000..88b7826 --- /dev/null +++ b/src/main/java/Driver.java @@ -0,0 +1,65 @@ +import business.Ledger; +import models.*; + +import java.math.BigDecimal; +import java.util.Arrays; + +public class Driver { + public static void main(String[] args) { + + Ledger ledger = new Ledger(); + Users users = new Users(); + users.addUser(new User("u1")); + users.addUser(new User("u2")); + users.addUser(new User("u3")); + users.addUser(new User("u4")); + ledger.showBalances(); + ledger.getBalancesOfUser(users.getUser("u1")); + Expense expense1 = new EqualExpense( + users.getUser("u1") + ,new BigDecimal(1000) + ,Arrays.asList( + users.getUser("u1") + ,users.getUser("u2") + ,users.getUser("u3") + ,users.getUser("u4") + ) + ); + ledger.ProcessExpense(expense1); + ledger.getBalancesOfUser(users.getUser("u4")); + ledger.getBalancesOfUser(users.getUser("u1")); + Expense expense2 = new ExactExpense( + users.getUser("u1") + ,new BigDecimal(1250) + ,Arrays.asList( + users.getUser("u2") + ,users.getUser("u3") + ) + ,Arrays.asList( + new BigDecimal(370) + , new BigDecimal(880) + ) + ); + ledger.ProcessExpense(expense2); + ledger.getAllBalances(); + Expense expense3 = new PercentExpense( + users.getUser("u4") + ,new BigDecimal(1200) + ,Arrays.asList( + users.getUser("u1") + ,users.getUser("u2") + ,users.getUser("u3") + ,users.getUser("u4") + ) + ,Arrays.asList( + new BigDecimal(40) + ,new BigDecimal(20) + ,new BigDecimal(20) + ,new BigDecimal(20) + ) + ); + ledger.ProcessExpense(expense3); + ledger.getBalancesOfUser(users.getUser("u1")); + ledger.getAllBalances(); + } +} diff --git a/src/main/java/business/Ledger.java b/src/main/java/business/Ledger.java new file mode 100644 index 0000000..418e667 --- /dev/null +++ b/src/main/java/business/Ledger.java @@ -0,0 +1,84 @@ +package business; + +import models.Balance; +import models.Expense; +import models.User; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +public class Ledger { + // TODO hashmap implementation for performance + List balances; + + public Ledger() { + this.balances = new ArrayList<>(); + } + + public void ProcessExpense(Expense expense) { + List balances = expense.getBalances(); + for (Balance balance : balances) { + Balance existingBalance = getBalanceOfUsers(balance.getBorrower(), balance.getGiver()); + if (existingBalance == null) { + this.balances.add(balance); + continue; + } + if(existingBalance.getBorrower().equals(balance.getBorrower())) { + existingBalance.addAmount(balance.getAmount()); + } else { + BigDecimal amount = existingBalance.getAmount().subtract(balance.getAmount()); + if(amount.compareTo(new BigDecimal(0))==0) { + this.balances.remove(existingBalance); + } else if(amount.compareTo(new BigDecimal(0))>0) { + existingBalance.setAmount(amount); + } else { + this.balances.remove(existingBalance); + this.balances.add(new Balance(balance.getBorrower(), balance.getGiver(), amount.negate())); + } + } + } + } + + private Balance getBalanceOfUsers(User user1, User user2) { + Balance balance = null; + for (Balance balanceLoop : balances) { + if(balanceLoop.isUsersInvolved(user1, user2)) { + balance = balanceLoop; + } + } + return balance; + } + + public void showBalances(){ + printBalance(balances); + } + + public void getBalancesOfUser(User user) { + List balancesOfUser = new ArrayList<>(); + for (Balance balance : balances) { + if (balance.isUserInvolved(user)) { + balancesOfUser.add(balance); + } + } + printBalance(balancesOfUser); + } + + public void getAllBalances() { + printBalance(this.balances); + } + + private void printBalance(List balances) { + if(balances.isEmpty()) { + System.out.println("No balances"); + } + else { + for (Balance balance : balances) { + System.out.println(balance); + } + } + System.out.println("-"); + } + + +} diff --git a/src/main/java/models/Balance.java b/src/main/java/models/Balance.java new file mode 100644 index 0000000..c74bced --- /dev/null +++ b/src/main/java/models/Balance.java @@ -0,0 +1,54 @@ +package models; + +import java.math.BigDecimal; + +public class Balance { + User borrower; + User giver; + BigDecimal amount; + + public Balance(User borrower, User giver, BigDecimal amount) { + this.borrower = borrower; + this.giver = giver; + this.amount = amount; + } + + public User getBorrower() { + return borrower; + } + + public User getGiver() { + return giver; + } + + @Override + public String toString() { + return String.format("%s owes %s: %s", borrower.getName(), giver.getName(), amount); + } + + public boolean isUserInvolved(User user) { + if(borrower.equals(user) || giver.equals(user)) { + return true; + } + return false; + } + + public boolean isUsersInvolved(User user1, User user2) { + if((borrower.equals(user1)&& giver.equals(user2))||(borrower.equals(user2)&&giver.equals(user1))) { + return true; + } + return false; + } + + public void addAmount(BigDecimal amount) { + this.amount = this.amount.add(amount); + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } +} diff --git a/src/main/java/models/EqualExpense.java b/src/main/java/models/EqualExpense.java new file mode 100644 index 0000000..47afb16 --- /dev/null +++ b/src/main/java/models/EqualExpense.java @@ -0,0 +1,25 @@ +package models; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +public class EqualExpense extends Expense { + + public EqualExpense(User payer, BigDecimal amount, List payee) { + super(payer, amount, payee); + } + + @Override + public List getBalances() { + List balances = new ArrayList<>(); + BigDecimal sharedAmount = amount.divide(new BigDecimal(payee.size())); + for (User user : payee) { + if(user.equals(payer)) { + continue; + } + balances.add(new Balance(user,payer,sharedAmount)); + } + return balances; + } +} diff --git a/src/main/java/models/ExactExpense.java b/src/main/java/models/ExactExpense.java new file mode 100644 index 0000000..488a314 --- /dev/null +++ b/src/main/java/models/ExactExpense.java @@ -0,0 +1,25 @@ +package models; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +public class ExactExpense extends Expense{ + private List amounts; + public ExactExpense(User payer, BigDecimal amount, List payee,List amounts) { + super(payer, amount, payee); + this.amounts = amounts; + } + + @Override + public List getBalances() { + List balances = new ArrayList<>(); + for (int i = 0; i < payee.size(); i++) { + if(payee.get(i).equals(payer)) { + continue; + } + balances.add(new Balance(payee.get(i),payer,amounts.get(i))); + } + return balances; + } +} diff --git a/src/main/java/models/Expense.java b/src/main/java/models/Expense.java new file mode 100644 index 0000000..55f51c5 --- /dev/null +++ b/src/main/java/models/Expense.java @@ -0,0 +1,30 @@ +package models; + +import java.math.BigDecimal; +import java.util.List; + +public abstract class Expense { + protected User payer; + protected BigDecimal amount; + List payee; + + public Expense(User payer, BigDecimal amount, List payee) { + if (payer == null) { + throw new IllegalArgumentException("payer must not be null"); + } + + if(amount.compareTo(new BigDecimal(0))<=0) { + throw new IllegalArgumentException("amount must be positive"); + } + + if (payee == null || payee.isEmpty() || payee.contains(null)) { + throw new IllegalArgumentException("payee list must not be null or empty or containing null. "); + } + + this.payer = payer; + this.amount = amount; + this.payee = payee; + } + + abstract public List getBalances(); +} diff --git a/src/main/java/models/PercentExpense.java b/src/main/java/models/PercentExpense.java new file mode 100644 index 0000000..081e19b --- /dev/null +++ b/src/main/java/models/PercentExpense.java @@ -0,0 +1,27 @@ +package models; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +public class PercentExpense extends Expense{ + private List percentages; + public PercentExpense(User payer, BigDecimal amount, List payee, List percentages) { + super(payer, amount, payee); + this.percentages = percentages; + } + + @Override + public List getBalances() { + List balances = new ArrayList<>(); + for (int i = 0; i < payee.size(); i++) { + if(payee.get(i).equals(payer)) { + continue; + } + BigDecimal percent = percentages.get(i).divide(new BigDecimal(100)); + balances.add(new Balance(payee.get(i),payer,amount.multiply(percent))); + } + return balances; + + } +} diff --git a/src/main/java/models/User.java b/src/main/java/models/User.java new file mode 100644 index 0000000..80913fe --- /dev/null +++ b/src/main/java/models/User.java @@ -0,0 +1,31 @@ +package models; + +import java.util.Objects; + +public class User { + private String name; + + public User(String name) { + if (name == null) { + throw new IllegalArgumentException("name must not be null."); + } + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof User)) return false; + User user = (User) o; + return getName().equals(user.getName()); + } + + @Override + public int hashCode() { + return Objects.hash(getName()); + } +} diff --git a/src/main/java/models/Users.java b/src/main/java/models/Users.java new file mode 100644 index 0000000..0947888 --- /dev/null +++ b/src/main/java/models/Users.java @@ -0,0 +1,24 @@ +package models; + +import java.util.ArrayList; +import java.util.List; + +public class Users { + List users; + + public Users() { + this.users = new ArrayList<>(); + } + + public User getUser(String name) { + for (User user : users) { + if (user.getName().equalsIgnoreCase(name)) { + return user; + } + } + return null; + } + public void addUser(User user) { + users.add(user); + } +}