1 <% include('/elements/header.html', "$action Service Definition",
2 menubar('View all service definitions' => "${p}browse/part_svc.cgi"),
3 #" onLoad=\"visualize()\""
9 Service Part #<% $part_svc->svcpart ? $part_svc->svcpart : "(NEW)" %>
11 Service <INPUT TYPE="text" NAME="svc" VALUE="<% $hashref->{svc} %>"><BR>
12 Disable new orders <INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<% $hashref->{disabled} eq 'Y' ? ' CHECKED' : '' %>><BR>
13 <INPUT TYPE="hidden" NAME="svcpart" VALUE="<% $hashref->{svcpart} %>">
15 Service definitions are the templates for items you offer to your customers.
16 <UL><LI>svc_acct - Accounts - anything with a username (Mailboxes, PPP accounts, shell accounts, RADIUS entries for broadband, etc.)
17 <LI>svc_domain - Domains
18 <LI>svc_forward - mail forwarding
19 <LI>svc_www - Virtual domain website
20 <LI>svc_broadband - Broadband/High-speed Internet service (always-on)
21 <LI>svc_phone - Customer phone numbers
22 <LI>svc_external - Externally-tracked service
23 <!-- <LI>svc_charge - One-time charges (Partially unimplemented)
24 <LI>svc_wo - Work orders (Partially unimplemented)
27 For the selected table, you can give fields default or fixed (unchangable)
28 values, or select an inventory class to manually or automatically fill in
32 % #YUCK. false laziness w/part_svc.pm. go away virtual fields, please
34 % foreach my $svcdb ( FS::part_svc->svc_tables() ) {
35 % eval "use FS::$svcdb;";
36 % my $self = "FS::$svcdb"->new;
37 % $vfields{$svcdb} = {};
38 % foreach my $field ($self->virtual_fields) { # svc_Common::virtual_fields with a null svcpart returns all of them
39 % my $pvf = $self->pvf($field);
40 % $vfields{$svcdb}->{$field} = $pvf;
41 % #warn "\$vfields{$svcdb}->{$field} = $pvf";
45 % #code duplication w/ edit/part_svc.cgi, should move this hash to part_svc.pm
46 % # and generalize the subs
47 % # condition sub is tested to see whether to disable display of this choice
48 % # params: ( $def, $layer, $field ) (see SUB below)
50 % $_[0]->{disable_inventory}
51 % || $_[0]->{'type'} ne 'text'
53 % tie my %flag, 'Tie::IxHash',
54 % '' => { 'desc' => 'No default', },
55 % 'D' => { 'desc' => 'Default',
57 % sub { $_[0]->{disable_default} },
59 % 'F' => { 'desc' => 'Fixed (unchangeable)',
61 % sub { $_[0]->{disable_fixed} },
63 % 'S' => { 'desc' => 'Selectable Choice',
65 % sub { !ref($_[0]) || $_[0]->{disable_select} },
67 %# need to template-ize httemplate/edit/svc_* first
68 %# 'M' => { 'desc' => 'Manual selection from inventory',
69 %# 'condition' => $inv_sub,
71 % 'A' => { 'desc' => 'Automatically fill in from inventory',
72 % 'condition' => $inv_sub,
74 % 'X' => { 'desc' => 'Excluded',
76 % sub { ! $vfields{$_[1]}->{$_[2]} },
81 % my @dbs = $hashref->{svcdb}
82 % ? ( $hashref->{svcdb} )
83 % : FS::part_svc->svc_tables();
85 % tie my %svcdb, 'Tie::IxHash', map { $_=>$_ } grep dbdef->table($_), @dbs;
86 % my $widget = new HTML::Widgets::SelectLayers(
87 % #'selected_layer' => $p_svcdb,
88 % 'selected_layer' => $hashref->{svcdb} || 'svc_acct',
89 % 'options' => \%svcdb,
90 % 'form_name' => 'dummy',
91 % #'form_action' => 'process/part_svc.cgi',
92 % 'form_action' => 'part_svc.cgi', #self
93 % 'form_text' => [ qw( svc svcpart ) ],
94 % 'form_checkbox' => [ 'disabled' ],
95 % 'layer_callback' => sub {
98 % my $html = qq!<INPUT TYPE="hidden" NAME="svcdb" VALUE="$layer">!;
103 % map { qsearch( 'part_export', {exporttype => $_ } ) }
104 % keys %{FS::part_export::export_info($layer)};
105 % $html .= '<BR><BR>'. table().
106 % "<TR><TH COLSPAN=$columns>Exports</TH></TR><TR>";
107 % foreach my $part_export ( @part_export ) {
108 % $html .= '<TD><INPUT TYPE="checkbox"'.
109 % ' NAME="exportnum'. $part_export->exportnum. '" VALUE="1" ';
111 % if ( $clone || $part_svc->svcpart ) #null svcpart search causing error
112 % && qsearchs( 'export_svc', {
113 % exportnum => $part_export->exportnum,
114 % svcpart => $clone || $part_svc->svcpart });
115 % $html .= '>'. $part_export->exportnum. ': '. $part_export->exporttype.
116 % ' to '. $part_export->machine. '</TD>';
118 % $html .= '</TR><TR>' unless $count % $columns;
120 % $html .= '</TR></TABLE><BR><BR>';
122 % $html .= include('/elements/table-grid.html', 'cellpadding' => 4 ).
124 % '<TH CLASS="grid" BGCOLOR="#cccccc">Field</TH>'.
125 % '<TH CLASS="grid" BGCOLOR="#cccccc" COLSPAN=2>Modifier</TH>'.
128 % my $bgcolor1 = '#eeeeee';
129 % my $bgcolor2 = '#ffffff';
133 % my @fields = defined( dbdef->table($layer) )
134 % ? grep { $_ ne 'svcnum' } fields($layer)
136 % push @fields, 'usergroup' if $layer eq 'svc_acct'; #kludge
137 % $part_svc->svcpart($clone) if $clone; #haha, undone below
140 % foreach my $field (@fields) {
142 % #my $def = $defs{$layer}{$field};
143 % my $def = FS::part_svc->svc_table_fields($layer)->{$field};
144 % my $label = $def->{'def_label'} || $def->{'label'};
145 % my $formatter = $def->{'format'} || sub { shift };
146 % my $part_svc_column = $part_svc->part_svc_column($field);
147 % my $value = &$formatter($part_svc_column->columnvalue);
148 % my $flag = $part_svc_column->columnflag;
150 % if ( $bgcolor eq $bgcolor1 ) {
151 % $bgcolor = $bgcolor2;
153 % $bgcolor = $bgcolor1;
156 % $html .= qq!<TR><TD CLASS="grid" BGCOLOR="$bgcolor" ALIGN="right">!.
157 % ( $label || $field ).
159 % $flag = '' if $def->{type} eq 'disabled';
161 % $html .= qq!<TD CLASS="grid" BGCOLOR="$bgcolor">!;
163 % if ( $def->{type} eq 'disabled' ) {
165 % $html .= 'No default';
169 % $html .= qq!<SELECT NAME="${layer}__${field}_flag"!.
170 % qq! onChange="${layer}__${field}_flag_changed(this)">!;
172 % foreach my $f ( keys %flag ) {
174 % #here is where the SUB from above is called, to skip some choices
175 % next if $flag{$f}->{condition}
176 % && &{ $flag{$f}->{condition} }( $def, $layer, $field );
178 % $html .= qq!<OPTION VALUE="$f"!.
179 % ' SELECTED'x($flag eq $f ).
180 % '>'. $flag{$f}->{desc};
184 % $html .= '</SELECT>';
186 % $html .= join("\n",
188 % " function ${layer}__${field}_flag_changed(what) {",
189 % ' var f = what.options[what.selectedIndex].value;',
190 % ' if ( f == "" || f == "X" ) { //disable',
191 % " what.form.${layer}__${field}.disabled = true;".
192 % " what.form.${layer}__${field}.style.backgroundColor = '#dddddd';".
193 % " if ( what.form.${layer}__${field}_classnum ) {".
194 % " what.form.${layer}__${field}_classnum.disabled = true;".
195 % " what.form.${layer}__${field}_classnum.style.backgroundColor = '#dddddd';".
197 % ' } else if ( f == "D" || f == "F" || f =="S" ) { //enable, text box',
198 % " what.form.${layer}__${field}.disabled = false;".
199 % " what.form.${layer}__${field}.style.backgroundColor = '#ffffff';".
200 % " if ( f == 'S' || '${field}' == 'usergroup' ) {". # kludge
201 % " what.form.${layer}__${field}.multiple = true;".
203 % " what.form.${layer}__${field}.multiple = false;".
205 % " what.form.${layer}__${field}.style.display = '';".
206 % " if ( what.form.${layer}__${field}_classnum ) {".
207 % " what.form.${layer}__${field}_classnum.disabled = false;".
208 % " what.form.${layer}__${field}_classnum.style.backgroundColor = '#ffffff';".
209 % " what.form.${layer}__${field}_classnum.style.display = 'none';".
211 % ' } else if ( f == "M" || f == "A" ) { //enable, inventory',
212 % " what.form.${layer}__${field}.disabled = false;".
213 % " what.form.${layer}__${field}.style.backgroundColor = '#ffffff';".
214 % " what.form.${layer}__${field}.style.display = 'none';".
215 % " if ( what.form.${layer}__${field}_classnum ) {".
216 % " what.form.${layer}__${field}_classnum.disabled = false;".
217 % " what.form.${layer}__${field}_classnum.style.backgroundColor = '#ffffff';".
218 % " what.form.${layer}__${field}_classnum.style.display = '';".
227 % $html .= qq!</TD><TD CLASS="grid" BGCOLOR="$bgcolor">!;
229 % my $disabled = $flag ? ''
230 % : 'DISABLED STYLE="background-color: #dddddd"';
232 % if ( !$def->{type} || $def->{type} eq 'text' ) {
234 % my $nodisplay = ' STYLE="display:none"';
235 % my $is_inv = ( $flag =~ /^[MA]$/ );
238 % qq!<INPUT TYPE="text" NAME="${layer}__${field}" VALUE="$value" !.
240 % ( $is_inv ? $nodisplay : $disabled ).
243 % $html .= include('/elements/select-table.html',
244 % 'element_name' => "${layer}__${field}_classnum",
245 % 'element_etc' => ( $is_inv
249 % 'table' => 'inventory_class',
250 % 'name_col' => 'classname',
252 % 'empty_label' => 'Select inventory class',
255 % } elsif ( $def->{type} eq 'select' ) {
257 % $html .= qq!<SELECT NAME="${layer}__${field}" $disabled!;
258 % $html .= ' MULTIPLE' if $flag eq 'S';
260 % $html .= '<OPTION> </OPTION>' unless $value;
261 % if ( $def->{select_table} ) {
262 % foreach my $record ( qsearch( $def->{select_table}, {} ) ) {
263 % my $rvalue = $record->getfield($def->{select_key});
264 % $html .= qq!<OPTION VALUE="$rvalue"!.
265 % (grep(/^$rvalue$/, split(',',$value)) ? ' SELECTED>' : '>' ).
266 % $record->getfield($def->{select_label}). '</OPTION>';
268 % } else { # select_list
269 % foreach my $item ( @{$def->{select_list}} ) {
270 % $html .= qq!<OPTION VALUE="$item"!.
271 % (grep(/^$item$/, split(',',$value)) ? ' SELECTED>' : '>' ).
272 % $item. '</OPTION>';
275 % $html .= '</SELECT>';
277 % } elsif ( $def->{type} eq 'radius_usergroup_selector' ) {
279 % #XXX disable the RADIUS usergroup selector? ugh it sure does need
280 % #an overhaul, people have dum group problems because of it
282 % $html .= FS::svc_acct::radius_usergroup_selector(
283 % [ split(',', $value) ], "${layer}__${field}" );
285 % } elsif ( $def->{type} eq 'disabled' ) {
288 % qq!<INPUT TYPE="hidden" NAME="${layer}__${field}" VALUE="">!;
292 % $html .= '<font color="#ff0000">unknown type'. $def->{type};
296 % $html .= "</TD></TR>\n";
298 % } #foreach my $field (@fields) {
300 % $part_svc->svcpart('') if $clone; #undone
301 % $html .= "</TABLE>";
303 % $html .= include('/elements/progress-init.html',
305 % [ qw(svc svcpart disabled exportnum), @fields ],
306 % 'process/part_svc.cgi',
307 % $p.'browse/part_svc.cgi',
310 % $html .= '<BR><INPUT NAME="submit" TYPE="button" VALUE="'.
311 % ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '" '.
312 % ' onClick="document.'. "$layer.submit.disabled=true; ".
313 % "fixup(document.$layer); $layer". 'process();">';
315 % #$html .= '<BR><INPUT TYPE="submit" VALUE="'.
316 % # ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '">';
325 Table <% $widget->html %>
327 <% include('/elements/footer.html') %>
332 unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
336 if ( $cgi->param('clone') && $cgi->param('clone') =~ /^(\d+)$/ ) {#clone
337 #$cgi->param('clone') =~ /^(\d+)$/ or die "malformed query: $query";
338 $part_svc = qsearchs('part_svc', { 'svcpart'=>$1 } )
339 or die "unknown svcpart: $1";
340 $clone = $part_svc->svcpart;
341 $part_svc->svcpart('');
342 } elsif ( $cgi->keywords ) { #edit
343 my($query) = $cgi->keywords;
344 $query =~ /^(\d+)$/ or die "malformed query: $query";
345 $part_svc=qsearchs('part_svc', { 'svcpart'=>$1 } )
346 or die "unknown svcpart: $1";
348 $part_svc = new FS::part_svc {};
351 my $action = $part_svc->svcpart ? 'Edit' : 'Add';
352 my $hashref = $part_svc->hashref;
353 # my $p_svcdb = $part_svc->svcdb || 'svc_acct';