1 /*******************************************************
2 Copyright (C) 2006 Madhan Kanagavel
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 ********************************************************/
18
19 #include "categexp.h"
20 #include "budget.h"
21 #include "htmlbuilder.h"
22
23 #include "htmlbuilder.h"
24 #include "mmOption.h"
25 #include <algorithm>
26 #include "model/Model_Category.h"
27
28 #define CATEGORY_SORT_BY_NAME 1
29 #define CATEGORY_SORT_BY_AMOUNT 2
30
mmReportCategoryExpenses(mmDateRange * date_range,const wxString & title,int type)31 mmReportCategoryExpenses::mmReportCategoryExpenses
32 (mmDateRange* date_range, const wxString& title, int type)
33 : mmPrintableBase("mmReportCategoryExpenses")
34 , date_range_(date_range)
35 , title_(title)
36 , type_(type)
37 , ignoreFutureDate_(mmIniOptions::instance().ignoreFutureTransactions_)
38 , with_date_(false)
39 {
40 with_date_ = date_range_->is_with_date();
41 }
42
~mmReportCategoryExpenses()43 mmReportCategoryExpenses::~mmReportCategoryExpenses()
44 {
45 if(date_range_)
46 delete date_range_;
47 }
48
RefreshData()49 void mmReportCategoryExpenses::RefreshData()
50 {
51 data_.clear();
52 wxString color;
53 std::map<int, std::map<int, std::map<int, double> > > categoryStats;
54 Model_Category::instance().getCategoryStats(categoryStats
55 , date_range_
56 , ignoreFutureDate_
57 , false
58 , with_date_);
59
60 data_holder line;
61 int i = 0;
62 mmHTMLBuilder hb;
63 int groupID = 1;
64 for (const auto& category : Model_Category::instance().all(Model_Category::COL_CATEGNAME))
65 {
66 const wxString& sCategName = category.CATEGNAME;
67 double amt = categoryStats[category.CATEGID][-1][0];
68 if (type_ == GOES && amt < 0.0) amt = 0;
69 if (type_ == COME && amt > 0.0) amt = 0;
70 if (amt != 0.0)
71 data_.push_back({ hb.getColor(i++), sCategName, amt, groupID });
72
73 auto subcategories = Model_Category::sub_category(category);
74 std::stable_sort(subcategories.begin(), subcategories.end(), SorterBySUBCATEGNAME());
75 for (const auto& sub_category : subcategories)
76 {
77 wxString sFullCategName = Model_Category::full_name(category.CATEGID, sub_category.SUBCATEGID);
78 amt = categoryStats[category.CATEGID][sub_category.SUBCATEGID][0];
79 if (type_ == GOES && amt < 0.0) amt = 0;
80 if (type_ == COME && amt > 0.0) amt = 0;
81 if (amt != 0.0)
82 data_.push_back({ hb.getColor(i++), sFullCategName, amt, groupID });
83 }
84 groupID++;
85 }
86 }
87
getHTMLText()88 wxString mmReportCategoryExpenses::getHTMLText()
89 {
90 RefreshData();
91 valueList_.clear();
92 // Data is presorted by name
93 std::vector<data_holder> sortedData(data_);
94
95 std::map <int, int> group_counter;
96 std::map <int, double> group_total;
97 for (const auto& entry : sortedData)
98 {
99 group_counter[entry.categs]++;
100 group_total[entry.categs] += entry.amount;
101 group_total[-1] += entry.amount < 0 ? entry.amount : 0;
102 group_total[-2] += entry.amount > 0 ? entry.amount : 0;
103 if (type_ != NONE) valueList_.push_back({ entry.color, entry.name, entry.amount });
104 }
105
106 std::stable_sort(valueList_.begin(), valueList_.end()
107 , [](const ValueTrio& x, const ValueTrio& y)
108 {
109 if (x.amount != y.amount)
110 return fabs(x.amount) > fabs(y.amount);
111 else
112 return x.label < y.label;
113 }
114 );
115
116 mmHTMLBuilder hb;
117 hb.init();
118 hb.addDivContainer();
119 hb.addHeader(2, title_);
120 hb.DisplayDateHeading(date_range_->start_date(), date_range_->end_date(), with_date_);
121
122 hb.addDivRow();
123 hb.addDivCol17_67();
124
125 // Add the graph
126 hb.addDivCol25_50();
127 if (type_ != NONE && !valueList_.empty())
128 hb.addPieChart(valueList_, "Categories");
129 hb.endDiv();
130
131 hb.startTable();
132 hb.startThead();
133 hb.startTableRow();
134 if (type_ != NONE) hb.addTableHeaderCell(" ");
135 hb.addTableHeaderCell(_("Category"));
136 hb.addTableHeaderCell(_("Amount"), true);
137 hb.addTableHeaderCell(_("Total"), true);
138 hb.endTableRow();
139 hb.endThead();
140
141 hb.startTbody();
142 int group = 0;
143 for (const auto& entry : sortedData)
144 {
145 group++;
146 hb.startTableRow();
147 if (type_ != NONE) hb.addColorMarker(entry.color);
148 hb.addTableCell(entry.name);
149 hb.addMoneyCell(entry.amount);
150 if (group_counter[entry.categs] > 1)
151 hb.addTableCell("");
152 else
153 hb.addMoneyCell(entry.amount);
154 hb.endTableRow();
155
156 if (group_counter[entry.categs] == group && group_counter[entry.categs] > 1)
157 {
158 group = 0;
159 hb.startTableRow();
160 if (type_ != NONE) hb.addTableCell("");
161 hb.addTableCell(_("Category Total: "));
162 hb.addTableCell("");
163 hb.addMoneyCell(group_total[entry.categs]);
164 hb.endTableRow();
165 }
166 if (group_counter[entry.categs] == 1 || group == 0) {
167 group = 0;
168 }
169 }
170 hb.endTbody();
171
172 int span = (type_ != NONE) ? 4 : 3;
173 hb.startTfoot();
174 if (type_ == NONE)
175 {
176 hb.addTotalRow(_("Total Expenses: "), span, group_total[-1]);
177 hb.addTotalRow(_("Total Income: "), span, group_total[-2]);
178 }
179 hb.addTotalRow(_("Grand Total: "), span, group_total[-1] + group_total[-2]);
180 hb.endTfoot();
181
182 hb.endTable();
183 hb.endDiv();
184 hb.endDiv();
185 hb.endDiv();
186 hb.end();
187
188 return hb.getHTMLText();
189 }
190
mmReportCategoryExpensesGoes(mmDateRange * date_range,const wxString & title)191 mmReportCategoryExpensesGoes::mmReportCategoryExpensesGoes
192 ( mmDateRange* date_range, const wxString& title)
193 : mmReportCategoryExpenses(date_range, title, 2)
194 {}
195
mmReportCategoryExpensesGoesCurrentMonth()196 mmReportCategoryExpensesGoesCurrentMonth::mmReportCategoryExpensesGoesCurrentMonth
197 ( )
198 : mmReportCategoryExpensesGoes(new mmCurrentMonth()
199 , wxString::Format(_("Where the Money Goes - %s"), _("Current Month")))
200 {}
201
mmReportCategoryExpensesGoesCurrentMonthToDate()202 mmReportCategoryExpensesGoesCurrentMonthToDate::mmReportCategoryExpensesGoesCurrentMonthToDate
203 ( )
204 : mmReportCategoryExpensesGoes(new mmCurrentMonthToDate()
205 , wxString::Format(_("Where the Money Goes - %s"), _("Current Month to Date")))
206 {}
207
mmReportCategoryExpensesGoesLastMonth()208 mmReportCategoryExpensesGoesLastMonth::mmReportCategoryExpensesGoesLastMonth
209 ( )
210 : mmReportCategoryExpensesGoes(new mmLastMonth()
211 , wxString::Format(_("Where the Money Goes - %s"), _("Last Month")))
212 {}
213
mmReportCategoryExpensesGoesLast30Days()214 mmReportCategoryExpensesGoesLast30Days::mmReportCategoryExpensesGoesLast30Days
215 ( )
216 : mmReportCategoryExpensesGoes(new mmLast30Days()
217 , wxString::Format(_("Where the Money Goes - %s"), _("Last 30 Days")))
218 {}
219
mmReportCategoryExpensesGoesLastYear()220 mmReportCategoryExpensesGoesLastYear::mmReportCategoryExpensesGoesLastYear
221 ( )
222 : mmReportCategoryExpensesGoes(new mmLastYear()
223 , wxString::Format(_("Where the Money Goes - %s"), _("Last Year")))
224 {}
225
mmReportCategoryExpensesGoesCurrentYear()226 mmReportCategoryExpensesGoesCurrentYear::mmReportCategoryExpensesGoesCurrentYear()
227 : mmReportCategoryExpensesGoes(new mmCurrentYear()
228 , wxString::Format(_("Where the Money Goes - %s"), _("Current Year")))
229 {}
230
mmReportCategoryExpensesGoesCurrentYearToDate()231 mmReportCategoryExpensesGoesCurrentYearToDate::mmReportCategoryExpensesGoesCurrentYearToDate
232 ( )
233 : mmReportCategoryExpensesGoes(new mmCurrentYearToDate()
234 , wxString::Format(_("Where the Money Goes - %s"), _("Current Year to Date")))
235 {}
236
mmReportCategoryExpensesGoesLastFinancialYear(const int day,const int month)237 mmReportCategoryExpensesGoesLastFinancialYear::mmReportCategoryExpensesGoesLastFinancialYear
238 ( const int day, const int month)
239 : mmReportCategoryExpensesGoes(new mmLastFinancialYear(day, month)
240 , wxString::Format(_("Where the Money Goes - %s"), _("Last Financial Year")))
241 {}
242
mmReportCategoryExpensesGoesCurrentFinancialYear(const int day,const int month)243 mmReportCategoryExpensesGoesCurrentFinancialYear::mmReportCategoryExpensesGoesCurrentFinancialYear
244 ( const int day, const int month)
245 : mmReportCategoryExpensesGoes(new mmCurrentFinancialYear(day, month)
246 , wxString::Format(_("Where the Money Goes - %s"), _("Current Financial Year")))
247 {}
248
mmReportCategoryExpensesGoesCurrentFinancialYearToDate(const int day,const int month)249 mmReportCategoryExpensesGoesCurrentFinancialYearToDate::mmReportCategoryExpensesGoesCurrentFinancialYearToDate
250 (const int day, const int month)
251 : mmReportCategoryExpensesGoes(new mmCurrentFinancialYearToDate(day, month)
252 , wxString::Format(_("Where the Money Goes - %s"), _("Current Financial Year to Date")))
253 {}
254
mmReportCategoryExpensesComes(mmDateRange * date_range,const wxString & title)255 mmReportCategoryExpensesComes::mmReportCategoryExpensesComes
256 (mmDateRange* date_range, const wxString& title)
257 : mmReportCategoryExpenses(date_range, title, 1)
258 {}
259
mmReportCategoryExpensesComesCurrentMonth()260 mmReportCategoryExpensesComesCurrentMonth::mmReportCategoryExpensesComesCurrentMonth
261 ( )
262 : mmReportCategoryExpensesComes(new mmCurrentMonth()
263 , wxString::Format(_("Where the Money Comes From - %s"), _("Current Month")))
264 {}
265
mmReportCategoryExpensesComesCurrentMonthToDate()266 mmReportCategoryExpensesComesCurrentMonthToDate::mmReportCategoryExpensesComesCurrentMonthToDate
267 ( )
268 : mmReportCategoryExpensesComes(new mmCurrentMonthToDate()
269 , wxString::Format(_("Where the Money Comes From - %s"), _("Current Month to Date")))
270 {}
271
mmReportCategoryExpensesComesLastMonth()272 mmReportCategoryExpensesComesLastMonth::mmReportCategoryExpensesComesLastMonth
273 ( )
274 : mmReportCategoryExpensesComes(new mmLastMonth()
275 , wxString::Format(_("Where the Money Comes From - %s"), _("Last Month")))
276 {}
277
mmReportCategoryExpensesComesLast30Days()278 mmReportCategoryExpensesComesLast30Days::mmReportCategoryExpensesComesLast30Days
279 ( )
280 : mmReportCategoryExpensesComes(new mmLast30Days()
281 , wxString::Format(_("Where the Money Comes From - %s"), _("Last 30 Days")))
282 {}
283
mmReportCategoryExpensesComesLastYear()284 mmReportCategoryExpensesComesLastYear::mmReportCategoryExpensesComesLastYear
285 ( )
286 : mmReportCategoryExpensesComes(new mmLastYear()
287 , wxString::Format(_("Where the Money Comes From - %s"), _("Last Year")))
288 {}
289
mmReportCategoryExpensesComesCurrentYear()290 mmReportCategoryExpensesComesCurrentYear::mmReportCategoryExpensesComesCurrentYear
291 ( )
292 : mmReportCategoryExpensesComes(new mmCurrentYear()
293 , wxString::Format(_("Where the Money Comes From - %s"), _("Current Year")))
294 {}
295
mmReportCategoryExpensesComesCurrentYearToDate()296 mmReportCategoryExpensesComesCurrentYearToDate::mmReportCategoryExpensesComesCurrentYearToDate
297 ( )
298 : mmReportCategoryExpensesComes(new mmCurrentYearToDate()
299 , wxString::Format(_("Where the Money Comes From - %s"), _("Current Year to Date")))
300 {}
301
mmReportCategoryExpensesComesLastFinancialYear(int day,int month)302 mmReportCategoryExpensesComesLastFinancialYear::mmReportCategoryExpensesComesLastFinancialYear
303 ( int day, int month)
304 : mmReportCategoryExpensesComes(new mmLastFinancialYear(day, month)
305 , wxString::Format(_("Where the Money Comes From - %s"), _("Last Financial Year")))
306 {}
307
mmReportCategoryExpensesComesCurrentFinancialYear(int day,int month)308 mmReportCategoryExpensesComesCurrentFinancialYear::mmReportCategoryExpensesComesCurrentFinancialYear
309 ( int day, int month)
310 : mmReportCategoryExpensesComes(new mmCurrentFinancialYear(day, month)
311 , wxString::Format(_("Where the Money Comes From - %s"), _("Current Financial Year")))
312 {}
313
mmReportCategoryExpensesComesCurrentFinancialYearToDate(int day,int month)314 mmReportCategoryExpensesComesCurrentFinancialYearToDate::mmReportCategoryExpensesComesCurrentFinancialYearToDate
315 (int day, int month)
316 : mmReportCategoryExpensesComes(new mmCurrentFinancialYearToDate(day, month)
317 , wxString::Format(_("Where the Money Comes From - %s"), _("Current Financial Year to Date")))
318 {}
319
mmReportCategoryExpensesCategories(mmDateRange * date_range,const wxString & title)320 mmReportCategoryExpensesCategories::mmReportCategoryExpensesCategories
321 ( mmDateRange* date_range, const wxString& title)
322 : mmReportCategoryExpenses(date_range, title, 0)
323 {}
324
mmReportCategoryExpensesCategoriesCurrentMonth()325 mmReportCategoryExpensesCategoriesCurrentMonth::mmReportCategoryExpensesCategoriesCurrentMonth
326 ( )
327 : mmReportCategoryExpensesCategories(new mmCurrentMonth()
328 , wxString::Format(_("Categories - %s"), _("Current Month")))
329 {}
330
mmReportCategoryExpensesCategoriesCurrentMonthToDate()331 mmReportCategoryExpensesCategoriesCurrentMonthToDate::mmReportCategoryExpensesCategoriesCurrentMonthToDate
332 ( )
333 : mmReportCategoryExpensesCategories(new mmCurrentMonthToDate()
334 , wxString::Format(_("Categories - %s"), _("Current Month to Date")))
335 {}
336
mmReportCategoryExpensesCategoriesLastMonth()337 mmReportCategoryExpensesCategoriesLastMonth::mmReportCategoryExpensesCategoriesLastMonth()
338 : mmReportCategoryExpensesCategories(new mmLastMonth()
339 , wxString::Format(_("Categories - %s"), _("Last Month")))
340 {}
341
mmReportCategoryExpensesCategoriesLast30Days()342 mmReportCategoryExpensesCategoriesLast30Days::mmReportCategoryExpensesCategoriesLast30Days
343 ( )
344 : mmReportCategoryExpensesCategories(new mmLast30Days()
345 , wxString::Format(_("Categories - %s"), _("Last 30 Days")))
346 {}
347
mmReportCategoryExpensesCategoriesLastYear()348 mmReportCategoryExpensesCategoriesLastYear::mmReportCategoryExpensesCategoriesLastYear()
349 : mmReportCategoryExpensesCategories(new mmLastYear()
350 , wxString::Format(_("Categories - %s"), _("Last Year")))
351 {}
352
mmReportCategoryExpensesCategoriesCurrentYear()353 mmReportCategoryExpensesCategoriesCurrentYear::mmReportCategoryExpensesCategoriesCurrentYear
354 ( )
355 : mmReportCategoryExpensesCategories(new mmCurrentYear()
356 , wxString::Format(_("Categories - %s"), _("Current Year")))
357 {}
358
mmReportCategoryExpensesCategoriesCurrentYearToDate()359 mmReportCategoryExpensesCategoriesCurrentYearToDate::mmReportCategoryExpensesCategoriesCurrentYearToDate
360 ( )
361 : mmReportCategoryExpensesCategories(new mmCurrentYearToDate()
362 , wxString::Format(_("Categories - %s"), _("Current Year to Date")))
363 {}
364
mmReportCategoryExpensesCategoriesLastFinancialYear(int day,int month)365 mmReportCategoryExpensesCategoriesLastFinancialYear::mmReportCategoryExpensesCategoriesLastFinancialYear
366 ( int day, int month)
367 : mmReportCategoryExpensesCategories(new mmLastFinancialYear(day, month)
368 , wxString::Format(_("Categories - %s"), _("Last Financial Year")))
369 {}
370
mmReportCategoryExpensesCategoriesCurrentFinancialYear(int day,int month)371 mmReportCategoryExpensesCategoriesCurrentFinancialYear::mmReportCategoryExpensesCategoriesCurrentFinancialYear
372 ( int day, int month)
373 : mmReportCategoryExpensesCategories(new mmCurrentFinancialYear(day, month)
374 , wxString::Format(_("Categories - %s"), _("Current Financial Year")))
375 {}
376
mmReportCategoryExpensesCategoriesCurrentFinancialYearToDate(int day,int month)377 mmReportCategoryExpensesCategoriesCurrentFinancialYearToDate::mmReportCategoryExpensesCategoriesCurrentFinancialYearToDate
378 (int day, int month)
379 : mmReportCategoryExpensesCategories(new mmCurrentFinancialYearToDate(day, month)
380 , wxString::Format(_("Categories - %s"), _("Current Financial Year to Date")))
381 {}
382