Skip to content

Commit

Permalink
added sorting by price and month in descending order, renamed and add…
Browse files Browse the repository at this point in the history
…ed categories, added other logic fixes
  • Loading branch information
pradipmudi committed Oct 28, 2023
1 parent c203ab5 commit 4dec239
Show file tree
Hide file tree
Showing 18 changed files with 679 additions and 57 deletions.
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ dependencies {
implementation 'mysql:mysql-connector-java:8.0.27'
testImplementation 'ch.qos.logback:logback-classic:1.4.11'
implementation 'io.swagger.core.v3:swagger-annotations:2.2.14'
implementation 'org.apache.commons:commons-text:1.10.0'
}

tasks.named('test') {
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/com/expensys/config/CorsConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.expensys.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@Configuration
public class CorsConfig {

@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOrigin("http://localhost:"); // Specify your allowed origin(s)
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}

27 changes: 22 additions & 5 deletions src/main/java/com/expensys/constant/CategoryMappings.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@

import com.expensys.model.enums.Category;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.*;

public class CategoryMappings {
public static final Set<Category> MAIN_CATEGORIES;
public static final Set<Category> SUB_CATEGORIES;
public static final Map<Category, Category> SUB_TO_MAIN_CATEGORY_MAPPINGS;

private CategoryMappings(){}

Expand All @@ -22,14 +21,32 @@ private CategoryMappings(){}

Set<Category> subCategories = new HashSet<>();
subCategories.add(Category.GROCERIES);
subCategories.add(Category.VEGETABLES_AND_FRUITS);
subCategories.add(Category.VEGETABLES_FRUITS_DAIRY_AND_MEAT);
subCategories.add(Category.MEDICAL);
subCategories.add(Category.OUTSIDE_FOOD);
subCategories.add(Category.LOSE_OF_MONEY);
subCategories.add(Category.SALON);
subCategories.add(Category.SALON_AND_COSMETICS);
subCategories.add(Category.TRANSPORT);
subCategories.add(Category.SHOPPING);
subCategories.add(Category.ENTERTAINMENT);
subCategories.add(Category.RENT_AND_OTHER_BILLS);
subCategories.add(Category.OTHERS);
SUB_CATEGORIES = Collections.unmodifiableSet(subCategories);

Map<Category, Category> subToMainCategoryMappings = new HashMap<>();
subToMainCategoryMappings.put(Category.GROCERIES, Category.ESSENTIAL);
subToMainCategoryMappings.put(Category.VEGETABLES_FRUITS_DAIRY_AND_MEAT, Category.ESSENTIAL);
subToMainCategoryMappings.put(Category.MEDICAL, Category.ESSENTIAL);
subToMainCategoryMappings.put(Category.SALON_AND_COSMETICS, Category.EXPENSE);
subToMainCategoryMappings.put(Category.TRANSPORT, Category.EXPENSE);
subToMainCategoryMappings.put(Category.SHOPPING, Category.EXPENSE);
subToMainCategoryMappings.put(Category.OUTSIDE_FOOD, Category.EXPENSE);
subToMainCategoryMappings.put(Category.LOSE_OF_MONEY, Category.LOSE_OF_MONEY);
subToMainCategoryMappings.put(Category.OTHERS, Category.EXPENSE);
subToMainCategoryMappings.put(Category.ESSENTIAL, Category.ESSENTIAL);
subToMainCategoryMappings.put(Category.EXPENSE, Category.EXPENSE);
subToMainCategoryMappings.put(Category.ENTERTAINMENT, Category.EXPENSE);
subToMainCategoryMappings.put(Category.RENT_AND_OTHER_BILLS, Category.EXPENSE);
SUB_TO_MAIN_CATEGORY_MAPPINGS = Collections.unmodifiableMap(subToMainCategoryMappings);
}
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,30 @@
package com.expensys.controller;

import com.expensys.model.request.ReportRequest;
import com.expensys.model.response.Report;
import com.expensys.model.request.NewExpense;
import com.expensys.service.main.ExpenseManagementService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/report")
@RequestMapping("/expense")
public class ExpenseManagementController {
Logger logger = LoggerFactory.getLogger(ExpenseManagementController.class);
private final ExpenseManagementService expenseManagementService;

@Autowired
public ExpenseManagementController(ExpenseManagementService expenseManagementService) {
this.expenseManagementService = expenseManagementService;
}

@GetMapping
public ResponseEntity<List<Report>> getReport(@ModelAttribute ReportRequest reportRequest){
List<Report> reportList = expenseManagementService.getReport(reportRequest);
return new ResponseEntity<>(reportList, HttpStatus.OK);
@CrossOrigin
@PostMapping("/save")
public ResponseEntity<HttpStatus> saveExpense(@RequestBody NewExpense newExpense){
logger.info("newExpense -> {}",newExpense);
// expenseManagementService.addExpense(newExpense);
return new ResponseEntity<>(expenseManagementService.addExpense(newExpense) ? HttpStatus.OK : HttpStatus.INTERNAL_SERVER_ERROR);
}


}
32 changes: 32 additions & 0 deletions src/main/java/com/expensys/controller/ReportController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.expensys.controller;

import com.expensys.model.request.ReportRequest;
import com.expensys.model.response.Report;
import com.expensys.service.main.ExpenseManagementService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/report")
public class ReportController {
Logger logger = LoggerFactory.getLogger(ReportController.class);
private final ExpenseManagementService expenseManagementService;

public ReportController(ExpenseManagementService expenseManagementService) {
this.expenseManagementService = expenseManagementService;
}

@CrossOrigin
@GetMapping
public ResponseEntity<List<Report>> getReport(@ModelAttribute ReportRequest reportRequest){
List<Report> reportList = expenseManagementService.getReport(reportRequest);
return new ResponseEntity<>(reportList, HttpStatus.OK);
}


}
2 changes: 1 addition & 1 deletion src/main/java/com/expensys/entity/ExpenseEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@Table(name = "expenses")
public class ExpenseEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.expensys.convertor;
package com.expensys.helper;


import com.expensys.model.Expense;
Expand All @@ -12,6 +12,8 @@
import java.util.*;
import java.util.stream.Collectors;

import static com.expensys.constant.CategoryMappings.SUB_TO_MAIN_CATEGORY_MAPPINGS;

public class ExpenseToReportConvertor {
private ExpenseToReportConvertor() {
// Initialization code
Expand All @@ -31,7 +33,8 @@ private HashMap<Month, List<ReportInfo>> prepareReportInfoListFromExpenseListByM

ReportInfo reportInfo = ReportInfo.builder()
.mainCategory(expense.getCategory())
.subCategory(reportRequest.getCategory().equals(Category.MAIN) ? expense.getCategory().getCat() : expense.getSubCategory())
// .subCategory(reportRequest.getCategory().equals(Category.MAIN) ? expense.getCategory().getCat() : expense.getSubCategory())
.subCategory(SUB_TO_MAIN_CATEGORY_MAPPINGS.get(expense.getCategory()).toString())
.spent(expense.getSpent())
.user(SpentBy.ALL.equals(spentBy) ? spentBy.toString() : expense.getSpentBy())
.build();
Expand All @@ -53,12 +56,16 @@ private HashMap<Month, List<ReportInfo>> prepareReportInfoListFromExpenseListByM

private List<Report> prepareReportInfoFromReportInfoByMonth(HashMap<Month, List<ReportInfo>> monthReportInfoMap, ReportRequest reportRequest) {
List<Report> reportList = new ArrayList<>();
for (Map.Entry<Month,List<ReportInfo>> monthEntry : monthReportInfoMap.entrySet()) {

for (Map.Entry<Month, List<ReportInfo>> monthEntry : monthReportInfoMap.entrySet()) {
Month month = monthEntry.getKey();
Report currentReport = new Report(month, processReportInfoList(monthReportInfoMap.get(month), reportRequest));

reportList.add(currentReport);
}

// Sort the reportList based on the month's integer values in descending order
Collections.sort(reportList, (r1, r2) -> Integer.compare(Integer.valueOf(r2.getMonth().getMonthValue()), Integer.valueOf(r1.getMonth().getMonthValue())));

return reportList;
}

Expand All @@ -78,10 +85,11 @@ public List<ReportInfo> processReportInfoList(List<ReportInfo> reportInfoList, R
return spentBycategory.entrySet().stream()
.map(entry -> ReportInfo.builder()
.mainCategory(entry.getKey())
.subCategory(entry.getKey().getCat())
.subCategory(SUB_TO_MAIN_CATEGORY_MAPPINGS.get(entry.getKey()).toString())
.user(SpentBy.ALL.getSpentBy())
.spent(entry.getValue())
.build())
.sorted(Comparator.comparing(ReportInfo::getSpent).reversed())
.toList();
} else if (SpentBy.USER.equals(reportRequest.getSpentBy())) {
// Aggregate spent amount by subCategory and spentBy user, ignoring case
Expand All @@ -95,7 +103,7 @@ public List<ReportInfo> processReportInfoList(List<ReportInfo> reportInfoList, R
// Create a new list of ReportInfo objects based on Task 2, retaining the mainCategory
return categoryAndSpentByUser.entrySet().stream()
.flatMap(entry -> {
String category = entry.getKey().getCat();
Category category = entry.getKey();
// Extract the mainCategory for the subCategory
Category mainCategory = filteredList.stream()
.filter(reportInfo -> category.equals(reportInfo.getSubCategory()))
Expand All @@ -105,13 +113,14 @@ public List<ReportInfo> processReportInfoList(List<ReportInfo> reportInfoList, R
// Create ReportInfo objects for each user and subCategory combination
return entry.getValue().entrySet().stream()
.map(userEntry -> ReportInfo.builder()
.mainCategory(mainCategory)
.subCategory(category)
.mainCategory(category)
.subCategory(SUB_TO_MAIN_CATEGORY_MAPPINGS.get(category).toString())
.spent(userEntry.getValue())
.user(userEntry.getKey().toUpperCase())
.build());
})
.sorted(Comparator.comparing(ReportInfo::getUser)) // Sort by user field
.sorted(Comparator.comparing(ReportInfo::getSpent).reversed())
.toList();
}

Expand Down
77 changes: 77 additions & 0 deletions src/main/java/com/expensys/helper/WordSimilarityCalculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.expensys.helper;

import org.apache.commons.text.similarity.CosineSimilarity;
import java.util.*;

public class WordSimilarityCalculator {
private int wordLength;

public WordSimilarityCalculator(int wordLength) {
this.wordLength = wordLength;
}

public static void main(String[] args) {
// System.out.println(calculateSimilarity("vegetable & fruits", "vegetables and fruits"));
System.out.println(calculateSimilarity("fruit", "fruits"));
}

public static double calculateSimilarity(String word1, String word2) {
// Tokenization
List<String> word1List = tokenizeWord(word1);
List<String> word2List = tokenizeWord(word2);

// Remove stopwords
List<String> word1Set = removeStopWords(word1List);
List<String> word2Set = removeStopWords(word2List);

// Convert the lists to maps with word frequencies
Map<CharSequence, Integer> word1Map = createWordFrequencyMap(word1Set);
Map<CharSequence, Integer> word2Map = createWordFrequencyMap(word2Set);

// Calculate cosine similarity
CosineSimilarity cosineSimilarity = new CosineSimilarity();
double similarity = cosineSimilarity.cosineSimilarity(word1Map, word2Map);

return similarity;
}

private static List<String> tokenizeWord(String word) {
List<String> tokenList = new ArrayList<>();
String[] tokens = word.split("\\s+"); // Split by whitespace
for (String token : tokens) {
tokenList.add(token.toLowerCase());
}
return tokenList;
}

private static List<String> removeStopWords(List<String> tokens) {
List<String> cleanedTokens = new ArrayList<>();
Set<String> stopWords = getStopWords(); // Define your set of stopwords

for (String token : tokens) {
if (!stopWords.contains(token)) {
cleanedTokens.add(token);
}
}

return cleanedTokens;
}

private static Map<CharSequence, Integer> createWordFrequencyMap(List<String> words) {
Map<CharSequence, Integer> wordFrequencyMap = new HashMap<>();
for (String word : words) {
wordFrequencyMap.put(word, wordFrequencyMap.getOrDefault(word, 0) + 1);
}
return wordFrequencyMap;
}

private static Set<String> getStopWords() {
// Define your set of English stopwords here
Set<String> stopWords = new HashSet<>();
stopWords.add("the");
stopWords.add("and");
stopWords.add("&");
// Add more stopwords as needed
return stopWords;
}
}
6 changes: 4 additions & 2 deletions src/main/java/com/expensys/model/enums/Category.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ public enum Category {
OUTSIDE_FOOD("outside food"),
MEDICAL("medical"),
SHOPPING("shopping"),
SALON("salon"),
SALON_AND_COSMETICS("salon and cosmetics"),
TRANSPORT("transport"),
GROCERIES("groceries"),
VEGETABLES_AND_FRUITS("vegetables and fruits"),
VEGETABLES_FRUITS_DAIRY_AND_MEAT("vegetables, fruits, dairy and meat"),
LOSE_OF_MONEY("lose of money"),
ESSENTIAL("essential"),
EXPENSE("expense"),
ENTERTAINMENT("entertainment"),
RENT_AND_OTHER_BILLS("rent and other bills"),
OTHERS("others");

private String cat;
Expand Down
Loading

0 comments on commit 4dec239

Please sign in to comment.