View | Details | Raw Unified | Return to bug 14224
Collapse All | Expand All

(-)a/C4/Circulation.pm (-2 / +41 lines)
Lines 92-97 BEGIN { Link Here
92
        &GetBranchItemRule
92
        &GetBranchItemRule
93
		&GetBiblioIssues
93
		&GetBiblioIssues
94
		&GetOpenIssue
94
		&GetOpenIssue
95
        &SetIssueNote
95
		&AnonymiseIssueHistory
96
		&AnonymiseIssueHistory
96
        &CheckIfIssuedToPatron
97
        &CheckIfIssuedToPatron
97
        &IsItemIssued
98
        &IsItemIssued
Lines 2450-2456 sub GetOpenIssue { Link Here
2450
=head2 GetIssues
2451
=head2 GetIssues
2451
2452
2452
    $issues = GetIssues({});    # return all issues!
2453
    $issues = GetIssues({});    # return all issues!
2453
    $issues = GetIssues({ borrowernumber => $borrowernumber, biblionumber => $biblionumber });
2454
    $issues = GetIssues({ borrowernumber => $borrowernumber, biblionumber => $biblionumber, issue_id => $issue_id });
2454
2455
2455
Returns all pending issues that match given criteria.
2456
Returns all pending issues that match given criteria.
2456
Returns a arrayref or undef if an error occurs.
2457
Returns a arrayref or undef if an error occurs.
Lines 2465-2470 Allowed criteria are: Link Here
2465
2466
2466
=item * itemnumber
2467
=item * itemnumber
2467
2468
2469
=item * issue_id
2470
2468
=back
2471
=back
2469
2472
2470
=cut
2473
=cut
Lines 2474-2480 sub GetIssues { Link Here
2474
2477
2475
    # Build filters
2478
    # Build filters
2476
    my @filters;
2479
    my @filters;
2477
    my @allowed = qw(borrowernumber biblionumber itemnumber);
2480
    my @allowed = qw(borrowernumber biblionumber itemnumber issue_id);
2478
    foreach (@allowed) {
2481
    foreach (@allowed) {
2479
        if (defined $criteria->{$_}) {
2482
        if (defined $criteria->{$_}) {
2480
            push @filters, {
2483
            push @filters, {
Lines 3968-3973 sub GetPendingOnSiteCheckouts { Link Here
3968
    |, { Slice => {} } );
3971
    |, { Slice => {} } );
3969
}
3972
}
3970
3973
3974
=head2 SetIssueNote
3975
3976
  &SetIssueNote($issue_id, $note);
3977
3978
Sets a note to the issuenotes table for the given issue.
3979
3980
=over 4
3981
3982
=item C<$issue_id> is the id of the issue for which to set the note
3983
3984
=item C<$note> is the note to set
3985
3986
=back
3987
3988
Returns:
3989
  True on success
3990
  False on failure
3991
3992
=cut
3993
3994
sub SetIssueNote {
3995
    my ( $issue_id, $note) = @_;
3996
3997
    my $dbh  = C4::Context->dbh;
3998
3999
    if ( ! ( $issue_id && $note ) or not $issue_id =~ /\d+/) {
4000
      return;
4001
    }
4002
4003
    my $query = "UPDATE issues SET notedate=NOW(),note=? WHERE issue_id=?";
4004
    my $sth = $dbh->prepare($query);
4005
    $sth->execute( $note, $issue_id );
4006
    return 1;
4007
}
4008
4009
3971
__END__
4010
__END__
3972
4011
3973
=head1 AUTHOR
4012
=head1 AUTHOR
(-)a/circ/returns.pl (+3 lines)
Lines 269-274 if ($barcode) { Link Here
269
    my $hbr = GetBranchItemRule($biblio->{'homebranch'}, $itemtype)->{'returnbranch'} || "homebranch";
269
    my $hbr = GetBranchItemRule($biblio->{'homebranch'}, $itemtype)->{'returnbranch'} || "homebranch";
270
    my $returnbranch = $biblio->{$hbr} ;
270
    my $returnbranch = $biblio->{$hbr} ;
271
271
272
    my $issue = GetItemIssue($itemnumber);
273
272
    $template->param(
274
    $template->param(
273
        title            => $biblio->{'title'},
275
        title            => $biblio->{'title'},
274
        homebranch       => $biblio->{'homebranch'},
276
        homebranch       => $biblio->{'homebranch'},
Lines 281-286 if ($barcode) { Link Here
281
        biblionumber     => $biblio->{'biblionumber'},
283
        biblionumber     => $biblio->{'biblionumber'},
282
        borrower         => $borrower,
284
        borrower         => $borrower,
283
        additional_materials => $biblio->{'materials'},
285
        additional_materials => $biblio->{'materials'},
286
        issue            => $issue,
284
    );
287
    );
285
288
286
    my %input = (
289
    my %input = (
(-)a/installer/data/mysql/atomicupdate/bug_14224-add_new_issue_columns.sql (+2 lines)
Line 0 Link Here
1
ALTER TABLE issues ADD COLUMN `note` mediumtext default NULL; -- issue note text
2
ALTER TABLE issues ADD COLUMN `notedate` datetime default NULL; -- datetime of issue note (yyyy-mm-dd hh:mm::ss)
(-)a/installer/data/mysql/kohastructure.sql (+2 lines)
Lines 1156-1161 CREATE TABLE `issues` ( -- information related to check outs or issues Link Here
1156
  `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, -- the date and time this record was last touched
1156
  `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, -- the date and time this record was last touched
1157
  `issuedate` datetime default NULL, -- date the item was checked out or issued
1157
  `issuedate` datetime default NULL, -- date the item was checked out or issued
1158
  `onsite_checkout` int(1) NOT NULL default 0, -- in house use flag
1158
  `onsite_checkout` int(1) NOT NULL default 0, -- in house use flag
1159
  `note` mediumtext default NULL, -- issue note text
1160
  `notedate` datetime default NULL, -- datetime of issue note (yyyy-mm-dd hh:mm::ss)
1159
  PRIMARY KEY (`issue_id`),
1161
  PRIMARY KEY (`issue_id`),
1160
  KEY `issuesborridx` (`borrowernumber`),
1162
  KEY `issuesborridx` (`borrowernumber`),
1161
  KEY `itemnumber_idx` (`itemnumber`),
1163
  KEY `itemnumber_idx` (`itemnumber`),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt (+10 lines)
Lines 123-128 $(document).ready(function () { Link Here
123
 <div id="rotating-collection" class="dialog message">This item is part of a rotating collection and needs to be transferred to [% collectionBranch %]</div>
123
 <div id="rotating-collection" class="dialog message">This item is part of a rotating collection and needs to be transferred to [% collectionBranch %]</div>
124
[% END %]
124
[% END %]
125
125
126
<!-- Patron has added an issue note -->
127
[% IF ( issue.note) %]
128
    <div class="dialog message">
129
        <h1>Patron note</h1>
130
        <p>[% issue.notedate %]</p>
131
        <p><a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% itembiblionumber %]"> [% title |html %]</a> [% author %]</p>
132
        <p>[% issue.note %]</p>
133
    </div>
134
[% END %]
135
126
<!-- Patron has fines -->
136
<!-- Patron has fines -->
127
[% IF ( fines ) %]
137
[% IF ( fines ) %]
128
    <div class="dialog alert">
138
    <div class="dialog alert">
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-sendissuenote.tt (+21 lines)
Line 0 Link Here
1
<SUBJECT>
2
Issue note for [% title %] [% author %]
3
<END_SUBJECT>
4
5
[% USE HtmlToText %]
6
7
<HEADER>
8
[% FILTER html2text %]
9
    <p>Hi,</p>
10
    <p>[% MEMBER.firstname %] [% MEMBER.surname %] sent you the following note related to the check out of
11
    <p>[% title %] [% author %].</p>
12
[% END %]
13
14
<END_HEADER>
15
16
<MESSAGE>
17
[% FILTER html2text %]
18
    [% note %]
19
[% END %]
20
21
<END_MESSAGE>
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt (+45 lines)
Lines 98-103 Link Here
98
                        </div>
98
                        </div>
99
                    [% END # / IF patron_flagged %]
99
                    [% END # / IF patron_flagged %]
100
100
101
                    <div class="alert alert-info" id="notesaved" style="display:none"></div>
102
101
                    [% SET OPACMySummaryNote = Koha.Preference('OPACMySummaryNote') %]
103
                    [% SET OPACMySummaryNote = Koha.Preference('OPACMySummaryNote') %]
102
                    [% IF OPACMySummaryNote %][% OPACMySummaryNote %][% END %]
104
                    [% IF OPACMySummaryNote %][% OPACMySummaryNote %][% END %]
103
105
Lines 142-147 Link Here
142
                                                [% IF ( OPACMySummaryHTML ) %]
144
                                                [% IF ( OPACMySummaryHTML ) %]
143
                                                    <th class="nosort">Links</th>
145
                                                    <th class="nosort">Links</th>
144
                                                [% END %]
146
                                                [% END %]
147
                                                    <th class="nosort">Note</th>
145
                                            </tr>
148
                                            </tr>
146
                                        </thead>
149
                                        </thead>
147
                                        <tbody>
150
                                        <tbody>
Lines 254-259 Link Here
254
                                                [% IF ( OPACMySummaryHTML ) %]
257
                                                [% IF ( OPACMySummaryHTML ) %]
255
                                                    <td class="links">[% ISSUE.MySummaryHTML %]</td>
258
                                                    <td class="links">[% ISSUE.MySummaryHTML %]</td>
256
                                                [% END %]
259
                                                [% END %]
260
                                                    <td class="note">
261
                                                        <input type="text" data-issue_id="[% ISSUE.issue_id%]" name="note" value="[% ISSUE.note %]"></input>
262
                                                    </td>
257
                                            </tr>
263
                                            </tr>
258
                                        [% END # /FOREACH ISSUES %]
264
                                        [% END # /FOREACH ISSUES %]
259
                                    </tbody>
265
                                    </tbody>
Lines 732-737 Link Here
732
                [% END %]
738
                [% END %]
733
            [% END %]
739
            [% END %]
734
740
741
            $("input[name='note']").keyup(function(e){
742
                var self = $(this);
743
                if(e.which == 13) {
744
                    e.preventDefault();
745
                    if(!self.val()) return;
746
747
                    var ajaxData = {
748
                        'issue_id': $(this).data('issue_id'),
749
                        'note': self.val()
750
                    };
751
752
                    $.ajax({
753
                        url: '/cgi-bin/koha/opac-user.pl',
754
                        type: 'POST',
755
                        dataType: 'json',
756
                        data: ajaxData,
757
                    })
758
                    .done(function(data) {
759
                        if(data.status == 'success') {
760
                            $("#notesaved").removeClass("alert-error");
761
                            $("#notesaved").addClass("alert-info");
762
                            $("#notesaved").html("Note saved and sent to library.");
763
                        } else {
764
                            $("#notesaved").removeClass("alert-info");
765
                            $("#notesaved").addClass("alert-error");
766
                            $("#notesaved").html(data.error);
767
                        }
768
                    })
769
                    .fail(function(data) {
770
                        $("#notesaved").removeClass("alert-info");
771
                        $("#notesaved").addClass("alert-error");
772
                        $("#notesaved").html("Ajax request failed. Could not save note.");
773
                    })
774
                    .always(function() {
775
                        $("#notesaved").show();
776
                    });
777
                }
778
            });
779
735
            $( ".suspend-until" ).datepicker({ minDate: 1 }); // Require that "until date" be in the future
780
            $( ".suspend-until" ).datepicker({ minDate: 1 }); // Require that "until date" be in the future
736
        });
781
        });
737
        //]]>
782
        //]]>
(-)a/opac/opac-user.pl (-3 / +118 lines)
Lines 22-39 use strict; Link Here
22
22
23
use CGI qw ( -utf8 );
23
use CGI qw ( -utf8 );
24
24
25
use C4::Auth;
25
use Mail::Sendmail;
26
use MIME::QuotedPrint;
27
use Carp;
28
use C4::Auth qw(:DEFAULT check_cookie_auth);
26
use C4::Koha;
29
use C4::Koha;
27
use C4::Circulation;
30
use C4::Circulation;
28
use C4::Reserves;
31
use C4::Reserves;
29
use C4::Members;
32
use C4::Members;
30
use C4::Members::AttributeTypes;
33
use C4::Members::AttributeTypes;
31
use C4::Members::Attributes qw/GetBorrowerAttributeValue/;
34
use C4::Members::Attributes qw/GetBorrowerAttributeValue/;
32
use C4::Output;
35
use CGI::Cookie; # need to check cookies before having CGI parse the POST request
36
use C4::Output qw(:DEFAULT :ajax);
37
use C4::Scrubber;
33
use C4::Biblio;
38
use C4::Biblio;
34
use C4::Items;
39
use C4::Items;
35
use C4::Letters;
40
use C4::Letters;
36
use C4::Branch; # GetBranches
41
use C4::Branch; # GetBranches
42
use Koha::Email;
37
use Koha::DateUtils;
43
use Koha::DateUtils;
38
use Koha::Borrower::Debarments qw(IsDebarred);
44
use Koha::Borrower::Debarments qw(IsDebarred);
39
45
Lines 54-59 BEGIN { Link Here
54
    }
60
    }
55
}
61
}
56
62
63
sub ajax_auth_cgi {     # returns CGI object
64
	my $needed_flags = shift;
65
	my %cookies = fetch CGI::Cookie;
66
	my $input = CGI->new;
67
    my $sessid = $cookies{'CGISESSID'}->value;
68
	my ($auth_status, $auth_sessid) = check_cookie_auth($sessid, $needed_flags);
69
	if ($auth_status ne "ok") {
70
		output_with_http_headers $input, undef,
71
		"window.alert('Your CGI session cookie ($sessid) is not current.  " .
72
		"Please refresh the page and try again.');\n", 'js';
73
		exit 0;
74
	}
75
	return $input;
76
}
77
78
my $is_ajax = is_ajax();
79
my $query = ($is_ajax) ? &ajax_auth_cgi({}) : CGI->new();
80
if ($is_ajax) {
81
    my $scrubber = C4::Scrubber->new();
82
    my $note = $query->param('note');
83
    my $issue_id = $query->param('issue_id');
84
    my $clean_note = $scrubber->scrub($note);
85
    my $status = "success";
86
    my $error = "";
87
    my ($error, $member, $issue);
88
89
    my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
90
        {
91
            template_name   => "opac-sendissuenote.tt",
92
            query           => $query,
93
            type            => "opac",
94
            authnotrequired => 1,
95
        }
96
    );
97
98
    # verify issue_id
99
    if ( $issue_id =~ /\d+/ ) {
100
        $member = GetMember(borrowernumber => $borrowernumber);
101
        ($issue) = @{C4::Circulation::GetIssues({issue_id => $issue_id})};
102
103
        if ( $issue->{'borrowernumber'} != $borrowernumber ) {
104
            $status = "fail";
105
            $error = "Invalid issue id!";
106
        }
107
    } else {
108
        $status = "fail";
109
        $error = "Invalid issue id!";
110
    }
111
112
    if ( (not $error) && SetIssueNote($issue_id, $clean_note) ) {
113
        my $branch = GetBranchDetail($issue->{'branchcode'});
114
115
        if ( $branch->{'branchemail'} ) {
116
            my $biblio = GetBiblioFromItemNumber($issue->{'itemnumber'});
117
            my $message = Koha::Email->new();
118
            my %mail = $message->create_message_headers();
119
120
            $template->param(
121
                author => $biblio->{'author'},
122
                title => $biblio->{'title'},
123
                MEMBER => $member,
124
                note => $clean_note,
125
            );
126
127
            # Getting template result
128
            my $template_res = $template->output();
129
            my $body;
130
131
            # Analysing information and getting mail properties
132
            if ( $template_res =~ /<SUBJECT>(.*)<END_SUBJECT>/s ) {
133
                $mail{subject} = $1;
134
                $mail{subject} =~ s|\n?(.*)\n?|$1|;
135
            }
136
            else { $mail{'subject'} = "no subject"; }
137
            $mail{subject} = Encode::encode("UTF-8", $mail{subject});
138
139
            my $email_header = "";
140
            if ( $template_res =~ /<HEADER>(.*)<END_HEADER>/s ) {
141
                $email_header = $1;
142
                $email_header =~ s|\n?(.*)\n?|$1|;
143
                $email_header = encode_qp(Encode::encode("UTF-8", $email_header));
144
            }
145
146
            if ( $template_res =~ /<MESSAGE>(.*)<END_MESSAGE>/s ) {
147
                $body = $1;
148
                $body =~ s|\n?(.*)\n?|$1|;
149
                $body = encode_qp(Encode::encode("UTF-8", $body));
150
            }
151
152
            $mail{to} = $branch->{'branchemail'};
153
            $mail{from} = $member->{'email'} || ($branch->{'branchemail'}=~s/^.+@/noreply@/ && $branch->{'branchemail'});
154
            $mail{body} = $email_header . $body;
155
156
            unless ( sendmail(%mail) ) {
157
                $status = "fail";
158
                $error = "Could not send message to library. Message will still show at check in.";
159
                carp "Error sending mail: $Mail::Sendmail::error \n";
160
            }
161
        }
162
    } else {
163
        $status = "fail";
164
        $error = "Could not save note. Invalid issue id or empty note.";
165
    }
166
167
    my $response = "{\"status\": \"$status\", \"note\": \"$clean_note\", \"issue_id\": \"$issue_id\", \"error\": \"$error\"}";
168
	output_with_http_headers($query, undef, $response, 'js');
169
    exit;
170
}
171
172
57
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
173
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
58
    {
174
    {
59
        template_name   => "opac-user.tt",
175
        template_name   => "opac-user.tt",
60
- 

Return to bug 14224