X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_main_county.pm;h=796e0c4600570ddc4bab57d801c2a3026edb10d2;hb=4b5d4c82766ef1869d03df63fa1e2f0dd050cb6a;hp=76c982ae8a91b131809833b9af76e290cfa9e48a;hpb=eb9668a6f3181ee02cb335272c5ee4616e61fd09;p=freeside.git diff --git a/FS/FS/cust_main_county.pm b/FS/FS/cust_main_county.pm index 76c982ae8..796e0c460 100644 --- a/FS/FS/cust_main_county.pm +++ b/FS/FS/cust_main_county.pm @@ -4,7 +4,13 @@ use strict; use vars qw( @ISA @EXPORT_OK $conf @cust_main_county %cust_main_county $countyflag ); use Exporter; -use FS::Record qw( qsearch ); +use FS::Record qw( qsearch dbh ); +use FS::cust_bill_pkg; +use FS::cust_bill; +use FS::cust_pkg; +use FS::part_pkg; +use FS::cust_tax_exempt; +use FS::cust_tax_exempt_pkg; @ISA = qw( FS::Record ); @EXPORT_OK = qw( regionselector ); @@ -110,7 +116,7 @@ sub check { $self->exempt_amount(0) unless $self->exempt_amount; $self->ut_numbern('taxnum') - || $self->ut_textn('state') + || $self->ut_anything('state') || $self->ut_textn('county') || $self->ut_text('country') || $self->ut_float('tax') @@ -151,19 +157,193 @@ sub recurtax { return ''; } +=item sql_taxclass_sameregion + +Returns an SQL WHERE fragment or the empty string to search for entries +with different tax classes. + +=cut + +#hmm, description above could be better... + +sub sql_taxclass_sameregion { + my $self = shift; + + my $same_query = 'SELECT taxclass FROM cust_main_county '. + ' WHERE taxnum != ? AND country = ?'; + my @same_param = ( 'taxnum', 'country' ); + foreach my $opt_field (qw( state county )) { + if ( $self->$opt_field() ) { + $same_query .= " AND $opt_field = ?"; + push @same_param, $opt_field; + } else { + $same_query .= " AND $opt_field IS NULL"; + } + } + + my @taxclasses = $self->_list_sql( \@same_param, $same_query ); + + return '' unless scalar(@taxclasses); + + '( taxclass IS NULL OR ( '. #only if !$self->taxclass ?? + join(' AND ', map { 'taxclass != '.dbh->quote($_) } @taxclasses ). + ' ) ) '; +} + +sub _list_sql { + my( $self, $param, $sql ) = @_; + my $sth = dbh->prepare($sql) or die dbh->errstr; + $sth->execute( map $self->$_(), @$param ) + or die "Unexpected error executing statement $sql: ". $sth->errstr; + map $_->[0], @{ $sth->fetchall_arrayref }; +} + +=item taxline CUST_BILL_PKG, ... + +Returns a listref of a name and an amount of tax calculated for the list of +packages. Returns a scalar error message on error. + +=cut + +sub taxline { + my $self = shift; + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $name = $self->taxname || 'Tax'; + my $amount = 0; + + foreach my $cust_bill_pkg (@_) { + + my $cust_bill = $cust_bill_pkg->cust_pkg->cust_bill; + my $part_pkg = $cust_bill_pkg->part_pkg; + + my $taxable_charged = 0; + $taxable_charged += $cust_bill_pkg->setup + unless $part_pkg->setuptax =~ /^Y$/i + || $self->setuptax =~ /^Y$/i; + $taxable_charged += $cust_bill_pkg->recur + unless $part_pkg->recurtax =~ /^Y$/i + || $self->recurtax =~ /^Y$/i; + + return [ $name, 0 ] + unless $taxable_charged; + + if ( $self->exempt_amount && $self->exempt_amount > 0 ) { + #my ($mon,$year) = (localtime($cust_bill_pkg->sdate) )[4,5]; + my ($mon,$year) = + (localtime( $cust_bill_pkg->sdate || $cust_bill->_date ) )[4,5]; + $mon++; + my $freq = $part_pkg->freq || 1; + if ( $freq !~ /(\d+)$/ ) { + $dbh->rollback if $oldAutoCommit; + return "daily/weekly package definitions not (yet?)". + " compatible with monthly tax exemptions"; + } + my $taxable_per_month = + sprintf("%.2f", $taxable_charged / $freq ); + + #call the whole thing off if this customer has any old + #exemption records... + my @cust_tax_exempt = + qsearch( 'cust_tax_exempt' => { custnum=> $cust_bill->custnum } ); + if ( @cust_tax_exempt ) { + $dbh->rollback if $oldAutoCommit; + return + 'this customer still has old-style tax exemption records; '. + 'run bin/fs-migrate-cust_tax_exempt?'; + } + + foreach my $which_month ( 1 .. $freq ) { + + #maintain the new exemption table now + my $sql = " + SELECT SUM(amount) + FROM cust_tax_exempt_pkg + LEFT JOIN cust_bill_pkg USING ( billpkgnum ) + LEFT JOIN cust_bill USING ( invnum ) + WHERE custnum = ? + AND taxnum = ? + AND year = ? + AND month = ? + "; + my $sth = dbh->prepare($sql) or do { + $dbh->rollback if $oldAutoCommit; + return "fatal: can't lookup exising exemption: ". dbh->errstr; + }; + $sth->execute( + $cust_bill->custnum, + $self->taxnum, + 1900+$year, + $mon, + ) or do { + $dbh->rollback if $oldAutoCommit; + return "fatal: can't lookup exising exemption: ". dbh->errstr; + }; + my $existing_exemption = $sth->fetchrow_arrayref->[0] || 0; + + my $remaining_exemption = + $self->exempt_amount - $existing_exemption; + if ( $remaining_exemption > 0 ) { + my $addl = $remaining_exemption > $taxable_per_month + ? $taxable_per_month + : $remaining_exemption; + $taxable_charged -= $addl; + + my $cust_tax_exempt_pkg = new FS::cust_tax_exempt_pkg ( { + 'billpkgnum' => $cust_bill_pkg->billpkgnum, + 'taxnum' => $self->taxnum, + 'year' => 1900+$year, + 'month' => $mon, + 'amount' => sprintf("%.2f", $addl ), + } ); + my $error = $cust_tax_exempt_pkg->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "fatal: can't insert cust_tax_exempt_pkg: $error"; + } + } # if $remaining_exemption > 0 + + #++ + $mon++; + #until ( $mon < 12 ) { $mon -= 12; $year++; } + until ( $mon < 13 ) { $mon -= 12; $year++; } + + } #foreach $which_month + + } #if $tax->exempt_amount + + $taxable_charged = sprintf( "%.2f", $taxable_charged); + + $amount += $taxable_charged * $self->tax / 100 + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + return [ $name, $amount ] +} + =back =head1 SUBROUTINES =over 4 -=item regionselector [ COUNTY STATE COUNTRY [ PREFIX [ ONCHANGE ] ] ] +=item regionselector [ COUNTY STATE COUNTRY [ PREFIX [ ONCHANGE [ DISABLED ] ] ] ] =cut sub regionselector { my ( $selected_county, $selected_state, $selected_country, - $prefix, $onchange ) = @_; + $prefix, $onchange, $disabled ) = @_; $prefix = '' unless defined $prefix; @@ -196,8 +376,9 @@ END foreach my $country ( sort keys %cust_main_county ) { $script_html .= "\nif ( country == \"$country\" ) {\n"; foreach my $state ( sort keys %{$cust_main_county{$country}} ) { - my $text = $state || '(n/a)'; - $script_html .= qq!opt(what.form.${prefix}state, "$state", "$text");\n!; + ( my $dstate = $state ) =~ s/[\n\r]//g; + my $text = $dstate || '(n/a)'; + $script_html .= qq!opt(what.form.${prefix}state, "$dstate", "$text");\n!; } $script_html .= "}\n"; } @@ -238,7 +419,7 @@ END my $county_html = $script_html; if ( $countyflag ) { - $county_html .= qq!!; $county_html .= ''; } else { $county_html .= @@ -246,25 +427,25 @@ END } my $state_html = qq!'; $state_html .= ''; my $country_html = qq!';