פיתוח מודול ייבוא/ייצוא מותאם אישית עבור 1C-Bitrix
החלפה סטנדרטית דרך CommerceML מכסה משימות טיפוסיות עם 1C: קטלוג, הזמנות, יתרות. אבל כשהנתונים מגיעים בפורמט לא סטנדרטי – XML מספק, JSON מ-CRM, דוחות XLSX – הביצועים יורדים והמיפוי הופך למסע חיפושים. מודול ייבוא/ייצוא מותאם אישית פותר זאת: הוא עובד ישירות עם כל מקור, משתמש בעיבוד זורם (stream processing) לנפחים גדולים, ותומך בסנכרון דו-כיווני עם בקרת התנגשויות. אנו מפתחים מודולים כאלה במתכונת turnkey: מניתוח סכמה ועד פריסה והדרכת מנהלים. הצוות שלנו עוסק בפיתוח מותאם אישית כבר 10+ שנים ויישם בהצלחה 40+ אינטגרציות לקמעונאות, לוגיסטיקה וייצור. נבחן את הפרויקט שלך תוך יום אחד – צור קשר לייעוץ.
תרחיש טיפוסי: יש לך מחסן חיצוני או מערכת ERP שמוציאה נתונים בפורמט CommerceML. אבל CommerceML הוא XML כבד שלוקח שעות לעבד נפחים מעל 10,000 פריטים לכל טעינה. מודול מותאם אישית מנתח נתונים עם מפענח משלו, תוך שימוש ב-XMLReader לסטרימינג, ויכול לעבד עד 1,000 אלמנטים בשנייה. ההבדל הוא פי 3–5 מהר יותר מהחלפה סטנדרטית. בנוסף, אנו מיישמים עיבוד אצווה עם סוכני Bitrix, מה שמבטל פסקי זמן של בקשות אינטרנט.
מתי CommerceML לא מספיק
CommerceML הוא פרוטוקול אוניברסלי, אבל הוא לא תמיד גמיש. אם מקור הנתונים שלך הוא JSON API של שירות צד שלישי, XLSX בינארי עם אלפי שורות, או דורש טרנספורמציות שדות מורכבות (מיזוג, הסרת כפילויות, קישור לטבלאות ייחוס), החלפה סטנדרטית אינה יעילה. מודול מותאם אישית יכול להתמודד עם פורמטים שרירותיים: XML (כל סכמה), CSV, XLSX, JSON, וגם להוריד קבצים דרך FTP/SFTP. לנפחים מעל 100,000 רשומות, טעינה במנות (chunked loading) היא חובה – אנו מטמיעים אותה בליבת המודול.
איך עובד סנכרון דו-כיווני
החלק הקשה ביותר הוא הימנעות מהתנגשויות כשמתרחשים שינויים בו-זמנית בשתי המערכות. אנו משתמשים בסנכרון מבוסס חותמת זמן עם שדה ALTER TABLE b_iblock_element ADD COLUMN sync_hash VARCHAR(32); ALTER TABLE b_iblock_element ADD COLUMN synced_at DATETIME; . בייצוא, אנו רושמים את ה-hash של מצב הרשומה. בייבוא הבא: אם ה-hash השתנה במקור – אנו מעדכנים את Bitrix; אם הוא השתנה ב-Bitrix (המשתמש ערך) – אנו שולחים את השינויים חזרה למקור. אם שניהם השתנו – התנגשות, מתועדת לפתרון ידני.
SQL להוספת שדה sync_hash
ALTER TABLE b_iblock_element ADD COLUMN sync_hash VARCHAR(32); ALTER TABLE b_iblock_element ADD COLUMN synced_at DATETIME; ארכיטקטורת מודול מותאם אישית
מודול Bitrix הוא תיקייה ב-/local/modules/{vendor}.{modulename}/ הרשומה דרך RegisterModule. מבנה סטנדרטי:
local/modules/company.import/ ├── install/ │ ├── index.php # InstallDB(), UnInstallDB(), DoInstall() │ └── db/mysql/install.sql ├── lib/ │ ├── Importer.php # основная логика │ ├── Parser/ │ │ ├── XmlParser.php │ │ └── CsvParser.php │ └── Queue/ │ └── ImportQueue.php ├── admin/ │ └── import_settings.php # административный интерфейс ├── include.php └── .settings.php ייבוא ממקור XML מותאם אישית
דוגמה למימוש מפענח לסכמה מותאמת אישית:
namespace Company\Import; use Bitrix\Main\Loader; use Bitrix\Catalog\ProductTable; class Importer { private \SimpleXMLElement $xml; public function __construct(string $filePath) { Loader::includeModule('iblock'); Loader::includeModule('catalog'); $this->xml = simplexml_load_file($filePath); } public function run(): array { $stats = ['created' => 0, 'updated' => 0, 'errors' => 0]; foreach ($this->xml->products->product as $product) { try { $this->processProduct($product, $stats); } catch (\Throwable $e) { \Bitrix\Main\Diag\Debug::writeToFile($e->getMessage(), 'IMPORT ERROR', '/bitrix/modules/company.import/error.log'); $stats['errors']++; } } return $stats; } private function processProduct(\SimpleXMLElement $p, array &$stats): void { $externalId = (string)$p->id; $existing = $this->findByExternalId($externalId); $fields = [ 'IBLOCK_ID' => IMPORT_IBLOCK_ID, 'NAME' => (string)$p->name, 'CODE' => \CUtil::translit((string)$p->name, 'ru'), 'ACTIVE' => (string)$p->is_active === '1' ? 'Y' : 'N', 'PROPERTY_VALUES' => [ 'EXTERNAL_ID' => $externalId, 'VENDOR_CODE' => (string)$p->sku, 'DESCRIPTION' => (string)$p->description, ], ]; if ($existing) { \CIBlockElement::Update($existing, $fields); $stats['updated']++; } else { $el = new \CIBlockElement(); $newId = $el->Add($fields); if (!$newId) throw new \RuntimeException($el->LAST_ERROR); $stats['created']++; } // Обновляем цену и остаток \CPrice::SetBasePrice($newId ?? $existing, (float)$p->price, 'RUB'); \CCatalogProduct::Update($newId ?? $existing, ['QUANTITY' => (int)$p->stock]); } } עיבוד אצווה וסוכנים
עבור 100,000+ רשומות, בקשת אינטרנט ישירה היא בלתי אפשרית – פסק זמן. אנו משתמשים בסוכן Bitrix ששומר התקדמות במסד הנתונים. הסוכן רץ כל דקה ומעבד את המנה הבאה:
class ImportQueue { public static function processChunk(int $jobId, int $offset, int $limit = 500): array { $job = ImportJobTable::getById($jobId)->fetch(); // ... читаем $limit строк начиная с $offset // ... обрабатываем // ... обновляем прогресс в БД return ['processed' => $count, 'total' => $job['total_rows']]; } } function ImportAgent(): string { $activeJob = getActiveImportJob(); if (!$activeJob) return ''; $result = ImportQueue::processChunk($activeJob['id'], $activeJob['offset']); if ($activeJob['offset'] + $result['processed'] >= $result['total']) { markJobComplete($activeJob['id']); return ''; } return 'ImportAgent();'; } ייצוא נתונים
ייצוא לפורמט מותאם אישית עבור מערכת חיצונית:
class Exporter { public function exportOrders(\DateTime $from, \DateTime $to): string { $orders = \Bitrix\Sale\OrderTable::getList([ 'filter' => [ '>=DATE_INSERT' => $from->format('d.m.Y H:i:s'), '<=DATE_INSERT' => $to->format('d.m.Y H:i:s'), 'CANCELED' => 'N', ], 'select' => ['ID', 'ACCOUNT_NUMBER', 'PRICE', 'CURRENCY', 'DATE_INSERT', 'USER_ID'], ])->fetchAll(); $xml = new \XMLWriter(); $xml->openMemory(); $xml->startDocument('1.0', 'UTF-8'); $xml->startElement('orders'); foreach ($orders as $order) { $xml->startElement('order'); $xml->writeElement('id', $order['ID']); $xml->writeElement('number', $order['ACCOUNT_NUMBER']); $xml->writeElement('amount', $order['PRICE']); $xml->writeElement('date', $order['DATE_INSERT']->format(\DateTime::ATOM)); // ... позиции заказа $xml->endElement(); } $xml->endElement(); return $xml->outputMemory(); } } פורמטים ומקורות
| פורמט/מקור | כלים | הערות |
|---|---|---|
| XML (מותאם אישית) | SimpleXML, XMLReader | XMLReader לקבצים > 100 MB |
| CSV/XLSX | PhpSpreadsheet, fgetcsv | XLSX – בינארי, דורש ספרייה |
| JSON REST API | curl, Guzzle | פאג'ינציה, הגבלת קצב |
| FTP/SFTP | phpseclib | הורדת קבצים אוטומטית |
| 1C CommerceML | החלפת Bitrix מובנית | התאמה אישית דרך אירועים |
| Google Sheets | Google Sheets API v4 | לנפחים קטנים |
איך להאיץ ייבוא קטלוג גדול?
עבור נפחים מעל 50,000 פריטים, החלפה סטנדרטית נתקלת במגבלות זמן ביצוע וזיכרון של PHP. מודול מותאם אישית משתמש בסוכנים אסינכרוניים, טעינה במנות, ופרופילינג של שאילתות. אנו מוסיפים אינדקסים על מזהים חיצוניים ותאריך סנכרון, ומאיצים חיפוש כפילויות פי 10. לקוחות משיגים ייבוא של 100,000 אלמנטים ב-2–3 דקות במקום שעה.
לוח זמנים ועלות
עלות הפיתוח מחושבת באופן אישי לפי מורכבות המיפוי, מספר הפורמטים והצורך בסנכרון דו-כיווני. ניתן הערכה מדויקת לאחר ניתוח הנתונים שלך.
| שלב | משך |
|---|---|
| ניתוח פורמט ומיפוי שדות | 1–2 ימים |
| פיתוח מפענח/מייצא | 3–5 ימים |
| עיבוד אצווה, סוכן Bitrix | 2–3 ימים |
| ממשק ניהולי | 2–3 ימים |
| סנכרון דו-כיווני (אם נדרש) | 3–5 ימים |
| בדיקות עם נתונים אמיתיים | 2–3 ימים |
סה"כ: 2–3 שבועות לייבוא חד-כיווני; 3–4 שבועות לסנכרון דו-כיווני.
מה כלול
- קוד מקור של המודול עם הערות.
- תיעוד API של המודול ומדריך התקנה.
- גישה למאגר Git עם היסטוריית שינויים.
- הדרכת מנהלים (עד שעתיים אונליין).
- אחריות ל-3 חודשים על פעילות רציפה.
קבל ייעוץ מהנדס – בקש ביקורת מקדימה של ההחלפה שלך.CommerceML — פרוטוקול החלפה







