add datestamp to batch name derived from filename, remove temp files for all errors...
[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 0 < ( 
43       SELECT COUNT(*) FROM svc_phone LEFT JOIN cust_svc USING (svcnum)
44         WHERE cust_pkg.pkgnum = cust_svc.pkgnum
45           AND 0 < ( SELECT COUNT(*) 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                   )
55     )
56     AND 0 = (
57       SELECT COUNT(*) FROM queue
58         WHERE queue.job = 'FS::cust_main::queued_bill'
59           AND queue.custnum = cust_pkg.custnum
60     )
61     
62   ";
63 # don't repeatedly queue failures
64 #          AND status != 'failed'
65
66 while (1) {
67
68   my $found = 0;
69   foreach my $cust_pkg ( 
70     qsearch( {
71       'select'    => 'cust_pkg.*, part_pkg.plan',
72       'table'     => 'cust_pkg',
73       'addl_from' => $addl_from,
74       'hashref'   => {},
75       'extra_sql' => $extra_sql,
76     } )
77   ) {
78
79     $found = 1;
80
81     #my $work_cust_pkg = $cust_pkg;
82
83     #my $cust_main = $cust_pkg->cust_main;
84
85     my $time = time;
86
87     my $job = new FS::queue {
88       'job'     => 'FS::cust_main::queued_bill',
89       'secure'  => 'Y',
90       'custnum' => $cust_pkg->custnum,
91     };
92     my $error = $job->insert(
93       'custnum'      => $cust_pkg->custnum, 
94       'time'         => $time,
95       'invoice_time' => $time,
96       'actual_time'  => $time,
97       'check_freq'   => '1d', #well
98       #'debug'        => 1,
99     );
100
101     if ( $error ) {
102       #die "FATAL: error inserting billing job: $error\n";
103       warn "WARNING: error inserting billing job (will retry in 30 seconds):".
104            " $error\n";
105       sleep 30; #i dunno, wait and see if the database comes back?
106     }
107
108   }
109
110   myexit() if sigterm() || sigint();
111   sleep 1 unless $found;
112
113 }
114
115 #--
116
117 sub _shouldrun {
118
119   my $extra_sql =
120     ' AND 0 < ( SELECT COUNT(*) FROM cust_pkg
121                   WHERE cust_pkg.pkgpart = part_pkg.pkgpart
122                     AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )
123               )
124     ';
125
126   my @part_pkg =
127     grep $_->option('bill_every_call', 'hush'),
128     qsearch({
129       'table'     => 'part_pkg',
130       'hashref'   => { 'plan' => 'voip_cdr' },
131       'extra_sql' => $extra_sql,
132     })
133   ;
134
135   scalar(@part_pkg);
136
137 }
138
139 sub usage { 
140   die "Usage:\n\n  freeside-cdrd user\n";
141 }
142
143 =head1 NAME
144
145 freeside-cdrd - Real-time daemon for CDRs
146
147 =head1 SYNOPSIS
148
149   freeside-cdrd
150
151 =head1 DESCRIPTION
152
153 Runs continuously, searches for CDRs and bills customers who have VoIP
154 price plands with the B<bill_every_call> option set.
155
156 =head1 SEE ALSO
157
158 =cut
159
160 1;