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