<% my( $cust_main ) = @_; my $conf = new FS::Conf; my $custnum = $cust_main->custnum; %>

Payment History
Post cash/check payment | Process credit card payment | Process electronic check (ACH) payment
Post credit
<% #get payment history my @history = (); #invoices foreach my $cust_bill ($cust_main->cust_bill) { my $pre = ( $cust_bill->owed > 0 ) ? 'Open ' : ''; my $post = ( $cust_bill->owed > 0 ) ? '' : ''; my $invnum = $cust_bill->invnum; push @history, { 'date' => $cust_bill->_date, 'desc' => qq!!. $pre. "Invoice #$invnum (Balance \$". $cust_bill->owed. ')'. $post. '', 'charge' => $cust_bill->charged, }; } #payments (some false laziness w/credits) foreach my $cust_pay ($cust_main->cust_pay) { my $payby = $cust_pay->payby; my $payinfo; if ( $payby eq 'CARD' ) { $payinfo = $cust_pay->payinfo_masked; } elsif ( $payby eq 'CHEK' && $cust_pay->payinfo =~ /^(\d+)\@(\d+)$/ ) { $payinfo = "ABA $2, Acct# $1"; } else { $payinfo = $cust_pay->payinfo; } my @cust_bill_pay = $cust_pay->cust_bill_pay; my @cust_pay_refund = $cust_pay->cust_pay_refund; my $target = "$payby$payinfo"; $payby =~ s/^BILL$/Check #/ if $payinfo; $payby =~ s/^CHEK$/Electronic check /; $payby =~ s/^PREP$/Prepaid card /; $payby =~ s/^BILL$//; $payby =~ s/^(CARD|COMP)$/$1 /; my $info = $payby ? " ($payby$payinfo)" : ''; my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' ); if ( scalar(@cust_bill_pay) == 0 && scalar(@cust_pay_refund) == 0 ) { #completely unapplied $pre = 'Unapplied '; $post = ''; $apply = qq! (apply)'; } elsif ( scalar(@cust_bill_pay) == 1 && scalar(@cust_pay_refund) == 0 && $cust_pay->unapplied == 0 ) { #applied to one invoice, the usual situation $desc = ' applied to Invoice #'. $cust_bill_pay[0]->invnum; } elsif ( scalar(@cust_bill_pay) == 0 && scalar(@cust_pay_refund) == 1 && $cust_pay->unapplied == 0 ) { #applied to one refund $desc = ' refunded on '. time2str("%D", $cust_pay_refund[0]->_date); } else { #complicated $desc = '
'; foreach my $app ( sort { $a->_date <=> $b->_date } ( @cust_bill_pay, @cust_pay_refund ) ) { if ( $app->isa('FS::cust_bill_pay') ) { $desc .= '  '. '$'. $app->amount. ' applied to Invoice #'. $app->invnum. '
'; #' on '. time2str("%D", $cust_bill_pay->_date). } elsif ( $app->isa('FS::cust_pay_refund') ) { $desc .= '  '. '$'. $app->amount. ' refunded on'. time2str("%D", $app->_date). '
'; } else { die "$app is not a FS::cust_bill_pay or FS::cust_pay_refund"; } } if ( $cust_pay->unapplied > 0 ) { $desc .= '  '. '$'. $cust_pay->unapplied. ' unapplied'. qq! (apply)'. '
'; } } my $refund = ''; my $refund_days = $conf->config('card_refund-days') || 120; if ( $cust_pay->closed !~ /^Y/i && $cust_pay->payby =~ /^(CARD|CHEK)$/ && time-$cust_pay->_date < $refund_days*86400 && $cust_pay->unrefunded > 0 ) { $refund = qq! (refund)!; } my $void = ''; if ( $cust_pay->closed !~ /^Y/i && $cust_pay->payby ne 'CARD' && ( $cust_pay->payby ne 'CHEK' || $conf->exists('echeck-void') ) ) { $void = qq! (void)!; } my $delete = ''; if ( $cust_pay->closed !~ /^Y/i && $conf->exists('deletepayments') ) { $delete = qq! (delete)!; } my $unapply = ''; if ( $cust_pay->closed !~ /^Y/i && $conf->exists('unapplypayments') && scalar(@cust_bill_pay) ) { $unapply = qq! (unapply)!; } push @history, { 'date' => $cust_pay->_date, 'desc' => $pre. "Payment$post$info$desc". "$apply$refund$void$delete$unapply", 'payment' => $cust_pay->paid, 'target' => $target, }; } #voided payments foreach my $cust_pay_void ($cust_main->cust_pay_void) { my $payby = $cust_pay_void->payby; my $payinfo = $payby eq 'CARD' ? $cust_pay_void->payinfo_masked : $cust_pay_void->payinfo; $payby =~ s/^BILL$/Check #/ if $payinfo; $payby =~ s/^CHEK$/Electronic check /; $payby =~ s/^BILL$//; $payby =~ s/^(CARD|COMP)$/$1 /; my $info = $payby ? " ($payby$payinfo)" : ''; push @history, { 'date' => $cust_pay_void->_date, 'desc' => "Payment $info voided ". time2str("%D", $cust_pay_void->void_date). " by ". $cust_pay_void->otaker. '', 'void_payment' => $cust_pay_void->paid, }; } #credits (some false laziness w/payments) foreach my $cust_credit ($cust_main->cust_credit) { my @cust_credit_bill = $cust_credit->cust_credit_bill; my @cust_credit_refund = $cust_credit->cust_credit_refund; my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' ); if ( scalar(@cust_credit_bill) == 0 && scalar(@cust_credit_refund) == 0 ) { #completely unapplied $pre = 'Unapplied '; $post = ''; $apply = qq! (apply)'; } elsif ( scalar(@cust_credit_bill) == 1 && scalar(@cust_credit_refund) == 0 && $cust_credit->credited == 0 ) { #applied to one invoice, the usual situation $desc = ' applied to Invoice #'. $cust_credit_bill[0]->invnum; } elsif ( scalar(@cust_credit_bill) == 0 && scalar(@cust_credit_refund) == 1 && $cust_credit->credited == 0 ) { #applied to one refund $desc = ' refunded on '. time2str("%D", $cust_credit_refund[0]->_date); } else { #complicated $desc = '
'; foreach my $app ( sort { $a->_date <=> $b->_date } ( @cust_credit_bill, @cust_credit_refund ) ) { if ( $app->isa('FS::cust_credit_bill') ) { $desc .= '  '. '$'. $app->amount. ' applied to Invoice #'. $app->invnum. '
'; #' on '. time2str("%D", $app->_date). } elsif ( $app->isa('FS::cust_credit_refund') ) { $desc .= '  '. '$'. $app->amount. ' refunded on'. time2str("%D", $app->_date). '
'; } else { die "$app is not a FS::cust_credit_bill or a FS::cust_credit_refund"; } } if ( $cust_credit->credited > 0 ) { $desc .= '  $'. $cust_credit->credited. ' unapplied'. qq! (apply)'. '
'; } } # my $delete = ''; if ( $cust_credit->closed !~ /^Y/i && $conf->exists('deletecredits') ) { $delete = qq! (!. qq!delete)!; } my $unapply = ''; if ( $cust_credit->closed !~ /^Y/i && $conf->exists('unapplycredits') && scalar(@cust_credit_bill) ) { $unapply = qq! (!. qq!unapply)!; } push @history, { 'date' => $cust_credit->_date, 'desc' => $pre. "Credit$post by ". $cust_credit->otaker. ' ('. $cust_credit->reason. ')'. "$desc$apply$delete$unapply", 'credit' => $cust_credit->amount, }; } #refunds foreach my $cust_refund ($cust_main->cust_refund) { my $payby = $cust_refund->payby; my $payinfo = $payby eq 'CARD' ? $cust_refund->payinfo_masked : $cust_refund->payinfo; $payby =~ s/^BILL$/Check #/ if $payinfo; $payby =~ s/^CHEK$/Electronic check /; $payby =~ s/^(CARD|COMP)$/$1 /; push @history, { 'date' => $cust_refund->_date, 'desc' => "Refund ($payby$payinfo) by ". $cust_refund->otaker, 'refund' => $cust_refund->refund, }; } %> <%= table() %> Date Description Charge Payment In-house
Credit
Refund Balance <% #display payment history my %target; my $balance = 0; foreach my $item ( sort { $a->{'date'} <=> $b->{'date'} } @history ) { my $charge = exists($item->{'charge'}) ? sprintf('$%.2f', $item->{'charge'}) : ''; my $payment = exists($item->{'payment'}) ? sprintf('- $%.2f', $item->{'payment'}) : ''; $payment ||= sprintf('- $%.2f', $item->{'void_payment'}) if exists($item->{'void_payment'}); my $credit = exists($item->{'credit'}) ? sprintf('- $%.2f', $item->{'credit'}) : ''; my $refund = exists($item->{'refund'}) ? sprintf('$%.2f', $item->{'refund'}) : ''; my $target = exists($item->{'target'}) ? $item->{'target'} : ''; $balance += $item->{'charge'} if exists $item->{'charge'}; $balance -= $item->{'payment'} if exists $item->{'payment'}; $balance -= $item->{'credit'} if exists $item->{'credit'}; $balance += $item->{'refund'} if exists $item->{'refund'}; $balance = sprintf("%.2f", $balance); $balance =~ s/^\-0\.00$/0.00/; #yay ieee fp ( my $showbalance = '$'. $balance ) =~ s/^\$\-/- \$/; %> <% unless ( !$target || $target{$target}++ ) { %> <% } %> <%= time2str("%D",$item->{'date'}) %> <% if ( $target && $target{$target} == 1 ) { %> <% } %> <%= $item->{'desc'} %> <%= $charge %> <%= $payment %> <%= $credit %> <%= $refund %> <%= $showbalance %> <% } %>