diff options
author | Mark Wells <mark@freeside.biz> | 2013-03-18 19:33:34 -0700 |
---|---|---|
committer | Mark Wells <mark@freeside.biz> | 2013-03-18 19:33:34 -0700 |
commit | c2e126583354b58ef54ffa7f580b115b8eed1dd3 (patch) | |
tree | 0e0c25a9e8ccff3085b6caf55408f8c383720471 /httemplate | |
parent | 04f99991071acf5c390ea4d52db37798543ff9d8 (diff) |
multiple inventory classes for service columns, #21442
Diffstat (limited to 'httemplate')
-rwxr-xr-x | httemplate/browse/part_svc.cgi | 12 | ||||
-rw-r--r-- | httemplate/edit/elements/edit.html | 1 | ||||
-rw-r--r-- | httemplate/edit/elements/part_svc_column.html | 303 | ||||
-rw-r--r-- | httemplate/edit/elements/svc_Common.html | 27 | ||||
-rwxr-xr-x | httemplate/edit/part_svc.cgi | 555 | ||||
-rw-r--r-- | httemplate/edit/process/elements/svc_Common.html | 5 | ||||
-rw-r--r-- | httemplate/elements/tr-select-inventory_item.html | 48 | ||||
-rw-r--r-- | httemplate/search/elements/svc_Common.html | 48 | ||||
-rwxr-xr-x | httemplate/search/svc_acct.cgi | 2 | ||||
-rwxr-xr-x | httemplate/search/svc_broadband.cgi | 2 | ||||
-rwxr-xr-x | httemplate/search/svc_dish.cgi | 2 | ||||
-rwxr-xr-x | httemplate/search/svc_external.cgi | 2 | ||||
-rw-r--r-- | httemplate/search/svc_hardware.cgi | 2 | ||||
-rw-r--r-- | httemplate/search/svc_phone.cgi | 2 | ||||
-rwxr-xr-x | httemplate/search/svc_www.cgi | 2 | ||||
-rw-r--r-- | httemplate/view/elements/svc_Common.html | 9 | ||||
-rw-r--r-- | httemplate/view/svc_hardware.cgi | 3 |
17 files changed, 574 insertions, 451 deletions
diff --git a/httemplate/browse/part_svc.cgi b/httemplate/browse/part_svc.cgi index f941ae586..0d3685355 100755 --- a/httemplate/browse/part_svc.cgi +++ b/httemplate/browse/part_svc.cgi @@ -175,12 +175,14 @@ function part_export_areyousure(href) { % my $value = &$formatter($part_svc->part_svc_column($field)->columnvalue); % if ( $flag =~ /^[MAH]$/ ) { % my $select_table = ($flag eq 'H') ? 'hardware_class' : 'inventory_class'; -% $select_class{$value} ||= -% qsearchs($select_table, { 'classnum' => $value } ); +% foreach my $classnum ( split(',', $value) ) { +% $select_class{$classnum} = +% qsearchs($select_table, { 'classnum' => $classnum } ); % - <% $select_class{$value} - ? $select_class{$value}->classname - : "WARNING: $select_table.classnum $value not found" %> + <% $select_class{$classnum} + ? $select_class{$classnum}->classname + : "WARNING: $select_table.classnum $classnum not found" %><BR> +% } % } else { <% $value %> diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html index a24f23805..3e6bd5bec 100644 --- a/httemplate/edit/elements/edit.html +++ b/httemplate/edit/elements/edit.html @@ -329,6 +329,7 @@ Example: % qw( country ), #select-country % qw( width height ), #htmlarea % qw( alt_format ), #select-cust_location +% qw( classnum ), # select-inventory_item % ; % % #select-table diff --git a/httemplate/edit/elements/part_svc_column.html b/httemplate/edit/elements/part_svc_column.html new file mode 100644 index 000000000..d03c49d2f --- /dev/null +++ b/httemplate/edit/elements/part_svc_column.html @@ -0,0 +1,303 @@ +<%doc> +To be called from part_svc.cgi. +<& elements/part_svc_column.html, + 'svc_acct', + # options... + 'part_svc' => $part_svc, # the existing part_svc to edit + 'clone' => 0, # or a svcpart to clone from +&> + +</%doc> +<%once> +# the semantics of this could be better + +# all of these conditions are when NOT to allow that flag choice +# don't allow the 'inventory' flags (M, A) to be chosen for +# fields that aren't free-text +my $inv_sub = sub { $_[0]->{disable_inventory} || $_[0]->{type} ne 'text' }; +tie my %flag, 'Tie::IxHash', + '' => { 'desc' => 'No default', 'condition' => sub { 0 } }, + 'D' => { 'desc' => 'Default', + 'condition' => + sub { $_[0]->{disable_default } } + }, + 'F' => { 'desc' => 'Fixed (unchangeable)', + 'condition' => + sub { $_[0]->{disable_fixed} }, + }, + 'S' => { 'desc' => 'Selectable Choice', + 'condition' => + sub { $_[0]->{disable_select} }, + }, + 'M' => { 'desc' => 'Manual selection from inventory', + 'condition' => $inv_sub, + }, + 'A' => { 'desc' => 'Automatically fill in from inventory', + 'condition' => $inv_sub, + }, + 'H' => { 'desc' => 'Select from hardware class', + 'condition' => sub { $_[0]->{type} ne 'select-hardware' }, + }, + 'X' => { 'desc' => 'Excluded', + 'condition' => sub { 1 }, # obsolete + }, +; + +# the semantics of this could be much better +sub flag_condition { + my $f = shift; + not &{ $flag{$f}->{'condition'} }(@_); +} + +my %communigate_fields = ( + 'svc_acct' => { map { $_=>1 } + qw( file_quota file_maxnum file_maxsize + password_selfchange password_recover + ), + grep /^cgp_/, fields('svc_acct') + }, + 'svc_domain' => { map { $_=>1 } + qw( max_accounts trailer parent_svcnum ), + grep /^(cgp|acct_def)_/, fields('svc_domain') + }, +); +</%once> +<INPUT TYPE="hidden" NAME="svcdb" VALUE="<% $svcdb %>"> +<BR><BR> +<& /elements/table.html &> + <TR><TH COLSPAN=<% $columns %>>Exports</TH></TR> + <TR> +% # exports +% foreach my $part_export (@part_export) { + <TD> + <INPUT TYPE="checkbox" \ + NAME="exportnum<% $part_export->exportnum %>" \ + VALUE=1 \ + <% $has_export_svc{$part_export->exportnum} ? 'CHECKED' : '' %>> + <% $part_export->label_html %> + </TD> +% $count++; +% if ( $count % $columns == 0 ) { + </TR> + <TR> +% } +% } + </TR> +</TABLE><BR><BR> +For the selected table, you can give fields default or fixed (unchangeable) +values, or select an inventory class to manually or automatically fill in +that field. +<& /elements/table-grid.html, cellpadding => 4 &> + <TR> + <TH BGCOLOR="#cccccc">Field</TH> + <TH BGCOLOR="#cccccc">Label</TH> + <TH BGCOLOR="#cccccc" COLSPAN=2>Modifier</TH> + </TR> +% $part_svc->set('svcpart' => $opt{'clone'}) if $opt{'clone'}; # for now +% my $i = 0; +% foreach my $field (@fields) { +% my $def = shift @defs; +% my $part_svc_column = $part_svc->part_svc_column($field); +% my $flag = $part_svc_column->columnflag; +% my $formatter = $def->{'format'} || sub { shift }; +% my $value = &{$formatter}($part_svc_column->columnvalue); + <TR CLASS="row<%$i%>"> + <TD ROWSPAN=2 CLASS="grid" ALIGN="right"> + <% $def->{'label'} || $field %> + </TD> + <TD ROWSPAN=2 CLASS="grid"> + <INPUT NAME="<% $svcdb %>__<% $field %>_label" + STYLE="text-align: right" + VALUE="<% $part_svc_column->columnlabel || $def->{'label'} |h %>"> + </TD> + + <TD ROWSPAN=1 CLASS="grid"> +% # flag selection +% if ( $def->{'type'} eq 'disabled' ) { +% $flag = ''; + No default +% } else { +% my $name = $svcdb.'__'.$field.'_flag'; + <SELECT NAME="<%$name%>" + ID="<%$name%>" + STYLE="width:100%" + onchange="flag_changed(this)"> +% foreach my $f (keys %flag) { +% if ( flag_condition($f, $def, $svcdb, $field) ) { + <OPTION VALUE="<%$f%>"<% $flag eq $f ? ' SELECTED' : ''%>> + <% $flag{$f}->{desc} %> + </OPTION> +% } +% } + </SELECT> +% } # if $def->{'type'} eq 'disabled' + </TD> + <TD CLASS="grid"> +% # value entry/selection +% my $name = $svcdb.'__'.$field; +% # These are all MANDATORY SELECT types. Regardless of the flag value, +% # there will never be a text input (either in svc_* or in part_svc) for +% # these fields. +% if ( $def->{'type'} eq 'checkbox' ) { + <& /elements/checkbox.html, + 'field' => $name, + 'curr_value' => $value, + 'value' => 'Y' &> +% +% } elsif ( $def->{'type'} eq 'select' ) { +% +% if ( $def->{'select_table'} ) { + <& /elements/select-table.html, + 'field' => $name, + 'id' => $name.'_select', + 'table' => $def->{'select_table'}, + 'name_col' => $def->{'select_label'}, + 'value_col' => $def->{'select_key'}, + 'order_by' => dbdef->table($def->{'select_table'})->primary_key, + 'multiple' => $def->{'multiple'}, + 'disable_empty' => 1, + 'curr_value' => $value, + &> +% } else { +% my (@options, %labels); +% if ( $def->{'select_list'} ) { +% @options = @{ $def->{'select_list'} }; +% @labels{@options} = @options; +% } elsif ( $def->{'select_hash'} ) { +% if ( ref($def->{'select_hash'}) eq 'ARRAY' ) { +% tie my %hash, 'Tie::IxHash', @{ $def->{'select_hash'} }; +% $def->{'select_hash'} = \%hash; +% } +% @options = keys( %{ $def->{'select_hash'} } ); +% %labels = %{ $def->{'select_hash'} }; +% } + <& /elements/select.html, + 'field' => $name, + 'id' => $name.'_select', + 'options' => \@options, + 'labels' => \%labels, + 'multiple' => $def->{'multiple'}, + 'curr_value' => $value, + &> +% } +% } elsif ( $def->{'type'} =~ /select-(.*?).html/ ) { + <& '/elements/'.$def->{'type'}, + 'field' => $name, + 'id' => $name.'_select', + 'multiple' => $def->{'multiple'}, + 'curr_value' => $value, + &> +% } elsif ( $def->{'type'} eq 'communigate_pro-accessmodes' ) { + <& /elements/communigate_pro-accessmodes.html, + 'element_name_prefix' => $name.'_', + 'curr_value' => $value, + &> +% } elsif ( $def->{'type'} eq 'textarea' ) { +% # special cases + <TEXTAREA NAME="<%$name%>"><% $value |h %></TEXTAREA> +% } elsif ( $def->{'type'} eq 'disabled' ) { + <INPUT TYPE="hidden" NAME="<%$name%>" VALUE=""> +% } else { +% # the normal case: a text input, and a _select which is an inventory +% # or hardware class + <INPUT TYPE="text" + NAME="<%$name%>" + ID="<%$name%>" + VALUE="<%$value%>"> +% # inventory class selection + <& /elements/select-table.html, + 'field' => $name.'_classnum', + 'id' => $name.'_select', + 'table' => 'inventory_class', + 'name_col' => 'classname', + 'curr_value' => $value, + 'empty_label' => 'Select inventory class', + 'multiple' => 1, + &> +% } + </TD> + </TR> + <TR CLASS="row<%$i%>"> + <TD COLSPAN=2 CLASS="def_info"> +% if ( $def->{def_info} ) { + (<% $def->{def_info} %>) + </TD> + </TR> +% } +% $i = 1-$i; +% } # foreach my $field +% +% # special case: svc_acct password edit ACL +% if ( $svcdb eq 'svc_acct' ) { +% push @fields, 'restrict_edit_password'; + <TR> + <TD COLSPAN=3 ALIGN="right"> + <% emt('Require "Provision" access right to edit password') %> + </TD> + <TD> + <INPUT TYPE="checkbox" NAME="restrict_edit_password" VALUE="Y" \ + <% $part_svc->restrict_edit_password ? 'CHECKED' : '' %>> + </TD> + </TR> +% } +</TABLE> +<& /elements/progress-init.html, + $svcdb, #form name + [ # form fields to send + qw(svc svcpart classnum selfservice_access disabled preserve exportnum), + @fields + ], + 'process/part_svc.cgi', # target + $p.'browse/part_svc.cgi', # redirect landing + $svcdb, #key +&> +% $svcpart = '' if $opt{clone}; +<BR> +<INPUT NAME="submit" + TYPE="button" + VALUE="<% emt($svcpart ? 'Apply changes' : 'Add service') %>" + onclick="fixup_submit('<%$svcdb%>')" +> +<%init> +my $svcdb = shift; +my %opt = @_; +my $columns = 3; +my $count = 0; +my $communigate = 0; +my $conf = FS::Conf->new; + +my $part_svc = $opt{'part_svc'} || FS::part_svc->new; + +my @part_export; +my $export_info = FS::part_export::export_info($svcdb); +foreach (keys %{ $export_info }) { + push @part_export, qsearch('part_export', { exporttype => $_ }); +} +$communigate = scalar(grep {$_->exporttype =~ /^communigate/} @part_export); + +my $svcpart = $opt{'clone'} || $part_svc->svcpart; +my %has_export_svc; +if ( $svcpart ) { + foreach (qsearch('export_svc', { svcpart => $svcpart })) { + $has_export_svc{$_->exportnum} = 1; + } +} + +my @fields; +if ( defined( dbdef->table($svcdb) ) ) { # when is it ever not defined? + @fields = grep { + $_ ne 'svcnum' + and ( $communigate || ! $communigate_fields{$svcdb}->{$_} ) + and ( !FS::part_svc->svc_table_fields($svcdb)->{$_}->{disable_part_svc_column} + || $part_svc->part_svc_column($_)->columnflag ) + } fields($svcdb); +} +if ( $svcdb eq 'svc_acct' + or ( $svcdb eq 'svc_broadband' and $conf->exists('svc_broadband-radius') ) + ) +{ + push @fields, 'usergroup'; +} + +my @defs = map { FS::part_svc->svc_table_fields($svcdb)->{$_} } @fields; +</%init> diff --git a/httemplate/edit/elements/svc_Common.html b/httemplate/edit/elements/svc_Common.html index 0d9d36c07..d46d1cb42 100644 --- a/httemplate/edit/elements/svc_Common.html +++ b/httemplate/edit/elements/svc_Common.html @@ -88,30 +88,13 @@ } elsif ( $flag eq 'A' ) { $f->{'type'} = 'hidden'; } elsif ( $flag eq 'M' ) { + $f->{'type'} = 'select-inventory_item'; $f->{'empty_label'} = 'Select inventory item'; - $f->{'type'} = 'select-table'; - $f->{'table'} = 'inventory_item'; - $f->{'name_col'} = 'item'; - $f->{'value_col'} = 'item'; - $f->{'agent_virt'} = 1; - $f->{'agent_null'} = 1; - $f->{'hashref'} = { - 'classnum'=>$columndef->columnvalue, - #'svcnum' => '', - }; - $f->{'extra_sql'} = 'AND ( svcnum IS NULL '; - $f->{'extra_sql'} .= ' OR svcnum = '. $object->svcnum - if $object->svcnum; - $f->{'extra_sql'} .= ' ) '; + $f->{'extra_sql'} = 'WHERE ( svcnum IS NULL ' . + ($object->svcnum && ' OR svcnum = '.$object->svcnum) . + ')'; + $f->{'classnum'} = $columndef->columnvalue; $f->{'disable_empty'} = $object->svcnum ? 1 : 0; - if ( $f->{'field'} eq 'mac_addr' ) { - $f->{'compare_sub'} = sub { - my($a, $b) = @_; - $a =~ s/[-: ]//g; - $b =~ s/[-: ]//g; - lc($a) eq lc($b); - }; - } } elsif ( $flag eq 'H' ) { $f->{'type'} = 'select-hardware_type'; $f->{'hashref'} = { diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi index 8a84b208a..58c237efd 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -1,11 +1,111 @@ -<& /elements/header.html, "$action Service Definition", - menubar('View all service definitions' => "${p}browse/part_svc.cgi"), +<& /elements/header.html, "$action Service Definition" &> +<& /elements/menubar.html, + 'View all service definitions' => "${p}browse/part_svc.cgi" #" onLoad=\"visualize()\"" &> <& /elements/init_overlib.html &> -<BR> +<BR><BR> + +<STYLE TYPE="text/css"> +.disabled { + background-color: #dddddd; +} +.hidden { + display: none; +} +.enabled { + background-color: #ffffff; +} +.row0 TD { + background-color: #eeeeee; +} +.row1 TD { + background-color: #ffffff; +} +.def_info { + text-align: center; + padding: 0px; + border-top: none; + font-size: smaller; + font-style: italic; +} +</STYLE> +<SCRIPT TYPE="text/javascript"> +function fixup_submit(layer) { + document.forms[layer].submit.disabled = true; + fixup(document.forms[layer]); + window[layer+'process'].call(); +} + +function flag_changed(obj) { + var newflag = obj.value; + var a = obj.name.match(/(.*)__(.*)_flag/); + var layer = a[1]; + var field = a[2]; + var input = document.getElementById(layer + '__' + field); + // for fields that have both 'input' and 'select', 'select' is 'select from + // inventory class'. + var select = document.getElementById(layer + '__' + field + '_select'); + if (newflag == "" || newflag == "X") { // disable + if ( input ) { + input.disabled = true; + input.className = 'disabled'; + } + if ( select ) { + select.disabled = true; + select.className = 'hidden'; + } + } else if ( newflag == 'D' || newflag == 'F' || newflag == 'S' ) { + if ( input ) { + // enable text box, disable inventory select + input.disabled = false; + input.className = 'enabled'; + if ( select ) { + select.disabled = false; + select.className = 'hidden'; + } + } else if ( select ) { + // enable select + select.disabled = false; + select.className = 'enabled'; + if ( newflag == 'S' || select.getAttribute('should_be_multiple') ) { + select.multiple = true; + } else { + select.multiple = false; + } + } + } else if ( newflag == 'M' || newflag == 'A' || newflag == 'H' ) { + // these all require a class selection + if ( select ) { + select.disabled = false; + select.className = 'enabled'; + if ( input ) { + input.disabled = false; + input.className = 'hidden'; + } + } + } +} + +window.onload = function() { + var selects = document.getElementsByTagName('SELECT'); + for(i = 0; i < selects.length; i++) { + var obj = selects[i]; + if ( obj.multiple ) { + obj.setAttribute('should_be_multiple', true); + } + } + for(i = 0; i < selects.length; i++) { + var obj = selects[i]; + if ( obj.name.match(/_flag$/) ) { + flag_changed(obj); + } + } +}; + +</SCRIPT> <FORM NAME="dummy"> @@ -53,400 +153,6 @@ <BR> -% my %vfields; -% #code duplication w/ edit/part_svc.cgi, should move this hash to part_svc.pm -% # and generalize the subs -% # condition sub is tested to see whether to disable display of this choice -% # params: ( $def, $layer, $field ) (see SUB below) -% my $inv_sub = sub { -% $_[0]->{disable_inventory} -% || $_[0]->{'type'} ne 'text' -% }; -% tie my %flag, 'Tie::IxHash', -% '' => { 'desc' => 'No default', }, -% 'D' => { 'desc' => 'Default', -% 'condition' => -% sub { $_[0]->{disable_default} }, -% }, -% 'F' => { 'desc' => 'Fixed (unchangeable)', -% 'condition' => -% sub { $_[0]->{disable_fixed} }, -% }, -% 'S' => { 'desc' => 'Selectable Choice', -% 'condition' => -% sub { !ref($_[0]) || $_[0]->{disable_select} }, -% }, -% 'M' => { 'desc' => 'Manual selection from inventory', -% 'condition' => $inv_sub, -% }, -% 'A' => { 'desc' => 'Automatically fill in from inventory', -% 'condition' => $inv_sub, -% }, -% 'H' => { 'desc' => 'Select from hardware class', -% 'condition' => sub { $_[0]->{type} ne 'select-hardware' }, -% }, -% 'X' => { 'desc' => 'Excluded', -% 'condition' => -% sub { ! $vfields{$_[1]}->{$_[2]} }, -% -% }, -% ; -% -% my @dbs = $hashref->{svcdb} -% ? ( $hashref->{svcdb} ) -% : FS::part_svc->svc_tables(); -% -% my $help = ''; -% unless ( $hashref->{svcpart} ) { -% $help = ' '. -% include('/elements/popup_link.html', -% 'action' => $p.'docs/part_svc-table.html', -% 'label' => 'help', -% 'actionlabel' => 'Service table help', -% 'width' => 763, -% #'height' => 400, -% ); -% } -% -% tie my %svcdb, 'Tie::IxHash', map { $_=>$_ } grep dbdef->table($_), @dbs; -% my $widget = new HTML::Widgets::SelectLayers( -% #'selected_layer' => $p_svcdb, -% 'selected_layer' => $hashref->{svcdb} || 'svc_acct', -% 'options' => \%svcdb, -% 'form_name' => 'dummy', -% #'form_action' => 'process/part_svc.cgi', -% 'form_action' => 'part_svc.cgi', #self -% 'form_elements' => [qw( svc svcpart classnum selfservice_access -% disabled preserve -% )], -% 'html_between' => $help, -% 'layer_callback' => sub { -% my $layer = shift; -% -% my $html = qq!<INPUT TYPE="hidden" NAME="svcdb" VALUE="$layer">!; -% -% #$html .= $svcdb_info; -% -% my $columns = 3; -% my $count = 0; -% my $communigate = 0; -% my @part_export = -% map { qsearch( 'part_export', {exporttype => $_ } ) } -% keys %{FS::part_export::export_info($layer)}; -% $html .= '<BR><BR>'. include('/elements/table.html') . -% "<TR><TH COLSPAN=$columns>Exports</TH></TR><TR>"; -% foreach my $part_export ( @part_export ) { -% $communigate++ if $part_export->exporttype =~ /^communigate/; -% $html .= '<TD><INPUT TYPE="checkbox"'. -% ' NAME="exportnum'. $part_export->exportnum. '" VALUE="1" '; -% $html .= 'CHECKED' -% if ( $clone || $part_svc->svcpart ) #null svcpart search causing error -% && qsearchs( 'export_svc', { -% exportnum => $part_export->exportnum, -% svcpart => $clone || $part_svc->svcpart }); -% $html .= '>'. $part_export->label_html. '</TD>'; -% $count++; -% $html .= '</TR><TR>' unless $count % $columns; -% } -% $html .= '</TR></TABLE><BR><BR>'. $mod_info; -% -% $html .= include('/elements/table-grid.html', 'cellpadding' => 4 ). -% '<TR>'. -% '<TH CLASS="grid" BGCOLOR="#cccccc">Field</TH>'. -% '<TH CLASS="grid" BGCOLOR="#cccccc">Label</TH>'. -% '<TH CLASS="grid" BGCOLOR="#cccccc" COLSPAN=2>Modifier</TH>'. -% '</TR>'; -% -% my $bgcolor1 = '#eeeeee'; -% my $bgcolor2 = '#ffffff'; -% my $bgcolor; -% -% #yucky kludge -% my @fields = (); -% if ( defined( dbdef->table($layer) ) ) { -% @fields = grep { -% $_ ne 'svcnum' -% && ( $communigate || !$communigate_fields{$layer}->{$_} ) -% && ( !FS::part_svc->svc_table_fields($layer) -% ->{$_}->{disable_part_svc_column} -% || $part_svc->part_svc_column($_)->columnflag -% ) -% } fields($layer); -% } -% push @fields, 'usergroup' -% if $layer eq 'svc_acct' -% or ( $layer eq 'svc_broadband' and -% $conf->exists('svc_broadband-radius') ); # double kludge -% # (but we do want to check the config, right?) -% $part_svc->svcpart($clone) if $clone; #haha, undone below -% -% -% foreach my $field (@fields) { -% -% #a few lines of false laziness w/browse/part_svc.cgi -% my $def = FS::part_svc->svc_table_fields($layer)->{$field}; -% my $def_info = $def->{'def_info'}; -% my $formatter = $def->{'format'} || sub { shift }; -% -% my $part_svc_column = $part_svc->part_svc_column($field); -% my $label = $part_svc_column->columnlabel || $def->{'label'}; -% my $value = &$formatter($part_svc_column->columnvalue); -% my $flag = $part_svc_column->columnflag; -% -% if ( $bgcolor eq $bgcolor1 ) { -% $bgcolor = $bgcolor2; -% } else { -% $bgcolor = $bgcolor1; -% } -% -% $html .= qq!<TR><TD ROWSPAN=2 CLASS="grid" BGCOLOR="$bgcolor" ALIGN="right">!. -% ( $def->{'label'} || $field ). -% "</TD>"; -% -% $html .= qq!<TD ROWSPAN=2 CLASS="grid" BGCOLOR="$bgcolor"><INPUT NAME="${layer}__${field}_label" VALUE="!. encode_entities($label). '" STYLE="text-align:right"></TD>'; -% -% $flag = '' if $def->{type} eq 'disabled'; -% -% $html .= qq!<TD CLASS="grid" BGCOLOR="$bgcolor">!; -% -% if ( $def->{type} eq 'disabled' ) { -% -% $html .= 'No default'; -% -% } else { -% -% $html .= qq!<SELECT NAME="${layer}__${field}_flag"!. -% qq! onChange="${layer}__${field}_flag_changed(this)">!; -% -% foreach my $f ( keys %flag ) { -% -% # need to template-ize more httemplate/edit/svc_* first -% next if $f eq 'M' and $layer !~ /^svc_(broadband|external|phone|dish)$/; -% -% #here is where the SUB from above is called, to skip some choices -% next if $flag{$f}->{condition} -% && &{ $flag{$f}->{condition} }( $def, $layer, $field ); -% -% $html .= qq!<OPTION VALUE="$f"!. -% ' SELECTED'x($flag eq $f ). -% '>'. $flag{$f}->{desc}; -% -% } -% -% $html .= '</SELECT>'; -% -% $html .= join("\n", -% '<SCRIPT>', -% " function ${layer}__${field}_flag_changed(what) {", -% ' var f = what.options[what.selectedIndex].value;', -% ' if ( f == "" || f == "X" ) { //disable', -% " what.form.${layer}__${field}.disabled = true;". -% " what.form.${layer}__${field}.style.backgroundColor = '#dddddd';". -% " if ( what.form.${layer}__${field}_classnum ) {". -% " what.form.${layer}__${field}_classnum.disabled = true;". -% " what.form.${layer}__${field}_classnum.style.backgroundColor = '#dddddd';". -% " }". -% ' } else if ( f == "D" || f == "F" || f =="S" ) { //enable, text box', -% " what.form.${layer}__${field}.disabled = false;". -% " what.form.${layer}__${field}.style.backgroundColor = '#ffffff';". -% " if ( f == 'S' || '${field}' == 'usergroup' ) {". # kludge -% " what.form.${layer}__${field}.multiple = true;". -% " } else {". -% " what.form.${layer}__${field}.multiple = false;". -% " }". -% " what.form.${layer}__${field}.style.display = '';". -% " if ( what.form.${layer}__${field}_classnum ) {". -% " what.form.${layer}__${field}_classnum.disabled = false;". -% " what.form.${layer}__${field}_classnum.style.backgroundColor = '#ffffff';". -% " what.form.${layer}__${field}_classnum.style.display = 'none';". -% " }". -% ' } else if ( f == "M" || f == "A" || f == "H" ) { '. -% '//enable, inventory', -% " what.form.${layer}__${field}.disabled = false;". -% " what.form.${layer}__${field}.style.backgroundColor = '#ffffff';". -% " what.form.${layer}__${field}.style.display = 'none';". -% " if ( what.form.${layer}__${field}_classnum ) {". -% " what.form.${layer}__${field}_classnum.disabled = false;". -% " what.form.${layer}__${field}_classnum.style.backgroundColor = '#ffffff';". -% " what.form.${layer}__${field}_classnum.style.display = '';". -% " }". -% ' }', -% ' }', -% '</SCRIPT>', -% ); -% -% } -% -% $html .= qq!</TD><TD CLASS="grid" BGCOLOR="$bgcolor">!; -% -% my $disabled = $flag ? '' -% : 'DISABLED STYLE="background-color: #dddddd"'; -% my $nodisplay = ' STYLE="display:none"'; -% -% if ( !$def->{type} || $def->{type} eq 'text' ) { -% -% my $is_inv = ( $flag =~ /^[MA]$/ ); -% -% $html .= -% qq!<INPUT TYPE="text" NAME="${layer}__${field}" VALUE="$value" !. -% $disabled. -% ( $is_inv ? $nodisplay : $disabled ). -% '>'; -% -% $html .= include('/elements/select-table.html', -% 'element_name' => "${layer}__${field}_classnum", -% 'id' => "${layer}__${field}_classnum", -% 'element_etc' => ( $is_inv -% ? $disabled -% : $nodisplay -% ), -% 'table' => 'inventory_class', -% 'name_col' => 'classname', -% 'value' => $value, -% 'empty_label' => 'Select inventory class', -% ); -% -% } elsif ( $def->{type} eq 'checkbox' ) { -% -% $html .= include('/elements/checkbox.html', -% 'field' => $layer.'__'.$field, -% 'curr_value' => $value, -% 'value' => 'Y', -% ); -% -% } elsif ( $def->{type} eq 'select' ) { -% -% $html .= qq!<SELECT NAME="${layer}__${field}" $disabled!; -% $html .= ' MULTIPLE' if $flag eq 'S'; -% $html .= '>'; -% $html .= '<OPTION> </OPTION>' unless $value; -% if ( $def->{select_table} ) { -% foreach my $record ( qsearch( $def->{select_table}, {} ) ) { -% my $rvalue = $record->getfield($def->{select_key}); -% my $select_label = $def->{select_label}; -% $html .= qq!<OPTION VALUE="$rvalue"!. -% (grep(/^$rvalue$/, split(',',$value)) ? ' SELECTED>' : '>' ). -% $record->$select_label(). '</OPTION>'; -% } #next $record -% } elsif ( $def->{select_list} ) { -% foreach my $item ( @{$def->{select_list}} ) { -% $html .= qq!<OPTION VALUE="$item"!. -% (grep(/^$item$/, split(',',$value)) ? ' SELECTED>' : '>' ). -% $item. '</OPTION>'; -% } #next $item -% } elsif ( $def->{select_hash} ) { -% if ( ref($def->{select_hash}) eq 'ARRAY' ) { -% tie my %hash, 'Tie::IxHash', @{ $def->{select_hash} }; -% $def->{select_hash} = \%hash; -% } -% foreach my $key ( keys %{$def->{select_hash}} ) { -% $html .= qq!<OPTION VALUE="$key"!. -% (grep(/^$key$/, split(',',$value)) ? ' SELECTED>' : '>' ). -% $def->{select_hash}{$key}. '</OPTION>'; -% } #next $key -% } #endif -% $html .= '</SELECT>'; -% -% } elsif ( $def->{type} eq 'textarea' ) { -% -% $html .= -% qq!<TEXTAREA NAME="${layer}__${field}">!. encode_entities($value). -% '</TEXTAREA>'; -% -% } elsif ( $def->{type} =~ /select-(.*?).html/ ) { -% -% $html .= include("/elements/".$def->{type}, -% 'curr_value' => $value, -% 'element_name' => "${layer}__${field}", -% 'element_etc' => $disabled, -% 'multiple' => ($def->{multiple} || -% $flag eq 'S'), -% # allow the table def to force 'multiple' -% ); -% -% } elsif ( $def->{type} eq 'communigate_pro-accessmodes' ) { -% -% $html .= include('/elements/communigate_pro-accessmodes.html', -% 'element_name_prefix' => "${layer}__${field}_", -% 'curr_value' => $value, -% #doesn't work#'element_etc' => $disabled, -% ); -% -% } elsif ( $def->{type} eq 'select-hardware' ) { -% -% $html .= qq!<INPUT TYPE="text" NAME="${layer}__${field}" $disabled>!; -% $html .= include('/elements/select-hardware_class.html', -% 'curr_value' => $value, -% 'element_name' => "${layer}__${field}_classnum", -% 'id' => "${layer}__${field}_classnum", -% 'element_etc' => $flag ne 'H' && $nodisplay, -% 'empty_label' => 'Select hardware class', -% ); -% -% } elsif ( $def->{type} eq 'disabled' ) { -% -% $html .= -% qq!<INPUT TYPE="hidden" NAME="${layer}__${field}" VALUE="">!; -% -% } else { -% -% $html .= '<font color="#ff0000">unknown type '. $def->{type}; -% -% } -% -% $html .= "</TD></TR>\n"; - -% $def_info = "($def_info)" if $def_info; -% $html .= -% qq!<TR>!. -% qq! <TD COLSPAN=2 BGCOLOR="$bgcolor" ALIGN="center" !. -% qq! STYLE="padding:0; border-top: none">!. -% qq! <FONT SIZE="-1"><I>$def_info</I></FONT>!. -% qq! </TD>!. -% qq!</TR>\n!; -% -% } #foreach my $field (@fields) { -% -% if ( $layer eq 'svc_acct' ) { -% # eww, more ugly special-caseyness -% $html .= -% '<TR><TD COLSPAN=3 ALIGN="right">'. -% emt('Require "Provision" access right to edit password'). -% '</TD><TD>'. -% '<INPUT TYPE="checkbox" NAME="restrict_edit_password" VALUE="Y"'. -% ($part_svc->restrict_edit_password ? ' CHECKED' : ''). -% '></TD></TR>'; -% } else { -% $html .= -% '<INPUT TYPE="hidden" NAME="restrict_edit_password" VALUE="">'; -% } -% -% $part_svc->svcpart('') if $clone; #undone -% $html .= "</TABLE>"; -% -% $html .= include('/elements/progress-init.html', -% $layer, #form name -% [ qw(svc svcpart classnum selfservice_access -% disabled preserve -% exportnum restrict_edit_password), -% @fields ], -% 'process/part_svc.cgi', -% $p.'browse/part_svc.cgi', -% $layer, -% ); -% $html .= '<BR><INPUT NAME="submit" TYPE="button" VALUE="'. -% ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '" '. -% ' onClick="document.'. "$layer.submit.disabled=true; ". -% "fixup(document.$layer); $layer". 'process();">'; -% -% #$html .= '<BR><INPUT TYPE="submit" VALUE="'. -% # ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '">'; -% -% $html; -% -% }, -% ); - <BR> Table <% $widget->html %> @@ -479,28 +185,43 @@ my $action = $part_svc->svcpart ? 'Edit' : 'Add'; my $hashref = $part_svc->hashref; # my $p_svcdb = $part_svc->svcdb || 'svc_acct'; -my %communigate_fields = ( - 'svc_acct' => { map { $_=>1 } - qw( file_quota file_maxnum file_maxsize - password_selfchange password_recover - ), - grep /^cgp_/, fields('svc_acct') - }, - 'svc_domain' => { map { $_=>1 } - qw( max_accounts trailer parent_svcnum ), - grep /^(cgp|acct_def)_/, fields('svc_domain') - }, - #'svc_forward' => { map { $_=>1 } qw( ) }, - #'svc_mailinglist' => { map { $_=>1 } qw( ) }, - #'svc_cert' => { map { $_=>1 } qw( ) }, -); -my $mod_info = ' -For the selected table, you can give fields default or fixed (unchangable) -values, or select an inventory class to manually or automatically fill in -that field. -'; +my @dbs = $hashref->{svcdb} + ? ( $hashref->{svcdb} ) + : FS::part_svc->svc_tables(); + +my $help = ''; +unless ( $hashref->{svcpart} ) { + $help = ' '. + include('/elements/popup_link.html', + 'action' => $p.'docs/part_svc-table.html', + 'label' => 'help', + 'actionlabel' => 'Service table help', + 'width' => 763, + #'height' => 400, + ); +} +tie my %svcdb, 'Tie::IxHash', map { $_=>$_ } grep dbdef->table($_), @dbs; +my $widget = new HTML::Widgets::SelectLayers( + #'selected_layer' => $p_svcdb, + 'selected_layer' => $hashref->{svcdb} || 'svc_acct', + 'options' => \%svcdb, + 'form_name' => 'dummy', + #'form_action' => 'process/part_svc.cgi', + 'form_action' => 'part_svc.cgi', #self + 'form_elements' => [qw( svc svcpart classnum selfservice_access + disabled preserve + )], + 'html_between' => $help, + 'layer_callback' => sub { + include('elements/part_svc_column.html', + shift, + 'part_svc' => $part_svc, + 'clone' => $clone + ) + } +); </%init> diff --git a/httemplate/edit/process/elements/svc_Common.html b/httemplate/edit/process/elements/svc_Common.html index 5a8afbd6c..06f4c00b1 100644 --- a/httemplate/edit/process/elements/svc_Common.html +++ b/httemplate/edit/process/elements/svc_Common.html @@ -10,5 +10,10 @@ my %opt = @_; my $table = $opt{'table'}; $opt{'fields'} ||= [ fields($table) ]; push @{ $opt{'fields'} }, qw( pkgnum svcpart ); +foreach (fields($table)) { + if ( $cgi->param($_.'_classnum') ) { + push @{ $opt{'fields'} }, $_.'_classnum'; + } +} </%init> diff --git a/httemplate/elements/tr-select-inventory_item.html b/httemplate/elements/tr-select-inventory_item.html new file mode 100644 index 000000000..669e85f27 --- /dev/null +++ b/httemplate/elements/tr-select-inventory_item.html @@ -0,0 +1,48 @@ +% if ( scalar(@classnums) == 0 ) { +<& tr-fixed.html, %opt &> +% } elsif ( scalar(@classnums) == 1 ) { +% $opt{'extra_sql'} .= ' AND '.$classnum_sql; +<& tr-select-table.html, + 'table' => 'inventory_item', + 'name_col' => 'item', + 'value_col' => 'item', + %opt +&> +% } else { +<& tr-td-label.html, %opt &> +<TD> +<& select-tiered.html, + 'prefix' => $opt{'field'}.'_', + 'tiers' => [ + { + field => $opt{'field'}.'_classnum', + table => 'inventory_class', + extra_sql => "WHERE $classnum_sql", + name_col => 'classname', + empty_label => '(all)', + }, + { + field => $opt{'field'}, + table => 'inventory_item', + name_col => 'item', + value_col => 'item', + link_col => 'classnum', + extra_sql => delete($opt{'extra_sql'}), + disable_empty => 1, + }, + ], + %opt, +&> +</TD> +</TR> +% } +<%init> +my %opt = @_; +my @classnums; +if (ref($opt{'classnum'})) { + @classnums = @{ $opt{'classnum'} }; +} else { + @classnums = split(',', $opt{'classnum'}); +} +my $classnum_sql = 'classnum IN('.join(',', @classnums).')'; +</%init> diff --git a/httemplate/search/elements/svc_Common.html b/httemplate/search/elements/svc_Common.html new file mode 100644 index 000000000..56c75bba3 --- /dev/null +++ b/httemplate/search/elements/svc_Common.html @@ -0,0 +1,48 @@ +<& search.html, %opt &> +<%doc> +Currently does nothing but insert the classnames for fields chosen from an +inventory class. +</%doc> +<%init> +my %opt = @_; +my $query = $opt{query}; +my $svcdb = $query->{'table'}; + +# to avoid looking up the inventory class of every service in the database, +# keep as much of the base query as possible. +my $item_query = { %$query }; +$item_query->{'table'} = 'inventory_item'; +$item_query->{'addl_from'} = + " JOIN ( $svcdb ". $query->{'addl_from'} . + ") ON inventory_item.svcnum = $svcdb.svcnum ". + " JOIN inventory_class ON (inventory_item.classnum = inventory_class.classnum)"; +# avoid conflict with inventory_item.agentnum +$item_query->{'extra_sql'} =~ s/ agentnum/ cust_main.agentnum/g; +$item_query->{'select'} = 'inventory_item.svcnum, '. + 'inventory_item.svc_field, '. + 'inventory_class.classname'; +my @items = qsearch($item_query); +my %item_fields; +foreach my $i (@items) { + $item_fields{ $i->svc_field } ||= {}; + $item_fields{ $i->svc_field }{ $i->svcnum } = $i->classname; +} + +$opt{'sort_fields'} ||= []; +for ( my $i = 0; $i < @{ $opt{'fields'} }; $i++ ) { + my $f = $opt{'fields'}[$i]; + next if ref($f); # it's not a plain table column + $opt{'sort_fields'}[$i] ||= $f; + my $classnames = $item_fields{$f}; # hashref of svcnum -> classname + next if !$classnames; # there are no inventory items in this column + $opt{'fields'}[$i] = sub { + my $svc = $_[0]; + if ( exists($classnames->{$svc->svcnum}) ) { + return $svc->$f . '<BR><I>('. $classnames->{$svc->svcnum} . ')</I>'; + } else { + return $svc->$f; + } + }; #sub +} + +</%init> diff --git a/httemplate/search/svc_acct.cgi b/httemplate/search/svc_acct.cgi index 92e1c500c..b9e5a7cc9 100755 --- a/httemplate/search/svc_acct.cgi +++ b/httemplate/search/svc_acct.cgi @@ -1,4 +1,4 @@ -<& elements/search.html, +<& elements/svc_Common.html, 'title' => emt('Account Search Results'), 'name' => emt('accounts'), 'query' => $sql_query, diff --git a/httemplate/search/svc_broadband.cgi b/httemplate/search/svc_broadband.cgi index c22887e08..8366d214b 100755 --- a/httemplate/search/svc_broadband.cgi +++ b/httemplate/search/svc_broadband.cgi @@ -1,4 +1,4 @@ -<& elements/search.html, +<& elements/svc_Common.html, 'title' => 'Broadband Search Results', 'name' => 'broadband services', 'html_init' => $html_init, diff --git a/httemplate/search/svc_dish.cgi b/httemplate/search/svc_dish.cgi index 1578aa1e3..1f8cbc395 100755 --- a/httemplate/search/svc_dish.cgi +++ b/httemplate/search/svc_dish.cgi @@ -1,4 +1,4 @@ -<& elements/search.html, +<& elements/svc_Common.html, 'title' => 'Dish Network Search Results', 'name' => 'services', 'query' => $sql_query, diff --git a/httemplate/search/svc_external.cgi b/httemplate/search/svc_external.cgi index 19099878a..b282939a7 100755 --- a/httemplate/search/svc_external.cgi +++ b/httemplate/search/svc_external.cgi @@ -1,4 +1,4 @@ -<& elements/search.html, +<& elements/svc_Common.html, 'title' => 'External service search results', 'name' => 'external services', 'query' => $sql_query, diff --git a/httemplate/search/svc_hardware.cgi b/httemplate/search/svc_hardware.cgi index 28aa13217..93fc2c391 100644 --- a/httemplate/search/svc_hardware.cgi +++ b/httemplate/search/svc_hardware.cgi @@ -1,4 +1,4 @@ -<& elements/search.html, +<& elements/svc_Common.html, 'title' => 'Hardware service search results', 'name' => 'installations', 'query' => $sql_query, diff --git a/httemplate/search/svc_phone.cgi b/httemplate/search/svc_phone.cgi index cc4aa60f5..f3a056475 100644 --- a/httemplate/search/svc_phone.cgi +++ b/httemplate/search/svc_phone.cgi @@ -1,4 +1,4 @@ -<& elements/search.html, +<& elements/svc_Common.html, 'title' => "Phone number search results", 'name' => 'phone numbers', 'query' => $sql_query, diff --git a/httemplate/search/svc_www.cgi b/httemplate/search/svc_www.cgi index eefe89302..7410262e8 100755 --- a/httemplate/search/svc_www.cgi +++ b/httemplate/search/svc_www.cgi @@ -1,4 +1,4 @@ -<& elements/search.html, +<& elements/svc_Common.html, 'title' => 'Virtual Host Search Results', 'name' => 'virtual hosts', 'query' => $sql_query, diff --git a/httemplate/view/elements/svc_Common.html b/httemplate/view/elements/svc_Common.html index a7f8f6df4..d735195fe 100644 --- a/httemplate/view/elements/svc_Common.html +++ b/httemplate/view/elements/svc_Common.html @@ -57,6 +57,7 @@ function areyousure(href) { <% ntable("#cccccc") %><TR><TD><% ntable("#cccccc",2) %> +% my @inventory_items = $svc_x->inventory_item; % foreach my $f ( @$fields ) { % % my($field, $type, $value); @@ -76,6 +77,14 @@ function areyousure(href) { % } % % my $columndef = $part_svc->part_svc_column($field); +% if ( $columndef->columnflag =~ /^[MA]$/ && $columndef->columnvalue =~ /,/ ) +% { +% # inventory-select field with multiple classes +% # show the class name to disambiguate +% my ($item) = grep { $_->svc_field eq $field } @inventory_items; +% my $class = qsearchs('inventory_class', { classnum => $item->classnum }); +% $value .= ' <i>('. $class->classname . ')</i>' if $class; +% } % unless ($columndef->columnflag eq 'F' && !length($columndef->columnvalue)) { <TR> diff --git a/httemplate/view/svc_hardware.cgi b/httemplate/view/svc_hardware.cgi index aa3ff0091..eef1c1140 100644 --- a/httemplate/view/svc_hardware.cgi +++ b/httemplate/view/svc_hardware.cgi @@ -13,6 +13,9 @@ my %labels = map { $_ => ( ref($fields->{$_}) : $fields->{$_} ); } keys %$fields; + +$labels{'display_hw_addr'} = 'Hardware address'; + my $model = { field => 'typenum', type => 'text', value_callback => sub { $_[0]->hardware_type->description } |