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