1 /*
2  * Copyright 2004-2006  Ace Jones <acejones@users.sourceforge.net>
3  * Copyright 2006       Darren Gould <darren_gould@gmx.de>
4  * Copyright 2007-2010  Alvaro Soliverez <asoliverez@gmail.com>
5  * Copyright 2017-2018  Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
6  * Copyright 2018       Michael Kiefer <Michael-Kiefer@web.de>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "mymoneyreport_p.h"
23 
24 // ----------------------------------------------------------------------------
25 // QT Includes
26 
27 // ----------------------------------------------------------------------------
28 // KDE Includes
29 
30 // ----------------------------------------------------------------------------
31 // Project Includes
32 
33 #include "mymoneymoney.h"
34 #include "mymoneyfile.h"
35 #include "mymoneyaccount.h"
36 #include "mymoneytransaction.h"
37 #include "mymoneytransactionfilter.h"
38 #include "mymoneyexception.h"
39 
MyMoneyReport()40 MyMoneyReport::MyMoneyReport() :
41   MyMoneyObject(*new MyMoneyReportPrivate)
42 {
43 }
44 
MyMoneyReport(const QString & id)45 MyMoneyReport::MyMoneyReport(const QString &id) :
46   MyMoneyObject(*new MyMoneyReportPrivate, id)
47 {
48 }
49 
MyMoneyReport(eMyMoney::Report::RowType rt,unsigned ct,eMyMoney::TransactionFilter::Date dl,eMyMoney::Report::DetailLevel ss,const QString & name,const QString & comment)50 MyMoneyReport::MyMoneyReport(eMyMoney::Report::RowType rt,
51                              unsigned ct,
52                              eMyMoney::TransactionFilter::Date dl,
53                              eMyMoney::Report::DetailLevel ss,
54                              const QString& name,
55                              const QString& comment) :
56   MyMoneyObject(*new MyMoneyReportPrivate)
57 {
58   Q_D(MyMoneyReport);
59   d->m_name = name;
60   d->m_comment = comment;
61   d->m_detailLevel = ss;
62   d->m_investmentSum = ct & eMyMoney::Report::QueryColumn::CapitalGain ? eMyMoney::Report::InvestmentSum::Sold : eMyMoney::Report::InvestmentSum::Period;
63   d->m_reportType = d->rowTypeToReportType(rt);
64   d->m_rowType = rt;
65   d->m_dateLock = dl;
66 
67   //set report type
68   if (d->m_reportType == eMyMoney::Report::ReportType::PivotTable)
69     d->m_columnType = static_cast<eMyMoney::Report::ColumnType>(ct);
70   if (d->m_reportType == eMyMoney::Report::ReportType::QueryTable)
71     d->m_queryColumns = static_cast<eMyMoney::Report::QueryColumn>(ct);
72   setDateFilter(dl);
73 
74   //throw exception if the type is inconsistent
75   if (d->rowTypeToReportType(rt) == eMyMoney::Report::ReportType::Invalid ||
76       d->m_reportType == eMyMoney::Report::ReportType::NoReport)
77     throw MYMONEYEXCEPTION_CSTRING("Invalid report type");
78 
79   //add the corresponding account groups
80   addAccountGroupsByRowType(rt);
81   switch(rt) {
82     case eMyMoney::Report::RowType::AssetLiability:
83     case eMyMoney::Report::RowType::Account:
84     case eMyMoney::Report::RowType::ExpenseIncome:
85       d->m_showRowTotals = true;
86       break;
87     default:
88       break;
89   }
90 
91 #ifdef DEBUG_REPORTS
92   QDebug out = qDebug();
93   out << _name << toString(_rt) << toString(m_reportType);
94   foreach(const eMyMoney::Account::Type accountType, m_accountGroups)
95     out << MyMoneyeMyMoney::Account::accountTypeToString(accountType);
96   if (m_accounts.size() > 0)
97     out << m_accounts;
98 #endif
99 }
100 
MyMoneyReport(const MyMoneyReport & other)101 MyMoneyReport::MyMoneyReport(const MyMoneyReport& other) :
102   MyMoneyObject(*new MyMoneyReportPrivate(*other.d_func()), other.id()),
103   MyMoneyTransactionFilter(other)
104 {
105 }
106 
MyMoneyReport(const QString & id,const MyMoneyReport & other)107 MyMoneyReport::MyMoneyReport(const QString& id, const MyMoneyReport& other) :
108   MyMoneyObject(*new MyMoneyReportPrivate(*other.d_func()), id),
109   MyMoneyTransactionFilter(other)
110 {
111   Q_D(MyMoneyReport);
112   d->m_movingAverageDays = 0;
113   d->m_currentDateColumn = 0;
114 }
115 
~MyMoneyReport()116 MyMoneyReport::~MyMoneyReport()
117 {
118 }
119 
addAccountGroupsByRowType(eMyMoney::Report::RowType rt)120 void MyMoneyReport::addAccountGroupsByRowType(eMyMoney::Report::RowType rt)
121 {
122   //add the corresponding account groups
123   switch(rt) {
124     case eMyMoney::Report::RowType::AccountInfo:
125     case eMyMoney::Report::RowType::AssetLiability:
126       addAccountGroup(eMyMoney::Account::Type::Asset);
127       addAccountGroup(eMyMoney::Account::Type::Liability);
128       break;
129 
130     case eMyMoney::Report::RowType::Account:
131       addAccountGroup(eMyMoney::Account::Type::Asset);
132       addAccountGroup(eMyMoney::Account::Type::AssetLoan);
133       addAccountGroup(eMyMoney::Account::Type::Cash);
134       addAccountGroup(eMyMoney::Account::Type::Checkings);
135       addAccountGroup(eMyMoney::Account::Type::CreditCard);
136       if (m_expertMode)
137         addAccountGroup(eMyMoney::Account::Type::Equity);
138       addAccountGroup(eMyMoney::Account::Type::Expense);
139       addAccountGroup(eMyMoney::Account::Type::Income);
140       addAccountGroup(eMyMoney::Account::Type::Liability);
141       addAccountGroup(eMyMoney::Account::Type::Loan);
142       addAccountGroup(eMyMoney::Account::Type::Savings);
143       addAccountGroup(eMyMoney::Account::Type::Stock);
144       break;
145 
146     case eMyMoney::Report::RowType::ExpenseIncome:
147       addAccountGroup(eMyMoney::Account::Type::Expense);
148       addAccountGroup(eMyMoney::Account::Type::Income);
149       break;
150 
151     //FIXME take this out once we have sorted out all issues regarding budget of assets and liabilities -- asoliverez@gmail.com
152     case eMyMoney::Report::RowType::Budget:
153     case eMyMoney::Report::RowType::BudgetActual:
154       addAccountGroup(eMyMoney::Account::Type::Expense);
155       addAccountGroup(eMyMoney::Account::Type::Income);
156       break;
157 
158     //cash flow reports show splits for all account groups
159     case eMyMoney::Report::RowType::CashFlow:
160       addAccountGroup(eMyMoney::Account::Type::Expense);
161       addAccountGroup(eMyMoney::Account::Type::Income);
162       addAccountGroup(eMyMoney::Account::Type::Asset);
163       addAccountGroup(eMyMoney::Account::Type::Liability);
164       break;
165     default:
166       break;
167   }
168 }
169 
reportType() const170 eMyMoney::Report::ReportType MyMoneyReport::reportType() const
171 {
172   Q_D(const MyMoneyReport);
173   return d->m_reportType;
174 }
175 
setReportType(eMyMoney::Report::ReportType rt)176 void MyMoneyReport::setReportType(eMyMoney::Report::ReportType rt)
177 {
178   Q_D(MyMoneyReport);
179   d->m_reportType = rt;
180 }
181 
name() const182 QString MyMoneyReport::name() const
183 {
184   Q_D(const MyMoneyReport);
185   return d->m_name;
186 }
187 
setName(const QString & s)188 void MyMoneyReport::setName(const QString& s)
189 {
190   Q_D(MyMoneyReport);
191   d->m_name = s;
192 }
193 
isShowingRowTotals() const194 bool MyMoneyReport::isShowingRowTotals() const
195 {
196   Q_D(const MyMoneyReport);
197   return (d->m_showRowTotals);
198 }
199 
setShowingRowTotals(bool f)200 void MyMoneyReport::setShowingRowTotals(bool f)
201 {
202   Q_D(MyMoneyReport);
203   d->m_showRowTotals = f;
204 }
205 
isShowingColumnTotals() const206 bool MyMoneyReport::isShowingColumnTotals() const
207 {
208   Q_D(const MyMoneyReport);
209   return d->m_showColumnTotals;
210 }
211 
setShowingColumnTotals(bool f)212 void MyMoneyReport::setShowingColumnTotals(bool f)
213 {
214   Q_D(MyMoneyReport);
215   d->m_showColumnTotals = f;
216 }
217 
rowType() const218 eMyMoney::Report::RowType MyMoneyReport::rowType() const
219 {
220   Q_D(const MyMoneyReport);
221   return d->m_rowType;
222 }
223 
setRowType(eMyMoney::Report::RowType rt)224 void MyMoneyReport::setRowType(eMyMoney::Report::RowType rt)
225 {
226   Q_D(MyMoneyReport);
227   d->m_rowType = rt;
228   d->m_reportType = d->rowTypeToReportType(rt);
229 
230   d->m_accountGroupFilter = false;
231   d->m_accountGroups.clear();
232 
233   addAccountGroupsByRowType(rt);
234 }
235 
isRunningSum() const236 bool MyMoneyReport::isRunningSum() const
237 {
238   Q_D(const MyMoneyReport);
239   return (d->m_rowType == eMyMoney::Report::RowType::AssetLiability);
240 }
241 
columnType() const242 eMyMoney::Report::ColumnType MyMoneyReport::columnType() const
243 {
244   Q_D(const MyMoneyReport);
245   return d->m_columnType;
246 }
247 
setColumnType(eMyMoney::Report::ColumnType ct)248 void MyMoneyReport::setColumnType(eMyMoney::Report::ColumnType ct)
249 {
250   Q_D(MyMoneyReport);
251   d->m_columnType = ct;
252 }
253 
isConvertCurrency() const254 bool MyMoneyReport::isConvertCurrency() const
255 {
256   Q_D(const MyMoneyReport);
257   return d->m_convertCurrency;
258 }
259 
setConvertCurrency(bool f)260 void MyMoneyReport::setConvertCurrency(bool f)
261 {
262   Q_D(MyMoneyReport);
263   d->m_convertCurrency = f;
264 }
265 
columnPitch() const266 uint MyMoneyReport::columnPitch() const
267 {
268   Q_D(const MyMoneyReport);
269   return static_cast<uint>(d->m_columnType);
270 }
271 
comment() const272 QString MyMoneyReport::comment() const
273 {
274   Q_D(const MyMoneyReport);
275   return d->m_comment;
276 }
277 
setComment(const QString & comment)278 void MyMoneyReport::setComment(const QString& comment)
279 {
280   Q_D(MyMoneyReport);
281   d->m_comment = comment;
282 }
283 
queryColumns() const284 eMyMoney::Report::QueryColumn MyMoneyReport::queryColumns() const
285 {
286   Q_D(const MyMoneyReport);
287   return d->m_queryColumns;
288 }
289 
setQueryColumns(eMyMoney::Report::QueryColumn qc)290 void MyMoneyReport::setQueryColumns(eMyMoney::Report::QueryColumn qc)
291 {
292   Q_D(MyMoneyReport);
293   d->m_queryColumns = qc;
294 }
295 
group() const296 QString MyMoneyReport::group() const
297 {
298   Q_D(const MyMoneyReport);
299   return d->m_group;
300 }
301 
setGroup(const QString & group)302 void MyMoneyReport::setGroup(const QString& group)
303 {
304   Q_D(MyMoneyReport);
305   d->m_group = group;
306 }
307 
isFavorite() const308 bool MyMoneyReport::isFavorite() const
309 {
310   Q_D(const MyMoneyReport);
311   return d->m_favorite;
312 }
313 
setFavorite(bool f)314 void MyMoneyReport::setFavorite(bool f)
315 {
316   Q_D(MyMoneyReport);
317   d->m_favorite = f;
318 }
319 
isTax() const320 bool MyMoneyReport::isTax() const
321 {
322   Q_D(const MyMoneyReport);
323   return d->m_tax;
324 }
325 
setTax(bool f)326 void MyMoneyReport::setTax(bool f)
327 {
328   Q_D(MyMoneyReport);
329   d->m_tax = f;
330 }
331 
isInvestmentsOnly() const332 bool MyMoneyReport::isInvestmentsOnly() const
333 {
334   Q_D(const MyMoneyReport);
335   return d->m_investments;
336 }
337 
setInvestmentsOnly(bool f)338 void MyMoneyReport::setInvestmentsOnly(bool f)
339 {
340   Q_D(MyMoneyReport);
341   d->m_investments = f; if (f) d->m_loans = false;
342 }
343 
isLoansOnly() const344 bool MyMoneyReport::isLoansOnly() const
345 {
346   Q_D(const MyMoneyReport);
347   return d->m_loans;
348 }
349 
setLoansOnly(bool f)350 void MyMoneyReport::setLoansOnly(bool f)
351 {
352   Q_D(MyMoneyReport);
353   d->m_loans = f; if (f) d->m_investments = false;
354 }
355 
detailLevel() const356 eMyMoney::Report::DetailLevel MyMoneyReport::detailLevel() const
357 {
358   Q_D(const MyMoneyReport);
359   return d->m_detailLevel;
360 }
361 
setDetailLevel(eMyMoney::Report::DetailLevel detail)362 void MyMoneyReport::setDetailLevel(eMyMoney::Report::DetailLevel detail)
363 {
364   Q_D(MyMoneyReport);
365   d->m_detailLevel = detail;
366 }
367 
investmentSum() const368 eMyMoney::Report::InvestmentSum MyMoneyReport::investmentSum() const
369 {
370   Q_D(const MyMoneyReport);
371   return d->m_investmentSum;
372 }
373 
setInvestmentSum(eMyMoney::Report::InvestmentSum sum)374 void MyMoneyReport::setInvestmentSum(eMyMoney::Report::InvestmentSum sum)
375 {
376   Q_D(MyMoneyReport);
377   d->m_investmentSum = sum;
378 }
379 
isHideTransactions() const380 bool MyMoneyReport::isHideTransactions() const
381 {
382   Q_D(const MyMoneyReport);
383   return d->m_hideTransactions;
384 }
385 
setHideTransactions(bool f)386 void MyMoneyReport::setHideTransactions(bool f)
387 {
388   Q_D(MyMoneyReport);
389   d->m_hideTransactions = f;
390 }
391 
chartType() const392 eMyMoney::Report::ChartType MyMoneyReport::chartType() const
393 {
394   Q_D(const MyMoneyReport);
395   return d->m_chartType;
396 }
397 
setChartType(eMyMoney::Report::ChartType type)398 void MyMoneyReport::setChartType(eMyMoney::Report::ChartType type)
399 {
400   Q_D(MyMoneyReport);
401   d->m_chartType = type;
402 }
403 
chartPalette() const404 eMyMoney::Report::ChartPalette MyMoneyReport::chartPalette() const
405 {
406   Q_D(const MyMoneyReport);
407   return d->m_chartPalette;
408 }
409 
setChartPalette(eMyMoney::Report::ChartPalette type)410 void MyMoneyReport::setChartPalette(eMyMoney::Report::ChartPalette type)
411 {
412   Q_D(MyMoneyReport);
413   d->m_chartPalette = type;
414 }
415 
isChartDataLabels() const416 bool MyMoneyReport::isChartDataLabels() const
417 {
418   Q_D(const MyMoneyReport);
419   return d->m_chartDataLabels;
420 }
421 
setChartDataLabels(bool f)422 void MyMoneyReport::setChartDataLabels(bool f)
423 {
424   Q_D(MyMoneyReport);
425   d->m_chartDataLabels = f;
426 }
427 
isChartCHGridLines() const428 bool MyMoneyReport::isChartCHGridLines() const
429 {
430   Q_D(const MyMoneyReport);
431   return d->m_chartCHGridLines;
432 }
433 
setChartCHGridLines(bool f)434 void MyMoneyReport::setChartCHGridLines(bool f)
435 {
436   Q_D(MyMoneyReport);
437   d->m_chartCHGridLines = f;
438 }
439 
isChartSVGridLines() const440 bool MyMoneyReport::isChartSVGridLines() const
441 {
442   Q_D(const MyMoneyReport);
443   return d->m_chartSVGridLines;
444 }
445 
setChartSVGridLines(bool f)446 void MyMoneyReport::setChartSVGridLines(bool f)
447 {
448   Q_D(MyMoneyReport);
449   d->m_chartSVGridLines = f;
450 }
451 
isChartByDefault() const452 bool MyMoneyReport::isChartByDefault() const
453 {
454   Q_D(const MyMoneyReport);
455   return d->m_chartByDefault;
456 }
457 
setChartByDefault(bool f)458 void MyMoneyReport::setChartByDefault(bool f)
459 {
460   Q_D(MyMoneyReport);
461   d->m_chartByDefault = f;
462 }
463 
chartLineWidth() const464 uint MyMoneyReport::chartLineWidth() const
465 {
466   Q_D(const MyMoneyReport);
467   return d->m_chartLineWidth;
468 }
469 
setChartLineWidth(uint f)470 void MyMoneyReport::setChartLineWidth(uint f)
471 {
472   Q_D(MyMoneyReport);
473   d->m_chartLineWidth = f;
474 }
475 
isLogYAxis() const476 bool MyMoneyReport::isLogYAxis() const
477 {
478   Q_D(const MyMoneyReport);
479   return d->m_logYaxis;
480 }
481 
setLogYAxis(bool f)482 void MyMoneyReport::setLogYAxis(bool f)
483 {
484   Q_D(MyMoneyReport);
485   d->m_logYaxis = f;
486 }
487 
isNegExpenses() const488 bool MyMoneyReport::isNegExpenses() const
489 {
490   Q_D(const MyMoneyReport);
491   return d->m_negExpenses;
492 }
493 
setNegExpenses(bool f)494 void MyMoneyReport::setNegExpenses(bool f)
495 {
496   Q_D(MyMoneyReport);
497   d->m_negExpenses = f;
498 }
499 
dataRangeStart() const500 QString MyMoneyReport::dataRangeStart() const
501 {
502   Q_D(const MyMoneyReport);
503   return d->m_dataRangeStart;
504 }
505 
setDataRangeStart(const QString & f)506 void MyMoneyReport::setDataRangeStart(const QString& f)
507 {
508   Q_D(MyMoneyReport);
509   d->m_dataRangeStart = f;
510 }
511 
dataRangeEnd() const512 QString MyMoneyReport::dataRangeEnd() const
513 {
514   Q_D(const MyMoneyReport);
515   return d->m_dataRangeEnd;
516 }
517 
setDataRangeEnd(const QString & f)518 void MyMoneyReport::setDataRangeEnd(const QString& f)
519 {
520   Q_D(MyMoneyReport);
521   d->m_dataRangeEnd = f;
522 }
523 
dataMajorTick() const524 QString MyMoneyReport::dataMajorTick() const
525 {
526   Q_D(const MyMoneyReport);
527   return d->m_dataMajorTick;
528 }
529 
setDataMajorTick(const QString & f)530 void MyMoneyReport::setDataMajorTick(const QString& f)
531 {
532   Q_D(MyMoneyReport);
533   d->m_dataMajorTick = f;
534 }
535 
dataMinorTick() const536 QString MyMoneyReport::dataMinorTick() const
537 {
538   Q_D(const MyMoneyReport);
539   return d->m_dataMinorTick;
540 }
541 
setDataMinorTick(const QString & f)542 void MyMoneyReport::setDataMinorTick(const QString& f)
543 {
544   Q_D(MyMoneyReport);
545   d->m_dataMinorTick = f;
546 }
547 
yLabelsPrecision() const548 uint MyMoneyReport::yLabelsPrecision() const
549 {
550   Q_D(const MyMoneyReport);
551   return d->m_yLabelsPrecision;
552 }
553 
setYLabelsPrecision(int f)554 void MyMoneyReport::setYLabelsPrecision(int f)
555 {
556   Q_D(MyMoneyReport);
557   d->m_yLabelsPrecision = f;
558 }
559 
isIncludingSchedules() const560 bool MyMoneyReport::isIncludingSchedules() const
561 {
562   Q_D(const MyMoneyReport);
563   return d->m_includeSchedules;
564 }
565 
setIncludingSchedules(bool f)566 void MyMoneyReport::setIncludingSchedules(bool f)
567 {
568   Q_D(MyMoneyReport);
569   d->m_includeSchedules = f;
570 }
571 
isColumnsAreDays() const572 bool MyMoneyReport::isColumnsAreDays() const
573 {
574   Q_D(const MyMoneyReport);
575   return d->m_columnsAreDays;
576 }
577 
setColumnsAreDays(bool f)578 void MyMoneyReport::setColumnsAreDays(bool f)
579 {
580   Q_D(MyMoneyReport);
581   d->m_columnsAreDays = f;
582 }
583 
isIncludingTransfers() const584 bool MyMoneyReport::isIncludingTransfers() const
585 {
586   Q_D(const MyMoneyReport);
587   return d->m_includeTransfers;
588 }
589 
setIncludingTransfers(bool f)590 void MyMoneyReport::setIncludingTransfers(bool f)
591 {
592   Q_D(MyMoneyReport);
593   d->m_includeTransfers = f;
594 }
595 
isIncludingUnusedAccounts() const596 bool MyMoneyReport::isIncludingUnusedAccounts() const
597 {
598   Q_D(const MyMoneyReport);
599   return d->m_includeUnusedAccounts;
600 }
601 
setIncludingUnusedAccounts(bool f)602 void MyMoneyReport::setIncludingUnusedAccounts(bool f)
603 {
604   Q_D(MyMoneyReport);
605   d->m_includeUnusedAccounts = f;
606 }
607 
hasBudget() const608 bool MyMoneyReport::hasBudget() const
609 {
610   Q_D(const MyMoneyReport);
611   return !d->m_budgetId.isEmpty();
612 }
613 
budget() const614 QString MyMoneyReport::budget() const
615 {
616   Q_D(const MyMoneyReport);
617   return d->m_budgetId;
618 }
619 
620 /**
621   * Sets the budget used for this report
622   *
623   * @param budget The ID of the budget to use, or an empty string
624   * to indicate a budget is NOT included
625   * @param fa Whether to display actual data alongside the budget.
626   * Setting to false means the report displays ONLY the budget itself.
627   * @warning For now, the budget ID is ignored.  The budget id is
628   * simply checked for any non-empty string, and if so, hasBudget()
629   * will return true.
630   */
setBudget(const QString & budget,bool fa)631 void MyMoneyReport::setBudget(const QString& budget, bool fa)
632 {
633   Q_D(MyMoneyReport);
634   d->m_budgetId = budget; d->m_includeBudgetActuals = fa;
635 }
636 
isIncludingBudgetActuals() const637 bool MyMoneyReport::isIncludingBudgetActuals() const
638 {
639   Q_D(const MyMoneyReport);
640   return d->m_includeBudgetActuals;
641 }
642 
setIncludingBudgetActuals(bool f)643 void MyMoneyReport::setIncludingBudgetActuals(bool f)
644 {
645   Q_D(MyMoneyReport);
646   d->m_includeBudgetActuals = f;
647 }
648 
isIncludingForecast() const649 bool MyMoneyReport::isIncludingForecast() const
650 {
651   Q_D(const MyMoneyReport);
652   return d->m_includeForecast;
653 }
654 
setIncludingForecast(bool f)655 void MyMoneyReport::setIncludingForecast(bool f)
656 {
657   Q_D(MyMoneyReport);
658   d->m_includeForecast = f;
659 }
660 
isIncludingMovingAverage() const661 bool MyMoneyReport::isIncludingMovingAverage() const
662 {
663   Q_D(const MyMoneyReport);
664   return d->m_includeMovingAverage;
665 }
666 
setIncludingMovingAverage(bool f)667 void MyMoneyReport::setIncludingMovingAverage(bool f)
668 {
669   Q_D(MyMoneyReport);
670   d->m_includeMovingAverage = f;
671 }
672 
movingAverageDays() const673 int MyMoneyReport::movingAverageDays() const
674 {
675   Q_D(const MyMoneyReport);
676   return d->m_movingAverageDays;
677 }
678 
setMovingAverageDays(int days)679 void MyMoneyReport::setMovingAverageDays(int days)
680 {
681   Q_D(MyMoneyReport);
682   d->m_movingAverageDays = days;
683 }
684 
isIncludingPrice() const685 bool MyMoneyReport::isIncludingPrice() const
686 {
687   Q_D(const MyMoneyReport);
688   return d->m_includePrice;
689 }
690 
setIncludingPrice(bool f)691 void MyMoneyReport::setIncludingPrice(bool f)
692 {
693   Q_D(MyMoneyReport);
694   d->m_includePrice = f;
695 }
696 
isIncludingAveragePrice() const697 bool MyMoneyReport::isIncludingAveragePrice() const
698 {
699   Q_D(const MyMoneyReport);
700   return d->m_includeAveragePrice;
701 }
702 
setIncludingAveragePrice(bool f)703 void MyMoneyReport::setIncludingAveragePrice(bool f)
704 {
705   Q_D(MyMoneyReport);
706   d->m_includeAveragePrice = f;
707 }
708 
dataFilter() const709 eMyMoney::Report::DataLock MyMoneyReport::dataFilter() const
710 {
711   Q_D(const MyMoneyReport);
712   return d->m_dataLock;
713 }
714 
isDataUserDefined() const715 bool MyMoneyReport::isDataUserDefined() const
716 {
717   Q_D(const MyMoneyReport);
718   return d->m_dataLock == eMyMoney::Report::DataLock::UserDefined;
719 }
720 
setDataFilter(eMyMoney::Report::DataLock u)721 void MyMoneyReport::setDataFilter(eMyMoney::Report::DataLock u)
722 {
723   Q_D(MyMoneyReport);
724   d->m_dataLock = u;
725 }
726 
dateRange() const727 eMyMoney::TransactionFilter::Date MyMoneyReport::dateRange() const
728 {
729   Q_D(const MyMoneyReport);
730   return d->m_dateLock;
731 }
732 
isDateUserDefined() const733 bool MyMoneyReport::isDateUserDefined() const
734 {
735   Q_D(const MyMoneyReport);
736   return d->m_dateLock == eMyMoney::TransactionFilter::Date::UserDefined;
737 }
738 
739 /**
740   * Set the underlying date filter and LOCK that filter to the specified
741   * range.  For example, if @p _u is "CurrentMonth", this report should always
742   * be updated to the current month no matter when the report is run.
743   *
744   * This updating is not entirely automatic, you should update it yourself by
745   * calling updateDateFilter.
746   *
747   * @param _u The date range constant (MyMoneyTransactionFilter::dateRangeE)
748   *          which this report should be locked to.
749   */
750 
setDateFilter(eMyMoney::TransactionFilter::Date u)751 void MyMoneyReport::setDateFilter(eMyMoney::TransactionFilter::Date u)
752 {
753   Q_D(MyMoneyReport);
754   d->m_dateLock = u;
755   if (u != eMyMoney::TransactionFilter::Date::UserDefined)
756     MyMoneyTransactionFilter::setDateFilter(u);
757 }
758 
setDateFilter(const QDate & db,const QDate & de)759 void MyMoneyReport::setDateFilter(const QDate& db, const QDate& de)
760 {
761   MyMoneyTransactionFilter::setDateFilter(db, de);
762 }
763 
updateDateFilter()764 void MyMoneyReport::updateDateFilter()
765 {
766   Q_D(MyMoneyReport);
767   if (d->m_dateLock != eMyMoney::TransactionFilter::Date::UserDefined) MyMoneyTransactionFilter::setDateFilter(d->m_dateLock);
768 }
769 
770 
isMixedTime() const771 bool MyMoneyReport::isMixedTime() const
772 {
773   Q_D(const MyMoneyReport);
774   return d->m_mixedTime;
775 }
776 
setMixedTime(bool f)777 void MyMoneyReport::setMixedTime(bool f)
778 {
779   Q_D(MyMoneyReport);
780   d->m_mixedTime = f;
781 }
782 
currentDateColumn() const783 int MyMoneyReport::currentDateColumn() const
784 {
785   Q_D(const MyMoneyReport);
786   return d->m_currentDateColumn;
787 }
788 
setCurrentDateColumn(int f)789 void MyMoneyReport::setCurrentDateColumn(int f)
790 {
791   Q_D(MyMoneyReport);
792   d->m_currentDateColumn = f;
793 }
794 
settlementPeriod() const795 uint MyMoneyReport::settlementPeriod() const
796 {
797   Q_D(const MyMoneyReport);
798   return d->m_settlementPeriod;
799 }
800 
setSettlementPeriod(uint days)801 void MyMoneyReport::setSettlementPeriod(uint days)
802 {
803   Q_D(MyMoneyReport);
804   d->m_settlementPeriod = days;
805 }
806 
isShowingSTLTCapitalGains() const807 bool MyMoneyReport::isShowingSTLTCapitalGains() const
808 {
809   Q_D(const MyMoneyReport);
810   return d->m_showSTLTCapitalGains;
811 }
812 
setShowSTLTCapitalGains(bool f)813 void MyMoneyReport::setShowSTLTCapitalGains(bool f)
814 {
815   Q_D(MyMoneyReport);
816   d->m_showSTLTCapitalGains = f;
817 }
818 
termSeparator() const819 QDate MyMoneyReport::termSeparator() const
820 {
821   Q_D(const MyMoneyReport);
822   return d->m_tseparator;
823 }
824 
setTermSeparator(const QDate & date)825 void MyMoneyReport::setTermSeparator(const QDate& date)
826 {
827   Q_D(MyMoneyReport);
828   d->m_tseparator = date;
829 }
830 
isSkippingZero() const831 bool MyMoneyReport::isSkippingZero() const
832 {
833   Q_D(const MyMoneyReport);
834   return d->m_skipZero;
835 }
836 
setSkipZero(int f)837 void MyMoneyReport::setSkipZero(int f)
838 {
839   Q_D(MyMoneyReport);
840   d->m_skipZero = f;
841 }
842 
clearTransactionFilter()843 void MyMoneyReport::clearTransactionFilter()
844 {
845   Q_D(MyMoneyReport);
846   d->m_accountGroupFilter = false;
847   d->m_accountGroups.clear();
848 
849   MyMoneyTransactionFilter::clear();
850 }
851 
assignFilter(const MyMoneyTransactionFilter & filter)852 void MyMoneyReport::assignFilter(const MyMoneyTransactionFilter& filter)
853 {
854   MyMoneyTransactionFilter::operator=(filter);
855 }
856 
validDateRange(QDate & db,QDate & de)857 void MyMoneyReport::validDateRange(QDate& db, QDate& de)
858 {
859   db = fromDate();
860   de = toDate();
861 
862   // if either begin or end date are invalid we have one of the following
863   // possible date filters:
864   //
865   // a) begin date not set - first transaction until given end date
866   // b) end date not set   - from given date until last transaction
867   // c) both not set       - first transaction until last transaction
868   //
869   // If there is no transaction in the engine at all, we use the current
870   // year as the filter criteria.
871 
872   if (!db.isValid() || !de.isValid()) {
873     QList<MyMoneyTransaction> list = MyMoneyFile::instance()->transactionList(*this);
874     QDate tmpBegin, tmpEnd;
875 
876     if (!list.isEmpty()) {
877       qSort(list);
878       // try to use the post dates
879       tmpBegin = list.front().postDate();
880       tmpEnd = list.back().postDate();
881       // if the post dates are not valid try the entry dates
882       if (!tmpBegin.isValid())
883         tmpBegin = list.front().entryDate();
884       if (!tmpEnd.isValid())
885         tmpEnd = list.back().entryDate();
886     }
887     // make sure that we leave this function with valid dates no mather what
888     if (!tmpBegin.isValid() || !tmpEnd.isValid() || tmpBegin > tmpEnd) {
889       tmpBegin = QDate(QDate::currentDate().year(), 1, 1);   // the first date in the file
890       tmpEnd = QDate(QDate::currentDate().year(), 12, 31);   // the last date in the file
891     }
892     if (!db.isValid())
893       db = tmpBegin;
894     if (!de.isValid())
895       de = tmpEnd;
896   }
897   if (db > de)
898     db = de;
899 }
900 
accountGroups(QList<eMyMoney::Account::Type> & list) const901 bool MyMoneyReport::accountGroups(QList<eMyMoney::Account::Type>& list) const
902 {
903   Q_D(const MyMoneyReport);
904   bool result = d->m_accountGroupFilter;
905 
906   if (result) {
907     QList<eMyMoney::Account::Type>::const_iterator it_group = d->m_accountGroups.begin();
908     while (it_group != d->m_accountGroups.end()) {
909       list += (*it_group);
910       ++it_group;
911     }
912   }
913   return result;
914 }
915 
addAccountGroup(eMyMoney::Account::Type type)916 void MyMoneyReport::addAccountGroup(eMyMoney::Account::Type type)
917 {
918   Q_D(MyMoneyReport);
919   if (!d->m_accountGroups.isEmpty() && type != eMyMoney::Account::Type::Unknown) {
920     if (d->m_accountGroups.contains(type))
921       return;
922   }
923   d->m_accountGroupFilter = true;
924   if (type != eMyMoney::Account::Type::Unknown)
925     d->m_accountGroups.push_back(type);
926 }
927 
includesAccountGroup(eMyMoney::Account::Type type) const928 bool MyMoneyReport::includesAccountGroup(eMyMoney::Account::Type type) const
929 {
930   Q_D(const MyMoneyReport);
931   bool result = (! d->m_accountGroupFilter)
932                 || (isIncludingTransfers() && d->m_rowType == eMyMoney::Report::RowType::ExpenseIncome)
933                 || d->m_accountGroups.contains(type);
934 
935   return result;
936 }
937 
includes(const MyMoneyAccount & acc) const938 bool MyMoneyReport::includes(const MyMoneyAccount& acc) const
939 {
940   Q_D(const MyMoneyReport);
941   auto result = false;
942 
943   if (includesAccountGroup(acc.accountGroup())) {
944     switch (acc.accountGroup()) {
945       case eMyMoney::Account::Type::Income:
946       case eMyMoney::Account::Type::Expense:
947         if (isTax())
948           result = (acc.value("Tax") == "Yes") && includesCategory(acc.id());
949         else
950           result = includesCategory(acc.id());
951         break;
952       case eMyMoney::Account::Type::Asset:
953       case eMyMoney::Account::Type::Liability:
954         if (isLoansOnly())
955           result = acc.isLoan() && includesAccount(acc.id());
956         else if (isInvestmentsOnly())
957           result = acc.isInvest() && includesAccount(acc.id());
958         else if (isIncludingTransfers() && d->m_rowType == eMyMoney::Report::RowType::ExpenseIncome)
959           // If transfers are included, ONLY include this account if it is NOT
960           // included in the report itself!!
961           result = ! includesAccount(acc.id());
962         else
963           result = includesAccount(acc.id());
964         break;
965       case eMyMoney::Account::Type::Equity:
966         if (isInvestmentsOnly())
967           result = (isIncludingPrice() || isIncludingAveragePrice()) && acc.isInvest() && includesAccount(acc.id());
968         break;
969       default:
970         result = includesAccount(acc.id());
971     }
972   }
973   return result;
974 }
975 
hasReferenceTo(const QString & id) const976 bool MyMoneyReport::hasReferenceTo(const QString& id) const
977 {
978   QStringList list;
979 
980   // collect all ids
981   accounts(list);
982   categories(list);
983   payees(list);
984   tags(list);
985 
986   return list.contains(id);
987 }
988 
989 int MyMoneyReport::m_lineWidth = 2;
990 bool MyMoneyReport::m_expertMode = false;
991 
setLineWidth(int width)992 void MyMoneyReport::setLineWidth(int width)
993 {
994   m_lineWidth = width;
995 }
996 
lineWidth()997 int MyMoneyReport::lineWidth()
998 {
999   return m_lineWidth;
1000 }
1001 
setExpertMode(bool expertMode)1002 void MyMoneyReport::setExpertMode(bool expertMode)
1003 {
1004   m_expertMode = expertMode;
1005 }
1006 
toString(eMyMoney::Report::RowType type)1007 QString MyMoneyReport::toString(eMyMoney::Report::RowType type)
1008 {
1009   switch(type) {
1010   case eMyMoney::Report::RowType::NoRows             : return "eMyMoney::Report::RowType::NoRows";
1011   case eMyMoney::Report::RowType::AssetLiability     : return "eMyMoney::Report::RowType::AssetLiability";
1012   case eMyMoney::Report::RowType::ExpenseIncome      : return "eMyMoney::Report::RowType::ExpenseIncome";
1013   case eMyMoney::Report::RowType::Category           : return "eMyMoney::Report::RowType::Category";
1014   case eMyMoney::Report::RowType::TopCategory        : return "eTopCategory";
1015   case eMyMoney::Report::RowType::Account            : return "eAccount";
1016   case eMyMoney::Report::RowType::Tag                : return "eTag";
1017   case eMyMoney::Report::RowType::Payee              : return "ePayee";
1018   case eMyMoney::Report::RowType::Month              : return "eMonth";
1019   case eMyMoney::Report::RowType::Week               : return "eWeek";
1020   case eMyMoney::Report::RowType::TopAccount         : return "eTopAccount";
1021   case eMyMoney::Report::RowType::AccountByTopAccount: return "eAccountByTopAccount";
1022   case eMyMoney::Report::RowType::EquityType         : return "eEquityType";
1023   case eMyMoney::Report::RowType::AccountType        : return "eAccountType";
1024   case eMyMoney::Report::RowType::Institution        : return "eInstitution";
1025   case eMyMoney::Report::RowType::Budget             : return "eBudget";
1026   case eMyMoney::Report::RowType::BudgetActual       : return "eBudgetActual";
1027   case eMyMoney::Report::RowType::Schedule           : return "eSchedule";
1028   case eMyMoney::Report::RowType::AccountInfo        : return "eAccountInfo";
1029   case eMyMoney::Report::RowType::AccountLoanInfo    : return "eAccountLoanInfo";
1030   case eMyMoney::Report::RowType::AccountReconcile   : return "eAccountReconcile";
1031   case eMyMoney::Report::RowType::CashFlow           : return "eCashFlow";
1032   default                  : return "undefined";
1033   }
1034 }
1035 
toString(eMyMoney::Report::ReportType type)1036 QString MyMoneyReport::toString(eMyMoney::Report::ReportType type)
1037 {
1038   switch(type) {
1039   case eMyMoney::Report::ReportType::NoReport:   return "eNoReport";
1040   case eMyMoney::Report::ReportType::PivotTable: return "ePivotTable";
1041   case eMyMoney::Report::ReportType::QueryTable: return "eQueryTable";
1042   case eMyMoney::Report::ReportType::InfoTable:  return "eInfoTable";
1043   default:          return "undefined";
1044   }
1045 }
1046