diff options
author | mark <mark> | 2011-02-15 23:52:44 +0000 |
---|---|---|
committer | mark <mark> | 2011-02-15 23:52:44 +0000 |
commit | f45d153d287a514b50506ac9a4af9f6bf0d13b68 (patch) | |
tree | 30e63f3261d87aec6c43968a405c338a38fb8dbd | |
parent | 6f0a91812069a2553a157637bc4e4c6f6a58ccc0 (diff) |
batch payment revocation, RT#10545
-rw-r--r-- | FS/FS/cust_pay_batch.pm | 28 | ||||
-rw-r--r-- | FS/FS/pay_batch.pm | 25 | ||||
-rw-r--r-- | httemplate/misc/process/pay_batch-approve.cgi | 9 | ||||
-rwxr-xr-x | httemplate/search/cust_pay_batch.cgi | 116 | ||||
-rw-r--r-- | httemplate/search/elements/cust_pay_batch_top.html | 127 | ||||
-rwxr-xr-x | httemplate/search/pay_batch.cgi | 6 |
6 files changed, 183 insertions, 128 deletions
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 +); </%init> 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 = '<TABLE>'; +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!<TR><FORM ACTION="$p/misc/download-batch.cgi" METHOD="POST">!; - if ( $fixed ) { - $html_init .= qq!<INPUT TYPE="hidden" NAME="format" VALUE="$fixed">!; - } else { - $html_init .= qq!Download batch in format !. - qq!<SELECT NAME="format">!. - qq!<OPTION VALUE="">Default batch mode</OPTION>!. - qq!<OPTION VALUE="csv-td_canada_trust-merchant_pc_batch">CSV file for TD Canada Trust Merchant PC Batch</OPTION>!. - qq!<OPTION VALUE="csv-chase_canada-E-xactBatch">CSV file for Chase Canada E-xactBatch</OPTION>!. - qq!<OPTION VALUE="PAP">80 byte file for TD Canada Trust PAP Batch</OPTION>!. - qq!<OPTION VALUE="BoM">Bank of Montreal ECA batch</OPTION>!. - qq!<OPTION VALUE="ach-spiritone">Spiritone ACH batch</OPTION>!. - qq!<OPTION VALUE="paymentech">Chase Paymentech XML</OPTION>!. - qq!<OPTION VALUE="RBC">Royal Bank of Canada PDS</OPTION>!. - qq!<OPTION VALUE="td_eft1464">TD Commercial Banking EFT 1464 byte</OPTION>!. - - qq!</SELECT>!; - } - $html_init .= qq!<INPUT TYPE="hidden" NAME="batchnum" VALUE="$batchnum"><INPUT TYPE="submit" VALUE="Download"></FORM><BR><BR></TR>!; - } - - if ( - $pay_batch->status eq 'I' - || ( $pay_batch->status eq 'R' - && $FS::CurrentUser::CurrentUser->access_right('Reprocess batches') - ) - ) { - $html_init .= '<TR>'. - 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<BR></TR><TR>'. - include('/elements/file-upload.html', - 'field' => 'file', - 'label' => 'Filename', - 'no_table'=> 1 - ). - '<BR></TR>' - ; - if ( $fixed and $fixed eq 'td_eft1464' ) { - # special case, this one has two upload formats - $html_init .= qq!<TR>Format !. - qq!<SELECT NAME="format">!. - qq!<OPTION VALUE="td_eftack264">TD EFT Acknowledgement</OPTION>!. - qq!<OPTION VALUE="td_eftret80">TD EFT Returned Items</OPTION>!. - qq!</SELECT><BR></TR>!; - } - elsif ( $fixed ) { - $html_init .= qq!<INPUT TYPE="hidden" NAME="format" VALUE="$fixed">!; - } else { - # should pull this from %import_info - $html_init .= qq!<TR>Format !. - qq!<SELECT NAME="format">!. - qq!<OPTION VALUE="">Default batch mode</OPTION>!. - qq!<OPTION VALUE="csv-td_canada_trust-merchant_pc_batch">CSV results from TD Canada Trust Merchant PC Batch</OPTION>!. - qq!<OPTION VALUE="csv-chase_canada-E-xactBatch">CSV file for Chase Canada E-xactBatch</OPTION>!. - qq!<OPTION VALUE="PAP">264 byte results for TD Canada Trust PAP Batch</OPTION>!. - qq!<OPTION VALUE="BoM">Bank of Montreal ECA results</OPTION>!. - qq!<OPTION VALUE="ach-spiritone">Spiritone ACH batch</OPTION>!. - qq!<OPTION VALUE="paymentech">Chase Paymentech XML</OPTION>!. - qq!<OPTION VALUE="RBC">Royal Bank of Canada PDS</OPTION>!. - qq!<OPTION VALUE="td_eftack264">TD EFT Acknowledgement</OPTION>!. - qq!<OPTION VALUE="td_eftret80">TD EFT Returned Items</OPTION>!. - qq!</SELECT><BR></TR>!; - } - $html_init .= qq!<INPUT TYPE="hidden" NAME="batchnum" VALUE="$batchnum">!; - $html_init .= '<TR> <INPUT TYPE="submit" VALUE="Upload"></FORM><BR> </TR>'; - 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!<TR><INPUT TYPE="button" VALUE="Manually approve" onclick=" -if ( confirm('Approve all remaining payments in this batch?') ) - window.location.href='${p}misc/process/pay_batch-approve.cgi?batchnum=$batchnum';"></TR>! - } - } - $html_init .= '</TABLE>'; + $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<BR>\$" . - sprintf("%.2f", $total) ." total in batch<BR>"; -} - </%init> 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') ) +% ) { +<TABLE> +<TR><FORM ACTION="<%$p%>misc/download-batch.cgi" METHOD="POST"> +<INPUT TYPE="hidden" NAME="batchnum" VALUE="<%$batchnum%>"> +% if ( $fixed ) { +<INPUT TYPE="hidden" NAME="format" VALUE="<%$fixed%>"> +% } +% else { +Download batch in format <SELECT NAME="format"> +% foreach ( keys %download_formats ) { +<OPTION VALUE="<%$_%>"><% $download_formats{$_} %></OPTION> +% } +</SELECT> +% } +<INPUT TYPE="submit" VALUE="Download"></FORM><BR><BR></TR> +% } # 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') +% ) +% ) { +<TR> +<% 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<BR></TR> +<TR> +<% include('/elements/file-upload.html', + 'field' => 'file', + 'label' => 'Filename', + 'no_table' => 1, +) %> +<INPUT TYPE="hidden" NAME="batchnum" VALUE="<% $batchnum %>"> +<BR></TR> +% if ( $fixed ) { +% if ( $fixed eq 'td_eft1464' ) { # special case +<TR>Format <SELECT NAME="format"> +<OPTION VALUE="td_eftack264">TD EFT Acknowledgement</OPTION> +<OPTION VALUE="td_eftret80">TD EFT Returned Items</OPTION> +</SELECT></TR> +% } +% else { +<INPUT TYPE="hidden" NAME="format" VALUE="<% $fixed %>"> +% } +% } +% else { +<TR>Format <SELECT NAME="format"> +% foreach ( keys(%upload_formats) ) { +<OPTION VALUE="<%$_%>"><% $upload_formats{$_} %></OPTION> +% } +% } # if $fixed +<TR><INPUT TYPE="submit" VALUE="Upload"></TR> +</FORM><BR> +% } # end upload + +% # manual approval +% if ( $fixed eq 'td_eft1464' +% and $status eq 'I' +% and $payby eq 'CHEK' +% and $conf->exists('batch-manual_approval') +% ) { +<TR><INPUT TYPE="button" VALUE="Manually approve" onclick=" +if ( confirm('Approve all remaining payments in this batch?') ) + window.location.href='<%$p%>misc/process/pay_batch-approve.cgi?batchnum=<%$batchnum%>'; +"></TR> +% } # end manual approval +</TABLE> + +% # summary info +Batch is <% $statustext{$status} %><BR> +<%$count%> payments batched<BR> +<%$money_char%><%$total%> total in batch<BR> + +<%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)); +</%init> 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 = '<A HREF="' . $cgi->self_url . '"><I>'. + ($resolved ? 'Hide' : 'Show') . ' resolved batches</I></A><BR>'; + </%init> |