package FS::cust_pay_batch;
+use base qw( FS::payinfo_Mixin FS::cust_main_Mixin FS::Record );
use strict;
-use vars qw( @ISA $DEBUG );
-use Carp qw( confess );
+use vars qw( $DEBUG );
+use Carp qw( carp confess );
use Business::CreditCard 0.28;
use FS::Record qw(dbh qsearch qsearchs);
-use FS::payinfo_Mixin;
-use FS::cust_main;
-use FS::cust_bill;
-
-@ISA = qw( FS::payinfo_Mixin FS::cust_main_Mixin FS::Record );
# 1 is mostly method/subroutine entry and options
# 2 traces progress of some operations
=item batchnum - indentifies group in batch
-=item payby - CARD/CHEK/LECB/BILL/COMP
+=item payby - CARD/CHEK
=item payinfo
sub check {
my $self = shift;
+ my $conf = new FS::Conf;
+
my $error =
$self->ut_numbern('paybatchnum')
|| $self->ut_numbern('trancode') #deprecated
|| $self->ut_number('custnum')
|| $self->ut_text('address1')
|| $self->ut_textn('address2')
- || $self->ut_text('city')
+ || ($conf->exists('cust_main-no_city_in_address')
+ ? $self->ut_textn('city')
+ : $self->ut_text('city'))
|| $self->ut_textn('state')
;
if ( $self->exp eq '' ) {
return "Expiration date required"
- unless $self->payby =~ /^(CHEK|DCHK|LECB|WEST)$/;
+ unless $self->payby =~ /^(CHEK|DCHK|WEST)$/;
$self->exp('');
} else {
if ( $self->exp =~ /^(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})$/ ) {
Returns the customer (see L<FS::cust_main>) for this batched credit card
payment.
-=cut
-
-sub cust_main {
- my $self = shift;
- qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
-}
-
=item expmmyy
Returns the credit card expiration date in MMYY format. If this is a
=cut
-sub pay_batch {
- my $self = shift;
- FS::pay_batch->by_key($self->batchnum);
-}
-
#you know what, screw this in the new world of events. we should be able to
#get the event defs to retry (remove once.pm condition, add every.pm) without
#mucking about with statuses of previous cust_event records. right?
confess "deprecated method cust_pay_batch->retriable called; try removing ".
"the once condition and adding an every condition?";
- my $self = shift;
-
- local $SIG{HUP} = 'IGNORE'; #Hmm
- local $SIG{INT} = 'IGNORE';
- local $SIG{QUIT} = 'IGNORE';
- local $SIG{TERM} = 'IGNORE';
- local $SIG{TSTP} = 'IGNORE';
- local $SIG{PIPE} = 'IGNORE';
-
- my $oldAutoCommit = $FS::UID::AutoCommit;
- local $FS::UID::AutoCommit = 0;
- my $dbh = dbh;
-
- my $cust_bill = qsearchs('cust_bill', { 'invnum' => $self->invnum } )
- or return "event $self->eventnum references nonexistant invoice $self->invnum";
-
- warn "cust_pay_batch->retriable working with self of " . $self->paybatchnum . " and invnum of " . $self->invnum;
- my @cust_bill_event =
- sort { $a->part_bill_event->seconds <=> $b->part_bill_event->seconds }
- grep {
- $_->part_bill_event->eventcode =~ /\$cust_bill->batch_card/
- && $_->status eq 'done'
- && ! $_->statustext
- }
- $cust_bill->cust_bill_event;
- # complain loudly if scalar(@cust_bill_event) > 1 ?
- my $error = $cust_bill_event[0]->retriable;
- if ($error ) {
- # gah, even with transactions.
- $dbh->commit if $oldAutoCommit; #well.
- return "error marking invoice event retriable: $error";
- }
- '';
}
=item approve OPTIONS
my %opt = @_;
my $paybatchnum = $new->paybatchnum;
my $old = qsearchs('cust_pay_batch', { paybatchnum => $paybatchnum })
- or return "paybatchnum $paybatchnum not found";
+ or return "cannot approve, paybatchnum $paybatchnum not found";
# leave these restrictions in place until TD EFT is converted over
# to B::BP
- return "paybatchnum $paybatchnum already resolved ('".$old->status."')"
+ return "cannot approve paybatchnum $paybatchnum, already resolved ('".$old->status."')"
if $old->status;
$new->status('Approved');
my $error = $new->replace($old);
if ( $error ) {
- return "error updating status of paybatchnum $paybatchnum: $error\n";
+ return "error approving paybatchnum $paybatchnum: $error\n";
}
my $cust_pay = new FS::cust_pay ( {
'custnum' => $new->custnum,
my $paybatchnum = $new->paybatchnum;
my $old = qsearchs('cust_pay_batch', { paybatchnum => $paybatchnum })
- or return "paybatchnum $paybatchnum not found";
+ or return "cannot decline, paybatchnum $paybatchnum not found";
if ( $old->status ) {
# Handle the case where payments are rejected after the batch has been
# approved. FS::pay_batch::import_results won't allow results to be
}
else {
# normal case: refuse to do anything
- return "paybatchnum $paybatchnum already resolved ('".$old->status."')";
+ return "cannot decline paybatchnum $paybatchnum, already resolved ('".$old->status."')";
}
} # !$old->status
$new->status('Declined');
$new->failure_status($failure_status);
my $error = $new->replace($old);
if ( $error ) {
- return "error updating status of paybatchnum $paybatchnum: $error\n";
+ return "error declining paybatchnum $paybatchnum: $error\n";
}
my $due_cust_event = $new->cust_main->due_cust_event(
'eventtable' => 'cust_pay_batch',
);
}
+=item process_unbatch_and_delete
+
+L</unbatch_and_delete> run as a queued job, accepts I<$job> and I<$param>.
+
+=cut
+
+sub process_unbatch_and_delete {
+ my ($job, $param) = @_;
+ my $self = qsearchs('cust_pay_batch',{ 'paybatchnum' => scalar($param->{'paybatchnum'}) })
+ or die 'Could not find paybatchnum ' . $param->{'paybatchnum'};
+ my $error = $self->unbatch_and_delete;
+ die $error if $error;
+ return '';
+}
+
+=item unbatch_and_delete
+
+May only be called on a record with an empty status and an associated
+L<pay_batch> with a status of 'O' (not yet in transit.) Deletes all associated
+records from L<cust_bill_pay_batch> and then deletes this record.
+If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub unbatch_and_delete {
+ my $self = shift;
+
+ return 'Cannot unbatch a cust_pay_batch with status ' . $self->status
+ if $self->status;
+
+ my $pay_batch = qsearchs('pay_batch',{ 'batchnum' => $self->batchnum })
+ or return 'Cannot find associated pay_batch record';
+
+ return 'Cannot unbatch from a pay_batch with status ' . $pay_batch->status
+ if $pay_batch->status ne 'O';
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ # have not generated actual payments yet, so should be safe to delete
+ foreach my $cust_bill_pay_batch (
+ qsearch('cust_bill_pay_batch',{ 'paybatchnum' => $self->paybatchnum })
+ ) {
+ my $error = $cust_bill_pay_batch->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
+
+ my $error = $self->delete;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+=item cust_bill
+
+Returns the invoice linked to this batched payment. Deprecated, will be
+removed.
+
+=cut
+
+sub cust_bill {
+ carp "FS::cust_pay_batch->cust_bill is deprecated";
+ my $self = shift;
+ $self->invnum ? qsearchs('cust_bill', { invnum => $self->invnum }) : '';
+}
+
=back
=head1 BUGS