From 1006b34fc949a533c86c7ecfffa3eb593aff0607 Mon Sep 17 00:00:00 2001 From: Thibaud Guillot Date: Tue, 3 Dec 2024 14:04:51 +0100 Subject: [PATCH] Bug 38493: Add possibility to add mutliple bookings at once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note: For now it's implemented only on the OPAC side If the biblio_id parameter is not present in the url, the modal window will be replaced by another form. Items can be found by barcode, and once added, validated by clicking on the button. Pickup locations will automatically appear according to the item's biblios. Test plan: 1) Apply this patch and restart_all 2) Active booking for one item or itemtype 3) Go on the OPAC url 'cgi-bin/koha/opac-bookings.pl' 4) You can add some items with their barcodes 5) Dynamically delete items if you want 6) And when you're ready, click on 'Validate items' it will check if you can perform a booking for each items with the same pickup library and on the same period Sponsored by: Association de Gestion des Ĺ’uvres Sociales d'Inria (AGOS) --- .../bootstrap/en/includes/modals/bookings.inc | 137 +++++++++++++- .../bootstrap/en/modules/opac-bookings.tt | 6 +- .../js/modals/place_multiple_bookings.js | 169 ++++++++++++++++++ 3 files changed, 308 insertions(+), 4 deletions(-) create mode 100644 koha-tmpl/opac-tmpl/bootstrap/js/modals/place_multiple_bookings.js diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/modals/bookings.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/modals/bookings.inc index 2645a244d4..aa5c850ce0 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/modals/bookings.inc +++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/modals/bookings.inc @@ -66,7 +66,42 @@ [% END %] - [% CASE %] + [% CASE 'add-multiple' %] +
+
+ + + + +
    +
  1. +
    + + + +
    +
      +
    • + +
    • + + + Required +
    • +
    • +
      + + + Required +
      +
      Select the booking start date and end date
      +
    • +
    +
    [% END %] - \ No newline at end of file + + diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-bookings.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-bookings.tt index 18b78fbe2b..77be977c8a 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-bookings.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-bookings.tt @@ -67,15 +67,16 @@
    + [% SET action_method = biblio == '' ? 'add-multiple' : 'add' %] - [% PROCESS 'modals/bookings.inc' action = 'add' %] + [% PROCESS 'modals/bookings.inc' action = action_method %]
    [% PROCESS 'bookings-table.inc' %] @@ -92,6 +93,7 @@ [% Asset.js("js/form-submit.js") | $raw %] [% Asset.js("lib/vis-timeline/vis-timeline-graph2d.min.js") | $raw %] [% Asset.js("js/modals/place_booking.js") | $raw %] + [% Asset.js("js/modals/place_multiple_bookings.js") | $raw %] [% Asset.js("lib/bootstrap/js/bootstrap.min.js") | $raw %] [% INCLUDE 'select2.inc' %] [% INCLUDE 'calendar.inc' %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/js/modals/place_multiple_bookings.js b/koha-tmpl/opac-tmpl/bootstrap/js/modals/place_multiple_bookings.js new file mode 100644 index 0000000000..bb21c6f141 --- /dev/null +++ b/koha-tmpl/opac-tmpl/bootstrap/js/modals/place_multiple_bookings.js @@ -0,0 +1,169 @@ +function validateItems (){ + let $pickupSelect = $("#pickup_library_id"); + var bookingItems = $('#items-list li').map(function() { + var barcode = $(this).attr('id').replace('booking_item-', ''); + var biblioId = $(this).data('biblio_id'); + var itemId = $(this).data('item_id'); + return { + [barcode]: { + biblionumber: biblioId, + itemnumber: itemId + } + }; + }).get(); + + var pickupLocations = []; + var promises = bookingItems.map(function(item) { + var barcode = Object.keys(item)[0]; + var biblionumber = item[barcode].biblionumber; + + return new Promise(function(resolve, reject) { + addPickupLocation(pickupLocations, biblionumber, resolve, reject); + }); + }); + Promise.all(promises).then(function() { + $pickupSelect.empty(); + pickupLocations.forEach(el => { + let option = $( + '" + ); + $pickupSelect.append(option); + }); + }).catch(function(error) { + console.log("An error occurred while fetching pickup locations: ", error); + }); + $pickupSelect.prop('disabled', false); + + // Set flatpickr + let periodPicker = $("#period").get(0)._flatpickr; + periodPicker.set("mode", "range"); + + // Set onChange for flatpickr + let changeExists = periodPicker.config.onChange.filter( + (f) => f.name === "periodChange" + ); + if (changeExists.length === 0) { + periodPicker.config.onChange.push(function periodChange( + selectedDates, + dateStr, + instance + ) { + // Range set, update hidden fields and set available items + if (selectedDates[0] && selectedDates[1]) { + // set form fields from picker + let picker_start = dayjs(selectedDates[0]); + let picker_end = dayjs(selectedDates[1]).endOf( + "day" + ); + $("#booking-start_date").val( + picker_start.toISOString() + ); + $("#booking-end_date").val( + picker_end.toISOString() + ); + } + }); + } +} + +function addPickupLocation(locations, biblionumber, resolve, reject) { + let pickup_url = "/api/v1/biblios/" + biblionumber + "/pickup_locations"; + $.ajax({ + url: pickup_url, + type: "GET", + dataType: "json", + data: { + _order_by: "name", + _per_page: "-1", + patron_id: logged_in_user_id, + }, + success: function(response) { + var library_id = response[0].library_id; + var library_name = response[0].name; + + if (!locations.some(location => location.id === library_id)) { + locations.push({ id: library_id, name: library_name }); + } + resolve(); + }, + error: function(xhr, status, error) { + console.log("Pickup location fetch failed: ", error); + reject(error); + }, + }); +} + +$("#opac-add-multiple-form-booking").on("submit", function (e) { + e.preventDefault(); + + var url = "/api/v1/bookings"; + + var items_list = $('#items-list li'); + var start_date = $("#booking-start_date").val(); + var end_date = $("#booking-end_date").val(); + var pickup_library_id = $("#pickup_library_id").val(); + + var errors = []; + var requests = []; + var sendBookingRequest = function (item_id, biblio_id) { + return $.post( + url, + JSON.stringify({ + start_date: start_date, + end_date: end_date, + biblio_id: biblio_id, + item_id: item_id, + patron_id: logged_in_user_id, + pickup_library_id: pickup_library_id + }) + ); + }; + + items_list.each(function (i) { + item_id = $(this).data('item_id'); + biblio_id = $(this).data('biblio_id'); + var request = sendBookingRequest(item_id, biblio_id); + + requests.push(request); + + request.fail(function (data) { + var error = data.responseJSON.error; + var errorMessage = error ? error : "Failure"; + errors.push(item_id + " - " + errorMessage); + }); + }); + + $.when.apply($, requests).done(function () { + if (errors.length > 0) { + $("#booking_result").replaceWith( + '
    ' + + errors.join("
    ") + + "
    " + ); + } else { + $("#opac-add-multiple-booking-modal").modal("hide"); + window.location.reload(); + } + }).fail(function () { + $("#booking_result").replaceWith( + '
    ' + + errors.join("
    ") + + "
    " + ); + }); +}); + +$("#opac-add-multiple-booking-modal").on("hidden.bs.modal", function (e) { + $("#period").get(0)._flatpickr.clear(); + $("#booking-start_date").val(""); + $("#booking-end_date").val(""); + $("#booking_id").val(""); + // Reset pickup library select + $("#pickup_library_id").val(null).trigger("change"); + $("#pickup_library_id").empty(); + $("#pickup_library_id").prop("disabled", true); +}); -- 2.25.1