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 |
- |
|
|