'quantity', 'int', '', '', '', '',
'primary_svc','char', 'NULL', 1, '', '',
'hidden', 'char', 'NULL', 1, '', '',
+ 'provision_hold', 'char', 'NULL', 1, '', '',
],
'primary_key' => 'pkgsvcnum',
'unique' => [ ['pkgpart', 'svcpart'] ],
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 ... ]
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
} # 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
);
}
+# 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;
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.
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 =
'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 ) {
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.
+'hidden' field in these records. I<provision_hold> can be set
+to a hashref of svcparts and flag values ('Y' or '') to set the 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.
warn " replacing pkg_svc records" if $DEBUG;
my $pkg_svc = $options->{'pkg_svc'};
my $hidden_svc = $options->{'hidden_svc'} || {};
+ 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 $provision_hold = $provision_hold->{$part_svc->svcpart} || '';
my $primary_svc =
( defined($options->{'primary_svc'}) && $options->{'primary_svc'}
&& $options->{'primary_svc'} == $part_svc->svcpart
my $old_quantity = 0;
my $old_primary_svc = '';
my $old_hidden = '';
+ 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_provision_hold = $old_pkg_svc->provision_hold;
}
next unless $old_quantity != $quantity ||
$old_primary_svc ne $primary_svc ||
- $old_hidden ne $hidden;
+ $old_hidden ne $hidden ||
+ $old_provision_hold ne $provision_hold;
my $new_pkg_svc = new FS::pkg_svc( {
'pkgsvcnum' => ( $old_pkg_svc ? $old_pkg_svc->pkgsvcnum : '' ),
'quantity' => $quantity,
'primary_svc' => $primary_svc,
'hidden' => $hidden,
+ 'provision_hold' => $provision_hold,
} );
my $error = $old_pkg_svc
? $new_pkg_svc->replace($old_pkg_svc)
=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
|| $self->ut_number('svcpart')
|| $self->ut_number('quantity')
|| $self->ut_enum('hidden', [ '', 'Y' ] )
+ || $self->ut_flag('provision_hold')
;
return $error if $error;
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;
- push @args, 'pkg_svc' => \%pkg_svc, 'hidden_svc' => \%hidden_svc;
+ push @args, 'pkg_svc' => \%pkg_svc,
+ 'hidden_svc' => \%hidden_svc,
+ 'provision_hold' => \%provision_hold;
###
# cust_pkg and custnum_ref (inserts only)
% $quan = $pkg_svc->quantity;
% }
%
+% 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 ) {
% push @possible_exports, $export if $export->can('external_pkg_map');
<TD>
<INPUT TYPE="checkbox" NAME="hidden<% $svcpart %>" VALUE="Y"<% $pkg_svc->hidden =~ /^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 ) ) {
'<TH BGCOLOR="#dcdcdc"><FONT SIZE=-2>Primary</FONT></TH>'.
'<TH BGCOLOR="#dcdcdc">Service</TH>'.
'<TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Hide</FONT></TH>'.
+ '<TH BGCOLOR="#dcdcdc"><FONT SIZE=-1>Hold<BR>Until<BR>Provision</FONT></TH>'.
'</TR>';
my $part_pkg = $opt{'object'};