bug 5579: tweaks to bulkmarcimport.pl
[koha.git] / C4 / Items.pm
index ee6bf3a..44272e2 100644 (file)
@@ -1,6 +1,7 @@
 package C4::Items;
 
 # Copyright 2007 LibLime, Inc.
+# Parts Copyright Biblibre 2010
 #
 # This file is part of Koha.
 #
@@ -32,6 +33,9 @@ use C4::Branch;
 require C4::Reserves;
 use C4::Charset;
 use C4::Acquisition;
+use List::MoreUtils qw/any/;
+use Data::Dumper; # used as part of logging item record changes, not just for
+                  # debugging; so please don't remove this
 
 use vars qw($VERSION @ISA @EXPORT);
 
@@ -64,9 +68,11 @@ BEGIN {
         GetItemInfosOf
         GetItemsByBiblioitemnumber
         GetItemsInfo
+       GetItemsLocationInfo
         get_itemnumbers_of
         GetItemnumberFromBarcode
         GetBarcodeFromItemnumber
+      GetHiddenItemnumbers
 
                DelItemCheck
                MoveItemFromBiblio 
@@ -118,11 +124,7 @@ of C<C4::Items>
 
 =head2 GetItem
 
-=over 4
-
-$item = GetItem($itemnumber,$barcode,$serial);
-
-=back
+  $item = GetItem($itemnumber,$barcode,$serial);
 
 Return item information, for a given itemnumber or barcode.
 The return value is a hashref mapping item column
@@ -152,7 +154,6 @@ sub GetItem {
     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();
-               warn $data->{'serialseq'} , $data->{'publisheddate'};
     }
        #if we don't have an items.itype, use biblioitems.itemtype.
        if( ! $data->{'itype'} ) {
@@ -165,11 +166,7 @@ sub GetItem {
 
 =head2 CartToShelf
 
-=over 4
-
-CartToShelf($itemnumber);
-
-=back
+  CartToShelf($itemnumber);
 
 Set the current shelving location of the item record
 to its stored permanent shelving location.  This is
@@ -193,12 +190,8 @@ sub CartToShelf {
 
 =head2 AddItemFromMarc
 
-=over 4
-
-my ($biblionumber, $biblioitemnumber, $itemnumber) 
-    = AddItemFromMarc($source_item_marc, $biblionumber);
-
-=back
+  my ($biblionumber, $biblioitemnumber, $itemnumber) 
+      = AddItemFromMarc($source_item_marc, $biblionumber);
 
 Given a MARC::Record object containing an embedded item
 record and a biblionumber, create a new item record.
@@ -222,12 +215,8 @@ sub AddItemFromMarc {
 
 =head2 AddItem
 
-=over 4
-
-my ($biblionumber, $biblioitemnumber, $itemnumber) 
-    = AddItem($item, $biblionumber[, $dbh, $frameworkcode, $unlinked_item_subfields]);
-
-=back
+  my ($biblionumber, $biblioitemnumber, $itemnumber) 
+      = AddItem($item, $biblionumber[, $dbh, $frameworkcode, $unlinked_item_subfields]);
 
 Given a hash containing item column names as keys,
 create a new Koha item record.
@@ -275,9 +264,7 @@ sub AddItem {
        my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} );
     $item->{'itemnumber'} = $itemnumber;
 
-    # create MARC tag representing item and add to bib
-    my $new_item_marc = _marc_from_item_hash($item, $frameworkcode, $unlinked_item_subfields);
-    _add_item_field_to_biblio($new_item_marc, $item->{'biblionumber'}, $frameworkcode );
+    ModZebra( $item->{biblionumber}, "specialUpdate", "biblioserver", undef, undef );
    
     logaction("CATALOGUING", "ADD", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
     
@@ -286,11 +273,8 @@ sub AddItem {
 
 =head2 AddItemBatchFromMarc
 
-=over 4
-
-($itemnumber_ref, $error_ref) = AddItemBatchFromMarc($record, $biblionumber, $biblioitemnumber, $frameworkcode);
-
-=back
+  ($itemnumber_ref, $error_ref) = AddItemBatchFromMarc($record, 
+             $biblionumber, $biblioitemnumber, $frameworkcode);
 
 Efficiently create item records from a MARC biblio record with
 embedded item fields.  This routine is suitable for batch jobs.
@@ -308,7 +292,7 @@ This function returns an arrayref of new itemsnumbers and an arrayref of item
 errors encountered during the processing.  Each entry in the errors
 list is a hashref containing the following keys:
 
-=over 2
+=over
 
 =item item_sequence
 
@@ -386,18 +370,14 @@ sub AddItemBatchFromMarc {
     }
 
     # update the MARC biblio
-    $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode );
#   $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode );
 
     return (\@itemnumbers, \@errors);
 }
 
 =head2 ModItemFromMarc
 
-=over 4
-
-ModItemFromMarc($item_marc, $biblionumber, $itemnumber);
-
-=back
+  ModItemFromMarc($item_marc, $biblionumber, $itemnumber);
 
 This function updates an item record based on a supplied
 C<MARC::Record> object containing an embedded item field.
@@ -426,7 +406,7 @@ my %default_values_for_mod_from_marc = (
     'items.cn_source'    => undef, 
     copynumber           => undef, 
     damaged              => 0,
-    dateaccessioned      => undef, 
+#    dateaccessioned      => undef,
     enumchron            => undef, 
     holdingbranch        => undef, 
     homebranch           => undef, 
@@ -443,6 +423,7 @@ my %default_values_for_mod_from_marc = (
     replacementpricedate => undef, 
     restricted           => undef, 
     stack                => undef, 
+    stocknumber          => undef, 
     uri                  => undef, 
     wthdrawn             => 0,
 );
@@ -452,28 +433,25 @@ sub ModItemFromMarc {
     my $biblionumber = shift;
     my $itemnumber = shift;
 
-    my $dbh = C4::Context->dbh;
-    my $frameworkcode = GetFrameworkCode( $biblionumber );
-       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 $dbh           = C4::Context->dbh;
+    my $frameworkcode = GetFrameworkCode($biblionumber);
+    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);
-   
+    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[, $original_item_marc]);
-
-=back
+  ModItem({ column => $newvalue }, $biblionumber, 
+                  $itemnumber[, $original_item_marc]);
 
 Change one or more columns in an item record and update
 the MARC representation of the item.
@@ -528,27 +506,16 @@ sub ModItem {
     # update items table
     _koha_modify_item($item);
 
-    # update biblio MARC XML
-    my $whole_item = GetItem($itemnumber) or die "FAILED GetItem($itemnumber)";
+    # request that bib be reindexed so that searching on current
+    # item status is possible
+    ModZebra( $biblionumber, "specialUpdate", "biblioserver", undef, undef );
 
-    unless (defined $unlinked_item_subfields) {
-        $unlinked_item_subfields = _parse_unlinked_item_subfields_from_xml($whole_item->{'more_subfields_xml'});
-    }
-    my $new_item_marc = _marc_from_item_hash($whole_item, $frameworkcode, $unlinked_item_subfields) 
-        or die "FAILED _marc_from_item_hash($whole_item, $frameworkcode)";
-    
-    _replace_item_field_in_biblio($new_item_marc, $biblionumber, $itemnumber, $frameworkcode);
-       ($new_item_marc       eq '0') and die "$new_item_marc is '0', not hashref";  # logaction line would crash anyway
-    logaction("CATALOGUING", "MODIFY", $itemnumber, $new_item_marc->as_formatted) if C4::Context->preference("CataloguingLog");
+    logaction("CATALOGUING", "MODIFY", $itemnumber, Dumper($item)) if C4::Context->preference("CataloguingLog");
 }
 
 =head2 ModItemTransfer
 
-=over 4
-
-ModItemTransfer($itenumber, $frombranch, $tobranch);
-
-=back
+  ModItemTransfer($itenumber, $frombranch, $tobranch);
 
 Marks an item as being transferred from one branch
 to another.
@@ -573,11 +540,7 @@ sub ModItemTransfer {
 
 =head2 ModDateLastSeen
 
-=over 4
-
-ModDateLastSeen($itemnum);
-
-=back
+  ModDateLastSeen($itemnum);
 
 Mark item as seen. Is called when an item is issued, returned or manually marked during inventory/stocktaking.
 C<$itemnum> is the item number
@@ -593,11 +556,7 @@ sub ModDateLastSeen {
 
 =head2 DelItem
 
-=over 4
-
-DelItem($dbh, $biblionumber, $itemnumber);
-
-=back
+  DelItem($dbh, $biblionumber, $itemnumber);
 
 Exported function (core API) for deleting an item record in Koha.
 
@@ -612,30 +571,18 @@ sub DelItem {
 
     # get the MARC record
     my $record = GetMarcBiblio($biblionumber);
-    my $frameworkcode = GetFrameworkCode($biblionumber);
+    ModZebra( $biblionumber, "specialUpdate", "biblioserver", undef, undef );
 
     # backup the record
     my $copy2deleted = $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
     $copy2deleted->execute( $record->as_usmarc(), $itemnumber );
 
     #search item field code
-    my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
-    my @fields = $record->field($itemtag);
-
-    # delete the item specified
-    foreach my $field (@fields) {
-        if ( $field->subfield($itemsubfield) eq $itemnumber ) {
-            $record->delete_field($field);
-        }
-    }
-    &ModBiblioMarc( $record, $biblionumber, $frameworkcode );
     logaction("CATALOGUING", "DELETE", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
 }
 
 =head2 CheckItemPreSave
 
-=over 4
-
     my $item_ref = TransformMarcToKoha($marc, 'items');
     # do stuff
     my %errors = CheckItemPreSave($item_ref);
@@ -649,8 +596,6 @@ sub DelItem {
         print "item is OK";
     }
 
-=back
-
 Given a hashref containing item fields, determine if it can be
 inserted or updated in the database.  Specifically, checks for
 database integrity issues, and returns a hash containing any
@@ -733,11 +678,7 @@ has copy-and-paste work.
 
 =head2 GetItemStatus
 
-=over 4
-
-$itemstatushash = GetItemStatus($fwkcode);
-
-=back
+  $itemstatushash = GetItemStatus($fwkcode);
 
 Returns a list of valid values for the
 C<items.notforloan> field.
@@ -752,32 +693,24 @@ Create a status selector with the following code
 
 =head3 in PERL SCRIPT
 
-=over 4
-
-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);
-
-=back
+ 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
 
-=over 4
-
-<select name="statusloop">
-    <option value="">Default</option>
-<!-- TMPL_LOOP name="statusloop" -->
-    <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="statusname" --></option>
-<!-- /TMPL_LOOP -->
-</select>
-
-=back
+ <select name="statusloop">
+     <option value="">Default</option>
+ <!-- TMPL_LOOP name="statusloop" -->
+     <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="statusname" --></option>
+ <!-- /TMPL_LOOP -->
+ </select>
 
 =cut
 
@@ -833,11 +766,7 @@ sub GetItemStatus {
 
 =head2 GetItemLocation
 
-=over 4
-
-$itemlochash = GetItemLocation($fwk);
-
-=back
+  $itemlochash = GetItemLocation($fwk);
 
 Returns a list of valid values for the
 C<items.location> field.
@@ -850,34 +779,26 @@ Create a location selector with the following code
 
 =head3 in PERL SCRIPT
 
-=over 4
-
-my $itemlochash = getitemlocation;
-my @itemlocloop;
-foreach my $thisloc (keys %$itemlochash) {
-    my $selected = 1 if $thisbranch eq $branch;
-    my %row =(locval => $thisloc,
-                selected => $selected,
-                locname => $itemlochash->{$thisloc},
-            );
-    push @itemlocloop, \%row;
-}
-$template->param(itemlocationloop => \@itemlocloop);
-
-=back
+  my $itemlochash = getitemlocation;
+  my @itemlocloop;
+  foreach my $thisloc (keys %$itemlochash) {
+      my $selected = 1 if $thisbranch eq $branch;
+      my %row =(locval => $thisloc,
+                  selected => $selected,
+                  locname => $itemlochash->{$thisloc},
+               );
+      push @itemlocloop, \%row;
+  }
+  $template->param(itemlocationloop => \@itemlocloop);
 
 =head3 in TEMPLATE
 
-=over 4
-
-<select name="location">
-    <option value="">Default</option>
-<!-- TMPL_LOOP name="itemlocationloop" -->
-    <option value="<!-- TMPL_VAR name="locval" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="locname" --></option>
-<!-- /TMPL_LOOP -->
-</select>
-
-=back
+  <select name="location">
+      <option value="">Default</option>
+  <!-- TMPL_LOOP name="itemlocationloop" -->
+      <option value="<!-- TMPL_VAR name="locval" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="locname" --></option>
+  <!-- /TMPL_LOOP -->
+  </select>
 
 =cut
 
@@ -931,11 +852,7 @@ sub GetItemLocation {
 
 =head2 GetLostItems
 
-=over 4
-
-$items = GetLostItems( $where, $orderby );
-
-=back
+  $items = GetLostItems( $where, $orderby );
 
 This function gets a list of lost items.
 
@@ -959,9 +876,9 @@ from the "items" table as keys.
 
 =item usage in the perl script:
 
-my $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
 
@@ -1006,11 +923,9 @@ sub GetLostItems {
 
 =head2 GetItemsForInventory
 
-=over 4
-
-$itemlist = GetItemsForInventory($minlocation, $maxlocation, $location, $itemtype $datelastseen, $branch, $offset, $size, $statushash);
-
-=back
+  $itemlist = GetItemsForInventory($minlocation, $maxlocation, 
+                 $location, $itemtype $datelastseen, $branch, 
+                 $offset, $size, $statushash);
 
 Retrieve a list of title/authors/barcode/callnumber, for biblio inventory.
 
@@ -1026,7 +941,7 @@ $statushash requires a hashref that has the authorized values fieldname (intems.
 =cut
 
 sub GetItemsForInventory {
-    my ( $minlocation, $maxlocation,$location, $itemtype, $ignoreissued, $datelastseen, $branch, $offset, $size, $statushash ) = @_;
+    my ( $minlocation, $maxlocation,$location, $itemtype, $ignoreissued, $datelastseen, $branchcode, $branch, $offset, $size, $statushash ) = @_;
     my $dbh = C4::Context->dbh;
     my ( @bind_params, @where_strings );
 
@@ -1065,10 +980,14 @@ END_SQL
         push @where_strings, 'items.location = ?';
         push @bind_params, $location;
     }
-    
-    if ( $branch ) {
+
+    if ( $branchcode ) {
+        if($branch eq "homebranch"){
         push @where_strings, 'items.homebranch = ?';
-        push @bind_params, $branch;
+        }else{
+            push @where_strings, 'items.holdingbranch = ?';
+        }
+        push @bind_params, $branchcode;
     }
     
     if ( $itemtype ) {
@@ -1104,10 +1023,7 @@ END_SQL
 
 =head2 GetItemsCount
 
-=over 4
-$count = &GetItemsCount( $biblionumber);
-
-=back
+  $count = &GetItemsCount( $biblionumber);
 
 This function return count of item with $biblionumber
 
@@ -1127,11 +1043,7 @@ sub GetItemsCount {
 
 =head2 GetItemInfosOf
 
-=over 4
-
-GetItemInfosOf(@itemnumbers);
-
-=back
+  GetItemInfosOf(@itemnumbers);
 
 =cut
 
@@ -1148,11 +1060,7 @@ sub GetItemInfosOf {
 
 =head2 GetItemsByBiblioitemnumber
 
-=over 4
-
-GetItemsByBiblioitemnumber($biblioitemnumber);
-
-=back
+  GetItemsByBiblioitemnumber($biblioitemnumber);
 
 Returns an arrayref of hashrefs suitable for use in a TMPL_LOOP
 Called by C<C4::XISBN>
@@ -1204,11 +1112,7 @@ sub GetItemsByBiblioitemnumber {
 
 =head2 GetItemsInfo
 
-=over 4
-
-@results = GetItemsInfo($biblionumber, $type);
-
-=back
+  @results = GetItemsInfo($biblionumber, $type);
 
 Returns information about books with the given biblionumber.
 
@@ -1272,6 +1176,7 @@ sub GetItemsInfo {
            biblioitems.url,
            items.notforloan as itemnotforloan,
            itemtypes.description,
+           itemtypes.notforloan as notforloan_per_itemtype,
            branchurl
      FROM items
      LEFT JOIN branches ON items.homebranch = branches.branchcode
@@ -1355,7 +1260,31 @@ sub GetItemsInfo {
             my ($lib) = $sthnflstatus->fetchrow;
             $data->{notforloanvalue} = $lib;
         }
-               $data->{itypenotforloan} = $data->{notforloan} if (C4::Context->preference('item-level_itypes'));
+
+        # get restricted status and description if applicable
+        my $restrictedstatus = $dbh->prepare(
+            'SELECT authorised_value
+            FROM   marc_subfield_structure
+            WHERE  kohafield="items.restricted"
+        '
+        );
+
+        $restrictedstatus->execute;
+        ($authorised_valuecode) = $restrictedstatus->fetchrow;
+        if ($authorised_valuecode) {
+            $restrictedstatus = $dbh->prepare(
+                "SELECT lib,lib_opac FROM authorised_values
+                 WHERE  category=?
+                 AND authorised_value=?"
+            );
+            $restrictedstatus->execute( $authorised_valuecode,
+                $data->{restricted} );
+
+            if ( my $rstdata = $restrictedstatus->fetchrow_hashref ) {
+                $data->{restricted} = $rstdata->{'lib'};
+                $data->{restrictedopac} = $rstdata->{'lib_opac'};
+            }
+        }
 
         # my stack procedures
         my $stackstatus = $dbh->prepare(
@@ -1404,13 +1333,76 @@ sub GetItemsInfo {
        }
 }
 
-=head2 GetLastAcquisitions
+=head2 GetItemsLocationInfo
 
-=over 4
+  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}>
 
-my $lastacq = GetLastAcquisitions({'branches' => ('branch1','branch2'), 'itemtypes' => ('BK','BD')}, 10);
+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 ) {
+             $data->{location_intranet} = GetKohaAuthorisedValueLib('LOC', $data->{location});
+             $data->{location_opac}= GetKohaAuthorisedValueLib('LOC', $data->{location}, 1);
+            push @results, $data;
+       }
+       return @results;
+}
+
+
+=head2 GetLastAcquisitions
+
+  my $lastacq = GetLastAcquisitions({'branches' => ('branch1','branch2'), 
+                                    'itemtypes' => ('BK','BD')}, 10);
 
 =cut
 
@@ -1460,11 +1452,7 @@ sub  GetLastAcquisitions {
 
 =head2 get_itemnumbers_of
 
-=over 4
-
-my @itemnumbers_of = get_itemnumbers_of(@biblionumbers);
-
-=back
+  my @itemnumbers_of = get_itemnumbers_of(@biblionumbers);
 
 Given a list of biblionumbers, return the list of corresponding itemnumbers
 for each biblionumber.
@@ -1499,11 +1487,7 @@ sub get_itemnumbers_of {
 
 =head2 GetItemnumberFromBarcode
 
-=over 4
-
-$result = GetItemnumberFromBarcode($barcode);
-
-=back
+  $result = GetItemnumberFromBarcode($barcode);
 
 =cut
 
@@ -1520,11 +1504,7 @@ sub GetItemnumberFromBarcode {
 
 =head2 GetBarcodeFromItemnumber
 
-=over 4
-
-$result = GetBarcodeFromItemnumber($itemnumber);
-
-=back
+  $result = GetBarcodeFromItemnumber($itemnumber);
 
 =cut
 
@@ -1539,14 +1519,64 @@ sub GetBarcodeFromItemnumber {
     return ($result);
 }
 
+=head2 GetHiddenItemnumbers
+
+=over 4
+
+$result = GetHiddenItemnumbers(@items);
+
+=back
+
+=cut
+
+sub GetHiddenItemnumbers {
+    my (@items) = @_;
+    my @resultitems;
+
+    my $yaml = C4::Context->preference('OpacHiddenItems');
+    my $hidingrules;
+    eval {
+       $hidingrules = YAML::Load($yaml);
+    };
+    if ($@) {
+       warn "Unable to parse OpacHiddenItems syspref : $@";
+       return ();
+    } else {
+    my $dbh = C4::Context->dbh;
+
+       # For each item
+       foreach my $item (@items) {
+
+           # We check each rule
+           foreach my $field (keys %$hidingrules) {
+               my $query = "SELECT $field from items where itemnumber = ?";
+               my $sth = $dbh->prepare($query);        
+               $sth->execute($item->{'itemnumber'});
+               my ($result) = $sth->fetchrow;
+
+               # If the results matches the values in the yaml file
+               if (any { $result eq $_ } @{$hidingrules->{$field}}) {
+
+                   # We add the itemnumber to the list
+                   push @resultitems, $item->{'itemnumber'};       
+
+                   # If at least one rule matched for an item, no need to test the others
+                   last;
+               }
+           }
+       }
+       return @resultitems;
+    }
+
+ }
+
 =head3 get_item_authorised_values
 
-  find the types and values for all authorised values assigned to this item.
+find the types and values for all authorised values assigned to this item.
 
-  parameters:
-    itemnumber
+parameters: itemnumber
 
-  returns: a hashref malling the authorised value to the value set for this itemnumber
+returns: a hashref malling the authorised value to the value set for this itemnumber
 
     $authorised_values = {
              'CCODE'      => undef,
@@ -1562,7 +1592,7 @@ sub GetBarcodeFromItemnumber {
              'itemtypes'  => 'SER',
            };
 
-   Notes: see C4::Biblio::get_biblio_authorised_values for a similar method at the biblio level.
+Notes: see C4::Biblio::get_biblio_authorised_values for a similar method at the biblio level.
 
 =cut
 
@@ -1592,25 +1622,24 @@ sub get_item_authorised_values {
 
 =head3 get_authorised_value_images
 
-  find a list of icons that are appropriate for display based on the
-  authorised values for a biblio.
+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
+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:
+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.
+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
 
@@ -1651,11 +1680,7 @@ without careful thought.
 
 =head2 GetMarcItem
 
-=over 4
-
-my $item_marc = GetMarcItem($biblionumber, $itemnumber);
-
-=back
+  my $item_marc = GetMarcItem($biblionumber, $itemnumber);
 
 Returns MARC::Record of the item passed in parameter.
 This function is meant for use only in C<cataloguing/additem.pl>,
@@ -1742,11 +1767,7 @@ my %derived_columns = (
 
 =head2 _set_derived_columns_for_add 
 
-=over 4
-
-_set_derived_column_for_add($item);
-
-=back
+  _set_derived_column_for_add($item);
 
 Given an item hash representing a new item to be added,
 calculate any derived columns.  Currently the only
@@ -1770,11 +1791,7 @@ sub _set_derived_columns_for_add {
 
 =head2 _set_derived_columns_for_mod 
 
-=over 4
-
-_set_derived_column_for_mod($item);
-
-=back
+  _set_derived_column_for_mod($item);
 
 Given an item hash representing a new item to be modified.
 calculate any derived columns.  Currently the only
@@ -1821,11 +1838,7 @@ sub _set_derived_columns_for_mod {
 
 =head2 _do_column_fixes_for_mod
 
-=over 4
-
-_do_column_fixes_for_mod($item);
-
-=back
+  _do_column_fixes_for_mod($item);
 
 Given an item hashref containing one or more
 columns to modify, fix up certain values.
@@ -1858,15 +1871,14 @@ sub _do_column_fixes_for_mod {
     if (exists $item->{'location'} && !exists $item->{'permanent_location'}) {
         $item->{'permanent_location'} = $item->{'location'};
     }
+    if (exists $item->{'timestamp'}) {
+        delete $item->{'timestamp'};
+    }
 }
 
 =head2 _get_single_item_column
 
-=over 4
-
-_get_single_item_column($column, $itemnumber);
-
-=back
+  _get_single_item_column($column, $itemnumber);
 
 Retrieves the value of a single column from an C<items>
 row specified by C<$itemnumber>.
@@ -1886,11 +1898,7 @@ sub _get_single_item_column {
 
 =head2 _calc_items_cn_sort
 
-=over 4
-
-_calc_items_cn_sort($item, $source_values);
-
-=back
+  _calc_items_cn_sort($item, $source_values);
 
 Helper routine to calculate C<items.cn_sort>.
 
@@ -1905,11 +1913,7 @@ sub _calc_items_cn_sort {
 
 =head2 _set_defaults_for_add 
 
-=over 4
-
-_set_defaults_for_add($item_hash);
-
-=back
+  _set_defaults_for_add($item_hash);
 
 Given an item hash representing an item to be added, set
 correct default values for columns whose default value
@@ -1950,11 +1954,7 @@ sub _set_defaults_for_add {
 
 =head2 _koha_new_item
 
-=over 4
-
-my ($itemnumber,$error) = _koha_new_item( $item, $barcode );
-
-=back
+  my ($itemnumber,$error) = _koha_new_item( $item, $barcode );
 
 Perform the actual insert into the C<items> table.
 
@@ -2000,7 +2000,8 @@ sub _koha_new_item {
             uri = ?,
             enumchron           = ?,
             more_subfields_xml  = ?,
-            copynumber          = ?
+            copynumber          = ?,
+            stocknumber         = ?
           ";
     my $sth = $dbh->prepare($query);
    $sth->execute(
@@ -2037,6 +2038,7 @@ sub _koha_new_item {
             $item->{'enumchron'},
             $item->{'more_subfields_xml'},
             $item->{'copynumber'},
+            $item->{'stocknumber'},
     );
     my $itemnumber = $dbh->{'mysql_insertid'};
     if ( defined $sth->errstr ) {
@@ -2047,16 +2049,14 @@ sub _koha_new_item {
 
 =head2 MoveItemFromBiblio
 
-=over 4
-
-MoveItemFromBiblio($itenumber, $frombiblio, $tobiblio);
-
-=back
+  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;
@@ -2066,68 +2066,23 @@ sub MoveItemFromBiblio {
     $sth = $dbh->prepare("UPDATE items SET biblioitemnumber = ?, biblionumber = ? WHERE itemnumber = ? AND biblionumber = ?");
     my $return = $sth->execute($tobiblioitem, $tobiblio, $itemnumber, $frombiblio);
     if ($return == 1) {
-
-       # Getting framework
-       my $frameworkcode = GetFrameworkCode($frombiblio);
-
-       # Getting marc field for itemnumber
-       my ($itemtag, $itemsubfield) = GetMarcFromKohaField('items.itemnumber', $frameworkcode);
-
-       # Getting the record we want to move the item from
-       my $record = GetMarcBiblio($frombiblio);
-
-       # The item we want to move
-       my $item;
-
-       # For each item
-       foreach my $fielditem ($record->field($itemtag)){
-               # If it is the item we want to move
-               if ($fielditem->subfield($itemsubfield) == $itemnumber) {
-                   # We save it
-                   $item = $fielditem;
-                   # Then delete it from the record
-                   $record->delete_field($fielditem) 
-               }
-       }
-
-       # If we found an item (should always true, except in case of database-marcxml inconsistency)
-       if ($item) {
-
+        ModZebra( $tobiblio, "specialUpdate", "biblioserver", undef, undef );
+        ModZebra( $frombiblio, "specialUpdate", "biblioserver", undef, undef );
            # Checking if the item we want to move is in an order 
-           my $order = GetOrderFromItemnumber($itemnumber);
+        my $order = GetOrderFromItemnumber($itemnumber);
            if ($order) {
-               # Replacing the biblionumber within the order if necessary
-               $order->{'biblionumber'} = $tobiblio;
+                   # Replacing the biblionumber within the order if necessary
+                   $order->{'biblionumber'} = $tobiblio;
                ModOrder($order);
            }
-
-           # Saving the modification
-           ModBiblioMarc($record, $frombiblio, $frameworkcode);
-
-           # Getting the record we want to move the item to
-           $record = GetMarcBiblio($tobiblio);
-
-           # Inserting the previously saved item
-           $record->insert_fields_ordered($item);      
-
-           # Saving the modification
-           ModBiblioMarc($record, $tobiblio, $frameworkcode);
-
-       } else {
-           return undef;
+        return $tobiblio;
        }
-    } else {
-       return undef;
-    }
+    return;
 }
 
 =head2 DelItemCheck
 
-=over 4
-
-DelItemCheck($dbh, $biblionumber, $itemnumber);
-
-=back
+   DelItemCheck($dbh, $biblionumber, $itemnumber);
 
 Exported function (core API) for deleting an item record in Koha if there no current issue.
 
@@ -2141,32 +2096,38 @@ sub DelItemCheck {
     my $sth=$dbh->prepare("select * from issues i where i.itemnumber=?");
     $sth->execute($itemnumber);
 
-    my $onloan=$sth->fetchrow;
-
-    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;
-        if ($reserve){
-            $error = "book_reserved";
-        }else{
-            DelItem($dbh, $biblionumber, $itemnumber);
-            return 1;
-        }
+    my $item = GetItem($itemnumber);
+    my $onloan = $sth->fetchrow;
+    if ($onloan) {
+        $error = "book_on_loan";
+    }
+    elsif (C4::Context->preference("IndependantBranches") and (C4::Context->userenv->{branch} ne $item->{C4::Context->preference("HomeOrHoldingBranch")||'homebranch'})){
+        $error = "not_same_branch";
+    } 
+    else {
+       if ($onloan){ 
+           $error = "book_on_loan" 
+       }
+       else {
+           # check it doesnt have a waiting reserve
+           $sth=$dbh->prepare("SELECT * FROM reserves WHERE (found = 'W' or found = 'T') AND itemnumber = ?");
+           $sth->execute($itemnumber);
+           my $reserve=$sth->fetchrow;
+           if ($reserve) {
+               $error = "book_reserved";
+           } 
+           else {
+               DelItem($dbh, $biblionumber, $itemnumber);
+               return 1;
+           }
+       }
     }
     return $error;
 }
 
 =head2 _koha_modify_item
 
-=over 4
-
-my ($itemnumber,$error) =_koha_modify_item( $item );
-
-=back
+  my ($itemnumber,$error) =_koha_modify_item( $item );
 
 Perform the actual update of the C<items> row.  Note that this
 routine accepts a hashref specifying the columns to update.
@@ -2198,11 +2159,7 @@ sub _koha_modify_item {
 
 =head2 _koha_delete_item
 
-=over 4
-
-_koha_delete_item( $dbh, $itemnum );
-
-=back
+  _koha_delete_item( $dbh, $itemnum );
 
 Internal function to delete an item record from the koha tables
 
@@ -2233,11 +2190,7 @@ sub _koha_delete_item {
 
 =head2 _marc_from_item_hash
 
-=over 4
-
-my $item_marc = _marc_from_item_hash($item, $frameworkcode[, $unlinked_item_subfields]);
-
-=back
+  my $item_marc = _marc_from_item_hash($item, $frameworkcode[, $unlinked_item_subfields]);
 
 Given an item hash representing a complete item record,
 create a C<MARC::Record> object containing an embedded
@@ -2265,93 +2218,26 @@ sub _marc_from_item_hash {
                                 : ()  } keys %{ $item } }; 
 
     my $item_marc = MARC::Record->new();
-    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 {
-            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;
+    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
+        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 );
             }
-            $item_marc->add_fields( $tag, " ", " ", $subfield =>  $mungeditem->{$item_field}, @$add_subfields);
         }
     }
 
     return $item_marc;
 }
 
-=head2 _add_item_field_to_biblio
-
-=over 4
-
-_add_item_field_to_biblio($item_marc, $biblionumber, $frameworkcode);
-
-=back
-
-Adds the fields from a MARC record containing the
-representation of a Koha item record to the MARC
-biblio record.  The input C<$item_marc> record
-is expect to contain just one field, the embedded
-item information field.
-
-=cut
-
-sub _add_item_field_to_biblio {
-    my ($item_marc, $biblionumber, $frameworkcode) = @_;
-
-    my $biblio_marc = GetMarcBiblio($biblionumber);
-    foreach my $field ($item_marc->fields()) {
-        $biblio_marc->append_fields($field);
-    }
-
-    ModBiblioMarc($biblio_marc, $biblionumber, $frameworkcode);
-}
-
-=head2 _replace_item_field_in_biblio
-
-=over
-
-&_replace_item_field_in_biblio($item_marc, $biblionumber, $itemnumber, $frameworkcode)
-
-=back
-
-Given a MARC::Record C<$item_marc> containing one tag with the MARC 
-representation of the item, examine the biblio MARC
-for the corresponding tag for that item and 
-replace it with the tag from C<$item_marc>.
-
-=cut
-
-sub _replace_item_field_in_biblio {
-    my ($ItemRecord, $biblionumber, $itemnumber, $frameworkcode) = @_;
-    my $dbh = C4::Context->dbh;
-    
-    # get complete MARC record & replace the item field by the new one
-    my $completeRecord = GetMarcBiblio($biblionumber);
-    my ($itemtag,$itemsubfield) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
-    my $itemField = $ItemRecord->field($itemtag);
-    my @items = $completeRecord->field($itemtag);
-    my $found = 0;
-    foreach (@items) {
-        if ($_->subfield($itemsubfield) eq $itemnumber) {
-            $_->replace_with($itemField);
-            $found = 1;
-        }
-    }
-  
-    unless ($found) { 
-        # If we haven't found the matching field,
-        # just add it.  However, this means that
-        # there is likely a bug.
-        $completeRecord->append_fields($itemField);
-    }
-
-    # save the record
-    ModBiblioMarc($completeRecord, $biblionumber, $frameworkcode);
-}
-
 =head2 _repack_item_errors
 
 Add an error message hash generated by C<CheckItemPreSave>
@@ -2380,11 +2266,7 @@ sub _repack_item_errors {
 
 =head2 _get_unlinked_item_subfields
 
-=over 4
-
-my $unlinked_item_subfields = _get_unlinked_item_subfields($original_item_marc, $frameworkcode);
-
-=back
+  my $unlinked_item_subfields = _get_unlinked_item_subfields($original_item_marc, $frameworkcode);
 
 =cut
 
@@ -2414,11 +2296,7 @@ sub _get_unlinked_item_subfields {
 
 =head2 _get_unlinked_subfields_xml
 
-=over 4
-
-my $unlinked_subfields_xml = _get_unlinked_subfields_xml($unlinked_item_subfields);
-
-=back
+  my $unlinked_subfields_xml = _get_unlinked_subfields_xml($unlinked_item_subfields);
 
 =cut
 
@@ -2440,11 +2318,7 @@ sub _get_unlinked_subfields_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
+  my $unlinked_item_subfields = _parse_unlinked_item_subfields_from_xml($whole_item->{'more_subfields_xml'}):
 
 =cut