Bugzilla – Attachment 29336 Details for
Bug 8133
hourly loans doesn't know when library closed
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 8133 - New fix: hourly loans doesn't know when library closed
Bug-8133---New-fix-hourly-loans-doesnt-know-when-l.patch (text/plain), 42.38 KB, created by
Maxime Beaulieu
on 2014-06-27 20:54:14 UTC
(
hide
)
Description:
Bug 8133 - New fix: hourly loans doesn't know when library closed
Filename:
MIME Type:
Creator:
Maxime Beaulieu
Created:
2014-06-27 20:54:14 UTC
Size:
42.38 KB
patch
obsolete
>From 437368abbf2522149677975cd0ec5967ef19374e Mon Sep 17 00:00:00 2001 >From: mbeaulieu <mbeaulieu@inlibro.com> >Date: Fri, 27 Jun 2014 16:17:42 -0400 >Subject: [PATCH] Bug 8133 - New fix: hourly loans doesn't know when library > closed > >Overdues now take into account opening and closing time. >Fines will not be applied when the library is closed. > >A test script 't/Calendar1.t' is provided for preleminary testing. >--- > C4/Calendar.pm | 62 +++- > C4/Circulation.pm | 37 ++- > C4/Overdues.pm | 31 +- > Koha/Calendar.pm | 84 +++-- > installer/data/mysql/updatedatabase.pl | 34 ++ > .../prog/en/modules/tools/holidays.tt | 143 ++++++++- > misc/cronjobs/fines.pl | 17 +- > t/Calendar1.t | 333 ++++++++++++++++++++ > tools/holidays.pl | 66 +++- > 9 files changed, 755 insertions(+), 52 deletions(-) > create mode 100755 t/Calendar1.t > >diff --git a/C4/Calendar.pm b/C4/Calendar.pm >index 1e687db..10dbd77 100644 >--- a/C4/Calendar.pm >+++ b/C4/Calendar.pm >@@ -17,13 +17,19 @@ package C4::Calendar; > > use strict; > use warnings; >-use vars qw($VERSION @EXPORT); >+use vars qw($VERSION @ISA @EXPORT_OK @EXPORT); > > use Carp; > use Date::Calc qw( Date_to_Days Today); > > use C4::Context; > >+BEGIN { >+ $VERSION = 3.07.00.049; >+ @ISA = qw(Exporter); >+ @EXPORT_OK = qw(setOpeningHours getOpeningHours); >+} >+ > use constant ISO_DATE_FORMAT => "%04d-%02d-%02d"; > =head1 NAME > >@@ -722,6 +728,60 @@ sub daysBetween { > return($count); > } > >+sub setOpeningHours { >+ my ($branchcode, $weekcode, $openhour, $closehour) = @_; >+ >+ my $dbh = C4::Context->dbh; >+ my $sth = $dbh->prepare("SELECT * FROM openinghours WHERE branchcode = ? AND weekcode = ?"); >+ $sth->execute($branchcode, $weekcode); >+ >+ if ( not $sth->fetchrow_hashref ) { >+ my $sth2 = $dbh->prepare('INSERT INTO openinghours (branchcode, weekcode, openhour, closehour) VALUES(?,?,?,?)'); >+ >+ $sth2->execute( $branchcode, $weekcode, $openhour, $closehour ); >+ } >+ else { >+ my $sth3 = $dbh->prepare('UPDATE openinghours set openhour = ?, closehour = ? WHERE branchcode = ? AND weekcode = ? '); >+ >+ $sth3->execute( $openhour, $closehour, $branchcode, $weekcode ); >+ } >+} >+ >+sub getOpeningHours { >+ my ($branchcode) = @_; >+ my $dbh = C4::Context->dbh; >+ my $query = "SELECT * FROM openinghours "; >+ $query .= "WHERE branchcode = ?" if(defined $branchcode); >+ my $sth = $dbh->prepare($query); >+ >+ my %results; >+ >+ if($branchcode){ >+ $sth->execute($branchcode); >+ while ( my $hours = $sth->fetchrow_hashref ) { >+ $results{ $hours->{'weekcode'} } = $hours; >+ } >+ } >+ else{ >+ $sth->execute(); >+ my @tmp; >+ while ( my $row = $sth->fetchrow_hashref ) { >+ #add a few precalculated fields >+ my $t1 = DateTime::Format::DateParse->parse_datetime( $row->{openhour}); >+ my $t2 = DateTime::Format::DateParse->parse_datetime( $row->{closehour}); >+ $row->{hashopen} = {hour => $t1->hour(), minute => $t1->minute(), second => $t1->second()}; >+ $row->{hashclose} = {hour => $t2->hour(), minute => $t2->minute(), second => $t2->second() }; >+ $row->{totalminutes} = $t1->delta_ms($t2)->delta_minutes(); >+ >+ #build the hash >+ $results{ $row->{'branchcode'} } ||= {}; >+ $results{ $row->{'branchcode'} }->{$row->{'weekcode'}} = $row; >+ } >+ } >+ >+ return \%results; >+} >+ > 1; > > __END__ >diff --git a/C4/Circulation.pm b/C4/Circulation.pm >index 6b700ec..6650fcb 100644 >--- a/C4/Circulation.pm >+++ b/C4/Circulation.pm >@@ -33,6 +33,7 @@ use C4::Dates qw(format_date); > use C4::Accounts; > use C4::ItemCirculationAlertPreference; > use C4::Message; >+use C4::Calendar qw(getOpeningHours); > use C4::Debug; > use C4::Branch; # GetBranches > use C4::Log; # logaction >@@ -91,6 +92,7 @@ BEGIN { > &AnonymiseIssueHistory > &CheckIfIssuedToPatron > &IsItemIssued >+ &CalcDateDue > ); > > # subs to deal with returns >@@ -120,6 +122,7 @@ BEGIN { > &DeleteOfflineOperation > &ProcessOfflineOperation > ); >+ > } > > =head1 NAME >@@ -1729,7 +1732,7 @@ sub AddReturn { > return (0, { BadBarcode => $barcode }); # no barcode means no item or borrower. bail out. > } > my $issue = GetItemIssue($itemnumber); >-# warn Dumper($iteminformation); >+ > if ($issue and $issue->{borrowernumber}) { > $borrower = C4::Members::GetMemberDetails($issue->{borrowernumber}) > or die "Data inconsistency: barcode $barcode (itemnumber:$itemnumber) claims to be issued to non-existant borrowernumber '$issue->{borrowernumber}'\n" >@@ -3228,6 +3231,24 @@ C<$borrower> = Borrower object > C<$isrenewal> = Boolean: is true if we want to calculate the date due for a renewal. Else is false. > > =cut >+sub CapDateDue{ >+ my ( $calcDueDate, $loanlength, $branch) = @_; >+ >+ # for hourly loans, we will limit the due date to close time >+ return $calcDueDate unless ($loanlength->{lengthunit} eq 'hours'); >+ >+# my $now = DateTime->now( time_zone => C4::Context->tz() ); >+ my $branchHours = getOpeningHours(); >+ >+ my $close = $calcDueDate->clone()->truncate( to => 'days'); >+ $close->set($branchHours->{$branch}->{$calcDueDate->local_day_of_week()-1}->{hashclose}); >+ >+ if (DateTime->compare($calcDueDate, $close) > 0){ # we want the document back at close time >+ return $close; >+ } >+ >+ return $calcDueDate; >+} > > sub CalcDateDue { > my ( $startdate, $itemtype, $branch, $borrower, $isrenewal ) = @_; >@@ -3255,13 +3276,17 @@ sub CalcDateDue { > ->truncate( to => 'minute' ); > } > >- >+ my $calendar = Koha::Calendar->new( branchcode => $branch ); > # calculate the datedue as normal > if ( C4::Context->preference('useDaysMode') eq 'Days' ) > { # ignoring calendar > if ( $loanlength->{lengthunit} eq 'hours' ) { >- $datedue->add( hours => $loanlength->{$length_key} ); >- } else { # days >+ if($loanlength->{issuelength} == 24){ >+ $datedue = $calendar->addDate( $datedue, 1); >+ } else { >+ $datedue->add( hours => $loanlength->{issuelength} ); >+ } >+ }else { # days > $datedue->add( days => $loanlength->{$length_key} ); > $datedue->set_hour(23); > $datedue->set_minute(59); >@@ -3274,7 +3299,6 @@ sub CalcDateDue { > else { # days > $dur = DateTime::Duration->new( days => $loanlength->{$length_key}); > } >- my $calendar = Koha::Calendar->new( branchcode => $branch ); > $datedue = $calendar->addDate( $datedue, $dur, $loanlength->{lengthunit} ); > if ($loanlength->{lengthunit} eq 'days') { > $datedue->set_hour(23); >@@ -3311,7 +3335,7 @@ sub CalcDateDue { > } > } > >- return $datedue; >+ return CapDateDue($datedue, $loanlength, $branch); > } > > >@@ -3761,4 +3785,3 @@ __END__ > Koha Development Team <http://koha-community.org/> > > =cut >- >diff --git a/C4/Overdues.pm b/C4/Overdues.pm >index 169b36c..3ed86f0 100644 >--- a/C4/Overdues.pm >+++ b/C4/Overdues.pm >@@ -41,6 +41,7 @@ BEGIN { > # subs to rename (and maybe merge some...) > push @EXPORT, qw( > &CalcFine >+ &_get_chargeable_units > &Getoverdues > &checkoverdues > &NumberNotifyId >@@ -110,8 +111,9 @@ sub Getoverdues { > if ( C4::Context->preference('item-level_itypes') ) { > $statement = " > SELECT issues.*, items.itype as itemtype, items.homebranch, items.barcode >- FROM issues >+ FROM issues > LEFT JOIN items USING (itemnumber) >+join issuingrules on issuingrules.itemtype = items.itype > WHERE date_due < NOW() > "; > } else { >@@ -135,6 +137,11 @@ LEFT JOIN biblioitems USING (biblioitemnumber) > $statement .= ' AND ( TO_DAYS( NOW() )-TO_DAYS( date_due ) ) < ? '; > push @bind_parameters, $params->{'maximumdays'}; > } >+ >+ if($params->{'shortrun'}){ >+ $statement .= " and issuingrules.lengthunit in ('hours') " ; >+ } >+ > $statement .= 'ORDER BY borrowernumber'; > my $sth = $dbh->prepare( $statement ); > $sth->execute( @bind_parameters ); >@@ -240,7 +247,7 @@ or "Final Notice". But CalcFine never defined any value. > =cut > > sub CalcFine { >- my ( $item, $bortype, $branchcode, $due_dt, $end_date ) = @_; >+ my ( $item, $bortype, $branchcode, $due_dt, $end_date, $openingHours ) = @_; > my $start_date = $due_dt->clone(); > # get issuingrules (fines part will be used) > my $itemtype = $item->{itemtype} || $item->{itype}; >@@ -248,7 +255,7 @@ sub CalcFine { > my $fine_unit = $data->{lengthunit}; > $fine_unit ||= 'days'; > >- my $chargeable_units = _get_chargeable_units($fine_unit, $start_date, $end_date, $branchcode); >+ my $chargeable_units = _get_chargeable_units($fine_unit, $start_date, $end_date, $branchcode, $openingHours); > my $units_minus_grace = $chargeable_units - $data->{firstremind}; > my $amount = 0; > if ($data->{'chargeperiod'} && ($units_minus_grace > 0) ) { >@@ -282,25 +289,29 @@ C<$branchcode> is the branch whose calendar to use for finding holidays. > =cut > > sub _get_chargeable_units { >- my ($unit, $dt1, $dt2, $branchcode) = @_; >+ my ($unit, $dt1, $dt2, $branchcode, $openingHours) = @_; > my $charge_units = 0; > my $charge_duration; > if ($unit eq 'hours') { > if(C4::Context->preference('finesCalendar') eq 'noFinesWhenClosed') { >- my $calendar = Koha::Calendar->new( branchcode => $branchcode ); >- $charge_duration = $calendar->hours_between( $dt1, $dt2 ); >+ if (!defined $openingHours->{$branchcode}{'Calendar'}){ >+ $openingHours->{$branchcode}{'Calendar'} = Koha::Calendar->new( branchcode => $branchcode ); >+ } >+ $charge_duration = $openingHours->{$branchcode}{'Calendar'}->hours_between( $dt1, $dt2, $openingHours->{$branchcode} ); > } else { > $charge_duration = $dt2->delta_ms( $dt1 ); > } >- if($charge_duration->in_units('hours') == 0 && $charge_duration->in_units('seconds') > 0){ >+ if($charge_duration->in_units($unit) == 0 && $charge_duration->in_units('seconds') > 0){ > return 1; > } >- return $charge_duration->in_units('hours'); >+ return $charge_duration->in_units($unit); > } > else { # days > if(C4::Context->preference('finesCalendar') eq 'noFinesWhenClosed') { >- my $calendar = Koha::Calendar->new( branchcode => $branchcode ); >- $charge_duration = $calendar->days_between( $dt1, $dt2 ); >+ if (!defined $openingHours->{$branchcode}{'Calendar'}){ >+ $openingHours->{$branchcode}{'Calendar'} = Koha::Calendar->new( branchcode => $branchcode ); >+ } >+ $charge_duration = $openingHours->{$branchcode}{'Calendar'}->days_between( $dt1, $dt2, $openingHours->{$branchcode} ); > } else { > $charge_duration = $dt2->delta_days( $dt1 ); > } >diff --git a/Koha/Calendar.pm b/Koha/Calendar.pm >index 276c7ce..7ef78d3 100644 >--- a/Koha/Calendar.pm >+++ b/Koha/Calendar.pm >@@ -271,7 +271,7 @@ sub days_between { > my $self = shift; > my $start_dt = shift; > my $end_dt = shift; >- >+ my $branchHours = shift; > if ( $start_dt->compare($end_dt) > 0 ) { > # swap dates > my $int_dt = $end_dt; >@@ -279,47 +279,79 @@ sub days_between { > $start_dt = $int_dt; > } > >- >- # start and end should not be closed days > my $days = $start_dt->delta_days($end_dt)->delta_days; >- for (my $dt = $start_dt->clone(); >- $dt <= $end_dt; >- $dt->add(days => 1) >- ) { >- if ($self->is_holiday($dt)) { >- $days--; >+ # start and end should not be closed days >+ while ($start_dt <= $end_dt) { >+ if (defined $branchHours->{holidays}{$start_dt->ymd()}) { >+ $days-- if $branchHours->{holidays}{$start_dt->ymd()}; >+ } else { >+ $branchHours->{holidays}{$start_dt->ymd()} = $self->is_holiday($start_dt); >+ $days-- if $branchHours->{holidays}{$start_dt->ymd()}; > } >+ $start_dt->add(days => 1); > } > return DateTime::Duration->new( days => $days ); > > } > > sub hours_between { >- my ($self, $start_date, $end_date) = @_; >+ my ($self, $start_date, $end_date, $branchHours) = @_; >+ > my $start_dt = $start_date->clone(); > my $end_dt = $end_date->clone(); >- my $duration = $end_dt->delta_ms($start_dt); >+ > $start_dt->truncate( to => 'day' ); > $end_dt->truncate( to => 'day' ); >- # NB this is a kludge in that it assumes all days are 24 hours >- # However for hourly loans the logic should be expanded to >- # take into account open/close times then it would be a duration >- # of library open hours >- my $skipped_days = 0; >- for (my $dt = $start_dt->clone(); >- $dt <= $end_dt; >- $dt->add(days => 1) >- ) { >- if ($self->is_holiday($dt)) { >- ++$skipped_days; >+ >+ if (defined $branchHours->{0}){ # We were given the branch's opening hours. >+ my $totalMinutes = 0; >+ for (my $dt = $start_dt->clone(); $dt <= $end_dt; $dt->add(days => 1)) { >+ # hash to keep track of holidays >+ if (defined $branchHours->{holidays}{$dt->ymd()}) { >+ next if $branchHours->{holidays}{$dt->ymd()}; >+ } else { >+ $branchHours->{holidays}{$dt->ymd()} = $self->is_holiday($dt); >+ next if ($self->is_holiday($dt)); >+ } >+ >+ if(DateTime->compare($dt,$start_dt) == 0){ # from location till close time >+ #create a timestamp for today's close time using the current day object with the branchHours's hours. >+ my $close = $dt->clone()->set($branchHours->{$dt->local_day_of_week()-1}->{hashclose}); >+ >+ if(DateTime->compare($end_date, $close) < 0){ # we are still the same day, before closing time >+ $totalMinutes += $start_date->delta_ms($end_date)->delta_minutes(); >+ } elsif(DateTime->compare($start_date, $close) < 0) { # we started (issue) before closing hour >+ $totalMinutes += $start_date->delta_ms($close)->delta_minutes(); >+ } >+ } >+ elsif(DateTime->compare($dt, $end_dt) == 0){ # from open time till now >+ my $open = $dt->clone()->set($branchHours->{$dt->local_day_of_week()-1}->{hashopen}); >+ if(DateTime->compare($end_date, $open) > 0) { # we end (return issue) after opening hour >+ $totalMinutes += $end_date->delta_ms($open)->delta_minutes(); >+ } >+ } >+ else{ >+ $totalMinutes += $branchHours->{$dt->local_day_of_week()- 1}->{totalminutes}; >+ } > } >+ >+ return DateTime::Duration->new( minutes => $totalMinutes); > } >- if ($skipped_days) { >- $duration->subtract_duration(DateTime::Duration->new( hours => 24 * $skipped_days)); >+ else{ >+ my $duration = $end_dt->delta_ms($start_dt); >+ my $skipped_days = 0; >+ while ($start_dt <= $end_dt){ >+ if ($self->is_holiday($start_dt)) { >+ ++$skipped_days; >+ } >+ $start_dt->add(days => 1); >+ } >+ if ($skipped_days) { >+ $duration->subtract_duration(DateTime::Duration->new( hours => 24 * $skipped_days)); >+ } >+ return $duration; > } > >- return $duration; >- > } > > sub set_daysmode { >diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl >index c68ba51..5bbe3c3 100755 >--- a/installer/data/mysql/updatedatabase.pl >+++ b/installer/data/mysql/updatedatabase.pl >@@ -8560,6 +8560,40 @@ if ( CheckVersion($DBversion) ) { > SetVersion($DBversion); > } > >+$DBversion ="XXX"; >+if( CheckVersion($DBversion) ){ >+ $dbh->do(q{ >+ CREATE TABLE IF NOT EXISTS openinghours ( >+ branchcode varchar(10) NOT NULL, >+ weekcode int(2) NOT NULL, >+ openhour time NOT NULL, >+ closehour time NOT NULL, >+ PRIMARY KEY (branchcode,weekcode) >+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8; >+ }); >+ $dbh->do(q{ >+ ALTER TABLE openinghours >+ ADD CONSTRAINT openinghours_ibfk_1 >+ FOREIGN KEY (branchcode) REFERENCES >+ branches(branchcode); >+ }); >+ >+ my $sth = $dbh->prepare("SELECT branchcode FROM branches"); >+ $sth->execute; >+ my @branches; >+ my $weekcode; >+ while (@branches = $sth->fetchrow_array()){ >+ for ($weekcode = 0; $weekcode <= 6; $weekcode++) { >+ my $count = $dbh->selectrow_array('SELECT count(*) FROM openinghours WHERE branchcode=? and weekcode=?',undef, $branches[0], $weekcode); >+ if ($count==0){ >+ $dbh->do('INSERT INTO openinghours (branchcode, weekcode, openhour, closehour) VALUES (?, ?, ? ,?)', undef, $branches[0], $weekcode, '09:00:00', '17:00:00') or die $dbh->errstr; >+ } >+ } >+ } >+ print "Calendar opening hours set.\n"; >+ SetVersion($DBversion); >+} >+ > =head1 FUNCTIONS > > =head2 TableExists($table) >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt >index f29944d..a8cc2ba 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt >@@ -6,6 +6,10 @@ > [% INCLUDE 'datatables.inc' %] > <script type="text/javascript"> > //<![CDATA[ >+ >+ var MSG_HOURS_INCOHERENT = _("Opening hours could not be greater than the closing hours"); >+ >+ [% IF (dateformat == 'metric') %]dt_add_type_uk_date();[% END %] > var weekdays = new Array(_("Sundays"),_("Mondays"),_("Tuesdays"),_("Wednesdays"),_("Thursdays"),_("Fridays"),_("Saturdays")); > > /* Creates all the structures to deal with all different kinds of holidays */ >@@ -36,6 +40,39 @@ > formObject.submit(); > } > >+ function checkschedule() { >+ var verify = 0; >+ for (var i=0; i<7 ; i++) { >+ var tabopenhour = document.getElementById('openhour_' + i); >+ var selectValueoh = tabopenhour.options[tabopenhour.selectedIndex].value; >+ >+ var tabopenmin = document.getElementById('openmin_' + i); >+ var selectValueom = tabopenmin.options[tabopenmin.selectedIndex].value; >+ >+ var tabclosehour = document.getElementById('closehour_' + i); >+ var selectValuech = tabclosehour.options[tabclosehour.selectedIndex].value; >+ >+ var tabclosemin = document.getElementById('closemin_' + i); >+ var selectValuecm = tabclosemin.options[tabclosemin.selectedIndex].value; >+ >+ if (selectValueoh == selectValuech) { >+ if (selectValueom > selectValuecm) { >+ alert(MSG_HOURS_INCOHERENT); >+ verify = 1; >+ break; >+ } >+ } else if (selectValueoh > selectValuech) { >+ alert(MSG_HOURS_INCOHERENT); >+ verify = 1; >+ break; >+ } >+ } >+ >+ if (verify != 0) { >+ return false; >+ } >+ return true; >+ } > // This function shows the "Show Holiday" panel // > function showHoliday (exceptionPosibility, dayName, day, month, year, weekDay, title, description, holidayType) { > $("#newHoliday").slideUp("fast"); >@@ -447,7 +484,7 @@ td.repeatableyearly a.ui-state-default { background: #FFCC66 none; color : Bl > </tr> > [% END %] > </tbody> >-</table> >+ > [% END %] > > [% IF ( WEEK_DAYS_LOOP ) %] >@@ -523,6 +560,110 @@ td.repeatableyearly a.ui-state-default { background: #FFCC66 none; color : Bl > </tbody> > </table> > [% END %] >+ >+<h3>Opening hours</h3> >+<form name="formhour" method="post" action="/cgi-bin/koha/tools/holidays.pl" onSubmit="return checkschedule()"> >+<table> >+<thead> >+<tr> >+ <th class="repeatableweekly">Day of week</th> >+ <th class="repeatableweekly">Opening hours</th> >+ <th class="repeatableweekly">Closing hours</th> >+</tr> >+</thead> >+<tbody> >+ [% FOR day IN tabdays %] >+ <tr> >+ <td>[% IF ( day == 0 ) %]Sunday[% END %] >+ [% IF ( day == 1 ) %]Monday[% END %] >+ [% IF ( day == 2 ) %]Tuesday[% END %] >+ [% IF ( day == 3 ) %]Wednesday[% END %] >+ [% IF ( day == 4 ) %]Thursday[% END %] >+ [% IF ( day == 5 ) %]Friday[% END %] >+ [% IF ( day == 6 ) %]Saturday[% END %] >+ </td> >+ <td> >+ <select id="openhour_[% day %]" name="openhour_[% day %]"> >+ [% FOR hour IN hours %] >+ [% flag1 = 0 %] >+ [% FOREACH tabschedul IN tabschedule %] >+ [% IF (day == tabschedul.dayb ) %] >+ [% IF (hour == tabschedul.openhourb) %] >+ <option value="[% tabschedul.openhourb %]" selected="selected">[% hour %]</option> >+ [% flag1 = 1 %] >+ [% END %] >+ [% END %] >+ [% END %] >+ >+ [% IF (flag1 == 0) %] >+ <option value="[% hour %]">[% hour %]</option> >+ [% END %] >+ [% END %] >+ </select>h >+ <select id="openmin_[% day %]" name="openmin_[% day %]"> >+ [% FOR minute IN minutes %] >+ [% flag2 = 0 %] >+ [% FOREACH tabschedul IN tabschedule %] >+ [% IF (day == tabschedul.dayb ) %] >+ [% IF (minute == tabschedul.openminb) %] >+ <option value="[% tabschedul.openminb %]" selected="selected">[% minute %]</option> >+ [% flag2 = 1 %] >+ [% END %] >+ [% END %] >+ [% END %] >+ >+ [% IF (flag2 == 0) %] >+ <option value="[% minute %]">[% minute %]</option> >+ [% END %] >+ [% END %] >+ </select>min >+ </td> >+ <td> >+ <select id="closehour_[% day %]" name="closehour_[% day %]"> >+ [% FOR hour IN hours %] >+ [% flag3 = 0 %] >+ [% FOREACH tabschedul IN tabschedule %] >+ [% IF (day == tabschedul.dayb ) %] >+ [% IF (hour == tabschedul.closehourb) %] >+ <option value="[% tabschedul.closehourb %]" selected="selected">[% hour %]</option> >+ [% flag3 = 1 %] >+ [% END %] >+ [% END %] >+ [% END %] >+ >+ [% IF (flag3 == 0) %] >+ <option value="[% hour %]">[% hour %]</option> >+ [% END %] >+ [% END %] >+ </select>h >+ <select id="closemin_[% day %]" name="closemin_[% day %]"> >+ [% FOR minute IN minutes %] >+ [% flag4 = 0 %] >+ [% FOREACH tabschedul IN tabschedule %] >+ [% IF (day == tabschedul.dayb ) %] >+ [% IF (minute == tabschedul.closeminb) %] >+ <option value="[% tabschedul.closeminb %]" selected="selected">[% minute %]</option> >+ [% flag4 = 1 %] >+ [% END %] >+ [% END %] >+ [% END %] >+ >+ [% IF (flag4 == 0) %] >+ <option value="[% minute %]">[% minute %]</option> >+ [% END %] >+ [% END %] >+ </select>min >+ <input type="hidden" name="confirm" value="1" /> >+ <input type="hidden" name="weekcode_[% day %]" value="[% day %]" /> >+ <input type="hidden" name="branch" value="[% branch %]" /> >+ </td> >+ </tr> >+ [% END %] >+ <tr><td colspan=3 align="center"><input type="submit" name="submit" value="Save" /></td></tr> >+</tbody> >+</table> >+</form> >+ > </div> > </div> > </div> >diff --git a/misc/cronjobs/fines.pl b/misc/cronjobs/fines.pl >index 02bde14..2e7391e 100755 >--- a/misc/cronjobs/fines.pl >+++ b/misc/cronjobs/fines.pl >@@ -38,17 +38,20 @@ use File::Spec; > > use Koha::Calendar; > use Koha::DateUtils; >+use C4::Calendar qw(getOpeningHours); > > my $help; > my $verbose; > my $output_dir; > my $log; >+my $shortrun; > > GetOptions( > 'h|help' => \$help, > 'v|verbose' => \$verbose, > 'l|log' => \$log, > 'o|out:s' => \$output_dir, >+ 's|short' => \$shortrun, > ); > my $usage = << 'ENDUSAGE'; > >@@ -62,6 +65,7 @@ This script has the following parameters : > -l --log: log the output to a file (optional if the -o parameter is given) > -o --out: ouput directory for logs (defaults to env or /tmp if !exist) > -v --verbose >+ -s --short: only verifies the short duration borrowing (hourly) > > ENDUSAGE > >@@ -86,6 +90,8 @@ if ($log or $output_dir) { > $filename = get_filename($output_dir); > } > >+my $openingHours = getOpeningHours(); >+ > my $fh; > if ($filename) { > open $fh, '>>', $filename or croak "Cannot write file $filename: $!"; >@@ -93,11 +99,12 @@ if ($filename) { > print {$fh} "\n"; > } > my $counted = 0; >-my $overdues = Getoverdues(); >+my $overdues = Getoverdues( {shortrun => $shortrun}); >+use Data::Dumper; >+ > for my $overdue ( @{$overdues} ) { > if ( !defined $overdue->{borrowernumber} ) { >- carp >-"ERROR in Getoverdues : issues.borrowernumber IS NULL. Repair 'issues' table now! Skipping record.\n"; >+ carp "ERROR in Getoverdues : issues.borrowernumber IS NULL. Repair 'issues' table now! Skipping record.\n"; > next; > } > my $borrower = BorType( $overdue->{borrowernumber} ); >@@ -117,9 +124,7 @@ for my $overdue ( @{$overdues} ) { > } > ++$counted; > >- my ( $amount, $type, $unitcounttotal ) = >- CalcFine( $overdue, $borrower->{categorycode}, >- $branchcode, $datedue, $today ); >+ my ( $amount, $type, $unitcounttotal ) = CalcFine( $overdue, $borrower->{categorycode}, $branchcode, $datedue, $today, $openingHours ); > $type ||= q{}; > > # Don't update the fine if today is a holiday. >diff --git a/t/Calendar1.t b/t/Calendar1.t >new file mode 100755 >index 0000000..0d49972 >--- /dev/null >+++ b/t/Calendar1.t >@@ -0,0 +1,333 @@ >+#!/usr/bin/env perl >+ >+use strict; >+use warnings; >+use Data::Dumper; >+use DateTime; >+use DateTime::Duration; >+use Test::More tests => 13; >+use Test::MockModule; >+use DBD::Mock; >+use Koha::DateUtils; >+use C4::Calendar qw(getOpeningHours); >+use C4::Circulation qw(CalcDateDue); >+use C4::Overdues qw(_get_chargeable_units); >+ >+BEGIN { >+ die "DBD::Mock v$DBD::Mock::VERSION is too old. This test requires v1.45 or higher.", 33 >+ unless $DBD::Mock::VERSION >= 1.45; >+ >+ use_ok('Koha::Calendar'); >+ use_ok('C4::Calendar'); >+ use_ok('C4::Circulation'); >+ use_ok('C4::Overdues'); >+} >+ >+my $module_context = new Test::MockModule('C4::Context'); >+$module_context->mock( >+ '_new_dbh', >+ sub { >+ my $dbh = DBI->connect( 'DBI:Mock:', '', '' ) >+ || die "Cannot create handle: $DBI::errstr\n"; >+ return $dbh; >+ } >+); >+ >+# Initialize the global $dbh variable >+my $dbh = C4::Context->dbh(); >+ >+{ #C4::Calendar >+ my $sessionCal = DBD::Mock::Session->new('sessionCal' => ( >+ { #Opening hours by branch >+ statement => "SELECT * FROM openinghours WHERE branchcode = ?", >+ bound_params => ['BIB'], >+ results => [ >+ ['branchcode', 'weekcode', 'openhour', 'closehour'], >+ ['BIB', 0, '09:00:00', '17:00:00'], >+ ['BIB', 1, '09:00:00', '17:00:00'], >+ ['BIB', 2, '09:00:00', '17:00:00'], >+ ['BIB', 3, '09:00:00', '17:00:00'], >+ ['BIB', 4, '09:00:00', '17:00:00'], >+ ['BIB', 5, '09:00:00', '17:00:00'], >+ ['BIB', 6, '09:00:00', '17:00:00'] >+ ] >+ } >+ )); >+ >+ $dbh->{ mock_session } = $sessionCal; >+ >+ print "\nTesting C4::Calendar\n"; >+ can_ok('C4::Calendar', ('getOpeningHours')); >+ can_ok('C4::Calendar', ('setOpeningHours')); >+ getOpeningHours('BIB'); >+} >+ >+print "\nTesting C4::Circulation\n"; >+{ #C4::Circulation : Calendar Mode >+ my $sessionCircCal = DBD::Mock::Session->new('sessionCircCal' => ( >+ # Mock queries for test 7 >+ { >+ statement => qr/\s*SELECT issuelength, lengthunit, renewalperiod/, >+ results => [ >+ [ 'issuelength', 'lengthunit', 'renewalperiod' ], >+ [ 5, 'hours' , 0 ] >+ ] >+ }, >+ { >+ statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL', >+ results => DBD::Mock->NULL_RESULTSET >+ }, >+ { >+ statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL', >+ results => [ >+ ['day', 'month'], >+ [24,6] >+ ] >+ }, >+ { >+ statement => 'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1', >+ results => DBD::Mock->NULL_RESULTSET >+ }, >+ { >+ statement => 'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0', >+ results => DBD::Mock->NULL_RESULTSET >+ }, >+ { #GetIssuingRules called in GetHardDueDate >+ statement => qr/select \* from issuingrules/, >+ results => [ >+ ['hardduedate', 'hardduedatecompare'], >+ [undef,-1] >+ ] >+ }, >+ { #Opening hours >+ statement => 'SELECT * FROM openinghours ', >+ results => [ >+ ['branchcode', 'weekcode', 'openhour', 'closehour'], >+ ['BIB', 0, '09:00:00', '17:00:00'], >+ ['BIB', 1, '09:00:00', '17:00:00'], >+ ['BIB', 2, '09:00:00', '17:00:00'], >+ ['BIB', 3, '09:00:00', '17:00:00'], >+ ['BIB', 4, '09:00:00', '17:00:00'], >+ ['BIB', 5, '09:00:00', '17:00:00'], >+ ['BIB', 6, '09:00:00', '17:00:00'] >+ ] >+ }, >+ # Mock Queries for test 8 >+ { >+ statement => qr/\s*SELECT issuelength, lengthunit, renewalperiod/, >+ results => [ >+ [ 'issuelength', 'lengthunit', 'renewalperiod' ], >+ [ 1, 'days' , 0 ] >+ ] >+ }, >+ { >+ statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL', >+ results => DBD::Mock->NULL_RESULTSET >+ }, >+ { >+ statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL', >+ results => [ >+ ['day', 'month'], >+ [24,6] >+ ] >+ }, >+ { #GetIssuingRules called in GetHardDueDate >+ statement => qr/select \* from issuingrules/, >+ results => [ >+ ['hardduedate', 'hardduedatecompare'], >+ [undef,-1] >+ ] >+ }, >+ # Mock queries for test 9 >+ { >+ statement => qr/\s*SELECT issuelength, lengthunit, renewalperiod/, >+ results => [ >+ [ 'issuelength', 'lengthunit', 'renewalperiod' ], >+ [ 5, 'days' , 0 ] >+ ] >+ }, >+ { >+ statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL', >+ results => DBD::Mock->NULL_RESULTSET >+ }, >+ { >+ statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL', >+ results => [ >+ ['day', 'month'], >+ [24,6] >+ ] >+ }, >+ { #GetIssuingRules called in GetHardDueDate >+ statement => qr/select \* from issuingrules/, >+ results => [ >+ ['hardduedate', 'hardduedatecompare'], >+ [undef,-1] >+ ] >+ } >+ )); >+ $dbh->{ mock_session } = $sessionCircCal; >+ >+ $module_context->mock('preference',sub {return 'Calendar';}); >+ print " useDaysMode set to 'Calendar'\n"; >+ >+ #7 Testing 5 hours loan >+ is(CalcDateDue(dt_from_string('2014-06-23T14:00:00', 'iso'), 0, 'BIB',{categorycode => 0, dateexpiry => '2020'}, 0), dt_from_string('2014-06-23T17:00:00', 'iso'), "Testing hourly loans. Due at close time."); >+ #8 Testing single day loan >+ is(CalcDateDue(dt_from_string('2014-06-23T12:00:00', 'iso'), 0, 'BIB',{categorycode => 0, dateexpiry => '2020'}, 0), dt_from_string('2014-06-25T23:59:00', 'iso'), "Testing single day loan due the day after the holiday."); >+ #9 Testing 5 days loan >+ is(CalcDateDue(dt_from_string('2014-06-23T12:00:00', 'iso'), 0, 'BIB',{categorycode => 0, dateexpiry => '2020'}, 0), dt_from_string('2014-06-29T23:59:00', 'iso'), "Testing 5 days loan. Loan period is extended by 1 because of the holiday."); >+ >+ #C4::Circulation : DateDue Mode >+ >+ my $sessionCircDate = DBD::Mock::Session->new('sessionCircDate' => ( >+ # Mock queries for test 10 >+ { >+ statement => qr/\s*SELECT issuelength, lengthunit, renewalperiod/, >+ results => [ >+ [ 'issuelength', 'lengthunit', 'renewalperiod' ], >+ [ 5, 'hours' , 0 ] >+ ] >+ }, >+ { >+ statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL', >+ results => DBD::Mock->NULL_RESULTSET >+ }, >+ { >+ statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL', >+ results => [ >+ ['day', 'month'], >+ [24,6] >+ ] >+ }, >+ { #GetIssuingRules called in GetHardDueDate >+ statement => qr/select \* from issuingrules/, >+ results => [ >+ ['hardduedate', 'hardduedatecompare'], >+ [undef,-1] >+ ] >+ }, >+ { #Opening hours >+ statement => 'SELECT * FROM openinghours ', >+ results => [ >+ ['branchcode', 'weekcode', 'openhour', 'closehour'], >+ ['BIB', 0, '09:00:00', '17:00:00'], >+ ['BIB', 1, '09:00:00', '17:00:00'], >+ ['BIB', 2, '09:00:00', '17:00:00'], >+ ['BIB', 3, '09:00:00', '17:00:00'], >+ ['BIB', 4, '09:00:00', '17:00:00'], >+ ['BIB', 5, '09:00:00', '17:00:00'], >+ ['BIB', 6, '09:00:00', '17:00:00'] >+ ] >+ }, >+ # Mock Queries for test 11 >+ { >+ statement => qr/\s*SELECT issuelength, lengthunit, renewalperiod/, >+ results => [ >+ [ 'issuelength', 'lengthunit', 'renewalperiod' ], >+ [ 24, 'hours' , 0 ] >+ ] >+ }, >+ { >+ statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL', >+ results => DBD::Mock->NULL_RESULTSET >+ }, >+ { >+ statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL', >+ results => [ >+ ['day', 'month'], >+ [24,6] >+ ] >+ }, >+ { #GetIssuingRules called in GetHardDueDate >+ statement => qr/select \* from issuingrules/, >+ results => [ >+ ['hardduedate', 'hardduedatecompare'], >+ [undef,-1] >+ ] >+ }, >+ { #Opening hours >+ statement => 'SELECT * FROM openinghours ', >+ results => [ >+ ['branchcode', 'weekcode', 'openhour', 'closehour'], >+ ['BIB', 0, '09:00:00', '17:00:00'], >+ ['BIB', 1, '09:00:00', '17:00:00'], >+ ['BIB', 2, '09:00:00', '17:00:00'], >+ ['BIB', 3, '09:00:00', '17:00:00'], >+ ['BIB', 4, '09:00:00', '17:00:00'], >+ ['BIB', 5, '09:00:00', '17:00:00'], >+ ['BIB', 6, '09:00:00', '17:00:00'] >+ ] >+ }, >+ # Mock queries for test 12 >+ { >+ statement => qr/\s*SELECT issuelength, lengthunit, renewalperiod/, >+ results => [ >+ [ 'issuelength', 'lengthunit', 'renewalperiod' ], >+ [ 5, 'days' , 0 ] >+ ] >+ }, >+ { >+ statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL', >+ results => DBD::Mock->NULL_RESULTSET >+ }, >+ { >+ statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL', >+ results => [ >+ ['day', 'month'], >+ [24,6] >+ ] >+ }, >+ { #GetIssuingRules called in GetHardDueDate >+ statement => qr/select \* from issuingrules/, >+ results => [ >+ ['hardduedate', 'hardduedatecompare'], >+ [undef,-1] >+ ] >+ } >+ )); >+ $module_context->mock('preference',sub {return 'DateDue';}); >+ print " useDaysMode set to 'DateDue'\n"; >+ >+ $dbh->{ mock_session } = $sessionCircDate; >+ >+ #10 Testing 5 hours loan >+ is(CalcDateDue(dt_from_string('2014-06-23T14:00:00', 'iso'), 0, 'BIB',{categorycode => 0, dateexpiry => '2020'}, 0), dt_from_string('2014-06-23T17:00:00', 'iso'), "Testing hourly loans. Due at close time."); >+ #11 Testing single day loan >+ is(CalcDateDue(dt_from_string('2014-06-23T12:00:00', 'iso'), 0, 'BIB',{categorycode => 0, dateexpiry => '2020'}, 0), dt_from_string('2014-06-25T10:00:00', 'iso'), "Testing single day loan due the day after the holiday."); >+ #12 Testing 5 days loan >+ is(CalcDateDue(dt_from_string('2014-06-23T12:00:00', 'iso'), 0, 'BIB',{categorycode => 0, dateexpiry => '2020'}, 0), dt_from_string('2014-06-28T23:59:00', 'iso'), "Testing 5 days loan. Unaffected by the single day holiday."); >+} >+ >+{ #C4::Overdues >+ print "\nTesting C4::Overdues\n"; >+ $module_context->mock('preference',sub {return 'noFinesWhenClosed';}); >+ print " finesCalendar syspref set to 'noFinesWhenClosed'\n"; >+ my $sessionOver = DBD::Mock::Session->new('sessionOver' =>( >+ { #Opening hours >+ statement => 'SELECT * FROM openinghours ', >+ results => [ >+ ['branchcode', 'weekcode', 'openhour', 'closehour'], >+ ['BIB', 0, '09:00:00', '17:00:00'], >+ ['BIB', 1, '09:00:00', '17:00:00'], >+ ['BIB', 2, '09:00:00', '17:00:00'], >+ ['BIB', 3, '09:00:00', '17:00:00'], >+ ['BIB', 4, '09:00:00', '17:00:00'], >+ ['BIB', 5, '09:00:00', '17:00:00'], >+ ['BIB', 6, '09:00:00', '17:00:00'] >+ ] >+ }, >+ { >+ statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL', >+ results => DBD::Mock->NULL_RESULTSET >+ }, >+ { >+ statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL', >+ results => [ >+ ['day', 'month'], >+ [24,6] >+ ] >+ } >+ )); >+ $dbh->{ mock_session } = $sessionOver; >+ is(_get_chargeable_units('hours', dt_from_string('2014-06-23T12:00:00', 'iso'), dt_from_string('2014-06-25T10:00:00', 'iso'), 'BIB', getOpeningHours()), 6, "Test if _get_chargeable_units takes opening hours and holidays into account."); >+} >diff --git a/tools/holidays.pl b/tools/holidays.pl >index 376de5f..9b4999b 100755 >--- a/tools/holidays.pl >+++ b/tools/holidays.pl >@@ -25,7 +25,9 @@ use C4::Auth; > use C4::Output; > > use C4::Branch; # GetBranches >-use C4::Calendar; >+use C4::Calendar qw/setOpeningHours getOpeningHours/; >+ >+use C4::Dates; > > my $input = new CGI; > >@@ -81,6 +83,28 @@ for my $thisbranch ( > # branches calculated - put branch codes in a single string so they can be passed in a form > my $branchcodes = join '|', keys %{$branches}; > >+ >+# Get opening hours >+ >+my $j; >+for ($j=0; $j<7; $j++) { >+ my $openhour = $input->param('openhour_'.$j); >+ my $openmin = $input->param('openmin_'.$j); >+ my $closehour = $input->param('closehour_'.$j); >+ my $closemin = $input->param('closemin_'.$j); >+ my $weekcode = $input->param('weekcode_'.$j); >+ >+ my $confirmhour = $input->param('confirm'); >+ if ($confirmhour) { >+ my $openh = $openhour; >+ $openh .= ":".$openmin.":00"; >+ my $closeh = $closehour; >+ $closeh .= ":".$closemin.":00"; >+ >+ setOpeningHours($branch, $weekcode, $openh, $closeh); >+ } >+} >+ > # Get all the holidays > > my $calendar = C4::Calendar->new(branchcode => $branch); >@@ -146,6 +170,42 @@ foreach my $yearMonthDay (keys %$single_holidays) { > push @holidays, \%holiday; > } > >+my $tabhour = getOpeningHours($branch); >+my $openhourbranch; >+my $openminbranch; >+my $closehourbranch; >+my $closeminbranch; >+my @tabschedule; >+foreach my $schedule (keys %$tabhour) { >+ my $hourop = $tabhour->{$schedule}->{'openhour'}; >+ my $closeop = $tabhour->{$schedule}->{'closehour'}; >+ my %row; >+ >+ my @tab1 = split(/:/, $hourop); >+ $openhourbranch = $tab1[0]; >+ $openminbranch = $tab1[1]; >+ >+ my @tab2 = split(/:/, $closeop); >+ $closehourbranch = $tab2[0]; >+ $closeminbranch = $tab2[1]; >+ >+ %row = (dayb => $tabhour->{$schedule}->{'weekcode'}, >+ openhourb => $openhourbranch, >+ openminb => $openminbranch, >+ closehourb => $closehourbranch, >+ closeminb => $closeminbranch); >+ push @tabschedule, \%row; >+} >+ >+my @hours; >+my @minutes = ('00','15','30','45'); >+my $i; >+for ($i=0; $i<=23; $i++) { >+ $hours[$i] = ($i<10) ? "0".$i:$i; >+} >+ >+my @tabdays = ('0','1','2','3','4','5','6'); >+ > $template->param( > WEEK_DAYS_LOOP => \@week_days, > branchloop => \@branchloop, >@@ -158,6 +218,10 @@ $template->param( > branch => $branch, > branchname => $branchname, > branch => $branch, >+ hours => \@hours, >+ minutes => \@minutes, >+ tabdays => \@tabdays, >+ tabschedule => \@tabschedule, > ); > > # Shows the template with the real values replaced >-- >1.7.9.5
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 8133
:
19326
|
19494
|
19740
|
29336
|
31973
|
32176
|
32327
|
32985
|
32986
|
32990
|
32991