private static FinancialAccountRows RowsNotInVatReport(FinancialAccounts accounts, DateTime endTime) { FinancialAccountRows result = new FinancialAccountRows(); result.AddRange(accounts.SelectMany(account => RowsNotInVatReport(account, endTime))); return(result); }
public static FinancialAccountRows ForOrganization(Organization organization, DateTime fromDate, DateTime toDate) { FinancialAccounts orgAccounts = FinancialAccounts.ForOrganization(organization); orgAccounts.GetRows(fromDate, toDate); return (FromArray(SwarmDb.GetDatabaseForReading() .GetFinancialAccountRows(orgAccounts.Identities, fromDate, toDate, false))); }
private void PopulateOrderedList(FinancialAccounts orderedList, int renderNodeId) { foreach (FinancialAccount account in this._treeMap[renderNodeId]) { orderedList.Add(account); if (this._treeMap.ContainsKey(account.Identity)) { PopulateOrderedList(orderedList, account.Identity); // recursive call } } }
private void AddChildrenValuesToParents(Dictionary <int, Int64> lookup, FinancialAccounts accounts) { // Iterate backwards and add any value to its parent's value, as they are sorted in tree order. for (int index = accounts.Count - 1; index >= 0; index--) { int parentFinancialAccountId = accounts[index].ParentFinancialAccountId; int accountId = accounts[index].Identity; if (parentFinancialAccountId != 0) { lookup[parentFinancialAccountId] += lookup[accountId]; } } }
public FinancialAccounts ThisAndBelow() { return(FinancialAccounts.ThisAndBelow(this)); }
public FinancialAccounts GetTree() { return(FinancialAccounts.GetTree(this)); }
private void AddVatReportItemsFromAccountRows(FinancialAccountRows rows, Dictionary <int, bool> transactionsIncludedLookup) { if (rows.Count == 0) { return; } Organization organization = rows[0].Transaction.Organization; // there is always a rows[0] because check above int vatInboundAccountId = organization.FinancialAccounts.AssetsVatInboundUnreported.Identity; int vatOutboundAccountId = organization.FinancialAccounts.DebtsVatOutboundUnreported.Identity; Dictionary <int, bool> turnoverAccountLookup = new Dictionary <int, bool>(); FinancialAccounts turnoverAccounts = FinancialAccounts.ForOrganization(organization, FinancialAccountType.Income); foreach (FinancialAccount turnoverAccount in turnoverAccounts) { turnoverAccountLookup[turnoverAccount.Identity] = true; } foreach (FinancialAccountRow accountRow in rows) { FinancialTransaction tx = accountRow.Transaction; if (tx.Dependency is VatReport) { continue; // Never include previous VAT reports in new VAT reports } if (!transactionsIncludedLookup.ContainsKey(tx.Identity)) { Int64 vatInbound = 0; Int64 vatOutbound = 0; Int64 turnOver = 0; transactionsIncludedLookup[accountRow.FinancialTransactionId] = true; FinancialTransactionRows txRows = accountRow.Transaction.Rows; foreach (FinancialTransactionRow txRow in txRows) { if (txRow.FinancialAccountId == vatInboundAccountId) { vatInbound += txRow.AmountCents; } else if (txRow.FinancialAccountId == vatOutboundAccountId) { vatOutbound += -txRow.AmountCents; // this is a negative, so converting to positive } else if (turnoverAccountLookup.ContainsKey(txRow.FinancialAccountId)) { turnOver -= txRow.AmountCents; // turnover accounts are sign reversed, so convert to positive } } // Add new row to the VAT report AddItem(tx, turnOver, vatInbound, vatOutbound); } } }
private void PopulateLookups(FinancialAccounts accounts) { // Seven elements in each array: lastyear, q1, q2, q3, q4, thisyear, thisyearbudget this._singleLookups = new Dictionary <int, Int64> [7]; this._treeLookups = new Dictionary <int, Int64> [7]; for (int index = 0; index < 7; index++) { this._treeLookups[index] = new Dictionary <int, Int64>(); this._singleLookups[index] = new Dictionary <int, Int64>(); } DateTime[] quarterBoundaries = { new DateTime(this.Year, 1, 1), new DateTime(this.Year, 4, 1), new DateTime(this.Year, 7, 1), new DateTime(this.Year, 10, 1), new DateTime(this.Year + 1, 1, 1) }; // 1) Actually, the accounts are already sorted. Or are supposed to be, anyway, // since FinancialAccounts.ForOrganization gets the _tree_ rather than the flat list. // 2) Add all values to the accounts. foreach (FinancialAccount account in accounts) { // If result account, find budget if (this._accountType == FinancialAccountType.Result) { this._singleLookups[6][account.Identity] = account.GetBudgetCents(this.Year); } else { this._singleLookups[6][account.Identity] = 0; // if balance account, this is zero } // Find this year's inbound if (this._accountType == FinancialAccountType.Result) { this._singleLookups[0][account.Identity] = account.GetDeltaCents( new DateTime(this.Year - 1, 1, 1), new DateTime(this.Year, 1, 1)); } else if (this._accountType == FinancialAccountType.Balance) { this._singleLookups[0][account.Identity] = account.GetDeltaCents(new DateTime(1900, 1, 1), new DateTime(this.Year, 1, 1)); } else { throw new InvalidOperationException( "Can only calculate yearly reports for balance or P&L statements"); } // Find quarter diffs for (int quarter = 0; quarter < 4; quarter++) { this._singleLookups[quarter + 1][account.Identity] = account.GetDeltaCents(quarterBoundaries[quarter], quarterBoundaries[quarter + 1]); } // Find outbound if (this._accountType == FinancialAccountType.Result) { this._singleLookups[5][account.Identity] = account.GetDeltaCents(new DateTime(this.Year, 1, 1), new DateTime(this.Year + 1, 1, 1)); } else if (this._accountType == FinancialAccountType.Balance) { this._singleLookups[5][account.Identity] = account.GetDeltaCents(new DateTime(1900, 1, 1), new DateTime(this.Year + 1, 1, 1)); } else { throw new InvalidOperationException( "Can only calculate yearly reports for balance or P&L statements"); } // copy to treeLookups for (int index = 0; index < 7; index++) { this._treeLookups[index][account.Identity] = this._singleLookups[index][account.Identity]; } } // 3) Add all children's values to parents for (int index = 0; index < 7; index++) { AddChildrenValuesToParents(this._treeLookups[index], accounts); } // Done. }
public static AnnualReport Create(Organization organization, int year, FinancialAccountType accountType) { AnnualReport report = new AnnualReport(); report.Organization = organization; report.Year = year; report._accountType = accountType; // Get accounts FinancialAccounts accounts = FinancialAccounts.ForOrganization(organization, accountType); // Remove unwanted accounts FinancialAccount resultsAccount = organization.FinancialAccounts.CostsYearlyResult; foreach (FinancialAccount account in accounts) { // For now, just remove the "results" account. TODO: Remove inactive accounts, too. if (account.Identity == resultsAccount.Identity) { accounts.Remove(account); break; } } // Build tree (there should be a template for this) report._treeMap = new Dictionary <int, List <FinancialAccount> >(); foreach (FinancialAccount account in accounts) { if (!report._treeMap.ContainsKey(account.ParentIdentity)) { report._treeMap[account.ParentIdentity] = new List <FinancialAccount>(); } report._treeMap[account.ParentIdentity].Add(account); } FinancialAccounts orderedList = new FinancialAccounts(); // This list is guaranteed to have parents before children report.PopulateOrderedList(orderedList, 0); // recursively add nodes parents-first report.PopulateLookups(orderedList); // populate the lookup tables for results per account report.PopulateTotals(); report.ReportLines = new List <AnnualReportLine>(); report.RecurseAddLines(report.ReportLines, 0); // Aggregate accounts, if appropriate if (report._treeMap[0].Count > 3) { // regroup list report.AggregateAccounts(); } return(report); }
public static VatReport Create(Organization organization, int year, int startMonth, int monthCount) { VatReport newReport = CreateDbRecord(organization, year, startMonth, monthCount); DateTime endDate = new DateTime(year, startMonth, 1).AddMonths(monthCount); FinancialAccount vatInbound = organization.FinancialAccounts.AssetsVatInboundUnreported; FinancialAccount vatOutbound = organization.FinancialAccounts.DebtsVatOutboundUnreported; FinancialAccount sales = organization.FinancialAccounts.IncomeSales; FinancialAccounts salesTree = sales.ThisAndBelow(); FinancialAccountRows inboundRows = RowsNotInVatReport(vatInbound, endDate); FinancialAccountRows outboundRows = RowsNotInVatReport(vatOutbound, endDate); FinancialAccountRows turnoverRows = RowsNotInVatReport(salesTree, endDate); Dictionary <int, bool> transactionsIncludedLookup = new Dictionary <int, bool>(); newReport.AddVatReportItemsFromAccountRows(inboundRows, transactionsIncludedLookup); newReport.AddVatReportItemsFromAccountRows(outboundRows, transactionsIncludedLookup); newReport.AddVatReportItemsFromAccountRows(turnoverRows, transactionsIncludedLookup); newReport.Release(); // Create financial TX that moves this VAT from unreported to reported Int64 differenceCents = newReport.VatInboundCents - newReport.VatOutboundCents; if (differenceCents != 0 && newReport.VatInboundCents > 0) { // if there's anything to report FinancialTransaction vatReportTransaction = FinancialTransaction.Create(organization, endDate.AddDays(4).AddHours(9), newReport.Description); if (newReport.VatInboundCents > 0) { vatReportTransaction.AddRow(organization.FinancialAccounts.AssetsVatInboundUnreported, -newReport.VatInboundCents, null); } if (newReport.VatOutboundCents > 0) { vatReportTransaction.AddRow(organization.FinancialAccounts.DebtsVatOutboundUnreported, newReport.VatOutboundCents, null); // not negative, because our number is sign-different from the bookkeeping's } if (differenceCents < 0) // outbound > inbound { vatReportTransaction.AddRow(organization.FinancialAccounts.DebtsVatOutboundReported, differenceCents, null); // debt, so negative as in our variable } else // inbound > outbound { vatReportTransaction.AddRow(organization.FinancialAccounts.AssetsVatInboundReported, differenceCents, null); // asset, so positive as in our variable } vatReportTransaction.Dependency = newReport; newReport.OpenTransaction = vatReportTransaction; } else { newReport.Open = false; // nothing to close, no tx created } return(newReport); }