use C4::Context;
use C4::Koha;
use C4::Biblio;
-use C4::Dates qw/format_date format_date_in_iso/;
+use Koha::DateUtils;
use MARC::Record;
use C4::ClassSource;
use C4::Log;
use Data::Dumper; # used as part of logging item record changes, not just for
# debugging; so please don't remove this
use Koha::DateUtils qw/dt_from_string/;
-
use Koha::Database;
-use vars qw($VERSION @ISA @EXPORT);
+use Koha::Biblioitems;
+use Koha::Items;
+use Koha::SearchEngine;
+use Koha::SearchEngine::Search;
+use Koha::Libraries;
+
+use vars qw(@ISA @EXPORT);
BEGIN {
- $VERSION = 3.07.00.049;
require Exporter;
@ISA = qw( Exporter );
GetItemnumberFromBarcode
GetBarcodeFromItemnumber
GetHiddenItemnumbers
+ ItemSafeToDelete
DelItemCheck
MoveItemFromBiblio
GetLatestAcquisitions
my $localitemmarc=MARC::Record->new;
$localitemmarc->append_fields($source_item_marc->field($itemtag));
- my $item = &TransformMarcToKoha( $dbh, $localitemmarc, $frameworkcode ,'items');
+ my $item = &TransformMarcToKoha( $localitemmarc, $frameworkcode ,'items');
my $unlinked_item_subfields = _get_unlinked_item_subfields($localitemmarc, $frameworkcode);
return AddItem($item, $biblionumber, $dbh, $frameworkcode, $unlinked_item_subfields);
}
$temp_item_marc->append_fields($item_field);
# add biblionumber and biblioitemnumber
- my $item = TransformMarcToKoha( $dbh, $temp_item_marc, $frameworkcode, 'items' );
+ my $item = TransformMarcToKoha( $temp_item_marc, $frameworkcode, '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;
=cut
-our %default_values_for_mod_from_marc;
-
sub _build_default_values_for_mod_marc {
my ($frameworkcode) = @_;
- return $default_values_for_mod_from_marc{$frameworkcode}
- if exists $default_values_for_mod_from_marc{$frameworkcode};
- my $marc_structure = C4::Biblio::GetMarcStructure( 1, $frameworkcode );
+
+ my $cache = Koha::Caches->get_instance();
+ my $cache_key = "default_value_for_mod_marc-$frameworkcode";
+ my $cached = $cache->get_from_cache($cache_key);
+ return $cached if $cached;
+
my $default_values = {
barcode => undef,
booksellerid => undef,
location => undef,
permanent_location => undef,
materials => undef,
+ new_status => undef,
notforloan => 0,
# paidfor => undef, # commented, see bug 12817
price => undef,
uri => undef,
withdrawn => 0,
};
+ my %default_values_for_mod_from_marc;
while ( my ( $field, $default_value ) = each %$default_values ) {
my $kohafield = $field;
$kohafield =~ s|^([^\.]+)$|items.$1|;
- $default_values_for_mod_from_marc{$frameworkcode}{$field} =
+ $default_values_for_mod_from_marc{$field} =
$default_value
if C4::Koha::IsKohaFieldLinked(
{ kohafield => $kohafield, frameworkcode => $frameworkcode } );
}
- return $default_values_for_mod_from_marc{$frameworkcode};
+
+ $cache->set_in_cache($cache_key, \%default_values_for_mod_from_marc);
+ return \%default_values_for_mod_from_marc;
}
sub ModItemFromMarc {
my $localitemmarc = MARC::Record->new;
$localitemmarc->append_fields( $item_marc->field($itemtag) );
- my $item = &TransformMarcToKoha( $dbh, $localitemmarc, $frameworkcode, 'items' );
- my $default_values = _build_default_values_for_mod_marc();
+ my $item = &TransformMarcToKoha( $localitemmarc, $frameworkcode, 'items' );
+ my $default_values = _build_default_values_for_mod_marc($frameworkcode);
foreach my $item_field ( keys %$default_values ) {
$item->{$item_field} = $default_values->{$item_field}
unless exists $item->{$item_field};
sub ModDateLastSeen {
my ($itemnumber) = @_;
- my $today = C4::Dates->new();
- ModItem({ itemlost => 0, datelastseen => $today->output("iso") }, undef, $itemnumber);
+ my $today = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
+ ModItem({ itemlost => 0, datelastseen => $today }, undef, $itemnumber);
}
=head2 DelItem
sub CheckItemPreSave {
my $item_ref = shift;
- require C4::Branch;
my %errors = ();
# check for valid home branch
if (exists $item_ref->{'homebranch'} and defined $item_ref->{'homebranch'}) {
- my $branch_name = C4::Branch::GetBranchName($item_ref->{'homebranch'});
- unless (defined $branch_name) {
- # relies on fact that branches.branchname is a non-NULL column,
- # so GetBranchName returns undef only if branch does not exist
+ my $home_library = Koha::Libraries->find( $item_ref->{homebranch} );
+ unless (defined $home_library) {
$errors{'invalid_homebranch'} = $item_ref->{'homebranch'};
}
}
# check for valid holding branch
if (exists $item_ref->{'holdingbranch'} and defined $item_ref->{'holdingbranch'}) {
- my $branch_name = C4::Branch::GetBranchName($item_ref->{'holdingbranch'});
- unless (defined $branch_name) {
- # relies on fact that branches.branchname is a non-NULL column,
- # so GetBranchName returns undef only if branch does not exist
+ my $holding_library = Koha::Libraries->find( $item_ref->{holdingbranch} );
+ unless (defined $holding_library) {
$errors{'invalid_holdingbranch'} = $item_ref->{'holdingbranch'};
}
}
branch => $branch,
offset => $offset,
size => $size,
- stautshash => $statushash
+ statushash => $statushash,
interface => $interface,
} );
}
if ($datelastseen) {
- $datelastseen = format_date_in_iso($datelastseen);
+ $datelastseen = output_pref({ str => $datelastseen, dateformat => 'iso', dateonly => 1 });
push @where_strings, '(datelastseen < ? OR datelastseen IS NULL)';
push @bind_params, $datelastseen;
}
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 = "
SELECT items.*,
biblio.*,
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
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 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($biblionumber);
+ $sth->execute($language, $biblionumber);
my $i = 0;
my @results;
my $serial;
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';
+ my ($biblionumber) = @_;
+ my $marcrecord = GetMarcBiblio($biblionumber);
+
+ return unless $marcrecord;
+
+ 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})
+ if ( my $itemnumbers =
+ get_itemnumbers_of($hostbiblionumber)->{$hostbiblionumber} )
{
@itemnumbers = @$itemnumbers;
}
- foreach my $itemnumber (@itemnumbers){
- if ($itemnumber eq $linkeditemnumber){
- push (@returnhostitemnumbers,$itemnumber);
+ foreach my $itemnumber (@itemnumbers) {
+ if ( $itemnumber eq $linkeditemnumber ) {
+ push( @returnhostitemnumbers, $itemnumber );
last;
}
}
}
+
return @returnhostitemnumbers;
}
return @resultitems;
}
-=head3 get_item_authorised_values
-
-find the types and values for all authorised values assigned to this item.
-
-parameters: itemnumber
-
-returns: a hashref malling the authorised value to the value set for this itemnumber
-
- $authorised_values = {
- 'CCODE' => undef,
- 'DAMAGED' => '0',
- 'LOC' => '3',
- 'LOST' => '0'
- 'NOT_LOAN' => '0',
- 'RESTRICTED' => undef,
- 'STACK' => undef,
- 'WITHDRAWN' => '0',
- 'branches' => 'CPL',
- 'cn_source' => undef,
- 'itemtypes' => 'SER',
- };
-
-Notes: see C4::Biblio::get_biblio_authorised_values for a similar method at the biblio level.
-
-=cut
-
-sub get_item_authorised_values {
- my $itemnumber = shift;
-
- # assume that these entries in the authorised_value table are item level.
- my $query = q(SELECT distinct authorised_value, kohafield
- FROM marc_subfield_structure
- WHERE kohafield like 'item%'
- AND authorised_value != '' );
-
- my $itemlevel_authorised_values = C4::Context->dbh->selectall_hashref( $query, 'authorised_value' );
- my $iteminfo = GetItem( $itemnumber );
- # warn( Data::Dumper->Dump( [ $itemlevel_authorised_values ], [ 'itemlevel_authorised_values' ] ) );
- my $return;
- foreach my $this_authorised_value ( keys %$itemlevel_authorised_values ) {
- my $field = $itemlevel_authorised_values->{ $this_authorised_value }->{'kohafield'};
- $field =~ s/^items\.//;
- if ( exists $iteminfo->{ $field } ) {
- $return->{ $this_authorised_value } = $iteminfo->{ $field };
- }
- }
- # warn( Data::Dumper->Dump( [ $return ], [ 'return' ] ) );
- return $return;
-}
-
-=head3 get_authorised_value_images
-
-find a list of icons that are appropriate for display based on the
-authorised values for a biblio.
-
-parameters: listref of authorised values, such as comes from
-get_item_authorised_values or
-from C4::Biblio::get_biblio_authorised_values
-
-returns: listref of hashrefs for each image. Each hashref looks like this:
-
- { imageurl => '/intranet-tmpl/prog/img/itemtypeimg/npl/WEB.gif',
- label => '',
- category => '',
- value => '', }
-
-Notes: Currently, I put on the full path to the images on the staff
-side. This should either be configurable or not done at all. Since I
-have to deal with 'intranet' or 'opac' in
-get_biblio_authorised_values, perhaps I should be passing it in.
-
-=cut
-
-sub get_authorised_value_images {
- my $authorised_values = shift;
-
- my @imagelist;
-
- my $authorised_value_list = GetAuthorisedValues();
- # warn ( Data::Dumper->Dump( [ $authorised_value_list ], [ 'authorised_value_list' ] ) );
- foreach my $this_authorised_value ( @$authorised_value_list ) {
- if ( exists $authorised_values->{ $this_authorised_value->{'category'} }
- && $authorised_values->{ $this_authorised_value->{'category'} } eq $this_authorised_value->{'authorised_value'} ) {
- # warn ( Data::Dumper->Dump( [ $this_authorised_value ], [ 'this_authorised_value' ] ) );
- if ( defined $this_authorised_value->{'imageurl'} ) {
- push @imagelist, { imageurl => C4::Koha::getitemtypeimagelocation( 'intranet', $this_authorised_value->{'imageurl'} ),
- label => $this_authorised_value->{'lib'},
- category => $this_authorised_value->{'category'},
- value => $this_authorised_value->{'authorised_value'}, };
- }
- }
- }
-
- # warn ( Data::Dumper->Dump( [ \@imagelist ], [ 'imagelist' ] ) );
- return \@imagelist;
-
-}
-
=head1 LIMITED USE FUNCTIONS
The following functions, while part of the public API,
(not defined $item->{'withdrawn'} or $item->{'withdrawn'} eq '')) {
$item->{'withdrawn'} = 0;
}
- if (exists $item->{'location'} && !$item->{'permanent_location'}) {
+ if (exists $item->{location}
+ and $item->{location} ne 'CART'
+ and $item->{location} ne 'PROC'
+ and not $item->{permanent_location}
+ ) {
$item->{'permanent_location'} = $item->{'location'};
}
if (exists $item->{'timestamp'}) {
sub _set_defaults_for_add {
my $item = shift;
- $item->{dateaccessioned} ||= C4::Dates->new->output('iso');
+ $item->{dateaccessioned} ||= output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
$item->{$_} ||= 0 for (qw( notforloan damaged itemlost withdrawn));
}
my ( $item, $barcode ) = @_;
my $dbh=C4::Context->dbh;
my $error;
+ $item->{permanent_location} //= $item->{location};
my $query =
"INSERT INTO items SET
biblionumber = ?,
notforloan = ?,
damaged = ?,
itemlost = ?,
- withdrawn = ?,
+ withdrawn = ?,
itemcallnumber = ?,
coded_location_qualifier = ?,
restricted = ?,
holdingbranch = ?,
paidfor = ?,
location = ?,
- permanent_location = ?,
+ permanent_location = ?,
onloan = ?,
issues = ?,
renewals = ?,
ccode = ?,
itype = ?,
materials = ?,
- uri = ?,
+ uri = ?,
enumchron = ?,
more_subfields_xml = ?,
copynumber = ?,
- stocknumber = ?
+ stocknumber = ?,
+ new_status = ?
";
my $sth = $dbh->prepare($query);
- my $today = C4::Dates->today('iso');
+ my $today = output_pref({ dt => dt_from_string, dateformat => 'iso', dateonly => 1 });
$sth->execute(
$item->{'biblionumber'},
$item->{'biblioitemnumber'},
$item->{'more_subfields_xml'},
$item->{'copynumber'},
$item->{'stocknumber'},
+ $item->{'new_status'},
);
my $itemnumber;
return;
}
-=head2 DelItemCheck
+=head2 ItemSafeToDelete
- DelItemCheck($dbh, $biblionumber, $itemnumber);
+ ItemSafeToDelete( $biblionumber, $itemnumber);
-Exported function (core API) for deleting an item record in Koha if there no current issue.
+Exported function (core API) for checking whether an item record is safe to delete.
+
+returns 1 if the item is safe to delete,
+
+"book_on_loan" if the item is checked out,
+
+"not_same_branch" if the item is blocked by independent branches,
+
+"book_reserved" if the there are holds aganst the item, or
+
+"linked_analytics" if the item has linked analytic records.
=cut
-sub DelItemCheck {
- my ( $dbh, $biblionumber, $itemnumber ) = @_;
- my $error;
+sub ItemSafeToDelete {
+ my ( $biblionumber, $itemnumber ) = @_;
+ my $status;
+ my $dbh = C4::Context->dbh;
- my $countanalytics=GetAnalyticsCount($itemnumber);
+ my $error;
+ my $countanalytics = GetAnalyticsCount($itemnumber);
# check that there is no issue on this item before deletion.
- my $sth = $dbh->prepare(q{
+ my $sth = $dbh->prepare(
+ q{
SELECT COUNT(*) FROM issues
WHERE itemnumber = ?
- });
+ }
+ );
$sth->execute($itemnumber);
my ($onloan) = $sth->fetchrow;
my $item = GetItem($itemnumber);
- if ($onloan){
- $error = "book_on_loan"
+ if ($onloan) {
+ $status = "book_on_loan";
}
- elsif ( !C4::Context->IsSuperLibrarian()
+ elsif ( defined C4::Context->userenv
+ and !C4::Context->IsSuperLibrarian()
and C4::Context->preference("IndependentBranches")
and ( C4::Context->userenv->{branch} ne $item->{'homebranch'} ) )
{
- $error = "not_same_branch";
+ $status = "not_same_branch";
}
- else{
+ else {
# check it doesn't have a waiting reserve
- $sth = $dbh->prepare(q{
+ $sth = $dbh->prepare(
+ q{
SELECT COUNT(*) 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(
- {
- biblionumber => $biblionumber,
- itemnumber => $itemnumber
- }
- );
- return 1;
+ if ($reserve) {
+ $status = "book_reserved";
+ }
+ elsif ( $countanalytics > 0 ) {
+ $status = "linked_analytics";
+ }
+ else {
+ $status = 1;
}
}
- return $error;
+ return $status;
+}
+
+=head2 DelItemCheck
+
+ DelItemCheck( $biblionumber, $itemnumber);
+
+Exported function (core API) for deleting an item record in Koha if there no current issue.
+
+DelItemCheck wraps ItemSafeToDelete around DelItem.
+
+=cut
+
+sub DelItemCheck {
+ my ( $biblionumber, $itemnumber ) = @_;
+ my $status = ItemSafeToDelete( $biblionumber, $itemnumber );
+
+ if ( $status == 1 ) {
+ DelItem(
+ {
+ biblionumber => $biblionumber,
+ itemnumber => $itemnumber
+ }
+ );
+ }
+ return $status;
}
=head2 _koha_modify_item
sub GetAnalyticsCount {
my ($itemnumber) = @_;
- require C4::Search;
### ZOOM search here
my $query;
$query= "hi=".$itemnumber;
- my ($err,$res,$result) = C4::Search::SimpleSearch($query,0,10);
+ my $searcher = Koha::SearchEngine::Search->new({index => $Koha::SearchEngine::BIBLIOS_INDEX});
+ my ($err,$res,$result) = $searcher->simple_search_compat($query,0,10);
return ($result);
}
# loop through each subfield
my $cntsubf;
foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
- next if ( subfield_is_koha_internal_p($subfield) );
+ next if IsMarcStructureInternal($tagslib->{$tag}{$subfield});
next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
my %subfield_data;
$subfield_data{tag} = $tag;
#----- itemtypes
} elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
- my $sth = $dbh->prepare( "SELECT itemtype,description FROM itemtypes ORDER BY description" );
- $sth->execute;
+ my $itemtypes = GetItemTypes( style => 'array' );
push @authorised_values, ""
unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
- while ( my ( $itemtype, $description ) = $sth->fetchrow_array ) {
- push @authorised_values, $itemtype;
- $authorised_lib{$itemtype} = $description;
+ for my $itemtype ( @$itemtypes ) {
+ push @authorised_values, $itemtype->{itemtype};
+ $authorised_lib{$itemtype->{itemtype}} = $itemtype->{translated_description};
}
#---- class_sources
} elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "cn_source" ) {
};
}
+sub ToggleNewStatus {
+ my ( $params ) = @_;
+ my @rules = @{ $params->{rules} };
+ my $report_only = $params->{report_only};
+
+ my $dbh = C4::Context->dbh;
+ my @errors;
+ my @item_columns = map { "items.$_" } Koha::Items->columns;
+ my @biblioitem_columns = map { "biblioitems.$_" } Koha::Biblioitems->columns;
+ my $report;
+ for my $rule ( @rules ) {
+ my $age = $rule->{age};
+ my $conditions = $rule->{conditions};
+ my $substitutions = $rule->{substitutions};
+ my @params;
+
+ my $query = q|
+ SELECT items.biblionumber, items.itemnumber
+ FROM items
+ LEFT JOIN biblioitems ON biblioitems.biblionumber = items.biblionumber
+ WHERE 1
+ |;
+ for my $condition ( @$conditions ) {
+ if (
+ grep {/^$condition->{field}$/} @item_columns
+ or grep {/^$condition->{field}$/} @biblioitem_columns
+ ) {
+ if ( $condition->{value} =~ /\|/ ) {
+ my @values = split /\|/, $condition->{value};
+ $query .= qq| AND $condition->{field} IN (|
+ . join( ',', ('?') x scalar @values )
+ . q|)|;
+ push @params, @values;
+ } else {
+ $query .= qq| AND $condition->{field} = ?|;
+ push @params, $condition->{value};
+ }
+ }
+ }
+ if ( defined $age ) {
+ $query .= q| AND TO_DAYS(NOW()) - TO_DAYS(dateaccessioned) >= ? |;
+ push @params, $age;
+ }
+ my $sth = $dbh->prepare($query);
+ $sth->execute( @params );
+ while ( my $values = $sth->fetchrow_hashref ) {
+ my $biblionumber = $values->{biblionumber};
+ my $itemnumber = $values->{itemnumber};
+ my $item = C4::Items::GetItem( $itemnumber );
+ for my $substitution ( @$substitutions ) {
+ next unless $substitution->{field};
+ C4::Items::ModItem( {$substitution->{field} => $substitution->{value}}, $biblionumber, $itemnumber )
+ unless $report_only;
+ push @{ $report->{$itemnumber} }, $substitution;
+ }
+ }
+ }
+
+ return $report;
+}
+
+
1;