From 287a756ab6c7072349dee8818e9775d67c8847be Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 21 Nov 2012 13:08:26 -0500 Subject: New test data for increasing the set of possible tags. I use more tags than just Invoice and Receipt, so I'd like this to support more than just two. Here's some test data showing other tags that I use. --- .../tests/Financial/BankStuff/bank-statement.pdf | Bin 0 -> 3257 bytes .../tests/Projects/Foo/earmark-record.txt | 1 + .../tests/non-profit-test-data.ledger | 4 +++- 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 contrib/non-profit-audit-reports/tests/Financial/BankStuff/bank-statement.pdf create mode 100644 contrib/non-profit-audit-reports/tests/Projects/Foo/earmark-record.txt (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/tests/Financial/BankStuff/bank-statement.pdf b/contrib/non-profit-audit-reports/tests/Financial/BankStuff/bank-statement.pdf new file mode 100644 index 00000000..27b40353 Binary files /dev/null and b/contrib/non-profit-audit-reports/tests/Financial/BankStuff/bank-statement.pdf differ diff --git a/contrib/non-profit-audit-reports/tests/Projects/Foo/earmark-record.txt b/contrib/non-profit-audit-reports/tests/Projects/Foo/earmark-record.txt new file mode 100644 index 00000000..c5ac98ac --- /dev/null +++ b/contrib/non-profit-audit-reports/tests/Projects/Foo/earmark-record.txt @@ -0,0 +1 @@ +I, Another J. Donor, would like $400 to be earmarked for Foo! diff --git a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger index 69aeb571..fb6134ff 100644 --- a/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger +++ b/contrib/non-profit-audit-reports/tests/non-profit-test-data.ledger @@ -5,8 +5,9 @@ Assets:Checking $100.00 -2011/03/15 A Later Donation to Project Foo +2011/03/15 Another J. Donor Income:Foo:Donation $-400.00 + ;Approval: Projects/Foo/earmark-record.txt Assets:Checking $400.00 2011/04/20 (1) Baz Hosting Services, LLC @@ -24,3 +25,4 @@ ;Receipt: Projects/Blah/Expenses/hosting/AprilHostingReceipt.pdf ;Invoice: Projects/Blah/Expenses/hosting/april-invoice.pdf Assets:Checking $-250.00 + ;Statement: Financial/BankStuff/bank-statement.pdf -- cgit v1.2.3 From 01dc0416b9262905e66887b29ccef31d2867b9df Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 21 Nov 2012 13:09:55 -0500 Subject: Support a broader set of possible tags to be placed into the spreadsheet. I've now made a hard-coded list of potential tags that are supported and will be linked to in the general ledger spreadsheet. This list should probably be in a configuration file of some sort eventually, rather than hard coded. Indeed, note that the hard-coding goes into two different scripts, and thus the lists could easily get out of sync. --- contrib/non-profit-audit-reports/csv2ods.py | 5 ++++- contrib/non-profit-audit-reports/general-ledger-report.plx | 12 ++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/csv2ods.py b/contrib/non-profit-audit-reports/csv2ods.py index f6150158..59571280 100755 --- a/contrib/non-profit-audit-reports/csv2ods.py +++ b/contrib/non-profit-audit-reports/csv2ods.py @@ -24,6 +24,9 @@ import sys, os, os.path, optparse import csv import ooolib2 +file_fields = [ 'Receipt', 'Invoice', 'Statement', 'Contract', 'PurchaseOrder', + 'Approval', 'Check', 'IncomeDistributionAnalysis', 'CurrencyRate' ] + def err(msg): print 'error: %s' % msg sys.exit(1) @@ -56,7 +59,7 @@ def csv2ods(csvname, odsname, verbose = False): if len(val) > 0 and val[0] == '$': doc.set_cell_value(col + 1, row, 'currency', val[1:]) else: - if ( (col == 5) and (val != 'Receipt') and len(val) > 0) or ( (col == 6) and (val != 'Invoice') and len(val) > 0): + if ((col >= 5) and (not val in file_fields) and len(val) > 0): linkrel = '../' + val # ../ means remove the name of the *.ods linkname = os.path.basename(val) # name is just the last component doc.set_cell_value(col + 1, row, 'link', (linkrel, linkname)) diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 5286d625..1c293db9 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -107,8 +107,16 @@ foreach my $acct (@sortedAccounts) { close(GL_TEXT_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; print GL_CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; - print GL_CSV_OUT '"DATE","CHECK NUM","NAME","TRANSACTION AMT","RUNNING TOTAL","Receipt","Invoice"', "\n"; - @acctLedgerOpts = ('-F', '"%(date)","%C","%P","%t","%T","%(tag(\'Receipt\'))","%(tag(\'Invoice\'))"\n', '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); + print GL_CSV_OUT '"DATE","CHECK NUM","NAME","TRANSACTION AMT","RUNNING TOTAL"'; + my $formatString = '"%(date)","%C","%P","%t","%T"'; + foreach my $tagField (qw/Receipt Invoice Statement Contract PurchaseOrder Approval Check IncomeDistributionAnalysis CurrencyRate/) { + print GL_CSV_OUT ',"', $tagField, '"'; + $formatString .= ',"%(tag(\'' . $tagField . '\'))"'; + } + $formatString .= "\n"; + print GL_CSV_OUT "\n"; + + @acctLedgerOpts = ('-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); open(GL_CSV_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; -- cgit v1.2.3 From b5316132d44a91ff664b39c194710f5f88051d74 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 21 Nov 2012 13:34:55 -0500 Subject: MANIFEST output file that indicates which files are mentioned in general-ledger. Due to reporting options given to ledger, not every file will be referenced by the general-ledger spreadsheet. The generated MANIFEST file now indicates which files were actually referenced in the general-ledger. The demo.sh script now uses this MANIFEST to create a zip file that contains only those files. --- contrib/non-profit-audit-reports/demo.sh | 4 +++- contrib/non-profit-audit-reports/general-ledger-report.plx | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/demo.sh b/contrib/non-profit-audit-reports/demo.sh index 6a9dcadf..a4b837a6 100755 --- a/contrib/non-profit-audit-reports/demo.sh +++ b/contrib/non-profit-audit-reports/demo.sh @@ -32,11 +32,13 @@ else exit 1 fi +echo general-ledger.ods >> MANIFEST + # create a portable zip file with the spreadsheet # and the linked artifacts echo creating portable zipfile... -zip -r ../general-ledger.zip general-ledger.ods Financial Projects -x '*.txt' +cat MANIFEST | zip -@ ../general-ledger.zip echo " " echo "created general-ledger.zip" diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 1c293db9..07f0b9da 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -44,6 +44,7 @@ if (@ARGV < 3) { print STDERR "usage: $0 \n"; exit 1; } +open(MANIFEST, ">", "MANIFEST") or die "Unable to open MANIFEST for writing: $!"; my($beginDate, $endDate, @otherLedgerOpts) = @ARGV; @@ -53,8 +54,6 @@ my(@chartOfAccountsOpts) = ('-F', "%150A\n", '-w', '-s', open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) or die "Unable to run $LEDGER_CMD @chartOfAccountsOpts: $!"; -open(CHART_OUTPUT, ">", "chart-of-accounts.txt") or die "unable to write chart-of-accounts.txt: $!"; - my @accounts; while (my $line = ) { chomp $line; @@ -65,6 +64,7 @@ while (my $line = ) { close(CHART_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; open(CHART_OUTPUT, ">", "chart-of-accounts.txt") or die "unable to write chart-of-accounts.txt: $!"; +print MANIFEST "chart-of-accounts.txt\n"; my @sortedAccounts; foreach my $acct ( @@ -91,7 +91,9 @@ $formattedEndDate = $formattedEndDate->calc($oneDayLess); $formattedEndDate = $formattedEndDate->printf("%Y/%m/%d"); open(GL_TEXT_OUT, ">", "general-ledger.txt") or die "unable to write general-ledger.txt: $!"; +print MANIFEST "general-ledger.txt\n"; open(GL_CSV_OUT, ">", "general-ledger.csv") or die "unable to write general-ledger.csv: $!"; +print MANIFEST "general-ledger.csv\n"; foreach my $acct (@sortedAccounts) { print GL_TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; @@ -122,6 +124,14 @@ foreach my $acct (@sortedAccounts) { foreach my $line () { print GL_CSV_OUT $line; + next if $line =~ /ACCOUNT:.*PERIOD/; # Skip column header lines + $line =~ s/^"[^"]*","[^"]*","[^"]*","[^"]*","[^"]*",//; + while ($line =~ s/^"([^"]*)"(,|$)//) { + my $file = $1; + next if $file =~ /^\s*$/; + warn "$file does not exist and/or is not readable" unless -r $file; + print MANIFEST "$file\n"; + } } close(GL_CSV_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; } -- cgit v1.2.3 From 6a3b25f85bd31ae8d7fdd55dd7f9a83a95d96e0d Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 1 Nov 2011 12:13:31 -0400 Subject: Began fund-report.plx, which started as a copy of trial-balance-report.plx. The revision history of trial-balance-report.plx can be found in the following location: http://gitorious.org/bkuhn/small-hacks/blobs/history/master/trial-balance-report.plx --- contrib/non-profit-audit-reports/fund-report.plx | 135 +++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100755 contrib/non-profit-audit-reports/fund-report.plx (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx new file mode 100755 index 00000000..e690b13b --- /dev/null +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -0,0 +1,135 @@ +#!/usr/bin/perl +# fund-report.plx -*- Perl -*- +# +# Script to generate a Trial Balance report for a ledger. +# +# Copyright (C) 2011, Bradley M. Kuhn +# +# This program gives you software freedom; you can copy, modify, convey, +# and/or redistribute it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program in a file called 'GPLv3'. If not, write to the: +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor +# Boston, MA 02110-1301, USA. + +use strict; +use warnings; + +use Math::BigFloat; + +my $LEDGER_CMD = "/usr/bin/ledger"; + +my $ACCT_WIDTH = 70; + +sub ParseNumber($) { + $_[0] =~ s/,//g; + return Math::BigFloat->new($_[0]); +} +Math::BigFloat->precision(-2); +my $ZERO = Math::BigFloat->new("0.00"); + +if (@ARGV < 2) { + print STDERR "usage: $0 \n"; + exit 1; +} + +my($startDate, $endDate, @mainLedgerOptions) = @ARGV; + +# First, get fund list from ending balance +my(@ledgerOptions) = (@mainLedgerOptions, + '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', + '-e', $endDate, 'reg', '^Funds:Restricted:'); + + +my %funds; + +open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) + or die "Unable to run $LEDGER_CMD for funds: $!"; + +while (my $fundLine = ) { + die "Unable to parse output line from funds command: $fundLine" + unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; + $funds{$account}{ending} = $amount; +} +close LEDGER_FUNDS; + +# First, get fund list from ending balance +@ledgerOptions = (@mainLedgerOptions, + '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', + '-e', $startDate, 'reg', '^Funds:Restricted:'); + +open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) + or die "Unable to run $LEDGER_CMD for funds: $!"; + +while (my $fundLine = ) { + die "Unable to parse output line from funds command: $fundLine" + unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; + $funds{$account}{starting} = $amount; +} +close LEDGER_FUNDS; + + +foreach my $fund (keys %funds) { + $funds{$fund}{starting} = $ZERO if not defined $funds{$fund}{starting}; +} + +@ledgerOptions = (@mainLedgerOptions, + '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', + '-b', $startDate, '-e', $endDate, 'reg'); + +foreach my $type ('Income', 'Expenses') { + foreach my $fund (keys %funds) { + open(LEDGER_INCOME, "-|", $LEDGER_CMD, @ledgerOptions, "^${type}:$fund") + or die "Unable to run $LEDGER_CMD for funds: $!"; + $funds{$fund}{$type} = $ZERO; + while (my $line = ) { + die "Unable to parse output line from $type line command: $line" + unless $line =~ /^\s*([^\$]+)\s+\$\s*\s*([\-\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $funds{$fund}{$type} += $amount; + } + close LEDGER_INCOME; + } +} + +my($totStart, $totEnd) = ($ZERO, $ZERO); + +foreach my $fund (sort keys %funds) { + print "Fund: $fund\n"; + print " Balance as of $startDate: ", sprintf("\$%15.2f\n\n", $funds{$fund}{starting}); + print " Income during period: ", sprintf("\$%15.2f\n", $funds{$fund}{Income}); + print " Expenses during period: ", sprintf("\$%15.2f\n\n", $funds{$fund}{Expenses}); + print " Balance as of $endDate: ", sprintf("\$%15.2f\n", $funds{$fund}{ending}); + print "\n\n"; + # Santity check: + if ($funds{$fund}{ending} != + ( ($funds{$fund}{starting} - $funds{$fund}{Income}) - $funds{$fund}{Expenses})) { + print "$fund FAILED SANITY CHECK\n\n\n"; + die "$fund FAILED SANITY CHECK"; + } + $totStart += $funds{$fund}{starting}; + $totEnd += $funds{$fund}{ending}; +} +print "\n\n\nTotal Restricted Funds as of $startDate: ", sprintf("\$%15.2f\n", $totStart); +print "\nTotal Restricted Funds as of $endDate: ", sprintf("\$%15.2f\n", $totEnd); +############################################################################### +# +# Local variables: +# compile-command: "perl -c fund-report.plx" +# End: + -- cgit v1.2.3 From 55227e4d2c30923da7014826f9f02a21facbacfa Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 1 Nov 2011 12:15:25 -0400 Subject: Fix ledger options and be sure starting is set to zero for new funds. --- contrib/non-profit-audit-reports/fund-report.plx | 44 ++++-------------------- 1 file changed, 6 insertions(+), 38 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index e690b13b..22373eb8 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -59,7 +59,7 @@ while (my $fundLine = ) { unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); - $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; + $account =~ s/^\s+Funds:Restricted://; $account =~ s/\s+$//; $funds{$account}{ending} = $amount; } close LEDGER_FUNDS; @@ -77,56 +77,24 @@ while (my $fundLine = ) { unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); - $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; + $account =~ s/^\s+Funds:Restricted://; $account =~ s/\s+$//; $funds{$account}{starting} = $amount; } close LEDGER_FUNDS; - foreach my $fund (keys %funds) { $funds{$fund}{starting} = $ZERO if not defined $funds{$fund}{starting}; } -@ledgerOptions = (@mainLedgerOptions, - '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', - '-b', $startDate, '-e', $endDate, 'reg'); - -foreach my $type ('Income', 'Expenses') { - foreach my $fund (keys %funds) { - open(LEDGER_INCOME, "-|", $LEDGER_CMD, @ledgerOptions, "^${type}:$fund") - or die "Unable to run $LEDGER_CMD for funds: $!"; - $funds{$fund}{$type} = $ZERO; - while (my $line = ) { - die "Unable to parse output line from $type line command: $line" - unless $line =~ /^\s*([^\$]+)\s+\$\s*\s*([\-\d\.\,]+)/; - my($account, $amount) = ($1, $2); - $amount = ParseNumber($amount); - $funds{$fund}{$type} += $amount; - } - close LEDGER_INCOME; - } -} - -my($totStart, $totEnd) = ($ZERO, $ZERO); +my $format = "%-${ACCT_WIDTH}.${ACCT_WIDTH}s \$%11.2f \$%11.2f\n"; +my($totDeb, $totCred) = ($ZERO, $ZERO); foreach my $fund (sort keys %funds) { print "Fund: $fund\n"; - print " Balance as of $startDate: ", sprintf("\$%15.2f\n\n", $funds{$fund}{starting}); - print " Income during period: ", sprintf("\$%15.2f\n", $funds{$fund}{Income}); - print " Expenses during period: ", sprintf("\$%15.2f\n\n", $funds{$fund}{Expenses}); - print " Balance as of $endDate: ", sprintf("\$%15.2f\n", $funds{$fund}{ending}); + print " Balance as of $startDate: ", sprintf("\$%11.2f\n", $funds{$fund}{starting}); + print " Balance as of $endDate: ", sprintf("\$%11.2f\n", $funds{$fund}{ending}); print "\n\n"; - # Santity check: - if ($funds{$fund}{ending} != - ( ($funds{$fund}{starting} - $funds{$fund}{Income}) - $funds{$fund}{Expenses})) { - print "$fund FAILED SANITY CHECK\n\n\n"; - die "$fund FAILED SANITY CHECK"; - } - $totStart += $funds{$fund}{starting}; - $totEnd += $funds{$fund}{ending}; } -print "\n\n\nTotal Restricted Funds as of $startDate: ", sprintf("\$%15.2f\n", $totStart); -print "\nTotal Restricted Funds as of $endDate: ", sprintf("\$%15.2f\n", $totEnd); ############################################################################### # # Local variables: -- cgit v1.2.3 From daad6e5700141bfbed6bb6a984ad99f76e7ac09d Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 1 Nov 2011 12:24:19 -0400 Subject: Added income/expense summing. --- contrib/non-profit-audit-reports/fund-report.plx | 29 +++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 22373eb8..35463fe3 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -59,7 +59,7 @@ while (my $fundLine = ) { unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); - $account =~ s/^\s+Funds:Restricted://; $account =~ s/\s+$//; + $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; $funds{$account}{ending} = $amount; } close LEDGER_FUNDS; @@ -77,21 +77,44 @@ while (my $fundLine = ) { unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); - $account =~ s/^\s+Funds:Restricted://; $account =~ s/\s+$//; + $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; $funds{$account}{starting} = $amount; } close LEDGER_FUNDS; + foreach my $fund (keys %funds) { $funds{$fund}{starting} = $ZERO if not defined $funds{$fund}{starting}; } +@ledgerOptions = (@mainLedgerOptions, + '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', + '-b', $startDate, '-e', $endDate, 'reg'); + +foreach my $type ('Income', 'Expenses') { + foreach my $fund (keys %funds) { + open(LEDGER_INCOME, "-|", $LEDGER_CMD, @ledgerOptions, "^${type}:$fund") + or die "Unable to run $LEDGER_CMD for funds: $!"; + $funds{$fund}{$type} = $ZERO; + while (my $line = ) { + die "Unable to parse output line from $type line command: $line" + unless $line =~ /^\s*([^\$]+)\s+\$\s*\s*([\-\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $funds{$fund}{$type} += $amount; + } + close LEDGER_INCOME; + } +} + my $format = "%-${ACCT_WIDTH}.${ACCT_WIDTH}s \$%11.2f \$%11.2f\n"; my($totDeb, $totCred) = ($ZERO, $ZERO); foreach my $fund (sort keys %funds) { print "Fund: $fund\n"; - print " Balance as of $startDate: ", sprintf("\$%11.2f\n", $funds{$fund}{starting}); + print " Balance as of $startDate: ", sprintf("\$%11.2f\n\n", $funds{$fund}{starting}); + print " Income during period: ", sprintf("\$%11.2f\n", $funds{$fund}{Income}); + print " Expenses during period: ", sprintf("\$%11.2f\n", $funds{$fund}{Expenses}); print " Balance as of $endDate: ", sprintf("\$%11.2f\n", $funds{$fund}{ending}); print "\n\n"; } -- cgit v1.2.3 From 9051804fb17bde5d33394747ea38000f26318edd Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 1 Nov 2011 12:28:01 -0400 Subject: Fixed formatting and added sanity check code. --- contrib/non-profit-audit-reports/fund-report.plx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 35463fe3..9d6a31b3 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -114,9 +114,15 @@ foreach my $fund (sort keys %funds) { print "Fund: $fund\n"; print " Balance as of $startDate: ", sprintf("\$%11.2f\n\n", $funds{$fund}{starting}); print " Income during period: ", sprintf("\$%11.2f\n", $funds{$fund}{Income}); - print " Expenses during period: ", sprintf("\$%11.2f\n", $funds{$fund}{Expenses}); + print " Expenses during period: ", sprintf("\$%11.2f\n\n", $funds{$fund}{Expenses}); print " Balance as of $endDate: ", sprintf("\$%11.2f\n", $funds{$fund}{ending}); print "\n\n"; + # Santity check: + if ($funds{$fund}{ending} == + ($funds{$fund}{starting} + $funds{$fund}{Income} + $funds{$fund}{Expenses})) { + print "$fund FAILED SANITY CHECK\n\n\n"; + die "$fund FAILED SANITY CHECK"; + } } ############################################################################### # -- cgit v1.2.3 From cf969fcbb4cf1cdf0b76124b44e549ca03e8590e Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 1 Nov 2011 12:41:15 -0400 Subject: Formatting changes, and added total for restricted funds. --- contrib/non-profit-audit-reports/fund-report.plx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 9d6a31b3..e690b13b 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -107,23 +107,26 @@ foreach my $type ('Income', 'Expenses') { } } -my $format = "%-${ACCT_WIDTH}.${ACCT_WIDTH}s \$%11.2f \$%11.2f\n"; -my($totDeb, $totCred) = ($ZERO, $ZERO); +my($totStart, $totEnd) = ($ZERO, $ZERO); foreach my $fund (sort keys %funds) { print "Fund: $fund\n"; - print " Balance as of $startDate: ", sprintf("\$%11.2f\n\n", $funds{$fund}{starting}); - print " Income during period: ", sprintf("\$%11.2f\n", $funds{$fund}{Income}); - print " Expenses during period: ", sprintf("\$%11.2f\n\n", $funds{$fund}{Expenses}); - print " Balance as of $endDate: ", sprintf("\$%11.2f\n", $funds{$fund}{ending}); + print " Balance as of $startDate: ", sprintf("\$%15.2f\n\n", $funds{$fund}{starting}); + print " Income during period: ", sprintf("\$%15.2f\n", $funds{$fund}{Income}); + print " Expenses during period: ", sprintf("\$%15.2f\n\n", $funds{$fund}{Expenses}); + print " Balance as of $endDate: ", sprintf("\$%15.2f\n", $funds{$fund}{ending}); print "\n\n"; # Santity check: - if ($funds{$fund}{ending} == - ($funds{$fund}{starting} + $funds{$fund}{Income} + $funds{$fund}{Expenses})) { + if ($funds{$fund}{ending} != + ( ($funds{$fund}{starting} - $funds{$fund}{Income}) - $funds{$fund}{Expenses})) { print "$fund FAILED SANITY CHECK\n\n\n"; die "$fund FAILED SANITY CHECK"; } + $totStart += $funds{$fund}{starting}; + $totEnd += $funds{$fund}{ending}; } +print "\n\n\nTotal Restricted Funds as of $startDate: ", sprintf("\$%15.2f\n", $totStart); +print "\nTotal Restricted Funds as of $endDate: ", sprintf("\$%15.2f\n", $totEnd); ############################################################################### # # Local variables: -- cgit v1.2.3 From 5305642e4dafcd662c3c6842a383aaf4b27938d4 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 21 Nov 2012 14:00:58 -0500 Subject: Formatting adaptations for Ledger 3. This includes addition of currency-forcing options such as -V and -X $, as well as corrections to the formatting string options for Ledger 3. --- contrib/non-profit-audit-reports/fund-report.plx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index e690b13b..673263d7 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -25,7 +25,7 @@ use warnings; use Math::BigFloat; -my $LEDGER_CMD = "/usr/bin/ledger"; +my $LEDGER_CMD = "/usr/local/bin/ledger"; my $ACCT_WIDTH = 70; @@ -45,8 +45,8 @@ my($startDate, $endDate, @mainLedgerOptions) = @ARGV; # First, get fund list from ending balance my(@ledgerOptions) = (@mainLedgerOptions, - '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', - '-e', $endDate, 'reg', '^Funds:Restricted:'); + '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-s', + '-e', $endDate, 'reg', '/^Funds:Restricted:/'); my %funds; @@ -55,7 +55,7 @@ open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) or die "Unable to run $LEDGER_CMD for funds: $!"; while (my $fundLine = ) { - die "Unable to parse output line from funds command: $fundLine" + die "Unable to parse output line from funds command: \"$fundLine\"" unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); @@ -66,7 +66,7 @@ close LEDGER_FUNDS; # First, get fund list from ending balance @ledgerOptions = (@mainLedgerOptions, - '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', + '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-w', '-s', '-e', $startDate, 'reg', '^Funds:Restricted:'); open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) @@ -88,7 +88,7 @@ foreach my $fund (keys %funds) { } @ledgerOptions = (@mainLedgerOptions, - '--wide-register-format', "%-.70A %22.108t\n", '-w', '-s', + '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-w', '-s', '-b', $startDate, '-e', $endDate, 'reg'); foreach my $type ('Income', 'Expenses') { -- cgit v1.2.3 From 60f45c3e2cff809f6c9356e9853cf38070bd3ec6 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Wed, 21 Nov 2012 14:52:39 -0500 Subject: Ignore entries in the report. With the advent of multi-currency in accounts, lines can be generated in reports. I don't know if there's a way to turn these off on the Ledger command line or not at the moment, but if they're there, they clearly should be ignored by this script. --- contrib/non-profit-audit-reports/fund-report.plx | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 673263d7..a463bccf 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -40,26 +40,26 @@ if (@ARGV < 2) { print STDERR "usage: $0 \n"; exit 1; } - my($startDate, $endDate, @mainLedgerOptions) = @ARGV; # First, get fund list from ending balance my(@ledgerOptions) = (@mainLedgerOptions, '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-s', '-e', $endDate, 'reg', '/^Funds:Restricted:/'); - - my %funds; open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) or die "Unable to run $LEDGER_CMD for funds: $!"; while (my $fundLine = ) { - die "Unable to parse output line from funds command: \"$fundLine\"" - unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; + die "Unable to parse output line from first funds command: \"$fundLine\"" + unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\-\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); - $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; + $account =~ s/\s+$//; + next if $account =~ /\/ and (abs($amount) <= 0.02); + die "Weird account found, $account with amount of $amount in first funds command\n" + unless $account =~ s/^\s*Funds:Restricted://; $funds{$account}{ending} = $amount; } close LEDGER_FUNDS; @@ -73,11 +73,14 @@ open(LEDGER_FUNDS, "-|", $LEDGER_CMD, @ledgerOptions) or die "Unable to run $LEDGER_CMD for funds: $!"; while (my $fundLine = ) { - die "Unable to parse output line from funds command: $fundLine" - unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*\s*([\d\.\,]+)/; + die "Unable to parse output line from second funds command: $fundLine" + unless $fundLine =~ /^\s*([^\$]+)\s+\$\s*([\-\d\.\,]+)/; my($account, $amount) = ($1, $2); $amount = ParseNumber($amount); - $account =~ s/^\s*Funds:Restricted://; $account =~ s/\s+$//; + $account =~ s/\s+$//; + next if $account =~ /\/ and (abs($amount) <= 0.02); + die "Weird account found, $account with amount of $amount in first second command\n" + unless $account =~ s/^\s*Funds:Restricted://; $funds{$account}{starting} = $amount; } close LEDGER_FUNDS; -- cgit v1.2.3 From 7772e33720db8234d12640996033bcba8ca98e7f Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 22 Nov 2012 16:45:59 -0500 Subject: Include all types of totals that need to be considered when generating fund report. --- contrib/non-profit-audit-reports/fund-report.plx | 26 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index a463bccf..764080d0 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -64,7 +64,7 @@ while (my $fundLine = ) { } close LEDGER_FUNDS; -# First, get fund list from ending balance +# First, get fund list from starting balance @ledgerOptions = (@mainLedgerOptions, '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-w', '-s', '-e', $startDate, 'reg', '^Funds:Restricted:'); @@ -94,7 +94,10 @@ foreach my $fund (keys %funds) { '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-w', '-s', '-b', $startDate, '-e', $endDate, 'reg'); -foreach my $type ('Income', 'Expenses') { +my @possibleTypes = ('Unearned Income', 'Retained Earnings', 'Retained Costs', + 'Accrued:Accounts Payable', 'Accrued:Accounts Receivable'); + +foreach my $type ('Income', 'Expenses', @possibleTypes) { foreach my $fund (keys %funds) { open(LEDGER_INCOME, "-|", $LEDGER_CMD, @ledgerOptions, "^${type}:$fund") or die "Unable to run $LEDGER_CMD for funds: $!"; @@ -113,15 +116,20 @@ foreach my $type ('Income', 'Expenses') { my($totStart, $totEnd) = ($ZERO, $ZERO); foreach my $fund (sort keys %funds) { - print "Fund: $fund\n"; - print " Balance as of $startDate: ", sprintf("\$%15.2f\n\n", $funds{$fund}{starting}); - print " Income during period: ", sprintf("\$%15.2f\n", $funds{$fund}{Income}); - print " Expenses during period: ", sprintf("\$%15.2f\n\n", $funds{$fund}{Expenses}); - print " Balance as of $endDate: ", sprintf("\$%15.2f\n", $funds{$fund}{ending}); - print "\n\n"; + my $sanityTotal = $funds{$fund}{starting}; + print "Fund: $fund\n", sprintf("%-35s\$%26.2f\n\n", "Balance as of $startDate:", + $funds{$fund}{starting}); + foreach my $type ('Income', 'Expenses', @possibleTypes) { + my $formattedType = $type; $formattedType =~ s/^Accrued://; + next if $type ne 'Income' and $type ne 'Expenses' and $funds{$fund}{$type} == $ZERO; + print sprintf("%19s during period: \$%26.2f\n", $formattedType, $funds{$fund}{$type}); + } + print sprintf("\n%-35s\$%26.2f\n", "Balance as of $endDate:", + $funds{$fund}{ending}), "\n\n"; # Santity check: if ($funds{$fund}{ending} != - ( ($funds{$fund}{starting} - $funds{$fund}{Income}) - $funds{$fund}{Expenses})) { + ($funds{$fund}{starting} + - $funds{$fund}{Income} - $funds{$fund}{'Unearned Income'} - $funds{$fund}{Expenses})) { print "$fund FAILED SANITY CHECK\n\n\n"; die "$fund FAILED SANITY CHECK"; } -- cgit v1.2.3 From 530fa76beab2e5e16603d0bf554308056edd1c98 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 22 Nov 2012 16:46:42 -0500 Subject: Update copyright year, I've made changes. --- contrib/non-profit-audit-reports/fund-report.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 764080d0..5b74a606 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -3,7 +3,7 @@ # # Script to generate a Trial Balance report for a ledger. # -# Copyright (C) 2011, Bradley M. Kuhn +# Copyright (C) 2011, 2012, Bradley M. Kuhn # # This program gives you software freedom; you can copy, modify, convey, # and/or redistribute it under the terms of the GNU General Public License -- cgit v1.2.3 From 7ed4d20d87868d5e3918b5d2cccf6558e2849ca6 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Thu, 22 Nov 2012 19:40:36 -0500 Subject: Began summary reports script, starting with a basic balance sheet. --- .../non-profit-audit-reports/summary-reports.plx | 168 +++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100755 contrib/non-profit-audit-reports/summary-reports.plx (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx new file mode 100755 index 00000000..1b9bc734 --- /dev/null +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -0,0 +1,168 @@ +#!/usr/bin/perl +# fund-report.plx -*- Perl -*- +# +# Script to generate end-of-year summary reports. +# +# Copyright (C) 2011, 2012, Bradley M. Kuhn +# +# This program gives you software freedom; you can copy, modify, convey, +# and/or redistribute it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program in a file called 'GPLv3'. If not, write to the: +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor +# Boston, MA 02110-1301, USA. + +use strict; +use warnings; + +use Math::BigFloat; + +my $VERBOSE = 0; +my $DEBUG = 0; + +my $LEDGER_BIN = "/usr/local/bin/ledger"; + +my $ACCT_WIDTH = 70; + +sub Commify ($) { + my $text = reverse $_[0]; + $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g; + return scalar reverse $text; +} + +sub ParseNumber($) { + $_[0] =~ s/,//g; + return Math::BigFloat->new($_[0]); +} +Math::BigFloat->precision(-2); +my $ZERO = Math::BigFloat->new("0.00"); + +if (@ARGV < 2) { + print STDERR "usage: $0 \n"; + exit 1; +} +my($startDate, $endDate, @mainLedgerOptions) = @ARGV; + +# First, get fund list from ending balance +my(@ledgerOptions) = (@mainLedgerOptions, + '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-S', 'T', '-s', + 'd', 'T', '-e', $endDate, 'bal', '/^Assets/'); + +my %reportFields = + ('Cash' => { args => [ '-e', $endDate, 'bal', '/^Assets/' ] }, + 'Accounts Receivable' => {args => [ '-e', $endDate, 'bal', '/^Accrued:Accounts Receivable/' ]}, + 'Accounts Payable' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Accounts Payable/' ]}, + 'Accrued Expenses' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Expenses/' ]}, + 'Unearned Income, Conference Registration' => {args => [ '-e', $endDate, 'bal', + '/^Unearned Income.*Conf.*Reg/' ]}, + 'Unearned Income, Other' => {args => [ '-e', $endDate, 'bal', '/^Unearned Income/', 'and', 'not', + '/^Unearned Income.*Conf.*Reg/' ]}, + 'Unrestricted Net Assets' => {args => [ '-e', $endDate, 'bal', '/^(Income|Expenses):Conservancy/' ]}, + 'Temporarily Restricted Net Assets' => {args => [ '-e', $endDate, 'bal', '/^(Income|Expenses)/', + 'and', 'not', '/^(Unearned Income|(Income|Expenses):Conservancy)/' ]}, + 'Total Net Assets' => {args => [ '-e', $endDate, 'bal', '/^(Income|Expenses)/' ]}, + +); +foreach my $item (keys %reportFields) { + my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, + '-V', '-S', 'T', '-s', '-d', 'T', @{$reportFields{$item}{args}}); + open(FILE, "-|", @fullCommand) + or die "unable to run command ledger command: @fullCommand: $!"; + + my $foundBalance; + my $seenTotalLine = 0; + + print STDERR ($VERBOSE ? "Running: @fullCommand\n" : "."); + print STDERR " Output of @fullCommand\n" if $DEBUG; + + while (my $line = ) { + print STDERR $line if ($DEBUG); + + $seenTotalLine = 1 if $line =~ /^\s*\-+\s*/; # Skip lines until the total line + $foundBalance = $1 + if (not $seenTotalLine and $line =~ /^\s*[^0-9\-]+\s*([\-\d,\.]+)\s+/); + + if ($line =~ /^\s*\$\s*([\-\d,\.]+)\s*$/) { + $foundBalance = $1; + last; + } + } + close FILE; + die "problem running ledger command: @fullCommand: $!" unless ($? == 0); + if (not defined $foundBalance) { + $foundBalance = $ZERO; + } else { + $foundBalance =~ s/,//g; + $foundBalance = Math::BigFloat->new($foundBalance); + } + $foundBalance = $ZERO if not defined $foundBalance; + $reportFields{$item}{total} = abs($foundBalance); + print STDERR "$item: $reportFields{$item}{total}\n" if $VERBOSE; +} + +die "Cash+accounts receivable total does not equal net assets and liabilities total" + if ( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total}) != + ($reportFields{'Accounts Payable'}{total} + + $reportFields{'Accrued Expenses'}{total} + + $reportFields{'Unearned Income, Conference Registration'}{total} + + $reportFields{'Unearned Income, Other'}{total} + + $reportFields{'Total Net Assets'}{total})); + +die "Total net assets doesn't equal sum of restricted and unrestricted ones!" + if ($reportFields{'Total Net Assets'}{total} != + $reportFields{'Unrestricted Net Assets'}{total} + + $reportFields{'Temporarily Restricted Net Assets'}{total}); + +open(ASSETS, ">", "assets-and-liabilities.txt") + or die "unable to open assets-and-liabilities.txt for writing: $!"; + +print ASSETS "ASSETS\n\n"; + +my $formatStr = " %-42s \$%18s\n"; +my $formatStrTotal = "%-45s \$%12s\n"; +my $tot = $ZERO; +foreach my $item ('Cash', 'Accounts Receivable') { + next if $reportFields{$item}{total} == $ZERO; + print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); + $tot += $reportFields{$item}{total}; +} +print ASSETS "\n", sprintf($formatStrTotal, "TOTAL ASSETS", Commify($tot)), "\n\nLIABILITIES\n\n"; + +my $totLiabilities = $ZERO; +foreach my $item ('Accounts Payable', 'Accrued Expenses', + 'Unearned Income, Conference Registration', 'Unearned Income, Other') { + next if $reportFields{$item}{total} == $ZERO; + print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); + $totLiabilities += $reportFields{$item}{total}; +} +print ASSETS "\n", sprintf($formatStr, "TOTAL LIABILTIES", Commify($totLiabilities)), + "\n\nNET ASSETS\n\n"; + +my $totNetAssets = $ZERO; +foreach my $item ('Unrestricted Net Assets', 'Temporarily Restricted Net Assets') { + next if $reportFields{$item}{total} == $ZERO; + print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); + $totNetAssets += $reportFields{$item}{total}; +} +print ASSETS "\n", sprintf($formatStr, "TOTAL NET ASSETS", Commify($totNetAssets)), "\n\n", + sprintf($formatStrTotal, "TOTAL LIABILITIES AND NET ASSETS", + Commify($totNetAssets + $totLiabilities)); + +close ASSETS; +print STDERR "\n"; +die "unable to write to Assets-and-liabilities.txt: $!" unless ($? == 0); + +############################################################################### +# +# Local variables: +# compile-command: "perl -c summary-reports.plx" +# End: + -- cgit v1.2.3 From f0ee16a373412e3654120e3847430a1a94ea8d23 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:35:38 -0500 Subject: Add Loans. --- contrib/non-profit-audit-reports/summary-reports.plx | 1 + 1 file changed, 1 insertion(+) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 1b9bc734..a175f5ba 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -59,6 +59,7 @@ my(@ledgerOptions) = (@mainLedgerOptions, my %reportFields = ('Cash' => { args => [ '-e', $endDate, 'bal', '/^Assets/' ] }, 'Accounts Receivable' => {args => [ '-e', $endDate, 'bal', '/^Accrued:Accounts Receivable/' ]}, + 'Loans Receivable' => {args => [ '-e', $endDate, 'bal', '/^Accrued:Loans Receivable/' ]}, 'Accounts Payable' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Accounts Payable/' ]}, 'Accrued Expenses' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Expenses/' ]}, 'Unearned Income, Conference Registration' => {args => [ '-e', $endDate, 'bal', -- cgit v1.2.3 From 7b0e4c48067296d15c6f350948cbf29d7aec5787 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:35:45 -0500 Subject: Add -X $. --- contrib/non-profit-audit-reports/summary-reports.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index a175f5ba..c0731322 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -74,7 +74,7 @@ my %reportFields = ); foreach my $item (keys %reportFields) { my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, - '-V', '-S', 'T', '-s', '-d', 'T', @{$reportFields{$item}{args}}); + '-V', '-X', '$', '-S', 'T', '-s', '-d', 'T', @{$reportFields{$item}{args}}); open(FILE, "-|", @fullCommand) or die "unable to run command ledger command: @fullCommand: $!"; -- cgit v1.2.3 From cba448b28bbc26a03a5b590818ff8668ac162681 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:36:11 -0500 Subject: Move sanity checks to the bottom, after report is generated. Also, fix formatting. --- .../non-profit-audit-reports/summary-reports.plx | 33 +++++++++++----------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index c0731322..0f0e09ee 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -109,28 +109,15 @@ foreach my $item (keys %reportFields) { print STDERR "$item: $reportFields{$item}{total}\n" if $VERBOSE; } -die "Cash+accounts receivable total does not equal net assets and liabilities total" - if ( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total}) != - ($reportFields{'Accounts Payable'}{total} + - $reportFields{'Accrued Expenses'}{total} + - $reportFields{'Unearned Income, Conference Registration'}{total} + - $reportFields{'Unearned Income, Other'}{total} + - $reportFields{'Total Net Assets'}{total})); - -die "Total net assets doesn't equal sum of restricted and unrestricted ones!" - if ($reportFields{'Total Net Assets'}{total} != - $reportFields{'Unrestricted Net Assets'}{total} + - $reportFields{'Temporarily Restricted Net Assets'}{total}); - open(ASSETS, ">", "assets-and-liabilities.txt") or die "unable to open assets-and-liabilities.txt for writing: $!"; print ASSETS "ASSETS\n\n"; -my $formatStr = " %-42s \$%18s\n"; -my $formatStrTotal = "%-45s \$%12s\n"; +my $formatStr = " %-42s \$%13s\n"; +my $formatStrTotal = "%-45s \$%13s\n"; my $tot = $ZERO; -foreach my $item ('Cash', 'Accounts Receivable') { +foreach my $item ('Cash', 'Accounts Receivable', 'Loans Receivable') { next if $reportFields{$item}{total} == $ZERO; print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); $tot += $reportFields{$item}{total}; @@ -161,6 +148,20 @@ close ASSETS; print STDERR "\n"; die "unable to write to Assets-and-liabilities.txt: $!" unless ($? == 0); +die "Cash+accounts receivable total does not equal net assets and liabilities total" + if ( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total} + + $reportFields{'Loans Receivable'}{total}) != + ($reportFields{'Accounts Payable'}{total} + + $reportFields{'Accrued Expenses'}{total} + + $reportFields{'Unearned Income, Conference Registration'}{total} + + $reportFields{'Unearned Income, Other'}{total} + + $reportFields{'Total Net Assets'}{total})); + +die "Total net assets doesn't equal sum of restricted and unrestricted ones!" + if ($reportFields{'Total Net Assets'}{total} != + $reportFields{'Unrestricted Net Assets'}{total} + + $reportFields{'Temporarily Restricted Net Assets'}{total}); + ############################################################################### # # Local variables: -- cgit v1.2.3 From 46b13e8e550fb05a3e863e913cf6cd359ef42272 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:44:53 -0500 Subject: Include credit card balances in the Liabilities list. --- contrib/non-profit-audit-reports/summary-reports.plx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 0f0e09ee..04923de8 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -62,6 +62,7 @@ my %reportFields = 'Loans Receivable' => {args => [ '-e', $endDate, 'bal', '/^Accrued:Loans Receivable/' ]}, 'Accounts Payable' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Accounts Payable/' ]}, 'Accrued Expenses' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Expenses/' ]}, + 'Liabilities, Credit Cards' => {args => [ '-e', $endDate, 'bal', '/^Liabilities:Credit Card/' ]}, 'Unearned Income, Conference Registration' => {args => [ '-e', $endDate, 'bal', '/^Unearned Income.*Conf.*Reg/' ]}, 'Unearned Income, Other' => {args => [ '-e', $endDate, 'bal', '/^Unearned Income/', 'and', 'not', @@ -125,7 +126,7 @@ foreach my $item ('Cash', 'Accounts Receivable', 'Loans Receivable') { print ASSETS "\n", sprintf($formatStrTotal, "TOTAL ASSETS", Commify($tot)), "\n\nLIABILITIES\n\n"; my $totLiabilities = $ZERO; -foreach my $item ('Accounts Payable', 'Accrued Expenses', +foreach my $item ('Accounts Payable', 'Liabilities, Credit Cards', 'Accrued Expenses', 'Unearned Income, Conference Registration', 'Unearned Income, Other') { next if $reportFields{$item}{total} == $ZERO; print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); @@ -155,6 +156,7 @@ die "Cash+accounts receivable total does not equal net assets and liabilities to $reportFields{'Accrued Expenses'}{total} + $reportFields{'Unearned Income, Conference Registration'}{total} + $reportFields{'Unearned Income, Other'}{total} + + $reportFields{'Liabilities, Credit Cards'}{total} + $reportFields{'Total Net Assets'}{total})); die "Total net assets doesn't equal sum of restricted and unrestricted ones!" -- cgit v1.2.3 From ccd5d06c04576bbd3911d4ce0c9ccb8c4ec4cfc5 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:45:52 -0500 Subject: Include any other liabilities that aren't credit cards. --- contrib/non-profit-audit-reports/summary-reports.plx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 04923de8..14923a42 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -63,6 +63,8 @@ my %reportFields = 'Accounts Payable' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Accounts Payable/' ]}, 'Accrued Expenses' => {args => [ '-e', $endDate, 'bal', '/^Accrued.*Expenses/' ]}, 'Liabilities, Credit Cards' => {args => [ '-e', $endDate, 'bal', '/^Liabilities:Credit Card/' ]}, + 'Liabilities, Other' => {args => [ '-e', $endDate, 'bal', '/^Liabilities/', + 'and', 'not', '/^Liabilities:Credit Card/']}, 'Unearned Income, Conference Registration' => {args => [ '-e', $endDate, 'bal', '/^Unearned Income.*Conf.*Reg/' ]}, 'Unearned Income, Other' => {args => [ '-e', $endDate, 'bal', '/^Unearned Income/', 'and', 'not', @@ -126,7 +128,8 @@ foreach my $item ('Cash', 'Accounts Receivable', 'Loans Receivable') { print ASSETS "\n", sprintf($formatStrTotal, "TOTAL ASSETS", Commify($tot)), "\n\nLIABILITIES\n\n"; my $totLiabilities = $ZERO; -foreach my $item ('Accounts Payable', 'Liabilities, Credit Cards', 'Accrued Expenses', +foreach my $item ('Accounts Payable', 'Accrued Expenses', + 'Liabilities, Credit Cards', 'Liabilities, Other', 'Unearned Income, Conference Registration', 'Unearned Income, Other') { next if $reportFields{$item}{total} == $ZERO; print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); @@ -157,6 +160,7 @@ die "Cash+accounts receivable total does not equal net assets and liabilities to $reportFields{'Unearned Income, Conference Registration'}{total} + $reportFields{'Unearned Income, Other'}{total} + $reportFields{'Liabilities, Credit Cards'}{total} + + $reportFields{'Liabilities, Other'}{total} + $reportFields{'Total Net Assets'}{total})); die "Total net assets doesn't equal sum of restricted and unrestricted ones!" -- cgit v1.2.3 From 23dd0899f2634cad221b1859f127a0a6c96d62a2 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:48:32 -0500 Subject: Allow for one penny margin of error on totals. --- contrib/non-profit-audit-reports/summary-reports.plx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 14923a42..875f89be 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -44,6 +44,7 @@ sub ParseNumber($) { } Math::BigFloat->precision(-2); my $ZERO = Math::BigFloat->new("0.00"); +my $ONE_PENNY = Math::BigFloat->new("0.01"); if (@ARGV < 2) { print STDERR "usage: $0 \n"; @@ -153,20 +154,20 @@ print STDERR "\n"; die "unable to write to Assets-and-liabilities.txt: $!" unless ($? == 0); die "Cash+accounts receivable total does not equal net assets and liabilities total" - if ( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total} - + $reportFields{'Loans Receivable'}{total}) != - ($reportFields{'Accounts Payable'}{total} + + if (abs( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total} + + $reportFields{'Loans Receivable'}{total})) - + abs($reportFields{'Accounts Payable'}{total} + $reportFields{'Accrued Expenses'}{total} + $reportFields{'Unearned Income, Conference Registration'}{total} + $reportFields{'Unearned Income, Other'}{total} + $reportFields{'Liabilities, Credit Cards'}{total} + $reportFields{'Liabilities, Other'}{total} + - $reportFields{'Total Net Assets'}{total})); + $reportFields{'Total Net Assets'}{total}) > $ONE_PENNY); die "Total net assets doesn't equal sum of restricted and unrestricted ones!" - if ($reportFields{'Total Net Assets'}{total} != - $reportFields{'Unrestricted Net Assets'}{total} + - $reportFields{'Temporarily Restricted Net Assets'}{total}); + if (abs($reportFields{'Total Net Assets'}{total}) - + abs($reportFields{'Unrestricted Net Assets'}{total} + + $reportFields{'Temporarily Restricted Net Assets'}{total}) > $ONE_PENNY); ############################################################################### # -- cgit v1.2.3 From e0df353ca37e4601921341a692300754186c8e6e Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 08:53:02 -0500 Subject: Call a Balance Sheet, a Balance Sheet. :) --- contrib/non-profit-audit-reports/summary-reports.plx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 875f89be..27a8d210 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -113,43 +113,43 @@ foreach my $item (keys %reportFields) { print STDERR "$item: $reportFields{$item}{total}\n" if $VERBOSE; } -open(ASSETS, ">", "assets-and-liabilities.txt") - or die "unable to open assets-and-liabilities.txt for writing: $!"; +open(BALANCE_SHEET, ">", "balance-sheet.txt") + or die "unable to open balance-sheet.txt for writing: $!"; -print ASSETS "ASSETS\n\n"; +print BALANCE_SHEET "ASSETS\n\n"; my $formatStr = " %-42s \$%13s\n"; my $formatStrTotal = "%-45s \$%13s\n"; my $tot = $ZERO; foreach my $item ('Cash', 'Accounts Receivable', 'Loans Receivable') { next if $reportFields{$item}{total} == $ZERO; - print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); + print BALANCE_SHEET sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); $tot += $reportFields{$item}{total}; } -print ASSETS "\n", sprintf($formatStrTotal, "TOTAL ASSETS", Commify($tot)), "\n\nLIABILITIES\n\n"; +print BALANCE_SHEET "\n", sprintf($formatStrTotal, "TOTAL ASSETS", Commify($tot)), "\n\nLIABILITIES\n\n"; my $totLiabilities = $ZERO; foreach my $item ('Accounts Payable', 'Accrued Expenses', 'Liabilities, Credit Cards', 'Liabilities, Other', 'Unearned Income, Conference Registration', 'Unearned Income, Other') { next if $reportFields{$item}{total} == $ZERO; - print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); + print BALANCE_SHEET sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); $totLiabilities += $reportFields{$item}{total}; } -print ASSETS "\n", sprintf($formatStr, "TOTAL LIABILTIES", Commify($totLiabilities)), +print BALANCE_SHEET "\n", sprintf($formatStr, "TOTAL LIABILTIES", Commify($totLiabilities)), "\n\nNET ASSETS\n\n"; my $totNetAssets = $ZERO; foreach my $item ('Unrestricted Net Assets', 'Temporarily Restricted Net Assets') { next if $reportFields{$item}{total} == $ZERO; - print ASSETS sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); + print BALANCE_SHEET sprintf($formatStr, "$item:", Commify($reportFields{$item}{total})); $totNetAssets += $reportFields{$item}{total}; } -print ASSETS "\n", sprintf($formatStr, "TOTAL NET ASSETS", Commify($totNetAssets)), "\n\n", +print BALANCE_SHEET "\n", sprintf($formatStr, "TOTAL NET ASSETS", Commify($totNetAssets)), "\n\n", sprintf($formatStrTotal, "TOTAL LIABILITIES AND NET ASSETS", Commify($totNetAssets + $totLiabilities)); -close ASSETS; +close BALANCE_SHEET; print STDERR "\n"; die "unable to write to Assets-and-liabilities.txt: $!" unless ($? == 0); -- cgit v1.2.3 From 239df56cfba6ad715f4fc63f9fde6dd968e973cd Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 09:01:19 -0500 Subject: Output should include a heading and an ending date. --- contrib/non-profit-audit-reports/summary-reports.plx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 27a8d210..c41fee50 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -24,6 +24,7 @@ use strict; use warnings; use Math::BigFloat; +use Date::Manip; my $VERBOSE = 0; my $DEBUG = 0; @@ -113,10 +114,16 @@ foreach my $item (keys %reportFields) { print STDERR "$item: $reportFields{$item}{total}\n" if $VERBOSE; } +my $err; open(BALANCE_SHEET, ">", "balance-sheet.txt") or die "unable to open balance-sheet.txt for writing: $!"; -print BALANCE_SHEET "ASSETS\n\n"; +print BALANCE_SHEET " BALANCE SHEET\n", + " Ending ", + UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), + "%B %e, %Y\n"), + "\n\nASSETS\n\n"; +die "Date calculation error" if ($err); my $formatStr = " %-42s \$%13s\n"; my $formatStrTotal = "%-45s \$%13s\n"; -- cgit v1.2.3 From fe608b12e2a3b774bc7e56b40d95444bcf0d476e Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 09:02:35 -0500 Subject: Remove cruft cut-and-pasted from another script. --- contrib/non-profit-audit-reports/summary-reports.plx | 5 ----- 1 file changed, 5 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index c41fee50..154662f1 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -53,11 +53,6 @@ if (@ARGV < 2) { } my($startDate, $endDate, @mainLedgerOptions) = @ARGV; -# First, get fund list from ending balance -my(@ledgerOptions) = (@mainLedgerOptions, - '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-S', 'T', '-s', - 'd', 'T', '-e', $endDate, 'bal', '/^Assets/'); - my %reportFields = ('Cash' => { args => [ '-e', $endDate, 'bal', '/^Assets/' ] }, 'Accounts Receivable' => {args => [ '-e', $endDate, 'bal', '/^Accrued:Accounts Receivable/' ]}, -- cgit v1.2.3 From 76292d08d92365a10964255a01a60ee1f6aa7448 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 09:07:12 -0500 Subject: Calculate dates in a reusable way throughout script. --- contrib/non-profit-audit-reports/summary-reports.plx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 154662f1..b49e6bdd 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -53,6 +53,14 @@ if (@ARGV < 2) { } my($startDate, $endDate, @mainLedgerOptions) = @ARGV; +my $err; +my $formattedEndDate = UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), + "%B %e, %Y"); +die "Date calculation error on $endDate" if ($err); + +my $formattedStartDate = UnixDate(ParseDate($endDate), "%B %e, %Y"), +die "Date calculation error on $startDate" if ($err); + my %reportFields = ('Cash' => { args => [ '-e', $endDate, 'bal', '/^Assets/' ] }, 'Accounts Receivable' => {args => [ '-e', $endDate, 'bal', '/^Accrued:Accounts Receivable/' ]}, @@ -109,16 +117,12 @@ foreach my $item (keys %reportFields) { print STDERR "$item: $reportFields{$item}{total}\n" if $VERBOSE; } -my $err; open(BALANCE_SHEET, ">", "balance-sheet.txt") or die "unable to open balance-sheet.txt for writing: $!"; print BALANCE_SHEET " BALANCE SHEET\n", - " Ending ", - UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), - "%B %e, %Y\n"), + " Ending ", $formattedEndDate, "\n", "\n\nASSETS\n\n"; -die "Date calculation error" if ($err); my $formatStr = " %-42s \$%13s\n"; my $formatStrTotal = "%-45s \$%13s\n"; -- cgit v1.2.3 From 13c8a1fb569ddd83a65645e40c7f0c83b3a725eb Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Fri, 23 Nov 2012 09:53:05 -0500 Subject: Beginnings of income report. --- contrib/non-profit-audit-reports/summary-reports.plx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index b49e6bdd..9cb2aece 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -175,9 +175,26 @@ die "Total net assets doesn't equal sum of restricted and unrestricted ones!" abs($reportFields{'Unrestricted Net Assets'}{total} + $reportFields{'Temporarily Restricted Net Assets'}{total}) > $ONE_PENNY); + +my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-b', $startDate, '-e', $endDate, + '-F', '%-.80A %22.108t\n', '-s', + 'reg', '^Income'); + +open(FILE, "-|", @fullCommand) + or die "unable to run command ledger command: @fullCommand: $!"; + +open(INCOME, ">", "income.txt") + or die "unable to open balance-sheet.txt for writing: $!"; + +print INCOME " INCOME\n", + " Between $formattedStartDate and $formattedEndDate\n\n"; + +foreach my $line () { print INCOME $line; } +close INCOME; +die "unable to write to income.txt: $!" unless ($? == 0); ############################################################################### # # Local variables: # compile-command: "perl -c summary-reports.plx" # End: - -- cgit v1.2.3 From 7467917c7b93a39bbd90ccb059a9b55fdfbe52c4 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sat, 24 Nov 2012 13:57:06 -0500 Subject: Generate income report. --- .../non-profit-audit-reports/summary-reports.plx | 81 ++++++++++++++++++---- 1 file changed, 67 insertions(+), 14 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 9cb2aece..a30868d5 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -57,8 +57,7 @@ my $err; my $formattedEndDate = UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), "%B %e, %Y"); die "Date calculation error on $endDate" if ($err); - -my $formattedStartDate = UnixDate(ParseDate($endDate), "%B %e, %Y"), +my $formattedStartDate = UnixDate(ParseDate($startDate), "%B %e, %Y"); die "Date calculation error on $startDate" if ($err); my %reportFields = @@ -157,7 +156,7 @@ print BALANCE_SHEET "\n", sprintf($formatStr, "TOTAL NET ASSETS", Commify($totNe close BALANCE_SHEET; print STDERR "\n"; -die "unable to write to Assets-and-liabilities.txt: $!" unless ($? == 0); +die "unable to write to balance-sheet.txt: $!" unless ($? == 0); die "Cash+accounts receivable total does not equal net assets and liabilities total" if (abs( ($reportFields{'Cash'}{total} + $reportFields{'Accounts Receivable'}{total} @@ -176,23 +175,77 @@ die "Total net assets doesn't equal sum of restricted and unrestricted ones!" $reportFields{'Temporarily Restricted Net Assets'}{total}) > $ONE_PENNY); -my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', - '-b', $startDate, '-e', $endDate, - '-F', '%-.80A %22.108t\n', '-s', - 'reg', '^Income'); +my %incomeGroups = ('INTEREST INCOME' => { args => ['/^Income.*Interest/' ] }, + 'DONATIONS' => { args => [ '/^Income.*Donation/' ] }, + 'BOOK ROYALTIES & AFFILIATE PROGRAMS' => + { args => [ '/^Income.*(Royalt|Affilate)/' ] }, + 'CONFERENCES, REGISTRATION' => {args => [ '/^Income.*Conf.*Reg/' ] }, + 'CONFERENCES, RELATED BUSINESS INCOME' => { args => [ '/^Income.*(Booth|RBI)/'] }, + 'LICENSE ENFORCEMENT' => { args => [ '/^Income.*Enforce/' ]}, + 'TRADEMARKS' => {args => [ '/^Income.*Trademark/' ]}, + 'ADVERSITING' => {args => [ '/^Income.*Advertising/' ]}); + +my @otherArgs; +foreach my $type (keys %incomeGroups) { + @otherArgs = ("/^Income/") if @otherArgs == 0; + push(@otherArgs, 'and', 'not', @{$incomeGroups{$type}{args}}); +} +$incomeGroups{"OTHER"}{args} = \@otherArgs; +$incomeGroups{"TOTAL"}{args} = ['/^Income/']; + +open(INCOME, ">", "income.txt") or die "unable to open income.txt for writing: $!"; -open(FILE, "-|", @fullCommand) - or die "unable to run command ledger command: @fullCommand: $!"; +foreach my $type (keys %incomeGroups) { + my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-b', $startDate, '-e', $endDate, + '-F', '%-.80A %22.108t\n', '-s', + 'reg', @{$incomeGroups{$type}{args}}); -open(INCOME, ">", "income.txt") - or die "unable to open balance-sheet.txt for writing: $!"; + open(FILE, "-|", @fullCommand) + or die "unable to run command ledger command: @fullCommand: $!"; + + print STDERR ($VERBOSE ? "Running: @fullCommand\n" : "."); + $incomeGroups{$type}{total} = $ZERO; + $incomeGroups{$type}{output} = ""; + + foreach my $line () { + die "Unable to parse output line from second funds command: $line" + unless $line =~ /^\s*([^\$]+)\s+\$\s*([\-\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $account =~ s/\s+$//; + next if $account =~ /\/ and (abs($amount) <= 0.02); + die "Weird account found, $account with amount of $amount in income command\n" + unless $account =~ s/^\s*Income://; + + $incomeGroups{$type}{total} += $amount; + $incomeGroups{$type}{output} .= " $line"; + } +} print INCOME " INCOME\n", " Between $formattedStartDate and $formattedEndDate\n\n"; -foreach my $line () { print INCOME $line; } -close INCOME; -die "unable to write to income.txt: $!" unless ($? == 0); + +my $overallTotal = $ZERO; + +$formatStrTotal = "%-90s \$%14s\n"; +foreach my $type ('DONATIONS', 'LICENSE ENFORCEMENT', + 'CONFERENCES, REGISTRATION', 'CONFERENCES, RELATED BUSINESS INCOME', + 'BOOK ROYALTIES & AFFILIATE PROGRAMS', 'ADVERSITING', + 'TRADEMARKS', 'INTEREST INCOME', 'OTHER') { + print INCOME "\n$type\n", + $incomeGroups{$type}{output}, "\n", + sprintf($formatStrTotal, "TOTAL $type:", Commify($incomeGroups{$type}{total})); + $overallTotal += $incomeGroups{$type}{total}; +} +print INCOME "\n\n\n", sprintf($formatStrTotal, "OVERALL TOTAL:", Commify($overallTotal)); + +close INCOME; die "unable to write to income.txt: $!" unless ($? == 0); + +die "calculated total of $overallTotal does equal $incomeGroups{TOTAL}{total}" + if (abs($overallTotal) - abs($incomeGroups{TOTAL}{total}) > $ONE_PENNY); + ############################################################################### # # Local variables: -- cgit v1.2.3 From 470ed356be4b92bb2967eab281d187f03691ad48 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 08:41:14 -0500 Subject: Expenses report completed. --- .../non-profit-audit-reports/summary-reports.plx | 101 +++++++++++++++++++++ 1 file changed, 101 insertions(+) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index a30868d5..7b521ccb 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -234,6 +234,7 @@ foreach my $type ('DONATIONS', 'LICENSE ENFORCEMENT', 'CONFERENCES, REGISTRATION', 'CONFERENCES, RELATED BUSINESS INCOME', 'BOOK ROYALTIES & AFFILIATE PROGRAMS', 'ADVERSITING', 'TRADEMARKS', 'INTEREST INCOME', 'OTHER') { + next if ($incomeGroups{$type}{output} =~ /^\s*$/ and $incomeGroups{$type}{total} == $ZERO); print INCOME "\n$type\n", $incomeGroups{$type}{output}, "\n", sprintf($formatStrTotal, "TOTAL $type:", Commify($incomeGroups{$type}{total})); @@ -246,6 +247,106 @@ close INCOME; die "unable to write to income.txt: $!" unless ($? == 0); die "calculated total of $overallTotal does equal $incomeGroups{TOTAL}{total}" if (abs($overallTotal) - abs($incomeGroups{TOTAL}{total}) > $ONE_PENNY); +print STDERR "\n"; + +my %expenseGroups = ('BANKING FEES' => { regex => '^Expenses.*(Banking Fees|Currency Conversion)' }, + 'COMPUTING, HOSTING AND EQUIPMENT' => { regex => '^Expenses.*(Hosting|Computer Equipment)' }, + 'CONFERENCES' => { regex => '^Expenses.*(Conferences|Sprint)' }, + 'DEVELOPER MENTORING' => {regex => '^Expenses.*Mentor' }, + 'LICENSE ENFORCEMENT' => { regex => '^Expenses.*Enforce' }, + 'ACCOUNTING' => { regex => '^Expenses.*(Accounting|Annual Audit)' }, + 'PAYROLL' => { regex => '^Expenses.*Payroll' }, + 'OFFICE' => { regex => '^Expenses.*(Office|Phones)' }, + 'RENT' => { regex => '^Expenses.*Rent' }, + 'SOFTWARE DEVELOPMENT' => { regex => '^Expenses.*Development' }, + 'OTHER PROGRAM ACTIVITY' => {regex => '^Expenses.*Gould' }, + 'ADVOCACY AND PROMOTION' => {regex => '^Expenses.*(Slipstream|Advocacy Merchandise|Promotional)' }, + 'ADVERSITING' => {regex => '^Expenses.*Advertising' }); + +foreach my $type (keys %expenseGroups, 'TRAVEL') { + $expenseGroups{$type}{total} = $ZERO; + $expenseGroups{$type}{output} = ""; +} + +open(EXPENSE, ">", "expense.txt") or die "unable to open expense.txt for writing: $!"; + +my(@fullCommand) = ($LEDGER_BIN, @mainLedgerOptions, '-V', '-X', '$', + '-b', $startDate, '-e', $endDate, + '-F', '%-.80A %22.108t\n', '-s', + 'reg', '/^Expenses/'); + +open(FILE, "-|", @fullCommand) + or die "unable to run command ledger command: @fullCommand: $!"; + +print STDERR ($VERBOSE ? "Running: @fullCommand\n" : "."); + +my $firstTotal = $ZERO; +foreach my $line () { + die "Unable to parse output line from second funds command: $line" + unless $line =~ /^\s*([^\$]+)\s+\$\s*([\-\d\.\,]+)/; + my($account, $amount) = ($1, $2); + $amount = ParseNumber($amount); + $account =~ s/\s+$//; + next if $account =~ /\/ and (abs($amount) <= 0.02); + die "Weird account found, $account, with amount of $amount in expenses command\n" + unless $account =~ /^\s*Expenses:/; + + if ($account =~ /Travel/) { + $expenseGroups{'TRAVEL'}{total} += $amount; + $expenseGroups{'TRAVEL'}{output} .= " $line"; + } else { + my $taken = 0; + foreach my $type (keys %expenseGroups) { + last if $taken; + next if $type eq 'TRAVEL' or $type eq 'OTHER'; + next unless $line =~ /$expenseGroups{$type}{regex}/; + $taken = 1; + $expenseGroups{$type}{total} += $amount; + $expenseGroups{$type}{output} .= " $line"; + } + if (not $taken) { + $expenseGroups{'OTHER'}{total} += $amount; + $expenseGroups{'OTHER'}{output} .= " $line"; + } + } + $firstTotal += $amount; +} +print EXPENSE " EXPENSES\n", + " Between $formattedStartDate and $formattedEndDate\n\n"; +$overallTotal = $ZERO; +$formatStrTotal = "%-90s \$%14s\n"; + +my %verifyAllGroups; +foreach my $key (keys %expenseGroups) { + $verifyAllGroups{$key} = 1; +} +foreach my $type ('PAYROLL', 'SOFTWARE DEVELOPMENT', 'LICENSE ENFORCEMENT', 'CONFERENCES', + 'DEVELOPER MENTORING', 'TRAVEL', 'BANKING FEES', 'ADVOCACY AND PROMOTION', + 'COMPUTING, HOSTING AND EQUIPMENT', 'ACCOUNTING', + 'OFFICE', 'RENT', 'ADVERSITING', 'OTHER PROGRAM ACTIVITY', 'OTHER') { + delete $verifyAllGroups{$type}; + + die "$type is not defined!" if not defined $expenseGroups{$type}; + next if ($expenseGroups{$type}{output} =~ /^\s*$/ and $expenseGroups{$type}{total} == $ZERO); + + print EXPENSE "\n$type\n", + $expenseGroups{$type}{output}, "\n", + sprintf($formatStrTotal, "TOTAL $type:", Commify($expenseGroups{$type}{total})); + $overallTotal += $expenseGroups{$type}{total}; +} + +print EXPENSE "\n\n\n", sprintf($formatStrTotal, "OVERALL TOTAL:", Commify($overallTotal)); + +close EXPENSE; die "unable to write to expense.txt: $!" unless ($? == 0); + +die "GROUPS NOT INCLUDED : ", join(keys(%verifyAllGroups), ", "), "\n" + unless (keys %verifyAllGroups == 0); + +die "calculated total of $overallTotal does equal $firstTotal" + if (abs($overallTotal) - abs($firstTotal) > $ONE_PENNY); + +print STDERR "\n"; + ############################################################################### # # Local variables: -- cgit v1.2.3 From ca359f0606d80160e075100a290e8d05312ac7c9 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 4 Dec 2011 19:47:30 -0500 Subject: First attempt at this cash-receipts-and-disbursments-journals.plx script, based on general-ledger-report.plx The general-ledger-report.plx was originally found in this repository: http://gitorious.org/bkuhn/small-hacks/blobs/master/general-ledger-report.plx And these early commits on cash-receipts-and-disbursments-journals.plx were fro that repository as well, in: http://gitorious.org/bkuhn/small-hacks/blobs/master/cash-receipts-and-disbursments-journals.plx --- .../cash-receipts-and-disbursments-journals.plx | 131 +++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx new file mode 100644 index 00000000..6b704c08 --- /dev/null +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -0,0 +1,131 @@ +#!/usr/bin/perl +# cash-receipts-and-disbursments-journals -*- Perl -*- +# +# Script to generate a General Ledger report that accountants like +# using Ledger. +# +# Copyright (C) 2011, Bradley M. Kuhn +# +# This program gives you software freedom; you can copy, modify, convey, +# and/or redistribute it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program in a file called 'GPLv3'. If not, write to the: +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor +# Boston, MA 02110-1301, USA. + +use strict; +use warnings; + +use Math::BigFloat; +use Date::Manip; + +my $LEDGER_CMD = "/usr/bin/ledger"; + +my $ACCT_WIDTH = 75; + +sub ParseNumber($) { + $_[0] =~ s/,//g; + return Math::BigFloat->new($_[0]); +} + +sub LedgerAcctToFilename($) { + $_[0] =~ s/ /-/g; + $_[0] =~ s/:/-/g; + returen $_[0]; +} + +Math::BigFloat->precision(-2); +my $ZERO = Math::BigFloat->new("0.00"); + +if (@ARGV < 2) { + print STDERR "usage: $0 \n"; + exit 1; +} + +my($beginDate, $endDate, @otherLedgerOpts) = @ARGV; + +my(@chartOfAccountsOpts) = ('--wide-register-format', "%150A\n", '-w', '-s', + '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg'); + +open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) + or die "Unable to run $LEDGER_CMD @chartOfAccountsOpts: $!"; + +my @accounts; +while (my $line = ) { + chomp $line; + $line =~ s/^\s*//; $line =~ s/\s*$//; + push(@accounts, $line); + +} +close(CHART_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; + +my $formattedEndDate = new Date::Manip::Date; +die "badly formatted end date, $endDate" if $formattedEndDate->parse($endDate); +my $oneDayLess = new Date::Manip::Delta; +die "bad one day less" if $oneDayLess->parse("- 1 day"); +$formattedEndDate = $formattedEndDate->calc($oneDayLess); +$formattedEndDate = $formattedEndDate->printf("%Y/%m/%d"); + +foreach my $acct (@accounts) { + next unless ($acct =~ /^(?:Assets|Liabilities)/); + + my $acctFilename = LedgerAcctToFilename($acct); + + foreach my $typeData ({ name => 'disbursements', query => 'a<=0' }, + { name => 'receipts', query => 'a>0' }) { + my $fileNameBase = $acctFilename . '-' . $typeData->{name}; + + print TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; + print CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; + print CSV_OUT '"DATE","CHECK NUM","NAME","ACCOUNT","AMOUNT"', "\n"; + my @entryLedgerOpts = ('-l', $typeData->{query}, + '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'print', $acct); + + open(ENTRY_DATA, "-|", $LEDGER_CMD, @entryLedgerOpts) + or die "Unable to run $LEDGER_CMD @entryLedgerOpts: $!"; + + my $tempFile = "tmp$$"; + + open(ENTRY_OUT, ">", $tempFile) or die "Unable to write $tempFile: $!"; + + while (my $line = ) { print ENTRY_OUT $line; } + close(ENTRY_DATA); die "Error reading ledger output for entries: $!" unless $? == 0; + close(ENTRY_OUT); die "Error writing ledger output for entries to temp file, $tempFile: $!" unless $? == 0; + + my @txtRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', + "%D %-.70P %-.10C %-.80A %18t\n%/%68|%15|%-.80A %18t\n", '-w', '--sort', 'd', + '-b', $beginDate, '-e', $endDate, 'reg'); + + my @csvRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', + '"%D","%C","%P",%A","%t"\n%/|"","","","%A","%t"\n"', '-w', '--sort', 'd', + '-b', $beginDate, '-e', $endDate, 'reg'); + + open(TXT_DATA, "-|", $LEDGER_CMD, @txtRegLedgerOpts) + or die "unable to run ledger command for $fileNameBase.txt: $!"; + + while (my $line = ) { print TEXT_OUT $line; } + close(TXT_DATA); die "Error read from txt ledger command $!" unless $? == 0; + close(TEXT_OUT); die "Error read write text out to $fileNameBase.txt: $!" unless $? == 0; + + open(CSV_DATA, "-|", $LEDGER_CMD, @csvRegLedgerOpts) + or die "unable to run ledger command for $fileNameBase.csv: $!"; + + while (my $line = ) { print CSV_OUT $line; } + close(CSV_DATA); die "Error read from csv ledger command $!" unless $? == 0; + close(CSV_OUT); die "Error read write csv out to $fileNameBase.csv: $!" unless $? == 0; + } +} +############################################################################### +# +# Local variables: +# compile-command: "perl -c cash-receipts-and-disbursments-journals.plx" +# End: + -- cgit v1.2.3 From d817000b828c8ce1808d95cb7fae259fe05630ec Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 4 Dec 2011 20:06:32 -0500 Subject: Various changes to get the script working. --- .../cash-receipts-and-disbursments-journals.plx | 30 ++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) mode change 100644 => 100755 contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx old mode 100644 new mode 100755 index 6b704c08..5dbe7033 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -26,6 +26,7 @@ use warnings; use Math::BigFloat; use Date::Manip; +use File::Temp qw/tempfile/; my $LEDGER_CMD = "/usr/bin/ledger"; @@ -37,9 +38,10 @@ sub ParseNumber($) { } sub LedgerAcctToFilename($) { - $_[0] =~ s/ /-/g; - $_[0] =~ s/:/-/g; - returen $_[0]; + my $x = $_[0]; + $x =~ s/ /-/g; + $x =~ s/:/-/g; + return $x; } Math::BigFloat->precision(-2); @@ -83,36 +85,40 @@ foreach my $acct (@accounts) { { name => 'receipts', query => 'a>0' }) { my $fileNameBase = $acctFilename . '-' . $typeData->{name}; + open(TEXT_OUT, ">", "$fileNameBase.txt") or die "unable to open $fileNameBase.txt: $!"; + open(CSV_OUT, ">", "$fileNameBase.csv") or die "unable to open $fileNameBase.csv: $!"; + print TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; print CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; print CSV_OUT '"DATE","CHECK NUM","NAME","ACCOUNT","AMOUNT"', "\n"; + my @entryLedgerOpts = ('-l', $typeData->{query}, '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'print', $acct); open(ENTRY_DATA, "-|", $LEDGER_CMD, @entryLedgerOpts) or die "Unable to run $LEDGER_CMD @entryLedgerOpts: $!"; - my $tempFile = "tmp$$"; + my($tempFH, $tempFile) = tempfile("cashreportsXXXXXXXX", TMPDIR => 1); - open(ENTRY_OUT, ">", $tempFile) or die "Unable to write $tempFile: $!"; - - while (my $line = ) { print ENTRY_OUT $line; } + while (my $line = ) { print $tempFH $line; } close(ENTRY_DATA); die "Error reading ledger output for entries: $!" unless $? == 0; - close(ENTRY_OUT); die "Error writing ledger output for entries to temp file, $tempFile: $!" unless $? == 0; + $tempFH->close() or die "Error writing ledger output for entries to temp file, $tempFile: $!"; + + goto SKIP_REGISTER_COMMANDS if (-z $tempFile); my @txtRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', "%D %-.70P %-.10C %-.80A %18t\n%/%68|%15|%-.80A %18t\n", '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, 'reg'); my @csvRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', - '"%D","%C","%P",%A","%t"\n%/|"","","","%A","%t"\n"', '-w', '--sort', 'd', + '"%D","%C","%P",%A","%t"\n%/"","","","%A","%t"\n', '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, 'reg'); + open(TXT_DATA, "-|", $LEDGER_CMD, @txtRegLedgerOpts) or die "unable to run ledger command for $fileNameBase.txt: $!"; while (my $line = ) { print TEXT_OUT $line; } - close(TXT_DATA); die "Error read from txt ledger command $!" unless $? == 0; close(TEXT_OUT); die "Error read write text out to $fileNameBase.txt: $!" unless $? == 0; open(CSV_DATA, "-|", $LEDGER_CMD, @csvRegLedgerOpts) @@ -120,7 +126,11 @@ foreach my $acct (@accounts) { while (my $line = ) { print CSV_OUT $line; } close(CSV_DATA); die "Error read from csv ledger command $!" unless $? == 0; + + SKIP_REGISTER_COMMANDS: + close(TXT_DATA); die "Error read from txt ledger command $!" unless $? == 0; close(CSV_OUT); die "Error read write csv out to $fileNameBase.csv: $!" unless $? == 0; + unlink($tempFile); } } ############################################################################### -- cgit v1.2.3 From c7a798be8e7f2ac4c10c70b732cdc20f768eb3c2 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Tue, 6 Dec 2011 09:19:58 -0500 Subject: Fixed output. --- .../cash-receipts-and-disbursments-journals.plx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index 5dbe7033..c1c8d833 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -111,7 +111,7 @@ foreach my $acct (@accounts) { '-b', $beginDate, '-e', $endDate, 'reg'); my @csvRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', - '"%D","%C","%P",%A","%t"\n%/"","","","%A","%t"\n', '-w', '--sort', 'd', + '\n"%D","%C","%P","%A","%t"\n%/"","","","%A","%t"\n', '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, 'reg'); -- cgit v1.2.3 From 586c4eb3b3b93faf048df2e31c339c7459e3df9e Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 12:18:26 -0500 Subject: Use -V to normalize currencies in general-ledger report. --- contrib/non-profit-audit-reports/general-ledger-report.plx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 07f0b9da..dc48a509 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -48,7 +48,7 @@ open(MANIFEST, ">", "MANIFEST") or die "Unable to open MANIFEST for writing: $!" my($beginDate, $endDate, @otherLedgerOpts) = @ARGV; -my(@chartOfAccountsOpts) = ('-F', "%150A\n", '-w', '-s', +my(@chartOfAccountsOpts) = ('-V', '-F', "%150A\n", '-w', '-s', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg'); open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) @@ -97,7 +97,7 @@ print MANIFEST "general-ledger.csv\n"; foreach my $acct (@sortedAccounts) { print GL_TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; - my @acctLedgerOpts = ('-F', + my @acctLedgerOpts = ('-V', '-F', "%(date) %-.10C %-.80P %-.80N %18t %18T\n", '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); open(GL_TEXT_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) @@ -118,7 +118,7 @@ foreach my $acct (@sortedAccounts) { $formatString .= "\n"; print GL_CSV_OUT "\n"; - @acctLedgerOpts = ('-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); + @acctLedgerOpts = ('-V', '-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg', $acct); open(GL_CSV_DATA, "-|", $LEDGER_CMD, @acctLedgerOpts) or die "Unable to run $LEDGER_CMD @acctLedgerOpts: $!"; -- cgit v1.2.3 From 3e634b6d45ef1991350141df22ed038bae8de07e Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 12:18:58 -0500 Subject: Ignore accounts. --- contrib/non-profit-audit-reports/general-ledger-report.plx | 1 + 1 file changed, 1 insertion(+) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index dc48a509..192be350 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -57,6 +57,7 @@ open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) my @accounts; while (my $line = ) { chomp $line; + next if $line =~ /^\s*\<\s*Adjustment\s*\>\s*$/; $line =~ s/^\s*//; $line =~ s/\s*$//; push(@accounts, $line); -- cgit v1.2.3 From 4318c11fd9b94a3508fac7cd7724407f2f7f6645 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 12:19:44 -0500 Subject: Expense report favors Conferences first, then takes Travel as if it were an Other category only after categories have been handled. --- .../non-profit-audit-reports/summary-reports.plx | 29 +++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/summary-reports.plx b/contrib/non-profit-audit-reports/summary-reports.plx index 7b521ccb..7d2267d6 100755 --- a/contrib/non-profit-audit-reports/summary-reports.plx +++ b/contrib/non-profit-audit-reports/summary-reports.plx @@ -291,20 +291,21 @@ foreach my $line () { die "Weird account found, $account, with amount of $amount in expenses command\n" unless $account =~ /^\s*Expenses:/; - if ($account =~ /Travel/) { - $expenseGroups{'TRAVEL'}{total} += $amount; - $expenseGroups{'TRAVEL'}{output} .= " $line"; - } else { - my $taken = 0; - foreach my $type (keys %expenseGroups) { - last if $taken; - next if $type eq 'TRAVEL' or $type eq 'OTHER'; - next unless $line =~ /$expenseGroups{$type}{regex}/; - $taken = 1; - $expenseGroups{$type}{total} += $amount; - $expenseGroups{$type}{output} .= " $line"; - } - if (not $taken) { + my $taken = 0; + # Note: Prioritize to put things under conference expenses if they were for a conference. + foreach my $type ('CONFERENCES', keys %expenseGroups) { + last if $taken; + next if $type eq 'TRAVEL' or $type eq 'OTHER'; + next unless $line =~ /$expenseGroups{$type}{regex}/; + $taken = 1; + $expenseGroups{$type}{total} += $amount; + $expenseGroups{$type}{output} .= " $line"; + } + if (not $taken) { + if ($account =~ /Travel/) { + $expenseGroups{'TRAVEL'}{total} += $amount; + $expenseGroups{'TRAVEL'}{output} .= " $line"; + } else { $expenseGroups{'OTHER'}{total} += $amount; $expenseGroups{'OTHER'}{output} .= " $line"; } -- cgit v1.2.3 From 4f8ea18fec539c6b2e48fa7125bceaa795e899de Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 13:26:01 -0500 Subject: Support selection of string encoding. Allow command line option that permits specification of string encoding, passed to Python's unicode() function. --- contrib/non-profit-audit-reports/csv2ods.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/csv2ods.py b/contrib/non-profit-audit-reports/csv2ods.py index 59571280..2b3024d4 100755 --- a/contrib/non-profit-audit-reports/csv2ods.py +++ b/contrib/non-profit-audit-reports/csv2ods.py @@ -31,7 +31,7 @@ def err(msg): print 'error: %s' % msg sys.exit(1) -def csv2ods(csvname, odsname, verbose = False): +def csv2ods(csvname, odsname, encoding='', verbose = False): if verbose: print 'converting from %s to %s' % (csvname, odsname) doc = ooolib2.Calc() @@ -56,6 +56,8 @@ def csv2ods(csvname, odsname, verbose = False): if len(fields) > 0: for col in range(len(fields)): val = fields[col] + if encoding != '': + val = unicode(val, 'utf8') if len(val) > 0 and val[0] == '$': doc.set_cell_value(col + 1, row, 'currency', val[1:]) else: @@ -92,6 +94,8 @@ def main(): help='csv file to process') parser.add_option('-o', '--ods', action='store', help='ods output filename') + parser.add_option('-e', '--encoding', action='store', + help='unicode character encoding type') (options, args) = parser.parse_args() if len(args) != 0: parser.error("not expecting extra args") @@ -104,7 +108,8 @@ def main(): print '%s: verbose mode on' % program print 'csv:', options.csv print 'ods:', options.ods - csv2ods(options.csv, options.ods, options.verbose) + print 'ods:', options.encoding + csv2ods(options.csv, options.ods, options.verbose, options.encoding) if __name__ == '__main__': main() -- cgit v1.2.3 From df6428f549a3a82d52bb18b1e71b468e35b2c444 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 13:26:27 -0500 Subject: Adapted for use with Ledger 3. Includes forcing of -V so all currency is in default. --- .../cash-receipts-and-disbursments-journals.plx | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx index c1c8d833..346e4064 100755 --- a/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx +++ b/contrib/non-profit-audit-reports/cash-receipts-and-disbursments-journals.plx @@ -4,7 +4,7 @@ # Script to generate a General Ledger report that accountants like # using Ledger. # -# Copyright (C) 2011, Bradley M. Kuhn +# Copyright (C) 2011, 2012 Bradley M. Kuhn # # This program gives you software freedom; you can copy, modify, convey, # and/or redistribute it under the terms of the GNU General Public License @@ -28,7 +28,7 @@ use Math::BigFloat; use Date::Manip; use File::Temp qw/tempfile/; -my $LEDGER_CMD = "/usr/bin/ledger"; +my $LEDGER_CMD = "/usr/local/bin/ledger"; my $ACCT_WIDTH = 75; @@ -54,7 +54,7 @@ if (@ARGV < 2) { my($beginDate, $endDate, @otherLedgerOpts) = @ARGV; -my(@chartOfAccountsOpts) = ('--wide-register-format', "%150A\n", '-w', '-s', +my(@chartOfAccountsOpts) = ('-V', '-F', "%150A\n", '-w', '-s', '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'reg'); open(CHART_DATA, "-|", $LEDGER_CMD, @chartOfAccountsOpts) @@ -90,7 +90,7 @@ foreach my $acct (@accounts) { print TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; print CSV_OUT "\n\"ACCOUNT:\",\"$acct\"\n\"PERIOD START:\",\"$beginDate\"\n\"PERIOD END:\",\"$formattedEndDate\"\n"; - print CSV_OUT '"DATE","CHECK NUM","NAME","ACCOUNT","AMOUNT"', "\n"; + print CSV_OUT '"DATE","CHECK NUM","NAME","ACCOUNT","AMOUNT"'; my @entryLedgerOpts = ('-l', $typeData->{query}, '-b', $beginDate, '-e', $endDate, @otherLedgerOpts, 'print', $acct); @@ -106,12 +106,18 @@ foreach my $acct (@accounts) { goto SKIP_REGISTER_COMMANDS if (-z $tempFile); - my @txtRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', - "%D %-.70P %-.10C %-.80A %18t\n%/%68|%15|%-.80A %18t\n", '-w', '--sort', 'd', + my @txtRegLedgerOpts = ('-f', $tempFile, '-V', '-F', + "%(date) %-.70P %-.10C %-.80A %18t\n", '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, 'reg'); - my @csvRegLedgerOpts = ('-f', $tempFile, '--wide-register-format', - '\n"%D","%C","%P","%A","%t"\n%/"","","","%A","%t"\n', '-w', '--sort', 'd', + my $formatString = '\n"%(date)","%C","%P","%A","%t"\n%/"","","","%A","%t"'; + foreach my $tagField (qw/Receipt Invoice Statement Contract PurchaseOrder Approval Check IncomeDistributionAnalysis CurrencyRate/) { + print CSV_OUT ',"', $tagField, '"'; + $formatString .= ',"%(tag(\'' . $tagField . '\'))"'; + } + $formatString .= "\n"; + print CSV_OUT "\n"; + my @csvRegLedgerOpts = ('-f', $tempFile, '-V', '-F', $formatString, '-w', '--sort', 'd', '-b', $beginDate, '-e', $endDate, 'reg'); -- cgit v1.2.3 From 10d3f5593302b07897f88d7b9c771558af4a2738 Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 14:33:53 -0500 Subject: Print date in a more friendly format. Includes issue of "ends on" date being correct for mere mortals as opposed to being right for Ledger only. --- contrib/non-profit-audit-reports/fund-report.plx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/fund-report.plx b/contrib/non-profit-audit-reports/fund-report.plx index 5b74a606..0c03d009 100755 --- a/contrib/non-profit-audit-reports/fund-report.plx +++ b/contrib/non-profit-audit-reports/fund-report.plx @@ -24,6 +24,7 @@ use strict; use warnings; use Math::BigFloat; +use Date::Manip; my $LEDGER_CMD = "/usr/local/bin/ledger"; @@ -42,6 +43,13 @@ if (@ARGV < 2) { } my($startDate, $endDate, @mainLedgerOptions) = @ARGV; +my $err; +my $formattedEndDate = UnixDate(DateCalc(ParseDate($endDate), ParseDateDelta("- 1 day"), \$err), + "%B %e, %Y"); +die "Date calculation error on $endDate" if ($err); +my $formattedStartDate = UnixDate(ParseDate($startDate), "%B %e, %Y"); +die "Date calculation error on $startDate" if ($err); + # First, get fund list from ending balance my(@ledgerOptions) = (@mainLedgerOptions, '-V', '-X', '$', '-F', "%-.70A %22.108t\n", '-s', @@ -117,14 +125,14 @@ my($totStart, $totEnd) = ($ZERO, $ZERO); foreach my $fund (sort keys %funds) { my $sanityTotal = $funds{$fund}{starting}; - print "Fund: $fund\n", sprintf("%-35s\$%26.2f\n\n", "Balance as of $startDate:", + print "Fund: $fund\n", sprintf("%-35s\$%26.2f\n\n", "Balance as of $formattedStartDate:", $funds{$fund}{starting}); foreach my $type ('Income', 'Expenses', @possibleTypes) { my $formattedType = $type; $formattedType =~ s/^Accrued://; next if $type ne 'Income' and $type ne 'Expenses' and $funds{$fund}{$type} == $ZERO; print sprintf("%19s during period: \$%26.2f\n", $formattedType, $funds{$fund}{$type}); } - print sprintf("\n%-35s\$%26.2f\n", "Balance as of $endDate:", + print sprintf("\n%-35s\$%26.2f\n", "Balance as of $formattedEndDate:", $funds{$fund}{ending}), "\n\n"; # Santity check: if ($funds{$fund}{ending} != @@ -136,8 +144,8 @@ foreach my $fund (sort keys %funds) { $totStart += $funds{$fund}{starting}; $totEnd += $funds{$fund}{ending}; } -print "\n\n\nTotal Restricted Funds as of $startDate: ", sprintf("\$%15.2f\n", $totStart); -print "\nTotal Restricted Funds as of $endDate: ", sprintf("\$%15.2f\n", $totEnd); +print "\n\n\nTotal Restricted Funds as of $formattedStartDate: ", sprintf("\$%15.2f\n", $totStart); +print "\nTotal Restricted Funds as of $formattedStartDate: ", sprintf("\$%15.2f\n", $totEnd); ############################################################################### # # Local variables: -- cgit v1.2.3 From 32e51f65a19d030363f9c5d29472c59b2df0cccd Mon Sep 17 00:00:00 2001 From: "Bradley M. Kuhn" Date: Sun, 25 Nov 2012 14:36:29 -0500 Subject: Verify that files are not duplicated in the MANIFEST. Keep a hash so that file output to the MANIFEST file doesn't have duplicates of the same file name in it. --- contrib/non-profit-audit-reports/general-ledger-report.plx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'contrib') diff --git a/contrib/non-profit-audit-reports/general-ledger-report.plx b/contrib/non-profit-audit-reports/general-ledger-report.plx index 192be350..d1c92975 100755 --- a/contrib/non-profit-audit-reports/general-ledger-report.plx +++ b/contrib/non-profit-audit-reports/general-ledger-report.plx @@ -96,6 +96,7 @@ print MANIFEST "general-ledger.txt\n"; open(GL_CSV_OUT, ">", "general-ledger.csv") or die "unable to write general-ledger.csv: $!"; print MANIFEST "general-ledger.csv\n"; +my %manifest; foreach my $acct (@sortedAccounts) { print GL_TEXT_OUT "\n\nACCOUNT: $acct\nFROM: $beginDate TO $formattedEndDate\n\n"; my @acctLedgerOpts = ('-V', '-F', @@ -131,7 +132,8 @@ foreach my $acct (@sortedAccounts) { my $file = $1; next if $file =~ /^\s*$/; warn "$file does not exist and/or is not readable" unless -r $file; - print MANIFEST "$file\n"; + print MANIFEST "$file\n" if not defined $manifest{$file}; + $manifest{$file} = $line; } } close(GL_CSV_DATA); die "error reading ledger output for chart of accounts: $!" unless $? == 0; -- cgit v1.2.3