From 7f3e66d67c4c2595a73d41c24072ed2d16f4c8fa Mon Sep 17 00:00:00 2001
From: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Date: Tue, 19 Oct 2021 13:57:00 +0100
Subject: [PATCH] Bug 33736: Add pendingbookings report

This patch adds a 'Bookings to collect' page to circulation that allows
for a workflow similar to 'Holds to pull', but for bookings.

NOTE: Refinements still required
---
 api/v1/swagger/paths/bookings.yaml            |   4 +
 circ/pendingbookings.pl                       |  49 ++++
 .../prog/en/modules/circ/circulation-home.tt  |   5 +-
 .../prog/en/modules/circ/pendingbookings.tt   | 209 ++++++++++++++++++
 4 files changed, 266 insertions(+), 1 deletion(-)
 create mode 100755 circ/pendingbookings.pl
 create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingbookings.tt

diff --git a/api/v1/swagger/paths/bookings.yaml b/api/v1/swagger/paths/bookings.yaml
index f1dcb9f9be9..68e5218c18b 100644
--- a/api/v1/swagger/paths/bookings.yaml
+++ b/api/v1/swagger/paths/bookings.yaml
@@ -74,6 +74,10 @@
     x-koha-authorization:
       permissions:
         catalogue: 1
+    x-koha-embed:
+      - biblio
+      - item
+      - patron
   post:
     operationId: addBooking
     parameters:
diff --git a/circ/pendingbookings.pl b/circ/pendingbookings.pl
new file mode 100755
index 00000000000..45a9a2605e7
--- /dev/null
+++ b/circ/pendingbookings.pl
@@ -0,0 +1,49 @@
+#!/usr/bin/perl
+
+# Copyright PTFS Europe 2021
+#
+# 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 CGI qw ( -utf8 );
+
+use C4::Output qw( output_html_with_http_headers );
+use C4::Auth qw( get_template_and_user );
+
+use Koha::DateUtils qw(dt_from_string);
+
+my $input = CGI->new;
+my ( $template, $borrowernumber, $cookie, $flags ) = get_template_and_user(
+    {
+        template_name => "circ/pendingbookings.tt",
+        query         => $input,
+        type          => "intranet",
+        flagsrequired => { circulate => 'manage_bookings' },
+    }
+);
+
+my $today = dt_from_string();
+my $startdate = $today->truncate( to => 'day' );
+my $enddate = $startdate->clone->add( days => 1 );
+
+$template->param(
+    todaysdate          => $today,
+    from                => $startdate,
+    to                  => $enddate
+);
+
+output_html_with_http_headers $input, $cookie, $template->output;
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation-home.tt
index cec04724898..530b25f48b0 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation-home.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation-home.tt
@@ -75,7 +75,7 @@
             </div>
 
             <div class="col-sm-5 col-md-4">
-                <h3>Holds</h3>
+                <h3>Holds & Bookings</h3>
 
                 <ul class="buttons-list">
                     <li>
@@ -95,6 +95,9 @@
                     <li>
                         <a class="circ-button" href="/cgi-bin/koha/circ/reserveratios.pl"><i class="fa-solid fa-chart-line"></i> Hold ratios</a>
                     </li>
+                    <li>
+                        <a class="circ-button" href="/cgi-bin/koha/circ/pendingbookings.pl"><i class="fa fa-hand-grab-o"></i> Bookings to collect</a>
+                    </li>
                 </ul>
 
                 [% IF Koha.Preference('UseRecalls') and CAN_user_recalls %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingbookings.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingbookings.tt
new file mode 100644
index 00000000000..11cb47241fb
--- /dev/null
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingbookings.tt
@@ -0,0 +1,209 @@
+[% USE raw %]
+[% USE Asset %]
+[% USE Koha %]
+[% USE KohaDates %]
+[% USE TablesSettings %]
+[% PROCESS 'i18n.inc' %]
+[% SET footerjs = 1 %]
+[% INCLUDE 'doc-head-open.inc' %]
+<title>[% FILTER collapse %]
+    [% t("Bookings to collect") | html %] &rsaquo;
+    [% t("Circulation") | html %] &rsaquo;
+    [% t("Koha") | html %]
+[% END %]</title>
+[% INCLUDE 'doc-head-close.inc' %]
+</head>
+
+<body id="circ_pendingbookings" class="circ">
+    [% INCLUDE 'header.inc' %]
+    [% INCLUDE 'circ-search.inc' %]
+
+    <nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
+        <ol>
+            <li>
+                <a href="/cgi-bin/koha/mainpage.pl">Home</a>
+            </li>
+            <li>
+                <a href="/cgi-bin/koha/circ/circulation-home.pl">Circulation</a>
+            </li>
+            <li>
+                <a href="#" aria-current="page">
+                Bookings to collect
+            </a>
+            </li>
+        </ol>
+    </nav>
+
+    <div class="main container-fluid">
+        <div class="row">
+
+            <!-- Results -->
+            <div class="col-sm-10 col-sm-push-2">
+                <main>
+                    <h2>Items required for bookings between <span id="from_date">[% from | $KohaDates %]</span> and <span id="to_date">[% to | $KohaDates %]</span></h2>
+                    <h3>Reported on [% todaysdate | $KohaDates %]</h3>
+                    <p>The following items have not been collected for bookings. Please retrieve them
+                        and check them in.</p>
+                    <div id="searchresults">
+                        <table id="bookingst"></table>
+                    </div>
+                </main>
+            </div>
+
+            <!-- Filters -->
+            <div class="col-sm-2 col-sm-pull-10">
+                <aside>
+                    <div id="filters">
+                        <form id="bookingsf">
+                            <fieldset class="brief">
+                                <h4>Refine results</h4>
+                                <ol>
+                                    <li>
+                                        <label for="from">Start date: </label>
+                                        <input type="text" size="10" id="from" name="from" value="[% from | html %]" class="flatpickr" data-date_to="to"/>
+                                    </li>
+                                    <li>
+                                        <label for="to">End date: </label>
+                                        <input type="text" size="10" id="to" name="to" value="[% to | html %]" class="flatpickr"/>
+                                    </li>
+                                </ol>
+
+                                <fieldset class="action">
+                                    <input type="submit" name="run_report" value="Submit" class="submit"/>
+                                </fieldset>
+                            </fieldset>
+                        </form>
+                    </div>
+                </aside>
+            </div>
+        </div>
+        <!-- /.row -->
+
+        [% MACRO jsinclude BLOCK %]
+        [% INCLUDE 'calendar.inc' %]
+        [% INCLUDE 'datatables.inc' %]
+        [% INCLUDE 'columns_settings.inc' %]
+        [% Asset.js("lib/jquery/plugins/jquery.dataTables.columnFilter.js") | $raw %]
+        [% INCLUDE 'js-biblio-format.inc' %]
+        [% INCLUDE 'js-date-format.inc' %]
+        [% INCLUDE 'js-patron-format.inc' %]
+        <script>
+            let table_settings = [% TablesSettings.GetTableSettings( 'circ', 'bookings', 'bookings-to-collect', 'json' ) | $raw %];
+            $(document).ready(function() {
+
+                let additional_filters = {
+                    start_date: function() {
+                       let fromdate = $("#from");
+                       let isoFrom;
+                       if ( fromdate.val() !== '' ) {
+                         isoFrom = fromdate.get(0)._flatpickr.selectedDates[0].toISOString().substring(0,10);
+                       }
+
+                       let todate = $("#to");
+                       let isoTo;
+                       if ( todate.val() !== '' ) {
+                         isoTo = todate.get(0)._flatpickr.selectedDates[0].toISOString().substring(0,10);
+                       }
+
+                       return { '>=': isoFrom, '<=': isoTo };
+                    }
+                };
+
+                var bookings_table_url = '/api/v1/bookings?';
+                var bookings_table = $("#bookingst").kohaTable({
+                    "ajax": {
+                        "url": bookings_table_url
+                    },
+                    "embed": [
+                        "biblio",
+                        "item",
+                        "patron"
+                    ],
+                    "order": [[ 1, "asc" ]],
+                    "columns": [{
+                        "data": "booking_id",
+                        "title": "Booking ID",
+                        "visible": false
+                    },
+                    {
+                        "data": "biblio.title",
+                        "title": "Title",
+                        "searchable": true,
+                        "orderable": true,
+                        "render": function(data,type,row,meta) {
+                            return $biblio_to_html(row.biblio, {
+                                link: 'bookings'
+                            });
+                        }
+                    },
+                    {
+                        "data": "item.external_id",
+                        "title": "Item",
+                        "searchable": true,
+                        "orderable": true,
+                        "defaultContent": "Any item",
+                        "render": function(data,type,row,meta) {
+                            if ( row.item ) {
+                                return row.item.external_id + " (" + row.booking_id + ")";
+                            } else {
+                                return null;
+                            }
+                        }
+                    },
+                    {
+                        "data": "item.callnumber",
+                        "title": "Callnumber",
+                        "searchable": true,
+                        "orderable": true,
+                        "render": function(data,type,row,meta) {
+                            if ( row.item ) {
+                                return row.item.callnumber;
+                            } else {
+                                return null;
+                            }
+                        }
+                    },
+                    {
+                        "data": "patron.firstname:patron.surname",
+                        "title": "Patron",
+                        "searchable": true,
+                        "orderable": true,
+                        "render": function(data, type, row, meta) {
+                            return $patron_to_html(row.patron, {
+                                display_cardnumber: true,
+                                url: true
+                            });
+                        }
+                    },
+                    {
+                        "data": "start_date",
+                        "name": "start_date",
+                        "title": "Booking dates",
+                        "type": "date",
+                        "searchable": false,
+                        "orderable": true,
+                        "render": function(data, type, row, meta) {
+                            return $date(row.start_date) + ' - ' + $date(row.end_date);
+                        }
+                    },
+                    {
+                        "name": "actions",
+                        "title": "Actions",
+                        "searchable": false,
+                        "orderable": false,
+                        "render": function(data,type,row,meta){
+                            return "";
+                        }
+                    }]
+                }, table_settings, 1, additional_filters);
+
+                /** Date filtering */
+                $("#bookingsf").on("submit", function(e){
+                    /* stop form from submitting normally */
+                    e.preventDefault();
+                    bookings_table.DataTable().draw();
+                });
+            });
+        </script>
+        [% END %]
+        [% INCLUDE 'intranet-bottom.inc' %]
-- 
2.43.0