sticky setting for expanded payment history, #41397
[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 % if ( $old_history ) {
347 <& .hide_history_row, $old_history++ &>
348 % }
349
350 </TABLE>
351     </TD>
352   </TR>
353 </TABLE>
354
355 <SCRIPT SRC="<% $fsurl %>elements/page_pref.js"></SCRIPT>
356 <SCRIPT TYPE="text/javascript">
357
358 function show_history(show) { // but don't update pref
359   var balance_forward_row = document.getElementById('balance_forward_row');
360
361   balance_forward_row.style.display = show ? 'none' : '';
362   for ( var i = 0; i < <% $old_history %>; i++ ) {
363     var oldRow = document.getElementById('old_history'+i);
364     oldRow.style.display = show ? '' : 'none';
365   }
366 }
367
368 function update_show_history (show) {
369
370   show = show ? 1 : 0;
371   show_history(show);
372   // update user pref (blind post, don't care about the output here)
373   set_page_pref('expand_old_history', '<% $custnum %>', show);
374 }
375
376 $().ready(function() {
377   show_history(<% get_page_pref('expand_old_history', $custnum) %>);
378 });
379
380 </SCRIPT>
381 <%def .balance_forward_row>
382 %  my( $b, $date ) = @_;
383 %  ( my $balance_forward = $money_char. $b ) =~ s/^\$\-/-&nbsp;\$/;
384
385    <TR ID="balance_forward_row">
386      <TD CLASS="grid" BGCOLOR="#dddddd">
387        <% time2str($date_format, $date) %>
388      </TD>
389
390      <TD CLASS="grid" BGCOLOR="#dddddd">
391        <I><% mt("Starting balance on [_1]", time2str($date_format, $date) ) |h %></I>
392        (<A HREF="javascript:void(0);" onClick="update_show_history(true);"><% mt('show prior history') |h %></A>)
393      </TD>
394
395      <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
396      <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
397      <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
398      <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
399      <TD CLASS="grid" BGCOLOR="#dddddd" ALIGN="right"><I><% $balance_forward %></I></TD>
400
401    </TR>
402 </%def>
403 <%def .hide_history_row>
404 %  my $num = shift;
405   <TR ID="old_history<% $num %>" STYLE="display: none">
406     <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
407     <TD CLASS="grid" BGCOLOR="#dddddd">
408       <I>(<A HREF="#" onclick="update_show_history(false)"><% mt('hide prior history') |h %></A>)</I>
409     </TD>
410     <TD CLASS="grid" BGCOLOR="#dddddd" COLSPAN=5></TD>
411   </TR>
412 </%def>
413
414 <%shared>
415 my $conf = new FS::Conf;
416 my $date_format = $conf->config('date_format') || '%m/%d/%Y';
417 my $money_char = $conf->config('money_char') || '$';
418 </%shared>
419 <%init>
420
421 my( $cust_main ) = @_;
422 my $custnum = $cust_main->custnum;
423
424 my $curuser = $FS::CurrentUser::CurrentUser;
425
426 my @payby = grep /\w/, $conf->config('payby');
427 #@payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH WEST COMP ))
428 @payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH COMP ))
429   unless @payby;
430 my %payby = map { $_=>1 } @payby;
431
432 my %status = (
433   'Queued'     => 'O', #Open
434   'In-transit' => 'I',
435   'Complete'   => 'R', #Resolved
436   'All'        => '',
437 );
438
439 #get payment history
440 my @history = ();
441
442 my %opt = (
443
444   #config
445   ( map { $_ => scalar($conf->config($_)) }
446         qw( card_refund-days date_format )
447   ),
448   ( map { $_ => $conf->exists($_) } 
449         qw( deleteinvoices deletepayments deleterefunds pkg-balances
450             cust_credit_bill_pkg-manual cust_bill_pay_pkg-manual
451           )
452   ),
453   'money_char             ' => $money_char,
454
455   #rights
456   ( map { $_ => $curuser->access_right($_) }
457       (
458         'View invoices', 'Void invoices', 'Unvoid invoices', 'Delete invoices', 'Resend invoices',
459         'Apply payment', 'Refund credit card payment', 'Refund Echeck payment',
460         'Post refund', 'Post check refund', 'Post cash refund ', 'Refund payment',
461         'Credit card void', 'Echeck void', 'Void payments', 'Unvoid payments',
462         'Delete payment', 'Unapply payment',
463         'Apply credit', 'Delete credit', 'Unapply credit', 'Void credit', 'Unvoid credit',
464         'Delete refund',
465         'Billing event reports', 'View customer billing events',
466       )
467   ),
468
469   #customer information
470   'total_owed'              => $cust_main->total_owed,
471   'total_unapplied_refunds' => $cust_main->total_unapplied_refunds,
472   'has_email_address'       => scalar($cust_main->invoicing_list_emailonly),
473 );
474
475 $opt{'date_format'} ||= '%m/%d/%Y';
476
477 #legacy invoices
478 foreach my $legacy_cust_bill ($cust_main->legacy_cust_bill) {
479   push @history, {
480     'date'   => $legacy_cust_bill->_date,
481     'order'  => 1,
482     'num'    => $legacy_cust_bill->legacyid,
483     'desc'   => include('payment_history/legacy_invoice.html', $legacy_cust_bill, %opt ),
484     'charge_nobal' => $legacy_cust_bill->charged,
485   };
486 }
487
488 #invoices
489 my $num_cust_bill = 0;
490 foreach my $cust_bill ($cust_main->cust_bill) {
491   push @history, {
492     'date'   => $cust_bill->_date,
493     'order'  => 1,
494     'num'    => $cust_bill->invnum,
495     'desc'   => include('payment_history/invoice.html', $cust_bill, %opt ),
496     'charge' => $cust_bill->charged,
497   };
498   $num_cust_bill++;
499 }
500
501 #voided invoices
502 foreach my $cust_bill_void ($cust_main->cust_bill_void) {
503   push @history, {
504     'date'        => $cust_bill_void->_date,
505     'order'       => 0,
506     'num'         => $cust_bill_void->invnum,
507     'desc'        => include('payment_history/voided_invoice.html', $cust_bill_void, %opt ),
508     'void_charge' => $cust_bill_void->charged,
509   };
510 }
511
512 #statements
513 foreach my $cust_statement ($cust_main->cust_statement) {
514   push @history, {
515     'date'   => $cust_statement->_date,
516     'order'  => 2,
517     'num'    => $cust_statement->statementnum,
518     'desc'   => include('payment_history/statement.html', $cust_statement, %opt ),
519     #'charge' => $cust_bill->charged,
520   };
521 }
522
523 #payments (some false laziness w/credits)
524 foreach my $cust_pay ($cust_main->cust_pay) {
525   push @history, {
526     'date'    => $cust_pay->_date,
527     'order'   => 6,
528     'num'     => $cust_pay->paynum,
529     'desc'    => include('payment_history/payment.html', $cust_pay, %opt ),
530     'payment' => $cust_pay->paid,
531     #'target'  => $target, #XXX
532   };
533 }
534
535 #pending payments 
536 foreach my $cust_pay_pending ($cust_main->cust_pay_pending) {
537   push @history, {
538     'date'    => $cust_pay_pending->_date,
539     'order'   => 4,
540     'num'     => $cust_pay_pending->paypendingnum,
541     'desc'    => include('payment_history/pending_payment.html', $cust_pay_pending, %opt ),
542     'void_payment' => $cust_pay_pending->paid, 
543   };
544 }
545
546
547 #voided payments
548 foreach my $cust_pay_void ($cust_main->cust_pay_void) {
549   push @history, {
550     'date'   => $cust_pay_void->_date,
551     'order'  => 3,
552     'num'    => $cust_pay_void->paynum,
553     'desc'   => include('payment_history/voided_payment.html', $cust_pay_void, %opt ),
554     'void_payment' => $cust_pay_void->paid,
555   };
556
557 }
558
559 #voided credits 
560 foreach my $cust_credit_void ($cust_main->cust_credit_void) {
561   push @history, {
562     'date'        => $cust_credit_void->_date,
563     'order'       => 7,
564     'num'         => $cust_credit_void->paynum,
565     'desc'        => include('payment_history/voided_credit.html', $cust_credit_void, %opt ),
566     'void_credit' => $cust_credit_void->amount,
567   };
568 }
569
570 #declined payments
571 foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) {
572   push @history, {
573     'date'    => $cust_pay_pending->_date,
574     'order'   => 5,
575     'num'     => $cust_pay_pending->paypendingnum,
576     'desc'    => include('payment_history/attempted_payment.html', $cust_pay_pending, %opt ),
577     'void_payment' => $cust_pay_pending->paid, #??
578     #'target'  => $target, #XXX
579   };
580 }
581 #declined batch payments
582 foreach my $cust_pay_batch (
583   $cust_main->cust_pay_batch(hashref => {status => 'Declined'})
584 ) {
585   my $pay_batch = $cust_pay_batch->pay_batch;
586   push @history, {
587     'date'    => $pay_batch->upload,
588     'order'   => 5,
589     'num'     => $cust_pay_batch->paybatchnum,
590     'desc'    => include('payment_history/attempted_batch_payment.html', $cust_pay_batch, %opt),
591     'void_payment' => $cust_pay_batch->amount,
592   };
593 }
594
595 #credits (some false laziness w/payments)
596 foreach my $cust_credit ($cust_main->cust_credit) {
597   push @history, {
598     'date'   => $cust_credit->_date,
599     'order'  => 8,
600     'num'    => $cust_credit->crednum,
601     'desc'   => include('payment_history/credit.html', $cust_credit, %opt ),
602     'credit' => $cust_credit->amount,
603   };
604
605 }
606
607 #refunds
608 foreach my $cust_refund ($cust_main->cust_refund) {
609   push @history, {
610     'date'   => $cust_refund->_date,
611     'order'  => 9,
612     'num'    => $cust_refund->refundnum,
613     'desc'   => include('payment_history/refund.html', $cust_refund, %opt),
614     'refund' => $cust_refund->refund,
615   };
616
617 }
618
619 # sort in forward order first, and calculate running balances
620 my $years =  $conf->config('payment_history-years') || 2;
621 my $older_than = time - $years * 31556926; #60*60*24*365.2422
622 my $balance = 0;
623
624 @history = sort {    $a->{date}  <=> $b->{date}
625                   or $a->{order} <=> $b->{order}
626                   or $a->{num}   <=> $b->{num}
627                 }
628              @history;
629
630 my $i = 0;
631 my $balance_forward;
632 foreach my $item (@history) {
633   $balance += $item->{'charge'}  if exists $item->{'charge'};
634   $balance -= $item->{'payment'} if exists $item->{'payment'};
635   $balance -= $item->{'credit'}  if exists $item->{'credit'};
636   $balance += $item->{'refund'}  if exists $item->{'refund'};
637   $balance = sprintf("%.2f", $balance);
638   $balance =~ s/^\-0\.00$/0.00/;
639   $item->{'balance'} = $balance;
640
641   if ( $item->{'date'} < $older_than ) {
642     $item->{'hide'} = 1;
643   } elsif ( $history[$i-1]->{'hide'} ) {
644     # this is the end of the hidden section
645     $history[$i-1]->{'balance_forward'} = 1;
646   }
647   $i++;
648 }
649 if ( @history and $history[-1]->{'hide'} ) {
650   # then everything is hidden
651   $history[-1]->{'balance_forward'} = 1;
652 }
653
654 # then sort in user-pref order
655 if ( $curuser->option('history_order') eq 'newest' ) {
656   @history = sort {    $b->{date}  <=> $a->{date}
657                     or $b->{order} <=> $a->{order} #or still forward here?
658                     or $b->{num}   <=> $a->{num}
659                   }
660                @history;
661 } # else it's already oldest-first, and there are no other options yet
662
663 sub translate_payby {
664     my ($payby,$payinfo) = (shift,shift);
665     my %payby = (
666         FS::payby->payby2shortname,
667         BILL    => $payinfo ? emt('Check #') : '',
668         CHEK    => emt('Electronic check '),
669         PREP    => emt('Prepaid card '),
670         CARD    => emt('Credit card #'),
671         COMP    => emt('Complimentary by '),
672         #CASH    => emt('Cash'),
673         #WEST    => emt('Western Union'),
674         #MCRD    => emt('Manual credit card'),
675     );
676     $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby; 
677     $payby;
678 };
679
680 sub translate_payby_refund {
681     my ($payby,$payinfo) = (shift,shift);
682     my %payby = (
683         FS::payby->payby2shortname,
684         BILL    => $payinfo ? emt('Check #') : emt('Check'),
685         CHEK    => emt('Electronic check '),
686         CARD    => emt('Credit card #'),
687         COMP    => emt('Complimentary by '),
688     );
689     $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby; 
690     $payby;
691 };
692
693 sub translate_payinfo {
694     my $object = shift;
695     my $payby = $object->payby;
696     my $payinfo = $object->payinfo;
697
698     if ( $payby eq 'CARD' ) {
699         $payinfo = $object->paymask;
700     } elsif ( $payby eq 'CHEK' ) {
701         #false laziness w/payinfo_Mixin::payby_payinfo_pretty, should use that
702         my( $account, $aba ) = split('@', $object->paymask );
703         if ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #blame canada
704           my($branch, $routing) = ($1, $2);
705           $payinfo = emt("Routing [_1], Branch [_2], Acct [_3]",
706                          $routing, $branch, $account);
707         } else {
708           $payinfo = emt("Routing [_1], Acct [_2]", $aba, $account);
709         }
710     }
711
712     ($payby,$payinfo);
713 }
714
715 sub areyousure_link {
716     my ($url,$msg,$title,$label) = (shift,shift,shift,shift);
717     ' (<A HREF="javascript:areyousure(\''.$url.'\',\''.$msg.'\')" TITLE="'.$title.'" STYLE="white-space: nowrap;">'.$label.'</A>)';
718 }
719
720 </%init>