[freeside-commits] branch master updated. 7a33cb6e4c3e33b7399d6574cbd3ee38ddcba5e0

Mark Wells mark at 420.am
Wed Dec 7 15:29:40 PST 2016


The branch, master has been updated
       via  7a33cb6e4c3e33b7399d6574cbd3ee38ddcba5e0 (commit)
      from  ecd038f7ae5c1ffc929f3c928ecd161eeb45d9be (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 7a33cb6e4c3e33b7399d6574cbd3ee38ddcba5e0
Author: Mark Wells <mark at freeside.biz>
Date:   Wed Dec 7 15:27:49 2016 -0800

    specify Avalara tax product for per-line taxes, #73063

diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index f8b82f4..0e41b1a 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -3248,6 +3248,7 @@ sub tables_hashref {
         'adjourn_months', 'int',    'NULL', '', '', '',
         'contract_end_months','int','NULL', '', '', '',
         'change_to_pkgpart', 'int', 'NULL', '', '', '',
+        'units_taxproductnum','int','NULL', '', '', '',
       ],
       'primary_key'  => 'pkgpart',
       'unique'       => [],
@@ -3265,6 +3266,10 @@ sub tables_hashref {
                           { columns    => [ 'taxproductnum' ],
                             table      => 'part_pkg_taxproduct',
                           },
+                          { columns    => [ 'units_taxproductnum' ],
+                            table      => 'part_pkg_taxproduct',
+                            references => [ 'taxproductnum' ],
+                          },
                           { columns    => [ 'agentnum' ],
                             table      => 'agent',
                           },
diff --git a/FS/FS/TaxEngine/billsoft.pm b/FS/FS/TaxEngine/billsoft.pm
index 69717a2..9147f5c 100644
--- a/FS/FS/TaxEngine/billsoft.pm
+++ b/FS/FS/TaxEngine/billsoft.pm
@@ -188,8 +188,7 @@ sub create_batch {
     # cache some things
     my (%cust_pkg, %part_pkg, %cust_location, %classname);
     # keys are transaction codes (the first part of the taxproduct string)
-    # and then locationnums; for per-location taxes
-    my %sales;
+    my %all_tcodes;
 
     my @options = $self->conf->config('billsoft-taxconfig');
     
@@ -239,8 +238,7 @@ sub create_batch {
 
         my $taxproduct = $self->part_pkg_taxproduct($part_pkg, $classnum)
           or next;
-        my $tcode = substr($taxproduct, 0, 6);
-        my $scode = substr($taxproduct, 6, 6);
+        my ($tcode, $scode) = split(':', $taxproduct);
 
         # For CDRs, use the call termination site rather than setting
         # Termination fields to the service address.
@@ -259,9 +257,6 @@ sub create_batch {
 
       } # while $cdr = $cdr_search->fetch
       
-      my $recur_tcode;
-      # now write lines for the non-CDR portion of the charges
-
       my $locationnum = $cust_pkg->locationnum;
 
       # use termination address for the service location
@@ -284,13 +279,10 @@ sub create_batch {
         my $taxproduct = $self->part_pkg_taxproduct($part_pkg, $_);
         next unless $taxproduct;
 
-        my $tcode = substr($taxproduct, 0, 6);
-        my $scode = substr($taxproduct, 6, 6);
-        $sales{$tcode} ||= 0;
-        $recur_tcode = $tcode if $_ eq 'recur';
+        my ($tcode, $scode) = split(':', $taxproduct);
+        $all_tcodes{$tcode} ||= 1;
 
         my $price = $cust_bill_pkg->get($_);
-        $sales{$tcode} += $price;
 
         $price -= $usage_total if $_ eq 'recur';
 
@@ -305,10 +297,9 @@ sub create_batch {
 
       } # foreach (setup, recur)
 
-      # S-code 21: taxes based on number of lines (E911, mostly)
-      # voip_cdr and voip_inbound packages know how to report this.  Not all 
-      # T-codes are eligible for this; only report it if the /21 taxproduct
-      # exists.
+      # taxes based on number of lines (E911, mostly)
+      # mostly S-code 21 but can be others, as they want to know about
+      # Centrex trunks, PBX extensions, etc.
       #
       # (note: the nomenclature of "service" and "transaction" codes is 
       # backward from the way most people would use the terms.  you'd think
@@ -318,25 +309,18 @@ sub create_batch {
       # to avoid confusion.)
 
       # XXX cache me
-      # XXX this isn't precisely correct. Local exchange service on
-      # high-capacity trunks, Centrex, and PBX trunks are supposed to be
-      # reported as three separate implicit transactions: number of trunks,
-      # of outbound channels, of extensions.
-      # This is also true for VoIP PBX trunks. Come back to this.
-      if ( $recur_tcode ) {
-        my $lines_taxproduct = FS::part_pkg_taxproduct->count(
-          'data_vendor = \'billsoft\' and taxproduct = ?',
-          sprintf('%06d%06d', $recur_tcode, 21)
-        );
+      if ( my $lines_taxproduct = $part_pkg->units_taxproduct ) {
         my $lines = $cust_bill_pkg->units;
-
-        if ( $lines_taxproduct and $lines ) {
+        my $taxproduct = $lines_taxproduct->taxproduct;
+        my ($tcode, $scode) = split(':', $taxproduct);
+        $all_tcodes{$tcode} ||= 1;
+        if ( $lines ) {
           $csv->print_hr($fh, {
             %pkg_properties,
             %termination,
             RequestType       => 'CalcTaxes',
-            TransactionType   => $recur_tcode,
-            ServiceType       => 21,
+            TransactionType   => $tcode,
+            ServiceType       => $scode,
             Charge            => 0,
             Lines             => $lines,
           } );
@@ -345,12 +329,16 @@ sub create_batch {
 
     } # foreach my $cust_bill_pkg
 
-    foreach my $tcode (keys %sales) {
+    foreach my $tcode (keys %all_tcodes) {
 
-      # S-code 43: per-invoice tax (apparently this is a thing)
+      # S-code 43: per-invoice tax
+      # XXX not exactly correct; there's "Invoice Bundle" (7:94) and
+      # "Centrex Invoice" (7:623). Local Exchange service would benefit from
+      # more high-level selection of the tax properties. (Infer from the FCC
+      # reporting options?)
       my $invoice_taxproduct = FS::part_pkg_taxproduct->count(
         'data_vendor = \'billsoft\' and taxproduct = ?',
-        sprintf('%06d%06d', $tcode, 43)
+        $tcode . ':43'
       );
       if ( $invoice_taxproduct ) {
         $csv->print_hr($fh, {
diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm
index 35f178e..ae63487 100644
--- a/FS/FS/part_pkg.pm
+++ b/FS/FS/part_pkg.pm
@@ -735,6 +735,7 @@ sub check {
     || $self->ut_floatn('pay_weight')
     || $self->ut_floatn('credit_weight')
     || $self->ut_numbern('taxproductnum')
+    || $self->ut_numbern('units_taxproductnum')
     || $self->ut_foreign_keyn('classnum',       'pkg_class', 'classnum')
     || $self->ut_foreign_keyn('addon_classnum', 'pkg_class', 'classnum')
     || $self->ut_foreign_keyn('taxproductnum',
@@ -1731,6 +1732,19 @@ sub taxproduct_description {
   $part_pkg_taxproduct ? $part_pkg_taxproduct->description : '';
 }
 
+=item units_taxproduct
+
+Returns the L<FS::part_pkg_taxproduct> record used to report the taxable
+service units (usually phone lines) on this package.
+
+=cut
+
+sub units_taxproduct {
+  my $self = shift;
+  $self->units_taxproductnum
+    ? FS::part_pkg_taxproduct->by_key($self->units_taxproductnum)
+    : '';
+}
 
 =item tax_rates DATA_PROVIDER, GEOCODE, [ CLASS ]
 
diff --git a/FS/FS/part_pkg_taxproduct.pm b/FS/FS/part_pkg_taxproduct.pm
index e86d028..51bc37f 100644
--- a/FS/FS/part_pkg_taxproduct.pm
+++ b/FS/FS/part_pkg_taxproduct.pm
@@ -223,7 +223,8 @@ sub batch_import {
   
   my $imported = 0;
   my $csv = Text::CSV_XS->new;
-  # fields: taxproduct, description
+  my $error;
+  # for importing the "transervdesc.txt" file
   while ( my $row = $csv->getline($fh) ) {
     if (!defined $row) {
       $dbh->rollback if $oldAutoCommit;
@@ -236,15 +237,32 @@ sub batch_import {
       );
     }
 
-    my $new = FS::part_pkg_taxproduct->new({
-        'data_vendor' => 'billsoft',
-        'taxproduct'  => $row->[0],
-        'description' => $row->[1],
+    # columns 0-2: irrelevant here
+    my $taxproduct = $row->[3] . ':' . $row->[5];
+    my $description = $row->[4];
+    $description =~ s/\s+$//;
+    $description .= ':' . $row->[6];
+    $description =~ s/\s+$//;
+    my $ppt = qsearchs('part_pkg_taxproduct', {
+      'data_vendor' => 'billsoft',
+      'taxproduct'  => $taxproduct
     });
-    my $error = $new->insert;
+    if ( $ppt ) {
+      $ppt->set('description', $description);
+      $ppt->set('note', $row->[7]);
+      $error = $ppt->replace;
+    } else {
+      $ppt = FS::part_pkg_taxproduct->new({
+          'data_vendor' => 'billsoft',
+          'taxproduct'  => $taxproduct,
+          'description' => $description,
+          'note'        => $row->[7],
+      });
+      $error = $ppt->insert;
+    }
     if ( $error ) {
       $dbh->rollback if $oldAutoCommit;
-      return "error inserting part_pkg_taxproduct: $error\n";
+      return "error inserting part_pkg_taxproduct $taxproduct: $error\n";
     }
     $imported++;
   }
diff --git a/httemplate/browse/part_pkg.cgi b/httemplate/browse/part_pkg.cgi
index acc3211..8c51b35 100755
--- a/httemplate/browse/part_pkg.cgi
+++ b/httemplate/browse/part_pkg.cgi
@@ -601,12 +601,18 @@ if ( $taxclasses ) {
         { 'data'  => &$taxproduct_sub($base_ppt), 'align' => 'right' },
       ];
     }
+    if ( my $units_ppt = $part_pkg->units_taxproduct ) {
+      push @$out, [
+        { 'data'  => emt('Lines'), 'align' => 'left' },
+        { 'data'  => &$taxproduct_sub($units_ppt), 'align' => 'right' },
+      ];
+    }
     for (my $i = 0; $i < scalar @classnums; $i++) {
       my $num = $part_pkg->option('usage_taxproductnum_' . $classnums[$i]);
       next if !$num;
       my $ppt = FS::part_pkg_taxproduct->by_key($num);
       push @$out, [
-        { 'data'  => $classnames[$i] . ': ', 'align' => 'left', },
+        { 'data'  => $classnames[$i], 'align' => 'left', },
         { 'data'  => &$taxproduct_sub($ppt), 'align' => 'right' },
       ];
     }
diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi
index 64a7525..84aac5b 100755
--- a/httemplate/edit/part_pkg.cgi
+++ b/httemplate/edit/part_pkg.cgi
@@ -40,7 +40,6 @@
                    'setuptax'         => 'Setup fee tax exempt',
                    'recurtax'         => 'Recurring fee tax exempt',
                    'taxclass'         => 'Tax class',
-                   'taxproduct_select'=> 'Tax products',
                    'plan'             => 'Price plan',
                    'disabled'         => 'Disable new orders',
                    'disable_line_item_date_ranges' => 'Disable line item date ranges',
@@ -73,6 +72,7 @@
                    'contract_end_months' => 'Contract ends after ',
                    'expire_months'    => 'Cancel the package after ',
                    'change_to_pkgpart'=> 'and replace it with ',
+                   'units_taxproductnum' => 'Per-line tax product',
                  },
 
      'fields' => [
@@ -214,28 +214,15 @@
                        type  => 'hidden',
                        value => join(',', @taxproductnums),
                      },
-                     #{ field => 'taxproduct_select',
-                     #  type  => 'selectlayers',
-                     #  options => [ '(default)', @taxproductnums ],
-                     #  curr_value => '(default)',
-                     #  labels  => { ( '(default)' => '(default)' ),
-                     #               map {($_=>$usage_class{$_})}
-                     #               @taxproductnums
-                     #             },
-                     #  layer_fields => \%taxproduct_fields,
-                     #  layer_values_callback => $taxproduct_values,
-                     #  layers_only  =>   !$taxproducts,
-                     #  cell_style   => ( !$taxproducts
-                     #                    ? 'display:none'
-                     #                    : ''
-                     #                  ),
-                     #},
                      { field => 'taxproductnum',
                        type  => 'part_pkg-taxproducts',
                        include_opt_callback =>
                          sub { pkgpart => $_[0]->pkgpart },
                      },
-
+                     { field => 'units_taxproductnum',
+                       type  => ($tax_data_vendor ?
+                                  'select-taxproduct' : 'hidden'),
+                     },
                      { type  => 'tablebreak-tr-title',
                        value => 'Promotions', #better name?
                      },
@@ -445,7 +432,7 @@ my $agent_clone_extra_sql =
   ' ) ';
 
 my $conf = new FS::Conf;
-my $taxproducts = $conf->config('tax_data_vendor') ne '';
+my $tax_data_vendor = $conf->config('tax_data_vendor');
 
 my $fcc_opts = $conf->exists('part_pkg-show_fcc_options');
 
@@ -1112,13 +1099,8 @@ my $html_bottom = sub {
   my $return =
     include('/elements/selectlayers.html', %selectlayers, 'layers_only'=>1 ).
     '<SCRIPT TYPE="text/javascript">'.
-      include('/elements/selectlayers.html', %selectlayers, 'js_only'=>1 );
-
-#  $return .=
-#    "taxproduct_selectchanged(document.getElementById('taxproduct_select'));\n"
-#      if $taxproducts;
-
-  $return .= '</SCRIPT>';
+      include('/elements/selectlayers.html', %selectlayers, 'js_only'=>1 ) .
+    '</SCRIPT>';
 
   $return;
 
@@ -1199,16 +1181,8 @@ my $field_callback = sub {
   my $field = $fieldref->{field};
   if ($field eq 'taxproductnums') {
     $fieldref->{value} = join(',', @taxproductnums);
-  } elsif ($field eq 'taxproduct_select') {
-    $fieldref->{options} = [ '(default)', @taxproductnums ];
-    $fieldref->{labels}  = { ( '(default)' => '(default)' ),
-                             map {( $_ => ($usage_class{$_} || $_) )}
-                               @taxproductnums
-                           };
-    $fieldref->{layer_fields} = \%taxproduct_fields;
-    $fieldref->{layer_values_callback} = $taxproduct_values;
   } elsif ($field eq 'taxproductnum') { # part_pkg-taxproduct, new style
-    if ( !$taxproducts ) {
+    if ( !$tax_data_vendor ) {
       # then make the widget go away
       $fieldref->{type} = 'hidden';
     }
diff --git a/httemplate/elements/tr-part_pkg-taxproducts.html b/httemplate/elements/tr-part_pkg-taxproducts.html
index 5dcea09..50dace7 100644
--- a/httemplate/elements/tr-part_pkg-taxproducts.html
+++ b/httemplate/elements/tr-part_pkg-taxproducts.html
@@ -54,7 +54,8 @@ my %pkg_options;
 if ($pkgpart) {
   my $part_pkg = FS::part_pkg->by_key($pkgpart);
   %pkg_options = $part_pkg->options;
-  $curr_values{''} = $part_pkg->taxproductnum;
+  $curr_values{''} =   $cgi->param('taxproductnum')
+                    || $part_pkg->taxproductnum;
 }
 
 foreach my $usage_class (@classes) {
@@ -66,4 +67,5 @@ foreach my $usage_class (@classes) {
   $curr_values{$classnum} = $curr_value;
   $separate = 1 if ( length($classnum) and length($curr_value) );
 }
+
 </%init>

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

Summary of changes:
 FS/FS/Schema.pm                                  |    5 ++
 FS/FS/TaxEngine/billsoft.pm                      |   54 +++++++++-------------
 FS/FS/part_pkg.pm                                |   14 ++++++
 FS/FS/part_pkg_taxproduct.pm                     |   32 ++++++++++---
 httemplate/browse/part_pkg.cgi                   |    8 +++-
 httemplate/edit/part_pkg.cgi                     |   44 ++++--------------
 httemplate/elements/tr-part_pkg-taxproducts.html |    4 +-
 7 files changed, 84 insertions(+), 77 deletions(-)




More information about the freeside-commits mailing list