remove CVS Log tag
[freeside.git] / FS / bin / freeside-tax-report
1 #!/usr/bin/perl -Tw
2
3
4 use strict;
5 use Date::Parse;
6 use Time::Local;
7 use Getopt::Std;
8 use Text::Template;
9 use FS::Conf;
10 use FS::UID qw(adminsuidsetup);
11 use FS::Record qw(qsearch);
12 use FS::cust_bill;
13 use FS::cust_bill_pay;
14 use FS::cust_pay;
15
16 # Set the mail program
17 my $mail_program = "/usr/sbin/sendmail -t -n"; 
18
19 &untaint_argv;  #what it sounds like  (eww)
20 use vars qw($opt_v $opt_p $opt_m $opt_e $opt_t $opt_s $opt_f $report_lines $report_template @buf);
21 getopts("vpmef:s:");    #switches
22
23 #we're at now now (and later).
24 my($_finishdate)= $opt_f ? str2time($main::opt_f) : $^T;
25 my($_startdate)= $opt_s ? str2time($main::opt_s) : $^T;
26
27 # Get the current month
28 my ($ssec,$smin,$shour,$smday,$smon,$syear) =
29         (localtime($_startdate) )[0,1,2,3,4,5]; 
30 $smon++;
31 $syear += 1900;
32
33 # Get the current month
34 my ($fsec,$fmin,$fhour,$fmday,$fmon,$fyear) =
35         (localtime($_finishdate) )[0,1,2,3,4,5]; 
36 $fmon++;
37 $fyear += 1900;
38
39 # Login to the database
40 my $user = shift or die &usage;
41 adminsuidsetup $user;
42
43 # Get the needed configuration files
44 my $conf = new FS::Conf;
45 my $lpr = $conf->config('lpr');
46 my $email = $conf->config('email');
47 my @report_template = $conf->config('report_template')
48   or die "cannot load config file report_template";
49 $report_lines = 0;
50 foreach ( grep /report_lines\(\d+\)/, @report_template ) { #kludgy :/
51   /report_lines\((\d+)\)/;
52   $report_lines += $1;
53 }
54 die "no report_lines() functions in template?" unless $report_lines;
55 $report_template = new Text::Template (
56   TYPE   => 'ARRAY',
57   SOURCE => [ map "$_\n", @report_template ],
58 ) or die "can't create new Text::Template object: $Text::Template::ERROR";
59
60
61 my(@cust_bills)=qsearch('cust_bill',{});
62 if (scalar(@cust_bills) == 0)
63 {
64         exit 1;
65 }
66
67 # Open print and email pipes
68 # $lpr and opt_p for printing
69 # $email and opt_m for email
70
71 if ($lpr && $main::opt_p)
72 {
73         open(LPR, "|$lpr");
74 }
75
76 if ($email && $main::opt_m)
77 {
78         open (MAIL, "|$mail_program");
79         print MAIL <<END
80 To: $email
81 From: Account Processor
82 Subject: Sales Taxes Invoiced
83
84
85 END
86 }
87
88 my $comped = 0;
89 my $comped_tax = 0;
90 my $other = 0;
91 my $other_tax = 0;
92 my $total = 0;
93 my $taxed = 0;
94 my $untaxed = 0;
95 my $total_tax = 0;
96
97 # Now I can start looping
98 foreach my $cust_bill (@cust_bills)
99 {
100         my $_date = $cust_bill->getfield('_date');
101         my $invnum = $cust_bill->getfield('invnum');
102         my $charged = $cust_bill->getfield('charged');
103
104         if ($_date >= $_startdate && $_date <= $_finishdate) {
105                 $total += $charged;
106
107                 # The following lines were used to produce rather verbose reports
108                 #my ($sec,$min,$hour,$mday,$mon,$year) =
109                 #       (localtime($_date) )[0,1,2,3,4,5]; 
110                 #$mon++;
111                 #$year -= 100 if $year >= 100;
112                 #$year = "0" . $year if $year < 10;
113
114                 my $invoice_amt =0;
115                 my $invoice_tax =0;
116                 my $invoice_comped =0;
117                 my(@cust_bill_pkgs)= $cust_bill->cust_bill_pkg;
118                 foreach my $cust_bill_pkg (@cust_bill_pkgs) {
119
120                         my $recur = $cust_bill_pkg->getfield('recur');
121                         my $setup = $cust_bill_pkg->getfield('setup');
122                         my $pkgnum = $cust_bill_pkg->getfield('pkgnum');
123                         
124                         if ($pkgnum == 0) {
125                                 # The following line was used to produce rather verbose reports
126                                 # push @buf, ('', sprintf(qq{%10s%15s%14.2f}, "$mon/$mday/$year", "Tax $invnum", $recur+$setup));
127                                 $invoice_tax += $recur;
128                                 $invoice_tax += $setup;
129                         } else {
130                                 # The following line was used to produce rather verbose reports
131                                 # push @buf, ('', sprintf(qq{%10s%15s%14.2f}, "$mon/$mday/$year", "Inv $invnum", $recur+$setup));
132                                 $invoice_amt += $recur;
133                                 $invoice_amt += $setup;
134                         }
135
136                 }
137
138                 my(@cust_bill_pays)= $cust_bill->cust_bill_pay;
139                 foreach my $cust_bill_pay (@cust_bill_pays) {
140                         my $payby = $cust_bill_pay->cust_pay->payby;
141                         my $paid = $cust_bill_pay->getfield('amount');
142                         if ($payby =~ 'COMP') {
143                                 $invoice_comped += $paid;
144                         }
145                 }
146
147                 if (abs($invoice_comped - ($invoice_amt + $invoice_tax)) < 0.0001){
148                         $comped += $invoice_amt;
149                         $comped_tax += $invoice_tax;
150                 } elsif ($invoice_comped > 0) {
151                         push @buf, sprintf(qq{\nInvoice %10d has inexpliciable complimentary payments of %14.9f\n}, $invnum, $invoice_comped);
152                         $other += $invoice_amt;
153                         $other_tax += $invoice_tax;
154                 } elsif ($invoice_tax > 0) {
155                         $total_tax += $invoice_tax;
156                         $taxed += $invoice_amt;
157                 } else {
158                         $untaxed += $invoice_amt;
159                 }
160
161         }
162
163 }
164
165 push @buf, ('', sprintf(qq{%25s%14.2f}, "Complimentary", $comped));
166 push @buf, sprintf(qq{%25s%14.2f}, "Complimentary Tax", $comped_tax);
167 push @buf, sprintf(qq{%25s%14.2f}, "Other", $other);
168 push @buf, sprintf(qq{%25s%14.2f}, "Other Tax", $other_tax);
169 push @buf, sprintf(qq{%25s%14.2f}, "Untaxed", $untaxed);
170 push @buf, sprintf(qq{%25s%14.2f}, "Taxed", $taxed);
171 push @buf, sprintf(qq{%25s%14.2f}, "Tax", $total_tax);
172 push @buf, ('', sprintf(qq{%39s}, "========="), sprintf(qq{%39.2f}, $total));
173
174 sub FS::tax_report::_template::report_lines {
175   my $lines = shift;
176   map {
177     scalar(@buf) ? shift @buf : '' ;
178   }
179   ( 1 .. $lines );
180 }
181
182 $FS::tax_report::_template::title = qq~SALES TAXES INVOICED for $smon/$smday/$syear through $fmon/$fmday/$fyear~;
183 $FS::tax_report::_template::title = $opt_t if $opt_t;
184 $FS::tax_report::_template::page = 1;
185 $FS::tax_report::_template::date = $^T;
186 $FS::tax_report::_template::date = $^T;
187 $FS::tax_report::_template::fdate = $_finishdate;
188 $FS::tax_report::_template::fdate = $_finishdate;
189 $FS::tax_report::_template::sdate = $_startdate;
190 $FS::tax_report::_template::sdate = $_startdate;
191 $FS::tax_report::_template::total_pages = 
192   int( scalar(@buf) / $report_lines);
193 $FS::tax_report::_template::total_pages++ if scalar(@buf) % $report_lines;
194
195 my @report;
196 while (@buf) {
197   push @report, split("\n", 
198     $report_template->fill_in( PACKAGE => 'FS::tax_report::_template' )
199   );
200   $FS::tax_report::_template::page++;
201 }
202
203 if ($opt_v) {
204   print map "$_\n", @report;
205 }
206 if($lpr && $opt_p)
207 {
208   print LPR map "$_\n", @report;
209   print LPR "\f" if $opt_e;
210   close LPR || die "Could not close printer: $lpr\n";
211 }
212 if($email && $opt_m)
213 {
214   print MAIL map "$_\n", @report;
215   close MAIL || die "Could not close printer: $email\n";
216 }
217
218
219 # subroutines
220 sub untaint_argv {
221   foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV
222     $ARGV[$_] =~ /^([\w\-\/ :]*)$/ || die "Illegal argument \"$ARGV[$_]\"";
223     $ARGV[$_]=$1;
224   }
225 }
226
227 sub usage {
228   die "Usage:\n\n  freeside-tax-report [-v] [-p] [-e] user\n";
229 }
230
231 =head1 NAME
232
233 freeside-tax-report - Prints or emails sales taxes invoiced in a given period.
234
235 =head1 SYNOPSIS
236
237   freeside-tax-report [-v] [-p] [-m] [-e] [-t "title"] [-s date] [-f date] user
238
239 =head1 DESCRIPTION
240
241 Prints or emails sales taxes invoiced in a given period.
242
243 -v: Verbose - Prints records to STDOUT.
244
245 -p: Print to printer lpr as found in the conf directory.
246
247 -m: Email output to user found in the Conf email file.
248
249 -e: Print a final form feed to the printer.
250
251 -t: supply a title for the top of each page.
252
253 -s: starting date for inclusion
254
255 -f: final date for inclusion
256
257 user: From the mapsecrets file - see config.html from the base documentation
258
259 =head1 VERSION
260
261 $Id: freeside-tax-report,v 1.3 2002-03-06 00:17:32 ivan Exp $
262
263 =head1 BUGS
264
265 Yes..... Use at your own risk. No guarantees or warrantees of any
266 kind apply to this program. Parts of this program are hacked from
267 other GNU licensed software created mainly by Ivan Kohler.
268
269 This is released under the GNU Public License. See www.gnu.org
270 for more information regarding this license.
271
272 =head1 SEE ALSO
273
274 L<FS::cust_main>, config.html from the base documentation
275
276 =head1 AUTHOR
277
278 Jeff Finucane <jeff@cmh.net>
279
280 based on print-batch by Joel Griffiths <griff@aver-computer.com>
281
282 =cut
283