|
Lines 121-127
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 121 |
dataType: 'json', |
121 |
dataType: 'json', |
| 122 |
type: 'GET' |
122 |
type: 'GET' |
| 123 |
}); |
123 |
}); |
| 124 |
|
124 |
|
| 125 |
// Fetch list of existing bookings |
125 |
// Fetch list of existing bookings |
| 126 |
let bookingsFetch = $.ajax({ |
126 |
let bookingsFetch = $.ajax({ |
| 127 |
url: '/api/v1/bookings?biblio_id=' + biblionumber, |
127 |
url: '/api/v1/bookings?biblio_id=' + biblionumber, |
|
Lines 135-141
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 135 |
dataType: 'json', |
135 |
dataType: 'json', |
| 136 |
type: 'GET' |
136 |
type: 'GET' |
| 137 |
}); |
137 |
}); |
| 138 |
|
138 |
|
| 139 |
// Update item select2 and period flatpickr |
139 |
// Update item select2 and period flatpickr |
| 140 |
$.when(itemsFetch, bookingsFetch, checkoutsFetch).then( |
140 |
$.when(itemsFetch, bookingsFetch, checkoutsFetch).then( |
| 141 |
function(itemsFetch,bookingsFetch, checkoutsFetch){ |
141 |
function(itemsFetch,bookingsFetch, checkoutsFetch){ |
|
Lines 157-163
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 157 |
}; |
157 |
}; |
| 158 |
bookings.unshift(booking); |
158 |
bookings.unshift(booking); |
| 159 |
} |
159 |
} |
| 160 |
|
160 |
|
| 161 |
// Item select2 |
161 |
// Item select2 |
| 162 |
$("#booking_item_id").select2({ |
162 |
$("#booking_item_id").select2({ |
| 163 |
dropdownParent: $(".modal-content", "#placeBookingModal"), |
163 |
dropdownParent: $(".modal-content", "#placeBookingModal"), |
|
Lines 166-178
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 166 |
minimumResultsForSearch: 20, |
166 |
minimumResultsForSearch: 20, |
| 167 |
placeholder: __("Select item") |
167 |
placeholder: __("Select item") |
| 168 |
}); |
168 |
}); |
| 169 |
|
169 |
|
| 170 |
// Update flatpickr mode |
170 |
// Update flatpickr mode |
| 171 |
periodPicker.set('mode', 'range'); |
171 |
periodPicker.set('mode', 'range'); |
| 172 |
|
172 |
|
| 173 |
// Total bookable items |
173 |
// Total bookable items |
| 174 |
let bookable = 0; |
174 |
let bookable = 0; |
| 175 |
|
175 |
|
| 176 |
for (item of bookable_items) { |
176 |
for (item of bookable_items) { |
| 177 |
bookable++; |
177 |
bookable++; |
| 178 |
// Populate item select (NOTE: Do we still need this check for pre-existing select option here?) |
178 |
// Populate item select (NOTE: Do we still need this check for pre-existing select option here?) |
|
Lines 183-211
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 183 |
$('#booking_item_id').append(newOption); |
183 |
$('#booking_item_id').append(newOption); |
| 184 |
} |
184 |
} |
| 185 |
} |
185 |
} |
| 186 |
|
186 |
|
| 187 |
// Set disable function for periodPicker |
187 |
// Set disable function for periodPicker |
| 188 |
let disableExists = periodPicker.config.disable.filter(f => f.name === 'dateDisable'); |
188 |
let disableExists = periodPicker.config.disable.filter(f => f.name === 'dateDisable'); |
| 189 |
if ( disableExists.length === 0 ) { |
189 |
if ( disableExists.length === 0 ) { |
| 190 |
periodPicker.config.disable.push(function dateDisable(date){ |
190 |
periodPicker.config.disable.push(function dateDisable(date){ |
| 191 |
|
191 |
|
| 192 |
// set local copy of selectedDates |
192 |
// set local copy of selectedDates |
| 193 |
let selectedDates = periodPicker.selectedDates; |
193 |
let selectedDates = periodPicker.selectedDates; |
| 194 |
|
194 |
|
| 195 |
// set booked counter |
195 |
// set booked counter |
| 196 |
let booked = 0; |
196 |
let booked = 0; |
| 197 |
|
197 |
|
| 198 |
// reset the unavailable items array |
198 |
// reset the unavailable items array |
| 199 |
let unavailable_items = []; |
199 |
let unavailable_items = []; |
| 200 |
|
200 |
|
| 201 |
// reset the biblio level bookings array |
201 |
// reset the biblio level bookings array |
| 202 |
let biblio_bookings = []; |
202 |
let biblio_bookings = []; |
| 203 |
|
203 |
|
| 204 |
// disable dates before selected date |
204 |
// disable dates before selected date |
| 205 |
if (!selectedDates[1] && (selectedDates[0] && selectedDates[0] > date)) { |
205 |
if (!selectedDates[1] && (selectedDates[0] && selectedDates[0] > date)) { |
| 206 |
return true; |
206 |
return true; |
| 207 |
} |
207 |
} |
| 208 |
|
208 |
|
| 209 |
// iterate existing bookings |
209 |
// iterate existing bookings |
| 210 |
for (booking of bookings) { |
210 |
for (booking of bookings) { |
| 211 |
|
211 |
|
|
Lines 216-225
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 216 |
|
216 |
|
| 217 |
let start_date = flatpickr.parseDate(booking.start_date); |
217 |
let start_date = flatpickr.parseDate(booking.start_date); |
| 218 |
let end_date = flatpickr.parseDate(booking.end_date); |
218 |
let end_date = flatpickr.parseDate(booking.end_date); |
| 219 |
|
219 |
|
| 220 |
// patron has selected a start date (end date checks) |
220 |
// patron has selected a start date (end date checks) |
| 221 |
if (selectedDates[0]) { |
221 |
if (selectedDates[0]) { |
| 222 |
|
222 |
|
| 223 |
// new booking start date is between existing booking start and end dates |
223 |
// new booking start date is between existing booking start and end dates |
| 224 |
if (selectedDates[0] >= start_date && selectedDates[0] <= end_date) { |
224 |
if (selectedDates[0] >= start_date && selectedDates[0] <= end_date) { |
| 225 |
if (booking.item_id) { |
225 |
if (booking.item_id) { |
|
Lines 232-238
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 232 |
} |
232 |
} |
| 233 |
} |
233 |
} |
| 234 |
} |
234 |
} |
| 235 |
|
235 |
|
| 236 |
// new booking end date would be between existing booking start and end dates |
236 |
// new booking end date would be between existing booking start and end dates |
| 237 |
else if (date >= start_date && date <= end_date) { |
237 |
else if (date >= start_date && date <= end_date) { |
| 238 |
if (booking.item_id) { |
238 |
if (booking.item_id) { |
|
Lines 245-251
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 245 |
} |
245 |
} |
| 246 |
} |
246 |
} |
| 247 |
} |
247 |
} |
| 248 |
|
248 |
|
| 249 |
// new booking would span existing booking |
249 |
// new booking would span existing booking |
| 250 |
else if (selectedDates[0] <= start_date && date >= end_date) { |
250 |
else if (selectedDates[0] <= start_date && date >= end_date) { |
| 251 |
if (booking.item_id) { |
251 |
if (booking.item_id) { |
|
Lines 258-269
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 258 |
} |
258 |
} |
| 259 |
} |
259 |
} |
| 260 |
} |
260 |
} |
| 261 |
|
261 |
|
| 262 |
// new booking would not conflict |
262 |
// new booking would not conflict |
| 263 |
else { |
263 |
else { |
| 264 |
continue; |
264 |
continue; |
| 265 |
} |
265 |
} |
| 266 |
|
266 |
|
| 267 |
// check that there are available items |
267 |
// check that there are available items |
| 268 |
// available = all bookable items - booked items - booked biblios |
268 |
// available = all bookable items - booked items - booked biblios |
| 269 |
let total_available = bookable_items.length - unavailable_items.length - biblio_bookings.length; |
269 |
let total_available = bookable_items.length - unavailable_items.length - biblio_bookings.length; |
|
Lines 271-296
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 271 |
return true; |
271 |
return true; |
| 272 |
} |
272 |
} |
| 273 |
} |
273 |
} |
| 274 |
|
274 |
|
| 275 |
// patron has not yet selected a start date (start date checks) |
275 |
// patron has not yet selected a start date (start date checks) |
| 276 |
else if (date <= end_date && date >= start_date) { |
276 |
else if (date <= end_date && date >= start_date) { |
| 277 |
|
277 |
|
| 278 |
// same item, disable date |
278 |
// same item, disable date |
| 279 |
if (booking.item_id && booking.item_id == booking_item_id) { |
279 |
if (booking.item_id && booking.item_id == booking_item_id) { |
| 280 |
return true; |
280 |
return true; |
| 281 |
} |
281 |
} |
| 282 |
|
282 |
|
| 283 |
// count all clashes, both item and biblio level |
283 |
// count all clashes, both item and biblio level |
| 284 |
booked++; |
284 |
booked++; |
| 285 |
if (booked == bookable) { |
285 |
if (booked == bookable) { |
| 286 |
return true; |
286 |
return true; |
| 287 |
} |
287 |
} |
| 288 |
|
288 |
|
| 289 |
// FIXME: The above is not intelligent enough to spot |
289 |
// FIXME: The above is not intelligent enough to spot |
| 290 |
// cases where an item must be used for a biblio level booking |
290 |
// cases where an item must be used for a biblio level booking |
| 291 |
// due to all other items being booking within the biblio level |
291 |
// due to all other items being booking within the biblio level |
| 292 |
// booking period... we end up with a clash |
292 |
// booking period... we end up with a clash |
| 293 |
// To reproduce: |
293 |
// To reproduce: |
| 294 |
// * One bib with two bookable items. |
294 |
// * One bib with two bookable items. |
| 295 |
// * Add item level booking |
295 |
// * Add item level booking |
| 296 |
// * Add biblio level booking that extends one day beyond the item level booking |
296 |
// * Add biblio level booking that extends one day beyond the item level booking |
|
Lines 301-315
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 301 |
} |
301 |
} |
| 302 |
}); |
302 |
}); |
| 303 |
}; |
303 |
}; |
| 304 |
|
304 |
|
| 305 |
// Setup listener for item select2 |
305 |
// Setup listener for item select2 |
| 306 |
$('#booking_item_id').on('select2:select', function(e) { |
306 |
$('#booking_item_id').on('select2:select', function(e) { |
| 307 |
booking_item_id = e.params.data.id ? e.params.data.id : null; |
307 |
booking_item_id = e.params.data.id ? e.params.data.id : null; |
| 308 |
|
308 |
|
| 309 |
// redraw pariodPicker taking selected item into account |
309 |
// redraw pariodPicker taking selected item into account |
| 310 |
periodPicker.redraw(); |
310 |
periodPicker.redraw(); |
| 311 |
}); |
311 |
}); |
| 312 |
|
312 |
|
| 313 |
// Set onChange for flatpickr |
313 |
// Set onChange for flatpickr |
| 314 |
let changeExists = periodPicker.config.onChange.filter(f => f.name ==='periodChange'); |
314 |
let changeExists = periodPicker.config.onChange.filter(f => f.name ==='periodChange'); |
| 315 |
if(changeExists.length === 0) { |
315 |
if(changeExists.length === 0) { |
|
Lines 321-327
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 321 |
let picker_end = dayjs(selectedDates[1]).endOf('day'); |
321 |
let picker_end = dayjs(selectedDates[1]).endOf('day'); |
| 322 |
$('#booking_start_date').val(picker_start.toISOString()); |
322 |
$('#booking_start_date').val(picker_start.toISOString()); |
| 323 |
$('#booking_end_date').val(picker_end.toISOString()); |
323 |
$('#booking_end_date').val(picker_end.toISOString()); |
| 324 |
|
324 |
|
| 325 |
// set available items in select2 |
325 |
// set available items in select2 |
| 326 |
let booked_items = bookings.filter(function(booking) { |
326 |
let booked_items = bookings.filter(function(booking) { |
| 327 |
let start_date = flatpickr.parseDate(booking.start_date); |
327 |
let start_date = flatpickr.parseDate(booking.start_date); |
|
Lines 360-377
$('#placeBookingModal').on('show.bs.modal', function(e) {
Link Here
|
| 360 |
} |
360 |
} |
| 361 |
}); |
361 |
}); |
| 362 |
}; |
362 |
}; |
| 363 |
|
363 |
|
| 364 |
// Enable flatpickr now we have date function populated |
364 |
// Enable flatpickr now we have date function populated |
| 365 |
periodPicker.redraw(); |
365 |
periodPicker.redraw(); |
| 366 |
$("#period_fields :input").prop('disabled', false); |
366 |
$("#period_fields :input").prop('disabled', false); |
| 367 |
|
367 |
|
| 368 |
// Redraw select with new options and enable |
368 |
// Redraw select with new options and enable |
| 369 |
$('#booking_item_id').trigger('change'); |
369 |
$('#booking_item_id').trigger('change'); |
| 370 |
$("#booking_item_id").prop("disabled", false); |
370 |
$("#booking_item_id").prop("disabled", false); |
| 371 |
|
371 |
|
| 372 |
// Set the flag to indicate that data has been fetched |
372 |
// Set the flag to indicate that data has been fetched |
| 373 |
dataFetched = true; |
373 |
dataFetched = true; |
| 374 |
|
374 |
|
| 375 |
// Set form values |
375 |
// Set form values |
| 376 |
setFormValues(patron_id,booking_item_id,start_date,end_date,periodPicker); |
376 |
setFormValues(patron_id,booking_item_id,start_date,end_date,periodPicker); |
| 377 |
}, |
377 |
}, |
|
Lines 459-465
$("#placeBookingForm").on('submit', function(e) {
Link Here
|
| 459 |
"patron_id": $('#booking_patron_id').find(':selected').val() |
459 |
"patron_id": $('#booking_patron_id').find(':selected').val() |
| 460 |
}) |
460 |
}) |
| 461 |
); |
461 |
); |
| 462 |
|
462 |
|
| 463 |
posting.done(function(data) { |
463 |
posting.done(function(data) { |
| 464 |
// Update bookings store for subsequent bookings |
464 |
// Update bookings store for subsequent bookings |
| 465 |
bookings.push(data); |
465 |
bookings.push(data); |
|
Lines 485-501
$("#placeBookingForm").on('submit', function(e) {
Link Here
|
| 485 |
}); |
485 |
}); |
| 486 |
timeline.focus(data.booking_id); |
486 |
timeline.focus(data.booking_id); |
| 487 |
} |
487 |
} |
| 488 |
|
488 |
|
| 489 |
// Update bookings counts |
489 |
// Update bookings counts |
| 490 |
$('.bookings_count').html(parseInt($('.bookings_count').html(), 10)+1); |
490 |
$('.bookings_count').html(parseInt($('.bookings_count').html(), 10)+1); |
| 491 |
|
491 |
|
| 492 |
// Set feedback |
492 |
// Set feedback |
| 493 |
$('#transient_result').replaceWith('<div id="transient_result" class="dialog success">'+_("Booking successfully placed")+'</div>'); |
493 |
$('#transient_result').replaceWith('<div id="transient_result" class="dialog message">'+_("Booking successfully placed")+'</div>'); |
| 494 |
|
494 |
|
| 495 |
// Close modal |
495 |
// Close modal |
| 496 |
$('#placeBookingModal').modal('hide'); |
496 |
$('#placeBookingModal').modal('hide'); |
| 497 |
}); |
497 |
}); |
| 498 |
|
498 |
|
| 499 |
posting.fail(function(data) { |
499 |
posting.fail(function(data) { |
| 500 |
$('#booking_result').replaceWith('<div id="booking_result" class="alert alert-danger">'+_("Failure")+'</div>'); |
500 |
$('#booking_result').replaceWith('<div id="booking_result" class="alert alert-danger">'+_("Failure")+'</div>'); |
| 501 |
}); |
501 |
}); |
|
Lines 513-519
$("#placeBookingForm").on('submit', function(e) {
Link Here
|
| 513 |
"patron_id": $('#booking_patron_id').find(':selected').val() |
513 |
"patron_id": $('#booking_patron_id').find(':selected').val() |
| 514 |
}) |
514 |
}) |
| 515 |
}); |
515 |
}); |
| 516 |
|
516 |
|
| 517 |
putting.done(function(data) { |
517 |
putting.done(function(data) { |
| 518 |
update_success = 1; |
518 |
update_success = 1; |
| 519 |
|
519 |
|
|
Lines 544-555
$("#placeBookingForm").on('submit', function(e) {
Link Here
|
| 544 |
} |
544 |
} |
| 545 |
|
545 |
|
| 546 |
// Set feedback |
546 |
// Set feedback |
| 547 |
$('#transient_result').replaceWith('<div id="transient_result" class="dialog success">'+_("Booking successfully updated")+'</div>'); |
547 |
$('#transient_result').replaceWith('<div id="transient_result" class="dialog message">'+_("Booking successfully updated")+'</div>'); |
| 548 |
|
548 |
|
| 549 |
// Close modal |
549 |
// Close modal |
| 550 |
$('#placeBookingModal').modal('hide'); |
550 |
$('#placeBookingModal').modal('hide'); |
| 551 |
}); |
551 |
}); |
| 552 |
|
552 |
|
| 553 |
putting.fail(function(data) { |
553 |
putting.fail(function(data) { |
| 554 |
$('#booking_result').replaceWith('<div id="booking_result" class="alert alert-danger">'+__("Failure")+'</div>'); |
554 |
$('#booking_result').replaceWith('<div id="booking_result" class="alert alert-danger">'+__("Failure")+'</div>'); |
| 555 |
}); |
555 |
}); |
| 556 |
- |
|
|