package FS::ClientAPI::PrepaidPhone;
use strict;
-#use vars qw($DEBUG $me);
+use vars qw($DEBUG $me);
use FS::Record qw(qsearchs);
+use FS::Conf;
use FS::rate;
use FS::svc_phone;
-#$DEBUG = 0;
-#$me = '[FS::ClientAPI::PrepaidPhone]';
+$DEBUG = 0;
+$me = '[FS::ClientAPI::PrepaidPhone]';
#TODO:
# - shared-secret auth? (set a conf value)
my $src = $packet->{'src'};
my $dst = $packet->{'dst'};
- my $number;
+ my $chargeto;
+ my $rateby;
#my $conf = new FS::Conf;
#if ( #XXX toll-free? collect?
# $phonenum = $dst;
#} else { #use the src to find the customer
- $number = $src;
+ $chargeto = $src;
+ $rateby = $dst;
#}
my( $countrycode, $phonenum );
- if ( $number #this is an interesting regex to parse out 1&2 digit countrycodes
+ if ( $chargeto #an interesting regex to parse out 1&2 digit countrycodes
=~ /^(2[078]|3[0-469]|4[013-9]|5[1-8]|6[0-6]|7|8[1-469]|9[0-58])(\d*)$/
- || $number =~ /^(\d{3})(\d*)$/
+ || $chargeto =~ /^(\d{3})(\d*)$/
)
{
$countrycode = $1;
$phonenum = $2;
} else {
- return { 'error' => "unparsable number: $number" };
+ return { 'error' => "unparsable billing number: $chargeto" };
}
+
my $svc_phone = qsearchs('svc_phone', { 'countrycode' => $countrycode,
'phonenum' => $phonenum,
}
};
my $cust_pkg = $svc_phone->cust_svc->cust_pkg;
- my $part_pkg = $cust_pkg->part_pkg;
my $cust_main = $cust_pkg->cust_main;
+ my $part_pkg = $cust_pkg->part_pkg;
+ my @part_pkg = ( $part_pkg, map $_->dst_pkg, $part_pkg->bill_part_pkg_link );
+ #XXX uuh, behavior indeterminate if you have more than one voip_cdr+prefix
+ #add-on, i guess.
+ warn "$me ". scalar(@part_pkg). ': '.
+ join('/', map { $_->plan. $_->option('rating_method') } @part_pkg )
+ if $DEBUG;
+ @part_pkg =
+ grep { $_->plan eq 'voip_cdr' && $_->option('rating_method') eq 'prefix' }
+ @part_pkg;
+
my %return = (
'custnum' => $cust_pkg->custnum,
#'balance' => $cust_pkg->cust_main->balance,
);
- return \%return unless $part_pkg->plan eq 'voip_cdr'
- && $part_pkg->option('rating_method') eq 'prefix';
+ warn "$me: ". scalar(@part_pkg). ': '.
+ join('/', map { $_->plan. $_->option('rating_method') } @part_pkg )
+ if $DEBUG;
+ return \%return unless @part_pkg;
+
+ warn "$me searching for rate ". $part_pkg[0]->option('ratenum')
+ if $DEBUG;
+
+ my $rate = qsearchs('rate', { 'ratenum'=>$part_pkg[0]->option('ratenum') } );
+
+ unless ( $rate ) {
+ my $error = 'ratenum '. $part_pkg[0]->option('ratenum'). ' not found';
+ warn "$me $error"
+ if $DEBUG;
+ return { 'error'=>$error };
+ }
- my $rate = qsearchs('rate', { 'ratenum' => $part_pkg->option('ratenum') } );
+ warn "$me found rate ". $rate->ratenum
+ if $DEBUG;
#rate the call and arrive at a max # of seconds for the customer's balance
- my $rate_detail = $rate->dest_detail({ 'countrycode' => $countrycode,
- 'phonenum' => $phonenum,
+
+ my( $rate_countrycode, $rate_phonenum );
+ if ( $rateby #this is an interesting regex to parse out 1&2 digit countrycodes
+ =~ /^(2[078]|3[0-469]|4[013-9]|5[1-8]|6[0-6]|7|8[1-469]|9[0-58])(\d*)$/
+ || $rateby =~ /^(\d{3})(\d*)$/
+ )
+ {
+ $rate_countrycode = $1;
+ $rate_phonenum = $2;
+ } else {
+ return { 'error' => "unparsable rating number: $rateby" };
+ }
+
+ my $rate_detail = $rate->dest_detail({ 'countrycode' => $rate_countrycode,
+ 'phonenum' => $rate_phonenum,
});
+ unless ( $rate_detail ) {
+ return { 'error'=>"can't find rate for +$rate_countrycode $rate_phonenum"};
+ }
+
+ unless ( $rate_detail->min_charge > 0 ) {
+ #XXX no charge?? return lots of seconds, a default, 0 or what?
+ #return { 'error' => '0 rate for +$rate_countrycode $rate_phonenum; prepaid service not available" };
+ #customer wants no default for now# $return{'seconds'} = 1800; #half hour?!
+ return \%return;
+ }
+
+ my $balance = FS::ClientAPI::PrepaidPhone->prepaid_phone_balance( $cust_pkg );
#XXX granularity? included minutes? another day...
+ if ( $balance >= 0 ) {
+ return { 'error'=>'No balance' };
+ } else {
+ $return{'seconds'} = int(60 * abs($balance) / $rate_detail->min_charge);
+ }
- $return{'seconds'} = int(60 * $cust_main->balance / $rate_detail->min_charge);
+ warn "$me returning seconds: ". $return{'seconds'};
return \%return;
sub phonenum_balance {
my $packet = shift;
+ warn "$me phonenum_balance called with countrycode ".$packet->{'countrycode'}.
+ " and phonenum ". $packet->{'phonenum'}. "\n"
+ if $DEBUG;
+
my $svc_phone = qsearchs('svc_phone', {
'countrycode' => ( $packet->{'countrycode'} || 1 ),
'phonenum' => $packet->{'phonenum'},
});
unless ( $svc_phone ) {
+ warn "$me no phone number found\n" if $DEBUG;
return { 'custnum' => '',
'balance' => 0,
};
my $cust_pkg = $svc_phone->cust_svc->cust_pkg;
+ my $balance = FS::ClientAPI::PrepaidPhone->prepaid_phone_balance( $cust_pkg );
+
+ warn "$me returning $balance balance for pkgnum ". $cust_pkg->pkgnum.
+ ", custnum ". $cust_pkg->custnum
+ if $DEBUG;
+
return {
'custnum' => $cust_pkg->custnum,
- 'balance' => $cust_pkg->cust_main->balance,
+ 'balance' => $balance,
};
}
+sub prepaid_phone_balance {
+ my $class = shift; # i guess
+ my ($cust_pkg) = @_;
+
+ my $conf = new FS::Conf;
+
+ my $pkg_balances = $conf->config_bool('pkg-balances');
+
+ my $balance = $pkg_balances ? $cust_pkg->balance
+ : $cust_pkg->cust_main->balance;
+
+ if ( $conf->config_bool('cdr-prerate') ) {
+ my @cust_pkg = $pkg_balances ? ( $cust_pkg )
+ : ( $cust_pkg->cust_main->ncancelled_pkgs );
+ foreach my $cust_pkg ( @cust_pkg ) {
+
+ #we only support prerated CDRs with "VOIP/telco CDR rating (standard)"
+ # and "Phone numbers (svc_phone.phonenum)" CDR service matching for now
+ my $part_pkg = $cust_pkg->part_pkg;
+ next unless $part_pkg->plan eq 'voip_cdr'
+ && ($part_pkg->option('cdr_svc_method') || 'svc_phone.phonenum')
+ eq 'svc_phone.phonenum'
+ && ! $part_pkg->option('bill_inactive_svcs');
+ #XXX skip when there's included minutes
+
+ #select prerated cdrs & subtract them from balance
+
+ # false laziness w/ part_pkg/voip_cdr.pm sorta
+
+ my %options = (
+ 'disable_src' => $part_pkg->option('disable_src'),
+ 'default_prefix' => $part_pkg->option('default_prefix'),
+ 'cdrtypenum' => $part_pkg->option('use_cdrtypenum'),
+ 'calltypenum' => $part_pkg->option('use_calltypenum'),
+ 'status' => 'rated',
+ 'by_svcnum' => 1,
+ ); # $last_bill, $$sdate )
+
+ my @cust_svc = grep { $_->part_svc->svcdb eq 'svc_phone' }
+ $cust_pkg->cust_svc;
+ foreach my $cust_svc ( @cust_svc ) {
+
+ my $svc_x = $cust_svc->svc_x;
+ my $sum_cdr = $svc_x->sum_cdrs(%options);
+ $balance += $sum_cdr->rated_price;
+
+ }
+
+ }
+ }
+
+ $balance;
+
+}
+
1;