convert prospects to customers via quotations, RT#20688
authorIvan Kohler <ivan@freeside.biz>
Tue, 16 Sep 2014 13:41:00 +0000 (06:41 -0700)
committerIvan Kohler <ivan@freeside.biz>
Tue, 16 Sep 2014 13:41:00 +0000 (06:41 -0700)
FS/FS/prospect_main.pm
FS/FS/quotation.pm
httemplate/edit/prospect_main.html
httemplate/search/prospect_main.html
httemplate/view/prospect_main.html

index 55b12f2..5148143 100644 (file)
@@ -6,6 +6,7 @@ use vars qw( $DEBUG @location_fields );
 use Scalar::Util qw( blessed );
 use FS::Record qw( dbh qsearch ); # qsearchs );
 use FS::cust_location;
+use FS::cust_main;
 
 $DEBUG = 0;
 
@@ -78,7 +79,11 @@ primary key
 
 =item agentnum
 
-Agent
+Agent (see L<FS::agent>)
+
+=item refnum
+
+Referral (see L<FS::part_referral>)
 
 =item company
 
@@ -237,7 +242,8 @@ 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_key( 'refnum',   'part_referral', 'refnum' )
     || $self->ut_textn('company')
   ;
   return $error if $error;
@@ -292,6 +298,49 @@ Returns the qualifications (see L<FS::qual>) associated with this prospect.
 
 Returns the agent (see L<FS::agent>) for this customer.
 
+=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 = $self->contact;
+
+  #XXX define one contact type as "billing", then we could pick just that one
+  my @invoicing_list = map $_->emailaddress, map $_->contact_email, @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 ) ),
+  };
+
+  #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');
+  }
+
+  $cust_main->insert( {}, \@invoicing_list,
+    'prospectnum' => $self->prospectnum,
+  )
+    or $cust_main;
+}
+
 =item search HASHREF
 
 (Class method)
index cf6652f..9d47857 100644 (file)
@@ -3,7 +3,11 @@ use base qw( FS::Template_Mixin FS::cust_main_Mixin FS::otaker_Mixin FS::Record
            );
 
 use strict;
+use Tie::RefHash;
 use FS::CurrentUser;
+use FS::UID qw( dbh );
+use FS::cust_main;
+use FS::cust_pkg;
 
 =head1 NAME
 
@@ -194,6 +198,75 @@ sub _items_total {
 
 sub enable_previous { 0 }
 
+=item convert_cust_main
+
+If this quotation already belongs to a customer, then returns that customer, as
+an FS::cust_main object.
+
+Otherwise, creates a new customer (FS::cust_main object and record, and
+associated) based on this quotation's prospect, then orders this quotation's
+packages as real packages for the 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_main = $self->cust_main;
+  return $cust_main if $cust_main; #already converted, don't again
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  $cust_main = $self->prospect_main->convert_cust_main;
+  unless ( ref($cust_main) ) { # eq 'FS::cust_main' ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $cust_main;
+  }
+
+  $self->prospectnum('');
+  $self->custnum( $cust_main->custnum );
+  my $error = $self->replace || $self->order;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
+  $cust_main;
+
+}
+
+=item order
+
+This method is for use with quotations which are already associated with a customer.
+
+Orders this quotation's packages as real packages for the customer.
+
+If there is an error, returns an error message, otherwise returns false.
+
+=cut
+
+sub order {
+  my $self = shift;
+
+  tie my %cust_pkg, 'Tie::RefHash',
+    map { FS::cust_pkg->new({ pkgpart  => $_->pkgpart,
+                              quantity => $_->quantity,
+                           })
+            => [] #services
+        }
+      $self->quotation_pkg ;
+
+  $self->cust_main->order_pkgs( \%cust_pkg );
+
+}
+
 =back
 
 =head1 CLASS METHODS
index d398541..da5c6ce 100644 (file)
@@ -3,6 +3,7 @@
      'table'           => 'prospect_main',
      'labels'          => { 'prospectnum' => 'Prospect',
                             'agentnum'    => 'Agent',
+                            'refnum'      => 'Advertising source',
                             'company'     => 'Company',
                             'contactnum'  => 'Contact',
                             'locationnum' => '&nbsp;',
          'empty_label' => 'Select agent',
          'colspan'     => 6,
        },
+       { 'field'       => 'refnum',
+         'type'        => 'select-part_referral',
+         'empty_label' => 'Select advertising source',
+         'colspan'     => 6,
+       },
        { 'field'    => 'residential_commercial',
          'type'     => 'radio',
          'options'  => [ 'Residential', 'Commercial', ],
index ab37b90..4798f58 100644 (file)
@@ -23,6 +23,8 @@
                                   '', #link to contact edit???
                                 ],
              'agent_virt'    => 1,
+             'disableable'   => 1,
+             'disabled_statuspos' => 2,
 &>
 <%init>
 
index 6c4595d..689b422 100644 (file)
 
 <TR>
   <TD ALIGN="right">Prospect #</TD>
-  <TD BGCOLOR="#FFFFFF"><B><% $prospectnum %></B></TD>
+  <TD BGCOLOR="#FFFFFF"><B><% $prospectnum %></B>
+%   if ( $prospect_main->disabled ) {
+      <B>(DISABLED)</B>
+%   }
+  </TD>
 </TR>
 
 %unless ( scalar(@agentnums) == 1
 %  my $agent = qsearchs('agent',{ 'agentnum' => $prospect_main->agentnum } );
    <TR>
      <TD ALIGN="right">Agent</TD>
-     <TD BGCOLOR="#ffffff"><% $agent->agentnum %>: <% $agent->agent %></TD>
+     <TD BGCOLOR="#ffffff"><% $agent->agentnum %>: <% $agent->agent |h %></TD>
+   </TR>
+%}
+
+%unless ( ! $prospect_main->refnum ) { # || scalar(@part_referral) == 1 ) {
+%  my $part_referral = qsearchs('part_referral',{ 'refnum' => $prospect_main->refnum } );
+   <TR>
+     <TD ALIGN="right">Advertising source</TD>
+     <TD BGCOLOR="#ffffff"><% $part_referral->referral |h %></TD>
    </TR>
 %}
 
@@ -76,6 +88,9 @@
       <TR>
         <TH CLASS="grid" BGCOLOR="#cccccc">#</TH>
         <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Date') |h %></TH>
+        <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Setup') |h %></TH>
+        <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Recurring') |h %></TH>
+        <TH CLASS="grid" BGCOLOR="#cccccc"></TH>
       </TR>
 %     foreach my $quotation (@quotations) {
 %       if ( $bgcolor eq $bgcolor1 ) {
         <TR>
           <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $a %><% $quotation->quotationnum %></A></TD>
           <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $a %><% time2str($date_format, $quotation->_date) |h %></A></TD>
+          <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $a %><% $quotation->total_setup |h %></A></TD>
+          <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $a %><% $quotation->total_recur |h %></A></TD>
+          <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><A HREF="<%$p%>edit/process/quotation_convert.html?quotationnum=<% $quotation->quotationnum %>">Convert to customer</A></TD>
         </TR>
 %     }
     </TABLE>