allow . in untaint_argv, for usernames
[freeside.git] / FS / bin / freeside-receivables-report
1 #!/usr/bin/perl -Tw
2
3 use strict;
4 use Date::Parse;
5 use Time::Local;
6 use Getopt::Std;
7 use Text::Template;
8 use Net::SMTP;
9 use Mail::Header;
10 use Mail::Internet;
11 use FS::Conf;
12 use FS::UID qw(adminsuidsetup);
13 use FS::Record qw(qsearch);
14 use FS::cust_main;
15
16
17 &untaint_argv;  #what it sounds like  (eww)
18 use vars qw($opt_v $opt_p $opt_m $opt_e $opt_t $report_lines $report_template @buf $header);
19 getopts("vpmet:");      #switches
20
21 #we're at now now (and later).
22 my($_date)= $^T;
23
24 # Get the current month
25 my ($sec,$min,$hour,$mday,$mon,$year) =
26         (localtime($_date) )[0,1,2,3,4,5]; 
27 $mon++;
28 $year += 1900;
29
30 # Login to the database
31 my $user = shift or die &usage;
32 adminsuidsetup $user;
33
34 # Get the needed configuration files
35 my $conf = new FS::Conf;
36 my $lpr = $conf->config('lpr');
37 my $email = $conf->config('email');
38 my $smtpmachine = $conf->config('smtpmachine');
39 my $mail_sender = $conf->exists('invoice_from') ? $conf->config('invoice_from') :
40   'postmaster';
41 my @report_template = $conf->config('report_template')
42   or die "cannot load config file report_template";
43 $report_lines = 0;
44   foreach ( grep /report_lines\(\d+\)/, @report_template ) { #kludgy :/
45   /report_lines\((\d+)\)/;
46   $report_lines += $1;
47 }
48 die "no report_lines() functions in template?" unless $report_lines;
49 $report_template = new Text::Template (
50   TYPE   => 'ARRAY',
51   SOURCE => [ map "$_\n", @report_template ],
52 ) or die "can't create new Text::Template object: $Text::Template::ERROR";
53
54
55 my(@customers)=qsearch('cust_main',{});
56 if (scalar(@customers) == 0)
57 {
58         exit 1;
59 }
60
61 # Open print and email pipes
62 # $lpr and opt_p for printing
63 # $email and opt_m for email
64
65 if ($lpr && $opt_p)
66 {
67         open(LPR, "|$lpr");
68 }
69
70 if ($email && $opt_m)
71 {
72   $ENV{MAILADDRESS} = $mail_sender;
73   $header = new Mail::Header ( [
74     "From: Account Processor",
75     "To: $email",
76     "Sender: $mail_sender",
77     "Reply-To: $mail_sender",
78     "Subject: Receivables",
79   ] );
80 }
81
82 my $total = 0;
83
84
85 # Now I can start looping
86 foreach my $customer (@customers)
87 {
88   my $custnum = $customer->getfield('custnum');
89   my $first = $customer->getfield('first');
90   my $last = $customer->getfield('last');
91   my $company = $customer->getfield('company');
92   my $daytime = $customer->getfield('daytime');
93   my $balance = $customer->balance;
94
95
96   if ($balance != 0) {
97     $total += $balance;
98     push @buf, sprintf(qq{%8d %-32.32s %12s %9.2f},
99       $custnum,
100       $first . " " . $last . "   " . $company,
101       $daytime,
102       $balance);
103
104   }
105
106 }
107
108 push @buf, ('', sprintf(qq{%61s}, "========="), sprintf(qq{%61.2f}, $total));
109
110 sub FS::receivables_report::_template::report_lines {
111   my $lines = shift;
112   map {
113     scalar(@buf) ? shift @buf : '' ;
114   }
115   ( 1 .. $lines );
116 }
117
118 $FS::receivables_report::_template::title = " R E C E I V A B L E S ";
119 $FS::receivables_report::_template::title = $opt_t if $opt_t;
120 $FS::receivables_report::_template::page = 1;
121 $FS::receivables_report::_template::date = $_date;
122 $FS::receivables_report::_template::date = $_date;
123 $FS::receivables_report::_template::total_pages = 
124   int( scalar(@buf) / $report_lines);
125 $FS::receivables_report::_template::total_pages++ if scalar(@buf) % $report_lines;
126
127 my @report;
128 while (@buf) {
129   push @report, split("\n", 
130     $report_template->fill_in( PACKAGE => 'FS::receivables_report::_template' )
131   );
132   $FS::receivables_report::_template::page++;
133 }
134
135 if ($opt_v) {
136   print map "$_\n", @report;
137 }
138 if($lpr && $opt_p)
139 {
140   print LPR map "$_\n", @report;
141   print LPR "\f" if $opt_e;
142   close LPR || die "Could not close printer: $lpr\n";
143 }
144 if($email && $opt_m)
145 {
146   my $message = new Mail::Internet (
147     'Header' => $header,
148     'Body' => [ (@report) ],
149   );
150   $!=0;
151   $message->smtpsend( Host => "$smtpmachine" )
152     or die "can't send report to $email via $smtpmachine: $!";
153 }
154
155
156 # subroutines
157
158 sub untaint_argv {
159   foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV
160     $ARGV[$_] =~ /^([\w\-\/ \.]*)$/ || die "Illegal argument \"$ARGV[$_]\"";
161     $ARGV[$_]=$1;
162   }
163 }
164
165 sub usage {
166   die "Usage:\n\n  freeside-receivables-report [-v] [-p] [-e] user\n";
167 }
168
169 =head1 NAME
170
171 freeside-receivables-report - Prints or emails outstanding receivables.
172
173 =head1 SYNOPSIS
174
175   freeside-receivables-report [-v] [-p] [-m] [-e] [-t "title"] user
176
177 =head1 DESCRIPTION
178
179 Prints or emails outstanding receivables
180
181 B<-v>: Verbose - Prints records to STDOUT.
182
183 B<-p>: Print to printer lpr as found in the conf directory.
184
185 B<-m>: Mail output to user found in the Conf email file.
186
187 B<-e>: Print a final form feed to the printer.
188
189 B<-t>: supply a title for the top of each page.
190
191 user: From the mapsecrets file - see config.html from the base documentation
192
193 =head1 VERSION
194
195 $Id: freeside-receivables-report,v 1.6 2002-09-09 22:57:34 ivan Exp $
196
197 =head1 BUGS
198
199 Yes..... Use at your own risk. No guarantees or warrantees of any
200 kind apply to this program. Parts of this program are hacked from
201 other GNU licensed software created mainly by Ivan Kohler.
202
203 This is released under the GNU Public License. See www.gnu.org
204 for more information regarding this license.
205
206 =head1 SEE ALSO
207
208 L<FS::cust_main>, config.html from the base documentation
209
210 =head1 AUTHOR
211
212 Jeff Finucane <jeff@cmh.net>
213
214 based on print-batch by Joel Griffiths <griff@aver-computer.com>
215
216 =cut
217