From 6594141fbec41e9b0da58c9fa03bf28007c3b928 Mon Sep 17 00:00:00 2001
From: Pedro Amorim <pedro.amorim@ptfs-europe.com>
Date: Fri, 5 Jan 2024 15:24:07 +0000
Subject: [PATCH] Bug 35604: ConfirmAuto workflow stage

Signed-off-by: David Nind <david@davidnind.com>
---
 Koha/ILL/Request/Workflow/ConfirmAuto.pm      | 116 +++++++++++++
 ill/ill-requests.pl                           |   9 +
 .../prog/en/modules/ill/ill-requests.tt       |  48 ++++++
 .../intranet-tmpl/prog/js/ill-autobackend.js  | 163 ++++++++++++++++++
 .../bootstrap/en/modules/opac-illrequests.tt  |  42 ++++-
 .../opac-tmpl/bootstrap/js/ill-autobackend.js | 161 +++++++++++++++++
 opac/opac-illrequests.pl                      |  13 ++
 7 files changed, 551 insertions(+), 1 deletion(-)
 create mode 100644 Koha/ILL/Request/Workflow/ConfirmAuto.pm
 create mode 100644 koha-tmpl/intranet-tmpl/prog/js/ill-autobackend.js
 create mode 100644 koha-tmpl/opac-tmpl/bootstrap/js/ill-autobackend.js

diff --git a/Koha/ILL/Request/Workflow/ConfirmAuto.pm b/Koha/ILL/Request/Workflow/ConfirmAuto.pm
new file mode 100644
index 0000000000..fe25702011
--- /dev/null
+++ b/Koha/ILL/Request/Workflow/ConfirmAuto.pm
@@ -0,0 +1,116 @@
+package Koha::ILL::Request::Workflow::ConfirmAuto;
+
+# Copyright 2023 PTFS Europe Ltd
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
+
+use Modern::Perl;
+
+use base qw(Koha::ILL::Request::Workflow);
+
+use JSON qw( encode_json );
+use Koha::ILL::Backends;
+
+=head1 NAME
+
+Koha::ILL::Request::Workflow::ConfirmAuto - Koha ILL ConfirmAuto Workflow
+
+=head1 SYNOPSIS
+
+Object-oriented class that provides the AutoILLBackendPriority confirmation screen
+
+=head1 DESCRIPTION
+
+This class provides the ability to verify if it should render the AutoILLBackendPriority
+confirmation screen and handle the template params accordingly
+
+=head1 API
+
+=head2 Class Methods
+
+=head3 show_confirm_auto
+
+    my $show_confirm_auto =
+    Koha::ILL::Request::Workflow::ConfirmAuto->show_confirm_auto($params);
+
+Given $request, returns true if confirm auto should be shown
+
+=cut
+
+sub show_confirm_auto {
+    my ( $self, $request ) = @_;
+
+    return
+
+        # AutoILLBackendPriority is enabled
+        C4::Context->preference("AutoILLBackendPriority")
+
+        # Confirm auto has not yet been submitted
+        && !$self->{metadata}->{confirm_auto_submitted}
+
+        # The form has been submitted and the backend is able to create the request
+        && $request->_backend_capability( 'can_create_request', $self->{metadata} );
+
+}
+
+=head3 confirm_auto_template_params
+
+Given $params, returns the template parameters for rendering the confirm auto screen
+
+=cut
+
+sub confirm_auto_template_params {
+    my ( $self, $params ) = @_;
+
+    $params->{method} = 'confirmautoill' if $self->{ui_context} eq 'staff';
+    delete $params->{stage}              if $self->{ui_context} eq 'staff';
+
+    my @backends = $self->get_priority_backends();
+    return (
+        whole              => $params,
+        metadata           => $self->prep_metadata($params),
+        core_fields        => Koha::ILL::Backend::Standard->_get_core_fields,
+        auto_backends_json => scalar encode_json( \@backends ),
+        $self->{ui_context} eq 'opac'
+        ? (
+            illrequestsview => 1,
+            message         => $params->{message},
+            op              => 'confirmautoill',
+            )
+        : ()
+    );
+}
+
+=head3 get_priority_backends
+
+Returns backends ordered by AutoILLBackendPriority
+
+=cut
+
+sub get_priority_backends {
+    my ( $self, $params ) = @_;
+
+    my @backends;
+    my @priority_enabled_backends = split ",", C4::Context->preference('AutoILLBackendPriority');
+    foreach my $backend (@priority_enabled_backends) {
+        my $loaded_backend          = Koha::ILL::Request->new->load_backend($backend);
+        my $availability_check_info = $loaded_backend->_backend->availability_check_info( $self->{metadata} );
+        push @backends, $availability_check_info if $availability_check_info;
+    }
+    return @backends;
+}
+
+1;
diff --git a/ill/ill-requests.pl b/ill/ill-requests.pl
index 71d716ac56..a75ebc4ce4 100755
--- a/ill/ill-requests.pl
+++ b/ill/ill-requests.pl
@@ -31,6 +31,7 @@ use Koha::ILL::Request;
 use Koha::ILL::Batches;
 use Koha::ILL::Request::Workflow::Availability;
 use Koha::ILL::Request::Workflow::TypeDisclaimer;
+use Koha::ILL::Request::Workflow::ConfirmAuto;
 use Koha::Libraries;
 use Koha::Plugins;
 
@@ -137,6 +138,8 @@ if ( $backends_available ) {
           Koha::ILL::Request::Workflow::Availability->new( $params, 'staff' );
         my $type_disclaimer =
         Koha::ILL::Request::Workflow::TypeDisclaimer->new( $params, 'staff' );
+        my $confirm_auto =
+        Koha::ILL::Request::Workflow::ConfirmAuto->new( $params, 'staff' );
 
         # ILLCheckAvailability operation
         if ($availability->show_availability($request)) {
@@ -150,6 +153,12 @@ if ( $backends_available ) {
             $template->param(
                 $type_disclaimer->type_disclaimer_template_params($params)
             );
+        # ConfirmAuto operation
+        } elsif ( $confirm_auto->show_confirm_auto($request)) {
+            $op = 'confirmautoill';
+            $template->param(
+                $confirm_auto->confirm_auto_template_params($params)
+            );
         # Ready to create ILL request
         } else {
             my $backend_result = $request->backend_create($params);
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt
index 732f706d0b..f4754793a3 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt
@@ -44,6 +44,13 @@
             [% WRAPPER breadcrumb_item bc_active= 1 %]
                 <span>Request type disclaimer</span>
             [% END %]
+        [% ELSIF query_type == 'confirmautoill' %]
+            [% WRAPPER breadcrumb_item %]
+                <a href="/cgi-bin/koha/ill/ill-requests.pl">ILL requests</a>
+            [% END %]
+            [% WRAPPER breadcrumb_item bc_active= 1 %]
+                <span>Confirm automatic request</span>
+            [% END %]
         [% ELSE %]
             [% WRAPPER breadcrumb_item bc_active= 1 %]
                 <span>ILL requests</span>
@@ -929,6 +936,39 @@
                             </fieldset>
                         </form>
                     </div>
+                    [% ELSIF op == 'confirmautoill' %]
+                    <!-- confirmautoill -->
+                    <h1>Confirm automatic request</h1>
+                    <div id="results" class="page-section">
+                        <form method="post" id="confirmautoill-form">
+                            <fieldset class="rows">
+                                <h3>Confirm backend:</h3>
+                                <p id="autoillbackends"></p>
+                                <p id="autoillbackend-message" class="text-info"></p>
+                            </fieldset>
+                            <fieldset class="action">
+                                [% FOREACH key IN whole.keys %]
+                                    [% value = whole.$key %]
+                                    [% IF key != 'method' && key != 'custom_key' && key != 'custom_value' %]
+                                        <input type="hidden" name="[% key | html %]" value="[% value | html %]">
+                                    [% END %]
+                                [% END %]
+                                [% custom_keys = whole.custom_key.split('\0') %]
+                                [% custom_values = whole.custom_value.split('\0') %]
+                                [% i = 0 %]
+                                [% FOREACH custom_key IN custom_keys %]
+                                    <input type="hidden" name="custom_key" value="[% custom_key | html %]">
+                                    <input type="hidden" name="custom_value" value="[% custom_values.$i | html %]">
+                                    [% i = i + 1 %]
+                                [% END %]
+                                <input type="hidden" name="method" value="create" />
+                                <input type="hidden" name="stage" value="form">
+                                <input type="hidden" name="confirm_auto_submitted" value="1">
+                                <input type="submit" value="Confirm" />
+                                <a class="cancel" href="ill-requests.pl">Cancel</a>
+                            </fieldset>
+                        </form>
+                    </div>
                 [% ELSIF op == 'batch_list' || op == 'batch_create' %]
                     [% INCLUDE 'ill-batch.inc' %]
                 [% ELSE %]
@@ -973,6 +1013,11 @@
         [% ELSE %]
         var services = [];
         [% END %]
+        [% IF auto_backends_json.length > 0 %]
+        var auto_backends = [% auto_backends_json | $raw %];
+        [% ELSE %]
+        var auto_backends = [];
+        [% END %]
         [% IF metadata.length > 0 %]
         var metadata = "[% metadata | $raw %]";
         [% END %]
@@ -1008,6 +1053,9 @@
     [% IF (op == 'availability' || op == 'generic_confirm') && Koha.Preference('ILLCheckAvailability') %]
         [% Asset.js("js/ill-availability.js") | $raw %]
     [% END %]
+    [% IF (op == 'confirmautoill' && Koha.Preference('AutoILLBackendPriority')) %]
+        [% Asset.js("js/ill-autobackend.js") | $raw %]
+    [% END %]
     [% IF op == 'availability' && Koha.Preference('ILLCheckAvailability') %]
         <script>
             $(document).ready(function() {
diff --git a/koha-tmpl/intranet-tmpl/prog/js/ill-autobackend.js b/koha-tmpl/intranet-tmpl/prog/js/ill-autobackend.js
new file mode 100644
index 0000000000..ac3dfe5892
--- /dev/null
+++ b/koha-tmpl/intranet-tmpl/prog/js/ill-autobackend.js
@@ -0,0 +1,163 @@
+$(document).ready(function () {
+    let auto_ill_el = "#confirmautoill-form #autoillbackends";
+    let auto_ill_message_el = "#confirmautoill-form #autoillbackend-message";
+
+    confirmAutoInit();
+    getBackendsAvailability(auto_backends, metadata);
+
+    /**
+     * Retrieves the backend availability for a given auto backend and metadata.
+     *
+     * @param {Object} auto_backend - The auto backend object.
+     * @param {string} metadata - The metadata string.
+     * @return {Promise} A Promise that resolves to the JSON response.
+     */
+    async function getBackendAvailability(auto_backend, metadata) {
+        return $.ajax({
+            url: auto_backend.endpoint + metadata,
+            type: "GET",
+            dataType: "json",
+            beforeSend: function () {
+                _addBackendPlaceholderEl(auto_backend.name);
+                _addBackendOption(auto_backend.name);
+                _addVerifyingMessage(auto_backend.name);
+                auto_backend.available = 0;
+            },
+            success: function (data) {
+                _addSuccessMessage(auto_backend.name);
+                auto_backend.available = 1;
+            },
+            error: function (request, textstatus) {
+                if (textstatus === "timeout") {
+                    _addErrorMessage(
+                        auto_backend.name,
+                        __("Verification timed out.")
+                    );
+                } else {
+                    let message = "Error";
+                    if (request.hasOwnProperty("responseJSON")) {
+                        if (request.responseJSON.error) {
+                            message = request.responseJSON.error;
+                        } else if (request.responseJSON.errors) {
+                            message = request.responseJSON.errors
+                                .map(error => error.message)
+                                .join(", ");
+                        }
+                    }
+                    _addErrorMessage(auto_backend.name, message);
+                }
+            },
+            timeout: 10000,
+        });
+    }
+
+    /**
+     * Asynchronously checks the availability of multiple auto backends.
+     *
+     * @param {Array} auto_backends - An array of auto backends to check availability for.
+     * @param {Object} metadata - Additional metadata for the availability check.
+     * @return {void}
+     */
+    function getBackendsAvailability(auto_backends, metadata) {
+        let promises = [];
+        for (const auto_backend of auto_backends) {
+            try {
+                const prom = getBackendAvailability(auto_backend, metadata);
+                promises.push(prom);
+            } catch (e) {
+                console.log(e);
+            }
+        }
+        Promise.allSettled(promises).then(() => {
+            let auto_backend = auto_backends.find(backend => backend.available);
+            if (typeof auto_backend === "undefined") {
+                _setAutoBackend("Standard");
+            } else {
+                _setAutoBackend(auto_backend.name);
+            }
+            $('#confirmautoill-form .action input[type="submit"]').prop(
+                "disabled",
+                false
+            );
+        });
+        _addBackendPlaceholderEl("Standard");
+        _addBackendOption("Standard");
+    }
+
+    function _addSuccessMessage(auto_backend_name) {
+        _removeVerifyingMessage(auto_backend_name);
+        $(auto_ill_el + " > #backend-" + auto_backend_name).append(
+            '<span class="text-success"><i class="fa-solid fa-check"></i> ' +
+                __("Available.").format(auto_backend_name) +
+                "</span>"
+        );
+    }
+
+    function _addErrorMessage(auto_backend_name, message) {
+        _removeVerifyingMessage(auto_backend_name);
+        $(auto_ill_el + " > #backend-" + auto_backend_name).append(
+            '<span class="text-danger"> <i class="fa-solid fa-xmark"></i> ' +
+                __("Not readily available:").format(auto_backend_name) +
+                " " +
+                message +
+                "</span>"
+        );
+    }
+
+    function _addBackendOption(auto_backend_name) {
+        $(auto_ill_el + " > #backend-" + auto_backend_name).append(
+            ' <input type="radio" id="' +
+                auto_backend_name +
+                '" name="backend" value="' +
+                auto_backend_name +
+                '">' +
+                ' <label for="' +
+                auto_backend_name +
+                '" class="radio">' +
+                auto_backend_name +
+                "</label> "
+        );
+    }
+
+    function _addVerifyingMessage(auto_backend_name) {
+        $(auto_ill_el + " > #backend-" + auto_backend_name).append(
+            '<span id="verifying-availabilty" class="text-info"><i id="issues-table-load-delay-spinner" class="fa fa-spinner fa-pulse fa-fw"></i> ' +
+                __("Verifying availability...").format(auto_backend_name) +
+                "</span>"
+        );
+    }
+    function _removeVerifyingMessage(auto_backend_name) {
+        $(
+            auto_ill_el +
+                " #backend-" +
+                auto_backend_name +
+                " #verifying-availabilty"
+        ).remove();
+    }
+
+    function _setAutoBackend(auto_backend_name) {
+        $(
+            '#confirmautoill-form #autoillbackends input[id="' +
+                auto_backend_name +
+                '"]'
+        ).prop("checked", true);
+        $(auto_ill_message_el).html(
+            __(
+                "The recommended backend for your request is <strong>%s</strong>."
+            ).format(auto_backend_name)
+        );
+    }
+
+    function _addBackendPlaceholderEl(auto_backend_name) {
+        $(auto_ill_el).append('<div id="backend-' + auto_backend_name + '">');
+    }
+
+    function confirmAutoInit() {
+        $('#confirmautoill-form .action input[name="backend"]').remove();
+        $('#confirmautoill-form .action input[type="submit"]').prop(
+            "disabled",
+            true
+        );
+        $(auto_ill_message_el).html(__("Fetching backends availability..."));
+    }
+});
diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-illrequests.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-illrequests.tt
index 7c6e5da1fa..38abce1e35 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-illrequests.tt
+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-illrequests.tt
@@ -45,6 +45,10 @@
                 [% WRAPPER breadcrumb_item bc_active= 1 %]
                     <span>Ill request disclaimer</span>
                 [% END %]
+            [% ELSIF op == 'confirmautoill' %]
+                [% WRAPPER breadcrumb_item bc_active= 1 %]
+                    <span>Confirm automatic request</span>
+                [% END %]
             [% END %]
         [% ELSE %]
             [% WRAPPER breadcrumb_item bc_active= 1 %]
@@ -121,7 +125,7 @@
                                 <div id="illrequests-create-button" class="dropdown btn-group">
                                     [% IF Koha.Preference('AutoILLBackendPriority') %]
                                         <a id="ill-new" class="btn btn-primary" href="/cgi-bin/koha/opac-illrequests.pl?method=create&amp;backend=Standard">
-                                            <i class="fa fa-plus" aria-hidden="true"></i> Create a new request
+                                            <i class="fa fa-plus" aria-hidden="true"></i> Create a new auto request
                                         </a>
                                     [% ELSIF backends.size > 1 %]
                                         <button class="btn btn-primary dropdown-toggle" type="button" id="ill-backend-dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
@@ -329,6 +333,34 @@
                                     </fieldset>
                                 </form>
                             </div>
+                        [% ELSIF op == 'confirmautoill' %]
+                            <h1>Confirming automatic request</h1>
+                            <div id="results" class="page-section">
+                                <form method="post" id="confirmautoill-form">
+                                    [% INCLUDE 'csrf-token.inc' %]
+                                    <fieldset class="rows">
+                                        <p id="autoillbackends"></p>
+                                        <p id="autoillbackend-message" class="text-info"></p>
+                                    </fieldset>
+                                    <fieldset class="action">
+                                        [% FOREACH key IN whole.keys %]
+                                            [% value = whole.$key %]
+                                            [% IF key != 'custom_key' && key != 'custom_value' && key != 'csrf_token' %]
+                                                <input type="hidden" name="[% key | html %]" value="[% value | html %]">
+                                            [% END %]
+                                        [% END %]
+                                        [% custom_keys = whole.custom_key.split('\0') %]
+                                        [% custom_values = whole.custom_value.split('\0') %]
+                                        [% i = 0 %]
+                                        [% FOREACH custom_key IN custom_keys %]
+                                            <input type="hidden" name="custom_key" value="[% custom_key | html %]">
+                                            <input type="hidden" name="custom_value" value="[% custom_values.$i | html %]">
+                                            [% i = i + 1 %]
+                                        [% END %]
+                                        <input type="hidden" name="confirm_auto_submitted" value="1">
+                                    </fieldset>
+                                </form>
+                            </div>
                         [% END # / IF op == 'cud-create' %]
                     </div> <!-- / #illrequests -->
                 [% END # /IF !backends_available %]
@@ -355,6 +387,11 @@
         [% ELSE %]
             var services = [];
         [% END %]
+        [% IF auto_backends_json.length > 0 %]
+        var auto_backends = [% auto_backends_json | $raw %];
+        [% ELSE %]
+        var auto_backends = [];
+        [% END %]
         [% IF metadata.length > 0 %]
             var metadata = "[% metadata | $raw %]";
         [% END %]
@@ -367,6 +404,9 @@
             });
         </script>
     [% END %]
+    [% IF op == 'confirmautoill' %]
+        [% Asset.js("js/ill-autobackend.js") | $raw %]
+    [% END %]
     [% TRY %]
         [% PROCESS backend_jsinclude %]
     [% CATCH %]
diff --git a/koha-tmpl/opac-tmpl/bootstrap/js/ill-autobackend.js b/koha-tmpl/opac-tmpl/bootstrap/js/ill-autobackend.js
new file mode 100644
index 0000000000..cc25885473
--- /dev/null
+++ b/koha-tmpl/opac-tmpl/bootstrap/js/ill-autobackend.js
@@ -0,0 +1,161 @@
+$(document).ready(function () {
+    let auto_ill_el = "#confirmautoill-form #autoillbackends";
+    let auto_ill_message_el = "#confirmautoill-form #autoillbackend-message";
+
+    confirmAutoInit();
+    getBackendsAvailability(auto_backends, metadata);
+
+    /**
+     * Retrieves the backend availability for a given auto backend and metadata.
+     *
+     * @param {Object} auto_backend - The auto backend object.
+     * @param {string} metadata - The metadata string.
+     * @return {Promise} A Promise that resolves to the JSON response.
+     */
+    async function getBackendAvailability(auto_backend, metadata) {
+        return $.ajax({
+            url: auto_backend.endpoint + metadata,
+            type: "GET",
+            dataType: "json",
+            beforeSend: function () {
+                _addBackendPlaceholderEl(auto_backend.name);
+                _addBackendOption(auto_backend.name);
+                _addVerifyingMessage(auto_backend.name);
+                auto_backend.available = 0;
+            },
+            success: function (data) {
+                _addSuccessMessage(auto_backend.name);
+                auto_backend.available = 1;
+            },
+            error: function (request, textstatus) {
+                if (textstatus === "timeout") {
+                    _addErrorMessage(
+                        auto_backend.name,
+                        __("Verification timed out.")
+                    );
+                } else {
+                    let message = "Error";
+                    if (request.hasOwnProperty("responseJSON")) {
+                        if (request.responseJSON.error) {
+                            message = request.responseJSON.error;
+                        } else if (request.responseJSON.errors) {
+                            message = request.responseJSON.errors
+                                .map(error => error.message)
+                                .join(", ");
+                        }
+                    }
+                    _addErrorMessage(auto_backend.name, message);
+                }
+            },
+            timeout: 10000,
+        });
+    }
+
+    /**
+     * Asynchronously checks the availability of multiple auto backends.
+     *
+     * @param {Array} auto_backends - An array of auto backends to check availability for.
+     * @param {Object} metadata - Additional metadata for the availability check.
+     * @return {void}
+     */
+    function getBackendsAvailability(auto_backends, metadata) {
+        let promises = [];
+        for (const auto_backend of auto_backends) {
+            try {
+                const prom = getBackendAvailability(auto_backend, metadata);
+                promises.push(prom);
+            } catch (e) {
+                console.log(e);
+            }
+        }
+        Promise.allSettled(promises).then(() => {
+            let auto_backend = auto_backends.find(backend => backend.available);
+            if (typeof auto_backend === "undefined") {
+                _setAutoBackend("Standard");
+            } else {
+                _setAutoBackend(auto_backend.name);
+            }
+            $('#confirmautoill-form .action input[type="submit"]').prop(
+                "disabled",
+                false
+            );
+        });
+        _addBackendPlaceholderEl("Standard");
+        _addBackendOption("Standard");
+    }
+
+    function _addSuccessMessage(auto_backend_name) {
+        _removeVerifyingMessage(auto_backend_name);
+        $(auto_ill_el + " > #backend-" + auto_backend_name).append(
+            '<span class="text-success"><i class="fa-solid fa-check"></i> ' +
+                __("Available.").format(auto_backend_name) +
+                "</span>"
+        );
+    }
+
+    function _addErrorMessage(auto_backend_name, message) {
+        _removeVerifyingMessage(auto_backend_name);
+        $(auto_ill_el + " > #backend-" + auto_backend_name).append(
+            '<span class="text-danger"> <i class="fa-solid fa-xmark"></i> ' +
+                __("Not readily available:").format(auto_backend_name) +
+                " " +
+                message +
+                "</span>"
+        );
+    }
+
+    function _addBackendOption(auto_backend_name) {
+        $(auto_ill_el + " > #backend-" + auto_backend_name).append(
+            ' <input type="radio" id="' +
+                auto_backend_name +
+                '" name="backend" value="' +
+                auto_backend_name +
+                '">' +
+                ' <label for="' +
+                auto_backend_name +
+                '" class="radio">' +
+                auto_backend_name +
+                "</label> "
+        );
+    }
+
+    function _addVerifyingMessage(auto_backend_name) {
+        $(auto_ill_el + " > #backend-" + auto_backend_name).append(
+            '<span id="verifying-availabilty" class="text-info"><i id="issues-table-load-delay-spinner" class="fa fa-spinner fa-pulse fa-fw"></i> ' +
+                __("Verifying availability...").format(auto_backend_name) +
+                "</span>"
+        );
+    }
+    function _removeVerifyingMessage(auto_backend_name) {
+        $(
+            auto_ill_el +
+                " #backend-" +
+                auto_backend_name +
+                " #verifying-availabilty"
+        ).remove();
+    }
+
+    function _setAutoBackend(auto_backend_name) {
+        $(
+            '#confirmautoill-form #autoillbackends input[id="' +
+                auto_backend_name +
+                '"]'
+        ).prop("checked", true);
+        $("#confirmautoill-form").submit();
+    }
+
+    function _addBackendPlaceholderEl(auto_backend_name) {
+        $(auto_ill_el)
+            .append('<div id="backend-' + auto_backend_name + '">')
+            .hide();
+    }
+
+    function confirmAutoInit() {
+        $('#confirmautoill-form .action input[name="backend"]').remove();
+        $(auto_ill_message_el).html(
+            '<span id="verifying-availabilty" class="text-info"><i id="issues-table-load-delay-spinner" class="fa fa-spinner fa-pulse fa-fw"></i> ' +
+                __("Placing your request...") +
+                "</span>"
+        );
+    }
+});
diff --git a/opac/opac-illrequests.pl b/opac/opac-illrequests.pl
index 92f3e5e4f6..a7582e0c8a 100755
--- a/opac/opac-illrequests.pl
+++ b/opac/opac-illrequests.pl
@@ -33,6 +33,7 @@ use Koha::ILL::Request;
 use Koha::Libraries;
 use Koha::Patrons;
 use Koha::ILL::Request::Workflow::Availability;
+use Koha::ILL::Request::Workflow::ConfirmAuto;
 use Koha::ILL::Request::Workflow::TypeDisclaimer;
 
 my $query = CGI->new;
@@ -124,6 +125,8 @@ if ( $op eq 'list' ) {
           Koha::ILL::Request::Workflow::Availability->new( $params, 'opac' );
         my $type_disclaimer =
           Koha::ILL::Request::Workflow::TypeDisclaimer->new( $params, 'opac' );
+        my $confirm_auto =
+          Koha::ILL::Request::Workflow::ConfirmAuto->new( $params, 'opac' );
 
         # ILLCheckAvailability operation
         if ($availability->show_availability($request)) {
@@ -145,6 +148,16 @@ if ( $op eq 'list' ) {
                 $template->output, undef,
                 { force_no_caching => 1 };
             exit;
+        # ConfirmAuto operation
+        } elsif ( $confirm_auto->show_confirm_auto($request)) {
+            $op = 'confirmautoill';
+            $template->param(
+                $confirm_auto->confirm_auto_template_params($params)
+            );
+            output_html_with_http_headers $query, $cookie,
+                $template->output, undef,
+                { force_no_caching => 1 };
+            exit;
         }
 
         my $patron = Koha::Patrons->find( { borrowernumber => $loggedinuser } );
-- 
2.39.2