X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_main.pm;h=4a254e06ccf0e996993a77cb1ad21e8cf054d825;hb=1c14b1faec0f3f07a6d4190cf535b3ddb45075ce;hp=b863748a0abefc36f15d24c28ee455c00090cedc;hpb=b84f789033eba9a0fc74bca5a071cfefd87f3c69;p=freeside.git diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index b863748a0..4a254e06c 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -15,7 +15,7 @@ use Date::Format; use Mail::Internet; use Mail::Header; use Business::CreditCard; -use FS::UID qw( getotaker ); +use FS::UID qw( getotaker dbh ); use FS::Record qw( qsearchs qsearch ); use FS::cust_pkg; use FS::cust_bill; @@ -183,17 +183,24 @@ sub table { 'cust_main'; } Adds this customer to the database. If there is an error, returns the error, otherwise returns false. +There is a special insert mode in which you pass a data structure to the insert +method containing FS::cust_pkg and FS::svc_I objects. When +running under a transactional database, all records are inserted atomicly, or +the transaction is rolled back. There should be a better explanation of this, +but until then, here's an example: + + use Tie::RefHash; + tie %hash, 'Tie::RefHash'; #this part is important + %hash = { + $cust_pkg => [ $svc_acct ], + }; + $cust_main->insert( \%hash ); + =cut sub insert { my $self = shift; - my $flag = 0; - if ( $self->payby eq 'PREPAY' ) { - $self->payby('BILL'); - $flag = 1; - } - local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; local $SIG{QUIT} = 'IGNORE'; @@ -201,30 +208,79 @@ sub insert { local $SIG{TSTP} = 'IGNORE'; local $SIG{PIPE} = 'IGNORE'; - my $error = $self->SUPER::insert; - return $error if $error; + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; - if ( $flag ) { - my $prepay_credit = - qsearchs('prepay_credit', { 'identifier' => $self->payinfo } ); + my $amount = 0; + my $seconds = 0; + if ( $self->payby eq 'PREPAY' ) { + $self->payby('BILL'); + my $prepay_credit = qsearchs( + 'prepay_credit', + { 'identifier' => $self->payinfo }, + '', + 'FOR UPDATE' + ); warn "WARNING: can't find pre-found prepay_credit: ". $self->payinfo unless $prepay_credit; - my $amount = $prepay_credit->amount; + $amount = $prepay_credit->amount; + $seconds = $prepay_credit->seconds; my $error = $prepay_credit->delete; if ( $error ) { - warn "WARNING: can't delete prepay_credit: ". $self->payinfo; - } else { - my $cust_credit = new FS::cust_credit { - 'custnum' => $self->custnum, - 'amount' => $amount, - }; - my $error = $cust_credit->insert; - warn "WARNING: error inserting cust_credit for prepay_credit: $error" - if $error; + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + my $error = $self->SUPER::insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + if ( @_ ) { + my $cust_pkgs = shift; + foreach my $cust_pkg ( keys %$cust_pkgs ) { + $cust_pkg->custnum( $self->custnum ); + $error = $cust_pkg->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + foreach my $svc_something ( @{$cust_pkgs->{$cust_pkg}} ) { + $svc_something->pkgnum( $cust_pkg->pkgnum ); + if ( $seconds && $svc_something->isa('FS::svc_acct') ) { + $svc_something->seconds( $svc_something->seconds + $seconds ); + $seconds = 0; + } + $error = $svc_something->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } } + } + if ( $seconds ) { + $dbh->rollback if $oldAutoCommit; + return "No svc_acct record to apply pre-paid time"; } + if ( $amount ) { + my $cust_credit = new FS::cust_credit { + 'custnum' => $self->custnum, + 'amount' => $amount, + }; + $error = $cust_credit->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; } @@ -249,13 +305,6 @@ or credits (see L). sub delete { my $self = shift; - if ( qsearch( 'cust_bill', { 'custnum' => $self->custnum } ) ) { - return "Can't delete a customer with invoices"; - } - if ( qsearch( 'cust_credit', { 'custnum' => $self->custnum } ) ) { - return "Can't delete a customer with credits"; - } - local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; local $SIG{QUIT} = 'IGNORE'; @@ -263,27 +312,56 @@ sub delete { local $SIG{TSTP} = 'IGNORE'; local $SIG{PIPE} = 'IGNORE'; + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + if ( qsearch( 'cust_bill', { 'custnum' => $self->custnum } ) ) { + $dbh->rollback if $oldAutoCommit; + return "Can't delete a customer with invoices"; + } + if ( qsearch( 'cust_credit', { 'custnum' => $self->custnum } ) ) { + $dbh->rollback if $oldAutoCommit; + return "Can't delete a customer with credits"; + } + my @cust_pkg = qsearch( 'cust_pkg', { 'custnum' => $self->custnum } ); if ( @cust_pkg ) { my $new_custnum = shift; - return "Invalid new customer number: $new_custnum" - unless qsearchs( 'cust_main', { 'custnum' => $new_custnum } ); + unless ( qsearchs( 'cust_main', { 'custnum' => $new_custnum } ) ) { + $dbh->rollback if $oldAutoCommit; + return "Invalid new customer number: $new_custnum"; + } foreach my $cust_pkg ( @cust_pkg ) { my %hash = $cust_pkg->hash; $hash{'custnum'} = $new_custnum; my $new_cust_pkg = new FS::cust_pkg ( \%hash ); my $error = $new_cust_pkg->replace($cust_pkg); - return $error if $error; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } } } foreach my $cust_main_invoice ( qsearch( 'cust_main_invoice', { 'custnum' => $self->custnum } ) ) { my $error = $cust_main_invoice->delete; - return $error if $error; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + my $error = $self->SUPER::delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; } - $self->SUPER::delete; + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; + } =item replace OLD_RECORD @@ -494,6 +572,10 @@ sub bill { local $SIG{TSTP} = 'IGNORE'; local $SIG{PIPE} = 'IGNORE'; + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + # find the packages which are due for billing, find out how much they are # & generate invoice database. @@ -565,9 +647,9 @@ sub bill { } } - warn "setup is undefinded" unless defined($setup); - warn "recur is undefinded" unless defined($recur); - warn "cust_pkg bill is undefinded" unless defined($cust_pkg->bill); + warn "setup is undefined" unless defined($setup); + warn "recur is undefined" unless defined($recur); + warn "cust_pkg bill is undefined" unless defined($cust_pkg->bill); if ( $cust_pkg_mod_flag ) { $error=$cust_pkg->replace($old_cust_pkg); @@ -593,7 +675,10 @@ sub bill { my $charged = sprintf( "%.2f", $total_setup + $total_recur ); - return '' if scalar(@cust_bill_pkg) == 0; + unless ( @cust_bill_pkg ) { + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + return ''; + } unless ( $self->getfield('tax') =~ /Y/i || $self->getfield('payby') eq 'COMP' @@ -624,11 +709,10 @@ sub bill { 'charged' => $charged, } ); $error = $cust_bill->insert; - #shouldn't happen, but how else to handle this? (wrap me in eval, to catch - # fatal errors) - die "Error creating cust_bill record: $error!\n", - "Check updated but unbilled packages for customer", $self->custnum, "\n" - if $error; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "$error for customer #". $self->custnum; + } my $invnum = $cust_bill->invnum; my $cust_bill_pkg; @@ -636,11 +720,13 @@ sub bill { $cust_bill_pkg->setfield( 'invnum', $invnum ); $error = $cust_bill_pkg->insert; #shouldn't happen, but how else tohandle this? - die "Error creating cust_bill_pkg record: $error!\n", - "Check incomplete invoice ", $invnum, "\n" - if $error; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "$error for customer #". $self->custnum; + } } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; #no error } @@ -673,10 +759,6 @@ sub collect { my( $self, %options ) = @_; my $invoice_time = $options{'invoice_time'} || time; - my $total_owed = $self->balance; - warn "collect: total owed $total_owed " if $Debug; - return '' unless $total_owed > 0; #redundant????? - #put below somehow? local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; @@ -685,6 +767,17 @@ sub collect { local $SIG{TSTP} = 'IGNORE'; local $SIG{PIPE} = 'IGNORE'; + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $total_owed = $self->balance; + warn "collect: total owed $total_owed " if $Debug; + unless ( $total_owed > 0 ) { #redundant????? + $dbh->rollback if $oldAutoCommit; + return ''; + } + foreach my $cust_bill ( qsearch('cust_bill', { 'custnum' => $self->custnum, } ) ) { @@ -758,14 +851,20 @@ sub collect { 'paybatch' => '' } ); my $error = $cust_pay->insert; - return 'Error COMPing invnum #' . $cust_bill->invnum . - ':' . $error if $error; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return 'Error COMPing invnum #'. $cust_bill->invnum. ": $error"; + } + } elsif ( $self->payby eq 'CARD' ) { if ( $options{'batch_card'} ne 'yes' ) { - return "Real time card processing not enabled!" unless $processor; + unless ( $processor ) { + $dbh->rollback if $oldAutoCommit; + return "Real time card processing not enabled!"; + } if ( $processor =~ /^cybercash/ ) { @@ -806,7 +905,8 @@ sub collect { } elsif ( $processor eq 'cybercash3.2' ) { %result = &CCMckDirectLib3_2::SendCC2_1Server(@full_xaction); } else { - return "Unkonwn real-time processor $processor\n"; + $dbh->rollback if $oldAutoCommit; + return "Unknown real-time processor $processor"; } #if ( $result{'MActionCode'} == 7 ) { #cybercash smps v.1.1.3 @@ -821,18 +921,28 @@ sub collect { 'paybatch' => "$processor:$paybatch", } ); my $error = $cust_pay->insert; - return 'Error applying payment, invnum #' . - $cust_bill->invnum. ':'. $error if $error; + if ( $error ) { + # gah, even with transactions. + $dbh->commit if $oldAutoCommit; #well. + my $e = 'WARNING: Card debited but database not updated - '. + 'error applying payment, invnum #' . $cust_bill->invnum. + " (CyberCash Order-ID $paybatch): $error"; + warn $e; + return $e; + } } elsif ( $result{'Mstatus'} ne 'failure-bad-money' || $options{'report_badcard'} ) { + $dbh->commit if $oldAutoCommit; return 'Cybercash error, invnum #' . $cust_bill->invnum. ':'. $result{'MErrMsg'}; } else { + $dbh->commit or die $dbh->errstr if $oldAutoCommit; return ''; } } else { - return "Unkonwn real-time processor $processor\n"; + $dbh->rollback if $oldAutoCommit; + return "Unknown real-time processor $processor\n"; } } else { #batch card @@ -855,15 +965,20 @@ sub collect { 'amount' => $amount, } ); my $error = $cust_pay_batch->insert; - return "Error adding to cust_pay_batch: $error" if $error; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "Error adding to cust_pay_batch: $error"; + } } } else { + $dbh->rollback if $oldAutoCommit; return "Unknown payment type ". $self->payby; } } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; } @@ -999,7 +1114,7 @@ sub check_invoicing_list { =head1 VERSION -$Id: cust_main.pm,v 1.7 2000-06-27 12:15:37 ivan Exp $ +$Id: cust_main.pm,v 1.11 2001-04-09 23:05:15 ivan Exp $ =head1 BUGS