CRM Integration Architecture
CRM Integration Overview
┌─────────────┠┌──────────────────┠┌─────────────â”
│ Magento │◄───►│ CRM Connector │◄───►│ Salesforce/ │
│ 2 Store │ │ (Sync Engine) │ │ HubSpot │
└─────────────┘ └──────────────────┘ └─────────────┘
│ │ │
Customer Data Contact Sync CRM Records
Order Data Lead Mapping Opportunities
Cart Data Opportunity Sync Campaigns
CRM Adapter Interface
namespace Vendor\Integration\Model\Crm;
interface CrmAdapterInterface
{
/**
* Sync customer to CRM
*/
public function syncCustomer(CustomerInterface $customer): CrmResult;
/**
* Sync order as opportunity
*/
public function syncOrderAsOpportunity(OrderInterface $order): CrmResult;
/**
* Pull CRM contact data
*/
public function pullContact(string $crmId): ContactData;
/**
* Sync abandoned cart as lead
*/
public function syncCartAsLead(CartInterface $cart): CrmResult;
}
Salesforce Adapter
namespace Vendor\Integration\Model\Crm\Salesforce;
class SalesforceAdapter implements CrmAdapterInterface
{
private SalesforceClient $client;
private FieldMapperInterface $fieldMapper;
public function syncCustomer(CustomerInterface $customer): CrmResult
{
$mappedData = $this->fieldMapper->mapCustomer($customer);
$response = $this->client->upsert('Contact', [
'ExternalId__c' => $customer->getId(),
'FirstName' => $customer->getFirstname(),
'LastName' => $customer->getLastname(),
'Email' => $customer->getEmail(),
'Phone' => $customer->getPhone(),
'MailingStreet' => $customer->getStreetFull(),
'MailingCity' => $customer->getCity(),
'MailingState' => $customer->getRegion()->getRegionCode(),
'MailingPostalCode' => $customer->getPostcode(),
'MailingCountry' => $customer->getCountryId(),
]);
return new CrmResult([
'success' => true,
'crm_id' => $response['id'],
'action' => $response['created'] ? 'created' : 'updated',
]);
}
}
Customer Data Sync
Sync Strategy
namespace Vendor\Integration\Model\Crm\Sync;
class CustomerSyncStrategy
{
private CrmAdapterInterface $crmAdapter;
private CustomerRepositoryInterface $customerRepo;
private SyncLogInterface $syncLog;
public function syncAllCustomers(int $pageSize = 100): SyncReport
{
$report = new SyncReport();
$page = 1;
do {
$searchResult = $this->customerRepo->getList(
$this->createSearchCriteria($page, $pageSize)
);
foreach ($searchResult->getItems() as $customer) {
try {
$result = $this->crmAdapter->syncCustomer($customer);
$report->addSuccess($customer->getId());
$this->syncLog->logSync(
$customer->getId(),
'customer',
$result
);
} catch (\Exception $e) {
$report->addFailure($customer->getId(), $e->getMessage());
}
}
$page++;
} while ($searchResult->getTotalCount() > $page * $pageSize);
return $report;
}
}
Webhook for Real-time Sync
namespace Vendor\Integration\Observer;
class CustomerSaveAfter implements ObserverInterface
{
private CrmAdapterInterface $crmAdapter;
private ConfigInterface $config;
public function execute(Observer $observer): void
{
if (!$this->config->isRealtimeSyncEnabled()) {
return;
}
$customer = $observer->getEvent()->getCustomer();
$this->crmAdapter->syncCustomer($customer);
}
}
Lead and Opportunity Management
Abandoned Cart to Lead
namespace Vendor\Integration\Model\Crm\Cart;
class AbandonedCartToLead
{
private CrmAdapterInterface $crmAdapter;
public function process(CartInterface $cart): CrmResult
{
$leadData = [
'FirstName' => $cart->getCustomerFirstname() ?: 'Guest',
'LastName' => 'Cart Abandoner',
'Email' => $cart->getCustomerEmail(),
'Company' => 'Magento Store',
'LeadSource' => 'Website',
'Description' => sprintf(
'Abandoned cart #%s with %d items, "total": %s',
$cart->getId(),
$cart->getItemsCount(),
$cart->getGrandTotal()
),
'Amount' => $cart->getGrandTotal(),
];
return $this->crmAdapter->syncCartAsLead($cart);
}
}
Order to Opportunity
namespace Vendor\Integration\Model\Crm\Order;
class OrderToOpportunity
{
public function convert(OrderInterface $order): OpportunityData
{
return new OpportunityData([
'Name' => sprintf('Order #%s', $order->getIncrementId()),
'AccountId' => $this->getAccountId($order),
'Amount' => $order->getGrandTotal(),
'CloseDate' => $order->getCreatedAt(),
'StageName' => 'Closed Won',
'Description' => $this->buildDescription($order),
'Magento_Order_Id__c' => $order->getIncrementId(),
]);
}
}
```"
},
{
"id": "ch4",
"title": "Field Mapping and Transformation",
"content": "## Field Mapping Configuration
```php
namespace Vendor\Integration\Model\Crm\Mapping;
interface FieldMapperInterface
{
public function mapCustomer(CustomerInterface $customer): array;
public function mapOrder(OrderInterface $order): array;
public function reverseMap(array $crmData): array;
}
class ConfigurableFieldMapper implements FieldMapperInterface
{
private array $fieldMap;
public function __construct(array $fieldMap = [])
{
$this->fieldMap = $fieldMap;
}
public function mapCustomer(CustomerInterface $customer): array
{
$mapped = [];
foreach ($this->fieldMap as $magentoField => $crmField) {
$value = $this->getValue($customer, $magentoField);
$mapped[$crmField] = $this->transform($value, $crmField);
}
return $mapped;
}
}
di.xml Mapping Configuration
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Vendor\Integration\Model\Crm\Mapping\ConfigurableFieldMapper">
<arguments>
<argument name="fieldMap" xsi:type="array">
<item name="firstname" xsi:type="string">FirstName</item>
<item name="lastname" xsi:type="string">LastName</item>
<item name="email" xsi:type="string">Email</item>
<item name="phone" xsi:type="string">Phone</item>
<item name="taxvat" xsi:type="string">TaxId__c</item>
</argument>
</arguments>
</type>
</config>
Quiz
1. What does a CRM adapter do?
2. How can abandoned carts become CRM leads?
3. What is field mapping in CRM integration?
Flashcards
Question
What does a CRM adapter provide?
Click to reveal answer
Answer
Translation layer between Magento and CRM systems
Question
How to sync in real-time?
Click to reveal answer
Answer
Use observers on save events to trigger CRM sync
Question
What is field mapping?
Click to reveal answer
Answer
Configurable translation between Magento and CRM fields
Question
What data can sync to CRM?
Click to reveal answer
Answer
Customers, orders, carts, leads, opportunities
Revision Notes
Key Takeaways
- 1. CRM adapters provide standardized integration interfaces
- 2. Real-time sync uses observers on entity save events
- 3. Batch sync is more efficient for bulk operations
- 4. Field mapping translates attribute names between systems
- 5. Abandoned carts can automatically become CRM leads
Interview Tips
- • Explain real-time vs batch sync trade-offs
- • Discuss how field mapping handles different data formats
- • Describe the lifecycle of a customer sync
- • Talk about error handling in CRM integrations
Cheat Sheet
CRM Integration:
Adapter → Salesforce/HubSpot/Custom
Real-time → Observer + async queue
Batch → Cron job + pagination
Field Mapping:
firstname → FirstName
lastname → LastName
email → Email
phone → Phone
Sync Types:
Customer → Contact
Order → Opportunity
Cart → Lead