예제 #1
0
        private static void WriteRow(IReportWriter writer, bool header, bool addExpanderCell, string name, IEnumerable <string> values)
        {
            if (header)
            {
                writer.StartHeaderRow();
            }
            else
            {
                writer.StartRow();
            }

            if (addExpanderCell)
            {
                writer.StartCell();
                writer.EndCell();
            }

            writer.StartCell();
            writer.WriteParagraph(name);
            writer.EndCell();

            foreach (string v in values)
            {
                writer.StartCell();

                if (!string.IsNullOrEmpty(v))
                {
                    writer.WriteNumber(v);
                }

                writer.EndCell();
            }

            writer.EndRow();
        }
예제 #2
0
        private void WriteCapitalGainsTotal(IReportWriter writer, decimal total)
        {
            writer.StartHeaderRow();
            writer.StartCell();
            writer.WriteParagraph("Total");
            writer.EndCell();

            writer.StartCell();
            writer.EndCell();

            writer.StartCell();
            writer.EndCell();

            writer.StartCell();
            writer.EndCell();

            writer.StartCell();
            writer.EndCell();

            writer.StartCell();
            writer.EndCell();

            writer.StartCell();
            writer.EndCell();

            writer.StartCell();
            writer.EndCell();

            writer.StartCell();
            writer.WriteNumber(GiveUpTheFractionalPennies(total).ToString("C"));
            writer.EndCell();

            writer.EndRow();
        }
예제 #3
0
 private static void WriteHeader(IReportWriter writer, string caption)
 {
     writer.StartHeaderRow();
     writer.StartCell(1, 2);
     writer.WriteParagraph(caption);
     writer.EndCell();
     writer.EndRow();
 }
예제 #4
0
        public void Generate(IReportWriter writer)
        {
            writer.WriteHeading("Unaccepted Transactions");

            Transactions transactions = myMoney.Transactions;

            foreach (Account a in this.myMoney.Accounts.GetAccounts(true))
            {
                if (a.IsClosed)
                {
                    continue;
                }

                bool first = true;

                foreach (Transaction t in this.myMoney.Transactions.GetTransactionsFrom(a))
                {
                    if (t.Unaccepted)
                    {
                        if (first)
                        {
                            writer.EndTable();
                            writer.WriteHeading(a.Name);
                            writer.StartTable();

                            writer.StartColumnDefinitions();
                            foreach (double minWidth in new double[] { 100, 300, 120 })
                            {
                                writer.WriteColumnDefinition(minWidth.ToString(), minWidth, double.MaxValue);
                            }
                            writer.EndColumnDefinitions();

                            writer.StartHeaderRow();
                            foreach (string header in new string[] { "Date", "Payee/Category/Memo", "Amount", })
                            {
                                writer.StartCell();
                                writer.WriteParagraph(header);
                                writer.EndCell();
                            }
                            writer.EndRow();

                            first = false;
                        }
                        WriteRow(writer, t.Date.ToShortDateString(), t.PayeeName ?? string.Empty, t.Amount.ToString("C"));
                        WriteRow(writer, string.Empty, t.CategoryName ?? string.Empty, string.Empty);
                        WriteRow(writer, string.Empty, t.Memo ?? string.Empty, string.Empty);
                    }
                }
            }

            writer.EndTable();

            writer.WriteParagraph("Generated on " + DateTime.Today.ToLongDateString(), System.Windows.FontStyles.Italic, System.Windows.FontWeights.Normal, System.Windows.Media.Brushes.Gray);
        }
예제 #5
0
        private void WriteRow(IReportWriter writer, bool header, bool addExpanderCell, string name, IEnumerable <CashFlowCell> cells)
        {
            if (header)
            {
                writer.StartHeaderRow();
            }
            else
            {
                writer.StartRow();
            }

            if (addExpanderCell)
            {
                writer.StartCell();
                writer.EndCell();
            }

            writer.StartCell();
            writer.WriteParagraph(name);
            writer.EndCell();

            foreach (CashFlowCell cell in cells)
            {
                writer.StartCell();

                if (cell.Value != 0)
                {
                    writer.WriteNumber(cell.Value.ToString("N0"));

                    if (cell.Data.Count > 0)
                    {
                        FlowDocumentReportWriter fw = (FlowDocumentReportWriter)writer;
                        Paragraph p = fw.CurrentParagraph;
                        p.Tag = cell;
                        p.PreviewMouseLeftButtonDown += OnReportCellMouseDown;
                        p.Cursor = Cursors.Arrow;
                        //p.TextDecorations.Add(TextDecorations.Underline);
                        //p.Foreground = Brushes.DarkSlateBlue;
                        p.SetResourceReference(Paragraph.ForegroundProperty, "HyperlinkForeground");
                    }
                }

                writer.EndCell();
            }

            writer.EndRow();
        }
예제 #6
0
 private void WriteHeaderRow(IReportWriter writer, String col1, String col2, String col3)
 {
     writer.StartHeaderRow();
     writer.StartCell(1, 2);
     writer.WriteParagraph(col1);
     writer.EndCell();
     writer.StartCell();
     writer.WriteNumber(col2);
     writer.EndCell();
     writer.StartCell();
     if (col3 != null)
     {
         writer.WriteNumber(col3);
         writer.EndCell();
     }
     writer.EndRow();
 }
예제 #7
0
        private static void WriteRowHeaders(IReportWriter writer)
        {
            writer.StartHeaderRow();
            writer.StartCell();
            // optional expander button.
            writer.EndCell();

            writer.StartCell();
            writer.WriteParagraph("Date Acquired");
            writer.EndCell();

            writer.StartCell();
            writer.WriteParagraph("Description");
            writer.EndCell();

            writer.StartCell();
            writer.WriteNumber("Quantity");
            writer.EndCell();

            writer.StartCell();
            writer.WriteNumber("Price");
            writer.EndCell();

            writer.StartCell();
            writer.WriteNumber("Market Value");
            writer.EndCell();

            writer.StartCell();
            writer.WriteNumber("Unit Cost");
            writer.EndCell();

            writer.StartCell();
            writer.WriteNumber("Cost Basis");
            writer.EndCell();

            writer.StartCell();
            writer.WriteNumber("Gain/Loss");
            writer.EndCell();

            writer.StartCell();
            writer.WriteNumber("%");
            writer.EndCell();
            writer.EndRow();
        }
예제 #8
0
        void WriteHeaders(IReportWriter writer)
        {
            writer.StartTable();
            writer.StartColumnDefinitions();
            for (int i = 0; i < 9; i++)
            {
                writer.WriteColumnDefinition("Auto", 100, double.MaxValue);
            }
            writer.EndColumnDefinitions();

            writer.StartHeaderRow();
            writer.StartCell();
            writer.WriteParagraph("Security");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber("Quantity");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber("Date Acquired");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber("Acquisition Price");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber("Cost Basis");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber("Date Sold");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber("Sale Price");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber("Proceeds");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber("Gain or Loss");
            writer.EndCell();
            writer.EndRow();
        }
예제 #9
0
        public void Generate(IReportWriter writer)
        {
            flowwriter = writer as FlowDocumentReportWriter;

            calc = new CostBasisCalculator(this.myMoney, this.reportDate);

            string heading = "Investment Portfolio Summary";

            if (this.account != null)
            {
                heading += " for " + account.Name + " (" + account.AccountId + ")";
            }

            writer.WriteHeading(heading);

            if (reportDate.Date != DateTime.Today)
            {
                writer.WriteSubHeading("As of " + reportDate.Date.AddDays(-1).ToLongDateString());
            }

            totalMarketValue = 0;
            totalGainLoss    = 0;

            // outer table contains 2 columns, left is the summary table, right is the pie chart.
            writer.StartTable();
            writer.StartColumnDefinitions();
            writer.WriteColumnDefinition("Auto", 100, double.MaxValue);
            writer.WriteColumnDefinition("Auto", 100, double.MaxValue);
            writer.EndColumnDefinitions();
            writer.StartRow();
            writer.StartCell();

            writer.StartTable();
            writer.StartColumnDefinitions();

            foreach (double minWidth in new double[] { 300, 100, 100 })
            {
                writer.WriteColumnDefinition("Auto", minWidth, double.MaxValue);
            }
            writer.EndColumnDefinitions();
            writer.StartHeaderRow();
            writer.StartCell();
            writer.WriteParagraph("Security Type");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber("Market Value");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber("Gain/Loss");
            writer.EndCell();
            writer.EndRow();

            List <SecurityPieData> data = new List <SecurityPieData>();

            decimal cash = this.myMoney.GetInvestmentCashBalance(account);

            if (cash > 0)
            {
                writer.StartRow();
                writer.StartCell();
                writer.WriteParagraph("Cash");
                writer.EndCell();
                writer.StartCell();
                writer.WriteNumber(cash.ToString("C"));
                writer.EndCell();
                writer.EndRow();

                data.Add(new SecurityPieData()
                {
                    Total = RoundToNearestCent(cash),
                    Name  = "Cash"
                });
            }

            totalMarketValue += cash;

            if (account == null)
            {
                WriteSummary(writer, data, "Tax Deferred ", new Predicate <Account>((a) => { return(a.IsTaxDeferred); }));
                WriteSummary(writer, data, "", new Predicate <Account>((a) => { return(!a.IsTaxDeferred); }));
            }
            else
            {
                WriteSummary(writer, data, "", new Predicate <Account>((a) => { return(a == account); }));
            }

            writer.StartHeaderRow();
            writer.StartCell();
            writer.WriteParagraph("Total");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber(totalMarketValue.ToString("C"));
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber(totalGainLoss.ToString("C"));
            writer.EndCell();
            writer.EndRow();
            writer.EndTable();

            writer.EndCell();
            // pie chart
            Chart chart = new Chart();

            chart.MinWidth            = 400;
            chart.MinHeight           = 300;
            chart.BorderThickness     = new Thickness(0);
            chart.Padding             = new Thickness(0);
            chart.Margin              = new Thickness(0, 00, 0, 0);
            chart.VerticalAlignment   = VerticalAlignment.Top;
            chart.HorizontalAlignment = HorizontalAlignment.Left;

            PieSeries series = new PieSeries();

            series.IndependentValueBinding = new Binding("Name");
            series.DependentValueBinding   = new Binding("Total");
            chart.Series.Add(series);
            series.ItemsSource = data;

            writer.StartCell();
            writer.WriteElement(chart);
            writer.EndCell();

            // end the outer table.
            writer.EndTable();

            totalMarketValue = 0;
            totalGainLoss    = 0;

            List <SecuritySale> errors = new List <SecuritySale>(calc.GetPendingSales(new Predicate <Account>((a) => { return(a == account); })));

            if (errors.Count > 0)
            {
                writer.WriteSubHeading("Pending Sales");

                foreach (var sp in errors)
                {
                    writer.WriteParagraph(string.Format("Pending sale of {1} units of '{2}' from account '{0}' recorded on {3}", sp.Account.Name, sp.UnitsSold, sp.Security.Name, sp.DateSold.ToShortDateString()));
                }
            }


            if (account == null)
            {
                WriteDetails(writer, "Tax Deferred ", new Predicate <Account>((a) => { return(a.IsTaxDeferred); }));
                WriteDetails(writer, "", new Predicate <Account>((a) => { return(!a.IsTaxDeferred); }));
            }
            else
            {
                WriteDetails(writer, "", new Predicate <Account>((a) => { return(a == account); }));
            }
        }
예제 #10
0
        private void WriteRow(IReportWriter writer, bool expandable, bool header, FontWeight weight, DateTime?aquired, string description, string descriptionUrl, decimal?quantity, decimal?price, decimal marketValue, decimal?unitCost, decimal costBasis, decimal gainLoss)
        {
            if (header)
            {
                writer.StartHeaderRow();
            }
            else
            {
                writer.StartRow();
            }

            if (expandable)
            {
                writer.StartCell();
                writer.EndCell();
            }

            writer.StartCell();
            if (aquired.HasValue)
            {
                writer.WriteParagraph(aquired.Value.ToShortDateString(), FontStyles.Normal, weight, null);
            }
            writer.EndCell();

            writer.StartCell();
            writer.WriteParagraph(description, FontStyles.Normal, weight, null);
            if (!string.IsNullOrEmpty(descriptionUrl))
            {
                FlowDocumentReportWriter fw = (FlowDocumentReportWriter)writer;
                Paragraph p = fw.CurrentParagraph;
                p.Tag = descriptionUrl;
                p.PreviewMouseLeftButtonDown += OnReportCellMouseDown;
                p.Cursor = Cursors.Arrow;
                //p.TextDecorations.Add(TextDecorations.Underline);
                p.SetResourceReference(Paragraph.ForegroundProperty, "HyperlinkForeground");
            }
            writer.EndCell();

            writer.StartCell();
            if (quantity.HasValue)
            {
                writer.WriteNumber(quantity.Value.ToString("N2"));
            }
            writer.EndCell();

            writer.StartCell();
            if (price.HasValue)
            {
                writer.WriteNumber(price.Value.ToString("N2"));
            }
            writer.EndCell();

            writer.StartCell();
            writer.WriteNumber(marketValue.ToString("N2"));
            writer.EndCell();

            writer.StartCell();
            if (unitCost.HasValue)
            {
                writer.WriteNumber(unitCost.Value.ToString("N2"));
            }
            writer.EndCell();

            writer.StartCell();
            writer.WriteNumber(costBasis.ToString("N2"));
            writer.EndCell();

            writer.StartCell();
            writer.WriteNumber(gainLoss.ToString("N2"));
            writer.EndCell();

            writer.StartCell();
            decimal percent = costBasis == 0 ? 0 : (gainLoss / costBasis) * 100;

            writer.WriteNumber(percent.ToString("N0"));
            writer.EndCell();

            writer.EndRow();
        }
예제 #11
0
 private void WriteheaderRow(IReportWriter writer, String col1, String col2, String col3)
 {
     writer.StartHeaderRow();
     WriteSummaryRow(writer, col1, col2, col3);
 }
예제 #12
0
        private void GenerateCategories(IReportWriter writer)
        {
            TaxCategoryCollection taxCategories = new TaxCategoryCollection();
            List <TaxCategory>    list          = taxCategories.GenerateGroups(money, this.startDate, this.endDate);

            if (list == null)
            {
                writer.WriteParagraph("You have not associated any categories with tax categories.");
                writer.WriteParagraph("Please use the Category Properties dialog to associate tax categories then try again.");
                return;
            }

            writer.WriteHeading("Tax Categories");
            writer.StartTable();

            writer.StartColumnDefinitions();
            writer.WriteColumnDefinition("auto", 100, double.MaxValue);
            writer.WriteColumnDefinition("auto", 100, double.MaxValue);
            writer.WriteColumnDefinition("auto", 100, double.MaxValue);
            writer.EndColumnDefinitions();
            writer.StartHeaderRow();
            writer.StartCell();
            writer.WriteParagraph("Category");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber("Amount");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber("Tax Excempt");
            writer.EndCell();
            writer.EndRow();

            decimal tax = GetSalesTax();

            writer.StartRow();
            writer.StartCell();
            writer.WriteParagraph("Sales Tax");
            writer.EndCell();
            writer.StartCell();
            writer.WriteNumber(tax.ToString("C"), FontStyles.Normal, FontWeights.Bold, null);
            writer.EndCell();
            writer.EndRow();

            foreach (TaxCategory tc in list)
            {
                writer.StartHeaderRow();
                writer.StartCell();
                writer.WriteParagraph(tc.Name);
                writer.EndCell();
                writer.StartCell();
                writer.EndCell();
                writer.EndRow();

                decimal sum = 0;
                IDictionary <string, List <Transaction> > groups = tc.Groups;
                foreach (KeyValuePair <string, List <Transaction> > subtotal in groups)
                {
                    writer.StartRow();
                    writer.StartCell();
                    writer.WriteParagraph(subtotal.Key);
                    writer.EndCell();

                    decimal value     = 0;
                    decimal taxExempt = 0;
                    foreach (Transaction t in subtotal.Value)
                    {
                        var amount = t.Amount;
                        if (t.Investment != null && t.Investment.Security != null && t.Investment.Security.Taxable == YesNo.No)
                        {
                            taxExempt += amount;
                        }
                        else
                        {
                            value += amount;
                        }
                    }

                    if (tc.DefaultSign < 0)
                    {
                        value = value * -1;
                    }

                    writer.StartCell();
                    writer.WriteNumber(value.ToString("C"));
                    writer.EndCell();

                    writer.StartCell();
                    if (taxExempt > 0)
                    {
                        writer.WriteNumber(taxExempt.ToString("C"));
                    }
                    writer.EndCell();
                    writer.EndRow();
                    sum += value;
                }

                writer.StartRow();
                writer.StartCell();
                writer.EndCell();
                writer.StartCell();
                writer.WriteNumber(sum.ToString("C"), FontStyles.Normal, FontWeights.Bold, null);
                writer.EndCell();
                writer.EndRow();
            }

            writer.EndTable();
        }
예제 #13
0
        private void GenerateCapitalGains(IReportWriter writer)
        {
            var calculator = new CapitalGainsTaxCalculator(this.money, this.endDate, this.consolidateOnDateSold, true);

            List <SecuritySale> errors = new List <SecuritySale>(from s in calculator.GetSales() where s.Error != null select s);

            if (errors.Count > 0)
            {
                writer.WriteHeading("Errors Found");
                foreach (SecuritySale error in errors)
                {
                    writer.WriteParagraph(error.Error.Message);
                }
            }

            if ((from u in calculator.Unknown where InRange(u.DateSold) select u).Any())
            {
                writer.WriteHeading("Capital Gains with Unknown Cost Basis");

                writer.StartTable();
                writer.StartColumnDefinitions();
                for (int i = 0; i < 4; i++)
                {
                    writer.WriteColumnDefinition("Auto", 100, double.MaxValue);
                }
                writer.EndColumnDefinitions();

                writer.StartHeaderRow();
                writer.StartCell();
                writer.WriteParagraph("Security");
                writer.EndCell();
                writer.StartCell();
                writer.WriteNumber("Quantity");
                writer.EndCell();
                writer.StartCell();
                writer.WriteNumber("Date Sold");
                writer.EndCell();
                writer.StartCell();
                writer.WriteNumber("Sale Price");
                writer.EndCell();
                writer.StartCell();
                writer.WriteNumber("Proceeds");
                writer.EndCell();
                writer.EndRow();

                foreach (var data in calculator.Unknown)
                {
                    if (!InRange(data.DateSold))
                    {
                        continue;
                    }
                    writer.StartRow();
                    writer.StartCell();
                    writer.WriteParagraph(data.Security.Name);
                    writer.EndCell();

                    writer.StartCell();
                    writer.WriteNumber(Rounded(data.UnitsSold, 3));
                    writer.EndCell();

                    writer.StartCell();
                    writer.WriteNumber(data.DateSold.ToShortDateString());
                    writer.EndCell();

                    writer.StartCell();
                    writer.WriteNumber(data.SalePricePerUnit.ToString("C"));
                    writer.EndCell();

                    writer.StartCell();
                    writer.WriteNumber(data.SaleProceeds.ToString("C"));
                    writer.EndCell();
                }

                writer.EndTable();
            }

            if (calculator.ShortTerm.Count > 0)
            {
                decimal total = 0;
                writer.WriteHeading("Short Term Capital Gains and Losses");
                WriteHeaders(writer);
                foreach (var data in calculator.ShortTerm)
                {
                    if (!InRange(data.DateSold))
                    {
                        continue;
                    }
                    WriteCapitalGains(writer, data);
                    total += data.TotalGain;
                }
                WriteCapitalGainsTotal(writer, total);
                writer.EndTable();
            }

            if (calculator.LongTerm.Count > 0)
            {
                decimal total = 0;
                writer.WriteHeading("Long Term Capital Gains and Losses");
                WriteHeaders(writer);
                foreach (var data in calculator.LongTerm)
                {
                    if (!InRange(data.DateSold))
                    {
                        continue;
                    }
                    WriteCapitalGains(writer, data);
                    total += data.TotalGain;
                }
                WriteCapitalGainsTotal(writer, total);
            }
            writer.EndTable();
        }
예제 #14
0
        public override void Generate(IReportWriter writer)
        {
            writer.WriteHeading("Budget Report");

            this.rows = new Dictionary <string, BudgetRow>();

            this.columns = new Dictionary <DateTime, BudgetColumn>();

            foreach (Category rc in money.Categories.GetRootCategories())
            {
                if (rc.Type != CategoryType.Expense)
                {
                    continue;
                }
                string rowHeader = rc.Name;
                this.CategoryFilter = rc;


                // Add column for the budget itself.
                BudgetColumn budgetColumn;
                if (!columns.TryGetValue(DateTime.MinValue, out budgetColumn))
                {
                    budgetColumn = new BudgetColumn()
                    {
                        Name = BudgetColumnHeader,
                    };
                    columns[DateTime.MinValue] = budgetColumn;
                }
                budgetColumn.Total += rc.Budget;

                foreach (BudgetData b in this.Compute())
                {
                    BudgetRow row = null;
                    if (!rows.TryGetValue(rowHeader, out row))
                    {
                        row = new BudgetRow()
                        {
                            Name   = rowHeader,
                            Budget = rc.Budget
                        };
                        rows[rowHeader] = row;
                    }

                    DateTime budgetDate = new DateTime(b.BudgetDate.Year, b.BudgetDate.Month, 1);
                    row.Actuals.Add((decimal)b.Actual);
                    row.Headers.Add(b.Name);

                    // Add column for this BudgetData
                    BudgetColumn col;
                    if (!columns.TryGetValue(budgetDate, out col))
                    {
                        col = new BudgetColumn()
                        {
                            Date = budgetDate,
                            Name = b.Name
                        };
                        columns[budgetDate] = col;
                    }
                    col.Total += (decimal)b.Actual;
                }
            }

            writer.StartTable();

            writer.StartColumnDefinitions();
            writer.WriteColumnDefinition("300", 300, 300); // category names
            foreach (var pair in from p in columns orderby p.Key select p)
            {
                writer.WriteColumnDefinition("Auto", 100, double.MaxValue); // decimal values.
            }
            writer.WriteColumnDefinition("Auto", 100, double.MaxValue);     // total.
            writer.EndColumnDefinitions();

            // write table headers
            List <string> master = new List <string>();

            writer.StartHeaderRow();
            writer.StartCell();
            writer.EndCell();
            foreach (var pair in from p in columns orderby p.Key select p)
            {
                BudgetColumn c    = pair.Value;
                string       name = c.Name;
                if (name != BudgetColumnHeader)
                {
                    master.Add(name); // list of all columns we have found (not including "Budget" column)
                }
                writer.StartCell();
                writer.WriteNumber(name);
                writer.EndCell();
            }
            writer.StartCell();
            writer.WriteNumber("Balance");
            writer.EndCell();
            writer.EndRow();

            Brush   overBudgetBrush = Brushes.Red;
            decimal totalBalance    = 0;

            // Now write out the rows.
            foreach (BudgetRow row in from r in rows.Values orderby r.Name select r)
            {
                writer.StartRow();
                writer.StartCell();
                writer.WriteParagraph(row.Name);
                writer.EndCell();

                writer.StartCell();
                decimal budget = row.Budget;
                writer.WriteNumber(budget.ToString("C"));
                writer.EndCell();

                decimal balance = 0;

                foreach (string col in master)
                {
                    writer.StartCell();
                    int i = row.Headers.IndexOf(col);
                    if (i >= 0)
                    {
                        decimal actual = row.Actuals[i];
                        writer.WriteNumber(actual.ToString("C"), FontStyles.Normal, FontWeights.Normal,
                                           actual > budget ? overBudgetBrush : null);

                        balance += (row.Budget - actual);
                    }
                    writer.EndCell();
                }

                totalBalance += balance;

                writer.StartCell();
                writer.WriteNumber(balance.ToString("C"));
                writer.EndCell();

                writer.EndRow();
            }

            // Now write out the totals.
            writer.StartHeaderRow();
            writer.StartCell();
            writer.EndCell();
            foreach (var pair in from p in columns orderby p.Key select p)
            {
                BudgetColumn c = pair.Value;
                writer.StartCell();
                writer.WriteNumber(c.Total.ToString("C"));
                writer.EndCell();
            }
            writer.StartCell();
            writer.WriteNumber(totalBalance.ToString("C"));
            writer.EndCell();

            writer.EndRow();

            writer.EndTable();

            writer.WriteParagraph("Generated on " + DateTime.Today.ToLongDateString(), System.Windows.FontStyles.Italic, System.Windows.FontWeights.Normal, System.Windows.Media.Brushes.Gray);
        }