use Koha::Biblioitems;
use Koha::Items;
+use Koha::ItemTypes;
use Koha::SearchEngine;
use Koha::SearchEngine::Search;
use Koha::Libraries;
CheckItemPreSave
- GetItemStatus
GetItemLocation
GetLostItems
GetItemsForInventory
- GetItemsCount
GetItemInfosOf
GetItemsByBiblioitemnumber
GetItemsInfo
ShelfToCart
GetAnalyticsCount
- GetItemHolds
SearchItemsByField
SearchItems
records in Koha, and is used by cataloguing, circulation,
acquisitions, and serials management.
+# FIXME This POD is not up-to-date
A Koha item record is stored in two places: the
items table and embedded in a MARC tag in the XML
version of the associated bib record in C<biblioitems.marcxml>.
sub GetItem {
my ($itemnumber,$barcode, $serial) = @_;
my $dbh = C4::Context->dbh;
- my $data;
+ my $item;
if ($itemnumber) {
- my $sth = $dbh->prepare("
- SELECT * FROM items
- WHERE itemnumber = ?");
- $sth->execute($itemnumber);
- $data = $sth->fetchrow_hashref;
+ $item = Koha::Items->find( $itemnumber );
} else {
- my $sth = $dbh->prepare("
- SELECT * FROM items
- WHERE barcode = ?"
- );
- $sth->execute($barcode);
- $data = $sth->fetchrow_hashref;
- }
-
- return unless ( $data );
-
- if ( $serial) {
- my $ssth = $dbh->prepare("SELECT serialseq,publisheddate from serialitems left join serial on serialitems.serialid=serial.serialid where serialitems.itemnumber=?");
- $ssth->execute($data->{'itemnumber'}) ;
- ($data->{'serialseq'} , $data->{'publisheddate'}) = $ssth->fetchrow_array();
- }
- #if we don't have an items.itype, use biblioitems.itemtype.
- # FIXME this should respect the itypes systempreference
- # if (C4::Context->preference('item-level_itypes')) {
- if( ! $data->{'itype'} ) {
- my $sth = $dbh->prepare("SELECT itemtype FROM biblioitems WHERE biblionumber = ?");
- $sth->execute($data->{'biblionumber'});
- ($data->{'itype'}) = $sth->fetchrow_array;
- }
+ $item = Koha::Items->find( { barcode => $barcode } );
+ }
+
+ return unless ( $item );
+
+ my $data = $item->unblessed();
+ $data->{itype} = $item->effective_itemtype(); # set the correct itype
+
+ if ($serial) {
+ my $ssth = $dbh->prepare("SELECT serialseq,publisheddate from serialitems left join serial on serialitems.serialid=serial.serialid where serialitems.itemnumber=?");
+ $ssth->execute( $data->{'itemnumber'} );
+ ( $data->{'serialseq'}, $data->{'publisheddate'} ) = $ssth->fetchrow_array();
+ }
+
return $data;
} # sub GetItem
This API assumes that the bib record has already been
saved to the C<biblio> and C<biblioitems> tables. It does
-not expect that C<biblioitems.marcxml> are populated, but it
+not expect that C<biblio_metadata.metadata> is populated, but it
will do so via a call to ModBibiloMarc.
The goal of this API is to have a similar effect to using AddBiblio
# FIXME check the item has no current issues
my $deleted = _koha_delete_item( $itemnumber );
- # get the MARC record
- my $record = GetMarcBiblio($biblionumber);
ModZebra( $biblionumber, "specialUpdate", "biblioserver" );
#search item field code
=cut
-=head2 GetItemStatus
-
- $itemstatushash = GetItemStatus($fwkcode);
-
-Returns a list of valid values for the
-C<items.notforloan> field.
-
-NOTE: does B<not> return an individual item's
-status.
-
-Can be MARC dependent.
-fwkcode is optional.
-But basically could be can be loan or not
-Create a status selector with the following code
-
-=head3 in PERL SCRIPT
-
- my $itemstatushash = getitemstatus;
- my @itemstatusloop;
- foreach my $thisstatus (keys %$itemstatushash) {
- my %row =(value => $thisstatus,
- statusname => $itemstatushash->{$thisstatus}->{'statusname'},
- );
- push @itemstatusloop, \%row;
- }
- $template->param(statusloop=>\@itemstatusloop);
-
-=head3 in TEMPLATE
-
-<select name="statusloop" id="statusloop">
- <option value="">Default</option>
- [% FOREACH statusloo IN statusloop %]
- [% IF ( statusloo.selected ) %]
- <option value="[% statusloo.value %]" selected="selected">[% statusloo.statusname %]</option>
- [% ELSE %]
- <option value="[% statusloo.value %]">[% statusloo.statusname %]</option>
- [% END %]
- [% END %]
-</select>
-
-=cut
-
-sub GetItemStatus {
-
- # returns a reference to a hash of references to status...
- my ($fwk) = @_;
- my %itemstatus;
- my $dbh = C4::Context->dbh;
- my $sth;
- $fwk = '' unless ($fwk);
- my ( $tag, $subfield ) =
- GetMarcFromKohaField( "items.notforloan", $fwk );
- if ( $tag and $subfield ) {
- my $sth =
- $dbh->prepare(
- "SELECT authorised_value
- FROM marc_subfield_structure
- WHERE tagfield=?
- AND tagsubfield=?
- AND frameworkcode=?
- "
- );
- $sth->execute( $tag, $subfield, $fwk );
- if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
- my $authvalsth =
- $dbh->prepare(
- "SELECT authorised_value,lib
- FROM authorised_values
- WHERE category=?
- ORDER BY lib
- "
- );
- $authvalsth->execute($authorisedvaluecat);
- while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
- $itemstatus{$authorisedvalue} = $lib;
- }
- return \%itemstatus;
- }
- else {
-
- #No authvalue list
- # build default
- }
- }
-
- #No authvalue list
- #build default
- $itemstatus{"1"} = "Not For Loan";
- return \%itemstatus;
-}
-
=head2 GetItemLocation
$itemlochash = GetItemLocation($fwk);
offset => $offset,
size => $size,
statushash => $statushash,
- interface => $interface,
} );
Retrieve a list of title/authors/barcode/callnumber, for biblio inventory.
my $offset = $parameters->{'offset'} // '';
my $size = $parameters->{'size'} // '';
my $statushash = $parameters->{'statushash'} // '';
- my $interface = $parameters->{'interface'} // '';
my $dbh = C4::Context->dbh;
my ( @bind_params, @where_strings );
$sth->execute( @bind_params );
my ($iTotalRecords) = $sth->fetchrow_array();
- my $avmapping = C4::Koha::GetKohaAuthorisedValuesMapping( {
- interface => $interface
- } );
+ my @avs = Koha::AuthorisedValues->search(
+ { 'marc_subfield_structures.kohafield' => { '>' => '' },
+ 'me.authorised_value' => { '>' => '' },
+ },
+ { join => { category => 'marc_subfield_structures' },
+ distinct => ['marc_subfield_structures.kohafield, me.category, frameworkcode, me.authorised_value'],
+ '+select' => [ 'marc_subfield_structures.kohafield', 'marc_subfield_structures.frameworkcode', 'me.authorised_value', 'me.lib' ],
+ '+as' => [ 'kohafield', 'frameworkcode', 'authorised_value', 'lib' ],
+ }
+ );
+
+ my $avmapping = { map { $_->get_column('kohafield') . ',' . $_->get_column('frameworkcode') . ',' . $_->get_column('authorised_value') => $_->get_column('lib') } @avs };
+
foreach my $row (@$tmpresults) {
# Auth values
return (\@results, $iTotalRecords);
}
-=head2 GetItemsCount
-
- $count = &GetItemsCount( $biblionumber);
-
-This function return count of item with $biblionumber
-
-=cut
-
-sub GetItemsCount {
- my ( $biblionumber ) = @_;
- my $dbh = C4::Context->dbh;
- my $query = "SELECT count(*)
- FROM items
- WHERE biblionumber=?";
- my $sth = $dbh->prepare($query);
- $sth->execute($biblionumber);
- my $count = $sth->fetchrow;
- return ($count);
-}
-
=head2 GetItemInfosOf
GetItemInfosOf(@itemnumbers);
my $itemnumber_values = @itemnumbers ? join( ',', @itemnumbers ) : "''";
+ my $dbh = C4::Context->dbh;
my $query = "
SELECT *
FROM items
WHERE itemnumber IN ($itemnumber_values)
";
- return get_infos_of( $query, 'itemnumber' );
+ return $dbh->selectall_hashref($query, 'itemnumber');
}
=head2 GetItemsByBiblioitemnumber
sub GetItemsInfo {
my ( $biblionumber ) = @_;
my $dbh = C4::Context->dbh;
- # note biblioitems.* must be avoided to prevent large marc and marcxml fields from killing performance.
require C4::Languages;
my $language = C4::Languages::getlanguage();
my $query = "
$serial ||= $data->{'serial'};
- my $av;
+ my $descriptions;
# get notforloan complete status if applicable
- $av = Koha::AuthorisedValues->search_by_koha_field({frameworkcode => $data->{frameworkcode}, kohafield => 'items.notforloan', authorised_value => $data->{itemnotforloan} });
- $av = $av->count ? $av->next : undef;
- $data->{notforloanvalue} = $av ? $av->lib : '';
- $data->{notforloanvalueopac} = $av ? $av->opac_description : '';
+ $descriptions = Koha::AuthorisedValues->get_description_by_koha_field({frameworkcode => $data->{frameworkcode}, kohafield => 'items.notforloan', authorised_value => $data->{itemnotforloan} });
+ $data->{notforloanvalue} = $descriptions->{lib} // '';
+ $data->{notforloanvalueopac} = $descriptions->{opac_description} // '';
# get restricted status and description if applicable
- $av = Koha::AuthorisedValues->search_by_koha_field({frameworkcode => $data->{frameworkcode}, kohafield => 'items.restricted', authorised_value => $data->{restricted} });
- $av = $av->count ? $av->next : undef;
- $data->{restricted} = $av ? $av->lib : '';
- $data->{restrictedopac} = $av ? $av->opac_description : '';
+ $descriptions = Koha::AuthorisedValues->get_description_by_koha_field({frameworkcode => $data->{frameworkcode}, kohafield => 'items.restricted', authorised_value => $data->{restricted} });
+ $data->{restricted} = $descriptions->{lib} // '';
+ $data->{restrictedopac} = $descriptions->{opac_description} // '';
# my stack procedures
- $av = Koha::AuthorisedValues->search_by_koha_field({frameworkcode => $data->{frameworkcode}, kohafield => 'items.stack', authorised_value => $data->{stack} });
- $data->{stack} = $av->count ? $av->next->lib : '';
+ $descriptions = Koha::AuthorisedValues->get_description_by_koha_field({frameworkcode => $data->{frameworkcode}, kohafield => 'items.stack', authorised_value => $data->{stack} });
+ $data->{stack} = $descriptions->{lib} // '';
# Find the last 3 people who borrowed this item.
my $sth2 = $dbh->prepare("SELECT * FROM old_issues,borrowers
my $dbh=C4::Context->dbh;
my $error;
$item->{permanent_location} //= $item->{location};
+ _mod_item_dates( $item );
my $query =
"INSERT INTO items SET
biblionumber = ?,
my $query = "UPDATE items SET ";
my @bind;
+ _mod_item_dates( $item );
for my $key ( keys %$item ) {
next if ( $key eq 'itemnumber' );
$query.="$key=?,";
return ($item->{'itemnumber'},$error);
}
+sub _mod_item_dates { # date formatting for date fields in item hash
+ my ( $item ) = @_;
+ return if !$item || ref($item) ne 'HASH';
+
+ my @keys = grep
+ { $_ =~ /^onloan$|^date|date$|datetime$/ }
+ keys %$item;
+ # Incl. dateaccessioned,replacementpricedate,datelastborrowed,datelastseen
+ # NOTE: We do not (yet) have items fields ending with datetime
+ # Fields with _on$ have been handled already
+
+ foreach my $key ( @keys ) {
+ next if !defined $item->{$key}; # skip undefs
+ my $dt = eval { dt_from_string( $item->{$key} ) };
+ # eval: dt_from_string will die on us if we pass illegal dates
+
+ my $newstr;
+ if( defined $dt && ref($dt) eq 'DateTime' ) {
+ if( $key =~ /datetime/ ) {
+ $newstr = DateTime::Format::MySQL->format_datetime($dt);
+ } else {
+ $newstr = DateTime::Format::MySQL->format_date($dt);
+ }
+ }
+ $item->{$key} = $newstr; # might be undef to clear garbage
+ }
+}
+
=head2 _koha_delete_item
_koha_delete_item( $itemnum );
return ($result);
}
-=head2 GetItemHolds
-
- $holds = &GetItemHolds($biblionumber, $itemnumber);
-
-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;
-}
-
=head2 SearchItemsByField
my $items = SearchItemsByField($field, $value);
$column = $kohafield;
} else {
# MARC field is not linked to a DB field so we need to use
- # ExtractValue on biblioitems.marcxml or
+ # ExtractValue on marcxml from biblio_metadata or
# items.more_subfields_xml, depending on the MARC field.
my $xpath;
my $sqlfield;
$sqlfield = 'more_subfields_xml';
$xpath = '//record/datafield/subfield[@code="' . $marcsubfield . '"]';
} else {
- $sqlfield = 'marcxml';
+ $sqlfield = 'metadata'; # From biblio_metadata
if ($marcfield < 10) {
$xpath = "//record/controlfield[\@tag=\"$marcfield\"]";
} else {
FROM items
LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
+ LEFT JOIN biblio_metadata ON biblio_metadata.biblionumber = biblio.biblionumber
+ WHERE 1
};
if (defined $where_str and $where_str ne '') {
- $query .= qq{ WHERE $where_str };
+ $query .= qq{ AND $where_str };
}
+ $query .= q{ AND biblio_metadata.format = 'marcxml' AND biblio_metadata.marcflavour = ? };
+ push @where_args, C4::Context->preference('marcflavour');
+
my @columns = Koha::Database->new()->schema()->resultset('Item')->result_source->columns;
push @columns, Koha::Database->new()->schema()->resultset('Biblio')->result_source->columns;
push @columns, Koha::Database->new()->schema()->resultset('Biblioitem')->result_source->columns;
if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.itemcallnumber'
&& $defaultvalues
&& $defaultvalues->{'callnumber'} ) {
- if( $itemrecord and $defaultvalues and not $itemrecord->field($subfield) ){
+ if( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield) ){
# if the item record exists, only use default value if the item has no callnumber
$defaultvalue = $defaultvalues->{callnumber};
} elsif ( !$itemrecord and $defaultvalues ) {
if ( ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.holdingbranch' || $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.homebranch' )
&& $defaultvalues
&& $defaultvalues->{'branchcode'} ) {
- if ( $itemrecord and $defaultvalues and not $itemrecord->field($subfield) ) {
+ if ( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield) ) {
$defaultvalue = $defaultvalues->{branchcode};
}
}
&& $defaultvalues
&& $defaultvalues->{'location'} ) {
- if ( $itemrecord and $defaultvalues and not $itemrecord->field($subfield) ) {
+ if ( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield) ) {
# if the item record exists, only use default value if the item has no locationr
$defaultvalue = $defaultvalues->{location};
} elsif ( !$itemrecord and $defaultvalues ) {
#----- itemtypes
} elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
- my $itemtypes = GetItemTypes( style => 'array' );
+ my $itemtypes = Koha::ItemTypes->search_with_localization;
push @authorised_values, ""
unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
- for my $itemtype ( @$itemtypes ) {
- push @authorised_values, $itemtype->{itemtype};
- $authorised_lib{$itemtype->{itemtype}} = $itemtype->{translated_description};
+ while ( my $itemtype = $itemtypes->next ) {
+ push @authorised_values, $itemtype->itemtype;
+ $authorised_lib{$itemtype->itemtype} = $itemtype->translated_description;
}
if ($defaultvalues && $defaultvalues->{'itemtype'}) {
$defaultvalue = $defaultvalues->{'itemtype'};
});
my $pars = { dbh => $dbh, record => undef, tagslib =>$tagslib, id => $subfield_data{id}, tabloop => undef };
$plugin->build( $pars );
+ if ( $itemrecord and my $field = $itemrecord->field($tag) ) {
+ $defaultvalue = $field->subfield($subfield);
+ }
if( !$plugin->errstr ) {
#TODO Move html to template; see report 12176/13397
my $tab= $plugin->noclick? '-1': '';
my $class= $plugin->noclick? ' disabled': '';
my $title= $plugin->noclick? 'No popup': 'Tag editor';
- $subfield_data{marc_value} = qq[<input type="text" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="50" maxlength="255" /><a href="#" id="buttonDot_$subfield_data{id}" tabindex="$tab" class="buttonDot $class" title="$title">...</a>\n].$plugin->javascript;
+ $subfield_data{marc_value} = qq[<input type="text" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="50" maxlength="255" value="$defaultvalue" /><a href="#" id="buttonDot_$subfield_data{id}" tabindex="$tab" class="buttonDot $class" title="$title">...</a>\n].$plugin->javascript;
} else {
warn $plugin->errstr;
- $subfield_data{marc_value} = qq(<input type="text" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="50" maxlength="255" />); # supply default input form
+ $subfield_data{marc_value} = qq(<input type="text" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="50" maxlength="255" value="$defaultvalue" />); # supply default input form
}
}
elsif ( $tag eq '' ) { # it's an hidden field