service def classes, to support corecom portal, RT#17617
authorIvan Kohler <ivan@freeside.biz>
Mon, 14 May 2012 05:16:37 +0000 (22:16 -0700)
committerIvan Kohler <ivan@freeside.biz>
Mon, 14 May 2012 05:16:37 +0000 (22:16 -0700)
14 files changed:
FS/FS.pm
FS/FS/Schema.pm
FS/FS/part_svc.pm
FS/FS/part_svc_class.pm [new file with mode: 0644]
FS/MANIFEST
FS/t/part_svc_class.t [new file with mode: 0644]
httemplate/browse/part_svc_class.html [new file with mode: 0644]
httemplate/docs/part_svc-table.html [new file with mode: 0644]
httemplate/edit/part_svc.cgi
httemplate/edit/part_svc_class.html [new file with mode: 0644]
httemplate/edit/process/part_svc_class.html [new file with mode: 0644]
httemplate/elements/menu.html
httemplate/elements/select-part_svc_class.html [new file with mode: 0644]
httemplate/elements/tr-select-part_svc_class.html [new file with mode: 0644]

index 8c78179..e169166 100644 (file)
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -214,6 +214,8 @@ L<FS::inventory_item> - Inventory items
 
 L<FS::part_svc> - Service definition class
 
 
 L<FS::part_svc> - Service definition class
 
+L<FS::part_svc_class> - Service class class
+
 L<FS::part_svc_column> - Column constraint class
 
 L<FS::export_svc> - Class linking service definitions (see L<FS::part_svc>)
 L<FS::part_svc_column> - Column constraint class
 
 L<FS::export_svc> - Class linking service definitions (see L<FS::part_svc>)
index 843e210..e3f34a4 100644 (file)
@@ -1850,6 +1850,7 @@ sub tables_hashref {
         'disabled',              'char', 'NULL',         1, '', '', 
         'preserve',              'char', 'NULL',         1, '', '',
         'selfservice_access', 'varchar', 'NULL',   $char_d, '', '',
         'disabled',              'char', 'NULL',         1, '', '', 
         'preserve',              'char', 'NULL',         1, '', '',
         'selfservice_access', 'varchar', 'NULL',   $char_d, '', '',
+        'classnum',               'int', 'NULL',        '', '', '',
       ],
       'primary_key' => 'svcpart',
       'unique' => [],
       ],
       'primary_key' => 'svcpart',
       'unique' => [],
@@ -1870,6 +1871,17 @@ sub tables_hashref {
       'index' => [ [ 'svcpart' ] ],
     },
 
       'index' => [ [ 'svcpart' ] ],
     },
 
+    'part_svc_class' => {
+      'columns' => [
+        'classnum',    'serial',   '',      '', '', '', 
+        'classname',   'varchar',  '', $char_d, '', '', 
+        'disabled',    'char', 'NULL',       1, '', '', 
+      ],
+      'primary_key' => 'classnum',
+      'unique' => [],
+      'index' => [ ['disabled'] ],
+    },
+
     #(this should be renamed to part_pop)
     'svc_acct_pop' => {
       'columns' => [
     #(this should be renamed to part_pop)
     'svc_acct_pop' => {
       'columns' => [
index 7e592bf..20b80c6 100644 (file)
@@ -9,6 +9,7 @@ use FS::part_svc_column;
 use FS::part_export;
 use FS::export_svc;
 use FS::cust_svc;
 use FS::part_export;
 use FS::export_svc;
 use FS::cust_svc;
+use FS::part_svc_class;
 
 @ISA = qw(FS::Record);
 
 
 @ISA = qw(FS::Record);
 
@@ -51,6 +52,8 @@ FS::Record.  The following fields are currently supported:
 =item svcdb - table used for this service.  See L<FS::svc_acct>,
 L<FS::svc_domain>, and L<FS::svc_forward>, among others.
 
 =item svcdb - table used for this service.  See L<FS::svc_acct>,
 L<FS::svc_domain>, and L<FS::svc_forward>, among others.
 
+=item classnum - Optional service class (see L<FS::svc_class>)
+
 =item disabled - Disabled flag, empty or `Y'
 
 =item preserve - Preserve after cancellation, empty or 'Y'
 =item disabled - Disabled flag, empty or `Y'
 
 =item preserve - Preserve after cancellation, empty or 'Y'
@@ -387,6 +390,7 @@ sub check {
     || $self->ut_enum('disabled', [ '', 'Y' ] )
     || $self->ut_enum('preserve', [ '', 'Y' ] )
     || $self->ut_enum('selfservice_access', [ '', 'hidden', 'readonly' ] )
     || $self->ut_enum('disabled', [ '', 'Y' ] )
     || $self->ut_enum('preserve', [ '', 'Y' ] )
     || $self->ut_enum('selfservice_access', [ '', 'hidden', 'readonly' ] )
+    || $self->ut_foreign_keyn('classnum', 'part_svc_class', 'classnum' )
   ;
   return $error if $error;
 
   ;
   return $error if $error;
 
@@ -712,7 +716,7 @@ sub process {
   my $job = shift;
 
   my $param = thaw(decode_base64(shift));
   my $job = shift;
 
   my $param = thaw(decode_base64(shift));
-  warn Dumper($param) if $DEBUG;
+  warn Dumper($param);# if $DEBUG;
 
   my $old = qsearchs('part_svc', { 'svcpart' => $param->{'svcpart'} }) 
     if $param->{'svcpart'};
 
   my $old = qsearchs('part_svc', { 'svcpart' => $param->{'svcpart'} }) 
     if $param->{'svcpart'};
diff --git a/FS/FS/part_svc_class.pm b/FS/FS/part_svc_class.pm
new file mode 100644 (file)
index 0000000..d1c9915
--- /dev/null
@@ -0,0 +1,126 @@
+package FS::part_svc_class;
+use base qw( FS::class_Common );
+
+use strict;
+use FS::Record; # qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::part_svc_class - Object methods for part_svc_class records
+
+=head1 SYNOPSIS
+
+  use FS::part_svc_class;
+
+  $record = new FS::part_svc_class \%hash;
+  $record = new FS::part_svc_class { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_svc_class object represents a service class.  FS::part_svc_class
+inherits from FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item classnum
+
+primary key
+
+=item classname
+
+classname
+
+=item disabled
+
+disabled
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new service class.  To add the service class to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to.  You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'part_svc_class'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid service class.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('classnum')
+    || $self->ut_text('classname')
+    || $self->ut_enum('disabled', [ '', 'Y' ] )
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
index 91711d3..8bb4eee 100644 (file)
@@ -638,3 +638,5 @@ FS/sales.pm
 t/sales.t
 FS/access_groupsales.pm
 t/access_groupsales.t
 t/sales.t
 FS/access_groupsales.pm
 t/access_groupsales.t
+FS/part_svc_class.pm
+t/part_svc_class.t
diff --git a/FS/t/part_svc_class.t b/FS/t/part_svc_class.t
new file mode 100644 (file)
index 0000000..e838c0b
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_svc_class;
+$loaded=1;
+print "ok 1\n";
diff --git a/httemplate/browse/part_svc_class.html b/httemplate/browse/part_svc_class.html
new file mode 100644 (file)
index 0000000..73bd603
--- /dev/null
@@ -0,0 +1,34 @@
+<% include( 'elements/browse.html',
+                 'title'       => 'Service classes',
+                 'html_init'   => $html_init,
+                 'name'        => 'service classes',
+                 'disableable' => 1,
+                 'disabled_statuspos' => 1,
+                 'query'       => { 'table'     => 'part_svc_class',
+                                    'hashref'   => {},
+                                    'order_by' => 'ORDER BY classnum',
+                                  },
+                 'count_query' => $count_query,
+                 'header'      => $header,
+                 'fields'      => $fields,
+                 'links'       => $links,
+             )
+%>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my $html_init = 
+  'Service classes are user-defined, informational types for services.<BR><BR>'.
+  qq!<A HREF="${p}edit/part_svc_class.html"><I>Add a service class</I></A><BR><BR>!;
+
+my $count_query = 'SELECT COUNT(*) FROM part_svc_class';
+
+my $link = [ $p.'edit/part_svc_class.html?', 'classnum' ];
+
+my $header = [ '#', 'Class' ];
+my $fields = [ 'classnum', 'classname' ];
+my $links  = [ $link, $link ];
+
+</%init>
diff --git a/httemplate/docs/part_svc-table.html b/httemplate/docs/part_svc-table.html
new file mode 100644 (file)
index 0000000..48841f5
--- /dev/null
@@ -0,0 +1,63 @@
+<& /elements/header-popup.html &>
+
+<TABLE>
+  <TR>
+    <TH ALIGN="left">Generic</TH>
+    <TH ALIGN="left">Access</TH>
+    <TH ALIGN="left">Telephony</TH>
+<!--    <TH>Hosting</TH>
+    <TH>Colocation</TH>
+-->
+  </TR>
+  <TR>
+    <TD VALIGN="top">
+      <UL STYLE="margin:0">
+        <LI><B>svc_acct</B>: Accounts - anything with a username (mailbox, shell, RADIUS, etc.)
+        <LI><B>svc_hardware</B>: Equipment supplied to customers
+        <LI><B>svc_external</B>: Externally-tracked service
+      </UL>
+    </TD>
+    <TD VALIGN="top">
+      <UL STYLE="margin:0">
+        <LI><B>svc_dsl</B>: DSL
+        <LI><B>svc_broadband</B>: Wireless broadband
+        <LI><B>svc_dish</B>: DISH Network
+      </UL>
+    </TD>
+    <TD VALIGN="top">
+      <UL STYLE="margin:0">
+        <LI><B>svc_phone</B>: Customer phone number
+        <LI><B>svc_pbx</B>: Customer PBX
+      </UL>
+    </TD>
+  </TR>
+</TABLE>
+<BR>
+<TABLE>
+  <TR>
+    <TH ALIGN="left">Hosting</TH>
+    <TH ALIGN="left">Colocation</TH>
+  </TR>
+    <TD VALIGN="top">
+      <UL STYLE="margin:0">
+        <LI><B>svc_domain</B>: Domain
+        <LI><B>svc_cert</B>: Certificate
+        <LI><B>svc_forward</B>: Mail forwarding
+        <LI><B>svc_mailinglist</B>: Mailing list
+        <LI><B>svc_www</B>: Virtual domain website
+      </UL>
+    </TD>
+    <TD VALIGN="top">
+      <UL STYLE="margin:0">
+        <LI><B>svc_port</B>: Customer router/switch port
+      </UL>
+    </TD>
+  </TR>
+<TABLE>
+<!--   <LI>svc_charge - One-time charges (Partially unimplemented)
+       <LI>svc_wo - Work orders (Partially unimplemented)
+-->
+
+</BODY>
+</HTML>
+
index fae8961..4bd0837 100755 (executable)
@@ -1,17 +1,27 @@
-<% include('/elements/header.html', "$action Service Definition",
+<& /elements/header.html, "$action Service Definition",
            menubar('View all service definitions' => "${p}browse/part_svc.cgi"),
            #" onLoad=\"visualize()\""
            menubar('View all service definitions' => "${p}browse/part_svc.cgi"),
            #" onLoad=\"visualize()\""
-          )
-%>
+&>
+
+<& /elements/init_overlib.html &>
+
+<BR>
 
 <FORM NAME="dummy">
 
 
 <FORM NAME="dummy">
 
-      Service Part #<% $part_svc->svcpart ? $part_svc->svcpart : "(NEW)" %>
-<BR><BR>
-Service  <INPUT TYPE="text" NAME="svc" VALUE="<% $hashref->{svc} %>"><BR>
+<FONT CLASS="fsinnerbox-title">Service Part #<% $part_svc->svcpart ? $part_svc->svcpart : "(NEW)" %></FONT>
+<TABLE CLASS="fsinnerbox">
+<TR>
+  <TD ALIGN="right">Service</TD>
+  <TD><INPUT TYPE="text" NAME="svc" VALUE="<% $hashref->{svc} %>"></TD>
+<TR>
+
+<& /elements/tr-select-part_svc_class.html, curr_value=>$hashref->{classnum} &>
 
 
-Self-service access:
-<SELECT NAME="selfservice_access">
+<TR>
+  <TD ALIGN="right">Self-service access</TD>
+  <TD>
+    <SELECT NAME="selfservice_access">
 % tie my %selfservice_access, 'Tie::IxHash', #false laziness w/browse/part_svc
 %   ''         => 'Yes',
 %   'hidden'   => 'Hidden',
 % tie my %selfservice_access, 'Tie::IxHash', #false laziness w/browse/part_svc
 %   ''         => 'Yes',
 %   'hidden'   => 'Hidden',
@@ -22,12 +32,22 @@ Self-service access:
           <% $_ eq $hashref->{'selfservice_access'} ? 'SELECTED' : '' %>
   ><% $selfservice_access{$_} %>
 % }
           <% $_ eq $hashref->{'selfservice_access'} ? 'SELECTED' : '' %>
   ><% $selfservice_access{$_} %>
 % }
-</SELECT><BR>
+    </SELECT>
+  </TD>
+</TR>
 
 
-<INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<% $hashref->{disabled} eq 'Y' ? ' CHECKED' : '' %>>&nbsp;Disable new orders<BR>
 
 
-<INPUT TYPE="checkbox" NAME="preserve" VALUE="Y"<% $hashref->{'preserve'} eq 'Y' ? ' CHECKED' : '' %>>&nbsp;Preserve this service on package cancellation<BR>
+<TR>
+  <TD ALIGN="right">Disable new orders</TD>
+  <TD><INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<% $hashref->{disabled} eq 'Y' ? ' CHECKED' : '' %>></TD>
+</TR>
 
 
+<TR>
+  <TD ALIGN="right">Preserve this service on package cancellation</TD>
+  <TD><INPUT TYPE="checkbox" NAME="preserve" VALUE="Y"<% $hashref->{'preserve'} eq 'Y' ? ' CHECKED' : '' %>>&nbsp;</TD>
+</TR>
+
+</TABLE>
 
 <INPUT TYPE="hidden" NAME="svcpart" VALUE="<% $hashref->{svcpart} %>">
 
 
 <INPUT TYPE="hidden" NAME="svcpart" VALUE="<% $hashref->{svcpart} %>">
 
@@ -76,6 +96,18 @@ Self-service access:
 %             ? ( $hashref->{svcdb} )
 %             : FS::part_svc->svc_tables();
 %
 %             ? ( $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,
 %  tie my %svcdb, 'Tie::IxHash', map { $_=>$_ } grep dbdef->table($_), @dbs;
 %  my $widget = new HTML::Widgets::SelectLayers(
 %    #'selected_layer' => $p_svcdb,
@@ -84,15 +116,16 @@ Self-service access:
 %    'form_name'      => 'dummy',
 %    #'form_action'    => 'process/part_svc.cgi',
 %    'form_action'    => 'part_svc.cgi', #self
 %    'form_name'      => 'dummy',
 %    #'form_action'    => 'process/part_svc.cgi',
 %    'form_action'    => 'part_svc.cgi', #self
-%    'form_text'      => [ qw( svc svcpart ) ],
-%    'form_select'    => [ 'selfservice_access' ],
-%    'form_checkbox'  => [ 'disabled', 'preserve' ],
+%    '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">!;
 %
 %    'layer_callback' => sub {
 %      my $layer = shift;
 %      
 %      my $html = qq!<INPUT TYPE="hidden" NAME="svcdb" VALUE="$layer">!;
 %
-%      $html .= $svcdb_info;
+%      #$html .= $svcdb_info;
 %
 %      my $columns = 3;
 %      my $count = 0;
 %
 %      my $columns = 3;
 %      my $count = 0;
@@ -267,6 +300,7 @@ Self-service access:
 %
 %          $html .= include('/elements/select-table.html',
 %                             'element_name' => "${layer}__${field}_classnum",
 %
 %          $html .= include('/elements/select-table.html',
 %                             'element_name' => "${layer}__${field}_classnum",
+%                             'id'           => "${layer}__${field}_classnum",
 %                             'element_etc'  => ( $is_inv
 %                                                   ? $disabled
 %                                                   : $nodisplay
 %                             'element_etc'  => ( $is_inv
 %                                                   ? $disabled
 %                                                   : $nodisplay
@@ -349,6 +383,7 @@ Self-service access:
 %          $html .= include('/elements/select-hardware_class.html',
 %                             'curr_value'    => $value,
 %                             'element_name'  => "${layer}__${field}_classnum",
 %          $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',
 %                          );
 %                             'element_etc'   => $flag ne 'H' && $nodisplay,
 %                             'empty_label'   => 'Select hardware class',
 %                          );
@@ -382,7 +417,8 @@ Self-service access:
 %
 %      $html .= include('/elements/progress-init.html',
 %                         $layer, #form name
 %
 %      $html .= include('/elements/progress-init.html',
 %                         $layer, #form name
-%                         [ qw(svc svcpart selfservice_access disabled preserve
+%                         [ qw(svc svcpart classnum selfservice_access
+%                              disabled preserve
 %                              exportnum),
 %                           @fields ],
 %                         'process/part_svc.cgi',
 %                              exportnum),
 %                           @fields ],
 %                         'process/part_svc.cgi',
@@ -401,9 +437,8 @@ Self-service access:
 %
 %    },
 %  );
 %
 %    },
 %  );
-%
-%
 
 
+<BR>
 Table <% $widget->html %>
 
 <% include('/elements/footer.html') %>
 Table <% $widget->html %>
 
 <% include('/elements/footer.html') %>
@@ -451,66 +486,6 @@ my %communigate_fields = (
   #'svc_cert'        => { map { $_=>1 } qw( ) },
 );
 
   #'svc_cert'        => { map { $_=>1 } qw( ) },
 );
 
-my $svcdb_info = '
-<TABLE>
-  <TR>
-    <TH ALIGN="left">Generic</TH>
-    <TH ALIGN="left">Access</TH>
-    <TH ALIGN="left">Telephony</TH>
-<!--    <TH>Hosting</TH>
-    <TH>Colocation</TH>
--->
-  </TR>
-  <TR>
-    <TD VALIGN="top">
-      <UL STYLE="margin:0">
-        <LI><B>svc_acct</B>: Accounts - anything with a username (mailbox, shell, RADIUS, etc.)
-        <LI><B>svc_hardware</B>: Equipment supplied to customers
-        <LI><B>svc_external</B>: Externally-tracked service
-      </UL>
-    </TD>
-    <TD VALIGN="top">
-      <UL STYLE="margin:0">
-        <LI><B>svc_dsl</B>: DSL
-        <LI><B>svc_broadband</B>: Wireless broadband
-        <LI><B>svc_dish</B>: DISH Network
-      </UL>
-    </TD>
-    <TD VALIGN="top">
-      <UL STYLE="margin:0">
-        <LI><B>svc_phone</B>: Customer phone number
-        <LI><B>svc_pbx</B>: Customer PBX
-      </UL>
-    </TD>
-  </TR>
-</TABLE>
-<BR>
-<TABLE>
-  <TR>
-    <TH ALIGN="left">Hosting</TH>
-    <TH ALIGN="left">Colocation</TH>
-  </TR>
-    <TD VALIGN="top">
-      <UL STYLE="margin:0">
-        <LI><B>svc_domain</B>: Domain
-        <LI><B>svc_cert</B>: Certificate
-        <LI><B>svc_forward</B>: Mail forwarding
-        <LI><B>svc_mailinglist</B>: Mailing list
-        <LI><B>svc_www</B>: Virtual domain website
-      </UL>
-    </TD>
-    <TD VALIGN="top">
-      <UL STYLE="margin:0">
-        <LI><B>svc_port</B>: Customer router/switch port
-      </UL>
-    </TD>
-  </TR>
-<TABLE>
-<!--   <LI>svc_charge - One-time charges (Partially unimplemented)
-       <LI>svc_wo - Work orders (Partially unimplemented)
--->
-';
-
 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
 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
diff --git a/httemplate/edit/part_svc_class.html b/httemplate/edit/part_svc_class.html
new file mode 100644 (file)
index 0000000..0d9a007
--- /dev/null
@@ -0,0 +1,6 @@
+<% include( 'elements/class_Common.html',
+              'name'   => 'Service class',
+              'table'  => 'part_svc_class',
+             'nocat' => 1,
+          )
+%>
diff --git a/httemplate/edit/process/part_svc_class.html b/httemplate/edit/process/part_svc_class.html
new file mode 100644 (file)
index 0000000..16165dd
--- /dev/null
@@ -0,0 +1,11 @@
+<% include( 'elements/process.html',
+               'table'       => 'part_svc_class',
+               'viewall_dir' => 'browse',
+           )
+%>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+</%init>
index 42feb7b..fcc17ea 100644 (file)
@@ -457,6 +457,7 @@ tie my %config_radius, 'Tie::IxHash',
 tie my %config_export_svc, 'Tie::IxHash', ();
 if ( $curuser->access_right('Configuration') ) {
   $config_export_svc{'Service definitions'} = [ $fsurl.'browse/part_svc.cgi', 'Services are items you offer to your customers' ];
 tie my %config_export_svc, 'Tie::IxHash', ();
 if ( $curuser->access_right('Configuration') ) {
   $config_export_svc{'Service definitions'} = [ $fsurl.'browse/part_svc.cgi', 'Services are items you offer to your customers' ];
+  $config_export_svc{'Service classes'} = [ $fsurl.'browse/part_svc_class.html', 'Services classes are user-defined, informational types for services' ];
   $config_export_svc{'Provisioning exports'} = [ $fsurl.'browse/part_export.cgi', 'Provisioning services to external machines, databases and APIs' ];
 }
 $config_export_svc{'Dialup'}  = [ \%config_dialup, ''    ]
   $config_export_svc{'Provisioning exports'} = [ $fsurl.'browse/part_export.cgi', 'Provisioning services to external machines, databases and APIs' ];
 }
 $config_export_svc{'Dialup'}  = [ \%config_dialup, ''    ]
diff --git a/httemplate/elements/select-part_svc_class.html b/httemplate/elements/select-part_svc_class.html
new file mode 100644 (file)
index 0000000..280e3e1
--- /dev/null
@@ -0,0 +1,22 @@
+<% include( '/elements/select-table.html',
+                 'table'       => 'part_svc_class',
+                 'name_col'    => 'classname',
+                 'value'       => $classnum,
+                 'empty_label' => '(none)',
+                 'hashref'     => \%hash,
+                 %opt,
+             )
+%>
+<%init>
+
+my %opt = @_;
+my $classnum = $opt{'curr_value'} || $opt{'value'};
+
+my %hash = ();
+$hash{'disabled'} = '' unless $opt{'showdisabled'};
+
+
+$opt{'records'} = delete $opt{'part_svc_class'}
+  if $opt{'part_svc_class'};
+
+</%init>
diff --git a/httemplate/elements/tr-select-part_svc_class.html b/httemplate/elements/tr-select-part_svc_class.html
new file mode 100644 (file)
index 0000000..2f4b093
--- /dev/null
@@ -0,0 +1,27 @@
+% if ( scalar(@{ $opt{'part_svc_class'} }) == 0 ) { 
+
+  <INPUT TYPE="hidden" NAME="<% $opt{'element_name'} || $opt{'field'} || 'classnum' %>" VALUE="">
+
+% } else { 
+
+  <TR>
+    <TD ALIGN="right"><% $opt{'label'} || 'Service class' %></TD>
+    <TD>
+      <% include( '/elements/select-part_svc_class.html',
+                    'curr_value' => $classnum,
+                    %opt
+                )
+      %>
+    </TD>
+  </TR>
+
+% } 
+
+<%init>
+
+my %opt = @_;
+my $classnum = $opt{'curr_value'} || $opt{'value'};
+
+$opt{'part_svc_class'} ||= [ qsearch( 'part_svc_class', { disabled=>'' } ) ];
+
+</%init>