LP#1422379 Move money.billing timestamps back to moment of fine
authorDan Wells <dbw2@calvin.edu>
Thu, 29 Jan 2015 21:07:27 +0000 (16:07 -0500)
committerDan Wells <dbw2@calvin.edu>
Mon, 16 Feb 2015 14:40:01 +0000 (09:40 -0500)
Current code stamps billings into the future, with the underlying
concept that the time represents when the billing ends, not when it
begins.  This is hard to understand, and requires frequent explanation
to those not familiar with it.

Let's instead do the more natural thing and have the first billing come
one second after the due time, then every fine interval after that.

Signed-off-by: Dan Wells <dbw2@calvin.edu>
Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm

index b619711..41d69f5 100644 (file)
@@ -13,7 +13,7 @@ use OpenILS::Utils::CStoreEditor qw/:funcs/;
 use DateTime;
 use DateTime::Format::ISO8601;
 use OpenILS::Utils::Penalty;
-use POSIX qw(ceil);
+use POSIX qw(floor);
 use OpenILS::Application::Circ::CircCommon;
 use OpenILS::Application::AppUtils;
 my $U = "OpenILS::Application::AppUtils";
@@ -1180,22 +1180,21 @@ sub generate_fines {
             my $current_fine_total = 0;
             $current_fine_total += int($_->amount * 100) for (grep { $_ and !$_->voided } @fines);
     
-            my $last_fine;
+            my $next_fine;
             if ($fine) {
                 $client->respond( "Last billing time: ".$fine->billing_ts." (clensed format: ".cleanse_ISO8601( $fine->billing_ts ).")");
-                $last_fine = $parser->parse_datetime( cleanse_ISO8601( $fine->billing_ts ) )->epoch;
+                my $last_fine = $parser->parse_datetime( cleanse_ISO8601( $fine->billing_ts ) )->epoch;
+                $next_fine = $last_fine + $fine_interval;
             } else {
                 $log->info( "Potential first billing for circ ".$c->id );
-                $last_fine = $due;
+                $next_fine = $due + 1; # first fine comes one second after due time
 
                 $grace_period = OpenILS::Application::Circ::CircCommon->extend_grace_period($c->$circ_lib_method->to_fieldmapper->id,$c->$due_date_method,$grace_period,undef,$hoo{$c->$circ_lib_method});
             }
 
-            return if ($last_fine > $now);
+            return if ($next_fine > $now);
             # Generate fines for each past interval, including the one we are inside
-            my $pending_fine_count = ceil( ($now - $last_fine) / $fine_interval );
-
-            if ( $last_fine == $due                         # we have no fines yet
+            if ( $next_fine == $due + 1                     # we have no fines yet
                  && $grace_period                           # and we have a grace period
                  && $now < $due + $grace_period             # and some date math says were are within the grace period
             ) {
@@ -1204,6 +1203,7 @@ sub generate_fines {
                 return;
             }
 
+            my $pending_fine_count = 1 + floor( ($now - $next_fine) / $fine_interval ); # next fine + every fine interval after that
             $client->respond( "\t$pending_fine_count pending fine(s)\n" );
             return unless ($pending_fine_count);
 
@@ -1231,9 +1231,9 @@ sub generate_fines {
                 }
                 
                 # XXX Use org time zone (or default to 'local') once we have the ou setting built for that
-                my $billing_ts = DateTime->from_epoch( epoch => $last_fine, time_zone => 'local' );
+                my $billing_ts = DateTime->from_epoch( epoch => $next_fine, time_zone => 'local' );
                 my $current_bill_count = $bill;
-                while ( $current_bill_count ) {
+                while ( $current_bill_count > 1 ) {
                     $billing_ts->add( seconds_to_interval_hash( $fine_interval ) );
                     $current_bill_count--;
                 }