- } else {
- # leave this as is for now
-
- my $name = $taxline->{'name'};
- my $amount = $taxline->{'amount'};
-
- #warn "adding $amount as $name\n";
- $taxname{ $name } ||= [];
- push @{ $taxname{ $name } }, $tax;
-
- $tax_amount{ $tax } += $amount;
-
- # link records between cust_main_county/tax_rate and cust_location
- $tax_rate_location{ $tax } ||= [];
- my $taxratelocationnum =
- $tax_object->tax_rate_location->taxratelocationnum;
- push @{ $tax_rate_location{ $tax } },
- {
- 'taxnum' => $tax_object->taxnum,
- 'taxtype' => ref($tax_object),
- 'amount' => sprintf('%.2f', $amount ),
- 'locationtaxid' => $tax_object->location,
- 'taxratelocationnum' => $taxratelocationnum,
- };
- } #if ref($tax_object)...
- } #foreach keys %$taxlisthash
+ # all first-tier taxes are calculated. now for tax on tax:
+
+ foreach my $taxable_item ( @$cust_bill_pkg ) {
+ # taxes that apply to this item
+ my $this_has_tax = $item_has_tax{$taxable_item};
+
+ my $location = $taxable_item->tax_location;
+
+ foreach my $charge_class (keys %$this_has_tax) {
+ # taxes that apply to this item and charge class
+ my $this_class_has_tax = $this_has_tax->{$charge_class};
+ foreach my $taxnum (keys %$this_class_has_tax) {
+
+ # for each tax item that was calculated in phase 1, get the
+ # tax definition
+ my $tax_object = FS::tax_rate->by_key($taxnum);
+ # and find all taxes that apply to it in this location
+ my @tot = $tax_object->tax_on_tax( $location );
+ next if !@tot;
+ warn "found possible taxed taxnum $taxnum\n"
+ if $DEBUG > 2;
+ # Calculate ToT separately for each taxable item and class, and only
+ # if _that class on the item_ is already taxed under the ToT. This is
+ # counterintuitive.
+ # See RT#5243 and RT#36380.
+ foreach my $tot (@tot) {
+ my $totnum = $tot->taxnum;
+ warn "checking taxnum $totnum which we call ". $tot->taxname ."\n"
+ if $DEBUG > 2;
+ # note: if the _null class_ on this item is taxed under the ToT,
+ # then this specific class is taxed also (because null class
+ # includes all classes) and so ToT is applicable.
+ if (
+ exists $this_class_has_tax->{ $totnum }
+ or exists $this_has_tax->{''}{ $totnum }
+ ) {
+
+ warn "calculating tax on tax: taxnum $totnum on $taxnum\n"
+ if $DEBUG;
+ my @taxlines = $tot->taxline(
+ $this_class_has_tax->{ $taxnum }, # the first-stage tax
+ 'custnum' => $custnum,
+ 'invoice_time' => $invoice_time,
+ );
+ next if (!@taxlines); # it didn't apply after all
+ if (!ref($taxlines[0])) {
+ warn "error evaluating taxnum $totnum TOT on custnum $custnum\n";
+ return $taxlines[0];
+ }
+ foreach my $taxline (@taxlines) {
+ push @{ $taxname{ $taxline->itemdesc } }, $taxline;
+ }
+ } # if $has_tax
+ } # foreach my $tot (tax-on-tax rate definition)
+ } # foreach $taxnum (first-tier rate definition)
+ } # foreach $charge_class
+ } # foreach $taxable_item