summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FS/FS/cust_bill_pkg.pm4
-rw-r--r--FS/FS/part_pkg.pm21
-rw-r--r--FS/FS/part_pkg/flat.pm52
3 files changed, 45 insertions, 32 deletions
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 );
}