Bugs 6634: manager_id not recorded for payments and rental charges
[koha.git] / C4 / Creators / Layout.pm
1 package C4::Creators::Layout;
2
3 use strict;
4 use warnings;
5
6 use autouse 'Data::Dumper' => qw(Dumper);
7
8 use C4::Context;
9 use C4::Debug;
10 use C4::Creators::PDF;
11
12 BEGIN {
13     use version; our $VERSION = qv('1.0.0_1');
14 }
15
16 # FIXME: Consider this style parameter verification instead...
17 #  my %param = @_;
18 #   for (keys %param)
19 #    {   my $lc = lc($_);
20 #        if (exists $default{$lc})
21 #        {  $default{$lc} = $param{$_};
22 #        }
23 #        else
24 #        {  print STDERR "Unknown parameter $_ , not used \n";
25 #        }
26 #    }
27
28 sub _check_params {
29     my $exit_code = 0;
30     my @valtmpl_id_params = (
31         'layout_id',
32         'barcode_type',
33         'printing_type',
34         'layout_name',
35         'guidebox',
36         'font',
37         'font_size',
38         'callnum_split',
39         'text_justify',
40         'format_string',
41         'layout_xml',           # FIXME: all layouts should be stored in xml format to greatly simplify handling -chris_n
42         'creator',
43         'units',
44         'start_label',
45     );
46     if (scalar(@_) >1) {
47         my %given_params = @_;
48         foreach my $key (keys %given_params) {
49             if (!(grep m/$key/, @valtmpl_id_params)) {
50                 warn sprintf('(Multiple parameters) Unrecognized parameter type of "%s".', $key);
51                 $exit_code = 1;
52             }
53         }
54     }
55     else {
56         if (!(grep m/$_/, @valtmpl_id_params)) {
57             warn sprintf('(Single parameter) Unrecognized parameter type of "%s".', $_);
58             $exit_code = 1;
59         }
60     }
61     return $exit_code;
62 }
63
64 sub new {
65     my $invocant = shift;
66     my $self = '';
67     if (_check_params(@_) eq 1) {
68         return -1;
69     }
70     my $type = ref($invocant) || $invocant;
71     if (grep {$_ eq 'Labels'} @_) {
72        $self = {
73             layout_xml      =>      '',
74             units           =>      'POINT',
75             start_label     =>      1,
76             barcode_type    =>      'CODE39',
77             printing_type   =>      'BAR',
78             layout_name     =>      'DEFAULT',
79             guidebox        =>      0,
80             font            =>      'TR',
81             font_size       =>      3,
82             callnum_split   =>      0,
83             text_justify    =>      'L',
84             format_string   =>      'title, author, isbn, issn, itemtype, barcode, callnumber',
85             @_,
86         };
87     }
88     elsif (grep {$_ eq 'Patroncards'} @_) {
89         $self = {
90             layout_xml => '<opt>Default Layout</opt>',
91             @_,
92         }
93     }
94     bless ($self, $type);
95     return $self;
96 }
97
98 sub retrieve {
99     my $invocant = shift;
100     my %opts = @_;
101     my $type = ref($invocant) || $invocant;
102     my $query = "SELECT * FROM creator_layouts WHERE layout_id = ? AND creator = ?";
103     my $sth = C4::Context->dbh->prepare($query);
104     $sth->execute($opts{'layout_id'}, $opts{'creator'});
105     if ($sth->err) {
106         warn sprintf('Database returned the following error: %s', $sth->errstr);
107         return -1;
108     }
109     my $self = $sth->fetchrow_hashref;
110     bless ($self, $type);
111     return $self;
112 }
113
114 sub delete {
115     my $self = {};
116     my %opts = ();
117     my $call_type = '';
118     my @params = ();
119     if (ref($_[0])) {
120         $self = shift;  # check to see if this is a method call
121         $call_type = 'C4::Labels::Layout->delete';
122         push @params, $self->{'layout_id'}, $self->{'creator'};
123     }
124     else {
125         my $class = shift;
126         %opts = @_;
127         $call_type = $class . '::delete';
128         push @params, $opts{'layout_id'}, $opts{'creator'};
129     }
130     if (scalar(@params) < 2) {   # If there is no layout id or creator type then we cannot delete it
131         warn sprintf('%s : Cannot delete layout as the profile id is invalid or non-existant.', $call_type) if !$params[0];
132         warn sprintf('%s : Cannot delete layout as the creator type is invalid or non-existant.', $call_type) if !$params[1];
133         return -1;
134     }
135     my $query = "DELETE FROM creator_layouts WHERE layout_id = ? AND creator = ?";
136     my $sth = C4::Context->dbh->prepare($query);
137     $sth->execute(@params);
138     if ($sth->err) {
139         warn sprintf('Database returned the following error on attempted DELETE: %s', $sth->errstr);
140         return -1;
141     }
142 }
143
144 sub save {
145     my $self = shift;
146     if ($self->{'layout_id'}) {        # if we have an id, the record exists and needs UPDATE
147         my @params;
148         my $query = "UPDATE creator_layouts SET ";
149         foreach my $key (keys %{$self}) {
150             next if ($key eq 'layout_id') || ($key eq 'creator');
151             push (@params, $self->{$key});
152             $query .= "$key=?, ";
153         }
154         $query = substr($query, 0, (length($query)-2));
155         $query .= " WHERE layout_id=? AND creator = ?;";
156         push (@params, $self->{'layout_id'}, $self->{'creator'});
157         my $sth = C4::Context->dbh->prepare($query);
158         #local $sth->{TraceLevel} = "3";        # enable DBI trace and set level; outputs to STDERR
159         $sth->execute(@params);
160         if ($sth->err) {
161             warn sprintf('Database returned the following error: %s', $sth->errstr);
162             return -1;
163         }
164         return $self->{'layout_id'};
165     }
166     else {                      # otherwise create a new record
167         my @params;
168         my $query = "INSERT INTO creator_layouts (";
169         foreach my $key (keys %{$self}) {
170             push (@params, $self->{$key});
171             $query .= "$key, ";
172         }
173         $query = substr($query, 0, (length($query)-2));
174         $query .= ") VALUES (";
175         for (my $i=1; $i<=(scalar keys %$self); $i++) {
176             $query .= "?,";
177         }
178         $query = substr($query, 0, (length($query)-1));
179         $query .= ");";
180         my $sth = C4::Context->dbh->prepare($query);
181         $sth->execute(@params);
182         if ($sth->err) {
183             warn sprintf('Database returned the following error: %s', $sth->errstr);
184             return -1;
185         }
186         my $sth1 = C4::Context->dbh->prepare("SELECT MAX(layout_id) FROM creator_layouts;");
187         $sth1->execute();
188         my $id = $sth1->fetchrow_array;
189         $self->{'layout_id'} = $id;
190         return $id;
191     }
192 }
193
194 sub get_attr {
195     my $self = shift;
196     if (_check_params(@_) eq 1) {
197         return -1;
198     }
199     my ($attr) = @_;
200     if (exists($self->{$attr})) {
201         return $self->{$attr};
202     }
203     else {
204         return -1;
205     }
206     return;
207 }
208
209 sub set_attr {
210     my $self = shift;
211     if (_check_params(@_) eq 1) {
212         return -1;
213     }
214     my %attrs = @_;
215     foreach my $attrib (keys(%attrs)) {
216         $self->{$attrib} = $attrs{$attrib};
217     };
218     return 0;
219 }
220
221 sub get_text_wrap_cols {
222     my $self = shift;
223     my %params = @_;
224     my $string = '';
225     my $strwidth = 0;
226     my $col_count = 0;
227     my $textlimit = $params{'label_width'} - (( 3 * $params{'left_text_margin'} ) || 13.5 );
228
229     while ($strwidth < $textlimit) {
230         $string .= '0';
231         $col_count++;
232         $strwidth = C4::Creators::PDF->StrWidth( $string, $self->{'font'}, $self->{'font_size'} );
233     }
234     return $col_count;
235 }
236
237 1;
238 __END__
239
240 =head1 NAME
241
242 C4::Labels::Layout -A class for creating and manipulating layout objects in Koha
243
244 =head1 ABSTRACT
245
246 This module provides methods for creating, retrieving, and otherwise manipulating label layout objects used by Koha to create and export labels.
247
248 =head1 METHODS
249
250 =head2 new()
251
252     Invoking the I<new> method constructs a new layout object containing the default values for a layout.
253     The following parameters are optionally accepted as key => value pairs:
254
255         C<barcode_type>         Defines the barcode type to be used on labels. NOTE: At present only the following barcode types are supported in the label creator code:
256
257 =over 9
258
259 =item .
260             CODE39          = Code 3 of 9
261
262 =item .
263             CODE39MOD       = Code 3 of 9 with modulo 43 checksum
264
265 =item .
266             CODE39MOD10     = Code 3 of 9 with modulo 10 checksum
267
268 =item .
269             COOP2OF5        = A varient of 2 of 5 barcode based on NEC's "Process 8000" code
270
271 =item .
272             INDUSTRIAL2OF5  = The standard 2 of 5 barcode (a binary level bar code developed by Identicon Corp. and Computer Identics Corp. in 1970)
273
274 =back
275
276         C<printing_type>        Defines the general layout to be used on labels. NOTE: At present there are only five printing types supported in the label creator code:
277
278 =over 9
279
280 =item .
281 BIB     = Only the bibliographic data is printed
282
283 =item .
284 BARBIB  = Barcode proceeds bibliographic data
285
286 =item .
287 BIBBAR  = Bibliographic data proceeds barcode
288
289 =item .
290 ALT     = Barcode and bibliographic data are printed on alternating labels
291
292 =item .
293 BAR     = Only the barcode is printed
294
295 =back
296
297         C<layout_name>          The descriptive name for this layout.
298         C<guidebox>             Setting this to '1' will result in a guide box being drawn around the labels marking the edge of each label
299         C<font>                 Defines the type of font to be used on labels. NOTE: The following fonts are available by default on most systems:
300
301 =over 9
302
303 =item .
304 TR      = Times-Roman
305
306 =item .
307 TB      = Times Bold
308
309 =item .
310 TI      = Times Italic
311
312 =item .
313 TBI     = Times Bold Italic
314
315 =item .
316 C       = Courier
317
318 =item .
319 CB      = Courier Bold
320
321 =item .
322 CO      = Courier Oblique (Italic)
323
324 =item .
325 CBO     = Courier Bold Oblique
326
327 =item .
328 H       = Helvetica
329
330 =item .
331 HB      = Helvetica Bold
332
333 =item .
334 HBO     = Helvetical Bold Oblique
335
336 =back
337
338         C<font_size>            Defines the size of the font in postscript points to be used on labels
339         C<callnum_split>        Setting this to '1' will enable call number splitting on labels
340         C<text_justify>         Defines the text justification to be used on labels. NOTE: The following justification styles are currently supported by label creator code:
341
342 =over 9
343
344 =item .
345 L       = Left
346
347 =item .
348 C       = Center
349
350 =item .
351 R       = Right
352
353 =back
354
355         C<format_string>        Defines what fields will be printed and in what order they will be printed on labels. These include any of the data fields that may be mapped
356                                 to your MARC frameworks. Specify MARC subfields as a 4-character tag-subfield string: ie. 254a Enclose a whitespace-separated list of fields
357                                 to concatenate on one line in double quotes. ie. "099a 099b" or "itemcallnumber barcode" Static text strings may be entered in single-quotes:
358                                 ie. 'Some static text here.'
359
360     example:
361         C<my $layout = Layout->new(); # Creates and returns a new layout object>
362
363         C<my $layout = C4::Labels::Layout->new(barcode_type => 'CODE39', printing_type => 'BIBBAR', font => 'C', font_size => 6); # Creates and returns a new layout object using
364             the supplied values to override the defaults>
365
366     B<NOTE:> This layout is I<not> written to the database until save() is invoked. You have been warned!
367
368 =head2 retrieve(layout_id => layout_id)
369
370     Invoking the I<retrieve> method constructs a new layout object containing the current values for layout_id. The method returns a new object upon success and 1 upon failure.
371     Errors are logged to the Apache log.
372
373     example:
374         C<my $layout = Layout->retrieve(layout_id => 1); # Retrieves layout record 1 and returns an object containing the record>
375
376 =head2 delete()
377
378     Invoking the delete method attempts to delete the layout from the database. The method returns 0 upon success and -1 upon failure. Errors are logged to the Apache log.
379     NOTE: This method may also be called as a function and passed a key/value pair simply deleteing that template from the database. See the example below.
380
381     examples:
382         C<my $exitstat = $layout->delete(); # to delete the record behind the $layout object>
383         C<my $exitstat = Layout->delete(layout_id => 1); # to delete layout record 1>
384
385 =head2 save()
386
387     Invoking the I<save> method attempts to insert the layout into the database if the layout is new and update the existing layout record if the layout exists.
388     The method returns the new record id upon success and -1 upon failure (This avoids conflicting with a record id of 1). Errors are logged to the Apache log.
389
390     example:
391         C<my $exitstat = $layout->save(); # to save the record behind the $layout object>
392
393 =head2 get_attr($attribute)
394
395     Invoking the I<get_attr> method will return the value of the requested attribute or -1 on errors.
396
397     example:
398         C<my $value = $layout->get_attr($attribute);>
399
400 =head2 set_attr(attribute => value, attribute_2 => value)
401
402     Invoking the I<set_attr> method will set the value of the supplied attributes to the supplied values. The method accepts key/value pairs separated by
403     commas.
404
405     example:
406         C<$layout->set_attr(attribute => value);>
407
408 =head2 get_text_wrap_cols()
409
410     Invoking the I<get_text_wrap_cols> method will return the number of columns that can be printed on the label before wrapping to the next line.
411
412     examples:
413         C<my $text_wrap_cols = $layout->get_text_wrap_cols();>
414
415 =head1 AUTHOR
416
417 Chris Nighswonger <cnighswonger AT foundations DOT edu>
418
419 =head1 COPYRIGHT
420
421 Copyright 2009 Foundations Bible College.
422
423 =head1 LICENSE
424
425 This file is part of Koha.
426
427 Koha is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
428 Foundation; either version 2 of the License, or (at your option) any later version.
429
430 You should have received a copy of the GNU General Public License along with Koha; if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
431 Fifth Floor, Boston, MA 02110-1301 USA.
432
433 =head1 DISCLAIMER OF WARRANTY
434
435 Koha is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
436 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
437
438 =cut