This commit was generated by cvs2svn to compensate for changes in r5562,
[freeside.git] / httemplate / edit / part_event.html
1 <% include( 'elements/edit.html',
2               'name'   => 'Billing event definition',
3               'table'  => 'part_event',
4               'fields' => [
5                             'event',
6                             { field   => 'eventtable',
7                               type    => 'select',
8                               options => [ FS::part_event->eventtables ],
9                               labels  => $eventtable_labels,
10                               onchange => 'eventtable_changed',
11                             },
12                             { field   => 'agentnum',
13                               type    => 'select-agent',
14                               disable_empty => $disable_empty_agent,
15                             },
16                             { field   => 'check_freq',
17                               type    => 'select',
18                               options => [ '1d', '1m' ],
19                               labels  => $check_freq_labels,
20                             },
21                             { field   => 'disabled',
22                               type    => 'checkbox',
23                               value   => 'Y',
24                             },
25                             { type    => 'title',
26                               value   => 'Event Conditions',
27                             },
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',
46                             },
47                             { type    => 'title',
48                               value   => 'Event Action',
49                             },
50                             { field   => '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'),
58                             },
59
60                           ],
61               'labels' => {
62                             'eventpart'  => 'Event',
63                             'event'      => 'Event name',
64                             'eventtable' => 'Type',
65                             'agentnum'   => 'Agent',
66                             'check_freq' => 'Check frequency',
67                             'disabled'   => 'Disable event',
68
69                             'conditionname' => 'Add&nbsp;new&nbsp;condition',
70                             #'weight',
71                             'action'     => 'Action',
72                           },
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'} }, '';
77               },
78               'error_callback' => $error_callback,
79
80               'agent_virt'       => 1,
81               'agent_null_right' => 'Edit global billing events',
82           )
83 %>
84 <SCRIPT TYPE="text/javascript">
85
86   window.onload = function () { eventtable_changed(document.getElementById('eventtable')) };
87   var notonload = 0;
88
89   function eventtable_changed(what) {
90
91 %   if ( $JS_DEBUG ) {
92       alert('eventtable_changed called on ' + what );
93 %   }
94
95     var eventtable = what.options[what.selectedIndex].value;
96     var eventdesc  = what.options[what.selectedIndex].text;
97
98     //remove the ** Select type **
99     if ( what.options[0].value == '' && notonload++ > 0 ) {
100       what.options[0] = null;
101     }
102
103     ////
104     // XXX gray out conditions that can't apply?
105     ////
106
107     ////
108     // update condition selects
109     ////
110
111     for ( var cnum=0; document.getElementById('conditionname'+cnum); cnum++ ) {
112       var cond_id = 'conditionname' + cnum;
113       var cond_select = document.getElementById(cond_id);
114
115 %     if ( $JS_DEBUG ) {
116         alert('updating ' + cond_id);
117 %     }
118
119       // save off the current value
120       var conditionname = cond_select.options[cond_select.selectedIndex].value;
121       var cond_desc     = cond_select.options[cond_select.selectedIndex].text;
122
123       var seen_condition = condition_repop(cond_select);
124
125       var warning = document.getElementById(cond_id + '_warning');
126 %     if ( $JS_DEBUG ) {
127         alert('turning off warning; setting style.display of '+ cond_id +
128               '_warning (' + warning + ') to none');
129 %     }
130       warning.style.display = 'none';
131
132       if ( ! seen_condition && conditionname != '') {
133         // add the current (not valid) condition back
134         opt(cond_select, conditionname, cond_desc, true );
135         if ( true <% @implicit_conditions
136                        ? ( ' && '. join(' && ', map { "conditionname != '$_'" }
137                                                     @implicit_conditions
138                                        )
139                          )
140                        : ''
141                   %> ) {
142           // turn on a warning and gray out the condition row
143 %         if ( $JS_DEBUG ) {
144             alert('turning on warning; setting style.display of '+ cond_id +
145                   '_warning (' + warning + ') to none');
146 %         }
147           warning.innerHTML = 'Not applicable to ' + eventdesc + ' events';
148           warning.style.display = '';
149         }
150       }
151
152     }
153
154
155     ////
156     // update action select
157     ////
158
159     // save off the current value first!!
160     var action = what.form.action.options[what.form.action.selectedIndex].value;
161     var a_desc = what.form.action.options[what.form.action.selectedIndex].text;
162     var seen_action = false;
163
164     // blank the current action select
165     for ( var i = what.form.action.length; i >= 0; i-- )
166       what.form.action.options[i] = null;
167
168     if ( action == '' ) {
169       opt(what.form.action, action, a_desc, true );
170     }
171
172     // repopulate it
173 %   foreach my $eventtable ( FS::part_event->eventtables ) {
174 %     tie my %actions, 'Tie::IxHash', FS::part_event->actions($eventtable);
175 %     #use Data::Dumper; warn Dumper(%actions);
176
177       if ( eventtable == '<% $eventtable %>' ) {
178
179 %       foreach my $action ( keys %actions ) {
180 %         ( my $description = $actions{$action}->{'description'} ) =~ s/'/\\'/g;
181
182           var sel = false;
183           if ( action == '<% $action %>' ) {
184             seen_action = true;
185             sel = true;
186           }
187           opt( what.form.action, '<% $action %>', '<% $description %>', sel );
188 %       }
189
190       }
191
192 %   }
193
194     // by default, turn off warnings and enable the submit button
195     var warning = document.getElementById('action_warning');
196     warning.style.display = 'none';
197     var submit_button = document.getElementById('submit');
198     submit_button.disabled = '';
199
200     if ( ! seen_action && action != '' ) {
201       // add the current (not valid) action back
202       opt( what.form.action, action, a_desc, true );
203       // turn on a warning and disable the submit button
204       //warning.innerHTML = a_desc + ' event not available as a ' +
205       warning.innerHTML = 'Not available as a ' + eventdesc + ' action';
206       warning.style.display = '';
207       submit_button.disabled = 'disabled';
208     }
209
210   }
211
212   function opt(what,value,text,selected) {
213     var optionName = new Option(text, value, false, selected);
214     var length = what.length;
215     what.options[length] = optionName;
216   }
217
218   function action_changed(what) {
219     // remove '** Select new **'
220     if ( what.options[0].value == '' ) {
221        what.options[0] = null;
222     }
223     // remove the warning, remove the invalid action, enable the submit button
224     var warning = document.getElementById('action_warning');
225     if ( warning.style.display == '' ) {
226       warning.style.display = 'none';
227       what.options[what.length-1] = null;
228       document.getElementById('submit').disabled = '';
229     }
230   }
231
232   function condition_changed(what) {
233     // remove '** Select new **'
234     if ( what.options[0].value == '' ) {
235        what.options[0] = null;
236     }
237
238     var previousValue = what.getAttribute('previousValue');
239     var previousText = what.getAttribute('previousText');
240     var value = what.options[what.selectedIndex].value;
241     var text = what.options[what.selectedIndex].text;
242
243 %   foreach my $value ( keys %condition_remove_warnings ) {
244       if ( previousValue == '<% $value %>' ) {
245         if ( !confirm( <% $condition_remove_warnings{$value} |js_string %> ) ) {
246           for ( var i=0; i < what.length; i++ ) {
247             if ( what.options[i].value == previousValue ) {
248               what.selectedIndex = i;
249             }
250           }
251           return false;
252         }
253       }
254 %   }
255
256     //alert(previous + ' changed to ' + value);
257
258     var field_regex = /(\d+)$/;
259     var match = field_regex.exec(what.name);
260     if ( !match ) {
261       alert(what.name + " didn't match?!");
262       return;
263     }
264
265     //add the previous condition *back* to all the other selects...
266     condition_add(previousValue, previousText, match[1]);
267
268     what.setAttribute('previousValue', value);
269     what.setAttribute('previousText', text);
270
271     // remove the new condition from all other selects
272     condition_remove(value, match[1]);
273
274   }
275
276   function condition_avail(check_cond, curnum) {
277     for ( var cnum=0; document.getElementById('conditionname'+cnum); cnum++ ) {
278       if ( cnum == curnum ) continue;
279
280       var cond_id = 'conditionname' + cnum;
281       var cond_select = document.getElementById(cond_id);
282
283       //alert("checking " + cond_id + " (" + cond_select.disabled + ")");
284
285       if ( cond_select.disabled ) continue;
286
287       // the current value
288       var conditionname = cond_select.options[cond_select.selectedIndex].value;
289
290       if ( check_cond == conditionname ) return false;
291
292     }
293
294     return true;
295
296   }
297
298   function condition_remove(remove_cond, curnum) {
299
300     if ( remove_cond.length == 0 ) return;
301
302     for ( var cnum=0; document.getElementById('conditionname'+cnum); cnum++ ) {
303       if ( cnum == curnum ) continue;
304
305       var cond_id = 'conditionname' + cnum;
306       var cond_select = document.getElementById(cond_id);
307
308       //for ( var i = cond_select.length; i >= 0; i-- ) {
309       for ( var i=0; i < cond_select.length; i++ ) {
310         if ( cond_select.options[i].value == remove_cond ) {
311           cond_select.options[i] = null;
312         }
313       }
314
315     }
316
317   }
318
319   function condition_add(add_condname, add_conddesc, curnum) {
320
321     if ( add_condname.length == 0 ) return;
322
323     var eventtable_el = document.getElementById('eventtable');
324     var eventtable = eventtable_el.options[eventtable_el.selectedIndex].value;
325
326     var in_eventtable = false;
327
328 %   foreach my $eventtable ( FS::part_event->eventtables ) {
329 %     tie my %conditions, 'Tie::IxHash',
330 %       FS::part_event_condition->conditions($eventtable);
331
332       if ( eventtable == '<% $eventtable %>' ) {
333
334 %       foreach my $conditionname ( keys %conditions ) {
335 %         my $description = $conditions{$conditionname}->{'description'};
336 %         $description =~ s/'/\\'/g;
337
338           if ( add_condname == '<% $conditionname %>' ) {
339             in_eventtable = true;
340           }
341
342 %       }
343
344       }
345
346 %   }
347
348     if ( ! in_eventtable ) return;
349
350     for ( var cnum=0; document.getElementById('conditionname'+cnum); cnum++ ) {
351       if ( cnum == curnum ) continue;
352
353       var cond_id = 'conditionname' + cnum;
354       var cond_select = document.getElementById(cond_id);
355
356       if ( cond_select.disabled ) continue;
357
358       //alert("adding " + add_condname + " to " + cond_id);
359
360       opt(cond_select, add_condname, add_conddesc, false );
361
362       cond_select.parentNode.parentNode.style.display = '';
363
364     }
365
366   }
367
368   function condition_repop(cond_select) {
369
370     var eventtable_el = document.getElementById('eventtable');
371     var eventtable = eventtable_el.options[eventtable_el.selectedIndex].value;
372
373     // save off the current value
374     var conditionname = cond_select.options[cond_select.selectedIndex].value;
375     var cond_desc     = cond_select.options[cond_select.selectedIndex].text;
376     var seen_condition = false;
377
378     if ( cond_select.disabled ) return false; //skip deleted conditions
379
380     var field_regex = /(\d+)$/;
381     var match = field_regex.exec(cond_select.name);
382     if ( !match ) {
383       alert(what.name + " didn't match?!");
384       return;
385     }
386     var cnum = match[1];
387
388     // blank the current condition select
389     for ( var i = cond_select.length; i >= 0; i-- )
390       cond_select.options[i] = null;
391
392     if ( conditionname == '' ) {
393       opt(cond_select, conditionname, cond_desc, true );
394     }
395
396     // repopulate it
397 %   foreach my $eventtable ( FS::part_event->eventtables ) {
398 %     tie my %conditions, 'Tie::IxHash',
399 %       FS::part_event_condition->conditions($eventtable);
400
401       if ( eventtable == '<% $eventtable %>' ) {
402
403 %       foreach my $conditionname ( keys %conditions ) {
404 %         my $description = $conditions{$conditionname}->{'description'};
405 %         $description =~ s/'/\\'/g;
406
407           var sel = false;
408           if ( conditionname == '<% $conditionname %>' ) {
409             seen_condition = true;
410             sel = true;
411           }
412
413           if ( condition_avail("<% $conditionname %>", cnum) ) {
414             opt(cond_select, '<% $conditionname %>', '<% $description %>', sel);
415           }
416
417 %       }
418
419       }
420         
421 %   }
422
423     if ( cond_select.length > 1 || cond_select.length == 1 && cond_select.options[0].value.length > 0 ) {
424        
425       cond_select.parentNode.parentNode.style.display = '';
426
427     } else {
428       cond_select.parentNode.parentNode.style.display = 'none';
429     }
430
431     return seen_condition;
432
433   }
434
435 </SCRIPT>
436 <%once>
437
438 #misc (eventtable, check_freq)
439
440 my $eventtable_labels = FS::part_event->eventtable_labels;
441 $eventtable_labels->{''} = '** Select type **';
442
443 my $check_freq_labels = FS::part_event->check_freq_labels;
444
445 #conditions
446
447 tie my %all_conditions, 'Tie::IxHash', 
448   '' => { 'description' => '*** Select new condition ***', },
449   FS::part_event_condition->conditions();
450
451 my %condition_labels = map { $_ => $all_conditions{$_}->{'description'} }
452                            keys %all_conditions;
453
454 #my %condition_fields = map { $_ => $all_conditions{$_}->{option_fields} } 
455 #                           keys %all_conditions;
456 my %condition_fields = map { my $c = $_;
457                              tie my %opts, 'Tie::IxHash',
458                                @{ $all_conditions{$c}->{'option_fields'} || []};
459                              %opts = ( map { ( "$c.$_" => $opts{$_} ); }
460                                            keys %opts
461                                      );
462                              ( $c => [ %opts ] );
463                            } 
464                            keys %all_conditions;
465
466 my @implicit_conditions = sort { $all_conditions{$a}->{'implicit_flag'} <=>
467                                  $all_conditions{$b}->{'implicit_flag'}
468                                }
469                           grep { $all_conditions{$_}->{'implicit_flag'} }
470                           keys %all_conditions;
471
472 my @implicit_condition_objs = map {
473                                     new FS::part_event_condition {
474                                       'conditionname' => $_,
475                                     };
476                                   }
477                                   @implicit_conditions;
478
479 my %condition_remove_warnings =
480   map  { ( $_ => $all_conditions{$_}->{'remove_warning'} ); }
481   grep { $all_conditions{$_}->{'remove_warning'} }
482   keys %all_conditions;
483
484 #actions
485
486 tie my %all_actions, 'Tie::IxHash', 
487   '' => { 'description' => '*** Select event action ***', },
488   FS::part_event->actions();
489
490 my %action_labels = map { $_ => $all_actions{$_}->{'description'} }
491                         keys %all_actions;
492
493 #my %action_fields = map { $_ => $all_actions{$_}->{option_fields} }
494 #                        keys %all_actions;
495 my %action_fields = map { my $action = $_;
496                           tie my %opts, 'Tie::IxHash',
497                             @{ $all_actions{$action}->{option_fields} || [] };
498                           %opts = ( map { ( "$action.$_" => $opts{$_} ); }
499                                         keys %opts
500                                   );
501                           ( $action => [ %opts ] );
502                         }
503                         keys %all_actions;
504
505 #subs
506
507 sub n_a {
508   my $t = shift;
509
510   return sub {
511     my $field = shift;
512     qq( <FONT ID="${field}_warning" STYLE="display:none" COLOR="#FF0000">).
513       "Party Party Join us Join us".
514       '</FONT>';
515   };
516 }
517
518 my $action_layer_values = sub {
519   my( $cgi, $part_event ) = @_;
520   my $action = $cgi->param('action') || $part_event->action;
521   return {} unless $action;
522   scalar( #force hashref
523     {
524       #map { $_ => { $part_event->options } }
525       #    keys %action_fields
526       map { my $action = $_;
527             my %fields = @{ $action_fields{$action} };
528             my %obj_opts = $part_event->options;
529             %obj_opts = map { ( "$action.$_" => $obj_opts{$_} ); }
530                             keys %obj_opts;
531             my %opts =
532               map { #false laziness w/process/part_event.html
533                     my $option = $_;
534                     my $value = scalar($cgi->param($_)) || $obj_opts{$_};
535
536                     if ( $option =~ /^(.*)\.reasonnum$/ && $value == -1 ) {
537                       $value = {
538                         'typenum' => scalar( $cgi->param( "new${option}T" ) ),
539                         'reason'  => scalar( $cgi->param( "new${option}"  ) ),
540                       };
541                     }
542
543                     ( $option => $value );
544
545                   }
546                   keys %fields;
547             ( $action => \%opts );
548           }
549           keys %action_fields
550     }
551   );
552 };
553
554 tie my %cgi_conditions, 'Tie::IxHash';
555
556 my $error_callback = sub {
557   my( $cgi, $object, $fields_listref ) = @_;
558
559   my @cond_params = grep /^conditionname\d+$/, $cgi->param;
560
561   %cgi_conditions = map {
562     my $param = $_;
563     my $conditionname = $cgi->param($param);
564     $conditionname => {
565       map { 
566
567         my $cgi_key = $_;
568         $cgi_key =~ /^$param\.$conditionname\.(.*)$/ or die 'wtf!';
569         my $key = $1;
570         #my $value = $cgi->param($_);
571
572         #my $info = $all_conditions->{$conditionname}
573         my %cond_opts =
574           @{ $all_conditions{$conditionname}->{'option_fields'} || []};
575         my $info = $cond_opts{$key};
576
577         my $value;
578         #false laziness w/process/part_event.html
579         if (      $info->{'type'} =~ /^(select|checkbox)-?multiple$/
580                or $info->{'type'} =~ /^select/ && $info->{'multiple'} ) {
581           $value = { map { $_ => 1 } $cgi->param($cgi_key) };
582         } elsif ( $info->{'type'} eq 'freq' ) {
583           $value = $cgi->param($cgi_key). $cgi->param($cgi_key.'_units');
584         } else {
585           $value = $cgi->param($cgi_key);
586         }
587
588         $key => $value;
589
590       } grep /^$param\.$conditionname\./, $cgi->param
591     };
592   } grep $cgi->param($_), grep /^conditionname\d+$/, $cgi->param;
593
594 };
595
596 my $condition_error_callback = sub {
597   map {
598     new FS::part_event_condition { 'conditionname' => $_, };
599   } keys %cgi_conditions;
600 };
601
602 my $condition_layer_values = sub {
603   #m2name_table option causes this to be
604   # part_event_condition instead of part_event
605   my ( $cgi, $part_event_condition, $switches ) = @_;
606   scalar( #force hashref
607     {
608       #map { $_ => { $part_event_condition->options } }
609       #    keys %condition_fields
610       map { my $conditionname = $_;
611             my %opts = $switches->{'mode'} eq 'error'
612                        ? %{ $cgi_conditions{$conditionname} || {} }
613                        : $part_event_condition->options;
614             %opts = (
615               map { ( "$conditionname.$_" => $opts{$_} ); }
616                   keys %opts
617             );
618             ( $conditionname => \%opts );
619           }
620           keys %condition_fields
621     }
622   );
623 };
624
625
626 </%once>
627 <%init>
628
629 my $curuser = $FS::CurrentUser::CurrentUser;
630
631 die "access denied"
632   unless $curuser->access_right('Edit billing events')
633       || $curuser->access_right('Edit global billing events');
634
635 my $disable_empty_agent= ! $curuser->access_right('Edit global billing events');
636
637 %cgi_conditions = ();
638 my $use_cgi_conditions = 0;
639
640 my $JS_DEBUG = 0;
641
642 </%init>