Bug 30484: Implement support for ILL request updates
This commit adds support for the concept of ILL request update notices. - Adds a new Koha::Illrequest::SupplierUpdate class that is used to encapsulate an update to a request, this update may come from a supplier via a backend or from core ILL via, perhaps, a user action - Adds a new Koha::Illrequest::SupplierUpdateProcessor base class that can be subclassed in order to create a processor that can be passed an update and act accordingly. - Updates to Illrequest.pm to support the above classes and allow core Koha to offer update processors - A shell script to initiate a periodic process to check for updates meeting given criteria and run the appropriate processors Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de> https://bugs.koha-community.org/show_bug.cgi?id=28909 Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
parent
adf0094d66
commit
65a2fc2fa3
4 changed files with 505 additions and 6 deletions
|
@ -116,6 +116,33 @@ available for request.
|
|||
|
||||
=head2 Class methods
|
||||
|
||||
=head3 init_processors
|
||||
|
||||
$request->init_processors()
|
||||
|
||||
Initialises an empty processors arrayref
|
||||
|
||||
=cut
|
||||
|
||||
sub init_processors {
|
||||
my ( $self ) = @_;
|
||||
|
||||
$self->{processors} = [];
|
||||
}
|
||||
|
||||
=head3 push_processor
|
||||
|
||||
$request->push_processors(sub { ...something... });
|
||||
|
||||
Pushes a passed processor function into our processors arrayref
|
||||
|
||||
=cut
|
||||
|
||||
sub push_processor {
|
||||
my ( $self, $processor ) = @_;
|
||||
push @{$self->{processors}}, $processor;
|
||||
}
|
||||
|
||||
=head3 statusalias
|
||||
|
||||
my $statusalias = $request->statusalias;
|
||||
|
@ -371,6 +398,7 @@ sub _backend_capability {
|
|||
try {
|
||||
$capability = $self->_backend->capabilities($name);
|
||||
} catch {
|
||||
warn $_;
|
||||
return 0;
|
||||
};
|
||||
# Try to invoke it
|
||||
|
@ -896,6 +924,28 @@ sub backend_create {
|
|||
return $self->expandTemplate($result);
|
||||
}
|
||||
|
||||
=head3 backend_get_update
|
||||
|
||||
my $update = backend_get_update($request);
|
||||
|
||||
Given a request, returns an update in a prescribed
|
||||
format that can then be passed to update parsers
|
||||
|
||||
=cut
|
||||
|
||||
sub backend_get_update {
|
||||
my ( $self, $options ) = @_;
|
||||
|
||||
my $response = $self->_backend_capability(
|
||||
'get_supplier_update',
|
||||
{
|
||||
request => $self,
|
||||
%{$options}
|
||||
}
|
||||
);
|
||||
return $response;
|
||||
}
|
||||
|
||||
=head3 expandTemplate
|
||||
|
||||
my $params = $abstract->expandTemplate($params);
|
||||
|
@ -1437,7 +1487,7 @@ Send a specified notice regarding this request to a patron
|
|||
=cut
|
||||
|
||||
sub send_patron_notice {
|
||||
my ( $self, $notice_code ) = @_;
|
||||
my ( $self, $notice_code, $additional_text ) = @_;
|
||||
|
||||
# We need a notice code
|
||||
if (!$notice_code) {
|
||||
|
@ -1448,8 +1498,9 @@ sub send_patron_notice {
|
|||
|
||||
# Map from the notice code to the messaging preference
|
||||
my %message_name = (
|
||||
ILL_PICKUP_READY => 'Ill_ready',
|
||||
ILL_REQUEST_UNAVAIL => 'Ill_unavailable'
|
||||
ILL_PICKUP_READY => 'Ill_ready',
|
||||
ILL_REQUEST_UNAVAIL => 'Ill_unavailable',
|
||||
ILL_REQUEST_UPDATE => 'Ill_update'
|
||||
);
|
||||
|
||||
# Get the patron's messaging preferences
|
||||
|
@ -1471,8 +1522,9 @@ sub send_patron_notice {
|
|||
my @fail = ();
|
||||
for my $transport (@transports) {
|
||||
my $letter = $self->get_notice({
|
||||
notice_code => $notice_code,
|
||||
transport => $transport
|
||||
notice_code => $notice_code,
|
||||
transport => $transport,
|
||||
additional_text => $additional_text
|
||||
});
|
||||
if ($letter) {
|
||||
my $result = C4::Letters::EnqueueLetter({
|
||||
|
@ -1613,13 +1665,50 @@ sub get_notice {
|
|||
substitute => {
|
||||
ill_bib_title => $title ? $title->value : '',
|
||||
ill_bib_author => $author ? $author->value : '',
|
||||
ill_full_metadata => $metastring
|
||||
ill_full_metadata => $metastring,
|
||||
additional_text => $params->{additional_text}
|
||||
}
|
||||
);
|
||||
|
||||
return $letter;
|
||||
}
|
||||
|
||||
|
||||
=head3 attach_processors
|
||||
|
||||
Receive a Koha::Illrequest::SupplierUpdate and attach
|
||||
any processors we have for it
|
||||
|
||||
=cut
|
||||
|
||||
sub attach_processors {
|
||||
my ( $self, $update ) = @_;
|
||||
|
||||
foreach my $processor(@{$self->{processors}}) {
|
||||
if (
|
||||
$processor->{target_source_type} eq $update->{source_type} &&
|
||||
$processor->{target_source_name} eq $update->{source_name}
|
||||
) {
|
||||
$update->attach_processor($processor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
=head3 append_to_note
|
||||
|
||||
append_to_note("Some text");
|
||||
|
||||
Append some text to the staff note
|
||||
|
||||
=cut
|
||||
|
||||
sub append_to_note {
|
||||
my ($self, $text) = @_;
|
||||
my $current = $self->notesstaff;
|
||||
$text = ($current && length $current > 0) ? "$current\n\n$text" : $text;
|
||||
$self->notesstaff($text)->store;
|
||||
}
|
||||
|
||||
=head3 id_prefix
|
||||
|
||||
my $prefix = $record->id_prefix;
|
||||
|
|
111
Koha/Illrequest/SupplierUpdate.pm
Normal file
111
Koha/Illrequest/SupplierUpdate.pm
Normal file
|
@ -0,0 +1,111 @@
|
|||
package Koha::Illrequest::SupplierUpdate;
|
||||
|
||||
# Copyright 2022 PTFS Europe Ltd
|
||||
#
|
||||
# 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;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::Illrequest::SupplierUpdate - Represents a single request update from a supplier
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
Object-oriented class that provides an object allowing us to interact with
|
||||
an update from a supplier
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Object-oriented class that provides an object allowing us to interact with
|
||||
an update from a supplier
|
||||
|
||||
=head1 API
|
||||
|
||||
=head2 Class Methods
|
||||
|
||||
=head3 new
|
||||
|
||||
my $update = Koha::Illrequest::SupplierUpdate->new(
|
||||
$source_type,
|
||||
$source_name,
|
||||
$update
|
||||
);
|
||||
|
||||
Create a new Koha::Illrequest::SupplierUpdate object.
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my ( $class, $source_type, $source_name, $update, $request ) = @_;
|
||||
my $self = {};
|
||||
|
||||
$self->{source_type} = $source_type;
|
||||
$self->{source_name} = $source_name;
|
||||
$self->{update} = $update;
|
||||
$self->{request} = $request;
|
||||
$self->{processors} = [];
|
||||
|
||||
bless $self, $class;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
=head3 attach_processor
|
||||
|
||||
Koha::Illrequest::SupplierUpdate->attach_processor($processor);
|
||||
|
||||
Pushes a processor function onto the 'processors' arrayref
|
||||
|
||||
=cut
|
||||
|
||||
sub attach_processor {
|
||||
my ( $self, $processor ) = @_;
|
||||
push(@{$self->{processors}}, $processor);
|
||||
}
|
||||
|
||||
=head3 run_processors
|
||||
|
||||
Koha::Illrequest::SupplierUpdate->run_processors();
|
||||
|
||||
Iterates all processors on this object and runs each
|
||||
|
||||
=cut
|
||||
|
||||
sub run_processors {
|
||||
my ( $self, $options ) = @_;
|
||||
my $results = [];
|
||||
foreach my $processor(@{$self->{processors}}) {
|
||||
my $processor_result = {
|
||||
name => $processor->{name},
|
||||
result => {
|
||||
success => [],
|
||||
error => []
|
||||
}
|
||||
};
|
||||
$processor->run($self, $options, $processor_result->{result});
|
||||
push @{$results}, $processor_result;
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Andrew Isherwood <andrew.isherwood@ptfs-europe.com>
|
||||
|
||||
=cut
|
||||
|
||||
1;
|
85
Koha/Illrequest/SupplierUpdateProcessor.pm
Normal file
85
Koha/Illrequest/SupplierUpdateProcessor.pm
Normal file
|
@ -0,0 +1,85 @@
|
|||
package Koha::Illrequest::SupplierUpdateProcessor;
|
||||
|
||||
# Copyright 2022 PTFS Europe Ltd
|
||||
#
|
||||
# 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;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::Illrequest::SupplierUpdateProcessor - Represents a SupplerUpdate processor
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
Object-oriented class that provides an object allowing us to perform processing on
|
||||
a SupplierUpdate
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Object-oriented base class that provides an object allowing us to perform processing on
|
||||
a SupplierUpdate
|
||||
** This class should not be directly instantiated, it should only be sub-classed **
|
||||
|
||||
=head1 API
|
||||
|
||||
=head2 Class Methods
|
||||
|
||||
=head3 new
|
||||
|
||||
my $processor = Koha::Illrequest::SupplierUpdateProcessor->new(
|
||||
$target_source_type,
|
||||
$target_source_name
|
||||
);
|
||||
|
||||
Create a new Koha::Illrequest::SupplierUpdateProcessor object.
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my ( $class, $target_source_type, $target_source_name, $processor_name ) = @_;
|
||||
my $self = {};
|
||||
|
||||
$self->{target_source_type} = $target_source_type;
|
||||
$self->{target_source_name} = $target_source_name;
|
||||
$self->{name} = $processor_name;
|
||||
|
||||
bless $self, $class;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
=head3 run
|
||||
|
||||
Koha::Illrequest::SupplierUpdateProcessor->run();
|
||||
|
||||
Runs the processor
|
||||
|
||||
=cut
|
||||
|
||||
sub run {
|
||||
my ( $self ) = @_;
|
||||
my ( $package, $filename ) = caller;
|
||||
warn __PACKAGE__ . " run should only be invoked by a subclass\n";
|
||||
}
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Andrew Isherwood <andrew.isherwood@ptfs-europe.com>
|
||||
|
||||
=cut
|
||||
|
||||
1;
|
214
misc/process_ill_updates.pl
Executable file
214
misc/process_ill_updates.pl
Executable file
|
@ -0,0 +1,214 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# This file is part of Koha.
|
||||
#
|
||||
# Copyright (C) 2022 PTFS Europe
|
||||
#
|
||||
# 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 Getopt::Long qw( GetOptions );
|
||||
use POSIX;
|
||||
|
||||
use Koha::Script;
|
||||
use Koha::Illrequests;
|
||||
|
||||
# Command line option values
|
||||
my $get_help = 0;
|
||||
my $statuses = "";
|
||||
my $status_alias = "";
|
||||
my $status_to = "";
|
||||
my $status_alias_to = "";
|
||||
my $backend = "";
|
||||
my $dry_run = 0;
|
||||
my $delay = 0;
|
||||
my $debug = 0;
|
||||
|
||||
my $options = GetOptions(
|
||||
'h|help' => \$get_help,
|
||||
'statuses:s' => \$statuses,
|
||||
'status-alias:s' => \$status_alias,
|
||||
'status-to:s' => \$status_to,
|
||||
'status-alias-to:s' => \$status_alias_to,
|
||||
'backend=s' => \$backend,
|
||||
'dry-run' => \$dry_run,
|
||||
'api-delay:i' => \$delay,
|
||||
'debug' => \$debug
|
||||
);
|
||||
|
||||
if ($get_help) {
|
||||
get_help();
|
||||
exit 1;
|
||||
}
|
||||
|
||||
if (!$backend) {
|
||||
print "No backend specified\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# First check we can proceed
|
||||
my $cfg = Koha::Illrequest::Config->new;
|
||||
my $backends = $cfg->available_backends;
|
||||
my $has_branch = $cfg->has_branch;
|
||||
my $backends_available = ( scalar @{$backends} > 0 );
|
||||
if (!$has_branch || $backends_available == 0) {
|
||||
print "Unable to proceed:\n";
|
||||
print "Branch configured: $has_branch\n";
|
||||
print "Backends available: $backends_available\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# Get all required requests
|
||||
my @statuses_arr = split(/:/, $statuses);
|
||||
my @status_alias_arr = split(/:/, $status_alias);
|
||||
|
||||
my $where = {
|
||||
backend => $backend
|
||||
};
|
||||
|
||||
if (scalar @statuses_arr > 0) {
|
||||
my @or = grep(!/null/, @statuses_arr);
|
||||
if (scalar @or < scalar @statuses_arr) {
|
||||
push @or, undef;
|
||||
}
|
||||
$where->{status} = \@or;
|
||||
}
|
||||
|
||||
if (scalar @status_alias_arr > 0) {
|
||||
my @or = grep(!/null/, @status_alias_arr);
|
||||
if (scalar @or < scalar @status_alias_arr) {
|
||||
push @or, undef;
|
||||
}
|
||||
$where->{status_alias} = \@or;
|
||||
}
|
||||
|
||||
debug_msg("DBIC WHERE:");
|
||||
debug_msg($where);
|
||||
|
||||
my $requests = Koha::Illrequests->search($where);
|
||||
|
||||
debug_msg("Processing " . $requests->count . " requests");
|
||||
|
||||
# Create an options hashref to pass to processors
|
||||
my $options_to_pass = {
|
||||
dry_run => $dry_run,
|
||||
status_to => $status_to,
|
||||
status_alias_to => $status_alias_to,
|
||||
delay => $delay,
|
||||
debug => \&debug_msg
|
||||
};
|
||||
|
||||
# The progress log
|
||||
my $output = [];
|
||||
|
||||
while (my $request = $requests->next) {
|
||||
debug_msg("- Request ID " . $request->illrequest_id);
|
||||
my $update = $request->backend_get_update($options_to_pass);
|
||||
# The log for this request
|
||||
my $update_log = {
|
||||
request_id => $request->illrequest_id,
|
||||
processed_by => $request->_backend->name,
|
||||
processors_run => []
|
||||
};
|
||||
if ($update) {
|
||||
# Currently we make an assumption, this may need revisiting
|
||||
# if we need to extend the functionality:
|
||||
#
|
||||
# Only the backend that originated the update will want to
|
||||
# process it
|
||||
#
|
||||
# Since each backend's update format is different, it may
|
||||
# be necessary for a backend to subclass Koha::Illrequest::SupplierUpdate
|
||||
# so it can provide methods (corresponding to a generic interface) that
|
||||
# return pertinent info to core ILL when it is processing updates
|
||||
#
|
||||
# Attach any request processors
|
||||
$request->attach_processors($update);
|
||||
# Attach any processors from this request's backend
|
||||
$request->_backend->attach_processors($update);
|
||||
my $processor_results = $update->run_processors($options_to_pass);
|
||||
# Update our progress log
|
||||
$update_log->{processors_run} = $processor_results;
|
||||
}
|
||||
push @{$output}, $update_log;
|
||||
}
|
||||
|
||||
print_summary($output);
|
||||
|
||||
sub print_summary {
|
||||
my ( $log ) = @_;
|
||||
|
||||
my $timestamp = POSIX::strftime("%d/%m/%Y %H:%M:%S\n", localtime);
|
||||
print "Run details:\n";
|
||||
foreach my $entry(@{$log}) {
|
||||
my @processors_run = @{$entry->{processors_run}};
|
||||
print "Request ID: " . $entry->{request_id} . "\n";
|
||||
print " Processing by: " . $entry->{processed_by} . "\n";
|
||||
print " Number of processors run: " . scalar @processors_run . "\n";
|
||||
if (scalar @processors_run > 0) {
|
||||
print " Processor details:\n";
|
||||
foreach my $processor(@processors_run) {
|
||||
print " Processor name: " . $processor->{name} . "\n";
|
||||
print " Success messages: " . join(", ", @{$processor->{result}->{success}}) . "\n";
|
||||
print " Error messages: " . join(", ", @{$processor->{result}->{error}}) . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
print "Job completed at $timestamp\n====================================\n\n"
|
||||
}
|
||||
|
||||
sub debug_msg {
|
||||
my ( $msg ) = @_;
|
||||
|
||||
if (!$debug) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ref $msg eq 'HASH') {
|
||||
use Data::Dumper;
|
||||
$msg = Dumper $msg;
|
||||
}
|
||||
print STDERR "$msg\n";
|
||||
}
|
||||
|
||||
sub get_help {
|
||||
print <<"HELP";
|
||||
$0: Fetch and process outstanding ILL updates
|
||||
|
||||
This script will fetch all requests that have the specified
|
||||
statuses and run any applicable processor scripts on them.
|
||||
For example, the RapidILL backend provides a processor script
|
||||
that emails users when their requested electronic resource
|
||||
request has been fulfilled
|
||||
|
||||
Parameters:
|
||||
--statuses <statuses> specify the statuses a request must have in order to be processed,
|
||||
statuses should be separated by a : e.g. REQ:COMP:NEW. A null value
|
||||
can be specified by passing null, e.g. --statuses null
|
||||
|
||||
--status-aliases <status-aliases> specify the statuses aliases a request must have in order to be processed,
|
||||
statuses should be separated by a : e.g. STA:OLD:PRE. A null value
|
||||
can be specified by passing null, e.g. --status-aliases null
|
||||
--status-to <status-to> specify the status a successfully processed request must be set to
|
||||
after processing
|
||||
--status-alias-to <status-alias-to> specify the status alias a successfully processed request must be set to
|
||||
after processing
|
||||
--dry-run only produce a run report, without actually doing anything permanent
|
||||
--api-delay <seconds> if a processing script needs to make an API call, how long a pause
|
||||
should be inserted between each API call
|
||||
--debug print additional debugging info during run
|
||||
|
||||
--help or -h get help
|
||||
HELP
|
||||
}
|
Loading…
Reference in a new issue