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