(bug #2904) support of 856$u and 856$z in UNIMARC
[koha.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 use warnings;
22 # use utf8;
23 use MARC::Record;
24 use MARC::File::USMARC;
25 # Force MARC::File::XML to use LibXML SAX Parser
26 $XML::SAX::ParserPackage = "XML::LibXML::SAX";
27 require MARC::File::XML;
28 use ZOOM;
29
30 use C4::Koha;
31 use C4::Dates qw/format_date/;
32 use C4::Log; # logaction
33 use C4::ClassSource;
34 use C4::Charset;
35
36 use vars qw($VERSION @ISA @EXPORT);
37
38 BEGIN {
39         $VERSION = 1.00;
40
41         require Exporter;
42         @ISA = qw( Exporter );
43
44         # to add biblios
45 # EXPORTED FUNCTIONS.
46         push @EXPORT, qw( 
47                 &AddBiblio
48         );
49
50         # to get something
51         push @EXPORT, qw(
52                 &GetBiblio
53                 &GetBiblioData
54                 &GetBiblioItemData
55                 &GetBiblioItemInfosOf
56                 &GetBiblioItemByBiblioNumber
57                 &GetBiblioFromItemNumber
58
59                 &GetMarcNotes
60                 &GetMarcSubjects
61                 &GetMarcBiblio
62                 &GetMarcAuthors
63                 &GetMarcSeries
64                 GetMarcUrls
65                 &GetUsedMarcStructure
66                 &GetXmlBiblio
67
68                 &GetAuthorisedValueDesc
69                 &GetMarcStructure
70                 &GetMarcFromKohaField
71                 &GetFrameworkCode
72                 &GetPublisherNameFromIsbn
73                 &TransformKohaToMarc
74         );
75
76         # To modify something
77         push @EXPORT, qw(
78                 &ModBiblio
79                 &ModBiblioframework
80                 &ModZebra
81         );
82         # To delete something
83         push @EXPORT, qw(
84                 &DelBiblio
85         );
86
87     # To link headings in a bib record
88     # to authority records.
89     push @EXPORT, qw(
90         &LinkBibHeadingsToAuthorities
91     );
92
93         # Internal functions
94         # those functions are exported but should not be used
95         # they are usefull is few circumstances, so are exported.
96         # but don't use them unless you're a core developer ;-)
97         push @EXPORT, qw(
98                 &ModBiblioMarc
99         );
100         # Others functions
101         push @EXPORT, qw(
102                 &TransformMarcToKoha
103                 &TransformHtmlToMarc2
104                 &TransformHtmlToMarc
105                 &TransformHtmlToXml
106                 &PrepareItemrecordDisplay
107                 &GetNoZebraIndexes
108         );
109 }
110
111 =head1 NAME
112
113 C4::Biblio - cataloging management functions
114
115 =head1 DESCRIPTION
116
117 Biblio.pm contains functions for managing storage and editing of bibliographic data within Koha. Most of the functions in this module are used for cataloging records: adding, editing, or removing biblios, biblioitems, or items. Koha's stores bibliographic information in three places:
118
119 =over 4
120
121 =item 1. in the biblio,biblioitems,items, etc tables, which are limited to a one-to-one mapping to underlying MARC data
122
123 =item 2. as raw MARC in the Zebra index and storage engine
124
125 =item 3. as raw MARC the biblioitems.marc and biblioitems.marcxml
126
127 =back
128
129 In the 3.0 version of Koha, the authoritative record-level information is in biblioitems.marcxml
130
131 Because the data isn't completely normalized there's a chance for information to get out of sync. The design choice to go with a un-normalized schema was driven by performance and stability concerns. However, if this occur, it can be considered as a bug : The API is (or should be) complete & the only entry point for all biblio/items managements.
132
133 =over 4
134
135 =item 1. Compared with MySQL, Zebra is slow to update an index for small data changes -- especially for proc-intensive operations like circulation
136
137 =item 2. Zebra's index has been known to crash and a backup of the data is necessary to rebuild it in such cases
138
139 =back
140
141 Because of this design choice, the process of managing storage and editing is a bit convoluted. Historically, Biblio.pm's grown to an unmanagable size and as a result we have several types of functions currently:
142
143 =over 4
144
145 =item 1. Add*/Mod*/Del*/ - high-level external functions suitable for being called from external scripts to manage the collection
146
147 =item 2. _koha_* - low-level internal functions for managing the koha tables
148
149 =item 3. Marc management function : as the MARC record is stored in biblioitems.marc(xml), some subs dedicated to it's management are in this package. They should be used only internally by Biblio.pm, the only official entry points being AddBiblio, AddItem, ModBiblio, ModItem.
150
151 =item 4. Zebra functions used to update the Zebra index
152
153 =item 5. internal helper functions such as char_decode, checkitems, etc. Some of these probably belong in Koha.pm
154
155 =back
156
157 The MARC record (in biblioitems.marcxml) contains the complete marc record, including items. It also contains the biblionumber. That is the reason why it is not stored directly by AddBiblio, with all other fields . To save a biblio, we need to :
158
159 =over 4
160
161 =item 1. save datas in biblio and biblioitems table, that gives us a biblionumber and a biblioitemnumber
162
163 =item 2. add the biblionumber and biblioitemnumber into the MARC records
164
165 =item 3. save the marc record
166
167 =back
168
169 When dealing with items, we must :
170
171 =over 4
172
173 =item 1. save the item in items table, that gives us an itemnumber
174
175 =item 2. add the itemnumber to the item MARC field
176
177 =item 3. overwrite the MARC record (with the added item) into biblioitems.marc(xml)
178
179 When modifying a biblio or an item, the behaviour is quite similar.
180
181 =back
182
183 =head1 EXPORTED FUNCTIONS
184
185 =head2 AddBiblio
186
187 =over 4
188
189 ($biblionumber,$biblioitemnumber) = AddBiblio($record,$frameworkcode);
190
191 =back
192
193 Exported function (core API) for adding a new biblio to koha.
194
195 The first argument is a C<MARC::Record> object containing the
196 bib to add, while the second argument is the desired MARC
197 framework code.
198
199 This function also accepts a third, optional argument: a hashref
200 to additional options.  The only defined option is C<defer_marc_save>,
201 which if present and mapped to a true value, causes C<AddBiblio>
202 to omit the call to save the MARC in C<bibilioitems.marc>
203 and C<biblioitems.marcxml>  This option is provided B<only>
204 for the use of scripts such as C<bulkmarcimport.pl> that may need
205 to do some manipulation of the MARC record for item parsing before
206 saving it and which cannot afford the performance hit of saving
207 the MARC record twice.  Consequently, do not use that option
208 unless you can guarantee that C<ModBiblioMarc> will be called.
209
210 =cut
211
212 sub AddBiblio {
213     my $record = shift;
214     my $frameworkcode = shift;
215     my $options = @_ ? shift : undef;
216     my $defer_marc_save = 0;
217     if (defined $options and exists $options->{'defer_marc_save'} and $options->{'defer_marc_save'}) {
218         $defer_marc_save = 1;
219     }
220
221     my ($biblionumber,$biblioitemnumber,$error);
222     my $dbh = C4::Context->dbh;
223     # transform the data into koha-table style data
224     my $olddata = TransformMarcToKoha( $dbh, $record, $frameworkcode );
225     ($biblionumber,$error) = _koha_add_biblio( $dbh, $olddata, $frameworkcode );
226     $olddata->{'biblionumber'} = $biblionumber;
227     ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $olddata );
228
229     _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
230
231     # update MARC subfield that stores biblioitems.cn_sort
232     _koha_marc_update_biblioitem_cn_sort($record, $olddata, $frameworkcode);
233     
234     # now add the record
235     $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode ) unless $defer_marc_save;
236       
237     logaction("CATALOGUING", "ADD", $biblionumber, "biblio") if C4::Context->preference("CataloguingLog");
238
239     return ( $biblionumber, $biblioitemnumber );
240 }
241
242 =head2 ModBiblio
243
244 =over 4
245
246     ModBiblio( $record,$biblionumber,$frameworkcode);
247
248 =back
249
250 Replace an existing bib record identified by C<$biblionumber>
251 with one supplied by the MARC::Record object C<$record>.  The embedded
252 item, biblioitem, and biblionumber fields from the previous
253 version of the bib record replace any such fields of those tags that
254 are present in C<$record>.  Consequently, ModBiblio() is not
255 to be used to try to modify item records.
256
257 C<$frameworkcode> specifies the MARC framework to use
258 when storing the modified bib record; among other things,
259 this controls how MARC fields get mapped to display columns
260 in the C<biblio> and C<biblioitems> tables, as well as
261 which fields are used to store embedded item, biblioitem,
262 and biblionumber data for indexing.
263
264 =cut
265
266 sub ModBiblio {
267     my ( $record, $biblionumber, $frameworkcode ) = @_;
268     if (C4::Context->preference("CataloguingLog")) {
269         my $newrecord = GetMarcBiblio($biblionumber);
270         logaction("CATALOGUING", "MODIFY", $biblionumber, "BEFORE=>".$newrecord->as_formatted);
271     }
272     
273     my $dbh = C4::Context->dbh;
274     
275     $frameworkcode = "" unless $frameworkcode;
276
277     # get the items before and append them to the biblio before updating the record, atm we just have the biblio
278     my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
279     my $oldRecord = GetMarcBiblio( $biblionumber );
280
281     # delete any item fields from incoming record to avoid
282     # duplication or incorrect data - use AddItem() or ModItem()
283     # to change items
284     foreach my $field ($record->field($itemtag)) {
285         $record->delete_field($field);
286     }
287     
288     # parse each item, and, for an unknown reason, re-encode each subfield 
289     # if you don't do that, the record will have encoding mixed
290     # and the biblio will be re-encoded.
291     # strange, I (Paul P.) searched more than 1 day to understand what happends
292     # but could only solve the problem this way...
293    my @fields = $oldRecord->field( $itemtag );
294     foreach my $fielditem ( @fields ){
295         my $field;
296         foreach ($fielditem->subfields()) {
297             if ($field) {
298                 $field->add_subfields(Encode::encode('utf-8',$_->[0]) => Encode::encode('utf-8',$_->[1]));
299             } else {
300                 $field = MARC::Field->new("$itemtag",'','',Encode::encode('utf-8',$_->[0]) => Encode::encode('utf-8',$_->[1]));
301             }
302           }
303         $record->append_fields($field);
304     }
305     
306     # update biblionumber and biblioitemnumber in MARC
307     # FIXME - this is assuming a 1 to 1 relationship between
308     # biblios and biblioitems
309     my $sth =  $dbh->prepare("select biblioitemnumber from biblioitems where biblionumber=?");
310     $sth->execute($biblionumber);
311     my ($biblioitemnumber) = $sth->fetchrow;
312     $sth->finish();
313     _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
314
315     # load the koha-table data object
316     my $oldbiblio = TransformMarcToKoha( $dbh, $record, $frameworkcode );
317
318     # update MARC subfield that stores biblioitems.cn_sort
319     _koha_marc_update_biblioitem_cn_sort($record, $oldbiblio, $frameworkcode);
320
321     # update the MARC record (that now contains biblio and items) with the new record data
322     &ModBiblioMarc( $record, $biblionumber, $frameworkcode );
323     
324     # modify the other koha tables
325     _koha_modify_biblio( $dbh, $oldbiblio, $frameworkcode );
326     _koha_modify_biblioitem_nonmarc( $dbh, $oldbiblio );
327     return 1;
328 }
329
330 =head2 ModBiblioframework
331
332     ModBiblioframework($biblionumber,$frameworkcode);
333     Exported function to modify a biblio framework
334
335 =cut
336
337 sub ModBiblioframework {
338     my ( $biblionumber, $frameworkcode ) = @_;
339     my $dbh = C4::Context->dbh;
340     my $sth = $dbh->prepare(
341         "UPDATE biblio SET frameworkcode=? WHERE biblionumber=?"
342     );
343     $sth->execute($frameworkcode, $biblionumber);
344     return 1;
345 }
346
347 =head2 DelBiblio
348
349 =over
350
351 my $error = &DelBiblio($dbh,$biblionumber);
352 Exported function (core API) for deleting a biblio in koha.
353 Deletes biblio record from Zebra and Koha tables (biblio,biblioitems,items)
354 Also backs it up to deleted* tables
355 Checks to make sure there are not issues on any of the items
356 return:
357 C<$error> : undef unless an error occurs
358
359 =back
360
361 =cut
362
363 sub DelBiblio {
364     my ( $biblionumber ) = @_;
365     my $dbh = C4::Context->dbh;
366     my $error;    # for error handling
367     
368     # First make sure this biblio has no items attached
369     my $sth = $dbh->prepare("SELECT itemnumber FROM items WHERE biblionumber=?");
370     $sth->execute($biblionumber);
371     if (my $itemnumber = $sth->fetchrow){
372         # Fix this to use a status the template can understand
373         $error .= "This Biblio has items attached, please delete them first before deleting this biblio ";
374     }
375
376     return $error if $error;
377
378     # Delete in Zebra. Be careful NOT to move this line after _koha_delete_biblio
379     # for at least 2 reasons :
380     # - we need to read the biblio if NoZebra is set (to remove it from the indexes
381     # - if something goes wrong, the biblio may be deleted from Koha but not from zebra
382     #   and we would have no way to remove it (except manually in zebra, but I bet it would be very hard to handle the problem)
383     my $oldRecord;
384     if (C4::Context->preference("NoZebra")) {
385         # only NoZebra indexing needs to have
386         # the previous version of the record
387         $oldRecord = GetMarcBiblio($biblionumber);
388     }
389     ModZebra($biblionumber, "recordDelete", "biblioserver", $oldRecord, undef);
390
391     # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems
392     $sth =
393       $dbh->prepare(
394         "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
395     $sth->execute($biblionumber);
396     while ( my $biblioitemnumber = $sth->fetchrow ) {
397
398         # delete this biblioitem
399         $error = _koha_delete_biblioitems( $dbh, $biblioitemnumber );
400         return $error if $error;
401     }
402
403     # delete biblio from Koha tables and save in deletedbiblio
404     # must do this *after* _koha_delete_biblioitems, otherwise
405     # delete cascade will prevent deletedbiblioitems rows
406     # from being generated by _koha_delete_biblioitems
407     $error = _koha_delete_biblio( $dbh, $biblionumber );
408
409     logaction("CATALOGUING", "DELETE", $biblionumber, "") if C4::Context->preference("CataloguingLog");
410
411     return;
412 }
413
414 =head2 LinkBibHeadingsToAuthorities
415
416 =over 4
417
418 my $headings_linked = LinkBibHeadingsToAuthorities($marc);
419
420 =back
421
422 Links bib headings to authority records by checking
423 each authority-controlled field in the C<MARC::Record>
424 object C<$marc>, looking for a matching authority record,
425 and setting the linking subfield $9 to the ID of that
426 authority record.  
427
428 If no matching authority exists, or if multiple
429 authorities match, no $9 will be added, and any 
430 existing one inthe field will be deleted.
431
432 Returns the number of heading links changed in the
433 MARC record.
434
435 =cut
436
437 sub LinkBibHeadingsToAuthorities {
438     my $bib = shift;
439
440     my $num_headings_changed = 0;
441     foreach my $field ($bib->fields()) {
442         my $heading = C4::Heading->new_from_bib_field($field);    
443         next unless defined $heading;
444
445         # check existing $9
446         my $current_link = $field->subfield('9');
447
448         # look for matching authorities
449         my $authorities = $heading->authorities();
450
451         # want only one exact match
452         if ($#{ $authorities } == 0) {
453             my $authority = MARC::Record->new_from_usmarc($authorities->[0]);
454             my $authid = $authority->field('001')->data();
455             next if defined $current_link and $current_link eq $authid;
456
457             $field->delete_subfield(code => '9') if defined $current_link;
458             $field->add_subfields('9', $authid);
459             $num_headings_changed++;
460         } else {
461             if (defined $current_link) {
462                 $field->delete_subfield(code => '9');
463                 $num_headings_changed++;
464             }
465         }
466
467     }
468     return $num_headings_changed;
469 }
470
471 =head2 GetBiblioData
472
473 =over 4
474
475 $data = &GetBiblioData($biblionumber);
476 Returns information about the book with the given biblionumber.
477 C<&GetBiblioData> returns a reference-to-hash. The keys are the fields in
478 the C<biblio> and C<biblioitems> tables in the
479 Koha database.
480 In addition, C<$data-E<gt>{subject}> is the list of the book's
481 subjects, separated by C<" , "> (space, comma, space).
482 If there are multiple biblioitems with the given biblionumber, only
483 the first one is considered.
484
485 =back
486
487 =cut
488
489 sub GetBiblioData {
490     my ( $bibnum ) = @_;
491     my $dbh = C4::Context->dbh;
492
493   #  my $query =  C4::Context->preference('item-level_itypes') ? 
494     #   " SELECT * , biblioitems.notes AS bnotes, biblio.notes
495     #       FROM biblio
496     #        LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
497     #       WHERE biblio.biblionumber = ?
498     #        AND biblioitems.biblionumber = biblio.biblionumber
499     #";
500     
501     my $query = " SELECT * , biblioitems.notes AS bnotes, itemtypes.notforloan as bi_notforloan, biblio.notes
502             FROM biblio
503             LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
504             LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
505             WHERE biblio.biblionumber = ?
506             AND biblioitems.biblionumber = biblio.biblionumber ";
507          
508     my $sth = $dbh->prepare($query);
509     $sth->execute($bibnum);
510     my $data;
511     $data = $sth->fetchrow_hashref;
512     $sth->finish;
513
514     return ($data);
515 }    # sub GetBiblioData
516
517 =head2 &GetBiblioItemData
518
519 =over 4
520
521 $itemdata = &GetBiblioItemData($biblioitemnumber);
522
523 Looks up the biblioitem with the given biblioitemnumber. Returns a
524 reference-to-hash. The keys are the fields from the C<biblio>,
525 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
526 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
527
528 =back
529
530 =cut
531
532 #'
533 sub GetBiblioItemData {
534     my ($biblioitemnumber) = @_;
535     my $dbh       = C4::Context->dbh;
536     my $query = "SELECT *,biblioitems.notes AS bnotes
537         FROM biblio LEFT JOIN biblioitems on biblio.biblionumber=biblioitems.biblionumber ";
538     unless(C4::Context->preference('item-level_itypes')) { 
539         $query .= "LEFT JOIN itemtypes on biblioitems.itemtype=itemtypes.itemtype ";
540     }    
541     $query .= " WHERE biblioitemnumber = ? ";
542     my $sth       =  $dbh->prepare($query);
543     my $data;
544     $sth->execute($biblioitemnumber);
545     $data = $sth->fetchrow_hashref;
546     $sth->finish;
547     return ($data);
548 }    # sub &GetBiblioItemData
549
550 =head2 GetBiblioItemByBiblioNumber
551
552 =over 4
553
554 NOTE : This function has been copy/paste from C4/Biblio.pm from head before zebra integration.
555
556 =back
557
558 =cut
559
560 sub GetBiblioItemByBiblioNumber {
561     my ($biblionumber) = @_;
562     my $dbh = C4::Context->dbh;
563     my $sth = $dbh->prepare("Select * FROM biblioitems WHERE biblionumber = ?");
564     my $count = 0;
565     my @results;
566
567     $sth->execute($biblionumber);
568
569     while ( my $data = $sth->fetchrow_hashref ) {
570         push @results, $data;
571     }
572
573     $sth->finish;
574     return @results;
575 }
576
577 =head2 GetBiblioFromItemNumber
578
579 =over 4
580
581 $item = &GetBiblioFromItemNumber($itemnumber,$barcode);
582
583 Looks up the item with the given itemnumber. if undef, try the barcode.
584
585 C<&itemnodata> returns a reference-to-hash whose keys are the fields
586 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
587 database.
588
589 =back
590
591 =cut
592
593 #'
594 sub GetBiblioFromItemNumber {
595     my ( $itemnumber, $barcode ) = @_;
596     my $dbh = C4::Context->dbh;
597     my $sth;
598     if($itemnumber) {
599         $sth=$dbh->prepare(  "SELECT * FROM items 
600             LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
601             LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
602              WHERE items.itemnumber = ?") ; 
603         $sth->execute($itemnumber);
604     } else {
605         $sth=$dbh->prepare(  "SELECT * FROM items 
606             LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
607             LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
608              WHERE items.barcode = ?") ; 
609         $sth->execute($barcode);
610     }
611     my $data = $sth->fetchrow_hashref;
612     $sth->finish;
613     return ($data);
614 }
615
616 =head2 GetBiblio
617
618 =over 4
619
620 ( $count, @results ) = &GetBiblio($biblionumber);
621
622 =back
623
624 =cut
625
626 sub GetBiblio {
627     my ($biblionumber) = @_;
628     my $dbh = C4::Context->dbh;
629     my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber = ?");
630     my $count = 0;
631     my @results;
632     $sth->execute($biblionumber);
633     while ( my $data = $sth->fetchrow_hashref ) {
634         $results[$count] = $data;
635         $count++;
636     }    # while
637     $sth->finish;
638     return ( $count, @results );
639 }    # sub GetBiblio
640
641 =head2 GetBiblioItemInfosOf
642
643 =over 4
644
645 GetBiblioItemInfosOf(@biblioitemnumbers);
646
647 =back
648
649 =cut
650
651 sub GetBiblioItemInfosOf {
652     my @biblioitemnumbers = @_;
653
654     my $query = '
655         SELECT biblioitemnumber,
656             publicationyear,
657             itemtype
658         FROM biblioitems
659         WHERE biblioitemnumber IN (' . join( ',', @biblioitemnumbers ) . ')
660     ';
661     return get_infos_of( $query, 'biblioitemnumber' );
662 }
663
664 =head1 FUNCTIONS FOR HANDLING MARC MANAGEMENT
665
666 =head2 GetMarcStructure
667
668 =over 4
669
670 $res = GetMarcStructure($forlibrarian,$frameworkcode);
671
672 Returns a reference to a big hash of hash, with the Marc structure for the given frameworkcode
673 $forlibrarian  :if set to 1, the MARC descriptions are the librarians ones, otherwise it's the public (OPAC) ones
674 $frameworkcode : the framework code to read
675
676 =back
677
678 =cut
679
680 # cache for results of GetMarcStructure -- needed
681 # for batch jobs
682 our $marc_structure_cache;
683
684 sub GetMarcStructure {
685     my ( $forlibrarian, $frameworkcode ) = @_;
686     my $dbh=C4::Context->dbh;
687     $frameworkcode = "" unless $frameworkcode;
688
689     if (defined $marc_structure_cache and exists $marc_structure_cache->{$forlibrarian}->{$frameworkcode}) {
690         return $marc_structure_cache->{$forlibrarian}->{$frameworkcode};
691     }
692
693     my $sth;
694     my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
695
696     # check that framework exists
697     $sth =
698       $dbh->prepare(
699         "SELECT COUNT(*) FROM marc_tag_structure WHERE frameworkcode=?");
700     $sth->execute($frameworkcode);
701     my ($total) = $sth->fetchrow;
702     $frameworkcode = "" unless ( $total > 0 );
703     $sth =
704       $dbh->prepare(
705         "SELECT tagfield,liblibrarian,libopac,mandatory,repeatable 
706         FROM marc_tag_structure 
707         WHERE frameworkcode=? 
708         ORDER BY tagfield"
709       );
710     $sth->execute($frameworkcode);
711     my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
712
713     while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) =
714         $sth->fetchrow )
715     {
716         $res->{$tag}->{lib} =
717           ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
718         $res->{$tag}->{tab}        = "";
719         $res->{$tag}->{mandatory}  = $mandatory;
720         $res->{$tag}->{repeatable} = $repeatable;
721     }
722
723     $sth =
724       $dbh->prepare(
725             "SELECT tagfield,tagsubfield,liblibrarian,libopac,tab,mandatory,repeatable,authorised_value,authtypecode,value_builder,kohafield,seealso,hidden,isurl,link,defaultvalue 
726                 FROM marc_subfield_structure 
727             WHERE frameworkcode=? 
728                 ORDER BY tagfield,tagsubfield
729             "
730     );
731     
732     $sth->execute($frameworkcode);
733
734     my $subfield;
735     my $authorised_value;
736     my $authtypecode;
737     my $value_builder;
738     my $kohafield;
739     my $seealso;
740     my $hidden;
741     my $isurl;
742     my $link;
743     my $defaultvalue;
744
745     while (
746         (
747             $tag,          $subfield,      $liblibrarian,
748             ,              $libopac,       $tab,
749             $mandatory,    $repeatable,    $authorised_value,
750             $authtypecode, $value_builder, $kohafield,
751             $seealso,      $hidden,        $isurl,
752             $link,$defaultvalue
753         )
754         = $sth->fetchrow
755       )
756     {
757         $res->{$tag}->{$subfield}->{lib} =
758           ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
759         $res->{$tag}->{$subfield}->{tab}              = $tab;
760         $res->{$tag}->{$subfield}->{mandatory}        = $mandatory;
761         $res->{$tag}->{$subfield}->{repeatable}       = $repeatable;
762         $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
763         $res->{$tag}->{$subfield}->{authtypecode}     = $authtypecode;
764         $res->{$tag}->{$subfield}->{value_builder}    = $value_builder;
765         $res->{$tag}->{$subfield}->{kohafield}        = $kohafield;
766         $res->{$tag}->{$subfield}->{seealso}          = $seealso;
767         $res->{$tag}->{$subfield}->{hidden}           = $hidden;
768         $res->{$tag}->{$subfield}->{isurl}            = $isurl;
769         $res->{$tag}->{$subfield}->{'link'}           = $link;
770         $res->{$tag}->{$subfield}->{defaultvalue}     = $defaultvalue;
771     }
772
773     $marc_structure_cache->{$forlibrarian}->{$frameworkcode} = $res;
774
775     return $res;
776 }
777
778 =head2 GetUsedMarcStructure
779
780     the same function as GetMarcStructure expcet it just take field
781     in tab 0-9. (used field)
782     
783     my $results = GetUsedMarcStructure($frameworkcode);
784     
785     L<$results> is a ref to an array which each case containts a ref
786     to a hash which each keys is the columns from marc_subfield_structure
787     
788     L<$frameworkcode> is the framework code. 
789     
790 =cut
791
792 sub GetUsedMarcStructure($){
793     my $frameworkcode = shift || '';
794     my $dbh           = C4::Context->dbh;
795     my $query         = qq/
796         SELECT *
797         FROM   marc_subfield_structure
798         WHERE   tab > -1 
799             AND frameworkcode = ?
800     /;
801     my @results;
802     my $sth = $dbh->prepare($query);
803     $sth->execute($frameworkcode);
804     while (my $row = $sth->fetchrow_hashref){
805         push @results,$row;
806     }
807     return \@results;
808 }
809
810 =head2 GetMarcFromKohaField
811
812 =over 4
813
814 ($MARCfield,$MARCsubfield)=GetMarcFromKohaField($kohafield,$frameworkcode);
815 Returns the MARC fields & subfields mapped to the koha field 
816 for the given frameworkcode
817
818 =back
819
820 =cut
821
822 sub GetMarcFromKohaField {
823     my ( $kohafield, $frameworkcode ) = @_;
824     return 0, 0 unless $kohafield and defined $frameworkcode;
825     my $relations = C4::Context->marcfromkohafield;
826     return (
827         $relations->{$frameworkcode}->{$kohafield}->[0],
828         $relations->{$frameworkcode}->{$kohafield}->[1]
829     );
830 }
831
832 =head2 GetMarcBiblio
833
834 =over 4
835
836 my $record = GetMarcBiblio($biblionumber);
837
838 =back
839
840 Returns MARC::Record representing bib identified by
841 C<$biblionumber>.  If no bib exists, returns undef.
842 The MARC record contains both biblio & item data.
843
844 =cut
845
846 sub GetMarcBiblio {
847     my $biblionumber = shift;
848     my $dbh          = C4::Context->dbh;
849     my $sth          =
850       $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
851     $sth->execute($biblionumber);
852     my $row = $sth->fetchrow_hashref;
853     my $marcxml = StripNonXmlChars($row->{'marcxml'});
854      MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
855     my $record = MARC::Record->new();
856     if ($marcxml) {
857         $record = eval {MARC::Record::new_from_xml( $marcxml, "utf8", C4::Context->preference('marcflavour'))};
858         if ($@) {warn " problem with :$biblionumber : $@ \n$marcxml";}
859 #      $record = MARC::Record::new_from_usmarc( $marc) if $marc;
860         return $record;
861     } else {
862         return undef;
863     }
864 }
865
866 =head2 GetXmlBiblio
867
868 =over 4
869
870 my $marcxml = GetXmlBiblio($biblionumber);
871
872 Returns biblioitems.marcxml of the biblionumber passed in parameter.
873 The XML contains both biblio & item datas
874
875 =back
876
877 =cut
878
879 sub GetXmlBiblio {
880     my ( $biblionumber ) = @_;
881     my $dbh = C4::Context->dbh;
882     my $sth =
883       $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
884     $sth->execute($biblionumber);
885     my ($marcxml) = $sth->fetchrow;
886     return $marcxml;
887 }
888
889 =head2 GetAuthorisedValueDesc
890
891 =over 4
892
893 my $subfieldvalue =get_authorised_value_desc(
894     $tag, $subf[$i][0],$subf[$i][1], '', $taglib, $category);
895 Retrieve the complete description for a given authorised value.
896
897 Now takes $category and $value pair too.
898 my $auth_value_desc =GetAuthorisedValueDesc(
899     '','', 'DVD' ,'','','CCODE');
900
901 =back
902
903 =cut
904
905 sub GetAuthorisedValueDesc {
906     my ( $tag, $subfield, $value, $framework, $tagslib, $category ) = @_;
907     my $dbh = C4::Context->dbh;
908
909     if (!$category) {
910
911         return $value unless defined $tagslib->{$tag}->{$subfield}->{'authorised_value'};
912
913 #---- branch
914         if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
915             return C4::Branch::GetBranchName($value);
916         }
917
918 #---- itemtypes
919         if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "itemtypes" ) {
920             return getitemtypeinfo($value)->{description};
921         }
922
923 #---- "true" authorized value
924         $category = $tagslib->{$tag}->{$subfield}->{'authorised_value'}
925     }
926
927     if ( $category ne "" ) {
928         my $sth =
929             $dbh->prepare(
930                     "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
931                     );
932         $sth->execute( $category, $value );
933         my $data = $sth->fetchrow_hashref;
934         return $data->{'lib'};
935     }
936     else {
937         return $value;    # if nothing is found return the original value
938     }
939 }
940
941 =head2 GetMarcNotes
942
943 =over 4
944
945 $marcnotesarray = GetMarcNotes( $record, $marcflavour );
946 Get all notes from the MARC record and returns them in an array.
947 The note are stored in differents places depending on MARC flavour
948
949 =back
950
951 =cut
952
953 sub GetMarcNotes {
954     my ( $record, $marcflavour ) = @_;
955     my $scope;
956     if ( $marcflavour eq "MARC21" ) {
957         $scope = '5..';
958     }
959     else {    # assume unimarc if not marc21
960         $scope = '3..';
961     }
962     my @marcnotes;
963     my $note = "";
964     my $tag  = "";
965     my $marcnote;
966     foreach my $field ( $record->field($scope) ) {
967         my $value = $field->as_string();
968         if ( $note ne "" ) {
969             $marcnote = { marcnote => $note, };
970             push @marcnotes, $marcnote;
971             $note = $value;
972         }
973         if ( $note ne $value ) {
974             $note = $note . " " . $value;
975         }
976     }
977
978     if ( $note ) {
979         $marcnote = { marcnote => $note };
980         push @marcnotes, $marcnote;    #load last tag into array
981     }
982     return \@marcnotes;
983 }    # end GetMarcNotes
984
985 =head2 GetMarcSubjects
986
987 =over 4
988
989 $marcsubjcts = GetMarcSubjects($record,$marcflavour);
990 Get all subjects from the MARC record and returns them in an array.
991 The subjects are stored in differents places depending on MARC flavour
992
993 =back
994
995 =cut
996
997 sub GetMarcSubjects {
998     my ( $record, $marcflavour ) = @_;
999     my ( $mintag, $maxtag );
1000     if ( $marcflavour eq "MARC21" ) {
1001         $mintag = "600";
1002         $maxtag = "699";
1003     }
1004     else {    # assume unimarc if not marc21
1005         $mintag = "600";
1006         $maxtag = "611";
1007     }
1008     
1009     my @marcsubjects;
1010     my $subject = "";
1011     my $subfield = "";
1012     my $marcsubject;
1013
1014     foreach my $field ( $record->field('6..' )) {
1015         next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1016         my @subfields_loop;
1017         my @subfields = $field->subfields();
1018         my $counter = 0;
1019         my @link_loop;
1020         # if there is an authority link, build the link with an= subfield9
1021         my $subfield9 = $field->subfield('9');
1022         for my $subject_subfield (@subfields ) {
1023             # don't load unimarc subfields 3,4,5
1024             next if (($marcflavour eq "UNIMARC") and ($subject_subfield->[0] =~ /3|4|5/ ) );
1025             my $code = $subject_subfield->[0];
1026             my $value = $subject_subfield->[1];
1027             my $linkvalue = $value;
1028             $linkvalue =~ s/(\(|\))//g;
1029             my $operator = " and " unless $counter==0;
1030             if ($subfield9) {
1031                 @link_loop = ({'limit' => 'an' ,link => "$subfield9" });
1032             } else {
1033                 push @link_loop, {'limit' => 'su', link => $linkvalue, operator => $operator };
1034             }
1035             my $separator = C4::Context->preference("authoritysep") unless $counter==0;
1036             # ignore $9
1037             my @this_link_loop = @link_loop;
1038             push @subfields_loop, {code => $code, value => $value, link_loop => \@this_link_loop, separator => $separator} unless ($subject_subfield->[0] eq 9 );
1039             $counter++;
1040         }
1041                 
1042         push @marcsubjects, { MARCSUBJECT_SUBFIELDS_LOOP => \@subfields_loop };
1043         
1044     }
1045         return \@marcsubjects;
1046 }  #end getMARCsubjects
1047
1048 =head2 GetMarcAuthors
1049
1050 =over 4
1051
1052 authors = GetMarcAuthors($record,$marcflavour);
1053 Get all authors from the MARC record and returns them in an array.
1054 The authors are stored in differents places depending on MARC flavour
1055
1056 =back
1057
1058 =cut
1059
1060 sub GetMarcAuthors {
1061     my ( $record, $marcflavour ) = @_;
1062     my ( $mintag, $maxtag );
1063     # tagslib useful for UNIMARC author reponsabilities
1064     my $tagslib = &GetMarcStructure( 1, '' ); # FIXME : we don't have the framework available, we take the default framework. May be bugguy on some setups, will be usually correct.
1065     if ( $marcflavour eq "MARC21" ) {
1066         $mintag = "700";
1067         $maxtag = "720"; 
1068     }
1069     elsif ( $marcflavour eq "UNIMARC" ) {    # assume unimarc if not marc21
1070         $mintag = "700";
1071         $maxtag = "712";
1072     }
1073     else {
1074         return;
1075     }
1076     my @marcauthors;
1077
1078     foreach my $field ( $record->fields ) {
1079         next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1080         my @subfields_loop;
1081         my @link_loop;
1082         my @subfields = $field->subfields();
1083         my $count_auth = 0;
1084         # if there is an authority link, build the link with Koha-Auth-Number: subfield9
1085         my $subfield9 = $field->subfield('9');
1086         for my $authors_subfield (@subfields) {
1087             # don't load unimarc subfields 3, 5
1088             next if ($marcflavour eq 'UNIMARC' and ($authors_subfield->[0] =~ /3|5/ ) );
1089             my $subfieldcode = $authors_subfield->[0];
1090             my $value = $authors_subfield->[1];
1091             my $linkvalue = $value;
1092             $linkvalue =~ s/(\(|\))//g;
1093             my $operator = " and " unless $count_auth==0;
1094             # if we have an authority link, use that as the link, otherwise use standard searching
1095             if ($subfield9) {
1096                 @link_loop = ({'limit' => 'an' ,link => "$subfield9" });
1097             }
1098             else {
1099                 # reset $linkvalue if UNIMARC author responsibility
1100                 if ( $marcflavour eq 'UNIMARC' and ($authors_subfield->[0] eq "4")) {
1101                     $linkvalue = "(".GetAuthorisedValueDesc( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib ).")";
1102                 }
1103                 push @link_loop, {'limit' => 'au', link => $linkvalue, operator => $operator };
1104             }
1105             $value = GetAuthorisedValueDesc( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib ) if ( $marcflavour eq 'UNIMARC' and ($authors_subfield->[0] =~/4/));
1106             my @this_link_loop = @link_loop;
1107             my $separator = C4::Context->preference("authoritysep") unless $count_auth==0;
1108             push @subfields_loop, {code => $subfieldcode, value => $value, link_loop => \@this_link_loop, separator => $separator} unless ($authors_subfield->[0] eq '9' );
1109             $count_auth++;
1110         }
1111         push @marcauthors, { MARCAUTHOR_SUBFIELDS_LOOP => \@subfields_loop };
1112     }
1113     return \@marcauthors;
1114 }
1115
1116 =head2 GetMarcUrls
1117
1118 =over 4
1119
1120 $marcurls = GetMarcUrls($record,$marcflavour);
1121 Returns arrayref of URLs from MARC data, suitable to pass to tmpl loop.
1122 Assumes web resources (not uncommon in MARC21 to omit resource type ind) 
1123
1124 =back
1125
1126 =cut
1127
1128 sub GetMarcUrls {
1129     my ($record, $marcflavour) = @_;
1130     my @marcurls;
1131     for my $field ($record->field('856')) {
1132         my $marcurl;
1133         my $url = $field->subfield('u');
1134         my @notes;
1135         for my $note ( $field->subfield('z')) {
1136             push @notes , {note => $note};
1137         }        
1138         if($marcflavour eq 'MARC21') {
1139             my $s3 = $field->subfield('3');
1140             my $link = $field->subfield('y');
1141                         unless($url =~ /^\w+:/) {
1142                                 if($field->indicator(1) eq '7') {
1143                                         $url = $field->subfield('2') . "://" . $url;
1144                                 } elsif ($field->indicator(1) eq '1') {
1145                                         $url = 'ftp://' . $url;
1146                                 } else {  
1147                                         #  properly, this should be if ind1=4,
1148                                         #  however we will assume http protocol since we're building a link.
1149                                         $url = 'http://' . $url;
1150                                 }
1151                         }
1152                         # TODO handle ind 2 (relationship)
1153                 $marcurl = {  MARCURL => $url,
1154                       notes => \@notes,
1155             };
1156             $marcurl->{'linktext'} = $link || $s3 || C4::Context->preference('URLLinkText') || $url ;;
1157             $marcurl->{'part'} = $s3 if($link);
1158             $marcurl->{'toc'} = 1 if($s3 =~ /^[Tt]able/) ;
1159         } else {
1160             $marcurl->{'linktext'} = $field->subfield('z') || C4::Context->preference('URLLinkText') || $url;
1161             $marcurl->{'MARCURL'} = $url ;
1162         }
1163         push @marcurls, $marcurl;    
1164     }
1165     return \@marcurls;
1166 }  #end GetMarcUrls
1167
1168 =head2 GetMarcSeries
1169
1170 =over 4
1171
1172 $marcseriesarray = GetMarcSeries($record,$marcflavour);
1173 Get all series from the MARC record and returns them in an array.
1174 The series are stored in differents places depending on MARC flavour
1175
1176 =back
1177
1178 =cut
1179
1180 sub GetMarcSeries {
1181     my ($record, $marcflavour) = @_;
1182     my ($mintag, $maxtag);
1183     if ($marcflavour eq "MARC21") {
1184         $mintag = "440";
1185         $maxtag = "490";
1186     } else {           # assume unimarc if not marc21
1187         $mintag = "600";
1188         $maxtag = "619";
1189     }
1190
1191     my @marcseries;
1192     my $subjct = "";
1193     my $subfield = "";
1194     my $marcsubjct;
1195
1196     foreach my $field ($record->field('440'), $record->field('490')) {
1197         my @subfields_loop;
1198         #my $value = $field->subfield('a');
1199         #$marcsubjct = {MARCSUBJCT => $value,};
1200         my @subfields = $field->subfields();
1201         #warn "subfields:".join " ", @$subfields;
1202         my $counter = 0;
1203         my @link_loop;
1204         for my $series_subfield (@subfields) {
1205             my $volume_number;
1206             undef $volume_number;
1207             # see if this is an instance of a volume
1208             if ($series_subfield->[0] eq 'v') {
1209                 $volume_number=1;
1210             }
1211
1212             my $code = $series_subfield->[0];
1213             my $value = $series_subfield->[1];
1214             my $linkvalue = $value;
1215             $linkvalue =~ s/(\(|\))//g;
1216             my $operator = " and " unless $counter==0;
1217             push @link_loop, {link => $linkvalue, operator => $operator };
1218             my $separator = C4::Context->preference("authoritysep") unless $counter==0;
1219             if ($volume_number) {
1220             push @subfields_loop, {volumenum => $value};
1221             }
1222             else {
1223             push @subfields_loop, {code => $code, value => $value, link_loop => \@link_loop, separator => $separator, volumenum => $volume_number};
1224             }
1225             $counter++;
1226         }
1227         push @marcseries, { MARCSERIES_SUBFIELDS_LOOP => \@subfields_loop };
1228         #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
1229         #push @marcsubjcts, $marcsubjct;
1230         #$subjct = $value;
1231
1232     }
1233     my $marcseriessarray=\@marcseries;
1234     return $marcseriessarray;
1235 }  #end getMARCseriess
1236
1237 =head2 GetFrameworkCode
1238
1239 =over 4
1240
1241     $frameworkcode = GetFrameworkCode( $biblionumber )
1242
1243 =back
1244
1245 =cut
1246
1247 sub GetFrameworkCode {
1248     my ( $biblionumber ) = @_;
1249     my $dbh = C4::Context->dbh;
1250     my $sth = $dbh->prepare("SELECT frameworkcode FROM biblio WHERE biblionumber=?");
1251     $sth->execute($biblionumber);
1252     my ($frameworkcode) = $sth->fetchrow;
1253     return $frameworkcode;
1254 }
1255
1256 =head2 GetPublisherNameFromIsbn
1257
1258     $name = GetPublishercodeFromIsbn($isbn);
1259     if(defined $name){
1260         ...
1261     }
1262
1263 =cut
1264
1265 sub GetPublisherNameFromIsbn($){
1266     my $isbn = shift;
1267     $isbn =~ s/[- _]//g;
1268     $isbn =~ s/^0*//;
1269     my @codes = (split '-', DisplayISBN($isbn));
1270     my $code = $codes[0].$codes[1].$codes[2];
1271     my $dbh  = C4::Context->dbh;
1272     my $query = qq{
1273         SELECT distinct publishercode
1274         FROM   biblioitems
1275         WHERE  isbn LIKE ?
1276         AND    publishercode IS NOT NULL
1277         LIMIT 1
1278     };
1279     my $sth = $dbh->prepare($query);
1280     $sth->execute("$code%");
1281     my $name = $sth->fetchrow;
1282     return $name if length $name;
1283     return undef;
1284 }
1285
1286 =head2 TransformKohaToMarc
1287
1288 =over 4
1289
1290     $record = TransformKohaToMarc( $hash )
1291     This function builds partial MARC::Record from a hash
1292     Hash entries can be from biblio or biblioitems.
1293     This function is called in acquisition module, to create a basic catalogue entry from user entry
1294
1295 =back
1296
1297 =cut
1298
1299 sub TransformKohaToMarc {
1300
1301     my ( $hash ) = @_;
1302     my $dbh = C4::Context->dbh;
1303     my $sth =
1304     $dbh->prepare(
1305         "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE frameworkcode=? AND kohafield=?"
1306     );
1307     my $record = MARC::Record->new();
1308     foreach (keys %{$hash}) {
1309         &TransformKohaToMarcOneField( $sth, $record, $_,
1310             $hash->{$_}, '' );
1311         }
1312     return $record;
1313 }
1314
1315 =head2 TransformKohaToMarcOneField
1316
1317 =over 4
1318
1319     $record = TransformKohaToMarcOneField( $sth, $record, $kohafieldname, $value, $frameworkcode );
1320
1321 =back
1322
1323 =cut
1324
1325 sub TransformKohaToMarcOneField {
1326     my ( $sth, $record, $kohafieldname, $value, $frameworkcode ) = @_;
1327     $frameworkcode='' unless $frameworkcode;
1328     my $tagfield;
1329     my $tagsubfield;
1330
1331     if ( !defined $sth ) {
1332         my $dbh = C4::Context->dbh;
1333         $sth = $dbh->prepare(
1334             "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE frameworkcode=? AND kohafield=?"
1335         );
1336     }
1337     $sth->execute( $frameworkcode, $kohafieldname );
1338     if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
1339         my $tag = $record->field($tagfield);
1340         if ($tag) {
1341             $tag->update( $tagsubfield => $value );
1342             $record->delete_field($tag);
1343             $record->insert_fields_ordered($tag);
1344         }
1345         else {
1346             $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
1347         }
1348     }
1349     return $record;
1350 }
1351
1352 =head2 TransformHtmlToXml
1353
1354 =over 4
1355
1356 $xml = TransformHtmlToXml( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type )
1357
1358 $auth_type contains :
1359 - nothing : rebuild a biblio, un UNIMARC the encoding is in 100$a pos 26/27
1360 - UNIMARCAUTH : rebuild an authority. In UNIMARC, the encoding is in 100$a pos 13/14
1361 - ITEM : rebuild an item : in UNIMARC, 100$a, it's in the biblio ! (otherwise, we would get 2 100 fields !)
1362
1363 =back
1364
1365 =cut
1366
1367 sub TransformHtmlToXml {
1368     my ( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type ) = @_;
1369     my $xml = MARC::File::XML::header('UTF-8');
1370     $auth_type = C4::Context->preference('marcflavour') unless $auth_type;
1371     MARC::File::XML->default_record_format($auth_type);
1372     # in UNIMARC, field 100 contains the encoding
1373     # check that there is one, otherwise the 
1374     # MARC::Record->new_from_xml will fail (and Koha will die)
1375     my $unimarc_and_100_exist=0;
1376     $unimarc_and_100_exist=1 if $auth_type eq 'ITEM'; # if we rebuild an item, no need of a 100 field
1377     my $prevvalue;
1378     my $prevtag = -1;
1379     my $first   = 1;
1380     my $j       = -1;
1381     for ( my $i = 0 ; $i < @$tags ; $i++ ) {
1382         if (C4::Context->preference('marcflavour') eq 'UNIMARC' and @$tags[$i] eq "100" and @$subfields[$i] eq "a") {
1383             # if we have a 100 field and it's values are not correct, skip them.
1384             # if we don't have any valid 100 field, we will create a default one at the end
1385             my $enc = substr( @$values[$i], 26, 2 );
1386             if ($enc eq '01' or $enc eq '50' or $enc eq '03') {
1387                 $unimarc_and_100_exist=1;
1388             } else {
1389                 next;
1390             }
1391         }
1392         @$values[$i] =~ s/&/&amp;/g;
1393         @$values[$i] =~ s/</&lt;/g;
1394         @$values[$i] =~ s/>/&gt;/g;
1395         @$values[$i] =~ s/"/&quot;/g;
1396         @$values[$i] =~ s/'/&apos;/g;
1397 #         if ( !utf8::is_utf8( @$values[$i] ) ) {
1398 #             utf8::decode( @$values[$i] );
1399 #         }
1400         if ( ( @$tags[$i] ne $prevtag ) ) {
1401             $j++ unless ( @$tags[$i] eq "" );
1402             if ( !$first ) {
1403                 $xml .= "</datafield>\n";
1404                 if (   ( @$tags[$i] && @$tags[$i] > 10 )
1405                     && ( @$values[$i] ne "" ) )
1406                 {
1407                     my $ind1 = substr( @$indicator[$j], 0, 1 );
1408                     my $ind2;
1409                     if ( @$indicator[$j] ) {
1410                         $ind2 = substr( @$indicator[$j], 1, 1 );
1411                     }
1412                     else {
1413                         warn "Indicator in @$tags[$i] is empty";
1414                         $ind2 = " ";
1415                     }
1416                     $xml .=
1417 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1418                     $xml .=
1419 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1420                     $first = 0;
1421                 }
1422                 else {
1423                     $first = 1;
1424                 }
1425             }
1426             else {
1427                 if ( @$values[$i] ne "" ) {
1428
1429                     # leader
1430                     if ( @$tags[$i] eq "000" ) {
1431                         $xml .= "<leader>@$values[$i]</leader>\n";
1432                         $first = 1;
1433
1434                         # rest of the fixed fields
1435                     }
1436                     elsif ( @$tags[$i] < 10 ) {
1437                         $xml .=
1438 "<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
1439                         $first = 1;
1440                     }
1441                     else {
1442                         my $ind1 = substr( @$indicator[$j], 0, 1 );
1443                         my $ind2 = substr( @$indicator[$j], 1, 1 );
1444                         $xml .=
1445 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1446                         $xml .=
1447 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1448                         $first = 0;
1449                     }
1450                 }
1451             }
1452         }
1453         else {    # @$tags[$i] eq $prevtag
1454             if ( @$values[$i] eq "" ) {
1455             }
1456             else {
1457                 if ($first) {
1458                     my $ind1 = substr( @$indicator[$j], 0, 1 );
1459                     my $ind2 = substr( @$indicator[$j], 1, 1 );
1460                     $xml .=
1461 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1462                     $first = 0;
1463                 }
1464                 $xml .=
1465 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1466             }
1467         }
1468         $prevtag = @$tags[$i];
1469     }
1470     $xml .= "</datafield>\n" if @$tags > 0;
1471     if (C4::Context->preference('marcflavour') eq 'UNIMARC' and !$unimarc_and_100_exist) {
1472 #     warn "SETTING 100 for $auth_type";
1473         use POSIX qw(strftime);
1474         my $string = strftime( "%Y%m%d", localtime(time) );
1475         # set 50 to position 26 is biblios, 13 if authorities
1476         my $pos=26;
1477         $pos=13 if $auth_type eq 'UNIMARCAUTH';
1478         $string = sprintf( "%-*s", 35, $string );
1479         substr( $string, $pos , 6, "50" );
1480         $xml .= "<datafield tag=\"100\" ind1=\"\" ind2=\"\">\n";
1481         $xml .= "<subfield code=\"a\">$string</subfield>\n";
1482         $xml .= "</datafield>\n";
1483     }
1484     $xml .= MARC::File::XML::footer();
1485     return $xml;
1486 }
1487
1488 =head2 TransformHtmlToMarc
1489
1490     L<$record> = TransformHtmlToMarc(L<$params>,L<$cgi>)
1491     L<$params> is a ref to an array as below:
1492     {
1493         'tag_010_indicator1_531951' ,
1494         'tag_010_indicator2_531951' ,
1495         'tag_010_code_a_531951_145735' ,
1496         'tag_010_subfield_a_531951_145735' ,
1497         'tag_200_indicator1_873510' ,
1498         'tag_200_indicator2_873510' ,
1499         'tag_200_code_a_873510_673465' ,
1500         'tag_200_subfield_a_873510_673465' ,
1501         'tag_200_code_b_873510_704318' ,
1502         'tag_200_subfield_b_873510_704318' ,
1503         'tag_200_code_e_873510_280822' ,
1504         'tag_200_subfield_e_873510_280822' ,
1505         'tag_200_code_f_873510_110730' ,
1506         'tag_200_subfield_f_873510_110730' ,
1507     }
1508     L<$cgi> is the CGI object which containts the value.
1509     L<$record> is the MARC::Record object.
1510
1511 =cut
1512
1513 sub TransformHtmlToMarc {
1514     my $params = shift;
1515     my $cgi    = shift;
1516
1517     # explicitly turn on the UTF-8 flag for all
1518     # 'tag_' parameters to avoid incorrect character
1519     # conversion later on
1520     my $cgi_params = $cgi->Vars;
1521     foreach my $param_name (keys %$cgi_params) {
1522         if ($param_name =~ /^tag_/) {
1523             my $param_value = $cgi_params->{$param_name};
1524             if (utf8::decode($param_value)) {
1525                 $cgi_params->{$param_name} = $param_value;
1526             } 
1527             # FIXME - need to do something if string is not valid UTF-8
1528         }
1529     }
1530    
1531     # creating a new record
1532     my $record  = MARC::Record->new();
1533     my $i=0;
1534     my @fields;
1535     while ($params->[$i]){ # browse all CGI params
1536         my $param = $params->[$i];
1537         my $newfield=0;
1538         # if we are on biblionumber, store it in the MARC::Record (it may not be in the edited fields)
1539         if ($param eq 'biblionumber') {
1540             my ( $biblionumbertagfield, $biblionumbertagsubfield ) =
1541                 &GetMarcFromKohaField( "biblio.biblionumber", '' );
1542             if ($biblionumbertagfield < 10) {
1543                 $newfield = MARC::Field->new(
1544                     $biblionumbertagfield,
1545                     $cgi->param($param),
1546                 );
1547             } else {
1548                 $newfield = MARC::Field->new(
1549                     $biblionumbertagfield,
1550                     '',
1551                     '',
1552                     "$biblionumbertagsubfield" => $cgi->param($param),
1553                 );
1554             }
1555             push @fields,$newfield if($newfield);
1556         } 
1557         elsif ($param =~ /^tag_(\d*)_indicator1_/){ # new field start when having 'input name="..._indicator1_..."
1558             my $tag  = $1;
1559             
1560             my $ind1 = substr($cgi->param($param),0,1);
1561             my $ind2 = substr($cgi->param($params->[$i+1]),0,1);
1562             $newfield=0;
1563             my $j=$i+2;
1564             
1565             if($tag < 10){ # no code for theses fields
1566     # in MARC editor, 000 contains the leader.
1567                 if ($tag eq '000' ) {
1568                     $record->leader($cgi->param($params->[$j+1])) if length($cgi->param($params->[$j+1]))==24;
1569     # between 001 and 009 (included)
1570                 } elsif ($cgi->param($params->[$j+1]) ne '') {
1571                     $newfield = MARC::Field->new(
1572                         $tag,
1573                         $cgi->param($params->[$j+1]),
1574                     );
1575                 }
1576     # > 009, deal with subfields
1577             } else {
1578                 while(defined $params->[$j] && $params->[$j] =~ /_code_/){ # browse all it's subfield
1579                     my $inner_param = $params->[$j];
1580                     if ($newfield){
1581                         if($cgi->param($params->[$j+1]) ne ''){  # only if there is a value (code => value)
1582                             $newfield->add_subfields(
1583                                 $cgi->param($inner_param) => $cgi->param($params->[$j+1])
1584                             );
1585                         }
1586                     } else {
1587                         if ( $cgi->param($params->[$j+1]) ne '' ) { # creating only if there is a value (code => value)
1588                             $newfield = MARC::Field->new(
1589                                 $tag,
1590                                 ''.$ind1,
1591                                 ''.$ind2,
1592                                 $cgi->param($inner_param) => $cgi->param($params->[$j+1]),
1593                             );
1594                         }
1595                     }
1596                     $j+=2;
1597                 }
1598             }
1599             push @fields,$newfield if($newfield);
1600         }
1601         $i++;
1602     }
1603     
1604     $record->append_fields(@fields);
1605     return $record;
1606 }
1607
1608 # cache inverted MARC field map
1609 our $inverted_field_map;
1610
1611 =head2 TransformMarcToKoha
1612
1613 =over 4
1614
1615     $result = TransformMarcToKoha( $dbh, $record, $frameworkcode )
1616
1617 =back
1618
1619 Extract data from a MARC bib record into a hashref representing
1620 Koha biblio, biblioitems, and items fields. 
1621
1622 =cut
1623 sub TransformMarcToKoha {
1624     my ( $dbh, $record, $frameworkcode, $limit_table ) = @_;
1625
1626     my $result;
1627     $limit_table=$limit_table||0;
1628     $frameworkcode = '' unless defined $frameworkcode;
1629     
1630     unless (defined $inverted_field_map) {
1631         $inverted_field_map = _get_inverted_marc_field_map();
1632     }
1633
1634     my %tables = ();
1635     if ( defined $limit_table && $limit_table eq 'items') {
1636         $tables{'items'} = 1;
1637     } else {
1638         $tables{'items'} = 1;
1639         $tables{'biblio'} = 1;
1640         $tables{'biblioitems'} = 1;
1641     }
1642
1643     # traverse through record
1644     MARCFIELD: foreach my $field ($record->fields()) {
1645         my $tag = $field->tag();
1646         next MARCFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag};
1647         if ($field->is_control_field()) {
1648             my $kohafields = $inverted_field_map->{$frameworkcode}->{$tag}->{list};
1649             ENTRY: foreach my $entry (@{ $kohafields }) {
1650                 my ($subfield, $table, $column) = @{ $entry };
1651                 next ENTRY unless exists $tables{$table};
1652                 my $key = _disambiguate($table, $column);
1653                 if ($result->{$key}) {
1654                     unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($field->data() eq "")) {
1655                         $result->{$key} .= " | " . $field->data();
1656                     }
1657                 } else {
1658                     $result->{$key} = $field->data();
1659                 }
1660             }
1661         } else {
1662             # deal with subfields
1663             MARCSUBFIELD: foreach my $sf ($field->subfields()) {
1664                 my $code = $sf->[0];
1665                 next MARCSUBFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code};
1666                 my $value = $sf->[1];
1667                 SFENTRY: foreach my $entry (@{ $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code} }) {
1668                     my ($table, $column) = @{ $entry };
1669                     next SFENTRY unless exists $tables{$table};
1670                     my $key = _disambiguate($table, $column);
1671                     if ($result->{$key}) {
1672                         unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($value eq "")) {
1673                             $result->{$key} .= " | " . $value;
1674                         }
1675                     } else {
1676                         $result->{$key} = $value;
1677                     }
1678                 }
1679             }
1680         }
1681     }
1682
1683     # modify copyrightdate to keep only the 1st year found
1684     if (exists $result->{'copyrightdate'}) {
1685         my $temp = $result->{'copyrightdate'};
1686         $temp =~ m/c(\d\d\d\d)/;
1687         if ( $temp =~ m/c(\d\d\d\d)/ and $1 > 0 ) { # search cYYYY first
1688             $result->{'copyrightdate'} = $1;
1689         }
1690         else {                      # if no cYYYY, get the 1st date.
1691             $temp =~ m/(\d\d\d\d)/;
1692             $result->{'copyrightdate'} = $1;
1693         }
1694     }
1695
1696     # modify publicationyear to keep only the 1st year found
1697     if (exists $result->{'publicationyear'}) {
1698         my $temp = $result->{'publicationyear'};
1699         if ( $temp =~ m/c(\d\d\d\d)/ and $1 > 0 ) { # search cYYYY first
1700             $result->{'publicationyear'} = $1;
1701         }
1702         else {                      # if no cYYYY, get the 1st date.
1703             $temp =~ m/(\d\d\d\d)/;
1704             $result->{'publicationyear'} = $1;
1705         }
1706     }
1707
1708     return $result;
1709 }
1710
1711 sub _get_inverted_marc_field_map {
1712     my $field_map = {};
1713     my $relations = C4::Context->marcfromkohafield;
1714
1715     foreach my $frameworkcode (keys %{ $relations }) {
1716         foreach my $kohafield (keys %{ $relations->{$frameworkcode} }) {
1717             next unless @{ $relations->{$frameworkcode}->{$kohafield} }; # not all columns are mapped to MARC tag & subfield
1718             my $tag = $relations->{$frameworkcode}->{$kohafield}->[0];
1719             my $subfield = $relations->{$frameworkcode}->{$kohafield}->[1];
1720             my ($table, $column) = split /[.]/, $kohafield, 2;
1721             push @{ $field_map->{$frameworkcode}->{$tag}->{list} }, [ $subfield, $table, $column ];
1722             push @{ $field_map->{$frameworkcode}->{$tag}->{sfs}->{$subfield} }, [ $table, $column ];
1723         }
1724     }
1725     return $field_map;
1726 }
1727
1728 =head2 _disambiguate
1729
1730 =over 4
1731
1732 $newkey = _disambiguate($table, $field);
1733
1734 This is a temporary hack to distinguish between the
1735 following sets of columns when using TransformMarcToKoha.
1736
1737 items.cn_source & biblioitems.cn_source
1738 items.cn_sort & biblioitems.cn_sort
1739
1740 Columns that are currently NOT distinguished (FIXME
1741 due to lack of time to fully test) are:
1742
1743 biblio.notes and biblioitems.notes
1744 biblionumber
1745 timestamp
1746 biblioitemnumber
1747
1748 FIXME - this is necessary because prefixing each column
1749 name with the table name would require changing lots
1750 of code and templates, and exposing more of the DB
1751 structure than is good to the UI templates, particularly
1752 since biblio and bibloitems may well merge in a future
1753 version.  In the future, it would also be good to 
1754 separate DB access and UI presentation field names
1755 more.
1756
1757 =back
1758
1759 =cut
1760
1761 sub _disambiguate {
1762     my ($table, $column) = @_;
1763     if ($column eq "cn_sort" or $column eq "cn_source") {
1764         return $table . '.' . $column;
1765     } else {
1766         return $column;
1767     }
1768
1769 }
1770
1771 =head2 get_koha_field_from_marc
1772
1773 =over 4
1774
1775 $result->{_disambiguate($table, $field)} = get_koha_field_from_marc($table,$field,$record,$frameworkcode);
1776
1777 Internal function to map data from the MARC record to a specific non-MARC field.
1778 FIXME: this is meant to replace TransformMarcToKohaOneField after more testing.
1779
1780 =back
1781
1782 =cut
1783
1784 sub get_koha_field_from_marc {
1785     my ($koha_table,$koha_column,$record,$frameworkcode) = @_;
1786     my ( $tagfield, $subfield ) = GetMarcFromKohaField( $koha_table.'.'.$koha_column, $frameworkcode );  
1787     my $kohafield;
1788     foreach my $field ( $record->field($tagfield) ) {
1789         if ( $field->tag() < 10 ) {
1790             if ( $kohafield ) {
1791                 $kohafield .= " | " . $field->data();
1792             }
1793             else {
1794                 $kohafield = $field->data();
1795             }
1796         }
1797         else {
1798             if ( $field->subfields ) {
1799                 my @subfields = $field->subfields();
1800                 foreach my $subfieldcount ( 0 .. $#subfields ) {
1801                     if ( $subfields[$subfieldcount][0] eq $subfield ) {
1802                         if ( $kohafield ) {
1803                             $kohafield .=
1804                               " | " . $subfields[$subfieldcount][1];
1805                         }
1806                         else {
1807                             $kohafield =
1808                               $subfields[$subfieldcount][1];
1809                         }
1810                     }
1811                 }
1812             }
1813         }
1814     }
1815     return $kohafield;
1816
1817
1818
1819 =head2 TransformMarcToKohaOneField
1820
1821 =over 4
1822
1823 $result = TransformMarcToKohaOneField( $kohatable, $kohafield, $record, $result, $frameworkcode )
1824
1825 =back
1826
1827 =cut
1828
1829 sub TransformMarcToKohaOneField {
1830
1831     # FIXME ? if a field has a repeatable subfield that is used in old-db,
1832     # only the 1st will be retrieved...
1833     my ( $kohatable, $kohafield, $record, $result, $frameworkcode ) = @_;
1834     my $res = "";
1835     my ( $tagfield, $subfield ) =
1836       GetMarcFromKohaField( $kohatable . "." . $kohafield,
1837         $frameworkcode );
1838     foreach my $field ( $record->field($tagfield) ) {
1839         if ( $field->tag() < 10 ) {
1840             if ( $result->{$kohafield} ) {
1841                 $result->{$kohafield} .= " | " . $field->data();
1842             }
1843             else {
1844                 $result->{$kohafield} = $field->data();
1845             }
1846         }
1847         else {
1848             if ( $field->subfields ) {
1849                 my @subfields = $field->subfields();
1850                 foreach my $subfieldcount ( 0 .. $#subfields ) {
1851                     if ( $subfields[$subfieldcount][0] eq $subfield ) {
1852                         if ( $result->{$kohafield} ) {
1853                             $result->{$kohafield} .=
1854                               " | " . $subfields[$subfieldcount][1];
1855                         }
1856                         else {
1857                             $result->{$kohafield} =
1858                               $subfields[$subfieldcount][1];
1859                         }
1860                     }
1861                 }
1862             }
1863         }
1864     }
1865     return $result;
1866 }
1867
1868 =head1  OTHER FUNCTIONS
1869
1870
1871 =head2 PrepareItemrecordDisplay
1872
1873 =over 4
1874
1875 PrepareItemrecordDisplay($itemrecord,$bibnum,$itemumber);
1876
1877 Returns a hash with all the fields for Display a given item data in a template
1878
1879 =back
1880
1881 =cut
1882
1883 sub PrepareItemrecordDisplay {
1884
1885     my ( $bibnum, $itemnum, $defaultvalues ) = @_;
1886
1887     my $dbh = C4::Context->dbh;
1888     my $frameworkcode = &GetFrameworkCode( $bibnum );
1889     my ( $itemtagfield, $itemtagsubfield ) =
1890       &GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
1891     my $tagslib = &GetMarcStructure( 1, $frameworkcode );
1892     my $itemrecord = C4::Items::GetMarcItem( $bibnum, $itemnum) if ($itemnum);
1893     my @loop_data;
1894     my $authorised_values_sth =
1895       $dbh->prepare(
1896 "SELECT authorised_value,lib FROM authorised_values WHERE category=? ORDER BY lib"
1897       );
1898     foreach my $tag ( sort keys %{$tagslib} ) {
1899         my $previous_tag = '';
1900         if ( $tag ne '' ) {
1901             # loop through each subfield
1902             my $cntsubf;
1903             foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
1904                 next if ( subfield_is_koha_internal_p($subfield) );
1905                 next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
1906                 my %subfield_data;
1907                 $subfield_data{tag}           = $tag;
1908                 $subfield_data{subfield}      = $subfield;
1909                 $subfield_data{countsubfield} = $cntsubf++;
1910                 $subfield_data{kohafield}     =
1911                   $tagslib->{$tag}->{$subfield}->{'kohafield'};
1912
1913          #        $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
1914                 $subfield_data{marc_lib} = $tagslib->{$tag}->{$subfield}->{lib};
1915                 $subfield_data{mandatory} =
1916                   $tagslib->{$tag}->{$subfield}->{mandatory};
1917                 $subfield_data{repeatable} =
1918                   $tagslib->{$tag}->{$subfield}->{repeatable};
1919                 $subfield_data{hidden} = "display:none"
1920                   if $tagslib->{$tag}->{$subfield}->{hidden};
1921                 my ( $x, $value );
1922                 ( $x, $value ) = _find_value( $tag, $subfield, $itemrecord )
1923                   if ($itemrecord);
1924                 $value =~ s/"/&quot;/g;
1925
1926                 # search for itemcallnumber if applicable
1927                 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
1928                     'items.itemcallnumber'
1929                     && C4::Context->preference('itemcallnumber') )
1930                 {
1931                     my $CNtag =
1932                       substr( C4::Context->preference('itemcallnumber'), 0, 3 );
1933                     my $CNsubfield =
1934                       substr( C4::Context->preference('itemcallnumber'), 3, 1 );
1935                     my $temp = $itemrecord->field($CNtag) if ($itemrecord);
1936                     if ($temp) {
1937                         $value = $temp->subfield($CNsubfield);
1938                     }
1939                 }
1940                 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
1941                     'items.itemcallnumber'
1942                     && $defaultvalues->{'callnumber'} )
1943                 {
1944                     my $temp = $itemrecord->field($subfield) if ($itemrecord);
1945                     unless ($temp) {
1946                         $value = $defaultvalues->{'callnumber'};
1947                     }
1948                 }
1949                 if ( ($tagslib->{$tag}->{$subfield}->{kohafield} eq
1950                     'items.holdingbranch' ||
1951                     $tagslib->{$tag}->{$subfield}->{kohafield} eq
1952                     'items.homebranch')          
1953                     && $defaultvalues->{'branchcode'} )
1954                 {
1955                     my $temp = $itemrecord->field($subfield) if ($itemrecord);
1956                     unless ($temp) {
1957                         $value = $defaultvalues->{branchcode};
1958                     }
1959                 }
1960                 if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
1961                     my @authorised_values;
1962                     my %authorised_lib;
1963
1964                     # builds list, depending on authorised value...
1965                     #---- branch
1966                     if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq
1967                         "branches" )
1968                     {
1969                         if ( ( C4::Context->preference("IndependantBranches") )
1970                             && ( C4::Context->userenv->{flags} != 1 ) )
1971                         {
1972                             my $sth =
1973                               $dbh->prepare(
1974                                 "SELECT branchcode,branchname FROM branches WHERE branchcode = ? ORDER BY branchname"
1975                               );
1976                             $sth->execute( C4::Context->userenv->{branch} );
1977                             push @authorised_values, ""
1978                               unless (
1979                                 $tagslib->{$tag}->{$subfield}->{mandatory} );
1980                             while ( my ( $branchcode, $branchname ) =
1981                                 $sth->fetchrow_array )
1982                             {
1983                                 push @authorised_values, $branchcode;
1984                                 $authorised_lib{$branchcode} = $branchname;
1985                             }
1986                         }
1987                         else {
1988                             my $sth =
1989                               $dbh->prepare(
1990                                 "SELECT branchcode,branchname FROM branches ORDER BY branchname"
1991                               );
1992                             $sth->execute;
1993                             push @authorised_values, ""
1994                               unless (
1995                                 $tagslib->{$tag}->{$subfield}->{mandatory} );
1996                             while ( my ( $branchcode, $branchname ) =
1997                                 $sth->fetchrow_array )
1998                             {
1999                                 push @authorised_values, $branchcode;
2000                                 $authorised_lib{$branchcode} = $branchname;
2001                             }
2002                         }
2003
2004                         #----- itemtypes
2005                     }
2006                     elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq
2007                         "itemtypes" )
2008                     {
2009                         my $sth =
2010                           $dbh->prepare(
2011                             "SELECT itemtype,description FROM itemtypes ORDER BY description"
2012                           );
2013                         $sth->execute;
2014                         push @authorised_values, ""
2015                           unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2016                         while ( my ( $itemtype, $description ) =
2017                             $sth->fetchrow_array )
2018                         {
2019                             push @authorised_values, $itemtype;
2020                             $authorised_lib{$itemtype} = $description;
2021                         }
2022
2023                         #---- "true" authorised value
2024                     }
2025                     else {
2026                         $authorised_values_sth->execute(
2027                             $tagslib->{$tag}->{$subfield}->{authorised_value} );
2028                         push @authorised_values, ""
2029                           unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2030                         while ( my ( $value, $lib ) =
2031                             $authorised_values_sth->fetchrow_array )
2032                         {
2033                             push @authorised_values, $value;
2034                             $authorised_lib{$value} = $lib;
2035                         }
2036                     }
2037                     $subfield_data{marc_value} = CGI::scrolling_list(
2038                         -name     => 'field_value',
2039                         -values   => \@authorised_values,
2040                         -default  => "$value",
2041                         -labels   => \%authorised_lib,
2042                         -size     => 1,
2043                         -tabindex => '',
2044                         -multiple => 0,
2045                     );
2046                 }
2047                 elsif ( $tagslib->{$tag}->{$subfield}->{thesaurus_category} ) {
2048                     $subfield_data{marc_value} =
2049 "<input type=\"text\" name=\"field_value\"  size=\"47\" maxlength=\"255\" /> <a href=\"javascript:Dopop('cataloguing/thesaurus_popup.pl?category=$tagslib->{$tag}->{$subfield}->{thesaurus_category}&index=',)\">...</a>";
2050
2051 #"
2052 # COMMENTED OUT because No $i is provided with this API.
2053 # And thus, no value_builder can be activated.
2054 # BUT could be thought over.
2055 #         } elsif ($tagslib->{$tag}->{$subfield}->{'value_builder'}) {
2056 #             my $plugin="value_builder/".$tagslib->{$tag}->{$subfield}->{'value_builder'};
2057 #             require $plugin;
2058 #             my $extended_param = plugin_parameters($dbh,$itemrecord,$tagslib,$i,0);
2059 #             my ($function_name,$javascript) = plugin_javascript($dbh,$record,$tagslib,$i,0);
2060 #             $subfield_data{marc_value}="<input type=\"text\" value=\"$value\" name=\"field_value\"  size=47 maxlength=255 DISABLE READONLY OnFocus=\"javascript:Focus$function_name()\" OnBlur=\"javascript:Blur$function_name()\"> <a href=\"javascript:Clic$function_name()\">...</a> $javascript";
2061                 }
2062                 else {
2063                     $subfield_data{marc_value} =
2064 "<input type=\"text\" name=\"field_value\" value=\"$value\" size=\"50\" maxlength=\"255\" />";
2065                 }
2066                 push( @loop_data, \%subfield_data );
2067             }
2068         }
2069     }
2070     my $itemnumber = $itemrecord->subfield( $itemtagfield, $itemtagsubfield )
2071       if ( $itemrecord && $itemrecord->field($itemtagfield) );
2072     return {
2073         'itemtagfield'    => $itemtagfield,
2074         'itemtagsubfield' => $itemtagsubfield,
2075         'itemnumber'      => $itemnumber,
2076         'iteminformation' => \@loop_data
2077     };
2078 }
2079 #"
2080
2081 #
2082 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2083 # at the same time
2084 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2085 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2086 # =head2 ModZebrafiles
2087
2088 # &ModZebrafiles( $dbh, $biblionumber, $record, $folder, $server );
2089
2090 # =cut
2091
2092 # sub ModZebrafiles {
2093
2094 #     my ( $dbh, $biblionumber, $record, $folder, $server ) = @_;
2095
2096 #     my $op;
2097 #     my $zebradir =
2098 #       C4::Context->zebraconfig($server)->{directory} . "/" . $folder . "/";
2099 #     unless ( opendir( DIR, "$zebradir" ) ) {
2100 #         warn "$zebradir not found";
2101 #         return;
2102 #     }
2103 #     closedir DIR;
2104 #     my $filename = $zebradir . $biblionumber;
2105
2106 #     if ($record) {
2107 #         open( OUTPUT, ">", $filename . ".xml" );
2108 #         print OUTPUT $record;
2109 #         close OUTPUT;
2110 #     }
2111 # }
2112
2113 =head2 ModZebra
2114
2115 =over 4
2116
2117 ModZebra( $biblionumber, $op, $server, $oldRecord, $newRecord );
2118
2119     $biblionumber is the biblionumber we want to index
2120     $op is specialUpdate or delete, and is used to know what we want to do
2121     $server is the server that we want to update
2122     $oldRecord is the MARC::Record containing the previous version of the record.  This is used only when 
2123       NoZebra=1, as NoZebra indexing needs to know the previous version of a record in order to
2124       do an update.
2125     $newRecord is the MARC::Record containing the new record. It is usefull only when NoZebra=1, and is used to know what to add to the nozebra database. (the record in mySQL being, if it exist, the previous record, the one just before the modif. We need both : the previous and the new one.
2126     
2127 =back
2128
2129 =cut
2130
2131 sub ModZebra {
2132 ###Accepts a $server variable thus we can use it for biblios authorities or other zebra dbs
2133     my ( $biblionumber, $op, $server, $oldRecord, $newRecord ) = @_;
2134     my $dbh=C4::Context->dbh;
2135
2136     # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2137     # at the same time
2138     # replaced by a zebraqueue table, that is filled with ModZebra to run.
2139     # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2140
2141     if (C4::Context->preference("NoZebra")) {
2142         # lock the nozebra table : we will read index lines, update them in Perl process
2143         # and write everything in 1 transaction.
2144         # lock the table to avoid someone else overwriting what we are doing
2145         $dbh->do('LOCK TABLES nozebra WRITE,biblio WRITE,biblioitems WRITE, systempreferences WRITE, auth_types WRITE, auth_header WRITE, auth_subfield_structure READ');
2146         my %result; # the result hash that will be built by deletion / add, and written on mySQL at the end, to improve speed
2147         if ($op eq 'specialUpdate') {
2148             # OK, we have to add or update the record
2149             # 1st delete (virtually, in indexes), if record actually exists
2150             if ($oldRecord) { 
2151                 %result = _DelBiblioNoZebra($biblionumber,$oldRecord,$server);
2152             }
2153             # ... add the record
2154             %result=_AddBiblioNoZebra($biblionumber,$newRecord, $server, %result);
2155         } else {
2156             # it's a deletion, delete the record...
2157             # warn "DELETE the record $biblionumber on $server".$record->as_formatted;
2158             %result=_DelBiblioNoZebra($biblionumber,$oldRecord,$server);
2159         }
2160         # ok, now update the database...
2161         my $sth = $dbh->prepare("UPDATE nozebra SET biblionumbers=? WHERE server=? AND indexname=? AND value=?");
2162         foreach my $key (keys %result) {
2163             foreach my $index (keys %{$result{$key}}) {
2164                 $sth->execute($result{$key}->{$index}, $server, $key, $index);
2165             }
2166         }
2167         $dbh->do('UNLOCK TABLES');
2168     } else {
2169         #
2170         # we use zebra, just fill zebraqueue table
2171         #
2172         my $check_sql = "SELECT COUNT(*) FROM zebraqueue 
2173                          WHERE server = ?
2174                          AND   biblio_auth_number = ?
2175                          AND   operation = ?
2176                          AND   done = 0";
2177         my $check_sth = $dbh->prepare_cached($check_sql);
2178         $check_sth->execute($server, $biblionumber, $op);
2179         my ($count) = $check_sth->fetchrow_array;
2180         $check_sth->finish();
2181         if ($count == 0) {
2182             my $sth=$dbh->prepare("INSERT INTO zebraqueue  (biblio_auth_number,server,operation) VALUES(?,?,?)");
2183             $sth->execute($biblionumber,$server,$op);
2184             $sth->finish;
2185         }
2186     }
2187 }
2188
2189 =head2 GetNoZebraIndexes
2190
2191     %indexes = GetNoZebraIndexes;
2192     
2193     return the data from NoZebraIndexes syspref.
2194
2195 =cut
2196
2197 sub GetNoZebraIndexes {
2198     my $no_zebra_indexes = C4::Context->preference('NoZebraIndexes');
2199     my %indexes;
2200     INDEX: foreach my $line (split /['"],[\n\r]*/,$no_zebra_indexes) {
2201         $line =~ /(.*)=>(.*)/;
2202         my $index = $1; # initial ' or " is removed afterwards
2203         my $fields = $2;
2204         $index =~ s/'|"|\s//g;
2205         $fields =~ s/'|"|\s//g;
2206         $indexes{$index}=$fields;
2207     }
2208     return %indexes;
2209 }
2210
2211 =head1 INTERNAL FUNCTIONS
2212
2213 =head2 _DelBiblioNoZebra($biblionumber,$record,$server);
2214
2215     function to delete a biblio in NoZebra indexes
2216     This function does NOT delete anything in database : it reads all the indexes entries
2217     that have to be deleted & delete them in the hash
2218     The SQL part is done either :
2219     - after the Add if we are modifying a biblio (delete + add again)
2220     - immediatly after this sub if we are doing a true deletion.
2221     $server can be 'biblioserver' or 'authorityserver' : it indexes biblios or authorities (in the same table, $server being part of the table itself
2222
2223 =cut
2224
2225
2226 sub _DelBiblioNoZebra {
2227     my ($biblionumber, $record, $server)=@_;
2228     
2229     # Get the indexes
2230     my $dbh = C4::Context->dbh;
2231     # Get the indexes
2232     my %index;
2233     my $title;
2234     if ($server eq 'biblioserver') {
2235         %index=GetNoZebraIndexes;
2236         # get title of the record (to store the 10 first letters with the index)
2237         my ($titletag,$titlesubfield) = GetMarcFromKohaField('biblio.title');
2238         $title = lc($record->subfield($titletag,$titlesubfield));
2239     } else {
2240         # for authorities, the "title" is the $a mainentry
2241         my ($auth_type_tag, $auth_type_sf) = C4::AuthoritiesMarc::get_auth_type_location();
2242         my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield($auth_type_tag, $auth_type_sf));
2243         warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
2244         $title = $record->subfield($authref->{auth_tag_to_report},'a');
2245         $index{'mainmainentry'}= $authref->{'auth_tag_to_report'}.'a';
2246         $index{'mainentry'}    = $authref->{'auth_tag_to_report'}.'*';
2247         $index{'auth_type'}    = "${auth_type_tag}${auth_type_sf}";
2248     }
2249     
2250     my %result;
2251     # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
2252     $title =~ s/ |,|;|\[|\]|\(|\)|\*|-|'|=//g;
2253     # limit to 10 char, should be enough, and limit the DB size
2254     $title = substr($title,0,10);
2255     #parse each field
2256     my $sth2=$dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
2257     foreach my $field ($record->fields()) {
2258         #parse each subfield
2259         next if $field->tag <10;
2260         foreach my $subfield ($field->subfields()) {
2261             my $tag = $field->tag();
2262             my $subfieldcode = $subfield->[0];
2263             my $indexed=0;
2264             # check each index to see if the subfield is stored somewhere
2265             # otherwise, store it in __RAW__ index
2266             foreach my $key (keys %index) {
2267 #                 warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
2268                 if ($index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/) {
2269                     $indexed=1;
2270                     my $line= lc $subfield->[1];
2271                     # remove meaningless value in the field...
2272                     $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
2273                     # ... and split in words
2274                     foreach (split / /,$line) {
2275                         next unless $_; # skip  empty values (multiple spaces)
2276                         # if the entry is already here, do nothing, the biblionumber has already be removed
2277                         unless ( defined( $result{$key}->{$_} ) && ( $result{$key}->{$_} =~ /$biblionumber,$title\-(\d);/) ) {
2278                             # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
2279                             $sth2->execute($server,$key,$_);
2280                             my $existing_biblionumbers = $sth2->fetchrow;
2281                             # it exists
2282                             if ($existing_biblionumbers) {
2283 #                                 warn " existing for $key $_: $existing_biblionumbers";
2284                                 $result{$key}->{$_} =$existing_biblionumbers;
2285                                 $result{$key}->{$_} =~ s/$biblionumber,$title\-(\d);//;
2286                             }
2287                         }
2288                     }
2289                 }
2290             }
2291             # the subfield is not indexed, store it in __RAW__ index anyway
2292             unless ($indexed) {
2293                 my $line= lc $subfield->[1];
2294                 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
2295                 # ... and split in words
2296                 foreach (split / /,$line) {
2297                     next unless $_; # skip  empty values (multiple spaces)
2298                     # if the entry is already here, do nothing, the biblionumber has already be removed
2299                     unless ($result{'__RAW__'}->{$_} =~ /$biblionumber,$title\-(\d);/) {
2300                         # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
2301                         $sth2->execute($server,'__RAW__',$_);
2302                         my $existing_biblionumbers = $sth2->fetchrow;
2303                         # it exists
2304                         if ($existing_biblionumbers) {
2305                             $result{'__RAW__'}->{$_} =$existing_biblionumbers;
2306                             $result{'__RAW__'}->{$_} =~ s/$biblionumber,$title\-(\d);//;
2307                         }
2308                     }
2309                 }
2310             }
2311         }
2312     }
2313     return %result;
2314 }
2315
2316 =head2 _AddBiblioNoZebra($biblionumber, $record, $server, %result);
2317
2318     function to add a biblio in NoZebra indexes
2319
2320 =cut
2321
2322 sub _AddBiblioNoZebra {
2323     my ($biblionumber, $record, $server, %result)=@_;
2324     my $dbh = C4::Context->dbh;
2325     # Get the indexes
2326     my %index;
2327     my $title;
2328     if ($server eq 'biblioserver') {
2329         %index=GetNoZebraIndexes;
2330         # get title of the record (to store the 10 first letters with the index)
2331         my ($titletag,$titlesubfield) = GetMarcFromKohaField('biblio.title');
2332         $title = lc($record->subfield($titletag,$titlesubfield));
2333     } else {
2334         # warn "server : $server";
2335         # for authorities, the "title" is the $a mainentry
2336         my ($auth_type_tag, $auth_type_sf) = C4::AuthoritiesMarc::get_auth_type_location();
2337         my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield($auth_type_tag, $auth_type_sf));
2338         warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
2339         $title = $record->subfield($authref->{auth_tag_to_report},'a');
2340         $index{'mainmainentry'} = $authref->{auth_tag_to_report}.'a';
2341         $index{'mainentry'}     = $authref->{auth_tag_to_report}.'*';
2342         $index{'auth_type'}    = "${auth_type_tag}${auth_type_sf}";
2343     }
2344
2345     # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
2346     $title =~ s/ |\.|,|;|\[|\]|\(|\)|\*|-|'|:|=|\r|\n//g;
2347     # limit to 10 char, should be enough, and limit the DB size
2348     $title = substr($title,0,10);
2349     #parse each field
2350     my $sth2=$dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
2351     foreach my $field ($record->fields()) {
2352         #parse each subfield
2353         ###FIXME: impossible to index a 001-009 value with NoZebra
2354         next if $field->tag <10;
2355         foreach my $subfield ($field->subfields()) {
2356             my $tag = $field->tag();
2357             my $subfieldcode = $subfield->[0];
2358             my $indexed=0;
2359 #             warn "INDEXING :".$subfield->[1];
2360             # check each index to see if the subfield is stored somewhere
2361             # otherwise, store it in __RAW__ index
2362             foreach my $key (keys %index) {
2363 #                 warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
2364                 if ($index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/) {
2365                     $indexed=1;
2366                     my $line= lc $subfield->[1];
2367                     # remove meaningless value in the field...
2368                     $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:|\r|\n/ /g;
2369                     # ... and split in words
2370                     foreach (split / /,$line) {
2371                         next unless $_; # skip  empty values (multiple spaces)
2372                         # if the entry is already here, improve weight
2373 #                         warn "managing $_";
2374                         if ( exists $result{$key}->{$_} && $result{$key}->{"$_"} =~ /$biblionumber,\Q$title\E\-(\d+);/) {
2375                             my $weight = $1 + 1;
2376                             $result{$key}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//g;
2377                             $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
2378                         } else {
2379                             # get the value if it exist in the nozebra table, otherwise, create it
2380                             $sth2->execute($server,$key,$_);
2381                             my $existing_biblionumbers = $sth2->fetchrow;
2382                             # it exists
2383                             if ($existing_biblionumbers) {
2384                                 $result{$key}->{"$_"} =$existing_biblionumbers;
2385                                 my $weight = defined $1 ? $1 + 1 : 1;
2386                                 $result{$key}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//g;
2387                                 $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
2388                             # create a new ligne for this entry
2389                             } else {
2390 #                             warn "INSERT : $server / $key / $_";
2391                                 $dbh->do('INSERT INTO nozebra SET server='.$dbh->quote($server).', indexname='.$dbh->quote($key).',value='.$dbh->quote($_));
2392                                 $result{$key}->{"$_"}.="$biblionumber,$title-1;";
2393                             }
2394                         }
2395                     }
2396                 }
2397             }
2398             # the subfield is not indexed, store it in __RAW__ index anyway
2399             unless ($indexed) {
2400                 my $line= lc $subfield->[1];
2401                 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:|\r|\n/ /g;
2402                 # ... and split in words
2403                 foreach (split / /,$line) {
2404                     next unless $_; # skip  empty values (multiple spaces)
2405                     # if the entry is already here, improve weight
2406                     if ($result{'__RAW__'}->{"$_"} =~ /$biblionumber,\Q$title\E\-(\d+);/) { 
2407                         my $weight=$1+1;
2408                         $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//;
2409                         $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
2410                     } else {
2411                         # get the value if it exist in the nozebra table, otherwise, create it
2412                         $sth2->execute($server,'__RAW__',$_);
2413                         my $existing_biblionumbers = $sth2->fetchrow;
2414                         # it exists
2415                         if ($existing_biblionumbers) {
2416                             $result{'__RAW__'}->{"$_"} =$existing_biblionumbers;
2417                             my $weight=$1+1;
2418                             $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//;
2419                             $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
2420                         # create a new ligne for this entry
2421                         } else {
2422                             $dbh->do('INSERT INTO nozebra SET server='.$dbh->quote($server).',  indexname="__RAW__",value='.$dbh->quote($_));
2423                             $result{'__RAW__'}->{"$_"}.="$biblionumber,$title-1;";
2424                         }
2425                     }
2426                 }
2427             }
2428         }
2429     }
2430     return %result;
2431 }
2432
2433
2434 =head2 _find_value
2435
2436 =over 4
2437
2438 ($indicators, $value) = _find_value($tag, $subfield, $record,$encoding);
2439
2440 Find the given $subfield in the given $tag in the given
2441 MARC::Record $record.  If the subfield is found, returns
2442 the (indicators, value) pair; otherwise, (undef, undef) is
2443 returned.
2444
2445 PROPOSITION :
2446 Such a function is used in addbiblio AND additem and serial-edit and maybe could be used in Authorities.
2447 I suggest we export it from this module.
2448
2449 =back
2450
2451 =cut
2452
2453 sub _find_value {
2454     my ( $tagfield, $insubfield, $record, $encoding ) = @_;
2455     my @result;
2456     my $indicator;
2457     if ( $tagfield < 10 ) {
2458         if ( $record->field($tagfield) ) {
2459             push @result, $record->field($tagfield)->data();
2460         }
2461         else {
2462             push @result, "";
2463         }
2464     }
2465     else {
2466         foreach my $field ( $record->field($tagfield) ) {
2467             my @subfields = $field->subfields();
2468             foreach my $subfield (@subfields) {
2469                 if ( @$subfield[0] eq $insubfield ) {
2470                     push @result, @$subfield[1];
2471                     $indicator = $field->indicator(1) . $field->indicator(2);
2472                 }
2473             }
2474         }
2475     }
2476     return ( $indicator, @result );
2477 }
2478
2479 =head2 _koha_marc_update_bib_ids
2480
2481 =over 4
2482
2483 _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
2484
2485 Internal function to add or update biblionumber and biblioitemnumber to
2486 the MARC XML.
2487
2488 =back
2489
2490 =cut
2491
2492 sub _koha_marc_update_bib_ids {
2493     my ($record, $frameworkcode, $biblionumber, $biblioitemnumber) = @_;
2494
2495     # we must add bibnum and bibitemnum in MARC::Record...
2496     # we build the new field with biblionumber and biblioitemnumber
2497     # we drop the original field
2498     # we add the new builded field.
2499     my ($biblio_tag, $biblio_subfield ) = GetMarcFromKohaField("biblio.biblionumber",$frameworkcode);
2500     my ($biblioitem_tag, $biblioitem_subfield ) = GetMarcFromKohaField("biblioitems.biblioitemnumber",$frameworkcode);
2501
2502     if ($biblio_tag != $biblioitem_tag) {
2503         # biblionumber & biblioitemnumber are in different fields
2504
2505         # deal with biblionumber
2506         my ($new_field, $old_field);
2507         if ($biblio_tag < 10) {
2508             $new_field = MARC::Field->new( $biblio_tag, $biblionumber );
2509         } else {
2510             $new_field =
2511               MARC::Field->new( $biblio_tag, '', '',
2512                 "$biblio_subfield" => $biblionumber );
2513         }
2514
2515         # drop old field and create new one...
2516         $old_field = $record->field($biblio_tag);
2517         $record->delete_field($old_field) if $old_field;
2518         $record->append_fields($new_field);
2519
2520         # deal with biblioitemnumber
2521         if ($biblioitem_tag < 10) {
2522             $new_field = MARC::Field->new( $biblioitem_tag, $biblioitemnumber, );
2523         } else {
2524             $new_field =
2525               MARC::Field->new( $biblioitem_tag, '', '',
2526                 "$biblioitem_subfield" => $biblioitemnumber, );
2527         }
2528         # drop old field and create new one...
2529         $old_field = $record->field($biblioitem_tag);
2530         $record->delete_field($old_field) if $old_field;
2531         $record->insert_fields_ordered($new_field);
2532
2533     } else {
2534         # biblionumber & biblioitemnumber are in the same field (can't be <10 as fields <10 have only 1 value)
2535         my $new_field = MARC::Field->new(
2536             $biblio_tag, '', '',
2537             "$biblio_subfield" => $biblionumber,
2538             "$biblioitem_subfield" => $biblioitemnumber
2539         );
2540
2541         # drop old field and create new one...
2542         my $old_field = $record->field($biblio_tag);
2543         $record->delete_field($old_field) if $old_field;
2544         $record->insert_fields_ordered($new_field);
2545     }
2546 }
2547
2548 =head2 _koha_marc_update_biblioitem_cn_sort
2549
2550 =over 4
2551
2552 _koha_marc_update_biblioitem_cn_sort($marc, $biblioitem, $frameworkcode);
2553
2554 =back
2555
2556 Given a MARC bib record and the biblioitem hash, update the
2557 subfield that contains a copy of the value of biblioitems.cn_sort.
2558
2559 =cut
2560
2561 sub _koha_marc_update_biblioitem_cn_sort {
2562     my $marc = shift;
2563     my $biblioitem = shift;
2564     my $frameworkcode= shift;
2565
2566     my ($biblioitem_tag, $biblioitem_subfield ) = GetMarcFromKohaField("biblioitems.cn_sort",$frameworkcode);
2567     return unless $biblioitem_tag;
2568
2569     my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
2570
2571     if (my $field = $marc->field($biblioitem_tag)) {
2572         $field->delete_subfield(code => $biblioitem_subfield);
2573         if ($cn_sort ne '') {
2574             $field->add_subfields($biblioitem_subfield => $cn_sort);
2575         }
2576     } else {
2577         # if we get here, no biblioitem tag is present in the MARC record, so
2578         # we'll create it if $cn_sort is not empty -- this would be
2579         # an odd combination of events, however
2580         if ($cn_sort) {
2581             $marc->insert_grouped_field(MARC::Field->new($biblioitem_tag, ' ', ' ', $biblioitem_subfield => $cn_sort));
2582         }
2583     }
2584 }
2585
2586 =head2 _koha_add_biblio
2587
2588 =over 4
2589
2590 my ($biblionumber,$error) = _koha_add_biblio($dbh,$biblioitem);
2591
2592 Internal function to add a biblio ($biblio is a hash with the values)
2593
2594 =back
2595
2596 =cut
2597
2598 sub _koha_add_biblio {
2599     my ( $dbh, $biblio, $frameworkcode ) = @_;
2600
2601     my $error;
2602
2603     # set the series flag
2604     my $serial = 0;
2605     if ( $biblio->{'seriestitle'} ) { $serial = 1 };
2606
2607     my $query = 
2608         "INSERT INTO biblio
2609         SET frameworkcode = ?,
2610             author = ?,
2611             title = ?,
2612             unititle =?,
2613             notes = ?,
2614             serial = ?,
2615             seriestitle = ?,
2616             copyrightdate = ?,
2617             datecreated=NOW(),
2618             abstract = ?
2619         ";
2620     my $sth = $dbh->prepare($query);
2621     $sth->execute(
2622         $frameworkcode,
2623         $biblio->{'author'},
2624         $biblio->{'title'},
2625         $biblio->{'unititle'},
2626         $biblio->{'notes'},
2627         $serial,
2628         $biblio->{'seriestitle'},
2629         $biblio->{'copyrightdate'},
2630         $biblio->{'abstract'}
2631     );
2632
2633     my $biblionumber = $dbh->{'mysql_insertid'};
2634     if ( $dbh->errstr ) {
2635         $error.="ERROR in _koha_add_biblio $query".$dbh->errstr;
2636         warn $error;
2637     }
2638
2639     $sth->finish();
2640     #warn "LEAVING _koha_add_biblio: ".$biblionumber."\n";
2641     return ($biblionumber,$error);
2642 }
2643
2644 =head2 _koha_modify_biblio
2645
2646 =over 4
2647
2648 my ($biblionumber,$error) == _koha_modify_biblio($dbh,$biblio,$frameworkcode);
2649
2650 Internal function for updating the biblio table
2651
2652 =back
2653
2654 =cut
2655
2656 sub _koha_modify_biblio {
2657     my ( $dbh, $biblio, $frameworkcode ) = @_;
2658     my $error;
2659
2660     my $query = "
2661         UPDATE biblio
2662         SET    frameworkcode = ?,
2663                author = ?,
2664                title = ?,
2665                unititle = ?,
2666                notes = ?,
2667                serial = ?,
2668                seriestitle = ?,
2669                copyrightdate = ?,
2670                abstract = ?
2671         WHERE  biblionumber = ?
2672         "
2673     ;
2674     my $sth = $dbh->prepare($query);
2675     
2676     $sth->execute(
2677         $frameworkcode,
2678         $biblio->{'author'},
2679         $biblio->{'title'},
2680         $biblio->{'unititle'},
2681         $biblio->{'notes'},
2682         $biblio->{'serial'},
2683         $biblio->{'seriestitle'},
2684         $biblio->{'copyrightdate'},
2685         $biblio->{'abstract'},
2686         $biblio->{'biblionumber'}
2687     ) if $biblio->{'biblionumber'};
2688
2689     if ( $dbh->errstr || !$biblio->{'biblionumber'} ) {
2690         $error.="ERROR in _koha_modify_biblio $query".$dbh->errstr;
2691         warn $error;
2692     }
2693     return ( $biblio->{'biblionumber'},$error );
2694 }
2695
2696 =head2 _koha_modify_biblioitem_nonmarc
2697
2698 =over 4
2699
2700 my ($biblioitemnumber,$error) = _koha_modify_biblioitem_nonmarc( $dbh, $biblioitem );
2701
2702 Updates biblioitems row except for marc and marcxml, which should be changed
2703 via ModBiblioMarc
2704
2705 =back
2706
2707 =cut
2708
2709 sub _koha_modify_biblioitem_nonmarc {
2710     my ( $dbh, $biblioitem ) = @_;
2711     my $error;
2712
2713     # re-calculate the cn_sort, it may have changed
2714     my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
2715
2716     my $query = 
2717     "UPDATE biblioitems 
2718     SET biblionumber    = ?,
2719         volume          = ?,
2720         number          = ?,
2721         itemtype        = ?,
2722         isbn            = ?,
2723         issn            = ?,
2724         publicationyear = ?,
2725         publishercode   = ?,
2726         volumedate      = ?,
2727         volumedesc      = ?,
2728         collectiontitle = ?,
2729         collectionissn  = ?,
2730         collectionvolume= ?,
2731         editionstatement= ?,
2732         editionresponsibility = ?,
2733         illus           = ?,
2734         pages           = ?,
2735         notes           = ?,
2736         size            = ?,
2737         place           = ?,
2738         lccn            = ?,
2739         url             = ?,
2740         cn_source       = ?,
2741         cn_class        = ?,
2742         cn_item         = ?,
2743         cn_suffix       = ?,
2744         cn_sort         = ?,
2745         totalissues     = ?
2746         where biblioitemnumber = ?
2747         ";
2748     my $sth = $dbh->prepare($query);
2749     $sth->execute(
2750         $biblioitem->{'biblionumber'},
2751         $biblioitem->{'volume'},
2752         $biblioitem->{'number'},
2753         $biblioitem->{'itemtype'},
2754         $biblioitem->{'isbn'},
2755         $biblioitem->{'issn'},
2756         $biblioitem->{'publicationyear'},
2757         $biblioitem->{'publishercode'},
2758         $biblioitem->{'volumedate'},
2759         $biblioitem->{'volumedesc'},
2760         $biblioitem->{'collectiontitle'},
2761         $biblioitem->{'collectionissn'},
2762         $biblioitem->{'collectionvolume'},
2763         $biblioitem->{'editionstatement'},
2764         $biblioitem->{'editionresponsibility'},
2765         $biblioitem->{'illus'},
2766         $biblioitem->{'pages'},
2767         $biblioitem->{'bnotes'},
2768         $biblioitem->{'size'},
2769         $biblioitem->{'place'},
2770         $biblioitem->{'lccn'},
2771         $biblioitem->{'url'},
2772         $biblioitem->{'biblioitems.cn_source'},
2773         $biblioitem->{'cn_class'},
2774         $biblioitem->{'cn_item'},
2775         $biblioitem->{'cn_suffix'},
2776         $cn_sort,
2777         $biblioitem->{'totalissues'},
2778         $biblioitem->{'biblioitemnumber'}
2779     );
2780     if ( $dbh->errstr ) {
2781         $error.="ERROR in _koha_modify_biblioitem_nonmarc $query".$dbh->errstr;
2782         warn $error;
2783     }
2784     return ($biblioitem->{'biblioitemnumber'},$error);
2785 }
2786
2787 =head2 _koha_add_biblioitem
2788
2789 =over 4
2790
2791 my ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $biblioitem );
2792
2793 Internal function to add a biblioitem
2794
2795 =back
2796
2797 =cut
2798
2799 sub _koha_add_biblioitem {
2800     my ( $dbh, $biblioitem ) = @_;
2801     my $error;
2802
2803     my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
2804     my $query =
2805     "INSERT INTO biblioitems SET
2806         biblionumber    = ?,
2807         volume          = ?,
2808         number          = ?,
2809         itemtype        = ?,
2810         isbn            = ?,
2811         issn            = ?,
2812         publicationyear = ?,
2813         publishercode   = ?,
2814         volumedate      = ?,
2815         volumedesc      = ?,
2816         collectiontitle = ?,
2817         collectionissn  = ?,
2818         collectionvolume= ?,
2819         editionstatement= ?,
2820         editionresponsibility = ?,
2821         illus           = ?,
2822         pages           = ?,
2823         notes           = ?,
2824         size            = ?,
2825         place           = ?,
2826         lccn            = ?,
2827         marc            = ?,
2828         url             = ?,
2829         cn_source       = ?,
2830         cn_class        = ?,
2831         cn_item         = ?,
2832         cn_suffix       = ?,
2833         cn_sort         = ?,
2834         totalissues     = ?
2835         ";
2836     my $sth = $dbh->prepare($query);
2837     $sth->execute(
2838         $biblioitem->{'biblionumber'},
2839         $biblioitem->{'volume'},
2840         $biblioitem->{'number'},
2841         $biblioitem->{'itemtype'},
2842         $biblioitem->{'isbn'},
2843         $biblioitem->{'issn'},
2844         $biblioitem->{'publicationyear'},
2845         $biblioitem->{'publishercode'},
2846         $biblioitem->{'volumedate'},
2847         $biblioitem->{'volumedesc'},
2848         $biblioitem->{'collectiontitle'},
2849         $biblioitem->{'collectionissn'},
2850         $biblioitem->{'collectionvolume'},
2851         $biblioitem->{'editionstatement'},
2852         $biblioitem->{'editionresponsibility'},
2853         $biblioitem->{'illus'},
2854         $biblioitem->{'pages'},
2855         $biblioitem->{'bnotes'},
2856         $biblioitem->{'size'},
2857         $biblioitem->{'place'},
2858         $biblioitem->{'lccn'},
2859         $biblioitem->{'marc'},
2860         $biblioitem->{'url'},
2861         $biblioitem->{'biblioitems.cn_source'},
2862         $biblioitem->{'cn_class'},
2863         $biblioitem->{'cn_item'},
2864         $biblioitem->{'cn_suffix'},
2865         $cn_sort,
2866         $biblioitem->{'totalissues'}
2867     );
2868     my $bibitemnum = $dbh->{'mysql_insertid'};
2869     if ( $dbh->errstr ) {
2870         $error.="ERROR in _koha_add_biblioitem $query".$dbh->errstr;
2871         warn $error;
2872     }
2873     $sth->finish();
2874     return ($bibitemnum,$error);
2875 }
2876
2877 =head2 _koha_delete_biblio
2878
2879 =over 4
2880
2881 $error = _koha_delete_biblio($dbh,$biblionumber);
2882
2883 Internal sub for deleting from biblio table -- also saves to deletedbiblio
2884
2885 C<$dbh> - the database handle
2886 C<$biblionumber> - the biblionumber of the biblio to be deleted
2887
2888 =back
2889
2890 =cut
2891
2892 # FIXME: add error handling
2893
2894 sub _koha_delete_biblio {
2895     my ( $dbh, $biblionumber ) = @_;
2896
2897     # get all the data for this biblio
2898     my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber=?");
2899     $sth->execute($biblionumber);
2900
2901     if ( my $data = $sth->fetchrow_hashref ) {
2902
2903         # save the record in deletedbiblio
2904         # find the fields to save
2905         my $query = "INSERT INTO deletedbiblio SET ";
2906         my @bind  = ();
2907         foreach my $temp ( keys %$data ) {
2908             $query .= "$temp = ?,";
2909             push( @bind, $data->{$temp} );
2910         }
2911
2912         # replace the last , by ",?)"
2913         $query =~ s/\,$//;
2914         my $bkup_sth = $dbh->prepare($query);
2915         $bkup_sth->execute(@bind);
2916         $bkup_sth->finish;
2917
2918         # delete the biblio
2919         my $del_sth = $dbh->prepare("DELETE FROM biblio WHERE biblionumber=?");
2920         $del_sth->execute($biblionumber);
2921         $del_sth->finish;
2922     }
2923     $sth->finish;
2924     return undef;
2925 }
2926
2927 =head2 _koha_delete_biblioitems
2928
2929 =over 4
2930
2931 $error = _koha_delete_biblioitems($dbh,$biblioitemnumber);
2932
2933 Internal sub for deleting from biblioitems table -- also saves to deletedbiblioitems
2934
2935 C<$dbh> - the database handle
2936 C<$biblionumber> - the biblioitemnumber of the biblioitem to be deleted
2937
2938 =back
2939
2940 =cut
2941
2942 # FIXME: add error handling
2943
2944 sub _koha_delete_biblioitems {
2945     my ( $dbh, $biblioitemnumber ) = @_;
2946
2947     # get all the data for this biblioitem
2948     my $sth =
2949       $dbh->prepare("SELECT * FROM biblioitems WHERE biblioitemnumber=?");
2950     $sth->execute($biblioitemnumber);
2951
2952     if ( my $data = $sth->fetchrow_hashref ) {
2953
2954         # save the record in deletedbiblioitems
2955         # find the fields to save
2956         my $query = "INSERT INTO deletedbiblioitems SET ";
2957         my @bind  = ();
2958         foreach my $temp ( keys %$data ) {
2959             $query .= "$temp = ?,";
2960             push( @bind, $data->{$temp} );
2961         }
2962
2963         # replace the last , by ",?)"
2964         $query =~ s/\,$//;
2965         my $bkup_sth = $dbh->prepare($query);
2966         $bkup_sth->execute(@bind);
2967         $bkup_sth->finish;
2968
2969         # delete the biblioitem
2970         my $del_sth =
2971           $dbh->prepare("DELETE FROM biblioitems WHERE biblioitemnumber=?");
2972         $del_sth->execute($biblioitemnumber);
2973         $del_sth->finish;
2974     }
2975     $sth->finish;
2976     return undef;
2977 }
2978
2979 =head1 UNEXPORTED FUNCTIONS
2980
2981 =head2 ModBiblioMarc
2982
2983     &ModBiblioMarc($newrec,$biblionumber,$frameworkcode);
2984     
2985     Add MARC data for a biblio to koha 
2986     
2987     Function exported, but should NOT be used, unless you really know what you're doing
2988
2989 =cut
2990
2991 sub ModBiblioMarc {
2992     
2993 # pass the MARC::Record to this function, and it will create the records in the marc field
2994     my ( $record, $biblionumber, $frameworkcode ) = @_;
2995     my $dbh = C4::Context->dbh;
2996     my @fields = $record->fields();
2997     if ( !$frameworkcode ) {
2998         $frameworkcode = "";
2999     }
3000     my $sth =
3001       $dbh->prepare("UPDATE biblio SET frameworkcode=? WHERE biblionumber=?");
3002     $sth->execute( $frameworkcode, $biblionumber );
3003     $sth->finish;
3004     my $encoding = C4::Context->preference("marcflavour");
3005
3006     # deal with UNIMARC field 100 (encoding) : create it if needed & set encoding to unicode
3007     if ( $encoding eq "UNIMARC" ) {
3008         my $string;
3009         if ( length($record->subfield( 100, "a" )) == 35 ) {
3010             $string = $record->subfield( 100, "a" );
3011             my $f100 = $record->field(100);
3012             $record->delete_field($f100);
3013         }
3014         else {
3015             $string = POSIX::strftime( "%Y%m%d", localtime );
3016             $string =~ s/\-//g;
3017             $string = sprintf( "%-*s", 35, $string );
3018         }
3019         substr( $string, 22, 6, "frey50" );
3020         unless ( $record->subfield( 100, "a" ) ) {
3021             $record->insert_grouped_field(
3022                 MARC::Field->new( 100, "", "", "a" => $string ) );
3023         }
3024     }
3025     my $oldRecord;
3026     if (C4::Context->preference("NoZebra")) {
3027         # only NoZebra indexing needs to have
3028         # the previous version of the record
3029         $oldRecord = GetMarcBiblio($biblionumber);
3030     }
3031     $sth =
3032       $dbh->prepare(
3033         "UPDATE biblioitems SET marc=?,marcxml=? WHERE biblionumber=?");
3034     $sth->execute( $record->as_usmarc(), $record->as_xml_record($encoding),
3035         $biblionumber );
3036     $sth->finish;
3037     ModZebra($biblionumber,"specialUpdate","biblioserver",$oldRecord,$record);
3038     return $biblionumber;
3039 }
3040
3041 =head2 z3950_extended_services
3042
3043 z3950_extended_services($serviceType,$serviceOptions,$record);
3044
3045     z3950_extended_services is used to handle all interactions with Zebra's extended serices package, which is employed to perform all management of the MARC data stored in Zebra.
3046
3047 C<$serviceType> one of: itemorder,create,drop,commit,update,xmlupdate
3048
3049 C<$serviceOptions> a has of key/value pairs. For instance, if service_type is 'update', $service_options should contain:
3050
3051     action => update action, one of specialUpdate, recordInsert, recordReplace, recordDelete, elementUpdate.
3052
3053 and maybe
3054
3055     recordidOpaque => Opaque Record ID (user supplied) or recordidNumber => Record ID number (system number).
3056     syntax => the record syntax (transfer syntax)
3057     databaseName = Database from connection object
3058
3059     To set serviceOptions, call set_service_options($serviceType)
3060
3061 C<$record> the record, if one is needed for the service type
3062
3063     A record should be in XML. You can convert it to XML from MARC by running it through marc2xml().
3064
3065 =cut
3066
3067 sub z3950_extended_services {
3068     my ( $server, $serviceType, $action, $serviceOptions ) = @_;
3069
3070     # get our connection object
3071     my $Zconn = C4::Context->Zconn( $server, 0, 1 );
3072
3073     # create a new package object
3074     my $Zpackage = $Zconn->package();
3075
3076     # set our options
3077     $Zpackage->option( action => $action );
3078
3079     if ( $serviceOptions->{'databaseName'} ) {
3080         $Zpackage->option( databaseName => $serviceOptions->{'databaseName'} );
3081     }
3082     if ( $serviceOptions->{'recordIdNumber'} ) {
3083         $Zpackage->option(
3084             recordIdNumber => $serviceOptions->{'recordIdNumber'} );
3085     }
3086     if ( $serviceOptions->{'recordIdOpaque'} ) {
3087         $Zpackage->option(
3088             recordIdOpaque => $serviceOptions->{'recordIdOpaque'} );
3089     }
3090
3091  # this is an ILL request (Zebra doesn't support it, but Koha could eventually)
3092  #if ($serviceType eq 'itemorder') {
3093  #   $Zpackage->option('contact-name' => $serviceOptions->{'contact-name'});
3094  #   $Zpackage->option('contact-phone' => $serviceOptions->{'contact-phone'});
3095  #   $Zpackage->option('contact-email' => $serviceOptions->{'contact-email'});
3096  #   $Zpackage->option('itemorder-item' => $serviceOptions->{'itemorder-item'});
3097  #}
3098
3099     if ( $serviceOptions->{record} ) {
3100         $Zpackage->option( record => $serviceOptions->{record} );
3101
3102         # can be xml or marc
3103         if ( $serviceOptions->{'syntax'} ) {
3104             $Zpackage->option( syntax => $serviceOptions->{'syntax'} );
3105         }
3106     }
3107
3108     # send the request, handle any exception encountered
3109     eval { $Zpackage->send($serviceType) };
3110     if ( $@ && $@->isa("ZOOM::Exception") ) {
3111         return "error:  " . $@->code() . " " . $@->message() . "\n";
3112     }
3113
3114     # free up package resources
3115     $Zpackage->destroy();
3116 }
3117
3118 =head2 set_service_options
3119
3120 my $serviceOptions = set_service_options($serviceType);
3121
3122 C<$serviceType> itemorder,create,drop,commit,update,xmlupdate
3123
3124 Currently, we only support 'create', 'commit', and 'update'. 'drop' support will be added as soon as Zebra supports it.
3125
3126 =cut
3127
3128 sub set_service_options {
3129     my ($serviceType) = @_;
3130     my $serviceOptions;
3131
3132 # FIXME: This needs to be an OID ... if we ever need 'syntax' this sub will need to change
3133 #   $serviceOptions->{ 'syntax' } = ''; #zebra doesn't support syntaxes other than xml
3134
3135     if ( $serviceType eq 'commit' ) {
3136
3137         # nothing to do
3138     }
3139     if ( $serviceType eq 'create' ) {
3140
3141         # nothing to do
3142     }
3143     if ( $serviceType eq 'drop' ) {
3144         die "ERROR: 'drop' not currently supported (by Zebra)";
3145     }
3146     return $serviceOptions;
3147 }
3148
3149 =head3 get_biblio_authorised_values
3150
3151   find the types and values for all authorised values assigned to this biblio.
3152
3153   parameters:
3154     biblionumber
3155
3156   returns: a hashref malling the authorised value to the value set for this biblionumber
3157
3158       $authorised_values = {
3159                              'Scent'     => 'flowery',
3160                              'Audience'  => 'Young Adult',
3161                              'itemtypes' => 'SER',
3162                            };
3163
3164   Notes: forlibrarian should probably be passed in, and called something different.
3165
3166
3167 =cut
3168
3169 sub get_biblio_authorised_values {
3170     my $biblionumber = shift;
3171     
3172     my $forlibrarian = 1; # are we in staff or opac?
3173     my $frameworkcode = GetFrameworkCode( $biblionumber );
3174
3175     my $authorised_values;
3176
3177     my $record  = GetMarcBiblio( $biblionumber )
3178       or return $authorised_values;
3179     my $tagslib = GetMarcStructure( $forlibrarian, $frameworkcode )
3180       or return $authorised_values;
3181
3182     # assume that these entries in the authorised_value table are bibliolevel.
3183     # ones that start with 'item%' are item level.
3184     my $query = q(SELECT distinct authorised_value, kohafield
3185                     FROM marc_subfield_structure
3186                     WHERE authorised_value !=''
3187                       AND (kohafield like 'biblio%'
3188                        OR  kohafield like '') );
3189     my $bibliolevel_authorised_values = C4::Context->dbh->selectall_hashref( $query, 'authorised_value' );
3190     
3191     foreach my $tag ( keys( %$tagslib ) ) {
3192         foreach my $subfield ( keys( %{$tagslib->{ $tag }} ) ) {
3193             # warn "checking $subfield. type is: " . ref $tagslib->{ $tag }{ $subfield };
3194             if ( 'HASH' eq ref $tagslib->{ $tag }{ $subfield } ) {
3195                 if ( defined $tagslib->{ $tag }{ $subfield }{'authorised_value'} && exists $bibliolevel_authorised_values->{ $tagslib->{ $tag }{ $subfield }{'authorised_value'} } ) {
3196                     if ( defined $record->field( $tag ) ) {
3197                         my $this_subfield_value = $record->field( $tag )->subfield( $subfield );
3198                         if ( defined $this_subfield_value ) {
3199                             $authorised_values->{ $tagslib->{ $tag }{ $subfield }{'authorised_value'} } = $this_subfield_value;
3200                         }
3201                     }
3202                 }
3203             }
3204         }
3205     }
3206     # warn ( Data::Dumper->Dump( [ $authorised_values ], [ 'authorised_values' ] ) );
3207     return $authorised_values;
3208 }
3209
3210
3211 1;
3212
3213 __END__
3214
3215 =head1 AUTHOR
3216
3217 Koha Developement team <info@koha.org>
3218
3219 Paul POULAIN paul.poulain@free.fr
3220
3221 Joshua Ferraro jmf@liblime.com
3222
3223 =cut