"Fossies" - the Fresh Open Source Software Archive

Member "koha-19.11.15/Koha/Item.pm" (23 Feb 2021, 13712 Bytes) of package /linux/misc/koha-19.11.15.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Item.pm" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 20.11.00_vs_20.11.01.

    1 package Koha::Item;
    2 
    3 # Copyright ByWater Solutions 2014
    4 #
    5 # This file is part of Koha.
    6 #
    7 # Koha is free software; you can redistribute it and/or modify it under the
    8 # terms of the GNU General Public License as published by the Free Software
    9 # Foundation; either version 3 of the License, or (at your option) any later
   10 # version.
   11 #
   12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
   13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
   14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
   15 #
   16 # You should have received a copy of the GNU General Public License along
   17 # with Koha; if not, write to the Free Software Foundation, Inc.,
   18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   19 
   20 use Modern::Perl;
   21 
   22 use Carp;
   23 use List::MoreUtils qw(any);
   24 
   25 use Koha::Database;
   26 use Koha::DateUtils qw( dt_from_string );
   27 
   28 use C4::Context;
   29 
   30 use Koha::Checkouts;
   31 use Koha::IssuingRules;
   32 use Koha::Item::Transfer::Limits;
   33 use Koha::Item::Transfers;
   34 use Koha::Patrons;
   35 use Koha::Libraries;
   36 use Koha::StockRotationItem;
   37 use Koha::StockRotationRotas;
   38 
   39 use base qw(Koha::Object);
   40 
   41 =head1 NAME
   42 
   43 Koha::Item - Koha Item object class
   44 
   45 =head1 API
   46 
   47 =head2 Class methods
   48 
   49 =cut
   50 
   51 =head3 effective_itemtype
   52 
   53 Returns the itemtype for the item based on whether item level itemtypes are set or not.
   54 
   55 =cut
   56 
   57 sub effective_itemtype {
   58     my ( $self ) = @_;
   59 
   60     return $self->_result()->effective_itemtype();
   61 }
   62 
   63 =head3 home_branch
   64 
   65 =cut
   66 
   67 sub home_branch {
   68     my ($self) = @_;
   69 
   70     $self->{_home_branch} ||= Koha::Libraries->find( $self->homebranch() );
   71 
   72     return $self->{_home_branch};
   73 }
   74 
   75 =head3 holding_branch
   76 
   77 =cut
   78 
   79 sub holding_branch {
   80     my ($self) = @_;
   81 
   82     $self->{_holding_branch} ||= Koha::Libraries->find( $self->holdingbranch() );
   83 
   84     return $self->{_holding_branch};
   85 }
   86 
   87 =head3 biblio
   88 
   89 my $biblio = $item->biblio;
   90 
   91 Return the bibliographic record of this item
   92 
   93 =cut
   94 
   95 sub biblio {
   96     my ( $self ) = @_;
   97     my $biblio_rs = $self->_result->biblio;
   98     return Koha::Biblio->_new_from_dbic( $biblio_rs );
   99 }
  100 
  101 =head3 biblioitem
  102 
  103 my $biblioitem = $item->biblioitem;
  104 
  105 Return the biblioitem record of this item
  106 
  107 =cut
  108 
  109 sub biblioitem {
  110     my ( $self ) = @_;
  111     my $biblioitem_rs = $self->_result->biblioitem;
  112     return Koha::Biblioitem->_new_from_dbic( $biblioitem_rs );
  113 }
  114 
  115 =head3 checkout
  116 
  117 my $checkout = $item->checkout;
  118 
  119 Return the checkout for this item
  120 
  121 =cut
  122 
  123 sub checkout {
  124     my ( $self ) = @_;
  125     my $checkout_rs = $self->_result->issue;
  126     return unless $checkout_rs;
  127     return Koha::Checkout->_new_from_dbic( $checkout_rs );
  128 }
  129 
  130 =head3 holds
  131 
  132 my $holds = $item->holds();
  133 my $holds = $item->holds($params);
  134 my $holds = $item->holds({ found => 'W'});
  135 
  136 Return holds attached to an item, optionally accept a hashref of params to pass to search
  137 
  138 =cut
  139 
  140 sub holds {
  141     my ( $self,$params ) = @_;
  142     my $holds_rs = $self->_result->reserves->search($params);
  143     return Koha::Holds->_new_from_dbic( $holds_rs );
  144 }
  145 
  146 =head3 get_transfer
  147 
  148 my $transfer = $item->get_transfer;
  149 
  150 Return the transfer if the item is in transit or undef
  151 
  152 =cut
  153 
  154 sub get_transfer {
  155     my ( $self ) = @_;
  156     my $transfer_rs = $self->_result->branchtransfers->search({ datearrived => undef })->first;
  157     return unless $transfer_rs;
  158     return Koha::Item::Transfer->_new_from_dbic( $transfer_rs );
  159 }
  160 
  161 =head3 last_returned_by
  162 
  163 Gets and sets the last borrower to return an item.
  164 
  165 Accepts and returns Koha::Patron objects
  166 
  167 $item->last_returned_by( $borrowernumber );
  168 
  169 $last_returned_by = $item->last_returned_by();
  170 
  171 =cut
  172 
  173 sub last_returned_by {
  174     my ( $self, $borrower ) = @_;
  175 
  176     my $items_last_returned_by_rs = Koha::Database->new()->schema()->resultset('ItemsLastBorrower');
  177 
  178     if ($borrower) {
  179         return $items_last_returned_by_rs->update_or_create(
  180             { borrowernumber => $borrower->borrowernumber, itemnumber => $self->id } );
  181     }
  182     else {
  183         unless ( $self->{_last_returned_by} ) {
  184             my $result = $items_last_returned_by_rs->single( { itemnumber => $self->id } );
  185             if ($result) {
  186                 $self->{_last_returned_by} = Koha::Patrons->find( $result->get_column('borrowernumber') );
  187             }
  188         }
  189 
  190         return $self->{_last_returned_by};
  191     }
  192 }
  193 
  194 =head3 can_article_request
  195 
  196 my $bool = $item->can_article_request( $borrower )
  197 
  198 Returns true if item can be specifically requested
  199 
  200 $borrower must be a Koha::Patron object
  201 
  202 =cut
  203 
  204 sub can_article_request {
  205     my ( $self, $borrower ) = @_;
  206 
  207     my $rule = $self->article_request_type($borrower);
  208 
  209     return 1 if $rule && $rule ne 'no' && $rule ne 'bib_only';
  210     return q{};
  211 }
  212 
  213 =head3 hidden_in_opac
  214 
  215 my $bool = $item->hidden_in_opac({ [ rules => $rules ] })
  216 
  217 Returns true if item fields match the hidding criteria defined in $rules.
  218 Returns false otherwise.
  219 
  220 Takes HASHref that can have the following parameters:
  221     OPTIONAL PARAMETERS:
  222     $rules : { <field> => [ value_1, ... ], ... }
  223 
  224 Note: $rules inherits its structure from the parsed YAML from reading
  225 the I<OpacHiddenItems> system preference.
  226 
  227 =cut
  228 
  229 sub hidden_in_opac {
  230     my ( $self, $params ) = @_;
  231 
  232     my $rules = $params->{rules} // {};
  233 
  234     return 1
  235         if C4::Context->preference('hidelostitems') and
  236            $self->itemlost > 0;
  237 
  238     my $hidden_in_opac = 0;
  239 
  240     foreach my $field ( keys %{$rules} ) {
  241 
  242         if ( any { $self->$field eq $_ } @{ $rules->{$field} } ) {
  243             $hidden_in_opac = 1;
  244             last;
  245         }
  246     }
  247 
  248     return $hidden_in_opac;
  249 }
  250 
  251 =head3 can_be_transferred
  252 
  253 $item->can_be_transferred({ to => $to_library, from => $from_library })
  254 Checks if an item can be transferred to given library.
  255 
  256 This feature is controlled by two system preferences:
  257 UseBranchTransferLimits to enable / disable the feature
  258 BranchTransferLimitsType to use either an itemnumber or ccode as an identifier
  259                          for setting the limitations
  260 
  261 Takes HASHref that can have the following parameters:
  262     MANDATORY PARAMETERS:
  263     $to   : Koha::Library
  264     OPTIONAL PARAMETERS:
  265     $from : Koha::Library  # if not given, item holdingbranch
  266                            # will be used instead
  267 
  268 Returns 1 if item can be transferred to $to_library, otherwise 0.
  269 
  270 To find out whether at least one item of a Koha::Biblio can be transferred, please
  271 see Koha::Biblio->can_be_transferred() instead of using this method for
  272 multiple items of the same biblio.
  273 
  274 =cut
  275 
  276 sub can_be_transferred {
  277     my ($self, $params) = @_;
  278 
  279     my $to   = $params->{to};
  280     my $from = $params->{from};
  281 
  282     $to   = $to->branchcode;
  283     $from = defined $from ? $from->branchcode : $self->holdingbranch;
  284 
  285     return 1 if $from eq $to; # Transfer to current branch is allowed
  286     return 1 unless C4::Context->preference('UseBranchTransferLimits');
  287 
  288     my $limittype = C4::Context->preference('BranchTransferLimitsType');
  289     return Koha::Item::Transfer::Limits->search({
  290         toBranch => $to,
  291         fromBranch => $from,
  292         $limittype => $limittype eq 'itemtype'
  293                         ? $self->effective_itemtype : $self->ccode
  294     })->count ? 0 : 1;
  295 }
  296 
  297 =head3 article_request_type
  298 
  299 my $type = $item->article_request_type( $borrower )
  300 
  301 returns 'yes', 'no', 'bib_only', or 'item_only'
  302 
  303 $borrower must be a Koha::Patron object
  304 
  305 =cut
  306 
  307 sub article_request_type {
  308     my ( $self, $borrower ) = @_;
  309 
  310     my $branch_control = C4::Context->preference('HomeOrHoldingBranch');
  311     my $branchcode =
  312         $branch_control eq 'homebranch'    ? $self->homebranch
  313       : $branch_control eq 'holdingbranch' ? $self->holdingbranch
  314       :                                      undef;
  315     my $borrowertype = $borrower->categorycode;
  316     my $itemtype = $self->effective_itemtype();
  317     my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule({ categorycode => $borrowertype, itemtype => $itemtype, branchcode => $branchcode });
  318 
  319     return q{} unless $issuing_rule;
  320     return $issuing_rule->article_requests || q{}
  321 }
  322 
  323 =head3 current_holds
  324 
  325 =cut
  326 
  327 sub current_holds {
  328     my ( $self ) = @_;
  329     my $attributes = { order_by => 'priority' };
  330     my $dtf = Koha::Database->new->schema->storage->datetime_parser;
  331     my $params = {
  332         itemnumber => $self->itemnumber,
  333         suspend => 0,
  334         -or => [
  335             reservedate => { '<=' => $dtf->format_date(dt_from_string) },
  336             waitingdate => { '!=' => undef },
  337         ],
  338     };
  339     my $hold_rs = $self->_result->reserves->search( $params, $attributes );
  340     return Koha::Holds->_new_from_dbic($hold_rs);
  341 }
  342 
  343 =head3 stockrotationitem
  344 
  345   my $sritem = Koha::Item->stockrotationitem;
  346 
  347 Returns the stock rotation item associated with the current item.
  348 
  349 =cut
  350 
  351 sub stockrotationitem {
  352     my ( $self ) = @_;
  353     my $rs = $self->_result->stockrotationitem;
  354     return 0 if !$rs;
  355     return Koha::StockRotationItem->_new_from_dbic( $rs );
  356 }
  357 
  358 =head3 add_to_rota
  359 
  360   my $item = $item->add_to_rota($rota_id);
  361 
  362 Add this item to the rota identified by $ROTA_ID, which means associating it
  363 with the first stage of that rota.  Should this item already be associated
  364 with a rota, then we will move it to the new rota.
  365 
  366 =cut
  367 
  368 sub add_to_rota {
  369     my ( $self, $rota_id ) = @_;
  370     Koha::StockRotationRotas->find($rota_id)->add_item($self->itemnumber);
  371     return $self;
  372 }
  373 
  374 =head3 has_pending_hold
  375 
  376   my $is_pending_hold = $item->has_pending_hold();
  377 
  378 This method checks the tmp_holdsqueue to see if this item has been selected for a hold, but not filled yet and returns true or false
  379 
  380 =cut
  381 
  382 sub has_pending_hold {
  383     my ( $self ) = @_;
  384     my $pending_hold = $self->_result->tmp_holdsqueues;
  385     return $pending_hold->count ? 1: 0;
  386 }
  387 
  388 =head3 as_marc_field
  389 
  390     my $mss   = C4::Biblio::GetMarcSubfieldStructure( '', { unsafe => 1 } );
  391     my $field = $item->as_marc_field({ [ mss => $mss ] });
  392 
  393 This method returns a MARC::Field object representing the Koha::Item object
  394 with the current mappings configuration.
  395 
  396 =cut
  397 
  398 sub as_marc_field {
  399     my ( $self, $params ) = @_;
  400 
  401     my $mss = $params->{mss} // C4::Biblio::GetMarcSubfieldStructure( '', { unsafe => 1 } );
  402     my $item_tag = $mss->{'items.itemnumber'}[0]->{tagfield};
  403 
  404     my @subfields;
  405 
  406     my @columns = $self->_result->result_source->columns;
  407 
  408     foreach my $item_field ( @columns ) {
  409         my $mapping = $mss->{ "items.$item_field"}[0];
  410         my $tagfield    = $mapping->{tagfield};
  411         my $tagsubfield = $mapping->{tagsubfield};
  412         next if !$tagfield; # TODO: Should we raise an exception instead?
  413                             # Feels like safe fallback is better
  414 
  415         push @subfields, $tagsubfield => $self->$item_field
  416             if defined $self->$item_field and $item_field ne '';
  417     }
  418 
  419     my $unlinked_item_subfields = C4::Items::_parse_unlinked_item_subfields_from_xml($self->more_subfields_xml);
  420     push( @subfields, @{$unlinked_item_subfields} )
  421         if defined $unlinked_item_subfields and $#$unlinked_item_subfields > -1;
  422 
  423     my $field;
  424 
  425     $field = MARC::Field->new(
  426         "$item_tag", ' ', ' ', @subfields
  427     ) if @subfields;
  428 
  429     return $field;
  430 }
  431 
  432 =head3 to_api_mapping
  433 
  434 This method returns the mapping for representing a Koha::Item object
  435 on the API.
  436 
  437 =cut
  438 
  439 sub to_api_mapping {
  440     return {
  441         itemnumber               => 'item_id',
  442         biblionumber             => 'biblio_id',
  443         biblioitemnumber         => undef,
  444         barcode                  => 'external_id',
  445         dateaccessioned          => 'acquisition_date',
  446         booksellerid             => 'acquisition_source',
  447         homebranch               => 'home_library_id',
  448         price                    => 'purchase_price',
  449         replacementprice         => 'replacement_price',
  450         replacementpricedate     => 'replacement_price_date',
  451         datelastborrowed         => 'last_checkout_date',
  452         datelastseen             => 'last_seen_date',
  453         stack                    => undef,
  454         notforloan               => 'not_for_loan_status',
  455         damaged                  => 'damaged_status',
  456         damaged_on               => 'damaged_date',
  457         itemlost                 => 'lost_status',
  458         itemlost_on              => 'lost_date',
  459         withdrawn                => 'withdrawn',
  460         withdrawn_on             => 'withdrawn_date',
  461         itemcallnumber           => 'callnumber',
  462         coded_location_qualifier => 'coded_location_qualifier',
  463         issues                   => 'checkouts_count',
  464         renewals                 => 'renewals_count',
  465         reserves                 => 'holds_count',
  466         restricted               => 'restricted_status',
  467         itemnotes                => 'public_notes',
  468         itemnotes_nonpublic      => 'internal_notes',
  469         holdingbranch            => 'holding_library_id',
  470         paidfor                  => undef,
  471         timestamp                => 'timestamp',
  472         location                 => 'location',
  473         permanent_location       => 'permanent_location',
  474         onloan                   => 'checked_out_date',
  475         cn_source                => 'call_number_source',
  476         cn_sort                  => 'call_number_sort',
  477         ccode                    => 'collection_code',
  478         materials                => 'materials_notes',
  479         uri                      => 'uri',
  480         itype                    => 'item_type',
  481         more_subfields_xml       => 'extended_subfields',
  482         enumchron                => 'serial_issue_number',
  483         copynumber               => 'copy_number',
  484         stocknumber              => 'inventory_number',
  485         new_status               => 'new_status'
  486     };
  487 }
  488 
  489 =head2 Internal methods
  490 
  491 =head3 _type
  492 
  493 =cut
  494 
  495 sub _type {
  496     return 'Item';
  497 }
  498 
  499 =head1 AUTHOR
  500 
  501 Kyle M Hall <kyle@bywatersolutions.com>
  502 
  503 =cut
  504 
  505 1;