summaryrefslogtreecommitdiff
path: root/FS/FS/cust_main
diff options
context:
space:
mode:
authorMitch Jackson <mitch@freeside.biz>2018-09-11 03:23:52 -0400
committerMitch Jackson <mitch@freeside.biz>2018-09-19 12:02:19 -0400
commit94f0030bae0ce3e493b99860901158e30e9651fd (patch)
treeae3576bdc3073d825a424030275f7ca1918675bd /FS/FS/cust_main
parentb9bb2b3bc596c18245199cd799c5f50d3e02ea59 (diff)
RT# 78547 Allow for simulated billing within a transaction
Diffstat (limited to 'FS/FS/cust_main')
-rw-r--r--FS/FS/cust_main/Billing.pm17
-rw-r--r--FS/FS/cust_main/Billing_Realtime.pm31
2 files changed, 35 insertions, 13 deletions
diff --git a/FS/FS/cust_main/Billing.pm b/FS/FS/cust_main/Billing.pm
index 71d5c9b..1be7d39 100644
--- a/FS/FS/cust_main/Billing.pm
+++ b/FS/FS/cust_main/Billing.pm
@@ -26,6 +26,7 @@ use FS::pkg_category;
use FS::FeeOrigin_Mixin;
use FS::Log;
use FS::TaxEngine;
+use FS::Misc::Savepoint;
# 1 is mostly method/subroutine entry and options
# 2 traces progress of some operations
@@ -1753,7 +1754,10 @@ sub collect {
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
#never want to roll back an event just because it returned an error
- local $FS::UID::AutoCommit = 1; #$oldAutoCommit;
+ # unless $FS::UID::ForceObeyAutoCommit is set
+ local $FS::UID::AutoCommit = 1
+ unless !$oldAutoCommit
+ && $FS::UID::ForceObeyAutoCommit;
$self->do_cust_event(
'debug' => ( $options{'debug'} || 0 ),
@@ -1961,9 +1965,13 @@ sub do_cust_event {
}
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
#never want to roll back an event just because it or a different one
# returned an error
- local $FS::UID::AutoCommit = 1; #$oldAutoCommit;
+ # unless $FS::UID::ForceObeyAutoCommit is set
+ local $FS::UID::AutoCommit = 1
+ unless !$oldAutoCommit
+ && $FS::UID::ForceObeyAutoCommit;
foreach my $cust_event ( @$due_cust_event ) {
@@ -2288,16 +2296,21 @@ sub apply_payments_and_credits {
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
+ my $savepoint_label = 'Billing__apply_payments_and_credits';
+ savepoint_create( $savepoint_label );
+
$self->select_for_update; #mutex
foreach my $cust_bill ( $self->open_cust_bill ) {
my $error = $cust_bill->apply_payments_and_credits(%options);
if ( $error ) {
+ savepoint_rollback_and_release( $savepoint_label );
$dbh->rollback if $oldAutoCommit;
return "Error applying: $error";
}
}
+ savepoint_release( $savepoint_label );
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
''; #no error
diff --git a/FS/FS/cust_main/Billing_Realtime.pm b/FS/FS/cust_main/Billing_Realtime.pm
index 70dc9d1..64b551c 100644
--- a/FS/FS/cust_main/Billing_Realtime.pm
+++ b/FS/FS/cust_main/Billing_Realtime.pm
@@ -16,6 +16,7 @@ use FS::cust_bill_pay;
use FS::cust_refund;
use FS::banned_pay;
use FS::payment_gateway;
+use FS::Misc::Savepoint;
$realtime_bop_decline_quiet = 0;
@@ -27,6 +28,7 @@ $me = '[FS::cust_main::Billing_Realtime]';
our $BOP_TESTING = 0;
our $BOP_TESTING_SUCCESS = 1;
+our $BOP_TESTING_TIMESTAMP = '';
install_callback FS::UID sub {
$conf = new FS::Conf;
@@ -405,7 +407,7 @@ sub realtime_bop {
confess "Can't call realtime_bop within another transaction ".
'($FS::UID::AutoCommit is false)'
- unless $FS::UID::AutoCommit;
+ unless $FS::UID::AutoCommit || $BOP_TESTING;
local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG;
@@ -682,7 +684,7 @@ sub realtime_bop {
my $cust_pay_pending = new FS::cust_pay_pending {
'custnum' => $self->custnum,
'paid' => $options{amount},
- '_date' => '',
+ '_date' => $BOP_TESTING ? $BOP_TESTING_TIMESTAMP : '',
'payby' => $bop_method2payby{$options{method}},
'payinfo' => $options{payinfo},
'paymask' => $options{paymask},
@@ -757,7 +759,7 @@ sub realtime_bop {
return { reference => $cust_pay_pending->paypendingnum,
map { $_ => $transaction->$_ } qw ( popup_url collectitems ) };
- } elsif ( $transaction->is_success() && $action2 ) {
+ } elsif ( !$BOP_TESTING && $transaction->is_success() && $action2 ) {
$cust_pay_pending->status('authorized');
my $cpp_authorized_err = $cust_pay_pending->replace;
@@ -946,7 +948,7 @@ sub _realtime_bop_result {
'custnum' => $self->custnum,
'invnum' => $options{'invnum'},
'paid' => $cust_pay_pending->paid,
- '_date' => '',
+ '_date' => $BOP_TESTING ? $BOP_TESTING_TIMESTAMP : '',
'payby' => $cust_pay_pending->payby,
'payinfo' => $options{'payinfo'},
'paymask' => $options{'paymask'} || $cust_pay_pending->paymask,
@@ -967,12 +969,16 @@ sub _realtime_bop_result {
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
+ my $savepoint_label = '_realtime_bop_result';
+ savepoint_create( $savepoint_label );
+
#start a transaction, insert the cust_pay and set cust_pay_pending.status to done in a single transction
my $error = $cust_pay->insert($options{'manual'} ? ( 'manual' => 1 ) : () );
if ( $error ) {
- $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
+ savepoint_rollback( $savepoint_label );
+
$cust_pay->invnum(''); #try again with no specific invnum
$cust_pay->paynum('');
my $error2 = $cust_pay->insert( $options{'manual'} ?
@@ -981,7 +987,8 @@ sub _realtime_bop_result {
if ( $error2 ) {
# gah. but at least we have a record of the state we had to abort in
# from cust_pay_pending now.
- $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
+ savepoint_rollback_and_release( $savepoint_label );
+
my $e = "WARNING: $options{method} captured but payment not recorded -".
" error inserting payment (". $payment_gateway->gateway_module.
"): $error2".
@@ -996,9 +1003,10 @@ sub _realtime_bop_result {
my $jobnum = $cust_pay_pending->jobnum;
if ( $jobnum ) {
my $placeholder = qsearchs( 'queue', { 'jobnum' => $jobnum } );
-
+
unless ( $placeholder ) {
- $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
+ savepoint_rollback_and_release( $savepoint_label );
+
my $e = "WARNING: $options{method} captured but job $jobnum not ".
"found for paypendingnum ". $cust_pay_pending->paypendingnum. "\n";
warn $e;
@@ -1008,7 +1016,8 @@ sub _realtime_bop_result {
$error = $placeholder->delete;
if ( $error ) {
- $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
+ savepoint_rollback_and_release( $savepoint_label );
+
my $e = "WARNING: $options{method} captured but could not delete ".
"job $jobnum for paypendingnum ".
$cust_pay_pending->paypendingnum. ": $error\n";
@@ -1030,8 +1039,8 @@ sub _realtime_bop_result {
my $cpp_done_err = $cust_pay_pending->replace;
if ( $cpp_done_err ) {
+ savepoint_rollback_and_release( $savepoint_label );
- $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
my $e = "WARNING: $options{method} captured but payment not recorded - ".
"error updating status for paypendingnum ".
$cust_pay_pending->paypendingnum. ": $cpp_done_err \n";
@@ -1039,7 +1048,7 @@ sub _realtime_bop_result {
return $e;
} else {
-
+ savepoint_release( $savepoint_label );
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
if ( $options{'apply'} ) {