Bug 9016: Create a message for each transport type.
[koha.git] / 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             $mtt = $mtt->{message_transport_type};
192             push @letter_loop, {
193                 message_transport_type => $mtt,
194             }
195         }
196         $template->param(
197             branchcode => $branchcode,
198             module     => $module,
199         );
200         $template->param( adding => 1 );
201     }
202
203     $template->param(
204         letters => \@letter_loop,
205     );
206
207     my $field_selection;
208     push @{$field_selection}, add_fields('branches');
209     if ($module eq 'reserves') {
210         push @{$field_selection}, add_fields('borrowers', 'reserves', 'biblio', 'items');
211     }
212     elsif ($module eq 'claimacquisition') {
213         push @{$field_selection}, add_fields('aqbooksellers', 'aqorders', 'biblio', 'biblioitems');
214     }
215     elsif ($module eq 'claimissues') {
216         push @{$field_selection}, add_fields('aqbooksellers', 'serial', 'subscription');
217         push @{$field_selection},
218         {
219             value => q{},
220             text => '---BIBLIO---'
221         };
222         foreach(qw(title author serial)) {
223             push @{$field_selection}, {value => "biblio.$_", text => ucfirst $_ };
224         }
225     }
226     elsif ($module eq 'suggestions') {
227         push @{$field_selection}, add_fields('suggestions', 'borrowers', 'biblio');
228     }
229     else {
230         push @{$field_selection}, add_fields('biblio','biblioitems'),
231             add_fields('items'),
232             {value => 'items.content', text => 'items.content'},
233             {value => 'items.fine',    text => 'items.fine'},
234             add_fields('borrowers');
235         if ($module eq 'circulation') {
236             push @{$field_selection}, add_fields('opac_news');
237
238         }
239
240         if ( $module eq 'circulation' && $code eq "CHECKIN" ) {
241             push @{$field_selection}, add_fields('old_issues');
242         } else {
243             push @{$field_selection}, add_fields('issues');
244         }
245     }
246
247     $template->param(
248         module     => $module,
249         branchloop => _branchloop($branchcode),
250         SQLfieldname => $field_selection,
251     );
252     return;
253 }
254
255 sub add_validate {
256     my $dbh        = C4::Context->dbh;
257     my $oldbranchcode = $input->param('oldbranchcode');
258     my $branchcode    = $input->param('branchcode') || '';
259     my $module        = $input->param('module');
260     my $oldmodule     = $input->param('oldmodule');
261     my $code          = $input->param('code');
262     my $name          = $input->param('name');
263     my @mtt           = $input->param('message_transport_type');
264     my @title         = $input->param('title');
265     my @content       = $input->param('content');
266     for my $mtt ( @mtt ) {
267         my $is_html = $input->param("is_html_$mtt");
268         my $title   = shift @title;
269         my $content = shift @content;
270         my $letter = get_letters($oldbranchcode,$oldmodule, $code, $mtt);
271         unless ( $title and $content ) {
272             delete_confirmed( $oldbranchcode, $oldmodule, $code, $mtt );
273             next;
274         }
275         if ( exists $letter->{$mtt} ) {
276             $dbh->do(
277                 q{
278                     UPDATE letter
279                     SET branchcode = ?, module = ?, name = ?, is_html = ?, title = ?, content = ?
280                     WHERE branchcode = ? AND module = ? AND code = ? AND message_transport_type = ?
281                 },
282                 undef,
283                 $branchcode, $module, $name, $is_html || 0, $title, $content,
284                 $oldbranchcode, $oldmodule, $code, $mtt
285             );
286         } else {
287             $dbh->do(
288                 q{INSERT INTO letter (branchcode,module,code,name,is_html,title,content,message_transport_type) VALUES (?,?,?,?,?,?,?,?)},
289                 undef,
290                 $branchcode, $module, $code, $name, $is_html || 0, $title, $content, $mtt
291             );
292         }
293     }
294     # set up default display
295     default_display($branchcode);
296 }
297
298 sub add_copy {
299     my $dbh        = C4::Context->dbh;
300     my $oldbranchcode = $input->param('oldbranchcode');
301     my $branchcode    = $input->param('branchcode');
302     my $module        = $input->param('module');
303     my $code          = $input->param('code');
304
305     return if keys %{ get_letters($branchcode,$module, $code, '*') };
306
307     my $old_letters = get_letters($oldbranchcode,$module, $code, '*');
308
309     my $message_transport_types = GetMessageTransportTypes();
310     for my $mtt ( @$message_transport_types ) {
311         next unless exists $old_letters->{$mtt};
312         my $old_letter = $old_letters->{$mtt};
313
314         $dbh->do(
315             q{INSERT INTO letter (branchcode,module,code,name,is_html,title,content,message_transport_type) VALUES (?,?,?,?,?,?,?,?)},
316             undef,
317             $branchcode, $module, $code, $old_letter->{name}, $old_letter->{is_html}, $old_letter->{title}, $old_letter->{content}, $mtt
318         );
319     }
320 }
321
322 sub delete_confirm {
323     my ($branchcode, $module, $code) = @_;
324     my $dbh = C4::Context->dbh;
325     my $letter = get_letters($branchcode, $module, $code, '*');
326     my @values = values %$letter;
327     $template->param(
328         branchcode => $branchcode,
329         branchname => GetBranchName($branchcode),
330         code => $code,
331         module => $module,
332         name => $values[0]->{name},
333     );
334     return;
335 }
336
337 sub delete_confirmed {
338     my ($branchcode, $module, $code, $mtt) = @_;
339     my ($sql, $args) = _letter_from_where($branchcode, $module, $code, $mtt);
340     my $dbh    = C4::Context->dbh;
341     $dbh->do("DELETE $sql", undef, @$args);
342     # setup default display for screen
343     default_display($branchcode);
344     return;
345 }
346
347 sub retrieve_letters {
348     my ($branchcode, $searchstring) = @_;
349
350     $branchcode = $my_branch if $branchcode && $my_branch;
351
352     my $dbh = C4::Context->dbh;
353     my ($sql, @where, @args);
354     $sql = "SELECT branchcode, module, code, name, branchname
355             FROM letter
356             LEFT OUTER JOIN branches USING (branchcode)
357     ";
358     if ($searchstring && $searchstring=~m/(\S+)/) {
359         $searchstring = $1 . q{%};
360         push @where, 'code LIKE ?';
361         push @args, $searchstring;
362     }
363     elsif ($branchcode) {
364         push @where, 'branchcode = ?';
365         push @args, $branchcode || '';
366     }
367     elsif ($my_branch) {
368         push @where, "(branchcode = ? OR branchcode = '')";
369         push @args, $my_branch;
370     }
371
372     $sql .= " WHERE ".join(" AND ", @where) if @where;
373     $sql .= " GROUP BY branchcode,module,code";
374     $sql .= " ORDER BY module, code, branchcode";
375
376     return $dbh->selectall_arrayref($sql, { Slice => {} }, @args);
377 }
378
379 sub default_display {
380     my ($branchcode, $searchfield) = @_;
381
382     if ( $searchfield  ) {
383         $template->param( search      => 1 );
384     }
385     my $results = retrieve_letters($branchcode,$searchfield);
386
387     my $loop_data = [];
388     my $protected_letters = protected_letters();
389     foreach my $row (@{$results}) {
390         $row->{protected} = !$row->{branchcode} && $protected_letters->{ $row->{code} };
391         push @{$loop_data}, $row;
392
393     }
394
395     $template->param(
396         letter => $loop_data,
397         branchloop => _branchloop($branchcode),
398     );
399 }
400
401 sub _branchloop {
402     my ($branchcode) = @_;
403
404     my $branches = GetBranches();
405     my @branchloop;
406     for my $thisbranch (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %$branches) {
407         push @branchloop, {
408             value      => $thisbranch,
409             selected   => $branchcode && $thisbranch eq $branchcode,
410             branchname => $branches->{$thisbranch}->{'branchname'},
411         };
412     }
413
414     return \@branchloop;
415 }
416
417 sub add_fields {
418     my @tables = @_;
419     my @fields = ();
420
421     for my $table (@tables) {
422         push @fields, get_columns_for($table);
423
424     }
425     return @fields;
426 }
427
428 sub get_columns_for {
429     my $table = shift;
430 # FIXME untranslateable
431     my %column_map = (
432         aqbooksellers => '---BOOKSELLERS---',
433         aqorders      => '---ORDERS---',
434         serial        => '---SERIALS---',
435         reserves      => '---HOLDS---',
436         suggestions   => '---SUGGESTIONS---',
437     );
438     my @fields = ();
439     if (exists $column_map{$table} ) {
440         push @fields, {
441             value => q{},
442             text  => $column_map{$table} ,
443         };
444     }
445     else {
446         my $tlabel = '---' . uc $table;
447         $tlabel.= '---';
448         push @fields, {
449             value => q{},
450             text  => $tlabel,
451         };
452     }
453
454     my $sql = "SHOW COLUMNS FROM $table";# TODO not db agnostic
455     my $table_prefix = $table . q|.|;
456     my $rows = C4::Context->dbh->selectall_arrayref($sql, { Slice => {} });
457     for my $row (@{$rows}) {
458         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
459         push @fields, {
460             value => $table_prefix . $row->{Field},
461             text  => $table_prefix . $row->{Field},
462         }
463     }
464     if ($table eq 'borrowers') {
465         if ( my $attributes = C4::Members::Attributes::GetAttributes() ) {
466             foreach (@$attributes) {
467                 push @fields, {
468                     value => "borrower-attribute:$_",
469                     text  => "attribute:$_",
470                 }
471             }
472         }
473     }
474     return @fields;
475 }