],
'primary_key' => 'svclinknum',
'unique' => [ ['agentnum','src_svcpart','dst_svcpart','link_type'] ],
- 'index' => [ [ 'src_svcpart' ] ],
+ 'index' => [ [ 'src_svcpart' ], [ 'src_svcpart', 'link_type' ], [ 'disabled' ] ],
'foreign_keys' => [
{ columns => [ 'src_svcpart' ],
table => 'part_svc',
}
}
+ my $error = $self->check_pkg_svc(%options);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
}
if ( $options{'cust_pkg'} ) {
my $hidden_svc = $options->{'hidden_svc'} || {};
my $bulk_skip = $options->{'bulk_skip'} || {};
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} || '';
return $error;
}
} #foreach $part_svc
+
+ my $error = $new->check_pkg_svc(%$options);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
} #if $options->{pkg_svc}
my @part_pkg_vendor = $old->part_pkg_vendor;
'';
}
+=item check_pkg_svc
+
+Checks pkg_svc records as a whole (for part_svc_link dependencies).
+
+If there is an error, returns the error, otherwise returns false.
+
+=cut
+
+sub check_pkg_svc {
+ my( $self, %opt ) = @_;
+
+ my $agentnum = $self->agentnum;
+
+ my %pkg_svc = map { $_->svcpart => $_ } $self->pkg_svc;
+
+ foreach my $svcpart ( keys %pkg_svc ) {
+
+ warn 'checking '. $pkg_svc{$svcpart}->svcpart;
+
+ foreach my $part_svc_link ( $self->part_svc_link(
+ 'src_svcpart' => $svcpart,
+ 'link_type' => 'part_pkg_restrict',
+ )
+ ) {
+
+ use Data::Dumper;
+ warn 'checking '. Dumper($part_svc_link);
+
+ return $part_svc_link->dst_svc. ' must be included with '.
+ $part_svc_link->src_svc
+ unless $pkg_svc{ $part_svc_link->dst_svcpart };
+ }
+
+ }
+
+ return '' if $opt{part_pkg_restrict_soft_override};
+
+ foreach my $svcpart ( keys %pkg_svc ) {
+
+ foreach my $part_svc_link ( $self->part_svc_link(
+ 'src_svcpart' => $svcpart,
+ 'link_type' => 'part_pkg_restrict_soft',
+ )
+ ) {
+ return $part_svc_link->dst_svc. ' is suggested with '.
+ $part_svc_link->src_svc
+ unless $pkg_svc{ $part_svc_link->dst_svcpart };
+ }
+
+ }
+
+ '';
+}
+
+=item part_svc_link OPTION => VALUE ...
+
+Returns the service dependencies (see L<FS::part_svc_link>) for the given
+search options, taking into account this package definition's agent.
+
+Available options are any field in part_svc_link. Typically used options are
+src_svcpart and link_type.
+
+=cut
+
+sub part_svc_link {
+ my( $self, %opt ) = @_;
+
+ my $agentnum = $self->agentnum;
+
+ qsearch({ 'table' => 'part_svc_link',
+ 'hashref' => \%opt,
+ 'extra_sql' =>
+ $agentnum
+ ? "AND ( agentnum IS NULL OR agentnum = $agentnum )"
+ : 'AND agentnum IS NULL',
+ });
+}
+
=item supersede OLD [, OPTION => VALUE ... ]
Inserts this package as a successor to the package OLD. All options are as
# XXX false laziness w/edit/part_svc_link.html
-=item part_svc_restrict
+=item part_pkg_restrict
In package defintions, require the destination service definition when the
source service definition is included
-=item part_svc_restrict_soft
+=item part_pkg_restrict_soft
-Soft order block: in package definitions, warn if the destination service
-definition is included without the source service definition
+Soft order block: in package definitions, suggest the destination service definition when the source service definition is included
=item cust_svc_provision_restrict
# (and hooks each place we have manual checks for the various rules)
# but this will do for now
- $self->link_type eq 'part_svc_restrict'
+ $self->link_type eq 'part_pkg_restrict'
and return "In package definitions, $dst is required when $src is included";
- $self->link_type eq 'part_svc_restrict_soft'
+ $self->link_type eq 'part_pkg_restrict_soft'
and return "In package definitions, $dst is suggested when $src is included";
$self->link_type eq 'cust_svc_provision_restrict'
=cut
-
sub dst_part_svc {
my $self = shift;
qsearchs('part_svc', { svcpart=>$self->dst_svcpart } );
=cut
sub dst_svc {
- shift->src_part_svc->svc;
+ shift->dst_part_svc->svc;
}
=back
'html_init' => '', #after the header/menubar
+ 'form_init' => '', #after html_init, error and the opening <FORM>, but
+ #before any other form contents
+
#string or coderef of additional HTML to add before </TABLE>
'html_table_bottom' => '',
<INPUT TYPE="hidden" NAME="svcdb" VALUE="<% $table %>">
<INPUT TYPE="hidden" NAME="<% $pkey %>" VALUE="<% $clone ? '' : $object->$pkey() %>">
+ <% defined($opt{'form_init'})
+ ? ( ref($opt{'form_init'})
+ ? &{$opt{'form_init'}}()
+ : $opt{'form_init'}
+ )
+ : ''
+ %>
+
% unless ( $opt{'no_pkey_display'} ) {
<FONT SIZE="+1"><B>
'cgiparam'
);
+ if ( $cgi->param('error') =~ / is suggested with / ) {
+ #yeah, detection is a shitty kludge, but we don't have exception objects
+ $opt->{form_init} = '<INPUT TYPE="checkbox" NAME="part_pkg_restrict_soft_override" VALUE="Y"> Override suggestion<BR><BR>';
+ }
+
};
my $new_hashref_callback = sub { { 'plan' => 'flat' }; };
type => 'select',
#XXX false laziness w/part_svc_link POD documentation
options =>[ qw(
- part_svc_restrict part_svc_restrict_soft
+ part_pkg_restrict part_pkg_restrict_soft
cust_svc_provision_restrict cust_svc_unprovision_restrict
cust_svc_unprovision_cascade cust_svc_suspend_cascade
)],
labels => {
- part_svc_restrict => 'In package defintions, prevent including the destination service definition unless the source service definition is also included',
- part_svc_restrict_soft => 'Soft order block: in package definitions, warn if the destination service definition is included without the source service definition',
+ part_pkg_restrict => 'In package defintions, require the destination service definition when the source service definition is included',
+ part_pkg_restrict_soft => 'In package definitions, suggest the destination service definition when the source service definition is included',
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',
push @args, 'part_pkg_vendor' => \%part_pkg_vendor;
}
+ push @args, 'part_pkg_restrict_soft_override' => 1
+ if $cgi->param('part_pkg_restrict_soft_override');
+
#warn "args: ".join('/', @args). "\n";
@args;