3 # Copyright ByWater Solutions 2014
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
23 use List
::MoreUtils
qw(any);
28 use Koha
::DateUtils
qw( dt_from_string );
33 use C4
::Biblio
qw( ModZebra ); # FIXME This is terrible, we should move the indexation code outside of C4::Biblio
34 use C4
::ClassSource
; # FIXME We would like to avoid that
35 use C4
::Log
qw( logaction );
38 use Koha
::CirculationRules
;
39 use Koha
::Item
::Transfer
::Limits
;
40 use Koha
::Item
::Transfers
;
45 use Koha
::StockRotationItem
;
46 use Koha
::StockRotationRotas
;
48 use base
qw(Koha::Object);
52 Koha::Item - Koha Item object class
64 $params can take an optional 'skip_modzebra_update' parameter.
65 If set, the reindexation process will not happen (ModZebra not called)
67 NOTE: This is a temporary fix to answer a performance issue when lot of items
68 are added (or modified) at the same time.
69 The correct way to fix this is to make the ES reindexation process async.
70 You should not turn it on if you do not understand what it is doing exactly.
76 my $params = @_ ?
shift : {};
78 my $log_action = $params->{log_action
} // 1;
80 # We do not want to oblige callers to pass this value
81 # Dev conveniences vs performance?
82 unless ( $self->biblioitemnumber ) {
83 $self->biblioitemnumber( $self->biblio->biblioitem->biblioitemnumber );
86 # See related changes from C4::Items::AddItem
87 unless ( $self->itype ) {
88 $self->itype($self->biblio->biblioitem->itemtype);
91 my $today = dt_from_string
;
92 unless ( $self->in_storage ) { #AddItem
93 unless ( $self->permanent_location ) {
94 $self->permanent_location($self->location);
96 unless ( $self->replacementpricedate ) {
97 $self->replacementpricedate($today);
99 unless ( $self->datelastseen ) {
100 $self->datelastseen($today);
103 unless ( $self->dateaccessioned ) {
104 $self->dateaccessioned($today);
107 if ( $self->itemcallnumber
108 or $self->cn_source )
110 my $cn_sort = GetClassSort
( $self->cn_source, $self->itemcallnumber, "" );
111 $self->cn_sort($cn_sort);
114 C4
::Biblio
::ModZebra
( $self->biblionumber, "specialUpdate", "biblioserver" )
115 unless $params->{skip_modzebra_update
};
117 logaction
( "CATALOGUING", "ADD", $self->itemnumber, "item" )
118 if $log_action && C4
::Context
->preference("CataloguingLog");
120 $self->_after_item_action_hooks({ action
=> 'create' });
124 my %updated_columns = $self->_result->get_dirty_columns;
125 return $self->SUPER::store
unless %updated_columns;
127 # Retrieve the item for comparison if we need to
129 exists $updated_columns{itemlost
}
130 or exists $updated_columns{withdrawn
}
131 or exists $updated_columns{damaged
}
132 ) ?
$self->get_from_storage : undef;
134 # Update *_on fields if needed
135 # FIXME: Why not for AddItem as well?
136 my @fields = qw( itemlost withdrawn damaged );
137 for my $field (@fields) {
139 # If the field is defined but empty or 0, we are
140 # removing/unsetting and thus need to clear out
142 if ( exists $updated_columns{$field}
143 && defined( $self->$field )
146 my $field_on = "${field}_on";
147 $self->$field_on(undef);
149 # If the field has changed otherwise, we much update
151 elsif (exists $updated_columns{$field}
152 && $updated_columns{$field}
153 && !$pre_mod_item->$field )
155 my $field_on = "${field}_on";
157 DateTime
::Format
::MySQL
->format_datetime(
164 if ( exists $updated_columns{itemcallnumber
}
165 or exists $updated_columns{cn_source
} )
167 my $cn_sort = GetClassSort
( $self->cn_source, $self->itemcallnumber, "" );
168 $self->cn_sort($cn_sort);
172 if ( exists $updated_columns{location
}
173 and $self->location ne 'CART'
174 and $self->location ne 'PROC'
175 and not exists $updated_columns{permanent_location
} )
177 $self->permanent_location( $self->location );
180 # If item was lost and has now been found,
181 # reverse any list item charges if necessary.
182 if ( exists $updated_columns{itemlost
}
183 and $updated_columns{itemlost
} <= 0
184 and $pre_mod_item->itemlost > 0 )
186 $self->_set_found_trigger($pre_mod_item);
190 C4
::Biblio
::ModZebra
( $self->biblionumber, "specialUpdate", "biblioserver" )
191 unless $params->{skip_modzebra_update
};
193 $self->_after_item_action_hooks({ action
=> 'modify' });
195 logaction
( "CATALOGUING", "MODIFY", $self->itemnumber, "item " . Dumper
($self->unblessed) )
196 if $log_action && C4
::Context
->preference("CataloguingLog");
199 unless ( $self->dateaccessioned ) {
200 $self->dateaccessioned($today);
203 return $self->SUPER::store
;
212 my $params = @_ ?
shift : {};
214 # FIXME check the item has no current issues
215 # i.e. raise the appropriate exception
217 C4
::Biblio
::ModZebra
( $self->biblionumber, "specialUpdate", "biblioserver" )
218 unless $params->{skip_modzebra_update
};
220 $self->_after_item_action_hooks({ action
=> 'delete' });
222 logaction
( "CATALOGUING", "DELETE", $self->itemnumber, "item" )
223 if C4
::Context
->preference("CataloguingLog");
225 return $self->SUPER::delete;
234 my $params = @_ ?
shift : {};
236 my $safe_to_delete = $self->safe_to_delete;
237 return $safe_to_delete unless $safe_to_delete eq '1';
239 $self->move_to_deleted;
241 return $self->delete($params);
244 =head3 safe_to_delete
246 returns 1 if the item is safe to delete,
248 "book_on_loan" if the item is checked out,
250 "not_same_branch" if the item is blocked by independent branches,
252 "book_reserved" if the there are holds aganst the item, or
254 "linked_analytics" if the item has linked analytic records.
256 "last_item_for_hold" if the item is the last one on a record on which a biblio-level hold is placed
263 return "book_on_loan" if $self->checkout;
265 return "not_same_branch"
266 if defined C4
::Context
->userenv
267 and !C4
::Context
->IsSuperLibrarian()
268 and C4
::Context
->preference("IndependentBranches")
269 and ( C4
::Context
->userenv->{branch
} ne $self->homebranch );
271 # check it doesn't have a waiting reserve
272 return "book_reserved"
273 if $self->holds->search( { found
=> [ 'W', 'T' ] } )->count;
275 return "linked_analytics"
276 if C4
::Items
::GetAnalyticsCount
( $self->itemnumber ) > 0;
278 return "last_item_for_hold"
279 if $self->biblio->items->count == 1
280 && $self->biblio->holds->search(
289 =head3 move_to_deleted
291 my $is_moved = $item->move_to_deleted;
293 Move an item to the deleteditems table.
294 This can be done before deleting an item, to make sure the data are not completely deleted.
298 sub move_to_deleted
{
300 my $item_infos = $self->unblessed;
301 delete $item_infos->{timestamp
}; #This ensures the timestamp date in deleteditems will be set to the current timestamp
302 return Koha
::Database
->new->schema->resultset('Deleteditem')->create($item_infos);
306 =head3 effective_itemtype
308 Returns the itemtype for the item based on whether item level itemtypes are set or not.
312 sub effective_itemtype
{
315 return $self->_result()->effective_itemtype();
325 $self->{_home_branch
} ||= Koha
::Libraries
->find( $self->homebranch() );
327 return $self->{_home_branch
};
330 =head3 holding_branch
337 $self->{_holding_branch
} ||= Koha
::Libraries
->find( $self->holdingbranch() );
339 return $self->{_holding_branch
};
344 my $biblio = $item->biblio;
346 Return the bibliographic record of this item
352 my $biblio_rs = $self->_result->biblio;
353 return Koha
::Biblio
->_new_from_dbic( $biblio_rs );
358 my $biblioitem = $item->biblioitem;
360 Return the biblioitem record of this item
366 my $biblioitem_rs = $self->_result->biblioitem;
367 return Koha
::Biblioitem
->_new_from_dbic( $biblioitem_rs );
372 my $checkout = $item->checkout;
374 Return the checkout for this item
380 my $checkout_rs = $self->_result->issue;
381 return unless $checkout_rs;
382 return Koha
::Checkout
->_new_from_dbic( $checkout_rs );
387 my $holds = $item->holds();
388 my $holds = $item->holds($params);
389 my $holds = $item->holds({ found => 'W'});
391 Return holds attached to an item, optionally accept a hashref of params to pass to search
396 my ( $self,$params ) = @_;
397 my $holds_rs = $self->_result->reserves->search($params);
398 return Koha
::Holds
->_new_from_dbic( $holds_rs );
403 my $transfer = $item->get_transfer;
405 Return the transfer if the item is in transit or undef
411 my $transfer_rs = $self->_result->branchtransfers->search({ datearrived
=> undef })->first;
412 return unless $transfer_rs;
413 return Koha
::Item
::Transfer
->_new_from_dbic( $transfer_rs );
416 =head3 last_returned_by
418 Gets and sets the last borrower to return an item.
420 Accepts and returns Koha::Patron objects
422 $item->last_returned_by( $borrowernumber );
424 $last_returned_by = $item->last_returned_by();
428 sub last_returned_by
{
429 my ( $self, $borrower ) = @_;
431 my $items_last_returned_by_rs = Koha
::Database
->new()->schema()->resultset('ItemsLastBorrower');
434 return $items_last_returned_by_rs->update_or_create(
435 { borrowernumber
=> $borrower->borrowernumber, itemnumber
=> $self->id } );
438 unless ( $self->{_last_returned_by
} ) {
439 my $result = $items_last_returned_by_rs->single( { itemnumber
=> $self->id } );
441 $self->{_last_returned_by
} = Koha
::Patrons
->find( $result->get_column('borrowernumber') );
445 return $self->{_last_returned_by
};
449 =head3 can_article_request
451 my $bool = $item->can_article_request( $borrower )
453 Returns true if item can be specifically requested
455 $borrower must be a Koha::Patron object
459 sub can_article_request
{
460 my ( $self, $borrower ) = @_;
462 my $rule = $self->article_request_type($borrower);
464 return 1 if $rule && $rule ne 'no' && $rule ne 'bib_only';
468 =head3 hidden_in_opac
470 my $bool = $item->hidden_in_opac({ [ rules => $rules ] })
472 Returns true if item fields match the hidding criteria defined in $rules.
473 Returns false otherwise.
475 Takes HASHref that can have the following parameters:
477 $rules : { <field> => [ value_1, ... ], ... }
479 Note: $rules inherits its structure from the parsed YAML from reading
480 the I<OpacHiddenItems> system preference.
485 my ( $self, $params ) = @_;
487 my $rules = $params->{rules
} // {};
490 if C4
::Context
->preference('hidelostitems') and
493 my $hidden_in_opac = 0;
495 foreach my $field ( keys %{$rules} ) {
497 if ( any
{ $self->$field eq $_ } @
{ $rules->{$field} } ) {
503 return $hidden_in_opac;
506 =head3 can_be_transferred
508 $item->can_be_transferred({ to => $to_library, from => $from_library })
509 Checks if an item can be transferred to given library.
511 This feature is controlled by two system preferences:
512 UseBranchTransferLimits to enable / disable the feature
513 BranchTransferLimitsType to use either an itemnumber or ccode as an identifier
514 for setting the limitations
516 Takes HASHref that can have the following parameters:
517 MANDATORY PARAMETERS:
520 $from : Koha::Library # if not given, item holdingbranch
521 # will be used instead
523 Returns 1 if item can be transferred to $to_library, otherwise 0.
525 To find out whether at least one item of a Koha::Biblio can be transferred, please
526 see Koha::Biblio->can_be_transferred() instead of using this method for
527 multiple items of the same biblio.
531 sub can_be_transferred
{
532 my ($self, $params) = @_;
534 my $to = $params->{to
};
535 my $from = $params->{from
};
537 $to = $to->branchcode;
538 $from = defined $from ?
$from->branchcode : $self->holdingbranch;
540 return 1 if $from eq $to; # Transfer to current branch is allowed
541 return 1 unless C4
::Context
->preference('UseBranchTransferLimits');
543 my $limittype = C4
::Context
->preference('BranchTransferLimitsType');
544 return Koha
::Item
::Transfer
::Limits
->search({
547 $limittype => $limittype eq 'itemtype'
548 ?
$self->effective_itemtype : $self->ccode
552 =head3 pickup_locations
554 $pickup_locations = $item->pickup_locations( {patron => $patron } )
556 Returns possible pickup locations for this item, according to patron's home library (if patron is defined and holds are allowed only from hold groups)
557 and if item can be transferred to each pickup location.
561 sub pickup_locations
{
562 my ($self, $params) = @_;
564 my $patron = $params->{patron
};
566 my $circ_control_branch =
567 C4
::Reserves
::GetReservesControlBranch
( $self->unblessed(), $patron->unblessed );
569 C4
::Circulation
::GetBranchItemRule
( $circ_control_branch, $self->itype );
572 if(defined $patron) {
573 return \
@libs if $branchitemrule->{holdallowed
} == 3 && !$self->home_branch->validate_hold_sibling( {branchcode
=> $patron->branchcode} );
574 return \
@libs if $branchitemrule->{holdallowed
} == 1 && $self->home_branch->branchcode ne $patron->branchcode;
577 if ($branchitemrule->{hold_fulfillment_policy
} eq 'holdgroup') {
578 @libs = $self->home_branch->get_hold_libraries;
579 push @libs, $self->home_branch unless scalar(@libs) > 0;
580 } elsif ($branchitemrule->{hold_fulfillment_policy
} eq 'patrongroup') {
581 my $plib = Koha
::Libraries
->find({ branchcode
=> $patron->branchcode});
582 @libs = $plib->get_hold_libraries;
583 push @libs, $self->home_branch unless scalar(@libs) > 0;
584 } elsif ($branchitemrule->{hold_fulfillment_policy
} eq 'homebranch') {
585 push @libs, $self->home_branch;
586 } elsif ($branchitemrule->{hold_fulfillment_policy
} eq 'holdingbranch') {
587 push @libs, $self->holding_branch;
589 @libs = Koha
::Libraries
->search({
592 order_by
=> ['branchname']
596 my @pickup_locations;
597 foreach my $library (@libs) {
598 if ($library->pickup_location && $self->can_be_transferred({ to
=> $library })) {
599 push @pickup_locations, $library;
603 return \
@pickup_locations;
606 =head3 article_request_type
608 my $type = $item->article_request_type( $borrower )
610 returns 'yes', 'no', 'bib_only', or 'item_only'
612 $borrower must be a Koha::Patron object
616 sub article_request_type
{
617 my ( $self, $borrower ) = @_;
619 my $branch_control = C4
::Context
->preference('HomeOrHoldingBranch');
621 $branch_control eq 'homebranch' ?
$self->homebranch
622 : $branch_control eq 'holdingbranch' ?
$self->holdingbranch
624 my $borrowertype = $borrower->categorycode;
625 my $itemtype = $self->effective_itemtype();
626 my $rule = Koha
::CirculationRules
->get_effective_rule(
628 rule_name
=> 'article_requests',
629 categorycode
=> $borrowertype,
630 itemtype
=> $itemtype,
631 branchcode
=> $branchcode
635 return q{} unless $rule;
636 return $rule->rule_value || q{}
645 my $attributes = { order_by
=> 'priority' };
646 my $dtf = Koha
::Database
->new->schema->storage->datetime_parser;
648 itemnumber
=> $self->itemnumber,
651 reservedate
=> { '<=' => $dtf->format_date(dt_from_string
) },
652 waitingdate
=> { '!=' => undef },
655 my $hold_rs = $self->_result->reserves->search( $params, $attributes );
656 return Koha
::Holds
->_new_from_dbic($hold_rs);
659 =head3 stockrotationitem
661 my $sritem = Koha::Item->stockrotationitem;
663 Returns the stock rotation item associated with the current item.
667 sub stockrotationitem
{
669 my $rs = $self->_result->stockrotationitem;
671 return Koha
::StockRotationItem
->_new_from_dbic( $rs );
676 my $item = $item->add_to_rota($rota_id);
678 Add this item to the rota identified by $ROTA_ID, which means associating it
679 with the first stage of that rota. Should this item already be associated
680 with a rota, then we will move it to the new rota.
685 my ( $self, $rota_id ) = @_;
686 Koha
::StockRotationRotas
->find($rota_id)->add_item($self->itemnumber);
690 =head3 has_pending_hold
692 my $is_pending_hold = $item->has_pending_hold();
694 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
698 sub has_pending_hold
{
700 my $pending_hold = $self->_result->tmp_holdsqueues;
701 return $pending_hold->count ?
1: 0;
706 my $mss = C4::Biblio::GetMarcSubfieldStructure( '', { unsafe => 1 } );
707 my $field = $item->as_marc_field({ [ mss => $mss ] });
709 This method returns a MARC::Field object representing the Koha::Item object
710 with the current mappings configuration.
715 my ( $self, $params ) = @_;
717 my $mss = $params->{mss
} // C4
::Biblio
::GetMarcSubfieldStructure
( '', { unsafe
=> 1 } );
718 my $item_tag = $mss->{'items.itemnumber'}[0]->{tagfield
};
722 my @columns = $self->_result->result_source->columns;
724 foreach my $item_field ( @columns ) {
725 my $mapping = $mss->{ "items.$item_field"}[0];
726 my $tagfield = $mapping->{tagfield
};
727 my $tagsubfield = $mapping->{tagsubfield
};
728 next if !$tagfield; # TODO: Should we raise an exception instead?
729 # Feels like safe fallback is better
731 push @subfields, $tagsubfield => $self->$item_field
732 if defined $self->$item_field and $item_field ne '';
735 my $unlinked_item_subfields = C4
::Items
::_parse_unlinked_item_subfields_from_xml
($self->more_subfields_xml);
736 push( @subfields, @
{$unlinked_item_subfields} )
737 if defined $unlinked_item_subfields and $#$unlinked_item_subfields > -1;
741 $field = MARC
::Field
->new(
742 "$item_tag", ' ', ' ', @subfields
748 =head3 renewal_branchcode
750 Returns the branchcode to be recorded in statistics renewal of the item
754 sub renewal_branchcode
{
756 my ($self, $params ) = @_;
758 my $interface = C4
::Context
->interface;
760 if ( $interface eq 'opac' ){
761 my $renewal_branchcode = C4
::Context
->preference('OpacRenewalBranch');
762 if( !defined $renewal_branchcode || $renewal_branchcode eq 'opacrenew' ){
763 $branchcode = 'OPACRenew';
765 elsif ( $renewal_branchcode eq 'itemhomebranch' ) {
766 $branchcode = $self->homebranch;
768 elsif ( $renewal_branchcode eq 'patronhomebranch' ) {
769 $branchcode = $self->checkout->patron->branchcode;
771 elsif ( $renewal_branchcode eq 'checkoutbranch' ) {
772 $branchcode = $self->checkout->branchcode;
778 $branchcode = ( C4
::Context
->userenv && defined C4
::Context
->userenv->{branch
} )
779 ? C4
::Context
->userenv->{branch
} : $params->{branch
};
784 =head3 _set_found_trigger
786 $self->_set_found_trigger
788 Finds the most recent lost item charge for this item and refunds the patron
789 appropriately, taking into account any payments or writeoffs already applied
792 Internal function, not exported, called only by Koha::Item->store.
796 sub _set_found_trigger
{
797 my ( $self, $pre_mod_item ) = @_;
799 ## If item was lost, it has now been found, reverse any list item charges if necessary.
800 my $no_refund_after_days =
801 C4
::Context
->preference('NoRefundOnLostReturnedItemsAge');
802 if ($no_refund_after_days) {
803 my $today = dt_from_string
();
804 my $lost_age_in_days =
805 dt_from_string
( $pre_mod_item->itemlost_on )->delta_days($today)
808 return $self unless $lost_age_in_days < $no_refund_after_days;
812 unless Koha
::CirculationRules
->get_lostreturn_policy(
815 return_branch
=> C4
::Context
->userenv
816 ? C4
::Context
->userenv->{'branch'}
821 # check for charge made for lost book
822 my $accountlines = Koha
::Account
::Lines
->search(
824 itemnumber
=> $self->itemnumber,
825 debit_type_code
=> 'LOST',
826 status
=> [ undef, { '<>' => 'FOUND' } ]
829 order_by
=> { -desc
=> [ 'date', 'accountlines_id' ] }
833 return $self unless $accountlines->count > 0;
835 my $accountline = $accountlines->next;
836 my $total_to_refund = 0;
838 return $self unless $accountline->borrowernumber;
840 my $patron = Koha
::Patrons
->find( $accountline->borrowernumber );
842 unless $patron; # Patron has been deleted, nobody to credit the return to
843 # FIXME Should not we notify this somewhere
845 my $account = $patron->account;
848 if ( $accountline->amount > $accountline->amountoutstanding ) {
850 # some amount has been cancelled. collect the offsets that are not writeoffs
851 # this works because the only way to subtract from this kind of a debt is
852 # using the UI buttons 'Pay' and 'Write off'
853 my $credits_offsets = Koha
::Account
::Offsets
->search(
855 debit_id
=> $accountline->id,
856 credit_id
=> { '!=' => undef }, # it is not the debit itself
857 type
=> { '!=' => 'Writeoff' },
858 amount
=> { '<' => 0 } # credits are negative on the DB
862 $total_to_refund = ( $credits_offsets->count > 0 )
863 ?
$credits_offsets->total * -1 # credits are negative on the DB
867 my $credit_total = $accountline->amountoutstanding + $total_to_refund;
870 if ( $credit_total > 0 ) {
872 C4
::Context
->userenv ? C4
::Context
->userenv->{'branch'} : undef;
873 $credit = $account->add_credit(
875 amount
=> $credit_total,
876 description
=> 'Item found ' . $self->itemnumber,
877 type
=> 'LOST_FOUND',
878 interface
=> C4
::Context
->interface,
879 library_id
=> $branchcode,
880 item_id
=> $self->itemnumber,
881 issue_id
=> $accountline->issue_id
885 $credit->apply( { debits
=> [$accountline] } );
886 $self->{_refunded
} = 1;
889 # Update the account status
890 $accountline->status('FOUND');
891 $accountline->store();
893 if ( defined $account and C4
::Context
->preference('AccountAutoReconcile') ) {
894 $account->reconcile_balance;
900 =head3 to_api_mapping
902 This method returns the mapping for representing a Koha::Item object
909 itemnumber
=> 'item_id',
910 biblionumber
=> 'biblio_id',
911 biblioitemnumber
=> undef,
912 barcode
=> 'external_id',
913 dateaccessioned
=> 'acquisition_date',
914 booksellerid
=> 'acquisition_source',
915 homebranch
=> 'home_library_id',
916 price
=> 'purchase_price',
917 replacementprice
=> 'replacement_price',
918 replacementpricedate
=> 'replacement_price_date',
919 datelastborrowed
=> 'last_checkout_date',
920 datelastseen
=> 'last_seen_date',
922 notforloan
=> 'not_for_loan_status',
923 damaged
=> 'damaged_status',
924 damaged_on
=> 'damaged_date',
925 itemlost
=> 'lost_status',
926 itemlost_on
=> 'lost_date',
927 withdrawn
=> 'withdrawn',
928 withdrawn_on
=> 'withdrawn_date',
929 itemcallnumber
=> 'callnumber',
930 coded_location_qualifier
=> 'coded_location_qualifier',
931 issues
=> 'checkouts_count',
932 renewals
=> 'renewals_count',
933 reserves
=> 'holds_count',
934 restricted
=> 'restricted_status',
935 itemnotes
=> 'public_notes',
936 itemnotes_nonpublic
=> 'internal_notes',
937 holdingbranch
=> 'holding_library_id',
939 timestamp
=> 'timestamp',
940 location
=> 'location',
941 permanent_location
=> 'permanent_location',
942 onloan
=> 'checked_out_date',
943 cn_source
=> 'call_number_source',
944 cn_sort
=> 'call_number_sort',
945 ccode
=> 'collection_code',
946 materials
=> 'materials_notes',
948 itype
=> 'item_type',
949 more_subfields_xml
=> 'extended_subfields',
950 enumchron
=> 'serial_issue_number',
951 copynumber
=> 'copy_number',
952 stocknumber
=> 'inventory_number',
953 new_status
=> 'new_status'
959 my $itemtype = $item->itemtype;
961 Returns Koha object for effective itemtype
967 return Koha
::ItemTypes
->find( $self->effective_itemtype );
970 =head2 Internal methods
972 =head3 _after_item_action_hooks
974 Helper method that takes care of calling all plugin hooks
978 sub _after_item_action_hooks
{
979 my ( $self, $params ) = @_;
981 my $action = $params->{action
};
988 item_id
=> $self->itemnumber,
1003 Kyle M Hall <kyle@bywatersolutions.com>