[35/40] Work on C4::Labels tests and various bugfixs resulting
[koha.git] / C4 / Labels / Batch.pm
1 package C4::Labels::Batch;
2
3 use strict;
4 use warnings;
5
6 use Sys::Syslog qw(syslog);
7
8 use C4::Context;
9 use C4::Debug;
10
11 BEGIN {
12     use version; our $VERSION = qv('1.0.0_1');
13 }
14
15 sub _check_params {
16     my $given_params = {};
17     my $exit_code = 0;
18     my @valid_template_params = (
19         'label_id',
20         'batch_id',
21         'item_number',
22         'branch_code',
23     );
24     if (scalar(@_) >1) {
25         $given_params = {@_};
26         foreach my $key (keys %{$given_params}) {
27             if (!(grep m/$key/, @valid_template_params)) {
28                 syslog("LOG_ERR", "C4::Labels::Batch : Unrecognized parameter type of \"%s\".", $key);
29                 $exit_code = 1;
30             }
31         }
32     }
33     else {
34         if (!(grep m/$_/, @valid_template_params)) {
35             syslog("LOG_ERR", "C4::Labels::Batch : Unrecognized parameter type of \"%s\".", $_);
36             $exit_code = 1;
37         }
38     }
39     return $exit_code;
40 }
41
42 sub new {
43     my ($invocant) = shift;
44     my $type = ref($invocant) || $invocant;
45     my $self = {
46         batch_id        => 0,
47         items           => [],
48         branch_code     => 'NB',
49         batch_stat      => 0,   # False if any data has changed and the db has not been updated
50         @_,
51     };
52     my $sth = C4::Context->dbh->prepare("SELECT MAX(batch_id) FROM labels_batches;");
53     $sth->execute();
54     my $batch_id = $sth->fetchrow_array;
55     $self->{'batch_id'} = ++$batch_id unless $self->{'batch_id'} != 0;      # this allows batch_id to be passed in for individual label printing
56     bless ($self, $type);
57     return $self;
58 }
59
60 sub add_item {
61     my $self = shift;
62     my $item_number = shift;
63     my $query = "INSERT INTO labels_batches (batch_id, item_number, branch_code) VALUES (?,?,?);";
64     my $sth = C4::Context->dbh->prepare($query);
65 #    $sth->{'TraceLevel'} = 3;
66     $sth->execute($self->{'batch_id'}, $item_number, $self->{'branch_code'});
67     if ($sth->err) {
68         syslog("LOG_ERR", "C4::Labels::Batch->add_item : Database returned the following error on attempted INSERT: %s", $sth->errstr);
69         return -1;
70     }
71     $query = "SELECT max(label_id) FROM labels_batches WHERE batch_id=? AND item_number=? AND branch_code=?;";
72     my $sth1 = C4::Context->dbh->prepare($query);
73     $sth1->execute($self->{'batch_id'}, $item_number, $self->{'branch_code'});
74     my $label_id = $sth1->fetchrow_array;
75     push (@{$self->{'items'}}, {item_number => $item_number, label_id => $label_id});
76     $self->{'batch_stat'} = 1;
77     return 0;
78 }
79
80 sub get_attr {
81     my $self = shift;
82     return $self->{$_[0]};
83 }
84
85 sub remove_item {
86     my $self = shift;
87     my $label_id = shift;
88     my $query = "DELETE FROM labels_batches WHERE label_id=? AND batch_id=?;";
89     my $sth = C4::Context->dbh->prepare($query);
90 #    $sth->{'TraceLevel'} = 3;
91     $sth->execute($label_id, $self->{'batch_id'});
92     if ($sth->err) {
93         syslog("LOG_ERR", "C4::Labels::Batch->remove_item : Database returned the following error on attempted DELETE: %s", $sth->errstr);
94         return -1;
95     }
96     @{$self->{'items'}} = grep{$_->{'label_id'} != $label_id} @{$self->{'items'}};
97     $self->{'batch_stat'} = 1;
98     return 0;
99 }
100
101 # FIXME: This method is effectively useless the way the current add_item method is written. Ideally, the items should be added to the object
102 #       and then the save method called. This does not work well in practice due to the inability to pass objects accross cgi script calls.
103 #       I'm leaving it here because it should be here and for consistency's sake. -cnighswonger
104 #
105 #=head2 $batch->save()
106 #
107 #    Invoking the I<save> method attempts to insert the batch into the database. The method returns
108 #    the new record batch_id upon success and -1 upon failure (This avoids conflicting with a record
109 #    batch_id of 1). Errors are logged to the syslog.
110 #
111 #    example:
112 #        my $exitstat = $batch->save(); # to save the record behind the $batch object
113 #
114 #=cut
115 #
116 #sub save {
117 #    my $self = shift;
118 #    foreach my $item_number (@{$self->{'items'}}) {
119 #        my $query = "INSERT INTO labels_batches (batch_id, item_number, branch_code) VALUES (?,?,?);";
120 #        my $sth1 = C4::Context->dbh->prepare($query);
121 #        $sth1->execute($self->{'batch_id'}, $item_number->{'item_number'}, $self->{'branch_code'});
122 #        if ($sth1->err) {
123 #            syslog("LOG_ERR", "C4::Labels::Batch->save : Database returned the following error on attempted INSERT: %s", $sth1->errstr);
124 #            return -1;
125 #        }
126 #        $self->{'batch_stat'} = 1;
127 #        return $self->{'batch_id'};
128 #    }
129 #}
130
131 sub retrieve {
132     my $invocant = shift;
133     my %opts = @_;
134     my $type = ref($invocant) || $invocant;
135     my $record_flag = 0;
136     my $query = "SELECT * FROM labels_batches WHERE batch_id = ? ORDER BY label_id";  
137     my $sth = C4::Context->dbh->prepare($query);
138 #    $sth->{'TraceLevel'} = 3;
139     $sth->execute($opts{'batch_id'});
140     my $self = {
141         batch_id        => $opts{'batch_id'},
142         items           => [],
143     };
144     while (my $record = $sth->fetchrow_hashref) {
145         $self->{'branch_code'} = $record->{'branch_code'};
146         push (@{$self->{'items'}}, {item_number => $record->{'item_number'}, label_id => $record->{'label_id'}});
147         $record_flag = 1;       # true if one or more rows were retrieved
148     }
149     return -2 if $record_flag == 0;     # a hackish sort of way of indicating no such record exists
150     if ($sth->err) {
151         syslog("LOG_ERR", "C4::Labels::Batch->retrieve : Database returned the following error on attempted SELECT: %s", $sth->errstr);
152         return -1;
153     }
154     $self->{'batch_stat'} = 1;
155     bless ($self, $type);
156     return $self;
157 }
158
159 sub delete {
160     my $self = {};
161     my %opts = ();
162     my $call_type = '';
163     my @query_params = ();
164     if (ref($_[0])) {
165         $self = shift;  # check to see if this is a method call
166         $call_type = 'C4::Labels::Batch->delete';
167         @query_params = ($self->{'batch_id'}, $self->{'branch_code'});
168     }
169     else {
170         %opts = @_;
171         $call_type = 'C4::Labels::Batch::delete';
172         @query_params = ($opts{'batch_id'}, $opts{'branch_code'});
173     }
174     if ($query_params[0] eq '') {   # If there is no template id then we cannot delete it
175         syslog("LOG_ERR", "%s : Cannot delete batch as the batch id is invalid or non-existant.", $call_type);
176         return -1;
177     }
178     my $query = "DELETE FROM labels_batches WHERE batch_id = ? AND branch_code =?";
179     my $sth = C4::Context->dbh->prepare($query);
180 #    $sth->{'TraceLevel'} = 3;
181     $sth->execute(@query_params);
182     if ($sth->err) {
183         syslog("LOG_ERR", "%s : Database returned the following error on attempted INSERT: %s", $call_type, $sth->errstr);
184         return -1;
185     }
186     return 0;
187 }
188
189 sub remove_duplicates {
190     my $self = shift;
191     my %seen=();
192     my $query = "DELETE FROM labels_batches WHERE label_id = ?;"; # ORDER BY timestamp ASC LIMIT ?;";
193     my $sth = C4::Context->dbh->prepare($query);
194     my @duplicate_items = grep{$seen{$_->{'item_number'}}++} @{$self->{'items'}};
195     foreach my $item (@duplicate_items) {
196         $sth->execute($item->{'label_id'});
197         if ($sth->err) {
198             syslog("LOG_ERR", "C4::Labels::Batch->remove_duplicates() : Database returned the following error on attempted DELETE for label_id %s: %s", $item->{'label_id'}, $sth->errstr);
199             return -1;
200         }
201         $sth->finish(); # Per DBI.pm docs: "If execute() is called on a statement handle that's still active ($sth->{Active} is true) then it should effectively call finish() to tidy up the previous execution results before starting this new execution."
202         @{$self->{'items'}} = grep{$_->{'label_id'} != $item->{'label_id'}} @{$self->{'items'}};  # the correct label/item must be removed from the current batch object as well; this should be done *after* each sql DELETE in case the DELETE fails
203     }
204     return scalar(@duplicate_items);
205 }
206
207 1;
208 __END__
209
210 =head1 NAME
211
212 C4::Labels::Batch - A class for creating and manipulating batch objects in Koha
213
214 =head1 ABSTRACT
215
216 This module provides methods for creating, and otherwise manipulating batch objects used by Koha to create and export labels.
217
218 =head1 METHODS
219
220 =head2 new()
221
222     Invoking the I<new> method constructs a new batch object with no items. It is possible to pre-populate the batch with items and a branch code by passing them
223     as in the second example below.
224
225     B<NOTE:> The items list must be an arrayref pointing to an array of hashes containing a key/data pair after this fashion: {item_number => item_number}. The order of
226     the array elements determines the order of the items in the batch.
227
228     example:
229         C<my $batch = C4::Labels::Batch->new(); # Creates and returns a new batch object>
230
231         C<my $batch = C4::Labels::Batch->new(items => $arrayref, branch_code => branch_code) #    Creates and returns a new batch object containing the items passed in
232             with the branch code passed in.>
233
234     B<NOTE:> This batch is I<not> written to the database until C<$batch->save()> is invoked. You have been warned!
235
236 =head2 $batch->add_item(item_number => $item_number, branch_code => $branch_code)
237
238     Invoking the I<add_item> method will add the supplied item to the batch object.
239
240     example:
241         $batch->add_item(item_number => $item_number, branch_code => $branch_code);
242
243 =head2 $batch->get_attr($attribute)
244
245     Invoking the I<get_attr> method will return the requested attribute.
246
247     example:
248         my @items = $batch->get_attr('items');
249
250 =head2 $batch->remove_item($item_number)
251
252     Invoking the I<remove_item> method will remove the supplied item number from the batch object.
253
254     example:
255         $batch->remove_item($item_number);
256
257 =head2 C4::Labels::Batch->retrieve(batch_id => $batch_id)
258
259     Invoking the I<retrieve> method constructs a new batch object containing the current values for batch_id. The method returns a new object upon success and 1 upon failure.
260     Errors are logged to the syslog.
261
262     examples:
263
264         my $batch = C4::Labels::Batch->retrieve(batch_id => 1); # Retrieves batch 1 and returns an object containing the record
265
266 =head2 delete()
267
268     Invoking the delete method attempts to delete the template from the database. The method returns -1 upon failure. Errors are logged to the syslog.
269     NOTE: This method may also be called as a function and passed a key/value pair simply deleteing that batch from the database. See the example below.
270
271     examples:
272         my $exitstat = $batch->delete(); # to delete the record behind the $batch object
273         my $exitstat = C4::Labels::Batch->delete(batch_id => 1); # to delete batch 1
274
275 =head2 remove_duplicates()
276
277     Invoking the remove_duplicates method attempts to remove duplicate items in the batch from the database. The method returns the count of duplicate records removed upon
278     success and -1 upon failure. Errors are logged to the syslog.
279     NOTE: This method may also be called as a function and passed a key/value pair removing duplicates in the batch passed in. See the example below.
280
281     examples:
282         my $remove_count = $batch->remove_duplicates(); # to remove duplicates the record behind the $batch object
283         my $remove_count = C4::Labels::Batch->remove_duplicates(batch_id => 1); # to remove duplicates in batch 1
284
285 =head1 AUTHOR
286
287 Chris Nighswonger <cnighswonger AT foundations DOT edu>
288
289 =head1 COPYRIGHT
290
291 Copyright 2009 Foundations Bible College.
292
293 =head1 LICENSE
294
295 This file is part of Koha.
296        
297 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
298 Foundation; either version 2 of the License, or (at your option) any later version.
299
300 You should have received a copy of the GNU General Public License along with Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
301 Suite 330, Boston, MA  02111-1307 USA
302
303 =head1 DISCLAIMER OF WARRANTY
304
305 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
306 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
307
308 =cut
309