X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fpart_pkg%2Fvoip_inbound.pm;h=81f276500b9b2acdc64dab8fba7d82814ccf37e0;hb=d22baa4e71bfa9e153c1fe1152ff4c748f1d935c;hp=a16ef1fc46536a6b513e130fbe23c5a35c42bc58;hpb=4a0ec17006cfc39c3b8272f048d7cef3533e39c0;p=freeside.git diff --git a/FS/FS/part_pkg/voip_inbound.pm b/FS/FS/part_pkg/voip_inbound.pm index a16ef1fc4..81f276500 100644 --- a/FS/FS/part_pkg/voip_inbound.pm +++ b/FS/FS/part_pkg/voip_inbound.pm @@ -10,6 +10,7 @@ use FS::Conf; use FS::Record qw(qsearchs qsearch); use FS::cdr; use FS::rate_detail; +use FS::detail_format; $DEBUG = 0; @@ -59,15 +60,21 @@ tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities(); 'type' => 'checkbox', }, - 'use_carrierid' => { 'name' => 'Only charge for CDRs where the Carrier ID is set to: ', + 'use_carrierid' => { 'name' => 'Only charge for CDRs where the Carrier ID is set to any of these (comma-separated) values: ', }, - 'use_cdrtypenum' => { 'name' => 'Only charge for CDRs where the CDR Type is set to: ', + 'use_cdrtypenum' => { 'name' => 'Only charge for CDRs where the CDR Type is set to this cdrtypenum: ', }, - 'ignore_cdrtypenum' => { 'name' => 'Do not charge for CDRs where the CDR Type is set to: ', + 'ignore_cdrtypenum' => { 'name' => 'Do not charge for CDRs where the CDR Type is set to this cdrtypenum: ', }, + 'use_calltypenum' => { 'name' => 'Only charge for CDRs where the CDR Call Type is set to this cdrtypenum: ', + }, + + 'ignore_calltypenum' => { 'name' => 'Do not charge for CDRs where the CDR Call Type is set to this cdrtypenum: ', + }, + 'ignore_disposition' => { 'name' => 'Do not charge for CDRs where the Disposition is set to any of these (comma-separated) values: ', }, @@ -146,6 +153,7 @@ tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities(); use_amaflags use_carrierid use_cdrtypenum ignore_cdrtypenum + use_calltypenum ignore_calltypenum ignore_disposition disposition_in skip_dcontext skip_dstchannel_prefix skip_dst_length_less skip_lastapp @@ -159,7 +167,7 @@ tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities(); sub price_info { my $self = shift; - my $str = $self->SUPER::price_info; + my $str = $self->SUPER::price_info(@_); $str .= " plus usage" if $str; $str; } @@ -171,7 +179,7 @@ sub calc_recur { my $charges = 0; $charges += $self->calc_usage(@_); - $charges += $self->calc_recur_Common(@_); + $charges += ($cust_pkg->quantity || 1) * $self->calc_recur_Common(@_); $charges; @@ -206,8 +214,17 @@ sub calc_usage { # my $downstream_cdr = ''; my $included_min = $self->option('min_included', 1) || 0; + $included_min *= ($cust_pkg->quantity || 1); my $use_duration = $self->option('use_duration'); my $output_format = $self->option('output_format', 1) || 'default'; + + my $formatter = + FS::detail_format->new($output_format, + buffer => $details, + inbound => 1, + locale => $cust_pkg->cust_main->locale + ); + my $granularity = length($self->option('sec_granularity')) ? $self->option('sec_granularity') : 60; @@ -222,19 +239,22 @@ sub calc_usage { ) { my $svc_phone = $cust_svc->svc_x; - foreach my $cdr ( $svc_phone->get_cdrs( + my $cdr_search = $svc_phone->psearch_cdrs( 'inbound' => 1, 'default_prefix' => $self->option('default_prefix'), 'status' => '', # unprocessed only 'for_update' => 1, - ) - ) { + ); + $cdr_search->limit(1000); + $cdr_search->increment(0); + while ( my $cdr = $cdr_search->fetch ) { my $reason = $self->check_chargable( $cdr, 'option_cache' => \%opt_cache, ); if ( $reason ) { warn "not charging for CDR ($reason)\n" if $DEBUG; + $cdr_search->adjust(1); next; } @@ -279,97 +299,100 @@ sub calc_usage { 'granularity' => $granularity, ) ); - push @$details, - { format => 'C', - detail => $call_details[0], - amount => $charge, - classnum => $cdr->calltypenum, #classnum - #phonenum => $self->phonenum, - accountcode => $cdr->accountcode, - startdate => $cdr->startdate, - duration => $seconds, - # regionname?? => '', #regionname, not set for inbound calls - }; - } - - my $error = $cdr->set_status_and_rated_price( 'done', - $charge, - $cust_svc->svcnum, - 'inbound' => 1 ); - die $error if $error; +# push @$details, +# { format => 'C', +# detail => $call_details[0], +# amount => $charge, +# classnum => $cdr->calltypenum, #classnum +# #phonenum => $self->phonenum, +# accountcode => $cdr->accountcode, +# startdate => $cdr->startdate, +# duration => $seconds, +# # regionname?? => '', #regionname, not set for inbound calls +# }; + } + + # eventually use FS::cdr::rate for this + my $error = $cdr->set_status_and_rated_price( + 'done', + $charge, + $cust_svc->svcnum, + 'rated_seconds' => $use_duration ? $cdr->duration : $cdr->billsec, + 'rated_granularity' => $granularity, + 'rated_classnum' => $cdr->calltypenum, + 'inbound' => 1, + ); + die $error if $error; + $formatter->append($cdr); + + $cdr_search->adjust(1) if $cdr->freesidestatus eq ''; } #$cdr } # $cust_svc - unshift @$details, { format => 'C', - detail => FS::cdr::invoice_header($output_format), - } - if @$details; +# unshift @$details, { format => 'C', +# detail => FS::cdr::invoice_header($output_format), +# } +# if @$details; + + $formatter->finish; + unshift @$details, $formatter->header if @$details; $charges; } #returns a reason why not to rate this CDR, or false if the CDR is chargeable +# lots of false laziness w/voip_cdr... sub check_chargable { my( $self, $cdr, %flags ) = @_; - #should have some better way of checking these options from a hash - #or something - - my @opt = qw( - use_amaflags - use_carrierid - use_cdrtypenum - ignore_cdrtypenum - disposition_in - ignore_disposition - skip_dcontext - skip_dstchannel_prefix - skip_dst_length_less - skip_lastapp - ); - foreach my $opt (grep !exists($flags{option_cache}->{$_}), @opt ) { - $flags{option_cache}->{$opt} = $self->option($opt, 1); - } - my %opt = %{ $flags{option_cache} }; - return 'amaflags != 2' - if $opt{'use_amaflags'} && $cdr->amaflags != 2; - - return "disposition NOT IN ( $opt{'disposition_in'} )" - if $opt{'disposition_in'} =~ /\S/ - && !grep { $cdr->disposition eq $_ } split(/\s*,\s*/, $opt{'disposition_in'}); - - return "disposition IN ( $opt{'ignore_disposition'} )" - if $opt{'ignore_disposition'} =~ /\S/ - && grep { $cdr->disposition eq $_ } split(/\s*,\s*/, $opt{'ignore_disposition'}); - - return "carrierid != $opt{'use_carrierid'}" - if length($opt{'use_carrierid'}) - && $cdr->carrierid ne $opt{'use_carrierid'}; #ne otherwise 0 matches '' - - return "cdrtypenum != $opt{'use_cdrtypenum'}" - if length($opt{'use_cdrtypenum'}) - && $cdr->cdrtypenum ne $opt{'use_cdrtypenum'}; #ne otherwise 0 matches '' - - return "cdrtypenum == $opt{'ignore_cdrtypenum'}" - if length($opt{'ignore_cdrtypenum'}) - && $cdr->cdrtypenum eq $opt{'ignore_cdrtypenum'}; #eq otherwise 0 matches '' - - return "dcontext IN ( $opt{'skip_dcontext'} )" - if $opt{'skip_dcontext'} =~ /\S/ - && grep { $cdr->dcontext eq $_ } split(/\s*,\s*/, $opt{'skip_dcontext'}); - - my $len_prefix = length($opt{'skip_dstchannel_prefix'}); - return "dstchannel starts with $opt{'skip_dstchannel_prefix'}" + if $self->option_cacheable('use_amaflags') && $cdr->amaflags != 2; + + return "disposition NOT IN ( ". $self->option_cacheable('disposition_in')." )" + if $self->option_cacheable('disposition_in') =~ /\S/ + && !grep { $cdr->disposition eq $_ } split(/\s*,\s*/, $self->option_cacheable('disposition_in')); + + return "disposition IN ( ". $self->option_cacheable('ignore_disposition')." )" + if $self->option_cacheable('ignore_disposition') =~ /\S/ + && grep { $cdr->disposition eq $_ } split(/\s*,\s*/, $self->option_cacheable('ignore_disposition')); + + return "carrierid NOT IN ( ". $self->option_cacheable('use_carrierid'). " )" + if $self->option_cacheable('use_carrierid') =~ /\S/ + && !grep { $cdr->carrierid eq $_ } split(/\s*,\s*/, $self->option_cacheable('use_carrierid')); #eq otherwise 0 matches '' + + # unlike everything else, use_cdrtypenum is applied in FS::svc_x::get_cdrs. + return "cdrtypenum != ". $self->option_cacheable('use_cdrtypenum') + if length($self->option_cacheable('use_cdrtypenum')) + && $cdr->cdrtypenum ne $self->option_cacheable('use_cdrtypenum'); #ne otherwise 0 matches '' + + return "cdrtypenum == ". $self->option_cacheable('ignore_cdrtypenum') + if length($self->option_cacheable('ignore_cdrtypenum')) + && $cdr->cdrtypenum eq $self->option_cacheable('ignore_cdrtypenum'); #eq otherwise 0 matches '' + + # unlike everything else, use_calltypenum is applied in FS::svc_x::get_cdrs. + return "calltypenum != ". $self->option_cacheable('use_calltypenum') + if length($self->option_cacheable('use_calltypenum')) + && $cdr->calltypenum ne $self->option_cacheable('use_calltypenum'); #ne otherwise 0 matches '' + + return "calltypenum == ". $self->option_cacheable('ignore_calltypenum') + if length($self->option_cacheable('ignore_calltypenum')) + && $cdr->calltypenum eq $self->option_cacheable('ignore_calltypenum'); #eq otherwise 0 matches '' + + return "dcontext IN ( ". $self->option_cacheable('skip_dcontext'). " )" + if $self->option_cacheable('skip_dcontext') =~ /\S/ + && grep { $cdr->dcontext eq $_ } split(/\s*,\s*/, $self->option_cacheable('skip_dcontext')); + + my $len_prefix = length($self->option_cacheable('skip_dstchannel_prefix')); + return "dstchannel starts with ". $self->option_cacheable('skip_dstchannel_prefix') if $len_prefix - && substr($cdr->dstchannel,0,$len_prefix) eq $opt{'skip_dstchannel_prefix'}; + && substr($cdr->dstchannel,0,$len_prefix) eq $self->option_cacheable('skip_dstchannel_prefix'); - my $dst_length = $opt{'skip_dst_length_less'}; + my $dst_length = $self->option_cacheable('skip_dst_length_less'); return "destination less than $dst_length digits" if $dst_length && length($cdr->dst) < $dst_length; - return "lastapp is $opt{'skip_lastapp'}" - if length($opt{'skip_lastapp'}) && $cdr->lastapp eq $opt{'skip_lastapp'}; + return "lastapp is ". $self->option_cacheable('skip_lastapp') + if length($self->option_cacheable('skip_lastapp')) && $cdr->lastapp eq $self->option_cacheable('skip_lastapp'); #all right then, rate it ''; @@ -381,6 +404,7 @@ sub is_free { # This equates svc_phone records; perhaps svc_phone should have a field # to indicate it represents a line +# #XXX no count_available_phones? sub calc_units { my($self, $cust_pkg ) = @_; my $count =