Bugzilla – Attachment 94849 Details for
Bug 14697
Extend and enhance "Claims returned" lost status
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 14697: Enhance the return claims feature [FIXME]
Bug-14697-Enhance-the-return-claims-feature-FIXME.patch (text/plain), 45.08 KB, created by
Kyle M Hall (khall)
on 2019-10-29 19:20:55 UTC
(
hide
)
Description:
Bug 14697: Enhance the return claims feature [FIXME]
Filename:
MIME Type:
Creator:
Kyle M Hall (khall)
Created:
2019-10-29 19:20:55 UTC
Size:
45.08 KB
patch
obsolete
>From 62c834496d57fd0e21abff5e519e290ce926e780 Mon Sep 17 00:00:00 2001 >From: Kyle M Hall <kyle@bywatersolutions.com> >Date: Tue, 29 Oct 2019 12:29:54 -0300 >Subject: [PATCH] Bug 14697: Enhance the return claims feature [FIXME] > >This adds a "Claims returned" feature that extends and enhances the claims returned lost status. >To use this feature, a new LOST status to represent an item claimed as returned needs to be created. >The value of this LOST authorised value should be set in the new syspref ClaimReturnedLostValue. >Setting this system preference turns on the feature. > >Once the feature is enabled, you should be able to mark checked out items as return claims from the >checkout and patron details pages, and also modify them from the new claims tab on those pages. > >Returning a claimed item will notify the librarian that the item in question has a claim on it. > >Setting the ClaimReturnedWarningThreshold will add an alert to make librarians aware that this >patron has many return claims on the patron's record. > >Test Plan: >1) Create a "Claims Returned" lost value >2) Create some RETURN_CLAIM_RESOLUTION authorized values >3) Set ClaimReturnedLostValue >4) Set ClaimReturnedChargeFee >5) Set ClaimReturnedWarningThreshold >6) Create some checkouts >7) Claim some returns >8) Verify ClaimReturnedChargeFee works with all 3 options >9) Verify ClaimReturnedWarningThreshold shows a warning once the threshold has been exceeded >10) Edit notes on a claim >11) Resolve a claim >12) Delete a claim > >Sponsored-by: North Central Regional Library System > >Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io> > >Signed-off-by: Andrew Fuerste-Henry <andrew@bywatersolutions.com> > >Signed-off-by: Lisette Scheer <lisetteslatah@gmail.com> >--- > circ/circulation.pl | 1 + > circ/returns.pl | 4 +- > .../prog/en/includes/checkouts-table.inc | 71 +++++ > .../prog/en/includes/patron-return-claims.inc | 15 + > .../prog/en/includes/strings.inc | 5 + > .../admin/preferences/circulation.pref | 19 ++ > .../prog/en/modules/catalogue/moredetail.tt | 36 ++- > .../prog/en/modules/circ/circulation.tt | 36 +++ > .../prog/en/modules/circ/returns.tt | 19 ++ > .../prog/en/modules/members/moremember.tt | 25 ++ > koha-tmpl/intranet-tmpl/prog/js/checkouts.js | 282 +++++++++++++++++- > members/moremember.pl | 1 + > svc/checkouts | 61 ++-- > svc/return_claims | 127 ++++++++ > 14 files changed, 666 insertions(+), 36 deletions(-) > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/includes/patron-return-claims.inc > create mode 100755 svc/return_claims > >diff --git a/circ/circulation.pl b/circ/circulation.pl >index 60e5455279..5bc227d032 100755 >--- a/circ/circulation.pl >+++ b/circ/circulation.pl >@@ -643,6 +643,7 @@ $template->param( > override_high_holds => $override_high_holds, > nopermission => scalar $query->param('nopermission'), > autoswitched => $autoswitched, >+ logged_in_user => $logged_in_user, > ); > > output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/circ/returns.pl b/circ/returns.pl >index 42226b4bcc..ddce95ab75 100755 >--- a/circ/returns.pl >+++ b/circ/returns.pl >@@ -542,7 +542,9 @@ foreach my $code ( keys %$messages ) { > elsif ( $code eq 'DataCorrupted' ) { > $err{data_corrupted} = 1; > } >- else { >+ elsif ( $code eq 'ReturnClaims' ) { >+ $template->param( ReturnClaims => $messages->{ReturnClaims} ); >+ } else { > die "Unknown error code $code"; # note we need all the (empty) elsif's above, or we die. > # This forces the issue of staying in sync w/ Circulation.pm > } >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc >index 1276e70ab1..f1bc60ff4b 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc >@@ -28,6 +28,7 @@ > <th scope="col">Price</th> > <th scope="col">Renew <p class="column-tool"><a href="#" id="CheckAllRenewals">select all</a> | <a href="#" id="UncheckAllRenewals">none</a></p></th> > <th scope="col">Check in <p class="column-tool"><a href="#" id="CheckAllCheckins">select all</a> | <a href="#" id="UncheckAllCheckins">none</a></p></th> >+ <th scope="col">Return claims</th> > <th scope="col">Export <p class="column-tool"><a href="#" id="CheckAllExports">select all</a> | <a href="#" id="UncheckAllExports">none</a></p></th> > </tr> > </thead> >@@ -83,3 +84,73 @@ > <p>Patron has nothing checked out.</p> > [% END %] > </div> >+ >+<!-- Claims Returned Modal --> >+<div class="modal fade" id="claims-returned-modal" tabindex="-1" role="dialog" aria-labelledby="claims-returned-modal-label"> >+ <div class="modal-dialog" role="document"> >+ <div class="modal-content"> >+ <div class="modal-header"> >+ <h4 class="modal-title" id="claims-returned-modal-label">Claim returned</h4> >+ </div> >+ <div class="modal-body"> >+ >+ <div class="form-group"> >+ <label for="claims-returned-notes" class="control-label">Notes</label> >+ <div> >+ <textarea id="claims-returned-notes" class="form-control" rows="3"></textarea> >+ </div> >+ </div> >+ >+ [% IF Koha.Preference('ClaimReturnedChargeFee') == 'ask' %] >+ <div class="form-group"> >+ <div class="checkbox"> >+ <label for="claims-returned-charge-lost-fee"> >+ <input id="claims-returned-charge-lost-fee" type="checkbox" value="1"> >+ Charge lost fee >+ </label> >+ </div> >+ </div> >+ [% END %] >+ >+ <input type="hidden" id="claims-returned-itemnumber" /> >+ </div> >+ <div class="modal-footer"> >+ <button id="claims-returned-modal-btn-submit" type="button" class="btn btn-primary"><i class="fa fa-exclamation-circle"></i> Make claim</button> >+ <button class="btn btn-default deny cancel" href="#" data-dismiss="modal" aria-hidden="true"><i class="fa fa-times"></i> Cancel</button> >+ </div> >+ </div> >+ </div> >+</div> >+ >+<!-- Resolve Return Claim Modal --> >+<div class="modal fade" id="claims-returned-resolved-modal" tabindex="-1" role="dialog" aria-labelledby="claims-returned-resolved-modal-label"> >+ <div class="modal-dialog" role="document"> >+ <div class="modal-content"> >+ <div class="modal-header"> >+ <h4 class="modal-title" id="claims-returned-resolved-modal-label">Resolve return claim</h4> >+ </div> >+ <div class="modal-body"> >+ >+ <div class="form-group"> >+ <label for="claims-returned-resolved-code">Resolution</label> >+ [% SET resolutions = AuthorisedValues.GetAuthValueDropbox('RETURN_CLAIM_RESOLUTION') %] >+ <select class="form-control" id="claims-returned-resolved-modal-resolved-code"> >+ [% FOREACH r IN resolutions %] >+ <option value="[% r.authorised_value | html %]">[% r.lib | html %]</option> >+ [% END %] >+ </select> >+ </div> >+ >+ <input type="hidden" id="claims-returned-resolved-modal-id"/> >+ </div> >+ <div class="modal-footer"> >+ <button id="claims-returned-resolved-modal-btn-submit" type="button" class="btn btn-primary"> >+ <i id="claims-returned-resolved-modal-btn-submit-icon" class="fa fa-exclamation-circle"></i> >+ <i id="claims-returned-resolved-modal-btn-submit-spinner" class="fa fa-spinner fa-pulse fa-fw" style="display:none"></i> >+ Resolve claim >+ </button> >+ <button class="btn btn-default deny cancel" href="#" data-dismiss="modal" aria-hidden="true"><i class="fa fa-times"></i> Cancel</button> >+ </div> >+ </div> >+ </div> >+</div> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-return-claims.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-return-claims.inc >new file mode 100644 >index 0000000000..63f1dad303 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-return-claims.inc >@@ -0,0 +1,15 @@ >+<div id="return-claims"> >+ <table id="return-claims-table" class="table table-bordered table-striped"> >+ <thead> >+ <tr> >+ <th class="return-claim-id">Claim ID</th> >+ <th class="return-claim-record-title anti-the">Title</th> >+ <th class="return-claim-notes">Notes</th> >+ <th class="return-claim-created-on">Created on</th> >+ <th class="return-claim-updated-on">Updated on</th> >+ <th class="return-claim-resolution">Resolution</th> >+ <th class="return-claim-actions"> </th> >+ </tr> >+ </thead> >+ </table> >+</div> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/strings.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/strings.inc >index e88a90fb6d..7eba12b93e 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/strings.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/strings.inc >@@ -5,6 +5,10 @@ > var NOT_RENEWABLE_RESTRICTION = _("Not allowed: patron restricted"); > var CIRCULATION_RENEWED_DUE = _("Renewed, due:"); > var CIRCULATION_RENEW_FAILED = _("Renew failed:"); >+ var RETURN_CLAIMED = _("Return claimed"); >+ var RETURN_CLAIMED_FAILURE = _("Unable to claim as returned"); >+ var RETURN_CLAIMED_MAKE = _("Claim returned"); >+ var RETURN_CLAIMED_NOTES = _("Notes about return claim"); > var NOT_CHECKED_OUT = _("not checked out"); > var TOO_MANY_RENEWALS = _("too many renewals"); > var ON_RESERVE = _("on hold"); >@@ -47,4 +51,5 @@ > var MSG_NO_ITEMTYPE = _("No itemtype"); > var MSG_CHECKOUTS_BY_ITEMTYPE = _("Number of checkouts by item type"); > var PATRON_NOTE = _("Patron note"); >+ var CONFIRM_DELETE_RETURN_CLAIM = _("Are you sure you want to delete this return claim?"); > </script> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref >index 3c24d51273..f7ab923def 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref >@@ -1084,3 +1084,22 @@ Circulation: > pages: Pages > chapters: Chapters > - >+ Return Claims: >+ - >+ - When marking a checkout as "claims returned", >+ - pref: ClaimReturnedChargeFee >+ default: ask >+ choices: >+ ask: ask if a lost fee should be charged >+ charge: charge a lost fee >+ no_charge: don't charge a lost fee >+ - . >+ - >+ - Use the LOST authorised value >+ - pref: ClaimReturnedLostValue >+ - to represent returns claims >+ - >+ - Warn librarians that a patron has excessive return cliams if the patron has claimed the return of more than >+ - pref: ClaimReturnedWarningThreshold >+ class: integer >+ - items. >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt >index 0a6d0609eb..8d5e712567 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt >@@ -100,21 +100,31 @@ > <li><span class="label">Lost status:</span> > [% IF ( CAN_user_circulate ) %] > <form action="updateitem.pl" method="post"> >- <input type="hidden" name="biblionumber" value="[% ITEM_DAT.biblionumber | html %]" /> >- <input type="hidden" name="biblioitemnumber" value="[% ITEM_DAT.biblioitemnumber | html %]" /> >- <input type="hidden" name="itemnumber" value="[% ITEM_DAT.itemnumber | html %]" /> >- <select name="itemlost" > >- <option value="">Choose</option> >- [% FOREACH itemlostloo IN itemlostloop %] >- [% IF itemlostloo.authorised_value == ITEM_DAT.itemlost %] >- <option value="[% itemlostloo.authorised_value | html %]" selected="selected">[% itemlostloo.lib | html %]</option> >+ <input type="hidden" name="biblionumber" value="[% ITEM_DAT.biblionumber | html %]" /> >+ <input type="hidden" name="biblioitemnumber" value="[% ITEM_DAT.biblioitemnumber | html %]" /> >+ <input type="hidden" name="itemnumber" value="[% ITEM_DAT.itemnumber | html %]" /> >+ <select name="itemlost" > >+ <option value="">Choose</option> >+ [% FOREACH itemlostloo IN itemlostloop %] >+ [% IF itemlostloo.authorised_value == ITEM_DAT.itemlost %] >+ <option value="[% itemlostloo.authorised_value | html %]" selected="selected">[% itemlostloo.lib | html %]</option> >+ [% ELSE %] >+ <option value="[% itemlostloo.authorised_value | html %]">[% itemlostloo.lib | html %]</option> >+ [% END %] >+ [% END %] >+ </select> >+ <input type="hidden" name="withdrawn" value="[% ITEM_DAT.withdrawn | html %]" /> >+ <input type="hidden" name="damaged" value="[% ITEM_DAT.damaged | html %]" /> >+ >+ [% SET ClaimReturnedLostValue = Koha.Preference('ClaimReturnedLostValue') %] >+ [% IF ClaimReturnedLostValue && ITEM_DAT.itemlost == ClaimReturnedLostValue %] >+ <input type="submit" name="submit" class="submit" value="Set status" disabled="disabled"/> >+ <p class="help-block">Item has been claimed as returned.</p> > [% ELSE %] >- <option value="[% itemlostloo.authorised_value | html %]">[% itemlostloo.lib | html %]</option> >+ <input type="hidden" name="op" value="set_lost" /> >+ <input type="submit" name="submit" class="submit" value="Set status" /></form> > [% END %] >- [% END %] >- </select> >- <input type="hidden" name="op" value="set_lost" /> >- <input type="submit" name="submit" class="submit" value="Set status" /></form> >+ </form> > [% ELSE %] > [% FOREACH itemlostloo IN itemlostloop %] > [% IF ( itemlostloo.selected ) %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt >index 86803440d4..acbe85abab 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt >@@ -732,6 +732,12 @@ > <li><span class="circ-hlt">Overdues: Patron has ITEMS OVERDUE.</span> <a href="#checkouts">See highlighted items below</a></li> > [% END %] > >+ [% SET ClaimReturnedWarningThreshold = Koha.Preference('ClaimReturnedWarningThreshold') %] >+ [% SET return_claims = patron.return_claims %] >+ [% IF return_claims.count %] >+ <li><span class="circ-hlt return-claims">Return claims: Patron has [% return_claims.count | html %] RETURN CLAIMS.</span> >+ [% END %] >+ > [% IF ( charges ) %] > [% INCLUDE 'blocked-fines.inc' fines = chargesamount %] > [% END %] >@@ -845,6 +851,30 @@ > </li> > [% END %] > >+ <li> >+ [% IF ( patron.return_claims.count ) %] >+ <a href="#return-claims" id="return-claims-tab"> >+ <span id="return-claims-count-resolved">[% patron.return_claims.resolved.count | html %]</span> >+ / >+ <span id="return-claims-count-unresolved">[% patron.return_claims.unresolved.count | html %]</span> >+ Claim(s) >+ </a> >+ [% ELSE %] >+ <a href="#return-claims" id="return-claims-tab"> >+ <span id="return-claims-count-resolved">0</span> >+ / >+ <span id="return-claims-count-unresolved">0</span> >+ Claim(s) >+ </a> >+ [% END %] >+ </li> >+ >+ [% IF Koha.Preference('ArticleRequests') %] >+ <li> >+ <a href="#article-requests" id="article-requests-tab"> [% patron.article_requests_current.count | html %] Article requests</a> >+ </li> >+ [% END %] >+ > <li><a id="debarments-tab-link" href="#reldebarments">[% debarments.count | html %] Restrictions</a></li> > > [% SET enrollments = patron.get_club_enrollments(1) %] >@@ -928,6 +958,8 @@ > [% END # /IF holds_count %] > </div> <!-- /#reserves --> > >+ [% INCLUDE 'patron-return-claims.inc' %] >+ > [% IF Koha.Preference('ArticleRequests') %] > [% INCLUDE 'patron-article-requests.inc' %] > [% END %] >@@ -995,6 +1027,10 @@ > [% Asset.js("js/circ-patron-search-results.js") | $raw %] > <script type="text/javascript"> > /* Set some variable needed in circulation.js */ >+ var logged_in_user_borrowernumber = "[% logged_in_user.borrowernumber | html %]"; >+ var ClaimReturnedLostValue = "[% Koha.Preference('ClaimReturnedLostValue') | html %]"; >+ var ClaimReturnedChargeFee = "[% Koha.Preference('ClaimReturnedChargeFee') | html %]"; >+ var ClaimReturnedWarningThreshold = "[% Koha.Preference('ClaimReturnedWarningThreshold') | html %]"; > var MSG_DT_LOADING_RECORDS = _("Loading... you may continue scanning."); > var interface = "[% interface | html %]"; > var theme = "[% theme | html %]"; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >index dd359dd881..6294c06d2a 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >@@ -156,6 +156,25 @@ > </div> > [% END %] > >+ <!-- Item has return claim(s) --> >+ [% IF ( ReturnClaims ) %] >+ <div class="dialog alert return-claim"> >+ <h3> >+ This item has been claimed as returned by: >+ <ul> >+ [% FOREACH rc IN ReturnClaims %] >+ [% SET patron = rc.patron %] >+ <li> >+ <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% patron.borrowernumber | uri %]"> >+ [% patron.firstname | html %] [% patron.surname | html %] >+ </a> >+ </li> >+ [% END %] >+ </ul> >+ </h3> >+ </div> >+ [% END %] >+ > <!-- Patron has waiting holds --> > [% IF ( waiting_holds ) %] > <div id="awaiting-pickup" class="dialog message"> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt >index ac14659230..bf6dac9b8d 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt >@@ -715,6 +715,25 @@ > <a href="#article-requests" id="article-requests-tab"> [% patron.article_requests_current.count | html %] Article requests</a> > </li> > [% END %] >+ >+ <li> >+ [% IF ( patron.return_claims.count ) %] >+ <a href="#return-claims" id="return-claims-tab"> >+ <span id="return-claims-count-resolved">[% patron.return_claims.resolved.count | html %]</span> >+ / >+ <span id="return-claims-count-unresolved">[% patron.return_claims.unresolved.count | html %]</span> >+ Claim(s) >+ </a> >+ [% ELSE %] >+ <a href="#return-claims" id="return-claims-tab"> >+ <span id="return-claims-count-resolved">0</span> >+ / >+ <span id="return-claims-count-unresolved">0</span> >+ Claim(s) >+ </a> >+ [% END %] >+ </li> >+ > <li> > <a id="debarments-tab-link" href="#reldebarments">[% debarments.size | html %] Restrictions</a> > </li> >@@ -807,6 +826,8 @@ > </div> [% # /div#reserves %] > [% END %] > >+ [% INCLUDE 'patron-return-claims.inc' %] >+ > [% IF Koha.Preference('ArticleRequests') %] > [% INCLUDE 'patron-article-requests.inc' %] > [% END %] >@@ -839,6 +860,10 @@ > [% Asset.js("js/messaging-preference-form.js") | $raw %] > <script> > /* Set some variable needed in circulation.js */ >+ var logged_in_user_borrowernumber = "[% logged_in_user.borrowernumber | html %]"; >+ var ClaimReturnedLostValue = "[% Koha.Preference('ClaimReturnedLostValue') | html %]"; >+ var ClaimReturnedChargeFee = "[% Koha.Preference('ClaimReturnedChargeFee') | html %]"; >+ var ClaimReturnedWarningThreshold = "[% Koha.Preference('ClaimReturnedWarningThreshold') | html %]"; > var interface = "[% interface | html %]"; > var theme = "[% theme | html %]"; > var borrowernumber = "[% patron.borrowernumber | html %]"; >diff --git a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js >index e317f5747d..2bfd18e6cf 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js >@@ -270,7 +270,9 @@ $(document).ready(function() { > > due = "<span id='date_due_" + oObj.itemnumber + "' class='date_due'>" + due + "</span>"; > >- if ( oObj.lost ) { >+ if ( oObj.lost && oObj.claims_returned ) { >+ due += "<span class='lost claims_returned'>" + oObj.lost.escapeHtml() + "</span>"; >+ } else if ( oObj.lost ) { > due += "<span class='lost'>" + oObj.lost.escapeHtml() + "</span>"; > } > >@@ -540,6 +542,20 @@ $(document).ready(function() { > } > } > }, >+ { >+ "bVisible": ClaimReturnedLostValue ? true : false, >+ "bSortable": false, >+ "mDataProp": function ( oObj ) { >+ let content = ""; >+ >+ if ( oObj.return_claim_id ) { >+ content = `<span class="badge">${oObj.return_claim_created_on_formatted}</span>`; >+ } else { >+ content = `<a class="btn btn-default btn-xs claim-returned-btn" data-itemnumber="${oObj.itemnumber}"><i class="fa fa-exclamation-circle"></i> ${RETURN_CLAIMED_MAKE}</a>`; >+ } >+ return content; >+ } >+ }, > { > "bVisible": exports_enabled == 1 ? true : false, > "bSortable": false, >@@ -810,4 +826,268 @@ $(document).ready(function() { > } > } ).prop('checked', false); > } >+ >+ // Handle return claims >+ $(document).on("click", '.claim-returned-btn', function(e){ >+ e.preventDefault(); >+ itemnumber = $(this).data('itemnumber'); >+ >+ $('#claims-returned-itemnumber').val(itemnumber); >+ $('#claims-returned-notes').val(""); >+ $('#claims-returned-charge-lost-fee').attr('checked', false) >+ $('#claims-returned-modal').modal() >+ }); >+ $(document).on("click", '#claims-returned-modal-btn-submit', function(e){ >+ let itemnumber = $('#claims-returned-itemnumber').val(); >+ let notes = $('#claims-returned-notes').val(); >+ let fee = $('#claims-returned-charge-lost-fee').attr('checked') ? true : false; >+ >+ $('#claims-returned-modal').modal('hide') >+ >+ $(`.claim-returned-btn[data-itemnumber='${itemnumber}']`).replaceWith(`<img id='return_claim_spinner_${itemnumber}' src='${interface}/${theme}/img/spinner-small.gif' />`); >+ >+ params = { >+ item_id: itemnumber, >+ notes: notes, >+ charge_lost_fee: fee, >+ created_by: logged_in_user_borrowernumber, >+ }; >+ >+ $.post( '/api/v1/return_claims', JSON.stringify(params), function( data ) { >+ >+ id = "#return_claim_spinner_" + data.item_id; >+ >+ let created_on = new Date(data.created_on); >+ >+ let content = ""; >+ if ( data.claim_id ) { >+ content = `<span class="badge">${created_on.toLocaleDateString()}</span>`; >+ $(id).parent().parent().addClass('ok'); >+ } else { >+ content = RETURN_CLAIMED_FAILURE; >+ $(id).parent().parent().addClass('warn'); >+ } >+ >+ $(id).replaceWith( content ); >+ >+ refreshReturnClaimsTable(); >+ }, "json") >+ >+ }); >+ >+ >+ // Don't load return claims table unless it is clicked on >+ var returnClaimsTable; >+ $("#return-claims-tab").click( function() { >+ refreshReturnClaimsTable(); >+ }); >+ >+ function refreshReturnClaimsTable(){ >+ loadReturnClaimsTable(); >+ $("#return-claims-table").DataTable().ajax.reload(); >+ } >+ function loadReturnClaimsTable() { >+ if ( ! returnClaimsTable ) { >+ returnClaimsTable = $("#return-claims-table").dataTable({ >+ "bAutoWidth": false, >+ "sDom": "rt", >+ "aaSorting": [], >+ "aoColumns": [ >+ { >+ "mDataProp": "id", >+ "bVisible": false, >+ }, >+ { >+ "mDataProp": function ( oObj ) { >+ let title = `<a class="return-claim-title strong" href="/cgi-bin/koha/circ/request-rcticle.pl?biblionumber=[% rc.checkout.item.biblionumber | html %]"> >+ ${oObj.title} >+ ${oObj.enumchron || ""} >+ </a>`; >+ if ( oObj.author ) { >+ title += `by ${oObj.author}`; >+ } >+ title += `<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=${oObj.biblionumber}&itemnumber=${oObj.itemnumber}">${oObj.barcode}</a>`; >+ >+ return title; >+ } >+ }, >+ { >+ "sClass": "return-claim-notes-td", >+ "mDataProp": function ( oObj ) { >+ return ` >+ <span id="return-claim-notes-static-${oObj.id}" class="return-claim-notes" data-return-claim-id="${oObj.id}">${oObj.notes}</span> >+ <i style="float:right" class="fa fa-pencil-square-o" title="Double click to edit"></i> >+ `; >+ } >+ }, >+ { >+ "mDataProp": function ( oObj ) { >+ let created_on = new Date( oObj.created_on ); >+ return created_on.toLocaleDateString(); >+ } >+ }, >+ { >+ "mDataProp": function ( oObj ) { >+ let updated_on = new Date( oObj.updated_on ); >+ return updated_on.toLocaleDateString(); >+ } >+ }, >+ { >+ "mDataProp": function ( oObj ) { >+ if ( ! oObj.resolution ) return ""; >+ >+ let desc = `<strong>${oObj.resolution_data.lib}</strong> on <i>${oObj.resolved_on}</i>`; >+ if (oObj.resolved_by_data) desc += ` by <a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=${oObj.resolved_by_data.borrowernumber}">${oObj.resolved_by_data.firstname || ""} ${oObj.resolved_by_data.surname || ""}</a>`; >+ return desc; >+ } >+ }, >+ { >+ "mDataProp": function ( oObj ) { >+ let delete_html = oObj.resolved_on >+ ? `<li><a href="#" class="return-claim-tools-delete" data-return-claim-id="${oObj.id}"><i class="fa fa-trash"></i> Delete</a></li>` >+ : ""; >+ let resolve_html = ! oObj.resolution >+ ? `<li><a href="#" class="return-claim-tools-resolve" data-return-claim-id="${oObj.id}"><i class="fa fa-check-square"></i> Resolve</a></li>` >+ : ""; >+ >+ return ` >+ <div class="btn-group"> >+ <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> >+ Actions <span class="caret"></span> >+ </button> >+ <ul class="dropdown-menu"> >+ <li><a href="#" class="return-claim-tools-editnotes" data-return-claim-id="${oObj.id}"><i class="fa fa-edit"></i> Edit notes</a></li> >+ ${resolve_html} >+ ${delete_html} >+ </ul> >+ </div> >+ `; >+ } >+ }, >+ ], >+ "bPaginate": false, >+ "bProcessing": true, >+ "bServerSide": false, >+ "sAjaxSource": '/cgi-bin/koha/svc/return_claims', >+ "fnServerData": function ( sSource, aoData, fnCallback ) { >+ aoData.push( { "name": "borrowernumber", "value": borrowernumber } ); >+ >+ $.getJSON( sSource, aoData, function (json) { >+ let resolved = json.resolved; >+ let unresolved = json.unresolved; >+ >+ $('#return-claims-count-resolved').text(resolved); >+ $('#return-claims-count-unresolved').text(unresolved); >+ >+ fnCallback(json) >+ } ); >+ }, >+ }); >+ } >+ } >+ >+ $('body').on('click', '.return-claim-tools-editnotes', function() { >+ let id = $(this).data('return-claim-id'); >+ $(`#return-claim-notes-static-${id}`).parent().dblclick(); >+ }); >+ $('body').on('dblclick', '.return-claim-notes-td', function() { >+ let elt = $(this).children('.return-claim-notes'); >+ let id = elt.data('return-claim-id'); >+ if ( $(`#return-claim-notes-editor-textarea-${id}`).length == 0 ) { >+ let note = elt.text(); >+ let editor = ` >+ <span id="return-claim-notes-editor-${id}"> >+ <textarea id="return-claim-notes-editor-textarea-${id}">${note}</textarea> >+ <br/> >+ <a class="btn btn-default btn-xs claim-returned-notes-editor-submit" data-return-claim-id="${id}"><i class="fa fa-save"></i> Update</a> >+ <a class="claim-returned-notes-editor-cancel" data-return-claim-id="${id}" href="#">Cancel</a> >+ </span> >+ `; >+ elt.hide(); >+ $(editor).insertAfter( elt ); >+ } >+ }); >+ >+ $('body').on('click', '.claim-returned-notes-editor-submit', function(){ >+ let id = $(this).data('return-claim-id'); >+ let notes = $(`#return-claim-notes-editor-textarea-${id}`).val(); >+ >+ let params = { >+ notes: notes, >+ updated_by: logged_in_user_borrowernumber >+ }; >+ >+ $(this).parent().remove(); >+ >+ $.ajax({ >+ url: `/api/v1/return_claims/${id}/notes`, >+ type: 'PUT', >+ data: JSON.stringify(params), >+ success: function( data ) { >+ let notes = $(`#return-claim-notes-static-${id}`); >+ notes.text(data.notes); >+ notes.show(); >+ }, >+ contentType: "json" >+ }); >+ }); >+ >+ $('body').on('click', '.claim-returned-notes-editor-cancel', function(){ >+ let id = $(this).data('return-claim-id'); >+ $(this).parent().remove(); >+ $(`#return-claim-notes-static-${id}`).show(); >+ }); >+ >+ // Hanld return claim deletion >+ $('body').on('click', '.return-claim-tools-delete', function() { >+ let confirmed = confirm(CONFIRM_DELETE_RETURN_CLAIM); >+ if ( confirmed ) { >+ let id = $(this).data('return-claim-id'); >+ >+ $.ajax({ >+ url: `/api/v1/return_claims/${id}`, >+ type: 'DELETE', >+ success: function( data ) { >+ refreshReturnClaimsTable(); >+ } >+ }); >+ } >+ }); >+ >+ // Handle return claim resolution >+ $('body').on('click', '.return-claim-tools-resolve', function() { >+ let id = $(this).data('return-claim-id'); >+ >+ $('#claims-returned-resolved-modal-id').val(id); >+ $('#claims-returned-resolved-modal').modal() >+ }); >+ >+ $(document).on('click', '#claims-returned-resolved-modal-btn-submit', function(e) { >+ let resolution = $('#claims-returned-resolved-modal-resolved-code').val(); >+ let id = $('#claims-returned-resolved-modal-id').val(); >+ >+ $('#claims-returned-resolved-modal-btn-submit-spinner').show(); >+ $('#claims-returned-resolved-modal-btn-submit-icon').hide(); >+ >+ params = { >+ resolution: resolution, >+ updated_by: logged_in_user_borrowernumber >+ }; >+ >+ $.ajax({ >+ url: `/api/v1/return_claims/${id}/resolve`, >+ type: 'PUT', >+ data: JSON.stringify(params), >+ success: function( data ) { >+ $('#claims-returned-resolved-modal-btn-submit-spinner').hide(); >+ $('#claims-returned-resolved-modal-btn-submit-icon').show(); >+ $('#claims-returned-resolved-modal').modal('hide') >+ >+ refreshReturnClaimsTable(); >+ }, >+ contentType: "json" >+ }); >+ >+ }); >+ > }); >diff --git a/members/moremember.pl b/members/moremember.pl >index 593b0d1156..a2ba396020 100755 >--- a/members/moremember.pl >+++ b/members/moremember.pl >@@ -209,6 +209,7 @@ $template->param( > housebound_role => scalar $patron->housebound_role, > relatives_issues_count => $relatives_issues_count, > relatives_borrowernumbers => \@relatives, >+ logged_in_user => $logged_in_user, > ); > > output_html_with_http_headers $input, $cookie, $template->output; >diff --git a/svc/checkouts b/svc/checkouts >index 892eab84fe..053b589843 100755 >--- a/svc/checkouts >+++ b/svc/checkouts >@@ -64,28 +64,28 @@ print $input->header( -type => 'text/plain', -charset => 'UTF-8' ); > my @parameters; > my $sql = ' > SELECT >- issuedate, >- date_due, >- date_due < now() as date_due_overdue, >+ issues.issuedate, >+ issues.date_due, >+ issues.date_due < now() as date_due_overdue, > issues.timestamp, > >- onsite_checkout, >+ issues.onsite_checkout, > >- biblionumber, >+ biblio.biblionumber, > biblio.title, > biblio.subtitle, > biblio.medium, > biblio.part_number, > biblio.part_name, >- author, >+ biblio.author, > >- itemnumber, >- barcode, >+ items.itemnumber, >+ items.barcode, > branches2.branchname AS homebranch, >- itemnotes, >- itemnotes_nonpublic, >- itemcallnumber, >- replacementprice, >+ items.itemnotes, >+ items.itemnotes_nonpublic, >+ items.itemcallnumber, >+ items.replacementprice, > > issues.branchcode, > branches.branchname, >@@ -95,17 +95,23 @@ my $sql = ' > > items.ccode AS collection, > >- borrowernumber, >- surname, >- firstname, >- cardnumber, >+ borrowers.borrowernumber, >+ borrowers.surname, >+ borrowers.firstname, >+ borrowers.cardnumber, > >- itemlost, >- damaged, >- location, >+ items.itemlost, >+ items.damaged, >+ items.location, > items.enumchron, > >- DATEDIFF( issuedate, CURRENT_DATE() ) AS not_issued_today >+ DATEDIFF( issues.issuedate, CURRENT_DATE() ) AS not_issued_today, >+ >+ return_claims.id AS return_claim_id, >+ return_claims.notes AS return_claim_notes, >+ return_claims.created_on AS return_claim_created_on, >+ return_claims.updated_on AS return_claim_updated_on >+ > FROM issues > LEFT JOIN items USING ( itemnumber ) > LEFT JOIN biblio USING ( biblionumber ) >@@ -113,7 +119,8 @@ my $sql = ' > LEFT JOIN borrowers USING ( borrowernumber ) > LEFT JOIN branches ON ( issues.branchcode = branches.branchcode ) > LEFT JOIN branches branches2 ON ( items.homebranch = branches2.branchcode ) >- WHERE borrowernumber >+ LEFT JOIN return_claims USING ( issue_id ) >+ WHERE issues.borrowernumber > '; > > if ( @borrowernumber == 1 ) { >@@ -131,6 +138,7 @@ my $sth = $dbh->prepare($sql); > $sth->execute(@parameters); > > my $item_level_itypes = C4::Context->preference('item-level_itypes'); >+my $claims_returned_lost_value = C4::Context->preference('ClaimReturnedLostValue'); > > my @checkouts_today; > my @checkouts_previous; >@@ -165,9 +173,11 @@ while ( my $c = $sth->fetchrow_hashref() ) { > $collection = $av->count ? $av->next->lib : ''; > } > my $lost; >+ my $claims_returned; > if ( $c->{itemlost} ) { > my $av = Koha::AuthorisedValues->search({ category => 'LOST', authorised_value => $c->{itemlost} }); > $lost = $av->count ? $av->next->lib : ''; >+ $claims_returned = $c->{itemlost} eq $claims_returned_lost_value; > } > my $damaged; > if ( $c->{damaged} ) { >@@ -212,6 +222,14 @@ while ( my $c = $sth->fetchrow_hashref() ) { > renewals_count => $renewals_count, > renewals_allowed => $renewals_allowed, > renewals_remaining => $renewals_remaining, >+ >+ return_claim_id => $c->{return_claim_id}, >+ return_claim_notes => $c->{return_claim_notes}, >+ return_claim_created_on => $c->{return_claim_created_on}, >+ return_claim_updated_on => $c->{return_claim_updated_on}, >+ return_claim_created_on_formatted => $c->{return_claim_created_on} ? output_pref({ dt => dt_from_string( $c->{return_claim_created_on} ) }) : undef, >+ return_claim_updated_on_formatted => $c->{return_claim_updated_on} ? output_pref({ dt => dt_from_string( $c->{return_claim_updated_on} ) }) : undef, >+ > issuedate_formatted => output_pref( > { > dt => dt_from_string( $c->{issuedate} ), >@@ -225,6 +243,7 @@ while ( my $c = $sth->fetchrow_hashref() ) { > } > ), > lost => $lost, >+ claims_returned => $claims_returned, > damaged => $damaged, > borrower => { > surname => $c->{surname}, >diff --git a/svc/return_claims b/svc/return_claims >new file mode 100755 >index 0000000000..e10d5f174e >--- /dev/null >+++ b/svc/return_claims >@@ -0,0 +1,127 @@ >+#!/usr/bin/perl >+ >+# Copyright 2019 ByWater Solutions >+# >+# This file is part of Koha. >+# >+# 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, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use CGI; >+use JSON qw(to_json); >+ >+use C4::Auth qw(check_cookie_auth haspermission get_session); >+use C4::Context; >+ >+use Koha::AuthorisedValues; >+use Koha::DateUtils; >+use Koha::Patrons; >+ >+my $input = new CGI; >+ >+my ( $auth_status, $sessionID ) = >+ check_cookie_auth( $input->cookie('CGISESSID') ); >+ >+my $session = get_session($sessionID); >+my $userid = $session->param('id'); >+ >+unless ( >+ haspermission( >+ $userid, { circulate => 'circulate_remaining_permissions' } >+ ) >+ || haspermission( $userid, { borrowers => 'edit_borrowers' } ) >+ ) >+{ >+ exit 0; >+} >+ >+my @sort_columns = qw/title notes created_on updated_on/; >+ >+my $borrowernumber = $input->param('borrowernumber'); >+my $offset = $input->param('iDisplayStart'); >+my $results_per_page = $input->param('iDisplayLength') || -1; >+ >+my $sorting_column = $input->param('iSortCol_0') || q{}; >+$sorting_column = >+ ( $sorting_column && $sort_columns[$sorting_column] ) >+ ? $sort_columns[$sorting_column] >+ : 'created_on'; >+ >+my $sorting_direction = $input->param('sSortDir_0') || q{}; >+$sorting_direction = $sorting_direction eq 'asc' ? 'asc' : 'desc'; >+ >+$results_per_page = undef if ( $results_per_page == -1 ); >+ >+binmode STDOUT, ":encoding(UTF-8)"; >+print $input->header( -type => 'text/plain', -charset => 'UTF-8' ); >+ >+my $sql = qq{ >+ SELECT >+ return_claims.*, >+ >+ biblio.biblionumber, >+ biblio.title, >+ biblio.author, >+ >+ items.enumchron, >+ items.barcode >+ FROM return_claims >+ LEFT JOIN items USING ( itemnumber ) >+ LEFT JOIN biblio USING ( biblionumber ) >+ LEFT JOIN biblioitems USING ( biblionumber ) >+ WHERE return_claims.borrowernumber = ? >+ ORDER BY $sorting_column $sorting_direction >+}; >+ >+my $dbh = C4::Context->dbh(); >+my $sth = $dbh->prepare($sql); >+$sth->execute($borrowernumber); >+ >+my $resolved = 0; >+my $unresolved = 0; >+my @return_claims; >+while ( my $claim = $sth->fetchrow_hashref() ) { >+ $claim->{created_on_formatted} = output_pref( { dt => dt_from_string( $claim->{created_on} ) } ) if $claim->{created_on}; >+ $claim->{updated_on_formatted} = output_pref( { dt => dt_from_string( $claim->{updated_on} ) } ) if $claim->{updated_on}; >+ $claim->{resolved_on_formatted} = output_pref( { dt => dt_from_string( $claim->{resolved_on} ) } ) if $claim->{resolved_on}; >+ >+ my $patron = $claim->{resolved_by} ? Koha::Patrons->find( $claim->{resolved_by} ) : undef; >+ $claim->{resolved_by_data} = $patron->unblessed if $patron; >+ >+ my $resolution = $claim->{resolution} >+ ? Koha::AuthorisedValues->find( >+ { >+ category => 'RETURN_CLAIM_RESOLUTION', >+ authorised_value => $claim->{resolution}, >+ } >+ ) >+ : undef; >+ $claim->{resolution_data} = $resolution->unblessed if $resolution; >+ >+ $claim->{resolved_on} ? $resolved++ : $unresolved++; >+ >+ push( @return_claims, $claim ); >+} >+ >+my $data = { >+ iTotalRecords => scalar @return_claims, >+ iTotalDisplayRecords => scalar @return_claims, >+ sEcho => $input->param('sEcho') || undef, >+ aaData => \@return_claims, >+ resolved => $resolved, >+ unresolved => $unresolved >+}; >+ >+print to_json($data); >-- >2.21.0 (Apple Git-122)
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 14697
:
92407
|
92408
|
92409
|
92410
|
92962
|
92963
|
92964
|
92965
|
93005
|
93006
|
93007
|
93008
|
93012
|
93013
|
93014
|
93015
|
93017
|
93038
|
93039
|
93040
|
93041
|
93042
|
93061
|
93062
|
93063
|
93064
|
93065
|
93952
|
93953
|
93954
|
93955
|
93956
|
93957
|
93959
|
94842
|
94843
|
94844
|
94845
|
94846
|
94847
|
94848
| 94849 |
94850
|
94851
|
94852
|
94853
|
94854
|
94857
|
94877
|
94878