wxString StocksListCtrl::OnGetItemText(long item, long column) const { if (column == COL_ID) return wxString::Format("%i", m_stocks[item].STOCKID).Trim(); if (column == COL_DATE) return mmGetDateForDisplay(mmGetStorageStringAsDate(m_stocks[item].PURCHASEDATE)); if (column == COL_NAME) return m_stocks[item].STOCKNAME; if (column == COL_SYMBOL) return m_stocks[item].SYMBOL; if (column == COL_NUMBER) { int precision = m_stocks[item].NUMSHARES == floor(m_stocks[item].NUMSHARES) ? 0 : 4; return Model_Currency::toString(m_stocks[item].NUMSHARES, stock_panel_->m_currency, precision); } if (column == COL_PRICE) return Model_Currency::toString(m_stocks[item].PURCHASEPRICE, stock_panel_->m_currency); if (column == COL_VALUE) return Model_Currency::toString(m_stocks[item].VALUE, stock_panel_->m_currency, 4); if (column == COL_GAIN_LOSS) return Model_Currency::toString(getGainLoss(item), stock_panel_->m_currency); if (column == COL_CURRENT) return Model_Currency::toString(m_stocks[item].CURRENTPRICE, stock_panel_->m_currency, 4); if (column == COL_CURRVALUE) return Model_Currency::toString(m_stocks[item].CURRENTPRICE*m_stocks[item].NUMSHARES, stock_panel_->m_currency); if (column == COL_PRICEDATE) return mmGetDateForDisplay(mmGetStorageStringAsDate(Model_Stock::instance().lastPriceDate(&m_stocks[item]))); if (column == COL_COMMISSION) return Model_Currency::toString(m_stocks[item].COMMISSION, stock_panel_->m_currency); if (column == COL_NOTES) { wxString full_notes = m_stocks[item].NOTES; if (Model_Attachment::NrAttachments(Model_Attachment::reftype_desc(Model_Attachment::STOCK), m_stocks[item].STOCKID)) full_notes = full_notes.Prepend(mmAttachmentManage::GetAttachmentNoteSign()); return full_notes; } return wxEmptyString; }
wxString mmBillsDepositsPanel::getItem(long item, long column) { const Model_Billsdeposits::Full_Data& bill = this->bills_.at(item); switch (column) { case COL_ID: return wxString::Format("%i", bill.BDID).Trim(); case COL_PAYMENT_DATE: return mmGetDateForDisplay(Model_Billsdeposits::NEXTOCCURRENCEDATE(bill)); case COL_DUE_DATE: return mmGetDateForDisplay(Model_Billsdeposits::TRANSDATE(bill)); case COL_ACCOUNT: return bill.ACCOUNTNAME; case COL_PAYEE: return bill.PAYEENAME; case COL_STATUS: return bill.STATUS; case COL_CATEGORY: if (bill.has_split()) return _("Split......."); else return bill.CATEGNAME; case COL_TYPE: return wxGetTranslation(bill.TRANSCODE); case COL_AMOUNT: return Model_Account::toCurrency(bill.TRANSAMOUNT, Model_Account::instance().get(bill.ACCOUNTID)); case COL_FREQUENCY: return GetFrequency(&bill); case COL_REPEATS: if (bill.NUMOCCURRENCES == -1) return L"\x221E"; else return wxString::Format("%i", bill.NUMOCCURRENCES).Trim(); case COL_AUTO: { int repeats = bill.REPEATS; wxString repeatSTR = _("Manual"); if (repeats >= BD_REPEATS_MULTIPLEX_BASE) { repeats -= BD_REPEATS_MULTIPLEX_BASE; repeatSTR = _("Suggested"); if (repeats >= BD_REPEATS_MULTIPLEX_BASE) { repeats -= BD_REPEATS_MULTIPLEX_BASE; repeatSTR = _("Automated"); } } return repeatSTR; } case COL_DAYS: return GetRemainingDays(&bill); case COL_NUMBER: return bill.TRANSACTIONNUMBER; case COL_NOTES: return bill.NOTES; default: return wxEmptyString; } }
wxString mmAssetsPanel::getItem(long item, long column) { const Model_Asset::Data& asset = this->m_assets[item]; switch (column) { case COL_ICON: return " "; case COL_ID: return wxString::Format("%i", asset.ASSETID).Trim(); case COL_NAME: return asset.ASSETNAME; case COL_TYPE: return wxGetTranslation(asset.ASSETTYPE); case COL_VALUE_INITIAL: return Model_Currency::toCurrency(asset.VALUE); case COL_VALUE_CURRENT: return Model_Currency::toCurrency(Model_Asset::value(asset)); case COL_DATE: return mmGetDateForDisplay(Model_Asset::STARTDATE(asset)); case COL_NOTES: { wxString full_notes = asset.NOTES; if (Model_Attachment::NrAttachments(Model_Attachment::reftype_desc(Model_Attachment::ASSET), asset.ASSETID)) full_notes = full_notes.Prepend(mmAttachmentManage::GetAttachmentNoteSign()); return full_notes; } default: return ""; } }
wxString mmReportChartStocks::getHTMLText() { mmHTMLBuilder hb; hb.init(); hb.addHeader(2, _("Stocks Performance Charts")); wxTimeSpan dtDiff = dtRange_->end_date() - dtRange_->start_date(); if (dtRange_->is_with_date() && dtDiff.GetDays() <= 366) hb.DisplayDateHeading(dtRange_->start_date(), dtRange_->end_date(), true); hb.addHorizontalLine(); int count = 0, heldAt = -1; bool pointDot = false, showGridLines = false; wxTimeSpan dist; wxDate dateDt, precDateDt = wxInvalidDateTime; for (const auto& stock : Model_Stock::instance().all(Model_Stock::COL_HELDAT)) { int dataCount = 0, freq = 1; Model_StockHistory::Data_Set histData = Model_StockHistory::instance().find(Model_StockHistory::SYMBOL(stock.SYMBOL), Model_StockHistory::DATE(dtRange_->start_date(), GREATER_OR_EQUAL), Model_StockHistory::DATE(dtRange_->end_date(), LESS_OR_EQUAL)); std::stable_sort(histData.begin(), histData.end(), SorterByDATE()); if (histData.size() <= 30) showGridLines = pointDot = true; else if (histData.size() <= 366) showGridLines = true; else freq = histData.size() / 366; std::vector<ValueTrio> aData; for (const auto& hist : histData) { if (dataCount % freq == 0) { ValueTrio val; dateDt = Model_StockHistory::DATE(hist); if (histData.size() <= 30) val.label = mmGetDateForDisplay(dateDt); else if (precDateDt.IsValid() && dateDt.GetMonth() != precDateDt.GetMonth()) val.label = dateDt.GetMonthName(dateDt.GetMonth()); else val.label = ""; val.amount = hist.VALUE; aData.push_back(val); precDateDt = dateDt; } dataCount++; } if (!aData.empty()) { Model_Account::Data* account = Model_Account::instance().get(stock.HELDAT); hb.addHeader(1, wxString::Format("%s - (%s)", stock.STOCKNAME, account->ACCOUNTNAME)); hb.addLineChart(aData, stock.STOCKNAME, count, 1000, 400, pointDot, showGridLines, true); } heldAt = stock.HELDAT; count++; } return hb.getHTMLText(); }
void mmWebAppDialog::fillControls() { webtranListBox_->DeleteAllItems(); WebAppTransactions_.clear(); mmWebApp::WebApp_DownloadNewTransaction(WebAppTransactions_, false); for (const auto& WebTran : WebAppTransactions_) { wxVector<wxVariant> data; data.push_back(wxVariant(wxString::Format(wxT("%i"),WebTran.ID))); //WEBTRAN_ID data.push_back(wxVariant(mmGetDateForDisplay(WebTran.Date))); //WEBTRAN_DATE data.push_back(wxVariant(WebTran.Account)); //WEBTRAN_ACCOUNT data.push_back(wxVariant(WebTran.Status)); //WEBTRAN_STATUS data.push_back(wxVariant(WebTran.Type)); //WEBTRAN_TYPE wxString Payee = WebTran.Type != "Transfer" ? WebTran.Payee : "> " + WebTran.ToAccount; data.push_back(wxVariant(Payee)); //WEBTRAN_PAYEE wxString Category = WebTran.Category; if (WebTran.SubCategory != wxEmptyString) Category += ":" + WebTran.SubCategory; data.push_back(wxVariant(Category)); //WEBTRAN_CATEGORY data.push_back(wxVariant(wxString::Format(wxT("%f"),WebTran.Amount))); data.push_back(wxVariant(WebTran.Notes)); //WEBTRAN_NOTES data.push_back(wxVariant(WebTran.Attachments)); //WEBTRAN_ATTACHMENTS webtranListBox_->AppendItem(data, (wxUIntPtr)WebTran.ID); } }
void mm_html_template::load_context() { (*this)(L"TODAY") = mmGetDateForDisplay(wxDate::Today().FormatISODate()) + " " + wxDate::Now().FormatISOTime(); for (const auto &r: Model_Infotable::instance().all()) (*this)(r.INFONAME.ToStdWstring()) = r.INFOVALUE; (*this)(L"INFOTABLE") = Model_Infotable::to_loop_t(); const Model_Currency::Data* currency = Model_Currency::GetBaseCurrency(); if (currency) currency->to_template(*this); }
void mmStockDialog::OnHistoryAddButton(wxCommandEvent& /*event*/) { if (m_stock->SYMBOL.IsEmpty()) return; wxString listStr; wxDateTime dt; long i, histID; double dPrice = 0.0; Model_Account::Data* account = Model_Account::instance().get(m_stock->HELDAT); Model_Currency::Data* currency = Model_Account::currency(account); wxString currentPriceStr = currentPrice_->GetValue().Trim(); if (!Model_Currency::fromString(currentPriceStr, dPrice, currency) || (dPrice < 0.0)) return; histID = Model_StockHistory::instance().addUpdate(m_stock->SYMBOL, priceDate_->GetValue(), dPrice, Model_StockHistory::MANUAL); for (i=0; i<priceListBox_->GetItemCount(); i++) { listStr = priceListBox_->GetItemText(i, 0); mmParseDisplayStringToDate(dt, listStr, mmOptions::instance().dateFormat_); if (dt.FormatISODate() == priceDate_->GetValue().FormatISODate()) break; } if (i == priceListBox_->GetItemCount()) { //add for (i=0; i<priceListBox_->GetItemCount(); i++) { listStr = priceListBox_->GetItemText(i, 0); mmParseDisplayStringToDate(dt, listStr, mmOptions::instance().dateFormat_); if (dt.FormatISODate() < priceDate_->GetValue().FormatISODate()) break; } wxListItem item; item.SetId(i); item.SetData(histID); priceListBox_->InsertItem( item ); } if (i != priceListBox_->GetItemCount()) { listStr = Model_Account::toString(dPrice, account, 4); priceListBox_->SetItem(i, 0, mmGetDateForDisplay(priceDate_->GetValue())); priceListBox_->SetItem(i, 1, listStr); listStr = Model_Account::toString(dPrice - m_stock->PURCHASEPRICE, account, 4); priceListBox_->SetItem(i, 2, listStr); } }
void mmMainCurrencyDialog::ShowCurrencyHistory() { valueListBox_->DeleteAllItems(); int baseCurrencyID = Option::instance().BaseCurrency(); if (currencyID_ <= 0 || currencyID_ == baseCurrencyID) { historyButtonAdd_->Disable(); historyButtonDelete_->Disable(); return; } else { historyButtonAdd_->Enable(); historyButtonDelete_->Enable(); } Model_CurrencyHistory::Data_Set histData = Model_CurrencyHistory::instance().find(Model_CurrencyHistory::CURRENCYID(currencyID_)); std::stable_sort(histData.begin(), histData.end(), SorterByCURRDATE()); std::reverse(histData.begin(), histData.end()); if (!histData.empty()) { int idx = 0; for (const auto &d : histData) { wxListItem item; item.SetId(idx); item.SetData(d.CURRHISTID); valueListBox_->InsertItem(item); const wxDate dtdt = Model_CurrencyHistory::CURRDATE(d); const wxString dispAmount = wxString::Format(wxT("%f"), d.CURRVALUE); valueListBox_->SetItem(idx, 0, mmGetDateForDisplay(dtdt)); valueListBox_->SetItem(idx, 1, dispAmount); const wxString& priceAmount = wxEmptyString; valueListBox_->SetItem(idx, 2, priceAmount); idx++; } valueListBox_->RefreshItems(0, --idx); } }
void mmReportSummaryStocks::RefreshData() { stocks_.clear(); gain_loss_sum_total_ = 0.0; stockBalance_ = 0.0; data_holder line; account_holder account; for (const auto& a : Model_Account::instance().all(Model_Account::COL_ACCOUNTNAME)) { if (Model_Account::type(a) != Model_Account::INVESTMENT) continue; if (Model_Account::status(a) != Model_Account::OPEN) continue; account.id = a.id(); account.name = a.ACCOUNTNAME; account.gainloss = 0.0; account.total = Model_Account::investment_balance(a).first; account.data.clear(); for (const auto& stock : Model_Stock::instance().find(Model_Stock::HELDAT(a.ACCOUNTID))) { const Model_Currency::Data* currency = Model_Account::currency(a); stockBalance_ += currency->BASECONVRATE * stock.VALUE; account.gainloss += stock.VALUE - Model_Stock::value(stock); gain_loss_sum_total_ += (stock.VALUE - Model_Stock::value(stock)) * currency->BASECONVRATE; line.name = stock.STOCKNAME; line.symbol = stock.SYMBOL; line.date = mmGetDateForDisplay(Model_Stock::PURCHASEDATE(stock)); line.qty = stock.NUMSHARES; line.purchase = stock.PURCHASEPRICE; line.current = stock.CURRENTPRICE; line.commission = stock.COMMISSION; line.gainloss = stock.VALUE - Model_Stock::value(stock); line.value = stock.VALUE; account.data.push_back(line); } stocks_.push_back(account); } }
wxString StocksListCtrl::OnGetItemText(long item, long column) const { if (column == COL_DATE) return mmGetDateForDisplay(mmGetStorageStringAsDate(m_stocks[item].PURCHASEDATE)); if (column == COL_NAME) return m_stocks[item].STOCKNAME; if (column == COL_NUMBER) { int precision = m_stocks[item].NUMSHARES == floor(m_stocks[item].NUMSHARES) ? 0 : 4; return Model_Currency::toString(m_stocks[item].NUMSHARES, stock_panel_->m_currency, precision); } if (column == COL_GAIN_LOSS) return Model_Currency::toString(getGainLoss(item), stock_panel_->m_currency /*, 4*/); if (column == COL_VALUE) return Model_Currency::toString(m_stocks[item].VALUE, stock_panel_->m_currency); if (column == COL_CURRENT) return Model_Currency::toString(m_stocks[item].CURRENTPRICE, stock_panel_->m_currency); if (column == COL_NOTES) { wxString full_notes = m_stocks[item].NOTES; if (Model_Attachment::NrAttachments(Model_Attachment::reftype_desc(Model_Attachment::STOCK), m_stocks[item].STOCKID)) full_notes = full_notes.Prepend(mmAttachmentManage::GetAttachmentNoteSign()); return full_notes; } return ""; }
void mmStockDialog::showStockHistory() { priceListBox_->DeleteAllItems(); if (m_stock->SYMBOL.IsEmpty()) return; Model_Account::Data* account = Model_Account::instance().get(m_stock->HELDAT); Model_StockHistory::Data_Set histData = Model_StockHistory::instance().find(Model_StockHistory::SYMBOL(m_stock->SYMBOL)); std::stable_sort(histData.begin(), histData.end(), SorterByDATE()); std::reverse(histData.begin(), histData.end()); if (histData.size()>300) histData.resize(300); if (!histData.empty()) { int idx=0; for (const auto &d : histData) { wxListItem item; item.SetId(idx); item.SetData(d.HISTID); priceListBox_->InsertItem( item ); const wxDate dtdt = Model_StockHistory::DATE(d); const wxString dispAmount = Model_Account::toString(d.VALUE, account, 4); priceListBox_->SetItem(idx, 0, mmGetDateForDisplay(dtdt)); priceListBox_->SetItem(idx, 1, dispAmount); if (idx == 0) { priceDate_->SetValue(dtdt); currentPrice_->SetValue(dispAmount); } const wxString& priceAmount = Model_Account::toString(d.VALUE - m_stock->PURCHASEPRICE, account, 4); priceListBox_->SetItem(idx, 2, priceAmount); idx++; } priceListBox_->RefreshItems(0, --idx); } }
const wxString mmExportTransaction::getTransactionCSV(const Model_Checking::Full_Data & full_tran, int accountID, const wxString& dateMask) { bool out = full_tran.ACCOUNTID == accountID; const wxString delimit = Model_Infotable::instance().GetStringInfo("DELIMITER", mmex::DEFDELIMTER); wxString buffer = ""; int trans_id = full_tran.id(); const wxString& accountName = (!out ? full_tran.PAYEENAME : full_tran.ACCOUNTNAME); wxString categ = full_tran.m_splits.empty() ? full_tran.CATEGNAME : ""; wxString transNum = full_tran.TRANSACTIONNUMBER; wxString notes = (full_tran.NOTES); notes.Replace("''", "'"); notes.Replace("\n", "\\n"); if (Model_Checking::type(full_tran) == Model_Checking::TRANSFER) { categ = "[" + (!out ? full_tran.ACCOUNTNAME : full_tran.PAYEENAME) + "]"; //Transaction number used to make transaction unique // to proper merge transfer records if (transNum.IsEmpty() && notes.IsEmpty()) transNum = wxString::Format("#%i", full_tran.id()); } if (!full_tran.m_splits.empty()) { for (const auto &split_entry : full_tran.m_splits) { double value = split_entry.SPLITTRANSAMOUNT; if (Model_Checking::type(full_tran) == Model_Checking::WITHDRAWAL) value = -value; const wxString split_amount = wxString() << value; const wxString split_categ = Model_Category::full_name(split_entry.CATEGID, split_entry.SUBCATEGID); buffer << trans_id << delimit << inQuotes(accountName, delimit) << delimit << inQuotes(mmGetDateForDisplay(Model_Checking::TRANSDATE(full_tran)), delimit) << delimit << inQuotes(full_tran.PAYEENAME, delimit) << delimit << full_tran.STATUS << delimit << full_tran.TRANSCODE << delimit << inQuotes(split_categ, delimit) << delimit << inQuotes(split_amount, delimit) << delimit << "" << delimit << inQuotes(notes, delimit) << "\n"; } } else { buffer << trans_id << delimit << inQuotes(accountName, delimit) << delimit << inQuotes(mmGetDateForDisplay(Model_Checking::TRANSDATE(full_tran)), delimit) << delimit << inQuotes(full_tran.PAYEENAME, delimit) << delimit << full_tran.STATUS << delimit << full_tran.TRANSCODE << delimit << inQuotes(categ, delimit) << delimit << Model_Checking::balance(full_tran, (out ? full_tran.ACCOUNTID : full_tran.TOACCOUNTID)) << delimit << "" << delimit << inQuotes(notes, delimit) << "\n"; } return buffer; }
/*** Trigger a quote download ***/ bool mmStocksPanel::onlineQuoteRefresh(wxString& sError) { if(listCtrlAccount_->m_stocks.size() < 1) { sError = _("Nothing to update"); return false; } //Symbol, (Amount, Name) std::map<wxString, std::pair<double, wxString> > stocks_data; wxString site = ""; for (const auto &stock : listCtrlAccount_->m_stocks) { const wxString symbol = stock.SYMBOL.Upper(); if (!symbol.IsEmpty()) { if (stocks_data.find(symbol) == stocks_data.end()) { stocks_data[symbol] = std::make_pair(stock.CURRENTPRICE, ""); site << symbol << "+"; } } } if (site.Right(1).Contains("+")) site.RemoveLast(1); //Sample: http://finance.yahoo.com/d/quotes.csv?s=SBER.ME+GAZP.ME&f=sl1c4n&e=.csv //Sample CSV: "SBER.ME",85.49,"RUB","SBERBANK" site = wxString::Format(mmex::weblink::YahooQuotes, site); refresh_button_->SetBitmapLabel(wxBitmap(wxImage(led_yellow_xpm).Scale(16,16))); stock_details_->SetLabelText(_("Connecting...")); wxString sOutput; int err_code = site_content(site, sOutput); if (err_code != wxURL_NOERR) { sError = sOutput; return false; } //--// wxString StockSymbolWithSuffix, sName, StockQuoteCurrency; double dPrice = 0.0; wxStringTokenizer tkz(sOutput, "\r\n"); while (tkz.HasMoreTokens()) { const wxString csvline = tkz.GetNextToken(); StockSymbolWithSuffix = ""; StockQuoteCurrency = ""; wxRegEx pattern("\"([^\"]+)\",([^,][0-9.]+),\"([^\"]*)\",\"([^\"]*)\""); if (pattern.Matches(csvline)) { StockSymbolWithSuffix = pattern.GetMatch(csvline, 1); pattern.GetMatch(csvline, 2).ToDouble(&dPrice); StockQuoteCurrency = pattern.GetMatch(csvline, 3); sName = pattern.GetMatch(csvline, 4); } bool updated = !StockSymbolWithSuffix.IsEmpty(); /* HACK FOR GBP http://sourceforge.net/p/moneymanagerex/bugs/414/ http://sourceforge.net/p/moneymanagerex/bugs/360/ 1. If the share has GBp as currency, its downloaded value in pence 2. If the share has another currency, we don't need to modify the price */ if (updated && dPrice > 0) { if (StockQuoteCurrency == "GBp") dPrice = dPrice / 100; stocks_data[StockSymbolWithSuffix].first = dPrice; stocks_data[StockSymbolWithSuffix].second = sName; sError << wxString::Format(_("%s\t -> %s\n") , StockSymbolWithSuffix, wxString::Format("%0.4f", dPrice)); } } for (auto &s: listCtrlAccount_->m_stocks) { std::map<wxString, std::pair<double, wxString> >::const_iterator it = stocks_data.find(s.SYMBOL.Upper()); if (it == stocks_data.end()) continue; dPrice = it->second.first; s.CURRENTPRICE = dPrice; s.VALUE = dPrice * s.NUMSHARES; if (s.STOCKNAME.empty()) s.STOCKNAME = it->second.second; Model_Stock::instance().save(&s); Model_StockHistory::instance().addUpdate(s.SYMBOL, wxDate::Now(), dPrice, Model_StockHistory::ONLINE); } // Now refresh the display int selected_id = -1; if (listCtrlAccount_->get_selectedIndex() > -1) selected_id = listCtrlAccount_->m_stocks[listCtrlAccount_->get_selectedIndex()].STOCKID; listCtrlAccount_->doRefreshItems(selected_id); // We are done! LastRefreshDT_ = wxDateTime::Now(); StocksRefreshStatus_ = true; refresh_button_->SetBitmapLabel(wxBitmap(wxImage(led_green_xpm).Scale(16,16))); strLastUpdate_.Printf(_("%s on %s"), LastRefreshDT_.FormatTime() , mmGetDateForDisplay(LastRefreshDT_)); Model_Infotable::instance().Set("STOCKS_LAST_REFRESH_DATETIME", strLastUpdate_); return true; }
void mmReportCashFlow::getStats(double& tInitialBalance, std::vector<ValueTrio>& forecastVector) { int years = cashFlowReportType_ == YEARLY ? 10 : 1;// Monthly for 10 years or Daily for 1 year std::map<wxDateTime, double> daily_balance; for (const auto& account : Model_Account::instance().all()) { if (Model_Account::status(account) == Model_Account::CLOSED || Model_Account::type(account) == Model_Account::INVESTMENT) continue; if (accountArray_) { if (wxNOT_FOUND == accountArray_->Index(account.ACCOUNTNAME)) continue; } else { if (! activeTermAccounts_ && Model_Account::type(account) == Model_Account::TERM) continue; if (! activeBankAccounts_ && (Model_Account::type(account) == Model_Account::CHECKING || Model_Account::type(account) == Model_Account::CREDIT_CARD)) continue; } const Model_Currency::Data* currency = Model_Account::currency(account); tInitialBalance += account.INITIALBAL * currency->BASECONVRATE; for (const auto& tran : Model_Account::transaction(account)) { daily_balance[Model_Checking::TRANSDATE(tran)] += Model_Checking::balance(tran, account.ACCOUNTID) * currency->BASECONVRATE; } } // We now know the total balance on the account // Start by walking through the recurring transaction list const wxDateTime yearFromNow = today_.Add(wxDateSpan::Years(years)); forecastVec fvec; for (const auto& entry : Model_Billsdeposits::instance().all()) { wxDateTime nextOccurDate = Model_Billsdeposits::NEXTOCCURRENCEDATE(entry); if (nextOccurDate > yearFromNow) continue; int repeatsType = entry.REPEATS; int numRepeats = entry.NUMOCCURRENCES; double amt = entry.TRANSAMOUNT; double toAmt = entry.TOTRANSAMOUNT; // DeMultiplex the Auto Executable fields from the db entry: REPEATS if (repeatsType >= BD_REPEATS_MULTIPLEX_BASE) // Auto Execute User Acknowlegement required repeatsType -= BD_REPEATS_MULTIPLEX_BASE; if (repeatsType >= BD_REPEATS_MULTIPLEX_BASE) // Auto Execute Silent mode repeatsType -= BD_REPEATS_MULTIPLEX_BASE; bool processNumRepeats = numRepeats != -1 || repeatsType == 0; if (repeatsType == 0) { numRepeats = 1; processNumRepeats = true; } int accountID = entry.ACCOUNTID; int toAccountID = entry.TOACCOUNTID; const Model_Account::Data* account = Model_Account::instance().get(accountID); bool isAccountFound = account && !(accountArray_ != nullptr && wxNOT_FOUND == accountArray_->Index(account->ACCOUNTNAME)); //linear search const Model_Account::Data* to_account = Model_Account::instance().get(toAccountID); bool isToAccountFound = to_account && !(accountArray_ != nullptr && wxNOT_FOUND == accountArray_->Index(to_account->ACCOUNTNAME)); //linear search if (!isAccountFound && !isToAccountFound) continue; // skip account // Determine if we need to process this account if (!m_cashflowSpecificAccounts) { if (Model_Account::status(account) == Model_Account::CLOSED || Model_Account::type(account) == Model_Account::INVESTMENT) continue; if (!activeTermAccounts_ && Model_Account::type(account) == Model_Account::TERM) continue; if (!activeBankAccounts_ && (Model_Account::type(account) == Model_Account::CHECKING || Model_Account::type(account) == Model_Account::CREDIT_CARD)) continue; } double convRate = (account ? Model_Account::currency(account)->BASECONVRATE : 1.0); double toConvRate = (to_account ? Model_Account::currency(to_account)->BASECONVRATE : 1.0); // Process all possible recurring transactions for this BD while (1) { if (nextOccurDate > yearFromNow) break; if (processNumRepeats) numRepeats--; mmRepeatForecast rf; rf.date = nextOccurDate; rf.amount = 0.0; switch (Model_Billsdeposits::type(entry)) { case Model_Billsdeposits::WITHDRAWAL: rf.amount = -amt * convRate; break; case Model_Billsdeposits::DEPOSIT: rf.amount = +amt * convRate; break; case Model_Billsdeposits::TRANSFER: if (isAccountFound) rf.amount -= amt * convRate; if (isToAccountFound) rf.amount += toAmt * toConvRate; break; default: break; } fvec.push_back(rf); if (processNumRepeats && (numRepeats <= 0)) break; nextOccurDate = Model_Billsdeposits::nextOccurDate(repeatsType, numRepeats, nextOccurDate); if (repeatsType == Model_Billsdeposits::REPEAT_IN_X_DAYS) // repeat in numRepeats Days (Once only) { if (numRepeats > 0) numRepeats = -1; else break; } else if (repeatsType == Model_Billsdeposits::REPEAT_IN_X_MONTHS) // repeat in numRepeats Months (Once only) { if (numRepeats > 0) numRepeats = -1; else break; } else if (repeatsType == Model_Billsdeposits::REPEAT_EVERY_X_DAYS) // repeat every numRepeats Days numRepeats = entry.NUMOCCURRENCES; else if (repeatsType == Model_Billsdeposits::REPEAT_EVERY_X_MONTHS) // repeat every numRepeats Months numRepeats = entry.NUMOCCURRENCES; } // end while } //end query const wxDateTime& dtBegin = today_; for (int idx = 0; idx < (int) forecastVector.size(); idx++) { wxDateTime dtEnd = cashFlowReportType_ == YEARLY ? dtBegin.Add(wxDateSpan::Months(idx)) : dtBegin.Add(wxDateSpan::Days(idx)); for (const auto& balance : fvec) { if (balance.date.IsBetween(dtBegin, dtEnd)) forecastVector[idx].amount += balance.amount; } for (const auto& d_balance : daily_balance) { if (!d_balance.first.IsLaterThan(dtEnd)) forecastVector[idx].amount += d_balance.second; } forecastVector[idx].label = mmGetDateForDisplay(dtEnd); } }
wxString mmReportSummaryByDate::getHTMLText() { int i = 0, j; double balancePerDay[5]; mmHTMLBuilder hb; wxString datePrec; wxDate date, dateStart = wxDate::Now(), dateEnd = wxDate::Now(); wxDateSpan span; mmHistoryItem *pHistItem; mmHistoryData arHistory; std::vector<balanceMap> balanceMapVec(Model_Account::instance().all().size()); std::vector<std::map<wxDate, double>::const_iterator> arIt(balanceMapVec.size()); std::vector<double> arBalance(balanceMapVec.size()); std::vector<wxString> totBalanceData; std::vector<wxDate> arDates; hb.init(); hb.addDivContainer(); hb.addHeader(2, wxString::Format(_("Accounts Balance - %s"), mode_==0 ? _("Monthly Report"):_("Yearly Report"))); hb.addDateNow(); hb.addLineBreak(); hb.startTable(); hb.startThead(); hb.startTableRow(); hb.addTableHeaderCell(_("Date")); hb.addTableHeaderCell(_("Cash"), true); hb.addTableHeaderCell(_("Bank Accounts"), true); hb.addTableHeaderCell(_("Credit Card Accounts"), true); hb.addTableHeaderCell(_("Term Accounts"), true); hb.addTableHeaderCell(_("Total"), true); hb.addTableHeaderCell(_("Stocks"), true); hb.addTableHeaderCell(_("Balance"), true); hb.endTableRow(); hb.endDiv(); hb.endThead(); for (const auto& account: Model_Account::instance().all()) { if (Model_Account::type(account) != Model_Account::INVESTMENT) { // in balanceMapVec ci sono i totali dei movimenti giorno per giorno const Model_Currency::Data* currency = Model_Account::currency(account); for (const auto& tran: Model_Account::transaction(account)) balanceMapVec[i][Model_Checking::TRANSDATE(tran)] += Model_Checking::balance(tran, account.ACCOUNTID) * Model_CurrencyHistory::getDayRate(currency->id(), tran.TRANSDATE); if (Model_Account::type(account) != Model_Account::TERM && balanceMapVec[i].size()) { date = balanceMapVec[i].begin()->first; if (date.IsEarlierThan(dateStart)) dateStart = date; } arBalance[i] = account.INITIALBAL * Model_CurrencyHistory::getDayRate(currency->id(), dateStart.FormatISODate()); } else { Model_Stock::Data_Set stocks = Model_Stock::instance().find(Model_Stock::HELDAT(account.id())); for (const auto & stock : stocks) { arHistory.resize(arHistory.size() + 1); pHistItem = arHistory.data() + arHistory.size() - 1; pHistItem->acctId = account.id(); pHistItem->stockId = stock.STOCKID; pHistItem->purchasePrice = stock.PURCHASEPRICE; pHistItem->purchaseDate = Model_Stock::PURCHASEDATE(stock); pHistItem->purchaseDateStr = stock.PURCHASEDATE; pHistItem->numShares = stock.NUMSHARES; pHistItem->stockHist = Model_StockHistory::instance().find(Model_StockHistory::SYMBOL(stock.SYMBOL)); std::stable_sort(pHistItem->stockHist.begin(), pHistItem->stockHist.end(), SorterByDATE()); std::reverse(pHistItem->stockHist.begin(), pHistItem->stockHist.end()); } } i++; } if (mode_ == 0) { dateEnd -= wxDateSpan::Months(1); dateEnd.SetToLastMonthDay(dateEnd.GetMonth(), dateEnd.GetYear()); span = wxDateSpan::Months(1); } else if (mode_ == 1) { dateEnd.Set(31, wxDateTime::Dec, wxDateTime::Now().GetYear()); span = wxDateSpan::Years(1); } else wxASSERT(0); date = dateEnd; while (date.IsLaterThan(dateStart)) date -= span; dateStart = date; i = 0; for (const auto& acctMap: balanceMapVec) arIt[i++] = acctMap.begin(); // prepare the dates array while (dateStart <= dateEnd) { if (mode_ == 0) dateStart.SetToLastMonthDay(dateStart.GetMonth(), dateStart.GetYear()); arDates.push_back(dateStart); dateStart += span; } date = wxDate::Today(); if (date.GetDay() != dateEnd.GetDay() || date.GetMonth() != dateEnd.GetMonth() || date.GetYear() != dateEnd.GetYear()) arDates.push_back(date); for (const auto & dateStart : arDates) { i = 0; for (auto& account: Model_Account::instance().all()) { if (Model_Account::type(account) != Model_Account::INVESTMENT) { for (; arIt[i] != balanceMapVec[i].end(); ++arIt[i]) { if (arIt[i]->first.IsLaterThan(dateStart)) break; arBalance[i] += arIt[i]->second; } } else { double convRate = 1.0; Model_Currency::Data* currency = Model_Account::currency(account); if (currency) convRate = Model_CurrencyHistory::getDayRate(currency->id(), dateStart.FormatISODate()); arBalance[i] = arHistory.getDailyBalanceAt(&account, dateStart) * convRate; } i++; } totBalanceData.push_back(dateStart.FormatISODate()); for (j=0; j<5; j++) balancePerDay[j] = 0.0; for (j=0; j<5; j++) { i = 0; for (const auto& account: Model_Account::instance().all()) { if ((j == 0 && Model_Account::type(account) == Model_Account::CASH) || (j == 1 && Model_Account::type(account) == Model_Account::CHECKING) || (j == 2 && Model_Account::type(account) == Model_Account::CREDIT_CARD) || (j == 3 && Model_Account::type(account) == Model_Account::TERM) || (j == 4 && Model_Account::type(account) == Model_Account::INVESTMENT)) { balancePerDay[j] += arBalance[i]; } i++; } totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[j])); } totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[0] + balancePerDay[1] + balancePerDay[2] + balancePerDay[3])); totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[0] + balancePerDay[1] + balancePerDay[2] + balancePerDay[3] + balancePerDay[4])); } hb.startTbody(); for (i = totBalanceData.size() - 8; i >= 0; i -= 8) { if (datePrec.Left(4) != totBalanceData[i].Left(4)) { hb.startTotalTableRow(); hb.addTableCell(totBalanceData[i].Left(4)); hb.addTableCell(""); hb.addTableCell(""); hb.addTableCell(""); hb.addTableCell(""); hb.addTableCell(""); hb.addTableCell(""); hb.addTableCell(""); hb.endTableRow(); } hb.startTableRow(); hb.addTableCell(mmGetDateForDisplay(mmGetStorageStringAsDate(totBalanceData[i]))); hb.addTableCell(totBalanceData[i + 1], true); hb.addTableCell(totBalanceData[i + 2], true); hb.addTableCell(totBalanceData[i + 3], true); hb.addTableCell(totBalanceData[i + 4], true); hb.addTableCell(totBalanceData[i + 6], true); hb.addTableCell(totBalanceData[i + 5], true); hb.addTableCell(totBalanceData[i + 7], true); hb.endTableRow(); datePrec = totBalanceData[i]; } hb.endTbody(); hb.endTable(); hb.end(); Model_Report::outputReportFile(hb.getHTMLText()); return ""; }
wxString mmReportTransactions::getHTMLText() { mmHTMLBuilder hb; hb.init(); hb.addDivContainer(); wxString transHeading = _("Transaction List "); const Model_Account::Data* acc = Model_Account::instance().get(refAccountID_); if (acc) transHeading = wxString::Format(_("Transaction List for Account: %s"), acc->ACCOUNTNAME); hb.addHeader(2, transHeading); hb.addDateNow(); hb.addLineBreak(); hb.startSortTable(); hb.startThead(); // Display the data Headings hb.startTableRow(); hb.addTableHeaderCell(_("Date")); hb.addTableHeaderCell(_("Account")); hb.addTableHeaderCell(_("Payee")); hb.addTableHeaderCell(_("Status")); hb.addTableHeaderCell(_("Category")); hb.addTableHeaderCell(_("Type")); hb.addTableHeaderCell(_("Number")); hb.addTableHeaderCell(_("Notes")); hb.addTableHeaderCell(_("Amount"), true); hb.endTableRow(); hb.endThead(); hb.startTbody(); double total = 0; Model_Account::Data* account = nullptr; bool monoAcc = transDialog_->getAccountCheckBox(); if (monoAcc) account = Model_Account::instance().get(transDialog_->getAccountID()); // Display the data for each row for (auto& transaction : trans_) { hb.startTableRow(); hb.addTableCell(mmGetDateForDisplay(mmGetStorageStringAsDate(transaction.TRANSDATE))); hb.addTableCellLink(wxString::Format("trxid:%d", transaction.TRANSID), transaction.ACCOUNTNAME); hb.addTableCell(transaction.PAYEENAME); hb.addTableCell(transaction.STATUS); hb.addTableCell(transaction.CATEGNAME); hb.addTableCell(wxGetTranslation(transaction.TRANSCODE)); hb.addTableCell(transaction.TRANSACTIONNUMBER); hb.addTableCell(transaction.NOTES); // Get the exchange rate for the account if (!monoAcc) { account = Model_Account::instance().get(transaction.ACCOUNTID); if (account) { const Model_Currency::Data* currency = Model_Account::currency(account); double convRate = 1; if (currency) convRate = currency->BASECONVRATE; double amount = Model_Checking::balance(transaction, transaction.ACCOUNTID) * convRate; hb.addCurrencyCell(amount); total += amount; } else hb.addTableCell(""); } else { double amount = Model_Checking::balance(transaction, account->ACCOUNTID); const Model_Currency::Data* currency = Model_Account::currency(account); hb.addCurrencyCell(amount, currency); total += amount; } hb.endTableRow(); } hb.endTbody(); // display the total balance. const wxString totalStr = Model_Currency::toCurrency(total, (monoAcc ? Model_Account::currency(account) : Model_Currency::GetBaseCurrency())); const std::vector<wxString> v{ totalStr }; hb.addTotalRow(_("Total Amount: "), 9, v); hb.endTable(); transDialog_->getDescription(hb); hb.endDiv(); hb.end(); return hb.getHTMLText(); }
wxString mmReportSummaryByDate::getHTMLText() { int i = 0, j; double balancePerDay[5]; mmHTMLBuilder hb; wxString datePrec; wxDate date, dateStart = wxDate::Now(), dateEnd = wxDate::Now(); wxDateSpan span; std::vector<balanceMap> balanceMapVec(Model_Account::instance().all().size()); std::vector<std::map<wxDate, double>::const_iterator> arIt(balanceMapVec.size()); std::vector<double> arBalance(balanceMapVec.size()); std::vector<wxString> totBalanceData; hb.init(); hb.addDivContainer(); hb.addHeader(2, wxString::Format(_("Account Balance - %s"), mode_==0 ? _("Monthly Report"):_("Yearly Report"))); hb.addDateNow(); hb.addLineBreak(); hb.startTable(); hb.startThead(); hb.startTableRow(); hb.addTableHeaderCell(_("Date")); hb.addTableHeaderCell(_("Bank Account"), true); hb.addTableHeaderCell(_("Credit Card Accounts"), true); hb.addTableHeaderCell(_("Term Accounts"), true); hb.addTableHeaderCell(_("Stocks"), true); hb.addTableHeaderCell(_("Balance"), true); hb.endTableRow(); hb.endDiv(); hb.endThead(); for (const auto& account: Model_Account::instance().all()) { if (Model_Account::type(account) == Model_Account::CHECKING || Model_Account::type(account) == Model_Account::CREDIT_CARD || Model_Account::type(account) == Model_Account::TERM) { // in balanceMapVec ci sono i totali dei movimenti giorno per giorno const Model_Currency::Data* currency = Model_Account::currency(account); for (const auto& tran: Model_Account::transaction(account)) balanceMapVec[i][Model_Checking::TRANSDATE(tran)] += Model_Checking::balance(tran, account.ACCOUNTID) * currency->BASECONVRATE; if ((Model_Account::type(account) == Model_Account::CHECKING || Model_Account::type(account) == Model_Account::CREDIT_CARD) && balanceMapVec[i].size()) { date = balanceMapVec[i].begin()->first; if (date.IsEarlierThan(dateStart)) dateStart = date; } arBalance[i] = account.INITIALBAL * currency->BASECONVRATE; } i++; } if (mode_ == 0) { dateEnd -= wxDateSpan::Months(1); dateEnd.SetToLastMonthDay(dateEnd.GetMonth(), dateEnd.GetYear()); span = wxDateSpan::Months(1); } else if (mode_ == 1) { dateEnd.Set(31, wxDateTime::Dec, wxDateTime::Now().GetYear(), 23, 59, 59); span = wxDateSpan::Years(1); } else wxASSERT(0); date = dateEnd; while (date.IsLaterThan(dateStart)) date -= span; dateStart = date; //dateStart.Set(31,wxDateTime::Dec,2013); i = 0; for (const auto& acctMap: balanceMapVec) arIt[i++] = acctMap.begin(); while (dateStart <= dateEnd) { if (mode_ == 0 ) dateStart.SetToLastMonthDay(dateStart.GetMonth(), dateStart.GetYear()); i = 0; for (auto& account: Model_Account::instance().all()) { if (Model_Account::type(account) == Model_Account::CHECKING || Model_Account::type(account) == Model_Account::CREDIT_CARD || Model_Account::type(account) == Model_Account::TERM) { for (; arIt[i] != balanceMapVec[i].end(); ++arIt[i]) { if (arIt[i]->first.IsLaterThan(dateStart)) break; arBalance[i] += arIt[i]->second; } } else if (Model_Account::type(account) == Model_Account::INVESTMENT) arBalance[i] = GetDailyBalanceAt(&account, dateStart); i++; } totBalanceData.push_back(dateStart.FormatISODate()); for (j=0; j<5; j++) balancePerDay[j] = 0.0; for (j=0; j<4; j++) { i = 0; for (const auto& account: Model_Account::instance().all()) { if ((j == 0 && Model_Account::type(account) == Model_Account::CHECKING) || (j == 1 && Model_Account::type(account) == Model_Account::CREDIT_CARD) || (j == 2 && Model_Account::type(account) == Model_Account::TERM) || (j == 3 && Model_Account::type(account) == Model_Account::INVESTMENT)) { balancePerDay[j] += arBalance[i]; } i++; } totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[j])); balancePerDay[4] += balancePerDay[j]; } totBalanceData.push_back(Model_Currency::toCurrency(balancePerDay[j])); dateStart += span; } hb.startTbody(); for (i = totBalanceData.size() - 6; i >= 0; i -= 6) { if (datePrec.Left(4) != totBalanceData[i].Left(4)) { hb.startTotalTableRow(); hb.addTableCell(totBalanceData[i].Left(4)); hb.addTableCell(""); hb.addTableCell(""); hb.addTableCell(""); hb.addTableCell(""); hb.addTableCell(""); hb.endTableRow(); } hb.startTableRow(); hb.addTableCell(mmGetDateForDisplay(mmGetStorageStringAsDate(totBalanceData[i]))); hb.addTableCell(totBalanceData[i + 1], true); hb.addTableCell(totBalanceData[i + 2], true); hb.addTableCell(totBalanceData[i + 3], true); hb.addTableCell(totBalanceData[i + 4], true); hb.addTableCell(totBalanceData[i + 5], true); hb.endTableRow(); datePrec = totBalanceData[i]; } hb.endTbody(); hb.endTable(); hb.end(); return hb.getHTMLText(); }
void mmHTMLBuilder::addTableCell(const wxDateTime& date) { wxString date_str = mmGetDateForDisplay(date); this->addTableCell(date_str); }
wxString mmReportChartStocks::getHTMLText() { mmHTMLBuilder hb; hb.init(); hb.addDivContainer(); hb.addHeader(2, getReportTitle()); hb.addDateNow(); wxTimeSpan dtDiff = m_date_range->end_date() - m_date_range->start_date(); if (m_date_range->is_with_date() && dtDiff.GetDays() <= 366) hb.DisplayDateHeading(m_date_range->start_date(), m_date_range->end_date(), true); hb.addHorizontalLine(); bool pointDot = false, showGridLines = false; wxTimeSpan dist; wxDate precDateDt = wxInvalidDateTime; for (const auto& stock : Model_Stock::instance().all(Model_Stock::COL_HELDAT)) { int dataCount = 0, freq = 1; Model_StockHistory::Data_Set histData = Model_StockHistory::instance().find(Model_StockHistory::SYMBOL(stock.SYMBOL), Model_StockHistory::DATE(m_date_range->start_date(), GREATER_OR_EQUAL), Model_StockHistory::DATE(m_date_range->end_date(), LESS_OR_EQUAL)); std::stable_sort(histData.begin(), histData.end(), SorterByDATE()); if (histData.size() <= 30) showGridLines = pointDot = true; else if (histData.size() <= 366) showGridLines = true; else freq = histData.size() / 366; std::vector<LineGraphData> aData; for (const auto& hist : histData) { if (dataCount % freq == 0) { LineGraphData val; val.xPos = mmGetDateForDisplay(hist.DATE); const wxDate dateDt = Model_StockHistory::DATE(hist); if (histData.size() <= 30) val.label = val.xPos; else if (precDateDt.IsValid() && dateDt.GetMonth() != precDateDt.GetMonth()) val.label = wxGetTranslation(dateDt.GetEnglishMonthName(dateDt.GetMonth())); else val.label = ""; val.amount = hist.VALUE; aData.push_back(val); precDateDt = dateDt; } dataCount++; } if (!aData.empty()) { hb.addDivRow(); Model_Account::Data* account = Model_Account::instance().get(stock.HELDAT); hb.addHeader(1, wxString::Format("%s - (%s)", stock.STOCKNAME, account->ACCOUNTNAME)); hb.addDivCol17_67(); hb.addLineChart(aData, stock.STOCKNAME, 0, 1000, 400, pointDot, showGridLines); hb.endDiv(); hb.endDiv(); } } hb.endDiv(); hb.end(); return hb.getHTMLText(); }