#!/usr/bin/perl -w use strict; use FS::Daemon ':all'; #daemonize1 drop_root daemonize2 myexit logfile sig* use FS::UID qw( adminsuidsetup ); use FS::Record qw( qsearch ); #qsearchs); #use FS::cdr; use FS::cust_pkg; use FS::queue; my $user = shift or die &usage; #daemonize1('freeside-sprepaidd', $user); #keep unique pid files w/multi installs daemonize1('freeside-cdrd'); drop_root(); adminsuidsetup($user); logfile( "%%%FREESIDE_LOG%%%/cdrd-log.". $FS::UID::datasrc ); daemonize2(); die "not running; no voip_cdr package defs w/ bill_every_call and customer pkgs" unless _shouldrun(); #-- my $addl_from = 'LEFT JOIN part_pkg USING ( pkgpart ) '. "LEFT JOIN part_pkg_option ON ( cust_pkg.pkgpart = part_pkg_option.pkgpart AND part_pkg_option.optionname = 'bill_every_call' )"; #XXX should pay attention to disable_src for efficiency my $extra_sql = "WHERE plan = 'voip_cdr' ". " AND optionvalue = '1' ". " AND ( susp IS NULL OR susp = 0)". " AND ( cancel IS NULL OR cancel = 0)". " AND EXISTS ( SELECT 1 FROM svc_phone LEFT JOIN cust_svc USING (svcnum) WHERE cust_pkg.pkgnum = cust_svc.pkgnum AND EXISTS ( SELECT 1 FROM cdr WHERE ( freesidestatus IS NULL OR freesidestatus = '' ) AND ( charged_party = svc_phone.phonenum OR charged_party = svc_phone.countrycode || svc_phone.phonenum OR src = svc_phone.phonenum OR src = svc_phone.countrycode || svc_phone.phonenum ) LIMIT 1 ) LIMIT 1 ) AND NOT EXISTS ( SELECT 1 FROM queue WHERE queue.job = 'FS::cust_main::queued_bill' AND queue.custnum = cust_pkg.custnum LIMIT 1 ) "; # don't repeatedly queue failures # AND status != 'failed' while (1) { my $found = 0; foreach my $cust_pkg ( qsearch( { 'select' => 'cust_pkg.*, part_pkg.plan', 'table' => 'cust_pkg', 'addl_from' => $addl_from, 'hashref' => {}, 'extra_sql' => $extra_sql, } ) ) { $found = 1; #my $work_cust_pkg = $cust_pkg; #my $cust_main = $cust_pkg->cust_main; my $time = time; my $job = new FS::queue { 'job' => 'FS::cust_main::queued_bill', 'secure' => 'Y', 'custnum' => $cust_pkg->custnum, }; my $error = $job->insert( 'custnum' => $cust_pkg->custnum, 'time' => $time, 'invoice_time' => $time, 'actual_time' => $time, 'check_freq' => '1d', #well #'debug' => 1, ); if ( $error ) { #die "FATAL: error inserting billing job: $error\n"; warn "WARNING: error inserting billing job (will retry in 30 seconds):". " $error\n"; sleep 30; #i dunno, wait and see if the database comes back? } } myexit() if sigterm() || sigint(); sleep 5 unless $found; } #-- sub _shouldrun { my $extra_sql = ' AND EXISTS ( SELECT 1 FROM cust_pkg WHERE cust_pkg.pkgpart = part_pkg.pkgpart AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 ) ) '; my @part_pkg = grep $_->option('bill_every_call', 'hush'), qsearch({ 'table' => 'part_pkg', 'hashref' => { 'plan' => 'voip_cdr' }, 'extra_sql' => $extra_sql, }) ; scalar(@part_pkg); } sub usage { die "Usage:\n\n freeside-cdrd user\n"; } =head1 NAME freeside-cdrd - Real-time daemon for CDRs =head1 SYNOPSIS freeside-cdrd =head1 DESCRIPTION Runs continuously, searches for CDRs and bills customers who have VoIP price plands with the B option set. =head1 SEE ALSO =cut 1;