Bugzilla – Attachment 134627 Details for
Bug 30484
Interlibrary loans should have the ability to send notices based on request supplier updates
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 30484: Implement support for ILL request updates
Bug-30484-Implement-support-for-ILL-request-update.patch (text/plain), 17.81 KB, created by
Andrew Isherwood
on 2022-05-05 09:22:45 UTC
(
hide
)
Description:
Bug 30484: Implement support for ILL request updates
Filename:
MIME Type:
Creator:
Andrew Isherwood
Created:
2022-05-05 09:22:45 UTC
Size:
17.81 KB
patch
obsolete
>From fa7065302187d16a3d2b18fd452c9b587c2aecc6 Mon Sep 17 00:00:00 2001 >From: Andrew Isherwood <andrew.isherwood@ptfs-europe.com> >Date: Fri, 8 Apr 2022 16:09:30 +0100 >Subject: [PATCH] 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 >--- > Koha/Illrequest.pm | 101 +++++++++- > Koha/Illrequest/SupplierUpdate.pm | 111 +++++++++++ > Koha/Illrequest/SupplierUpdateProcessor.pm | 85 ++++++++ > misc/process_ill_updates.pl | 214 +++++++++++++++++++++ > 4 files changed, 505 insertions(+), 6 deletions(-) > create mode 100644 Koha/Illrequest/SupplierUpdate.pm > create mode 100644 Koha/Illrequest/SupplierUpdateProcessor.pm > create mode 100755 misc/process_ill_updates.pl > >diff --git a/Koha/Illrequest.pm b/Koha/Illrequest.pm >index 6d26418cd9..dd046873ab 100644 >--- a/Koha/Illrequest.pm >+++ b/Koha/Illrequest.pm >@@ -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 >@@ -879,6 +907,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); >@@ -1402,7 +1452,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) { >@@ -1413,8 +1463,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 >@@ -1436,8 +1487,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({ >@@ -1578,13 +1630,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; >diff --git a/Koha/Illrequest/SupplierUpdate.pm b/Koha/Illrequest/SupplierUpdate.pm >new file mode 100644 >index 0000000000..3cc54298fc >--- /dev/null >+++ b/Koha/Illrequest/SupplierUpdate.pm >@@ -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; >diff --git a/Koha/Illrequest/SupplierUpdateProcessor.pm b/Koha/Illrequest/SupplierUpdateProcessor.pm >new file mode 100644 >index 0000000000..3136127c83 >--- /dev/null >+++ b/Koha/Illrequest/SupplierUpdateProcessor.pm >@@ -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; >diff --git a/misc/process_ill_updates.pl b/misc/process_ill_updates.pl >new file mode 100755 >index 0000000000..a159d844e8 >--- /dev/null >+++ b/misc/process_ill_updates.pl >@@ -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 >+} >-- >2.20.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 30484
:
133394
|
133395
|
133396
|
133399
|
133400
|
133401
|
134486
|
134487
|
134488
|
134569
|
134570
|
134571
|
134572
|
134573
|
134574
|
134626
|
134627
|
134628
|
138859
|
138860
|
138861
|
138862