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