1 package Koha
::Calendar
;
8 use DateTime
::Duration
;
14 my ( $classname, %options ) = @_;
16 bless $self, $classname;
17 for my $o_name ( keys %options ) {
19 $self->{$o} = $options{$o_name};
21 if ( exists $options{TEST_MODE
} ) {
25 if ( !defined $self->{branchcode
} ) {
26 croak
'No branchcode argument passed to Koha::Calendar->new';
34 my $branch = $self->{branchcode
};
35 my $dbh = C4
::Context
->dbh();
36 my $repeat_sth = $dbh->prepare(
37 'SELECT * from repeatable_holidays WHERE branchcode = ? AND ISNULL(weekday) = ?'
39 $repeat_sth->execute( $branch, 0 );
40 $self->{weekly_closed_days
} = [ 0, 0, 0, 0, 0, 0, 0 ];
41 Readonly
::Scalar
my $sunday => 7;
42 while ( my $tuple = $repeat_sth->fetchrow_hashref ) {
43 $self->{weekly_closed_days
}->[ $tuple->{weekday
} ] = 1;
45 $repeat_sth->execute( $branch, 1 );
46 $self->{day_month_closed_days
} = {};
47 while ( my $tuple = $repeat_sth->fetchrow_hashref ) {
48 $self->{day_month_closed_days
}->{ $tuple->{day
} }->{ $tuple->{month
} } =
51 my $special = $dbh->prepare(
52 'SELECT day, month, year, title, description FROM special_holidays WHERE ( branchcode = ? ) AND (isexception = ?)'
54 $special->execute( $branch, 1 );
56 while ( my ( $day, $month, $year, $title, $description ) =
57 $special->fetchrow ) {
63 time_zone
=> C4
::Context
->tz()
64 )->truncate( to
=> 'day' );
66 $self->{exception_holidays
} =
67 DateTime
::Set
->from_datetimes( dates
=> $dates );
68 $special->execute( $branch, 1 );
70 while ( my ( $day, $month, $year, $title, $description ) =
71 $special->fetchrow ) {
77 time_zone
=> C4
::Context
->tz()
78 )->truncate( to
=> 'day' );
80 $self->{single_holidays
} = DateTime
::Set
->from_datetimes( dates
=> $dates );
81 $self->{days_mode
} = C4
::Context
->preference('useDaysMode');
86 my ( $self, $startdate, $add_duration, $unit ) = @_;
87 my $base_date = $startdate->clone();
88 if ( ref $add_duration ne 'DateTime::Duration' ) {
89 $add_duration = DateTime
::Duration
->new( days
=> $add_duration );
91 $unit ||= q{}; # default days ?
92 my $days_mode = $self->{days_mode
};
93 Readonly
::Scalar
my $return_by_hour => 10;
94 my $day_dur = DateTime
::Duration
->new( days
=> 1 );
95 if ( $add_duration->is_negative() ) {
98 if ( $days_mode eq 'Datedue' ) {
100 my $dt = $base_date + $add_duration;
101 while ( $self->is_holiday($dt) ) {
103 # TODOP if hours set to 10 am
104 $dt->add_duration($day_dur);
105 if ( $unit eq 'hours' ) {
106 $dt->set_hour($return_by_hour); # Staffs specific
110 } elsif ( $days_mode eq 'Calendar' ) {
111 if ( $unit eq 'hours' ) {
112 $base_date->add_duration($add_duration);
113 while ( $self->is_holiday($base_date) ) {
114 $base_date->add_duration($day_dur);
119 my $days = abs $add_duration->in_units('days');
121 $base_date->add_duration($day_dur);
122 if ( $self->is_holiday($base_date) ) {
129 if ( $unit eq 'hours' ) {
130 my $dt = $base_date->clone()->subtract( days
=> 1 );
131 if ( $self->is_holiday($dt) ) {
132 $base_date->set_hour($return_by_hour); # Staffs specific
137 return $base_date + $add_duration;
142 my ( $self, $dt ) = @_;
143 my $dow = $dt->day_of_week;
147 if ( $self->{weekly_closed_days
}->[$dow] == 1 ) {
150 $dt->truncate( to
=> 'days' );
152 my $month = $dt->month;
153 if ( exists $self->{day_month_closed_days
}->{$month}->{$day} ) {
156 if ( $self->{exception_holidays
}->contains($dt) ) {
159 if ( $self->{single_holidays
}->contains($dt) ) {
163 # damn have to go to work after all
169 my $start_dt = shift;
172 # start and end should not be closed days
173 my $duration = $end_dt->delta_days($start_dt);
174 $start_dt->truncate( to
=> 'days' );
175 $end_dt->truncate( to
=> 'days' );
176 while ( DateTime
->compare( $start_dt, $end_dt ) == -1 ) {
177 $start_dt->add( days
=> 1 );
178 if ( $self->is_holiday($start_dt) ) {
179 $duration->subtract( days
=> 1 );
187 my ($self, $start_dt, $end_dt) = @_;
188 my $duration = $end_dt->delta_ms($start_dt);
189 $start_dt->truncate( to
=> 'days' );
190 $end_dt->truncate( to
=> 'days' );
191 # NB this is a kludge in that it assumes all days are 24 hours
192 # However for hourly loans the logic should be expanded to
193 # take into account open/close times then it would be a duration
194 # of library open hours
195 while ( DateTime
->compare( $start_dt, $end_dt ) == -1 ) {
196 $start_dt->add( days
=> 1 );
197 if ( $self->is_holiday($start_dt) ) {
198 $duration->subtract( hours
=> 24 );
207 $self->{weekly_closed_days
} = [ 1, 0, 0, 0, 0, 0, 0 ]; # Sunday only
208 $self->{day_month_closed_days
} = { 6 => { 16 => 1, } };
210 $self->{exception_holidays
} =
211 DateTime
::Set
->from_datetimes( dates
=> $dates );
212 my $special = DateTime
->new(
216 time_zone
=> 'Europe/London',
218 push @
{$dates}, $special;
219 $self->{single_holidays
} = DateTime
::Set
->from_datetimes( dates
=> $dates );
220 $self->{days_mode
} = 'Calendar';
229 Koha::Calendar - Object containing a branches calendar
233 This documentation refers to Koha::Calendar version 0.0.1
239 my $c = Koha::Calender->new( branchcode => 'MAIN' );
240 my $dt = DateTime->now();
243 $open = $c->is_holiday($dt);
244 # when will item be due if loan period = $dur (a DateTime::Duration object)
245 $duedate = $c->addDate($dt,$dur,'days');
250 Implements those features of C4::Calendar needed for Staffs Rolling Loans
254 =head2 new : Create a calendar object
256 my $calendar = Koha::Calendar->new( branchcode => 'MAIN' );
258 The option branchcode is required
263 my $dt = $calendar->addDate($date, $dur, $unit)
265 C<$date> is a DateTime object representing the starting date of the interval.
267 C<$offset> is a DateTime::Duration to add to it
269 C<$unit> is a string value 'days' or 'hours' toflag granularity of duration
271 Currently unit is only used to invoke Staffs return Monday at 10 am rule this
272 parameter will be removed when issuingrules properly cope with that
277 $yesno = $calendar->is_holiday($dt);
279 passed at DateTime object returns 1 if it is a closed day
280 0 if not according to the calendar
284 $duration = $calendar->days_between($start_dt, $end_dt);
286 Passed two dates returns a DateTime::Duration object measuring the length between them
291 Will croak if not passed a branchcode in new
293 =head1 BUGS AND LIMITATIONS
295 This only contains a limited subset of the functionality in C4::Calendar
296 Only enough to support Staffs Rolling loans
300 Colin Campbell colin.campbell@ptfs-europe.com
302 =head1 LICENSE AND COPYRIGHT
304 Copyright (c) 2011 PTFS-Europe Ltd All rights reserved
306 This program is free software: you can redistribute it and/or modify
307 it under the terms of the GNU General Public License as published by
308 the Free Software Foundation, either version 2 of the License, or
309 (at your option) any later version.
311 This program is distributed in the hope that it will be useful,
312 but WITHOUT ANY WARRANTY; without even the implied warranty of
313 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
314 GNU General Public License for more details.
316 You should have received a copy of the GNU General Public License
317 along with this program. If not, see <http://www.gnu.org/licenses/>.