Как создать продукт с дополнительными атрибутами в Magento через Soap/Java

Добрый день!

Я хотел бы использовать API Magentos SOAP для управления каталогом продуктов, атрибутами и т.д. Я запускаю следующую конфигурацию: -

  • Magento 1.6
  • Сопоставление API WS-I для мыла
  • Mac OSX Lion
  • Mamp 2.0.5

Если кто-то хочет создать новый продукт, необходимо установить несколько свойств объекта продукта. Следующий код продемонстрирует мой подход:

    public int createProduct(DatabaseProduct product) {

        ArrayOfString categories = new ArrayOfString();
                categories.getComplexObjectArray().add(categoryID);
        createEntity.setCategoryIds(categories);

        CatalogProductCreateEntity createEntity = populateCreateOrUpdateEntity(product);

        CatalogProductCreateRequestParam param = new CatalogProductCreateRequestParam();
        param.setSessionId(sessionId);
        param.setSet(setId);
        param.setSku(product.getSku());
        param.setType("simple");
        param.setStore(storeId);
        param.setProductData(createEntity);

        CatalogProductCreateResponseParam response = service.catalogProductCreate(param);
        return response.getResult();
    }

    private CatalogProductCreateEntity populateCreateOrUpdateEntity(DatabaseProduct product) {

        CatalogProductCreateEntity createEntity = new CatalogProductCreateEntity();
        createEntity.setShortDescription(product.getDescription().substring(0, 20) + "...");
        createEntity.setDescription(product.getDescription());
        createEntity.setName(product.getName());
        createEntity.setPrice(String.valueOf(product.getPrice()));
        createEntity.setStatus("1"); //active
        createEntity.setVisibility("4"); //visible in search/catalog
        createEntity.setWeight("70"); //some value 
        createEntity.setTaxClassId("2"); //standard

            AssociativeArray attributes = new AssociativeArray();            

            AssociativeEntity attr1 = new AssociativeEntity();
            attr1.("attribute1_key";
            attr1.("attribute1_value");
            attributes.getComplexObjectArray().add(attr1);

            AssociativeEntity attr2 = new AssociativeEntity();
            attr2.("attribute2_key");
            attr2.("attribute2_value");
            attributes.getComplexObjectArray().add(attr2);

        createEntity.setAdditionalAttributes(attributes);

        return createEntity;
    }

Я понял, что получаю сообщение об ошибке "system.log" Magento.

2012-01-21T09:41:01+00:00 DEBUG (7): First parameter must either be an object or the name of an existing class/opt/website/magento/app/code/core/Mage/Catalog/Model/Product/Api/V2.php

Я могу локализовать ошибку в файле "V2.php" в строке 265. Согласно документации php.net метод "property_exists()" может проверять только поля в объектах. На самом деле переменная "$productData" содержит свойство "additional_attributes", которое имеет тип массива. Поэтому выполнение этого кода приведет к ошибке.

Кроме того, я не знаю, чтобы воспроизвести объект в структуре объекта "$productData" с помощью Magentos SOAP API V2.

Если я рассмотрю этот код (цикл "foreach" ) в строке 270, он указывает, что существует объект ( "$productData" ), содержащий массив ( "additional_attributes" ), который снова должен инкапсулировать набор пар ключ/значение (если я прав)

253        protected function _prepareDataForSave ($product, $productData)
254     {
255         if (property_exists($productData, 'website_ids') && is_array($productData->website_ids)) {
256             $product->setWebsiteIds($productData->website_ids);
257         }
258 
259         Mage::log("debug1");
260         Mage::log(property_exists($productData, 'additional_attributes'));
261         
262         Mage::log($productData);
263         
264         if (property_exists($productData, 'additional_attributes')) {
265             if (property_exists($productData->additional_attributes, 'single_data')) {
266                 
267                 Mage::log("---> single");
268                 Mage::log($productData->additional_attributes);
269                 
270                 foreach ($productData->additional_attributes->single_data as $_attribute) {
271                     $_attrCode = $_attribute->key;
272                     $productData->$_attrCode = $_attribute->value;
273                 }
274             }
275             if (property_exists($productData->additional_attributes, 'multi_data')) {
276                 
277                 Mage::log("---> multi");
278                 Mage::log($productData->additional_attributes);
279                 
280                 foreach ($productData->additional_attributes->multi_data as $_attribute) {
281                     $_attrCode = $_attribute->key;
282                     $productData->$_attrCode = $_attribute->value;
283                 }
284             }   
285                 
286             Mage::log("debugXXX");
287             unset($productData->additional_attributes);
288         }
289         
290         Mage::log("debug2");
291         
292         foreach ($product->getTypeInstance(true)->getEditableAttributes($product) as $attribute) {
293             $_attrCode = $attribute->getAttributeCode();
294             if ($this->_isAllowedAttribute($attribute) && (isset($productData->$_attrCode))) {
295                 $product->setData(
296         ... etc ...

Кажется, это ошибка. Итак, вот мой вопрос.

Я собираюсь назвать это проблемой программирования, которая должна быть опубликована в базе ошибок? Есть ли способ преодолеть эту проблему? Должен ли я переписать части php.code сверху, чтобы удовлетворить мою потребность обрабатывать информацию о продукте для правильного создания продукта?

Заранее спасибо

    $productData
    (
            [name] => testname
            [description] => testdescription
            [short_description] => shorttestdescription
            [weight] => 70
            [status] => 1
            [visibility] => 4
            [price] => 359.0
            [tax_class_id] => 2
            [additional_attributes] => Array
            (
                    [attribute1] => 999.0
                    [attribute2] => testcontent
            )
    )

CatalogProductCreate-Call из WSDL, сгенерированного SoapUI:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:Magento">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:catalogProductCreateRequestParam>
         <sessionId>?</sessionId>
         <type>?</type>
         <set>?</set>
         <sku>?</sku>
         <productData>
            <!--Optional:-->
            <categories>
               <!--Zero or more repetitions:-->
               <complexObjectArray>?</complexObjectArray>
            </categories>
            <!--Optional:-->
            <websites>
               <!--Zero or more repetitions:-->
               <complexObjectArray>?</complexObjectArray>
            </websites>
            <!--Optional:-->
            <name>?</name>
            <!--Optional:-->
            <description>?</description>
            <!--Optional:-->
            <short_description>?</short_description>
            <!--Optional:-->
            <weight>?</weight>
            <!--Optional:-->
            <status>?</status>
            <!--Optional:-->
            <url_key>?</url_key>
            <!--Optional:-->
            <url_path>?</url_path>
            <!--Optional:-->
            <visibility>?</visibility>
            <!--Optional:-->
            <category_ids>
               <!--Zero or more repetitions:-->
               <complexObjectArray>?</complexObjectArray>
            </category_ids>
            <!--Optional:-->
            <website_ids>
               <!--Zero or more repetitions:-->
               <complexObjectArray>?</complexObjectArray>
            </website_ids>
            <!--Optional:-->
            <has_options>?</has_options>
            <!--Optional:-->
            <gift_message_available>?</gift_message_available>
            <!--Optional:-->
            <price>?</price>
            <!--Optional:-->
            <special_price>?</special_price>
            <!--Optional:-->
            <special_from_date>?</special_from_date>
            <!--Optional:-->
            <special_to_date>?</special_to_date>
            <!--Optional:-->
            <tax_class_id>?</tax_class_id>
            <!--Optional:-->
            <tier_price>
               <!--Zero or more repetitions:-->
               <complexObjectArray>
                  <!--Optional:-->
                  <customer_group_id>?</customer_group_id>
                  <!--Optional:-->
                  <website>?</website>
                  <!--Optional:-->
                  <qty>?</qty>
                  <!--Optional:-->
                  <price>?</price>
               </complexObjectArray>
            </tier_price>
            <!--Optional:-->
            <meta_title>?</meta_title>
            <!--Optional:-->
            <meta_keyword>?</meta_keyword>
            <!--Optional:-->
            <meta_description>?</meta_description>
            <!--Optional:-->
            <custom_design>?</custom_design>
            <!--Optional:-->
            <custom_layout_update>?</custom_layout_update>
            <!--Optional:-->
            <options_container>?</options_container>
            <!--Optional:-->
            <additional_attributes>
               <!--Zero or more repetitions:-->
               <complexObjectArray>
                  <key>?</key>
                  <value>?</value>
               </complexObjectArray>
            </additional_attributes>
            <!--Optional:-->
            <stock_data>
               <!--Optional:-->
               <qty>?</qty>
               <!--Optional:-->
               <is_in_stock>?</is_in_stock>
               <!--Optional:-->
               <manage_stock>?</manage_stock>
               <!--Optional:-->
               <use_config_manage_stock>?</use_config_manage_stock>
               <!--Optional:-->
               <min_qty>?</min_qty>
               <!--Optional:-->
               <use_config_min_qty>?</use_config_min_qty>
               <!--Optional:-->
               <min_sale_qty>?</min_sale_qty>
               <!--Optional:-->
               <use_config_min_sale_qty>?</use_config_min_sale_qty>
               <!--Optional:-->
               <max_sale_qty>?</max_sale_qty>
               <!--Optional:-->
               <use_config_max_sale_qty>?</use_config_max_sale_qty>
               <!--Optional:-->
               <is_qty_decimal>?</is_qty_decimal>
               <!--Optional:-->
               <backorders>?</backorders>
               <!--Optional:-->
               <use_config_backorders>?</use_config_backorders>
               <!--Optional:-->
               <notify_stock_qty>?</notify_stock_qty>
               <!--Optional:-->
               <use_config_notify_stock_qty>?</use_config_notify_stock_qty>
            </stock_data>
         </productData>
         <!--Optional:-->
         <store>?</store>
      </urn:catalogProductCreateRequestParam>
   </soapenv:Body>
</soapenv:Envelope>

Ответ 1

В API-интерфейсе V2 SOAP кажется, что нам нужно вложить дополнительные_трибуты в слой multi_data или single_data?

Глядя на приложение/код/​​ядро ​​/Маг/Каталог/Модель/Продукт/Api/V2.php # 256 Я думаю, нам нужно использовать

$manufacturer = new stdClass();
$manufacturer->key = "manufacturer";
$manufacturer->value = "20";
$additionalAttrs['single_data'][] = $manufacturer;

или

$manufacturer = new stdClass();
$manufacturer->key = "manufacturer";
$manufacturer->value = "20";
$additionalAttrs['multi_data'][] = $manufacturer;

для использования как:

    $productData = new stdClass();
    $additionalAttrs = array();

            // manufacturer from one of the two above ^

    $productData->name                   = $data['name']; 
    $productData->description            = $data['description'];
    $productData->short_description      = $data['short_description'];
    $productData->weight                 = 0;
    $productData->status                 = 2; // 1 = active
    $productData->visibility             = 4; //visible in search/catalog
    $productData->category_ids           = $data['categories']; 
    $productData->price                  = $data['price'];
    $productData->tax_class_id           = 2; // 2=standard
    $productData->additional_attributes  = $additionalAttrs;

    // Create new product
    try {
        $proxy->catalogProductCreate($sessionId, 'virtual', 9, $sku, $productData); // 9 is courses
    } catch (SoapFault $e) {
        print $e->getMessage();  //Internal Error. Please see log for details.
        exit();
    }

Ответ 2

На самом деле мне пришлось заплатить приложение/код/​​ядро ​​/Mage/Catalog/Model/Product/Api/V2.php, чтобы этот вызов работал в версии 1.6.2.0.

Существующий код проверяет либо атрибут "single_data", либо "multi_data" в свойстве "Additional_attributes" и пытается перебирать их как ассоциативный массив:

if (property_exists($productData, 'additional_attributes')) {
        if (property_exists($productData->additional_attributes, 'single_data')) {
            foreach ($productData->additional_attributes->single_data as $_attribute) {
                $_attrCode = $_attribute->key;
                $productData->$_attrCode = $_attribute->value;
            }
        }
        if (property_exists($productData->additional_attributes, 'multi_data')) {
            foreach ($productData->additional_attributes->multi_data as $_attribute) {
                $_attrCode = $_attribute->key;
                $productData->$_attrCode = $_attribute->value;
            }
        }
}

Я думаю, что проблема в том, что, поскольку мы передаем структуру ассоциативного массива:

<item>
  <key>...</key>
  <value>...</value>
</item>
<item>
  <key>...</key>
  <value>...</value>
</item>

непосредственно под блоком Additional_attribtutes, то это действительно свойство extra_attributes, которое нужно повторить, чтобы вытащить ключ/значения атрибута, поэтому я добавил третий блок if:

 if (gettype($productData->additional_attributes) == 'array') {
            foreach ($productData->additional_attributes as $k => $v) {
                    $_attrCode = $k;
                    $productData->$_attrCode = $v;
            }
  }

С помощью этого кода добавляются/обновляются мои пользовательские атрибуты.

Вот пример запроса:

 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"   xmlns:urn="urn:Magento">
 <soapenv:Header/>
 <soapenv:Body>
   <urn:catalogProductUpdateRequestParam>
     <sessionId>100fe1f9d0518b0fd0ed49cc460c1fa6</sessionId>
     <productId>1</productId>
     <productData>
        <name>product 3</name>
        <!--  the custom attributes to updated.... 
        -->
        <additional_attributes>
           <complexObjectArray>
              <key>feed_id</key>
              <value>56920</value>
           </complexObjectArray>
           <complexObjectArray>
              <key>feed_active</key>
              <value>1</value>
           </complexObjectArray>
        </additional_attributes>
      </productData>
    </urn:catalogProductUpdateRequestParam>
  </soapenv:Body>
</soapenv:Envelope>

Ответ 3

Это не ошибка. Я использую этот Magento SOAP API V2 более года, и концепция, которую команда Magento применила здесь, абсолютно верна.

Прежде всего, каждый раз, когда любой, использующий SOAP API V2, должен полностью проверить WSDL этого соответствующего Magento, чтобы он мог правильно создавать/вызывать сообщения. URL-адрес для загрузки WSDL API-интерфейса SOAP API2: "<your_magento_home_page_url>/api/v2_soap/index/wsdl/1".

Теперь, возвращаясь к вашему вопросу, тип элемента "additional_attributes" равен "associativeArray", что означает, что его XML должен выглядеть примерно так: -

<additional_attributes>
  <!--
  This XML tag "item" can be anything;
  it what I use, but can definitely be any other valid non-used literal.
  -->
  <item>
    <key>attribute_1_code</key>
    <value>attribute_1_value_as_defined_in_database</value>
  </item>
  <item>
    <key>attribute_2_code</key>
    <value>attribute_2_value_as_defined_in_database</value>
  </item>
</additional_attributes>

Одним из примеров вышеуказанного формата XML будет: -

<additional_attributes>
  <item>
    <key>color</key>
    <!--
    I haven't provided the name / string "Blue",
    because Magento EAV database structure will only hold the option value
    (which is a unique ID) and not the option literal string.
    -->
    <value>56</value> <!-- assuming this value for "Blue" color -->
  </item>
  <item>
    <key>manufacturer</key>
    <value>87</value> <!-- assuming this value for the manufacturer "Intel" -->
  </item>
</additional_attributes>

Итак, ваша переменная "$productData" должна содержать следующие значения: -

$productData
(
    [name] => testname
    [description] => testdescription
    [short_description] => shorttestdescription
    [weight] => 70
    [status] => 1
    [visibility] => 4
    [price] => 359.0
    [tax_class_id] => 2
    [additional_attributes] => Array
    (
        [0] => Array
        (
            [key] => attribute1
            [value] => 999.0
        )
        [1] => Array
        (
            [key] => attribute2
            [value] => testcontent
        )
    )
)

Надеюсь, что это поможет.

Ответ 4

stroisi почти полностью верен. Только одно исправление для этого ответа: добавленное вами третье условие будет оцениваться до true для первых двух условий (таким образом, добавление этих атрибутов дважды, если вы используете SOAPv2 в режиме, не совместимом с WSI).

Эта цепочка условий должна выглядеть так:

    // ...
        if (property_exists($productData->additional_attributes, 'single_data')) {
            foreach ($productData->additional_attributes->single_data as $_attribute) {
                $_attrCode = $_attribute->key;
                $productData->$_attrCode = $_attribute->value;
            }
        }
        if (property_exists($productData->additional_attributes, 'multi_data')) {
            foreach ($productData->additional_attributes->multi_data as $_attribute) {
                $_attrCode = $_attribute->key;
                $productData->$_attrCode = $_attribute->value;
            }
        }
        else if (! property_exists($productData->additional_attributes, 'single_data')) {
            foreach ($productData->additional_attributes as $key => $value) {
                $productData->$key = $value;
            }
        }
    // ...

Третье условие утверждает, что как 'single_data', так и 'multi_data' являются не свойствами additional_attributes.


Хотя, на мой взгляд, правильный способ исправить эту ошибку - отредактировать файл "wsi.xml", чтобы он соответствовал wsdl.xml(или наоборот).

Ответ 5

Я использую SOAP API для ввода продуктов в магазинах magento. вот полный код

В случае универсального пользовательского атрибута.

                $arrProductTime = explode(',', '136,139');

                $result = $client->catalogProductCreate($session, 'simple', $attributeSet->set_id, 'product_sku1234', array(

                    'categories' => array(36),
                    'websites' => array(1),
                    'name' => 'my_pdt1008',
                    'description' => 'my_pdt1',
                    'short_description' => 'my_pdt1000',
                    'weight' => '11',
                    'status' => '1',
                    'url_key' => 'product-url-key1',
                    'url_path' => 'product-url-path1',
                    'visibility' => '4',
                    'price' => '100',
                    'tax_class_id' => 1,
                    'meta_title' => 'Product meta title1',
                    'meta_keyword' => 'Product meta keyword1',
                    'meta_description' => 'Product meta description1',
                    'stock_data' => array('qty'=>'100','is_in_stock'=>1,'manage_stock'=>1),
                    'additional_attributes' => array('multi_data' => array(array('key' => 'product_time', 'value' => $arrProductTime)))
                ));

Ответ 6

Все, я потратил много времени на создание продукта с дополнительным атрибутом multi_data. Ну, наконец, мне удалось это работать со следующим пакетом:

<x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:Magento">
    <x:Header/>
    <x:Body>
        <urn:catalogProductCreate>
            <urn:sessionId>fa6c91d36b1fbef209b3724cf0e3b188</urn:sessionId>
            <urn:type>simple</urn:type>
            <urn:set>4</urn:set>
            <urn:sku>147823691</urn:sku>
            <urn:productData>
                <urn:categories></urn:categories>
                <urn:websites></urn:websites>
                <urn:name>sample product-ntz-9May</urn:name>
                <urn:description>sample product-ntz-8May</urn:description>
                <urn:short_description>sample product-ntz-8May</urn:short_description>
                <urn:weight>?</urn:weight>
                <urn:status>1</urn:status>
                <urn:url_key>?</urn:url_key>
                <urn:url_path>?</urn:url_path>
                <urn:visibility>?</urn:visibility>
                <urn:category_ids></urn:category_ids>
                <urn:website_ids></urn:website_ids>
                <urn:has_options>?</urn:has_options>
                <urn:gift_message_available>?</urn:gift_message_available>
                <urn:price>?</urn:price>
                 <urn:tax_class_id>?</urn:tax_class_id>
                <urn:tier_price></urn:tier_price>
                <urn:meta_title>?</urn:meta_title>
                <urn:meta_keyword>?</urn:meta_keyword>
                <urn:meta_description>?</urn:meta_description>
                <urn:custom_design>?</urn:custom_design>
                <urn:custom_layout_update>?</urn:custom_layout_update>
                <urn:options_container>?</urn:options_container>
                <urn:additional_attributes>

                          '''<urn:multi_data>
                            <item>
                               <key>cert</key>
                               <value>
                                    <item>12300</item>//keys of multiselect dropdown
                                    <item>201690</item>
                                </value>
                             </item>
                           </urn:multi_data>'''

                    <urn:single_data>
                        <item>
                            <key>finish</key>
                            <value>22534</value>
                        </item>
                    </urn:single_data>
                </urn:additional_attributes>
                <urn:stock_data>
                    <urn:qty>?</urn:qty>
                    <urn:is_in_stock>0</urn:is_in_stock>
                    <urn:manage_stock>0</urn:manage_stock>
                    <urn:use_config_manage_stock>0</urn:use_config_manage_stock>
                    <urn:min_qty>0</urn:min_qty>
                    <urn:use_config_min_qty>0</urn:use_config_min_qty>
                    <urn:min_sale_qty>0</urn:min_sale_qty>
                    <urn:use_config_min_sale_qty>0</urn:use_config_min_sale_qty>
                    <urn:max_sale_qty>0</urn:max_sale_qty>
                    <urn:use_config_max_sale_qty>0</urn:use_config_max_sale_qty>
                    <urn:is_qty_decimal>0</urn:is_qty_decimal>
                    <urn:backorders>0</urn:backorders>
                    <urn:use_config_backorders>0</urn:use_config_backorders>
                    <urn:notify_stock_qty>0</urn:notify_stock_qty>
                    <urn:use_config_notify_stock_qty>0</urn:use_config_notify_stock_qty>
                </urn:stock_data>
            </urn:productData>
            <urn:storeView>0</urn:storeView>
        </urn:catalogProductCreate>
    </x:Body>
</x:Envelope>

Надеюсь, это сэкономит кому-то время.