Bug 9016: (follow-up) GetMessageTransportTypes returns an arrayref, not hashref
[koha_ffzg] / tools / letter.pl
1 #!/usr/bin/perl
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
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 =head1 tools/letter.pl
21
22  ALGO :
23  this script use an $op to know what to do.
24  if $op is empty or none of the values listed below,
25         - the default screen is built (with all or filtered (if search string is set) records).
26         - the   user can click on add, modify or delete record.
27     - filtering is done on the code field
28  if $op=add_form
29         - if primary key (module + code) exists, this is a modification,so we read the required record
30         - builds the add/modify form
31  if $op=add_validate
32         - the user has just send data, so we create/modify the record
33  if $op=delete_form
34         - we show the record selected and ask for confirmation
35  if $op=delete_confirm
36         - we delete the designated record
37
38 =cut
39
40 # TODO This script drives the CRUD operations on the letter table
41 # The DB interaction should be handled by calls to C4/Letters.pm
42
43 use strict;
44 use warnings;
45 use CGI;
46 use C4::Auth;
47 use C4::Context;
48 use C4::Output;
49 use C4::Branch; # GetBranches
50 use C4::Letters;
51 use C4::Members::Attributes;
52
53 # _letter_from_where($branchcode,$module, $code, $mtt)
54 # - return FROM WHERE clause and bind args for a letter
55 sub _letter_from_where {
56     my ($branchcode, $module, $code, $mtt) = @_;
57     my $sql = q{FROM letter WHERE branchcode = ? AND module = ? AND code = ?};
58     $sql .= q{ AND message_transport_type = ?} if $mtt ne '*';
59     my @args = ( $branchcode || '', $module, $code, ($mtt ne '*' ? $mtt : ()) );
60 # Mysql is retarded. cause branchcode is part of the primary key it cannot be null. How does that
61 # work with foreign key constraint I wonder...
62
63 #   if ($branchcode) {
64 #       $sql .= " AND branchcode = ?";
65 #       push @args, $branchcode;
66 #   } else {
67 #       $sql .= " AND branchcode IS NULL";
68 #   }
69
70     return ($sql, \@args);
71 }
72
73 # get_letters($branchcode,$module, $code, $mtt)
74 # - return letters with the given $branchcode, $module, $code and $mtt exists
75 sub get_letters {
76     my ($sql, $args) = _letter_from_where(@_);
77     my $dbh = C4::Context->dbh;
78     my $letter = $dbh->selectall_hashref("SELECT * $sql", 'message_transport_type', undef, @$args);
79     return $letter;
80 }
81
82 # $protected_letters = protected_letters()
83 # - return a hashref of letter_codes representing letters that should never be deleted
84 sub protected_letters {
85     my $dbh = C4::Context->dbh;
86     my $codes = $dbh->selectall_arrayref(q{SELECT DISTINCT letter_code FROM message_transports});
87     return { map { $_->[0] => 1 } @{$codes} };
88 }
89
90 our $input       = new CGI;
91 my $searchfield = $input->param('searchfield');
92 my $script_name = '/cgi-bin/koha/tools/letter.pl';
93 our $branchcode  = $input->param('branchcode');
94 my $code        = $input->param('code');
95 my $module      = $input->param('module') || '';
96 my $content     = $input->param('content');
97 my $op          = $input->param('op') || '';
98 my $dbh = C4::Context->dbh;
99
100 our ( $template, $borrowernumber, $cookie, $staffflags ) = get_template_and_user(
101     {
102         template_name   => 'tools/letter.tmpl',
103         query           => $input,
104         type            => 'intranet',
105         authnotrequired => 0,
106         flagsrequired   => { tools => 'edit_notices' },
107         debug           => 1,
108     }
109 );
110
111 our $my_branch = C4::Context->preference("IndependentBranches") && !$staffflags->{'superlibrarian'}
112   ?  C4::Context->userenv()->{'branch'}
113   : undef;
114 # we show only the TMPL_VAR names $op
115
116 $template->param(
117     independant_branch => $my_branch,
118         script_name => $script_name,
119   searchfield => $searchfield,
120     branchcode => $branchcode,
121         action => $script_name
122 );
123
124 if ($op eq 'copy') {
125     add_copy();
126     $op = 'add_form';
127 }
128
129 if ($op eq 'add_form') {
130     add_form($branchcode, $module, $code);
131 }
132 elsif ( $op eq 'add_validate' ) {
133     add_validate();
134     $op = q{}; # next operation is to return to default screen
135 }
136 elsif ( $op eq 'delete_confirm' ) {
137     delete_confirm($branchcode, $module, $code);
138 }
139 elsif ( $op eq 'delete_confirmed' ) {
140     my $mtt = $input->param('message_transport_type');
141     delete_confirmed($branchcode, $module, $code, $mtt);
142     $op = q{}; # next operation is to return to default screen
143 }
144 else {
145     default_display($branchcode,$searchfield);
146 }
147
148 # Do this last as delete_confirmed resets
149 if ($op) {
150     $template->param($op  => 1);
151 } else {
152     $template->param(no_op_set => 1);
153 }
154
155 output_html_with_http_headers $input, $cookie, $template->output;
156
157 sub add_form {
158     my ( $branchcode,$module, $code ) = @_;
159
160     my $letters;
161     # if code has been passed we can identify letter and its an update action
162     if ($code) {
163         $letters = get_letters($branchcode,$module, $code, '*');
164     }
165
166     my $message_transport_types = GetMessageTransportTypes();
167     my @letter_loop;
168     if ($letters) {
169         my $first_flag = 1;
170         for my $mtt ( @$message_transport_types ) {
171             if ( $first_flag ) {
172                 $template->param(
173                     modify     => 1,
174                     code       => $code,
175                     branchcode => $branchcode,
176                     name       => $letters->{$mtt}{name},
177                 );
178                 $first_flag = 0;
179             }
180
181             push @letter_loop, {
182                 message_transport_type => $mtt,
183                 is_html    => $letters->{$mtt}{is_html},
184                 title      => $letters->{$mtt}{title},
185                 content    => $letters->{$mtt}{content},
186             };
187         }
188     }
189     else { # initialize the new fields
190         for my $mtt ( @$message_transport_types ) {
191             push @letter_loop, {
192                 message_transport_type => $mtt,
193             }
194         }
195         $template->param(
196             branchcode => $branchcode,
197             module     => $module,
198         );
199         $template->param( adding => 1 );
200     }
201
202     $template->param(
203         letters => \@letter_loop,
204     );
205
206     my $field_selection;
207     push @{$field_selection}, add_fields('branches');
208     if ($module eq 'reserves') {
209         push @{$field_selection}, add_fields('borrowers', 'reserves', 'biblio', 'items');
210     }
211     elsif ($module eq 'claimacquisition') {
212         push @{$field_selection}, add_fields('aqbooksellers', 'aqorders', 'biblio', 'biblioitems');
213     }
214     elsif ($module eq 'claimissues') {
215         push @{$field_selection}, add_fields('aqbooksellers', 'serial', 'subscription');
216         push @{$field_selection},
217         {
218             value => q{},
219             text => '---BIBLIO---'
220         };
221         foreach(qw(title author serial)) {
222             push @{$field_selection}, {value => "biblio.$_", text => ucfirst $_ };
223         }
224     }
225     elsif ($module eq 'suggestions') {
226         push @{$field_selection}, add_fields('suggestions', 'borrowers', 'biblio');
227     }
228     else {
229         push @{$field_selection}, add_fields('biblio','biblioitems'),
230             add_fields('items'),
231             {value => 'items.content', text => 'items.content'},
232             {value => 'items.fine',    text => 'items.fine'},
233             add_fields('borrowers');
234         if ($module eq 'circulation') {
235             push @{$field_selection}, add_fields('opac_news');
236
237         }
238
239         if ( $module eq 'circulation' && $code eq "CHECKIN" ) {
240             push @{$field_selection}, add_fields('old_issues');
241         } else {
242             push @{$field_selection}, add_fields('issues');
243         }
244     }
245
246     $template->param(
247         module     => $module,
248         branchloop => _branchloop($branchcode),
249         SQLfieldname => $field_selection,
250     );
251     return;
252 }
253
254 sub add_validate {
255     my $dbh        = C4::Context->dbh;
256     my $oldbranchcode = $input->param('oldbranchcode');
257     my $branchcode    = $input->param('branchcode') || '';
258     my $module        = $input->param('module');
259     my $oldmodule     = $input->param('oldmodule');
260     my $code          = $input->param('code');
261     my $name          = $input->param('name');
262     my @mtt           = $input->param('message_transport_type');
263     my @title         = $input->param('title');
264     my @content       = $input->param('content');
265     for my $mtt ( @mtt ) {
266         my $is_html = $input->param("is_html_$mtt");
267         my $title   = shift @title;
268         my $content = shift @content;
269         my $letter = get_letters($oldbranchcode,$oldmodule, $code, $mtt);
270         unless ( $title and $content ) {
271             delete_confirmed( $oldbranchcode, $oldmodule, $code, $mtt );
272             next;
273         }
274         if ( exists $letter->{$mtt} ) {
275             $dbh->do(
276                 q{
277                     UPDATE letter
278                     SET branchcode = ?, module = ?, name = ?, is_html = ?, title = ?, content = ?
279                     WHERE branchcode = ? AND module = ? AND code = ? AND message_transport_type = ?
280                 },
281                 undef,
282                 $branchcode, $module, $name, $is_html || 0, $title, $content,
283                 $oldbranchcode, $oldmodule, $code, $mtt
284             );
285         } else {
286             $dbh->do(
287                 q{INSERT INTO letter (branchcode,module,code,name,is_html,title,content,message_transport_type) VALUES (?,?,?,?,?,?,?,?)},
288                 undef,
289                 $branchcode, $module, $code, $name, $is_html || 0, $title, $content, $mtt
290             );
291         }
292     }
293     # set up default display
294     default_display($branchcode);
295 }
296
297 sub add_copy {
298     my $dbh        = C4::Context->dbh;
299     my $oldbranchcode = $input->param('oldbranchcode');
300     my $branchcode    = $input->param('branchcode');
301     my $module        = $input->param('module');
302     my $code          = $input->param('code');
303
304     return if keys %{ get_letters($branchcode,$module, $code, '*') };
305
306     my $old_letters = get_letters($oldbranchcode,$module, $code, '*');
307
308     my $message_transport_types = GetMessageTransportTypes();
309     for my $mtt ( @$message_transport_types ) {
310         next unless exists $old_letters->{$mtt};
311         my $old_letter = $old_letters->{$mtt};
312
313         $dbh->do(
314             q{INSERT INTO letter (branchcode,module,code,name,is_html,title,content,message_transport_type) VALUES (?,?,?,?,?,?,?,?)},
315             undef,
316             $branchcode, $module, $code, $old_letter->{name}, $old_letter->{is_html}, $old_letter->{title}, $old_letter->{content}, $mtt
317         );
318     }
319 }
320
321 sub delete_confirm {
322     my ($branchcode, $module, $code) = @_;
323     my $dbh = C4::Context->dbh;
324     my $letter = get_letters($branchcode, $module, $code, '*');
325     my @values = values %$letter;
326     $template->param(
327         branchcode => $branchcode,
328         branchname => GetBranchName($branchcode),
329         code => $code,
330         module => $module,
331         name => $values[0]->{name},
332     );
333     return;
334 }
335
336 sub delete_confirmed {
337     my ($branchcode, $module, $code, $mtt) = @_;
338     my ($sql, $args) = _letter_from_where($branchcode, $module, $code, $mtt);
339     my $dbh    = C4::Context->dbh;
340     $dbh->do("DELETE $sql", undef, @$args);
341     # setup default display for screen
342     default_display($branchcode);
343     return;
344 }
345
346 sub retrieve_letters {
347     my ($branchcode, $searchstring) = @_;
348
349     $branchcode = $my_branch if $branchcode && $my_branch;
350
351     my $dbh = C4::Context->dbh;
352     my ($sql, @where, @args);
353     $sql = "SELECT branchcode, module, code, name, branchname
354             FROM letter
355             LEFT OUTER JOIN branches USING (branchcode)
356     ";
357     if ($searchstring && $searchstring=~m/(\S+)/) {
358         $searchstring = $1 . q{%};
359         push @where, 'code LIKE ?';
360         push @args, $searchstring;
361     }
362     elsif ($branchcode) {
363         push @where, 'branchcode = ?';
364         push @args, $branchcode || '';
365     }
366     elsif ($my_branch) {
367         push @where, "(branchcode = ? OR branchcode = '')";
368         push @args, $my_branch;
369     }
370
371     $sql .= " WHERE ".join(" AND ", @where) if @where;
372     $sql .= " GROUP BY branchcode,module,code";
373     $sql .= " ORDER BY module, code, branchcode";
374
375     return $dbh->selectall_arrayref($sql, { Slice => {} }, @args);
376 }
377
378 sub default_display {
379     my ($branchcode, $searchfield) = @_;
380
381     if ( $searchfield  ) {
382         $template->param( search      => 1 );
383     }
384     my $results = retrieve_letters($branchcode,$searchfield);
385
386     my $loop_data = [];
387     my $protected_letters = protected_letters();
388     foreach my $row (@{$results}) {
389         $row->{protected} = !$row->{branchcode} && $protected_letters->{ $row->{code} };
390         push @{$loop_data}, $row;
391
392     }
393
394     $template->param(
395         letter => $loop_data,
396         branchloop => _branchloop($branchcode),
397     );
398 }
399
400 sub _branchloop {
401     my ($branchcode) = @_;
402
403     my $branches = GetBranches();
404     my @branchloop;
405     for my $thisbranch (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %$branches) {
406         push @branchloop, {
407             value      => $thisbranch,
408             selected   => $branchcode && $thisbranch eq $branchcode,
409             branchname => $branches->{$thisbranch}->{'branchname'},
410         };
411     }
412
413     return \@branchloop;
414 }
415
416 sub add_fields {
417     my @tables = @_;
418     my @fields = ();
419
420     for my $table (@tables) {
421         push @fields, get_columns_for($table);
422
423     }
424     return @fields;
425 }
426
427 sub get_columns_for {
428     my $table = shift;
429 # FIXME untranslateable
430     my %column_map = (
431         aqbooksellers => '---BOOKSELLERS---',
432         aqorders      => '---ORDERS---',
433         serial        => '---SERIALS---',
434         reserves      => '---HOLDS---',
435         suggestions   => '---SUGGESTIONS---',
436     );
437     my @fields = ();
438     if (exists $column_map{$table} ) {
439         push @fields, {
440             value => q{},
441             text  => $column_map{$table} ,
442         };
443     }
444     else {
445         my $tlabel = '---' . uc $table;
446         $tlabel.= '---';
447         push @fields, {
448             value => q{},
449             text  => $tlabel,
450         };
451     }
452
453     my $sql = "SHOW COLUMNS FROM $table";# TODO not db agnostic
454     my $table_prefix = $table . q|.|;
455     my $rows = C4::Context->dbh->selectall_arrayref($sql, { Slice => {} });
456     for my $row (@{$rows}) {
457         next if $row->{'Field'} eq 'timestamp'; # this is really an irrelevant field and there may be other common fields that should be excluded from the list
458         push @fields, {
459             value => $table_prefix . $row->{Field},
460             text  => $table_prefix . $row->{Field},
461         }
462     }
463     if ($table eq 'borrowers') {
464         if ( my $attributes = C4::Members::Attributes::GetAttributes() ) {
465             foreach (@$attributes) {
466                 push @fields, {
467                     value => "borrower-attribute:$_",
468                     text  => "attribute:$_",
469                 }
470             }
471         }
472     }
473     return @fields;
474 }