look for a voip rate in pricing add-ons too... eek. also correct rating to destinati...
[freeside.git] / FS / FS / ClientAPI / PrepaidPhone.pm
1 package FS::ClientAPI::PrepaidPhone;
2
3 use strict;
4 #use vars qw($DEBUG $me);
5 use FS::Record qw(qsearchs);
6 use FS::rate;
7 use FS::svc_phone;
8
9 #$DEBUG = 0;
10 #$me = '[FS::ClientAPI::PrepaidPhone]';
11
12 #TODO:
13 # - shared-secret auth? (set a conf value)
14
15 =item call_time HASHREF
16
17 HASHREF contains the following parameters:
18
19 =over 4
20
21 =item src
22
23 Source number (with countrycode)
24
25 =item dst
26
27 Destination number (with countrycode)
28
29 =back
30
31 Always returns a hashref.  If there is an error, the hashref contains a single
32 "error" key with the error message as a value.  Otherwise, returns a hashref
33 with the following keys:
34
35 =over 4
36
37 =item custnum
38
39 Empty if no customer is found associated with the number, customer number
40 otherwise.
41
42 =item seconds
43
44 Number of seconds remaining for a call to destination number
45
46 =back
47
48 =cut
49
50 sub call_time {
51   my $packet = shift;
52
53   my $src = $packet->{'src'};
54   my $dst = $packet->{'dst'};
55
56   my $chargeto;
57   my $rateby;
58   #my $conf = new FS::Conf;
59   #if ( #XXX toll-free?  collect?
60   #  $phonenum = $dst;
61   #} else { #use the src to find the customer
62     $chargeto = $src;
63     $rateby = $dst;
64   #}
65
66   my( $countrycode, $phonenum );
67   if ( $chargeto #an interesting regex to parse out 1&2 digit countrycodes
68          =~ /^(2[078]|3[0-469]|4[013-9]|5[1-8]|6[0-6]|7|8[1-469]|9[0-58])(\d*)$/
69        || $chargeto =~ /^(\d{3})(\d*)$/
70      )
71   {
72     $countrycode = $1;
73     $phonenum = $2;
74   } else { 
75     return { 'error' => "unparsable billing number: $chargeto" };
76   }
77
78
79   my $svc_phone = qsearchs('svc_phone', { 'countrycode' => $countrycode,
80                                           'phonenum'    => $phonenum,
81                                         }
82                           );
83
84   unless ( $svc_phone ) {
85     return { 'error' => "can't find customer for +$countrycode $phonenum" };
86 #    return { 'custnum' => '',
87 #             'seconds' => 0,
88 #             #'balance' => 0,
89 #           };
90   };
91
92   my $cust_pkg = $svc_phone->cust_svc->cust_pkg;
93   my $cust_main = $cust_pkg->cust_main;
94
95   my $part_pkg = $cust_pkg->part_pkg;
96   my @part_pkg = ( $part_pkg, map $_->dst_pkg, $part_pkg->bill_part_pkg_link );
97   #XXX uuh, behavior indeterminate if you have more than one voip_cdr+prefix
98   #add-on, i guess.
99   @part_pkg =
100     grep { $_->plan eq 'voip_cdr' && $_->option('rating_method') eq 'prefix' }
101          @part_pkg;
102
103   my %return = (
104     'custnum' => $cust_pkg->custnum,
105     #'balance' => $cust_pkg->cust_main->balance,
106   );
107
108   return \%return unless @part_pkg;
109
110   my $rate = qsearchs('rate', { 'ratenum'=>$part_pkg[0]->option('ratenum') } );
111
112   #rate the call and arrive at a max # of seconds for the customer's balance
113
114   my( $rate_countrycode, $rate_phonenum );
115   if ( $rateby #this is an interesting regex to parse out 1&2 digit countrycodes
116          =~ /^(2[078]|3[0-469]|4[013-9]|5[1-8]|6[0-6]|7|8[1-469]|9[0-58])(\d*)$/
117        || $rateby =~ /^(\d{3})(\d*)$/
118      )
119   {
120     $rate_countrycode = $1;
121     $rate_phonenum = $2;
122   } else { 
123     return { 'error' => "unparsable rating number: $rateby" };
124   }
125
126   my $rate_detail = $rate->dest_detail({ 'countrycode' => $rate_countrycode,
127                                          'phonenum'    => $rate_phonenum,
128                                        });
129   unless ( $rate_detail ) {
130     return { 'error'=>"can't find rate for +$rate_countrycode $rate_phonenum"};
131   }
132
133   unless ( $rate_detail->min_charge > 0 ) {
134     #XXX no charge??  return lots of seconds, a default, 0 or what?
135     #return { 'error' => '0 rate for +$rate_countrycode $rate_phonenum; prepaid service not available" };
136     $return{'seconds'} = 1800; #half hour?!
137     return \%return;
138   }
139
140   #XXX granularity?  included minutes?  another day...
141   $return{'seconds'} = int(60 * $cust_main->balance / $rate_detail->min_charge);
142
143   return \%return;
144  
145 }
146
147 =item call_time_nanpa 
148
149 Like I<call_time>, except countrycode 1 is not required, and all other
150 countrycodes must be prefixed with 011.
151
152 =cut
153
154 # - everything is assumed to be countrycode 1 unless it starts with 011(ccode)
155 sub call_time_nanpa {
156   my $packet = shift;
157
158   foreach (qw( src dst )) {
159     if ( $packet->{$_} =~ /^011(\d+)/ ) {
160       $packet->{$_} = $1;
161     } elsif ( $packet->{$_} !~ /^1/ ) {
162       $packet->{$_} = '1'.$packet->{$_};
163     }
164   }
165
166   call_time($packet);
167
168 }
169
170 =item phonenum_balance HASHREF
171
172 HASHREF contains the following parameters:
173
174 =over 4
175
176 =item countrycode
177
178 Optional countrycode.  Defaults to 1.
179
180 =item phonenum
181
182 Phone number.
183
184 =back
185
186 Always returns a hashref.  If there is an error, the hashref contains a single
187 "error" key with the error message as a value.  Otherwise, returns a hashref
188 with the following keys:
189
190 =over 4
191
192 =item custnum
193
194 Empty if no customer is found associated with the number, customer number
195 otherwise.
196
197 =item balance
198
199 Customer balance.
200
201 =back
202
203 =cut
204
205 sub phonenum_balance {
206   my $packet = shift;
207
208   my $svc_phone = qsearchs('svc_phone', {
209     'countrycode' => ( $packet->{'countrycode'} || 1 ),
210     'phonenum'    => $packet->{'phonenum'},
211   });
212
213   unless ( $svc_phone ) {
214     return { 'custnum' => '',
215              'balance' => 0,
216            };
217   };
218
219   my $cust_pkg = $svc_phone->cust_svc->cust_pkg;
220
221   return {
222     'custnum' => $cust_pkg->custnum,
223     'balance' => $cust_pkg->cust_main->balance,
224   };
225
226 }
227
228 1;