X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_main%2FBilling.pm;h=9bfab96ef622ec979cbdb90feed0129bc4ce3518;hb=92b6628c08e4478e48b6f250320a3e3e93262ec2;hp=9e2082fc32e036cc46189406dc13a3215a007c38;hpb=707368aa7db1cecdd05b74c8531249a1e1370823;p=freeside.git diff --git a/FS/FS/cust_main/Billing.pm b/FS/FS/cust_main/Billing.pm index 9e2082fc3..9bfab96ef 100644 --- a/FS/FS/cust_main/Billing.pm +++ b/FS/FS/cust_main/Billing.pm @@ -21,7 +21,7 @@ use FS::cust_bill_pkg_tax_rate_location; use FS::part_event; use FS::part_event_condition; use FS::pkg_category; -use FS::cust_event_fee; +use FS::FeeOrigin_Mixin; use FS::Log; use FS::TaxEngine; @@ -390,7 +390,7 @@ terms or the default terms are used. sub bill { my( $self, %options ) = @_; - return '' if $self->payby eq 'COMP'; + return '' if $self->complimentary eq 'Y'; local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG; my $log = FS::Log->new('FS::cust_main::Billing::bill'); @@ -518,13 +518,36 @@ sub bill { push @{ $cust_bill_pkg{$pass} }, @transfer_items; # treating this as recur, just because most charges are recur... ${$total_recur{$pass}} += $_->recur foreach @transfer_items; + + # currently not considering separate_bill here, as it's for + # one-time charges only } foreach my $part_pkg ( @part_pkg ) { $cust_pkg->set($_, $hash{$_}) foreach qw ( setup last_bill bill ); - my $pass = ($cust_pkg->no_auto || $part_pkg->no_auto) ? 'no_auto' : ''; + my $pass = ''; + if ( $cust_pkg->separate_bill ) { + # if no_auto is also set, that's fine. we just need to not have + # invoices that are both auto and no_auto, and since the package + # gets an invoice all to itself, it will only be one or the other. + $pass = $cust_pkg->pkgnum; + if (!exists $cust_bill_pkg{$pass}) { # it may not exist yet + push @passes, $pass; + $total_setup{$pass} = do { my $z = 0; \$z }; + $total_recur{$pass} = do { my $z = 0; \$z }; + # it also needs its own tax context + $tax_engines{$pass} = FS::TaxEngine->new( + cust_main => $self, + invoice_time => $invoice_time, + cancel => $options{cancel} + ); + $cust_bill_pkg{$pass} = []; + } + } elsif ( ($cust_pkg->no_auto || $part_pkg->no_auto) ) { + $pass = 'no_auto'; + } my $next_bill = $cust_pkg->getfield('bill') || 0; my $error; @@ -566,13 +589,7 @@ sub bill { } #foreach my $cust_pkg - #if the customer isn't on an automatic payby, everything can go on a single - #invoice anyway? - #if ( $cust_main->payby !~ /^(CARD|CHEK)$/ ) { - #merge everything into one list - #} - - foreach my $pass (@passes) { # keys %cust_bill_pkg ) { + foreach my $pass (@passes) { # keys %cust_bill_pkg ) my @cust_bill_pkg = _omit_zero_value_bundles(@{ $cust_bill_pkg{$pass} }); @@ -584,17 +601,17 @@ sub bill { # process fees ### - my @pending_event_fees = FS::cust_event_fee->by_cust($self->custnum, + my @pending_fees = FS::FeeOrigin_Mixin->by_cust($self->custnum, hashref => { 'billpkgnum' => '' } ); - warn "$me found pending fee events:\n".Dumper(\@pending_event_fees)."\n" - if @pending_event_fees and $DEBUG > 1; + warn "$me found pending fees:\n".Dumper(\@pending_fees)."\n" + if @pending_fees and $DEBUG > 1; # determine whether to generate an invoice my $generate_bill = scalar(@cust_bill_pkg) > 0; - foreach my $event_fee (@pending_event_fees) { - $generate_bill = 1 unless $event_fee->nextbill; + foreach my $fee (@pending_fees) { + $generate_bill = 1 unless $fee->nextbill; } # don't create an invoice with no line items, or where the only line @@ -603,38 +620,11 @@ sub bill { # calculate fees... my @fee_items; - foreach my $event_fee (@pending_event_fees) { - my $object = $event_fee->cust_event->cust_X; - my $part_fee = $event_fee->part_fee; - my $cust_bill; - if ( $object->isa('FS::cust_main') - or $object->isa('FS::cust_pkg') - or $object->isa('FS::cust_pay_batch') ) - { - # Not the real cust_bill object that will be inserted--in particular - # there are no taxes yet. If you want to charge a fee on the total - # invoice amount including taxes, you have to put the fee on the next - # invoice. - $cust_bill = FS::cust_bill->new({ - 'custnum' => $self->custnum, - 'cust_bill_pkg' => \@cust_bill_pkg, - 'charged' => ${ $total_setup{$pass} } + - ${ $total_recur{$pass} }, - }); - - # If this is a package event, only apply the fee to line items - # from that package. - if ($object->isa('FS::cust_pkg')) { - $cust_bill->set('cust_bill_pkg', - [ grep { $_->pkgnum == $object->pkgnum } @cust_bill_pkg ] - ); - } + foreach my $fee_origin (@pending_fees) { + my $part_fee = $fee_origin->part_fee; - } elsif ( $object->isa('FS::cust_bill') ) { - # simple case: applying the fee to a previous invoice (late fee, - # etc.) - $cust_bill = $object; - } + # check whether the fee is applicable before doing anything expensive: + # # if the fee def belongs to a different agent, don't charge the fee. # event conditions should prevent this, but just in case they don't, # skip the fee. @@ -645,10 +635,41 @@ sub bill { } # also skip if it's disabled next if $part_fee->disabled eq 'Y'; + + # Decide which invoice to base the fee on. + my $cust_bill = $fee_origin->cust_bill; + if (!$cust_bill) { + # Then link it to the current invoice. This isn't the real cust_bill + # object that will be inserted--in particular there are no taxes yet. + # If you want to charge a fee on the total invoice amount including + # taxes, you have to put the fee on the next invoice. + $cust_bill = FS::cust_bill->new({ + 'custnum' => $self->custnum, + 'cust_bill_pkg' => \@cust_bill_pkg, + 'charged' => ${ $total_setup{$pass} } + + ${ $total_recur{$pass} }, + }); + + # If the origin is for a specific package, then only apply the fee to + # line items from that package. + if ( my $cust_pkg = $fee_origin->cust_pkg ) { + my @charge_fee_on_item; + my $charge_fee_on_amount = 0; + foreach (@cust_bill_pkg) { + if ($_->pkgnum == $cust_pkg->pkgnum) { + push @charge_fee_on_item, $_; + $charge_fee_on_amount += $_->setup + $_->recur; + } + } + $cust_bill->set('cust_bill_pkg', \@charge_fee_on_item); + $cust_bill->set('charged', $charge_fee_on_amount); + } + + } # $cust_bill is now set # calculate the fee my $fee_item = $part_fee->lineitem($cust_bill) or next; # link this so that we can clear the marker on inserting the line item - $fee_item->set('cust_event_fee', $event_fee); + $fee_item->set('fee_origin', $fee_origin); push @fee_items, $fee_item; }