Move checks of additem.pl to the API
[koha.git] / cataloguing / additem.pl
1 #!/usr/bin/perl
2
3
4 # Copyright 2000-2002 Katipo Communications
5 #
6 # This file is part of Koha.
7 #
8 # Koha is free software; you can redistribute it and/or modify it under the
9 # terms of the GNU General Public License as published by the Free Software
10 # Foundation; either version 2 of the License, or (at your option) any later
11 # version.
12 #
13 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
14 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License along with
18 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
19 # Suite 330, Boston, MA  02111-1307 USA
20
21 use CGI;
22 use strict;
23 use C4::Auth;
24 use C4::Output;
25 use C4::Biblio;
26 use C4::Items;
27 use C4::Context;
28 use C4::Koha; # XXX subfield_is_koha_internal_p
29 use C4::Branch; # XXX subfield_is_koha_internal_p
30 use C4::ClassSource;
31
32 use Date::Calc qw(Today);
33
34 use MARC::File::XML;
35
36 sub find_value {
37     my ($tagfield,$insubfield,$record) = @_;
38     my $result;
39     my $indicator;
40     foreach my $field ($record->field($tagfield)) {
41         my @subfields = $field->subfields();
42         foreach my $subfield (@subfields) {
43             if (@$subfield[0] eq $insubfield) {
44                 $result .= @$subfield[1];
45                 $indicator = $field->indicator(1).$field->indicator(2);
46             }
47         }
48     }
49     return($indicator,$result);
50 }
51
52 sub get_item_from_barcode {
53     my ($barcode)=@_;
54     my $dbh=C4::Context->dbh;
55     my $result;
56     my $rq=$dbh->prepare("SELECT itemnumber from items where items.barcode=?");
57     $rq->execute($barcode);
58     ($result)=$rq->fetchrow;
59     return($result);
60 }
61
62 my $input = new CGI;
63 my $dbh = C4::Context->dbh;
64 my $error = $input->param('error');
65 my $biblionumber = $input->param('biblionumber');
66 my $itemnumber = $input->param('itemnumber');
67 my $op = $input->param('op');
68
69 my ($template, $loggedinuser, $cookie)
70     = get_template_and_user({template_name => "cataloguing/additem.tmpl",
71                  query => $input,
72                  type => "intranet",
73                  authnotrequired => 0,
74                  flagsrequired => {editcatalogue => 1},
75                  debug => 1,
76                  });
77
78 # find itemtype
79 my $frameworkcode = &GetFrameworkCode($biblionumber);
80
81 my $tagslib = &GetMarcStructure(1,$frameworkcode);
82 my $record = GetMarcBiblio($biblionumber);
83 my $oldrecord = TransformMarcToKoha($dbh,$record);
84 my $itemrecord;
85 my $nextop="additem";
86 my @errors; # store errors found while checking data BEFORE saving item.
87 #-------------------------------------------------------------------------------
88 if ($op eq "additem") {
89 #-------------------------------------------------------------------------------
90     # rebuild
91     my @tags = $input->param('tag');
92     my @subfields = $input->param('subfield');
93     my @values = $input->param('field_value');
94     # build indicator hash.
95     my @ind_tag = $input->param('ind_tag');
96     my @indicator = $input->param('indicator');
97     my $xml = TransformHtmlToXml(\@tags,\@subfields,\@values,\@indicator,\@ind_tag, 'ITEM');
98         my $record=MARC::Record::new_from_xml($xml, 'UTF-8');
99     # if autoBarcode is set to 'incremental', calculate barcode...
100         # NOTE: This code is subject to change in 3.2 with the implemenation of ajax based autobarcode code
101         # NOTE: 'incremental' is the ONLY autoBarcode option available to those not using javascript
102     if (C4::Context->preference('autoBarcode') eq 'incremental') {
103         my ($tagfield,$tagsubfield) = &GetMarcFromKohaField("items.barcode",$frameworkcode);
104         unless ($record->field($tagfield)->subfield($tagsubfield)) {
105             my $sth_barcode = $dbh->prepare("select max(abs(barcode)) from items");
106             $sth_barcode->execute;
107             my ($newbarcode) = $sth_barcode->fetchrow;
108             $newbarcode++;
109             # OK, we have the new barcode, now create the entry in MARC record
110             my $fieldItem = $record->field($tagfield);
111             $record->delete_field($fieldItem);
112             $fieldItem->add_subfields($tagsubfield => $newbarcode);
113             $record->insert_fields_ordered($fieldItem);
114         }
115     }
116 # check for item barcode # being unique
117     my $addedolditem = TransformMarcToKoha($dbh,$record);
118     my $exist_itemnumber = get_item_from_barcode($addedolditem->{'barcode'});
119     push @errors,"barcode_not_unique" if($exist_itemnumber);
120     # if barcode exists, don't create, but report The problem.
121     my ($oldbiblionumber,$oldbibnum,$oldbibitemnum) = AddItemFromMarc($record,$biblionumber) unless ($exist_itemnumber);
122     if ($exist_itemnumber) {
123         $nextop = "additem";
124         $itemrecord = $record;
125     } else {
126         $nextop = "additem";
127     }
128 #-------------------------------------------------------------------------------
129 } elsif ($op eq "edititem") {
130 #-------------------------------------------------------------------------------
131 # retrieve item if exist => then, it's a modif
132     $itemrecord = C4::Items::GetMarcItem($biblionumber,$itemnumber);
133     $nextop="saveitem";
134 #-------------------------------------------------------------------------------
135 } elsif ($op eq "delitem") {
136 #-------------------------------------------------------------------------------
137     $error = &DelItemCheck($dbh,$biblionumber,$itemnumber);
138     if($error == 1){
139         print $input->redirect("additem.pl?biblionumber=$biblionumber&frameworkcode=$frameworkcode");
140     }else{
141         push @errors,$error;
142         $nextop="additem";
143     }
144 #-------------------------------------------------------------------------------
145 } elsif ($op eq "delallitems") {
146 #-------------------------------------------------------------------------------
147     my @biblioitems = &GetBiblioItemByBiblioNumber($biblionumber);
148     foreach my $biblioitem (@biblioitems){
149         my $items = &GetItemsByBiblioitemnumber($biblioitem->{biblioitemnumber});
150
151         foreach my $item (@$items){
152             &DelItem($dbh,$biblionumber,$item->{itemnumber});
153         }
154     }
155     print $input->redirect("/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=$biblionumber");
156 #-------------------------------------------------------------------------------
157 } elsif ($op eq "saveitem") {
158 #-------------------------------------------------------------------------------
159     # rebuild
160     my @tags = $input->param('tag');
161     my @subfields = $input->param('subfield');
162     my @values = $input->param('field_value');
163     # build indicator hash.
164     my @ind_tag = $input->param('ind_tag');
165     my @indicator = $input->param('indicator');
166     #    my $itemnumber = $input->param('itemnumber');
167     my $xml = TransformHtmlToXml(\@tags,\@subfields,\@values,\@indicator,\@ind_tag,'ITEM');
168     my $itemtosave=MARC::Record::new_from_xml($xml, 'UTF-8');
169     # MARC::Record builded => now, record in DB
170     # warn "R: ".$record->as_formatted;
171     # check that the barcode don't exist already
172     my $addedolditem = TransformMarcToKoha($dbh,$itemtosave);
173     my $exist_itemnumber = get_item_from_barcode($addedolditem->{'barcode'});
174     if ($exist_itemnumber && $exist_itemnumber != $itemnumber) {
175         push @errors,"barcode_not_unique";
176     } else {
177         my ($oldbiblionumber,$oldbibnum,$oldbibitemnum) = ModItemFromMarc($itemtosave,$biblionumber,$itemnumber);
178     $itemnumber="";
179     }
180     $nextop="additem";
181 }
182
183 #
184 #-------------------------------------------------------------------------------
185 # build screen with existing items. and "new" one
186 #-------------------------------------------------------------------------------
187
188 # now, build existiing item list
189 my $temp = GetMarcBiblio( $biblionumber );
190 my @fields = $temp->fields();
191 #my @fields = $record->fields();
192 my %witness; #---- stores the list of subfields used at least once, with the "meaning" of the code
193 my @big_array;
194 #---- finds where items.itemnumber is stored
195 my ($itemtagfield,$itemtagsubfield) = &GetMarcFromKohaField("items.itemnumber",$frameworkcode);
196 my ($branchtagfield,$branchtagsubfield) = &GetMarcFromKohaField("items.homebranch",$frameworkcode);
197
198 foreach my $field (@fields) {
199     next if ($field->tag()<10);
200     my @subf=$field->subfields;
201     my %this_row;
202 # loop through each subfield
203     for my $i (0..$#subf) {
204         next if ($tagslib->{$field->tag()}->{$subf[$i][0]}->{tab} ne 10 
205                 && ($field->tag() ne $itemtagfield 
206                 && $subf[$i][0] ne $itemtagsubfield));
207
208         $witness{$subf[$i][0]} = $tagslib->{$field->tag()}->{$subf[$i][0]}->{lib} if ($tagslib->{$field->tag()}->{$subf[$i][0]}->{tab}  eq 10);
209                 if ($tagslib->{$field->tag()}->{$subf[$i][0]}->{tab}  eq 10) {
210                 $this_row{$subf[$i][0]}=GetAuthorisedValueDesc( $field->tag(),
211                         $subf[$i][0], $subf[$i][1], '', $tagslib) 
212                                                 || $subf[$i][1];
213                 }
214
215         if (($field->tag eq $branchtagfield) && ($subf[$i][$0] eq $branchtagsubfield) && C4::Context->preference("IndependantBranches")) {
216             #verifying rights
217             my $userenv = C4::Context->userenv();
218             unless (($userenv->{'flags'} == 1) or (($userenv->{'branch'} eq $subf[$i][1]))){
219                     $this_row{'nomod'}=1;
220             }
221         }
222         $this_row{itemnumber} = $subf[$i][1] if ($field->tag() eq $itemtagfield && $subf[$i][0] eq $itemtagsubfield);
223     }
224     if (%this_row) {
225         push(@big_array, \%this_row);
226     }
227 }
228 #fill big_row with missing data
229 foreach my $subfield_code  (keys(%witness)) {
230     for (my $i=0;$i<=$#big_array;$i++) {
231         $big_array[$i]{$subfield_code}="&nbsp;" unless ($big_array[$i]{$subfield_code});
232     }
233 }
234 my ($holdingbrtagf,$holdingbrtagsubf) = &GetMarcFromKohaField("items.holdingbranch",$frameworkcode);
235 @big_array = sort {$a->{$holdingbrtagsubf} cmp $b->{$holdingbrtagsubf}} @big_array;
236
237 # now, construct template !
238 # First, the existing items for display
239 my @item_value_loop;
240 my @header_value_loop;
241 for (my $i=0;$i<=$#big_array; $i++) {
242     my $items_data;
243     foreach my $subfield_code (sort keys(%witness)) {
244         $items_data .="<td>".$big_array[$i]{$subfield_code}."</td>";
245     }
246     my %row_data;
247     $items_data =~ s/"/&quot;/g;
248     $row_data{item_value} = $items_data;
249     $row_data{itemnumber} = $big_array[$i]->{itemnumber};
250     #reporting this_row values
251     $row_data{'nomod'} = $big_array[$i]{'nomod'};
252     push(@item_value_loop,\%row_data);
253 }
254 foreach my $subfield_code (sort keys(%witness)) {
255     my %header_value;
256     $header_value{header_value} = $witness{$subfield_code};
257     push(@header_value_loop, \%header_value);
258 }
259
260 # now, build the item form for entering a new item
261 my @loop_data =();
262 my $i=0;
263 my $authorised_values_sth = $dbh->prepare("SELECT authorised_value,lib FROM authorised_values WHERE category=? ORDER BY lib");
264
265 foreach my $tag (sort keys %{$tagslib}) {
266   my $previous_tag = '';
267 # loop through each subfield
268   foreach my $subfield (sort keys %{$tagslib->{$tag}}) {
269     next if subfield_is_koha_internal_p($subfield);
270     next if ($tagslib->{$tag}->{$subfield}->{'tab'}  ne "10");
271     my %subfield_data;
272  
273     my $index_subfield= int(rand(1000000)); 
274     if($subfield eq '@'){
275         $subfield_data{id} = "tag_".$tag."_subfield_00_".$index_subfield;
276     } else {
277          $subfield_data{id} = "tag_".$tag."_subfield_".$subfield."_".$index_subfield;
278     }
279     $subfield_data{tag}=$tag;
280     $subfield_data{subfield}=$subfield;
281     $subfield_data{random}=int(rand(1000000)); 
282 #        $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
283     $subfield_data{marc_lib}="<span id=\"error$i\" title=\"".$tagslib->{$tag}->{$subfield}->{lib}."\">".$tagslib->{$tag}->{$subfield}->{lib}."</span>";
284     $subfield_data{mandatory}=$tagslib->{$tag}->{$subfield}->{mandatory};
285     $subfield_data{repeatable}=$tagslib->{$tag}->{$subfield}->{repeatable};
286     my ($x,$value);
287     ($x,$value) = find_value($tag,$subfield,$itemrecord) if ($itemrecord);
288     $value =~ s/"/&quot;/g;
289     unless ($value) {
290         $value = $tagslib->{$tag}->{$subfield}->{defaultvalue};
291
292         # get today date & replace YYYY, MM, DD if provided in the default value
293         my ( $year, $month, $day ) = Today();
294         $month = sprintf( "%02d", $month );
295         $day   = sprintf( "%02d", $day );
296         $value =~ s/YYYY/$year/g;
297         $value =~ s/MM/$month/g;
298         $value =~ s/DD/$day/g;
299     }
300     $subfield_data{visibility} = "display:none;" if (($tagslib->{$tag}->{$subfield}->{hidden} > 4) || ($tagslib->{$tag}->{$subfield}->{hidden} < -4));
301     #testing branch value if IndependantBranches.
302     my $test = (C4::Context->preference("IndependantBranches")) &&
303               ($tag eq $branchtagfield) && ($subfield eq $branchtagsubfield) &&
304               (C4::Context->userenv->{flags} != 1) && ($value) && ($value ne C4::Context->userenv->{branch}) ;
305 #         print $input->redirect(".pl?biblionumber=$biblionumber") if ($test);
306         # search for itemcallnumber if applicable
307     if (!$value && $tagslib->{$tag}->{$subfield}->{kohafield} eq 'items.itemcallnumber' && C4::Context->preference('itemcallnumber')) {
308         my $CNtag = substr(C4::Context->preference('itemcallnumber'),0,3);
309         my $CNsubfield = substr(C4::Context->preference('itemcallnumber'),3,1);
310         my $CNsubfield2 = substr(C4::Context->preference('itemcallnumber'),4,1);
311         my $temp2 = $temp->field($CNtag);
312         if ($temp2) {
313                 $value = ($temp2->subfield($CNsubfield)).' '.($temp2->subfield($CNsubfield2));
314 #remove any trailing space incase one subfield is used
315         $value=~s/^\s+|\s+$//g;
316       }
317     }
318     if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
319       my @authorised_values;
320       my %authorised_lib;
321       my $dbh=C4::Context->dbh;   
322   
323       # builds list, depending on authorised value...
324   
325       #---- branch
326       if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
327           #Use GetBranches($onlymine)
328           my $onlymine=C4::Context->preference('IndependantBranches') && 
329                   C4::Context->userenv && 
330                   C4::Context->userenv->{flags}!=1 && 
331                   C4::Context->userenv->{branch};
332           my $branches = GetBranches($onlymine);
333           my @branchloop;
334           foreach my $thisbranch ( sort keys %$branches ) {
335               push @authorised_values, $thisbranch;
336               $authorised_lib{$thisbranch} = $branches->{$thisbranch}->{'branchname'};
337           }
338           
339           #----- itemtypes
340       }
341       elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
342           my $sth =
343             $dbh->prepare(
344               "select itemtype,description from itemtypes order by description");
345           $sth->execute;
346           push @authorised_values, ""
347             unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
348                       
349           while ( my ( $itemtype, $description ) = $sth->fetchrow_array ) {
350               push @authorised_values, $itemtype;
351               $authorised_lib{$itemtype} = $description;
352           }
353
354           unless ( $value ) {
355               my $default_itemtype;
356               my $itype_sth = $dbh->prepare("SELECT itemtype FROM biblioitems WHERE biblionumber = ?");
357               $itype_sth->execute( $biblionumber );
358               ( $default_itemtype ) = $itype_sth->fetchrow_array;
359               $value = $default_itemtype;
360           }
361   
362           #---- class_sources
363       }
364       elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "cn_source" ) {
365           push @authorised_values, ""
366             unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
367             
368           my $class_sources = GetClassSources();
369
370           my $default_source = C4::Context->preference("DefaultClassificationSource");
371           
372           foreach my $class_source (sort keys %$class_sources) {
373               next unless $class_sources->{$class_source}->{'used'} or
374                           ($value and $class_source eq $value) or
375                           ($class_source eq $default_source);
376               push @authorised_values, $class_source;
377               $authorised_lib{$class_source} = $class_sources->{$class_source}->{'description'};
378           }
379                   $value = $default_source unless ($value);
380
381           #---- "true" authorised value
382       }
383       else {
384           $authorised_values_sth->execute(
385               $tagslib->{$tag}->{$subfield}->{authorised_value} );
386   
387           push @authorised_values, ""
388             unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
389   
390           while ( my ( $value, $lib ) = $authorised_values_sth->fetchrow_array ) {
391               push @authorised_values, $value;
392               $authorised_lib{$value} = $lib;
393           }
394       }
395       $subfield_data{marc_value} =CGI::scrolling_list(
396           -name     => "field_value",
397           -values   => \@authorised_values,
398           -default  => $value,
399           -labels   => \%authorised_lib,
400           -override => 1,
401           -size     => 1,
402           -multiple => 0,
403           -tabindex => 1,
404           -id       => "tag_".$tag."_subfield_".$subfield."_".$index_subfield,
405           -class    => "input_marceditor",
406       );
407     # it's a thesaurus / authority field
408     }
409     elsif ( $tagslib->{$tag}->{$subfield}->{authtypecode} ) {
410         $subfield_data{marc_value} =
411             "<input type=\"text\"
412                     id=\"".$subfield_data{id}."\"
413                     name=\"field_value\"
414                     value=\"$value\"
415                     class=\"input_marceditor\"
416                     tabindex=\"1\"
417                     size=\"67\"
418                     maxlength=\"255\" 
419                     \/>
420                     <a href=\"#\" class=\"buttonDot\"
421                         onclick=\"Dopop('/cgi-bin/koha/authorities/auth_finder.pl?authtypecode=".$tagslib->{$tag}->{$subfield}->{authtypecode}."&index=$subfield_data{id}','$subfield_data{id}'); return false;\" title=\"Tag Editor\">...</a>
422     ";
423     # it's a plugin field
424     }
425     elsif ( $tagslib->{$tag}->{$subfield}->{'value_builder'} ) {
426
427         # opening plugin. Just check wether we are on a developper computer on a production one
428         # (the cgidir differs)
429         my $cgidir = C4::Context->intranetdir . "/cgi-bin/cataloguing/value_builder";
430         unless ( opendir( DIR, "$cgidir" ) ) {
431             $cgidir = C4::Context->intranetdir . "/cataloguing/value_builder";
432             closedir( DIR );
433         }
434         my $plugin = $cgidir . "/" . $tagslib->{$tag}->{$subfield}->{'value_builder'};
435         if (do $plugin) {
436             my $extended_param = plugin_parameters( $dbh, $temp, $tagslib, $subfield_data{id}, \@loop_data );
437             my ( $function_name, $javascript ) = plugin_javascript( $dbh, $temp, $tagslib, $subfield_data{id}, \@loop_data );
438         
439             $subfield_data{marc_value} =
440                     "<input tabindex=\"1\"
441                             type=\"text\"
442                             id=\"".$subfield_data{id}."\"
443                             name=\"field_value\"
444                             value=\"$value\"
445                             class=\"input_marceditor\"
446                             onfocus=\"Focus$function_name(".$subfield_data{random}.")\"
447                             size=\"67\"
448                             maxlength=\"255\" 
449                             onblur=\"Blur$function_name(".$subfield_data{random}."); \" \/>
450                             <a href=\"#\" class=\"buttonDot\" onclick=\"Clic$function_name('$subfield_data{id}'); return false;\" title=\"Tag Editor\">...</a>
451                     $javascript";
452         } else {
453             warn "Plugin Failed: $plugin";
454             # supply default input form
455             $subfield_data{marc_value} =
456                 "<input type=\"text\"
457                         id=\"".$subfield_data{id}."\"
458                         name=\"field_value\"
459                         value=\"$value\"
460                         tabindex=\"1\"
461                         size=\"67\"
462                         maxlength=\"255\" 
463                         class=\"input_marceditor\"
464                 \/>
465                 ";
466         }
467         # it's an hidden field
468     }
469     elsif ( $tag eq '' ) {
470         $subfield_data{marc_value} =
471             "<input tabindex=\"1\"
472                     type=\"hidden\"
473                     id=\"".$subfield_data{id}."\"
474                     name=\"field_value\"
475                     size=\"67\"
476                     maxlength=\"255\" 
477                     value=\"$value\" \/>
478             ";
479     }
480     elsif ( $tagslib->{$tag}->{$subfield}->{'hidden'} ) {
481         $subfield_data{marc_value} =
482             "<input type=\"text\"
483                     id=\"".$subfield_data{id}."\"
484                     name=\"field_value\"
485                     class=\"input_marceditor\"
486                     tabindex=\"1\"
487                     size=\"67\"
488                     maxlength=\"255\" 
489                     value=\"$value\"
490             \/>";
491
492         # it's a standard field
493     }
494     else {
495         if (
496             length($value) > 100
497             or
498             ( C4::Context->preference("marcflavour") eq "UNIMARC" && $tag >= 300
499                 and $tag < 400 && $subfield eq 'a' )
500             or (    $tag >= 500
501                 and $tag < 600
502                 && C4::Context->preference("marcflavour") eq "MARC21" )
503           )
504         {
505             $subfield_data{marc_value} =
506                 "<textarea cols=\"70\"
507                            rows=\"4\"
508                            id=\"".$subfield_data{id}."\"
509                            name=\"field_value\"
510                            class=\"input_marceditor\"
511                            tabindex=\"1\"
512                             size=\"67\"
513                             maxlength=\"255\" 
514                            >$value</textarea>
515                 ";
516         }
517         else {
518             $subfield_data{marc_value} =
519                 "<input type=\"text\"
520                         id=\"".$subfield_data{id}."\"
521                         name=\"field_value\"
522                         value=\"$value\"
523                         tabindex=\"1\"
524                         size=\"67\"
525                         maxlength=\"255\" 
526                         class=\"input_marceditor\"
527                 \/>
528                 ";
529         }
530     }
531 #        $subfield_data{marc_value}="<input type=\"text\" name=\"field_value\">";
532         push(@loop_data, \%subfield_data);
533         $i++
534     }
535 }
536
537 # what's the next op ? it's what we are not in : an add if we're editing, otherwise, and edit.
538 $template->param( title => $record->title() ) if ($record ne "-1");
539 $template->param(item_loop => \@item_value_loop,
540                         item_header_loop => \@header_value_loop,
541                         biblionumber => $biblionumber,
542                         title => $oldrecord->{title},
543                         author => $oldrecord->{author},
544                         item => \@loop_data,
545                         itemnumber => $itemnumber,
546                         itemtagfield => $itemtagfield,
547                         itemtagsubfield =>$itemtagsubfield,
548                         op => $nextop,
549                         opisadd => ($nextop eq "saveitem")?0:1);
550 foreach my $error (@errors) {
551     $template->param($error => 1);
552 }
553 output_html_with_http_headers $input, $cookie, $template->output;