show prorate details on invoice, #16010
[freeside.git] / FS / FS / cust_main / Billing.pm
index 37053fe..0a557fc 100644 (file)
@@ -129,6 +129,14 @@ sub bill_and_collect {
     else                                                     { warn   $error; }
   }
 
+  $error = $self->unsuspend_resumed_pkgs( day_end( $options{actual_time} ) );
+  if ( $error ) {
+    $error = "Error resuming custnum ".$self->custnum. ": $error";
+    if    ( $options{fatal} && $options{fatal} eq 'return' ) { return $error; }
+    elsif ( $options{fatal}                                ) { die    $error; }
+    else                                                     { warn   $error; }
+  }
+
   $job->update_statustext('20,billing packages') if $job;
   $error = $self->bill( %options );
   if ( $error ) {
@@ -177,14 +185,15 @@ sub cancel_expired_pkgs {
   foreach my $cust_pkg ( @cancel_pkgs ) {
     my $cpr = $cust_pkg->last_cust_pkg_reason('expire');
     my $error = $cust_pkg->cancel($cpr ? ( 'reason'        => $cpr->reasonnum,
-                                           'reason_otaker' => $cpr->otaker
+                                           'reason_otaker' => $cpr->otaker,
+                                           'time'          => $time,
                                          )
                                        : ()
                                  );
     push @errors, 'pkgnum '.$cust_pkg->pkgnum.": $error" if $error;
   }
 
-  scalar(@errors) ? join(' / ', @errors) : '';
+  join(' / ', @errors);
 
 }
 
@@ -226,7 +235,25 @@ sub suspend_adjourned_pkgs {
     push @errors, 'pkgnum '.$cust_pkg->pkgnum.": $error" if $error;
   }
 
-  scalar(@errors) ? join(' / ', @errors) : '';
+  join(' / ', @errors);
+
+}
+
+sub unsuspend_resumed_pkgs {
+  my ( $self, $time, %options ) = @_;
+  
+  my @unsusp_pkgs = $self->ncancelled_pkgs( { 
+    'extra_sql' => " AND resume IS NOT NULL AND resume > 0 AND resume <= $time "
+  } );
+
+  my @errors = ();
+
+  foreach my $cust_pkg ( @unsusp_pkgs ) {
+    my $error = $cust_pkg->unsuspend( 'time' => $time );
+    push @errors, 'pkgnum '.$cust_pkg->pkgnum.": $error" if $error;
+  }
+
+  join(' / ', @errors);
 
 }
 
@@ -407,7 +434,8 @@ sub bill {
 
       my $next_bill = $cust_pkg->getfield('bill') || 0;
       my $error;
-      while ( $next_bill <= $time ) {
+      # let this run once if this is the last bill upon cancellation
+      while ( $next_bill <= $time or $options{cancel} ) {
         $error =
           $self->_make_lines( 'part_pkg'            => $part_pkg,
                               'cust_pkg'            => $cust_pkg,
@@ -427,6 +455,9 @@ sub bill {
         # or if we're not incrementing the bill date.
         last if ($cust_pkg->getfield('bill') || 0) == $next_bill;
 
+        # or if we're letting it run only once
+        last if $options{cancel};
+
         $next_bill = $cust_pkg->getfield('bill') || 0;
 
         #stop if -o was passed to freeside-daily
@@ -1085,7 +1116,12 @@ sub _make_lines {
         'freq'      => $part_pkg->freq,
       };
 
-      if ( $part_pkg->recur_temporality eq 'preceding' ) {
+      if ( $part_pkg->option('prorate_defer_bill',1) 
+           and !$hash{last_bill} ) {
+        # both preceding and upcoming, technically
+        $cust_bill_pkg->sdate( $cust_pkg->setup );
+        $cust_bill_pkg->edate( $cust_pkg->bill );
+      } elsif ( $part_pkg->recur_temporality eq 'preceding' ) {
         $cust_bill_pkg->sdate( $hash{last_bill} );
         $cust_bill_pkg->edate( $sdate - 86399   ); #60s*60m*24h-1
         $cust_bill_pkg->edate( $time ) if $options{cancel};
@@ -1165,7 +1201,7 @@ sub _handle_taxes {
 
     } else {
 
-      my @loc_keys = qw( city county state country );
+      my @loc_keys = qw( district city county state country );
       my %taxhash;
       if ( $conf->exists('tax-pkg_address') && $cust_pkg->locationnum ) {
         my $cust_location = $cust_pkg->cust_location;
@@ -1182,7 +1218,7 @@ sub _handle_taxes {
 
       my @taxes = ();
       my %taxhash_elim = %taxhash;
-      my @elim = qw( city county state );
+      my @elim = qw( district city county state );
       do { 
 
         #first try a match with taxclass
@@ -1490,7 +1526,7 @@ sub retry_realtime {
                                      ).
                           ' ) ';
 
-  my @cust_event = qsearchs({
+  my @cust_event = qsearch({
     'table'     => 'cust_event',
     'select'    => 'cust_event.*',
     'addl_from' => "LEFT JOIN part_event USING ( eventpart ) $join",
@@ -2163,6 +2199,7 @@ sub apply_payments {
 
     cancel_expired_pkgs
     suspend_adjourned_pkgs
+    unsuspend_resumed_pkgs
 
     bill
       (do_cust_event pre-bill)