line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ************************************************************************* |
2
|
|
|
|
|
|
|
# Copyright (c) 2014-2017, SUSE LLC |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# All rights reserved. |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
# Redistribution and use in source and binary forms, with or without |
7
|
|
|
|
|
|
|
# modification, are permitted provided that the following conditions are met: |
8
|
|
|
|
|
|
|
# |
9
|
|
|
|
|
|
|
# 1. Redistributions of source code must retain the above copyright notice, |
10
|
|
|
|
|
|
|
# this list of conditions and the following disclaimer. |
11
|
|
|
|
|
|
|
# |
12
|
|
|
|
|
|
|
# 2. Redistributions in binary form must reproduce the above copyright |
13
|
|
|
|
|
|
|
# notice, this list of conditions and the following disclaimer in the |
14
|
|
|
|
|
|
|
# documentation and/or other materials provided with the distribution. |
15
|
|
|
|
|
|
|
# |
16
|
|
|
|
|
|
|
# 3. Neither the name of SUSE LLC nor the names of its contributors may be |
17
|
|
|
|
|
|
|
# used to endorse or promote products derived from this software without |
18
|
|
|
|
|
|
|
# specific prior written permission. |
19
|
|
|
|
|
|
|
# |
20
|
|
|
|
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
21
|
|
|
|
|
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22
|
|
|
|
|
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23
|
|
|
|
|
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
24
|
|
|
|
|
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25
|
|
|
|
|
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26
|
|
|
|
|
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27
|
|
|
|
|
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28
|
|
|
|
|
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29
|
|
|
|
|
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30
|
|
|
|
|
|
|
# POSSIBILITY OF SUCH DAMAGE. |
31
|
|
|
|
|
|
|
# ************************************************************************* |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
use 5.012; |
35
|
41
|
|
|
41
|
|
3704
|
use strict; |
|
41
|
|
|
|
|
132
|
|
36
|
41
|
|
|
41
|
|
225
|
use warnings; |
|
41
|
|
|
|
|
88
|
|
|
41
|
|
|
|
|
699
|
|
37
|
41
|
|
|
41
|
|
184
|
use App::CELL qw( $CELL $log $meta $site ); |
|
41
|
|
|
|
|
78
|
|
|
41
|
|
|
|
|
1053
|
|
38
|
41
|
|
|
41
|
|
224
|
use App::Dochazka::REST::Model::Shared qw( cud decode_schedule_json load load_multiple select_single ); |
|
41
|
|
|
|
|
104
|
|
|
41
|
|
|
|
|
4087
|
|
39
|
41
|
|
|
41
|
|
1559
|
use Data::Dumper; |
|
41
|
|
|
|
|
96
|
|
|
41
|
|
|
|
|
2575
|
|
40
|
41
|
|
|
41
|
|
265
|
use JSON; |
|
41
|
|
|
|
|
88
|
|
|
41
|
|
|
|
|
1507
|
|
41
|
41
|
|
|
41
|
|
259
|
use Params::Validate qw( :all ); |
|
41
|
|
|
|
|
89
|
|
|
41
|
|
|
|
|
253
|
|
42
|
41
|
|
|
41
|
|
4313
|
use Try::Tiny; |
|
41
|
|
|
|
|
158
|
|
|
41
|
|
|
|
|
5366
|
|
43
|
41
|
|
|
41
|
|
281
|
|
|
41
|
|
|
|
|
74
|
|
|
41
|
|
|
|
|
1789
|
|
44
|
|
|
|
|
|
|
# we get 'spawn', 'reset', and accessors from parent |
45
|
|
|
|
|
|
|
use parent 'App::Dochazka::Common::Model::Schedule'; |
46
|
41
|
|
|
41
|
|
1919
|
|
|
41
|
|
|
|
|
1997
|
|
|
41
|
|
|
|
|
4744
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head1 NAME |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
App::Dochazka::REST::Model::Schedule - schedule functions |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head1 SYNOPSIS |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
use App::Dochazka::REST::Model::Schedule; |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
... |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=head1 DESCRIPTION |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
A description of the schedule data model follows. |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=head2 Schedules in the database |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=head3 Table |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
Schedules are stored the C<schedules> table. For any given schedule, there is |
77
|
|
|
|
|
|
|
always only one record in the table -- i.e., individual schedules can be used |
78
|
|
|
|
|
|
|
for multiple employees. (For example, an organization might have hundreds of |
79
|
|
|
|
|
|
|
employees on a single, unified schedule.) |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS schedules ( |
82
|
|
|
|
|
|
|
sid serial PRIMARY KEY, |
83
|
|
|
|
|
|
|
schedule text UNIQUE NOT NULL, |
84
|
|
|
|
|
|
|
disabled boolean, |
85
|
|
|
|
|
|
|
remark text |
86
|
|
|
|
|
|
|
); |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
The value of the 'schedule' field is a JSON array which looks something like this: |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
[ |
91
|
|
|
|
|
|
|
{ low_dow:"MON", low_time:"08:00", high_dow:"MON", high_time:"12:00" }, |
92
|
|
|
|
|
|
|
{ low_dow:"MON", low_time:"12:30", high_dow:"MON", high_time:"16:30" }, |
93
|
|
|
|
|
|
|
{ low_dow:"TUE", low_time:"08:00", high_dow:"TUE", high_time:"12:00" }, |
94
|
|
|
|
|
|
|
{ low_dow:"TUE", low_time:"12:30", high_dow:"TUE", high_time:"16:30" }, |
95
|
|
|
|
|
|
|
... |
96
|
|
|
|
|
|
|
] |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
Or, to give an example of a more convoluted schedule: |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
[ |
101
|
|
|
|
|
|
|
{ low_dow:"WED", low_time:"22:15", high_dow:"THU", high_time:"03:25" }, |
102
|
|
|
|
|
|
|
{ low_dow:"THU", low_time:"05:25", high_dow:"THU", high_time:"09:55" }, |
103
|
|
|
|
|
|
|
{ low_dow:"SAT", low_time:"19:05", high_dow:"SUN", high_time:"24:00" } |
104
|
|
|
|
|
|
|
] |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
The intervals in the JSON string must be sorted and the whitespace, etc. |
107
|
|
|
|
|
|
|
must be consistent in order for the UNIQUE constraint in the 'schedule' |
108
|
|
|
|
|
|
|
table to work properly. However, these precautions will no longer be |
109
|
|
|
|
|
|
|
necessary after PostgreSQL 9.4 comes out and the field type is changed to |
110
|
|
|
|
|
|
|
'jsonb'. |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
The 'disabled' field is intended go be used to control which schedules get |
113
|
|
|
|
|
|
|
offered in, e.g., front-end dialogs when administrators choose which schedule |
114
|
|
|
|
|
|
|
to assign to a new employee, and the like. For example, there may be schedules |
115
|
|
|
|
|
|
|
in the database that were used in the past, but it is no longer desirable to |
116
|
|
|
|
|
|
|
offer these schedules in the front-end dialog, so the administrator can "remove" |
117
|
|
|
|
|
|
|
them from the dialog by setting this field to 'true'. |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=head3 Process for creating new schedules |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
It is important to understand how the JSON string introduced in the previous |
123
|
|
|
|
|
|
|
section is assembled -- or, more generally, how a schedule is created. Essentially, |
124
|
|
|
|
|
|
|
the schedule is first created in a C<schedintvls> table, with a record for each |
125
|
|
|
|
|
|
|
time interval in the schedule. This table has triggers and a C<gist> index that |
126
|
|
|
|
|
|
|
enforce schedule data integrity so that only a valid schedule can be inserted. |
127
|
|
|
|
|
|
|
Once the schedule has been successfully built up in C<schedintvls>, it is |
128
|
|
|
|
|
|
|
"translated" (using a stored procedure) into a single JSON string, which is |
129
|
|
|
|
|
|
|
stored in the C<schedules> table. This process is described in more detail below: |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
First, if the schedule already exists in the C<schedules> table, nothing |
132
|
|
|
|
|
|
|
more need be done -- we can skip to L<Schedhistory> |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
If the schedule we need is not yet in the database, we will have to create it. |
135
|
|
|
|
|
|
|
This is a three-step process: (1) build up the schedule in the C<schedintvls> |
136
|
|
|
|
|
|
|
table (sometimes referred to as the "scratch schedule" table because it is used |
137
|
|
|
|
|
|
|
to store an intermediate product with only a short lifespan); (2) translate the |
138
|
|
|
|
|
|
|
schedule to form the schedule's JSON representation; (3) insert the JSON string |
139
|
|
|
|
|
|
|
into the C<schedules> table. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
The C<schedintvls>, or "scratch schedule", table: |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
CREATE SEQUENCE scratch_sid_seq; |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS schedintvls ( |
146
|
|
|
|
|
|
|
int_id serial PRIMARY KEY, |
147
|
|
|
|
|
|
|
ssid integer NOT NULL, |
148
|
|
|
|
|
|
|
intvl tsrange NOT NULL, |
149
|
|
|
|
|
|
|
EXCLUDE USING gist (ssid WITH =, intvl WITH &&) |
150
|
|
|
|
|
|
|
)/, |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
As stated above, before the C<schedule> table is touched, a "scratch schedule" |
153
|
|
|
|
|
|
|
must first be created in the C<schedintvls> table. Although this operation |
154
|
|
|
|
|
|
|
changes the database, it should be seen as a "dry run". The C<gist> index and |
155
|
|
|
|
|
|
|
a trigger assure that: |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=over |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=item * no overlapping entries are entered |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=item * all the entries fall within a single 168-hour period |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=item * all the times are evenly divisible by five minutes |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=back |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# |
168
|
|
|
|
|
|
|
# FIXME: expand the trigger to check for "closed-open" C<< [ ..., ... ) >> tsrange |
169
|
|
|
|
|
|
|
# |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
If the schedule is successfully inserted into C<schedintvls>, the next step is |
172
|
|
|
|
|
|
|
to "translate", or convert, the individual intervals (expressed as tsrange |
173
|
|
|
|
|
|
|
values) into the four-key hashes described in L<Schedules in the database>, |
174
|
|
|
|
|
|
|
assemble the JSON string, and insert a new row in C<schedules>. |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
To facilitate this conversion, a stored procedure C<translate_schedintvl> was |
177
|
|
|
|
|
|
|
developed. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
Successful insertion into C<schedules> will generate a Schedule ID (SID) for |
180
|
|
|
|
|
|
|
the schedule, enabling it to be used to make Schedhistory objects. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
At this point, the scratch schedule is deleted from the C<schedintvls> table. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
=head2 Schedules in the Perl API |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=head3 L<Schedintvls> class |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=over |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=item * constructor (L<spawn>) |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=item * L<reset> method (recycles an existing object) |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=item * basic accessor (L<ssid>) |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=item * L<intvls> accessor (arrayref containing all tsrange intervals in schedule) |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=item * L<schedule> accessor (arrayref containing "translated" intervals) |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=item * L<load> method (load the object from the database and translate the tsrange intervals) |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=item * L<insert> method (insert all the tsrange elements in one go) |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=item * L<delete> method (delete all the tsrange elements when we're done with them) |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=item * L<json> method (generate JSON string from the translated intervals) |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=back |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
For basic workflow, see C<t/model/schedule.t>. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=head3 C<Schedule> class |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=over |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=item * constructor (L<spawn>) |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=item * L<reset> method (recycles an existing object) |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=item * basic accessors (L<sid>, L<schedule>, L<remark>) |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=item * L<insert> method (inserts the schedule if it isn't in the database already) |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=item * L<delete> method |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=item * L<load> method (not implemented yet) |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
#=item * L<get_schedule_json> function (get JSON string associated with a given SID) |
232
|
|
|
|
|
|
|
# |
233
|
|
|
|
|
|
|
=back |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
For basic workflow, see C<t/model/schedule.t>. |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=head1 EXPORTS |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
This module provides the following exports: |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=over |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
#=item * C<get_schedule_json> |
247
|
|
|
|
|
|
|
# |
248
|
|
|
|
|
|
|
=item * C<get_all_schedules> |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=item * C<sid_exists> (boolean) |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=back |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=cut |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
use Exporter qw( import ); |
257
|
41
|
|
|
41
|
|
77318
|
our @EXPORT_OK = qw( |
|
41
|
|
|
|
|
100
|
|
|
41
|
|
|
|
|
33129
|
|
258
|
|
|
|
|
|
|
get_all_schedules |
259
|
|
|
|
|
|
|
sid_exists |
260
|
|
|
|
|
|
|
); |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=head1 METHODS |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=head2 insert |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
Instance method. Attempts to INSERT a record into the 'schedules' table. |
270
|
|
|
|
|
|
|
Field values are taken from the object. Returns a status object. |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
If the "schedule" field of the schedule to be inserted matches an existing |
273
|
|
|
|
|
|
|
schedule, no new record is inserted. Instead, the existing schedule record |
274
|
|
|
|
|
|
|
is returned. In such a case, the "scode", "remark", and "disabled" fields |
275
|
|
|
|
|
|
|
are ignored - except when they are NULL in the existing record. |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=cut |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
my $self = shift; |
280
|
|
|
|
|
|
|
my ( $context ) = validate_pos( @_, { type => HASHREF } ); |
281
|
0
|
|
|
0
|
1
|
|
|
282
|
0
|
|
|
|
|
|
# if the exact same schedule is already in the database, we |
283
|
|
|
|
|
|
|
# don't insert it again |
284
|
|
|
|
|
|
|
my $status = select_single( |
285
|
|
|
|
|
|
|
conn => $context->{'dbix_conn'}, |
286
|
|
|
|
|
|
|
sql => $site->SQL_SCHEDULES_SELECT_BY_SCHEDULE, |
287
|
|
|
|
|
|
|
keys => [ $self->{schedule} ], |
288
|
|
|
|
|
|
|
); |
289
|
0
|
|
|
|
|
|
$log->info( "select_single returned: " . Dumper $status ); |
290
|
|
|
|
|
|
|
if ( $status->level eq 'OK' ) { |
291
|
0
|
|
|
|
|
|
my $found_sched = App::Dochazka::REST::Model::Schedule->spawn( |
292
|
0
|
0
|
|
|
|
|
sid => $status->payload->[0], |
|
|
0
|
|
|
|
|
|
293
|
0
|
|
|
|
|
|
scode => $status->payload->[1], |
294
|
|
|
|
|
|
|
schedule => $status->payload->[2], |
295
|
|
|
|
|
|
|
remark => $status->payload->[3], |
296
|
|
|
|
|
|
|
disabled => $status->payload->[4], |
297
|
|
|
|
|
|
|
); |
298
|
|
|
|
|
|
|
$self->{'sid'} = $found_sched->sid; |
299
|
|
|
|
|
|
|
{ |
300
|
0
|
|
|
|
|
|
# |
301
|
|
|
|
|
|
|
# the exact schedule exists, but if any of { scode, remark, disabled } |
302
|
|
|
|
|
|
|
# are NULL and we have a value, update the record to reflect the value |
303
|
|
|
|
|
|
|
# (in other words, do not prefer NULLs over real values) |
304
|
|
|
|
|
|
|
# |
305
|
|
|
|
|
|
|
my $do_update = 0; |
306
|
|
|
|
|
|
|
if ( ! defined( $found_sched->scode ) and defined( $self->scode ) ) { |
307
|
0
|
|
|
|
|
|
$found_sched->scode( $self->scode ); |
|
0
|
|
|
|
|
|
|
308
|
0
|
0
|
0
|
|
|
|
$do_update = 1; |
309
|
0
|
|
|
|
|
|
} |
310
|
0
|
|
|
|
|
|
if ( ! defined( $found_sched->remark ) and defined( $self->remark ) ) { |
311
|
|
|
|
|
|
|
$found_sched->remark( $self->remark ); |
312
|
0
|
0
|
0
|
|
|
|
$do_update = 1; |
313
|
0
|
|
|
|
|
|
} |
314
|
0
|
|
|
|
|
|
if ( ! defined( $found_sched->disabled ) and defined( $self->disabled ) ) { |
315
|
|
|
|
|
|
|
$found_sched->disabled( $self->disabled ); |
316
|
0
|
0
|
0
|
|
|
|
$do_update = 1; |
317
|
0
|
|
|
|
|
|
} |
318
|
0
|
|
|
|
|
|
if ( $do_update ) { |
319
|
|
|
|
|
|
|
$status = $found_sched->update( $context ); |
320
|
0
|
0
|
|
|
|
|
if ( $status->level eq 'OK' and $status->code eq 'DOCHAZKA_CUD_OK' ) { |
321
|
0
|
|
|
|
|
|
$status->code( 'DOCHAZKA_SCHEDULE_UPDATE_OK' ); |
322
|
0
|
0
|
0
|
|
|
|
} |
323
|
0
|
|
|
|
|
|
return $status; |
324
|
|
|
|
|
|
|
} |
325
|
0
|
|
|
|
|
|
return $CELL->status_ok( 'DOCHAZKA_SCHEDULE_EXISTS', args => [ $self->{sid} ], |
326
|
|
|
|
|
|
|
payload => $found_sched ); |
327
|
0
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
} elsif( $status->level ne 'NOTICE' ) { |
329
|
|
|
|
|
|
|
$log->info( "select_single status was neither OK nor NOTICE; returning it as-is" ); |
330
|
|
|
|
|
|
|
return $status; |
331
|
0
|
|
|
|
|
|
} |
332
|
0
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# no exact match found, insert a new record |
334
|
|
|
|
|
|
|
$log->debug( __PACKAGE__ . "::insert calling cud to insert new schedule" ); |
335
|
|
|
|
|
|
|
$status = cud( |
336
|
0
|
|
|
|
|
|
conn => $context->{'dbix_conn'}, |
337
|
|
|
|
|
|
|
eid => $context->{'current'}->{'eid'}, |
338
|
|
|
|
|
|
|
object => $self, |
339
|
0
|
|
|
|
|
|
sql => $site->SQL_SCHEDULE_INSERT, |
340
|
|
|
|
|
|
|
attrs => [ 'scode', 'schedule', 'remark' ], |
341
|
|
|
|
|
|
|
); |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
if ( $status->ok ) { |
344
|
|
|
|
|
|
|
$status->code( 'DOCHAZKA_SCHEDULE_INSERT_OK' ); |
345
|
0
|
0
|
|
|
|
|
$log->info( "Inserted new schedule with SID " . $self->{sid} ); |
346
|
0
|
|
|
|
|
|
} |
347
|
0
|
|
|
|
|
|
return $status; |
348
|
|
|
|
|
|
|
} |
349
|
0
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=head2 update |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
Although we do not allow the 'sid' or 'schedule' fields to be updated, schedule |
354
|
|
|
|
|
|
|
records have 'scode', 'remark' and 'disabled' fields that can be updated via this |
355
|
|
|
|
|
|
|
method. |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=cut |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
my $self = shift; |
360
|
|
|
|
|
|
|
my ( $context ) = validate_pos( @_, { type => HASHREF } ); |
361
|
|
|
|
|
|
|
|
362
|
0
|
|
|
0
|
1
|
|
return $CELL->status_err( 'DOCHAZKA_MALFORMED_400' ) unless $self->{'sid'}; |
363
|
0
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
my $status = cud( |
365
|
0
|
0
|
|
|
|
|
conn => $context->{'dbix_conn'}, |
366
|
|
|
|
|
|
|
eid => $context->{'current'}->{'eid'}, |
367
|
|
|
|
|
|
|
object => $self, |
368
|
|
|
|
|
|
|
sql => $site->SQL_SCHEDULE_UPDATE, |
369
|
0
|
|
|
|
|
|
attrs => [ 'scode', 'remark', 'disabled', 'sid' ], |
370
|
|
|
|
|
|
|
); |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
return $status; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
0
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=head2 delete |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
Instance method. Attempts to DELETE a schedule record. This may succeed |
379
|
|
|
|
|
|
|
if no other records in the database refer to this schedule. |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=cut |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
my $self = shift; |
384
|
|
|
|
|
|
|
my ( $context ) = validate_pos( @_, { type => HASHREF } ); |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
my $status = cud( |
387
|
0
|
|
|
0
|
1
|
|
conn => $context->{'dbix_conn'}, |
388
|
0
|
|
|
|
|
|
eid => $context->{'current'}->{'eid'}, |
389
|
|
|
|
|
|
|
object => $self, |
390
|
|
|
|
|
|
|
sql => $site->SQL_SCHEDULE_DELETE, |
391
|
|
|
|
|
|
|
attrs => [ 'sid' ], |
392
|
0
|
|
|
|
|
|
); |
393
|
|
|
|
|
|
|
$self->reset( sid => $self->{sid} ) if $status->ok; |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
$log->debug( "Entering " . __PACKAGE__ . "::delete with status " . Dumper( $status ) ); |
396
|
|
|
|
|
|
|
return $status; |
397
|
0
|
0
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
0
|
|
|
|
|
|
|
400
|
0
|
|
|
|
|
|
=head2 load_by_scode |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
Analogous function to L<App::Dochazka::REST::Model::Activity/"load_by_aid">. |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=cut |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
my $self = shift; |
407
|
|
|
|
|
|
|
my ( $conn, $scode ) = validate_pos( @_, |
408
|
|
|
|
|
|
|
{ isa => 'DBIx::Connector' }, |
409
|
|
|
|
|
|
|
{ type => SCALAR }, |
410
|
|
|
|
|
|
|
); |
411
|
0
|
|
|
0
|
1
|
|
|
412
|
0
|
|
|
|
|
|
return load( |
413
|
|
|
|
|
|
|
conn => $conn, |
414
|
|
|
|
|
|
|
class => __PACKAGE__, |
415
|
|
|
|
|
|
|
sql => $site->SQL_SCHEDULE_SELECT_BY_SCODE, |
416
|
|
|
|
|
|
|
keys => [ $scode ], |
417
|
0
|
|
|
|
|
|
); |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=head2 load_by_sid |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
Analogous function to L<App::Dochazka::REST::Model::Activity/"load_by_aid">. |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
=cut |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
my $self = shift; |
429
|
|
|
|
|
|
|
my ( $conn, $sid ) = validate_pos( @_, |
430
|
|
|
|
|
|
|
{ isa => 'DBIx::Connector' }, |
431
|
|
|
|
|
|
|
{ type => SCALAR }, |
432
|
|
|
|
|
|
|
); |
433
|
|
|
|
|
|
|
|
434
|
0
|
|
|
0
|
1
|
|
return load( |
435
|
0
|
|
|
|
|
|
conn => $conn, |
436
|
|
|
|
|
|
|
class => __PACKAGE__, |
437
|
|
|
|
|
|
|
sql => $site->SQL_SCHEDULE_SELECT_BY_SID, |
438
|
|
|
|
|
|
|
keys => [ $sid ], |
439
|
|
|
|
|
|
|
); |
440
|
0
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
=head1 FUNCTIONS |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=head2 sid_exists |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
Boolean function |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=cut |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
BEGIN { |
454
|
|
|
|
|
|
|
no strict 'refs'; |
455
|
|
|
|
|
|
|
*{'sid_exists'} = App::Dochazka::REST::Model::Shared::make_test_exists( 'sid' ); |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
=head2 get_all_schedules |
460
|
41
|
|
|
41
|
|
330
|
|
|
41
|
|
|
|
|
118
|
|
|
41
|
|
|
|
|
5039
|
|
461
|
41
|
|
|
41
|
|
5760
|
Returns a list of all schedule objects, ordered by sid. Takes one |
|
41
|
|
|
|
|
11098
|
|
462
|
|
|
|
|
|
|
argument - a paramhash that can contain only one key, 'disabled', |
463
|
|
|
|
|
|
|
which can be either true or false (defaults to true). |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=cut |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
my %PH = validate( @_, { |
468
|
|
|
|
|
|
|
conn => { isa => 'DBIx::Connector' }, |
469
|
|
|
|
|
|
|
disabled => { type => SCALAR, default => 0 } |
470
|
|
|
|
|
|
|
} ); |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
my $sql = $PH{disabled} |
473
|
|
|
|
|
|
|
? $site->SQL_SCHEDULES_SELECT_ALL_INCLUDING_DISABLED |
474
|
0
|
|
|
0
|
1
|
|
: $site->SQL_SCHEDULES_SELECT_ALL_EXCEPT_DISABLED; |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
# run the query and gather the results |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
return load_multiple( |
479
|
|
|
|
|
|
|
conn => $PH{'conn'}, |
480
|
0
|
0
|
|
|
|
|
class => __PACKAGE__, |
481
|
|
|
|
|
|
|
sql => $sql, |
482
|
|
|
|
|
|
|
keys => [], |
483
|
|
|
|
|
|
|
); |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
|
486
|
0
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
#=head2 get_schedule_json |
488
|
|
|
|
|
|
|
# |
489
|
|
|
|
|
|
|
#Given a SID, queries the database for the JSON string associated with the SID. |
490
|
|
|
|
|
|
|
#Returns undef if not found. |
491
|
|
|
|
|
|
|
# |
492
|
|
|
|
|
|
|
#=cut |
493
|
|
|
|
|
|
|
# |
494
|
|
|
|
|
|
|
#sub get_schedule_json { |
495
|
|
|
|
|
|
|
# my ( $sid ) = @_; |
496
|
|
|
|
|
|
|
# die "Problem with arguments in get_schedule_json" if not defined $sid; |
497
|
|
|
|
|
|
|
# |
498
|
|
|
|
|
|
|
# my $json; |
499
|
|
|
|
|
|
|
# try { |
500
|
|
|
|
|
|
|
# $conn->do( fixup => sub { |
501
|
|
|
|
|
|
|
# ( $json ) = $_->selectrow_array( $site->SQL_SCHEDULES_SELECT_SCHEDULE, |
502
|
|
|
|
|
|
|
# undef, |
503
|
|
|
|
|
|
|
# $sid ); |
504
|
|
|
|
|
|
|
# } ); |
505
|
|
|
|
|
|
|
# } |
506
|
|
|
|
|
|
|
# |
507
|
|
|
|
|
|
|
# if ( $json ) { |
508
|
|
|
|
|
|
|
# $log->debug( __PACKAGE__ . "::get_schedule_json got schedule from database: $json" ); |
509
|
|
|
|
|
|
|
# return decode_schedule_json( $json ); |
510
|
|
|
|
|
|
|
# } |
511
|
|
|
|
|
|
|
# return; |
512
|
|
|
|
|
|
|
#} |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
=head1 AUTHOR |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
Nathan Cutler, C<< <presnypreklad@gmail.com> >> |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=cut |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
1; |
523
|
|
|
|
|
|
|
|