From 0708f987a32cecfea5034d2856a290c4013b0cc8 Mon Sep 17 00:00:00 2001 From: Pedro Amorim Date: Fri, 15 Dec 2023 12:51:43 +0000 Subject: [PATCH] Bug 35570: Put 'FreeForm' backend into core as 'Standard' FreeForm copied as is from HEAD 369dffb159f1e70162b685b473dcf26c76f7e7e7 At https://github.com/PTFS-Europe/koha-ill-freeform/commits/reorganize_ILL/ Only edits made were 'freeform' -> 'standard' in the markup of the .inc files and some occurrences of FreeForm in Standard.pm (previous Base.pm) file. Signed-off-by: David Nind Signed-off-by: Tomas Cohen Arazi Signed-off-by: Katrin Fischer --- Koha/ILL/Backend/Standard.pm | 1215 +++++++++++++++++ Koha/ILL/Backend/intra-includes/cancel.inc | 17 + Koha/ILL/Backend/intra-includes/confirm.inc | 19 + Koha/ILL/Backend/intra-includes/create.inc | 203 +++ Koha/ILL/Backend/intra-includes/edititem.inc | 88 ++ Koha/ILL/Backend/intra-includes/illview.inc | 0 Koha/ILL/Backend/intra-includes/migrate.inc | 119 ++ Koha/ILL/Backend/opac-includes/create.inc | 122 ++ .../Backend/shared-includes/custom_fields.inc | 22 + .../Backend/shared-includes/forms/article.inc | 50 + .../Backend/shared-includes/forms/book.inc | 45 + .../Backend/shared-includes/forms/chapter.inc | 62 + .../shared-includes/forms/conference.inc | 49 + .../Backend/shared-includes/forms/journal.inc | 29 + .../Backend/shared-includes/forms/other.inc | 0 .../shared-includes/forms/resource.inc | 53 + .../Backend/shared-includes/forms/thesis.inc | 25 + Koha/ILL/Backend/shared-includes/shared.js | 38 + 18 files changed, 2156 insertions(+) create mode 100644 Koha/ILL/Backend/Standard.pm create mode 100644 Koha/ILL/Backend/intra-includes/cancel.inc create mode 100644 Koha/ILL/Backend/intra-includes/confirm.inc create mode 100644 Koha/ILL/Backend/intra-includes/create.inc create mode 100644 Koha/ILL/Backend/intra-includes/edititem.inc create mode 100644 Koha/ILL/Backend/intra-includes/illview.inc create mode 100644 Koha/ILL/Backend/intra-includes/migrate.inc create mode 100644 Koha/ILL/Backend/opac-includes/create.inc create mode 100644 Koha/ILL/Backend/shared-includes/custom_fields.inc create mode 100644 Koha/ILL/Backend/shared-includes/forms/article.inc create mode 100644 Koha/ILL/Backend/shared-includes/forms/book.inc create mode 100644 Koha/ILL/Backend/shared-includes/forms/chapter.inc create mode 100644 Koha/ILL/Backend/shared-includes/forms/conference.inc create mode 100644 Koha/ILL/Backend/shared-includes/forms/journal.inc create mode 100644 Koha/ILL/Backend/shared-includes/forms/other.inc create mode 100644 Koha/ILL/Backend/shared-includes/forms/resource.inc create mode 100644 Koha/ILL/Backend/shared-includes/forms/thesis.inc create mode 100644 Koha/ILL/Backend/shared-includes/shared.js diff --git a/Koha/ILL/Backend/Standard.pm b/Koha/ILL/Backend/Standard.pm new file mode 100644 index 0000000000..748680ad1a --- /dev/null +++ b/Koha/ILL/Backend/Standard.pm @@ -0,0 +1,1215 @@ +package Koha::ILL::Backend::Standard; + +# Copyright PTFS Europe 2023 +# +# 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 DateTime; +use File::Basename qw( dirname ); +use C4::Installer; + +use Koha::ILL::Requests; +use Koha::ILL::Request::Attribute; +use C4::Biblio qw( AddBiblio ); +use C4::Charset qw( MarcToUTF8Record ); + +=head1 NAME + +Koha::ILL::Backend::Standard - Koha ILL Backend: Standard + +=head1 SYNOPSIS + +Koha ILL implementation for the "Standard" backend . + +=head1 DESCRIPTION + +=head2 Overview + +We will be providing the Abstract interface which requires we implement the +following methods: +- create -> initial placement of the request for an ILL order +- confirm -> confirm placement of the ILL order (No-op in Standard) +- cancel -> request an already 'confirm'ed ILL order be cancelled +- status_graph -> return a hashref of additional statuses +- name -> return the name of this backend +- metadata -> return mapping of fields from requestattributes + +=head2 On the Standard backend + +The Standard backend is a simple backend that is supposed to act as a +fallback. It provides the end user with some mandatory fields in a form as +well as the option to enter additional fields with arbitrary names & values. + +=head1 API + +=head2 Class Methods + +=cut + +=head3 new + +my $backend = Koha::ILL::Backend::Standard->new; + +=cut + +sub new { + + # -> instantiate the backend + my ( $class, $other ) = @_; + my $framework = + defined $other->{config}->{configuration}->{raw_config}->{framework} + ? $other->{config}->{configuration}->{raw_config}->{framework} + : 'FA'; + my $self = { framework => $framework }; + bless( $self, $class ); + return $self; +} + +=head3 name + +Return the name of this backend. + +=cut + +sub name { + return "Standard"; +} + +=head3 capabilities + + $capability = $backend->capabilities($name); + +Return the sub implementing a capability selected by NAME, or 0 if that +capability is not implemented. + +=cut + +sub capabilities { + my ( $self, $name ) = @_; + my ($query) = @_; + my $capabilities = { + + # Get the requested partner email address(es) + get_requested_partners => sub { _get_requested_partners(@_); }, + + # Set the requested partner email address(es) + set_requested_partners => sub { _set_requested_partners(@_); }, + + # Migrate + migrate => sub { $self->migrate(@_); }, + + # Return whether we can create the request + # i.e. the create form has been submitted + can_create_request => sub { _can_create_request(@_) }, + + # This is required for compatibility + # with Koha versions prior to bug 33716 + should_display_availability => sub { _can_create_request(@_) }, + + # View and manage a request + illview => sub { illview(@_); }, + + provides_batch_requests => sub { return 1; }, + + # We can create ILL requests with data passed from the API + create_api => sub { $self->create_api(@_) } + }; + return $capabilities->{$name}; +} + +=head3 metadata + +Return a hashref containing canonical values from the key/value +illrequestattributes store. We may want to ignore certain values +that we do not consider to be metadata + +=cut + +sub metadata { + my ( $self, $request ) = @_; + my $attrs = $request->illrequestattributes; + my $metadata = {}; + my @ignore = ( 'requested_partners', 'type', 'type_disclaimer_value', 'type_disclaimer_date' ); + my $core_fields = _get_core_fields(); + while ( my $attr = $attrs->next ) { + my $type = $attr->type; + if ( !grep { $_ eq $type } @ignore ) { + my $name; + $name = $core_fields->{$type} || ucfirst($type); + $metadata->{$name} = $attr->value; + } + } + return $metadata; +} + +=head3 status_graph + +This backend provides no additional actions on top of the core_status_graph. + +=cut + +sub status_graph { + return { + MIG => { + prev_actions => [ 'NEW', 'REQ', 'GENREQ', 'REQREV', 'QUEUED', 'CANCREQ', ], + id => 'MIG', + name => 'Switched provider', + ui_method_name => 'Switch provider', + method => 'migrate', + next_actions => [], + ui_method_icon => 'fa-search', + }, + EDITITEM => { + prev_actions => ['NEW'], + id => 'EDITITEM', + name => 'Edited item metadata', + ui_method_name => 'Edit item metadata', + method => 'edititem', + next_actions => [], + ui_method_icon => 'fa-edit', + }, + + }; +} + +=head3 create + + my $response = $backend->create({ params => $params }); + +We just want to generate a form that allows the end-user to associate key +value pairs in the database. + +=cut + +sub create { + my ( $self, $params ) = @_; + my $other = $params->{other}; + my $stage = $other->{stage}; + my $core_fields = _get_core_string(); + if ( !$stage || $stage eq 'init' ) { + + # First thing we want to do, is check if we're receiving + # an OpenURL and transform it into something we can + # understand + if ( $other->{openurl} ) { + + # We only want to transform once + delete $other->{openurl}; + $params = _openurl_to_ill($params); + } + + # We simply need our template .INC to produce a form. + return { + cwd => dirname(__FILE__), + error => 0, + status => '', + message => '', + method => 'create', + stage => 'form', + value => $params, + core => $core_fields + }; + } elsif ( $stage eq 'form' ) { + + # We may be recieving a submitted form due to an additional + # custom field being added or deleted, or the material type + # having been changed, so check for these things + if ( !_can_create_request($other) ) { + if ( defined $other->{'add_new_custom'} ) { + my ( $custom_keys, $custom_vals ) = + _get_custom( $other->{'custom_key'}, $other->{'custom_value'} ); + push @{$custom_keys}, '---'; + push @{$custom_vals}, '---'; + $other->{'custom_key'} = join "\0", @{$custom_keys}; + $other->{'custom_value'} = join "\0", @{$custom_vals}; + } elsif ( defined $other->{'custom_delete'} ) { + my $delete_idx = $other->{'custom_delete'}; + my ( $custom_keys, $custom_vals ) = + _get_custom( $other->{'custom_key'}, $other->{'custom_value'} ); + splice @{$custom_keys}, $delete_idx, 1; + splice @{$custom_vals}, $delete_idx, 1; + $other->{'custom_key'} = join "\0", @{$custom_keys}; + $other->{'custom_value'} = join "\0", @{$custom_vals}; + } elsif ( defined $other->{'change_type'} ) { + + # We may be receiving a submitted form due to the user having + # changed request material type, so we just need to go straight + # back to the form, the type has been changed in the params + delete $other->{'change_type'}; + } + return { + cwd => dirname(__FILE__), + status => "", + message => "", + error => 0, + value => $params, + method => "create", + stage => "form", + core => $core_fields + }; + } + + # Received completed details of form. Validate and create request. + ## Validate + my ( $brw_count, $brw ) = + _validate_borrower( $other->{'cardnumber'} ); + my $result = { + cwd => dirname(__FILE__), + status => "", + message => "", + error => 1, + value => {}, + method => "create", + stage => "form", + core => $core_fields + }; + my $failed = 0; + if ( !$other->{'type'} ) { + $result->{status} = "missing_type"; + $result->{value} = $params; + $failed = 1; + } elsif ( !$other->{'branchcode'} ) { + $result->{status} = "missing_branch"; + $result->{value} = $params; + $failed = 1; + } elsif ( !Koha::Libraries->find( $other->{'branchcode'} ) ) { + $result->{status} = "invalid_branch"; + $result->{value} = $params; + $failed = 1; + } elsif ( $brw_count == 0 ) { + $result->{status} = "invalid_borrower"; + $result->{value} = $params; + $failed = 1; + } elsif ( $brw_count > 1 ) { + + # We must select a specific borrower out of our options. + $params->{brw} = $brw; + $result->{value} = $params; + $result->{stage} = "borrowers"; + $result->{error} = 0; + $failed = 1; + } + return $result if $failed; + + $self->add_request( { request => $params->{request}, other => $other } ); + + my $request_details = _get_request_details( $params, $other ); + + ## -> create response. + return { + cwd => dirname(__FILE__), + error => 0, + status => '', + message => '', + method => 'create', + stage => 'commit', + next => 'illview', + value => $request_details, + core => $core_fields + }; + } else { + + # Invalid stage, return error. + return { + cwd => dirname(__FILE__), + error => 1, + status => 'unknown_stage', + message => '', + method => 'create', + stage => $params->{stage}, + value => {}, + }; + } +} + +=head3 edititem + +=cut + +sub edititem { + my ( $self, $params ) = @_; + + my $core = _get_core_fields(); + my $core_fields = _get_core_string(); + + # Don't allow editing of submitted requests + return { method => 'illlist' } if $params->{request}->status ne 'NEW'; + + my $other = $params->{other}; + my $stage = $other->{stage}; + if ( !$stage || $stage eq 'init' ) { + + my $attrs = $params->{request}->illrequestattributes->unblessed; + + # We need to identify which parameters are custom, and pass them + # to the template in a predefined form + my $custom_keys = []; + my $custom_vals = []; + foreach my $attr ( @{$attrs} ) { + if ( !$core->{ $attr->{type} } ) { + push @{$custom_keys}, $attr->{type}; + push @{$custom_vals}, $attr->{value}; + } else { + $other->{ $attr->{type} } = $attr->{value}; + } + } + $other->{'custom_key'} = join "\0", @{$custom_keys}; + $other->{'custom_value'} = join "\0", @{$custom_vals}; + + # Pass everything back to the template + return { + cwd => dirname(__FILE__), + error => 0, + status => '', + message => '', + method => 'edititem', + stage => 'form', + value => $params, + core => $core_fields + }; + } elsif ( $stage eq 'form' ) { + + # We may be recieving a submitted form due to an additional + # custom field being added or deleted, or the material type + # having been changed, so check for these things + if ( defined $other->{'add_new_custom'} + || defined $other->{'custom_delete'} + || defined $other->{'change_type'} ) + { + if ( defined $other->{'add_new_custom'} ) { + my ( $custom_keys, $custom_vals ) = + _get_custom( $other->{'custom_key'}, $other->{'custom_value'} ); + push @{$custom_keys}, '---'; + push @{$custom_vals}, '---'; + $other->{'custom_key'} = join "\0", @{$custom_keys}; + $other->{'custom_value'} = join "\0", @{$custom_vals}; + } elsif ( defined $other->{'custom_delete'} ) { + my $delete_idx = $other->{'custom_delete'}; + my ( $custom_keys, $custom_vals ) = + _get_custom( $other->{'custom_key'}, $other->{'custom_value'} ); + splice @{$custom_keys}, $delete_idx, 1; + splice @{$custom_vals}, $delete_idx, 1; + $other->{'custom_key'} = join "\0", @{$custom_keys}; + $other->{'custom_value'} = join "\0", @{$custom_vals}; + } elsif ( defined $other->{'change_type'} ) { + + # We may be receiving a submitted form due to the user having + # changed request material type, so we just need to go straight + # back to the form, the type has been changed in the params + delete $other->{'change_type'}; + } + return { + cwd => dirname(__FILE__), + status => "", + message => "", + error => 0, + value => $params, + method => "edititem", + stage => "form", + core => $core_fields + }; + } + + # We don't want the request ID param getting any further + delete $other->{illrequest_id}; + + my $result = { + cwd => dirname(__FILE__), + status => "", + message => "", + error => 1, + value => {}, + method => "edititem", + stage => "form", + core => $core_fields + }; + + # Received completed details of form. Validate and create request. + ## Validate + my $failed = 0; + if ( !$other->{'type'} ) { + $result->{status} = "missing_type"; + $result->{value} = $params; + $failed = 1; + } + return $result if $failed; + + ## Update request + + # ...Update Illrequest + my $request = $params->{request}; + $request->updated( DateTime->now ); + $request->store; + + # ...Populate Illrequestattributes + # generate $request_details + my $request_details = _get_request_details( $params, $other ); + + # We do this with a 'dump all and repopulate approach' inside + # a transaction, easier than catering for create, update & delete + my $dbh = C4::Context->dbh; + my $schema = Koha::Database->new->schema; + $schema->txn_do( + sub { + # Delete all existing attributes for this request + $dbh->do( + q| + DELETE FROM illrequestattributes WHERE illrequest_id=? + |, undef, $request->id + ); + + # Insert all current attributes for this request + foreach my $attr ( keys %{$request_details} ) { + my $value = $request_details->{$attr}; + if ( $value && length $value > 0 ) { + if ( column_exists( 'illrequestattributes', 'backend' ) ) { + my @bind = ( $request->id, 'Standard', $attr, $value, 0 ); + $dbh->do( + q| + INSERT INTO illrequestattributes + (illrequest_id, backend, type, value, readonly) VALUES + (?, ?, ?, ?, ?) + |, undef, @bind + ); + } else { + my @bind = ( $request->id, $attr, $value, 0 ); + $dbh->do( + q| + INSERT INTO illrequestattributes + (illrequest_id, type, value, readonly) VALUES + (?, ?, ?, ?) + |, undef, @bind + ); + } + } + } + } + ); + + ## -> create response. + return { + error => 0, + status => '', + message => '', + method => 'create', + stage => 'commit', + next => 'illview', + value => $request_details, + core => $core_fields + }; + } else { + + # Invalid stage, return error. + return { + error => 1, + status => 'unknown_stage', + message => '', + method => 'create', + stage => $params->{stage}, + value => {}, + }; + } +} + +=head3 confirm + + my $response = $backend->confirm({ params => $params }); + +Confirm the placement of the previously "selected" request (by using the +'create' method). + +In the Standard backend we only want to display a bit of text to let staff +confirm that they have taken the steps they need to take to "confirm" the +request. + +=cut + +sub confirm { + my ( $self, $params ) = @_; + my $stage = $params->{other}->{stage}; + if ( !$stage || $stage eq 'init' ) { + + # We simply need our template .INC to produce a text block. + return { + method => 'confirm', + stage => 'confirm', + value => $params, + }; + } elsif ( $stage eq 'confirm' ) { + my $request = $params->{request}; + $request->orderid( $request->illrequest_id ); + $request->status("REQ"); + $request->store; + + # ...then return our result: + return { + method => 'confirm', + stage => 'commit', + next => 'illview', + value => {}, + }; + } else { + + # Invalid stage, return error. + return { + error => 1, + status => 'unknown_stage', + message => '', + method => 'confirm', + stage => $params->{stage}, + value => {}, + }; + } +} + +=head3 cancel + + my $response = $backend->cancel({ params => $params }); + +We will attempt to cancel a request that was confirmed. + +In the Standard backend this simply means displaying text to the librarian +asking them to confirm they have taken all steps needed to cancel a confirmed +request. + +=cut + +sub cancel { + my ( $self, $params ) = @_; + my $stage = $params->{other}->{stage}; + if ( !$stage || $stage eq 'init' ) { + + # We simply need our template .INC to produce a text block. + return { + method => 'cancel', + stage => 'confirm', + value => $params, + }; + } elsif ( $stage eq 'confirm' ) { + $params->{request}->status("REQREV"); + $params->{request}->orderid(undef); + $params->{request}->store; + return { + method => 'cancel', + stage => 'commit', + next => 'illview', + value => $params, + }; + } else { + + # Invalid stage, return error. + return { + error => 1, + status => 'unknown_stage', + message => '', + method => 'cancel', + stage => $params->{stage}, + value => {}, + }; + } +} + +=head3 migrate + +Migrate a request into or out of this backend. + +=cut + +sub migrate { + my ( $self, $params ) = @_; + my $other = $params->{other}; + + my $stage = $other->{stage}; + my $step = $other->{step}; + + my $core_fields = _get_core_string(); + + # We may be recieving a submitted form due to an additional + # custom field being added or deleted, or the material type + # having been changed, so check for these things + if ( defined $other->{'add_new_custom'} + || defined $other->{'custom_delete'} + || defined $other->{'change_type'} ) + { + if ( defined $other->{'add_new_custom'} ) { + my ( $custom_keys, $custom_vals ) = + _get_custom( $other->{'custom_key'}, $other->{'custom_value'} ); + push @{$custom_keys}, '---'; + push @{$custom_vals}, '---'; + $other->{'custom_key'} = join "\0", @{$custom_keys}; + $other->{'custom_value'} = join "\0", @{$custom_vals}; + } elsif ( defined $other->{'custom_delete'} ) { + my $delete_idx = $other->{'custom_delete'}; + my ( $custom_keys, $custom_vals ) = + _get_custom( $other->{'custom_key'}, $other->{'custom_value'} ); + splice @{$custom_keys}, $delete_idx, 1; + splice @{$custom_vals}, $delete_idx, 1; + $other->{'custom_key'} = join "\0", @{$custom_keys}; + $other->{'custom_value'} = join "\0", @{$custom_vals}; + } elsif ( defined $other->{'change_type'} ) { + + # We may be receiving a submitted form due to the user having + # changed request material type, so we just need to go straight + # back to the form, the type has been changed in the params + delete $other->{'change_type'}; + } + return { + cwd => dirname(__FILE__), + status => "", + message => "", + error => 0, + value => $params, + method => "create", + stage => "form", + core => $core_fields + }; + } + + # Recieve a new request from another backend and suppliment it with + # anything we require specifically for this backend. + if ( !$stage || $stage eq 'immigrate' ) { + my $original_request = Koha::ILL::Requests->find( $other->{illrequest_id} ); + my $new_request = $params->{request}; + $new_request->borrowernumber( $original_request->borrowernumber ); + $new_request->branchcode( $original_request->branchcode ); + $new_request->status('NEW'); + $new_request->backend( $self->name ); + $new_request->placed( DateTime->now ); + $new_request->updated( DateTime->now ); + $new_request->store; + + my @default_attributes = (qw/title type author year volume isbn issn article_title article_author pages/); + my $original_attributes = + $original_request->illrequestattributes->search( { type => { '-in' => \@default_attributes } } ); + + my $request_details = + { map { $_->type => $_->value } ( $original_attributes->as_list ) }; + $request_details->{migrated_from} = $original_request->illrequest_id; + while ( my ( $type, $value ) = each %{$request_details} ) { + Koha::ILL::Request::Attribute->new( + { + illrequest_id => $new_request->illrequest_id, + column_exists( 'illrequestattributes', 'backend' ) ? ( backend => "Standard" ) : (), + type => $type, + value => $value, + } + )->store; + } + + return { + error => 0, + status => '', + message => '', + method => 'migrate', + stage => 'commit', + next => 'emigrate', + value => $params, + core => $core_fields + }; + } + + # Cleanup any outstanding work, close the request. + elsif ( $stage eq 'emigrate' ) { + my $new_request = $params->{request}; + my $from_id = $new_request->illrequestattributes->find( { type => 'migrated_from' } )->value; + my $request = Koha::ILL::Requests->find($from_id); + + # Just cancel the original request now it's been migrated away + $request->status("REQREV"); + $request->orderid(undef); + $request->store; + + return { + error => 0, + status => '', + message => '', + method => 'migrate', + stage => 'commit', + next => 'illview', + value => $params, + core => $core_fields + }; + } +} + +=head3 illview + + View and manage an ILL request + +=cut + +sub illview { + my ( $self, $params ) = @_; + + return { method => "illview" }; +} + +## Helpers + +=head3 _get_requested_partners + +=cut + +sub _get_requested_partners { + + # Take a request and retrieve an Illrequestattribute with + # the type 'requested_partners'. + my ($args) = @_; + my $where = { + illrequest_id => $args->{request}->id, + type => 'requested_partners' + }; + my $res = Koha::ILL::Request::Attributes->find($where); + return ($res) ? $res->value : undef; +} + +=head3 _set_requested_partners + +=cut + +sub _set_requested_partners { + + # Take a request and set an Illrequestattribute on it + # detailing the email address(es) of the requested + # partner(s). We replace any existing value since, by + # the time we get to this stage, any previous request + # from partners would have had to be cancelled + my ($args) = @_; + my $where = { + illrequest_id => $args->{request}->id, + type => 'requested_partners' + }; + Koha::ILL::Request::Attributes->search($where)->delete(); + Koha::ILL::Request::Attributes->new( + { + illrequest_id => $args->{request}->id, + column_exists( 'illrequestattributes', 'backend' ) ? ( backend => "Standard" ) : (), + type => 'requested_partners', + value => $args->{to} + } + )->store; +} + +=head3 _validate_borrower + +=cut + +sub _validate_borrower { + + # Perform cardnumber search. If no results, perform surname search. + # Return ( 0, undef ), ( 1, $brw ) or ( n, $brws ) + my ($input) = @_; + my $patrons = Koha::Patrons->new; + my ( $count, $brw ); + my $query = { cardnumber => $input }; + + my $brws = $patrons->search($query); + $count = $brws->count; + my @criteria = qw/ surname userid firstname end /; + while ( $count == 0 ) { + my $criterium = shift @criteria; + return ( 0, undef ) if ( "end" eq $criterium ); + $brws = $patrons->search( { $criterium => $input } ); + $count = $brws->count; + } + if ( $count == 1 ) { + $brw = $brws->next; + } else { + $brw = $brws; # found multiple results + } + return ( $count, $brw ); +} + +=head3 _get_custom + +=cut + +sub _get_custom { + + # Take an string of custom keys and an string + # of custom values, both delimited by \0 (by CGI) + # and return an arrayref of each + my ( $keys, $values ) = @_; + my @k = defined $keys ? split( "\0", $keys ) : (); + my @v = defined $values ? split( "\0", $values ) : (); + return ( \@k, \@v ); +} + +=head3 _prepare_custom + +=cut + +sub _prepare_custom { + + # Take an arrayref of custom keys and an arrayref + # of custom values, return a hashref of them + my ( $keys, $values ) = @_; + my %out = (); + if ($keys) { + my @k = split( "\0", $keys ); + my @v = split( "\0", $values ); + %out = map { $k[$_] => $v[$_] } 0 .. $#k; + } + return \%out; +} + +=head3 _get_request_details + + my $request_details = _get_request_details($params, $other); + +Return the illrequestattributes for a given request + +=cut + +sub _get_request_details { + my ( $params, $other ) = @_; + + # Get custom key / values we've been passed + # Prepare them for addition into the Illrequestattribute object + my $custom = + _prepare_custom( $other->{'custom_key'}, $other->{'custom_value'} ); + + my $return = {%$custom}; + my $core = _get_core_fields(); + foreach my $key ( keys %{$core} ) { + $return->{$key} = $params->{other}->{$key}; + } + + return $return; +} + +=head3 _get_core_string + +Return a comma delimited, quoted, string of core field keys + +=cut + +sub _get_core_string { + my $core = _get_core_fields(); + return join( ",", map { '"' . $_ . '"' } keys %{$core} ); +} + +=head3 _get_core_fields + +Return a hashref of core fields + +=cut + +sub _get_core_fields { + return { + article_author => 'Article author', + article_title => 'Article title', + associated_id => 'Associated ID', + author => 'Author', + chapter_author => 'Chapter author', + chapter => 'Chapter', + conference_date => 'Conference date', + doi => 'DOI', + editor => 'Editor', + institution => 'Institution', + isbn => 'ISBN', + issn => 'ISSN', + issue => 'Issue', + item_date => 'Date', + pages => 'Pages', + pagination => 'Pagination', + paper_author => 'Paper author', + paper_title => 'Paper title', + part_edition => 'Part / Edition', + publication => 'Publication', + published_date => 'Publication date', + published_place => 'Place of publication', + publisher => 'Publisher', + sponsor => 'Sponsor', + title => 'Title', + type => 'Type', + venue => 'Venue', + volume => 'Volume', + year => 'Year' + }; +} + +=head3 add_request + +Add an ILL request + +=cut + +sub add_request { + + my ( $self, $params ) = @_; + + # ...Populate Illrequestattributes + # generate $request_details + my $request_details = _get_request_details( $params, $params->{other} ); + + my ( $brw_count, $brw ) = + _validate_borrower( $params->{other}->{'cardnumber'} ); + + ## Create request + + # Create bib record + my $biblionumber = $self->_standard_request2biblio($request_details); + + # ...Populate Illrequest + my $request = $params->{request}; + $request->biblio_id($biblionumber) unless $biblionumber == 0; + $request->borrowernumber( $brw->borrowernumber ); + $request->branchcode( $params->{other}->{branchcode} ); + $request->status('NEW'); + $request->backend( $params->{other}->{backend} ); + $request->placed( DateTime->now ); + $request->updated( DateTime->now ); + $request->batch_id( + $params->{other}->{ill_batch_id} ? $params->{other}->{ill_batch_id} : $params->{other}->{batch_id} ) + if column_exists( 'illrequests', 'batch_id' ); + $request->store; + + while ( my ( $type, $value ) = each %{$request_details} ) { + if ( $value && length $value > 0 ) { + Koha::ILL::Request::Attribute->new( + { + illrequest_id => $request->illrequest_id, + column_exists( 'illrequestattributes', 'backend' ) ? ( backend => "Standard" ) : (), + type => $type, + value => $value, + readonly => 0 + } + )->store; + } + } + + return $request; +} + +=head3 _openurl_to_ill + +Take a hashref of OpenURL parameters and return +those same parameters but transformed to the ILL +schema + +=cut + +sub _openurl_to_ill { + my ($params) = @_; + + # Parameters to not place in our custom + # parameters arrays + my $ignore = { + openurl => 1, + backend => 1, + method => 1, + opac => 1, + cardnumber => 1, + branchcode => 1, + userid => 1, + password => 1, + koha_login_context => 1, + stage => 1 + }; + + my $transform_metadata = { + genre => 'type', + content => 'type', + format => 'type', + atitle => 'article_title', + aulast => 'author', + author => 'author', + date => 'year', + issue => 'issue', + volume => 'volume', + isbn => 'isbn', + issn => 'issn', + rft_id => 'doi', + year => 'year', + title => 'title', + author => 'author', + aulast => 'article_author', + pages => 'pages', + ctitle => 'chapter', + clast => 'chapter_author' + }; + + my $transform_value = { + type => { + fulltext => 'article', + selectedft => 'article', + print => 'book', + ebook => 'book', + journal => 'journal' + } + }; + + my $return = {}; + my $custom_key = []; + my $custom_value = []; + + # First make sure our keys are correct + foreach my $meta_key ( keys %{ $params->{other} } ) { + + # If we are transforming this property... + if ( exists $transform_metadata->{$meta_key} ) { + + # ...do it + $return->{ $transform_metadata->{$meta_key} } = $params->{other}->{$meta_key}; + } else { + + # Otherwise, pass it through untransformed and maybe move it + # to our custom parameters array + if ( !exists $ignore->{$meta_key} ) { + push @{$custom_key}, $meta_key; + push @{$custom_value}, $params->{other}->{$meta_key}; + } else { + $return->{$meta_key} = $params->{other}->{$meta_key}; + } + } + } + + # Now check our values are correct + foreach my $val_key ( keys %{$return} ) { + my $value = $return->{$val_key}; + if ( exists $transform_value->{$val_key} && exists $transform_value->{$val_key}->{$value} ) { + $return->{$val_key} = $transform_value->{$val_key}->{$value}; + } + } + if ( scalar @{$custom_key} > 0 ) { + $return->{custom_key} = join( "\0", @{$custom_key} ); + $return->{custom_value} = join( "\0", @{$custom_value} ); + } + $params->{other} = $return; + $params->{custom_keys} = $custom_key; + $params->{custom_values} = $custom_value; + return $params; + +} + +=head3 create_api + +Create a local submission from data supplied via an +API call + +=cut + +sub create_api { + my ( $self, $body, $request ) = @_; + + my $patron = Koha::Patrons->find( $body->{borrowernumber} ); + + $body->{cardnumber} = $patron->cardnumber; + + foreach my $attr ( @{ $body->{extended_attributes} } ) { + $body->{ $attr->{type} } = $attr->{value}; + } + + $body->{type} = $body->{'isbn'} ? 'book' : 'article'; + + my $submission = $self->add_request( { request => $request, other => $body } ); + + return $submission; +} + +=head3 _can_create_request + +Given the parameters we've been passed, should we create the request + +=cut + +sub _can_create_request { + my ($params) = @_; + return ( defined $params->{'stage'} + && $params->{'stage'} eq 'form' + && !defined $params->{'add_new_custom'} + && !defined $params->{'custom_delete'} + && !defined $params->{'change_type'} ) ? 1 : 0; +} + +=head3 _standard_request2biblio + +Given supplied metadata from a Standard request, create a basic biblio +record and return its ID + +=cut + +sub _standard_request2biblio { + my ( $self, $metadata ) = @_; + + # We only want to create biblios for books + return 0 unless $metadata->{type} eq 'book'; + + # We're going to try and populate author, title & ISBN + my $author = $metadata->{author} if $metadata->{author}; + my $title = $metadata->{title} if $metadata->{title}; + my $isbn = $metadata->{isbn} if $metadata->{isbn}; + + # Create the MARC::Record object and populate + my $record = MARC::Record->new(); + + # Fix character set where appropriate + my $marcflavour = C4::Context->preference('marcflavour') || 'MARC21'; + if ( $record->encoding() eq 'MARC-8' ) { + ($record) = MarcToUTF8Record( $record, $marcflavour ); + } + + if ($isbn) { + my $marc_isbn = MARC::Field->new( '020', '', '', a => $isbn ); + $record->append_fields($marc_isbn); + } + if ($author) { + my $marc_author = MARC::Field->new( '100', '1', '', a => $author ); + $record->append_fields($marc_author); + } + if ($title) { + my $marc_title = MARC::Field->new( '245', '0', '0', a => $title ); + $record->append_fields($marc_title); + } + + # Suppress the record + _set_suppression($record); + + # Create a biblio record + my ( $biblionumber, $biblioitemnumber ) = + AddBiblio( $record, $self->{framework} ); + + return $biblionumber; +} + +=head3 _set_suppression + + _set_suppression($record); + +Take a MARC::Record object and set it to be suppressed + +=cut + +sub _set_suppression { + my ($record) = @_; + + my $new942 = MARC::Field->new( '942', '', '', n => '1' ); + $record->append_fields($new942); + + return 1; +} + +=head1 AUTHORS + +Alex Sassmannshausen +Martin Renvoize +Andrew Isherwood + +=cut + +1; diff --git a/Koha/ILL/Backend/intra-includes/cancel.inc b/Koha/ILL/Backend/intra-includes/cancel.inc new file mode 100644 index 0000000000..6c107abb30 --- /dev/null +++ b/Koha/ILL/Backend/intra-includes/cancel.inc @@ -0,0 +1,17 @@ +[% IF whole.error %] +

Unhandled error

+[% END %] + +[% IF whole.stage == "confirm" %] +

Cancel manual request

+

Proceeding with this action will set this request to 'Cancelled'.

+

This means that actions have been taken to cancel this request at the source with whom the request was placed.

+

If you can confirm this has been done, please proceed.

+

+ [% base_url = "/cgi-bin/koha/ill/ill-requests.pl" %] + [% proceed_url = base_url _ "?method=cancel&stage=confirm" _ + "&illrequest_id=" _ request.illrequest_id %] + Revert request + Cancel +

+[% END %] diff --git a/Koha/ILL/Backend/intra-includes/confirm.inc b/Koha/ILL/Backend/intra-includes/confirm.inc new file mode 100644 index 0000000000..dcd003752e --- /dev/null +++ b/Koha/ILL/Backend/intra-includes/confirm.inc @@ -0,0 +1,19 @@ +[% IF whole.error %] +

Unhandled error

+[% END %] + +[% IF whole.stage == "confirm" %] +

Confirm manual request

+

Proceeding with this action will set this request to 'Requested'.

+

This means that actions have been taken to request this request from a source.

+

If you can confirm this has been done, please proceed.

+

+ [% base_url = "/cgi-bin/koha/ill/ill-requests.pl" %] + [% proceed_url = base_url _ "?method=confirm&stage=confirm" _ + "&illrequest_id=" _ request.illrequest_id %] + Confirm request + Cancel +

+[% ELSE %] +

Unknown stage. This should not have happened. +[% END %] diff --git a/Koha/ILL/Backend/intra-includes/create.inc b/Koha/ILL/Backend/intra-includes/create.inc new file mode 100644 index 0000000000..162d88749f --- /dev/null +++ b/Koha/ILL/Backend/intra-includes/create.inc @@ -0,0 +1,203 @@ +[% SET koha_version = Koha.Version %] +[% IF whole.error %] +[% IF whole.status == 'missing_identifier' %] +

Please Note: Mandatory field Identifier is missing.

+[% ELSIF whole.status == 'missing_branch' %] +

Please Note: Branch is a mandatory field.

+[% ELSIF whole.status == 'invalid_borrower' %] +

Please Note: The borrower details you entered are invalid.

+[% ELSIF whole.status == 'invalid_branch' %] +

Please Note: The branch you chose is invalid.

+[% ELSE %] +

Unhandled error

+[% END %] +[% END %] + +[% IF whole.stage == "form" %] +

Create a manual ILL request

+
+
+ General details +
    +
  1. + + +
  2. +
+
+ [% cwd = whole.cwd %] + [% type = whole.value.other.type %] + [% IF type %] + [% INCLUDE "${cwd}/shared-includes/forms/${type}.inc" %] + [% END %] + [% INCLUDE "${cwd}/shared-includes/custom_fields.inc" %] +
+ Patron options +
    +
  1. + + +
  2. +
  3. + + +
  4. +
+
+
+ + Cancel +
+ + + +
+[% BLOCK backend_jsinclude %] + +[% END %] + +[% ELSIF whole.stage == "borrowers" %] + +

Borrower selection

+
+ [% FOREACH prop IN whole.value.other.keys %] + [% IF prop != 'custom_key' && prop != 'custom_value' && prop != 'cardnumber' %] + + [% END %] + [% END %] + [% keys = whole.value.other.custom_key.split('\0') %] + [% values = whole.value.other.custom_value.split('\0') %] + [% i = 0 %] + [% FOREACH key IN keys %] + + + [% i = i + 1 %] + [% END %] +
+ Available borrowers for surname [% surname %] + [% FOREACH opt IN whole.value %] + [% IF opt.key == "brw" %] +
    +
  1. + + +
  2. +
+ [% END %] + [% END %] +
+
+ + Cancel +
+
+ +[% ELSE %] +

Unknown stage. This should not have happened. + +[% END %] diff --git a/Koha/ILL/Backend/intra-includes/edititem.inc b/Koha/ILL/Backend/intra-includes/edititem.inc new file mode 100644 index 0000000000..bb34ce293a --- /dev/null +++ b/Koha/ILL/Backend/intra-includes/edititem.inc @@ -0,0 +1,88 @@ +[% IF whole.error %] +[% IF whole.status == 'missing_type' %] +

Please Note: Mandatory field Type is missing.

+[% ELSE %] +

Unhandled error

+[% END %] +[% END %] + +

Edit a manual ILL request

+
+
+ General details +
    +
  1. + + +
  2. +
+
+ [% cwd = whole.cwd %] + [% type = whole.value.other.type %] + [% IF type %] + [% INCLUDE "${cwd}/shared-includes/forms/${type}.inc" %] + [% END %] + [% INCLUDE "${cwd}/shared-includes/custom_fields.inc" %] +
+ + Cancel +
+ + + + +
+[% BLOCK backend_jsinclude %] + +[% END %] diff --git a/Koha/ILL/Backend/intra-includes/illview.inc b/Koha/ILL/Backend/intra-includes/illview.inc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Koha/ILL/Backend/intra-includes/migrate.inc b/Koha/ILL/Backend/intra-includes/migrate.inc new file mode 100644 index 0000000000..dfef8bd390 --- /dev/null +++ b/Koha/ILL/Backend/intra-includes/migrate.inc @@ -0,0 +1,119 @@ +[% IF whole.error %] +[% IF whole.status == 'missing_identifier' %] +

Please Note: Mandatory field Identifier is missing.

+[% ELSIF whole.status == 'missing_branch' %] +

Please Note: Branch is a mandatory field.

+[% ELSIF whole.status == 'invalid_borrower' %] +

Please Note: The borrower details you entered are invalid.

+[% ELSIF whole.status == 'invalid_branch' %] +

Please Note: The branch you chose is invalid.

+[% ELSE %] +

Unhandled error

+[% END %] +[% END %] + +[% IF whole.stage == "form" %] +

Migrating an ILL request

+
+
+ General details +
    +
  1. + + +
  2. +
+
+ [% cwd = whole.cwd %] + [% type = whole.value.other.type %] + [% IF type %] + [% INCLUDE "${cwd}/shared-includes/forms/${type}.inc" %] + [% END %] + [% INCLUDE "${cwd}/shared-includes/custom_fields.inc" %] +
+ Patron options +
    +
  1. + + +
  2. +
  3. + + +
  4. +
+
+
+ + Cancel +
+
+[% BLOCK backend_jsinclude %] + +[% END %] + +[% ELSE %] +

Unknown stage. This should not have happened. + +[% END %] diff --git a/Koha/ILL/Backend/opac-includes/create.inc b/Koha/ILL/Backend/opac-includes/create.inc new file mode 100644 index 0000000000..9affaf3086 --- /dev/null +++ b/Koha/ILL/Backend/opac-includes/create.inc @@ -0,0 +1,122 @@ +[% IF whole.error %] +[% IF whole.status == 'missing_identifier' %] +

Please Note: Mandatory field Identifier is missing.

+[% ELSIF whole.status == 'missing_branch' %] +

Please Note: Branch is a mandatory field.

+[% ELSIF whole.status == 'invalid_borrower' %] +

Please Note: The borrower details you entered are invalid.

+[% ELSIF whole.status == 'invalid_branch' %] +

Please Note: The branch you chose is invalid.

+[% ELSE %] +

Unhandled error

+[% END %] +[% END %] + +[% IF whole.stage == "form" %] +

Create a manual ILL request

+
+
+ General details +
    +
  1. + + +
  2. +
+
+ [% cwd = whole.cwd %] + [% type = whole.value.other.type %] + [% IF type %] + [% INCLUDE "${cwd}/shared-includes/forms/${type}.inc" %] + [% END %] + [% INCLUDE "${cwd}/shared-includes/custom_fields.inc" %] +
+ Patron options +
    +
  1. + + +
  2. +
+
+ +
+ + Cancel +
+ + + +
+ +[% ELSE %] +

Unknown stage. This should not have happened. + +[% END %] +[% BLOCK backend_jsinclude %] + +[% END %] diff --git a/Koha/ILL/Backend/shared-includes/custom_fields.inc b/Koha/ILL/Backend/shared-includes/custom_fields.inc new file mode 100644 index 0000000000..e91b694a32 --- /dev/null +++ b/Koha/ILL/Backend/shared-includes/custom_fields.inc @@ -0,0 +1,22 @@ +

+ Custom fields +
    + [% keys = whole.value.other.custom_key.split('\0') %] + [% values = whole.value.other.custom_value.split('\0') %] + [% i = 0 %] + [% FOREACH key IN keys %] +
  1. + +
  2. + + [% i = i + 1 %] + [% END %] +
+ + +
diff --git a/Koha/ILL/Backend/shared-includes/forms/article.inc b/Koha/ILL/Backend/shared-includes/forms/article.inc new file mode 100644 index 0000000000..598b1191f5 --- /dev/null +++ b/Koha/ILL/Backend/shared-includes/forms/article.inc @@ -0,0 +1,50 @@ +
+ Journal details +
    +
  1. + + +
  2. +
  3. + + +
  4. +
  5. + + +
  6. +
  7. + + +
  8. +
  9. + + +
  10. +
+
+
+ Article details +
    +
  1. + + +
  2. +
  3. + + +
  4. +
  5. + + +
  6. +
  7. + + +
  8. +
  9. + + +
  10. +
+
diff --git a/Koha/ILL/Backend/shared-includes/forms/book.inc b/Koha/ILL/Backend/shared-includes/forms/book.inc new file mode 100644 index 0000000000..3ce9613ae2 --- /dev/null +++ b/Koha/ILL/Backend/shared-includes/forms/book.inc @@ -0,0 +1,45 @@ +
+ Book details +
    +
  1. + + +
  2. +
  3. + + +
  4. +
  5. + + +
  6. +
  7. + + +
  8. +
  9. + + +
  10. +
  11. + + +
  12. +
  13. + + +
  14. +
  15. + + +
  16. +
  17. + + +
  18. +
  19. + + +
  20. +
+
diff --git a/Koha/ILL/Backend/shared-includes/forms/chapter.inc b/Koha/ILL/Backend/shared-includes/forms/chapter.inc new file mode 100644 index 0000000000..8bf9ce003b --- /dev/null +++ b/Koha/ILL/Backend/shared-includes/forms/chapter.inc @@ -0,0 +1,62 @@ +
+ Book details +
    +
  1. + + +
  2. +
  3. + + +
  4. +
  5. + + +
  6. +
  7. + + +
  8. +
  9. + + +
  10. +
  11. + + +
  12. +
  13. + + +
  14. +
  15. + + +
  16. +
  17. + + +
  18. +
  19. + + +
  20. +
+
+
+ Chapter details +
    +
  1. + + +
  2. +
  3. + + +
  4. +
  5. + + +
  6. +
+
diff --git a/Koha/ILL/Backend/shared-includes/forms/conference.inc b/Koha/ILL/Backend/shared-includes/forms/conference.inc new file mode 100644 index 0000000000..facda38ee4 --- /dev/null +++ b/Koha/ILL/Backend/shared-includes/forms/conference.inc @@ -0,0 +1,49 @@ +
+ Conference details +
    +
  1. + + +
  2. +
  3. + + +
  4. +
  5. + + +
  6. +
  7. + + +
  8. +
  9. + + +
  10. +
  11. + + +
  12. +
  13. + + +
  14. +
  15. + + +
  16. +
  17. + + +
  18. +
  19. + + +
  20. +
  21. + + +
  22. +
+
diff --git a/Koha/ILL/Backend/shared-includes/forms/journal.inc b/Koha/ILL/Backend/shared-includes/forms/journal.inc new file mode 100644 index 0000000000..3f92e91382 --- /dev/null +++ b/Koha/ILL/Backend/shared-includes/forms/journal.inc @@ -0,0 +1,29 @@ +
+ Journal details +
    +
  1. + + +
  2. +
  3. + + +
  4. +
  5. + + +
  6. +
  7. + + +
  8. +
  9. + + +
  10. +
  11. + + +
  12. +
+
diff --git a/Koha/ILL/Backend/shared-includes/forms/other.inc b/Koha/ILL/Backend/shared-includes/forms/other.inc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Koha/ILL/Backend/shared-includes/forms/resource.inc b/Koha/ILL/Backend/shared-includes/forms/resource.inc new file mode 100644 index 0000000000..a8f9b8419f --- /dev/null +++ b/Koha/ILL/Backend/shared-includes/forms/resource.inc @@ -0,0 +1,53 @@ +
+ Generic resource details +
    +
  1. + + +
  2. +
  3. + + +
  4. +
  5. + + +
  6. +
  7. + + +
  8. +
  9. + + +
  10. +
  11. + + +
  12. +
  13. + + +
  14. +
  15. + + +
  16. +
  17. + + +
  18. +
  19. + + +
  20. +
  21. + + +
  22. +
  23. + + +
  24. +
+
diff --git a/Koha/ILL/Backend/shared-includes/forms/thesis.inc b/Koha/ILL/Backend/shared-includes/forms/thesis.inc new file mode 100644 index 0000000000..142cdcdc1e --- /dev/null +++ b/Koha/ILL/Backend/shared-includes/forms/thesis.inc @@ -0,0 +1,25 @@ +
+ Thesis details +
    +
  1. + + +
  2. +
  3. + + +
  4. +
  5. + + +
  6. +
  7. + + +
  8. +
  9. + + +
  10. +
+
diff --git a/Koha/ILL/Backend/shared-includes/shared.js b/Koha/ILL/Backend/shared-includes/shared.js new file mode 100644 index 0000000000..ab6e885b2c --- /dev/null +++ b/Koha/ILL/Backend/shared-includes/shared.js @@ -0,0 +1,38 @@ +var core = [ [% whole.core %] ]; +document.addEventListener('DOMContentLoaded', function() { + $('#add-new-fields').click(function(e) { + e.preventDefault(); + var row = '
  • ' + + '' + + ' '+ + '
  • '; + $('#standard-fields').append(row); + }); + $('#standard-fields').on('click', '.delete-new-field', + function(event) { + event.preventDefault(); + $(event.target).parent().remove(); + } + ); + $('#type').change(function() { + $('#create_form').prepend( + '' + ); + $('#create_form').submit(); + }); + $('#standard-fields').on('keyup', '.custom-name', function() { + var val = $(this).val(); + if (core.indexOf(val.toLowerCase()) > -1) { + $('#custom-warning').text(_('The name "' + val + '" is not permitted')).show(); + $('#ill-submit').attr('disabled', true); + $('#add-new-fields').attr('disabled', true); + } else { + $('#custom-warning').hide(); + $('#ill-submit').attr('disabled', false); + $('#add-new-fields').attr('disabled', false); + } + }); +}); -- 2.39.5