file format

Jason Rennie jrennie@ai.mit.edu
Sun, 25 Mar 2001 11:42:10 -0500


This is a multipart MIME message.

--==_Exmh_-17602499250
Content-Type: text/plain; charset=us-ascii

Hi Dave,

dave@krondo.com said:
> But since you're using perl, you might check out the perl interface
> that comes with GnuCash 1.4.x. It is used by gnc-prices. You don't
> have to parse anything :) 

Thanks again for the pointer.  It was a breeze to go from the gnc-prices
script to a report-producing perl script. :)  I'm including the script
that I've produced in case anyone else is looking for something like what
I wanted.

Jason

--==_Exmh_-17602499250
Content-Type: text/plain ; name="gnc-report.perl"; charset=us-ascii
Content-Description: gnc-report.perl
Content-Disposition: attachment; filename="gnc-report.perl"

#!/usr/bin/perl -w

# Produce average monthly expenditures by category

# Written by Jason Rennie <jrennie@ai.mit.edu>, March 2001

use lib '/usr/share/gnucash/perl';
use lib '/usr/lib/gnucash/perl';
use gnucash;
use strict;

my $gncFile;
my (undef, undef, undef, $mday, $month, $year, undef, undef, undef) =
    localtime (time);
$year += 1900;
$month++;
my $endDay = $mday;
my $endMonth = $month;
my $endYear = $year;
my $startDay = $endDay;
my $startMonth = $endMonth;
my $startYear = $endYear-1;
my $defaultExpr = 1;
my @acctExpr = ("Liabilites:Loans",
		"Expenses");

parseArgs(@ARGV);
my $months = monthDiff ($startMonth, $startYear, $endMonth, $endYear);
my $startTime = gnucash::xaccDMYToSec ($startDay, $startMonth, $startYear);
my $endTime = gnucash::xaccDMYToSec ($endDay, $endMonth, $endYear);
die "End time before start time" if ($endTime < $startTime);

print "Date: $month/$mday/$year\n";
print "Period: $startMonth/$startDay/$startYear to $endMonth/$endDay/$endYear\n";
print "Months: $months\n";

# open the file, read all of the accounts
my $sess = gnucash::xaccMallocSession ();
my $grp = gnucash::xaccSessionBeginFile ($sess, $gncFile);

die "failed to read file $ARGV[0], maybe its locked? " if (! $grp);

# get a flat list of accounts in the file
my @acctlist = &accountList ($grp);

printf "%50s    Monthly    # trans\n\n", "Account";

# loop over the accounts, look for stock and mutual funds.
foreach my $acct (@acctlist)
{
    my $match = 0;
    my $name = gnucash::xaccAccountGetFullName ($acct, ":");
    foreach my $expr (@acctExpr) {
	$match = 1 if ($name =~ m/$expr/i);
    }
    #print $name, "\n";#
	#next;#
    next if (!$match);

    my $sCount = gnucash::xaccAccountGetNumSplits ($acct);
    my $sum = 0;

    for (my $si=0; $si < $sCount; $si++) {
	my $split = gnucash::xaccAccountGetSplit ($acct, $si);
	my $trans = gnucash::xaccSplitGetParent ($split);
	my $time = gnucash::xaccTransGetDate ($trans);
	next if ($time < $startTime or $time > $endTime);
	my $value = gnucash::xaccSplitGetValue ($split);
	$sum += $value;
    }
    next if ($sum < 1 and $sum > -1);
    $sum /= $months;
    printf "%50s    \$%7.2f   %d\n", $name, int($sum*100)/100, $sCount;
}

gnucash::xaccSessionEnd ($sess);


sub accountList
{
  my ($grp) = @_;
  my $naccts = gnucash::xaccGroupGetNumAccounts ($grp);
  my @acctlist;

  for (my $n=0; $n < $naccts; $n++) {
      my @foo = gnucash::xaccGetAccounts ($grp);
      my $acct = gnucash::xaccGroupGetAccount ($grp, $n);
      push @acctlist, $acct;
      
      if (my $children = gnucash::xaccAccountGetChildren ($acct)) {
	  my @childlist = accountList ($children);
	  push @acctlist, @childlist;
      }
  }
  return (@acctlist);
}

sub monthDiff
{
    my ($monthStart, $yearStart, $monthEnd, $yearEnd) = @_;
    die "Start date must be before end date"
	if ($yearStart > $yearEnd
	    or ($yearStart == $yearEnd and $monthStart > $monthEnd));

    my $diff = $monthEnd - $monthStart;
    $diff += ($yearEnd - $yearStart)*12;
    return $diff;
}

sub parseArgs
{
    while ($_ = shift) {
	if ($_ eq "-h" or $_ eq "-?") {
	    usage();
	} elsif ($_ eq "-m") {
	    my $span = shift;
	    die "Argument to -m must be > 0" if ($span <= 0);
	    $startYear = $endYear+int(($endMonth - $span - 12)/12);
	    $startMonth = $endMonth+12*($endYear-$startYear)-$span;
	} elsif ($_ eq "-e") {
	    my $date = shift;
	    die "Wrong date format given to -e" if (!(my ($month, $mday, $year) = ($date =~ m,(\d+)/(\d+)/(\d+),)));
	    $endMonth = $month;
	    $endDay = $mday;
	    $year += 1900 if ($year > 50 and $year < 100);
	    $year += 2000 if ($year <= 50);
	    $endYear = $year;
	} elsif ($_ eq "-s") {
	    my $date = shift;
	    die "Wrong date format given to -s" if (!(my ($month, $mday, $year) = ($date =~ m,(\d+)/(\d+)/(\d+),)));
	    $startMonth = $month;
	    $startDay = $mday;
	    $year += 1900 if ($year > 50 and $year < 100);
	    $year += 2000 if ($year <= 50);
	    $startYear = $year;
	} elsif ($_ eq "-r") {
	    my $regex = shift;
	     if ($defaultExpr) {
		 @acctExpr = ($regex);
		 $defaultExpr = 0;
	     } else {
		 push @acctExpr, $regex;
	     }
	} else {
	    if (!defined($gncFile)) {
		$gncFile = $_;
	    } else {
		usage();
	    }
	}	    
    }
    if (!defined($gncFile)) {
	print STDERR "<gnucash-filename> required.";
	usage();
    }
}

sub usage
{
    print STDERR "$0 [options] <gnucash-filename>\n";
    print STDERR "\n";
    print STDERR "\t-m NUM\tNumber of months to span.\n";
    print STDERR "\t-e MM/DD/YYYY\tEnding date.\n";
    print STDERR "\t-s MM/DD/YYYY\tStarting date.\n";
    print STDERR "\t-r EXPR\tRegular expression for matching account name.\n";
    print STDERR "\t\tUse -r multiple times for multiple expressions.\n";
    exit(1);
}

--==_Exmh_-17602499250--