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()\""
27 <% include("/elements/header.html","$action Service Definition",
28 menubar( 'Main Menu' => $p,
29 'View all service definitions' => "${p}browse/part_svc.cgi"
36 Service Part #<% $part_svc->svcpart ? $part_svc->svcpart : "(NEW)" %>
38 Service <INPUT TYPE="text" NAME="svc" VALUE="<% $hashref->{svc} %>"><BR>
39 Disable new orders <INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<% $hashref->{disabled} eq 'Y' ? ' CHECKED' : '' %>><BR>
40 <INPUT TYPE="hidden" NAME="svcpart" VALUE="<% $hashref->{svcpart} %>">
42 Service definitions are the templates for items you offer to your customers.
43 <UL><LI>svc_acct - Accounts - anything with a username (Mailboxes, PPP accounts, shell accounts, RADIUS entries for broadband, etc.)
44 <LI>svc_domain - Domains
45 <LI>svc_forward - mail forwarding
46 <LI>svc_www - Virtual domain website
47 <LI>svc_broadband - Broadband/High-speed Internet service (always-on)
48 <LI>svc_phone - Customer phone numbers
49 <LI>svc_external - Externally-tracked service
50 <!-- <LI>svc_charge - One-time charges (Partially unimplemented)
51 <LI>svc_wo - Work orders (Partially unimplemented)
54 For the selected table, you can give fields default or fixed (unchangable)
55 values, or select an inventory class to manually or automatically fill in
60 %#these might belong somewhere else for other user interfaces
61 %#pry need to eventually create stuff that's shared amount UIs
62 %my $conf = new FS::Conf;
66 % 'dir' => 'Home directory',
67 % 'uid' => 'UID (set to fixed and blank for no UIDs)',
68 % 'slipip' => 'IP address',
69 %# 'popnum' => qq!<A HREF="$p/browse/svc_acct_pop.cgi/">POP number</A>!,
71 % desc => 'Access number',
73 % select_table => 'svc_acct_pop',
74 % select_key => 'popnum',
75 % select_label => 'city',
76 % disable_select => 1,
81 % disable_default => 1,
83 % disable_select => 1,
88 % disable_inventory => 1,
89 % disable_select => 1,
91 % '_password' => 'Password',
92 % 'gid' => 'GID (when blank, defaults to UID)',
94 % #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)',
95 % desc =>'Shell ( set to blank for no shell tracking)',
97 % select_list => [ $conf->config('shells') ],
98 % disable_inventory => 1,
99 % disable_select => 1,
101 % 'finger' => 'Real name (GECOS)',
103 % desc =>'svcnum from svc_domain',
105 % select_table => 'svc_domain',
106 % select_key => 'svcnum',
107 % select_label => 'domain',
108 % disable_inventory => 1,
109 % disable_select => 1,
112 % desc =>'RADIUS groups',
113 % type =>'radius_usergroup_selector',
114 % disable_select => 1,
115 % disable_inventory => 1,
117 % 'seconds' => { desc => '',
119 % disable_inventory => 1,
120 % disable_select => 1,
125 % 'domain' => 'Domain',
129 % 'srcsvc' => 'service from which mail is to be forwarded',
130 % 'dstsvc' => 'service to which mail is to be forwarded',
131 % 'dst' => 'someone@another.domain.com to use when dstsvc is 0',
135 %# 'amount' => 'amount',
138 %# 'worker' => 'Worker',
139 %# '_date' => 'Date',
147 % 'svc_broadband' => {
148 % 'speed_down' => 'Maximum download speed for this service in Kbps. 0 denotes unlimited.',
149 % 'speed_up' => 'Maximum upload speed for this service in Kbps. 0 denotes unlimited.',
150 % 'ip_addr' => 'IP address. Leave blank for automatic assignment.',
151 % 'blocknum' => 'Address block.',
155 % 'countrycode' => { desc => 'Country code',
157 % disable_inventory => 1,
158 % disable_select => 1,
160 % 'phonenum' => 'Phone number',
161 % 'pin' => { desc => 'Personal Identification Number',
163 % disable_inventory => 1,
164 % disable_select => 1,
168 % 'svc_external' => {
176 % foreach my $svcdb (grep dbdef->table($_), keys %defs ) {
177 % my $self = "FS::$svcdb"->new;
178 % $vfields{$svcdb} = {};
179 % foreach my $field ($self->virtual_fields) { # svc_Common::virtual_fields with a null svcpart returns all of them
180 % my $pvf = $self->pvf($field);
181 % my @list = $pvf->list;
182 % if (scalar @list) {
183 % $defs{$svcdb}->{$field} = { desc => $pvf->label,
185 % select_list => \@list };
187 % $defs{$svcdb}->{$field} = $pvf->label;
189 % $vfields{$svcdb}->{$field} = $pvf;
190 % warn "\$vfields{$svcdb}->{$field} = $pvf";
194 % #code duplication w/ edit/part_svc.cgi, should move this hash to part_svc.pm
195 % # and generalize the subs
196 % # condition sub is tested to see whether to disable display of this choice
197 % # params: ( $def, $layer, $field ) (see SUB below)
198 % my $inv_sub = sub {
199 % ref($_[0]) && ( $_[0]->{disable_inventory}
200 % || $_[0]->{'type'} ne 'text' )
202 % tie my %flag, 'Tie::IxHash',
203 % '' => { 'desc' => 'No default', },
204 % 'D' => { 'desc' => 'Default',
206 % sub { ref($_[0]) && $_[0]->{disable_default} },
208 % 'F' => { 'desc' => 'Fixed (unchangeable)',
210 % sub { ref($_[0]) && $_[0]->{disable_fixed} },
212 % 'S' => { 'desc' => 'Selectable Choice',
214 % sub { !ref($_[0]) || $_[0]->{disable_select} },
216 %# need to template-ize httemplate/edit/svc_* first
217 %# 'M' => { 'desc' => 'Manual selection from inventory',
218 %# 'condition' => $inv_sub,
220 % 'A' => { 'desc' => 'Automatically fill in from inventory',
221 % 'condition' => $inv_sub,
223 % 'X' => { 'desc' => 'Excluded',
225 % sub { ! $vfields{$_[1]}->{$_[2]} },
230 % my @dbs = $hashref->{svcdb}
231 % ? ( $hashref->{svcdb} )
232 % : qw( svc_acct svc_domain svc_forward svc_www svc_broadband svc_phone svc_external );
234 % tie my %svcdb, 'Tie::IxHash', map { $_=>$_ } grep dbdef->table($_), @dbs;
235 % my $widget = new HTML::Widgets::SelectLayers(
236 % #'selected_layer' => $p_svcdb,
237 % 'selected_layer' => $hashref->{svcdb} || 'svc_acct',
238 % 'options' => \%svcdb,
239 % 'form_name' => 'dummy',
240 % #'form_action' => 'process/part_svc.cgi',
241 % 'form_action' => 'part_svc.cgi', #self
242 % 'form_text' => [ qw( svc svcpart ) ],
243 % 'form_checkbox' => [ 'disabled' ],
244 % 'layer_callback' => sub {
247 % my $html = qq!<INPUT TYPE="hidden" NAME="svcdb" VALUE="$layer">!;
252 % map { qsearch( 'part_export', {exporttype => $_ } ) }
253 % keys %{FS::part_export::export_info($layer)};
254 % $html .= '<BR><BR>'. table().
255 % "<TR><TH COLSPAN=$columns>Exports</TH></TR><TR>";
256 % foreach my $part_export ( @part_export ) {
257 % $html .= '<TD><INPUT TYPE="checkbox"'.
258 % ' NAME="exportnum'. $part_export->exportnum. '" VALUE="1" ';
260 % if ( $clone || $part_svc->svcpart ) #null svcpart search causing error
261 % && qsearchs( 'export_svc', {
262 % exportnum => $part_export->exportnum,
263 % svcpart => $clone || $part_svc->svcpart });
264 % $html .= '>'. $part_export->exportnum. ': '. $part_export->exporttype.
265 % ' to '. $part_export->machine. '</TD>';
267 % $html .= '</TR><TR>' unless $count % $columns;
269 % $html .= '</TR></TABLE><BR><BR>';
271 % $html .= include('/elements/table-grid.html', 'cellpadding' => 4 ).
273 % '<TH CLASS="grid" BGCOLOR="#cccccc">Field</TH>'.
274 % '<TH CLASS="grid" BGCOLOR="#cccccc" COLSPAN=2>Modifier</TH>'.
277 % my $bgcolor1 = '#eeeeee';
278 % my $bgcolor2 = '#ffffff';
282 % my @fields = defined( dbdef->table($layer) )
283 % ? grep { $_ ne 'svcnum' } fields($layer)
285 % push @fields, 'usergroup' if $layer eq 'svc_acct'; #kludge
286 % $part_svc->svcpart($clone) if $clone; #haha, undone below
289 % foreach my $field (@fields) {
291 % my $part_svc_column = $part_svc->part_svc_column($field);
292 % my $value = $part_svc_column->columnvalue;
293 % my $flag = $part_svc_column->columnflag;
294 % my $def = $defs{$layer}{$field};
295 % my $desc = ref($def) ? $def->{desc} : $def;
297 % if ( $bgcolor eq $bgcolor1 ) {
298 % $bgcolor = $bgcolor2;
300 % $bgcolor = $bgcolor1;
303 % $html .= qq!<TR><TD CLASS="grid" BGCOLOR="$bgcolor" ALIGN="right">!.
305 % $html .= "- <FONT SIZE=-1>$desc</FONT>" if $desc;
307 % $flag = '' if ref($def) && $def->{type} eq 'disabled';
309 % $html .= qq!<TD CLASS="grid" BGCOLOR="$bgcolor">!;
311 % if ( ref($def) && $def->{type} eq 'disabled' ) {
313 % $html .= 'No default';
317 % $html .= qq!<SELECT NAME="${layer}__${field}_flag"!.
318 % qq! onChange="${layer}__${field}_flag_changed(this)">!;
320 % foreach my $f ( keys %flag ) {
322 % #here is where the SUB from above is called, to skip some choices
323 % next if $flag{$f}->{condition}
324 % && &{ $flag{$f}->{condition} }( $def, $layer, $field );
326 % $html .= qq!<OPTION VALUE="$f"!.
327 % ' SELECTED'x($flag eq $f ).
328 % '>'. $flag{$f}->{desc};
332 % $html .= '</SELECT>';
334 % $html .= join("\n",
336 % " function ${layer}__${field}_flag_changed(what) {",
337 % ' var f = what.options[what.selectedIndex].value;',
338 % ' if ( f == "" || f == "X" ) { //disable',
339 % " what.form.${layer}__${field}.disabled = true;".
340 % " what.form.${layer}__${field}.style.backgroundColor = '#dddddd';".
341 % " if ( what.form.${layer}__${field}_classnum ) {".
342 % " what.form.${layer}__${field}_classnum.disabled = true;".
343 % " what.form.${layer}__${field}_classnum.style.backgroundColor = '#dddddd';".
345 % ' } else if ( f == "D" || f == "F" || f =="S" ) { //enable, text box',
346 % " what.form.${layer}__${field}.disabled = false;".
347 % " what.form.${layer}__${field}.style.backgroundColor = '#ffffff';".
348 % " what.form.${layer}__${field}.style.display = '';".
349 % " if ( what.form.${layer}__${field}_classnum ) {".
350 % " what.form.${layer}__${field}_classnum.disabled = false;".
351 % " what.form.${layer}__${field}_classnum.style.backgroundColor = '#ffffff';".
352 % " what.form.${layer}__${field}_classnum.style.display = 'none';".
354 % ' } else if ( f == "M" || f == "A" ) { //enable, inventory',
355 % " what.form.${layer}__${field}.disabled = false;".
356 % " what.form.${layer}__${field}.style.backgroundColor = '#ffffff';".
357 % " what.form.${layer}__${field}.style.display = 'none';".
358 % " if ( what.form.${layer}__${field}_classnum ) {".
359 % " what.form.${layer}__${field}_classnum.disabled = false;".
360 % " what.form.${layer}__${field}_classnum.style.backgroundColor = '#ffffff';".
361 % " what.form.${layer}__${field}_classnum.style.display = '';".
370 % $html .= qq!</TD><TD CLASS="grid" BGCOLOR="$bgcolor">!;
372 % my $disabled = $flag ? ''
373 % : 'DISABLED STYLE="background-color: #dddddd"';
375 % if ( ! ref($def) || $def->{type} eq 'text' ) {
377 % my $nodisplay = ' STYLE="display:none"';
378 % my $is_inv = ( $flag =~ /^[MA]$/ );
381 % qq!<INPUT TYPE="text" NAME="${layer}__${field}" VALUE="$value" !.
383 % ( $is_inv ? $nodisplay : $disabled ).
386 % $html .= include('/elements/select-table.html',
387 % 'element_name' => "${layer}__${field}_classnum",
388 % 'element_etc' => ( $is_inv
392 % 'table' => 'inventory_class',
393 % 'name_col' => 'classname',
395 % 'empty_label' => 'Select inventory class',
398 % } elsif ( $def->{type} eq 'select' ) {
400 % $html .= qq!<SELECT NAME="${layer}__${field}" $disabled!;
401 % $html .= ' multiple' if $flag == 'S';
403 % $html .= '<OPTION> </OPTION>' unless $value;
404 % if ( $def->{select_table} ) {
405 % foreach my $record ( qsearch( $def->{select_table}, {} ) ) {
406 % my $rvalue = $record->getfield($def->{select_key});
407 % $html .= qq!<OPTION VALUE="$rvalue"!.
408 % (grep(/^$rvalue$/, split(',',$value)) ? ' SELECTED>' : '>' ).
409 % $record->getfield($def->{select_label}). '</OPTION>';
411 % } else { # select_list
412 % foreach my $item ( @{$def->{select_list}} ) {
413 % $html .= qq!<OPTION VALUE="$item"!.
414 % (grep(/^$item$/, split(',',$value)) ? ' SELECTED>' : '>' ).
415 % $item. '</OPTION>';
418 % $html .= '</SELECT>';
420 % } elsif ( $def->{type} eq 'radius_usergroup_selector' ) {
422 % #XXX disable the RADIUS usergroup selector? ugh it sure does need
423 % #an overhaul, people have dum group problems because of it
425 % $html .= FS::svc_acct::radius_usergroup_selector(
426 % [ split(',', $value) ], "${layer}__${field}" );
428 % } elsif ( $def->{type} eq 'disabled' ) {
431 % qq!<INPUT TYPE="hidden" NAME="${layer}__${field}" VALUE="">!;
435 % $html .= '<font color="#ff0000">unknown type'. $def->{type};
439 % $html .= "</TD></TR>\n";
441 % } #foreach my $field (@fields) {
443 % $part_svc->svcpart('') if $clone; #undone
444 % $html .= "</TABLE>";
446 % $html .= include('/elements/progress-init.html',
448 % [ qw(svc svcpart disabled exportnum), @fields ],
449 % 'process/part_svc.cgi',
450 % $p.'browse/part_svc.cgi',
453 % $html .= '<BR><INPUT NAME="submit" TYPE="button" VALUE="'.
454 % ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '" '.
455 % ' onClick="document.'. "$layer.submit.disabled=true; ".
456 % "fixup(document.$layer); $layer". 'process();">';
458 % #$html .= '<BR><INPUT TYPE="submit" VALUE="'.
459 % # ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '">';
468 Table <% $widget->html %>