RT #31482 you can now change the tax class when modifying a one-time charge.
[freeside.git] / httemplate / edit / quick-charge.html
1 <& /elements/header-popup.html, mt('One-time charge'), '',
2             ( $cgi->param('error') ? '' : 'onload="addRow()"' ),
3 &>
4
5 <LINK REL="stylesheet" TYPE="text/css" HREF="<%$fsurl%>elements/calendar-win2k-2.css" TITLE="win2k-2">
6 <SCRIPT TYPE="text/javascript" SRC="<%$fsurl%>elements/calendar_stripped.js"></SCRIPT>
7 <SCRIPT TYPE="text/javascript" SRC="<%$fsurl%>elements/calendar-en.js"></SCRIPT>
8 <SCRIPT TYPE="text/javascript" SRC="<%$fsurl%>elements/calendar-setup.js"></SCRIPT>
9
10 <& /elements/error.html &>
11
12 <SCRIPT TYPE="text/javascript">
13
14 function enable_quick_charge (e) {
15
16   if (    document.QuickChargeForm.amount.value
17        && document.QuickChargeForm.pkg.value    ) {
18     document.QuickChargeForm.submit.disabled = false;
19   } else {
20     document.QuickChargeForm.submit.disabled = true;
21   }
22
23 % if ( $curuser->option('disable_enter_submit_onetimecharge') ) {
24
25     var key;
26     if (window.event)
27           key = window.event.keyCode; //IE
28     else
29
30           key = e.which; //firefox, others
31
32     return (key != 13);
33
34 % } else {
35     return true;
36 % }
37
38 }
39
40 function validate_quick_charge () {
41   var pkg = document.QuickChargeForm.pkg.value;
42   var pkg_regex = /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=\[\]]*)$/ ;
43   var amount = document.QuickChargeForm.amount.value;
44   var amount_regex = /^\s*\$?\s*(\d*(\.?\d{1,2}))\s*$/ ;
45   var rval = true;
46
47   if ( ! amount_regex.test(amount) ) {
48     alert('Illegal amount - enter an amount to charge, for example, "5" or "43" or "21.46".');
49     return false;
50   }
51   if ( String(pkg).length < 1 ) {
52     rval = false;
53   }
54   if ( ! pkg_regex.test(pkg) ) {
55     rval = false;
56   }
57   var i=0;
58   for (i=0; i < rownum; i++) {
59     if (! eval('pkg_regex.test(document.QuickChargeForm.description' + i + '.value)')){
60       rval = false;
61       break;
62     }
63   }
64   if (rval == true) {
65     return true;
66   }
67
68   if ( ! pkg ) {
69     alert('Enter a description for the one-time charge');
70     return false;
71   }
72
73   alert('Illegal description - spaces, letters, numbers, and the following punctuation characters are allowed: . , ! ? @ # $ % & ( ) - + ; : ' + "'" + ' " = [ ]' );
74   return false;
75 }
76
77 function bill_now_changed (what) {
78   var form = what.form;
79   if ( what.checked ) {
80     form.start_date_text.disabled = true;
81     form.start_date.style.backgroundColor = '#dddddd';
82     form.start_date_button.style.display = 'none';
83     form.start_date_button_disabled.style.display = '';
84     form.invoice_terms.disabled = false;
85   } else {
86     form.start_date_text.disabled = false;
87     form.start_date.style.backgroundColor = '#ffffff';
88     form.start_date_button.style.display = '';
89     form.start_date_button_disabled.style.display = 'none';
90     form.invoice_terms.disabled = true;
91   }
92 }
93
94 </SCRIPT>
95
96 <FORM ACTION   = "process/quick-charge.cgi"
97       NAME     = "QuickChargeForm"
98       ID       = "QuickChargeForm"
99       METHOD   = "POST"
100       onSubmit = "document.QuickChargeForm.submit.disabled=true; return validate_quick_charge();"
101 >
102
103 <INPUT TYPE="hidden" NAME="custnum"     VALUE="<% $cust_main ? $cust_main->custnum : '' %>">
104 <INPUT TYPE="hidden" NAME="prospectnum" VALUE="<% $prospect_main ? $prospect_main->prospectnum : '' %>">
105 <INPUT TYPE="hidden" NAME="quotationnum" VALUE="<% $quotationnum %>">
106
107 <TABLE ID="QuickChargeTable" BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 STYLE="background-color: #cccccc">
108
109 % if ( $cust_pkg ) {
110
111 <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $cust_pkg->pkgnum %>">
112 % my $field = '/elements/tr-input-text.html';
113 % # don't allow changing these after the fact
114 % $field = '/elements/tr-fixed.html' if $billed;
115 <& $field,
116   label  => mt('Amount to charge'),
117   field  => 'amount',
118   value  => sprintf('%.2f',$part_pkg->option('setup_fee')),
119   size   => 8,
120   prefix => $money_char,
121 &> 
122
123 % if ( $curuser->access_right('Edit package definition costs') ) {
124   <& $field,
125     label  => mt('Cost'),
126     field  => 'setup_cost',
127     value  => sprintf('%.2f',$part_pkg->setup_cost),
128     size   => 8,
129     prefix => $money_char,
130   &> 
131 % }
132
133 %   if ( $conf->exists('invoice-unitprice') ) {
134 <& $field,
135   label => 'Quantity',
136   field => 'quantity',
137   value => $cust_pkg->quantity
138 &>
139 %   }
140
141 <& /elements/tr-select-pkg_class.html, 'curr_value' => $classnum  &>
142
143 % # crudely estimate whether any agent commission credits might exist
144 %   my @events = grep { $_->part_event->action =~ /credit/ }
145 %                $cust_pkg->cust_event;
146 %   if ( scalar @events ) {
147 <TR><TD></TD>
148   <TD><INPUT TYPE="checkbox" NAME="adjust_commission" VALUE="Y" CHECKED>
149 <% emt('Adjust commission credits if necessary') %>
150 </TD>
151 </TR>
152 %   }
153
154 % #display the future or past charge date, but don't allow changes
155 % # XXX we probably _could_ let as-yet unbilled charges be rescheduled, but
156 % # there's no compelling need yet
157 %   if ( $billed ) {
158       <& /elements/tr-fixed-date.html,
159         label => emt('Billed on'),
160         value => $cust_pkg->get('setup')
161       &>
162 %   } else {
163       <& /elements/tr-input-date-field.html,
164         {
165           name    => 'start_date',
166           label   => emt('Will be billed'),
167           value   => $cust_pkg->get('start_date'),
168           format  => $date_format,
169           noinit  => 1,
170         }
171       &>
172 %   }
173
174 <TR>
175   <TD ALIGN="right"><% mt('Tax exempt') |h %> </TD>
176   <TD><INPUT TYPE="checkbox" NAME="setuptax" VALUE="Y" <% $cgi->param('setuptax') ? 'CHECKED' : '' %>></TD>
177 </TR>
178
179 <& /elements/tr-select-taxclass.html, 'curr_value' => $part_pkg->get('taxclass')  &>
180
181 <& /elements/tr-select-taxproduct.html, 'label' => emt('Tax product'), 'onclick' => 'parent.taxproductmagic(this);', 'curr_value' => $part_pkg->get('taxproductnum')  &>
182
183 % } else { # new one-time charge
184
185     <TR>
186       <TD ALIGN="right"><% mt('Amount to charge') |h %> </TD>
187       <TD>
188         <% $money_char %><INPUT TYPE       = "text"
189                                 NAME       = "amount"
190                                 SIZE       = 8
191                                 VALUE      = "<% $amount %>"
192                                 onChange   = "return enable_quick_charge(event)"
193                                 onKeyPress = "return enable_quick_charge(event)"
194                          >
195       </TD>
196     </TR>
197
198 %   if ( $curuser->access_right('Edit package definition costs') ) {
199       <& /elements/tr-input-text.html,
200            label  => mt('Cost'),
201            field  => 'setup_cost',
202            value  => $setup_cost,
203            size   => 8,
204            prefix => $money_char,
205       &> 
206 %   }
207
208 %   if ( $conf->exists('invoice-unitprice') ) {
209     <TR>
210       <TD ALIGN="right"><% mt('Quantity') |h %> </TD>
211       <TD>
212         <INPUT TYPE       = "text"
213                NAME       = "quantity"
214                SIZE       = 4
215                VALUE      = "<% $quantity %>"
216                onKeyPress = "return enable_quick_charge(event)">
217       </TD>
218     </TR>
219 %   }
220
221 <& /elements/tr-select-pkg_class.html, 'curr_value' => $classnum  &>
222
223 % unless ( $quotationnum ) {
224
225     <TR>
226       <TD ALIGN="right"><% mt('Invoice now') |h %></TD>
227       <TD>
228         <INPUT TYPE  = "checkbox"
229                NAME  = "bill_now"
230                VALUE = "1"
231                <% $cgi->param('bill_now') ? 'CHECKED' : '' %>
232                onClick  = "bill_now_changed(this);"
233                onChange = "bill_now_changed(this);"
234         >
235         <% mt('with terms') |h %> 
236         <& /elements/select-terms.html,
237              'curr_value' => scalar($cgi->param('invoice_terms')),
238              'disabled'   => ( $cgi->param('bill_now') ? 0 : 1 ),
239              'agentnum'   => $cust_or_prospect->agentnum,
240         &>
241       </TD>
242     </TR>
243
244 %   # false laziness w/misc/order_pkg.html
245     <TR>
246       <TD ALIGN="right"><% mt('Charge date') |h %> </TD>
247       <TD>
248         <INPUT TYPE  = "text"
249                NAME  = "start_date"
250                SIZE  = 32
251                ID    = "start_date_text"
252                VALUE = "<% $start_date %>"
253                onKeyPress="return enable_quick_charge(event)"
254                <% $cgi->param('bill_now')
255                     ? 'STYLE = "background-color:#dddddd" DISABLED'
256                     : ''
257                %>
258         >
259         <IMG SRC   = "<%$fsurl%>images/calendar.png"
260              ID    = "start_date_button"
261              TITLE = "<% mt('Select date') |h %>"
262              STYLE = "cursor:pointer<% $cgi->param('bill_now') ? ';display:none' : '' %>"
263         >
264         <IMG SRC   = "<%$fsurl%>images/calendar-disabled.png"
265              ID    = "start_date_button_disabled"
266              <% $cgi->param('bill_now') ? '' : 'STYLE="display:none"' %>
267         >
268         <FONT SIZE=-1>(<% mt('leave blank to charge immediately') |h %>)</FONT>
269       </TD>
270     </TR>
271
272     <SCRIPT TYPE="text/javascript">
273       Calendar.setup({
274         inputField: "start_date_text",
275         ifFormat:   "<% $date_format %>",
276         button:     "start_date_button",
277         align:      "BR"
278       });
279     </SCRIPT>
280
281 % }
282
283 % if ( ! $quotationnum && $cust_main->payby =~ /^(CARD|CHEK)$/ ) {
284 %   my $what = lc(FS::payby->shortname($cust_main->payby));
285     <TR>
286       <TD ALIGN="right"><% mt("Disable automatic $what charge") |h %> </TD>
287       <TD COLSPAN=6><INPUT TYPE="checkbox" NAME="no_auto" VALUE="Y"></TD>
288     </TR>
289 % }
290
291 <TR>
292   <TD ALIGN="right"><% mt('Tax exempt') |h %> </TD>
293   <TD><INPUT TYPE="checkbox" NAME="setuptax" VALUE="Y" <% $cgi->param('setuptax') ? 'CHECKED' : '' %>></TD>
294 </TR>
295
296 <& /elements/tr-select-taxclass.html, 'curr_value' => $cgi->param('taxclass')  &>
297
298 <& /elements/tr-select-taxproduct.html, 'label' => emt('Tax product'), 'onclick' => 'parent.taxproductmagic(this);', 'curr_value' => $cgi->param('taxproductnum')  &>
299
300 <& /elements/tr-select-taxoverride.html, 'onclick' => 'parent.taxoverridemagic(this);', 'curr_value' => $cgi->param('tax_override')  &>
301
302 % } # if !$cust_pkg
303
304 <TR>
305   <TD ALIGN="right"><% mt('Description') |h %> </TD>
306   <TD>
307     <INPUT TYPE       = "text"
308            NAME       = "pkg"
309            SIZE       = "50"
310            MAXLENGTH  = "50"
311            VALUE      = "<% $pkg %>"
312            onChange   = "return enable_quick_charge(event)"
313            onKeyPress = "return enable_quick_charge(event)"
314     >
315   </TD>
316 </TR>
317
318 <TR>
319   <TD></TD>
320   <TD><FONT SIZE="-1"><% mt('Optional additional description (also printed on invoice):') |h %> </FONT></TD>
321 </TR>
322
323 % my $row = 0;
324 % foreach (@description) {
325     <TR>
326       <TD></TD>
327       <TD>
328         <INPUT TYPE       = "text"
329                NAME       = "description<% $row %>"
330                SIZE       = "60"
331                MAXLENGTH  = "65"
332                VALUE      = "<% $_ |h %>"
333                rownum     = "<% $row %>"
334                onKeyPress = "return enable_quick_charge(event)"
335                onKeyUp    = "return possiblyAddRow(event)"
336         >
337       </TD>
338     </TR>
339 % $row++;
340 % } 
341
342
343 </TABLE>
344
345 <BR>
346 % my $label = $cust_pkg
347 %             ? emt('Modify one-time charge')
348 %             : emt('Add one-time charge');
349 <INPUT TYPE="submit" ID="submit" NAME="submit" VALUE="<% $label %>" \
350 <% ($cgi->param('error') || $cust_pkg) ? '' :' DISABLED' %>>
351
352 </FORM>
353
354
355 <SCRIPT TYPE="text/javascript">
356
357   var rownum = <% $row %>;
358
359   function possiblyAddRow(e) {
360
361     if ( ( rownum - this.getAttribute('rownum') ) == 1 ) {
362       addRow();
363     }
364
365 %   if ( $curuser->option('disable_enter_submit_onetimecharge') ) {
366
367       var key;
368       if (window.event)
369             key = window.event.keyCode; //IE
370       else
371             key = e.which; //firefox, others
372
373       return (key != 13);
374
375 %   } else {
376       return true;
377 %   }
378
379   }
380
381   function addRow() {
382
383     var table = document.getElementById('QuickChargeTable');
384     var tablebody = table.getElementsByTagName('tbody').item(0);
385
386     var row = document.createElement('TR');
387
388     var empty_cell = document.createElement('TD');
389     row.appendChild(empty_cell);
390
391     var description_cell = document.createElement('TD');
392
393       //var description_input = document.createElement('INPUT');
394       var di = document.createElement('INPUT');
395       di.setAttribute('name', 'description'+rownum);
396       di.setAttribute('id',   'description'+rownum);
397       di.setAttribute('size', 60);
398       di.setAttribute('maxLength', 65);
399       di.setAttribute('rownum',   rownum);
400       di.onkeyup = possiblyAddRow;
401       di.onkeypress = enable_quick_charge;
402       description_cell.appendChild(di);
403
404     row.appendChild(description_cell);
405
406     tablebody.appendChild(row);
407
408     rownum++;
409
410   }
411
412 </SCRIPT>
413
414 </BODY>
415 </HTML>
416 <%init>
417
418 my $curuser = $FS::CurrentUser::CurrentUser;
419
420 die "access denied"
421   unless $curuser->access_right('One-time charge');
422
423 my $conf = new FS::Conf;
424 my $date_format = $conf->config('date_format') || '%m/%d/%Y';
425 my $money_char = $conf->config('money_char') || '$';
426
427 my( $cust_main, $cust_pkg, $prospect_main, $quotationnum ) = ( '', '', '', '' );
428 if ( $cgi->param('change_pkgnum') ) {
429   # change an existing one-time charge
430   die "access denied"
431     unless $curuser->access_right('Modify one-time charge');
432
433   $cgi->param('change_pkgnum') =~ /^(\d+)$/ or die "illegal pkgnum";
434   $cust_pkg = FS::cust_pkg->by_key($1) or die "pkgnum $1 not found";
435   $cust_main = $cust_pkg->cust_main;
436 } else {
437   if ( $cgi->param('quotationnum') =~ /^(\d+)$/ ) {
438     $quotationnum = $1;
439   }
440   if ( $cgi->param('custnum') =~ /^(\d+)$/ ) {
441     $cust_main = FS::cust_main->by_key($1) or die "custnum $1 not found";
442   }
443   if ( $cgi->param('prospectnum') =~ /^(\d+)$/ ) {
444     $prospect_main = FS::prospect_main->by_key($1) or die "prospectnum $1 not found";
445   }
446   die "custnum or prospectnum must be specified"
447     unless $cust_main || $prospect_main;
448 }
449
450 my $cust_or_prospect = $cust_main || $prospect_main;
451
452 if ( $cust_main ) {
453   my $custnum = $cust_main->custnum;
454   # agent-virt
455   if (!exists($curuser->agentnums_href->{$cust_main->agentnum})) {
456     die "custnum $custnum not found";
457   }
458 } elsif ( $prospect_main ) {
459   my $prospectnum = $prospect_main->prospectnum;
460   # agent-virt
461   if (!exists($curuser->agentnums_href->{$prospect_main->agentnum})) {
462     die "prospectnum $prospectnum not found";
463   }
464 }
465
466 my $format = "%m/%d/%Y %T %z (%Z)"; #false laziness w/REAL_cust_pkg.cgi?
467 my $start_date = $cust_main ? $cust_main->next_bill_date : '';
468 $start_date = $start_date ? time2str($format, $start_date) : '';
469
470 my $amount = '';
471 if ( $cgi->param('amount') =~ /^\s*\$?\s*(\d+(\.\d{1,2})?)\s*$/ ) {
472   $amount = $1;
473 }
474
475 my $setup_cost = '';
476 if ( $cgi->param('setup_cost') =~ /^\s*\$?\s*(\d+(\.\d{1,2})?)\s*$/ ) {
477   $setup_cost = $1;
478 }
479
480 my $quantity = 1;
481 if ( $cgi->param('quantity') =~ /^\s*(\d+)\s*$/ ) {
482   $quantity = $1;
483 }
484
485 $cgi->param('pkg') =~ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=\[\]]*)$/ 
486   or die 'illegal description';
487 my $pkg = $1;
488
489 my $default_terms;
490 if ( $cust_main && $cust_main->invoice_terms ) {
491   $default_terms = emt("Customer default ([_1])", $cust_main->invoice_terms);
492 } else {
493   $default_terms =
494     emt( "Default ([_1])",
495          ( $conf->config('invoice_default_terms', $cust_or_prospect->agentnum)
496              || emt('Payable upon receipt')
497          )
498        );
499 }
500
501 my @description;
502 my %param = $cgi->Vars;
503 for (my $i = 0; exists($param{"description$i"}); $i++) {
504   push @description, $param{"description$i"};
505 }
506
507 my $classnum;
508 if ( $cgi->param('classnum') =~ /^(\d+)$/ ) {
509   $classnum = $1;
510 }
511
512 my $part_pkg;
513 my $billed = 0;
514
515 if ( $cust_pkg ) { # set defaults
516   $part_pkg = $cust_pkg->part_pkg;
517   $pkg ||= $part_pkg->pkg;
518   $classnum ||= $part_pkg->classnum;
519   if (!@description) {
520     for (my $i = 0; $i < ($part_pkg->option('additional_count',1) || 0); $i++) 
521     {
522       push @description, $part_pkg->option("additional_info$i",1);
523     }
524   }
525   $billed = $cust_pkg->get('setup') ? 1 : 0;
526 }
527
528 </%init>