summaryrefslogtreecommitdiff
path: root/FS
diff options
context:
space:
mode:
authorMark Wells <mark@freeside.biz>2014-10-10 16:36:07 -0700
committerMark Wells <mark@freeside.biz>2014-10-10 16:36:07 -0700
commit83e442de6a041fa3b7580d53912eeb1490ddf47c (patch)
tree2dc9a967c5e26ec27b083ce40acea6b254b7a29b /FS
parent2a26e4616da323e083c941e9a8c3d2b35377bc3f (diff)
upstream-markup call rating and global default rates, #30633
Diffstat (limited to 'FS')
-rw-r--r--FS/FS/Schema.pm11
-rw-r--r--FS/FS/cdr.pm20
-rw-r--r--FS/FS/part_pkg/agent_cdr.pm8
-rw-r--r--FS/FS/rate.pm31
-rw-r--r--FS/FS/rate_detail.pm20
5 files changed, 71 insertions, 19 deletions
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index ba39d808f..0b82f91a5 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -4808,9 +4808,10 @@ sub tables_hashref {
'rate' => {
'columns' => [
- 'ratenum', 'serial', '', '', '', '',
- 'ratename', 'varchar', '', $char_d, '', '',
- 'agentnum', 'int', 'NULL', '', '', '',
+ 'ratenum', 'serial', '', '', '', '',
+ 'ratename', 'varchar', '',$char_d, '', '',
+ 'agentnum', 'int', 'NULL', '', '', '',
+ 'default_detailnum', 'int', 'NULL', '', '', '',
],
'primary_key' => 'ratenum',
'unique' => [],
@@ -4827,7 +4828,7 @@ sub tables_hashref {
'ratedetailnum', 'serial', '', '', '', '',
'ratenum', 'int', '', '', '', '',
'orig_regionnum', 'int', 'NULL', '', '', '',
- 'dest_regionnum', 'int', '', '', '', '',
+ 'dest_regionnum', 'int', 'NULL', '', '', '',
'min_included', 'int', '', '', '', '',
'conn_charge', 'decimal', '', '10,4', '0.0000', '',
'conn_cost', 'decimal', '', '10,4', '0.0000', '',
@@ -4839,6 +4840,8 @@ sub tables_hashref {
'classnum', 'int', 'NULL', '', '', '',
'cdrtypenum', 'int', 'NULL', '', '', '',
'region_group', 'char', 'NULL', 1, '', '',
+ 'upstream_mult_charge', 'decimal', '', '10,4', '0.0000', '',
+ 'upstream_mult_cost', 'decimal', '', '10,4', '0.0000', '',
],
'primary_key' => 'ratedetailnum',
'unique' => [ [ 'ratenum', 'orig_regionnum', 'dest_regionnum' ] ],
diff --git a/FS/FS/cdr.pm b/FS/FS/cdr.pm
index 9859dfade..7a5668d52 100644
--- a/FS/FS/cdr.pm
+++ b/FS/FS/cdr.pm
@@ -799,8 +799,8 @@ sub rate_prefix {
}
+ my $regionnum = $rate_detail->dest_regionnum;
my $rate_region = $rate_detail->dest_region;
- my $regionnum = $rate_region->regionnum;
warn " found rate for regionnum $regionnum ".
"and rate detail $rate_detail\n"
if $DEBUG;
@@ -842,6 +842,11 @@ sub rate_prefix {
my $charge = 0;
my $connection_charged = 0;
+ # before doing anything else, if there's an upstream multiplier and
+ # an upstream price, add that to the charge. (usually the rate detail
+ # will then have a minute charge of zero, but not necessarily.)
+ $charge += ($self->upstream_price || 0) * $rate_detail->upstream_mult_charge;
+
my $etime;
while($seconds_left) {
my $ratetimenum = $rate_detail->ratetimenum; # may be empty
@@ -989,7 +994,7 @@ sub rate_prefix {
$price,
$opt{'svcnum'},
'rated_pretty_dst' => $pretty_dst,
- 'rated_regionname' => $rate_region->regionname,
+ 'rated_regionname' => ($rate_region ? $rate_region->regionname : ''),
'rated_seconds' => $rated_seconds, #$seconds,
'rated_granularity' => $rate_detail->sec_granularity, #$granularity
'rated_ratedetailnum' => $rate_detail->ratedetailnum,
@@ -1073,10 +1078,15 @@ sub rate_cost {
my $rate_detail =
qsearchs('rate_detail', { 'ratedetailnum' => $self->rated_ratedetailnum } );
- return $rate_detail->min_cost if $self->rated_granularity == 0;
+ my $charge = 0;
+ $charge += ($self->upstream_price || 0) * ($rate_detail->upstream_mult_cost);
- my $minutes = $self->rated_seconds / 60;
- my $charge = $rate_detail->conn_cost + $minutes * $rate_detail->min_cost;
+ if ( $self->rated_granularity == 0 ) {
+ $charge += $rate_detail->min_cost;
+ } else {
+ my $minutes = $self->rated_seconds / 60;
+ $charge += $rate_detail->conn_cost + $minutes * $rate_detail->min_cost;
+ }
sprintf('%.2f', $charge + .00001 );
diff --git a/FS/FS/part_pkg/agent_cdr.pm b/FS/FS/part_pkg/agent_cdr.pm
index 55792f2d2..a638b5b5a 100644
--- a/FS/FS/part_pkg/agent_cdr.pm
+++ b/FS/FS/part_pkg/agent_cdr.pm
@@ -23,7 +23,7 @@ tie my %temporalities, 'Tie::IxHash',
%info = (
'name' => 'Wholesale CDR cost billing, for master customers of an agent.',
- 'shortname' => 'Whilesale CDR cost billing for agent.',
+ 'shortname' => 'Wholesale CDR cost billing for agent',
'inherit_fields' => [ 'prorate_Mixin', 'global_Mixin' ],
'fields' => { #false laziness w/cdr_termination
@@ -177,7 +177,11 @@ sub calc_recur {
my $classnum = ''; #usage class?
#option to turn off? or just use squelch_cdr for the customer probably
- push @$details, [ 'C', $call_details, $cost, $classnum ];
+ # XXX use detail_format for this at some point
+ push @$details, { 'format' => 'C',
+ 'detail' => $call_details,
+ 'amount' => $cost,
+ 'classnum' => $classnum };
#eofalse laziness w/cdr_termination
diff --git a/FS/FS/rate.pm b/FS/FS/rate.pm
index aef9d8bec..9a5b90546 100644
--- a/FS/FS/rate.pm
+++ b/FS/FS/rate.pm
@@ -46,6 +46,16 @@ Rate name
Optional agent (see L<FS::agent>) for agent-virtualized rates.
+=item default_detailnum
+
+Optional rate detail to apply when a call doesn't match any region in the
+rate plan. If this is not set, the call will either be left unrated (though
+it may still be processed under a different pricing addon package), or be
+marked as 'skipped', or throw a fatal error, depending on the setting of
+the 'ignore_unrateable' package option.
+
+=item
+
=back
=head1 METHODS
@@ -268,6 +278,7 @@ sub check {
$self->ut_numbern('ratenum')
|| $self->ut_text('ratename')
#|| $self->ut_foreign_keyn('agentnum', 'agent', 'agentnum')
+ || $self->ut_numbern('default_detailnum')
;
return $error if $error;
@@ -277,8 +288,8 @@ sub check {
=item dest_detail REGIONNUM | RATE_REGION_OBJECTD | HASHREF
Returns the rate detail (see L<FS::rate_detail>) for this rate to the
-specificed destination, or the empty string if no rate can be found for
-the given destination.
+specificed destination. If no rate can be found, returns the default
+rate if there is one, and an empty string otherwise.
Destination can be specified as an FS::rate_detail object or regionnum
(see L<FS::rate_detail>), or as a hashref containing the following keys:
@@ -379,8 +390,8 @@ sub dest_detail {
foreach (@details) {
return $_ if $_->ratetimenum eq '';
}
- # found nothing
- return;
+ # if still nothing, return the global default rate for this plan
+ return $self->default_detail;
}
=item rate_detail
@@ -389,6 +400,18 @@ Returns all region-specific details (see L<FS::rate_detail>) for this rate.
=back
+=item default_detail
+
+Returns the default rate detail, if there is one.
+
+=cut
+
+sub default_detail {
+ my $self = shift;
+ $self->default_detailnum ?
+ FS::rate_detail->by_key($self->default_detailnum) : ''
+}
+
=head1 SUBROUTINES
=over 4
diff --git a/FS/FS/rate_detail.pm b/FS/FS/rate_detail.pm
index d81d9dbda..d50c89f80 100644
--- a/FS/FS/rate_detail.pm
+++ b/FS/FS/rate_detail.pm
@@ -60,6 +60,13 @@ inherits from FS::Record. The following fields are currently supported:
=item region_group - Group in region group for rate plan
+=item upstream_mult_charge - the multiplier to apply to the upstream price.
+Defaults to zero, and should stay zero unless this rate is intended to include
+a markup on pre-rated CDRs.
+
+=item upstream_mult_cost - the multiplier to apply to the upstream price to
+calculate the wholesale cost.
+
=back
=head1 METHODS
@@ -124,7 +131,7 @@ sub check {
$self->ut_numbern('ratedetailnum')
|| $self->ut_foreign_key('ratenum', 'rate', 'ratenum')
|| $self->ut_foreign_keyn('orig_regionnum', 'rate_region', 'regionnum' )
- || $self->ut_foreign_key('dest_regionnum', 'rate_region', 'regionnum' )
+ || $self->ut_foreign_keyn('dest_regionnum', 'rate_region', 'regionnum' )
|| $self->ut_number('min_included')
#|| $self->ut_money('min_charge')
@@ -138,6 +145,9 @@ sub check {
|| $self->ut_foreign_keyn('classnum', 'usage_class', 'classnum' )
|| $self->ut_enum('region_group', [ '', 'Y' ])
+
+ || $self->ut_floatn('upstream_mult_charge')
+ || $self->ut_floatn('upstream_mult_cost')
;
return $error if $error;
@@ -182,10 +192,11 @@ with this call plan rate.
sub dest_regionname {
my $self = shift;
- $self->dest_region->regionname;
+ my $dest_region = $self->dest_region;
+ $dest_region ? $dest_region->regionname : 'Global default';
}
-=item dest_regionname
+=item dest_prefixes_short
Returns a short list of the prefixes for the destination region
(see L<FS::rate_region>) associated with this call plan rate.
@@ -194,7 +205,8 @@ Returns a short list of the prefixes for the destination region
sub dest_prefixes_short {
my $self = shift;
- $self->dest_region->prefixes_short;
+ my $dest_region = $self->dest_region;
+ $dest_region ? $dest_region->prefixes_short : '';
}
=item rate_time