1 <% include( 'elements/edit.html',
2 'name' => 'Billing event definition',
3 'table' => 'part_event',
6 { field => 'eventtable',
8 options => [ FS::part_event->eventtables ],
9 labels => $eventtable_labels,
10 onchange => 'eventtable_changed',
12 { field => 'agentnum',
13 type => 'select-agent',
14 disable_empty => $disable_empty_agent,
16 { field => 'check_freq',
18 options => [ '1d', '1m' ],
19 labels => $check_freq_labels,
21 { field => 'disabled',
26 value => 'Event Conditions',
28 { field => 'conditionname',
29 type => 'selectlayers',
30 options => [ keys %all_conditions ],
31 labels => \%condition_labels,
32 onchange => 'condition_changed(what);',
33 layer_fields => \%condition_fields,
34 layer_values_callback => $condition_layer_values,
35 html_between => n_a('action'),
36 m2name_table => 'part_event_condition',
37 m2name_namecol => 'conditionname',
38 m2name_label => 'Condition',
39 m2name_new_default => \@implicit_condition_objs,
40 m2name_error_callback =>
41 $condition_error_callback,
42 m2name_remove_warnings =>
43 \%condition_remove_warnings,
44 m2name_new_js => 'condition_repop',
45 m2name_remove_js => 'condition_add',
48 value => 'Event Action',
51 type => 'selectlayers',
52 options => [ keys %all_actions ],
53 labels => \%action_labels,
54 onchange => 'action_changed(what);',
55 layer_fields => \%action_fields,
56 layer_values_callback => $action_layer_values,
57 html_between => n_a('action'),
62 'eventpart' => 'Event',
63 'event' => 'Event name',
64 'eventtable' => 'Type',
65 'agentnum' => 'Agent',
66 'check_freq' => 'Check frequency',
67 'disabled' => 'Disable event',
69 'conditionname' => 'Add new condition',
73 'viewall_dir' => 'browse',
74 'new_callback' => sub { #start empty for new events only
75 my( $cgi, $object, $fields_listref ) = @_;
76 unshift @{ $fields_listref->[1]{'options'} }, '';
78 'error_callback' => $error_callback,
81 'agent_null_right' => 'Edit global billing events',
84 <SCRIPT TYPE="text/javascript">
86 window.onload = function () { eventtable_changed(document.getElementById('eventtable')) };
89 function eventtable_changed(what) {
92 alert('eventtable_changed called on ' + what );
95 var eventtable = what.options[what.selectedIndex].value;
97 alert ("eventtable: " + eventtable);
99 var eventdesc = what.options[what.selectedIndex].text;
101 //remove the ** Select type **
102 if ( what.options[0].value == '' && notonload++ > 0 ) {
103 what.options[0] = null;
107 // XXX gray out conditions that can't apply (in addition to the warning)?
111 // update condition selects
114 for ( var cnum=0; document.getElementById('conditionname'+cnum); cnum++ ) {
115 var cond_id = 'conditionname' + cnum;
116 var cond_select = document.getElementById(cond_id);
119 alert('updating ' + cond_id);
122 // save off the current value
123 var conditionname = cond_select.options[cond_select.selectedIndex].value;
124 var cond_desc = cond_select.options[cond_select.selectedIndex].text;
126 var seen_condition = condition_repop(cond_select);
128 var warning = document.getElementById(cond_id + '_warning');
130 alert('turning off warning; setting style.display of '+ cond_id +
131 '_warning (' + warning + ') to none');
133 warning.style.display = 'none';
135 if ( ! seen_condition && conditionname != '' ) {
136 // add the current (not valid) condition back
137 opt(cond_select, conditionname, cond_desc, true );
138 if ( ! condition_is_implicit(conditionname) ) {
139 cond_select.parentNode.parentNode.style.display = '';
140 cond_select.disabled = '';
141 // turn on a warning and gray out the condition row
143 alert('turning on warning; setting style.display of '+ cond_id +
144 '_warning (' + warning + ') to ""');
146 warning.innerHTML = 'Not applicable to ' + eventdesc + ' events';
147 warning.style.display = '';
149 if ( ! condition_in_eventtable(conditionname) ) {
151 alert(conditionname + " not in " + eventtable + "; disabling");
153 cond_select.parentNode.parentNode.style.display = 'none';
154 cond_select.disabled = 'disabled';
157 alert(conditionname + " implicit for " + eventtable + "; enabling");
159 cond_select.parentNode.parentNode.style.display = '';
160 cond_select.disabled = '';
169 // update action select
172 // save off the current value first!!
173 var action = what.form.action.options[what.form.action.selectedIndex].value;
174 var a_desc = what.form.action.options[what.form.action.selectedIndex].text;
175 var seen_action = false;
177 // blank the current action select
178 for ( var i = what.form.action.length; i >= 0; i-- )
179 what.form.action.options[i] = null;
181 if ( action == '' ) {
182 opt(what.form.action, action, a_desc, true );
186 % foreach my $eventtable ( FS::part_event->eventtables ) {
187 % tie my %actions, 'Tie::IxHash', FS::part_event->actions($eventtable);
188 % #use Data::Dumper; warn Dumper(%actions);
190 if ( eventtable == '<% $eventtable %>' ) {
192 % foreach my $action ( keys %actions ) {
193 % ( my $description = $actions{$action}->{'description'} ) =~ s/'/\\'/g;
196 if ( action == '<% $action %>' ) {
200 opt( what.form.action, '<% $action %>', '<% $description %>', sel );
207 // by default, turn off warnings and enable the submit button
208 var warning = document.getElementById('action_warning');
209 warning.style.display = 'none';
210 var submit_button = document.getElementById('submit');
211 submit_button.disabled = '';
213 if ( ! seen_action && action != '' ) {
214 // add the current (not valid) action back
215 opt( what.form.action, action, a_desc, true );
216 // turn on a warning and disable the submit button
217 //warning.innerHTML = a_desc + ' event not available as a ' +
218 warning.innerHTML = 'Not available as a ' + eventdesc + ' action';
219 warning.style.display = '';
220 submit_button.disabled = 'disabled';
225 function opt(what,value,text,selected) {
226 var optionName = new Option(text, value, false, selected);
227 var length = what.length;
228 what.options[length] = optionName;
231 function action_changed(what) {
232 // remove '** Select new **'
233 if ( what.options[0].value == '' ) {
234 what.options[0] = null;
236 // remove the warning, remove the invalid action, enable the submit button
237 var warning = document.getElementById('action_warning');
238 if ( warning.style.display == '' ) {
239 warning.style.display = 'none';
240 what.options[what.length-1] = null;
241 document.getElementById('submit').disabled = '';
245 function condition_changed(what) {
246 // remove '** Select new **'
247 if ( what.options[0].value == '' ) {
248 what.options[0] = null;
251 var previousValue = what.getAttribute('previousValue');
252 var previousText = what.getAttribute('previousText');
253 var value = what.options[what.selectedIndex].value;
254 var text = what.options[what.selectedIndex].text;
256 % foreach my $value ( keys %condition_remove_warnings ) {
257 if ( previousValue == '<% $value %>' ) {
258 if ( !confirm( <% $condition_remove_warnings{$value} |js_string %> ) ) {
259 for ( var i=0; i < what.length; i++ ) {
260 if ( what.options[i].value == previousValue ) {
261 what.selectedIndex = i;
269 //alert(previous + ' changed to ' + value);
271 var field_regex = /(\d+)$/;
272 var match = field_regex.exec(what.name);
274 alert(what.name + " didn't match?!");
278 //add the previous condition *back* to all the other selects...
279 condition_add(previousValue, previousText, match[1]);
281 what.setAttribute('previousValue', value);
282 what.setAttribute('previousText', text);
284 // remove the new condition from all other selects
285 condition_remove(value, match[1]);
289 function condition_avail(check_cond, curnum) {
290 for ( var cnum=0; document.getElementById('conditionname'+cnum); cnum++ ) {
291 if ( cnum == curnum ) continue;
293 var cond_id = 'conditionname' + cnum;
294 var cond_select = document.getElementById(cond_id);
296 //alert("checking " + cond_id + " (" + cond_select.disabled + ")");
298 if ( cond_select.disabled ) continue;
301 var conditionname = cond_select.options[cond_select.selectedIndex].value;
303 if ( check_cond == conditionname ) return false;
311 function condition_remove(remove_cond, curnum) {
313 if ( remove_cond.length == 0 ) return;
315 for ( var cnum=0; document.getElementById('conditionname'+cnum); cnum++ ) {
316 if ( cnum == curnum ) continue;
318 var cond_id = 'conditionname' + cnum;
319 var cond_select = document.getElementById(cond_id);
321 //for ( var i = cond_select.length; i >= 0; i-- ) {
322 for ( var i=0; i < cond_select.length; i++ ) {
323 if ( cond_select.options[i].value == remove_cond ) {
324 cond_select.options[i] = null;
332 function condition_add(add_condname, add_conddesc, curnum) {
334 if ( add_condname.length == 0 ) return;
336 var in_eventtable = condition_in_eventtable(add_condname);
338 if ( ! in_eventtable ) return;
340 for ( var cnum=0; document.getElementById('conditionname'+cnum); cnum++ ) {
341 if ( cnum == curnum ) continue;
343 var cond_id = 'conditionname' + cnum;
344 var cond_select = document.getElementById(cond_id);
346 if ( cond_select.disabled ) continue;
348 //alert("adding " + add_condname + " to " + cond_id);
350 opt(cond_select, add_condname, add_conddesc, false );
352 cond_select.parentNode.parentNode.style.display = '';
358 function condition_in_eventtable(condname) {
360 var eventtable_el = document.getElementById('eventtable');
361 var eventtable = eventtable_el.options[eventtable_el.selectedIndex].value;
363 var in_eventtable = false;
365 % foreach my $eventtable ( FS::part_event->eventtables ) {
366 % tie my %conditions, 'Tie::IxHash',
367 % FS::part_event_condition->conditions($eventtable);
369 if ( eventtable == '<% $eventtable %>' ) {
371 % foreach my $conditionname ( keys %conditions ) {
373 if ( condname == '<% $conditionname %>' ) {
374 in_eventtable = true;
383 return in_eventtable;
387 function condition_is_implicit(condname) {
389 if ( true <% @implicit_conditions
390 ? ( ' && '. join(' && ', map { "condname != '$_'" }
402 function condition_repop(cond_select) {
404 var eventtable_el = document.getElementById('eventtable');
405 var eventtable = eventtable_el.options[eventtable_el.selectedIndex].value;
407 // save off the current value
408 var conditionname = cond_select.options[cond_select.selectedIndex].value;
409 var cond_desc = cond_select.options[cond_select.selectedIndex].text;
410 var seen_condition = false;
412 //skip deleted conditions
413 if ( cond_select.disabled && conditionname != '' && ! condition_is_implicit(conditionname) ) {
417 var field_regex = /(\d+)$/;
418 var match = field_regex.exec(cond_select.name);
420 alert(what.name + " didn't match?!");
425 // blank the current condition select
426 for ( var i = cond_select.length; i >= 0; i-- )
427 cond_select.options[i] = null;
429 if ( conditionname == '' ) {
430 opt(cond_select, conditionname, cond_desc, true );
434 % foreach my $eventtable ( FS::part_event->eventtables ) {
435 % tie my %conditions, 'Tie::IxHash',
436 % FS::part_event_condition->conditions($eventtable);
438 if ( eventtable == '<% $eventtable %>' ) {
440 % foreach my $conditionname ( keys %conditions ) {
441 % my $description = $conditions{$conditionname}->{'description'};
442 % $description =~ s/'/\\'/g;
445 if ( conditionname == '<% $conditionname %>' ) {
446 seen_condition = true;
450 if ( condition_avail("<% $conditionname %>", cnum) ) {
451 opt(cond_select, '<% $conditionname %>', '<% $description %>', sel);
460 if ( cond_select.length > 1 || cond_select.length == 1 && cond_select.options[0].value.length > 0 ) {
462 cond_select.parentNode.parentNode.style.display = '';
463 cond_select.disabled = '';
466 cond_select.parentNode.parentNode.style.display = 'none';
467 cond_select.disabled = 'disabled';
470 return seen_condition;
477 #misc (eventtable, check_freq)
479 my $eventtable_labels = FS::part_event->eventtable_labels;
480 $eventtable_labels->{''} = '** Select type **';
482 my $check_freq_labels = FS::part_event->check_freq_labels;
486 tie my %all_conditions, 'Tie::IxHash',
487 '' => { 'description' => '*** Select new condition ***', },
488 FS::part_event_condition->conditions();
490 my %condition_labels = map { $_ => $all_conditions{$_}->{'description'} }
491 keys %all_conditions;
493 #my %condition_fields = map { $_ => $all_conditions{$_}->{option_fields} }
494 # keys %all_conditions;
495 my %condition_fields = map { my $c = $_;
496 tie my %opts, 'Tie::IxHash',
497 @{ $all_conditions{$c}->{'option_fields'} || []};
498 %opts = ( map { ( "$c.$_" => $opts{$_} ); }
503 keys %all_conditions;
505 my @implicit_conditions = sort { $all_conditions{$a}->{'implicit_flag'} <=>
506 $all_conditions{$b}->{'implicit_flag'}
508 grep { $all_conditions{$_}->{'implicit_flag'} }
509 keys %all_conditions;
511 my @implicit_condition_objs = map {
512 new FS::part_event_condition {
513 'conditionname' => $_,
516 @implicit_conditions;
518 my %condition_remove_warnings =
519 map { ( $_ => $all_conditions{$_}->{'remove_warning'} ); }
520 grep { $all_conditions{$_}->{'remove_warning'} }
521 keys %all_conditions;
525 tie my %all_actions, 'Tie::IxHash',
526 '' => { 'description' => '*** Select event action ***', },
527 FS::part_event->actions();
529 my %action_labels = map { $_ => $all_actions{$_}->{'description'} }
532 #my %action_fields = map { $_ => $all_actions{$_}->{option_fields} }
534 my %action_fields = map { my $action = $_;
535 tie my %opts, 'Tie::IxHash',
536 @{ $all_actions{$action}->{option_fields} || [] };
537 %opts = ( map { ( "$action.$_" => $opts{$_} ); }
540 ( $action => [ %opts ] );
551 qq( <FONT ID="${field}_warning" STYLE="display:none" COLOR="#FF0000">).
552 "Party Party Join us Join us".
557 my $action_layer_values = sub {
558 my( $cgi, $part_event ) = @_;
559 my $action = $cgi->param('action') || $part_event->action;
560 return {} unless $action;
561 scalar( #force hashref
563 #map { $_ => { $part_event->options } }
564 # keys %action_fields
565 map { my $action = $_;
566 my %fields = @{ $action_fields{$action} };
567 my %obj_opts = $part_event->options;
568 %obj_opts = map { ( "$action.$_" => $obj_opts{$_} ); }
571 map { #false laziness w/process/part_event.html
573 my $value = scalar($cgi->param($_)) || $obj_opts{$_};
575 if ( $option =~ /^(.*)\.reasonnum$/ && $value == -1 ) {
577 'typenum' => scalar( $cgi->param( "new${option}T" ) ),
578 'reason' => scalar( $cgi->param( "new${option}" ) ),
582 ( $option => $value );
586 ( $action => \%opts );
593 tie my %cgi_conditions, 'Tie::IxHash';
595 my $error_callback = sub {
596 my( $cgi, $object, $fields_listref ) = @_;
598 my @cond_params = grep /^conditionname\d+$/, $cgi->param;
600 %cgi_conditions = map {
602 my $conditionname = $cgi->param($param);
607 $cgi_key =~ /^$param\.$conditionname\.(.*)$/ or die 'wtf!';
609 #my $value = $cgi->param($_);
611 #my $info = $all_conditions->{$conditionname}
613 @{ $all_conditions{$conditionname}->{'option_fields'} || []};
614 my $info = $cond_opts{$key};
617 #false laziness w/process/part_event.html
618 if ( $info->{'type'} =~ /^(select|checkbox)-?multiple$/
619 or $info->{'type'} =~ /^select/ && $info->{'multiple'} ) {
620 $value = { map { $_ => 1 } $cgi->param($cgi_key) };
621 } elsif ( $info->{'type'} eq 'freq' ) {
622 $value = $cgi->param($cgi_key). $cgi->param($cgi_key.'_units');
624 $value = $cgi->param($cgi_key);
629 } grep /^$param\.$conditionname\./, $cgi->param
631 } grep $cgi->param($_), grep /^conditionname\d+$/, $cgi->param;
635 my $condition_error_callback = sub {
637 new FS::part_event_condition { 'conditionname' => $_, };
638 } keys %cgi_conditions;
641 my $condition_layer_values = sub {
642 #m2name_table option causes this to be
643 # part_event_condition instead of part_event
644 my ( $cgi, $part_event_condition, $switches ) = @_;
645 scalar( #force hashref
647 #map { $_ => { $part_event_condition->options } }
648 # keys %condition_fields
649 map { my $conditionname = $_;
650 my %opts = $switches->{'mode'} eq 'error'
651 ? %{ $cgi_conditions{$conditionname} || {} }
652 : $part_event_condition->options;
654 map { ( "$conditionname.$_" => $opts{$_} ); }
657 ( $conditionname => \%opts );
659 keys %condition_fields
668 my $curuser = $FS::CurrentUser::CurrentUser;
671 unless $curuser->access_right('Edit billing events')
672 || $curuser->access_right('Edit global billing events');
674 my $disable_empty_agent= ! $curuser->access_right('Edit global billing events');
676 %cgi_conditions = ();
677 my $use_cgi_conditions = 0;