Line 0
Link Here
|
|
|
1 |
package Koha::DiscreteCalendar; |
2 |
|
3 |
# This file is part of Koha. |
4 |
# |
5 |
# Koha is free software; you can redistribute it and/or modify it |
6 |
# under the terms of the GNU General Public License as published by |
7 |
# the Free Software Foundation; either version 3 of the License, or |
8 |
# (at your option) any later version. |
9 |
# |
10 |
# Koha is distributed in the hope that it will be useful, but |
11 |
# WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
# GNU General Public License for more details. |
14 |
# |
15 |
# You should have received a copy of the GNU General Public License |
16 |
# along with Koha; if not, see <http://www.gnu.org/licenses>. |
17 |
|
18 |
#####Sets holiday periods for each branch. Datedues will be extended if branch is closed -TG |
19 |
use strict; |
20 |
use warnings; |
21 |
|
22 |
use CGI qw ( -utf8 ); |
23 |
use Carp; |
24 |
use DateTime; |
25 |
use DateTime::Format::Strptime; |
26 |
|
27 |
use C4::Context; |
28 |
use C4::Output; |
29 |
use Koha::Database; |
30 |
use Koha::DateUtils; |
31 |
|
32 |
sub new { |
33 |
my ( $classname, %options ) = @_; |
34 |
my $self = {}; |
35 |
bless $self, $classname; |
36 |
for my $o_name ( keys %options ) { |
37 |
my $o = lc $o_name; |
38 |
$self->{$o} = $options{$o_name}; |
39 |
} |
40 |
if ( !defined $self->{branchcode} ) { |
41 |
croak 'No branchcode argument passed to Koha::DiscreteCalendar->new'; |
42 |
} |
43 |
$self->_init(); |
44 |
|
45 |
return $self; |
46 |
} |
47 |
|
48 |
sub _init { |
49 |
my $self = shift; |
50 |
$self->{days_mode} = C4::Context->preference('useDaysMode'); |
51 |
#If the branchcode doesn't exist we use the default calendar. |
52 |
my $schema = Koha::Database->new->schema; |
53 |
my $branchcode = $self->{branchcode}; |
54 |
my $dtf = $schema->storage->datetime_parser; |
55 |
my $today = $dtf->format_datetime(DateTime->today); |
56 |
my $rs = $schema->resultset('DiscreteCalendar')->single( |
57 |
{ |
58 |
branchcode => $branchcode, |
59 |
date => $today |
60 |
} |
61 |
); |
62 |
#use default if no calendar is found |
63 |
if (!$rs){ |
64 |
$self->{branchcode} = 'DFLT'; |
65 |
$self->{no_branch_selected} = 1; |
66 |
} |
67 |
|
68 |
} |
69 |
|
70 |
sub getDatesInfo { |
71 |
my $self = shift; |
72 |
my $branchcode = $self->{branchcode}; |
73 |
my @datesInfos =(); |
74 |
my $schema = Koha::Database->new->schema; |
75 |
|
76 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
77 |
{ |
78 |
branchcode => $branchcode |
79 |
}, |
80 |
{ |
81 |
select => [ 'date', { DATE => 'date' } ], |
82 |
as => [qw/ date date /], |
83 |
columns =>[ qw/ holidaytype openhour closehour note/] |
84 |
}, |
85 |
); |
86 |
|
87 |
while (my $date = $rs->next()){ |
88 |
my $outputdate = dt_from_string( $date->date(), 'iso'); |
89 |
$outputdate = output_pref( { dt => $outputdate, dateonly => 1 } ); |
90 |
push @datesInfos, { |
91 |
date => $date->date(), |
92 |
outputdate => $outputdate, |
93 |
holidaytype => $date->holidaytype() , |
94 |
openhour => $date->openhour(), |
95 |
closehour => $date->closehour(), |
96 |
note => $date->note() |
97 |
}; |
98 |
} |
99 |
|
100 |
return @datesInfos; |
101 |
} |
102 |
#This methode will copy everything from a given branch found to the new branch |
103 |
sub add_new_branch { |
104 |
my ($self, $copyBranch, $newBranch) = @_; |
105 |
$copyBranch = 'DFLT' unless $copyBranch; |
106 |
my $schema = Koha::Database->new->schema; |
107 |
|
108 |
my $branch_rs = $schema->resultset('DiscreteCalendar')->search({ |
109 |
branchcode => $copyBranch |
110 |
}); |
111 |
|
112 |
while(my $row = $branch_rs->next()){ |
113 |
$schema->resultset('DiscreteCalendar')->create({ |
114 |
date => $row->date(), |
115 |
branchcode => $newBranch, |
116 |
isopened => $row->isopened(), |
117 |
holidaytype => $row->holidaytype(), |
118 |
openhour => $row->openhour(), |
119 |
closehour => $row->closehour(), |
120 |
}); |
121 |
} |
122 |
|
123 |
} |
124 |
#DiscreteCalendar data transfer object (DTO) |
125 |
sub get_date_info { |
126 |
my ($self, $date) = @_; |
127 |
my $branchcode = $self->{branchcode}; |
128 |
my $schema = Koha::Database->new->schema; |
129 |
my $dtf = $schema->storage->datetime_parser; |
130 |
#String dates for Database usage |
131 |
my $date_string = $dtf->format_datetime($date); |
132 |
|
133 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
134 |
{ |
135 |
branchcode => $branchcode, |
136 |
}, |
137 |
{ |
138 |
select => [ 'date', { DATE => 'date' } ], |
139 |
as => [qw/ date date /], |
140 |
where => \['DATE(?) = date', $date_string ], |
141 |
columns =>[ qw/ branchcode holidaytype openhour closehour note/] |
142 |
}, |
143 |
); |
144 |
my $dateDTO; |
145 |
while (my $date = $rs->next()){ |
146 |
$dateDTO = { |
147 |
date => $date->date(), |
148 |
branchcode => $date->branchcode(), |
149 |
holidaytype => $date->holidaytype() , |
150 |
openhour => $date->openhour(), |
151 |
closehour => $date->closehour(), |
152 |
note => $date->note() |
153 |
}; |
154 |
} |
155 |
|
156 |
return $dateDTO; |
157 |
} |
158 |
|
159 |
|
160 |
sub getMaxDate { |
161 |
my $self = shift; |
162 |
my $branchcode = $self->{branchcode}; |
163 |
my $schema = Koha::Database->new->schema; |
164 |
|
165 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
166 |
{ |
167 |
branchcode => $branchcode |
168 |
}, |
169 |
{ |
170 |
select => [{ MAX => 'date' } ], |
171 |
as => [qw/ max /], |
172 |
} |
173 |
); |
174 |
|
175 |
return $rs->next()->get_column('max'); |
176 |
} |
177 |
|
178 |
sub getMinDate { |
179 |
my $self = shift; |
180 |
my $branchcode = $self->{branchcode}; |
181 |
my $schema = Koha::Database->new->schema; |
182 |
|
183 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
184 |
{ |
185 |
branchcode => $branchcode |
186 |
}, |
187 |
{ |
188 |
select => [{ MIN => 'date' } ], |
189 |
as => [qw/ min /], |
190 |
} |
191 |
); |
192 |
|
193 |
return $rs->next()->get_column('min'); |
194 |
} |
195 |
|
196 |
|
197 |
sub get_unique_holidays { |
198 |
my $self = shift; |
199 |
my $branchcode = $self->{branchcode}; |
200 |
my @single_holidays; |
201 |
my $schema = Koha::Database->new->schema; |
202 |
|
203 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
204 |
{ |
205 |
branchcode => $branchcode, |
206 |
holidaytype => 'E' |
207 |
}, |
208 |
{ |
209 |
select => [{ DATE => 'date' }, 'note' ], |
210 |
as => [qw/ date note/], |
211 |
} |
212 |
); |
213 |
while (my $date = $rs->next()){ |
214 |
my $outputdate = dt_from_string($date->date(), 'iso'); |
215 |
$outputdate = output_pref( { dt => $outputdate, dateonly => 1 } ); |
216 |
push @single_holidays, { |
217 |
date => $date->date(), |
218 |
outputdate => $outputdate, |
219 |
note => $date->note() |
220 |
} |
221 |
} |
222 |
|
223 |
return @single_holidays; |
224 |
} |
225 |
|
226 |
sub get_float_holidays { |
227 |
my $self = shift; |
228 |
my $branchcode = $self->{branchcode}; |
229 |
my @float_holidays; |
230 |
my $schema = Koha::Database->new->schema; |
231 |
|
232 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
233 |
{ |
234 |
branchcode => $branchcode, |
235 |
holidaytype => 'F' |
236 |
}, |
237 |
{ |
238 |
select => [{ DATE => 'date' }, 'note' ], |
239 |
as => [qw/ date note/], |
240 |
} |
241 |
); |
242 |
while (my $date = $rs->next()){ |
243 |
my $outputdate = dt_from_string($date->date(), 'iso'); |
244 |
$outputdate = output_pref( { dt => $outputdate, dateonly => 1 } ); |
245 |
push @float_holidays, { |
246 |
date => $date->date(), |
247 |
outputdate => $outputdate, |
248 |
note => $date->note() |
249 |
} |
250 |
} |
251 |
|
252 |
return @float_holidays; |
253 |
} |
254 |
|
255 |
sub get_need_valdation_holidays { |
256 |
my $self = shift; |
257 |
my $branchcode = $self->{branchcode}; |
258 |
my @need_validation_holidays; |
259 |
my $schema = Koha::Database->new->schema; |
260 |
|
261 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
262 |
{ |
263 |
branchcode => $branchcode, |
264 |
holidaytype => 'N' |
265 |
}, |
266 |
{ |
267 |
select => [{ DATE => 'date' }, 'note' ], |
268 |
as => [qw/ date note/], |
269 |
} |
270 |
); |
271 |
while (my $date = $rs->next()){ |
272 |
my $outputdate = dt_from_string($date->date(), 'iso'); |
273 |
$outputdate = output_pref( { dt => $outputdate, dateonly => 1 } ); |
274 |
push @need_validation_holidays, { |
275 |
date => $date->date(), |
276 |
outputdate => $outputdate, |
277 |
note => $date->note() |
278 |
} |
279 |
} |
280 |
|
281 |
return @need_validation_holidays; |
282 |
} |
283 |
|
284 |
sub get_repeatable_holidays { |
285 |
my $self = shift; |
286 |
my $branchcode = $self->{branchcode}; |
287 |
my @repeatable_holidays; |
288 |
my $schema = Koha::Database->new->schema; |
289 |
|
290 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
291 |
{ |
292 |
branchcode => $branchcode, |
293 |
holidaytype => 'R', |
294 |
|
295 |
}, |
296 |
{ |
297 |
select => \[ 'distinct DAY(date), MONTH(date), note'], |
298 |
as => [qw/ day month note/], |
299 |
} |
300 |
); |
301 |
|
302 |
while (my $date = $rs->next()){ |
303 |
push @repeatable_holidays, { |
304 |
day=> $date->get_column('day'), |
305 |
month => $date->get_column('month'), |
306 |
note => $date->note() |
307 |
}; |
308 |
} |
309 |
|
310 |
return @repeatable_holidays; |
311 |
} |
312 |
|
313 |
sub get_week_days_holidays { |
314 |
my $self = shift; |
315 |
my $branchcode = $self->{branchcode}; |
316 |
my @week_days; |
317 |
my $schema = Koha::Database->new->schema; |
318 |
|
319 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
320 |
{ |
321 |
holidaytype => 'W', |
322 |
branchcode => $branchcode, |
323 |
}, |
324 |
{ |
325 |
select => [{ DAYOFWEEK => 'date'}, 'note'], |
326 |
as => [qw/ weekday note /], |
327 |
distinct => 1, |
328 |
} |
329 |
); |
330 |
|
331 |
while (my $date = $rs->next()){ |
332 |
push @week_days, { |
333 |
weekday => ($date->get_column('weekday') -1), |
334 |
note => $date->note() |
335 |
}; |
336 |
} |
337 |
|
338 |
return @week_days; |
339 |
} |
340 |
=head1 edit_holiday |
341 |
|
342 |
Modifies a date or a range of dates |
343 |
|
344 |
C<$title> Is the title to be modified for the holiday formed by $year/$month/$day. |
345 |
|
346 |
C<$weekday> Is the day of week for the holiday |
347 |
|
348 |
C<$holidaytype> Is the type of the holiday : |
349 |
E : Exception holiday, single day. |
350 |
F : Floating holiday, different day each year. |
351 |
N : Needs validation, copied float holiday from the past |
352 |
R : Repeatable holiday, repeated on same date. |
353 |
W : Weekly holiday, same day of the week. |
354 |
|
355 |
C<$openHour> Is the opening hour. |
356 |
C<$closeHour> Is the closing hour. |
357 |
C<$startDate> Is the start of the range of dates. |
358 |
C<$endDate> Is the end of the range of dates. |
359 |
=back |
360 |
=cut |
361 |
|
362 |
sub edit_holiday { |
363 |
my ($self, $title, $weekday, $holidaytype, $openHour, $closeHour, $startDate, $endDate, $deleteType, $today) = @_; |
364 |
my $branchcode = $self->{branchcode}; |
365 |
my $schema = Koha::Database->new->schema; |
366 |
my $dtf = $schema->storage->datetime_parser; |
367 |
#String dates for Database usage |
368 |
my $startDate_String = $dtf->format_datetime($startDate); |
369 |
my $endDate_String = $dtf->format_datetime($endDate); |
370 |
$today = DateTime->today unless $today; |
371 |
$today = $dtf->format_datetime($today); |
372 |
|
373 |
my %updateValues = ( |
374 |
isopened => 0, |
375 |
note => $title, |
376 |
holidaytype => $holidaytype, |
377 |
); |
378 |
$updateValues{openhour} = $openHour if $openHour ne ''; |
379 |
$updateValues{closehour} = $closeHour if $closeHour ne ''; |
380 |
|
381 |
if($holidaytype eq 'W') { |
382 |
#Insert/Update weekly holidays |
383 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
384 |
{ |
385 |
branchcode => $branchcode, |
386 |
}, |
387 |
{ |
388 |
where => \[ 'DAYOFWEEK(date) = ? and date >= ?', $weekday, $today], |
389 |
} |
390 |
); |
391 |
|
392 |
while (my $date = $rs->next()){ |
393 |
$date->update(\%updateValues); |
394 |
} |
395 |
}elsif ($holidaytype eq 'E' || $holidaytype eq 'F' || $holidaytype eq 'N') { |
396 |
#Insert/Update Exception Float and Needs Validation holidays |
397 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
398 |
{ |
399 |
branchcode => $branchcode, |
400 |
}, |
401 |
{ |
402 |
where => \['date between DATE(?) and DATE(?) and date >= ?',$startDate_String, $endDate_String, $today] |
403 |
} |
404 |
); |
405 |
while (my $date = $rs->next()){ |
406 |
$date->update(\%updateValues); |
407 |
} |
408 |
|
409 |
}elsif ($holidaytype eq 'R') { |
410 |
#Insert/Update repeatable holidays |
411 |
my $parser = DateTime::Format::Strptime->new( |
412 |
pattern => '%m-%d', |
413 |
on_error => 'croak', |
414 |
); |
415 |
#Format the dates to have only month-day ex: 01-04 for January 4th |
416 |
$startDate = $parser->format_datetime($startDate); |
417 |
$endDate = $parser->format_datetime($endDate); |
418 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
419 |
{ |
420 |
branchcode => $branchcode, |
421 |
}, |
422 |
{ |
423 |
where => \["(DATE_FORMAT(date,'\%m-\%d') BETWEEN ? AND ? ) AND date >= ?", $startDate, $endDate, $today], |
424 |
} |
425 |
); |
426 |
while (my $date = $rs->next()){ |
427 |
$date->update(\%updateValues); |
428 |
} |
429 |
|
430 |
}else { |
431 |
#Delete/Update date(s) |
432 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
433 |
{ |
434 |
branchcode => $branchcode, |
435 |
}, |
436 |
{ |
437 |
where => \['date between DATE(?) and DATE(?) and date >= ?',$startDate_String, $endDate_String, $today], |
438 |
} |
439 |
); |
440 |
#If none, the date(s) will be normal days, else, |
441 |
if($holidaytype eq 'none'){ |
442 |
$updateValues{holidaytype} =''; |
443 |
$updateValues{isopened} =1; |
444 |
}else{ |
445 |
delete $updateValues{holidaytype}; |
446 |
} |
447 |
while (my $date = $rs->next()){ |
448 |
if($deleteType){ |
449 |
if($date->holidaytype() eq 'W' && $startDate_String eq $endDate_String){ |
450 |
$self->remove_weekly_holidays($weekday, \%updateValues, $today); |
451 |
}elsif($date->holidaytype() eq 'R'){ |
452 |
$self->remove_repeatable_holidays($startDate, $endDate, \%updateValues, $today); |
453 |
} |
454 |
}else{ |
455 |
$date->update(\%updateValues); |
456 |
} |
457 |
} |
458 |
} |
459 |
} |
460 |
|
461 |
sub remove_weekly_holidays { |
462 |
my ($self, $weekday, $updateValues, $today) = @_; |
463 |
my $branchcode = $self->{branchcode}; |
464 |
my $schema = Koha::Database->new->schema; |
465 |
|
466 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
467 |
{ |
468 |
branchcode => $branchcode, |
469 |
isopened => 0, |
470 |
holidaytype => 'W' |
471 |
}, |
472 |
{ |
473 |
where => \["DAYOFWEEK(date) = ? and date >= ?", $weekday,$today], |
474 |
} |
475 |
); |
476 |
|
477 |
while (my $date = $rs->next()){ |
478 |
$date->update($updateValues); |
479 |
} |
480 |
} |
481 |
|
482 |
sub remove_repeatable_holidays { |
483 |
my ($self, $startDate, $endDate, $updateValues, $today) = @_; |
484 |
my $branchcode = $self->{branchcode}; |
485 |
my $schema = Koha::Database->new->schema; |
486 |
my $parser = DateTime::Format::Strptime->new( |
487 |
pattern => '%m-%d', |
488 |
on_error => 'croak', |
489 |
); |
490 |
#Format the dates to have only month-day ex: 01-04 for January 4th |
491 |
$startDate = $parser->format_datetime($startDate); |
492 |
$endDate = $parser->format_datetime($endDate); |
493 |
|
494 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
495 |
{ |
496 |
branchcode => $branchcode, |
497 |
isopened => 0, |
498 |
holidaytype => 'R', |
499 |
}, |
500 |
{ |
501 |
where => \["(DATE_FORMAT(date,'\%m-\%d') BETWEEN ? AND ? ) AND date >= ?", $startDate, $endDate, $today], |
502 |
} |
503 |
); |
504 |
|
505 |
while (my $date = $rs->next()){ |
506 |
$date->update($updateValues); |
507 |
} |
508 |
} |
509 |
|
510 |
sub copyToBranch { |
511 |
my ($self,$newBranch) =@_; |
512 |
my $branchcode = $self->{branchcode}; |
513 |
my $schema = Koha::Database->new->schema; |
514 |
|
515 |
my $copyFrom = $schema->resultset('DiscreteCalendar')->search( |
516 |
{ |
517 |
branchcode => $branchcode |
518 |
}, |
519 |
{ |
520 |
columns => [ qw/ date isopened note holidaytype openhour closehour /] |
521 |
} |
522 |
); |
523 |
while (my $copyDate = $copyFrom->next()){ |
524 |
my $copyTo = $schema->resultset('DiscreteCalendar')->search( |
525 |
{ |
526 |
branchcode => $newBranch, |
527 |
date => $copyDate->date(), |
528 |
}, |
529 |
{ |
530 |
columns => [ qw/ date branchcode isopened note holidaytype openhour closehour /] |
531 |
} |
532 |
); |
533 |
#if the date does not exist in the copyTO branch, than skip it. |
534 |
if($copyTo->count ==0){ |
535 |
next; |
536 |
} |
537 |
$copyTo->next()->update({ |
538 |
isopened => $copyDate->isopened(), |
539 |
holidaytype => $copyDate->holidaytype(), |
540 |
note => $copyDate->note(), |
541 |
openhour => $copyDate->openhour(), |
542 |
closehour => $copyDate->closehour() |
543 |
}); |
544 |
} |
545 |
} |
546 |
|
547 |
sub isOpened { |
548 |
my($self, $date) = @_; |
549 |
my $branchcode = $self->{branchcode}; |
550 |
my $schema = Koha::Database->new->schema; |
551 |
my $dtf = $schema->storage->datetime_parser; |
552 |
$date= $dtf->format_datetime($date); |
553 |
#if the date is not found |
554 |
my $isOpened = -1; |
555 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
556 |
{ |
557 |
branchcode => $branchcode, |
558 |
}, |
559 |
{ |
560 |
where => \['date = DATE(?)', $date] |
561 |
} |
562 |
); |
563 |
$isOpened = $rs->next()->isopened() if $rs->count() != 0; |
564 |
|
565 |
return $isOpened; |
566 |
} |
567 |
|
568 |
sub is_holiday { |
569 |
my($self, $date) = @_; |
570 |
my $branchcode = $self->{branchcode}; |
571 |
my $schema = Koha::Database->new->schema; |
572 |
my $dtf = $schema->storage->datetime_parser; |
573 |
$date= $dtf->format_datetime($date); |
574 |
#if the date is not found |
575 |
my $isHoliday = -1; |
576 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
577 |
{ |
578 |
branchcode => $branchcode, |
579 |
}, |
580 |
{ |
581 |
where => \['date = DATE(?)', $date] |
582 |
} |
583 |
); |
584 |
|
585 |
if($rs->count() != 0){ |
586 |
$isHoliday = 0 if $rs->first()->isopened(); |
587 |
$isHoliday = 1 if !$rs->first()->isopened(); |
588 |
} |
589 |
|
590 |
return $isHoliday; |
591 |
} |
592 |
|
593 |
sub copyHoliday { |
594 |
my ($self, $from_startDate, $from_endDate, $to_startDate, $to_endDate, $daysnumber) = @_; |
595 |
my $branchcode = $self->{branchcode}; |
596 |
my $copyFromType = $from_startDate && $from_endDate eq '' ? 'oneDay': 'range'; |
597 |
my $schema = Koha::Database->new->schema; |
598 |
my $dtf = $schema->storage->datetime_parser; |
599 |
|
600 |
if ($copyFromType eq 'oneDay'){ |
601 |
my $where; |
602 |
$to_startDate = $dtf->format_datetime($to_startDate); |
603 |
if ($to_startDate && $to_endDate) { |
604 |
$to_endDate = $dtf->format_datetime($to_endDate); |
605 |
$where = \["date between ? and ?", $to_startDate, $to_endDate]; |
606 |
} else { |
607 |
$where = \['date = ?', $to_startDate]; |
608 |
} |
609 |
|
610 |
$from_startDate = $dtf->format_datetime($from_startDate); |
611 |
my $fromDate = $schema->resultset('DiscreteCalendar')->search( |
612 |
{ |
613 |
branchcode => $branchcode, |
614 |
date => $from_startDate |
615 |
} |
616 |
); |
617 |
my $toDates = $schema->resultset('DiscreteCalendar')->search( |
618 |
{ |
619 |
branchcode => $branchcode, |
620 |
}, |
621 |
{ |
622 |
where => $where |
623 |
} |
624 |
); |
625 |
|
626 |
my $copyDate = $fromDate->next(); |
627 |
while (my $date = $toDates->next()){ |
628 |
$date->update({ |
629 |
isopened => $copyDate->isopened(), |
630 |
holidaytype => $copyDate->holidaytype(), |
631 |
note => $copyDate->note(), |
632 |
openhour => $copyDate->openhour(), |
633 |
closehour => $copyDate->closehour() |
634 |
}) |
635 |
} |
636 |
|
637 |
}else{ |
638 |
my $endDate = dt_from_string($from_endDate); |
639 |
$to_startDate = $dtf->format_datetime($to_startDate); |
640 |
$to_endDate = $dtf->format_datetime($to_endDate); |
641 |
if($daysnumber ==7){ |
642 |
for (my $tempDate = $from_startDate->clone(); $tempDate <= $endDate;$tempDate->add(days => 1)){ |
643 |
my $formatedDate = $dtf->format_datetime($tempDate); |
644 |
my $fromDate = $schema->resultset('DiscreteCalendar')->search( |
645 |
{ |
646 |
branchcode => $branchcode, |
647 |
date => $formatedDate, |
648 |
}, |
649 |
{ |
650 |
select => [{ DAYOFWEEK => 'date' }], |
651 |
as => [qw/ weekday /], |
652 |
columns =>[ qw/ holidaytype note openhour closehour note/] |
653 |
} |
654 |
); |
655 |
my $copyDate = $fromDate->next(); |
656 |
my $weekday = $copyDate->get_column('weekday'); |
657 |
|
658 |
my $toDate = $schema->resultset('DiscreteCalendar')->search( |
659 |
{ |
660 |
branchcode => $branchcode, |
661 |
|
662 |
}, |
663 |
{ |
664 |
where => \['date between ? and ? and DAYOFWEEK(date) = ?',$to_startDate, $to_endDate, $weekday] |
665 |
} |
666 |
); |
667 |
my $copyToDate = $toDate->next(); |
668 |
$copyToDate->update({ |
669 |
isopened => $copyDate->isopened(), |
670 |
holidaytype => $copyDate->holidaytype(), |
671 |
note => $copyDate->note(), |
672 |
openhour => $copyDate->openhour(), |
673 |
closehour => $copyDate->closehour() |
674 |
}); |
675 |
|
676 |
} |
677 |
}else{ |
678 |
my $to_startDate = dt_from_string($to_startDate); |
679 |
my $to_endDate = dt_from_string($to_endDate); |
680 |
for (my $tempDate = $from_startDate->clone(); $tempDate <= $endDate;$tempDate->add(days => 1)){ |
681 |
my $from_formatedDate = $dtf->format_datetime($tempDate); |
682 |
my $fromDate = $schema->resultset('DiscreteCalendar')->search( |
683 |
{ |
684 |
branchcode => $branchcode, |
685 |
date => $from_formatedDate, |
686 |
}, |
687 |
{ |
688 |
order_by => { -asc => 'date' } |
689 |
} |
690 |
); |
691 |
my $to_formatedDate = $dtf->format_datetime($to_startDate); |
692 |
my $toDate = $schema->resultset('DiscreteCalendar')->search( |
693 |
{ |
694 |
branchcode => $branchcode, |
695 |
date => $to_formatedDate |
696 |
}, |
697 |
{ |
698 |
order_by => { -asc => 'date' } |
699 |
} |
700 |
); |
701 |
my $copyDate = $fromDate->next(); |
702 |
$toDate->next()->update({ |
703 |
isopened => $copyDate->isopened(), |
704 |
holidaytype => $copyDate->holidaytype(), |
705 |
note => $copyDate->note(), |
706 |
openhour => $copyDate->openhour(), |
707 |
closehour => $copyDate->closehour() |
708 |
}); |
709 |
$to_startDate->add(days =>1); |
710 |
} |
711 |
} |
712 |
|
713 |
|
714 |
} |
715 |
} |
716 |
|
717 |
sub days_between { |
718 |
my ($self, $start_date, $end_date, ) = @_; |
719 |
my $branchcode = $self->{branchcode}; |
720 |
|
721 |
if ( $start_date->compare($end_date) > 0 ) { |
722 |
# swap dates |
723 |
my $int_dt = $end_date; |
724 |
$end_date = $start_date; |
725 |
$start_date = $int_dt; |
726 |
} |
727 |
|
728 |
my $schema = Koha::Database->new->schema; |
729 |
my $dtf = $schema->storage->datetime_parser; |
730 |
$start_date = $dtf->format_datetime($start_date); |
731 |
$end_date = $dtf->format_datetime($end_date); |
732 |
|
733 |
my $days_between = $schema->resultset('DiscreteCalendar')->search( |
734 |
{ |
735 |
branchcode => $branchcode, |
736 |
isopened => 1, |
737 |
}, |
738 |
{ |
739 |
where => \['date >= date(?) and date < date(?)',$start_date, $end_date] |
740 |
} |
741 |
); |
742 |
|
743 |
return DateTime::Duration->new( days => $days_between->count()); |
744 |
} |
745 |
|
746 |
sub next_open_day { |
747 |
my ( $self, $date ) = @_; |
748 |
my $branchcode = $self->{branchcode}; |
749 |
my $schema = Koha::Database->new->schema; |
750 |
my $dtf = $schema->storage->datetime_parser; |
751 |
$date = $dtf->format_datetime($date); |
752 |
|
753 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
754 |
{ |
755 |
branchcode => $branchcode, |
756 |
isopened => 1, |
757 |
}, |
758 |
{ |
759 |
where => \['date > date(?)', $date], |
760 |
order_by => { -asc => 'date' }, |
761 |
rows => 1 |
762 |
} |
763 |
); |
764 |
return dt_from_string( $rs->next()->date(), 'iso'); |
765 |
} |
766 |
|
767 |
sub prev_open_day { |
768 |
my ( $self, $date ) = @_; |
769 |
my $branchcode = $self->{branchcode}; |
770 |
my $schema = Koha::Database->new->schema; |
771 |
my $dtf = $schema->storage->datetime_parser; |
772 |
$date = $dtf->format_datetime($date); |
773 |
|
774 |
my $rs = $schema->resultset('DiscreteCalendar')->search( |
775 |
{ |
776 |
branchcode => $branchcode, |
777 |
isopened => 1, |
778 |
}, |
779 |
{ |
780 |
where => \['date < date(?)', $date], |
781 |
order_by => { -desc => 'date' }, |
782 |
rows => 1 |
783 |
} |
784 |
); |
785 |
return dt_from_string( $rs->next()->date(), 'iso'); |
786 |
} |
787 |
|
788 |
sub days_forward { |
789 |
my $self = shift; |
790 |
my $start_dt = shift; |
791 |
my $num_days = shift; |
792 |
|
793 |
return $start_dt unless $num_days > 0; |
794 |
|
795 |
my $base_dt = $start_dt->clone(); |
796 |
|
797 |
while ($num_days--) { |
798 |
$base_dt = $self->next_open_day($base_dt); |
799 |
} |
800 |
|
801 |
return $base_dt; |
802 |
} |
803 |
|
804 |
sub hours_between { |
805 |
my ($self, $start_dt, $end_dt) = @_; |
806 |
my $branchcode = $self->{branchcode}; |
807 |
my $schema = Koha::Database->new->schema; |
808 |
my $dtf = $schema->storage->datetime_parser; |
809 |
my $start_date = $start_dt->clone(); |
810 |
my $end_date = $end_dt->clone(); |
811 |
my $duration = $end_date->delta_ms($start_date); |
812 |
$start_date->truncate( to => 'day' ); |
813 |
$end_date->truncate( to => 'day' ); |
814 |
|
815 |
# NB this is a kludge in that it assumes all days are 24 hours |
816 |
# However for hourly loans the logic should be expanded to |
817 |
# take into account open/close times then it would be a duration |
818 |
# of library open hours |
819 |
my $skipped_days = 0; |
820 |
$start_date = $dtf->format_datetime($start_date); |
821 |
$end_date = $dtf->format_datetime($end_date); |
822 |
my $hours_between = $schema->resultset('DiscreteCalendar')->search( |
823 |
{ |
824 |
branchcode => $branchcode, |
825 |
isopened => 0 |
826 |
}, |
827 |
{ |
828 |
where => \[ 'date between ? and ?', $start_date, $end_date], |
829 |
} |
830 |
); |
831 |
|
832 |
if ($skipped_days = $hours_between->count()) { |
833 |
$duration->subtract_duration(DateTime::Duration->new( hours => 24 * $skipped_days)); |
834 |
} |
835 |
|
836 |
return $duration; |
837 |
} |
838 |
|
839 |
sub open_hours_between { |
840 |
my ($self, $start_date, $end_date) = @_; |
841 |
my $branchcode = $self->{branchcode}; |
842 |
my $schema = Koha::Database->new->schema; |
843 |
my $dtf = $schema->storage->datetime_parser; |
844 |
$start_date = $dtf->format_datetime($start_date); |
845 |
$end_date = $dtf->format_datetime($end_date); |
846 |
|
847 |
my $working_hours_between = $schema->resultset('DiscreteCalendar')->search( |
848 |
{ |
849 |
branchcode => $branchcode, |
850 |
isopened => 1, |
851 |
}, |
852 |
{ |
853 |
select => \['sum(time_to_sec(timediff(closehour, openhour)) / 3600)'], |
854 |
as => [qw /hours_between/], |
855 |
where => \['date BETWEEN DATE(?) AND DATE(?)', $start_date, $end_date] |
856 |
} |
857 |
); |
858 |
|
859 |
my $loan_day = $schema->resultset('DiscreteCalendar')->search( |
860 |
{ |
861 |
branchcode => $branchcode, |
862 |
}, |
863 |
{ |
864 |
where => \['date = DATE(?)', $start_date], |
865 |
} |
866 |
); |
867 |
|
868 |
my $return_day = $schema->resultset('DiscreteCalendar')->search( |
869 |
{ |
870 |
branchcode => $branchcode, |
871 |
}, |
872 |
{ |
873 |
where => \['date = DATE(?)', $end_date], |
874 |
} |
875 |
); |
876 |
|
877 |
#Capture the time portion of the date |
878 |
$start_date =~ /\s(.*)/; |
879 |
my $loan_date_time = $1; |
880 |
$end_date =~ /\s(.*)/; |
881 |
my $return_date_time = $1; |
882 |
|
883 |
my $not_used_hours = $schema->resultset('DiscreteCalendar')->search( |
884 |
{ |
885 |
branchcode => $branchcode, |
886 |
isopened => 1, |
887 |
}, |
888 |
{ |
889 |
select => \[ '(time_to_sec(timediff(?, ?)) + time_to_sec(timediff(?, ?)) ) / 3600', $return_day->next()->closehour(), $return_date_time, $loan_date_time, $loan_day->next()->openhour()], |
890 |
as => [qw /not_used_hours/], |
891 |
} |
892 |
); |
893 |
|
894 |
return ($working_hours_between->next()->get_column('hours_between') - $not_used_hours->next()->get_column('not_used_hours')); |
895 |
} |
896 |
sub addDate { |
897 |
my ( $self, $startdate, $add_duration, $unit ) = @_; |
898 |
|
899 |
# Default to days duration (legacy support I guess) |
900 |
if ( ref $add_duration ne 'DateTime::Duration' ) { |
901 |
$add_duration = DateTime::Duration->new( days => $add_duration ); |
902 |
} |
903 |
|
904 |
$unit ||= 'days'; # default days ? |
905 |
my $dt; |
906 |
|
907 |
if ( $unit eq 'hours' ) { |
908 |
# Fixed for legacy support. Should be set as a branch parameter |
909 |
my $return_by_hour = 10; |
910 |
|
911 |
$dt = $self->addHours($startdate, $add_duration, $return_by_hour); |
912 |
} else { |
913 |
# days |
914 |
$dt = $self->addDays($startdate, $add_duration); |
915 |
} |
916 |
|
917 |
return $dt; |
918 |
} |
919 |
|
920 |
sub addHours { |
921 |
my ( $self, $startdate, $hours_duration, $return_by_hour ) = @_; |
922 |
my $base_date = $startdate->clone(); |
923 |
|
924 |
$base_date->add_duration($hours_duration); |
925 |
|
926 |
# If we are using the calendar behave for now as if Datedue |
927 |
# was the chosen option (current intended behaviour) |
928 |
|
929 |
if ( $self->{days_mode} ne 'Days' && |
930 |
$self->is_holiday($base_date) ) { |
931 |
|
932 |
if ( $hours_duration->is_negative() ) { |
933 |
$base_date = $self->prev_open_day($base_date); |
934 |
} else { |
935 |
$base_date = $self->next_open_day($base_date); |
936 |
} |
937 |
|
938 |
$base_date->set_hour($return_by_hour); |
939 |
|
940 |
} |
941 |
|
942 |
return $base_date; |
943 |
} |
944 |
|
945 |
sub addDays { |
946 |
my ( $self, $startdate, $days_duration ) = @_; |
947 |
my $base_date = $startdate->clone(); |
948 |
|
949 |
$self->{days_mode} ||= q{}; |
950 |
|
951 |
if ( $self->{days_mode} eq 'Calendar' ) { |
952 |
# use the calendar to skip all days the library is closed |
953 |
# when adding |
954 |
my $days = abs $days_duration->in_units('days'); |
955 |
|
956 |
if ( $days_duration->is_negative() ) { |
957 |
while ($days) { |
958 |
$base_date = $self->prev_open_day($base_date); |
959 |
--$days; |
960 |
} |
961 |
} else { |
962 |
while ($days) { |
963 |
$base_date = $self->next_open_day($base_date); |
964 |
--$days; |
965 |
} |
966 |
} |
967 |
|
968 |
} else { # Days or Datedue |
969 |
# use straight days, then use calendar to push |
970 |
# the date to the next open day if Datedue |
971 |
$base_date->add_duration($days_duration); |
972 |
|
973 |
if ( $self->{days_mode} eq 'Datedue' ) { |
974 |
# Datedue, then use the calendar to push |
975 |
# the date to the next open day if holiday |
976 |
if (!$self->isOpened($base_date) ) { |
977 |
|
978 |
if ( $days_duration->is_negative() ) { |
979 |
$base_date = $self->prev_open_day($base_date); |
980 |
} else { |
981 |
$base_date = $self->next_open_day($base_date); |
982 |
} |
983 |
} |
984 |
} |
985 |
} |
986 |
|
987 |
return $base_date; |
988 |
} |
989 |
|
990 |
1; |