Bug 3186 - invalid or uninstalled SMSSendDriver (or bad number format) causes process...
[koha.git] / C4 / Creators / Lib.pm
blobc519352a60000fdb8875e1e322b7fd7e622b0afa
1 package C4::Creators::Lib;
3 # Copyright 2009 Foundations Bible College.
5 # This file is part of Koha.
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.
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.
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.
20 use strict;
21 use warnings;
23 use autouse 'Data::Dumper' => qw(Dumper);
25 use C4::Context;
26 use C4::Debug;
28 BEGIN {
29 use version; our $VERSION = qv('3.07.00.049');
30 use base qw(Exporter);
31 our @EXPORT = qw(get_all_templates
32 get_all_layouts
33 get_all_profiles
34 get_all_image_names
35 get_batch_summary
36 get_label_summary
37 get_card_summary
38 get_barcode_types
39 get_label_types
40 get_font_types
41 get_text_justification_types
42 get_output_formats
43 get_column_names
44 get_table_names
45 get_unit_values
46 html_table
50 =head1 NAME
52 C4::Creators::Lib
54 =cut
56 =head1 FUNCTIONS
58 =cut
60 #=head2 C4::Creators::Lib::_SELECT()
62 # This function returns a recordset upon success and 1 upon failure. Errors are logged to the Apache log.
64 # examples:
66 # my $field_value = _SELECT(field_name, table_name, condition);
68 #=cut
70 sub _SELECT {
71 my @params = @_;
72 my $query = "SELECT $params[0] FROM $params[1]";
73 $params[2] ? $query .= " WHERE $params[2];" : $query .= ';';
74 my $sth = C4::Context->dbh->prepare($query);
75 # $sth->{'TraceLevel'} = 3;
76 $sth->execute();
77 if ($sth->err) {
78 warn sprintf('Database returned the following error: %s', $sth->errstr);
79 return 1;
81 my $record_set = [];
82 while (my $row = $sth->fetchrow_hashref()) {
83 push(@$record_set, $row);
85 return $record_set;
88 my $barcode_types = [
89 {type => 'CODE39', name => 'Code 39', desc => 'Translates the characters 0-9, A-Z, \'-\', \'*\', \'+\', \'$\', \'%\', \'/\', \'.\' and \' \' to a barcode pattern.', selected => 0},
90 {type => 'CODE39MOD', name => 'Code 39 + Modulo43', desc => 'Translates the characters 0-9, A-Z, \'-\', \'*\', \'+\', \'$\', \'%\', \'/\', \'.\' and \' \' to a barcode pattern. Encodes Mod 43 checksum.', selected => 0},
91 {type => 'CODE39MOD10', name => 'Code 39 + Modulo10', desc => 'Translates the characters 0-9, A-Z, \'-\', \'*\', \'+\', \'$\', \'%\', \'/\', \'.\' and \' \' to a barcode pattern. Encodes Mod 10 checksum.', selected => 0},
92 {type => 'COOP2OF5', name => 'COOP2of5', desc => 'Creates COOP2of5 barcodes from a string consisting of the numeric characters 0-9', selected => 0},
93 {type => 'EAN13', name => 'EAN13', desc => 'Creates EAN13 barcodes from a string of 12 or 13 digits. The check number (the 13:th digit) is calculated if not supplied.', selected => 0},
94 # {type => 'EAN8', name => 'EAN8', desc => 'Translates a string of 7 or 8 digits to EAN8 barcodes. The check number (the 8:th digit) is calculated if not supplied.', selected => 0},
95 # {type => 'IATA2of5', name => 'IATA2of5', desc => 'Creates IATA2of5 barcodes from a string consisting of the numeric characters 0-9', selected => 0},
96 {type => 'INDUSTRIAL2OF5', name => 'Industrial2of5', desc => 'Creates Industrial2of5 barcodes from a string consisting of the numeric characters 0-9', selected => 0},
97 # {type => 'ITF', name => 'Interleaved2of5', desc => 'Translates the characters 0-9 to a barcodes. These barcodes could also be called 'Interleaved2of5'.', selected => 0},
98 # {type => 'MATRIX2OF5', name => 'Matrix2of5', desc => 'Creates Matrix2of5 barcodes from a string consisting of the numeric characters 0-9', selected => 0},
99 # {type => 'NW7', name => 'NW7', desc => 'Creates a NW7 barcodes from a string consisting of the numeric characters 0-9', selected => 0},
100 # {type => 'UPCA', name => 'UPCA', desc => 'Translates a string of 11 or 12 digits to UPCA barcodes. The check number (the 12:th digit) is calculated if not supplied.', selected => 0},
101 # {type => 'UPCE', name => 'UPCE', desc => 'Translates a string of 6, 7 or 8 digits to UPCE barcodes. If the string is 6 digits long, '0' is added first in the string. The check number (the 8:th digit) is calculated if not supplied.', selected => 0},
104 my $label_types = [
105 {type => 'BIB', name => 'Biblio', desc => 'Only the bibliographic data is printed.', selected => 0},
106 {type => 'BARBIB', name => 'Barcode/Biblio', desc => 'Barcode proceeds bibliographic data.', selected => 0},
107 {type => 'BIBBAR', name => 'Biblio/Barcode', desc => 'Bibliographic data proceeds barcode.', selected => 0},
108 {type => 'ALT', name => 'Alternating', desc => 'Barcode and bibliographic data are printed on alternating labels.', selected => 0},
109 {type => 'BAR', name => 'Barcode', desc => 'Only the barcode is printed.', selected => 0},
112 my $font_types = [
113 {type => 'TR', name => 'Times-Roman', selected => 0},
114 {type => 'TB', name => 'Times-Bold', selected => 0},
115 {type => 'TI', name => 'Times-Italic', selected => 0},
116 {type => 'TBI', name => 'Times-Bold-Italic', selected => 0},
117 {type => 'C', name => 'Courier', selected => 0},
118 {type => 'CB', name => 'Courier-Bold', selected => 0},
119 {type => 'CO', name => 'Courier-Oblique', selected => 0},
120 {type => 'CBO', name => 'Courier-Bold-Oblique', selected => 0},
121 {type => 'H', name => 'Helvetica', selected => 0},
122 {type => 'HO', name => 'Helvetica-Oblique', selected => 0},
123 {type => 'HB', name => 'Helvetica-Bold', selected => 0},
124 {type => 'HBO', name => 'Helvetica-Bold-Oblique', selected => 0},
127 my $text_justification_types = [
128 {type => 'L', name => 'Left', selected => 0},
129 {type => 'C', name => 'Center', selected => 0},
130 {type => 'R', name => 'Right', selected => 0},
131 # {type => 'F', name => 'Full', selected => 0},
134 my $unit_values = [
135 {type => 'POINT', desc => 'PostScript Points', value => 1, selected => 0},
136 {type => 'AGATE', desc => 'Adobe Agates', value => 5.1428571, selected => 0},
137 {type => 'INCH', desc => 'US Inches', value => 72, selected => 0},
138 {type => 'MM', desc => 'SI Millimeters', value => 2.83464567, selected => 0},
139 {type => 'CM', desc => 'SI Centimeters', value => 28.3464567, selected => 0},
142 my $output_formats = [
143 {type => 'pdf', desc => 'PDF File'},
144 {type => 'csv', desc => 'CSV File'},
147 =head2 C4::Creators::Lib::get_all_templates()
149 my $templates = get_all_templates();
151 This function returns a reference to a hash containing all templates upon success and 1 upon failure. Errors are logged to the Apache log.
153 =cut
155 sub get_all_templates {
156 my %params = @_;
157 my @templates = ();
158 my $query = "SELECT " . ($params{'field_list'} ? $params{'field_list'} : '*') . " FROM creator_templates";
159 $query .= ($params{'filter'} ? " WHERE $params{'filter'} " : '');
160 $query .= ($params{'orderby'} ? " ORDER BY $params{'orderby'} " : '');
161 my $sth = C4::Context->dbh->prepare($query);
162 $sth->execute();
163 if ($sth->err) {
164 warn sprintf('Database returned the following error: %s', $sth->errstr);
165 return -1;
167 ADD_TEMPLATES:
168 while (my $template = $sth->fetchrow_hashref) {
169 push(@templates, $template);
171 return \@templates;
174 =head2 C4::Creators::Lib::get_all_layouts()
176 my $layouts = get_all_layouts();
178 This function returns a reference to a hash containing all layouts upon success and 1 upon failure. Errors are logged to the Apache log.
180 =cut
182 sub get_all_layouts {
183 my %params = @_;
184 my @layouts = ();
185 my $query = "SELECT " . ($params{'field_list'} ? $params{'field_list'} : '*') . " FROM creator_layouts";
186 $query .= ($params{'filter'} ? " WHERE $params{'filter'} " : '');
187 $query .= ($params{'orderby'} ? " ORDER BY $params{'orderby'} " : '');
188 my $sth = C4::Context->dbh->prepare($query);
189 $sth->execute();
190 if ($sth->err) {
191 warn sprintf('Database returned the following error: %s', $sth->errstr);
192 return -1;
194 ADD_LAYOUTS:
195 while (my $layout = $sth->fetchrow_hashref) {
196 push(@layouts, $layout);
198 return \@layouts;
201 =head2 C4::Creators::Lib::get_all_profiles()
203 my $profiles = get_all_profiles();
205 my $profiles = get_all_profiles(field_list => field_list, filter => filter_string);
207 This function returns an arrayref whose elements are hashes containing all profiles upon success and 1 upon failure. Errors are logged
208 to the Apache log. Two parameters are accepted. The first limits the field(s) returned. This parameter should be string of comma separted
209 fields. ie. "field_1, field_2, ...field_n" The second limits the records returned based on a string containing a valud SQL 'WHERE' filter.
211 NOTE: Do not pass in the keyword 'WHERE.'
213 =cut
215 sub get_all_profiles {
216 my %params = @_;
217 my @profiles = ();
218 my $query = "SELECT " . ($params{'field_list'} ? $params{'field_list'} : '*') . " FROM printers_profile";
219 $query .= ($params{'filter'} ? " WHERE $params{'filter'};" : ';');
220 my $sth = C4::Context->dbh->prepare($query);
221 # $sth->{'TraceLevel'} = 3 if $debug;
222 $sth->execute();
223 if ($sth->err) {
224 warn sprintf('Database returned the following error: %s', $sth->errstr);
225 return -1;
227 ADD_PROFILES:
228 while (my $profile = $sth->fetchrow_hashref) {
229 push(@profiles, $profile);
231 return \@profiles;
234 =head2 C4::Creators::Lib::get_all_image_names()
236 =cut
238 sub get_all_image_names {
239 my $image_names = [];
240 my $query = "SELECT image_name FROM creator_images";
241 my $sth = C4::Context->dbh->prepare($query);
242 # $sth->{'TraceLevel'} = 3 if $debug;
243 $sth->execute();
244 if ($sth->err) {
245 warn sprintf('Database returned the following error: %s', $sth->errstr);
246 return -1;
248 grep {push @$image_names, {type => $$_[0], name => $$_[0], selected => 0}} @{$sth->fetchall_arrayref([0])};
249 return $image_names;
252 =head2 C4::Creators::Lib::get_batch_summary()
254 my $batches = get_batch_summary();
256 my $batches = get_batch_summary(filter => filter_string);
258 This function returns an arrayref whose elements are hashes containing the batch_ids of current batches along with the item count
259 for each batch upon success and 1 upon failure. Item counts are stored under the key '_item_count' Errors are logged to the Apache log.
260 One parameter is accepted which limits the records returned based on a string containing a valud SQL 'WHERE' filter.
262 NOTE: Do not pass in the keyword 'WHERE.'
264 =cut
266 sub get_batch_summary {
267 my %params = @_;
268 my @batches = ();
269 my $query = "SELECT batch_id,count(batch_id) as _item_count FROM creator_batches WHERE creator=?";
270 $query .= ($params{'filter'} ? " AND $params{'filter'}" : '');
271 $query .= " GROUP BY batch_id";
272 my $sth = C4::Context->dbh->prepare($query);
273 # $sth->{'TraceLevel'} = 3;
274 $sth->execute($params{'creator'});
275 if ($sth->err) {
276 warn sprintf('Database returned the following error on attempted SELECT: %s', $sth->errstr);
277 return -1;
279 while (my $batch = $sth->fetchrow_hashref) {
280 push(@batches, $batch);
282 return \@batches;
285 =head2 C4::Creators::Lib::get_label_summary()
287 my $labels = get_label_summary();
289 my $labels = get_label_summary(items => @item_list);
291 This function returns an arrayref whose elements are hashes containing the label_ids of current labels along with the item count
292 for each label upon success and 1 upon failure. Item counts are stored under the key '_item_count' Errors are logged to the Apache log.
293 One parameter is accepted which limits the records returned based on a string containing a valud SQL 'WHERE' filter.
295 NOTE: Do not pass in the keyword 'WHERE.'
297 =cut
299 sub get_label_summary {
300 my %params = @_;
301 my $label_number = 0;
302 my @label_summaries = ();
303 my $query = " SELECT b.title, b.author, bi.itemtype, i.barcode, i.biblionumber, i.itype
304 FROM creator_batches AS c LEFT JOIN items AS i ON (c.item_number=i.itemnumber)
305 LEFT JOIN biblioitems AS bi ON (i.biblioitemnumber=bi.biblioitemnumber)
306 LEFT JOIN biblio AS b ON (bi.biblionumber=b.biblionumber)
307 WHERE itemnumber=? AND batch_id=?;
309 my $sth = C4::Context->dbh->prepare($query);
310 foreach my $item (@{$params{'items'}}) {
311 $label_number++;
312 $sth->execute($item->{'item_number'}, $params{'batch_id'});
313 if ($sth->err) {
314 warn sprintf('Database returned the following error on attempted SELECT: %s', $sth->errstr);
315 return -1;
317 my $record = $sth->fetchrow_hashref;
318 my $label_summary;
319 $label_summary->{'_label_number'} = $label_number;
320 $record->{'author'} =~ s/[^\.|\w]$// if $record->{'author'}; # strip off ugly trailing chars... but not periods or word chars
321 $record->{'title'} =~ s/\W*$//; # strip off ugly trailing chars
322 # FIXME contructing staff interface URLs should be done *much* higher up the stack - for the most part, C4 module code
323 # should not know that it's part of a web app
324 $record->{'title'} = '<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=' . $record->{'biblionumber'} . '"> ' . $record->{'title'} . '</a>';
325 $label_summary->{'_summary'} = $record->{'title'} . " | " . ($record->{'author'} ? $record->{'author'} : 'N/A');
326 $label_summary->{'_item_type'} = C4::Context->preference("item-level_itypes") ? $record->{'itype'} : $record->{'itemtype'};
327 $label_summary->{'_barcode'} = $record->{'barcode'};
328 $label_summary->{'_item_number'} = $item->{'item_number'};
329 $label_summary->{'_label_id'} = $item->{'label_id'};
330 push (@label_summaries, $label_summary);
332 return \@label_summaries;
335 =head2 C4::Creators::Lib::get_card_summary()
337 my $cards = get_card_summary();
339 my $cards = get_card_summary(items => @item_list);
341 This function returns an arrayref whose elements are hashes containing the label_ids of current cards along with the item count
342 for each card upon success and 1 upon failure. Item counts are stored under the key '_item_count' Errors are logged to the Apache log.
343 One parameter is accepted which limits the records returned based on a string containing a valud SQL 'WHERE' filter.
345 NOTE: Do not pass in the keyword 'WHERE.'
347 =cut
349 sub get_card_summary {
350 my %params = @_;
351 my $card_number = 0;
352 my @card_summaries = ();
353 my $query = "SELECT CONCAT_WS(', ', surname, firstname) AS name, cardnumber FROM borrowers WHERE borrowernumber=?;";
354 my $sth = C4::Context->dbh->prepare($query);
355 foreach my $item (@{$params{'items'}}) {
356 $card_number++;
357 $sth->execute($item->{'borrower_number'});
358 if ($sth->err) {
359 warn sprintf('Database returned the following error on attempted SELECT: %s', $sth->errstr);
360 return -1;
362 my $record = $sth->fetchrow_hashref;
363 my $card_summary->{'_card_number'} = $card_number;
364 $card_summary->{'_summary'} = $record->{'name'};
365 $card_summary->{'borrowernumber'} = $item->{'borrower_number'};
366 $card_summary->{'_label_id'} = $item->{'label_id'};
367 push (@card_summaries, $card_summary);
369 return \@card_summaries;
372 =head2 C4::Creators::Lib::get_barcode_types()
374 my $barcode_types = get_barcode_types();
376 This function returns a reference to an array of hashes containing all barcode types along with their name and description.
378 =cut
380 sub get_barcode_types {
381 return $barcode_types;
384 =head2 C4::Creators::Lib::get_label_types()
386 my $label_types = get_label_types();
388 This function returns a reference to an array of hashes containing all label types along with their name and description.
390 =cut
392 sub get_label_types {
393 return $label_types;
396 =head2 C4::Creators::Lib::get_font_types()
398 my $font_types = get_font_types();
400 This function returns a reference to an array of hashes containing all font types along with their name and description.
402 =cut
404 sub get_font_types {
405 return $font_types;
408 =head2 C4::Creators::Lib::get_text_justification_types()
410 my $text_justification_types = get_text_justification_types();
412 This function returns a reference to an array of hashes containing all text justification types along with their name and description.
414 =cut
416 sub get_text_justification_types {
417 return $text_justification_types;
420 =head2 C4::Creators::Lib::get_unit_values()
422 my $unit_values = get_unit_values();
424 This function returns a reference to an array of hashes containing all unit types along with their description and multiplier.
425 NOTE: All units are relative to a PostScript Point.
426 There are 72 PS points to the inch.
428 =cut
430 sub get_unit_values {
431 return $unit_values;
434 =head2 C4::Creators::Lib::get_output_formats()
436 my $label_output_formats = get_output_formats();
438 This function returns a reference to an array of hashes containing all label output formats along with their description.
440 =cut
442 sub get_output_formats {
443 return $output_formats;
446 =head2 C4::Creators::Lib::get_column_names($table_name)
448 Return an arrayref of an array containing the column names of the supplied table.
450 =cut
452 sub get_column_names {
453 my $table = shift;
454 my $dbh = C4::Context->dbh();
455 my $column_names = [];
456 my $sth = $dbh->column_info(undef,undef,$table,'%');
457 while (my $info = $sth->fetchrow_hashref()){
458 $$column_names[$info->{'ORDINAL_POSITION'}] = $info->{'COLUMN_NAME'};
460 return $column_names;
463 =head2 C4::Creators::Lib::get_table_names($search_term)
465 Return an arrayref of an array containing the table names which contain the supplied search term.
467 =cut
469 sub get_table_names {
470 my $search_term = shift;
471 my $dbh = C4::Context->dbh();
472 my $table_names = [];
473 my $sth = $dbh->table_info(undef,undef,"%$search_term%");
474 while (my $info = $sth->fetchrow_hashref()){
475 push (@$table_names, $info->{'TABLE_NAME'});
477 return $table_names;
480 =head2 C4::Creators::Lib::html_table()
482 This function returns an arrayref of an array of hashes contianing the supplied data formatted suitably to
483 be passed off as a template parameter and used to build an html table.
485 my $table = html_table(header_fields, array_of_row_data);
486 $template->param(
487 table_loop => $table,
490 html example:
492 <table>
493 [% FOREACH table_loo IN table_loop %]
494 [% IF ( table_loo.header_fields ) %]
495 <tr>
496 [% FOREACH header_field IN table_loo.header_fields %]
497 <th>[% header_field.field_label %]</th>
498 [% END %]
499 </tr>
500 [% ELSE %]
501 <tr>
502 [% FOREACH text_field IN table_loo.text_fields %]
503 [% IF ( text_field.select_field ) %]
504 <td><input type="checkbox" name="action" value="[% text_field.field_value %]"></td>
505 [% ELSE %]
506 <td>[% text_field.field_value %]</td>
507 [% END %]
508 [% END %]
509 </tr>
510 [% END %]
511 [% END %]
512 </table>
514 =cut
516 sub html_table {
517 my $headers = shift;
518 my $data = shift;
519 return undef if scalar(@$data) == 0; # no need to generate a table if there is not data to display
520 my $table = [];
521 my $fields = [];
522 my @table_columns = ();
523 my ($row_index, $col_index) = (0,0);
524 my $cols = 0; # number of columns to wrap on
525 my $field_count = 0;
526 my $select_value = undef;
527 my $link_field = undef;
528 POPULATE_HEADER:
529 foreach my $header (@$headers) {
530 my @key = keys %$header;
531 if ($key[0] eq 'select' ) {
532 push (@table_columns, $key[0]);
533 $$fields[$col_index] = {hidden => 0, select_field => 0, field_name => ($key[0]), field_label => $header->{$key[0]}{'label'}};
534 # do special formatting stuff....
535 $select_value = $header->{$key[0]}{'value'};
537 else {
538 # do special formatting stuff....
539 $link_field->{$key[0]} = ($header->{$key[0]}{'link_field'} == 1 ? 1 : 0);
540 push (@table_columns, $key[0]);
541 $$fields[$col_index] = {hidden => 0, select_field => 0, field_name => ($key[0]), field_label => $header->{$key[0]}{'label'}};
543 $field_count++;
544 $col_index++;
546 $$table[$row_index] = {header_fields => $fields};
547 $cols = $col_index;
548 $field_count *= scalar(@$data); # total fields to be displayed in the table
549 $col_index = 0;
550 $row_index++;
551 $fields = [];
552 POPULATE_TABLE:
553 foreach my $db_row (@$data) {
554 POPULATE_ROW:
555 foreach my $table_column (@table_columns) {
556 if (grep {$table_column eq $_} keys %$db_row) {
557 $$fields[$col_index] = {hidden => 0, link_field => $link_field->{$table_column}, select_field => 0, field_name => ($table_column . "_tbl"), field_value => $db_row->{$table_column}};
558 $col_index++;
559 next POPULATE_ROW;
561 elsif ($table_column =~ m/^_((.*)_(.*$))/) { # this a special case
562 my $table_name = get_table_names($2);
563 my $record_set = _SELECT($1, @$table_name[0], $2 . "_id = " . $db_row->{$2 . "_id"});
564 $$fields[$col_index] = {hidden => 0, link_field => $link_field->{$table_column}, select_field => 0, field_name => ($table_column . "_tbl"), field_value => $$record_set[0]{$1}};
565 $col_index++;
566 next POPULATE_ROW;
568 elsif ($table_column eq 'select' ) {
569 $$fields[$col_index] = {hidden => 0, select_field => 1, field_name => 'select', field_value => $db_row->{$select_value}};
572 $$table[$row_index] = {text_fields => $fields};
573 $col_index = 0;
574 $row_index++;
575 $fields = [];
577 return $table;
581 __END__
583 =head1 AUTHOR
585 Chris Nighswonger <cnighswonger AT foundations DOT edu>
587 =cut