script to rewrite Taqua CDRs with accountcode/caller id status, #72355
[freeside.git] / bin / taqua-accountcode-rewrite
1 #!/usr/bin/perl
2
3 my $usage = "
4 This script is for fixing CDRs that were supposed to receive Taqua
5 accountcode/caller ID rewrites but didn't. It will skip records that had
6 any rewrites performed, but will operate on CDRs that have already been
7 billed. Options:
8
9 -s DATE: find calls on or after DATE (required)
10 -e DATE: find calls on or before DATE (optional, defaults to right now)
11 -v: show records as they're updated
12 ";
13
14 use strict;
15 use FS::Misc::Getopt;
16 use FS::Record qw(qsearch qsearchs dbh);
17 use FS::Cursor;
18 our %opt;
19 our $DEBUG;
20
21 getopts('');
22
23 die $usage unless $opt{start};
24
25 my $fixed = 0;
26 my $notfound = 0;
27 my $failed = 0;
28 my $extra_sql = 'WHERE lastapp IS NOT NULL AND freesiderewritestatus IS NULL' .
29                 ' AND cdrtypenum = 1'.
30                 ' AND calldate >= to_timestamp('.$opt{start}.')';
31 if ( $opt{end} ) {
32   $extra_sql .= ' AND calldate < to_timestamp('.$opt{end}.')';
33 }
34 my $cursor = FS::Cursor->new({
35   table     => 'cdr',
36   hashref   => {},
37   extra_sql => $extra_sql,
38 });
39
40 $FS::UID::AutoCommit = 0;
41
42 while (my $cdr = $cursor->fetch) {
43   # copy-paste from cdrrewrited, except:
44   # - move all conditions for this rewrite into the SQL
45   # - don't check for config option to enable rewriting
46   # - don't retry, don't remember not-found acctids
47
48   my @status;
49
50   #find the matching CDR
51   my %search = ( 'sessionnum' => $cdr->sessionnum );
52   if ( $cdr->lastapp eq 'acctcode' ) {
53     $search{'src'} = $cdr->subscriber;
54   } elsif ( $cdr->lastapp eq 'CallerId' ) {
55     $search{'dst'} = $cdr->subscriber;
56   }
57   if ($DEBUG) {
58     my $desc = '#'.$cdr->acctid . ': sessionnum ' . $cdr->sessionnum .  ', '.
59       "subscriber ".$cdr->subscriber;
60     warn $desc."\n";
61   }
62   my $primary = qsearchs('cdr', \%search);
63
64   unless ( $primary ) {
65
66     my $cantfind = "can't find primary CDR with session ". $cdr->sessionnum .
67                    ', ';
68     if ($search{'src'}) {
69       $cantfind .= 'src '.$search{'src'};
70     } else {
71       $cantfind .= 'dst '.$search{'dst'};
72     }
73     warn "ERROR: $cantfind\n";
74     $notfound++;
75     next;
76
77   } else {
78
79     if ( $cdr->lastapp eq 'acctcode' ) {
80       # lastdata contains the dialed account code
81       $primary->accountcode( $cdr->lastdata );
82       push @status, 'taqua-accountcode';
83       warn '#'.$primary->acctid . ': accountcode = '.$cdr->lastdata . "\n"
84         if $DEBUG;
85     } elsif ( $cdr->lastapp eq 'CallerId' ) {
86       # lastdata contains "allowed" or "restricted"
87       # or case variants thereof
88       if ( lc($cdr->lastdata) eq 'restricted' ) {
89         $primary->clid( 'PRIVATE' );
90       }
91       push @status, 'taqua-callerid';
92       warn '#'.$primary->acctid . ': clid = '.$cdr->lastdata . "\n"
93         if $DEBUG;
94     } else {
95       warn "unknown Taqua service name: ".$cdr->lastapp."\n";
96     }
97     #$primary->freesiderewritestatus( 'taqua-accountcode-primary' );
98     my $error = $primary->replace if $primary->modified;
99     if ( $error ) {
100       warn "WARNING: error rewriting primary CDR: $error\n";
101       $failed++;
102       dbh->rollback;
103       next;
104     }
105     if ( $primary->freesidestatus eq 'done' and
106          $cdr->lastapp eq 'acctcode' and
107          $primary->rated_price > 0 ) {
108       # then have to update the billing detail also
109       my $detail;
110       if ( $primary->detailnum ) {
111         # has been on 3.x since January 2016...
112         $detail = qsearchs('cust_bill_pkg_detail', {
113           'detailnum' => $primary->detailnum
114         });
115       } else {
116         # otherwise, try our best: find a detail with the right price,
117         # source number, and start and end dates
118         $detail = qsearchs('cust_bill_pkg_detail', {
119           'amount'     => $primary->rated_price,
120           'classnum'   => $cdr->rated_classnum,
121           'duration'   => $primary->rated_seconds,
122           'startdate'  => $primary->startdate,
123           'format'     => 'C',
124           'phonenum'   => $primary->src, # not perfect
125         });
126       }
127       if ($detail) {
128         warn "detail #".$detail->detailnum."\n" if $DEBUG;
129         $detail->set('accountcode', $primary->accountcode);
130         $error = $detail->replace;
131         if ($error) {
132           warn "WARNING: error rewriting invoice detail: $error\n";
133           $failed++;
134           dbh->rollback;
135           next;
136         }
137       } else {
138         warn "ERROR: can't find invoice detail for cdr#".$primary->acctid."\n";
139         $notfound++;
140         dbh->rollback;
141         next;
142       }
143     } # if this is an acctcode record and the primary was billed
144
145     $cdr->status('done'); #so it doesn't try to rate
146
147   }
148
149   $cdr->freesiderewritestatus(
150     scalar(@status) ? join('/', @status) : 'skipped'
151   );
152
153   my $error = $cdr->replace;
154   if ( $error ) {
155     warn "WARNING: error rewriting CDR: $error\n";
156     dbh->rollback;
157     $failed++;
158   } else {
159     dbh->commit;
160     $fixed++;
161   }
162 }
163
164 print "Finished.
165 Rewrites: $fixed
166 Primary record not found: $notfound
167 Errors: $failed
168 ";