3 my $custnum = $cust_main->custnum;
5 my $conf = new FS::Conf;
7 my @payby = grep /\w/, $conf->config('payby');
8 #@payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH WEST COMP ))
9 @payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH COMP ))
11 my %payby = map { $_=>1 } @payby;
17 <BR><BR><A NAME="history"><FONT SIZE="+2">Payment History</FONT></A><BR>
19 <% if ( $payby{'BILL'} ) { %>
21 <%= $s++ ? ' | ' : '' %>
22 <A HREF="<%= $p %>edit/cust_pay.cgi?payby=BILL;custnum=<%= $custnum %>">Post check payment</A>
26 <% if ( $payby{'CASH'} ) { %>
28 <%= $s++ ? ' | ' : '' %>
29 <A HREF="<%= $p %>edit/cust_pay.cgi?payby=CASH;custnum=<%= $custnum %>">Post cash payment</A>
33 <% if ( $payby{'WEST'} ) { %>
35 <%= $s++ ? ' | ' : '' %>
36 <A HREF="<%= $p %>edit/cust_pay.cgi?payby=WEST;custnum=<%= $custnum %>">Post Western Union payment</A>
40 <% if ( $payby{'CARD'} || $payby{'DCRD'} ) { %>
42 <%= $s++ ? ' | ' : '' %>
43 <A HREF="<%= $p %>misc/payment.cgi?payby=CARD;custnum=<%= $custnum %>">Process credit card payment</A>
47 <% if ( $payby{'CHEK'} || $payby{'DCHK'} ) { %>
49 <%= $s++ ? ' | ' : '' %>
50 <A HREF="<%= $p %>misc/payment.cgi?payby=CHEK;custnum=<%= $custnum %>">Process electronic check (ACH) payment</A>
54 <% if ( $payby{'MCRD'} ) { %>
56 <%= $s++ ? ' | ' : '' %>
57 <A HREF="<%= $p %>edit/cust_pay.cgi?payby=MCRD;custnum=<%= $custnum %>">Post manual credit card payment</A>
63 <A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('<%= $p %>edit/cust_credit.cgi?<%= $custnum %>', 392, 336, 'cust_credit_popup' ), CAPTION, 'Post credit', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK )">Post credit</A>
72 foreach my $cust_bill ($cust_main->cust_bill) {
73 my $pre = ( $cust_bill->owed > 0 )
74 ? '<B><FONT SIZE="+1" COLOR="#FF0000">Open '
76 my $post = ( $cust_bill->owed > 0 ) ? '</FONT></B>' : '';
77 my $invnum = $cust_bill->invnum;
79 'date' => $cust_bill->_date,
80 'desc' => qq!<A HREF="${p}view/cust_bill.cgi?$invnum">!. $pre.
81 "Invoice #$invnum (Balance \$". $cust_bill->owed. ')'.
83 'charge' => $cust_bill->charged,
87 #payments (some false laziness w/credits)
88 foreach my $cust_pay ($cust_main->cust_pay) {
90 my $payby = $cust_pay->payby;
93 if ( $payby eq 'CARD' ) {
94 $payinfo = $cust_pay->payinfo_masked;
95 } elsif ( $payby eq 'CHEK' && $cust_pay->payinfo =~ /^(\d+)\@(\d+)$/ ) {
96 $payinfo = "ABA $2, Acct# $1";
98 $payinfo = $cust_pay->payinfo;
100 my @cust_bill_pay = $cust_pay->cust_bill_pay;
101 my @cust_pay_refund = $cust_pay->cust_pay_refund;
103 my $target = "$payby$payinfo";
104 $payby =~ s/^BILL$/Check #/ if $payinfo;
105 $payby =~ s/^CHEK$/Electronic check /;
106 $payby =~ s/^PREP$/Prepaid card /;
107 $payby =~ s/^CARD$/Credit card #/;
108 $payby =~ s/^COMP$/Complimentary by /;
109 $payby =~ s/^CASH$/Cash/;
110 $payby =~ s/^WEST$/Western Union/;
111 $payby =~ s/^MCRD$/Manual credit card/;
112 $payby =~ s/^BILL$//;
113 my $info = $payby ? " ($payby$payinfo)" : '';
115 my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
116 if ( scalar(@cust_bill_pay) == 0
117 && scalar(@cust_pay_refund) == 0 ) {
118 #completely unapplied
119 $pre = '<B><FONT COLOR="#FF0000">Unapplied ';
120 $post = '</FONT></B>';
121 $apply = qq! (<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('${p}edit/cust_bill_pay.cgi?!.
123 qq!', 392, 336, 'cust_credit_popup' ), CAPTION, 'Post credit', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK )">apply</A>)!;
125 } elsif ( scalar(@cust_bill_pay) == 1
126 && scalar(@cust_pay_refund) == 0
127 && $cust_pay->unapplied == 0 ) {
128 #applied to one invoice, the usual situation
129 $desc = ' applied to Invoice #'. $cust_bill_pay[0]->invnum;
130 } elsif ( scalar(@cust_bill_pay) == 0
131 && scalar(@cust_pay_refund) == 1
132 && $cust_pay->unapplied == 0 ) {
133 #applied to one refund
134 $desc = ' refunded on '. time2str("%D", $cust_pay_refund[0]->_date);
138 foreach my $app ( sort { $a->_date <=> $b->_date }
139 ( @cust_bill_pay, @cust_pay_refund ) ) {
140 if ( $app->isa('FS::cust_bill_pay') ) {
141 $desc .= ' '.
143 ' applied to Invoice #'. $app->invnum.
145 #' on '. time2str("%D", $cust_bill_pay->_date).
146 } elsif ( $app->isa('FS::cust_pay_refund') ) {
147 $desc .= ' '.
149 ' refunded on'. time2str("%D", $app->_date).
152 die "$app is not a FS::cust_bill_pay or FS::cust_pay_refund";
155 if ( $cust_pay->unapplied > 0 ) {
156 $desc .= ' '.
157 '<B><FONT COLOR="#FF0000">$'.
158 $cust_pay->unapplied. ' unapplied</FONT></B>'.
159 qq! (<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('${p}edit/cust_bill_pay.cgi?!.
161 qq!', 392, 336, 'cust_credit_popup' ), CAPTION, 'Post credit', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK )">apply</A>)!.
167 my $refund_days = $conf->config('card_refund-days') || 120;
168 if ( $cust_pay->closed !~ /^Y/i
169 && $cust_pay->payby =~ /^(CARD|CHEK)$/
170 && time-$cust_pay->_date < $refund_days*86400
171 && $cust_pay->unrefunded > 0
173 $refund = qq! (<A HREF="${p}edit/cust_refund.cgi?payby=$1;!.
174 qq!paynum=!. $cust_pay->paynum. '"'.
175 qq! TITLE="Send a refund for this payment to the payment gateway"!.
180 if ( $cust_pay->closed !~ /^Y/i
181 && ( $cust_pay->payby ne 'CARD' || $conf->exists('cc-void') )
182 && ( $cust_pay->payby ne 'CHEK' || $conf->exists('echeck-void') )
184 $void = qq! (<A HREF="javascript:areyousure('!.
185 qq!${p}misc/void-cust_pay.cgi?!. $cust_pay->paynum.
186 qq!', 'Are you sure you want to void this payment?')"!.
187 qq! TITLE="Void this payment from the database!.
188 ( $cust_pay->payby =~ /^(CARD|CHEK)$/
189 ? ' (do not send anything to the payment gateway)'
196 if ( $cust_pay->closed !~ /^Y/i && $conf->exists('deletepayments') ) {
197 $delete = qq! (<A HREF="javascript:areyousure('!.
198 qq!${p}misc/delete-cust_pay.cgi?!. $cust_pay->paynum.
199 qq!', 'Are you sure you want to delete this payment?')"!.
200 qq! TITLE="Delete this payment from the database completely - not recommended"!.
205 if ( $cust_pay->closed !~ /^Y/i
206 && $conf->exists('unapplypayments')
207 && scalar(@cust_bill_pay) ) {
208 $unapply = qq! (<A HREF="javascript:areyousure('!.
209 qq!${p}misc/unapply-cust_pay.cgi?!. $cust_pay->paynum.
210 qq!', 'Are you sure you want to unapply this payment?')"!.
211 qq! TITLE="Keep this payment, but dissociate it from the invoices it is currently applied against"!.
216 'date' => $cust_pay->_date,
217 'desc' => $pre. "Payment$post$info$desc".
218 "$apply$refund$void$delete$unapply",
219 'payment' => $cust_pay->paid,
225 foreach my $cust_pay_void ($cust_main->cust_pay_void) {
227 my $payby = $cust_pay_void->payby;
228 my $payinfo = $payby eq 'CARD'
229 ? $cust_pay_void->payinfo_masked
230 : $cust_pay_void->payinfo;
232 $payby =~ s/^BILL$/Check #/ if $payinfo;
233 $payby =~ s/^CHEK$/Electronic check /;
234 $payby =~ s/^BILL$//;
235 $payby =~ s/^(CARD|COMP)$/$1 /;
236 my $info = $payby ? " ($payby$payinfo)" : '';
239 if ( $cust_pay_void->closed !~ /^Y/i && $conf->exists('unvoid') ) {
240 $unvoid = qq! (<A HREF="javascript:areyousure('!.
241 qq!${p}misc/unvoid-cust_pay_void.cgi?!. $cust_pay_void->paynum.
242 qq!', 'Are you sure you want to unvoid this payment?')"!.
243 qq! TITLE="Unvoid this payment from the database!.
244 ( $cust_pay_void->payby =~ /^(CARD|CHEK)$/
245 ? ' (do not send anything to the payment gateway)'
252 'date' => $cust_pay_void->_date,
253 'desc' => "<DEL>Payment $info</DEL> <I>voided ".
254 time2str("%D", $cust_pay_void->void_date).
255 " by ". $cust_pay_void->otaker. '</i>'. $unvoid,
256 'void_payment' => $cust_pay_void->paid,
261 #credits (some false laziness w/payments)
262 foreach my $cust_credit ($cust_main->cust_credit) {
264 my @cust_credit_bill = $cust_credit->cust_credit_bill;
265 my @cust_credit_refund = $cust_credit->cust_credit_refund;
267 my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
268 if ( scalar(@cust_credit_bill) == 0
269 && scalar(@cust_credit_refund) == 0 ) {
270 #completely unapplied
271 $pre = '<B><FONT COLOR="#FF0000">Unapplied ';
272 $post = '</FONT></B>';
273 $apply = qq! (<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('${p}edit/cust_credit_bill.cgi?!.
274 $cust_credit->crednum.
275 qq!', 392, 336, 'cust_credit_popup' ), CAPTION, 'Post credit', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK )">apply</A>)!;
276 } elsif ( scalar(@cust_credit_bill) == 1
277 && scalar(@cust_credit_refund) == 0
278 && $cust_credit->credited == 0 ) {
279 #applied to one invoice, the usual situation
280 $desc = ' applied to Invoice #'. $cust_credit_bill[0]->invnum;
281 } elsif ( scalar(@cust_credit_bill) == 0
282 && scalar(@cust_credit_refund) == 1
283 && $cust_credit->credited == 0 ) {
284 #applied to one refund
285 $desc = ' refunded on '. time2str("%D", $cust_credit_refund[0]->_date);
289 foreach my $app ( sort { $a->_date <=> $b->_date }
290 ( @cust_credit_bill, @cust_credit_refund ) ) {
291 if ( $app->isa('FS::cust_credit_bill') ) {
292 $desc .= ' '.
294 ' applied to Invoice #'. $app->invnum.
296 #' on '. time2str("%D", $app->_date).
297 } elsif ( $app->isa('FS::cust_credit_refund') ) {
298 $desc .= ' '.
300 ' refunded on'. time2str("%D", $app->_date).
303 die "$app is not a FS::cust_credit_bill or a FS::cust_credit_refund";
306 if ( $cust_credit->credited > 0 ) {
307 $desc .= ' <B><FONT COLOR="#FF0000">$'.
308 $cust_credit->credited. ' unapplied</FONT></B>'.
309 qq! (<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('${p}edit/cust_credit_bill.cgi?!.
310 $cust_credit->crednum.
311 qq!', 392, 336, 'cust_credit_popup' ), CAPTION, 'Post credit', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK )">apply</A>)!.
317 if ( $cust_credit->closed !~ /^Y/i && $conf->exists('deletecredits') ) {
318 $delete = qq! (<A HREF="javascript:areyousure('!.
319 qq!${p}misc/delete-cust_credit.cgi?!. $cust_credit->crednum.
320 qq!', 'Are you sure you want to delete this credit?')">!.
325 if ( $cust_credit->closed !~ /^Y/i
326 && $conf->exists('unapplycredits')
327 && scalar(@cust_credit_bill) ) {
328 $unapply = qq! (<A HREF="javascript:areyousure('!.
329 qq!${p}misc/unapply-cust_credit.cgi?!. $cust_credit->crednum.
330 qq!', 'Are you sure you want to unapply this credit?')">!.
335 'date' => $cust_credit->_date,
336 'desc' => $pre. "Credit$post by ". $cust_credit->otaker.
337 ( $cust_credit->reason
338 ? ' ('. $cust_credit->reason. ')'
341 "$desc$apply$delete$unapply",
342 'credit' => $cust_credit->amount,
348 foreach my $cust_refund ($cust_main->cust_refund) {
350 my $payby = $cust_refund->payby;
351 my $payinfo = $payby eq 'CARD'
352 ? $cust_refund->payinfo_masked
353 : $cust_refund->payinfo;
355 $payby =~ s/^BILL$/Check #/ if $payinfo;
356 $payby =~ s/^CHEK$/Electronic check /;
357 $payby =~ s/^(CARD|COMP)$/$1 /;
360 'date' => $cust_refund->_date,
361 'desc' => "Refund ($payby$payinfo) by ". $cust_refund->otaker,
362 'refund' => $cust_refund->refund,
369 <%= include("/elements/table.html") %>
373 <TH><FONT SIZE=-1>Charge</FONT></TH>
374 <TH><FONT SIZE=-1>Payment</FONT></TH>
375 <TH><FONT SIZE=-1>In-house<BR>Credit</FONT></TH>
376 <TH><FONT SIZE=-1>Refund</FONT></TH>
377 <TH><FONT SIZE=-1>Balance</FONT></TH>
381 #display payment history
385 foreach my $item ( sort { $a->{'date'} <=> $b->{'date'} } @history ) {
387 my $charge = exists($item->{'charge'})
388 ? sprintf('$%.2f', $item->{'charge'})
390 my $payment = exists($item->{'payment'})
391 ? sprintf('- $%.2f', $item->{'payment'})
393 $payment ||= sprintf('<DEL>- $%.2f</DEL>', $item->{'void_payment'})
394 if exists($item->{'void_payment'});
395 my $credit = exists($item->{'credit'})
396 ? sprintf('- $%.2f', $item->{'credit'})
398 my $refund = exists($item->{'refund'})
399 ? sprintf('$%.2f', $item->{'refund'})
402 my $target = exists($item->{'target'}) ? $item->{'target'} : '';
404 $balance += $item->{'charge'} if exists $item->{'charge'};
405 $balance -= $item->{'payment'} if exists $item->{'payment'};
406 $balance -= $item->{'credit'} if exists $item->{'credit'};
407 $balance += $item->{'refund'} if exists $item->{'refund'};
408 $balance = sprintf("%.2f", $balance);
409 $balance =~ s/^\-0\.00$/0.00/; #yay ieee fp
410 ( my $showbalance = '$'. $balance ) =~ s/^\$\-/- \$/;
416 <% unless ( !$target || $target{$target}++ ) { %>
417 <A NAME="<%= $target %>">
419 <%= time2str("%D",$item->{'date'}) %>
420 <% if ( $target && $target{$target} == 1 ) { %>
425 <TD><%= $item->{'desc'} %></TD>
426 <TD ALIGN="right"><%= $charge %></TD>
427 <TD ALIGN="right"><%= $payment %></TD>
428 <TD ALIGN="right"><%= $credit %></TD>
429 <TD ALIGN="right"><%= $refund %></TD>
430 <TD ALIGN="right"><%= $showbalance %></TD>