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_mailinglist - Mailing list
20 <LI>svc_www - Virtual domain website
21 <LI>svc_broadband - Broadband/High-speed Internet service (always-on)
22 <LI>svc_phone - Customer phone numbers
23 <LI>svc_pbx - Customer PBXs
24 <LI>svc_external - Externally-tracked service
25 <!-- <LI>svc_charge - One-time charges (Partially unimplemented)
26 <LI>svc_wo - Work orders (Partially unimplemented)
29 For the selected table, you can give fields default or fixed (unchangable)
30 values, or select an inventory class to manually or automatically fill in
34 % #YUCK. false laziness w/part_svc.pm. go away virtual fields, please
36 % foreach my $svcdb ( FS::part_svc->svc_tables() ) {
37 % eval "use FS::$svcdb;";
38 % my $self = "FS::$svcdb"->new;
39 % $vfields{$svcdb} = {};
40 % foreach my $field ($self->virtual_fields) { # svc_Common::virtual_fields with a null svcpart returns all of them
41 % my $pvf = $self->pvf($field);
42 % $vfields{$svcdb}->{$field} = $pvf;
43 % #warn "\$vfields{$svcdb}->{$field} = $pvf";
47 % #code duplication w/ edit/part_svc.cgi, should move this hash to part_svc.pm
48 % # and generalize the subs
49 % # condition sub is tested to see whether to disable display of this choice
50 % # params: ( $def, $layer, $field ) (see SUB below)
52 % $_[0]->{disable_inventory}
53 % || $_[0]->{'type'} ne 'text'
55 % tie my %flag, 'Tie::IxHash',
56 % '' => { 'desc' => 'No default', },
57 % 'D' => { 'desc' => 'Default',
59 % sub { $_[0]->{disable_default} },
61 % 'F' => { 'desc' => 'Fixed (unchangeable)',
63 % sub { $_[0]->{disable_fixed} },
65 % 'S' => { 'desc' => 'Selectable Choice',
67 % sub { !ref($_[0]) || $_[0]->{disable_select} },
69 % 'M' => { 'desc' => 'Manual selection from inventory',
70 % 'condition' => $inv_sub,
72 % 'A' => { 'desc' => 'Automatically fill in from inventory',
73 % 'condition' => $inv_sub,
75 % 'X' => { 'desc' => 'Excluded',
77 % sub { ! $vfields{$_[1]}->{$_[2]} },
82 % my @dbs = $hashref->{svcdb}
83 % ? ( $hashref->{svcdb} )
84 % : FS::part_svc->svc_tables();
86 % tie my %svcdb, 'Tie::IxHash', map { $_=>$_ } grep dbdef->table($_), @dbs;
87 % my $widget = new HTML::Widgets::SelectLayers(
88 % #'selected_layer' => $p_svcdb,
89 % 'selected_layer' => $hashref->{svcdb} || 'svc_acct',
90 % 'options' => \%svcdb,
91 % 'form_name' => 'dummy',
92 % #'form_action' => 'process/part_svc.cgi',
93 % 'form_action' => 'part_svc.cgi', #self
94 % 'form_text' => [ qw( svc svcpart ) ],
95 % 'form_checkbox' => [ 'disabled' ],
96 % 'layer_callback' => sub {
99 % my $html = qq!<INPUT TYPE="hidden" NAME="svcdb" VALUE="$layer">!;
104 % map { qsearch( 'part_export', {exporttype => $_ } ) }
105 % keys %{FS::part_export::export_info($layer)};
106 % $html .= '<BR><BR>'. table().
107 % "<TR><TH COLSPAN=$columns>Exports</TH></TR><TR>";
108 % foreach my $part_export ( @part_export ) {
109 % $html .= '<TD><INPUT TYPE="checkbox"'.
110 % ' NAME="exportnum'. $part_export->exportnum. '" VALUE="1" ';
112 % if ( $clone || $part_svc->svcpart ) #null svcpart search causing error
113 % && qsearchs( 'export_svc', {
114 % exportnum => $part_export->exportnum,
115 % svcpart => $clone || $part_svc->svcpart });
116 % $html .= '>'. $part_export->exportnum. ': '. $part_export->exporttype.
117 % ' to '. $part_export->machine. '</TD>';
119 % $html .= '</TR><TR>' unless $count % $columns;
121 % $html .= '</TR></TABLE><BR><BR>';
123 % $html .= include('/elements/table-grid.html', 'cellpadding' => 4 ).
125 % '<TH CLASS="grid" BGCOLOR="#cccccc">Field</TH>'.
126 % '<TH CLASS="grid" BGCOLOR="#cccccc">Label</TH>'.
127 % '<TH CLASS="grid" BGCOLOR="#cccccc" COLSPAN=2>Modifier</TH>'.
130 % my $bgcolor1 = '#eeeeee';
131 % my $bgcolor2 = '#ffffff';
135 % my @fields = defined( dbdef->table($layer) )
138 % ( !FS::part_svc->svc_table_fields($layer)
139 % ->{$_}->{disable_part_svc_column} ||
140 % $part_svc->part_svc_column($_)->columnflag
145 % push @fields, 'usergroup' if $layer eq 'svc_acct'; #kludge
146 % $part_svc->svcpart($clone) if $clone; #haha, undone below
149 % foreach my $field (@fields) {
151 % #a few lines of false laziness w/browse/part_svc.cgi
152 % my $def = FS::part_svc->svc_table_fields($layer)->{$field};
153 % my $def_info = $def->{'def_info'};
154 % my $formatter = $def->{'format'} || sub { shift };
156 % my $part_svc_column = $part_svc->part_svc_column($field);
157 % my $label = $part_svc_column->columnlabel || $def->{'label'};
158 % my $value = &$formatter($part_svc_column->columnvalue);
159 % my $flag = $part_svc_column->columnflag;
161 % if ( $bgcolor eq $bgcolor1 ) {
162 % $bgcolor = $bgcolor2;
164 % $bgcolor = $bgcolor1;
167 % $html .= qq!<TR><TD ROWSPAN=2 CLASS="grid" BGCOLOR="$bgcolor" ALIGN="right">!.
168 % ( $def->{'label'} || $field ).
171 % $html .= qq!<TD ROWSPAN=2 CLASS="grid" BGCOLOR="$bgcolor"><INPUT NAME="${layer}__${field}_label" VALUE="!. encode_entities($label). '" STYLE="text-align:right"></TD>';
173 % $flag = '' if $def->{type} eq 'disabled';
175 % $html .= qq!<TD CLASS="grid" BGCOLOR="$bgcolor">!;
177 % if ( $def->{type} eq 'disabled' ) {
179 % $html .= 'No default';
183 % $html .= qq!<SELECT NAME="${layer}__${field}_flag"!.
184 % qq! onChange="${layer}__${field}_flag_changed(this)">!;
186 % foreach my $f ( keys %flag ) {
188 % # need to template-ize more httemplate/edit/svc_* first
189 % next if $f eq 'M' and $layer !~ /^svc_(broadband|external|phone)$/;
191 % #here is where the SUB from above is called, to skip some choices
192 % next if $flag{$f}->{condition}
193 % && &{ $flag{$f}->{condition} }( $def, $layer, $field );
195 % $html .= qq!<OPTION VALUE="$f"!.
196 % ' SELECTED'x($flag eq $f ).
197 % '>'. $flag{$f}->{desc};
201 % $html .= '</SELECT>';
203 % $html .= join("\n",
205 % " function ${layer}__${field}_flag_changed(what) {",
206 % ' var f = what.options[what.selectedIndex].value;',
207 % ' if ( f == "" || f == "X" ) { //disable',
208 % " what.form.${layer}__${field}.disabled = true;".
209 % " what.form.${layer}__${field}.style.backgroundColor = '#dddddd';".
210 % " if ( what.form.${layer}__${field}_classnum ) {".
211 % " what.form.${layer}__${field}_classnum.disabled = true;".
212 % " what.form.${layer}__${field}_classnum.style.backgroundColor = '#dddddd';".
214 % ' } else if ( f == "D" || f == "F" || f =="S" ) { //enable, text box',
215 % " what.form.${layer}__${field}.disabled = false;".
216 % " what.form.${layer}__${field}.style.backgroundColor = '#ffffff';".
217 % " if ( f == 'S' || '${field}' == 'usergroup' ) {". # kludge
218 % " what.form.${layer}__${field}.multiple = true;".
220 % " what.form.${layer}__${field}.multiple = false;".
222 % " what.form.${layer}__${field}.style.display = '';".
223 % " if ( what.form.${layer}__${field}_classnum ) {".
224 % " what.form.${layer}__${field}_classnum.disabled = false;".
225 % " what.form.${layer}__${field}_classnum.style.backgroundColor = '#ffffff';".
226 % " what.form.${layer}__${field}_classnum.style.display = 'none';".
228 % ' } else if ( f == "M" || f == "A" ) { //enable, inventory',
229 % " what.form.${layer}__${field}.disabled = false;".
230 % " what.form.${layer}__${field}.style.backgroundColor = '#ffffff';".
231 % " what.form.${layer}__${field}.style.display = 'none';".
232 % " if ( what.form.${layer}__${field}_classnum ) {".
233 % " what.form.${layer}__${field}_classnum.disabled = false;".
234 % " what.form.${layer}__${field}_classnum.style.backgroundColor = '#ffffff';".
235 % " what.form.${layer}__${field}_classnum.style.display = '';".
244 % $html .= qq!</TD><TD CLASS="grid" BGCOLOR="$bgcolor">!;
246 % my $disabled = $flag ? ''
247 % : 'DISABLED STYLE="background-color: #dddddd"';
249 % if ( !$def->{type} || $def->{type} eq 'text' ) {
251 % my $nodisplay = ' STYLE="display:none"';
252 % my $is_inv = ( $flag =~ /^[MA]$/ );
255 % qq!<INPUT TYPE="text" NAME="${layer}__${field}" VALUE="$value" !.
257 % ( $is_inv ? $nodisplay : $disabled ).
260 % $html .= include('/elements/select-table.html',
261 % 'element_name' => "${layer}__${field}_classnum",
262 % 'element_etc' => ( $is_inv
266 % 'table' => 'inventory_class',
267 % 'name_col' => 'classname',
269 % 'empty_label' => 'Select inventory class',
272 % } elsif ( $def->{type} eq 'checkbox' ) {
274 % $html .= include('/elements/checkbox.html',
275 % 'field' => $layer.'__'.$field,
276 % 'curr_value' => $value,
280 % } elsif ( $def->{type} eq 'select' ) {
282 % $html .= qq!<SELECT NAME="${layer}__${field}" $disabled!;
283 % $html .= ' MULTIPLE' if $flag eq 'S';
285 % $html .= '<OPTION> </OPTION>' unless $value;
286 % if ( $def->{select_table} ) {
287 % foreach my $record ( qsearch( $def->{select_table}, {} ) ) {
288 % my $rvalue = $record->getfield($def->{select_key});
289 % my $select_label = $def->{select_label};
290 % $html .= qq!<OPTION VALUE="$rvalue"!.
291 % (grep(/^$rvalue$/, split(',',$value)) ? ' SELECTED>' : '>' ).
292 % $record->$select_label(). '</OPTION>';
294 % } else { # select_list
295 % foreach my $item ( @{$def->{select_list}} ) {
296 % $html .= qq!<OPTION VALUE="$item"!.
297 % (grep(/^$item$/, split(',',$value)) ? ' SELECTED>' : '>' ).
298 % $item. '</OPTION>';
301 % $html .= '</SELECT>';
303 % } elsif ( $def->{type} eq 'select-svc_pbx.html' ) {
305 % $html .= include('/elements/select-svc_pbx.html',
306 % 'curr_value' => $value,
307 % 'element_name' => "${layer}__${field}",
308 % 'element_etc' => $disabled,
309 % 'multiple' => ($flag eq 'S'),
312 % } elsif ( $def->{type} eq 'radius_usergroup_selector' ) {
314 % #XXX disable the RADIUS usergroup selector? ugh it sure does need
315 % #an overhaul, people have dum group problems because of it
317 % $html .= FS::svc_acct::radius_usergroup_selector(
318 % [ split(',', $value) ], "${layer}__${field}" );
320 % } elsif ( $def->{type} eq 'communigate_pro-accessmodes' ) {
322 % $html .= include('/elements/communigate_pro-accessmodes.html',
323 % 'element_name_prefix' => "${layer}__${field}_",
324 % 'curr_value' => $value,
325 % #doesn't work#'element_etc' => $disabled,
328 % } elsif ( $def->{type} eq 'disabled' ) {
331 % qq!<INPUT TYPE="hidden" NAME="${layer}__${field}" VALUE="">!;
335 % $html .= '<font color="#ff0000">unknown type '. $def->{type};
339 % $html .= "</TD></TR>\n";
341 % $def_info = "($def_info)" if $def_info;
344 % qq! <TD COLSPAN=2 BGCOLOR="$bgcolor" ALIGN="center" !.
345 % qq! STYLE="padding:0; border-top: none">!.
346 % qq! <FONT SIZE="-1"><I>$def_info</I></FONT>!.
350 % } #foreach my $field (@fields) {
352 % $part_svc->svcpart('') if $clone; #undone
353 % $html .= "</TABLE>";
355 % $html .= include('/elements/progress-init.html',
357 % [ qw(svc svcpart disabled exportnum), @fields ],
358 % 'process/part_svc.cgi',
359 % $p.'browse/part_svc.cgi',
362 % $html .= '<BR><INPUT NAME="submit" TYPE="button" VALUE="'.
363 % ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '" '.
364 % ' onClick="document.'. "$layer.submit.disabled=true; ".
365 % "fixup(document.$layer); $layer". 'process();">';
367 % #$html .= '<BR><INPUT TYPE="submit" VALUE="'.
368 % # ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '">';
377 Table <% $widget->html %>
379 <% include('/elements/footer.html') %>
384 unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
388 if ( $cgi->param('clone') && $cgi->param('clone') =~ /^(\d+)$/ ) {#clone
389 #$cgi->param('clone') =~ /^(\d+)$/ or die "malformed query: $query";
390 $part_svc = qsearchs('part_svc', { 'svcpart'=>$1 } )
391 or die "unknown svcpart: $1";
392 $clone = $part_svc->svcpart;
393 $part_svc->svcpart('');
394 } elsif ( $cgi->keywords ) { #edit
395 my($query) = $cgi->keywords;
396 $query =~ /^(\d+)$/ or die "malformed query: $query";
397 $part_svc=qsearchs('part_svc', { 'svcpart'=>$1 } )
398 or die "unknown svcpart: $1";
400 $part_svc = new FS::part_svc {};
403 my $action = $part_svc->svcpart ? 'Edit' : 'Add';
404 my $hashref = $part_svc->hashref;
405 # my $p_svcdb = $part_svc->svcdb || 'svc_acct';