add ability to search on a date range of invoice events and then reprint or reemail...
[freeside.git] / FS / FS / cust_bill_event.pm
1 package FS::cust_bill_event;
2
3 use strict;
4 use vars qw( @ISA $DEBUG );
5 use FS::Record qw( qsearch qsearchs );
6 use FS::cust_bill;
7 use FS::part_bill_event;
8
9 @ISA = qw(FS::Record);
10
11 $DEBUG = 0;
12
13 =head1 NAME
14
15 FS::cust_bill_event - Object methods for cust_bill_event records
16
17 =head1 SYNOPSIS
18
19   use FS::cust_bill_event;
20
21   $record = new FS::cust_bill_event \%hash;
22   $record = new FS::cust_bill_event { 'column' => 'value' };
23
24   $error = $record->insert;
25
26   $error = $new_record->replace($old_record);
27
28   $error = $record->delete;
29
30   $error = $record->check;
31
32 =head1 DESCRIPTION
33
34 An FS::cust_bill_event object represents an complete invoice event.
35 FS::cust_bill_event inherits from FS::Record.  The following fields are
36 currently supported:
37
38 =over 4
39
40 =item eventnum - primary key
41
42 =item invnum - invoice (see L<FS::cust_bill>)
43
44 =item eventpart - event definition (see L<FS::part_bill_event>)
45
46 =item _date - specified as a UNIX timestamp; see L<perlfunc/"time">.  Also see
47 L<Time::Local> and L<Date::Parse> for conversion functions.
48
49 =item status - event status: B<done> or B<failed>
50
51 =item statustext - additional status detail (i.e. error message)
52
53 =back
54
55 =head1 METHODS
56
57 =over 4
58
59 =item new HASHREF
60
61 Creates a new completed invoice event.  To add the compelted invoice event to
62 the database, see L<"insert">.
63
64 Note that this stores the hash reference, not a distinct copy of the hash it
65 points to.  You can ask the object for a copy with the I<hash> method.
66
67 =cut
68
69 # the new method can be inherited from FS::Record, if a table method is defined
70
71 sub table { 'cust_bill_event'; }
72
73 =item insert
74
75 Adds this record to the database.  If there is an error, returns the error,
76 otherwise returns false.
77
78 =cut
79
80 # the insert method can be inherited from FS::Record
81
82 =item delete
83
84 Delete this record from the database.
85
86 =cut
87
88 # the delete method can be inherited from FS::Record
89
90 =item replace OLD_RECORD
91
92 Replaces the OLD_RECORD with this one in the database.  If there is an error,
93 returns the error, otherwise returns false.
94
95 =cut
96
97 # the replace method can be inherited from FS::Record
98
99 =item check
100
101 Checks all fields to make sure this is a valid completed invoice event.  If
102 there is an error, returns the error, otherwise returns false.  Called by the
103 insert and replace methods.
104
105 =cut
106
107 # the check method should currently be supplied - FS::Record contains some
108 # data checking routines
109
110 sub check {
111   my $self = shift;
112
113   my $error = $self->ut_numbern('eventnum')
114     || $self->ut_number('invnum')
115     || $self->ut_number('eventpart')
116     || $self->ut_number('_date')
117     || $self->ut_enum('status', [qw( done failed )])
118     || $self->ut_textn('statustext')
119   ;
120
121   return "Unknown invnum ". $self->invnum
122     unless qsearchs( 'cust_bill' ,{ 'invnum' => $self->invnum } );
123
124   return "Unknown eventpart ". $self->eventpart
125     unless qsearchs( 'part_bill_event' ,{ 'eventpart' => $self->eventpart } );
126
127   $self->SUPER::check;
128 }
129
130 =item part_bill_event
131
132 Returns the invoice event definition (see L<FS::part_bill_event>) for this
133 completed invoice event.
134
135 =cut
136
137 sub part_bill_event {
138   my $self = shift;
139   qsearchs( 'part_bill_event', { 'eventpart' => $self->eventpart } );
140 }
141
142 =item cust_bill
143
144 Returns the invoice (see L<FS::cust_bill>) for this completed invoice event.
145
146 =cut
147
148 sub cust_bill {
149   my $self = shift;
150   qsearchs( 'cust_bill', { 'invnum' => $self->invnum } );
151 }
152
153 =item retry
154
155 Changes the status of this event from B<done> to B<failed>, allowing it to be
156 retried.
157
158 =cut
159
160 sub retry {
161   my $self = shift;
162   return '' unless $self->status eq 'done';
163   my $old = ref($self)->new( { $self->hash } );
164   $self->status('failed');
165   $self->replace($old);
166 }
167
168 =back
169
170 =head1 SUBROUTINES
171
172 =over 4
173
174 =item reprint
175
176 =cut
177
178 sub process_reprint {
179   process_re_X('print', @_);
180 }
181
182 =item reemail
183
184 =cut
185
186 sub process_reemail {
187   process_re_X('email', @_);
188 }
189
190 =item refax
191
192 =cut
193
194 sub process_refax {
195   process_re_X('fax', @_);
196 }
197
198 use Storable qw(thaw);
199 use Data::Dumper;
200 use MIME::Base64;
201 sub process_re_X {
202   my( $method, $job ) = ( shift, shift );
203
204   my $param = thaw(decode_base64(shift));
205   warn Dumper($param) if $DEBUG;
206
207   re_X(
208     $method,
209     $param->{'beginning'},
210     $param->{'ending'},
211     $param->{'failed'},
212     $job,
213   );
214
215 }
216
217 sub re_X {
218   my($method, $beginning, $ending, $failed, $job) = @_;
219
220   my $where = " WHERE plan LIKE 'send%'".
221               "   AND cust_bill_event._date >= $beginning".
222               "   AND cust_bill_event._date <= $ending";
223   $where .= " AND statustext != '' AND statustext IS NOT NULL"
224     if $failed;
225
226   my $from = 'LEFT JOIN part_bill_event USING ( eventpart )';
227
228   my @cust_bill_event = qsearch( 'cust_bill_event', {}, '', $where, '', $from );
229
230   my( $num, $last, $min_sec ) = (0, time, 5); #progresbar foo
231   foreach my $cust_bill_event ( @cust_bill_event ) {
232
233     $cust_bill_event->cust_bill->$method(
234       $cust_bill_event->part_bill_event->templatename
235     );
236
237     if ( $job ) { #progressbar foo
238       $num++;
239       if ( time - $min_sec > $last ) {
240         my $error = $job->update_statustext(
241           int( 100 * $num / scalar(@cust_bill_event) )
242         );
243         die $error if $error;
244         $last = time;
245       }
246     }
247
248   }
249
250   #this doesn't work, but it would be nice
251   #if ( $job ) { #progressbar foo
252   #  my $error = $job->update_statustext(
253   #    scalar(@cust_bill_event). " invoices re-${method}ed"
254   #  );
255   #  die $error if $error;
256   #}
257
258 }
259
260 =back
261
262 =head1 BUGS
263
264 Far too early in the morning.
265
266 =head1 SEE ALSO
267
268 L<FS::part_bill_event>, L<FS::cust_bill>, L<FS::Record>, schema.html from the
269 base documentation.
270
271 =cut
272
273 1;
274