+ return "error inserting cust_pay: $error";
+ }
+
+ if ( my $credit_type = $conf->config('prepayment_discounts-credit_type') ) {
+ if ( my $months = $self->discount_term ) {
+ # XXX this should be moved out somewhere, but discount_term_values
+ # doesn't fit right
+ my ($cust_bill) = ($cust_main->cust_bill)[-1]; # most recent invoice
+ return "can't accept prepayment for an unbilled customer" if !$cust_bill;
+
+ # %billing_pkgs contains this customer's active monthly packages.
+ # Recurring fees for those packages will be credited and then rebilled
+ # for the full discount term. Other packages on the last invoice
+ # (canceled, non-monthly recurring, or one-time charges) will be
+ # left as they are.
+ my %billing_pkgs = map { $_->pkgnum => $_ }
+ grep { $_->part_pkg->freq eq '1' }
+ $cust_main->billing_pkgs;
+ my $credit = 0; # sum of recurring charges from that invoice
+ my $last_bill_date = 0; # the real bill date
+ foreach my $item ( $cust_bill->cust_bill_pkg ) {
+ next if !exists($billing_pkgs{$item->pkgnum}); # skip inactive packages
+ $credit += $item->recur;
+ $last_bill_date = $item->cust_pkg->last_bill
+ if defined($item->cust_pkg)
+ and $item->cust_pkg->last_bill > $last_bill_date
+ }
+
+ my $cust_credit = new FS::cust_credit {
+ 'custnum' => $self->custnum,
+ 'amount' => sprintf('%.2f', $credit),
+ 'reason' => 'customer chose to prepay for discount',
+ };
+ $error = $cust_credit->insert('reason_type' => $credit_type);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error inserting prepayment credit: $error";
+ }
+ # don't apply it yet
+
+ # bill for the entire term
+ $_->bill($_->last_bill) foreach (values %billing_pkgs);
+ $error = $cust_main->bill(
+ # no recurring_only, we want unbilled packages with start dates to
+ # get billed
+ 'no_usage_reset' => 1,
+ 'time' => $last_bill_date, # not $cust_bill->_date
+ 'pkg_list' => [ values %billing_pkgs ],
+ 'freq_override' => $months,
+ );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error inserting cust_pay: $error";
+ }
+ $error = $cust_main->apply_payments_and_credits;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error inserting cust_pay: $error";
+ }
+ my $new_balance = $cust_main->balance;
+ if ($new_balance > 0) {
+ $dbh->rollback if $oldAutoCommit;
+ return "balance after prepay discount attempt: $new_balance";
+ }
+ # user friendly: override the "apply only to this invoice" mode
+ $self->invnum('');
+
+ }
+