+ $self->set('unitsetup', $unitsetup);
+ $self->set('unitrecur', $unitrecur);
+ my $error = $self->replace;
+ return $error if $error;
+
+ # semi-duplicates calc_discount
+ my $setup_discount = 0;
+ my $recur_discount = 0;
+
+ my %setup_discounts; # quotationpkgdiscountnum => amount
+ my %recur_discounts; # quotationpkgdiscountnum => amount
+
+ # XXX the order of applying discounts is ill-defined, which matters
+ # if there are percentage and amount discounts on the same package.
+ #
+ # but right now there can only be one discount on any package, so
+ # it doesn't matter
+ foreach my $pkg_discount ($self->quotation_pkg_discount) {
+
+ my $discount = $pkg_discount->discount;
+ my $this_setup_discount = 0;
+ my $this_recur_discount = 0;
+
+ if ( $discount->percent > 0 ) {
+
+ if ( $discount->setup ) {
+ $this_setup_discount = ($discount->percent * $unitsetup / 100);
+ }
+ $this_recur_discount = ($discount->percent * $unitrecur / 100);
+
+ } elsif ( $discount->amount > 0 ) {
+
+ my $discount_left = $discount->amount;
+ if ( $discount->setup ) {
+ if ( $discount_left > $unitsetup - $setup_discount ) {
+ # then discount the setup to zero
+ $discount_left -= $unitsetup - $setup_discount;
+ $this_setup_discount = $unitsetup - $setup_discount;
+ } else {
+ # not enough discount to fully cover the setup
+ $this_setup_discount = $discount_left;
+ $discount_left = 0;
+ }
+ }
+ # same logic for recur
+ if ( $discount_left > $unitrecur - $recur_discount ) {
+ $this_recur_discount = $unitrecur - $recur_discount;
+ } else {
+ $this_recur_discount = $discount_left;
+ }
+
+ }
+
+ # increment the total discountage
+ $setup_discount += $this_setup_discount;
+ $recur_discount += $this_recur_discount;
+ # and update the pkg_discount object
+ $pkg_discount->set('setup_amount', sprintf('%.2f', $setup_discount));
+ $pkg_discount->set('recur_amount', sprintf('%.2f', $recur_discount));
+ my $error = $pkg_discount->replace;
+ return $error if $error;
+ }
+
+ '';
+}
+
+=item insert_discount
+
+Associates this package with a discount (see L<FS::cust_pkg_discount>,
+possibly inserting a new discount on the fly (see L<FS::discount>). Properties
+of the discount will be taken from this object.
+
+=cut
+
+sub insert_discount {
+ #my ($self, %options) = @_;
+ my $self = shift;
+
+ my $quotation_pkg_discount = FS::quotation_pkg_discount->new( {
+ 'quotationpkgnum' => $self->quotationpkgnum,
+ 'discountnum' => $self->discountnum,
+ #for the create a new discount case
+ '_type' => $self->discountnum__type,
+ 'amount' => $self->discountnum_amount,
+ 'percent' => $self->discountnum_percent,
+ 'months' => $self->discountnum_months,
+ 'setup' => $self->discountnum_setup,
+ } );
+
+ $quotation_pkg_discount->insert;
+}
+
+sub _item_discount {
+ my $self = shift;
+ my @pkg_discounts = $self->pkg_discount;
+ return if @pkg_discounts == 0;
+
+ my @ext;
+ my $d = {
+ _is_discount => 1,
+ description => $self->mt('Discount'),
+ setup_amount => 0,
+ recur_amount => 0,
+ amount => 0,
+ ext_description => \@ext,
+ # maybe should show quantity/unit discount?
+ };
+ foreach my $pkg_discount (@pkg_discounts) {
+ push @ext, $pkg_discount->description;
+ $d->{setup_amount} -= $pkg_discount->setup_amount;
+ $d->{recur_amount} -= $pkg_discount->recur_amount;
+ }
+ $d->{setup_amount} *= $self->quantity || 1;
+ $d->{recur_amount} *= $self->quantity || 1;
+ $d->{amount} = $d->{setup_amount} + $d->{recur_amount};
+
+ return $d;
+}
+
+sub setup {
+ my $self = shift;
+ ($self->unitsetup - sum(0, map { $_->setup_amount } $self->pkg_discount))
+ * ($self->quantity || 1);