StabisoDocs

Sales and customers

Importing a Salesforce export

A company moving from Salesforce brings its CRM over in the files Salesforce exports: its people, accounts, products and prices, its deals and the calls, emails, meetings, tasks and notes about them. The import reads them one object at a time, checks each file with a dry run that saves nothing, and imports it only when the file has no problem at all. Each record keeps its Salesforce id, so importing the same file again, or a newer export, brings over only what is new. It is the data import of vendors and customers, made for Salesforce's files. The design is ADR-0084.

Screen: Settings → Data Import → Import from Salesforce (/settings/import/salesforce), or "import from Salesforce" in the search bar.

POST /v1/entities/{entity}/imports/salesforce
     multipart: file, object, mode (dry_run | commit), mapping (JSON, optional)

A commit needs an Idempotency-Key; it answers 422 import_has_problems with every problem when the file has one, and changes nothing. Agents never import (403). Every commit is audited (import.salesforce, with the file's name, SHA-256, rows and what it created).

The files

Salesforce writes the files in Setup → Data Export (the weekly export, one CSV per object) or with Data Loader; a report exported as CSV or Excel works too. An export names its columns by API name (BillingCity), a report by label (Billing City); the import knows both. A file holds at most 10,000 rows and 20 MB.

Import them in this order, since each object links to the ones before it:

Step Object Salesforce file Becomes
1 Users User.csv a link to the person here with the same email (owners, assignees)
2 Accounts Account.csv customers, with their parent companies
3 Contacts Contact.csv the contacts of those customers
4 Products Product2.csv products
5 Price books Pricebook2.csv noted (which one is the standard book)
6 Price book entries PricebookEntry.csv list prices, and prices on price lists
7 Opportunities Opportunity.csv deals of the sales pipeline, open, won and lost
8 Tasks Task.csv tasks, calls and emails on the timeline
9 Events Event.csv meetings
10 Notes Note.csv notes

Mapping the columns

The dry run lists each of our fields and the column of the file it is read from. Any of them can be pointed at another column (a custom field such as Region__c) or at none; the file is checked again at once. Columns the import does not read are listed and left alone. Every problem and note names the file's own column and line.

The organization's own fields of companies, contacts and deals are fields of the accounts, contacts and opportunities files too (custom.<key>): each is read from the column <key>__c, Salesforce's name for a custom field (industry from Industry__c), or from a column named as the field, or from the column chosen. A value is checked as any value of the field: a choice that is not one of its choices is a problem of its line.

What each object becomes

Users. A user is linked to the person of the organization with the same email; a user without one is skipped with a note, and the records they own are imported without an owner.

Accounts. An account becomes a customer through the same service as one entered by hand, so the customer approval policy applies: customers that wait for activation are counted, with a link to Approvals. Its code is the AccountNumber, else (none, or one another customer has) the company's next customer number (C-00001). Its billing address is split into street and number; a country name or code in English, German, French or Italian is read, an empty country is the company's (with a note). A US state or Canadian province is kept for sales tax. A VAT number in a custom field is kept; one that fails its check is marked unverified. The description becomes a note. An account whose code and name, or name alone, is already a customer here is linked to that customer rather than doubled. A deleted account is skipped. An account's parent (ParentId) is its parent company here: the file is imported parents first, whatever its order; a parent that is not imported leaves the customer without one, with a note.

Contacts. A contact becomes a contact of the customer its account became: first and last name, its title (else its department) as role, email, phone, mobile, the email opt-out (HasOptedOutOfEmail) and, when the file has one, its language (a code such as de or fr_CH, or a name such as Deutsch). Its description becomes a note on the customer with the contact. A person already at the customer (the same email, else the same name) is linked rather than doubled. A contact whose account is not imported is a problem; one at no account (a private contact) is skipped with a note.

Products. A product is booked to the company's default revenue account. Salesforce does not say whether a product is goods or a service, which decides its VAT: without a column saying so it is a service, and the import says how many to check. A billing frequency of Monthly or Annual makes a recurring product priced per month or year. Its code is the ProductCode, else (none, or one that is taken or not a code) the company's next product number (P-00001).

Prices. An entry of the standard price book is the product's list price in its currency. An entry of another price book is a price on a price list, one list per price book and currency. An entry that uses the standard price, or is inactive, adds nothing.

Opportunities. A deal names its customer by its account, or, when the account was not imported, a prospect by the account's name. Salesforce's standard stages map to ours (Qualification and Needs Analysis are Qualified, Proposal/Price Quote is Proposal, Negotiation/Review is Negotiation); a stage of its own takes the stage its probability falls in. A closed deal is won or lost on its close date; a won deal needs an active customer, a lost one keeps its loss reason. Amounts stay in the deal's currency. Its ContactId is the person it is with, when that contact is one of its customer's.

Tasks, events, notes. Each lands on the timeline of the deal or customer it is about, or of the customer of the contact it names, and keeps the contact it was with (WhoId). A task of subtype Call or Email is a call or email; a completed one is done on its completion day. One about a record the import does not bring over (a lead, a case) is skipped with a note.

Nothing twice

Each imported record is kept in external_record with its Salesforce object and id (15-character ids, as in reports, and 18-character ids are the same record), the record it became, and the file it came from. A record already imported is counted as such and left as it is; the import never overwrites what was changed here since. A customer or contact merged into another here since (a duplicate, ADR-0089) is followed to the one that stays: a later deal, contact or task about it lands there, never on the merged one. The links are part of the company's data export.

Stabiso, the Enterprise System of Record · generated from the code and its guides · release 6f03a5e846b3