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
/** * Eyyo Wholesale XML -> Shopify CSV Converter * XML: https://eyyowholesale.com/xml/products/merchant/4880?pattern=standart&lang=tr * Kur: USD -> TRY (x43) * * XML Yapisi: * <products> * <product> * id, sku, ean, mpn, gtin * categoryId, categoryPath, brand, title, detail * stock, desi, currency, salePrice, costPrice, tax * images -> image[] -> src * variants -> variant[] -> variantId, variantSku, variantEan, variantStock, variantSalePrice * attributes -> attribute -> label, value * specs -> spec -> label, value * </product> * </products> */ module.exports = function convertEyyo(item, utils = {}) { // ============ HELPER FUNCTIONS ============ const trim = v => (v == null ? '' : String(v).trim()); const isUrl = u => /^https?:\/\//i.test(String(u || '')); const toNum = v => { if (v == null || v === '') return null; const str = String(v).replace(/\s/g, '').replace(',', '.'); const n = Number(str); return Number.isFinite(n) ? n : null; }; const money = v => { const n = toNum(v); return n == null || n <= 0 ? '0.00' : n.toFixed(2); }; const toInt = v => { const n = parseInt(String(v || '0').replace(/[^\d]/g, ''), 10); return Number.isFinite(n) && n >= 0 ? n : 0; }; const uniq = arr => Array.from(new Set((arr || []).filter(Boolean))); // Turkce karakter donusumu const turkishToLatin = s => String(s) .replace(/\u011f/g, 'g').replace(/\u011e/g, 'g') .replace(/\u00fc/g, 'u').replace(/\u00dc/g, 'u') .replace(/\u015f/g, 's').replace(/\u015e/g, 's') .replace(/\u0131/g, 'i').replace(/\u0130/g, 'i') .replace(/\u00f6/g, 'o').replace(/\u00d6/g, 'o') .replace(/\u00e7/g, 'c').replace(/\u00c7/g, 'c'); const slugify = (s = '') => { if (utils.slugify) return utils.slugify(s); return turkishToLatin(String(s)) .toLowerCase() .normalize('NFKD') .replace(/[\u0300-\u036f]/g, '') .replace(/[^a-z0-9]+/g, '-') .replace(/(^-|-$)/g, ''); }; const cleanHTML = (s = '') => String(s) .replace(/<script[\s\S]*?<\/script>/gi, '') .replace(/<style[\s\S]*?<\/style>/gi, '') .replace(/ /gi, ' ') .replace(/\s+/g, ' ') .trim(); // xml2js array unwrapper const val = v => { if (Array.isArray(v)) return val(v[0]); if (v && typeof v === 'object' && '_' in v) return val(v._); return v; }; const toArray = v => { if (v == null) return []; return Array.isArray(v) ? v : [v]; }; // USD -> TRY kur cevirimi const USD_TO_TRY = 43; // Beden siralama const SIZE_ORDER = ['XXS', 'XS', 'S', 'M', 'L', 'XL', '2XL', 'XXL', '3XL', '4XL', '5XL']; const sizeRank = s => { const u = String(s || '').toUpperCase().trim(); // Sayisal beden kontrolu (36, 38, 40, 75, 80 vs.) const num = parseInt(u, 10); if (!isNaN(num)) return num; // Aralikli beden kontrolu (XS-S, M-L gibi) if (u.includes('-') && u.length > 2) { const firstSize = u.split('-')[0]; const i = SIZE_ORDER.indexOf(firstSize); return i === -1 ? 999 : i; } const i = SIZE_ORDER.indexOf(u); return i === -1 ? 999 : i; }; // Beden normalizasyonu (SSTD -> STD) const normalizeSize = s => { const u = String(s || '').toUpperCase().trim(); if (u === 'SSTD') return 'STD'; return u; }; // Set Icerik Bilgisi - Toptan satis icin beden dagilimi const getSetContent = (sizes) => { const sorted = sizes.map(s => normalizeSize(s)).sort((a, b) => sizeRank(a) - sizeRank(b)); // Aralikli beden kontrolu (XS-S, M-L gibi) - bunlar icin ayri format const hasRangeSizes = sorted.some(s => s.includes('-') && s.length > 2); if (hasRangeSizes) { // Aralikli bedenler icin: XS-S-3 M-L-3 formatinda const count = Math.floor(6 / sorted.length); return sorted.map(s => `${s}-${count}`).join(' '); } const key = sorted.join('-'); const SET_MAP = { // Standart 'STD': 'STD-6', // Harf bedenler 'XS-S-M': 'XS-2 S-2 M-2', 'S-M-L': 'S-2 M-2 L-2', 'XS-S-M-L': 'XS-1 S-2 M-2 L-1', 'S-M-L-XL': 'S-1 M-2 L-2 XL-1', 'XS-S-M-L-XL': 'XS-1 S-2 M-1 L-1 XL-1', // Sayi bedenler (elbise) '36-38-40-42': '36-1 38-2 40-2 42-1', // Sayi bedenler (ic giyim) '75-80-85-90': '75-1 80-2 85-2 90-1', }; return SET_MAP[key] || ''; // Tanimsiz kombinasyonlar icin bos dondur }; // ============ XML WRAPPER UNWRAP ============ // Root wrapper kontrolu - products > product if (item.products) { const products = toArray(item.products.product || item.products); return products.flatMap(p => convertEyyo(p, utils)); } // Alternatif wrapper - product array if (item.product && !item.id && !item.sku) { const products = toArray(item.product); return products.flatMap(p => convertEyyo(p, utils)); } // ============ SINGLE PRODUCT CONVERSION ============ // Temel alanlar const productId = trim(val(item.id)) || ''; const sku = trim(val(item.sku)) || ''; const ean = trim(val(item.ean)) || ''; const mpn = trim(val(item.mpn)) || ''; const title = trim(val(item.title)) || 'Isimsiz Urun'; const brand = trim(val(item.brand)) || 'Eyyo'; const detail = cleanHTML(val(item.detail) || ''); // Kategori const categoryPath = trim(val(item.categoryPath)) || ''; const categoryParts = categoryPath.split(/[\/>,]/).map(s => s.trim()).filter(Boolean); const productType = categoryParts[categoryParts.length - 1] || categoryPath || 'Giyim'; // Stok const totalStock = toInt(val(item.stock)); // Fiyat (USD -> TRY) const salePrice = (toNum(val(item.salePrice)) || 0) * USD_TO_TRY; const costPrice = (toNum(val(item.costPrice)) || 0) * USD_TO_TRY; // Desi/Agirlik const desi = toInt(val(item.desi)) || 1; const weight = desi * 200; // Desi to gram approximation // Specs'ten renk bilgisi al let colorName = ''; let specsNode = item.specs; if (Array.isArray(specsNode)) { specsNode = specsNode[0]; } if (specsNode && specsNode.spec) { const specArray = toArray(specsNode.spec); specArray.forEach(spec => { const label = trim(val(spec.label)).toLowerCase(); if (label === 'renk' || label === 'color') { colorName = trim(val(spec.value)); } }); } // Gorseller const images = []; let imagesNode = item.images; if (Array.isArray(imagesNode)) { imagesNode = imagesNode[0]; } if (imagesNode && imagesNode.image) { const imageArray = toArray(imagesNode.image); imageArray.forEach(img => { const src = trim(val(img.src) || val(img)); if (isUrl(src) && !images.includes(src)) { images.push(src); } }); } // Tags const tags = uniq([ brand, ...categoryParts, colorName ]).filter(Boolean).join(', '); // Handle olustur const handle = utils.toHandle ? utils.toHandle(productId + '-' + title) : slugify(productId + '-' + title); const PRODUCT_KEY = productId || handle; // ============ VARYANT ISLEME ============ let variants = []; let variantsNode = item.variants; if (Array.isArray(variantsNode)) { variantsNode = variantsNode[0]; } if (variantsNode && variantsNode.variant) { const variantArray = toArray(variantsNode.variant); variants = variantArray.map(v => { // Attribute'lardan beden bilgisi al let optionName = 'Beden'; let optionValue = 'STD'; let attrNode = v.attributes; if (Array.isArray(attrNode)) { attrNode = attrNode[0]; } if (attrNode && attrNode.attribute) { const attr = Array.isArray(attrNode.attribute) ? attrNode.attribute[0] : attrNode.attribute; optionName = trim(val(attr.label)) || 'Beden'; optionValue = normalizeSize(trim(val(attr.value))) || 'STD'; } return { id: trim(val(v.variantId)), sku: trim(val(v.variantSku)) || sku, ean: trim(val(v.variantEan)) || ean, stock: toInt(val(v.variantStock)), price: (toNum(val(v.variantSalePrice)) || 0) * USD_TO_TRY || salePrice, optionName: optionName, optionValue: optionValue }; }).filter(v => v.optionValue); } // Varyant yoksa varsayilan olustur if (variants.length === 0) { variants = [{ id: productId, sku: sku || productId, ean: ean, stock: totalStock, price: salePrice, optionName: 'Title', optionValue: 'Default Title' }]; } // Bedenleri sirala variants.sort((a, b) => sizeRank(a.optionValue) - sizeRank(b.optionValue)); // Set Icerik Bilgisi olustur const allSizes = variants.map(v => v.optionValue).filter(s => s && s !== 'Default Title'); const setContentInfo = allSizes.length > 0 ? getSetContent(allSizes) : ''; const setContentHTML = setContentInfo ? `<p><strong>Set İçerik Bilgisi:</strong> ${setContentInfo}</p>` : ''; const finalDescription = setContentHTML + detail; // ============ CSV SATIRLARI OLUSTUR ============ const rows = []; // Ilk varyantin option name'ini kullan const mainOptionName = variants[0].optionName; variants.forEach((variant, idx) => { const isFirst = idx === 0; const variantPrice = money(variant.price); const row = { __PRODUCT_KEY: PRODUCT_KEY, Handle: handle, Title: isFirst ? title : '', 'Body (HTML)': isFirst ? finalDescription : '', Vendor: isFirst ? brand : '', Type: isFirst ? productType : '', Tags: isFirst ? tags : '', Published: 'TRUE', 'Option1 Name': isFirst ? mainOptionName : '', 'Option1 Value': variant.optionValue, 'Option2 Name': '', 'Option2 Value': '', 'Option3 Name': '', 'Option3 Value': '', 'Variant SKU': variant.sku, 'Variant Grams': weight, 'Variant Inventory Tracker': 'shopify', 'Variant Inventory Qty': variant.stock, 'Variant Inventory Policy': 'deny', 'Variant Fulfillment Service': 'manual', 'Variant Price': variantPrice, 'Variant Compare At Price': '', 'Variant Requires Shipping': 'TRUE', 'Variant Taxable': 'TRUE', 'Variant Barcode': variant.ean, 'Image Src': isFirst && images[0] ? images[0] : '', 'Image Position': isFirst && images[0] ? '1' : '', 'Image Alt Text': isFirst && images[0] ? `${title} ${variant.optionValue}` : '', 'Gift Card': 'FALSE', 'SEO Title': isFirst ? title.substring(0, 70) : '', 'SEO Description': isFirst ? (detail || title).replace(/<[^>]*>/g, ' ').substring(0, 160).trim() : '', 'Google Shopping / Google Product Category': '', 'Google Shopping / Gender': isFirst ? 'unisex' : '', 'Google Shopping / Age Group': isFirst ? 'adult' : '', 'Google Shopping / MPN': variant.sku, 'Google Shopping / AdWords Grouping': '', 'Google Shopping / AdWords Labels': '', 'Google Shopping / Condition': isFirst ? 'new' : '', 'Google Shopping / Custom Product': '', 'Google Shopping / Custom Label 0': '', 'Google Shopping / Custom Label 1': '', 'Google Shopping / Custom Label 2': '', 'Google Shopping / Custom Label 3': '', 'Google Shopping / Custom Label 4': '', 'Variant Image': isFirst && images[0] ? images[0] : '', 'Variant Weight Unit': 'g', 'Variant Tax Code': '', 'Cost per item': '', Status: isFirst ? 'active' : '' }; rows.push(row); }); // Ek gorseller (ilk gorsel haric) images.slice(1).forEach((src, idx) => { rows.push({ __PRODUCT_KEY: PRODUCT_KEY, Handle: handle, 'Image Src': src, 'Image Position': String(idx + 2), 'Image Alt Text': title }); }); return rows; };
Güncelle
İptal
İstatistikler
Toplam Çalışma
3270
Başarı Oranı
95%
İşlenen Ürün
0
Push Edilen
0