X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fcust_main.pm;h=2af6a1f011552b8b91066ab31b91450249c25af5;hp=ecd30702f622c7a47d24e4dab15a7433e11f5e07;hb=dbf521cf2f1f1a05f4722006f339b2595c8ee70f;hpb=912cbcaf930f41cd6a087ea4bcc581aad035dd41 diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index ecd30702f..2af6a1f01 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 @@ -2159,7 +2161,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 @@ -2222,10 +2228,9 @@ sub cancel_pkgs { } dbh->commit; - $FS::UID::AutoCommit = 1; my @errors; - # now cancel all services, the same way we would for individual packages. - # if any of them fail, cancel the rest anyway. + # 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] } @@ -2238,8 +2243,15 @@ 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) { return @errors; @@ -2253,15 +2265,34 @@ 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 ( $error ) { + dbh->rollback; + push @errors, 'pkgnum '.$_->pkgnum.': '.$error; + } else { + dbh->commit; + } } return @errors; @@ -4769,15 +4800,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