Browse Source

Bug 22818: Add generation and sending of notices

This patch adds the ability for ILL to send notices, both triggered by
staff and triggered by events.

Staff can trigger notices to patrons from the "Manage ILL request" screen:
- ILL request ready for pickup
- ILL request unavailable
- Place request with partners

The following notices to staff are triggered automatically:
- Request has been modified by patron
- Request has been cancelled by patron

Branches can now specify an "ILL email" address to which notices
intended to inform staff of changes to requests by patrons can be sent.

The sending of notices is controlled by a few new sysprefs:
- "ILLDefaultStaffEmail" - Fallback email address for staff ILL notices
to be sent to in the absence of a branch address
- "ILLSendStaffNotices" - To specify which staff notices should be sent
automatically when requests are manipulated by patrons

Patron notices are also controlled by the patron's messaging
preferences

Sponsored-by: PTFS Europe
Signed-off-by: Niamh Walker-Headon <Niamh.Walker-Headon@it-tallaght.ie>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
tags/v20.11.00
Andrew Isherwood 1 year ago
parent
commit
1a7f09709a
6 changed files with 400 additions and 74 deletions
  1. +278
    -72
      Koha/Illrequest.pm
  2. +40
    -1
      Koha/Illrequest/Logger.pm
  3. +35
    -1
      ill/ill-requests.pl
  4. +39
    -0
      koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt
  5. +6
    -0
      koha-tmpl/intranet-tmpl/prog/en/modules/ill/log/patron_notice.tt
  6. +2
    -0
      opac/opac-illrequests.pl

+ 278
- 72
Koha/Illrequest.pm View File

@@ -25,6 +25,8 @@ use Encode qw( encode );
use Try::Tiny;
use DateTime;

use C4::Letters;
use C4::Members;
use Koha::Database;
use Koha::DateUtils qw/ dt_from_string /;
use Koha::Email;
@@ -248,6 +250,7 @@ sub status_alias {

Overloaded getter/setter for request status,
also nullifies status_alias and records the fact that the status has changed
and sends a notice if appropriate

=cut

@@ -281,6 +284,10 @@ sub status {
});
}
delete $self->{previous_status};
# If status has changed to cancellation requested, send a notice
if ($new_status eq 'CANCREQ') {
$self->send_staff_notice('ILL_REQUEST_CANCEL');
}
return $ret;
} else {
return $current_status;
@@ -1287,38 +1294,11 @@ sub generic_confirm {
my $library = Koha::Libraries->find($params->{current_branchcode})
|| die "Invalid current branchcode. Are you logged in as the database user?";
if ( !$params->{stage}|| $params->{stage} eq 'init' ) {
my $draft->{subject} = "ILL Request";
$draft->{body} = <<EOF;
Dear Sir/Madam,

We would like to request an interlibrary loan for a title matching the
following description:

EOF

my $details = $self->metadata;
while (my ($title, $value) = each %{$details}) {
$draft->{body} .= " - " . $title . ": " . $value . "\n"
if $value;
}
$draft->{body} .= <<EOF;

Please let us know if you are able to supply this to us.

Kind Regards

EOF

my @address = map { $library->$_ }
qw/ branchname branchaddress1 branchaddress2 branchaddress3
branchzip branchcity branchstate branchcountry branchphone
branchillemail branchemail /;
my $address = "";
foreach my $line ( @address ) {
$address .= $line . "\n" if $line;
}

$draft->{body} .= $address;
# Get the message body from the notice definition
my $letter = $self->get_notice({
notice_code => 'ILL_PARTNER_REQ',
transport => 'email'
});

my $partners = Koha::Patrons->search({
categorycode => $self->_config->partner_code
@@ -1330,7 +1310,10 @@ EOF
method => 'generic_confirm',
stage => 'draft',
value => {
draft => $draft,
draft => {
subject => $letter->{title},
body => $letter->{content}
},
partners => $partners,
}
};
@@ -1346,57 +1329,280 @@ EOF
"No target email addresses found. Either select at least one partner or check your ILL partner library records.")
if ( !$to );
# Create the from, replyto and sender headers
my $from = $library->branchemail;
my $reply_to = $library->branchreplyto || $from;
my $from = $branch->branchillemail || $branch->branchemail;
my $replyto = $branch->branchreplyto || $from;
Koha::Exceptions::Ill::NoLibraryEmail->throw(
"Your library has no usable email address. Please set it.")
if ( !$from );

# Create the email
my $email = Koha::Email->create(
{
to => $to,
from => $from,
reply_to => $reply_to,
subject => $params->{subject},
text_body => $params->{body},
# So we get a notice hashref, then substitute the possibly
# modified title and body from the draft stage
my $letter = $self->get_notice({
notice_code => 'ILL_PARTNER_REQ',
transport => 'email'
});
$letter->{title} = $params->{subject};
$letter->{content} = $params->{body};

# Send the email
my $params = {
letter => $letter,
borrowernumber => $self->borrowernumber,
message_transport_type => 'email',
to_address => $to,
from_address => $from
};

if ($letter) {
my $result = C4::Letters::EnqueueLetter($params);
if ( $result ) {
$self->status("GENREQ")->store;
$self->_backend_capability(
'set_requested_partners',
{
request => $self,
to => $to
}
);
return {
error => 0,
status => '',
message => '',
method => 'generic_confirm',
stage => 'commit',
next => 'illview',
};
}
);
}
return {
error => 1,
status => 'email_failed',
message => 'Email queueing failed',
method => 'generic_confirm',
stage => 'draft',
};
} else {
die "Unknown stage, should not have happened."
}
}

# Send it
try {
=head3 get_staff_to_address

$email->send_or_die({ transport => $library->smtp_server->transport });
my $email = $request->get_staff_to_address();

$self->status("GENREQ")->store;
$self->_backend_capability(
'set_requested_partners',
{
request => $self,
to => $to
}
);
return {
error => 0,
status => '',
message => '',
method => 'generic_confirm',
stage => 'commit',
next => 'illview',
};
Get the email address to which staff notices should be sent

=cut

sub get_staff_to_address {
my ( $self ) = @_;

# The various places we can get an ILL staff email address from
# (In order of preference)
#
# Dedicated branch address
my $library = Koha::Libraries->find( $self->branchcode );
my $branch_ill_to = $library->branchillemail;
# General purpose ILL address from syspref
my $syspref = C4::Context->preference("ILLDefaultStaffEmail");
# Branch general email address
my $branch_to = $library->branchemail;
# Last resort
my $koha_admin = C4::Context->preference('KohaAdminEmailAddress');

my $to;
if ($branch_ill_to) {
$to = $branch_ill_to;
} elsif ($syspref) {
$to = $syspref;
} elsif ($branch_to) {
$to = $branch_to;
} elsif ($koha_admin) {
$to = $koha_admin;
}

# $to will not be defined if we didn't find a usable address
return $to;
}

=head3 send_patron_notice

my $result = $request->send_patron_notice($notice_code);

Send a specified notice regarding this request to a patron

=cut

sub send_patron_notice {
my ( $self, $notice_code ) = @_;

# We need a notice code
if (!$notice_code) {
return {
error => 'notice_no_type'
};
}

# Map from the notice code to the messaging preference
my %message_name = (
ILL_PICKUP_READY => 'Ill_ready',
ILL_REQUEST_UNAVAIL => 'Ill_unavailable'
);

# Get the patron's messaging preferences
my $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences({
borrowernumber => $self->borrowernumber,
message_name => $message_name{$notice_code}
});
my @transports = keys %{ $borrower_preferences->{transports} };

# Send the notice to the patron via the chosen transport methods
# and record the results
my @success = ();
my @fail = ();
for my $transport (@transports) {
my $letter = $self->get_notice({
notice_code => $notice_code,
transport => $transport
});
if ($letter) {
my $result = C4::Letters::EnqueueLetter({
letter => $letter,
borrowernumber => $self->borrowernumber,
message_transport_type => $transport,
});
if ($result) {
push @success, $transport;
} else {
push @fail, $transport;
}
} else {
push @fail, $transport;
}
catch {
return {
error => 1,
status => 'email_failed',
message => "$_",
method => 'generic_confirm',
stage => 'draft',
};
}
if (scalar @success > 0) {
my $logger = Koha::Illrequest::Logger->new;
$logger->log_patron_notice({
request => $self,
notice_code => $notice_code
});
}
return {
result => {
success => \@success,
fail => \@fail
}
};
}

=head3 send_staff_notice

my $result = $request->send_staff_notice($notice_code);

Send a specified notice regarding this request to staff

=cut

sub send_staff_notice {
my ( $self, $notice_code ) = @_;

# We need a notice code
if (!$notice_code) {
return {
error => 'notice_no_type'
};
}

# Get the staff notices that have been assigned for sending in
# the syspref
my $staff_to_send = C4::Context->preference('ILLSendStaffNotices');

# If it hasn't been enabled in the syspref, we don't want to send it
if ($staff_to_send !~ /\b$notice_code\b/) {
return {
error => 'notice_not_enabled'
};
}

my $letter = $self->get_notice({
notice_code => $notice_code,
transport => 'email'
});

# Try and get an address to which to send staff notices
my $to_address = scalar $self->get_staff_to_address;

my $params = {
letter => $letter,
borrowernumber => $self->borrowernumber,
message_transport_type => 'email',
};

if ($to_address) {
$params->{to_address} = $to_address;
$params->{from_address} = $to_address;
} else {
die "Unknown stage, should not have happened."
return {
error => 'notice_no_create'
};
}

if ($letter) {
C4::Letters::EnqueueLetter($params)
or warn "can't enqueue letter $letter";
return {
success => 'notice_queued'
};
} else {
return {
error => 'notice_no_create'
};
}
}

=head3 get_notice

my $notice = $request->get_notice($params);

Return a compiled notice hashref for the passed notice code
and transport type

=cut

sub get_notice {
my ( $self, $params ) = @_;

my $title = $self->illrequestattributes->find(
{ type => 'title' }
);
my $author = $self->illrequestattributes->find(
{ type => 'author' }
);
my $metahash = $self->metadata;
my @metaarray = ();
while (my($key, $value) = each %{$metahash}) {
push @metaarray, "- $key: $value" if $value;
}
my $metastring = join("\n", @metaarray);
my $letter = C4::Letters::GetPreparedLetter(
module => 'ill',
letter_code => $params->{notice_code},
message_transport_type => $params->{transport},
lang => $self->patron->lang,
tables => {
illrequests => $self->illrequest_id,
borrowers => $self->borrowernumber,
biblio => $self->biblio_id,
branches => $self->branchcode,
},
substitute => {
ill_bib_title => $title ? $title->value : 'N/A',
ill_bib_author => $author ? $author->value : 'N/A',
ill_full_metadata => $metastring
}
);

return $letter;
}

=head3 id_prefix


+ 40
- 1
Koha/Illrequest/Logger.pm View File

@@ -26,6 +26,7 @@ use C4::Context;
use C4::Templates;
use C4::Log qw( logaction );
use Koha::ActionLogs;
use Koha::Notice::Template;

=head1 NAME

@@ -62,6 +63,9 @@ sub new {
$self->{loggers} = {
status => sub {
$self->log_status_change(@_);
},
patron_notice => sub {
$self->log_patron_notice(@_);
}
};

@@ -70,7 +74,8 @@ sub new {
C4::Templates::_get_template_file('ill/log/', 'intranet', $query);

$self->{templates} = {
STATUS_CHANGE => $base . 'status_change.tt'
STATUS_CHANGE => $base . 'status_change.tt',
PATRON_NOTICE => $base . 'patron_notice.tt'
};

bless $self, $class;
@@ -103,6 +108,31 @@ sub log_maybe {
}
}

=head3 log_patron_notice

Koha::IllRequest::Logger->log_patron_notice($params);

Receive a hashref containing a request object and params to log,
and log it

=cut

sub log_patron_notice {
my ( $self, $params ) = @_;

if (defined $params->{request} && defined $params->{notice_code}) {
$self->log_something({
modulename => 'ILL',
actionname => 'PATRON_NOTICE',
objectnumber => $params->{request}->id,
infos => to_json({
log_origin => 'core',
notice_code => $params->{notice_code}
})
});
}
}

=head3 log_status_change

Koha::IllRequest::Logger->log_status_change($params);
@@ -210,6 +240,14 @@ sub get_request_logs {
{ order_by => { -desc => "timestamp" } }
)->unblessed;

# Populate a lookup table for all ILL notice types
my $notice_types = Koha::Notice::Templates->search({
module => 'ill'
})->unblessed;
my $notice_hash;
foreach my $notice(@{$notice_types}) {
$notice_hash->{$notice->{code}} = $notice;
}
# Populate a lookup table for status aliases
my $aliases = C4::Koha::GetAuthorisedValues('ILLSTATUS');
my $alias_hash;
@@ -217,6 +255,7 @@ sub get_request_logs {
$alias_hash->{$alias->{authorised_value}} = $alias;
}
foreach my $log(@{$logs}) {
$log->{notice_types} = $notice_hash;
$log->{aliases} = $alias_hash;
$log->{info} = from_json($log->{info});
$log->{template} = $self->get_log_template({


+ 35
- 1
ill/ill-requests.pl View File

@@ -23,6 +23,7 @@ use CGI;

use C4::Auth;
use C4::Output;
use Koha::Notice::Templates;
use Koha::AuthorisedValues;
use Koha::Illcomment;
use Koha::Illrequests;
@@ -72,12 +73,28 @@ if ( $backends_available ) {
# View the details of an ILL
my $request = Koha::Illrequests->find($params->{illrequest_id});

# Get the details for notices that can be sent from here
my $notices = Koha::Notice::Templates->search(
{
module => 'ill',
code => { -in => [ 'ILL_PICKUP_READY' ,'ILL_REQUEST_UNAVAIL' ] },
},
{
columns => [ qw/code name/ ],
distinct => 1
}
)->unblessed;

$template->param(
notices => $notices,
request => $request,
csrf_token => Koha::Token->new->generate_csrf({
session_id => scalar $cgi->cookie('CGISESSID'),
}),
( $params->{error} ? ( error => $params->{error} ) : () ),
( $params->{tran_error} ?
( tran_error => $params->{tran_error} ) : () ),
( $params->{tran_success} ?
( tran_success => $params->{tran_success} ) : () ),
);

} elsif ( $op eq 'create' ) {
@@ -380,6 +397,23 @@ if ( $backends_available ) {
);
exit;

} elsif ( $op eq "send_notice" ) {
my $illrequest_id = $params->{illrequest_id};
my $request = Koha::Illrequests->find($illrequest_id);
my $ret = $request->send_patron_notice($params->{notice_code});
my $append = '';
if ($ret->{result} && scalar @{$ret->{result}->{success}} > 0) {
$append .= '&tran_success=' . join(',', @{$ret->{result}->{success}});
}
if ($ret->{result} && scalar @{$ret->{result}->{fail}} > 0) {
$append .= '&tran_fail=' . join(',', @{$ret->{result}->{fail}}.join(','));
}
# Redirect to view the whole request
print $cgi->redirect(
"/cgi-bin/koha/ill/ill-requests.pl?method=illview&illrequest_id=".
scalar $params->{illrequest_id} . $append
);
exit;
} else {
my $request = Koha::Illrequests->find($params->{illrequest_id});
my $backend_result = $request->custom_capability($op, $params);


+ 39
- 0
koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt View File

@@ -99,6 +99,10 @@
</p>
[% END %]

[% IF whole.success %]
<p>[% whole.success | html %]</p>
[% END %]

[% IF query_type == 'create' %]
<h1>New ILL request</h1>
[% PROCESS $whole.template %]
@@ -462,6 +466,31 @@
[% END %]
[% END %]

[% IF tran_success %]
[% succ_methods = [] %]
[% IF tran_success.match('email') %]
[% succ_methods.push('email') %]
[% END %]
[% IF tran_success.match('sms') %]
[% succ_methods.push('SMS') %]
[% END %]
<div class="alert">
The requested notice was queued for delivery by [% succ_methods.join(', ') | html %]
</div>
[% END %]
[% IF tran_fail %]
[% fail_methods = [] %]
[% IF tran_fail.match('email') %]
[% fail_methods.push('email') %]
[% END %]
[% IF tran_fail.match('sms') %]
[% fail_methods.push('SMS') %]
[% END %]
<div class="alert">
The requested notice was NOT queued for delivery by [% fail_methods.join(', ') | html %]
</div>
[% END %]

<h1>Manage ILL request</h1>
<div id="request-toolbar" class="btn-toolbar">
<a title="Edit request" id="ill-toolbar-btn-edit-action" class="btn btn-default" href="/cgi-bin/koha/ill/ill-requests.pl?method=edit_action&amp;illrequest_id=[% request.illrequest_id | html %]">
@@ -523,6 +552,16 @@
</a>
[% END %]
[% END %]
<div class="dropdown btn-group">
<button class="btn btn-default dropdown-toggle" type="button" id="ill-notice-dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-envelope"></i> Send notice to patron <span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="ill-notice-dropdown">
[% FOREACH notice IN notices %]
<li><a href="/cgi-bin/koha/ill/ill-requests.pl?method=send_notice&amp;illrequest_id=[% request.illrequest_id | uri %]&amp;notice_code=[% notice.code | uri %]">[% notice.name | html %]</a></li>
[% END %]
</ul>
</div>
<a title="Display supplier metadata" id="ill-request-display-metadata" class="btn btn-default pull-right" href="#">
<span class="fa fa-eye"></span>
Display supplier metadata


+ 6
- 0
koha-tmpl/intranet-tmpl/prog/en/modules/ill/log/patron_notice.tt View File

@@ -0,0 +1,6 @@
[% USE KohaDates %]
<p>
[% log.timestamp | $KohaDates with_hours => 1 %] : <b>Patron notice sent: </b>
[% notice_code = log.info.notice_code %]
&quot;[% log.notice_types.$notice_code.name | html %]&quot;
</p>

+ 2
- 0
opac/opac-illrequests.pl View File

@@ -85,6 +85,8 @@ if ( $op eq 'list' ) {
illrequest_id => $params->{illrequest_id}
});
$request->notesopac($params->{notesopac})->store;
# Send a notice to staff alerting them of the update
$request->send_staff_notice('ILL_REQUEST_MODIFIED');
print $query->redirect(
'/cgi-bin/koha/opac-illrequests.pl?method=view&illrequest_id=' .
$params->{illrequest_id} .


Loading…
Cancel
Save