use Modern::Perl;
-use vars qw(@ISA @EXPORT);
+our (@ISA, @EXPORT_OK);
BEGIN {
require Exporter;
@ISA = qw(Exporter);
- @EXPORT = qw(
+ @EXPORT_OK = qw(
AddItemFromMarc
AddItemBatchFromMarc
ModItemFromMarc
ModItemTransfer
CheckItemPreSave
GetItemsForInventory
- GetItemsInfo
- GetItemsLocationInfo
- GetHostItemsInfo
get_hostitemnumbers_of
- GetHiddenItemnumbers
- MoveItemFromBiblio
+ GetMarcItem
CartToShelf
GetAnalyticsCount
SearchItems
PrepareItemrecordDisplay
+ ToggleNewStatus
);
}
-use Carp;
-use Try::Tiny;
+use Carp qw( croak );
use C4::Context;
use C4::Koha;
-use C4::Biblio;
-use Koha::DateUtils;
+use C4::Biblio qw( GetMarcStructure TransformMarcToKoha );
use MARC::Record;
-use C4::ClassSource;
-use C4::Log;
-use List::MoreUtils qw(any);
-use YAML::XS;
+use C4::ClassSource qw( GetClassSort GetClassSources GetClassSource );
+use C4::Log qw( logaction );
+use List::MoreUtils qw( any );
use DateTime::Format::MySQL;
-use Data::Dumper; # used as part of logging item record changes, not just for
# debugging; so please don't remove this
use Koha::AuthorisedValues;
-use Koha::DateUtils qw(dt_from_string);
+use Koha::DateUtils qw( dt_from_string );
use Koha::Database;
+use Koha::Biblios;
use Koha::Biblioitems;
use Koha::Items;
use Koha::ItemTypes;
Given a MARC::Record object containing an embedded item
record and a biblionumber, create a new item record.
-The final optional parameter, C<$params>, expected to contain
+The final optional parameter, C<$params>, may contain
'skip_record_index' key, which relayed down to Koha::Item/store,
there it prevents calling of index_records,
which takes most of the time in batch adds/deletes: index_records
to be called later in C<additem.pl> after the whole loop.
+You may also optionally pass biblioitemnumber in the params hash to
+boost performance of inserts by preventing a lookup in Koha::Item.
+
$params:
skip_record_index => 1|0
+ biblioitemnumber => $biblioitemnumber
=cut
# parse item hash from MARC
my $frameworkcode = C4::Biblio::GetFrameworkCode($biblionumber);
my ( $itemtag, $itemsubfield ) = C4::Biblio::GetMarcFromKohaField( "items.itemnumber" );
-
my $localitemmarc = MARC::Record->new;
$localitemmarc->append_fields( $source_item_marc->field($itemtag) );
- my $item_values = C4::Biblio::TransformMarcToKoha( $localitemmarc, $frameworkcode, 'items' );
+ my $item_values = C4::Biblio::TransformMarcToKoha({ record => $localitemmarc, limit_table => 'items' });
my $unlinked_item_subfields = _get_unlinked_item_subfields( $localitemmarc, $frameworkcode );
$item_values->{more_subfields_xml} = _get_unlinked_subfields_xml($unlinked_item_subfields);
$item_values->{biblionumber} = $biblionumber;
+ $item_values->{biblioitemnumber} = $params->{biblioitemnumber};
$item_values->{cn_source} = delete $item_values->{'items.cn_source'}; # Because of C4::Biblio::_disambiguate
$item_values->{cn_sort} = delete $item_values->{'items.cn_sort'}; # Because of C4::Biblio::_disambiguate
my $item = Koha::Item->new( $item_values )->store({ skip_record_index => $params->{skip_record_index} });
$temp_item_marc->append_fields($item_field);
# add biblionumber and biblioitemnumber
- my $item = TransformMarcToKoha( $temp_item_marc, $frameworkcode, 'items' );
+ my $item = TransformMarcToKoha({ record => $temp_item_marc, limit_table => 'items' });
my $unlinked_item_subfields = _get_unlinked_item_subfields($temp_item_marc, $frameworkcode);
$item->{'more_subfields_xml'} = _get_unlinked_subfields_xml($unlinked_item_subfields);
$item->{'biblionumber'} = $biblionumber;
my $localitemmarc = MARC::Record->new;
$localitemmarc->append_fields( $item_marc->field($itemtag) );
my $item_object = Koha::Items->find($itemnumber);
- my $item = TransformMarcToKoha( $localitemmarc, $frameworkcode, 'items' );
+ my $item = TransformMarcToKoha({ record => $localitemmarc, limit_table => 'items' });
+
+ # When importing items we blank this column, we need to set it to the existing value
+ # to prevent it being blanked by set_or_blank
+ $item->{onloan} = $item_object->onloan if( $item_object->onloan && !defined $item->{onloan} );
+
+ my ( $perm_loc_tag, $perm_loc_subfield ) = C4::Biblio::GetMarcFromKohaField( "items.permanent_location" );
+ my $has_permanent_location = defined $perm_loc_tag && defined $item_marc->subfield( $perm_loc_tag, $perm_loc_subfield );
# Retrieving the values for the fields that are not linked
my @mapped_fields = Koha::MarcSubfieldStructures->search(
$item_object = $item_object->set_or_blank($item);
$item_object->cn_sort($existing_cn_sort); # Resetting to the existing value
+ $item_object->make_column_dirty('permanent_location') if $has_permanent_location;
+
my $unlinked_item_subfields = _get_unlinked_item_subfields( $localitemmarc, $frameworkcode );
$item_object->more_subfields_xml(_get_unlinked_subfields_xml($unlinked_item_subfields));
$item_object->store({ skip_record_index => $params->{skip_record_index} });
my $dbh = C4::Context->dbh;
my $item = Koha::Items->find( $itemnumber );
- # Remove the 'shelving cart' location status if it is being used.
- CartToShelf( $itemnumber ) if $item->location && $item->location eq 'CART' && ( !$item->permanent_location || $item->permanent_location ne 'CART' );
-
- $dbh->do("UPDATE branchtransfers SET datearrived = NOW(), comments = ? WHERE itemnumber = ? AND datearrived IS NULL", undef, "Canceled, new transfer from $frombranch to $tobranch created", $itemnumber);
+ # NOTE: This retains the existing hard coded behaviour by ignoring transfer limits
+ # and always replacing any existing transfers. (In theory, calls to ModItemTransfer
+ # will have been preceded by a check of branch transfer limits)
+ my $to_library = Koha::Libraries->find($tobranch);
+ my $transfer = $item->request_transfer(
+ {
+ to => $to_library,
+ reason => $trigger,
+ ignore_limits => 1,
+ replace => 1
+ }
+ );
- #new entry in branchtransfers....
- my $sth = $dbh->prepare(
- "INSERT INTO branchtransfers (itemnumber, frombranch, datesent, tobranch, reason)
- VALUES (?, ?, NOW(), ?, ?)");
- $sth->execute($itemnumber, $frombranch, $tobranch, $trigger);
+ # Immediately set the item to in transit if it is checked in
+ if ( !$item->checkout ) {
+ $item->holdingbranch($frombranch)->store(
+ {
+ log_action => 0,
+ skip_record_index => $params->{skip_record_index}
+ }
+ );
+ $transfer->transit;
+ }
- # FIXME we are fetching the item twice in the 2 next statements!
- Koha::Items->find($itemnumber)->holdingbranch($frombranch)->store({ log_action => 0, skip_record_index => $params->{skip_record_index} });
- ModDateLastSeen($itemnumber, undef, { skip_record_index => $params->{skip_record_index} });
return;
}
sub ModDateLastSeen {
my ( $itemnumber, $leave_item_lost, $params ) = @_;
- my $today = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
-
my $item = Koha::Items->find($itemnumber);
- $item->datelastseen($today);
+ $item->datelastseen(dt_from_string);
$item->itemlost(0) unless $leave_item_lost;
- $item->store({ log_action => 0, skip_record_index => $params->{skip_record_index} });
+ $item->store({ log_action => 0, skip_record_index => $params->{skip_record_index}, skip_holds_queue => $params->{skip_holds_queue} });
}
=head2 CheckItemPreSave
- my $item_ref = TransformMarcToKoha($marc, 'items');
+ my $item_ref = TransformMarcToKoha({ record => $marc, limit_table => 'items' });
# do stuff
my %errors = CheckItemPreSave($item_ref);
if (exists $errors{'duplicate_barcode'}) {
my $statushash = $parameters->{'statushash'} // '';
my $ignore_waiting_holds = $parameters->{'ignore_waiting_holds'} // '';
my $itemtypes = $parameters->{'itemtypes'} || [];
+ my $ccode = $parameters->{'ccode'} // '';
my $dbh = C4::Context->dbh;
my ( @bind_params, @where_strings );
my $max_cnsort = GetClassSort($class_source,undef,$maxlocation);
my $select_columns = q{
- SELECT DISTINCT(items.itemnumber), barcode, itemcallnumber, title, author, biblio.biblionumber, biblio.frameworkcode, datelastseen, homebranch, location, notforloan, damaged, itemlost, withdrawn, stocknumber, items.cn_sort
+ SELECT DISTINCT(items.itemnumber), barcode, itemcallnumber, title, author, biblio.biblionumber, biblio.frameworkcode, datelastseen, homebranch, location, notforloan, damaged, itemlost, withdrawn, stocknumber, items.cn_sort, ccode
+
};
my $select_count = q{SELECT COUNT(DISTINCT(items.itemnumber))};
my $query = q{
}
}
+ if ($ccode){
+ push @where_strings, 'ccode = ?';
+ push @bind_params, $ccode;
+ }
+
if ($minlocation) {
push @where_strings, 'items.cn_sort >= ?';
push @bind_params, $min_cnsort;
}
if ($datelastseen) {
- $datelastseen = output_pref({ str => $datelastseen, dateformat => 'iso', dateonly => 1 });
push @where_strings, '(datelastseen < ? OR datelastseen IS NULL)';
push @bind_params, $datelastseen;
}
'+select' => [ 'marc_subfield_structures.kohafield', 'marc_subfield_structures.frameworkcode', 'me.authorised_value', 'me.lib' ],
'+as' => [ 'kohafield', 'frameworkcode', 'authorised_value', 'lib' ],
}
- );
+ )->as_list;
my $avmapping = { map { $_->get_column('kohafield') . ',' . $_->get_column('frameworkcode') . ',' . $_->get_column('authorised_value') => $_->get_column('lib') } @avs };
return (\@results, $iTotalRecords);
}
-=head2 GetItemsInfo
-
- @results = GetItemsInfo($biblionumber);
-
-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 attributes from the
-C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
-Koha database. Other keys include:
-
-=over 2
-
-=item C<$data-E<gt>{branchname}>
-
-The name (not the code) of the branch to which the book belongs.
-
-=item C<$data-E<gt>{datelastseen}>
-
-This is simply C<items.datelastseen>, except that while the date is
-stored in YYYY-MM-DD format in the database, here it is converted to
-DD/MM/YYYY format. A NULL date is returned as C<//>.
-
-=item C<$data-E<gt>{datedue}>
-
-=item C<$data-E<gt>{class}>
-
-This is the concatenation of C<biblioitems.classification>, the book's
-Dewey code, and C<biblioitems.subclass>.
-
-=item C<$data-E<gt>{ocount}>
-
-I think this is the number of copies of the book available.
-
-=item C<$data-E<gt>{order}>
-
-If this is set, it is set to C<One Order>.
-
-=back
-
-=cut
-
-sub GetItemsInfo {
- my ( $biblionumber ) = @_;
- my $dbh = C4::Context->dbh;
- require C4::Languages;
- my $language = C4::Languages::getlanguage();
- my $query = "
- SELECT items.*,
- biblio.*,
- biblioitems.volume,
- biblioitems.number,
- biblioitems.itemtype,
- biblioitems.isbn,
- biblioitems.issn,
- biblioitems.publicationyear,
- biblioitems.publishercode,
- biblioitems.volumedate,
- biblioitems.volumedesc,
- biblioitems.lccn,
- biblioitems.url,
- items.notforloan as itemnotforloan,
- issues.borrowernumber,
- issues.date_due as datedue,
- issues.onsite_checkout,
- borrowers.cardnumber,
- borrowers.surname,
- borrowers.firstname,
- borrowers.branchcode as bcode,
- serial.serialseq,
- serial.publisheddate,
- itemtypes.description,
- COALESCE( localization.translation, itemtypes.description ) AS translated_description,
- itemtypes.notforloan as notforloan_per_itemtype,
- holding.branchurl,
- holding.branchcode,
- holding.branchname,
- holding.opac_info as holding_branch_opac_info,
- home.opac_info as home_branch_opac_info,
- IF(tmp_holdsqueue.itemnumber,1,0) AS has_pending_hold
- FROM items
- LEFT JOIN branches AS holding ON items.holdingbranch = holding.branchcode
- LEFT JOIN branches AS home ON items.homebranch=home.branchcode
- LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
- LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
- LEFT JOIN issues USING (itemnumber)
- LEFT JOIN borrowers USING (borrowernumber)
- LEFT JOIN serialitems USING (itemnumber)
- LEFT JOIN serial USING (serialid)
- LEFT JOIN itemtypes ON itemtypes.itemtype = "
- . (C4::Context->preference('item-level_itypes') ? 'items.itype' : 'biblioitems.itemtype');
- $query .= q|
- LEFT JOIN tmp_holdsqueue USING (itemnumber)
- LEFT JOIN localization ON itemtypes.itemtype = localization.code
- AND localization.entity = 'itemtypes'
- AND localization.lang = ?
- |;
-
- $query .= " WHERE items.biblionumber = ? ORDER BY home.branchname, items.enumchron, LPAD( items.copynumber, 8, '0' ), items.dateaccessioned DESC" ;
- my $sth = $dbh->prepare($query);
- $sth->execute($language, $biblionumber);
- my $i = 0;
- my @results;
- my $serial;
-
- my $userenv = C4::Context->userenv;
- my $want_not_same_branch = C4::Context->preference("IndependentBranches") && !C4::Context->IsSuperLibrarian();
- while ( my $data = $sth->fetchrow_hashref ) {
- if ( $data->{borrowernumber} && $want_not_same_branch) {
- $data->{'NOTSAMEBRANCH'} = $data->{'bcode'} ne $userenv->{branch};
- }
-
- $serial ||= $data->{'serial'};
-
- my $descriptions;
- # get notforloan complete status if applicable
- $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
- $descriptions = Koha::AuthorisedValues->get_description_by_koha_field({frameworkcode => $data->{frameworkcode}, kohafield => 'items.restricted', authorised_value => $data->{restricted} });
- $data->{restrictedvalue} = $descriptions->{lib} // '';
- $data->{restrictedvalueopac} = $descriptions->{opac_description} // '';
-
- # my stack procedures
- $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
- WHERE itemnumber = ?
- AND old_issues.borrowernumber = borrowers.borrowernumber
- ORDER BY returndate DESC
- LIMIT 3");
- $sth2->execute($data->{'itemnumber'});
- my $ii = 0;
- while (my $data2 = $sth2->fetchrow_hashref()) {
- $data->{"timestamp$ii"} = $data2->{'timestamp'} if $data2->{'timestamp'};
- $data->{"card$ii"} = $data2->{'cardnumber'} if $data2->{'cardnumber'};
- $data->{"borrower$ii"} = $data2->{'borrowernumber'} if $data2->{'borrowernumber'};
- $ii++;
- }
-
- $results[$i] = $data;
- $i++;
- }
-
- return $serial
- ? sort { ($b->{'publisheddate'} || $b->{'enumchron'}) cmp ($a->{'publisheddate'} || $a->{'enumchron'}) } @results
- : @results;
-}
-
-=head2 GetItemsLocationInfo
-
- my @itemlocinfo = GetItemsLocationInfo($biblionumber);
-
-Returns the branch names, shelving location and itemcallnumber for each item attached to the biblio in question
-
-C<GetItemsInfo> returns a list of references-to-hash. Data returned:
-
-=over 2
-
-=item C<$data-E<gt>{homebranch}>
-
-Branch Name of the item's homebranch
-
-=item C<$data-E<gt>{holdingbranch}>
-
-Branch Name of the item's holdingbranch
-
-=item C<$data-E<gt>{location}>
-
-Item's shelving location code
-
-=item C<$data-E<gt>{location_intranet}>
-
-The intranet description for the Shelving Location as set in authorised_values 'LOC'
-
-=item C<$data-E<gt>{location_opac}>
-
-The OPAC description for the Shelving Location as set in authorised_values 'LOC'. Falls back to intranet description if no OPAC
-description is set.
-
-=item C<$data-E<gt>{itemcallnumber}>
-
-Item's itemcallnumber
-
-=item C<$data-E<gt>{cn_sort}>
-
-Item's call number normalized for sorting
-
-=back
-
-=cut
-
-sub GetItemsLocationInfo {
- my $biblionumber = shift;
- my @results;
-
- my $dbh = C4::Context->dbh;
- my $query = "SELECT a.branchname as homebranch, b.branchname as holdingbranch,
- location, itemcallnumber, cn_sort
- FROM items, branches as a, branches as b
- WHERE homebranch = a.branchcode AND holdingbranch = b.branchcode
- AND biblionumber = ?
- ORDER BY cn_sort ASC";
- my $sth = $dbh->prepare($query);
- $sth->execute($biblionumber);
-
- while ( my $data = $sth->fetchrow_hashref ) {
- my $av = Koha::AuthorisedValues->search({ category => 'LOC', authorised_value => $data->{location} });
- $av = $av->count ? $av->next : undef;
- $data->{location_intranet} = $av ? $av->lib : '';
- $data->{location_opac} = $av ? $av->opac_description : '';
- push @results, $data;
- }
- 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('EasyAnalyticalRecords') ) {
- return @returnitemsInfo;
- }
-
- my @fields;
- if( C4::Context->preference('marcflavour') eq 'MARC21' ||
- C4::Context->preference('marcflavour') eq 'NORMARC') {
- @fields = $record->field('773');
- } elsif( C4::Context->preference('marcflavour') eq 'UNIMARC') {
- @fields = $record->field('461');
- }
-
- foreach my $hostfield ( @fields ) {
- 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 get_hostitemnumbers_of
my @itemnumbers_of = get_hostitemnumbers_of($biblionumber);
return ();
}
- my $marcrecord = C4::Biblio::GetMarcBiblio({ biblionumber => $biblionumber });
+ my $biblio = Koha::Biblios->find($biblionumber);
+ my $marcrecord = $biblio->metadata->record;
return unless $marcrecord;
my ( @returnhostitemnumbers, $tag, $biblio_s, $item_s );
my $marcflavor = C4::Context->preference('marcflavour');
- if ( $marcflavor eq 'MARC21' || $marcflavor eq 'NORMARC' ) {
+ if ( $marcflavor eq 'MARC21' ) {
$tag = '773';
$biblio_s = '0';
$item_s = '9';
return @returnhostitemnumbers;
}
-=head2 GetHiddenItemnumbers
-
- my @itemnumbers_to_hide = GetHiddenItemnumbers({ items => \@items, borcat => $category });
-
-Given a list of items it checks which should be hidden from the OPAC given
-the current configuration. Returns a list of itemnumbers corresponding to
-those that should be hidden. Optionally takes a borcat parameter for certain borrower types
-to be excluded
-
-=cut
-
-sub GetHiddenItemnumbers {
- my $params = shift;
- my $items = $params->{items};
- if (my $exceptions = C4::Context->preference('OpacHiddenItemsExceptions') and $params->{'borcat'}){
- foreach my $except (split(/\|/, $exceptions)){
- if ($params->{'borcat'} eq $except){
- return; # we don't hide anything for this borrower category
- }
- }
- }
- my @resultitems;
-
- my $yaml = C4::Context->preference('OpacHiddenItems');
- return () if (! $yaml =~ /\S/ );
- $yaml = "$yaml\n\n"; # YAML is anal on ending \n. Surplus does not hurt
- my $hidingrules;
- eval {
- $hidingrules = YAML::XS::Load($yaml);
- };
- if ($@) {
- warn "Unable to parse OpacHiddenItems syspref : $@";
- return ();
- }
- my $dbh = C4::Context->dbh;
-
- # For each item
- foreach my $item (@$items) {
-
- # We check each rule
- foreach my $field (keys %$hidingrules) {
- my $val;
- if (exists $item->{$field}) {
- $val = $item->{$field};
- }
- else {
- my $query = "SELECT $field from items where itemnumber = ?";
- $val = $dbh->selectrow_array($query, undef, $item->{'itemnumber'});
- }
- $val = '' unless defined $val;
-
- # If the results matches the values in the yaml file
- if (any { $val 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;
-}
-
=head1 LIMITED USE FUNCTIONS
The following functions, while part of the public API,
=cut
-=head2 MoveItemFromBiblio
-
- MoveItemFromBiblio($itenumber, $frombiblio, $tobiblio);
-
-Moves an item from a biblio to another
-
-Returns undef if the move failed or the biblionumber of the destination record otherwise
-
-=cut
-
-sub MoveItemFromBiblio {
- my ($itemnumber, $frombiblio, $tobiblio) = @_;
- my $dbh = C4::Context->dbh;
- my ( $tobiblioitem ) = $dbh->selectrow_array(q|
- SELECT biblioitemnumber
- FROM biblioitems
- WHERE biblionumber = ?
- |, undef, $tobiblio );
- my $return = $dbh->do(q|
- UPDATE items
- SET biblioitemnumber = ?,
- biblionumber = ?
- WHERE itemnumber = ?
- AND biblionumber = ?
- |, undef, $tobiblioitem, $tobiblio, $itemnumber, $frombiblio );
- if ($return == 1) {
- my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX });
- $indexer->index_records( $tobiblio, "specialUpdate", "biblioserver" );
- $indexer->index_records( $frombiblio, "specialUpdate", "biblioserver" );
- # Checking if the item we want to move is in an order
- require C4::Acquisition;
- my $order = C4::Acquisition::GetOrderFromItemnumber($itemnumber);
- if ($order) {
- # Replacing the biblionumber within the order if necessary
- $order->{'biblionumber'} = $tobiblio;
- C4::Acquisition::ModOrder($order);
- }
-
- # Update reserves, hold_fill_targets, tmp_holdsqueue and linktracker tables
- for my $table_name ( qw( reserves hold_fill_targets tmp_holdsqueue linktracker ) ) {
- $dbh->do( qq|
- UPDATE $table_name
- SET biblionumber = ?
- WHERE itemnumber = ?
- |, undef, $tobiblio, $itemnumber );
- }
- return $tobiblio;
- }
- return;
-}
-
=head2 _marc_from_item_hash
my $item_marc = _marc_from_item_hash($item, $frameworkcode[, $unlinked_item_subfields]);
sub GetAnalyticsCount {
my ($itemnumber) = @_;
+ if ( !C4::Context->preference('EasyAnalyticalRecords') ) {
+ return 0;
+ }
+
### ZOOM search here
my $query;
$query= "hi=".$itemnumber;
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;
- my @operators = qw(= != > < >= <= like);
+ push @columns, Koha::Database->new()->schema()->resultset('Issue')->result_source->columns;
+ my @operators = qw(= != > < >= <= is like);
push @operators, 'not like';
my $field = $filter->{field} // q{};
if ( (0 < grep { $_ eq $field } @columns) or (substr($field, 0, 5) eq 'marc:') ) {
}
$column = "ExtractValue($sqlfield, '$xpath')";
}
+ }
+ elsif ($field eq 'isbn') {
+ if ( C4::Context->preference("SearchWithISBNVariations") and $query ) {
+ my @isbns = C4::Koha::GetVariationsOfISBN( $query );
+ $query = [];
+ push @$query, @isbns;
+ }
+ $column = $field;
+ }
+ elsif ($field eq 'issn') {
+ if ( C4::Context->preference("SearchWithISSNVariations") and $query ) {
+ my @issns = C4::Koha::GetVariationsOfISSN( $query );
+ $query = [];
+ push @$query, @issns;
+ }
+ $column = $field;
} else {
$column = $field;
}
}
if (ref $query eq 'ARRAY') {
- if ($op eq '=') {
- $op = 'IN';
- } elsif ($op eq '!=') {
- $op = 'NOT IN';
+ if ($op eq 'like') {
+ $where_fragment = {
+ str => "($column LIKE " . join (" OR $column LIKE ", ('?') x @$query ) . ")",
+ args => $query,
+ };
}
+ else {
+ if ($op eq '=') {
+ $op = 'IN';
+ } elsif ($op eq '!=') {
+ $op = 'NOT IN';
+ }
+ $where_fragment = {
+ str => "$column $op (" . join (',', ('?') x @$query) . ")",
+ args => $query,
+ };
+ }
+ } elsif ( $op eq 'is' ) {
$where_fragment = {
- str => "$column $op (" . join (',', ('?') x @$query) . ")",
- args => $query,
+ str => "$column $op $query",
+ args => [],
};
} else {
$where_fragment = {
=item * query: the value to search in this column
-=item * operator: comparison operator. Can be one of = != > < >= <= like 'not like'
+=item * operator: comparison operator. Can be one of = != > < >= <= like 'not like' is
=back
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
+ LEFT JOIN issues ON issues.itemnumber = items.itemnumber
WHERE 1
};
if (defined $where_str and $where_str ne '') {
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;
- my $sortby = (0 < grep {$params->{sortby} eq $_} @columns)
- ? $params->{sortby} : 'itemnumber';
- my $sortorder = (uc($params->{sortorder}) eq 'ASC') ? 'ASC' : 'DESC';
- $query .= qq{ ORDER BY $sortby $sortorder };
+ push @columns, Koha::Database->new()->schema()->resultset('Issue')->result_source->columns;
+
+ if ( $params->{sortby} eq 'availability' ) {
+ my $sortorder = (uc($params->{sortorder}) eq 'ASC') ? 'ASC' : 'DESC';
+ $query .= qq{ ORDER BY onloan $sortorder };
+ } else {
+ my $sortby = (0 < grep {$params->{sortby} eq $_} @columns)
+ ? $params->{sortby} : 'itemnumber';
+ my $sortorder = (uc($params->{sortorder}) eq 'ASC') ? 'ASC' : 'DESC';
+ $query .= qq{ ORDER BY $sortby $sortorder };
+ }
my $rows = $params->{rows};
my @limit_args;
=head2 PrepareItemrecordDisplay
- PrepareItemrecordDisplay($itemrecord,$bibnum,$itemumber,$frameworkcode);
+ PrepareItemrecordDisplay($bibnum,$itemumber,$defaultvalues,$frameworkcode);
Returns a hash with all the fields for Display a given item data in a template
+$defaultvalues should either contain a hashref of values for the new item, or be undefined.
+
The $frameworkcode returns the item for the given frameworkcode, ONLY if bibnum is not provided
=cut
# its contents. See also GetMarcStructure.
my $tagslib = GetMarcStructure( 1, $frameworkcode, { unsafe => 1 } );
+ # Pick the default location from NewItemsDefaultLocation
+ if ( C4::Context->preference('NewItemsDefaultLocation') ) {
+ $defaultvalues //= {};
+ $defaultvalues->{location} //= C4::Context->preference('NewItemsDefaultLocation');
+ }
+
# return nothing if we don't have found an existing framework.
return q{} unless $tagslib;
my $itemrecord;
# loop through each subfield
my $cntsubf;
- foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
- next if IsMarcStructureInternal($tagslib->{$tag}{$subfield});
- next unless ( $tagslib->{$tag}->{$subfield}->{'tab'} );
- next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
+ foreach my $subfield (
+ sort { $a->{display_order} <=> $b->{display_order} || $a->{subfield} cmp $b->{subfield} }
+ grep { ref($_) && %$_ } # Not a subfield (values for "important", "lib", "mandatory", etc.) or empty
+ values %{ $tagslib->{$tag} } )
+ {
+ next unless ( $subfield->{'tab'} );
+ next if ( $subfield->{'tab'} ne "10" );
my %subfield_data;
$subfield_data{tag} = $tag;
- $subfield_data{subfield} = $subfield;
+ $subfield_data{subfield} = $subfield->{subfield};
$subfield_data{countsubfield} = $cntsubf++;
- $subfield_data{kohafield} = $tagslib->{$tag}->{$subfield}->{'kohafield'};
- $subfield_data{id} = "tag_".$tag."_subfield_".$subfield."_".int(rand(1000000));
+ $subfield_data{kohafield} = $subfield->{kohafield};
+ $subfield_data{id} = "tag_".$tag."_subfield_".$subfield->{subfield}."_".int(rand(1000000));
# $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
- $subfield_data{marc_lib} = $tagslib->{$tag}->{$subfield}->{lib};
- $subfield_data{mandatory} = $tagslib->{$tag}->{$subfield}->{mandatory};
- $subfield_data{repeatable} = $tagslib->{$tag}->{$subfield}->{repeatable};
+ $subfield_data{marc_lib} = $subfield->{lib};
+ $subfield_data{mandatory} = $subfield->{mandatory};
+ $subfield_data{repeatable} = $subfield->{repeatable};
$subfield_data{hidden} = "display:none"
- if ( ( $tagslib->{$tag}->{$subfield}->{hidden} > 4 )
- || ( $tagslib->{$tag}->{$subfield}->{hidden} < -4 ) );
+ if ( ( $subfield->{hidden} > 4 )
+ || ( $subfield->{hidden} < -4 ) );
my ( $x, $defaultvalue );
if ($itemrecord) {
- ( $x, $defaultvalue ) = _find_value( $tag, $subfield, $itemrecord );
+ ( $x, $defaultvalue ) = _find_value( $tag, $subfield->{subfield}, $itemrecord );
}
- $defaultvalue = $tagslib->{$tag}->{$subfield}->{defaultvalue} unless $defaultvalue;
+ $defaultvalue = $subfield->{defaultvalue} unless $defaultvalue;
if ( !defined $defaultvalue ) {
$defaultvalue = q||;
} else {
$defaultvalue =~ s/<<USER>>/$username/g;
}
- my $maxlength = $tagslib->{$tag}->{$subfield}->{maxlength};
+ my $maxlength = $subfield->{maxlength};
# search for itemcallnumber if applicable
- if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.itemcallnumber'
+ if ( $subfield->{kohafield} eq 'items.itemcallnumber'
&& C4::Context->preference('itemcallnumber') && $itemrecord) {
foreach my $itemcn_pref (split(/,/,C4::Context->preference('itemcallnumber'))){
my $CNtag = substr( $itemcn_pref, 0, 3 );
next unless my $field = $itemrecord->field($CNtag);
my $CNsubfields = substr( $itemcn_pref, 3 );
+ $CNsubfields = undef if $CNsubfields eq '';
$defaultvalue = $field->as_string( $CNsubfields, ' ');
last if $defaultvalue;
}
}
- if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.itemcallnumber'
+ if ( $subfield->{kohafield} eq 'items.itemcallnumber'
&& $defaultvalues
&& $defaultvalues->{'callnumber'} ) {
- if( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield) ){
+ if( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield->{subfield}) ){
# if the item record exists, only use default value if the item has no callnumber
$defaultvalue = $defaultvalues->{callnumber};
} elsif ( !$itemrecord and $defaultvalues ) {
$defaultvalue = $defaultvalues->{callnumber};
}
}
- if ( ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.holdingbranch' || $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.homebranch' )
+ if ( ( $subfield->{kohafield} eq 'items.holdingbranch' || $subfield->{kohafield} eq 'items.homebranch' )
&& $defaultvalues
&& $defaultvalues->{'branchcode'} ) {
if ( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield) ) {
$defaultvalue = $defaultvalues->{branchcode};
}
}
- if ( ( $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.location' )
+ if ( ( $subfield->{kohafield} eq 'items.location' )
&& $defaultvalues
&& $defaultvalues->{'location'} ) {
- if ( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield) ) {
+ if ( $itemrecord and $defaultvalues and not $itemrecord->subfield($tag,$subfield->{subfield}) ) {
# if the item record exists, only use default value if the item has no locationr
$defaultvalue = $defaultvalues->{location};
} elsif ( !$itemrecord and $defaultvalues ) {
$defaultvalue = $defaultvalues->{location};
}
}
- if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
+ if ( ( $subfield->{kohafield} eq 'items.ccode' )
+ && $defaultvalues
+ && $defaultvalues->{'ccode'} ) {
+
+ if ( !$itemrecord and $defaultvalues ) {
+ # if the item record *doesn't* exists, always use the default value
+ $defaultvalue = $defaultvalues->{ccode};
+ }
+ }
+ if ( $subfield->{authorised_value} ) {
my @authorised_values;
my %authorised_lib;
# builds list, depending on authorised value...
#---- branch
- if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
+ if ( $subfield->{'authorised_value'} eq "branches" ) {
if ( ( C4::Context->preference("IndependentBranches") )
&& !C4::Context->IsSuperLibrarian() ) {
my $sth = $dbh->prepare( "SELECT branchcode,branchname FROM branches WHERE branchcode = ? ORDER BY branchname" );
$sth->execute( C4::Context->userenv->{branch} );
push @authorised_values, ""
- unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
+ unless ( $subfield->{mandatory} );
while ( my ( $branchcode, $branchname ) = $sth->fetchrow_array ) {
push @authorised_values, $branchcode;
$authorised_lib{$branchcode} = $branchname;
my $sth = $dbh->prepare( "SELECT branchcode,branchname FROM branches ORDER BY branchname" );
$sth->execute;
push @authorised_values, ""
- unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
+ unless ( $subfield->{mandatory} );
while ( my ( $branchcode, $branchname ) = $sth->fetchrow_array ) {
push @authorised_values, $branchcode;
$authorised_lib{$branchcode} = $branchname;
}
#----- itemtypes
- } elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
+ } elsif ( $subfield->{authorised_value} eq "itemtypes" ) {
my $itemtypes = Koha::ItemTypes->search_with_localization;
push @authorised_values, "";
while ( my $itemtype = $itemtypes->next ) {
}
#---- class_sources
- } elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "cn_source" ) {
+ } elsif ( $subfield->{authorised_value} eq "cn_source" ) {
push @authorised_values, "";
my $class_sources = GetClassSources();
#---- "true" authorised value
} else {
$authorised_values_sth->execute(
- $tagslib->{$tag}->{$subfield}->{authorised_value},
+ $subfield->{authorised_value},
$branch_limit ? $branch_limit : ()
);
push @authorised_values, "";
default => $defaultvalue // q{},
labels => \%authorised_lib,
};
- } elsif ( $tagslib->{$tag}->{$subfield}->{value_builder} ) {
+ } elsif ( $subfield->{value_builder} ) {
# it is a plugin
require Koha::FrameworkPlugin;
my $plugin = Koha::FrameworkPlugin->new({
- name => $tagslib->{$tag}->{$subfield}->{value_builder},
+ name => $subfield->{value_builder},
item_style => 1,
});
- my $pars = { dbh => $dbh, record => undef, tagslib =>$tagslib, id => $subfield_data{id}, tabloop => undef };
+ my $pars = { dbh => $dbh, record => undef, tagslib =>$tagslib, id => $subfield_data{id} };
$plugin->build( $pars );
if ( $itemrecord and my $field = $itemrecord->field($tag) ) {
- $defaultvalue = $field->subfield($subfield) || q{};
+ $defaultvalue = $field->subfield($subfield->{subfield}) || q{};
}
if( !$plugin->errstr ) {
#TODO Move html to template; see report 12176/13397
elsif ( $tag eq '' ) { # it's an hidden field
$subfield_data{marc_value} = qq(<input type="hidden" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="50" maxlength="$maxlength" value="$defaultvalue" />);
}
- elsif ( $tagslib->{$tag}->{$subfield}->{'hidden'} ) { # FIXME: shouldn't input type be "hidden" ?
+ elsif ( $subfield->{'hidden'} ) { # FIXME: shouldn't input type be "hidden" ?
$subfield_data{marc_value} = qq(<input type="text" id="$subfield_data{id}" name="field_value" class="input_marceditor" size="50" maxlength="$maxlength" value="$defaultvalue" />);
}
elsif ( length($defaultvalue) > 100
or (C4::Context->preference("marcflavour") eq "UNIMARC" and
- 300 <= $tag && $tag < 400 && $subfield eq 'a' )
+ 300 <= $tag && $tag < 400 && $subfield->{subfield} eq 'a' )
or (C4::Context->preference("marcflavour") eq "MARC21" and
500 <= $tag && $tag < 600 )
) {
my $report;
for my $rule ( @rules ) {
my $age = $rule->{age};
+ # Default to using items.dateaccessioned if there's an old item modification rule
+ # missing an agefield value
+ my $agefield = $rule->{agefield} ? $rule->{agefield} : 'items.dateaccessioned';
my $conditions = $rule->{conditions};
my $substitutions = $rule->{substitutions};
foreach ( @$substitutions ) {
WHERE 1
|;
for my $condition ( @$conditions ) {
+ next unless $condition->{field};
if (
grep { $_ eq $condition->{field} } @item_columns
or grep { $_ eq $condition->{field} } @biblioitem_columns
}
}
if ( defined $age ) {
- $query .= q| AND TO_DAYS(NOW()) - TO_DAYS(dateaccessioned) >= ? |;
+ $query .= qq| AND TO_DAYS(NOW()) - TO_DAYS($agefield) >= ? |;
push @params, $age;
}
my $sth = $dbh->prepare($query);