1 package FS::cust_main_county;
4 use vars qw( @ISA @EXPORT_OK $conf
5 @cust_main_county %cust_main_county $countyflag );
7 use FS::Record qw( qsearch dbh );
9 @ISA = qw( FS::Record );
10 @EXPORT_OK = qw( regionselector );
12 @cust_main_county = ();
15 #ask FS::UID to run this stuff for us later
16 $FS::UID::callback{'FS::cust_main_county'} = sub {
22 FS::cust_main_county - Object methods for cust_main_county objects
26 use FS::cust_main_county;
28 $record = new FS::cust_main_county \%hash;
29 $record = new FS::cust_main_county { 'column' => 'value' };
31 $error = $record->insert;
33 $error = $new_record->replace($old_record);
35 $error = $record->delete;
37 $error = $record->check;
39 ($county_html, $state_html, $country_html) =
40 FS::cust_main_county::regionselector( $county, $state, $country );
44 An FS::cust_main_county object represents a tax rate, defined by locale.
45 FS::cust_main_county inherits from FS::Record. The following fields are
50 =item taxnum - primary key (assigned automatically for new tax rates)
58 =item tax - percentage
64 =item taxname - if defined, printed on invoices instead of "Tax"
66 =item setuptax - if 'Y', this tax does not apply to setup fees
68 =item recurtax - if 'Y', this tax does not apply to recurring fees
78 Creates a new tax rate. To add the tax rate to the database, see L<"insert">.
82 sub table { 'cust_main_county'; }
86 Adds this tax rate to the database. If there is an error, returns the error,
87 otherwise returns false.
91 Deletes this tax rate from the database. If there is an error, returns the
92 error, otherwise returns false.
94 =item replace OLD_RECORD
96 Replaces the OLD_RECORD with this one in the database. If there is an error,
97 returns the error, otherwise returns false.
101 Checks all fields to make sure this is a valid tax rate. If there is an error,
102 returns the error, otherwise returns false. Called by the insert and replace
110 $self->exempt_amount(0) unless $self->exempt_amount;
112 $self->ut_numbern('taxnum')
113 || $self->ut_anything('state')
114 || $self->ut_textn('county')
115 || $self->ut_text('country')
116 || $self->ut_float('tax')
117 || $self->ut_textn('taxclass') # ...
118 || $self->ut_money('exempt_amount')
119 || $self->ut_textn('taxname')
120 || $self->ut_enum('setuptax', [ '', 'Y' ] )
121 || $self->ut_enum('recurtax', [ '', 'Y' ] )
122 || $self->SUPER::check
129 if ( $self->dbdef_table->column('taxname') ) {
130 return $self->setfield('taxname', $_[0]) if @_;
131 return $self->getfield('taxname');
138 if ( $self->dbdef_table->column('setuptax') ) {
139 return $self->setfield('setuptax', $_[0]) if @_;
140 return $self->getfield('setuptax');
147 if ( $self->dbdef_table->column('recurtax') ) {
148 return $self->setfield('recurtax', $_[0]) if @_;
149 return $self->getfield('recurtax');
154 =item sql_taxclass_sameregion
156 Returns an SQL WHERE fragment or the empty string to search for entries
157 with different tax classes.
161 #hmm, description above could be better...
163 sub sql_taxclass_sameregion {
166 my $same_query = 'SELECT taxclass FROM cust_main_county '.
167 ' WHERE taxnum != ? AND country = ?';
168 my @same_param = ( 'taxnum', 'country' );
169 foreach my $opt_field (qw( state county )) {
170 if ( $self->$opt_field() ) {
171 $same_query .= " AND $opt_field = ?";
172 push @same_param, $opt_field;
174 $same_query .= " AND $opt_field IS NULL";
178 my @taxclasses = $self->_list_sql( \@same_param, $same_query );
180 return '' unless scalar(@taxclasses);
182 '( taxclass IS NULL OR ( '. #only if !$self->taxclass ??
183 join(' AND ', map { 'taxclass != '.dbh->quote($_) } @taxclasses ).
188 my( $self, $param, $sql ) = @_;
189 my $sth = dbh->prepare($sql) or die dbh->errstr;
190 $sth->execute( map $self->$_(), @$param )
191 or die "Unexpected error executing statement $sql: ". $sth->errstr;
192 map $_->[0], @{ $sth->fetchall_arrayref };
201 =item regionselector [ COUNTY STATE COUNTRY [ PREFIX [ ONCHANGE [ DISABLED ] ] ] ]
206 my ( $selected_county, $selected_state, $selected_country,
207 $prefix, $onchange, $disabled ) = @_;
209 $prefix = '' unless defined $prefix;
213 # unless ( @cust_main_county ) { #cache
214 @cust_main_county = qsearch('cust_main_county', {} );
215 foreach my $c ( @cust_main_county ) {
216 $countyflag=1 if $c->county;
217 #push @{$cust_main_county{$c->country}{$c->state}}, $c->county;
218 $cust_main_county{$c->country}{$c->state}{$c->county} = 1;
221 $countyflag=1 if $selected_county;
223 my $script_html = <<END;
225 function opt(what,value,text) {
226 var optionName = new Option(text, value, false, false);
227 var length = what.length;
228 what.options[length] = optionName;
230 function ${prefix}country_changed(what) {
231 country = what.options[what.selectedIndex].text;
232 for ( var i = what.form.${prefix}state.length; i >= 0; i-- )
233 what.form.${prefix}state.options[i] = null;
235 #what.form.${prefix}state.options[0] = new Option('', '', false, true);
237 foreach my $country ( sort keys %cust_main_county ) {
238 $script_html .= "\nif ( country == \"$country\" ) {\n";
239 foreach my $state ( sort keys %{$cust_main_county{$country}} ) {
240 ( my $dstate = $state ) =~ s/[\n\r]//g;
241 my $text = $dstate || '(n/a)';
242 $script_html .= qq!opt(what.form.${prefix}state, "$dstate", "$text");\n!;
244 $script_html .= "}\n";
247 $script_html .= <<END;
249 function ${prefix}state_changed(what) {
253 $script_html .= <<END;
254 state = what.options[what.selectedIndex].text;
255 country = what.form.${prefix}country.options[what.form.${prefix}country.selectedIndex].text;
256 for ( var i = what.form.${prefix}county.length; i >= 0; i-- )
257 what.form.${prefix}county.options[i] = null;
260 foreach my $country ( sort keys %cust_main_county ) {
261 $script_html .= "\nif ( country == \"$country\" ) {\n";
262 foreach my $state ( sort keys %{$cust_main_county{$country}} ) {
263 $script_html .= "\nif ( state == \"$state\" ) {\n";
264 #foreach my $county ( sort @{$cust_main_county{$country}{$state}} ) {
265 foreach my $county ( sort keys %{$cust_main_county{$country}{$state}} ) {
266 my $text = $county || '(n/a)';
268 qq!opt(what.form.${prefix}county, "$county", "$text");\n!;
270 $script_html .= "}\n";
272 $script_html .= "}\n";
276 $script_html .= <<END;
281 my $county_html = $script_html;
283 $county_html .= qq!<SELECT NAME="${prefix}county" onChange="$onchange" $disabled>!;
284 $county_html .= '</SELECT>';
287 qq!<INPUT TYPE="hidden" NAME="${prefix}county" VALUE="$selected_county">!;
290 my $state_html = qq!<SELECT NAME="${prefix}state" !.
291 qq!onChange="${prefix}state_changed(this); $onchange" $disabled>!;
292 foreach my $state ( sort keys %{ $cust_main_county{$selected_country} } ) {
293 my $text = $state || '(n/a)';
294 my $selected = $state eq $selected_state ? 'SELECTED' : '';
295 $state_html .= qq(\n<OPTION $selected VALUE="$state">$text</OPTION>);
297 $state_html .= '</SELECT>';
299 $state_html .= '</SELECT>';
301 my $country_html = qq!<SELECT NAME="${prefix}country" !.
302 qq!onChange="${prefix}country_changed(this); $onchange" $disabled>!;
303 my $countrydefault = $conf->config('countrydefault') || 'US';
304 foreach my $country (
305 sort { ($b eq $countrydefault) <=> ($a eq $countrydefault) or $a cmp $b }
306 keys %cust_main_county
308 my $selected = $country eq $selected_country ? ' SELECTED' : '';
309 $country_html .= qq(\n<OPTION$selected VALUE="$country">$country</OPTION>");
311 $country_html .= '</SELECT>';
313 ($county_html, $state_html, $country_html);
321 regionselector? putting web ui components in here? they should probably live
326 L<FS::Record>, L<FS::cust_main>, L<FS::cust_bill>, schema.html from the base