fix encryption upgrades when a payment is refunded, then deleted. RT#74270, RT#73085
[freeside.git] / FS / bin / freeside-cdrd
1 #!/usr/bin/perl -w
2
3 use strict;
4 use FS::Daemon ':all'; #daemonize1 drop_root daemonize2 myexit logfile sig*
5 use FS::UID qw( adminsuidsetup );
6 use FS::Record qw( qsearch ); #qsearchs);
7 #use FS::cdr;
8 use FS::cust_pkg;
9 use FS::queue;
10
11 my $user = shift or die &usage;
12
13 #daemonize1('freeside-sprepaidd', $user); #keep unique pid files w/multi installs
14 daemonize1('freeside-cdrd');
15
16 drop_root();
17
18 adminsuidsetup($user);
19
20 logfile( "%%%FREESIDE_LOG%%%/cdrd-log.". $FS::UID::datasrc );
21
22 daemonize2();
23
24 die "not running; no voip_cdr package defs w/ bill_every_call and customer pkgs"
25   unless _shouldrun();
26
27 #--
28
29 my $addl_from =
30   'LEFT JOIN part_pkg USING ( pkgpart ) '.
31   "LEFT JOIN part_pkg_option
32      ON ( cust_pkg.pkgpart = part_pkg_option.pkgpart
33           AND part_pkg_option.optionname = 'bill_every_call' )";
34
35 #XXX should pay attention to disable_src for efficiency
36
37 my $extra_sql =
38   "WHERE plan = 'voip_cdr' ".
39   " AND optionvalue = '1' ".
40   " AND ( susp   IS NULL OR susp   = 0)".
41   " AND ( cancel IS NULL OR cancel = 0)".
42   " AND EXISTS ( 
43       SELECT 1 FROM svc_phone LEFT JOIN cust_svc USING (svcnum)
44         WHERE cust_pkg.pkgnum = cust_svc.pkgnum
45           AND EXISTS ( SELECT 1 FROM cdr
46                          WHERE ( freesidestatus IS NULL OR freesidestatus = '' )
47                            AND (    charged_party = svc_phone.phonenum
48                                  OR charged_party = svc_phone.countrycode
49                                                     || svc_phone.phonenum
50                                  OR src = svc_phone.phonenum
51                                  OR src = svc_phone.countrycode
52                                           || svc_phone.phonenum
53                                )
54                          LIMIT 1
55                      )
56         LIMIT 1
57     )
58     AND NOT EXISTS (
59       SELECT 1 FROM queue
60         WHERE queue.job = 'FS::cust_main::queued_bill'
61           AND queue.custnum = cust_pkg.custnum
62         LIMIT 1
63     )
64     
65   ";
66 # don't repeatedly queue failures
67 #          AND status != 'failed'
68
69 while (1) {
70
71   my $found = 0;
72   foreach my $cust_pkg ( 
73     qsearch( {
74       'select'    => 'cust_pkg.*, part_pkg.plan',
75       'table'     => 'cust_pkg',
76       'addl_from' => $addl_from,
77       'hashref'   => {},
78       'extra_sql' => $extra_sql,
79     } )
80   ) {
81
82     $found = 1;
83
84     #my $work_cust_pkg = $cust_pkg;
85
86     #my $cust_main = $cust_pkg->cust_main;
87
88     my $time = time;
89
90     my $job = new FS::queue {
91       'job'     => 'FS::cust_main::queued_bill',
92       'secure'  => 'Y',
93       'custnum' => $cust_pkg->custnum,
94     };
95     my $error = $job->insert(
96       'custnum'      => $cust_pkg->custnum, 
97       'time'         => $time,
98       'invoice_time' => $time,
99       'actual_time'  => $time,
100       'check_freq'   => '1d', #well
101       #'debug'        => 1,
102     );
103
104     if ( $error ) {
105       #die "FATAL: error inserting billing job: $error\n";
106       warn "WARNING: error inserting billing job (will retry in 30 seconds):".
107            " $error\n";
108       sleep 30; #i dunno, wait and see if the database comes back?
109     }
110
111   }
112
113   myexit() if sigterm() || sigint();
114   sleep 5 unless $found;
115
116 }
117
118 #--
119
120 sub _shouldrun {
121
122   my $extra_sql =
123     ' AND EXISTS ( SELECT 1 FROM cust_pkg
124                      WHERE cust_pkg.pkgpart = part_pkg.pkgpart
125                        AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )
126                  )
127     ';
128
129   my @part_pkg =
130     grep $_->option('bill_every_call', 'hush'),
131     qsearch({
132       'table'     => 'part_pkg',
133       'hashref'   => { 'plan' => 'voip_cdr' },
134       'extra_sql' => $extra_sql,
135     })
136   ;
137
138   scalar(@part_pkg);
139
140 }
141
142 sub usage { 
143   die "Usage:\n\n  freeside-cdrd user\n";
144 }
145
146 =head1 NAME
147
148 freeside-cdrd - Real-time daemon for CDRs
149
150 =head1 SYNOPSIS
151
152   freeside-cdrd
153
154 =head1 DESCRIPTION
155
156 Runs continuously, searches for CDRs and bills customers who have VoIP
157 price plands with the B<bill_every_call> option set.
158
159 =head1 SEE ALSO
160
161 =cut
162
163 1;