fix 'Can't call method "setup" on an undefined value' error when using into rates...
[freeside.git] / FS / FS / cust_statement.pm
1 package FS::cust_statement;
2
3 use strict;
4 use base qw( FS::cust_bill );
5 use FS::Record qw( dbh qsearch ); #qsearchs );
6 use FS::cust_main;
7 use FS::cust_bill;
8
9 =head1 NAME
10
11 FS::cust_statement - Object methods for cust_statement records
12
13 =head1 SYNOPSIS
14
15   use FS::cust_statement;
16
17   $record = new FS::cust_statement \%hash;
18   $record = new FS::cust_statement { 'column' => 'value' };
19
20   $error = $record->insert;
21
22   $error = $new_record->replace($old_record);
23
24   $error = $record->delete;
25
26   $error = $record->check;
27
28 =head1 DESCRIPTION
29
30 An FS::cust_statement object represents an informational statement which
31 aggregates one or more invoices.  FS::cust_statement inherits from
32 FS::cust_bill.
33
34 The following fields are currently supported:
35
36 =over 4
37
38 =item statementnum
39
40 primary key
41
42 =item custnum
43
44 customer
45
46 =item _date
47
48 date
49
50 =back
51
52 =head1 METHODS
53
54 =over 4
55
56 =item new HASHREF
57
58 Creates a new record.  To add the record to the database, see L<"insert">.
59
60 Note that this stores the hash reference, not a distinct copy of the hash it
61 points to.  You can ask the object for a copy with the I<hash> method.
62
63 =cut
64
65 sub new { FS::Record::new(@_); }
66
67 sub table { 'cust_statement'; }
68
69 =item insert
70
71 Adds this record to the database.  If there is an error, returns the error,
72 otherwise returns false.
73
74 =cut
75
76 sub insert {
77   my $self = shift;
78
79   local $SIG{HUP} = 'IGNORE';
80   local $SIG{INT} = 'IGNORE';
81   local $SIG{QUIT} = 'IGNORE';
82   local $SIG{TERM} = 'IGNORE';
83   local $SIG{TSTP} = 'IGNORE';
84   local $SIG{PIPE} = 'IGNORE';
85
86   my $oldAutoCommit = $FS::UID::AutoCommit;
87   local $FS::UID::AutoCommit = 0;
88   my $dbh = dbh;
89
90   FS::Record::insert($self);
91
92   foreach my $cust_bill (
93                           qsearch({
94                             'table'     => 'cust_bill',
95                             'hashref'   => { 'custnum'      => $self->custnum,
96                                              'statementnum' => '',
97                                            },
98                             'extra_sql' => 'FOR UPDATE' ,
99                           })
100                         )
101   {
102     $cust_bill->statementnum( $self->statementnum );
103     my $error = $cust_bill->replace;
104     if ( $error ) {
105       $dbh->rollback if $oldAutoCommit;
106       return "Error associating invoice: $error";
107     }
108   }
109
110   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
111   ''; #no error
112
113 }
114
115 =item delete
116
117 Delete this record from the database.
118
119 =cut
120
121 sub delete { FS::Record::delete(@_); }
122
123 =item replace OLD_RECORD
124
125 Replaces the OLD_RECORD with this one in the database.  If there is an error,
126 returns the error, otherwise returns false.
127
128 =cut
129
130 sub replace { FS::Record::replace(@_); }
131
132 sub replace_check { ''; }
133
134 =item check
135
136 Checks all fields to make sure this is a valid record.  If there is
137 an error, returns the error, otherwise returns false.  Called by the insert
138 and replace methods.
139
140 =cut
141
142 sub check {
143   my $self = shift;
144
145   my $error = 
146     $self->ut_numbern('statementnum')
147     || $self->ut_foreign_key('custnum', 'cust_main', 'custnum' )
148     || $self->ut_numbern('_date')
149   ;
150   return $error if $error;
151
152   $self->_date(time) unless $self->_date;
153
154   #don't want to call cust_bill, and Record just checks virtual fields
155   #$self->SUPER::check;
156   '';
157
158 }
159
160 =item cust_bill
161
162 Returns the associated invoices (cust_bill records) for this statement.
163
164 =cut
165
166 sub cust_bill {
167   my $self = shift;
168   qsearch('cust_bill', { 'statementnum' => $self->statementnum } );
169 }
170
171 sub _aggregate {
172   my( $self, $method ) = ( shift, shift );
173
174   my @agg = ();
175
176   foreach my $cust_bill ( $self->cust_bill ) {
177     push @agg, $cust_bill->$method( @_ );
178   }
179
180   @agg;
181 }
182
183 sub _total {
184   my( $self, $method ) = ( shift, shift );
185
186   my $total = 0;
187
188   foreach my $cust_bill ( $self->cust_bill ) {
189     $total += $cust_bill->$method( @_ );
190   }
191
192   $total;
193 }
194
195 =item cust_bill_pkg
196
197 Returns the line items (see L<FS::cust_bill_pkg>) for all associated invoices.
198
199 =item cust_bill_pkg_pkgnum PKGNUM
200
201 Returns the line items (see L<FS::cust_bill_pkg>) for all associated invoices
202 and specified pkgnum.
203
204 =item cust_bill_pay
205
206 Returns all payment applications (see L<FS::cust_bill_pay>) for all associated
207 invoices.
208
209 =item cust_credited
210
211 Returns all applied credits (see L<FS::cust_credit_bill>) for all associated
212 invoices.
213
214 =item cust_bill_pay_pkgnum PKGNUM
215
216 Returns all payment applications (see L<FS::cust_bill_pay>) for all associated
217 invoices with matching pkgnum.
218
219 =item cust_credited_pkgnum PKGNUM
220
221 Returns all applied credits (see L<FS::cust_credit_bill>) for all associated
222 invoices with matching pkgnum.
223
224 =cut
225
226 sub cust_bill_pay        { shift->_aggregate('cust_bill_pay',        @_); }
227 sub cust_credited        { shift->_aggregate('cust_credited',        @_); }
228 sub cust_bill_pay_pkgnum { shift->_aggregate('cust_bill_pay_pkgnum', @_); }
229 sub cust_credited_pkgnum { shift->_aggregate('cust_credited_pkgnum', @_); }
230
231 sub cust_bill_pkg        { shift->_aggregate('cust_bill_pkg',        @_); }
232 sub cust_bill_pkg_pkgnum { shift->_aggregate('cust_bill_pkg_pkgnum', @_); }
233
234 =item tax
235
236 Returns the total tax amount for all assoicated invoices.0
237
238 =cut
239
240 =item charged
241
242 Returns the total amount charged for all associated invoices.
243
244 =cut
245
246 =item owed
247
248 Returns the total amount owed for all associated invoices.
249
250 =cut
251
252 sub tax     { shift->_total('tax',     @_); }
253 sub charged { shift->_total('charged', @_); }
254 sub owed    { shift->_total('owed',    @_); }
255
256 #don't show previous info
257 sub previous {
258   ( 0 ); # 0, empty list
259 }
260
261 =back
262
263 =head1 BUGS
264
265 =head1 SEE ALSO
266
267 L<FS::cust_bill>, L<FS::Record>, schema.html from the base documentation.
268
269 =cut
270
271 1;
272