+ my %currency;
+
+ # little private function to unapply payments from a cust_bill_pkg until
+ # there's a specified amount of unpaid balance on it.
+ # it's a separate sub because we do it for both tax and nontax items. it's
+ # private because it needs access to some local data structures.
+ my $unapply_sub = sub {
+ my ($cust_bill_pkg, $setuprecur, $need_to_unapply) = @_;
+
+ my $invnum = $cust_bill_pkg->invnum;
+
+ $need_to_unapply -= $cust_bill_pkg->owed($setuprecur);
+ return if $need_to_unapply < 0.005;
+
+ my $error;
+ # then unapply payments one at a time (partially if need be) until the
+ # unpaid balance = the credit amount.
+ foreach my $cust_bill_pay_pkg (
+ $cust_bill_pkg->cust_bill_pay_pkg($setuprecur)
+ ) {
+ my $this_amount = $cust_bill_pay_pkg->amount;
+ if ( $this_amount > $need_to_unapply ) {
+ # unapply the needed amount
+ $cust_bill_pay_pkg->set('amount',
+ sprintf('%.2f', $this_amount - $need_to_unapply));
+ $error = $cust_bill_pay_pkg->replace;
+ $unapplied_payments{$invnum}{$cust_bill_pay_pkg->billpaynum} += $need_to_unapply;
+ last; # and we're done
+
+ } else {
+ # unapply it all
+ $error = $cust_bill_pay_pkg->delete;
+ $unapplied_payments{$invnum}{$cust_bill_pay_pkg->billpaynum} += $this_amount;
+
+ $need_to_unapply -= $this_amount;
+ }
+
+ } # foreach $cust_bill_pay_pkg
+
+ # return an error if we somehow still have leftover $need_to_unapply?
+
+ return $error;
+ };