split discount bs out into its own file before cust_main/Billing.pm becomes as bad...
authorivan <ivan>
Fri, 5 Nov 2010 22:58:50 +0000 (22:58 +0000)
committerivan <ivan>
Fri, 5 Nov 2010 22:58:50 +0000 (22:58 +0000)
FS/FS/cust_main.pm
FS/FS/cust_main/Billing.pm
FS/FS/cust_main/Billing_Discount.pm [new file with mode: 0644]
FS/MANIFEST

index 7969965..03e8cc6 100644 (file)
@@ -5,6 +5,7 @@ use strict;
              #FS::cust_main:_Marketgear when they're ready to move to 2.1
 use base qw( FS::cust_main::Packages
              FS::cust_main::Billing FS::cust_main::Billing_Realtime
+             FS::cust_main::Billing_Discount
              FS::otaker_Mixin FS::payinfo_Mixin FS::cust_main_Mixin
              FS::geocode_Mixin
              FS::Record
index e004788..536a938 100644 (file)
@@ -12,7 +12,6 @@ use FS::cust_bill_pkg;
 use FS::cust_bill_pkg_display;
 use FS::cust_bill_pay;
 use FS::cust_credit_bill;
-use FS::cust_pkg;
 use FS::cust_tax_adjustment;
 use FS::tax_rate;
 use FS::tax_rate_location;
@@ -20,6 +19,7 @@ use FS::cust_bill_pkg_tax_location;
 use FS::cust_bill_pkg_tax_rate_location;
 use FS::part_event;
 use FS::part_event_condition;
+use FS::pkg_category;
 
 # 1 is mostly method/subroutine entry and options
 # 2 traces progress of some operations
@@ -897,6 +897,7 @@ sub _make_lines {
 
     # There may be some part_pkg for which this is wrong.  Only those
     # which can_discount are supported.
+    # (the UI should prevent adding discounts to these at the moment)
 
     $recur = eval { $cust_pkg->$method( \$sdate, \@details, \%param ) };
     return "$@ running $method for $cust_pkg\n"
@@ -1626,174 +1627,6 @@ Explicitly pass the objects to be tested (typically used with eventtable).
 Set to true to return the objects, but not actually insert them into the
 database.
 
-=item discount_terms
-
-Returns a list of lengths for term discounts
-
-=cut
-
-sub _discount_pkgs_and_bill {
-my $self = shift;
-
-  my @cust_bill = $self->cust_bill;
-  my $cust_bill = pop @cust_bill;
-  return () unless $cust_bill && $cust_bill->owed;
-
-  my @where = ();
-  push @where, "cust_bill_pkg.invnum = ". $cust_bill->invnum;
-  push @where, "cust_bill_pkg.pkgpart_override IS NULL";
-  push @where, "part_pkg.freq = '1'";
-  push @where, "(cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0)";
-  push @where, "(cust_pkg.susp   IS NULL OR cust_pkg.susp   = 0)";
-  push @where, "0<(SELECT count(*) FROM part_pkg_discount
-                  WHERE part_pkg.pkgpart = part_pkg_discount.pkgpart)";
-  push @where,
-    "0=(SELECT count(*) FROM cust_bill_pkg_discount
-         WHERE cust_bill_pkg.billpkgnum = cust_bill_pkg_discount.billpkgnum)";
-
-  my $extra_sql = 'WHERE '. join(' AND ', @where);
-
-  my @cust_pkg = 
-    qsearch({
-      'table' => 'cust_pkg',
-      'select' => "DISTINCT cust_pkg.*",
-      'addl_from' => 'JOIN cust_bill_pkg USING(pkgnum) '.
-                     'JOIN part_pkg USING(pkgpart)',
-      'hashref' => {},
-      'extra_sql' => $extra_sql,
-    }); 
-
-  ($cust_bill, @cust_pkg);
-}
-
-sub _discountable_pkgs_at_term {
-  my ($term, @pkgs) = @_;
-  my $part_pkg = new FS::part_pkg { freq => $term - 1 };
-  grep { ( !$_->adjourn || $_->adjourn > $part_pkg->add_freq($_->bill) ) && 
-         ( !$_->expire  || $_->expire  > $part_pkg->add_freq($_->bill) )
-       }
-    @pkgs;
-}
-
-=item discount_terms
-
-Returns a list of lengths for term discounts
-
-=cut
-
-sub discount_terms {
-my $self = shift;
-
-  my %terms = ();
-
-  my @discount_pkgs = $self->_discount_pkgs_and_bill;
-  shift @discount_pkgs; #discard bill;
-  
-  map { $terms{$_->months} = 1 }
-    grep { $_->months && $_->months > 1 }
-    map { $_->discount }
-    map { $_->part_pkg->part_pkg_discount }
-    @discount_pkgs;
-
-  return sort { $a <=> $b } keys %terms;
-
-}
-
-=back
-
-=item discount_term_values MONTHS
-
-Returns a list with credit, dollar amount saved, and total bill acheived
-by prepaying the most recent invoice for MONTHS.
-
-=cut
-
-sub discount_term_values {
-  my $self = shift;
-  my $term = shift;
-
-  local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG;
-
-  warn "$me discount_term_values called with $term\n" if $DEBUG;
-
-  my %result = ();
-
-  my @packages = $self->_discount_pkgs_and_bill;
-  my $cust_bill = shift(@packages);
-  @packages = _discountable_pkgs_at_term( $term, @packages );
-  return () unless scalar(@packages);
-
-  $_->bill($_->last_bill) foreach @packages;
-  my @final = map { new FS::cust_pkg { $_->hash } } @packages;
-
-  my %options = (
-                  'recurring_only' => 1,
-                  'no_usage_reset' => 1,
-                  'no_commit'      => 1,
-                );
-
-  my %params =  (
-                  'return_bill'    => [],
-                  'pkg_list'       => \@packages,
-                  'time'           => $cust_bill->_date,
-                );
-
-  my $error = $self->bill(%options, %params);
-  die $error if $error; # XXX think about this a bit more
-
-  my $credit = 0;
-  $credit += $_->charged foreach @{$params{return_bill}};
-  $credit = sprintf('%.2f', $credit);
-  warn "$me discount_term_values $term credit: $credit\n" if $DEBUG;
-
-  %params =  (
-               'return_bill'    => [],
-               'pkg_list'       => \@packages,
-               'time'           => $packages[0]->part_pkg->add_freq($cust_bill->_date)
-             );
-
-  $error = $self->bill(%options, %params);
-  die $error if $error; # XXX think about this a bit more
-
-  my $next = 0;
-  $next += $_->charged foreach @{$params{return_bill}};
-  warn "$me discount_term_values $term next: $next\n" if $DEBUG;
-  
-  %params =  ( 
-               'return_bill'    => [],
-               'pkg_list'       => \@final,
-               'time'           => $cust_bill->_date,
-               'freq_override'  => $term,
-             );
-
-  $error = $self->bill(%options, %params);
-  die $error if $error; # XXX think about this a bit more
-
-  my $final = $self->balance - $credit;
-  $final += $_->charged foreach @{$params{return_bill}};
-  $final = sprintf('%.2f', $final);
-  warn "$me discount_term_values $term final: $final\n" if $DEBUG;
-
-  my $savings = sprintf('%.2f', $self->balance + ($term - 1) * $next - $final);
-
-  ( $credit, $savings, $final );
-
-}
-
-sub discount_terms_hash {
-  my $self = shift;
-
-  my %result = ();
-  my @terms = $self->discount_terms;
-  foreach my $term (@terms) {
-    my @result = $self->discount_term_values($term);
-    $result{$term} = [ @result ] if scalar(@result);
-  }
-
-  return %result;
-
-}
-
 =back
 
 =cut
@@ -2245,6 +2078,8 @@ sub apply_payments {
   return $total_unapplied_payments;
 }
 
+=back
+
 =head1 BUGS
 
 =head1 SEE ALSO
diff --git a/FS/FS/cust_main/Billing_Discount.pm b/FS/FS/cust_main/Billing_Discount.pm
new file mode 100644 (file)
index 0000000..9dda389
--- /dev/null
@@ -0,0 +1,207 @@
+package FS::cust_main::Billing_Discount;
+
+use strict;
+use vars qw( $DEBUG $me );
+use FS::Record qw( qsearch ); #qsearchs );
+use FS::cust_pkg;
+
+# 1 is mostly method/subroutine entry and options
+# 2 traces progress of some operations
+# 3 is even more information including possibly sensitive data
+$DEBUG = 0;
+$me = '[FS::cust_main::Billing_Discount]';
+
+=head1 NAME
+
+FS::cust_main::Billing_Discount - Billing discount mixin for cust_main
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+These methods are available on FS::cust_main objects.
+
+=head1 METHODS
+
+=over 4
+
+=item _discount_pkg_and_bill
+
+=cut
+
+sub _discount_pkgs_and_bill {
+  my $self = shift;
+
+  my @cust_bill = $self->cust_bill;
+  my $cust_bill = pop @cust_bill;
+  return () unless $cust_bill && $cust_bill->owed;
+
+  my @where = ();
+  push @where, "cust_bill_pkg.invnum = ". $cust_bill->invnum;
+  push @where, "cust_bill_pkg.pkgpart_override IS NULL";
+  push @where, "part_pkg.freq = '1'";
+  push @where, "(cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0)";
+  push @where, "(cust_pkg.susp   IS NULL OR cust_pkg.susp   = 0)";
+  push @where, "0<(SELECT count(*) FROM part_pkg_discount
+                  WHERE part_pkg.pkgpart = part_pkg_discount.pkgpart)";
+  push @where,
+    "0=(SELECT count(*) FROM cust_bill_pkg_discount
+         WHERE cust_bill_pkg.billpkgnum = cust_bill_pkg_discount.billpkgnum)";
+
+  my $extra_sql = 'WHERE '. join(' AND ', @where);
+
+  my @cust_pkg = 
+    qsearch({
+      'table' => 'cust_pkg',
+      'select' => "DISTINCT cust_pkg.*",
+      'addl_from' => 'JOIN cust_bill_pkg USING(pkgnum) '.
+                     'JOIN part_pkg USING(pkgpart)',
+      'hashref' => {},
+      'extra_sql' => $extra_sql,
+    }); 
+
+  ($cust_bill, @cust_pkg);
+}
+
+=item _discountable_pkgs_at_term
+
+=cut
+
+#this isn't even a method
+sub _discountable_pkgs_at_term {
+  my ($term, @pkgs) = @_;
+  my $part_pkg = new FS::part_pkg { freq => $term - 1 };
+  grep { ( !$_->adjourn || $_->adjourn > $part_pkg->add_freq($_->bill) ) && 
+         ( !$_->expire  || $_->expire  > $part_pkg->add_freq($_->bill) )
+       }
+    @pkgs;
+}
+
+=item discount_terms
+
+Returns a list of lengths for term discounts
+
+=cut
+
+sub discount_terms {
+  my $self = shift;
+
+  my %terms = ();
+
+  my @discount_pkgs = $self->_discount_pkgs_and_bill;
+  shift @discount_pkgs; #discard bill;
+  
+  map { $terms{$_->months} = 1 }
+    grep { $_->months && $_->months > 1 }
+    map { $_->discount }
+    map { $_->part_pkg->part_pkg_discount }
+    @discount_pkgs;
+
+  return sort { $a <=> $b } keys %terms;
+
+}
+
+=item discount_term_values MONTHS
+
+Returns a list with credit, dollar amount saved, and total bill acheived
+by prepaying the most recent invoice for MONTHS.
+
+=cut
+
+sub discount_term_values {
+  my $self = shift;
+  my $term = shift;
+
+  local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG;
+
+  warn "$me discount_term_values called with $term\n" if $DEBUG;
+
+  my %result = ();
+
+  my @packages = $self->_discount_pkgs_and_bill;
+  my $cust_bill = shift(@packages);
+  @packages = _discountable_pkgs_at_term( $term, @packages );
+  return () unless scalar(@packages);
+
+  $_->bill($_->last_bill) foreach @packages;
+  my @final = map { new FS::cust_pkg { $_->hash } } @packages;
+
+  my %options = (
+                  'recurring_only' => 1,
+                  'no_usage_reset' => 1,
+                  'no_commit'      => 1,
+                );
+
+  my %params =  (
+                  'return_bill'    => [],
+                  'pkg_list'       => \@packages,
+                  'time'           => $cust_bill->_date,
+                );
+
+  my $error = $self->bill(%options, %params);
+  die $error if $error; # XXX think about this a bit more
+
+  my $credit = 0;
+  $credit += $_->charged foreach @{$params{return_bill}};
+  $credit = sprintf('%.2f', $credit);
+  warn "$me discount_term_values $term credit: $credit\n" if $DEBUG;
+
+  %params =  (
+               'return_bill'    => [],
+               'pkg_list'       => \@packages,
+               'time'           => $packages[0]->part_pkg->add_freq($cust_bill->_date)
+             );
+
+  $error = $self->bill(%options, %params);
+  die $error if $error; # XXX think about this a bit more
+
+  my $next = 0;
+  $next += $_->charged foreach @{$params{return_bill}};
+  warn "$me discount_term_values $term next: $next\n" if $DEBUG;
+  
+  %params =  ( 
+               'return_bill'    => [],
+               'pkg_list'       => \@final,
+               'time'           => $cust_bill->_date,
+               'freq_override'  => $term,
+             );
+
+  $error = $self->bill(%options, %params);
+  die $error if $error; # XXX think about this a bit more
+
+  my $final = $self->balance - $credit;
+  $final += $_->charged foreach @{$params{return_bill}};
+  $final = sprintf('%.2f', $final);
+  warn "$me discount_term_values $term final: $final\n" if $DEBUG;
+
+  my $savings = sprintf('%.2f', $self->balance + ($term - 1) * $next - $final);
+
+  ( $credit, $savings, $final );
+
+}
+
+sub discount_terms_hash {
+  my $self = shift;
+
+  my %result = ();
+  my @terms = $self->discount_terms;
+  foreach my $term (@terms) {
+    my @result = $self->discount_term_values($term);
+    $result{$term} = [ @result ] if scalar(@result);
+  }
+
+  return %result;
+
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::cust_main>, L<FS::cust_main::Billing>
+
+=cut
+
+1;
index 56f7af0..b4bce28 100644 (file)
@@ -69,6 +69,7 @@ FS/cust_credit.pm
 FS/cust_credit_bill.pm
 FS/cust_main.pm
 FS/cust_main/Billing.pm
+FS/cust_main/Billing_Discount.pm
 FS/cust_main/Billing_Realtime.pm
 FS/cust_main/Import.pm
 FS/cust_main/Packages.pm