X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_pay_batch.pm;h=774ea29618b42e8524e0961582d2ab51f5eae85f;hb=de5f40d0e0746bfd0c8a1e14bd1ed2979bf5d152;hp=9f2e9ddfc3c63258ba2d7866e9045e9ade81c770;hpb=8c450aab9bae89373c2c1b35c85597bb52299de3;p=freeside.git diff --git a/FS/FS/cust_pay_batch.pm b/FS/FS/cust_pay_batch.pm index 9f2e9ddfc..774ea2961 100644 --- a/FS/FS/cust_pay_batch.pm +++ b/FS/FS/cust_pay_batch.pm @@ -8,14 +8,20 @@ use FS::Record qw(dbh qsearch qsearchs); use FS::payinfo_Mixin; use FS::cust_main; use FS::cust_bill; +use Storable qw( thaw ); +use MIME::Base64 qw( decode_base64 ); -@ISA = qw( FS::payinfo_Mixin FS::Record ); + +@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 # 3 is even more information including possibly sensitive data $DEBUG = 0; +#@encrypted_fields = ('payinfo'); +sub nohistory_fields { ('payinfo'); } + =head1 NAME FS::cust_pay_batch - Object methods for batch cards @@ -80,7 +86,9 @@ following fields are currently supported: =item country -=item status +=item status - 'Approved' or 'Declined' + +=item error_message - the error returned by the gateway if any =back @@ -125,6 +133,8 @@ and replace methods. sub check { my $self = shift; + my $conf = new FS::Conf; + my $error = $self->ut_numbern('paybatchnum') || $self->ut_numbern('trancode') #deprecated @@ -133,7 +143,9 @@ sub check { || $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') ; @@ -289,41 +301,47 @@ sub retriable { ''; } -=item approve PAYBATCH +=item approve OPTIONS Approve this payment. This will replace the existing record with the same paybatchnum, set its status to 'Approved', and generate a payment record (L). This should only be called from the batch import process. +OPTIONS may contain "gatewaynum", "processor", "auth", and "order_number". + =cut sub approve { # to break up the Big Wall of Code that is import_results my $new = shift; - my $paybatch = shift; + 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, - 'paybatch' => $paybatch, 'payinfo' => $new->payinfo || $old->payinfo, 'paid' => $new->paid, '_date' => $new->_date, 'usernum' => $new->usernum, 'batchnum' => $new->batchnum, + 'gatewaynum' => $opt{'gatewaynum'}, + 'processor' => $opt{'processor'}, + 'auth' => $opt{'auth'}, + 'order_number' => $opt{'order_number'} } ); + $error = $cust_pay->insert; if ( $error ) { return "error inserting payment for paybatchnum $paybatchnum: $error\n"; @@ -350,7 +368,7 @@ sub decline { 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 @@ -361,6 +379,12 @@ sub decline { # Void the payment my $cust_pay = qsearchs('cust_pay', { custnum => $new->custnum, + batchnum => $new->batchnum + }); + # these should all be migrated over, but if it's not found, look for + # batchnum in the 'paybatch' field also + $cust_pay ||= qsearchs('cust_pay', { + custnum => $new->custnum, paybatch => $new->batchnum }); if ( !$cust_pay ) { @@ -371,13 +395,14 @@ sub decline { } 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->error_message($reason); 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', @@ -452,6 +477,76 @@ sub request_item { ); } +=item process_unbatch_and_delete + +L run as a queued job, accepts I<$job> and I<$param>. + +=cut + +sub process_unbatch_and_delete { + my ($job, $param) = @_; + $param = thaw(decode_base64($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 with a status of 'O' (not yet in transit.) Deletes all associated +records from L 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; + ''; + +} + =back =head1 BUGS