1 | |
|
2 | |
|
3 | |
|
4 | |
package org.homeunix.thecave.buddi.plugin.builtin.report; |
5 | |
|
6 | |
import java.util.Collections; |
7 | |
import java.util.Comparator; |
8 | |
import java.util.Date; |
9 | |
import java.util.List; |
10 | |
|
11 | |
import org.homeunix.thecave.buddi.i18n.BuddiKeys; |
12 | |
import org.homeunix.thecave.buddi.i18n.keys.BudgetCategoryTypes; |
13 | |
import org.homeunix.thecave.buddi.i18n.keys.PluginReportDateRangeChoices; |
14 | |
import org.homeunix.thecave.buddi.plugin.api.BuddiReportPlugin; |
15 | |
import org.homeunix.thecave.buddi.plugin.api.model.ImmutableBudgetCategory; |
16 | |
import org.homeunix.thecave.buddi.plugin.api.model.ImmutableDocument; |
17 | |
import org.homeunix.thecave.buddi.plugin.api.model.ImmutableSplit; |
18 | |
import org.homeunix.thecave.buddi.plugin.api.model.ImmutableTransaction; |
19 | |
import org.homeunix.thecave.buddi.plugin.api.model.ImmutableTransactionSplit; |
20 | |
import org.homeunix.thecave.buddi.plugin.api.util.HtmlHelper; |
21 | |
import org.homeunix.thecave.buddi.plugin.api.util.HtmlPage; |
22 | |
import org.homeunix.thecave.buddi.plugin.api.util.TextFormatter; |
23 | |
|
24 | |
import ca.digitalcave.moss.common.DateUtil; |
25 | |
import ca.digitalcave.moss.common.Version; |
26 | |
import ca.digitalcave.moss.swing.MossDocumentFrame; |
27 | |
|
28 | |
|
29 | |
|
30 | |
|
31 | |
|
32 | |
|
33 | |
|
34 | |
|
35 | 2977 | public class AverageIncomeExpenseByCategory extends BuddiReportPlugin { |
36 | |
|
37 | |
public static final long serialVersionUID = 0; |
38 | |
|
39 | |
public Version getMaximumVersion() { |
40 | 0 | return null; |
41 | |
} |
42 | |
|
43 | |
public Version getMinimumVersion() { |
44 | 0 | return null; |
45 | |
} |
46 | |
|
47 | |
public boolean isPluginActive() { |
48 | 3025 | return true; |
49 | |
} |
50 | |
|
51 | |
@Override |
52 | |
public HtmlPage getReport(ImmutableDocument model, MossDocumentFrame callingFrame, Date startDate, Date endDate) { |
53 | 0 | StringBuilder sb = HtmlHelper.getHtmlHeader(getName(), null, startDate, endDate); |
54 | |
|
55 | 0 | List<ImmutableBudgetCategory> categories = model.getImmutableBudgetCategories(); |
56 | 0 | Collections.sort(categories, new Comparator<ImmutableBudgetCategory>(){ |
57 | |
public int compare(ImmutableBudgetCategory o1, ImmutableBudgetCategory o2) { |
58 | |
|
59 | 0 | if (o1.isIncome() != o2.isIncome()){ |
60 | 0 | if (o1.isIncome()){ |
61 | 0 | return -1; |
62 | |
} |
63 | |
else { |
64 | 0 | return 1; |
65 | |
} |
66 | |
} |
67 | |
|
68 | |
|
69 | 0 | return o1.toString().compareTo(o2.toString()); |
70 | |
} |
71 | |
}); |
72 | |
|
73 | 0 | sb.append("<h1>").append(TextFormatter.getTranslation(BuddiKeys.REPORT_SUMMARY)).append("</h1>\n"); |
74 | 0 | sb.append("<table class='main'>\n"); |
75 | |
|
76 | 0 | sb.append("<tr><th>"); |
77 | 0 | sb.append(TextFormatter.getTranslation(BuddiKeys.NAME)); |
78 | 0 | sb.append("</th><th>"); |
79 | 0 | sb.append(TextFormatter.getTranslation(BuddiKeys.ACTUAL)); |
80 | 0 | sb.append("</th><th>"); |
81 | 0 | sb.append(TextFormatter.getTranslation(BuddiKeys.AVERAGE)); |
82 | 0 | sb.append(" / "); |
83 | 0 | sb.append(TextFormatter.getTranslation(model.getBudgetCategoryType(BudgetCategoryTypes.BUDGET_CATEGORY_TYPE_MONTH).getName())); |
84 | 0 | sb.append("</th></tr>\n"); |
85 | |
|
86 | 0 | long totalActual = 0, totalAverage = 0; |
87 | |
|
88 | 0 | for (ImmutableBudgetCategory c : categories){ |
89 | |
|
90 | |
|
91 | 0 | List<ImmutableTransaction> transactions = model.getImmutableTransactions(c, startDate, endDate); |
92 | 0 | long actual = 0; |
93 | 0 | for (ImmutableTransaction transaction : transactions) { |
94 | 0 | if (!transaction.isDeleted()){ |
95 | |
|
96 | 0 | if (transaction.getFrom().equals(c) || transaction.getTo().equals(c)){ |
97 | 0 | actual += transaction.getAmount(); |
98 | |
} |
99 | |
|
100 | 0 | for (ImmutableTransactionSplit split : transaction.getImmutableToSplits()) { |
101 | 0 | if (split.getSource().equals(c)){ |
102 | 0 | actual += split.getAmount(); |
103 | |
} |
104 | |
} |
105 | 0 | for (ImmutableTransactionSplit split : transaction.getImmutableFromSplits()) { |
106 | 0 | if (split.getSource().equals(c)){ |
107 | 0 | actual -= split.getAmount(); |
108 | |
} |
109 | |
} |
110 | |
|
111 | |
|
112 | 0 | if (transaction.getTo() instanceof ImmutableBudgetCategory){ |
113 | 0 | totalActual -= transaction.getAmount(); |
114 | |
} |
115 | 0 | else if (transaction.getFrom() instanceof ImmutableBudgetCategory){ |
116 | 0 | totalActual += transaction.getAmount(); |
117 | |
} |
118 | |
|
119 | |
|
120 | 0 | if (transaction.getTo() instanceof ImmutableSplit){ |
121 | 0 | for (ImmutableTransactionSplit split : transaction.getImmutableToSplits()) { |
122 | 0 | if (split.getSource().equals(c)){ |
123 | 0 | totalActual -= split.getAmount(); |
124 | |
} |
125 | |
} |
126 | |
} |
127 | 0 | if (transaction.getFrom() instanceof ImmutableSplit){ |
128 | 0 | for (ImmutableTransactionSplit split : transaction.getImmutableFromSplits()) { |
129 | 0 | if (split.getSource().equals(c)){ |
130 | 0 | totalActual += split.getAmount(); |
131 | |
} |
132 | |
} |
133 | |
} |
134 | |
} |
135 | |
} |
136 | |
|
137 | |
long average; |
138 | |
|
139 | 0 | if(isQuarter(startDate, endDate,model.getBudgetCategoryType(BudgetCategoryTypes.BUDGET_CATEGORY_TYPE_MONTH).getDaysInPeriod(endDate))) |
140 | 0 | average = (long) ((double) actual / 3.0); |
141 | |
else |
142 | 0 | average = (long) ((double) actual / (double) DateUtil.getDaysBetween(startDate, endDate, true) * |
143 | |
model.getBudgetCategoryType(BudgetCategoryTypes.BUDGET_CATEGORY_TYPE_MONTH).getDaysInPeriod(endDate)); |
144 | |
|
145 | 0 | if (c.isIncome()){ |
146 | 0 | totalAverage += average; |
147 | |
} |
148 | |
else { |
149 | 0 | totalAverage -= average; |
150 | |
} |
151 | |
|
152 | |
|
153 | 0 | if (transactions.size() > 0){ |
154 | 0 | sb.append("<tr>"); |
155 | 0 | sb.append("<td>"); |
156 | 0 | sb.append(TextFormatter.getTranslation(c.toString())); |
157 | 0 | sb.append("</td><td class='right" + (TextFormatter.isRed(c, actual) ? " red'" : "'") + ">"); |
158 | 0 | sb.append(TextFormatter.getFormattedCurrency(actual)); |
159 | 0 | sb.append("</td><td class='right" + (TextFormatter.isRed(c, average) ? " red'" : "'") + "'>"); |
160 | 0 | sb.append(TextFormatter.getFormattedCurrency(average)); |
161 | 0 | sb.append("</td></tr>\n"); |
162 | |
} |
163 | 0 | } |
164 | |
|
165 | 0 | sb.append("<tr><th>"); |
166 | 0 | sb.append(TextFormatter.getTranslation(BuddiKeys.TOTAL)); |
167 | 0 | sb.append("</th><th class='right" + (TextFormatter.isRed(totalActual) ? " red'" : "'") + "'>"); |
168 | 0 | sb.append(TextFormatter.getFormattedCurrency(totalActual)); |
169 | 0 | sb.append("</th><th class='right" + (TextFormatter.isRed(totalAverage) ? " red'" : "'") + "'>"); |
170 | 0 | sb.append(TextFormatter.getFormattedCurrency(totalAverage)); |
171 | 0 | sb.append("</th></tr>\n"); |
172 | |
|
173 | 0 | sb.append("</table>\n\n"); |
174 | |
|
175 | 0 | sb.append("<hr>\n"); |
176 | |
|
177 | 0 | sb.append("<h1>").append(TextFormatter.getTranslation(BuddiKeys.REPORT_DETAILS)).append("</h1>\n"); |
178 | |
|
179 | 0 | for (ImmutableBudgetCategory bc : categories){ |
180 | 0 | List<ImmutableTransaction> transactions = model.getImmutableTransactions(bc, startDate, endDate); |
181 | |
|
182 | |
|
183 | 0 | if (transactions.size() > 0){ |
184 | 0 | sb.append(bc.isIncome() ? "<h2>" : "<h2 class='red'>"); |
185 | 0 | sb.append(TextFormatter.getTranslation(bc.toString())); |
186 | 0 | sb.append("</h2>\n"); |
187 | |
|
188 | 0 | sb.append(HtmlHelper.getHtmlTransactionHeader()); |
189 | |
|
190 | |
|
191 | 0 | for (ImmutableTransaction t : transactions) { |
192 | 0 | if (!t.isDeleted()) |
193 | 0 | sb.append(HtmlHelper.getHtmlTransactionRow(t, bc)); |
194 | |
} |
195 | |
|
196 | 0 | sb.append(HtmlHelper.getHtmlTransactionFooter()); |
197 | |
} |
198 | 0 | } |
199 | |
|
200 | 0 | sb.append(HtmlHelper.getHtmlFooter()); |
201 | |
|
202 | 0 | return new HtmlPage(sb.toString(), null); |
203 | |
} |
204 | |
|
205 | |
public String getName() { |
206 | 0 | return TextFormatter.getTranslation(BuddiKeys.REPORT_TITLE_AVERAGE_INCOME_AND_EXPENSES_BY_CATEGORY); |
207 | |
} |
208 | |
|
209 | |
public String getDescription() { |
210 | 3025 | return BuddiKeys.REPORT_DESCRIPTION_AVERAGE_INCOME_AND_EXPENSES_BY_CATEGORY.toString(); |
211 | |
} |
212 | |
|
213 | |
@Override |
214 | |
public PluginReportDateRangeChoices getDateRangeChoice() { |
215 | 3025 | return PluginReportDateRangeChoices.INTERVAL; |
216 | |
} |
217 | |
|
218 | |
|
219 | |
public boolean isQuarter(Date startDate, Date endDate , long days) |
220 | |
{ |
221 | 0 | if(!DateUtil.isSameYear(startDate, endDate)) |
222 | 0 | return false; |
223 | 0 | if(DateUtil.getDay(startDate) != 1) |
224 | 0 | return false; |
225 | 0 | if(DateUtil.getDay(endDate) != days) |
226 | 0 | return false; |
227 | 0 | if(DateUtil.getMonthsBetween(startDate, endDate, false) != 2) |
228 | 0 | return false; |
229 | 0 | return true; |
230 | |
} |
231 | |
|
232 | |
} |