Koha/koha-tmpl/intranet-tmpl/prog/js/place_booking_modal.js
Martin Renvoize 6bfe8467cb
Bug 29002: (follow-up) Add bookings count to side menu
This patch adds booking counts to the bookings option in the side menu
for biblio display pages.

Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Janet McGowan <janet.mcgowan@ptfs-europe.com>
Signed-off-by: Caroline Cyr La Rose <caroline.cyr-la-rose@inlibro.com>
Signed-off-by: Laurence Rault <laurence.rault@biblibre.com>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
2023-11-03 12:04:14 -03:00

346 lines
14 KiB
JavaScript

$('#placeBookingModal').on('show.bs.modal', function(e) {
var button = $(e.relatedTarget);
var biblionumber = button.data('biblionumber');
var itemnumber = button.data('itemnumber') || 0;
$('#booking_biblio_id').val(biblionumber);
// Patron select2
$("#booking_patron_id").kohaSelect({
dropdownParent: $(".modal-content", "#placeBookingModal"),
width: '30%',
dropdownAutoWidth: true,
allowClear: true,
minimumInputLength: 3,
ajax: {
url: '/api/v1/patrons',
delay: 250,
dataType: 'json',
data: function(params) {
var search_term = (params.term === undefined) ? '' : params.term;
var query = {
'q': JSON.stringify({
"-or": [{
"firstname": {
"-like": search_term + '%'
}
},
{
"surname": {
"-like": search_term + '%'
}
},
{
"cardnumber": {
"-like": search_term + '%'
}
}
]
}),
'_order_by': 'firstname',
'_page': params.page,
};
return query;
},
processResults: function(data, params) {
var results = [];
data.results.forEach(function(patron) {
results.push({
"id": patron.patron_id,
"text": escape_str(patron.firstname) + " " + escape_str(patron.surname) + " (" + escape_str(patron.cardnumber) + ")"
});
});
return {
"results": results, "pagination": { "more": data.pagination.more }
};
},
},
placeholder: "Search for a patron"
});
// If passed patron, pre-select
var patron_id = button.data('patron') || 0;
if (patron_id) {
var patron = $.ajax({
url: '/api/v1/patrons/' + patron_id,
dataType: 'json',
type: 'GET'
});
$.when(patron).then(
function(patron){
var newOption = new Option(escape_str(patron.firstname) + " " + escape_str(patron.surname) + " (" + escape_str(patron.cardnumber) + ")", patron.patron_id, true, true);
$('#booking_patron_id').append(newOption).trigger('change');
}
);
}
// Item select2
$("#booking_item_id").select2({
dropdownParent: $(".modal-content", "#placeBookingModal"),
width: '30%',
dropdownAutoWidth: true,
minimumResultsForSearch: 20,
placeholder: "Select item"
});
// Adopt flatpickr and update mode
var periodPicker = $("#period").get(0)._flatpickr;
periodPicker.set('mode', 'range');
// Fetch list of bookable items
var items = $.ajax({
url: '/api/v1/biblios/' + biblionumber + '/items?bookable=1' + '&_per_page=-1',
dataType: 'json',
type: 'GET'
});
// Fetch list of existing bookings
var bookings = $.ajax({
url: '/api/v1/bookings?biblio_id=' + biblionumber,
dataType: 'json',
type: 'GET'
});
// Update item select2 and period flatpickr
$.when(items, bookings).then(
function(items,bookings){
// Total bookable items
var bookable = 0;
for (item of items[0]) {
bookable++;
// Populate item select
if (!($('#booking_item_id').find("option[value='" + item.item_id + "']").length)) {
if (itemnumber && itemnumber == item.item_id) {
// Create a DOM Option and pre-select by default
var newOption = new Option(escape_str(item.external_id), item.item_id, true, true);
// Append it to the select
$('#booking_item_id').append(newOption);
} else {
// Create a DOM Option and de-select by default
var newOption = new Option(escape_str(item.external_id), item.item_id, false, false);
// Append it to the select
$('#booking_item_id').append(newOption);
}
}
}
// Redraw select with new options and enable
$('#booking_item_id').trigger('change');
$("#booking_item_id").prop("disabled", false);
// Set disabled dates in datepicker
periodPicker.config.disable.push( function(date) {
// set local copy of selectedDates
let selectedDates = periodPicker.selectedDates;
// set booked counter
let booked = 0;
// reset the unavailable items array
let unavailable_items = [];
// reset the biblio level bookings array
let biblio_bookings = [];
// disable dates before selected date
if (selectedDates[0] && selectedDates[0] > date) {
return true;
}
// iterate existing bookings
for (booking of bookings[0]) {
var start_date = flatpickr.parseDate(booking.start_date);
var end_date = flatpickr.parseDate(booking.end_date);
// patron has selected a start date (end date checks)
if (selectedDates[0]) {
// new booking start date is between existing booking start and end dates
if (selectedDates[0] >= start_date && selectedDates[0] <= end_date) {
if (booking.item_id) {
if (unavailable_items.indexOf(booking.item_id) === -1) {
unavailable_items.push(booking.item_id);
}
} else {
if (biblio_bookings.indexOf(booking.booking_id) === -1) {
biblio_bookings.push(booking.booking_id);
}
}
}
// new booking end date would be between existing booking start and end dates
else if (date >= start_date && date <= end_date) {
if (booking.item_id) {
if (unavailable_items.indexOf(booking.item_id) === -1) {
unavailable_items.push(booking.item_id);
}
} else {
if (biblio_bookings.indexOf(booking.booking_id) === -1) {
biblio_bookings.push(booking.booking_id);
}
}
}
// new booking would span existing booking
else if (selectedDates[0] <= start_date && date >= end_date) {
if (booking.item_id) {
if (unavailable_items.indexOf(booking.item_id) === -1) {
unavailable_items.push(booking.item_id);
}
} else {
if (biblio_bookings.indexOf(booking.booking_id) === -1) {
biblio_bookings.push(booking.booking_id);
}
}
}
// new booking would not conflict
else {
continue;
}
// check that there are available items
// available = all bookable items - booked items - booked biblios
let total_available = items[0].length - unavailable_items.length - biblio_bookings.length;
if (total_available === 0) {
return true;
}
}
// patron has not yet selected a start date (start date checks)
else if (date <= end_date && date >= start_date) {
// same item, disable date
if (booking.item_id && booking.item_id == itemnumber) {
return true;
}
// count all clashes, both item and biblio level
booked++;
if (booked == bookable) {
return true;
}
}
}
});
// Enable flatpickr now we have date function populated
periodPicker.redraw();
$("#period_fields :input").prop('disabled', false);
// Setup listener for item select2
$('#booking_item_id').on('select2:select', function(e) {
itemnumber = e.params.data.id ? e.params.data.id : null;
// redraw pariodPicker taking selected item into account
periodPicker.redraw();
});
// Set onClose for flatpickr
periodPicker.config.onClose.push(function(selectedDates, dateStr, instance) {
if ( selectedDates[0] && selectedDates[1] ) {
// set form fields from picker
let picker_start = new Date(selectedDates[0]);
let picker_end = new Date(selectedDates[1]);
picker_end.setHours(picker_end.getHours()+23);
picker_end.setMinutes(picker_end.getMinutes()+59);
$('#booking_start_date').val(picker_start.toISOString());
$('#booking_end_date').val(picker_end.toISOString());
// set available items in select2
var booked_items = bookings[0].filter(function(booking) {
let start_date = flatpickr.parseDate(booking.start_date);
let end_date = flatpickr.parseDate(booking.end_date);
// This booking ends before the start of the new booking
if ( end_date <= selectedDates[0] ) {
return false;
}
// This booking starts after then end of the new booking
if ( start_date >= selectedDates[1] ) {
return false;
}
// This booking overlaps
return true;
});
$("#booking_item_id > option").each(function() {
let option = $(this);
if ( itemnumber && itemnumber == option.val() ) {
console.log("itemnumber defined and equal to value");
} else if ( booked_items.some(function(booked_item){
return option.val() == booked_item.item_id;
}) ) {
option.prop('disabled',true);
} else {
option.prop('disabled',false);
}
});
}
});
},
function(jqXHR, textStatus, errorThrown){
console.log("Fetch failed");
}
);
});
$("#placeBookingForm").on('submit', function(e) {
e.preventDefault();
var url = '/api/v1/bookings';
var start_date = $('#booking_start_date').val();
var end_date = $('#booking_end_date').val();
var item_id = $('#booking_item_id').val();
var posting = $.post(
url,
JSON.stringify({
"start_date": start_date,
"end_date": end_date,
"biblio_id": $('#booking_biblio_id').val(),
"item_id": item_id != 0 ? item_id : null,
"patron_id": $('#booking_patron_id').find(':selected').val()
})
);
posting.done(function(data) {
// Update bookings page as required
if (typeof bookings_table !== 'undefined' && bookings_table !== null) {
bookings_table.api().ajax.reload();
}
if (typeof timeline !== 'undefined' && timeline !== null) {
timeline.itemsData.add({
id: data.booking_id,
booking: data.booking_id,
patron: data.patron_id,
start: dayjs(data.start_date).toDate(),
end: dayjs(data.end_date).toDate(),
content: 'Booking: ' + data.booking_id,
editable: { remove: true, updateTime: true },
type: 'range',
group: data.item_id ? data.item_id : 0
});
}
// Update bookings counts
$('.bookings_count').html(parseInt($('.bookings_count').html(), 10)+1);
// Close modal
$('#placeBookingModal').modal('hide');
// Reset form
$('#booking_patron_id').val(null).trigger('change');
$('#booking_item_id').val(null).trigger('change');
$("#period").get(0)._flatpickr.clear();
$('#booking_start_date').val('');
$('#booking_end_date').val('');
});
posting.fail(function(data) {
$('#booking_result').replaceWith('<div id="booking_result" class="alert alert-danger">Failure</div>');
});
});