diff --git a/src/main/java/de/deadlocker8/budgetmaster/controller/ReportController.java b/src/main/java/de/deadlocker8/budgetmaster/controller/ReportController.java index dd4812e619bcfcddfaa61b37f5e2ff99f29b44cc..71256d2fafd9e5678cedefdc7f3744ac3360070e 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/controller/ReportController.java +++ b/src/main/java/de/deadlocker8/budgetmaster/controller/ReportController.java @@ -1,27 +1,41 @@ package de.deadlocker8.budgetmaster.controller; +import com.itextpdf.text.DocumentException; +import de.deadlocker8.budgetmaster.entities.Transaction; +import de.deadlocker8.budgetmaster.entities.account.Account; import de.deadlocker8.budgetmaster.entities.report.ReportColumn; import de.deadlocker8.budgetmaster.entities.report.ReportSettings; -import de.deadlocker8.budgetmaster.repositories.SettingsRepository; +import de.deadlocker8.budgetmaster.reports.Budget; +import de.deadlocker8.budgetmaster.reports.ReportConfiguration; +import de.deadlocker8.budgetmaster.reports.ReportConfigurationBuilder; import de.deadlocker8.budgetmaster.services.HelpersService; +import de.deadlocker8.budgetmaster.services.SettingsService; +import de.deadlocker8.budgetmaster.services.TransactionService; import de.deadlocker8.budgetmaster.services.report.ReportColumnService; +import de.deadlocker8.budgetmaster.services.report.ReportGeneratorService; import de.deadlocker8.budgetmaster.services.report.ReportSettingsService; +import de.thecodelabs.utils.util.Localization; import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; -import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + @Controller public class ReportController extends BaseController { @Autowired - private SettingsRepository settingsRepository; + private SettingsService settingsService; @Autowired private ReportSettingsService reportSettingsService; @@ -29,6 +43,12 @@ public class ReportController extends BaseController @Autowired private ReportColumnService reportColumnService; + @Autowired + private ReportGeneratorService reportGeneratorService; + + @Autowired + private TransactionService transactionService; + @Autowired private HelpersService helpers; @@ -43,9 +63,8 @@ public class ReportController extends BaseController } @RequestMapping(value = "/reports/generate", method = RequestMethod.POST) - public String post(Model model, - @ModelAttribute("NewReportSettings") ReportSettings reportSettings, - BindingResult bindingResult) + public String post(HttpServletResponse response, + @ModelAttribute("NewReportSettings") ReportSettings reportSettings) { reportSettingsService.getRepository().delete(0); for(ReportColumn reportColumn : reportSettings.getColumns()) @@ -54,6 +73,47 @@ public class ReportController extends BaseController } reportSettingsService.getRepository().save(reportSettings); + + LOGGER.debug("Exporting month report..."); + + //TODO handle all accounts + Account account = helpers.getCurrentAccount(); + List<Transaction> transactions = transactionService.getTransactionsForMonthAndYear(account, reportSettings.getDate().getMonthOfYear(), reportSettings.getDate().getYear(), settingsService.getSettings().isRestActivated()); + Budget budget = new Budget(helpers.getIncomeSumForTransactionList(transactions), helpers.getExpenditureSumForTransactionList(transactions)); + + ReportConfiguration reportConfiguration = new ReportConfigurationBuilder() + .setBudget(budget) + .setCategoryBudgets(new ArrayList<>()) + .setReportSettings(reportSettings) + .setReportItems(new ArrayList<>()) + .createReportConfiguration(); + + try + { + byte[] dataBytes = reportGeneratorService.generate(reportConfiguration); + String fileName = Localization.getString("report.initial.filename", reportSettings.getDate().toString("MM"), reportSettings.getDate().toString("YYYY")); + response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); + + response.setContentType("application/pdf; charset=UTF-8"); + response.setContentLength(dataBytes.length); + response.setCharacterEncoding("UTF-8"); + + try(ServletOutputStream out = response.getOutputStream()) + { + out.write(dataBytes); + out.flush(); + LOGGER.debug("Exporting month report DONE"); + } + catch(IOException e) + { + e.printStackTrace(); + } + } + catch(DocumentException e) + { + e.printStackTrace(); + } + return "redirect:/reports"; } } \ No newline at end of file diff --git a/src/main/java/de/deadlocker8/budgetmaster/controller/TransactionController.java b/src/main/java/de/deadlocker8/budgetmaster/controller/TransactionController.java index 67ed4305ee60d1333ecfb046ca50f628e98eb1c8..28571dc05539049bc7cd7842a0234c17d99a83ef 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/controller/TransactionController.java +++ b/src/main/java/de/deadlocker8/budgetmaster/controller/TransactionController.java @@ -65,7 +65,7 @@ public class TransactionController extends BaseController List<Transaction> transactions = transactionService.getTransactionsForMonthAndYear(helpers.getCurrentAccount(), date.getMonthOfYear(), date.getYear(), getSettings().isRestActivated()); int incomeSum = helpers.getIncomeSumForTransactionList(transactions); - int paymentSum = helpers.getPaymentSumForTransactionList(transactions); + int paymentSum = helpers.getExpenditureSumForTransactionList(transactions); int rest = incomeSum + paymentSum; model.addAttribute("transactions", transactions); @@ -88,7 +88,7 @@ public class TransactionController extends BaseController DateTime date = helpers.getDateTimeFromCookie(cookieDate); List<Transaction> transactions = transactionService.getTransactionsForMonthAndYear(helpers.getCurrentAccount(), date.getMonthOfYear(), date.getYear(), getSettings().isRestActivated()); int incomeSum = helpers.getIncomeSumForTransactionList(transactions); - int paymentSum = helpers.getPaymentSumForTransactionList(transactions); + int paymentSum = helpers.getExpenditureSumForTransactionList(transactions); int rest = incomeSum + paymentSum; model.addAttribute("transactions", transactions); diff --git a/src/main/java/de/deadlocker8/budgetmaster/entities/report/ReportSettings.java b/src/main/java/de/deadlocker8/budgetmaster/entities/report/ReportSettings.java index 7ddead4f055d4c2ab0c319c29168b1c8921ab65d..2b84a578ad8c705ecef4c95ba12fdca0e3fd1175 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/entities/report/ReportSettings.java +++ b/src/main/java/de/deadlocker8/budgetmaster/entities/report/ReportSettings.java @@ -9,6 +9,7 @@ import javax.persistence.OneToMany; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; @Entity public class ReportSettings @@ -96,8 +97,12 @@ public class ReportSettings public List<ReportColumn> getColumnsSorted() { - columns.sort(Comparator.comparing(ReportColumn::getPosition)); - return columns; + return columns.stream().sorted(Comparator.comparing(ReportColumn::getPosition)).collect(Collectors.toList()); + } + + public List<ReportColumn> getColumnsSortedAndFiltered() + { + return columns.stream().filter(ReportColumn::isActivated).sorted(Comparator.comparing(ReportColumn::getPosition)).collect(Collectors.toList()); } public List<ReportColumn> getColumns() diff --git a/src/main/java/de/deadlocker8/budgetmaster/reports/Budget.java b/src/main/java/de/deadlocker8/budgetmaster/reports/Budget.java new file mode 100644 index 0000000000000000000000000000000000000000..5ac312beeb664e61c1220b51bec412e80806f05d --- /dev/null +++ b/src/main/java/de/deadlocker8/budgetmaster/reports/Budget.java @@ -0,0 +1,32 @@ +package de.deadlocker8.budgetmaster.reports; + +public class Budget +{ + private double incomeSum; + private double expenditureSum; + + public Budget(double incomeSum, double expenditureSum) + { + this.incomeSum = incomeSum; + this.expenditureSum = expenditureSum; + } + + public double getIncomeSum() + { + return incomeSum; + } + + public double getExpenditureSum() + { + return expenditureSum; + } + + @Override + public String toString() + { + return "Budget{" + + "incomeSum=" + incomeSum + + ", expenditureSum=" + expenditureSum + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/de/deadlocker8/budgetmaster/reports/CategoryBudget.java b/src/main/java/de/deadlocker8/budgetmaster/reports/CategoryBudget.java new file mode 100644 index 0000000000000000000000000000000000000000..5c174297fbf620ecd4941ed340f7982714a914fe --- /dev/null +++ b/src/main/java/de/deadlocker8/budgetmaster/reports/CategoryBudget.java @@ -0,0 +1,41 @@ +package de.deadlocker8.budgetmaster.reports; + +import de.deadlocker8.budgetmaster.entities.category.Category; + +public class CategoryBudget +{ + private Category category; + private double budget; + + public CategoryBudget(Category category, double budget) + { + this.category = category; + this.budget = budget; + } + + public Category getCategory() + { + return category; + } + + public void setCategory(Category category) + { + this.category = category; + } + + public double getBudget() + { + return budget; + } + + public void setBudget(double budget) + { + this.budget = budget; + } + + @Override + public String toString() + { + return "CategoryBudget [category=" + category + ", budget=" + budget + "]"; + } +} \ No newline at end of file diff --git a/src/main/java/de/deadlocker8/budgetmaster/reports/ColumnType.java b/src/main/java/de/deadlocker8/budgetmaster/reports/ColumnType.java index 89d417eabaadb5ff68a6a484a81436f692fcb676..afb9a7c4b6e3b48fc9b2e3875163b415647620ce 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/reports/ColumnType.java +++ b/src/main/java/de/deadlocker8/budgetmaster/reports/ColumnType.java @@ -26,6 +26,19 @@ public enum ColumnType this.proportion = proportion; } + public static ColumnType getByName(String name) + { + for(ColumnType type : ColumnType.values()) + { + if(type.name.equalsIgnoreCase(name)) + { + return type; + } + } + + return null; + } + public String getName() { return Localization.getString(name); diff --git a/src/main/java/de/deadlocker8/budgetmaster/reports/ReportConfiguration.java b/src/main/java/de/deadlocker8/budgetmaster/reports/ReportConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..283349f6d1a6da6ef8549be9e660adb194f4dfed --- /dev/null +++ b/src/main/java/de/deadlocker8/budgetmaster/reports/ReportConfiguration.java @@ -0,0 +1,53 @@ +package de.deadlocker8.budgetmaster.reports; + +import de.deadlocker8.budgetmaster.entities.Transaction; +import de.deadlocker8.budgetmaster.entities.report.ReportSettings; + +import java.util.ArrayList; + +public class ReportConfiguration +{ + private ArrayList<Transaction> transactions; + private ArrayList<CategoryBudget> categoryBudgets; + private ReportSettings reportSettings; + private Budget budget; + + public ReportConfiguration(ArrayList<Transaction> transactions, ArrayList<CategoryBudget> categoryBudgets, ReportSettings reportSettings, Budget budget) + { + this.transactions = transactions; + this.categoryBudgets = categoryBudgets; + this.reportSettings = reportSettings; + this.budget = budget; + } + + public ArrayList<Transaction> getTransactions() + { + return transactions; + } + + public ArrayList<CategoryBudget> getCategoryBudgets() + { + return categoryBudgets; + } + + public ReportSettings getReportSettings() + { + return reportSettings; + } + + public Budget getBudget() + { + return budget; + } + + @Override + public String toString() + { + return "ReportConfiguration{" + + "transactions=" + transactions + + ", categoryBudgets=" + categoryBudgets + + ", reportSettings=" + reportSettings + + ", budget=" + budget + + '}'; + } +} diff --git a/src/main/java/de/deadlocker8/budgetmaster/reports/ReportConfigurationBuilder.java b/src/main/java/de/deadlocker8/budgetmaster/reports/ReportConfigurationBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..1668579db3eef221b9b43709c38ae43f2466557b --- /dev/null +++ b/src/main/java/de/deadlocker8/budgetmaster/reports/ReportConfigurationBuilder.java @@ -0,0 +1,43 @@ +package de.deadlocker8.budgetmaster.reports; + +import de.deadlocker8.budgetmaster.entities.Transaction; +import de.deadlocker8.budgetmaster.entities.report.ReportSettings; + +import java.util.ArrayList; + +public class ReportConfigurationBuilder +{ + private ArrayList<Transaction> transactions; + private ArrayList<CategoryBudget> categoryBudgets; + private ReportSettings reportSettings; + private Budget budget; + + public ReportConfigurationBuilder setReportItems(ArrayList<Transaction> transactions) + { + this.transactions = transactions; + return this; + } + + public ReportConfigurationBuilder setCategoryBudgets(ArrayList<CategoryBudget> categoryBudgets) + { + this.categoryBudgets = categoryBudgets; + return this; + } + + public ReportConfigurationBuilder setReportSettings(ReportSettings reportSettings) + { + this.reportSettings = reportSettings; + return this; + } + + public ReportConfigurationBuilder setBudget(Budget budget) + { + this.budget = budget; + return this; + } + + public ReportConfiguration createReportConfiguration() + { + return new ReportConfiguration(transactions, categoryBudgets, reportSettings, budget); + } +} \ No newline at end of file diff --git a/src/main/java/de/deadlocker8/budgetmaster/reports/ReportGenerator.java b/src/main/java/de/deadlocker8/budgetmaster/reports/ReportGenerator.java deleted file mode 100644 index d015ac81ed43d393b77c6037813fb52599c35e80..0000000000000000000000000000000000000000 --- a/src/main/java/de/deadlocker8/budgetmaster/reports/ReportGenerator.java +++ /dev/null @@ -1,297 +0,0 @@ -package de.deadlocker8.budgetmaster.reports; - -//import java.awt.Color; -//import java.io.File; -//import java.io.FileNotFoundException; -//import java.io.FileOutputStream; -//import java.util.ArrayList; -// -//import org.joda.time.DateTime; -//import org.joda.time.format.DateTimeFormat; -// -//import com.itextpdf.text.BaseColor; -//import com.itextpdf.text.Chapter; -//import com.itextpdf.text.Chunk; -//import com.itextpdf.text.Document; -//import com.itextpdf.text.DocumentException; -//import com.itextpdf.text.Element; -//import com.itextpdf.text.Font; -//import com.itextpdf.text.FontFactory; -//import com.itextpdf.text.Paragraph; -//import com.itextpdf.text.Phrase; -//import com.itextpdf.text.pdf.BaseFont; -//import com.itextpdf.text.pdf.GrayColor; -//import com.itextpdf.text.pdf.PdfPCell; -//import com.itextpdf.text.pdf.PdfPTable; -//import com.itextpdf.text.pdf.PdfWriter; -// -//import de.deadlocker8.budgetmaster.logic.Budget; -//import de.deadlocker8.budgetmaster.logic.category.CategoryBudget; -//import de.deadlocker8.budgetmaster.logic.utils.Fonts; -//import de.deadlocker8.budgetmaster.logic.utils.Helpers; -//import de.deadlocker8.budgetmaster.logic.utils.Strings; -//import tools.Localization; - -public class ReportGenerator -{ -// private ArrayList<ReportItem> reportItems; -// private ArrayList<CategoryBudget> categoryBudgets; -// private ReportPreferences reportPreferences; -// private File savePath; -// private String currency; -// private DateTime date; -// private Budget budget; -// private final String FONT = Fonts.OPEN_SANS; -// -// public ReportGenerator(ArrayList<ReportItem> reportItems, ArrayList<CategoryBudget> categoryBudgets, ReportPreferences reportPreferences, File savePath, String currency, DateTime date, Budget budget) -// { -// this.reportItems = reportItems; -// this.categoryBudgets = categoryBudgets; -// this.reportPreferences = reportPreferences; -// this.savePath = savePath; -// this.currency = currency; -// this.date = date; -// this.budget = budget; -// } -// -// private Chapter generateHeader() -// { -// Font font = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 16, Font.BOLDITALIC, BaseColor.BLACK); -// Chunk chunk = new Chunk(Localization.getString(Strings.REPORT_HEADLINE, date.toString("MMMM yyyy")), font); -// Chapter chapter = new Chapter(new Paragraph(chunk), 1); -// chapter.setNumberDepth(0); -// chapter.add(Chunk.NEWLINE); -// return chapter; -// } -// -// private PdfPTable generateTable(int tableWidth, AmountType amountType) -// { -// int numberOfColumns = reportPreferences.getColumnOrder().getColumns().size(); -// int totalIncome = 0; -// int totalPayment = 0; -// -// if(numberOfColumns > 0) -// { -// float[] proportions = new float[numberOfColumns]; -// for(int i = 0; i < reportPreferences.getColumnOrder().getColumns().size(); i++) -// { -// proportions[i] = reportPreferences.getColumnOrder().getColumns().get(i).getProportion(); -// } -// -// PdfPTable table = new PdfPTable(proportions); -// table.setWidthPercentage(tableWidth); -// Font font = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 8, Font.NORMAL, GrayColor.BLACK); -// -// for(ColumnType column : reportPreferences.getColumnOrder().getColumns()) -// { -// PdfPCell cell = new PdfPCell(new Phrase(column.getName(), font)); -// cell.setBackgroundColor(GrayColor.LIGHT_GRAY); -// cell.setHorizontalAlignment(Element.ALIGN_CENTER); -// cell.setVerticalAlignment(Element.ALIGN_MIDDLE); -// table.addCell(cell); -// } -// -// for(ReportItem currentItem : reportItems) -// { -// if(currentItem.getAmount() > 0) -// { -// totalIncome += currentItem.getAmount(); -// if(amountType == AmountType.PAYMENT) -// { -// continue; -// } -// } -// else -// { -// totalPayment += currentItem.getAmount(); -// if(amountType == AmountType.INCOME) -// { -// continue; -// } -// } -// -// for(ColumnType column : reportPreferences.getColumnOrder().getColumns()) -// { -// PdfPCell cell = new PdfPCell(new Phrase(getProperty(currentItem, column), font)); -// cell.setBackgroundColor(new BaseColor(Color.WHITE)); -// cell.setHorizontalAlignment(Element.ALIGN_CENTER); -// cell.setVerticalAlignment(Element.ALIGN_MIDDLE); -// table.addCell(cell); -// } -// } -// -// PdfPCell cellTotal; -// String total = ""; -// switch(amountType) -// { -// case BOTH: -// String totalIncomeString = Helpers.getCurrencyString(totalIncome, currency); -// String totalPaymentString = Helpers.getCurrencyString(totalPayment, currency); -// total = Localization.getString(Strings.REPORT_SUM_TOTAL, totalIncomeString, totalPaymentString); -// break; -// case INCOME: -// total = Localization.getString(Strings.REPORT_SUM, Helpers.getCurrencyString(totalIncome, currency)); -// break; -// case PAYMENT: -// total = Localization.getString(Strings.REPORT_SUM, Helpers.getCurrencyString(totalPayment, currency)); -// break; -// default: -// break; -// } -// -// cellTotal = new PdfPCell(new Phrase(total, font)); -// cellTotal.setBackgroundColor(new BaseColor(Color.WHITE)); -// cellTotal.setColspan(numberOfColumns); -// cellTotal.setHorizontalAlignment(Element.ALIGN_RIGHT); -// cellTotal.setVerticalAlignment(Element.ALIGN_MIDDLE); -// table.addCell(cellTotal); -// -// return table; -// } -// return null; -// } -// -// public void generate() throws FileNotFoundException, DocumentException -// { -// Document document = new Document(); -// PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(savePath)); -// writer.setPageEvent(new HeaderFooterPageEvent()); -// document.open(); -// document.setMargins(50, 45, 50, 70); -// Font headerFont = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 14, Font.BOLD, BaseColor.BLACK); -// Font smallHeaderFont = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12, Font.BOLD, BaseColor.BLACK); -// -// document.add(generateHeader()); -// document.add(Chunk.NEWLINE); -// -// if(reportPreferences.isIncludeBudget()) -// { -// Font fontGreen = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12, Font.NORMAL, new BaseColor(36, 122, 45)); -// Font fontRed = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12, Font.NORMAL, BaseColor.RED); -// Font fontBlack = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12, Font.BOLD, BaseColor.BLACK); -// -// document.add(new Paragraph(Localization.getString(Strings.REPORT_BUDGET), headerFont)); -// document.add(Chunk.NEWLINE); -// document.add(new Paragraph(Localization.getString(Strings.REPORT_INCOMES) + Helpers.getCurrencyString(budget.getIncomeSum(), currency), fontGreen)); -// document.add(new Paragraph(Localization.getString(Strings.REPORT_PAYMENTS) + Helpers.getCurrencyString(budget.getPaymentSum(), currency), fontRed)); -// document.add(new Paragraph(Localization.getString(Strings.REPORT_BUDGET_REST) + Helpers.getCurrencyString(budget.getIncomeSum() + budget.getPaymentSum(), currency), fontBlack)); -// document.add(Chunk.NEWLINE); -// } -// -// document.add(new Paragraph(Localization.getString(Strings.REPORT_HEADLINE_PAYMENTS_OVERVIEW), headerFont)); -// document.add(Chunk.NEWLINE); -// -// if(reportPreferences.isSplitTable()) -// { -// document.add(new Paragraph(Localization.getString(Strings.TITLE_INCOMES), smallHeaderFont)); -// document.add(Chunk.NEWLINE); -// -// PdfPTable table = generateTable(100, AmountType.INCOME); -// if(table != null) -// { -// document.add(table); -// } -// -// document.add(Chunk.NEWLINE); -// document.add(new Paragraph(Localization.getString(Strings.TITLE_PAYMENTS), smallHeaderFont)); -// document.add(Chunk.NEWLINE); -// -// table = generateTable(100, AmountType.PAYMENT); -// if(table != null) -// { -// document.add(table); -// } -// } -// else -// { -// PdfPTable table = generateTable(100, AmountType.BOTH); -// if(table != null) -// { -// document.add(table); -// } -// } -// -// if(reportPreferences.isIncludeCategoryBudgets()) -// { -// document.add(Chunk.NEWLINE); -// document.add(new Paragraph(Localization.getString(Strings.TITLE_CATEGORY_BUDGETS), smallHeaderFont)); -// document.add(Chunk.NEWLINE); -// -// PdfPTable table = generateCategoryBudgets(); -// if(table != null) -// { -// document.add(table); -// } -// } -// -// document.close(); -// } -// -// private PdfPTable generateCategoryBudgets() -// { -// PdfPTable table = new PdfPTable(2); -// table.setWidthPercentage(100); -// Font font = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 8, Font.NORMAL, BaseColor.BLACK); -// -// //header cells -// PdfPCell cellHeaderCategory = new PdfPCell(new Phrase(Localization.getString(Strings.TITLE_CATEGORY), font)); -// cellHeaderCategory.setBackgroundColor(GrayColor.LIGHT_GRAY); -// cellHeaderCategory.setHorizontalAlignment(Element.ALIGN_CENTER); -// table.addCell(cellHeaderCategory); -// PdfPCell cellHeaderAmount = new PdfPCell(new Phrase(Localization.getString(Strings.TITLE_AMOUNT), font)); -// cellHeaderAmount.setBackgroundColor(GrayColor.LIGHT_GRAY); -// cellHeaderAmount.setHorizontalAlignment(Element.ALIGN_CENTER); -// table.addCell(cellHeaderAmount); -// -// for(CategoryBudget budget : categoryBudgets) -// { -// PdfPCell cellName = new PdfPCell(new Phrase(budget.getCategory().getName(), font)); -// cellName.setBackgroundColor(new BaseColor(Color.WHITE)); -// cellName.setHorizontalAlignment(Element.ALIGN_CENTER); -// cellName.setVerticalAlignment(Element.ALIGN_MIDDLE); -// table.addCell(cellName); -// -// PdfPCell cellAmount = new PdfPCell(new Phrase(Helpers.getCurrencyString(budget.getBudget() / 100.0, currency), font)); -// cellAmount.setBackgroundColor(new BaseColor(Color.WHITE)); -// cellAmount.setHorizontalAlignment(Element.ALIGN_CENTER); -// cellAmount.setVerticalAlignment(Element.ALIGN_MIDDLE); -// table.addCell(cellAmount); -// } -// -// return table; -// } -// -// private String getProperty(ReportItem reportItem, ColumnType columnType) -// { -// switch(columnType) -// { -// case AMOUNT: -// return Helpers.getCurrencyString(reportItem.getAmount(), currency); -// case CATEGORY: -// return reportItem.getCategory().getName(); -// case DATE: -// return DateTime.parse(reportItem.getDate(), DateTimeFormat.forPattern("YYYY-MM-dd")).toString("dd.MM.YYYY"); -// case DESCRIPTION: -// return reportItem.getDescription(); -// case TAGS: -// return reportItem.getTags(); -// case NAME: -// return reportItem.getName(); -// case POSITION: -// return String.valueOf(reportItem.getPosition()); -// case RATING: -// return reportItem.getAmount() > 0 ? "+" : "-"; -// case REPEATING: -// if(reportItem.getRepeating()) -// { -// return Localization.getString(Strings.REPORT_REPEATING_YES); -// } -// else -// { -// return Localization.getString(Strings.REPORT_REPEATING_NO); -// } -// default: -// return null; -// } -// } -} \ No newline at end of file diff --git a/src/main/java/de/deadlocker8/budgetmaster/reports/ReportItem.java b/src/main/java/de/deadlocker8/budgetmaster/reports/ReportItem.java deleted file mode 100644 index 3223635cc1cabcb2879fcd02b6898429e4c1a23b..0000000000000000000000000000000000000000 --- a/src/main/java/de/deadlocker8/budgetmaster/reports/ReportItem.java +++ /dev/null @@ -1,107 +0,0 @@ -package de.deadlocker8.budgetmaster.reports; - - -import de.deadlocker8.budgetmaster.entities.category.Category; - -public class ReportItem -{ - private int position; - private int amount; - private String date; - private Category category; - private String name; - private String description; - private String tags; - private boolean repeating; - - public ReportItem() - { - - } - - public int getPosition() - { - return position; - } - - public void setPosition(int position) - { - this.position = position; - } - - public int getAmount() - { - return amount; - } - - public void setAmount(int amount) - { - this.amount = amount; - } - - public String getDate() - { - return date; - } - - public void setDate(String date) - { - this.date = date; - } - - public Category getCategory() - { - return category; - } - - public void setCategory(Category category) - { - this.category = category; - } - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public String getDescription() - { - return description; - } - - public void setDescription(String description) - { - this.description = description; - } - - public String getTags() - { - return tags; - } - - public void setTags(String tags) - { - this.tags = tags; - } - - public boolean getRepeating() - { - return repeating; - } - - public void setRepeating(boolean repeating) - { - this.repeating = repeating; - } - - @Override - public String toString() - { - return "ReportItem [position=" + position + ", amount=" + amount + ", date=" + date + ", category=" + category + ", name=" + name + ", description=" + description + ", tags=" + tags + ", repeating=" + repeating + "]"; - } -} \ No newline at end of file diff --git a/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java b/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java index 32ce882fd3ba57918c0c6e31e36516b3029b94f0..8237019369115a7fb013408f5a47309b4714f689 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java +++ b/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java @@ -231,7 +231,7 @@ public class HelpersService return sum; } - public int getPaymentSumForTransactionList(List<Transaction> transactions) + public int getExpenditureSumForTransactionList(List<Transaction> transactions) { int sum = 0; for(Transaction transaction : transactions) diff --git a/src/main/java/de/deadlocker8/budgetmaster/services/report/ReportGeneratorService.java b/src/main/java/de/deadlocker8/budgetmaster/services/report/ReportGeneratorService.java new file mode 100644 index 0000000000000000000000000000000000000000..79aa8a21116d42c4abd075d2652d0b487b8923d8 --- /dev/null +++ b/src/main/java/de/deadlocker8/budgetmaster/services/report/ReportGeneratorService.java @@ -0,0 +1,290 @@ +package de.deadlocker8.budgetmaster.services.report; + +import com.itextpdf.text.*; +import com.itextpdf.text.pdf.*; +import de.deadlocker8.budgetmaster.entities.Tag; +import de.deadlocker8.budgetmaster.entities.Transaction; +import de.deadlocker8.budgetmaster.entities.report.ReportColumn; +import de.deadlocker8.budgetmaster.reports.*; +import de.deadlocker8.budgetmaster.services.HelpersService; +import de.deadlocker8.budgetmaster.utils.Strings; +import de.thecodelabs.utils.util.Localization; +import javafx.scene.paint.Color; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.ByteArrayOutputStream; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class ReportGeneratorService +{ + @Autowired + HelpersService helpersService; + + private final static String FONT = Fonts.OPEN_SANS; + + @Autowired + public ReportGeneratorService(HelpersService helpersService) + { + this.helpersService = helpersService; + } + + private Chapter generateHeader(ReportConfiguration reportConfiguration) + { + Font font = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 16, Font.BOLDITALIC, BaseColor.BLACK); + Chunk chunk = new Chunk(Localization.getString(Strings.REPORT_HEADLINE, reportConfiguration.getReportSettings().getDate().toString("MMMM yyyy")), font); + Chapter chapter = new Chapter(new Paragraph(chunk), 1); + chapter.setNumberDepth(0); + chapter.add(Chunk.NEWLINE); + return chapter; + } + + private PdfPTable generateTable(ReportConfiguration reportConfiguration, int tableWidth, AmountType amountType) + { + List<ReportColumn> columns = reportConfiguration.getReportSettings().getColumnsSortedAndFiltered(); + int numberOfColumns = columns.size(); + int totalIncome = 0; + int totalPayment = 0; + + if(numberOfColumns > 0) + { + float[] proportions = new float[numberOfColumns]; + for(int i = 0; i < columns.size(); i++) + { + ReportColumn column = columns.get(i); + proportions[i] = ColumnType.getByName(column.getKey()).getProportion(); + } + + PdfPTable table = new PdfPTable(proportions); + table.setWidthPercentage(tableWidth); + Font font = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 8, Font.NORMAL, GrayColor.BLACK); + + // add table header + for(ReportColumn column : columns) + { + ColumnType columnType = ColumnType.getByName(column.getKey()); + + PdfPCell cell = new PdfPCell(new Phrase(columnType.getName(), font)); + cell.setBackgroundColor(GrayColor.LIGHT_GRAY); + cell.setHorizontalAlignment(Element.ALIGN_CENTER); + cell.setVerticalAlignment(Element.ALIGN_MIDDLE); + table.addCell(cell); + } + + for(Transaction currentItem : reportConfiguration.getTransactions()) + { + if(currentItem.getAmount() > 0) + { + totalIncome += currentItem.getAmount(); + if(amountType == AmountType.PAYMENT) + { + continue; + } + } + else + { + totalPayment += currentItem.getAmount(); + if(amountType == AmountType.INCOME) + { + continue; + } + } + + for(int i = 0; i < columns.size(); i++) + { + ReportColumn column = columns.get(i); + ColumnType columnType = ColumnType.getByName(column.getKey()); + PdfPCell cell = new PdfPCell(new Phrase(getProperty(currentItem, columnType, i), font)); + cell.setBackgroundColor(getBaseColor(Color.WHITE)); + cell.setHorizontalAlignment(Element.ALIGN_CENTER); + cell.setVerticalAlignment(Element.ALIGN_MIDDLE); + table.addCell(cell); + } + } + + PdfPCell cellTotal; + String total = ""; + switch(amountType) + { + case BOTH: + String totalIncomeString = helpersService.getCurrencyString(totalIncome); + String totalPaymentString = helpersService.getCurrencyString(totalPayment); + total = Localization.getString(Strings.REPORT_SUM_TOTAL, totalIncomeString, totalPaymentString); + break; + case INCOME: + total = Localization.getString(Strings.REPORT_SUM, helpersService.getCurrencyString(totalIncome)); + break; + case PAYMENT: + total = Localization.getString(Strings.REPORT_SUM, helpersService.getCurrencyString(totalPayment)); + break; + default: + break; + } + + cellTotal = new PdfPCell(new Phrase(total, font)); + cellTotal.setBackgroundColor(getBaseColor(Color.WHITE)); + cellTotal.setColspan(numberOfColumns); + cellTotal.setHorizontalAlignment(Element.ALIGN_RIGHT); + cellTotal.setVerticalAlignment(Element.ALIGN_MIDDLE); + table.addCell(cellTotal); + + return table; + } + return null; + } + + public byte[] generate(ReportConfiguration reportConfiguration) throws DocumentException + { + Document document = new Document(); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + PdfWriter writer = PdfWriter.getInstance(document, byteArrayOutputStream); + writer.setPageEvent(new HeaderFooterPageEvent()); + document.open(); + document.setMargins(50, 45, 50, 70); + Font headerFont = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 14, Font.BOLD, BaseColor.BLACK); + Font smallHeaderFont = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12, Font.BOLD, BaseColor.BLACK); + + document.add(generateHeader(reportConfiguration)); + document.add(Chunk.NEWLINE); + + if(reportConfiguration.getReportSettings().isIncludeBudget()) + { + Font fontGreen = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12, Font.NORMAL, new BaseColor(36, 122, 45)); + Font fontRed = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12, Font.NORMAL, BaseColor.RED); + Font fontBlack = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12, Font.BOLD, BaseColor.BLACK); + + Budget budget = reportConfiguration.getBudget(); + + document.add(new Paragraph(Localization.getString(Strings.REPORT_BUDGET), headerFont)); + document.add(Chunk.NEWLINE); + document.add(new Paragraph(Localization.getString(Strings.REPORT_INCOMES) + helpersService.getCurrencyString(budget.getIncomeSum()), fontGreen)); + document.add(new Paragraph(Localization.getString(Strings.REPORT_PAYMENTS) + helpersService.getCurrencyString(budget.getExpenditureSum()), fontRed)); + document.add(new Paragraph(Localization.getString(Strings.REPORT_BUDGET_REST) + helpersService.getCurrencyString(budget.getIncomeSum() + budget.getExpenditureSum()), fontBlack)); + document.add(Chunk.NEWLINE); + } + + document.add(new Paragraph(Localization.getString(Strings.REPORT_HEADLINE_TRANSACTIONS_OVERVIEW), headerFont)); + document.add(Chunk.NEWLINE); + + if(reportConfiguration.getReportSettings().isSplitTables()) + { + document.add(new Paragraph(Localization.getString(Strings.TITLE_INCOMES), smallHeaderFont)); + document.add(Chunk.NEWLINE); + + PdfPTable table = generateTable(reportConfiguration, 100, AmountType.INCOME); + if(table != null) + { + document.add(table); + } + + document.add(Chunk.NEWLINE); + document.add(new Paragraph(Localization.getString(Strings.TITLE_EXPENDITURES), smallHeaderFont)); + document.add(Chunk.NEWLINE); + + table = generateTable(reportConfiguration,100, AmountType.PAYMENT); + if(table != null) + { + document.add(table); + } + } + else + { + PdfPTable table = generateTable(reportConfiguration, 100, AmountType.BOTH); + if(table != null) + { + document.add(table); + } + } + + if(reportConfiguration.getReportSettings().isIncludeCategoryBudgets()) + { + document.add(Chunk.NEWLINE); + document.add(new Paragraph(Localization.getString(Strings.TITLE_CATEGORY_BUDGETS), smallHeaderFont)); + document.add(Chunk.NEWLINE); + + PdfPTable table = generateCategoryBudgets(reportConfiguration); + if(table != null) + { + document.add(table); + } + } + + document.close(); + return byteArrayOutputStream.toByteArray(); + } + + private PdfPTable generateCategoryBudgets(ReportConfiguration reportConfiguration) + { + PdfPTable table = new PdfPTable(2); + table.setWidthPercentage(100); + Font font = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 8, Font.NORMAL, BaseColor.BLACK); + + //header cells + PdfPCell cellHeaderCategory = new PdfPCell(new Phrase(Localization.getString(Strings.REPORT_CATEGORY), font)); + cellHeaderCategory.setBackgroundColor(GrayColor.LIGHT_GRAY); + cellHeaderCategory.setHorizontalAlignment(Element.ALIGN_CENTER); + table.addCell(cellHeaderCategory); + PdfPCell cellHeaderAmount = new PdfPCell(new Phrase(Localization.getString(Strings.REPORT_AMOUNT), font)); + cellHeaderAmount.setBackgroundColor(GrayColor.LIGHT_GRAY); + cellHeaderAmount.setHorizontalAlignment(Element.ALIGN_CENTER); + table.addCell(cellHeaderAmount); + + for(CategoryBudget budget : reportConfiguration.getCategoryBudgets()) + { + PdfPCell cellName = new PdfPCell(new Phrase(budget.getCategory().getName(), font)); + cellName.setBackgroundColor(getBaseColor(Color.WHITE)); + cellName.setHorizontalAlignment(Element.ALIGN_CENTER); + cellName.setVerticalAlignment(Element.ALIGN_MIDDLE); + table.addCell(cellName); + + PdfPCell cellAmount = new PdfPCell(new Phrase(helpersService.getCurrencyString(budget.getBudget() / 100.0), font)); + cellAmount.setBackgroundColor(getBaseColor(Color.WHITE)); + cellAmount.setHorizontalAlignment(Element.ALIGN_CENTER); + cellAmount.setVerticalAlignment(Element.ALIGN_MIDDLE); + table.addCell(cellAmount); + } + + return table; + } + + private String getProperty(Transaction transaction, ColumnType columnType, int position) + { + switch(columnType) + { + case AMOUNT: + return helpersService.getCurrencyString(transaction.getAmount()); + case CATEGORY: + return transaction.getCategory().getName(); + case DATE: + return transaction.getDate().toString("dd.MM.YYYY"); + case DESCRIPTION: + return transaction.getDescription(); + case TAGS: + return transaction.getTags().stream().map(Tag::getName).collect(Collectors.joining(", ")); + case NAME: + return transaction.getName(); + case POSITION: + return String.valueOf(position); + case RATING: + return transaction.getAmount() > 0 ? "+" : "-"; + case REPEATING: + if(transaction.isRepeating()) + { + return Localization.getString(Strings.REPORT_REPEATING_YES); + } + else + { + return Localization.getString(Strings.REPORT_REPEATING_NO); + } + default: + return null; + } + } + + private BaseColor getBaseColor(Color color) + { + return new BaseColor((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue()); + } +} \ No newline at end of file diff --git a/src/main/java/de/deadlocker8/budgetmaster/utils/Strings.java b/src/main/java/de/deadlocker8/budgetmaster/utils/Strings.java index 23bb8956706fc87b5c92669bb51f396d2f86e066..0ea9e82c56496b2a33b26275aef3a8830b76a402 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/utils/Strings.java +++ b/src/main/java/de/deadlocker8/budgetmaster/utils/Strings.java @@ -6,6 +6,9 @@ public class Strings public static final String CATEGORY_NONE = "category.none"; public static final String CATEGORY_REST = "category.rest"; public static final String VERSION = "version"; + public static final String TITLE_INCOMES = "title.incomes"; + public static final String TITLE_EXPENDITURES = "title.expenditures"; + public static final String TITLE_CATEGORY_BUDGETS = "title.category.budgets"; //ACCOUNT public static final String ACCOUNT_DEFAULT_NAME = "account.default.name"; @@ -59,7 +62,7 @@ public class Strings public static final String REPORT_RATING = "report.rating"; public static final String REPORT_AMOUNT = "report.amount"; public static final String REPORT_HEADLINE = "report.headline"; - public static final String REPORT_HEADLINE_PAYMENTS_OVERVIEW = "report.headline.payments.overview"; + public static final String REPORT_HEADLINE_TRANSACTIONS_OVERVIEW = "report.headline.transactions.overview"; public static final String REPORT_SUM_TOTAL = "report.sum.total"; public static final String REPORT_SUM = "report.sum"; public static final String REPORT_REPEATING_YES ="report.repeating.yes"; @@ -67,6 +70,6 @@ public class Strings public static final String REPORT_INITIAL_FILENAME ="report.initial.filename"; public static final String REPORT_BUDGET = "report.budget"; public static final String REPORT_INCOMES = "report.incomes"; - public static final String REPORT_PAYMENTS = "report.payments"; + public static final String REPORT_PAYMENTS = "report.expenditures"; public static final String REPORT_BUDGET_REST = "report.budget.rest"; } \ No newline at end of file diff --git a/src/main/resources/languages/_de.properties b/src/main/resources/languages/_de.properties index ef2ca774437a0cffa9cdeaf5161870c00a15dc52..14449f562482aa6cd4d9ee138a3ae9d886716cd7 100644 --- a/src/main/resources/languages/_de.properties +++ b/src/main/resources/languages/_de.properties @@ -35,6 +35,7 @@ title.transaction.new=Neue Buchung title.datepicker=Datum w�hlen title.account.new=Neues Konto title.account.edit=Konto bearbeiten +title.category.budgets=Verbrauch nach Kategorien # MISC category.none=Keine Kategorie @@ -231,7 +232,7 @@ report.repeating.no=Nein report.initial.filename=BudgetMaster Monatsbericht - {0}_{1}.pdf report.budget=Budget report.incomes=Einnahmen: -report.payments=Ausgaben: +report.expenditures=Ausgaben: report.budget.rest=Restbudget: # home menu diff --git a/src/main/resources/languages/_en.properties b/src/main/resources/languages/_en.properties index 28e4810abf8fcc4e78689b617e8c609437b5517f..c11d823c78ba21285173101725eb3966808f9137 100644 --- a/src/main/resources/languages/_en.properties +++ b/src/main/resources/languages/_en.properties @@ -35,6 +35,7 @@ title.transaction.new=New Transaction title.datepicker=Choose date title.account.new=New Account title.account.edit=Edit Account +title.category.budgets=Consumption by categories # MISC category.none=No Category @@ -230,7 +231,7 @@ report.repeating.no=No report.initial.filename=BudgetMaster Month Report - {0}_{1}.pdf report.budget=Budget report.incomes=Incomes: -report.payments=Expenditures: +report.expenditures=Expenditures: report.budget.rest=Remaining Budget: # home menu