From 60724f233fbeb9388f4b2cbb68a4e6297c2b2118 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Sat, 24 Aug 2013 15:43:08 -0700 Subject: [PATCH] CCH taxes with new customer locations, #21485 --- FS/FS/cust_main/Billing.pm | 22 ++++++------------- FS/FS/cust_main/Location.pm | 27 ++++++++++++++++++++++++ FS/FS/cust_main/Search.pm | 4 +++- FS/FS/geocode_Mixin.pm | 17 +++++++++------ FS/FS/tax_rate.pm | 13 ++++++------ bin/test_scrub | 7 ++++++ httemplate/elements/standardize_locations.js | 8 +++---- httemplate/misc/confirm-address_standardize.html | 2 +- 8 files changed, 66 insertions(+), 34 deletions(-) diff --git a/FS/FS/cust_main/Billing.pm b/FS/FS/cust_main/Billing.pm index 081dd70f7..0a364f509 100644 --- a/FS/FS/cust_main/Billing.pm +++ b/FS/FS/cust_main/Billing.pm @@ -1387,6 +1387,8 @@ sub _handle_taxes { local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG; + my $location = $cust_pkg->tax_location; + return if ( $self->payby eq 'COMP' ); #dubious if ( $conf->exists('enable_taxproducts') @@ -1429,7 +1431,7 @@ sub _handle_taxes { } - my %tax_cust_bill_pkg = $cust_bill_pkg->disintegrate; + my %tax_cust_bill_pkg = $cust_bill_pkg->disintegrate; # grrr foreach my $key (keys %tax_cust_bill_pkg) { # $key is "setup", "recur", or a usage class name. ('' is a usage class.) # $tax_cust_bill_pkg{$key} is a cust_bill_pkg for that component of @@ -1444,11 +1446,6 @@ sub _handle_taxes { # this is the tax identifier, not the taxname my $taxname = ref( $tax ). ' '. $tax->taxnum; - $taxname .= ' billpkgnum'. $cust_bill_pkg->billpkgnum; - # We need to create a separate $taxlisthash entry for each billpkgnum - # on the invoice, so that cust_bill_pkg_tax_location records will - # be linked correctly. - # $taxlisthash: keys are "setup", "recur", and usage classes. # Values are arrayrefs, first the tax object (cust_main_county # or tax_rate) and then any cust_bill_pkg objects that the @@ -1468,7 +1465,7 @@ sub _handle_taxes { if $DEBUG > 2; next unless $tax_object->can('tax_on_tax'); - foreach my $tot ( $tax_object->tax_on_tax( $self ) ) { + foreach my $tot ( $tax_object->tax_on_tax( $location ) ) { my $totname = ref( $tot ). ' '. $tot->taxnum; warn "checking $totname which we call ". $tot->taxname. " as applicable\n" @@ -1476,7 +1473,7 @@ sub _handle_taxes { next unless exists( $localtaxlisthash{ $totname } ); # only increase # existing taxes warn "adding $totname to taxed taxes\n" if $DEBUG > 2; - # we're calling taxline() right here? wtf? + # calculate the tax amount that the tax_on_tax will apply to my $hashref_or_error = $tax_object->taxline( $localtaxlisthash{$tax}, 'custnum' => $self->custnum, @@ -1485,6 +1482,7 @@ sub _handle_taxes { return $hashref_or_error unless ref($hashref_or_error); + # and append it to the list of taxable items $taxlisthash->{ $totname } ||= [ $tot ]; push @{ $taxlisthash->{ $totname } }, $hashref_or_error->{amount}; @@ -1500,7 +1498,6 @@ sub _handle_taxes { # because we need to record that fact. my @loc_keys = qw( district city county state country ); - my $location = $cust_pkg->tax_location; my %taxhash = map { $_ => $location->$_ } @loc_keys; $taxhash{'taxclass'} = $part_pkg->taxclass; @@ -1544,12 +1541,7 @@ sub _gather_taxes { local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG; - my $geocode; - if ( $cust_pkg->locationnum && $conf->exists('tax-pkg_address') ) { - $geocode = $cust_pkg->cust_location->geocode('cch'); - } else { - $geocode = $self->geocode('cch'); - } + my $geocode = $cust_pkg->tax_location->geocode('cch'); my @taxes = (); diff --git a/FS/FS/cust_main/Location.pm b/FS/FS/cust_main/Location.pm index 22feaf9c8..5590f8869 100644 --- a/FS/FS/cust_main/Location.pm +++ b/FS/FS/cust_main/Location.pm @@ -124,6 +124,11 @@ sub _upgrade_data { local $DEBUG = 0; my $error; + my $tax_prefix = 'bill_'; + if ( FS::Conf->new->exists('tax-ship_address') ) { + $tax_prefix = 'ship_'; + } + # Step 0: set up contact classes and phone types my $service_contact_class = qsearchs('contact_class', { classname => 'Service'}) @@ -198,6 +203,14 @@ sub _upgrade_data { 'last' => $cust_main->get('ship_last'), 'first' => $cust_main->get('ship_first'), }); + if ( !$cust_main->get('ship_last') or !$cust_main->get('ship_first') ) + { + warn "customer $custnum has no service contact name; substituting ". + "customer name\n"; + $contact->set('last' => $cust_main->get('last')); + $contact->set('first' => $cust_main->get('first')); + } + if ( $unlike{'company'} ) { # there's no contact.company field, but keep a record of it $contact->set(comment => 'Company: '.$cust_main->get('ship_company')); @@ -224,6 +237,20 @@ sub _upgrade_data { $cust_main->set("ship_$_" => '') foreach qw(last first company); } #if %unlike } #if ship_address1 + + # special case: should go with whichever location is used to calculate + # taxes, because that's the one it originally came from + if ( my $geocode = $cust_main->get('geocode') ) { + $bill_location->set('geocode' => ''); + $ship_location->set('geocode' => ''); + + if ( $tax_prefix eq 'bill_' ) { + $bill_location->set('geocode', $geocode); + } elsif ( $tax_prefix eq 'ship_' ) { + $ship_location->set('geocode', $geocode); + } + } + $error = $bill_location->insert; die "error migrating billing address for customer $custnum: $error" if $error; diff --git a/FS/FS/cust_main/Search.pm b/FS/FS/cust_main/Search.pm index b022985a0..f14f897ea 100644 --- a/FS/FS/cust_main/Search.pm +++ b/FS/FS/cust_main/Search.pm @@ -668,7 +668,9 @@ sub search { # parse with hardcoded tax location checkbox ## - push @where, "ship_location.geocode is not null" + my $tax_prefix = FS::Conf->new->exists('tax-ship_location') ? 'ship_' + : 'bill_'; + push @where, "${tax_prefix}location.geocode is not null" if $params->{'with_geocode'}; ## diff --git a/FS/FS/geocode_Mixin.pm b/FS/FS/geocode_Mixin.pm index 29491db61..57d8ca0e8 100644 --- a/FS/FS/geocode_Mixin.pm +++ b/FS/FS/geocode_Mixin.pm @@ -186,12 +186,17 @@ sub geocode { my $geocode = $self->get('geocode'); #XXX only one data_vendor for geocode return $geocode if $geocode; - my $prefix = - ( FS::Conf->new->exists('tax-ship_address') && $self->has_ship_address ) - ? 'ship_' - : ''; + if ( $self->isa('FS::cust_main') ) { + warn "WARNING: FS::cust_main->geocode deprecated"; + + # do the best we can + my $m = FS::Conf->new->exists('tax-ship_address') ? 'ship_location' + : 'bill_location'; + my $location = $self->$m or return ''; + return $location->geocode($data_vendor); + } - my($zip,$plus4) = split /-/, $self->get("${prefix}zip") + my($zip,$plus4) = split /-/, $self->get('zip') if $self->country eq 'US'; $zip ||= ''; @@ -212,7 +217,7 @@ sub geocode { if scalar(@cust_tax_location); warn "WARNING: customer ". $self->custnum. - ": multiple locations for zip ". $self->get("${prefix}zip"). + ": multiple locations for zip ". $self->get("zip"). "; using arbitrary geocode $geocode\n" if scalar(@cust_tax_location) > 1; diff --git a/FS/FS/tax_rate.pm b/FS/FS/tax_rate.pm index 342c7cb0b..095939f9a 100644 --- a/FS/FS/tax_rate.pm +++ b/FS/FS/tax_rate.pm @@ -514,10 +514,10 @@ sub _fatal_or_null { } } -=item tax_on_tax CUST_MAIN +=item tax_on_tax CUST_LOCATION Returns a list of taxes which are candidates for taxing taxes for the -given customer (see L) +given service location (see L) =cut @@ -525,13 +525,13 @@ given customer (see L) sub tax_on_tax { #akshun my $self = shift; - my $cust_main = shift; + my $cust_location = shift; warn "looking up taxes on tax ". $self->taxnum. " for customer ". - $cust_main->custnum + $cust_location->custnum if $DEBUG; - my $geocode = $cust_main->geocode($self->data_vendor); + my $geocode = $cust_location->geocode($self->data_vendor); # CCH oddness in m2m my $dbh = dbh; @@ -2120,8 +2120,7 @@ EOF =head1 SEE ALSO -L, L, L, schema.html from the base -documentation. +L, L, L =cut diff --git a/bin/test_scrub b/bin/test_scrub index 88edc335b..45a257ab9 100644 --- a/bin/test_scrub +++ b/bin/test_scrub @@ -42,10 +42,17 @@ my $dsth = dbh->prepare("DELETE FROM cust_main_invoice WHERE dest != 'POST'") or die dbh->errstr; $dsth->execute or die $dsth->errstr; +my $sth = dbh->prepare("UPDATE part_event SET disabled = 'Y'"); +$sth->execute or die $sth->errstr; + my $conf = new FS::Conf; foreach my $item (qw( business-onlinepayment business-onlinepayment-ach + dump-localdest + dump-scpdest + cust_bill-ftp_spool + smtpmachine )) { $conf->delete($item); } diff --git a/httemplate/elements/standardize_locations.js b/httemplate/elements/standardize_locations.js index d7c36701e..ad774d897 100644 --- a/httemplate/elements/standardize_locations.js +++ b/httemplate/elements/standardize_locations.js @@ -207,7 +207,7 @@ function post_standardization() { var country_el = cf.elements['<% $taxpre %>country']; var country = country_el.options[ country_el.selectedIndex ].value; - var geocode = cf.elements['bill_geocode'].value; + var geocode = cf.elements['<% $taxpre %>geocode'].value; if ( country == 'CA' || country == 'US' ) { @@ -229,14 +229,14 @@ function post_standardization() { } else { - cf.elements['bill_geocode'].value = 'DEFAULT'; + cf.elements['<% $taxpre %>geocode'].value = 'DEFAULT'; <% $post_geocode %>; } } else { - cf.elements['bill_geocode'].value = ''; + cf.elements['<% $taxpre %>geocode'].value = ''; <% $post_geocode %>; } @@ -261,7 +261,7 @@ function update_geocode() { cf.elements['<% $taxpre %>city'].value = argsHash['city']; setselect(cf.elements['<% $taxpre %>state'], argsHash['state']); cf.elements['<% $taxpre %>zip'].value = argsHash['zip']; - cf.elements['bill_geocode'].value = argsHash['geocode']; + cf.elements['<% $taxpre %>geocode'].value = argsHash['geocode']; <% $post_geocode %>; } diff --git a/httemplate/misc/confirm-address_standardize.html b/httemplate/misc/confirm-address_standardize.html index 420e8ea1d..33d22195b 100644 --- a/httemplate/misc/confirm-address_standardize.html +++ b/httemplate/misc/confirm-address_standardize.html @@ -103,7 +103,7 @@ Confirm address standardization % else { - -- 2.11.0