File: | Koha/Calendar.pm |
Coverage: | 61.2% |
line | stmt | bran | cond | sub | time | code |
---|---|---|---|---|---|---|
1 | package Koha::Calendar; | |||||
2 | 15 15 15 | 490 107 494 | use strict; | |||
3 | 15 15 15 | 150 115 626 | use warnings; | |||
4 | 15 15 15 15 15 15 | 950 1008 343 142 83 253 | use 5.010; | |||
5 | ||||||
6 | 15 15 15 | 121 70 415 | use DateTime; | |||
7 | 15 15 15 | 27909 1022730 1339 | use DateTime::Set; | |||
8 | 15 15 15 | 302 165 462 | use DateTime::Duration; | |||
9 | 15 15 15 | 203 134 343 | use C4::Context; | |||
10 | 15 15 15 | 142 128 1512 | use Carp; | |||
11 | 15 15 15 | 48211 55059 25030 | use Readonly; | |||
12 | ||||||
13 | sub new { | |||||
14 | 1 | 24 | my ( $classname, %options ) = @_; | |||
15 | 1 | 22 | my $self = {}; | |||
16 | 1 | 27 | bless $self, $classname; | |||
17 | 1 | 21 | for my $o_name ( keys %options ) { | |||
18 | 1 | 19 | my $o = lc $o_name; | |||
19 | 1 | 21 | $self->{$o} = $options{$o_name}; | |||
20 | } | |||||
21 | 1 | 21 | if ( exists $options{TEST_MODE} ) { | |||
22 | 1 | 18 | $self->_mockinit(); | |||
23 | 1 | 10 | return $self; | |||
24 | } | |||||
25 | 0 | 0 | if ( !defined $self->{branchcode} ) { | |||
26 | 0 | 0 | croak 'No branchcode argument passed to Koha::Calendar->new'; | |||
27 | } | |||||
28 | 0 | 0 | $self->_init(); | |||
29 | 0 | 0 | return $self; | |||
30 | } | |||||
31 | ||||||
32 | sub _init { | |||||
33 | 0 | 0 | my $self = shift; | |||
34 | 0 | 0 | my $branch = $self->{branchcode}; | |||
35 | 0 | 0 | my $dbh = C4::Context->dbh(); | |||
36 | 0 | 0 | my $repeat_sth = $dbh->prepare( | |||
37 | 'SELECT * from repeatable_holidays WHERE branchcode = ? AND ISNULL(weekday) = ?' | |||||
38 | ); | |||||
39 | 0 | 0 | $repeat_sth->execute( $branch, 0 ); | |||
40 | 0 | 0 | $self->{weekly_closed_days} = [ 0, 0, 0, 0, 0, 0, 0 ]; | |||
41 | 0 | 0 | Readonly::Scalar my $sunday => 7; | |||
42 | 0 | 0 | while ( my $tuple = $repeat_sth->fetchrow_hashref ) { | |||
43 | 0 | 0 | $self->{weekly_closed_days}->[ $tuple->{weekday} ] = 1; | |||
44 | } | |||||
45 | 0 | 0 | $repeat_sth->execute( $branch, 1 ); | |||
46 | 0 | 0 | $self->{day_month_closed_days} = {}; | |||
47 | 0 | 0 | while ( my $tuple = $repeat_sth->fetchrow_hashref ) { | |||
48 | 0 | 0 | $self->{day_month_closed_days}->{ $tuple->{day} }->{ $tuple->{month} } = | |||
49 | 1; | |||||
50 | } | |||||
51 | 0 | 0 | my $special = $dbh->prepare( | |||
52 | 'SELECT day, month, year, title, description FROM special_holidays WHERE ( branchcode = ? ) AND (isexception = ?)' | |||||
53 | ); | |||||
54 | 0 | 0 | $special->execute( $branch, 1 ); | |||
55 | 0 | 0 | my $dates = []; | |||
56 | 0 | 0 | while ( my ( $day, $month, $year, $title, $description ) = | |||
57 | $special->fetchrow ) { | |||||
58 | 0 0 | 0 0 | push @{$dates}, | |||
59 | DateTime->new( | |||||
60 | day => $day, | |||||
61 | month => $month, | |||||
62 | year => $year, | |||||
63 | time_zone => C4::Context->tz() | |||||
64 | )->truncate( to => 'day' ); | |||||
65 | } | |||||
66 | 0 | 0 | $self->{exception_holidays} = | |||
67 | DateTime::Set->from_datetimes( dates => $dates ); | |||||
68 | 0 | 0 | $special->execute( $branch, 1 ); | |||
69 | 0 | 0 | $dates = []; | |||
70 | 0 | 0 | while ( my ( $day, $month, $year, $title, $description ) = | |||
71 | $special->fetchrow ) { | |||||
72 | 0 0 | 0 0 | push @{$dates}, | |||
73 | DateTime->new( | |||||
74 | day => $day, | |||||
75 | month => $month, | |||||
76 | year => $year, | |||||
77 | time_zone => C4::Context->tz() | |||||
78 | )->truncate( to => 'day' ); | |||||
79 | } | |||||
80 | 0 | 0 | $self->{single_holidays} = DateTime::Set->from_datetimes( dates => $dates ); | |||
81 | 0 | 0 | $self->{days_mode} = C4::Context->preference('useDaysMode'); | |||
82 | 0 | 0 | return; | |||
83 | } | |||||
84 | ||||||
85 | sub addDate { | |||||
86 | 2 | 23 | my ( $self, $startdate, $add_duration, $unit ) = @_; | |||
87 | 2 | 28 | my $base_date = $startdate->clone(); | |||
88 | 2 | 54 | if ( ref $add_duration ne 'DateTime::Duration' ) { | |||
89 | 2 | 32 | $add_duration = DateTime::Duration->new( days => $add_duration ); | |||
90 | } | |||||
91 | 2 | 271 | $unit ||= q{}; # default days ? | |||
92 | 2 | 22 | my $days_mode = $self->{days_mode}; | |||
93 | 2 | 28 | Readonly::Scalar my $return_by_hour => 10; | |||
94 | 2 | 163 | my $day_dur = DateTime::Duration->new( days => 1 ); | |||
95 | 2 | 424 | if ( $add_duration->is_negative() ) { | |||
96 | 1 | 32 | $day_dur->inverse(); | |||
97 | } | |||||
98 | 2 | 186 | if ( $days_mode eq 'Datedue' ) { | |||
99 | ||||||
100 | 0 | 0 | my $dt = $base_date + $add_duration; | |||
101 | 0 | 0 | while ( $self->is_holiday($dt) ) { | |||
102 | ||||||
103 | # TODOP if hours set to 10 am | |||||
104 | 0 | 0 | $dt->add_duration($day_dur); | |||
105 | 0 | 0 | if ( $unit eq 'hours' ) { | |||
106 | 0 | 0 | $dt->set_hour($return_by_hour); # Staffs specific | |||
107 | } | |||||
108 | } | |||||
109 | 0 | 0 | return $dt; | |||
110 | } elsif ( $days_mode eq 'Calendar' ) { | |||||
111 | 2 | 16 | if ( $unit eq 'hours' ) { | |||
112 | 0 | 0 | $base_date->add_duration($add_duration); | |||
113 | 0 | 0 | while ( $self->is_holiday($base_date) ) { | |||
114 | 0 | 0 | $base_date->add_duration($day_dur); | |||
115 | ||||||
116 | } | |||||
117 | ||||||
118 | } else { | |||||
119 | 2 | 25 | my $days = abs $add_duration->in_units('days'); | |||
120 | 2 | 67 | while ($days) { | |||
121 | 3 | 52 | $base_date->add_duration($day_dur); | |||
122 | 3 | 4280 | if ( $self->is_holiday($base_date) ) { | |||
123 | 1 | 25 | next; | |||
124 | } else { | |||||
125 | 2 | 13 | --$days; | |||
126 | } | |||||
127 | } | |||||
128 | } | |||||
129 | 2 | 6 | if ( $unit eq 'hours' ) { | |||
130 | 0 | 0 | my $dt = $base_date->clone()->subtract( days => 1 ); | |||
131 | 0 | 0 | if ( $self->is_holiday($dt) ) { | |||
132 | 0 | 0 | $base_date->set_hour($return_by_hour); # Staffs specific | |||
133 | } | |||||
134 | } | |||||
135 | 2 | 19 | return $base_date; | |||
136 | } else { # Days | |||||
137 | 0 | 0 | return $base_date + $add_duration; | |||
138 | } | |||||
139 | } | |||||
140 | ||||||
141 | sub is_holiday { | |||||
142 | 8 | 60 | my ( $self, $dt ) = @_; | |||
143 | 8 | 84 | my $dow = $dt->day_of_week; | |||
144 | 8 | 126 | if ( $dow == 7 ) { | |||
145 | 2 | 28 | $dow = 0; | |||
146 | } | |||||
147 | 8 | 59 | if ( $self->{weekly_closed_days}->[$dow] == 1 ) { | |||
148 | 2 | 36 | return 1; | |||
149 | } | |||||
150 | 6 | 47 | $dt->truncate( to => 'days' ); | |||
151 | 6 | 4533 | my $day = $dt->day; | |||
152 | 6 | 80 | my $month = $dt->month; | |||
153 | 6 | 74 | if ( exists $self->{day_month_closed_days}->{$month}->{$day} ) { | |||
154 | 1 | 14 | return 1; | |||
155 | } | |||||
156 | 5 | 49 | if ( $self->{exception_holidays}->contains($dt) ) { | |||
157 | 0 | 0 | return 1; | |||
158 | } | |||||
159 | 5 | 2498 | if ( $self->{single_holidays}->contains($dt) ) { | |||
160 | 1 | 1065 | return 1; | |||
161 | } | |||||
162 | ||||||
163 | # damn have to go to work after all | |||||
164 | 4 | 2714 | return 0; | |||
165 | } | |||||
166 | ||||||
167 | sub days_between { | |||||
168 | 0 | 0 | my $self = shift; | |||
169 | 0 | 0 | my $start_dt = shift; | |||
170 | 0 | 0 | my $end_dt = shift; | |||
171 | 0 | 0 | $start_dt->truncate( to => 'hours' ); | |||
172 | 0 | 0 | $end_dt->truncate( to => 'hours' ); | |||
173 | ||||||
174 | # start and end should not be closed days | |||||
175 | 0 | 0 | my $duration = $end_dt - $start_dt; | |||
176 | 0 | 0 | $start_dt->truncate( to => 'days' ); | |||
177 | 0 | 0 | $end_dt->truncate( to => 'days' ); | |||
178 | 0 | 0 | while ( DateTime->compare( $start_dt, $end_dt ) == -1 ) { | |||
179 | 0 | 0 | $start_dt->add( days => 1 ); | |||
180 | 0 | 0 | if ( $self->is_holiday($start_dt) ) { | |||
181 | 0 | 0 | $duration->subtract( days => 1 ); | |||
182 | } | |||||
183 | } | |||||
184 | 0 | 0 | return $duration; | |||
185 | ||||||
186 | } | |||||
187 | ||||||
188 | sub _mockinit { | |||||
189 | 1 | 17 | my $self = shift; | |||
190 | 1 | 17 | $self->{weekly_closed_days} = [ 1, 0, 0, 0, 0, 0, 0 ]; # Sunday only | |||
191 | 1 | 19 | $self->{day_month_closed_days} = { 6 => { 16 => 1, } }; | |||
192 | 1 | 15 | my $dates = []; | |||
193 | 1 | 23 | $self->{exception_holidays} = | |||
194 | DateTime::Set->from_datetimes( dates => $dates ); | |||||
195 | 1 | 498 | my $special = DateTime->new( | |||
196 | year => 2011, | |||||
197 | month => 6, | |||||
198 | day => 1, | |||||
199 | time_zone => 'Europe/London', | |||||
200 | ); | |||||
201 | 1 1 | 71915 3 | push @{$dates}, $special; | |||
202 | 1 | 26 | $self->{single_holidays} = DateTime::Set->from_datetimes( dates => $dates ); | |||
203 | 1 | 929 | $self->{days_mode} = 'Calendar'; | |||
204 | 1 | 5 | return; | |||
205 | } | |||||
206 | ||||||
207 | 1; |