+=item find_or_insert
+
+Finds an existing location matching the customer and address values in this
+location, if one exists, and sets the contents of this location equal to that
+one (including its locationnum).
+
+If an existing location is not found, this one I<will> be inserted. (This is a
+change from the "new_or_existing" method that this replaces.)
+
+The following fields are considered "essential" and I<must> match: custnum,
+address1, address2, city, county, state, zip, country, location_number,
+location_type, location_kind. Disabled locations will be found only if this
+location is set to disabled.
+
+All other fields are considered "non-essential" and will be ignored in
+finding a matching location. If the existing location doesn't match
+in these fields, it will be updated in-place to match.
+
+Returns an error string if inserting or updating a location failed.
+
+It is unfortunately hard to determine if this created a new location or not.
+
+=cut
+
+sub find_or_insert {
+ my $self = shift;
+
+ warn "find_or_insert:\n".Dumper($self) if $DEBUG;
+
+ my @essential = (qw(custnum address1 address2 city county state zip country
+ location_number location_type location_kind disabled));
+
+ if ($conf->exists('cust_main-no_city_in_address')) {
+ warn "Warning: passed city to find_or_insert when cust_main-no_city_in_address is configured, ignoring it"
+ if $self->get('city');
+ $self->set('city','');
+ }
+
+ # I don't think this is necessary
+ #if ( !$self->coord_auto and $self->latitude and $self->longitude ) {
+ # push @essential, qw(latitude longitude);
+ # # but NOT coord_auto; if the latitude and longitude match the geocoded
+ # # values then that's good enough
+ #}
+
+ # put nonempty, nonessential fields/values into this hash
+ my %nonempty = map { $_ => $self->get($_) }
+ grep {$self->get($_)} $self->fields;
+ delete @nonempty{@essential};
+ delete $nonempty{'locationnum'};
+
+ my %hash = map { $_ => $self->get($_) } @essential;
+ foreach (values %hash) {
+ s/^\s+//;
+ s/\s+$//;
+ }
+ my @matches = qsearch('cust_location', \%hash);
+
+ # we no longer reject matches for having different values in nonessential
+ # fields; we just alter the record to match
+ if ( @matches ) {
+ my $old = $matches[0];
+ warn "found existing location #".$old->locationnum."\n" if $DEBUG;
+ foreach my $field (keys %nonempty) {
+ if ($old->get($field) ne $nonempty{$field}) {
+ warn "altering $field to match requested location" if $DEBUG;
+ $old->set($field, $nonempty{$field});
+ }
+ } # foreach $field
+
+ if ( $old->modified ) {
+ warn "updating non-essential fields\n" if $DEBUG;
+ my $error = $old->replace;
+ return $error if $error;
+ }
+ # set $self equal to $old
+ foreach ($self->fields) {
+ $self->set($_, $old->get($_));
+ }
+ return "";
+ }
+
+ # didn't find a match
+ warn "not found; inserting new location\n" if $DEBUG;
+ return $self->insert;
+}
+