X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fcust_main.pm;h=11d77639327cedc03ec5bdf73d225b33a6eeb2c0;hp=9ba1129e555a51d9300f0c4a070cd026a454b7d8;hb=c5a2d3613acdc3b9ab6f32eaf5316c2834071417;hpb=47d5558991d119d7b8fbd9e8256a78776af5d585 diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 9ba1129e5..11d776393 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -29,6 +29,7 @@ use Date::Format; use File::Temp; #qw( tempfile ); use Business::CreditCard 0.28; use List::Util qw(min); +use Try::Tiny; use FS::UID qw( dbh driver_name ); use FS::Record qw( qsearchs qsearch dbdef regexp_sql ); use FS::Cursor; @@ -76,6 +77,7 @@ use FS::upgrade_journal; use FS::sales; use FS::cust_payby; use FS::contact; +use FS::reason; # 1 is mostly method/subroutine entry and options # 2 traces progress of some operations @@ -596,17 +598,21 @@ sub insert { } } - my $contact = FS::contact->new({ - 'custnum' => $self->get('custnum'), - 'last' => $self->get('last'), - 'first' => $self->get('first'), - 'emailaddress' => $email, - 'invoice_dest' => 'Y', # yes, you can set this via the contact - }); - my $error = $contact->insert; - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return $error; + if ( $email ) { + + my $contact = FS::contact->new({ + 'custnum' => $self->get('custnum'), + 'last' => $self->get('last'), + 'first' => $self->get('first'), + 'emailaddress' => $email, + 'invoice_dest' => 'Y', # yes, you can set this via the contact + }); + my $error = $contact->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } } @@ -1863,6 +1869,10 @@ sub check { && ! $self->custnum && $conf->exists('cust_main-require_locale'); + return "Please select a customer class" + if ! $self->classnum + && $conf->exists('cust_main-require_classnum'); + foreach my $flag (qw( tax spool_cdr squelch_cdr archived email_csv_cdr )) { $self->$flag() =~ /^(Y?)$/ or return "Illegal $flag: ". $self->$flag(); $self->$flag($1); @@ -2159,7 +2169,11 @@ FS::cust_pkg::cancel() methods. =item quiet - can be set true to supress email cancellation notices. -=item reason - can be set to a cancellation reason (see L), either a reasonnum of an existing reason, or passing a hashref will create a new reason. The hashref should have the following keys: typenum - Reason type (see L, reason - Text of the new reason. +=item reason - can be set to a cancellation reason (see L), either a +reasonnum of an existing reason, or passing a hashref will create a new reason. +The hashref should have the following keys: +typenum - Reason type (see L) +reason - Text of the new reason. =item cust_pkg_reason - can be an arrayref of L objects for the individual packages, parallel to the C argument. The @@ -2174,7 +2188,10 @@ reason and reason_otaker arguments will be taken from those objects. sub cancel_pkgs { my( $self, %opt ) = @_; - my $oldAutoCommit = $FS::UID::AutoCommit; + # we're going to cancel services, which is not reversible + die "cancel_pkgs cannot be run inside a transaction" + if $FS::UID::AutoCommit == 0; + local $FS::UID::AutoCommit = 0; return ( 'access denied' ) @@ -2193,7 +2210,7 @@ sub cancel_pkgs { my $ban = new FS::banned_pay $cust_payby->_new_banned_pay_hashref; my $error = $ban->insert; if ($error) { - dbh->rollback if $oldAutoCommit; + dbh->rollback; return ( $error ); } @@ -2213,13 +2230,15 @@ sub cancel_pkgs { 'time' => $cancel_time ); if ($error) { warn "Error billing during cancel, custnum ". $self->custnum. ": $error"; - dbh->rollback if $oldAutoCommit; + dbh->rollback; return ( "Error billing during cancellation: $error" ); } } + dbh->commit; my @errors; - # now cancel all services, the same way we would for individual packages + # try to cancel each service, the same way we would for individual packages, + # but in cancel weight order. my @cust_svc = map { $_->cust_svc } @pkgs; my @sorted_cust_svc = map { $_->[0] } @@ -2232,11 +2251,17 @@ sub cancel_pkgs { foreach my $cust_svc (@sorted_cust_svc) { my $part_svc = $cust_svc->part_svc; next if ( defined($part_svc) and $part_svc->preserve ); - my $error = $cust_svc->cancel; # immediate cancel, no date option - push @errors, $error if $error; + # immediate cancel, no date option + # transactionize individually + my $error = try { $cust_svc->cancel } catch { $_ }; + if ( $error ) { + dbh->rollback; + push @errors, $error; + } else { + dbh->commit; + } } if (@errors) { - dbh->rollback if $oldAutoCommit; return @errors; } @@ -2248,23 +2273,37 @@ sub cancel_pkgs { if ($opt{'cust_pkg_reason'}) { @cprs = @{ delete $opt{'cust_pkg_reason'} }; } + my $null_reason; foreach (@pkgs) { my %lopt = %opt; if (@cprs) { my $cpr = shift @cprs; - $lopt{'reason'} = $cpr->reasonnum; - $lopt{'reason_otaker'} = $cpr->otaker; + if ( $cpr ) { + $lopt{'reason'} = $cpr->reasonnum; + $lopt{'reason_otaker'} = $cpr->otaker; + } else { + warn "no reason found when canceling package ".$_->pkgnum."\n"; + # we're not actually required to pass a reason to cust_pkg::cancel, + # but if we're getting to this point, something has gone awry. + $null_reason ||= FS::reason->new_or_existing( + reason => 'unknown reason', + type => 'Cancel Reason', + class => 'C', + ); + $lopt{'reason'} = $null_reason->reasonnum; + $lopt{'reason_otaker'} = $FS::CurrentUser::CurrentUser->username; + } } my $error = $_->cancel(%lopt); - push @errors, 'pkgnum '.$_->pkgnum.': '.$error if $error; - } - - if (@errors) { - dbh->rollback if $oldAutoCommit; - return @errors; + if ( $error ) { + dbh->rollback; + push @errors, 'pkgnum '.$_->pkgnum.': '.$error; + } else { + dbh->commit; + } } - return; + return @errors; } sub _banned_pay_hashref { @@ -4404,6 +4443,10 @@ CHEK only CHEK only +=item saved_cust_payby + +scalar reference, for returning saved object + =back =cut @@ -4600,6 +4643,9 @@ PAYBYLOOP: return $error; } + ${$opt{'saved_cust_payby'}} = $new + if $opt{'saved_cust_payby'}; + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; @@ -4769,15 +4815,10 @@ Returns an SQL expression identifying un-cancelled cust_main records. =cut sub uncancelled_sql { uncancel_sql(@_); } -sub uncancel_sql { " - ( 0 < ( $select_count_pkgs - AND ( cust_pkg.cancel IS NULL - OR cust_pkg.cancel = 0 - ) - ) - OR 0 = ( $select_count_pkgs ) - ) -"; } +sub uncancel_sql { + my $self = shift; + "( NOT (".$self->cancelled_sql.") )"; #sensitive to cust_main-status_module +} =item balance_sql