diff options
author | Mark Wells <mark@freeside.biz> | 2016-07-07 20:22:45 -0700 |
---|---|---|
committer | Mark Wells <mark@freeside.biz> | 2016-07-07 20:22:45 -0700 |
commit | db1221a82f407c9ebc782ff03e9cf61115eef8cb (patch) | |
tree | 20fc398c481e9ceb02b330c14d6fcdfd8fefebfc | |
parent | 6401184cc06d3a324a230490097289d0d6e7fa91 (diff) | |
parent | f609fce353fab43501bf8e3823c613562f29e18d (diff) |
Merge branch 'FREESIDE_3_BRANCH' of git.freeside.biz:/home/git/freeside into 3.x
-rw-r--r-- | FS/FS/cust_pkg.pm | 206 | ||||
-rw-r--r-- | FS/FS/h_svc_acct.pm | 1 | ||||
-rw-r--r-- | FS/FS/h_svc_forward.pm | 4 | ||||
-rw-r--r-- | FS/FS/h_svc_www.pm | 1 | ||||
-rw-r--r-- | FS/FS/svc_acct.pm | 2 | ||||
-rwxr-xr-x | httemplate/misc/cancel_pkg.html | 31 | ||||
-rwxr-xr-x | httemplate/misc/process/cancel_pkg.html | 3 | ||||
-rw-r--r-- | httemplate/view/cust_main/packages/services.html | 20 | ||||
-rw-r--r-- | httemplate/view/cust_main/packages/status.html | 2 |
9 files changed, 226 insertions, 44 deletions
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index e6374decf..b5777027b 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1090,6 +1090,166 @@ sub cancel_if_expired { ''; } +=item uncancel_svc_x + +For cancelled cust_pkg, returns a list of new, uninserted FS::svc_X records +for services that would be inserted by L</uncancel>. Returned objects also +include the field _h_svc_x, which contains the service history object. + +Set pkgnum before inserting. + +Accepts the following options: + +only_svcnum - arrayref of svcnum, only returns objects for these svcnum +(and only if they would otherwise be returned by this) + +=cut + +sub uncancel_svc_x { + my ($self, %opt) = @_; + + die 'uncancel_svc_x called on a non-cancelled cust_pkg' unless $self->get('cancel'); + + #find historical services within this timeframe before the package cancel + # (incompatible with "time" option to cust_pkg->cancel?) + my $fuzz = 2 * 60; #2 minutes? too much? (might catch separate unprovision) + # too little? (unprovisioing export delay?) + my($end, $start) = ( $self->get('cancel'), $self->get('cancel') - $fuzz ); + my @h_cust_svc = $self->h_cust_svc( $end, $start ); + + my @svc_x; + foreach my $h_cust_svc (@h_cust_svc) { + next if $opt{'only_svcnum'} && !(grep { $_ == $h_cust_svc->svcnum } @{$opt{'only_svcnum'}}); + # filter out services that still exist on this package (ie preserved svcs) + # but keep services that have since been provisioned on another package (for informational purposes) + next if qsearchs('cust_svc',{ 'svcnum' => $h_cust_svc->svcnum, 'pkgnum' => $self->pkgnum }); + my $h_svc_x = $h_cust_svc->h_svc_x( $end, $start ); + next unless $h_svc_x; # this probably doesn't happen, but just in case + (my $table = $h_svc_x->table) =~ s/^h_//; + require "FS/$table.pm"; + my $class = "FS::$table"; + my $svc_x = $class->new( { + 'svcpart' => $h_cust_svc->svcpart, + '_h_svc_x' => $h_svc_x, + map { $_ => $h_svc_x->get($_) } fields($table) + } ); + + # radius_usergroup + if ( $h_svc_x->isa('FS::h_svc_Radius_Mixin') ) { + $svc_x->usergroup( [ $h_svc_x->h_usergroup($end, $start) ] ); + } + + #these are pretty rare, but should handle them + # - dsl_device (mac addresses) + # - phone_device (mac addresses) + # - dsl_note (ikano notes) + # - domain_record (i.e. restore DNS information w/domains) + # - inventory_item(?) (inventory w/un-cancelling service?) + # - nas (svc_broaband nas stuff) + #this stuff is unused in the wild afaik + # - mailinglistmember + # - router.svcnum? + # - svc_domain.parent_svcnum? + # - acct_snarf (ancient mail fetching config) + # - cgp_rule (communigate) + # - cust_svc_option (used by our Tron stuff) + # - acct_rt_transaction (used by our time worked stuff) + + push @svc_x, $svc_x; + } + return @svc_x; +} + +=item uncancel_svc_summary + +Returns an array of hashrefs, one for each service that could +potentially be reprovisioned by L</uncancel>, with the following keys: + +svcpart + +svc + +uncancel_svcnum + +label - from history table if not currently calculable, undefined if it can't be loaded + +reprovisionable - 1 if test reprovision succeeded, otherwise 0 + +num_cust_svc - number of svcs for this svcpart, only if summarizing (see below) + +Cannot be run from within a transaction. Performs inserts +to test the results, and then rolls back the transaction. +Does not perform exports, so does not catch if export would fail. + +Also accepts the following options: + +no_test_reprovision - skip the test inserts (reprovisionable field will not exist) + +summarize_size - if true, returns a single summary record for svcparts with at +least this many svcs, will have key num_cust_svc but not uncancel_svcnum, label or reprovisionable + +=cut + +sub uncancel_svc_summary { + my ($self, %opt) = @_; + + die 'uncancel_svc_summary called on a non-cancelled cust_pkg' unless $self->get('cancel'); + die 'uncancel_svc_summary called from within a transaction' unless $FS::UID::AutoCommit; + + local $FS::svc_Common::noexport_hack = 1; # very important not to run exports!!! + local $FS::UID::AutoCommit = 0; + + # sort by svcpart, to check summarize_size + my $uncancel_svc_x = {}; + foreach my $svc_x (sort { $a->{'svcpart'} <=> $b->{'svcpart'} } $self->uncancel_svc_x) { + $uncancel_svc_x->{$svc_x->svcpart} = [] unless $uncancel_svc_x->{$svc_x->svcpart}; + push @{$uncancel_svc_x->{$svc_x->svcpart}}, $svc_x; + } + + my @out; + foreach my $svcpart (keys %$uncancel_svc_x) { + my @svcpart_svc_x = @{$uncancel_svc_x->{$svcpart}}; + if ($opt{'summarize_size'} && (@svcpart_svc_x >= $opt{'summarize_size'})) { + my $svc_x = $svcpart_svc_x[0]; #grab first one for access to $part_svc + my $part_svc = $svc_x->part_svc; + push @out, { + 'svcpart' => $part_svc->svcpart, + 'svc' => $part_svc->svc, + 'num_cust_svc' => scalar(@svcpart_svc_x), + }; + } else { + foreach my $svc_x (@svcpart_svc_x) { + my $part_svc = $svc_x->part_svc; + my $out = { + 'svcpart' => $part_svc->svcpart, + 'svc' => $part_svc->svc, + 'uncancel_svcnum' => $svc_x->get('_h_svc_x')->svcnum, + }; + $svc_x->pkgnum($self->pkgnum); # provisioning services on a canceled package, will be rolled back + my $insert_error; + unless ($opt{'no_test_reprovision'}) { + # avoid possibly fatal errors from missing linked records + eval { $insert_error = $svc_x->insert }; + $insert_error ||= $@; + } + if ($opt{'no_test_reprovision'} or $insert_error) { + # avoid possibly fatal errors from missing linked records + eval { $out->{'label'} = $svc_x->label }; + eval { $out->{'label'} = $svc_x->get('_h_svc_x')->label } unless defined($out->{'label'}); + $out->{'reprovisionable'} = 0 unless $opt{'no_test_reprovision'}; + } else { + $out->{'label'} = $svc_x->label; + $out->{'reprovisionable'} = 1; + } + push @out, $out; + } + } + } + + dbh->rollback; + return @out; +} + =item uncancel "Un-cancels" this package: Orders a new package with the same custnum, pkgpart, @@ -1102,6 +1262,8 @@ svc_fatal: service provisioning errors are fatal svc_errors: pass an array reference, will be filled in with any provisioning errors +only_svcnum: arrayref, only attempt to re-provision these cancelled services + main_pkgnum: link the package as a supplemental package of this one. For internal use only. @@ -1165,32 +1327,12 @@ sub uncancel { # insert services ## - #find historical services within this timeframe before the package cancel - # (incompatible with "time" option to cust_pkg->cancel?) - my $fuzz = 2 * 60; #2 minutes? too much? (might catch separate unprovision) - # too little? (unprovisioing export delay?) - my($end, $start) = ( $self->get('cancel'), $self->get('cancel') - $fuzz ); - my @h_cust_svc = $self->h_cust_svc( $end, $start ); - my @svc_errors; - foreach my $h_cust_svc (@h_cust_svc) { - my $h_svc_x = $h_cust_svc->h_svc_x( $end, $start ); - #next unless $h_svc_x; #should this happen? - (my $table = $h_svc_x->table) =~ s/^h_//; - require "FS/$table.pm"; - my $class = "FS::$table"; - my $svc_x = $class->new( { - 'pkgnum' => $cust_pkg->pkgnum, - 'svcpart' => $h_cust_svc->svcpart, - map { $_ => $h_svc_x->get($_) } fields($table) - } ); - - # radius_usergroup - if ( $h_svc_x->isa('FS::h_svc_Radius_Mixin') ) { - $svc_x->usergroup( [ $h_svc_x->h_usergroup($end, $start) ] ); - } + foreach my $svc_x ($self->uncancel_svc_x('only_svcnum' => $options{'only_svcnum'})) { + $svc_x->pkgnum($cust_pkg->pkgnum); my $svc_error = $svc_x->insert; + if ( $svc_error ) { if ( $options{svc_fatal} ) { $dbh->rollback if $oldAutoCommit; @@ -1214,23 +1356,7 @@ sub uncancel { } } # svc_fatal } # svc_error - } #foreach $h_cust_svc - - #these are pretty rare, but should handle them - # - dsl_device (mac addresses) - # - phone_device (mac addresses) - # - dsl_note (ikano notes) - # - domain_record (i.e. restore DNS information w/domains) - # - inventory_item(?) (inventory w/un-cancelling service?) - # - nas (svc_broaband nas stuff) - #this stuff is unused in the wild afaik - # - mailinglistmember - # - router.svcnum? - # - svc_domain.parent_svcnum? - # - acct_snarf (ancient mail fetching config) - # - cgp_rule (communigate) - # - cust_svc_option (used by our Tron stuff) - # - acct_rt_transaction (used by our time worked stuff) + } #foreach uncancel_svc_x ## # also move over any services that didn't unprovision at cancellation diff --git a/FS/FS/h_svc_acct.pm b/FS/FS/h_svc_acct.pm index f525f8206..7416054bc 100644 --- a/FS/FS/h_svc_acct.pm +++ b/FS/FS/h_svc_acct.pm @@ -28,6 +28,7 @@ FS::h_svc_acct - Historical account objects sub svc_domain { my $self = shift; + $_[0] ||= $self->history_date; qsearchs( 'h_svc_domain', { 'svcnum' => $self->domsvc }, FS::h_svc_domain->sql_h_searchs(@_), diff --git a/FS/FS/h_svc_forward.pm b/FS/FS/h_svc_forward.pm index 25b203904..c0eeb3fc5 100644 --- a/FS/FS/h_svc_forward.pm +++ b/FS/FS/h_svc_forward.pm @@ -32,6 +32,8 @@ FS::h_svc_forward - Historical mail forwarding alias objects sub srcsvc_acct { my $self = shift; + + $_[0] ||= $self->history_date; my $h_svc_acct = qsearchs( 'h_svc_acct', { 'svcnum' => $self->srcsvc }, @@ -52,6 +54,8 @@ sub srcsvc_acct { sub dstsvc_acct { my $self = shift; + + $_[0] ||= $self->history_date; my $h_svc_acct = qsearchs( 'h_svc_acct', { 'svcnum' => $self->dstsvc }, diff --git a/FS/FS/h_svc_www.pm b/FS/FS/h_svc_www.pm index 2a3b6dca6..20002214b 100644 --- a/FS/FS/h_svc_www.pm +++ b/FS/FS/h_svc_www.pm @@ -33,6 +33,7 @@ sub domain_record { carp 'Called FS::h_svc_www->domain_record on svcnum ' . $self->svcnum if $DEBUG; + $_[0] ||= $self->history_date; my $domain_record = qsearchs( 'h_domain_record', { 'recnum' => $self->recnum }, diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 74ddcd5c7..a86db9c0a 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -738,7 +738,7 @@ sub insert { #welcome email my @welcome_exclude_svcparts = $conf->config('svc_acct_welcome_exclude'); - unless ( grep { $_ eq $self->svcpart } @welcome_exclude_svcparts ) { + unless ($FS::svc_Common::noexport_hack or ( grep { $_ eq $self->svcpart } @welcome_exclude_svcparts )) { my $error = ''; my $msgnum = $conf->config('welcome_msgnum', $agentnum); if ( $msgnum ) { diff --git a/httemplate/misc/cancel_pkg.html b/httemplate/misc/cancel_pkg.html index 0f33f4dfb..d77c47ed6 100755 --- a/httemplate/misc/cancel_pkg.html +++ b/httemplate/misc/cancel_pkg.html @@ -45,12 +45,41 @@ } &> <& /elements/tr-checkbox.html, - 'label' => mt("Uncancel even if a service can't be re-provisioned"), + 'label' => mt("Uncancel even if service reprovisioning fails"), 'field' => 'svc_not_fatal', 'value' => 'Y', &> % $date_init = 1; +% my @uncancel_svcs = sort { $b->{'reprovisionable'} <=> $a->{'reprovisionable'} } +% sort { $a->{'svcpart'} <=> $b->{'svcpart'} } +% $cust_pkg->uncancel_svc_summary(); +% if (@uncancel_svcs) { +<TR><TD COLSPAN="2"> </TD></TR> +<TR><TH ALIGN="right"><% emt("Re-provision the following services") %></TH><TD></TD> +% foreach my $uncancel_svc (@uncancel_svcs) { +% my $uncancel_curr_value = $uncancel_svc->{'uncancel_svcnum'}; +% my $uncancel_disabled = ''; +% my $uncancel_postfix = ''; +% if ($cgi->param('error')) { +% $uncancel_curr_value = '' unless grep { $_ == $uncancel_svc->{'uncancel_svcnum'} } $cgi->param('only_svcnum'); +% } +% unless ($uncancel_svc->{'reprovisionable'}) { +% $uncancel_curr_value = ''; +% $uncancel_disabled = 1; +% $uncancel_postfix = '<I>(' . emt('Cannot be reprovisioned') . ')</I>'; +% } + <& /elements/tr-checkbox.html, + 'label' => $uncancel_svc->{'svc'} . ': ' . $uncancel_svc->{'label'}, + 'field' => 'only_svcnum', + 'value' => $uncancel_svc->{'uncancel_svcnum'}, + 'curr_value' => $uncancel_curr_value, + 'disabled' => $uncancel_disabled, + 'cell_style' => 'font-weight: normal', + 'postfix' => $uncancel_postfix, + &> +% } +% } % } % unless ( $method eq 'resume' || $method eq 'uncancel' ) { diff --git a/httemplate/misc/process/cancel_pkg.html b/httemplate/misc/process/cancel_pkg.html index 6972a49bf..eb3b2efe6 100755 --- a/httemplate/misc/process/cancel_pkg.html +++ b/httemplate/misc/process/cancel_pkg.html @@ -85,6 +85,8 @@ my $bill = my $svc_fatal = ( $cgi->param('svc_not_fatal') ne 'Y' ); +my $only_svcnum = ($method eq 'uncancel') ? [ $cgi->param('only_svcnum') ] : undef; + $error ||= $cust_pkg->$method( 'reason' => $reasonnum, 'date' => $date, 'resume_date' => $resume_date, @@ -92,6 +94,7 @@ $error ||= $cust_pkg->$method( 'reason' => $reasonnum, 'bill' => $bill, 'svc_fatal' => $svc_fatal, 'options' => $options, + 'only_svcnum' => $only_svcnum, ); if ($error) { diff --git a/httemplate/view/cust_main/packages/services.html b/httemplate/view/cust_main/packages/services.html index 39055f49a..a23a4c2fe 100644 --- a/httemplate/view/cust_main/packages/services.html +++ b/httemplate/view/cust_main/packages/services.html @@ -105,9 +105,25 @@ function clearhint_search_cust_svc(obj, str) { </TD> </TR> -% } +% } + +% } #foreach part_svc + +% if ($cust_pkg->get('cancel')) { +% foreach my $svc ( +% $cust_pkg->uncancel_svc_summary('summarize_size' => $opt{'cust_pkg-large_pkg_size'}, 'no_test_reprovision' => 1) +% ) { + <TR> + <TD ALIGN="right" VALIGN="top"><% $svc->{'svc'} |h %></TD> + <TD STYLE="padding-bottom:0px; font-style: italic"> + <% $svc->{'num_cust_svc'} + ? $svc->{'num_cust_svc'} . ' ' . emt('services in history') + : (defined($svc->{'label'}) ? $svc->{'label'} : emt('(cannot load svc label)')) |h %> + </TD> + </TR> +% } +% } -% } </TABLE> </TD> diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html index a6bd0cef4..12608ee2c 100644 --- a/httemplate/view/cust_main/packages/status.html +++ b/httemplate/view/cust_main/packages/status.html @@ -679,6 +679,8 @@ sub pkg_uncancel_link { 'actionlabel' => emt('Un-cancel'), #'color' => #? 'cust_pkg' => shift, + 'width' => 960, + 'height' => 740, ) } |