From 4fca6a5a80e474a55c3cd040f0d4a1c39f74f984 Mon Sep 17 00:00:00 2001
From: Tomas Cohen Arazi <tomascohen@gmail.com>
Date: Fri, 21 Sep 2012 12:50:26 -0300
Subject: [PATCH] Bug 8800 -  useDaysMode=Datedue wrong behaviour
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

useDaysMode=Datedue wasn't used as advertised in the docs. Added a
next_open_day sub to Koha::Calendar and some tests for it.

- AddIssue was fixed for the case $datedue was defined in circ/circulation.pl
- CalcDateDue was modified to be consistent with the intended behaviour

Regards
To+

Sponsored-by: Universidad Nacional de Córdoba
---
 C4/Circulation.pm |   22 ++++++++++++++++------
 Koha/Calendar.pm  |   26 +++++++++++++++++++++++---
 t/Calendar.t      |    6 +++++-
 3 files changed, 44 insertions(+), 10 deletions(-)

diff --git a/C4/Circulation.pm b/C4/Circulation.pm
index 71e13bb..825c3cb 100644
--- a/C4/Circulation.pm
+++ b/C4/Circulation.pm
@@ -1161,6 +1161,10 @@ sub AddIssue {
 	my $barcodecheck=CheckValidBarcode($barcode);
     if ($datedue && ref $datedue ne 'DateTime') {
         $datedue = dt_from_string($datedue);
+        if ( C4::Context->preference('useDaysMode') eq 'Datedue' ) {
+          # use the calendar to push the due date to the next open day
+          $datedue = $calendar->next_open_day($datedue);
+        }
     }
     # $issuedate defaults to today.
     if ( ! defined $issuedate ) {
@@ -3004,22 +3008,29 @@ sub CalcDateDue {
             C4::Context->preference('dateformat')
         );
     } else {
-
         # otherwise, calculate the datedue as normal
-        if ( C4::Context->preference('useDaysMode') eq 'Days' )
-        {    # ignoring calendar
+        my $calendar = Koha::Calendar->new( branchcode => $branch );
+
+        if ( C4::Context->preference('useDaysMode') ne 'Calendar' )
+        {   # ignoring calendar to calculate date due
             my $dt =
               DateTime->now( time_zone => C4::Context->tz() )
               ->truncate( to => 'minute' );
             if ( $loanlength->{lengthunit} eq 'hours' ) {
                 $dt->add( hours => $loanlength->{issuelength} );
-                return $dt;
             } else {    # days
                 $dt->add( days => $loanlength->{issuelength} );
                 $dt->set_hour(23);
                 $dt->set_minute(59);
-                return $dt;
             }
+            
+            if ( C4::Context->preference('useDaysMode') eq 'Datedue' ) {
+                # use the calendar to push the due date to the next open day
+                $dt = $calendar->next_open_day($dt);
+            }
+
+            return $dt;
+
         } else {
             my $dur;
             if ($loanlength->{lengthunit} eq 'hours') {
@@ -3031,7 +3042,6 @@ sub CalcDateDue {
             if (ref $startdate ne 'DateTime' ) {
                 $startdate = dt_from_string($startdate);
             }
-            my $calendar = Koha::Calendar->new( branchcode => $branch );
             $datedue = $calendar->addDate( $startdate, $dur, $loanlength->{lengthunit} );
             if ($loanlength->{lengthunit} eq 'days') {
                 $datedue->set_hour(23);
diff --git a/Koha/Calendar.pm b/Koha/Calendar.pm
index 2a2e062..862e4f8 100644
--- a/Koha/Calendar.pm
+++ b/Koha/Calendar.pm
@@ -164,6 +164,16 @@ sub is_holiday {
     return 0;
 }
 
+sub next_open_day {
+    my ( $self, $dt ) = @_;
+
+    while ($self->is_holiday($dt)) {
+        $dt->add(days => 1);
+    }
+
+    return $dt;
+}
+
 sub days_between {
     my $self     = shift;
     my $start_dt = shift;
@@ -273,9 +283,9 @@ This documentation refers to Koha::Calendar version 0.0.1
 
 =head1 SYNOPSIS
 
-  use Koha::Calendat
+  use Koha::Calendar
 
-  my $c = Koha::Calender->new( branchcode => 'MAIN' );
+  my $c = Koha::Calendar->new( branchcode => 'MAIN' );
   my $dt = DateTime->now();
 
   # are we open
@@ -315,7 +325,7 @@ parameter will be removed when issuingrules properly cope with that
 
 $yesno = $calendar->is_holiday($dt);
 
-passed at DateTime object returns 1 if it is a closed day
+passed a DateTime object returns 1 if it is a closed day
 0 if not according to the calendar
 
 =head2 days_between
@@ -326,6 +336,16 @@ Passed two dates returns a DateTime::Duration object measuring the length betwee
 ignoring closed days. Always returns a positive number irrespective of the
 relative order of the parameters
 
+=head2 next_open_day
+
+$datetime = $calendar->next_open_day($duedate_dt)
+
+Passed a Datetime returns another Datetime representing the next open day. It is
+intended for use to calculate the due date when useDaysMode syspref is set to either
+'Datedue' or 'Calendar'.
+
+Note: if is_holiday($duedate_dt) = 0 then it should return the same date.
+
 =head2 set_daysmode
 
 For testing only allows the calling script to change days mode
diff --git a/t/Calendar.t b/t/Calendar.t
index 283300e..9ff4e13 100755
--- a/t/Calendar.t
+++ b/t/Calendar.t
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 use DateTime;
-use Test::More tests => 21;
+use Test::More tests => 23;
 use Koha::DateUtils;
 
 BEGIN {
@@ -127,3 +127,7 @@ $cal->add_holiday( dt_from_string('2012-07-07','iso') );
 $daycount = $cal->days_between( dt_from_string("2012-07-01",'iso'),
     dt_from_string("2012-07-15",'iso') )->in_units('days');
 cmp_ok( $daycount, '==', 12, 'multiple holidays correctly recognized' );
+$dt = dt_from_string('2012-07-07','iso');
+cmp_ok( $dt->add(days => 1), '==', $cal->next_open_day(dt_from_string('2012-07-07','iso')), 'Next open day correctly calculated' );
+$dt = dt_from_string('2012-07-08','iso');
+cmp_ok( $dt, '==', $cal->next_open_day(dt_from_string('2012-07-08','iso')), 'Next open day correctly calculated (idempotent version)' );
-- 
1.7.9.5