E-Ticaret Panel
Mağazalar
Mağaza Düzenle
Mağaza Adı
XML Linki
Shopify Store Name
.myshopify.com
Access Token
API Version
2025-07 (En Güncel - Önerilen)
2025-04
2025-01
2024-10
2024-07
2024-04 (Legacy)
2024-01 (Legacy)
Mevcut: 2025-07
Kontrol Süresi
Saniye
Dakika
Saat
Gün
Product Path (Opsiyonel)
XML'de ürünlerin bulunduğu path
🏷️ Vendor (Marka) Filtreleme
📦 Tüm markalar işleniyor
← Ana sayfadan "Filtre Ekle" butonuyla vendor seçimi yapabilirsiniz
Converter Kodunuz
/* * Lustrin XML → Shopify CSV converter (düzeltilmiş versiyon) * Option1 = Beden * Option2 = Renk * Option3 = '' (kullanılmıyor) */ module.exports = function convert(item, utils = {}) { /* ---------- yardımcı fonksiyonlar ---------- */ const text = v => { if (v == null) return ''; if (Array.isArray(v)) return text(v[0]); if (typeof v === 'object') { if ('_' in v) return String(v._).trim(); if ('Deger' in v) return String(v.Deger).trim(); if ('Tanim' in v) return String(v.Tanim).trim(); return ''; } return String(v).trim(); }; const num = v => Number.parseFloat(String(v ?? '').replace(',', '.')) || 0; const uniq = arr => [...new Set(arr.filter(Boolean).map(u => u.trim()))]; const strip = s => String(s || '').replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim(); /* ---------- XML sarmallarını aç ---------- */ if (!item) return []; if (item.Root?.Urunler?.Urun || item.Urunler?.Urun) { const list = item.Root?.Urunler?.Urun || item.Urunler?.Urun; const arr = Array.isArray(list) ? list : [list]; return arr.flatMap(u => convert(u, utils)); } if (item.Urun) item = item.Urun; /* ---------- ürün temel bilgileri ---------- */ const id = text(item.UrunKartiID); const rawTitle = text(item.UrunAdi) || 'İsimsiz Ürün'; const title = utils.normalizeTitle ? utils.normalizeTitle(rawTitle) : rawTitle; const vendor = utils.normalizeVendor ? utils.normalizeVendor(text(item.Marka)) : text(item.Marka) || 'Lustrin'; const type = text(item.Kategori); const tags = text(item.KategoriTree); /* ---------- görseller ---------- */ let images = []; (function collectImages() { let r = item.Resimler; if (Array.isArray(r)) r = r[0]; const raws = r?.Resim ? (Array.isArray(r.Resim) ? r.Resim : [r.Resim]) : []; images = uniq(raws.map(text)); })(); /* ---------- renk ve beden çıkarma fonksiyonu ---------- */ function extractColorAndSize(secenek) { let renk = ''; let beden = ''; // EkSecenekOzellik'i al let ekSecenek = secenek?.EkSecenekOzellik; // Array ise ilk elemanı al if (Array.isArray(ekSecenek)) { ekSecenek = ekSecenek[0]; } // Ozellik listesini al if (ekSecenek?.Ozellik) { const ozl = ekSecenek.Ozellik; const ozellikleri = Array.isArray(ozl) ? ozl : [ozl]; // Her özelliği kontrol et for (const ozellik of ozellikleri) { if (!ozellik) continue; // XML attribute'larını kontrol et let tanimVal = ''; let degerVal = ''; // xml2js formatında attribute'lar $ altında olabilir if (ozellik.$ && typeof ozellik.$ === 'object') { tanimVal = ozellik.$.Tanim || ''; degerVal = ozellik.$.Deger || ''; } else { // Doğrudan attribute olarak da olabilir tanimVal = ozellik.Tanim || ozellik['@Tanim'] || ''; degerVal = ozellik.Deger || ozellik['@Deger'] || ''; } // Element içeriğini de kontrol et if (!degerVal) { degerVal = ozellik._ || ozellik['#text'] || text(ozellik) || ''; } tanimVal = String(tanimVal).trim(); degerVal = String(degerVal).trim(); // Renk kontrolü - farklı varyasyonlar if (tanimVal.toLowerCase().includes('renk')) { renk = degerVal; } // Beden kontrolü - farklı varyasyonlar else if (tanimVal.toLowerCase().includes('beden') || tanimVal.toLowerCase().includes('asorti') || tanimVal.toLowerCase().includes('kişlik')) { beden = degerVal; } } } return { renk: renk || 'Belirtilmedi', beden: beden || 'STD' }; } /* ---------- varyant sarmalı ---------- */ const secenekWrapper = item.UrunSecenek; const secenekList = (() => { if (!secenekWrapper) return [{}]; const wraps = Array.isArray(secenekWrapper) ? secenekWrapper : [secenekWrapper]; return wraps.flatMap(w => { const s = w.Secenek; return Array.isArray(s) ? s : s ? [s] : []; }); })(); /* ---------- varyant listesi oluştur ---------- */ const rawDetails = secenekList.map((s, i) => { const extracted = extractColorAndSize(s); const qty = num(text(s.StokAdedi)); const price = num(text(s.SatisFiyati) || text(s.IndirimliFiyat)).toFixed(2); const sku = text(s.StokKodu) || `${id}-${i + 1}`; const barcode = text(s.Barkod); return { beden: extracted.beden, renk: extracted.renk, qty, price, sku, barcode }; }); /* ---------- aynı beden-renk kombinasyonlarını birleştir ---------- */ const map = new Map(); rawDetails.forEach(d => { const key = `${d.beden}|${d.renk}`; if (map.has(key)) { const existing = map.get(key); existing.qty += d.qty; } else { map.set(key, { ...d }); } }); const variants = Array.from(map.values()); /* ---------- teknik detaylar ---------- */ let teknikList = []; (() => { let td = item.TeknikDetaylar; if (Array.isArray(td)) td = td[0]; if (td && td.TeknikDetay) { const lst = Array.isArray(td.TeknikDetay) ? td.TeknikDetay : [td.TeknikDetay]; teknikList = lst .map(t => ({ name: text(t.OzellikTanim), val: text(t.DegerTanim) })) .filter(o => o.name || o.val); } })(); /* ---------- açıklama HTML ---------- */ function buildDescriptionHTML() { const blocks = []; const onYazi = text(item.OnYazi); const aciklama = text(item.Aciklama); const ozelAlan1 = text(item.OzelAlan1); if (onYazi) blocks.push(onYazi); if (aciklama) blocks.push(aciklama); if (ozelAlan1) blocks.push('<strong>Set İçerik Bilgisi:</strong> ' + ozelAlan1); if (teknikList.length) { const li = teknikList.map(t => `<li><strong>${t.name}:</strong> ${t.val}</li>`).join(''); blocks.push('<h3>Teknik Detaylar</h3><ul>' + li + '</ul>'); } const rows = variants.map(d => ` <tr> <td>${d.sku}</td> <td>${d.renk}</td> <td>${d.beden}</td> <td>${d.qty}</td> <td>${d.price} TRY</td> <td>${d.barcode || '-'}</td> </tr>`).join(''); blocks.push(` <h3>Varyasyonlar</h3> <table border="1" cellpadding="6" cellspacing="0"> <thead> <tr> <th>SKU</th><th>Renk</th><th>Beden</th><th>Stok</th><th>Fiyat</th><th>Barkod</th> </tr> </thead> <tbody>${rows}</tbody> </table>`.trim()); const barkodlar = Array.from(new Set(variants.map(d => d.barcode).filter(Boolean))); if (barkodlar.length) blocks.push('<strong>Barkod:</strong> ' + barkodlar.join(' , ')); return blocks.join('<br/>'); } const bodyHtml = buildDescriptionHTML(); const seoDesc = strip(bodyHtml).substring(0, 160); /* ---------- Handle ---------- */ const base = `${id}-${title}`; const handle = utils.toHandle ? utils.toHandle(base) : base.toLowerCase() .replace(/[^\w\s-]/g, '') // Özel karakterleri kaldır .replace(/\s+/g, '-') // Boşlukları tire ile değiştir .replace(/-+/g, '-') // Çoklu tireleri tek tire yap .replace(/^-+|-+$/g, ''); // Başta ve sonda tire varsa kaldır const PK = handle; /* ---------- satır şablonu ---------- */ function rowTemplate() { return { '__PRODUCT_KEY': PK, 'Handle': handle, 'Title': title, 'Body (HTML)': '', 'Vendor': '', 'Type': '', 'Tags': '', 'Published': 'TRUE', 'Option1 Name': 'Beden', 'Option1 Value': '', 'Option2 Name': 'Renk', 'Option2 Value': '', 'Option3 Name': '', 'Option3 Value': '', 'Variant SKU': '', 'Variant Barcode': '', 'Variant Inventory Qty': 0, 'Variant Price': '0.00', 'Image Src': '', 'Image Position': '', 'Image Alt Text': '', 'SEO Title': '', 'SEO Description': '', 'Status': 'active' }; } function imgRow(src, pos) { const r = rowTemplate(); r['Image Src'] = src; r['Image Position'] = pos; r['Image Alt Text'] = title; // Tekrar eden alanları temizle r['Body (HTML)'] = r.Vendor = r.Type = r.Tags = r['SEO Title'] = r['SEO Description'] = ''; return r; } /* ---------- satırları oluştur ---------- */ const rows = []; let imgPos = 1; const hero = images[0]; variants.forEach((v, idx) => { const r = rowTemplate(); // İlk satırda ürün bilgilerini doldur if (idx === 0) { r['Body (HTML)'] = bodyHtml; r.Vendor = vendor; r.Type = type; r.Tags = tags; r['SEO Title'] = title; r['SEO Description'] = seoDesc; // Ana görsel varsa ekle if (hero) { r['Image Src'] = hero; r['Image Position'] = String(imgPos++); r['Image Alt Text'] = `${title} ${v.renk} ${v.beden}`.trim(); } } // Varyant bilgilerini doldur r['Option1 Value'] = v.beden; // Beden r['Option2 Value'] = v.renk; // Renk r['Variant SKU'] = v.sku; r['Variant Barcode'] = v.barcode; r['Variant Inventory Qty'] = v.qty; r['Variant Price'] = v.price; rows.push(r); }); // Kalan görselleri ekle images.slice(1).forEach(src => rows.push(imgRow(src, String(imgPos++)))); return rows; };
Güncelle
İptal
İstatistikler
Toplam Çalışma
4392
Başarı Oranı
96%
İşlenen Ürün
0
Push Edilen
0