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