%#display payment history %my %target = (); % %my $hidden = 0; %my $seen = 0; %my $old_history = 0; %my $lastdate = 0; % %foreach my $item ( @history ) { % % $lastdate = $item->{'date'}; % % my $display = ''; % if ( $item->{'hide'} ) { % $display = ' STYLE="display:none" '; % } % % if ( $bgcolor eq $bgcolor1 ) { % $bgcolor = $bgcolor2; % } else { % $bgcolor = $bgcolor1; % } % % my $charge = exists($item->{'charge'}) % ? sprintf("$money_char\%.2f", $item->{'charge'}) % : exists($item->{'charge_nobal'}) % ? sprintf("$money_char\%.2f", $item->{'charge_nobal'}) % : exists($item->{'void_charge'}) % ? sprintf("$money_char\%.2f", $item->{'void_charge'}) % : ''; % % my $payment = exists($item->{'payment'}) % ? sprintf("- $money_char\%.2f", $item->{'payment'}) % : ''; % % $payment ||= sprintf( "- $money_char\%.2f", % $item->{'void_payment'} % ) % if exists($item->{'void_payment'}); % % my $credit = exists($item->{'credit'}) % ? sprintf("- $money_char\%.2f", $item->{'credit'}) % : ''; % % $credit ||= sprintf( "- $money_char\%.2f", % $item->{'void_credit'} % ) % if exists($item->{'void_credit'}); % % my $refund = exists($item->{'refund'}) % ? sprintf("$money_char\%.2f", $item->{'refund'}) % : ''; % % my $target = exists($item->{'target'}) ? $item->{'target'} : ''; % % my $showbalance = $money_char . $item->{'balance'}; % $showbalance =~ s/^\$\-/- \$/; > % if ( $item->{'balance_forward'} ) { <& .balance_forward_row, $item->{'balance'}, $item->{'date'} &> % } %} # foreach $item % if ( $old_history ) { <& .hide_history_row, $old_history++ &> % }
%# batched payment links % if ( ( $conf->exists('batch-enable') || $conf->config('batch-enable_payby') ) % && $curuser->access_right('View customer batched payments') % ) % { <% mt('View batched payments:') |h %> % foreach my $status (qw( Queued In-transit Complete All )) { <% mt($status) |h %> <% $status ne 'All' ? '|' : '' %> % }
% }
%# and now the table <& /elements/table-grid.html &> % my $bgcolor1 = '#eeeeee'; % my $bgcolor2 = '#ffffff'; % my $bgcolor = '';
<% mt('Date') |h %> <% mt('Description') |h %> <% mt('Invoice') |h %> <% mt('Payment') |h %> <% mt('In-house Credit') |h %> <% mt('Refund') |h %> <% mt('Balance') |h %>
% unless ( !$target || $target{$target}++ ) { % } <% time2str($date_format, $item->{'date'}) %> % if ( $target && $target{$target} == 1 ) { % } <% $item->{'desc'} %> <% $charge %> <% $payment %> <% $credit %> <% $refund %> <% $showbalance %>
<%def .balance_forward_row> % my( $b, $date ) = @_; % ( my $balance_forward = $money_char. $b ) =~ s/^\$\-/- \$/; <% time2str($date_format, $date) %> <% mt("Starting balance on [_1]", time2str($date_format, $date) ) |h %> (<% mt('show prior history') |h %>) <% $balance_forward %> <%def .hide_history_row> % my $num = shift; (<% mt('hide prior history') |h %>) <%shared> my $conf = new FS::Conf; my $date_format = $conf->config('date_format') || '%m/%d/%Y'; my $money_char = $conf->config('money_char') || '$'; <%init> my( $cust_main ) = @_; my $custnum = $cust_main->custnum; my $curuser = $FS::CurrentUser::CurrentUser; my %status = ( 'Queued' => 'O', #Open 'In-transit' => 'I', 'Complete' => 'R', #Resolved 'All' => '', ); #get payment history my @history = (); my %opt = ( #config ( map { $_ => scalar($conf->config($_)) } qw( card_refund-days date_format ) ), ( map { $_ => $conf->exists($_) } qw( deletepayments deleterefunds pkg-balances cust_credit_bill_pkg-manual cust_bill_pay_pkg-manual ) ), 'money_char ' => $money_char, #rights ( map { $_ => $curuser->access_right($_) } ( 'View invoices', 'Void invoices', 'Unvoid invoices', 'Resend invoices', 'Apply payment', 'Refund credit card payment', 'Refund Echeck payment', 'Post refund', 'Post check refund', 'Post cash refund ', 'Refund payment', 'Credit card void', 'Echeck void', 'Void payments', 'Unvoid payments', 'Unapply payment', 'Apply credit', 'Unapply credit', 'Void credit', 'Unvoid credit', 'Delete refund', 'Billing event reports', 'View customer billing events', ) ), #customer information 'total_owed' => $cust_main->total_owed, 'total_unapplied_refunds' => $cust_main->total_unapplied_refunds, 'has_email_address' => scalar($cust_main->invoicing_list_emailonly), ); $opt{'date_format'} ||= '%m/%d/%Y'; #legacy invoices foreach my $legacy_cust_bill ($cust_main->legacy_cust_bill) { push @history, { 'date' => $legacy_cust_bill->_date, 'order' => 1, 'num' => $legacy_cust_bill->legacyid, 'desc' => include('payment_history/legacy_invoice.html', $legacy_cust_bill, %opt ), 'charge_nobal' => $legacy_cust_bill->charged, }; } #invoices my $num_cust_bill = 0; foreach my $cust_bill ($cust_main->cust_bill) { push @history, { 'date' => $cust_bill->_date, 'order' => 1, 'num' => $cust_bill->invnum, 'desc' => include('payment_history/invoice.html', $cust_bill, %opt ), 'charge' => $cust_bill->charged, }; $num_cust_bill++; } #voided invoices foreach my $cust_bill_void ($cust_main->cust_bill_void) { push @history, { 'date' => $cust_bill_void->_date, 'order' => 0, 'num' => $cust_bill_void->invnum, 'desc' => include('payment_history/voided_invoice.html', $cust_bill_void, %opt ), 'void_charge' => $cust_bill_void->charged, }; } #statements foreach my $cust_statement ($cust_main->cust_statement) { push @history, { 'date' => $cust_statement->_date, 'order' => 2, 'num' => $cust_statement->statementnum, 'desc' => include('payment_history/statement.html', $cust_statement, %opt ), #'charge' => $cust_bill->charged, }; } #payments (some false laziness w/credits) foreach my $cust_pay ($cust_main->cust_pay) { push @history, { 'date' => $cust_pay->_date, 'order' => 6, 'num' => $cust_pay->paynum, 'desc' => include('payment_history/payment.html', $cust_pay, %opt ), 'payment' => $cust_pay->paid, #'target' => $target, #XXX }; } #pending payments foreach my $cust_pay_pending ($cust_main->cust_pay_pending) { push @history, { 'date' => $cust_pay_pending->_date, 'order' => 4, 'num' => $cust_pay_pending->paypendingnum, 'desc' => include('payment_history/pending_payment.html', $cust_pay_pending, %opt ), 'void_payment' => $cust_pay_pending->paid, }; } #voided payments foreach my $cust_pay_void ($cust_main->cust_pay_void) { push @history, { 'date' => $cust_pay_void->_date, 'order' => 3, 'num' => $cust_pay_void->paynum, 'desc' => include('payment_history/voided_payment.html', $cust_pay_void, %opt ), 'void_payment' => $cust_pay_void->paid, }; } #voided credits foreach my $cust_credit_void ($cust_main->cust_credit_void) { push @history, { 'date' => $cust_credit_void->_date, 'order' => 7, 'num' => $cust_credit_void->paynum, 'desc' => include('payment_history/voided_credit.html', $cust_credit_void, %opt ), 'void_credit' => $cust_credit_void->amount, }; } #declined payments foreach my $cust_pay_pending ($cust_main->cust_pay_pending_attempt) { push @history, { 'date' => $cust_pay_pending->_date, 'order' => 5, 'num' => $cust_pay_pending->paypendingnum, 'desc' => include('payment_history/attempted_payment.html', $cust_pay_pending, %opt ), 'void_payment' => $cust_pay_pending->paid, #?? #'target' => $target, #XXX }; } #declined batch payments foreach my $cust_pay_batch ( $cust_main->cust_pay_batch(hashref => {status => 'Declined'}) ) { my $pay_batch = $cust_pay_batch->pay_batch; push @history, { 'date' => $pay_batch->upload, 'order' => 5, 'num' => $cust_pay_batch->paybatchnum, 'desc' => include('payment_history/attempted_batch_payment.html', $cust_pay_batch, %opt), 'void_payment' => $cust_pay_batch->amount, }; } #credits (some false laziness w/payments) foreach my $cust_credit ($cust_main->cust_credit) { push @history, { 'date' => $cust_credit->_date, 'order' => 8, 'num' => $cust_credit->crednum, 'desc' => include('payment_history/credit.html', $cust_credit, %opt ), 'credit' => $cust_credit->amount, }; } #refunds foreach my $cust_refund ($cust_main->cust_refund) { push @history, { 'date' => $cust_refund->_date, 'order' => 9, 'num' => $cust_refund->refundnum, 'desc' => include('payment_history/refund.html', $cust_refund, %opt), 'refund' => $cust_refund->refund, }; } # sort in forward order first, and calculate running balances my $years = $conf->config('payment_history-years') || 2; my $older_than = time - $years * 31556926; #60*60*24*365.2422 my $balance = 0; @history = sort { $a->{date} <=> $b->{date} or $a->{order} <=> $b->{order} or $a->{num} <=> $b->{num} } @history; my $i = 0; my $balance_forward; foreach my $item (@history) { $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/; $item->{'balance'} = $balance; if ( $item->{'date'} < $older_than ) { $item->{'hide'} = 1; } elsif ( $history[$i-1]->{'hide'} ) { # this is the end of the hidden section $history[$i-1]->{'balance_forward'} = 1; } $i++; } if ( @history and $history[-1]->{'hide'} ) { # then everything is hidden $history[-1]->{'balance_forward'} = 1; } # then sort in user-pref order if ( $curuser->option('history_order') eq 'newest' ) { @history = sort { $b->{date} <=> $a->{date} or $b->{order} <=> $a->{order} #or still forward here? or $b->{num} <=> $a->{num} } @history; } # else it's already oldest-first, and there are no other options yet sub translate_payby { my ($payby,$payinfo) = (shift,shift); my %payby = ( FS::payby->payby2shortname, BILL => $payinfo ? emt('Check #') : '', CHEK => emt('Electronic check '), PREP => emt('Prepaid card '), CARD => emt('Credit card #'), COMP => emt('Complimentary by '), #CASH => emt('Cash'), #WEST => emt('Western Union'), #MCRD => emt('Manual credit card'), ); $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby; $payby; }; sub translate_payby_refund { my ($payby,$payinfo) = (shift,shift); my %payby = ( FS::payby->payby2shortname, BILL => $payinfo ? emt('Check #') : emt('Check'), CHEK => emt('Electronic check '), CARD => emt('Credit card #'), COMP => emt('Complimentary by '), ); $payby = (exists $payby{$payby}) ? $payby{$payby} : $payby; $payby; }; sub translate_payinfo { my $object = shift; my $payby = $object->payby; my $payinfo = $object->payinfo; if ( $payby eq 'CARD' ) { $payinfo = $object->paymask; } elsif ( $payby eq 'CHEK' ) { #false laziness w/payinfo_Mixin::payby_payinfo_pretty, should use that my( $account, $aba ) = split('@', $object->paymask ); if ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #blame canada my($branch, $routing) = ($1, $2); $payinfo = emt("Routing [_1], Branch [_2], Acct [_3]", $routing, $branch, $account); } else { $payinfo = emt("Routing [_1], Acct [_2]", $aba, $account); } } ($payby,$payinfo); } sub areyousure_link { my ($url,$msg,$title,$label) = (shift,shift,shift,shift); ' ('.$label.')'; }