Bug 32121: Show an alert when adding a checked out item to an item bundle
When trying to add a checked out item to an item bundle, an alert message will show up, giving the user a chance to return the item immediately before adding it to the bundle Test plan: 1. Create an item bundle (see bug 28854 comment 458) 2. Create a biblio with one item and check out this item. 3. Try to add the checked out item to the bundle You should see a message saying that the item is checked out. Next to this message should be a button "Check in and add to bundle". 4. Click on the button. There should be a message saying that the item was added to the bundle. 5. Close the modal window and verify that the item was correctly returned and added to the bundle Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com> Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com> Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
parent
f781fdb4a2
commit
de36244266
|
|
@ -0,0 +1,32 @@
|
|||
package Koha::Exceptions::Checkin;
|
||||
|
||||
# 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;
|
||||
|
||||
use Koha::Exception;
|
||||
|
||||
use Exception::Class (
|
||||
'Koha::Exceptions::Checkin' => {
|
||||
isa => 'Koha::Exception',
|
||||
},
|
||||
'Koha::Exceptions::Checkin::FailedCheckin' => {
|
||||
isa => 'Koha::Exceptions::Checkin',
|
||||
description => "Checkin failed"
|
||||
},
|
||||
);
|
||||
|
||||
1;
|
||||
|
|
@ -20,14 +20,17 @@ use Modern::Perl;
|
|||
use Koha::Exception;
|
||||
|
||||
use Exception::Class (
|
||||
|
||||
'Koha::Exceptions::Item::Bundle' => {
|
||||
isa => 'Koha::Exception',
|
||||
},
|
||||
'Koha::Exceptions::Item::Bundle::IsBundle' => {
|
||||
isa => 'Koha::Exceptions::Item::Bundle',
|
||||
description => "A bundle cannot be added to a bundle",
|
||||
}
|
||||
},
|
||||
'Koha::Exceptions::Item::Bundle::ItemIsCheckedOut' => {
|
||||
isa => 'Koha::Exceptions::Item::Bundle',
|
||||
description => 'Someone tried to add a checked out item to a bundle',
|
||||
},
|
||||
);
|
||||
|
||||
=head1 NAME
|
||||
|
|
@ -44,6 +47,10 @@ Generic Item::Bundle exception
|
|||
|
||||
Exception to be used when attempting to add one bundle into another.
|
||||
|
||||
=head2 Koha::Exceptions::Item::Bundle::ItemIsCheckedOut
|
||||
|
||||
Exception to be used when attempting to add a checked out item to a bundle.
|
||||
|
||||
=cut
|
||||
|
||||
1;
|
||||
|
|
|
|||
21
Koha/Item.pm
21
Koha/Item.pm
|
|
@ -36,6 +36,8 @@ use Koha::Biblio::ItemGroups;
|
|||
use Koha::Checkouts;
|
||||
use Koha::CirculationRules;
|
||||
use Koha::CoverImages;
|
||||
use Koha::Exceptions::Checkin;
|
||||
use Koha::Exceptions::Item::Bundle;
|
||||
use Koha::Exceptions::Item::Transfer;
|
||||
use Koha::Item::Attributes;
|
||||
use Koha::Exceptions::Item::Bundle;
|
||||
|
|
@ -1699,7 +1701,9 @@ Adds the bundle_item passed to this item
|
|||
=cut
|
||||
|
||||
sub add_to_bundle {
|
||||
my ( $self, $bundle_item ) = @_;
|
||||
my ( $self, $bundle_item, $options ) = @_;
|
||||
|
||||
$options //= {};
|
||||
|
||||
Koha::Exceptions::Item::Bundle::IsBundle->throw()
|
||||
if ( $self->itemnumber eq $bundle_item->itemnumber
|
||||
|
|
@ -1713,6 +1717,19 @@ sub add_to_bundle {
|
|||
try {
|
||||
$schema->txn_do(
|
||||
sub {
|
||||
my $checkout = $bundle_item->checkout;
|
||||
if ($checkout) {
|
||||
unless ($options->{force_checkin}) {
|
||||
Koha::Exceptions::Item::Bundle::ItemIsCheckedOut->throw();
|
||||
}
|
||||
|
||||
my $branchcode = C4::Context->userenv->{'branch'};
|
||||
my ($success) = C4::Circulation::AddReturn($bundle_item->barcode, $branchcode);
|
||||
unless ($success) {
|
||||
Koha::Exceptions::Checkin::FailedCheckin->throw();
|
||||
}
|
||||
}
|
||||
|
||||
$self->_result->add_to_item_bundles_hosts(
|
||||
{ item => $bundle_item->itemnumber } );
|
||||
|
||||
|
|
@ -1764,7 +1781,7 @@ sub add_to_bundle {
|
|||
$_->rethrow();
|
||||
}
|
||||
else {
|
||||
$_;
|
||||
$_->rethrow();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -278,7 +278,8 @@ sub add_to_bundle {
|
|||
}
|
||||
|
||||
return try {
|
||||
my $link = $item->add_to_bundle($bundle_item);
|
||||
my $force_checkin = $c->validation->param('body')->{'force_checkin'};
|
||||
my $link = $item->add_to_bundle($bundle_item, { force_checkin => $force_checkin });
|
||||
return $c->render(
|
||||
status => 201,
|
||||
openapi => $bundle_item
|
||||
|
|
@ -301,8 +302,23 @@ sub add_to_bundle {
|
|||
error => 'Bundles cannot be nested'
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
} elsif (ref($_) eq 'Koha::Exceptions::Item::Bundle::ItemIsCheckedOut') {
|
||||
return $c->render(
|
||||
status => 409,
|
||||
openapi => {
|
||||
error => 'Item is checked out',
|
||||
key => 'checked_out'
|
||||
}
|
||||
);
|
||||
} elsif (ref($_) eq 'Koha::Exceptions::Checkin::FailedCheckin') {
|
||||
return $c->render(
|
||||
status => 409,
|
||||
openapi => {
|
||||
error => 'Item cannot be checked in',
|
||||
key => 'failed_checkin'
|
||||
}
|
||||
);
|
||||
} else {
|
||||
$c->unhandled_exception($_);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,4 +11,8 @@ properties:
|
|||
- string
|
||||
- "null"
|
||||
description: Item barcode
|
||||
force_checkin:
|
||||
type:
|
||||
- boolean
|
||||
- "null"
|
||||
additionalProperties: false
|
||||
|
|
|
|||
|
|
@ -1937,36 +1937,45 @@ Note that permanent location is a code, and location may be an authval.
|
|||
bundle_form_active = item_id;
|
||||
});
|
||||
|
||||
$("#addToBundleForm").submit(function(event) {
|
||||
|
||||
/* stop form from submitting normally */
|
||||
event.preventDefault();
|
||||
|
||||
/* get the action attribute from the <form action=""> element */
|
||||
var $form = $(this),
|
||||
url = $form.attr('action');
|
||||
|
||||
function addToBundle (url, data) {
|
||||
/* Send the data using post with external_id */
|
||||
var posting = $.post({
|
||||
url: url,
|
||||
data: JSON.stringify({ external_id: $('#external_id').val()}),
|
||||
data: JSON.stringify(data),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
dataType: "json"
|
||||
});
|
||||
|
||||
const barcode = data.external_id;
|
||||
|
||||
/* Report the results */
|
||||
posting.done(function(data) {
|
||||
var barcode = $('#external_id').val();
|
||||
$('#addResult').replaceWith('<div id="addResult" class="alert alert-success">'+_("Success: Added '%s'").format(barcode)+'</div>');
|
||||
$('#external_id').val('').focus();
|
||||
bundle_changed = 1;
|
||||
});
|
||||
posting.fail(function(data) {
|
||||
var barcode = $('#external_id').val();
|
||||
if ( data.status === 409 ) {
|
||||
var response = data.responseJSON;
|
||||
if ( response.key === "PRIMARY" ) {
|
||||
$('#addResult').replaceWith('<div id="addResult" class="alert alert-warning">'+_("Warning: Item '%s' already attached").format(barcode)+'</div>');
|
||||
} else if (response.key === 'checked_out') {
|
||||
const button = $('<button type="button">')
|
||||
.addClass('btn btn-xs')
|
||||
.text(__('Check in and add to bundle'))
|
||||
.on('click', function () {
|
||||
addToBundle(url, { external_id: barcode, force_checkin: true });
|
||||
});
|
||||
$('#addResult')
|
||||
.empty()
|
||||
.attr('class', 'alert alert-warning')
|
||||
.append(__x('Warning: Item {barcode} is checked out', { barcode }))
|
||||
.append(' ', button);
|
||||
} else if (response.key === 'failed_checkin') {
|
||||
$('#addResult')
|
||||
.empty()
|
||||
.attr('class', 'alert alert-danger')
|
||||
.append(__x('Failure: Item {barcode} cannot be checked in', { barcode }))
|
||||
} else {
|
||||
$('#addResult').replaceWith('<div id="addResult" class="alert alert-danger">'+_("Failure: Item '%s' belongs to another bundle").format(barcode)+'</div>');
|
||||
}
|
||||
|
|
@ -1984,6 +1993,16 @@ Note that permanent location is a code, and location may be an authval.
|
|||
}
|
||||
$('#external_id').val('').focus();
|
||||
});
|
||||
}
|
||||
|
||||
$("#addToBundleForm").submit(function(event) {
|
||||
/* stop form from submitting normally */
|
||||
event.preventDefault();
|
||||
|
||||
const url = this.action;
|
||||
const data = { external_id: this.elements.external_id.value };
|
||||
|
||||
addToBundle(url, data);
|
||||
});
|
||||
|
||||
$("#addToBundleModal").on("hidden.bs.modal", function(e){
|
||||
|
|
|
|||
|
|
@ -213,12 +213,17 @@ subtest 'bundle_host tests' => sub {
|
|||
};
|
||||
|
||||
subtest 'add_to_bundle tests' => sub {
|
||||
plan tests => 6;
|
||||
plan tests => 7;
|
||||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
t::lib::Mocks::mock_preference( 'BundleNotLoanValue', 1 );
|
||||
|
||||
my $library = $builder->build_object({ class => 'Koha::Libraries' });
|
||||
t::lib::Mocks::mock_userenv({
|
||||
branchcode => $library->branchcode
|
||||
});
|
||||
|
||||
my $host_item = $builder->build_sample_item();
|
||||
my $bundle_item1 = $builder->build_sample_item();
|
||||
my $bundle_item2 = $builder->build_sample_item();
|
||||
|
|
@ -242,6 +247,26 @@ subtest 'add_to_bundle tests' => sub {
|
|||
'Koha::Exceptions::Item::Bundle::IsBundle',
|
||||
'Exception thrown if you try to add a bundle host to a bundle item';
|
||||
|
||||
my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
|
||||
C4::Circulation::AddIssue( $patron->unblessed, $bundle_item2->barcode );
|
||||
throws_ok { $host_item->add_to_bundle($bundle_item2) }
|
||||
'Koha::Exceptions::Item::Bundle::ItemIsCheckedOut',
|
||||
'Exception thrown if you try to add a checked out item';
|
||||
|
||||
$bundle_item2->withdrawn(1)->store;
|
||||
t::lib::Mocks::mock_preference( 'BlockReturnOfWithdrawnItems', 1 );
|
||||
throws_ok { $host_item->add_to_bundle( $bundle_item2, { force_checkin => 1 } ) }
|
||||
'Koha::Exceptions::Checkin::FailedCheckin',
|
||||
'Exception thrown if you try to add a checked out item using
|
||||
"force_checkin" and the return is not possible';
|
||||
|
||||
$bundle_item2->withdrawn(0)->store;
|
||||
lives_ok { $host_item->add_to_bundle( $bundle_item2, { force_checkin => 1 } ) }
|
||||
'No exception if you try to add a checked out item using "force_checkin" and the return is possible';
|
||||
|
||||
$bundle_item2->discard_changes;
|
||||
ok( !$bundle_item2->checkout, 'Item is not checked out after being added to a bundle' );
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue