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