multiple inventory classes for service columns, #21442
authorMark Wells <mark@freeside.biz>
Tue, 19 Mar 2013 02:33:34 +0000 (19:33 -0700)
committerMark Wells <mark@freeside.biz>
Tue, 19 Mar 2013 02:33:34 +0000 (19:33 -0700)
20 files changed:
FS/FS/part_svc.pm
FS/FS/part_svc_column.pm
FS/FS/svc_Common.pm
httemplate/browse/part_svc.cgi
httemplate/edit/elements/edit.html
httemplate/edit/elements/part_svc_column.html [new file with mode: 0644]
httemplate/edit/elements/svc_Common.html
httemplate/edit/part_svc.cgi
httemplate/edit/process/elements/svc_Common.html
httemplate/elements/tr-select-inventory_item.html [new file with mode: 0644]
httemplate/search/elements/svc_Common.html [new file with mode: 0644]
httemplate/search/svc_acct.cgi
httemplate/search/svc_broadband.cgi
httemplate/search/svc_dish.cgi
httemplate/search/svc_external.cgi
httemplate/search/svc_hardware.cgi
httemplate/search/svc_phone.cgi
httemplate/search/svc_www.cgi
httemplate/view/elements/svc_Common.html
httemplate/view/svc_hardware.cgi

index 6ca4889..da794dd 100644 (file)
@@ -757,11 +757,9 @@ sub process {
                     if ( $flag =~ /^[MAH]$/ ) {
                       $param->{ $f } = delete( $param->{ $f.'_classnum' } );
                     }
-                   if ( $flag =~ /^S$/ 
-                          or $_ eq 'usergroup' ) {
-                      $param->{ $f } = ref($param->{ $f })
-                                         ? join(',', @{$param->{ $f }} )
-                                         : $param->{ $f };
+                   if ( ( $flag =~ /^[MAHS]$/ or $_ eq 'usergroup' )
+                         and ref($param->{ $f }) ) {
+                      $param->{ $f } = join(',', @{ $param->{ $f } });
                    }
                     ( $f, $f.'_flag', $f.'_label' );
                   }
index d467516..38ce1fa 100644 (file)
@@ -99,8 +99,14 @@ sub check {
   $self->columnflag(uc($1));
 
   if ( $self->columnflag =~ /^[MA]$/ ) {
-    $error =
-      $self->ut_foreign_key( 'columnvalue', 'inventory_class', 'classnum' );
+    # split, check all values independently, and normalize
+    my @classnums = split(/\s*,\s*/, $self->columnvalue);
+    foreach (@classnums) {
+      $self->set('columnvalue', $_);
+      $error = $self->ut_foreign_key( 'columnvalue', 'inventory_class', 'classnum' );
+      return $error if $error;
+    }
+    $self->set('columnvalue', join(',', @classnums));
   }
   if ( $self->columnflag eq 'H' ) {
     $error = 
index ff465bf..0aea455 100644 (file)
@@ -842,13 +842,20 @@ sub set_auto_inventory {
     next if $columnflag eq 'A' && $self->$field() ne '';
 
     my $classnum = $part_svc_column->columnvalue;
-    my %hash = ( 'classnum' => $classnum );
+    my %hash;
 
     if ( $columnflag eq 'A' && $self->$field() eq '' ) {
       $hash{'svcnum'} = '';
     } elsif ( $columnflag eq 'M' ) {
       return "Select inventory item for $field" unless $self->getfield($field);
       $hash{'item'} = $self->getfield($field);
+      my $chosen_classnum = $self->getfield($field.'_classnum');
+      if ( grep {$_ == $chosen_classnum} split(',', $classnum) ) {
+        $classnum = $chosen_classnum;
+      }
+      # otherwise the chosen classnum is either (all), or somehow not on 
+      # the list, so ignore it and choose the first item that's in any
+      # class on the list
     }
 
     my $agentnums_sql = $FS::CurrentUser::CurrentUser->agentnums_sql(
@@ -859,18 +866,30 @@ sub set_auto_inventory {
     my $inventory_item = qsearchs({
       'table'     => 'inventory_item',
       'hashref'   => \%hash,
-      'extra_sql' => "AND $agentnums_sql",
+      'extra_sql' => "AND classnum IN ($classnum) AND $agentnums_sql",
       'order_by'  => 'ORDER BY ( agentnum IS NULL ) '. #agent inventory first
                      ' LIMIT 1 FOR UPDATE',
     });
 
     unless ( $inventory_item ) {
+      # should really only be shown if columnflag eq 'A'...
       $dbh->rollback if $oldAutoCommit;
-      my $inventory_class =
-        qsearchs('inventory_class', { 'classnum' => $classnum } );
-      return "Can't find inventory_class.classnum $classnum"
-        unless $inventory_class;
-      return "Out of ". PL_N($inventory_class->classname);
+      my $message = 'Out of ';
+      my @classnums = split(',', $classnum);
+      foreach ( @classnums ) {
+        my $class = FS::inventory_class->by_key($_)
+          or return "Can't find inventory_class.classnum $_";
+        $message .= PL_N($class->classname);
+        if ( scalar(@classnums) > 2 ) { # english is hard
+          if ( $_ != $classnums[-1] ) {
+            $message .= ', ';
+          }
+        }
+        if ( scalar(@classnums) > 1 and $_ == $classnums[-2] ) {
+          $message .= 'and ';
+        }
+      }
+      return $message;
     }
 
     next if $columnflag eq 'M' && $inventory_item->svcnum == $self->svcnum;
@@ -878,13 +897,14 @@ sub set_auto_inventory {
     $self->setfield( $field, $inventory_item->item );
       #if $columnflag eq 'A' && $self->$field() eq '';
 
+    # release the old inventory item, if there was one
     if ( $old && $old->$field() && $old->$field() ne $self->$field() ) {
       my $old_inv = qsearchs({
         'table'     => 'inventory_item',
-        'hashref'   => { 'classnum' => $classnum,
+        'hashref'   => { 
                          'svcnum'   => $old->svcnum,
                        },
-        'extra_sql' => ' AND '.
+        'extra_sql' => "AND classnum IN ($classnum) AND ".
           '( ( svc_field IS NOT NULL AND svc_field = '.$dbh->quote($field).' )'.
           '  OR ( svc_field IS NULL AND item = '. dbh->quote($old->$field).' )'.
           ')',
@@ -920,6 +940,9 @@ sub set_auto_inventory {
 
 =item return_inventory
 
+Release all inventory items attached to this service's fields.  Call
+when unprovisioning the service.
+
 =cut
 
 sub return_inventory {
index f941ae5..0d36853 100755 (executable)
@@ -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 %>
index a24f238..3e6bd5b 100644 (file)
@@ -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 (file)
index 0000000..d03c49d
--- /dev/null
@@ -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>
index 0d9d36c..d46d1cb 100644 (file)
                    } 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'}     = {
index 8a84b20..58c237e 100755 (executable)
-<& /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">
 
 
 <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 = '&nbsp;'.
-%            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 = '&nbsp;'.
+          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>
 
 
index 5a8afbd..06f4c00 100644 (file)
@@ -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 (file)
index 0000000..669e85f
--- /dev/null
@@ -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 (file)
index 0000000..56c75bb
--- /dev/null
@@ -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>
index 92e1c50..b9e5a7c 100755 (executable)
@@ -1,4 +1,4 @@
-<& elements/search.html,
+<& elements/svc_Common.html,
                  'title'       => emt('Account Search Results'),
                  'name'        => emt('accounts'),
                  'query'       => $sql_query,
index c22887e..8366d21 100755 (executable)
@@ -1,4 +1,4 @@
-<& elements/search.html,
+<& elements/svc_Common.html,
               'title'       => 'Broadband Search Results',
               'name'        => 'broadband services',
               'html_init'   => $html_init,
index 1578aa1..1f8cbc3 100755 (executable)
@@ -1,4 +1,4 @@
-<& elements/search.html,
+<& elements/svc_Common.html,
                  'title'       => 'Dish Network Search Results',
                  'name'        => 'services',
                  'query'       => $sql_query,
index 1909987..b282939 100755 (executable)
@@ -1,4 +1,4 @@
-<& elements/search.html,
+<& elements/svc_Common.html,
                  'title'             => 'External service search results',
                  'name'              => 'external services',
                  'query'             => $sql_query,
index 28aa132..93fc2c3 100644 (file)
@@ -1,4 +1,4 @@
-<& elements/search.html,
+<& elements/svc_Common.html,
             'title'             => 'Hardware service search results',
             'name'              => 'installations',
             'query'             => $sql_query,
index cc4aa60..f3a0564 100644 (file)
@@ -1,4 +1,4 @@
-<& elements/search.html,
+<& elements/svc_Common.html,
                  'title'             => "Phone number search results",
                  'name'              => 'phone numbers',
                  'query'             => $sql_query,
index eefe893..7410262 100755 (executable)
@@ -1,4 +1,4 @@
-<& elements/search.html,
+<& elements/svc_Common.html,
                  'title'       => 'Virtual Host Search Results',
                  'name'        => 'virtual hosts',
                  'query'       => $sql_query,
index a7f8f6d..d735195 100644 (file)
@@ -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>
index aa3ff00..eef1c11 100644 (file)
@@ -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 }