diff options
author | Ivan Kohler <ivan@freeside.biz> | 2015-01-20 21:41:15 -0800 |
---|---|---|
committer | Ivan Kohler <ivan@freeside.biz> | 2015-01-20 21:41:15 -0800 |
commit | 908a4522939c0225ef4e7ba4236dab2eebe9daca (patch) | |
tree | 34890c50a3642e19391cc0851bd35b28e4010e76 /FS | |
parent | e46ea78f6d233fbf0314d1386237bd225ef29035 (diff) |
credit sources, RT#28917
Diffstat (limited to 'FS')
-rw-r--r-- | FS/FS.pm | 2 | ||||
-rw-r--r-- | FS/FS/Schema.pm | 21 | ||||
-rw-r--r-- | FS/FS/cust_credit.pm | 11 | ||||
-rw-r--r-- | FS/FS/cust_credit_source_bill_pkg.pm | 122 | ||||
-rw-r--r-- | FS/FS/cust_pkg.pm | 7 | ||||
-rw-r--r-- | FS/FS/part_pkg/flat.pm | 25 | ||||
-rw-r--r-- | FS/MANIFEST | 2 |
7 files changed, 183 insertions, 7 deletions
@@ -452,6 +452,8 @@ L<FS::cust_credit_bill> - Credit application to invoice class L<FS::cust_credit_bill_pkg> - Line-item specific credit application to invoice class +L<FS::cust_credit_source_bill_pkg> - Line-item sources for triggered package credits + L<FS::cust_pay_refund> - Refund application to payment class L<FS::pay_batch> - Credit card transaction queue class diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index f51b576..b6358b9 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1526,6 +1526,27 @@ sub tables_hashref { ], }, + 'cust_credit_source_bill_pkg' => { + 'columns' => [ + 'creditsourcebillpkgnum', 'serial', '', '', '', '', + 'crednum', 'int', '', '', '', '', + 'billpkgnum', 'int', '', '', '', '', + 'amount', @money_type, '', '', + 'currency', 'char', 'NULL', 3, '', '', + ], + 'primary_key' => 'creditsourcebillpkgnum', + 'unique' => [], + 'index' => [ ['crednum'], ['billpkgnum'] ], + 'foreign_keys' => [ + { columns => ['billpkgnum'], + table => 'cust_bill_pkg', + }, + { columns => ['crednum'], + table => 'cust_credit', + }, + ], + }, + 'cust_main' => { 'columns' => [ 'custnum', 'serial', '', '', '', '', diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm index 212be7a..dde847a 100644 --- a/FS/FS/cust_credit.pm +++ b/FS/FS/cust_credit.pm @@ -176,6 +176,17 @@ sub insert { return "error inserting $self: $error"; } + if ( $options{'cust_credit_source_bill_pkg'} ) { + foreach my $ccsbr ( @{ $options{'cust_credit_source_bill_pkg'} } ) { + $ccsbr->crednum( $self->crednum ); + $error = $ccsbr->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "error inserting $ccsbr: $error"; + } + } + } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; #false laziness w/ cust_pay::insert diff --git a/FS/FS/cust_credit_source_bill_pkg.pm b/FS/FS/cust_credit_source_bill_pkg.pm new file mode 100644 index 0000000..dae0d0f --- /dev/null +++ b/FS/FS/cust_credit_source_bill_pkg.pm @@ -0,0 +1,122 @@ +package FS::cust_credit_source_bill_pkg; +use base qw( FS::cust_main_Mixin FS::Record ); + +use strict; +#use FS::Record qw( qsearch qsearchs ); + +=head1 NAME + +FS::cust_credit_source_bill_pkg - Object methods for cust_credit_source_bill_pkg records + +=head1 SYNOPSIS + + use FS::cust_credit_source_bill_pkg; + + $record = new FS::cust_credit_source_bill_pkg \%hash; + $record = new FS::cust_credit_source_bill_pkg { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::cust_credit_source_bill_pkg object represents the record that a credit +was triggered by a specific line item. FS::cust_credit_source_bill_pkg +inherits from FS::Record. The following fields are currently supported: + +=over 4 + +=item creditsourcebillpkgnum + +Primary key + +=item crednum + +Credit (see L<FS::cust_credit>) + +=item billpkgnum + +Line item (see L<FS::cust_bill_pkg>) + +=item amount + +Amount specific to this line item. + +=item currency + +Currency + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new record. To add the record to the database, see L<"insert">. + +Note that this stores the hash reference, not a distinct copy of the hash it +points to. You can ask the object for a copy with the I<hash> method. + +=cut + +sub table { 'cust_credit_source_bill_pkg'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=item delete + +Delete this record from the database. + +=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. + +=item check + +Checks all fields to make sure this is a valid record. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +sub check { + my $self = shift; + + my $error = + $self->ut_numbern('creditsourcebillpkgnum') + || $self->ut_foreign_key('crednum', 'cust_credit', 'crednum') + || $self->ut_foreign_key('billpkgnum', 'cust_bill_pkg', 'billpkgnum') + || $self->ut_money('amount') + || $self->ut_currencyn('currency') + ; + return $error if $error; + + $self->SUPER::check; +} + +=back + +=head1 BUGS + +Terminology/documentation surrounding credit "sources" vs. credit +"applications" is hard to understand. + +=head1 SEE ALSO + +L<FS::cust_credit>, L<FS::cust_bill_pkg>, L<FS::Record> + +=cut + +1; + diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index d55bd7b..5e070e3 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1440,7 +1440,11 @@ sub credit_remaining { and $next_bill > 0 # the package has a next bill date and $next_bill >= $time # which is in the future ) { - my $remaining_value = $self->calc_remain('time' => $time); + my @cust_credit_source_bill_pkg = (); + my $remaining_value = $self->calc_remain( + 'time' => $time, + 'cust_credit_source_bill_pkg' => \@cust_credit_source_bill_pkg, + ); if ( $remaining_value > 0 ) { warn "Crediting for $remaining_value on package ".$self->pkgnum."\n" if $DEBUG; @@ -1448,6 +1452,7 @@ sub credit_remaining { $remaining_value, 'Credit for unused time on '. $self->part_pkg->pkg, 'reason_type' => $reason_type, + 'cust_credit_source_bill_pkg' => \@cust_credit_source_bill_pkg, ); return "Error crediting customer \$$remaining_value for unused time". " on ". $self->part_pkg->pkg. ": $error" diff --git a/FS/FS/part_pkg/flat.pm b/FS/FS/part_pkg/flat.pm index cb2986e..d9d4588 100644 --- a/FS/FS/part_pkg/flat.pm +++ b/FS/FS/part_pkg/flat.pm @@ -7,6 +7,7 @@ use base qw( FS::part_pkg::prorate_Mixin use strict; use vars qw( %info %usage_recharge_fields @usage_recharge_fieldorder ); use FS::Record qw( qsearch ); +use FS::cust_credit_source_bill_pkg; use Tie::IxHash; use List::Util qw( min ); use FS::UI::bytecount; @@ -242,7 +243,7 @@ sub calc_remain { # Use sdate < $time and edate >= $time because when billing on # cancellation, edate = $time. my $credit = 0; - foreach my $item ( + foreach my $cust_bill_pkg ( qsearch('cust_bill_pkg', { pkgnum => $cust_pkg->pkgnum, sdate => {op => '<' , value => $time}, @@ -250,16 +251,28 @@ sub calc_remain { recur => {op => '>' , value => 0}, }) ) { + # hack to deal with the weird behavior of edate on package cancellation - my $edate = $item->edate; + my $edate = $cust_bill_pkg->edate; if ( $self->recur_temporality eq 'preceding' ) { - $edate = $self->add_freq($item->sdate); + $edate = $self->add_freq($cust_bill_pkg->sdate); } - $credit += ($item->recur - $item->usage) * - ($edate - $time) / ($edate - $item->sdate); + + my $amount = ($cust_bill_pkg->recur - $cust_bill_pkg->usage) * + ($edate - $time) / ($edate - $cust_bill_pkg->sdate); + $credit += $amount; + + push @{ $options{'cust_credit_source_bill_pkg'} }, + new FS::cust_credit_source_bill_pkg { + 'billpkgnum' => $cust_bill_pkg->billpkgnum, + 'amount' => sprintf('%.2f', $amount), + 'currency' => $cust_bill_pkg->cust_bill->currency, + } + if $options{'cust_credit_source_bill_pkg'}; + } + sprintf('%.2f', $credit); - #sprintf("%.2f", $self->base_recur($cust_pkg, \$time) * ( $next_bill - $time ) / $freq_sec ); } diff --git a/FS/MANIFEST b/FS/MANIFEST index 581ab0d..6e36c33 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -832,3 +832,5 @@ FS/circuit_termination.pm t/circuit_termination.t FS/svc_circuit.pm t/svc_circuit.t +FS/cust_credit_source_bill_pkg.pm +t/cust_credit_source_bill_pkg.t |