summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Prykop <jonathan@freeside.biz>2015-04-24 22:19:34 -0500
committerJonathan Prykop <jonathan@freeside.biz>2015-04-24 22:19:34 -0500
commit4fda726fa9f8e709c68ec823edc5ae702723281c (patch)
tree1436b287dc8467b16aa2f11c6cdc62f36e2fae82
parent326075e45814387624303357207eae9069301f58 (diff)
RT#34289: Flag service fields as mandatory
-rw-r--r--FS/FS/Schema.pm1
-rw-r--r--FS/FS/part_svc.pm16
-rw-r--r--FS/FS/part_svc_column.pm3
-rw-r--r--FS/FS/svc_Common.pm37
-rw-r--r--FS/FS/svc_acct.pm6
-rw-r--r--FS/FS/svc_domain.pm5
-rwxr-xr-xhttemplate/browse/part_svc.cgi13
-rw-r--r--httemplate/edit/elements/part_svc_column.html15
-rwxr-xr-xhttemplate/edit/part_svc.cgi20
9 files changed, 106 insertions, 10 deletions
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 7f28e11f7..42122f700 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -3595,6 +3595,7 @@ sub tables_hashref {
'columnlabel', 'varchar', 'NULL', $char_d, '', '',
'columnvalue', 'varchar', 'NULL', 512, '', '',
'columnflag', 'char', 'NULL', 1, '', '',
+ 'required', 'char', 'NULL', 1, '', '',
],
'primary_key' => 'columnnum',
'unique' => [ [ 'svcpart', 'columnname' ] ],
diff --git a/FS/FS/part_svc.pm b/FS/FS/part_svc.pm
index f56878acf..1da30cbb4 100644
--- a/FS/FS/part_svc.pm
+++ b/FS/FS/part_svc.pm
@@ -95,8 +95,12 @@ the part_svc_column table appropriately (see L<FS::part_svc_column>).
=item I<svcdb>__I<field> - Default or fixed value for I<field> in I<svcdb>.
+=item I<svcdb>__I<field>_label
+
=item I<svcdb>__I<field>_flag - defines I<svcdb>__I<field> action: null or empty (no default), `D' for default, `F' for fixed (unchangeable), , `S' for selectable choice, `M' for manual selection from inventory, or `A' for automatic selection from inventory. For virtual fields, can also be 'X' for excluded.
+=item I<svcdb>__I<field>_required - I<field> should always have a true value
+
=back
If you want to add part_svc_column records for fields that do not exist as
@@ -145,6 +149,7 @@ sub insert {
foreach my $field (
grep { $_ ne 'svcnum'
&& ( defined( $self->getfield($svcdb.'__'.$_.'_flag') )
+ || defined($self->getfield($svcdb.'__'.$_.'_required'))
|| $self->getfield($svcdb.'__'.$_.'_label') !~ /^\s*$/ )
} (fields($svcdb), @fields)
) {
@@ -156,6 +161,7 @@ sub insert {
my $flag = $self->getfield($svcdb.'__'.$field.'_flag');
my $label = $self->getfield($svcdb.'__'.$field.'_label');
+ my $required = $self->getfield($svcdb.'__'.$field.'_required') ? 'Y' : '';
if ( uc($flag) =~ /^([A-Z])$/ || $label !~ /^\s*$/ ) {
if ( uc($flag) =~ /^([A-Z])$/ ) {
@@ -170,6 +176,8 @@ sub insert {
$part_svc_column->setfield('columnlabel', $label)
if $label !~ /^\s*$/;
+ $part_svc_column->setfield('required', $required);
+
if ( $previous ) {
$error = $part_svc_column->replace($previous);
} else {
@@ -279,6 +287,7 @@ sub replace {
foreach my $field (
grep { $_ ne 'svcnum'
&& ( defined( $new->getfield($svcdb.'__'.$_.'_flag') )
+ || defined($new->getfield($svcdb.'__'.$_.'_required'))
|| $new->getfield($svcdb.'__'.$_.'_label') !~ /^\s*$/ )
} (fields($svcdb),@fields)
) {
@@ -291,6 +300,7 @@ sub replace {
my $flag = $new->getfield($svcdb.'__'.$field.'_flag');
my $label = $new->getfield($svcdb.'__'.$field.'_label');
+ my $required = $new->getfield($svcdb.'__'.$field.'_required') ? 'Y' : '';
if ( uc($flag) =~ /^([A-Z])$/ || $label !~ /^\s*$/ ) {
@@ -309,6 +319,8 @@ sub replace {
$part_svc_column->setfield('columnlabel', $label)
if $label !~ /^\s*$/;
+ $part_svc_column->setfield('required', $required);
+
if ( $previous ) {
$error = $part_svc_column->replace($previous);
} else {
@@ -699,6 +711,8 @@ some components specified by "select-.*.html", and a bunch more...
=item select_allow_empty - Used with select_table, adds an empty option
+=item required - This field should always have a true value (do not use with type checkbox or disabled)
+
=back
=cut
@@ -773,7 +787,7 @@ sub process {
and ref($param->{ $f }) ) {
$param->{ $f } = join(',', @{ $param->{ $f } });
}
- ( $f, $f.'_flag', $f.'_label' );
+ ( $f, $f.'_flag', $f.'_label', $f.'_required' );
}
@fields;
diff --git a/FS/FS/part_svc_column.pm b/FS/FS/part_svc_column.pm
index 38ce1fa80..75a2dfb1a 100644
--- a/FS/FS/part_svc_column.pm
+++ b/FS/FS/part_svc_column.pm
@@ -45,6 +45,8 @@ fields are currently supported:
=item columnflag - null or empty (no default), `D' for default, `F' for fixed (unchangeable), `S' for selectable choice, `M' for manual selection from inventory, `A' for automatic selection from inventory, or `H' for selection from a hardware class. For virtual fields, can also be 'X' for excluded.
+=item required - column value expected to be true
+
=back
=head1 METHODS
@@ -91,6 +93,7 @@ sub check {
|| $self->ut_alpha('columnname')
|| $self->ut_textn('columnlabel')
|| $self->ut_anything('columnvalue')
+ || $self->ut_flag('required')
;
return $error if $error;
diff --git a/FS/FS/svc_Common.pm b/FS/FS/svc_Common.pm
index 8199ba183..b1f9d146f 100644
--- a/FS/FS/svc_Common.pm
+++ b/FS/FS/svc_Common.pm
@@ -152,13 +152,46 @@ sub cust_linked {
Checks the validity of fields in this record.
-At present, this does nothing but call FS::Record::check (which, in turn,
-does nothing but run virtual field checks).
+Only checks fields marked as required in table_info or
+part_svc_column definition. Should be invoked by service-specific
+check using SUPER. Invokes FS::Record::check using SUPER.
=cut
sub check {
my $self = shift;
+
+ ## Checking required fields
+
+ # get fields marked as required in table_info
+ my $required = {};
+ my $labels = {};
+ my $tinfo = $self->can('table_info') ? $self->table_info : {};
+ my $fields = $tinfo->{'fields'} || {};
+ foreach my $field (keys %$fields) {
+ if (ref($fields->{$field}) && $fields->{$field}->{'required'}) {
+ $required->{$field} = 1;
+ $labels->{$field} = $fields->{$field}->{'label'};
+ }
+ }
+ # add fields marked as required in database
+ foreach my $column (
+ qsearch('part_svc_column',{
+ 'svcpart' => $self->svcpart,
+ 'required' => 'Y'
+ })
+ ) {
+ $required->{$column->columnname} = 1;
+ $labels->{$column->columnname} = $column->columnlabel;
+ }
+ # do the actual checking
+ foreach my $field (keys %$required) {
+ unless ($self->$field) {
+ my $name = $labels->{$field} || $field;
+ return "Field $name is required\n"
+ }
+ }
+
$self->SUPER::check;
}
diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm
index 452f250d8..790ac3468 100644
--- a/FS/FS/svc_acct.pm
+++ b/FS/FS/svc_acct.pm
@@ -283,6 +283,7 @@ sub table_info {
disable_default => 1,
disable_fixed => 1,
disable_select => 1,
+ required => 1,
},
'password_selfchange' => { label => 'Password modification',
type => 'checkbox',
@@ -310,7 +311,9 @@ sub table_info {
type => 'text',
disable_inventory => 1,
},
- '_password' => 'Password',
+ '_password' => { label => 'Password',
+ required => 1
+ },
'gid' => {
label => 'GID',
def_info => 'when blank, defaults to UID',
@@ -333,6 +336,7 @@ sub table_info {
select_key => 'svcnum',
select_label => 'domain',
disable_inventory => 1,
+ required => 1,
},
'pbxsvc' => { label => 'PBX',
type => 'select-svc_pbx.html',
diff --git a/FS/FS/svc_domain.pm b/FS/FS/svc_domain.pm
index b01d67310..78556cf8b 100644
--- a/FS/FS/svc_domain.pm
+++ b/FS/FS/svc_domain.pm
@@ -134,7 +134,10 @@ sub table_info {
'display_weight' => 20,
'cancel_weight' => 60,
'fields' => {
- 'domain' => 'Domain',
+ 'domain' => {
+ label => 'Domain',
+ required => 1,
+ },
'parent_svcnum' => {
label => 'Parent domain / Communigate administrator domain',
type => 'select',
diff --git a/httemplate/browse/part_svc.cgi b/httemplate/browse/part_svc.cgi
index 0d3685355..ec5f321dd 100755
--- a/httemplate/browse/part_svc.cgi
+++ b/httemplate/browse/part_svc.cgi
@@ -61,6 +61,8 @@ function part_export_areyousure(href) {
<TH COLSPAN=2 CLASS="grid" BGCOLOR="#cccccc">Modifier</TH>
+ <TH CLASS="grid" BGCOLOR="#cccccc" STYLE="font-size: smaller;">Required</TH>
+
</TR>
% my $conf = FS::Conf->new;
% foreach my $part_svc ( @part_svc ) {
@@ -78,6 +80,9 @@ function part_export_areyousure(href) {
% $col->columnflag || ( $col->columnlabel !~ /^\S*$/
% && $col->columnlabel ne $def->{'label'}
% )
+% || ( $col->required
+% && !$def->{'required'}
+% )
% )
% }
% @dfields ;
@@ -150,7 +155,7 @@ function part_export_areyousure(href) {
</TD>
% unless ( @fields ) {
-% for ( 1..4 ) {
+% for ( 1..5 ) {
<TD CLASS="grid" BGCOLOR="<% $bgcolor %>"</TD>
% }
% }
@@ -170,7 +175,6 @@ function part_export_areyousure(href) {
<TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $field %></TD>
<TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $label %></TD>
<TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $flag{$flag} %></TD>
-
<TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
% my $value = &$formatter($part_svc->part_svc_column($field)->columnvalue);
% if ( $flag =~ /^[MAH]$/ ) {
@@ -189,6 +193,11 @@ function part_export_areyousure(href) {
% }
</TD>
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+% if ($part_svc_column->required) {
+ Yes
+% }
+ </TD>
% $n1="</TR><TR>";
% } #foreach $field
% if ( $part_svc->restrict_edit_password ) {
diff --git a/httemplate/edit/elements/part_svc_column.html b/httemplate/edit/elements/part_svc_column.html
index 2bb4f5e41..a6ccaf867 100644
--- a/httemplate/edit/elements/part_svc_column.html
+++ b/httemplate/edit/elements/part_svc_column.html
@@ -77,6 +77,7 @@ that field.
<TH BGCOLOR="#cccccc">Field</TH>
<TH BGCOLOR="#cccccc">Label</TH>
<TH BGCOLOR="#cccccc" COLSPAN=2>Modifier</TH>
+ <TH BGCOLOR="#cccccc">Required?</TH>
</TR>
% $part_svc->set('svcpart' => $opt{'clone'}) if $opt{'clone'}; # for now
% my $i = 0;
@@ -210,9 +211,17 @@ that field.
&>
% }
</TD>
+ <TD>
+% if (!$def->{'type'} || !(grep {$_ eq $def->{'type'}} ('checkbox','disabled'))) {
+ <INPUT ID="<% $name.'_required' %>" TYPE="checkbox" NAME="<% $svcdb %>__<% $field %>_required" VALUE="Y"
+ <% ($part_svc_column->required || $def->{'required'}) ? 'CHECKED' : '' %>
+ <% $def->{'required'} ? 'DISABLED' : '' %>
+ >
+% }
+ </TD>
</TR>
<TR CLASS="row<%$i%>">
- <TD COLSPAN=2 CLASS="def_info">
+ <TD COLSPAN=3 CLASS="def_info">
% if ( $def->{def_info} ) {
(<% $def->{def_info} %>)
</TD>
@@ -228,7 +237,7 @@ that field.
<TD COLSPAN=3 ALIGN="right">
<% emt('Require "Provision" access right to edit password') %>
</TD>
- <TD>
+ <TD COLSPAN=2>
<INPUT TYPE="checkbox" NAME="restrict_edit_password" VALUE="Y" \
<% $part_svc->restrict_edit_password ? 'CHECKED' : '' %>>
</TD>
@@ -244,7 +253,7 @@ that field.
<TD COLSPAN=3 ALIGN="right">
<% emt('This service has an attached router') %>
</TD>
- <TD>
+ <TD COLSPAN=2>
<INPUT TYPE="checkbox" NAME="has_router" VALUE="Y" \
<% $part_svc->has_router ? 'CHECKED' : '' %>>
</TD>
diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi
index 47b020c5a..7a47f1550 100755
--- a/httemplate/edit/part_svc.cgi
+++ b/httemplate/edit/part_svc.cgi
@@ -101,6 +101,15 @@ function flag_changed(obj) {
}
}
}
+ var required = document.getElementById(layer + '__' + field + '_required');
+ if (required && !required.disabledinit) {
+ if (newflag == "F") {
+ required.checked = false;
+ required.disabled = true;
+ } else {
+ required.disabled = false;
+ }
+ }
}
window.onload = function() {
@@ -111,6 +120,17 @@ window.onload = function() {
obj.setAttribute('should_be_multiple', true);
}
}
+ var inputs = document.getElementsByTagName('INPUT');
+ for(i = 0; i < inputs.length; i++) {
+ var obj = inputs[i];
+ if (obj.type == 'checkbox') {
+ if ( obj.name.match(/_required$/) ) {
+ if ( obj.disabled ) {
+ obj.disabledinit = 1;
+ }
+ }
+ }
+ }
for(i = 0; i < selects.length; i++) {
var obj = selects[i];
if ( obj.name.match(/_flag$/) ) {