require C4::Reserves;
use C4::Charset;
use C4::Acquisition;
+use List::MoreUtils qw/any/;
+use Data::Dumper; # used as part of logging item record changes, not just for
+ # debugging; so please don't remove this
use vars qw($VERSION @ISA @EXPORT);
GetItemsByBiblioitemnumber
GetItemsInfo
GetItemsLocationInfo
+ GetHostItemsInfo
get_itemnumbers_of
+ get_hostitemnumbers_of
GetItemnumberFromBarcode
GetBarcodeFromItemnumber
-
+ GetHiddenItemnumbers
DelItemCheck
MoveItemFromBiblio
GetLatestAcquisitions
CartToShelf
+
+ GetAnalyticsCount
+ GetItemHolds
);
}
my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} );
$item->{'itemnumber'} = $itemnumber;
- # create MARC tag representing item and add to bib
- my $new_item_marc = _marc_from_item_hash($item, $frameworkcode, $unlinked_item_subfields);
- _add_item_field_to_biblio($new_item_marc, $item->{'biblionumber'}, $frameworkcode );
+ ModZebra( $item->{biblionumber}, "specialUpdate", "biblioserver", undef, undef );
logaction("CATALOGUING", "ADD", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
}
# update the MARC biblio
- $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode );
+ # $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode );
return (\@itemnumbers, \@errors);
}
changed from the cataloging and serials
item editors are included in this hash.
+Returns item record
+
=cut
my %default_values_for_mod_from_marc = (
itemnotes => undef,
itype => undef,
location => undef,
+ permanent_location => undef,
materials => undef,
notforloan => 0,
paidfor => undef,
}
my $unlinked_item_subfields = _get_unlinked_item_subfields( $localitemmarc, $frameworkcode );
- return ModItem($item, $biblionumber, $itemnumber, $dbh, $frameworkcode, $unlinked_item_subfields);
+ ModItem($item, $biblionumber, $itemnumber, $dbh, $frameworkcode, $unlinked_item_subfields);
+ return $item;
}
=head2 ModItem
};
$item->{'itemnumber'} = $itemnumber or return undef;
+
+ $item->{onloan} = undef if $item->{itemlost};
+
_set_derived_columns_for_mod($item);
_do_column_fixes_for_mod($item);
# FIXME add checks
# update items table
_koha_modify_item($item);
- # update biblio MARC XML
- my $whole_item = GetItem($itemnumber) or die "FAILED GetItem($itemnumber)";
+ # request that bib be reindexed so that searching on current
+ # item status is possible
+ ModZebra( $biblionumber, "specialUpdate", "biblioserver", undef, undef );
- unless (defined $unlinked_item_subfields) {
- $unlinked_item_subfields = _parse_unlinked_item_subfields_from_xml($whole_item->{'more_subfields_xml'});
- }
- my $new_item_marc = _marc_from_item_hash($whole_item, $frameworkcode, $unlinked_item_subfields)
- or die "FAILED _marc_from_item_hash($whole_item, $frameworkcode)";
-
- _replace_item_field_in_biblio($new_item_marc, $biblionumber, $itemnumber, $frameworkcode);
- ($new_item_marc eq '0') and die "$new_item_marc is '0', not hashref"; # logaction line would crash anyway
- logaction("CATALOGUING", "MODIFY", $itemnumber, $new_item_marc->as_formatted) if C4::Context->preference("CataloguingLog");
+ logaction("CATALOGUING", "MODIFY", $itemnumber, Dumper($item)) if C4::Context->preference("CataloguingLog");
}
=head2 ModItemTransfer
# get the MARC record
my $record = GetMarcBiblio($biblionumber);
- my $frameworkcode = GetFrameworkCode($biblionumber);
+ ModZebra( $biblionumber, "specialUpdate", "biblioserver", undef, undef );
# backup the record
my $copy2deleted = $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
$copy2deleted->execute( $record->as_usmarc(), $itemnumber );
+ # This last update statement makes that the timestamp column in deleteditems is updated too. If you remove these lines, please add a line to update the timestamp separately. See Bugzilla report 7146 and Biblio.pm (DelBiblio).
#search item field code
- my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
- my @fields = $record->field($itemtag);
-
- # delete the item specified
- foreach my $field (@fields) {
- if ( $field->subfield($itemsubfield) eq $itemnumber ) {
- $record->delete_field($field);
- }
- }
- &ModBiblioMarc( $record, $biblionumber, $frameworkcode );
logaction("CATALOGUING", "DELETE", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
}
=head2 GetItemsInfo
- @results = GetItemsInfo($biblionumber, $type);
-
-Returns information about books with the given biblionumber.
+ @results = GetItemsInfo($biblionumber);
-C<$type> may be either C<intra> or anything else. If it is not set to
-C<intra>, then the search will exclude lost, very overdue, and
-withdrawn items.
+Returns information about items with the given biblionumber.
C<GetItemsInfo> returns a list of references-to-hash. Each element
-contains a number of keys. Most of them are table items from the
+contains a number of keys. Most of them are attributes from the
C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
Koha database. Other keys include:
=cut
sub GetItemsInfo {
- my ( $biblionumber, $type ) = @_;
+ my ( $biblionumber ) = @_;
my $dbh = C4::Context->dbh;
# note biblioitems.* must be avoided to prevent large marc and marcxml fields from killing performance.
my $query = "
itemtypes.notforloan as notforloan_per_itemtype,
branchurl
FROM items
- LEFT JOIN branches ON items.homebranch = branches.branchcode
+ LEFT JOIN branches ON items.holdingbranch = branches.branchcode
LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
LEFT JOIN itemtypes ON itemtypes.itemtype = "
$data->{cardnumber} = $idata->{cardnumber};
$data->{surname} = $idata->{surname};
$data->{firstname} = $idata->{firstname};
+ $data->{lastreneweddate} = $idata->{lastreneweddate};
$datedue = $idata->{'date_due'};
if (C4::Context->preference("IndependantBranches")){
my $userenv = C4::Context->userenv;
return @results;
}
+=head2 GetHostItemsInfo
+
+ $hostiteminfo = GetHostItemsInfo($hostfield);
+ Returns the iteminfo for items linked to records via a host field
+
+=cut
+
+sub GetHostItemsInfo {
+ my ($record) = @_;
+ my @returnitemsInfo;
+
+ if (C4::Context->preference('marcflavour') eq 'MARC21' ||
+ C4::Context->preference('marcflavour') eq 'NORMARC'){
+ foreach my $hostfield ( $record->field('773') ) {
+ my $hostbiblionumber = $hostfield->subfield("0");
+ my $linkeditemnumber = $hostfield->subfield("9");
+ my @hostitemInfos = GetItemsInfo($hostbiblionumber);
+ foreach my $hostitemInfo (@hostitemInfos){
+ if ($hostitemInfo->{itemnumber} eq $linkeditemnumber){
+ push (@returnitemsInfo,$hostitemInfo);
+ last;
+ }
+ }
+ }
+ } elsif ( C4::Context->preference('marcflavour') eq 'UNIMARC'){
+ foreach my $hostfield ( $record->field('461') ) {
+ my $hostbiblionumber = $hostfield->subfield("0");
+ my $linkeditemnumber = $hostfield->subfield("9");
+ my @hostitemInfos = GetItemsInfo($hostbiblionumber);
+ foreach my $hostitemInfo (@hostitemInfos){
+ if ($hostitemInfo->{itemnumber} eq $linkeditemnumber){
+ push (@returnitemsInfo,$hostitemInfo);
+ last;
+ }
+ }
+ }
+ }
+ return @returnitemsInfo;
+}
+
=head2 GetLastAcquisitions
return \%itemnumbers_of;
}
+=head2 get_hostitemnumbers_of
+
+ my @itemnumbers_of = get_hostitemnumbers_of($biblionumber);
+
+Given a biblionumber, return the list of corresponding itemnumbers that are linked to it via host fields
+
+Return a reference on a hash where key is a biblionumber and values are
+references on array of itemnumbers.
+
+=cut
+
+
+sub get_hostitemnumbers_of {
+ my ($biblionumber) = @_;
+ my $marcrecord = GetMarcBiblio($biblionumber);
+ my (@returnhostitemnumbers,$tag, $biblio_s, $item_s);
+
+ my $marcflavor = C4::Context->preference('marcflavour');
+ if ($marcflavor eq 'MARC21' || $marcflavor eq 'NORMARC') {
+ $tag='773';
+ $biblio_s='0';
+ $item_s='9';
+ } elsif ($marcflavor eq 'UNIMARC') {
+ $tag='461';
+ $biblio_s='0';
+ $item_s='9';
+ }
+
+ foreach my $hostfield ( $marcrecord->field($tag) ) {
+ my $hostbiblionumber = $hostfield->subfield($biblio_s);
+ my $linkeditemnumber = $hostfield->subfield($item_s);
+ my @itemnumbers;
+ if (my $itemnumbers = get_itemnumbers_of($hostbiblionumber)->{$hostbiblionumber})
+ {
+ @itemnumbers = @$itemnumbers;
+ }
+ foreach my $itemnumber (@itemnumbers){
+ if ($itemnumber eq $linkeditemnumber){
+ push (@returnhostitemnumbers,$itemnumber);
+ last;
+ }
+ }
+ }
+ return @returnhostitemnumbers;
+}
+
+
=head2 GetItemnumberFromBarcode
$result = GetItemnumberFromBarcode($barcode);
return ($result);
}
+=head2 GetHiddenItemnumbers
+
+=over 4
+
+$result = GetHiddenItemnumbers(@items);
+
+=back
+
+=cut
+
+sub GetHiddenItemnumbers {
+ my (@items) = @_;
+ my @resultitems;
+
+ my $yaml = C4::Context->preference('OpacHiddenItems');
+ my $hidingrules;
+ eval {
+ $hidingrules = YAML::Load($yaml);
+ };
+ if ($@) {
+ warn "Unable to parse OpacHiddenItems syspref : $@";
+ return ();
+ } else {
+ my $dbh = C4::Context->dbh;
+
+ # For each item
+ foreach my $item (@items) {
+
+ # We check each rule
+ foreach my $field (keys %$hidingrules) {
+ my $query = "SELECT $field from items where itemnumber = ?";
+ my $sth = $dbh->prepare($query);
+ $sth->execute($item->{'itemnumber'});
+ my ($result) = $sth->fetchrow;
+
+ # If the results matches the values in the yaml file
+ if (any { $result eq $_ } @{$hidingrules->{$field}}) {
+
+ # We add the itemnumber to the list
+ push @resultitems, $item->{'itemnumber'};
+
+ # If at least one rule matched for an item, no need to test the others
+ last;
+ }
+ }
+ }
+ return @resultitems;
+ }
+
+ }
+
=head3 get_item_authorised_values
find the types and values for all authorised values assigned to this item.
homebranch = ?,
price = ?,
replacementprice = ?,
- replacementpricedate = NOW(),
+ replacementpricedate = ?,
datelastborrowed = ?,
- datelastseen = NOW(),
+ datelastseen = ?,
stack = ?,
notforloan = ?,
damaged = ?,
holdingbranch = ?,
paidfor = ?,
location = ?,
+ permanent_location = ?,
onloan = ?,
issues = ?,
renewals = ?,
stocknumber = ?
";
my $sth = $dbh->prepare($query);
+ my $today = C4::Dates->today('iso');
$sth->execute(
$item->{'biblionumber'},
$item->{'biblioitemnumber'},
$item->{'homebranch'},
$item->{'price'},
$item->{'replacementprice'},
+ $item->{'replacementpricedate'} || $today,
$item->{datelastborrowed},
+ $item->{datelastseen} || $today,
$item->{stack},
$item->{'notforloan'},
$item->{'damaged'},
$item->{'holdingbranch'},
$item->{'paidfor'},
$item->{'location'},
+ $item->{'permanent_location'},
$item->{'onloan'},
$item->{'issues'},
$item->{'renewals'},
$item->{'copynumber'},
$item->{'stocknumber'},
);
- my $itemnumber = $dbh->{'mysql_insertid'};
+
+ my $itemnumber;
if ( defined $sth->errstr ) {
$error.="ERROR in _koha_new_item $query".$sth->errstr;
}
+ else {
+ $itemnumber = $dbh->{'mysql_insertid'};
+ }
+
return ( $itemnumber, $error );
}
$sth = $dbh->prepare("UPDATE items SET biblioitemnumber = ?, biblionumber = ? WHERE itemnumber = ? AND biblionumber = ?");
my $return = $sth->execute($tobiblioitem, $tobiblio, $itemnumber, $frombiblio);
if ($return == 1) {
-
- # Getting framework
- my $frameworkcode = GetFrameworkCode($frombiblio);
-
- # Getting marc field for itemnumber
- my ($itemtag, $itemsubfield) = GetMarcFromKohaField('items.itemnumber', $frameworkcode);
-
- # Getting the record we want to move the item from
- my $record = GetMarcBiblio($frombiblio);
-
- # The item we want to move
- my $item;
-
- # For each item
- foreach my $fielditem ($record->field($itemtag)){
- # If it is the item we want to move
- if ($fielditem->subfield($itemsubfield) == $itemnumber) {
- # We save it
- $item = $fielditem;
- # Then delete it from the record
- $record->delete_field($fielditem)
- }
- }
-
- # If we found an item (should always true, except in case of database-marcxml inconsistency)
- if ($item) {
-
+ ModZebra( $tobiblio, "specialUpdate", "biblioserver", undef, undef );
+ ModZebra( $frombiblio, "specialUpdate", "biblioserver", undef, undef );
# Checking if the item we want to move is in an order
- my $order = GetOrderFromItemnumber($itemnumber);
+ my $order = GetOrderFromItemnumber($itemnumber);
if ($order) {
- # Replacing the biblionumber within the order if necessary
- $order->{'biblionumber'} = $tobiblio;
+ # Replacing the biblionumber within the order if necessary
+ $order->{'biblionumber'} = $tobiblio;
ModOrder($order);
}
-
- # Saving the modification
- ModBiblioMarc($record, $frombiblio, $frameworkcode);
-
- # Getting the record we want to move the item to
- $record = GetMarcBiblio($tobiblio);
-
- # Inserting the previously saved item
- $record->insert_fields_ordered($item);
-
- # Saving the modification
- ModBiblioMarc($record, $tobiblio, $frameworkcode);
-
- } else {
- return undef;
+ return $tobiblio;
}
- } else {
- return undef;
- }
+ return;
}
=head2 DelItemCheck
my ( $dbh, $biblionumber, $itemnumber ) = @_;
my $error;
+ my $countanalytics=GetAnalyticsCount($itemnumber);
+
+
# check that there is no issue on this item before deletion.
my $sth=$dbh->prepare("select * from issues i where i.itemnumber=?");
$sth->execute($itemnumber);
my $item = GetItem($itemnumber);
- my $onloan = $sth->fetchrow;
- if ($onloan) {
- $error = "book_on_loan";
+ my $onloan=$sth->fetchrow;
+
+ if ($onloan){
+ $error = "book_on_loan"
}
- elsif (C4::Context->preference("IndependantBranches") and (C4::Context->userenv->{branch} ne $item->{C4::Context->preference("HomeOrHoldingBranch")||'homebranch'})){
+ elsif ( C4::Context->userenv->{flags} & 1 and
+ C4::Context->preference("IndependantBranches") and
+ (C4::Context->userenv->{branch} ne
+ $item->{C4::Context->preference("HomeOrHoldingBranch")||'homebranch'}) )
+ {
$error = "not_same_branch";
- }
- else {
- if ($onloan){
- $error = "book_on_loan"
- }
- else {
- # check it doesnt have a waiting reserve
- $sth=$dbh->prepare("SELECT * FROM reserves WHERE (found = 'W' or found = 'T') AND itemnumber = ?");
- $sth->execute($itemnumber);
- my $reserve=$sth->fetchrow;
- if ($reserve) {
- $error = "book_reserved";
- }
- else {
- DelItem($dbh, $biblionumber, $itemnumber);
- return 1;
- }
- }
+ }
+ else{
+ # check it doesnt have a waiting reserve
+ $sth=$dbh->prepare("SELECT * FROM reserves WHERE (found = 'W' or found = 'T') AND itemnumber = ?");
+ $sth->execute($itemnumber);
+ my $reserve=$sth->fetchrow;
+ if ($reserve){
+ $error = "book_reserved";
+ } elsif ($countanalytics > 0){
+ $error = "linked_analytics";
+ } else {
+ DelItem($dbh, $biblionumber, $itemnumber);
+ return 1;
+ }
}
return $error;
}
return $item_marc;
}
-=head2 _add_item_field_to_biblio
-
- _add_item_field_to_biblio($item_marc, $biblionumber, $frameworkcode);
-
-Adds the fields from a MARC record containing the
-representation of a Koha item record to the MARC
-biblio record. The input C<$item_marc> record
-is expect to contain just one field, the embedded
-item information field.
-
-=cut
-
-sub _add_item_field_to_biblio {
- my ($item_marc, $biblionumber, $frameworkcode) = @_;
-
- my $biblio_marc = GetMarcBiblio($biblionumber);
- foreach my $field ($item_marc->fields()) {
- $biblio_marc->append_fields($field);
- }
-
- ModBiblioMarc($biblio_marc, $biblionumber, $frameworkcode);
-}
-
-=head2 _replace_item_field_in_biblio
-
- &_replace_item_field_in_biblio($item_marc, $biblionumber, $itemnumber, $frameworkcode)
-
-Given a MARC::Record C<$item_marc> containing one tag with the MARC
-representation of the item, examine the biblio MARC
-for the corresponding tag for that item and
-replace it with the tag from C<$item_marc>.
-
-=cut
-
-sub _replace_item_field_in_biblio {
- my ($ItemRecord, $biblionumber, $itemnumber, $frameworkcode) = @_;
- my $dbh = C4::Context->dbh;
-
- # get complete MARC record & replace the item field by the new one
- my $completeRecord = GetMarcBiblio($biblionumber);
- my ($itemtag,$itemsubfield) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
- my $itemField = $ItemRecord->field($itemtag);
- my @items = $completeRecord->field($itemtag);
- my $found = 0;
- foreach (@items) {
- if ($_->subfield($itemsubfield) eq $itemnumber) {
- $_->replace_with($itemField);
- $found = 1;
- }
- }
-
- unless ($found) {
- # If we haven't found the matching field,
- # just add it. However, this means that
- # there is likely a bug.
- $completeRecord->append_fields($itemField);
- }
-
- # save the record
- ModBiblioMarc($completeRecord, $biblionumber, $frameworkcode);
-}
-
=head2 _repack_item_errors
Add an error message hash generated by C<CheckItemPreSave>
return $unlinked_subfields;
}
+=head2 GetAnalyticsCount
+
+ $count= &GetAnalyticsCount($itemnumber)
+
+counts Usage of itemnumber in Analytical bibliorecords.
+
+=cut
+
+sub GetAnalyticsCount {
+ my ($itemnumber) = @_;
+ if (C4::Context->preference('NoZebra')) {
+ # Read the index Koha-Auth-Number for this authid and count the lines
+ my $result = C4::Search::NZanalyse("hi=$itemnumber");
+ my @tab = split /;/,$result;
+ return scalar @tab;
+ } else {
+ ### ZOOM search here
+ my $query;
+ $query= "hi=".$itemnumber;
+ my ($err,$res,$result) = C4::Search::SimpleSearch($query,0,10);
+ return ($result);
+ }
+}
+
+=head2 GetItemHolds
+
+=over 4
+$holds = &GetItemHolds($biblionumber, $itemnumber);
+
+=back
+
+This function return the count of holds with $biblionumber and $itemnumber
+
+=cut
+
+sub GetItemHolds {
+ my ($biblionumber, $itemnumber) = @_;
+ my $holds;
+ my $dbh = C4::Context->dbh;
+ my $query = "SELECT count(*)
+ FROM reserves
+ WHERE biblionumber=? AND itemnumber=?";
+ my $sth = $dbh->prepare($query);
+ $sth->execute($biblionumber, $itemnumber);
+ $holds = $sth->fetchrow;
+ return $holds;
+}
1;