From: mark Date: Wed, 8 Feb 2012 02:17:58 +0000 (+0000) Subject: correct unused-time credits for discounted packages, #16352 X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=7fbe88a91e80c40c70f3e666ce1965586544c181 correct unused-time credits for discounted packages, #16352 --- diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm index 1a99f6ad2..1ee5c0943 100644 --- a/FS/FS/cust_bill_pkg.pm +++ b/FS/FS/cust_bill_pkg.pm @@ -893,7 +893,7 @@ sub usage { if ( $self->get('details') ) { - return sum( + return sum( 0, map { $_->amount || 0 } grep { !defined($classnum) or $classnum eq $_->classnum } @{ $self->get('details') } @@ -908,7 +908,7 @@ sub usage { my $sth = dbh->prepare($sql) or die dbh->errstr; $sth->execute or die $sth->errstr; - return $sth->fetchrow_arrayref->[0]; + return $sth->fetchrow_arrayref->[0] || 0; } diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm index 1c30b67ac..373982b84 100644 --- a/FS/FS/part_pkg.pm +++ b/FS/FS/part_pkg.pm @@ -1292,29 +1292,16 @@ sub calc_recur { die 'no calc_recur for '. shift->plan. "\n"; } sub calc_remain { 0; } sub calc_units { 0; } +#fallback for everything not based on flat.pm +sub recur_temporality { 'upcoming'; } +sub calc_cancel { 0; } + #fallback for everything except bulk.pm sub hide_svc_detail { 0; } #fallback for packages that can't/won't summarize usage sub sum_usage { 0; } -# somewhat more intelligent fallback-- -# covers the standard cases of billing outstanding usage or just running -# another recurring billing cycle -sub calc_cancel { - my $self = shift; - my $conf = new FS::Conf; - if ( $self->recur_temporality eq 'preceding' - and $self->option('bill_recur_on_cancel',1) ) { - return $self->calc_recur(@_); - } - elsif ( $conf->exists('bill_usage_on_cancel') # should be a package option? - and $self->can('calc_usage') ) { - return $self->calc_usage(@_); - } - 0; -} - =item recur_cost_permonth CUST_PKG recur_cost divided by freq (only supported for monthly and longer frequencies) diff --git a/FS/FS/part_pkg/flat.pm b/FS/FS/part_pkg/flat.pm index 531a6a80e..0e44f5db5 100644 --- a/FS/FS/part_pkg/flat.pm +++ b/FS/FS/part_pkg/flat.pm @@ -6,6 +6,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 Tie::IxHash; use List::Util qw( min ); use FS::UI::bytecount; @@ -189,6 +190,22 @@ sub base_recur_permonth { sprintf('%.2f', $self->base_recur($cust_pkg) / $self->freq ); } +sub calc_cancel { + my $self = shift; + my $conf = new FS::Conf; + if ( $self->recur_temporality eq 'preceding' + and $self->option('bill_recur_on_cancel', 1) ) { + # run another recurring cycle + return $self->calc_recur(@_); + } + elsif ( $conf->exists('bill_usage_on_cancel') # should be a package option? + and $self->can('calc_usage') ) { + # bill for outstanding usage + return $self->calc_usage(@_); + } + 0; +} + sub calc_remain { my ($self, $cust_pkg, %options) = @_; @@ -205,19 +222,28 @@ sub calc_remain { || ! $next_bill || $next_bill < $time; - my %sec = ( - 'h' => 3600, # 60 * 60 - 'd' => 86400, # 60 * 60 * 24 - 'w' => 604800, # 60 * 60 * 24 * 7 - 'm' => 2629744, # 60 * 60 * 24 * 365.2422 / 12 - ); - - $self->freq =~ /^(\d+)([hdwm]?)$/ - or die 'unparsable frequency: '. $self->freq; - my $freq_sec = $1 * $sec{$2||'m'}; - return 0 unless $freq_sec; - - sprintf("%.2f", $self->base_recur($cust_pkg, \$time) * ( $next_bill - $time ) / $freq_sec ); + # Use actual charge for this period, not base_recur (for discounts). + # Use sdate < $time and edate >= $time because when billing on + # cancellation, edate = $time. + my $credit = 0; + foreach my $item ( + qsearch('cust_bill_pkg', { + pkgnum => $cust_pkg->pkgnum, + sdate => {op => '<' , value => $time}, + edate => {op => '>=', value => $time}, + recur => {op => '>' , value => 0}, + }) + ) { + # hack to deal with the weird behavior of edate on package cancellation + my $edate = $item->edate; + if ( $self->recur_temporality eq 'preceding' ) { + $edate = $self->add_freq($item->sdate); + } + $credit += ($item->recur - $item->usage) * + ($edate - $time) / ($edate - $item->sdate); + } + sprintf('%.2f', $credit); + #sprintf("%.2f", $self->base_recur($cust_pkg, \$time) * ( $next_bill - $time ) / $freq_sec ); }