home *** CD-ROM | disk | FTP | other *** search
/ PC World 2000 February / PCWorld_2000-02_cd.bin / live / usr / X11R6 / lib / X11 / cbb / contrib / recur.pl < prev    next >
Perl Script  |  1998-10-07  |  10KB  |  355 lines

  1. #!/usr/bin/perl
  2. #  recur.pl - Manage and update recurring transactions in a .cbb file.
  3. #
  4. #  Written by Curtis Olson.  Started January 16, 1996.
  5. #
  6. #  Copyright (C) 1996  Curtis L. Olson  - curt@sledge.mn.org
  7. #
  8. #  This program is free software; you can redistribute it and/or modify
  9. #  it under the terms of the GNU General Public License as published by
  10. #  the Free Software Foundation; either version 2 of the License, or
  11. #  (at your option) any later version.
  12. #
  13. #  This program is distributed in the hope that it will be useful,
  14. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. #  GNU General Public License for more details.
  17. #
  18. #  You should have received a copy of the GNU General Public License
  19. #  along with this program; if not, write to the Free Software
  20. #  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. #
  22. # $Id: recur.pl,v 2.9 1998/08/14 14:28:44 curt Exp $
  23. # (Log is kept at end of this file)
  24.  
  25.  
  26. use strict;    # don't take no guff
  27.  
  28. require "timelocal.pl";
  29.  
  30.  
  31. package CBB;
  32.  
  33. my($key, $date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total);
  34. my($recur, $result, $update);
  35. my($future_days, $secs_per_day, $cur_date, $account);
  36.  
  37.  
  38. # specify the installed location of the necessary pieces.
  39. $CBB::cbb_incl_dir = "/usr/X11R6/lib/X11/cbb";
  40. unshift(@INC, $CBB::cbb_incl_dir);
  41.  
  42. require "memorized.pl";
  43. require "categories.pl";
  44. require "common.pl";
  45. require "engine.pl";
  46. require "memorized.pl";
  47.  
  48.  
  49. ($#ARGV >= 0) || die "Usage: $0 account";
  50.  
  51.  
  52. # how many days to plan ahead
  53. #$future_days = 366;        # approximately 1 year;
  54. $future_days = 92;        # approximately 3 months;
  55. $secs_per_day = 86400;        # seconds per day;
  56.  
  57. $cur_date = &raw_date;
  58.  
  59. $account = shift(@ARGV);
  60. if ( $account !~ /\.cbb$/ ) {
  61.     die "Account name must end in '.cbb'\n";
  62. }
  63.  
  64. (&load_trans($account) eq "ok") || die "Cannot open account:  $account";
  65.  
  66. #-----------------------------------------------------------------------
  67. # Traverse all transactions and perform the following steps on entries with
  68. # $cleared = "?":
  69. #   1.  If date has passed, change $cleared to "!"
  70. #   2.  If date is present or future, delete entry.  These entries will be
  71. #       reinserted later.
  72. #-----------------------------------------------------------------------
  73.  
  74. print "Updating/deleting current recurring transactions:  ";
  75.  
  76. $result = &first_trans();
  77. while ( $result ne "none" ) {
  78.     ($key, $date, $check, $desc, $debit, $credit, $cat, $com, $cleared,
  79.      $total) = split(/\t/, $result);
  80.  
  81.     if ( $cleared eq "?" ) {
  82.     if ( $date < $cur_date ) {
  83.         # set $cleared to "!"
  84.         # print "updating - $result\n";
  85.         print ".";
  86.         $update = "$key\t$date\t$check\t$desc\t$debit\t$credit\t".
  87.         "$cat\t$com\t!\t$total";
  88.         &update_trans($update);
  89.     } else {
  90.         # delete
  91.         # print "deleting - $result\n";
  92.         print ".";
  93.         &delete_trans($key);
  94.     }
  95.     }
  96.     
  97.     $result = &next_trans();
  98. }
  99.  
  100. print "\n";
  101.  
  102.  
  103. #-----------------------------------------------------------------------
  104. # Now add in all future recurring transactions
  105. #-----------------------------------------------------------------------
  106.  
  107. print "Adding in future recurring transactions:  ";
  108.  
  109. # print "$account - " . &file_root($account) . "\n";
  110. $recur = &file_root($account) . ".rcr";    # 
  111. # print "$recur\n";        # 
  112. open(RECUR, "<$recur") || die "Cannot open:  $recur";
  113.  
  114. while ( <RECUR> ) {
  115.     # print length($_) . " - $_";
  116.     if ( m/^#/ || ! m/\t/ ) {
  117.     # ignore this line
  118.     } else {
  119.     # Ok, we found one!
  120.     &add_all_recurs($_);
  121.     }
  122. }
  123.  
  124. close(RECUR);
  125.  
  126. # Finally, save the result
  127.  
  128. (&save_trans("$account") eq "ok") || die "Cannot save account:  $account";
  129.  
  130.  
  131. #-----------------------------------------------------------------------
  132. # Supporting Routines
  133. #-----------------------------------------------------------------------
  134.  
  135. # Add all recuring transactions specified
  136.  
  137. sub add_all_recurs {
  138.     my($line) = @_;
  139.     my($days, $months, $years, $desc, $debit, $credit, $com, $cat, $begindate, 
  140.        $cutoff);
  141.     my($date, $dates, $key, $trans, @DATES);
  142.  
  143.     chop($line);
  144.  
  145.     ($days, $months, $years, $desc, $debit, $credit, $com, $cat,
  146.      $begindate, $cutoff) = split(/\t/, $line);
  147.  
  148.     if ( ($begindate eq "") || ($begindate < $cur_date) ) {
  149.     $begindate = $cur_date;
  150.     }
  151.  
  152.     if ( $cutoff eq "" ) {
  153.     $cutoff = &calc_cutoff();
  154.     }
  155.  
  156.     # print "cutoff = $cutoff\n";
  157.  
  158.     if ( ($days < 32) || ($days =~ m/,/) || ($days eq "*") ) {
  159.     # type 1 recurring transaction
  160.     $dates = &gen_dates_1($days, $months, $years, $begindate, $cutoff);
  161.     # print "$dates\n";
  162.     } else {
  163.     # type 2 recurring transaction
  164.     $dates = &gen_dates_2($days, $months, $years, $begindate, $cutoff);
  165.     # print "$dates\n";
  166.     }
  167.  
  168.     @DATES = split(/,/, $dates);
  169.  
  170.     foreach $date (@DATES) {
  171.     print ".";
  172.     $trans = "$date\t\t$desc\t$debit\t$credit\t$cat\t$com\t?\t";
  173.         if ($cat =~ m/^\[/) {
  174.             $key = &create_xfer($trans);
  175.         } else {
  176.             $key = &create_trans($trans);
  177.         }
  178.     }
  179. }
  180.  
  181. print "\n";
  182.  
  183.  
  184. # Calculate cutoff date
  185.  
  186. sub calc_cutoff {
  187.     my($csec,$cmin,$chour,$cmday,$cmon,$cyear,$cwday,$cyday,$cisdst) = 
  188.         localtime(time);
  189.     my($cutoff_secs, $today_secs);
  190.  
  191.     # print "calling timelocal with cmon = $cmon\n";
  192.     $today_secs = &main'timelocal(0, 0, 0, $cmday, $cmon, $cyear);
  193.     $cutoff_secs = $today_secs + ($future_days * $secs_per_day);
  194.  
  195.     ($csec,$cmin,$chour,$cmday,$cmon,$cyear,$cwday,$cyday,$cisdst) = 
  196.         localtime($cutoff_secs);
  197.  
  198.     return ¢ury() . $cyear . &pad($cmon + 1) . &pad($cmday);  
  199. }
  200.  
  201.  
  202. # Generate a list of type 1 dates
  203.  
  204. sub gen_dates_1 {
  205.     my($days, $months, $years, $begindate, $cutoff) = @_;
  206.     my($csec,$cmin,$chour,$cmday,$cmon,$cyear,$cwday,$cyday,$cisdst) = 
  207.         localtime(time);
  208.     my($ldates) = "";
  209.     my($day, $month, $year, $tdays, $tmonth, $tyear);
  210.     my($this_date, $month_end, $next_month);
  211.     my(@DAYS, @MONTHS, @YEARS);
  212.  
  213.     # print "$days - $months - $years\n";
  214.  
  215.     if ( $months eq "*" ) {
  216.     $months = "1,2,3,4,5,6,7,8,9,10,11,12";
  217.     }
  218.     @MONTHS = split(/,/, $months);
  219.  
  220.     if ( $years eq "*" ) {
  221.     $years = "$cyear," . ($cyear+1);
  222.     }
  223.     @YEARS = split(/,/, $years);
  224.  
  225.     foreach $year (@YEARS) {
  226.     foreach $month (@MONTHS) {
  227.         # print ¢ury() . $year . &pad($month) . "\n";
  228.         if ( $month == 12 ) {
  229.         $tyear = $year + 1; $tmonth = 1;
  230.         } else {
  231.         $tyear = $year; $tmonth = $month + 1;
  232.         }
  233.         # note in perl the months start at 0 ... :(
  234.         # print "calling timelocal with tmonth = $tmonth \n";
  235.         $next_month = &main'timelocal(0, 0, 0, 1, ($tmonth - 1), $tyear);
  236.         # subtract the number of seconds in a day to get the last
  237.         # day of the previous month
  238.         $month_end = $next_month - $secs_per_day;
  239.         ($csec,$cmin,$chour,$cmday,$cmon,$cyear,$cwday,$cyday,$cisdst) = 
  240.         localtime($month_end);
  241.  
  242.         if ( $days eq "*" ) {
  243.         $tdays = "1";
  244.         $day = 2;
  245.         while ( $day <= $cmday ) {
  246.             $tdays .= "," . $day;
  247.             $day++;
  248.         }
  249.         } else {
  250.         $tdays = $days;
  251.         $tdays =~ s/last/$cmday/;
  252.         }
  253.  
  254.         # print "$tdays\n";
  255.  
  256.         @DAYS = split(/,/, $tdays);
  257.         foreach $day (@DAYS) {
  258.         $this_date = ¢ury() . $year . &pad($month) . &pad($day);
  259.         if ( ($this_date >= $begindate) && ($this_date <= $cutoff) ) {
  260.             # print "$this_date\n";
  261.             if ( $ldates eq "" ) {
  262.             $ldates = $this_date;
  263.             } else {
  264.             $ldates .= "," . $this_date;
  265.             }
  266.         }
  267.         }
  268.     }
  269.     }
  270.  
  271.     return $ldates;
  272. }
  273.  
  274.  
  275. # Generate a list of type 2 dates
  276.  
  277. sub gen_dates_2 {
  278.     my($start, $incr, $junk, $begindate, $cutoff) = @_;
  279.     my($ldates) = "";
  280.     my($csec,$cmin,$chour,$cmday,$cmon,$cyear,$cwday,$cyday,$cisdst);
  281.     my($scentury, $syear, $smonth, $sday) = 
  282.     $start =~ /(\d\d)(\d\d)(\d\d)(\d\d)/;
  283.     my($secs, $sincr, $start_secs, $this_date);
  284.  
  285.     # print "$syear - $smonth - $sday\n";
  286.  
  287.     # print "calling timelocal with smonth = $smonth\n";
  288.     $start_secs = &main'timelocal(0, 0, 0, $sday, ($smonth - 1), $syear);
  289.     $sincr = $incr * $secs_per_day;
  290.  
  291.     $secs = $start_secs;
  292.     ($csec,$cmin,$chour,$cmday,$cmon,$cyear,$cwday,$cyday,$cisdst) = 
  293.     localtime($secs);
  294.     $this_date = ¢ury() . $cyear . &pad($cmon + 1) . &pad($cmday);
  295.     while ( $this_date <= $cutoff ) {
  296.     if ( $this_date >= $begindate ) {
  297.         if ( $ldates eq "" ) {
  298.         $ldates = $this_date;
  299.         } else {
  300.         $ldates .= "," . $this_date;
  301.         }
  302.         # print "$this_date\n";
  303.     }
  304.     $secs += $sincr;
  305.     ($csec,$cmin,$chour,$cmday,$cmon,$cyear,$cwday,$cyday,$cisdst) = 
  306.         localtime($secs);
  307.     $this_date = ¢ury() . $cyear . &pad($cmon + 1) . &pad($cmday);
  308.     }
  309.  
  310.     return $ldates;
  311. }
  312.  
  313.  
  314. #----------------------------------------------------------------------------
  315. # $Log: recur.pl,v $
  316. # Revision 2.9  1998/08/14 14:28:44  curt
  317. # Added desc-pie graph.
  318. # Added option to eliminate splash screen.
  319. # Other misc. tweaks and bug fixes.
  320. #
  321. # Revision 2.8  1997/02/28 21:21:58  curt
  322. # Fixed some problems introduced by using "use strict"
  323. #
  324. # Revision 2.7  1997/02/19 18:09:09  curt
  325. # Fixed some residual oversites from switching to "use strict".
  326. #
  327. # Revision 2.6  1997/01/18 17:26:39  curt
  328. # Added "use strict" pragma to enforce good scoping habits.
  329. #
  330. # Revision 2.5  1996/10/03 04:49:08  curt
  331. # Fixed an inconsistency in &raw_date() in common.pl (with how it was
  332. # called.)
  333. #
  334. # Version now is 0.67-beta-x
  335. #
  336. # Revision 2.4  1996/10/03 03:53:42  curt
  337. # CBB now determines the current century automatically ... no need for it
  338. # to be hard coded.  Removed all hardcoded instances of the century (especially
  339. # in reports.pl and recur.pl)
  340. #
  341. # Added an optional --debug flag to the invocation of CBB.
  342. #
  343. # Revision 2.3  1996/09/17 19:41:10  curt
  344. # Add support for recurring transfer transactions.
  345. #
  346. # Revision 2.2  1996/07/13 02:58:24  curt
  347. # Misc. changes.
  348. #
  349. # Revision 2.1  1996/02/27  05:36:04  curt
  350. # Just stumbling around a bit with cvs ... :-(
  351. #
  352. # Revision 2.0  1996/02/27  04:43:14  curt
  353. # Initial 2.0 revision.  (See "Log" files for old history.)
  354.