From 936268de49782e943f062b6c9b5a8fd073ce6b5b Mon Sep 17 00:00:00 2001 From: Vishal M Yadav Date: Tue, 4 Jun 2024 18:18:58 +0530 Subject: [PATCH] added splitwise machine coding code: test pending --- .gitignore | 38 ++++++ .idea/.gitignore | 8 ++ .idea/checkstyle-idea.xml | 15 +++ .idea/codeStyles/Project.xml | 7 + .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/encodings.xml | 7 + .idea/misc.xml | 14 ++ .idea/uiDesigner.xml | 124 ++++++++++++++++++ .idea/vcs.xml | 6 + pom.xml | 31 +++++ src/main/java/com/gatomalvado/Main.java | 8 ++ .../java/com/gatomalvado/splitwise/Main.java | 104 +++++++++++++++ .../gatomalvado/splitwise/model/Expense.java | 22 ++++ .../splitwise/model/ExpenseType.java | 13 ++ .../com/gatomalvado/splitwise/model/User.java | 15 +++ .../splitwise/model/UserBalance.java | 16 +++ .../orchestrator/ExpenseManager.java | 73 +++++++++++ .../service/UserBalanceGenerator.java | 13 ++ .../impl/EqualUserBalanceGenerator.java | 32 +++++ .../impl/ExactUserBalanceGenerator.java | 46 +++++++ .../impl/PercentUserBalanceGenerator.java | 47 +++++++ 21 files changed, 644 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/checkstyle-idea.xml create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/uiDesigner.xml create mode 100644 .idea/vcs.xml create mode 100644 pom.xml create mode 100644 src/main/java/com/gatomalvado/Main.java create mode 100644 src/main/java/com/gatomalvado/splitwise/Main.java create mode 100644 src/main/java/com/gatomalvado/splitwise/model/Expense.java create mode 100644 src/main/java/com/gatomalvado/splitwise/model/ExpenseType.java create mode 100644 src/main/java/com/gatomalvado/splitwise/model/User.java create mode 100644 src/main/java/com/gatomalvado/splitwise/model/UserBalance.java create mode 100644 src/main/java/com/gatomalvado/splitwise/orchestrator/ExpenseManager.java create mode 100644 src/main/java/com/gatomalvado/splitwise/service/UserBalanceGenerator.java create mode 100644 src/main/java/com/gatomalvado/splitwise/service/impl/EqualUserBalanceGenerator.java create mode 100644 src/main/java/com/gatomalvado/splitwise/service/impl/ExactUserBalanceGenerator.java create mode 100644 src/main/java/com/gatomalvado/splitwise/service/impl/PercentUserBalanceGenerator.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/checkstyle-idea.xml b/.idea/checkstyle-idea.xml new file mode 100644 index 0000000..7f57652 --- /dev/null +++ b/.idea/checkstyle-idea.xml @@ -0,0 +1,15 @@ + + + + 10.15.0 + JavaOnly + + + \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..919ce1f --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..824b2cc --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..ef964bb --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..cadeb64 --- /dev/null +++ b/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + + com.gatomalvado + MachineCoding + 1.0-SNAPSHOT + + + 21 + 21 + UTF-8 + + + + org.projectlombok + lombok + RELEASE + provided + + + org.projectlombok + lombok + 1.18.30 + provided + + + + \ No newline at end of file diff --git a/src/main/java/com/gatomalvado/Main.java b/src/main/java/com/gatomalvado/Main.java new file mode 100644 index 0000000..3af65b3 --- /dev/null +++ b/src/main/java/com/gatomalvado/Main.java @@ -0,0 +1,8 @@ +package com.gatomalvado; + +public class Main { + + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/src/main/java/com/gatomalvado/splitwise/Main.java b/src/main/java/com/gatomalvado/splitwise/Main.java new file mode 100644 index 0000000..21f5523 --- /dev/null +++ b/src/main/java/com/gatomalvado/splitwise/Main.java @@ -0,0 +1,104 @@ +package com.gatomalvado.splitwise; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Scanner; +import java.util.Set; +import java.util.stream.Collectors; + +import com.gatomalvado.splitwise.model.Expense; +import com.gatomalvado.splitwise.model.ExpenseType; +import com.gatomalvado.splitwise.model.User; +import com.gatomalvado.splitwise.orchestrator.ExpenseManager; + +public class Main { + + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + ExpenseManager expenseManager = new ExpenseManager(); + + // create users + User user1 = User.builder().userId("User1").build(); + User user2 = User.builder().userId("User2").build(); + User user3 = User.builder().userId("User3").build(); + User user4 = User.builder().userId("User4").build(); + + // add user to the expense manager + expenseManager.addUser(user1); + expenseManager.addUser(user2); + expenseManager.addUser(user3); + expenseManager.addUser(user4); + + while(true){ + String command = scanner.nextLine(); + String[] commands = command.split(" "); + String commandType = commands[0]; + + switch(commandType){ + case "SHOW": + if(commands.length == 2){ + expenseManager.showBalanceForUser(commands[1]); + } else { + expenseManager.showBalance(); + } + case "EXPENSE": + String userWhoPaid = commands[1]; + int numberOfUsers = Integer.parseInt(commands[2]); + String expenseType = commands[3 + numberOfUsers]; + List userInvolved = new ArrayList<>(); + for(int i=3; i< 3+numberOfUsers; i++){ + userInvolved.add(commands[i]); + } + Double amount = Double.parseDouble(commands[4+numberOfUsers]); + Expense expense = null; + switch(expenseType) { + case "EQUAL": + expense = Expense.builder() + .expenseType(ExpenseType.EQUAL) + .paidBy(userWhoPaid) + .paidFor(userInvolved) + .amount(amount) + .build(); + expenseManager.addExpense(expense); + case "EXACT": + List amounts = new ArrayList<>(); + for(int i=5+numberOfUsers; i percentages = new ArrayList<>(); + for(int i=5+numberOfUsers; i paidFor; + private Double amount; + private List percentage; + private List exactAmount; +} diff --git a/src/main/java/com/gatomalvado/splitwise/model/ExpenseType.java b/src/main/java/com/gatomalvado/splitwise/model/ExpenseType.java new file mode 100644 index 0000000..9422257 --- /dev/null +++ b/src/main/java/com/gatomalvado/splitwise/model/ExpenseType.java @@ -0,0 +1,13 @@ +package com.gatomalvado.splitwise.model; + +public enum ExpenseType { + EQUAL("equal"), + EXACT("exact"), + PERCENT("percent"); + + private String name; + + ExpenseType(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/gatomalvado/splitwise/model/User.java b/src/main/java/com/gatomalvado/splitwise/model/User.java new file mode 100644 index 0000000..8e405d1 --- /dev/null +++ b/src/main/java/com/gatomalvado/splitwise/model/User.java @@ -0,0 +1,15 @@ +package com.gatomalvado.splitwise.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +@Data +@AllArgsConstructor +@Builder +public class User { + private String userId; + private String name; + private String email; + private String mobile; +} diff --git a/src/main/java/com/gatomalvado/splitwise/model/UserBalance.java b/src/main/java/com/gatomalvado/splitwise/model/UserBalance.java new file mode 100644 index 0000000..1fdff03 --- /dev/null +++ b/src/main/java/com/gatomalvado/splitwise/model/UserBalance.java @@ -0,0 +1,16 @@ +package com.gatomalvado.splitwise.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UserBalance { + private String owedTo; + private String userId; + private Double amount; +} diff --git a/src/main/java/com/gatomalvado/splitwise/orchestrator/ExpenseManager.java b/src/main/java/com/gatomalvado/splitwise/orchestrator/ExpenseManager.java new file mode 100644 index 0000000..44e9f5d --- /dev/null +++ b/src/main/java/com/gatomalvado/splitwise/orchestrator/ExpenseManager.java @@ -0,0 +1,73 @@ +package com.gatomalvado.splitwise.orchestrator; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.stream.Collectors; + +import com.gatomalvado.splitwise.model.Expense; +import com.gatomalvado.splitwise.model.ExpenseType; +import com.gatomalvado.splitwise.model.User; +import com.gatomalvado.splitwise.model.UserBalance; +import com.gatomalvado.splitwise.service.UserBalanceGenerator; + +public class ExpenseManager { + + private Map userStore; + + private List userBalances; + + private Map userBalanceGeneratorMap; + + public ExpenseManager(){ + this.userStore = new HashMap<>(); + this.userBalances = new ArrayList<>(); + initMap(); + } + + public void addExpense(Expense expense) { + List userBalanceList = userBalanceGeneratorMap.get(expense.getExpenseType()).generateUserBalance(expense); + userBalances.addAll(userBalanceList); + } + + public void addUser(User user){ + userStore.put(user.getUserId(), user); + } + + public void showBalance() { + Collection userCollection = userStore.values(); + userCollection.stream().forEach((usr) -> { + List userBalanceList = userBalances.stream().filter((usb) -> usb.getUserId().equals(usr.getUserId())).toList(); + Map oweToMap = new HashMap<>(); + userBalanceList.forEach((usb) -> { + oweToMap.put(usb.getOwedTo(), oweToMap.getOrDefault(usb.getOwedTo(), 0.0) + usb.getAmount()); + }); + oweToMap.keySet().forEach((otm) -> { + System.out.println(usr.getUserId() + " owes to " + otm + " " + oweToMap.get(otm)); + }); + }); + } + + public void showBalanceForUser(String userId) { + List userBalanceList = userBalances.stream().filter((usb) -> usb.getUserId().equals(userId)).toList(); + Map oweToMap = new HashMap<>(); + userBalanceList.forEach((usb) -> { + oweToMap.put(usb.getOwedTo(), oweToMap.getOrDefault(usb.getOwedTo(), 0.0) + usb.getAmount()); + }); + oweToMap.keySet().forEach((otm) -> { + System.out.println(userId + " owes to " + otm + " " + oweToMap.get(otm)); + }); + } + + private void initMap(){ + userBalanceGeneratorMap = new HashMap<>(); + ServiceLoader serviceLoader = ServiceLoader.load(UserBalanceGenerator.class); + for(UserBalanceGenerator userBalanceGenerator : serviceLoader) { + userBalanceGeneratorMap.put(userBalanceGenerator.getType(), userBalanceGenerator); + } + } + +} diff --git a/src/main/java/com/gatomalvado/splitwise/service/UserBalanceGenerator.java b/src/main/java/com/gatomalvado/splitwise/service/UserBalanceGenerator.java new file mode 100644 index 0000000..e5b72a2 --- /dev/null +++ b/src/main/java/com/gatomalvado/splitwise/service/UserBalanceGenerator.java @@ -0,0 +1,13 @@ +package com.gatomalvado.splitwise.service; + +import java.util.List; + +import com.gatomalvado.splitwise.model.Expense; +import com.gatomalvado.splitwise.model.ExpenseType; +import com.gatomalvado.splitwise.model.UserBalance; + +public interface UserBalanceGenerator { + List generateUserBalance(Expense expense); + + ExpenseType getType(); +} diff --git a/src/main/java/com/gatomalvado/splitwise/service/impl/EqualUserBalanceGenerator.java b/src/main/java/com/gatomalvado/splitwise/service/impl/EqualUserBalanceGenerator.java new file mode 100644 index 0000000..696987f --- /dev/null +++ b/src/main/java/com/gatomalvado/splitwise/service/impl/EqualUserBalanceGenerator.java @@ -0,0 +1,32 @@ +package com.gatomalvado.splitwise.service.impl; + +import java.util.ArrayList; +import java.util.List; + +import com.gatomalvado.splitwise.model.Expense; +import com.gatomalvado.splitwise.model.ExpenseType; +import com.gatomalvado.splitwise.model.UserBalance; +import com.gatomalvado.splitwise.service.UserBalanceGenerator; + +public class EqualUserBalanceGenerator implements UserBalanceGenerator { + + @Override + public List generateUserBalance(Expense expense) { + List userBalances = new ArrayList<>(); + Double amount = expense.getAmount(); + int usersLength = expense.getPaidFor().size(); + double amountToDistribute = amount/usersLength; + for(String userId: expense.getPaidFor()) { + if(!userId.equals(expense.getPaidBy())){ + userBalances.add(UserBalance.builder().amount(amountToDistribute).owedTo(expense.getPaidBy()).userId(userId).build()); + } + } + return userBalances; + } + + @Override + public ExpenseType getType() { + return ExpenseType.EQUAL; + } + +} diff --git a/src/main/java/com/gatomalvado/splitwise/service/impl/ExactUserBalanceGenerator.java b/src/main/java/com/gatomalvado/splitwise/service/impl/ExactUserBalanceGenerator.java new file mode 100644 index 0000000..94af301 --- /dev/null +++ b/src/main/java/com/gatomalvado/splitwise/service/impl/ExactUserBalanceGenerator.java @@ -0,0 +1,46 @@ +package com.gatomalvado.splitwise.service.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import com.gatomalvado.splitwise.model.Expense; +import com.gatomalvado.splitwise.model.ExpenseType; +import com.gatomalvado.splitwise.model.UserBalance; +import com.gatomalvado.splitwise.service.UserBalanceGenerator; + +public class ExactUserBalanceGenerator implements UserBalanceGenerator { + + @Override + public List generateUserBalance(Expense expense) { + if(!validateShare(expense)) { + // throw exception here + } + List userBalances = new ArrayList<>(); + int usersLength = expense.getPaidFor().size(); + List amounts = expense.getExactAmount(); + for(int i=0; i amounts = expense.getExactAmount(); + Double amount = expense.getAmount(); + double total = 0.0; + for(int i=0; i generateUserBalance(Expense expense) { + if(!validateShare(expense)) { + // throw exception here + } + List userBalances = new ArrayList<>(); + Double amount = expense.getAmount(); + int usersLength = expense.getPaidFor().size(); + for(int i=0; i percentage = expense.getPercentage(); + AtomicReference ans = new AtomicReference<>(0.0); + percentage.stream().forEach((pc) ->{ + ans.set(ans.get() + pc); + }); + Double finalValue = ans.get(); + return finalValue == 100.0; + } + +}