5 %# batched payment links
7 % if ( ( $conf->exists('batch-enable') || $conf->config('batch-enable_payby') )
8 % && $curuser->access_right('View customer batched payments')
11 <% mt('View batched payments:') |h %>
12 % foreach my $status (qw( Queued In-transit Complete All )) {
13 <A HREF="<% $p %>search/cust_pay_batch.cgi?status=<% $status{$status} %>;custnum=<% $custnum %>"><% mt($status) |h %></A>
14 <% $status ne 'All' ? '|' : '' %>
26 <& /elements/table-grid.html &>
27 % my $bgcolor1 = '#eeeeee';
28 % my $bgcolor2 = '#ffffff';
33 <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Date') |h %></TH>
34 <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Description') |h %></TH>
35 <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Invoice') |h %></FONT></TH>
36 <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Payment') |h %></FONT></TH>
37 <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('In-house Credit') |h %></FONT></TH>
38 <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Refund') |h %></FONT></TH>
39 <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Balance') |h %></FONT></TH>
43 %#display payment history
52 %foreach my $item ( @history ) {
54 % $lastdate = $item->{'date'};
57 % if ( $item->{'hide'} ) {
58 % $display = ' STYLE="display:none" ';
61 % if ( $bgcolor eq $bgcolor1 ) {
62 % $bgcolor = $bgcolor2;
64 % $bgcolor = $bgcolor1;
67 % my $charge = exists($item->{'charge'})
68 % ? sprintf("$money_char\%.2f", $item->{'charge'})
69 % : exists($item->{'charge_nobal'})
70 % ? sprintf("$money_char\%.2f", $item->{'charge_nobal'})
71 % : exists($item->{'void_charge'})
72 % ? sprintf("<DEL>$money_char\%.2f</DEL>", $item->{'void_charge'})
75 % my $payment = exists($item->{'payment'})
76 % ? sprintf("- $money_char\%.2f", $item->{'payment'})
79 % $payment ||= sprintf( "<DEL>- $money_char\%.2f</DEL>",
80 % $item->{'void_payment'}
82 % if exists($item->{'void_payment'});
84 % my $credit = exists($item->{'credit'})
85 % ? sprintf("- $money_char\%.2f", $item->{'credit'})
88 % $credit ||= sprintf( "<DEL>- $money_char\%.2f</DEL>",
89 % $item->{'void_credit'}
91 % if exists($item->{'void_credit'});
93 % my $refund = exists($item->{'refund'})
94 % ? sprintf("$money_char\%.2f", $item->{'refund'})
97 % my $target = exists($item->{'target'}) ? $item->{'target'} : '';
99 % my $showbalance = $money_char . $item->{'balance'};
100 % $showbalance =~ s/^\$\-/- \$/;
102 <TR <% $display ? $display.' ID="old_history'.$old_history++.'"' : ''%>>
103 <TD VALIGN="top" CLASS="grid" BGCOLOR="<% $bgcolor %>">
104 % unless ( !$target || $target{$target}++ ) {
106 <A NAME="<% $target %>">
109 <% time2str($date_format, $item->{'date'}) %>
110 % if ( $target && $target{$target} == 1 ) {
117 <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
118 <% $item->{'desc'} %>
120 <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
123 <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
126 <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
129 <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
132 <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
137 % if ( $item->{'balance_forward'} ) {
138 <& .balance_forward_row, $item->{'balance'}, $item->{'date'} &>
147 <SCRIPT TYPE="text/javascript">
149 function show_history () {
150 //alert('showing history!');
152 var balance_forward_row = document.getElementById('balance_forward_row');
154 balance_forward_row.style.display = 'none';
155 for ( var i = 0; i < <% $old_history %>; i++ ) {
156 var oldRow = document.getElementById('old_history'+i);
157 oldRow.style.display = '';
163 <%def .balance_forward_row>
164 % my( $b, $date ) = @_;
165 % ( my $balance_forward = $money_char. $b ) =~ s/^\$\-/- \$/;
167 <TR ID="balance_forward_row">
168 <TD CLASS="grid" BGCOLOR="#dddddd">
169 <% time2str($date_format, $date) %>
172 <TD CLASS="grid" BGCOLOR="#dddddd">
173 <I><% mt("Starting balance on [_1]", time2str($date_format, $date) ) |h %></I>
174 (<A HREF="javascript:void(0);" onClick="show_history();"><% mt('show prior history') |h %></A>)
177 <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
178 <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
179 <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
180 <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
181 <TD CLASS="grid" BGCOLOR="#dddddd" ALIGN="right"><I><% $balance_forward %></I></TD>
186 my $conf = new FS::Conf;
187 my $date_format = $conf->config('date_format') || '%m/%d/%Y';
188 my $money_char = $conf->config('money_char') || '$';
192 my( $cust_main ) = @_;
193 my $custnum = $cust_main->custnum;
195 my $curuser = $FS::CurrentUser::CurrentUser;
198 'Queued' => 'O', #Open
200 'Complete' => 'R', #Resolved
210 ( map { $_ => scalar($conf->config($_)) }
211 qw( card_refund-days date_format )
213 ( map { $_ => $conf->exists($_) }
214 qw( deletepayments deleterefunds pkg-balances
215 cust_credit_bill_pkg-manual cust_bill_pay_pkg-manual
218 'money_char ' => $money_char,
221 ( map { $_ => $curuser->access_right($_) }
223 'View invoices', 'Void invoices', 'Unvoid invoices', 'Resend invoices',
224 'Apply payment', 'Refund credit card payment', 'Refund Echeck payment',
225 'Post refund', 'Post check refund', 'Post cash refund ', 'Refund payment',
226 'Credit card void', 'Echeck void', 'Void payments', 'Unvoid payments',
228 'Apply credit', 'Unapply credit', 'Void credit', 'Unvoid credit',
230 'Billing event reports', 'View customer billing events',
234 #customer information
235 'total_owed' => $cust_main->total_owed,
236 'total_unapplied_refunds' => $cust_main->total_unapplied_refunds,
237 'has_email_address' => scalar($cust_main->invoicing_list_emailonly),
240 $opt{'date_format'} ||= '%m/%d/%Y';
243 foreach my $legacy_cust_bill ($cust_main->legacy_cust_bill) {
245 'date' => $legacy_cust_bill->_date,
247 'num' => $legacy_cust_bill->legacyid,
248 'desc' => include('payment_history/legacy_invoice.html', $legacy_cust_bill, %opt ),
249 'charge_nobal' => $legacy_cust_bill->charged,
254 my $num_cust_bill = 0;
255 foreach my $cust_bill ($cust_main->cust_bill) {
257 'date' => $cust_bill->_date,
259 'num' => $cust_bill->invnum,
260 'desc' => include('payment_history/invoice.html', $cust_bill, %opt ),
261 'charge' => $cust_bill->charged,
267 foreach my $cust_bill_void ($cust_main->cust_bill_void) {
269 'date' => $cust_bill_void->_date,
271 'num' => $cust_bill_void->invnum,
272 'desc' => include('payment_history/voided_invoice.html', $cust_bill_void, %opt ),
273 'void_charge' => $cust_bill_void->charged,
278 foreach my $cust_statement ($cust_main->cust_statement) {
280 'date' => $cust_statement->_date,
282 'num' => $cust_statement->statementnum,
283 'desc' => include('payment_history/statement.html', $cust_statement, %opt ),
284 #'charge' => $cust_bill->charged,
288 #payments (some false laziness w/credits)
289 foreach my $cust_pay ($cust_main->cust_pay) {
291 'date' => $cust_pay->_date,
293 'num' => $cust_pay->paynum,
294 'desc' => include('payment_history/payment.html', $cust_pay, %opt ),
295 'payment' => $cust_pay->paid,
296 #'target' => $target, #XXX
301 foreach my $cust_pay_pending ($cust_main->cust_pay_pending) {
303 'date' => $cust_pay_pending->_date,
305 'num' => $cust_pay_pending->paypendingnum,
306 'desc' => include('payment_history/pending_payment.html', $cust_pay_pending, %opt ),
307 'void_payment' => $cust_pay_pending->paid,
313 foreach my $cust_pay_void ($cust_main->cust_pay_void) {
315 'date' => $cust_pay_void->_date,
317 'num' => $cust_pay_void->paynum,
318 'desc' => include('payment_history/voided_payment.html', $cust_pay_void, %opt ),
319 'void_payment' => $cust_pay_void->paid,
325 foreach my $cust_credit_void ($cust_main->cust_credit_void) {
327 'date' => $cust_credit_void->_date,
329 'num' => $cust_credit_void->paynum,
330 'desc' => include('payment_history/voided_credit.html', $cust_credit_void, %opt ),
331 'void_credit' => $cust_credit_void->amount,
336 foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) {
338 'date' => $cust_pay_pending->_date,
340 'num' => $cust_pay_pending->paypendingnum,
341 'desc' => include('payment_history/attempted_payment.html', $cust_pay_pending, %opt ),
342 'void_payment' => $cust_pay_pending->paid, #??
343 #'target' => $target, #XXX
346 #declined batch payments
347 foreach my $cust_pay_batch (
348 $cust_main->cust_pay_batch(hashref => {status => 'Declined'})
350 my $pay_batch = $cust_pay_batch->pay_batch;
352 'date' => $pay_batch->upload,
354 'num' => $cust_pay_batch->paybatchnum,
355 'desc' => include('payment_history/attempted_batch_payment.html', $cust_pay_batch, %opt),
356 'void_payment' => $cust_pay_batch->amount,
360 #credits (some false laziness w/payments)
361 foreach my $cust_credit ($cust_main->cust_credit) {
363 'date' => $cust_credit->_date,
365 'num' => $cust_credit->crednum,
366 'desc' => include('payment_history/credit.html', $cust_credit, %opt ),
367 'credit' => $cust_credit->amount,
373 foreach my $cust_refund ($cust_main->cust_refund) {
375 'date' => $cust_refund->_date,
377 'num' => $cust_refund->refundnum,
378 'desc' => include('payment_history/refund.html', $cust_refund, %opt),
379 'refund' => $cust_refund->refund,
384 # sort in forward order first, and calculate running balances
385 my $years = $conf->config('payment_history-years') || 2;
386 my $older_than = time - $years * 31556926; #60*60*24*365.2422
389 @history = sort { $a->{date} <=> $b->{date}
390 or $a->{order} <=> $b->{order}
391 or $a->{num} <=> $b->{num}
397 foreach my $item (@history) {
398 $balance += $item->{'charge'} if exists $item->{'charge'};
399 $balance -= $item->{'payment'} if exists $item->{'payment'};
400 $balance -= $item->{'credit'} if exists $item->{'credit'};
401 $balance += $item->{'refund'} if exists $item->{'refund'};
402 $balance = sprintf("%.2f", $balance);
403 $balance =~ s/^\-0\.00$/0.00/;
404 $item->{'balance'} = $balance;
406 if ( $item->{'date'} < $older_than ) {
408 } elsif ( $history[$i-1]->{'hide'} ) {
409 # this is the end of the hidden section
410 $history[$i-1]->{'balance_forward'} = 1;
414 if ( @history and $history[-1]->{'hide'} ) {
415 # then everything is hidden
416 $history[-1]->{'balance_forward'} = 1;
419 # then sort in user-pref order
420 if ( $curuser->option('history_order') eq 'newest' ) {
421 @history = sort { $b->{date} <=> $a->{date}
422 or $b->{order} <=> $a->{order} #or still forward here?
423 or $b->{num} <=> $a->{num}
426 } # else it's already oldest-first, and there are no other options yet
428 sub translate_payby {
429 my ($payby,$payinfo) = (shift,shift);
431 FS::payby->payby2shortname,
432 BILL => $payinfo ? emt('Check #') : '',
433 CHEK => emt('Electronic check '),
434 PREP => emt('Prepaid card '),
435 CARD => emt('Credit card #'),
436 COMP => emt('Complimentary by '),
437 #CASH => emt('Cash'),
438 #WEST => emt('Western Union'),
439 #MCRD => emt('Manual credit card'),
441 $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby;
445 sub translate_payby_refund {
446 my ($payby,$payinfo) = (shift,shift);
448 FS::payby->payby2shortname,
449 BILL => $payinfo ? emt('Check #') : emt('Check'),
450 CHEK => emt('Electronic check '),
451 CARD => emt('Credit card #'),
452 COMP => emt('Complimentary by '),
454 $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby;
458 sub translate_payinfo {
460 my $payby = $object->payby;
461 my $payinfo = $object->payinfo;
463 if ( $payby eq 'CARD' ) {
464 $payinfo = $object->paymask;
465 } elsif ( $payby eq 'CHEK' ) {
466 #false laziness w/payinfo_Mixin::payby_payinfo_pretty, should use that
467 my( $account, $aba ) = split('@', $object->paymask );
468 if ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #blame canada
469 my($branch, $routing) = ($1, $2);
470 $payinfo = emt("Routing [_1], Branch [_2], Acct [_3]",
471 $routing, $branch, $account);
473 $payinfo = emt("Routing [_1], Acct [_2]", $aba, $account);
480 sub areyousure_link {
481 my ($url,$msg,$title,$label) = (shift,shift,shift,shift);
482 ' (<A HREF="javascript:areyousure(\''.$url.'\',\''.$msg.'\')" TITLE="'.$title.'">'.$label.'</A>)';