1 package FS::cust_bill_void;
2 use base qw( FS::Template_Mixin FS::cust_main_Mixin FS::otaker_Mixin
3 FS::reason_Mixin FS::Record );
6 use vars qw( $me $DEBUG );
7 use FS::Record qw( qsearch qsearchs dbh fields );
8 use FS::cust_statement;
10 use FS::cust_bill_pkg_void;
13 $me = '[ FS::cust_bill_void ]';
18 FS::cust_bill_void - Object methods for cust_bill_void records
22 use FS::cust_bill_void;
24 $record = new FS::cust_bill_void \%hash;
25 $record = new FS::cust_bill_void { 'column' => 'value' };
27 $error = $record->insert;
29 $error = $new_record->replace($old_record);
31 $error = $record->delete;
33 $error = $record->check;
37 An FS::cust_bill_void object represents a voided invoice. FS::cust_bill_void
38 inherits from FS::Record. The following fields are currently supported:
62 =item previous_balance
92 freeform string (deprecated)
96 reason for voiding the payment (see L<FS::reson>)
111 Creates a new voided invoice. To add the voided invoice to the database, see L<"insert">.
113 Note that this stores the hash reference, not a distinct copy of the hash it
114 points to. You can ask the object for a copy with the I<hash> method.
118 sub table { 'cust_bill_void'; }
119 sub notice_name { 'VOIDED Invoice'; }
120 sub template_conf { 'invoice_'; }
124 my $agentnum = $self->cust_main->agentnum;
125 my $tc = $self->template_conf;
127 $self->conf->exists($tc.'sections', $agentnum) ||
128 $self->conf->exists($tc.'sections_by_location', $agentnum);
134 Adds this record to the database. If there is an error, returns the error,
135 otherwise returns false.
141 "Un-void"s this invoice: Deletes the voided invoice from the database and adds
142 back a normal invoice (and related tables).
149 local $SIG{HUP} = 'IGNORE';
150 local $SIG{INT} = 'IGNORE';
151 local $SIG{QUIT} = 'IGNORE';
152 local $SIG{TERM} = 'IGNORE';
153 local $SIG{TSTP} = 'IGNORE';
154 local $SIG{PIPE} = 'IGNORE';
156 my $oldAutoCommit = $FS::UID::AutoCommit;
157 local $FS::UID::AutoCommit = 0;
160 my $cust_bill = new FS::cust_bill ( {
161 map { $_ => $self->get($_) } fields('cust_bill')
163 my $error = $cust_bill->insert;
165 $dbh->rollback if $oldAutoCommit;
169 foreach my $cust_bill_pkg_void ( $self->cust_bill_pkg ) {
170 my $error = $cust_bill_pkg_void->unvoid;
172 $dbh->rollback if $oldAutoCommit;
177 $error = $self->delete;
179 $dbh->rollback if $oldAutoCommit;
183 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
191 Delete this record from the database.
195 =item replace OLD_RECORD
197 Replaces the OLD_RECORD with this one in the database. If there is an error,
198 returns the error, otherwise returns false.
204 Checks all fields to make sure this is a valid voided invoice. If there is
205 an error, returns the error, otherwise returns false. Called by the insert
214 $self->ut_number('invnum')
215 || $self->ut_foreign_key('custnum', 'cust_main', 'custnum' )
216 || $self->ut_numbern('_date')
217 || $self->ut_money('charged')
218 || $self->ut_textn('invoice_terms')
219 || $self->ut_moneyn('previous_balance')
220 || $self->ut_moneyn('billing_balance')
221 || $self->ut_enum('closed', [ '', 'Y' ])
222 || $self->ut_foreign_keyn('statementnum', 'cust_statement', 'statementnum')
223 || $self->ut_numbern('agent_invid')
224 || $self->ut_numbern('promised_date')
225 || $self->ut_numbern('void_date')
226 || $self->ut_textn('reason')
227 || $self->ut_numbern('void_usernum')
228 || $self->ut_foreign_keyn('reasonnum', 'reason', 'reasonnum')
230 return $error if $error;
232 $self->void_date(time) unless $self->void_date;
234 $self->void_usernum($FS::CurrentUser::CurrentUser->usernum)
235 unless $self->void_usernum;
242 Returns the displayed invoice number for this invoice: agent_invid if
243 cust_bill-default_agent_invid is set and it has a value, invnum otherwise.
249 my $conf = $self->conf;
250 if ( $conf->exists('cust_bill-default_agent_invid') && $self->agent_invid ){
251 return $self->agent_invid;
253 return $self->invnum;
257 =item void_access_user
259 Returns the voiding employee object (see L<FS::access_user>).
263 sub void_access_user {
265 qsearchs('access_user', { 'usernum' => $self->void_usernum } );
274 Returns the text of the associated void reason (see L<FS::reason>) for this.
278 sub cust_bill_pkg { #actually cust_bill_pkg_void objects
280 qsearch('cust_bill_pkg_void', { invnum=>$self->invnum });
287 Returns the packages (see L<FS::cust_pkg>) corresponding to the line items for
294 my @cust_pkg = map { $_->pkgnum > 0 ? $_->cust_pkg : () }
295 $self->cust_bill_pkg;
297 grep { ! $saw{$_->pkgnum}++ } @cust_pkg;
300 =item search_sql_where HASHREF
302 Class method which returns an SQL WHERE fragment to search for parameters
303 specified in HASHREF. Accepts the following parameters for
304 L<FS::cust_bill::search_sql_where>: C<_date>, C<invnum_min>, C<invnum_max>,
305 C<agentnum>, C<custnum>, C<cust_classnum>, C<refnum>. Also
306 accepts the following:
312 Arrayref of start and end date to find invoices voided in a date range.
316 User identifier (L<FS::access_user> key) that voided the invoice.
322 sub search_sql_where {
323 my($class, $param) = @_;
325 my $cust_bill_param = {
326 map { $_ => $param->{$_} }
327 grep { exists($param->{$_}) }
328 qw( _date invnum_min invnum_max agentnum custnum cust_classnum
331 my $search_sql = FS::cust_bill->search_sql_where($cust_bill_param);
332 $search_sql =~ s/cust_bill/cust_bill_void/g;
333 my @search = ($search_sql);
335 if ( $param->{void_date} ) {
336 my($beginning, $ending) = @{$param->{void_date}};
337 push @search, "cust_bill_void.void_date >= $beginning",
338 "cust_bill_void.void_date < $ending";
341 if ( $param->{void_usernum} =~ /^(\d+)$/ ) {
343 push @search, "cust_bill_void.void_usernum = $1";
346 join(" AND ", @search);
350 =item enable_previous
354 sub enable_previous { 0 }
358 # Used by FS::Upgrade to migrate to a new database.
359 sub _upgrade_data { # class method
360 my ($class, %opts) = @_;
362 warn "$me upgrading $class\n" if $DEBUG;
364 $class->_upgrade_reasonnum(%opts);
373 L<FS::Record>, schema.html from the base documentation.