// Generate reports to output directory. func (report *Report) Generate(outputDir string) error { var buf bytes.Buffer var filename string switch report.period { case ReportPeriodInfinite: fmt.Fprintf(&buf, "All transactions\n\n") filename = filepath.Join(outputDir, "all.txt") case ReportPeriodYearly: fmt.Fprintf(&buf, "%d\n\n", report.from.Year()) filename = filepath.Join(outputDir, fmt.Sprintf("%d.txt", report.from.Year())) case ReportPeriodQuarterly: quarterName := fmt.Sprintf("Q%d", (report.from.Month()-1)/3+1) fmt.Fprintf(&buf, "%s %d\n\n", quarterName, report.from.Year()) filename = filepath.Join(outputDir, fmt.Sprintf("%d-%s.txt", report.from.Year(), quarterName)) case ReportPeriodMonthly: fmt.Fprintf(&buf, "%s %d\n\n", report.from.Month(), report.from.Year()) filename = filepath.Join(outputDir, fmt.Sprintf("%d-%02d.txt", report.from.Year(), report.from.Month())) default: return fmt.Errorf("unsupported report period %d", report.period) } file, err := os.Create(filename) if err != nil { return err } defer file.Close() var accounts []*Account for _, account := range report.accounts { accounts = append(accounts, account) } sort.Sort(sortByAccountName(accounts)) // Account summary t := new(table.Table) t.SetTitles(table.Row{ {Content: "account"}, {Content: "amount"}, {Content: "cumulative"}, {Content: "delta"}, }) for _, account := range accounts { cumulativeStr := balanceToString(account.CumulativeBalance()) deltaStr := fmt.Sprintf("%+.2f", report.AccountDelta(account.name)) if cumulativeStr != "-" || deltaStr != "+0.00" { t.AddRow(table.Row{ {Content: account.name.Leaf(), PadLeft: uint(indentAmount * account.name.Depth())}, {Content: balanceToString(account.FlatBalance()), Align: table.AlignRight}, {Content: cumulativeStr, Align: table.AlignRight}, {Content: deltaStr, Align: table.AlignRight}, }) } } buf.Write(t.RenderText()) // Transaction log fmt.Fprintf(&buf, "\nTransactions\n\n") t = new(table.Table) t.SetTitles(table.Row{ {Content: "date"}, {Content: "account"}, {Content: "debit"}, {Content: "credit"}, }) var prevDate time.Time for _, tr := range report.transactions { var dateStr string if tr.date != prevDate { dateStr = tr.date.Format(transactionDateFormat) } prevDate = tr.date t.AddRow(table.Row{ {Content: dateStr}, {Content: string(tr.accounts[Dr])}, {Content: fmt.Sprintf("%.2f", tr.amount), Align: table.AlignRight}, {Content: ""}, }) t.AddRow(table.Row{ {Content: ""}, {Content: string(tr.accounts[Cr])}, {Content: ""}, {Content: fmt.Sprintf("%.2f", tr.amount), Align: table.AlignRight}, }) } buf.Write(t.RenderText()) fmt.Fprintf(file, "%s", buf.Bytes()) return nil }