- my $conf = $self->conf;
- my $cust_main = $self->cust_main;
- my( $pr_total, @pr_cust_bill ) = $self->previous; #previous balance
- my @b = ();
- foreach ( @pr_cust_bill ) {
- my $date = $conf->exists('invoice_show_prior_due_date')
- ? 'due '. $_->due_date2str('short')
- : $self->time2str_local('short', $_->_date);
- push @b, {
- 'description' => $self->mt('Previous Balance, Invoice #'). $_->invnum. " ($date)",
- #'pkgpart' => 'N/A',
- 'pkgnum' => 'N/A',
- 'amount' => sprintf("%.2f", $_->owed),
- };
+
+ # simple memoize
+ if ($self->get('_items_previous')) {
+ return sort { $a->{_date} <=> $b->{_date} }
+ values %{ $self->get('_items_previous') };
+ }
+
+ # Gets the customer's current balance and outstanding invoices.
+ my ($prev_balance, @open_invoices) = $self->previous;
+
+ my %invoices = map {
+ $_->invnum => $self->__items_previous_map_invoice($_)
+ } @open_invoices;
+
+ # Which credits and payments displayed on the bill will vary based on
+ # conf flag previous_balance-payments_since.
+ my @credits = $self->_items_credits();
+ my @payments = $self->_items_payments();
+
+
+ if ($self->conf->exists('previous_balance-payments_since')) {
+ # For each credit or payment, determine which invoices it was applied to.
+ # Manipulate data displayed so the invoice displayed appears as a
+ # snapshot in time... with previous balances and balance owed displayed
+ # as they were at the time of invoice creation.
+
+ my @credits_postbill = $self->_items_credits_postbill();
+ my @payments_postbill = $self->_items_payments_postbill();
+
+ my %pmnt_dupechk;
+ my %cred_dupechk;
+
+ # Each section below follows this pattern on a payment/credit
+ #
+ # - Dupe check, avoid adjusting for the same item twice
+ # - If invoice being adjusted for isn't in our list, add it
+ # - Adjust the invoice balance to refelct balnace without the
+ # credit or payment applied
+ #
+
+ # Working with payments displayed on this bill
+ for my $pmt_hash (@payments) {
+ my $pmt_obj = qsearchs('cust_pay', {paynum => $pmt_hash->{paynum}});
+ for my $cust_bill_pay ($pmt_obj->cust_bill_pay) {
+ next if exists $pmnt_dupechk{$cust_bill_pay->billpaynum};
+ $pmnt_dupechk{$cust_bill_pay->billpaynum} = 1;
+
+ my $invnum = $cust_bill_pay->invnum;
+
+ $invoices{$invnum} = $self->__items_previous_get_invoice($invnum)
+ unless exists $invoices{$invnum};
+
+ $invoices{$invnum}->{amount} += $cust_bill_pay->amount;
+ }
+ }
+
+ # Working with credits displayed on this bill
+ for my $cred_hash (@credits) {
+ my $cred_obj = qsearchs('cust_credit', {crednum => $cred_hash->{crednum}});
+ for my $cust_credit_bill ($cred_obj->cust_credit_bill) {
+ next if exists $cred_dupechk{$cust_credit_bill->creditbillnum};
+ $cred_dupechk{$cust_credit_bill->creditbillnum} = 1;
+
+ my $invnum = $cust_credit_bill->invnum;
+
+ $invoices{$invnum} = $self->__items_previous_get_invoice($invnum)
+ unless exists $invoices{$invnum};
+
+ $invoices{$invnum}->{amount} += $cust_credit_bill->amount;
+ }
+ }
+
+ # Working with both credits and payments which are not displayed
+ # on this bill, but which have affected this bill's balances
+ for my $postbill (@payments_postbill, @credits_postbill) {
+
+ if ($postbill->{billpaynum}) {
+ next if exists $pmnt_dupechk{$postbill->{billpaynum}};
+ $pmnt_dupechk{$postbill->{billpaynum}} = 1;
+ } elsif ($postbill->{creditbillnum}) {
+ next if exists $cred_dupechk{$postbill->{creditbillnum}};
+ $cred_dupechk{$postbill->{creditbillnum}} = 1;
+ } else {
+ die "Missing creditbillnum or billpaynum";
+ }
+
+ my $invnum = $postbill->{invnum};
+
+ $invoices{$invnum} = $self->__items_previous_get_invoice($invnum)
+ unless exists $invoices{$invnum};
+
+ $invoices{$invnum}->{amount} += $postbill->{amount};
+ }
+
+ # Make sure current invoice doesn't appear in previous items
+ delete $invoices{$self->invnum}
+ if exists $invoices{$self->invnum};
+