4 if ( $cgi->param('clone') && $cgi->param('clone') =~ /^(\d+)$/ ) {#clone
5 #$cgi->param('clone') =~ /^(\d+)$/ or die "malformed query: $query";
6 $part_svc = qsearchs('part_svc', { 'svcpart'=>$1 } )
7 or die "unknown svcpart: $1";
8 $clone = $part_svc->svcpart;
9 $part_svc->svcpart('');
10 } elsif ( $cgi->keywords ) { #edit
11 my($query) = $cgi->keywords;
12 $query =~ /^(\d+)$/ or die "malformed query: $query";
13 $part_svc=qsearchs('part_svc', { 'svcpart'=>$1 } )
14 or die "unknown svcpart: $1";
16 $part_svc = new FS::part_svc {};
19 my $action = $part_svc->svcpart ? 'Edit' : 'Add';
20 my $hashref = $part_svc->hashref;
21 # my $p_svcdb = $part_svc->svcdb || 'svc_acct';
24 #" onLoad=\"visualize()\""
26 <%= include("/elements/header.html","$action Service Definition",
27 menubar( 'Main Menu' => $p,
28 'View all service definitions' => "${p}browse/part_svc.cgi"
35 Service Part #<%= $part_svc->svcpart ? $part_svc->svcpart : "(NEW)" %>
37 Service <INPUT TYPE="text" NAME="svc" VALUE="<%= $hashref->{svc} %>"><BR>
38 Disable new orders <INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<%= $hashref->{disabled} eq 'Y' ? ' CHECKED' : '' %>><BR>
39 <INPUT TYPE="hidden" NAME="svcpart" VALUE="<%= $hashref->{svcpart} %>">
41 Service definitions are the templates for items you offer to your customers.
42 <UL><LI>svc_acct - Accounts - anything with a username (Mailboxes, PPP accounts, shell accounts, etc.)
43 <LI>svc_domain - Domains
44 <LI>svc_forward - mail forwarding
45 <LI>svc_www - Virtual domain website
46 <LI>svc_broadband - Broadband/High-speed Internet service (always-on)
47 <LI>svc_external - Externally-tracked service
48 <!-- <LI>svc_charge - One-time charges (Partially unimplemented)
49 <LI>svc_wo - Work orders (Partially unimplemented)
52 For the selected table, you can give fields default or fixed (unchangable)
53 values, or select an inventory class to manually or automatically fill in
59 #these might belong somewhere else for other user interfaces
60 #pry need to eventually create stuff that's shared amount UIs
61 my $conf = new FS::Conf;
64 'dir' => 'Home directory',
65 'uid' => 'UID (set to fixed and blank for no UIDs)',
66 'slipip' => 'IP address',
67 # 'popnum' => qq!<A HREF="$p/browse/svc_acct_pop.cgi/">POP number</A>!,
69 desc => 'Access number',
71 select_table => 'svc_acct_pop',
72 select_key => 'popnum',
73 select_label => 'city',
84 disable_inventory => 1,
86 '_password' => 'Password',
87 'gid' => 'GID (when blank, defaults to UID)',
89 #desc =>'Shell (all service definitions should have a default or fixed shell that is present in the <b>shells</b> configuration file, set to blank for no shell tracking)',
90 desc =>'Shell ( set to blank for no shell tracking)',
92 select_list => [ $conf->config('shells') ],
93 disable_inventory => 1,
95 'finger' => 'Real name (GECOS)',
97 desc =>'svcnum from svc_domain',
99 select_table => 'svc_domain',
100 select_key => 'svcnum',
101 select_label => 'domain',
102 disable_inventory => 1,
105 desc =>'RADIUS groups',
106 type =>'radius_usergroup_selector',
107 disable_inventory => 1,
109 'seconds' => { desc => '',
111 disable_inventory => 1,
115 'domain' => 'Domain',
118 'srcsvc' => 'service from which mail is to be forwarded',
119 'dstsvc' => 'service to which mail is to be forwarded',
120 'dst' => 'someone@another.domain.com to use when dstsvc is 0',
123 # 'amount' => 'amount',
126 # 'worker' => 'Worker',
134 'speed_down' => 'Maximum download speed for this service in Kbps. 0 denotes unlimited.',
135 'speed_up' => 'Maximum upload speed for this service in Kbps. 0 denotes unlimited.',
136 'ip_addr' => 'IP address. Leave blank for automatic assignment.',
137 'blocknum' => 'Address block.',
146 foreach my $svcdb (grep dbdef->table($_), keys %defs ) {
147 my $self = "FS::$svcdb"->new;
148 $vfields{$svcdb} = {};
149 foreach my $field ($self->virtual_fields) { # svc_Common::virtual_fields with a null svcpart returns all of them
150 my $pvf = $self->pvf($field);
151 my @list = $pvf->list;
153 $defs{$svcdb}->{$field} = { desc => $pvf->label,
155 select_list => \@list };
157 $defs{$svcdb}->{$field} = $pvf->label;
159 $vfields{$svcdb}->{$field} = $pvf;
160 warn "\$vfields{$svcdb}->{$field} = $pvf";
164 #code duplication w/ edit/part_svc.cgi, should move this hash to part_svc.pm
165 # and generalize the subs
166 # condition sub is tested to see whether to disable display of this choice
167 # params: ( $def, $layer, $field ) (see SUB below)
169 ref($_[0]) && ( $_[0]->{disable_inventory}
170 || $_[0]->{'type'} ne 'text' )
172 tie my %flag, 'Tie::IxHash',
173 '' => { 'desc' => 'No default', },
174 'D' => { 'desc' => 'Default',
176 sub { ref($_[0]) && $_[0]->{disable_default} },
178 'F' => { 'desc' => 'Fixed (unchangeable)',
180 sub { ref($_[0]) && $_[0]->{disable_fixed} },
182 'M' => { 'desc' => 'Manual selection from inventory',
183 'condition' => $inv_sub,
185 'A' => { 'desc' => 'Automatically fill in from inventory',
186 'condition' => $inv_sub,
188 'X' => { 'desc' => 'Excluded',
190 sub { ! $vfields{$_[1]}->{$_[2]} },
195 my @dbs = $hashref->{svcdb}
196 ? ( $hashref->{svcdb} )
197 : qw( svc_acct svc_domain svc_forward svc_www svc_broadband svc_external );
199 tie my %svcdb, 'Tie::IxHash', map { $_=>$_ } grep dbdef->table($_), @dbs;
200 my $widget = new HTML::Widgets::SelectLayers(
201 #'selected_layer' => $p_svcdb,
202 'selected_layer' => $hashref->{svcdb} || 'svc_acct',
203 'options' => \%svcdb,
204 'form_name' => 'dummy',
205 #'form_action' => 'process/part_svc.cgi',
206 'form_action' => 'part_svc.cgi', #self
207 'form_text' => [ qw( svc svcpart ) ],
208 'form_checkbox' => [ 'disabled' ],
209 'layer_callback' => sub {
212 my $html = qq!<INPUT TYPE="hidden" NAME="svcdb" VALUE="$layer">!;
217 map { qsearch( 'part_export', {exporttype => $_ } ) }
218 keys %{FS::part_export::export_info($layer)};
219 $html .= '<BR><BR>'. table().
220 "<TR><TH COLSPAN=$columns>Exports</TH></TR><TR>";
221 foreach my $part_export ( @part_export ) {
222 $html .= '<TD><INPUT TYPE="checkbox"'.
223 ' NAME="exportnum'. $part_export->exportnum. '" VALUE="1" ';
225 if ( $clone || $part_svc->svcpart ) #null svcpart search causing error
226 && qsearchs( 'export_svc', {
227 exportnum => $part_export->exportnum,
228 svcpart => $clone || $part_svc->svcpart });
229 $html .= '>'. $part_export->exportnum. ': '. $part_export->exporttype.
230 ' to '. $part_export->machine. '</TD>';
232 $html .= '</TR><TR>' unless $count % $columns;
234 $html .= '</TR></TABLE><BR><BR>';
236 $html .= include('/elements/table-grid.html', 'cellpadding' => 4 ).
238 '<TH CLASS="grid" BGCOLOR="#cccccc">Field</TH>'.
239 '<TH CLASS="grid" BGCOLOR="#cccccc" COLSPAN=2>Modifier</TH>'.
242 my $bgcolor1 = '#eeeeee';
243 my $bgcolor2 = '#ffffff';
247 my @fields = defined( dbdef->table($layer) )
248 ? grep { $_ ne 'svcnum' } fields($layer)
250 push @fields, 'usergroup' if $layer eq 'svc_acct'; #kludge
251 $part_svc->svcpart($clone) if $clone; #haha, undone below
254 foreach my $field (@fields) {
256 my $part_svc_column = $part_svc->part_svc_column($field);
257 my $value = $part_svc_column->columnvalue;
258 my $flag = $part_svc_column->columnflag;
259 my $def = $defs{$layer}{$field};
260 my $desc = ref($def) ? $def->{desc} : $def;
262 if ( $bgcolor eq $bgcolor1 ) {
263 $bgcolor = $bgcolor2;
265 $bgcolor = $bgcolor1;
268 $html .= qq!<TR><TD CLASS="grid" BGCOLOR="$bgcolor" ALIGN="right">!.
270 $html .= "- <FONT SIZE=-1>$desc</FONT>" if $desc;
272 $flag = '' if ref($def) && $def->{type} eq 'disabled';
274 $html .= qq!<TD CLASS="grid" BGCOLOR="$bgcolor">!;
276 if ( ref($def) && $def->{type} eq 'disabled' ) {
278 $html .= 'No default';
282 $html .= qq!<SELECT NAME="${layer}__${field}_flag"!.
283 qq! onChange="${layer}__${field}_flag_changed(this)">!;
285 foreach my $f ( keys %flag ) {
287 #here is where the SUB from above is called, to skip some choices
288 next if $flag{$f}->{condition}
289 && &{ $flag{$f}->{condition} }( $def, $layer, $field );
291 $html .= qq!<OPTION VALUE="$f"!.
292 ' SELECTED'x($flag eq $f ).
293 '>'. $flag{$f}->{desc};
297 $html .= '</SELECT>';
301 " function ${layer}__${field}_flag_changed(what) {",
302 ' var f = what.options[what.selectedIndex].value;',
303 ' if ( f == "" || f == "X" ) { //disable',
304 " what.form.${layer}__${field}.disabled = true;".
305 " what.form.${layer}__${field}.style.backgroundColor = '#dddddd';".
306 " if ( what.form.${layer}__${field}_classnum ) {".
307 " what.form.${layer}__${field}_classnum.disabled = true;".
308 " what.form.${layer}__${field}_classnum.style.backgroundColor = '#dddddd';".
310 ' } else if ( f == "D" || f == "F" ) { //enable, text box',
311 " what.form.${layer}__${field}.disabled = false;".
312 " what.form.${layer}__${field}.style.backgroundColor = '#ffffff';".
313 " what.form.${layer}__${field}.style.display = '';".
314 " if ( what.form.${layer}__${field}_classnum ) {".
315 " what.form.${layer}__${field}_classnum.disabled = false;".
316 " what.form.${layer}__${field}_classnum.style.backgroundColor = '#ffffff';".
317 " what.form.${layer}__${field}_classnum.style.display = 'none';".
319 ' } else if ( f == "M" || f == "A" ) { //enable, inventory',
320 " what.form.${layer}__${field}.disabled = false;".
321 " what.form.${layer}__${field}.style.backgroundColor = '#ffffff';".
322 " what.form.${layer}__${field}.style.display = 'none';".
323 " if ( what.form.${layer}__${field}_classnum ) {".
324 " what.form.${layer}__${field}_classnum.disabled = false;".
325 " what.form.${layer}__${field}_classnum.style.backgroundColor = '#ffffff';".
326 " what.form.${layer}__${field}_classnum.style.display = '';".
335 $html .= qq!</TD><TD CLASS="grid" BGCOLOR="$bgcolor">!;
337 my $disabled = $flag ? ''
338 : 'DISABLED STYLE="background-color: #dddddd"';
340 if ( ! ref($def) || $def->{type} eq 'text' ) {
342 my $nodisplay = ' STYLE="display:none"';
343 my $is_inv = ( $flag =~ /^[MA]$/ );
346 qq!<INPUT TYPE="text" NAME="${layer}__${field}" VALUE="$value" !.
348 ( $is_inv ? $nodisplay : $disabled ).
351 $html .= include('/elements/select-table.html',
352 'element_name' => "${layer}__${field}_classnum",
353 'element_etc' => ( $is_inv
357 'table' => 'inventory_class',
358 'name_col' => 'classname',
360 'empty_label' => 'Select inventory class',
363 } elsif ( $def->{type} eq 'select' ) {
365 $html .= qq!<SELECT NAME="${layer}__${field}" $disabled>!;
366 $html .= '<OPTION> </OPTION>' unless $value;
367 if ( $def->{select_table} ) {
368 foreach my $record ( qsearch( $def->{select_table}, {} ) ) {
369 my $rvalue = $record->getfield($def->{select_key});
370 $html .= qq!<OPTION VALUE="$rvalue"!.
371 ( $rvalue==$value ? ' SELECTED>' : '>' ).
372 $record->getfield($def->{select_label}). '</OPTION>';
374 } else { # select_list
375 foreach my $item ( @{$def->{select_list}} ) {
376 $html .= qq!<OPTION VALUE="$item"!.
377 ( $item eq $value ? ' SELECTED>' : '>' ).
381 $html .= '</SELECT>';
383 } elsif ( $def->{type} eq 'radius_usergroup_selector' ) {
385 #XXX disable the RADIUS usergroup selector? ugh it sure does need
386 #an overhaul, people have dum group problems because of it
388 $html .= FS::svc_acct::radius_usergroup_selector(
389 [ split(',', $value) ], "${layer}__${field}" );
391 } elsif ( $def->{type} eq 'disabled' ) {
394 qq!<INPUT TYPE="hidden" NAME="${layer}__${field}" VALUE="">!;
398 $html .= '<font color="#ff0000">unknown type'. $def->{type};
402 $html .= "</TD></TR>\n";
404 } #foreach my $field (@fields) {
406 $part_svc->svcpart('') if $clone; #undone
409 $html .= include('/elements/progress-init.html',
411 [ qw(svc svcpart disabled exportnum), @fields ],
412 'process/part_svc.cgi',
413 $p.'browse/part_svc.cgi',
416 $html .= '<BR><INPUT NAME="submit" TYPE="button" VALUE="'.
417 ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '" '.
418 ' onClick="document.'. "$layer.submit.disabled=true; ".
419 "fixup(document.$layer); $layer". 'process();">';
421 #$html .= '<BR><INPUT TYPE="submit" VALUE="'.
422 # ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '">';
430 Table <%= $widget->html %>