fix A/R report
[freeside.git] / bin / rate-intl.import
1 #!/usr/bin/perl
2
3 use strict;
4 use Text::CSV;
5 use FS::Misc::Getopt;
6 use FS::Record qw(qsearchs qsearch dbh);
7 use FS::rate;
8 use FS::rate_region;
9 use FS::rate_prefix;
10 use FS::rate_detail;
11
12 getopts('');
13
14 $FS::UID::AutoCommit = 0;
15 my $dbh = dbh;
16
17 my $file = shift or usage();
18 open my $in, '<', $file or die "$file: $!\n";
19 my $csv = Text::CSV->new({ binary => 1, auto_diag => 2 });
20 # set header row
21 $csv->column_names($csv->getline($in));
22
23 my $error;
24
25 my $granularity = 1;
26 # default is to charge per second; edit this if needed
27
28 while (my $row = $csv->getline_hr($in)) {
29   print $csv->string;
30
31   # ProfileKey is just a number
32   my $rate = qsearchs('rate', { 'ratename' => $row->{'ProfileKey'} });
33   if (!$rate) {
34     $rate = FS::rate->new({ 'ratename' => $row->{'ProfileKey'} });
35     $error = $rate->insert;
36     die $error if $error;
37   }
38
39   # DestinationId looks like "Country - City" or "Country - Mobile -
40   # Carrier" (or sometimes just "Country - Mobile").
41   my $region = qsearchs('rate_region', {
42       'regionname' => $row->{'DestinationId'}
43   });
44   if (!$region) {
45     $region = FS::rate_region->new({
46       'regionname' => $row->{'DestinationId'}
47     });
48     $error = $region->insert;
49     die $error if $error;
50   }
51
52   # Prefix strings found in there look like
53   # "e164:123-45-6nnnnnnn-"
54   # The first group of digits is the country code, any others are the
55   # prefix. Sometimes the nnnn's are NNNN's. The dashes are not guaranteed
56   # to be anywhere specific.
57   # Catchall prefixes start with "-A", which has a meaning like "match
58   # anything, but at a lower priority than a digit match".
59   # NANPA numbers use "1-", and for a catchall area code use "1-AAA-".
60   my $cc_long = $row->{CountryCodeLong};
61   $cc_long =~ /^e164:(\d+)-([\d-]*)A*-?n+-$/i;
62   my $countrycode = $1;
63   if (!$countrycode) { # totally legit reasons for this, e.g. 1-AAA-411
64     warn "can't parse number prefix:\n$cc_long\n";
65     next;
66   }
67   my $prefix = $2;
68   $prefix =~ s/-//g;
69
70   my %prefix = (
71       'regionnum'   => $region->regionnum,
72       'countrycode' => $countrycode,
73       'npa'         => $prefix,
74   );
75   my $rate_prefix = qsearchs('rate_prefix', \%prefix);
76   if (!$rate_prefix) {
77     $rate_prefix = FS::rate_prefix->new(\%prefix);
78     $error = $rate_prefix->insert;
79     die $error if $error;
80   }
81
82   # enough to identify the detail
83   my %detail = (
84     'ratenum'         => $rate->ratenum,
85     'dest_regionnum'  => $region->regionnum,
86     'cdrtypenum'      => '',
87     'ratetimenum'     => '',
88   );
89   my $dest_detail = qsearchs('rate_detail', \%detail);
90   # ProfileRate is 5 decimal places, same as rate_detail.min_charge
91   if (!$dest_detail) {
92     $dest_detail = FS::rate_detail->new({
93         %detail,
94         'min_included'    => 0,
95         'min_charge'      => $row->{ProfileRate},
96         'sec_granularity' => $granularity,
97     });
98     $error = $dest_detail->insert;
99   } else {
100     local $FS::Record::nowarn_identical = 1;
101     $dest_detail->set('min_charge' => $row->{ProfileRate});
102     $error = $dest_detail->replace;
103   }
104   die $error if $error;
105 }
106 dbh->commit;
107 print "Finished.\n";
108
109
110 sub usage {
111   die "Usage: rate-intl.import <user> <file>.csv\n\n";
112 }
113