Bug 16573: change created_on type - atomic update
[koha.git] / C4 / Creators / Lib.pm
blob2063d5de81005031a45cb4330965623fec9a4328
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
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
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 base qw(Exporter);
30 our @EXPORT = qw(get_all_templates
31 get_all_layouts
32 get_all_profiles
33 get_all_image_names
34 get_batch_summary
35 get_label_summary
36 get_card_summary
37 get_barcode_types
38 get_label_types
39 get_font_types
40 get_text_justification_types
41 get_output_formats
42 get_table_names
43 get_unit_values
44 html_table
48 =head1 NAME
50 C4::Creators::Lib
52 =cut
54 =head1 FUNCTIONS
56 =cut
58 #=head2 C4::Creators::Lib::_SELECT()
60 # This function returns a recordset upon success and 1 upon failure. Errors are logged to the Apache log.
62 # examples:
64 # my $field_value = _SELECT(field_name, table_name, condition);
66 #=cut
68 sub _SELECT {
69 my @params = @_;
70 my $query = "SELECT $params[0] FROM $params[1]";
71 $params[2] ? $query .= " WHERE $params[2];" : $query .= ';';
72 my $sth = C4::Context->dbh->prepare($query);
73 # $sth->{'TraceLevel'} = 3;
74 $sth->execute();
75 if ($sth->err) {
76 warn sprintf('Database returned the following error: %s', $sth->errstr);
77 return 1;
79 my $record_set = [];
80 while (my $row = $sth->fetchrow_hashref()) {
81 push(@$record_set, $row);
83 return $record_set;
86 my $barcode_types = [
87 {type => 'CODE39', name => 'Code 39', desc => 'Translates the characters 0-9, A-Z, \'-\', \'*\', \'+\', \'$\', \'%\', \'/\', \'.\' and \' \' to a barcode pattern.', selected => 0},
88 {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},
89 {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},
90 {type => 'COOP2OF5', name => 'COOP2of5', desc => 'Creates COOP2of5 barcodes from a string consisting of the numeric characters 0-9', selected => 0},
91 {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},
92 # {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},
93 # {type => 'IATA2of5', name => 'IATA2of5', desc => 'Creates IATA2of5 barcodes from a string consisting of the numeric characters 0-9', selected => 0},
94 {type => 'INDUSTRIAL2OF5', name => 'Industrial2of5', desc => 'Creates Industrial2of5 barcodes from a string consisting of the numeric characters 0-9', selected => 0},
95 # {type => 'ITF', name => 'Interleaved2of5', desc => 'Translates the characters 0-9 to a barcodes. These barcodes could also be called 'Interleaved2of5'.', selected => 0},
96 # {type => 'MATRIX2OF5', name => 'Matrix2of5', desc => 'Creates Matrix2of5 barcodes from a string consisting of the numeric characters 0-9', selected => 0},
97 # {type => 'NW7', name => 'NW7', desc => 'Creates a NW7 barcodes from a string consisting of the numeric characters 0-9', selected => 0},
98 # {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},
99 # {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},
102 my $label_types = [
103 {type => 'BIB', name => 'Biblio', desc => 'Only the bibliographic data is printed.', selected => 0},
104 {type => 'BARBIB', name => 'Barcode/Biblio', desc => 'Barcode proceeds bibliographic data.', selected => 0},
105 {type => 'BIBBAR', name => 'Biblio/Barcode', desc => 'Bibliographic data proceeds barcode.', selected => 0},
106 {type => 'ALT', name => 'Alternating', desc => 'Barcode and bibliographic data are printed on alternating labels.', selected => 0},
107 {type => 'BAR', name => 'Barcode', desc => 'Only the barcode is printed.', selected => 0},
110 my $font_types = [
111 {type => 'TR', name => 'Times-Roman', selected => 0},
112 {type => 'TB', name => 'Times-Bold', selected => 0},
113 {type => 'TI', name => 'Times-Italic', selected => 0},
114 {type => 'TBI', name => 'Times-Bold-Italic', selected => 0},
115 {type => 'C', name => 'Courier', selected => 0},
116 {type => 'CB', name => 'Courier-Bold', selected => 0},
117 {type => 'CO', name => 'Courier-Oblique', selected => 0},
118 {type => 'CBO', name => 'Courier-Bold-Oblique', selected => 0},
119 {type => 'H', name => 'Helvetica', selected => 0},
120 {type => 'HO', name => 'Helvetica-Oblique', selected => 0},
121 {type => 'HB', name => 'Helvetica-Bold', selected => 0},
122 {type => 'HBO', name => 'Helvetica-Bold-Oblique', selected => 0},
125 my $text_justification_types = [
126 {type => 'L', name => 'Left', selected => 0},
127 {type => 'C', name => 'Center', selected => 0},
128 {type => 'R', name => 'Right', selected => 0},
129 # {type => 'F', name => 'Full', selected => 0},
132 my $unit_values = [
133 {type => 'POINT', desc => 'PostScript Points', value => 1, selected => 0},
134 {type => 'AGATE', desc => 'Adobe Agates', value => 5.1428571, selected => 0},
135 {type => 'INCH', desc => 'US Inches', value => 72, selected => 0},
136 {type => 'MM', desc => 'SI Millimeters', value => 2.83464567, selected => 0},
137 {type => 'CM', desc => 'SI Centimeters', value => 28.3464567, selected => 0},
140 my $output_formats = [
141 {type => 'pdf', desc => 'PDF File'},
142 {type => 'csv', desc => 'CSV File'},
145 =head2 C4::Creators::Lib::get_all_templates()
147 my $templates = get_all_templates();
149 This function returns a reference to a hash containing all templates upon success and 1 upon failure. Errors are logged to the Apache log.
151 =cut
153 sub get_all_templates {
154 my %params = @_;
155 my @templates = ();
156 my $query = "SELECT " . ($params{'field_list'} ? $params{'field_list'} : '*') . " FROM creator_templates";
157 $query .= ($params{'filter'} ? " WHERE $params{'filter'} " : '');
158 $query .= ($params{'orderby'} ? " ORDER BY $params{'orderby'} " : '');
159 my $sth = C4::Context->dbh->prepare($query);
160 $sth->execute();
161 if ($sth->err) {
162 warn sprintf('Database returned the following error: %s', $sth->errstr);
163 return -1;
165 ADD_TEMPLATES:
166 while (my $template = $sth->fetchrow_hashref) {
167 push(@templates, $template);
169 return \@templates;
172 =head2 C4::Creators::Lib::get_all_layouts()
174 my $layouts = get_all_layouts();
176 This function returns a reference to a hash containing all layouts upon success and 1 upon failure. Errors are logged to the Apache log.
178 =cut
180 sub get_all_layouts {
181 my %params = @_;
182 my @layouts = ();
183 my $query = "SELECT " . ($params{'field_list'} ? $params{'field_list'} : '*') . " FROM creator_layouts";
184 $query .= ($params{'filter'} ? " WHERE $params{'filter'} " : '');
185 $query .= ($params{'orderby'} ? " ORDER BY $params{'orderby'} " : '');
186 my $sth = C4::Context->dbh->prepare($query);
187 $sth->execute();
188 if ($sth->err) {
189 warn sprintf('Database returned the following error: %s', $sth->errstr);
190 return -1;
192 ADD_LAYOUTS:
193 while (my $layout = $sth->fetchrow_hashref) {
194 push(@layouts, $layout);
196 return \@layouts;
199 =head2 C4::Creators::Lib::get_all_profiles()
201 my $profiles = get_all_profiles();
203 my $profiles = get_all_profiles(field_list => field_list, filter => filter_string);
205 This function returns an arrayref whose elements are hashes containing all profiles upon success and 1 upon failure. Errors are logged
206 to the Apache log. Two parameters are accepted. The first limits the field(s) returned. This parameter should be string of comma separted
207 fields. ie. "field_1, field_2, ...field_n" The second limits the records returned based on a string containing a valud SQL 'WHERE' filter.
209 NOTE: Do not pass in the keyword 'WHERE.'
211 =cut
213 sub get_all_profiles {
214 my %params = @_;
215 my @profiles = ();
216 my $query = "SELECT " . ($params{'field_list'} ? $params{'field_list'} : '*') . " FROM printers_profile";
217 $query .= ($params{'filter'} ? " WHERE $params{'filter'};" : ';');
218 my $sth = C4::Context->dbh->prepare($query);
219 # $sth->{'TraceLevel'} = 3 if $debug;
220 $sth->execute();
221 if ($sth->err) {
222 warn sprintf('Database returned the following error: %s', $sth->errstr);
223 return -1;
225 ADD_PROFILES:
226 while (my $profile = $sth->fetchrow_hashref) {
227 push(@profiles, $profile);
229 return \@profiles;
232 =head2 C4::Creators::Lib::get_all_image_names()
234 =cut
236 sub get_all_image_names {
237 my $image_names = [];
238 my $query = "SELECT image_name FROM creator_images";
239 my $sth = C4::Context->dbh->prepare($query);
240 # $sth->{'TraceLevel'} = 3 if $debug;
241 $sth->execute();
242 if ($sth->err) {
243 warn sprintf('Database returned the following error: %s', $sth->errstr);
244 return -1;
246 grep {push @$image_names, {type => $$_[0], name => $$_[0], selected => 0}} @{$sth->fetchall_arrayref([0])};
247 return $image_names;
250 =head2 C4::Creators::Lib::get_batch_summary()
252 my $batches = get_batch_summary();
254 my $batches = get_batch_summary(filter => filter_string);
256 This function returns an arrayref whose elements are hashes containing the batch_ids of current batches along with the item count
257 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.
258 One parameter is accepted which limits the records returned based on a string containing a valud SQL 'WHERE' filter.
260 NOTE: Do not pass in the keyword 'WHERE.'
262 =cut
264 sub get_batch_summary {
265 my %params = @_;
266 my @batches = ();
267 my $query = "SELECT batch_id,count(batch_id) as _item_count FROM creator_batches WHERE creator=?";
268 $query .= ($params{'filter'} ? " AND $params{'filter'}" : '');
269 $query .= " GROUP BY batch_id";
270 my $sth = C4::Context->dbh->prepare($query);
271 # $sth->{'TraceLevel'} = 3;
272 $sth->execute($params{'creator'});
273 if ($sth->err) {
274 warn sprintf('Database returned the following error on attempted SELECT: %s', $sth->errstr);
275 return -1;
277 while (my $batch = $sth->fetchrow_hashref) {
278 push(@batches, $batch);
280 return \@batches;
283 =head2 C4::Creators::Lib::get_label_summary()
285 my $labels = get_label_summary();
287 my $labels = get_label_summary(items => @item_list);
289 This function returns an arrayref whose elements are hashes containing the label_ids of current labels along with the item count
290 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.
291 One parameter is accepted which limits the records returned based on a string containing a valud SQL 'WHERE' filter.
293 NOTE: Do not pass in the keyword 'WHERE.'
295 =cut
297 sub get_label_summary {
298 my %params = @_;
299 my $label_number = 0;
300 my @label_summaries = ();
301 my $query = " SELECT b.title, b.author, bi.itemtype, i.barcode, i.biblionumber, i.itype
302 FROM creator_batches AS c LEFT JOIN items AS i ON (c.item_number=i.itemnumber)
303 LEFT JOIN biblioitems AS bi ON (i.biblioitemnumber=bi.biblioitemnumber)
304 LEFT JOIN biblio AS b ON (bi.biblionumber=b.biblionumber)
305 WHERE itemnumber=? AND batch_id=?;
307 my $sth = C4::Context->dbh->prepare($query);
308 foreach my $item (@{$params{'items'}}) {
309 $label_number++;
310 $sth->execute($item->{'item_number'}, $params{'batch_id'});
311 if ($sth->err) {
312 warn sprintf('Database returned the following error on attempted SELECT: %s', $sth->errstr);
313 return -1;
315 my $record = $sth->fetchrow_hashref;
316 my $label_summary;
317 $label_summary->{'_label_number'} = $label_number;
318 $record->{'author'} =~ s/[^\.|\w]$// if $record->{'author'}; # strip off ugly trailing chars... but not periods or word chars
319 $record->{'title'} =~ s/\W*$//; # strip off ugly trailing chars
320 # FIXME contructing staff interface URLs should be done *much* higher up the stack - for the most part, C4 module code
321 # should not know that it's part of a web app
322 $record->{'title'} = '<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=' . $record->{'biblionumber'} . '"> ' . $record->{'title'} . '</a>';
323 $label_summary->{'_summary'} = $record->{'title'} . " | " . ($record->{'author'} ? $record->{'author'} : 'N/A');
324 $label_summary->{'_item_type'} = C4::Context->preference("item-level_itypes") ? $record->{'itype'} : $record->{'itemtype'};
325 $label_summary->{'_barcode'} = $record->{'barcode'};
326 $label_summary->{'_item_number'} = $item->{'item_number'};
327 $label_summary->{'_label_id'} = $item->{'label_id'};
328 push (@label_summaries, $label_summary);
330 return \@label_summaries;
333 =head2 C4::Creators::Lib::get_card_summary()
335 my $cards = get_card_summary();
337 my $cards = get_card_summary(items => @item_list);
339 This function returns an arrayref whose elements are hashes containing the label_ids of current cards along with the item count
340 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.
341 One parameter is accepted which limits the records returned based on a string containing a valud SQL 'WHERE' filter.
343 NOTE: Do not pass in the keyword 'WHERE.'
345 =cut
347 sub get_card_summary {
348 my %params = @_;
349 my $card_number = 0;
350 my @card_summaries = ();
351 my $query = "SELECT CONCAT_WS(', ', surname, firstname) AS name, cardnumber FROM borrowers WHERE borrowernumber=?;";
352 my $sth = C4::Context->dbh->prepare($query);
353 foreach my $item (@{$params{'items'}}) {
354 $card_number++;
355 $sth->execute($item->{'borrower_number'});
356 if ($sth->err) {
357 warn sprintf('Database returned the following error on attempted SELECT: %s', $sth->errstr);
358 return -1;
360 my $record = $sth->fetchrow_hashref;
361 my $card_summary->{'_card_number'} = $card_number;
362 $card_summary->{'_summary'} = $record->{'name'};
363 $card_summary->{'borrowernumber'} = $item->{'borrower_number'};
364 $card_summary->{'_label_id'} = $item->{'label_id'};
365 push (@card_summaries, $card_summary);
367 return \@card_summaries;
370 =head2 C4::Creators::Lib::get_barcode_types()
372 my $barcode_types = get_barcode_types();
374 This function returns a reference to an array of hashes containing all barcode types along with their name and description.
376 =cut
378 sub get_barcode_types {
379 return $barcode_types;
382 =head2 C4::Creators::Lib::get_label_types()
384 my $label_types = get_label_types();
386 This function returns a reference to an array of hashes containing all label types along with their name and description.
388 =cut
390 sub get_label_types {
391 return $label_types;
394 =head2 C4::Creators::Lib::get_font_types()
396 my $font_types = get_font_types();
398 This function returns a reference to an array of hashes containing all font types along with their name and description.
400 =cut
402 sub get_font_types {
403 return $font_types;
406 =head2 C4::Creators::Lib::get_text_justification_types()
408 my $text_justification_types = get_text_justification_types();
410 This function returns a reference to an array of hashes containing all text justification types along with their name and description.
412 =cut
414 sub get_text_justification_types {
415 return $text_justification_types;
418 =head2 C4::Creators::Lib::get_unit_values()
420 my $unit_values = get_unit_values();
422 This function returns a reference to an array of hashes containing all unit types along with their description and multiplier.
423 NOTE: All units are relative to a PostScript Point.
424 There are 72 PS points to the inch.
426 =cut
428 sub get_unit_values {
429 return $unit_values;
432 =head2 C4::Creators::Lib::get_output_formats()
434 my $label_output_formats = get_output_formats();
436 This function returns a reference to an array of hashes containing all label output formats along with their description.
438 =cut
440 sub get_output_formats {
441 return $output_formats;
445 =head2 C4::Creators::Lib::get_table_names($search_term)
447 Return an arrayref of an array containing the table names which contain the supplied search term.
449 =cut
451 sub get_table_names {
452 my $search_term = shift;
453 my $dbh = C4::Context->dbh();
454 my $table_names = [];
455 my $sth = $dbh->table_info(undef,undef,"%$search_term%");
456 while (my $info = $sth->fetchrow_hashref()){
457 push (@$table_names, $info->{'TABLE_NAME'});
459 return $table_names;
462 =head2 C4::Creators::Lib::html_table()
464 This function returns an arrayref of an array of hashes contianing the supplied data formatted suitably to
465 be passed off as a template parameter and used to build an html table.
467 my $table = html_table(header_fields, array_of_row_data);
468 $template->param(
469 table_loop => $table,
472 html example:
474 <table>
475 [% FOREACH table_loo IN table_loop %]
476 [% IF ( table_loo.header_fields ) %]
477 <tr>
478 [% FOREACH header_field IN table_loo.header_fields %]
479 <th>[% header_field.field_label %]</th>
480 [% END %]
481 </tr>
482 [% ELSE %]
483 <tr>
484 [% FOREACH text_field IN table_loo.text_fields %]
485 [% IF ( text_field.select_field ) %]
486 <td><input type="checkbox" name="action" value="[% text_field.field_value %]"></td>
487 [% ELSE %]
488 <td>[% text_field.field_value %]</td>
489 [% END %]
490 [% END %]
491 </tr>
492 [% END %]
493 [% END %]
494 </table>
496 =cut
498 sub html_table {
499 my $headers = shift;
500 my $data = shift;
501 return undef if scalar(@$data) == 0; # no need to generate a table if there is not data to display
502 my $table = [];
503 my $fields = [];
504 my @table_columns = ();
505 my ($row_index, $col_index) = (0,0);
506 my $cols = 0; # number of columns to wrap on
507 my $field_count = 0;
508 my $select_value = undef;
509 my $link_field = undef;
510 POPULATE_HEADER:
511 foreach my $header (@$headers) {
512 my @key = keys %$header;
513 if ($key[0] eq 'select' ) {
514 push (@table_columns, $key[0]);
515 $$fields[$col_index] = {hidden => 0, select_field => 0, field_name => ($key[0]), field_label => $header->{$key[0]}{'label'}};
516 # do special formatting stuff....
517 $select_value = $header->{$key[0]}{'value'};
519 else {
520 # do special formatting stuff....
521 $link_field->{$key[0]} = ($header->{$key[0]}{'link_field'} == 1 ? 1 : 0);
522 push (@table_columns, $key[0]);
523 $$fields[$col_index] = {hidden => 0, select_field => 0, field_name => ($key[0]), field_label => $header->{$key[0]}{'label'}};
525 $field_count++;
526 $col_index++;
528 $$table[$row_index] = {header_fields => $fields};
529 $cols = $col_index;
530 $field_count *= scalar(@$data); # total fields to be displayed in the table
531 $col_index = 0;
532 $row_index++;
533 $fields = [];
534 POPULATE_TABLE:
535 foreach my $db_row (@$data) {
536 POPULATE_ROW:
537 foreach my $table_column (@table_columns) {
538 if (grep {$table_column eq $_} keys %$db_row) {
539 $$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}};
540 $col_index++;
541 next POPULATE_ROW;
543 elsif ($table_column =~ m/^_((.*)_(.*$))/) { # this a special case
544 my $table_name = get_table_names($2);
545 my $record_set = _SELECT($1, @$table_name[0], $2 . "_id = " . $db_row->{$2 . "_id"});
546 $$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}};
547 $col_index++;
548 next POPULATE_ROW;
550 elsif ($table_column eq 'select' ) {
551 $$fields[$col_index] = {hidden => 0, select_field => 1, field_name => 'select', field_value => $db_row->{$select_value}};
554 $$table[$row_index] = {text_fields => $fields};
555 $col_index = 0;
556 $row_index++;
557 $fields = [];
559 return $table;
563 __END__
565 =head1 AUTHOR
567 Chris Nighswonger <cnighswonger AT foundations DOT edu>
569 =cut