add condition_sql optimization to "Customer does not have uncancelled package of...
[freeside.git] / bin / rate-level3-us.import
1 #!/usr/bin/perl -w
2
3 use strict;
4
5 use FS::UID qw(adminsuidsetup);
6 use Spreadsheet::ParseExcel;
7 use FS::Record qw(qsearchs);
8 use FS::rate;
9 use FS::rate_region;
10 use FS::rate_prefix;
11 use FS::rate_detail;
12 use FS::usage_class;
13
14 use Text::CSV_XS;
15
16 my $user = shift or usage();
17 my $file = shift or usage();
18 adminsuidsetup $user;
19
20 sub usage {
21   die "Usage:\n\n  rate-level3-us.import user rates.xls [ multiplier ]\n";
22 }
23
24 my %lata_ocn;
25
26 my $csvfile = 'npa-nxx-companytype-ocn.csv'; # not distributed here
27 #NPA,NXX,COMPANY TYPE,OCN,COMPANY NAME,LATA,RATECENTER,STATE
28 open my $fh, '<', $csvfile
29   or die $!;
30
31 my $csv = Text::CSV_XS->new;
32 while (!$csv->eof) {
33   my $row = $csv->getline($fh);
34   my $lata = $row->[5] or next;
35   my $ocn = $row->[3];
36   my $key = $lata . '-' . $ocn;
37   push @{ $lata_ocn{$key} ||= [] },
38     { npa => $row->[0],
39       nxx => $row->[1],
40       ratecenter => $row->[6],
41       state => $row->[7]
42     }
43   ;
44 }
45
46 my $multiplier = shift;
47 $multiplier ||= 1;
48
49 my $parser = Spreadsheet::ParseExcel->new;
50 my $book = $parser->parse($file);
51 my $sheet = $book->worksheet('VT - US48 OCN Rates')
52   or die "No 'VT - US48 OCN Rates' sheet found.\n";
53
54 my $row = 0;
55 for (; $row < 256; $row++) {
56   if (lc($sheet->get_cell($row, 0)->value) eq 'lata') {
57     last;
58   }
59 }
60 die "Start of data table not found.\n" if $row == 256;
61
62 my $error;
63
64 my $granularity = 1;
65 # default is to charge per second; edit this if needed
66
67
68 my %rate;
69 my %classnum;
70 foreach (qw(INTERSTATE INTRASTATE)) {
71   my $rate = qsearchs('rate', { 'ratename' => $_ });
72   if (!$rate) {
73     $rate = FS::rate->new({ 'ratename' => $_ });
74     $error = $rate->insert;
75     die $error if $error;
76   }
77   $rate{$_} = $rate;
78   my $class = qsearchs('usage_class', { 'classname' => ucfirst($_) });
79   $classnum{$_} = $class->classnum if $class;
80 }
81
82 $row++;
83 my ($lata, $ocn, $jurisdiction, $charge) = @_;
84 while ( $sheet->get_cell($row, 0) ) {
85   ($lata, $ocn, $jurisdiction, $charge) = map {
86     $sheet->get_cell($row, $_)->value
87   } 0..3;
88
89   last if !$lata;
90
91   print join("\t", $lata, $ocn, $jurisdiction, $charge),"\n";
92
93   my $here = '[line '.($row+1).']';
94
95   my @regionnums; # add the rate to each of these...
96
97   if ( $lata eq '*' ) {
98
99     my $regionname = 'Other US';
100     my $region = qsearchs('rate_region', { 'regionname' => $regionname });
101     if (!$region) {
102       $region = FS::rate_region->new({ 'regionname' => $regionname });
103       $error = $region->insert;
104       die "$here inserting region: $error\n" if $error;
105     }
106     my %prefix = (
107       'regionnum' => $region->regionnum,
108       'countrycode' => '1',
109       'npa' => '',
110       'nxx' => '',
111     );
112     my $rate_prefix = qsearchs('rate_prefix', \%prefix);
113     if (!$rate_prefix) {
114       $rate_prefix = FS::rate_prefix->new(\%prefix);
115       $error = $rate_prefix->insert;
116       die "$here inserting prefix: $error\n" if $error;
117     }
118     push @regionnums, $region->regionnum;
119
120   } else {
121
122     my $data = $lata_ocn{"$lata-$ocn"};
123     if (!$data) {
124       warn "$here no prefixes found for lata $lata / ocn $ocn\n";
125       next;
126     }
127
128     # find prefixes corresponding to this LATA/OCN. there can be MANY.
129
130     foreach my $prefixdata (@$data) {
131       my $npa = $prefixdata->{npa}
132         or die "$here no NPA found.\n";
133       my $nxx = $prefixdata->{nxx}
134         or die "$here no NXX found.\n";
135
136       # show a useful regionname, but include the LATA/OCN in it to
137       # prevent overlap.
138       my $regionname = $prefixdata->{ratecenter} . ', ' .
139                        $prefixdata->{state} .
140                        " $lata-$ocn";
141
142       my $region = qsearchs('rate_region', { 'regionname' => $regionname });
143       if (!$region) {
144         $region = FS::rate_region->new({ 'regionname' => $regionname });
145         $error = $region->insert;
146         die "$here inserting region: $error\n" if $error;
147       }
148
149       my %prefix = (
150         'regionnum'   => $region->regionnum,
151         'countrycode' => '1',
152         'npa'         => $npa . $nxx,
153       );
154       my $rate_prefix = qsearchs('rate_prefix', \%prefix);
155       if (!$rate_prefix) {
156         # don't search on unindexed fields
157         $prefix{'latanum'} = $lata;
158         $prefix{'ocn'}     = $ocn;
159         $prefix{'state'}   = $prefixdata->{state},
160         $rate_prefix = FS::rate_prefix->new(\%prefix);
161         $error = $rate_prefix->insert;
162         die "$here inserting prefix: $error\n" if $error;
163       }
164       push @regionnums, $region->regionnum;
165     } # foreach $prefixdata
166
167   } # $lata ne '*'
168
169   $charge =~ s/^[\s\$]*//;
170   $charge = sprintf('%.05f', $charge * $multiplier);
171
172   foreach my $regionnum (@regionnums) {
173     my $rate = $rate{$jurisdiction}
174       or die "$here unknown jurisdiction $jurisdiction\n";
175     my %detail = (
176       'ratenum'         => $rate->ratenum,
177       'dest_regionnum'  => $regionnum,
178       'cdrtypenum'      => '',
179       'ratetimenum'     => '',
180     );
181     
182     my $dest_detail = qsearchs('rate_detail', \%detail);
183     if (!$dest_detail) {
184       $dest_detail = FS::rate_detail->new({
185           %detail,
186           'min_included'    => 0,
187           'min_charge'      => $charge,
188           'sec_granularity' => $granularity,
189       });
190       $error = $dest_detail->insert;
191     } else {
192       local $FS::Record::nowarn_identical = 1;
193       $dest_detail->set('min_charge' => $charge);
194       $error = $dest_detail->replace;
195     }
196     die "$here setting rate detail: $error\n" if $error;
197   }
198 } continue {
199   $row++
200 }
201