payment history reverse order balance quirk with two check payments in same batch...
[freeside.git] / httemplate / view / cust_main / payment_history.html
1 <TABLE>
2   <TR>
3     <TD ALIGN="left">
4
5 %# payment links
6
7 % my $s = 0;
8 % if ( $payby{'BILL'} && $curuser->access_right(['Post payment', 'Post check payment' ]) ) { 
9   <% $s++ ? ' | ' : '' %>
10   <& /elements/popup_link-cust_main.html,
11                'label'       => emt('Enter check payment'),
12                'action'      => "${p}edit/cust_pay.cgi?popup=1;payby=BILL",
13                'cust_main'   => $cust_main,
14                'actionlabel' => emt('Enter check payment'),
15                'width'       => ( $opt{'pkg-balances'} ? 763 : 392),
16                'height'      => 392,
17   &>
18 % } 
19
20 % if ( $payby{'CASH'} && $curuser->access_right(['Post payment', 'Post cash payment']) ) { 
21   <% $s++ ? ' | ' : '' %>
22   <& /elements/popup_link-cust_main.html,
23                'label'       => emt('Enter cash payment'),
24                'action'      => "${p}edit/cust_pay.cgi?popup=1;payby=CASH",
25                'cust_main'   => $cust_main,
26                'actionlabel' => emt('Enter cash payment'),
27                'width'       => ( $opt{'pkg-balances'} ? 763 : 392),
28                'height'      => 392,
29   &>
30 % } 
31
32 % if ( $payby{'WEST'} && $curuser->access_right('Post payment') ) { 
33   <% $s++ ? ' | ' : '' %>
34   <A HREF="<% $p %>edit/cust_pay.cgi?payby=WEST;custnum=<% $custnum %>"><% mt('Enter Western Union payment') |h %></A>
35 % } 
36
37 <% $s ? '<BR>' : '' %>
38 % $s=0;
39
40 % if ( ( $payby{'CARD'} || $payby{'DCRD'} )
41 %        && $curuser->access_right(['Process payment', 'Process credit card payment'])
42 %        && ! $cust_main->is_encrypted($cust_main->payinfo)
43 %      ) {
44   <% $s++ ? ' | ' : '' %>
45   <A HREF="<% $p %>misc/payment.cgi?payby=CARD;custnum=<% $custnum %>"><% mt('Process credit card payment') |h %></A>
46 % } 
47
48 % if ( ( $payby{'CHEK'} || $payby{'DCHK'} )
49 %        && $curuser->access_right(['Process payment', 'Process Echeck payment'])
50 %        && ! $cust_main->is_encrypted($cust_main->payinfo)
51 %      ) {
52   <% $s++ ? ' | ' : '' %>
53   <A HREF="<% $p %>misc/payment.cgi?payby=CHEK;custnum=<% $custnum %>"><% mt('Process electronic check (ACH) payment') |h %></A>
54 % } 
55
56 % if ( $payby{'MCRD'} && $curuser->access_right('Post payment') ) { 
57   <% $s++ ? ' | ' : '' %>
58   <A HREF="<% $p %>edit/cust_pay.cgi?payby=MCRD;custnum=<% $custnum %>"><% mt('Post manual (offline/POS) credit card payment') |h %></A>
59 % } 
60
61 <% $s ? '<BR>' : '' %>
62
63 %# credit links
64
65 % $s=0;
66 % if ( $curuser->access_right('Post credit') ) { 
67   <% $s++ ? ' | ' : '' %>
68   <& /elements/popup_link-cust_main.html,
69                'label'       => emt('Enter credit'),
70                'action'      => "${p}edit/cust_credit.cgi",
71                'cust_main'   => $cust_main,
72                'actionlabel' => emt('Enter credit'),
73                'width'       => ( $opt{'pkg-balances'} ? 763 : 616),
74   &>
75 % }
76 % if ( $curuser->access_right('Credit line items') ) { 
77   <% $s++ ? ' | ' : '' %>
78   <& /elements/popup_link-cust_main.html,
79                'label'       => emt('Credit line items'),
80                #'action'      => "${p}search/cust_bill_pkg.cgi?nottax=1;type=select",
81                'action'      => "${p}edit/credit-cust_bill_pkg.html",
82                'cust_main'   => $cust_main,
83                'actionlabel' => emt('Credit line items'),
84                'width'       => 968, #763,
85                'height'      => 575,
86   &>
87 % } 
88 <% $s ? '<BR>' : '' %>
89
90 %# refund links
91
92 % $s = 0;
93 % if ( $payby{'BILL'} && $curuser->access_right(['Post refund', 'Post check refund']) ) { 
94   <% $s++ ? ' | ' : '' %>
95   <& /elements/popup_link-cust_main.html,
96                'label'       => emt('Enter check refund'),
97                'action'      => "${p}edit/cust_refund.cgi?popup=1;payby=BILL",
98                'cust_main'   => $cust_main,
99                'actionlabel' => emt('Enter check refund'),
100                'width'       => 392,
101   &>
102 % } 
103
104 % if ( $payby{'CASH'} && $curuser->access_right(['Post refund', 'Post cash refund']) ) { 
105   <% $s++ ? ' | ' : '' %>
106   <& /elements/popup_link-cust_main.html,
107                'label'       => emt('Enter cash refund'),
108                'action'      => "${p}edit/cust_refund.cgi?popup=1;payby=CASH",
109                'cust_main'   => $cust_main,
110                'actionlabel' => emt('Enter cash refund'),
111                'width'       => 392,
112   &>
113 % } 
114
115 %# someday, perhaps.  very few gateways let you do unlinked refunds at all.
116 %# Authorize.net makes you sign a special form
117 %#
118 %#    % if ( ( $payby{'CARD'} || $payby{'DCRD'} )
119 %#    %        && $curuser->access_right('Process refund')
120 %#    %        && ! $cust_main->is_encrypted($cust_main->payinfo)
121 %#    %      ) {
122 %#      <% $s++ ? ' | ' : '' %>
123 %#      <A HREF="<% $p %>misc/refund.cgi?payby=CARD;custnum=<% $custnum %>">Process credit card refund</A>
124 %#    % } 
125 %#    
126 %#    % if ( ( $payby{'CHEK'} || $payby{'DCHK'} )
127 %#    %        && $curuser->access_right('Process refund')
128 %#    %        && ! $cust_main->is_encrypted($cust_main->payinfo)
129 %#    %      ) {
130 %#      <% $s++ ? ' | ' : '' %>
131 %#      <A HREF="<% $p %>misc/refund.cgi?payby=CHEK;custnum=<% $custnum %>">Process electronic check (ACH) refund</A>
132 %#    % } 
133
134 % if ( $payby{'MCRD'} && $curuser->access_right('Post refund') ) { 
135   <% $s++ ? ' | ' : '' %>
136   <A HREF="<% $p %>edit/cust_refund.cgi?payby=MCRD;custnum=<% $custnum %>"><% mt('Post manual (offline/POS) credit card refund') |h %></A>
137 % } 
138
139     </TD>
140     <TD ALIGN="right" VALIGN="top">
141
142 %# invoice reports, combined statement
143 % if ( $curuser->access_right('List invoices') ) { 
144 %   if ( $num_cust_bill > 0 ) {
145   <A HREF="<% $p %>view/cust_main_statement-pdf.cgi?<% $custnum %>"><%
146   mt('Download typeset statement PDF') |h %></A>
147   <BR>
148 %   }
149   <A HREF="<% $p %>search/report_cust_bill.html?custnum=<% $custnum %>"><% mt('Invoice reports') |h %></A>
150 % } 
151 <BR>
152
153 %# XXX payments, credits, refund reports
154
155 %# tax exemption link
156
157 % my $view_exemptions = $curuser->access_right('View customer tax exemptions');
158 % my $add_adjustment = ( $conf->exists('enable_tax_adjustments')
159 %                       && $curuser->access_right('Add customer tax adjustment')
160 %                      );
161 % if ( $view_exemptions || $add_adjustment ) {
162
163 %   if ( $view_exemptions ) {
164       <A HREF="<% $p %>search/cust_tax_exempt_pkg.cgi?custnum=<% $custnum %>"><% mt('View tax exemptions') |h %></A>
165       <% $add_adjustment ? '|' : '' %>
166 %   } 
167
168 %   if ( $add_adjustment ) {
169       <& /elements/popup_link.html, {
170            'action' => $p.'edit/cust_tax_adjustment.html?custnum='. $cust_main->custnum,
171            'label'  => emt('Add tax adjustment'),
172            'actionlabel' => emt('Add tax adjustment'),
173            'height' => 200,
174          }
175       &>
176       |
177       <A HREF="<% $p %>search/cust_tax_adjustment.html?custnum=<% $custnum %>"><% mt('View tax adjustments') |h %></A>
178 %   } 
179
180   <BR>
181 % }
182
183 %# batched payment links
184
185 % if ( ( $conf->exists('batch-enable') || $conf->config('batch-enable_payby') )
186 %      && $curuser->access_right('View customer batched payments')
187 %    )
188 % { 
189     <% mt('View batched payments:') |h %> 
190 %   foreach my $status (qw( Queued In-transit Complete All )) {
191       <A HREF="<% $p %>search/cust_pay_batch.cgi?status=<% $status{$status} %>;custnum=<% $custnum %>"><% mt($status) |h %></A> 
192       <% $status ne 'All' ? '|' : '' %>
193 %   }
194     <BR>
195 % } 
196
197 %# pending payment links
198
199 % if ( $curuser->access_right('View customer pending payments')
200 %      && scalar($cust_main->cust_pay_pending)
201 %    )
202 % {
203     <A HREF="<% $p %>search/cust_pay_pending.html?magic=_date;statusNOT=done;custnum=<% $custnum %>"><% mt('View pending payments') |h %></A><BR>
204 % }
205
206     </TD>
207   </TR>
208   <TR>
209     <TD COLSPAN=2>
210
211 %# and now the table
212
213 <& /elements/table-grid.html &>
214 % my $bgcolor1 = '#eeeeee';
215 %   my $bgcolor2 = '#ffffff';
216 %   my $bgcolor = '';
217
218 <TR>
219   <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Date') |h %></TH>
220   <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Description') |h %></TH>
221   <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Invoice') |h %></FONT></TH>
222   <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Payment') |h %></FONT></TH>
223   <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('In-house Credit') |h %></FONT></TH>
224   <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Refund') |h %></FONT></TH>
225   <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Balance') |h %></FONT></TH>
226 </TR>
227
228 %#display payment history
229
230 %my %target = ();
231 %
232 %my $hidden = 0;
233 %my $seen = 0;
234 %my $old_history = 0;
235 %my $lastdate = 0;
236 %
237 %foreach my $item ( @history ) {
238 %
239 %  $lastdate = $item->{'date'};
240 %
241 %  my $display = '';
242 %  if ( $item->{'hide'} ) {
243 %    $display = ' STYLE="display:none" ';
244 %  }
245 %
246 %  if ( $bgcolor eq $bgcolor1 ) {
247 %    $bgcolor = $bgcolor2;
248 %  } else {
249 %    $bgcolor = $bgcolor1;
250 %  }
251 %
252 %  my $charge  = exists($item->{'charge'})
253 %                  ? sprintf("$money_char\%.2f", $item->{'charge'})
254 %                  : exists($item->{'charge_nobal'})
255 %                    ? sprintf("$money_char\%.2f", $item->{'charge_nobal'})
256 %                    : exists($item->{'void_charge'})
257 %                      ? sprintf("<DEL>$money_char\%.2f</DEL>", $item->{'void_charge'})
258 %                      : '';
259 %
260 %  my $payment = exists($item->{'payment'})
261 %                  ? sprintf("-&nbsp;$money_char\%.2f", $item->{'payment'})
262 %                  : '';
263 %
264 %  $payment ||= sprintf( "<DEL>-&nbsp;$money_char\%.2f</DEL>",
265 %                        $item->{'void_payment'}
266 %                      )
267 %    if exists($item->{'void_payment'});
268 %
269 %  my $credit  = exists($item->{'credit'})
270 %                  ? sprintf("-&nbsp;$money_char\%.2f", $item->{'credit'})
271 %                  : '';
272 %
273 %  $credit ||= sprintf( "<DEL>-&nbsp;$money_char\%.2f</DEL>",
274 %                       $item->{'void_credit'}
275 %                     )
276 %    if exists($item->{'void_credit'});
277 %
278 %  my $refund  = exists($item->{'refund'})
279 %                  ? sprintf("$money_char\%.2f", $item->{'refund'})
280 %                  : '';
281 %
282 %  my $target = exists($item->{'target'}) ? $item->{'target'} : '';
283 %
284 %  my $showbalance = $money_char . $item->{'balance'};
285 %  $showbalance =~ s/^\$\-/-&nbsp;\$/;
286
287   <TR <% $display ? $display.' ID="old_history'.$old_history++.'"'  : ''%>>
288     <TD VALIGN="top" CLASS="grid" BGCOLOR="<% $bgcolor %>">
289 % unless ( !$target || $target{$target}++ ) { 
290
291         <A NAME="<% $target %>">
292 % } 
293
294       <% time2str($date_format, $item->{'date'}) %>
295 % if ( $target && $target{$target} == 1 ) { 
296
297         </A>
298 % } 
299
300       </FONT>
301     </TD>
302     <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
303       <% $item->{'desc'} %>
304     </TD>
305     <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
306       <% $charge  %>
307     </TD>
308     <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
309       <% $payment %>
310     </TD>
311     <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
312       <% $credit  %>
313     </TD>
314     <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
315       <% $refund  %>
316     </TD>
317     <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
318       <% $showbalance %>
319     </TD>
320   </TR>
321
322 % if ( $item->{'balance_forward'} ) {
323 <& .balance_forward_row, $item->{'balance'}, $item->{'date'} &>
324 % } 
325 %} # foreach $item
326
327 </TABLE>
328     </TD>
329   </TR>
330 </TABLE>
331
332 <SCRIPT TYPE="text/javascript">
333
334 function show_history () {
335   //alert('showing history!');
336
337   var balance_forward_row = document.getElementById('balance_forward_row');
338
339   balance_forward_row.style.display = 'none';
340   for ( var i = 0; i < <% $old_history %>; i++ ) {
341     var oldRow = document.getElementById('old_history'+i);
342     oldRow.style.display = '';
343   }
344
345 }
346
347 </SCRIPT>
348 <%def .balance_forward_row>
349 %  my( $b, $date ) = @_;
350 %  ( my $balance_forward = $money_char. $b ) =~ s/^\$\-/-&nbsp;\$/;
351
352    <TR ID="balance_forward_row">
353      <TD CLASS="grid" BGCOLOR="#dddddd">
354        <% time2str($date_format, $date) %>
355      </TD>
356
357      <TD CLASS="grid" BGCOLOR="#dddddd">
358        <I><% mt("Starting balance on [_1]", time2str($date_format, $date) ) |h %></I>
359        (<A HREF="javascript:void(0);" onClick="show_history();"><% mt('show prior history') |h %></A>)
360      </TD>
361
362      <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
363      <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
364      <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
365      <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
366      <TD CLASS="grid" BGCOLOR="#dddddd" ALIGN="right"><I><% $balance_forward %></I></TD>
367
368    </TR>
369 </%def>
370 <%shared>
371 my $conf = new FS::Conf;
372 my $date_format = $conf->config('date_format') || '%m/%d/%Y';
373 my $money_char = $conf->config('money_char') || '$';
374 </%shared>
375 <%init>
376
377 my( $cust_main ) = @_;
378 my $custnum = $cust_main->custnum;
379
380 my $curuser = $FS::CurrentUser::CurrentUser;
381
382 my @payby = grep /\w/, $conf->config('payby');
383 #@payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH WEST COMP ))
384 @payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH COMP ))
385   unless @payby;
386 my %payby = map { $_=>1 } @payby;
387
388 my %status = (
389   'Queued'     => 'O', #Open
390   'In-transit' => 'I',
391   'Complete'   => 'R', #Resolved
392   'All'        => '',
393 );
394
395 #get payment history
396 my @history = ();
397
398 my %opt = (
399
400   #config
401   ( map { $_ => scalar($conf->config($_)) }
402         qw( card_refund-days date_format )
403   ),
404   ( map { $_ => $conf->exists($_) } 
405         qw( deleteinvoices deletepayments deleterefunds pkg-balances
406             cust_credit_bill_pkg-manual cust_bill_pay_pkg-manual
407           )
408   ),
409   'money_char             ' => $money_char,
410
411   #rights
412   ( map { $_ => $curuser->access_right($_) }
413       (
414         'View invoices', 'Void invoices', 'Unvoid invoices', 'Delete invoices',
415         'Apply payment', 'Refund credit card payment', 'Refund Echeck payment',
416         'Credit card void', 'Echeck void', 'Void payments', 'Unvoid payments',
417         'Delete payment', 'Unapply payment',
418         'Apply credit', 'Delete credit', 'Unapply credit',
419         'Delete refund',
420         'Billing event reports', 'View customer billing events',
421       )
422   ),
423
424   #customer information
425   'total_owed'              => $cust_main->total_owed,
426   'total_unapplied_refunds' => $cust_main->total_unapplied_refunds,
427 );
428
429 $opt{'date_format'} ||= '%m/%d/%Y';
430
431 #legacy invoices
432 foreach my $legacy_cust_bill ($cust_main->legacy_cust_bill) {
433   push @history, {
434     'date'   => $legacy_cust_bill->_date,
435     'order'  => 1,
436     'num'    => $legacy_cust_bill->legacyid,
437     'desc'   => include('payment_history/legacy_invoice.html', $legacy_cust_bill, %opt ),
438     'charge_nobal' => $legacy_cust_bill->charged,
439   };
440 }
441
442 #invoices
443 my $num_cust_bill = 0;
444 foreach my $cust_bill ($cust_main->cust_bill) {
445   push @history, {
446     'date'   => $cust_bill->_date,
447     'order'  => 1,
448     'num'    => $cust_bill->invnum,
449     'desc'   => include('payment_history/invoice.html', $cust_bill, %opt ),
450     'charge' => $cust_bill->charged,
451   };
452   $num_cust_bill++;
453 }
454
455 #voided invoices
456 foreach my $cust_bill_void ($cust_main->cust_bill_void) {
457   push @history, {
458     'date'        => $cust_bill_void->_date,
459     'order'       => 0,
460     'num'         => $cust_bill_void->invnum,
461     'desc'        => include('payment_history/voided_invoice.html', $cust_bill_void, %opt ),
462     'void_charge' => $cust_bill_void->charged,
463   };
464 }
465
466 #statements
467 foreach my $cust_statement ($cust_main->cust_statement) {
468   push @history, {
469     'date'   => $cust_statement->_date,
470     'order'  => 2,
471     'num'    => $cust_statement->statementnum,
472     'desc'   => include('payment_history/statement.html', $cust_statement, %opt ),
473     #'charge' => $cust_bill->charged,
474   };
475 }
476
477 #payments (some false laziness w/credits)
478 foreach my $cust_pay ($cust_main->cust_pay) {
479   push @history, {
480     'date'    => $cust_pay->_date,
481     'order'   => 6,
482     'num'     => $cust_pay->paynum,
483     'desc'    => include('payment_history/payment.html', $cust_pay, %opt ),
484     'payment' => $cust_pay->paid,
485     #'target'  => $target, #XXX
486   };
487 }
488
489 #pending payments 
490 foreach my $cust_pay_pending ($cust_main->cust_pay_pending) {
491   push @history, {
492     'date'    => $cust_pay_pending->_date,
493     'order'   => 4,
494     'num'     => $cust_pay_pending->paypendingnum,
495     'desc'    => include('payment_history/pending_payment.html', $cust_pay_pending, %opt ),
496     'void_payment' => $cust_pay_pending->paid, 
497   };
498 }
499
500
501 #voided payments
502 foreach my $cust_pay_void ($cust_main->cust_pay_void) {
503   push @history, {
504     'date'   => $cust_pay_void->_date,
505     'order'  => 3,
506     'num'    => $cust_pay_void->paynum,
507     'desc'   => include('payment_history/voided_payment.html', $cust_pay_void, %opt ),
508     'void_payment' => $cust_pay_void->paid,
509   };
510
511 }
512
513 #voided credits 
514 foreach my $cust_credit_void ($cust_main->cust_credit_void) {
515   push @history, {
516     'date'        => $cust_credit_void->_date,
517     'order'       => 7,
518     'num'         => $cust_credit_void->paynum,
519     'desc'        => include('payment_history/voided_credit.html', $cust_credit_void, %opt ),
520     'void_credit' => $cust_credit_void->amount,
521   };
522 }
523
524 #declined payments
525 foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) {
526   push @history, {
527     'date'    => $cust_pay_pending->_date,
528     'order'   => 5,
529     'num'     => $cust_pay_pending->paypendingnum,
530     'desc'    => include('payment_history/attempted_payment.html', $cust_pay_pending, %opt ),
531     'void_payment' => $cust_pay_pending->paid, #??
532     #'target'  => $target, #XXX
533   };
534 }
535 #declined batch payments
536 foreach my $cust_pay_batch (
537   $cust_main->cust_pay_batch(hashref => {status => 'Declined'})
538 ) {
539   my $pay_batch = $cust_pay_batch->pay_batch;
540   push @history, {
541     'date'    => $pay_batch->upload,
542     'order'   => 5,
543     'num'     => $cust_pay_batch->paybatchnum,
544     'desc'    => include('payment_history/attempted_batch_payment.html', $cust_pay_batch, %opt),
545     'void_payment' => $cust_pay_batch->amount,
546   };
547 }
548
549 #credits (some false laziness w/payments)
550 foreach my $cust_credit ($cust_main->cust_credit) {
551   push @history, {
552     'date'   => $cust_credit->_date,
553     'order'  => 8,
554     'num'    => $cust_credit->crednum,
555     'desc'   => include('payment_history/credit.html', $cust_credit, %opt ),
556     'credit' => $cust_credit->amount,
557   };
558
559 }
560
561 #refunds
562 foreach my $cust_refund ($cust_main->cust_refund) {
563   push @history, {
564     'date'   => $cust_refund->_date,
565     'order'  => 9,
566     'num'    => $cust_refund->refundnum,
567     'desc'   => include('payment_history/refund.html', $cust_refund, %opt),
568     'refund' => $cust_refund->refund,
569   };
570
571 }
572
573 # sort in forward order first, and calculate running balances
574 my $years =  $conf->config('payment_history-years') || 2;
575 my $older_than = time - $years * 31556926; #60*60*24*365.2422
576 my $balance = 0;
577
578 @history = sort {    $a->{date}  <=> $b->{date}
579                   or $a->{order} <=> $b->{order}
580                   or $a->{num}   <=> $b->{num}
581                 }
582              @history;
583
584 my $i = 0;
585 my $balance_forward;
586 foreach my $item (@history) {
587   $balance += $item->{'charge'}  if exists $item->{'charge'};
588   $balance -= $item->{'payment'} if exists $item->{'payment'};
589   $balance -= $item->{'credit'}  if exists $item->{'credit'};
590   $balance += $item->{'refund'}  if exists $item->{'refund'};
591   $balance = sprintf("%.2f", $balance);
592   $balance =~ s/^\-0\.00$/0.00/;
593   $item->{'balance'} = $balance;
594
595   if ( $item->{'date'} < $older_than ) {
596     $item->{'hide'} = 1;
597   } elsif ( $history[$i-1]->{'hide'} ) {
598     # this is the end of the hidden section
599     $history[$i-1]->{'balance_forward'} = 1;
600   }
601   $i++;
602 }
603 if ( @history and $history[-1]->{'hide'} ) {
604   # then everything is hidden
605   $history[-1]->{'balance_forward'} = 1;
606 }
607
608 # then sort in user-pref order
609 if ( $curuser->option('history_order') eq 'newest' ) {
610   @history = sort {    $b->{date}  <=> $a->{date}
611                     or $b->{order} <=> $a->{order} #or still forward here?
612                     or $b->{num}   <=> $a->{num}
613                   }
614                @history;
615 } # else it's already oldest-first, and there are no other options yet
616
617 sub translate_payby {
618     my ($payby,$payinfo) = (shift,shift);
619     my %payby = (
620         FS::payby->payby2shortname,
621         BILL    => $payinfo ? emt('Check #') : '',
622         CHEK    => emt('Electronic check '),
623         PREP    => emt('Prepaid card '),
624         CARD    => emt('Credit card #'),
625         COMP    => emt('Complimentary by '),
626         #CASH    => emt('Cash'),
627         #WEST    => emt('Western Union'),
628         #MCRD    => emt('Manual credit card'),
629     );
630     $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby; 
631     $payby;
632 };
633
634 sub translate_payby_refund {
635     my ($payby,$payinfo) = (shift,shift);
636     my %payby = (
637         FS::payby->payby2shortname,
638         BILL    => $payinfo ? emt('Check #') : emt('Check'),
639         CHEK    => emt('Electronic check '),
640         CARD    => emt('Credit card #'),
641         COMP    => emt('Complimentary by '),
642     );
643     $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby; 
644     $payby;
645 };
646
647 sub translate_payinfo {
648     my $object = shift;
649     my $payby = $object->payby;
650     my $payinfo = $object->payinfo;
651
652     if ( $payby eq 'CARD' ) {
653         $payinfo = $object->paymask;
654     } elsif ( $payby eq 'CHEK' ) {
655         #false laziness w/payinfo_Mixin::payby_payinfo_pretty, should use that
656         my( $account, $aba ) = split('@', $object->paymask );
657         if ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #blame canada
658           my($branch, $routing) = ($1, $2);
659           $payinfo = emt("Routing [_1], Branch [_2], Acct [_3]",
660                          $routing, $branch, $account);
661         } else {
662           $payinfo = emt("Routing [_1], Acct [_2]", $aba, $account);
663         }
664     }
665
666     ($payby,$payinfo);
667 }
668
669 sub areyousure_link {
670     my ($url,$msg,$title,$label) = (shift,shift,shift,shift);
671     ' (<A HREF="javascript:areyousure(\''.$url.'\',\''.$msg.'\')" TITLE="'.$title.'">'.$label.'</A>)';
672 }
673
674 </%init>