예제 #1
0
        private static FinancialAccountRows RowsNotInVatReport(FinancialAccounts accounts, DateTime endTime)
        {
            FinancialAccountRows result = new FinancialAccountRows();

            result.AddRange(accounts.SelectMany(account => RowsNotInVatReport(account, endTime)));

            return(result);
        }
예제 #2
0
        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)));
        }
예제 #3
0
        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
                }
            }
        }
예제 #4
0
        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];
                }
            }
        }
예제 #5
0
 public FinancialAccounts ThisAndBelow()
 {
     return(FinancialAccounts.ThisAndBelow(this));
 }
예제 #6
0
 public FinancialAccounts GetTree()
 {
     return(FinancialAccounts.GetTree(this));
 }
예제 #7
0
        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);
                }
            }
        }
예제 #8
0
        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.
        }
예제 #9
0
        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);
        }
예제 #10
0
        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);
        }