MARCXML only. No more MARC record. No more non-marc handling
[koha.git] / cataloguing / additem.pl
1 #!/usr/bin/perl
2
3 # $Id$
4
5 # Copyright 2000-2002 Katipo Communications
6 #
7 # This file is part of Koha.
8 #
9 # Koha is free software; you can redistribute it and/or modify it under the
10 # terms of the GNU General Public License as published by the Free Software
11 # Foundation; either version 2 of the License, or (at your option) any later
12 # version.
13 #
14 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License along with
19 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
20 # Suite 330, Boston, MA  02111-1307 USA
21
22 use CGI;
23 use strict;
24 use C4::Auth;
25 use C4::Output;
26 use C4::Interface::CGI::Output;
27 use C4::Biblio;
28 use C4::Context;
29 use C4::Koha; # XXX subfield_is_koha_internal_p
30 use C4::Search;
31 use C4::Circulation::Circ2;
32 use Encode;
33 use C4::Log;
34
35 my $logstatus=C4::Context->preference('Activate_log');
36
37 sub find_value {
38         my ($tagfield,$insubfield,$record) = @_;
39         my $result;
40         my $indicator;
41 my $item=$record->{datafield};
42 my $controlfield=$record->{controlfield};
43 my $leader=$record->{leader};
44  if ($tagfield eq '000'){
45 ## We are getting the leader
46 $result=$leader->[0];
47 return($indicator,$result);
48 }
49      if ($tagfield <10){
50         foreach my $control (@$controlfield) {
51                 if ($control->{tag} eq $tagfield){
52                 $result.=$control->{content};
53                 }
54         }
55       }else{
56         foreach my $field (@$item) {            
57               if ($field->{tag} eq $tagfield){  
58                     foreach my $subfield ( $field->{'subfield'}){
59                        foreach my $code ( @$subfield){
60                         if ($code->{code} eq $insubfield) {
61                                 $result .= $code->{content};
62                                 $indicator = $field->{ind1}.$field->{ind2};
63                         }
64                       }## each code
65                   }##each subfield
66               }## if tag
67         }### $field
68      }## tag<10
69         return($indicator,$result);
70 }
71 my $input = new CGI;
72 my $dbh = C4::Context->dbh;
73 my $error = $input->param('error');
74 my $biblionumber = $input->param('biblionumber');
75 my $oldbiblionumber =$biblionumber;
76 my $frameworkcode=$input->param('frameworkcode');
77 my $op = $input->param('op');
78 my $itemnumber = $input->param('itemnumber');
79 my $fromserials=$input->param('fromserials');## if a serial is being added do not display navigation menus
80 my $serialid=$input->param('serialid');
81 my @itemrecords; ##Builds existing items
82 my $bibliorecord; #Bibliorecord relared to this item
83 my $newrecord; ## the new record buing built
84 my $itemrecexist; #item record we are editing
85 my $xml; ## data on html
86  $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber) unless $frameworkcode;
87 my $tagslib = &MARCitemsgettagslib($dbh,1,$frameworkcode);
88 my $itemrecord;
89 my $nextop="additem";
90 my @errors; # store errors found while checking data BEFORE saving item.
91
92 ###DO NOT CHANGE TO RETRIVE FROM ZEBRA#####
93 my $record =XMLgetbiblio($dbh,$biblionumber);
94 $bibliorecord=XML_xml2hash_onerecord($record);
95 my @itemxmls=XMLgetallitems($dbh,$biblionumber);
96         foreach my $itemrecord(@itemxmls){
97         my $itemhash=XML_xml2hash($itemrecord);
98         push @itemrecords, $itemhash;
99         }
100 ####
101
102 my ($template, $loggedinuser, $cookie)
103     = get_template_and_user({template_name => "cataloguing/additem.tmpl",
104                              query => $input,
105                              type => "intranet",
106                              authnotrequired => 0,
107                              flagsrequired => {editcatalogue => 1},
108                              debug => 1,
109                              });
110
111 #------------------------------------------------------------------------------------------------------------------------------
112 if ($op eq "additem") {
113 #------------------------------------------------------------------------------------------------------------------------------
114         # rebuild
115
116         my @tags = $input->param('tag');
117         my @subfields = $input->param('subfield');
118         my @values = $input->param('field_value');
119         # build indicator hash.
120         my @ind_tag = $input->param('ind_tag');
121         my @indicator = $input->param('indicator');
122         my %indicators;
123         for (my $i=0;$i<=$#ind_tag;$i++) {
124                 $indicators{$ind_tag[$i]} = $indicator[$i];
125         }
126 ## check for malformed xml -- non UTF-8 like (MARC8) will break xml without warning
127 ### This usually happens with data coming from other Z3950 servers
128 ## Slows the saving process so comment out at your own risk
129 eval{
130  $xml = MARChtml2xml(\@tags,\@subfields,\@values,\@indicator,\@ind_tag);        
131 };
132  if ($@){
133 push @errors,"non_utf8" ;
134 $nextop = "additem";
135 goto FINAL;
136   };
137  my $newrecord=XML_xml2hash_onerecord($xml);
138 my $newbarcode=XML_readline_onerecord($newrecord,"barcode","holdings"); 
139
140         # if autoBarcode is ON, calculate barcode...
141         if (C4::Context->preference('autoBarcode')) {   
142                 unless ($newbarcode) {
143                         my $sth_barcode = $dbh->prepare("select max(abs(barcode)) from items");
144                         $sth_barcode->execute;
145                         ($newbarcode) = $sth_barcode->fetchrow;
146                         $newbarcode++;
147                         # OK, we have the new barcode, now create the entry in MARC record
148                         $newrecord=XML_writeline( $newrecord, "barcode", $newbarcode,"holdings" );
149                 }
150         }
151 # check for item barcode # being unique
152         my ($oldrecord)=XMLgetitem($dbh,"",$newbarcode);
153         
154         push @errors,"barcode_not_unique" if($oldrecord);
155 # MARC::Record builded => now, record in DB
156 ## User may be keeping serialids in marc records -- check and add it 
157 if ($fromserials){
158 $newrecord=XML_writeline( $newrecord, "serialid", $serialid,"holdings" );
159 }
160         # if barcode exists, don't create, but report the problem.
161         unless ($oldrecord){
162           $itemnumber=NEWnewitem($dbh,$newrecord,$biblionumber) ;
163                 if ($fromserials){
164                 my $holdingbranch=XML_readline_onerecord($newrecord,"holdingbranch","holdings");        
165                 $template->param(exit=>1,holdingbranch=>$holdingbranch);
166                 }
167         $nextop = "additem";
168         }
169         else{
170                 $nextop = "additem";
171                 $itemrecexist = $newrecord;
172         } 
173 #------------------------------------------------------------------------------------------------------------------------------
174 } elsif ($op eq "edititem") {
175 #------------------------------------------------------------------------------------------------------------------------------
176 # retrieve item if exist => then, it's a modif
177          ($itemrecexist) = XMLfinditem($itemnumber,@itemrecords);## item is already in our array-getit
178         $nextop="saveitem";
179         
180 #logaction($loggedinuser,"acqui.simple","modify",$oldbiblionumber,"item : ".$itemnumber) if ($logstatus);
181         
182 #------------------------------------------------------------------------------------------------------------------------------
183 } elsif ($op eq "delitem") {
184 #------------------------------------------------------------------------------------------------------------------------------
185 # retrieve item if exist => then, it's a modif
186 my $sth=$dbh->prepare("select * from issues i where i.returndate is null and i.itemnumber=?");
187  $sth->execute($itemnumber);
188 my $onloan=$sth->fetchrow;
189 push @errors,"book_on_loan" if ($onloan);
190         if ($onloan){
191         $nextop = "additem";
192 }else{
193         &NEWdelitem($dbh,$itemnumber);
194         $nextop="additem";
195 }
196 #------------------------------------------------------------------------------------------------------------------------------
197 } elsif ($op eq "saveitem") {
198 #------------------------------------------------------------------------------------------------------------------------------
199         # rebuild
200 #warn "save item";
201         my @tags = $input->param('tag');
202         my @subfields = $input->param('subfield');
203         my @values = $input->param('field_value');
204         # build indicator hash.
205         my @ind_tag = $input->param('ind_tag');
206         my @indicator = $input->param('indicator');
207         my $itemnumber = $input->param('itemnumber');
208         my %indicators;
209         for (my $i=0;$i<=$#ind_tag;$i++) {
210                 $indicators{$ind_tag[$i]} = $indicator[$i];
211         }
212 ## check for malformed xml -- non UTF-8 like (MARC8) will break xml without warning
213 ### This usually happens with data coming from other Z3950 servers
214 ## Slows the saving process so comment out at your own risk
215 eval{
216  $xml = MARChtml2xml(\@tags,\@subfields,\@values,\@indicator,\@ind_tag);        
217 };
218          if ($@){
219 push @errors,"non_utf8" ;
220 $nextop = "edititem";
221 goto FINAL;
222   };
223  my $newrecord=XML_xml2hash_onerecord($xml);
224         my $newbarcode=XML_readline_onerecord($newrecord,"barcode","holdings");
225         my ($oldrecord)=XMLgetitem($dbh,"",$newbarcode);
226         $oldrecord=XML_xml2hash_onerecord($oldrecord);
227         my $exist=XML_readline_onerecord($oldrecord,"itemnumber","holdings") if $oldrecord;
228         if ($exist && ($exist ne $itemnumber)){
229         push @errors,"barcode_not_unique" ; ## Although editing user may have changed the barcode
230         $nextop="edititem";
231         }else{
232          NEWmoditem($dbh,$newrecord,$biblionumber,$itemnumber);
233         $itemnumber="";
234         $nextop="additem";
235
236         }
237 }
238
239 #
240 #------------------------------------------------------------------------------------------------------------------------------
241 # build screen with existing items. and "new" one
242 #------------------------------------------------------------------------------------------------------------------------------
243 FINAL:
244 my %indicators;
245 $indicators{995}='  ';
246 # now, build existing item list
247
248
249
250 my ($itemtagfield,$itemtagsubfield) = &MARCfind_marc_from_kohafield("itemnumber","holdings");
251 my @itemnums;
252 my @fields;
253 my %witness; #---- stores the list of subfields used at least once, with the "meaning" of the code
254 my @big_array;
255 my @item_value_loop;
256 my @header_value_loop;
257 unless($fromserials){ ## do not display existing items if adding a serial. It could be a looong list
258 foreach my $itemrecord (@itemrecords){
259
260 my $item=$itemrecord->{datafield};
261 my $controlfield=$itemrecord->{controlfield};
262 my $leader=$itemrecord->{leader};
263 my %this_row;
264         ### The leader
265         unless ($tagslib->{'000'}->{'@'}->{tab}  ne 10 || substr($tagslib->{'000'}->{'@'}->{hidden},1,1)>0){
266         my @datasub='000@';
267         $witness{$datasub[0]} = $tagslib->{'000'}->{'@'}->{lib};
268         $this_row{$datasub[0]} =$leader->[0];
269         }## leader
270         foreach my $control (@$controlfield){
271                 push @itemnums,$control->{content} if ($control->{tag} eq $itemtagfield);
272                 next if ($tagslib->{$control->{tag}}->{'@'}->{tab}  ne 10);
273                 next if (substr($tagslib->{$control->{tag}}->{'@'}->{hidden},1,1)>0);   
274                                         
275                         my @datasub=$control->{tag}.'@';
276                         $witness{$datasub[0]} = $tagslib->{$control->{tag}}->{'@'}->{lib};
277                         $this_row{$datasub[0]} =$control->{content};                    
278         }## Controlfields 
279         foreach my $data (@$item){
280                 foreach my $subfield ( $data->{'subfield'}){
281                         foreach my $code ( @$subfield){ 
282                         # loop through each subfield                    
283                         push @itemnums,$code->{content} if ($data->{tag} eq $itemtagfield && $code->{code} eq $itemtagsubfield);
284                         next if ($tagslib->{$data->{tag}}->{$code->{code}}->{tab}  ne 10);
285                         next if (substr($tagslib->{$data->{tag}}->{$code->{code}}->{hidden},1,1)>0);
286                         $witness{$data->{tag}.$code->{code}} = $tagslib->{$data->{tag}}->{$code->{code}}->{lib};
287                         $this_row{$data->{tag}.$code->{code}} =$code->{content};
288                         }
289                         
290                 }# subfield
291         
292         }## each data
293         if (%this_row) {
294         push(@big_array, \%this_row);
295         }
296 }## each record
297 #fill big_row with missing datas
298 foreach my $subfield_code  (keys(%witness)) {
299         for (my $i=0;$i<=$#big_array;$i++) {
300                 $big_array[$i]{$subfield_code}="&nbsp;" unless ($big_array[$i]{$subfield_code});
301         }
302 }
303 # now, construct template !
304
305 for (my $i=0;$i<=$#big_array; $i++) {
306         my $items_data;
307         foreach my $subfield_code (sort keys(%witness)) {
308                 $items_data .="<td>".$big_array[$i]{$subfield_code}."</td>";
309         }
310         my %row_data;
311         $row_data{item_value} = $items_data;
312         $row_data{itemnumber} = $itemnums[$i];
313         push(@item_value_loop,\%row_data);
314 }
315 foreach my $subfield_code (sort keys(%witness)) {
316         my %header_value;
317         $header_value{header_value} = $witness{$subfield_code};
318         push(@header_value_loop, \%header_value);
319 }
320 }## unless from serials
321 # next item form
322 my @loop_data =();
323 my $i=0;
324 my $authorised_values_sth = $dbh->prepare("select authorised_value,lib from authorised_values where category=? order by lib");
325
326 foreach my $tag (sort keys %{$tagslib}) {
327  if ($itemtagfield <10){
328 next if($tag==$itemtagfield);
329 }
330         my $previous_tag = '';
331 # loop through each subfield
332         foreach my $subfield (sort keys %{$tagslib->{$tag}}) {
333                 next if subfield_is_koha_internal_p($subfield);
334                 next if ($tagslib->{$tag}->{$subfield}->{'tab'}  ne "10");
335                 next if  ($tagslib->{$tag} eq $itemtagfield && $tagslib->{$tag}->{$subfield} eq $itemtagsubfield);
336                 my %subfield_data;
337                 $subfield_data{tag}=$tag;
338                 $subfield_data{subfield}=$subfield;
339                 $subfield_data{marc_lib}="<span id=\"error$i\">".$tagslib->{$tag}->{$subfield}->{lib}."</span>";
340                 $subfield_data{mandatory}=$tagslib->{$tag}->{$subfield}->{mandatory};
341                 $subfield_data{repeatable}=$tagslib->{$tag}->{$subfield}->{repeatable};
342         $subfield_data{hidden}= "display:none" if (substr($tagslib->{$tag}->{$subfield}->{hidden},2,1)>0);
343         
344                 my ($x,$value);
345                 ($x,$value) = find_value($tag,$subfield,$itemrecexist) if ($itemrecexist);
346                 # search for itemcallnumber if applicable
347                 my ($itemcntag,$itemcntagsub)=MARCfind_marc_from_kohafield("itemcallnumber","holdings");
348                 if ($tag eq $itemcntag && $subfield eq $itemcntagsub && C4::Context->preference('itemcallnumber')) {
349                         my $CNtag = substr(C4::Context->preference('itemcallnumber'),0,3);
350                         my $CNsubfield = substr(C4::Context->preference('itemcallnumber'),3,1);
351                         my $CNsubfield2 = substr(C4::Context->preference('itemcallnumber'),4,1);
352                         my $temp1 = XML_readline_onerecord($bibliorecord,"","",$CNtag,$CNsubfield);
353                         my $temp2 = XML_readline_onerecord($bibliorecord,"","",$CNtag,$CNsubfield2);
354                         $value = $temp1.' '.$temp2;
355                         $value=~s/^\s+|\s+$//g;
356                         
357                 }
358                 if ($tagslib->{$tag}->{$subfield}->{authorised_value}) {
359                         my @authorised_values;
360                         my %authorised_lib;
361                         # builds list, depending on authorised value...
362                         #---- branch
363                         if ($tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
364                                 my $sth=$dbh->prepare("select branchcode,branchname from branches order by branchname");
365                                 $sth->execute;
366                                 push @authorised_values, "" unless ($tagslib->{$tag}->{$subfield}->{mandatory});
367                                 while (my ($branchcode,$branchname) = $sth->fetchrow_array) {
368                                         push @authorised_values, $branchcode;
369                                         $authorised_lib{$branchcode}=$branchname;
370                                 }
371                         #----- itemtypes
372                         } elsif ($tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes") {
373                                 my $sth=$dbh->prepare("select itemtype,description from itemtypes order by description");
374                                 $sth->execute;
375                                 push @authorised_values, "" unless ($tagslib->{$tag}->{$subfield}->{mandatory});
376                                 while (my ($itemtype,$description) = $sth->fetchrow_array) {
377                                         push @authorised_values, $itemtype;
378                                         $authorised_lib{$itemtype}=$description;
379                                 }
380                         #---- "true" authorised value
381                         } else {
382                                 $authorised_values_sth->execute($tagslib->{$tag}->{$subfield}->{authorised_value});
383                                 push @authorised_values, "" unless ($tagslib->{$tag}->{$subfield}->{mandatory});
384                                 while (my ($value,$lib) = $authorised_values_sth->fetchrow_array) {
385                                         push @authorised_values, $value;
386                                         $authorised_lib{$value}=$lib;
387                                 }
388                         }
389                         $subfield_data{marc_value}= CGI::scrolling_list(-name=>'field_value',
390                                                                                                                                                 -values=> \@authorised_values,
391                                                                                                                                                 -default=>"$value",                                                                                                                                             -labels => \%authorised_lib,                                                                                                                                            -size=>1,
392                                                                                                                                                 -multiple=>0,                                                                                           );
393                 } elsif ($tagslib->{$tag}->{$subfield}->{thesaurus_category}) {
394                         $subfield_data{marc_value}="<input type=\"text\" name=\"field_value\"  size=47 maxlength=255 DISABLE READONLY> <a href=\"javascript:Dopop('../authorities/auth_finder.pl?authtypecode=".$tagslib->{$tag}->{$subfield}->{authtypecode}."&index=$i',$i)\">...</a>";
395                         #"
396                 } elsif ($tagslib->{$tag}->{$subfield}->{'value_builder'}) {
397                 my $cgidir = C4::Context->intranetdir ."/cgi-bin/value_builder";
398                 unless (opendir(DIR, "$cgidir")) {
399                         $cgidir = C4::Context->intranetdir."/value_builder";
400                 } 
401                 my $plugin=$cgidir."/".$tagslib->{$tag}->{$subfield}->{'value_builder'}; 
402                 require $plugin;
403                 my $extended_param = plugin_parameters($dbh,$newrecord,$tagslib,$i,0);
404                 my ($function_name,$javascript) = plugin_javascript($dbh,$newrecord,$tagslib,$i,0);
405                 $subfield_data{marc_value}="<input type=\"text\" name=\"field_value\"  value=\"$value\" size=\"47\" maxlength=\"255\" DISABLE READONLY OnFocus=\"javascript:Focus$function_name($i)\" OnBlur=\"javascript:Blur$function_name($i)\"> <a href=\"javascript:Clic$function_name($i)\">...</a> $javascript";
406                 } else {
407                         $subfield_data{marc_value}="<input type=\"text\" name=\"field_value\" value=\"$value\" size=50 maxlength=255>";
408                 }
409 #               $subfield_data{marc_value}="<input type=\"text\" name=\"field_value\">";
410                 push(@loop_data, \%subfield_data);
411                 $i++
412         }
413 }
414
415
416 # what's the next op ? it's what we are not in : an add if we're editing, otherwise, and edit.
417 $template->param(item_loop => \@item_value_loop,
418                                                 item_header_loop => \@header_value_loop,
419                                                 biblionumber =>$biblionumber,
420                                                 title => &XML_readline_onerecord($bibliorecord,"title","biblios"),
421                                                 author => &XML_readline_onerecord($bibliorecord,"author","biblios"),
422                                                 item => \@loop_data,
423                                                 itemnumber => $itemnumber,
424                                                 itemtagfield => $itemtagfield,
425                                                 itemtagsubfield =>$itemtagsubfield,
426                                                 op => $nextop,
427                                                 opisadd => ($nextop eq "saveitem")?0:1,
428                                                 fromserials=>$fromserials, serialid=>$serialid,);
429 foreach my $error (@errors) {
430         $template->param($error => 1);
431
432 }
433 output_html_with_http_headers $input, $cookie, $template->output;
434
435 sub XMLfinditem {
436 my ($itemnumber,@itemrecords)=@_;
437 foreach my $record (@itemrecords){
438 my $inumber=XML_readline_onerecord($record,"itemnumber","holdings");
439         if ($inumber ==$itemnumber){
440         return $record;
441         }
442 }
443 }