3 use FS::Record qw(qsearch qsearchs);
14 cdr-manual-rate -f freesidestatus [ -s startdate ] [ -e enddate ] user
18 $FS::UID::AutoCommit = 1; # because partial completion of this is useful
22 $where_date = " AND startdate >= $opt{start} ";
25 $where_date .= " AND startdate < $opt{end} ";
28 my $cursor = FS::Cursor->new({
30 'hashref' => { freesidestatus => $opt{f} },
31 'extra_sql' => $where_date,
34 our %svc_phone = (); # phonenum => svc_phone
35 our %pkgnum = (); # phonenum => pkgnum
36 our %cust_pkg = (); # pkgnum => cust_pkg
37 our %pkgpart = (); # phonenum => pkgpart
38 our %part_pkg = (); # pkgpart => part_pkg
46 while (my $cdr = $cursor->fetch) {
49 my $cdrdesc = "CDR ". $cdr->acctid.", ".$cdr->src." -> ".$cdr->dst;
51 # borrow CDR-to-package matching code from cdrrated...
52 my $number = $cdr->charged_party || $cdr->src;
54 # strip the prefix from the number
55 my $prefix = '+1'; #$options{'default_prefix'};
57 $number = substr($number, length($prefix))
58 if $prefix eq substr($number, 0, length($prefix));
59 if ( $prefix && $prefix =~ /^\+(\d+)$/ ) {
61 $number = substr($number, length($prefix))
62 if $prefix eq substr($number, 0, length($prefix));
65 # find a svc_phone that matches it
66 unless ( $svc_phone{$number} ) {
67 #only phone number matching supported right now
68 my $svc_phone = qsearchs('svc_phone', { 'phonenum' => $number } );
69 unless ( $svc_phone ) {
70 warn "can't find a phone service for $cdrdesc\n";
75 $svc_phone{$number} = $svc_phone;
80 unless ( $pkgnum{$number} ) {
82 my $cust_pkg = $svc_phone{$number}->cust_svc->cust_pkg;
84 warn "can't find a package for $cdrdesc\n";
88 $pkgnum{$number} = $cust_pkg->pkgnum;
89 $cust_pkg{$cust_pkg->pkgnum} ||= $cust_pkg;
93 unless ( $pkgpart{$number} ) {
94 #get the package, search through the part_pkg and linked for a voip_cdr def w/matching cdrtypenum (or no use_cdrtypenum)
95 my $cust_pkg = $cust_pkg{$pkgnum{$number}};
97 foreach ($cust_pkg->part_pkg->self_and_bill_linked) {
98 if ($_->plan eq 'voip_cdr'
99 && ( ! length($_->option_cacheable('use_cdrtypenum'))
100 || $_->option_cacheable('use_cdrtypenum')
101 eq $cdr->cdrtypenum #eq otherwise 0 matches ''
103 && ( ! length($_->option_cacheable('ignore_cdrtypenum'))
104 || $_->option_cacheable('ignore_cdrtypenum')
105 ne $cdr->cdrtypenum #ne otherwise 0 matches ''
114 warn "can't find a voip_cdr package definition for $cdrdesc\n";
117 } elsif (scalar(@part_pkg) > 1) {
118 warn "found more than one package that could rate $cdrdesc\n";
123 $pkgpart{$number} = $part_pkg[0]->pkgpart;
124 $part_pkg{ $part_pkg[0]->pkgpart } ||= $part_pkg[0];
126 } # unless $pkgpart{$number}
128 # now actually rate the call. ignore included minutes, since that's a
129 # property of the billing cycle and this call isn't part of a billing
131 my $error = $cdr->rate(
132 'part_pkg' => $part_pkg{ $pkgpart{$number} },
133 'cust_pkg' => $cust_pkg{ $pkgnum{$number} },
134 'svcnum' => $svc_phone{$number}->svcnum,
137 warn "can't rate $cdrdesc: $error\n";
141 $error = $cdr->set_status('done');
143 # don't know how this would happen...
144 warn "can't set status on $cdrdesc: $error\n";
154 Incomplete information: $notfound
155 Failed rating: $failed
156 Successfully rated: $success