72225: OQH - Mandatory Fields on Customer Creation [v3]
[freeside.git] / FS / FS / GeocodeCache.pm
1 package FS::GeocodeCache;
2
3 use strict;
4 use vars qw($conf $DEBUG);
5 use base qw( FS::geocode_Mixin );
6 use FS::Record qw( qsearch qsearchs );
7 use FS::Conf;
8 use FS::Misc::Geo;
9
10 use Data::Dumper;
11
12 FS::UID->install_callback( sub { $conf = new FS::Conf; } );
13
14 $DEBUG = 0;
15
16 =head1 NAME
17
18 FS::GeocodeCache - An address undergoing the geocode process.
19
20 =head1 SYNOPSIS
21
22   use FS::GeocodeCache;
23
24   $record = FS::GeocodeCache->standardize(%location_hash);
25
26 =head1 DESCRIPTION
27
28 An FS::GeocodeCache object represents a street address in the process of 
29 being geocoded.  FS::GeocodeCache inherits from FS::geocode_Mixin.
30
31 Most methods on this object throw an exception on error.
32
33 FS::GeocodeCache has the following fields, with the same meaning as in 
34 L<FS::cust_location>:
35
36 =over 4
37
38 =item address1
39
40 =item address2
41
42 =item city
43
44 =item county
45
46 =item state
47
48 =item zip
49
50 =item latitude
51
52 =item longitude
53
54 =item addr_clean
55
56 =item country
57
58 =item censustract
59
60 =item geocode
61
62 =item district
63
64 =back
65
66 =head1 METHODS
67
68 =over 4
69
70 =item new HASHREF
71
72 Creates a new cache object.  For internal use.  See C<standardize>.
73
74 =cut
75
76 # minimalist constructor
77 sub new {
78   my $class = shift;
79   my $self = {
80     company     => '',
81     address1    => '',
82     address2    => '',
83     city        => '',
84     state       => '',
85     zip         => '',
86     country     => '',
87     latitude    => '',
88     longitude   => '',
89     addr_clean  => '',
90     censustract => '',
91     @_
92   };
93   bless $self, $class;
94 }
95
96 # minimalist accessor, for compatibility with geocode_Mixin
97 sub get {
98   $_[0]->{$_[1]}
99 }
100
101 sub set {
102   $_[0]->{$_[1]} = $_[2];
103 }
104
105 sub location_hash { %{$_[0]} };
106
107 =item set_censustract
108
109 Look up the censustract, if it's not already filled in, and return it.
110 On error, sets 'error' and returns nothing.
111
112 This uses the "get_censustract_*" methods in L<FS::Misc::Geo>; currently
113 the only one is 'ffiec'.
114
115 =cut
116
117 sub set_censustract {
118   my $self = shift;
119
120   if ( $self->get('censustract') =~ /^\d{9}\.\d{2}$/ ) {
121     return $self->get('censustract');
122   }
123   my $censusyear = $conf->config('census_year');
124   return if !$censusyear;
125
126   my $method = 'ffiec';
127   # configurable censustract-only lookup goes here if it's ever needed.
128   $method = "get_censustract_$method";
129   my $censustract = eval { FS::Misc::Geo->$method($self, $censusyear) };
130   $self->set("censustract_error", $@);
131   $self->set("censustract", $censustract);
132 }
133
134 =item set_coord
135
136 Set the latitude and longitude fields if they're not already set.  Returns
137 those values, in order.
138
139 =cut
140
141 sub set_coord { # the one in geocode_Mixin will suffice
142   my $self = shift;
143   if ( !$self->get('latitude') || !$self->get('longitude') ) {
144     $self->SUPER::set_coord;
145     $self->set('coord_error', $@);
146   }
147   return $self->get('latitude'), $self->get('longitude');
148 }
149
150 =head1 CLASS METHODS
151
152 =over 4
153
154 =item standardize LOCATION
155
156 Given a location hash or L<FS::geocode_Mixin> object, standardize the 
157 address using the configured method and return an L<FS::GeocodeCache> 
158 object.
159
160 The methods are the "standardize_*" functions in L<FS::Geo::Misc>.
161
162 =cut
163
164 sub standardize {
165   my $class = shift;
166   my $location = shift;
167   $location = { $location->location_hash }
168     if UNIVERSAL::can($location, 'location_hash');
169
170   local $Data::Dumper::Terse = 1;
171   warn "standardizing location:\n".Dumper($location) if $DEBUG;
172
173   my $method = $conf->config('address_standardize_method');
174
175   if ( $method ) {
176     $method = "standardize_$method";
177     my $new_location = eval { FS::Misc::Geo->$method( $location ) };
178     if ( $new_location ) {
179       $location = {
180         addr_clean => 'Y',
181         %$new_location
182         # standardize_* can return an address with addr_clean => '' if
183         # the address is somehow questionable
184       }
185     }
186     else {
187       # XXX need an option to decide what to do on error
188       $location->{'addr_clean'} = '';
189       $location->{'error'} = $@;
190     }
191     warn "result:\n".Dumper($location) if $DEBUG;
192   }
193   # else $location = $location
194   my $cache = $class->new(%$location);
195   return $cache;
196 }
197
198 =back
199
200 =head1 BUGS
201
202 =head1 SEE ALSO
203
204 L<FS::Record>, schema.html from the base documentation.
205
206 =cut
207
208 1;
209