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;
197 my @payby = grep /\w/, $conf->config('payby');
198 #@payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH WEST COMP ))
199 @payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH COMP ))
201 my %payby = map { $_=>1 } @payby;
204 'Queued' => 'O', #Open
206 'Complete' => 'R', #Resolved
216 ( map { $_ => scalar($conf->config($_)) }
217 qw( card_refund-days date_format )
219 ( map { $_ => $conf->exists($_) }
220 qw( deletepayments deleterefunds pkg-balances
221 cust_credit_bill_pkg-manual cust_bill_pay_pkg-manual
224 'money_char ' => $money_char,
227 ( map { $_ => $curuser->access_right($_) }
229 'View invoices', 'Void invoices', 'Unvoid invoices',
230 'Apply payment', 'Refund credit card payment', 'Refund Echeck payment',
231 'Post refund', 'Post check refund', 'Post cash refund ', 'Refund payment',
232 'Credit card void', 'Echeck void', 'Void payments', 'Unvoid payments',
234 'Delete payment', 'Unapply payment',
235 'Apply credit', 'Delete credit', 'Unapply credit', 'Void credit', 'Unvoid credit',
238 'Apply credit', 'Unapply credit', 'Void credit', 'Unvoid credit',
239 >>>>>>> 727d620... remove payment deletion, RT#37908
241 'Billing event reports', 'View customer billing events',
245 #customer information
246 'total_owed' => $cust_main->total_owed,
247 'total_unapplied_refunds' => $cust_main->total_unapplied_refunds,
250 $opt{'date_format'} ||= '%m/%d/%Y';
253 foreach my $legacy_cust_bill ($cust_main->legacy_cust_bill) {
255 'date' => $legacy_cust_bill->_date,
257 'num' => $legacy_cust_bill->legacyid,
258 'desc' => include('payment_history/legacy_invoice.html', $legacy_cust_bill, %opt ),
259 'charge_nobal' => $legacy_cust_bill->charged,
264 my $num_cust_bill = 0;
265 foreach my $cust_bill ($cust_main->cust_bill) {
267 'date' => $cust_bill->_date,
269 'num' => $cust_bill->invnum,
270 'desc' => include('payment_history/invoice.html', $cust_bill, %opt ),
271 'charge' => $cust_bill->charged,
277 foreach my $cust_bill_void ($cust_main->cust_bill_void) {
279 'date' => $cust_bill_void->_date,
281 'num' => $cust_bill_void->invnum,
282 'desc' => include('payment_history/voided_invoice.html', $cust_bill_void, %opt ),
283 'void_charge' => $cust_bill_void->charged,
288 foreach my $cust_statement ($cust_main->cust_statement) {
290 'date' => $cust_statement->_date,
292 'num' => $cust_statement->statementnum,
293 'desc' => include('payment_history/statement.html', $cust_statement, %opt ),
294 #'charge' => $cust_bill->charged,
298 #payments (some false laziness w/credits)
299 foreach my $cust_pay ($cust_main->cust_pay) {
301 'date' => $cust_pay->_date,
303 'num' => $cust_pay->paynum,
304 'desc' => include('payment_history/payment.html', $cust_pay, %opt ),
305 'payment' => $cust_pay->paid,
306 #'target' => $target, #XXX
311 foreach my $cust_pay_pending ($cust_main->cust_pay_pending) {
313 'date' => $cust_pay_pending->_date,
315 'num' => $cust_pay_pending->paypendingnum,
316 'desc' => include('payment_history/pending_payment.html', $cust_pay_pending, %opt ),
317 'void_payment' => $cust_pay_pending->paid,
323 foreach my $cust_pay_void ($cust_main->cust_pay_void) {
325 'date' => $cust_pay_void->_date,
327 'num' => $cust_pay_void->paynum,
328 'desc' => include('payment_history/voided_payment.html', $cust_pay_void, %opt ),
329 'void_payment' => $cust_pay_void->paid,
335 foreach my $cust_credit_void ($cust_main->cust_credit_void) {
337 'date' => $cust_credit_void->_date,
339 'num' => $cust_credit_void->paynum,
340 'desc' => include('payment_history/voided_credit.html', $cust_credit_void, %opt ),
341 'void_credit' => $cust_credit_void->amount,
346 foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) {
348 'date' => $cust_pay_pending->_date,
350 'num' => $cust_pay_pending->paypendingnum,
351 'desc' => include('payment_history/attempted_payment.html', $cust_pay_pending, %opt ),
352 'void_payment' => $cust_pay_pending->paid, #??
353 #'target' => $target, #XXX
356 #declined batch payments
357 foreach my $cust_pay_batch (
358 $cust_main->cust_pay_batch(hashref => {status => 'Declined'})
360 my $pay_batch = $cust_pay_batch->pay_batch;
362 'date' => $pay_batch->upload,
364 'num' => $cust_pay_batch->paybatchnum,
365 'desc' => include('payment_history/attempted_batch_payment.html', $cust_pay_batch, %opt),
366 'void_payment' => $cust_pay_batch->amount,
370 #credits (some false laziness w/payments)
371 foreach my $cust_credit ($cust_main->cust_credit) {
373 'date' => $cust_credit->_date,
375 'num' => $cust_credit->crednum,
376 'desc' => include('payment_history/credit.html', $cust_credit, %opt ),
377 'credit' => $cust_credit->amount,
383 foreach my $cust_refund ($cust_main->cust_refund) {
385 'date' => $cust_refund->_date,
387 'num' => $cust_refund->refundnum,
388 'desc' => include('payment_history/refund.html', $cust_refund, %opt),
389 'refund' => $cust_refund->refund,
394 # sort in forward order first, and calculate running balances
395 my $years = $conf->config('payment_history-years') || 2;
396 my $older_than = time - $years * 31556926; #60*60*24*365.2422
399 @history = sort { $a->{date} <=> $b->{date}
400 or $a->{order} <=> $b->{order}
401 or $a->{num} <=> $b->{num}
407 foreach my $item (@history) {
408 $balance += $item->{'charge'} if exists $item->{'charge'};
409 $balance -= $item->{'payment'} if exists $item->{'payment'};
410 $balance -= $item->{'credit'} if exists $item->{'credit'};
411 $balance += $item->{'refund'} if exists $item->{'refund'};
412 $balance = sprintf("%.2f", $balance);
413 $balance =~ s/^\-0\.00$/0.00/;
414 $item->{'balance'} = $balance;
416 if ( $item->{'date'} < $older_than ) {
418 } elsif ( $history[$i-1]->{'hide'} ) {
419 # this is the end of the hidden section
420 $history[$i-1]->{'balance_forward'} = 1;
424 if ( @history and $history[-1]->{'hide'} ) {
425 # then everything is hidden
426 $history[-1]->{'balance_forward'} = 1;
429 # then sort in user-pref order
430 if ( $curuser->option('history_order') eq 'newest' ) {
431 @history = sort { $b->{date} <=> $a->{date}
432 or $b->{order} <=> $a->{order} #or still forward here?
433 or $b->{num} <=> $a->{num}
436 } # else it's already oldest-first, and there are no other options yet
438 sub translate_payby {
439 my ($payby,$payinfo) = (shift,shift);
441 FS::payby->payby2shortname,
442 BILL => $payinfo ? emt('Check #') : '',
443 CHEK => emt('Electronic check '),
444 PREP => emt('Prepaid card '),
445 CARD => emt('Credit card #'),
446 COMP => emt('Complimentary by '),
447 #CASH => emt('Cash'),
448 #WEST => emt('Western Union'),
449 #MCRD => emt('Manual credit card'),
451 $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby;
455 sub translate_payby_refund {
456 my ($payby,$payinfo) = (shift,shift);
458 FS::payby->payby2shortname,
459 BILL => $payinfo ? emt('Check #') : emt('Check'),
460 CHEK => emt('Electronic check '),
461 CARD => emt('Credit card #'),
462 COMP => emt('Complimentary by '),
464 $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby;
468 sub translate_payinfo {
470 my $payby = $object->payby;
471 my $payinfo = $object->payinfo;
473 if ( $payby eq 'CARD' ) {
474 $payinfo = $object->paymask;
475 } elsif ( $payby eq 'CHEK' ) {
476 #false laziness w/payinfo_Mixin::payby_payinfo_pretty, should use that
477 my( $account, $aba ) = split('@', $object->paymask );
478 if ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #blame canada
479 my($branch, $routing) = ($1, $2);
480 $payinfo = emt("Routing [_1], Branch [_2], Acct [_3]",
481 $routing, $branch, $account);
483 $payinfo = emt("Routing [_1], Acct [_2]", $aba, $account);
490 sub areyousure_link {
491 my ($url,$msg,$title,$label) = (shift,shift,shift,shift);
492 ' (<A HREF="javascript:areyousure(\''.$url.'\',\''.$msg.'\')" TITLE="'.$title.'">'.$label.'</A>)';