'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: ',
},
'type' => 'checkbox',
},
+ 'bill_only_pkg_dates' => { 'name' => 'Only bill CDRs with a date during the package billing period',
+ 'type' => 'checkbox',
+ },
+
#XXX also have option for an external db
# 'cdr_location' => { 'name' => 'CDR database location'
# 'type' => 'select',
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
use_duration
output_format usage_mandate summarize_usage usage_section
bill_every_call
+ bill_only_pkg_dates
)
],
'weight' => 42,
sub price_info {
my $self = shift;
- my $str = $self->SUPER::price_info;
+ my $str = $self->SUPER::price_info(@_);
$str .= " plus usage" if $str;
$str;
}
my $charges = 0;
$charges += $self->calc_usage(@_);
- $charges += $self->calc_recur_Common(@_);
+ $charges += ($cust_pkg->quantity || 1) * $self->calc_recur_Common(@_);
$charges;
if $self->recur_temporality eq 'preceding'
&& ( $last_bill eq '' || $last_bill == 0 );
- my $spool_cdr = $cust_pkg->cust_main->spool_cdr;
-
-
my $charges = 0;
# 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);
+ 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')
) {
my $svc_phone = $cust_svc->svc_x;
- foreach my $cdr ( $svc_phone->get_cdrs(
+ my %options = (
'inbound' => 1,
'default_prefix' => $self->option('default_prefix'),
'status' => '', # unprocessed only
'for_update' => 1,
- )
- ) {
+ );
+ if ( $self->option('bill_only_pkg_dates') ) {
+ $options{'begin'} = $last_bill;
+ $options{'end'} = $$sdate;
+ }
+
+ my $cdr_search = $svc_phone->psearch_cdrs(%options);
+ $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;
}
my @call_details = (
$cdr->downstream_csv( 'format' => $output_format,
'charge' => $charge,
- 'seconds' => ($use_duration
- ? $cdr->duration
- : $cdr->billsec
- ),
+ 'seconds' => $seconds,
'granularity' => $granularity,
)
);
'done',
$charge,
$cust_svc->svcnum,
- 'rated_seconds' => $use_duration ? $cdr->duration : $cdr->billsec,
+ 'rated_seconds' => $seconds,
'rated_granularity' => $granularity,
'rated_classnum' => $cdr->calltypenum,
- 'inbound' => 1,
+ 'inbound' => 1, # to update cdr_termination, not cdr
);
die $error if $error;
$formatter->append($cdr);
+ $cdr_search->adjust(1) if $cdr->freesidestatus eq '';
+
} #$cdr
} # $cust_svc
# unshift @$details, { format => 'C',
}
#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;
+ if $self->option_cacheable('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 "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 ( $opt{'skip_dcontext'} )"
- if $opt{'skip_dcontext'} =~ /\S/
- && grep { $cdr->dcontext eq $_ } split(/\s*,\s*/, $opt{'skip_dcontext'});
+ 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($opt{'skip_dstchannel_prefix'});
- return "dstchannel starts with $opt{'skip_dstchannel_prefix'}"
+ 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
'';
0;
}
-# This equates svc_phone records; perhaps svc_phone should have a field
-# to indicate it represents a line
-sub calc_units {
- my($self, $cust_pkg ) = @_;
- my $count =
- scalar(grep { $_->part_svc->svcdb eq 'svc_phone' } $cust_pkg->cust_svc);
- $count;
-}
-
1;