summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FS/FS/Schema.pm1
-rw-r--r--FS/FS/cust_pkg.pm33
-rw-r--r--FS/FS/cust_svc.pm63
-rw-r--r--FS/FS/part_pkg.pm25
-rw-r--r--FS/FS/pkg_svc.pm3
-rwxr-xr-xhttemplate/edit/process/part_pkg.cgi2
-rw-r--r--httemplate/elements/tr-pkg_svc.html11
7 files changed, 116 insertions, 22 deletions
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index c8b9b63..184c6c9 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -3543,6 +3543,7 @@ sub tables_hashref {
'primary_svc', 'char', 'NULL', 1, '', '',
'hidden', 'char', 'NULL', 1, '', '',
'bulk_skip', 'char', 'NULL', 1, '', '',
+ 'provision_hold', 'char', 'NULL', 1, '', '',
],
'primary_key' => 'pkgsvcnum',
'unique' => [ ['pkgpart', 'svcpart'] ],
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index fbecd8d..c5a3d2e 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -3389,28 +3389,33 @@ Returns a list of FS::part_svc objects representing services included in this
package but not yet provisioned. Each FS::part_svc object also has an extra
field, I<num_avail>, which specifies the number of available services.
+Accepts option I<provision_hold>; if true, only returns part_svc for which the
+associated pkg_svc has the provision_hold flag set.
+
=cut
sub available_part_svc {
my $self = shift;
+ my %opt = @_;
my $pkg_quantity = $self->quantity || 1;
grep { $_->num_avail > 0 }
- map {
- my $part_svc = $_->part_svc;
- $part_svc->{'Hash'}{'num_avail'} = #evil encapsulation-breaking
- $pkg_quantity * $_->quantity - $self->num_cust_svc($_->svcpart);
-
- # more evil encapsulation breakage
- if($part_svc->{'Hash'}{'num_avail'} > 0) {
- my @exports = $part_svc->part_export_did;
- $part_svc->{'Hash'}{'can_get_dids'} = scalar(@exports);
- }
-
- $part_svc;
- }
- $self->part_pkg->pkg_svc;
+ map {
+ my $part_svc = $_->part_svc;
+ $part_svc->{'Hash'}{'num_avail'} = #evil encapsulation-breaking
+ $pkg_quantity * $_->quantity - $self->num_cust_svc($_->svcpart);
+
+ # more evil encapsulation breakage
+ if ($part_svc->{'Hash'}{'num_avail'} > 0) {
+ my @exports = $part_svc->part_export_did;
+ $part_svc->{'Hash'}{'can_get_dids'} = scalar(@exports);
+ }
+
+ $part_svc;
+ }
+ grep { $opt{'provision_hold'} ? $_->provision_hold : 1 }
+ $self->part_pkg->pkg_svc;
}
=item part_svc [ OPTION => VALUE ... ]
diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm
index 986c5ae..c5099fc 100644
--- a/FS/FS/cust_svc.pm
+++ b/FS/FS/cust_svc.pm
@@ -102,6 +102,37 @@ sub table { 'cust_svc'; }
Adds this service to the database. If there is an error, returns the error,
otherwise returns false.
+=cut
+
+sub insert {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::insert;
+
+ #check if this releases a hold (see FS::pkg_svc provision_hold)
+ $error ||= $self->_provision_hold;
+
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error if $error
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ ''; #no error
+
+}
+
=item delete
Deletes this service from the database. If there is an error, returns the
@@ -428,6 +459,9 @@ sub replace {
} # if ($svc_x->locationnum)
} # if this is a location change
+ #check if this releases a hold (see FS::pkg_svc provision_hold)
+ $error ||= $new->_provision_hold;
+
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return $error if $error
@@ -1206,6 +1240,35 @@ sub smart_search_param {
);
}
+# If the associated cust_pkg is 'on hold'
+# and the associated pkg_svc has the provision_hold flag
+# and there are no more available_part_svcs on the cust_pkg similarly flagged,
+# then removes hold from pkg
+# returns $error or '' on success,
+# does not indicate if pkg status was changed
+sub _provision_hold {
+ my $self = shift;
+
+ # check status of cust_pkg
+ my $cust_pkg = $self->cust_pkg;
+ return '' unless $cust_pkg->status eq 'on hold';
+
+ # check flag on this svc
+ # small false laziness with $self->pkg_svc
+ # to avoid looking up cust_pkg twice
+ my $pkg_svc = qsearchs( 'pkg_svc', {
+ 'svcpart' => $self->svcpart,
+ 'pkgpart' => $cust_pkg->pkgpart,
+ });
+ return '' unless $pkg_svc->provision_hold;
+
+ # check for any others available with that flag
+ return '' if $cust_pkg->available_part_svc( 'provision_hold' => 1 );
+
+ # conditions met, remove hold
+ return $cust_pkg->unsuspend;
+}
+
sub _upgrade_data {
my $class = shift;
diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm
index 498da8a..97bce45 100644
--- a/FS/FS/part_pkg.pm
+++ b/FS/FS/part_pkg.pm
@@ -183,7 +183,8 @@ I<custnum_ref> and I<options>.
If I<pkg_svc> is set to a hashref with svcparts as keys and quantities as
values, appropriate FS::pkg_svc records will be inserted. I<hidden_svc> can
be set to a hashref of svcparts and flag values ('Y' or '') to set the
-'hidden' field in these records.
+'hidden' field in these records, and I<provision_hold> can be set similarly
+for the 'provision_hold' field in these records.
If I<primary_svc> is set to the svcpart of the primary service, the appropriate
FS::pkg_svc record will be updated.
@@ -293,6 +294,7 @@ sub insert {
warn " inserting pkg_svc records" if $DEBUG;
my $pkg_svc = $options{'pkg_svc'} || {};
my $hidden_svc = $options{'hidden_svc'} || {};
+ my $provision_hold = $options{'provision_hold'} || {};
foreach my $part_svc ( qsearch('part_svc', {} ) ) {
my $quantity = $pkg_svc->{$part_svc->svcpart} || 0;
my $primary_svc =
@@ -306,6 +308,7 @@ sub insert {
'quantity' => $quantity,
'primary_svc' => $primary_svc,
'hidden' => $hidden_svc->{$part_svc->svcpart},
+ 'provision_hold' => $provision_hold->{$part_svc->svcpart},
} );
my $error = $pkg_svc->insert;
if ( $error ) {
@@ -386,15 +389,15 @@ sub delete {
Replaces OLD_RECORD with this one in the database. If there is an error,
returns the error, otherwise returns false.
-Currently available options are: I<pkg_svc>, I<hidden_svc>, I<primary_svc>
-and I<options>
+Currently available options are: I<pkg_svc>, I<hidden_svc>, I<primary_svc>,
+I<bulk_skip>, I<provision_hold> and I<options>
If I<pkg_svc> is set to a hashref with svcparts as keys and quantities as
values, the appropriate FS::pkg_svc records will be replaced. I<hidden_svc>
can be set to a hashref of svcparts and flag values ('Y' or '') to set the
-'hidden' field in these records. I<bulk_skip> can be set to a hashref of
-svcparts and flag values ('Y' or '') to set the 'bulk_skip' field in those
-records.
+'hidden' field in these records. I<bulk_skip> and I<provision_hold> can be set
+to a hashref of svcparts and flag values ('Y' or '') to set the respective field
+in those records.
If I<primary_svc> is set to the svcpart of the primary service, the appropriate
FS::pkg_svc record will be updated.
@@ -532,12 +535,14 @@ sub replace {
my $pkg_svc = $options->{'pkg_svc'};
my $hidden_svc = $options->{'hidden_svc'} || {};
my $bulk_skip = $options->{'bulk_skip'} || {};
+ my $provision_hold = $options->{'provision_hold'} || {};
if ( $pkg_svc ) { # if it wasn't passed, don't change existing pkg_svcs
foreach my $part_svc ( qsearch('part_svc', {} ) ) {
my $quantity = $pkg_svc->{$part_svc->svcpart} || 0;
my $hidden = $hidden_svc->{$part_svc->svcpart} || '';
my $bulk_skip = $bulk_skip->{$part_svc->svcpart} || '';
+ my $provision_hold = $provision_hold->{$part_svc->svcpart} || '';
my $primary_svc =
( defined($options->{'primary_svc'}) && $options->{'primary_svc'}
&& $options->{'primary_svc'} == $part_svc->svcpart
@@ -554,18 +559,21 @@ sub replace {
my $old_primary_svc = '';
my $old_hidden = '';
my $old_bulk_skip = '';
+ my $old_provision_hold = '';
if ( $old_pkg_svc ) {
$old_quantity = $old_pkg_svc->quantity;
$old_primary_svc = $old_pkg_svc->primary_svc
if $old_pkg_svc->dbdef_table->column('primary_svc'); # is this needed?
$old_hidden = $old_pkg_svc->hidden;
- $old_bulk_skip = $old_pkg_svc->old_bulk_skip;
+ $old_bulk_skip = $old_pkg_svc->old_bulk_skip; # should this just be bulk_skip?
+ $old_provision_hold = $old_pkg_svc->provision_hold;
}
next unless $old_quantity != $quantity
|| $old_primary_svc ne $primary_svc
|| $old_hidden ne $hidden
- || $old_bulk_skip ne $bulk_skip;
+ || $old_bulk_skip ne $bulk_skip
+ || $old_provision_hold ne $provision_hold;
my $new_pkg_svc = new FS::pkg_svc( {
'pkgsvcnum' => ( $old_pkg_svc ? $old_pkg_svc->pkgsvcnum : '' ),
@@ -575,6 +583,7 @@ sub replace {
'primary_svc' => $primary_svc,
'hidden' => $hidden,
'bulk_skip' => $bulk_skip,
+ 'provision_hold' => $provision_hold,
} );
my $error = $old_pkg_svc
? $new_pkg_svc->replace($old_pkg_svc)
diff --git a/FS/FS/pkg_svc.pm b/FS/FS/pkg_svc.pm
index 4efffd9..b2dc870 100644
--- a/FS/FS/pkg_svc.pm
+++ b/FS/FS/pkg_svc.pm
@@ -47,6 +47,8 @@ definition includes
=item hidden - 'Y' to hide this service on invoices, null otherwise.
+=item provision_hold - 'Y' to release package hold when all services marked with this are provisioned
+
=back
=head1 METHODS
@@ -107,6 +109,7 @@ sub check {
|| $self->ut_number('svcpart')
|| $self->ut_number('quantity')
|| $self->ut_enum('hidden', [ '', 'Y' ] )
+ || $self->ut_flag('provision_hold')
;
return $error if $error;
diff --git a/httemplate/edit/process/part_pkg.cgi b/httemplate/edit/process/part_pkg.cgi
index 61a6337..b804202 100755
--- a/httemplate/edit/process/part_pkg.cgi
+++ b/httemplate/edit/process/part_pkg.cgi
@@ -160,6 +160,7 @@ my $args_callback = sub {
my @svcparts = map { $_->svcpart } qsearch('part_svc', {});
my %pkg_svc = map { $_ => scalar($cgi->param("pkg_svc$_" )) } @svcparts;
my %hidden_svc = map { $_ => scalar($cgi->param("hidden$_" )) } @svcparts;
+ my %provision_hold = map { $_ => scalar($cgi->param("provision_hold$_" )) } @svcparts;
my %bulk_skip = map { $_ => ( $cgi->param("no_bulk_skip$_") eq 'Y'
? '' : 'Y'
)
@@ -167,6 +168,7 @@ my $args_callback = sub {
push @args, 'pkg_svc' => \%pkg_svc,
'hidden_svc' => \%hidden_svc,
+ 'provision_hold' => \%provision_hold,
'bulk_skip' => \%bulk_skip;
###
diff --git a/httemplate/elements/tr-pkg_svc.html b/httemplate/elements/tr-pkg_svc.html
index a44c5b9..cfef51c 100644
--- a/httemplate/elements/tr-pkg_svc.html
+++ b/httemplate/elements/tr-pkg_svc.html
@@ -45,6 +45,12 @@
% } else {
% $bulk_skip = $pkg_svc->bulk_skip;
% }
+% my $provision_hold = '';
+% if ( grep { $_ eq "provision_hold$svcpart" } $cgi->param ) {
+% $provision_hold = $cgi->param("hidden_svc$svcpart");
+% } else {
+% $provision_hold = $pkg_svc->provision_hold;
+% }
%
% my @exports = $pkg_svc->part_svc->part_export;
% foreach my $export ( @exports ) {
@@ -72,6 +78,10 @@
<INPUT TYPE="checkbox" NAME="no_bulk_skip<% $svcpart %>" VALUE="Y"<% $bulk_skip =~ /^Y/i ? '' : ' CHECKED' %>>
</TD>
+ <TD ALIGN="center">
+ <INPUT TYPE="checkbox" NAME="provision_hold<% $svcpart %>" VALUE="Y"<% $provision_hold =~ /^Y/i ? ' CHECKED' : ''%>>
+ </TD>
+
</TR>
% foreach ( 1 .. $columns-1 ) {
% if ( $count == int( $_ * scalar(@part_svc) / $columns ) ) {
@@ -127,6 +137,7 @@ my $thead = "\n\n". ntable('#cccccc', 2).
'<TH BGCOLOR="#dcdcdc">Service</TH>'.
'<TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Hide<BR>from<BR>Invoices</FONT></TH>'.
'<TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Bulk<BR>Charge</FONT></TH>'.
+ '<TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Hold<BR>Until<BR>Provision</FONT></TH>'.
'</TR>';
my $part_pkg = $opt{'object'};