--- /dev/null
+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;
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
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;
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;
=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
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 } );
$_->rethrow();
}
else {
- $_;
+ $_->rethrow();
}
};
}
}
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
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($_);
}
};
- string
- "null"
description: Item barcode
+ force_checkin:
+ type:
+ - boolean
+ - "null"
additionalProperties: false
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>');
}
}
$('#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){
};
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();
'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;
};