[freeside-commits] branch FREESIDE_3_BRANCH updated. 0d678bcd0d18621ede25d0465b71e919e1c5212e

Mark Wells mark at 420.am
Mon Aug 17 12:18:23 PDT 2015


The branch, FREESIDE_3_BRANCH has been updated
       via  0d678bcd0d18621ede25d0465b71e919e1c5212e (commit)
       via  471305e3debe7bd92742e63439a21f1905a91737 (commit)
       via  3fa17959680a3181b652f2af160904210d45e1ef (commit)
       via  f33a1eaf968dbdbfbc55d7fb05cd2e36237c7676 (commit)
      from  e8c2e9a2fe84ad1dd5c4bc02d8837fdd3549bd18 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 0d678bcd0d18621ede25d0465b71e919e1c5212e
Author: Mark Wells <mark at freeside.biz>
Date:   Mon Aug 17 12:13:14 2015 -0700

    but still show credited amount on line item report, #18676 fixes

diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi
index 06716c7..fcf2110 100644
--- a/httemplate/search/cust_bill_pkg.cgi
+++ b/httemplate/search/cust_bill_pkg.cgi
@@ -41,8 +41,8 @@
                    @peritem,
                    'invnum',
                    '_date',
-                   '', #'pay_amount',
-                   '', #'credit_amount',
+                   'pay_amount',
+                   'credit_amount',
                    FS::UI::Web::cust_sort_fields(),
                  ],
                  'links'       => [
@@ -437,15 +437,6 @@ if ( $cgi->param('nottax') ) {
       USING (billpkgnum)";
     }
 
-    # This is the only place we should attempt to show credits on here:
-    # the total of credit applications to the line item.
-
-    my $credit_sub = 'SELECT SUM(amount) AS credit_amount, billpkgnum
-    FROM cust_credit_bill_pkg GROUP BY billpkgnum';
-
-    $join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit
-    ON (cust_bill_pkg.billpkgnum = item_credit.billpkgnum)";
-   
     if ( @tax_where or $cgi->param('taxable') ) {
       # process tax restrictions
       unshift @tax_where,
@@ -689,7 +680,6 @@ if ( $cgi->param('nottax') ) {
 
 } # nottax / istax
 
-
 #total payments
 my $pay_sub = "SELECT SUM(cust_bill_pay_pkg.amount)
                  FROM cust_bill_pay_pkg
@@ -697,6 +687,15 @@ my $pay_sub = "SELECT SUM(cust_bill_pay_pkg.amount)
               ";
 push @select, "($pay_sub) AS pay_amount";
 
+#total credits
+my $credit_sub = 'SELECT SUM(amount) AS credit_amount, billpkgnum
+                  FROM cust_credit_bill_pkg GROUP BY billpkgnum';
+
+$join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit
+  ON (cust_bill_pkg.billpkgnum = item_credit.billpkgnum)";
+push @select, 'credit_amount';
+
+# standard customer fields
 push @select, 'cust_main.custnum', FS::UI::Web::cust_sql_fields();
 
 #salesnum

commit 471305e3debe7bd92742e63439a21f1905a91737
Author: Mark Wells <mark at freeside.biz>
Date:   Fri Aug 14 14:43:02 2015 -0700

    fix anomalous behavior in line item report with consolidated taxes, needed for #26770, from...#18676, I think?
    
    Conflicts:
    	httemplate/search/cust_bill_pkg.cgi

diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi
index 53ef6b4..06716c7 100644
--- a/httemplate/search/cust_bill_pkg.cgi
+++ b/httemplate/search/cust_bill_pkg.cgi
@@ -436,6 +436,15 @@ if ( $cgi->param('nottax') ) {
       $join_pkg .= " LEFT JOIN ($exempt_sub) AS item_exempt
       USING (billpkgnum)";
     }
+
+    # This is the only place we should attempt to show credits on here:
+    # the total of credit applications to the line item.
+
+    my $credit_sub = 'SELECT SUM(amount) AS credit_amount, billpkgnum
+    FROM cust_credit_bill_pkg GROUP BY billpkgnum';
+
+    $join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit
+    ON (cust_bill_pkg.billpkgnum = item_credit.billpkgnum)";
    
     if ( @tax_where or $cgi->param('taxable') ) {
       # process tax restrictions
@@ -552,60 +561,118 @@ if ( $cgi->param('nottax') ) {
 
 } elsif ( $cgi->param('istax') ) {
 
-  @peritem = ( 'setup' ); # taxes only have setup
-  @peritem_desc = ( 'Tax charge' );
+  # ensure that it is a tax:
+  push @where, 'cust_bill_pkg.pkgnum = 0',
+               'cust_bill_pkg.feepart IS NULL';
 
-  push @where, 'cust_bill_pkg.pkgnum = 0';
+  # We MUST NOT join cust_bill_pkg to any table that it's 1:many to.
+  # Otherwise we get duplication of the cust_bill_pkg records, 
+  # inaccurate totals, nonsensical paging behavior, etc.
+  # We CAN safely join it to a subquery that has unique billpkgnums, and 
+  # that's what we'll do.
+
+  my $tax_subquery;
+  my @tax_where;
 
   # tax location when using tax_rate_location
   if ( $cgi->param('vendortax') ) {
 
-    $join_pkg .= ' LEFT JOIN cust_bill_pkg_tax_rate_location USING ( billpkgnum ) '.
-                 ' LEFT JOIN tax_rate_location USING ( taxratelocationnum )';
+    $tax_subquery = '
+      SELECT billpkgnum, SUM(amount) as tax_total
+      FROM cust_bill_pkg_tax_rate_location AS tax
+        JOIN tax_rate_location USING (taxratelocationnum)
+    ';
     foreach (qw( state county city locationtaxid)) {
       if ( scalar($cgi->param($_)) ) {
         my $place = dbh->quote( $cgi->param($_) );
-        push @where, "tax_rate_location.$_ = $place";
+        push @tax_where, "tax_rate_location.$_ = $place";
       }
     }
 
-    push @total, 'SUM(
-      COALESCE(cust_bill_pkg_tax_rate_location.amount, 
-               cust_bill_pkg.setup + cust_bill_pkg.recur)
-    )';
-    push @total_desc, "$money_char%.2f total";
-
   } else { # the internal-tax case
 
-    $join_pkg .= '
-      LEFT JOIN cust_bill_pkg_tax_location USING (billpkgnum)
-      JOIN cust_main_county           USING (taxnum)
-    ';
-
-    # don't double-count the components of consolidated taxes
-    @total = ( 'COUNT(DISTINCT cust_bill_pkg.billpkgnum)',
-               'SUM(cust_bill_pkg_tax_location.amount)' );
-    @total_desc = "$money_char%.2f total";
+    my $tax_select = 'SELECT tax.billpkgnum, SUM(tax.amount) as tax_total';
+    my $tax_from = ' FROM cust_bill_pkg_tax_location AS tax JOIN cust_main_county USING (taxnum)';
+
+    # package classnum
+    if ( grep { $_ eq 'classnum' } $cgi->param ) {
+      my @classnums = grep /^\d*$/, $cgi->param('classnum');
+      $tax_from .= '
+        JOIN cust_bill_pkg AS taxed_item
+          ON (tax.taxable_billpkgnum = taxed_item.billpkgnum)
+        LEFT JOIN cust_pkg AS taxed_pkg ON (taxed_item.pkgnum = taxed_pkg.pkgnum)
+        LEFT JOIN part_pkg AS taxed_part_pkg ON (taxed_pkg.pkgpart = taxed_part_pkg.pkgpart)
+        LEFT JOIN part_fee AS taxed_part_fee ON (taxed_item.feepart = taxed_part_fee.feepart)
+      ';
+      push @tax_where,
+        "COALESCE(taxed_part_pkg.classnum, taxed_part_fee.classnum,0) IN ( ".
+                       join(',', @classnums ).
+                   ' )'
+        if @classnums;
+    }
 
     # taxclass
     if ( $cgi->param('taxclassNULL') ) {
-      push @where, 'cust_main_county.taxclass IS NULL';
+      push @tax_where, 'cust_main_county.taxclass IS NULL';
     }
 
     # taxname
     if ( $cgi->param('taxnameNULL') ) {
-      push @where, 'cust_main_county.taxname IS NULL OR '.
+      push @tax_where, 'cust_main_county.taxname IS NULL OR '.
                    'cust_main_county.taxname = \'Tax\'';
     } elsif ( $cgi->param('taxname') ) {
-      push @where, 'cust_main_county.taxname = '.
+      push @tax_where, 'cust_main_county.taxname = '.
                     dbh->quote($cgi->param('taxname'));
     }
 
-    # specific taxnums
-    if ( $cgi->param('taxnum') =~ /^([0-9,]+)$/ ) {
-      push @where, "cust_main_county.taxnum IN ($1)";
+    # itemdesc, for breakdown from the vendor tax report
+    # (is this even used? vendor tax report shouldn't use cust_bill_pkg.cgi)
+    if ( $cgi->param('itemdesc') ) {
+      if ( $cgi->param('itemdesc') eq 'Tax' ) {
+        push @where, "($itemdesc = 'Tax' OR $itemdesc is null)";
+      } else {
+        push @where, "$itemdesc = ". dbh->quote($cgi->param('itemdesc'));
+      }
+    }
+
+    # specific taxnums (the usual way)
+    if ( $cgi->param('taxnum') =~ /^([\d,]+)$/) {
+      push @tax_where, "cust_main_county.taxnum IN ($1)";
     }
-  } # the normal case
+
+    $tax_subquery = "$tax_select $tax_from";
+
+  } # end of internal-tax case
+
+  if (@tax_where) {
+    $tax_subquery .= '
+      WHERE ' . join(' AND ', map "($_)", @tax_where);
+  }
+  $tax_subquery .= ' GROUP BY tax.billpkgnum ';
+
+  # now join THAT into the main report
+  # (inner join, so that tax line items that don't match the tax_where 
+  # conditions don't appear in the output.)
+
+  $join_pkg .= " JOIN ($tax_subquery) AS _istax USING (billpkgnum) ";
+
+  push @select, 'tax_total';
+
+  @peritem = ( 'setup' ); # total tax on the invoice, not just the filtered tax
+  @peritem_desc = ( 'Tax charge' );
+
+  @total = ( 'COUNT(cust_bill_pkg.billpkgnum)',
+             'SUM(cust_bill_pkg.setup)' );
+  @total_desc = ( "$money_char%.2f total tax" );
+
+  if ( @tax_where ) {
+    # then also show the filtered tax
+    push @peritem, 'tax_total';
+    push @peritem_desc, 'Tax in category';
+    push @total, 'SUM(tax_total)';
+    push @total_desc, "$money_char%.2f tax in this category";
+    # would also be nice to include a line explaining what the category is
+  }
 
   # report group (itemdesc)
   if ( $cgi->param('report_group') =~ /^(=|!=) (.*)$/ ) {
@@ -620,15 +687,6 @@ if ( $cgi->param('nottax') ) {
     }
   }
 
-  # itemdesc, for breakdown from the vendor tax report
-  if ( $cgi->param('itemdesc') ) {
-    if ( $cgi->param('itemdesc') eq 'Tax' ) {
-      push @where, "($itemdesc = 'Tax' OR $itemdesc is null)";
-    } else {
-      push @where, "$itemdesc = ". dbh->quote($cgi->param('itemdesc'));
-    }
-  }
-
 } # nottax / istax
 
 
@@ -639,87 +697,6 @@ my $pay_sub = "SELECT SUM(cust_bill_pay_pkg.amount)
               ";
 push @select, "($pay_sub) AS pay_amount";
 
-
-# credit
-if ( $cgi->param('credit') ) {
-
-  my $credit_where;
-
-  my($cr_begin, $cr_end) = FS::UI::Web::parse_beginning_ending($cgi, 'credit');
-  $credit_where = "WHERE cust_credit_bill._date >= $cr_begin " .
-                  "AND cust_credit_bill._date <= $cr_end";
-
-  my $credit_sub;
-
-  if ( $cgi->param('istax') ) {
-    # then we need to group/join by billpkgtaxlocationnum, to get only the 
-    # relevant part of partial taxes
-    my $credit_sub = "SELECT SUM(cust_credit_bill_pkg.amount) AS credit_amount,
-      reason.reason as reason_text, access_user.username AS username_text,
-      billpkgtaxlocationnum, billpkgnum
-    FROM cust_credit_bill_pkg
-      JOIN cust_credit_bill USING (creditbillnum)
-      JOIN cust_credit USING (crednum)
-      LEFT JOIN reason USING (reasonnum)
-      LEFT JOIN access_user USING (usernum)
-    $credit_where
-    GROUP BY billpkgnum, billpkgtaxlocationnum, reason.reason, 
-      access_user.username";
-
-    if ( $cgi->param('out') ) {
-
-      # find credits that are applied to the line items, but not to 
-      # a cust_bill_pkg_tax_location link
-      $join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit
-        USING (billpkgnum)";
-      push @where, 'item_credit.billpkgtaxlocationnum IS NULL';
-
-    } else {
-
-      # find credits that are applied to the CBPTL links that are 
-      # considered "interesting" by the report criteria
-      $join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit
-        USING (billpkgtaxlocationnum)";
-
-    }
-
-  } else {
-    # then only group by billpkgnum
-    my $credit_sub = "SELECT SUM(cust_credit_bill_pkg.amount) AS credit_amount,
-      reason.reason as reason_text, access_user.username AS username_text,
-      billpkgnum
-    FROM cust_credit_bill_pkg
-      JOIN cust_credit_bill USING (creditbillnum)
-      JOIN cust_credit USING (crednum)
-      LEFT JOIN reason USING (reasonnum)
-      LEFT JOIN access_user USING (usernum)
-    $credit_where
-    GROUP BY billpkgnum, reason.reason, access_user.username";
-    $join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit USING (billpkgnum)";
-  }
-
-  push @where,    'item_credit.billpkgnum IS NOT NULL';
-  push @select,   'item_credit.credit_amount',
-                  'item_credit.username_text',
-                  'item_credit.reason_text';
-  push @peritem,  'credit_amount', 'username_text', 'reason_text';
-  push @peritem_desc, 'Credited', 'By', 'Reason';
-  push @total,    'SUM(credit_amount)';
-  push @total_desc, "$money_char%.2f credited";
-
-} else {
-
-  #still want a credit total column
-
-  my $credit_sub = "
-    SELECT SUM(cust_credit_bill_pkg.amount)
-      FROM cust_credit_bill_pkg
-        WHERE cust_bill_pkg.billpkgnum = cust_credit_bill_pkg.billpkgnum
-  ";
-  push @select, "($credit_sub) AS credit_amount";
-
-}
-
 push @select, 'cust_main.custnum', FS::UI::Web::cust_sql_fields();
 
 #salesnum
diff --git a/httemplate/search/report_tax-xls.cgi b/httemplate/search/report_tax-xls.cgi
index d0ef434..743f147 100755
--- a/httemplate/search/report_tax-xls.cgi
+++ b/httemplate/search/report_tax-xls.cgi
@@ -146,7 +146,7 @@ my $colhead = $format[0]->{colhead};
 # print header
 $ws->merge_range($y, 1, $y, 5, 'Sales', $colhead);
 $ws->merge_range($y, 6, $y+1, 8, 'Rate', $colhead);
-$ws->merge_range($y, 9, $y, 14, 'Tax', $colhead);
+$ws->merge_range($y, 9, $y, 15, 'Tax', $colhead);
 
 $y++;
 $colhead = $format[0]->{colhead_small};
@@ -156,16 +156,17 @@ $ws->write($y, 9, 'Estimated', $colhead);
 $ws->write($y, 10, 'Invoiced', $colhead);
 $ws->write($y, 12, 'Credited', $colhead);
 $ws->write($y, 14, 'Net due',  $colhead);
+$ws->write($y, 15, 'Collected',$colhead);
 $y++;
 
 # print data
-my $rownum = 0;
+my $rownum = 1;
 my $prev_row = { pkgclass => 'DUMMY PKGCLASS' };
 
 foreach my $row (@rows) {
   $x = 0;
   if ( $row->{pkgclass} ne $prev_row->{pkgclass} ) {
-    $rownum = 0;
+    $rownum = 1;
     if ( $params{breakdown}->{pkgclass} ) {
       $ws->merge_range($y, 0, $y, 14,
         $pkgclass_name{$row->{pkgclass}},
@@ -206,6 +207,8 @@ foreach my $row (@rows) {
   $ws->write_string($y, $x, " = ", $f->{bigmath});
   $x++;
   $ws->write($y, $x, $row->{tax} - $row->{credit}, $f->{currency});
+  $x++;
+  $ws->write($y, $x, $row->{tax_paid} || 0, $f->{currency});
 
   $rownum++;
   $y++;
diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi
index 491cd42..1d90647 100644
--- a/httemplate/search/report_tax.cgi
+++ b/httemplate/search/report_tax.cgi
@@ -32,6 +32,8 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px }
     <TH ROWSPAN=3>Tax credited</TH>
     <TH ROWSPAN=3></TH>
     <TH ROWSPAN=3>Net tax due</TH>
+    <TH ROWSPAN=3></TH>
+    <TH ROWSPAN=3>Tax collected</TH>
   </TR>
 
   <TR>
@@ -131,13 +133,16 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px }
 %   # credited tax
     <TD CLASS="bigmath"> − </TD>
     <TD>
-      <A HREF="<% $creditlink . $rowlink %>">
+%#      <A HREF="<% $creditlink . $rowlink %>"> currently broken
         <% $money_sprintf->( $row->{credit} ) %>
-      </A>
+%#      </A>
     </TD>
 %   # net tax due
     <TD CLASS="bigmath"> = </TD>
     <TD><% $money_sprintf->( $row->{tax} - $row->{credit} ) %></TD>
+%   # tax collected
+    <TD> </TD>
+    <TD><% $money_sprintf->( $row->{tax_paid} ) %></TD>
   </TR>
 %   $rownum++;
 %   $prev_row = $row;
@@ -218,12 +223,12 @@ if ( $params{agentnum} ) {
 my $saleslink  = $p. "search/cust_bill_pkg.cgi?$dateagentlink;nottax=1";
 my $taxlink    = $p. "search/cust_bill_pkg.cgi?$dateagentlink;istax=1";
 my $exemptlink = $p. "search/cust_tax_exempt_pkg.cgi?$dateagentlink";
-my $creditlink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;credit=1;istax=1";
-
-if ( $params{'credit_date'} eq 'cust_credit_bill' ) {
-  $creditlink =~ s/begin/credit_begin/;
-  $creditlink =~ s/end/credit_end/;
-}
+#my $creditlink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;credit=1;istax=1";
+#if ( $params{'credit_date'} eq 'cust_credit_bill' ) {
+#  $creditlink =~ s/begin/credit_begin/;
+#  $creditlink =~ s/end/credit_end/;
+#}
+my $creditlink = ''; # disabled until we find a sane way to do this
 
 my %pkgclass_name = map { $_->classnum, $_->classname } qsearch('pkg_class');
 $pkgclass_name{''} = 'Unclassified';

commit 3fa17959680a3181b652f2af160904210d45e1ef
Author: Mark Wells <mark at freeside.biz>
Date:   Fri Aug 14 14:38:43 2015 -0700

    add "tax collected" to tax liability report, #26770

diff --git a/FS/FS/Report/Tax.pm b/FS/FS/Report/Tax.pm
index 23c1645..0923d55 100644
--- a/FS/FS/Report/Tax.pm
+++ b/FS/FS/Report/Tax.pm
@@ -52,9 +52,10 @@ sub report_internal {
   }
 
   # %breakdown: short name => field identifier
+  # null classnum should remain null, not be converted to zero
   %breakdown = (
     'taxclass'  => 'cust_main_county.taxclass',
-    'pkgclass'  => 'part_pkg.classnum',
+    'pkgclass'  => 'COALESCE(part_fee.classnum,part_pkg.classnum)',
     'city'      => 'cust_main_county.city',
     'district'  => 'cust_main_county.district',
     'state'     => 'cust_main_county.state',
@@ -69,7 +70,8 @@ sub report_internal {
 
   my $join_cust_pkg = $join_cust.
                       ' LEFT JOIN cust_pkg      USING ( pkgnum  )
-                        LEFT JOIN part_pkg      USING ( pkgpart ) ';
+                        LEFT JOIN part_pkg      USING ( pkgpart )
+                        LEFT JOIN part_fee      USING ( feepart ) ';
 
   my $from_join_cust_pkg = " FROM cust_bill_pkg $join_cust_pkg "; 
 
@@ -239,7 +241,7 @@ sub report_internal {
   # there isn't one for 'sales', because we calculate sales by adding up 
   # the taxable and exempt columns.
   
-  # TAX QUERIES (billed tax, credited tax)
+  # TAX QUERIES (billed tax, credited tax, collected tax)
   # -----------
 
   # sum of billed tax:
@@ -252,14 +254,16 @@ sub report_internal {
   if ( $breakdown{pkgclass} ) {
     # If we're not grouping by package class, this is unnecessary, and
     # probably really expensive.
+    # Remember that fees also have package classes.
     $taxfrom .= "
                   LEFT JOIN cust_bill_pkg AS taxable
                     ON (cust_bill_pkg_tax_location.taxable_billpkgnum = taxable.billpkgnum)
                   LEFT JOIN cust_pkg ON (taxable.pkgnum = cust_pkg.pkgnum)
-                  LEFT JOIN part_pkg USING (pkgpart)";
+                  LEFT JOIN part_pkg USING (pkgpart)
+                  LEFT JOIN part_fee ON (taxable.feepart = part_fee.feepart) ";
   }
 
-  my $istax = "cust_bill_pkg.pkgnum = 0";
+  my $istax = "cust_bill_pkg.pkgnum = 0 and cust_bill_pkg.feepart is null";
 
   $sql{tax} = "$select SUM(cust_bill_pkg_tax_location.amount)
                $taxfrom
@@ -272,8 +276,8 @@ sub report_internal {
                $group_all";
 
   # sum of credits applied against billed tax
-  # ($creditfrom includes join of taxable item to part_pkg if with_pkgclass
-  # is on)
+  # ($creditfrom includes join of taxable item to part_pkg/part_fee if 
+  # with_pkgclass is on)
   my $creditfrom = $taxfrom .
     ' JOIN cust_credit_bill_pkg USING (billpkgtaxlocationnum)' .
     ' JOIN cust_credit_bill     USING (creditbillnum)';
@@ -296,6 +300,27 @@ sub report_internal {
                   $creditwhere AND $istax
                   $group_all";
 
+  # sum of tax paid
+  # this suffers from the same ambiguity as anything else that applies 
+  # received payments to specific packages, but in reality the discrepancy
+  # should be minimal since people either pay their bill or don't.
+  # the join is on billpkgtaxlocationnum to avoid cross-producting.
+ 
+  my $paidfrom = $taxfrom .
+    ' JOIN cust_bill_pay_pkg'.
+    ' ON (cust_bill_pay_pkg.billpkgtaxlocationnum ='.
+    ' cust_bill_pkg_tax_location.billpkgtaxlocationnum)';
+
+  $sql{tax_paid} = "$select SUM(cust_bill_pay_pkg.amount)
+                    $paidfrom
+                    $where AND $istax
+                    $group";
+
+  $all_sql{tax_paid} = "$select_all SUM(cust_bill_pay_pkg.amount)
+                    $paidfrom
+                    $where AND $istax
+                    $group_all";
+
   my %data;
   my %total;
   # note that we use keys(%sql) here and keys(%all_sql) later. nothing
@@ -303,7 +328,7 @@ sub report_internal {
   # as for the individual category queries
   foreach my $k (keys(%sql)) {
     my $stmt = $sql{$k};
-    warn "\n".uc($k).":\n".$stmt."\n" if $DEBUG;
+    warn "\n".uc($k).":\n".$stmt."\n" if $DEBUG > 1;
     my $sth = dbh->prepare($stmt);
     # eight columns: pkgclass, taxclass, state, county, city, district
     # taxnums (comma separated), value
@@ -322,7 +347,7 @@ sub report_internal {
       push @$bin, [ $k, $row->[6], $row->[7] ];
     }
   }
-  warn "DATA:\n".Dumper(\%data) if $DEBUG > 1;
+  warn "DATA:\n".Dumper(\%data) if $DEBUG;
 
   foreach my $k (keys %all_sql) {
     warn "\nTOTAL ".uc($k).":\n".$all_sql{$k}."\n" if $DEBUG;

commit f33a1eaf968dbdbfbc55d7fb05cd2e36237c7676
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Wed Aug 12 21:48:43 2015 -0500

    RT#25026: Option to include taxes in sales report

diff --git a/FS/FS/Report/Table.pm b/FS/FS/Report/Table.pm
index 63e5318..4b1ad05 100644
--- a/FS/FS/Report/Table.pm
+++ b/FS/FS/Report/Table.pm
@@ -485,9 +485,9 @@ sub cust_pkg_recur_cost {
 
 =item cust_bill_pkg: the total package charges on invoice line items.
 
-'charges': limit the type of charges included (setup, recur, usage, discount).
-Should be a string containing one or more of 'S', 'R', 'U', or 'D'; if 
-unspecified, defaults to all three.
+'charges': limit the type of charges included (setup, recur, usage, discount, taxes).
+Should be a string containing one or more of 'S', 'R', or 'U'; or 'D' or 'T' (discount
+and taxes should not be combined with the others.)  If unspecified, defaults to 'SRU'.
 
 'classnum': limit to this package class.
 
@@ -517,6 +517,7 @@ sub cust_bill_pkg {
   $sum += $self->cust_bill_pkg_recur(@_) if $charges{R};
   $sum += $self->cust_bill_pkg_detail(@_) if $charges{U};
   $sum += $self->cust_bill_pkg_discount(@_) if $charges{D};
+  $sum += $self->cust_bill_pkg_taxes(@_) if $charges{T};
 
   if ($opt{'average_per_cust_pkg'}) {
     my $count = $self->cust_bill_pkg_count_pkgnum(@_);
@@ -727,6 +728,31 @@ sub cust_bill_pkg_discount {
   $self->scalar_sql($total_sql);
 }
 
+sub cust_bill_pkg_taxes {
+  my $self = shift;
+  my ($speriod, $eperiod, $agentnum, %opt) = @_;
+
+  $agentnum ||= $opt{'agentnum'};
+
+  my @where = (
+    '(cust_bill_pkg.pkgnum != 0 OR feepart IS NOT NULL)',
+    $self->with_classnum($opt{'classnum'}, $opt{'use_override'}),
+    $self->with_report_option(%opt),
+    $self->in_time_period_and_agent($speriod, $eperiod, $agentnum),
+    $self->with_refnum(%opt),
+    $self->with_cust_classnum(%opt)
+  );
+
+  my $total_sql = "SELECT COALESCE(SUM(cust_bill_pkg_tax_location.amount),0)
+    FROM cust_bill_pkg
+    $cust_bill_pkg_join
+    LEFT JOIN cust_bill_pkg_tax_location 
+      ON (cust_bill_pkg.billpkgnum = cust_bill_pkg_tax_location.taxable_billpkgnum)
+    WHERE " . join(' AND ', grep $_, @where);
+
+  $self->scalar_sql($total_sql);
+}
+
 ##### package churn report #####
 
 =item active_pkg: The number of packages that were active at the start of 
diff --git a/httemplate/graph/cust_bill_pkg.cgi b/httemplate/graph/cust_bill_pkg.cgi
index b5486f4..83eb0e8 100644
--- a/httemplate/graph/cust_bill_pkg.cgi
+++ b/httemplate/graph/cust_bill_pkg.cgi
@@ -1,5 +1,4 @@
 <% include('elements/monthly.html',
-   #Dumper(
                 'title'        => $title,
                 'graph_type'   => $graph_type,
                 'items'        => \@items,
@@ -28,6 +27,7 @@ my $bottom_link = "$link;";
 my $use_usage = $cgi->param('use_usage') || 0;
 my $use_setup = $cgi->param('use_setup') || 0;
 my $use_discount = $cgi->param('use_discount') || 2;
+my $use_taxes = $cgi->param('use_taxes') || 0;
 
 my $use_override         = $cgi->param('use_override')         ? 1 : 0;
 my $average_per_cust_pkg = $cgi->param('average_per_cust_pkg') ? 1 : 0;
@@ -50,6 +50,7 @@ my %charge_labels = (
   'R'  => 'recurring',
   'U'  => 'usage',
   'D'  => 'discount',
+  'T'  => 'taxes',
 );
 
 #XXX or virtual
@@ -194,8 +195,14 @@ if ( $use_discount == 1 ) {
   push @components, 'D';
 } # else leave discounts off entirely; never combine them with setup/recur
 
+# could in theory combine with setup/recur/usage,
+# but would require reverse engineering the tax calculation
+if ( $use_taxes == 1 ) {
+  push @components, 'T';
+} 
+
 # Categorization of line items goes
-# Agent -> Referral -> Package class -> Component (setup/recur/usage)
+# Agent -> Referral -> Package class -> Component (setup/recur/usage/discount/taxes)
 # If per-agent totals are enabled, they go under the Agent level.
 # There aren't any other kinds of subtotals.
 
@@ -255,6 +262,8 @@ foreach my $agent ( $all_agent || $sel_agent || $FS::CurrentUser::CurrentUser->a
         if ( $component eq 'D' ) {
           # discounts ignore 'charges' and 'distribute'
           $row_link = "${p}search/cust_bill_pkg_discount.html?";
+        } elsif ( $component eq 'T' ) {
+          $row_link = "${p}search/cust_bill_pkg.cgi?istax=1;";
         }
 
         $row_link .=  ($all_agent ? '' : "agentnum=$row_agentnum;").
@@ -314,6 +323,8 @@ foreach my $agent ( $all_agent || $sel_agent || $FS::CurrentUser::CurrentUser->a
           if ( $component eq 'D' ) {
             # discounts ignore 'charges' and 'distribute'
             $row_link ="${p}search/cust_bill_pkg_discount.html?";
+          } elsif ( $component eq 'T' ) {
+            $row_link = "${p}search/cust_bill_pkg.cgi?istax=1;";
           }
 
           $row_link .= ($all_agent ? '' : "agentnum=$row_agentnum;").
@@ -386,9 +397,8 @@ foreach my $agent ( $all_agent || $sel_agent || $FS::CurrentUser::CurrentUser->a
 
   $anum++;
 
-}
+} # foreach $agent
 
-#use Data::Dumper;
 if ( $cgi->param('debug') == 1 ) {
   $FS::Report::Table::DEBUG = 1;
 }
diff --git a/httemplate/graph/report_cust_bill_pkg.html b/httemplate/graph/report_cust_bill_pkg.html
index e996714..9a212a3 100644
--- a/httemplate/graph/report_cust_bill_pkg.html
+++ b/httemplate/graph/report_cust_bill_pkg.html
@@ -165,7 +165,6 @@ window.onload = class_mode_changed;
 
 </TR>
 
-
 <TR>
   <TH CLASS="background" COLSPAN=2> </TH>
 </TR>
@@ -196,6 +195,12 @@ window.onload = class_mode_changed;
     'options' => [ 2, 1 ], # 3.x only: make 2 the default
     'labels'  => { 1 => 'Separate', 2 => 'Do not show' },
 &>
+<& /elements/tr-select.html,
+    'label'   => 'Taxes',
+    'field'   => 'use_taxes',
+    'options' => [ 1, 2 ],
+    'labels'  => { 1 => 'Separate', 2 => 'Do not show' },
+&>
 
 <TR>
   <TD ALIGN="right">Colors</TD>
diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi
index a542403..53ef6b4 100644
--- a/httemplate/search/cust_bill_pkg.cgi
+++ b/httemplate/search/cust_bill_pkg.cgi
@@ -629,18 +629,6 @@ if ( $cgi->param('nottax') ) {
     }
   }
 
-  # classnum (of underlying package)
-  # not specified: all classes
-  # 0: empty class
-  # N: classnum
-  if ( grep { $_ eq 'classnum' } $cgi->param ) {
-    my @classnums = grep /^\d+$/, $cgi->param('classnum');
-    push @where, "COALESCE(part_fee.classnum, $part_pkg.classnum, 0) IN ( ".
-                     join(',', @classnums ).
-                 ' )'
-      if @classnums;
-  }
-
 } # nottax / istax
 
 

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/Report/Table.pm                      |   32 +++-
 FS/FS/Report/Tax.pm                        |   43 ++++--
 httemplate/graph/cust_bill_pkg.cgi         |   18 ++-
 httemplate/graph/report_cust_bill_pkg.html |    7 +-
 httemplate/search/cust_bill_pkg.cgi        |  228 ++++++++++++----------------
 httemplate/search/report_tax-xls.cgi       |    9 +-
 httemplate/search/report_tax.cgi           |   21 ++-
 7 files changed, 198 insertions(+), 160 deletions(-)




More information about the freeside-commits mailing list