#!/usr/local/bin/perl -Tw # # bill: Bill customer(s) # # Usage: bill [ -c [ i ] ] [ -d 'date' ] [ -b ] # # Bills all customers. # # Adds record to /dbin/cust_bill and /dbin/cust_pay (if payment made - # CARD & COMP), prints invoice / charges card etc. # # -c: Turn on collecting (you probably want this). # # -i: real-time billing (as opposed to batch billing). only relevant # for credit cards. # # -d: Pretent it's 'date'. Date is in any format Date::Parse is happy with, # but be careful. # # ## n/a ## -b: send batch when done billing # # ivan@voicenet.com sep/oct 96 # # separated billing and collections, cleaned up code. # ivan@voicenet.com 96-nov-11 # # added -d option # ivan@voicenet.com 96-nov-13 # # added -v option and started to implement it, added 'd:' to getopts call # (oops!) # ivan@voicenet.com 97-jan-2 # # added more debug messages, moved some searches to fssearch.pl library (for # speed) # rewrote "all customer" finder to know about bill dates, for speed. # ivan@voicenet.com 97-jan-8 # # thought about it a while, and removed passing of the -d option to collect...? # ivan@voicenet.com 97-jan-14 # # make all -v stuff STDERR # ivan@voicenet.com 97-feb-4 # # added pkgnum as argument to program from /db/part_pkg, with kludge for the # "/bin/echo XX" 's already there. # ivan@voicenet.com 97-feb-23 # # - general cleanup # - customers who are suspended can still be billed for the setup fee # - cust_pkg record is re-read after the package setup fee program is run. # this way, # that program can modify the record (for example, to start accounts off # suspended) # (best to think four or five times before modifying anything else!) # ivan@voicenet.com 97-feb-26 # # don't bill recurring fee if its not time! (was removed) # ivan@voicenet.com 97-mar-6 # # added -b option, send batch when done billing. # ivan@voicenet.com 97-apr-4 # #insecure dependency on line 179ish below needs to be fixed before bill is #used setuid # ivan@voicenet.com 97-jun-2 # # removed running of setup program (depriciated) # ivan@voicenet.com 97-jul-21 # # rewrote for new API, removed option to specify custnums (use FS::Bill # instead), removed -v option (?) # ivan@voicenet.com 97-jul-22 - 23 - 25 -28 # (need to add back in email stuff, look in /home/ivan/old/dbin/collect) # # s/suidsetup/adminsuidsetup/, s/FS::Search/FS::Record/, added some batch # exporting stuff (which still needs to be generalized) and removed &idiot # ivan@sisd.com 98-may-27 # setup use strict; use Fcntl qw(:flock); use Date::Parse; use Getopt::Std; use FS::UID qw(adminsuidsetup swapuid); use FS::Record qw(qsearch qsearchs); use FS::Bill; my($batchfile)="/var/spool/freeside/batch"; my($batchlock)="/var/spool/freeside/batch.lock"; adminsuidsetup; &untaint_argv; #what it sounds like (eww) use vars qw($opt_b $opt_c $opt_i $opt_d); getopts("bcid:"); #switches #we're at now now (and later). my($time)= $main::opt_d ? str2time($main::opt_d) : $^T; # find packages w/ bill < time && cancel != '', and create corresponding # customer objects my($cust_main,%saw); foreach $cust_main ( map { if ( ( $_->getfield('bill') || 0 ) <= $time && !$saw{ $_->getfield('custnum') }++ ) { qsearchs('cust_main',{'custnum'=> $_->getfield('custnum') } ); } else { (); } } qsearch('cust_pkg',{'cancel'=>''}) ) { # and bill them print "Billing customer #" . $cust_main->getfield('custnum') . "\n"; bless($cust_main,"FS::Bill"); my($error); $error=$cust_main->bill('time'=>$time); warn "Error billing, customer #" . $cust_main->getfield('custnum') . ":" . $error if $error; if ($main::opt_c) { $error=$cust_main->collect('invoice_time'=>$time, 'batch_card' => $main::opt_i ? 'no' : 'yes', ); warn "Error collecting customer #" . $cust_main->getfield('custnum') . ":" . $error if $error; #sleep 1; } } #if ($main::opt_b) { # # die "Batch still waiting for reply? ($batchlock exists)\n" if -e $batchlock; # open(BATCHLOCK,"+>>$batchlock") or die "Can't open $batchlock: $!"; # select(BATCHLOCK); $|=1; select(STDOUT); # unless ( flock(BATCHLOCK,,LOCK_EX|LOCK_NB) ) { # seek(BATCHLOCK,0,0); # my($pid)=; # chop($pid); # die "Is a batch running? (pid $pid)\n"; # } # seek(BATCHLOCK,0,0); # print BATCHLOCK $$,"\n"; # # ( open(BATCH,">$batchfile") # and flock(BATCH,LOCK_EX|LOCK_NB) # ) or die "Can't open $batchfile: $!"; # # my($cust_pay_batch); # foreach $cust_pay_batch (qsearch('cust_pay_batch',{})) { # print BATCH join(':', # $_->getfield('cardnum'), # $_->getfield('exp'), # $_->getfield('amount'), # $_->getfield('payname') # || $_->getfield('first'). ' '. $_->getfield('last'), # "Description", # $_->getfield('zip'), # ),"\n"; # } # # flock(BATCH,LOCK_UN); # close BATCH; # # flock(BATCHLOCK,LOCK_UN); # close BATCHLOCK; #} # subroutines sub untaint_argv { foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV $ARGV[$_] =~ /^([\w\-\/]*)$/ || die "Illegal arguement \"$ARGV[$_]\""; $ARGV[$_]=$1; } }