Bug 17698: Make patron notes show up on staff dashboard

This patch adds a user permission for managing issue notes, and a 'noteseen'
column to the issues table.

To test:
1) Apply Bug 14224 first
2) Apply this patch, update database, rebuild schema.
3) Restart koha-common and memcached
4) Turn on AllowCheckoutNotes syspref if haven't already
5) Issue two items to two different users (one item each)
6) Log into the OPAC as one of the users and add an issue note to their
issue
7) Log out and log back into the OPAC as the other user
8) Disable Javascript
9) Refresh opac-user.pl
10) Leave a checkout note on their issue
11) Enable javascript and log into the Staff Client as a superlibrarian
user
12) Go to your user's account and edit their permissions to have
everything ticked EXCEPT circulate->manage checkout notes.
13) Go to main intranet page. There should be no message saying
'checkout notes pending'.
14) Go to circulation home page. There should be no link to Checkout notes.
15) Go back to user's permissions and tick circulate->manage checkout notes.
16) Go back to main intranet page. There should now be a message at the
bottom saying 'Checkout notes pending: 2'
17) Go to circulation home page. There should be a link to Checkout notes
with a 2 next to it. Click this link
18) Attempt to mark an checkout note as seen. This should update the status
of the checkout note to 'seen' and disable to 'mark as seen' button while
enabling the 'mark as not seen' button.
19) Test both buttons with both issues.
20) Test select all and clear all buttons
21) Confirm that buttons at the bottom are only enabled if a checkbox is
checked
22) Try selecting both issues and using the buttons at the bottom to
mark multiple issue notes at once.
23) Confirm the barcode link to the item works as expected.
24) Confirm the cardnumber link to the user works as expected.
25) Confirm all table details show correctly.

Sponsored-by: Catalyst IT

Signed-off-by: Josef Moravec <josef.moravec@gmail.com>

Followed test plan, works as expected
Signed-off-by: Marc Véron <veron@veron.ch>

Signed-off-by: Brendan Gallagher <brendan@bywatersolutions.com>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Amended patch: Remove self-checkout permissions

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
This commit is contained in:
Aleisha Amohia 2016-12-01 00:54:07 +00:00 committed by Nick Clemens
parent 9eec98d318
commit 4a3eaf02e2
14 changed files with 336 additions and 2 deletions

71
circ/checkout-notes.pl Executable file
View File

@ -0,0 +1,71 @@
#!/usr/bin/perl
# Copyright 2016 Aleisha Amohia <aleisha@catalyst.net.nz>
#
# 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, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use CGI qw ( -utf8 );
use C4::Context;
use C4::Output;
use C4::Auth;
use Koha::Checkouts;
my $query = new CGI;
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
{
template_name => "circ/checkout-notes.tt",
query => $query,
type => "intranet",
authnotrequired => 0,
flagsrequired => { circulation => "manage_checkout_notes" },
}
);
my $schema = Koha::Database->new()->schema();
my @notes = $schema->resultset('Issue')->search({ 'me.note' => { '!=', undef } }, { prefetch => [ 'borrower', { item => 'biblionumber' } ] });
$template->param(
notes => \@notes,
);
my $action;
foreach (qw( seen notseen )) {
$action = $_ if ( $query->param("mark_selected-$_") );
}
$action ||= 'none';
my @issue_ids = $query->multi_param('issue_ids');
if ( $action eq 'seen' ) {
foreach my $issue_id ( @issue_ids ) {
my $issue = Koha::Checkouts->find($issue_id);
$issue->set({ noteseen => 1 })->store;
}
} elsif ( $action eq 'notseen' ) {
foreach my $issue_id ( @issue_ids ) {
my $issue = Koha::Checkouts->find($issue_id);
$issue->set({ noteseen => 0 })->store;
}
}
$template->param(
selected_count => scalar(@issue_ids),
action => $action,
);
output_html_with_http_headers $query, $cookie, $template->output;

View File

@ -22,6 +22,7 @@ use C4::Auth;
use C4::Output;
use C4::Context;
use Koha::BiblioFrameworks;
use Koha::Checkouts;
my $query = new CGI;
my ($template, $loggedinuser, $cookie, $flags) = get_template_and_user(
@ -39,5 +40,7 @@ $template->param( fast_cataloging => 1 ) if Koha::BiblioFrameworks->find( 'FA' )
$template->{'VARS'}->{'AllowOfflineCirculation'} = C4::Context->preference('AllowOfflineCirculation');
my $pending_checkout_notes = Koha::Checkouts->search({ noteseen => 0 })->count;
$template->param( pending_checkout_notes => $pending_checkout_notes );
output_html_with_http_headers $query, $cookie, $template->output;

View File

@ -0,0 +1,13 @@
$DBversion = 'XXX';
if( CheckVersion( $DBversion ) ) {
unless( column_exists( 'issues', 'noteseen' ) ) {
$dbh->do(q|ALTER TABLE issues ADD COLUMN noteseen int(1) default NULL AFTER notedate|);
}
unless( column_exists( 'old_issues', 'noteseen' ) ) {
$dbh->do(q|ALTER TABLE old_issues ADD COLUMN noteseen int(1) default NULL AFTER notedate|);
}
SetVersion( $DBversion );
print "Upgrade to $DBversion done (Bug 17698: Add column issues.noteseen and old_issues.noteseen)\n";
}

View File

@ -0,0 +1 @@
INSERT INTO permissions (module_bit, code, description) VALUES ( 1, 'manage_checkout_nots', 'Mark checkout notes as seen/not seen');

View File

@ -1754,6 +1754,7 @@ CREATE TABLE `issues` ( -- information related to check outs or issues
`onsite_checkout` int(1) NOT NULL default 0, -- in house use flag
`note` LONGTEXT default NULL, -- issue note text
`notedate` datetime default NULL, -- datetime of issue note (yyyy-mm-dd hh:mm::ss)
`noteseen` int(1) default NULL, -- describes whether checkout note has been seen 1, not been seen 0 or doesn't exist null
PRIMARY KEY (`issue_id`),
UNIQUE KEY `itemnumber` (`itemnumber`),
KEY `issuesborridx` (`borrowernumber`),
@ -1785,6 +1786,7 @@ CREATE TABLE `old_issues` ( -- lists items that were checked out and have been r
`onsite_checkout` int(1) NOT NULL default 0, -- in house use flag
`note` LONGTEXT default NULL, -- issue note text
`notedate` datetime default NULL, -- datetime of issue note (yyyy-mm-dd hh:mm::ss)
`noteseen` int(1) default NULL, -- describes whether checkout note has been seen 1, not been seen 0 or doesn't exist null
PRIMARY KEY (`issue_id`),
KEY `old_issuesborridx` (`borrowernumber`),
KEY `old_issuesitemidx` (`itemnumber`),

View File

@ -4,6 +4,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
( 1, 'overdues_report', 'Execute overdue items report'),
( 1, 'force_checkout', 'Force checkout if a limitation exists'),
( 1, 'manage_restrictions', 'Manage restrictions for accounts'),
( 1, 'manage_checkout_nots', 'Mark checkout notes as seen/not seen'),
( 3, 'parameters_remaining_permissions', 'Remaining system parameters permissions'),
( 3, 'manage_circ_rules', 'Manage circulation rules'),
( 4, 'edit_borrowers', 'Add, modify and view patron information'),

View File

@ -31,6 +31,7 @@
[%- CASE 'manage_restrictions' -%]<span>Manage restrictions for accounts</span>
[%- CASE 'overdues_report' -%]<span>Execute overdue items report</span>
[%- CASE 'override_renewals' -%]<span>Override blocked renewals</span>
[%- CASE 'manage_checkout_notes' %]<span>Mark checkout notes as seen/not seen</span>
[%- CASE 'manage_circ_rules' -%]<span>manage circulation rules</span>
[%- CASE 'parameters_remaining_permissions' -%]<span>Remaining system parameters permissions</span>
[%- CASE 'edit_borrowers' -%]<span>Add, modify and view patron information</span>

View File

@ -0,0 +1,164 @@
[% USE Koha %]
[% USE KohaDates %]
[% USE Branches %]
[% INCLUDE 'doc-head-open.inc' %]
<title>Home &rsaquo; Circulation &rsaquo; Checkout Notes</title>
[% INCLUDE 'doc-head-close.inc' %]
<link rel="stylesheet" type="text/css" href="[% interface %]/[% theme %]/css/datatables.css" />
[% INCLUDE 'datatables.inc' %]
<script type="text/javascript">
//<![CDATA[
$(document).ready(function(){
$("#notestable").dataTable($.extend(true, {}, dataTablesDefaults, {
"aoColumnDefs": [
{ "aTargets": [ 0, -1 ], "bSearchable": false, "bSortable": false },
],
"sPaginationType": "four_button"
}));
$(".SelectAll").on("click", function(){
$("input[name='issue_ids'][type='checkbox']").prop("checked", true);
$(".btn-sm").prop("disabled", false);
});
$(".ClearAll").on("click", function(){
$("input[name='issue_ids'][type='checkbox']").prop("checked", false);
$(".btn-sm").prop("disabled", true);
});
$("#error").hide();
$("input[type='checkbox']").click(function(event){
if ( $("input[type='checkbox']").is(":checked") ) {
$(".btn-sm").prop("disabled", false);
} else {
$(".btn-sm").prop("disabled", true);
}
});
$(".btn-xs").click(function(event){
event.preventDefault(); // prevent form submission
var $action = $(this).attr("name");
var $issue_id = $(this).data('issue_id');
var ajaxData = {
'action': $action,
'issue_id': $issue_id,
};
$.ajax({
url: '/cgi-bin/koha/svc/checkout_notes/',
type: 'POST',
dataType: 'json',
data: ajaxData,
})
.done(function(data){
if (data.status == 'success'){
if ( $action == 'notseen' ){
$("#status_" + $issue_id).text("Not seen");
$(event.target).siblings(".seen").prop("disabled", false);
$(event.target).prop("disabled", true);
} else {
$("#status_" + $issue_id).text("Seen");
$(event.target).siblings(".notseen").prop("disabled", false);
$(event.target).prop("disabled", true);
}
} else {
$("#error").text(_("Unable to change status of note."));
$("#error").show();
}
});
});
});
//]]>
</script>
[% INCLUDE 'calendar.inc' %]
<script type="text/javascript" src="[% interface %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
</head>
[% INCLUDE 'header.inc' %]
[% INCLUDE 'circ-search.inc' %]
<div id="breadcrumbs">
<a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo;
<a href="/cgi-bin/koha/circ/circulation-home.pl">Circulation</a> &rsaquo;
Checkout notes
</div>
<div id="doc" class="yui-t7"> <!-- <div id="doc3" class="yui-t2" -->
<div id="bd">
<div id="yui-main">
<h1>Checkout notes</h1>
<div class="dialog alert" id="error"></div>
[% IF ( selected_count ) %]
<div class="dialog message">
[% IF ( action == 'seen' ) %]
[% selected_count %] note(s) marked as seen.
[% ELSIF ( action == 'notseen' ) %]
[% selected_count %] note(s) marked as not seen.
[% ELSE %]
Failed to change the status of [% selected_count %] item(s).
[% END %]
</div>
<a href="/cgi-bin/koha/circ/checkout-notes.pl" class="btn btn-default btn-sm"><i class="fa fa-left"></i> Return to checkout notes</a>
[% ELSE %]
[% IF ( notes ) %]
<fieldset class="action">
<a class="SelectAll"><i class="fa fa-check"></i> Select all</a> | <a class="ClearAll"><i class="fa fa-remove"></i> Clear all</a>
</fieldset>
<form id="mark_selected" method="post" action="/cgi-bin/koha/circ/checkout-notes.pl">
<table id="notestable">
<thead>
<tr>
<th>&nbsp;</th>
<th>Title</th>
<th>Note</th>
<th>Date</th>
<th>Set by</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
[% FOREACH note IN notes %]
<tr>
<td><input type="checkbox" name="issue_ids" value="[% note.issue_id %]"></td>
<td>[% note.item.biblionumber.title %] - [% note.item.biblionumber.author %] (<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% note.item.biblionumber.biblionumber %]">[% note.item.barcode %]</a>)</td>
<td>[% note.note %]</td>
<td>[% note.notedate | $KohaDates %]</td>
<td>[% note.borrower.firstname %] [% note.borrower.surname %] (<a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% note.borrower.borrowernumber %]">[% note.borrower.cardnumber %]</a>)</td>
<td>[% IF ( note.noteseen == 0 ) %]
<span id="status_[% note.issue_id %]">Not seen</span>
[% ELSIF ( note.noteseen == 1 ) %]
<span id="status_[% note.issue_id %]">Seen</span>
[% END %]</td>
<td class="actions">[% IF ( note.noteseen == 1 ) %]
<button name="seen" data-issue_id="[% note.issue_id %]" class="seen btn btn-default btn-xs" disabled="disabled"><i class="fa fa-eye"></i> Mark seen</button> <button name="notseen" data-issue_id="[% note.issue_id %]" class="notseen btn btn-default btn-xs"><i class="fa fa-eye-slash"></i> Mark not seen</button>
[% ELSIF ( note.noteseen == 0 ) %]
<button name="seen" data-issue_id="[% note.issue_id %]" class="seen btn btn-default btn-xs"><i class="fa fa-eye"></i> Mark seen</button> <button name="notseen" data-issue_id="[% note.issue_id %]" class="notseen btn btn-default btn-xs" disabled="disabled"><i class="fa fa-eye-slash"></i> Mark not seen</button>
[% END %]</td>
</tr>
[% END %]
</tbody>
</table>
<fieldset class="action">
<button type="submit" class="btn btn-default btn-sm" name="mark_selected-seen" value="seen" disabled="disabled"><i class="fa fa-eye"></i> Mark seen</button>
<button type="submit" class="btn btn-default btn-sm" name="mark_selected-notseen" value="notseen" disabled="disabled"><i class="fa fa-eye-slash"></i> Mark not seen</button>
</fieldset>
</form>
[% END %] <!-- notes -->
[% END %] <!-- selected_count -->
</div> <!-- yui-main -->
</div> <!-- bd -->
</div> <!-- doc3 -->
[% INCLUDE 'intranet-bottom.inc' %]

View File

@ -39,6 +39,11 @@
</li>
[% END %]
[% END %]
[% IF ( Koha.Preference('AllowCheckoutNotes') && CAN_user_circulate_manage_checkout_notes ) %]
<li>
<a href="/cgi-bin/koha/circ/checkout-notes.pl">Checkout notes</a> [% IF ( pending_checkout_notes ) %]<span class="number_box"><a href="/cgi-bin/koha/circ/checkout-notes.pl">[% pending_checkout_notes %]</a></span>[% END %]
</li>
[% END %]
</ul>
</div>

View File

@ -172,6 +172,13 @@
</div>
[% END %]
[% IF Koha.Preference('AllowCheckoutNotes') && CAN_user_circulate_manage_checkout_notes && pending_checkout_notes %]
<div class="pending-info" id="checkout_notes_pending">
<a href="/cgi-bin/koha/circ/checkout-notes.pl">Checkout notes pending</a>:
<span class="pending-number-link">[% pending_checkout_notes %]</span>
</div>
[% END %]
</div>
[% END %]

View File

@ -31,6 +31,7 @@ use Koha::Patron::Modifications;
use Koha::Patron::Discharge;
use Koha::Reviews;
use Koha::ArticleRequests;
use Koha::Checkouts;
my $query = new CGI;
@ -74,6 +75,7 @@ my $pending_article_requests = Koha::ArticleRequests->search_limited(
$branch ? ( branchcode => $branch ) : (),
}
)->count;
my $pending_checkout_notes = Koha::Checkouts->search({ noteseen => 0 })->count;
$template->param(
pendingcomments => $pendingcomments,
@ -82,6 +84,7 @@ $template->param(
pending_borrower_modifications => $pending_borrower_modifications,
pending_discharge_requests => $pending_discharge_requests,
pending_article_requests => $pending_article_requests,
pending_checkout_notes => $pending_checkout_notes,
);
output_html_with_http_headers $query, $cookie, $template->output;

View File

@ -67,7 +67,7 @@ if ( $action eq 'issuenote' && C4::Context->preference('AllowCheckoutNotes') ) {
my $note = $query->param('note');
my $scrubber = C4::Scrubber->new();
my $clean_note = $scrubber->scrub($note);
if ( $issue->set({ notedate => dt_from_string(), note => $clean_note })->store ) {
if ( $issue->set({ notedate => dt_from_string(), note => $clean_note, noteseen => 0 })->store ) {
if ($clean_note) { # only send email if note not empty
my $branch = Koha::Libraries->find( $issue->branchcode );
my $letter = C4::Letters::GetPreparedLetter (

View File

@ -76,7 +76,7 @@ if ($is_ajax) {
}
if ( $issue ) {
$issue->set({ notedate => dt_from_string(), note => $clean_note })->store;
$issue->set({ notedate => dt_from_string(), note => $clean_note, noteseen => 0 })->store;
if($clean_note) { # only send email if note not empty
my $branch = Koha::Libraries->find( $issue->branchcode );
my $biblionumber = $issue->item->biblionumber;

63
svc/checkout_notes Executable file
View File

@ -0,0 +1,63 @@
#!/usr/bin/perl
# This file is part of Koha.
#
# Copyright 2017 Aleisha Amohia <aleisha@catalyst.net.nz>
#
# 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 JSON qw( to_json );
use CGI;
use C4::Service;
use C4::Auth qw /check_cookie_auth/;
use C4::Output qw(:DEFAULT :ajax);
use Koha::Checkouts;
=head1 NAME
svc/checkout_notes - Web service for managing patron notes set on issues
=head1 DESCRIPTION
=cut
# AJAX requests
my $is_ajax = is_ajax();
my $query = new CGI;
my ( $auth_status, $sessionID ) = check_cookie_auth( $query->cookie('CGISESSID'), { circulate => 'manage_checkout_notes' } );
if ( $auth_status ne "ok" ) {
exit 0;
}
if ($is_ajax) {
my $issue_id = $query->param('issue_id');
my $issue = Koha::Checkouts->find($issue_id);
my $action = $query->param('action');
my $status = 'success';
if ($action eq 'seen'){
$issue->set({ noteseen => 1 })->store;
if ( $issue->noteseen != 1 ) {
$status = 'failure';
}
} elsif ($action eq 'notseen'){
$issue->set({ noteseen => 0 })->store;
if ( $issue->noteseen != 0 ) {
$status = 'failure';
}
}
my $json = to_json ( { status => $status } );
output_with_http_headers $query, undef, $json, 'js';
exit;
}