From a9bd30b5b5231db37360e285fbbfa237195cd064 Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Thu, 30 Apr 2015 06:52:43 -0700 Subject: [PATCH] service dependencies: cust_svc_suspend_cascade, RT#33685 --- FS/FS/cust_pkg.pm | 49 ++++++++++++++++++++------------------ FS/FS/cust_svc.pm | 31 ++++++++++++++++++++++++ FS/FS/part_svc_link.pm | 4 ++-- httemplate/edit/part_svc_link.html | 2 +- 4 files changed, 60 insertions(+), 26 deletions(-) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 07e02f92c..935236245 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1404,31 +1404,34 @@ sub suspend { } } - my @labels = (); - - foreach my $cust_svc ( - qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum } ) - ) { - my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $cust_svc->svcpart } ); - - $part_svc->svcdb =~ /^([\w\-]+)$/ or do { - $dbh->rollback if $oldAutoCommit; - return "Illegal svcdb value in part_svc!"; - }; - my $svcdb = $1; - require "FS/$svcdb.pm"; - - my $svc = qsearchs( $svcdb, { 'svcnum' => $cust_svc->svcnum } ); - if ($svc) { - $error = $svc->suspend; - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return $error; - } - my( $label, $value ) = $cust_svc->label; - push @labels, "$label: $value"; + my @cust_svc = qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum } ) + + #attempt ordering ala cust_svc_suspend_cascade (without infinite-looping + # on the circular dep case) + # (this is too simple for multi-level deps, we need to use something + # to resolve the DAG properly when possible) + my %svcpart = (); + $svcpart{$_->svcpart} = 0 foreach @cust_svc; + foreach my $svcpart ( keys %svcpart ) { + foreach my $part_pkg_link ( + FS::part_svc_link->by_agentnum($self->cust_main->agentnum, + src_svcpart => $svcpart, + link_type => 'cust_svc_suspend_cascade' + ) + ) { + $svcpart{$part_svc_link->dst_svcpart} = max( + $svcpart{$part_svc_link->dst_svcpart}, + $svcpart{$part_svc_link->src_svcpart} + 1 + ); } } + @cust_svc = sort { $svcpart{ $a->svcpart } <=> $svcpart{ $b->svcpart } } + @cust_svc; + + my @labels = (); + foreach my $cust_svc ( @cust_svc ) { + $cust_svc->suspend( 'labels_arrayref' => \@labels ); + } # suspension fees: if there is a feepart, and it's not an unsuspend fee, # and this is not a suspend-before-cancel diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index 5922e32ad..046558004 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -183,6 +183,37 @@ sub delete { } +=item suspend + +Suspends the relevant service by calling the B method of the associated +FS::svc_XXX object (i.e. an FS::svc_acct object or FS::svc_domain object). + +If there is an error, returns the error, otherwise returns false. + +=cut + +sub suspend { + my( $self, %opt ) = @_; + + $self->part_svc->svcdb =~ /^([\w\-]+)$/ or return 'Illegal part_svc.svcdb'; + my $svcdb = $1; + require "FS/$svcdb.pm"; + + my $svc = qsearchs( $svcdb, { 'svcnum' => $self->svcnum } ) + or return ''; + + $error = $svc->suspend; + return $error if $error; + + if ( $opt{labels_arryref} ) { + my( $label, $value ) = $self->label; + push @{ $opt{labels_arrayref} }, "$label: $value"; + } + + ''; + +} + =item cancel Cancels the relevant service by calling the B method of the associated diff --git a/FS/FS/part_svc_link.pm b/FS/FS/part_svc_link.pm index a7f1b0f38..e8c2cc556 100644 --- a/FS/FS/part_svc_link.pm +++ b/FS/FS/part_svc_link.pm @@ -88,7 +88,7 @@ unprovisioned =item cust_svc_suspend_cascade -Suspend the destination service before the source service +Suspend the destination service after the source service =back @@ -205,7 +205,7 @@ sub description { and return "Automatically unprovision $dst when $src is unprovisioned"; $l eq 'cust_svc_suspend_cascade' - and return "Suspend $dst before $src"; + and return "Suspend $dst after $src"; warn "WARNING: unknown part_svc_link.link_type $l\n"; return "$src (unknown link_type $l) $dst"; diff --git a/httemplate/edit/part_svc_link.html b/httemplate/edit/part_svc_link.html index c8c385dd5..980b24e47 100644 --- a/httemplate/edit/part_svc_link.html +++ b/httemplate/edit/part_svc_link.html @@ -35,7 +35,7 @@ my @fields = ( cust_svc_provision_restrict => 'Require the target service to be provisioned before the source service', cust_svc_unprovision_restrict => 'Require the target service to be unprovisioned before the source service', cust_svc_unprovision_cascade => 'Automatically unprovision the target service when the source service is unprovisioned', - cust_svc_suspend_cascade => 'Suspend the target service before the source service', + cust_svc_suspend_cascade => 'Suspend the target service after the source service', }, }, { field => 'disabled', type => 'checkbox', value => 'Y' } -- 2.11.0