Implementing two-way catalog synchronization with an ERP system
ERP (SAP, Oracle NetSuite, Microsoft Dynamics, Odoo) — enterprise resource planning system. Unlike 1C, ERP systems have mature REST APIs or SOAP/OData interfaces, but each with its own data model and versioning logic.
Integration protocol options
| ERP | Protocol | Format |
|---|---|---|
| SAP S/4HANA | OData v4, REST | JSON/XML |
| Oracle NetSuite | REST (SuiteQL) | JSON |
| Microsoft Dynamics 365 | OData v4 | JSON |
| Odoo | JSON-RPC / REST | JSON |
| 1C:ERP | CommerceML + REST | XML/JSON |
Integration pattern: Event-Driven vs Polling
Polling — site periodically requests changes from ERP. Simpler to implement, but creates delays.
Webhooks / Change Data Capture — ERP notifies site of each change. Minimal delays, but requires ERP support.
Hybrid approach (recommended): webhooks for critical data (prices, inventory), polling hourly for less urgent (descriptions, characteristics).
Example: Odoo integration
import xmlrpc.client
class OdooConnector:
def __init__(self, url, db, username, password):
self.url = url
self.db = db
# Authentication
common = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/common')
self.uid = common.authenticate(db, username, password, {})
self.models = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/object')
def get_products(self, since: datetime = None):
domain = [['active', '=', True]]
if since:
domain.append(['write_date', '>', since.isoformat()])
return self.models.execute_kw(
self.db, self.uid, self.password,
'product.template', 'search_read',
[domain],
{'fields': ['id', 'name', 'default_code', 'list_price',
'qty_available', 'categ_id', 'description_sale']}
)
Processing changes
class ERPSyncService:
def sync_products(self):
last_sync = SyncState.get_last_sync('erp_products')
products = self.erp.get_products(since=last_sync)
updated = 0
for erp_product in products:
product, created = Product.objects.update_or_create(
erp_id=erp_product['id'],
defaults={
'name': erp_product['name'],
'sku': erp_product.get('default_code', ''),
'price': erp_product['list_price'],
'stock': erp_product['qty_available'],
'category': self.map_category(erp_product['categ_id']),
}
)
updated += 1
SyncState.update_last_sync('erp_products', datetime.now())
return updated
Timeline
Integration with specific ERP via API with two-way synchronization: 12–20 working days depending on API documentation quality and ERP test environment availability.







