Hazır ERP bağlayıcıları kullanım durumlarının %70’ini kapsar. Geriye kalan %30 — özel alanlar, karmaşık fiyatlandırma kuralları, çoklu depo mantığı, onay iş akışları — özel bir bağlayıcı gerektirir. İşte güvenilir, sürdürülebilir ve üretime hazır bir bağlayıcı nasıl geliştirileceği.

Mimari

Özel bir bağlayıcı, WooCommerce ve ERP’niz arasında yer alan bir middleware servisidir:

┌─────────────┐     ┌──────────────────┐     ┌──────────┐

│ WooCommerce │────>│ Middleware │────>│ ERP │

│ REST API │<────│ (Node.js/Python) │<────│ API │

└─────────────┘ │ │ └──────────┘

│ ┌────────────┐ │

│ │ Queue │ │

│ │ (Redis) │ │

│ └────────────┘ │

│ ┌────────────┐ │

│ │ DB │ │

│ │ (mapping) │ │

│ └────────────┘ │

└──────────────────┘

Senkronizasyon Motoru

Bağlayıcınızın çekirdeği, veriyi her iki yönde işleyen bir senkronizasyon motorudur:

class SyncEngine {

constructor(wooClient, erpClient, db) {

this.woo = wooClient;

this.erp = erpClient;

this.db = db;

this.queue = new Queue('sync-jobs');

}

// Product sync: ERP → WooCommerce

async syncProducts() {

const lastSync = await this.db.getLastSync('products');

const erpProducts = await this.erp.getModifiedProducts(lastSync);

for (const product of erpProducts) {

await this.queue.add('sync-product', {

erpId: product.id,

data: product

});

}

}

// Order sync: WooCommerce → ERP

async syncOrders() {

const lastSync = await this.db.getLastSync('orders');

const wcOrders = await this.woo.getOrdersSince(lastSync);

for (const order of wcOrders) {

await this.queue.add('sync-order', {

wcOrderId: order.id,

data: order

});

}

}

}

Veri Eşleme Katmanı

En kritik bileşen. Senkronizasyon mantığınızdan ayrı bir eşleme konfigürasyonu oluşturun:

// mapping.js

const PRODUCT_MAPPING = {

// ERP field → WooCommerce field

'item_code': 'sku',

'item_name': 'name',

'description': { field: 'description', transform: 'htmlEncode' },

'unit_price': { field: 'regular_price', transform: 'toString' },

'stock_qty': { field: 'stock_quantity', transform: 'parseInt' },

'is_active': { field: 'status', transform: (val) => val ? 'publish' : 'draft' },

'weight_kg': { field: 'weight', transform: 'toString' },

'category_code': { field: 'categories', transform: 'mapCategory' }

};

const ORDER_MAPPING = {

// WooCommerce field → ERP field

'id': 'external_ref',

'billing.email': 'customer_email',

'billing.first_name': { field: 'customer_name', transform: 'combineName' },

'line_items': { field: 'order_lines', transform: 'mapLineItems' },

'total': { field: 'order_total', transform: 'parseFloat' }

};

function applyMapping(source, mapping) {

const result = {};

for (const [sourceKey, target] of Object.entries(mapping)) {

const value = getNestedValue(source, sourceKey);

if (typeof target === 'string') {

result[target] = value;

} else {

const transformed = transforms[target.transform]

? transforms[target.transform](value, source)

: value;

result[target.field] = transformed;

}

}

return result;

}

Kuyruk Tabanlı İşleme

Senkronizasyonları asla satır içinde işlemeyin. Güvenilirlik için iş kuyruğu kullanın:

const Queue = require('bull');

const syncQueue = new Queue('erp-sync', {

redis: { host: '127.0.0.1', port: 6379 },

defaultJobOptions: {

attempts: 3,

backoff: { type: 'exponential', delay: 2000 },

removeOnComplete: 100,

removeOnFail: 500

}

});

// Process product sync jobs

syncQueue.process('sync-product', async (job) => {

const { erpId, data } = job.data;

// Check if product exists in WooCommerce

const mapping = await db.getMapping('product', erpId);

if (mapping) {

// Update existing product

await wooClient.updateProduct(mapping.wc_id, applyMapping(data, PRODUCT_MAPPING));

} else {

// Create new product

const wcProduct = await wooClient.createProduct(applyMapping(data, PRODUCT_MAPPING));

await db.createMapping('product', erpId, wcProduct.id);

}

return { success: true, erpId };

});

// Handle failures

syncQueue.on('failed', (job, err) => {

console.error(Job ${job.id} failed: ${err.message});

if (job.attemptsMade >= job.opts.attempts) {

alertTeam(Sync failed permanently: ${job.data.erpId} - ${err.message});

}

});

ID Eşleme Tablosu

WooCommerce ID’leri ve ERP ID’leri farklıdır. Bir eşleme tablosu tutun:

CREATE TABLE entity_mapping (

id INT AUTO_INCREMENT PRIMARY KEY,

entity_type ENUM('product', 'customer', 'order', 'category') NOT NULL,

erp_id VARCHAR(100) NOT NULL,

wc_id INT NOT NULL,

last_synced_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

sync_hash VARCHAR(64), -- Hash of data to detect changes

UNIQUE KEY (entity_type, erp_id),

INDEX (entity_type, wc_id)

);

sync_hash alanı gereksiz güncellemeleri önler. ERP verisi son senkronizasyondan bu yana değişmemişse, WooCommerce API çağrısını atlayın.

function hasChanged(currentData, storedHash) {

const currentHash = crypto.createHash('md5')

.update(JSON.stringify(currentData))

.digest('hex');

return currentHash !== storedHash;

}

Webhook Alıcısı

Gerçek zamanlı sipariş senkronizasyonu için WooCommerce webhook’larını alın:

app.post('/webhooks/woocommerce/order-created', (req, res) => {

// Verify webhook signature

const signature = req.headers['x-wc-webhook-signature'];

const expected = crypto.createHmac('sha256', WEBHOOK_SECRET)

.update(JSON.stringify(req.body))

.digest('base64');

if (signature !== expected) {

return res.status(401).send('Invalid signature');

}

// Queue the order for processing

syncQueue.add('sync-order', {

wcOrderId: req.body.id,

data: req.body

});

res.status(200).send('OK');

});

İzleme Panosu

Senkronizasyon sağlığını takip etmek için basit bir pano oluşturun:

app.get('/api/sync/status', async (req, res) => {

const [productCount] = await db.query('SELECT COUNT(*) as count FROM entity_mapping WHERE entity_type = "product"');

const [orderCount] = await db.query('SELECT COUNT(*) as count FROM entity_mapping WHERE entity_type = "order"');

const [recentFails] = await db.query('SELECT * FROM sync_log WHERE status = "failed" AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)');

const queueStats = await syncQueue.getJobCounts();

res.json({

mappedProducts: productCount[0].count,

mappedOrders: orderCount[0].count,

queue: queueStats,

recentFailures: recentFails.length,

lastProductSync: await db.getLastSync('products'),

lastOrderSync: await db.getLastSync('orders')

});

});

Deployment

Bağlayıcınızı bağımsız bir servis olarak deploy edin:

  • Tutarlı ortamlar için Docker
  • Süreç yönetimi için PM2 veya systemd
  • Uptime izleme için sağlık kontrolü endpoint’i
  • Winston + CloudWatch veya ELK ile log toplama

Sonuç

Özel bir WooCommerce-ERP bağlayıcısı önemli bir mühendislik yatırımıdır, ancak entegrasyon gereksinimleriniz hazır çözümlerin sunduklarını aştığında kendini amorti eder. Temel bileşenler — veri eşleme, kuyruk işleme, ID eşleme, hata işleme ve izleme — hangi ERP’ye bağlanıyor olursanız olun evrenseldir. Bunları bir kez iyi oluşturun ve değişen iş gereksinimlerine uyum sağlayabilecek bir temele sahip olursunuz.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Close Search Window