restore fallback to customer billing address for CC transactions, RT#77641, RT#71513
[freeside.git] / FS / FS / cust_main / Credit_Limit.pm
1 package FS::cust_main::Credit_Limit;
2
3 use strict;
4 use vars qw( $conf $default_credit_limit $credit_limit_delay );
5 use FS::UID qw( dbh );
6 use FS::Record qw( qsearchs );
7 use FS::cust_main_credit_limit;
8
9 #ask FS::UID to run this stuff for us later
10 install_callback FS::UID sub { 
11   $conf = new FS::Conf;
12   #yes, need it for stuff below (prolly should be cached)
13   $default_credit_limit = $conf->config('default_credit_limit') || 0;
14 };
15
16 $credit_limit_delay = 6 * 60 * 60; #6 hours?  conf?
17
18 sub check_credit_limit {
19   my $self = shift;
20
21   my $credit_limit = $self->credit_limit || $default_credit_limit;
22
23   return '' unless $credit_limit > 0;
24
25   #see if we've already triggered this credit limit recently
26   return ''
27     if qsearchs({
28          'table'    => 'cust_main_credit_limit',
29          'hashref'  => {
30            'custnum'      => $self->custnum,
31            'credit_limit' => { op=>'>=', value=> $credit_limit },
32            '_date'        => { op=>'>=', value=> time - $credit_limit_delay, },
33          },
34          'order_by' => 'LIMIT 1',
35        });
36
37   #count up prerated CDRs
38
39   my @cust_svc = map $_->cust_svc_unsorted( 'svcdb'=>'svc_phone' ),
40                    $self->all_pkgs;
41   my @svcnum = map $_->svcnum, @cust_svc;
42
43   #false laziness  w/svc_phone->sum_cdrs / psearch_cdrs
44   my $sum = qsearchs( {
45     'select'    => 'SUM(rated_price) AS rated_price',
46     'table'     => 'cdr',
47     #'hashref'   => { 'freesidestatus' => 'rated', },
48     'extra_sql' => " WHERE freesidestatus = 'rated' ".
49                    ' AND svcnum IN ('. join(',',@svcnum). ') ',
50   } );
51
52   return '' unless $sum->rated_price > $credit_limit;
53
54   #XXX trigger an alert
55   # (email send / ticket create / nagios alert export) ?
56   # maybe an over_credit_limit cust_main export or some such?
57
58   # record we did it so we don't do it continuously
59   my $cust_main_credit_limit = new FS::cust_main_credit_limit {
60     'custnum'      => $self->custnum,
61     '_date'        => time,
62     'credit_limit' => $credit_limit,
63     'amount'       => sprintf('%.2f', $sum->rated_price ),
64   };
65   my $error = $cust_main_credit_limit->insert;
66   if ( $error ) {
67     #"should never happen", but better to survive e.g. database going
68     # away and coming back and resume doing our thing
69     warn $error;
70     sleep 30;
71   }
72
73 }
74
75 sub num_cust_main_credit_limit {
76   my $self = shift;
77
78   my $sql = 'SELECT COUNT(*) FROM cust_main_credit_limit WHERE custnum = ?';
79   my $sth = dbh->prepare($sql)   or die  dbh->errstr;
80   $sth->execute( $self->custnum) or die $sth->errstr;
81
82   $sth->fetchrow_arrayref->[0];
83 }
84
85 1;