option to credit unused time on suspension as part of suspend reason, #31702
[freeside.git] / httemplate / elements / tr-select-reason.html
1 <%doc>
2
3 Example:
4
5   include( '/elements/tr-select-reason.html',
6
7     #required 
8     'field'         => 'reasonnum',
9     'reason_class'  => 'C', # currently 'C', 'R', 'F',  or 'S'
10                            # for cancel, credit, refund, or suspend
11
12     #recommended
13     'cgi' => $cgi, #easiest way for things to be properly "sticky" on errors
14
15     #optional
16     'control_button' => 'element_name', #button to be enabled when a reason is
17                                         #selected
18     'id'             => 'element_id',
19
20     #deprecated ways to keep things "sticky" on errors
21     # (requires duplicate code in each using file to parse cgi params)
22     'curr_value'     => $curr_value,
23     'curr_value'     => {
24                           'typenum' => $typenum,
25                           'reason'  => $reason,
26                         },
27
28   )
29
30 </%doc>
31
32 % # note style improvements.
33 % # - no more conditionally included code here
34 % # - callers are not expected to pass javascript fragments
35 % # - no redundant checking of ACLs or parameters
36 % # - form fields are grouped for easy management
37 % # - use the standard select-table widget instead of ad hoc crap
38 <SCRIPT TYPE="text/javascript">
39   function <% $id %>_changed() {
40     var hints = <% encode_json(\%all_hints) %>;
41     var select_reason = document.getElementById('<% $id %>');
42
43     document.getElementById('<% $id %>_hint').innerHTML =
44       hints[select_reason.value] || '';
45
46     // toggle submit button state
47     var submit_button = document.getElementById(<% $opt{control_button} |js_string %>);
48     if (submit_button) {
49       submit_button.disabled = ( select_reason.value == 0 );
50     }
51
52     // toggle visibility of 'new reason' fields
53     var new_fields = document.getElementById('<% $id %>_new_fields');
54     if ( select_reason.value == -1 ) {
55       new_fields.disabled = false;
56       new_fields.style.display = '';
57     } else {
58       new_fields.disabled = true;
59       new_fields.style.display = 'none';
60     }
61
62   }
63   <&| onload.js &> <% $id %>_changed(); </&>
64 </SCRIPT>
65
66 %# sadly can't just use add_inline here, as we have non-text fields
67 <& tr-select-table.html,
68   'label'           => 'Reason',
69   'field'           => $name,
70   'id'              => $id,
71   'table'           => 'reason',
72   'records'         => \@reasons,
73   'label_callback'  => sub { my $reason = shift;
74                              $reason->type . ' : ' .  $reason->reason },
75   'disable_empty'   => 1,
76   'pre_options'     => [ 0 => 'Select reason...' ],
77   'post_options'    => [ -1 => 'Add new reason' ],
78   'curr_value'      => $init_reason,
79   'onchange'        => $id.'_changed()',
80 &>
81
82 % # "add new reason" fields
83 % # should be a <fieldset>, but that doesn't fit well into the table
84
85 <TR id="<% $id %>_new_fields">
86   <TD COLSPAN=2>
87     <TABLE CLASS="inv" STYLE="text-align: left">
88
89       <& tr-input-text.html,
90         label => 'New reason',
91         field => $id.'_new_reason'
92       &>
93
94 % my @types = qsearch( 'reason_type', { 'class' => $class } );
95 % if (scalar(@types) < 1) {  # we should never reach this
96       <TR>
97         <TD ALIGN="right">
98           <P><% mt('No reason types. Please add some.') |h %></P>
99         </TD>
100       </TR>
101 % } elsif (scalar(@types) == 1) {
102       <& tr-fixed.html,
103         label => 'Reason type',
104         field => $id.'_new_reason_type',
105         curr_value => $types[0]->typenum,
106         formatted_value => $types[0]->type,
107       &>
108 % } else { # more than one type, the normal case
109       <& tr-select-table.html,
110         label         => 'Reason type',
111         field         => $id.'_new_reason_type',
112         table         => 'reason_type',
113         name_col      => 'type',
114         hashref       => { 'class' => $class },
115         disable_empty => 1,
116       &>
117 % } # scalar(@types)
118
119 % if ( $class eq 'S' ) {
120       <& tr-checkbox.html,
121         label => 'Credit the unused portion of service when suspending',
122         field => $id.'_new_unused_credit',
123         value => 'Y'
124       &>
125       <& tr-select-part_pkg.html,
126         label   => 'Charge this fee when unsuspending',
127         field   => $id.'_new_unsuspend_pkgpart',
128         hashref => { disabled => '', freq => '0' },
129         empty_label => 'none',
130       &>
131       <& tr-checkbox.html,
132         label => 'Hold unsuspension fee until the next bill',
133         field => $id.'_new_unsuspend_hold',
134         value => 'Y',
135       &>
136 % }
137     </table>
138   </td>
139 </tr>
140
141 % # container for hints
142 <TR>
143   <TD COLSPAN=2 ALIGN="center" id="<% $id %>_hint" style="font-size:small">
144   </TD>
145 </TR>
146
147 <%init>
148
149 my %opt = @_;
150
151 my $name = $opt{'field'};
152 my $class = $opt{'reason_class'};
153
154 my $init_reason;
155 if ( $opt{'cgi'} ) {
156   $init_reason = $opt{'cgi'}->param($name);
157 } else {
158   $init_reason = $opt{'curr_value'};
159 }
160
161 my $id = $opt{'id'} || $name;
162
163 my $add_access_right;
164 if ($class eq 'C') {
165   $add_access_right = 'Add on-the-fly cancel reason';
166 } elsif ($class eq 'S') {
167   $add_access_right = 'Add on-the-fly suspend reason';
168 } elsif ($class eq 'R') {
169   $add_access_right = 'Add on-the-fly credit reason';
170 } elsif ($class eq 'F') {
171   $add_access_right = 'Add on-the-fly refund reason';
172 } else {
173   die "illegal class: $class";
174 }
175
176 my @reasons = qsearch({
177   'table'           => 'reason',
178   'addl_from'       => ' LEFT JOIN reason_type'.
179                        ' ON (reason.reason_type = reason_type.typenum)',
180   'hashref'         => { disabled => '' },
181   'extra_sql'       => " AND reason_type.class = '$class'",
182   'order_by'        => ' ORDER BY type, reason',
183 });
184
185 my %all_hints;
186 if ( $class eq 'S' ) {
187   my $conf = FS::Conf->new;
188   %all_hints = ( 0 => '', -1 => '' );
189   foreach my $reason (@reasons) {
190     my @hints;
191     if ( $reason->unsuspend_pkgpart ) {
192       my $part_pkg = FS::part_pkg->by_key($reason->unsuspend_pkgpart);
193       if ( $part_pkg ) {
194         if ( $part_pkg->option('setup_fee',1) > 0 and 
195              $part_pkg->option('recur_fee',1) == 0 ) {
196           # the usual case
197           push @hints,
198             mt('A [_1] unsuspension fee will apply.', 
199                ($conf->config('money_char') || '$') .
200                sprintf('%.2f', $part_pkg->option('setup_fee'))
201                );
202         } else {
203           # oddball cases--not really supported
204           push @hints,
205             mt('An unsuspension package will apply: [_1]',
206               $part_pkg->price_info
207               );
208         }
209       } else { #no $part_pkg
210         push @hints,
211           '<FONT COLOR="#ff0000">Unsuspend pkg #'.$reason->unsuspend_pkgpart.
212           ' not found.</FONT>';
213       }
214     }
215     if ( $reason->unused_credit ) {
216       push @hints, mt('The customer will be credited for unused time.');
217     }
218     $all_hints{ $reason->reasonnum } = join('<BR>', @hints);
219   }
220 }
221
222 my $curuser = $FS::CurrentUser::CurrentUser;
223 </%init>