( $content{account_number}, $content{routing_code} ) =
split('@', $payinfo);
$content{bank_name} = $o_payname;
- $content{bank_state} = $self->getfield('paystate');
- $content{account_type} = uc($self->getfield('paytype')) || 'CHECKING';
+ $content{bank_state} = exists($options{'paystate'})
+ ? $options{'paystate'}
+ : $self->getfield('paystate');
+ $content{account_type} = exists($options{'paytype'})
+ ? uc($options{'paytype'}) || 'CHECKING'
+ : uc($self->getfield('paytype')) || 'CHECKING';
$content{account_name} = $payname;
$content{customer_org} = $self->company ? 'B' : 'I';
- $content{state_id} = $self->getfield('stateid');
- $content{state_id_state} = $self->getfield('stateid_state');
+ $content{state_id} = exists($options{'stateid'})
+ ? $options{'stateid'}
+ : $self->getfield('stateid');
+ $content{state_id_state} = exists($options{'stateid_state'})
+ ? $options{'stateid_state'}
+ : $self->getfield('stateid_state');
$content{customer_ssn} = exists($options{'ss'})
? $options{'ss'}
: $self->ss;
'paybatch' => $paybatch,
'paydate' => $paydate,
} );
+ $cust_pay->payunique( $options{payunique} ) if length($options{payunique});
+
my $error = $cust_pay->insert($options{'manual'} ? ( 'manual' => 1 ) : () );
+
if ( $error ) {
$cust_pay->invnum(''); #try again with no specific invnum
my $error2 = $cust_pay->insert( $options{'manual'} ?
}
} elsif ( $method eq 'ECHECK' ) {
- ( $content{account_number}, $content{routing_code} ) =
- split('@', $payinfo = $self->payinfo);
+
+ if ( $cust_pay ) {
+ $payinfo = $cust_pay->payinfo;
+ } else {
+ $payinfo = $self->payinfo;
+ }
+ ( $content{account_number}, $content{routing_code} )= split('@', $payinfo );
$content{bank_name} = $self->payname;
$content{account_type} = 'CHECKING';
$content{account_name} = $payname;
In most cases, this new method should be used in place of sequential
apply_payments and apply_credits methods.
+If there is an error, returns the error, otherwise returns false.
+
=cut
sub apply_payments_and_credits {
my $self = shift;
+ 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;
+
+ $self->select_for_update; #mutex
+
foreach my $cust_bill ( $self->open_cust_bill ) {
- $cust_bill->apply_payments_and_credits;
+ my $error = $cust_bill->apply_payments_and_credits;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "Error applying: $error";
+ }
}
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ ''; #no error
+
}
=item apply_credits OPTION => VALUE ...
value of any remaining unapplied credits available for refund (see
L<FS::cust_refund>).
+Dies if there is an error.
+
=cut
sub apply_credits {
my $self = shift;
my %opt = @_;
- return 0 unless $self->total_credited;
+ 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;
+
+ $self->select_for_update; #mutex
+
+ unless ( $self->total_credited ) {
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ return 0;
+ }
my @credits = sort { $b->_date <=> $a->_date} (grep { $_->credited > 0 }
qsearch('cust_credit', { 'custnum' => $self->custnum } ) );
'amount' => $amount,
} );
my $error = $cust_credit_bill->insert;
- die $error if $error;
+ if ( $error ) {
+ $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
+ die $error;
+ }
redo if ($cust_bill->owed > 0);
}
- return $self->total_credited;
+ my $total_credited = $self->total_credited;
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ return $total_credited;
}
=item apply_payments
#and returns the value of any remaining unapplied payments.
+Dies if there is an error.
+
=cut
sub apply_payments {
my $self = shift;
+ 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;
+
+ $self->select_for_update; #mutex
+
#return 0 unless
my @payments = sort { $b->_date <=> $a->_date } ( grep { $_->unapplied > 0 }
'amount' => $amount,
} );
my $error = $cust_bill_pay->insert;
- die $error if $error;
+ if ( $error ) {
+ $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
+ die $error;
+ }
redo if ( $cust_bill->owed > 0);
}
- return $self->total_unapplied_payments;
+ my $total_unapplied_payments = $self->total_unapplied_payments;
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+ return $total_unapplied_payments;
}
=item total_credited
@fuzzyfields = ( 'last', 'first', 'company' );
sub check_and_rebuild_fuzzyfiles {
- my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ my $dir = $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc;
rebuild_fuzzyfiles() if grep { ! -e "$dir/cust_main.$_" } @fuzzyfields
}
use Fcntl qw(:flock);
- my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ my $dir = $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc;
mkdir $dir, 0700 unless -d $dir;
foreach my $fuzzy ( @fuzzyfields ) {
sub all_X {
my( $self, $field ) = @_;
- my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ my $dir = $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc;
open(CACHE,"<$dir/cust_main.$field")
or die "can't open $dir/cust_main.$field: $!";
my @array = map { chomp; $_; } <CACHE>;
use Fcntl qw(:flock);
- my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
+ my $dir = $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc;
foreach my $field (qw( first last company )) {
my $value = shift;
return "can't bill customer for $line: $error";
}
- $cust_main->apply_payments_and_credits;
-
+ $error = $cust_main->apply_payments_and_credits;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't bill customer for $line: $error";
+ }
+
$error = $cust_main->collect();
if ( $error ) {
$dbh->rollback if $oldAutoCommit;