summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Wells <mark@freeside.biz>2013-01-29 16:28:26 -0800
committerMark Wells <mark@freeside.biz>2013-01-30 12:09:29 -0800
commit61097b876e692dbf5571a17b9aa415949607085f (patch)
treeaead5bab2124ce0aaca391a15de3deeaa383f867
parent6bd91fa5feb41ea3294bdaee5fe1c1134f19c330 (diff)
record and show batch payment status info, #21117
-rw-r--r--FS/FS/Schema.pm1
-rw-r--r--FS/FS/cust_pay_batch.pm19
-rw-r--r--FS/FS/pay_batch.pm26
-rw-r--r--FS/FS/pay_batch/paymentech.pm23
-rwxr-xr-xhttemplate/search/cust_pay_batch.cgi91
-rwxr-xr-xhttemplate/search/elements/cust_pay_or_refund.html21
6 files changed, 110 insertions, 71 deletions
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 70928a801..de3659a4c 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -1695,6 +1695,7 @@ sub tables_hashref {
'payname', 'varchar', 'NULL', $char_d, '', '',
'amount', @money_type, '', '',
'status', 'varchar', 'NULL', $char_d, '', '',
+ 'error_message', 'varchar', 'NULL', $char_d, '', '',
],
'primary_key' => 'paybatchnum',
'unique' => [],
diff --git a/FS/FS/cust_pay_batch.pm b/FS/FS/cust_pay_batch.pm
index 9f2e9ddfc..4138436a7 100644
--- a/FS/FS/cust_pay_batch.pm
+++ b/FS/FS/cust_pay_batch.pm
@@ -9,7 +9,7 @@ use FS::payinfo_Mixin;
use FS::cust_main;
use FS::cust_bill;
-@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
@@ -80,7 +80,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
@@ -289,19 +291,21 @@ 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<FS::cust_pay>). 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";
@@ -317,13 +321,17 @@ sub approve {
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";
@@ -375,6 +383,7 @@ sub decline {
}
} # !$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";
diff --git a/FS/FS/pay_batch.pm b/FS/FS/pay_batch.pm
index 0274914eb..2a048a115 100644
--- a/FS/FS/pay_batch.pm
+++ b/FS/FS/pay_batch.pm
@@ -401,12 +401,12 @@ sub import_results {
foreach ('paid', '_date', 'payinfo') {
$new_cust_pay_batch->$_($hash{$_}) if $hash{$_};
}
- $error = $new_cust_pay_batch->approve($hash{'paybatch'} || $self->batchnum);
+ $error = $new_cust_pay_batch->approve(%hash);
$total += $hash{'paid'};
} elsif ( &{$declined_condition}(\%hash) ) {
- $error = $new_cust_pay_batch->decline;
+ $error = $new_cust_pay_batch->decline($hash{'error_message'});;
}
@@ -572,8 +572,6 @@ sub import_from_gateway {
my $payby; # CARD or CHEK
my $error;
- # follow realtime gateway practice here
- # though eventually this stuff should go into separate fields...
my $paybatch = $gateway->gatewaynum . '-' . $gateway->gateway_module .
':' . $item->authorization . ':' . $item->order_number;
@@ -644,8 +642,11 @@ sub import_from_gateway {
payby => $payby,
invnum => $item->invoice_number,
batchnum => $pay_batch->batchnum,
- paybatch => $paybatch,
payinfo => $payinfo,
+ gatewaynum => $gateway->gatewaynum,
+ processor => $gateway->gateway_module,
+ auth => $item->authorization,
+ order_number => $item->order_number,
}
);
$error ||= $cust_pay->insert;
@@ -725,7 +726,12 @@ sub import_from_gateway {
# approval status
if ( $item->approved ) {
# follow Billing_Realtime format for paybatch
- $error = $cust_pay_batch->approve($paybatch);
+ $error = $cust_pay_batch->approve(
+ 'gatewaynum' => $gateway->gatewaynum,
+ 'processor' => $gateway->gateway_module,
+ 'auth' => $item->authorization,
+ 'order_number' => $item->order_number,
+ );
$total += $cust_pay_batch->paid;
}
else {
@@ -829,6 +835,9 @@ sub try_to_resolve {
}
return $error if $error;
}
+ } elsif ( @unresolved ) {
+ # auto resolve is not enabled, and we're not ready to resolve
+ return;
}
$self->set_status('R');
@@ -1028,7 +1037,6 @@ sub manual_approve {
my $self = shift;
my $date = time;
my %opt = @_;
- my $paybatch = $opt{'paybatch'} || $self->batchnum;
my $usernum = $opt{'usernum'} || die "manual approval requires a usernum";
my $conf = FS::Conf->new;
return 'manual batch approval disabled'
@@ -1058,7 +1066,9 @@ sub manual_approve {
'_date' => $date,
'usernum' => $usernum,
};
- my $error = $new_cust_pay_batch->approve($paybatch);
+ my $error = $new_cust_pay_batch->approve();
+ # there are no approval options here (authorization, order_number, etc.)
+ # because the transaction wasn't really approved
if ( $error ) {
$dbh->rollback;
return 'paybatchnum '.$cust_pay_batch->paybatchnum.": $error";
diff --git a/FS/FS/pay_batch/paymentech.pm b/FS/FS/pay_batch/paymentech.pm
index c75903de7..47be4eb31 100644
--- a/FS/FS/pay_batch/paymentech.pm
+++ b/FS/FS/pay_batch/paymentech.pm
@@ -23,7 +23,10 @@ my $gateway;
'_date',
'approvalStatus',
'order_number',
- 'authorization',
+ 'auth',
+ 'procStatus',
+ 'procStatusMessage',
+ 'respCodeMessage',
],
xmlkeys => [
'orderID',
@@ -31,6 +34,9 @@ my $gateway;
'approvalStatus',
'txRefNum',
'authorizationCode',
+ 'procStatus',
+ 'procStatusMessage',
+ 'respCodeMessage',
],
'hook' => sub {
if ( !$gateway ) {
@@ -38,7 +44,7 @@ my $gateway;
# as the batch config, if there is one. If not, leave
# gateway out entirely.
my $merchant = (FS::Conf->new->config('batchconfig-paymentech'))[2];
- my $g = qsearchs({
+ $gateway = qsearchs({
'table' => 'payment_gateway',
'addl_from' => ' JOIN payment_gateway_option USING (gatewaynum) ',
'hashref' => { disabled => '',
@@ -46,18 +52,19 @@ my $gateway;
optionvalue => $merchant,
},
});
- $gateway = ($g ? $g->gatewaynum . '-' : '') . 'PaymenTech';
}
my ($hash, $oldhash) = @_;
+ $hash->{'gatewaynum'} = $gateway->gatewaynum if $gateway;
+ $hash->{'processor'} = 'PaymenTech';
my ($mon, $day, $year, $hour, $min, $sec) =
$hash->{'_date'} =~ /^(..)(..)(....)(..)(..)(..)$/;
$hash->{'_date'} = timelocal($sec, $min, $hour, $day, $mon-1, $year);
$hash->{'paid'} = $oldhash->{'amount'};
- $hash->{'paybatch'} = join(':',
- $gateway,
- $hash->{'authorization'},
- $hash->{'order_number'},
- );
+ if ( $hash->{'procStatus'} == 0 ) {
+ $hash->{'error_message'} = $hash->{'respCodeMessage'};
+ } else {
+ $hash->{'error_message'} = $hash->{'procStatusMessage'};
+ }
},
'approved' => sub { my $hash = shift;
$hash->{'approvalStatus'}
diff --git a/httemplate/search/cust_pay_batch.cgi b/httemplate/search/cust_pay_batch.cgi
index 800df8702..830a6c699 100755
--- a/httemplate/search/cust_pay_batch.cgi
+++ b/httemplate/search/cust_pay_batch.cgi
@@ -7,53 +7,40 @@
'disable_download' => 1,
'header' => [ '#',
'Inv #',
- 'Customer',
+ 'Cust #',
'Customer',
'Card Name',
'Card',
'Exp',
'Amount',
'Status',
+ '', # error_message
],
- 'fields' => [ sub {
- shift->[0];
- },
- sub {
- shift->[1];
- },
- sub {
- shift->[2];
- },
- sub {
- my $cpb = shift;
- $cpb->[3] . ', ' . $cpb->[4];
- },
- sub {
- shift->[5];
- },
- sub {
- my $cardnum = shift->[6];
- 'x'x(length($cardnum)-4). substr($cardnum,(length($cardnum)-4));
- },
- sub {
- shift->[7] =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
- my( $mon, $year ) = ( $2, $1 );
- $mon = "0$mon" if length($mon) == 1;
- "$mon/$year";
- },
- sub {
- shift->[8];
- },
- sub {
- shift->[9];
- },
- ],
- 'align' => 'lllllllrl',
- 'links' => [ ['', sub{'#';}],
- ["${p}view/cust_bill.cgi?", sub{shift->[1];},],
- ["${p}view/cust_main.cgi?", sub{shift->[2];},],
- ["${p}view/cust_main.cgi?", sub{shift->[2];},],
+ 'fields' => [ 'paybatchnum',
+ 'invnum',
+ 'custnum',
+ sub { $_[0]->cust_main->name_short },
+ 'payname',
+ 'mask_payinfo',
+ sub {
+ return('') if $_[0]->payby ne 'CARD';
+ $_[0]->get('exp') =~ /^\d\d(\d\d)-(\d\d)/;
+ sprintf('%02d/%02d',$1,$2);
+ },
+ sub {
+ sprintf('%.02f', $_[0]->amount)
+ },
+ 'status',
+ 'error_message',
+ ],
+ 'align' => 'rrrlllcrll',
+ 'links' => [ '',
+ ["${p}view/cust_bill.cgi?", 'invnum'],
+ (["${p}view/cust_main.cgi?", 'custnum']) x 2,
],
+ 'link_onclicks' => [ ('') x 8,
+ $sub_receipt
+ ],
)
%>
<%init>
@@ -124,13 +111,25 @@ $count_query = 'SELECT COUNT(*) FROM cust_pay_batch AS cpb ' .
'LEFT JOIN pay_batch USING ( batchnum )' .
$search;
-#grr
-$sql_query = "SELECT paybatchnum,invnum,custnum,cpb.last,cpb.first," .
- "cpb.payname,cpb.payinfo,cpb.exp,amount,cpb.status " .
- "FROM cust_pay_batch AS cpb " .
- 'LEFT JOIN cust_main USING ( custnum ) ' .
- 'LEFT JOIN pay_batch USING ( batchnum ) ' .
- "$search ORDER BY $orderby";
+$sql_query = {
+ 'table' => 'cust_pay_batch',
+ 'select' => 'cust_pay_batch.*, cust_main.*, cust_pay.paynum',
+ 'hashref' => {},
+ 'addl_from' => 'LEFT JOIN pay_batch USING ( batchnum ) '.
+ 'LEFT JOIN cust_main USING ( custnum ) '.
+
+ 'LEFT JOIN cust_pay USING ( batchnum, custnum ) ',
+ 'extra_sql' => $search,
+ 'order_by' => "ORDER BY $orderby",
+};
+
+my $sub_receipt = sub {
+ my $paynum = shift->paynum or return '';
+ include('/elements/popup_link_onclick.html',
+ 'action' => $p.'view/cust_pay.html?link=popup;paynum='.$paynum,
+ 'actionlabel' => emt('Payment Receipt'),
+ );
+};
my $html_init = '';
if ( $pay_batch ) {
diff --git a/httemplate/search/elements/cust_pay_or_refund.html b/httemplate/search/elements/cust_pay_or_refund.html
index eeef0c0e1..b9da7ef06 100755
--- a/httemplate/search/elements/cust_pay_or_refund.html
+++ b/httemplate/search/elements/cust_pay_or_refund.html
@@ -51,6 +51,7 @@ Examples:
'sort_fields' => \@sort_fields,
'align' => $align,
'links' => \@links,
+ 'link_onclicks' => \@link_onclicks,
'color' => \@color,
'style' => \@style,
&>
@@ -134,11 +135,12 @@ if ( $cgi->param('tax_names') ) {
}
}
-my @header = ();
-my @fields = ();
-my @sort_fields = ();
+my @header;
+my @fields;
+my @sort_fields;
my $align = '';
-my @links = ();
+my @links;
+my @link_onclicks;
if ( $opt{'pre_header'} ) {
push @header, @{ $opt{'pre_header'} };
$align .= 'c' x scalar(@{ $opt{'pre_header'} });
@@ -147,6 +149,16 @@ if ( $opt{'pre_header'} ) {
push @sort_fields, @{ $opt{'pre_fields'} };
}
+my $sub_receipt = sub {
+ my $obj = shift;
+ my $objnum = $obj->primary_key . '=' . $obj->get($obj->primary_key);
+
+ include('/elements/popup_link_onclick.html',
+ 'action' => $p.'view/cust_pay.html?link=popup;'.$objnum,
+ 'actionlabel' => emt('Payment Receipt'),
+ );
+};
+
push @header, "\u$name_singular",
'Amount',
;
@@ -155,6 +167,7 @@ push @links, '', '';
push @fields, 'payby_payinfo_pretty',
sub { sprintf('$%.2f', shift->$amount_field() ) },
;
+push @link_onclicks, $sub_receipt, '',
push @sort_fields, '', $amount_field;
if ( $unapplied ) {