From 78bde8594493a5497d778bd1657d21acd2240467 Mon Sep 17 00:00:00 2001 From: Jonathan Druart <jonathan.druart@bugs.koha-community.org> Date: Mon, 11 Jan 2021 15:42:18 +0100 Subject: [PATCH] Bug 20212: Use the DT column filtering provided by the wrapper Bug 27402 is adding it, we do not longer need the query_from_filters JS function. This patch also remove the filters on the left. As we have DT remembering the filter on the table we don't need them anymore. Technical note: Prior to this patch, the search on biblio.author, biblio.title and biblio.isbn was done by adding hidden columns. Now we are using: "data": "biblio.author:biblio.title:biblio.isbn" to tell the wrapper we are going to build a search on these 3 attributes. Another trick is to pass a default_filters parameters to the wrapper, to tell it we want to filter on the orders of a given vendor (this is a bugfix, the original implementation was returning all the orders). However We should not use /acq/orders?vendor_id=42 but /acq/vendor/42/orders instead (which does not exist yet), otherwise (with bug 27353 ) we are going to display the wrong number of non-filtering rows. The change in Orders.pm is only formatting to match what's done in Bug 27353: Set X-Base-Total-Count header for REST API Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io> Signed-off-by: Andrew Fuerste-Henry <andrew@bywatersolutions.com> --- Koha/REST/V1/Acquisitions/Orders.pm | 20 +- acqui/finishreceive.pl | 2 +- acqui/parcel.pl | 20 -- .../prog/en/modules/acqui/orderreceive.tt | 2 +- .../intranet-tmpl/prog/en/modules/acqui/parcel.tt | 251 ++------------------- koha-tmpl/intranet-tmpl/prog/js/datatables.js | 46 +++- 6 files changed, 68 insertions(+), 273 deletions(-) diff --git a/Koha/REST/V1/Acquisitions/Orders.pm b/Koha/REST/V1/Acquisitions/Orders.pm index 4cb0fe982f..5419ce5c45 100644 --- a/Koha/REST/V1/Acquisitions/Orders.pm +++ b/Koha/REST/V1/Acquisitions/Orders.pm @@ -143,19 +143,15 @@ sub list { # Perform search my $orders = $orders_rs->search( $filtered_params, $attributes ); + my $total = $orders_rs->search->count; - if ($orders->is_paged) { - $c->add_pagination_headers({ - total => $orders->pager->total_entries, - params => $args, - }); - } - else { - $c->add_pagination_headers({ - total => $orders->count, - params => $args, - }); - } + $c->add_pagination_headers( + { + total => ($orders->is_paged ? $orders->pager->total_entries : $orders->count), + base_total => $total, + params => $args, + } + ); return $c->render( status => 200, diff --git a/acqui/finishreceive.pl b/acqui/finishreceive.pl index 0ed88506c7..961e3d566f 100755 --- a/acqui/finishreceive.pl +++ b/acqui/finishreceive.pl @@ -190,4 +190,4 @@ if ($suggestion_id) { $suggestion->update( { reason => $reason } ) if $suggestion; } -print $input->redirect("/cgi-bin/koha/acqui/parcel.pl?invoiceid=$invoiceid&sticky_filters=1"); +print $input->redirect("/cgi-bin/koha/acqui/parcel.pl?invoiceid=$invoiceid"); diff --git a/acqui/parcel.pl b/acqui/parcel.pl index 9e4974ba90..1e42ed9174 100755 --- a/acqui/parcel.pl +++ b/acqui/parcel.pl @@ -109,25 +109,6 @@ unless( $invoiceid and $invoice->{invoiceid} ) { exit; } -my $sticky_filters = $input->param('sticky_filters') || 0; - -if ($sticky_filters) { - my $search = $input->cookie("filter_parcel_summary"); - my $ean = $input->cookie("filter_parcel_ean"); - my $basketname = $input->cookie("filter_parcel_basketname"); - my $orderno = $input->cookie("filter_parcel_orderno"); - my $basketgroupname = $input->cookie("filter_parcel_basketgroupname"); - - $template->param( - summaryfilter => $search, - eanfilter => $ean, - basketfilter => $basketname, - orderfilter => $orderno, - basketgroupnamefilter => $basketgroupname, - ); -} - - my $booksellerid = $invoice->{booksellerid}; my $bookseller = Koha::Acquisition::Booksellers->find( $booksellerid ); @@ -211,6 +192,5 @@ $template->param( total_tax_excluded => $total_tax_excluded, total_tax_included => $total_tax_included, subtotal_for_funds => $subtotal_for_funds, - sticky_filters => $sticky_filters, ); output_html_with_http_headers $input, $cookie, $template->output; diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt index 578a08ae65..61468aff99 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt @@ -370,7 +370,7 @@ </div> </div><div class="row"><fieldset class="action"> <input type="submit" value="Save" class="button" accesskey="w" /> - <a class="cancel" href="/cgi-bin/koha/acqui/parcel.pl?invoiceid=[% invoiceid | html %]&sticky_filters=1">Cancel</a> + <a class="cancel" href="/cgi-bin/koha/acqui/parcel.pl?invoiceid=[% invoiceid | html %]">Cancel</a> </fieldset></div> </form> [% ELSE %] This ordernumber does not exist. diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt index 99d6459c94..4b19420edf 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt @@ -105,9 +105,6 @@ <th>Basket</th> <th>Basket group</th> <th>Order line</th> - <th class="hidden">Title</th> - <th class="hidden">Author</th> - <th class="hidden">ISBN</th> <th>Summary</th> <th>More</th> <th>Replacement price</th> @@ -118,24 +115,6 @@ <th> </th> <th> </th> </tr> - <tr> - <th><div class="input-group input-group-sm"><input id="basket_name_column_search" type="text" class="form-control column-filter" data-search-fields='["basket.name"]'></div></th> - <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["basket.basket_group.name"]'></div></th> - <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["me.order_id"]'></div></th> - <th class="hidden"> </th> - <th class="hidden"> </th> - <th class="hidden"> </th> - <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["me.internal_note","me.vendor_note","biblio.title","biblio.author","biblio.isbn","biblio.publisher","biblio.publication_year","biblio.copyright_date","biblio.suggestions.suggester.surname","biblio.suggestions.suggester.firstname"]'></div></th> - <th> </th> - <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["me.replacement_price"]'></div></th> - <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["me.quantity"]'></div></th> - <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["me.ecost"]'></div></th> - <th> </th> - <!--th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["order_cost"]'></div></th--> - <th><div class="input-group input-group-sm"><input type="text" class="form-control column-filter" data-search-fields='["fund.name"]'></div></th> - <th> </th> - <th> </th> - </tr> </thead> </table> </div> @@ -340,41 +319,6 @@ <div class="col-sm-2 col-sm-pull-10"> <aside> -<form action="/cgi-bin/koha/acqui/parcel.pl" id="filterform" method="post"> - <fieldset class="brief"> - <h4>Filter</h4> - <ol> - <li> - <label for="summaryfilter">ISBN, author or title:</label> - <input type="text" name="summaryfilter" id="summaryfilter" value="[% summaryfilter | html %]"/> - </li> - <li> - <label for="basketfilter">Basket name:</label> - <input type="text" name="basketfilter" id="basketfilter" value="[% basketfilter | html %]"/> - </li> - <li> - <label for="basketgroupnamefilter">Basket group name:</label> - <input type="text" name="basketgroupnamefilter" id="basketgroupnamefilter" value="[% basketgroupnamefilter | html %]" /> - </li> - <li> - <label for="orderfilter">Order line:</label> - <input type="text" name="orderfilter" id="orderfilter" value="[% orderfilter | html %]"/> - </li> - [% IF (UNIMARC) %] - <li> - <label for="eanfilter">EAN:</label> - <input type="text" name="eanfilter" id="eanfilter" value="[% eanfilter | html %]"/> - </li> - [% END %] - </ol> - <fieldset class="action"> - <input type="hidden" value="search" name="op" /> - <input type="hidden" value="[% invoiceid | html %]" name="invoiceid" /> - <input type="submit" value="Filter" /> - <a href="#" id="clear_form_filters">Clear</a> - </fieldset> - </fieldset> -</form> [% INCLUDE 'acquisitions-menu.inc' %] </aside> </div> <!-- /.col-sm-2.col-sm-pull-10 --> @@ -388,86 +332,8 @@ <style>#dataPreview { width : 80%; } @media (max-width: 767px) { #dataPreview { margin: 0; width : auto; } }</style> <script> dt_overwrite_html_sorting_localeCompare(); - var sticky_filters = [% sticky_filters | html %]; var columns_filter = {}; - function query_from_filters( base_query ) { - - var query_and = []; - - var summary = $("#summaryfilter").val(); - var basket_group = $("#basketgroupnamefilter").val(); - var basket_name = $("#basketfilter").val(); - var order_id = $("#orderfilter").val(); - var ean = $("#eanfilter").val(); - - // ean == undefined if the HTML doesn't have it - ean = (ean === undefined) ? '' : ean; - - if ( basket_name != "" ) { - query_and.push( { "basket.name": { "like": '%'+basket_name+'%' } } ); - } - if (basket_group != "") { - query_and.push( { "basket.basket_group.name": { "like": '%'+basket_group+'%' } } ); - } - if (summary != "") { - query_and.push( { "-or": [{"biblio.title": { "like": '%'+summary+'%' } }, - {"biblio.author": { "like": '%'+summary+'%' } }, - {"biblio.isbn": { "like": '%'+summary+'%' } } ] } ); - } - if (ean != "") { - query_and.push( { "biblio.ean": ean } ); - } - - $(".column-filter").each(function () { - var search_fields = $(this).data('search-fields'); - var value = this.value; - - if ( value != '' && - value != undefined ) { // skip if empty - - var columns_filters = []; - - search_fields.forEach( function (item) { - if ( item === "me.order_id" || - item === "me.replacement_price" || - item === "me.quantity" || - item === "me.ecost" ) { - // For numbers, we do 'starts with' - var object = {}; - object[item] = { "like": value+'%' }; - columns_filters.push( object ); - } - else { - var object = {}; - object[item] = { "like": '%'+value+'%' }; - columns_filters.push( object ); - } - }); - - if ( columns_filters.length > 1 ) { - query_and.push( { "-or": columns_filters } ); - } - else if ( columns_filters.length > 0 ) { - query_and.push( columns_filters[0] ); - } - } - }); - - var query_params = []; - - if ( query_and.length > 0 ) { - query_and.push(base_query); - query_params.push('q=' + encodeURIComponent(JSON.stringify({ "-and": query_and }))); - } - - if ( order_id != "" ) { - query_params.push("order_id="+order_id); - } - - return query_params; - } - function _escape_str(s){ return s != null ? s.escapeHtml() : ""; } @@ -480,7 +346,6 @@ if ( $("#receivedt").length ) { var receivedt = $("#receivedt").dataTable($.extend(true, {}, dataTablesDefaults, { "bStateSave": true, - "iCookieDuration": 60*60*24*1000, // 1000 days "iDisplayLength": 10, "aLengthMenu": [[5, 10, 20, 50, 100, -1], [5, 10, 20, 50, 100, _("All")]], "aoColumnDefs": [ @@ -505,15 +370,9 @@ })); } - var base_query = { "basket.vendor_id": [% booksellerid | html %] }; - var query_params = query_from_filters( base_query ); - - var THE_query = query_params.join("&"); - - var pending_orders_url = '/api/v1/acquisitions/orders?only_active=1'; var pending_orders_table = $("#pending_orders").api({ "ajax": { - "url": pending_orders_url + '&' + THE_query + "url": '/api/v1/acquisitions/orders?only_active=1' }, "header_filter": true, "embed": [ @@ -527,8 +386,6 @@ "items" ], "stateSave": true, // remember state on page reload - "orderCellsTop": true, // tell the datatable sorting is done on the top row - 'dom': 'C<"top pager"ilpfB><"#filter_c">tr<"bottom pager"ip>', "drawCallback": function (settings) { $(".previewData").on("click", function(e){ e.preventDefault(); @@ -539,20 +396,9 @@ $('#dataPreview').modal({show:true}); }); }, - "columnDefs": [ { - "targets": [3,4,5,9], - "render": function (data, type, row, meta) { - return _escape_str(data); - } - }, - { - "targets": [8,10], - "render": function (data, type, row, meta) { - return _escape_price(data); - } - } ], "columns": [ { "data": "basket.name", + "searchable": true, "orderable": true, "render": function(data, type, row, meta) { if (type != 'display') return _escape_str(data); @@ -584,27 +430,10 @@ } }, { - "data": "biblio.author", - "visible": false, - "searchable": true, - "orderable": false - }, - { - "data": "biblio.title", - "visible": false, - "searchable": true, - "orderable": false - }, - { - "data": "biblio.isbn", - "visible": false, - "searchable": true, - "orderable": false - }, - { - "data": function(row, type, val, meta) { + "data": "biblio.author:biblio.title:biblio.isbn", + "render": function(data, type, row, meta) { var result = ''; - if ( row.biblio_id != null ) { + if ( row && row.biblio_id != null ) { result = "<p><a href=\"/cgi-bin/koha/catalogue/detail.pl?biblionumber="+encodeURIComponent(row.biblio_id)+"\">"+row.biblio.title.escapeHtml()+"</a>"; if ( row.biblio.author != null ) result += _(" by ") + row.biblio.author.escapeHtml(); @@ -672,16 +501,18 @@ return result; }, - "orderable": false + "orderable": false, }, { - "data": function( row, type, val, meta) { + "data": "", + "render": function(data, type, row, meta) { var result = '<a href="/cgi-bin/koha/acqui/showorder.pl?ordernumber=' + encodeURIComponent(row.order_id) + '" class="previewData">' + _("Order") + '</a><br>' + '<a href="/cgi-bin/koha/catalogue/showmarc.pl?id=' + encodeURIComponent(row.biblio_id) + '" class="previewData">' + _("MARC") + '</a><br>' + '<a href="/cgi-bin/koha/catalogue/showmarc.pl?viewas=card&id=' + encodeURIComponent(row.biblio_id) + '" class="previewData">' + _("Card") + '</a>'; return result; }, - "orderable": false + "orderable": false, + "searchable": false }, { "data": "replacement_price" @@ -694,10 +525,12 @@ "data": "ecost" }, { - "data": function ( row, type, val, meta ) { + "data": "", + "render": function(data, type, row, meta) { return (row.quantity * row.ecost).format_price(); }, - "orderable": false // FIXME: How can we do it in DBIC? + "orderable": false, // FIXME: How can we do it in DBIC? + "searchable": false }, { "data": "fund.name", @@ -707,17 +540,20 @@ } }, { - "data": function( row, type, val, meta ) { + "data": "", + "render": function(data, type, row, meta) { return '<a href="orderreceive.pl?ordernumber=' + encodeURIComponent(row.order_id) + '&invoiceid=[% invoiceid | uri %]' + '">' + _("Receive") + '</a><br/>' + '<a href="#" onclick="transfer_order_popup(' + row.order_id.escapeHtml() + '); return false;">' + _("Transfer") + '</a>'; }, - "orderable": false + "orderable": false, + "searchable": false }, { - "data": function( row, type, val, meta ) { + "data": "", + "render": function(data, type, row, meta) { var result = ""; if ( row.current_holds_count > 0 ) { @@ -775,52 +611,11 @@ return result; }, - "orderable": false + "orderable": false, + "searchable": false } ] - }); - - // column filter events handling - $(".column-filter").each(function () { - $(this).on( 'keyup change', function () { - // recalculate the query - var query_params = query_from_filters( base_query ); - // refresh the datatable as appropriate - if ( query_params.length > 0 ) { - pending_orders_table.api().ajax.url( pending_orders_url + '&' + query_params.join("&") ); - } - else { - pending_orders_table.api().ajax.url( pending_orders_url + '&q=' + encodeURI(JSON.stringify(base_query)) ); - } - pending_orders_table.api().ajax.reload( null, false ); - }); - }); - - $("#filterform").on("submit", function(e) { - e.preventDefault(); - - // Save the filters in the cookie - $.cookie("filter_parcel_summary", $("#summaryfilter").val()); - $.cookie("filter_parcel_basketname", $("#basketfilter").val()); - $.cookie("filter_parcel_orderno", $("#orderfilter").val()); - $.cookie("filter_parcel_basketgroupname", $("#basketgroupnamefilter").val()); - $.cookie("filter_parcel_ean", $("#eanfilter").val()); - - var query_params = query_from_filters( base_query ); - - if ( query_params.length > 0 ) { - pending_orders_table.api().ajax.url( pending_orders_url + '&' + query_params.join("&") ); - } - else { - pending_orders_table.api().ajax.url( pending_orders_url + '&q=' + encodeURI(JSON.stringify(base_query)) ); - } - pending_orders_table.api().ajax.reload( null, false ); - }); - - $('#clear_form_filters').on("click", function(){ - $(this).closest('form').find("input[type=text], textarea").val(""); - pending_orders_table.api().ajax.url(pending_orders_url + '&q=' + encodeURI(JSON.stringify(base_query))).draw(); - }); + }, {}, 1, {"basket.vendor_id": [% booksellerid | html %]}); $(".previewData").on("click", function(e){ e.preventDefault(); diff --git a/koha-tmpl/intranet-tmpl/prog/js/datatables.js b/koha-tmpl/intranet-tmpl/prog/js/datatables.js index be2da8c976..33a21d8287 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/datatables.js +++ b/koha-tmpl/intranet-tmpl/prog/js/datatables.js @@ -509,7 +509,7 @@ jQuery.fn.dataTable.ext.errMode = function(settings, note, message) { (function($) { - $.fn.api = function(options, columns_settings, add_filters) { + $.fn.api = function(options, columns_settings, add_filters, default_filters) { var settings = null; if ( add_filters ) { @@ -563,6 +563,22 @@ jQuery.fn.dataTable.ext.errMode = function(settings, note, message) { _per_page: length }; + + function build_query(col){ + var parts = []; + var attributes = col.data.split(':'); + for (var i=0;i<attributes.length;i++){ + var part = {}; + var attr = attributes[i]; + var value = data.columns[col.idx].search.value; + part[!attr.includes('.')?'me.'+attr:attr] = options.criteria === 'exact' + ? value + : {like: (['contains', 'ends_with'].indexOf(options.criteria) !== -1?'%':'') + value + (['contains', 'starts_with'].indexOf(options.criteria) !== -1?'%':'')}; + parts.push(part); + } + return parts; + } + var filter = data.search.value; // Build query for each column filter var and_query_parameters = settings.aoColumns @@ -570,10 +586,10 @@ jQuery.fn.dataTable.ext.errMode = function(settings, note, message) { return col.bSearchable && typeof col.data == 'string' && data.columns[col.idx].search.value != '' }) .map(function(col) { - var part = {}; - var value = data.columns[col.idx].search.value; - part[!col.data.includes('.')?'me.'+col.data:col.data] = options.criteria === 'exact'?value:{like: (['contains', 'ends_with'].indexOf(options.criteria) !== -1?'%':'')+value+(['contains', 'starts_with'].indexOf(options.criteria) !== -1?'%':'')}; - return part; + return build_query(col) + }) + .map(function r(e){ + return ($.isArray(e) ? $.map(e, r) : e); }); // Build query for the global search filter @@ -582,12 +598,15 @@ jQuery.fn.dataTable.ext.errMode = function(settings, note, message) { return col.bSearchable && typeof col.data == 'string' && data.columns[col.idx].search.value == '' && filter != '' }) .map(function(col) { - var part = {}; - value = filter; - part[!col.data.includes('.')?'me.'+col.data:col.data] = options.criteria === 'exact'?value:{like: (['contains', 'ends_with'].indexOf(options.criteria) !== -1?'%':'')+value+(['contains', 'starts_with'].indexOf(options.criteria) !== -1?'%':'')}; - return part; + return build_query(col) + }) + .map(function r(e){ + return ($.isArray(e) ? $.map(e, r) : e); }); + if ( default_filters ) { + and_query_parameters.push(default_filters); + } query_parameters = and_query_parameters; query_parameters.push(or_query_parameters); if(query_parameters.length) { @@ -748,8 +767,13 @@ jQuery.fn.dataTable.ext.errMode = function(settings, note, message) { var is_searchable = table_dt.settings()[0].aoColumns[i].bSearchable; if ( is_searchable ) { var title = $(this).text(); - var search_title = _("Search %s").format(title); - $(this).html( '<input type="text" placeholder="%s" />'.format(search_title) ); + var existing_search = table_dt.column(i).search(); + if ( existing_search ) { + $(this).html( '<input type="text" value="%s" style="width: 100%" />'.format(existing_search) ); + } else { + var search_title = _("Search %s").format(title); + $(this).html( '<input type="text" placeholder="%s" style="width: 100%" />'.format(search_title) ); + } $( 'input', this ).on( 'keyup change', function () { if ( table_dt.column(i).search() !== this.value ) { -- 2.11.0