+=item states_hash COUNTRY
+
+Returns a list of key/value pairs containing state (or other sub-country
+division) abbriviations and names.
+
+=cut
+
+use FS::Record qw(qsearch);
+use Locale::SubCountry;
+
+sub states_hash {
+ my($country) = @_;
+
+ my @states =
+# sort
+ map { s/[\n\r]//g; $_; }
+ map { $_->state; }
+ qsearch({
+ 'select' => 'state',
+ 'table' => 'cust_main_county',
+ 'hashref' => { 'country' => $country },
+ 'extra_sql' => 'GROUP BY state',
+ });
+
+ #it could throw a fatal "Invalid country code" error (for example "AX")
+ my $subcountry = eval { new Locale::SubCountry($country) }
+ or return ( '', '(n/a)' );
+
+ #"i see your schwartz is as big as mine!"
+ map { ( $_->[0] => $_->[1] ) }
+ sort { $a->[1] cmp $b->[1] }
+ map { [ $_ => state_label($_, $subcountry) ] }
+ @states;
+}
+
+=item counties STATE COUNTRY
+
+Returns a list of counties for this state and country.
+
+=cut
+
+sub counties {
+ my( $state, $country ) = @_;
+
+ sort map { s/[\n\r]//g; $_; }
+ map { $_->county }
+ qsearch({
+ 'select' => 'DISTINCT county',
+ 'table' => 'cust_main_county',
+ 'hashref' => { 'state' => $state,
+ 'country' => $country,
+ },
+ });
+}
+
+=item state_label STATE COUNTRY_OR_LOCALE_SUBCOUNRY_OBJECT
+
+=cut
+
+sub state_label {
+ my( $state, $country ) = @_;
+
+ unless ( ref($country) ) {
+ $country = eval { new Locale::SubCountry($country) }
+ or return'(n/a)';
+
+ }
+
+ # US kludge to avoid changing existing behaviour
+ # also we actually *use* the abbriviations...
+ my $full_name = $country->country_code eq 'US'
+ ? ''
+ : $country->full_name($state);
+
+ $full_name = '' if $full_name eq 'unknown';
+ $full_name =~ s/\(see also.*\)\s*$//;
+ $full_name .= " ($state)" if $full_name;
+
+ $full_name || $state || '(n/a)';
+
+}
+
+=item card_types
+
+Returns a hash reference of the accepted credit card types. Keys are shorter
+identifiers and values are the longer strings used by the system (see
+L<Business::CreditCard>).
+
+=cut
+
+#$conf from above
+
+sub card_types {
+ my $conf = new FS::Conf;
+
+ my %card_types = (
+ #displayname #value (Business::CreditCard)
+ "VISA" => "VISA card",
+ "MasterCard" => "MasterCard",
+ "Discover" => "Discover card",
+ "American Express" => "American Express card",
+ "Diner's Club/Carte Blanche" => "Diner's Club/Carte Blanche",
+ "enRoute" => "enRoute",
+ "JCB" => "JCB",
+ "BankCard" => "BankCard",
+ "Switch" => "Switch",
+ "Solo" => "Solo",
+ );
+ my @conf_card_types = grep { ! /^\s*$/ } $conf->config('card-types');
+ if ( @conf_card_types ) {
+ #perhaps the hash is backwards for this, but this way works better for
+ #usage in selfservice
+ %card_types = map { $_ => $card_types{$_} }
+ grep {
+ my $d = $_;
+ grep { $card_types{$d} eq $_ } @conf_card_types
+ }
+ keys %card_types;
+ }
+
+ \%card_types;
+}
+
+=back
+