@@ -, +, @@ checked out. Hit ENTER to save/send. specified for the branch which the item was checked out from. - This patch is still not ready for testing - am committing and - So far I have - moved the ajax code into svc/patron_notes. - made use of the built-in letters and notices functions to send this email etc (easier to test, removes a lot of unnecessary code etc), so I have removed the opac-sendissuenote.tt file and instead added a note to the database in 'letters' table which will be added to the message queue when the note is submitted - GetIssue subroutine to return the matching issue - Created a new GetPatronNote subroutine to fetch the notes on the circulation.pl page (previously the librarian could only see the note on checkin on the returns.pl page, which is not the only place you can check in) - Fallback form for when JS is deactivated - Testing: - Schema needs to be rebuilt before testing - Turn on 'AllowIssueNote' syspref - Show message_queue in mysql to test the notice is being sent - Test with and without JS - will provide instructions for this later - Still to do: - Making use of Koha::Issue[s] as per Comment 11 and Comment 14 - Show patron notes on the staff client dashboard (the way suggestions and patron detail updates show up on the main page) so librarians can mark notes as 'seen' - will do in a new patch when this is complete --- C4/Circulation.pm | 1 - Koha/Issue.pm | 130 +++++++++++++++++++++ circ/returns.pl | 3 + .../bug_14224-add_new_issue_columns.sql | 2 + .../bug_14224-add_patron_notice_to_letters.sql | 1 + .../atomicupdate/bug_14224-issue_notes_syspref.sql | 1 + installer/data/mysql/kohastructure.sql | 30 +++++ installer/data/mysql/sysprefs.sql | 1 + .../en/modules/admin/preferences/circulation.pref | 6 + .../intranet-tmpl/prog/en/modules/circ/returns.tt | 10 ++ koha-tmpl/intranet-tmpl/prog/js/checkouts.js | 13 ++- .../bootstrap/en/modules/opac-issue-note.tt | 54 +++++++++ .../opac-tmpl/bootstrap/en/modules/opac-user.tt | 94 +++++++++++++++ opac/opac-issue-note.pl | 81 +++++++++++++ opac/opac-user.pl | 3 + opac/svc/patron_notes | 109 +++++++++++++++++ svc/checkin | 4 + 17 files changed, 538 insertions(+), 5 deletions(-) create mode 100644 installer/data/mysql/atomicupdate/bug_14224-add_new_issue_columns.sql create mode 100644 installer/data/mysql/atomicupdate/bug_14224-add_patron_notice_to_letters.sql create mode 100644 installer/data/mysql/atomicupdate/bug_14224-issue_notes_syspref.sql create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-issue-note.tt create mode 100644 opac/opac-issue-note.pl create mode 100755 opac/svc/patron_notes --- a/C4/Circulation.pm +++ a/C4/Circulation.pm @@ -2509,7 +2509,6 @@ sub GetOpenIssue { =head2 GetIssues $issues = GetIssues({}); # return all issues! - $issues = GetIssues({ borrowernumber => $borrowernumber, biblionumber => $biblionumber }); Returns all pending issues that match given criteria. Returns a arrayref or undef if an error occurs. --- a/Koha/Issue.pm +++ a/Koha/Issue.pm @@ -21,8 +21,138 @@ use Koha::Database; use base qw(Koha::Object); +use vars qw(@ISA @EXPORT); + +BEGIN { + require Exporter; + @ISA = qw(Exporter); + + push @EXPORT, qw( + &GetIssue + &SetIssueNote + &SendIssueNote + &GetPatronNote + ); +} + sub _type { return 'Issue'; } +=head2 GetIssue + + $issue = GetIssue({ issue_id => $issue_id }); + +Returns issue with provided issue_id + +=cut + +sub GetIssue { + my ($criteria) = @_; + # Build filters + my @filters; + my @allowed = qw(borrowernumber biblionumber itemnumber issue_id); + foreach (@allowed) { + if (defined $criteria->{$_}) { + push @filters, { + field => $_, + value => $criteria->{$_}, + }; + } + } + + # Build SQL query + my $where = ''; + if (@filters) { + $where = "WHERE " . join(' AND ', map { "$_->{field} = ?" } @filters); + } + my $query = q{ + SELECT issues.* + FROM issues + }; + $query .= $where; + + # Execute SQL query + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare($query); + $sth->execute(map { $_->{value} } @filters); + + my $issue = $sth->fetchrow_hashref; + return $issue; +} + +=head2 SetIssueNote + + &SetIssueNote($issue_id, $note); + +Sets a note to the issuenotes table for the given issue. + +=over 4 + +=item C<$issue_id> is the id of the issue for which to set the note + +=item C<$note> is the note to set + +=back + +Returns: +True on success +False on failure + +=cut + +sub SetIssueNote { + my ( $issue_id, $note) = @_; + my $dbh = C4::Context->dbh; + unless ( $issue_id =~ /\d+/ ) { + return; + } + + my $query = "UPDATE issues SET notedate=NOW(),note=? WHERE issue_id=?"; + my $sth = $dbh->prepare($query); + return $sth->execute( $note, $issue_id ); +} + +=head2 SendIssueNote + + &SendIssueNote($biblio, $borrower, $branch); + +Sends the issue note to the library (adds it to the message queue). + +=cut + +sub SendIssueNote { + my $biblio = shift; + my $borrower = shift; + my $branch = shift; + my $letter = C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => 'PATRON_NOTE', + branchcode => $branch, + tables => { + 'biblio' => $biblio->{biblionumber}, + 'borrowers' => $borrower->{borrowernumber}, + }, + ); + C4::Message->enqueue($letter, $borrower, 'email'); +} + +=head2 GetPatronNote + + &GetPatronNote($itemnumber); + +Gets the patron note of an issue upon checkin using itemnumber + +=cut + +sub GetPatronNote { + my $itemnumber = shift; + my $dbh = C4::Context->dbh; + my $query = "SELECT note FROM issues WHERE itemnumber = ?"; + my $sth = $dbh->prepare($query); + $sth->execute($itemnumber); + my $patronnote = $sth->fetchrow_hashref; + return $patronnote->{note}; +} + 1; --- a/circ/returns.pl +++ a/circ/returns.pl @@ -282,6 +282,8 @@ if ($barcode) { my $descriptions = Koha::AuthorisedValues->get_description_by_koha_field({frameworkcode => '', kohafield =>'items.materials', authorised_value => $materials }); $materials = $descriptions->{lib} // ''; + my $issue = GetItemIssue($itemnumber); + $template->param( title => $biblio->{'title'}, homebranch => $biblio->{'homebranch'}, @@ -295,6 +297,7 @@ if ($barcode) { biblionumber => $biblio->{'biblionumber'}, borrower => $borrower, additional_materials => $materials, + issue => $issue, ); my %input = ( --- a/installer/data/mysql/atomicupdate/bug_14224-add_new_issue_columns.sql +++ a/installer/data/mysql/atomicupdate/bug_14224-add_new_issue_columns.sql @@ -0,0 +1,2 @@ +ALTER IGNORE TABLE issues ADD `note` mediumtext default NULL; +ALTER IGNORE TABLE issues ADD `notedate` datetime default NULL; --- a/installer/data/mysql/atomicupdate/bug_14224-add_patron_notice_to_letters.sql +++ a/installer/data/mysql/atomicupdate/bug_14224-add_patron_notice_to_letters.sql @@ -0,0 +1, @@ +INSERT IGNORE INTO letter (`module`, `code`, `branchcode`, `name`, `is_html`, `title`, `content`, `message_transport_type`) VALUES ('circulation', 'PATRON_NOTE', '', 'Patron note on item', '0', 'Patron issue note', '<> <> has added a note to the item <> - <> (<>).','email'); --- a/installer/data/mysql/atomicupdate/bug_14224-issue_notes_syspref.sql +++ a/installer/data/mysql/atomicupdate/bug_14224-issue_notes_syspref.sql @@ -0,0 +1, @@ +INSERT IGNORE INTO systempreferences (`variable`, `value`, `options`, `explanation`,`type`) VALUES ('AllowIssueNotes', '0', NULL, 'Allow patrons to submit notes about checked out items.','YesNo'); --- a/installer/data/mysql/kohastructure.sql +++ a/installer/data/mysql/kohastructure.sql @@ -841,6 +841,36 @@ CREATE TABLE `import_items` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -- +-- Table structure for table `issues` +-- + +DROP TABLE IF EXISTS `issues`; +CREATE TABLE `issues` ( -- information related to check outs or issues + `issue_id` int(11) NOT NULL AUTO_INCREMENT, -- primary key for issues table + `borrowernumber` int(11), -- foreign key, linking this to the borrowers table for the patron this item was checked out to + `itemnumber` int(11), -- foreign key, linking this to the items table for the item that was checked out + `date_due` datetime default NULL, -- datetime the item is due (yyyy-mm-dd hh:mm::ss) + `branchcode` varchar(10) default NULL, -- foreign key, linking to the branches table for the location the item was checked out + `returndate` datetime default NULL, -- date the item was returned, will be NULL until moved to old_issues + `lastreneweddate` datetime default NULL, -- date the item was last renewed + `return` varchar(4) default NULL, + `renewals` tinyint(4) default NULL, -- lists the number of times the item was renewed + `auto_renew` BOOLEAN default FALSE, -- automatic renewal + `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, -- the date and time this record was last touched + `issuedate` datetime default NULL, -- date the item was checked out or issued + `onsite_checkout` int(1) NOT NULL default 0, -- in house use flag + `note` mediumtext default NULL, -- issue note text + `notedate` datetime default NULL, -- datetime of issue note (yyyy-mm-dd hh:mm::ss) + PRIMARY KEY (`issue_id`), + KEY `issuesborridx` (`borrowernumber`), + KEY `itemnumber_idx` (`itemnumber`), + KEY `branchcode_idx` (`branchcode`), + KEY `bordate` (`borrowernumber`,`timestamp`), + CONSTRAINT `issues_ibfk_1` FOREIGN KEY (`borrowernumber`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT `issues_ibfk_2` FOREIGN KEY (`itemnumber`) REFERENCES `items` (`itemnumber`) ON DELETE RESTRICT ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -- Table structure for table `issuingrules` -- --- a/installer/data/mysql/sysprefs.sql +++ a/installer/data/mysql/sysprefs.sql @@ -29,6 +29,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('AllowNotForLoanOverride','0','','If ON, Koha will allow the librarian to loan a not for loan item.','YesNo'), ('AllowOfflineCirculation','0','','If on, enables HTML5 offline circulation functionality.','YesNo'), ('AllowPatronToSetCheckoutsVisibilityForGuarantor', '0', NULL, 'If enabled, the patron can set checkouts to be visible to his or her guarantor', 'YesNo'), +('AllowIssueNotes', '0', NULL, 'Allow patrons to submit notes about checked out items.','YesNo'), ('AllowPKIAuth','None','None|Common Name|emailAddress','Use the field from a client-side SSL certificate to look a user in the Koha database','Choice'), ('AllowPurchaseSuggestionBranchChoice','0','1','Allow user to choose branch when making a purchase suggestion','YesNo'), ('AllowRenewalIfOtherItemsAvailable','0',NULL,'If enabled, allow a patron to renew an item with unfilled holds if other available items can fill that hold.','YesNo'), --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref @@ -136,6 +136,12 @@ Circulation: yes: Show no: "Do not show" - all items in the "Checked-in items" list, even items that were not checked out. + - + - pref: AllowIssueNotes + choices: + yes: Allow + no: "Don't allow" + - patrons to submit notes about checked out items. Checkout Policy: - --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt @@ -183,6 +183,16 @@ $(document).ready(function () { [% END %] + +[% IF ( issue.note) %] +
+

Patron note

+

[% issue.notedate %]

+

[% title |html %] [% author %]

+

[% issue.note %]

+
+[% END %] + [% IF ( fines ) %]
--- a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js +++ a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js @@ -67,6 +67,7 @@ $(document).ready(function() { content = CIRCULATION_RETURNED; $(id).parent().parent().addClass('ok'); $('#date_due_' + data.itemnumber).html(CIRCULATION_RETURNED); + $('#patron_note_' + data.itemnumber).html("Patron note: " + data.patronnote); } else { content = CIRCULATION_NOT_RETURNED; $(id).parent().parent().addClass('warn'); @@ -218,7 +219,7 @@ $(document).ready(function() { }, { "mDataProp": function ( oObj ) { - title = "" + oObj.title; @@ -242,7 +243,7 @@ $(document).ready(function() { if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) { span_class = "circ-hlt"; } - title += " - " + oObj.itemnotes + "" + title += " - " + oObj.itemnotes + ""; } if ( oObj.itemnotes_nonpublic ) { @@ -250,7 +251,7 @@ $(document).ready(function() { if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) { span_class = "circ-hlt"; } - title += " - " + oObj.itemnotes_nonpublic + "" + title += " - " + oObj.itemnotes_nonpublic + ""; } var onsite_checkout = ''; @@ -258,6 +259,8 @@ $(document).ready(function() { onsite_checkout += " (" + INHOUSE_USE + ")"; } + var patron_note = " "; + title += " " + "" + oObj.barcode + "" - + onsite_checkout; + + onsite_checkout + + "
" + + patron_note return title; }, --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-issue-note.tt +++ a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-issue-note.tt @@ -0,0 +1,54 @@ +[% USE Koha %] +[% USE KohaDates %] +[% USE Branches %] +[% INCLUDE 'doc-head-open.inc' %] +[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › Your library home +[% INCLUDE 'doc-head-close.inc' %] +[% BLOCK cssinclude %][% END %] + +[% INCLUDE 'bodytag.inc' bodyid='opac-issue-note' %] +[% INCLUDE 'masthead.inc' %] + +
+ + +
+
+
+ +
+
+
+

Editing issue note for [% title %] [% author %]

+ [% IF not(Koha.Preference("AllowIssueNotes")) %] + Issue notes have not been enabled. Please contact the library. + [% ELSE %] +
+
+ + + + + + +
+
+ Cancel +
+
+ [% END %] +
+
+
+
+ +
+ +[% INCLUDE 'opac-bottom.inc' %] +[% BLOCK jsinclude %][% END %] --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt +++ a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt @@ -120,6 +120,8 @@ Using this account is not recommended because some parts of Koha will not functi
[% END # / IF patron_flagged %] + + [% SET OPACMySummaryNote = Koha.Preference('OPACMySummaryNote') %] [% IF OPACMySummaryNote %][% OPACMySummaryNote %][% END %] @@ -165,6 +167,9 @@ Using this account is not recommended because some parts of Koha will not functi [% IF ( OPACMySummaryHTML ) %] Links [% END %] + [% IF ( AllowIssueNotes ) %] + Note + [% END %] @@ -283,6 +288,13 @@ Using this account is not recommended because some parts of Koha will not functi [% IF ( OPACMySummaryHTML ) %] [% ISSUE.MySummaryHTML %] [% END %] + [% IF ( AllowIssueNotes ) %] + + + + Edit / Create note + + [% END %] [% END # /FOREACH ISSUES %] @@ -883,6 +895,88 @@ Using this account is not recommended because some parts of Koha will not functi [% END %] [% END %] + [% IF ( AllowIssueNotes ) %] + + /* If JS enabled, show button, otherwise show link to redirect to a page where note can be submitted */ + $("a[name='nonjs_submitnote']").hide(); + + $("input[name='note']").prop('readonly', false); + $("input[name='note']").keyup(function(e){ + /* prevent submitting of renewselected form */ + if(e.which == 13) + e.preventDefault(); + + var $btn_save = $('#save_'+$(this).data('issue_id')); + var origvalue = $(this).data('origvalue'); + var value = $(this).val(); + + if(origvalue != value) { + if(origvalue != "") + $btn_save.text('Submit changes'); + else + $btn_save.text('Submit note'); + $btn_save.show(); + } else { + $btn_save.hide(); + } + }); + + $("a[name='js_submitnote']").click(function(e){ + var $self = $(this); + var title = $(this).parent().siblings('.title').html(); + var $noteinput = $(this).siblings('input[name="note"]').first(); + + var ajaxData = { + 'action': 'issuenote', + 'issue_id': $noteinput.data('issue_id'), + 'note': $noteinput.val(), + }; + + $.ajax({ + url: '/cgi-bin/koha/svc/patron_notes/', + type: 'POST', + dataType: 'json', + data: ajaxData, + }) + .done(function(data) { + var message = ""; + if(data.status == 'saved') { + $("#notesaved").removeClass("alert-error"); + $("#notesaved").addClass("alert-info"); + $noteinput.data('origvalue', data.note); + $noteinput.val(data.note); + message = "

Your note about " + title + " has been saved and sent to the library.

"; + $self.hide(); + } else if(data.status == 'removed') { + $("#notesaved").removeClass("alert-error"); + $("#notesaved").addClass("alert-info"); + $noteinput.data('origvalue', ""); + $noteinput.val(""); + message = "

Your note about " + title + " was removed.

"; + $self.hide(); + } else { + $("#notesaved").removeClass("alert-info"); + $("#notesaved").addClass("alert-error"); + message = "

Your note about " + title + " could not be saved.

" + + "

" + data.error + "

"; + } + + message += "

" + data.note + "

"; + $("#notesaved").html(message); + }) + .fail(function(data) { + $("#notesaved").removeClass("alert-info"); + $("#notesaved").addClass("alert-error"); + var message = "

Your note about " + title + " could not be saved.

" + + "

Ajax request has failed.

"; + $("#notesaved").html(message); + }) + .always(function() { + $("#notesaved").show(); + }); + }); + [% END %] + $( ".suspend-until" ).datepicker({ minDate: 1 }); // Require that "until date" be in the future }); //]]> --- a/opac/opac-issue-note.pl +++ a/opac/opac-issue-note.pl @@ -0,0 +1,81 @@ +#!/usr/bin/perl + +# Copyright 2016 Aleisha Amohia +# +# 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 . + +use Modern::Perl; + +use strict; +use warnings; + +use CGI qw ( -utf8 ); +use C4::Koha; +use C4::Context; +use C4::Scrubber; +use C4::Members; +use C4::Output; +use C4::Auth; +use C4::Biblio; +use Koha::Issue; +use Koha::Issues; + +my $query = new CGI; + +my ( $template, $borrowernumber, $cookie ) = get_template_and_user( + { + template_name => "opac-issue-note.tt", + query => $query, + type => "opac", + authnotrequired => 0, + debug => 1, + } +); + +my $member = C4::Members::GetMember( borrowernumber => $borrowernumber ); +$template->param( + firstname => $member->{'firstname'}, + surname => $member->{'surname'}, + borrowernumber => $borrowernumber, +); + +my $issue_id = $query->param('issue_id'); +my $issue = Koha::Issue::GetIssue({ issue_id => $issue_id }); +my $itemnumber = $issue->{'itemnumber'}; +my $biblio = GetBiblioFromItemNumber($itemnumber); +$template->param( + issue_id => $issue_id, + title => $biblio->{'title'}, + author => $biblio->{'author'}, + note => $issue->{'note'}, + itemnumber => $issue->{'itemnumber'}, +); + +my $action = $query->param('action') || ""; +if ( $action eq 'issuenote' && C4::Context->preference('AllowIssueNotes') ) { + my $note = $query->param('note'); + my $scrubber = C4::Scrubber->new(); + my $clean_note = $scrubber->scrub($note); + if ( Koha::Issue::SetIssueNote($issue_id, $clean_note) ) { + if ($clean_note) { # only send email if note not empty + my $branch = Koha::Libraries->find( $issue->{branchcode} ); + Koha::Issue::SendIssueNote($biblio, $member, $branch); + } + } + print $query->redirect("/cgi-bin/koha/opac-user.pl"); +} + +output_html_with_http_headers $query, $cookie, $template->output, undef, { force_no_caching => 1 }; --- a/opac/opac-user.pl +++ a/opac/opac-user.pl @@ -33,6 +33,7 @@ use C4::Output; use C4::Biblio; use C4::Items; use C4::Letters; +use Koha::Libraries; use Koha::DateUtils; use Koha::Holds; use Koha::Database; @@ -260,6 +261,8 @@ if ($issues){ } my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing'); $canrenew = 0 if ($overduesblockrenewing ne 'allow' and $overdues_count == $count); + +$template->param( AllowIssueNotes => C4::Context->preference('AllowIssueNotes') ); $template->param( ISSUES => \@issuedat ); $template->param( issues_count => $count ); $template->param( canrenew => $canrenew ); --- a/opac/svc/patron_notes +++ a/opac/svc/patron_notes @@ -0,0 +1,109 @@ +#!/usr/bin/perl + +# This file is part of Koha. +# +# Copyright 2014 BibLibre +# +# 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 . + +use Modern::Perl; + +use C4::Service; +use C4::Auth qw /check_cookie_auth/; +use C4::Letters qw( GetLetters ); +use CGI::Cookie; # need to check cookies before having CGI parse the POST request +use C4::Output qw(:DEFAULT :ajax); +use C4::Scrubber; +use C4::Circulation; +use C4::Members; +use C4::Biblio; +use Koha::Issue; + +=head1 NAME + +svc/patron_notes - Web service for setting patron notes on items + +=head1 DESCRIPTION + +=cut + +sub ajax_auth_cgi { # returns CGI object + my $needed_flags = shift; + my %cookies = fetch CGI::Cookie; + my $input = CGI->new; + my $sessid = $cookies{'CGISESSID'}->value; + my ($auth_status, $auth_sessid) = check_cookie_auth($sessid, $needed_flags); + if ($auth_status ne "ok") { + output_with_http_headers $input, undef, + "window.alert('Your CGI session cookie ($sessid) is not current. " . + "Please refresh the page and try again.');\n", 'js'; + exit 0; + } + return $input; +} + +# AJAX requests +my $is_ajax = is_ajax(); +my $query = ($is_ajax) ? &ajax_auth_cgi({}) : CGI->new(); +if ($is_ajax) { + my $action = $query->param('action'); + + # Issue Note + if ( $action eq 'issuenote' && C4::Context->preference('AllowIssueNotes') ) { + my $scrubber = C4::Scrubber->new(); + my $note = $query->param('note'); + my $issue_id = $query->param('issue_id'); + my $clean_note = $scrubber->scrub($note); + my $status = "saved"; + my $error = ""; + my ($member, $issue); + + my ( $template, $borrowernumber, $cookie ) = C4::Auth::get_template_and_user({ + template_name => "opac-user.tt", + query => $query, + type => "opac", + authnotrequired => 1, + }); + + # verify issue_id + if ( $issue_id =~ /\d+/ ) { + $member = GetMember(borrowernumber => $borrowernumber); + $issue = Koha::Issue::GetIssue({issue_id => $issue_id}); + if ( $issue->{'borrowernumber'} != $borrowernumber ) { + $status = "fail"; + $error = "Invalid issue id!"; + } + } else { + $status = "fail"; + $error = "Invalid issue id!"; + } + + if ( (not $error) && SetIssueNote($issue_id, $clean_note) ) { + if($clean_note) { # only send email if note not empty + my $branch = Koha::Libraries->find( $issue->{branchcode} ); + my $biblio = GetBiblioFromItemNumber($issue->{'itemnumber'}); + SendIssueNote($biblio, $member, $branch); + } else { # note empty, i.e removed + $status = "removed"; + } + } else { + $status = "fail"; + $error = "Perhaps the item has already been checked in?"; + } + + my $response = "{\"status\": \"$status\", \"note\": \"$clean_note\", \"issue_id\": \"$issue_id\", \"error\": \"$error\"}"; + output_with_http_headers($query, undef, $response, 'js'); + exit; + } # END Issue Note +} --- a/svc/checkin +++ a/svc/checkin @@ -26,6 +26,7 @@ use C4::Circulation; use C4::Items qw(GetBarcodeFromItemnumber GetItem ModItem); use C4::Context; use C4::Auth qw(check_cookie_auth); +use Koha::Issue; my $input = new CGI; @@ -72,6 +73,9 @@ if ( C4::Context->preference("ReturnToShelvingCart") ) { ModItem( $item, $item->{'biblionumber'}, $item->{'itemnumber'} ); } +my $patronnote = GetPatronNote($itemnumber); +$data->{patronnote} = $patronnote; + ( $data->{returned} ) = AddReturn( $barcode, $branchcode, $exempt_fine ); print to_json($data); --