From: Jonathan Prykop Date: Tue, 5 May 2015 20:49:51 +0000 (-0500) Subject: RT#34289: Flag service fields as mandatory X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=fb7f3203c7d839ae3964d5e2cac71892422a10d1 RT#34289: Flag service fields as mandatory --- diff --git a/FS/FS/part_svc.pm b/FS/FS/part_svc.pm index abeb28bd2..beea3f1bc 100644 --- a/FS/FS/part_svc.pm +++ b/FS/FS/part_svc.pm @@ -143,56 +143,53 @@ sub insert { # add part_svc_column records my $svcdb = $self->svcdb; -# my @rows = map { /^${svcdb}__(.*)$/; $1 } -# grep ! /_flag$/, -# grep /^${svcdb}__/, -# fields('part_svc'); - foreach my $field ( - grep { $_ ne 'svcnum' - && ( defined( $self->getfield($svcdb.'__'.$_.'_flag') ) - || defined($self->getfield($svcdb.'__'.$_.'_required')) - || $self->getfield($svcdb.'__'.$_.'_label') !~ /^\s*$/ ) - } (fields($svcdb), @fields) - ) { - my $part_svc_column = $self->part_svc_column($field); - my $previous = qsearchs('part_svc_column', { - 'svcpart' => $self->svcpart, - 'columnname' => $field, - } ); + foreach my $field (fields($svcdb), @fields) { + next if $field eq 'svcnum'; + my $prefix = $svcdb.'__'; + if ( defined( $self->getfield($prefix.$_.'_flag')) + or defined($self->getfield($prefix.$_.'_required')) + or length($self->getfield($prefix.$_.'_label')) + ) { + my $part_svc_column = $self->part_svc_column($field); + my $previous = qsearchs('part_svc_column', { + 'svcpart' => $self->svcpart, + 'columnname' => $field, + } ); - 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])$/ ) { - my $parser = FS::part_svc->svc_table_fields($svcdb)->{$field}->{parse} - || sub { shift }; - $part_svc_column->setfield('columnflag', $1); - $part_svc_column->setfield('columnvalue', - &$parser($self->getfield($svcdb.'__'.$field)) - ); - } + my $flag = $self->getfield($prefix.$field.'_flag'); + my $label = $self->getfield($prefix.$field.'_label'); + my $required = $self->getfield($prefix.$field.'_required') ? 'Y' : ''; + if ( uc($flag) =~ /^([A-Z])$/ || $label !~ /^\s*$/ ) { - $part_svc_column->setfield('columnlabel', $label) - if $label !~ /^\s*$/; + if ( uc($flag) =~ /^([A-Z])$/ ) { + my $parser = FS::part_svc->svc_table_fields($svcdb)->{$field}->{parse} + || sub { shift }; + $part_svc_column->setfield('columnflag', $1); + $part_svc_column->setfield('columnvalue', + &$parser($self->getfield($prefix.$field)) + ); + } + + $part_svc_column->setfield('columnlabel', $label) + if $label !~ /^\s*$/; - $part_svc_column->setfield('required', $required); + $part_svc_column->setfield('required', $required); + + if ( $previous ) { + $error = $part_svc_column->replace($previous); + } else { + $error = $part_svc_column->insert; + } - if ( $previous ) { - $error = $part_svc_column->replace($previous); } else { - $error = $part_svc_column->insert; + $error = $previous ? $previous->delete : ''; + } + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; } - } else { - $error = $previous ? $previous->delete : ''; - } - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return $error; } - } # add export_svc records @@ -285,54 +282,54 @@ sub replace { # maintain part_svc_column records my $svcdb = $new->svcdb; - foreach my $field ( - grep { $_ ne 'svcnum' - && ( defined( $new->getfield($svcdb.'__'.$_.'_flag') ) - || defined($new->getfield($svcdb.'__'.$_.'_required')) - || $new->getfield($svcdb.'__'.$_.'_label') !~ /^\s*$/ ) - } (fields($svcdb),@fields) - ) { - - my $part_svc_column = $new->part_svc_column($field); - my $previous = qsearchs('part_svc_column', { - 'svcpart' => $new->svcpart, - 'columnname' => $field, - } ); - - my $flag = $new->getfield($svcdb.'__'.$field.'_flag'); - my $label = $new->getfield($svcdb.'__'.$field.'_label'); - my $required = $new->getfield($svcdb.'__'.$field.'_required') ? 'Y' : ''; + foreach my $field (fields($svcdb),@fields) { + next if $field eq 'svcnum'; + my $prefix = $svcdb.'__'; + if ( defined( $new->getfield($prefix.$_.'_flag')) + or defined($new->getfield($prefix.$_.'_required')) + or length($new->getfield($prefix.$_.'_label')) + ) { + my $part_svc_column = $new->part_svc_column($field); + my $previous = qsearchs('part_svc_column', { + 'svcpart' => $new->svcpart, + 'columnname' => $field, + } ); + + 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*$/ ) { - - if ( uc($flag) =~ /^([A-Z])$/ ) { - $part_svc_column->setfield('columnflag', $1); - my $parser = FS::part_svc->svc_table_fields($svcdb)->{$field}->{parse} - || sub { shift }; - $part_svc_column->setfield('columnvalue', - &$parser($new->getfield($svcdb.'__'.$field)) - ); - } else { - $part_svc_column->setfield('columnflag', ''); - $part_svc_column->setfield('columnvalue', ''); - } + if ( uc($flag) =~ /^([A-Z])$/ || $label !~ /^\s*$/ ) { + + if ( uc($flag) =~ /^([A-Z])$/ ) { + $part_svc_column->setfield('columnflag', $1); + my $parser = FS::part_svc->svc_table_fields($svcdb)->{$field}->{parse} + || sub { shift }; + $part_svc_column->setfield('columnvalue', + &$parser($new->getfield($svcdb.'__'.$field)) + ); + } else { + $part_svc_column->setfield('columnflag', ''); + $part_svc_column->setfield('columnvalue', ''); + } - $part_svc_column->setfield('columnlabel', $label) - if $label !~ /^\s*$/; + $part_svc_column->setfield('columnlabel', $label) + if $label !~ /^\s*$/; - $part_svc_column->setfield('required', $required); + $part_svc_column->setfield('required', $required); - if ( $previous ) { - $error = $part_svc_column->replace($previous); + if ( $previous ) { + $error = $part_svc_column->replace($previous); + } else { + $error = $part_svc_column->insert; + } } else { - $error = $part_svc_column->insert; + $error = $previous ? $previous->delete : ''; + } + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; } - } else { - $error = $previous ? $previous->delete : ''; - } - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return $error; } } @@ -606,6 +603,7 @@ sub svc_x { =cut my $svc_defs; +my $svc_info; sub _svc_defs { return $svc_defs if $svc_defs; #cache @@ -660,7 +658,14 @@ sub _svc_defs { sort { $info{$a}->{'display_weight'} <=> $info{$b}->{'display_weight'} } keys %info, ; - + + tie my %svc_info, 'Tie::IxHash', + map { $_ => $info{$_} } + sort { $info{$a}->{'display_weight'} <=> $info{$b}->{'display_weight'} } + keys %info, + ; + + $svc_info = \%svc_info; #access via svc_table_info $svc_defs = \%svc_defs; #cache } @@ -736,6 +741,27 @@ sub svc_table_fields { $def; } +=item svc_table_info TABLE + +Returns table_info for TABLE from cache, or empty +hashref if none is found. + +Caution: caches table_info for ALL services when run; +access a service's table_info directly unless you know +you're loading them all. + +Caution: does not standardize fields into hashrefs; +use L to access fields. + +=cut + +sub svc_table_info { + my $class = shift; + my $table = shift; + $class->_svc_defs; #creates cache if needed + return $svc_info->{$table} || {}; +} + =back =head1 SUBROUTINES diff --git a/FS/FS/svc_Common.pm b/FS/FS/svc_Common.pm index 34ae2195e..9853d5b74 100644 --- a/FS/FS/svc_Common.pm +++ b/FS/FS/svc_Common.pm @@ -170,28 +170,30 @@ sub check { 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'}; + if ($tinfo->{'manual_require'}) { + 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" + # 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 (length($self->get($field)) > 0) { + my $name = $labels->{$field} || $field; + return "Field $name is required\n" + } } } diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index ffcadc9cb..9636b3ed1 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -261,6 +261,7 @@ sub table_info { 'display_weight' => 10, 'cancel_weight' => 50, 'ip_field' => 'slipip', + 'manual_require' => 1, 'fields' => { 'dir' => 'Home directory', 'uid' => { diff --git a/FS/FS/svc_broadband.pm b/FS/FS/svc_broadband.pm index 40f2c9b2d..2cdc284d7 100755 --- a/FS/FS/svc_broadband.pm +++ b/FS/FS/svc_broadband.pm @@ -103,6 +103,7 @@ sub table_info { 'display_weight' => 50, 'cancel_weight' => 70, 'ip_field' => 'ip_addr', + 'manual_require' => 1, 'fields' => { 'svcnum' => 'Service', 'description' => 'Descriptive label', diff --git a/FS/FS/svc_dish.pm b/FS/FS/svc_dish.pm index 5c9e21710..2d249d17f 100644 --- a/FS/FS/svc_dish.pm +++ b/FS/FS/svc_dish.pm @@ -63,9 +63,10 @@ sub table_info { 'name' => 'Dish service', 'display_weight' => 58, 'cancel_weight' => 85, + 'manual_require' => 1, 'fields' => { 'svcnum' => { label => 'Service' }, - 'acctnum' => { label => 'DISH account#', %opts }, + 'acctnum' => { label => 'DISH account#', required => 1, %opts }, 'installdate' => { label => 'Install date', %opts }, 'note' => { label => 'Installation notes', %opts }, } diff --git a/FS/FS/svc_domain.pm b/FS/FS/svc_domain.pm index 78556cf8b..b01d67310 100644 --- a/FS/FS/svc_domain.pm +++ b/FS/FS/svc_domain.pm @@ -134,10 +134,7 @@ sub table_info { 'display_weight' => 20, 'cancel_weight' => 60, 'fields' => { - 'domain' => { - label => 'Domain', - required => 1, - }, + 'domain' => 'Domain', 'parent_svcnum' => { label => 'Parent domain / Communigate administrator domain', type => 'select', diff --git a/FS/FS/svc_hardware.pm b/FS/FS/svc_hardware.pm index d9c3c464e..2be8954c8 100644 --- a/FS/FS/svc_hardware.pm +++ b/FS/FS/svc_hardware.pm @@ -76,6 +76,7 @@ sub table_info { 'name_plural' => 'Hardware', 'display_weight' => 59, 'cancel_weight' => 86, + 'manual_require' => 1, 'fields' => { 'svcnum' => { label => 'Service' }, 'typenum' => { label => 'Device type', @@ -84,6 +85,7 @@ sub table_info { disable_fixed => 1, disable_default => 1, disable_inventory => 1, + required => 1, }, 'serial' => { label => 'Serial number', %opts }, 'hw_addr' => { label => 'Hardware address', %opts }, diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html index c80cdae19..c9eceb459 100644 --- a/httemplate/edit/elements/edit.html +++ b/httemplate/edit/elements/edit.html @@ -395,6 +395,7 @@ Example: % 'value' => $opt{curr_value}, % 'label' => $label, % 'noinit' => $f->{noinit}, +% 'required' => $f->{'required'}, % } % ); % } diff --git a/httemplate/edit/elements/part_svc_column.html b/httemplate/edit/elements/part_svc_column.html index a6ccaf867..d9500320a 100644 --- a/httemplate/edit/elements/part_svc_column.html +++ b/httemplate/edit/elements/part_svc_column.html @@ -77,7 +77,7 @@ that field. Field Label Modifier - Required? + <% $manual_require ? 'Required?' : '' %> % $part_svc->set('svcpart' => $opt{'clone'}) if $opt{'clone'}; # for now % my $i = 0; @@ -212,7 +212,9 @@ that field. % } -% if (!$def->{'type'} || !(grep {$_ eq $def->{'type'}} ('checkbox','disabled'))) { +% if ($manual_require && +% (!$def->{'type'} || !(grep {$_ eq $def->{'type'}} ('checkbox','disabled'))) +% ) { required || $def->{'required'}) ? 'CHECKED' : '' %> <% $def->{'required'} ? 'DISABLED' : '' %> @@ -310,4 +312,5 @@ if ( $svcdb eq 'svc_acct' } my @defs = map { FS::part_svc->svc_table_fields($svcdb)->{$_} } @fields; +my $manual_require = FS::part_svc->svc_table_info($svcdb)->{'manual_require'}; diff --git a/httemplate/edit/elements/svc_Common.html b/httemplate/edit/elements/svc_Common.html index 97b630f76..a4e345e40 100644 --- a/httemplate/edit/elements/svc_Common.html +++ b/httemplate/edit/elements/svc_Common.html @@ -102,6 +102,9 @@ my $columndef = $part_svc->part_svc_column($f->{'field'}); my $flag = $columndef->columnflag; + $f->{'required'} = 1 + if $columndef->required; + if ( $flag eq 'F' ) { #fixed $f->{'value'} = $columndef->columnvalue; if (length($columndef->columnvalue)) { diff --git a/httemplate/edit/svc_acct.cgi b/httemplate/edit/svc_acct.cgi index 90f48237f..a5e778981 100755 --- a/httemplate/edit/svc_acct.cgi +++ b/httemplate/edit/svc_acct.cgi @@ -30,8 +30,9 @@ <% $part_svc->svc %> - - <% mt('Username') |h %> +<% include('/elements/tr-td-label.html', + 'label' => mt('Username'), + 'required' => $part_svc->part_svc_column('username')->required ) %> % if ( $svcnum && $conf->exists('svc_acct-no_edit_username') ) { <% $svc_acct->username() %> @@ -43,9 +44,10 @@ %if ( $part_svc->part_svc_column('_password')->columnflag ne 'F' ) { - % #XXX eventually should require "Edit Password" ACL - <% mt('Password') |h %> +<% include('/elements/tr-td-label.html', + 'label' => mt('Password'), + 'required' => $part_svc->part_svc_column('_password')->required ) %> MAXLENGTH=<% $pmax %>> <& /elements/random_pass.html, 'clear_password' &> @@ -60,8 +62,9 @@ %if ( $conf->exists('security_phrase') % && $part_svc->part_svc_column('sec_phrase')->columnflag ne 'F' ) { - - <% mt('Security phrase') |h %> +<% include('/elements/tr-td-label.html', + 'label' => mt('Security phrase'), + 'required' => $part_svc->part_svc_column('sec_phrase')->required ) %> (<% mt('for forgotten passwords') |h %>) @@ -97,8 +100,9 @@ % ) % ); - - <% mt('Domain') |h %> +<% include('/elements/tr-td-label.html', + 'label' => mt('Domain'), + 'required' => $part_svc->part_svc_column('domsvc')->required ) %> % } else { - - <% mt('Access number') |h %> +<% include('/elements/tr-td-label.html', + 'label' => mt('Access number'), + 'required' => $part_svc->part_svc_column('popnum')->required ) %> <% FS::svc_acct_pop::popselector($popnum) %> % } @@ -156,6 +161,7 @@ 'curr_value' => $svc_acct->sectornum, #'part_svc' => $part_svc, #'cust_pkg' => $cust_pkg, + 'required' => $part_svc->part_svc_column('sectornum')->required, &> %} else { @@ -176,6 +182,9 @@ % % if ( length($svc_acct->$xid()) ) { +<% include('/elements/tr-td-label.html', + 'label' => uc($xid), + 'required' => $part_svc->part_svc_column($xid)->required ) %> <% uc($xid) %> <% $svc_acct->$xid() %> @@ -187,8 +196,9 @@ % } else { - - <% uc($xid) %> +<% include('/elements/tr-td-label.html', + 'label' => uc($xid), + 'required' => $part_svc->part_svc_column($xid)->required ) %> @@ -205,8 +215,9 @@ % } else { - - <% mt('Real Name') |h %> +<% include('/elements/tr-td-label.html', + 'label' => mt('Real Name'), + 'required' => $part_svc->part_svc_column('finger')->required ) %> @@ -223,8 +234,9 @@ % } else { - - <% mt('Home directory') |h %> +<% include('/elements/tr-td-label.html', + 'label' => mt('Home directory'), + 'required' => $part_svc->part_svc_column('dir')->required ) %> % } @@ -240,8 +252,9 @@ % } else { - - <% mt('Shell') |h %> +<% include('/elements/tr-td-label.html', + 'label' => mt('Shell'), + 'required' => $part_svc->part_svc_column('shell')->required ) %> % } else { - - <% mt('IP') |h %> +<% include('/elements/tr-td-label.html', + 'label' => mt('IP'), + 'required' => $part_svc->part_svc_column('slipip')->required ) %> % } @@ -324,8 +340,9 @@ % } - - <% mt('RADIUS groups') |h %> +<% include('/elements/tr-td-label.html', + 'label' => mt('RADIUS groups'), + 'required' => $part_svc->part_svc_column('usergroup')->required ) %> % if ( $part_svc_usergroup->columnflag eq 'F' ) { <% join('
', @groupnames) %> % } else { diff --git a/httemplate/edit/svc_acct/communigate.html b/httemplate/edit/svc_acct/communigate.html index 6370a54dc..370bfb0e7 100644 --- a/httemplate/edit/svc_acct/communigate.html +++ b/httemplate/edit/svc_acct/communigate.html @@ -47,8 +47,9 @@ % } else { % my $quota_label = $communigate ? 'Mail storage limit' : 'Quota'; - - <% $quota_label %> +<% include('/elements/tr-td-label.html', + 'label' => $quota_label, + 'required' => $part_svc->part_svc_column('quota')->required ) %> % } diff --git a/httemplate/edit/svc_broadband.cgi b/httemplate/edit/svc_broadband.cgi index 1b85460e6..81c694aa5 100644 --- a/httemplate/edit/svc_broadband.cgi +++ b/httemplate/edit/svc_broadband.cgi @@ -102,7 +102,16 @@ END my @fields = ( qw( description speed_down speed_up ), { field=>'sectornum', type=>'select-tower_sector', }, - { field=>'routernum', type=>'select-router_block_ip' }, + { field=>'routernum', type=>'select-router_block_ip', + include_opt_callback => sub { + my $svc_broadband = shift; + my $part_svc = $svc_broadband->part_svc; + return () unless $part_svc; #sanity check + my $col = $part_svc->part_svc_column('ip_addr'); + return () unless $col; #sanity check + return ('ip_addr_required' => $col->required); + }, + }, { field=>'mac_addr' , type=>'input-mac_addr' }, qw( latitude longitude altitude diff --git a/httemplate/elements/tr-input-date-field.html b/httemplate/elements/tr-input-date-field.html index ff9855184..f2a570b99 100644 --- a/httemplate/elements/tr-input-date-field.html +++ b/httemplate/elements/tr-input-date-field.html @@ -13,6 +13,7 @@ Example: 'usedatetime' => 1, #use DateTime->strftime to format the date # instead of Date::Format->time2str 'noinit' => 1, #first one on the page is enough + 'required' => 1, }, &> @@ -24,8 +25,9 @@ Example: % } - - <% $label %> +<% include('/elements/tr-td-label.html', + 'label' => $label, + 'required' => $required ) %> > @@ -48,7 +50,7 @@ Example: <%init> -my($name, $value, $label, $format, $usedatetime, $noinit, $colspan); +my($name, $value, $label, $format, $usedatetime, $noinit, $colspan, $required); if ( ref($_[0]) ) { my $opt = shift; $name = $opt->{'name'}; @@ -58,6 +60,7 @@ if ( ref($_[0]) ) { $usedatetime = $opt->{'usedatetime'}; $noinit = $opt->{'noinit'}; $colspan = $opt->{'colspan'} || 1; + $required = $opt->{'required'}; } else { ($name, $value, $label, $format, $usedatetime) = @_; $colspan = 1; diff --git a/httemplate/elements/tr-select-hardware_type.html b/httemplate/elements/tr-select-hardware_type.html index c3066417b..b51afc0a5 100644 --- a/httemplate/elements/tr-select-hardware_type.html +++ b/httemplate/elements/tr-select-hardware_type.html @@ -1,5 +1,6 @@ - - <% $opt{'label'} || 'Device type: ' %> +<% include('/elements/tr-td-label.html', + 'label' => $opt{'label'} || 'Device type: ', + 'required' => $opt{'required'} ) %> <% include('select-hardware_type.html', %opt) %> diff --git a/httemplate/elements/tr-select-router_block_ip.html b/httemplate/elements/tr-select-router_block_ip.html index 11f7c4831..ee135686c 100644 --- a/httemplate/elements/tr-select-router_block_ip.html +++ b/httemplate/elements/tr-select-router_block_ip.html @@ -30,7 +30,7 @@ function clearhint_ip_addr (what) { what.value = ''; } -<& /elements/tr-td-label.html, label => ($opt{'label'} || 'Router') &> +<& /elements/tr-td-label.html, label => ($opt{'label'} || 'Router'), required => $opt{'required'} &> <& /elements/select-tiered.html, prefix => 'router_', tiers => [ { @@ -56,9 +56,9 @@ function clearhint_ip_addr (what) { ] &> -<& /elements/tr-td-label.html, label => 'IP address' &> +<& /elements/tr-td-label.html, label => 'IP address', required => $opt{'ip_addr_required'} &> -% warn Dumper \%fixed; +% #warn Dumper \%fixed; % if ( exists $fixed{$ip_field} ) { <% $opt{'ip_addr'} || '' %>