credit limit for CDR prerating, RT#27267
[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' => { 'status' => 'rated',
48                    'svcnum' => { op    => 'IN',
49                                  value => '('. join(',',@svcnum). ')',
50                                },
51                  },
52   } );
53
54   return '' unless $sum->rated_price > $credit_limit;
55
56   #XXX trigger an alert
57   # (email send / ticket create / nagios alert export) ?
58   # maybe an over_credit_limit cust_main export or some such?
59
60   # record we did it so we don't do it continuously
61   my $cust_main_credit_limit = new FS::cust_main_credit_limit {
62     'custnum'      => $self->custnum,
63     '_date'        => time,
64     'credit_limit' => $credit_limit,
65     'amount'       => sprintf('%.2f', $sum->rated_price ),
66   };
67   my $error = $cust_main_credit_limit->insert;
68   if ( $error ) {
69     #"should never happen", but better to survive e.g. database going
70     # away and coming back and resume doing our thing
71     warn $error;
72     sleep 30;
73   }
74
75 }
76
77 sub num_cust_main_credit_limit {
78   my $self = shift;
79
80   my $sql = 'SELECT COUNT(*) FROM cust_main_credit_limit WHERE custnum = ?';
81   my $sth = dbh->prepare($sql)   or die  dbh->errstr;
82   $sth->execute( $self->custnum) or die $sth->errstr;
83
84   $sth->fetchrow_arrayref->[0];
85 }
86
87 1;