From c26d88325b2e0686ca65ae87b3c28a668478f055 Mon Sep 17 00:00:00 2001 From: Aleisha Amohia Date: Sun, 23 Aug 2015 18:22:50 +0200 Subject: [PATCH] Bug 14224: Allow patron notes about item shown at check in This patch adds a "Note" input field to checked out items in the "your summary" section. The field allows patrons to write notes about the item checked out, such as "this DVD is scratched", "the binding was torn", etc. The note will be emailed to the library and displayed on item check in. Patch adds two fields to the "issues" table - "note" and "notedate". Patch adds syspref "AllowIssueNotes" - default off. Test Plan: 1) Apply this patch 2) Update database 3) Rebuild schema 4) Turn on 'AllowIssueNote' syspref 5) Check out three different items to a borrower (may be easiest to check out to yourself) 6) Log in as that borrower (or yourself) on the OPAC side and go to your summary 7) Confirm text field shows under Note column for all checkouts. Set a note for each issue, confirm all save. 8) Check the message_queue in mysql for the entries for ALL THREE issue notes. 9) Disable javascript in your browser 10) Refresh your summary page. Confirm that you can no longer edit the notes in the text field. Click the 'Create/edit note' button and confirm you are redirected to a new page. 11) Confirm that the correct title and author show for the note button you clicked. 12) Set the note and click Submit -> confirm you are redirected back to summary page and note is saved 13) Confirm there is a new entry in message_queue 14) Enable javascript and go back to the your checkouts page in the staff client for the borrower you issued the items to 15) Check in TWO items 16) Confirm that the issue notes show under the "Date due" column for the two items you checked in, and are accurate to the item (i.e. the right issue note under the right item) 17) Go to circ/returns.pl and check in the final item using the barcode. Confirm the issue note shows and the date is formatted correctly. Sponsored-by: Region Halland --- C4/Circulation.pm | 112 +++++++++++++++++++++ Koha/Issue.pm | 53 ++++++++++ Koha/Issues.pm | 62 ++++++++++++ Koha/Schema/Result/Issue.pm | 23 ++++- circ/returns.pl | 3 + .../bug_14224-add_new_issue_columns.sql | 4 + .../bug_14224-add_patron_notice_to_letters.sql | 1 + .../atomicupdate/bug_14224-issue_notes_syspref.sql | 1 + installer/data/mysql/kohastructure.sql | 4 + 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 | 88 ++++++++++++++++ opac/opac-user.pl | 2 + opac/svc/patron_notes | 108 ++++++++++++++++++++ svc/checkin | 10 +- 19 files changed, 642 insertions(+), 7 deletions(-) create mode 100644 Koha/Issue.pm create mode 100644 Koha/Issues.pm 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 100755 opac/opac-issue-note.pl create mode 100755 opac/svc/patron_notes diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 80ae062..13f1743 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -2512,6 +2512,118 @@ sub GetOpenIssue { } +=head2 GetIssues + + $issues = GetIssues({}); # return all issues! + +Returns all pending issues that match given criteria. +Returns a arrayref or undef if an error occurs. + +Allowed criteria are: + +=over 2 + +=item * borrowernumber + +=item * biblionumber + +=item * itemnumber + +=back + +=cut + +sub GetIssues { + my ($criteria) = @_; + + # Build filters + my @filters; + my @allowed = qw(borrowernumber biblionumber itemnumber); + foreach (@allowed) { + if (defined $criteria->{$_}) { + push @filters, { + field => $_, + value => $criteria->{$_}, + }; + } + } + + # Do we need to join other tables ? + my %join; + if (defined $criteria->{biblionumber}) { + $join{items} = 1; + } + + # Build SQL query + my $where = ''; + if (@filters) { + $where = "WHERE " . join(' AND ', map { "$_->{field} = ?" } @filters); + } + my $query = q{ + SELECT issues.* + FROM issues + }; + if (defined $join{items}) { + $query .= q{ + LEFT JOIN items ON (issues.itemnumber = items.itemnumber) + }; + } + $query .= $where; + + # Execute SQL query + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare($query); + my $rv = $sth->execute(map { $_->{value} } @filters); + + return $rv ? $sth->fetchall_arrayref({}) : undef; +} + +=head2 GetItemIssues + + $issues = &GetItemIssues($itemnumber, $history); + +Returns patrons that have issued a book + +C<$itemnumber> is the itemnumber +C<$history> is false if you just want the current "issuer" (if any) +and true if you want issues history from old_issues also. + +Returns reference to an array of hashes + +=cut + +sub GetItemIssues { + my ( $itemnumber, $history ) = @_; + my $today = DateTime->now( time_zome => C4::Context->tz); # get today date + $today->truncate( to => 'minute' ); + my $sql = "SELECT * FROM issues + JOIN borrowers USING (borrowernumber) + JOIN items USING (itemnumber) + WHERE issues.itemnumber = ? "; + if ($history) { + $sql .= "UNION ALL + SELECT * FROM old_issues + LEFT JOIN borrowers USING (borrowernumber) + JOIN items USING (itemnumber) + WHERE old_issues.itemnumber = ? "; + } + $sql .= "ORDER BY date_due DESC"; + my $sth = C4::Context->dbh->prepare($sql); + if ($history) { + $sth->execute($itemnumber, $itemnumber); + } else { + $sth->execute($itemnumber); + } + my $results = $sth->fetchall_arrayref({}); + foreach (@$results) { + my $date_due = dt_from_string($_->{date_due},'sql'); + $date_due->truncate( to => 'minute' ); + + $_->{overdue} = (DateTime->compare($date_due, $today) == -1) ? 1 : 0; + } + return $results; +} + =head2 GetBiblioIssues $issues = GetBiblioIssues($biblionumber); diff --git a/Koha/Issue.pm b/Koha/Issue.pm new file mode 100644 index 0000000..e979a06 --- /dev/null +++ b/Koha/Issue.pm @@ -0,0 +1,53 @@ +package Koha::Issue; + +#!/usr/bin/perl + +# Copyright 2017 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 Koha::Database; + +use base qw( Koha::Object ); + +=head1 NAME + +Koha::Issue - Koha Issue object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'Issue'; +} + +=head1 AUTHOR + +Aleisha Amohia +Catalyst IT + +=cut + +1; diff --git a/Koha/Issues.pm b/Koha/Issues.pm new file mode 100644 index 0000000..dfa8132 --- /dev/null +++ b/Koha/Issues.pm @@ -0,0 +1,62 @@ +package Koha::Issues; + +#!/usr/bin/perl + +# Copyright 2017 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 Koha::Database; +use Koha::Issue; + +use base qw( Koha::Objects ); + +=head1 NAME + +Koha::Issues - Koha Issues object set class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'Issue'; +} + +=head3 object class + +=cut + +sub object_class { + return 'Koha::Issue'; +} + +=head1 AUTHOR + +Aleisha Amohia +Catalyst IT + +=cut + +1; diff --git a/Koha/Schema/Result/Issue.pm b/Koha/Schema/Result/Issue.pm index 0144a86..43d5c75 100644 --- a/Koha/Schema/Result/Issue.pm +++ b/Koha/Schema/Result/Issue.pm @@ -101,6 +101,17 @@ __PACKAGE__->table("issues"); default_value: 0 is_nullable: 0 +=head2 note + + data_type: 'mediumtext' + is_nullable: 1 + +=head2 notedate + + data_type: 'datetime' + datetime_undef_if_invalid: 1 + is_nullable: 1 + =cut __PACKAGE__->add_columns( @@ -151,6 +162,14 @@ __PACKAGE__->add_columns( }, "onsite_checkout", { data_type => "integer", default_value => 0, is_nullable => 0 }, + "note", + { data_type => "mediumtext", is_nullable => 1 }, + "notedate", + { + data_type => "datetime", + datetime_undef_if_invalid => 1, + is_nullable => 1, + }, ); =head1 PRIMARY KEY @@ -222,8 +241,8 @@ __PACKAGE__->belongs_to( ); -# Created by DBIx::Class::Schema::Loader v0.07039 @ 2015-11-04 12:00:58 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:kREecsHr6wZPiokS946BHw +# Created by DBIx::Class::Schema::Loader v0.07042 @ 2016-12-01 02:20:55 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:a7FCuypwxtuE6oJjEnRJRg __PACKAGE__->belongs_to( "borrower", diff --git a/circ/returns.pl b/circ/returns.pl index 5927759..c3260c8 100755 --- a/circ/returns.pl +++ b/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 = ( diff --git a/installer/data/mysql/atomicupdate/bug_14224-add_new_issue_columns.sql b/installer/data/mysql/atomicupdate/bug_14224-add_new_issue_columns.sql new file mode 100644 index 0000000..6ed41dc --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_14224-add_new_issue_columns.sql @@ -0,0 +1,4 @@ +ALTER IGNORE TABLE issues ADD `note` mediumtext default NULL AFTER `onsite_checkout`; +ALTER IGNORE TABLE issues ADD `notedate` datetime default NULL AFTER `note`; +ALTER IGNORE TABLE old_issues ADD `note` mediumtext default NULL AFTER `onsite_checkout`; +ALTER IGNORE TABLE old_issues ADD `notedate` datetime default NULL AFTER `note`; diff --git a/installer/data/mysql/atomicupdate/bug_14224-add_patron_notice_to_letters.sql b/installer/data/mysql/atomicupdate/bug_14224-add_patron_notice_to_letters.sql new file mode 100644 index 0000000..135887e --- /dev/null +++ b/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'); diff --git a/installer/data/mysql/atomicupdate/bug_14224-issue_notes_syspref.sql b/installer/data/mysql/atomicupdate/bug_14224-issue_notes_syspref.sql new file mode 100644 index 0000000..e619b21 --- /dev/null +++ b/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'); diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index f40692e..a9fd5dc 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -1744,6 +1744,8 @@ CREATE TABLE `issues` ( -- information related to check outs or issues `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`), UNIQUE KEY `itemnumber` (`itemnumber`), KEY `issuesborridx` (`borrowernumber`), @@ -1773,6 +1775,8 @@ CREATE TABLE `old_issues` ( -- lists items that were checked out and have been r `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 `old_issuesborridx` (`borrowernumber`), KEY `old_issuesitemidx` (`itemnumber`), diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql index ef83c3d..41c70b7 100644 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -22,6 +22,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('AllowHoldPolicyOverride','0',NULL,'Allow staff to override hold policies when placing holds','YesNo'), ('AllowHoldsOnDamagedItems','1','','Allow hold requests to be placed on damaged items','YesNo'), ('AllowHoldsOnPatronsPossessions','1',NULL,'Allow holds on records that patron have items of it','YesNo'), +('AllowIssueNotes', '0', NULL, 'Allow patrons to submit notes about checked out items.','YesNo'), ('AllowItemsOnHoldCheckout','0','','Do not generate RESERVE_WAITING and RESERVED warning when checking out items reserved to someone else. This allows self checkouts for those items.','YesNo'), ('AllowItemsOnHoldCheckoutSCO','0','','Do not generate RESERVE_WAITING and RESERVED warning in the SCO module when checking out items reserved to someone else. This allows self checkouts for those items.','YesNo'), ('AllowMultipleCovers','0','1','Allow multiple cover images to be attached to each bibliographic record.','YesNo'), 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 e69e37f..6c4b9ed 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 @@ -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: - 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 c0b9c90..6a878d5 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt +++ b/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 | $KohaDates %]

+

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

+

[% issue.note %]

+
+[% END %] + [% IF ( fines ) %]
diff --git a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js index f12743f..3c5d745 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js +++ b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js @@ -67,6 +67,9 @@ $(document).ready(function() { content = CIRCULATION_RETURNED; $(id).parent().parent().addClass('ok'); $('#date_due_' + data.itemnumber).html(CIRCULATION_RETURNED); + if ( data.patronnote != null ) { + $('.patron_note_' + data.itemnumber).html("Patron note: " + data.patronnote); + } } else { content = CIRCULATION_NOT_RETURNED; $(id).parent().parent().addClass('warn'); @@ -213,13 +216,15 @@ $(document).ready(function() { due += "" + oObj.damaged + ""; } + var patron_note = " "; + due +="
" + patron_note; return due; } }, { "mDataProp": function ( oObj ) { - title = "" + oObj.title; @@ -243,7 +248,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 ) { @@ -251,7 +256,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 = ''; @@ -269,7 +274,7 @@ $(document).ready(function() { + "'>" + oObj.barcode + "" - + onsite_checkout; + + onsite_checkout return title; }, diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-issue-note.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-issue-note.tt new file mode 100644 index 0000000..6a68ad8 --- /dev/null +++ b/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 %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt index ef24771..63950cb 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt +++ b/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 ( Koha.Preference('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 ( Koha.Preference('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 ( Koha.Preference('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 }); //]]> diff --git a/opac/opac-issue-note.pl b/opac/opac-issue-note.pl new file mode 100755 index 0000000..3568a8c --- /dev/null +++ b/opac/opac-issue-note.pl @@ -0,0 +1,88 @@ +#!/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 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 C4::Letters; +use Koha::Issues; +use Koha::DateUtils; + +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::Issues->find( $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 ( $issue->set({ notedate => dt_from_string(), note => $clean_note })->store ) { + if ($clean_note) { # only send email if note not empty + my $branch = Koha::Libraries->find( $issue->branchcode ); + my $letter = C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => 'PATRON_NOTE', + branchcode => $branch, + tables => { + 'biblio' => $biblio->{biblionumber}, + 'borrowers' => $member->{borrowernumber}, + }, + ); + C4::Message->enqueue($letter, $member, 'email'); + } + } + print $query->redirect("/cgi-bin/koha/opac-user.pl"); +} + +output_html_with_http_headers $query, $cookie, $template->output, undef, { force_no_caching => 1 }; diff --git a/opac/opac-user.pl b/opac/opac-user.pl index 04a94c0..1f5154b 100755 --- a/opac/opac-user.pl +++ b/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; @@ -262,6 +263,7 @@ if ($issues){ } my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing'); $canrenew = 0 if ($overduesblockrenewing ne 'allow' and $overdues_count == $count); + $template->param( ISSUES => \@issuedat ); $template->param( issues_count => $count ); $template->param( canrenew => $canrenew ); diff --git a/opac/svc/patron_notes b/opac/svc/patron_notes new file mode 100755 index 0000000..6a8981a --- /dev/null +++ b/opac/svc/patron_notes @@ -0,0 +1,108 @@ +#!/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; +use CGI; +use C4::Output qw(:DEFAULT :ajax); +use C4::Scrubber; +use C4::Circulation; +use C4::Members; +use C4::Biblio; +use Koha::Issues; +use Koha::DateUtils; + +=head1 NAME + +svc/patron_notes - Web service for setting patron notes on items + +=head1 DESCRIPTION + +=cut + +# AJAX requests +my $is_ajax = is_ajax(); +my $query = new CGI; +my ( $auth_status, $sessionID ) = check_cookie_auth( $query->cookie('CGISESSID'), {} ); +if ( $auth_status ne "ok" ) { + exit 0; +} +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::Issues->find($issue_id); + if ( $issue->borrowernumber != $borrowernumber ) { + $status = "fail"; + $error = "Invalid issue id!"; + } + } else { + $status = "fail"; + $error = "Invalid issue id!"; + } + + if ( (not $error) && $issue->set({ notedate => dt_from_string(), note => $clean_note })->store ) { + if($clean_note) { # only send email if note not empty + my $branch = Koha::Libraries->find( $issue->branchcode ); + my $biblio = GetBiblioFromItemNumber($issue->itemnumber); + my $letter = C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => 'PATRON_NOTE', + branchcode => $branch, + tables => { + 'biblio' => $biblio->{biblionumber}, + 'borrowers' => $member->{borrowernumber}, + }, + ); + C4::Message->enqueue($letter, $member, 'email'); + } 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 +} diff --git a/svc/checkin b/svc/checkin index c10a1b8..4ffcddf 100755 --- a/svc/checkin +++ b/svc/checkin @@ -1,6 +1,6 @@ #!/usr/bin/perl -# Copyright 2014 ByWater Solutions +# Copyright 2016 Aleisha Amohia # # This file is part of Koha. # @@ -72,6 +72,14 @@ if ( C4::Context->preference("ReturnToShelvingCart") ) { ModItem( $item, $item->{'biblionumber'}, $item->{'itemnumber'} ); } +my $dbh = C4::Context->dbh; +my $query = "SELECT note FROM issues WHERE itemnumber = ?"; +my $sth = $dbh->prepare($query); +$sth->execute($itemnumber); +my $issue = $sth->fetchrow_hashref; +my $patronnote = $issue->{note}; +$data->{patronnote} = $patronnote; + ( $data->{returned} ) = AddReturn( $barcode, $branchcode, $exempt_fine ); print to_json($data); -- 2.1.4