Integration Architecture Overview
Integration Types
ERP Integration:
├── Product catalog sync
├── Inventory sync
├── Order export
├── Customer sync
└── Financial data
CRM Integration:
├── Customer data sync
├── Order history
├── Support tickets
└── Marketing data
Third-party:
├── Shipping carriers
├── Payment gateways
├── Tax services
└── Analytics
Integration Patterns
1. Point-to-Point:
System A ↔ System B
Simple, but doesn't scale
2. Hub-and-Spoke:
System A ↔ Hub ↔ System B
Centralized, easier management
3. Event-Driven:
System A → Event Bus → System B
Loose coupling, scalable
4. API Gateway:
Client → Gateway → Multiple Systems
Single entry point, rate limiting
Data Flow
Magento 2 Integration:
├── Outbound (Magento → External)
│ ├── Product updates
│ ├── Order exports
│ ├── Customer sync
│ └── Inventory updates
├── Inbound (External → Magento)
│ ├── Product imports
│ ├── Price updates
│ ├── Inventory updates
│ └── Customer imports
└── Bidirectional
├── Real-time sync
├── Batch sync
└── Event-based sync
ERP Integration Patterns
Product Sync
// ERP product import
class ErpProductImport
{
public function importProducts($products)
{
foreach ($products as $erpProduct) {
// Map ERP data to Magento
$productData = $this->mapProductData($erpProduct);
// Check if product exists
$existing = $this->productRepository->get(
$productData['sku'],
false
);
if ($existing) {
// Update existing product
$existing->addData($productData);
$this->productRepository->save($existing);
} else {
// Create new product
$product = $this->productFactory->create();
$product->addData($productData);
$this->productRepository->save($product);
}
// Sync inventory
$this->inventoryService->updateStock(
$productData['sku'],
$erpProduct['stock']
);
}
}
private function mapProductData($erpProduct)
{
return [
'sku' => $erpProduct['item_code'],
'name' => $erpProduct['description'],
'price' => $erpProduct['unit_price'],
'qty' => $erpProduct['quantity_on_hand'],
'status' => $erpProduct['is_active'] ? 1 : 0,
'weight' => $erpProduct['weight'],
'description' => $erpProduct['long_description']
];
}
}
Order Export
// Export order to ERP
class OrderExportService
{
public function exportOrder($order)
{
$erpOrder = $this->mapOrderData($order);
// Send to ERP
$response = $this->erpClient->createOrder($erpOrder);
if ($response->isSuccess()) {
// Update order with ERP reference
$order->setData('erp_order_id', $response->getOrderId());
$order->addStatusHistoryComment(
'Exported to ERP: ' . $response->getOrderId()
);
$order->save();
} else {
throw new \Exception('ERP export failed: ' . $response->getMessage());
}
}
private function mapOrderData($order)
{
return [
'customer_id' => $order->getCustomerErpId(),
'po_number' => $order->getPoNumber(),
'items' => array_map(function($item) {
return [
'sku' => $item->getSku(),
'qty' => $item->getQtyOrdered(),
'price' => $item->getPrice()
];
}, $order->getItems()),
'shipping_address' => $this->mapAddress($order->getShippingAddress()),
'totals' => [
'subtotal' => $order->getSubtotal(),
'tax' => $order->getTaxAmount(),
'shipping' => $order->getShippingAmount(),
'total' => $order->getGrandTotal()
]
];
}
}
Inventory Sync
// Real-time inventory sync
class InventorySyncService
{
public function syncInventory($sku, $qty, $sourceCode)
{
// Update Magento inventory
$this->inventoryService->updateStock($sku, $sourceCode, $qty);
// Send to ERP
$this->erpClient->updateInventory([
'sku' => $sku,
'warehouse' => $sourceCode,
'quantity' => $qty
]);
// Update search index
$this->searchService->updateStock($sku, $qty);
}
// Batch sync
public function batchSync($inventoryData)
{
foreach ($inventoryData as $item) {
$this->syncInventory(
$item['sku'],
$item['qty'],
$item['source']
);
}
}
}
Message Queue Design
Queue Architecture
Message Queue System:
├── Producers
│ ├── Order creation
│ ├── Product update
│ └── Inventory change
├── Queues
│ ├── order.export
│ ├── product.sync
│ ├── inventory.update
│ └── notification.send
├── Consumers
│ ├── ERP sync worker
│ ├── Search indexer
│ ├── Email sender
│ └── Analytics processor
└── Dead Letter Queue
└── Failed messages
Queue Implementation
// Producer
class MessageProducer
{
public function send($queue, $message, $options = [])
{
$this->queue->sendMessage($queue, json_encode($message), $options);
}
}
// Consumer
class ErpSyncConsumer
{
public function process(MessageInterface $message)
{
$data = json_decode($message->getBody(), true);
try {
switch ($data['type']) {
case 'order':
$this->orderExportService->exportOrder($data['order_id']);
break;
case 'product':
$this->productSyncService->syncProduct($data['product_id']);
break;
case 'inventory':
$this->inventorySyncService->syncInventory(
$data['sku'],
$data['qty']
);
break;
}
// Acknowledge message
$this->queue->acknowledge($message);
} catch (\Exception $e) {
$this->logger->error('Queue processing failed', [
'error' => $e->getMessage(),
'message' => $message->getBody()
]);
// Retry or dead letter
if ($message->getRedeliveryCount() >= 3) {
$this->queue->deadLetter($message);
} else {
$this->queue->retry($message);
}
}
}
}
Queue Configuration
<!-- queue_consumer.xml -->
<config>
<queue name="order.export">
<consumer name="erp.order.export"
queue="order.export"
handler="Vendor\Module\Consumer\ErpOrderExport::process"
maxMessages="100"/>
</queue>
<queue name="product.sync">
<consumer name="erp.product.sync"
queue="product.sync"
handler="Vendor\Module\Consumer\ErpProductSync::process"/>
</queue>
</config>
Webhook Design
Webhook System
// Webhook manager
class WebhookManager
{
public function register($event, $url, $secret)
{
$webhook = $this->webhookFactory->create();
$webhook->setEvent($event);
$webhook->setUrl($url);
$webhook->setSecret($secret);
$webhook->setIsActive(true);
$this->webhookRepository->save($webhook);
}
public function dispatch($event, $data)
{
$webhooks = $this->webhookRepository->getByEvent($event);
foreach ($webhooks as $webhook) {
$this->sendWebhook($webhook, $data);
}
}
private function sendWebhook($webhook, $data)
{
$payload = json_encode([
'event' => $webhook->getEvent(),
'data' => $data,
'timestamp' => time()
]);
// Generate signature
$signature = hash_hmac('sha256', $payload, $webhook->getSecret());
// Send request
$response = $this->httpClient->post($webhook->getUrl(), [
'headers' => [
'Content-Type' => 'application/json',
'X-Webhook-Signature' => $signature,
'X-Webhook-Event' => $webhook->getEvent()
],
'body' => $payload
]);
// Log result
$this->logWebhook($webhook, $response);
}
}
Webhook Security
// Verify webhook signature
public function verifySignature($payload, $signature, $secret)
{
$expected = hash_hmac('sha256', $payload, $secret);
return hash_equals($expected, $signature);
}
// Rate limiting
public function checkRateLimit($webhookId)
{
$key = 'webhook_' . $webhookId . '_rate';
$count = $this->cache->increment($key);
if ($count > 100) { // 100 requests per hour
throw new \Exception('Rate limit exceeded');
}
if ($count === 1) {
$this->cache->save('1', $key, [], 3600);
}
}
Practice Problems
Design ERP integration for real-time inventory sync and batch order export.
Solution
// System:
// 1. Inventory: Real-time sync via queue
// 2. Orders: Batch export every 5 min
// 3. Products: Nightly full sync
// 4. Errors: Retry + dead letter
// 5. Monitoring: Queue depth, failure rate
// 6. Fallback: Manual sync option Quiz
1. What is the benefit of event-driven integration?
2. What is the purpose of message queues?
3. What is a dead letter queue?
4. How should webhook signatures be verified?
Flashcards
Question
Event-driven integration benefit?
Click to reveal answer
Answer
Loose coupling between systems
Question
Message queue purpose?
Click to reveal answer
Answer
Async processing and load leveling
Question
Dead letter queue?
Click to reveal answer
Answer
Failed messages that can't be processed
Question
Webhook signature verification?
Click to reveal answer
Answer
HMAC signature with shared secret
Question
ERP integration patterns?
Click to reveal answer
Answer
Product sync, order export, inventory sync
Revision Notes
Key Takeaways
- 1. Event-driven: Loose coupling, scalable
- 2. Message queues: Async processing, load leveling
- 3. Dead letter queue: Failed message handling
- 4. Webhooks: HMAC signature verification
- 5. ERP: Product, order, inventory sync
Interview Tips
- • Compare integration patterns
- • Explain message queue benefits
- • Discuss webhook security
- • Know ERP integration requirements
Cheat Sheet
Integration Design
- Event-driven: Loose coupling
- Queues: Async, load leveling
- Dead letter: Failed messages
- Webhooks: HMAC verification
- ERP: Product, order, inventory sync