use strict;
use vars qw( $DEBUG );
-use Carp qw( confess );
+use Carp qw( carp confess );
use Business::CreditCard 0.28;
use FS::Record qw(dbh qsearch qsearchs);
=item payname - name on card
+=item paytype - account type ((personal|business) (checking|savings))
+
=item first - name
=item last - name
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')
;
$error = $self->payinfo_check();
return $error if $error;
+ if ( $self->payby eq 'CHEK' ) {
+ # because '' is on the list of paytypes:
+ my $paytype = $self->paytype or return "Bank account type required";
+ if (grep { $_ eq $paytype} FS::cust_payby->paytypes) {
+ #ok
+ } else {
+ return "Bank account type '$paytype' is not allowed"
+ }
+ } else {
+ $self->set('paytype', '');
+ }
+
if ( $self->exp eq '' ) {
return "Expiration date required"
unless $self->payby =~ /^(CHEK|DCHK|WEST)$/;
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,
'payby' => $new->payby,
'payinfo' => $new->payinfo || $old->payinfo,
+ 'paymask' => $new->mask_payinfo,
'paid' => $new->paid,
'_date' => $new->_date,
'usernum' => $new->usernum,
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',
$self->payinfo =~ /(\d+)@(\d+)/; # or else what?
$payment{account_number} = $1;
$payment{routing_code} = $2;
- $payment{account_type} = $cust_main->paytype;
+ $payment{account_type} = $self->paytype;
# XXX what if this isn't their regular payment method?
} else {
die "unsupported BatchPayment method: ".$pay_batch->payby;
}
+ my $recurring;
+ if ( $cust_main->status =~ /^active|suspended|ordered$/ ) {
+ if ( $self->payinfo_used ) {
+ $recurring = 'S'; # subsequent
+ } else {
+ $recurring = 'F'; # first use
+ }
+ } else {
+ $recurring = 'N'; # non-recurring
+ }
+
Business::BatchPayment->create(Item =>
# required
action => 'payment',
( map { $_ => $location->$_ } qw(address2 city state country zip) ),
invoice_number => $self->invnum,
+ recurring_billing => $recurring,
%payment,
);
}
+=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