-# major problem: this whole thing is way too sloppy.
-# minor problem: the description lines need better formatting.
-
-@history = (); #needed for mod_perl :)
-
-@bills = qsearch('cust_bill',{'custnum'=>$custnum});
-foreach $bill (@bills) {
- my($bref)=$bill->hashref;
- push @history,
- $bref->{_date} . qq!\t<A HREF="!. popurl(2). qq!view/cust_bill.cgi?! .
- $bref->{invnum} . qq!">Invoice #! . $bref->{invnum} .
- qq! (Balance \$! . $bill->owed . qq!)</A>\t! .
- $bref->{charged} . qq!\t\t\t!;
-
- my(@payments)=qsearch('cust_pay',{'invnum'=> $bref->{invnum} } );
- my($payment);
- foreach $payment (@payments) {
- my($date,$invnum,$payby,$payinfo,$paid)=($payment->getfield('_date'),
- $payment->getfield('invnum'),
- $payment->getfield('payby'),
- $payment->getfield('payinfo'),
- $payment->getfield('paid'),
- );
- push @history,
- "$date\tPayment, Invoice #$invnum ($payby $payinfo)\t\t$paid\t\t";
+ my $delete = '';
+ if ( $cust_credit->closed !~ /^Y/i && $conf->exists('deletecredits') ) {
+ $delete = qq! (<A HREF="javascript:areyousure('!.
+ qq!${p}misc/delete-cust_credit.cgi?!. $cust_credit->crednum.
+ qq!', 'Are you sure you want to delete this credit?')">!.
+ qq!delete</A>)!;
+ }
+
+ my $unapply = '';
+ if ( $cust_credit->closed !~ /^Y/i
+ && $conf->exists('unapplycredits')
+ && scalar(@cust_credit_bill) ) {
+ $unapply = qq! (<A HREF="javascript:areyousure('!.
+ qq!${p}misc/unapply-cust_credit.cgi?!. $cust_credit->crednum.
+ qq!', 'Are you sure you want to unapply this credit?')">!.
+ qq!unapply</A>)!;
+ }
+
+ 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() %>
+ <TR>
+ <TH>Date</TH>
+ <TH>Description</TH>
+ <TH><FONT SIZE=-1>Charge</FONT></TH>
+ <TH><FONT SIZE=-1>Payment</FONT></TH>
+ <TH><FONT SIZE=-1>In-house<BR>Credit</FONT></TH>
+ <TH><FONT SIZE=-1>Refund</FONT></TH>
+ <TH><FONT SIZE=-1>Balance</FONT></TH>
+ </TR>
+
+ <%
+ #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('<DEL>- $%.2f</DEL>', $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/^\$\-/- \$/;
+
+ %>
+
+ <TR>
+ <TD>
+ <% unless ( !$target || $target{$target}++ ) { %>
+ <A NAME="<%= $target %>">
+ <% } %>
+ <%= time2str("%D",$item->{'date'}) %>
+ <% if ( $target && $target{$target} == 1 ) { %>
+ </A>
+ <% } %>
+ </FONT>
+ </TD>
+ <TD><%= $item->{'desc'} %></TD>
+ <TD ALIGN="right"><%= $charge %></TD>
+ <TD ALIGN="right"><%= $payment %></TD>
+ <TD ALIGN="right"><%= $credit %></TD>
+ <TD ALIGN="right"><%= $refund %></TD>
+ <TD ALIGN="right"><%= $showbalance %></TD>
+ </TR>
+
+ <% } %>
+
+ </TABLE>
+
+<% } %>
+
+</BODY></HTML>
+
+<%
+#subroutines
+
+sub get_packages {
+ my $cust_main = shift or return undef;
+ my $conf = shift;
+
+ my @packages = ();
+
+ foreach my $cust_pkg (
+ $conf->exists('hidecancelledpackages')
+ ? $cust_main->ncancelled_pkgs
+ : $cust_main->all_pkgs
+ ) {
+
+ my $part_pkg = $cust_pkg->part_pkg;
+
+ my %pkg = ();
+
+ #to get back to the original object... should use it in the first place!!
+ $pkg{cust_pkg} = $cust_pkg;
+ $pkg{part_pkg} = $part_pkg;
+
+ $pkg{pkgnum} = $cust_pkg->pkgnum;
+ $pkg{pkg} = $part_pkg->pkg;
+ $pkg{pkgpart} = $part_pkg->pkgpart;
+ $pkg{comment} = $part_pkg->getfield('comment');
+ $pkg{freq} = $part_pkg->freq;
+ $pkg{setup} = $cust_pkg->getfield('setup');
+ $pkg{last_bill} = $cust_pkg->getfield('last_bill');
+ $pkg{next_bill} = $cust_pkg->getfield('bill');
+ $pkg{susp} = $cust_pkg->getfield('susp');
+ $pkg{expire} = $cust_pkg->getfield('expire');
+ $pkg{cancel} = $cust_pkg->getfield('cancel');
+
+
+ my %svcparts = map {
+ $_->svcpart => {
+ $_->part_svc->hash,
+ 'quantity' => $_->quantity,
+ 'count' => $cust_pkg->num_cust_svc($_->svcpart),
+ #'services' => [],
+ };
+ } $part_pkg->pkg_svc;
+
+ foreach my $cust_svc ( $cust_pkg->cust_svc ) {
+ #warn "svcnum ". $cust_svc->svcnum. " / svcpart ". $cust_svc->svcpart. "\n";
+ my $svc = {
+ 'svcnum' => $cust_svc->svcnum,
+ 'label' => ($cust_svc->label)[1],
+ };
+
+ #false laziness with above, to catch extraneous services. whole
+ #damn thing should be OO...
+ my $svcpart = ( $svcparts{$cust_svc->svcpart} ||= {
+ $cust_svc->part_svc->hash,
+ 'quantity' => 0,
+ 'count' => $cust_pkg->num_cust_svc($cust_svc->svcpart),
+ #'services' => [],
+ } );
+
+ push @{$svcpart->{services}}, $svc;
+
+ }
+
+ $pkg{svcparts} = [ values %svcparts ];
+
+ push @packages, \%pkg;
+