item rework: replaced AddBiblioAndItems
[koha.git] / C4 / Biblio.pm
index fc3a986..3871b12 100755 (executable)
@@ -27,10 +27,10 @@ use MARC::File::USMARC;
 use MARC::File::XML;
 use ZOOM;
 use C4::Koha;
+use C4::Branch;
 use C4::Dates qw/format_date/;
 use C4::Log; # logaction
 use C4::ClassSource;
-
 use vars qw($VERSION @ISA @EXPORT);
 
 # TODO: fix version
@@ -40,8 +40,10 @@ use vars qw($VERSION @ISA @EXPORT);
 
 # EXPORTED FUNCTIONS.
 
-# to add biblios or items
-push @EXPORT, qw( &AddBiblio &AddItem );
+# to add biblios
+push @EXPORT, qw( 
+  &AddBiblio
+);
 
 # to get something
 push @EXPORT, qw(
@@ -52,15 +54,6 @@ push @EXPORT, qw(
   &GetBiblioItemByBiblioNumber
   &GetBiblioFromItemNumber
   
-  &GetMarcItem
-  &GetItem
-  &GetItemInfosOf
-  &GetItemStatus
-  &GetItemLocation
-  &GetLostItems
-  &GetItemsForInventory
-  &GetItemsCount
-
   &GetMarcNotes
   &GetMarcSubjects
   &GetMarcBiblio
@@ -69,10 +62,6 @@ push @EXPORT, qw(
   GetMarcUrls
   &GetUsedMarcStructure
 
-  &GetItemsInfo
-  &GetItemsByBiblioitemnumber
-  &GetItemnumberFromBarcode
-  &get_itemnumbers_of
   &GetXmlBiblio
 
   &GetAuthorisedValueDesc
@@ -86,19 +75,13 @@ push @EXPORT, qw(
 # To modify something
 push @EXPORT, qw(
   &ModBiblio
-  &ModItem
-  &ModItemTransfer
   &ModBiblioframework
   &ModZebra
-  &ModItemInMarc
-  &ModItemInMarconefield
-  &ModDateLastSeen
 );
 
 # To delete something
 push @EXPORT, qw(
   &DelBiblio
-  &DelItem
 );
 
 # Internal functions
@@ -107,7 +90,6 @@ push @EXPORT, qw(
 # but don't use them unless you're a core developer ;-)
 push @EXPORT, qw(
   &ModBiblioMarc
-  &AddItemInMarc
 );
 
 # Others functions
@@ -200,14 +182,37 @@ When modifying a biblio or an item, the behaviour is quite similar.
 =over 4
 
 ($biblionumber,$biblioitemnumber) = AddBiblio($record,$frameworkcode);
-Exported function (core API) for adding a new biblio to koha.
 
 =back
 
+Exported function (core API) for adding a new biblio to koha.
+
+The first argument is a C<MARC::Record> object containing the
+bib to add, while the second argument is the desired MARC
+framework code.
+
+This function also accepts a third, optional argument: a hashref
+to additional options.  The only defined option is C<defer_marc_save>,
+which if present and mapped to a true value, causes C<AddBiblio>
+to omit the call to save the MARC in C<bibilioitems.marc>
+and C<biblioitems.marcxml>  This option is provided B<only>
+for the use of scripts such as C<bulkmarcimport.pl> that may need
+to do some manipulation of the MARC record for item parsing before
+saving it and which cannot afford the performance hit of saving
+the MARC record twice.  Consequently, do not use that option
+unless you can guarantee that C<ModBiblioMarc> will be called.
+
 =cut
 
 sub AddBiblio {
-    my ( $record, $frameworkcode ) = @_;
+    my $record = shift;
+    my $frameworkcode = shift;
+    my $options = @_ ? shift : undef;
+    my $defer_marc_save = 0;
+    if (defined $options and exists $options->{'defer_marc_save'} and $options->{'defer_marc_save'}) {
+        $defer_marc_save = 1;
+    }
+
     my ($biblionumber,$biblioitemnumber,$error);
     my $dbh = C4::Context->dbh;
     # transform the data into koha-table style data
@@ -219,7 +224,7 @@ sub AddBiblio {
     _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
 
     # now add the record
-    $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode );
+    $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode ) unless $defer_marc_save;
       
     &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$biblionumber,"biblio") 
         if C4::Context->preference("CataloguingLog");
@@ -227,76 +232,6 @@ sub AddBiblio {
     return ( $biblionumber, $biblioitemnumber );
 }
 
-=head2 AddItem
-
-=over 2
-
-    $biblionumber = AddItem( $record, $biblionumber)
-    Exported function (core API) for adding a new item to Koha
-
-=back
-
-=cut
-
-sub AddItem {
-    my ( $record, $biblionumber ) = @_;
-    my $dbh = C4::Context->dbh;
-    
-    # add item in old-DB
-    my $frameworkcode = GetFrameworkCode( $biblionumber );
-    my $item = &TransformMarcToKoha( $dbh, $record, $frameworkcode );
-
-    # needs old biblionumber and biblioitemnumber
-    $item->{'biblionumber'} = $biblionumber;
-    my $sth =
-      $dbh->prepare(
-        "SELECT biblioitemnumber,itemtype FROM biblioitems WHERE biblionumber=?"
-      );
-    $sth->execute( $item->{'biblionumber'} );
-    my $itemtype;
-    ( $item->{'biblioitemnumber'}, $itemtype ) = $sth->fetchrow;
-    $sth =
-      $dbh->prepare(
-        "SELECT notforloan FROM itemtypes WHERE itemtype=?");
-    $sth->execute( C4::Context->preference('item-level_itypes') ? $item->{'itype'} : $itemtype );
-    my $notforloan = $sth->fetchrow;
-    ##Change the notforloan field if $notforloan found
-    if ( $notforloan > 0 ) {
-        $item->{'notforloan'} = $notforloan;
-        &MARCitemchange( $record, "items.notforloan", $notforloan );
-    }
-    if ( !$item->{'dateaccessioned'} || $item->{'dateaccessioned'} eq '' ) {
-
-        # find today's date
-        my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
-          localtime(time);
-        $year += 1900;
-        $mon  += 1;
-        my $date =
-          "$year-" . sprintf( "%0.2d", $mon ) . "-" . sprintf( "%0.2d", $mday );
-        $item->{'dateaccessioned'} = $date;
-        &MARCitemchange( $record, "items.dateaccessioned", $date );
-    }
-    my ( $itemnumber, $error ) = &_koha_new_items( $dbh, $item, $item->{barcode} );
-    # add itemnumber to MARC::Record before adding the item.
-    $sth = $dbh->prepare(
-"SELECT tagfield,tagsubfield 
-FROM marc_subfield_structure
-WHERE frameworkcode=? 
-    AND kohafield=?"
-      );
-    &TransformKohaToMarcOneField( $sth, $record, "items.itemnumber", $itemnumber,
-        $frameworkcode );
-
-    # add the item
-    &AddItemInMarc( $record, $item->{'biblionumber'},$frameworkcode );
-   
-    &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$itemnumber,"item") 
-        if C4::Context->preference("CataloguingLog");
-    
-    return ($item->{biblionumber}, $item->{biblioitemnumber},$itemnumber);
-}
-
 =head2 ModBiblio
 
     ModBiblio( $record,$biblionumber,$frameworkcode);
@@ -358,76 +293,6 @@ sub ModBiblio {
     return 1;
 }
 
-=head2 ModItem
-
-=over 2
-
-Exported function (core API) for modifying an item in Koha.
-
-=back
-
-=cut
-
-sub ModItem {
-    my ( $record, $biblionumber, $itemnumber, $delete, $new_item_hashref )
-      = @_;
-    
-    #logging
-    &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$itemnumber,$record->as_formatted) 
-        if C4::Context->preference("CataloguingLog");
-      
-    my $dbh = C4::Context->dbh;
-    
-    # if we have a MARC record, we're coming from cataloging and so
-    # we do the whole routine: update the MARC and zebra, then update the koha
-    # tables
-    if ($record) {
-        my $frameworkcode = GetFrameworkCode( $biblionumber );
-        ModItemInMarc( $record, $biblionumber, $itemnumber, $frameworkcode );
-        my $olditem       = TransformMarcToKoha( $dbh, $record, $frameworkcode,'items');
-        $olditem->{'biblionumber'} = $biblionumber;
-        my $sth =  $dbh->prepare("select biblioitemnumber from biblioitems where biblionumber=?");
-        $sth->execute($biblionumber);
-        my ($biblioitemnumber) = $sth->fetchrow;
-        $sth->finish(); 
-        $olditem->{'biblioitemnumber'} = $biblioitemnumber;
-        _koha_modify_item( $dbh, $olditem );
-        return $biblionumber;
-    }
-
-    # otherwise, we're just looking to modify something quickly
-    # (like a status) so we just update the koha tables
-    elsif ($new_item_hashref) {
-        _koha_modify_item( $dbh, $new_item_hashref );
-    }
-}
-
-sub ModItemTransfer {
-    my ( $itemnumber, $frombranch, $tobranch ) = @_;
-    
-    my $dbh = C4::Context->dbh;
-    
-    #new entry in branchtransfers....
-    my $sth = $dbh->prepare(
-        "INSERT INTO branchtransfers (itemnumber, frombranch, datesent, tobranch)
-        VALUES (?, ?, NOW(), ?)");
-    $sth->execute($itemnumber, $frombranch, $tobranch);
-    #update holdingbranch in items .....
-     $sth= $dbh->prepare(
-          "UPDATE items SET holdingbranch = ? WHERE items.itemnumber = ?");
-    $sth->execute($tobranch,$itemnumber);
-    &ModDateLastSeen($itemnumber);
-    $sth = $dbh->prepare(
-        "SELECT biblionumber FROM items WHERE itemnumber=?"
-      );
-    $sth->execute($itemnumber);
-    while ( my ( $biblionumber ) = $sth->fetchrow ) {
-        &ModItemInMarconefield( $biblionumber, $itemnumber,
-            'items.holdingbranch', $tobranch );
-    }
-    return;
-}
-
 =head2 ModBiblioframework
 
     ModBiblioframework($biblionumber,$frameworkcode);
@@ -445,96 +310,6 @@ sub ModBiblioframework {
     return 1;
 }
 
-=head2 ModItemInMarconefield
-
-=over
-
-modify only 1 field in a MARC item (mainly used for holdingbranch, but could also be used for status modif - moving a book to "lost" on a long overdu for example)
-&ModItemInMarconefield( $biblionumber, $itemnumber, $itemfield, $newvalue )
-
-=back
-
-=cut
-
-sub ModItemInMarconefield {
-    my ( $biblionumber, $itemnumber, $itemfield, $newvalue ) = @_;
-    my $dbh = C4::Context->dbh;
-    if ( !defined $newvalue ) {
-        $newvalue = "";
-    }
-
-    my $record = GetMarcItem( $biblionumber, $itemnumber );
-    my ($tagfield, $tagsubfield) = GetMarcFromKohaField( $itemfield,'');
-    # FIXME - the condition is done this way because GetMarcFromKohaField
-    # returns (0, 0) if it can't field a MARC tag for the kohafield.  However,
-    # some fields like items.wthdrawn are mapped to subfield $0, making the
-    # customary test of "if ($tagfield && $tagsubfield)" incorrect.
-    # GetMarcFromKohaField should probably be returning (undef, undef), making
-    # the correct test "if (defined $tagfield && defined $tagsubfield)", but
-    # this would be a large change and consequently deferred for after 3.0.
-    if (not(int($tagfield) == 0 && int($tagsubfield) == 0)) { 
-        my $tag = $record->field($tagfield);
-        if ($tag) {
-#             my $tagsubs = $record->field($tagfield)->subfield($tagsubfield);
-            $tag->update( $tagsubfield => $newvalue );
-            $record->delete_field($tag);
-            $record->insert_fields_ordered($tag);
-            my $frameworkcode = GetFrameworkCode( $biblionumber );
-            &ModItemInMarc( $record, $biblionumber, $itemnumber, $frameworkcode );
-        }
-    }
-}
-
-=head2 ModItemInMarc
-
-=over
-
-&ModItemInMarc( $record, $biblionumber, $itemnumber, $frameworkcode )
-
-=back
-
-=cut
-
-sub ModItemInMarc {
-    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);
-    foreach (@items) {
-        if ($_->subfield($itemsubfield) eq $itemnumber) {
-#             $completeRecord->delete_field($_);
-            $_->replace_with($itemField);
-        }
-    }
-    # save the record
-    my $sth = $dbh->prepare("UPDATE biblioitems SET marc=?,marcxml=? WHERE biblionumber=?");
-    $sth->execute( $completeRecord->as_usmarc(), $completeRecord->as_xml_record(),$biblionumber );
-    $sth->finish;
-    ModZebra($biblionumber,"specialUpdate","biblioserver",$completeRecord);
-}
-
-=head2 ModDateLastSeen
-
-&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
-
-=cut
-
-sub ModDateLastSeen {
-    my ($itemnum) = @_;
-    my $dbh       = C4::Context->dbh;
-    my $sth       =
-      $dbh->prepare(
-          "UPDATE items SET itemlost=0,datelastseen  = NOW() WHERE items.itemnumber = ?"
-      );
-    $sth->execute($itemnum);
-    return;
-}
 =head2 DelBiblio
 
 =over
@@ -596,48 +371,6 @@ sub DelBiblio {
     return;
 }
 
-=head2 DelItem
-
-=over
-
-DelItem( $biblionumber, $itemnumber );
-Exported function (core API) for deleting an item record in Koha.
-
-=back
-
-=cut
-
-sub DelItem {
-    my ( $dbh, $biblionumber, $itemnumber ) = @_;
-    
-    # check the item has no current issues
-    
-    
-    &_koha_delete_item( $dbh, $itemnumber );
-
-    # get the MARC record
-    my $record = GetMarcBiblio($biblionumber);
-    my $frameworkcode = GetFrameworkCode($biblionumber);
-
-    # 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(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$itemnumber,"item") 
-        if C4::Context->preference("CataloguingLog");
-}
-
 =head2 GetBiblioData
 
 =over 4
@@ -684,468 +417,6 @@ sub GetBiblioData {
     return ($data);
 }    # sub GetBiblioData
 
-
-=head2 GetItemsInfo
-
-=over 4
-
-  @results = &GetItemsInfo($biblionumber, $type);
-
-Returns information about books with the given biblionumber.
-
-C<$type> may be either C<intra> or anything else. If it is not set to
-C<intra>, then the search will exclude lost, very overdue, and
-withdrawn items.
-
-C<&GetItemsInfo> returns a list of references-to-hash. Each element
-contains a number of keys. Most of them are table items from the
-C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
-Koha database. Other keys include:
-
-=over 4
-
-=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
-
-=back
-
-=cut
-
-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" ;
-    my $sth = $dbh->prepare($query);
-    $sth->execute($biblionumber);
-    my $i = 0;
-    my @results;
-    my ( $date_due, $count_reserves );
-
-    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"
-       );
-    while ( my $data = $sth->fetchrow_hashref ) {
-        my $datedue = '';
-        $isth->execute( $data->{'itemnumber'} );
-        if ( my $idata = $isth->fetchrow_hashref ) {
-            $data->{borrowernumber} = $idata->{borrowernumber};
-            $data->{cardnumber}     = $idata->{cardnumber};
-            $data->{surname}     = $idata->{surname};
-            $data->{firstname}     = $idata->{firstname};
-            $datedue                = $idata->{'date_due'};
-        if (C4::Context->preference("IndependantBranches")){
-        my $userenv = C4::Context->userenv;
-        if ( ($userenv) && ( $userenv->{flags} != 1 ) ) { 
-            $data->{'NOTSAMEBRANCH'} = 1 if ($idata->{'bcode'} ne $userenv->{branch});
-        }
-        }
-        }
-        if ( $datedue eq '' ) {
-            my ( $restype, $reserves ) =
-              C4::Reserves::CheckReserves( $data->{'itemnumber'} );
-            if ($restype) {
-                $count_reserves = $restype;
-            }
-        }
-        $isth->finish;
-
-        #get branch information.....
-        my $bsth = $dbh->prepare(
-            "SELECT * FROM branches WHERE branchcode = ?
-        "
-        );
-        $bsth->execute( $data->{'holdingbranch'} );
-        if ( my $bdata = $bsth->fetchrow_hashref ) {
-            $data->{'branchname'} = $bdata->{'branchname'};
-        }
-        $data->{'datedue'}        = $datedue;
-        $data->{'count_reserves'} = $count_reserves;
-
-        # get notforloan complete status if applicable
-        my $sthnflstatus = $dbh->prepare(
-            'SELECT authorised_value
-            FROM   marc_subfield_structure
-            WHERE  kohafield="items.notforloan"
-        '
-        );
-
-        $sthnflstatus->execute;
-        my ($authorised_valuecode) = $sthnflstatus->fetchrow;
-        if ($authorised_valuecode) {
-            $sthnflstatus = $dbh->prepare(
-                "SELECT lib FROM authorised_values
-                 WHERE  category=?
-                 AND authorised_value=?"
-            );
-            $sthnflstatus->execute( $authorised_valuecode,
-                $data->{itemnotforloan} );
-            my ($lib) = $sthnflstatus->fetchrow;
-            $data->{notforloan} = $lib;
-        }
-
-        # my stack procedures
-        my $stackstatus = $dbh->prepare(
-            'SELECT authorised_value
-             FROM   marc_subfield_structure
-             WHERE  kohafield="items.stack"
-        '
-        );
-        $stackstatus->execute;
-
-        ($authorised_valuecode) = $stackstatus->fetchrow;
-        if ($authorised_valuecode) {
-            $stackstatus = $dbh->prepare(
-                "SELECT lib
-                 FROM   authorised_values
-                 WHERE  category=?
-                 AND    authorised_value=?
-            "
-            );
-            $stackstatus->execute( $authorised_valuecode, $data->{stack} );
-            my ($lib) = $stackstatus->fetchrow;
-            $data->{stack} = $lib;
-        }
-        # Find the last 3 people who borrowed this item.
-        my $sth2 = $dbh->prepare("SELECT * FROM issues,borrowers
-                                    WHERE itemnumber = ?
-                                    AND issues.borrowernumber = borrowers.borrowernumber
-                                    AND returndate IS NOT NULL 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++;
-    }
-    $sth->finish;
-
-    return (@results);
-}
-
-=head2 getitemstatus
-
-=over 4
-
-$itemstatushash = &getitemstatus($fwkcode);
-returns information about status.
-Can be MARC dependant.
-fwkcode is optional.
-But basically could be can be loan or not
-Create a status selector with the following code
-
-=head3 in PERL SCRIPT
-
-my $itemstatushash = getitemstatus;
-my @itemstatusloop;
-foreach my $thisstatus (keys %$itemstatushash) {
-    my %row =(value => $thisstatus,
-                statusname => $itemstatushash->{$thisstatus}->{'statusname'},
-            );
-    push @itemstatusloop, \%row;
-}
-$template->param(statusloop=>\@itemstatusloop);
-
-
-=head3 in TEMPLATE
-
-            <select name="statusloop">
-                <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
-
-sub GetItemStatus {
-
-    # returns a reference to a hash of references to status...
-    my ($fwk) = @_;
-    my %itemstatus;
-    my $dbh = C4::Context->dbh;
-    my $sth;
-    $fwk = '' unless ($fwk);
-    my ( $tag, $subfield ) =
-      GetMarcFromKohaField( "items.notforloan", $fwk );
-    if ( $tag and $subfield ) {
-        my $sth =
-          $dbh->prepare(
-            "SELECT authorised_value
-            FROM marc_subfield_structure
-            WHERE tagfield=?
-                AND tagsubfield=?
-                AND frameworkcode=?
-            "
-          );
-        $sth->execute( $tag, $subfield, $fwk );
-        if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
-            my $authvalsth =
-              $dbh->prepare(
-                "SELECT authorised_value,lib
-                FROM authorised_values 
-                WHERE category=? 
-                ORDER BY lib
-                "
-              );
-            $authvalsth->execute($authorisedvaluecat);
-            while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
-                $itemstatus{$authorisedvalue} = $lib;
-            }
-            $authvalsth->finish;
-            return \%itemstatus;
-            exit 1;
-        }
-        else {
-
-            #No authvalue list
-            # build default
-        }
-        $sth->finish;
-    }
-
-    #No authvalue list
-    #build default
-    $itemstatus{"1"} = "Not For Loan";
-    return \%itemstatus;
-}
-
-=head2 getitemlocation
-
-=over 4
-
-$itemlochash = &getitemlocation($fwk);
-returns informations about location.
-where fwk stands for an optional framework code.
-Create a location selector with the following code
-
-=head3 in PERL SCRIPT
-
-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
-
-<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
-
-=cut
-
-sub GetItemLocation {
-
-    # returns a reference to a hash of references to location...
-    my ($fwk) = @_;
-    my %itemlocation;
-    my $dbh = C4::Context->dbh;
-    my $sth;
-    $fwk = '' unless ($fwk);
-    my ( $tag, $subfield ) =
-      GetMarcFromKohaField( "items.location", $fwk );
-    if ( $tag and $subfield ) {
-        my $sth =
-          $dbh->prepare(
-            "SELECT authorised_value
-            FROM marc_subfield_structure 
-            WHERE tagfield=? 
-                AND tagsubfield=? 
-                AND frameworkcode=?"
-          );
-        $sth->execute( $tag, $subfield, $fwk );
-        if ( my ($authorisedvaluecat) = $sth->fetchrow ) {
-            my $authvalsth =
-              $dbh->prepare(
-                "SELECT authorised_value,lib
-                FROM authorised_values
-                WHERE category=?
-                ORDER BY lib"
-              );
-            $authvalsth->execute($authorisedvaluecat);
-            while ( my ( $authorisedvalue, $lib ) = $authvalsth->fetchrow ) {
-                $itemlocation{$authorisedvalue} = $lib;
-            }
-            $authvalsth->finish;
-            return \%itemlocation;
-            exit 1;
-        }
-        else {
-
-            #No authvalue list
-            # build default
-        }
-        $sth->finish;
-    }
-
-    #No authvalue list
-    #build default
-    $itemlocation{"1"} = "Not For Loan";
-    return \%itemlocation;
-}
-
-=head2 GetLostItems
-
-$items = GetLostItems($where,$orderby);
-
-This function get the items lost into C<$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.
-
-=item return:
-C<$items> is a reference to an array full of hasref which keys are items' table column.
-
-=item usage in the perl script:
-
-my %where;
-$where{barcode} = 0001548;
-my $items = GetLostItems( \%where, "homebranch" );
-$template->param(itemsloop => $items);
-
-=back
-
-=cut
-
-sub GetLostItems {
-    # Getting input args.
-    my $where   = shift;
-    my $orderby = shift;
-    my $dbh     = C4::Context->dbh;
-
-    my $query   = "
-        SELECT *
-        FROM   items
-        WHERE  itemlost IS NOT NULL
-          AND  itemlost <> 0
-    ";
-    foreach my $key (keys %$where) {
-        $query .= " AND " . $key . " LIKE '%" . $where->{$key} . "%'";
-    }
-    $query .= " ORDER BY ".$orderby if defined $orderby;
-
-    my $sth = $dbh->prepare($query);
-    $sth->execute;
-    my @items;
-    while ( my $row = $sth->fetchrow_hashref ){
-        push @items, $row;
-    }
-    return \@items;
-}
-
-=head2 GetItemsForInventory
-
-$itemlist = GetItemsForInventory($minlocation,$maxlocation,$datelastseen,$offset,$size)
-
-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 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 $dbh = C4::Context->dbh;
-    my $sth;
-    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 );
-    }
-    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 );
-    }
-    my @results;
-    while ( my $row = $sth->fetchrow_hashref ) {
-        $offset-- if ($offset);
-        $row->{datelastseen}=format_date($row->{datelastseen});
-        if ( ( !$offset ) && $size ) {
-            push @results, $row;
-            $size--;
-        }
-    }
-    return \@results;
-}
-
 =head2 &GetBiblioItemData
 
 =over 4
@@ -1180,27 +451,6 @@ sub GetBiblioItemData {
     return ($data);
 }    # sub &GetBiblioItemData
 
-=head2 GetItemnumberFromBarcode
-
-=over 4
-
-$result = GetItemnumberFromBarcode($barcode);
-
-=back
-
-=cut
-
-sub GetItemnumberFromBarcode {
-    my ($barcode) = @_;
-    my $dbh = C4::Context->dbh;
-
-    my $rq =
-      $dbh->prepare("SELECT itemnumber FROM items WHERE items.barcode=?");
-    $rq->execute($barcode);
-    my ($result) = $rq->fetchrow;
-    return ($result);
-}
-
 =head2 GetBiblioItemByBiblioNumber
 
 =over 4
@@ -1292,161 +542,6 @@ sub GetBiblio {
     return ( $count, @results );
 }    # sub GetBiblio
 
-=head2 GetItem
-
-=over 4
-
-$data = &GetItem($itemnumber,$barcode);
-
-return Item information, for a given itemnumber or barcode
-
-=back
-
-=cut
-
-sub GetItem {
-    my ($itemnumber,$barcode) = @_;
-    my $dbh = C4::Context->dbh;
-    if ($itemnumber) {
-        my $sth = $dbh->prepare("
-            SELECT * FROM items 
-            WHERE itemnumber = ?");
-        $sth->execute($itemnumber);
-        my $data = $sth->fetchrow_hashref;
-        return $data;
-    } else {
-        my $sth = $dbh->prepare("
-            SELECT * FROM items 
-            WHERE barcode = ?"
-            );
-        $sth->execute($barcode);
-        my $data = $sth->fetchrow_hashref;
-        return $data;
-    }
-}    # sub GetItem
-
-=head2 get_itemnumbers_of
-
-=over 4
-
-my @itemnumbers_of = get_itemnumbers_of(@biblionumbers);
-
-Given a list of biblionumbers, return the list of corresponding itemnumbers
-for each biblionumber.
-
-Return a reference on a hash where keys are biblionumbers and values are
-references on array of itemnumbers.
-
-=back
-
-=cut
-
-sub get_itemnumbers_of {
-    my @biblionumbers = @_;
-
-    my $dbh = C4::Context->dbh;
-
-    my $query = '
-        SELECT itemnumber,
-            biblionumber
-        FROM items
-        WHERE biblionumber IN (?' . ( ',?' x scalar @biblionumbers - 1 ) . ')
-    ';
-    my $sth = $dbh->prepare($query);
-    $sth->execute(@biblionumbers);
-
-    my %itemnumbers_of;
-
-    while ( my ( $itemnumber, $biblionumber ) = $sth->fetchrow_array ) {
-        push @{ $itemnumbers_of{$biblionumber} }, $itemnumber;
-    }
-
-    return \%itemnumbers_of;
-}
-
-=head2 GetItemInfosOf
-
-=over 4
-
-GetItemInfosOf(@itemnumbers);
-
-=back
-
-=cut
-
-sub GetItemInfosOf {
-    my @itemnumbers = @_;
-
-    my $query = '
-        SELECT *
-        FROM items
-        WHERE itemnumber IN (' . join( ',', @itemnumbers ) . ')
-    ';
-    return get_infos_of( $query, 'itemnumber' );
-}
-
-=head2 GetItemsByBiblioitemnumber
-
-=over 4
-
-GetItemsByBiblioitemnumber($biblioitemnumber);
-
-Returns an arrayref of hashrefs suitable for use in a TMPL_LOOP
-Called by moredetail.pl
-
-=back
-
-=cut
-
-sub GetItemsByBiblioitemnumber {
-    my ( $bibitem ) = @_;
-    my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare("SELECT * FROM items WHERE items.biblioitemnumber = ?") || die $dbh->errstr;
-    # Get all items attached to a biblioitem
-    my $i = 0;
-    my @results; 
-    $sth->execute($bibitem) || die $sth->errstr;
-    while ( my $data = $sth->fetchrow_hashref ) {  
-        # 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'} );
-        if ( my $data2 = $sth2->fetchrow_hashref ) {
-            # if item is out, set the due date and who it is out too
-            $data->{'date_due'}   = $data2->{'date_due'};
-            $data->{'cardnumber'} = $data2->{'cardnumber'};
-            $data->{'borrowernumber'}   = $data2->{'borrowernumber'};
-        }
-        else {
-            # set date_due to blank, so in the template we check itemlost, and wthdrawn 
-            $data->{'date_due'} = '';                                                                                                         
-        }    # 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
-                      ORDER BY returndate desc,timestamp desc LIMIT 3";
-        $sth2 = $dbh->prepare($query2) || die $dbh->errstr;
-        $sth2->execute( $data->{'itemnumber'} ) || die $sth2->errstr;
-        my $i2 = 0;
-        while ( my $data2 = $sth2->fetchrow_hashref ) {
-            $data->{"timestamp$i2"} = $data2->{'timestamp'};
-            $data->{"card$i2"}      = $data2->{'cardnumber'};
-            $data->{"borrower$i2"}  = $data2->{'borrowernumber'};
-            $i2++;
-        }
-        $sth2->finish;
-        push(@results,$data);
-    } 
-    $sth->finish;
-    return (\@results); 
-}
-
-
 =head2 GetBiblioItemInfosOf
 
 =over 4
@@ -1734,65 +829,6 @@ sub GetAuthorisedValueDesc {
     }
 }
 
-=head2 GetMarcItem
-
-=over 4
-
-Returns MARC::Record of the item passed in parameter.
-
-=back
-
-=cut
-
-sub GetMarcItem {
-    my ( $biblionumber, $itemnumber ) = @_;
-
-    # GetMarcItem has been revised so that it does the following:
-    #  1. Gets the item information from the items table.
-    #  2. Converts it to a MARC field for storage in the bib record.
-    #
-    # The previous behavior was:
-    #  1. Get the bib record.
-    #  2. Return the MARC tag corresponding to the item record.
-    #
-    # The difference is that one treats the items row as authoritative,
-    # while the other treats the MARC representation as authoritative
-    # under certain circumstances.
-    #
-    # FIXME - a big one
-    #
-    # As of 2007-11-27, this change hopefully does not introduce
-    # any bugs.  However, it does mean that for code that uses
-    # ModItemInMarconefield to update one subfield (corresponding to
-    # an items column) is now less efficient.
-    #
-    # The API needs to be shifted to the following:
-    #  1. User updates items record.
-    #  2. Linked bib is sent for indexing.
-    # 
-    # The missing step 1.5 is updating the item tag in the bib MARC record
-    # so that the indexes are updated.  Depending on performance considerations,
-    # this may ultimately mean of of the following:
-    #  a. MARC field for item is updated right away.
-    #  b. MARC field for item is updated only as part of indexing.
-    #  c. MARC field for item is never actually stored in bib record; instead
-    #     it is generated only when needed for indexing, item export, and
-    #     (maybe) OPAC display.
-    #
-
-    my $itemrecord = GetItem($itemnumber);
-
-    # 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 $itemmarc = TransformKohaToMarc($mungeditem);
-    return $itemmarc;
-
-}
-
-
-
 =head2 GetMarcNotes
 
 =over 4
@@ -2308,7 +1344,7 @@ sub TransformHtmlToXml {
         }
         $prevtag = @$tags[$i];
     }
-    if (C4::Context->preference('marcflavour') and !$unimarc_and_100_exist) {
+    if (C4::Context->preference('marcflavour') eq 'UNIMARC' and !$unimarc_and_100_exist) {
 #     warn "SETTING 100 for $auth_type";
         use POSIX qw(strftime);
         my $string = strftime( "%Y%m%d", localtime(time) );
@@ -2429,6 +1465,9 @@ sub TransformHtmlToMarc {
     return $record;
 }
 
+# cache inverted MARC field map
+our $inverted_field_map;
+
 =head2 TransformMarcToKoha
 
 =over 4
@@ -2437,49 +1476,70 @@ sub TransformHtmlToMarc {
 
 =back
 
-=cut
+Extract data from a MARC bib record into a hashref representing
+Koha biblio, biblioitems, and items fields. 
 
+=cut
 sub TransformMarcToKoha {
-    my ( $dbh, $record, $frameworkcode, $table ) = @_;
+    my ( $dbh, $record, $frameworkcode, $limit_table ) = @_;
 
     my $result;
 
-    # sometimes we only want to return the items data
-    if ($table eq 'items') {
-        my $sth = $dbh->prepare("SHOW COLUMNS FROM items");
-        $sth->execute();
-        while ( (my $field) = $sth->fetchrow ) {
-            my $value = get_koha_field_from_marc($table,$field,$record,$frameworkcode);
-            my $key = _disambiguate($table, $field);
-            if ($result->{$key}) {
-                $result->{$key} .= " | " . $value;
-            } else {
-                $result->{$key} = $value;
-            }
-        }
-        return $result;
+    unless (defined $inverted_field_map) {
+        $inverted_field_map = _get_inverted_marc_field_map();
+    }
+
+    my %tables = ();
+    if ($limit_table eq 'items') {
+        $tables{'items'} = 1;
     } else {
-        my @tables = ('biblio','biblioitems','items');
-        foreach my $table (@tables){
-            my $sth2 = $dbh->prepare("SHOW COLUMNS from $table");
-            $sth2->execute;
-            while (my ($field) = $sth2->fetchrow){
-                # FIXME use of _disambiguate is a temporary hack
-                # $result->{_disambiguate($table, $field)} = get_koha_field_from_marc($table,$field,$record,$frameworkcode);
-                my $value = get_koha_field_from_marc($table,$field,$record,$frameworkcode);
-                my $key = _disambiguate($table, $field);
+        $tables{'items'} = 1;
+        $tables{'biblio'} = 1;
+        $tables{'biblioitems'} = 1;
+    }
+
+    # traverse through record
+    MARCFIELD: foreach my $field ($record->fields()) {
+        my $tag = $field->tag();
+        next MARCFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag};
+        if ($field->is_control_field()) {
+            my $kohafields = $inverted_field_map->{$frameworkcode}->{$tag}->{list};
+            ENTRY: foreach my $entry (@{ $kohafields }) {
+                my ($subfield, $table, $column) = @{ $entry };
+                next ENTRY unless exists $tables{$table};
+                my $key = _disambiguate($table, $column);
                 if ($result->{$key}) {
-                    # FIXME - hack to not bring in duplicates of the same value
-                    unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($value eq "")) {
-                        $result->{$key} .= " | " . $value;
+                    unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($field->data() eq "")) {
+                        $result->{$key} .= " | " . $field->data();
                     }
                 } else {
-                    $result->{$key} = $value;
+                    $result->{$key} = $field->data();
+                }
+            }
+        } else {
+            # deal with subfields
+            MARCSUBFIELD: foreach my $sf ($field->subfields()) {
+                my $code = $sf->[0];
+                next MARCSUBFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code};
+                my $value = $sf->[1];
+                SFENTRY: foreach my $entry (@{ $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code} }) {
+                    my ($table, $column) = @{ $entry };
+                    next SFENTRY unless exists $tables{$table};
+                    my $key = _disambiguate($table, $column);
+                    if ($result->{$key}) {
+                        unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($value eq "")) {
+                            $result->{$key} .= " | " . $value;
+                        }
+                    } else {
+                        $result->{$key} = $value;
+                    }
                 }
             }
-            $sth2->finish();
         }
-        # modify copyrightdate to keep only the 1st year found
+    }
+
+    # modify copyrightdate to keep only the 1st year found
+    if (exists $result->{'copyrightdate'}) {
         my $temp = $result->{'copyrightdate'};
         $temp =~ m/c(\d\d\d\d)/;    # search cYYYY first
         if ( $1 > 0 ) {
@@ -2489,9 +1549,11 @@ sub TransformMarcToKoha {
             $temp =~ m/(\d\d\d\d)/;
             $result->{'copyrightdate'} = $1;
         }
-    
-        # modify publicationyear to keep only the 1st year found
-        $temp = $result->{'publicationyear'};
+    }
+
+    # modify publicationyear to keep only the 1st year found
+    if (exists $result->{'publicationyear'}) {
+        my $temp = $result->{'publicationyear'};
         $temp =~ m/c(\d\d\d\d)/;    # search cYYYY first
         if ( $1 > 0 ) {
             $result->{'publicationyear'} = $1;
@@ -2500,10 +1562,26 @@ sub TransformMarcToKoha {
             $temp =~ m/(\d\d\d\d)/;
             $result->{'publicationyear'} = $1;
         }
-        return $result;
     }
+
+    return $result;
 }
 
+sub _get_inverted_marc_field_map {
+    my $field_map = {};
+    my $relations = C4::Context->marcfromkohafield;
+
+    foreach my $frameworkcode (keys %{ $relations }) {
+        foreach my $kohafield (keys %{ $relations->{$frameworkcode} }) {
+            my $tag = $relations->{$frameworkcode}->{$kohafield}->[0];
+            my $subfield = $relations->{$frameworkcode}->{$kohafield}->[1];
+            my ($table, $column) = split /[.]/, $kohafield, 2;
+            push @{ $field_map->{$frameworkcode}->{$tag}->{list} }, [ $subfield, $table, $column ];
+            push @{ $field_map->{$frameworkcode}->{$tag}->{sfs}->{$subfield} }, [ $table, $column ];
+        }
+    }
+    return $field_map;
+}
 
 =head2 _disambiguate
 
@@ -3152,7 +2230,6 @@ sub GetNoZebraIndexes {
     my %indexes;
     foreach my $line (split /('|"),/,$index) {
         $line =~ /(.*)=>(.*)/;
-warn $line;
         my $index = substr($1,1); # get the index, don't forget to remove initial ' or "
         my $fields = $2;
         $index =~ s/'|"|\s//g;
@@ -3383,36 +2460,6 @@ sub _AddBiblioNoZebra {
 }
 
 
-=head2 MARCitemchange
-
-=over 4
-
-&MARCitemchange( $record, $itemfield, $newvalue )
-
-Function to update a single value in an item field.
-Used twice, could probably be replaced by something else, but works well...
-
-=back
-
-=back
-
-=cut
-
-sub MARCitemchange {
-    my ( $record, $itemfield, $newvalue ) = @_;
-    my $dbh = C4::Context->dbh;
-    
-    my ( $tagfield, $tagsubfield ) =
-      GetMarcFromKohaField( $itemfield, "" );
-    if ( ($tagfield) && ($tagsubfield) ) {
-        my $tag = $record->field($tagfield);
-        if ($tag) {
-            $tag->update( $tagsubfield => $newvalue );
-            $record->delete_field($tag);
-            $record->insert_fields_ordered($tag);
-        }
-    }
-}
 =head2 _find_value
 
 =over 4
@@ -3818,151 +2865,6 @@ sub _koha_add_biblioitem {
     return ($bibitemnum,$error);
 }
 
-=head2 _koha_new_items
-
-=over 4
-
-my ($itemnumber,$error) = _koha_new_items( $dbh, $item, $barcode );
-
-=back
-
-=cut
-
-sub _koha_new_items {
-    my ( $dbh, $item, $barcode ) = @_;
-    my $error;
-
-    my ($items_cn_sort) = GetClassSort($item->{'items.cn_source'}, $item->{'itemcallnumber'}, "");
-
-    # if dateaccessioned is provided, use it. Otherwise, set to NOW()
-    if ( $item->{'dateaccessioned'} eq '' || !$item->{'dateaccessioned'} ) {
-        my $today = C4::Dates->new();    
-        $item->{'dateaccessioned'} =  $today->output("iso"); #TODO: check time issues
-    }
-    my $query = 
-           "INSERT INTO items SET
-            biblionumber        = ?,
-            biblioitemnumber    = ?,
-            barcode             = ?,
-            dateaccessioned     = ?,
-            booksellerid        = ?,
-            homebranch          = ?,
-            price               = ?,
-            replacementprice    = ?,
-            replacementpricedate = NOW(),
-            datelastborrowed    = ?,
-            datelastseen        = NOW(),
-            stack               = ?,
-            notforloan          = ?,
-            damaged             = ?,
-            itemlost            = ?,
-            wthdrawn            = ?,
-            itemcallnumber      = ?,
-            restricted          = ?,
-            itemnotes           = ?,
-            holdingbranch       = ?,
-            paidfor             = ?,
-            location            = ?,
-            onloan              = ?,
-            issues              = ?,
-            renewals            = ?,
-            reserves            = ?,
-            cn_source           = ?,
-            cn_sort             = ?,
-            ccode               = ?,
-            itype               = ?,
-            materials           = ?,
-            uri                 = ?
-          ";
-    my $sth = $dbh->prepare($query);
-    $sth->execute(
-            $item->{'biblionumber'},
-            $item->{'biblioitemnumber'},
-            $barcode,
-            $item->{'dateaccessioned'},
-            $item->{'booksellerid'},
-            $item->{'homebranch'},
-            $item->{'price'},
-            $item->{'replacementprice'},
-            $item->{datelastborrowed},
-            $item->{stack},
-            $item->{'notforloan'},
-            $item->{'damaged'},
-            $item->{'itemlost'},
-            $item->{'wthdrawn'},
-            $item->{'itemcallnumber'},
-            $item->{'restricted'},
-            $item->{'itemnotes'},
-            $item->{'holdingbranch'},
-            $item->{'paidfor'},
-            $item->{'location'},
-            $item->{'onloan'},
-            $item->{'issues'},
-            $item->{'renewals'},
-            $item->{'reserves'},
-            $item->{'items.cn_source'},
-            $items_cn_sort,
-            $item->{'ccode'},
-            $item->{'itype'},
-            $item->{'materials'},
-            $item->{'uri'},
-    );
-    my $itemnumber = $dbh->{'mysql_insertid'};
-    if ( defined $sth->errstr ) {
-        $error.="ERROR in _koha_new_items $query".$sth->errstr;
-    }
-    $sth->finish();
-    return ( $itemnumber, $error );
-}
-
-=head2 _koha_modify_item
-
-=over 4
-
-my ($itemnumber,$error) =_koha_modify_item( $dbh, $item, $op );
-
-=back
-
-=cut
-
-sub _koha_modify_item {
-    my ( $dbh, $item ) = @_;
-    my $error;
-
-    # calculate items.cn_sort
-    if($item->{'itemcallnumber'}) {
-        # This works, even when user is setting the call number blank (in which case
-        # how would we get here to calculate new (blank) of items.cn_sort?).
-        # 
-        # Why?  Because at present the only way to update itemcallnumber is via
-        # additem.pl; since it uses a MARC data-entry form, TransformMarcToKoha
-        # already has created $item->{'items.cn_sort'} and set it to undef because the 
-        # subfield for items.cn_sort in the framework is specified as ignored, meaning
-        # that it is not supplied or passed to the form.  Thus, if the user has
-        # blanked itemcallnumber, there is already a undef value for $item->{'items.cn_sort'}.
-        #
-        # This is subtle; it is also fragile.
-        $item->{'items.cn_sort'} = GetClassSort($item->{'items.cn_source'}, $item->{'itemcallnumber'}, "");
-    }
-    my $query = "UPDATE items SET ";
-    my @bind;
-    for my $key ( keys %$item ) {
-        $query.="$key=?,";
-        push @bind, $item->{$key};
-    }
-    $query =~ s/,$//;
-    $query .= " WHERE itemnumber=?";
-    push @bind, $item->{'itemnumber'};
-    my $sth = $dbh->prepare($query);
-    $sth->execute(@bind);
-    if ( $dbh->errstr ) {
-        $error.="ERROR in _koha_modify_item $query".$dbh->errstr;
-        warn $error;
-    }
-    $sth->finish();
-    return ($item->{'itemnumber'},$error);
-}
-
 =head2 _koha_delete_biblio
 
 =over 4
@@ -4065,44 +2967,6 @@ sub _koha_delete_biblioitems {
     return undef;
 }
 
-=head2 _koha_delete_item
-
-=over 4
-
-_koha_delete_item( $dbh, $itemnum );
-
-Internal function to delete an item record from the koha tables
-
-=back
-
-=cut
-
-sub _koha_delete_item {
-    my ( $dbh, $itemnum ) = @_;
-
-    # save the deleted item to deleteditems table
-    my $sth = $dbh->prepare("SELECT * FROM items WHERE itemnumber=?");
-    $sth->execute($itemnum);
-    my $data = $sth->fetchrow_hashref();
-    $sth->finish();
-    my $query = "INSERT INTO deleteditems SET ";
-    my @bind  = ();
-    foreach my $key ( keys %$data ) {
-        $query .= "$key = ?,";
-        push( @bind, $data->{$key} );
-    }
-    $query =~ s/\,$//;
-    $sth = $dbh->prepare($query);
-    $sth->execute(@bind);
-    $sth->finish();
-
-    # delete from items table
-    $sth = $dbh->prepare("DELETE FROM items WHERE itemnumber=?");
-    $sth->execute($itemnum);
-    $sth->finish();
-    return undef;
-}
-
 =head1 UNEXPORTED FUNCTIONS
 
 =head2 ModBiblioMarc
@@ -4159,38 +3023,6 @@ sub ModBiblioMarc {
     return $biblionumber;
 }
 
-=head2 AddItemInMarc
-
-=over 4
-
-$newbiblionumber = AddItemInMarc( $record, $biblionumber, $frameworkcode );
-
-Add an item in a MARC record and save the MARC record
-
-Function exported, but should NOT be used, unless you really know what you're doing
-
-=back
-
-=cut
-
-sub AddItemInMarc {
-
-    # pass the MARC::Record to this function, and it will create the records in the marc tables
-    my ( $record, $biblionumber, $frameworkcode ) = @_;
-    my $newrec = &GetMarcBiblio($biblionumber);
-
-    # create it
-    my @fields = $record->fields();
-    foreach my $field (@fields) {
-        $newrec->append_fields($field);
-    }
-
-    # FIXME: should we be making sure the biblionumbers are the same?
-    my $newbiblionumber =
-      &ModBiblioMarc( $newrec, $biblionumber, $frameworkcode );
-    return $newbiblionumber;
-}
-
 =head2 z3950_extended_services
 
 z3950_extended_services($serviceType,$serviceOptions,$record);
@@ -4299,25 +3131,6 @@ sub set_service_options {
     return $serviceOptions;
 }
 
-=head2 GetItemsCount
-
-$count = &GetItemsCount( $biblionumber);
-this function return count of item with $biblionumber
-=cut
-
-sub GetItemsCount {
-    my ( $biblionumber ) = @_;
-    my $dbh = C4::Context->dbh;
-    my $query = "SELECT count(*)
-          FROM  items 
-          WHERE biblionumber=?";
-    my $sth = $dbh->prepare($query);
-    $sth->execute($biblionumber);
-    my $count = $sth->fetchrow;  
-    $sth->finish;
-    return ($count);
-}
-
 END { }    # module clean-up code here (global destructor)
 
 1;