backport refund reasons, #39398
[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'       => 440,
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', 'Resend 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   'has_email_address'       => scalar($cust_main->invoicing_list_emailonly),
448 );
449
450 $opt{'date_format'} ||= '%m/%d/%Y';
451
452 #legacy invoices
453 foreach my $legacy_cust_bill ($cust_main->legacy_cust_bill) {
454   push @history, {
455     'date'   => $legacy_cust_bill->_date,
456     'order'  => 1,
457     'num'    => $legacy_cust_bill->legacyid,
458     'desc'   => include('payment_history/legacy_invoice.html', $legacy_cust_bill, %opt ),
459     'charge_nobal' => $legacy_cust_bill->charged,
460   };
461 }
462
463 #invoices
464 my $num_cust_bill = 0;
465 foreach my $cust_bill ($cust_main->cust_bill) {
466   push @history, {
467     'date'   => $cust_bill->_date,
468     'order'  => 1,
469     'num'    => $cust_bill->invnum,
470     'desc'   => include('payment_history/invoice.html', $cust_bill, %opt ),
471     'charge' => $cust_bill->charged,
472   };
473   $num_cust_bill++;
474 }
475
476 #voided invoices
477 foreach my $cust_bill_void ($cust_main->cust_bill_void) {
478   push @history, {
479     'date'        => $cust_bill_void->_date,
480     'order'       => 0,
481     'num'         => $cust_bill_void->invnum,
482     'desc'        => include('payment_history/voided_invoice.html', $cust_bill_void, %opt ),
483     'void_charge' => $cust_bill_void->charged,
484   };
485 }
486
487 #statements
488 foreach my $cust_statement ($cust_main->cust_statement) {
489   push @history, {
490     'date'   => $cust_statement->_date,
491     'order'  => 2,
492     'num'    => $cust_statement->statementnum,
493     'desc'   => include('payment_history/statement.html', $cust_statement, %opt ),
494     #'charge' => $cust_bill->charged,
495   };
496 }
497
498 #payments (some false laziness w/credits)
499 foreach my $cust_pay ($cust_main->cust_pay) {
500   push @history, {
501     'date'    => $cust_pay->_date,
502     'order'   => 6,
503     'num'     => $cust_pay->paynum,
504     'desc'    => include('payment_history/payment.html', $cust_pay, %opt ),
505     'payment' => $cust_pay->paid,
506     #'target'  => $target, #XXX
507   };
508 }
509
510 #pending payments 
511 foreach my $cust_pay_pending ($cust_main->cust_pay_pending) {
512   push @history, {
513     'date'    => $cust_pay_pending->_date,
514     'order'   => 4,
515     'num'     => $cust_pay_pending->paypendingnum,
516     'desc'    => include('payment_history/pending_payment.html', $cust_pay_pending, %opt ),
517     'void_payment' => $cust_pay_pending->paid, 
518   };
519 }
520
521
522 #voided payments
523 foreach my $cust_pay_void ($cust_main->cust_pay_void) {
524   push @history, {
525     'date'   => $cust_pay_void->_date,
526     'order'  => 3,
527     'num'    => $cust_pay_void->paynum,
528     'desc'   => include('payment_history/voided_payment.html', $cust_pay_void, %opt ),
529     'void_payment' => $cust_pay_void->paid,
530   };
531
532 }
533
534 #voided credits 
535 foreach my $cust_credit_void ($cust_main->cust_credit_void) {
536   push @history, {
537     'date'        => $cust_credit_void->_date,
538     'order'       => 7,
539     'num'         => $cust_credit_void->paynum,
540     'desc'        => include('payment_history/voided_credit.html', $cust_credit_void, %opt ),
541     'void_credit' => $cust_credit_void->amount,
542   };
543 }
544
545 #declined payments
546 foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) {
547   push @history, {
548     'date'    => $cust_pay_pending->_date,
549     'order'   => 5,
550     'num'     => $cust_pay_pending->paypendingnum,
551     'desc'    => include('payment_history/attempted_payment.html', $cust_pay_pending, %opt ),
552     'void_payment' => $cust_pay_pending->paid, #??
553     #'target'  => $target, #XXX
554   };
555 }
556 #declined batch payments
557 foreach my $cust_pay_batch (
558   $cust_main->cust_pay_batch(hashref => {status => 'Declined'})
559 ) {
560   my $pay_batch = $cust_pay_batch->pay_batch;
561   push @history, {
562     'date'    => $pay_batch->upload,
563     'order'   => 5,
564     'num'     => $cust_pay_batch->paybatchnum,
565     'desc'    => include('payment_history/attempted_batch_payment.html', $cust_pay_batch, %opt),
566     'void_payment' => $cust_pay_batch->amount,
567   };
568 }
569
570 #credits (some false laziness w/payments)
571 foreach my $cust_credit ($cust_main->cust_credit) {
572   push @history, {
573     'date'   => $cust_credit->_date,
574     'order'  => 8,
575     'num'    => $cust_credit->crednum,
576     'desc'   => include('payment_history/credit.html', $cust_credit, %opt ),
577     'credit' => $cust_credit->amount,
578   };
579
580 }
581
582 #refunds
583 foreach my $cust_refund ($cust_main->cust_refund) {
584   push @history, {
585     'date'   => $cust_refund->_date,
586     'order'  => 9,
587     'num'    => $cust_refund->refundnum,
588     'desc'   => include('payment_history/refund.html', $cust_refund, %opt),
589     'refund' => $cust_refund->refund,
590   };
591
592 }
593
594 # sort in forward order first, and calculate running balances
595 my $years =  $conf->config('payment_history-years') || 2;
596 my $older_than = time - $years * 31556926; #60*60*24*365.2422
597 my $balance = 0;
598
599 @history = sort {    $a->{date}  <=> $b->{date}
600                   or $a->{order} <=> $b->{order}
601                   or $a->{num}   <=> $b->{num}
602                 }
603              @history;
604
605 my $i = 0;
606 my $balance_forward;
607 foreach my $item (@history) {
608   $balance += $item->{'charge'}  if exists $item->{'charge'};
609   $balance -= $item->{'payment'} if exists $item->{'payment'};
610   $balance -= $item->{'credit'}  if exists $item->{'credit'};
611   $balance += $item->{'refund'}  if exists $item->{'refund'};
612   $balance = sprintf("%.2f", $balance);
613   $balance =~ s/^\-0\.00$/0.00/;
614   $item->{'balance'} = $balance;
615
616   if ( $item->{'date'} < $older_than ) {
617     $item->{'hide'} = 1;
618   } elsif ( $history[$i-1]->{'hide'} ) {
619     # this is the end of the hidden section
620     $history[$i-1]->{'balance_forward'} = 1;
621   }
622   $i++;
623 }
624 if ( @history and $history[-1]->{'hide'} ) {
625   # then everything is hidden
626   $history[-1]->{'balance_forward'} = 1;
627 }
628
629 # then sort in user-pref order
630 if ( $curuser->option('history_order') eq 'newest' ) {
631   @history = sort {    $b->{date}  <=> $a->{date}
632                     or $b->{order} <=> $a->{order} #or still forward here?
633                     or $b->{num}   <=> $a->{num}
634                   }
635                @history;
636 } # else it's already oldest-first, and there are no other options yet
637
638 sub translate_payby {
639     my ($payby,$payinfo) = (shift,shift);
640     my %payby = (
641         FS::payby->payby2shortname,
642         BILL    => $payinfo ? emt('Check #') : '',
643         CHEK    => emt('Electronic check '),
644         PREP    => emt('Prepaid card '),
645         CARD    => emt('Credit card #'),
646         COMP    => emt('Complimentary by '),
647         #CASH    => emt('Cash'),
648         #WEST    => emt('Western Union'),
649         #MCRD    => emt('Manual credit card'),
650     );
651     $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby; 
652     $payby;
653 };
654
655 sub translate_payby_refund {
656     my ($payby,$payinfo) = (shift,shift);
657     my %payby = (
658         FS::payby->payby2shortname,
659         BILL    => $payinfo ? emt('Check #') : emt('Check'),
660         CHEK    => emt('Electronic check '),
661         CARD    => emt('Credit card #'),
662         COMP    => emt('Complimentary by '),
663     );
664     $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby; 
665     $payby;
666 };
667
668 sub translate_payinfo {
669     my $object = shift;
670     my $payby = $object->payby;
671     my $payinfo = $object->payinfo;
672
673     if ( $payby eq 'CARD' ) {
674         $payinfo = $object->paymask;
675     } elsif ( $payby eq 'CHEK' ) {
676         #false laziness w/payinfo_Mixin::payby_payinfo_pretty, should use that
677         my( $account, $aba ) = split('@', $object->paymask );
678         if ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #blame canada
679           my($branch, $routing) = ($1, $2);
680           $payinfo = emt("Routing [_1], Branch [_2], Acct [_3]",
681                          $routing, $branch, $account);
682         } else {
683           $payinfo = emt("Routing [_1], Acct [_2]", $aba, $account);
684         }
685     }
686
687     ($payby,$payinfo);
688 }
689
690 sub areyousure_link {
691     my ($url,$msg,$title,$label) = (shift,shift,shift,shift);
692     ' (<A HREF="javascript:areyousure(\''.$url.'\',\''.$msg.'\')" TITLE="'.$title.'">'.$label.'</A>)';
693 }
694
695 </%init>