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', 'Resend 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,
243 'has_email_address' => scalar($cust_main->invoicing_list_emailonly),
246 $opt{'date_format'} ||= '%m/%d/%Y';
249 foreach my $legacy_cust_bill ($cust_main->legacy_cust_bill) {
251 'date' => $legacy_cust_bill->_date,
253 'num' => $legacy_cust_bill->legacyid,
254 'desc' => include('payment_history/legacy_invoice.html', $legacy_cust_bill, %opt ),
255 'charge_nobal' => $legacy_cust_bill->charged,
260 my $num_cust_bill = 0;
261 foreach my $cust_bill ($cust_main->cust_bill) {
263 'date' => $cust_bill->_date,
265 'num' => $cust_bill->invnum,
266 'desc' => include('payment_history/invoice.html', $cust_bill, %opt ),
267 'charge' => $cust_bill->charged,
273 foreach my $cust_bill_void ($cust_main->cust_bill_void) {
275 'date' => $cust_bill_void->_date,
277 'num' => $cust_bill_void->invnum,
278 'desc' => include('payment_history/voided_invoice.html', $cust_bill_void, %opt ),
279 'void_charge' => $cust_bill_void->charged,
284 foreach my $cust_statement ($cust_main->cust_statement) {
286 'date' => $cust_statement->_date,
288 'num' => $cust_statement->statementnum,
289 'desc' => include('payment_history/statement.html', $cust_statement, %opt ),
290 #'charge' => $cust_bill->charged,
294 #payments (some false laziness w/credits)
295 foreach my $cust_pay ($cust_main->cust_pay) {
297 'date' => $cust_pay->_date,
299 'num' => $cust_pay->paynum,
300 'desc' => include('payment_history/payment.html', $cust_pay, %opt ),
301 'payment' => $cust_pay->paid,
302 #'target' => $target, #XXX
307 foreach my $cust_pay_pending ($cust_main->cust_pay_pending) {
309 'date' => $cust_pay_pending->_date,
311 'num' => $cust_pay_pending->paypendingnum,
312 'desc' => include('payment_history/pending_payment.html', $cust_pay_pending, %opt ),
313 'void_payment' => $cust_pay_pending->paid,
319 foreach my $cust_pay_void ($cust_main->cust_pay_void) {
321 'date' => $cust_pay_void->_date,
323 'num' => $cust_pay_void->paynum,
324 'desc' => include('payment_history/voided_payment.html', $cust_pay_void, %opt ),
325 'void_payment' => $cust_pay_void->paid,
331 foreach my $cust_credit_void ($cust_main->cust_credit_void) {
333 'date' => $cust_credit_void->_date,
335 'num' => $cust_credit_void->paynum,
336 'desc' => include('payment_history/voided_credit.html', $cust_credit_void, %opt ),
337 'void_credit' => $cust_credit_void->amount,
342 foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) {
344 'date' => $cust_pay_pending->_date,
346 'num' => $cust_pay_pending->paypendingnum,
347 'desc' => include('payment_history/attempted_payment.html', $cust_pay_pending, %opt ),
348 'void_payment' => $cust_pay_pending->paid, #??
349 #'target' => $target, #XXX
352 #declined batch payments
353 foreach my $cust_pay_batch (
354 $cust_main->cust_pay_batch(hashref => {status => 'Declined'})
356 my $pay_batch = $cust_pay_batch->pay_batch;
358 'date' => $pay_batch->upload,
360 'num' => $cust_pay_batch->paybatchnum,
361 'desc' => include('payment_history/attempted_batch_payment.html', $cust_pay_batch, %opt),
362 'void_payment' => $cust_pay_batch->amount,
366 #credits (some false laziness w/payments)
367 foreach my $cust_credit ($cust_main->cust_credit) {
369 'date' => $cust_credit->_date,
371 'num' => $cust_credit->crednum,
372 'desc' => include('payment_history/credit.html', $cust_credit, %opt ),
373 'credit' => $cust_credit->amount,
379 foreach my $cust_refund ($cust_main->cust_refund) {
381 'date' => $cust_refund->_date,
383 'num' => $cust_refund->refundnum,
384 'desc' => include('payment_history/refund.html', $cust_refund, %opt),
385 'refund' => $cust_refund->refund,
390 # sort in forward order first, and calculate running balances
391 my $years = $conf->config('payment_history-years') || 2;
392 my $older_than = time - $years * 31556926; #60*60*24*365.2422
395 @history = sort { $a->{date} <=> $b->{date}
396 or $a->{order} <=> $b->{order}
397 or $a->{num} <=> $b->{num}
403 foreach my $item (@history) {
404 $balance += $item->{'charge'} if exists $item->{'charge'};
405 $balance -= $item->{'payment'} if exists $item->{'payment'};
406 $balance -= $item->{'credit'} if exists $item->{'credit'};
407 $balance += $item->{'refund'} if exists $item->{'refund'};
408 $balance = sprintf("%.2f", $balance);
409 $balance =~ s/^\-0\.00$/0.00/;
410 $item->{'balance'} = $balance;
412 if ( $item->{'date'} < $older_than ) {
414 } elsif ( $history[$i-1]->{'hide'} ) {
415 # this is the end of the hidden section
416 $history[$i-1]->{'balance_forward'} = 1;
420 if ( @history and $history[-1]->{'hide'} ) {
421 # then everything is hidden
422 $history[-1]->{'balance_forward'} = 1;
425 # then sort in user-pref order
426 if ( $curuser->option('history_order') eq 'newest' ) {
427 @history = sort { $b->{date} <=> $a->{date}
428 or $b->{order} <=> $a->{order} #or still forward here?
429 or $b->{num} <=> $a->{num}
432 } # else it's already oldest-first, and there are no other options yet
434 sub translate_payby {
435 my ($payby,$payinfo) = (shift,shift);
437 FS::payby->payby2shortname,
438 BILL => $payinfo ? emt('Check #') : '',
439 CHEK => emt('Electronic check '),
440 PREP => emt('Prepaid card '),
441 CARD => emt('Credit card #'),
442 COMP => emt('Complimentary by '),
443 #CASH => emt('Cash'),
444 #WEST => emt('Western Union'),
445 #MCRD => emt('Manual credit card'),
447 $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby;
451 sub translate_payby_refund {
452 my ($payby,$payinfo) = (shift,shift);
454 FS::payby->payby2shortname,
455 BILL => $payinfo ? emt('Check #') : emt('Check'),
456 CHEK => emt('Electronic check '),
457 CARD => emt('Credit card #'),
458 COMP => emt('Complimentary by '),
460 $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby;
464 sub translate_payinfo {
466 my $payby = $object->payby;
467 my $payinfo = $object->payinfo;
469 if ( $payby eq 'CARD' ) {
470 $payinfo = $object->paymask;
471 } elsif ( $payby eq 'CHEK' ) {
472 #false laziness w/payinfo_Mixin::payby_payinfo_pretty, should use that
473 my( $account, $aba ) = split('@', $object->paymask );
474 if ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #blame canada
475 my($branch, $routing) = ($1, $2);
476 $payinfo = emt("Routing [_1], Branch [_2], Acct [_3]",
477 $routing, $branch, $account);
479 $payinfo = emt("Routing [_1], Acct [_2]", $aba, $account);
486 sub areyousure_link {
487 my ($url,$msg,$title,$label) = (shift,shift,shift,shift);
488 ' (<A HREF="javascript:areyousure(\''.$url.'\',\''.$msg.'\')" TITLE="'.$title.'">'.$label.'</A>)';