From f45d153d287a514b50506ac9a4af9f6bf0d13b68 Mon Sep 17 00:00:00 2001 From: mark Date: Tue, 15 Feb 2011 23:52:44 +0000 Subject: [PATCH] batch payment revocation, RT#10545 --- FS/FS/cust_pay_batch.pm | 28 ++++- FS/FS/pay_batch.pm | 25 ++-- httemplate/misc/process/pay_batch-approve.cgi | 9 +- httemplate/search/cust_pay_batch.cgi | 116 ++----------------- httemplate/search/elements/cust_pay_batch_top.html | 127 +++++++++++++++++++++ httemplate/search/pay_batch.cgi | 6 + 6 files changed, 183 insertions(+), 128 deletions(-) create mode 100644 httemplate/search/elements/cust_pay_batch_top.html diff --git a/FS/FS/cust_pay_batch.pm b/FS/FS/cust_pay_batch.pm index 9fa14598a..171ec9fcf 100644 --- a/FS/FS/cust_pay_batch.pm +++ b/FS/FS/cust_pay_batch.pm @@ -290,6 +290,7 @@ sub approve { 'payinfo' => $new->payinfo || $old->payinfo, 'paid' => $new->paid, '_date' => $new->_date, + 'usernum' => $new->usernum, } ); $error = $cust_pay->insert; if ( $error ) { @@ -304,16 +305,37 @@ sub approve { Decline this payment. This will replace the existing record with the same paybatchnum, set its status to 'Declined', and run collection events as appropriate. This should only be called from the batch import process. - =cut + sub decline { my $new = shift; + my $conf = new FS::Conf; + my $paybatchnum = $new->paybatchnum; my $old = qsearchs('cust_pay_batch', { paybatchnum => $paybatchnum }) or return "paybatchnum $paybatchnum not found"; - return "paybatchnum $paybatchnum already resolved ('".$old->status."')" - if $old->status; + if ( $old->status ) { + # Handle the case where payments are rejected after the batch has been + # approved. Only if manual approval is enabled. + if ( $conf->exists('batch-manual_approval') + and lc($old->status) eq 'approved' ) { + # Void the payment + my $cust_pay = qsearchs('cust_pay', { + custnum => $new->custnum, + paybatch => $new->batchnum + }); + if ( !$cust_pay ) { + # should never happen... + return "failed to revoke paybatchnum $paybatchnum, payment not found"; + } + $cust_pay->void('Returned payment'); + } + else { + # normal case: refuse to do anything + return "paybatchnum $paybatchnum already resolved ('".$old->status."')"; + } + } # !$old->status $new->status('Declined'); my $error = $new->replace($old); if ( $error ) { diff --git a/FS/FS/pay_batch.pm b/FS/FS/pay_batch.pm index 5ccad5bf1..850335e84 100644 --- a/FS/FS/pay_batch.pm +++ b/FS/FS/pay_batch.pm @@ -231,17 +231,12 @@ sub import_results { my $reself = $self->select_for_update; - unless ( $reself->status eq 'I' ) { + if ( $reself->status ne 'I' + and !$conf->exists('batch-manual_approval') ) { $dbh->rollback if $oldAutoCommit; return "batchnum ". $self->batchnum. "no longer in transit"; } - my $error = $self->set_status('R'); - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return $error; - } - my $total = 0; my $line; @@ -396,7 +391,13 @@ sub import_results { $dbh->rollback; die $@; } - $self->set_status('I') if !$close; + if ( $close ) { + my $error = $self->set_status('R'); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } } $dbh->commit or die $dbh->errstr if $oldAutoCommit; @@ -538,6 +539,7 @@ sub manual_approve { 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' if ( ! $conf->exists('batch-manual_approval') ); @@ -562,8 +564,9 @@ sub manual_approve { ) { my $new_cust_pay_batch = new FS::cust_pay_batch { $cust_pay_batch->hash, - 'paid' => $cust_pay_batch->amount, - '_date' => $date, + 'paid' => $cust_pay_batch->amount, + '_date' => $date, + 'usernum' => $usernum, }; my $error = $new_cust_pay_batch->approve($paybatch); if ( $error ) { @@ -572,9 +575,7 @@ sub manual_approve { } $payments++; } - return 'no unresolved payments in batch' if $payments == 0; $self->set_status('R'); - $dbh->commit; return; } diff --git a/httemplate/misc/process/pay_batch-approve.cgi b/httemplate/misc/process/pay_batch-approve.cgi index f857e2318..ff5f12b38 100644 --- a/httemplate/misc/process/pay_batch-approve.cgi +++ b/httemplate/misc/process/pay_batch-approve.cgi @@ -7,10 +7,11 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Process batches'); my $batchnum = $cgi->param('batchnum'); -# make a record in the paybatch of who did this -my $paybatch = 'manual-'.$FS::CurrentUser::CurrentUser->username. - '-' . time2str('%Y/%m/%d-%T'. "-$$-". rand() * 2**32, time); +my $paybatch = $batchnum; +my $usernum = $FS::CurrentUser::CurrentUser->usernum; my $pay_batch = qsearchs('pay_batch', { 'batchnum' => $batchnum }) or die "batchnum '$batchnum' not found"; -my $error = $pay_batch->manual_approve('paybatch' => $paybatch); +my $error = $pay_batch->manual_approve( + 'paybatch' => $paybatch, 'usernum' => $usernum +); diff --git a/httemplate/search/cust_pay_batch.cgi b/httemplate/search/cust_pay_batch.cgi index 4a2248726..8022d4666 100755 --- a/httemplate/search/cust_pay_batch.cgi +++ b/httemplate/search/cust_pay_batch.cgi @@ -3,7 +3,10 @@ 'name' => 'batch details', 'query' => $sql_query, 'count_query' => $count_query, - 'html_init' => $pay_batch ? $html_init : '', + 'html_init' => $pay_batch ? + include('elements/cust_pay_batch_top.html', + 'pay_batch' => $pay_batch + ) : '', 'header' => [ '#', 'Inv #', 'Customer', @@ -66,7 +69,6 @@ die "access denied" && ( $conf->exists('batch-enable') || $conf->config('batch-enable_payby') ) - #&& $FS::CurrentUser::CurrentUser->access_right('View customer batched payments') ); my( $count_query, $sql_query ); @@ -124,113 +126,9 @@ $sql_query = "SELECT paybatchnum,invnum,custnum,cpb.last,cpb.first," . 'LEFT JOIN pay_batch USING ( batchnum ) ' . "$search ORDER BY $orderby"; -my $html_init = ''; +my $html_init = ''; if ( $pay_batch ) { - my $fixed = $conf->config('batch-fixed_format-'. $pay_batch->payby); - if ( - $pay_batch->status eq 'O' - || ( $pay_batch->status eq 'I' - && $FS::CurrentUser::CurrentUser->access_right('Reprocess batches') - ) - || ( $pay_batch->status eq 'R' - && $FS::CurrentUser::CurrentUser->access_right('Redownload resolved batches') - ) - ) { - $html_init .= qq!!; - if ( $fixed ) { - $html_init .= qq!!; - } else { - $html_init .= qq!Download batch in format !. - qq!!; - } - $html_init .= qq!

!; - } - - if ( - $pay_batch->status eq 'I' - || ( $pay_batch->status eq 'R' - && $FS::CurrentUser::CurrentUser->access_right('Reprocess batches') - ) - ) { - $html_init .= ''. - include('/elements/form-file_upload.html', - 'name' => 'FileUpload', - 'action' => "$p/misc/upload-batch.cgi", - 'num_files' => 1, - 'fields' => [ 'batchnum', 'format' ], - 'message' => 'Batch results uploaded.', - ) . - 'Upload results
'. - include('/elements/file-upload.html', - 'field' => 'file', - 'label' => 'Filename', - 'no_table'=> 1 - ). - '
' - ; - if ( $fixed and $fixed eq 'td_eft1464' ) { - # special case, this one has two upload formats - $html_init .= qq!Format !. - qq!
!; - } - elsif ( $fixed ) { - $html_init .= qq!!; - } else { - # should pull this from %import_info - $html_init .= qq!Format !. - qq!
!; - } - $html_init .= qq!!; - $html_init .= '
'; - if ( $conf->exists('batch-manual_approval') - and $conf->config('batch-fixed_format-CHEK') eq 'td_eft1464' - and $pay_batch->status eq 'I' - and $pay_batch->payby eq 'CHEK' ) { - $html_init .= qq!! - } - } - $html_init .= '
'; + $html_init = include('elements/cust_pay_batch_top.html', + 'pay_batch' => $pay_batch); } - -if ($pay_batch) { - my $sth = dbh->prepare($count_query) or die dbh->errstr. "doing $count_query"; - $sth->execute or die "Error executing \"$count_query\": ". $sth->errstr; - my $cards = $sth->fetchrow_arrayref->[0]; - - my $st = "SELECT SUM(amount) from cust_pay_batch WHERE batchnum=". $batchnum; - $sth = dbh->prepare($st) or die dbh->errstr. "doing $st"; - $sth->execute or die "Error executing \"$st\": ". $sth->errstr; - my $total = $sth->fetchrow_arrayref->[0]; - - $html_init .= "$cards credit card payments batched
\$" . - sprintf("%.2f", $total) ." total in batch
"; -} - diff --git a/httemplate/search/elements/cust_pay_batch_top.html b/httemplate/search/elements/cust_pay_batch_top.html new file mode 100644 index 000000000..96ed428b0 --- /dev/null +++ b/httemplate/search/elements/cust_pay_batch_top.html @@ -0,0 +1,127 @@ +% # Download batch +% if ( $status eq 'O' +% or ( $status eq 'I' and $curuser->access_right('Reprocess batches') ) +% or ( $status eq 'R' and $curuser->access_right('Redownload resolved batches') ) +% ) { + + + +% if ( $fixed ) { + +% } +% else { +Download batch in format +% } +

+% } # end of download + +% # Upload batch +% if ( $pay_batch->status eq 'I' +% or ( $pay_batch->status eq 'R' +% and $curuser->access_right('Reprocess batches') +% and $conf->exists('batch-manual_approval') +% ) +% ) { + +<% include('/elements/form-file_upload.html', + 'name' => 'FileUpload', + 'action' => "${p}misc/upload-batch.cgi", + 'num_files' => 1, + 'fields' => [ 'batchnum', 'format' ], + 'message' => 'Batch results uploaded.', +) %> +Upload results
+ +<% include('/elements/file-upload.html', + 'field' => 'file', + 'label' => 'Filename', + 'no_table' => 1, +) %> + +
+% if ( $fixed ) { +% if ( $fixed eq 'td_eft1464' ) { # special case +Format +% } +% else { + +% } +% } +% else { +Format +
+% } # end upload + +% # manual approval +% if ( $fixed eq 'td_eft1464' +% and $status eq 'I' +% and $payby eq 'CHEK' +% and $conf->exists('batch-manual_approval') +% ) { + +% } # end manual approval +
+ +% # summary info +Batch is <% $statustext{$status} %>
+<%$count%> payments batched
+<%$money_char%><%$total%> total in batch
+ +<%init> +my %opt = @_; +my $pay_batch = $opt{'pay_batch'} or return; +my $conf = new FS::Conf; +my $money_char = $conf->config('money_char') || '$'; +my $payby = $pay_batch->payby; +my $status = $pay_batch->status; +my $curuser = $FS::CurrentUser::CurrentUser; +my $batchnum = $pay_batch->batchnum; + +my $fixed = $conf->config("batch-fixed_format-$payby"); + +tie my %download_formats, 'Tie::IxHash', ( +'' => 'Default batch mode', +'csv-td_canada_trust-merchant_pc_batch' => + 'CSV file for TD Canada Trust Merchant PC Batch', +'csv-chase_canada-E-xactBatch' => + 'CSV file for Chase Canada E-xactBatch', +'PAP' => '80 byte file for TD Canada Trust PAP Batch', +'BoM' => 'Bank of Montreal ECA batch', +'ach-spiritone' => 'Spiritone ACH batch', +'paymentech' => 'XML file for Chase Paymentech', +'RBC' => 'Royal Bank of Canada PDS batch', +'td_eft1464' => '1464 byte file for TD Commercial Banking EFT', +# insert new batch formats here +); + +tie my %upload_formats, 'Tie::IxHash', ( + %download_formats, +# minor tweaks + 'td_eftack' => 'TD EFT Acknowledgement', + 'td_eftret' => 'TD EFT Returned Items', +); +delete $upload_formats{'td_eft1464'}; +$upload_formats{'PAP'} = '264 byte results for TD Canada Trust PAP Batch', + +my %statustext = ( 'O' => 'open', 'I' => 'in transit', 'R' => 'resolved' ); + +my $count_query = "SELECT COUNT(*) FROM cust_pay_batch WHERE batchnum=$batchnum"; +my $count = FS::Record->scalar_sql($count_query); +my $sum_query = "SELECT SUM(amount) FROM cust_pay_batch WHERE batchnum=$batchnum"; +my $total = sprintf("%.2f", FS::Record->scalar_sql($sum_query)); + diff --git a/httemplate/search/pay_batch.cgi b/httemplate/search/pay_batch.cgi index 6d571b42f..34297a500 100755 --- a/httemplate/search/pay_batch.cgi +++ b/httemplate/search/pay_batch.cgi @@ -80,6 +80,7 @@ sub { shift->status eq 'O' ? "b" : '' }, sub { shift->status eq 'I' ? "b" : '' }, ], + 'html_init' => $html_init, ) %> @@ -128,4 +129,9 @@ my $extra_sql = scalar(@where) ? 'WHERE ' . join(' AND ', @where) : ''; my $link = [ "${p}search/cust_pay_batch.cgi?dcln=1;batchnum=", 'batchnum' ]; +my $resolved = $cgi->param('resolved') || 0; +$cgi->param('resolved' => !$resolved); +my $html_init = ''. + ($resolved ? 'Hide' : 'Show') . ' resolved batches
'; + -- 2.11.0