@@ -, +, @@ --- Koha/Item.pm | 12 ++ Koha/Template/Plugin/AuthorisedValues.pm | 4 +- api/v1/swagger/definitions/item.yaml | 28 +++++ api/v1/swagger/paths/biblios.yaml | 10 ++ .../prog/en/modules/catalogue/detail.tt | 109 +++++++++++++++++- 5 files changed, 155 insertions(+), 8 deletions(-) --- a/Koha/Item.pm +++ a/Koha/Item.pm @@ -767,6 +767,10 @@ sub get_transfer { return Koha::Item::Transfer->_new_from_dbic($transfer) if $transfer; } +sub transfer { + return shift->get_transfer(@_); +} + =head3 get_transfers my $transfer = $item->get_transfers; @@ -1049,6 +1053,11 @@ sub current_holds { return Koha::Holds->_new_from_dbic($hold_rs); } +sub first_hold { + my ( $self ) = @_; + return $self->current_holds->next; +} + =head3 stockrotationitem my $sritem = Koha::Item->stockrotationitem; @@ -1744,6 +1753,9 @@ sub itemtype { return Koha::ItemTypes->find( $self->effective_itemtype ); } +sub item_type { + return shift->itemtype; +} =head3 orders --- a/Koha/Template/Plugin/AuthorisedValues.pm +++ a/Koha/Template/Plugin/AuthorisedValues.pm @@ -69,8 +69,8 @@ sub GetCategories { sub GetDescriptionsByKohaField { my ( $self, $params ) = @_; - return Koha::AuthorisedValues->get_descriptions_by_koha_field( - { kohafield => $params->{kohafield} } ); + return [ Koha::AuthorisedValues->get_descriptions_by_koha_field( + { kohafield => $params->{kohafield} } ) ]; } sub GetDescriptionByKohaField { --- a/api/v1/swagger/definitions/item.yaml +++ a/api/v1/swagger/definitions/item.yaml @@ -242,6 +242,34 @@ properties: type: - object - "null" + checkout: + type: + - object + - "null" + transfer: + type: + - object + - "null" + first_hold: + type: + - object + - "null" + recall: + type: + - object + - "null" + item_type: + type: + - object + - "null" + in_bundle: + type: + - boolean + - "null" + bundle_host: + type: + - object + - "null" _strings: type: - object --- a/api/v1/swagger/paths/biblios.yaml +++ a/api/v1/swagger/paths/biblios.yaml @@ -423,6 +423,16 @@ type: string enum: - +strings + - checkout + - checkout.patron + - transfer + - first_hold + - first_hold.patron + - recall + - recall.patron + - item_type + - in_bundle + - bundle_host - cover_image_ids - item_group_item.item_group.description - serialitem.serial --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt @@ -2485,11 +2485,16 @@ }); [% END %] - const can_edit_items_from = [% To.json(can_edit_items_from) | $raw %]; + 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])); + const av_lost = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.itemlost' })) | $raw %].map( av => [av.authorised_value, av.lib])); + const av_withdrawn = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.withdrawn' })) | $raw %].map( av => [av.authorised_value, av.lib])); + const av_damaged = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.damaged' })) | $raw %].map( av => [av.authorised_value, av.lib])); + const av_not_for_loan= new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.notforloan' })) | $raw %].map( av => [av.authorised_value, av.lib])); + const av_restricted = new Map([% To.json(AuthorisedValues.GetDescriptionsByKohaField({ kohafield => 'items.restricted' })) | $raw %].map( av => [av.authorised_value, av.lib])); let table_url = "/api/v1/biblios/[% biblio.biblionumber | uri %]/items?"; - let embed = ["+strings"]; + let embed = ["+strings,checkout,checkout.patron,transfer,first_hold,first_hold.patron,item_type"]; [% IF Koha.Preference('LocalCoverImages') %] embed.push('cover_image_ids'); [% END %] @@ -2499,6 +2504,10 @@ [% IF biblio.serial %] embed.push('serialitem.serial'); [% END %] + [% IF Koha.Preference('UseRecalls') %] + embed.push('recall', 'recall.patron') + [% END %] + embed.push('in_bundle', 'bundle_host'); let table_settings = [% TablesSettings.GetTableSettings('catalogue', 'detail','holdings_table','json') | $raw %]; var items_table = $("#table_items").kohaTable({ ajax: { url: table_url }, @@ -2659,12 +2668,100 @@ } }, { - data: "", + data: "me.lost_status", className: "status", - searchable: false, // FIXME - orderable: true, + searchable: false, // FIXME We are losing the ability to search on the status + orderable: false, render: function (data, type, row, meta) { - return "status"; // FIXME Display status + let nodes = ""; + if ( row.checkout ) { + nodes += ''; + if ( row.checkout.onsite_checkout ) { + if ( can_edit_items_from[row.holding_library_id] ){ + let patron_to_html = $patron_to_html(row.checkout.patron); [%# FIXME What about hide_patron_infos_if_needed?? %] + nodes += _("Currently in local use by %s").format(patron_to_html); + } else { + nodes += _("Currently in local use"); + } + } else { + nodes += ''; + if ( can_edit_items_from[row.holding_library_id] ){ + let patron_to_html = $patron_to_html(row.checkout.patron); [%# FIXME What about hide_patron_infos_if_needed?? %] + nodes += _("Checked out to %s").format(patron_to_html); + } else { + nodes += _("Checked out"); + } + } + nodes += ': '; + nodes += _("due %s").format($date(row.checkout.due_date)); [%# FIXME Missing due date formatting here, $date do not have as_due_date option %] + nodes += "" + } else if ( row.transfer ) { + if ( row.transfer.datesent ) { + nodes += '%s'.format(_("In transit from %s to %s since %s").format(row.transfer.frombranch, row.transfer.tobranch, $date(row.transfer.datesent))); [%# FIXME display library names, not codes, do we use _strings here? %] + } else { + nodes += '%s'.format(_("Transit pending from %s to %s since %s").format(row.transfer.frombranch, row.transfer.tobranch, $date(row.transfer.daterequested))); [%# FIXME See above %] + } + } + + if ( row.lost_status ) { + let lost_lib = av_lost.get(row.lost_status.toString()) || _("Unavailable (lost or missing"); + nodes += '%s'.format(lost_lib); + } + + if ( row.withdrawn ) { + let withdrawn_lib = av_withdrawn.get(row.withdrawn.toString()) || _("Withdrawn"); + nodes += '%s'.format(withdrawn_lib); + } + + if ( row.damaged ) { + let damaged_lib = av_damaged.get(row.damaged.toString()) || _("Damaged"); + nodes += '%s'.format(damaged_lib); + } + + if ( row.not_for_loan_status || row.item_type.notforloan ) { + let not_for_loan_lib = av_not_for_loan.get(row.not_for_loan_status.toString()); + nodes += '%s'.format(_("Not for loan")) + ( not_for_loan_lib ? ' (%s)'.format(not_for_loan_lib) : '' ) + ''; + } + + if ( row.first_hold ) { + if ( row.first_hold.waiting_date ) { + [%# FIXME Display library names instead of codes %] + [%# FIXME We lost the desk name, we need an additional embed %] + nodes += '%s'.format(_("Waiting at %s since %s.".format(row.first_hold.pickup_library_id, $date(row.first_hold.waiting_date)))); + [% IF Koha.Preference('canreservefromotherbranches') %] + if ( row.first_hold.waiting_date || row.first_hold.priority == 1 ) { + let patron_to_html = $patron_to_html(row.first_hold.patron); [%# FIXME What about hide_patron_infos_if_needed?? %] + nodes += ' %s'.format(_("Hold for: %s").format(patron_to_html)); + } + [% END %] + } else { + nodes += '%s'.format(_("There is an item level hold on this item (priority = %s).").format(row.first_hold.priority)); + } + } + + [% IF Koha.Preference('UseRecalls') %] + if ( row.recall ) { + if ( row.recall.waiting_date ) { + nodes += '%s'.format(_("Waiting at %s since %s").format(row.recall.pickup_library_id, $date(row.recall.waiting_date))); # FIXME Display library names instead of codes + } else { + let patron_to_html = $patron_to_html(row.recall.patron); + nodes += '%s'.format(_("recalled by %s on %s").format(patron_to_html, row.recall.created_date)); + } + } + [% END %] + + if ( ! ( row.not_for_loan_status || row.item_type.notforloan || row.checked_out_date || row.lost_status || row.withdrawn || row.damaged || row.transfer || row.first_hold || row.recall ) ) { + nodes += ' %s'.format(_("Available")) + } + + if ( row.restricted_status ) { + nodes += '(%s)'.format(av_restricted.get(row.restricted_status.toString())); + } + + if ( row.in_bundle ) { + nodes += '%s'.format(_("In bundle: %s").format($biblio_to_html(row.bundle_host.biblio, { link: true }))); + } + return nodes; } }, { --