remove payment deletion, RT#37908
[freeside.git] / httemplate / view / cust_main / payment_history.html
1 <TABLE>
2   <TR>
3     <TD ALIGN="left">
4
5 %# batched payment links
6
7 % if ( ( $conf->exists('batch-enable') || $conf->config('batch-enable_payby') )
8 %      && $curuser->access_right('View customer batched payments')
9 %    )
10 % { 
11     <% mt('View batched payments:') |h %> 
12 %   foreach my $status (qw( Queued In-transit Complete All )) {
13       <A HREF="<% $p %>search/cust_pay_batch.cgi?status=<% $status{$status} %>;custnum=<% $custnum %>"><% mt($status) |h %></A> 
14       <% $status ne 'All' ? '|' : '' %>
15 %   }
16     <BR>
17 % } 
18
19     </TD>
20   </TR>
21   <TR>
22     <TD COLSPAN=2>
23
24 %# and now the table
25
26 <& /elements/table-grid.html &>
27 % my $bgcolor1 = '#eeeeee';
28 %   my $bgcolor2 = '#ffffff';
29 %   my $bgcolor = '';
30
31 <THEAD>
32 <TR>
33   <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Date') |h %></TH>
34   <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Description') |h %></TH>
35   <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Invoice') |h %></FONT></TH>
36   <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Payment') |h %></FONT></TH>
37   <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('In-house Credit') |h %></FONT></TH>
38   <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Refund') |h %></FONT></TH>
39   <TH CLASS="grid" BGCOLOR="#cccccc"><FONT SIZE=-1><% mt('Balance') |h %></FONT></TH>
40 </TR>
41 </THEAD>
42
43 %#display payment history
44
45 %my %target = ();
46 %
47 %my $hidden = 0;
48 %my $seen = 0;
49 %my $old_history = 0;
50 %my $lastdate = 0;
51 %
52 %foreach my $item ( @history ) {
53 %
54 %  $lastdate = $item->{'date'};
55 %
56 %  my $display = '';
57 %  if ( $item->{'hide'} ) {
58 %    $display = ' STYLE="display:none" ';
59 %  }
60 %
61 %  if ( $bgcolor eq $bgcolor1 ) {
62 %    $bgcolor = $bgcolor2;
63 %  } else {
64 %    $bgcolor = $bgcolor1;
65 %  }
66 %
67 %  my $charge  = exists($item->{'charge'})
68 %                  ? sprintf("$money_char\%.2f", $item->{'charge'})
69 %                  : exists($item->{'charge_nobal'})
70 %                    ? sprintf("$money_char\%.2f", $item->{'charge_nobal'})
71 %                    : exists($item->{'void_charge'})
72 %                      ? sprintf("<DEL>$money_char\%.2f</DEL>", $item->{'void_charge'})
73 %                      : '';
74 %
75 %  my $payment = exists($item->{'payment'})
76 %                  ? sprintf("-&nbsp;$money_char\%.2f", $item->{'payment'})
77 %                  : '';
78 %
79 %  $payment ||= sprintf( "<DEL>-&nbsp;$money_char\%.2f</DEL>",
80 %                        $item->{'void_payment'}
81 %                      )
82 %    if exists($item->{'void_payment'});
83 %
84 %  my $credit  = exists($item->{'credit'})
85 %                  ? sprintf("-&nbsp;$money_char\%.2f", $item->{'credit'})
86 %                  : '';
87 %
88 %  $credit ||= sprintf( "<DEL>-&nbsp;$money_char\%.2f</DEL>",
89 %                       $item->{'void_credit'}
90 %                     )
91 %    if exists($item->{'void_credit'});
92 %
93 %  my $refund  = exists($item->{'refund'})
94 %                  ? sprintf("$money_char\%.2f", $item->{'refund'})
95 %                  : '';
96 %
97 %  my $target = exists($item->{'target'}) ? $item->{'target'} : '';
98 %
99 %  my $showbalance = $money_char . $item->{'balance'};
100 %  $showbalance =~ s/^\$\-/-&nbsp;\$/;
101
102   <TR <% $display ? $display.' ID="old_history'.$old_history++.'"'  : ''%>>
103     <TD VALIGN="top" CLASS="grid" BGCOLOR="<% $bgcolor %>">
104 % unless ( !$target || $target{$target}++ ) { 
105
106         <A NAME="<% $target %>">
107 % } 
108
109       <% time2str($date_format, $item->{'date'}) %>
110 % if ( $target && $target{$target} == 1 ) { 
111
112         </A>
113 % } 
114
115       </FONT>
116     </TD>
117     <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
118       <% $item->{'desc'} %>
119     </TD>
120     <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
121       <% $charge  %>
122     </TD>
123     <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
124       <% $payment %>
125     </TD>
126     <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
127       <% $credit  %>
128     </TD>
129     <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
130       <% $refund  %>
131     </TD>
132     <TD VALIGN="top" ALIGN="right" CLASS="grid" BGCOLOR="<% $bgcolor %>">
133       <% $showbalance %>
134     </TD>
135   </TR>
136
137 % if ( $item->{'balance_forward'} ) {
138 <& .balance_forward_row, $item->{'balance'}, $item->{'date'} &>
139 % } 
140 %} # foreach $item
141
142 </TABLE>
143     </TD>
144   </TR>
145 </TABLE>
146
147 <SCRIPT TYPE="text/javascript">
148
149 function show_history () {
150   //alert('showing history!');
151
152   var balance_forward_row = document.getElementById('balance_forward_row');
153
154   balance_forward_row.style.display = 'none';
155   for ( var i = 0; i < <% $old_history %>; i++ ) {
156     var oldRow = document.getElementById('old_history'+i);
157     oldRow.style.display = '';
158   }
159
160 }
161
162 </SCRIPT>
163 <%def .balance_forward_row>
164 %  my( $b, $date ) = @_;
165 %  ( my $balance_forward = $money_char. $b ) =~ s/^\$\-/-&nbsp;\$/;
166
167    <TR ID="balance_forward_row">
168      <TD CLASS="grid" BGCOLOR="#dddddd">
169        <% time2str($date_format, $date) %>
170      </TD>
171
172      <TD CLASS="grid" BGCOLOR="#dddddd">
173        <I><% mt("Starting balance on [_1]", time2str($date_format, $date) ) |h %></I>
174        (<A HREF="javascript:void(0);" onClick="show_history();"><% mt('show prior history') |h %></A>)
175      </TD>
176
177      <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
178      <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
179      <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
180      <TD CLASS="grid" BGCOLOR="#dddddd"></TD>
181      <TD CLASS="grid" BGCOLOR="#dddddd" ALIGN="right"><I><% $balance_forward %></I></TD>
182
183    </TR>
184 </%def>
185 <%shared>
186 my $conf = new FS::Conf;
187 my $date_format = $conf->config('date_format') || '%m/%d/%Y';
188 my $money_char = $conf->config('money_char') || '$';
189 </%shared>
190 <%init>
191
192 my( $cust_main ) = @_;
193 my $custnum = $cust_main->custnum;
194
195 my $curuser = $FS::CurrentUser::CurrentUser;
196
197 my @payby = grep /\w/, $conf->config('payby');
198 #@payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH WEST COMP ))
199 @payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH COMP ))
200   unless @payby;
201 my %payby = map { $_=>1 } @payby;
202
203 my %status = (
204   'Queued'     => 'O', #Open
205   'In-transit' => 'I',
206   'Complete'   => 'R', #Resolved
207   'All'        => '',
208 );
209
210 #get payment history
211 my @history = ();
212
213 my %opt = (
214
215   #config
216   ( map { $_ => scalar($conf->config($_)) }
217         qw( card_refund-days date_format )
218   ),
219   ( map { $_ => $conf->exists($_) } 
220         qw( deletepayments deleterefunds pkg-balances
221             cust_credit_bill_pkg-manual cust_bill_pay_pkg-manual
222           )
223   ),
224   'money_char             ' => $money_char,
225
226   #rights
227   ( map { $_ => $curuser->access_right($_) }
228       (
229         'View invoices', 'Void invoices', 'Unvoid invoices',
230         'Apply payment', 'Refund credit card payment', 'Refund Echeck payment',
231         'Post refund', 'Post check refund', 'Post cash refund ', 'Refund payment',
232         'Credit card void', 'Echeck void', 'Void payments', 'Unvoid payments',
233 <<<<<<< HEAD
234         'Delete payment', 'Unapply payment',
235         'Apply credit', 'Delete credit', 'Unapply credit', 'Void credit', 'Unvoid credit',
236 =======
237         'Unapply payment',
238         'Apply credit', 'Unapply credit', 'Void credit', 'Unvoid credit',
239 >>>>>>> 727d620... remove payment deletion, RT#37908
240         'Delete refund',
241         'Billing event reports', 'View customer billing events',
242       )
243   ),
244
245   #customer information
246   'total_owed'              => $cust_main->total_owed,
247   'total_unapplied_refunds' => $cust_main->total_unapplied_refunds,
248 );
249
250 $opt{'date_format'} ||= '%m/%d/%Y';
251
252 #legacy invoices
253 foreach my $legacy_cust_bill ($cust_main->legacy_cust_bill) {
254   push @history, {
255     'date'   => $legacy_cust_bill->_date,
256     'order'  => 1,
257     'num'    => $legacy_cust_bill->legacyid,
258     'desc'   => include('payment_history/legacy_invoice.html', $legacy_cust_bill, %opt ),
259     'charge_nobal' => $legacy_cust_bill->charged,
260   };
261 }
262
263 #invoices
264 my $num_cust_bill = 0;
265 foreach my $cust_bill ($cust_main->cust_bill) {
266   push @history, {
267     'date'   => $cust_bill->_date,
268     'order'  => 1,
269     'num'    => $cust_bill->invnum,
270     'desc'   => include('payment_history/invoice.html', $cust_bill, %opt ),
271     'charge' => $cust_bill->charged,
272   };
273   $num_cust_bill++;
274 }
275
276 #voided invoices
277 foreach my $cust_bill_void ($cust_main->cust_bill_void) {
278   push @history, {
279     'date'        => $cust_bill_void->_date,
280     'order'       => 0,
281     'num'         => $cust_bill_void->invnum,
282     'desc'        => include('payment_history/voided_invoice.html', $cust_bill_void, %opt ),
283     'void_charge' => $cust_bill_void->charged,
284   };
285 }
286
287 #statements
288 foreach my $cust_statement ($cust_main->cust_statement) {
289   push @history, {
290     'date'   => $cust_statement->_date,
291     'order'  => 2,
292     'num'    => $cust_statement->statementnum,
293     'desc'   => include('payment_history/statement.html', $cust_statement, %opt ),
294     #'charge' => $cust_bill->charged,
295   };
296 }
297
298 #payments (some false laziness w/credits)
299 foreach my $cust_pay ($cust_main->cust_pay) {
300   push @history, {
301     'date'    => $cust_pay->_date,
302     'order'   => 6,
303     'num'     => $cust_pay->paynum,
304     'desc'    => include('payment_history/payment.html', $cust_pay, %opt ),
305     'payment' => $cust_pay->paid,
306     #'target'  => $target, #XXX
307   };
308 }
309
310 #pending payments 
311 foreach my $cust_pay_pending ($cust_main->cust_pay_pending) {
312   push @history, {
313     'date'    => $cust_pay_pending->_date,
314     'order'   => 4,
315     'num'     => $cust_pay_pending->paypendingnum,
316     'desc'    => include('payment_history/pending_payment.html', $cust_pay_pending, %opt ),
317     'void_payment' => $cust_pay_pending->paid, 
318   };
319 }
320
321
322 #voided payments
323 foreach my $cust_pay_void ($cust_main->cust_pay_void) {
324   push @history, {
325     'date'   => $cust_pay_void->_date,
326     'order'  => 3,
327     'num'    => $cust_pay_void->paynum,
328     'desc'   => include('payment_history/voided_payment.html', $cust_pay_void, %opt ),
329     'void_payment' => $cust_pay_void->paid,
330   };
331
332 }
333
334 #voided credits 
335 foreach my $cust_credit_void ($cust_main->cust_credit_void) {
336   push @history, {
337     'date'        => $cust_credit_void->_date,
338     'order'       => 7,
339     'num'         => $cust_credit_void->paynum,
340     'desc'        => include('payment_history/voided_credit.html', $cust_credit_void, %opt ),
341     'void_credit' => $cust_credit_void->amount,
342   };
343 }
344
345 #declined payments
346 foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) {
347   push @history, {
348     'date'    => $cust_pay_pending->_date,
349     'order'   => 5,
350     'num'     => $cust_pay_pending->paypendingnum,
351     'desc'    => include('payment_history/attempted_payment.html', $cust_pay_pending, %opt ),
352     'void_payment' => $cust_pay_pending->paid, #??
353     #'target'  => $target, #XXX
354   };
355 }
356 #declined batch payments
357 foreach my $cust_pay_batch (
358   $cust_main->cust_pay_batch(hashref => {status => 'Declined'})
359 ) {
360   my $pay_batch = $cust_pay_batch->pay_batch;
361   push @history, {
362     'date'    => $pay_batch->upload,
363     'order'   => 5,
364     'num'     => $cust_pay_batch->paybatchnum,
365     'desc'    => include('payment_history/attempted_batch_payment.html', $cust_pay_batch, %opt),
366     'void_payment' => $cust_pay_batch->amount,
367   };
368 }
369
370 #credits (some false laziness w/payments)
371 foreach my $cust_credit ($cust_main->cust_credit) {
372   push @history, {
373     'date'   => $cust_credit->_date,
374     'order'  => 8,
375     'num'    => $cust_credit->crednum,
376     'desc'   => include('payment_history/credit.html', $cust_credit, %opt ),
377     'credit' => $cust_credit->amount,
378   };
379
380 }
381
382 #refunds
383 foreach my $cust_refund ($cust_main->cust_refund) {
384   push @history, {
385     'date'   => $cust_refund->_date,
386     'order'  => 9,
387     'num'    => $cust_refund->refundnum,
388     'desc'   => include('payment_history/refund.html', $cust_refund, %opt),
389     'refund' => $cust_refund->refund,
390   };
391
392 }
393
394 # sort in forward order first, and calculate running balances
395 my $years =  $conf->config('payment_history-years') || 2;
396 my $older_than = time - $years * 31556926; #60*60*24*365.2422
397 my $balance = 0;
398
399 @history = sort {    $a->{date}  <=> $b->{date}
400                   or $a->{order} <=> $b->{order}
401                   or $a->{num}   <=> $b->{num}
402                 }
403              @history;
404
405 my $i = 0;
406 my $balance_forward;
407 foreach my $item (@history) {
408   $balance += $item->{'charge'}  if exists $item->{'charge'};
409   $balance -= $item->{'payment'} if exists $item->{'payment'};
410   $balance -= $item->{'credit'}  if exists $item->{'credit'};
411   $balance += $item->{'refund'}  if exists $item->{'refund'};
412   $balance = sprintf("%.2f", $balance);
413   $balance =~ s/^\-0\.00$/0.00/;
414   $item->{'balance'} = $balance;
415
416   if ( $item->{'date'} < $older_than ) {
417     $item->{'hide'} = 1;
418   } elsif ( $history[$i-1]->{'hide'} ) {
419     # this is the end of the hidden section
420     $history[$i-1]->{'balance_forward'} = 1;
421   }
422   $i++;
423 }
424 if ( @history and $history[-1]->{'hide'} ) {
425   # then everything is hidden
426   $history[-1]->{'balance_forward'} = 1;
427 }
428
429 # then sort in user-pref order
430 if ( $curuser->option('history_order') eq 'newest' ) {
431   @history = sort {    $b->{date}  <=> $a->{date}
432                     or $b->{order} <=> $a->{order} #or still forward here?
433                     or $b->{num}   <=> $a->{num}
434                   }
435                @history;
436 } # else it's already oldest-first, and there are no other options yet
437
438 sub translate_payby {
439     my ($payby,$payinfo) = (shift,shift);
440     my %payby = (
441         FS::payby->payby2shortname,
442         BILL    => $payinfo ? emt('Check #') : '',
443         CHEK    => emt('Electronic check '),
444         PREP    => emt('Prepaid card '),
445         CARD    => emt('Credit card #'),
446         COMP    => emt('Complimentary by '),
447         #CASH    => emt('Cash'),
448         #WEST    => emt('Western Union'),
449         #MCRD    => emt('Manual credit card'),
450     );
451     $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby; 
452     $payby;
453 };
454
455 sub translate_payby_refund {
456     my ($payby,$payinfo) = (shift,shift);
457     my %payby = (
458         FS::payby->payby2shortname,
459         BILL    => $payinfo ? emt('Check #') : emt('Check'),
460         CHEK    => emt('Electronic check '),
461         CARD    => emt('Credit card #'),
462         COMP    => emt('Complimentary by '),
463     );
464     $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby; 
465     $payby;
466 };
467
468 sub translate_payinfo {
469     my $object = shift;
470     my $payby = $object->payby;
471     my $payinfo = $object->payinfo;
472
473     if ( $payby eq 'CARD' ) {
474         $payinfo = $object->paymask;
475     } elsif ( $payby eq 'CHEK' ) {
476         #false laziness w/payinfo_Mixin::payby_payinfo_pretty, should use that
477         my( $account, $aba ) = split('@', $object->paymask );
478         if ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #blame canada
479           my($branch, $routing) = ($1, $2);
480           $payinfo = emt("Routing [_1], Branch [_2], Acct [_3]",
481                          $routing, $branch, $account);
482         } else {
483           $payinfo = emt("Routing [_1], Acct [_2]", $aba, $account);
484         }
485     }
486
487     ($payby,$payinfo);
488 }
489
490 sub areyousure_link {
491     my ($url,$msg,$title,$label) = (shift,shift,shift,shift);
492     ' (<A HREF="javascript:areyousure(\''.$url.'\',\''.$msg.'\')" TITLE="'.$title.'">'.$label.'</A>)';
493 }
494
495 </%init>