use C4::Log;
use C4::Branch;
require C4::Reserves;
+use C4::Charset;
use vars qw($VERSION @ISA @EXPORT);
ModDateLastSeen
ModItemTransfer
DelItem
+ DelItemCheck
CheckItemPreSave
$ssth->execute($data->{'itemnumber'}) ;
($data->{'serialseq'} , $data->{'publisheddate'}) = $ssth->fetchrow_array();
warn $data->{'serialseq'} , $data->{'publisheddate'};
- }
+ }
+ #if we don't have an items.itype, use biblioitems.itemtype.
+ if( ! $data->{'itype'} ) {
+ my $sth = $dbh->prepare("SELECT itemtype FROM biblioitems WHERE biblionumber = ?");
+ $sth->execute($data->{'biblionumber'});
+ ($data->{'itype'}) = $sth->fetchrow_array;
+ }
return $data;
} # sub GetItem
# parse item hash from MARC
my $frameworkcode = GetFrameworkCode( $biblionumber );
- my $item = &TransformMarcToKoha( $dbh, $source_item_marc, $frameworkcode );
- return AddItem($item, $biblionumber, $dbh, $frameworkcode);
+ my ($itemtag,$itemsubfield)=GetMarcFromKohaField("items.itemnumber",$frameworkcode);
+
+ my $localitemmarc=MARC::Record->new;
+ $localitemmarc->append_fields($source_item_marc->field($itemtag));
+ my $item = &TransformMarcToKoha( $dbh, $localitemmarc, $frameworkcode ,'items');
+ my $unlinked_item_subfields = _get_unlinked_item_subfields($localitemmarc, $frameworkcode);
+ return AddItem($item, $biblionumber, $dbh, $frameworkcode, $unlinked_item_subfields);
}
=head2 AddItem
=over 4
my ($biblionumber, $biblioitemnumber, $itemnumber)
- = AddItem($item, $biblionumber[, $dbh, $frameworkcode]);
+ = AddItem($item, $biblionumber[, $dbh, $frameworkcode, $unlinked_item_subfields]);
=back
Given a hash containing item column names as keys,
create a new Koha item record.
-The two optional parameters (C<$dbh> and C<$frameworkcode>)
+The first two optional parameters (C<$dbh> and C<$frameworkcode>)
do not need to be supplied for general use; they exist
simply to allow them to be picked up from AddItemFromMarc.
+The final optional parameter, C<$unlinked_item_subfields>, contains
+an arrayref containing subfields present in the original MARC
+representation of the item (e.g., from the item editor) that are
+not mapped to C<items> columns directly but should instead
+be stored in C<items.more_subfields_xml> and included in
+the biblio items tag for display and indexing.
+
=cut
sub AddItem {
my $dbh = @_ ? shift : C4::Context->dbh;
my $frameworkcode = @_ ? shift : GetFrameworkCode( $biblionumber );
+ my $unlinked_item_subfields;
+ if (@_) {
+ $unlinked_item_subfields = shift
+ };
# needs old biblionumber and biblioitemnumber
$item->{'biblionumber'} = $biblionumber;
_set_defaults_for_add($item);
_set_derived_columns_for_add($item);
+ $item->{'more_subfields_xml'} = _get_unlinked_subfields_xml($unlinked_item_subfields);
# FIXME - checks here
- my ( $itemnumber, $error ) = _koha_new_item( $dbh, $item, $item->{barcode} );
+ unless ( $item->{itype} ) { # default to biblioitem.itemtype if no itype
+ my $itype_sth = $dbh->prepare("SELECT itemtype FROM biblioitems WHERE biblionumber = ?");
+ $itype_sth->execute( $item->{'biblionumber'} );
+ ( $item->{'itype'} ) = $itype_sth->fetchrow_array;
+ }
+
+ 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);
+ my $new_item_marc = _marc_from_item_hash($item, $frameworkcode, $unlinked_item_subfields);
_add_item_field_to_biblio($new_item_marc, $item->{'biblionumber'}, $frameworkcode );
- logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$itemnumber,"item")
- if C4::Context->preference("CataloguingLog");
+ logaction("CATALOGUING", "ADD", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
return ($item->{biblionumber}, $item->{biblioitemnumber}, $itemnumber);
}
# add biblionumber and biblioitemnumber
my $item = TransformMarcToKoha( $dbh, $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;
$item->{'biblioitemnumber'} = $biblioitemnumber;
_set_defaults_for_add($item);
_set_derived_columns_for_add($item);
- my ( $itemnumber, $error ) = _koha_new_item( $dbh, $item, $item->{barcode} );
+ my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} );
warn $error if $error;
push @itemnumbers, $itemnumber; # FIXME not checking error
$item->{'itemnumber'} = $itemnumber;
- &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$itemnumber,"item")
- if C4::Context->preference("CataloguingLog");
+ logaction("CATALOGUING", "ADD", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
- my $new_item_marc = _marc_from_item_hash($item, $frameworkcode);
+ my $new_item_marc = _marc_from_item_hash($item, $frameworkcode, $unlinked_item_subfields);
$item_field->replace_with($new_item_marc->field($itemtag));
}
This API is meant for the use of C<additem.pl>; for
other purposes, C<ModItem> should be used.
+This function uses the hash %default_values_for_mod_from_marc,
+which contains default values for item fields to
+apply when modifying an item. This is needed beccause
+if an item field's value is cleared, TransformMarcToKoha
+does not include the column in the
+hash that's passed to ModItem, which without
+use of this hash makes it impossible to clear
+an item field's value. See bug 2466.
+
+Note that only columns that can be directly
+changed from the cataloging and serials
+item editors are included in this hash.
+
=cut
+my %default_values_for_mod_from_marc = (
+ barcode => undef,
+ booksellerid => undef,
+ ccode => undef,
+ 'items.cn_source' => undef,
+ copynumber => undef,
+ damaged => 0,
+ dateaccessioned => undef,
+ enumchron => undef,
+ holdingbranch => undef,
+ homebranch => undef,
+ itemcallnumber => undef,
+ itemlost => 0,
+ itemnotes => undef,
+ itype => undef,
+ location => undef,
+ materials => undef,
+ notforloan => 0,
+ paidfor => undef,
+ price => undef,
+ replacementprice => undef,
+ replacementpricedate => undef,
+ restricted => undef,
+ stack => undef,
+ uri => undef,
+ wthdrawn => 0,
+);
+
sub ModItemFromMarc {
my $item_marc = shift;
my $biblionumber = shift;
my $dbh = C4::Context->dbh;
my $frameworkcode = GetFrameworkCode( $biblionumber );
- my $item = &TransformMarcToKoha( $dbh, $item_marc, $frameworkcode );
-
- return ModItem($item, $biblionumber, $itemnumber, $dbh, $frameworkcode);
+ my ($itemtag,$itemsubfield)=GetMarcFromKohaField("items.itemnumber",$frameworkcode);
+
+ my $localitemmarc=MARC::Record->new;
+ $localitemmarc->append_fields($item_marc->field($itemtag));
+ my $item = &TransformMarcToKoha( $dbh, $localitemmarc, $frameworkcode, 'items');
+ foreach my $item_field (keys %default_values_for_mod_from_marc) {
+ $item->{$item_field} = $default_values_for_mod_from_marc{$item_field} unless exists $item->{$item_field};
+ }
+ my $unlinked_item_subfields = _get_unlinked_item_subfields($localitemmarc, $frameworkcode);
+
+ return ModItem($item, $biblionumber, $itemnumber, $dbh, $frameworkcode, $unlinked_item_subfields);
}
=head2 ModItem
=over 4
-ModItem({ column => $newvalue }, $biblionumber, $itemnumber);
+ModItem({ column => $newvalue }, $biblionumber, $itemnumber[, $original_item_marc]);
=back
names to the new values. The second and third arguments
are the biblionumber and itemnumber, respectively.
+The fourth, optional parameter, C<$unlinked_item_subfields>, contains
+an arrayref containing subfields present in the original MARC
+representation of the item (e.g., from the item editor) that are
+not mapped to C<items> columns directly but should instead
+be stored in C<items.more_subfields_xml> and included in
+the biblio items tag for display and indexing.
+
If one of the changed columns is used to calculate
the derived value of a column such as C<items.cn_sort>,
this routine will perform the necessary calculation
my $dbh = @_ ? shift : C4::Context->dbh;
my $frameworkcode = @_ ? shift : GetFrameworkCode( $biblionumber );
+
+ my $unlinked_item_subfields;
+ if (@_) {
+ $unlinked_item_subfields = shift;
+ $item->{'more_subfields_xml'} = _get_unlinked_subfields_xml($unlinked_item_subfields);
+ };
$item->{'itemnumber'} = $itemnumber or return undef;
_set_derived_columns_for_mod($item);
# it should be a separate function)
# update items table
- _koha_modify_item($dbh, $item);
+ _koha_modify_item($item);
# update biblio MARC XML
my $whole_item = GetItem($itemnumber) or die "FAILED GetItem($itemnumber)";
- my $new_item_marc = _marc_from_item_hash($whole_item, $frameworkcode) or die "FAILED _marc_from_item_hash($whole_item, $frameworkcode)";
+
+ 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);
- (C4::Context->userenv eq '0') and die "userenv is '0', not hashref"; # logaction line would crash anyway
($new_item_marc eq '0') and die "$new_item_marc is '0', not hashref"; # logaction line would crash anyway
- logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$itemnumber,$new_item_marc->as_formatted)
- if C4::Context->preference("CataloguingLog");
+ logaction("CATALOGUING", "MODIFY", $itemnumber, $new_item_marc->as_formatted) if C4::Context->preference("CataloguingLog");
}
=head2 ModItemTransfer
}
}
&ModBiblioMarc( $record, $biblionumber, $frameworkcode );
- &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$itemnumber,"item")
- if C4::Context->preference("CataloguingLog");
+ logaction("CATALOGUING", "DELETE", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
+}
+
+=head2 DelItemCheck
+
+=over 4
+
+DelItemCheck($dbh, $biblionumber, $itemnumber);
+
+=back
+
+Exported function (core API) for deleting an item record in Koha if there no current issue.
+
+=cut
+
+sub DelItemCheck {
+ my ( $dbh, $biblionumber, $itemnumber ) = @_;
+ my $error;
+
+ # 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 $onloan=$sth->fetchrow;
+
+ $sth->finish();
+ if ($onloan){
+ $error = "book_on_loan"
+ }else{
+ # check it doesnt have a waiting reserve
+ $sth=$dbh->prepare("SELECT * FROM reserves WHERE found = 'W' AND itemnumber = ?");
+ $sth->execute($itemnumber);
+ my $reserve=$sth->fetchrow;
+ $sth->finish();
+ if ($reserve){
+ $error = "book_reserved";
+ }else{
+ DelItem($dbh, $biblionumber, $itemnumber);
+ return 1;
+ }
+ }
+ return $error;
}
=head2 CheckItemPreSave
=over 4
-$items = GetLostItems($where,$orderby);
+$items = GetLostItems( $where, $orderby );
=back
-This function get the items lost into C<$items>.
+This function gets a list of lost items.
=over 2
=item input:
+
C<$where> is a hashref. it containts a field of the items table as key
-and the value to match as value.
-C<$orderby> is a field of the items table.
+and the value to match as value. For example:
+
+{ barcode => 'abc123',
+ homebranch => 'CPL', }
+
+C<$orderby> is a field of the items table by which the resultset
+should be orderd.
=item return:
-C<$items> is a reference to an array full of hasref which keys are items' table column.
+
+C<$items> is a reference to an array full of hashrefs with columns
+from the "items" table as keys.
=item usage in the perl script:
-my %where;
-$where{barcode} = 0001548;
-my $items = GetLostItems( \%where, "homebranch" );
-$template->param(itemsloop => $items);
+my $where = { barcode => '0001548' };
+my $items = GetLostItems( $where, "homebranch" );
+$template->param( itemsloop => $items );
=back
my $query = "
SELECT *
FROM items
- WHERE itemlost IS NOT NULL
- AND itemlost <> 0
+ LEFT JOIN biblio ON (items.biblionumber = biblio.biblionumber)
+ LEFT JOIN biblioitems ON (items.biblionumber = biblioitems.biblionumber)
+ LEFT JOIN authorised_values ON (items.itemlost = authorised_values.authorised_value)
+ WHERE
+ authorised_values.category = 'LOST'
+ AND itemlost IS NOT NULL
+ AND itemlost <> 0
";
+ my @query_parameters;
foreach my $key (keys %$where) {
- $query .= " AND " . $key . " LIKE '%" . $where->{$key} . "%'";
+ $query .= " AND $key LIKE ?";
+ push @query_parameters, "%$where->{$key}%";
+ }
+ my @ordervalues = qw/title author homebranch itype barcode price replacementprice lib datelastseen location/;
+
+ if ( defined $orderby && grep($orderby, @ordervalues)) {
+ $query .= ' ORDER BY '.$orderby;
}
- $query .= " ORDER BY ".$orderby if defined $orderby;
my $sth = $dbh->prepare($query);
- $sth->execute;
- my @items;
+ $sth->execute( @query_parameters );
+ my $items = [];
while ( my $row = $sth->fetchrow_hashref ){
- push @items, $row;
+ push @$items, $row;
}
- return \@items;
+ return $items;
}
=head2 GetItemsForInventory
=over 4
-$itemlist = GetItemsForInventory($minlocation,$maxlocation,$datelastseen,$offset,$size)
+$itemlist = GetItemsForInventory($minlocation, $maxlocation, $location, $itemtype $datelastseen, $branch, $offset, $size);
=back
Retrieve a list of title/authors/barcode/callnumber, for biblio inventory.
-The sub returns a list of hashes, containing itemnumber, author, title, barcode & item callnumber.
-It is ordered by callnumber,title.
+The sub returns a reference to a list of hashes, each containing
+itemnumber, author, title, barcode, item callnumber, and date last
+seen. It is ordered by callnumber then title.
-The minlocation & maxlocation parameters are used to specify a range of item callnumbers
+The required minlocation & maxlocation parameters are used to specify a range of item callnumbers
the datelastseen can be used to specify that you want to see items not seen since a past date only.
offset & size can be used to retrieve only a part of the whole listing (defaut behaviour)
=cut
sub GetItemsForInventory {
- my ( $minlocation, $maxlocation,$location, $datelastseen, $branch, $offset, $size ) = @_;
+ my ( $minlocation, $maxlocation,$location, $itemtype, $ignoreissued, $datelastseen, $branch, $offset, $size ) = @_;
my $dbh = C4::Context->dbh;
- my $sth;
+ my ( @bind_params, @where_strings );
+
+ my $query = <<'END_SQL';
+SELECT items.itemnumber, barcode, itemcallnumber, title, author, biblio.biblionumber, datelastseen
+FROM items
+ LEFT JOIN biblio ON items.biblionumber = biblio.biblionumber
+ LEFT JOIN biblioitems on items.biblionumber = biblioitems.biblionumber
+END_SQL
+
+ if ($minlocation) {
+ push @where_strings, 'itemcallnumber >= ?';
+ push @bind_params, $minlocation;
+ }
+
+ if ($maxlocation) {
+ push @where_strings, 'itemcallnumber <= ?';
+ push @bind_params, $maxlocation;
+ }
+
if ($datelastseen) {
- $datelastseen=format_date_in_iso($datelastseen);
- my $query =
- "SELECT itemnumber,barcode,itemcallnumber,title,author,biblio.biblionumber,datelastseen
- FROM items
- LEFT JOIN biblio ON items.biblionumber=biblio.biblionumber
- WHERE itemcallnumber>= ?
- AND itemcallnumber <=?
- AND (datelastseen< ? OR datelastseen IS NULL)";
- $query.= " AND items.location=".$dbh->quote($location) if $location;
- $query.= " AND items.homebranch=".$dbh->quote($branch) if $branch;
- $query .= " ORDER BY itemcallnumber,title";
- $sth = $dbh->prepare($query);
- $sth->execute( $minlocation, $maxlocation, $datelastseen );
+ $datelastseen = format_date_in_iso($datelastseen);
+ push @where_strings, '(datelastseen < ? OR datelastseen IS NULL)';
+ push @bind_params, $datelastseen;
}
- else {
- my $query ="
- SELECT itemnumber,barcode,itemcallnumber,biblio.biblionumber,title,author,datelastseen
- FROM items
- LEFT JOIN biblio ON items.biblionumber=biblio.biblionumber
- WHERE itemcallnumber>= ?
- AND itemcallnumber <=?";
- $query.= " AND items.location=".$dbh->quote($location) if $location;
- $query.= " AND items.homebranch=".$dbh->quote($branch) if $branch;
- $query .= " ORDER BY itemcallnumber,title";
- $sth = $dbh->prepare($query);
- $sth->execute( $minlocation, $maxlocation );
+
+ if ( $location ) {
+ push @where_strings, 'items.location = ?';
+ push @bind_params, $location;
+ }
+
+ if ( $branch ) {
+ push @where_strings, 'items.homebranch = ?';
+ push @bind_params, $branch;
}
+
+ if ( $itemtype ) {
+ push @where_strings, 'biblioitems.itemtype = ?';
+ push @bind_params, $itemtype;
+ }
+ if ( $ignoreissued) {
+ $query .= "LEFT JOIN issues ON items.itemnumber = issues.itemnumber ";
+ push @where_strings, 'issues.date_due IS NULL';
+ }
+
+ if ( $ignoreissued) {
+ $query .= "LEFT JOIN issues ON items.itemnumber = issues.itemnumber ";
+ push @where_strings, 'issues.date_due IS NULL';
+ }
+
+ if ( @where_strings ) {
+ $query .= 'WHERE ';
+ $query .= join ' AND ', @where_strings;
+ }
+ $query .= ' ORDER BY itemcallnumber, title';
+ my $sth = $dbh->prepare($query);
+ $sth->execute( @bind_params );
+
my @results;
+ $size--;
while ( my $row = $sth->fetchrow_hashref ) {
$offset-- if ($offset);
$row->{datelastseen}=format_date($row->{datelastseen});
# Foreach item, get circulation information
my $sth2 = $dbh->prepare( "SELECT * FROM issues,borrowers
WHERE itemnumber = ?
- AND returndate is NULL
AND issues.borrowernumber = borrowers.borrowernumber"
);
$sth2->execute( $data->{'itemnumber'} );
} # else
$sth2->finish;
# Find the last 3 people who borrowed this item.
- my $query2 = "SELECT * FROM issues, borrowers WHERE itemnumber = ?
- AND issues.borrowernumber = borrowers.borrowernumber
- AND returndate is not NULL
+ my $query2 = "SELECT * FROM old_issues, borrowers WHERE itemnumber = ?
+ AND old_issues.borrowernumber = borrowers.borrowernumber
ORDER BY returndate desc,timestamp desc LIMIT 3";
$sth2 = $dbh->prepare($query2) || die $dbh->errstr;
$sth2->execute( $data->{'itemnumber'} ) || die $sth2->errstr;
sub GetItemsInfo {
my ( $biblionumber, $type ) = @_;
my $dbh = C4::Context->dbh;
- my $query = "SELECT *,items.notforloan as itemnotforloan
- FROM items
- LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
- LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber";
- $query .= (C4::Context->preference('item-level_itypes')) ?
- " LEFT JOIN itemtypes on items.itype = itemtypes.itemtype "
- : " LEFT JOIN itemtypes on biblioitems.itemtype = itemtypes.itemtype ";
- $query .= "WHERE items.biblionumber = ? ORDER BY items.dateaccessioned desc" ;
+ # note biblioitems.* must be avoided to prevent large marc and marcxml fields from killing performance.
+ 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,
+ itemtypes.description
+ FROM items
+ LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
+ LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
+ LEFT JOIN itemtypes ON itemtypes.itemtype = "
+ . (C4::Context->preference('item-level_itypes') ? 'items.itype' : 'biblioitems.itemtype');
+ $query .= " WHERE items.biblionumber = ? ORDER BY items.dateaccessioned desc" ;
my $sth = $dbh->prepare($query);
$sth->execute($biblionumber);
my $i = 0;
my @results;
- my ( $date_due, $count_reserves, $serial );
+ my $serial;
my $isth = $dbh->prepare(
"SELECT issues.*,borrowers.cardnumber,borrowers.surname,borrowers.firstname,borrowers.branchcode as bcode
FROM issues LEFT JOIN borrowers ON issues.borrowernumber=borrowers.borrowernumber
- WHERE itemnumber = ?
- AND returndate IS NULL"
+ WHERE itemnumber = ?"
);
my $ssth = $dbh->prepare("SELECT serialseq,publisheddate from serialitems left join serial on serialitems.serialid=serial.serialid where serialitems.itemnumber=? ");
while ( my $data = $sth->fetchrow_hashref ) {
- warn $data->{itemnumber};
+ my $count_reserves;
my $datedue = '';
$isth->execute( $data->{'itemnumber'} );
if ( my $idata = $isth->fetchrow_hashref ) {
if ( $data->{'serial'}) {
$ssth->execute($data->{'itemnumber'}) ;
($data->{'serialseq'} , $data->{'publisheddate'}) = $ssth->fetchrow_array();
- warn $data->{'serialseq'} , $data->{'publisheddate'};
$serial = 1;
}
if ( $datedue eq '' ) {
$sthnflstatus->execute( $authorised_valuecode,
$data->{itemnotforloan} );
my ($lib) = $sthnflstatus->fetchrow;
- $data->{notforloan} = $lib;
+ $data->{notforloanvalue} = $lib;
}
+ $data->{itypenotforloan} = $data->{notforloan} if (C4::Context->preference('item-level_itypes'));
# my stack procedures
my $stackstatus = $dbh->prepare(
$data->{stack} = $lib;
}
# Find the last 3 people who borrowed this item.
- my $sth2 = $dbh->prepare("SELECT * FROM issues,borrowers
+ my $sth2 = $dbh->prepare("SELECT * FROM old_issues,borrowers
WHERE itemnumber = ?
- AND issues.borrowernumber = borrowers.borrowernumber
- AND returndate IS NOT NULL LIMIT 3");
+ 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()) {
$results[$i] = $data;
$i++;
}
- $sth->finish;
if($serial) {
- return( sort { $b->{'publisheddate'} cmp $a->{'publisheddate'} } @results );
+ return( sort { ($b->{'publisheddate'} || $b->{'enumchron'}) cmp ($a->{'publisheddate'} || $a->{'enumchron'}) } @results );
} else {
return (@results);
}
return ($result);
}
+=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,
# Tack on 'items.' prefix to column names so that TransformKohaToMarc will work.
# Also, don't emit a subfield if the underlying field is blank.
- my $mungeditem = { map { $itemrecord->{$_} ne '' ? ("items.$_" => $itemrecord->{$_}) : () } keys %{ $itemrecord } };
+ my $mungeditem = {
+ map {
+ defined($itemrecord->{$_}) && $itemrecord->{$_} ne '' ? ("items.$_" => $itemrecord->{$_}) : ()
+ } keys %{ $itemrecord }
+ };
my $itemmarc = TransformKohaToMarc($mungeditem);
+
+ my $unlinked_item_subfields = _parse_unlinked_item_subfields_from_xml($mungeditem->{'items.more_subfields_xml'});
+ if (defined $unlinked_item_subfields and $#$unlinked_item_subfields > -1) {
+ my @fields = $itemmarc->fields();
+ if ($#fields > -1) {
+ $fields[0]->add_subfields(@$unlinked_item_subfields);
+ }
+ }
+
return $itemmarc;
}
sub _set_defaults_for_add {
my $item = shift;
-
- # if dateaccessioned is provided, use it. Otherwise, set to NOW()
- if (!(exists $item->{'dateaccessioned'}) ||
- ($item->{'dateaccessioned'} eq '')) {
- # FIXME add check for invalid date
- my $today = C4::Dates->new();
- $item->{'dateaccessioned'} = $today->output("iso"); #TODO: check time issues
- }
-
- # various item status fields cannot be null
- $item->{'notforloan'} = 0 unless exists $item->{'notforloan'} and defined $item->{'notforloan'} and $item->{'notforloan'} ne '';
- $item->{'damaged'} = 0 unless exists $item->{'damaged'} and defined $item->{'damaged'} and $item->{'damaged'} ne '';
- $item->{'itemlost'} = 0 unless exists $item->{'itemlost'} and defined $item->{'itemlost'} and $item->{'itemlost'} ne '';
- $item->{'wthdrawn'} = 0 unless exists $item->{'wthdrawn'} and defined $item->{'wthdrawn'} and $item->{'wthdrawn'} ne '';
+ $item->{dateaccessioned} ||= C4::Dates->new->output('iso');
+ $item->{$_} ||= 0 for (qw( notforloan damaged itemlost wthdrawn));
}
=head2 _koha_new_item
=over 4
-my ($itemnumber,$error) = _koha_new_item( $dbh, $item, $barcode );
+my ($itemnumber,$error) = _koha_new_item( $item, $barcode );
=back
=cut
sub _koha_new_item {
- my ( $dbh, $item, $barcode ) = @_;
+ my ( $item, $barcode ) = @_;
+ my $dbh=C4::Context->dbh;
my $error;
my $query =
"INSERT INTO items SET
ccode = ?,
itype = ?,
materials = ?,
- uri = ?
+ uri = ?,
+ enumchron = ?,
+ more_subfields_xml = ?,
+ copynumber = ?
";
my $sth = $dbh->prepare($query);
$sth->execute(
$item->{'itype'},
$item->{'materials'},
$item->{'uri'},
+ $item->{'enumchron'},
+ $item->{'more_subfields_xml'},
+ $item->{'copynumber'},
);
my $itemnumber = $dbh->{'mysql_insertid'};
if ( defined $sth->errstr ) {
=over 4
-my ($itemnumber,$error) =_koha_modify_item( $dbh, $item, $op );
+my ($itemnumber,$error) =_koha_modify_item( $item );
=back
=cut
sub _koha_modify_item {
- my ( $dbh, $item ) = @_;
+ my ( $item ) = @_;
+ my $dbh=C4::Context->dbh;
my $error;
my $query = "UPDATE items SET ";
$query =~ s/,$//;
$query .= " WHERE itemnumber=?";
push @bind, $item->{'itemnumber'};
- my $sth = $dbh->prepare($query);
+ my $sth = C4::Context->dbh->prepare($query);
$sth->execute(@bind);
- if ( $dbh->errstr ) {
+ if ( C4::Context->dbh->errstr ) {
$error.="ERROR in _koha_modify_item $query".$dbh->errstr;
warn $error;
}
=over 4
-my $item_marc = _marc_from_item_hash($item, $frameworkcode);
+my $item_marc = _marc_from_item_hash($item, $frameworkcode[, $unlinked_item_subfields]);
=back
create a C<MARC::Record> object containing an embedded
tag representing that item.
+The third, optional parameter C<$unlinked_item_subfields> is
+an arrayref of subfields (not mapped to C<items> fields per the
+framework) to be added to the MARC representation
+of the item.
+
=cut
sub _marc_from_item_hash {
my $item = shift;
my $frameworkcode = shift;
+ my $unlinked_item_subfields;
+ if (@_) {
+ $unlinked_item_subfields = shift;
+ }
# Tack on 'items.' prefix to column names so lookup from MARC frameworks will work
# Also, don't emit a subfield if the underlying field is blank.
foreach my $item_field (keys %{ $mungeditem }) {
my ($tag, $subfield) = GetMarcFromKohaField($item_field, $frameworkcode);
next unless defined $tag and defined $subfield; # skip if not mapped to MARC field
- if (my $field = $item_marc->field($tag)) {
- $field->add_subfields($subfield => $mungeditem->{$item_field});
- } else {
- $item_marc->add_fields( $tag, " ", " ", $subfield => $mungeditem->{$item_field});
+
+
+ my @values = split(/\s?\|\s?/, $mungeditem->{$item_field}, -1);
+ foreach my $value (@values){
+ if (my $field = $item_marc->field($tag)) {
+ $field->add_subfields($subfield => $value);
+ } else {
+ my $add_subfields = [];
+ if (defined $unlinked_item_subfields and ref($unlinked_item_subfields) eq 'ARRAY' and $#$unlinked_item_subfields > -1) {
+ $add_subfields = $unlinked_item_subfields;
+ }
+ $item_marc->add_fields( $tag, " ", " ", $subfield => $value, @$add_subfields);
+ }
}
}
my ($item_marc, $biblionumber, $frameworkcode) = @_;
my $biblio_marc = GetMarcBiblio($biblionumber);
-
foreach my $field ($item_marc->fields()) {
$biblio_marc->append_fields($field);
}
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);
return @repacked_errors;
}
+=head2 _get_unlinked_item_subfields
+
+=over 4
+
+my $unlinked_item_subfields = _get_unlinked_item_subfields($original_item_marc, $frameworkcode);
+
+=back
+
+=cut
+
+sub _get_unlinked_item_subfields {
+ my $original_item_marc = shift;
+ my $frameworkcode = shift;
+
+ my $marcstructure = GetMarcStructure(1, $frameworkcode);
+
+ # assume that this record has only one field, and that that
+ # field contains only the item information
+ my $subfields = [];
+ my @fields = $original_item_marc->fields();
+ if ($#fields > -1) {
+ my $field = $fields[0];
+ my $tag = $field->tag();
+ foreach my $subfield ($field->subfields()) {
+ if (defined $subfield->[1] and
+ $subfield->[1] ne '' and
+ !$marcstructure->{$tag}->{$subfield->[0]}->{'kohafield'}) {
+ push @$subfields, $subfield->[0] => $subfield->[1];
+ }
+ }
+ }
+ return $subfields;
+}
+
+=head2 _get_unlinked_subfields_xml
+
+=over 4
+
+my $unlinked_subfields_xml = _get_unlinked_subfields_xml($unlinked_item_subfields);
+
+=back
+
+=cut
+
+sub _get_unlinked_subfields_xml {
+ my $unlinked_item_subfields = shift;
+
+ my $xml;
+ if (defined $unlinked_item_subfields and ref($unlinked_item_subfields) eq 'ARRAY' and $#$unlinked_item_subfields > -1) {
+ my $marc = MARC::Record->new();
+ # use of tag 999 is arbitrary, and doesn't need to match the item tag
+ # used in the framework
+ $marc->append_fields(MARC::Field->new('999', ' ', ' ', @$unlinked_item_subfields));
+ $marc->encoding("UTF-8");
+ $xml = $marc->as_xml("USMARC");
+ }
+
+ return $xml;
+}
+
+=head2 _parse_unlinked_item_subfields_from_xml
+
+=over 4
+
+my $unlinked_item_subfields = _parse_unlinked_item_subfields_from_xml($whole_item->{'more_subfields_xml'}):
+
+=back
+
+=cut
+
+sub _parse_unlinked_item_subfields_from_xml {
+ my $xml = shift;
+
+ return unless defined $xml and $xml ne "";
+ my $marc = MARC::Record->new_from_xml(StripNonXmlChars($xml),'UTF-8');
+ my $unlinked_subfields = [];
+ my @fields = $marc->fields();
+ if ($#fields > -1) {
+ foreach my $subfield ($fields[0]->subfields()) {
+ push @$unlinked_subfields, $subfield->[0] => $subfield->[1];
+ }
+ }
+ return $unlinked_subfields;
+}
+
1;