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';
32 <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Date') |h %></TH>
33 <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Description') |h %></TH>
34 <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Invoice') |h %></FONT></TH>
35 <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Payment') |h %></FONT></TH>
36 <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('In-house Credit') |h %></FONT></TH>
37 <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Refund') |h %></FONT></TH>
38 <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Balance') |h %></FONT></TH>
41 %#display payment history
50 %foreach my $item ( @history ) {
52 % $lastdate = $item->{'date'};
55 % if ( $item->{'hide'} ) {
56 % $display = ' STYLE="display:none" ';
59 % if ( $bgcolor eq $bgcolor1 ) {
60 % $bgcolor = $bgcolor2;
62 % $bgcolor = $bgcolor1;
65 % my $charge = exists($item->{'charge'})
66 % ? sprintf("$money_char\%.2f", $item->{'charge'})
67 % : exists($item->{'charge_nobal'})
68 % ? sprintf("$money_char\%.2f", $item->{'charge_nobal'})
69 % : exists($item->{'void_charge'})
70 % ? sprintf("<DEL>$money_char\%.2f</DEL>", $item->{'void_charge'})
73 % my $payment = exists($item->{'payment'})
74 % ? sprintf("- $money_char\%.2f", $item->{'payment'})
77 % $payment ||= sprintf( "<DEL>- $money_char\%.2f</DEL>",
78 % $item->{'void_payment'}
80 % if exists($item->{'void_payment'});
82 % my $credit = exists($item->{'credit'})
83 % ? sprintf("- $money_char\%.2f", $item->{'credit'})
86 % $credit ||= sprintf( "<DEL>- $money_char\%.2f</DEL>",
87 % $item->{'void_credit'}
89 % if exists($item->{'void_credit'});
91 % my $refund = exists($item->{'refund'})
92 % ? sprintf("$money_char\%.2f", $item->{'refund'})
95 % my $target = exists($item->{'target'}) ? $item->{'target'} : '';
97 % my $showbalance = $money_char . $item->{'balance'};
98 % $showbalance =~ s/^\$\-/- \$/;
100 <TR <% $display ? $display.' ID="old_history'.$old_history++.'"' : ''%>>
101 <TD VALIGN="top" CLASS="grid" BGCOLOR="<% $bgcolor %>">
102 % unless ( !$target || $target{$target}++ ) {
104 <A NAME="<% $target %>">
107 <% time2str($date_format, $item->{'date'}) %>
108 % if ( $target && $target{$target} == 1 ) {
115 <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
116 <% $item->{'desc'} %>
118 <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
121 <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
124 <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
127 <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
130 <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
135 % if ( $item->{'balance_forward'} ) {
136 <& .balance_forward_row, $item->{'balance'}, $item->{'date'} &>
145 <SCRIPT TYPE="text/javascript">
147 function show_history () {
148 //alert('showing history!');
150 var balance_forward_row = document.getElementById('balance_forward_row');
152 balance_forward_row.style.display = 'none';
153 for ( var i = 0; i < <% $old_history %>; i++ ) {
154 var oldRow = document.getElementById('old_history'+i);
155 oldRow.style.display = '';
161 <%def .balance_forward_row>
162 % my( $b, $date ) = @_;
163 % ( my $balance_forward = $money_char. $b ) =~ s/^\$\-/- \$/;
165 <TR ID="balance_forward_row">
166 <TD CLASS="grid" BGCOLOR="#dddddd">
167 <% time2str($date_format, $date) %>
170 <TD CLASS="grid" BGCOLOR="#dddddd">
171 <I><% mt("Starting balance on [_1]", time2str($date_format, $date) ) |h %></I>
172 (<A HREF="javascript:void(0);" onClick="show_history();"><% mt('show prior history') |h %></A>)
175 <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
176 <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
177 <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
178 <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
179 <TD CLASS="grid" BGCOLOR="#dddddd" ALIGN="right"><I><% $balance_forward %></I></TD>
184 my $conf = new FS::Conf;
185 my $date_format = $conf->config('date_format') || '%m/%d/%Y';
186 my $money_char = $conf->config('money_char') || '$';
190 my( $cust_main ) = @_;
191 my $custnum = $cust_main->custnum;
193 my $curuser = $FS::CurrentUser::CurrentUser;
195 my @payby = grep /\w/, $conf->config('payby');
196 #@payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH WEST COMP ))
197 @payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH COMP ))
199 my %payby = map { $_=>1 } @payby;
202 'Queued' => 'O', #Open
204 'Complete' => 'R', #Resolved
214 ( map { $_ => scalar($conf->config($_)) }
215 qw( card_refund-days date_format )
217 ( map { $_ => $conf->exists($_) }
218 qw( deleteinvoices deletepayments deleterefunds pkg-balances
219 cust_credit_bill_pkg-manual cust_bill_pay_pkg-manual
222 'money_char ' => $money_char,
225 ( map { $_ => $curuser->access_right($_) }
227 'View invoices', 'Void invoices', 'Unvoid invoices', 'Delete invoices',
228 'Apply payment', 'Refund credit card payment', 'Refund Echeck payment',
229 'Credit card void', 'Echeck void', 'Void payments', 'Unvoid payments',
230 'Delete payment', 'Unapply payment',
231 'Apply credit', 'Delete credit', 'Unapply credit', 'Void credit', 'Unvoid credit',
233 'Billing event reports', 'View customer billing events',
237 #customer information
238 'total_owed' => $cust_main->total_owed,
239 'total_unapplied_refunds' => $cust_main->total_unapplied_refunds,
242 $opt{'date_format'} ||= '%m/%d/%Y';
245 foreach my $legacy_cust_bill ($cust_main->legacy_cust_bill) {
247 'date' => $legacy_cust_bill->_date,
249 'num' => $legacy_cust_bill->legacyid,
250 'desc' => include('payment_history/legacy_invoice.html', $legacy_cust_bill, %opt ),
251 'charge_nobal' => $legacy_cust_bill->charged,
256 my $num_cust_bill = 0;
257 foreach my $cust_bill ($cust_main->cust_bill) {
259 'date' => $cust_bill->_date,
261 'num' => $cust_bill->invnum,
262 'desc' => include('payment_history/invoice.html', $cust_bill, %opt ),
263 'charge' => $cust_bill->charged,
269 foreach my $cust_bill_void ($cust_main->cust_bill_void) {
271 'date' => $cust_bill_void->_date,
273 'num' => $cust_bill_void->invnum,
274 'desc' => include('payment_history/voided_invoice.html', $cust_bill_void, %opt ),
275 'void_charge' => $cust_bill_void->charged,
280 foreach my $cust_statement ($cust_main->cust_statement) {
282 'date' => $cust_statement->_date,
284 'num' => $cust_statement->statementnum,
285 'desc' => include('payment_history/statement.html', $cust_statement, %opt ),
286 #'charge' => $cust_bill->charged,
290 #payments (some false laziness w/credits)
291 foreach my $cust_pay ($cust_main->cust_pay) {
293 'date' => $cust_pay->_date,
295 'num' => $cust_pay->paynum,
296 'desc' => include('payment_history/payment.html', $cust_pay, %opt ),
297 'payment' => $cust_pay->paid,
298 #'target' => $target, #XXX
303 foreach my $cust_pay_pending ($cust_main->cust_pay_pending) {
305 'date' => $cust_pay_pending->_date,
307 'num' => $cust_pay_pending->paypendingnum,
308 'desc' => include('payment_history/pending_payment.html', $cust_pay_pending, %opt ),
309 'void_payment' => $cust_pay_pending->paid,
315 foreach my $cust_pay_void ($cust_main->cust_pay_void) {
317 'date' => $cust_pay_void->_date,
319 'num' => $cust_pay_void->paynum,
320 'desc' => include('payment_history/voided_payment.html', $cust_pay_void, %opt ),
321 'void_payment' => $cust_pay_void->paid,
327 foreach my $cust_credit_void ($cust_main->cust_credit_void) {
329 'date' => $cust_credit_void->_date,
331 'num' => $cust_credit_void->paynum,
332 'desc' => include('payment_history/voided_credit.html', $cust_credit_void, %opt ),
333 'void_credit' => $cust_credit_void->amount,
338 foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) {
340 'date' => $cust_pay_pending->_date,
342 'num' => $cust_pay_pending->paypendingnum,
343 'desc' => include('payment_history/attempted_payment.html', $cust_pay_pending, %opt ),
344 'void_payment' => $cust_pay_pending->paid, #??
345 #'target' => $target, #XXX
348 #declined batch payments
349 foreach my $cust_pay_batch (
350 $cust_main->cust_pay_batch(hashref => {status => 'Declined'})
352 my $pay_batch = $cust_pay_batch->pay_batch;
354 'date' => $pay_batch->upload,
356 'num' => $cust_pay_batch->paybatchnum,
357 'desc' => include('payment_history/attempted_batch_payment.html', $cust_pay_batch, %opt),
358 'void_payment' => $cust_pay_batch->amount,
362 #credits (some false laziness w/payments)
363 foreach my $cust_credit ($cust_main->cust_credit) {
365 'date' => $cust_credit->_date,
367 'num' => $cust_credit->crednum,
368 'desc' => include('payment_history/credit.html', $cust_credit, %opt ),
369 'credit' => $cust_credit->amount,
375 foreach my $cust_refund ($cust_main->cust_refund) {
377 'date' => $cust_refund->_date,
379 'num' => $cust_refund->refundnum,
380 'desc' => include('payment_history/refund.html', $cust_refund, %opt),
381 'refund' => $cust_refund->refund,
386 # sort in forward order first, and calculate running balances
387 my $years = $conf->config('payment_history-years') || 2;
388 my $older_than = time - $years * 31556926; #60*60*24*365.2422
391 @history = sort { $a->{date} <=> $b->{date}
392 or $a->{order} <=> $b->{order}
393 or $a->{num} <=> $b->{num}
399 foreach my $item (@history) {
400 $balance += $item->{'charge'} if exists $item->{'charge'};
401 $balance -= $item->{'payment'} if exists $item->{'payment'};
402 $balance -= $item->{'credit'} if exists $item->{'credit'};
403 $balance += $item->{'refund'} if exists $item->{'refund'};
404 $balance = sprintf("%.2f", $balance);
405 $balance =~ s/^\-0\.00$/0.00/;
406 $item->{'balance'} = $balance;
408 if ( $item->{'date'} < $older_than ) {
410 } elsif ( $history[$i-1]->{'hide'} ) {
411 # this is the end of the hidden section
412 $history[$i-1]->{'balance_forward'} = 1;
416 if ( @history and $history[-1]->{'hide'} ) {
417 # then everything is hidden
418 $history[-1]->{'balance_forward'} = 1;
421 # then sort in user-pref order
422 if ( $curuser->option('history_order') eq 'newest' ) {
423 @history = sort { $b->{date} <=> $a->{date}
424 or $b->{order} <=> $a->{order} #or still forward here?
425 or $b->{num} <=> $a->{num}
428 } # else it's already oldest-first, and there are no other options yet
430 sub translate_payby {
431 my ($payby,$payinfo) = (shift,shift);
433 FS::payby->payby2shortname,
434 BILL => $payinfo ? emt('Check #') : '',
435 CHEK => emt('Electronic check '),
436 PREP => emt('Prepaid card '),
437 CARD => emt('Credit card #'),
438 COMP => emt('Complimentary by '),
439 #CASH => emt('Cash'),
440 #WEST => emt('Western Union'),
441 #MCRD => emt('Manual credit card'),
443 $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby;
447 sub translate_payby_refund {
448 my ($payby,$payinfo) = (shift,shift);
450 FS::payby->payby2shortname,
451 BILL => $payinfo ? emt('Check #') : emt('Check'),
452 CHEK => emt('Electronic check '),
453 CARD => emt('Credit card #'),
454 COMP => emt('Complimentary by '),
456 $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby;
460 sub translate_payinfo {
462 my $payby = $object->payby;
463 my $payinfo = $object->payinfo;
465 if ( $payby eq 'CARD' ) {
466 $payinfo = $object->paymask;
467 } elsif ( $payby eq 'CHEK' ) {
468 #false laziness w/payinfo_Mixin::payby_payinfo_pretty, should use that
469 my( $account, $aba ) = split('@', $object->paymask );
470 if ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #blame canada
471 my($branch, $routing) = ($1, $2);
472 $payinfo = emt("Routing [_1], Branch [_2], Acct [_3]",
473 $routing, $branch, $account);
475 $payinfo = emt("Routing [_1], Acct [_2]", $aba, $account);
482 sub areyousure_link {
483 my ($url,$msg,$title,$label) = (shift,shift,shift,shift);
484 ' (<A HREF="javascript:areyousure(\''.$url.'\',\''.$msg.'\')" TITLE="'.$title.'">'.$label.'</A>)';