From e3dd3cc1ecdcf78d847813aad0a98d7a22bb2d50 Mon Sep 17 00:00:00 2001
From: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Date: Fri, 16 Jun 2023 12:34:59 +0200
Subject: [PATCH] Bug 34030: Add a "print slips" action links to print in batch

Sponsored-by: BULAC - http://www.bulac.fr/

Signed-off-by: BULAC - http://www.bulac.fr/
Signed-off-by: Heather Hernandez <heather_hernandez@nps.gov>
Signed-off-by: Laurence Rault <laurence.rault@biblibre.com>
---
 koha-tmpl/intranet-tmpl/prog/css/print.css    |  4 +
 .../prog/en/modules/circ/printslip.tt         | 12 ++-
 .../components/Preservation/TrainsShow.vue    | 95 ++++++++++++++++++-
 preservation/print_slip.pl                    | 43 ++++-----
 4 files changed, 122 insertions(+), 32 deletions(-)

diff --git a/koha-tmpl/intranet-tmpl/prog/css/print.css b/koha-tmpl/intranet-tmpl/prog/css/print.css
index b1cbc010b6b..2a914e657f9 100644
--- a/koha-tmpl/intranet-tmpl/prog/css/print.css
+++ b/koha-tmpl/intranet-tmpl/prog/css/print.css
@@ -1,3 +1,7 @@
+@media print {
+    .pagebreak { break-after: page; }
+}
+
 a:link {
 	color : #000000;
 	text-decoration: none;
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt
index e75a25b6be8..ab07dbf4a3b 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt
@@ -26,12 +26,18 @@
 <body id="circ_printslip" class="circ">
 <div id="receipt">
 
-[% IF plain %]
+[% UNLESS slips && slips.size %]
+    [% SET slips = [{content => slip, is_html => !plain}] %]
+[% END %]
+[% FOR slip IN slips %]
+[% UNLESS slip.is_html %]
 <pre>
-[% IF ( slip ) %][% slip | html %][% ELSE %]No slip template found[% END %]
+[% IF ( slip.content ) %][% slip.content | html %][% ELSE %]No slip template found[% END %]
 </pre>
 [% ELSE %]
-[% IF ( slip ) %][% slip | $raw %][% ELSE %]No slip template found[% END %]
+[% IF ( slip.content ) %][% slip.content | $raw %][% ELSE %]No slip template found[% END %]
+[% END %]
+[% IF slips.size > 1 && !loop.last%]<div class="pagebreak"></div>[% END %]
 [% END %]
 
 [% INCLUDE 'intranet-bottom.inc' %]
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/TrainsShow.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/TrainsShow.vue
index 82e60debc87..0524262539e 100644
--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/TrainsShow.vue
+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/TrainsShow.vue
@@ -153,6 +153,27 @@
             </fieldset>
             <fieldset v-if="train.items.length" class="rows">
                 <legend>{{ $__("Items") }}</legend>
+                <span class="action_links">
+                    <a
+                        role="link"
+                        @click="selectAll()"
+                        :title="$__('Select all')"
+                        ><i class="fa fa-check"></i>{{ $__("Select all") }}</a
+                    >
+                    <a @click="clearAll()" :title="$__('Clear all')"
+                        ><i class="fa fa-remove"></i>{{ $__("Clear all") }}</a
+                    >
+                    {{ $__("Actions: ") }}
+                    <a
+                        v-if="selected_items.length > 0"
+                        @click="printSelected()"
+                        :title="$__('Print slips')"
+                        ><i class="fa fa-print"></i>{{ $__("Print slips") }}</a
+                    >
+                    <a v-else class="disabled" :title="$__('Print slips')"
+                        ><i class="fa fa-print"></i>{{ $__("Print slips") }}</a
+                    >
+                </span>
                 <table v-if="item_table.display" :id="table_id"></table>
                 <ol v-else>
                     <li
@@ -268,6 +289,7 @@ export default {
             train_list: [],
             train_id_selected_for_copy: null,
             train_item_id_to_copy: null,
+            selected_items: [],
             av_options: {},
         }
     },
@@ -309,11 +331,21 @@ export default {
                             this.item_table.data.push(item_row)
                         })
                         this.item_table.columns = []
-                        this.item_table.columns.push({
-                            name: "",
-                            title: this.$__("ID"),
-                            data: "item.user_train_item_id",
-                        })
+                        this.item_table.columns.push(
+                            {
+                                name: "checkboxes",
+                                className: "checkboxes",
+                                width: "5%",
+                                render: (data, type, row) => {
+                                    return ""
+                                },
+                            },
+                            {
+                                name: "",
+                                title: this.$__("ID"),
+                                data: "item.user_train_item_id",
+                            }
+                        )
                         train.default_processing.attributes.forEach(a =>
                             this.item_table.columns.push({
                                 name: a.name,
@@ -478,6 +510,38 @@ export default {
                     }
                 )
         },
+        clearAll() {
+            this.selected_items = []
+            $("#" + this.table_id)
+                .find("input[name='user_train_item_id'][type='checkbox']")
+                .prop("checked", false)
+        },
+        selectAll() {
+            $("#" + this.table_id)
+                .find("input[name='user_train_item_id'][type='checkbox']")
+                .each((i, input) => {
+                    this.selected_items.push($(input).val())
+                    $(input).prop("checked", true)
+                })
+        },
+        printSelected() {
+            window.open(
+                "/cgi-bin/koha/preservation/print_slip.pl?%s_blank".format(
+                    this.selected_items
+                        .map(id => "train_item_id=" + id)
+                        .join("&")
+                )
+            )
+        },
+        updateSelectedItems(checked, train_item_id) {
+            if (checked) {
+                this.selected_items.push(train_item_id)
+            } else {
+                this.selected_items = this.selected_items.filter(
+                    id => id != train_item_id
+                )
+            }
+        },
         build_datatable: function () {
             let table_id = this.table_id
             let item_table = this.item_table
@@ -486,6 +550,7 @@ export default {
             let printSlip = this.printSlip
             let selectTrainForCopy = this.selectTrainForCopy
             let train = this.train
+            let updateSelectedItems = this.updateSelectedItems
 
             let table = KohaTable(table_id, {
                 data: item_table.data,
@@ -494,6 +559,25 @@ export default {
                 columns: item_table.columns,
                 drawCallback: function (settings) {
                     var api = new $.fn.dataTable.Api(settings)
+                    $.each($(this).find("td.checkboxes"), function (index, e) {
+                        let tr = $(this).parent()
+                        let train_item = api.row(tr).data().item
+                        let train_item_id = train_item.train_item_id
+
+                        let checkbox = createVNode("input", {
+                            type: "checkbox",
+                            name: "user_train_item_id",
+                            value: train_item_id,
+                            onChange: e => {
+                                updateSelectedItems(
+                                    e.target.checked,
+                                    train_item_id
+                                )
+                            },
+                        })
+
+                        render(checkbox, e)
+                    })
                     $.each($(this).find("td.actions"), function (index, e) {
                         let tr = $(this).parent()
                         let train_item = api.row(tr).data().item
@@ -599,6 +683,7 @@ export default {
 .action_links a {
     padding-left: 0.2em;
     font-size: 11px;
+    cursor: pointer;
 }
 .attributes_values {
     float: left;
diff --git a/preservation/print_slip.pl b/preservation/print_slip.pl
index ec3687ba0f1..b6daf50993a 100755
--- a/preservation/print_slip.pl
+++ b/preservation/print_slip.pl
@@ -26,7 +26,7 @@ use Koha::Patrons;
 use Koha::Preservation::Train::Items;
 
 my $input = CGI->new;
-my $train_item_id = $input->param('train_item_id');
+my @train_item_ids = $input->multi_param('train_item_id');
 
 my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
     {
@@ -40,32 +40,27 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
 my $logged_in_user = Koha::Patrons->find($loggedinuser);
 my $branch = C4::Context->userenv->{'branch'};
 
-my $train_item = Koha::Preservation::Train::Items->find($train_item_id);
-
-unless ($train_item){
-    print $input->redirect("/cgi-bin/koha/errors/404.pl");
-    exit;
+my @slips;
+for my $train_item_id ( @train_item_ids ) {
+    my $train_item = Koha::Preservation::Train::Items->find($train_item_id);
+    my $letter = C4::Letters::GetPreparedLetter(
+        module      => 'preservation',
+        letter_code => $train_item->processing->letter_code,
+        branchcode  => $branch,
+        lang        => $logged_in_user->lang,
+        tables      => {
+            preservation_train_items => $train_item_id,
+        },
+        message_transport_type => 'print'
+    );
+    push @slips, {
+        content => $letter->{content},
+        is_html => $letter->{is_html},
+    };
 }
 
-my $train = $train_item->train;
-
-my $letter = C4::Letters::GetPreparedLetter(
-    module      => 'preservation',
-    letter_code => $train_item->processing->letter_code,
-    branchcode  => $branch,
-    lang        => $logged_in_user->lang,
-    tables      => {
-        preservation_train_items => $train_item_id,
-    },
-    message_transport_type => 'print'
-);
-
-my $slip    = $letter->{content};
-my $is_html = $letter->{is_html};
-
 $template->param(
-    slip => $slip,
-    plain => !$is_html,
+    slips => \@slips,
     caller => 'preservation',
     stylesheet => C4::Context->preference("SlipCSS"),
 );
-- 
2.25.1