diff --git a/Koha/Item.pm b/Koha/Item.pm
index 341a8050b7..d623f5fba2 100644
--- a/Koha/Item.pm
+++ b/Koha/Item.pm
@@ -1446,11 +1446,7 @@ sub _status {
push @statuses, "local_use";
}
} elsif ( my $transfer = $self->transfer ) {
- if ( $transfer->datesent ) {
- push @statuses, "in_transit";
- } else {
- push @statuses, "transit_pending";
- }
+ push @statuses, "in_transit";
}
if ( $self->itemlost ) {
push @statuses, 'lost';
diff --git a/Koha/Items.pm b/Koha/Items.pm
index edf66466ff..bf65674595 100644
--- a/Koha/Items.pm
+++ b/Koha/Items.pm
@@ -225,6 +225,90 @@ sub filter_by_bookable {
);
}
+sub filter_by_checked_out {
+ my ( $self, $params ) = @_;
+
+ $params //= {};
+ my $checkouts = Koha::Checkouts->search(
+ { %$params, 'me.itemnumber' => [ $self->get_column('itemnumber') ], },
+ {
+ columns => ['itemnumber'],
+ distinct => 1
+ }
+ )->_resultset->as_query;
+
+ return $self->search( { 'me.itemnumber' => { '-in' => $checkouts } } );
+}
+
+sub filter_by_in_transit {
+ my ( $self, $params ) = @_;
+
+ $params //= {};
+ my $transfers = Koha::Item::Transfers->search(
+ { %$params, 'me.itemnumber' => [ $self->get_column('itemnumber') ], },
+ {
+ columns => ['itemnumber'],
+ distinct => 1
+ }
+ )->_resultset->as_query;
+
+ return $self->search( { 'me.itemnumber' => { '-in' => $transfers } } );
+}
+
+sub filter_by_for_loan {
+
+}
+
+sub filter_by_has_holds {
+ my ( $self, $params ) = @_;
+
+ $params //= {};
+ my $holds = Koha::Holds->search(
+ { %$params, 'me.itemnumber' => [ $self->get_column('itemnumber') ], },
+ {
+ columns => ['itemnumber'],
+ distinct => 1
+ }
+ )->_resultset->as_query;
+
+ return $self->search( { 'me.itemnumber' => { '-in' => $holds } } );
+}
+
+sub filter_by_has_recalls {
+ my ( $self, $params ) = @_;
+
+ $params //= {};
+ my $recalls = Koha::Recalls->search(
+ { %$params, 'me.itemnumber' => [ $self->get_column('itemnumber') ], },
+ {
+ columns => ['itemnumber'],
+ distinct => 1
+ }
+ )->_resultset->as_query;
+
+ return $self->search( { 'me.itemnumber' => { '-in' => $recalls } } );
+}
+
+sub filter_by_available {
+ my ($self) = @_;
+
+ my @all_itemnumbers = $self->get_column('itemnumber');
+ my @item_types_notforloan = Koha::ItemTypes->search( { notforloan => { '!=' => 0 } } )->get_column('itemtype');
+ my @not_available_itemnumbers;
+ push @not_available_itemnumbers, $self->filter_by_checked_out->get_column('itemnumber');
+ push @not_available_itemnumbers, $self->filter_by_in_transit->get_column('itemnumber');
+ push @not_available_itemnumbers, $self->search(
+ {
+ itemlost => 0, withdrawn => 0, damaged => 0, notforloan => 0,
+ itype => { -not_in => \@item_types_notforloan }, restricted => 0,
+ }
+ )->get_column('itemnumber');
+ push @not_available_itemnumbers, $self->filter_by_has_holds->get_column('itemnumber');
+ push @not_available_itemnumbers, $self->filter_by_has_recalls->get_column('itemnumber');
+
+ return Koha::Items->search( { 'me.itemnumber' => [ array_minus @all_itemnumbers, @not_available_itemnumbers ] } );
+}
+
=head3 move_to_biblio
$items->move_to_biblio($to_biblio);
@@ -498,6 +582,52 @@ sub apply_regex {
return $value;
}
+sub search {
+ my ( $self, $params, $attributes ) = @_;
+ my $status = ( $params && ref($params) eq 'HASH' ) ? delete $params->{_status} : undef;
+ if ($status) {
+ if ( $status eq 'checked_out' ) {
+ $self = $self->filter_by_checked_out( { onsite_checkout => 0 } );
+ }
+ if ( $status eq 'local_use' ) {
+ $self = $self->filter_by_checked_out( { onsite_checkout => 1 } );
+ }
+ if ( $status eq 'in_transit' ) {
+ $self = $self->filter_by_in_transit;
+ }
+ if ( $status eq 'lost' ) {
+ $self = $self->search( { itemlost => { '!=' => 0 } } );
+ }
+ if ( $status eq 'withdrawn' ) {
+ $self = $self->search( { withdrawn => { '!=' => 0 } } );
+ }
+ if ( $status eq 'damaged' ) {
+ $self = $self->search( { damaged => { '!=' => 0 } } );
+ }
+ if ( $status eq 'not_for_loan' ) {
+ my @item_types_notforloan =
+ Koha::ItemTypes->search( { notforloan => { '!=' => 0 } } )->get_column('itemtype');
+ $self = $self->search( [ { notforloan => { '!=' => 0 } }, { 'me.itype' => \@item_types_notforloan } ] );
+ }
+ if ( $status eq 'on_hold' ) {
+ $self = $self->filter_by_has_holds;
+ }
+ if ( $status eq 'recalled' ) {
+ $self = $self->filter_by_has_recalls;
+ }
+
+ if ( $status eq 'available' ) {
+ $self = $self->filter_by_available;
+ }
+
+ if ( $status eq 'restricted' ) {
+ $self = $self->search( { restricted => { '!=' => 0 } } );
+ }
+ }
+
+ return $self->SUPER::search( $params, $attributes );
+}
+
=head3 search_ordered
$items->search_ordered;
diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc
index 2c44d74df1..fa5f53d1f1 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc
+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc
@@ -220,6 +220,9 @@
});
const item_types_notforloan = new Map(all_item_types.map( it => [it.itemtype, it.notforloan] ));
+ const statuses = {checked_out: _("Checked out"), local_use: _("On-site checkout"), in_transit: _("In transit"), lost: _("Lost"), withdrawn: _("Withdrawn"), damaged:_("Damaged"), not_for_loan: _("Not for loan"), on_hold: _("On hold"), recalled: _("Recalled"), available: _("Available"), restricted: _("Restricted")};
+ const all_statuses = Object.keys(statuses).map(k => {return {_id: k, _str: statuses[k]}});
+
const can_edit_items_from = [% To.json(can_edit_items_from || []) | $raw %];
const item_type_image_locations = [% To.json(item_type_image_locations) | $raw %];
const av_loc = new Map([% To.json(AuthorisedValues.Get('LOC')) | $raw %].map( av => [av.authorised_value, av.lib]));
@@ -319,12 +322,17 @@
items_selection[tab_id] = [];
}
+ default_filters._status = function(){
+ return $("#" + tab_id + "_status select").val();
+ };
+
let offset = 2;
[% UNLESS Koha.Preference('LocalCoverImages') %]offset--;[% END %]
let filters_options = {
[offset] : () => all_item_types,
[offset+1] : () => all_libraries,
[offset+2] : () => all_libraries,
+ [offset+7] : () => all_statuses,
};
var items_table = $("#" + tab_id + '_table').kohaTable({
@@ -497,9 +505,9 @@
}
},
{
- data: "me._status",
+ data: "",
className: "status",
- searchable: false, // FIXME We are losing the ability to search on the status
+ searchable: false,
orderable: false,
render: function (data, type, row, meta) {
let nodes = "";
@@ -523,11 +531,11 @@
}
if ( status == 'in_transit' ) {
- nodes += '%s'.format(_("In transit from %s to %s since %s").format(escape_str(row.transfer._strings.from_library.str), escape_str(row.transfer._strings.to_library.str), $date(row.transfer.datesent)));
- }
-
- if ( status == 'transit_pending' ) {
- nodes += '%s'.format(_("Transit pending from %s to %s since %s").format(escape_str(row.transfer._strings.from_library.str), escape_str(row.transfer._strings.to_library.str), $date(row.transfer.daterequested)));
+ if ( row.transfer.datesent ) {
+ nodes += '%s'.format(_("In transit from %s to %s since %s").format(escape_str(row.transfer._strings.from_library.str), escape_str(row.transfer._strings.to_library.str), $date(row.transfer.datesent)));
+ } else {
+ nodes += '%s'.format(_("Transit pending from %s to %s since %s").format(escape_str(row.transfer._strings.from_library.str), escape_str(row.transfer._strings.to_library.str), $date(row.transfer.daterequested)));
+ }
}
if ( status == 'lost' ) {