Difference between revisions of "Importing contacts"

From Freephile Wiki
Jump to navigation Jump to search
m (added Category:Software using HotCat)
(20 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{Not free|CiviCRM}}
+
== Goal ==
 +
Import records into SugarCRM without using existing functionality, but rather by writing some PHP tool to do the work.  Records should go into Accounts and Contacts, which obviously implies a relationship.
  
[http://en.wikipedia.org/wiki/Sugarcrm SugarCRM] is the world's leading Customer Relationship Management (CRM) software available with complete freedom under the GPL license. For companies that want more than freedom, SugarCRM Inc, fully backs the product with expert support, service, training and customization. SugarCRM offers several deployment options, including on-demand, on-premise and appliance-based solutions to suit customers' security, integration and configuration needs.  Because CRM software captures the varied relationships between a company and it's sources of revenue, most businesses really stand to benefit from the intelligence provided by a CRM system.  All companies already have 'ad-hoc' methods to track leads, contacts, customer accounts and the company interactions with these (e.g. spreadsheets, lists and email records). They may even have organized CRM solutions in place.  Either way, once you decide to adopt an open and standards-based solution like SugarCRM, your first order of business will be to load it with your existing data.  SugarCRM has importing (and exporting) utilities that make it easy to do this, so these wizards will not be the focus of this article.  Instead, we'll focus on programmatic interaction with the system. 
+
== Resources Used ==
<!--
+
* http://www.sugarcrm.com/wiki/index.php?title=SOAP_Intro_and_Practical_Examples
{{Infobox Company
+
* http://freephile.com/crm/index.php?module=Home&action=TrainingPortal
|company_name=SugarCRM
+
* http://freephile.com/crm/soap.php
|company_type=Private
+
* http://www.sugarcrm.com/wiki/index.php?title=SOAP_in_PHP
|foundation=[[California]] 2004
+
* http://dietrich.ganx4.com/nusoap/
|location=[[Cupertino, California]]
 
|industry=CRM Software
 
|products= Sugar Community Edition, Sugar Professional, Sugar Enterprise
 
|num_employees=150+
 
|parent=
 
|subsid=
 
|homepage=[http://www.sugarcrm.com/ www.sugarcrm.com]
 
}} -->
 
{{Infobox
 
|name        = SugarCRM
 
|bodystyle    =
 
|title       = Company Info
 
|titlestyle  =
 
|above        =
 
|abovestyle  =
 
|image        =
 
|imagestyle  =
 
|caption      =
 
|captionstyle =
 
|headerstyle  =
 
|labelstyle  =
 
|datastyle    =
 
  
|header1  =  
+
==First I downloaded the source ==
|label1  = Company Name
+
# I went to the SugarCRM homepage, and clicked the top navbar link to "Sugar Open Source"
|data1    = SugarCRM
+
# I skipped the "Wizard" and went right to the "Download Page" because I know what I'm doing and also have a pre-existing setup of Linux, Apache MySQL and PHP - so I only want the app
|header2  =  
+
# I downloaded SugarCE-5.0.0e.zip (production release)
|label2  = Company Type
+
# I visited the recommended "Installation" instructions page at http://www.sugarforge.org/content/installation/
|data2    = private
+
# Then I installed it according to the instructions, however I immediately ran into trouble because the instructions did say to chmod 766 all files that needed to be writable by the web_user.   
|header3  =
+
# This command renders the directories non-executable which manifests in include errors because the web user (www-data) can not see into those directories (to find includes).
|label3  = Founded
+
<source lang="bash">
|data3    = California 2004
+
# find directories in the ./crm path and change the mode on them so that all users can execute (see into) the directory
|header4  =
+
find ./crm/ -type d |xargs chmod a+x
|label4  = Industry
+
</source>
|data4    = CRM Software
+
resolved the include errors
|header5  =
 
|label5  = Products
 
|data5    = Sugar Community Edition, Sugar Professional, Sugar Enterprise
 
|header6  =
 
|label6  = Employees
 
|data6    = 150+
 
|header7  =
 
|label7  = Website
 
|data7    = [http://www.sugarcrm.com/ www.sugarcrm.com]
 
|header8  =
 
|label8  =
 
|data8    =
 
|header9  =
 
|label9  =
 
|data9    =
 
|header10 =
 
|label10  =
 
|data10  =
 
}}
 
== Introduction ==
 
Typically a company will deploy the CRM system and will also create one or more pipelines which act as conduits to capture new account, and contact information.  This article will show how to establish a web service, using [http://en.wikipedia.org/wiki/SOAP SOAP] to add contacts and accounts to your [[Installing SugarCRM|SugarCRM installation]].  As an example scenario, let's suppose that a conference organizer wants to offer a sign-up sheet on their existing website. The existing website could be a [http://drupal.org Drupal] content management system (CMS) which not only manages the conference, but also adds company and individual contact details to the SugarCRM system via the web service. The details on creating the form for the capture are beyond the scope of this article but the capture routines could easily handle a form input (HTTP POST) just as easily as we read input from a file .  Again our focus for today will be on the plumbing of the interaction with the SOAP server.
 
 
 
== Goal ==
 
Import records into SugarCRM without using existing import wizards but rather by writing a tool in [http://en.wikipedia.org/wiki/PHP PHP] to do the work.  Records should go into Accounts and Contacts, while creating a relationship between the two.
 
 
 
== Requirements ==
 
Assume that we start with a spreadsheet that has column headings matching the 17 fields shown belowAssume too that we want to capture all of the data in the sample.  (The owner of the data collected it for a reason and they wouldn't be too happy with a loss of data in a migration to a new application!) I did not define new fields in the database, but I did correlate my data source to the Accounts and Contacts tables. Because I had parsed the data source (spreadsheet or CSV file) for column headings, I simply exported that variable and then used it as a comment right in my code workup as I went. What I mean is that I created a PHP (array) variable of the 17 field names, and then used the [http://php.net/var_export|var_export]() function to print it and copy/paste into a comment block so that I could mark up a plan for mapping those fields into fields in SugarCRM.
 
  
<source lang="php">
+
The instructions also fail to mention that the application wants to create a .htaccess file (which doesn't exist in the distribution and would not necessarily be writable to the web user.  As a failsafe, the information is printed to the screen in the installer.  However it doesn't properly display (lacking newline characters) which would make the content suitable for copy and paste into the file.  I found the source which generates the .htaccess content, and used that.  An alternative is to simply touch and chmod a .htaccess file prior to running the installer.
print '<pre>'; var_export ($arrFields); print '</pre>';
 
// copy and paste that output; then add comments about which fields go into which table
 
// comment the whole block so that it remains as a reference in the tool
 
array (
 
  0 => 'Company Name',// a:name                         
 
  1 => 'Industry',    // a:industry                     
 
  2 => 'First Name',  //                                  c:first_name
 
  3 => 'Last Name',  //                                  c:last_name
 
  4 => 'Fax',        // a:phone_fax                      c:phone_fax
 
  5 => 'Address',    // a:billing_address_street        c:primary_address_street
 
  6 => 'City',        // a:billing_address_city          c:primary_address_city
 
  7 => 'State',      // a:billing_address_state          c:primary_address_state
 
  8 => 'Zip Code',    // a:billing_address_postalcode    c:primary_address_postalcode
 
  9 => 'Country',    // a:billing_address_country        c:primary_address_country
 
  10 => 'Notes',      // a:description                   
 
  11 => 'Work Phone', // a:phone_office                  c:phone_work
 
  12 => 'Other Phone',// a:phone_alternate                c:phone_other
 
  13 => 'Email',      // a:email                          c:email1
 
  14 => 'website',    // a:website                       
 
  15 => 'employees',  // a:employees                     
 
  16 => 'ticker_symbol'// a:ticker_symbol                 
 
)
 
</source>
 
  
=== Using a Form ===
+
== Ideas on How to do the import ==
The [http://www.sugarcrm.com/wiki/index.php?title=SOAP_Intro_and_Practical_Examples SOAP Intro and Practical Examples], shows a simple form-based processing script for leads.
+
My self-imposed requirement was to capture all of the data provided -- assuming the owner of the data collected it for a reason and that they wouldn't be too happy with a loss of data in a migration to a new application. I looked briefly at the import functionality exposed by the application, but noticed how the lead capture did not reflect the same data profile as the source that I had.
  
The form can be found in the "examples" directory in the source.  Note: the example did not work as an application entry point (because even though it defined ('sugarEntry', true); there was also an IF that pre-empted that definition -- because requests inside the SugarCRM install directory will automatically bootstrap the SugarCRM system)To work around this, either put the example form outside the application directory or define sugarEntry as true ''without'' the 'if' conditional. Using the lead capture form is illustrated at http://www.sugarcrm.com/wiki/index.php?title=Creating_a_lead_capture_form_for_your_website
+
=== Existing Work ===
If your needs are more complex, you can learn more by looking at the modules dealing with Import (dataMaps), the database abstraction layer (SugarBeans and VarDefs) or the database directly to get a clearer picture of everything going on in the SugarCRM system.   
+
My first instinct was to find info about somebody doing this before (e.g. APIs, Documentation, forum questions, Wikis)
 +
 +
I searched the wiki for importing or APIs and quickly found the SOAP Intro and Practical Examples, so I figured I was onto a fast track.
 +
However, the soap example worked with a frontend form (which wasn't explained much) leading me to investigate more into what was required by the soap service. 
 +
When I found the form in "examples", it did not work as an application entry point (because even though it defined ('sugarEntry', true); there was also an IF that pre-empted that definition) because other code was being loaded before the formI did not immediately see this cause for the example failure, so I put the example form outside the application directory and successfully used the form to insert a single lead This is illustrated at http://www.sugarcrm.com/wiki/index.php?title=Creating_a_lead_capture_form_for_your_website
 +
Seeing that the example worked, but did not capture all the details provided in the data exercise, I knew I should look at the existing functionality of modules dealing with Import (dataMaps), the database abstraction layer (SugarBeans and VarDefs) or the database directly to get a clearer picture of what I needed to label everything.   
  
 
=== Use the Source Luke ===
 
=== Use the Source Luke ===
Answers are always found in the source, with the caveat that it can be confusing and/or time-consuming to find those answers.
+
My second instinct was to look at the source.  Answers are always found in the source, with the caveat that it can be confusing and/or time-consuming to find those answers.
 +
 
 +
Looking at the full application import routines and the four-step forms for importing leads, it was obvious that there was a lot of machinery that I didn't necessarily need or want to get involved with to simply import records.  For instance, I would not want to (re-)write the form and UI handling when I simply needed to insert records into a database.  This made me reconsider using the SOAP example to do the job.  In essence, it would only need to read the exercise data and create full records for the 50 provided leads.
  
Looking at the full application import routines and the four-step forms for importing leads, there is a lot of example machinery that you could use to create a sophisticated web front-end using SugarCRM internals. For this exercise, I want to assume that we'll be operating between two websites, and so I will simply insert records into the database communicating with SugarCRM's SOAP server.
+
<!--
 +
From looking at the source code of the import routines, I noticed that the modules/Import/config.php file defined various types of data profiles, and that the "Salesforce" profile was close to the data that I had.
  
; Tip: You can peer into the SugarCRM environment with a call to PHP's 'get_defined_vars()'.  This will give you some information about field maps etc.
 
 
<source lang="php">
 
<source lang="php">
 
# temp.php to show a concise view of the variables defined in the config script
 
# temp.php to show a concise view of the variables defined in the config script
Line 187: Line 123:
 
                 )
 
                 )
 
</source>  
 
</source>  
 +
-->
  
== Using SOAP ==
+
Note: Soap examples seem to have changed with the addition of a version number, so you must be careful about what example you use, and generally rely on the source to be the definitive source ;-)
 
 
Note: SOAP examples can obviously change slightly over time with SugarCRM, so you must be careful about what example you use, and generally rely on the source to be the definitive source ;-)
 
* soap/SoapPortalUsers.php
 
* soap/SoapSugarUsers.php
 
* soap/SoapData.php
 
* soap/SoapDeprecated.php
 
  
 
Getting on with the soap service, it is easy to discover the service profile and import the data
 
Getting on with the soap service, it is easy to discover the service profile and import the data
  
From the [http://freephile.com/crm/soap.php soap.php] page (which shows the WSDL), we can get a definition of the available SOAP calls.  For example, here is the definition of the 'create_account' method
+
From the [http://freephile.com/crm/soap.php|soap.php] page (which shows the WSDL), we can get a definition of the available SOAP calls.  For example, here is the definition of the 'create_account' method
  
 
<pre>
 
<pre>
Line 227: Line 158:
 
Transport: http://schemas.xmlsoap.org/soap/http
 
Transport: http://schemas.xmlsoap.org/soap/http
 
Documentation:  
 
Documentation:  
</pre>
+
And the create_contact method:
 
<pre>
 
 
Name: create_contact
 
Name: create_contact
 
Binding: sugarsoapBinding
 
Binding: sugarsoapBinding
Line 259: Line 188:
  
 
Even more detail can be had by inspecting the service.
 
Even more detail can be had by inspecting the service.
<source lang="php">
 
$get_available_modules_params = array (
 
  'session' => $session_id,
 
);
 
$result = $soapclient->call('get_available_modules', $get_available_modules_params);
 
print '<pre>'; var_export ($result); print '</pre>';
 
 
// output:
 
</source>
 
See [[Importing_contacts/sugar_modules]]
 
  
 
<source lang="php">
 
<source lang="php">
Line 284: Line 203:
  
 
===Accounts fields: ===
 
===Accounts fields: ===
[[Importing_contacts/Accounts|See the SOAP profile for Accounts]]
 
  
 +
<source lang="php">
 +
array (
 +
  'module_name' => 'Accounts',
 +
  'module_fields' =>
 +
  array (
 +
    0 =>
 +
    array (
 +
      'name' => 'id',
 +
      'type' => 'id',
 +
      'label' => 'ID',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    1 =>
 +
    array (
 +
      'name' => 'name',
 +
      'type' => 'name',
 +
      'label' => 'Name:',
 +
      'required' => 1,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    2 =>
 +
    array (
 +
      'name' => 'date_entered',
 +
      'type' => 'datetime',
 +
      'label' => 'Date Entered:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    3 =>
 +
    array (
 +
      'name' => 'date_modified',
 +
      'type' => 'datetime',
 +
      'label' => 'Date Modified:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    4 =>
 +
    array (
 +
      'name' => 'modified_user_id',
 +
      'type' => 'assigned_user_name',
 +
      'label' => 'Modified By Id',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    5 =>
 +
    array (
 +
      'name' => 'modified_by_name',
 +
      'type' => 'assigned_user_name',
 +
      'label' => 'Modified By Id',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    6 =>
 +
    array (
 +
      'name' => 'created_by',
 +
      'type' => 'assigned_user_name',
 +
      'label' => 'Created By Id',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    7 =>
 +
    array (
 +
      'name' => 'created_by_name',
 +
      'type' => 'assigned_user_name',
 +
      'label' => 'Created By Id',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    8 =>
 +
    array (
 +
      'name' => 'description',
 +
      'type' => 'text',
 +
      'label' => 'Description:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    9 =>
 +
    array (
 +
      'name' => 'deleted',
 +
      'type' => 'bool',
 +
      'label' => 'Deleted',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    10 =>
 +
    array (
 +
      'name' => 'assigned_user_id',
 +
      'type' => 'relate',
 +
      'label' => 'Assigned User:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    11 =>
 +
    array (
 +
      'name' => 'assigned_user_name',
 +
      'type' => 'relate',
 +
      'label' => 'Assigned to:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    12 =>
 +
    array (
 +
      'name' => 'account_type',
 +
      'type' => 'enum',
 +
      'label' => 'Type:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
        0 =>
 +
        array (
 +
          'name' => '',
 +
          'value' => '',
 +
        ),
 +
        1 =>
 +
        array (
 +
          'name' => 'Analyst',
 +
          'value' => 'Analyst',
 +
        ),
 +
        2 =>
 +
        array (
 +
          'name' => 'Competitor',
 +
          'value' => 'Competitor',
 +
        ),
 +
        3 =>
 +
        array (
 +
          'name' => 'Customer',
 +
          'value' => 'Customer',
 +
        ),
 +
        4 =>
 +
        array (
 +
          'name' => 'Integrator',
 +
          'value' => 'Integrator',
 +
        ),
 +
        5 =>
 +
        array (
 +
          'name' => 'Investor',
 +
          'value' => 'Investor',
 +
        ),
 +
        6 =>
 +
        array (
 +
          'name' => 'Partner',
 +
          'value' => 'Partner',
 +
        ),
 +
        7 =>
 +
        array (
 +
          'name' => 'Press',
 +
          'value' => 'Press',
 +
        ),
 +
        8 =>
 +
        array (
 +
          'name' => 'Prospect',
 +
          'value' => 'Prospect',
 +
        ),
 +
        9 =>
 +
        array (
 +
          'name' => 'Reseller',
 +
          'value' => 'Reseller',
 +
        ),
 +
        10 =>
 +
        array (
 +
          'name' => 'Other',
 +
          'value' => 'Other',
 +
        ),
 +
      ),
 +
    ),
 +
    13 =>
 +
    array (
 +
      'name' => 'industry',
 +
      'type' => 'enum',
 +
      'label' => 'Industry:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
        0 =>
 +
        array (
 +
          'name' => '',
 +
          'value' => '',
 +
        ),
 +
        1 =>
 +
        array (
 +
          'name' => 'Apparel',
 +
          'value' => 'Apparel',
 +
        ),
 +
        2 =>
 +
        array (
 +
          'name' => 'Banking',
 +
          'value' => 'Banking',
 +
        ),
 +
        3 =>
 +
        array (
 +
          'name' => 'Biotechnology',
 +
          'value' => 'Biotechnology',
 +
        ),
 +
        4 =>
 +
        array (
 +
          'name' => 'Chemicals',
 +
          'value' => 'Chemicals',
 +
        ),
 +
        5 =>
 +
        array (
 +
          'name' => 'Communications',
 +
          'value' => 'Communications',
 +
        ),
 +
        6 =>
 +
        array (
 +
          'name' => 'Construction',
 +
          'value' => 'Construction',
 +
        ),
 +
        7 =>
 +
        array (
 +
          'name' => 'Consulting',
 +
          'value' => 'Consulting',
 +
        ),
 +
        8 =>
 +
        array (
 +
          'name' => 'Education',
 +
          'value' => 'Education',
 +
        ),
 +
        9 =>
 +
        array (
 +
          'name' => 'Electronics',
 +
          'value' => 'Electronics',
 +
        ),
 +
        10 =>
 +
        array (
 +
          'name' => 'Energy',
 +
          'value' => 'Energy',
 +
        ),
 +
        11 =>
 +
        array (
 +
          'name' => 'Engineering',
 +
          'value' => 'Engineering',
 +
        ),
 +
        12 =>
 +
        array (
 +
          'name' => 'Entertainment',
 +
          'value' => 'Entertainment',
 +
        ),
 +
        13 =>
 +
        array (
 +
          'name' => 'Environmental',
 +
          'value' => 'Environmental',
 +
        ),
 +
        14 =>
 +
        array (
 +
          'name' => 'Finance',
 +
          'value' => 'Finance',
 +
        ),
 +
        15 =>
 +
        array (
 +
          'name' => 'Government',
 +
          'value' => 'Government',
 +
        ),
 +
        16 =>
 +
        array (
 +
          'name' => 'Healthcare',
 +
          'value' => 'Healthcare',
 +
        ),
 +
        17 =>
 +
        array (
 +
          'name' => 'Hospitality',
 +
          'value' => 'Hospitality',
 +
        ),
 +
        18 =>
 +
        array (
 +
          'name' => 'Insurance',
 +
          'value' => 'Insurance',
 +
        ),
 +
        19 =>
 +
        array (
 +
          'name' => 'Machinery',
 +
          'value' => 'Machinery',
 +
        ),
 +
        20 =>
 +
        array (
 +
          'name' => 'Manufacturing',
 +
          'value' => 'Manufacturing',
 +
        ),
 +
        21 =>
 +
        array (
 +
          'name' => 'Media',
 +
          'value' => 'Media',
 +
        ),
 +
        22 =>
 +
        array (
 +
          'name' => 'Not For Profit',
 +
          'value' => 'Not For Profit',
 +
        ),
 +
        23 =>
 +
        array (
 +
          'name' => 'Recreation',
 +
          'value' => 'Recreation',
 +
        ),
 +
        24 =>
 +
        array (
 +
          'name' => 'Retail',
 +
          'value' => 'Retail',
 +
        ),
 +
        25 =>
 +
        array (
 +
          'name' => 'Shipping',
 +
          'value' => 'Shipping',
 +
        ),
 +
        26 =>
 +
        array (
 +
          'name' => 'Technology',
 +
          'value' => 'Technology',
 +
        ),
 +
        27 =>
 +
        array (
 +
          'name' => 'Telecommunications',
 +
          'value' => 'Telecommunications',
 +
        ),
 +
        28 =>
 +
        array (
 +
          'name' => 'Transportation',
 +
          'value' => 'Transportation',
 +
        ),
 +
        29 =>
 +
        array (
 +
          'name' => 'Utilities',
 +
          'value' => 'Utilities',
 +
        ),
 +
        30 =>
 +
        array (
 +
          'name' => 'Other',
 +
          'value' => 'Other',
 +
        ),
 +
      ),
 +
    ),
 +
    14 =>
 +
    array (
 +
      'name' => 'annual_revenue',
 +
      'type' => 'varchar',
 +
      'label' => 'Annual Revenue:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    15 =>
 +
    array (
 +
      'name' => 'phone_fax',
 +
      'type' => 'phone',
 +
      'label' => 'Fax:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    16 =>
 +
    array (
 +
      'name' => 'billing_address_street',
 +
      'type' => 'varchar',
 +
      'label' => 'Billing Street:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    17 =>
 +
    array (
 +
      'name' => 'billing_address_city',
 +
      'type' => 'varchar',
 +
      'label' => 'Billing City:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    18 =>
 +
    array (
 +
      'name' => 'billing_address_state',
 +
      'type' => 'varchar',
 +
      'label' => 'Billing State:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    19 =>
 +
    array (
 +
      'name' => 'billing_address_postalcode',
 +
      'type' => 'varchar',
 +
      'label' => 'Billing Postal Code:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    20 =>
 +
    array (
 +
      'name' => 'billing_address_country',
 +
      'type' => 'varchar',
 +
      'label' => 'Billing Country:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    21 =>
 +
    array (
 +
      'name' => 'rating',
 +
      'type' => 'varchar',
 +
      'label' => 'Rating:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    22 =>
 +
    array (
 +
      'name' => 'phone_office',
 +
      'type' => 'phone',
 +
      'label' => 'Phone Office:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    23 =>
 +
    array (
 +
      'name' => 'phone_alternate',
 +
      'type' => 'phone',
 +
      'label' => 'Alternate Phone:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    24 =>
 +
    array (
 +
      'name' => 'website',
 +
      'type' => 'varchar',
 +
      'label' => 'Website:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    25 =>
 +
    array (
 +
      'name' => 'ownership',
 +
      'type' => 'varchar',
 +
      'label' => 'Ownership:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    26 =>
 +
    array (
 +
      'name' => 'employees',
 +
      'type' => 'num',
 +
      'label' => 'Employees:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    27 =>
 +
    array (
 +
      'name' => 'ticker_symbol',
 +
      'type' => 'varchar',
 +
      'label' => 'Ticker Symbol:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    28 =>
 +
    array (
 +
      'name' => 'shipping_address_street',
 +
      'type' => 'varchar',
 +
      'label' => 'Shipping Street:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    29 =>
 +
    array (
 +
      'name' => 'shipping_address_city',
 +
      'type' => 'varchar',
 +
      'label' => 'Shipping City:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    30 =>
 +
    array (
 +
      'name' => 'shipping_address_state',
 +
      'type' => 'varchar',
 +
      'label' => 'Shipping State:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    31 =>
 +
    array (
 +
      'name' => 'shipping_address_postalcode',
 +
      'type' => 'varchar',
 +
      'label' => 'Shipping Postal Code:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    32 =>
 +
    array (
 +
      'name' => 'shipping_address_country',
 +
      'type' => 'varchar',
 +
      'label' => 'Shipping Country:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    33 =>
 +
    array (
 +
      'name' => 'email1',
 +
      'type' => 'varchar',
 +
      'label' => 'Email:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    34 =>
 +
    array (
 +
      'name' => 'parent_id',
 +
      'type' => 'id',
 +
      'label' => 'Parent Account ID',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    35 =>
 +
    array (
 +
      'name' => 'sic_code',
 +
      'type' => 'varchar',
 +
      'label' => 'SIC Code:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    36 =>
 +
    array (
 +
      'name' => 'account_name',
 +
      'type' => 'relate',
 +
      'label' => 'Account Name:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    37 =>
 +
    array (
 +
      'name' => 'parent_name',
 +
      'type' => 'relate',
 +
      'label' => 'Member of:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    38 =>
 +
    array (
 +
      'name' => 'campaign_id',
 +
      'type' => 'id',
 +
      'label' => 'Campaign ID',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
  ),
 +
  'error' => '',
 +
)
 +
</source>
  
 
=== Contacts fields: ===
 
=== Contacts fields: ===
[[Importing_contacts/Contacts|See the SOAP profile for Contacts]]
 
 
 
== Setting Records ==
 
 
<source lang="php">
 
<source lang="php">
// read in our data from source CSV file format
+
array (
$arrData = file('./account_contact_list.csv');
+
  'module_name' => 'Contacts',
$separator = ',';
+
  'module_fields' =>
// initialize an array to hold structured data; we'll determine what columns we want and map our data
+
  array (
$leadData = array();
+
    0 =>
// take the first (header) row off the CSV file
+
    array (
$arrFields = explode($separator, array_shift($arrData));
+
      'name' => 'id',
// flipping the array gives us the integer value we need defined by it's name
+
      'type' => 'id',
// in other words, we now have an associative array of integers
+
      'label' => 'ID:',
$fieldKeys = array_flip($arrFields);
+
      'required' => 0,
 
+
      'options' =>  
// break up our records
+
      array (
foreach ($arrData as $k => $v) {
+
      ),
  $arrData[$k] = explode($separator, $v);
+
     ),
}
+
    1 =>  
 
+
    array (
foreach ($arrData as $record) {
+
      'name' => 'date_entered',
  // Accounts
+
      'type' => 'datetime',
  $set_entry_params = array(
+
      'label' => 'Date Created',
    'session' => $session_id,
+
      'required' => 0,
    'module_name' => 'Accounts',
+
      'options' =>
     'name_value_list'=>array(
+
      array (
        array('name'=>'name',                       'value'=>$record[$fieldKeys['Company Name']]), // required
+
      ),
        array('name'=>'industry',                   'value'=>$record[$fieldKeys['last_name']]),
+
    ),
        array('name'=>'phone_fax',                 'value'=>$record[$fieldKeys['Fax']]),
+
    2 =>
        array('name'=>'billing_address_street',     'value'=>$record[$fieldKeys['Address']]),
+
    array (
        array('name'=>'billing_address_city',       'value'=>$record[$fieldKeys['City']]),
+
      'name' => 'date_modified',
        array('name'=>'billing_address_state',     'value'=>$record[$fieldKeys['State']]),
+
      'type' => 'datetime',
        array('name'=>'billing_address_postalcode', 'value'=>$record[$fieldKeys['Zip Code']]),
+
      'label' => 'Date Modified:',
        array('name'=>'billing_address_country',   'value'=>$record[$fieldKeys['Country']]),
+
      'required' => 0,
        array('name'=>'description',               'value'=>$record[$fieldKeys['Notes']]),
+
       'options' =>  
        array('name'=>'phone_office',               'value'=>$record[$fieldKeys['Work Phone']]),
+
      array (
        array('name'=>'phone_alternate',           'value'=>$record[$fieldKeys['Other Phone']]),
+
      ),
        array('name'=>'email',                     'value'=>$record[$fieldKeys['Email']]),
+
    ),
        array('name'=>'website',                   'value'=>$record[$fieldKeys['website']]),
+
    3 =>
        array('name'=>'employees',                 'value'=>$record[$fieldKeys['employees']]),
+
    array (
        array('name'=>'ticker_symbol',             'value'=>$record[$fieldKeys['ticker_symbol']]),
+
      'name' => 'modified_user_id',
        array('name'=>'assigned_user_id',           'value'=>$user_guid)
+
      'type' => 'assigned_user_name',
     )
+
      'label' => 'Modified By Id',
  );
+
      'required' => 0,
  // make the soap call
+
      'options' =>
  $result = $soapclient->call('set_entry',$set_entry_params);
+
      array (
  // print "\n <br />Entry results:<br />\n<pre>\n"; var_export ($result); print "\n</pre>\n";
+
      ),
  // the return value will give us the unique identifier for the Account record, which we
+
    ),
  // then use to create a relationship entry when creating the Contact
+
    4 =>
  $accountId = $result['id'];
+
    array (
 
+
      'name' => 'modified_by_name',
  // Contacts
+
      'type' => 'assigned_user_name',
  $set_entry_params = array(
+
      'label' => 'Modified By Id',
    'session' => $session_id,
+
      'required' => 0,
    'module_name' => 'Contacts',
+
      'options' =>
     'name_value_list'=>array(
+
      array (
        array('name'=>'first_name',                 'value'=>$record[$fieldKeys['First Name']]),
+
      ),
        array('name'=>'last_name',                 'value'=>$record[$fieldKeys['Last Name']]),
+
    ),
        array('name'=>'phone_fax',                 'value'=>$record[$fieldKeys['Fax']]),
+
    5 =>
        array('name'=>'primary_address_street',     'value'=>$record[$fieldKeys['Address']]),
+
    array (
        array('name'=>'primary_address_city',      'value'=>$record[$fieldKeys['City']]),
+
      'name' => 'created_by',
        array('name'=>'primary_address_state',     'value'=>$record[$fieldKeys['State']]),
+
      'type' => 'assigned_user_name',
        array('name'=>'primary_address_postalcode', 'value'=>$record[$fieldKeys['Zip Code']]),
+
      'label' => 'Created By Id',
        array('name'=>'primary_address_country',   'value'=>$record[$fieldKeys['Country']]),
+
      'required' => 0,
         array('name'=>'phone_office',               'value'=>$record[$fieldKeys['Work Phone']]),
+
      'options' =>  
         array('name'=>'phone_other',               'value'=>$record[$fieldKeys['Other Phone']]),
+
      array (
         array('name'=>'email',                     'value'=>$record[$fieldKeys['Email']]),
+
      ),
         array('name'=>'account_name',               'value'=>$record[$fieldKeys['Company Name']]), // relation
+
    ),
         array('name'=>'account_id',                 'value'=>$accountId), // relation
+
    6 =>  
         array('name'=>'assigned_user_id',          'value'=>$user_guid)
+
    array (
    )
+
      'name' => 'created_by_name',
  );
+
      'type' => 'assigned_user_name',
  // make the soap call to create the (related) Contact entry
+
      'label' => 'Created By Id',
  $result = $soapclient->call('set_entry',$set_entry_params);
+
      'required' => 0,
  print "\n <br />Contact Entry results:<br />\n<pre>\n"; var_export ($result); print "\n</pre>\n";
+
      'options' =>
  $contactId = $result['id'];
+
      array (
 
+
      ),
 
+
    ),
  /**
+
    7 =>
  // alternately, if you have both ids, you can use set_relationship
+
    array (
  $set_relationship_params = array(
+
      'name' => 'description',
    'session'     => $session_id,
+
      'type' => 'text',
    'set_relationship_value' => array(
+
      'label' => 'Description:',
       'module1'     => 'Contacts',
+
      'required' => 0,
       'module1_id' => $contactId,
+
      'options' =>  
       'module2'     => 'Accounts',
+
      array (
      'module2_id'  => $accountId
+
      ),
    )
+
     ),
  );
+
    8 =>  
 
+
    array (
  $result = $soapclient->call('set_relationship', $set_relationship_params);
+
      'name' => 'deleted',
  print "\n <br />Relationship results:<br />\n<pre>\n"; var_export ($result); print "\n</pre>\n";
+
      'type' => 'bool',
 
+
      'label' => 'Deleted',
  */
+
      'required' => 0,
}
+
      'options' =>  
 +
      array (
 +
      ),
 +
    ),
 +
     9 =>  
 +
    array (
 +
      'name' => 'assigned_user_id',
 +
      'type' => 'relate',
 +
      'label' => 'Assigned User',
 +
      'required' => 0,
 +
      'options' =>  
 +
      array (
 +
      ),
 +
    ),
 +
    10 =>  
 +
    array (
 +
      'name' => 'assigned_user_name',
 +
      'type' => 'relate',
 +
      'label' => 'Assigned to:',
 +
       'required' => 0,
 +
      'options' =>  
 +
      array (
 +
      ),
 +
    ),
 +
    11 =>  
 +
    array (
 +
      'name' => 'salutation',
 +
      'type' => 'enum',
 +
      'label' => 'Salutation:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
        0 =>
 +
         array (
 +
          'name' => '',
 +
          'value' => '',
 +
        ),
 +
        1 =>
 +
         array (
 +
          'name' => 'Mr.',
 +
          'value' => 'Mr.',
 +
        ),
 +
        2 =>
 +
         array (
 +
          'name' => 'Ms.',
 +
          'value' => 'Ms.',
 +
        ),
 +
        3 =>
 +
         array (
 +
          'name' => 'Mrs.',
 +
          'value' => 'Mrs.',
 +
        ),
 +
        4 =>
 +
         array (
 +
          'name' => 'Dr.',
 +
          'value' => 'Dr.',
 +
        ),
 +
        5 =>
 +
         array (
 +
          'name' => 'Prof.',
 +
           'value' => 'Prof.',
 +
        ),
 +
      ),
 +
    ),
 +
    12 =>  
 +
    array (
 +
      'name' => 'first_name',
 +
      'type' => 'varchar',
 +
      'label' => 'First Name:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    13 =>
 +
    array (
 +
       'name' => 'last_name',
 +
       'type' => 'varchar',
 +
       'label' => 'Last Name:',
 +
      'required' => 1,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    14 =>
 +
    array (
 +
      'name' => 'title',
 +
      'type' => 'varchar',
 +
      'label' => 'Title:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    15 =>
 +
    array (
 +
      'name' => 'department',
 +
      'type' => 'varchar',
 +
      'label' => 'Department:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    16 =>
 +
    array (
 +
      'name' => 'do_not_call',
 +
      'type' => 'bool',
 +
      'label' => 'Do Not Call:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    17 =>
 +
    array (
 +
      'name' => 'phone_home',
 +
      'type' => 'phone',
 +
      'label' => 'Home:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    18 =>
 +
    array (
 +
      'name' => 'phone_mobile',
 +
      'type' => 'phone',
 +
      'label' => 'Mobile:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    19 =>
 +
    array (
 +
      'name' => 'phone_work',
 +
      'type' => 'phone',
 +
      'label' => 'Office Phone:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    20 =>
 +
    array (
 +
      'name' => 'phone_other',
 +
      'type' => 'phone',
 +
      'label' => 'Other Phone:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    21 =>
 +
    array (
 +
      'name' => 'phone_fax',
 +
      'type' => 'phone',
 +
      'label' => 'Fax:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    22 =>
 +
    array (
 +
      'name' => 'email1',
 +
      'type' => 'varchar',
 +
      'label' => 'Email:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    23 =>
 +
    array (
 +
      'name' => 'email2',
 +
      'type' => 'varchar',
 +
      'label' => 'Other Email:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    24 =>
 +
    array (
 +
      'name' => 'primary_address_street',
 +
      'type' => 'varchar',
 +
      'label' => 'Primary Address Street:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    25 =>
 +
    array (
 +
      'name' => 'primary_address_city',
 +
      'type' => 'varchar',
 +
      'label' => 'Primary Address City:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    26 =>
 +
    array (
 +
      'name' => 'primary_address_state',
 +
      'type' => 'varchar',
 +
      'label' => 'Primary Address State:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    27 =>
 +
    array (
 +
      'name' => 'primary_address_postalcode',
 +
      'type' => 'varchar',
 +
      'label' => 'Primary Address Postal Code:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    28 =>
 +
    array (
 +
      'name' => 'primary_address_country',
 +
      'type' => 'varchar',
 +
      'label' => 'Primary Address Country:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    29 =>
 +
    array (
 +
      'name' => 'alt_address_street',
 +
      'type' => 'varchar',
 +
      'label' => 'Alternate Address Street:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    30 =>
 +
    array (
 +
      'name' => 'alt_address_city',
 +
      'type' => 'varchar',
 +
      'label' => 'Alternate Address City:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    31 =>
 +
    array (
 +
      'name' => 'alt_address_state',
 +
      'type' => 'varchar',
 +
      'label' => 'Alternate Address State:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    32 =>
 +
    array (
 +
      'name' => 'alt_address_postalcode',
 +
      'type' => 'varchar',
 +
      'label' => 'Alternate Address Postal Code:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    33 =>
 +
    array (
 +
      'name' => 'alt_address_country',
 +
      'type' => 'varchar',
 +
      'label' => 'Alternate Address Country:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    34 =>
 +
    array (
 +
      'name' => 'assistant',
 +
      'type' => 'varchar',
 +
      'label' => 'Assistant:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    35 =>
 +
    array (
 +
      'name' => 'assistant_phone',
 +
      'type' => 'phone',
 +
      'label' => 'Assistant Phone:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    36 =>
 +
    array (
 +
      'name' => 'lead_source',
 +
      'type' => 'enum',
 +
      'label' => 'Lead Source:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
        0 =>
 +
        array (
 +
          'name' => '',
 +
          'value' => '',
 +
        ),
 +
        1 =>
 +
        array (
 +
          'name' => 'Cold Call',
 +
          'value' => 'Cold Call',
 +
        ),
 +
        2 =>
 +
        array (
 +
          'name' => 'Existing Customer',
 +
          'value' => 'Existing Customer',
 +
        ),
 +
        3 =>
 +
        array (
 +
          'name' => 'Self Generated',
 +
          'value' => 'Self Generated',
 +
        ),
 +
        4 =>
 +
        array (
 +
          'name' => 'Employee',
 +
          'value' => 'Employee',
 +
        ),
 +
        5 =>
 +
        array (
 +
          'name' => 'Partner',
 +
          'value' => 'Partner',
 +
        ),
 +
        6 =>
 +
        array (
 +
          'name' => 'Public Relations',
 +
          'value' => 'Public Relations',
 +
        ),
 +
        7 =>
 +
        array (
 +
          'name' => 'Direct Mail',
 +
          'value' => 'Direct Mail',
 +
        ),
 +
        8 =>
 +
        array (
 +
          'name' => 'Conference',
 +
          'value' => 'Conference',
 +
        ),
 +
        9 =>
 +
        array (
 +
          'name' => 'Trade Show',
 +
          'value' => 'Trade Show',
 +
        ),
 +
        10 =>
 +
        array (
 +
          'name' => 'Web Site',
 +
          'value' => 'Web Site',
 +
        ),
 +
        11 =>
 +
        array (
 +
          'name' => 'Word of mouth',
 +
          'value' => 'Word of mouth',
 +
        ),
 +
        12 =>
 +
        array (
 +
          'name' => 'Email',
 +
          'value' => 'Email',
 +
        ),
 +
        13 =>
 +
        array (
 +
          'name' => 'Campaign',
 +
          'value' => 'Campaign',
 +
        ),
 +
        14 =>
 +
        array (
 +
          'name' => 'Other',
 +
          'value' => 'Other',
 +
        ),
 +
      ),
 +
    ),
 +
    37 =>
 +
    array (
 +
      'name' => 'account_name',
 +
      'type' => 'relate',
 +
      'label' => 'Account Name:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    38 =>
 +
    array (
 +
      'name' => 'account_id',
 +
      'type' => 'relate',
 +
      'label' => 'Account ID:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    39 =>
 +
    array (
 +
      'name' => 'opportunity_role_fields',
 +
      'type' => 'relate',
 +
      'label' => 'Account Name:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    40 =>
 +
    array (
 +
      'name' => 'reports_to_id',
 +
      'type' => 'id',
 +
      'label' => 'Reports to ID:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    41 =>
 +
    array (
 +
      'name' => 'report_to_name',
 +
      'type' => 'relate',
 +
      'label' => 'Reports To:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    42 =>
 +
    array (
 +
      'name' => 'birthdate',
 +
      'type' => 'date',
 +
      'label' => 'Birthdate:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    43 =>
 +
    array (
 +
      'name' => 'portal_name',
 +
      'type' => 'varchar',
 +
      'label' => 'Portal Name:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    44 =>
 +
    array (
 +
      'name' => 'portal_active',
 +
      'type' => 'bool',
 +
      'label' => 'Portal Active:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    45 =>
 +
    array (
 +
      'name' => 'portal_app',
 +
      'type' => 'varchar',
 +
      'label' => 'Portal Application:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    46 =>
 +
    array (
 +
      'name' => 'campaign_id',
 +
      'type' => 'id',
 +
      'label' => 'Campaign ID',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    47 =>
 +
    array (
 +
      'name' => 'campaign_name',
 +
      'type' => 'relate',
 +
      'label' => 'Campaign:',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    48 =>
 +
    array (
 +
      'name' => 'c_accept_status_fields',
 +
      'type' => 'relate',
 +
      'label' => 'Accept Status',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
    49 =>
 +
    array (
 +
      'name' => 'm_accept_status_fields',
 +
      'type' => 'relate',
 +
      'label' => 'Accept Status',
 +
      'required' => 0,
 +
      'options' =>
 +
      array (
 +
      ),
 +
    ),
 +
  ),
 +
  'error' => '',
 +
)
 
</source>
 
</source>
  
== Conclusion ==
 
In this article we've shown how the SugarCRM system is enterprise-ready in that it has a fully built SOAP service that can be used to integrate the system with one or more 'front-end' websites or applications for data capture.  With important information easily added to the system, it allows the company to focus resources on managing the most valuable assets.  Due to SugarCRM's open source nature and standards support, it's easy to extend and integrate the system with other existing or new infrastructure components. In future articles, we'll take a look at still more interesting integrations with SugarCRM such as collaboration, document management and knowledge management.
 
  
 +
== Some Issues discovered ==
 +
"Import Step 2: Upload Export File" is a confusing title on the second step of the "Import Contacts" wizard.  It could read "Import Step 2: Specify Data File to load"
 +
 +
Typographical bug: I saw that the term "custom_delimeted" is used in a self-contained way in
 +
./modules/Import/language/en_us.lang.php
 +
./modules/Import/ImportStep1.html
 +
./modules/Import/ImportStep2.php
 +
This term is used elsewhere spelled correctly, and thus could potentially lead to a bug down the line.
  
<table class="toc">
+
The source is formatted differently, or practically not at all in some cases, due to various editors using different space and tab settings, even across different Operating Systems which leads to different line endings.  PHPBeautifier used in a commit hook would solve this in the repo.  Coding standards and configuration files like vim modelines would solve this on the developer desktop.
<tr>
 
<td>
 
-- Greg Rundlett
 
<br />
 
Greg Rundlett is an open source technologist.  He currently manages the Technology Services team at [http://www.oasis-open.org OASIS]. 
 
<br />
 
''This website is not affiliated nor endorsed by any third-party .''
 
</td>
 
</tr>
 
</table>
 
 
 
 
 
== Postscript: Some Improvements for SugarCRM ==
 
As with any software, there is always room for improvement.  Here are some minor issues that I noted in the course of writing this article.
 
# "Import Step 2: Upload Export File" is a confusing title on the second step of the "Import Contacts" wizard.  How can one use the words 'import', 'upload', 'export' all at once?  It could read "Import Step 2: Select Data File to load"
 
# Typographical bug: I saw that the term "custom_delimeted" in the language files.  It doesn't actually cause any errors, but b/c the term is used elsewhere (spelled correctly), this typo could potentially lead to a real bug down the line.
 
## ./modules/Import/language/en_us.lang.php
 
## ./modules/Import/ImportStep1.html
 
## ./modules/Import/ImportStep2.php
 
# The source is formatted poorly, or practically not at all in some cases, due to various editors using different space and tab settings, and line endings.  [http://pear.php.net/package/PHP_Beautifier PHP Beautifier] used in a commit hook would solve this in the version control system.  Coding standards and configuration files like vim modelines would solve this on the developer desktop.
 
 
 
Being open source, I can pass this information on to the developers (or even get involved myself by posting articles like this to [http://www.sugarcrm.com/wiki/index.php?title=Main_Page the wiki]) and will likely see a positive response to these suggested fixes.  Note too - SugarCRM fosters an extended community of value-add partners through it's [http://www.sugarforge.org/ forge site].
 
 
 
== Further Resources ==
 
* http://www.sugarcrm.com/wiki/index.php?title=SOAP_Intro_and_Practical_Examples
 
* http://freephile.com/crm/index.php?module=Home&action=TrainingPortal
 
* http://freephile.com/crm/soap.php
 
* http://www.sugarcrm.com/wiki/index.php?title=SOAP_in_PHP
 
* http://dietrich.ganx4.com/nusoap/
 
* http://www.beanizer.org/site/index.php/en/Articles/Sugar-CRM-integration-with-custom-PHP-applications-I.html
 
 
 
[[Category:CRM]]
 
[[Category:Code]]
 
[[Category:Software]]
 

Revision as of 20:33, 4 June 2008

Goal[edit | edit source]

Import records into SugarCRM without using existing functionality, but rather by writing some PHP tool to do the work. Records should go into Accounts and Contacts, which obviously implies a relationship.

Resources Used[edit | edit source]

First I downloaded the source[edit | edit source]

  1. I went to the SugarCRM homepage, and clicked the top navbar link to "Sugar Open Source"
  2. I skipped the "Wizard" and went right to the "Download Page" because I know what I'm doing and also have a pre-existing setup of Linux, Apache MySQL and PHP - so I only want the app
  3. I downloaded SugarCE-5.0.0e.zip (production release)
  4. I visited the recommended "Installation" instructions page at http://www.sugarforge.org/content/installation/
  5. Then I installed it according to the instructions, however I immediately ran into trouble because the instructions did say to chmod 766 all files that needed to be writable by the web_user.
  6. This command renders the directories non-executable which manifests in include errors because the web user (www-data) can not see into those directories (to find includes).
# find directories in the ./crm path and change the mode on them so that all users can execute (see into) the directory 
find ./crm/ -type d |xargs chmod a+x

resolved the include errors

The instructions also fail to mention that the application wants to create a .htaccess file (which doesn't exist in the distribution and would not necessarily be writable to the web user. As a failsafe, the information is printed to the screen in the installer. However it doesn't properly display (lacking newline characters) which would make the content suitable for copy and paste into the file. I found the source which generates the .htaccess content, and used that. An alternative is to simply touch and chmod a .htaccess file prior to running the installer.

Ideas on How to do the import[edit | edit source]

My self-imposed requirement was to capture all of the data provided -- assuming the owner of the data collected it for a reason and that they wouldn't be too happy with a loss of data in a migration to a new application. I looked briefly at the import functionality exposed by the application, but noticed how the lead capture did not reflect the same data profile as the source that I had.

Existing Work[edit | edit source]

My first instinct was to find info about somebody doing this before (e.g. APIs, Documentation, forum questions, Wikis)

I searched the wiki for importing or APIs and quickly found the SOAP Intro and Practical Examples, so I figured I was onto a fast track. However, the soap example worked with a frontend form (which wasn't explained much) leading me to investigate more into what was required by the soap service. When I found the form in "examples", it did not work as an application entry point (because even though it defined ('sugarEntry', true); there was also an IF that pre-empted that definition) because other code was being loaded before the form. I did not immediately see this cause for the example failure, so I put the example form outside the application directory and successfully used the form to insert a single lead This is illustrated at http://www.sugarcrm.com/wiki/index.php?title=Creating_a_lead_capture_form_for_your_website Seeing that the example worked, but did not capture all the details provided in the data exercise, I knew I should look at the existing functionality of modules dealing with Import (dataMaps), the database abstraction layer (SugarBeans and VarDefs) or the database directly to get a clearer picture of what I needed to label everything.

Use the Source Luke[edit | edit source]

My second instinct was to look at the source. Answers are always found in the source, with the caveat that it can be confusing and/or time-consuming to find those answers.

Looking at the full application import routines and the four-step forms for importing leads, it was obvious that there was a lot of machinery that I didn't necessarily need or want to get involved with to simply import records. For instance, I would not want to (re-)write the form and UI handling when I simply needed to insert records into a database. This made me reconsider using the SOAP example to do the job. In essence, it would only need to read the exercise data and create full records for the 50 provided leads.


Note: Soap examples seem to have changed with the addition of a version number, so you must be careful about what example you use, and generally rely on the source to be the definitive source ;-)

Getting on with the soap service, it is easy to discover the service profile and import the data

From the [1] page (which shows the WSDL), we can get a definition of the available SOAP calls. For example, here is the definition of the 'create_account' method

Name: create_account
Binding: sugarsoapBinding
Endpoint: http://freephile.com/crm/soap.php
SoapAction: http://freephile.com/crm/soap.php/create_account
Style: rpc
Input:
  use: encoded
  namespace: http://www.sugarcrm.com/sugarcrm
  encodingStyle: http://schemas.xmlsoap.org/soap/encoding/
  message: create_accountRequest
  parts:
    user_name: xsd:string
    password: xsd:string
    name: xsd:string
    phone: xsd:string
    website: xsd:string
Output:
  use: encoded
  namespace: http://www.sugarcrm.com/sugarcrm
  encodingStyle: http://schemas.xmlsoap.org/soap/encoding/
  message: create_accountResponse
  parts:
    return: xsd:string
Namespace: http://www.sugarcrm.com/sugarcrm
Transport: http://schemas.xmlsoap.org/soap/http
Documentation: 
 
Name: create_contact
Binding: sugarsoapBinding
Endpoint: http://freephile.com/crm/soap.php
SoapAction: http://freephile.com/crm/soap.php/create_contact
Style: rpc
Input:
  use: encoded
  namespace: http://www.sugarcrm.com/sugarcrm
  encodingStyle: http://schemas.xmlsoap.org/soap/encoding/
  message: create_contactRequest
  parts:
    user_name: xsd:string
    password: xsd:string
    first_name: xsd:string
    last_name: xsd:string
    email_address: xsd:string
Output:
  use: encoded
  namespace: http://www.sugarcrm.com/sugarcrm
  encodingStyle: http://schemas.xmlsoap.org/soap/encoding/
  message: create_contactResponse
  parts:
    return: xsd:string
Namespace: http://www.sugarcrm.com/sugarcrm
Transport: http://schemas.xmlsoap.org/soap/http
Documentation: 

Even more detail can be had by inspecting the service.

$interestedModules = array('Accounts', 'Contacts');

foreach ($interestedModules as $module_name) {
  $get_module_fields_params = array (
    'session' => $session_id,
    'module_name' => $module_name
  );
  $result = $soapclient->call('get_module_fields', $get_module_fields_params);
  print "\n $module_name fields:<br />\n<pre>\n"; var_export ($result); print "\n</pre>\n";
}

Accounts fields:[edit | edit source]

array (
  'module_name' => 'Accounts',
  'module_fields' => 
  array (
    0 => 
    array (
      'name' => 'id',
      'type' => 'id',
      'label' => 'ID',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    1 => 
    array (
      'name' => 'name',
      'type' => 'name',
      'label' => 'Name:',
      'required' => 1,
      'options' => 
      array (
      ),
    ),
    2 => 
    array (
      'name' => 'date_entered',
      'type' => 'datetime',
      'label' => 'Date Entered:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    3 => 
    array (
      'name' => 'date_modified',
      'type' => 'datetime',
      'label' => 'Date Modified:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    4 => 
    array (
      'name' => 'modified_user_id',
      'type' => 'assigned_user_name',
      'label' => 'Modified By Id',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    5 => 
    array (
      'name' => 'modified_by_name',
      'type' => 'assigned_user_name',
      'label' => 'Modified By Id',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    6 => 
    array (
      'name' => 'created_by',
      'type' => 'assigned_user_name',
      'label' => 'Created By Id',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    7 => 
    array (
      'name' => 'created_by_name',
      'type' => 'assigned_user_name',
      'label' => 'Created By Id',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    8 => 
    array (
      'name' => 'description',
      'type' => 'text',
      'label' => 'Description:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    9 => 
    array (
      'name' => 'deleted',
      'type' => 'bool',
      'label' => 'Deleted',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    10 => 
    array (
      'name' => 'assigned_user_id',
      'type' => 'relate',
      'label' => 'Assigned User:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    11 => 
    array (
      'name' => 'assigned_user_name',
      'type' => 'relate',
      'label' => 'Assigned to:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    12 => 
    array (
      'name' => 'account_type',
      'type' => 'enum',
      'label' => 'Type:',
      'required' => 0,
      'options' => 
      array (
        0 => 
        array (
          'name' => '',
          'value' => '',
        ),
        1 => 
        array (
          'name' => 'Analyst',
          'value' => 'Analyst',
        ),
        2 => 
        array (
          'name' => 'Competitor',
          'value' => 'Competitor',
        ),
        3 => 
        array (
          'name' => 'Customer',
          'value' => 'Customer',
        ),
        4 => 
        array (
          'name' => 'Integrator',
          'value' => 'Integrator',
        ),
        5 => 
        array (
          'name' => 'Investor',
          'value' => 'Investor',
        ),
        6 => 
        array (
          'name' => 'Partner',
          'value' => 'Partner',
        ),
        7 => 
        array (
          'name' => 'Press',
          'value' => 'Press',
        ),
        8 => 
        array (
          'name' => 'Prospect',
          'value' => 'Prospect',
        ),
        9 => 
        array (
          'name' => 'Reseller',
          'value' => 'Reseller',
        ),
        10 => 
        array (
          'name' => 'Other',
          'value' => 'Other',
        ),
      ),
    ),
    13 => 
    array (
      'name' => 'industry',
      'type' => 'enum',
      'label' => 'Industry:',
      'required' => 0,
      'options' => 
      array (
        0 => 
        array (
          'name' => '',
          'value' => '',
        ),
        1 => 
        array (
          'name' => 'Apparel',
          'value' => 'Apparel',
        ),
        2 => 
        array (
          'name' => 'Banking',
          'value' => 'Banking',
        ),
        3 => 
        array (
          'name' => 'Biotechnology',
          'value' => 'Biotechnology',
        ),
        4 => 
        array (
          'name' => 'Chemicals',
          'value' => 'Chemicals',
        ),
        5 => 
        array (
          'name' => 'Communications',
          'value' => 'Communications',
        ),
        6 => 
        array (
          'name' => 'Construction',
          'value' => 'Construction',
        ),
        7 => 
        array (
          'name' => 'Consulting',
          'value' => 'Consulting',
        ),
        8 => 
        array (
          'name' => 'Education',
          'value' => 'Education',
        ),
        9 => 
        array (
          'name' => 'Electronics',
          'value' => 'Electronics',
        ),
        10 => 
        array (
          'name' => 'Energy',
          'value' => 'Energy',
        ),
        11 => 
        array (
          'name' => 'Engineering',
          'value' => 'Engineering',
        ),
        12 => 
        array (
          'name' => 'Entertainment',
          'value' => 'Entertainment',
        ),
        13 => 
        array (
          'name' => 'Environmental',
          'value' => 'Environmental',
        ),
        14 => 
        array (
          'name' => 'Finance',
          'value' => 'Finance',
        ),
        15 => 
        array (
          'name' => 'Government',
          'value' => 'Government',
        ),
        16 => 
        array (
          'name' => 'Healthcare',
          'value' => 'Healthcare',
        ),
        17 => 
        array (
          'name' => 'Hospitality',
          'value' => 'Hospitality',
        ),
        18 => 
        array (
          'name' => 'Insurance',
          'value' => 'Insurance',
        ),
        19 => 
        array (
          'name' => 'Machinery',
          'value' => 'Machinery',
        ),
        20 => 
        array (
          'name' => 'Manufacturing',
          'value' => 'Manufacturing',
        ),
        21 => 
        array (
          'name' => 'Media',
          'value' => 'Media',
        ),
        22 => 
        array (
          'name' => 'Not For Profit',
          'value' => 'Not For Profit',
        ),
        23 => 
        array (
          'name' => 'Recreation',
          'value' => 'Recreation',
        ),
        24 => 
        array (
          'name' => 'Retail',
          'value' => 'Retail',
        ),
        25 => 
        array (
          'name' => 'Shipping',
          'value' => 'Shipping',
        ),
        26 => 
        array (
          'name' => 'Technology',
          'value' => 'Technology',
        ),
        27 => 
        array (
          'name' => 'Telecommunications',
          'value' => 'Telecommunications',
        ),
        28 => 
        array (
          'name' => 'Transportation',
          'value' => 'Transportation',
        ),
        29 => 
        array (
          'name' => 'Utilities',
          'value' => 'Utilities',
        ),
        30 => 
        array (
          'name' => 'Other',
          'value' => 'Other',
        ),
      ),
    ),
    14 => 
    array (
      'name' => 'annual_revenue',
      'type' => 'varchar',
      'label' => 'Annual Revenue:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    15 => 
    array (
      'name' => 'phone_fax',
      'type' => 'phone',
      'label' => 'Fax:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    16 => 
    array (
      'name' => 'billing_address_street',
      'type' => 'varchar',
      'label' => 'Billing Street:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    17 => 
    array (
      'name' => 'billing_address_city',
      'type' => 'varchar',
      'label' => 'Billing City:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    18 => 
    array (
      'name' => 'billing_address_state',
      'type' => 'varchar',
      'label' => 'Billing State:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    19 => 
    array (
      'name' => 'billing_address_postalcode',
      'type' => 'varchar',
      'label' => 'Billing Postal Code:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    20 => 
    array (
      'name' => 'billing_address_country',
      'type' => 'varchar',
      'label' => 'Billing Country:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    21 => 
    array (
      'name' => 'rating',
      'type' => 'varchar',
      'label' => 'Rating:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    22 => 
    array (
      'name' => 'phone_office',
      'type' => 'phone',
      'label' => 'Phone Office:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    23 => 
    array (
      'name' => 'phone_alternate',
      'type' => 'phone',
      'label' => 'Alternate Phone:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    24 => 
    array (
      'name' => 'website',
      'type' => 'varchar',
      'label' => 'Website:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    25 => 
    array (
      'name' => 'ownership',
      'type' => 'varchar',
      'label' => 'Ownership:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    26 => 
    array (
      'name' => 'employees',
      'type' => 'num',
      'label' => 'Employees:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    27 => 
    array (
      'name' => 'ticker_symbol',
      'type' => 'varchar',
      'label' => 'Ticker Symbol:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    28 => 
    array (
      'name' => 'shipping_address_street',
      'type' => 'varchar',
      'label' => 'Shipping Street:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    29 => 
    array (
      'name' => 'shipping_address_city',
      'type' => 'varchar',
      'label' => 'Shipping City:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    30 => 
    array (
      'name' => 'shipping_address_state',
      'type' => 'varchar',
      'label' => 'Shipping State:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    31 => 
    array (
      'name' => 'shipping_address_postalcode',
      'type' => 'varchar',
      'label' => 'Shipping Postal Code:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    32 => 
    array (
      'name' => 'shipping_address_country',
      'type' => 'varchar',
      'label' => 'Shipping Country:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    33 => 
    array (
      'name' => 'email1',
      'type' => 'varchar',
      'label' => 'Email:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    34 => 
    array (
      'name' => 'parent_id',
      'type' => 'id',
      'label' => 'Parent Account ID',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    35 => 
    array (
      'name' => 'sic_code',
      'type' => 'varchar',
      'label' => 'SIC Code:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    36 => 
    array (
      'name' => 'account_name',
      'type' => 'relate',
      'label' => 'Account Name:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    37 => 
    array (
      'name' => 'parent_name',
      'type' => 'relate',
      'label' => 'Member of:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    38 => 
    array (
      'name' => 'campaign_id',
      'type' => 'id',
      'label' => 'Campaign ID',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
  ),
  'error' => '',
)

Contacts fields:[edit | edit source]

array (
  'module_name' => 'Contacts',
  'module_fields' => 
  array (
    0 => 
    array (
      'name' => 'id',
      'type' => 'id',
      'label' => 'ID:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    1 => 
    array (
      'name' => 'date_entered',
      'type' => 'datetime',
      'label' => 'Date Created',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    2 => 
    array (
      'name' => 'date_modified',
      'type' => 'datetime',
      'label' => 'Date Modified:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    3 => 
    array (
      'name' => 'modified_user_id',
      'type' => 'assigned_user_name',
      'label' => 'Modified By Id',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    4 => 
    array (
      'name' => 'modified_by_name',
      'type' => 'assigned_user_name',
      'label' => 'Modified By Id',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    5 => 
    array (
      'name' => 'created_by',
      'type' => 'assigned_user_name',
      'label' => 'Created By Id',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    6 => 
    array (
      'name' => 'created_by_name',
      'type' => 'assigned_user_name',
      'label' => 'Created By Id',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    7 => 
    array (
      'name' => 'description',
      'type' => 'text',
      'label' => 'Description:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    8 => 
    array (
      'name' => 'deleted',
      'type' => 'bool',
      'label' => 'Deleted',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    9 => 
    array (
      'name' => 'assigned_user_id',
      'type' => 'relate',
      'label' => 'Assigned User',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    10 => 
    array (
      'name' => 'assigned_user_name',
      'type' => 'relate',
      'label' => 'Assigned to:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    11 => 
    array (
      'name' => 'salutation',
      'type' => 'enum',
      'label' => 'Salutation:',
      'required' => 0,
      'options' => 
      array (
        0 => 
        array (
          'name' => '',
          'value' => '',
        ),
        1 => 
        array (
          'name' => 'Mr.',
          'value' => 'Mr.',
        ),
        2 => 
        array (
          'name' => 'Ms.',
          'value' => 'Ms.',
        ),
        3 => 
        array (
          'name' => 'Mrs.',
          'value' => 'Mrs.',
        ),
        4 => 
        array (
          'name' => 'Dr.',
          'value' => 'Dr.',
        ),
        5 => 
        array (
          'name' => 'Prof.',
          'value' => 'Prof.',
        ),
      ),
    ),
    12 => 
    array (
      'name' => 'first_name',
      'type' => 'varchar',
      'label' => 'First Name:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    13 => 
    array (
      'name' => 'last_name',
      'type' => 'varchar',
      'label' => 'Last Name:',
      'required' => 1,
      'options' => 
      array (
      ),
    ),
    14 => 
    array (
      'name' => 'title',
      'type' => 'varchar',
      'label' => 'Title:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    15 => 
    array (
      'name' => 'department',
      'type' => 'varchar',
      'label' => 'Department:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    16 => 
    array (
      'name' => 'do_not_call',
      'type' => 'bool',
      'label' => 'Do Not Call:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    17 => 
    array (
      'name' => 'phone_home',
      'type' => 'phone',
      'label' => 'Home:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    18 => 
    array (
      'name' => 'phone_mobile',
      'type' => 'phone',
      'label' => 'Mobile:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    19 => 
    array (
      'name' => 'phone_work',
      'type' => 'phone',
      'label' => 'Office Phone:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    20 => 
    array (
      'name' => 'phone_other',
      'type' => 'phone',
      'label' => 'Other Phone:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    21 => 
    array (
      'name' => 'phone_fax',
      'type' => 'phone',
      'label' => 'Fax:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    22 => 
    array (
      'name' => 'email1',
      'type' => 'varchar',
      'label' => 'Email:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    23 => 
    array (
      'name' => 'email2',
      'type' => 'varchar',
      'label' => 'Other Email:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    24 => 
    array (
      'name' => 'primary_address_street',
      'type' => 'varchar',
      'label' => 'Primary Address Street:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    25 => 
    array (
      'name' => 'primary_address_city',
      'type' => 'varchar',
      'label' => 'Primary Address City:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    26 => 
    array (
      'name' => 'primary_address_state',
      'type' => 'varchar',
      'label' => 'Primary Address State:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    27 => 
    array (
      'name' => 'primary_address_postalcode',
      'type' => 'varchar',
      'label' => 'Primary Address Postal Code:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    28 => 
    array (
      'name' => 'primary_address_country',
      'type' => 'varchar',
      'label' => 'Primary Address Country:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    29 => 
    array (
      'name' => 'alt_address_street',
      'type' => 'varchar',
      'label' => 'Alternate Address Street:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    30 => 
    array (
      'name' => 'alt_address_city',
      'type' => 'varchar',
      'label' => 'Alternate Address City:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    31 => 
    array (
      'name' => 'alt_address_state',
      'type' => 'varchar',
      'label' => 'Alternate Address State:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    32 => 
    array (
      'name' => 'alt_address_postalcode',
      'type' => 'varchar',
      'label' => 'Alternate Address Postal Code:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    33 => 
    array (
      'name' => 'alt_address_country',
      'type' => 'varchar',
      'label' => 'Alternate Address Country:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    34 => 
    array (
      'name' => 'assistant',
      'type' => 'varchar',
      'label' => 'Assistant:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    35 => 
    array (
      'name' => 'assistant_phone',
      'type' => 'phone',
      'label' => 'Assistant Phone:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    36 => 
    array (
      'name' => 'lead_source',
      'type' => 'enum',
      'label' => 'Lead Source:',
      'required' => 0,
      'options' => 
      array (
        0 => 
        array (
          'name' => '',
          'value' => '',
        ),
        1 => 
        array (
          'name' => 'Cold Call',
          'value' => 'Cold Call',
        ),
        2 => 
        array (
          'name' => 'Existing Customer',
          'value' => 'Existing Customer',
        ),
        3 => 
        array (
          'name' => 'Self Generated',
          'value' => 'Self Generated',
        ),
        4 => 
        array (
          'name' => 'Employee',
          'value' => 'Employee',
        ),
        5 => 
        array (
          'name' => 'Partner',
          'value' => 'Partner',
        ),
        6 => 
        array (
          'name' => 'Public Relations',
          'value' => 'Public Relations',
        ),
        7 => 
        array (
          'name' => 'Direct Mail',
          'value' => 'Direct Mail',
        ),
        8 => 
        array (
          'name' => 'Conference',
          'value' => 'Conference',
        ),
        9 => 
        array (
          'name' => 'Trade Show',
          'value' => 'Trade Show',
        ),
        10 => 
        array (
          'name' => 'Web Site',
          'value' => 'Web Site',
        ),
        11 => 
        array (
          'name' => 'Word of mouth',
          'value' => 'Word of mouth',
        ),
        12 => 
        array (
          'name' => 'Email',
          'value' => 'Email',
        ),
        13 => 
        array (
          'name' => 'Campaign',
          'value' => 'Campaign',
        ),
        14 => 
        array (
          'name' => 'Other',
          'value' => 'Other',
        ),
      ),
    ),
    37 => 
    array (
      'name' => 'account_name',
      'type' => 'relate',
      'label' => 'Account Name:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    38 => 
    array (
      'name' => 'account_id',
      'type' => 'relate',
      'label' => 'Account ID:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    39 => 
    array (
      'name' => 'opportunity_role_fields',
      'type' => 'relate',
      'label' => 'Account Name:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    40 => 
    array (
      'name' => 'reports_to_id',
      'type' => 'id',
      'label' => 'Reports to ID:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    41 => 
    array (
      'name' => 'report_to_name',
      'type' => 'relate',
      'label' => 'Reports To:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    42 => 
    array (
      'name' => 'birthdate',
      'type' => 'date',
      'label' => 'Birthdate:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    43 => 
    array (
      'name' => 'portal_name',
      'type' => 'varchar',
      'label' => 'Portal Name:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    44 => 
    array (
      'name' => 'portal_active',
      'type' => 'bool',
      'label' => 'Portal Active:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    45 => 
    array (
      'name' => 'portal_app',
      'type' => 'varchar',
      'label' => 'Portal Application:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    46 => 
    array (
      'name' => 'campaign_id',
      'type' => 'id',
      'label' => 'Campaign ID',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    47 => 
    array (
      'name' => 'campaign_name',
      'type' => 'relate',
      'label' => 'Campaign:',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    48 => 
    array (
      'name' => 'c_accept_status_fields',
      'type' => 'relate',
      'label' => 'Accept Status',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
    49 => 
    array (
      'name' => 'm_accept_status_fields',
      'type' => 'relate',
      'label' => 'Accept Status',
      'required' => 0,
      'options' => 
      array (
      ),
    ),
  ),
  'error' => '',
)


Some Issues discovered[edit | edit source]

"Import Step 2: Upload Export File" is a confusing title on the second step of the "Import Contacts" wizard. It could read "Import Step 2: Specify Data File to load"

Typographical bug: I saw that the term "custom_delimeted" is used in a self-contained way in

./modules/Import/language/en_us.lang.php
./modules/Import/ImportStep1.html
./modules/Import/ImportStep2.php

This term is used elsewhere spelled correctly, and thus could potentially lead to a bug down the line.

The source is formatted differently, or practically not at all in some cases, due to various editors using different space and tab settings, even across different Operating Systems which leads to different line endings. PHPBeautifier used in a commit hook would solve this in the repo. Coding standards and configuration files like vim modelines would solve this on the developer desktop.