Better documentation, added warning if serviceType is 'drop' since it's
[koha-ffzg.git] / C4 / Biblio.pm
1 package C4::Biblio;
2
3 # Copyright 2000-2002 Katipo Communications
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
11 #
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA  02111-1307 USA
19
20 use strict;
21 require Exporter;
22 use C4::Context;
23 use C4::Database;
24 use C4::Date;
25 use MARC::Record;
26 use MARC::File::USMARC;
27 use MARC::File::XML;
28 use ZOOM;
29
30 use vars qw($VERSION @ISA @EXPORT);
31
32 # set the version for version checking
33 $VERSION = do { my @v = '$Revision$' =~ /\d+/g;
34                 shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
35
36 @ISA = qw(Exporter);
37
38 #
39 # don't forget MARCxxx subs are exported only for testing purposes. Should not be used
40 # as the old-style API and the NEW one are the only public functions.
41 #
42 @EXPORT = qw(
43   &newbiblio &newbiblioitem
44   &newsubject &newsubtitle &newitems 
45   
46   &modbiblio &checkitems &modbibitem
47   &modsubtitle &modsubject &modaddauthor &moditem
48   
49   &delitem &deletebiblioitem &delbiblio
50   
51   &getbiblio &bibdata &bibitems &bibitemdata 
52   &barcodes &ItemInfo &itemdata &itemissues &itemcount 
53   &getsubject &getaddauthor &getsubtitle
54   &getwebbiblioitems &getwebsites
55   &getbiblioitembybiblionumber
56   &getbiblioitem &getitemsbybiblioitem
57
58   &MARCfind_marc_from_kohafield
59   &MARCfind_frameworkcode
60   &find_biblioitemnumber
61   &MARCgettagslib
62
63   &NEWnewbiblio &NEWnewitem
64   &NEWmodbiblio &NEWmoditem
65   &NEWdelbiblio &NEWdelitem
66   &NEWmodbiblioframework
67
68   &MARCkoha2marcBiblio &MARCmarc2koha
69   &MARCkoha2marcItem &MARChtml2marc
70   &MARCgetbiblio &MARCgetitem
71   &XMLgetbiblio
72   
73   &FindDuplicate
74   &DisplayISBN
75
76   &z3950_extended_services
77   &set_service_options
78   
79   &get_item_from_barcode
80   &MARCfind_MARCbibid_from_oldbiblionumber
81
82 );
83
84 =head1 NAME
85
86 C4::Biblio - Acquisitions, Catalog Management Functions
87
88 =head1 SYNOPSIS
89
90 ( lot of changes for Koha 3.X)
91
92 Koha 1.2 and previous versions used a specific API to manage biblios. This API uses old-DB style parameters.
93 They are based on a hash, and store data in biblio/biblioitems/items tables (plus additionalauthors, 
94 bibliosubject and bibliosubtitle where applicable).
95
96 In Koha 2.X, we introduced a MARC-DB.
97
98 In Koha 3.X, we removed this MARC-DB for search as we wanted to use Zebra as search system.
99
100 So in Koha 3.X, saving a record means :
101
102  - storing the raw marc record (iso2709) in biblioitems.marc field. It contains both biblio & items information.
103  - storing the "decoded information" in biblio/biblioitems/items as previously.
104  - using zebra to manage search & indexing on the MARC data.
105  
106  In Koha, there is a systempreference for "MARC=ON" or "MARC=OFF" :
107  
108  * MARC=ON : when MARC=ON, Koha uses a MARC::Record object (in sub parameters). Saving information in the DB means : 
109
110  - transform the MARC record into a hash
111  - add the raw MARC record into the hash
112  - store them & update Zebra
113  
114  * MARC=OFF : when MARC=OFF, Koha uses a hash object (in sub parameters). Saving information in the DB means :
115
116  - transform the hash into a MARC record
117  - add the raw marc record into the hash
118  - store them & update zebra
119  
120 That's why we need 3 types of subs :
121
122 =head2 REALxxx subs
123
124 all I<subs beginning by REAL> do the effective storage of information (with a hash, one field of the hash being the raw marc record). Those subs also update the record in Zebra. REAL subs should be only for internal use (called by NEW or "something else" subs).
125
126 =head2 NEWxxx related subs
127
128 =over 4
129
130 all I<subs beginning by NEW> use MARC::Record as parameters. It's the API that MUST be used in the MARC acquisition system. They just create the hash, add it the raw marc record. Then, they call REALxxx sub.
131
132 all subs requires/use $dbh as 1st parameter and a MARC::Record object as 2nd parameter. They sometimes require another parameter.
133
134 =back
135
136 =head2 something_elsexxx related subs
137
138 =over 4
139
140 all I<subs beginning by seomething else> are the old-style API. They use a hash as parameter, transform the hash into a -small- marc record, and call REAL subs.
141
142 all subs require/use $dbh as 1st parameter and a hash as 2nd parameter.
143
144 =back
145
146 =head1 API
147
148 =head2 ZEBRA
149
150 =head3 z3950_extended_services
151
152 z3950_extended_services($Zconn,$serviceType,$serviceOptions,$record);
153
154         z3950_extended_services is used to handle all interactions with Zebra's extended serices package.
155
156 C<$Zconn> a connection object to the Zebra server
157
158 C<$serviceType> one of: itemorder,create,drop,commit,update,xmlupdate
159
160 C<$serviceOptions> a has of key/value pairs. For instance, if service_type is 'update', $service_options should contain:
161
162         action => update action, one of specialUpdate, recordInsert, recordReplace, recordDelete, elementUpdate.
163
164 and maybe
165
166         recordidOpaque => Opaque Record ID (user supplied) or recordidNumber => Record ID number (system number).
167         syntax => the record syntax (transfer syntax)
168         databaseName = Database from connection object
169
170         To set serviceOptions, call set_service_options($serviceType)
171
172 C<$record> the record, if one is needed for the service type
173
174         A record should be in XML. You can convert it to XML from MARC by running it through marc2xml().
175
176 =cut
177 sub z3950_extended_services {
178         my ($Zconn,$serviceType,$serviceOptions,$record) = @_;
179
180         # create a new package object
181         my $Zpackage = $Zconn->package();
182
183         # set our options
184         $Zpackage->option(action => $serviceOptions->{'action'});
185
186         if ($serviceOptions->{'databaseName'}) {
187                 $Zpackage->option(databaseName => $serviceOptions->{'databaseName'});
188         }
189         if ($serviceOptions->{'recordIdNumber'}) {
190                 $Zpackage->option(recordIdNumber => $serviceOptions->{'recordIdNumber'});
191         }
192         if ($serviceOptions->{'recordIdOpaque'}) {
193                 $Zpackage->option(recordIdOpaque => $serviceOptions->{'recordIdOpaque'});
194         }
195
196         # this is an ILL request (Zebra doesn't support it)
197         if ($serviceType eq 'itemorder') {
198            $Zpackage->option('contact-name' => $serviceOptions->{'contact-name'});
199            $Zpackage->option('contact-phone' => $serviceOptions->{'contact-phone'});
200            $Zpackage->option('contact-email' => $serviceOptions->{'contact-email'});
201            $Zpackage->option('itemorder-item' => $serviceOptions->{'itemorder-item'});
202         }
203
204         if ($record) {
205            my $xmlrecord = marc2xml($record);
206            $Zpackage->option(record => $xmlrecord);
207            if ($serviceOptions->{'syntax'}) {
208               $Zpackage->option(syntax => $serviceOptions->{'syntax'});
209            }
210         }
211
212         # send the request, handle any exception encountered
213         eval {  $Zpackage->send($serviceType) };
214         if ($@ && $@->isa("ZOOM::Exception")) {
215                 print "Oops!  ", $@->message(), "\n";
216                 return $@->code();
217         }
218         # free up package resources
219         $Zpackage->destroy();
220 }
221
222 =head2 set_service_options
223
224 my $serviceOptions = set_service_options($serviceType);
225
226 C<$serviceType> itemorder,create,drop,commit,update,xmlupdate
227
228 Currently, we only support 'create', 'commit', and 'update'. 'drop' support will be added as soon as Zebra supports it.
229
230 =cut
231
232 sub set_service_options {
233         my ($serviceType) = @_;
234         my $serviceOptions;
235
236         if ($serviceType eq 'update') {
237                 $serviceOptions->{ 'action' } = 'specialUpdate';
238
239         # FIXME: This needs to be an OID ... if we ever need 'syntax' this sub will need to change
240         #       $serviceOptions->{ 'syntax' } = ''; #zebra doesn't support syntaxes other than xml
241         }
242
243         if ($serviceType eq 'commit') {
244         # nothing to do
245
246         }
247         
248         if ($serviceType eq 'create') {
249         # nothing to do
250
251         }
252         
253         if (serviceType eq 'drop') {
254                 die "ERROR: 'drop' not currently supported (by Zebra)";
255         }
256         return $serviceOptions;
257 }
258
259 =head2 marc2xml
260
261 my $xmlrecord = marc2xml($record);
262
263 Convert from MARC to XML. Note that MARC::File::XML will automatically encode from MARC-8 to UTF-8 as of version .8
264
265 C<$record> a MARC record
266
267 =cut
268
269 sub marc2xml {
270         my ($record) = @_;
271         my $xmlrecord;
272         eval {
273                 $xmlrecord=$record->as_xml();
274         };
275         #TODO: better error handling here
276         if ($@){
277                 warn "ERROR: I suspect a badly formatted MARC record";
278         }
279         return $xmlrecord;
280 }
281
282 =head2 @tagslib = &MARCgettagslib($dbh,1|0,$frameworkcode);
283
284 =over 4
285
286 2nd param is 1 for liblibrarian and 0 for libopac
287 $frameworkcode contains the framework reference. If empty or does not exist, the default one is used
288
289 returns a hash with all values for all fields and subfields for a given MARC framework :
290         $res->{$tag}->{lib}        = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
291                     ->{tab}        = "";            # XXX
292                     ->{mandatory}  = $mandatory;
293                     ->{repeatable} = $repeatable;
294                     ->{$subfield}->{lib}              = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
295                                  ->{tab}              = $tab;
296                                  ->{mandatory}        = $mandatory;
297                                  ->{repeatable}       = $repeatable;
298                                  ->{authorised_value} = $authorised_value;
299                                  ->{authtypecode}     = $authtypecode;
300                                  ->{value_builder}    = $value_builder;
301                                  ->{kohafield}        = $kohafield;
302                                  ->{seealso}          = $seealso;
303                                  ->{hidden}           = $hidden;
304                                  ->{isurl}            = $isurl;
305                                  ->{link}            = $link;
306
307 =back
308
309 =cut
310
311 sub MARCgettagslib {
312     my ( $dbh, $forlibrarian, $frameworkcode ) = @_;
313     $frameworkcode = "" unless $frameworkcode;
314     $forlibrarian = 1 unless $forlibrarian;
315     my $sth;
316     my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
317
318     # check that framework exists
319     $sth =
320       $dbh->prepare(
321         "select count(*) from marc_tag_structure where frameworkcode=?");
322     $sth->execute($frameworkcode);
323     my ($total) = $sth->fetchrow;
324     $frameworkcode = "" unless ( $total > 0 );
325     $sth =
326       $dbh->prepare(
327 "select tagfield,liblibrarian,libopac,mandatory,repeatable from marc_tag_structure where frameworkcode=? order by tagfield"
328     );
329     $sth->execute($frameworkcode);
330     my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
331
332     while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) = $sth->fetchrow ) {
333         $res->{$tag}->{lib}        = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
334         $res->{$tag}->{tab}        = "";            # XXX
335         $res->{$tag}->{mandatory}  = $mandatory;
336         $res->{$tag}->{repeatable} = $repeatable;
337     }
338
339     $sth =
340       $dbh->prepare(
341 "select tagfield,tagsubfield,liblibrarian,libopac,tab, mandatory, repeatable,authorised_value,authtypecode,value_builder,kohafield,seealso,hidden,isurl,link from marc_subfield_structure where frameworkcode=? order by tagfield,tagsubfield"
342     );
343     $sth->execute($frameworkcode);
344
345     my $subfield;
346     my $authorised_value;
347     my $authtypecode;
348     my $value_builder;
349     my $kohafield;
350     my $seealso;
351     my $hidden;
352     my $isurl;
353         my $link;
354
355     while (
356         ( $tag,         $subfield,   $liblibrarian,   , $libopac,      $tab,
357         $mandatory,     $repeatable, $authorised_value, $authtypecode,
358         $value_builder, $kohafield,  $seealso,          $hidden,
359         $isurl,                 $link )
360         = $sth->fetchrow
361       )
362     {
363         $res->{$tag}->{$subfield}->{lib}              = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
364         $res->{$tag}->{$subfield}->{tab}              = $tab;
365         $res->{$tag}->{$subfield}->{mandatory}        = $mandatory;
366         $res->{$tag}->{$subfield}->{repeatable}       = $repeatable;
367         $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
368         $res->{$tag}->{$subfield}->{authtypecode}     = $authtypecode;
369         $res->{$tag}->{$subfield}->{value_builder}    = $value_builder;
370         $res->{$tag}->{$subfield}->{kohafield}        = $kohafield;
371         $res->{$tag}->{$subfield}->{seealso}          = $seealso;
372         $res->{$tag}->{$subfield}->{hidden}           = $hidden;
373         $res->{$tag}->{$subfield}->{isurl}            = $isurl;
374         $res->{$tag}->{$subfield}->{link}            = $link;
375     }
376     return $res;
377 }
378
379 =head2 ($tagfield,$tagsubfield) = &MARCfind_marc_from_kohafield($dbh,$kohafield);
380
381 =over 4
382
383 finds MARC tag and subfield for a given kohafield
384 kohafield is "table.field" where table= biblio|biblioitems|items, and field a field of the previous table
385
386 =back
387
388 =cut
389
390 sub MARCfind_marc_from_kohafield {
391     my ( $dbh, $kohafield,$frameworkcode ) = @_;
392     return 0, 0 unless $kohafield;
393     $frameworkcode='' unless $frameworkcode;
394         my $relations = C4::Context->marcfromkohafield;
395         return ($relations->{$frameworkcode}->{$kohafield}->[0],$relations->{$frameworkcode}->{$kohafield}->[1]);
396 }
397
398 =head2 $MARCRecord = &MARCgetbiblio($dbh,$biblionumber);
399
400 =over 4
401
402 Returns a MARC::Record for the biblio $biblionumber.
403
404 =cut
405
406 sub MARCgetbiblio {
407
408     # Returns MARC::Record of the biblio passed in parameter.
409     my ( $dbh, $biblionumber ) = @_;
410         my $sth = $dbh->prepare('select marc from biblioitems where biblionumber=?');
411         $sth->execute($biblionumber);
412         my ($marc) = $sth->fetchrow;
413         my $record = MARC::Record::new_from_usmarc($marc);
414     return $record;
415 }
416
417 =head2 $XML = &XMLgetbiblio($dbh,$biblionumber);
418
419 =over 4
420
421 Returns a raw XML for the biblio $biblionumber.
422
423 =cut
424
425 sub XMLgetbiblio {
426
427     # Returns MARC::Record of the biblio passed in parameter.
428     my ( $dbh, $biblionumber ) = @_;
429         my $sth = $dbh->prepare('select marcxml,marc from biblioitems where biblionumber=?');
430         $sth->execute($biblionumber);
431         my ($XML,$marc) = $sth->fetchrow;
432 #       my $record =MARC::Record::new_from_usmarc($marc);
433 #       warn "MARC : \n*-************************\n".$record->as_xml."\n*-************************\n";
434     return $XML;
435 }
436
437 =head2 $MARCrecord = &MARCgetitem($dbh,$biblionumber);
438
439 =over 4
440
441 Returns a MARC::Record with all items of biblio # $biblionumber
442
443 =back
444
445 =cut
446
447 sub MARCgetitem {
448
449     my ( $dbh, $biblionumber, $itemnumber ) = @_;
450         my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
451         # get the complete MARC record
452         my $sth = $dbh->prepare("select marc from biblioitems where biblionumber=?");
453         $sth->execute($biblionumber);
454         my ($rawmarc) = $sth->fetchrow;
455         my $record = MARC::File::USMARC::decode($rawmarc);
456         # now, find the relevant itemnumber
457         my ($itemnumberfield,$itemnumbersubfield) = MARCfind_marc_from_kohafield($dbh,'items.itemnumber',$frameworkcode);
458         # prepare the new item record
459         my $itemrecord = MARC::Record->new();
460         # parse all fields fields from the complete record
461         foreach ($record->field($itemnumberfield)) {
462                 # when the item field is found, save it
463                 if ($_->subfield($itemnumbersubfield) == $itemnumber) {
464                         $itemrecord->append_fields($_);
465                 }
466         }
467
468     return $itemrecord;
469 }
470
471 =head2 sub find_biblioitemnumber($dbh,$biblionumber);
472
473 =over 4
474
475 Returns the 1st biblioitemnumber related to $biblionumber. When MARC=ON we should have 1 biblionumber = 1 and only 1 biblioitemnumber
476 This sub is useless when MARC=OFF
477
478 =back
479
480 =cut
481 sub find_biblioitemnumber {
482         my ( $dbh, $biblionumber ) = @_;
483         my $sth = $dbh->prepare("select biblioitemnumber from biblioitems where biblionumber=?");
484         $sth->execute($biblionumber);
485         my ($biblioitemnumber) = $sth->fetchrow;
486         return $biblioitemnumber;
487 }
488
489 =head2 $frameworkcode = MARCfind_frameworkcode($dbh,$biblionumber);
490
491 =over 4
492
493 returns the framework of a given biblio
494
495 =back
496
497 =cut
498
499 sub MARCfind_frameworkcode {
500         my ( $dbh, $biblionumber ) = @_;
501         my $sth = $dbh->prepare("select frameworkcode from biblio where biblionumber=?");
502         $sth->execute($biblionumber);
503         my ($frameworkcode) = $sth->fetchrow;
504         return $frameworkcode;
505 }
506
507 =head2 $MARCRecord = &MARCkoha2marcBiblio($dbh,$bibliohash);
508
509 =over 4
510
511 MARCkoha2marcBiblio is a wrapper between old-DB and MARC-DB. It returns a MARC::Record builded with old-DB biblio/biblioitem :
512 all entries of the hash are transformed into their matching MARC field/subfield.
513
514 =back
515
516 =cut
517
518 sub MARCkoha2marcBiblio {
519
520         # this function builds partial MARC::Record from the old koha-DB fields
521         my ( $dbh, $bibliohash ) = @_;
522         # we don't have biblio entries in the hash, so we add them first
523         my $sth = $dbh->prepare("select * from biblio where biblionumber=?");
524         $sth->execute($bibliohash->{biblionumber});
525         my $biblio = $sth->fetchrow_hashref;
526         foreach (keys %$biblio) {
527                 $bibliohash->{$_}=$biblio->{$_};
528         }
529         $sth = $dbh->prepare("select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?");
530         my $record = MARC::Record->new();
531         foreach ( keys %$bibliohash ) {
532                 &MARCkoha2marcOnefield( $sth, $record, "biblio." . $_, $bibliohash->{$_}, '') if $bibliohash->{$_};
533                 &MARCkoha2marcOnefield( $sth, $record, "biblioitems." . $_, $bibliohash->{$_}, '') if $bibliohash->{$_};
534         }
535
536         # other fields => additional authors, subjects, subtitles
537         my $sth2 = $dbh->prepare(" SELECT author FROM additionalauthors WHERE biblionumber=?");
538         $sth2->execute($bibliohash->{biblionumber});
539         while ( my $row = $sth2->fetchrow_hashref ) {
540                 &MARCkoha2marcOnefield( $sth, $record, "additionalauthors.author", $bibliohash->{'author'},'' );
541         }
542         $sth2 = $dbh->prepare(" SELECT subject FROM bibliosubject WHERE biblionumber=?");
543         $sth2->execute($bibliohash->{biblionumber});
544         while ( my $row = $sth2->fetchrow_hashref ) {
545                 &MARCkoha2marcOnefield( $sth, $record, "bibliosubject.subject", $row->{'subject'},'' );
546         }
547         $sth2 = $dbh->prepare(" SELECT subtitle FROM bibliosubtitle WHERE biblionumber=?");
548         $sth2->execute($bibliohash->{biblionumber});
549         while ( my $row = $sth2->fetchrow_hashref ) {
550                 &MARCkoha2marcOnefield( $sth, $record, "bibliosubtitle.subtitle", $row->{'subtitle'},'' );
551         }
552         
553         return $record;
554 }
555
556 =head2 $MARCRecord = &MARCkoha2marcItem($dbh,$biblionumber,itemnumber);
557
558 MARCkoha2marcItem is a wrapper between old-DB and MARC-DB. It returns a MARC::Record builded with old-DB items :
559 all entries of the hash are transformed into their matching MARC field/subfield.
560
561 =over 4
562
563 =back
564
565 =cut
566
567 sub MARCkoha2marcItem {
568
569     # this function builds partial MARC::Record from the old koha-DB fields
570     my ( $dbh, $item ) = @_;
571
572     #    my $dbh=&C4Connect;
573     my $sth = $dbh->prepare("select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?");
574     my $record = MARC::Record->new();
575
576         foreach( keys %$item ) {
577                 if ( $item->{$_} ) {
578                         &MARCkoha2marcOnefield( $sth, $record, "items." . $_,
579                                 $item->{$_},'' );
580                 }
581         }
582     return $record;
583 }
584
585 =head2 MARCkoha2marcOnefield
586
587 =over 4
588
589 This sub is for internal use only, used by koha2marcBiblio & koha2marcItem
590
591 =back
592
593 =cut
594
595 sub MARCkoha2marcOnefield {
596     my ( $sth, $record, $kohafieldname, $value,$frameworkcode ) = @_;
597     my $tagfield;
598     my $tagsubfield;
599     $sth->execute($frameworkcode,$kohafieldname);
600     if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
601         if ( $record->field($tagfield) ) {
602             my $tag = $record->field($tagfield);
603             if ($tag) {
604                 $tag->add_subfields( $tagsubfield, $value );
605                 $record->delete_field($tag);
606                 $record->add_fields($tag);
607             }
608         }
609         else {
610             $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
611         }
612     }
613     return $record;
614 }
615
616 =head2 $MARCrecord = MARChtml2marc($dbh,$rtags,$rsubfields,$rvalues,%indicators);
617
618 =over 4
619
620 transforms the parameters (coming from HTML form) into a MARC::Record
621 parameters with r are references to arrays.
622
623 FIXME : should be improved for 3.0, to avoid having 4 differents arrays
624
625 =back
626
627 =cut
628
629 sub MARChtml2marc {
630         my ($dbh,$rtags,$rsubfields,$rvalues,%indicators) = @_;
631         my $prevtag = -1;
632         my $record = MARC::Record->new();
633 #       my %subfieldlist=();
634         my $prevvalue; # if tag <10
635         my $field; # if tag >=10
636         for (my $i=0; $i< @$rtags; $i++) {
637                 next unless @$rvalues[$i];
638                 # rebuild MARC::Record
639 #                       warn "0=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ";
640                 if (@$rtags[$i] ne $prevtag) {
641                         if ($prevtag < 10) {
642                                 if ($prevvalue) {
643                                         if ($prevtag ne '000') {
644                                                 $record->add_fields((sprintf "%03s",$prevtag),$prevvalue);
645                                         } else {
646                                                 $record->leader($prevvalue);
647                                         }
648                                 }
649                         } else {
650                                 if ($field) {
651                                         $record->add_fields($field);
652                                 }
653                         }
654                         $indicators{@$rtags[$i]}.='  ';
655                         if (@$rtags[$i] <10) {
656                                 $prevvalue= @$rvalues[$i];
657                                 undef $field;
658                         } else {
659                                 undef $prevvalue;
660                                 $field = MARC::Field->new( (sprintf "%03s",@$rtags[$i]), substr($indicators{@$rtags[$i]},0,1),substr($indicators{@$rtags[$i]},1,1), @$rsubfields[$i] => @$rvalues[$i]);
661 #                       warn "1=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ".$field->as_formatted;
662                         }
663                         $prevtag = @$rtags[$i];
664                 } else {
665                         if (@$rtags[$i] <10) {
666                                 $prevvalue=@$rvalues[$i];
667                         } else {
668                                 if (length(@$rvalues[$i])>0) {
669                                         $field->add_subfields(@$rsubfields[$i] => @$rvalues[$i]);
670 #                       warn "2=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ".$field->as_formatted;
671                                 }
672                         }
673                         $prevtag= @$rtags[$i];
674                 }
675         }
676         # the last has not been included inside the loop... do it now !
677         $record->add_fields($field) if $field;
678 #       warn "HTML2MARC=".$record->as_formatted;
679         return $record;
680 }
681
682
683 =head2 $hash = &MARCmarc2koha($dbh,$MARCRecord);
684
685 =over 4
686
687 builds a hash with old-db datas from a MARC::Record
688
689 =back
690
691 =cut
692
693 sub MARCmarc2koha {
694         my ($dbh,$record,$frameworkcode) = @_;
695         my $sth=$dbh->prepare("select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?");
696         my $result;  
697         my $sth2=$dbh->prepare("SHOW COLUMNS from biblio");
698         $sth2->execute;
699         my $field;
700         while (($field)=$sth2->fetchrow) {
701 #               warn "biblio.".$field;
702                 $result=&MARCmarc2kohaOneField($sth,"biblio",$field,$record,$result,$frameworkcode);
703         }
704         $sth2=$dbh->prepare("SHOW COLUMNS from biblioitems");
705         $sth2->execute;
706         while (($field)=$sth2->fetchrow) {
707                 if ($field eq 'notes') { $field = 'bnotes'; }
708 #               warn "biblioitems".$field;
709                 $result=&MARCmarc2kohaOneField($sth,"biblioitems",$field,$record,$result,$frameworkcode);
710         }
711         $sth2=$dbh->prepare("SHOW COLUMNS from items");
712         $sth2->execute;
713         while (($field)=$sth2->fetchrow) {
714 #               warn "items".$field;
715                 $result=&MARCmarc2kohaOneField($sth,"items",$field,$record,$result,$frameworkcode);
716         }
717         # additional authors : specific
718         $result = &MARCmarc2kohaOneField($sth,"bibliosubtitle","subtitle",$record,$result,$frameworkcode);
719         $result = &MARCmarc2kohaOneField($sth,"additionalauthors","additionalauthors",$record,$result,$frameworkcode);
720 # modify copyrightdate to keep only the 1st year found
721         my $temp = $result->{'copyrightdate'};
722         if ($temp){
723                 $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
724                 if ($1>0) {
725                         $result->{'copyrightdate'} = $1;
726                 } else { # if no cYYYY, get the 1st date.
727                         $temp =~ m/(\d\d\d\d)/;
728                         $result->{'copyrightdate'} = $1;
729                 }
730         }
731 # modify publicationyear to keep only the 1st year found
732         $temp = $result->{'publicationyear'};
733         $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
734         if ($1>0) {
735                 $result->{'publicationyear'} = $1;
736         } else { # if no cYYYY, get the 1st date.
737                 $temp =~ m/(\d\d\d\d)/;
738                 $result->{'publicationyear'} = $1;
739         }
740         return $result;
741 }
742
743 sub MARCmarc2kohaOneField {
744
745 # FIXME ? if a field has a repeatable subfield that is used in old-db, only the 1st will be retrieved...
746     my ( $sth, $kohatable, $kohafield, $record, $result,$frameworkcode ) = @_;
747     #    warn "kohatable / $kohafield / $result / ";
748     my $res = "";
749     my $tagfield;
750     my $subfield;
751     ( $tagfield, $subfield ) = MARCfind_marc_from_kohafield("",$kohatable.".".$kohafield,$frameworkcode);
752     foreach my $field ( $record->field($tagfield) ) {
753                 if ($field->tag()<10) {
754                         if ($result->{$kohafield}) {
755                                 # Reverse array filled with elements from repeated subfields 
756                                 # from first to last to avoid last to first concatenation of 
757                                 # elements in Koha DB.  -- thd.
758                                 $result->{$kohafield} .= " | ".reverse($field->data());
759                         } else {
760                                 $result->{$kohafield} = $field->data();
761                         }
762                 } else {
763                         if ( $field->subfields ) {
764                                 my @subfields = $field->subfields();
765                                 foreach my $subfieldcount ( 0 .. $#subfields ) {
766                                         if ($subfields[$subfieldcount][0] eq $subfield) {
767                                                 if ( $result->{$kohafield} ) {
768                                                         $result->{$kohafield} .= " | " . $subfields[$subfieldcount][1];
769                                                 }
770                                                 else {
771                                                         $result->{$kohafield} = $subfields[$subfieldcount][1];
772                                                 }
773                                         }
774                                 }
775                         }
776                 }
777     }
778 #       warn "OneField for $kohatable.$kohafield and $frameworkcode=> $tagfield, $subfield";
779     return $result;
780 }
781
782 =head2 ($biblionumber,$biblioitemnumber) = NEWnewbibilio($dbh,$MARCRecord,$frameworkcode);
783
784 =over 4
785
786 creates a biblio from a MARC::Record.
787
788 =back
789
790 =cut
791
792 sub NEWnewbiblio {
793     my ( $dbh,$Zconn,$record,$frameworkcode ) = @_;
794     my $biblionumber;
795     my $biblioitemnumber;
796     my $olddata = MARCmarc2koha( $dbh, $record,$frameworkcode );
797         $olddata->{frameworkcode} = $frameworkcode;
798     $biblionumber = REALnewbiblio( $dbh, $olddata );
799         $olddata->{biblionumber} = $biblionumber;
800         # add biblionumber into the MARC record (it's the ID for zebra)
801         my ( $tagfield, $tagsubfield ) =
802                                         MARCfind_marc_from_kohafield( $dbh, "biblio.biblionumber",$frameworkcode );
803         # create the field
804         my $newfield;
805         if ($tagfield<10) {
806                 $newfield = MARC::Field->new(
807                         $tagfield, $biblionumber,
808                 );
809         } else {
810                 $newfield = MARC::Field->new(
811                         $tagfield, '', '', "$tagsubfield" => $biblionumber,
812                 );
813         }
814         # drop old field (just in case it already exist and create new one...
815         my $old_field = $record->field($tagfield);
816         $record->delete_field($old_field);
817         $record->add_fields($newfield);
818
819         #create the marc entry, that stores the rax marc record in Koha 3.0
820         $olddata->{marc} = $record->as_usmarc();
821         $olddata->{marcxml} = $record->as_xml();
822         # and create biblioitem, that's all folks !
823     $biblioitemnumber = REALnewbiblioitem( $dbh, $Zconn, $olddata );
824
825     # search subtiles, addiauthors and subjects
826     ( $tagfield, $tagsubfield ) =
827       MARCfind_marc_from_kohafield( $dbh, "additionalauthors.author",$frameworkcode );
828     my @addiauthfields = $record->field($tagfield);
829     foreach my $addiauthfield (@addiauthfields) {
830         my @addiauthsubfields = $addiauthfield->subfield($tagsubfield);
831         foreach my $subfieldcount ( 0 .. $#addiauthsubfields ) {
832             REALmodaddauthor( $dbh, $biblionumber,
833                 $addiauthsubfields[$subfieldcount] );
834         }
835     }
836     ( $tagfield, $tagsubfield ) =
837       MARCfind_marc_from_kohafield( $dbh, "bibliosubtitle.subtitle",$frameworkcode );
838     my @subtitlefields = $record->field($tagfield);
839     foreach my $subtitlefield (@subtitlefields) {
840         my @subtitlesubfields = $subtitlefield->subfield($tagsubfield);
841         foreach my $subfieldcount ( 0 .. $#subtitlesubfields ) {
842             REALnewsubtitle( $dbh, $biblionumber,
843                 $subtitlesubfields[$subfieldcount] );
844         }
845     }
846     ( $tagfield, $tagsubfield ) =
847       MARCfind_marc_from_kohafield( $dbh, "bibliosubject.subject",$frameworkcode );
848     my @subj = $record->field($tagfield);
849     my @subjects;
850     foreach my $subject (@subj) {
851         my @subjsubfield = $subject->subfield($tagsubfield);
852         foreach my $subfieldcount ( 0 .. $#subjsubfield ) {
853             push @subjects, $subjsubfield[$subfieldcount];
854         }
855     }
856     REALmodsubject( $dbh, $biblionumber, 1, @subjects );
857     return ( $biblionumber, $biblioitemnumber );
858 }
859
860 =head2 NEWmodbilbioframework($dbh,$biblionumber,$frameworkcode);
861
862 =over 4
863
864 modify the framework of a biblio
865
866 =back
867
868 =cut
869
870 sub NEWmodbiblioframework {
871         my ($dbh,$biblionumber,$frameworkcode) =@_;
872         my $sth = $dbh->prepare("Update biblio SET frameworkcode=? WHERE biblionumber=?");
873         $sth->execute($frameworkcode,$biblionumber);
874         return 1;
875 }
876
877 =head2 NEWmodbiblio($dbh,$Zconn,$MARCrecord,$biblionumber,$frameworkcode);
878
879 =over 4
880
881 modify a biblio (MARC=ON)
882
883 =back
884
885 =cut
886
887 sub NEWmodbiblio {
888         my ($dbh,$Zconn,$record,$biblionumber,$frameworkcode) =@_;
889         $frameworkcode="" unless $frameworkcode;
890 #       &MARCmodbiblio($dbh,$bibid,$record,$frameworkcode,0);
891         my $oldbiblio = MARCmarc2koha($dbh,$record,$frameworkcode);
892         
893         $oldbiblio->{frameworkcode} = $frameworkcode;
894         #create the marc entry, that stores the rax marc record in Koha 3.0
895         $oldbiblio->{biblionumber} = $biblionumber unless $oldbiblio->{biblionumber};
896         $oldbiblio->{marc} = $record->as_usmarc();
897         $oldbiblio->{marcxml} = $record->as_xml();
898         warn "dans NEWmodbiblio $biblionumber = ".$oldbiblio->{biblionumber}." = ".$oldbiblio->{marcxml};
899         REALmodbiblio($dbh,$oldbiblio);
900         REALmodbiblioitem($dbh,$Zconn,$oldbiblio);
901         # now, modify addi authors, subject, addititles.
902         my ($tagfield,$tagsubfield) = MARCfind_marc_from_kohafield($dbh,"additionalauthors.author",$frameworkcode);
903         my @addiauthfields = $record->field($tagfield);
904         foreach my $addiauthfield (@addiauthfields) {
905                 my @addiauthsubfields = $addiauthfield->subfield($tagsubfield);
906                 $dbh->do("delete from additionalauthors where biblionumber=$biblionumber");
907                 foreach my $subfieldcount (0..$#addiauthsubfields) {
908                         REALmodaddauthor($dbh,$biblionumber,$addiauthsubfields[$subfieldcount]);
909                 }
910         }
911         ($tagfield,$tagsubfield) = MARCfind_marc_from_kohafield($dbh,"bibliosubtitle.subtitle",$frameworkcode);
912         my @subtitlefields = $record->field($tagfield);
913         foreach my $subtitlefield (@subtitlefields) {
914                 my @subtitlesubfields = $subtitlefield->subfield($tagsubfield);
915                 # delete & create subtitle again because REALmodsubtitle can't handle new subtitles
916                 # between 2 modifs
917                 $dbh->do("delete from bibliosubtitle where biblionumber=$biblionumber");
918                 foreach my $subfieldcount (0..$#subtitlesubfields) {
919                         foreach my $subtit(split /\||#/,$subtitlesubfields[$subfieldcount]) {
920                                 REALnewsubtitle($dbh,$biblionumber,$subtit);
921                         }
922                 }
923         }
924         ($tagfield,$tagsubfield) = MARCfind_marc_from_kohafield($dbh,"bibliosubject.subject",$frameworkcode);
925         my @subj = $record->field($tagfield);
926         my @subjects;
927         foreach my $subject (@subj) {
928                 my @subjsubfield = $subject->subfield($tagsubfield);
929                 foreach my $subfieldcount (0..$#subjsubfield) {
930                         push @subjects,$subjsubfield[$subfieldcount];
931                 }
932         }
933         REALmodsubject($dbh,$biblionumber,1,@subjects);
934         return 1;
935 }
936
937 =head2 NEWmodbilbioframework($dbh,$biblionumber,$frameworkcode);
938
939 =over 4
940
941 delete a biblio
942
943 =back
944
945 =cut
946
947 sub NEWdelbiblio {
948     my ( $dbh, $bibid ) = @_;
949     my $biblio = &MARCfind_oldbiblionumber_from_MARCbibid( $dbh, $bibid );
950     &REALdelbiblio( $dbh, $biblio );
951     my $sth =
952       $dbh->prepare(
953         "select biblioitemnumber from biblioitems where biblionumber=?");
954     $sth->execute($biblio);
955     while ( my ($biblioitemnumber) = $sth->fetchrow ) {
956         REALdelbiblioitem( $dbh, $biblioitemnumber );
957     }
958     &MARCdelbiblio( $dbh, $bibid, 0 );
959 }
960
961 =head2 $itemnumber = NEWnewitem($dbh, $Zconn, $record, $biblionumber, $biblioitemnumber);
962
963 =over 4
964
965 creates an item from a MARC::Record
966
967 =back
968
969 =cut
970
971 sub NEWnewitem {
972     my ( $dbh,$Zconn,$record,$biblionumber,$biblioitemnumber ) = @_;
973
974     # add item in old-DB
975         my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
976     my $item = &MARCmarc2koha( $dbh,$record,$frameworkcode );
977     # needs old biblionumber and biblioitemnumber
978     $item->{'biblionumber'} = $biblionumber;
979     $item->{'biblioitemnumber'}=$biblioitemnumber;
980     $item->{marc} = $record->as_usmarc();
981     warn $item->{marc};
982     my ( $itemnumber, $error ) = &REALnewitems( $dbh, $Zconn, $item, $item->{barcode} );
983         return $itemnumber;
984 }
985
986
987 =head2 $itemnumber = NEWmoditem($dbh, $Zconn, $record, $biblionumber, $biblioitemnumber,$itemnumber);
988
989 =over 4
990
991 Modify an item
992
993 =back
994
995 =cut
996
997 sub NEWmoditem {
998     my ( $dbh, $Zconn, $record, $biblionumber, $biblioitemnumber, $itemnumber) = @_;
999     
1000         my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
1001     my $olditem = MARCmarc2koha( $dbh, $record,$frameworkcode );
1002         # add MARC record
1003         $olditem->{marc} = $record->as_usmarc();
1004         $olditem->{biblionumber} = $biblionumber;
1005         $olditem->{biblioitemnumber} = $biblioitemnumber;
1006         # and modify item
1007     REALmoditem( $dbh, $Zconn, $olditem );
1008 }
1009
1010
1011 =head2 $itemnumber = NEWdelitem($dbh, $biblionumber, $biblioitemnumber, $itemnumber);
1012
1013 =over 4
1014
1015 delete an item
1016
1017 =back
1018
1019 =cut
1020
1021 sub NEWdelitem {
1022     my ( $dbh, $bibid, $itemnumber ) = @_;
1023     my $biblio = &MARCfind_oldbiblionumber_from_MARCbibid( $dbh, $bibid );
1024     &REALdelitem( $dbh, $itemnumber );
1025     &MARCdelitem( $dbh, $bibid, $itemnumber );
1026 }
1027
1028
1029 =head2 $biblionumber = REALnewbiblio($dbh,$biblio);
1030
1031 =over 4
1032
1033 adds a record in biblio table. Datas are in the hash $biblio.
1034
1035 =back
1036
1037 =cut
1038
1039 sub REALnewbiblio {
1040     my ( $dbh, $biblio ) = @_;
1041
1042         $dbh->do('lock tables biblio WRITE');
1043     my $sth = $dbh->prepare("Select max(biblionumber) from biblio");
1044     $sth->execute;
1045     my $data   = $sth->fetchrow_arrayref;
1046     my $bibnum = $$data[0] + 1;
1047     my $series = 0;
1048
1049     if ( $biblio->{'seriestitle'} ) { $series = 1 }
1050     $sth->finish;
1051     $sth =
1052       $dbh->prepare("insert into biblio set     biblionumber=?, title=?,                author=?,       copyrightdate=?,
1053                                                                                         serial=?,               seriestitle=?,  notes=?,        abstract=?,
1054                                                                                         unititle=?"
1055     );
1056     $sth->execute(
1057         $bibnum,             $biblio->{'title'},
1058         $biblio->{'author'}, $biblio->{'copyrightdate'},
1059         $biblio->{'serial'},             $biblio->{'seriestitle'},
1060         $biblio->{'notes'},  $biblio->{'abstract'},
1061                 $biblio->{'unititle'}
1062     );
1063
1064     $sth->finish;
1065         $dbh->do('unlock tables');
1066     return ($bibnum);
1067 }
1068
1069 =head2 $biblionumber = REALmodbiblio($dbh,$biblio);
1070
1071 =over 4
1072
1073 modify a record in biblio table. Datas are in the hash $biblio.
1074
1075 =back
1076
1077 =cut
1078
1079 sub REALmodbiblio {
1080     my ( $dbh, $biblio ) = @_;
1081     my $sth = $dbh->prepare("Update biblio set  title=?,                author=?,       abstract=?,     copyrightdate=?,
1082                                                                                                 seriestitle=?,  serial=?,       unititle=?,     notes=?,        frameworkcode=? 
1083                                                                                         where biblionumber = ?"
1084     );
1085     $sth->execute(
1086                 $biblio->{'title'},       $biblio->{'author'},
1087                 $biblio->{'abstract'},    $biblio->{'copyrightdate'},
1088                 $biblio->{'seriestitle'}, $biblio->{'serial'},
1089                 $biblio->{'unititle'},    $biblio->{'notes'},
1090                 $biblio->{frameworkcode},
1091                 $biblio->{'biblionumber'}
1092     );
1093         $sth->finish;
1094         return ( $biblio->{'biblionumber'} );
1095 }    # sub modbiblio
1096
1097 =head2 REALmodsubtitle($dbh,$bibnum,$subtitle);
1098
1099 =over 4
1100
1101 modify subtitles in bibliosubtitle table.
1102
1103 =back
1104
1105 =cut
1106
1107 sub REALmodsubtitle {
1108     my ( $dbh, $bibnum, $subtitle ) = @_;
1109     my $sth =
1110       $dbh->prepare(
1111         "update bibliosubtitle set subtitle = ? where biblionumber = ?");
1112     $sth->execute( $subtitle, $bibnum );
1113     $sth->finish;
1114 }    # sub modsubtitle
1115
1116 =head2 REALmodaddauthor($dbh,$bibnum,$author);
1117
1118 =over 4
1119
1120 adds or modify additional authors
1121 NOTE :  Strange sub : seems to delete MANY and add only ONE author... maybe buggy ?
1122
1123 =back
1124
1125 =cut
1126
1127 sub REALmodaddauthor {
1128     my ( $dbh, $bibnum, @authors ) = @_;
1129
1130     #    my $dbh   = C4Connect;
1131     my $sth =
1132       $dbh->prepare("Delete from additionalauthors where biblionumber = ?");
1133
1134     $sth->execute($bibnum);
1135     $sth->finish;
1136     foreach my $author (@authors) {
1137         if ( $author ne '' ) {
1138             $sth =
1139               $dbh->prepare(
1140                 "Insert into additionalauthors set author = ?, biblionumber = ?"
1141             );
1142
1143             $sth->execute( $author, $bibnum );
1144
1145             $sth->finish;
1146         }    # if
1147     }
1148 }    # sub modaddauthor
1149
1150 =head2 $errors = REALmodsubject($dbh,$bibnum, $force, @subject);
1151
1152 =over 4
1153
1154 modify/adds subjects
1155
1156 =back
1157
1158 =cut
1159 sub REALmodsubject {
1160     my ( $dbh, $bibnum, $force, @subject ) = @_;
1161
1162     #  my $dbh   = C4Connect;
1163     my $count = @subject;
1164     my $error="";
1165     for ( my $i = 0 ; $i < $count ; $i++ ) {
1166         $subject[$i] =~ s/^ //g;
1167         $subject[$i] =~ s/ $//g;
1168         my $sth =
1169           $dbh->prepare(
1170 "select * from catalogueentry where entrytype = 's' and catalogueentry = ?"
1171         );
1172         $sth->execute( $subject[$i] );
1173
1174         if ( my $data = $sth->fetchrow_hashref ) {
1175         }
1176         else {
1177             if ( $force eq $subject[$i] || $force == 1 ) {
1178
1179                 # subject not in aut, chosen to force anway
1180                 # so insert into cataloguentry so its in auth file
1181                 my $sth2 =
1182                   $dbh->prepare(
1183 "Insert into catalogueentry (entrytype,catalogueentry) values ('s',?)"
1184                 );
1185
1186                 $sth2->execute( $subject[$i] ) if ( $subject[$i] );
1187                 $sth2->finish;
1188             }
1189             else {
1190                 $error =
1191                   "$subject[$i]\n does not exist in the subject authority file";
1192                 my $sth2 =
1193                   $dbh->prepare(
1194 "Select * from catalogueentry where entrytype = 's' and (catalogueentry like ? or catalogueentry like ? or catalogueentry like ?)"
1195                 );
1196                 $sth2->execute( "$subject[$i] %", "% $subject[$i] %",
1197                     "% $subject[$i]" );
1198                 while ( my $data = $sth2->fetchrow_hashref ) {
1199                     $error .= "<br>$data->{'catalogueentry'}";
1200                 }    # while
1201                 $sth2->finish;
1202             }    # else
1203         }    # else
1204         $sth->finish;
1205     }    # else
1206     if ($error eq '') {
1207         my $sth =
1208           $dbh->prepare("Delete from bibliosubject where biblionumber = ?");
1209         $sth->execute($bibnum);
1210         $sth->finish;
1211         $sth =
1212           $dbh->prepare(
1213             "Insert into bibliosubject (subject,biblionumber) values (?,?)");
1214         my $query;
1215         foreach $query (@subject) {
1216             $sth->execute( $query, $bibnum ) if ( $query && $bibnum );
1217         }    # foreach
1218         $sth->finish;
1219     }    # if
1220
1221     #  $dbh->disconnect;
1222     return ($error);
1223 }    # sub modsubject
1224
1225 =head2 REALmodbiblioitem($dbh, $biblioitem);
1226
1227 =over 4
1228
1229 modify a biblioitem
1230
1231 =back
1232
1233 =cut
1234 sub REALmodbiblioitem {
1235     my ( $dbh, $Zconn, $biblioitem ) = @_;
1236     my $query;
1237
1238     my $sth = $dbh->prepare("update biblioitems set number=?,volume=?,                  volumedate=?,           lccn=?,
1239                                                                                 itemtype=?,                     url=?,                          isbn=?,                         issn=?,
1240                                                                                 publishercode=?,        publicationyear=?,      classification=?,       dewey=?,
1241                                                                                 subclass=?,                     illus=?,                        pages=?,                        volumeddesc=?,
1242                                                                                 notes=?,                        size=?,                         place=?,                        marc=?,
1243                                                                                 marcxml=?
1244                                                         where biblioitemnumber=?");
1245         $sth->execute(  $biblioitem->{number},                  $biblioitem->{volume},  $biblioitem->{volumedate},      $biblioitem->{lccn},
1246                                         $biblioitem->{itemtype},                $biblioitem->{url},             $biblioitem->{isbn},    $biblioitem->{issn},
1247                                 $biblioitem->{publishercode},   $biblioitem->{publicationyear}, $biblioitem->{classification},  $biblioitem->{dewey},
1248                                 $biblioitem->{subclass},                $biblioitem->{illus},           $biblioitem->{pages},   $biblioitem->{volumeddesc},
1249                                 $biblioitem->{bnotes},                  $biblioitem->{size},            $biblioitem->{place},   $biblioitem->{marc},
1250                                         $biblioitem->{marcxml},                 $biblioitem->{biblioitemnumber});
1251         my $record = MARC::File::USMARC::decode($biblioitem->{marc});
1252
1253         #my $Zconn = C4::Context->Zconn or die "unable to set Zconn";
1254         z3950_extended_services($Zconn,'update',set_service_options('update'),$record);
1255          #z3950_extended_services($Zconn,'commit',set_service_options('commit'));
1256
1257
1258 #       warn "MOD : $biblioitem->{biblioitemnumber} = ".$biblioitem->{marc};
1259 }    # sub modbibitem
1260
1261 =head2 REALnewbiblioitem($dbh,$Zconn,$biblioitem);
1262
1263 =over 4
1264
1265 adds a biblioitem ($biblioitem is a hash with the values)
1266
1267 =back
1268
1269 =cut
1270
1271 sub REALnewbiblioitem {
1272         my ( $dbh, $Zconn, $biblioitem ) = @_;
1273
1274         $dbh->do("lock tables biblioitems WRITE, biblio WRITE, marc_subfield_structure READ");
1275         my $sth = $dbh->prepare("Select max(biblioitemnumber) from biblioitems");
1276         my $data;
1277         my $biblioitemnumber;
1278
1279         $sth->execute;
1280         $data       = $sth->fetchrow_arrayref;
1281         $biblioitemnumber = $$data[0] + 1;
1282         
1283         # Insert biblioitemnumber in MARC record, we need it to manage items later...
1284         my $frameworkcode=MARCfind_frameworkcode($dbh,$biblioitem->{biblionumber});
1285         my ($biblioitemnumberfield,$biblioitemnumbersubfield) = MARCfind_marc_from_kohafield($dbh,'biblioitems.biblioitemnumber',$frameworkcode);
1286         my $record = MARC::File::USMARC::decode($biblioitem->{marc});
1287         my $field=$record->field($biblioitemnumberfield);
1288         $field->update($biblioitemnumbersubfield => "$biblioitemnumber");
1289         $biblioitem->{marc} = $record->as_usmarc();
1290         $biblioitem->{marcxml} = $record->as_xml();
1291
1292         $sth = $dbh->prepare( "insert into biblioitems set
1293                                                                         biblioitemnumber = ?,           biblionumber     = ?,
1294                                                                         volume           = ?,                   number           = ?,
1295                                                                         classification  = ?,                    itemtype         = ?,
1296                                                                         url              = ?,                           isbn             = ?,
1297                                                                         issn             = ?,                           dewey            = ?,
1298                                                                         subclass         = ?,                           publicationyear  = ?,
1299                                                                         publishercode    = ?,           volumedate       = ?,
1300                                                                         volumeddesc      = ?,           illus            = ?,
1301                                                                         pages            = ?,                           notes            = ?,
1302                                                                         size             = ?,                           lccn             = ?,
1303                                                                         marc             = ?,                           place            = ?,
1304                                                                         marcxml          = ?"
1305         );
1306         $sth->execute(
1307                 $biblioitemnumber,               $biblioitem->{'biblionumber'},
1308                 $biblioitem->{'volume'},         $biblioitem->{'number'},
1309                 $biblioitem->{'classification'}, $biblioitem->{'itemtype'},
1310                 $biblioitem->{'url'},            $biblioitem->{'isbn'},
1311                 $biblioitem->{'issn'},           $biblioitem->{'dewey'},
1312                 $biblioitem->{'subclass'},       $biblioitem->{'publicationyear'},
1313                 $biblioitem->{'publishercode'},  $biblioitem->{'volumedate'},
1314                 $biblioitem->{'volumeddesc'},    $biblioitem->{'illus'},
1315                 $biblioitem->{'pages'},          $biblioitem->{'bnotes'},
1316                 $biblioitem->{'size'},           $biblioitem->{'lccn'},
1317                 $biblioitem->{'marc'},           $biblioitem->{'place'},
1318                 $biblioitem->{marcxml},
1319         );
1320         $dbh->do("unlock tables");
1321         #my $Zconn = C4::Context->Zconn or die "unable to set Zconn";
1322         z3950_extended_services($Zconn,'update',set_service_options('update'),$record);
1323         #z3950_extended_services($Zconn,'commit',set_service_options('commit'));
1324         #zebra_create($biblioitem->{biblionumber}, $record);
1325         return ($biblioitemnumber);
1326 }
1327
1328 =head2 REALnewsubtitle($dbh,$bibnum,$subtitle);
1329
1330 =over 4
1331
1332 create a new subtitle
1333
1334 =back
1335
1336 =cut
1337 sub REALnewsubtitle {
1338     my ( $dbh, $bibnum, $subtitle ) = @_;
1339     my $sth =
1340       $dbh->prepare(
1341         "insert into bibliosubtitle set biblionumber = ?, subtitle = ?");
1342     $sth->execute( $bibnum, $subtitle ) if $subtitle;
1343     $sth->finish;
1344 }
1345
1346 =head2 ($itemnumber,$errors)= REALnewitems($dbh,$Zconn,$item,$barcode);
1347
1348 =over 4
1349
1350 create a item. $item is a hash and $barcode the barcode.
1351
1352 =back
1353
1354 =cut
1355
1356 sub REALnewitems {
1357     my ( $dbh, $Zconn,$item, $barcode ) = @_;
1358
1359 #       warn "OLDNEWITEMS";
1360         
1361         $dbh->do('lock tables items WRITE, biblio WRITE,biblioitems WRITE,marc_subfield_structure WRITE');
1362     my $sth = $dbh->prepare("Select max(itemnumber) from items");
1363     my $data;
1364     my $itemnumber;
1365     my $error = "";
1366     $sth->execute;
1367     $data       = $sth->fetchrow_hashref;
1368     $itemnumber = $data->{'max(itemnumber)'} + 1;
1369
1370 # FIXME the "notforloan" field seems to be named "loan" in some places. workaround bugfix.
1371     if ( $item->{'loan'} ) {
1372         $item->{'notforloan'} = $item->{'loan'};
1373     }
1374         $item->{'biblioitemnumber'} = 1;
1375     # if dateaccessioned is provided, use it. Otherwise, set to NOW()
1376     if ( $item->{'dateaccessioned'} ) {
1377         $sth = $dbh->prepare( "Insert into items set
1378                                                         itemnumber           = ?,                       biblionumber         = ?,
1379                                                         multivolumepart      = ?,
1380                                                         biblioitemnumber     = ?,                       barcode              = ?,
1381                                                         booksellerid         = ?,                       dateaccessioned      = ?,
1382                                                         homebranch           = ?,                       holdingbranch        = ?,
1383                                                         price                = ?,                       replacementprice     = ?,
1384                                                         replacementpricedate = NOW(),           datelastseen            = NOW(),
1385                                                         multivolume                     = ?,                    stack                           = ?,
1386                                                         itemlost                        = ?,                    wthdrawn                        = ?,
1387                                                         paidfor                         = ?,                    itemnotes            = ?,
1388                                                         itemcallnumber  =?,                                                     notforloan = ?,
1389                                                         location = ?
1390                                                         "
1391         );
1392         $sth->execute(
1393                         $itemnumber,                            $item->{'biblionumber'},
1394                         $item->{'multivolumepart'},
1395                         $item->{'biblioitemnumber'},$item->{barcode},
1396                         $item->{'booksellerid'},        $item->{'dateaccessioned'},
1397                         $item->{'homebranch'},          $item->{'holdingbranch'},
1398                         $item->{'price'},                       $item->{'replacementprice'},
1399                         $item->{multivolume},           $item->{stack},
1400                         $item->{itemlost},                      $item->{wthdrawn},
1401                         $item->{paidfor},                       $item->{'itemnotes'},
1402                         $item->{'itemcallnumber'},      $item->{'notforloan'},
1403                         $item->{'location'}
1404         );
1405                 if ( defined $sth->errstr ) {
1406                         $error .= $sth->errstr;
1407                 }
1408     }
1409     else {
1410         $sth = $dbh->prepare( "Insert into items set
1411                                                         itemnumber           = ?,                       biblionumber         = ?,
1412                                                         multivolumepart      = ?,
1413                                                         biblioitemnumber     = ?,                       barcode              = ?,
1414                                                         booksellerid         = ?,                       dateaccessioned      = NOW(),
1415                                                         homebranch           = ?,                       holdingbranch        = ?,
1416                                                         price                = ?,                       replacementprice     = ?,
1417                                                         replacementpricedate = NOW(),           datelastseen            = NOW(),
1418                                                         multivolume                     = ?,                    stack                           = ?,
1419                                                         itemlost                        = ?,                    wthdrawn                        = ?,
1420                                                         paidfor                         = ?,                    itemnotes            = ?,
1421                                                         itemcallnumber  =?,                                                     notforloan = ?,
1422                                                         location = ?
1423                                                         "
1424         );
1425         $sth->execute(
1426                         $itemnumber,                            $item->{'biblionumber'},
1427                         $item->{'multivolumepart'},
1428                         $item->{'biblioitemnumber'},$item->{barcode},
1429                         $item->{'booksellerid'},
1430                         $item->{'homebranch'},          $item->{'holdingbranch'},
1431                         $item->{'price'},                       $item->{'replacementprice'},
1432                         $item->{multivolume},           $item->{stack},
1433                         $item->{itemlost},                      $item->{wthdrawn},
1434                         $item->{paidfor},                       $item->{'itemnotes'},
1435                         $item->{'itemcallnumber'},      $item->{'notforloan'},
1436                         $item->{'location'}
1437         );
1438                 if ( defined $sth->errstr ) {
1439                         $error .= $sth->errstr;
1440                 }
1441     }
1442         # item stored, now, deal with the marc part...
1443         $sth = $dbh->prepare("select biblioitems.marc,biblio.frameworkcode from biblioitems,biblio 
1444                                                         where   biblio.biblionumber=biblioitems.biblionumber and 
1445                                                                         biblio.biblionumber=?");
1446         $sth->execute($item->{biblionumber});
1447     if ( defined $sth->errstr ) {
1448         $error .= $sth->errstr;
1449     }
1450         my ($rawmarc,$frameworkcode) = $sth->fetchrow;
1451         warn "ERROR IN REALnewitem, MARC record not found FOR $item->{biblionumber} => $rawmarc <=" unless $rawmarc;
1452         my $record = MARC::File::USMARC::decode($rawmarc);
1453         # ok, we have the marc record, add item number to the item field (in {marc}, and add the field to the record)
1454         my ($itemnumberfield,$itemnumbersubfield) = MARCfind_marc_from_kohafield($dbh,'items.itemnumber',$frameworkcode);
1455         my $itemrecord = MARC::Record->new_from_usmarc($item->{marc});
1456         warn $itemrecord;
1457         warn $itemnumberfield;
1458         warn $itemrecord->field($itemnumberfield);
1459         my $itemfield = $itemrecord->field($itemnumberfield);
1460         $itemfield->add_subfields($itemnumbersubfield => "$itemnumber");
1461         $record->insert_grouped_field($itemfield);
1462         # save the record into biblioitem
1463         $sth=$dbh->prepare("update biblioitems set marc=?,marcxml=? where biblionumber=?");
1464         $sth->execute($record->as_usmarc(),$record->as_xml(),$item->{biblionumber});
1465     if ( defined $sth->errstr ) {
1466         $error .= $sth->errstr;
1467     }
1468         #my $Zconn = C4::Context->Zconn or die "unable to set Zconn";
1469          z3950_extended_services($Zconn,'update',set_service_options('update'),$record);
1470          # z3950_extended_services($Zconn,'commit',set_service_options('commit'));
1471          #zebra_create($item->{biblionumber},$record);
1472         $dbh->do('unlock tables');
1473     return ( $itemnumber, $error );
1474 }
1475
1476 =head2 REALmoditem($dbh,$Zconn,$item);
1477
1478 =over 4
1479
1480 modify item
1481
1482 =back
1483
1484 =cut
1485
1486 sub REALmoditem {
1487     my ( $dbh, $Zconn, $item ) = @_;
1488     $item->{'bibitemnum'} = 1;
1489         my $error;
1490         $dbh->do('lock tables items WRITE, biblio WRITE,biblioitems WRITE');
1491     $item->{'itemnum'} = $item->{'itemnumber'} unless $item->{'itemnum'};
1492     my $query = "update items set  barcode=?,itemnotes=?,itemcallnumber=?,notforloan=?,location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?";
1493     my @bind = (
1494         $item->{'barcode'},                     $item->{'itemnotes'},
1495         $item->{'itemcallnumber'},      $item->{'notforloan'},
1496         $item->{'location'},            $item->{multivolumepart},
1497                 $item->{multivolume},           $item->{stack},
1498                 $item->{wthdrawn},
1499     );
1500     if ( $item->{'lost'} ne '' ) {
1501         $query = "update items set biblioitemnumber=?,barcode=?,itemnotes=?,homebranch=?,
1502                                                         itemlost=?,wthdrawn=?,itemcallnumber=?,notforloan=?,
1503                                                         location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?";
1504         @bind = (
1505             $item->{'bibitemnum'},     $item->{'barcode'},
1506             $item->{'itemnotes'},          $item->{'homebranch'},
1507             $item->{'lost'},           $item->{'wthdrawn'},
1508             $item->{'itemcallnumber'}, $item->{'notforloan'},
1509             $item->{'location'},                $item->{multivolumepart},
1510                         $item->{multivolume},           $item->{stack},
1511                         $item->{wthdrawn},
1512         );
1513                 if ($item->{homebranch}) {
1514                         $query.=",homebranch=?";
1515                         push @bind, $item->{homebranch};
1516                 }
1517                 if ($item->{holdingbranch}) {
1518                         $query.=",holdingbranch=?";
1519                         push @bind, $item->{holdingbranch};
1520                 }
1521     }
1522         $query.=" where itemnumber=?";
1523         push @bind,$item->{'itemnum'};
1524    if ( $item->{'replacement'} ne '' ) {
1525         $query =~ s/ where/,replacementprice='$item->{'replacement'}' where/;
1526     }
1527     my $sth = $dbh->prepare($query);
1528     $sth->execute(@bind);
1529         
1530         # item stored, now, deal with the marc part...
1531         $sth = $dbh->prepare("select biblioitems.marc,biblio.frameworkcode from biblioitems,biblio 
1532                                                         where   biblio.biblionumber=biblioitems.biblionumber and 
1533                                                                         biblio.biblionumber=? and 
1534                                                                         biblioitems.biblioitemnumber=?");
1535         $sth->execute($item->{biblionumber},$item->{biblioitemnumber});
1536     if ( defined $sth->errstr ) {
1537         $error .= $sth->errstr;
1538     }
1539         my ($rawmarc,$frameworkcode) = $sth->fetchrow;
1540         warn "ERROR IN REALmoditem, MARC record not found" unless $rawmarc;
1541         my $record = MARC::File::USMARC::decode($rawmarc);
1542         # ok, we have the marc record, find the previous item record for this itemnumber and delete it
1543         my ($itemnumberfield,$itemnumbersubfield) = MARCfind_marc_from_kohafield($dbh,'items.itemnumber',$frameworkcode);
1544         # prepare the new item record
1545         my $itemrecord = MARC::File::USMARC::decode($item->{marc});
1546         my $itemfield = $itemrecord->field($itemnumberfield);
1547         $itemfield->add_subfields($itemnumbersubfield => '$itemnumber');
1548         # parse all fields fields from the complete record
1549         foreach ($record->field($itemnumberfield)) {
1550                 # when the previous field is found, replace by the new one
1551                 if ($_->subfield($itemnumbersubfield) == $item->{itemnum}) {
1552                         $_->replace_with($itemfield);
1553                 }
1554         }
1555 #       $record->insert_grouped_field($itemfield);
1556         # save the record into biblioitem
1557         $sth=$dbh->prepare("update biblioitems set marc=?,marcxml=? where biblionumber=? and biblioitemnumber=?");
1558         $sth->execute($record->as_usmarc(),$record->as_xml(),$item->{biblionumber},$item->{biblioitemnumber});
1559         #my $Zconn = C4::Context->Zconn or die "unable to set Zconn";
1560          z3950_extended_services($Zconn,'update',set_service_options('update'),$record);
1561          # z3950_extended_services($Zconn,'commit',set_service_options('commit'));
1562          #zebra_create($item->biblionumber,$record);
1563     if ( defined $sth->errstr ) {
1564         $error .= $sth->errstr;
1565     }
1566         $dbh->do('unlock tables');
1567
1568     #  $dbh->disconnect;
1569 }
1570
1571 =head2 REALdelitem($dbh,$itemnum);
1572
1573 =over 4
1574
1575 delete item
1576
1577 =back
1578
1579 =cut
1580
1581 sub REALdelitem {
1582     my ( $dbh, $itemnum ) = @_;
1583
1584     #  my $dbh=C4Connect;
1585     my $sth = $dbh->prepare("select * from items where itemnumber=?");
1586     $sth->execute($itemnum);
1587     my $data = $sth->fetchrow_hashref;
1588     $sth->finish;
1589     my $query = "Insert into deleteditems set ";
1590     my @bind  = ();
1591     foreach my $temp ( keys %$data ) {
1592         $query .= "$temp = ?,";
1593         push ( @bind, $data->{$temp} );
1594     }
1595     $query =~ s/\,$//;
1596
1597     #  print $query;
1598     $sth = $dbh->prepare($query);
1599     $sth->execute(@bind);
1600     $sth->finish;
1601     $sth = $dbh->prepare("Delete from items where itemnumber=?");
1602     $sth->execute($itemnum);
1603     $sth->finish;
1604
1605     #  $dbh->disconnect;
1606 }
1607
1608 =head2 REALdelbiblioitem($dbh,$biblioitemnumber);
1609
1610 =over 4
1611
1612 deletes a biblioitem
1613 NOTE : not standard sub name. Should be REALdelbiblioitem()
1614
1615 =back
1616
1617 =cut
1618
1619 sub REALdelbiblioitem {
1620     my ( $dbh, $biblioitemnumber ) = @_;
1621
1622     #    my $dbh   = C4Connect;
1623     my $sth = $dbh->prepare( "Select * from biblioitems
1624 where biblioitemnumber = ?"
1625     );
1626     my $results;
1627
1628     $sth->execute($biblioitemnumber);
1629
1630     if ( $results = $sth->fetchrow_hashref ) {
1631         $sth->finish;
1632         $sth =
1633           $dbh->prepare(
1634 "Insert into deletedbiblioitems (biblioitemnumber, biblionumber, volume, number, classification, itemtype,
1635                                         isbn, issn ,dewey ,subclass ,publicationyear ,publishercode ,volumedate ,volumeddesc ,timestamp ,illus ,
1636                                         pages ,notes ,size ,url ,lccn ) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
1637         );
1638
1639         $sth->execute(
1640             $results->{biblioitemnumber}, $results->{biblionumber},
1641             $results->{volume},           $results->{number},
1642             $results->{classification},   $results->{itemtype},
1643             $results->{isbn},             $results->{issn},
1644             $results->{dewey},            $results->{subclass},
1645             $results->{publicationyear},  $results->{publishercode},
1646             $results->{volumedate},       $results->{volumeddesc},
1647             $results->{timestamp},        $results->{illus},
1648             $results->{pages},            $results->{notes},
1649             $results->{size},             $results->{url},
1650             $results->{lccn}
1651         );
1652         my $sth2 =
1653           $dbh->prepare("Delete from biblioitems where biblioitemnumber = ?");
1654         $sth2->execute($biblioitemnumber);
1655         $sth2->finish();
1656     }    # if
1657     $sth->finish;
1658
1659     # Now delete all the items attached to the biblioitem
1660     $sth = $dbh->prepare("Select * from items where biblioitemnumber = ?");
1661     $sth->execute($biblioitemnumber);
1662     my @results;
1663     while ( my $data = $sth->fetchrow_hashref ) {
1664         my $query = "Insert into deleteditems set ";
1665         my @bind  = ();
1666         foreach my $temp ( keys %$data ) {
1667             $query .= "$temp = ?,";
1668             push ( @bind, $data->{$temp} );
1669         }
1670         $query =~ s/\,$//;
1671         my $sth2 = $dbh->prepare($query);
1672         $sth2->execute(@bind);
1673     }    # while
1674     $sth->finish;
1675     $sth = $dbh->prepare("Delete from items where biblioitemnumber = ?");
1676     $sth->execute($biblioitemnumber);
1677     $sth->finish();
1678
1679     #    $dbh->disconnect;
1680 }    # sub deletebiblioitem
1681
1682 =head2 REALdelbiblio($dbh,$biblio);
1683
1684 =over 4
1685
1686 delete a biblio
1687
1688 =back
1689
1690 =cut
1691
1692 sub REALdelbiblio {
1693     my ( $dbh, $biblio ) = @_;
1694     my $sth = $dbh->prepare("select * from biblio where biblionumber=?");
1695     $sth->execute($biblio);
1696     if ( my $data = $sth->fetchrow_hashref ) {
1697         $sth->finish;
1698         my $query = "Insert into deletedbiblio set ";
1699         my @bind  = ();
1700         foreach my $temp ( keys %$data ) {
1701             $query .= "$temp = ?,";
1702             push ( @bind, $data->{$temp} );
1703         }
1704
1705         #replacing the last , by ",?)"
1706         $query =~ s/\,$//;
1707         $sth = $dbh->prepare($query);
1708         $sth->execute(@bind);
1709         $sth->finish;
1710         $sth = $dbh->prepare("Delete from biblio where biblionumber=?");
1711         $sth->execute($biblio);
1712         $sth->finish;
1713     }
1714     $sth->finish;
1715 }
1716
1717 =head2 $number = itemcount($biblio);
1718
1719 =over 4
1720
1721 returns the number of items attached to a biblio
1722
1723 =back
1724
1725 =cut
1726
1727 sub itemcount {
1728     my ($biblio) = @_;
1729     my $dbh = C4::Context->dbh;
1730
1731     #  print $query;
1732     my $sth = $dbh->prepare("Select count(*) from items where biblionumber=?");
1733     $sth->execute($biblio);
1734     my $data = $sth->fetchrow_hashref;
1735     $sth->finish;
1736     return ( $data->{'count(*)'} );
1737 }
1738
1739 =head2 $biblionumber = newbiblio($biblio);
1740
1741 =over 4
1742
1743 create a biblio. The parameter is a hash
1744
1745 =back
1746
1747 =cut
1748
1749 sub newbiblio {
1750     my ($biblio) = @_;
1751     my $dbh    = C4::Context->dbh;
1752     my $bibnum = REALnewbiblio( $dbh, $biblio );
1753     # finds new (MARC bibid
1754     #   my $bibid = &MARCfind_MARCbibid_from_oldbiblionumber($dbh,$bibnum);
1755 #     my $record = &MARCkoha2marcBiblio( $dbh, $bibnum );
1756 #     MARCaddbiblio( $dbh, $record, $bibnum,'' );
1757     return ($bibnum);
1758 }
1759
1760 =head2   $biblionumber = &modbiblio($biblio);
1761
1762 =over 4
1763
1764 Update a biblio record.
1765
1766 C<$biblio> is a reference-to-hash whose keys are the fields in the
1767 biblio table in the Koha database. All fields must be present, not
1768 just the ones you wish to change.
1769
1770 C<&modbiblio> updates the record defined by
1771 C<$biblio-E<gt>{biblionumber}> with the values in C<$biblio>.
1772
1773 C<&modbiblio> returns C<$biblio-E<gt>{biblionumber}> whether it was
1774 successful or not.
1775
1776 =back
1777
1778 =cut
1779
1780 sub modbiblio {
1781         my ($biblio) = @_;
1782         my $dbh  = C4::Context->dbh;
1783         my $biblionumber=REALmodbiblio($dbh,$biblio);
1784         my $record = MARCkoha2marcBiblio($dbh,$biblionumber,$biblionumber);
1785         # finds new (MARC bibid
1786         my $bibid = &MARCfind_MARCbibid_from_oldbiblionumber($dbh,$biblionumber);
1787         MARCmodbiblio($dbh,$bibid,$record,"",0);
1788         return($biblionumber);
1789 } # sub modbiblio
1790
1791 =head2   &modsubtitle($biblionumber, $subtitle);
1792
1793 =over 4
1794
1795 Sets the subtitle of a book.
1796
1797 C<$biblionumber> is the biblionumber of the book to modify.
1798
1799 C<$subtitle> is the new subtitle.
1800
1801 =back
1802
1803 =cut
1804
1805 sub modsubtitle {
1806     my ( $bibnum, $subtitle ) = @_;
1807     my $dbh = C4::Context->dbh;
1808     &REALmodsubtitle( $dbh, $bibnum, $subtitle );
1809 }    # sub modsubtitle
1810
1811 =head2 &modaddauthor($biblionumber, $author);
1812
1813 =over 4
1814
1815 Replaces all additional authors for the book with biblio number
1816 C<$biblionumber> with C<$author>. If C<$author> is the empty string,
1817 C<&modaddauthor> deletes all additional authors.
1818
1819 =back
1820
1821 =cut
1822
1823 sub modaddauthor {
1824     my ( $bibnum, @authors ) = @_;
1825     my $dbh = C4::Context->dbh;
1826     &REALmodaddauthor( $dbh, $bibnum, @authors );
1827 }    # sub modaddauthor
1828
1829 =head2 $error = &modsubject($biblionumber, $force, @subjects);
1830
1831 =over 4
1832
1833 $force - a subject to force
1834 $error - Error message, or undef if successful.
1835
1836 =back
1837
1838 =cut
1839
1840 sub modsubject {
1841     my ( $bibnum, $force, @subject ) = @_;
1842     my $dbh = C4::Context->dbh;
1843     my $error = &REALmodsubject( $dbh, $bibnum, $force, @subject );
1844     if ($error eq ''){
1845                 # When MARC is off, ensures that the MARC biblio table gets updated with new
1846                 # subjects, of course, it deletes the biblio in marc, and then recreates.
1847                 # This check is to ensure that no MARC data exists to lose.
1848 #               if (C4::Context->preference("MARC") eq '0'){
1849 #               warn "in modSUBJECT";
1850 #                       my $MARCRecord = &MARCkoha2marcBiblio($dbh,$bibnum);
1851 #                       my $bibid = &MARCfind_MARCbibid_from_oldbiblionumber($dbh,$bibnum);
1852 #                       &MARCmodbiblio($dbh,$bibid, $MARCRecord);
1853 #               }
1854         }
1855         return ($error);
1856 }    # sub modsubject
1857
1858 =head2 modbibitem($dbh, $Zconn,$biblioitem);
1859
1860 =over 4
1861
1862 modify a biblioitem. The parameter is a hash
1863
1864 =back
1865
1866 =cut
1867
1868 sub modbibitem {
1869     my ($dbh, $Zconn, $biblioitem) = @_;
1870     #my $dbh = C4::Context->dbh;
1871     &REALmodbiblioitem( $dbh, $Zconn, $biblioitem );
1872 }    # sub modbibitem
1873
1874 =head2 $biblioitemnumber = newbiblioitem($biblioitem)
1875
1876 =over 4
1877
1878 create a biblioitem, the parameter is a hash
1879
1880 =back
1881
1882 =cut
1883
1884 sub newbiblioitem {
1885     my ($dbh, $Zconn, $biblioitem) = @_;
1886     #my $dbh        = C4::Context->dbh;
1887         # add biblio information to the hash
1888     my $MARCbiblio = MARCkoha2marcBiblio( $dbh, $biblioitem );
1889         $biblioitem->{marc} = $MARCbiblio->as_usmarc();
1890     my $bibitemnum = &REALnewbiblioitem( $dbh, $Zconn, $biblioitem );
1891     return ($bibitemnum);
1892 }
1893
1894 =head2 newsubtitle($biblionumber,$subtitle);
1895
1896 =over 4
1897
1898 insert a subtitle for $biblionumber biblio
1899
1900 =back
1901
1902 =cut
1903
1904
1905 sub newsubtitle {
1906     my ( $bibnum, $subtitle ) = @_;
1907     my $dbh = C4::Context->dbh;
1908     &REALnewsubtitle( $dbh, $bibnum, $subtitle );
1909 }
1910
1911 =head2 $errors = newitems($dbh, $Zconn, $item, @barcodes);
1912
1913 =over 4
1914
1915 insert items ($item is a hash)
1916
1917 =back
1918
1919 =cut
1920
1921
1922 sub newitems {
1923     my ( $dbh, $Zconn, $item, @barcodes ) = @_;
1924     #my $dbh = C4::Context->dbh;
1925     my $errors;
1926     my $itemnumber;
1927     my $error;
1928     foreach my $barcode (@barcodes) {
1929                 # add items, one by one for each barcode.
1930                 my $oneitem=$item;
1931                 $oneitem->{barcode}= $barcode;
1932         my $MARCitem = &MARCkoha2marcItem( $dbh, $oneitem);
1933                 $oneitem->{marc} = $MARCitem->as_usmarc;
1934         ( $itemnumber, $error ) = &REALnewitems( $dbh,$Zconn,$oneitem);
1935 #         $errors .= $error;
1936 #         &MARCadditem( $dbh, $MARCitem, $item->{biblionumber} );
1937     }
1938     return ($errors);
1939 }
1940
1941 =head2 moditem($dbh,$Zconn,$item);
1942
1943 =over 4
1944
1945 modify an item ($item is a hash with all item informations)
1946
1947 =back
1948
1949 =cut
1950
1951
1952 sub moditem {
1953     my ($dbh,$Zconn,$item) = @_;
1954     #my $dbh = C4::Context->dbh;
1955     &REALmoditem( $dbh, $Zconn, $item );
1956     my $MARCitem =
1957       &MARCkoha2marcItem( $dbh, $item->{'biblionumber'}, $item->{'itemnum'} );
1958     my $bibid =
1959       &MARCfind_MARCbibid_from_oldbiblionumber( $dbh, $item->{biblionumber} );
1960     &MARCmoditem( $dbh, $MARCitem, $bibid, $item->{itemnum}, 0 );
1961 }
1962
1963 =head2 $error = checkitems($count,@barcodes);
1964
1965 =over 4
1966
1967 check for each @barcode entry that the barcode is not a duplicate
1968
1969 =back
1970
1971 =cut
1972
1973 sub checkitems {
1974     my ( $count, @barcodes ) = @_;
1975     my $dbh = C4::Context->dbh;
1976     my $error;
1977     my $sth = $dbh->prepare("Select * from items where barcode=?");
1978     for ( my $i = 0 ; $i < $count ; $i++ ) {
1979         $barcodes[$i] = uc $barcodes[$i];
1980         $sth->execute( $barcodes[$i] );
1981         if ( my $data = $sth->fetchrow_hashref ) {
1982             $error .= " Duplicate Barcode: $barcodes[$i]";
1983         }
1984     }
1985     $sth->finish;
1986     return ($error);
1987 }
1988
1989 =head2 $delitem($itemnum);
1990
1991 =over 4
1992
1993 delete item $itemnum being the item number to delete
1994
1995 =back
1996
1997 =cut
1998
1999 sub delitem {
2000     my ($itemnum) = @_;
2001     my $dbh = C4::Context->dbh;
2002     &REALdelitem( $dbh, $itemnum );
2003 }
2004
2005 =head2 deletebiblioitem($biblioitemnumber);
2006
2007 =over 4
2008
2009 delete the biblioitem $biblioitemnumber
2010
2011 =back
2012
2013 =cut
2014
2015 sub deletebiblioitem {
2016     my ($biblioitemnumber) = @_;
2017     my $dbh = C4::Context->dbh;
2018     &REALdelbiblioitem( $dbh, $biblioitemnumber );
2019 }    # sub deletebiblioitem
2020
2021 =head2 delbiblio($biblionumber)
2022
2023 =over 4
2024
2025 delete biblio $biblionumber
2026
2027 =back
2028
2029 =cut
2030
2031 sub delbiblio {
2032     my ($biblio) = @_;
2033     my $dbh = C4::Context->dbh;
2034     &REALdelbiblio( $dbh, $biblio );
2035     my $bibid = &MARCfind_MARCbibid_from_oldbiblionumber( $dbh, $biblio );
2036     &MARCdelbiblio( $dbh, $bibid, 0 );
2037 }
2038
2039 =head2 ($count,@results) = getbiblio($biblionumber);
2040
2041 =over 4
2042
2043 return an array with hash of biblios.
2044
2045 FIXME : biblionumber being the primary key, this sub will always return only 1 result, API should be modified...
2046
2047 =back
2048
2049 =cut
2050
2051 sub getbiblio {
2052     my ($biblionumber) = @_;
2053     my $dbh = C4::Context->dbh;
2054     my $sth = $dbh->prepare("Select * from biblio where biblionumber = ?");
2055
2056     # || die "Cannot prepare $query\n" . $dbh->errstr;
2057     my $count = 0;
2058     my @results;
2059
2060     $sth->execute($biblionumber);
2061
2062     # || die "Cannot execute $query\n" . $sth->errstr;
2063     while ( my $data = $sth->fetchrow_hashref ) {
2064         $results[$count] = $data;
2065         $count++;
2066     }    # while
2067
2068     $sth->finish;
2069     return ( $count, @results );
2070 }    # sub getbiblio
2071
2072 =item bibdata
2073
2074   $data = &bibdata($biblionumber, $type);
2075
2076 Returns information about the book with the given biblionumber.
2077
2078 C<$type> is ignored.
2079
2080 C<&bibdata> returns a reference-to-hash. The keys are the fields in
2081 the C<biblio>, C<biblioitems>, and C<bibliosubtitle> tables in the
2082 Koha database.
2083
2084 In addition, C<$data-E<gt>{subject}> is the list of the book's
2085 subjects, separated by C<" , "> (space, comma, space).
2086
2087 If there are multiple biblioitems with the given biblionumber, only
2088 the first one is considered.
2089
2090 =cut
2091 #'
2092 sub bibdata {
2093         my ($bibnum, $type) = @_;
2094         my $dbh   = C4::Context->dbh;
2095         my $sth   = $dbh->prepare("Select *, biblioitems.notes AS bnotes, biblio.notes
2096                                                                 from biblio 
2097                                                                 left join biblioitems on biblioitems.biblionumber = biblio.biblionumber
2098                                                                 left join bibliosubtitle on
2099                                                                 biblio.biblionumber = bibliosubtitle.biblionumber
2100                                                                 left join itemtypes on biblioitems.itemtype=itemtypes.itemtype
2101                                                                 where biblio.biblionumber = ?
2102                                                                 ");
2103         $sth->execute($bibnum);
2104         my $data;
2105         $data  = $sth->fetchrow_hashref;
2106         $sth->finish;
2107         # handle management of repeated subtitle
2108         $sth   = $dbh->prepare("Select * from bibliosubtitle where biblionumber = ?");
2109         $sth->execute($bibnum);
2110         my @subtitles;
2111         while (my $dat = $sth->fetchrow_hashref){
2112                 my %line;
2113                 $line{subtitle} = $dat->{subtitle};
2114                 push @subtitles, \%line;
2115         } # while
2116         $data->{subtitles} = \@subtitles;
2117         $sth->finish;
2118         $sth   = $dbh->prepare("Select * from bibliosubject where biblionumber = ?");
2119         $sth->execute($bibnum);
2120         my @subjects;
2121         while (my $dat = $sth->fetchrow_hashref){
2122                 my %line;
2123                 $line{subject} = $dat->{'subject'};
2124                 push @subjects, \%line;
2125         } # while
2126         $data->{subjects} = \@subjects;
2127         $sth->finish;
2128         $sth   = $dbh->prepare("Select * from additionalauthors where biblionumber = ?");
2129         $sth->execute($bibnum);
2130         while (my $dat = $sth->fetchrow_hashref){
2131                 $data->{'additionalauthors'} .= "$dat->{'author'} - ";
2132         } # while
2133         chop $data->{'additionalauthors'};
2134         chop $data->{'additionalauthors'};
2135         chop $data->{'additionalauthors'};
2136         $sth->finish;
2137         return($data);
2138 } # sub bibdata
2139
2140 =head2 ($count,@results) = getbiblioitem($biblioitemnumber);
2141
2142 =over 4
2143
2144 return an array with hash of biblioitemss.
2145
2146 FIXME : biblioitemnumber being unique, this sub will always return only 1 result, API should be modified...
2147
2148 =back
2149
2150 =cut
2151
2152 sub getbiblioitem {
2153     my ($biblioitemnum) = @_;
2154     my $dbh = C4::Context->dbh;
2155     my $sth = $dbh->prepare( "Select * from biblioitems where
2156 biblioitemnumber = ?"
2157     );
2158     my $count = 0;
2159     my @results;
2160
2161     $sth->execute($biblioitemnum);
2162
2163     while ( my $data = $sth->fetchrow_hashref ) {
2164         $results[$count] = $data;
2165         $count++;
2166     }    # while
2167
2168     $sth->finish;
2169     return ( $count, @results );
2170 }    # sub getbiblioitem
2171
2172 =head2 ($count,@results) = getbiblioitembybiblionumber($biblionumber);
2173
2174 =over 4
2175
2176 return an array with hash of biblioitems for the given biblionumber.
2177
2178 =back
2179
2180 =cut
2181
2182 sub getbiblioitembybiblionumber {
2183     my ($biblionumber) = @_;
2184     my $dbh = C4::Context->dbh;
2185     my $sth = $dbh->prepare("Select * from biblioitems where biblionumber = ?");
2186     my $count = 0;
2187     my @results;
2188
2189     $sth->execute($biblionumber);
2190
2191     while ( my $data = $sth->fetchrow_hashref ) {
2192         $results[$count] = $data;
2193         $count++;
2194     }    # while
2195
2196     $sth->finish;
2197     return ( $count, @results );
2198 }    # sub
2199
2200 =head2 ($count,@results) = getitemsbybiblioitem($biblionumber);
2201
2202 =over 4
2203
2204 returns an array with hash of items
2205
2206 =back
2207
2208 =cut
2209
2210 sub getitemsbybiblioitem {
2211     my ($biblioitemnum) = @_;
2212     my $dbh = C4::Context->dbh;
2213     my $sth = $dbh->prepare( "Select * from items, biblio where
2214 biblio.biblionumber = items.biblionumber and biblioitemnumber
2215 = ?"
2216     );
2217
2218     # || die "Cannot prepare $query\n" . $dbh->errstr;
2219     my $count = 0;
2220     my @results;
2221
2222     $sth->execute($biblioitemnum);
2223
2224     # || die "Cannot execute $query\n" . $sth->errstr;
2225     while ( my $data = $sth->fetchrow_hashref ) {
2226         $results[$count] = $data;
2227         $count++;
2228     }    # while
2229
2230     $sth->finish;
2231     return ( $count, @results );
2232 }    # sub getitemsbybiblioitem
2233
2234 =item ItemInfo
2235
2236   @results = &ItemInfo($env, $biblionumber, $type);
2237
2238 Returns information about books with the given biblionumber.
2239
2240 C<$type> may be either C<intra> or anything else. If it is not set to
2241 C<intra>, then the search will exclude lost, very overdue, and
2242 withdrawn items.
2243
2244 C<$env> is ignored.
2245
2246 C<&ItemInfo> returns a list of references-to-hash. Each element
2247 contains a number of keys. Most of them are table items from the
2248 C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
2249 Koha database. Other keys include:
2250
2251 =over 4
2252
2253 =item C<$data-E<gt>{branchname}>
2254
2255 The name (not the code) of the branch to which the book belongs.
2256
2257 =item C<$data-E<gt>{datelastseen}>
2258
2259 This is simply C<items.datelastseen>, except that while the date is
2260 stored in YYYY-MM-DD format in the database, here it is converted to
2261 DD/MM/YYYY format. A NULL date is returned as C<//>.
2262
2263 =item C<$data-E<gt>{datedue}>
2264
2265 =item C<$data-E<gt>{class}>
2266
2267 This is the concatenation of C<biblioitems.classification>, the book's
2268 Dewey code, and C<biblioitems.subclass>.
2269
2270 =item C<$data-E<gt>{ocount}>
2271
2272 I think this is the number of copies of the book available.
2273
2274 =item C<$data-E<gt>{order}>
2275
2276 If this is set, it is set to C<One Order>.
2277
2278 =back
2279
2280 =cut
2281 #'
2282 sub ItemInfo {
2283         my ($env,$biblionumber,$type) = @_;
2284         my $dbh   = C4::Context->dbh;
2285         my $query = "SELECT *,items.notforloan as itemnotforloan FROM items, biblio, biblioitems 
2286                                         left join itemtypes on biblioitems.itemtype = itemtypes.itemtype
2287                                         WHERE items.biblionumber = ?
2288                                         AND biblioitems.biblioitemnumber = items.biblioitemnumber
2289                                         AND biblio.biblionumber = items.biblionumber";
2290         $query .= " order by items.dateaccessioned desc";
2291         my $sth=$dbh->prepare($query);
2292         $sth->execute($biblionumber);
2293         my $i=0;
2294         my @results;
2295         while (my $data=$sth->fetchrow_hashref){
2296                 my $datedue = '';
2297                 my $isth=$dbh->prepare("Select issues.*,borrowers.cardnumber from issues,borrowers where itemnumber = ? and returndate is null and issues.borrowernumber=borrowers.borrowernumber");
2298                 $isth->execute($data->{'itemnumber'});
2299                 if (my $idata=$isth->fetchrow_hashref){
2300                 $data->{borrowernumber} = $idata->{borrowernumber};
2301                 $data->{cardnumber} = $idata->{cardnumber};
2302                 $datedue = format_date($idata->{'date_due'});
2303                 }
2304                 if ($datedue eq ''){
2305                         my ($restype,$reserves)=C4::Reserves2::CheckReserves($data->{'itemnumber'});
2306                         if ($restype) {
2307                                 $datedue=$restype;
2308                         }
2309                 }
2310                 $isth->finish;
2311         #get branch information.....
2312                 my $bsth=$dbh->prepare("SELECT * FROM branches WHERE branchcode = ?");
2313                 $bsth->execute($data->{'holdingbranch'});
2314                 if (my $bdata=$bsth->fetchrow_hashref){
2315                         $data->{'branchname'} = $bdata->{'branchname'};
2316                 }
2317                 my $date=format_date($data->{'datelastseen'});
2318                 $data->{'datelastseen'}=$date;
2319                 $data->{'datedue'}=$datedue;
2320         # get notforloan complete status if applicable
2321                 my $sthnflstatus = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield="items.notforloan"');
2322                 $sthnflstatus->execute;
2323                 my ($authorised_valuecode) = $sthnflstatus->fetchrow;
2324                 if ($authorised_valuecode) {
2325                         $sthnflstatus = $dbh->prepare("select lib from authorised_values where category=? and authorised_value=?");
2326                         $sthnflstatus->execute($authorised_valuecode,$data->{itemnotforloan});
2327                         my ($lib) = $sthnflstatus->fetchrow;
2328                         $data->{notforloan} = $lib;
2329                 }
2330                 $results[$i]=$data;
2331                 $i++;
2332         }
2333         $sth->finish;
2334         return(@results);
2335 }
2336
2337 =item bibitems
2338
2339   ($count, @results) = &bibitems($biblionumber);
2340
2341 Given the biblionumber for a book, C<&bibitems> looks up that book's
2342 biblioitems (different publications of the same book, the audio book
2343 and film versions, etc.).
2344
2345 C<$count> is the number of elements in C<@results>.
2346
2347 C<@results> is an array of references-to-hash; the keys are the fields
2348 of the C<biblioitems> and C<itemtypes> tables of the Koha database. In
2349 addition, C<itemlost> indicates the availability of the item: if it is
2350 "2", then all copies of the item are long overdue; if it is "1", then
2351 all copies are lost; otherwise, there is at least one copy available.
2352
2353 =cut
2354 #'
2355 sub bibitems {
2356     my ($bibnum) = @_;
2357     my $dbh   = C4::Context->dbh;
2358     my $sth   = $dbh->prepare("SELECT biblioitems.*,
2359                         itemtypes.*,
2360                         MIN(items.itemlost)        as itemlost,
2361                         MIN(items.dateaccessioned) as dateaccessioned
2362                           FROM biblioitems, itemtypes, items
2363                          WHERE biblioitems.biblionumber     = ?
2364                            AND biblioitems.itemtype         = itemtypes.itemtype
2365                            AND biblioitems.biblioitemnumber = items.biblioitemnumber
2366                       GROUP BY items.biblioitemnumber");
2367     my $count = 0;
2368     my @results;
2369     $sth->execute($bibnum);
2370     while (my $data = $sth->fetchrow_hashref) {
2371         $results[$count] = $data;
2372         $count++;
2373     } # while
2374     $sth->finish;
2375     return($count, @results);
2376 } # sub bibitems
2377
2378
2379 =item bibitemdata
2380
2381   $itemdata = &bibitemdata($biblioitemnumber);
2382
2383 Looks up the biblioitem with the given biblioitemnumber. Returns a
2384 reference-to-hash. The keys are the fields from the C<biblio>,
2385 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
2386 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
2387
2388 =cut
2389 #'
2390 sub bibitemdata {
2391     my ($bibitem) = @_;
2392     my $dbh   = C4::Context->dbh;
2393     my $sth   = $dbh->prepare("Select *,biblioitems.notes as bnotes from biblio, biblioitems,itemtypes where biblio.biblionumber = biblioitems.biblionumber and biblioitemnumber = ? and biblioitems.itemtype = itemtypes.itemtype");
2394     my $data;
2395
2396     $sth->execute($bibitem);
2397
2398     $data = $sth->fetchrow_hashref;
2399
2400     $sth->finish;
2401     return($data);
2402 } # sub bibitemdata
2403
2404
2405 =item getbibliofromitemnumber
2406
2407   $item = &getbibliofromitemnumber($env, $dbh, $itemnumber);
2408
2409 Looks up the item with the given itemnumber.
2410
2411 C<$env> and C<$dbh> are ignored.
2412
2413 C<&itemnodata> returns a reference-to-hash whose keys are the fields
2414 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
2415 database.
2416
2417 =cut
2418 #'
2419 sub getbibliofromitemnumber {
2420   my ($env,$dbh,$itemnumber) = @_;
2421   $dbh = C4::Context->dbh;
2422   my $sth=$dbh->prepare("Select * from biblio,items,biblioitems
2423     where items.itemnumber = ?
2424     and biblio.biblionumber = items.biblionumber
2425     and biblioitems.biblioitemnumber = items.biblioitemnumber");
2426 #  print $query;
2427   $sth->execute($itemnumber);
2428   my $data=$sth->fetchrow_hashref;
2429   $sth->finish;
2430   return($data);
2431 }
2432
2433 =item barcodes
2434
2435   @barcodes = &barcodes($biblioitemnumber);
2436
2437 Given a biblioitemnumber, looks up the corresponding items.
2438
2439 Returns an array of references-to-hash; the keys are C<barcode> and
2440 C<itemlost>.
2441
2442 The returned items include very overdue items, but not lost ones.
2443
2444 =cut
2445 #'
2446 sub barcodes{
2447     #called from request.pl
2448     my ($biblioitemnumber)=@_;
2449     my $dbh = C4::Context->dbh;
2450     my $sth=$dbh->prepare("SELECT barcode, itemlost, holdingbranch FROM items
2451                            WHERE biblioitemnumber = ?
2452                              AND (wthdrawn <> 1 OR wthdrawn IS NULL)");
2453     $sth->execute($biblioitemnumber);
2454     my @barcodes;
2455     my $i=0;
2456     while (my $data=$sth->fetchrow_hashref){
2457         $barcodes[$i]=$data;
2458         $i++;
2459     }
2460     $sth->finish;
2461     return(@barcodes);
2462 }
2463
2464
2465 =item itemdata
2466
2467   $item = &itemdata($barcode);
2468
2469 Looks up the item with the given barcode, and returns a
2470 reference-to-hash containing information about that item. The keys of
2471 the hash are the fields from the C<items> and C<biblioitems> tables in
2472 the Koha database.
2473
2474 =cut
2475 #'
2476 sub get_item_from_barcode {
2477   my ($barcode)=@_;
2478   my $dbh = C4::Context->dbh;
2479   my $sth=$dbh->prepare("Select * from items,biblioitems where barcode=?
2480   and items.biblioitemnumber=biblioitems.biblioitemnumber");
2481   $sth->execute($barcode);
2482   my $data=$sth->fetchrow_hashref;
2483   $sth->finish;
2484   return($data);
2485 }
2486
2487
2488 =item itemissues
2489
2490   @issues = &itemissues($biblioitemnumber, $biblio);
2491
2492 Looks up information about who has borrowed the bookZ<>(s) with the
2493 given biblioitemnumber.
2494
2495 C<$biblio> is ignored.
2496
2497 C<&itemissues> returns an array of references-to-hash. The keys
2498 include the fields from the C<items> table in the Koha database.
2499 Additional keys include:
2500
2501 =over 4
2502
2503 =item C<date_due>
2504
2505 If the item is currently on loan, this gives the due date.
2506
2507 If the item is not on loan, then this is either "Available" or
2508 "Cancelled", if the item has been withdrawn.
2509
2510 =item C<card>
2511
2512 If the item is currently on loan, this gives the card number of the
2513 patron who currently has the item.
2514
2515 =item C<timestamp0>, C<timestamp1>, C<timestamp2>
2516
2517 These give the timestamp for the last three times the item was
2518 borrowed.
2519
2520 =item C<card0>, C<card1>, C<card2>
2521
2522 The card number of the last three patrons who borrowed this item.
2523
2524 =item C<borrower0>, C<borrower1>, C<borrower2>
2525
2526 The borrower number of the last three patrons who borrowed this item.
2527
2528 =back
2529
2530 =cut
2531 #'
2532 sub itemissues {
2533     my ($bibitem, $biblio)=@_;
2534     my $dbh   = C4::Context->dbh;
2535     # FIXME - If this function die()s, the script will abort, and the
2536     # user won't get anything; depending on how far the script has
2537     # gotten, the user might get a blank page. It would be much better
2538     # to at least print an error message. The easiest way to do this
2539     # is to set $SIG{__DIE__}.
2540     my $sth   = $dbh->prepare("Select * from items where
2541 items.biblioitemnumber = ?")
2542       || die $dbh->errstr;
2543     my $i     = 0;
2544     my @results;
2545
2546     $sth->execute($bibitem)
2547       || die $sth->errstr;
2548
2549     while (my $data = $sth->fetchrow_hashref) {
2550         # Find out who currently has this item.
2551         # FIXME - Wouldn't it be better to do this as a left join of
2552         # some sort? Currently, this code assumes that if
2553         # fetchrow_hashref() fails, then the book is on the shelf.
2554         # fetchrow_hashref() can fail for any number of reasons (e.g.,
2555         # database server crash), not just because no items match the
2556         # search criteria.
2557         my $sth2   = $dbh->prepare("select * from issues,borrowers
2558 where itemnumber = ?
2559 and returndate is NULL
2560 and issues.borrowernumber = borrowers.borrowernumber");
2561
2562         $sth2->execute($data->{'itemnumber'});
2563         if (my $data2 = $sth2->fetchrow_hashref) {
2564             $data->{'date_due'} = $data2->{'date_due'};
2565             $data->{'card'}     = $data2->{'cardnumber'};
2566             $data->{'borrower'}     = $data2->{'borrowernumber'};
2567         } else {
2568             if ($data->{'wthdrawn'} eq '1') {
2569                 $data->{'date_due'} = 'Cancelled';
2570             } else {
2571                 $data->{'date_due'} = 'Available';
2572             } # else
2573         } # else
2574
2575         $sth2->finish;
2576
2577         # Find the last 3 people who borrowed this item.
2578         $sth2 = $dbh->prepare("select * from issues, borrowers
2579                                                 where itemnumber = ?
2580                                                                         and issues.borrowernumber = borrowers.borrowernumber
2581                                                                         and returndate is not NULL
2582                                                                         order by returndate desc,timestamp desc") || die $dbh->errstr;
2583         $sth2->execute($data->{'itemnumber'}) || die $sth2->errstr;
2584         for (my $i2 = 0; $i2 < 2; $i2++) { # FIXME : error if there is less than 3 pple borrowing this item
2585             if (my $data2 = $sth2->fetchrow_hashref) {
2586                 $data->{"timestamp$i2"} = $data2->{'timestamp'};
2587                 $data->{"card$i2"}      = $data2->{'cardnumber'};
2588                 $data->{"borrower$i2"}  = $data2->{'borrowernumber'};
2589             } # if
2590         } # for
2591
2592         $sth2->finish;
2593         $results[$i] = $data;
2594         $i++;
2595     }
2596
2597     $sth->finish;
2598     return(@results);
2599 }
2600
2601 =item getsubject
2602
2603   ($count, $subjects) = &getsubject($biblionumber);
2604
2605 Looks up the subjects of the book with the given biblionumber. Returns
2606 a two-element list. C<$subjects> is a reference-to-array, where each
2607 element is a subject of the book, and C<$count> is the number of
2608 elements in C<$subjects>.
2609
2610 =cut
2611 #'
2612 sub getsubject {
2613   my ($bibnum)=@_;
2614   my $dbh = C4::Context->dbh;
2615   my $sth=$dbh->prepare("Select * from bibliosubject where biblionumber=?");
2616   $sth->execute($bibnum);
2617   my @results;
2618   my $i=0;
2619   while (my $data=$sth->fetchrow_hashref){
2620     $results[$i]=$data;
2621     $i++;
2622   }
2623   $sth->finish;
2624   return($i,\@results);
2625 }
2626
2627 =item getaddauthor
2628
2629   ($count, $authors) = &getaddauthor($biblionumber);
2630
2631 Looks up the additional authors for the book with the given
2632 biblionumber.
2633
2634 Returns a two-element list. C<$authors> is a reference-to-array, where
2635 each element is an additional author, and C<$count> is the number of
2636 elements in C<$authors>.
2637
2638 =cut
2639 #'
2640 sub getaddauthor {
2641   my ($bibnum)=@_;
2642   my $dbh = C4::Context->dbh;
2643   my $sth=$dbh->prepare("Select * from additionalauthors where biblionumber=?");
2644   $sth->execute($bibnum);
2645   my @results;
2646   my $i=0;
2647   while (my $data=$sth->fetchrow_hashref){
2648     $results[$i]=$data;
2649     $i++;
2650   }
2651   $sth->finish;
2652   return($i,\@results);
2653 }
2654
2655
2656 =item getsubtitle
2657
2658   ($count, $subtitles) = &getsubtitle($biblionumber);
2659
2660 Looks up the subtitles for the book with the given biblionumber.
2661
2662 Returns a two-element list. C<$subtitles> is a reference-to-array,
2663 where each element is a subtitle, and C<$count> is the number of
2664 elements in C<$subtitles>.
2665
2666 =cut
2667 #'
2668 sub getsubtitle {
2669   my ($bibnum)=@_;
2670   my $dbh = C4::Context->dbh;
2671   my $sth=$dbh->prepare("Select * from bibliosubtitle where biblionumber=?");
2672   $sth->execute($bibnum);
2673   my @results;
2674   my $i=0;
2675   while (my $data=$sth->fetchrow_hashref){
2676     $results[$i]=$data;
2677     $i++;
2678   }
2679   $sth->finish;
2680   return($i,\@results);
2681 }
2682
2683
2684 =item getwebsites
2685
2686   ($count, @websites) = &getwebsites($biblionumber);
2687
2688 Looks up the web sites pertaining to the book with the given
2689 biblionumber.
2690
2691 C<$count> is the number of elements in C<@websites>.
2692
2693 C<@websites> is an array of references-to-hash; the keys are the
2694 fields from the C<websites> table in the Koha database.
2695
2696 =cut
2697 #FIXME : could maybe be deleted. Otherwise, would be better in a Websites.pm package
2698 #(with add / modify / delete subs)
2699
2700 sub getwebsites {
2701     my ($biblionumber) = @_;
2702     my $dbh   = C4::Context->dbh;
2703     my $sth   = $dbh->prepare("Select * from websites where biblionumber = ?");
2704     my $count = 0;
2705     my @results;
2706
2707     $sth->execute($biblionumber);
2708     while (my $data = $sth->fetchrow_hashref) {
2709         # FIXME - The URL scheme shouldn't be stripped off, at least
2710         # not here, since it's part of the URL, and will be useful in
2711         # constructing a link to the site. If you don't want the user
2712         # to see the "http://" part, strip that off when building the
2713         # HTML code.
2714         $data->{'url'} =~ s/^http:\/\///;       # FIXME - Leaning toothpick
2715                                                 # syndrome
2716         $results[$count] = $data;
2717         $count++;
2718     } # while
2719
2720     $sth->finish;
2721     return($count, @results);
2722 } # sub getwebsites
2723
2724 =item getwebbiblioitems
2725
2726   ($count, @results) = &getwebbiblioitems($biblionumber);
2727
2728 Given a book's biblionumber, looks up the web versions of the book
2729 (biblioitems with itemtype C<WEB>).
2730
2731 C<$count> is the number of items in C<@results>. C<@results> is an
2732 array of references-to-hash; the keys are the items from the
2733 C<biblioitems> table of the Koha database.
2734
2735 =cut
2736 #'
2737 sub getwebbiblioitems {
2738     my ($biblionumber) = @_;
2739     my $dbh   = C4::Context->dbh;
2740     my $sth   = $dbh->prepare("Select * from biblioitems where biblionumber = ?
2741 and itemtype = 'WEB'");
2742     my $count = 0;
2743     my @results;
2744
2745     $sth->execute($biblionumber);
2746     while (my $data = $sth->fetchrow_hashref) {
2747         $data->{'url'} =~ s/^http:\/\///;
2748         $results[$count] = $data;
2749         $count++;
2750     } # while
2751
2752     $sth->finish;
2753     return($count, @results);
2754 } # sub getwebbiblioitems
2755
2756 sub nsb_clean {
2757     my $NSB = '\x88';    # NSB : begin Non Sorting Block
2758     my $NSE = '\x89';    # NSE : Non Sorting Block end
2759                          # handles non sorting blocks
2760     my ($string) = @_;
2761     $_ = $string;
2762     s/$NSB/(/gm;
2763     s/[ ]{0,1}$NSE/) /gm;
2764     $string = $_;
2765     return ($string);
2766 }
2767
2768 sub FindDuplicate {
2769         my ($record)=@_;
2770         my $dbh = C4::Context->dbh;
2771         my $result = MARCmarc2koha($dbh,$record,'');
2772         my $sth;
2773         my ($biblionumber,$bibid,$title);
2774         # search duplicate on ISBN, easy and fast...
2775         if ($result->{isbn}) {
2776                 $sth = $dbh->prepare("select biblio.biblionumber,bibid,title from biblio,biblioitems,marc_biblio where biblio.biblionumber=biblioitems.biblionumber and marc_biblio.biblionumber=biblioitems.biblionumber and isbn=?");
2777                 $sth->execute($result->{'isbn'});
2778                 ($biblionumber,$bibid,$title) = $sth->fetchrow;
2779                 return $biblionumber,$bibid,$title if ($biblionumber);
2780         }
2781         # a more complex search : build a request for SearchMarc::catalogsearch()
2782         my (@tags, @and_or, @excluding, @operator, @value, $offset,$length);
2783         # search on biblio.title
2784         my ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblio.title","");
2785         if ($record->field($tag)) {
2786                 if ($record->field($tag)->subfields($subfield)) {
2787                         push @tags, "'".$tag.$subfield."'";
2788                         push @and_or, "and";
2789                         push @excluding, "";
2790                         push @operator, "contains";
2791                         push @value, $record->field($tag)->subfield($subfield);
2792 #                       warn "for title, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
2793                 }
2794         }
2795         # ... and on biblio.author
2796         ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblio.author","");
2797         if ($record->field($tag)) {
2798                 if ($record->field($tag)->subfields($subfield)) {
2799                         push @tags, "'".$tag.$subfield."'";
2800                         push @and_or, "and";
2801                         push @excluding, "";
2802                         push @operator, "contains";
2803                         push @value, $record->field($tag)->subfield($subfield);
2804 #                       warn "for author, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
2805                 }
2806         }
2807         # ... and on publicationyear.
2808         ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblioitems.publicationyear","");
2809         if ($record->field($tag)) {
2810                 if ($record->field($tag)->subfields($subfield)) {
2811                         push @tags, "'".$tag.$subfield."'";
2812                         push @and_or, "and";
2813                         push @excluding, "";
2814                         push @operator, "=";
2815                         push @value, $record->field($tag)->subfield($subfield);
2816 #                       warn "for publicationyear, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
2817                 }
2818         }
2819         # ... and on size.
2820         ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblioitems.size","");
2821         if ($record->field($tag)) {
2822                 if ($record->field($tag)->subfields($subfield)) {
2823                         push @tags, "'".$tag.$subfield."'";
2824                         push @and_or, "and";
2825                         push @excluding, "";
2826                         push @operator, "=";
2827                         push @value, $record->field($tag)->subfield($subfield);
2828 #                       warn "for size, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
2829                 }
2830         }
2831         # ... and on publisher.
2832         ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblioitems.publishercode","");
2833         if ($record->field($tag)) {
2834                 if ($record->field($tag)->subfields($subfield)) {
2835                         push @tags, "'".$tag.$subfield."'";
2836                         push @and_or, "and";
2837                         push @excluding, "";
2838                         push @operator, "=";
2839                         push @value, $record->field($tag)->subfield($subfield);
2840 #                       warn "for publishercode, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
2841                 }
2842         }
2843         # ... and on volume.
2844         ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblioitems.volume","");
2845         if ($record->field($tag)) {
2846                 if ($record->field($tag)->subfields($subfield)) {
2847                         push @tags, "'".$tag.$subfield."'";
2848                         push @and_or, "and";
2849                         push @excluding, "";
2850                         push @operator, "=";
2851                         push @value, $record->field($tag)->subfield($subfield);
2852 #                       warn "for volume, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
2853                 }
2854         }
2855
2856         my ($finalresult,$nbresult) = C4::SearchMarc::catalogsearch($dbh,\@tags,\@and_or,\@excluding,\@operator,\@value,0,10);
2857         # there is at least 1 result => return the 1st one
2858         if ($nbresult) {
2859 #               warn "$nbresult => ".@$finalresult[0]->{biblionumber},@$finalresult[0]->{bibid},@$finalresult[0]->{title};
2860                 return @$finalresult[0]->{biblionumber},@$finalresult[0]->{bibid},@$finalresult[0]->{title};
2861         }
2862         # no result, returns nothing
2863         return;
2864 }
2865
2866 sub DisplayISBN {
2867         my ($isbn)=@_;
2868         my $seg1;
2869         if(substr($isbn, 0, 1) <=7) {
2870                 $seg1 = substr($isbn, 0, 1);
2871         } elsif(substr($isbn, 0, 2) <= 94) {
2872                 $seg1 = substr($isbn, 0, 2);
2873         } elsif(substr($isbn, 0, 3) <= 995) {
2874                 $seg1 = substr($isbn, 0, 3);
2875         } elsif(substr($isbn, 0, 4) <= 9989) {
2876                 $seg1 = substr($isbn, 0, 4);
2877         } else {
2878                 $seg1 = substr($isbn, 0, 5);
2879         }
2880         my $x = substr($isbn, length($seg1));
2881         my $seg2;
2882         if(substr($x, 0, 2) <= 19) {
2883 #               if(sTmp2 < 10) sTmp2 = "0" sTmp2;
2884                 $seg2 = substr($x, 0, 2);
2885         } elsif(substr($x, 0, 3) <= 699) {
2886                 $seg2 = substr($x, 0, 3);
2887         } elsif(substr($x, 0, 4) <= 8399) {
2888                 $seg2 = substr($x, 0, 4);
2889         } elsif(substr($x, 0, 5) <= 89999) {
2890                 $seg2 = substr($x, 0, 5);
2891         } elsif(substr($x, 0, 6) <= 9499999) {
2892                 $seg2 = substr($x, 0, 6);
2893         } else {
2894                 $seg2 = substr($x, 0, 7);
2895         }
2896         my $seg3=substr($x,length($seg2));
2897         $seg3=substr($seg3,0,length($seg3)-1) ;
2898         my $seg4 = substr($x, -1, 1);
2899         return "$seg1-$seg2-$seg3-$seg4";
2900 }
2901
2902
2903 END { }    # module clean-up code here (global destructor)
2904
2905 =back
2906
2907 =head1 AUTHOR
2908
2909 Koha Developement team <info@koha.org>
2910
2911 Paul POULAIN paul.poulain@free.fr
2912
2913 =cut
2914
2915 # $Id$
2916 # $Log$
2917 # Revision 1.150  2006/02/25 20:49:15  kados
2918 # Better documentation, added warning if serviceType is 'drop' since it's
2919 # not supported in Zebra.
2920 #
2921 # Revision 1.149  2006/02/25 20:30:32  kados
2922 # IMPORTANT: Paul, I've removed the decode_char routine because it's no
2923 # longer necessary. If we need to convert from MARC-8 for display, we should:
2924 #
2925 # 1. use utf-8
2926 # 2. do it with MARC::Charset
2927 #
2928 # If you still need it, let me know and I'll put it back in.
2929 #
2930 # Revision 1.148  2006/02/25 19:23:01  kados
2931 # cleaning up POD docs, deleting zebra_create as it's no longer used (
2932 # replaced by z3950_extended_services).
2933 #
2934 # Revision 1.147  2006/02/25 19:09:59  kados
2935 # readding some lost subs
2936 #
2937 # Revision 1.145  2006/02/22 01:02:39  kados
2938 # Replacing all calls to zebra_update with calls to
2939 # z3950_extended_services. More work coming, but it's
2940 # working now.
2941 #
2942 # Revision 1.144  2006/02/20 14:22:38  kados
2943 # typo
2944 #
2945 # Revision 1.143  2006/02/20 13:26:11  kados
2946 # A new subroutine to handle Z39.50 extended services. You pass it a
2947 # connection object, service type, service options, and a record, and
2948 # it performs the service and handles any exception found.
2949 #
2950 # Revision 1.142  2006/02/16 20:49:56  kados
2951 # destroy a connection after we're done -- we really should just have one
2952 # connection object and not destroy it until the whole transaction is
2953 # finished -- but this will do for now
2954 #
2955 # Revision 1.141  2006/02/16 19:47:22  rangi
2956 # Trying to error trap a little more.
2957 #
2958 # Revision 1.140  2006/02/14 21:36:03  kados
2959 # adding a 'use ZOOM' to biblio.pm, needed for non-mod_perl install.
2960 # also adding diagnostic error if not able to connect to Zebra
2961 #
2962 # Revision 1.139  2006/02/14 19:53:25  rangi
2963 # Just a little missing my
2964 #
2965 # Seems to be working great Paul, and I like what you did with zebradb
2966 #
2967 # Revision 1.138  2006/02/14 11:25:22  tipaul
2968 # road to 3.0 : updating a biblio in zebra seems to work. Still working on it, there are probably some bugs !
2969 #
2970 # Revision 1.137  2006/02/13 16:34:26  tipaul
2971 # fixing some warnings (perl -w should be quiet)
2972 #
2973 # Revision 1.136  2006/01/10 17:01:29  tipaul
2974 # adding a XMLgetbiblio in Biblio.pm (1st draft, to use with zebra)
2975 #
2976 # Revision 1.135  2006/01/06 16:39:37  tipaul
2977 # synch'ing head and rel_2_2 (from 2.2.5, including npl templates)
2978 # Seems not to break too many things, but i'm probably wrong here.
2979 # at least, new features/bugfixes from 2.2.5 are here (tested on some features on my head local copy)
2980 #
2981 # - removing useless directories (koha-html and koha-plucene)
2982 #
2983 # Revision 1.134  2006/01/04 15:54:55  tipaul
2984 # utf8 is a : go for beta test in HEAD.
2985 # some explanations :
2986 # - updater/updatedatabase => will transform all tables in innoDB (not related to utf8, just to warn you) AND collate them in utf8 / utf8_general_ci. The SQL command is : ALTER TABLE tablename DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci.
2987 # - *-top.inc will show the pages in utf8
2988 # - THE HARD THING : for me, mysql-client and mysql-server were set up to communicate in iso8859-1, whatever the mysql collation ! Thus, pages were improperly shown, as datas were transmitted in iso8859-1 format ! After a full day of investigation, someone on usenet pointed "set NAMES 'utf8'" to explain that I wanted utf8. I could put this in my.cnf, but if I do that, ALL databases will "speak" in utf8, that's not what we want. Thus, I added a line in Context.pm : everytime a DB handle is opened, the communication is set to utf8.
2989 # - using marcxml field and no more the iso2709 raw marc biblioitems.marc field.
2990 #
2991 # Revision 1.133  2005/12/12 14:25:51  thd
2992 #
2993 #
2994 # Reverse array filled with elements from repeated subfields
2995 # to avoid last to first concatenation of elements in Koha DB.-
2996 #
2997 # Revision 1.132  2005-10-26 09:12:33  tipaul
2998 # big commit, still breaking things...
2999 #
3000 # * synch with rel_2_2. Probably the last non manual synch, as rel_2_2 should not be modified deeply.
3001 # * code cleaning (cleaning warnings from perl -w) continued
3002 #
3003 # Revision 1.131  2005/09/22 10:01:45  tipaul
3004 # see mail on koha-devel : code cleaning on Search.pm + normalizing API + use of biblionumber everywhere (instead of bn, biblio, ...)
3005 #
3006 # Revision 1.130  2005/09/02 14:34:14  tipaul
3007 # continuing the work to move to zebra. Begin of work for MARC=OFF support.
3008 # IMPORTANT NOTE : the MARCkoha2marc sub API has been modified. Instead of biblionumber & biblioitemnumber, it now gets a hash.
3009 # The sub is used only in Biblio.pm, so the API change should be harmless (except for me, but i'm aware ;-) )
3010 #
3011 # Revision 1.129  2005/08/12 13:50:31  tipaul
3012 # removing useless sub declarations
3013 #
3014 # Revision 1.128  2005/08/11 16:12:47  tipaul
3015 # Playing with the zebra...
3016 #
3017 # * go to koha cvs home directory
3018 # * in misc/zebra there is a unimarc directory. I suggest that marc21 libraries create a marc21 directory
3019 # * put your zebra.cfg files here & create your database.
3020 # * from koha cvs home directory, ln -s misc/zebra/marc21 zebra (I mean create a symbolic link to YOUR zebra directory)
3021 # * now, everytime you add/modify a biblio/item your zebra DB is updated correctly.
3022 #
3023 # NOTE :
3024 # * this uses a system call in perl. CPU consumming, but we are waiting for indexdata Perl/zoom
3025 # * deletion still not work
3026 # * UNIMARC zebra config files are provided in misc/zebra/unimarc directory. The most important line being :
3027 # in zebra.cfg :
3028 # recordId: (bib1,Local-number)
3029 # storeKeys:1
3030 #
3031 # in .abs file :
3032 # elm 090            Local-number            -
3033 # elm 090/?          Local-number            -
3034 # elm 090/?/9        Local-number            !:w
3035 #
3036 # (090$9 being the field mapped to biblio.biblionumber in Koha)
3037 #
3038 # Revision 1.127  2005/08/11 14:37:32  tipaul
3039 # * POD documenting
3040 # * removing useless subs
3041 # * removing some subs that are also elsewhere
3042 # * renaming all OLDxxx subs to REALxxx subs (should not change anything, as OLDxxx, as well as REAL, are supposed to be for Biblio.pm internal use only)
3043 #
3044 # Revision 1.126  2005/08/11 09:13:28  tipaul
3045 # just removing useless subs (a lot !!!) for code cleaning
3046 #
3047 # Revision 1.125  2005/08/11 09:00:07  tipaul
3048 # Ok guys, this time, it seems that item add and modif begin working as expected...
3049 # Still a lot of bugs to fix, of course
3050 #
3051 # Revision 1.124  2005/08/10 10:21:15  tipaul
3052 # continuing the road to zebra :
3053 # - the biblio add begins to work.
3054 # - the biblio modif begins to work.
3055 #
3056 # (still without doing anything on zebra)
3057 # (no new change in updatedatabase)
3058 #
3059 # Revision 1.123  2005/08/09 14:10:28  tipaul
3060 # 1st commit to go to zebra.
3061 # don't update your cvs if you want to have a working head...
3062 #
3063 # this commit contains :
3064 # * updater/updatedatabase : get rid with marc_* tables, but DON'T remove them. As a lot of things uses them, it would not be a good idea for instance to drop them. If you really want to play, you can rename them to test head without them but being still able to reintroduce them...
3065 # * Biblio.pm : modify MARCgetbiblio to find the raw marc record in biblioitems.marc field, not from marc_subfield_table, modify MARCfindframeworkcode to find frameworkcode in biblio.frameworkcode, modify some other subs to use biblio.biblionumber & get rid of bibid.
3066 # * other files : get rid of bibid and use biblionumber instead.
3067 #
3068 # What is broken :
3069 # * does not do anything on zebra yet.
3070 # * if you rename marc_subfield_table, you can't search anymore.
3071 # * you can view a biblio & bibliodetails, go to MARC editor, but NOT save any modif.
3072 # * don't try to add a biblio, it would add data poorly... (don't try to delete either, it may work, but that would be a surprise ;-) )
3073 #
3074 # IMPORTANT NOTE : you need MARC::XML package (http://search.cpan.org/~esummers/MARC-XML-0.7/lib/MARC/File/XML.pm), that requires a recent version of MARC::Record
3075 # Updatedatabase stores the iso2709 data in biblioitems.marc field & an xml version in biblioitems.marcxml Not sure we will keep it when releasing the stable version, but I think it's a good idea to have something readable in sql, at least for development stage.
3076
3077 # tipaul cutted previous commit notes