billing expiration alerts
[freeside.git] / FS / bin / freeside-expiration-alerter
1 #!/usr/bin/perl -Tw
2
3 use strict;
4 use Date::Format;
5 use Time::Local;
6 use Text::Template;
7 use Getopt::Std;
8 use FS::Conf;
9 use FS::UID qw(adminsuidsetup);
10 use FS::Record qw(qsearch);
11 use FS::cust_main;
12
13 use vars qw($smtpmachine);
14
15 #hush, perl!
16 $FS::alerter::_template::first = "";
17 $FS::alerter::_template::last = "";
18 $FS::alerter::_template::company = "";
19 $FS::alerter::_template::payby = "";
20 $FS::alerter::_template::expdate = "";
21
22 # Set the mail program  and other variables
23 my $mail_program = "/usr/sbin/sendmail -t -n"; 
24 my $mail_sender = "billing\@mydomain.tld"; 
25 my $default_mail_recipient = "postmaster";
26 my $warning_time = 30 * 24 * 60 * 60;
27 my $urgent_time = 15 * 24 * 60 * 60;
28 my $panic_time = 5 * 24 * 60 * 60;
29 my $window_time = 24 * 60 * 60;
30
31 &untaint_argv;  #what it sounds like  (eww)
32
33 #we're at now now (and later).
34 my($_date)= $^T;
35
36 # Get the current month
37 my ($sec,$min,$hour,$mday,$mon,$year) =
38         (localtime($_date) )[0,1,2,3,4,5]; 
39 $mon++;
40
41 # Login to the database
42 my $user = shift or die &usage;
43 adminsuidsetup $user;
44
45 # Get the needed configuration files
46 my $conf = new FS::Conf;
47 $smtpmachine = $conf->config('smtpmachine');
48
49 my(@customers)=qsearch('cust_main',{});
50 if (scalar(@customers) == 0)
51 {
52   exit 1;
53 }
54
55 # Open email pipe
56
57 open (MAIL, "|$mail_program");
58 print MAIL <<END
59 To: $default_mail_recipient
60 From: Account Processor
61 Subject: Unnotified Billing Arrangement Expirations
62
63
64 END
65
66 ;
67
68 my @alerter_template = $conf->config('alerter_template')
69   or die "cannot load config file alerter_template";
70
71 my $alerter = new Text::Template (TYPE => 'ARRAY', SOURCE => [ map "$_\n", @alerter_template ])
72   or die "can't create new Text::Template object:  Text::Template::ERROR";
73 $alerter->compile() or die "can't compile template:  Text::Template::ERROR";
74
75 # Now I can start looping
76 foreach my $customer (@customers)
77 {
78   my $custnum = $customer->getfield('custnum');
79   my $first = $customer->getfield('first');
80   my $last = $customer->getfield('last');
81   my $company = $customer->getfield('company');
82   my $payby = $customer->getfield('payby');
83   my $payinfo = $customer->getfield('payinfo');
84   my $paydate = $customer->getfield('paydate');
85   my $daytime = $customer->getfield('daytime');
86   my $night = $customer->getfield('night');
87         
88   my ($payyear,$paymonth,$payday) = split (/-/,$paydate);
89
90   my $expire_time = timelocal(0,0,0,$payday,--$paymonth,$payyear);
91
92   #credit cards expire at the end of the month/year of their exp date
93   if ($payby eq 'CARD') {
94     ($paymonth < 11) ? $paymonth++ : ($paymonth=0, $payyear++);
95     $expire_time = timelocal(0,0,0,$payday,$paymonth,$payyear);
96     $expire_time--;
97   }
98
99   if (($expire_time < $_date + $warning_time &&
100     $expire_time > $_date + $warning_time - $window_time) ||
101       ($expire_time < $_date + $urgent_time &&
102        $expire_time > $_date + $urgent_time - $window_time) ||
103       ($expire_time < $_date + $panic_time &&
104        $expire_time > $_date + $panic_time - $window_time)) {
105
106
107
108     my @packages = $customer->ncancelled_pkgs;
109     if (scalar(@packages) != 0) {
110       my @invoicing_list = $customer->invoicing_list;
111       if ( grep { $_ ne 'POST' } @invoicing_list ) { 
112         $ENV{SMTPHOSTS} = $smtpmachine;
113         $ENV{MAILADDRESS} = $mail_sender;
114         my $header = new Mail::Header ( [
115           "From: $mail_sender",
116           "To: ". join(', ', grep { $_ ne 'POST' } @invoicing_list ),
117           "Sender: $mail_sender",
118           "Reply-To: $mail_sender",
119           "Date: ". time2str("%a, %d %b %Y %X %z", time),
120           "Subject: Billing Arrangement Expiration",
121         ] );
122         $FS::alerter::_template::first = $first;
123         $FS::alerter::_template::last = $last;
124         $FS::alerter::_template::company = $company;
125         if ($payby eq 'CARD') {
126           $FS::alerter::_template::payby = "credit card (" .
127             substr($payinfo, 0, 2) . "xxxxxxxxxx" .
128             substr($payinfo, -4) . ")";
129         }elsif ($payby eq 'COMP') {
130           $FS::alerter::_template::payby = "complimentary account";
131         }else{
132           $FS::alerter::_template::payby = "current method";
133         }
134         $FS::alerter::_template::expdate = $expire_time;
135
136         my $message = new Mail::Internet (
137           'Header' => $header,
138           'Body' => [ $alerter->fill_in( PACKAGE => 'FS::alerter::_template' ) ],
139         );
140         $message->smtpsend or die "Can't send invoice email!: $!"; #die?  warn?
141
142       } elsif ( ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list ) { 
143         printf(MAIL qq{%5d %-32.32s %4s %10s %12s %12s\n},
144           $custnum,
145           $first . " " . $last . "   " . $company,
146           $payby,
147           $paydate,
148           $daytime,
149           $night);
150       }
151     }
152   }
153 }
154
155 # Now I need to close EMAIL
156 close MAIL || die "Could not close printer: $default_mail_recipient\n";
157
158
159 # subroutines
160 sub untaint_argv {
161   foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV
162     $ARGV[$_] =~ /^([\w\-\/]*)$/ || die "Illegal argument \"$ARGV[$_]\"";
163     $ARGV[$_]=$1;
164   }
165 }
166
167 sub usage {
168   die "Usage:\n\n  freeside-expiration-alerter user\n";
169 }
170
171 =head1 NAME
172
173 freeside-expiration-alerter - Emails notifications of credit card expirations.
174
175 =head1 SYNOPSIS
176
177   freeside-expiration-alerter user
178
179 =head1 DESCRIPTION
180
181 Emails customers notice that their credit card or other billing arrangement
182 is about to expire.  Usually run as a cron job.
183
184 user: From the mapsecrets file - see config.html from the base documentation
185
186 =head1 VERSION
187
188 $Id: freeside-expiration-alerter,v 1.1 2002-03-06 22:44:13 jeff Exp $
189
190 =head1 BUGS
191
192 Yes..... Use at your own risk. No guarantees or warrantees of any
193 kind apply to this program. Parts of this program are hacked from
194 other GNU licensed software created mainly by Ivan Kohler.
195
196 This is released under the GNU Public License. See www.gnu.org
197 for more information regarding this license.
198
199 =head1 SEE ALSO
200
201 L<FS::cust_main>, config.html from the base documentation
202
203 =head1 AUTHOR
204
205 Jeff Finucane <jeff@cmh.net>
206
207 =cut
208
209