Bugzilla – Attachment 86433 Details for
Bug 18589
Show ILLs as part of patron profile
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 18589: Show ILLs as part of patron profile
Bug-18589-Show-ILLs-as-part-of-patron-profile.patch (text/plain), 58.12 KB, created by
Andrew Isherwood
on 2019-03-11 12:00:33 UTC
(
hide
)
Description:
Bug 18589: Show ILLs as part of patron profile
Filename:
MIME Type:
Creator:
Andrew Isherwood
Created:
2019-03-11 12:00:33 UTC
Size:
58.12 KB
patch
obsolete
>From f3c40f363fe240a123a7e1da5a80f246a273f985 Mon Sep 17 00:00:00 2001 >From: Andrew Isherwood <andrew.isherwood@ptfs-europe.com> >Date: Mon, 11 Mar 2019 11:56:28 +0000 >Subject: [PATCH] Bug 18589: Show ILLs as part of patron profile > >This patch moves the display of a patron's ILL requests to be inline in >the Patron Profile page, as per all other patron information. > >It includes a substantial refactor of >koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt in that it >moves the display of the illlist table (which is populated by an API >request) into it's own separate include file. It also moves the >datatable related Javascript for this table into it's own JS file. Doing >this allows us to reuse both in both the new members/ill-requests.tt >template and the pre-existing ill/ill-requests.tt template. > >To test: >1) Ensure ILL is enabled and your user has sufficient permissions >2) Ensure your user has some ILL requests >3) Navigate to the user's patron profile page >4) Click on the "Interlibrary loans" tab >5) Observe that the requests table is displayed inline >6) Observe that only your user's requests are displayed > >Signed-off-by: Niamh.Walker-Headon@it-tallaght.ie > >This is essentially a reimplementation of attachment 84796 to take into >account all changes that had happened beneath this bug and also to >ensure JS strings are translatable. >--- > Koha/REST/V1/Illrequests.pm | 10 +- > ill/ill-requests.pl | 5 +- > .../intranet-tmpl/prog/en/includes/circ-menu.inc | 2 +- > .../prog/en/includes/ill-list-table-strings.inc | 19 + > .../prog/en/includes/ill-list-table.inc | 42 ++ > .../prog/en/modules/ill/ill-requests.tt | 590 +-------------------- > .../prog/en/modules/members/ill-requests.tt | 63 +++ > koha-tmpl/intranet-tmpl/prog/js/ill-list-table.js | 533 +++++++++++++++++++ > members/ill-requests.pl | 55 ++ > 9 files changed, 743 insertions(+), 576 deletions(-) > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/includes/ill-list-table-strings.inc > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/includes/ill-list-table.inc > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/ill-requests.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/ill-list-table.js > create mode 100755 members/ill-requests.pl > >diff --git a/Koha/REST/V1/Illrequests.pm b/Koha/REST/V1/Illrequests.pm >index a5ec780d2e..c3c51a592d 100644 >--- a/Koha/REST/V1/Illrequests.pm >+++ b/Koha/REST/V1/Illrequests.pm >@@ -55,7 +55,15 @@ sub list { > } > > # Get all requests >- my @requests = Koha::Illrequests->as_list; >+ # If necessary, only get those from a specified patron >+ my @requests; >+ if ($args->{borrowernumber}) { >+ @requests = Koha::Illrequests->search( >+ { borrowernumber => $args->{borrowernumber} } >+ ); >+ } else { >+ @requests = Koha::Illrequests->as_list; >+ } > > # Identify patrons & branches that > # we're going to need and get them >diff --git a/ill/ill-requests.pl b/ill/ill-requests.pl >index 1598ea862c..45f99c2ca3 100755 >--- a/ill/ill-requests.pl >+++ b/ill/ill-requests.pl >@@ -273,13 +273,12 @@ if ( $backends_available ) { > my $active_filters = []; > foreach my $filter(@{$possible_filters}) { > if ($params->{$filter}) { >- push @{$active_filters}, >- { name => $filter, value => $params->{$filter}}; >+ push @{$active_filters}, "$filter=$params->{$filter}"; > } > } > if (scalar @{$active_filters} > 0) { > $template->param( >- prefilters => $active_filters >+ prefilters => join(",", @{$active_filters}) > ); > } > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc >index f6c3d5e284..0adbccee66 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc >@@ -132,7 +132,7 @@ > [% IF houseboundview %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/housebound.pl?borrowernumber=[% patron.borrowernumber | uri %]">Housebound</a></li> > [% END %] > [% IF Koha.Preference('ILLModule') && CAN_user_ill %] >- <li><a href="/cgi-bin/koha/ill/ill-requests.pl?borrowernumber=[% patron.borrowernumber | uri %]">Interlibrary loans</a></li> >+ [% IF illview %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/ill-requests.pl?borrowernumber=[% patron.borrowernumber | uri %]">Interlibrary loans</a></li> > [% END %] > </ul></div> > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/ill-list-table-strings.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/ill-list-table-strings.inc >new file mode 100644 >index 0000000000..3ef5e6e650 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/ill-list-table-strings.inc >@@ -0,0 +1,19 @@ >+<script> >+ var ill_borrower_details = _('View borrower details'); >+ var ill_biblio_details = _('View biblio details'); >+ var ill_statuses = { >+ new: _('New request'), >+ req: _('Requested'), >+ genreq: _('Requested from partners'), >+ rev: _('Reverted'), >+ que: _('Queued request'), >+ canc: _('Cancellation requested'), >+ comp: _('Completed'), >+ del: _('Delete request') >+ }; >+ var ill_manage = _('Manage request'); >+ var ill_columns = { >+ biblio_id: _('Bibliographic record ID'), >+ updated: _('Updated on') >+ }; >+</script> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/ill-list-table.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/ill-list-table.inc >new file mode 100644 >index 0000000000..df26181f14 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/ill-list-table.inc >@@ -0,0 +1,42 @@ >+<div> >+ [% IF prefilters.length > 0 %] >+ <table id="ill-requests" data-prefilters="[% prefilters | html %]"> >+ [% ELSE %] >+ <table id="ill-requests"> >+ [% END %] >+ <thead> >+ <tr id="illview-header"> >+ <th scope="col">Request ID</th> >+ <th scope="col">Author</th> >+ <th scope="col">Title</th> >+ <th scope="col">Article title</th> >+ <th scope="col">Issue</th> >+ <th scope="col">Volume</th> >+ <th scope="col">Year</th> >+ <th scope="col">Pages</th> >+ <th scope="col">Type</th> >+ <th scope="col">Order ID</th> >+ <th scope="col">Patron</th> >+ <th scope="col">Bibliographic record</th> >+ <th scope="col">Branch</th> >+ <th scope="col">Status</th> >+ <th scope="col" class="placed"> </th> >+ <th scope="col" class="placed_formatted">Placed on</th> >+ <th scope="col" class="updated"> </th> >+ <th scope="col" class="updated_formatted">Updated on</th> >+ <th scope="col">Replied</th> >+ <th scope="col" class="completed"> </th> >+ <th scope="col" class="completed_formatted">Completed on</th> >+ <th scope="col">Access URL</th> >+ <th scope="col">Cost</th> >+ <th scope="col">Comments</th> >+ <th scope="col">OPAC notes</th> >+ <th scope="col">Staff notes</th> >+ <th scope="col">Backend</th> >+ <th scope="col" class="actions"></th> >+ </tr> >+ </thead> >+ <tbody id="illview-body"> >+ </tbody> >+ </table> >+</div> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt >index 85bb7cb2ea..a096f32015 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt >@@ -507,43 +507,8 @@ > <h1>View ILL requests</h1> > <div id="results"> > <h3>Details for all requests</h3> >+ [% INCLUDE 'ill-list-table.inc' %] > >- <table id="ill-requests"> >- <thead> >- <tr id="illview-header"> >- <th scope="col">Request ID</th> >- <th scope="col">Author</th> >- <th scope="col">Title</th> >- <th scope="col">Article title</th> >- <th scope="col">Issue</th> >- <th scope="col">Volume</th> >- <th scope="col">Year</th> >- <th scope="col">Pages</th> >- <th scope="col">Type</th> >- <th scope="col">Order ID</th> >- <th scope="col">Patron</th> >- <th scope="col">Bibliographic record</th> >- <th scope="col">Branch</th> >- <th scope="col">Status</th> >- <th scope="col" class="placed"> </th> >- <th scope="col" class="placed_formatted">Placed on</th> >- <th scope="col" class="updated"> </th> >- <th scope="col" class="updated_formatted">Updated on</th> >- <th scope="col">Replied</th> >- <th scope="col" class="completed"> </th> >- <th scope="col" class="completed_formatted">Completed on</th> >- <th scope="col">Access URL</th> >- <th scope="col">Cost</th> >- <th scope="col">Comments</th> >- <th scope="col">OPAC notes</th> >- <th scope="col">Staff notes</th> >- <th scope="col">Backend</th> >- <th scope="col" class="actions"></th> >- </tr> >- </thead> >- <tbody id="illview-body"> >- </tbody> >- </table> > </div> > [% ELSE %] > <!-- Custom Backend Action --> >@@ -555,548 +520,31 @@ > </div> > </div> > >-[% TRY %] >-[% PROCESS backend_jsinclude %] >-[% CATCH %] >-[% END %] >- > [% MACRO jsinclude BLOCK %] > [% INCLUDE 'datatables.inc' %] > [% INCLUDE 'columns_settings.inc' %] > [% INCLUDE 'calendar.inc' %] > [% Asset.js("lib/jquery/plugins/jquery.checkboxes.min.js") | $raw %] > <script> >- $(document).ready(function() { >- >- // Illview Datatable setup >- >- var columns_settings = [% ColumnsSettings.GetColumns( 'illrequests', 'ill-requests', 'ill-requests', 'json' ) %]; >- >- var table; >- >- // Filters that are active >- var activeFilters = {}; >- >- // Fields we need to expand (flatten) >- var expand = [ >- 'metadata', >- 'patron', >- 'library' >- ]; >- >- // Expanded fields >- // This is auto populated >- var expanded = {}; >- >- // Filterable columns >- var filterable = { >- status: { >- prep: function(tableData, oData) { >- var uniques = {}; >- tableData.forEach(function(row) { >- var resolvedName; >- if (row.status_alias) { >- resolvedName = row.status_alias.lib; >- } else { >- resolvedName = getStatusName( >- oData[0].capabilities[row.status].name >- ); >- } >- uniques[resolvedName] = 1 >- }); >- Object.keys(uniques).sort().forEach(function(unique) { >- $('#illfilter_status').append( >- '<option value="' + unique + >- '">' + unique + '</option>' >- ); >- }); >- }, >- listener: function() { >- var me = 'status'; >- $('#illfilter_status').change(function() { >- var sel = $('#illfilter_status option:selected').val(); >- if (sel && sel.length > 0) { >- activeFilters[me] = function() { >- table.api().column(13).search(sel); >- } >- } else { >- if (activeFilters.hasOwnProperty(me)) { >- delete activeFilters[me]; >- } >- } >- }); >- }, >- clear: function() { >- $('#illfilter_status').val(''); >- } >- }, >- pickupBranch: { >- prep: function(tableData, oData) { >- var uniques = {}; >- tableData.forEach(function(row) { >- uniques[row.library_branchname] = 1 >- }); >- Object.keys(uniques).sort().forEach(function(unique) { >- $('#illfilter_branchname').append( >- '<option value="' + unique + >- '">' + unique + '</option>' >- ); >- }); >- }, >- listener: function() { >- var me = 'pickupBranch'; >- $('#illfilter_branchname').change(function() { >- var sel = $('#illfilter_branchname option:selected').val(); >- if (sel && sel.length > 0) { >- activeFilters[me] = function() { >- table.api().column(12).search(sel); >- } >- } else { >- if (activeFilters.hasOwnProperty(me)) { >- delete activeFilters[me]; >- } >- } >- }); >- }, >- clear: function() { >- $('#illfilter_branchname').val(''); >- } >- }, >- patron: { >- listener: function() { >- var me = 'patron'; >- $('#illfilter_patron').change(function() { >- var val = $('#illfilter_patron').val(); >- if (val && val.length > 0) { >- activeFilters[me] = function() { >- table.api().column(10).search(val); >- } >- } else { >- if (activeFilters.hasOwnProperty(me)) { >- delete activeFilters[me]; >- } >- } >- }); >- }, >- clear: function() { >- $('#illfilter_patron').val(''); >- } >- }, >- dateModified: { >- clear: function() { >- $('#illfilter_datemodified_start, #illfilter_datemodified_end').val(''); >- } >- }, >- datePlaced: { >- clear: function() { >- $('#illfilter_dateplaced_start, #illfilter_dateplaced_end').val(''); >- } >- } >- }; >- >- // Expand any fields we're expanding >- var expandExpand = function(row) { >- expand.forEach(function(thisExpand) { >- if (row.hasOwnProperty(thisExpand)) { >- if (!expanded.hasOwnProperty(thisExpand)) { >- expanded[thisExpand] = []; >- } >- var expandObj = row[thisExpand]; >- Object.keys(expandObj).forEach( >- function(thisExpandCol) { >- var expColName = thisExpand + '_' + thisExpandCol.replace(/\s/g,'_'); >- // Keep a list of fields that have been expanded >- // so we can create toggle links for them >- if (expanded[thisExpand].indexOf(expColName) == -1) { >- expanded[thisExpand].push(expColName); >- } >- expandObj[expColName] = >- expandObj[thisExpandCol]; >- delete expandObj[thisExpandCol]; >- } >- ); >- $.extend(true, row, expandObj); >- delete row[thisExpand]; >- } >- }); >- }; >- >- // Strip the expand prefix if it exists, we do this for display >- var stripPrefix = function(value) { >- expand.forEach(function(thisExpand) { >- var regex = new RegExp(thisExpand + '_', 'g'); >- value = value.replace(regex, ''); >- }); >- return value; >- }; >- >- // Our 'render' function for borrowerlink >- var createPatronLink = function(data, type, row) { >- var patronLink = '<a title="' + _("View borrower details") + '" ' + >- 'href="/cgi-bin/koha/members/moremember.pl?' + >- 'borrowernumber='+row.borrowernumber+'">'; >- if ( row.patron_firstname ) { >- patronLink = patronLink + row.patron_firstname + ' '; >- } >- patronLink = patronLink + row.patron_surname + >- ' (' + row.patron_cardnumber + ')' + '</a>'; >- return patronLink; >- }; >- >- // Our 'render' function for biblio_id >- var createBiblioLink = function(data, type, row) { >- return (row.biblio_id) ? >- '<a title="' + _("View biblio details") + '" ' + >- 'href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=' + >- row.biblio_id + '">' + >- row.biblio_id + >- '</a>' : ''; >- }; >- >- // Our 'render' function for title >- var createTitle = function(data, type, row) { >- return ( >- row.hasOwnProperty('metadata_container_title') && >- row.metadata_container_title >- ) ? row.metadata_container_title : row.metadata_title; >- }; >- >- // Render function for request ID >- var createRequestId = function(data, type, row) { >- return row.id_prefix + row.illrequest_id; >- }; >- >- // Render function for type >- var createType = function(data, type, row) { >- if (!row.hasOwnProperty('metadata_Type') || !row.metadata_Type) { >- if (row.hasOwnProperty('medium') && row.medium) { >- row.metadata_Type = row.medium; >- } else { >- row.metadata_Type = null; >- } >- } >- return row.metadata_Type; >- }; >- >- // Render function for request status >- var createStatus = function(data, type, row, meta) { >- if (row.status_alias) { >- return row.status_alias.lib >- ? row.status_alias.lib >- : row.status_alias.authorised_value; >- } else { >- var origData = meta.settings.oInit.originalData; >- if (origData.length > 0) { >- var status_name = meta.settings.oInit.originalData[0].capabilities[ >- row.status >- ].name; >- return getStatusName(status_name, row); >- } else { >- return ''; >- } >- } >- }; >- >- var getStatusName = function(origName, row) { >- switch( origName ) { >- case "New request": >- return _("New request"); >- case "Requested": >- return _("Requested"); >- case "Requested from partners": >- var statStr = _("Requested from partners"); >- if ( >- row.hasOwnProperty('requested_partners') && >- row.requested_partners && >- row.requested_partners.length > 0 >- ) { >- statStr += ' (' + row.requested_partners + ')'; >- } >- return statStr; >- case "Request reverted": >- return _("Request reverted"); >- case "Queued request": >- return _("Queued request"); >- case "Cancellation requested": >- return _("Cancellation requested"); >- case "Completed": >- return _("Completed"); >- case "Delete request": >- return _("Delete request"); >- default: >- return origName; >- } >- }; >- >- // Render function for creating a row's action link >- var createActionLink = function(data, type, row) { >- return '<a class="btn btn-default btn-sm" ' + >- 'href="/cgi-bin/koha/ill/ill-requests.pl?' + >- 'method=illview&illrequest_id=' + >- row.illrequest_id + >- '">' + _("Manage request") + '</a>'; >- }; >- >- // Columns that require special treatment >- var specialCols = { >- action: { >- func: createActionLink, >- skipSanitize: true >- }, >- illrequest_id: { >- func: createRequestId >- }, >- status: { >- func: createStatus >- }, >- biblio_id: { >- name: _("Bibliograpic record ID"), >- func: createBiblioLink, >- skipSanitize: true >- }, >- metadata_title: { >- func: createTitle >- }, >- metadata_Type: { >- func: createType >- }, >- updated: { >- name: _("Updated on"), >- }, >- patron: { >- skipSanitize: true, >- func: createPatronLink >- } >- }; >- >- // Display the modal containing request supplier metadata >- $('#ill-request-display-log').on('click', function(e) { >- e.preventDefault(); >- $('#requestLog').modal({show:true}); >- }); >- >- // Toggle request attributes in Illview >- $('#toggle_requestattributes').on('click', function(e) { >- e.preventDefault(); >- $('#requestattributes').toggleClass('content_hidden'); >- }); >- >- // Toggle new comment form in Illview >- $('#toggle_addcomment').on('click', function(e) { >- e.preventDefault(); >- $('#addcomment').toggleClass('content_hidden'); >- }); >- >- // Filter partner list >- $('#partner_filter').keyup(function() { >- var needle = $('#partner_filter').val(); >- $('#partners > option').each(function() { >- var regex = new RegExp(needle, 'i'); >- if ( >- needle.length == 0 || >- $(this).is(':selected') || >- $(this).text().match(regex) >- ) { >- $(this).show(); >- } else { >- $(this).hide(); >- } >- }); >- }); >- >- // Display the modal containing request supplier metadata >- $('#ill-request-display-metadata').on('click', function(e) { >- e.preventDefault(); >- $('#dataPreview').modal({show:true}); >- }); >- >- // Allow us to chain Datatable render helpers together, so we >- // can use our custom functions and render.text(), which >- // provides us with data sanitization >- $.fn.dataTable.render.multi = function(renderArray) { >- return function(d, type, row, meta) { >- for(var r = 0; r < renderArray.length; r++) { >- var toCall = renderArray[r].hasOwnProperty('display') ? >- renderArray[r].display : >- renderArray[r]; >- d = toCall(d, type, row, meta); >- } >- return d; >- } >- } >- >- // Get our data from the API and process it prior to passing >- // it to datatables >- var ajax = $.ajax( >- '/api/v1/illrequests?embed=metadata,patron,capabilities,library,status_alias,comments,requested_partners' >- ).done(function() { >- var data = JSON.parse(ajax.responseText); >- // Make a copy, we'll be removing columns next and need >- // to be able to refer to data that has been removed >- var dataCopy = $.extend(true, [], data); >- // Expand columns that need it and create an array >- // of all column names >- $.each(dataCopy, function(k, row) { >- expandExpand(row); >- }); >- >- // Assemble an array of column definitions for passing >- // to datatables >- var colData = []; >- columns_settings.forEach(function(thisCol) { >- var colName = thisCol.columnname; >- // Create the base column object >- var colObj = $.extend({}, thisCol); >- colObj.name = colName; >- colObj.className = colName; >- colObj.defaultContent = ''; >- >- // We may need to process the data going in this >- // column, so do it if necessary >- if ( >- specialCols.hasOwnProperty(colName) && >- specialCols[colName].hasOwnProperty('func') >- ) { >- var renderArray = [ >- specialCols[colName].func >- ]; >- if (!specialCols[colName].skipSanitize) { >- renderArray.push( >- $.fn.dataTable.render.text() >- ); >- } >- >- colObj.render = $.fn.dataTable.render.multi( >- renderArray >- ); >- } else { >- colObj.data = colName; >- colObj.render = $.fn.dataTable.render.text() >- } >- // Make sure properties that aren't present in the API >- // response are populated with null to avoid Datatables >- // choking on their absence >- dataCopy.forEach(function(thisData) { >- if (!thisData.hasOwnProperty(colName)) { >- thisData[colName] = null; >- } >- }); >- colData.push(colObj); >- }); >- >- // Initialise the datatable >- table = KohaTable("ill-requests", { >- 'aoColumnDefs': [ >- { // Last column shouldn't be sortable or searchable >- 'aTargets': [ 'actions' ], >- 'bSortable': false, >- 'bSearchable': false >- }, >- { // When sorting 'placed', we want to use the >- // unformatted column >- 'aTargets': [ 'placed_formatted'], >- 'iDataSort': 14 >- }, >- { // When sorting 'updated', we want to use the >- // unformatted column >- 'aTargets': [ 'updated_formatted'], >- 'iDataSort': 16 >- }, >- { // When sorting 'completed', we want to use the >- // unformatted column >- 'aTargets': [ 'completed_formatted'], >- 'iDataSort': 19 >- } >- ], >- 'aaSorting': [[ 16, 'desc' ]], // Default sort, updated descending >- 'processing': true, // Display a message when manipulating >- 'sPaginationType': "full_numbers", // Pagination display >- 'deferRender': true, // Improve performance on big datasets >- 'data': dataCopy, >- 'columns': colData, >- 'originalData': data, // Enable render functions to access >- // our original data >- 'initComplete': function() { >- >- // Prepare any filter elements that need it >- for (var el in filterable) { >- if (filterable.hasOwnProperty(el)) { >- if (filterable[el].hasOwnProperty('prep')) { >- filterable[el].prep(dataCopy, data); >- } >- if (filterable[el].hasOwnProperty('listener')) { >- filterable[el].listener(); >- } >- } >- } >- >- } >- }, columns_settings); >- >- // Custom date range filtering >- $.fn.dataTable.ext.search.push(function(settings, data, dataIndex) { >- var placedStart = $('#illfilter_dateplaced_start').datepicker('getDate'); >- var placedEnd = $('#illfilter_dateplaced_end').datepicker('getDate'); >- var modifiedStart = $('#illfilter_datemodified_start').datepicker('getDate'); >- var modifiedEnd = $('#illfilter_datemodified_end').datepicker('getDate'); >- var rowPlaced = data[14] ? new Date(data[14]) : null; >- var rowModified = data[16] ? new Date(data[16]) : null; >- var placedPassed = true; >- var modifiedPassed = true; >- if (placedStart && rowPlaced && rowPlaced < placedStart) { >- placedPassed = false >- }; >- if (placedEnd && rowPlaced && rowPlaced > placedEnd) { >- placedPassed = false; >- } >- if (modifiedStart && rowModified && rowModified < modifiedStart) { >- modifiedPassed = false >- }; >- if (modifiedEnd && rowModified && rowModified > modifiedEnd) { >- modifiedPassed = false; >- } >- >- return placedPassed && modifiedPassed; >- >- }); >- >- } >- ); >- >- var clearSearch = function() { >- table.api().search('').columns().search(''); >- activeFilters = {}; >- for (var filter in filterable) { >- if ( >- filterable.hasOwnProperty(filter) && >- filterable[filter].hasOwnProperty('clear') >- ) { >- filterable[filter].clear(); >- } >- } >- table.api().draw(); >- }; >- >- // Apply any search filters, or clear any previous >- // ones >- $('#illfilter_form').submit(function(event) { >- event.preventDefault(); >- table.api().search('').columns().search(''); >- for (var active in activeFilters) { >- if (activeFilters.hasOwnProperty(active)) { >- activeFilters[active](); >- } >- } >- table.api().draw(); >- }); >- >- // Clear all filters >- $('#clear_search').click(function() { >- clearSearch(); >- }); >- >- }); >+ // Date format for datepickers >+ var dateMap = { >+ dmydot: 'dd.mm.yy', >+ iso: 'yy-mm-dd', >+ metric: 'dd/mm/yy', >+ us: 'mm/dd/yy' >+ }; >+ var dateFormat = dateMap['[% Koha.Preference('dateformat') | html %]']; >+ var prefilters = '[% prefilters | html %]'; >+ // Set column settings >+ var columns_settings = [% ColumnsSettings.GetColumns( 'illrequests', 'ill-requests', 'ill-requests', 'json' ) %]; > </script> >+ [% INCLUDE 'ill-list-table-strings.inc' %] >+ [% Asset.js("js/ill-list-table.js") | $raw %] >+[% END %] >+ >+[% TRY %] >+[% PROCESS backend_jsinclude %] >+[% CATCH %] > [% END %] > > [% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/ill-requests.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/ill-requests.tt >new file mode 100644 >index 0000000000..cab9a6c733 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/ill-requests.tt >@@ -0,0 +1,63 @@ >+[% USE raw %] >+[% USE Asset %] >+[% USE Branches %] >+[% USE Koha %] >+[% USE KohaDates %] >+[% SET footerjs = 1 %] >+[% USE AuthorisedValues %] >+[% USE ColumnsSettings %] >+ >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Patrons › ILL requests for [% INCLUDE 'patron-title.inc' no_html = 1 %]</title> >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+ >+<body> >+ [% INCLUDE 'header.inc' %] >+ [% INCLUDE 'patron-search.inc' %] >+ >+ <div id="breadcrumbs"> >+ <a href="/cgi-bin/koha/mainpage.pl">Home</a> >+ › <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> >+ › ILL requests for [% INCLUDE 'patron-title.inc' %] >+ </div> >+ >+ <div id="doc3" class="yui-t1"> >+ >+ <div id="bd"> >+ <div id="yui-main"> >+ <div class="yui-b"> >+ <div class="yui-g"> >+ <h2>ILL requests</h2> >+ [% INCLUDE 'ill-list-table.inc' %] >+ </div> >+ </div> >+ </div> >+ <div class="yui-b"> >+ [% INCLUDE 'circ-menu.inc' %] >+ </div> >+ </div> >+ >+ [% MACRO jsinclude BLOCK %] >+ [% INCLUDE 'datatables.inc' %] >+ [% INCLUDE 'columns_settings.inc' %] >+ [% INCLUDE 'calendar.inc' %] >+ [% Asset.js("lib/jquery/plugins/jquery.checkboxes.min.js") | $raw %] >+ <script> >+ // Date format for datepickers >+ var dateMap = { >+ dmydot: 'dd.mm.yy', >+ iso: 'yy-mm-dd', >+ metric: 'dd/mm/yy', >+ us: 'mm/dd/yy' >+ }; >+ var dateFormat = dateMap['[% Koha.Preference('dateformat') | html %]']; >+ var prefilters = '[% prefilters | html %]'; >+ // Set column settings >+ var columns_settings = [% ColumnsSettings.GetColumns( 'illrequests', 'ill-requests', 'ill-requests', 'json' ) %]; >+ </script> >+ [% INCLUDE 'ill-list-table-strings.inc' %] >+ [% Asset.js("js/ill-list-table.js") | $raw %] >+ [% END %] >+ >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/js/ill-list-table.js b/koha-tmpl/intranet-tmpl/prog/js/ill-list-table.js >new file mode 100644 >index 0000000000..41e7ecc956 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/ill-list-table.js >@@ -0,0 +1,533 @@ >+$(document).ready(function() { >+ >+ // Illview Datatable setup >+ >+ var table; >+ >+ // Filters that are active >+ var activeFilters = {}; >+ >+ // Get any prefilters >+ var prefilters = $('table#ill-requests').data('prefilters'); >+ >+ // Fields we need to expand (flatten) >+ var expand = [ >+ 'metadata', >+ 'patron', >+ 'library' >+ ]; >+ >+ // Expanded fields >+ // This is auto populated >+ var expanded = {}; >+ >+ // Filterable columns >+ var filterable = { >+ status: { >+ prep: function(tableData, oData) { >+ var uniques = {}; >+ tableData.forEach(function(row) { >+ var resolvedName; >+ if (row.status_alias) { >+ resolvedName = row.status_alias.lib; >+ } else { >+ resolvedName = getStatusName( >+ oData[0].capabilities[row.status].name >+ ); >+ } >+ uniques[resolvedName] = 1 >+ }); >+ Object.keys(uniques).sort().forEach(function(unique) { >+ $('#illfilter_status').append( >+ '<option value="' + unique + >+ '">' + unique + '</option>' >+ ); >+ }); >+ }, >+ listener: function() { >+ var me = 'status'; >+ $('#illfilter_status').change(function() { >+ var sel = $('#illfilter_status option:selected').val(); >+ if (sel && sel.length > 0) { >+ activeFilters[me] = function() { >+ table.api().column(13).search(sel); >+ } >+ } else { >+ if (activeFilters.hasOwnProperty(me)) { >+ delete activeFilters[me]; >+ } >+ } >+ }); >+ }, >+ clear: function() { >+ $('#illfilter_status').val(''); >+ } >+ }, >+ pickupBranch: { >+ prep: function(tableData, oData) { >+ var uniques = {}; >+ tableData.forEach(function(row) { >+ uniques[row.library_branchname] = 1 >+ }); >+ Object.keys(uniques).sort().forEach(function(unique) { >+ $('#illfilter_branchname').append( >+ '<option value="' + unique + >+ '">' + unique + '</option>' >+ ); >+ }); >+ }, >+ listener: function() { >+ var me = 'pickupBranch'; >+ $('#illfilter_branchname').change(function() { >+ var sel = $('#illfilter_branchname option:selected').val(); >+ if (sel && sel.length > 0) { >+ activeFilters[me] = function() { >+ table.api().column(12).search(sel); >+ } >+ } else { >+ if (activeFilters.hasOwnProperty(me)) { >+ delete activeFilters[me]; >+ } >+ } >+ }); >+ }, >+ clear: function() { >+ $('#illfilter_branchname').val(''); >+ } >+ }, >+ patron: { >+ listener: function() { >+ var me = 'patron'; >+ $('#illfilter_patron').change(function() { >+ var val = $('#illfilter_patron').val(); >+ if (val && val.length > 0) { >+ activeFilters[me] = function() { >+ table.api().column(10).search(val); >+ } >+ } else { >+ if (activeFilters.hasOwnProperty(me)) { >+ delete activeFilters[me]; >+ } >+ } >+ }); >+ }, >+ clear: function() { >+ $('#illfilter_patron').val(''); >+ } >+ }, >+ dateModified: { >+ clear: function() { >+ $('#illfilter_datemodified_start, #illfilter_datemodified_end').val(''); >+ } >+ }, >+ datePlaced: { >+ clear: function() { >+ $('#illfilter_dateplaced_start, #illfilter_dateplaced_end').val(''); >+ } >+ } >+ }; >+ >+ // Expand any fields we're expanding >+ var expandExpand = function(row) { >+ expand.forEach(function(thisExpand) { >+ if (row.hasOwnProperty(thisExpand)) { >+ if (!expanded.hasOwnProperty(thisExpand)) { >+ expanded[thisExpand] = []; >+ } >+ var expandObj = row[thisExpand]; >+ Object.keys(expandObj).forEach( >+ function(thisExpandCol) { >+ var expColName = thisExpand + '_' + thisExpandCol.replace(/\s/g,'_'); >+ // Keep a list of fields that have been expanded >+ // so we can create toggle links for them >+ if (expanded[thisExpand].indexOf(expColName) == -1) { >+ expanded[thisExpand].push(expColName); >+ } >+ expandObj[expColName] = >+ expandObj[thisExpandCol]; >+ delete expandObj[thisExpandCol]; >+ } >+ ); >+ $.extend(true, row, expandObj); >+ delete row[thisExpand]; >+ } >+ }); >+ }; >+ >+ // Strip the expand prefix if it exists, we do this for display >+ var stripPrefix = function(value) { >+ expand.forEach(function(thisExpand) { >+ var regex = new RegExp(thisExpand + '_', 'g'); >+ value = value.replace(regex, ''); >+ }); >+ return value; >+ }; >+ >+ // Our 'render' function for borrowerlink >+ var createPatronLink = function(data, type, row) { >+ var patronLink = '<a title="' + ill_borrower_details + '" ' + >+ 'href="/cgi-bin/koha/members/moremember.pl?' + >+ 'borrowernumber='+row.borrowernumber+'">'; >+ if ( row.patron_firstname ) { >+ patronLink = patronLink + row.patron_firstname + ' '; >+ } >+ patronLink = patronLink + row.patron_surname + >+ ' (' + row.patron_cardnumber + ')' + '</a>'; >+ return patronLink; >+ }; >+ >+ // Our 'render' function for biblio_id >+ var createBiblioLink = function(data, type, row) { >+ return (row.biblio_id) ? >+ '<a title="' + ill_biblio_details + '" ' + >+ 'href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=' + >+ row.biblio_id + '">' + >+ row.biblio_id + >+ '</a>' : ''; >+ }; >+ >+ // Our 'render' function for title >+ var createTitle = function(data, type, row) { >+ return ( >+ row.hasOwnProperty('metadata_container_title') && >+ row.metadata_container_title >+ ) ? row.metadata_container_title : row.metadata_title; >+ }; >+ >+ // Render function for request ID >+ var createRequestId = function(data, type, row) { >+ return row.id_prefix + row.illrequest_id; >+ }; >+ >+ // Render function for type >+ var createType = function(data, type, row) { >+ if (!row.hasOwnProperty('metadata_Type') || !row.metadata_Type) { >+ if (row.hasOwnProperty('medium') && row.medium) { >+ row.metadata_Type = row.medium; >+ } else { >+ row.metadata_Type = null; >+ } >+ } >+ return row.metadata_Type; >+ }; >+ >+ // Render function for request status >+ var createStatus = function(data, type, row, meta) { >+ if (row.status_alias) { >+ return row.status_alias.lib >+ ? row.status_alias.lib >+ : row.status_alias.authorised_value; >+ } else { >+ var origData = meta.settings.oInit.originalData; >+ if (origData.length > 0) { >+ var status_name = meta.settings.oInit.originalData[0].capabilities[ >+ row.status >+ ].name; >+ return getStatusName(status_name, row); >+ } else { >+ return ''; >+ } >+ } >+ }; >+ >+ var getStatusName = function(origName, row) { >+ switch( origName ) { >+ case "New request": >+ return ill_statuses.new; >+ case "Requested": >+ return ill_statuses.req; >+ case "Requested from partners": >+ var statStr = ill_statuses.genreq; >+ if ( >+ row.hasOwnProperty('requested_partners') && >+ row.requested_partners && >+ row.requested_partners.length > 0 >+ ) { >+ statStr += ' (' + row.requested_partners + ')'; >+ } >+ return statStr; >+ case "Request reverted": >+ return ill_statuses.rev; >+ case "Queued request": >+ return ill_statuses.que; >+ case "Cancellation requested": >+ return ill_statuses.canc; >+ case "Completed": >+ return ill_statuses.comp; >+ case "Delete request": >+ return ill_statuses.del; >+ default: >+ return origName; >+ } >+ }; >+ >+ // Render function for creating a row's action link >+ var createActionLink = function(data, type, row) { >+ return '<a class="btn btn-default btn-sm" ' + >+ 'href="/cgi-bin/koha/ill/ill-requests.pl?' + >+ 'method=illview&illrequest_id=' + >+ row.illrequest_id + >+ '">' + ill_manage + '</a>'; >+ }; >+ >+ // Columns that require special treatment >+ var specialCols = { >+ action: { >+ func: createActionLink, >+ skipSanitize: true >+ }, >+ illrequest_id: { >+ func: createRequestId >+ }, >+ status: { >+ func: createStatus >+ }, >+ biblio_id: { >+ name: ill_columns.biblio_id, >+ func: createBiblioLink, >+ skipSanitize: true >+ }, >+ metadata_title: { >+ func: createTitle >+ }, >+ metadata_Type: { >+ func: createType >+ }, >+ updated: { >+ name: ill_columns.updated >+ }, >+ patron: { >+ skipSanitize: true, >+ func: createPatronLink >+ } >+ }; >+ >+ // Display the modal containing request supplier metadata >+ $('#ill-request-display-log').on('click', function(e) { >+ e.preventDefault(); >+ $('#requestLog').modal({show:true}); >+ }); >+ >+ // Toggle request attributes in Illview >+ $('#toggle_requestattributes').on('click', function(e) { >+ e.preventDefault(); >+ $('#requestattributes').toggleClass('content_hidden'); >+ }); >+ >+ // Toggle new comment form in Illview >+ $('#toggle_addcomment').on('click', function(e) { >+ e.preventDefault(); >+ $('#addcomment').toggleClass('content_hidden'); >+ }); >+ >+ // Filter partner list >+ $('#partner_filter').keyup(function() { >+ var needle = $('#partner_filter').val(); >+ $('#partners > option').each(function() { >+ var regex = new RegExp(needle, 'i'); >+ if ( >+ needle.length == 0 || >+ $(this).is(':selected') || >+ $(this).text().match(regex) >+ ) { >+ $(this).show(); >+ } else { >+ $(this).hide(); >+ } >+ }); >+ }); >+ >+ // Display the modal containing request supplier metadata >+ $('#ill-request-display-metadata').on('click', function(e) { >+ e.preventDefault(); >+ $('#dataPreview').modal({show:true}); >+ }); >+ >+ // Allow us to chain Datatable render helpers together, so we >+ // can use our custom functions and render.text(), which >+ // provides us with data sanitization >+ $.fn.dataTable.render.multi = function(renderArray) { >+ return function(d, type, row, meta) { >+ for(var r = 0; r < renderArray.length; r++) { >+ var toCall = renderArray[r].hasOwnProperty('display') ? >+ renderArray[r].display : >+ renderArray[r]; >+ d = toCall(d, type, row, meta); >+ } >+ return d; >+ } >+ } >+ >+ // Get our data from the API and process it prior to passing >+ // it to datatables >+ var filterParam = prefilters ? '&' + prefilters : ''; >+ var ajax = $.ajax( >+ '/api/v1/illrequests?embed=metadata,patron,capabilities,library,status_alias,comments,requested_partners' >+ + filterParam >+ ).done(function() { >+ var data = JSON.parse(ajax.responseText); >+ // Make a copy, we'll be removing columns next and need >+ // to be able to refer to data that has been removed >+ var dataCopy = $.extend(true, [], data); >+ // Expand columns that need it and create an array >+ // of all column names >+ $.each(dataCopy, function(k, row) { >+ expandExpand(row); >+ }); >+ >+ // Assemble an array of column definitions for passing >+ // to datatables >+ var colData = []; >+ columns_settings.forEach(function(thisCol) { >+ var colName = thisCol.columnname; >+ // Create the base column object >+ var colObj = $.extend({}, thisCol); >+ colObj.name = colName; >+ colObj.className = colName; >+ colObj.defaultContent = ''; >+ >+ // We may need to process the data going in this >+ // column, so do it if necessary >+ if ( >+ specialCols.hasOwnProperty(colName) && >+ specialCols[colName].hasOwnProperty('func') >+ ) { >+ var renderArray = [ >+ specialCols[colName].func >+ ]; >+ if (!specialCols[colName].skipSanitize) { >+ renderArray.push( >+ $.fn.dataTable.render.text() >+ ); >+ } >+ >+ colObj.render = $.fn.dataTable.render.multi( >+ renderArray >+ ); >+ } else { >+ colObj.data = colName; >+ colObj.render = $.fn.dataTable.render.text() >+ } >+ // Make sure properties that aren't present in the API >+ // response are populated with null to avoid Datatables >+ // choking on their absence >+ dataCopy.forEach(function(thisData) { >+ if (!thisData.hasOwnProperty(colName)) { >+ thisData[colName] = null; >+ } >+ }); >+ colData.push(colObj); >+ }); >+ >+ // Initialise the datatable >+ table = KohaTable("ill-requests", { >+ 'aoColumnDefs': [ >+ { // Last column shouldn't be sortable or searchable >+ 'aTargets': [ 'actions' ], >+ 'bSortable': false, >+ 'bSearchable': false >+ }, >+ { // When sorting 'placed', we want to use the >+ // unformatted column >+ 'aTargets': [ 'placed_formatted'], >+ 'iDataSort': 14 >+ }, >+ { // When sorting 'updated', we want to use the >+ // unformatted column >+ 'aTargets': [ 'updated_formatted'], >+ 'iDataSort': 16 >+ }, >+ { // When sorting 'completed', we want to use the >+ // unformatted column >+ 'aTargets': [ 'completed_formatted'], >+ 'iDataSort': 19 >+ } >+ ], >+ 'aaSorting': [[ 16, 'desc' ]], // Default sort, updated descending >+ 'processing': true, // Display a message when manipulating >+ 'sPaginationType': "full_numbers", // Pagination display >+ 'deferRender': true, // Improve performance on big datasets >+ 'data': dataCopy, >+ 'columns': colData, >+ 'originalData': data, // Enable render functions to access >+ // our original data >+ 'initComplete': function() { >+ >+ // Prepare any filter elements that need it >+ for (var el in filterable) { >+ if (filterable.hasOwnProperty(el)) { >+ if (filterable[el].hasOwnProperty('prep')) { >+ filterable[el].prep(dataCopy, data); >+ } >+ if (filterable[el].hasOwnProperty('listener')) { >+ filterable[el].listener(); >+ } >+ } >+ } >+ >+ } >+ }, columns_settings); >+ >+ // Custom date range filtering >+ $.fn.dataTable.ext.search.push(function(settings, data, dataIndex) { >+ var placedStart = $('#illfilter_dateplaced_start').datepicker('getDate'); >+ var placedEnd = $('#illfilter_dateplaced_end').datepicker('getDate'); >+ var modifiedStart = $('#illfilter_datemodified_start').datepicker('getDate'); >+ var modifiedEnd = $('#illfilter_datemodified_end').datepicker('getDate'); >+ var rowPlaced = data[14] ? new Date(data[14]) : null; >+ var rowModified = data[16] ? new Date(data[16]) : null; >+ var placedPassed = true; >+ var modifiedPassed = true; >+ if (placedStart && rowPlaced && rowPlaced < placedStart) { >+ placedPassed = false >+ }; >+ if (placedEnd && rowPlaced && rowPlaced > placedEnd) { >+ placedPassed = false; >+ } >+ if (modifiedStart && rowModified && rowModified < modifiedStart) { >+ modifiedPassed = false >+ }; >+ if (modifiedEnd && rowModified && rowModified > modifiedEnd) { >+ modifiedPassed = false; >+ } >+ >+ return placedPassed && modifiedPassed; >+ >+ }); >+ >+ } >+ ); >+ >+ var clearSearch = function() { >+ table.api().search('').columns().search(''); >+ activeFilters = {}; >+ for (var filter in filterable) { >+ if ( >+ filterable.hasOwnProperty(filter) && >+ filterable[filter].hasOwnProperty('clear') >+ ) { >+ filterable[filter].clear(); >+ } >+ } >+ table.api().draw(); >+ }; >+ >+ // Apply any search filters, or clear any previous >+ // ones >+ $('#illfilter_form').submit(function(event) { >+ event.preventDefault(); >+ table.api().search('').columns().search(''); >+ for (var active in activeFilters) { >+ if (activeFilters.hasOwnProperty(active)) { >+ activeFilters[active](); >+ } >+ } >+ table.api().draw(); >+ }); >+ >+ // Clear all filters >+ $('#clear_search').click(function() { >+ clearSearch(); >+ }); >+ >+}); >diff --git a/members/ill-requests.pl b/members/ill-requests.pl >new file mode 100755 >index 0000000000..fad46ea91f >--- /dev/null >+++ b/members/ill-requests.pl >@@ -0,0 +1,55 @@ >+#!/usr/bin/perl >+ >+# This file is part of Koha. >+# >+# Copyright 2018 PTFS Europe >+# >+# 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::Auth; >+use C4::Output; >+use C4::Members; >+use C4::Members::Attributes qw(GetBorrowerAttributes); >+use Koha::Patrons; >+ >+my $input = new CGI; >+ >+my ( $template, $loggedinuser, $cookie ) = get_template_and_user( >+ { >+ template_name => "members/ill-requests.tt", >+ query => $input, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { borrowers => 'edit_borrowers' }, >+ debug => 1, >+ } >+); >+ >+my $borrowernumber = $input->param('borrowernumber'); >+ >+my $logged_in_user = Koha::Patrons->find( $loggedinuser ) or die "Not logged in"; >+my $patron = Koha::Patrons->find( $borrowernumber ); >+output_and_exit_if_error( $input, $cookie, $template, { module => 'members', logged_in_user => $logged_in_user, current_patron => $patron } ); >+ >+my $category = $patron->category; >+$template->param( >+ prefilters => "borrowernumber=$borrowernumber", >+ patron => $patron, >+ illview => 1, >+); >+ >+output_html_with_http_headers $input, $cookie, $template->output; >-- >2.11.0
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 18589
:
74809
|
79692
|
82177
|
82513
|
84197
|
84199
|
84204
|
84792
|
84796
|
86432
|
86433
|
86456
|
86465
|
86504
|
86506
|
86507
|
86714
|
86715
|
86716
|
86717
|
86718
|
86719
|
86720
|
86721
|
86722
|
86735
|
86736
|
86737