diff options
Diffstat (limited to 'FS/bin')
-rw-r--r-- | FS/bin/freeside-adduser | 57 | ||||
-rwxr-xr-x | FS/bin/freeside-apply-credits | 21 | ||||
-rwxr-xr-x | FS/bin/freeside-bill | 128 | ||||
-rwxr-xr-x | FS/bin/freeside-cc-receipts-report | 231 | ||||
-rwxr-xr-x | FS/bin/freeside-credit-report | 184 | ||||
-rwxr-xr-x | FS/bin/freeside-daily | 90 | ||||
-rwxr-xr-x | FS/bin/freeside-email | 61 | ||||
-rwxr-xr-x | FS/bin/freeside-overdue | 193 | ||||
-rw-r--r-- | FS/bin/freeside-queued | 176 | ||||
-rwxr-xr-x | FS/bin/freeside-receivables-report | 218 | ||||
-rw-r--r-- | FS/bin/freeside-setinvoice | 42 | ||||
-rwxr-xr-x | FS/bin/freeside-tax-report | 270 |
12 files changed, 1671 insertions, 0 deletions
diff --git a/FS/bin/freeside-adduser b/FS/bin/freeside-adduser new file mode 100644 index 000000000..9d424634b --- /dev/null +++ b/FS/bin/freeside-adduser @@ -0,0 +1,57 @@ +#!/usr/bin/perl -w +# +# $Id: freeside-adduser,v 1.4 2002-02-06 14:58:05 ivan Exp $ + +use strict; +use vars qw($opt_h $opt_c $opt_s); +use Getopt::Std; + +my $FREESIDE_CONF = "/usr/local/etc/freeside"; + +getopts("ch:s:"); +die &usage if $opt_c && ! $opt_h; +my $user = shift or die &usage; + +if ( $opt_h ) { + my @args = ( 'htpasswd' ); + push @args, '-c' if $opt_c; + push @args, $opt_h, $user; + system(@args) == 0 or die "htpasswd failed: $?"; +} + +my $secretfile = $opt_s || 'secrets'; + +open(MAPSECRETS,">>$FREESIDE_CONF/mapsecrets") + or die "can't open $FREESIDE_CONF/mapsecrets: $!"; +print MAPSECRETS "$user $secretfile\n"; +close MAPSECRETS or die "can't close $FREESIDE_CONF/mapsecrets: $!"; + +sub usage { + die "Usage:\n\n freeside-adduser [ -h htpasswd_file [ -c ] ] [ -s secretfile ] username" +} + +=head1 NAME + +freeside-adduser - Command line interface to add (freeside) users. + +=head1 SYNOPSIS + + freeside-adduser [ -h htpasswd_file [ -c ] ] [ -s secretfile ] username + +=head1 DESCRIPTION + +Adds a user to the Freeside billing system. This is for adding users (internal +sales/tech folks) to the web interface, not for adding customer accounts. + + -h: Also call htpasswd for this user with the given filename + + -c: Passed to htpasswd + + -s: Specify an alternate secret file + +=head1 SEE ALSO + +L<htpasswd>, base Freeside documentation + +=cut + diff --git a/FS/bin/freeside-apply-credits b/FS/bin/freeside-apply-credits new file mode 100755 index 000000000..ea6a7bdd0 --- /dev/null +++ b/FS/bin/freeside-apply-credits @@ -0,0 +1,21 @@ +#!/usr/bin/perl -Tw + +use strict; +use vars qw( $user $cust_main @customers ); +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch); +use FS::cust_main; + +$user = shift or die &usage; +&adminsuidsetup( $user ); + +my @customers = qsearch('cust_main', {} ); +die "No customers" unless (scalar(@customers) > 0); + +foreach $cust_main (@customers) { + print "Applying credits for customer #". $cust_main->custnum; + $cust_main->apply_credits; +} + + + diff --git a/FS/bin/freeside-bill b/FS/bin/freeside-bill new file mode 100755 index 000000000..49ad4a768 --- /dev/null +++ b/FS/bin/freeside-bill @@ -0,0 +1,128 @@ +#!/usr/bin/perl -w +# don't take any world-facing input +#!/usr/bin/perl -Tw + +use strict; +use Fcntl qw(:flock); +use Date::Parse; +use Getopt::Std; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch qsearchs); +use FS::cust_main; + +&untaint_argv; #what it sounds like (eww) +use vars qw($opt_a $opt_c $opt_d $opt_p); +getopts("acd:p"); +my $user = shift or die &usage; + +adminsuidsetup $user; + +my %bill_only = map { $_ => 1 } ( + @ARGV ? @ARGV : ( map $_->custnum, qsearch('cust_main', {} ) ) +); + +#we're at now now (and later). +my($time)= $opt_d ? str2time($opt_d) : $^T; + +# find packages w/ bill < time && cancel != '', and create corresponding +# customer objects + +my($cust_main,%saw); +foreach $cust_main ( + map { + unless ( exists $saw{ $_->custnum } && defined $saw{ $_->custnum} ) { + $saw{ $_->custnum } = 0; # to avoid 'use of uninitialized value' errors + } + if ( + ( $opt_a || ( ( $_->getfield('bill') || 0 ) <= $time ) ) + && $bill_only{ $_->custnum } + && !$saw{ $_->custnum }++ + ) { + qsearchs('cust_main',{'custnum'=> $_->custnum } ); + } else { + (); + } + } ( qsearch('cust_pkg', { 'cancel' => '' }), + qsearch('cust_pkg', { 'cancel' => 0 }), + ) +) { + + # and bill them + + print "Billing customer #" . $cust_main->getfield('custnum') . "\n"; + + my($error); + + $error=$cust_main->bill('time'=>$time); + warn "Error billing, customer #" . $cust_main->getfield('custnum') . + ":" . $error if $error; + + if ($opt_p) { + $cust_main->apply_payments; + $cust_main->apply_credits; + } + + if ($opt_c) { + $error=$cust_main->collect( 'invoice_time' => $time); + warn "Error collecting from customer #" . $cust_main->custnum. ":$error" + if $error; + + #sleep 1; + } + +} + +# subroutines + +sub untaint_argv { + foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV + #$ARGV[$_] =~ /^([\w\-\/]*)$/ || die "Illegal arguement \"$ARGV[$_]\""; + # Date::Parse + $ARGV[$_] =~ /^(.*)$/ || die "Illegal arguement \"$ARGV[$_]\""; + $ARGV[$_]=$1; + } +} + +sub usage { + die "Usage:\n\n freeside-bill [ -c [ -p ] ] [ -d 'date' ] user [ custnum custnum ... ]\n"; +} + +=head1 NAME + +freeside-bill - Command line (crontab, script) interface to customer billing. + +=head1 SYNOPSIS + + freeside-bill [ -c [ -p ] [ -a ] ] [ -d 'date' ] user [ custnum custnum ... ] + +=head1 DESCRIPTION + +This script is deprecated in 1.4.0. You should use freeside-daily instead. + +Bills customers. Searches for customers who are due for billing and calls +the bill and collect methods of a cust_main object. See L<FS::cust_main>. + + -c: Turn on collecting (you probably want this). + + -p: Apply unapplied payments and credits before collecting (you probably want + this too) + + -a: Call collect even if there isn't a new invoice (probably a bad idea for + daily use) + + -d: Pretend it's 'date'. Date is in any format Date::Parse is happy with, + but be careful. + +user: From the mapsecrets file - see config.html from the base documentation + +custnum: if one or more customer numbers are specified, only bills those +customers. Otherwise, bills all customers. + +=head1 BUGS + +=head1 SEE ALSO + +L<freeside-daily>, L<FS::cust_main>, config.html from the base documentation + +=cut + diff --git a/FS/bin/freeside-cc-receipts-report b/FS/bin/freeside-cc-receipts-report new file mode 100755 index 000000000..2713af397 --- /dev/null +++ b/FS/bin/freeside-cc-receipts-report @@ -0,0 +1,231 @@ +#!/usr/bin/perl -Tw + +use strict; +use Date::Parse; +use Time::Local; +use Getopt::Std; +use FS::Conf; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch qsearchs); +use FS::cust_pay; +use FS::cust_pay_batch; + +# Set the mail program +my $mail_program = "/usr/sbin/sendmail -t -n"; + +&untaint_argv; #what it sounds like (eww) +use vars qw($opt_v $opt_p $opt_e $opt_d $opt_s); +getopts("vped:s:"); #switches + +#we're at now now (and later). +my($_enddate)= $main::opt_d ? str2time($main::opt_d) : $^T; +my($_startdate)= $main::opt_d ? str2time($main::opt_s) : $^T; + +# Get the current month +my ($ssec,$smin,$shour,$smday,$smon,$syear) = + (localtime($_startdate) )[0,1,2,3,4,5]; +$syear+=1900; +$smon++; + +# Get the current month +my ($esec,$emin,$ehour,$emday,$emon,$eyear) = + (localtime($_enddate) )[0,1,2,3,4,5]; +$eyear+=1900; +$emon++; + +# Login to the database +my $user = shift or die &usage; +adminsuidsetup $user; + +# Get the needed configuration files +my $conf = new FS::Conf; +my $lpr = $conf->config('lpr'); +my $email = $conf->config('email'); + +my(@cust_pays)=qsearch('cust_pay',{}); +if (scalar(@cust_pays) == 0) +{ + exit 1; +} + +# Open print and email pipes +# $lpr and opt_p for printing +# $email and opt_e for email + +if ($lpr && $main::opt_p) +{ + open(LPR, "|$lpr"); + print LPR qq~ C R E D I T C A R D R E C E I P T S for period beginning: $smon/$smday/$syear and ending $emon/$emday/$eyear\n\n~; +} + +if ($email && $main::opt_e) +{ + open (MAIL, "|$mail_program"); + print MAIL <<END +To: $email +From: Account Processor +Subject: Receivables + + +C R E D I T C A R D R E C E I P T S for period beginning: $smon/$smday/$syear and ending $emon/$emday/$eyear + +END +} + +my $uninvoiced = 0; +my $total = 0; +my $taxed = 0; +my $untaxed = 0; +my $total_tax = 0; + +# Now I can start looping +foreach my $cust_pay (@cust_pays) +{ + my $_date = $cust_pay->getfield('_date'); + my $invnum = $cust_pay->getfield('invnum'); + my $paid = $cust_pay->getfield('paid'); + my $payby = $cust_pay->getfield('payby'); + + + if ($_date >= $_startdate && $_date <= $_enddate && $payby =~ 'CARD') { + $total += $paid; + + $uninvoiced += $cust_pay->unapplied; + my @cust_bill_pays = $cust_pay->cust_bill_pay; + foreach my $cust_bill_pay (@cust_bill_pays) { + my $invoice_amt =0; + my $invoice_tax =0; + my(@cust_bill_pkgs)= $cust_bill_pay->cust_bill->cust_bill_pkg; + foreach my $cust_bill_pkg (@cust_bill_pkgs) { + + my $recur = $cust_bill_pkg->getfield('recur'); + my $setup = $cust_bill_pkg->getfield('setup'); + my $pkgnum = $cust_bill_pkg->getfield('pkgnum'); + + if ($pkgnum == 0) { + $invoice_tax += $recur; + $invoice_tax += $setup; + } else { + $invoice_amt += $recur; + $invoice_amt += $setup; + } + + } + + if ($invoice_tax > 0) { + if ($invoice_amt != $paid) { + # attempt to prorate partially paid invoices + $total_tax += $paid / ($invoice_amt + $invoice_tax) * $invoice_tax; + $taxed += $paid / ($invoice_amt + $invoice_tax) * $invoice_amt; + } else { + $total_tax += $invoice_tax; + $taxed += $invoice_amt; + } + } else { + $untaxed += $paid; + } + + } + + } + +} + +if ($main::opt_v) { + printf(qq{\n%25s%14.2f\n}, "Uninvoiced", $uninvoiced); + printf(qq{%25s%14.2f\n}, "Untaxed", $untaxed); + printf(qq{%25s%14.2f\n}, "Taxed", $taxed); + printf(qq{%25s%14.2f\n}, "Tax", $total_tax); + printf(qq{\n%39s\n%39.2f\n}, "=========", $total); +} + +# Now I need to close LPR and EMAIL if they were open +if($lpr && $main::opt_p) +{ + printf(LPR qq{\n%25s%14.2f\n}, "Uninvoiced", $uninvoiced); + printf(LPR qq{%25s%14.2f\n}, "Untaxed", $untaxed); + printf(LPR qq{%25s%14.2f\n}, "Taxed", $taxed); + printf(LPR qq{%25s%14.2f\n}, "Tax", $total_tax); + printf(LPR qq{\n%39s\n%39.2f\n}, "=========", $total); + close LPR || die "Could not close printer: $lpr\n"; +} +if($email && $main::opt_e) +{ + printf(MAIL qq{\n%25s%14.2f\n}, "Untaxed", $untaxed); + printf(MAIL qq{%25s%14.2f\n}, "Taxed", $taxed); + printf(MAIL qq{%25s%14.2f\n}, "Tax", $total_tax); + printf(MAIL qq{\n%39s\n%39.2f\n}, "=========", $total); + close MAIL || die "Could not close printer: $email\n"; +} + + +# subroutines +sub untaint_argv { + foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV + $ARGV[$_] =~ /^([\w\-\/ :]*)$/ || die "Illegal argument \"$ARGV[$_]\""; + $ARGV[$_]=$1; + } +} + +sub usage { + die "Usage:\n\n freeside-tax-report [-v] [-p] [-e] user\n"; +} + +=head1 NAME + +freeside-tax-report - Prints or emails sales taxes invoiced in a given period. + +=head1 SYNOPSIS + + freeside-tax-report [-v] [-p] [-e] user + +=head1 DESCRIPTION + +Prints or emails sales taxes invoiced in a given period. + +-v: Verbose - Prints records to STDOUT. + +-p: Print to printer lpr as found in the conf directory. + +-e: Email output to user found in the Conf email file. + +user: From the mapsecrets file - see config.html from the base documentation + +=head1 VERSION + +$Id: freeside-cc-receipts-report,v 1.1 2002-02-22 23:18:32 jeff Exp $ + +=head1 BUGS + +Yes..... Use at your own risk. No guarantees or warrantees of any +kind apply to this program. Parts of this program are hacked from +other GNU licensed software created mainly by Ivan Kohler. + +This is released under the GNU Public License. See www.gnu.org +for more information regarding this license. + +=head1 SEE ALSO + +L<FS::cust_main>, config.html from the base documentation + +=head1 HISTORY + +griff@aver-computer.com July 99 + +$Log: freeside-cc-receipts-report,v $ +Revision 1.1 2002-02-22 23:18:32 jeff +add some reporting features + +Revision 1.2 2002/02/19 14:24:53 jeff +might be functional now + +Revision 1.1 2000/09/20 19:25:19 jeff +local modifications + +Revision 1.1 2000/05/13 21:57:56 ivan +add print_batch script from Joel Griffiths + + +=cut + + diff --git a/FS/bin/freeside-credit-report b/FS/bin/freeside-credit-report new file mode 100755 index 000000000..4307a21b0 --- /dev/null +++ b/FS/bin/freeside-credit-report @@ -0,0 +1,184 @@ +#!/usr/bin/perl -Tw + +use strict; +use Date::Parse; +use Time::Local; +use Getopt::Std; +use FS::Conf; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch); +use FS::cust_credit; + +# Set the mail program +my $mail_program = "/usr/sbin/sendmail -t -n"; + +&untaint_argv; #what it sounds like (eww) +use vars qw($opt_v $opt_p $opt_e $opt_d $opt_s); +getopts("vped:s:"); #switches + +#we're at now now (and later). +my($_enddate)= $main::opt_d ? str2time($main::opt_d) : $^T; +my($_startdate)= $main::opt_s ? str2time($main::opt_s) : $^T; + +# Get the current month +my ($ssec,$smin,$shour,$smday,$smon,$syear) = + (localtime($_startdate) )[0,1,2,3,4,5]; +$syear+=1900; +$smon++; + +# Get the current month +my ($esec,$emin,$ehour,$emday,$emon,$eyear) = + (localtime($_enddate) )[0,1,2,3,4,5]; +$eyear+=1900; +$emon++; + +# Login to the database +my $user = shift or die &usage; +adminsuidsetup $user; + +# Get the needed configuration files +my $conf = new FS::Conf; +my $lpr = $conf->config('lpr'); +my $email = $conf->config('email'); + +my(@cust_credits)=qsearch('cust_credit',{}); +if (scalar(@cust_credits) == 0) +{ + exit 1; +} + +# Open print and email pipes +# $lpr and opt_p for printing +# $email and opt_e for email + +if ($lpr && $main::opt_p) +{ + open(LPR, "|$lpr"); + print LPR qq~ I N H O U S E C R E D I T S for period beginning: $smon/$smday/$syear and ending $emon/$emday/$eyear\n\n~; +} + +if ($email && $main::opt_e) +{ + open (MAIL, "|$mail_program"); + print MAIL <<END +To: $email +From: Account Processor +Subject: In House Credits + + +I N H O U S E C R E D I T S for period beginning: $smon/$smday/$syear and ending $emon/$emday/$eyear + +END +} + +my $total = 0; + +# Now I can start looping +foreach my $cust_credit (@cust_credits) +{ + my $_date = $cust_credit->getfield('_date'); + my $amount = $cust_credit->getfield('amount'); + my $credited = $cust_credit->getfield('credited'); + + + if ($_date >= $_startdate && $_date <= $_enddate) { + $total += $amount; + + my ($sec,$min,$hour,$mday,$mon,$year) = + (localtime($_date) )[0,1,2,3,4,5]; + $mon++; + + } + +} + +if ($main::opt_v) { + printf(qq{\n\n%25s%14.2f\n}, "Credits Offered", $total); + printf(qq{\n%39s\n%39.2f\n}, "=========", $total); +} + +# Now I need to close LPR and EMAIL if they were open +if($lpr && $main::opt_p) +{ + printf(LPR qq{\n\n%25s%14.2f\n}, "Credits Offered", $total); + printf(LPR qq{\n%39s\n%39.2f\n}, "=========", $total); + close LPR || die "Could not close printer: $lpr\n"; +} +if($email && $main::opt_e) +{ + printf(MAIL qq{\n\n%25s%14.2f\n}, "Credits Offered", $total); + printf(MAIL qq{\n%39s\n%39.2f\n}, "=========", $total); + close MAIL || die "Could not close printer: $email\n"; +} + + +# subroutines +sub untaint_argv { + foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV + $ARGV[$_] =~ /^([\w\-\/ :]*)$/ || die "Illegal argument \"$ARGV[$_]\""; + $ARGV[$_]=$1; + } +} + +sub usage { + die "Usage:\n\n freeside-credit-report [-v] [-p] [-e] user\n"; +} + +=head1 NAME + +freeside-credit-report - Prints or emails in house credits offered in a given period. + +=head1 SYNOPSIS + + freeside-credit-report [-v] [-p] [-e] user + +=head1 DESCRIPTION + +Prints or emails in house credits offered in a given period. + +-v: Verbose - Prints records to STDOUT. + +-p: Print to printer lpr as found in the conf directory. + +-e: Email output to user found in the Conf email file. + +user: From the mapsecrets file - see config.html from the base documentation + +=head1 VERSION + +$Id: freeside-credit-report,v 1.1 2002-02-22 23:18:32 jeff Exp $ + +=head1 BUGS + +Yes..... Use at your own risk. No guarantees or warrantees of any +kind apply to this program. Parts of this program are hacked from +other GNU licensed software created mainly by Ivan Kohler. + +This is released under the GNU Public License. See www.gnu.org +for more information regarding this license. + +=head1 SEE ALSO + +L<FS::cust_main>, config.html from the base documentation + +=head1 HISTORY + +griff@aver-computer.com July 99 + +$Log: freeside-credit-report,v $ +Revision 1.1 2002-02-22 23:18:32 jeff +add some reporting features + +Revision 1.1 2002/02/19 14:24:53 jeff +might be functional now + +Revision 1.1 2000/09/20 19:25:19 jeff +local modifications + +Revision 1.1 2000/05/13 21:57:56 ivan +add print_batch script from Joel Griffiths + + +=cut + + diff --git a/FS/bin/freeside-daily b/FS/bin/freeside-daily new file mode 100755 index 000000000..8d839cb21 --- /dev/null +++ b/FS/bin/freeside-daily @@ -0,0 +1,90 @@ +#!/usr/bin/perl -w + +use strict; +use Fcntl qw(:flock); +use Date::Parse; +use Getopt::Std; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch qsearchs); +use FS::cust_main; + +&untaint_argv; #what it sounds like (eww) +use vars qw($opt_d); +getopts("d:"); +my $user = shift or die &usage; + +adminsuidsetup $user; + +my @cust_main = @ARGV + ? map { qsearchs('cust_main', { custnum => $_ } ) } @ARGV + : qsearch('cust_main', {} ) +; + +#we're at now now (and later). +my($time)= $opt_d ? str2time($opt_d) : $^T; + +my($cust_main,%saw); +foreach $cust_main ( @cust_main ) { + + my $error; + + $error = $cust_main->bill( 'time' => $time ); + warn "Error billing, custnum ". $cust_main->custnum. ": $error" if $error; + + $cust_main->apply_payments; + $cust_main->apply_credits; + + $error=$cust_main->collect( 'invoice_time' => $time ); + warn "Error collecting, custnum". $cust_main->custnum. ": $error" if $error; + +} + +# subroutines + +sub untaint_argv { + foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV + #$ARGV[$_] =~ /^([\w\-\/]*)$/ || die "Illegal arguement \"$ARGV[$_]\""; + # Date::Parse + $ARGV[$_] =~ /^(.*)$/ || die "Illegal arguement \"$ARGV[$_]\""; + $ARGV[$_]=$1; + } +} + +sub usage { + die "Usage:\n\n freeside-daily [ -d 'date' ] user [ custnum custnum ... ]\n"; +} + +=head1 NAME + +freeside-daily - Run daily billing and invoice collection events. + +=head1 SYNOPSIS + + freeside-daily [ -d 'date' ] user [ custnum custnum ... ] + +=head1 DESCRIPTION + +Bills customers and runs invoice collection events. Should be run from +crontab daily. + +This script replaces freeside-bill from 1.3.1. + +Bills customers. Searches for customers who are due for billing and calls +the bill and collect methods of a cust_main object. See L<FS::cust_main>. + + -d: Pretend it's 'date'. Date is in any format Date::Parse is happy with, + but be careful. + +user: From the mapsecrets file - see config.html from the base documentation + +custnum: if one or more customer numbers are specified, only bills those +customers. Otherwise, bills all customers. + +=head1 BUGS + +=head1 SEE ALSO + +L<FS::cust_main>, config.html from the base documentation + +=cut + diff --git a/FS/bin/freeside-email b/FS/bin/freeside-email new file mode 100755 index 000000000..c7ff41114 --- /dev/null +++ b/FS/bin/freeside-email @@ -0,0 +1,61 @@ +#!/usr/bin/perl -Tw + +use strict; +use FS::UID qw(adminsuidsetup); +use FS::Conf; +use FS::Record qw(qsearch); +use FS::svc_acct; + +&untaint_argv; #what it sounds like (eww) +my $user = shift or die &usage; + +adminsuidsetup $user; + +my $conf = new FS::Conf; +my $domain = $conf->config('domain'); + +my @svc_acct = qsearch('svc_acct', {}); +my @usernames = map $_->username, @svc_acct; +my @emails = map "$_\@$domain", @usernames; + +print join("\n", @emails), "\n"; + +# subroutines + +sub untaint_argv { + foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV + #$ARGV[$_] =~ /^([\w\-\/]*)$/ || die "Illegal arguement \"$ARGV[$_]\""; + # Date::Parse + $ARGV[$_] =~ /^(.*)$/ || die "Illegal arguement \"$ARGV[$_]\""; + $ARGV[$_]=$1; + } +} + +sub usage { + die "Usage:\n\n freeside-email user\n"; +} + +=head1 NAME + +freeside-email - Prints email addresses of all users on STDOUT + +=head1 SYNOPSIS + + freeside-email user + +=head1 DESCRIPTION + +Prints the email addresses of all customers on STDOUT, separated by newlines. + +user: From the mapsecrets file - see config.html from the base documentation + +=head1 VERSION + +$Id: freeside-email,v 1.1 2001-05-15 07:52:34 ivan Exp $ + +=head1 BUGS + +=head1 SEE ALSO + +=cut + diff --git a/FS/bin/freeside-overdue b/FS/bin/freeside-overdue new file mode 100755 index 000000000..db99e62b4 --- /dev/null +++ b/FS/bin/freeside-overdue @@ -0,0 +1,193 @@ +#!/usr/bin/perl -w + +use strict; +use vars qw( $days_to_pay $cust_main $cust_pkg + $cust_svc $svc_acct ); +use Getopt::Std; +use FS::cust_main; +use FS::cust_pkg; +use FS::cust_svc; +use FS::svc_acct; +use FS::Record qw(qsearch qsearchs); +use FS::UID qw(adminsuidsetup); + +&untaint_argv; +my %opt; +getopts('ed:qpl:scbyoi', \%opt); +my $user = shift or die &usage; + +adminsuidsetup $user; + +my $now = time; #eventually take a time option like freeside-bill +my ($sec,$min,$hour,$mday,$mon,$year) = + (localtime($now) )[0,1,2,3,4,5]; +$mon++; +$year += 1900; + +foreach $cust_main ( qsearch('cust_main',{} ) ) { + + my ( $eyear, $emon, $eday ) = ( 2037, 12, 31 ); + if ( $cust_main->paydate =~ /^(\d{4})\-(\d{1,2})\-(\d{1,2})$/ + && $cust_main->payby eq 'BILL') { + ( $eyear, $emon, $eday ) = ( $1, $2, $3 ); + } + + if ( ( $opt{d} + && $cust_main->balance_date(time - $opt{d} * 86400) > 0 + && qsearchs( 'cust_pkg', { 'custnum' => $cust_main->custnum, + 'susp' => "" } ) ) + || ( $opt{e} + && $cust_main->payby eq 'BILL' + && ( $eyear < $year + || ( $eyear == $year && $emon < $mon ) ) ) + ) { + + unless ( $opt{q} ) { + print $cust_main->custnum, "\t", + $cust_main->last, "\t", $cust_main->first, "\t", + $cust_main->balance_date(time-$opt{d} * 86400); + } + + if ( $opt{p} && ! grep { $_ eq 'POST' } $cust_main->invoicing_list ) { + print "\n\tAdding postal invoicing" unless $opt{q}; + my @invoicing_list = $cust_main->invoicing_list; + push @invoicing_list, 'POST'; + $cust_main->invoicing_list(\@invoicing_list); + } + + if ( $opt{l} ) { + print "\n\tCharging late fee of \$$opt{l}" unless $opt{q}; + my $error = $cust_main->charge($opt{l}, 'Late fee'); + # comment or plandata with info so we don't redo the same late fee every + # day + } + + foreach $cust_pkg ( qsearch( 'cust_pkg', + { 'custnum' => $cust_main->custnum } ) ) { + + if ($opt{s}) { + print "\n\tSuspending pkgnum " . $cust_pkg->pkgnum unless $opt{q}; + $cust_pkg->suspend; + } + + if ($opt{c}) { + print "\n\tCancelling pkgnum " . $cust_pkg->pkgnum unless $opt{q}; + $cust_pkg->cancel; + } + + } + + if ( $opt{b} ) { + print "\n\tBilling" unless $opt{q}; + my $error = $cust_main->bill('time'=>$now); + warn "Error billing, customer #" . $cust_main->custnum . + ":" . $error if $error; + } + + if ( $opt{y} ) { + print "\n\tApplying outstanding payments and credits" unless $opt{q}; + $cust_main->apply_payments; + $cust_main->apply_credits; + } + + if ( $opt{o} ) { + print "\n\tCollecting" unless $opt{q}; + my $error = $cust_main->collect( + 'invoice_time' => $now, + 'batch_card' => $opt{i} ? 'no' : 'yes', + 'force_print' => 'yes', + ); + warn "Error collecting from customer #" . $cust_main->custnum. ":$error" + if $error; + } + + print "\n" unless $opt{q}; + + } + +} + +sub untaint_argv { + foreach $_ ( $[ .. $#ARGV ) { + $ARGV[$_] =~ /^([\w\-\/\.]*)$/ || die "Illegal arguement \"$ARGV[$_]\""; + $ARGV[$_]=$1; + } +} + +sub usage { + die "Usage:\n\n freeside-overdue [ -e ] [ -d days ] [ -q ] [ -p ] [ -l amount ] [ -s ] [ -c ] [ -b ] [ -y ] [ -o [ -i ] ] user\n"; +} + + +=head1 NAME + +freeside-overdue - Perform actions on overdue and/or expired accounts. + +=head1 SYNOPSIS + + freeside-overdue [ -e ] [ -d days ] [ -q ] [ -p ] [ -l amount ] [ -s ] [ -c ] [ -b ] [ -y ] [ -o [ -i ] ] user + +=head1 DESCRIPTION + +Performs actions on overdue and/or expired accounts. + +Selection options (at least one selection option is required): + + -d: Customers with a balance due on invoices older than the supplied number + of days. Requires an integer argument. + + -e: Customers with a billing expiration date in the past. + +Action options: + + -q: Be quiet (by default, selected accounts are printed). + + -p: Add postal invoicing to the relevant customers. + + -l: Add a charge of the given amount to the relevant customers. + + -s: Suspend accounts. + + -c: Cancel accounts. + + -b: Bill customers (create invoices) + + -y: Apply unapplied payments and credits + + -o: Collect from customers (charge cards, print invoices) + + -i: real-time billing (as opposed to batch billing). only relevant + for credit cards. + + user: From the mapsecrets file - see config.html from the base documentation + +=head1 CRONTAB + +Example crontab entries: + +# suspend expired accounts +20 4 * * * freeside-overdue -e -s user + +# quietly add postal invoicing to customers over 30 days past due +20 4 * * * freeside-overdue -d 30 -p -q user + +# suspend accounts and charge a $10.23 fee for customers over 60 days past due +20 4 * * * freeside-overdue -d 60 -s -l 10.23 user + +# cancel accounts over 90 days past due +20 4 * * * freeside-overdue -d 90 -c user + +=head1 ORIGINAL AUTHORS + +Original disable-overdue version by mw/kwh: Mark W.? and Kristian Hoffmann ? + +Ivan seems to be turning it into the "do-everything" CLI. + +=head1 BUGS + +Hell now that this is the do-everything CLI it should have --longoptions + +=cut + +1; + diff --git a/FS/bin/freeside-queued b/FS/bin/freeside-queued new file mode 100644 index 000000000..56475d059 --- /dev/null +++ b/FS/bin/freeside-queued @@ -0,0 +1,176 @@ +#!/usr/bin/perl -w + +use strict; +use vars qw( $log_file $sigterm $sigint ); +use subs qw( _die _logmsg ); +use Fcntl qw(:flock); +use POSIX qw(setsid); +use Date::Format; +use IO::File; +use FS::UID qw(adminsuidsetup forksuidsetup driver_name); +use FS::Record qw(qsearchs); +use FS::queue; + +# no autoloading just yet +use FS::cust_main; +use FS::svc_acct; +use Net::SSH 0.05; + +my $pid_file = '/var/run/freeside-queued.pid'; + +my $user = shift or die &usage; + +&daemonize; + +sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; } +$SIG{CHLD} = \&REAPER; + + $sigterm = 0; + $sigint = 0; +$SIG{INT} = sub { warn "SIGINT received; shutting down\n"; $sigint++; }; +$SIG{TERM} = sub { warn "SIGTERM received; shutting down\n"; $sigterm++; }; + +$> = $FS::UID::freeside_uid unless $>; +$< = $>; +$ENV{HOME} = (getpwuid($>))[7]; #for ssh +adminsuidsetup $user; + +$log_file = "/usr/local/etc/freeside/queuelog.". $FS::UID::datasrc; + +$SIG{__DIE__} = \&_die; +$SIG{__WARN__} = \&_logmsg; + +warn "freeside-queued starting\n"; + +while (1) { + + my $job = qsearchs( + 'queue', + { 'status' => 'new' }, + '', + driver_name =~ /^mysql$/i + ? 'ORDER BY jobnum LIMIT 1 FOR UPDATE' + : 'ORDER BY jobnum FOR UPDATE LIMIT 1' + ) or do { + sleep 5; + next; + }; + + my %hash = $job->hash; + $hash{'status'} = 'locked'; + my $ljob = new FS::queue ( \%hash ); + my $error = $ljob->replace($job); + die $error if $error; + + my @args = $ljob->args; + + # number of children limit? + defined( my $pid = fork ) or do { + warn "WARNING: can't fork: $!\n"; + my %hash = $job->hash; + $hash{'status'} = 'failed'; + $hash{'statustext'} = "[freeside-queued] can't fork: $!"; + my $ljob = new FS::queue ( \%hash ); + my $error = $ljob->replace($job); + die $error if $error; + }; + + unless ( $pid ) { #kid time + + #get new db handles + $FS::UID::dbh->{InactiveDestroy} = 1; + $FS::svc_acct::icradius_dbh->{InactiveDestroy} = 1 + if $FS::svc_acct::icradius_dbh; + forksuidsetup($user); + + my $eval = "&". $ljob->job. '(@args);'; + warn "running $eval"; + eval $eval; + if ( $@ ) { + warn "job $eval failed"; + my %hash = $ljob->hash; + $hash{'status'} = 'failed'; + $hash{'statustext'} = $@; + my $fjob = new FS::queue( \%hash ); + my $error = $fjob->replace($ljob); + die $error if $error; + } else { + $ljob->delete; + } + + exit; + #end-of-kid + } + +} continue { + if ( $sigterm ) { + warn "received TERM signal; exiting\n"; + exit; + } + if ( $sigint ) { + warn "received INT signal; exiting\n"; + exit; + } +} + +sub usage { + die "Usage:\n\n freeside-queued user\n"; +} + +sub _die { + my $msg = shift; + unlink $pid_file if -e $pid_file; + _logmsg($msg); +} + +sub _logmsg { + chomp( my $msg = shift ); + my $log = new IO::File ">>$log_file"; + flock($log, LOCK_EX); + seek($log, 0, 2); + print $log "[". time2str("%a %b %e %T %Y",time). "] [$$] $msg\n"; + flock($log, LOCK_UN); + close $log; +} + +sub daemonize { + + chdir "/" or die "Can't chdir to /: $!"; + open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; + defined(my $pid = fork) or die "Can't fork: $!"; + if ( $pid ) { + print "freeside-queued started with pid $pid\n"; #logging to $log_file\n"; + exit unless $pid_file; + my $pidfh = new IO::File ">$pid_file" or exit; + print $pidfh "$pid\n"; + exit; + } + open STDOUT, '>/dev/null' + or die "Can't write to /dev/null: $!"; + setsid or die "Can't start a new session: $!"; + open STDERR, '>&STDOUT' or die "Can't dup stdout: $!"; + +} + +=head1 NAME + +freeside-queued - Job queue daemon + +=head1 SYNOPSIS + + freeside-queued user + +=head1 DESCRIPTION + +Job queue daemon. Should be running at all times. + +user: from the mapsecrets file - see config.html from the base documentation + +=head1 VERSION + +=head1 BUGS + +=head1 SEE ALSO + +=cut + diff --git a/FS/bin/freeside-receivables-report b/FS/bin/freeside-receivables-report new file mode 100755 index 000000000..cef652bfe --- /dev/null +++ b/FS/bin/freeside-receivables-report @@ -0,0 +1,218 @@ +#!/usr/bin/perl -Tw + +use strict; +use Date::Parse; +use Time::Local; +use Getopt::Std; +use Text::Template; +use FS::Conf; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch); +use FS::cust_main; + +# Set the mail program +my $mail_program = "/usr/sbin/sendmail -t -n"; + +&untaint_argv; #what it sounds like (eww) +use vars qw($opt_v $opt_p $opt_m $opt_e $opt_t $report_lines $report_template @buf); +getopts("vpmet:"); #switches + +#we're at now now (and later). +my($_date)= $^T; + +# Get the current month +my ($sec,$min,$hour,$mday,$mon,$year) = + (localtime($_date) )[0,1,2,3,4,5]; +$mon++; +$year += 1900; + +# Login to the database +my $user = shift or die &usage; +adminsuidsetup $user; + +# Get the needed configuration files +my $conf = new FS::Conf; +my $lpr = $conf->config('lpr'); +my $email = $conf->config('email'); +my @report_template = $conf->config('report_template') + or die "cannot load config file report_template"; +$report_lines = 0; + foreach ( grep /report_lines\(\d+\)/, @report_template ) { #kludgy :/ + /report_lines\((\d+)\)/; + $report_lines += $1; +} +die "no report_lines() functions in template?" unless $report_lines; +$report_template = new Text::Template ( + TYPE => 'ARRAY', + SOURCE => [ map "$_\n", @report_template ], +) or die "can't create new Text::Template object: $Text::Template::ERROR"; + + +my(@customers)=qsearch('cust_main',{}); +if (scalar(@customers) == 0) +{ + exit 1; +} + +# Open print and email pipes +# $lpr and opt_p for printing +# $email and opt_m for email + +if ($lpr && $opt_p) +{ + open(LPR, "|$lpr"); +} + +if ($email && $opt_m) +{ + open (MAIL, "|$mail_program"); + print MAIL <<END +To: $email +From: Account Processor +Subject: Receivables + + +END +} + +my $total = 0; + + +# Now I can start looping +foreach my $customer (@customers) +{ + my $custnum = $customer->getfield('custnum'); + my $first = $customer->getfield('first'); + my $last = $customer->getfield('last'); + my $company = $customer->getfield('company'); + my $daytime = $customer->getfield('daytime'); + my $balance = $customer->balance; + + + if ($balance != 0) { + $total += $balance; + push @buf, sprintf(qq{%5d %-32.32s %12s %9.2f}, + $custnum, + $first . " " . $last . " " . $company, + $daytime, + $balance); + + } + +} + +push @buf, ('', sprintf(qq{%61s}, "========="), sprintf(qq{%61.2f}, $total)); + +sub FS::receivables_report::_template::report_lines { + my $lines = shift; + map { + scalar(@buf) ? shift @buf : '' ; + } + ( 1 .. $lines ); +} + +$FS::receivables_report::_template::title = " R E C E I V A B L E S "; +$FS::receivables_report::_template::title = $opt_t if $opt_t; +$FS::receivables_report::_template::page = 1; +$FS::receivables_report::_template::date = $_date; +$FS::receivables_report::_template::date = $_date; +$FS::receivables_report::_template::total_pages = + int( scalar(@buf) / $report_lines); +$FS::receivables_report::_template::total_pages++ if scalar(@buf) % $report_lines; + +my @report; +while (@buf) { + push @report, split("\n", + $report_template->fill_in( PACKAGE => 'FS::receivables_report::_template' ) + ); + $FS::receivables_report::_template::page++; +} + +if ($opt_v) { + print map "$_\n", @report; +} +if($lpr && $opt_p) +{ + print LPR map "$_\n", @report; + print LPR "\f" if $opt_e; + close LPR || die "Could not close printer: $lpr\n"; +} +if($email && $opt_m) +{ + print MAIL map "$_\n", @report; + close MAIL || die "Could not close printer: $email\n"; +} + + +# subroutines + +sub untaint_argv { + foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV + $ARGV[$_] =~ /^([\w\-\/ ]*)$/ || die "Illegal argument \"$ARGV[$_]\""; + $ARGV[$_]=$1; + } +} + +sub usage { + die "Usage:\n\n freeside-receivables-report [-v] [-p] [-e] user\n"; +} + +=head1 NAME + +freeside-receivables-report - Prints or emails outstanding receivables. + +=head1 SYNOPSIS + + freeside-receivables-report [-v] [-p] [-m] [-e] [-t "title"] user + +=head1 DESCRIPTION + +Prints or emails outstanding receivables + +-v: Verbose - Prints records to STDOUT. + +-p: Print to printer lpr as found in the conf directory. + +-m: Mail output to user found in the Conf email file. + +-e: Print a final form feed to the printer. + +-t: supply a title for the top of each page. + +user: From the mapsecrets file - see config.html from the base documentation + +=head1 VERSION + +$Id: freeside-receivables-report,v 1.1 2002-02-22 23:18:32 jeff Exp $ + +=head1 BUGS + +Yes..... Use at your own risk. No guarantees or warrantees of any +kind apply to this program. Parts of this program are hacked from +other GNU licensed software created mainly by Ivan Kohler. + +This is released under the GNU Public License. See www.gnu.org +for more information regarding this license. + +=head1 SEE ALSO + +L<FS::cust_main>, config.html from the base documentation + +=head1 HISTORY + +griff@aver-computer.com July 99 + +$Log: freeside-receivables-report,v $ +Revision 1.1 2002-02-22 23:18:32 jeff +add some reporting features + +Revision 1.1 2000/09/20 19:25:19 jeff +local modifications + +Revision 1.1 2000/05/13 21:57:56 ivan +add print_batch script from Joel Griffiths + + +=cut + + diff --git a/FS/bin/freeside-setinvoice b/FS/bin/freeside-setinvoice new file mode 100644 index 000000000..708e2fa30 --- /dev/null +++ b/FS/bin/freeside-setinvoice @@ -0,0 +1,42 @@ +#!/usr/bin/perl + +use strict; +use FS::UID qw(adminsuidsetup); +use FS::Conf; +use FS::Record qw(qsearch qsearchs); +use FS::cust_main; +use FS::svc_acct; + +&untaint_argv; #what it sounds like (eww) +my $user = shift or die &usage; + +adminsuidsetup $user; + +foreach my $cust_main ( + grep { ! scalar($_->invoicing_list) } + qsearch( 'cust_main', {} ) +) { + my @dest; + my @cust_pkg = $cust_main->ncancelled_pkgs; + foreach my $cust_pkg ( @cust_pkg ) { + foreach my $cust_svc ( $cust_pkg->cust_svc ) { + my $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $cust_svc->svcnum } ); + push @dest, $svc_acct->svcnum if $svc_acct; + } + } + push @dest, 'POST' unless @dest; + $cust_main->invoicing_list(\@dest); +} + +sub untaint_argv { + foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV + $ARGV[$_] =~ /^(.*)$/ || die "Illegal arguement \"$ARGV[$_]\""; + $ARGV[$_]=$1; + } +} + +sub usage { + die "Usage:\n\n freeside-setinvoice user\n"; +} + + diff --git a/FS/bin/freeside-tax-report b/FS/bin/freeside-tax-report new file mode 100755 index 000000000..334c4107b --- /dev/null +++ b/FS/bin/freeside-tax-report @@ -0,0 +1,270 @@ +#!/usr/bin/perl -Tw + +use strict; +use Date::Parse; +use Time::Local; +use Getopt::Std; +use FS::Conf; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch); +use FS::cust_pay; +use FS::cust_pay_batch; + +# Set the mail program +my $mail_program = "/usr/sbin/sendmail -t -n"; + +&untaint_argv; #what it sounds like (eww) +use vars qw($opt_v $opt_p $opt_e $opt_d $opt_s); +getopts("vped:s:"); #switches + +#we're at now now (and later). +my($_enddate)= $main::opt_d ? str2time($main::opt_d) : $^T; +my($_startdate)= $main::opt_s ? str2time($main::opt_s) : $^T; + +# Get the current month +my ($ssec,$smin,$shour,$smday,$smon,$syear) = + (localtime($_startdate) )[0,1,2,3,4,5]; +$smon++; +$syear -= 100 if $syear >= 100; +$syear = "0" . $syear if $syear < 10; + +# Get the current month +my ($esec,$emin,$ehour,$emday,$emon,$eyear) = + (localtime($_enddate) )[0,1,2,3,4,5]; +$emon++; +$eyear -= 100 if $eyear >= 100; +$eyear = "0" . $eyear if $eyear < 10; + +# Login to the database +my $user = shift or die &usage; +adminsuidsetup $user; + +# Get the needed configuration files +my $conf = new FS::Conf; +my $lpr = $conf->config('lpr'); +my $email = $conf->config('email'); + +my(@cust_bills)=qsearch('cust_bill',{}); +if (scalar(@cust_bills) == 0) +{ + exit 1; +} + +if ($main::opt_v) +{ + print qq~ S A L E S T A X E S I N V O I C E D for period beginning: $smon/$smday/$syear and ending $emon/$emday/$eyear\n\n~; +} + +# Open print and email pipes +# $lpr and opt_p for printing +# $email and opt_e for email + +if ($lpr && $main::opt_p) +{ + open(LPR, "|$lpr"); + print LPR qq~ S A L E S T A X E S I N V O I C E D for period beginning: $smon/$smday/$syear and ending $emon/$emday/$eyear\n\n~; +} + +if ($email && $main::opt_e) +{ + open (MAIL, "|$mail_program"); + print MAIL <<END +To: $email +From: Account Processor +Subject: Sales Taxes Invoiced + + +S A L E S T A X E S I N V O I C E D for period beginning: $smon/$smday/$syear and ending $emon/$emday/$eyear + +END +} + +my $compped = 0; +my $compped_tax = 0; +my $other = 0; +my $other_tax = 0; +my $total = 0; +my $taxed = 0; +my $untaxed = 0; +my $total_tax = 0; + +# Now I can start looping +foreach my $cust_bill (@cust_bills) +{ + my $_date = $cust_bill->getfield('_date'); + my $invnum = $cust_bill->getfield('invnum'); + my $charged = $cust_bill->getfield('charged'); + + + if ($_date >= $_startdate && $_date <= $_enddate) { + $total += $charged; + + # The following lines were used to produce rather verbose reports + #my ($sec,$min,$hour,$mday,$mon,$year) = + # (localtime($_date) )[0,1,2,3,4,5]; + #$mon++; + #$year -= 100 if $year >= 100; + #$year = "0" . $year if $year < 10; + + my $invoice_amt =0; + my $invoice_tax =0; + my $invoice_compped =0; + my(@cust_bill_pkgs)= $cust_bill->cust_bill_pkg; + foreach my $cust_bill_pkg (@cust_bill_pkgs) { + + my $recur = $cust_bill_pkg->getfield('recur'); + my $setup = $cust_bill_pkg->getfield('setup'); + my $pkgnum = $cust_bill_pkg->getfield('pkgnum'); + + if ($pkgnum == 0) { + # The following line was used to produce rather verbose reports + # printf(MAIL qq{\n%10s%15s%14.2f}, "$mon/$mday/$year", "Tax $invnum", $recur+$setup); + $invoice_tax += $recur; + $invoice_tax += $setup; + } else { + # The following line was used to produce rather verbose reports + # printf(MAIL qq{\n%10s%15s%14.2f}, "$mon/$mday/$year", "Inv $invnum", $recur+$setup); + $invoice_amt += $recur; + $invoice_amt += $setup; + } + + } + + my(@cust_bill_pays)= $cust_bill->cust_bill_pay; + foreach my $cust_bill_pay (@cust_bill_pays) { + my $payby = $cust_bill_pay->cust_pay->payby; + my $paid = $cust_bill_pay->getfield('amount'); + if ($payby =~ 'COMP') { + $invoice_compped += $paid; + } + } + + if (abs($invoice_compped - ($invoice_amt + $invoice_tax)) < 0.0001){ + $compped += $invoice_amt; + $compped_tax += $invoice_tax; + } elsif ($invoice_compped > 0) { + printf(qq{\nInvoice %10d has inexpliciable complimentary payments of %14.9f\n}, $invnum, $invoice_compped); + $other += $invoice_amt; + $other_tax += $invoice_tax; + } elsif ($invoice_tax > 0) { + $total_tax += $invoice_tax; + $taxed += $invoice_amt; + } else { + $untaxed += $invoice_amt; + } + + } + +} + +if ($main::opt_v) { + printf(qq{\n\n%25s%14.2f\n}, "Complimentary", $compped); + printf(qq{%25s%14.2f\n}, "Complimentary Tax", $compped_tax); + printf(qq{%25s%14.2f\n}, "Other", $other); + printf(qq{%25s%14.2f\n}, "Other Tax", $other_tax); + printf(qq{%25s%14.2f\n}, "Untaxed", $untaxed); + printf(qq{%25s%14.2f\n}, "Taxed", $taxed); + printf(qq{%25s%14.2f\n}, "Tax", $total_tax); + printf(qq{\n%39s\n%39.2f\n}, "=========", $total); +} + +# Now I need to close LPR and EMAIL if they were open +if($lpr && $main::opt_p) +{ + printf(LPR qq{\n\n%25s%14.2f\n}, "Complimentary", $compped); + printf(LPR qq{%25s%14.2f\n}, "Complimentary Tax", $compped_tax); + printf(LPR qq{%25s%14.2f\n}, "Other", $other); + printf(LPR qq{%25s%14.2f\n}, "Other Tax", $other_tax); + printf(LPR qq{%25s%14.2f\n}, "Untaxed", $untaxed); + printf(LPR qq{%25s%14.2f\n}, "Taxed", $taxed); + printf(LPR qq{%25s%14.2f\n}, "Tax", $total_tax); + printf(LPR qq{\n%39s\n%39.2f\n}, "=========", $total); + close LPR || die "Could not close printer: $lpr\n"; +} +if($email && $main::opt_e) +{ + printf(MAIL qq{\n\n%25s%14.2f\n}, "Complimentary", $compped); + printf(MAIL qq{%25s%14.2f\n}, "Complimentary Tax", $compped_tax); + printf(MAIL qq{%25s%14.2f\n}, "Other", $other); + printf(MAIL qq{%25s%14.2f\n}, "Other Tax", $other_tax); + printf(MAIL qq{%25s%14.2f\n}, "Untaxed", $untaxed); + printf(MAIL qq{%25s%14.2f\n}, "Taxed", $taxed); + printf(MAIL qq{%25s%14.2f\n}, "Tax", $total_tax); + printf(MAIL qq{\n%39s\n%39.2f\n}, "=========", $total); + close MAIL || die "Could not close printer: $email\n"; +} + + +# subroutines +sub untaint_argv { + foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV + $ARGV[$_] =~ /^([\w\-\/ :]*)$/ || die "Illegal argument \"$ARGV[$_]\""; + $ARGV[$_]=$1; + } +} + +sub usage { + die "Usage:\n\n freeside-tax-report [-v] [-p] [-e] user\n"; +} + +=head1 NAME + +freeside-tax-report - Prints or emails sales taxes invoiced in a given period. + +=head1 SYNOPSIS + + freeside-tax-report [-v] [-p] [-e] user + +=head1 DESCRIPTION + +Prints or emails sales taxes invoiced in a given period. + +-v: Verbose - Prints records to STDOUT. + +-p: Print to printer lpr as found in the conf directory. + +-e: Email output to user found in the Conf email file. + +user: From the mapsecrets file - see config.html from the base documentation + +=head1 VERSION + +$Id: freeside-tax-report,v 1.1 2002-02-22 23:18:32 jeff Exp $ + +=head1 BUGS + +Yes..... Use at your own risk. No guarantees or warrantees of any +kind apply to this program. Parts of this program are hacked from +other GNU licensed software created mainly by Ivan Kohler. + +This is released under the GNU Public License. See www.gnu.org +for more information regarding this license. + +=head1 SEE ALSO + +L<FS::cust_main>, config.html from the base documentation + +=head1 HISTORY + +griff@aver-computer.com July 99 + +$Log: freeside-tax-report,v $ +Revision 1.1 2002-02-22 23:18:32 jeff +add some reporting features + +Revision 1.3 2002/02/19 14:24:53 jeff +might be functional now + +Revision 1.2 2001/08/20 18:31:49 jeff +before-merge-to-freeside_1_4_0-pre1 + +Revision 1.1 2000/09/20 19:25:19 jeff +local modifications + +Revision 1.1 2000/05/13 21:57:56 ivan +add print_batch script from Joel Griffiths + + +=cut + + |