Opencart - выгрузка  xml для rozetka.com.ua

Делаем основу для разработки выгрузки товаров на маркетплейс розетка

июнь 22 , 2018

Лидер интернет магазинов в Украине rozetka.com.ua в недавнего (может уже и с давнего) времени стала еще и маркетплейсом.

Что такое маркетплейс (marketplace)

Это площадка для продажи. Иными словами каждый кто продает может продавать и в розетке. Если у вас интернет магазин и пока что нет трафика и продаж можно сделать выгрузку на розетку и выставить там свой товар.

Чем это выгодно?

Тем что розетку посещают очень много заинтересованных будущих покупателей, которые уверены в этом магазине и легко там покупают все что надо. Пока что созданный магазин может не вызывать доверия посетителя, однако когда он увидит ваш товар на розетке он охотное его купит.

Как работать с розеткой?

Для начала надо с ними связаться и сообщить о намерении выставить ваш товар. Далее надо составить выгрузку в xml формате. Они предоставляют образец, который надо либо заполнить, либо создать выгрузку похожую на выгрузку в Я.Маркет или другие агрегаторы товаров, например Хотлайн. Далее им надо предоставить либо файл с товарами, либо ссылку на генерируемую выгрузку, что лучше т.к. позволяет отдавать всегда актуальные данные.

Требования к выгрузке

  • Выгрузка должна быть в формате xml той структуры которую они предоставляют.
  • Все товары должны быть в определенном названии Тип Бренд Модель Модификация артикул.
  • Все модификации (опции) товара должны быть как отдельный блок offer (товарное предложение). Уже специалисты розетки сами прилинкуют  товары между собой. Как мы знаем что каждый цвет, размер и т.п. в розетке это отдельная карточка товара.
  • Все атрибуты (параметры) должны быть названы также как в розетке что бы товар корректно работал в фильтром.
  • Фото товара должно быть качественным в едином цвете
  • Описание желательно делать с разметкой и без вставок купите у нас или видео.

Это основные требования, которые я хотел подчеркнуть. Полностью все посмотрите на сайте розетки, при заключении договора менеджеры дают доступ к информации;

Делаем выгрузку xml из Opencart в rozetka.com.ua

Понятно что файлом отдавать в розетку товарные предложения глупо и нет смысла. Делать надо выгрузку, то есть заходя по определенной ссылке - ваш магазин будет генерировать выгрузку в xml формате для розетки.

В данной статьи информация для примера как основа выгрузки. Все дополнительные работы можно сделать по договоренности с автором info@microdata.pro. Применимо к Opencart 2.3. Также в коде вы увидите пример выгрузки с  модулем связанные опции.

Для начала надо создать файл - контроллер по адресу catalog/controller/extension/feed/rozetka.php - это и будет наш адрес. Отдавать розетке будем эту ссылку: https://your_site.com/index.php?index.php?route=extension/feed/rozetka

В этом файле надо создать все товарные предложения. Ниже идет код для основы кто хочет себе сделать выгрузку, доработать можно под любой магазин самостоятельно, либо договорится с автором статьи. 

Код выгрузки в rozetka.com.ua

<?php
class ControllerExtensionFeedRozetka extends Controller {
    public function index() {
      set_time_limit(1200);

      $xml  = '<?xml version="1.0" encoding="UTF-8"?>';
      $xml .= '<!DOCTYPE yml_catalog SYSTEM "shops.dtd">';
      $xml .= '<yml_catalog date="' . date('Y-m-d H:i', time()) . '">';
        $xml .= '<shop>';
          $xml .= '<name>' . $this->config->get('config_name') . '</name>';
          $xml .= '<company>' . $this->config->get('config_name') . '</company>';
          $xml .= '<platform>Opencart</platform>';
          $xml .= '<url>' . HTTPS_SERVER . '</url>';
          $xml .= '<currencies>';
          $xml .= '<currency id="UAH" rate="1"/>';
          $xml .= '</currencies>';

          //categories
          $categories = $this->getCategories();
          if($categories) {
            $xml .= '<categories>';
              foreach($categories as $category) {
                  $xml .= '<category id="' . $category['category_id'] .'">' . $category['name'] .'</category>';
                  $parents = $this->getCategories($category['category_id']);
                  foreach($parents as $parent){
                    $xml .= '<category id="' . $parent['category_id'] .'" parentId="' . $category['category_id'] .'">' . $parent['name'] .'</category>';
                    $pars = $this->getCategories($parent['category_id']);
                    foreach($pars as $par){
                      $xml .= '<category id="' . $par['category_id'] .'" parentId="' . $parent['category_id'] .'">' . $par['name'] .'</category>';
                    }

                  }
              }
            $xml .= '</categories>';
          }
          //categories

          //products
          $this->load->model('catalog/product');
          $xml .= '<offers>';

          foreach($allow_brands as $manufacturer_id){
            $products = $this->model_catalog_product->getProducts(array('start' => 0, 'limit' => 1000000, 'filter_manufacturer_id' => $manufacturer_id));

            foreach($products as $product){

              if($product['isbn'] && $product['mpn']){ //ISBN - Тип, MPN - Модель,
                $product['name'] = $product['isbn'] . ' ' . $product['manufacturer'] . ' ' . $product['mpn'];
              }

              $sql = "SELECT *,
    					(SELECT price FROM " . DB_PREFIX . "relatedoptions_special ros
    					WHERE ros.relatedoptions_id = ro.relatedoptions_id
    					AND ros.customer_group_id = '" . (int)$this->config->get('config_customer_group_id') . "'
    					AND ((ros.date_start = '0000-00-00' OR ros.date_start < NOW()) AND (ros.date_end = '0000-00-00' OR ros.date_end > NOW()))
    					ORDER BY ros.priority ASC, ros.price ASC LIMIT 1) AS special,
    					(SELECT price FROM " . DB_PREFIX . "product_special ps
    					WHERE ps.product_id = ro.product_id
    					AND ps.customer_group_id = '" . (int)$this->config->get('config_customer_group_id') . "'
    					AND ((ps.date_start = '0000-00-00' OR ps.date_start < NOW()) AND (ps.date_end = '0000-00-00' OR ps.date_end > NOW()))
    					ORDER BY ps.priority ASC, ps.price ASC LIMIT 1) AS time
    					FROM " . DB_PREFIX . "relatedoptions ro
    					WHERE ro.product_id = '" . (int)$product['product_id'] . "'";
    				  $variants = $this->db->query($sql);
    				  $variants_rows = $variants->rows;

              $category_id = 0;
              $category_query = $this->db->query("SELECT category_id FROM " . DB_PREFIX . "product_to_category WHERE product_id = '" . $product['product_id'] . "'");
              if(isset($category_query->row['category_id']) && $category_query->row['category_id']){
                $category_id = $category_query->row['category_id'];
              }

              if (!$variants_rows) { //если просто товар без вариантов
                $xml .= '<offer id="' . $product['product_id'] . '" available="true">';
                  $xml .= '<url>' . $this->url->link('product/product', 'path=' . $category_id . '&product_id=' . $product['product_id']) . '</url>';

                  $price = $product['price'];
                  if($product['special']){
                    $price = $product['special'];
                  }

                  $xml .= '<price>' . $price . '</price>';
                  $xml .= '<currencyId>UAH</currencyId>';
                  $xml .= '<categoryId>' . $category_id . '</categoryId>';
                  $xml .= '<picture>' . HTTPS_SERVER . 'image/' . $product['image'] . '</picture>';

                  $images_query = $this->db->query("SELECT image FROM " . DB_PREFIX . "product_image WHERE product_id = '" . $product['product_id'] . "' ORDER BY sort_order ASC");
                  if($images_query->rows){
                    foreach($images_query->rows as $image){
                      $xml .= '<picture>' . HTTPS_SERVER . 'image/' . $image['image'] . '</picture>';
                    }
                  }

                  $xml .= '<vendor>' . $product['manufacturer'] . '</vendor>';
                  $xml .= '<stock_quantity>' . $product['quantity'] . '</stock_quantity>';
                  $xml .= '<name>' . $product['name'] . ' ' . $product['sku'] . '</name>';
                  $xml .= '<description><![CDATA[' . $product['description'] . ']]></description>';

                  $product_attributes = $this->model_catalog_product->getProductAttributes($product['product_id']);
                  foreach($product_attributes as $attribute_group){
                    foreach($attribute_group['attribute'] as $attribute){
                      $xml .= '<param name="' . $attribute['name'] . '">' . $attribute['text'] . '</param>';
                    }
                  }

                  // дополнительные данные
                  if($product['manufacturer_id'] == 33){ //Dz-Mattress
                    $xml .= '<param name="Доставка/Оплата">Товар под заказ. Срок доставки до 7 дней. Без предоплаты.</param>';
                  }

                  if($product['manufacturer_id'] == 50 && $category_id == 86){ //Morfey - Наматрасники
                    $xml .= '<param name="Доставка/Оплата">На следующий день можем привести. Без предоплаты</param>';
                  }

                  if($product['manufacturer_id'] == 50 && $product['product_id'] == 9961){ //Morfey - кровать подиум
                    $xml .= '<param name="Доставка/Оплата">Товар под заказ. Срок доставки до 14 дней. Предоплата 20%</param>';
                  }
                  // дополнительные данные

                $xml .= '</offer>';
              }else{ //если с вариантами offer id - sku - идентификатор
                $names = array();
                foreach ($variants_rows as $variant) {
                  $options_query = $this->db->query("SELECT option_value_id FROM " . DB_PREFIX . "relatedoptions_option WHERE relatedoptions_id = '" . (int)$variant['relatedoptions_id'] . "'");

                  foreach($options_query->rows as $row){
                    $razmer = $this->db->query("SELECT name FROM " . DB_PREFIX . "option_value_description WHERE option_value_id = '" . (int)$row['option_value_id'] . "'");
                    if (isset($razmer->row['name'])) {
                      $doptxt .= ' ' . $razmer->row['name'];
                    }
                  }

                $xml .= '<offer id="' . $product['product_id'] . '-' . $variant['relatedoptions_id'] . '" available="true">';
                  $xml .= '<url>' . $this->url->link('product/product', 'path=' . $category_id . '&product_id=' . $product['product_id']) . '</url>';

                  $price = $variant['price'];
                  if($variant['special']){
                    $price = $variant['special'];
                  }

                  $xml .= '<price>' . $price . '</price>';
                  $xml .= '<currencyId>UAH</currencyId>';
                  $xml .= '<categoryId>' . $category_id . '</categoryId>';
                  $xml .= '<picture>' . HTTPS_SERVER . 'image/' . $product['image'] . '</picture>';

                  $images_query = $this->db->query("SELECT image FROM " . DB_PREFIX . "product_image WHERE product_id = '" . $product['product_id'] . "' ORDER BY sort_order ASC");
                  if($images_query->rows){
                    foreach($images_query->rows as $image){
                      if($image['image'] != $product['image']){
                        $xml .= '<picture>' . HTTPS_SERVER . 'image/' . $image['image'] . '</picture>';
                      }
                    }
                  }

                  $xml .= '<vendor>' . $product['manufacturer'] . '</vendor>';
                  $xml .= '<stock_quantity>' . $variant['quantity'] . '</stock_quantity>';
                  $xml .= '<name>' . $product['name']  .  $doptxt . ' ' . $product['sku'] . '</name>';
                  $xml .= '<description><![CDATA[' . $product['description'] . ']]></description>';

                  $product_attributes = $this->model_catalog_product->getProductAttributes($product['product_id']);
                  foreach($product_attributes as $attribute_group){
                    foreach($attribute_group['attribute'] as $attribute){
                      $xml .= '<param name="' . $attribute['name'] . '">' . $attribute['text'] . '</param>';
                    }
                  }

                  // дополнительные данные
                  if($product['manufacturer_id'] == 33){
                    $xml .= '<param name="Доставка/Оплата">Товар под заказ. Срок доставки до 7 дней. Без предоплаты.</param>';
                  }

                  if($product['manufacturer_id'] == 50 && $category_id == 86){
                    $xml .= '<param name="Доставка/Оплата">Cрок доставки до 2 дней</param>';
                  }

                  if($product['manufacturer_id'] == 50 && $product['product_id'] == 9961){
                    $xml .= '<param name="Доставка/Оплата">Товар под заказ. Срок доставки до 14 дней. Предоплата 20%</param>';
                  }
                  // дополнительные данные

                $xml .= '</offer>';
                //

                }
              }

            } //foreach products

          $xml .= '</offers>';
          //products

        $xml .= '</shop>';
      $xml .= '</yml_catalog>';

      $xml = str_replace(HTTP_SERVER, HTTPS_SERVER, $xml);

      $this->response->addHeader('Content-Type: application/xml');
			$this->response->setOutput($xml);

    }

    public function getCategories($parent_id = 0) {
  		$query = $this->db->query("SELECT * FROM " . DB_PREFIX . "category c LEFT JOIN " . DB_PREFIX . "category_description cd ON (c.category_id = cd.category_id) LEFT JOIN " . DB_PREFIX . "category_to_store c2s ON (c.category_id = c2s.category_id) WHERE c.parent_id = '" . (int)$parent_id . "' AND cd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND c2s.store_id = '" . (int)$this->config->get('config_store_id') . "'  AND c.status = '1' ORDER BY c.sort_order, LCASE(cd.name)");

  		return $query->rows;
  	}
}

После чего у нас будет основа под выгрузку. Далее дорабатываем под свои нужны. Думаю написать модуль выгрузки. Но не уверен что он будет сильно востребован что бы вложения в разработку окупились количеством продаж. Пока что делаю выгрузку под заказ.