BrightSide Workbench Full Report + Source Code
ReportBody.java
Go to the documentation of this file.
1 /*
2  * TurrĂ³ i Cutiller Foundation. License notice.
3  * Copyright (C) 2020 Lluis TurrĂ³ Cutiller <http://www.turro.org/>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 package org.turro.financials.report;
20 
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.Writer;
24 import java.util.ArrayList;
25 import java.util.Date;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.TreeSet;
29 import java.util.logging.Level;
30 import java.util.logging.Logger;
31 import java.util.stream.Stream;
32 import org.turro.elephant.context.ElephantContext;
33 import org.turro.elephant.db.WhereClause;
34 import org.turro.elephant.impl.util.FileUtil;
35 import org.turro.financials.db.FinancialsPU;
36 import org.turro.financials.entity.RegisterEntry;
37 import org.turro.reflection.JSONSerializer;
38 
43 public class ReportBody {
44 
45  private String name;
46  private TreeSet<ReportRow> rows;
47  private TreeSet<ReportColumn> columns;
48  private transient HashMap<String, Double> values;
49  private transient HashMap<String, HashMap<String, Double>> sum;
50  private transient File file;
51 
52  public ReportBody(String name) {
53  this.name = name;
54  }
55 
56  public String getName() {
57  return name;
58  }
59 
60  public TreeSet<ReportRow> getRows() {
61  if(rows == null) rows = new TreeSet<>();
62  return rows;
63  }
64 
65  public TreeSet<ReportColumn> getColumns() {
66  if(columns == null) columns = new TreeSet<>();
67  return columns;
68  }
69 
70  public Double getValue(ReportRow row, ReportColumn column) {
71  if(values != null) {
72  Double accumulate = values.get(generateKey(row, column));
73  if(accumulate != null) {
74  return formatAndAddSum(row, column, accumulate);
75  }
76  }
77  return 0.0;
78  }
79 
80  public Double getSum(ReportRow row, ReportColumn column, String group) {
81  if(sum != null) {
82  Double total = sum.get(group).get(generateKey(null, column));
83  sum.get(group).put(generateKey(null, column), 0.0);
84  if(total != null) {
85  return row.isNegate() ? -total : total;
86  }
87  }
88  return 0.0;
89  }
90 
91  public File getFile() {
92  return file;
93  }
94 
95  public void fill(Date start, Date end) {
96  if(values != null) values.clear();
97  if(sum != null) sum.clear();
98  WhereClause wc = new WhereClause();
99  wc.addClause("select e from RegisterEntry e");
100  wc.addClause("where e.register.registerDate >= :start");
101  wc.addClause("and e.register.registerDate <= :end");
102  wc.addNamedValue("start", start);
103  wc.addNamedValue("end", end);
104  try(Stream<RegisterEntry> entries = new FinancialsPU().stream(RegisterEntry.class, wc)) {
105  entries.forEach((e) -> {
106  addEntry(e);
107  });
108  }
109  // Generate sum groups
110  if(sum == null) sum = new HashMap<>();
111  for(ReportRow row : getRows()) {
112  if(row.isSum()) {
113  sum.put(row.getGroup(), new HashMap<>());
114  }
115  }
116  }
117 
118  public boolean hasValues() {
119  return values != null && !values.isEmpty();
120  }
121 
122  private void setFile(File file) {
123  this.file = file;
124  }
125 
126  private void addEntry(RegisterEntry e) {
127  rows.forEach((row) -> {
128  if(!row.isSum() && row.check(e)) {
129  columns.forEach((column) -> {
130  if(column.check(e)) {
131  addValue(e, row, column);
132  }
133  });
134  }
135  });
136  }
137 
138  private String generateKey(ReportRow row, ReportColumn column) {
139  return row == null ? "" + column.hashCode() : row.hashCode() + "|" + column.hashCode();
140  }
141 
142  private void addValue(RegisterEntry e, ReportRow row, ReportColumn column) {
143  if(values == null) values = new HashMap<>();
144  double value = 0.0;
145  switch(row.getSumType()) {
146  case BALANCE:
147  value = e.getDebit() - e.getCredit();
148  break;
149  case DEBIT:
150  value = e.getDebit();
151  break;
152  case CREDIT:
153  value = e.getCredit();
154  break;
155  }
156  Double accumulate = values.get(generateKey(row, column));
157  if(accumulate == null) {
158  accumulate = value;
159  } else {
160  accumulate += value;
161  }
162  values.put(generateKey(row, column), accumulate);
163  }
164 
165  private Double formatAndAddSum(ReportRow row, ReportColumn column, Double value) {
166  value = row.isNegate() ? -value : value;
167  for(HashMap<String, Double> sm : sum.values()) {
168  Double total = sm.get(generateKey(null, column));
169  if(total == null) {
170  total = value;
171  } else {
172  total += value;
173  }
174  sm.put(generateKey(null, column), total);
175  }
176  return value;
177  }
178 
179  /* Report Elements */
180 
181  private static final String dveRoot = "/WEB-INF/elephant/reports/financials";
182 
183  public static List<ReportBody> reports() {
184  File root = new File(ElephantContext.getRealPath(dveRoot));
185  root.mkdirs();
186  List<ReportBody> reports = new ArrayList<>();
187  for(File file : root.listFiles()) {
188  if(file.isFile() && !file.isHidden()) {
189  reports.add(ReportBody.load(file));
190  }
191  }
192  return reports;
193  }
194 
195  public static ReportBody load(File file) {
196  ReportBody body = null;
197  if(file != null) {
198  try {
199  JSONSerializer ser = new JSONSerializer(true);
200  body = ser.fromJson(FileUtil.getContent(file), ReportBody.class);
201  body.setFile(file);
202  } catch (IOException ex) {
203  Logger.getLogger(ReportBody.class.getName()).log(Level.SEVERE, ElephantContext.logMsg(null), ex);
204  }
205  }
206  if(body == null) {
207  body = new ReportBody("Test report");
208  setTest(body);
209  ReportBody.save(body, "test");
210  }
211  return body;
212  }
213 
214  private static void save(ReportBody body, String name) {
215  try (Writer writer = FileUtil.getFileWriter(fileName(name))) {
216  JSONSerializer ser = new JSONSerializer(body, true);
217  writer.write(ser.toJson());
218  } catch (IOException ex) {
219  Logger.getLogger(ReportBody.class.getName()).log(Level.SEVERE, ElephantContext.logMsg(null), ex);
220  }
221  }
222 
223  private static String fileName(String name) {
224  return ElephantContext.getRealPath(dveRoot) + "/" + name + ".json";
225  }
226 
227  /* Defaults */
228 
229  private static void setTest(ReportBody body) {
230  ReportRow row = new ReportRow(0, "Test row", new String[] {"[67].*"}, ReportSumType.BALANCE, false);
231  body.getRows().add(row);
232  ReportColumn column = new ReportColumn(0, "Test column", new String[] {".*"});
233  body.getColumns().add(column);
234  }
235 
236 }
void addNamedValue(String name, Object value)
static OutputStreamWriter getFileWriter(String folder, String file)
Definition: FileUtil.java:158
static String getContent(File file)
Definition: FileUtil.java:245
Double getValue(ReportRow row, ReportColumn column)
Definition: ReportBody.java:70
void fill(Date start, Date end)
Definition: ReportBody.java:95
static ReportBody load(File file)
TreeSet< ReportColumn > getColumns()
Definition: ReportBody.java:65
Double getSum(ReportRow row, ReportColumn column, String group)
Definition: ReportBody.java:80
static List< ReportBody > reports()