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 'Apply credit', 'Unapply credit', 'Void credit', 'Unvoid credit',
236 'Billing event reports', 'View customer billing events',
240 #customer information
241 'total_owed' => $cust_main->total_owed,
242 'total_unapplied_refunds' => $cust_main->total_unapplied_refunds,
245 $opt{'date_format'} ||= '%m/%d/%Y';
248 foreach my $legacy_cust_bill ($cust_main->legacy_cust_bill) {
250 'date' => $legacy_cust_bill->_date,
252 'num' => $legacy_cust_bill->legacyid,
253 'desc' => include('payment_history/legacy_invoice.html', $legacy_cust_bill, %opt ),
254 'charge_nobal' => $legacy_cust_bill->charged,
259 my $num_cust_bill = 0;
260 foreach my $cust_bill ($cust_main->cust_bill) {
262 'date' => $cust_bill->_date,
264 'num' => $cust_bill->invnum,
265 'desc' => include('payment_history/invoice.html', $cust_bill, %opt ),
266 'charge' => $cust_bill->charged,
272 foreach my $cust_bill_void ($cust_main->cust_bill_void) {
274 'date' => $cust_bill_void->_date,
276 'num' => $cust_bill_void->invnum,
277 'desc' => include('payment_history/voided_invoice.html', $cust_bill_void, %opt ),
278 'void_charge' => $cust_bill_void->charged,
283 foreach my $cust_statement ($cust_main->cust_statement) {
285 'date' => $cust_statement->_date,
287 'num' => $cust_statement->statementnum,
288 'desc' => include('payment_history/statement.html', $cust_statement, %opt ),
289 #'charge' => $cust_bill->charged,
293 #payments (some false laziness w/credits)
294 foreach my $cust_pay ($cust_main->cust_pay) {
296 'date' => $cust_pay->_date,
298 'num' => $cust_pay->paynum,
299 'desc' => include('payment_history/payment.html', $cust_pay, %opt ),
300 'payment' => $cust_pay->paid,
301 #'target' => $target, #XXX
306 foreach my $cust_pay_pending ($cust_main->cust_pay_pending) {
308 'date' => $cust_pay_pending->_date,
310 'num' => $cust_pay_pending->paypendingnum,
311 'desc' => include('payment_history/pending_payment.html', $cust_pay_pending, %opt ),
312 'void_payment' => $cust_pay_pending->paid,
318 foreach my $cust_pay_void ($cust_main->cust_pay_void) {
320 'date' => $cust_pay_void->_date,
322 'num' => $cust_pay_void->paynum,
323 'desc' => include('payment_history/voided_payment.html', $cust_pay_void, %opt ),
324 'void_payment' => $cust_pay_void->paid,
330 foreach my $cust_credit_void ($cust_main->cust_credit_void) {
332 'date' => $cust_credit_void->_date,
334 'num' => $cust_credit_void->paynum,
335 'desc' => include('payment_history/voided_credit.html', $cust_credit_void, %opt ),
336 'void_credit' => $cust_credit_void->amount,
341 foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) {
343 'date' => $cust_pay_pending->_date,
345 'num' => $cust_pay_pending->paypendingnum,
346 'desc' => include('payment_history/attempted_payment.html', $cust_pay_pending, %opt ),
347 'void_payment' => $cust_pay_pending->paid, #??
348 #'target' => $target, #XXX
351 #declined batch payments
352 foreach my $cust_pay_batch (
353 $cust_main->cust_pay_batch(hashref => {status => 'Declined'})
355 my $pay_batch = $cust_pay_batch->pay_batch;
357 'date' => $pay_batch->upload,
359 'num' => $cust_pay_batch->paybatchnum,
360 'desc' => include('payment_history/attempted_batch_payment.html', $cust_pay_batch, %opt),
361 'void_payment' => $cust_pay_batch->amount,
365 #credits (some false laziness w/payments)
366 foreach my $cust_credit ($cust_main->cust_credit) {
368 'date' => $cust_credit->_date,
370 'num' => $cust_credit->crednum,
371 'desc' => include('payment_history/credit.html', $cust_credit, %opt ),
372 'credit' => $cust_credit->amount,
378 foreach my $cust_refund ($cust_main->cust_refund) {
380 'date' => $cust_refund->_date,
382 'num' => $cust_refund->refundnum,
383 'desc' => include('payment_history/refund.html', $cust_refund, %opt),
384 'refund' => $cust_refund->refund,
389 # sort in forward order first, and calculate running balances
390 my $years = $conf->config('payment_history-years') || 2;
391 my $older_than = time - $years * 31556926; #60*60*24*365.2422
394 @history = sort { $a->{date} <=> $b->{date}
395 or $a->{order} <=> $b->{order}
396 or $a->{num} <=> $b->{num}
402 foreach my $item (@history) {
403 $balance += $item->{'charge'} if exists $item->{'charge'};
404 $balance -= $item->{'payment'} if exists $item->{'payment'};
405 $balance -= $item->{'credit'} if exists $item->{'credit'};
406 $balance += $item->{'refund'} if exists $item->{'refund'};
407 $balance = sprintf("%.2f", $balance);
408 $balance =~ s/^\-0\.00$/0.00/;
409 $item->{'balance'} = $balance;
411 if ( $item->{'date'} < $older_than ) {
413 } elsif ( $history[$i-1]->{'hide'} ) {
414 # this is the end of the hidden section
415 $history[$i-1]->{'balance_forward'} = 1;
419 if ( @history and $history[-1]->{'hide'} ) {
420 # then everything is hidden
421 $history[-1]->{'balance_forward'} = 1;
424 # then sort in user-pref order
425 if ( $curuser->option('history_order') eq 'newest' ) {
426 @history = sort { $b->{date} <=> $a->{date}
427 or $b->{order} <=> $a->{order} #or still forward here?
428 or $b->{num} <=> $a->{num}
431 } # else it's already oldest-first, and there are no other options yet
433 sub translate_payby {
434 my ($payby,$payinfo) = (shift,shift);
436 FS::payby->payby2shortname,
437 BILL => $payinfo ? emt('Check #') : '',
438 CHEK => emt('Electronic check '),
439 PREP => emt('Prepaid card '),
440 CARD => emt('Credit card #'),
441 COMP => emt('Complimentary by '),
442 #CASH => emt('Cash'),
443 #WEST => emt('Western Union'),
444 #MCRD => emt('Manual credit card'),
446 $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby;
450 sub translate_payby_refund {
451 my ($payby,$payinfo) = (shift,shift);
453 FS::payby->payby2shortname,
454 BILL => $payinfo ? emt('Check #') : emt('Check'),
455 CHEK => emt('Electronic check '),
456 CARD => emt('Credit card #'),
457 COMP => emt('Complimentary by '),
459 $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby;
463 sub translate_payinfo {
465 my $payby = $object->payby;
466 my $payinfo = $object->payinfo;
468 if ( $payby eq 'CARD' ) {
469 $payinfo = $object->paymask;
470 } elsif ( $payby eq 'CHEK' ) {
471 #false laziness w/payinfo_Mixin::payby_payinfo_pretty, should use that
472 my( $account, $aba ) = split('@', $object->paymask );
473 if ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #blame canada
474 my($branch, $routing) = ($1, $2);
475 $payinfo = emt("Routing [_1], Branch [_2], Acct [_3]",
476 $routing, $branch, $account);
478 $payinfo = emt("Routing [_1], Acct [_2]", $aba, $account);
485 sub areyousure_link {
486 my ($url,$msg,$title,$label) = (shift,shift,shift,shift);
487 ' (<A HREF="javascript:areyousure(\''.$url.'\',\''.$msg.'\')" TITLE="'.$title.'">'.$label.'</A>)';