Bugzilla – Attachment 101000 Details for
Bug 24846
Add a tool to enable bulk edit of due dates
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 24846: Add new tool to batch extend due dates
Bug-24846-Add-new-tool-to-batch-extend-due-dates.patch (text/plain), 20.73 KB, created by
Martin Renvoize (ashimema)
on 2020-03-19 08:50:46 UTC
(
hide
)
Description:
Bug 24846: Add new tool to batch extend due dates
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2020-03-19 08:50:46 UTC
Size:
20.73 KB
patch
obsolete
>From 56ef9e753acae06347b31ca3c84a964767c52f06 Mon Sep 17 00:00:00 2001 >From: Jonathan Druart <jonathan.druart@bugs.koha-community.org> >Date: Mon, 16 Mar 2020 11:45:44 +0100 >Subject: [PATCH] Bug 24846: Add new tool to batch extend due dates > >With events sometimes leading to unforeseen branch closures (think Coronavirus as >an example), it would be helpful to have a tool that would allow librarians to >update due dates in bulk based on branch and current due date of the material. > >It allows to select checkouts given the following parameters: > * libraries > * patron's categories > * range of the due date > >You can set a hard due date, or define a number of days to extend the >due date. > >Test plan: >Check some items out >Use the new tool to extend the due dates >Test the different filters to make sure they all work > >Note: What about holidays? > >Signed-off-by: Bernardo Gonzalez Kriegel <bgkriegel@gmail.com> >Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com> >--- > .../modules/tools/batch_extend_due_dates.tt | 269 ++++++++++++++++++ > tools/batch_extend_due_dates.pl | 145 ++++++++++ > 2 files changed, 414 insertions(+) > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_extend_due_dates.tt > create mode 100755 tools/batch_extend_due_dates.pl > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_extend_due_dates.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_extend_due_dates.tt >new file mode 100644 >index 0000000000..1286337220 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batch_extend_due_dates.tt >@@ -0,0 +1,269 @@ >+[% USE raw %] >+[% USE Asset %] >+[% SET footerjs = 1 %] >+[% USE Branches %] >+[% USE Categories %] >+[% USE KohaDates %] >+[% USE ItemTypes %] >+[% PROCESS 'html_helpers.inc' %] >+ >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Tools › Batch extend due dates</title> >+[% INCLUDE 'doc-head-close.inc' %] >+[% Asset.css("css/humanmsg.css") | $raw %] >+</head> >+ >+<body id="tools_batch_extend_due_dates" class="tools"> >+ [% INCLUDE 'header.inc' %] >+ [% INCLUDE 'cat-search.inc' %] >+ >+ <div id="breadcrumbs"> >+ <a href="/cgi-bin/koha/mainpage.pl">Home</a> › >+ <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> › >+ <a href="/cgi-bin/koha/tools/batch_extend_due_dates.pl">Batch extend due dates</a> >+ </div> >+ >+ <div class="main container-fluid"> >+ <div class="row"> >+ <div class="col-sm-10 col-sm-push-2"> >+ <main> >+ >+ <h1>Batch extend due dates</h1> >+ >+ [% IF ( messages ) %] >+ <div class="dialog message"> >+ >+ [% FOREACH message IN messages %] >+ [% IF message.type == 'success' %] >+ <div><i class="fa fa-check success"></i> >+ [% ELSIF message.type == 'warning' %] >+ <div><i class="fa fa-warning warn"></i> >+ [% ELSIF message.type == 'error' %] >+ <div><i class="fa fa-exclamation error"></i> >+ [% END %] >+ [% IF message.error %] >+ (The error was: [% message.error | html %]. See the Koha logfile for more information). >+ [% END %] >+ </div> >+ [% END %] >+ >+ </div> <!-- .dialog.message --> >+ [% END %] >+ >+ [% IF view == 'form' %] >+ <form method="post" enctype="multipart/form-data" action="/cgi-bin/koha/tools/batch_extend_due_dates.pl" id="extend_due_dates_form"> >+ <fieldset class="rows"> >+ <legend>Checkout criteria:</legend> >+ <ol> >+ <li> >+ <label for="categorycodes">Patrons' categories: </label> >+ [% SET categories = Categories.all() %] >+ <select id="categorycodes" name="categorycodes" multiple="multiple"> >+ [% FOREACH cat IN categories %] >+ <option value="[% cat.categorycode | html %]">[% cat.description | html %]</option> >+ [% END %] >+ </select> >+ </li> >+ >+ <li> >+ <label for="branchcodes">Libraries: </label> >+ <select name="branchcodes" id="branchcodes" multiple="multiple"> >+ [% PROCESS options_for_libraries libraries => Branches.all() %] >+ </select> >+ </li> >+ >+ <li> >+ <label for="from_due_date">Due date from: </label> >+ <input type="text" size="10" id="from" name="from_due_date" class="datepickerfrom" /> >+ </li> >+ >+ <li> >+ <label for="to_due_date">Due date to:</label> >+ <input type="text" size="10" id="to" name="to_due_date" class="datepickerto" /> >+ </li> >+ </ol> >+ </fieldset> >+ <fieldset class="rows"> >+ <legend>New due date:</legend> >+ <ol> >+ <li> >+ <label for="new_hard_due_date">Hard due date: </label> >+ <input type="text" size="10" id="new_hard_due_date" name="new_hard_due_date" class="datepicker" /> >+ </li> >+ >+ <li> >+ <label for="due_date_days">Or add number of days:</label> >+ <input type="text" size="10" id="due_date_days" name="due_date_days"/> >+ </li> >+ </ol> >+ </fieldset> >+ <fieldset class="action"> >+ <input type="hidden" name="op" value="list" /> >+ <input type="submit" value="Continue" class="button" /> >+ <a class="cancel" href="/cgi-bin/koha/tools/tools-home.pl">Cancel</a> >+ </fieldset> >+ </form> <!-- /#extend_due_dates_form --> >+ [% ELSIF view == 'list' %] >+ [% IF checkouts.count %] >+ <form action="/cgi-bin/koha/tools/batch_extend_due_dates.pl" method="post" id="process"> >+ <div id="toolbar"> >+ <a id="selectall" href="#"><i class="fa fa-check"></i> Select all</a> >+ | <a id="clearall" href="#"><i class="fa fa-remove"></i> Clear all</a> >+ </div> >+ <table id="checkouts"> >+ <thead> >+ <tr> >+ <th> </th> >+ <th>Due date</th> >+ <th>Title</th> >+ <th>Item type</th> >+ <th>Home library</th> >+ <th>Checked out on</th> >+ <th>Checked out from</th> >+ <th>New due date</th> >+ </tr> >+ </thead> >+ <tbody> >+ [% FOR checkout IN checkouts %] >+ <tr> >+ <td><input type="checkbox" name="issue_id" value="[% checkout.issue_id | html %]" /></td> >+ <td>[% checkout.date_due | $KohaDates as_due_date => 1 %]</td> >+ <td><a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% checkout.item.biblio.biblionumber | uri %]">[% checkout.item.biblio.title | html %]</a></td> >+ <td>[% ItemTypes.GetDescription( checkout.item.effective_itemtype ) | html %]</td> >+ <td>[% checkout.item.home_branch.branchname | html %]</td> >+ <td>[% checkout.issuedate | $KohaDates %]</td> >+ <td>[% Branches.GetName( checkout.branchcode ) | html %]</td> >+ <td> >+ [% IF new_hard_due_date %] >+ [% new_hard_due_date | $KohaDates %] >+ [% ELSE %] >+ [% new_due_dates.shift | $KohaDates %] >+ [% END %] >+ </td> >+ </tr> >+ [% END %] >+ </tbody> >+ </table> <!-- /#checkouts --> >+ <div class="note"><i class="fa fa-exclamation"></i> Reminder: this action will modify all selected checkouts!</div> >+ <fieldset class="action"> >+ <input type="hidden" name="op" value="modify" /> >+ <input type="hidden" name="new_hard_due_date" value="[% new_hard_due_date | $KohaDates %]" /> >+ <input type="hidden" name="due_date_days" value="[% due_date_days | html %]" /> >+ <input type="submit" value="Modify selected checkouts" class="button" /> >+ <a class="cancel" href="/cgi-bin/koha/tools/batch_extend_due_dates.pl">Cancel</a> >+ </fieldset> >+ </form> <!-- /#process --> >+ [% ELSE %] >+ <div class="dialog message"> >+ No checkouts for the selected filters. >+ </div> >+ [% END %] >+ [% ELSIF view == 'report' %] >+ <div class="dialog message"> >+ Due dates have been modified! >+ </div> >+ >+ <table id="checkouts_result"> >+ <thead> >+ <tr> >+ <th>Due date</th> >+ <th>Title</th> >+ <th>Item type</th> >+ <th>Home library</th> >+ <th>Checked out on</th> >+ <th>Checked out from</th> >+ </tr> >+ </thead> >+ <tbody> >+ [% FOR checkout IN checkouts %] >+ <tr> >+ <td>[% checkout.date_due | $KohaDates as_due_date => 1 %]</td> >+ <td><a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% checkout.item.biblio.biblionumber | uri %]">[% checkout.item.biblio.title | html %]</a></td> >+ <td>[% ItemTypes.GetDescription( checkout.item.effective_itemtype ) | html %]</td> >+ <td>[% checkout.item.home_branch.branchname | html %]</td> >+ <td>[% checkout.issuedate | $KohaDates %]</td> >+ <td>[% Branches.GetName( checkout.branchcode ) | html %]</td> >+ </tr> >+ [% END %] >+ </tbody> >+ </table> <!-- /#checkouts_result --> >+ [% END %] >+ </main> >+ </div> <!-- /.col-sm-10.col-sm-push-2 --> >+ >+ <div class="col-sm-2 col-sm-pull-10"> >+ <aside> >+ [% INCLUDE 'tools-menu.inc' %] >+ </aside> >+ </div> <!-- /.col-sm-2.col-sm-pull-10 --> >+ </div> <!-- /.row --> >+ >+[% MACRO jsinclude BLOCK %] >+ [% Asset.js("js/tools-menu.js") | $raw %] >+ [% INCLUDE 'calendar.inc' %] >+ [% INCLUDE 'datatables.inc' %] >+ [% Asset.js("lib/jquery/plugins/jquery.checkboxes.min.js") | $raw %] >+ [% Asset.js("lib/jquery/plugins/humanmsg.js") | $raw %] >+ <script> >+ $(document).ready(function() { >+ >+ $("#selectall").click(function(e) { >+ e.preventDefault(); >+ $("#checkouts").checkCheckboxes(); >+ }); >+ $("#clearall").click(function(e) { >+ e.preventDefault(); >+ $("#checkouts").unCheckCheckboxes(); >+ }); >+ $("#selectall").click(); >+ >+ $("table#checkouts").dataTable($.extend(true, {}, dataTablesDefaults, { >+ "aoColumnDefs": [ >+ { "aTargets": [0, 3], "bSortable": false, "bSearchable": false }, >+ { "aTargets": [1], "sType": "num-html" } >+ ], >+ "sDom": 't', >+ "aaSorting": [], >+ "bPaginate": false >+ })); >+ >+ $("table#checkouts_result").dataTable($.extend(true, {}, dataTablesDefaults, { >+ "aoColumnDefs": [ >+ { "aTargets": [0, 3], "bSortable": false, "bSearchable": false }, >+ { "aTargets": [1], "sType": "num-html" } >+ ], >+ "sDom": 't', >+ "aaSorting": [], >+ "bPaginate": false >+ })); >+ >+ $("#extend_due_dates_form").on('submit', function(e) { >+ var new_hard_due_date = $("#new_hard_due_date").val(); >+ var due_date_days = $("#due_date_days").val(); >+ if (new_hard_due_date && due_date_days ) { >+ e.preventDefault(); >+ alert(_("You must fill only one of the two due date options")); >+ return false; >+ } else if ( !new_hard_due_date && !due_date_days ) { >+ e.preventDefault(); >+ alert(_("You must fill at least one of the two due date options")); >+ return false; >+ } >+ >+ return true; >+ }); >+ >+ $("#process").on('submit', function(e) { >+ if ($("input[type=checkbox][name='issue_id']:checked").length == 0) { >+ e.preventDefault(); >+ alert(_("Please select at least one checkout to process")); >+ return false; >+ } >+ return true; >+ }); >+ >+ }); >+ </script> >+[% END %] >+ >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/tools/batch_extend_due_dates.pl b/tools/batch_extend_due_dates.pl >new file mode 100755 >index 0000000000..5f0001df1c >--- /dev/null >+++ b/tools/batch_extend_due_dates.pl >@@ -0,0 +1,145 @@ >+#!/usr/bin/perl >+ >+# This file is part of Koha. >+# >+# Copyright 2020 Koha Development Team >+# >+# 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; >+ >+use C4::Auth qw( get_template_and_user ); >+use C4::Output qw( output_html_with_http_headers ); >+use Koha::Checkouts; >+use Koha::DateUtils qw( dt_from_string ); >+ >+my $input = new CGI; >+my $op = $input->param('op') // q|form|; >+ >+my ( $template, $loggedinuser, $cookie ) = get_template_and_user( >+ { >+ template_name => 'tools/batch_extend_due_dates.tt', >+ query => $input, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { tools => 'batch_extend_due_dates' }, >+ } >+); >+ >+if ( $op eq 'form' ) { >+ $template->param( view => 'form', ); >+} >+elsif ( $op eq 'list' ) { >+ >+ my @categorycodes = $input->multi_param('categorycodes'); >+ my @branchcodes = $input->multi_param('branchcodes'); >+ my $from_due_date = $input->param('from_due_date'); >+ my $to_due_date = $input->param('to_due_date'); >+ my $new_hard_due_date = $input->param('new_hard_due_date'); >+ my $due_date_days = $input->param('due_date_days'); >+ >+ my $dtf = Koha::Database->new->schema->storage->datetime_parser; >+ my $search_params; >+ if (@categorycodes) { >+ $search_params->{'borrower.categorycode'} = { -in => \@categorycodes }; >+ } >+ if (@branchcodes) { >+ $search_params->{'me.branchcode'} = { -in => \@branchcodes }; >+ } >+ if ( $from_due_date and $to_due_date ) { >+ my $to_due_date_endday = dt_from_string($to_due_date); >+ $to_due_date_endday >+ ->set( # We set last second of day to see all checkouts from that day >+ hour => 23, >+ minute => 59, >+ second => 59 >+ ); >+ $search_params->{'me.date_due'} = { >+ -between => [ >+ $dtf->format_datetime( dt_from_string($from_due_date) ), >+ $dtf->format_datetime($to_due_date_endday), >+ ] >+ }; >+ } >+ elsif ($from_due_date) { >+ $search_params->{'me.date_due'} = >+ { '>=' => $dtf->format_datetime( dt_from_string($from_due_date) ) }; >+ } >+ elsif ($to_due_date) { >+ my $to_due_date_endday = dt_from_string($to_due_date); >+ $to_due_date_endday >+ ->set( # We set last second of day to see all checkouts from that day >+ hour => 23, >+ minute => 59, >+ second => 59 >+ ); >+ $search_params->{'me.date_due'} = >+ { '<=' => $dtf->format_datetime($to_due_date_endday) }; >+ } >+ >+ my $checkouts = Koha::Checkouts->search( >+ $search_params, >+ { >+ join => [ 'item', 'borrower' ] >+ } >+ ); >+ >+ my @new_due_dates; >+ if ( not $new_hard_due_date && $due_date_days ) { >+ while ( my $checkout = $checkouts->next ) { >+ my $due_date = dt_from_string( $checkout->date_due ); >+ push @new_due_dates, $due_date->add( days => $due_date_days ); >+ } >+ } >+ $template->param( >+ checkouts => $checkouts, >+ new_hard_due_date => $new_hard_due_date >+ ? dt_from_string($new_hard_due_date) >+ : undef, >+ due_date_days => $due_date_days, >+ new_due_dates => \@new_due_dates, >+ view => 'list', >+ ); >+} >+elsif ( $op eq 'modify' ) { >+ >+ # We want to modify selected checkouts! >+ my @issue_ids = $input->multi_param('issue_id'); >+ my $new_hard_due_date = $input->param('new_hard_due_date'); >+ my $due_date_days = $input->param('due_date_days'); >+ >+ $new_hard_due_date &&= dt_from_string($new_hard_due_date); >+ my $checkouts = >+ Koha::Checkouts->search( { issue_id => { -in => \@issue_ids } } ); >+ while ( my $checkout = $checkouts->next ) { >+ if ($new_hard_due_date) { >+ $checkout->date_due($new_hard_due_date)->store; >+ } >+ else { >+ my $dt = dt_from_string( $checkout->date_due ) >+ ->add( days => $due_date_days ); >+ $checkout->date_due($dt)->store; >+ } >+ } >+ >+ $template->param( >+ view => 'report', >+ checkouts => $checkouts, >+ ); >+} >+ >+output_html_with_http_headers $input, $cookie, $template->output; >-- >2.20.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 24846
:
100729
|
100730
|
100731
|
100749
|
100750
|
100752
|
100753
|
100754
|
100914
|
100915
|
100969
|
100998
|
100999
| 101000 |
101001