Created beginnings of the CSV output for the General Ledger report.
[bkuhn:small-hacks.git] / general-ledger-report.plx
1 #!/usr/bin/perl
2 # general-ledger-report.plx                                    -*- Perl -*-
3 #
4 #    Script to generate a General Ledger report that accountants like
5 #    using Ledger.
6 #
7 # Copyright (C) 2011, Bradley M. Kuhn
8 #
9 # This program gives you software freedom; you can copy, modify, convey,
10 # and/or redistribute it under the terms of the GNU General Public License
11 # as published by the Free Software Foundation; either version 3 of the
12 # License, or (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 # General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License along
20 # with this program in a file called 'GPLv3'.  If not, write to the:
21 #    Free Software Foundation, Inc., 51 Franklin St, Fifth Floor
22 #                                    Boston, MA 02110-1301, USA.
23
24 use strict;
25 use warnings;
26
27 use Math::BigFloat;
28 use Date::Manip;
29
30 my $LEDGER_CMD = "/usr/bin/ledger";
31
32 my $ACCT_WIDTH = 75;
33
34 sub ParseNumber($) {
35   $_[0] =~ s/,//g;
36   return Math::BigFloat->new($_[0]);
37 }
38
39 Math::BigFloat->precision(-2);
40 my $ZERO =  Math::BigFloat->new("0.00");
41
42 if (@ARGV < 2) {
43   print STDERR "usage: $0 <BEGIN_DATE> <END_DATE> <OTHER_LEDGER_OPTS>\n";
44   exit 1;
45 }
46
47 my($beginDate, $endDate, @otherLedgerOpts) = @ARGV;
48
49 my(@chartOfAccountsOpts) = ('--wide-register-format', "%150A\n",  '-w', '-s',
50                             '-e', $endDate, @otherLedgerOpts, 'reg');
51
52 open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts)
53   or die "Unable to run $LEDGER_CMD @chartOfAccountsOpts: $!";
54
55 open(CHART_OUTPUT, ">", "chart-of-accounts.txt") or die "unable to write chart-of-accounts.txt: $!";
56
57 my @accounts;
58 while (my $line = <CHART_DATA>) {
59   chomp $line;
60   $line =~ s/^\s*//;   $line =~ s/\s*$//;
61   push(@accounts, $line);
62
63 }
64 close(CHART_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0;
65
66 open(CHART_OUTPUT, ">", "chart-of-accounts.txt") or die "unable to write chart-of-accounts.txt: $!";
67
68 my @sortedAccounts;
69 foreach my $acct (
70                   # Proper sorting for a chart of accounts
71                   sort {
72                     if ($a =~ /^Assets/ and $b !~ /^Assets/) {
73                       return -1;
74                     } elsif ($a =~ /^Liabilities/ and $b !~ /^Liabilitie/) {
75                       return -1;
76                     } else {
77                       return $a cmp $b;
78                     }
79                     } @accounts) {
80   print CHART_OUTPUT "$acct\n";
81   push(@sortedAccounts, $acct);
82 }
83 close(CHART_OUTPUT); die "error writing to chart-of-accounts.txt: $!" unless $? == 0;
84
85 my $formattedEndDate = new Date::Manip::Date;
86 die "badly formatted end date, $endDate" if $formattedEndDate->parse($endDate);
87 my $oneDayLess = new Date::Manip::Delta;
88 die "bad one day less" if $oneDayLess->parse("- 1 day");
89 $formattedEndDate = $formattedEndDate->calc($oneDayLess);
90 $formattedEndDate = $formattedEndDate->printf("%Y/%m/%d");
91
92 open(GL_TEXT_OUT, ">", "general-ledger.txt") or die "unable to write general-ledger.txt: $!";
93 open(GL_CSV_OUT, ">", "general-ledger.csv") or die "unable to write general-ledger.csv: $!";
94
95 foreach my $acct (@sortedAccounts) {
96   print GL_TEXT_OUT "\n\nACCOUNT: $acct\nFROM:    $beginDate TO $formattedEndDate\n\n";
97   my @acctLedgerOpts = ('--wide-register-format',
98                         "%D  %-.10C   %-.80P  %-.80N  %18t  %18T\n", '-w',
99                         '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct);
100   open(GL_TEXT_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts)
101     or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!";
102
103   foreach my $line (<GL_TEXT_DATA>) {
104     print GL_TEXT_OUT $line;
105   }
106   close(GL_TEXT_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0;
107
108   print GL_CSV_OUT "ACCOUNT,$acct\nPERIOD START,$beginDate,PERIOD END,$formattedEndDate\n\n";
109   @acctLedgerOpts = ('--wide-register-format',
110                      "%D,%-.10C,%-.100P,%-.200N,%18t,%18T\n", '-w',
111                         '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct);
112   open(GL_CSV_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts)
113     or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!";
114
115   foreach my $line (<GL_CSV_DATA>) {
116     print GL_CSV_OUT $line;
117   }
118   close(GL_CSV_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0;
119 }
120 close(GL_TEXT_OUT); die "error writing to general-ledger.txt: $!" unless $? == 0;
121 close(GL_CSV_OUT); die "error writing to general-ledger.csv: $!" unless $? == 0;
122 ###############################################################################
123 #
124 # Local variables:
125 # compile-command: "perl -c general-ledger-report.plx"
126 # End:
127