Bug 2505: adding warnings to C4/Biblio.pm
[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;
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 #---- branch
911         if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
912             return C4::Branch::GetBranchName($value);
913         }
914
915 #---- itemtypes
916         if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "itemtypes" ) {
917             return getitemtypeinfo($value)->{description};
918         }
919
920 #---- "true" authorized value
921         $category = $tagslib->{$tag}->{$subfield}->{'authorised_value'}
922     }
923
924     if ( $category ne "" ) {
925         my $sth =
926             $dbh->prepare(
927                     "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
928                     );
929         $sth->execute( $category, $value );
930         my $data = $sth->fetchrow_hashref;
931         return $data->{'lib'};
932     }
933     else {
934         return $value;    # if nothing is found return the original value
935     }
936 }
937
938 =head2 GetMarcNotes
939
940 =over 4
941
942 $marcnotesarray = GetMarcNotes( $record, $marcflavour );
943 Get all notes from the MARC record and returns them in an array.
944 The note are stored in differents places depending on MARC flavour
945
946 =back
947
948 =cut
949
950 sub GetMarcNotes {
951     my ( $record, $marcflavour ) = @_;
952     my $scope;
953     if ( $marcflavour eq "MARC21" ) {
954         $scope = '5..';
955     }
956     else {    # assume unimarc if not marc21
957         $scope = '3..';
958     }
959     my @marcnotes;
960     my $note = "";
961     my $tag  = "";
962     my $marcnote;
963     foreach my $field ( $record->field($scope) ) {
964         my $value = $field->as_string();
965         if ( $note ne "" ) {
966             $marcnote = { marcnote => $note, };
967             push @marcnotes, $marcnote;
968             $note = $value;
969         }
970         if ( $note ne $value ) {
971             $note = $note . " " . $value;
972         }
973     }
974
975     if ( $note ) {
976         $marcnote = { marcnote => $note };
977         push @marcnotes, $marcnote;    #load last tag into array
978     }
979     return \@marcnotes;
980 }    # end GetMarcNotes
981
982 =head2 GetMarcSubjects
983
984 =over 4
985
986 $marcsubjcts = GetMarcSubjects($record,$marcflavour);
987 Get all subjects from the MARC record and returns them in an array.
988 The subjects are stored in differents places depending on MARC flavour
989
990 =back
991
992 =cut
993
994 sub GetMarcSubjects {
995     my ( $record, $marcflavour ) = @_;
996     my ( $mintag, $maxtag );
997     if ( $marcflavour eq "MARC21" ) {
998         $mintag = "600";
999         $maxtag = "699";
1000     }
1001     else {    # assume unimarc if not marc21
1002         $mintag = "600";
1003         $maxtag = "611";
1004     }
1005     
1006     my @marcsubjects;
1007     my $subject = "";
1008     my $subfield = "";
1009     my $marcsubject;
1010
1011     foreach my $field ( $record->field('6..' )) {
1012         next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1013         my @subfields_loop;
1014         my @subfields = $field->subfields();
1015         my $counter = 0;
1016         my @link_loop;
1017         # if there is an authority link, build the link with an= subfield9
1018         my $subfield9 = $field->subfield('9');
1019         for my $subject_subfield (@subfields ) {
1020             # don't load unimarc subfields 3,4,5
1021             next if (($marcflavour eq "UNIMARC") and ($subject_subfield->[0] =~ /3|4|5/ ) );
1022             my $code = $subject_subfield->[0];
1023             my $value = $subject_subfield->[1];
1024             my $linkvalue = $value;
1025             $linkvalue =~ s/(\(|\))//g;
1026             my $operator = " and " unless $counter==0;
1027             if ($subfield9) {
1028                 @link_loop = ({'limit' => 'an' ,link => "$subfield9" });
1029             } else {
1030                 push @link_loop, {'limit' => 'su', link => $linkvalue, operator => $operator };
1031             }
1032             my $separator = C4::Context->preference("authoritysep") unless $counter==0;
1033             # ignore $9
1034             my @this_link_loop = @link_loop;
1035             push @subfields_loop, {code => $code, value => $value, link_loop => \@this_link_loop, separator => $separator} unless ($subject_subfield->[0] eq 9 );
1036             $counter++;
1037         }
1038                 
1039         push @marcsubjects, { MARCSUBJECT_SUBFIELDS_LOOP => \@subfields_loop };
1040         
1041     }
1042         return \@marcsubjects;
1043 }  #end getMARCsubjects
1044
1045 =head2 GetMarcAuthors
1046
1047 =over 4
1048
1049 authors = GetMarcAuthors($record,$marcflavour);
1050 Get all authors from the MARC record and returns them in an array.
1051 The authors are stored in differents places depending on MARC flavour
1052
1053 =back
1054
1055 =cut
1056
1057 sub GetMarcAuthors {
1058     my ( $record, $marcflavour ) = @_;
1059     my ( $mintag, $maxtag );
1060     # tagslib useful for UNIMARC author reponsabilities
1061     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.
1062     if ( $marcflavour eq "MARC21" ) {
1063         $mintag = "700";
1064         $maxtag = "720"; 
1065     }
1066     elsif ( $marcflavour eq "UNIMARC" ) {    # assume unimarc if not marc21
1067         $mintag = "700";
1068         $maxtag = "712";
1069     }
1070     else {
1071         return;
1072     }
1073     my @marcauthors;
1074
1075     foreach my $field ( $record->fields ) {
1076         next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1077         my @subfields_loop;
1078         my @link_loop;
1079         my @subfields = $field->subfields();
1080         my $count_auth = 0;
1081         # if there is an authority link, build the link with Koha-Auth-Number: subfield9
1082         my $subfield9 = $field->subfield('9');
1083         for my $authors_subfield (@subfields) {
1084             # don't load unimarc subfields 3, 5
1085             next if ($marcflavour eq 'UNIMARC' and ($authors_subfield->[0] =~ /3|5/ ) );
1086             my $subfieldcode = $authors_subfield->[0];
1087             my $value = $authors_subfield->[1];
1088             my $linkvalue = $value;
1089             $linkvalue =~ s/(\(|\))//g;
1090             my $operator = " and " unless $count_auth==0;
1091             # if we have an authority link, use that as the link, otherwise use standard searching
1092             if ($subfield9) {
1093                 @link_loop = ({'limit' => 'an' ,link => "$subfield9" });
1094             }
1095             else {
1096                 # reset $linkvalue if UNIMARC author responsibility
1097                 if ( $marcflavour eq 'UNIMARC' and ($authors_subfield->[0] eq "4")) {
1098                     $linkvalue = "(".GetAuthorisedValueDesc( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib ).")";
1099                 }
1100                 push @link_loop, {'limit' => 'au', link => $linkvalue, operator => $operator };
1101             }
1102             $value = GetAuthorisedValueDesc( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib ) if ( $marcflavour eq 'UNIMARC' and ($authors_subfield->[0] =~/4/));
1103             my @this_link_loop = @link_loop;
1104             my $separator = C4::Context->preference("authoritysep") unless $count_auth==0;
1105             push @subfields_loop, {code => $subfieldcode, value => $value, link_loop => \@this_link_loop, separator => $separator} unless ($authors_subfield->[0] == 9 );
1106             $count_auth++;
1107         }
1108         push @marcauthors, { MARCAUTHOR_SUBFIELDS_LOOP => \@subfields_loop };
1109     }
1110     return \@marcauthors;
1111 }
1112
1113 =head2 GetMarcUrls
1114
1115 =over 4
1116
1117 $marcurls = GetMarcUrls($record,$marcflavour);
1118 Returns arrayref of URLs from MARC data, suitable to pass to tmpl loop.
1119 Assumes web resources (not uncommon in MARC21 to omit resource type ind) 
1120
1121 =back
1122
1123 =cut
1124
1125 sub GetMarcUrls {
1126     my ($record, $marcflavour) = @_;
1127     my @marcurls;
1128     my $marcurl;
1129     for my $field ($record->field('856')) {
1130         my $url = $field->subfield('u');
1131         my @notes;
1132         for my $note ( $field->subfield('z')) {
1133             push @notes , {note => $note};
1134         }        
1135         if($marcflavour eq 'MARC21') {
1136             my $s3 = $field->subfield('3');
1137             my $link = $field->subfield('y');
1138                         unless($url =~ /^\w+:/) {
1139                                 if($field->indicator(1) eq '7') {
1140                                         $url = $field->subfield('2') . "://" . $url;
1141                                 } elsif ($field->indicator(1) eq '1') {
1142                                         $url = 'ftp://' . $url;
1143                                 } else {  
1144                                         #  properly, this should be if ind1=4,
1145                                         #  however we will assume http protocol since we're building a link.
1146                                         $url = 'http://' . $url;
1147                                 }
1148                         }
1149                         # TODO handle ind 2 (relationship)
1150                 $marcurl = {  MARCURL => $url,
1151                       notes => \@notes,
1152             };
1153             $marcurl->{'linktext'} = $link || $s3 || C4::Context->preference('URLLinkText') || $url ;;
1154             $marcurl->{'part'} = $s3 if($link);
1155             $marcurl->{'toc'} = 1 if($s3 =~ /^[Tt]able/) ;
1156         } else {
1157             $marcurl->{'linktext'} = $url || C4::Context->preference('URLLinkText') ;
1158         }
1159         push @marcurls, $marcurl;    
1160     }
1161     return \@marcurls;
1162 }  #end GetMarcUrls
1163
1164 =head2 GetMarcSeries
1165
1166 =over 4
1167
1168 $marcseriesarray = GetMarcSeries($record,$marcflavour);
1169 Get all series from the MARC record and returns them in an array.
1170 The series are stored in differents places depending on MARC flavour
1171
1172 =back
1173
1174 =cut
1175
1176 sub GetMarcSeries {
1177     my ($record, $marcflavour) = @_;
1178     my ($mintag, $maxtag);
1179     if ($marcflavour eq "MARC21") {
1180         $mintag = "440";
1181         $maxtag = "490";
1182     } else {           # assume unimarc if not marc21
1183         $mintag = "600";
1184         $maxtag = "619";
1185     }
1186
1187     my @marcseries;
1188     my $subjct = "";
1189     my $subfield = "";
1190     my $marcsubjct;
1191
1192     foreach my $field ($record->field('440'), $record->field('490')) {
1193         my @subfields_loop;
1194         #my $value = $field->subfield('a');
1195         #$marcsubjct = {MARCSUBJCT => $value,};
1196         my @subfields = $field->subfields();
1197         #warn "subfields:".join " ", @$subfields;
1198         my $counter = 0;
1199         my @link_loop;
1200         for my $series_subfield (@subfields) {
1201             my $volume_number;
1202             undef $volume_number;
1203             # see if this is an instance of a volume
1204             if ($series_subfield->[0] eq 'v') {
1205                 $volume_number=1;
1206             }
1207
1208             my $code = $series_subfield->[0];
1209             my $value = $series_subfield->[1];
1210             my $linkvalue = $value;
1211             $linkvalue =~ s/(\(|\))//g;
1212             my $operator = " and " unless $counter==0;
1213             push @link_loop, {link => $linkvalue, operator => $operator };
1214             my $separator = C4::Context->preference("authoritysep") unless $counter==0;
1215             if ($volume_number) {
1216             push @subfields_loop, {volumenum => $value};
1217             }
1218             else {
1219             push @subfields_loop, {code => $code, value => $value, link_loop => \@link_loop, separator => $separator, volumenum => $volume_number};
1220             }
1221             $counter++;
1222         }
1223         push @marcseries, { MARCSERIES_SUBFIELDS_LOOP => \@subfields_loop };
1224         #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
1225         #push @marcsubjcts, $marcsubjct;
1226         #$subjct = $value;
1227
1228     }
1229     my $marcseriessarray=\@marcseries;
1230     return $marcseriessarray;
1231 }  #end getMARCseriess
1232
1233 =head2 GetFrameworkCode
1234
1235 =over 4
1236
1237     $frameworkcode = GetFrameworkCode( $biblionumber )
1238
1239 =back
1240
1241 =cut
1242
1243 sub GetFrameworkCode {
1244     my ( $biblionumber ) = @_;
1245     my $dbh = C4::Context->dbh;
1246     my $sth = $dbh->prepare("SELECT frameworkcode FROM biblio WHERE biblionumber=?");
1247     $sth->execute($biblionumber);
1248     my ($frameworkcode) = $sth->fetchrow;
1249     return $frameworkcode;
1250 }
1251
1252 =head2 GetPublisherNameFromIsbn
1253
1254     $name = GetPublishercodeFromIsbn($isbn);
1255     if(defined $name){
1256         ...
1257     }
1258
1259 =cut
1260
1261 sub GetPublisherNameFromIsbn($){
1262     my $isbn = shift;
1263     $isbn =~ s/[- _]//g;
1264     $isbn =~ s/^0*//;
1265     my @codes = (split '-', DisplayISBN($isbn));
1266     my $code = $codes[0].$codes[1].$codes[2];
1267     my $dbh  = C4::Context->dbh;
1268     my $query = qq{
1269         SELECT distinct publishercode
1270         FROM   biblioitems
1271         WHERE  isbn LIKE ?
1272         AND    publishercode IS NOT NULL
1273         LIMIT 1
1274     };
1275     my $sth = $dbh->prepare($query);
1276     $sth->execute("$code%");
1277     my $name = $sth->fetchrow;
1278     return $name if length $name;
1279     return undef;
1280 }
1281
1282 =head2 TransformKohaToMarc
1283
1284 =over 4
1285
1286     $record = TransformKohaToMarc( $hash )
1287     This function builds partial MARC::Record from a hash
1288     Hash entries can be from biblio or biblioitems.
1289     This function is called in acquisition module, to create a basic catalogue entry from user entry
1290
1291 =back
1292
1293 =cut
1294
1295 sub TransformKohaToMarc {
1296
1297     my ( $hash ) = @_;
1298     my $dbh = C4::Context->dbh;
1299     my $sth =
1300     $dbh->prepare(
1301         "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE frameworkcode=? AND kohafield=?"
1302     );
1303     my $record = MARC::Record->new();
1304     foreach (keys %{$hash}) {
1305         &TransformKohaToMarcOneField( $sth, $record, $_,
1306             $hash->{$_}, '' );
1307         }
1308     return $record;
1309 }
1310
1311 =head2 TransformKohaToMarcOneField
1312
1313 =over 4
1314
1315     $record = TransformKohaToMarcOneField( $sth, $record, $kohafieldname, $value, $frameworkcode );
1316
1317 =back
1318
1319 =cut
1320
1321 sub TransformKohaToMarcOneField {
1322     my ( $sth, $record, $kohafieldname, $value, $frameworkcode ) = @_;
1323     $frameworkcode='' unless $frameworkcode;
1324     my $tagfield;
1325     my $tagsubfield;
1326
1327     if ( !defined $sth ) {
1328         my $dbh = C4::Context->dbh;
1329         $sth = $dbh->prepare(
1330             "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE frameworkcode=? AND kohafield=?"
1331         );
1332     }
1333     $sth->execute( $frameworkcode, $kohafieldname );
1334     if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
1335         my $tag = $record->field($tagfield);
1336         if ($tag) {
1337             $tag->update( $tagsubfield => $value );
1338             $record->delete_field($tag);
1339             $record->insert_fields_ordered($tag);
1340         }
1341         else {
1342             $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
1343         }
1344     }
1345     return $record;
1346 }
1347
1348 =head2 TransformHtmlToXml
1349
1350 =over 4
1351
1352 $xml = TransformHtmlToXml( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type )
1353
1354 $auth_type contains :
1355 - nothing : rebuild a biblio, un UNIMARC the encoding is in 100$a pos 26/27
1356 - UNIMARCAUTH : rebuild an authority. In UNIMARC, the encoding is in 100$a pos 13/14
1357 - ITEM : rebuild an item : in UNIMARC, 100$a, it's in the biblio ! (otherwise, we would get 2 100 fields !)
1358
1359 =back
1360
1361 =cut
1362
1363 sub TransformHtmlToXml {
1364     my ( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type ) = @_;
1365     my $xml = MARC::File::XML::header('UTF-8');
1366     $auth_type = C4::Context->preference('marcflavour') unless $auth_type;
1367     MARC::File::XML->default_record_format($auth_type);
1368     # in UNIMARC, field 100 contains the encoding
1369     # check that there is one, otherwise the 
1370     # MARC::Record->new_from_xml will fail (and Koha will die)
1371     my $unimarc_and_100_exist=0;
1372     $unimarc_and_100_exist=1 if $auth_type eq 'ITEM'; # if we rebuild an item, no need of a 100 field
1373     my $prevvalue;
1374     my $prevtag = -1;
1375     my $first   = 1;
1376     my $j       = -1;
1377     for ( my $i = 0 ; $i <= @$tags ; $i++ ) {
1378         if (C4::Context->preference('marcflavour') eq 'UNIMARC' and @$tags[$i] eq "100" and @$subfields[$i] eq "a") {
1379             # if we have a 100 field and it's values are not correct, skip them.
1380             # if we don't have any valid 100 field, we will create a default one at the end
1381             my $enc = substr( @$values[$i], 26, 2 );
1382             if ($enc eq '01' or $enc eq '50' or $enc eq '03') {
1383                 $unimarc_and_100_exist=1;
1384             } else {
1385                 next;
1386             }
1387         }
1388         @$values[$i] =~ s/&/&amp;/g;
1389         @$values[$i] =~ s/</&lt;/g;
1390         @$values[$i] =~ s/>/&gt;/g;
1391         @$values[$i] =~ s/"/&quot;/g;
1392         @$values[$i] =~ s/'/&apos;/g;
1393 #         if ( !utf8::is_utf8( @$values[$i] ) ) {
1394 #             utf8::decode( @$values[$i] );
1395 #         }
1396         if ( ( @$tags[$i] ne $prevtag ) ) {
1397             $j++ unless ( @$tags[$i] eq "" );
1398             if ( !$first ) {
1399                 $xml .= "</datafield>\n";
1400                 if (   ( @$tags[$i] && @$tags[$i] > 10 )
1401                     && ( @$values[$i] ne "" ) )
1402                 {
1403                     my $ind1 = substr( @$indicator[$j], 0, 1 );
1404                     my $ind2;
1405                     if ( @$indicator[$j] ) {
1406                         $ind2 = substr( @$indicator[$j], 1, 1 );
1407                     }
1408                     else {
1409                         warn "Indicator in @$tags[$i] is empty";
1410                         $ind2 = " ";
1411                     }
1412                     $xml .=
1413 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1414                     $xml .=
1415 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1416                     $first = 0;
1417                 }
1418                 else {
1419                     $first = 1;
1420                 }
1421             }
1422             else {
1423                 if ( @$values[$i] ne "" ) {
1424
1425                     # leader
1426                     if ( @$tags[$i] eq "000" ) {
1427                         $xml .= "<leader>@$values[$i]</leader>\n";
1428                         $first = 1;
1429
1430                         # rest of the fixed fields
1431                     }
1432                     elsif ( @$tags[$i] < 10 ) {
1433                         $xml .=
1434 "<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
1435                         $first = 1;
1436                     }
1437                     else {
1438                         my $ind1 = substr( @$indicator[$j], 0, 1 );
1439                         my $ind2 = substr( @$indicator[$j], 1, 1 );
1440                         $xml .=
1441 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1442                         $xml .=
1443 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1444                         $first = 0;
1445                     }
1446                 }
1447             }
1448         }
1449         else {    # @$tags[$i] eq $prevtag
1450             if ( @$values[$i] eq "" ) {
1451             }
1452             else {
1453                 if ($first) {
1454                     my $ind1 = substr( @$indicator[$j], 0, 1 );
1455                     my $ind2 = substr( @$indicator[$j], 1, 1 );
1456                     $xml .=
1457 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1458                     $first = 0;
1459                 }
1460                 $xml .=
1461 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1462             }
1463         }
1464         $prevtag = @$tags[$i];
1465     }
1466     if (C4::Context->preference('marcflavour') eq 'UNIMARC' and !$unimarc_and_100_exist) {
1467 #     warn "SETTING 100 for $auth_type";
1468         use POSIX qw(strftime);
1469         my $string = strftime( "%Y%m%d", localtime(time) );
1470         # set 50 to position 26 is biblios, 13 if authorities
1471         my $pos=26;
1472         $pos=13 if $auth_type eq 'UNIMARCAUTH';
1473         $string = sprintf( "%-*s", 35, $string );
1474         substr( $string, $pos , 6, "50" );
1475         $xml .= "<datafield tag=\"100\" ind1=\"\" ind2=\"\">\n";
1476         $xml .= "<subfield code=\"a\">$string</subfield>\n";
1477         $xml .= "</datafield>\n";
1478     }
1479     $xml .= MARC::File::XML::footer();
1480     return $xml;
1481 }
1482
1483 =head2 TransformHtmlToMarc
1484
1485     L<$record> = TransformHtmlToMarc(L<$params>,L<$cgi>)
1486     L<$params> is a ref to an array as below:
1487     {
1488         'tag_010_indicator1_531951' ,
1489         'tag_010_indicator2_531951' ,
1490         'tag_010_code_a_531951_145735' ,
1491         'tag_010_subfield_a_531951_145735' ,
1492         'tag_200_indicator1_873510' ,
1493         'tag_200_indicator2_873510' ,
1494         'tag_200_code_a_873510_673465' ,
1495         'tag_200_subfield_a_873510_673465' ,
1496         'tag_200_code_b_873510_704318' ,
1497         'tag_200_subfield_b_873510_704318' ,
1498         'tag_200_code_e_873510_280822' ,
1499         'tag_200_subfield_e_873510_280822' ,
1500         'tag_200_code_f_873510_110730' ,
1501         'tag_200_subfield_f_873510_110730' ,
1502     }
1503     L<$cgi> is the CGI object which containts the value.
1504     L<$record> is the MARC::Record object.
1505
1506 =cut
1507
1508 sub TransformHtmlToMarc {
1509     my $params = shift;
1510     my $cgi    = shift;
1511    
1512     # explicitly turn on the UTF-8 flag for all
1513     # 'tag_' parameters to avoid incorrect character
1514     # conversion later on
1515     my $cgi_params = $cgi->Vars;
1516     foreach my $param_name (keys %$cgi_params) {
1517         if ($param_name =~ /^tag_/) {
1518             my $param_value = $cgi_params->{$param_name};
1519             if (utf8::decode($param_value)) {
1520                 $cgi_params->{$param_name} = $param_value;
1521             } 
1522             # FIXME - need to do something if string is not valid UTF-8
1523         }
1524     }
1525    
1526     # creating a new record
1527     my $record  = MARC::Record->new();
1528     my $i=0;
1529     my @fields;
1530     while ($params->[$i]){ # browse all CGI params
1531         my $param = $params->[$i];
1532         my $newfield=0;
1533         # if we are on biblionumber, store it in the MARC::Record (it may not be in the edited fields)
1534         if ($param eq 'biblionumber') {
1535             my ( $biblionumbertagfield, $biblionumbertagsubfield ) =
1536                 &GetMarcFromKohaField( "biblio.biblionumber", '' );
1537             if ($biblionumbertagfield < 10) {
1538                 $newfield = MARC::Field->new(
1539                     $biblionumbertagfield,
1540                     $cgi->param($param),
1541                 );
1542             } else {
1543                 $newfield = MARC::Field->new(
1544                     $biblionumbertagfield,
1545                     '',
1546                     '',
1547                     "$biblionumbertagsubfield" => $cgi->param($param),
1548                 );
1549             }
1550             push @fields,$newfield if($newfield);
1551         } 
1552         elsif ($param =~ /^tag_(\d*)_indicator1_/){ # new field start when having 'input name="..._indicator1_..."
1553             my $tag  = $1;
1554             
1555             my $ind1 = substr($cgi->param($param),0,1);
1556             my $ind2 = substr($cgi->param($params->[$i+1]),0,1);
1557             $newfield=0;
1558             my $j=$i+2;
1559             
1560             if($tag < 10){ # no code for theses fields
1561     # in MARC editor, 000 contains the leader.
1562                 if ($tag eq '000' ) {
1563                     $record->leader($cgi->param($params->[$j+1])) if length($cgi->param($params->[$j+1]))==24;
1564     # between 001 and 009 (included)
1565                 } elsif ($cgi->param($params->[$j+1]) ne '') {
1566                     $newfield = MARC::Field->new(
1567                         $tag,
1568                         $cgi->param($params->[$j+1]),
1569                     );
1570                 }
1571     # > 009, deal with subfields
1572             } else {
1573                 while($params->[$j] =~ /_code_/){ # browse all it's subfield
1574                     my $inner_param = $params->[$j];
1575                     if ($newfield){
1576                         if($cgi->param($params->[$j+1]) ne ''){  # only if there is a value (code => value)
1577                             $newfield->add_subfields(
1578                                 $cgi->param($inner_param) => $cgi->param($params->[$j+1])
1579                             );
1580                         }
1581                     } else {
1582                         if ( $cgi->param($params->[$j+1]) ne '' ) { # creating only if there is a value (code => value)
1583                             $newfield = MARC::Field->new(
1584                                 $tag,
1585                                 ''.$ind1,
1586                                 ''.$ind2,
1587                                 $cgi->param($inner_param) => $cgi->param($params->[$j+1]),
1588                             );
1589                         }
1590                     }
1591                     $j+=2;
1592                 }
1593             }
1594             push @fields,$newfield if($newfield);
1595         }
1596         $i++;
1597     }
1598     
1599     $record->append_fields(@fields);
1600     return $record;
1601 }
1602
1603 # cache inverted MARC field map
1604 our $inverted_field_map;
1605
1606 =head2 TransformMarcToKoha
1607
1608 =over 4
1609
1610     $result = TransformMarcToKoha( $dbh, $record, $frameworkcode )
1611
1612 =back
1613
1614 Extract data from a MARC bib record into a hashref representing
1615 Koha biblio, biblioitems, and items fields. 
1616
1617 =cut
1618 sub TransformMarcToKoha {
1619     my ( $dbh, $record, $frameworkcode, $limit_table ) = @_;
1620
1621     my $result;
1622     $limit_table=$limit_table||0;
1623     
1624     unless (defined $inverted_field_map) {
1625         $inverted_field_map = _get_inverted_marc_field_map();
1626     }
1627
1628     my %tables = ();
1629     if ( defined $limit_table && $limit_table eq 'items') {
1630         $tables{'items'} = 1;
1631     } else {
1632         $tables{'items'} = 1;
1633         $tables{'biblio'} = 1;
1634         $tables{'biblioitems'} = 1;
1635     }
1636
1637     # traverse through record
1638     MARCFIELD: foreach my $field ($record->fields()) {
1639         my $tag = $field->tag();
1640         next MARCFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag};
1641         if ($field->is_control_field()) {
1642             my $kohafields = $inverted_field_map->{$frameworkcode}->{$tag}->{list};
1643             ENTRY: foreach my $entry (@{ $kohafields }) {
1644                 my ($subfield, $table, $column) = @{ $entry };
1645                 next ENTRY unless exists $tables{$table};
1646                 my $key = _disambiguate($table, $column);
1647                 if ($result->{$key}) {
1648                     unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($field->data() eq "")) {
1649                         $result->{$key} .= " | " . $field->data();
1650                     }
1651                 } else {
1652                     $result->{$key} = $field->data();
1653                 }
1654             }
1655         } else {
1656             # deal with subfields
1657             MARCSUBFIELD: foreach my $sf ($field->subfields()) {
1658                 my $code = $sf->[0];
1659                 next MARCSUBFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code};
1660                 my $value = $sf->[1];
1661                 SFENTRY: foreach my $entry (@{ $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code} }) {
1662                     my ($table, $column) = @{ $entry };
1663                     next SFENTRY unless exists $tables{$table};
1664                     my $key = _disambiguate($table, $column);
1665                     if ($result->{$key}) {
1666                         unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($value eq "")) {
1667                             $result->{$key} .= " | " . $value;
1668                         }
1669                     } else {
1670                         $result->{$key} = $value;
1671                     }
1672                 }
1673             }
1674         }
1675     }
1676
1677     # modify copyrightdate to keep only the 1st year found
1678     if (exists $result->{'copyrightdate'}) {
1679         my $temp = $result->{'copyrightdate'};
1680         $temp =~ m/c(\d\d\d\d)/;    # search cYYYY first
1681         if ( $1 > 0 ) {
1682             $result->{'copyrightdate'} = $1;
1683         }
1684         else {                      # if no cYYYY, get the 1st date.
1685             $temp =~ m/(\d\d\d\d)/;
1686             $result->{'copyrightdate'} = $1;
1687         }
1688     }
1689
1690     # modify publicationyear to keep only the 1st year found
1691     if (exists $result->{'publicationyear'}) {
1692         my $temp = $result->{'publicationyear'};
1693         $temp =~ m/c(\d\d\d\d)/;    # search cYYYY first
1694         if ( $1 > 0 ) {
1695             $result->{'publicationyear'} = $1;
1696         }
1697         else {                      # if no cYYYY, get the 1st date.
1698             $temp =~ m/(\d\d\d\d)/;
1699             $result->{'publicationyear'} = $1;
1700         }
1701     }
1702
1703     return $result;
1704 }
1705
1706 sub _get_inverted_marc_field_map {
1707     my $field_map = {};
1708     my $relations = C4::Context->marcfromkohafield;
1709
1710     foreach my $frameworkcode (keys %{ $relations }) {
1711         foreach my $kohafield (keys %{ $relations->{$frameworkcode} }) {
1712             my $tag = $relations->{$frameworkcode}->{$kohafield}->[0];
1713             my $subfield = $relations->{$frameworkcode}->{$kohafield}->[1];
1714             my ($table, $column) = split /[.]/, $kohafield, 2;
1715             push @{ $field_map->{$frameworkcode}->{$tag}->{list} }, [ $subfield, $table, $column ];
1716             push @{ $field_map->{$frameworkcode}->{$tag}->{sfs}->{$subfield} }, [ $table, $column ];
1717         }
1718     }
1719     return $field_map;
1720 }
1721
1722 =head2 _disambiguate
1723
1724 =over 4
1725
1726 $newkey = _disambiguate($table, $field);
1727
1728 This is a temporary hack to distinguish between the
1729 following sets of columns when using TransformMarcToKoha.
1730
1731 items.cn_source & biblioitems.cn_source
1732 items.cn_sort & biblioitems.cn_sort
1733
1734 Columns that are currently NOT distinguished (FIXME
1735 due to lack of time to fully test) are:
1736
1737 biblio.notes and biblioitems.notes
1738 biblionumber
1739 timestamp
1740 biblioitemnumber
1741
1742 FIXME - this is necessary because prefixing each column
1743 name with the table name would require changing lots
1744 of code and templates, and exposing more of the DB
1745 structure than is good to the UI templates, particularly
1746 since biblio and bibloitems may well merge in a future
1747 version.  In the future, it would also be good to 
1748 separate DB access and UI presentation field names
1749 more.
1750
1751 =back
1752
1753 =cut
1754
1755 sub _disambiguate {
1756     my ($table, $column) = @_;
1757     if ($column eq "cn_sort" or $column eq "cn_source") {
1758         return $table . '.' . $column;
1759     } else {
1760         return $column;
1761     }
1762
1763 }
1764
1765 =head2 get_koha_field_from_marc
1766
1767 =over 4
1768
1769 $result->{_disambiguate($table, $field)} = get_koha_field_from_marc($table,$field,$record,$frameworkcode);
1770
1771 Internal function to map data from the MARC record to a specific non-MARC field.
1772 FIXME: this is meant to replace TransformMarcToKohaOneField after more testing.
1773
1774 =back
1775
1776 =cut
1777
1778 sub get_koha_field_from_marc {
1779     my ($koha_table,$koha_column,$record,$frameworkcode) = @_;
1780     my ( $tagfield, $subfield ) = GetMarcFromKohaField( $koha_table.'.'.$koha_column, $frameworkcode );  
1781     my $kohafield;
1782     foreach my $field ( $record->field($tagfield) ) {
1783         if ( $field->tag() < 10 ) {
1784             if ( $kohafield ) {
1785                 $kohafield .= " | " . $field->data();
1786             }
1787             else {
1788                 $kohafield = $field->data();
1789             }
1790         }
1791         else {
1792             if ( $field->subfields ) {
1793                 my @subfields = $field->subfields();
1794                 foreach my $subfieldcount ( 0 .. $#subfields ) {
1795                     if ( $subfields[$subfieldcount][0] eq $subfield ) {
1796                         if ( $kohafield ) {
1797                             $kohafield .=
1798                               " | " . $subfields[$subfieldcount][1];
1799                         }
1800                         else {
1801                             $kohafield =
1802                               $subfields[$subfieldcount][1];
1803                         }
1804                     }
1805                 }
1806             }
1807         }
1808     }
1809     return $kohafield;
1810
1811
1812
1813 =head2 TransformMarcToKohaOneField
1814
1815 =over 4
1816
1817 $result = TransformMarcToKohaOneField( $kohatable, $kohafield, $record, $result, $frameworkcode )
1818
1819 =back
1820
1821 =cut
1822
1823 sub TransformMarcToKohaOneField {
1824
1825     # FIXME ? if a field has a repeatable subfield that is used in old-db,
1826     # only the 1st will be retrieved...
1827     my ( $kohatable, $kohafield, $record, $result, $frameworkcode ) = @_;
1828     my $res = "";
1829     my ( $tagfield, $subfield ) =
1830       GetMarcFromKohaField( $kohatable . "." . $kohafield,
1831         $frameworkcode );
1832     foreach my $field ( $record->field($tagfield) ) {
1833         if ( $field->tag() < 10 ) {
1834             if ( $result->{$kohafield} ) {
1835                 $result->{$kohafield} .= " | " . $field->data();
1836             }
1837             else {
1838                 $result->{$kohafield} = $field->data();
1839             }
1840         }
1841         else {
1842             if ( $field->subfields ) {
1843                 my @subfields = $field->subfields();
1844                 foreach my $subfieldcount ( 0 .. $#subfields ) {
1845                     if ( $subfields[$subfieldcount][0] eq $subfield ) {
1846                         if ( $result->{$kohafield} ) {
1847                             $result->{$kohafield} .=
1848                               " | " . $subfields[$subfieldcount][1];
1849                         }
1850                         else {
1851                             $result->{$kohafield} =
1852                               $subfields[$subfieldcount][1];
1853                         }
1854                     }
1855                 }
1856             }
1857         }
1858     }
1859     return $result;
1860 }
1861
1862 =head1  OTHER FUNCTIONS
1863
1864
1865 =head2 PrepareItemrecordDisplay
1866
1867 =over 4
1868
1869 PrepareItemrecordDisplay($itemrecord,$bibnum,$itemumber);
1870
1871 Returns a hash with all the fields for Display a given item data in a template
1872
1873 =back
1874
1875 =cut
1876
1877 sub PrepareItemrecordDisplay {
1878
1879     my ( $bibnum, $itemnum, $defaultvalues ) = @_;
1880
1881     my $dbh = C4::Context->dbh;
1882     my $frameworkcode = &GetFrameworkCode( $bibnum );
1883     my ( $itemtagfield, $itemtagsubfield ) =
1884       &GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
1885     my $tagslib = &GetMarcStructure( 1, $frameworkcode );
1886     my $itemrecord = C4::Items::GetMarcItem( $bibnum, $itemnum) if ($itemnum);
1887     my @loop_data;
1888     my $authorised_values_sth =
1889       $dbh->prepare(
1890 "SELECT authorised_value,lib FROM authorised_values WHERE category=? ORDER BY lib"
1891       );
1892     foreach my $tag ( sort keys %{$tagslib} ) {
1893         my $previous_tag = '';
1894         if ( $tag ne '' ) {
1895             # loop through each subfield
1896             my $cntsubf;
1897             foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
1898                 next if ( subfield_is_koha_internal_p($subfield) );
1899                 next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
1900                 my %subfield_data;
1901                 $subfield_data{tag}           = $tag;
1902                 $subfield_data{subfield}      = $subfield;
1903                 $subfield_data{countsubfield} = $cntsubf++;
1904                 $subfield_data{kohafield}     =
1905                   $tagslib->{$tag}->{$subfield}->{'kohafield'};
1906
1907          #        $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
1908                 $subfield_data{marc_lib} = $tagslib->{$tag}->{$subfield}->{lib};
1909                 $subfield_data{mandatory} =
1910                   $tagslib->{$tag}->{$subfield}->{mandatory};
1911                 $subfield_data{repeatable} =
1912                   $tagslib->{$tag}->{$subfield}->{repeatable};
1913                 $subfield_data{hidden} = "display:none"
1914                   if $tagslib->{$tag}->{$subfield}->{hidden};
1915                 my ( $x, $value );
1916                 ( $x, $value ) = _find_value( $tag, $subfield, $itemrecord )
1917                   if ($itemrecord);
1918                 $value =~ s/"/&quot;/g;
1919
1920                 # search for itemcallnumber if applicable
1921                 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
1922                     'items.itemcallnumber'
1923                     && C4::Context->preference('itemcallnumber') )
1924                 {
1925                     my $CNtag =
1926                       substr( C4::Context->preference('itemcallnumber'), 0, 3 );
1927                     my $CNsubfield =
1928                       substr( C4::Context->preference('itemcallnumber'), 3, 1 );
1929                     my $temp = $itemrecord->field($CNtag) if ($itemrecord);
1930                     if ($temp) {
1931                         $value = $temp->subfield($CNsubfield);
1932                     }
1933                 }
1934                 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
1935                     'items.itemcallnumber'
1936                     && $defaultvalues->{'callnumber'} )
1937                 {
1938                     my $temp = $itemrecord->field($subfield) if ($itemrecord);
1939                     unless ($temp) {
1940                         $value = $defaultvalues->{'callnumber'};
1941                     }
1942                 }
1943                 if ( ($tagslib->{$tag}->{$subfield}->{kohafield} eq
1944                     'items.holdingbranch' ||
1945                     $tagslib->{$tag}->{$subfield}->{kohafield} eq
1946                     'items.homebranch')          
1947                     && $defaultvalues->{'branchcode'} )
1948                 {
1949                     my $temp = $itemrecord->field($subfield) if ($itemrecord);
1950                     unless ($temp) {
1951                         $value = $defaultvalues->{branchcode};
1952                     }
1953                 }
1954                 if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
1955                     my @authorised_values;
1956                     my %authorised_lib;
1957
1958                     # builds list, depending on authorised value...
1959                     #---- branch
1960                     if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq
1961                         "branches" )
1962                     {
1963                         if ( ( C4::Context->preference("IndependantBranches") )
1964                             && ( C4::Context->userenv->{flags} != 1 ) )
1965                         {
1966                             my $sth =
1967                               $dbh->prepare(
1968                                 "SELECT branchcode,branchname FROM branches WHERE branchcode = ? ORDER BY branchname"
1969                               );
1970                             $sth->execute( C4::Context->userenv->{branch} );
1971                             push @authorised_values, ""
1972                               unless (
1973                                 $tagslib->{$tag}->{$subfield}->{mandatory} );
1974                             while ( my ( $branchcode, $branchname ) =
1975                                 $sth->fetchrow_array )
1976                             {
1977                                 push @authorised_values, $branchcode;
1978                                 $authorised_lib{$branchcode} = $branchname;
1979                             }
1980                         }
1981                         else {
1982                             my $sth =
1983                               $dbh->prepare(
1984                                 "SELECT branchcode,branchname FROM branches ORDER BY branchname"
1985                               );
1986                             $sth->execute;
1987                             push @authorised_values, ""
1988                               unless (
1989                                 $tagslib->{$tag}->{$subfield}->{mandatory} );
1990                             while ( my ( $branchcode, $branchname ) =
1991                                 $sth->fetchrow_array )
1992                             {
1993                                 push @authorised_values, $branchcode;
1994                                 $authorised_lib{$branchcode} = $branchname;
1995                             }
1996                         }
1997
1998                         #----- itemtypes
1999                     }
2000                     elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq
2001                         "itemtypes" )
2002                     {
2003                         my $sth =
2004                           $dbh->prepare(
2005                             "SELECT itemtype,description FROM itemtypes ORDER BY description"
2006                           );
2007                         $sth->execute;
2008                         push @authorised_values, ""
2009                           unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2010                         while ( my ( $itemtype, $description ) =
2011                             $sth->fetchrow_array )
2012                         {
2013                             push @authorised_values, $itemtype;
2014                             $authorised_lib{$itemtype} = $description;
2015                         }
2016
2017                         #---- "true" authorised value
2018                     }
2019                     else {
2020                         $authorised_values_sth->execute(
2021                             $tagslib->{$tag}->{$subfield}->{authorised_value} );
2022                         push @authorised_values, ""
2023                           unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2024                         while ( my ( $value, $lib ) =
2025                             $authorised_values_sth->fetchrow_array )
2026                         {
2027                             push @authorised_values, $value;
2028                             $authorised_lib{$value} = $lib;
2029                         }
2030                     }
2031                     $subfield_data{marc_value} = CGI::scrolling_list(
2032                         -name     => 'field_value',
2033                         -values   => \@authorised_values,
2034                         -default  => "$value",
2035                         -labels   => \%authorised_lib,
2036                         -size     => 1,
2037                         -tabindex => '',
2038                         -multiple => 0,
2039                     );
2040                 }
2041                 elsif ( $tagslib->{$tag}->{$subfield}->{thesaurus_category} ) {
2042                     $subfield_data{marc_value} =
2043 "<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>";
2044
2045 #"
2046 # COMMENTED OUT because No $i is provided with this API.
2047 # And thus, no value_builder can be activated.
2048 # BUT could be thought over.
2049 #         } elsif ($tagslib->{$tag}->{$subfield}->{'value_builder'}) {
2050 #             my $plugin="value_builder/".$tagslib->{$tag}->{$subfield}->{'value_builder'};
2051 #             require $plugin;
2052 #             my $extended_param = plugin_parameters($dbh,$itemrecord,$tagslib,$i,0);
2053 #             my ($function_name,$javascript) = plugin_javascript($dbh,$record,$tagslib,$i,0);
2054 #             $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";
2055                 }
2056                 else {
2057                     $subfield_data{marc_value} =
2058 "<input type=\"text\" name=\"field_value\" value=\"$value\" size=\"50\" maxlength=\"255\" />";
2059                 }
2060                 push( @loop_data, \%subfield_data );
2061             }
2062         }
2063     }
2064     my $itemnumber = $itemrecord->subfield( $itemtagfield, $itemtagsubfield )
2065       if ( $itemrecord && $itemrecord->field($itemtagfield) );
2066     return {
2067         'itemtagfield'    => $itemtagfield,
2068         'itemtagsubfield' => $itemtagsubfield,
2069         'itemnumber'      => $itemnumber,
2070         'iteminformation' => \@loop_data
2071     };
2072 }
2073 #"
2074
2075 #
2076 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2077 # at the same time
2078 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2079 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2080 # =head2 ModZebrafiles
2081
2082 # &ModZebrafiles( $dbh, $biblionumber, $record, $folder, $server );
2083
2084 # =cut
2085
2086 # sub ModZebrafiles {
2087
2088 #     my ( $dbh, $biblionumber, $record, $folder, $server ) = @_;
2089
2090 #     my $op;
2091 #     my $zebradir =
2092 #       C4::Context->zebraconfig($server)->{directory} . "/" . $folder . "/";
2093 #     unless ( opendir( DIR, "$zebradir" ) ) {
2094 #         warn "$zebradir not found";
2095 #         return;
2096 #     }
2097 #     closedir DIR;
2098 #     my $filename = $zebradir . $biblionumber;
2099
2100 #     if ($record) {
2101 #         open( OUTPUT, ">", $filename . ".xml" );
2102 #         print OUTPUT $record;
2103 #         close OUTPUT;
2104 #     }
2105 # }
2106
2107 =head2 ModZebra
2108
2109 =over 4
2110
2111 ModZebra( $biblionumber, $op, $server, $oldRecord, $newRecord );
2112
2113     $biblionumber is the biblionumber we want to index
2114     $op is specialUpdate or delete, and is used to know what we want to do
2115     $server is the server that we want to update
2116     $oldRecord is the MARC::Record containing the previous version of the record.  This is used only when 
2117       NoZebra=1, as NoZebra indexing needs to know the previous version of a record in order to
2118       do an update.
2119     $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.
2120     
2121 =back
2122
2123 =cut
2124
2125 sub ModZebra {
2126 ###Accepts a $server variable thus we can use it for biblios authorities or other zebra dbs
2127     my ( $biblionumber, $op, $server, $oldRecord, $newRecord ) = @_;
2128     my $dbh=C4::Context->dbh;
2129
2130     # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2131     # at the same time
2132     # replaced by a zebraqueue table, that is filled with ModZebra to run.
2133     # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2134
2135     if (C4::Context->preference("NoZebra")) {
2136         # lock the nozebra table : we will read index lines, update them in Perl process
2137         # and write everything in 1 transaction.
2138         # lock the table to avoid someone else overwriting what we are doing
2139         $dbh->do('LOCK TABLES nozebra WRITE,biblio WRITE,biblioitems WRITE, systempreferences WRITE, auth_types WRITE, auth_header WRITE, auth_subfield_structure READ');
2140         my %result; # the result hash that will be built by deletion / add, and written on mySQL at the end, to improve speed
2141         if ($op eq 'specialUpdate') {
2142             # OK, we have to add or update the record
2143             # 1st delete (virtually, in indexes), if record actually exists
2144             if ($oldRecord) { 
2145                 %result = _DelBiblioNoZebra($biblionumber,$oldRecord,$server);
2146             }
2147             # ... add the record
2148             %result=_AddBiblioNoZebra($biblionumber,$newRecord, $server, %result);
2149         } else {
2150             # it's a deletion, delete the record...
2151             # warn "DELETE the record $biblionumber on $server".$record->as_formatted;
2152             %result=_DelBiblioNoZebra($biblionumber,$oldRecord,$server);
2153         }
2154         # ok, now update the database...
2155         my $sth = $dbh->prepare("UPDATE nozebra SET biblionumbers=? WHERE server=? AND indexname=? AND value=?");
2156         foreach my $key (keys %result) {
2157             foreach my $index (keys %{$result{$key}}) {
2158                 $sth->execute($result{$key}->{$index}, $server, $key, $index);
2159             }
2160         }
2161         $dbh->do('UNLOCK TABLES');
2162     } else {
2163         #
2164         # we use zebra, just fill zebraqueue table
2165         #
2166         my $check_sql = "SELECT COUNT(*) FROM zebraqueue 
2167                          WHERE server = ?
2168                          AND   biblio_auth_number = ?
2169                          AND   operation = ?
2170                          AND   done = 0";
2171         my $check_sth = $dbh->prepare_cached($check_sql);
2172         $check_sth->execute($server, $biblionumber, $op);
2173         my ($count) = $check_sth->fetchrow_array;
2174         $check_sth->finish();
2175         if ($count == 0) {
2176             my $sth=$dbh->prepare("INSERT INTO zebraqueue  (biblio_auth_number,server,operation) VALUES(?,?,?)");
2177             $sth->execute($biblionumber,$server,$op);
2178             $sth->finish;
2179         }
2180     }
2181 }
2182
2183 =head2 GetNoZebraIndexes
2184
2185     %indexes = GetNoZebraIndexes;
2186     
2187     return the data from NoZebraIndexes syspref.
2188
2189 =cut
2190
2191 sub GetNoZebraIndexes {
2192     my $no_zebra_indexes = C4::Context->preference('NoZebraIndexes');
2193     my %indexes;
2194     INDEX: foreach my $line (split /['"],[\n\r]*/,$no_zebra_indexes) {
2195         $line =~ /(.*)=>(.*)/;
2196         my $index = $1; # initial ' or " is removed afterwards
2197         my $fields = $2;
2198         $index =~ s/'|"|\s//g;
2199         $fields =~ s/'|"|\s//g;
2200         $indexes{$index}=$fields;
2201     }
2202     return %indexes;
2203 }
2204
2205 =head1 INTERNAL FUNCTIONS
2206
2207 =head2 _DelBiblioNoZebra($biblionumber,$record,$server);
2208
2209     function to delete a biblio in NoZebra indexes
2210     This function does NOT delete anything in database : it reads all the indexes entries
2211     that have to be deleted & delete them in the hash
2212     The SQL part is done either :
2213     - after the Add if we are modifying a biblio (delete + add again)
2214     - immediatly after this sub if we are doing a true deletion.
2215     $server can be 'biblioserver' or 'authorityserver' : it indexes biblios or authorities (in the same table, $server being part of the table itself
2216
2217 =cut
2218
2219
2220 sub _DelBiblioNoZebra {
2221     my ($biblionumber, $record, $server)=@_;
2222     
2223     # Get the indexes
2224     my $dbh = C4::Context->dbh;
2225     # Get the indexes
2226     my %index;
2227     my $title;
2228     if ($server eq 'biblioserver') {
2229         %index=GetNoZebraIndexes;
2230         # get title of the record (to store the 10 first letters with the index)
2231         my ($titletag,$titlesubfield) = GetMarcFromKohaField('biblio.title');
2232         $title = lc($record->subfield($titletag,$titlesubfield));
2233     } else {
2234         # for authorities, the "title" is the $a mainentry
2235         my ($auth_type_tag, $auth_type_sf) = C4::AuthoritiesMarc::get_auth_type_location();
2236         my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield($auth_type_tag, $auth_type_sf));
2237         warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
2238         $title = $record->subfield($authref->{auth_tag_to_report},'a');
2239         $index{'mainmainentry'}= $authref->{'auth_tag_to_report'}.'a';
2240         $index{'mainentry'}    = $authref->{'auth_tag_to_report'}.'*';
2241         $index{'auth_type'}    = "${auth_type_tag}${auth_type_sf}";
2242     }
2243     
2244     my %result;
2245     # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
2246     $title =~ s/ |,|;|\[|\]|\(|\)|\*|-|'|=//g;
2247     # limit to 10 char, should be enough, and limit the DB size
2248     $title = substr($title,0,10);
2249     #parse each field
2250     my $sth2=$dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
2251     foreach my $field ($record->fields()) {
2252         #parse each subfield
2253         next if $field->tag <10;
2254         foreach my $subfield ($field->subfields()) {
2255             my $tag = $field->tag();
2256             my $subfieldcode = $subfield->[0];
2257             my $indexed=0;
2258             # check each index to see if the subfield is stored somewhere
2259             # otherwise, store it in __RAW__ index
2260             foreach my $key (keys %index) {
2261 #                 warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
2262                 if ($index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/) {
2263                     $indexed=1;
2264                     my $line= lc $subfield->[1];
2265                     # remove meaningless value in the field...
2266                     $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
2267                     # ... and split in words
2268                     foreach (split / /,$line) {
2269                         next unless $_; # skip  empty values (multiple spaces)
2270                         # if the entry is already here, do nothing, the biblionumber has already be removed
2271                         unless ( defined( $result{$key}->{$_} ) && ( $result{$key}->{$_} =~ /$biblionumber,$title\-(\d);/) ) {
2272                             # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
2273                             $sth2->execute($server,$key,$_);
2274                             my $existing_biblionumbers = $sth2->fetchrow;
2275                             # it exists
2276                             if ($existing_biblionumbers) {
2277 #                                 warn " existing for $key $_: $existing_biblionumbers";
2278                                 $result{$key}->{$_} =$existing_biblionumbers;
2279                                 $result{$key}->{$_} =~ s/$biblionumber,$title\-(\d);//;
2280                             }
2281                         }
2282                     }
2283                 }
2284             }
2285             # the subfield is not indexed, store it in __RAW__ index anyway
2286             unless ($indexed) {
2287                 my $line= lc $subfield->[1];
2288                 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
2289                 # ... and split in words
2290                 foreach (split / /,$line) {
2291                     next unless $_; # skip  empty values (multiple spaces)
2292                     # if the entry is already here, do nothing, the biblionumber has already be removed
2293                     unless ($result{'__RAW__'}->{$_} =~ /$biblionumber,$title\-(\d);/) {
2294                         # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
2295                         $sth2->execute($server,'__RAW__',$_);
2296                         my $existing_biblionumbers = $sth2->fetchrow;
2297                         # it exists
2298                         if ($existing_biblionumbers) {
2299                             $result{'__RAW__'}->{$_} =$existing_biblionumbers;
2300                             $result{'__RAW__'}->{$_} =~ s/$biblionumber,$title\-(\d);//;
2301                         }
2302                     }
2303                 }
2304             }
2305         }
2306     }
2307     return %result;
2308 }
2309
2310 =head2 _AddBiblioNoZebra($biblionumber, $record, $server, %result);
2311
2312     function to add a biblio in NoZebra indexes
2313
2314 =cut
2315
2316 sub _AddBiblioNoZebra {
2317     my ($biblionumber, $record, $server, %result)=@_;
2318     my $dbh = C4::Context->dbh;
2319     # Get the indexes
2320     my %index;
2321     my $title;
2322     if ($server eq 'biblioserver') {
2323         %index=GetNoZebraIndexes;
2324         # get title of the record (to store the 10 first letters with the index)
2325         my ($titletag,$titlesubfield) = GetMarcFromKohaField('biblio.title');
2326         $title = lc($record->subfield($titletag,$titlesubfield));
2327     } else {
2328         # warn "server : $server";
2329         # for authorities, the "title" is the $a mainentry
2330         my ($auth_type_tag, $auth_type_sf) = C4::AuthoritiesMarc::get_auth_type_location();
2331         my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield($auth_type_tag, $auth_type_sf));
2332         warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
2333         $title = $record->subfield($authref->{auth_tag_to_report},'a');
2334         $index{'mainmainentry'} = $authref->{auth_tag_to_report}.'a';
2335         $index{'mainentry'}     = $authref->{auth_tag_to_report}.'*';
2336         $index{'auth_type'}    = "${auth_type_tag}${auth_type_sf}";
2337     }
2338
2339     # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
2340     $title =~ s/ |\.|,|;|\[|\]|\(|\)|\*|-|'|:|=|\r|\n//g;
2341     # limit to 10 char, should be enough, and limit the DB size
2342     $title = substr($title,0,10);
2343     #parse each field
2344     my $sth2=$dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
2345     foreach my $field ($record->fields()) {
2346         #parse each subfield
2347         ###FIXME: impossible to index a 001-009 value with NoZebra
2348         next if $field->tag <10;
2349         foreach my $subfield ($field->subfields()) {
2350             my $tag = $field->tag();
2351             my $subfieldcode = $subfield->[0];
2352             my $indexed=0;
2353 #             warn "INDEXING :".$subfield->[1];
2354             # check each index to see if the subfield is stored somewhere
2355             # otherwise, store it in __RAW__ index
2356             foreach my $key (keys %index) {
2357 #                 warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
2358                 if ($index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/) {
2359                     $indexed=1;
2360                     my $line= lc $subfield->[1];
2361                     # remove meaningless value in the field...
2362                     $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:|\r|\n/ /g;
2363                     # ... and split in words
2364                     foreach (split / /,$line) {
2365                         next unless $_; # skip  empty values (multiple spaces)
2366                         # if the entry is already here, improve weight
2367 #                         warn "managing $_";
2368                         if ( exists $result{$key}->{$_} && $result{$key}->{"$_"} =~ /$biblionumber,\Q$title\E\-(\d+);/) {
2369                             my $weight = $1 + 1;
2370                             $result{$key}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//g;
2371                             $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
2372                         } else {
2373                             # get the value if it exist in the nozebra table, otherwise, create it
2374                             $sth2->execute($server,$key,$_);
2375                             my $existing_biblionumbers = $sth2->fetchrow;
2376                             # it exists
2377                             if ($existing_biblionumbers) {
2378                                 $result{$key}->{"$_"} =$existing_biblionumbers;
2379                                 my $weight = defined $1 ? $1 + 1 : 1;
2380                                 $result{$key}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//g;
2381                                 $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
2382                             # create a new ligne for this entry
2383                             } else {
2384 #                             warn "INSERT : $server / $key / $_";
2385                                 $dbh->do('INSERT INTO nozebra SET server='.$dbh->quote($server).', indexname='.$dbh->quote($key).',value='.$dbh->quote($_));
2386                                 $result{$key}->{"$_"}.="$biblionumber,$title-1;";
2387                             }
2388                         }
2389                     }
2390                 }
2391             }
2392             # the subfield is not indexed, store it in __RAW__ index anyway
2393             unless ($indexed) {
2394                 my $line= lc $subfield->[1];
2395                 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:|\r|\n/ /g;
2396                 # ... and split in words
2397                 foreach (split / /,$line) {
2398                     next unless $_; # skip  empty values (multiple spaces)
2399                     # if the entry is already here, improve weight
2400                     if ($result{'__RAW__'}->{"$_"} =~ /$biblionumber,\Q$title\E\-(\d+);/) { 
2401                         my $weight=$1+1;
2402                         $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//;
2403                         $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
2404                     } else {
2405                         # get the value if it exist in the nozebra table, otherwise, create it
2406                         $sth2->execute($server,'__RAW__',$_);
2407                         my $existing_biblionumbers = $sth2->fetchrow;
2408                         # it exists
2409                         if ($existing_biblionumbers) {
2410                             $result{'__RAW__'}->{"$_"} =$existing_biblionumbers;
2411                             my $weight=$1+1;
2412                             $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//;
2413                             $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
2414                         # create a new ligne for this entry
2415                         } else {
2416                             $dbh->do('INSERT INTO nozebra SET server='.$dbh->quote($server).',  indexname="__RAW__",value='.$dbh->quote($_));
2417                             $result{'__RAW__'}->{"$_"}.="$biblionumber,$title-1;";
2418                         }
2419                     }
2420                 }
2421             }
2422         }
2423     }
2424     return %result;
2425 }
2426
2427
2428 =head2 _find_value
2429
2430 =over 4
2431
2432 ($indicators, $value) = _find_value($tag, $subfield, $record,$encoding);
2433
2434 Find the given $subfield in the given $tag in the given
2435 MARC::Record $record.  If the subfield is found, returns
2436 the (indicators, value) pair; otherwise, (undef, undef) is
2437 returned.
2438
2439 PROPOSITION :
2440 Such a function is used in addbiblio AND additem and serial-edit and maybe could be used in Authorities.
2441 I suggest we export it from this module.
2442
2443 =back
2444
2445 =cut
2446
2447 sub _find_value {
2448     my ( $tagfield, $insubfield, $record, $encoding ) = @_;
2449     my @result;
2450     my $indicator;
2451     if ( $tagfield < 10 ) {
2452         if ( $record->field($tagfield) ) {
2453             push @result, $record->field($tagfield)->data();
2454         }
2455         else {
2456             push @result, "";
2457         }
2458     }
2459     else {
2460         foreach my $field ( $record->field($tagfield) ) {
2461             my @subfields = $field->subfields();
2462             foreach my $subfield (@subfields) {
2463                 if ( @$subfield[0] eq $insubfield ) {
2464                     push @result, @$subfield[1];
2465                     $indicator = $field->indicator(1) . $field->indicator(2);
2466                 }
2467             }
2468         }
2469     }
2470     return ( $indicator, @result );
2471 }
2472
2473 =head2 _koha_marc_update_bib_ids
2474
2475 =over 4
2476
2477 _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
2478
2479 Internal function to add or update biblionumber and biblioitemnumber to
2480 the MARC XML.
2481
2482 =back
2483
2484 =cut
2485
2486 sub _koha_marc_update_bib_ids {
2487     my ($record, $frameworkcode, $biblionumber, $biblioitemnumber) = @_;
2488
2489     # we must add bibnum and bibitemnum in MARC::Record...
2490     # we build the new field with biblionumber and biblioitemnumber
2491     # we drop the original field
2492     # we add the new builded field.
2493     my ($biblio_tag, $biblio_subfield ) = GetMarcFromKohaField("biblio.biblionumber",$frameworkcode);
2494     my ($biblioitem_tag, $biblioitem_subfield ) = GetMarcFromKohaField("biblioitems.biblioitemnumber",$frameworkcode);
2495
2496     if ($biblio_tag != $biblioitem_tag) {
2497         # biblionumber & biblioitemnumber are in different fields
2498
2499         # deal with biblionumber
2500         my ($new_field, $old_field);
2501         if ($biblio_tag < 10) {
2502             $new_field = MARC::Field->new( $biblio_tag, $biblionumber );
2503         } else {
2504             $new_field =
2505               MARC::Field->new( $biblio_tag, '', '',
2506                 "$biblio_subfield" => $biblionumber );
2507         }
2508
2509         # drop old field and create new one...
2510         $old_field = $record->field($biblio_tag);
2511         $record->delete_field($old_field) if $old_field;
2512         $record->append_fields($new_field);
2513
2514         # deal with biblioitemnumber
2515         if ($biblioitem_tag < 10) {
2516             $new_field = MARC::Field->new( $biblioitem_tag, $biblioitemnumber, );
2517         } else {
2518             $new_field =
2519               MARC::Field->new( $biblioitem_tag, '', '',
2520                 "$biblioitem_subfield" => $biblioitemnumber, );
2521         }
2522         # drop old field and create new one...
2523         $old_field = $record->field($biblioitem_tag);
2524         $record->delete_field($old_field) if $old_field;
2525         $record->insert_fields_ordered($new_field);
2526
2527     } else {
2528         # biblionumber & biblioitemnumber are in the same field (can't be <10 as fields <10 have only 1 value)
2529         my $new_field = MARC::Field->new(
2530             $biblio_tag, '', '',
2531             "$biblio_subfield" => $biblionumber,
2532             "$biblioitem_subfield" => $biblioitemnumber
2533         );
2534
2535         # drop old field and create new one...
2536         my $old_field = $record->field($biblio_tag);
2537         $record->delete_field($old_field) if $old_field;
2538         $record->insert_fields_ordered($new_field);
2539     }
2540 }
2541
2542 =head2 _koha_marc_update_biblioitem_cn_sort
2543
2544 =over 4
2545
2546 _koha_marc_update_biblioitem_cn_sort($marc, $biblioitem, $frameworkcode);
2547
2548 =back
2549
2550 Given a MARC bib record and the biblioitem hash, update the
2551 subfield that contains a copy of the value of biblioitems.cn_sort.
2552
2553 =cut
2554
2555 sub _koha_marc_update_biblioitem_cn_sort {
2556     my $marc = shift;
2557     my $biblioitem = shift;
2558     my $frameworkcode= shift;
2559
2560     my ($biblioitem_tag, $biblioitem_subfield ) = GetMarcFromKohaField("biblioitems.cn_sort",$frameworkcode);
2561     return unless $biblioitem_tag;
2562
2563     my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
2564
2565     if (my $field = $marc->field($biblioitem_tag)) {
2566         $field->delete_subfield(code => $biblioitem_subfield);
2567         if ($cn_sort ne '') {
2568             $field->add_subfields($biblioitem_subfield => $cn_sort);
2569         }
2570     } else {
2571         # if we get here, no biblioitem tag is present in the MARC record, so
2572         # we'll create it if $cn_sort is not empty -- this would be
2573         # an odd combination of events, however
2574         if ($cn_sort) {
2575             $marc->insert_grouped_field(MARC::Field->new($biblioitem_tag, ' ', ' ', $biblioitem_subfield => $cn_sort));
2576         }
2577     }
2578 }
2579
2580 =head2 _koha_add_biblio
2581
2582 =over 4
2583
2584 my ($biblionumber,$error) = _koha_add_biblio($dbh,$biblioitem);
2585
2586 Internal function to add a biblio ($biblio is a hash with the values)
2587
2588 =back
2589
2590 =cut
2591
2592 sub _koha_add_biblio {
2593     my ( $dbh, $biblio, $frameworkcode ) = @_;
2594
2595     my $error;
2596
2597     # set the series flag
2598     my $serial = 0;
2599     if ( $biblio->{'seriestitle'} ) { $serial = 1 };
2600
2601     my $query = 
2602         "INSERT INTO biblio
2603         SET frameworkcode = ?,
2604             author = ?,
2605             title = ?,
2606             unititle =?,
2607             notes = ?,
2608             serial = ?,
2609             seriestitle = ?,
2610             copyrightdate = ?,
2611             datecreated=NOW(),
2612             abstract = ?
2613         ";
2614     my $sth = $dbh->prepare($query);
2615     $sth->execute(
2616         $frameworkcode,
2617         $biblio->{'author'},
2618         $biblio->{'title'},
2619         $biblio->{'unititle'},
2620         $biblio->{'notes'},
2621         $serial,
2622         $biblio->{'seriestitle'},
2623         $biblio->{'copyrightdate'},
2624         $biblio->{'abstract'}
2625     );
2626
2627     my $biblionumber = $dbh->{'mysql_insertid'};
2628     if ( $dbh->errstr ) {
2629         $error.="ERROR in _koha_add_biblio $query".$dbh->errstr;
2630         warn $error;
2631     }
2632
2633     $sth->finish();
2634     #warn "LEAVING _koha_add_biblio: ".$biblionumber."\n";
2635     return ($biblionumber,$error);
2636 }
2637
2638 =head2 _koha_modify_biblio
2639
2640 =over 4
2641
2642 my ($biblionumber,$error) == _koha_modify_biblio($dbh,$biblio,$frameworkcode);
2643
2644 Internal function for updating the biblio table
2645
2646 =back
2647
2648 =cut
2649
2650 sub _koha_modify_biblio {
2651     my ( $dbh, $biblio, $frameworkcode ) = @_;
2652     my $error;
2653
2654     my $query = "
2655         UPDATE biblio
2656         SET    frameworkcode = ?,
2657                author = ?,
2658                title = ?,
2659                unititle = ?,
2660                notes = ?,
2661                serial = ?,
2662                seriestitle = ?,
2663                copyrightdate = ?,
2664                abstract = ?
2665         WHERE  biblionumber = ?
2666         "
2667     ;
2668     my $sth = $dbh->prepare($query);
2669     
2670     $sth->execute(
2671         $frameworkcode,
2672         $biblio->{'author'},
2673         $biblio->{'title'},
2674         $biblio->{'unititle'},
2675         $biblio->{'notes'},
2676         $biblio->{'serial'},
2677         $biblio->{'seriestitle'},
2678         $biblio->{'copyrightdate'},
2679         $biblio->{'abstract'},
2680         $biblio->{'biblionumber'}
2681     ) if $biblio->{'biblionumber'};
2682
2683     if ( $dbh->errstr || !$biblio->{'biblionumber'} ) {
2684         $error.="ERROR in _koha_modify_biblio $query".$dbh->errstr;
2685         warn $error;
2686     }
2687     return ( $biblio->{'biblionumber'},$error );
2688 }
2689
2690 =head2 _koha_modify_biblioitem_nonmarc
2691
2692 =over 4
2693
2694 my ($biblioitemnumber,$error) = _koha_modify_biblioitem_nonmarc( $dbh, $biblioitem );
2695
2696 Updates biblioitems row except for marc and marcxml, which should be changed
2697 via ModBiblioMarc
2698
2699 =back
2700
2701 =cut
2702
2703 sub _koha_modify_biblioitem_nonmarc {
2704     my ( $dbh, $biblioitem ) = @_;
2705     my $error;
2706
2707     # re-calculate the cn_sort, it may have changed
2708     my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
2709
2710     my $query = 
2711     "UPDATE biblioitems 
2712     SET biblionumber    = ?,
2713         volume          = ?,
2714         number          = ?,
2715         itemtype        = ?,
2716         isbn            = ?,
2717         issn            = ?,
2718         publicationyear = ?,
2719         publishercode   = ?,
2720         volumedate      = ?,
2721         volumedesc      = ?,
2722         collectiontitle = ?,
2723         collectionissn  = ?,
2724         collectionvolume= ?,
2725         editionstatement= ?,
2726         editionresponsibility = ?,
2727         illus           = ?,
2728         pages           = ?,
2729         notes           = ?,
2730         size            = ?,
2731         place           = ?,
2732         lccn            = ?,
2733         url             = ?,
2734         cn_source       = ?,
2735         cn_class        = ?,
2736         cn_item         = ?,
2737         cn_suffix       = ?,
2738         cn_sort         = ?,
2739         totalissues     = ?
2740         where biblioitemnumber = ?
2741         ";
2742     my $sth = $dbh->prepare($query);
2743     $sth->execute(
2744         $biblioitem->{'biblionumber'},
2745         $biblioitem->{'volume'},
2746         $biblioitem->{'number'},
2747         $biblioitem->{'itemtype'},
2748         $biblioitem->{'isbn'},
2749         $biblioitem->{'issn'},
2750         $biblioitem->{'publicationyear'},
2751         $biblioitem->{'publishercode'},
2752         $biblioitem->{'volumedate'},
2753         $biblioitem->{'volumedesc'},
2754         $biblioitem->{'collectiontitle'},
2755         $biblioitem->{'collectionissn'},
2756         $biblioitem->{'collectionvolume'},
2757         $biblioitem->{'editionstatement'},
2758         $biblioitem->{'editionresponsibility'},
2759         $biblioitem->{'illus'},
2760         $biblioitem->{'pages'},
2761         $biblioitem->{'bnotes'},
2762         $biblioitem->{'size'},
2763         $biblioitem->{'place'},
2764         $biblioitem->{'lccn'},
2765         $biblioitem->{'url'},
2766         $biblioitem->{'biblioitems.cn_source'},
2767         $biblioitem->{'cn_class'},
2768         $biblioitem->{'cn_item'},
2769         $biblioitem->{'cn_suffix'},
2770         $cn_sort,
2771         $biblioitem->{'totalissues'},
2772         $biblioitem->{'biblioitemnumber'}
2773     );
2774     if ( $dbh->errstr ) {
2775         $error.="ERROR in _koha_modify_biblioitem_nonmarc $query".$dbh->errstr;
2776         warn $error;
2777     }
2778     return ($biblioitem->{'biblioitemnumber'},$error);
2779 }
2780
2781 =head2 _koha_add_biblioitem
2782
2783 =over 4
2784
2785 my ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $biblioitem );
2786
2787 Internal function to add a biblioitem
2788
2789 =back
2790
2791 =cut
2792
2793 sub _koha_add_biblioitem {
2794     my ( $dbh, $biblioitem ) = @_;
2795     my $error;
2796
2797     my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
2798     my $query =
2799     "INSERT INTO biblioitems SET
2800         biblionumber    = ?,
2801         volume          = ?,
2802         number          = ?,
2803         itemtype        = ?,
2804         isbn            = ?,
2805         issn            = ?,
2806         publicationyear = ?,
2807         publishercode   = ?,
2808         volumedate      = ?,
2809         volumedesc      = ?,
2810         collectiontitle = ?,
2811         collectionissn  = ?,
2812         collectionvolume= ?,
2813         editionstatement= ?,
2814         editionresponsibility = ?,
2815         illus           = ?,
2816         pages           = ?,
2817         notes           = ?,
2818         size            = ?,
2819         place           = ?,
2820         lccn            = ?,
2821         marc            = ?,
2822         url             = ?,
2823         cn_source       = ?,
2824         cn_class        = ?,
2825         cn_item         = ?,
2826         cn_suffix       = ?,
2827         cn_sort         = ?,
2828         totalissues     = ?
2829         ";
2830     my $sth = $dbh->prepare($query);
2831     $sth->execute(
2832         $biblioitem->{'biblionumber'},
2833         $biblioitem->{'volume'},
2834         $biblioitem->{'number'},
2835         $biblioitem->{'itemtype'},
2836         $biblioitem->{'isbn'},
2837         $biblioitem->{'issn'},
2838         $biblioitem->{'publicationyear'},
2839         $biblioitem->{'publishercode'},
2840         $biblioitem->{'volumedate'},
2841         $biblioitem->{'volumedesc'},
2842         $biblioitem->{'collectiontitle'},
2843         $biblioitem->{'collectionissn'},
2844         $biblioitem->{'collectionvolume'},
2845         $biblioitem->{'editionstatement'},
2846         $biblioitem->{'editionresponsibility'},
2847         $biblioitem->{'illus'},
2848         $biblioitem->{'pages'},
2849         $biblioitem->{'bnotes'},
2850         $biblioitem->{'size'},
2851         $biblioitem->{'place'},
2852         $biblioitem->{'lccn'},
2853         $biblioitem->{'marc'},
2854         $biblioitem->{'url'},
2855         $biblioitem->{'biblioitems.cn_source'},
2856         $biblioitem->{'cn_class'},
2857         $biblioitem->{'cn_item'},
2858         $biblioitem->{'cn_suffix'},
2859         $cn_sort,
2860         $biblioitem->{'totalissues'}
2861     );
2862     my $bibitemnum = $dbh->{'mysql_insertid'};
2863     if ( $dbh->errstr ) {
2864         $error.="ERROR in _koha_add_biblioitem $query".$dbh->errstr;
2865         warn $error;
2866     }
2867     $sth->finish();
2868     return ($bibitemnum,$error);
2869 }
2870
2871 =head2 _koha_delete_biblio
2872
2873 =over 4
2874
2875 $error = _koha_delete_biblio($dbh,$biblionumber);
2876
2877 Internal sub for deleting from biblio table -- also saves to deletedbiblio
2878
2879 C<$dbh> - the database handle
2880 C<$biblionumber> - the biblionumber of the biblio to be deleted
2881
2882 =back
2883
2884 =cut
2885
2886 # FIXME: add error handling
2887
2888 sub _koha_delete_biblio {
2889     my ( $dbh, $biblionumber ) = @_;
2890
2891     # get all the data for this biblio
2892     my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber=?");
2893     $sth->execute($biblionumber);
2894
2895     if ( my $data = $sth->fetchrow_hashref ) {
2896
2897         # save the record in deletedbiblio
2898         # find the fields to save
2899         my $query = "INSERT INTO deletedbiblio SET ";
2900         my @bind  = ();
2901         foreach my $temp ( keys %$data ) {
2902             $query .= "$temp = ?,";
2903             push( @bind, $data->{$temp} );
2904         }
2905
2906         # replace the last , by ",?)"
2907         $query =~ s/\,$//;
2908         my $bkup_sth = $dbh->prepare($query);
2909         $bkup_sth->execute(@bind);
2910         $bkup_sth->finish;
2911
2912         # delete the biblio
2913         my $del_sth = $dbh->prepare("DELETE FROM biblio WHERE biblionumber=?");
2914         $del_sth->execute($biblionumber);
2915         $del_sth->finish;
2916     }
2917     $sth->finish;
2918     return undef;
2919 }
2920
2921 =head2 _koha_delete_biblioitems
2922
2923 =over 4
2924
2925 $error = _koha_delete_biblioitems($dbh,$biblioitemnumber);
2926
2927 Internal sub for deleting from biblioitems table -- also saves to deletedbiblioitems
2928
2929 C<$dbh> - the database handle
2930 C<$biblionumber> - the biblioitemnumber of the biblioitem to be deleted
2931
2932 =back
2933
2934 =cut
2935
2936 # FIXME: add error handling
2937
2938 sub _koha_delete_biblioitems {
2939     my ( $dbh, $biblioitemnumber ) = @_;
2940
2941     # get all the data for this biblioitem
2942     my $sth =
2943       $dbh->prepare("SELECT * FROM biblioitems WHERE biblioitemnumber=?");
2944     $sth->execute($biblioitemnumber);
2945
2946     if ( my $data = $sth->fetchrow_hashref ) {
2947
2948         # save the record in deletedbiblioitems
2949         # find the fields to save
2950         my $query = "INSERT INTO deletedbiblioitems SET ";
2951         my @bind  = ();
2952         foreach my $temp ( keys %$data ) {
2953             $query .= "$temp = ?,";
2954             push( @bind, $data->{$temp} );
2955         }
2956
2957         # replace the last , by ",?)"
2958         $query =~ s/\,$//;
2959         my $bkup_sth = $dbh->prepare($query);
2960         $bkup_sth->execute(@bind);
2961         $bkup_sth->finish;
2962
2963         # delete the biblioitem
2964         my $del_sth =
2965           $dbh->prepare("DELETE FROM biblioitems WHERE biblioitemnumber=?");
2966         $del_sth->execute($biblioitemnumber);
2967         $del_sth->finish;
2968     }
2969     $sth->finish;
2970     return undef;
2971 }
2972
2973 =head1 UNEXPORTED FUNCTIONS
2974
2975 =head2 ModBiblioMarc
2976
2977     &ModBiblioMarc($newrec,$biblionumber,$frameworkcode);
2978     
2979     Add MARC data for a biblio to koha 
2980     
2981     Function exported, but should NOT be used, unless you really know what you're doing
2982
2983 =cut
2984
2985 sub ModBiblioMarc {
2986     
2987 # pass the MARC::Record to this function, and it will create the records in the marc field
2988     my ( $record, $biblionumber, $frameworkcode ) = @_;
2989     my $dbh = C4::Context->dbh;
2990     my @fields = $record->fields();
2991     if ( !$frameworkcode ) {
2992         $frameworkcode = "";
2993     }
2994     my $sth =
2995       $dbh->prepare("UPDATE biblio SET frameworkcode=? WHERE biblionumber=?");
2996     $sth->execute( $frameworkcode, $biblionumber );
2997     $sth->finish;
2998     my $encoding = C4::Context->preference("marcflavour");
2999
3000     # deal with UNIMARC field 100 (encoding) : create it if needed & set encoding to unicode
3001     if ( $encoding eq "UNIMARC" ) {
3002         my $string;
3003         if ( length($record->subfield( 100, "a" )) == 35 ) {
3004             $string = $record->subfield( 100, "a" );
3005             my $f100 = $record->field(100);
3006             $record->delete_field($f100);
3007         }
3008         else {
3009             $string = POSIX::strftime( "%Y%m%d", localtime );
3010             $string =~ s/\-//g;
3011             $string = sprintf( "%-*s", 35, $string );
3012         }
3013         substr( $string, 22, 6, "frey50" );
3014         unless ( $record->subfield( 100, "a" ) ) {
3015             $record->insert_grouped_field(
3016                 MARC::Field->new( 100, "", "", "a" => $string ) );
3017         }
3018     }
3019     my $oldRecord;
3020     if (C4::Context->preference("NoZebra")) {
3021         # only NoZebra indexing needs to have
3022         # the previous version of the record
3023         $oldRecord = GetMarcBiblio($biblionumber);
3024     }
3025     $sth =
3026       $dbh->prepare(
3027         "UPDATE biblioitems SET marc=?,marcxml=? WHERE biblionumber=?");
3028     $sth->execute( $record->as_usmarc(), $record->as_xml_record($encoding),
3029         $biblionumber );
3030     $sth->finish;
3031     ModZebra($biblionumber,"specialUpdate","biblioserver",$oldRecord,$record);
3032     return $biblionumber;
3033 }
3034
3035 =head2 z3950_extended_services
3036
3037 z3950_extended_services($serviceType,$serviceOptions,$record);
3038
3039     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.
3040
3041 C<$serviceType> one of: itemorder,create,drop,commit,update,xmlupdate
3042
3043 C<$serviceOptions> a has of key/value pairs. For instance, if service_type is 'update', $service_options should contain:
3044
3045     action => update action, one of specialUpdate, recordInsert, recordReplace, recordDelete, elementUpdate.
3046
3047 and maybe
3048
3049     recordidOpaque => Opaque Record ID (user supplied) or recordidNumber => Record ID number (system number).
3050     syntax => the record syntax (transfer syntax)
3051     databaseName = Database from connection object
3052
3053     To set serviceOptions, call set_service_options($serviceType)
3054
3055 C<$record> the record, if one is needed for the service type
3056
3057     A record should be in XML. You can convert it to XML from MARC by running it through marc2xml().
3058
3059 =cut
3060
3061 sub z3950_extended_services {
3062     my ( $server, $serviceType, $action, $serviceOptions ) = @_;
3063
3064     # get our connection object
3065     my $Zconn = C4::Context->Zconn( $server, 0, 1 );
3066
3067     # create a new package object
3068     my $Zpackage = $Zconn->package();
3069
3070     # set our options
3071     $Zpackage->option( action => $action );
3072
3073     if ( $serviceOptions->{'databaseName'} ) {
3074         $Zpackage->option( databaseName => $serviceOptions->{'databaseName'} );
3075     }
3076     if ( $serviceOptions->{'recordIdNumber'} ) {
3077         $Zpackage->option(
3078             recordIdNumber => $serviceOptions->{'recordIdNumber'} );
3079     }
3080     if ( $serviceOptions->{'recordIdOpaque'} ) {
3081         $Zpackage->option(
3082             recordIdOpaque => $serviceOptions->{'recordIdOpaque'} );
3083     }
3084
3085  # this is an ILL request (Zebra doesn't support it, but Koha could eventually)
3086  #if ($serviceType eq 'itemorder') {
3087  #   $Zpackage->option('contact-name' => $serviceOptions->{'contact-name'});
3088  #   $Zpackage->option('contact-phone' => $serviceOptions->{'contact-phone'});
3089  #   $Zpackage->option('contact-email' => $serviceOptions->{'contact-email'});
3090  #   $Zpackage->option('itemorder-item' => $serviceOptions->{'itemorder-item'});
3091  #}
3092
3093     if ( $serviceOptions->{record} ) {
3094         $Zpackage->option( record => $serviceOptions->{record} );
3095
3096         # can be xml or marc
3097         if ( $serviceOptions->{'syntax'} ) {
3098             $Zpackage->option( syntax => $serviceOptions->{'syntax'} );
3099         }
3100     }
3101
3102     # send the request, handle any exception encountered
3103     eval { $Zpackage->send($serviceType) };
3104     if ( $@ && $@->isa("ZOOM::Exception") ) {
3105         return "error:  " . $@->code() . " " . $@->message() . "\n";
3106     }
3107
3108     # free up package resources
3109     $Zpackage->destroy();
3110 }
3111
3112 =head2 set_service_options
3113
3114 my $serviceOptions = set_service_options($serviceType);
3115
3116 C<$serviceType> itemorder,create,drop,commit,update,xmlupdate
3117
3118 Currently, we only support 'create', 'commit', and 'update'. 'drop' support will be added as soon as Zebra supports it.
3119
3120 =cut
3121
3122 sub set_service_options {
3123     my ($serviceType) = @_;
3124     my $serviceOptions;
3125
3126 # FIXME: This needs to be an OID ... if we ever need 'syntax' this sub will need to change
3127 #   $serviceOptions->{ 'syntax' } = ''; #zebra doesn't support syntaxes other than xml
3128
3129     if ( $serviceType eq 'commit' ) {
3130
3131         # nothing to do
3132     }
3133     if ( $serviceType eq 'create' ) {
3134
3135         # nothing to do
3136     }
3137     if ( $serviceType eq 'drop' ) {
3138         die "ERROR: 'drop' not currently supported (by Zebra)";
3139     }
3140     return $serviceOptions;
3141 }
3142
3143 =head3 get_biblio_authorised_values
3144
3145   find the types and values for all authorised values assigned to this biblio.
3146
3147   parameters:
3148     biblionumber
3149
3150   returns: a hashref malling the authorised value to the value set for this biblionumber
3151
3152       $authorised_values = {
3153                              'Scent'     => 'flowery',
3154                              'Audience'  => 'Young Adult',
3155                              'itemtypes' => 'SER',
3156                            };
3157
3158   Notes: forlibrarian should probably be passed in, and called something different.
3159
3160
3161 =cut
3162
3163 sub get_biblio_authorised_values {
3164     my $biblionumber = shift;
3165     
3166     my $forlibrarian = 1; # are we in staff or opac?
3167     my $frameworkcode = GetFrameworkCode( $biblionumber );
3168
3169     my $authorised_values;
3170
3171     my $record  = GetMarcBiblio( $biblionumber )
3172       or return $authorised_values;
3173     my $tagslib = GetMarcStructure( $forlibrarian, $frameworkcode )
3174       or return $authorised_values;
3175
3176     # assume that these entries in the authorised_value table are bibliolevel.
3177     # ones that start with 'item%' are item level.
3178     my $query = q(SELECT distinct authorised_value, kohafield
3179                     FROM marc_subfield_structure
3180                     WHERE authorised_value !=''
3181                       AND (kohafield like 'biblio%'
3182                        OR  kohafield like '') );
3183     my $bibliolevel_authorised_values = C4::Context->dbh->selectall_hashref( $query, 'authorised_value' );
3184     
3185     foreach my $tag ( keys( %$tagslib ) ) {
3186         foreach my $subfield ( keys( %{$tagslib->{ $tag }} ) ) {
3187             # warn "checking $subfield. type is: " . ref $tagslib->{ $tag }{ $subfield };
3188             if ( 'HASH' eq ref $tagslib->{ $tag }{ $subfield } ) {
3189                 if ( defined $tagslib->{ $tag }{ $subfield }{'authorised_value'} && exists $bibliolevel_authorised_values->{ $tagslib->{ $tag }{ $subfield }{'authorised_value'} } ) {
3190                     if ( defined $record->field( $tag ) ) {
3191                         my $this_subfield_value = $record->field( $tag )->subfield( $subfield );
3192                         if ( defined $this_subfield_value ) {
3193                             $authorised_values->{ $tagslib->{ $tag }{ $subfield }{'authorised_value'} } = $this_subfield_value;
3194                         }
3195                     }
3196                 }
3197             }
3198         }
3199     }
3200     # warn ( Data::Dumper->Dump( [ $authorised_values ], [ 'authorised_values' ] ) );
3201     return $authorised_values;
3202 }
3203
3204
3205 1;
3206
3207 __END__
3208
3209 =head1 AUTHOR
3210
3211 Koha Developement team <info@koha.org>
3212
3213 Paul POULAIN paul.poulain@free.fr
3214
3215 Joshua Ferraro jmf@liblime.com
3216
3217 =cut