Use any card on file when making a payment, RT#23741
[freeside.git] / httemplate / misc / payment.cgi
1 <& /elements/header.html, mt("Process [_1] payment",$type{$payby})  &>
2 <& /elements/small_custview.html, $cust_main, '', '', popurl(2) . "view/cust_main.cgi" &>
3 <BR>
4
5 <FORM NAME="OneTrueForm" ACTION="process/payment.cgi" METHOD="POST" onSubmit="document.OneTrueForm.process.disabled=true">
6 <INPUT TYPE="hidden" NAME="custnum"   VALUE="<% $custnum %>">
7 <INPUT TYPE="hidden" NAME="payby"     VALUE="<% $payby %>">
8 <INPUT TYPE="hidden" NAME="payunique" VALUE="<% $payunique %>">
9 <INPUT TYPE="hidden" NAME="balance"   VALUE="<% $balance %>">
10
11 <& /elements/init_overlib.html &>
12
13 <TABLE class="fsinnerbox">
14
15   <& /elements/tr-amount_fee.html,
16        'amount'             => $amount,
17        'process-pkgpart'    => 
18           scalar($conf->config('manual_process-pkgpart', $cust_main->agentnum)),
19        'process-display'    => scalar($conf->config('manual_process-display')),
20        'process-skip_first' => $conf->exists('manual_process-skip_first'),
21        'num_payments'       => scalar($cust_main->cust_pay), 
22        'surcharge_percentage' =>
23          ( $payby eq 'CARD'
24              ? scalar($conf->config('credit-card-surcharge-percentage'))
25              : 0
26          ),
27   &>
28
29 % if ( $conf->exists('part_pkg-term_discounts') ) {
30     <& /elements/tr-select-discount_term.html,
31          'custnum'   => $custnum,
32          'amount_id' => 'amount',
33     &>
34 % }
35
36 <SCRIPT TYPE="text/javascript">
37   function cust_payby_changed (what) {
38     var custpaybynum = what.options[what.selectedIndex].value
39     if ( custpaybynum == '' || custpaybynum == '0' ) {
40        //what.form.payinfo.disabled = false;
41        $('#cust_payby').slideDown();
42     } else {
43        //what.form.payinfo.value = '';
44        //what.form.payinfo.disabled = true;
45        $('#cust_payby').slideUp();
46     }
47   }
48 </SCRIPT>
49
50 % #can't quite handle CARD/CHEK on the same page yet, but very close
51 % #does it make sense from a UI/usability perspective?
52 %
53 % my @cust_payby = ();
54 % if ( $payby eq 'CARD' ) {
55 %   @cust_payby = $cust_main->cust_payby('CARD','DCRD');
56 % } elsif ( $payby eq 'CHEK' ) {
57 %   @cust_payby = $cust_main->cust_payby('CHEK','DCHK');
58 % } else {
59 %   die "unknown payby $payby";
60 % }
61 %
62 % my $custpaybynum = length(scalar($cgi->param('custpaybynum')))
63 %                      ? scalar($cgi->param('custpaybynum'))
64 %                      : scalar(@cust_payby) && $cust_payby[0]->custpaybynum;
65
66 <& /elements/tr-select-cust_payby.html,
67      'cust_payby' => \@cust_payby,
68      'curr_value' => $custpaybynum,
69      'onchange'   => 'cust_payby_changed(this)',
70 &>
71
72 </TABLE>
73 <BR>
74 <DIV ID="cust_payby"
75   <% $custpaybynum ? 'STYLE="display:none"'
76                    : ''
77   %>
78 >
79 <TABLE class="fsinnerbox">
80
81 % my $auto = 0;
82 % if ( $payby eq 'CARD' ) {
83 %
84 %   my( $payinfo, $paycvv, $month, $year ) = ( '', '', '', '' );
85 %   my $payname = $cust_main->first. ' '. $cust_main->getfield('last');
86 %   my $location = $cust_main->bill_location;
87
88     <TR>
89       <TH ALIGN="right"><% mt('Card number') |h %></TH>
90       <TD COLSPAN=7>
91         <TABLE>
92           <TR>
93             <TD>
94               <INPUT TYPE="text" NAME="payinfo" SIZE=20 MAXLENGTH=19 VALUE="<%$payinfo%>"> </TD>
95             <TH><% mt('Exp.') |h %></TH>
96             <TD>
97               <SELECT NAME="month">
98 % for ( ( map "0$_", 1 .. 9 ), 10 .. 12 ) { 
99
100                   <OPTION<% $_ == $month ? ' SELECTED' : '' %>><% $_ %>
101 % } 
102
103               </SELECT>
104             </TD>
105             <TD> / </TD>
106             <TD>
107               <SELECT NAME="year">
108 % my @a = localtime; for ( $a[5]+1900 .. $a[5]+1915 ) { 
109
110                   <OPTION<% $_ == $year ? ' SELECTED' : '' %>><% $_ %>
111 % } 
112
113               </SELECT>
114             </TD>
115           </TR>
116         </TABLE>
117       </TD>
118     </TR>
119     <TR>
120       <TH ALIGN="right"><% mt('CVV2') |h %></TH>
121       <TD><INPUT TYPE="text" NAME="paycvv" VALUE="<% $paycvv %>" SIZE=4 MAXLENGTH=4>
122           (<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/cvv2.html', 480, 352, 'cvv2_popup' ), CAPTION, 'CVV2 Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;"><% mt('help') |h %></A>)
123       </TD>
124     </TR>
125     <TR>
126       <TH ALIGN="right"><% mt('Exact name on card') |h %></TH>
127       <TD><INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="payname" VALUE="<%$payname%>"></TD>
128     </TR>
129
130     <& /elements/location.html,
131                   'object'         => $location,
132                   'no_asterisks'   => 1,
133                   'address1_label' => emt('Card billing address'),
134     &>
135
136 % } elsif ( $payby eq 'CHEK' ) {
137 %
138 %   my( $account, $aba, $branch, $payname, $ss, $paytype, $paystate,
139 %       $stateid, $stateid_state )
140 %     = ( '', '', '', '', '', '', '', '', '' );
141 %
142 %  #false laziness w/{edit,view}/cust_main/billing.html
143 %  my $routing_label = $conf->config('echeck-country') eq 'US'
144 %                        ? 'ABA/Routing number'
145 %                        : 'Routing number';
146 %  my $routing_size      = $conf->config('echeck-country') eq 'CA' ? 4 : 10;
147 %  my $routing_maxlength = $conf->config('echeck-country') eq 'CA' ? 3 : 9;
148
149     <INPUT TYPE="hidden" NAME="month" VALUE="12">
150     <INPUT TYPE="hidden" NAME="year" VALUE="2037">
151     <TR>
152       <TD ALIGN="right"><% mt('Account number') |h %></TD>
153       <TD><INPUT TYPE="text" SIZE=10 NAME="payinfo1" VALUE="<%$account%>"></TD>
154       <TD ALIGN="right"><% mt('Type') |h %></TD>
155       <TD><SELECT NAME="paytype"><% join('', map { qq!<OPTION VALUE="$_" !.($paytype eq $_ ? 'SELECTED' : '').">$_</OPTION>" } FS::cust_payby->paytypes) %></SELECT></TD>
156     </TR>
157     <TR>
158       <TD ALIGN="right"><% mt($routing_label) |h %></TD>
159       <TD>
160         <INPUT TYPE="text" SIZE="<% $routing_size %>" MAXLENGTH="<% $routing_maxlength %>" NAME="payinfo2" VALUE="<%$aba%>">
161         (<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/ach.html', 380, 240, 'ach_popup' ), CAPTION, 'ACH Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;"><% mt('help') |h %></A>)
162       </TD>
163     </TR>
164 %   if ( $conf->config('echeck-country') eq 'CA' ) {
165       <TR>
166         <TD ALIGN="right"><% mt('Branch number') |h %></TD>
167         <TD>
168           <INPUT TYPE="text" NAME="payinfo3" VALUE="<%$branch%>" SIZE=6 MAXLENGTH=5>
169         </TD>
170       </TR>
171 %   }
172     <TR>
173       <TD ALIGN="right"><% mt('Bank name') |h %></TD>
174       <TD><INPUT TYPE="text" NAME="payname" VALUE="<%$payname%>"></TD>
175     </TR>
176
177 %   if ( $conf->exists('show_bankstate') ) {
178       <TR>
179         <TD ALIGN="right"><% mt('Bank state') |h %></TD>
180         <TD><& /elements/select-state.html,
181                          'disable_empty' => 0,
182                          'empty_label'   => emt('(choose)'),
183                          'state'         => $paystate,
184                          'country'       => $cust_main->country,
185                          'prefix'        => 'pay',
186             &>
187         </TD>
188       </TR>
189 %   } else {
190       <INPUT TYPE="hidden" NAME="paystate" VALUE="<% $paystate %>">
191 %   }
192
193 %   if ( $conf->exists('show_ss') ) {
194       <TR>
195         <TD ALIGN="right">
196           <% mt('Account holder') |h %><BR>
197           <% mt('Social security or tax ID #') |h %> 
198         </TD>
199         <TD><INPUT TYPE="text" NAME="ss" VALUE="<% $ss %>"></TD>
200       </TR>
201 %   } else {
202       <INPUT TYPE="hidden" NAME="ss" VALUE="<% $ss %>"></TD>
203 %   }
204
205 %   if ( $conf->exists('show_stateid') ) {
206       <TR>
207         <TD ALIGN="right">
208           <% mt('Account holder') |h %><BR>
209           <% mt("Driver's license or state ID #") |h %> 
210         </TD>
211         <TD><INPUT TYPE="text" NAME="stateid" VALUE="<% $stateid %>"></TD>
212         <TD ALIGN="right"><% mt('State') |h %></TD>
213         <TD><& /elements/select-state.html,
214                          'disable_empty' => 0,
215                          'empty_label'   => emt('(choose)'),
216                          'state'         => $stateid_state,
217                          'country'       => $cust_main->country,
218                          'prefix'        => 'stateid_',
219             &>
220         </TD>
221       </TR>
222 %   } else {
223       <INPUT TYPE="hidden" NAME="stateid" VALUE="<% $stateid %>">
224       <INPUT TYPE="hidden" NAME="stateid_state" VALUE="<% $stateid_state %>">
225 %   }
226
227 % } #end CARD/CHEK-specific section
228
229
230 <TR>
231   <TD COLSPAN=8>
232     <INPUT TYPE="checkbox" CHECKED NAME="save" VALUE="1">
233     <% mt('Remember this information') |h %>
234   </TD>
235 </TR>
236
237 % if ( $conf->exists("batch-enable")
238 %      || grep $payby eq $_, $conf->config('batch-enable_payby')
239 %    ) {
240 %
241 %     if ( grep $payby eq $_, $conf->config('realtime-disable_payby') ) {
242
243           <INPUT TYPE="hidden" NAME="batch" VALUE="1">
244
245 %     } else {
246
247           <TR>
248             <TD COLSPAN=2>
249               <INPUT TYPE="checkbox" NAME="batch" VALUE="1">
250               <% mt('Add to current batch') |h %> 
251             </TD>
252           </TR>
253
254 %     }
255 % }
256
257 <TR>
258   <TD COLSPAN=8>
259     <INPUT TYPE="checkbox"<% $auto ? ' CHECKED' : '' %> NAME="auto" VALUE="1" onClick="if (this.checked) { document.OneTrueForm.save.checked=true; }">
260     <% mt("Charge future payments to this [_1] automatically",$type{$payby}) |h %> 
261 % if ( @cust_payby ) {
262     <% mt('as') |h %>
263     <SELECT NAME="weight">
264 %     for ( 1 .. 1+scalar(grep { $_->payby =~ /^(CARD|CHEK)$/ } @cust_payby) ) {
265         <OPTION VALUE="<%$_%>"><% mt( $weight{$_} ) |h %>
266 %     }
267     </SELECT>
268 % } else {
269     <INPUT TYPE="hidden" NAME="weight" VALUE="1">
270 % }
271   </TD>
272 </TR>
273
274 </TABLE>
275 </DIV>
276
277 <BR>
278 <INPUT TYPE="submit" NAME="process" VALUE="<% mt('Process payment') |h %>">
279 </FORM>
280
281 <& /elements/footer.html &>
282 <%once>
283
284 my %weight = (
285   1 => 'Primary',
286   2 => 'Secondary',
287   3 => 'Tertiary',
288   4 => 'Fourth',
289   5 => 'Fifth',
290   6 => 'Sixth',
291   7 => 'Seventh',
292 );
293
294 </%once>
295 <%init>
296
297 die "access denied"
298   unless $FS::CurrentUser::CurrentUser->access_right('Process payment');
299
300 my %type = ( 'CARD' => 'credit card',
301              'CHEK' => 'electronic check (ACH)',
302            );
303
304 $cgi->param('payby') =~ /^(CARD|CHEK)$/
305   or die "unknown payby ". $cgi->param('payby');
306 my $payby = $1;
307
308 $cgi->param('custnum') =~ /^(\d+)$/
309   or die "illegal custnum ". $cgi->param('custnum');
310 my $custnum = $1;
311
312 my $cust_main = qsearchs( 'cust_main', { 'custnum'=>$custnum } );
313 die "unknown custnum $custnum" unless $cust_main;
314
315 my $balance = $cust_main->balance;
316
317 my $payinfo = '';
318
319 my $conf = new FS::Conf;
320
321 #false laziness w/selfservice make_payment.html shortcut for one-country
322 my %states = map { $_->state => 1 }
323                qsearch('cust_main_county', {
324                  'country' => $conf->config('countrydefault') || 'US'
325                } );
326 my @states = sort { $a cmp $b } keys %states;
327
328 my $amount = '';
329 if ( $balance > 0 ) {
330   # when configured to do so, amount will only auto-fill with balance
331   # if balance represents a single invoice
332   $amount = $balance
333     unless $conf->exists('manual_process-single_invoice_amount')
334       && ($cust_main->open_cust_bill != 1);
335 }
336
337 my $payunique = "webui-payment-". time. "-$$-". rand() * 2**32;
338
339 </%init>