Browse Source

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>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
21.05.x
Jonathan Druart 7 months ago
parent
commit
6180725e61
  1. 20
      Koha/REST/V1/Acquisitions/Orders.pm
  2. 2
      acqui/finishreceive.pl
  3. 20
      acqui/parcel.pl
  4. 2
      koha-tmpl/intranet-tmpl/prog/en/modules/acqui/orderreceive.tt
  5. 251
      koha-tmpl/intranet-tmpl/prog/en/modules/acqui/parcel.tt
  6. 46
      koha-tmpl/intranet-tmpl/prog/js/datatables.js

20
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,

2
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");

20
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;

2
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.

251
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>&nbsp;</th>
<th>&nbsp;</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">&nbsp;</th>
<th class="hidden">&nbsp;</th>
<th class="hidden">&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</th>
<th>&nbsp;</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&amp;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) + '&amp;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();

46
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 = _("%s search").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 = _("%s search").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 ) {

Loading…
Cancel
Save