Bug 37762: Circulation: Hook to holds
Signed-off-by: Jason Robb <jrobb@sekls.org> Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com> Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
parent
1d6fb7f57d
commit
950c9ccb96
|
|
@ -143,18 +143,20 @@ This modules provides some functions to deal with reservations.
|
|||
|
||||
AddReserve(
|
||||
{
|
||||
branchcode => $branchcode,
|
||||
borrowernumber => $borrowernumber,
|
||||
biblionumber => $biblionumber,
|
||||
priority => $priority,
|
||||
reservation_date => $reservation_date,
|
||||
expiration_date => $expiration_date,
|
||||
notes => $notes,
|
||||
title => $title,
|
||||
itemnumber => $itemnumber,
|
||||
found => $found,
|
||||
itemtype => $itemtype,
|
||||
item_group_id => $item_group_id
|
||||
branchcode => $branchcode,
|
||||
borrowernumber => $borrowernumber,
|
||||
biblionumber => $biblionumber,
|
||||
priority => $priority,
|
||||
reservation_date => $reservation_date,
|
||||
expiration_date => $expiration_date,
|
||||
notes => $notes,
|
||||
title => $title,
|
||||
itemnumber => $itemnumber,
|
||||
found => $found,
|
||||
itemtype => $itemtype,
|
||||
item_group_id => $item_group_id,
|
||||
supplyill => $iso18626_request_id;
|
||||
iso18626_payload => $payload_hash;
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -193,6 +195,8 @@ sub AddReserve {
|
|||
my $item_group_id = $params->{item_group_id};
|
||||
my $confirmations = $params->{confirmations};
|
||||
my $forced = $params->{forced};
|
||||
my $supplyill = $params->{supplyill};
|
||||
my $iso18626_payload = $params->{iso18626_payload};
|
||||
|
||||
$resdate ||= dt_from_string;
|
||||
|
||||
|
|
@ -257,6 +261,9 @@ sub AddReserve {
|
|||
non_priority => $non_priority ? 1 : 0,
|
||||
}
|
||||
)->store();
|
||||
|
||||
$hold->iso18626_attach_hold($supplyill);
|
||||
|
||||
$hold->set_waiting() if $found && $found eq 'W';
|
||||
|
||||
# record patron activity
|
||||
|
|
@ -362,6 +369,8 @@ sub AddReserve {
|
|||
}
|
||||
}
|
||||
|
||||
$hold->progress_iso18626_request( 'hold_created', $iso18626_payload );
|
||||
|
||||
Koha::Plugins->call( 'after_hold_create', $hold );
|
||||
Koha::Plugins->call(
|
||||
'after_hold_action',
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package Koha::Controller::Catalogue;
|
|||
use Modern::Perl;
|
||||
|
||||
use C4::Auth qw( get_template_and_user );
|
||||
use Koha::ILL::ISO18626::Requests;
|
||||
use Koha::Patrons;
|
||||
|
||||
=head1 NAME
|
||||
|
|
@ -76,6 +77,15 @@ sub _prep_searchto_template_params {
|
|||
);
|
||||
}
|
||||
|
||||
if ( $query->cookie("holdforsupplyill") ) {
|
||||
my $holdfor_supply_ill = Koha::ILL::ISO18626::Requests->find( $query->cookie("holdforsupplyill") );
|
||||
if ($holdfor_supply_ill) {
|
||||
$template->param(
|
||||
holdforsupplyill => $query->cookie("holdforsupplyill"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
96
Koha/Hold.pm
96
Koha/Hold.pm
|
|
@ -36,6 +36,7 @@ use Koha::Items;
|
|||
use Koha::Libraries;
|
||||
use Koha::Calendar;
|
||||
use Koha::Plugins;
|
||||
use Koha::ILL::ISO18626::Request;
|
||||
|
||||
use Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue;
|
||||
|
||||
|
|
@ -431,6 +432,8 @@ sub set_waiting {
|
|||
|
||||
$self->set($values)->store();
|
||||
|
||||
$self->progress_iso18626_request('hold_waiting');
|
||||
|
||||
Koha::Plugins->call(
|
||||
'after_hold_action',
|
||||
{
|
||||
|
|
@ -692,6 +695,34 @@ sub patron {
|
|||
return Koha::Patron->_new_from_dbic($rs);
|
||||
}
|
||||
|
||||
=head3 iso18626_request
|
||||
|
||||
Returns the related Koha::ILL::ISO18626::Request object for this hold
|
||||
|
||||
=cut
|
||||
|
||||
sub iso18626_request {
|
||||
my ($self) = @_;
|
||||
my $rs = $self->_result->iso18626_request;
|
||||
return unless $rs;
|
||||
return Koha::ILL::ISO18626::Request->_new_from_dbic($rs);
|
||||
}
|
||||
|
||||
=head3 iso18626_attach_hold
|
||||
|
||||
Adds relationship to related this hold
|
||||
|
||||
=cut
|
||||
|
||||
sub iso18626_attach_hold {
|
||||
my ( $self, $iso18626_request_id ) = @_;
|
||||
|
||||
my $iso18626_request = Koha::ILL::ISO18626::Requests->find($iso18626_request_id);
|
||||
return unless $iso18626_request;
|
||||
|
||||
$iso18626_request->hold_id( $self->id )->store;
|
||||
}
|
||||
|
||||
=head3 item
|
||||
|
||||
Returns the related Koha::Item object for this Hold
|
||||
|
|
@ -1001,6 +1032,8 @@ sub cancel {
|
|||
}
|
||||
);
|
||||
|
||||
$self->progress_iso18626_request( 'hold_cancelled', undef ); #TODO: Add reasonUnfilled here
|
||||
|
||||
$self->cleanup_hold_group() unless $params->{skip_hold_group_cleanup};
|
||||
|
||||
if ($autofill_next) {
|
||||
|
|
@ -1143,6 +1176,7 @@ sub revert_found {
|
|||
C4::Reserves::FixPriority( { biblionumber => $self->biblionumber } );
|
||||
|
||||
$self->remove_as_hold_group_target();
|
||||
$self->progress_iso18626_request('hold_waiting_reverted');
|
||||
|
||||
Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue->new->enqueue( { biblio_ids => [ $self->biblionumber ] } )
|
||||
if C4::Context->preference('RealTimeHoldsQueue');
|
||||
|
|
@ -1191,6 +1225,68 @@ sub change_type {
|
|||
return $self;
|
||||
}
|
||||
|
||||
=head3 progress_iso18626_request
|
||||
|
||||
$hold->progress_iso18626_request( $action, $iso18626_payload );
|
||||
|
||||
Process and update the associated ISO18626 request based on a specific hold action.
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<$action>
|
||||
|
||||
Required string. The hold-related event trigger (e.g., 'hold_created' or 'hold_cancelled').
|
||||
|
||||
=item C<$iso18626_payload>
|
||||
|
||||
Required hashref. Contains data for the ISO18626 message, such as C<expectedDeliveryDate>, C<messageInfoNote>, or C<reasonUnfilled>.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub progress_iso18626_request {
|
||||
my ( $self, $action, $iso18626_payload ) = @_;
|
||||
|
||||
my $iso18626_request = $self->iso18626_request;
|
||||
|
||||
return unless $iso18626_request;
|
||||
|
||||
if ( $action eq 'hold_created' && $iso18626_request->status eq 'RequestReceived' ) {
|
||||
$iso18626_request->progress_request(
|
||||
'supplyingAgency',
|
||||
{
|
||||
'expectedDeliveryDate' => $iso18626_payload->{iso18626_statusInfo_expectedDeliveryDate},
|
||||
'messageInfoNote' => $iso18626_payload->{iso18626_messageInfo_note},
|
||||
'status' => 'ExpectToSupply'
|
||||
}
|
||||
);
|
||||
}
|
||||
if ( $action eq 'hold_waiting' ) {
|
||||
$iso18626_request->progress_request(
|
||||
'supplyingAgency',
|
||||
{ 'status' => 'WillSupply' }
|
||||
|
||||
#TODO: Add messageInfoNote input on the checkin modal to pass a message here.
|
||||
);
|
||||
}
|
||||
if ( $action eq 'hold_waiting_reverted' && $iso18626_request->status eq 'WillSupply' ) {
|
||||
$iso18626_request->progress_request(
|
||||
'supplyingAgency',
|
||||
{ 'status' => 'ExpectToSupply' }
|
||||
);
|
||||
}
|
||||
if ( $action eq 'hold_cancelled' ) {
|
||||
$iso18626_request->progress_request(
|
||||
'supplyingAgency',
|
||||
{
|
||||
'reasonUnfilled' => 'NotHeld', #Grab this from $iso18626_payload
|
||||
'status' => 'Unfilled'
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
=head3 store
|
||||
|
||||
Override base store method to set default
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ Method that returns the related I<Koha::Hold>
|
|||
|
||||
sub hold {
|
||||
my ($self) = @_;
|
||||
my $hold_rs = $self->_result->reserve;
|
||||
my $hold_rs = $self->_result->hold;
|
||||
return unless $hold_rs;
|
||||
return Koha::Hold->_new_from_dbic($hold_rs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,6 +100,14 @@ ISO18626 service type
|
|||
|
||||
ISO18626 Requesting Agency action that requires a manual response (yes or no)
|
||||
|
||||
=head2 hold_id
|
||||
|
||||
data_type: 'integer'
|
||||
is_foreign_key: 1
|
||||
is_nullable: 1
|
||||
|
||||
ID of the hold related to this ISO18626 request
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->add_columns(
|
||||
|
|
@ -171,6 +179,8 @@ __PACKAGE__->add_columns(
|
|||
extra => { list => ["Cancel", "Renew"] },
|
||||
is_nullable => 1,
|
||||
},
|
||||
"hold_id",
|
||||
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
|
||||
);
|
||||
|
||||
=head1 PRIMARY KEY
|
||||
|
|
@ -185,8 +195,42 @@ __PACKAGE__->add_columns(
|
|||
|
||||
__PACKAGE__->set_primary_key("iso18626_request_id");
|
||||
|
||||
=head1 UNIQUE CONSTRAINTS
|
||||
|
||||
=head2 C<uniq_reserve_id>
|
||||
|
||||
=over 4
|
||||
|
||||
=item * L</hold_id>
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->add_unique_constraint("uniq_reserve_id", ["hold_id"]);
|
||||
|
||||
=head1 RELATIONS
|
||||
|
||||
=head2 hold
|
||||
|
||||
Type: belongs_to
|
||||
|
||||
Related object: L<Koha::Schema::Result::Reserve>
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->belongs_to(
|
||||
"hold",
|
||||
"Koha::Schema::Result::Reserve",
|
||||
{ reserve_id => "hold_id" },
|
||||
{
|
||||
is_deferrable => 1,
|
||||
join_type => "LEFT",
|
||||
on_delete => "SET NULL",
|
||||
on_update => "CASCADE",
|
||||
},
|
||||
);
|
||||
|
||||
=head2 iso18626_messages
|
||||
|
||||
Type: has_many
|
||||
|
|
@ -219,39 +263,9 @@ __PACKAGE__->belongs_to(
|
|||
{ is_deferrable => 1, on_delete => "RESTRICT", on_update => "CASCADE" },
|
||||
);
|
||||
|
||||
=head2 old_reserve
|
||||
|
||||
Type: might_have
|
||||
|
||||
Related object: L<Koha::Schema::Result::OldReserve>
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->might_have(
|
||||
"old_reserve",
|
||||
"Koha::Schema::Result::OldReserve",
|
||||
{ "foreign.iso18626_request_id" => "self.iso18626_request_id" },
|
||||
{ cascade_copy => 0, cascade_delete => 0 },
|
||||
);
|
||||
|
||||
=head2 reserve
|
||||
|
||||
Type: might_have
|
||||
|
||||
Related object: L<Koha::Schema::Result::Reserve>
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->might_have(
|
||||
"reserve",
|
||||
"Koha::Schema::Result::Reserve",
|
||||
{ "foreign.iso18626_request_id" => "self.iso18626_request_id" },
|
||||
{ cascade_copy => 0, cascade_delete => 0 },
|
||||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2026-03-04 14:57:44
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:T0PCb3b3SH9O7/f3TYDnTw
|
||||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2026-02-24 13:34:37
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:7KqpCOYXvp6skCK/lTer0g
|
||||
|
||||
=head2 koha_object_class
|
||||
|
||||
|
|
|
|||
|
|
@ -455,6 +455,21 @@ __PACKAGE__->might_have(
|
|||
{ cascade_copy => 0, cascade_delete => 0 },
|
||||
);
|
||||
|
||||
=head2 iso18626_request
|
||||
|
||||
Type: might_have
|
||||
|
||||
Related object: L<Koha::Schema::Result::Iso18626Request>
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->might_have(
|
||||
"iso18626_request",
|
||||
"Koha::Schema::Result::Iso18626Request",
|
||||
{ "foreign.hold_id" => "self.reserve_id" },
|
||||
{ cascade_copy => 0, cascade_delete => 0 },
|
||||
);
|
||||
|
||||
=head2 item_group
|
||||
|
||||
Type: belongs_to
|
||||
|
|
@ -516,8 +531,8 @@ __PACKAGE__->belongs_to(
|
|||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-11-03 19:54:07
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:B8/T/fmEf+RMPQsqOG+MiQ
|
||||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2026-02-23 17:05:32
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:WQrlG+Rl+BYHA7poiEiwmA
|
||||
|
||||
__PACKAGE__->belongs_to(
|
||||
"item",
|
||||
|
|
|
|||
|
|
@ -124,6 +124,11 @@ properties:
|
|||
- boolean
|
||||
- "null"
|
||||
description: Cancellation requests count for the hold (x-koha-embed)
|
||||
iso18626_request:
|
||||
type:
|
||||
- object
|
||||
- "null"
|
||||
description: (x-koha-embed)
|
||||
biblio:
|
||||
type:
|
||||
- object
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@ properties:
|
|||
- object
|
||||
- "null"
|
||||
description: Embeded object
|
||||
hold_id:
|
||||
type:
|
||||
- integer
|
||||
- "null"
|
||||
description: Associated hold (reserves) internal identifier
|
||||
hold:
|
||||
type:
|
||||
- object
|
||||
- "null"
|
||||
description: Embeded object
|
||||
messages:
|
||||
type:
|
||||
- array
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@
|
|||
- patron
|
||||
- item_group
|
||||
- item_level_holds_count
|
||||
- iso18626_request
|
||||
collectionFormat: csv
|
||||
produces:
|
||||
- application/json
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
enum:
|
||||
- messages
|
||||
- requesting_agency
|
||||
- hold
|
||||
collectionFormat: csv
|
||||
produces:
|
||||
- application/json
|
||||
|
|
@ -83,6 +84,7 @@
|
|||
enum:
|
||||
- messages
|
||||
- requesting_agency
|
||||
- hold
|
||||
collectionFormat: csv
|
||||
produces:
|
||||
- application/json
|
||||
|
|
|
|||
|
|
@ -217,6 +217,14 @@ if ( $cgi->cookie("holdforclub") ) {
|
|||
}
|
||||
}
|
||||
|
||||
if ( my $searchcontext = $cgi->param('context') ) {
|
||||
my ( $context, $data ) = split( /:/, $searchcontext, 2 );
|
||||
$template->param(
|
||||
context => $context,
|
||||
context_data => $data,
|
||||
);
|
||||
}
|
||||
|
||||
# get biblionumbers stored in the cart
|
||||
my @cart_list;
|
||||
|
||||
|
|
|
|||
|
|
@ -3820,8 +3820,11 @@ CREATE TABLE `iso18626_requests` (
|
|||
`status` enum('RequestReceived','ExpectToSupply','WillSupply','Loaned', 'Overdue', 'Recalled', 'RetryPossible', 'Unfilled', 'HoldReturn', 'ReleaseHoldReturn', 'CopyCompleted', 'LoanCompleted', 'CompletedWithoutReturn', 'Cancelled') DEFAULT 'RequestReceived' COMMENT 'Current ISO18626 status of request',
|
||||
`service_type` enum('Copy','Loan','CopyOrLoan') NOT NULL COMMENT 'ISO18626 service type',
|
||||
`pending_requesting_agency_action` enum('Cancel','Renew') DEFAULT NULL COMMENT 'ISO18626 Requesting Agency action that requires a manual response (yes or no)',
|
||||
PRIMARY KEY (`iso18626_request_id`),
|
||||
`hold_id` int(11) DEFAULT NULL COMMENT 'ID of the hold related to this ISO18626 request',
|
||||
>>>>>>> 16e751e7126 (Bug 37762: Circulation: Hook to holds)
|
||||
UNIQUE KEY `uniq_reserve_id` (`hold_id`),
|
||||
KEY `iso18626_rafk` (`iso18626_requesting_agency_id`),
|
||||
CONSTRAINT `uniq_reserve_id` FOREIGN KEY (`hold_id`) REFERENCES `reserves` (`reserve_id`) ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT `iso18626_rafk` FOREIGN KEY (`iso18626_requesting_agency_id`) REFERENCES `iso18626_requesting_agencies` (`iso18626_requesting_agency_id`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@
|
|||
|
||||
[% IF ( CAN_user_reserveforothers ) %]
|
||||
[% IF biblio.items.filter_by_for_hold.count %]
|
||||
[% IF ( holdfor ) %]
|
||||
[% IF ( holdfor || holdforsupplyill ) %]
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-default dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fa-solid fa-bookmark"></i>
|
||||
|
|
@ -267,11 +267,19 @@
|
|||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% biblionumber | uri %]">Place hold</a></li>
|
||||
<li
|
||||
><a class="dropdown-item" href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% biblionumber | uri %]&findborrower=[% holdfor_patron.cardnumber | uri %]"
|
||||
>Place hold for [% INCLUDE 'patron-title.inc' patron => holdfor_patron no_title => 1 no_html => 1 %]</a
|
||||
></li
|
||||
>
|
||||
[% IF holdforsupplyill %]
|
||||
<li
|
||||
><a class="dropdown-item" href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% biblionumber | uri %]&findborrower=[% holdfor_patron.cardnumber | uri %]&supplyill=[% holdforsupplyill | uri %]"
|
||||
>Place supply ILL ([% holdforsupplyill | html %]) hold for [% INCLUDE 'patron-title.inc' patron => holdfor_patron no_title => 1 no_cardnumber => 1 no_html => 1 %]</a
|
||||
></li
|
||||
>
|
||||
[% ELSIF holdfor %]
|
||||
<li
|
||||
><a class="dropdown-item" href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% biblionumber | uri %]&findborrower=[% holdfor_patron.cardnumber | uri %]"
|
||||
>Place hold for [% INCLUDE 'patron-title.inc' patron => holdfor_patron no_title => 1 no_html => 1 %]</a
|
||||
></li
|
||||
>
|
||||
[% END %]
|
||||
</ul>
|
||||
</div>
|
||||
[% ELSE %]
|
||||
|
|
|
|||
|
|
@ -728,3 +728,18 @@
|
|||
</div>
|
||||
</div>
|
||||
[% END %]
|
||||
|
||||
[%- BLOCK search_context_dialog -%]
|
||||
[% IF context == 'supplyill' %]
|
||||
<div class="alert alert-info">
|
||||
<h4>You are searching to place a hold for <a target="_blank" href="/cgi-bin/koha/ill/iso18626_requests/[% context_data | url %]">supply ILL [% context_data | html %]</a></h4>
|
||||
</div>
|
||||
[% END %]
|
||||
[%- END -%]
|
||||
|
||||
[%- BLOCK search_context_form_input -%]
|
||||
[% IF context %]
|
||||
[% SET search_context_string = context_data ? (context _ ":" _ context_data) : context %]
|
||||
<input type="hidden" name="context" value="[% search_context_string | url %]" />
|
||||
[% END %]
|
||||
[%- END -%]
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@
|
|||
[% WRAPPER 'main-container.inc' %]
|
||||
<form action="search.pl" method="get">
|
||||
<div id="advanced-search">
|
||||
[% PROCESS search_context_form_input %]
|
||||
[% PROCESS search_context_dialog %]
|
||||
[% IF edit_filter %]
|
||||
<div id="toolbar" class="btn-toolbar">
|
||||
<legend>Editing filter: [% edit_filter.name | html %]</legend>
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@
|
|||
[% END #/ WRAPPER sub-header.inc %]
|
||||
|
||||
[% WRAPPER 'main-container.inc' aside='facets' %]
|
||||
[% PROCESS search_context_dialog %]
|
||||
<h1>Search results</h1>
|
||||
|
||||
[% IF ( total ) %]
|
||||
|
|
@ -158,12 +159,19 @@
|
|||
[% END # /IF virtualshelves %]
|
||||
|
||||
[% IF ( CAN_user_reserveforothers_place_holds && DisplayMultiPlaceHold ) %]
|
||||
[% IF ( holdfor or holdforclub ) %]
|
||||
[% IF ( holdfor or holdforclub or holdforsupplyill ) %]
|
||||
<div id="placeholdc" class="btn-group">
|
||||
<button class="btn btn-default btn-xs placehold"><i class="fa-solid fa-bookmark"></i> Place hold</button>
|
||||
<button class="btn btn-default btn-xs dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false"> </button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" class="placehold dropdown-item">Place hold</a></li>
|
||||
[% IF holdforsupplyill %]
|
||||
<li
|
||||
><a href="#" class="placeholdforsupplyill dropdown-item"
|
||||
>Place supply ILL ([% holdforsupplyill | html %]) hold for [% INCLUDE 'patron-title.inc' patron => holdfor_patron no_title => 1 no_cardnumber => 1 no_html => 1 %]</a
|
||||
></li
|
||||
>
|
||||
[% END %]
|
||||
[% IF holdfor %]
|
||||
<li><a href="#" class="placeholdfor dropdown-item">Place hold for [% INCLUDE 'patron-title.inc' patron => holdfor_patron no_title => 1 no_cardnumber => 1 no_html => 1 %]</a></li>
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
|
|
@ -955,6 +963,7 @@
|
|||
<!-- Value will be set here by placeHold() -->
|
||||
<input type="hidden" name="findborrower" id="holdFor" value="" />
|
||||
<input type="hidden" name="club" id="holdForClub" value="" />
|
||||
<input type="hidden" name="supplyill" id="holdForSupplyILL" value="" />
|
||||
</form>
|
||||
|
||||
<form id="list_form" method="get" action="/cgi-bin/koha/reserve/request.pl">
|
||||
|
|
@ -984,6 +993,7 @@
|
|||
var biblionumber = "[% biblionumber | html %]";
|
||||
var holdfor_cardnumber = "[% holdfor_patron.cardnumber | html %]";
|
||||
var holdforclub = "[% holdforclub | html %]";
|
||||
var holdforsupplyill = "[% holdforsupplyill | html %]";
|
||||
var userbranch = "[% userbranch | html %]";
|
||||
[% IF Koha.Preference('FilterSearchResultsByLoggedInBranch') %]
|
||||
$(document).ready( function() {
|
||||
|
|
|
|||
|
|
@ -643,6 +643,9 @@
|
|||
[% FOREACH biblionumber IN biblionumbers %]
|
||||
<input type="hidden" name="biblionumber" value="[% biblionumber | html %]" />
|
||||
[% END %]
|
||||
[% IF supplyill %]
|
||||
<input type="hidden" name="supplyill" value="[% supplyill | html %]" />
|
||||
[% END %]
|
||||
<input type="hidden" name="holdable_bibs" id="holdable_bibs" value="[% biblio.biblionumber | html %]" />
|
||||
<input type="hidden" name="title" value="[% biblio.title | html %]" />
|
||||
<input type="hidden" name="rank-request" value="[% fixedRank | html %]" />
|
||||
|
|
@ -698,6 +701,21 @@
|
|||
</li>
|
||||
</ol>
|
||||
</fieldset>
|
||||
[% IF supplyill %]
|
||||
<fieldset class="rows">
|
||||
<legend>ISO18626 ILL request details</legend>
|
||||
<p>This hold will be linked to <a target="_blank" href="/cgi-bin/koha/ill/iso18626_requests/[% supplyill | url %]"> supply ILL [% supplyill | html %]</a>. </p
|
||||
><p>This will update the ILL's status to "ExpectToSupply" and send an ISO18626 message to the requesting agency including the details below.</p>
|
||||
<li>
|
||||
<label for="iso18626_messageInfo_note">Message info note:</label>
|
||||
<textarea id="iso18626_messageInfo_note" name="iso18626_messageInfo_note" cols="30" rows="1"></textarea>
|
||||
</li>
|
||||
<li>
|
||||
<label for="iso18626_statusInfo_expectedDeliveryDate">Status info expected delivery date:</label>
|
||||
<input id="iso18626_statusInfo_expectedDeliveryDate" name="iso18626_statusInfo_expectedDeliveryDate" size="10" type="text" class="flatpickr" data-flatpickr-enable-time="true" />
|
||||
</li>
|
||||
</fieldset>
|
||||
[% END %]
|
||||
<fieldset class="rows any_specific">
|
||||
<legend>
|
||||
[% IF force_hold_level == 'item' || force_hold_level == 'item_group' %]
|
||||
|
|
@ -1540,7 +1558,7 @@
|
|||
[% INCLUDE 'calendar.inc' %]
|
||||
[% INCLUDE 'select2.inc' %]
|
||||
|
||||
[% SET url_biblio_params = "biblionumber=" _ biblionumbers.join("&biblionumber=") %]
|
||||
[% SET url_biblio_params = (supplyill ? "supplyill=" _ supplyill _ "&" : "") _ "biblionumber=" _ biblionumbers.join("&biblionumber=") %]
|
||||
[% IF multi_hold %]
|
||||
[% SET url_biblio_params = url_biblio_params _ "&multi_hold=1" %]
|
||||
[% END %]
|
||||
|
|
@ -1726,6 +1744,7 @@
|
|||
return false;
|
||||
});
|
||||
|
||||
//Write handling of supply ILL params here ? before submit?
|
||||
if (!multi_hold) {
|
||||
$("#hold-request-form").on("submit", function (e) {
|
||||
return check(e, $(this));
|
||||
|
|
@ -1841,6 +1860,22 @@
|
|||
msg = _("- Please select a pickup location for this hold") + "\n";
|
||||
}
|
||||
}
|
||||
// var supplyillID = Cookies.get("holdforsupplyill") || null;
|
||||
// if (supplyillID) {
|
||||
// const client = APIClient.ill;
|
||||
// client.supplying.patch({
|
||||
// expectedDeliveryDate: null,
|
||||
// messageInfoNote: "my message",
|
||||
// status : "ExpectToSupply"
|
||||
// }, supplyillID).then(
|
||||
// success => {
|
||||
// //alert(_("Successfully saved configuration"));
|
||||
// },
|
||||
// error => {
|
||||
// console.warn("Something wrong happened: %s".format(error));
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
|
||||
if (msg == "") {
|
||||
$("#hold-request-form").preventDoubleFormSubmit();
|
||||
|
|
|
|||
|
|
@ -191,6 +191,7 @@ export const APIClient = {
|
|||
circulation: createClientProxy(() => import("./circulation-api-client.js")),
|
||||
club: createClientProxy(() => import("./club-api-client.js")),
|
||||
cover_image: createClientProxy(() => import("./cover-image-api-client.js")),
|
||||
ill: createClientProxy(() => import("./ill-api-client.js")),
|
||||
localization: createClientProxy(
|
||||
() => import("./localization-api-client.js")
|
||||
),
|
||||
|
|
|
|||
|
|
@ -261,6 +261,13 @@ $(document).ready(function () {
|
|||
")</span>";
|
||||
}
|
||||
|
||||
if (oObj.iso18626_request) {
|
||||
title += create_iso18626_request_link(
|
||||
oObj.iso18626_request.id,
|
||||
oObj.iso18626_request.status
|
||||
);
|
||||
}
|
||||
|
||||
return title;
|
||||
},
|
||||
},
|
||||
|
|
@ -1314,7 +1321,13 @@ async function load_patron_holds_table(biblio_id, split_data) {
|
|||
ajax: {
|
||||
url: url,
|
||||
},
|
||||
embed: ["patron", "item", "item_group", "item_level_holds_count"],
|
||||
embed: [
|
||||
"patron",
|
||||
"item",
|
||||
"item_group",
|
||||
"item_level_holds_count",
|
||||
"iso18626_request",
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
targets: [2, 3],
|
||||
|
|
@ -1632,9 +1645,16 @@ async function load_patron_holds_table(biblio_id, split_data) {
|
|||
? `<div>(<a href="/cgi-bin/koha/reserve/hold-group.pl?hold_group_id=${row.hold_group_id}" class="hold-group">${__("Hold group")} ${row.hold_group_id}</a>)</div>`
|
||||
: "";
|
||||
|
||||
const iso_message = create_iso18626_request_link(
|
||||
row.iso18626_request.iso18626_request_id,
|
||||
row.iso18626_request.status
|
||||
);
|
||||
|
||||
const extras = group_hold_message + iso_message;
|
||||
|
||||
// Handle status cases
|
||||
if (row.status) {
|
||||
return `<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=${row.biblio_id}&itemnumber=${row.item_id}">${row.item.external_id}</a>${group_hold_message}`;
|
||||
return `<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=${row.biblio_id}&itemnumber=${row.item_id}">${row.item.external_id}</a>${extras}`;
|
||||
}
|
||||
|
||||
// Handle item level holds
|
||||
|
|
@ -1644,13 +1664,13 @@ async function load_patron_holds_table(biblio_id, split_data) {
|
|||
const itemLink = `<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=${row.biblio_id}&itemnumber=${row.item_id}">${barcode.escapeHtml ? barcode.escapeHtml() : barcode}</a>`;
|
||||
|
||||
if (row.item_level_holds_count >= 2) {
|
||||
return `${__("Only item")} ${itemLink}${group_hold_message}`;
|
||||
return `${__("Only item")} ${itemLink}${extras}`;
|
||||
}
|
||||
|
||||
return `<select id="change_hold_type" class="change_hold_type ${table_class}" data-id="${row.hold_id}">
|
||||
<option value="" selected>${__("Only item")} ${barcode}</option>
|
||||
<option value="">${__("Next available")}</option>
|
||||
</select>${group_hold_message}`;
|
||||
</select>${extras}`;
|
||||
}
|
||||
|
||||
// Handle item group
|
||||
|
|
@ -1658,8 +1678,7 @@ async function load_patron_holds_table(biblio_id, split_data) {
|
|||
return (
|
||||
__(
|
||||
"Next available item from group <strong>%s</strong>"
|
||||
).format(row.item_group.description) +
|
||||
group_hold_message
|
||||
).format(row.item_group.description) + extras
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1668,7 +1687,7 @@ async function load_patron_holds_table(biblio_id, split_data) {
|
|||
if (row.non_priority) {
|
||||
message += `<br/><i>${__("Non priority hold")}</i>`;
|
||||
}
|
||||
return message + group_hold_message;
|
||||
return message + extras;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* global KOHA biblionumber new_results_browser addMultiple vShelfAdd openWindow search_result SEARCH_RESULTS PREF_IntranetCoce PREF_CoceProviders CoceHost CoceProviders addRecord delSingleRecord PREF_BrowseResultSelection resetSearchContext addBibToContext delBibToContext getContextBiblioNumbers holdfor_cardnumber holdforclub strQuery PREF_StaffHighlightedWords PREF_NotHighlightedWords __ */
|
||||
/* global KOHA biblionumber new_results_browser addMultiple vShelfAdd openWindow search_result SEARCH_RESULTS PREF_IntranetCoce PREF_CoceProviders CoceHost CoceProviders addRecord delSingleRecord PREF_BrowseResultSelection resetSearchContext addBibToContext delBibToContext getContextBiblioNumbers holdfor_cardnumber holdforclub holdforsupplyill strQuery PREF_StaffHighlightedWords PREF_NotHighlightedWords __ */
|
||||
|
||||
function verify_cover_images() {
|
||||
/* Loop over each container in the template which contains covers */
|
||||
|
|
@ -203,6 +203,7 @@ $(document).ready(function () {
|
|||
e.preventDefault();
|
||||
$("#holdFor").val("");
|
||||
$("#holdForClub").val("");
|
||||
$("#holdForSupplyILL").val("");
|
||||
placeHold();
|
||||
});
|
||||
|
||||
|
|
@ -216,6 +217,11 @@ $(document).ready(function () {
|
|||
holdForClub();
|
||||
});
|
||||
|
||||
$(".placeholdforsupplyill").click(function (e) {
|
||||
e.preventDefault();
|
||||
holdForSupplyILL();
|
||||
});
|
||||
|
||||
$("#forgetholdfor, #forgetholdforclub").click(function (e) {
|
||||
e.preventDefault();
|
||||
forgetPatronAndClub();
|
||||
|
|
@ -416,6 +422,7 @@ function placeHold() {
|
|||
function forgetPatronAndClub() {
|
||||
Cookies.remove("holdfor", { path: "/", SameSite: "Lax" });
|
||||
Cookies.remove("holdforclub", { path: "/", SameSite: "Lax" });
|
||||
Cookies.remove("holdforsupplyill", { path: "/", SameSite: "Lax" }); //TODO: Make a its own button (?)
|
||||
$(".holdforlink").remove();
|
||||
$("#placeholdc").html(
|
||||
'<a class="btn btn-default btn-xs placehold" href="#"><i class="fa-solid fa-bookmark"></i> ' +
|
||||
|
|
@ -496,6 +503,12 @@ function holdForClub() {
|
|||
placeHold();
|
||||
}
|
||||
|
||||
function holdForSupplyILL() {
|
||||
$("#holdFor").val(holdfor_cardnumber);
|
||||
$("#holdForSupplyILL").val(holdforsupplyill);
|
||||
placeHold();
|
||||
}
|
||||
|
||||
function toggleBatchOp(b) {
|
||||
var results_batch_ops = $("#results_batch_ops");
|
||||
if (b) {
|
||||
|
|
|
|||
|
|
@ -1093,6 +1093,27 @@ function holds_table_patron_page() {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces ISO 18626 request link, given an object
|
||||
* @return {string} The HTML link
|
||||
*/
|
||||
function create_iso18626_request_link(id, status) {
|
||||
var iso18626_request_text = __("Supply ILL #%s: %s").format(id, status);
|
||||
|
||||
var iso18626_request_link =
|
||||
'<a href="/cgi-bin/koha/ill/iso18626_requests/' +
|
||||
encodeURIComponent(id) +
|
||||
'">' +
|
||||
iso18626_request_text +
|
||||
"</a>";
|
||||
|
||||
return (
|
||||
'<br><span class="fw-bold fst-italic">(' +
|
||||
iso18626_request_link +
|
||||
")</span>"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a roughly ideal position to scroll an element into view
|
||||
* @param {string} target - The HTML id of the element to scroll into view
|
||||
|
|
|
|||
|
|
@ -45,28 +45,29 @@ export default {
|
|||
},
|
||||
{
|
||||
id: "ExpectToSupply",
|
||||
confirm_message: $__(
|
||||
"Supplying library expects to fill the request, based on e.g. information in the local OPAC. The message may include the ExpectedDeliveryDate"
|
||||
),
|
||||
button_label: $__("Expect to supply"),
|
||||
icon: "fa-calendar-days",
|
||||
dont_show: iso18626_request => true, //This is handled by creating a new hold
|
||||
// confirm_message: $__(
|
||||
// "Supplying library expects to fill the request, based on e.g. information in the local OPAC. The message may include the ExpectedDeliveryDate"
|
||||
// ),
|
||||
// button_label: $__("Expect to supply"),
|
||||
// icon: "fa-calendar-days",
|
||||
next_actions: [
|
||||
"Loaned",
|
||||
"WillSupply",
|
||||
"RetryPossible",
|
||||
"Unfilled",
|
||||
],
|
||||
action_inputs: [
|
||||
{
|
||||
name: "expectedDeliveryDate",
|
||||
type: "date",
|
||||
label: $__("Expected delivery date"),
|
||||
toolTip: $__(
|
||||
"Date and time the supplying library expects to deliver the item."
|
||||
),
|
||||
},
|
||||
],
|
||||
index: 0,
|
||||
// action_inputs: [
|
||||
// {
|
||||
// name: "expectedDeliveryDate",
|
||||
// type: "date",
|
||||
// label: $__("Expected delivery date"),
|
||||
// toolTip: $__(
|
||||
// "Date and time the supplying library expects to deliver the item."
|
||||
// ),
|
||||
// },
|
||||
// ],
|
||||
// index: 0,
|
||||
},
|
||||
{
|
||||
id: "WillSupply",
|
||||
|
|
@ -638,6 +639,40 @@ export default {
|
|||
});
|
||||
}
|
||||
|
||||
if (resource.status == "RequestReceived") {
|
||||
show_buttons.push({
|
||||
cssClass: "btn btn-primary",
|
||||
title: "Search to hold",
|
||||
icon: "fa-calendar-days",
|
||||
onClick: () => {
|
||||
// !Copy pasted from member-menu.js
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + 10 * 60 * 1000);
|
||||
Cookies.set(
|
||||
"holdfor",
|
||||
resource.requesting_agency.patron_id,
|
||||
{
|
||||
path: "/",
|
||||
expires: date,
|
||||
sameSite: "Lax",
|
||||
}
|
||||
);
|
||||
Cookies.set(
|
||||
"holdforsupplyill",
|
||||
resource.iso18626_request_id,
|
||||
{
|
||||
path: "/",
|
||||
expires: date,
|
||||
sameSite: "Lax",
|
||||
}
|
||||
);
|
||||
location.href =
|
||||
"/cgi-bin/koha/catalogue/search.pl?context=supplyill:" +
|
||||
resource.iso18626_request_id;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: show_buttons,
|
||||
};
|
||||
|
|
@ -742,6 +777,13 @@ export default {
|
|||
hideIn: ["List", "Form"],
|
||||
group: $__("Request details"),
|
||||
},
|
||||
{
|
||||
name: "hold_id",
|
||||
label: $__("Hold on biblio"),
|
||||
type: "boolean",
|
||||
hideIn: ["List", "Form"],
|
||||
group: $__("Request details"),
|
||||
},
|
||||
{
|
||||
group: $__("ISO18626 Messages"),
|
||||
name: "messages",
|
||||
|
|
|
|||
|
|
@ -49,12 +49,23 @@ my $item_group_id = $input->param('item_group_id');
|
|||
my $expirationdate = $input->param('expiration_date');
|
||||
my $itemtype = $input->param('itemtype') || undef;
|
||||
my $non_priority = $input->param('non_priority');
|
||||
my $supplyill = $input->param('supplyill');
|
||||
my $op = $input->param('op') || q{};
|
||||
my $multi_holds = $input->param('multi_holds');
|
||||
my $hold_group_param = $input->param('hold_group') || undef;
|
||||
|
||||
my $patron = Koha::Patrons->find($borrowernumber);
|
||||
|
||||
my @allowed_iso18626_fields = qw(
|
||||
iso18626_statusInfo_expectedDeliveryDate
|
||||
iso18626_messageInfo_note
|
||||
);
|
||||
|
||||
my %iso18626_payload = map {
|
||||
my $val = $input->param($_);
|
||||
defined $val ? ( $_ => $val ) : ()
|
||||
} @allowed_iso18626_fields;
|
||||
|
||||
my $holds_to_place_count = $input->param('holds_to_place_count') || 1;
|
||||
|
||||
my %bibinfos = ();
|
||||
|
|
@ -106,6 +117,8 @@ if ( $op eq 'cud-placerequest' && $patron ) {
|
|||
found => undef,
|
||||
itemtype => $itemtype,
|
||||
non_priority => $non_priority,
|
||||
supplyill => $supplyill,
|
||||
iso18626_payload => \%iso18626_payload,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -135,6 +148,9 @@ if ( $op eq 'cud-placerequest' && $patron ) {
|
|||
found => undef,
|
||||
itemtype => $itemtype,
|
||||
non_priority => $non_priority,
|
||||
|
||||
# supplyill => $supplyill, FIXME: How does supplyill work with multi-hold?
|
||||
# iso18626_payload => \%iso18626_payload,
|
||||
}
|
||||
);
|
||||
push @successful_hold_ids, $reserve_id;
|
||||
|
|
@ -159,6 +175,8 @@ if ( $op eq 'cud-placerequest' && $patron ) {
|
|||
itemtype => $itemtype,
|
||||
non_priority => $non_priority,
|
||||
item_group_id => $item_group_id,
|
||||
supplyill => $supplyill,
|
||||
iso18626_payload => \%iso18626_payload,
|
||||
}
|
||||
);
|
||||
push @successful_hold_ids, $reserve_id;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ my $findclub = $input->param('findclub');
|
|||
$findclub = '' unless defined $findclub && !$findborrower;
|
||||
my $borrowernumber_hold = $input->param('borrowernumber') || '';
|
||||
my $club_hold = $input->param('club') || '';
|
||||
my $supplyill = $input->param('supplyill') || '';
|
||||
my $messageborrower;
|
||||
my $messageclub;
|
||||
my $warnings;
|
||||
|
|
@ -234,6 +235,10 @@ $template->param(
|
|||
multi_hold => $multi_hold,
|
||||
);
|
||||
|
||||
if ($supplyill) {
|
||||
$template->param( supplyill => $supplyill );
|
||||
}
|
||||
|
||||
# If we have the borrowernumber because we've performed an action, then we
|
||||
# don't want to try to place another reserve.
|
||||
if ( $borrowernumber_hold && !$op ) {
|
||||
|
|
|
|||
57
svc/holds
57
svc/holds
|
|
@ -90,31 +90,38 @@ while ( my $h = $holds_rs->next() ) {
|
|||
my $biblio = $h->biblio();
|
||||
my @subtitles = split( / \| /, $biblio->subtitle() // '' );
|
||||
my $hold = {
|
||||
DT_RowId => $h->reserve_id(),
|
||||
biblionumber => $biblionumber,
|
||||
title => $biblio->title(),
|
||||
subtitle => \@subtitles,
|
||||
medium => $biblio->medium() // '',
|
||||
part_number => $biblio->part_number() // '',
|
||||
part_name => $biblio->part_name() // '',
|
||||
author => $biblio->author(),
|
||||
reserve_id => $h->reserve_id(),
|
||||
branchcode => $h->branch()->branchname(),
|
||||
branches => $libraries,
|
||||
desk_name => $desk_name,
|
||||
reservedate => $h->reservedate(),
|
||||
expirationdate => $h->expirationdate(),
|
||||
suspend => $h->suspend(),
|
||||
suspend_until => $h->suspend_until(),
|
||||
found => $h->found(),
|
||||
waiting => $h->is_waiting(),
|
||||
waiting_at => $h->branch()->branchname(),
|
||||
waiting_here => $h->branch()->branchcode() eq $branch,
|
||||
priority => $h->priority(),
|
||||
reservenotes => $h->reservenotes(),
|
||||
itemtype_limit => $itemtype_limit,
|
||||
hold_group_id => $h->hold_group_id,
|
||||
is_hold_group_target => $h->is_hold_group_target,
|
||||
DT_RowId => $h->reserve_id(),
|
||||
biblionumber => $biblionumber,
|
||||
title => $biblio->title(),
|
||||
subtitle => \@subtitles,
|
||||
medium => $biblio->medium() // '',
|
||||
part_number => $biblio->part_number() // '',
|
||||
part_name => $biblio->part_name() // '',
|
||||
author => $biblio->author(),
|
||||
reserve_id => $h->reserve_id(),
|
||||
branchcode => $h->branch()->branchname(),
|
||||
branches => $libraries,
|
||||
desk_name => $desk_name,
|
||||
reservedate => $h->reservedate(),
|
||||
expirationdate => $h->expirationdate(),
|
||||
suspend => $h->suspend(),
|
||||
suspend_until => $h->suspend_until(),
|
||||
found => $h->found(),
|
||||
waiting => $h->is_waiting(),
|
||||
waiting_at => $h->branch()->branchname(),
|
||||
waiting_here => $h->branch()->branchcode() eq $branch,
|
||||
priority => $h->priority(),
|
||||
reservenotes => $h->reservenotes(),
|
||||
itemtype_limit => $itemtype_limit,
|
||||
hold_group_id => $h->hold_group_id,
|
||||
visual_hold_group_id => $h->hold_group ? $h->hold_group->visual_hold_group_id : q{},
|
||||
is_hold_group_target => $h->is_hold_group_target,
|
||||
iso18626_request => $h->iso18626_request
|
||||
? {
|
||||
id => $h->iso18626_request->iso18626_request_id,
|
||||
status => $h->iso18626_request->status,
|
||||
}
|
||||
: undef,
|
||||
reservedate_formatted => $h->reservedate()
|
||||
? output_pref( { dt => dt_from_string( $h->reservedate() ), dateonly => 1 } )
|
||||
: q{},
|
||||
|
|
|
|||
Loading…
Reference in New Issue