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

(-)a/C4/Calendar.pm (-97 / +56 lines)
Lines 20-26 use vars qw($VERSION @EXPORT); Link Here
20
20
21
use Carp;
21
use Carp;
22
22
23
use Koha::Database;
23
use C4::Context;
24
24
25
our ( @ISA, @EXPORT );
25
our ( @ISA, @EXPORT );
26
26
Lines 66-75 sub GetSingleEvents { Link Here
66
66
67
    return C4::Context->dbh->selectall_arrayref( q{
67
    return C4::Context->dbh->selectall_arrayref( q{
68
        SELECT
68
        SELECT
69
            CONCAT(LPAD(year, 4, '0'), '-', LPAD(month, 2, '0'), '-', LPAD(day, 2, '0')) as event_date,
69
            event_date, open_hour, open_minute, close_hour, close_minute, title, description,
70
            0 as open_hour, 0 as open_minute, IF(isexception, 24, 0) as close_hour,
70
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
71
            0 as close_minute, title, description, IF(isexception, 0, 1) as closed
71
        FROM calendar_events
72
        FROM special_holidays
73
        WHERE branchcode = ?
72
        WHERE branchcode = ?
74
    }, { Slice => {} }, $branchcode );
73
    }, { Slice => {} }, $branchcode );
75
}
74
}
Lines 87-97 sub GetWeeklyEvents { Link Here
87
86
88
    return C4::Context->dbh->selectall_arrayref( q{
87
    return C4::Context->dbh->selectall_arrayref( q{
89
        SELECT
88
        SELECT
90
            weekday, 0 as open_hour, 0 as open_minute, 0 as close_hour,
89
            weekday, open_hour, open_minute, close_hour, close_minute, title, description,
91
            0 as close_minute, title, description, 1 as closed
90
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
92
        FROM repeatable_holidays
91
        FROM calendar_repeats
93
        WHERE branchcode = ? AND weekday IS NOT NULL
92
        WHERE branchcode = ? AND weekday IS NOT NULL
94
    }, { Slice => {} }, $branchcode );
93
    }, { Slice => {} }, $branchcode ); 
95
}
94
}
96
95
97
=head2 GetYearlyEvents
96
=head2 GetYearlyEvents
Lines 107-236 sub GetYearlyEvents { Link Here
107
106
108
    return C4::Context->dbh->selectall_arrayref( q{
107
    return C4::Context->dbh->selectall_arrayref( q{
109
        SELECT
108
        SELECT
110
            month, day, 0 as open_hour, 0 as open_minute, 0 as close_hour,
109
            month, day, open_hour, open_minute, close_hour, close_minute, title, description,
111
            0 as close_minute, title, description, 1 as closed
110
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
112
        FROM repeatable_holidays
111
        FROM calendar_repeats
113
        WHERE branchcode = ? AND weekday IS NULL
112
        WHERE branchcode = ? AND weekday IS NULL
114
    }, { Slice => {} }, $branchcode );
113
    }, { Slice => {} }, $branchcode );
115
}
114
}
116
115
117
=head2 ModSingleEvent
116
=head2 ModSingleEvent
118
117
119
  ModSingleEvent( $branchcode, \%info )
118
  ModSingleEvent( $branchcode, $date, \%info )
120
119
121
Creates or updates an event for a single date. $info->{date} should be an
120
Creates or updates an event for a single date. $date should be an ISO-formatted
122
ISO-formatted date string, and \%info should also contain the following keys:
121
date string, and \%info should contain the following keys: open_hour,
123
open_hour, open_minute, close_hour, close_minute, title and description.
122
open_minute, close_hour, close_minute, title and description.
124
123
125
=cut
124
=cut
126
125
127
sub ModSingleEvent {
126
sub ModSingleEvent {
128
    my ( $branchcode, $info ) = @_;
127
    my ( $branchcode, $date, $info ) = @_;
129
128
130
    my ( $year, $month, $day ) = ( $info->{date} =~ /(\d+)-(\d+)-(\d+)/ );
129
    C4::Context->dbh->do( q{
131
    return unless ( $year && $month && $day );
130
        INSERT INTO calendar_events(branchcode, event_date, open_hour, open_minute, close_hour, close_minute, title, description)
132
131
        VALUES (?, ?, ?, ?, ?, ?, ?, ?)
133
    my $dbh = C4::Context->dbh;
132
        ON DUPLICATE KEY UPDATE open_hour = ?, open_minute = ?, close_hour = ?, close_minute = ?, title = ?, description = ?
134
    my @args = ( ( map { $info->{$_} } qw(title description) ), $info->{close_hour} != 0, $branchcode, $year, $month, $day );
133
    }, {}, $branchcode, $date, ( map { $info->{$_} } qw(open_hour open_minute close_hour close_minute title description) ) x 2 );
135
136
    # The code below relies on $dbh->do returning 0 when the update affects no rows
137
    my $affected = $dbh->do( q{
138
        UPDATE special_holidays
139
        SET
140
            title = ?, description = ?, isexception = ?
141
        WHERE branchcode = ? AND year = ? AND month = ? AND day = ?
142
    }, {}, @args );
143
144
    $dbh->do( q{
145
        INSERT
146
        INTO special_holidays(title, description, isexception, branchcode, year, month, day)
147
        VALUES (?, ?, ?, ?, ?, ?, ?)
148
    }, {}, @args ) unless ( $affected > 0 );
149
}
134
}
150
135
151
=head2 ModRepeatingEvent
136
=head2 ModRepeatingEvent
152
137
153
  ModRepeatingEvent( $branchcode, \%info )
138
  ModRepeatingEvent( $branchcode, $weekday, $month, $day, \%info )
154
139
155
Creates or updates a weekly- or yearly-repeating event. Either $info->{weekday},
140
Creates or updates a weekly- or yearly-repeating event. Either $weekday,
156
or $info->{month} and $info->{day} should be set, for a weekly or yearly event,
141
or $month and $day should be set, for a weekly or yearly event, respectively.
157
respectively.
158
142
159
=cut
143
=cut
160
144
161
sub _get_compare {
162
    my ( $colname, $value ) = @_;
163
164
    return ' AND ' . $colname . ' ' . ( defined( $value ) ? '=' : 'IS' ) . ' ?';
165
}
166
167
sub ModRepeatingEvent {
145
sub ModRepeatingEvent {
168
    my ( $branchcode, $info ) = @_;
146
    my ( $branchcode, $weekday, $month, $day, $info ) = @_;
169
147
170
    my $dbh = C4::Context->dbh;
148
    C4::Context->dbh->do( q{
171
    my $open = ( $info->{close_hour} != 0 );
149
        INSERT INTO calendar_repeats(branchcode, weekday, month, day, open_hour, open_minute, close_hour, close_minute, title, description)
172
150
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
173
    if ($open) {
151
        ON DUPLICATE KEY UPDATE open_hour = ?, open_minute = ?, close_hour = ?, close_minute = ?, title = ?, description = ?
174
        $dbh->do( q{
152
    }, {}, $branchcode, $weekday, $month, $day, ( map { $info->{$_} } qw(open_hour open_minute close_hour close_minute title description) ) x 2 );
175
            DELETE FROM repeatable_holidays
176
            WHERE branchcode = ?
177
        } . _get_compare( 'weekday', $info->{weekday} ) . _get_compare( 'month', $info->{month} ) . _get_compare( 'day', $info->{day} ), {}, $branchcode, $info->{weekday}, $info->{month}, $info->{day} );
178
    } else {
179
        my @args = ( ( map { $info->{$_} } qw(title description) ), $branchcode, $info->{weekday}, $info->{month}, $info->{day} );
180
181
        # The code below relies on $dbh->do returning 0 when the update affects no rows
182
        my $affected = $dbh->do( q{
183
            UPDATE repeatable_holidays
184
            SET
185
                title = ?, description = ?
186
            WHERE branchcode = ?
187
        } . _get_compare( 'weekday', $info->{weekday} ) . _get_compare( 'month', $info->{month} ) . _get_compare( 'day', $info->{day} ), {}, @args );
188
189
        $dbh->do( q{
190
            INSERT
191
            INTO repeatable_holidays(title, description, branchcode, weekday, month, day)
192
            VALUES (?, ?, ?, ?, ?, ?)
193
        }, {}, @args ) unless ( $affected > 0 );
194
    }
195
}
153
}
196
154
197
=head2 DelSingleEvent
155
=head2 DelSingleEvent
198
156
199
  DelSingleEvent( $branchcode, \%info )
157
  DelSingleEvent( $branchcode, $date, \%info )
200
158
201
Deletes an event for a single date. $info->{date} should be an ISO-formatted date string.
159
Deletes an event for a single date. $date should be an ISO-formatted date string.
202
160
203
=cut
161
=cut
204
162
205
sub DelSingleEvent {
163
sub DelSingleEvent {
206
    my ( $branchcode, $info ) = @_;
164
    my ( $branchcode, $date ) = @_;
207
208
    my ( $year, $month, $day ) = ( $info->{date} =~ /(\d+)-(\d+)-(\d+)/ );
209
    return unless ( $year && $month && $day );
210
165
211
    C4::Context->dbh->do( q{
166
    C4::Context->dbh->do( q{
212
        DELETE FROM special_holidays
167
        DELETE FROM calendar_events
213
        WHERE branchcode = ? AND year = ? AND month = ? AND day = ?
168
        WHERE branchcode = ? AND event_date = ?
214
    }, {}, $branchcode, $year, $month, $day );
169
    }, {}, $branchcode, $date );
170
}
171
172
sub _get_compare {
173
    my ( $colname, $value ) = @_;
174
175
    return ' AND ' . $colname . ' ' . ( defined( $value ) ? '=' : 'IS' ) . ' ?';
215
}
176
}
216
177
217
=head2 DelRepeatingEvent
178
=head2 DelRepeatingEvent
218
179
219
  DelRepeatingEvent( $branchcode, \%info )
180
  DelRepeatingEvent( $branchcode, $weekday, $month, $day )
220
181
221
Deletes a weekly- or yearly-repeating event. Either $info->{weekday}, or
182
Deletes a weekly- or yearly-repeating event. Either $weekday, or $month and
222
$info->{month} and $info->{day} should be set, for a weekly or yearly event,
183
$day should be set, for a weekly or yearly event, respectively.
223
respectively.
224
184
225
=cut
185
=cut
226
186
227
sub DelRepeatingEvent {
187
sub DelRepeatingEvent {
228
    my ( $branchcode, $info ) = @_;
188
    my ( $branchcode, $weekday, $month, $day ) = @_;
229
189
230
    C4::Context->dbh->do( q{
190
    C4::Context->dbh->do( q{
231
        DELETE FROM repeatable_holidays
191
        DELETE FROM calendar_repeats
232
        WHERE branchcode = ?
192
        WHERE branchcode = ?
233
    } . _get_compare( 'weekday', $info->{weekday} ) . _get_compare( 'month', $info->{month} ) . _get_compare( 'day', $info->{day} ), {}, $branchcode, $info->{weekday}, $info->{month}, $info->{day} );
193
    } . _get_compare( 'weekday', $weekday ) . _get_compare( 'month', $month ) . _get_compare( 'day', $day ), {}, $branchcode, $weekday, $month, $day );
234
}
194
}
235
195
236
=head2 CopyAllEvents
196
=head2 CopyAllEvents
Lines 245-260 sub CopyAllEvents { Link Here
245
    my ( $from_branchcode, $to_branchcode ) = @_;
205
    my ( $from_branchcode, $to_branchcode ) = @_;
246
206
247
    C4::Context->dbh->do( q{
207
    C4::Context->dbh->do( q{
248
        INSERT IGNORE INTO special_holidays(branchcode, year, month, day, isexception, title, description)
208
        INSERT IGNORE INTO calendar_events(branchcode, event_date, open_hour, open_minute, close_hour, close_minute, title, description)
249
        SELECT ?, year, month, day, isexception, title, description
209
        SELECT ?, event_date, open_hour, open_minute, close_hour, close_minute, title, description
250
        FROM special_holidays
210
        FROM calendar_events
251
        WHERE branchcode = ?
211
        WHERE branchcode = ?
252
    }, {}, $to_branchcode, $from_branchcode );
212
    }, {}, $to_branchcode, $from_branchcode );
253
213
254
    C4::Context->dbh->do( q{
214
    C4::Context->dbh->do( q{
255
        INSERT IGNORE INTO repeatable_holidays(branchcode, weekday, month, day, title, description)
215
        INSERT IGNORE INTO calendar_repeats(branchcode, weekday, month, day, open_hour, open_minute, close_hour, close_minute, title, description)
256
        SELECT ?, weekday, month, day, title, description
216
        SELECT ?, weekday, month, day, open_hour, open_minute, close_hour, close_minute, title, description
257
        FROM repeatable_holidays
217
        FROM calendar_repeats
258
        WHERE branchcode = ?
218
        WHERE branchcode = ?
259
    }, {}, $to_branchcode, $from_branchcode );
219
    }, {}, $to_branchcode, $from_branchcode );
260
}
220
}
Lines 267-272 __END__ Link Here
267
=head1 AUTHOR
227
=head1 AUTHOR
268
228
269
Koha Physics Library UNLP <matias_veleda@hotmail.com>
229
Koha Physics Library UNLP <matias_veleda@hotmail.com>
270
Jesse Weaver <jweaver@bywatersolutions.com>
271
230
272
=cut
231
=cut
(-)a/C4/Circulation.pm (+2 lines)
Lines 3337-3342 sub CalcDateDue { Link Here
3337
    return $datedue;
3337
    return $datedue;
3338
}
3338
}
3339
3339
3340
3341
3340
sub CheckValidBarcode{
3342
sub CheckValidBarcode{
3341
my ($barcode) = @_;
3343
my ($barcode) = @_;
3342
my $dbh = C4::Context->dbh;
3344
my $dbh = C4::Context->dbh;
(-)a/Koha/Calendar.pm (-154 / +177 lines)
Lines 29-119 sub _init { Link Here
29
    my $self       = shift;
29
    my $self       = shift;
30
    my $branch     = $self->{branchcode};
30
    my $branch     = $self->{branchcode};
31
    my $dbh        = C4::Context->dbh();
31
    my $dbh        = C4::Context->dbh();
32
    my $weekly_closed_days_sth = $dbh->prepare(
32
33
'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL'
33
    $self->{weekday_hours} = $dbh->selectall_hashref( q{
34
    );
34
        SELECT
35
    $weekly_closed_days_sth->execute( $branch );
35
            weekday, open_hour, open_minute, close_hour, close_minute,
36
    $self->{weekly_closed_days} = [ 0, 0, 0, 0, 0, 0, 0 ];
36
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
37
    Readonly::Scalar my $sunday => 7;
37
        FROM calendar_repeats
38
    while ( my $tuple = $weekly_closed_days_sth->fetchrow_hashref ) {
38
        WHERE branchcode = ? AND weekday IS NOT NULL
39
        $self->{weekly_closed_days}->[ $tuple->{weekday} ] = 1;
39
    }, 'weekday', { Slice => {} }, $branch ); 
40
    }
40
41
    my $day_month_closed_days_sth = $dbh->prepare(
41
    my $day_month_hours = $dbh->selectall_arrayref( q{
42
'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL'
42
        SELECT
43
    );
43
            month, day, open_hour, open_minute, close_hour, close_minute,
44
    $day_month_closed_days_sth->execute( $branch );
44
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
45
    $self->{day_month_closed_days} = {};
45
        FROM calendar_repeats
46
    while ( my $tuple = $day_month_closed_days_sth->fetchrow_hashref ) {
46
        WHERE branchcode = ? AND weekday IS NULL
47
        $self->{day_month_closed_days}->{ $tuple->{month} }->{ $tuple->{day} } =
47
    }, { Slice => {} }, $branch );
48
          1;
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;
49
    }
52
    }
50
53
54
    $self->{date_hours} = $dbh->selectall_hashref( q{
55
        SELECT
56
            event_date, open_hour, open_minute, close_hour, close_minute,
57
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
58
        FROM calendar_events
59
        WHERE branchcode = ?
60
    }, 'event_date', { Slice => {} }, $branch );
61
51
    $self->{days_mode}       = C4::Context->preference('useDaysMode');
62
    $self->{days_mode}       = C4::Context->preference('useDaysMode');
52
    $self->{test}            = 0;
63
    $self->{test}            = 0;
53
    return;
64
    return;
54
}
65
}
55
66
56
57
# FIXME: use of package-level variables for caching the holiday
58
# lists breaks persistance engines.  As of 2013-12-10, the RM
59
# is allowing this with the expectation that prior to release of
60
# 3.16, bug 8089 will be fixed and we can switch the caching over
61
# to Koha::Cache.
62
our ( $exception_holidays, $single_holidays );
63
sub _exception_holidays {
64
    my ( $self ) = @_;
65
    my $dbh = C4::Context->dbh;
66
    my $branch = $self->{branchcode};
67
    if ( $exception_holidays ) {
68
        $self->{exception_holidays} = $exception_holidays;
69
        return $exception_holidays;
70
    }
71
    my $exception_holidays_sth = $dbh->prepare(
72
'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1'
73
    );
74
    $exception_holidays_sth->execute( $branch );
75
    my $dates = [];
76
    while ( my ( $day, $month, $year ) = $exception_holidays_sth->fetchrow ) {
77
        push @{$dates},
78
          DateTime->new(
79
            day       => $day,
80
            month     => $month,
81
            year      => $year,
82
            time_zone => C4::Context->tz()
83
          )->truncate( to => 'day' );
84
    }
85
    $self->{exception_holidays} =
86
      DateTime::Set->from_datetimes( dates => $dates );
87
    $exception_holidays = $self->{exception_holidays};
88
    return $exception_holidays;
89
}
90
91
sub _single_holidays {
92
    my ( $self ) = @_;
93
    my $dbh = C4::Context->dbh;
94
    my $branch = $self->{branchcode};
95
    if ( $single_holidays ) {
96
        $self->{single_holidays} = $single_holidays;
97
        return $single_holidays;
98
    }
99
    my $single_holidays_sth = $dbh->prepare(
100
'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0'
101
    );
102
    $single_holidays_sth->execute( $branch );
103
    my $dates = [];
104
    while ( my ( $day, $month, $year ) = $single_holidays_sth->fetchrow ) {
105
        push @{$dates},
106
          DateTime->new(
107
            day       => $day,
108
            month     => $month,
109
            year      => $year,
110
            time_zone => C4::Context->tz()
111
          )->truncate( to => 'day' );
112
    }
113
    $self->{single_holidays} = DateTime::Set->from_datetimes( dates => $dates );
114
    $single_holidays = $self->{single_holidays};
115
    return $single_holidays;
116
}
117
sub addDate {
67
sub addDate {
118
    my ( $self, $startdate, $add_duration, $unit ) = @_;
68
    my ( $self, $startdate, $add_duration, $unit ) = @_;
119
69
Lines 126-135 sub addDate { Link Here
126
    my $dt;
76
    my $dt;
127
77
128
    if ( $unit eq 'hours' ) {
78
    if ( $unit eq 'hours' ) {
129
        # Fixed for legacy support. Should be set as a branch parameter
79
        $dt = $self->addHours($startdate, $add_duration);
130
        Readonly::Scalar my $return_by_hour => 10;
131
132
        $dt = $self->addHours($startdate, $add_duration, $return_by_hour);
133
    } else {
80
    } else {
134
        # days
81
        # days
135
        $dt = $self->addDays($startdate, $add_duration);
82
        $dt = $self->addDays($startdate, $add_duration);
Lines 139-163 sub addDate { Link Here
139
}
86
}
140
87
141
sub addHours {
88
sub addHours {
142
    my ( $self, $startdate, $hours_duration, $return_by_hour ) = @_;
89
    my ( $self, $startdate, $hours_duration ) = @_;
143
    my $base_date = $startdate->clone();
90
    my $base_date = $startdate->clone();
144
91
145
    $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
        }
146
109
147
    # If we are using the calendar behave for now as if Datedue
110
        while ( $hours_duration->is_negative ) {
148
    # was the chosen option (current intended behaviour)
111
            my $day_len = $hours->{open_time} - $base_date;
149
112
150
    if ( $self->{days_mode} ne 'Days' &&
113
            if ( DateTime::Duration->compare( $day_len, $hours_duration, $base_date ) > 0 ) {
151
          $self->is_holiday($base_date) ) {
114
                if ( $self->{days_mode} eq 'Calendar' ) { 
115
                    return $hours->{open_time};
116
                }
152
117
153
        if ( $hours_duration->is_negative() ) {
118
                $hours_duration->subtract( $day_len );
154
            $base_date = $self->prev_open_day($base_date);
119
                $base_date = $self->prev_open_day( $base_date );
155
        } else {
120
                $hours = $self->get_hours_full( $base_date );
156
            $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
            }
157
        }
137
        }
158
138
159
        $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
                }
160
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
        }
161
    }
156
    }
162
157
163
    return $base_date;
158
    return $base_date;
Lines 207-239 sub addDays { Link Here
207
202
208
sub is_holiday {
203
sub is_holiday {
209
    my ( $self, $dt ) = @_;
204
    my ( $self, $dt ) = @_;
210
    my $localdt = $dt->clone();
205
    my $day   = $dt->day;
211
    my $day   = $localdt->day;
206
    my $month = $dt->month;
212
    my $month = $localdt->month;
213
214
    $localdt->truncate( to => 'day' );
215
207
216
    if ( $self->_exception_holidays->contains($localdt) ) {
208
    if ( exists $self->{date_hours}->{ $dt->ymd } && !$self->{date_hours}->{ $dt->ymd }->{closed} ) {
217
        # exceptions are not holidays
218
        return 0;
209
        return 0;
219
    }
210
    }
220
211
221
    my $dow = $localdt->day_of_week;
212
    if ( ( $self->{day_month_hours}->{$month}->{$day} || {} )->{closed} ) {
222
    # Representation fix
223
    # TODO: Shouldn't we shift the rest of the $dow also?
224
    if ( $dow == 7 ) {
225
        $dow = 0;
226
    }
227
228
    if ( $self->{weekly_closed_days}->[$dow] == 1 ) {
229
        return 1;
213
        return 1;
230
    }
214
    }
231
215
232
    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} ) {
233
        return 1;
220
        return 1;
234
    }
221
    }
235
222
236
    if ( $self->_single_holidays->contains($localdt) ) {
223
    if ( ( $self->{date_hours}->{ $dt->ymd } || {} )->{closed} ) {
237
        return 1;
224
        return 1;
238
    }
225
    }
239
226
Lines 241-246 sub is_holiday { Link Here
241
    return 0;
228
    return 0;
242
}
229
}
243
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
244
sub next_open_day {
285
sub next_open_day {
245
    my ( $self, $dt ) = @_;
286
    my ( $self, $dt ) = @_;
246
    my $base_date = $dt->clone();
287
    my $base_date = $dt->clone();
Lines 298-342 sub hours_between { Link Here
298
    my ($self, $start_date, $end_date) = @_;
339
    my ($self, $start_date, $end_date) = @_;
299
    my $start_dt = $start_date->clone();
340
    my $start_dt = $start_date->clone();
300
    my $end_dt = $end_date->clone();
341
    my $end_dt = $end_date->clone();
301
    my $duration = $end_dt->delta_ms($start_dt);
342
302
    $start_dt->truncate( to => 'day' );
343
    if ( $start_dt->compare($end_dt) > 0 ) {
303
    $end_dt->truncate( to => 'day' );
344
        # swap dates
304
    # NB this is a kludge in that it assumes all days are 24 hours
345
        my $int_dt = $end_dt;
305
    # However for hourly loans the logic should be expanded to
346
        $end_dt = $start_dt;
306
    # take into account open/close times then it would be a duration
347
        $start_dt = $int_dt;
307
    # of library open hours
308
    my $skipped_days = 0;
309
    for (my $dt = $start_dt->clone();
310
        $dt <= $end_dt;
311
        $dt->add(days => 1)
312
    ) {
313
        if ($self->is_holiday($dt)) {
314
            ++$skipped_days;
315
        }
316
    }
317
    if ($skipped_days) {
318
        $duration->subtract_duration(DateTime::Duration->new( hours => 24 * $skipped_days));
319
    }
348
    }
320
349
321
    return $duration;
350
    my $start_hours = $self->get_hours_full( $start_dt );
351
    my $end_hours = $self->get_hours_full( $end_dt );
322
352
323
}
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} );
355
356
    return $end_dt - $start_dt if ( $start_dt->ymd eq $end_dt->ymd );
324
357
325
sub set_daysmode {
358
    my $duration = DateTime::Duration->new;
326
    my ( $self, $mode ) = @_;
359
    
360
    $duration->add_duration( $start_hours->{close_time} - $start_dt ) if ( $start_dt < $start_hours->{close_time} );
327
361
328
    # if not testing this is a no op
362
    for (my $date = $start_dt->clone->truncate( to => 'day' )->add( days => 1 );
329
    if ( $self->{test} ) {
363
        $date->ymd lt $end_dt->ymd;
330
        $self->{days_mode} = $mode;
364
        $date->add(days => 1)
365
    ) {
366
        my $hours = $self->get_hours_full( $date );
367
368
        $duration->add_duration( $hours->{close_time}->delta_ms( $hours->{open_time} ) );
331
    }
369
    }
332
370
333
    return;
371
    $duration->add_duration( $end_dt - $end_hours->{open_time} ) if ( $end_dt > $start_hours->{open_time} );
334
}
372
373
    return $duration;
335
374
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
}
375
}
341
376
342
1;
377
1;
Lines 392-405 parameter will be removed when issuingrules properly cope with that Link Here
392
427
393
=head2 addHours
428
=head2 addHours
394
429
395
    my $dt = $calendar->addHours($date, $dur, $return_by_hour )
430
    my $dt = $calendar->addHours($date, $dur )
396
431
397
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.
398
433
399
C<$offset> is a DateTime::Duration to add to it
434
C<$offset> is a DateTime::Duration to add to it
400
435
401
C<$return_by_hour> is an integer value representing the opening hour for the branch
402
403
436
404
=head2 addDays
437
=head2 addDays
405
438
Lines 446-461 Passed a Datetime returns another Datetime representing the previous open day. I Link Here
446
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
447
'Datedue' or 'Calendar'.
480
'Datedue' or 'Calendar'.
448
481
449
=head2 set_daysmode
450
451
For testing only allows the calling script to change days mode
452
453
=head2 clear_weekly_closed_days
454
455
In test mode changes the testing set of closed days to a new set with
456
no closed days. TODO passing an array of closed days to this would
457
allow testing of more configurations
458
459
=head1 DIAGNOSTICS
482
=head1 DIAGNOSTICS
460
483
461
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 667-672 CREATE TABLE `default_circ_rules` ( Link Here
667
    PRIMARY KEY (`singleton`)
667
    PRIMARY KEY (`singleton`)
668
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
668
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
669
669
670
671
--
672
-- Table structure for table `calendar_events`
673
--
674
DROP TABLE IF EXISTS `calendar_events`;
675
CREATE TABLE `calendar_events` (
676
    `branchcode` varchar(10) NOT NULL DEFAULT '',
677
    `event_date` date NOT NULL,
678
    `title` varchar(50) NOT NULL DEFAULT '',
679
    `description` text NOT NULL,
680
    `open_hour` smallint(6) NOT NULL,
681
    `open_minute` smallint(6) NOT NULL,
682
    `close_hour` smallint(6) NOT NULL,
683
    `close_minute` smallint(6) NOT NULL,
684
    PRIMARY KEY (`branchcode`,`event_date`),
685
    CONSTRAINT `calendar_events_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`)
686
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
687
688
--
689
-- Table structure for table `calendar_repeats`
690
--
691
DROP TABLE IF EXISTS `calendar_repeats`;
692
CREATE TABLE `calendar_repeats` (
693
    `branchcode` varchar(10) NOT NULL DEFAULT '',
694
    `weekday` smallint(6) DEFAULT NULL,
695
    `month` smallint(6) DEFAULT NULL,
696
    `day` smallint(6) DEFAULT NULL,
697
    `title` varchar(50) NOT NULL DEFAULT '',
698
    `description` text NOT NULL,
699
    `open_hour` smallint(6) NOT NULL,
700
    `open_minute` smallint(6) NOT NULL,
701
    `close_hour` smallint(6) NOT NULL,
702
    `close_minute` smallint(6) NOT NULL,
703
    UNIQUE KEY `branchcode` (`branchcode`,`weekday`),
704
    UNIQUE KEY `branchcode_2` (`branchcode`,`month`,`day`),
705
    CONSTRAINT `calendar_repeats_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`)
706
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
670
--
707
--
671
-- Table structure for table `cities`
708
-- Table structure for table `cities`
672
--
709
--
Lines 1766-1787 CREATE TABLE `printers_profile` ( Link Here
1766
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1803
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1767
1804
1768
--
1805
--
1769
-- Table structure for table `repeatable_holidays`
1770
--
1771
1772
DROP TABLE IF EXISTS `repeatable_holidays`;
1773
CREATE TABLE `repeatable_holidays` ( -- information for the days the library is closed
1774
  `id` int(11) NOT NULL auto_increment, -- unique identifier assigned by Koha
1775
  `branchcode` varchar(10) NOT NULL default '', -- foreign key from the branches table, defines which branch this closing is for
1776
  `weekday` smallint(6) default NULL, -- day of the week (0=Sunday, 1=Monday, etc) this closing is repeated on
1777
  `day` smallint(6) default NULL, -- day of the month this closing is on
1778
  `month` smallint(6) default NULL, -- month this closing is in
1779
  `title` varchar(50) NOT NULL default '', -- title of this closing
1780
  `description` text NOT NULL, -- description for this closing
1781
  PRIMARY KEY  (`id`)
1782
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1783
1784
--
1785
-- Table structure for table `reports_dictionary`
1806
-- Table structure for table `reports_dictionary`
1786
--
1807
--
1787
1808
Lines 1954-1976 CREATE TABLE sessions ( Link Here
1954
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1975
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1955
1976
1956
--
1977
--
1957
-- Table structure for table `special_holidays`
1958
--
1959
1960
DROP TABLE IF EXISTS `special_holidays`;
1961
CREATE TABLE `special_holidays` ( -- non repeatable holidays/library closings
1962
  `id` int(11) NOT NULL auto_increment, -- unique identifier assigned by Koha
1963
  `branchcode` varchar(10) NOT NULL default '', -- foreign key from the branches table, defines which branch this closing is for
1964
  `day` smallint(6) NOT NULL default 0, -- day of the month this closing is on
1965
  `month` smallint(6) NOT NULL default 0, -- month this closing is in
1966
  `year` smallint(6) NOT NULL default 0, -- year this closing is in
1967
  `isexception` smallint(1) NOT NULL default 1, -- is this a holiday exception to a repeatable holiday (1 for yes, 0 for no)
1968
  `title` varchar(50) NOT NULL default '', -- title for this closing
1969
  `description` text NOT NULL, -- description of this closing
1970
  PRIMARY KEY  (`id`)
1971
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1972
1973
--
1974
-- Table structure for table `statistics`
1978
-- Table structure for table `statistics`
1975
--
1979
--
1976
1980
(-)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 (+76 lines)
Lines 8778-8783 if ( CheckVersion($DBversion) ) { Link Here
8778
        INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('StatisticsFields','location|itype|ccode','Define fields (from the items table) used for statistics members',NULL,'Free')
8778
        INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('StatisticsFields','location|itype|ccode','Define fields (from the items table) used for statistics members',NULL,'Free')
8779
    });
8779
    });
8780
    print "Upgrade to $DBversion done (Bug 12728: Checked syspref StatisticsFields)\n";
8780
    print "Upgrade to $DBversion done (Bug 12728: Checked syspref StatisticsFields)\n";
8781
8782
    SetVersion($DBversion);
8783
}
8784
8785
$DBversion = "3.17.00.XXX";
8786
if ( CheckVersion($DBversion) ) {
8787
    print "Upgrade to $DBversion done (Bug 8133: create tables, migrate data to calendar_*)\n";
8788
8789
    $dbh->do( q{
8790
        CREATE TABLE `calendar_events` (
8791
          `branchcode` varchar(10) NOT NULL DEFAULT '',
8792
          `event_date` date NOT NULL,
8793
          `title` varchar(50) NOT NULL DEFAULT '',
8794
          `description` text NOT NULL,
8795
          `open_hour` smallint(6) NOT NULL,
8796
          `open_minute` smallint(6) NOT NULL,
8797
          `close_hour` smallint(6) NOT NULL,
8798
          `close_minute` smallint(6) NOT NULL,
8799
          PRIMARY KEY (`branchcode`,`event_date`),
8800
          CONSTRAINT `calendar_events_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`)
8801
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
8802
    } );
8803
8804
    $dbh->do( q{
8805
        CREATE TABLE `calendar_repeats` (
8806
          `branchcode` varchar(10) NOT NULL DEFAULT '',
8807
          `weekday` smallint(6) DEFAULT NULL,
8808
          `month` smallint(6) DEFAULT NULL,
8809
          `day` smallint(6) DEFAULT NULL,
8810
          `title` varchar(50) NOT NULL DEFAULT '',
8811
          `description` text NOT NULL,
8812
          `open_hour` smallint(6) NOT NULL,
8813
          `open_minute` smallint(6) NOT NULL,
8814
          `close_hour` smallint(6) NOT NULL,
8815
          `close_minute` smallint(6) NOT NULL,
8816
          UNIQUE KEY `branchcode` (`branchcode`,`weekday`),
8817
          UNIQUE KEY `branchcode_2` (`branchcode`,`month`,`day`),
8818
          CONSTRAINT `calendar_repeats_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`)
8819
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
8820
    } );
8821
8822
    $dbh->do( q{
8823
        INSERT INTO
8824
          calendar_events(branchcode, event_date, title, description, open_hour, open_minute, close_hour, close_minute)
8825
        SELECT
8826
          branchcode, CONCAT_WS('-', year, month, day), title, description, 0, 0, 0, 0
8827
          FROM special_holidays
8828
          WHERE isexception = 0
8829
    } );
8830
8831
    $dbh->do( q{
8832
        INSERT INTO
8833
          calendar_events(branchcode, event_date, title, description, open_hour, open_minute, close_hour, close_minute)
8834
        SELECT
8835
          branchcode, CONCAT_WS('-', year, month, day), title, description, 0, 0, 24, 0
8836
          FROM special_holidays
8837
          WHERE isexception = 1
8838
    } );
8839
8840
    $dbh->do( q{
8841
        INSERT INTO
8842
          calendar_repeats(branchcode, weekday, month, day, title, description, open_hour, open_minute, close_hour, close_minute)
8843
        SELECT
8844
          branchcode, weekday, month, day, title, description, 0, 0, 0, 0
8845
          FROM repeatable_holidays
8846
          WHERE weekday IS NULL
8847
    } );
8848
8849
    $dbh->do( q{
8850
        DROP TABLE repeatable_holidays;
8851
    } );
8852
8853
    $dbh->do( q{
8854
        DROP TABLE special_holidays;
8855
    } );
8856
8781
    SetVersion($DBversion);
8857
    SetVersion($DBversion);
8782
}
8858
}
8783
8859
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc (-1 / +1 lines)
Lines 87-93 Link Here
87
<h5>Additional tools</h5>
87
<h5>Additional tools</h5>
88
<ul>
88
<ul>
89
    [% IF ( CAN_user_tools_edit_calendar ) %]
89
    [% IF ( CAN_user_tools_edit_calendar ) %]
90
        <li><a href="/cgi-bin/koha/tools/calendar.pl">Calendar</a></li>
90
	<li><a href="/cgi-bin/koha/tools/calendar.pl">Calendar</a></li>
91
    [% END %]
91
    [% END %]
92
    [% IF ( CAN_user_tools_manage_csv_profiles ) %]
92
    [% IF ( CAN_user_tools_manage_csv_profiles ) %]
93
	<li><a href="/cgi-bin/koha/tools/csv-profiles.pl">CSV profiles</a></li>
93
	<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 (-26 / +30 lines)
Lines 5-11 Link Here
5
[% INCLUDE 'doc-head-close.inc' %]
5
[% INCLUDE 'doc-head-close.inc' %]
6
[% INCLUDE 'calendar.inc' %]
6
[% INCLUDE 'calendar.inc' %]
7
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
7
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
8
[% INCLUDE 'datatables.inc' %]
8
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.dataTables.min.js"></script>
9
[% INCLUDE 'datatables-strings.inc' %]
10
<script type="text/javascript" src="[% themelang %]/js/datatables.js"></script>
9
<script language="JavaScript" type="text/javascript">
11
<script language="JavaScript" type="text/javascript">
10
//<![CDATA[
12
//<![CDATA[
11
    [% IF (dateformat == 'metric') %]dt_add_type_uk_date();[% END %]
13
    [% IF (dateformat == 'metric') %]dt_add_type_uk_date();[% END %]
Lines 87-93 Link Here
87
        $('#showWeekday:first').val(weekDay);
89
        $('#showWeekday:first').val(weekDay);
88
        $('#showTitle').val(event.title);
90
        $('#showTitle').val(event.title);
89
        $('#showEventType').val(event.eventType);
91
        $('#showEventType').val(event.eventType);
90
92
        
91
        if (event.closed) {
93
        if (event.closed) {
92
            $('#showHoursTypeClosed')[0].checked = true;
94
            $('#showHoursTypeClosed')[0].checked = true;
93
        } else if (event.close_hour == 24) {
95
        } else if (event.close_hour == 24) {
Lines 95-102 Link Here
95
        } else {
97
        } else {
96
            $('#showHoursTypeOpenSet')[0].checked = true;
98
            $('#showHoursTypeOpenSet')[0].checked = true;
97
            $('#showHoursTypeOpenSet').change();
99
            $('#showHoursTypeOpenSet').change();
98
            $('#showOpenTime').val(event.open_hour + ':' + zeroPad(event.open_minute));
100
            $('#showOpenTime').val(event.open_hour + ':' + zeroPad(event.open_minute)); 
99
            $('#showCloseTime').val(event.close_hour + ':' + zeroPad(event.close_minute));
101
            $('#showCloseTime').val(event.close_hour + ':' + zeroPad(event.close_minute)); 
100
        }
102
        }
101
103
102
        $("#operationDelLabel").html(_("Delete this event."));
104
        $("#operationDelLabel").html(_("Delete this event."));
Lines 215-221 Link Here
215
            defaultDate: new Date("[% keydate %]")
217
            defaultDate: new Date("[% keydate %]")
216
        });
218
        });
217
        $(".hourssel input").change(function() {
219
        $(".hourssel input").change(function() {
218
            $(".hoursentry", this.form).toggle(this.value == 'openSet');
220
            $(".hoursentry", this.form).toggle(this.value == 'openSet'); 
219
        }).each( function() { this.checked = false } );
221
        }).each( function() { this.checked = false } );
220
    });
222
    });
221
//]]>
223
//]]>
Lines 261-267 li.hoursentry input { Link Here
261
<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
<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>
262
264
263
<div id="doc3" class="yui-t1">
265
<div id="doc3" class="yui-t1">
264
266
   
265
   <div id="bd">
267
   <div id="bd">
266
    <div id="yui-main">
268
    <div id="yui-main">
267
    <div class="yui-b">
269
    <div class="yui-b">
Lines 278-284 li.hoursentry input { Link Here
278
                    [% END %]
280
                    [% END %]
279
                [% END %]
281
                [% END %]
280
            </select>
282
            </select>
281
283
    
282
    <!-- ******************************** FLAT PANELS ******************************************* -->
284
    <!-- ******************************** FLAT PANELS ******************************************* -->
283
    <!-- *****           Makes all the flat panel to deal with events                     ***** -->
285
    <!-- *****           Makes all the flat panel to deal with events                     ***** -->
284
    <!-- **************************************************************************************** -->
286
    <!-- **************************************************************************************** -->
Lines 297-304 li.hoursentry input { Link Here
297
            </li>
299
            </li>
298
            <li>
300
            <li>
299
                <strong>From Date:</strong>
301
                <strong>From Date:</strong>
300
                <span id="showDaynameOutput"></span>,
302
                <span id="showDaynameOutput"></span>, 
301
303
                
302
                                [% 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
                                [% 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 %]
303
305
304
                <input type="hidden" id="showWeekday" name="weekday" />
306
                <input type="hidden" id="showWeekday" name="weekday" />
Lines 311-317 li.hoursentry input { Link Here
311
                <input type="text" id="datecancelrange" name="dateofrange" size="20" value="[% dateofrange %]" class="datepicker"/>
313
                <input type="text" id="datecancelrange" name="dateofrange" size="20" value="[% dateofrange %]" class="datepicker"/>
312
            </li>
314
            </li>
313
            <li class="radio hourssel">
315
            <li class="radio hourssel">
314
                <input type="radio" name="hoursType" id="showHoursTypeOpen" value="open" /><label for="showHoursTypeOpen">Open (will delete repeating events)</label>
316
                <input type="radio" name="hoursType" id="showHoursTypeOpen" value="open" /><label for="showHoursTypeOpen">Open</label>
317
                <input type="radio" name="hoursType" id="showHoursTypeOpenSet" value="openSet" /><label for="showHoursTypeOpenSet">Open (with set hours)</label>
315
                <input type="radio" name="hoursType" id="showHoursTypeClosed" value="closed" /><label for="showHoursTypeClosed">Closed</label>
318
                <input type="radio" name="hoursType" id="showHoursTypeClosed" value="closed" /><label for="showHoursTypeClosed">Closed</label>
316
            </li>
319
            </li>
317
            <li class="radio hoursentry" style="display:none">
320
            <li class="radio hoursentry" style="display:none">
Lines 321-329 li.hoursentry input { Link Here
321
                <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
                <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])" />
322
            </li>
325
            </li>
323
            <li><label for="showTitle">Title: </label><input type="text" name="title" id="showTitle" size="35" /></li>
326
            <li><label for="showTitle">Title: </label><input type="text" name="title" id="showTitle" size="35" /></li>
324
            <!-- showTitle is necessary for exception radio button to work properly -->
327
            <!-- showTitle is necessary for exception radio button to work properly --> 
325
                <label for="showDescription">Description:</label>
328
                <label for="showDescription">Description:</label>
326
                <textarea rows="2" cols="40" id="showDescription" name="description"></textarea>
329
                <textarea rows="2" cols="40" id="showDescription" name="description"></textarea>    
327
            </li>
330
            </li>
328
            <li class="radio"><input type="radio" name="op" id="showOperationDel" value="delete" /> <label for="showOperationDel" id="showOperationDelLabel">Delete this event</label>
331
            <li class="radio"><input type="radio" name="op" id="showOperationDel" value="delete" /> <label for="showOperationDel" id="showOperationDelLabel">Delete this event</label>
329
                <a href="#" class="helptext">[?]</a>
332
                <a href="#" class="helptext">[?]</a>
Lines 351-357 li.hoursentry input { Link Here
351
    <!-- ***************************** Panel to deal with new events **********************  -->
354
    <!-- ***************************** Panel to deal with new events **********************  -->
352
    <div class="panel" id="newEvent">
355
    <div class="panel" id="newEvent">
353
         <form action="/cgi-bin/koha/tools/calendar.pl" method="post">
356
         <form action="/cgi-bin/koha/tools/calendar.pl" method="post">
354
            <input type="hidden" name="branchCodes" id="branchCodes" value="[% branchcodes %]" />
357
            <input type="hidden" name="branchCodes" id="branchCodes" value="[% branchcodes %]" /> 
355
            <input type="hidden" name="op" value="save" />
358
            <input type="hidden" name="op" value="save" />
356
            <fieldset class="brief">
359
            <fieldset class="brief">
357
            <h3>Add new event</h3>
360
            <h3>Add new event</h3>
Lines 364-370 li.hoursentry input { Link Here
364
            </li>
367
            </li>
365
            <li>
368
            <li>
366
                <strong>From date:</strong>
369
                <strong>From date:</strong>
367
                <span id="newDaynameOutput"></span>,
370
                <span id="newDaynameOutput"></span>, 
368
371
369
                         [% 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
                         [% 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 %]
370
373
Lines 378-384 li.hoursentry input { Link Here
378
                <input type="text" id="dateofrange" name="dateofrange" size="20" value="[% dateofrange %]" class="datepicker" />
381
                <input type="text" id="dateofrange" name="dateofrange" size="20" value="[% dateofrange %]" class="datepicker" />
379
            </li>
382
            </li>
380
            <li class="radio hourssel">
383
            <li class="radio hourssel">
381
                <input type="radio" name="hoursType" id="newHoursTypeOpen" value="open" /><label for="newHoursTypeOpen">Open (will not work for repeating events)</label>
384
                <input type="radio" name="hoursType" id="newHoursTypeOpen" value="open" /><label for="newHoursTypeOpen">Open</label>
385
                <input type="radio" name="hoursType" id="newHoursTypeOpenSet" value="openSet" /><label for="newHoursTypeOpenSet">Open (with set hours)</label>
382
                <input type="radio" name="hoursType" id="newHoursTypeClosed" value="closed" /><label for="newHoursTypeClosed">Closed</label>
386
                <input type="radio" name="hoursType" id="newHoursTypeClosed" value="closed" /><label for="newHoursTypeClosed">Closed</label>
383
            </li>
387
            </li>
384
            <li class="radio hoursentry" style="display:none">
388
            <li class="radio hoursentry" style="display:none">
Lines 493-513 li.hoursentry input { Link Here
493
<script type="text/javascript">
497
<script type="text/javascript">
494
  document.write(weekdays[ [% event.weekday %]]);
498
  document.write(weekdays[ [% event.weekday %]]);
495
</script>
499
</script>
496
  </td>
500
  </td> 
497
  <td>[% event.title %]</td>
501
  <td>[% event.title %]</td> 
498
  <td>[% event.description %]</td>
502
  <td>[% event.description %]</td> 
499
  <td>
503
  <td>
500
    [% IF event.closed %]
504
    [% IF event.closed %]
501
    Closed
505
    Closed
502
    [% ELSIF event.close_hour == 24 %]
506
    [% ELSIF event.close_hour == 24 %]
503
    Open
507
    Open
504
    [% ELSE %]
508
    [% ELSE %]
505
    [% event.open_hour %]:[% event.open_minute > 10 ? event.open_minute : ( '0' _ event.open_minute) %] -
509
    [% event.open_hour %]:[% event.open_minute > 10 ? event.open_minute : ( '0' _ event.open_minute) %] - 
506
    [% event.close_hour %]:[% event.close_minute > 10 ? event.close_minute : ( '0' _ event.close_minute) %]
510
    [% event.close_hour %]:[% event.close_minute > 10 ? event.close_minute : ( '0' _ event.close_minute) %]
507
    [% END %]
511
    [% END %]
508
  </td>
512
  </td>
509
  </tr>
513
  </tr>
510
  [% END %]
514
  [% END %] 
511
</tbody>
515
</tbody>
512
</table>
516
</table>
513
[% END %]
517
[% END %]
Lines 531-550 li.hoursentry input { Link Here
531
  [% FOREACH event IN yearly_events %]
535
  [% FOREACH event IN yearly_events %]
532
  <tr>
536
  <tr>
533
  <td><span title="[% event.month_day_display %]">[% event.month_day_sort %]</span></td>
537
  <td><span title="[% event.month_day_display %]">[% event.month_day_sort %]</span></td>
534
  <td>[% event.title %]</td>
538
  <td>[% event.title %]</td> 
535
  <td>[% event.description %]</td>
539
  <td>[% event.description %]</td> 
536
  <td>
540
  <td>
537
    [% IF event.closed %]
541
    [% IF event.closed %]
538
    Closed
542
    Closed
539
    [% ELSIF event.close_hour == 24 %]
543
    [% ELSIF event.close_hour == 24 %]
540
    Open
544
    Open
541
    [% ELSE %]
545
    [% ELSE %]
542
    [% event.open_hour %]:[% event.open_minute > 10 ? event.open_minute : ( '0' _ event.open_minute) %] -
546
    [% event.open_hour %]:[% event.open_minute > 10 ? event.open_minute : ( '0' _ event.open_minute) %] - 
543
    [% event.close_hour %]:[% event.close_minute > 10 ? event.close_minute : ( '0' _ event.close_minute) %]
547
    [% event.close_hour %]:[% event.close_minute > 10 ? event.close_minute : ( '0' _ event.close_minute) %]
544
    [% END %]
548
    [% END %]
545
  </td>
549
  </td>
546
  </tr>
550
  </tr>
547
  [% END %]
551
  [% END %] 
548
</tbody>
552
</tbody>
549
</table>
553
</table>
550
[% END %]
554
[% END %]
Lines 572-583 li.hoursentry input { Link Here
572
    [% ELSIF event.close_hour == 24 %]
576
    [% ELSIF event.close_hour == 24 %]
573
    Open
577
    Open
574
    [% ELSE %]
578
    [% ELSE %]
575
    [% event.open_hour %]:[% event.open_minute > 10 ? event.open_minute : ( '0' _ event.open_minute) %] -
579
    [% event.open_hour %]:[% event.open_minute > 10 ? event.open_minute : ( '0' _ event.open_minute) %] - 
576
    [% event.close_hour %]:[% event.close_minute > 10 ? event.close_minute : ( '0' _ event.close_minute) %]
580
    [% event.close_hour %]:[% event.close_minute > 10 ? event.close_minute : ( '0' _ event.close_minute) %]
577
    [% END %]
581
    [% END %]
578
  </td>
582
  </td>
579
</tr>
583
</tr>
580
  [% END %]
584
  [% END %] 
581
</tbody>
585
</tbody>
582
</table>
586
</table>
583
[% END %]
587
[% END %]
(-)a/misc/cronjobs/staticfines.pl (-1 / +1 lines)
Lines 176-182 for ( my $i = 0 ; $i < scalar(@$data) ; $i++ ) { Link Here
176
        $calendars{$branchcode} = Koha::Calendar->new( branchcode => $branchcode );
176
        $calendars{$branchcode} = Koha::Calendar->new( branchcode => $branchcode );
177
    }
177
    }
178
    $calendar = $calendars{$branchcode};
178
    $calendar = $calendars{$branchcode};
179
    my $isHoliday = $calendar->is_holiday( DateTime->new(
179
    my $isHoliday = $calendar->is_holiday( DateTime->new( 
180
        year => $tyear,
180
        year => $tyear,
181
        month => $tmonth,
181
        month => $tmonth,
182
        day => $tday
182
        day => $tday
(-)a/t/Calendar.t (-22 / +117 lines)
Lines 4-16 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 => 34;
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
    use Carp;
15
    $SIG{ __DIE__ } = sub { Carp::confess( @_ ) };
14
}
16
}
15
17
16
my $module_context = new Test::MockModule('C4::Context');
18
my $module_context = new Test::MockModule('C4::Context');
Lines 38-75 SKIP: { Link Here
38
skip "DBD::Mock is too old", 33
40
skip "DBD::Mock is too old", 33
39
  unless $DBD::Mock::VERSION >= 1.45;
41
  unless $DBD::Mock::VERSION >= 1.45;
40
42
43
# Apologies for strange indentation, DBD::Mock is picky
41
my $holidays_session = DBD::Mock::Session->new('holidays_session' => (
44
my $holidays_session = DBD::Mock::Session->new('holidays_session' => (
42
    { # weekly holidays
45
    { # weekly holidays
43
        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
    },
44
        results   => [
53
        results   => [
45
                        ['weekday'],
54
                        ['weekday', 'open_hour', 'open_minute', 'close_hour', 'close_minute', 'closed'],
46
                        [0],    # sundays
55
                        [0, 0, 0, 0, 0, 1],    # sundays
47
                        [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
48
                     ]
59
                     ]
49
    },
60
    },
50
    { # day and month repeatable holidays
61
    { # day and month repeatable holidays
51
        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
    },
52
        results   => [
69
        results   => [
53
                        [ 'month', 'day' ],
70
                        [ 'month', 'day', 'open_hour', 'open_minute', 'close_hour', 'close_minute', 'closed' ],
54
                        [ 1, 1 ],   # new year's day
71
                        [ 1, 1, 0, 0, 0, 0, 1],   # new year's day
55
                        [12,25]     # christmas
72
                        [ 6,26,10, 0,15, 0, 0],    # wednesdays
73
                        [12,25, 0, 0, 0, 0, 1]     # christmas
56
                     ]
74
                     ]
57
    },
75
    },
58
    { # exception holidays
76
    { # exception holidays
59
        statement => "SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1",
77
        statement => q{
60
        results   => [
78
        SELECT
61
                        [ 'day', 'month', 'year' ],
79
            event_date, open_hour, open_minute, close_hour, close_minute,
62
                        [ 11, 11, 2012 ] # sunday exception
80
            (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed
63
                     ]
81
        FROM calendar_events
82
        WHERE branchcode = ?
64
    },
83
    },
65
    { # single holidays
66
        statement => "SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0",
67
        results   => [
84
        results   => [
68
                        [ 'day', 'month', 'year' ],
85
                        [ 'event_date', 'open_hour', 'open_minute', 'close_hour', 'close_minute', 'closed' ],
69
                        [ 1, 6, 2011 ],  # single holiday
86
                        [ '2012-11-11', 0, 0,24, 0, 0 ], # sunday exception
70
                        [ 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 ]
71
                     ]
90
                     ]
72
    }
91
    },
73
));
92
));
74
93
75
# Initialize the global $dbh variable
94
# Initialize the global $dbh variable
Lines 189-194 my $day_after_christmas = DateTime->new( Link Here
189
        minute    => 53,
208
        minute    => 53,
190
    );
209
    );
191
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
192
    my $later_dt = DateTime->new(    # Monday
227
    my $later_dt = DateTime->new(    # Monday
193
        year      => 2012,
228
        year      => 2012,
194
        month     => 9,
229
        month     => 9,
Lines 232-244 my $day_after_christmas = DateTime->new( Link Here
232
    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',
233
        'Negative call to addDate (Datedue)' );
268
        'Negative call to addDate (Datedue)' );
234
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
235
    ## 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.
236
    ## This tests are here as an API test.
287
    ## This tests are here as an API test.
237
    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'),
238
                '==', 40, 'days_between calculates correctly (Days)' );
289
                '==', 40, 'days_between calculates correctly (Datedue)' );
239
290
240
    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'),
241
                '==', 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)' );
242
305
243
306
244
}
307
}
Lines 274-284 my $day_after_christmas = DateTime->new( Link Here
274
    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',
275
            'Negative call to addDate (Calendar)' );
338
            'Negative call to addDate (Calendar)' );
276
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
277
    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'),
278
                '==', 40, 'days_between calculates correctly (Calendar)' );
357
                '==', 40, 'days_between calculates correctly (Calendar)' );
279
358
280
    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'),
281
                '==', 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)' );
282
}
367
}
283
368
284
369
Lines 311-316 my $day_after_christmas = DateTime->new( Link Here
311
    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',
312
        'Negative call to addDate (Days)' );
397
        'Negative call to addDate (Days)' );
313
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
314
    ## 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.
315
    ## This tests are here as an API test.
404
    ## This tests are here as an API test.
316
    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 319-324 my $day_after_christmas = DateTime->new( Link Here
319
    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'),
320
                '==', 40, 'Test parameter order not relevant (Days)' );
409
                '==', 40, 'Test parameter order not relevant (Days)' );
321
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
322
}
417
}
323
418
324
} # End SKIP block
419
} # End SKIP block
(-)a/t/db_dependent/Calendar.t (-48 / +40 lines)
Lines 1-86 Link Here
1
use Modern::Perl;
1
use Modern::Perl;
2
2
3
use Test::More tests => 14;
3
use Test::More tests => 18;
4
4
5
use C4::Calendar;
5
use C4::Calendar;
6
use C4::Context;
7
6
8
my $dbh = C4::Context->dbh;
7
my $new_holiday = { open_hour    => 0,
9
10
# Start transaction
11
$dbh->{AutoCommit} = 0;
12
$dbh->{RaiseError} = 1;
13
14
my %new_holiday = ( open_hour    => 0,
15
                    open_minute  => 0,
8
                    open_minute  => 0,
16
                    close_hour   => 0,
9
                    close_hour   => 0,
17
                    close_minute => 0,
10
                    close_minute => 0,
18
                    title        => 'example week_day_holiday',
11
                    title        => 'example week_day_holiday',
19
                    description  => 'This is an example week_day_holiday used for testing' );
12
                    description  => 'This is an example week_day_holiday used for testing' };
20
13
21
# Weekly events
14
# Weekly events
22
ModRepeatingEvent( 'UPL', { weekday => 1, %new_holiday } );
15
ModRepeatingEvent( 'MPL', 1, undef, undef, $new_holiday );
23
16
24
my $weekly_events = GetWeeklyEvents( 'UPL' );
17
my $weekly_events = GetWeeklyEvents( 'MPL' );
25
is( $weekly_events->[0]->{'title'}, $new_holiday{'title'}, 'weekly title' );
18
is( $weekly_events->[0]->{'title'}, $new_holiday->{'title'}, 'weekly title' );
26
is( $weekly_events->[0]->{'description'}, $new_holiday{'description'}, 'weekly description' );
19
is( $weekly_events->[0]->{'description'}, $new_holiday->{'description'}, 'weekly description' );
20
is( $weekly_events->[0]->{'open_hour'}, 0, 'weekly open_hour' );
27
21
28
$new_holiday{close_hour} = 24;
22
$new_holiday->{open_hour} = 7;
29
23
30
ModRepeatingEvent( 'UPL', { weekday => 1, %new_holiday } );
24
ModRepeatingEvent( 'MPL', 1, undef, undef, $new_holiday );
31
$weekly_events = GetWeeklyEvents( 'UPL' );
25
$weekly_events = GetWeeklyEvents( 'MPL' );
32
is( scalar @$weekly_events, 0, 'weekly modification, not insertion' );
26
is( scalar @$weekly_events, 1, 'weekly modification, not insertion' );
27
is( $weekly_events->[0]->{'open_hour'}, 7, 'weekly open_hour modified' );
33
28
34
$new_holiday{close_hour} = 0;
35
ModRepeatingEvent( 'UPL', { weekday => 1, %new_holiday } );
36
29
37
# Yearly events
30
# Yearly events
38
31
39
ModRepeatingEvent( 'UPL', { month => 6, day => 26, %new_holiday } );
32
$new_holiday->{open_hour} = 0;
33
ModRepeatingEvent( 'MPL', undef, 6, 26, $new_holiday );
40
34
41
my $yearly_events = GetYearlyEvents( 'UPL' );
35
my $yearly_events = GetYearlyEvents( 'MPL' );
42
is( $yearly_events->[0]->{'title'}, $new_holiday{'title'}, 'yearly title' );
36
is( $yearly_events->[0]->{'title'}, $new_holiday->{'title'}, 'yearly title' );
43
is( $yearly_events->[0]->{'description'}, $new_holiday{'description'}, 'yearly description' );
37
is( $yearly_events->[0]->{'description'}, $new_holiday->{'description'}, 'yearly description' );
38
is( $yearly_events->[0]->{'open_hour'}, 0, 'yearly open_hour' );
44
39
45
$new_holiday{close_hour} = 24;
40
$new_holiday->{open_hour} = 8;
46
41
47
ModRepeatingEvent( 'UPL', { month => 6, day => 26, %new_holiday } );
42
ModRepeatingEvent( 'MPL', undef, 6, 26, $new_holiday );
48
$yearly_events = GetYearlyEvents( 'UPL' );
43
$yearly_events = GetYearlyEvents( 'MPL' );
49
is( scalar @$yearly_events, 0, 'yearly modification, not insertion' );
44
is( scalar @$yearly_events, 1, 'yearly modification, not insertion' );
50
45
is( $yearly_events->[0]->{'open_hour'}, 8, 'yearly open_hour' );
51
$new_holiday{close_hour} = 0;
52
ModRepeatingEvent( 'UPL', { month => 6, day => 26, %new_holiday } );
53
46
54
# Single events
47
# Single events
55
48
56
ModSingleEvent( 'UPL', { date => '2013-03-17', %new_holiday } );
49
$new_holiday->{open_hour} = 0;
50
ModSingleEvent( 'MPL', '2013-03-17', $new_holiday );
57
51
58
my $single_events = GetSingleEvents( 'UPL' );
52
my $single_events = GetSingleEvents( 'MPL' );
59
is( $single_events->[0]->{'title'}, $new_holiday{'title'}, 'single title' );
53
is( $single_events->[0]->{'title'}, $new_holiday->{'title'}, 'single title' );
60
is( $single_events->[0]->{'description'}, $new_holiday{'description'}, 'single description' );
54
is( $single_events->[0]->{'description'}, $new_holiday->{'description'}, 'single description' );
61
is( $single_events->[0]->{'closed'}, 1, 'single closed' );
55
is( $single_events->[0]->{'open_hour'}, 0, 'single open_hour' );
62
56
63
$new_holiday{close_hour} = 24;
57
$new_holiday->{open_hour} = 11;
64
58
65
ModSingleEvent( 'UPL', { date => '2013-03-17', %new_holiday } );
59
ModSingleEvent( 'MPL', '2013-03-17', $new_holiday );
66
$single_events = GetSingleEvents( 'UPL' );
60
$single_events = GetSingleEvents( 'MPL' );
67
is( scalar @$single_events, 1, 'single modification, not insertion' );
61
is( scalar @$single_events, 1, 'single modification, not insertion' );
68
is( $single_events->[0]->{'closed'}, 0, 'single closed' );
62
is( $single_events->[0]->{'open_hour'}, 11, 'single open_hour' );
69
63
70
64
71
# delete
65
# delete
72
66
73
DelRepeatingEvent( 'UPL', { weekday => 1 } );
67
DelRepeatingEvent( 'MPL', 1, undef, undef );
74
$weekly_events = GetWeeklyEvents( 'UPL' );
68
$weekly_events = GetWeeklyEvents( 'MPL' );
75
is( scalar @$weekly_events, 0, 'weekly deleted' );
69
is( scalar @$weekly_events, 0, 'weekly deleted' );
76
70
77
DelRepeatingEvent( 'UPL', { month => 6, day => 26 } );
71
DelRepeatingEvent( 'MPL', undef, 6, 26 );
78
$yearly_events = GetYearlyEvents( 'UPL' );
72
$yearly_events = GetYearlyEvents( 'MPL' );
79
is( scalar @$yearly_events, 0, 'yearly deleted' );
73
is( scalar @$yearly_events, 0, 'yearly deleted' );
80
74
81
DelSingleEvent( 'UPL', { date => '2013-03-17' } );
75
DelSingleEvent( 'MPL', '2013-03-17' );
82
76
83
$single_events = GetSingleEvents( 'UPL' );
77
$single_events = GetSingleEvents( 'MPL' );
84
is( scalar @$single_events, 0, 'single deleted' );
78
is( scalar @$single_events, 0, 'single deleted' );
85
86
$dbh->rollback;
(-)a/tools/calendar.pl (-60 / +46 lines)
Lines 2-23 Link Here
2
2
3
# This file is part of Koha.
3
# This file is part of Koha.
4
#
4
#
5
# Koha is free software; you can redistribute it and/or modify it
5
# Koha is free software; you can redistribute it and/or modify it under the
6
# under the terms of the GNU General Public License as published by
6
# terms of the GNU General Public License as published by the Free Software
7
# the Free Software Foundation; either version 3 of the License, or
7
# Foundation; either version 2 of the License, or (at your option) any later
8
# (at your option) any later version.
8
# version.
9
#
9
#
10
# Koha is distributed in the hope that it will be useful, but
10
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
# GNU General Public License for more details.
14
#
13
#
15
# You should have received a copy of the GNU General Public License
14
# You should have received a copy of the GNU General Public License along with
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
15
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
16
# Suite 330, Boston, MA  02111-1307 USA
17
17
18
#####Sets holiday periods for each branch. Datedues will be extended if branch is closed -TG
18
#####Sets holiday periods for each branch. Datedues will be extended if branch is closed -TG
19
19
20
use Modern::Perl;
20
use Modern::Perl '2009';
21
21
22
use CGI;
22
use CGI;
23
23
Lines 55-67 unless($keydate = $calendarinput->output('iso')) { Link Here
55
}
55
}
56
$keydate =~ s/-/\//g;
56
$keydate =~ s/-/\//g;
57
57
58
my $branch= $input->param('branchName') || $input->param('branch') || C4::Context->userenv->{'branch'};
58
my $branch= $input->param('branch') || C4::Context->userenv->{'branch'};
59
# Set all the branches.
59
# Set all the branches.
60
my $onlymine=(C4::Context->preference('IndependentBranches') &&
60
my $onlymine=(C4::Context->preference('IndependentBranches') &&
61
              C4::Context->userenv &&
61
              C4::Context->userenv &&
62
              C4::Context->userenv->{flags} % 2 !=1  &&
62
              C4::Context->userenv->{flags} % 2 !=1  &&
63
              C4::Context->userenv->{branch}?1:0);
63
              C4::Context->userenv->{branch}?1:0);
64
if ( $onlymine ) {
64
if ( $onlymine ) { 
65
    $branch = C4::Context->userenv->{'branch'};
65
    $branch = C4::Context->userenv->{'branch'};
66
}
66
}
67
my $branchname = GetBranchName($branch);
67
my $branchname = GetBranchName($branch);
Lines 110-116 if ( $input->param( 'allBranches' ) || !$input->param( 'branchName' ) ) { Link Here
110
if ( $op eq 'save' ) {
110
if ( $op eq 'save' ) {
111
    my $date = $input->param( 'year' ) . '-' . $input->param( 'month' ) . '-' . $input->param( 'day' );
111
    my $date = $input->param( 'year' ) . '-' . $input->param( 'month' ) . '-' . $input->param( 'day' );
112
112
113
    local our ( $open_hour, $open_minute, $close_hour, $close_minute );
113
    my ( $open_hour, $open_minute, $close_hour, $close_minute );
114
114
115
    if ( $input->param( 'hoursType' ) eq 'open' ) {
115
    if ( $input->param( 'hoursType' ) eq 'open' ) {
116
        ( $open_hour, $open_minute ) = ( 0, 0 );
116
        ( $open_hour, $open_minute ) = ( 0, 0 );
Lines 124-133 if ( $op eq 'save' ) { Link Here
124
    }
124
    }
125
125
126
    foreach my $branchcode ( @branches ) {
126
    foreach my $branchcode ( @branches ) {
127
        my %event_types = (
127
        given ( $input->param( 'eventType' ) ) {
128
            'single' => sub {
128
            when ( 'single' ) {
129
                ModSingleEvent( $branchcode, {
129
                ModSingleEvent( $branchcode, $date, {
130
                    date => $date,
131
                    title => $input->param( 'title' ),
130
                    title => $input->param( 'title' ),
132
                    description => $input->param( 'description' ),
131
                    description => $input->param( 'description' ),
133
                    open_hour => $open_hour,
132
                    open_hour => $open_hour,
Lines 135-145 if ( $op eq 'save' ) { Link Here
135
                    close_hour => $close_hour,
134
                    close_hour => $close_hour,
136
                    close_minute => $close_minute
135
                    close_minute => $close_minute
137
                } );
136
                } );
138
            },
137
            }
139
138
140
            'weekly' => sub {
139
            when ( 'weekly' ) {
141
                ModRepeatingEvent( $branchcode, {
140
                ModRepeatingEvent( $branchcode, $input->param( 'weekday' ), undef, undef, {
142
                    weekday => $input->param( 'weekday' ),
143
                    title => $input->param( 'title' ),
141
                    title => $input->param( 'title' ),
144
                    description => $input->param( 'description' ),
142
                    description => $input->param( 'description' ),
145
                    open_hour => $open_hour,
143
                    open_hour => $open_hour,
Lines 147-158 if ( $op eq 'save' ) { Link Here
147
                    close_hour => $close_hour,
145
                    close_hour => $close_hour,
148
                    close_minute => $close_minute
146
                    close_minute => $close_minute
149
                } );
147
                } );
150
            },
148
            }
151
149
152
            'yearly' => sub {
150
            when ( 'yearly' ) {
153
                ModRepeatingEvent( $branchcode, {
151
                ModRepeatingEvent( $branchcode, undef, $input->param( 'month' ), $input->param( 'day' ), {
154
                    month => $input->param( 'month' ),
155
                    day => $input->param( 'day' ),
156
                    title => $input->param( 'title' ),
152
                    title => $input->param( 'title' ),
157
                    description => $input->param( 'description' ),
153
                    description => $input->param( 'description' ),
158
                    open_hour => $open_hour,
154
                    open_hour => $open_hour,
Lines 160-171 if ( $op eq 'save' ) { Link Here
160
                    close_hour => $close_hour,
156
                    close_hour => $close_hour,
161
                    close_minute => $close_minute
157
                    close_minute => $close_minute
162
                } );
158
                } );
163
            },
159
            }
164
160
165
            'singlerange' => sub {
161
            when ( 'singlerange' ) {
166
                foreach my $dt ( @ranged_dates ) {
162
                foreach my $dt ( @ranged_dates ) {
167
                    ModSingleEvent( $branchcode, {
163
                    ModSingleEvent( $branchcode, $dt->ymd, {
168
                        date => $dt->ymd,
169
                        title => $input->param( 'title' ),
164
                        title => $input->param( 'title' ),
170
                        description => $input->param( 'description' ),
165
                        description => $input->param( 'description' ),
171
                        open_hour => $open_hour,
166
                        open_hour => $open_hour,
Lines 174-186 if ( $op eq 'save' ) { Link Here
174
                        close_minute => $close_minute
169
                        close_minute => $close_minute
175
                    } );
170
                    } );
176
                }
171
                }
177
            },
172
            }
178
173
179
            'yearlyrange' => sub {
174
            when ( 'yearlyrange' ) {
180
                foreach my $dt ( @ranged_dates ) {
175
                foreach my $dt ( @ranged_dates ) {
181
                    ModRepeatingEvent( $branchcode, {
176
                    ModRepeatingEvent( $branchcode, undef, $dt->month, $dt->day, {
182
                        month => $dt->month,
183
                        day => $dt->day,
184
                        title => $input->param( 'title' ),
177
                        title => $input->param( 'title' ),
185
                        description => $input->param( 'description' ),
178
                        description => $input->param( 'description' ),
186
                        open_hour => $open_hour,
179
                        open_hour => $open_hour,
Lines 189-231 if ( $op eq 'save' ) { Link Here
189
                        close_minute => $close_minute
182
                        close_minute => $close_minute
190
                    } );
183
                    } );
191
                }
184
                }
192
            },
185
            }
193
        );
186
        }
194
195
        # Choose from the above options
196
        $event_types{ $input->param( 'eventType' ) }->();
197
    }
187
    }
198
} elsif ( $op eq 'delete' ) {
188
} elsif ( $op eq 'delete' ) {
199
    my $date = $input->param( 'year' ) . '-' . $input->param( 'month' ) . '-' . $input->param( 'day' );
189
    my $date = $input->param( 'year' ) . '-' . $input->param( 'month' ) . '-' . $input->param( 'day' );
200
190
201
    foreach my $branchcode ( @branches ) {
191
    foreach my $branchcode ( @branches ) {
202
        my %event_types = (
192
        given ( $input->param( 'eventType' ) ) {
203
            'single' => sub {
193
            when ( 'single' ) {
204
                DelSingleEvent( $branchcode, { date => $date } );
194
                DelSingleEvent( $branchcode, $date );
205
            },
195
            }
206
196
207
            'weekly' => sub {
197
            when ( 'weekly' ) {
208
                DelRepeatingEvent( $branchcode, { weekday => $input->param( 'weekday' ) } );
198
                DelRepeatingEvent( $branchcode, $input->param( 'weekday' ), undef, undef );
209
            },
199
            }
210
200
211
            'yearly' => sub {
201
            when ( 'yearly' ) {
212
                DelRepeatingEvent( $branchcode, { month => $input->param( 'month' ), day => $input->param( 'day' ) } );
202
                DelRepeatingEvent( $branchcode, undef, $input->param( 'month' ), $input->param( 'day' ) );
213
            },
203
            }
214
        );
204
        }
215
216
        # Choose from the above options
217
        $event_types{ $input->param( 'eventType' ) }->();
218
    }
205
    }
219
} elsif ( $op eq 'deleterange' ) {
206
} elsif ( $op eq 'deleterange' ) {
220
    foreach my $branchcode ( @branches ) {
207
    foreach my $branchcode ( @branches ) {
221
        foreach my $dt ( @ranged_dates ) {
208
        foreach my $dt ( @ranged_dates ) {
222
            DelSingleEvent( $branchcode, { date => $dt->ymd } );
209
            DelSingleEvent( $branchcode, $dt->ymd );
223
        }
210
        }
224
    }
211
    }
225
} elsif ( $op eq 'deleterangerepeat' ) {
212
} elsif ( $op eq 'deleterangerepeat' ) {
226
    foreach my $branchcode ( @branches ) {
213
    foreach my $branchcode ( @branches ) {
227
        foreach my $dt ( @ranged_dates ) {
214
        foreach my $dt ( @ranged_dates ) {
228
            DelRepeatingEvent( $branchcode, { month => $dt->month, day => $dt->day } );
215
            DelRepeatingEvent( $branchcode, undef, $dt->month, $dt->day );
229
        }
216
        }
230
    }
217
    }
231
} elsif ( $op eq 'copyall' ) {
218
} elsif ( $op eq 'copyall' ) {
232
- 

Return to bug 8133