diff options
Diffstat (limited to 'FS')
-rw-r--r-- | FS/FS/Report/Table.pm | 42 | ||||
-rw-r--r-- | FS/FS/Schema.pm | 4 | ||||
-rw-r--r-- | FS/FS/cdr.pm | 20 | ||||
-rw-r--r-- | FS/FS/cust_bill_pkg_detail.pm | 37 | ||||
-rw-r--r-- | FS/FS/detail_format.pm | 2 | ||||
-rw-r--r-- | FS/FS/detail_format/sum_count.pm | 4 | ||||
-rw-r--r-- | FS/FS/detail_format/sum_duration.pm | 4 | ||||
-rw-r--r-- | FS/FS/detail_format/sum_duration_prefix.pm | 4 |
8 files changed, 106 insertions, 11 deletions
diff --git a/FS/FS/Report/Table.pm b/FS/FS/Report/Table.pm index eeb99bac5..5fb56404d 100644 --- a/FS/FS/Report/Table.pm +++ b/FS/FS/Report/Table.pm @@ -599,6 +599,10 @@ sub _cust_bill_pkg_recurring { $self->in_time_period_and_agent($speriod, $eperiod, $agentnum, $_date); } + if ( $opt{'custnum'} =~ /^(\d+)$/ ) { + push @where, "(cust_main.custnum = $1)"; + } + return " FROM $cust_bill_pkg $cust_bill_pkg_join @@ -606,6 +610,16 @@ sub _cust_bill_pkg_recurring { } +=item cust_bill_pkg_recur: the total recur charges + +Most arguments as for C<cust_bill_pkg>, plus: + +'custnum': limit to this customer + +'cost': if true, return total recur costs instead + +=cut + sub cust_bill_pkg_recur { my $self = shift; my ($speriod, $eperiod, $agentnum, %opt) = @_; @@ -632,9 +646,11 @@ sub cust_bill_pkg_recur { ($cust_bill_pkg.edate - $cust_bill_pkg.sdate)"; } - my $total_sql = - "SELECT COALESCE(SUM(($cust_bill_pkg.recur - $item_usage) $recur_fraction),0)" . - $self->_cust_bill_pkg_recurring(@_); + my $total_sql = $opt{'cost'} + ? "SELECT SUM(part_pkg.recur_cost)" + : "SELECT COALESCE(SUM(($cust_bill_pkg.recur - $item_usage) $recur_fraction),0)"; + + $total_sql .= $self->_cust_bill_pkg_recurring(@_); $self->scalar_sql($total_sql); } @@ -650,10 +666,14 @@ sub cust_bill_pkg_count_pkgnum { =item cust_bill_pkg_detail: the total usage charges in detail lines. -Arguments as for C<cust_bill_pkg>, plus: +Most arguments as for C<cust_bill_pkg>, plus: 'usageclass': limit to this usage class number. +'custnum': limit to this customer + +'cost': if true, return total usage costs instead + =cut sub cust_bill_pkg_detail { @@ -686,7 +706,16 @@ sub cust_bill_pkg_detail { ); } + if ( $opt{'custnum'} =~ /^(\d+)$/ ) { + push @where, "(cust_main.custnum = $1)"; + } + my $total_sql = " SELECT SUM(cust_bill_pkg_detail.amount) "; + my $extra_join = ''; + if ($opt{'cost'}) { + $extra_join = " JOIN cdr USING ( detailnum ) "; + $total_sql = " SELECT SUM(cdr.rated_cost) "; + } $total_sql .= " FROM cust_bill_pkg_detail @@ -696,8 +725,9 @@ sub cust_bill_pkg_detail { LEFT JOIN cust_pkg ON cust_bill_pkg.pkgnum = cust_pkg.pkgnum LEFT JOIN part_pkg USING ( pkgpart ) LEFT JOIN part_pkg AS override ON pkgpart_override = override.pkgpart - LEFT JOIN part_fee USING ( feepart ) - WHERE ".join( ' AND ', grep $_, @where ); + LEFT JOIN part_fee USING ( feepart ) + ".$extra_join. + " WHERE ".join( ' AND ', grep $_, @where ); $self->scalar_sql($total_sql); diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index c855b1fba..a71b90249 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -3819,6 +3819,7 @@ sub tables_hashref { 'rated_ratedetailnum', 'int', 'NULL', '', '', '', 'rated_classnum', 'int', 'NULL', '', '', '', 'rated_ratename', 'varchar', 'NULL', $char_d, '', '', + 'rated_cost', 'decimal', 'NULL', '10,4', '', '', 'carrierid', 'bigint', 'NULL', '', '', '', @@ -3843,6 +3844,9 @@ sub tables_hashref { #new 'cdrbatchnum', 'int', 'NULL', '', '', '', + # FK to cust_bill_pkg_detail; having a value here absolutely means + # that the CDR appears on an invoice + 'detailnum', 'bigint', 'NULL', '', '', '', ], 'primary_key' => 'acctid', 'unique' => [], diff --git a/FS/FS/cdr.pm b/FS/FS/cdr.pm index cdca6fc75..8ccf7af63 100644 --- a/FS/FS/cdr.pm +++ b/FS/FS/cdr.pm @@ -161,6 +161,8 @@ following fields are currently supported: =item cdrbatch +=item detailnum - Link to invoice detail (L<FS::cust_bill_pkg_detail>) + =back =head1 METHODS @@ -214,6 +216,7 @@ sub table_info { #'upstream_rateplanid' => '', #'ratedetailnum' => '', 'rated_price' => 'Rated price', + 'rated_cost' => 'Rated cost', #'distance' => '', #'islocal' => '', #'calltypenum' => '', @@ -226,6 +229,7 @@ sub table_info { 'freesiderewritestatus' => 'Freeside rewrite status', 'cdrbatch' => 'Legacy batch', 'cdrbatchnum' => 'Batch', + 'detailnum' => 'Freeside invoice detail line', }, }; @@ -337,8 +341,12 @@ sub check { #check the foreign keys even? #do we want to outright *reject* the CDR? - my $error = - $self->ut_numbern('acctid'); + my $error = $self->ut_numbern('acctid'); + return $error if $error; + + if ( $self->freesidestatus ne 'done' ) { + $self->set('detailnum', ''); # can't have this on an unbilled call + } #add a config option to turn these back on if someone needs 'em # @@ -351,8 +359,6 @@ sub check { # # Telstra =1, Optus = 2, RSL COM = 3 # || $self->ut_foreign_keyn('carrierid', 'cdr_carrier', 'carrierid' ) - return $error if $error; - $self->SUPER::check; } @@ -463,7 +469,9 @@ Sets the status and rated price. Available options are: inbound, rated_pretty_dst, rated_regionname, rated_seconds, rated_minutes, rated_granularity, rated_ratedetailnum, -rated_classnum, rated_ratename. +rated_classnum, rated_ratename. If rated_ratedetailnum is provided, +will also set a recalculated L</rate_cost> in the rated_cost field +after the other fields are set (does not work with inbound.) If there is an error, returns the error, otherwise returns false. @@ -501,6 +509,8 @@ sub set_status_and_rated_price { qw( pretty_dst regionname seconds minutes granularity ratedetailnum classnum ratename ); $self->svcnum($svcnum) if $svcnum; + $self->rated_cost($self->rate_cost) if $opt{'rated_ratedetailnum'}; + return $self->replace(); } diff --git a/FS/FS/cust_bill_pkg_detail.pm b/FS/FS/cust_bill_pkg_detail.pm index d0cbdbec0..dd118c1b2 100644 --- a/FS/FS/cust_bill_pkg_detail.pm +++ b/FS/FS/cust_bill_pkg_detail.pm @@ -86,15 +86,52 @@ sub table { 'cust_bill_pkg_detail'; } Adds this record to the database. If there is an error, returns the error, otherwise returns false. +=cut + +sub insert { + my $self = shift; + my $error = $self->SUPER::insert(@_); + return $error if $error; + + # link CDRs + my $acctids = $self->get('acctid') or return ''; + $acctids = [ $acctids ] unless ref $acctids; + foreach my $acctid ( @$acctids ) { + my $cdr = FS::cdr->by_key($acctid); + $cdr->set('detailnum', $self->detailnum); + $error = $cdr->replace; + # this should never happen + return "error linking CDR #$acctid: $error" if $error; + } + ''; +} + =item delete Delete this record from the database. +=cut + +sub delete { + my $self = shift; + my $error = $self->SUPER::delete; + return $error if $error; + foreach my $cdr (qsearch('cdr', { detailnum => $self->detailnum })) { + $cdr->set('detailnum', ''); + $error = $cdr->replace; + return "error unlinking CDR #" . $cdr->acctid . ": $error" if $error; + } +} + =item replace OLD_RECORD Replaces the OLD_RECORD with this one in the database. If there is an error, returns the error, otherwise returns false. +=cut + +# the replace method can be inherited from FS::Record (doesn't touch CDRs) + =item check Checks all fields to make sure this is a valid line item detail. If there is diff --git a/FS/FS/detail_format.pm b/FS/FS/detail_format.pm index 8840a006d..be84680f9 100644 --- a/FS/FS/detail_format.pm +++ b/FS/FS/detail_format.pm @@ -178,6 +178,7 @@ Takes a single CDR and returns an invoice detail to describe it. By default, this maps the following fields from the CDR: +acctid => acctid rated_price => amount rated_classnum => classnum rated_seconds => duration @@ -208,6 +209,7 @@ sub single_detail { $price = 0 if $cdr->freesidestatus eq 'no-charge'; FS::cust_bill_pkg_detail->new( { + 'acctid' => $cdr->acctid, 'amount' => $price, 'classnum' => $cdr->rated_classnum, 'duration' => $cdr->rated_seconds, diff --git a/FS/FS/detail_format/sum_count.pm b/FS/FS/detail_format/sum_count.pm index c40fcb8fe..253956f0d 100644 --- a/FS/FS/detail_format/sum_count.pm +++ b/FS/FS/detail_format/sum_count.pm @@ -24,6 +24,7 @@ sub header_detail { sub append { my $self = shift; my $svcnums = ($self->{svcnums} ||= {}); + my $acctids = $self->{acctids} ||= []; foreach my $cdr (@_) { my $object = $self->{inbound} ? $cdr->cdr_termination(1) : $cdr; my $svcnum = $object->svcnum; # yes, $object->svcnum. @@ -33,6 +34,8 @@ sub append { $subtotal->{count}++; $subtotal->{amount} += $object->rated_price if $object->freesidestatus ne 'no-charge'; + + push @$acctids, $cdr->acctid; } } @@ -68,6 +71,7 @@ sub finish { startdate => '', #could use the earliest startdate in the bunch? regionname => '', #no, we're using prefix instead detail => $self->csv->string, + acctid => $self->{acctids}, }); } #foreach $svcnum diff --git a/FS/FS/detail_format/sum_duration.pm b/FS/FS/detail_format/sum_duration.pm index 1b967b407..c41bed385 100644 --- a/FS/FS/detail_format/sum_duration.pm +++ b/FS/FS/detail_format/sum_duration.pm @@ -24,6 +24,7 @@ sub header_detail { sub append { my $self = shift; my $svcnums = ($self->{svcnums} ||= {}); + my $acctids = ($self->{acctids} ||= []); foreach my $cdr (@_) { my $object = $self->{inbound} ? $cdr->cdr_termination(1) : $cdr; my $svcnum = $object->svcnum; # yes, $object->svcnum. @@ -34,6 +35,8 @@ sub append { $subtotal->{duration} += $object->rated_seconds; $subtotal->{amount} += $object->rated_price if $object->freesidestatus ne 'no-charge'; + + push @$acctids, $cdr->acctid; } } @@ -70,6 +73,7 @@ sub finish { startdate => '', #could use the earliest startdate in the bunch? regionname => '', #no, we're using prefix instead detail => $self->csv->string, + acctid => $self->{acctids}, }); } #foreach $svcnum diff --git a/FS/FS/detail_format/sum_duration_prefix.pm b/FS/FS/detail_format/sum_duration_prefix.pm index cd7bbe3cc..3c33dc163 100644 --- a/FS/FS/detail_format/sum_duration_prefix.pm +++ b/FS/FS/detail_format/sum_duration_prefix.pm @@ -24,6 +24,7 @@ my $prefix_length = 6; sub append { my $self = shift; my $prefixes = ($self->{prefixes} ||= {}); + my $acctids = ($self->{acctids} ||= []); foreach my $cdr (@_) { my (undef, $phonenum) = $cdr->parse_number( column => ( $self->{inbound} ? 'src' : 'dst' ), @@ -52,6 +53,8 @@ sub append { $subtotal->{duration} += $object->rated_seconds; $subtotal->{amount} += $object->rated_price if $object->freesidestatus ne 'no-charge'; + + push @$acctids, $cdr->acctid; } } @@ -91,6 +94,7 @@ sub finish { startdate => '', #could use the earliest startdate in the bunch? regionname => '', #no, we're using prefix instead detail => $self->csv->string, + acctid => $self->{acctids}, }); } #foreach $prefix } |