Dylan Doxey

NAME

Finance::Budget - A module for helping you predict the effectiveness of your budget.

SYNOPSIS

  use Finance::Budget;

  my $budget = Finance::Budget->new(
      {   days              => 365,
          opening_balance   => 123.01,
          transaction_types => [
              {   category   => 'PAYCHECK',
                  amount     => 1234.56,
                  recurrence => '0:0:2*4:0:0:0', # every second Thursday
              },
              {   category   => 'Visa',
                  amount     => -100.00,
                  recurrence => '0:1*0:0:0:0:0', # first of every month
              },
              {   category   => 'Cox',
                  amount     => -101.01,
                  recurrence => '0:1*0:15:0:0:0', # fifteenth of every month
              },
              {   category   => 'Mortgage',
                  amount     => -1000.10,
                  recurrence => '0:1*0:0:0:0:0',
              },
              {   category   => 'Water',
                  amount     => -150.00,
                  recurrence => '0:3*0:1:0:0:0', # first of every third month
              },
          ],
          exceptions => [
              {   category => 'Visa',
                  amount   => 0.00,
                  date     => '12/20/2016',
              },
              {   category => 'Cox',
                  amount   => 0.00,
                  date     => '01/01/2017',
              },
              {   category => 'Mortgage',
                  amount   => 0.00,
                  date     => '01/01/2017',
              },
          ],
          recent_history => [
              qq{"Date","No.","Description","Debit","Credit"},
              qq{"12/28/2016","","ACH Trans - Big Plastic","100.00",""},
              qq{"12/27/2016","","ACH Trans - COX CABLE","101.01",""},
              qq{"12/26/2016","","ACH Trans - US BANK MTG","1000.10",""},
              qq{"12/01/2016","","ACH Trans - Waters R Us","150.00",""},
              qq{"12/22/2016","","Deposit - Employer Inc","","1234.56"},
          ],
          categorizer => {
              'PAYCHECK' => [
                  qr{ employer \s inc }xmsi
              ],
              'Visa' => [
                  qr{ big \s plastic }xmsi
              ],
              'Cox' => [
                  qr{ cox \s cable }xmsi,
                  qr{ cox \s communications }xmsi,
              ],
              'Mortgage' => [
                  qr{ us \s bank \s mtg }xmsi
              ],
              'Water' => [
                  qr{ waters \s r \s us }xmsi
              ]
          }
      }
  );

  printf "Opening Balance: % 25s\n",
      $budget->opening_balance();

  while ( my $transaction = $budget->next() )
  {
      print "$transaction\n"
        if $transaction != 0;
  }

  my $chokepoints = $budget->get_chokepoints();

  printf "\nEye of the needle:\n%s\n\n",
      $chokepoints->eye();

  printf "Chokepoints:\n";

  while ( my $point = $chokepoints->next() )
  {
      die "negative chokepoint: $point\n"
          if $point < 0;

      print "$point\n";
  }

DESCRIPTION

This module consumes information about your budget planning and then creates a series of transactions to project what lays ahead.

This can be useful when considering taking on a new car payment or making a big purchase. For example, spending $300 today might have unexpected ramifications 90 days from now. This can also be handy in fine tuning your budget to ensure that it is sustainable.

Check out budget.pl in the demo directory of this project.

CONSTRUCTOR

PARAMETERS

days

The number of days to project into the future. The default is 365.

date_format

The format that the transactions will use on stringafication. The default is '%m/%d/%Y'.

currency_symbol

Set any string as a currency symbol. The default is '$'.

markup_callback

This is a code reference that gets invoked for each transaction stringafication event. You can use this to format the output any way you like.

The callback receives as the first argument a hash ref like:

  {   date_str    => '...',
      title       => '...',
      amount      => '$...',
      balance_str => '...',
      string      => '...',
      date        => <Date::Manip::Date object>,
      category    => '...',
      cents       => 0,
  }

The callback retuns a formatted string. The default just returns the 'string' value.

opening_balance

The opening blanace, in dollars, of your checking account. The default is 0.

transaction_types

This is a list of transaction type descriptor hashes. Each descriptor has three attributes:

  {   category   => 'Foobar',        # category name
      amount     => -1.00,           # dollar amount -/+
      recurrence => '0:1*0:0:0:0:0', # Date::Manip::Recur string
  }

This field also accepts a data filename which will be read using the Perl do() function.

exceptions

Use this to define one-off exceptions. For example, your electric utilty bill might generally be $100.00. But you happen to know the next payment will be exactly $87.42.

So, you can define an exception:

  {   category => 'Electric',
      amount   => -87.42,
      date     => '02/01/2017',  # parsable by Date::Manip::Date
  }

This field also accepts a data filename which will be read using the Perl do() function.

recent_history

This is a list of CSV lines that are scanned for the most recent occurrence date for each transaction type. These dates are important because they are the 'base date' for each recurring transaction. (See Date::Manip::Recur)

Each CSV line is expected to have a 'date' and a 'description' field as given by the first CSV line. This happens to be exactly what my financial institution provides when I download a CSV file from my online banking site.

This field also accepts a CSV filename which will be slurped into memory.

categorizer

This option accepts a hash of category names mapped to one of two things:

  1. An array ref of regexes. Each regex will be applied to the 'description' in the recent history data. When a match is made that category is applied.

  2. A code ref for a function that returns true if the 'description' applies to this category.

There doesn't need to be a categorizer entry for every single transaction type. For these cases, the category will be guessed when an otherwise uncategorized event matches the exact dollar and non-zero cent value of a transaction type. For example, a particular loan payment could be identified because you've decided to always define that transaction type with an amount of $100.42.

METHODS

opening_balance()

Returns a stringified version of the opening balance (supplied in the constructor).

next()

Get the next transaction.

get_chokepoints()

Returns a chokepoint iterator.

get_last_occurences()

Returns a hash ref mapping of categories and the last time each one occurred as parsed from the recent history.

This might be helpful for debugging your categorizers.

TRANSACTIONS

Each transaction represents one event in your budget lifespan.

You'll probably just be satisified to print each "$transaction" in its stringified form, which uses the markup callback you provide.

The transaction object also offers some getter methods.

get_date()
get_category()
get_amount()
get_balance()

The transaction objects can be interpolated into strings and they can be used in numeric comparisons.

  print "$transaction\n"
      if $transaction != 0;

CHOKEPOINTS

The chokepoints are the balance minima between the significant expenses and the significant income events. You might be interested in iterating through these to see where you're going to run into trouble.

The chokepoint objects can be interpolated into strings and they can be used in numeric comparisons.

  die "negative chokepoint: $point\n"
      if $point < 0;

eye()

This is the "eye" as in threading the needle -- the smallest of the chokepoints.

next()

Get the next chokepoint.

SEE ALSO

  Date::Manip::Recur
  Text::CSV

AUTHOR

Dylan Doxey, <dylan@cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2017 by Dylan Doxey

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.22.1 or, at your option, any later version of Perl 5 you may have available.