use FS::cust_bill_pkg_tax_rate_location_void;
use FS::cust_tax_exempt_pkg_void;
use FS::cust_bill_pkg_fee_void;
+use FS::reason;
+use FS::reason_type;
use FS::Cursor;
}
-=item void
+=item void [ REASON ]
Voids this line item: deletes the line item and adds a record of the voided
line item to the FS::cust_bill_pkg_void table (and related tables).
my $self = shift;
my $reason = scalar(@_) ? shift : '';
+ unless (ref($reason) || !$reason) {
+ $reason = FS::reason->new_or_existing(
+ 'class' => 'I',
+ 'type' => 'Invoice void',
+ 'reason' => $reason
+ );
+ }
+
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
local $SIG{QUIT} = 'IGNORE';
my $cust_bill_pkg_void = new FS::cust_bill_pkg_void ( {
map { $_ => $self->get($_) } $self->fields
} );
- $cust_bill_pkg_void->reason($reason);
+ $cust_bill_pkg_void->reasonnum($reason->reasonnum) if $reason;
my $error = $cust_bill_pkg_void->insert;
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
sub _item_discount {
my $self = shift;
+ my %options = @_;
+
+ my $d; # this will be returned.
+
my @pkg_discounts = $self->pkg_discount;
- return if @pkg_discounts == 0;
- # special case: if there are old "discount details" on this line item, don't
- # show discount line items
- if ( FS::cust_bill_pkg_detail->count("detail LIKE 'Includes discount%' AND billpkgnum = ?", $self->billpkgnum || 0) > 0 ) {
- return;
- }
-
- my @ext;
- my $d = {
- _is_discount => 1,
- description => $self->mt('Discount'),
- amount => 0,
- ext_description => \@ext,
- # maybe should show quantity/unit discount?
- };
- foreach my $pkg_discount (@pkg_discounts) {
- push @ext, $pkg_discount->description;
- $d->{amount} -= $pkg_discount->amount;
- }
- $d->{amount} *= $self->quantity || 1;
-
- return $d;
+ if (@pkg_discounts) {
+ # special case: if there are old "discount details" on this line item,
+ # don't show discount line items
+ if ( FS::cust_bill_pkg_detail->count("detail LIKE 'Includes discount%' AND billpkgnum = ?", $self->billpkgnum || 0) > 0 ) {
+ return;
+ }
+
+ my @ext;
+ $d = {
+ _is_discount => 1,
+ description => $self->mt('Discount'),
+ setup_amount => 0,
+ recur_amount => 0,
+ ext_description => \@ext,
+ pkgpart => $self->pkgpart,
+ feepart => $self->feepart,
+ # maybe should show quantity/unit discount?
+ };
+ foreach my $pkg_discount (@pkg_discounts) {
+ push @ext, $pkg_discount->description;
+ my $setuprecur = $pkg_discount->cust_pkg_discount->setuprecur;
+ $d->{$setuprecur.'_amount'} -= $pkg_discount->amount;
+ }
+ }
+
+ # show introductory rate as a pseudo-discount
+ if (!$d) { # this will conflict with showing real discounts
+ my $part_pkg = $self->part_pkg;
+ if ( $part_pkg and $part_pkg->option('show_as_discount') ) {
+ my $cust_pkg = $self->cust_pkg;
+ my $intro_end = $part_pkg->intro_end($cust_pkg);
+ my $_date = $self->cust_bill->_date;
+ if ( $intro_end > $_date ) {
+ $d = $part_pkg->item_discount($cust_pkg);
+ }
+ }
+ }
+
+ if ( $d ) {
+ $d->{setup_amount} *= $self->quantity || 1; # ??
+ $d->{recur_amount} *= $self->quantity || 1; # ??
+ }
+
+ $d;
}
=item set_display OPTION => VALUE ...
=item recur_show_zero
-=cut
+Whether to show a zero recurring amount. This is true if the package or its
+definition has the recur_show_zero flag, and the recurring fee is actually
+zero for this period.
-sub recur_show_zero { shift->_X_show_zero('recur'); }
-sub setup_show_zero { shift->_X_show_zero('setup'); }
+=cut
-sub _X_show_zero {
+sub recur_show_zero {
my( $self, $what ) = @_;
- return 0 unless $self->$what() == 0 && $self->pkgnum;
+ return 0 unless $self->get('recur') == 0 && $self->pkgnum;
+
+ $self->cust_pkg->_X_show_zero('recur');
+}
+
+=item setup_show_zero
+
+Whether to show a zero setup charge. This requires the package or its
+definition to have the setup_show_zero flag, but it also returns false if
+the package's setup date is before this line item's start date.
+
+=cut
- $self->cust_pkg->_X_show_zero($what);
+sub setup_show_zero {
+ my $self = shift;
+ return 0 unless $self->get('setup') == 0 && $self->pkgnum;
+ my $cust_pkg = $self->cust_pkg;
+ return 0 if ( $self->sdate || 0 ) > ( $cust_pkg->setup || 0 );
+ return $cust_pkg->_X_show_zero('setup');
}
=item credited [ BEFORE, AFTER, OPTIONS ]
if ( $self->pkgnum ) { # normal sales
return $self->cust_pkg->tax_locationnum;
} elsif ( $self->feepart ) { # fees
- return $self->cust_bill->cust_main->ship_locationnum;
+ my $custnum = $self->fee_origin->custnum;
+ if ( $custnum ) {
+ return FS::cust_main->by_key($custnum)->ship_locationnum;
+ }
} else { # taxes
return '';
}
if ( $self->pkgnum ) { # normal sales
return $self->cust_pkg->tax_location;
} elsif ( $self->feepart ) { # fees
- return $self->cust_bill->cust_main->ship_location;
+ my $custnum = $self->fee_origin->custnum;
+ if ( $custnum ) {
+ return FS::cust_main->by_key($custnum)->ship_location;
+ }
} else { # taxes
return;
}