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',
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,
239 $opt{'date_format'} ||= '%m/%d/%Y';
242 foreach my $legacy_cust_bill ($cust_main->legacy_cust_bill) {
244 'date' => $legacy_cust_bill->_date,
246 'num' => $legacy_cust_bill->legacyid,
247 'desc' => include('payment_history/legacy_invoice.html', $legacy_cust_bill, %opt ),
248 'charge_nobal' => $legacy_cust_bill->charged,
253 my $num_cust_bill = 0;
254 foreach my $cust_bill ($cust_main->cust_bill) {
256 'date' => $cust_bill->_date,
258 'num' => $cust_bill->invnum,
259 'desc' => include('payment_history/invoice.html', $cust_bill, %opt ),
260 'charge' => $cust_bill->charged,
266 foreach my $cust_bill_void ($cust_main->cust_bill_void) {
268 'date' => $cust_bill_void->_date,
270 'num' => $cust_bill_void->invnum,
271 'desc' => include('payment_history/voided_invoice.html', $cust_bill_void, %opt ),
272 'void_charge' => $cust_bill_void->charged,
277 foreach my $cust_statement ($cust_main->cust_statement) {
279 'date' => $cust_statement->_date,
281 'num' => $cust_statement->statementnum,
282 'desc' => include('payment_history/statement.html', $cust_statement, %opt ),
283 #'charge' => $cust_bill->charged,
287 #payments (some false laziness w/credits)
288 foreach my $cust_pay ($cust_main->cust_pay) {
290 'date' => $cust_pay->_date,
292 'num' => $cust_pay->paynum,
293 'desc' => include('payment_history/payment.html', $cust_pay, %opt ),
294 'payment' => $cust_pay->paid,
295 #'target' => $target, #XXX
300 foreach my $cust_pay_pending ($cust_main->cust_pay_pending) {
302 'date' => $cust_pay_pending->_date,
304 'num' => $cust_pay_pending->paypendingnum,
305 'desc' => include('payment_history/pending_payment.html', $cust_pay_pending, %opt ),
306 'void_payment' => $cust_pay_pending->paid,
312 foreach my $cust_pay_void ($cust_main->cust_pay_void) {
314 'date' => $cust_pay_void->_date,
316 'num' => $cust_pay_void->paynum,
317 'desc' => include('payment_history/voided_payment.html', $cust_pay_void, %opt ),
318 'void_payment' => $cust_pay_void->paid,
324 foreach my $cust_credit_void ($cust_main->cust_credit_void) {
326 'date' => $cust_credit_void->_date,
328 'num' => $cust_credit_void->paynum,
329 'desc' => include('payment_history/voided_credit.html', $cust_credit_void, %opt ),
330 'void_credit' => $cust_credit_void->amount,
335 foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) {
337 'date' => $cust_pay_pending->_date,
339 'num' => $cust_pay_pending->paypendingnum,
340 'desc' => include('payment_history/attempted_payment.html', $cust_pay_pending, %opt ),
341 'void_payment' => $cust_pay_pending->paid, #??
342 #'target' => $target, #XXX
345 #declined batch payments
346 foreach my $cust_pay_batch (
347 $cust_main->cust_pay_batch(hashref => {status => 'Declined'})
349 my $pay_batch = $cust_pay_batch->pay_batch;
351 'date' => $pay_batch->upload,
353 'num' => $cust_pay_batch->paybatchnum,
354 'desc' => include('payment_history/attempted_batch_payment.html', $cust_pay_batch, %opt),
355 'void_payment' => $cust_pay_batch->amount,
359 #credits (some false laziness w/payments)
360 foreach my $cust_credit ($cust_main->cust_credit) {
362 'date' => $cust_credit->_date,
364 'num' => $cust_credit->crednum,
365 'desc' => include('payment_history/credit.html', $cust_credit, %opt ),
366 'credit' => $cust_credit->amount,
372 foreach my $cust_refund ($cust_main->cust_refund) {
374 'date' => $cust_refund->_date,
376 'num' => $cust_refund->refundnum,
377 'desc' => include('payment_history/refund.html', $cust_refund, %opt),
378 'refund' => $cust_refund->refund,
383 # sort in forward order first, and calculate running balances
384 my $years = $conf->config('payment_history-years') || 2;
385 my $older_than = time - $years * 31556926; #60*60*24*365.2422
388 @history = sort { $a->{date} <=> $b->{date}
389 or $a->{order} <=> $b->{order}
390 or $a->{num} <=> $b->{num}
396 foreach my $item (@history) {
397 $balance += $item->{'charge'} if exists $item->{'charge'};
398 $balance -= $item->{'payment'} if exists $item->{'payment'};
399 $balance -= $item->{'credit'} if exists $item->{'credit'};
400 $balance += $item->{'refund'} if exists $item->{'refund'};
401 $balance = sprintf("%.2f", $balance);
402 $balance =~ s/^\-0\.00$/0.00/;
403 $item->{'balance'} = $balance;
405 if ( $item->{'date'} < $older_than ) {
407 } elsif ( $history[$i-1]->{'hide'} ) {
408 # this is the end of the hidden section
409 $history[$i-1]->{'balance_forward'} = 1;
413 if ( @history and $history[-1]->{'hide'} ) {
414 # then everything is hidden
415 $history[-1]->{'balance_forward'} = 1;
418 # then sort in user-pref order
419 if ( $curuser->option('history_order') eq 'newest' ) {
420 @history = sort { $b->{date} <=> $a->{date}
421 or $b->{order} <=> $a->{order} #or still forward here?
422 or $b->{num} <=> $a->{num}
425 } # else it's already oldest-first, and there are no other options yet
427 sub translate_payby {
428 my ($payby,$payinfo) = (shift,shift);
430 FS::payby->payby2shortname,
431 BILL => $payinfo ? emt('Check #') : '',
432 CHEK => emt('Electronic check '),
433 PREP => emt('Prepaid card '),
434 CARD => emt('Credit card #'),
435 COMP => emt('Complimentary by '),
436 #CASH => emt('Cash'),
437 #WEST => emt('Western Union'),
438 #MCRD => emt('Manual credit card'),
440 $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby;
444 sub translate_payby_refund {
445 my ($payby,$payinfo) = (shift,shift);
447 FS::payby->payby2shortname,
448 BILL => $payinfo ? emt('Check #') : emt('Check'),
449 CHEK => emt('Electronic check '),
450 CARD => emt('Credit card #'),
451 COMP => emt('Complimentary by '),
453 $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby;
457 sub translate_payinfo {
459 my $payby = $object->payby;
460 my $payinfo = $object->payinfo;
462 if ( $payby eq 'CARD' ) {
463 $payinfo = $object->paymask;
464 } elsif ( $payby eq 'CHEK' ) {
465 #false laziness w/payinfo_Mixin::payby_payinfo_pretty, should use that
466 my( $account, $aba ) = split('@', $object->paymask );
467 if ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #blame canada
468 my($branch, $routing) = ($1, $2);
469 $payinfo = emt("Routing [_1], Branch [_2], Acct [_3]",
470 $routing, $branch, $account);
472 $payinfo = emt("Routing [_1], Acct [_2]", $aba, $account);
479 sub areyousure_link {
480 my ($url,$msg,$title,$label) = (shift,shift,shift,shift);
481 ' (<A HREF="javascript:areyousure(\''.$url.'\',\''.$msg.'\')" TITLE="'.$title.'">'.$label.'</A>)';