Fix Contact selection on prospect, from Fernando-Kiernan, github#54
[freeside.git] / FS / FS / prospect_main.pm
index 6adc852..67e91cf 100644 (file)
@@ -1,17 +1,53 @@
 package FS::prospect_main;
+use base qw( FS::Quotable_Mixin FS::o2m_Common FS::Record );
 
 use strict;
-use base qw( FS::o2m_Common FS::Record );
-use vars qw( $DEBUG );
+use vars qw( $DEBUG @location_fields );
 use Scalar::Util qw( blessed );
-use FS::Record qw( dbh qsearch ); #qsearchs );
-use FS::agent;
+use FS::Conf;
+use FS::Record qw( dbh qsearch qsearchs );
 use FS::cust_location;
-use FS::contact;
-use FS::qual;
+use FS::cust_main;
 
 $DEBUG = 0;
 
+#started as false laziness w/cust_main/Location.pm
+
+use Carp qw(carp);
+
+my $init = 0;
+BEGIN {
+  # set up accessors for location fields
+  if (!$init) {
+    no strict 'refs';
+    @location_fields = 
+      qw( address1 address2 city county state zip country district
+        latitude longitude coord_auto censustract censusyear geocode
+        addr_clean );
+
+    foreach my $f (@location_fields) {
+      *{"FS::prospect_main::$f"} = sub {
+        carp "WARNING: tried to set cust_main.$f with accessor" if (@_ > 1);
+        my @cust_location = shift->cust_location or return '';
+        #arbitrarily picking the first because the UI only lets you add one
+        $cust_location[0]->$f
+      };
+    }
+    $init++;
+  }
+}
+
+#debugging shim--probably a performance hit, so remove this at some point
+sub get {
+  my $self = shift;
+  my $field = shift;
+  if ( $DEBUG and grep { $_ eq $field } @location_fields ) {
+    carp "WARNING: tried to get() location field $field";
+    $self->$field;
+  }
+  $self->FS::Record::get($field);
+}
+
 =head1 NAME
 
 FS::prospect_main - Object methods for prospect_main records
@@ -44,7 +80,11 @@ primary key
 
 =item agentnum
 
-Agent
+Agent (see L<FS::agent>)
+
+=item refnum
+
+Referral (see L<FS::part_referral>)
 
 =item company
 
@@ -203,24 +243,38 @@ sub check {
 
   my $error = 
     $self->ut_numbern('prospectnum')
-    || $self->ut_foreign_key('agentnum', 'agent', 'agentnum' )
+    || $self->ut_foreign_key(  'agentnum', 'agent',         'agentnum' )
+    || $self->ut_foreign_keyn( 'refnum',   'part_referral', 'refnum'   )
     || $self->ut_textn('company')
+    || $self->ut_foreign_keyn( 'taxstatusnum', 'tax_status', 'taxstatusnum' )
   ;
   return $error if $error;
 
+  my $company = $self->company;
+  $company =~ s/^\s+//; 
+  $company =~ s/\s+$//; 
+  $company =~ s/\s+/ /g;
+  $self->company($company);
+
   $self->SUPER::check;
 }
 
 =item name
 
+Returns a name for this prospect, as a string (company name for commercial
+prospects, contact name for residential prospects).
+
 =cut
 
 sub name {
   my $self = shift;
   return $self->company if $self->company;
 
-  my $contact = ($self->contact)[0]; #first contact?  good enough for now
-  return $contact->line if $contact;
+  my $prospect_contact = ($self->prospect_contact)[0]; #first contact?  good enough for now
+  my $contact = $prospect_contact->contact if $prospect_contact;
+  return $contact->line if $prospect_contact && $contact;
+
+  #address?
 
   'Prospect #'. $self->prospectnum;
 }
@@ -229,13 +283,6 @@ sub name {
 
 Returns the contacts (see L<FS::contact>) associated with this prospect.
 
-=cut
-
-sub contact {
-  my $self = shift;
-  qsearch( 'contact', { 'prospectnum' => $self->prospectnum } );
-}
-
 =item cust_location
 
 Returns the locations (see L<FS::cust_location>) associated with this prospect.
@@ -244,21 +291,99 @@ Returns the locations (see L<FS::cust_location>) associated with this prospect.
 
 sub cust_location {
   my $self = shift;
-  qsearch( 'cust_location', { 'prospectnum' => $self->prospectnum,
-                              'custnum'     => '' } );
+  qsearch({
+    'table'   => 'cust_location',
+    'hashref' => { 'prospectnum' => $self->prospectnum,
+                   'custnum'     => '',
+                 },
+    'order_by' => 'ORDER BY country, LOWER(state), LOWER(city), LOWER(county), LOWER(address1), LOWER(address2)',
+  });
 }
 
 =item qual
 
 Returns the qualifications (see L<FS::qual>) associated with this prospect.
 
+=item agent
+
+Returns the agent (see L<FS::agent>) for this customer.
+
+=item tax_status
+
+Returns the external tax status, as an FS::tax_status object, or the empty 
+string if there is no tax status.
+
 =cut
 
-sub qual {
+sub tax_status {
   my $self = shift;
-  qsearch( 'qual', { 'prospectnum' => $self->prospectnum } );
+  if ( $self->taxstatusnum ) {
+    qsearchs('tax_status', { 'taxstatusnum' => $self->taxstatusnum } );
+  } else { 
+    return '';
+  }
 }
 
+=item taxstatus
+
+Returns the tax status code if there is one.
+
+=cut
+
+sub taxstatus {
+  my $self = shift;
+  my $tax_status = $self->tax_status;
+  $tax_status
+    ? $tax_status->taxstatus
+    : '';
+}
+
+=item convert_cust_main
+
+Converts this prospect to a customer.
+
+If there is an error, returns an error message, otherwise, returns the
+newly-created FS::cust_main object.
+
+=cut
+
+sub convert_cust_main {
+  my $self = shift;
+
+  my @cust_location = $self->cust_location;
+  #the interface only allows one, so we're just gonna go with that for now
+
+  my @contact = map $_->contact, $self->prospect_contact;
+
+  #XXX i'm not compatible with cust_main-require_phone (which is kind of a
+  # pre-contact thing anyway)
+
+  my $cust_main = new FS::cust_main {
+    'bill_location' => $cust_location[0],
+    'ship_location' => $cust_location[0],
+    ( map { $_ => $self->$_ } qw( agentnum refnum company taxstatusnum ) ),
+  };
+
+  $cust_main->refnum( FS::Conf->new->config('referraldefault') || 1  )
+    unless $cust_main->refnum;
+
+  #XXX again, arbitrary, if one contact was "billing", that would be better
+  if ( $contact[0] ) {
+    $cust_main->set($_, $contact[0]->get($_)) foreach qw( first last );
+  } else {
+    $cust_main->set('first', 'Unknown');
+    $cust_main->set('last',  'Unknown');
+  }
+
+  #v3 payby no longer allowed
+  #$cust_main->payby('BILL');
+  #$cust_main->paydate('12/2037');
+
+  $cust_main->insert( {},
+    'prospectnum' => $self->prospectnum,
+  )
+    or $cust_main;
+}
 
 =item search HASHREF
 
@@ -316,6 +441,16 @@ sub search {
 
 }
 
+# stub this so that calling ->cust_bill doesn't return an empty string
+sub cust_bill {
+  return;
+}
+
+# XXX should have real localization here eventually
+sub locale {
+  FS::Conf->new->config('locale');
+}
+
 =back
 
 =head1 BUGS