View | Details | Raw Unified | Return to bug 8133
Collapse All | Expand All

(-)a/C4/Calendar.pm (-620 / +118 lines)
Lines 15-726 package C4::Calendar; Link Here
15
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
15
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
16
# Suite 330, Boston, MA  02111-1307 USA
16
# Suite 330, Boston, MA  02111-1307 USA
17
17
18
use strict;
18
use Modern::Perl;
19
use warnings;
20
use vars qw($VERSION @EXPORT);
19
use vars qw($VERSION @EXPORT);
21
20
22
use Carp;
21
use Carp;
23
use Date::Calc qw( Date_to_Days Today);
24
22
25
use C4::Context;
23
use C4::Context;
26
24
25
our ( @ISA, @EXPORT );
26
27
BEGIN {
28
    @ISA = qw( Exporter );
29
    @EXPORT = qw(
30
        GetSingleEvents
31
        GetWeeklyEvents
32
        GetYearlyEvents
33
        ModSingleEvent
34
        ModRepeatingEvent
35
        DelSingleEvent
36
        DelRepeatingEvent
37
        CopyAllEvents
38
    );
39
}
40
27
use constant ISO_DATE_FORMAT => "%04d-%02d-%02d";
41
use constant ISO_DATE_FORMAT => "%04d-%02d-%02d";
28
=head1 NAME
42
=head1 NAME
29
43
30
C4::Calendar::Calendar - Koha module dealing with holidays.
44
C4::Calendar - Koha module dealing with holidays.
31
45
32
=head1 SYNOPSIS
46
=head1 SYNOPSIS
33
47
34
    use C4::Calendar::Calendar;
48
    use C4::Calendar;
35
49
36
=head1 DESCRIPTION
50
=head1 DESCRIPTION
37
51
38
This package is used to deal with holidays. Through this package, you can set 
52
This package is used to deal with hours and holidays;
39
all kind of holidays for the library.
40
53
41
=head1 FUNCTIONS
54
=head1 FUNCTIONS
42
55
43
=head2 new
56
=head2 GetSingleEvents
44
57
45
  $calendar = C4::Calendar->new(branchcode => $branchcode);
58
  \@events = GetSingleEvents( $branchcode )
46
59
47
Each library branch has its own Calendar.  
60
Get the non-repeating events for the given library.
48
C<$branchcode> specifies which Calendar you want.
49
61
50
=cut
62
=cut
51
63
52
sub new {
64
sub GetSingleEvents {
53
    my $classname = shift @_;
65
    my ( $branchcode ) = @_;
54
    my %options = @_;
55
    my $self = bless({}, $classname);
56
    foreach my $optionName (keys %options) {
57
        $self->{lc($optionName)} = $options{$optionName};
58
    }
59
    defined($self->{branchcode}) or croak "No branchcode argument to new.  Should be C4::Calendar->new(branchcode => \$branchcode)";
60
    $self->_init($self->{branchcode});
61
    return $self;
62
}
63
66
64
sub _init {
67
    return C4::Context->dbh->selectall_arrayref( q{
65
    my $self = shift @_;
68
        SELECT
66
    my $branch = shift;
69
            event_date, open_hour, open_minute, close_hour, close_minute, title, description,
67
    defined($branch) or die "No branchcode sent to _init";  # must test for defined here and above to allow ""
70
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
68
    my $dbh = C4::Context->dbh();
71
        FROM calendar_events
69
    my $repeatable = $dbh->prepare( 'SELECT *
72
        WHERE branchcode = ?
70
                                       FROM repeatable_holidays
73
    }, { Slice => {} }, $branchcode );
71
                                      WHERE ( branchcode = ? )
72
                                        AND (ISNULL(weekday) = ?)' );
73
    $repeatable->execute($branch,0);
74
    my %week_days_holidays;
75
    while (my $row = $repeatable->fetchrow_hashref) {
76
        my $key = $row->{weekday};
77
        $week_days_holidays{$key}{title}       = $row->{title};
78
        $week_days_holidays{$key}{description} = $row->{description};
79
    }
80
    $self->{'week_days_holidays'} = \%week_days_holidays;
81
82
    $repeatable->execute($branch,1);
83
    my %day_month_holidays;
84
    while (my $row = $repeatable->fetchrow_hashref) {
85
        my $key = $row->{month} . "/" . $row->{day};
86
        $day_month_holidays{$key}{title}       = $row->{title};
87
        $day_month_holidays{$key}{description} = $row->{description};
88
        $day_month_holidays{$key}{day} = sprintf("%02d", $row->{day});
89
        $day_month_holidays{$key}{month} = sprintf("%02d", $row->{month});
90
    }
91
    $self->{'day_month_holidays'} = \%day_month_holidays;
92
93
    my $special = $dbh->prepare( 'SELECT day, month, year, title, description
94
                                    FROM special_holidays
95
                                   WHERE ( branchcode = ? )
96
                                     AND (isexception = ?)' );
97
    $special->execute($branch,1);
98
    my %exception_holidays;
99
    while (my ($day, $month, $year, $title, $description) = $special->fetchrow) {
100
        $exception_holidays{"$year/$month/$day"}{title} = $title;
101
        $exception_holidays{"$year/$month/$day"}{description} = $description;
102
        $exception_holidays{"$year/$month/$day"}{date} = 
103
		sprintf(ISO_DATE_FORMAT, $year, $month, $day);
104
    }
105
    $self->{'exception_holidays'} = \%exception_holidays;
106
107
    $special->execute($branch,0);
108
    my %single_holidays;
109
    while (my ($day, $month, $year, $title, $description) = $special->fetchrow) {
110
        $single_holidays{"$year/$month/$day"}{title} = $title;
111
        $single_holidays{"$year/$month/$day"}{description} = $description;
112
        $single_holidays{"$year/$month/$day"}{date} = 
113
		sprintf(ISO_DATE_FORMAT, $year, $month, $day);
114
    }
115
    $self->{'single_holidays'} = \%single_holidays;
116
    return $self;
117
}
74
}
118
75
119
=head2 get_week_days_holidays
76
=head2 GetWeeklyEvents
120
77
121
   $week_days_holidays = $calendar->get_week_days_holidays();
78
  \@events = GetWeeklyEvents( $branchcode )
122
79
123
Returns a hash reference to week days holidays.
80
Get the weekly-repeating events for the given library.
124
81
125
=cut
82
=cut
126
83
127
sub get_week_days_holidays {
84
sub GetWeeklyEvents {
128
    my $self = shift @_;
85
    my ( $branchcode ) = @_;
129
    my $week_days_holidays = $self->{'week_days_holidays'};
130
    return $week_days_holidays;
131
}
132
133
=head2 get_day_month_holidays
134
135
   $day_month_holidays = $calendar->get_day_month_holidays();
136
137
Returns a hash reference to day month holidays.
138
139
=cut
140
86
141
sub get_day_month_holidays {
87
    return C4::Context->dbh->selectall_arrayref( q{
142
    my $self = shift @_;
88
        SELECT
143
    my $day_month_holidays = $self->{'day_month_holidays'};
89
            weekday, open_hour, open_minute, close_hour, close_minute, title, description,
144
    return $day_month_holidays;
90
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
91
        FROM calendar_repeats
92
        WHERE branchcode = ? AND weekday IS NOT NULL
93
    }, { Slice => {} }, $branchcode ); 
145
}
94
}
146
95
147
=head2 get_exception_holidays
96
=head2 GetYearlyEvents
148
97
149
    $exception_holidays = $calendar->exception_holidays();
98
  \@events = GetYearlyEvents( $branchcode )
150
99
151
Returns a hash reference to exception holidays. This kind of days are those
100
Get the yearly-repeating events for the given library.
152
which stands for a holiday, but you wanted to make an exception for this particular
153
date.
154
101
155
=cut
102
=cut
156
103
157
sub get_exception_holidays {
104
sub GetYearlyEvents {
158
    my $self = shift @_;
105
    my ( $branchcode ) = @_;
159
    my $exception_holidays = $self->{'exception_holidays'};
160
    return $exception_holidays;
161
}
162
163
=head2 get_single_holidays
164
165
    $single_holidays = $calendar->get_single_holidays();
166
106
167
Returns a hash reference to single holidays. This kind of holidays are those which
107
    return C4::Context->dbh->selectall_arrayref( q{
168
happend just one time.
108
        SELECT
169
109
            month, day, open_hour, open_minute, close_hour, close_minute, title, description,
170
=cut
110
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
171
111
        FROM calendar_repeats
172
sub get_single_holidays {
112
        WHERE branchcode = ? AND weekday IS NULL
173
    my $self = shift @_;
113
    }, { Slice => {} }, $branchcode );
174
    my $single_holidays = $self->{'single_holidays'};
175
    return $single_holidays;
176
}
114
}
177
115
178
=head2 insert_week_day_holiday
116
=head2 ModSingleEvent
179
180
    insert_week_day_holiday(weekday => $weekday,
181
                            title => $title,
182
                            description => $description);
183
184
Inserts a new week day for $self->{branchcode}.
185
186
C<$day> Is the week day to make holiday.
187
117
188
C<$title> Is the title to store for the holiday formed by $year/$month/$day.
118
  ModSingleEvent( $branchcode, $date, \%info )
189
119
190
C<$description> Is the description to store for the holiday formed by $year/$month/$day.
120
Creates or updates an event for a single date. $date should be an ISO-formatted
121
date string, and \%info should contain the following keys: open_hour,
122
open_minute, close_hour, close_minute, title and description.
191
123
192
=cut
124
=cut
193
125
194
sub insert_week_day_holiday {
126
sub ModSingleEvent {
195
    my $self = shift @_;
127
    my ( $branchcode, $date, $info ) = @_;
196
    my %options = @_;
197
128
198
    my $weekday = $options{weekday};
129
    C4::Context->dbh->do( q{
199
    croak "Invalid weekday $weekday" unless $weekday =~ m/^[0-6]$/;
130
        INSERT INTO calendar_events(branchcode, event_date, open_hour, open_minute, close_hour, close_minute, title, description)
200
131
        VALUES (?, ?, ?, ?, ?, ?, ?, ?)
201
    my $dbh = C4::Context->dbh();
132
        ON DUPLICATE KEY UPDATE open_hour = ?, open_minute = ?, close_hour = ?, close_minute = ?, title = ?, description = ?
202
    my $insertHoliday = $dbh->prepare("insert into repeatable_holidays (id,branchcode,weekday,day,month,title,description) values ( '',?,?,NULL,NULL,?,? )"); 
133
    }, {}, $branchcode, $date, ( map { $info->{$_} } qw(open_hour open_minute close_hour close_minute title description) ) x 2 );
203
	$insertHoliday->execute( $self->{branchcode}, $weekday, $options{title}, $options{description});
204
    $self->{'week_days_holidays'}->{$weekday}{title} = $options{title};
205
    $self->{'week_days_holidays'}->{$weekday}{description} = $options{description};
206
    return $self;
207
}
134
}
208
135
209
=head2 insert_day_month_holiday
136
=head2 ModRepeatingEvent
210
211
    insert_day_month_holiday(day => $day,
212
                             month => $month,
213
                             title => $title,
214
                             description => $description);
215
216
Inserts a new day month holiday for $self->{branchcode}.
217
218
C<$day> Is the day month to make the date to insert.
219
220
C<$month> Is month to make the date to insert.
221
137
222
C<$title> Is the title to store for the holiday formed by $year/$month/$day.
138
  ModRepeatingEvent( $branchcode, $weekday, $month, $day, \%info )
223
139
224
C<$description> Is the description to store for the holiday formed by $year/$month/$day.
140
Creates or updates a weekly- or yearly-repeating event. Either $weekday,
141
or $month and $day should be set, for a weekly or yearly event, respectively.
225
142
226
=cut
143
=cut
227
144
228
sub insert_day_month_holiday {
145
sub ModRepeatingEvent {
229
    my $self = shift @_;
146
    my ( $branchcode, $weekday, $month, $day, $info ) = @_;
230
    my %options = @_;
231
147
232
    my $dbh = C4::Context->dbh();
148
    C4::Context->dbh->do( q{
233
    my $insertHoliday = $dbh->prepare("insert into repeatable_holidays (id,branchcode,weekday,day,month,title,description) values ('', ?, NULL, ?, ?, ?,? )");
149
        INSERT INTO calendar_repeats(branchcode, weekday, month, day, open_hour, open_minute, close_hour, close_minute, title, description)
234
	$insertHoliday->execute( $self->{branchcode}, $options{day},$options{month},$options{title}, $options{description});
150
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
235
    $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{title} = $options{title};
151
        ON DUPLICATE KEY UPDATE open_hour = ?, open_minute = ?, close_hour = ?, close_minute = ?, title = ?, description = ?
236
    $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{description} = $options{description};
152
    }, {}, $branchcode, $weekday, $month, $day, ( map { $info->{$_} } qw(open_hour open_minute close_hour close_minute title description) ) x 2 );
237
    return $self;
238
}
153
}
239
154
240
=head2 insert_single_holiday
155
=head2 DelSingleEvent
241
242
    insert_single_holiday(day => $day,
243
                          month => $month,
244
                          year => $year,
245
                          title => $title,
246
                          description => $description);
247
248
Inserts a new single holiday for $self->{branchcode}.
249
250
C<$day> Is the day month to make the date to insert.
251
252
C<$month> Is month to make the date to insert.
253
156
254
C<$year> Is year to make the date to insert.
157
  DelSingleEvent( $branchcode, $date, \%info )
255
158
256
C<$title> Is the title to store for the holiday formed by $year/$month/$day.
159
Deletes an event for a single date. $date should be an ISO-formatted date string.
257
258
C<$description> Is the description to store for the holiday formed by $year/$month/$day.
259
160
260
=cut
161
=cut
261
162
262
sub insert_single_holiday {
163
sub DelSingleEvent {
263
    my $self = shift @_;
164
    my ( $branchcode, $date ) = @_;
264
    my %options = @_;
265
    
266
    @options{qw(year month day)} = ( $options{date} =~ m/(\d+)-(\d+)-(\d+)/o )
267
      if $options{date} && !$options{day};
268
269
	my $dbh = C4::Context->dbh();
270
    my $isexception = 0;
271
    my $insertHoliday = $dbh->prepare("insert into special_holidays (id,branchcode,day,month,year,isexception,title,description) values ('', ?,?,?,?,?,?,?)");
272
	$insertHoliday->execute( $self->{branchcode}, $options{day},$options{month},$options{year}, $isexception, $options{title}, $options{description});
273
    $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title};
274
    $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description};
275
    return $self;
276
}
277
278
=head2 insert_exception_holiday
279
280
    insert_exception_holiday(day => $day,
281
                             month => $month,
282
                             year => $year,
283
                             title => $title,
284
                             description => $description);
285
286
Inserts a new exception holiday for $self->{branchcode}.
287
288
C<$day> Is the day month to make the date to insert.
289
290
C<$month> Is month to make the date to insert.
291
292
C<$year> Is year to make the date to insert.
293
294
C<$title> Is the title to store for the holiday formed by $year/$month/$day.
295
165
296
C<$description> Is the description to store for the holiday formed by $year/$month/$day.
166
    C4::Context->dbh->do( q{
297
167
        DELETE FROM calendar_events
298
=cut
168
        WHERE branchcode = ? AND event_date = ?
299
169
    }, {}, $branchcode, $date );
300
sub insert_exception_holiday {
301
    my $self = shift @_;
302
    my %options = @_;
303
304
    @options{qw(year month day)} = ( $options{date} =~ m/(\d+)-(\d+)-(\d+)/o )
305
      if $options{date} && !$options{day};
306
307
    my $dbh = C4::Context->dbh();
308
    my $isexception = 1;
309
    my $insertException = $dbh->prepare("insert into special_holidays (id,branchcode,day,month,year,isexception,title,description) values ('', ?,?,?,?,?,?,?)");
310
	$insertException->execute( $self->{branchcode}, $options{day},$options{month},$options{year}, $isexception, $options{title}, $options{description});
311
    $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title};
312
    $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description};
313
    return $self;
314
}
170
}
315
171
316
=head2 ModWeekdayholiday
172
sub _get_compare {
317
173
    my ( $colname, $value ) = @_;
318
    ModWeekdayholiday(weekday =>$weekday,
319
                      title => $title,
320
                      description => $description)
321
322
Modifies the title and description of a weekday for $self->{branchcode}.
323
324
C<$weekday> Is the title to update for the holiday.
325
326
C<$description> Is the description to update for the holiday.
327
174
328
=cut
175
    return ' AND ' . $colname . ' ' . ( defined( $value ) ? '=' : 'IS' ) . ' ?';
329
330
sub ModWeekdayholiday {
331
    my $self = shift @_;
332
    my %options = @_;
333
334
    my $dbh = C4::Context->dbh();
335
    my $updateHoliday = $dbh->prepare("UPDATE repeatable_holidays SET title = ?, description = ? WHERE branchcode = ? AND weekday = ?");
336
    $updateHoliday->execute( $options{title},$options{description},$self->{branchcode},$options{weekday}); 
337
    $self->{'week_days_holidays'}->{$options{weekday}}{title} = $options{title};
338
    $self->{'week_days_holidays'}->{$options{weekday}}{description} = $options{description};
339
    return $self;
340
}
176
}
341
177
342
=head2 ModDaymonthholiday
178
=head2 DelRepeatingEvent
343
344
    ModDaymonthholiday(day => $day,
345
                       month => $month,
346
                       title => $title,
347
                       description => $description);
348
349
Modifies the title and description for a day/month holiday for $self->{branchcode}.
350
179
351
C<$day> The day of the month for the update.
180
  DelRepeatingEvent( $branchcode, $weekday, $month, $day )
352
181
353
C<$month> The month to be used for the update.
182
Deletes a weekly- or yearly-repeating event. Either $weekday, or $month and
354
183
$day should be set, for a weekly or yearly event, respectively.
355
C<$title> The title to be updated for the holiday.
356
357
C<$description> The description to be update for the holiday.
358
184
359
=cut
185
=cut
360
186
361
sub ModDaymonthholiday {
187
sub DelRepeatingEvent {
362
    my $self = shift @_;
188
    my ( $branchcode, $weekday, $month, $day ) = @_;
363
    my %options = @_;
364
189
365
    my $dbh = C4::Context->dbh();
190
    C4::Context->dbh->do( q{
366
    my $updateHoliday = $dbh->prepare("UPDATE repeatable_holidays SET title = ?, description = ? WHERE month = ? AND day = ? AND branchcode = ?");
191
        DELETE FROM calendar_repeats
367
       $updateHoliday->execute( $options{title},$options{description},$options{month},$options{day},$self->{branchcode}); 
192
        WHERE branchcode = ?
368
    $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{title} = $options{title};
193
    } . _get_compare( 'weekday', $weekday ) . _get_compare( 'month', $month ) . _get_compare( 'day', $day ), {}, $branchcode, $weekday, $month, $day );
369
    $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{description} = $options{description};
370
    return $self;
371
}
194
}
372
195
373
=head2 ModSingleholiday
196
=head2 CopyAllEvents
374
375
    ModSingleholiday(day => $day,
376
                     month => $month,
377
                     year => $year,
378
                     title => $title,
379
                     description => $description);
380
381
Modifies the title and description for a single holiday for $self->{branchcode}.
382
197
383
C<$day> Is the day of the month to make the update.
198
  CopyAllEvents( $from_branchcode, $to_branchcode )
384
199
385
C<$month> Is the month to make the update.
200
Copies all events from one branch to another.
386
387
C<$year> Is the year to make the update.
388
389
C<$title> Is the title to update for the holiday formed by $year/$month/$day.
390
391
C<$description> Is the description to update for the holiday formed by $year/$month/$day.
392
201
393
=cut
202
=cut
394
203
395
sub ModSingleholiday {
204
sub CopyAllEvents {
396
    my $self = shift @_;
205
    my ( $from_branchcode, $to_branchcode ) = @_;
397
    my %options = @_;
398
399
    my $dbh = C4::Context->dbh();
400
    my $isexception = 0;
401
    my $updateHoliday = $dbh->prepare("UPDATE special_holidays SET title = ?, description = ? WHERE day = ? AND month = ? AND year = ? AND branchcode = ? AND isexception = ?");
402
      $updateHoliday->execute($options{title},$options{description},$options{day},$options{month},$options{year},$self->{branchcode},$isexception);    
403
    $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title};
404
    $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description};
405
    return $self;
406
}
407
408
=head2 ModExceptionholiday
409
410
    ModExceptionholiday(day => $day,
411
                        month => $month,
412
                        year => $year,
413
                        title => $title,
414
                        description => $description);
415
416
Modifies the title and description for an exception holiday for $self->{branchcode}.
417
418
C<$day> Is the day of the month for the holiday.
419
420
C<$month> Is the month for the holiday.
421
206
422
C<$year> Is the year for the holiday.
207
    C4::Context->dbh->do( q{
208
        INSERT IGNORE INTO calendar_events(branchcode, event_date, open_hour, open_minute, close_hour, close_minute, title, description)
209
        SELECT ?, event_date, open_hour, open_minute, close_hour, close_minute, title, description
210
        FROM calendar_events
211
        WHERE branchcode = ?
212
    }, {}, $to_branchcode, $from_branchcode );
423
213
424
C<$title> Is the title to be modified for the holiday formed by $year/$month/$day.
214
    C4::Context->dbh->do( q{
425
215
        INSERT IGNORE INTO calendar_repeats(branchcode, weekday, month, day, open_hour, open_minute, close_hour, close_minute, title, description)
426
C<$description> Is the description to be modified for the holiday formed by $year/$month/$day.
216
        SELECT ?, weekday, month, day, open_hour, open_minute, close_hour, close_minute, title, description
427
217
        FROM calendar_repeats
428
=cut
218
        WHERE branchcode = ?
429
219
    }, {}, $to_branchcode, $from_branchcode );
430
sub ModExceptionholiday {
431
    my $self = shift @_;
432
    my %options = @_;
433
434
    my $dbh = C4::Context->dbh();
435
    my $isexception = 1;
436
    my $updateHoliday = $dbh->prepare("UPDATE special_holidays SET title = ?, description = ? WHERE day = ? AND month = ? AND year = ? AND branchcode = ? AND isexception = ?");
437
    $updateHoliday->execute($options{title},$options{description},$options{day},$options{month},$options{year},$self->{branchcode},$isexception);    
438
    $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title};
439
    $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description};
440
    return $self;
441
}
220
}
442
221
443
=head2 delete_holiday
444
445
    delete_holiday(weekday => $weekday
446
                   day => $day,
447
                   month => $month,
448
                   year => $year);
449
450
Delete a holiday for $self->{branchcode}.
451
452
C<$weekday> Is the week day to delete.
453
454
C<$day> Is the day month to make the date to delete.
455
456
C<$month> Is month to make the date to delete.
457
458
C<$year> Is year to make the date to delete.
459
460
=cut
461
462
sub delete_holiday {
463
    my $self = shift @_;
464
    my %options = @_;
465
466
    # Verify what kind of holiday that day is. For example, if it is
467
    # a repeatable holiday, this should check if there are some exception
468
	# for that holiday rule. Otherwise, if it is a regular holiday, it´s 
469
    # ok just deleting it.
470
471
    my $dbh = C4::Context->dbh();
472
    my $isSingleHoliday = $dbh->prepare("SELECT id FROM special_holidays WHERE (branchcode = ?) AND (day = ?) AND (month = ?) AND (year = ?)");
473
    $isSingleHoliday->execute($self->{branchcode}, $options{day}, $options{month}, $options{year});
474
    if ($isSingleHoliday->rows) {
475
        my $id = $isSingleHoliday->fetchrow;
476
        $isSingleHoliday->finish; # Close the last query
477
478
        my $deleteHoliday = $dbh->prepare("DELETE FROM special_holidays WHERE id = ?");
479
        $deleteHoliday->execute($id);
480
        delete($self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"});
481
    } else {
482
        $isSingleHoliday->finish; # Close the last query
483
484
        my $isWeekdayHoliday = $dbh->prepare("SELECT id FROM repeatable_holidays WHERE branchcode = ? AND weekday = ?");
485
        $isWeekdayHoliday->execute($self->{branchcode}, $options{weekday});
486
        if ($isWeekdayHoliday->rows) {
487
            my $id = $isWeekdayHoliday->fetchrow;
488
            $isWeekdayHoliday->finish; # Close the last query
489
490
            my $updateExceptions = $dbh->prepare("UPDATE special_holidays SET isexception = 0 WHERE (WEEKDAY(CONCAT(special_holidays.year,'-',special_holidays.month,'-',special_holidays.day)) = ?) AND (branchcode = ?)");
491
            $updateExceptions->execute($options{weekday}, $self->{branchcode});
492
            $updateExceptions->finish; # Close the last query
493
494
            my $deleteHoliday = $dbh->prepare("DELETE FROM repeatable_holidays WHERE id = ?");
495
            $deleteHoliday->execute($id);
496
            delete($self->{'week_days_holidays'}->{$options{weekday}});
497
        } else {
498
            $isWeekdayHoliday->finish; # Close the last query
499
500
            my $isDayMonthHoliday = $dbh->prepare("SELECT id FROM repeatable_holidays WHERE (branchcode = ?) AND (day = ?) AND (month = ?)");
501
            $isDayMonthHoliday->execute($self->{branchcode}, $options{day}, $options{month});
502
            if ($isDayMonthHoliday->rows) {
503
                my $id = $isDayMonthHoliday->fetchrow;
504
                $isDayMonthHoliday->finish;
505
                my $updateExceptions = $dbh->prepare("UPDATE special_holidays SET isexception = 0 WHERE (special_holidays.branchcode = ?) AND (special_holidays.day = ?) and (special_holidays.month = ?)");
506
                $updateExceptions->execute($self->{branchcode}, $options{day}, $options{month});
507
                $updateExceptions->finish; # Close the last query
508
509
                my $deleteHoliday = $dbh->prepare("DELETE FROM repeatable_holidays WHERE (id = ?)");
510
                $deleteHoliday->execute($id);
511
                delete($self->{'day_month_holidays'}->{"$options{month}/$options{day}"});
512
            }
513
        }
514
    }
515
    return $self;
516
}
517
=head2 delete_holiday_range
518
519
    delete_holiday_range(day => $day,
520
                   month => $month,
521
                   year => $year);
522
523
Delete a holiday range of dates for $self->{branchcode}.
524
525
C<$day> Is the day month to make the date to delete.
526
527
C<$month> Is month to make the date to delete.
528
529
C<$year> Is year to make the date to delete.
530
531
=cut
532
533
sub delete_holiday_range {
534
    my $self = shift;
535
    my %options = @_;
536
537
    my $dbh = C4::Context->dbh();
538
    my $sth = $dbh->prepare("DELETE FROM special_holidays WHERE (branchcode = ?) AND (day = ?) AND (month = ?) AND (year = ?)");
539
    $sth->execute($self->{branchcode}, $options{day}, $options{month}, $options{year});
540
}
541
542
=head2 delete_holiday_range_repeatable
543
544
    delete_holiday_range_repeatable(day => $day,
545
                   month => $month);
546
547
Delete a holiday for $self->{branchcode}.
548
549
C<$day> Is the day month to make the date to delete.
550
551
C<$month> Is month to make the date to delete.
552
553
=cut
554
555
sub delete_holiday_range_repeatable {
556
    my $self = shift;
557
    my %options = @_;
558
559
    my $dbh = C4::Context->dbh();
560
    my $sth = $dbh->prepare("DELETE FROM repeatable_holidays WHERE (branchcode = ?) AND (day = ?) AND (month = ?)");
561
    $sth->execute($self->{branchcode}, $options{day}, $options{month});
562
}
563
564
=head2 delete_exception_holiday_range
565
566
    delete_exception_holiday_range(weekday => $weekday
567
                   day => $day,
568
                   month => $month,
569
                   year => $year);
570
571
Delete a holiday for $self->{branchcode}.
572
573
C<$day> Is the day month to make the date to delete.
574
575
C<$month> Is month to make the date to delete.
576
577
C<$year> Is year to make the date to delete.
578
579
=cut
580
581
sub delete_exception_holiday_range {
582
    my $self = shift;
583
    my %options = @_;
584
585
    my $dbh = C4::Context->dbh();
586
    my $sth = $dbh->prepare("DELETE FROM special_holidays WHERE (branchcode = ?) AND (isexception = 1) AND (day = ?) AND (month = ?) AND (year = ?)");
587
    $sth->execute($self->{branchcode}, $options{day}, $options{month}, $options{year});
588
}
589
590
=head2 isHoliday
591
592
    $isHoliday = isHoliday($day, $month $year);
593
594
C<$day> Is the day to check whether if is a holiday or not.
595
596
C<$month> Is the month to check whether if is a holiday or not.
597
598
C<$year> Is the year to check whether if is a holiday or not.
599
600
=cut
601
602
sub isHoliday {
603
    my ($self, $day, $month, $year) = @_;
604
	# FIXME - date strings are stored in non-padded metric format. should change to iso.
605
	# FIXME - should change arguments to accept C4::Dates object
606
	$month=$month+0;
607
	$year=$year+0;
608
	$day=$day+0;
609
    my $weekday = &Date::Calc::Day_of_Week($year, $month, $day) % 7; 
610
    my $weekDays   = $self->get_week_days_holidays();
611
    my $dayMonths  = $self->get_day_month_holidays();
612
    my $exceptions = $self->get_exception_holidays();
613
    my $singles    = $self->get_single_holidays();
614
    if (defined($exceptions->{"$year/$month/$day"})) {
615
        return 0;
616
    } else {
617
        if ((exists($weekDays->{$weekday})) ||
618
            (exists($dayMonths->{"$month/$day"})) ||
619
            (exists($singles->{"$year/$month/$day"}))) {
620
		 	return 1;
621
        } else {
622
            return 0;
623
        }
624
    }
625
626
}
627
628
=head2 copy_to_branch
629
630
    $calendar->copy_to_branch($target_branch)
631
632
=cut
633
634
sub copy_to_branch {
635
    my ($self, $target_branch) = @_;
636
637
    croak "No target_branch" unless $target_branch;
638
639
    my $target_calendar = C4::Calendar->new(branchcode => $target_branch);
640
641
    my ($y, $m, $d) = Today();
642
    my $today = sprintf ISO_DATE_FORMAT, $y,$m,$d;
643
644
    my $wdh = $self->get_week_days_holidays;
645
    $target_calendar->insert_week_day_holiday( weekday => $_, %{ $wdh->{$_} } )
646
      foreach keys %$wdh;
647
    $target_calendar->insert_day_month_holiday(%$_)
648
      foreach values %{ $self->get_day_month_holidays };
649
    $target_calendar->insert_exception_holiday(%$_)
650
      foreach grep { $_->{date} gt $today } values %{ $self->get_exception_holidays };
651
    $target_calendar->insert_single_holiday(%$_)
652
      foreach grep { $_->{date} gt $today } values %{ $self->get_single_holidays };
653
654
    return 1;
655
}
656
657
=head2 addDate
658
659
    my ($day, $month, $year) = $calendar->addDate($date, $offset)
660
661
C<$date> is a C4::Dates object representing the starting date of the interval.
662
663
C<$offset> Is the number of days that this function has to count from $date.
664
665
=cut
666
667
sub addDate {
668
    my ($self, $startdate, $offset) = @_;
669
    my ($year,$month,$day) = split("-",$startdate->output('iso'));
670
	my $daystep = 1;
671
	if ($offset < 0) { # In case $offset is negative
672
       # $offset = $offset*(-1);
673
		$daystep = -1;
674
    }
675
	my $daysMode = C4::Context->preference('useDaysMode');
676
    if ($daysMode eq 'Datedue') {
677
        ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $offset );
678
	 	while ($self->isHoliday($day, $month, $year)) {
679
            ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $daystep);
680
        }
681
    } elsif($daysMode eq 'Calendar') {
682
        while ($offset !=  0) {
683
            ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $daystep);
684
            if (!($self->isHoliday($day, $month, $year))) {
685
                $offset = $offset - $daystep;
686
			}
687
        }
688
	} else { ## ($daysMode eq 'Days') 
689
        ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $offset );
690
    }
691
    return(C4::Dates->new( sprintf(ISO_DATE_FORMAT,$year,$month,$day),'iso'));
692
}
693
694
=head2 daysBetween
695
696
    my $daysBetween = $calendar->daysBetween($startdate, $enddate)
697
698
C<$startdate> and C<$enddate> are C4::Dates objects that define the interval.
699
700
Returns the number of non-holiday days in the interval.
701
useDaysMode syspref has no effect here.
702
=cut
703
704
sub daysBetween {
705
    my $self      = shift or return;
706
    my $startdate = shift or return;
707
    my $enddate   = shift or return;
708
    my ($yearFrom,$monthFrom,$dayFrom) = split("-",$startdate->output('iso'));
709
    my ($yearTo,  $monthTo,  $dayTo  ) = split("-",  $enddate->output('iso'));
710
    if (Date_to_Days($yearFrom,$monthFrom,$dayFrom) > Date_to_Days($yearTo,$monthTo,$dayTo)) {
711
        return 0;
712
        # we don't go backwards  ( FIXME - handle this error better )
713
    }
714
    my $count = 0;
715
    while (1) {
716
        ($yearFrom != $yearTo or $monthFrom != $monthTo or $dayFrom != $dayTo) or last; # if they all match, it's the last day
717
        unless ($self->isHoliday($dayFrom, $monthFrom, $yearFrom)) {
718
            $count++;
719
        }
720
        ($yearFrom, $monthFrom, $dayFrom) = &Date::Calc::Add_Delta_Days($yearFrom, $monthFrom, $dayFrom, 1);
721
    }
722
    return($count);
723
}
724
222
725
1;
223
1;
726
224
(-)a/C4/Circulation.pm (-88 lines)
Lines 3101-3194 sub CalcDateDue { Link Here
3101
}
3101
}
3102
3102
3103
3103
3104
=head2 CheckRepeatableHolidays
3105
3106
  $countrepeatable = CheckRepeatableHoliday($itemnumber,$week_day,$branchcode);
3107
3108
This function checks if the date due is a repeatable holiday
3109
3110
C<$date_due>   = returndate calculate with no day check
3111
C<$itemnumber>  = itemnumber
3112
C<$branchcode>  = localisation of issue 
3113
3114
=cut
3115
3116
sub CheckRepeatableHolidays{
3117
my($itemnumber,$week_day,$branchcode)=@_;
3118
my $dbh = C4::Context->dbh;
3119
my $query = qq|SELECT count(*)  
3120
	FROM repeatable_holidays 
3121
	WHERE branchcode=?
3122
	AND weekday=?|;
3123
my $sth = $dbh->prepare($query);
3124
$sth->execute($branchcode,$week_day);
3125
my $result=$sth->fetchrow;
3126
$sth->finish;
3127
return $result;
3128
}
3129
3130
3131
=head2 CheckSpecialHolidays
3132
3133
  $countspecial = CheckSpecialHolidays($years,$month,$day,$itemnumber,$branchcode);
3134
3135
This function check if the date is a special holiday
3136
3137
C<$years>   = the years of datedue
3138
C<$month>   = the month of datedue
3139
C<$day>     = the day of datedue
3140
C<$itemnumber>  = itemnumber
3141
C<$branchcode>  = localisation of issue 
3142
3143
=cut
3144
3145
sub CheckSpecialHolidays{
3146
my ($years,$month,$day,$itemnumber,$branchcode) = @_;
3147
my $dbh = C4::Context->dbh;
3148
my $query=qq|SELECT count(*) 
3149
	     FROM `special_holidays`
3150
	     WHERE year=?
3151
	     AND month=?
3152
	     AND day=?
3153
             AND branchcode=?
3154
	    |;
3155
my $sth = $dbh->prepare($query);
3156
$sth->execute($years,$month,$day,$branchcode);
3157
my $countspecial=$sth->fetchrow ;
3158
$sth->finish;
3159
return $countspecial;
3160
}
3161
3162
=head2 CheckRepeatableSpecialHolidays
3163
3164
  $countspecial = CheckRepeatableSpecialHolidays($month,$day,$itemnumber,$branchcode);
3165
3166
This function check if the date is a repeatble special holidays
3167
3168
C<$month>   = the month of datedue
3169
C<$day>     = the day of datedue
3170
C<$itemnumber>  = itemnumber
3171
C<$branchcode>  = localisation of issue 
3172
3173
=cut
3174
3175
sub CheckRepeatableSpecialHolidays{
3176
my ($month,$day,$itemnumber,$branchcode) = @_;
3177
my $dbh = C4::Context->dbh;
3178
my $query=qq|SELECT count(*) 
3179
	     FROM `repeatable_holidays`
3180
	     WHERE month=?
3181
	     AND day=?
3182
             AND branchcode=?
3183
	    |;
3184
my $sth = $dbh->prepare($query);
3185
$sth->execute($month,$day,$branchcode);
3186
my $countspecial=$sth->fetchrow ;
3187
$sth->finish;
3188
return $countspecial;
3189
}
3190
3191
3192
3104
3193
sub CheckValidBarcode{
3105
sub CheckValidBarcode{
3194
my ($barcode) = @_;
3106
my ($barcode) = @_;
(-)a/C4/Overdues.pm (-124 lines)
Lines 306-435 sub _get_chargeable_units { Link Here
306
}
306
}
307
307
308
308
309
=head2 GetSpecialHolidays
310
311
    &GetSpecialHolidays($date_dues,$itemnumber);
312
313
return number of special days  between date of the day and date due
314
315
C<$date_dues> is the envisaged date of book return.
316
317
C<$itemnumber> is the book's item number.
318
319
=cut
320
321
sub GetSpecialHolidays {
322
    my ( $date_dues, $itemnumber ) = @_;
323
324
    # calcul the today date
325
    my $today = join "-", &Today();
326
327
    # return the holdingbranch
328
    my $iteminfo = GetIssuesIteminfo($itemnumber);
329
330
    # use sql request to find all date between date_due and today
331
    my $dbh = C4::Context->dbh;
332
    my $query =
333
      qq|SELECT DATE_FORMAT(concat(year,'-',month,'-',day),'%Y-%m-%d') as date
334
FROM `special_holidays`
335
WHERE DATE_FORMAT(concat(year,'-',month,'-',day),'%Y-%m-%d') >= ?
336
AND   DATE_FORMAT(concat(year,'-',month,'-',day),'%Y-%m-%d') <= ?
337
AND branchcode=?
338
|;
339
    my @result = GetWdayFromItemnumber($itemnumber);
340
    my @result_date;
341
    my $wday;
342
    my $dateinsec;
343
    my $sth = $dbh->prepare($query);
344
    $sth->execute( $date_dues, $today, $iteminfo->{'branchcode'} )
345
      ;    # FIXME: just use NOW() in SQL instead of passing in $today
346
347
    while ( my $special_date = $sth->fetchrow_hashref ) {
348
        push( @result_date, $special_date );
349
    }
350
351
    my $specialdaycount = scalar(@result_date);
352
353
    for ( my $i = 0 ; $i < scalar(@result_date) ; $i++ ) {
354
        $dateinsec = UnixDate( $result_date[$i]->{'date'}, "%o" );
355
        ( undef, undef, undef, undef, undef, undef, $wday, undef, undef ) =
356
          localtime($dateinsec);
357
        for ( my $j = 0 ; $j < scalar(@result) ; $j++ ) {
358
            if ( $wday == ( $result[$j]->{'weekday'} ) ) {
359
                $specialdaycount--;
360
            }
361
        }
362
    }
363
364
    return $specialdaycount;
365
}
366
367
=head2 GetRepeatableHolidays
368
369
    &GetRepeatableHolidays($date_dues, $itemnumber, $difference,);
370
371
return number of day closed between date of the day and date due
372
373
C<$date_dues> is the envisaged date of book return.
374
375
C<$itemnumber> is item number.
376
377
C<$difference> numbers of between day date of the day and date due
378
379
=cut
380
381
sub GetRepeatableHolidays {
382
    my ( $date_dues, $itemnumber, $difference ) = @_;
383
    my $dateinsec = UnixDate( $date_dues, "%o" );
384
    my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
385
      localtime($dateinsec);
386
    my @result = GetWdayFromItemnumber($itemnumber);
387
    my @dayclosedcount;
388
    my $j;
389
390
    for ( my $i = 0 ; $i < scalar(@result) ; $i++ ) {
391
        my $k = $wday;
392
393
        for ( $j = 0 ; $j < $difference ; $j++ ) {
394
            if ( $result[$i]->{'weekday'} == $k ) {
395
                push( @dayclosedcount, $k );
396
            }
397
            $k++;
398
            ( $k = 0 ) if ( $k eq 7 );
399
        }
400
    }
401
    return scalar(@dayclosedcount);
402
}
403
404
405
=head2 GetWayFromItemnumber
406
407
    &Getwdayfromitemnumber($itemnumber);
408
409
return the different week day from repeatable_holidays table
410
411
C<$itemnumber> is  item number.
412
413
=cut
414
415
sub GetWdayFromItemnumber {
416
    my ($itemnumber) = @_;
417
    my $iteminfo = GetIssuesIteminfo($itemnumber);
418
    my @result;
419
    my $query = qq|SELECT weekday
420
    FROM repeatable_holidays
421
    WHERE branchcode=?
422
|;
423
    my $sth = C4::Context->dbh->prepare($query);
424
425
    $sth->execute( $iteminfo->{'branchcode'} );
426
    while ( my $weekday = $sth->fetchrow_hashref ) {
427
        push( @result, $weekday );
428
    }
429
    return @result;
430
}
431
432
433
=head2 GetIssuesIteminfo
309
=head2 GetIssuesIteminfo
434
310
435
    &GetIssuesIteminfo($itemnumber);
311
    &GetIssuesIteminfo($itemnumber);
(-)a/Koha/Calendar.pm (-168 / +174 lines)
Lines 18-27 sub new { Link Here
18
        my $o = lc $o_name;
18
        my $o = lc $o_name;
19
        $self->{$o} = $options{$o_name};
19
        $self->{$o} = $options{$o_name};
20
    }
20
    }
21
    if ( exists $options{TEST_MODE} ) {
22
        $self->_mockinit();
23
        return $self;
24
    }
25
    if ( !defined $self->{branchcode} ) {
21
    if ( !defined $self->{branchcode} ) {
26
        croak 'No branchcode argument passed to Koha::Calendar->new';
22
        croak 'No branchcode argument passed to Koha::Calendar->new';
27
    }
23
    }
Lines 33-89 sub _init { Link Here
33
    my $self       = shift;
29
    my $self       = shift;
34
    my $branch     = $self->{branchcode};
30
    my $branch     = $self->{branchcode};
35
    my $dbh        = C4::Context->dbh();
31
    my $dbh        = C4::Context->dbh();
36
    my $weekly_closed_days_sth = $dbh->prepare(
37
'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL'
38
    );
39
    $weekly_closed_days_sth->execute( $branch );
40
    $self->{weekly_closed_days} = [ 0, 0, 0, 0, 0, 0, 0 ];
41
    Readonly::Scalar my $sunday => 7;
42
    while ( my $tuple = $weekly_closed_days_sth->fetchrow_hashref ) {
43
        $self->{weekly_closed_days}->[ $tuple->{weekday} ] = 1;
44
    }
45
    my $day_month_closed_days_sth = $dbh->prepare(
46
'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL'
47
    );
48
    $day_month_closed_days_sth->execute( $branch );
49
    $self->{day_month_closed_days} = {};
50
    while ( my $tuple = $day_month_closed_days_sth->fetchrow_hashref ) {
51
        $self->{day_month_closed_days}->{ $tuple->{month} }->{ $tuple->{day} } =
52
          1;
53
    }
54
32
55
    my $exception_holidays_sth = $dbh->prepare(
33
    $self->{weekday_hours} = $dbh->selectall_hashref( q{
56
'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1'
34
        SELECT
57
    );
35
            weekday, open_hour, open_minute, close_hour, close_minute,
58
    $exception_holidays_sth->execute( $branch );
36
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
59
    my $dates = [];
37
        FROM calendar_repeats
60
    while ( my ( $day, $month, $year ) = $exception_holidays_sth->fetchrow ) {
38
        WHERE branchcode = ? AND weekday IS NOT NULL
61
        push @{$dates},
39
    }, 'weekday', { Slice => {} }, $branch ); 
62
          DateTime->new(
40
63
            day       => $day,
41
    my $day_month_hours = $dbh->selectall_arrayref( q{
64
            month     => $month,
42
        SELECT
65
            year      => $year,
43
            month, day, open_hour, open_minute, close_hour, close_minute,
66
            time_zone => C4::Context->tz()
44
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
67
          )->truncate( to => 'day' );
45
        FROM calendar_repeats
46
        WHERE branchcode = ? AND weekday IS NULL
47
    }, { Slice => {} }, $branch );
48
49
    # DBD::Mock doesn't support multi-key selectall_hashref, so we do it ourselves for now
50
    foreach my $day_month ( @$day_month_hours ) {
51
        $self->{day_month_hours}->{ $day_month->{month} }->{ $day_month->{day} } = $day_month;
68
    }
52
    }
69
    $self->{exception_holidays} =
53
70
      DateTime::Set->from_datetimes( dates => $dates );
54
    $self->{date_hours} = $dbh->selectall_hashref( q{
71
55
        SELECT
72
    my $single_holidays_sth = $dbh->prepare(
56
            event_date, open_hour, open_minute, close_hour, close_minute,
73
'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0'
57
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
74
    );
58
        FROM calendar_events
75
    $single_holidays_sth->execute( $branch );
59
        WHERE branchcode = ?
76
    $dates = [];
60
    }, 'event_date', { Slice => {} }, $branch );
77
    while ( my ( $day, $month, $year ) = $single_holidays_sth->fetchrow ) {
61
78
        push @{$dates},
79
          DateTime->new(
80
            day       => $day,
81
            month     => $month,
82
            year      => $year,
83
            time_zone => C4::Context->tz()
84
          )->truncate( to => 'day' );
85
    }
86
    $self->{single_holidays} = DateTime::Set->from_datetimes( dates => $dates );
87
    $self->{days_mode}       = C4::Context->preference('useDaysMode');
62
    $self->{days_mode}       = C4::Context->preference('useDaysMode');
88
    $self->{test}            = 0;
63
    $self->{test}            = 0;
89
    return;
64
    return;
Lines 101-110 sub addDate { Link Here
101
    my $dt;
76
    my $dt;
102
77
103
    if ( $unit eq 'hours' ) {
78
    if ( $unit eq 'hours' ) {
104
        # Fixed for legacy support. Should be set as a branch parameter
79
        $dt = $self->addHours($startdate, $add_duration);
105
        Readonly::Scalar my $return_by_hour => 10;
106
107
        $dt = $self->addHours($startdate, $add_duration, $return_by_hour);
108
    } else {
80
    } else {
109
        # days
81
        # days
110
        $dt = $self->addDays($startdate, $add_duration);
82
        $dt = $self->addDays($startdate, $add_duration);
Lines 114-138 sub addDate { Link Here
114
}
86
}
115
87
116
sub addHours {
88
sub addHours {
117
    my ( $self, $startdate, $hours_duration, $return_by_hour ) = @_;
89
    my ( $self, $startdate, $hours_duration ) = @_;
118
    my $base_date = $startdate->clone();
90
    my $base_date = $startdate->clone();
119
91
120
    $base_date->add_duration($hours_duration);
92
    if ( $self->{days_mode} eq 'Days' ) {
93
        $base_date->add_duration( $hours_duration );
94
        return $base_date;
95
    }
96
    my $hours = $self->get_hours_full( $base_date );
97
98
    if ( $hours_duration->is_negative() ) {
99
        if ( $base_date <= $hours->{open_time} ) {
100
            # Library is already closed
101
            $base_date = $self->prev_open_day( $base_date );
102
            $hours = $self->get_hours_full( $base_date );
103
            $base_date = $hours->{close_time}->clone;
104
105
            if ( $self->{days_mode} eq 'Calendar' ) {
106
                return $base_date;
107
            }
108
        }
121
109
122
    # If we are using the calendar behave for now as if Datedue
110
        while ( $hours_duration->is_negative ) {
123
    # was the chosen option (current intended behaviour)
111
            my $day_len = $hours->{open_time} - $base_date;
124
112
125
    if ( $self->{days_mode} ne 'Days' &&
113
            if ( DateTime::Duration->compare( $day_len, $hours_duration, $base_date ) > 0 ) {
126
          $self->is_holiday($base_date) ) {
114
                if ( $self->{days_mode} eq 'Calendar' ) { 
115
                    return $hours->{open_time};
116
                }
127
117
128
        if ( $hours_duration->is_negative() ) {
118
                $hours_duration->subtract( $day_len );
129
            $base_date = $self->prev_open_day($base_date);
119
                $base_date = $self->prev_open_day( $base_date );
130
        } else {
120
                $hours = $self->get_hours_full( $base_date );
131
            $base_date = $self->next_open_day($base_date);
121
                $base_date = $hours->{close_time}->clone;
122
            } else {
123
                $base_date->add_duration( $hours_duration );
124
                return $base_date;
125
            }
126
        }
127
    } else {
128
        if ( $base_date >= $hours->{close_time} ) {
129
            # Library is already closed
130
            $base_date = $self->next_open_day( $base_date );
131
            $hours = $self->get_hours_full( $base_date );
132
            $base_date = $hours->{open_time}->clone;
133
134
            if ( $self->{days_mode} eq 'Calendar' ) {
135
                return $base_date;
136
            }
132
        }
137
        }
133
138
134
        $base_date->set_hour($return_by_hour);
139
        while ( $hours_duration->is_positive ) {
140
            my $day_len = $hours->{close_time} - $base_date;
141
142
            if ( DateTime::Duration->compare( $day_len, $hours_duration, $base_date ) < 0 ) {
143
                if ( $self->{days_mode} eq 'Calendar' ) { 
144
                    return $hours->{close_time};
145
                }
135
146
147
                $hours_duration->subtract( $day_len );
148
                $base_date = $self->next_open_day( $base_date );
149
                $hours = $self->get_hours_full( $base_date );
150
                $base_date = $hours->{open_time}->clone;
151
            } else {
152
                $base_date->add_duration( $hours_duration );
153
                return $base_date;
154
            }
155
        }
136
    }
156
    }
137
157
138
    return $base_date;
158
    return $base_date;
Lines 182-214 sub addDays { Link Here
182
202
183
sub is_holiday {
203
sub is_holiday {
184
    my ( $self, $dt ) = @_;
204
    my ( $self, $dt ) = @_;
185
    my $localdt = $dt->clone();
205
    my $day   = $dt->day;
186
    my $day   = $localdt->day;
206
    my $month = $dt->month;
187
    my $month = $localdt->month;
188
189
    $localdt->truncate( to => 'day' );
190
207
191
    if ( $self->{exception_holidays}->contains($localdt) ) {
208
    if ( exists $self->{date_hours}->{ $dt->ymd } && !$self->{date_hours}->{ $dt->ymd }->{closed} ) {
192
        # exceptions are not holidays
193
        return 0;
209
        return 0;
194
    }
210
    }
195
211
196
    my $dow = $localdt->day_of_week;
212
    if ( ( $self->{day_month_hours}->{$month}->{$day} || {} )->{closed} ) {
197
    # Representation fix
198
    # TODO: Shouldn't we shift the rest of the $dow also?
199
    if ( $dow == 7 ) {
200
        $dow = 0;
201
    }
202
203
    if ( $self->{weekly_closed_days}->[$dow] == 1 ) {
204
        return 1;
213
        return 1;
205
    }
214
    }
206
215
207
    if ( exists $self->{day_month_closed_days}->{$month}->{$day} ) {
216
    # We use 0 for Sunday, not 7
217
    my $dow = $dt->day_of_week % 7;
218
219
    if ( ( $self->{weekday_hours}->{ $dow } || {} )->{closed} ) {
208
        return 1;
220
        return 1;
209
    }
221
    }
210
222
211
    if ( $self->{single_holidays}->contains($localdt) ) {
223
    if ( ( $self->{date_hours}->{ $dt->ymd } || {} )->{closed} ) {
212
        return 1;
224
        return 1;
213
    }
225
    }
214
226
Lines 216-221 sub is_holiday { Link Here
216
    return 0;
228
    return 0;
217
}
229
}
218
230
231
sub get_hours {
232
    my ( $self, $dt ) = @_;
233
    my $day   = $dt->day;
234
    my $month = $dt->month;
235
236
    if ( exists $self->{date_hours}->{ $dt->ymd } ) {
237
        return $self->{date_hours}->{ $dt->ymd };
238
    }
239
240
    if ( exists $self->{day_month_hours}->{$month}->{$day} ) {
241
        return $self->{day_month_hours}->{$month}->{$day};
242
    }
243
244
    # We use 0 for Sunday, not 7
245
    my $dow = $dt->day_of_week % 7;
246
247
    if ( exists $self->{weekday_hours}->{ $dow } ) {
248
        return $self->{weekday_hours}->{ $dow };
249
    }
250
251
    # Assume open
252
    return {
253
        open_hour => 0,
254
        open_minute => 0,
255
        close_hour => 24,
256
        close_minute => 0,
257
        closed => 0
258
    };
259
}
260
261
sub get_hours_full {
262
    my ( $self, $dt ) = @_;
263
264
    my $hours = { %{ $self->get_hours( $dt ) } };
265
266
    $hours->{open_time} = $dt
267
        ->clone->truncate( to => 'day' )
268
        ->set_hour( $hours->{open_hour} )
269
        ->set_minute( $hours->{open_minute} );
270
271
    if ( $hours->{close_hour} == 24 ) {
272
        $hours->{close_time} = $dt
273
            ->clone->truncate( to => 'day' )
274
            ->add( days => 1 );
275
    } else {
276
        $hours->{close_time} = $dt
277
            ->clone->truncate( to => 'day' )
278
            ->set_hour( $hours->{close_hour} )
279
            ->set_minute( $hours->{close_minute} );
280
    }
281
282
    return $hours;
283
}
284
219
sub next_open_day {
285
sub next_open_day {
220
    my ( $self, $dt ) = @_;
286
    my ( $self, $dt ) = @_;
221
    my $base_date = $dt->clone();
287
    my $base_date = $dt->clone();
Lines 273-353 sub hours_between { Link Here
273
    my ($self, $start_date, $end_date) = @_;
339
    my ($self, $start_date, $end_date) = @_;
274
    my $start_dt = $start_date->clone();
340
    my $start_dt = $start_date->clone();
275
    my $end_dt = $end_date->clone();
341
    my $end_dt = $end_date->clone();
276
    my $duration = $end_dt->delta_ms($start_dt);
342
277
    $start_dt->truncate( to => 'day' );
343
    if ( $start_dt->compare($end_dt) > 0 ) {
278
    $end_dt->truncate( to => 'day' );
344
        # swap dates
279
    # NB this is a kludge in that it assumes all days are 24 hours
345
        my $int_dt = $end_dt;
280
    # However for hourly loans the logic should be expanded to
346
        $end_dt = $start_dt;
281
    # take into account open/close times then it would be a duration
347
        $start_dt = $int_dt;
282
    # of library open hours
283
    my $skipped_days = 0;
284
    for (my $dt = $start_dt->clone();
285
        $dt <= $end_dt;
286
        $dt->add(days => 1)
287
    ) {
288
        if ($self->is_holiday($dt)) {
289
            ++$skipped_days;
290
        }
291
    }
292
    if ($skipped_days) {
293
        $duration->subtract_duration(DateTime::Duration->new( hours => 24 * $skipped_days));
294
    }
348
    }
295
349
296
    return $duration;
350
    my $start_hours = $self->get_hours_full( $start_dt );
351
    my $end_hours = $self->get_hours_full( $end_dt );
297
352
298
}
353
    $start_dt = $start_hours->{open_time} if ( $start_dt < $start_hours->{open_time} );
354
    $end_dt = $end_hours->{close_time} if ( $end_dt > $end_hours->{close_time} );
299
355
300
sub _mockinit {
356
    return $end_dt - $start_dt if ( $start_dt->ymd eq $end_dt->ymd );
301
    my $self = shift;
302
    $self->{weekly_closed_days} = [ 1, 0, 0, 0, 0, 0, 0 ];    # Sunday only
303
    $self->{day_month_closed_days} = { 6 => { 16 => 1, } };
304
    my $dates = [];
305
    $self->{exception_holidays} =
306
      DateTime::Set->from_datetimes( dates => $dates );
307
    my $special = DateTime->new(
308
        year      => 2011,
309
        month     => 6,
310
        day       => 1,
311
        time_zone => 'Europe/London',
312
    );
313
    push @{$dates}, $special;
314
    $self->{single_holidays} = DateTime::Set->from_datetimes( dates => $dates );
315
316
    # if not defined, days_mode defaults to 'Calendar'
317
    if ( !defined($self->{days_mode}) ) {
318
        $self->{days_mode} = 'Calendar';
319
    }
320
357
321
    $self->{test} = 1;
358
    my $duration = DateTime::Duration->new;
322
    return;
359
    
323
}
360
    $duration->add_duration( $start_hours->{close_time} - $start_dt ) if ( $start_dt < $start_hours->{close_time} );
324
361
325
sub set_daysmode {
362
    for (my $date = $start_dt->clone->truncate( to => 'day' )->add( days => 1 );
326
    my ( $self, $mode ) = @_;
363
        $date->ymd lt $end_dt->ymd;
364
        $date->add(days => 1)
365
    ) {
366
        my $hours = $self->get_hours_full( $date );
327
367
328
    # if not testing this is a no op
368
        $duration->add_duration( $hours->{close_time}->delta_ms( $hours->{open_time} ) );
329
    if ( $self->{test} ) {
330
        $self->{days_mode} = $mode;
331
    }
369
    }
332
370
333
    return;
371
    $duration->add_duration( $end_dt - $end_hours->{open_time} ) if ( $end_dt > $start_hours->{open_time} );
334
}
335
336
sub clear_weekly_closed_days {
337
    my $self = shift;
338
    $self->{weekly_closed_days} = [ 0, 0, 0, 0, 0, 0, 0 ];    # Sunday only
339
    return;
340
}
341
372
342
sub add_holiday {
373
    return $duration;
343
    my $self = shift;
344
    my $new_dt = shift;
345
    my @dt = $self->{single_holidays}->as_list;
346
    push @dt, $new_dt;
347
    $self->{single_holidays} =
348
      DateTime::Set->from_datetimes( dates => \@dt );
349
374
350
    return;
351
}
375
}
352
376
353
1;
377
1;
Lines 403-416 parameter will be removed when issuingrules properly cope with that Link Here
403
427
404
=head2 addHours
428
=head2 addHours
405
429
406
    my $dt = $calendar->addHours($date, $dur, $return_by_hour )
430
    my $dt = $calendar->addHours($date, $dur )
407
431
408
C<$date> is a DateTime object representing the starting date of the interval.
432
C<$date> is a DateTime object representing the starting date of the interval.
409
433
410
C<$offset> is a DateTime::Duration to add to it
434
C<$offset> is a DateTime::Duration to add to it
411
435
412
C<$return_by_hour> is an integer value representing the opening hour for the branch
413
414
436
415
=head2 addDays
437
=head2 addDays
416
438
Lines 457-478 Passed a Datetime returns another Datetime representing the previous open day. I Link Here
457
intended for use to calculate the due date when useDaysMode syspref is set to either
479
intended for use to calculate the due date when useDaysMode syspref is set to either
458
'Datedue' or 'Calendar'.
480
'Datedue' or 'Calendar'.
459
481
460
=head2 set_daysmode
461
462
For testing only allows the calling script to change days mode
463
464
=head2 clear_weekly_closed_days
465
466
In test mode changes the testing set of closed days to a new set with
467
no closed days. TODO passing an array of closed days to this would
468
allow testing of more configurations
469
470
=head2 add_holiday
471
472
Passed a datetime object this will add it to the calendar's list of
473
closed days. This is for testing so that we can alter the Calenfar object's
474
list of specified dates
475
476
=head1 DIAGNOSTICS
482
=head1 DIAGNOSTICS
477
483
478
Will croak if not passed a branchcode in new
484
Will croak if not passed a branchcode in new
(-)a/installer/data/mysql/de-DE/optional/sample_holidays.sql (-5 / +5 lines)
Lines 1-5 Link Here
1
INSERT INTO `repeatable_holidays` VALUES
1
INSERT INTO `calendar_repeats` VALUES
2
(2,'MPL',0,NULL,NULL,'','Sonntag'),
2
(2,'MPL',0,NULL,NULL,'','Sonntag',0,0,0,0),
3
(3,'MPL',NULL,1,1,'','Neujahr'),
3
(3,'MPL',NULL,1,1,'','Neujahr',0,0,0,0),
4
(4,'MPL',NULL,25,12,'','1. Weihnachtsfeiertag'),
4
(4,'MPL',NULL,12,25,'','1. Weihnachtsfeiertag',0,0,0,0),
5
(5,'MPL',NULL,25,12,'','2. Weihnachtsfeiertag');
5
(5,'MPL',NULL,12,25,'','2. Weihnachtsfeiertag',0,0,0,0);
(-)a/installer/data/mysql/en/optional/sample_holidays.sql (-4 / +4 lines)
Lines 1-4 Link Here
1
INSERT INTO `repeatable_holidays` VALUES 
1
INSERT INTO `calendar_repeats` VALUES 
2
(2,'MPL',0,NULL,NULL,'','Sundays'),
2
(2,'MPL',0,NULL,NULL,'','Sundays',0,0,0,0),
3
(3,'MPL',NULL,1,1,'','New Year\'s Day'),
3
(3,'MPL',NULL,1,1,'','New Year\'s Day',0,0,0,0),
4
(4,'MPL',NULL,25,12,'','Christmas');
4
(4,'MPL',NULL,12,25,'','Christmas',0,0,0,0);
(-)a/installer/data/mysql/es-ES/optional/sample_holidays.sql (-4 / +4 lines)
Lines 1-4 Link Here
1
INSERT INTO `repeatable_holidays` VALUES 
1
INSERT INTO `calendar_repeats` VALUES 
2
(2,'',0,NULL,NULL,'','Sundays'),
2
(2,'',0,NULL,NULL,'','Sundays',0,0,0,0),
3
(3,'',NULL,1,1,'','New Year\'s Day'),
3
(3,'',NULL,1,1,'','New Year\'s Day',0,0,0,0),
4
(4,'',NULL,25,12,'','Christmas');
4
(4,'',NULL,12,25,'','Christmas',0,0,0,0);
(-)a/installer/data/mysql/it-IT/necessari/sample_holidays.sql (-5 / +5 lines)
Lines 1-8 Link Here
1
SET FOREIGN_KEY_CHECKS=0;
1
SET FOREIGN_KEY_CHECKS=0;
2
2
3
INSERT INTO `repeatable_holidays` VALUES 
3
INSERT INTO `calendar_repeats` VALUES 
4
(2,'',0,NULL,NULL,'','Domenica'),
4
(2,'',0,NULL,NULL,'','Domenica',0,0,0,0),
5
(3,'',NULL,1,1,'','Nuovo anno'),
5
(3,'',NULL,1,1,'','Nuovo anno',0,0,0,0),
6
(4,'',NULL,25,12,'','Natale');
6
(4,'',NULL,12,25,'','Natale',0,0,0,0);
7
7
8
SET FOREIGN_KEY_CHECKS=1;
8
SET FOREIGN_KEY_CHECKS=1;
(-)a/installer/data/mysql/kohastructure.sql (-33 / +37 lines)
Lines 640-645 CREATE TABLE `default_circ_rules` ( Link Here
640
    PRIMARY KEY (`singleton`)
640
    PRIMARY KEY (`singleton`)
641
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
641
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
642
642
643
644
--
645
-- Table structure for table `calendar_events`
646
--
647
DROP TABLE IF EXISTS `calendar_events`;
648
CREATE TABLE `calendar_events` (
649
    `branchcode` varchar(10) NOT NULL DEFAULT '',
650
    `event_date` date NOT NULL,
651
    `title` varchar(50) NOT NULL DEFAULT '',
652
    `description` text NOT NULL,
653
    `open_hour` smallint(6) NOT NULL,
654
    `open_minute` smallint(6) NOT NULL,
655
    `close_hour` smallint(6) NOT NULL,
656
    `close_minute` smallint(6) NOT NULL,
657
    PRIMARY KEY (`branchcode`,`event_date`),
658
    CONSTRAINT `calendar_events_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`)
659
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
660
661
--
662
-- Table structure for table `calendar_repeats`
663
--
664
DROP TABLE IF EXISTS `calendar_repeats`;
665
CREATE TABLE `calendar_repeats` (
666
    `branchcode` varchar(10) NOT NULL DEFAULT '',
667
    `weekday` smallint(6) DEFAULT NULL,
668
    `month` smallint(6) DEFAULT NULL,
669
    `day` smallint(6) DEFAULT NULL,
670
    `title` varchar(50) NOT NULL DEFAULT '',
671
    `description` text NOT NULL,
672
    `open_hour` smallint(6) NOT NULL,
673
    `open_minute` smallint(6) NOT NULL,
674
    `close_hour` smallint(6) NOT NULL,
675
    `close_minute` smallint(6) NOT NULL,
676
    UNIQUE KEY `branchcode` (`branchcode`,`weekday`),
677
    UNIQUE KEY `branchcode_2` (`branchcode`,`month`,`day`),
678
    CONSTRAINT `calendar_repeats_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`)
679
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
643
--
680
--
644
-- Table structure for table `cities`
681
-- Table structure for table `cities`
645
--
682
--
Lines 1719-1740 CREATE TABLE `printers_profile` ( Link Here
1719
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1756
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1720
1757
1721
--
1758
--
1722
-- Table structure for table `repeatable_holidays`
1723
--
1724
1725
DROP TABLE IF EXISTS `repeatable_holidays`;
1726
CREATE TABLE `repeatable_holidays` ( -- information for the days the library is closed
1727
  `id` int(11) NOT NULL auto_increment, -- unique identifier assigned by Koha
1728
  `branchcode` varchar(10) NOT NULL default '', -- foreign key from the branches table, defines which branch this closing is for
1729
  `weekday` smallint(6) default NULL, -- day of the week (0=Sunday, 1=Monday, etc) this closing is repeated on
1730
  `day` smallint(6) default NULL, -- day of the month this closing is on
1731
  `month` smallint(6) default NULL, -- month this closing is in
1732
  `title` varchar(50) NOT NULL default '', -- title of this closing
1733
  `description` text NOT NULL, -- description for this closing
1734
  PRIMARY KEY  (`id`)
1735
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1736
1737
--
1738
-- Table structure for table `reports_dictionary`
1759
-- Table structure for table `reports_dictionary`
1739
--
1760
--
1740
1761
Lines 1917-1939 CREATE TABLE sessions ( Link Here
1917
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1938
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1918
1939
1919
--
1940
--
1920
-- Table structure for table `special_holidays`
1921
--
1922
1923
DROP TABLE IF EXISTS `special_holidays`;
1924
CREATE TABLE `special_holidays` ( -- non repeatable holidays/library closings
1925
  `id` int(11) NOT NULL auto_increment, -- unique identifier assigned by Koha
1926
  `branchcode` varchar(10) NOT NULL default '', -- foreign key from the branches table, defines which branch this closing is for
1927
  `day` smallint(6) NOT NULL default 0, -- day of the month this closing is on
1928
  `month` smallint(6) NOT NULL default 0, -- month this closing is in
1929
  `year` smallint(6) NOT NULL default 0, -- year this closing is in
1930
  `isexception` smallint(1) NOT NULL default 1, -- is this a holiday exception to a repeatable holiday (1 for yes, 0 for no)
1931
  `title` varchar(50) NOT NULL default '', -- title for this closing
1932
  `description` text NOT NULL, -- description of this closing
1933
  PRIMARY KEY  (`id`)
1934
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1935
1936
--
1937
-- Table structure for table `statistics`
1941
-- Table structure for table `statistics`
1938
--
1942
--
1939
1943
(-)a/installer/data/mysql/nb-NO/2-Valgfritt/sample_holidays.sql (-7 / +7 lines)
Lines 19-28 Link Here
19
-- with Koha; if not, write to the Free Software Foundation, Inc.,
19
-- with Koha; if not, write to the Free Software Foundation, Inc.,
20
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
21
22
INSERT INTO `repeatable_holidays` VALUES 
22
INSERT INTO `calendar_repeats` VALUES 
23
(2,'',0,NULL,NULL,'','Søndager'),
23
(2,'',0,NULL,NULL,'','Søndager',0,0,0,0),
24
(3,'',NULL,1,1,'','1. nyttårsdag'),
24
(3,'',NULL,1,1,'','1. nyttårsdag',0,0,0,0),
25
(4,'',NULL,1,5,'','1. mai'),
25
(4,'',NULL,5,1,'','1. mai',0,0,0,0),
26
(5,'',NULL,17,5,'','17. mai'),
26
(5,'',NULL,5,17,'','17. mai',0,0,0,0),
27
(6,'',NULL,25,12,'','1. juledag'),
27
(6,'',NULL,12,25,'','1. juledag',0,0,0,0),
28
(7,'',NULL,26,12,'','2. juledag');
28
(7,'',NULL,12,26,'','2. juledag',0,0,0,0);
(-)a/installer/data/mysql/pl-PL/optional/sample_holidays.sql (-4 / +4 lines)
Lines 1-4 Link Here
1
INSERT INTO `repeatable_holidays` VALUES
1
INSERT INTO `calendar_repeats` VALUES
2
(2,'',0,NULL,NULL,'','Niedziele'),
2
(2,'',0,NULL,NULL,'','Niedziele',0,0,0,0),
3
(3,'',NULL,1,1,'','Nowy Rok'),
3
(3,'',NULL,1,1,'','Nowy Rok',0,0,0,0),
4
(4,'',NULL,25,12,'','Boże Narodzenie');
4
(4,'',NULL,12,25,'','Boże Narodzenie',0,0,0,0);
(-)a/installer/data/mysql/ru-RU/optional/holidays.sql (-15 / +15 lines)
Lines 1-23 Link Here
1
TRUNCATE repeatable_holidays;
1
TRUNCATE calendar_repeats;
2
2
3
INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) 
3
INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) 
4
VALUES (2, '',0,NULL,NULL,'','Воскресенья');
4
VALUES ('',0,NULL,NULL,'','Воскресенья', 0, 0, 0, 0);
5
5
6
INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) 
6
INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) 
7
VALUES (3, '',NULL,1,1,'','Новый год');
7
VALUES ('',NULL,1,1,'','Новый год', 0, 0, 0, 0);
8
8
9
INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) 
9
INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) 
10
VALUES (4, '',NULL,7,1,'','Рождество');
10
VALUES ('',NULL,7,1,'','Рождество', 0, 0, 0, 0);
11
11
12
INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) 
12
INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) 
13
VALUES (5, '',NULL,8,3,'','Международный женский день');
13
VALUES ('',NULL,8,3,'','Международный женский день', 0, 0, 0, 0);
14
14
15
INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) 
15
INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) 
16
VALUES (6, '',NULL,1,5,'','День Труда');
16
VALUES ('',NULL,1,5,'','День Труда', 0, 0, 0, 0);
17
17
18
INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) 
18
INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) 
19
VALUES (7, '',NULL,2,5,'','День Труда');
19
VALUES ('',NULL,2,5,'','День Труда', 0, 0, 0, 0);
20
20
21
INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) 
21
INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) 
22
VALUES (8, '',NULL,9,5,'','День Победы');
22
VALUES ('',NULL,9,5,'','День Победы', 0, 0, 0, 0);
23
23
(-)a/installer/data/mysql/uk-UA/optional/holidays.sql (-21 / +21 lines)
Lines 1-24 Link Here
1
TRUNCATE repeatable_holidays;
1
TRUNCATE calendar_repeats;
2
2
3
INSERT INTO `repeatable_holidays` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`) VALUES
3
INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) VALUES
4
('STL', 0,    NULL, NULL,'', 'Неділі'),
4
('STL', 0,    NULL, NULL,'', 'Неділі', 0, 0, 0, 0),
5
('STL', NULL, 1,    1,   '', 'Новий рік'),
5
('STL', NULL, 1,    1,   '', 'Новий рік', 0, 0, 0, 0),
6
('STL', NULL, 7,    1,   '', 'Різдво'),
6
('STL', NULL, 7,    1,   '', 'Різдво', 0, 0, 0, 0),
7
('STL', NULL, 8,    3,   '', 'Міжнародний жіночий день'),
7
('STL', NULL, 8,    3,   '', 'Міжнародний жіночий день', 0, 0, 0, 0),
8
('STL', NULL, 1,    5,   '', 'День Праці'),
8
('STL', NULL, 1,    5,   '', 'День Праці', 0, 0, 0, 0),
9
('STL', NULL, 2,    5,   '', 'День Праці'),
9
('STL', NULL, 2,    5,   '', 'День Праці', 0, 0, 0, 0),
10
('STL', NULL, 9,    5,   '', 'День Перемоги'),
10
('STL', NULL, 9,    5,   '', 'День Перемоги', 0, 0, 0, 0),
11
('STL', NULL, 28,   6,   '', 'День Конституції'),
11
('STL', NULL, 28,   6,   '', 'День Конституції', 0, 0, 0, 0),
12
('STL', NULL, 24,   8,   '', 'День Незалежності');
12
('STL', NULL, 24,   8,   '', 'День Незалежності', 0, 0, 0, 0);
13
13
14
INSERT INTO `repeatable_holidays` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`) VALUES
14
INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) VALUES
15
('LNSL', 0,    NULL, NULL,'', 'Неділі'),
15
('LNSL', 0,    NULL, NULL,'', 'Неділі', 0, 0, 0, 0),
16
('LNSL', NULL, 1,    1,   '', 'Новий рік'),
16
('LNSL', NULL, 1,    1,   '', 'Новий рік', 0, 0, 0, 0),
17
('LNSL', NULL, 7,    1,   '', 'Різдво'),
17
('LNSL', NULL, 7,    1,   '', 'Різдво', 0, 0, 0, 0),
18
('LNSL', NULL, 8,    3,   '', 'Міжнародний жіночий день'),
18
('LNSL', NULL, 8,    3,   '', 'Міжнародний жіночий день', 0, 0, 0, 0),
19
('LNSL', NULL, 1,    5,   '', 'День Праці'),
19
('LNSL', NULL, 1,    5,   '', 'День Праці', 0, 0, 0, 0),
20
('LNSL', NULL, 2,    5,   '', 'День Праці'),
20
('LNSL', NULL, 2,    5,   '', 'День Праці', 0, 0, 0, 0),
21
('LNSL', NULL, 9,    5,   '', 'День Перемоги'),
21
('LNSL', NULL, 9,    5,   '', 'День Перемоги', 0, 0, 0, 0),
22
('LNSL', NULL, 28,   6,   '', 'День Конституції'),
22
('LNSL', NULL, 28,   6,   '', 'День Конституції', 0, 0, 0, 0),
23
('LNSL', NULL, 24,   8,   '', 'День Незалежності');
23
('LNSL', NULL, 24,   8,   '', 'День Незалежності', 0, 0, 0, 0);
24
24
(-)a/installer/data/mysql/updatedatabase.pl (+75 lines)
Lines 7010-7015 CREATE TABLE IF NOT EXISTS borrower_files ( Link Here
7010
    SetVersion($DBversion);
7010
    SetVersion($DBversion);
7011
}
7011
}
7012
7012
7013
$DBversion = "3.13.00.XXX";
7014
if ( CheckVersion($DBversion) ) {
7015
    print "Upgrade to $DBversion done (Bug 8133: create tables, migrate data to calendar_*)\n";
7016
7017
    $dbh->do( q{
7018
        CREATE TABLE `calendar_events` (
7019
          `branchcode` varchar(10) NOT NULL DEFAULT '',
7020
          `event_date` date NOT NULL,
7021
          `title` varchar(50) NOT NULL DEFAULT '',
7022
          `description` text NOT NULL,
7023
          `open_hour` smallint(6) NOT NULL,
7024
          `open_minute` smallint(6) NOT NULL,
7025
          `close_hour` smallint(6) NOT NULL,
7026
          `close_minute` smallint(6) NOT NULL,
7027
          PRIMARY KEY (`branchcode`,`event_date`),
7028
          CONSTRAINT `calendar_events_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`)
7029
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
7030
    } );
7031
7032
    $dbh->do( q{
7033
        CREATE TABLE `calendar_repeats` (
7034
          `branchcode` varchar(10) NOT NULL DEFAULT '',
7035
          `weekday` smallint(6) DEFAULT NULL,
7036
          `month` smallint(6) DEFAULT NULL,
7037
          `day` smallint(6) DEFAULT NULL,
7038
          `title` varchar(50) NOT NULL DEFAULT '',
7039
          `description` text NOT NULL,
7040
          `open_hour` smallint(6) NOT NULL,
7041
          `open_minute` smallint(6) NOT NULL,
7042
          `close_hour` smallint(6) NOT NULL,
7043
          `close_minute` smallint(6) NOT NULL,
7044
          UNIQUE KEY `branchcode` (`branchcode`,`weekday`),
7045
          UNIQUE KEY `branchcode_2` (`branchcode`,`month`,`day`),
7046
          CONSTRAINT `calendar_repeats_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`)
7047
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
7048
    } );
7049
7050
    $dbh->do( q{
7051
        INSERT INTO
7052
          calendar_events(branchcode, event_date, title, description, open_hour, open_minute, close_hour, close_minute)
7053
        SELECT
7054
          branchcode, CONCAT_WS('-', year, month, day), title, description, 0, 0, 0, 0
7055
          FROM special_holidays
7056
          WHERE isexception = 0
7057
    } );
7058
7059
    $dbh->do( q{
7060
        INSERT INTO
7061
          calendar_events(branchcode, event_date, title, description, open_hour, open_minute, close_hour, close_minute)
7062
        SELECT
7063
          branchcode, CONCAT_WS('-', year, month, day), title, description, 0, 0, 24, 0
7064
          FROM special_holidays
7065
          WHERE isexception = 1
7066
    } );
7067
7068
    $dbh->do( q{
7069
        INSERT INTO
7070
          calendar_repeats(branchcode, weekday, month, day, title, description, open_hour, open_minute, close_hour, close_minute)
7071
        SELECT
7072
          branchcode, weekday, month, day, title, description, 0, 0, 0, 0
7073
          FROM repeatable_holidays
7074
          WHERE weekday IS NULL
7075
    } );
7076
7077
    $dbh->do( q{
7078
        DROP TABLE repeatable_holidays;
7079
    } );
7080
7081
    $dbh->do( q{
7082
        DROP TABLE special_holidays;
7083
    } );
7084
7085
    SetVersion($DBversion);
7086
}
7087
7013
=head1 FUNCTIONS
7088
=head1 FUNCTIONS
7014
7089
7015
=head2 TableExists($table)
7090
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc (-1 / +1 lines)
Lines 81-87 Link Here
81
<h5>Additional tools</h5>
81
<h5>Additional tools</h5>
82
<ul>
82
<ul>
83
    [% IF ( CAN_user_tools_edit_calendar ) %]
83
    [% IF ( CAN_user_tools_edit_calendar ) %]
84
	<li><a href="/cgi-bin/koha/tools/holidays.pl">Calendar</a></li>
84
	<li><a href="/cgi-bin/koha/tools/calendar.pl">Calendar</a></li>
85
    [% END %]
85
    [% END %]
86
    [% IF ( CAN_user_tools_manage_csv_profiles ) %]
86
    [% IF ( CAN_user_tools_manage_csv_profiles ) %]
87
	<li><a href="/cgi-bin/koha/tools/csv-profiles.pl">CSV profiles</a></li>
87
	<li><a href="/cgi-bin/koha/tools/csv-profiles.pl">CSV profiles</a></li>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/calendar.tt (+597 lines)
Line 0 Link Here
1
[% USE 'KohaDates' %]
2
[% INCLUDE 'doc-head-open.inc' %]
3
<title>Koha &rsaquo; Tools &rsaquo; [% branchname %] Calendar</title>
4
[% INCLUDE 'doc-head-close.inc' %]
5
[% INCLUDE 'calendar.inc' %]
6
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
7
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.dataTables.min.js"></script>
8
[% INCLUDE 'datatables-strings.inc' %]
9
<script type="text/javascript" src="[% themelang %]/js/datatables.js"></script>
10
<script language="JavaScript" type="text/javascript">
11
//<![CDATA[
12
    [% IF (dateformat == 'metric') %]dt_add_type_uk_date();[% END %]
13
    var weekdays = new Array(_("Sundays"),_("Mondays"),_("Tuesdays"),_("Wednesdays"),_("Thursdays"),_("Fridays"),_("Saturdays"));
14
15
    var single_events = {
16
        [% FOREACH event IN single_events %]
17
        '[% event.event_date %]': {
18
            title: '[% event.title %]',
19
            description: '[% event.description %]',
20
            closed: [% event.closed %],
21
            eventType: 'single',
22
            open_hour: '[% event.open_hour %]',
23
            open_minute: '[% event.open_minute %]',
24
            close_hour: '[% event.close_hour %]',
25
            close_minute: '[% event.close_minute %]'
26
        },
27
        [% END %]
28
    };
29
30
    var weekly_events = {
31
        [% FOREACH event IN weekly_events %]
32
        [% event.weekday %]: {
33
            title: '[% event.title %]',
34
            description: '[% event.description %]',
35
            closed: [% event.closed %],
36
            eventType: 'weekly',
37
            weekday: [% event.weekday %],
38
            open_hour: '[% event.open_hour %]',
39
            open_minute: '[% event.open_minute %]',
40
            close_hour: '[% event.close_hour %]',
41
            close_minute: '[% event.close_minute %]'
42
        },
43
        [% END %]
44
    };
45
46
    var yearly_events = {
47
        [% FOREACH event IN yearly_events %]
48
        '[% event.month %]-[% event.day %]': {
49
            title: '[% event.title %]',
50
            description: '[% event.description %]',
51
            closed: [% event.closed %],
52
            eventType: 'yearly',
53
            month: [% event.month %],
54
            day: [% event.day %],
55
            open_hour: '[% event.open_hour %]',
56
            open_minute: '[% event.open_minute %]',
57
            close_hour: '[% event.close_hour %]',
58
            close_minute: '[% event.close_minute %]'
59
        },
60
        [% END %]
61
    };
62
63
    function eventOperation(formObject, opType) {
64
        var op = document.getElementsByName('op');
65
        op[0].value = opType;
66
        formObject.submit();
67
    }
68
69
    function zeroPad(value) {
70
        return value >= 10 ? value : ('0' + value);
71
    }
72
73
    // This function shows the "Show Event" panel //
74
    function showEvent(dayName, day, month, year, weekDay, event) {
75
        $("#newEvent").slideUp("fast");
76
        $("#showEvent").slideDown("fast");
77
        $('#showDaynameOutput').html(dayName);
78
        $('#showDayname').val(dayName);
79
        $('#showBranchNameOutput').html($("#branch :selected").text());
80
        $('#showBranchName').val($("#branch").val());
81
        $('#showDayOutput').html(day);
82
        $('#showDay').val(day);
83
        $('#showMonthOutput').html(month);
84
        $('#showMonth').val(month);
85
        $('#showYearOutput').html(year);
86
        $('#showYear').val(year);
87
        $('#showDescription').val(event.description);
88
        $('#showWeekday:first').val(weekDay);
89
        $('#showTitle').val(event.title);
90
        $('#showEventType').val(event.eventType);
91
        
92
        if (event.closed) {
93
            $('#showHoursTypeClosed')[0].checked = true;
94
        } else if (event.close_hour == 24) {
95
            $('#showHoursTypeOpen')[0].checked = true;
96
        } else {
97
            $('#showHoursTypeOpenSet')[0].checked = true;
98
            $('#showHoursTypeOpenSet').change();
99
            $('#showOpenTime').val(event.open_hour + ':' + zeroPad(event.open_minute)); 
100
            $('#showCloseTime').val(event.close_hour + ':' + zeroPad(event.close_minute)); 
101
        }
102
103
        $("#operationDelLabel").html(_("Delete this event."));
104
        if(event.eventType == 'weekly') {
105
            $("#holtype").attr("class","key repeatableweekly").html(_("Event repeating weekly"));
106
        } else if(event.eventType == 'yearly') {
107
            $("#holtype").attr("class","key repeatableyearly").html(_("Event repeating yearly"));
108
        } else {
109
            $("#holtype").attr("class","key event").html(_("Single event"));
110
        }
111
    }
112
113
    // This function shows the "Add Event" panel //
114
    function newEvent (dayName, day, month, year, weekDay) {
115
        $("#showEvent").slideUp("fast");
116
        $("#newEvent").slideDown("fast");
117
        $("#newDaynameOutput").html(dayName);
118
        $("#newDayname").val(dayName);
119
        $("#newBranchNameOutput").html($('#branch :selected').text());
120
        $("#newBranchName").val($('#branch').val());
121
        $("#newDayOutput").html(day);
122
        $("#newDay").val(day);
123
        $("#newMonthOutput").html(month);
124
        $("#newMonth").val(month);
125
        $("#newYearOutput").html(year);
126
        $("#newYear").val(year);
127
        $("#newWeekday:first").val(weekDay);
128
    }
129
130
    function hidePanel(aPanelName) {
131
        $("#"+aPanelName).slideUp("fast");
132
    }
133
134
    function changeBranch () {
135
        var branch = $("#branch option:selected").val();
136
        location.href='/cgi-bin/koha/tools/calendar.pl?branch=' + branch + '&calendardate=' + "[% calendardate %]";
137
    }
138
139
    /* This function gives css clases to each kind of day */
140
    function dateStatusHandler(date) {
141
        date = new Date(date);
142
        var day = date.getDate();
143
        var month = date.getMonth() + 1;
144
        var year = date.getFullYear();
145
        var weekDay = date.getDay();
146
        var dayMonth = month + '-' + day;
147
        var dateString = year + '-' + zeroPad(month) + '-' + zeroPad(day);
148
149
        if ( single_events[dateString] != null) {
150
            return [true, "event", "Single event: "+single_events[dateString].title];
151
        } else if ( yearly_events[dayMonth] != null ) {
152
            return [true, "repeatableyearly", "Yearly event: "+yearly_events[dayMonth].title];
153
        } else if ( weekly_events[weekDay] != null ){
154
            return [true, "repeatableweekly", "Weekly event: "+weekly_events[weekDay].title];
155
        } else {
156
            return [true, "normalday", "Normal day"];
157
        }
158
    }
159
160
    /* This function is in charge of showing the correct panel considering the kind of event */
161
    function dateChanged(calendar) {
162
        calendar = new Date(calendar);
163
        var day = calendar.getDate();
164
        var month = calendar.getMonth() + 1;
165
        var year = calendar.getFullYear();
166
        var weekDay = calendar.getDay();
167
        var dayName = weekdays[weekDay];
168
        var dayMonth = month + '-' + day;
169
        var dateString = year + '-' + zeroPad(month) + '-' + zeroPad(day);
170
        if ( single_events[dateString] != null ) {
171
            showEvent( dayName, day, month, year, weekDay, single_events[dateString] );
172
        } else if ( yearly_events[dayMonth] != null ) {
173
            showEvent( dayName, day, month, year, weekDay, yearly_events[dayMonth] );
174
        } else if ( weekly_events[weekDay] != null ) {
175
            showEvent( dayName, day, month, year, weekDay, weekly_events[weekDay] );
176
        } else {
177
            newEvent( dayName, day, month, year, weekDay );
178
        }
179
    };
180
181
    $(document).ready(function() {
182
183
        $(".hint").hide();
184
        $("#branch").change(function(){
185
            changeBranch();
186
        });
187
        $("#weekly-events,#single-events").dataTable($.extend(true, {}, dataTablesDefaults, {
188
            "sDom": 't',
189
            "bPaginate": false
190
        }));
191
        $("#yearly-events").dataTable($.extend(true, {}, dataTablesDefaults, {
192
            "sDom": 't',
193
            "aoColumns": [
194
                { "sType": "title-string" },null,null,null
195
            ],
196
            "bPaginate": false
197
        }));
198
        $("a.helptext").click(function(){
199
            $(this).parent().find(".hint").toggle(); return false;
200
        });
201
        $("#dateofrange").datepicker();
202
        $("#datecancelrange").datepicker();
203
        $("#dateofrange").each(function () { this.value = "" });
204
        $("#datecancelrange").each(function () { this.value = "" });
205
        $("#jcalendar-container").datepicker({
206
          beforeShowDay: function(thedate) {
207
            var day = thedate.getDate();
208
            var month = thedate.getMonth() + 1;
209
            var year = thedate.getFullYear();
210
            var dateString = year + '/' + month + '/' + day;
211
            return dateStatusHandler(dateString);
212
            },
213
            onSelect: function(dateText, inst) {
214
                dateChanged($(this).datepicker("getDate"));
215
            },
216
            defaultDate: new Date("[% keydate %]")
217
        });
218
        $(".hourssel input").change(function() {
219
            $(".hoursentry", this.form).toggle(this.value == 'openSet'); 
220
        }).each( function() { this.checked = false } );
221
    });
222
//]]>
223
</script>
224
<style type="text/css"> .key { padding : 3px; white-space:nowrap; line-height:230%; }
225
.ui-datepicker { font-size : 150%; }
226
.ui-datepicker th, .ui-datepicker .ui-datepicker-title select { font-size : 80%; }
227
.ui-datepicker td a { padding : .5em; }
228
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { font-size : 80%; }
229
.key { padding : 3px; white-space:nowrap; line-height:230%; }
230
.normalday { background-color :  #EDEDED; color :  Black; border : 1px solid #BCBCBC; }
231
.exception { background-color :  #b3d4ff; color :  Black; border : 1px solid #BCBCBC; }
232
.event {  background-color :  #ffaeae; color :  Black;  border : 1px solid #BCBCBC; }
233
.repeatableweekly {  background-color :  #FFFF99; color :  Black;  border : 1px solid #BCBCBC; }
234
.repeatableyearly {  background-color :  #FFCC66; color :  Black;  border : 1px solid #BCBCBC; }
235
td.exception a.ui-state-default { background:  #b3d4ff none; color :  Black; border : 1px solid #BCBCBC; }
236
td.event a.ui-state-default {  background:  #ffaeae none; color :  Black;  border : 1px solid #BCBCBC; }
237
td.repeatableweekly a.ui-state-default {  background:  #FFFF99 none; color :  Black;  border : 1px solid #BCBCBC; }
238
td.repeatableyearly a.ui-state-default {  background:  #FFCC66 none; color :  Black;  border : 1px solid #BCBCBC; }
239
.information { z-index : 1; background-color :  #DCD2F1; width : 300px; display : none; border : 1px solid #000000; color :  #000000; font-size :  8pt; font-weight :  bold; background-color :  #FFD700; cursor :  pointer; padding : 2px; }
240
.panel { z-index : 1; display : none; border : 3px solid #CCC; padding : 3px; margin-top: .3em;  background-color: #FEFEFE; } fieldset.brief { border : 0; margin-top: 0; }
241
#showEvent { margin : .5em 0; } h1 select { width: 20em; } div.yui-b fieldset.brief ol { font-size:100%; } div.yui-b fieldset.brief li, div.yui-b fieldset.brief li.radio  { padding:0.2em 0; } .help { margin:.3em 0;border:1px solid #EEE;padding:.3em .7em; font-size : 90%; } #single-events, #weekly-events, #yearly-events { font-size : 90%; margin-bottom : 1em;} .calendar td, .calendar th, .calendar .button, .calendar tbody .day { padding : .7em; font-size: 110%; } .calendar { width: auto; border : 0; }
242
li.hourssel {
243
    margin-top: .5em;
244
}
245
li.hourssel label {
246
    padding-left: .2em;
247
    padding-right: .5em;
248
}
249
li.hoursentry {
250
    margin-bottom: .5em;
251
}
252
li.hoursentry input {
253
    padding-left: .2em;
254
    padding-right: .5em;
255
}
256
</style>
257
</head>
258
<body id="tools_events" class="tools">
259
[% INCLUDE 'header.inc' %]
260
[% INCLUDE 'cat-search.inc' %]
261
262
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> &rsaquo; [% branchname %] Calendar</div>
263
264
<div id="doc3" class="yui-t1">
265
   
266
   <div id="bd">
267
    <div id="yui-main">
268
    <div class="yui-b">
269
    <h2>[% branchname %] Calendar</h2>
270
    <div class="yui-g">
271
    <div class="yui-u first">
272
        <label for="branch">Calendar for:</label>
273
            <select id="branch" name="branch">
274
                [% FOREACH branchloo IN branchloop %]
275
                    [% IF ( branchloo.selected ) %]
276
                        <option value="[% branchloo.value %]" selected="selected">[% branchloo.branchname %]</option>
277
                    [% ELSE %]
278
                        <option value="[% branchloo.value %]">[% branchloo.branchname %]</option>
279
                    [% END %]
280
                [% END %]
281
            </select>
282
    
283
    <!-- ******************************** FLAT PANELS ******************************************* -->
284
    <!-- *****           Makes all the flat panel to deal with events                     ***** -->
285
    <!-- **************************************************************************************** -->
286
287
    <!-- ********************** Panel for showing already loaded events *********************** -->
288
    <div class="panel" id="showEvent">
289
         <form action="/cgi-bin/koha/tools/calendar.pl" method="post">
290
             <input type="hidden" id="showEventType" name="eventType" value="" />
291
            <fieldset class="brief">
292
            <h3>Edit this event</h3>
293
            <span id="holtype"></span>
294
            <ol>
295
            <li>
296
                <strong>Library:</strong> <span id="showBranchNameOutput"></span>
297
                <input type="hidden" id="showBranchName" name="branchName" />
298
            </li>
299
            <li>
300
                <strong>From Date:</strong>
301
                <span id="showDaynameOutput"></span>, 
302
                
303
                                [% IF ( dateformat == "us" ) %]<span id="showMonthOutput"></span>/<span id="showDayOutput"></span>/<span id="showYearOutput"></span>[% ELSIF ( dateformat == "metric" ) %]<span id="showDayOutput"></span>/<span id="showMonthOutput"></span>/<span id="showYearOutput"></span>[% ELSE %]<span id="showYearOutput"></span>/<span id="showMonthOutput"></span>/<span id="showDayOutput"></span>[% END %]
304
305
                <input type="hidden" id="showWeekday" name="weekday" />
306
                <input type="hidden" id="showDay" name="day" />
307
                <input type="hidden" id="showMonth" name="month" />
308
                <input type="hidden" id="showYear" name="year" />
309
            </li>
310
            <li class="dateinsert">
311
                <b>To Date : </b>
312
                <input type="text" id="datecancelrange" name="dateofrange" size="20" value="[% dateofrange %]" class="datepicker"/>
313
            </li>
314
            <li class="radio hourssel">
315
                <input type="radio" name="hoursType" id="showHoursTypeOpen" value="open" /><label for="showHoursTypeOpen">Open</label>
316
                <input type="radio" name="hoursType" id="showHoursTypeOpenSet" value="openSet" /><label for="showHoursTypeOpenSet">Open (with set hours)</label>
317
                <input type="radio" name="hoursType" id="showHoursTypeClosed" value="closed" /><label for="showHoursTypeClosed">Closed</label>
318
            </li>
319
            <li class="radio hoursentry" style="display:none">
320
                <label for="showOpenTime">Open at:</label>
321
                <input type="time" name="openTime" id="showOpenTime" size="3" maxlength="5" value="0:00" pattern="(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9])" />
322
                <label for="showCloseTime">Closed at:</label>
323
                <input type="time" name="closeTime" id="showCloseTime" size="3" maxlength="5" value="23:59" pattern="(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9])" />
324
            </li>
325
            <li><label for="showTitle">Title: </label><input type="text" name="title" id="showTitle" size="35" /></li>
326
            <!-- showTitle is necessary for exception radio button to work properly --> 
327
                <label for="showDescription">Description:</label>
328
                <textarea rows="2" cols="40" id="showDescription" name="description"></textarea>    
329
            </li>
330
            <li class="radio"><input type="radio" name="op" id="showOperationDel" value="delete" /> <label for="showOperationDel" id="showOperationDelLabel">Delete this event</label>
331
                <a href="#" class="helptext">[?]</a>
332
                <div class="hint">This will delete this event rule.
333
            <li class="radio"><input type="radio" name="op" id="showOperationDelRange" value="deleterange" /> <label for="showOperationDelRange" id="showOperationDelLabelRange">Delete the single events on a range</label>.
334
                <a href="#" class="helptext">[?]</a>
335
                <div class="hint">This will delete the single events only. The repeatable events will not be deleted.</div>
336
            </li>
337
            <li class="radio"><input type="radio" name="op" id="showOperationDelRangeRepeat" value="deleterangerepeat" /> <label for="showOperationDelRangeRepeat" id="showOperationDelLabelRangeRepeat">Delete the repeated events on a range</label>.
338
                <a href="#" class="helptext">[?]</a>
339
                <div class="hint">This will delete the yearly repeated events only.</div>
340
            </li>
341
            <li class="radio"><input type="radio" name="op" id="showOperationEdit" value="save" checked="checked" /> <label for="showOperationEdit">Edit this event</label>
342
                <a href="#" class="helptext">[?]</a>
343
                <div class="hint">This will save changes to the event's title and description. If the information for a repeatable event is modified, it affects all of the dates on which the event is repeated.</div></li>
344
            </ol>
345
            <fieldset class="action">
346
                <input type="submit" name="submit" value="Save" />
347
                <a href="#" class="cancel" name="cancel2" onclick=" hidePanel('showEvent');">Cancel</a>
348
            </fieldset>
349
            </fieldset>
350
        </form>
351
    </div>
352
353
    <!-- ***************************** Panel to deal with new events **********************  -->
354
    <div class="panel" id="newEvent">
355
         <form action="/cgi-bin/koha/tools/calendar.pl" method="post">
356
            <input type="hidden" name="branchCodes" id="branchCodes" value="[% branchcodes %]" /> 
357
            <input type="hidden" name="op" value="save" />
358
            <fieldset class="brief">
359
            <h3>Add new event</h3>
360
361
        <ol>
362
            <li>
363
                <strong>Library:</strong>
364
                <span id="newBranchNameOutput"></span>
365
                <input type="hidden" id="newBranchName" name="branchName" />
366
            </li>
367
            <li>
368
                <strong>From date:</strong>
369
                <span id="newDaynameOutput"></span>, 
370
371
                         [% IF ( dateformat == "us" ) %]<span id="newMonthOutput"></span>/<span id="newDayOutput"></span>/<span id="newYearOutput"></span>[% ELSIF ( dateformat == "metric" ) %]<span id="newDayOutput"></span>/<span id="newMonthOutput"></span>/<span id="newYearOutput"></span>[% ELSE %]<span id="newYearOutput"></span>/<span id="newMonthOutput"></span>/<span id="newDayOutput"></span>[% END %]
372
373
                <input type="hidden" id="newWeekday" name="weekday" />
374
                <input type="hidden" id="newDay" name="day" />
375
                <input type="hidden" id="newMonth" name="month" />
376
                <input type="hidden" id="newYear" name="year" />
377
            </li>
378
            <li class="dateinsert">
379
                <b>To date : </b>
380
                <input type="text" id="dateofrange" name="dateofrange" size="20" value="[% dateofrange %]" class="datepicker" />
381
            </li>
382
            <li class="radio hourssel">
383
                <input type="radio" name="hoursType" id="newHoursTypeOpen" value="open" /><label for="newHoursTypeOpen">Open</label>
384
                <input type="radio" name="hoursType" id="newHoursTypeOpenSet" value="openSet" /><label for="newHoursTypeOpenSet">Open (with set hours)</label>
385
                <input type="radio" name="hoursType" id="newHoursTypeClosed" value="closed" /><label for="newHoursTypeClosed">Closed</label>
386
            </li>
387
            <li class="radio hoursentry" style="display:none">
388
                <label for="newOpenTime">Open at:</label>
389
                <input type="time" name="openTime" id="newOpenTime" size="3" maxlength="5" value="0:00" pattern="(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9])" />
390
                <label for="newCloseTime">Closed at:</label>
391
                <input type="time" name="closeTime" id="newCloseTime" size="3" maxlength="5" value="23:59" pattern="(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9])" />
392
            </li>
393
            <li><label for="title">Title: </label><input type="text" name="title" id="title" size="35" /></li>
394
            <li><label for="newDescription">Description:</label>
395
                <textarea rows="2" cols="40" id="newDescription" name="description"></textarea>
396
            </li>
397
            <li class="radio"><input type="radio" name="eventType" id="newOperationOnce" value="single" checked="checked" />
398
                            <label for="newOperationOnce">Event only on this day</label>.
399
                            <a href="#" class="helptext">[?]</a>
400
                            <div class="hint">Make a single event. For example, selecting August 1st, 2012 will not affect August 1st in other years.</div>
401
                            </li>
402
            <li class="radio"><input type="radio" name="eventType" id="newOperationDay" value="weekly" />
403
                            <label for="newOperationDay">Event repeated weekly</label>.
404
                            <a href="#" class="helptext">[?]</a>
405
                            <div class="hint">Make this weekday an event, every week. For example, if your library is closed on Saturdays, use this option to make every Saturday a event.</div>
406
                            </li>
407
            <li class="radio"><input type="radio" name="eventType" id="newOperationYear" value="yearly" />
408
                            <label for="newOperationYear">Event repeated yearly</label>.
409
                            <a href="#" class="helptext">[?]</a>
410
                            <div class="hint">Make this day of the year an event, every year. For example, selecting August 1st will set the hours for August 1st every year.</div>
411
                            </li>
412
            <li class="radio"><input type="radio" name="eventType" id="newOperationField" value="singlerange" />
413
                            <label for="newOperationField">Events on a range</label>.
414
                            <a href="#" class="helptext">[?]</a>
415
                            <div class="hint">Make events for a range of days. For example, selecting August 1st, 2012 and August 10st, 2012 will make all days between 1st and 10st event, but will not affect August 1-10 in other years.</div>
416
                            </li>
417
            <li class="radio"><input type="radio" name="eventType" id="newOperationFieldyear" value="yearlyrange" />
418
                            <label for="newOperationFieldyear">Events repeated yearly on a range</label>.
419
                            <a href="#" class="helptext">[?]</a>
420
                            <div class="hint">Make a single event on a range repeated yearly. For example, selecting August 1st, 2012  and August 10st, 2012 will make all days between 1st and 10st event, and will affect August 1-10 in other years.</div>
421
                            </li>
422
                <li class="radio">
423
                <input type="checkbox" name="allBranches" id="allBranches" />
424
                <label for="allBranches">Copy to all libraries</label>.
425
                <a href="#" class="helptext">[?]</a>
426
                <div class="hint">If checked, this event will be copied to all libraries. If the event already exists for a library, no change is made.</div>
427
                </li></ol>
428
                <fieldset class="action">
429
                    <input type="submit" name="submit" value="Save" />
430
                    <a href="#" class="cancel" name="cancel2" onclick=" hidePanel('newEvent');">Cancel</a>
431
                </fieldset>
432
                </fieldset>
433
         </form>
434
    </div>
435
436
    <!-- *************************************************************************************** -->
437
    <!-- ******                          END OF FLAT PANELS                               ****** -->
438
    <!-- *************************************************************************************** -->
439
440
<!-- ************************************************************************************** -->
441
<!-- ******                              MAIN SCREEN CODE                            ****** -->
442
<!-- ************************************************************************************** -->
443
<h3>Calendar information</h3>
444
<div id="jcalendar-container"></div>
445
446
<div style="margin-top: 2em;">
447
<form action="/cgi-bin/koha/tools/calendar.pl" method="post">
448
    <input type="hidden" name="op" value="copyall" />
449
    <input type="hidden" name="from_branchcode" value="[% branch %]" />
450
  <label for="branchcode">Copy events to:</label>
451
  <select id="branchcode" name="branchcode" required>
452
    <option value=""></option>
453
    [% FOREACH branchloo IN branchloop %]
454
    <option value="[% branchloo.value %]">[% branchloo.branchname %]</option>
455
    [% END %]
456
  </select>
457
    <input type="submit" value="Copy" />
458
</form>
459
</div>
460
461
</div>
462
<div class="yui-u">
463
<div class="help">
464
<h4>Hints</h4>
465
    <ul>
466
        <li>Search in the calendar the day you want to set as event.</li>
467
        <li>Click the date to add or edit a event.</li>
468
        <li>Enter a title and description for the event.</li>
469
        <li>Specify how the event should repeat.</li>
470
        <li>Click Save to finish.</li>
471
    </ul>
472
<h4>Key</h4>
473
    <p>
474
        <span class="key normalday">Working day</span>
475
        <span class="key event">Unique event</span>
476
        <span class="key repeatableweekly">Event repeating weekly</span>
477
        <span class="key repeatableyearly">Event repeating yearly</span>
478
    </p>
479
</div>
480
<div id="event-list">
481
[% IF ( weekly_events ) %]
482
<h3>Weekly - Repeatable Events</h3>
483
<table id="weekly-events">
484
<thead>
485
<tr>
486
  <th class="repeatableweekly">Day of week</th>
487
  <th class="repeatableweekly">Title</th>
488
  <th class="repeatableweekly">Description</th>
489
  <th class="repeatableweekly">Hours</th>
490
</tr>
491
</thead>
492
<tbody>
493
  [% FOREACH event IN weekly_events %]
494
  <tr>
495
  <td>
496
<script type="text/javascript">
497
  document.write(weekdays[ [% event.weekday %]]);
498
</script>
499
  </td> 
500
  <td>[% event.title %]</td> 
501
  <td>[% event.description %]</td> 
502
  <td>
503
    [% IF event.closed %]
504
    Closed
505
    [% ELSIF event.close_hour == 24 %]
506
    Open
507
    [% ELSE %]
508
    [% event.open_hour %]:[% event.open_minute > 10 ? event.open_minute : ( '0' _ event.open_minute) %] - 
509
    [% event.close_hour %]:[% event.close_minute > 10 ? event.close_minute : ( '0' _ event.close_minute) %]
510
    [% END %]
511
  </td>
512
  </tr>
513
  [% END %] 
514
</tbody>
515
</table>
516
[% END %]
517
518
[% IF ( yearly_events ) %]
519
<h3>Yearly - Repeatable Events</h3>
520
<table id="yearly-events">
521
<thead>
522
<tr>
523
  [% IF ( dateformat == "metric" ) %]
524
  <th class="repeatableyearly">Day/Month</th>
525
  [% ELSE %]
526
  <th class="repeatableyearly">Month/Day</th>
527
  [% END %]
528
  <th class="repeatableyearly">Title</th>
529
  <th class="repeatableyearly">Description</th>
530
  <th class="repeatableyearly">Hours</th>
531
</tr>
532
</thead>
533
<tbody>
534
  [% FOREACH event IN yearly_events %]
535
  <tr>
536
  <td><span title="[% event.month_day_display %]">[% event.month_day_sort %]</span></td>
537
  <td>[% event.title %]</td> 
538
  <td>[% event.description %]</td> 
539
  <td>
540
    [% IF event.closed %]
541
    Closed
542
    [% ELSIF event.close_hour == 24 %]
543
    Open
544
    [% ELSE %]
545
    [% event.open_hour %]:[% event.open_minute > 10 ? event.open_minute : ( '0' _ event.open_minute) %] - 
546
    [% event.close_hour %]:[% event.close_minute > 10 ? event.close_minute : ( '0' _ event.close_minute) %]
547
    [% END %]
548
  </td>
549
  </tr>
550
  [% END %] 
551
</tbody>
552
</table>
553
[% END %]
554
555
[% IF ( single_events ) %]
556
<h3>Single Events</h3>
557
<table id="single-events">
558
<thead>
559
<tr>
560
  <th class="event">Date</th>
561
  <th class="event">Title</th>
562
  <th class="event">Description</th>
563
  <th class="event">Hours</th>
564
</tr>
565
</thead>
566
<tbody>
567
    [% FOREACH event IN single_events %]
568
<tr>
569
  <td><a href="/cgi-bin/koha/tools/calendar.pl?branch=[% branch %]&amp;calendardate=[% event.event_date | $KohaDates %]"><span title="[% event.event_date %]">[% event.event_date | $KohaDates %]</span></a></td>
570
  <td>[% event.title %]</td>
571
  <td>[% event.description %]</td>
572
  <td>
573
    [% IF event.closed %]
574
    Closed
575
    [% ELSIF event.close_hour == 24 %]
576
    Open
577
    [% ELSE %]
578
    [% event.open_hour %]:[% event.open_minute > 10 ? event.open_minute : ( '0' _ event.open_minute) %] - 
579
    [% event.close_hour %]:[% event.close_minute > 10 ? event.close_minute : ( '0' _ event.close_minute) %]
580
    [% END %]
581
  </td>
582
</tr>
583
  [% END %] 
584
</tbody>
585
</table>
586
[% END %]
587
</div>
588
</div>
589
</div>
590
</div>
591
</div>
592
593
<div class="yui-b noprint">
594
[% INCLUDE 'tools-menu.inc' %]
595
</div>
596
</div>
597
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt (-538 lines)
Lines 1-538 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Tools &rsaquo; [% branchname %] Calendar</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
[% INCLUDE 'calendar.inc' %]
5
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
6
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.dataTables.min.js"></script>
7
[% INCLUDE 'datatables-strings.inc' %]
8
<script type="text/javascript" src="[% themelang %]/js/datatables.js"></script>
9
<script language="JavaScript" type="text/javascript">
10
//<![CDATA[
11
    [% IF (dateformat == 'metric') %]dt_add_type_uk_date();[% END %]
12
    var weekdays = new Array(_("Sundays"),_("Mondays"),_("Tuesdays"),_("Wednesdays"),_("Thursdays"),_("Fridays"),_("Saturdays"));
13
14
    /* Creates all the structures to deal with all diferents kinds of holidays */
15
    var week_days = new Array();
16
    var holidays = new Array();
17
    var holidates = new Array();
18
    var exception_holidays = new Array();
19
    var day_month_holidays = new Array();
20
    var hola= "[% code %]";
21
    [% FOREACH WEEK_DAYS_LOO IN WEEK_DAYS_LOOP %]
22
    week_days["[% WEEK_DAYS_LOO.KEY %]"] = {title:"[% WEEK_DAYS_LOO.TITLE %]", description:"[% WEEK_DAYS_LOO.DESCRIPTION %]"};
23
    [% END %]
24
    [% FOREACH HOLIDAYS_LOO IN HOLIDAYS_LOOP %]
25
    holidates.push("[% HOLIDAYS_LOO.KEY %]");
26
    holidays["[% HOLIDAYS_LOO.KEY %]"] = {title:"[% HOLIDAYS_LOO.TITLE %]", description:"[% HOLIDAYS_LOO.DESCRIPTION %]"};
27
28
    [% END %]
29
    [% FOREACH EXCEPTION_HOLIDAYS_LOO IN EXCEPTION_HOLIDAYS_LOOP %]
30
    exception_holidays["[% EXCEPTION_HOLIDAYS_LOO.KEY %]"] = {title:"[% EXCEPTION_HOLIDAYS_LOO.TITLE %]", description:"[% EXCEPTION_HOLIDAYS_LOO.DESCRIPTION %]"};
31
    [% END %]
32
    [% FOREACH DAY_MONTH_HOLIDAYS_LOO IN DAY_MONTH_HOLIDAYS_LOOP %]
33
    day_month_holidays["[% DAY_MONTH_HOLIDAYS_LOO.KEY %]"] = {title:"[% DAY_MONTH_HOLIDAYS_LOO.TITLE %]", description:"[% DAY_MONTH_HOLIDAYS_LOO.DESCRIPTION %]"};
34
    [% END %]
35
36
    function holidayOperation(formObject, opType) {
37
        var op = document.getElementsByName('operation');
38
        op[0].value = opType;
39
        formObject.submit();
40
    }
41
42
    // This function shows the "Show Holiday" panel //
43
    function showHoliday (exceptionPosibility, dayName, day, month, year, weekDay, title, description, holidayType) {
44
        $("#newHoliday").slideUp("fast");
45
        $("#showHoliday").slideDown("fast");
46
        $('#showDaynameOutput').html(dayName);
47
        $('#showDayname').val(dayName);
48
        $('#showBranchNameOutput').html($("#branch :selected").text());
49
        $('#showBranchName').val($("#branch").val());
50
        $('#showDayOutput').html(day);
51
        $('#showDay').val(day);
52
        $('#showMonthOutput').html(month);
53
        $('#showMonth').val(month);
54
        $('#showYearOutput').html(year);
55
        $('#showYear').val(year);
56
        $('#showDescription').val(description);
57
        $('#showWeekday:first').val(weekDay);
58
        $('#showTitle').val(title);
59
        $('#showHolidayType').val(holidayType);
60
61
        if (holidayType == 'exception') {
62
            $("#showOperationDelLabel").html(_("Delete this exception."));
63
            $("#holtype").attr("class","key exception").html(_("Holiday exception"));
64
        } else if(holidayType == 'weekday') {
65
            $("#showOperationDelLabel").html(_("Delete this holiday."));
66
            $("#holtype").attr("class","key repeatableweekly").html(_("Holiday repeating weekly"));
67
        } else if(holidayType == 'daymonth') {
68
            $("#showOperationDelLabel").html(_("Delete this holiday."));
69
            $("#holtype").attr("class","key repeatableyearly").html(_("Holiday repeating yearly"));
70
        } else {
71
            $("#showOperationDelLabel").html(_("Delete this holiday."));
72
            $("#holtype").attr("class","key holiday").html(_("Unique holiday"));
73
        }
74
        
75
        if (exceptionPosibility == 1) {
76
            $("#exceptionPosibility").parent().show();
77
        } else {
78
            $("#exceptionPosibility").parent().hide();
79
        }
80
    }
81
82
    // This function shows the "Add Holiday" panel //
83
    function newHoliday (dayName, day, month, year, weekDay) {
84
        $("#showHoliday").slideUp("fast");
85
        $("#newHoliday").slideDown("fast");
86
        $("#newDaynameOutput").html(dayName);
87
        $("#newDayname").val(dayName);
88
        $("#newBranchNameOutput").html($('#branch :selected').text());
89
        $("#newBranchName").val($('#branch').val());
90
        $("#newDayOutput").html(day);
91
        $("#newDay").val(day);
92
        $("#newMonthOutput").html(month);
93
        $("#newMonth").val(month);
94
        $("#newYearOutput").html(year);
95
        $("#newYear").val(year);
96
        $("#newWeekday:first").val(weekDay);
97
    }
98
99
    function hidePanel(aPanelName) {
100
        $("#"+aPanelName).slideUp("fast");
101
    }
102
103
    function changeBranch () {
104
        var branch = $("#branch option:selected").val();
105
        location.href='/cgi-bin/koha/tools/holidays.pl?branch=' + branch + '&calendardate=' + "[% calendardate %]";
106
    }
107
108
    function Help() {
109
        newin=window.open("/cgi-bin/koha/help.pl","KohaHelp",'width=600,height=600,toolbar=false,scrollbars=yes');
110
    }
111
112
    /* This function gives css clases to each kind of day */
113
    function dateStatusHandler(date) {
114
        date = new Date(date);
115
        var day = date.getDate();
116
        var month = date.getMonth() + 1;
117
        var year = date.getFullYear();
118
        var weekDay = date.getDay();
119
        var dayMonth = month + '/' + day;
120
        var dateString = year + '/' + month + '/' + day;
121
        if (exception_holidays[dateString] != null) {
122
            return [true, "exception", "Exception: "+exception_holidays[dateString].title];
123
        } else if ( week_days[weekDay] != null ){
124
            return [true, "repeatableweekly", "Weekly holdiay: "+week_days[weekDay].title];
125
        } else if ( day_month_holidays[dayMonth] != null ) {
126
            return [true, "repeatableyearly", "Yearly holdiay: "+day_month_holidays[dayMonth].title];
127
        } else if (holidays[dateString] != null) {
128
            return [true, "holiday", "Single holiday: "+holidays[dateString].title];
129
        } else {
130
            return [true, "normalday", "Normal day"];
131
        }
132
    }
133
134
    /* This function is in charge of showing the correct panel considering the kind of holiday */
135
    function dateChanged(calendar) {
136
        calendar = new Date(calendar);
137
        var day = calendar.getDate();
138
        var month = calendar.getMonth() + 1;
139
        var year = calendar.getFullYear();
140
        var weekDay = calendar.getDay();
141
        var dayName = weekdays[weekDay];
142
        var dayMonth = month + '/' + day;
143
        var dateString = year + '/' + month + '/' + day;
144
            if (holidays[dateString] != null) {
145
                showHoliday(0, dayName, day, month, year, weekDay, holidays[dateString].title,     holidays[dateString].description, 'ymd');
146
            } else if (exception_holidays[dateString] != null) {
147
                showHoliday(0, dayName, day, month, year, weekDay, exception_holidays[dateString].title, exception_holidays[dateString].description, 'exception');
148
            } else if (week_days[weekDay] != null) {
149
                showHoliday(1, dayName, day, month, year, weekDay, week_days[weekDay].title,     week_days[weekDay].description, 'weekday');
150
            } else if (day_month_holidays[dayMonth] != null) {
151
                showHoliday(1, dayName, day, month, year, weekDay, day_month_holidays[dayMonth].title, day_month_holidays[dayMonth].description, 'daymonth');
152
            } else {
153
                newHoliday(dayName, day, month, year, weekDay);
154
            }
155
    };
156
157
    $(document).ready(function() {
158
159
        $(".hint").hide();
160
        $("#branch").change(function(){
161
            changeBranch();
162
        });
163
        $("#holidayexceptions,#holidayweeklyrepeatable,#holidaysunique").dataTable($.extend(true, {}, dataTablesDefaults, {
164
            "sDom": 't',
165
            "bPaginate": false
166
        }));
167
        $("#holidaysyearlyrepeatable").dataTable($.extend(true, {}, dataTablesDefaults, {
168
            "sDom": 't',
169
            "aoColumns": [
170
                { "sType": "title-string" },null,null
171
            ],
172
            "bPaginate": false
173
        }));
174
        $("a.helptext").click(function(){
175
            $(this).parent().find(".hint").toggle(); return false;
176
        });
177
        $("#dateofrange").datepicker();
178
        $("#datecancelrange").datepicker();
179
        $("#dateofrange").each(function () { this.value = "" });
180
        $("#datecancelrange").each(function () { this.value = "" });
181
        $("#jcalendar-container").datepicker({
182
          beforeShowDay: function(thedate) {
183
            var day = thedate.getDate();
184
            var month = thedate.getMonth() + 1;
185
            var year = thedate.getFullYear();
186
            var dateString = year + '/' + month + '/' + day;
187
            return dateStatusHandler(dateString);
188
            },
189
        onSelect: function(dateText, inst) {
190
            dateChanged($(this).datepicker("getDate"));
191
        },
192
        defaultDate: new Date("[% keydate %]")
193
    });
194
    });
195
//]]>
196
</script>
197
<style type="text/css"> .key { padding : 3px; white-space:nowrap; line-height:230%; }
198
.ui-datepicker { font-size : 150%; }
199
.ui-datepicker th, .ui-datepicker .ui-datepicker-title select { font-size : 80%; }
200
.ui-datepicker td a { padding : .5em; }
201
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { font-size : 80%; }
202
.key { padding : 3px; white-space:nowrap; line-height:230%; }
203
.normalday { background-color :  #EDEDED; color :  Black; border : 1px solid #BCBCBC; }
204
.exception { background-color :  #b3d4ff; color :  Black; border : 1px solid #BCBCBC; }
205
.holiday {  background-color :  #ffaeae; color :  Black;  border : 1px solid #BCBCBC; }
206
.repeatableweekly {  background-color :  #FFFF99; color :  Black;  border : 1px solid #BCBCBC; }
207
.repeatableyearly {  background-color :  #FFCC66; color :  Black;  border : 1px solid #BCBCBC; }
208
td.exception a.ui-state-default { background:  #b3d4ff none; color :  Black; border : 1px solid #BCBCBC; }
209
td.holiday a.ui-state-default {  background:  #ffaeae none; color :  Black;  border : 1px solid #BCBCBC; }
210
td.repeatableweekly a.ui-state-default {  background:  #D8EFB3 none; color :  Black;  border : 1px solid #BCBCBC; }
211
td.repeatableyearly a.ui-state-default {  background:  #FFFF99 none; color :  Black;  border : 1px solid #BCBCBC; }
212
.information { z-index : 1; background-color :  #DCD2F1; width : 300px; display : none; border : 1px solid #000000; color :  #000000; font-size :  8pt; font-weight :  bold; background-color :  #FFD700; cursor :  pointer; padding : 2px; }
213
.panel { z-index : 1; display : none; border : 3px solid #CCC; padding : 3px; margin-top: .3em;  background-color: #FEFEFE; } fieldset.brief { border : 0; margin-top: 0; }
214
#showHoliday { margin : .5em 0; } h1 select { width: 20em; } div.yui-b fieldset.brief ol { font-size:100%; } div.yui-b fieldset.brief li, div.yui-b fieldset.brief li.radio  { padding:0.2em 0; } .help { margin:.3em 0;border:1px solid #EEE;padding:.3em .7em; font-size : 90%; } #holidayweeklyrepeatable, #holidaysyearlyrepeatable, #holidaysunique, #holidayexceptions { font-size : 90%; margin-bottom : 1em;} .calendar td, .calendar th, .calendar .button, .calendar tbody .day { padding : .7em; font-size: 110%; } .calendar { width: auto; border : 0; }
215
</style>
216
</head>
217
<body id="tools_holidays" class="tools">
218
[% INCLUDE 'header.inc' %]
219
[% INCLUDE 'cat-search.inc' %]
220
221
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> &rsaquo; [% branchname %] Calendar</div>
222
223
<div id="doc3" class="yui-t1">
224
   
225
   <div id="bd">
226
    <div id="yui-main">
227
    <div class="yui-b">
228
    <h2>[% branchname %] Calendar</h2>
229
    <div class="yui-g">
230
    <div class="yui-u first">
231
        <label for="branch">Define the holidays for:</label>
232
            <select id="branch" name="branch">
233
                [% FOREACH branchloo IN branchloop %]
234
                    [% IF ( branchloo.selected ) %]
235
                        <option value="[% branchloo.value %]" selected="selected">[% branchloo.branchname %]</option>
236
                    [% ELSE %]
237
                        <option value="[% branchloo.value %]">[% branchloo.branchname %]</option>
238
                    [% END %]
239
                [% END %]
240
            </select>
241
    
242
    <!-- ******************************** FLAT PANELS ******************************************* -->
243
    <!-- *****           Makes all the flat panel to deal with holidays                     ***** -->
244
    <!-- **************************************************************************************** -->
245
246
    <!-- ********************** Panel for showing already loaded holidays *********************** -->
247
    <div class="panel" id="showHoliday">
248
         <form action="/cgi-bin/koha/tools/exceptionHolidays.pl" method="post">
249
             <input type="hidden" id="showHolidayType" name="showHolidayType" value="" />
250
            <fieldset class="brief">
251
            <h3>Edit this holiday</h3>
252
            <span id="holtype"></span>
253
            <ol>
254
            <li>
255
                <strong>Library:</strong> <span id="showBranchNameOutput"></span>
256
                <input type="hidden" id="showBranchName" name="showBranchName" />
257
            </li>
258
            <li>
259
                <strong>From Date:</strong>
260
                <span id="showDaynameOutput"></span>, 
261
                
262
                                [% IF ( dateformat == "us" ) %]<span id="showMonthOutput"></span>/<span id="showDayOutput"></span>/<span id="showYearOutput"></span>[% ELSIF ( dateformat == "metric" ) %]<span id="showDayOutput"></span>/<span id="showMonthOutput"></span>/<span id="showYearOutput"></span>[% ELSE %]<span id="showYearOutput"></span>/<span id="showMonthOutput"></span>/<span id="showDayOutput"></span>[% END %]
263
264
                <input type="hidden" id="showDayname" name="showDayname" />
265
                <input type="hidden" id="showWeekday" name="showWeekday" />
266
                <input type="hidden" id="showDay" name="showDay" />
267
                <input type="hidden" id="showMonth" name="showMonth" />
268
                <input type="hidden" id="showYear" name="showYear" />
269
            </li>
270
            <li class="dateinsert">
271
                <b>To Date : </b>
272
                <input type="text" id="datecancelrange" name="datecancelrange" size="20" value="[% datecancelrange %]" class="datepicker"/>
273
            </li>
274
            <li><label for="showTitle">Title: </label><input type="text" name="showTitle" id="showTitle" size="35" /></li>
275
            <!-- showTitle is necessary for exception radio button to work properly --> 
276
                <label for="showDescription">Description:</label>
277
                <textarea rows="2" cols="40" id="showDescription" name="showDescription"></textarea>    
278
            </li>
279
            <li class="radio"><div id="exceptionPosibility" style="position:static">
280
                <input type="radio" name="showOperation" id="showOperationExc" value="exception" /> <label for="showOperationExc">Generate an exception for this repeated holiday.</label>
281
                <a href="#" class="helptext">[?]</a>
282
                <div class="hint">You can make an exception for this holiday rule. This means that you will be able to say that for a repeatable holiday there is one day which is going to be an exception.</div>
283
            </div></li>
284
            <li class="radio"><input type="radio" name="showOperation" id="showOperationExcRange" value="exceptionrange" />
285
                <label for="newOperationFieldException">Generate exceptions on a range of dates.</label>
286
                <a href="#" class="helptext">[?]</a>
287
                <div class="hint">You can make an exception on a range of dates repeated yearly.</div>
288
            </li>
289
            <li class="radio"><input type="radio" name="showOperation" id="showOperationDel" value="delete" /> <label for="showOperationDel" id="showOperationDelLabel">Delete this holiday</label>
290
                <a href="#" class="helptext">[?]</a>
291
                <div class="hint">This will delete this holiday rule. If it is a repeatable holiday, this option checks for possible exceptions. If an exception exists, this option will remove the exception and set the date to a regular holiday.</div></li>
292
            <li class="radio"><input type="radio" name="showOperation" id="showOperationDelRange" value="deleterange" /> <label for="showOperationDelRange" id="showOperationDelLabelRange">Delete the single holidays on a range</label>.
293
                <a href="#" class="helptext">[?]</a>
294
                <div class="hint">This will delete the single holidays rules only. The repeatable holidays and exceptions will not be deleted.</div>
295
            </li>
296
            <li class="radio"><input type="radio" name="showOperation" id="showOperationDelRangeRepeat" value="deleterangerepeat" /> <label for="showOperationDelRangeRepeat" id="showOperationDelLabelRangeRepeat">Delete the repeated holidays on a range</label>.
297
                <a href="#" class="helptext">[?]</a>
298
                <div class="hint">This will delete the repeated holidays rules only. The repeatable holidays will be deleted but not the exceptions.</div>
299
            </li>
300
            <li class="radio"><input type="radio" name="showOperation" id="showOperationDelRangeRepeatExcept" value="deleterangerepeatexcept" /> <label for="showOperationDelRangeRepeatExcept" id="showOperationDelLabelRangeRepeatExcept">Delete the exceptions on a range</label>.
301
                <a href="#" class="helptext">[?]</a>
302
                <div class="hint">This will delete the exceptions inside a given range. Be careful about your scope range if it is oversized you could slow down Koha.</div>
303
            </li>
304
            <li class="radio"><input type="radio" name="showOperation" id="showOperationEdit" value="edit" checked="checked" /> <label for="showOperationEdit">Edit this holiday</label>
305
                <a href="#" class="helptext">[?]</a>
306
                <div class="hint">This will save changes to the holiday's title and description. If the information for a repeatable holiday is modified, it affects all of the dates on which the holiday is repeated.</div></li>
307
            </ol>
308
            <fieldset class="action">
309
                <input type="submit" name="submit" value="Save" />
310
                <a href="#" class="cancel" name="cancel2" onclick=" hidePanel('showHoliday');">Cancel</a>
311
            </fieldset>
312
            </fieldset>
313
        </form>
314
    </div>
315
316
    <!-- ***************************** Panel to deal with new holidays **********************  -->
317
    <div class="panel" id="newHoliday">
318
         <form action="/cgi-bin/koha/tools/newHolidays.pl" method="post">
319
                <input type="hidden" name="branchCodes" id="branchCodes" value="[% branchcodes %]" /> 
320
            <fieldset class="brief">
321
            <h3>Add new holiday</h3>
322
            <ol>
323
            <li>
324
                <strong>Library:</strong>
325
                <span id="newBranchNameOutput"></span>
326
                <input type="hidden" id="newBranchName" name="newBranchName" />
327
            </li>
328
            <li>
329
                <strong>From date:</strong>
330
                <span id="newDaynameOutput"></span>, 
331
332
                         [% IF ( dateformat == "us" ) %]<span id="newMonthOutput"></span>/<span id="newDayOutput"></span>/<span id="newYearOutput"></span>[% ELSIF ( dateformat == "metric" ) %]<span id="newDayOutput"></span>/<span id="newMonthOutput"></span>/<span id="newYearOutput"></span>[% ELSE %]<span id="newYearOutput"></span>/<span id="newMonthOutput"></span>/<span id="newDayOutput"></span>[% END %]
333
334
                <input type="hidden" id="newDayname" name="showDayname" />
335
                <input type="hidden" id="newWeekday" name="newWeekday" />
336
                <input type="hidden" id="newDay" name="newDay" />
337
                <input type="hidden" id="newMonth" name="newMonth" />
338
                <input type="hidden" id="newYear" name="newYear" />
339
            </li>
340
            <li class="dateinsert">
341
                <b>To date : </b>
342
                <input type="text" id="dateofrange" name="dateofrange" size="20" value="[% dateofrange %]" class="datepicker" />
343
            </li>
344
            <li><label for="title">Title: </label><input type="text" name="newTitle" id="title" size="35" /></li>
345
            <li><label for="newDescription">Description:</label>
346
                <textarea rows="2" cols="40" id="newDescription" name="newDescription"></textarea>
347
            </li>
348
            <li class="radio"><input type="radio" name="newOperation" id="newOperationOnce" value="holiday" checked="checked" />
349
            <label for="newOperationOnce">Holiday only on this day</label>.
350
            <a href="#" class="helptext">[?]</a>
351
            <div class="hint">Make a single holiday. For example, selecting August 1st, 2012 will make it a holiday, but will not affect August 1st in other years.</div>
352
            </li>
353
            <li class="radio"><input type="radio" name="newOperation" id="newOperationDay" value="weekday" />
354
                            <label for="newOperationDay">Holiday repeated every same day of the week</label>.
355
                            <a href="#" class="helptext">[?]</a>
356
                            <div class="hint">Make this weekday a holiday, every week. For example, if your library is closed on Saturdays, use this option to make every Saturday a holiday.</div>
357
                            </li>
358
            <li class="radio"><input type="radio" name="newOperation" id="newOperationYear" value="repeatable" />
359
                            <label for="newOperationYear">Holiday repeated yearly on the same date</label>.
360
                            <a href="#" class="helptext">[?]</a>
361
                            <div class="hint">This will take this day and month as a reference to make it a holiday. Through this option, you can repeat this rule for every year. For example, selecting August 1st will make August 1st a holiday every year.</div>
362
                            </li>
363
            <li class="radio"><input type="radio" name="newOperation" id="newOperationField" value="holidayrange" />
364
                            <label for="newOperationField">Holidays on a range</label>.
365
                            <a href="#" class="helptext">[?]</a>
366
                            <div class="hint">Make a single holiday on a range. For example, selecting August 1st, 2012  and August 10st, 2012 will make all days between 1st and 10st holiday, but will not affect August 1-10 in other years.</div>
367
                            </li>
368
            <li class="radio"><input type="radio" name="newOperation" id="newOperationFieldyear" value="holidayrangerepeat" />
369
                            <label for="newOperationFieldyear">Holidays repeated yearly on a range</label>.
370
                            <a href="#" class="helptext">[?]</a>
371
                            <div class="hint">Make a single holiday on a range repeated yearly. For example, selecting August 1st, 2012  and August 10st, 2012 will make all days between 1st and 10st holiday, and will affect August 1-10 in other years.</div>
372
                            </li>
373
                <li class="radio">
374
                <input type="checkbox" name="allBranches" id="allBranches" />
375
                <label for="allBranches">Copy to all libraries</label>.
376
                <a href="#" class="helptext">[?]</a>
377
                <div class="hint">If checked, this holiday will be copied to all libraries. If the holiday already exists for a library, no change is made.</div>
378
                </li></ol>
379
                <fieldset class="action">
380
                    <input type="submit" name="submit" value="Save" />
381
                    <a href="#" class="cancel" name="cancel2" onclick=" hidePanel('newHoliday');">Cancel</a>
382
                </fieldset>
383
                </fieldset>
384
         </form>
385
    </div>
386
387
    <!-- *************************************************************************************** -->
388
    <!-- ******                          END OF FLAT PANELS                               ****** -->
389
    <!-- *************************************************************************************** -->
390
391
<!-- ************************************************************************************** -->
392
<!-- ******                              MAIN SCREEN CODE                            ****** -->
393
<!-- ************************************************************************************** -->
394
<h3>Calendar information</h3>
395
<div id="jcalendar-container"></div>
396
397
<div style="margin-top: 2em;">
398
<form action="copy-holidays.pl" method="post">
399
    <input type="hidden" name="from_branchcode" value="[% branch %]" />
400
  <label for="branchcode">Copy holidays to:</label>
401
  <select id="branchcode" name="branchcode">
402
    <option value=""></option>
403
    [% FOREACH branchloo IN branchloop %]
404
    <option value="[% branchloo.value %]">[% branchloo.branchname %]</option>
405
    [% END %]
406
  </select>
407
    <input type="submit" value="Copy" />
408
</form>
409
</div>
410
411
</div>
412
<div class="yui-u">
413
<div class="help">
414
<h4>Hints</h4>
415
    <ul>
416
        <li>Search in the calendar the day you want to set as holiday.</li>
417
        <li>Click the date to add or edit a holiday.</li>
418
        <li>Enter a title and description for the holdiay.</li>
419
        <li>Specify how the holiday should repeat.</li>
420
        <li>Click Save to finish.</li>
421
    </ul>
422
<h4>Key</h4>
423
    <p>
424
        <span class="key normalday">Working day</span>
425
        <span class="key holiday">Unique holiday</span>
426
        <span class="key repeatableweekly">Holiday repeating weekly</span>
427
        <span class="key repeatableyearly">Holiday repeating yearly</span>
428
        <span class="key exception">Holiday exception</span>
429
    </p>
430
</div>
431
<div id="holiday-list">
432
<!-- Exceptions First -->
433
<!--   this will probably always have the least amount of data -->
434
[% IF ( EXCEPTION_HOLIDAYS_LOOP ) %]
435
<h3>Exceptions</h3>
436
  <table id="holidayexceptions">
437
<thead><tr>
438
  <th class="exception">Date</th>
439
  <th class="exception">Title</th>
440
  <th class="exception">Description</th>
441
</tr>
442
</thead>
443
<tbody>
444
  [% FOREACH EXCEPTION_HOLIDAYS_LOO IN EXCEPTION_HOLIDAYS_LOOP %]
445
  <tr>
446
  <td><a href="/cgi-bin/koha/tools/holidays.pl?branch=[% branch %]&amp;calendardate=[% EXCEPTION_HOLIDAYS_LOO.DATE %]"><span title="[% EXCEPTION_HOLIDAYS_LOO.DATE_SORT %]">[% EXCEPTION_HOLIDAYS_LOO.DATE %]</span></a></td>
447
  <td>[% EXCEPTION_HOLIDAYS_LOO.TITLE %]</td>
448
  <td>[% EXCEPTION_HOLIDAYS_LOO.DESCRIPTION %]</td> 
449
  </tr>
450
  [% END %] 
451
</tbody>
452
</table>
453
[% END %]
454
455
[% IF ( WEEK_DAYS_LOOP ) %]
456
<h3>Weekly - Repeatable Holidays</h3>
457
<table id="holidayweeklyrepeatable">
458
<thead>
459
<tr>
460
  <th class="repeatableweekly">Day of week</th>
461
  <th class="repeatableweekly">Title</th>
462
  <th class="repeatableweekly">Description</th>
463
</tr>
464
</thead>
465
<tbody>
466
  [% FOREACH WEEK_DAYS_LOO IN WEEK_DAYS_LOOP %]
467
  <tr>
468
  <td>
469
<script type="text/javascript">
470
  document.write(weekdays[ [% WEEK_DAYS_LOO.KEY %]]);
471
</script>
472
  </td> 
473
  <td>[% WEEK_DAYS_LOO.TITLE %]</td> 
474
  <td>[% WEEK_DAYS_LOO.DESCRIPTION %]</td> 
475
  </tr>
476
  [% END %] 
477
</tbody>
478
</table>
479
[% END %]
480
481
[% IF ( DAY_MONTH_HOLIDAYS_LOOP ) %]
482
<h3>Yearly - Repeatable Holidays</h3>
483
<table id="holidaysyearlyrepeatable">
484
<thead>
485
<tr>
486
  [% IF ( dateformat == "metric" ) %]
487
  <th class="repeatableyearly">Day/Month</th>
488
  [% ELSE %]
489
  <th class="repeatableyearly">Month/Day</th>
490
  [% END %]
491
  <th class="repeatableyearly">Title</th>
492
  <th class="repeatableyearly">Description</th>
493
</tr>
494
</thead>
495
<tbody>
496
  [% FOREACH DAY_MONTH_HOLIDAYS_LOO IN DAY_MONTH_HOLIDAYS_LOOP %]
497
  <tr>
498
  <td><span title="[% DAY_MONTH_HOLIDAYS_LOO.DATE_SORT %]">[% DAY_MONTH_HOLIDAYS_LOO.DATE %]</span></td>
499
  <td>[% DAY_MONTH_HOLIDAYS_LOO.TITLE %]</td> 
500
  <td>[% DAY_MONTH_HOLIDAYS_LOO.DESCRIPTION %]</td> 
501
  </tr>
502
  [% END %] 
503
</tbody>
504
</table>
505
[% END %]
506
507
[% IF ( HOLIDAYS_LOOP ) %]
508
<h3>Unique Holidays</h3>
509
<table id="holidaysunique">
510
<thead>
511
<tr>
512
  <th class="holiday">Date</th>
513
  <th class="holiday">Title</th>
514
  <th class="holiday">Description</th>
515
</tr>
516
</thead>
517
<tbody>
518
    [% FOREACH HOLIDAYS_LOO IN HOLIDAYS_LOOP %]
519
<tr>
520
  <td><a href="/cgi-bin/koha/tools/holidays.pl?branch=[% branch %]&amp;calendardate=[% HOLIDAYS_LOO.DATE %]"><span title="[% HOLIDAYS_LOO.DATE_SORT %]">[% HOLIDAYS_LOO.DATE %]</span></a></td>
521
  <td>[% HOLIDAYS_LOO.TITLE %]</td>
522
  <td>[% HOLIDAYS_LOO.DESCRIPTION %]</td>
523
</tr>
524
  [% END %] 
525
</tbody>
526
</table>
527
[% END %]
528
</div>
529
</div>
530
</div>
531
</div>
532
</div>
533
534
<div class="yui-b noprint">
535
[% INCLUDE 'tools-menu.inc' %]
536
</div>
537
</div>
538
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt (-1 / +1 lines)
Lines 68-74 Link Here
68
<h3>Additional tools</h3>
68
<h3>Additional tools</h3>
69
<dl>
69
<dl>
70
    [% IF ( CAN_user_tools_edit_calendar ) %]
70
    [% IF ( CAN_user_tools_edit_calendar ) %]
71
    <dt><a href="/cgi-bin/koha/tools/holidays.pl">Calendar</a></dt>
71
    <dt><a href="/cgi-bin/koha/tools/calendar.pl">Calendar</a></dt>
72
    <dd>Define days when the library is closed</dd>
72
    <dd>Define days when the library is closed</dd>
73
    [% END %]
73
    [% END %]
74
74
(-)a/misc/cronjobs/staticfines.pl (-3 / +8 lines)
Lines 40-48 use Date::Calc qw/Date_to_Days/; Link Here
40
use C4::Context;
40
use C4::Context;
41
use C4::Circulation;
41
use C4::Circulation;
42
use C4::Overdues;
42
use C4::Overdues;
43
use C4::Calendar qw();    # don't need any exports from Calendar
44
use C4::Biblio;
43
use C4::Biblio;
45
use C4::Debug;            # supplying $debug and $cgi_debug
44
use C4::Debug;            # supplying $debug and $cgi_debug
45
use Koha::Calendar;
46
46
use Getopt::Long;
47
use Getopt::Long;
47
use List::MoreUtils qw/none/;
48
use List::MoreUtils qw/none/;
48
use Koha::DateUtils;
49
use Koha::DateUtils;
Lines 172-181 for ( my $i = 0 ; $i < scalar(@$data) ; $i++ ) { Link Here
172
173
173
    my $calendar;
174
    my $calendar;
174
    unless ( defined( $calendars{$branchcode} ) ) {
175
    unless ( defined( $calendars{$branchcode} ) ) {
175
        $calendars{$branchcode} = C4::Calendar->new( branchcode => $branchcode );
176
        $calendars{$branchcode} = Koha::Calendar->new( branchcode => $branchcode );
176
    }
177
    }
177
    $calendar = $calendars{$branchcode};
178
    $calendar = $calendars{$branchcode};
178
    my $isHoliday = $calendar->isHoliday( $tday, $tmonth, $tyear );
179
    my $isHoliday = $calendar->is_holiday( DateTime->new( 
180
        year => $tyear,
181
        month => $tmonth,
182
        day => $tday
183
    ) );
179
184
180
    # Reassing datedue_days if -delay specified in commandline
185
    # Reassing datedue_days if -delay specified in commandline
181
    $bigdebug and warn "Using commandline supplied delay : $delay" if ($delay);
186
    $bigdebug and warn "Using commandline supplied delay : $delay" if ($delay);
(-)a/misc/cronjobs/thirdparty/TalkingTech_itiva_outbound.pl (-18 / +13 lines)
Lines 37-43 use C4::Items; Link Here
37
use C4::Letters;
37
use C4::Letters;
38
use C4::Overdues;
38
use C4::Overdues;
39
use C4::Dates;
39
use C4::Dates;
40
use C4::Calendar;
40
use Koha::Calendar;
41
41
42
sub usage {
42
sub usage {
43
    pod2usage( -verbose => 2 );
43
    pod2usage( -verbose => 2 );
Lines 311-333 sub GetWaitingHolds { Link Here
311
          sprintf( "%04d-%02d-%02d", $date_due[0], $date_due[1], $date_due[2] );
311
          sprintf( "%04d-%02d-%02d", $date_due[0], $date_due[1], $date_due[2] );
312
        $issue->{'level'} = 1;   # only one level for Hold Waiting notifications
312
        $issue->{'level'} = 1;   # only one level for Hold Waiting notifications
313
313
314
        my $days_to_subtract = 0;
314
        my $calendar = Koha::Calendar->new( branchcode => $issue->{'site'} );
315
        my $calendar = C4::Calendar->new( branchcode => $issue->{'site'} );
315
        $issue->{'days_since_waiting'} = $calendar->days_between(
316
        while (
316
            DateTime->new(
317
            $calendar->isHoliday(
317
                year => $waitingdate[0],
318
                reverse(
318
                month => $waitingdate[1],
319
                    Add_Delta_Days(
319
                day => $waitingdate[2],
320
                        $waitingdate[0], $waitingdate[1],
320
                time_zone => C4::Context->tz,
321
                        $waitingdate[2], $days_to_subtract
321
            ),
322
                    )
322
            DateTime->now(
323
                )
323
                time_zone => C4::Context->tz,
324
            )
324
            ),
325
          )
325
        );
326
        {
327
            $days_to_subtract++;
328
        }
329
        $issue->{'days_since_waiting'} =
330
          $issue->{'days_since_waiting'} - $days_to_subtract;
331
326
332
        if (
327
        if (
333
            (
328
            (
(-)a/t/Calendar.t (-26 / +117 lines)
Lines 4-20 use strict; Link Here
4
use warnings;
4
use warnings;
5
use DateTime;
5
use DateTime;
6
use DateTime::Duration;
6
use DateTime::Duration;
7
use Test::More tests => 35;
7
use Test::More tests => 51;
8
use Test::MockModule;
8
use Test::MockModule;
9
use DBD::Mock;
9
use DBD::Mock;
10
use Koha::DateUtils;
10
use Koha::DateUtils;
11
11
12
BEGIN {
12
BEGIN {
13
    use_ok('Koha::Calendar');
13
    use_ok('Koha::Calendar');
14
14
    use Carp;
15
    # This was the only test C4 had
15
    $SIG{ __DIE__ } = sub { Carp::confess( @_ ) };
16
    # Remove when no longer used
17
    use_ok('C4::Calendar');
18
}
16
}
19
17
20
my $module_context = new Test::MockModule('C4::Context');
18
my $module_context = new Test::MockModule('C4::Context');
Lines 42-79 SKIP: { Link Here
42
skip "DBD::Mock is too old", 33
40
skip "DBD::Mock is too old", 33
43
  unless $DBD::Mock::VERSION >= 1.45;
41
  unless $DBD::Mock::VERSION >= 1.45;
44
42
43
# Apologies for strange indentation, DBD::Mock is picky
45
my $holidays_session = DBD::Mock::Session->new('holidays_session' => (
44
my $holidays_session = DBD::Mock::Session->new('holidays_session' => (
46
    { # weekly holidays
45
    { # weekly holidays
47
        statement => "SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL",
46
        statement => q{
47
        SELECT
48
            weekday, open_hour, open_minute, close_hour, close_minute,
49
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
50
        FROM calendar_repeats
51
        WHERE branchcode = ? AND weekday IS NOT NULL
52
    },
48
        results   => [
53
        results   => [
49
                        ['weekday'],
54
                        ['weekday', 'open_hour', 'open_minute', 'close_hour', 'close_minute', 'closed'],
50
                        [0],    # sundays
55
                        [0, 0, 0, 0, 0, 1],    # sundays
51
                        [6]     # saturdays
56
                        [1,10, 0,19, 0, 0],    # mondays
57
                        [2,10, 0,19, 0, 0],    # tuesdays
58
                        [6, 0, 0, 0, 0, 1]     # saturdays
52
                     ]
59
                     ]
53
    },
60
    },
54
    { # day and month repeatable holidays
61
    { # day and month repeatable holidays
55
        statement => "SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL",
62
        statement => q{
63
        SELECT
64
            month, day, open_hour, open_minute, close_hour, close_minute,
65
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
66
        FROM calendar_repeats
67
        WHERE branchcode = ? AND weekday IS NULL
68
    },
56
        results   => [
69
        results   => [
57
                        [ 'month', 'day' ],
70
                        [ 'month', 'day', 'open_hour', 'open_minute', 'close_hour', 'close_minute', 'closed' ],
58
                        [ 1, 1 ],   # new year's day
71
                        [ 1, 1, 0, 0, 0, 0, 1],   # new year's day
59
                        [12,25]     # christmas
72
                        [ 6,26,10, 0,15, 0, 0],    # wednesdays
73
                        [12,25, 0, 0, 0, 0, 1]     # christmas
60
                     ]
74
                     ]
61
    },
75
    },
62
    { # exception holidays
76
    { # exception holidays
63
        statement => "SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1",
77
        statement => q{
64
        results   => [
78
        SELECT
65
                        [ 'day', 'month', 'year' ],
79
            event_date, open_hour, open_minute, close_hour, close_minute,
66
                        [ 11, 11, 2012 ] # sunday exception
80
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
67
                     ]
81
        FROM calendar_events
82
        WHERE branchcode = ?
68
    },
83
    },
69
    { # single holidays
70
        statement => "SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0",
71
        results   => [
84
        results   => [
72
                        [ 'day', 'month', 'year' ],
85
                        [ 'event_date', 'open_hour', 'open_minute', 'close_hour', 'close_minute', 'closed' ],
73
                        [ 1, 6, 2011 ],  # single holiday
86
                        [ '2012-11-11', 0, 0,24, 0, 0 ], # sunday exception
74
                        [ 4, 7, 2012 ]
87
                        [ '2011-06-01', 0, 0, 0, 0, 1 ],  # single holiday
88
                        [ '2012-07-04', 0, 0, 0, 0, 1 ],
89
                        [ '2014-06-26',12, 0,14, 0, 0 ]
75
                     ]
90
                     ]
76
    }
91
    },
77
));
92
));
78
93
79
# Initialize the global $dbh variable
94
# Initialize the global $dbh variable
Lines 193-198 my $day_after_christmas = DateTime->new( Link Here
193
        minute    => 53,
208
        minute    => 53,
194
    );
209
    );
195
210
211
    my $same_day_dt = DateTime->new(    # Monday
212
        year      => 2012,
213
        month     => 7,
214
        day       => 23,
215
        hour      => 13,
216
        minute    => 53,
217
    );
218
219
    my $after_close_dt = DateTime->new(    # Monday
220
        year      => 2012,
221
        month     => 7,
222
        day       => 23,
223
        hour      => 22,
224
        minute    => 53,
225
    );
226
196
    my $later_dt = DateTime->new(    # Monday
227
    my $later_dt = DateTime->new(    # Monday
197
        year      => 2012,
228
        year      => 2012,
198
        month     => 9,
229
        month     => 9,
Lines 236-248 my $day_after_christmas = DateTime->new( Link Here
236
    is( $cal->addDate($day_after_christmas, -1, 'days')->ymd(), '2012-12-24',
267
    is( $cal->addDate($day_after_christmas, -1, 'days')->ymd(), '2012-12-24',
237
        'Negative call to addDate (Datedue)' );
268
        'Negative call to addDate (Datedue)' );
238
269
270
    cmp_ok($cal->addDate( $test_dt, DateTime::Duration->new( hours => -10 ), 'hours' ),'eq',
271
        '2012-07-20T15:53:00',
272
        'Subtract 10 hours (Datedue)' );
273
274
    cmp_ok($cal->addDate( $test_dt, DateTime::Duration->new( hours => 10 ), 'hours' ),'eq',
275
        '2012-07-24T12:53:00',
276
        'Add 10 hours (Datedue)' );
277
278
    cmp_ok($cal->addDate( $test_dt, DateTime::Duration->new( hours => -1 ), 'hours' ),'eq',
279
        '2012-07-23T10:53:00',
280
        'Subtract 1 hours (Datedue)' );
281
282
    cmp_ok($cal->addDate( $test_dt, DateTime::Duration->new( hours => 1 ), 'hours' ),'eq',
283
        '2012-07-23T12:53:00',
284
        'Add 1 hours (Datedue)' );
285
239
    ## Note that the days_between API says closed days are not considered.
286
    ## Note that the days_between API says closed days are not considered.
240
    ## This tests are here as an API test.
287
    ## This tests are here as an API test.
241
    cmp_ok( $cal->days_between( $test_dt, $later_dt )->in_units('days'),
288
    cmp_ok( $cal->days_between( $test_dt, $later_dt )->in_units('days'),
242
                '==', 40, 'days_between calculates correctly (Days)' );
289
                '==', 40, 'days_between calculates correctly (Datedue)' );
243
290
244
    cmp_ok( $cal->days_between( $later_dt, $test_dt )->in_units('days'),
291
    cmp_ok( $cal->days_between( $later_dt, $test_dt )->in_units('days'),
245
                '==', 40, 'Test parameter order not relevant (Days)' );
292
                '==', 40, 'Test parameter order not relevant (Datedue)' );
293
294
    cmp_ok( $cal->hours_between( $test_dt, $same_day_dt )->in_units('hours'),
295
                '==', 2, 'hours_between calculates correctly (short period)' );
296
297
    cmp_ok( $cal->hours_between( $test_dt, $after_close_dt )->in_units('hours'),
298
                '==', 7, 'hours_between calculates correctly (after close)' );
299
300
    cmp_ok( $cal->hours_between( $test_dt, $later_dt )->in_units('hours'),
301
                '==', 725, 'hours_between calculates correctly (Datedue)' );
302
303
    cmp_ok( $cal->hours_between( $later_dt, $test_dt )->in_units('hours'),
304
                '==', 725, 'hours_between parameter order not relevant (Datedue)' );
246
305
247
306
248
}
307
}
Lines 278-288 my $day_after_christmas = DateTime->new( Link Here
278
    is( $cal->addDate($day_after_christmas, -1, 'days')->ymd(), '2012-12-24',
337
    is( $cal->addDate($day_after_christmas, -1, 'days')->ymd(), '2012-12-24',
279
            'Negative call to addDate (Calendar)' );
338
            'Negative call to addDate (Calendar)' );
280
339
340
    cmp_ok($cal->addDate( $test_dt, DateTime::Duration->new( hours => -10 ), 'hours' ),'eq',
341
        '2012-07-23T10:00:00',
342
        'Subtract 10 hours (Calendar)' );
343
344
    cmp_ok($cal->addDate( $test_dt, DateTime::Duration->new( hours => 10 ), 'hours' ),'eq',
345
        '2012-07-23T19:00:00',
346
        'Add 10 hours (Calendar)' );
347
348
    cmp_ok($cal->addDate( $test_dt, DateTime::Duration->new( hours => -1 ), 'hours' ),'eq',
349
        '2012-07-23T10:53:00',
350
        'Subtract 1 hours (Calendar)' );
351
352
    cmp_ok($cal->addDate( $test_dt, DateTime::Duration->new( hours => 1 ), 'hours' ),'eq',
353
        '2012-07-23T12:53:00',
354
        'Add 1 hours (Calendar)' );
355
281
    cmp_ok( $cal->days_between( $test_dt, $later_dt )->in_units('days'),
356
    cmp_ok( $cal->days_between( $test_dt, $later_dt )->in_units('days'),
282
                '==', 40, 'days_between calculates correctly (Calendar)' );
357
                '==', 40, 'days_between calculates correctly (Calendar)' );
283
358
284
    cmp_ok( $cal->days_between( $later_dt, $test_dt )->in_units('days'),
359
    cmp_ok( $cal->days_between( $later_dt, $test_dt )->in_units('days'),
285
                '==', 40, 'Test parameter order not relevant (Calendar)' );
360
                '==', 40, 'Test parameter order not relevant (Calendar)' );
361
362
    cmp_ok( $cal->hours_between( $test_dt, $later_dt )->in_units('hours'),
363
                '==', 725, 'hours_between calculates correctly (Calendar)' );
364
365
    cmp_ok( $cal->hours_between( $later_dt, $test_dt )->in_units('hours'),
366
                '==', 725, 'hours_between parameter order not relevant (Calendar)' );
286
}
367
}
287
368
288
369
Lines 315-320 my $day_after_christmas = DateTime->new( Link Here
315
    is( $cal->addDate($day_after_christmas, -1, 'days')->ymd(), '2012-12-25',
396
    is( $cal->addDate($day_after_christmas, -1, 'days')->ymd(), '2012-12-25',
316
        'Negative call to addDate (Days)' );
397
        'Negative call to addDate (Days)' );
317
398
399
    cmp_ok($cal->addDate( $test_dt, DateTime::Duration->new( hours => 10 ), 'hours' ),'eq',
400
        '2012-07-23T21:53:00',
401
        'Add 10 hours (Days)' );
402
318
    ## Note that the days_between API says closed days are not considered.
403
    ## Note that the days_between API says closed days are not considered.
319
    ## This tests are here as an API test.
404
    ## This tests are here as an API test.
320
    cmp_ok( $cal->days_between( $test_dt, $later_dt )->in_units('days'),
405
    cmp_ok( $cal->days_between( $test_dt, $later_dt )->in_units('days'),
Lines 323-328 my $day_after_christmas = DateTime->new( Link Here
323
    cmp_ok( $cal->days_between( $later_dt, $test_dt )->in_units('days'),
408
    cmp_ok( $cal->days_between( $later_dt, $test_dt )->in_units('days'),
324
                '==', 40, 'Test parameter order not relevant (Days)' );
409
                '==', 40, 'Test parameter order not relevant (Days)' );
325
410
411
    cmp_ok( $cal->hours_between( $test_dt, $later_dt )->in_units('hours'),
412
                '==', 725, 'hours_between calculates correctly (Days)' );
413
414
    cmp_ok( $cal->hours_between( $later_dt, $test_dt )->in_units('hours'),
415
                '==', 725, 'hours_between parameter order not relevant (Days)' );
416
326
}
417
}
327
418
328
} # End SKIP block
419
} # End SKIP block
(-)a/t/db_dependent/Calendar.t (+78 lines)
Line 0 Link Here
1
use Modern::Perl;
2
3
use Test::More tests => 18;
4
5
use C4::Calendar;
6
7
my $new_holiday = { open_hour    => 0,
8
                    open_minute  => 0,
9
                    close_hour   => 0,
10
                    close_minute => 0,
11
                    title        => 'example week_day_holiday',
12
                    description  => 'This is an example week_day_holiday used for testing' };
13
14
# Weekly events
15
ModRepeatingEvent( 'MPL', 1, undef, undef, $new_holiday );
16
17
my $weekly_events = GetWeeklyEvents( 'MPL' );
18
is( $weekly_events->[0]->{'title'}, $new_holiday->{'title'}, 'weekly title' );
19
is( $weekly_events->[0]->{'description'}, $new_holiday->{'description'}, 'weekly description' );
20
is( $weekly_events->[0]->{'open_hour'}, 0, 'weekly open_hour' );
21
22
$new_holiday->{open_hour} = 7;
23
24
ModRepeatingEvent( 'MPL', 1, undef, undef, $new_holiday );
25
$weekly_events = GetWeeklyEvents( 'MPL' );
26
is( scalar @$weekly_events, 1, 'weekly modification, not insertion' );
27
is( $weekly_events->[0]->{'open_hour'}, 7, 'weekly open_hour modified' );
28
29
30
# Yearly events
31
32
$new_holiday->{open_hour} = 0;
33
ModRepeatingEvent( 'MPL', undef, 6, 26, $new_holiday );
34
35
my $yearly_events = GetYearlyEvents( 'MPL' );
36
is( $yearly_events->[0]->{'title'}, $new_holiday->{'title'}, 'yearly title' );
37
is( $yearly_events->[0]->{'description'}, $new_holiday->{'description'}, 'yearly description' );
38
is( $yearly_events->[0]->{'open_hour'}, 0, 'yearly open_hour' );
39
40
$new_holiday->{open_hour} = 8;
41
42
ModRepeatingEvent( 'MPL', undef, 6, 26, $new_holiday );
43
$yearly_events = GetYearlyEvents( 'MPL' );
44
is( scalar @$yearly_events, 1, 'yearly modification, not insertion' );
45
is( $yearly_events->[0]->{'open_hour'}, 8, 'yearly open_hour' );
46
47
# Single events
48
49
$new_holiday->{open_hour} = 0;
50
ModSingleEvent( 'MPL', '2013-03-17', $new_holiday );
51
52
my $single_events = GetSingleEvents( 'MPL' );
53
is( $single_events->[0]->{'title'}, $new_holiday->{'title'}, 'single title' );
54
is( $single_events->[0]->{'description'}, $new_holiday->{'description'}, 'single description' );
55
is( $single_events->[0]->{'open_hour'}, 0, 'single open_hour' );
56
57
$new_holiday->{open_hour} = 11;
58
59
ModSingleEvent( 'MPL', '2013-03-17', $new_holiday );
60
$single_events = GetSingleEvents( 'MPL' );
61
is( scalar @$single_events, 1, 'single modification, not insertion' );
62
is( $single_events->[0]->{'open_hour'}, 11, 'single open_hour' );
63
64
65
# delete
66
67
DelRepeatingEvent( 'MPL', 1, undef, undef );
68
$weekly_events = GetWeeklyEvents( 'MPL' );
69
is( scalar @$weekly_events, 0, 'weekly deleted' );
70
71
DelRepeatingEvent( 'MPL', undef, 6, 26 );
72
$yearly_events = GetYearlyEvents( 'MPL' );
73
is( scalar @$yearly_events, 0, 'yearly deleted' );
74
75
DelSingleEvent( 'MPL', '2013-03-17' );
76
77
$single_events = GetSingleEvents( 'MPL' );
78
is( scalar @$single_events, 0, 'single deleted' );
(-)a/t/db_dependent/lib/KohaTest/Calendar/New.pm (-186 lines)
Lines 1-186 Link Here
1
package KohaTest::Calendar::New;
2
use base qw( KohaTest );
3
4
use strict;
5
use warnings;
6
7
use Test::More;
8
9
use C4::Calendar;
10
sub testing_class { 'C4::Calendar' };
11
12
13
=head2 STARTUP METHODS
14
15
These get run once, before the main test methods in this module
16
17
=cut
18
19
=head2 TEST METHODS
20
21
standard test methods
22
23
=head3 instantiation
24
25
  just test to see if I can instantiate an object
26
27
=cut
28
29
sub instantiation : Test( 14 ) {
30
    my $self = shift;
31
32
    my $calendar = C4::Calendar->new( branchcode => '' );
33
    isa_ok( $calendar, 'C4::Calendar' );
34
    # diag( Data::Dumper->Dump( [ $calendar ], [ 'calendar' ] ) );
35
36
    ok( exists $calendar->{'day_month_holidays'}, 'day_month_holidays' );
37
    ok( exists $calendar->{'single_holidays'},    'single_holidays' );
38
    ok( exists $calendar->{'week_days_holidays'}, 'week_days_holidays' );
39
    ok( exists $calendar->{'exception_holidays'}, 'exception_holidays' );
40
41
    # sample data has Sundays as a holiday
42
    ok( exists $calendar->{'week_days_holidays'}->{'0'} );
43
    is( $calendar->{'week_days_holidays'}->{'0'}->{'title'},       '',        'Sunday title' );
44
    is( $calendar->{'week_days_holidays'}->{'0'}->{'description'}, 'Sundays', 'Sunday description' );
45
    
46
    # sample data has Christmas as a holiday
47
    ok( exists $calendar->{'day_month_holidays'}->{'12/25'} );
48
    is( $calendar->{'day_month_holidays'}->{'12/25'}->{'title'},       '',          'Christmas title' );
49
    is( $calendar->{'day_month_holidays'}->{'12/25'}->{'description'}, 'Christmas', 'Christmas description' );
50
    
51
    # sample data has New Year's Day as a holiday
52
    ok( exists $calendar->{'day_month_holidays'}->{'1/1'} );
53
    is( $calendar->{'day_month_holidays'}->{'1/1'}->{'title'},       '',                'New Year title' );
54
    is( $calendar->{'day_month_holidays'}->{'1/1'}->{'description'}, q(New Year's Day), 'New Year description' );
55
    
56
}
57
58
sub week_day_holidays : Test( 8 ) {
59
    my $self = shift;
60
61
    my $calendar = C4::Calendar->new( branchcode => '' );
62
    isa_ok( $calendar, 'C4::Calendar' );
63
    # diag( Data::Dumper->Dump( [ $calendar ], [ 'calendar' ] ) );
64
65
    ok( exists $calendar->{'week_days_holidays'}, 'week_days_holidays' );
66
67
    my %new_holiday = ( weekday     => 1,
68
                        title       => 'example week_day_holiday',
69
                        description => 'This is an example week_day_holiday used for testing' );
70
    my $new_calendar = $calendar->insert_week_day_holiday( %new_holiday );
71
72
    # the calendar object returned from insert_week_day_holiday should be updated
73
    isa_ok( $new_calendar, 'C4::Calendar' );
74
    is( $new_calendar->{'week_days_holidays'}->{ $new_holiday{'weekday'} }->{'title'}, $new_holiday{'title'}, 'title' );
75
    is( $new_calendar->{'week_days_holidays'}->{ $new_holiday{'weekday'} }->{'description'}, $new_holiday{'description'}, 'description' );
76
77
    # new calendar objects should have the newly inserted holiday.
78
    my $refreshed_calendar = C4::Calendar->new( branchcode => '' );
79
    isa_ok( $refreshed_calendar, 'C4::Calendar' );
80
    # diag( Data::Dumper->Dump( [ $calendar ], [ 'calendar' ] ) );
81
    is( $new_calendar->{'week_days_holidays'}->{ $new_holiday{'weekday'} }->{'title'}, $new_holiday{'title'}, 'title' );
82
    is( $new_calendar->{'week_days_holidays'}->{ $new_holiday{'weekday'} }->{'description'}, $new_holiday{'description'}, 'description' );
83
84
}
85
  
86
87
sub day_month_holidays : Test( 8 ) {
88
    my $self = shift;
89
90
    my $calendar = C4::Calendar->new( branchcode => '' );
91
    isa_ok( $calendar, 'C4::Calendar' );
92
    # diag( Data::Dumper->Dump( [ $calendar ], [ 'calendar' ] ) );
93
94
    ok( exists $calendar->{'day_month_holidays'}, 'day_month_holidays' );
95
96
    my %new_holiday = ( day        => 4,
97
                        month       => 5,
98
                        title       => 'example day_month_holiday',
99
                        description => 'This is an example day_month_holiday used for testing' );
100
    my $new_calendar = $calendar->insert_day_month_holiday( %new_holiday );
101
102
    # the calendar object returned from insert_week_day_holiday should be updated
103
    isa_ok( $new_calendar, 'C4::Calendar' );
104
    my $mmdd = sprintf('%s/%s', $new_holiday{'month'}, $new_holiday{'day'} ) ;
105
    is( $new_calendar->{'day_month_holidays'}->{ $mmdd }->{'title'}, $new_holiday{'title'}, 'title' );
106
    is( $new_calendar->{'day_month_holidays'}->{ $mmdd }->{'description'}, $new_holiday{'description'}, 'description' );
107
108
    # new calendar objects should have the newly inserted holiday.
109
    my $refreshed_calendar = C4::Calendar->new( branchcode => '' );
110
    isa_ok( $refreshed_calendar, 'C4::Calendar' );
111
    # diag( Data::Dumper->Dump( [ $calendar ], [ 'calendar' ] ) );
112
    is( $new_calendar->{'day_month_holidays'}->{ $mmdd }->{'title'}, $new_holiday{'title'}, 'title' );
113
    is( $new_calendar->{'day_month_holidays'}->{ $mmdd }->{'description'}, $new_holiday{'description'}, 'description' );
114
115
}
116
  
117
118
119
sub exception_holidays : Test( 8 ) {
120
    my $self = shift;
121
122
    my $calendar = C4::Calendar->new( branchcode => '' );
123
    isa_ok( $calendar, 'C4::Calendar' );
124
    # diag( Data::Dumper->Dump( [ $calendar ], [ 'calendar' ] ) );
125
126
    ok( exists $calendar->{'exception_holidays'}, 'exception_holidays' );
127
128
    my %new_holiday = ( day        => 4,
129
                        month       => 5,
130
                        year        => 2010,
131
                        title       => 'example exception_holiday',
132
                        description => 'This is an example exception_holiday used for testing' );
133
    my $new_calendar = $calendar->insert_exception_holiday( %new_holiday );
134
    # diag( Data::Dumper->Dump( [ $new_calendar ], [ 'newcalendar' ] ) );
135
136
    # the calendar object returned from insert_week_day_holiday should be updated
137
    isa_ok( $new_calendar, 'C4::Calendar' );
138
    my $yyyymmdd = sprintf('%s/%s/%s', $new_holiday{'year'}, $new_holiday{'month'}, $new_holiday{'day'} ) ;
139
    is( $new_calendar->{'exception_holidays'}->{ $yyyymmdd }->{'title'}, $new_holiday{'title'}, 'title' );
140
    is( $new_calendar->{'exception_holidays'}->{ $yyyymmdd }->{'description'}, $new_holiday{'description'}, 'description' );
141
142
    # new calendar objects should have the newly inserted holiday.
143
    my $refreshed_calendar = C4::Calendar->new( branchcode => '' );
144
    isa_ok( $refreshed_calendar, 'C4::Calendar' );
145
    # diag( Data::Dumper->Dump( [ $calendar ], [ 'calendar' ] ) );
146
    is( $new_calendar->{'exception_holidays'}->{ $yyyymmdd }->{'title'}, $new_holiday{'title'}, 'title' );
147
    is( $new_calendar->{'exception_holidays'}->{ $yyyymmdd }->{'description'}, $new_holiday{'description'}, 'description' );
148
149
}
150
151
152
sub single_holidays : Test( 8 ) {
153
    my $self = shift;
154
155
    my $calendar = C4::Calendar->new( branchcode => '' );
156
    isa_ok( $calendar, 'C4::Calendar' );
157
    # diag( Data::Dumper->Dump( [ $calendar ], [ 'calendar' ] ) );
158
159
    ok( exists $calendar->{'single_holidays'}, 'single_holidays' );
160
161
    my %new_holiday = ( day        => 4,
162
                        month       => 5,
163
                        year        => 2011,
164
                        title       => 'example single_holiday',
165
                        description => 'This is an example single_holiday used for testing' );
166
    my $new_calendar = $calendar->insert_single_holiday( %new_holiday );
167
    # diag( Data::Dumper->Dump( [ $new_calendar ], [ 'newcalendar' ] ) );
168
169
    # the calendar object returned from insert_week_day_holiday should be updated
170
    isa_ok( $new_calendar, 'C4::Calendar' );
171
    my $yyyymmdd = sprintf('%s/%s/%s', $new_holiday{'year'}, $new_holiday{'month'}, $new_holiday{'day'} ) ;
172
    is( $new_calendar->{'single_holidays'}->{ $yyyymmdd }->{'title'}, $new_holiday{'title'}, 'title' );
173
    is( $new_calendar->{'single_holidays'}->{ $yyyymmdd }->{'description'}, $new_holiday{'description'}, 'description' );
174
175
    # new calendar objects should have the newly inserted holiday.
176
    my $refreshed_calendar = C4::Calendar->new( branchcode => '' );
177
    isa_ok( $refreshed_calendar, 'C4::Calendar' );
178
    # diag( Data::Dumper->Dump( [ $calendar ], [ 'calendar' ] ) );
179
    is( $new_calendar->{'single_holidays'}->{ $yyyymmdd }->{'title'}, $new_holiday{'title'}, 'title' );
180
    is( $new_calendar->{'single_holidays'}->{ $yyyymmdd }->{'description'}, $new_holiday{'description'}, 'description' );
181
182
}
183
  
184
185
1;
186
(-)a/t/db_dependent/lib/KohaTest/Circulation.pm (-3 lines)
Lines 43-51 sub methods : Test( 1 ) { Link Here
43
                      UpdateHoldingbranch 
43
                      UpdateHoldingbranch 
44
                      CalcDateDue  
44
                      CalcDateDue  
45
                      CheckValidDatedue 
45
                      CheckValidDatedue 
46
                      CheckRepeatableHolidays
47
                      CheckSpecialHolidays
48
                      CheckRepeatableSpecialHolidays
49
                      CheckValidBarcode
46
                      CheckValidBarcode
50
                      ReturnLostItem
47
                      ReturnLostItem
51
                      ProcessOfflinePayment
48
                      ProcessOfflinePayment
(-)a/t/db_dependent/lib/KohaTest/Overdues.pm (-3 lines)
Lines 15-23 sub methods : Test( 1 ) { Link Here
15
    my @methods = qw( Getoverdues 
15
    my @methods = qw( Getoverdues 
16
                       checkoverdues 
16
                       checkoverdues 
17
                       CalcFine 
17
                       CalcFine 
18
                       GetSpecialHolidays 
19
                       GetRepeatableHolidays
20
                       GetWdayFromItemnumber
21
                       GetIssuesIteminfo
18
                       GetIssuesIteminfo
22
                       UpdateFine 
19
                       UpdateFine 
23
                       BorType 
20
                       BorType 
(-)a/tools/calendar.pl (+255 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it under the
6
# terms of the GNU General Public License as published by the Free Software
7
# Foundation; either version 2 of the License, or (at your option) any later
8
# version.
9
#
10
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License along with
15
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
16
# Suite 330, Boston, MA  02111-1307 USA
17
18
#####Sets holiday periods for each branch. Datedues will be extended if branch is closed -TG
19
20
use Modern::Perl '2009';
21
22
use CGI;
23
24
use C4::Auth;
25
use C4::Output;
26
27
use C4::Branch; # GetBranches
28
use C4::Calendar;
29
30
my $input = new CGI;
31
32
my $dbh = C4::Context->dbh();
33
# Get the template to use
34
my ($template, $loggedinuser, $cookie)
35
    = get_template_and_user({template_name => "tools/calendar.tmpl",
36
                             type => "intranet",
37
                             query => $input,
38
                             authnotrequired => 0,
39
                             flagsrequired => {tools => 'edit_calendar'},
40
                             debug => 1,
41
                           });
42
43
# keydate - date passed to calendar.js.  calendar.js does not process dashes within a date.
44
my $keydate;
45
# calendardate - date passed in url for human readability (syspref)
46
my $calendardate;
47
my $today = C4::Dates->new();
48
my $calendarinput = C4::Dates->new($input->param('calendardate')) || $today;
49
# if the url has an invalid date default to 'now.'
50
unless($calendardate = $calendarinput->output('syspref')) {
51
  $calendardate = $today->output('syspref');
52
}
53
unless($keydate = $calendarinput->output('iso')) {
54
  $keydate = $today->output('iso');
55
}
56
$keydate =~ s/-/\//g;
57
58
my $branch= $input->param('branch') || C4::Context->userenv->{'branch'};
59
# Set all the branches.
60
my $onlymine=(C4::Context->preference('IndependentBranches') &&
61
              C4::Context->userenv &&
62
              C4::Context->userenv->{flags} % 2 !=1  &&
63
              C4::Context->userenv->{branch}?1:0);
64
if ( $onlymine ) { 
65
    $branch = C4::Context->userenv->{'branch'};
66
}
67
my $branchname = GetBranchName($branch);
68
my $branches   = GetBranches($onlymine);
69
my @branchloop;
70
for my $thisbranch (
71
    sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} }
72
    keys %{$branches} ) {
73
    push @branchloop,
74
      { value      => $thisbranch,
75
        selected   => $thisbranch eq $branch,
76
        branchname => $branches->{$thisbranch}->{'branchname'},
77
      };
78
}
79
80
# branches calculated - put branch codes in a single string so they can be passed in a form
81
my $branchcodes = join '|', keys %{$branches};
82
83
my $op = $input->param( 'op' ) // '';
84
85
my @ranged_dates;
86
87
if ( my $dateofrange = $input->param( 'dateofrange' ) ) {
88
    my $date = $input->param( 'year' ) . '-' . $input->param( 'month' ) . '-' . $input->param( 'day' );
89
90
    my ( $start_year, $start_month, $start_day ) = split( /-/, $date );
91
    my ( $end_year, $end_month, $end_day ) = split( /-/, C4::Dates->new( $dateofrange )->output( 'iso' ) );
92
93
    if ( $end_year && $end_month && $end_day ){
94
        my $first_dt = DateTime->new(year => $start_year, month => $start_month, day => $start_day);
95
        my $end_dt   = DateTime->new(year => $end_year, month => $end_month, day => $end_day);
96
97
        for ( my $dt = $first_dt->clone(); $dt <= $end_dt; $dt->add(days => 1) ) {
98
            push @ranged_dates, $dt->clone();
99
        }
100
    }
101
}
102
103
my @branches;
104
if ( $input->param( 'allBranches' ) || !$input->param( 'branchName' ) ) {
105
    @branches = split /\|/, $input->param( 'branchcodes' );
106
} else {
107
    @branches = ( $input->param( 'branchName' ) );
108
}
109
110
if ( $op eq 'save' ) {
111
    my $date = $input->param( 'year' ) . '-' . $input->param( 'month' ) . '-' . $input->param( 'day' );
112
113
    my ( $open_hour, $open_minute, $close_hour, $close_minute );
114
115
    if ( $input->param( 'hoursType' ) eq 'open' ) {
116
        ( $open_hour, $open_minute ) = ( 0, 0 );
117
        ( $close_hour, $close_minute ) = ( 24, 0 );
118
    } elsif ( $input->param( 'hoursType' ) eq 'closed' ) {
119
        ( $open_hour, $open_minute ) = ( 0, 0 );
120
        ( $close_hour, $close_minute ) = ( 0, 0 );
121
    } else {
122
        ( $open_hour, $open_minute ) = ( $input->param( 'openTime' ) =~ /(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9])/ );
123
        ( $close_hour, $close_minute ) = ( $input->param( 'closeTime' ) =~ /(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9])/ );
124
    }
125
126
    foreach my $branchcode ( @branches ) {
127
        given ( $input->param( 'eventType' ) ) {
128
            when ( 'single' ) {
129
                ModSingleEvent( $branchcode, $date, {
130
                    title => $input->param( 'title' ),
131
                    description => $input->param( 'description' ),
132
                    open_hour => $open_hour,
133
                    open_minute => $open_minute,
134
                    close_hour => $close_hour,
135
                    close_minute => $close_minute
136
                } );
137
            }
138
139
            when ( 'weekly' ) {
140
                ModRepeatingEvent( $branchcode, $input->param( 'weekday' ), undef, undef, {
141
                    title => $input->param( 'title' ),
142
                    description => $input->param( 'description' ),
143
                    open_hour => $open_hour,
144
                    open_minute => $open_minute,
145
                    close_hour => $close_hour,
146
                    close_minute => $close_minute
147
                } );
148
            }
149
150
            when ( 'yearly' ) {
151
                ModRepeatingEvent( $branchcode, undef, $input->param( 'month' ), $input->param( 'day' ), {
152
                    title => $input->param( 'title' ),
153
                    description => $input->param( 'description' ),
154
                    open_hour => $open_hour,
155
                    open_minute => $open_minute,
156
                    close_hour => $close_hour,
157
                    close_minute => $close_minute
158
                } );
159
            }
160
161
            when ( 'singlerange' ) {
162
                foreach my $dt ( @ranged_dates ) {
163
                    ModSingleEvent( $branchcode, $dt->ymd, {
164
                        title => $input->param( 'title' ),
165
                        description => $input->param( 'description' ),
166
                        open_hour => $open_hour,
167
                        open_minute => $open_minute,
168
                        close_hour => $close_hour,
169
                        close_minute => $close_minute
170
                    } );
171
                }
172
            }
173
174
            when ( 'yearlyrange' ) {
175
                foreach my $dt ( @ranged_dates ) {
176
                    ModRepeatingEvent( $branchcode, undef, $dt->month, $dt->day, {
177
                        title => $input->param( 'title' ),
178
                        description => $input->param( 'description' ),
179
                        open_hour => $open_hour,
180
                        open_minute => $open_minute,
181
                        close_hour => $close_hour,
182
                        close_minute => $close_minute
183
                    } );
184
                }
185
            }
186
        }
187
    }
188
} elsif ( $op eq 'delete' ) {
189
    my $date = $input->param( 'year' ) . '-' . $input->param( 'month' ) . '-' . $input->param( 'day' );
190
191
    foreach my $branchcode ( @branches ) {
192
        given ( $input->param( 'eventType' ) ) {
193
            when ( 'single' ) {
194
                DelSingleEvent( $branchcode, $date );
195
            }
196
197
            when ( 'weekly' ) {
198
                DelRepeatingEvent( $branchcode, $input->param( 'weekday' ), undef, undef );
199
            }
200
201
            when ( 'yearly' ) {
202
                DelRepeatingEvent( $branchcode, undef, $input->param( 'month' ), $input->param( 'day' ) );
203
            }
204
        }
205
    }
206
} elsif ( $op eq 'deleterange' ) {
207
    foreach my $branchcode ( @branches ) {
208
        foreach my $dt ( @ranged_dates ) {
209
            DelSingleEvent( $branchcode, $dt->ymd );
210
        }
211
    }
212
} elsif ( $op eq 'deleterangerepeat' ) {
213
    foreach my $branchcode ( @branches ) {
214
        foreach my $dt ( @ranged_dates ) {
215
            DelRepeatingEvent( $branchcode, undef, $dt->month, $dt->day );
216
        }
217
    }
218
} elsif ( $op eq 'copyall' ) {
219
    CopyAllEvents( $input->param( 'from_branchcode' ), $input->param( 'branchcode' ) );
220
}
221
222
my $yearly_events = GetYearlyEvents($branch);
223
foreach my $event ( @$yearly_events ) {
224
    # Determine date format on month and day.
225
    my $day_monthdate;
226
    my $day_monthdate_sort;
227
    if (C4::Context->preference("dateformat") eq "metric") {
228
      $day_monthdate_sort = "$event->{month}-$event->{day}";
229
      $day_monthdate = "$event->{day}/$event->{month}";
230
    } elsif (C4::Context->preference("dateformat") eq "us") {
231
      $day_monthdate = "$event->{month}/$event->{day}";
232
      $day_monthdate_sort = $day_monthdate;
233
    } else {
234
      $day_monthdate = "$event->{month}-$event->{day}";
235
      $day_monthdate_sort = $day_monthdate;
236
    }
237
238
    $event->{month_day_display} = $day_monthdate;
239
    $event->{month_day_sort} = $day_monthdate_sort;
240
}
241
242
$template->param(
243
    weekly_events            => GetWeeklyEvents($branch),
244
    yearly_events            => $yearly_events,
245
    single_events            => GetSingleEvents($branch),
246
    branchloop               => \@branchloop,
247
    calendardate             => $calendardate,
248
    keydate                  => $keydate,
249
    branchcodes              => $branchcodes,
250
    branch                   => $branch,
251
    branchname               => $branchname,
252
);
253
254
# Shows the template with the real values replaced
255
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/tools/copy-holidays.pl (-39 lines)
Lines 1-39 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2012 Catalyst IT
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
23
use CGI;
24
25
use C4::Auth;
26
use C4::Output;
27
28
29
use C4::Calendar;
30
31
my $input               = new CGI;
32
my $dbh                 = C4::Context->dbh();
33
34
my $branchcode          = $input->param('branchcode');
35
my $from_branchcode     = $input->param('from_branchcode');
36
37
C4::Calendar->new(branchcode => $from_branchcode)->copy_to_branch($branchcode) if $from_branchcode && $branchcode;
38
39
print $input->redirect("/cgi-bin/koha/tools/holidays.pl?branch=".($branchcode || $from_branchcode));
(-)a/tools/exceptionHolidays.pl (-145 lines)
Lines 1-145 Link Here
1
#!/usr/bin/perl
2
3
use strict;
4
use warnings;
5
6
use CGI;
7
8
use C4::Auth;
9
use C4::Output;
10
use DateTime;
11
12
use C4::Calendar;
13
14
my $input = new CGI;
15
my $dbh = C4::Context->dbh();
16
17
my $branchcode = $input->param('showBranchName');
18
my $weekday = $input->param('showWeekday');
19
my $day = $input->param('showDay');
20
my $month = $input->param('showMonth');
21
my $year = $input->param('showYear');
22
my $day1;
23
my $month1;
24
my $year1;
25
my $title = $input->param('showTitle');
26
my $description = $input->param('showDescription');
27
my $holidaytype = $input->param('showHolidayType');
28
my $datecancelrange = $input->param('datecancelrange');
29
my $calendardate = sprintf("%04d-%02d-%02d", $year, $month, $day);
30
my $isodate = C4::Dates->new($calendardate, 'iso');
31
$calendardate = $isodate->output('syspref');
32
33
my $calendar = C4::Calendar->new(branchcode => $branchcode);
34
35
$title || ($title = '');
36
if ($description) {
37
    $description =~ s/\r/\\r/g;
38
    $description =~ s/\n/\\n/g;
39
} else {
40
    $description = '';
41
}   
42
43
# We format the date
44
my @dateend = split(/[\/-]/, $datecancelrange);
45
if (C4::Context->preference("dateformat") eq "metric") {
46
    $day1 = $dateend[0];
47
    $month1 = $dateend[1];
48
    $year1 = $dateend[2];
49
}elsif (C4::Context->preference("dateformat") eq "us") {
50
    $month1 = $dateend[0];
51
    $day1 = $dateend[1];
52
    $year1 = $dateend[2];
53
} else {
54
    $year1 = $dateend[0];
55
    $month1 = $dateend[1];
56
    $day1 = $dateend[2];
57
}
58
59
# We make an array with holiday's days
60
my @holiday_list;
61
if ($year1 && $month1 && $day1){
62
            my $first_dt = DateTime->new(year => $year, month  => $month,  day => $day);
63
            my $end_dt   = DateTime->new(year => $year1, month  => $month1,  day => $day1);
64
65
            for (my $dt = $first_dt->clone();
66
                $dt <= $end_dt;
67
                $dt->add(days => 1) )
68
                {
69
                push @holiday_list, $dt->clone();
70
                }
71
}
72
if ($input->param('showOperation') eq 'exception') {
73
	$calendar->insert_exception_holiday(day => $day,
74
										month => $month,
75
									    year => $year,
76
						                title => $title,
77
						                description => $description);
78
} elsif ($input->param('showOperation') eq 'exceptionrange' ) {
79
        if (@holiday_list){
80
            foreach my $date (@holiday_list){
81
                $calendar->insert_exception_holiday(
82
                    day         => $date->{local_c}->{day},
83
                    month       => $date->{local_c}->{month},
84
                    year       => $date->{local_c}->{year},
85
                    title       => $title,
86
                    description => $description
87
                    );
88
            }
89
        }
90
} elsif ($input->param('showOperation') eq 'edit') {
91
    if($holidaytype eq 'weekday') {
92
      $calendar->ModWeekdayholiday(weekday => $weekday,
93
                                   title => $title,
94
                                   description => $description);
95
    } elsif ($holidaytype eq 'daymonth') {
96
      $calendar->ModDaymonthholiday(day => $day,
97
                                    month => $month,
98
                                    title => $title,
99
                                    description => $description);
100
    } elsif ($holidaytype eq 'ymd') {
101
      $calendar->ModSingleholiday(day => $day,
102
                                  month => $month,
103
                                  year => $year,
104
                                  title => $title,
105
                                  description => $description);
106
    } elsif ($holidaytype eq 'exception') {
107
      $calendar->ModExceptionholiday(day => $day,
108
                                  month => $month,
109
                                  year => $year,
110
                                  title => $title,
111
                                  description => $description);
112
    }
113
} elsif ($input->param('showOperation') eq 'delete') {
114
	$calendar->delete_holiday(weekday => $weekday,
115
	                          day => $day,
116
  	                          month => $month,
117
				              year => $year);
118
}elsif ($input->param('showOperation') eq 'deleterange') {
119
    if (@holiday_list){
120
        foreach my $date (@holiday_list){
121
            $calendar->delete_holiday_range(weekday => $weekday,
122
                                            day => $date->{local_c}->{day},
123
                                            month => $date->{local_c}->{month},
124
                                            year => $date->{local_c}->{year});
125
            }
126
    }
127
}elsif ($input->param('showOperation') eq 'deleterangerepeat') {
128
    if (@holiday_list){
129
        foreach my $date (@holiday_list){
130
           $calendar->delete_holiday_range_repeatable(weekday => $weekday,
131
                                         day => $date->{local_c}->{day},
132
                                         month => $date->{local_c}->{month});
133
        }
134
    }
135
}elsif ($input->param('showOperation') eq 'deleterangerepeatexcept') {
136
    if (@holiday_list){
137
        foreach my $date (@holiday_list){
138
           $calendar->delete_exception_holiday_range(weekday => $weekday,
139
                                         day => $date->{local_c}->{day},
140
                                         month => $date->{local_c}->{month},
141
                                         year => $date->{local_c}->{year});
142
        }
143
    }
144
}
145
print $input->redirect("/cgi-bin/koha/tools/holidays.pl?branch=$branchcode&calendardate=$calendardate");
(-)a/tools/holidays.pl (-163 lines)
Lines 1-163 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it under the
6
# terms of the GNU General Public License as published by the Free Software
7
# Foundation; either version 2 of the License, or (at your option) any later
8
# version.
9
#
10
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License along with
15
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
16
# Suite 330, Boston, MA  02111-1307 USA
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;
23
24
use C4::Auth;
25
use C4::Output;
26
27
use C4::Branch; # GetBranches
28
use C4::Calendar;
29
30
my $input = new CGI;
31
32
my $dbh = C4::Context->dbh();
33
# Get the template to use
34
my ($template, $loggedinuser, $cookie)
35
    = get_template_and_user({template_name => "tools/holidays.tmpl",
36
                             type => "intranet",
37
                             query => $input,
38
                             authnotrequired => 0,
39
                             flagsrequired => {tools => 'edit_calendar'},
40
                             debug => 1,
41
                           });
42
43
# keydate - date passed to calendar.js.  calendar.js does not process dashes within a date.
44
my $keydate;
45
# calendardate - date passed in url for human readability (syspref)
46
my $calendardate;
47
my $today = C4::Dates->new();
48
my $calendarinput = C4::Dates->new($input->param('calendardate')) || $today;
49
# if the url has an invalid date default to 'now.'
50
unless($calendardate = $calendarinput->output('syspref')) {
51
  $calendardate = $today->output('syspref');
52
}
53
unless($keydate = $calendarinput->output('iso')) {
54
  $keydate = $today->output('iso');
55
}
56
$keydate =~ s/-/\//g;
57
58
my $branch= $input->param('branch') || C4::Context->userenv->{'branch'};
59
# Set all the branches.
60
my $onlymine=(C4::Context->preference('IndependentBranches') &&
61
              C4::Context->userenv &&
62
              C4::Context->userenv->{flags} % 2 !=1  &&
63
              C4::Context->userenv->{branch}?1:0);
64
if ( $onlymine ) { 
65
    $branch = C4::Context->userenv->{'branch'};
66
}
67
my $branchname = GetBranchName($branch);
68
my $branches   = GetBranches($onlymine);
69
my @branchloop;
70
for my $thisbranch (
71
    sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} }
72
    keys %{$branches} ) {
73
    push @branchloop,
74
      { value      => $thisbranch,
75
        selected   => $thisbranch eq $branch,
76
        branchname => $branches->{$thisbranch}->{'branchname'},
77
      };
78
}
79
80
# branches calculated - put branch codes in a single string so they can be passed in a form
81
my $branchcodes = join '|', keys %{$branches};
82
83
# Get all the holidays
84
85
my $calendar = C4::Calendar->new(branchcode => $branch);
86
my $week_days_holidays = $calendar->get_week_days_holidays();
87
my @week_days;
88
foreach my $weekday (keys %$week_days_holidays) {
89
# warn "WEEK DAY : $weekday";
90
    my %week_day;
91
    %week_day = (KEY => $weekday,
92
                 TITLE => $week_days_holidays->{$weekday}{title},
93
                 DESCRIPTION => $week_days_holidays->{$weekday}{description});
94
    push @week_days, \%week_day;
95
}
96
97
my $day_month_holidays = $calendar->get_day_month_holidays();
98
my @day_month_holidays;
99
foreach my $monthDay (keys %$day_month_holidays) {
100
    # Determine date format on month and day.
101
    my $day_monthdate;
102
    my $day_monthdate_sort;
103
    if (C4::Context->preference("dateformat") eq "metric") {
104
      $day_monthdate_sort = "$day_month_holidays->{$monthDay}{month}-$day_month_holidays->{$monthDay}{day}";
105
      $day_monthdate = "$day_month_holidays->{$monthDay}{day}/$day_month_holidays->{$monthDay}{month}";
106
    } elsif (C4::Context->preference("dateformat") eq "us") {
107
      $day_monthdate = "$day_month_holidays->{$monthDay}{month}/$day_month_holidays->{$monthDay}{day}";
108
      $day_monthdate_sort = $day_monthdate;
109
    } else {
110
      $day_monthdate = "$day_month_holidays->{$monthDay}{month}-$day_month_holidays->{$monthDay}{day}";
111
      $day_monthdate_sort = $day_monthdate;
112
    }
113
    my %day_month;
114
    %day_month = (KEY => $monthDay,
115
                  DATE_SORT => $day_monthdate_sort,
116
                  DATE => $day_monthdate,
117
                  TITLE => $day_month_holidays->{$monthDay}{title},
118
                  DESCRIPTION => $day_month_holidays->{$monthDay}{description});
119
    push @day_month_holidays, \%day_month;
120
}
121
122
my $exception_holidays = $calendar->get_exception_holidays();
123
my @exception_holidays;
124
foreach my $yearMonthDay (keys %$exception_holidays) {
125
    my $exceptiondate = C4::Dates->new($exception_holidays->{$yearMonthDay}{date}, "iso");
126
    my %exception_holiday;
127
    %exception_holiday = (KEY => $yearMonthDay,
128
                          DATE_SORT => $exception_holidays->{$yearMonthDay}{date},
129
                          DATE => $exceptiondate->output("syspref"),
130
                          TITLE => $exception_holidays->{$yearMonthDay}{title},
131
                          DESCRIPTION => $exception_holidays->{$yearMonthDay}{description});
132
    push @exception_holidays, \%exception_holiday;
133
}
134
135
my $single_holidays = $calendar->get_single_holidays();
136
my @holidays;
137
foreach my $yearMonthDay (keys %$single_holidays) {
138
    my $holidaydate = C4::Dates->new($single_holidays->{$yearMonthDay}{date}, "iso");
139
    my %holiday;
140
    %holiday = (KEY => $yearMonthDay,
141
                DATE_SORT => $single_holidays->{$yearMonthDay}{date},
142
                DATE => $holidaydate->output("syspref"),
143
                TITLE => $single_holidays->{$yearMonthDay}{title},
144
                DESCRIPTION => $single_holidays->{$yearMonthDay}{description});
145
    push @holidays, \%holiday;
146
}
147
148
$template->param(
149
    WEEK_DAYS_LOOP           => \@week_days,
150
    branchloop               => \@branchloop,
151
    HOLIDAYS_LOOP            => \@holidays,
152
    EXCEPTION_HOLIDAYS_LOOP  => \@exception_holidays,
153
    DAY_MONTH_HOLIDAYS_LOOP  => \@day_month_holidays,
154
    calendardate             => $calendardate,
155
    keydate                  => $keydate,
156
    branchcodes              => $branchcodes,
157
    branch                   => $branch,
158
    branchname               => $branchname,
159
    branch                   => $branch,
160
);
161
162
# Shows the template with the real values replaced
163
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/tools/newHolidays.pl (-145 lines)
Lines 1-144 Link Here
1
#!/usr/bin/perl
2
3
use strict;
4
use warnings;
5
6
use CGI;
7
8
use C4::Auth;
9
use C4::Output;
10
11
12
use C4::Calendar;
13
use DateTime;
14
15
my $input               = new CGI;
16
my $dbh                 = C4::Context->dbh();
17
18
our $branchcode          = $input->param('newBranchName');
19
my $originalbranchcode  = $branchcode;
20
our $weekday             = $input->param('newWeekday');
21
our $day                 = $input->param('newDay');
22
our $month               = $input->param('newMonth');
23
our $year                = $input->param('newYear');
24
my $day1;
25
my $month1;
26
my $year1;
27
my $dateofrange         = $input->param('dateofrange');
28
our $title               = $input->param('newTitle');
29
our $description         = $input->param('newDescription');
30
our $newoperation        = $input->param('newOperation');
31
my $allbranches         = $input->param('allBranches');
32
33
my $calendardate        = sprintf("%04d-%02d-%02d", $year, $month, $day);
34
my $isodate             = C4::Dates->new($calendardate, 'iso');
35
$calendardate           = $isodate->output('syspref');
36
37
my @dateend = split(/[\/-]/, $dateofrange);
38
if (C4::Context->preference("dateformat") eq "metric") {
39
    $day1 = $dateend[0];
40
    $month1 = $dateend[1];
41
    $year1 = $dateend[2];
42
}elsif (C4::Context->preference("dateformat") eq "us") {
43
    $month1 = $dateend[0];
44
    $day1 = $dateend[1];
45
    $year1 = $dateend[2];
46
} else {
47
    $year1 = $dateend[0];
48
    $month1 = $dateend[1];
49
    $day1 = $dateend[2];
50
}
51
$title || ($title = '');
52
if ($description) {
53
	$description =~ s/\r/\\r/g;
54
	$description =~ s/\n/\\n/g;
55
} else {
56
	$description = '';
57
}
58
59
# We make an array with holiday's days
60
our @holiday_list;
61
if ($year1 && $month1 && $day1){
62
            my $first_dt = DateTime->new(year => $year, month  => $month,  day => $day);
63
            my $end_dt   = DateTime->new(year => $year1, month  => $month1,  day => $day1);
64
65
            for (my $dt = $first_dt->clone();
66
                $dt <= $end_dt;
67
                $dt->add(days => 1) )
68
                {
69
                push @holiday_list, $dt->clone();
70
                }
71
}
72
73
if($allbranches) {
74
	my $branch;
75
	my @branchcodes = split(/\|/, $input->param('branchCodes')); 
76
	foreach $branch (@branchcodes) {
77
		add_holiday($newoperation, $branch, $weekday, $day, $month, $year, $title, $description);
78
	}
79
} else {
80
	add_holiday($newoperation, $branchcode, $weekday, $day, $month, $year, $title, $description);
81
}
82
83
print $input->redirect("/cgi-bin/koha/tools/holidays.pl?branch=$originalbranchcode&calendardate=$calendardate");
84
85
sub add_holiday {
86
	($newoperation, $branchcode, $weekday, $day, $month, $year, $title, $description) = @_;  
87
	my $calendar = C4::Calendar->new(branchcode => $branchcode);
88
89
	if ($newoperation eq 'weekday') {
90
		unless ( $weekday && ($weekday ne '') ) { 
91
			# was dow calculated by javascript?  original code implies it was supposed to be.
92
			# if not, we need it.
93
			$weekday = &Date::Calc::Day_of_Week($year, $month, $day) % 7 unless($weekday);
94
		}
95
		unless($calendar->isHoliday($day, $month, $year)) {
96
			$calendar->insert_week_day_holiday(weekday => $weekday,
97
							           title => $title,
98
							           description => $description);
99
		}
100
	} elsif ($newoperation eq 'repeatable') {
101
		unless($calendar->isHoliday($day, $month, $year)) {
102
			$calendar->insert_day_month_holiday(day => $day,
103
	                                    month => $month,
104
							            title => $title,
105
							            description => $description);
106
		}
107
	} elsif ($newoperation eq 'holiday') {
108
		unless($calendar->isHoliday($day, $month, $year)) {
109
			$calendar->insert_single_holiday(day => $day,
110
	                                 month => $month,
111
						             year => $year,
112
						             title => $title,
113
						             description => $description);
114
		}
115
116
	} elsif ( $newoperation eq 'holidayrange' ) {
117
        if (@holiday_list){
118
            foreach my $date (@holiday_list){
119
                unless ( $calendar->isHoliday( $date->{local_c}->{day}, $date->{local_c}->{month}, $date->{local_c}->{year} ) ) {
120
                    $calendar->insert_single_holiday(
121
                        day         => $date->{local_c}->{day},
122
                        month       => $date->{local_c}->{month},
123
                        year        => $date->{local_c}->{year},
124
                        title       => $title,
125
                        description => $description
126
                    );
127
                }
128
            }
129
        }
130
    } elsif ( $newoperation eq 'holidayrangerepeat' ) {
131
        if (@holiday_list){
132
            foreach my $date (@holiday_list){
133
                unless ( $calendar->isHoliday( $date->{local_c}->{day}, $date->{local_c}->{month}, $date->{local_c}->{year} ) ) {
134
                    $calendar->insert_day_month_holiday(
135
                        day         => $date->{local_c}->{day},
136
                        month       => $date->{local_c}->{month},
137
                        title       => $title,
138
                        description => $description
139
                    );
140
                }
141
            }
142
        }
143
    }
144
}
145
- 

Return to bug 8133