From b75d4ab1d16cc08b37b5fe790370061c254fd3b4 Mon Sep 17 00:00:00 2001 From: Robert Goldmann <deadlocker@gmx.de> Date: Sat, 2 Mar 2019 14:36:56 +0100 Subject: [PATCH] #293 -added tags --- .../controller/FilterController.java | 1 + .../TransactionSpecifications.java | 6 ++ .../filter/FilterConfiguration.java | 59 ++++++++++++++----- ...{FilterCategory.java => FilterObject.java} | 8 +-- .../services/FilterHelpersService.java | 25 ++++++-- .../services/TransactionService.java | 4 +- src/main/resources/static/js/filter.js | 1 + .../templates/filter/filterMacros.ftl | 24 ++++++++ .../TransactionRepositoryTest.java | 44 ++++++++------ 9 files changed, 131 insertions(+), 41 deletions(-) rename src/main/java/de/deadlocker8/budgetmaster/filter/{FilterCategory.java => FilterObject.java} (81%) diff --git a/src/main/java/de/deadlocker8/budgetmaster/controller/FilterController.java b/src/main/java/de/deadlocker8/budgetmaster/controller/FilterController.java index 27daf9794..82d02cf1d 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/controller/FilterController.java +++ b/src/main/java/de/deadlocker8/budgetmaster/controller/FilterController.java @@ -43,6 +43,7 @@ public class FilterController extends BaseController { FilterConfiguration filterConfiguration = FilterConfiguration.DEFAULT; filterConfiguration.setFilterCategories(filterHelpers.getFilterCategories()); + filterConfiguration.setFilterTags(filterHelpers.getFilterTags()); request.setAttribute("filterConfiguration", filterConfiguration, WebRequest.SCOPE_SESSION); return "redirect:" + request.getHeader("Referer"); } diff --git a/src/main/java/de/deadlocker8/budgetmaster/entities/transaction/TransactionSpecifications.java b/src/main/java/de/deadlocker8/budgetmaster/entities/transaction/TransactionSpecifications.java index 3fafab39f..8787e58a8 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/entities/transaction/TransactionSpecifications.java +++ b/src/main/java/de/deadlocker8/budgetmaster/entities/transaction/TransactionSpecifications.java @@ -15,6 +15,7 @@ public class TransactionSpecifications final boolean isIncome, boolean isExpenditure, final Boolean isRepeating, final List<Integer> categoryIDs, + final List<Integer> tagIDs, final String name) { return (transaction, query, builder) -> { @@ -53,6 +54,11 @@ public class TransactionSpecifications predicates.add(builder.and(transaction.get(Transaction_.category).get("ID").in(categoryIDs))); } + if(tagIDs != null) + { +// predicates.add(builder.and(transaction.get(Transaction_.tags).in(tagIDs))); + } + if(name != null && name.length() > 0) { predicates.add(builder.and(builder.like(builder.lower(transaction.get(Transaction_.name)), "%"+name.toLowerCase()+"%"))); diff --git a/src/main/java/de/deadlocker8/budgetmaster/filter/FilterConfiguration.java b/src/main/java/de/deadlocker8/budgetmaster/filter/FilterConfiguration.java index 86bc1f52e..2868fe82f 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/filter/FilterConfiguration.java +++ b/src/main/java/de/deadlocker8/budgetmaster/filter/FilterConfiguration.java @@ -9,22 +9,24 @@ public class FilterConfiguration private boolean includeExpenditure; private boolean includeNotRepeating; private boolean includeRepeating; - private List<FilterCategory> filterCategories; + private List<FilterObject> filterCategories; + private List<FilterObject> filterTags; private String name; - public static final FilterConfiguration DEFAULT = new FilterConfiguration(true, true, true, true, null, ""); + public static final FilterConfiguration DEFAULT = new FilterConfiguration(true, true, true, true, null, null, ""); public FilterConfiguration() { } - public FilterConfiguration(boolean includeIncome, boolean includeExpenditure, boolean includeNotRepeating, boolean includeRepeating, List<FilterCategory> filterCategories, String name) + public FilterConfiguration(boolean includeIncome, boolean includeExpenditure, boolean includeNotRepeating, boolean includeRepeating, List<FilterObject> filterCategories, List<FilterObject> filterTags, String name) { this.includeIncome = includeIncome; this.includeExpenditure = includeExpenditure; this.includeNotRepeating = includeNotRepeating; this.includeRepeating = includeRepeating; this.filterCategories = filterCategories; + this.filterTags = filterTags; this.name = name; } @@ -77,16 +79,26 @@ public class FilterConfiguration return isIncludeRepeating(); } - public List<FilterCategory> getFilterCategories() + public List<FilterObject> getFilterCategories() { return filterCategories; } - public void setFilterCategories(List<FilterCategory> filterCategories) + public void setFilterCategories(List<FilterObject> filterCategories) { this.filterCategories = filterCategories; } + public List<FilterObject> getFilterTags() + { + return filterTags; + } + + public void setFilterTags(List<FilterObject> filterTags) + { + this.filterTags = filterTags; + } + public String getName() { return name; @@ -97,28 +109,38 @@ public class FilterConfiguration this.name = name; } - public List<Integer> getIncludedCategoryIDs() + private List<Integer> getIncludedIDs(List<FilterObject> objects) { - if(filterCategories == null) + if(objects == null) { return null; } - List<Integer> includedCategoryIDs = new ArrayList<>(); - for(FilterCategory filterCategory : filterCategories) + List<Integer> includedIDs = new ArrayList<>(); + for(FilterObject filterObject : objects) { - if(filterCategory.isInclude()) + if(filterObject.isInclude()) { - includedCategoryIDs.add(filterCategory.getID()); + includedIDs.add(filterObject.getID()); } } - if(includedCategoryIDs.size() == filterCategories.size()) + if(includedIDs.size() == objects.size()) { return null; } - return includedCategoryIDs; + return includedIDs; + } + + public List<Integer> getIncludedCategoryIDs() + { + return getIncludedIDs(filterCategories); + } + + public List<Integer> getIncludedTagIDs() + { + return getIncludedIDs(filterTags); } public boolean isActive() @@ -144,7 +166,7 @@ public class FilterConfiguration return true; } - for(FilterCategory filterCategory : filterCategories) + for(FilterObject filterCategory : filterCategories) { if(!filterCategory.isInclude()) { @@ -152,6 +174,14 @@ public class FilterConfiguration } } + for(FilterObject filterTag : filterTags) + { + if(!filterTag.isInclude()) + { + return true; + } + } + if(!defaultConfiguration.getName().equals(name)) { return true; @@ -169,6 +199,7 @@ public class FilterConfiguration ", includeNotRepeating=" + includeNotRepeating + ", includeRepeating=" + includeRepeating + ", filterCategories=" + filterCategories + + ", filterTags=" + filterTags + ", name='" + name + '\'' + '}'; } diff --git a/src/main/java/de/deadlocker8/budgetmaster/filter/FilterCategory.java b/src/main/java/de/deadlocker8/budgetmaster/filter/FilterObject.java similarity index 81% rename from src/main/java/de/deadlocker8/budgetmaster/filter/FilterCategory.java rename to src/main/java/de/deadlocker8/budgetmaster/filter/FilterObject.java index d8bf9a40b..e29fbb5bf 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/filter/FilterCategory.java +++ b/src/main/java/de/deadlocker8/budgetmaster/filter/FilterObject.java @@ -1,16 +1,16 @@ package de.deadlocker8.budgetmaster.filter; -public class FilterCategory +public class FilterObject { private Integer ID; private String name; private boolean include; - public FilterCategory() + public FilterObject() { } - public FilterCategory(Integer ID, String name, boolean include) + public FilterObject(Integer ID, String name, boolean include) { this.ID = ID; this.name = name; @@ -50,7 +50,7 @@ public class FilterCategory @Override public String toString() { - return "FilterCategory{" + + return "FilterObject{" + "ID=" + ID + ", name='" + name + '\'' + ", include=" + include + diff --git a/src/main/java/de/deadlocker8/budgetmaster/services/FilterHelpersService.java b/src/main/java/de/deadlocker8/budgetmaster/services/FilterHelpersService.java index 5a645c906..66715d59e 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/services/FilterHelpersService.java +++ b/src/main/java/de/deadlocker8/budgetmaster/services/FilterHelpersService.java @@ -2,7 +2,8 @@ package de.deadlocker8.budgetmaster.services; import de.deadlocker8.budgetmaster.entities.category.Category; import de.deadlocker8.budgetmaster.entities.category.CategoryType; -import de.deadlocker8.budgetmaster.filter.FilterCategory; +import de.deadlocker8.budgetmaster.entities.tag.Tag; +import de.deadlocker8.budgetmaster.filter.FilterObject; import de.deadlocker8.budgetmaster.filter.FilterConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -17,6 +18,9 @@ public class FilterHelpersService @Autowired private CategoryService categoryService; + @Autowired + private TagService tagService; + public FilterConfiguration getFilterConfiguration(HttpServletRequest request) { FilterConfiguration filterConfiguration; @@ -25,24 +29,37 @@ public class FilterHelpersService { filterConfiguration = FilterConfiguration.DEFAULT; filterConfiguration.setFilterCategories(getFilterCategories()); + filterConfiguration.setFilterTags(getFilterTags()); return filterConfiguration; } return (FilterConfiguration)sessionFilterConfiguration; } - public List<FilterCategory> getFilterCategories() + public List<FilterObject> getFilterCategories() { List<Category> categories = categoryService.getRepository().findAllByOrderByNameAsc(); - List<FilterCategory> filterCategories = new ArrayList<>(); + List<FilterObject> filterCategories = new ArrayList<>(); for(Category category : categories) { if(!category.getType().equals(CategoryType.REST)) { - filterCategories.add(new FilterCategory(category.getID(), category.getName(), true)); + filterCategories.add(new FilterObject(category.getID(), category.getName(), true)); } } return filterCategories; } + + public List<FilterObject> getFilterTags() + { + List<Tag> tags = tagService.getRepository().findAllByOrderByNameAsc(); + List<FilterObject> filterTags = new ArrayList<>(); + for(Tag tag : tags) + { + filterTags.add(new FilterObject(tag.getID(), tag.getName(), true)); + } + + return filterTags; + } } \ No newline at end of file diff --git a/src/main/java/de/deadlocker8/budgetmaster/services/TransactionService.java b/src/main/java/de/deadlocker8/budgetmaster/services/TransactionService.java index 53bff3001..b9d37a6a2 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/services/TransactionService.java +++ b/src/main/java/de/deadlocker8/budgetmaster/services/TransactionService.java @@ -97,11 +97,11 @@ public class TransactionService implements Resetable if(account.getType().equals(AccountType.ALL)) { - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, endDate, null, filterConfiguration.isIncludeIncome(), filterConfiguration.isIncludeExpenditure(), filterConfiguration.isIncludeRepeatingAndNotRepeating(), filterConfiguration.getIncludedCategoryIDs(), filterConfiguration.getName()); + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, endDate, null, filterConfiguration.isIncludeIncome(), filterConfiguration.isIncludeExpenditure(), filterConfiguration.isIncludeRepeatingAndNotRepeating(), filterConfiguration.getIncludedCategoryIDs(), filterConfiguration.getIncludedTagIDs(), filterConfiguration.getName()); return transactionRepository.findAll(spec); } - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, endDate, account, filterConfiguration.isIncludeIncome(), filterConfiguration.isIncludeExpenditure(), filterConfiguration.isIncludeRepeatingAndNotRepeating(), filterConfiguration.getIncludedCategoryIDs(), filterConfiguration.getName()); + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, endDate, account, filterConfiguration.isIncludeIncome(), filterConfiguration.isIncludeExpenditure(), filterConfiguration.isIncludeRepeatingAndNotRepeating(), filterConfiguration.getIncludedCategoryIDs(), filterConfiguration.getIncludedTagIDs(), filterConfiguration.getName()); return transactionRepository.findAll(spec); } diff --git a/src/main/resources/static/js/filter.js b/src/main/resources/static/js/filter.js index cb7994929..df9db5080 100644 --- a/src/main/resources/static/js/filter.js +++ b/src/main/resources/static/js/filter.js @@ -16,6 +16,7 @@ function updateStatus() { updateStatusForSectionByCheckboxes('section-type'); updateStatusForSectionByCheckboxes('section-repeating'); updateStatusForSectionByCheckboxes('section-categories'); + updateStatusForSectionByCheckboxes('section-tags'); updateStatusForSectionName('section-name'); } diff --git a/src/main/resources/templates/filter/filterMacros.ftl b/src/main/resources/templates/filter/filterMacros.ftl index a76321771..6b924e46f 100644 --- a/src/main/resources/templates/filter/filterMacros.ftl +++ b/src/main/resources/templates/filter/filterMacros.ftl @@ -117,6 +117,30 @@ </div> </li> + <li id="section-tags"> + <div class="collapsible-header"> + <i class="material-icons">label</i> + ${locale.getString("filter.tags")} + <div class="collapsible-header-status"></div> + </div> + <div class="collapsible-body"> + <div class="row no-margin"> + <div class="col s12"> + <#list filterConfiguration.getFilterTags() as filterTag> + <div> + <label> + <input type="checkbox" name="filterTags['${filterTag?index}'].include" <#if filterTag.isInclude()>checked="checked"</#if>> + <span class="text-color">${filterTag.getName()}</span> + </label> + <input type="hidden" name="filterTags['${filterTag?index}'].ID" value="${filterTag.getID()}"/> + <input type="hidden" name="filterTags['${filterTag?index}'].name" value="${filterTag.getName()}"/> + </div> + </#list> + </div> + </div> + </div> + </li> + <li id="section-name"> <div class="collapsible-header"> <i class="material-icons">subject</i> diff --git a/src/test/java/de/deadlocker8/budgetmaster/TransactionRepositoryTest.java b/src/test/java/de/deadlocker8/budgetmaster/TransactionRepositoryTest.java index cac3facef..83dd4c78e 100644 --- a/src/test/java/de/deadlocker8/budgetmaster/TransactionRepositoryTest.java +++ b/src/test/java/de/deadlocker8/budgetmaster/TransactionRepositoryTest.java @@ -4,15 +4,13 @@ import de.deadlocker8.budgetmaster.entities.account.Account; import de.deadlocker8.budgetmaster.entities.account.AccountType; import de.deadlocker8.budgetmaster.entities.category.Category; import de.deadlocker8.budgetmaster.entities.category.CategoryType; +import de.deadlocker8.budgetmaster.entities.tag.Tag; import de.deadlocker8.budgetmaster.entities.transaction.Transaction; import de.deadlocker8.budgetmaster.entities.transaction.TransactionSpecifications; import de.deadlocker8.budgetmaster.repeating.RepeatingOption; import de.deadlocker8.budgetmaster.repeating.endoption.RepeatingEndAfterXTimes; import de.deadlocker8.budgetmaster.repeating.modifier.RepeatingModifierDays; -import de.deadlocker8.budgetmaster.repositories.AccountRepository; -import de.deadlocker8.budgetmaster.repositories.CategoryRepository; -import de.deadlocker8.budgetmaster.repositories.RepeatingOptionRepository; -import de.deadlocker8.budgetmaster.repositories.TransactionRepository; +import de.deadlocker8.budgetmaster.repositories.*; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.junit.Before; @@ -49,6 +47,10 @@ public class TransactionRepositoryTest private AccountRepository accountRepository; private Account account; + @Autowired + private TagRepository tagRepository; + private Tag tag1; + @Autowired private RepeatingOptionRepository repeatingOptionRepository; private RepeatingOption repeatingOption; @@ -65,6 +67,8 @@ public class TransactionRepositoryTest category1 = categoryRepository.save(new Category("Category1", "#ff0000", CategoryType.CUSTOM)); category2 = categoryRepository.save(new Category("Category2", "#ff0000", CategoryType.CUSTOM)); + tag1 = tagRepository.save(new Tag("MyAwesomeTag")); + transaction1 = new Transaction(); transaction1.setName("Test"); transaction1.setAmount(200); @@ -97,14 +101,16 @@ public class TransactionRepositoryTest repeatingTransaction.setDescription(""); repeatingTransaction.setAccount(account); repeatingTransaction.setRepeatingOption(repeatingOption); - repeatingTransaction.setTags(new ArrayList<>()); + ArrayList<Tag> tags = new ArrayList<>(); + tags.add(tag1); + repeatingTransaction.setTags(tags); repeatingTransaction = transactionRepository.save(repeatingTransaction); } @Test public void getIncomesAndExpenditures() { - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, null, null, null); + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, null, null, null, null); List<Transaction> results = transactionRepository.findAll(spec); assertTrue(results.contains(transaction1)); @@ -115,7 +121,7 @@ public class TransactionRepositoryTest @Test public void getIncomes() { - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, false, null, null, null); + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, false, null, null, null, null); List<Transaction> results = transactionRepository.findAll(spec); assertTrue(results.contains(transaction1)); @@ -126,7 +132,7 @@ public class TransactionRepositoryTest @Test public void getExpenditures() { - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, false, true, null, null, null); + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, false, true, null, null, null, null); List<Transaction> results = transactionRepository.findAll(spec); assertFalse(results.contains(transaction1)); @@ -137,7 +143,7 @@ public class TransactionRepositoryTest @Test public void incomesAndExpendituresFalse() { - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, false, false, null, null, null); + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, false, false, null, null, null, null); List<Transaction> results = transactionRepository.findAll(spec); assertTrue(results.contains(transaction1)); @@ -148,7 +154,7 @@ public class TransactionRepositoryTest @Test public void getRepeating() { - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, true, null, null); + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, true, null, null, null); List<Transaction> results = transactionRepository.findAll(spec); assertFalse(results.contains(transaction1)); @@ -159,7 +165,7 @@ public class TransactionRepositoryTest @Test public void noRepeating() { - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, false, null, null); + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, false, null, null, null); List<Transaction> results = transactionRepository.findAll(spec); assertTrue(results.contains(transaction1)); @@ -172,7 +178,7 @@ public class TransactionRepositoryTest { List<Integer> categoryIDs = new ArrayList<>(); categoryIDs.add(categoryUnused.getID()); - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, null, categoryIDs, null); + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, null, categoryIDs, null, null); List<Transaction> results = transactionRepository.findAll(spec); assertFalse(results.contains(transaction1)); @@ -185,7 +191,7 @@ public class TransactionRepositoryTest { List<Integer> categoryIDs = new ArrayList<>(); categoryIDs.add(category1.getID()); - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, null, categoryIDs, null); + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, null, categoryIDs, null, null); List<Transaction> results = transactionRepository.findAll(spec); assertTrue(results.contains(transaction1)); @@ -196,7 +202,7 @@ public class TransactionRepositoryTest @Test public void getByFullName() { - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, null, null, "Repeating"); + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, null, null, null, "Repeating"); List<Transaction> results = transactionRepository.findAll(spec); assertFalse(results.contains(transaction1)); @@ -207,7 +213,7 @@ public class TransactionRepositoryTest @Test public void getByPartialName() { - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, null, null, "tin"); + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, null, null, null, "tin"); List<Transaction> results = transactionRepository.findAll(spec); assertFalse(results.contains(transaction1)); @@ -216,11 +222,15 @@ public class TransactionRepositoryTest } @Test - public void getRepeatingExpenditureByCategoryAndName() + public void getRepeatingExpenditureByCategoryAndTagsAndName() { List<Integer> categoryIDs = new ArrayList<>(); categoryIDs.add(category1.getID()); - Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, false, true, true, categoryIDs, "Repeating"); + + List<Integer> tagIDs = new ArrayList<>(); + tagIDs.add(tag1.getID()); + + Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, false, true, true, categoryIDs, tagIDs, "Repeating"); List<Transaction> results = transactionRepository.findAll(spec); assertFalse(results.contains(transaction1)); -- GitLab