How do I create a product with additional attributes in Magento via Soap/Java
Asked Answered
D

6

12

Good day!

I would like to use the Magento’s SOAP API to manage the product catalog, attributes etc. I'm running following configuration:-

  • Magento 1.6
  • Soap API WS-I compliance
  • Mac OSX Lion
  • Mamp 2.0.5

In case someone wants to create a new product, it is necessary to set a few properties of the product object. Following code will demonstrate my approach to do this :

    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;
    }

I realized that I get an error written to the "system.log" of 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

I could localize the error in the "V2.php" file on line 265. According to the php.net documentation the "property_exists()" method only can check for fields in objects. As a matter of fact the "$productData" variable holds a property called "additional_attributes" which is of the type array. Therefore the execution of this code will lead to an error.

Moreover I don’t know to reproduce the object the structure of the "$productData" object through the use of Magento’s SOAP API V2.

If I examine this code ("foreach" loop) in line 270, it indicates that there is an object ("$productData") holding an array ("additional_attributes") which again shall encapsulate a set of key/value pairs (if I am right)

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 ...

This seems to be a bug. So here is my question.

Am I going right to call this an programming issue which shall be posted in the bug base? Is there a way to get over this issue? Shall I rewrite parts of the php.code from above to satisfy my need to handle product information to create a product properly ?

Thanks in advance

    $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
            )
    )

the CatalogProductCreate-Call from the WSDL generated by 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>
Dextrorotation answered 22/1, 2012 at 11:24 Comment(1)
what is output of product_data? paste in here.Jejune
H
9

For the V2 SOAP API it appears that we need to nest the additional_attributes in a multi_data or single_data layer?

Looking at app/code/core/Mage/Catalog/Model/Product/Api/V2.php #256 I think we need to use

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

or

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

to be used like:

    $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();
    }
Housewares answered 15/5, 2012 at 20:20 Comment(4)
thats correct! but not possible the soap api generated by the wsdl.Dextrorotation
I am not understanding what you mean by it's not possible?Housewares
the classes generated by the wsdl do not provide the datastructure to create a single or multidata set. therefore it is not possible to package the data into a request.Dextrorotation
Thank you so much, I had spent forever trying to figure out how to get my additional attributes to show up, this did the trickSeawright
P
7

I actually had to patch app/code/core/Mage/Catalog/Model/Product/Api/V2.php to get this call to work in version 1.6.2.0.

The existing code checks for either a "single_data" or "multi_data" attribute under the 'additional_attributes' property and tries to iterate over the those as an associative array:

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;
            }
        }
}

I think that the issue is that since we're passing the associative array structure:

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

directly under the additional_attribtutes block then it's really the additional_attributes property that must be iterated over to pull the attribute key/values, so I added third if block:

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

With that code in place my custom attributes are being added/updated.

Here's a sample request:

 <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>
Pachisi answered 29/2, 2012 at 15:54 Comment(4)
You are a genius, thank you. All the other answers don't work with a Visual Studio generated proxy.Rotund
Great! That was also the solution to my problem: magento.stackexchange.com/questions/1308/…Pyridoxine
This is the answer to use if you are generating code from the WSDL and can also modify the magento PHP code. I can confirm that the issue exists in 1.9.1 and this fix allowed me to update attributes.Sweepback
And still in 1.9.3.2Sweepback
D
5

This is not a bug. I have been using this Magento SOAP API V2 for more than a year, and the concept which Magento team have applied here is absolutely correct.

First of all, every time any one using the SOAP API V2 must check the WSDL fully of that respective Magento, so that he can create / call messages correctly. The URL to load the WSDL of SOAP API V2 is "<your_magento_home_page_url>/api/v2_soap/index/wsdl/1".

Now coming back to your question, the type of the element "additional_attributes" is "associativeArray", which means its XML should look something like:-

<additional_attributes>
  <!--
  This XML tag "item" can be anything;
  it's 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>

One example of the above XML format will be:-

<additional_attributes>
  <item>
    <key>color</key>
    <!--
    I haven't provided the name / string "Blue",
    because Magento's 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>

So, your "$productData" variable must hold the values like this:-

$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
        )
    )
)

Hope it helps.

Demeter answered 22/1, 2012 at 18:25 Comment(6)
Hi! thanks. I a aware of the url to use: .../api/v2_soap/index/wsdl/1 or .../api/v2_soap?wsdl=1. So if I create an associativeArray I just can fill it with string values. In addition I created the Java files from the wsdl with Apache CXFDextrorotation
@fritz - Great to hear that. I hope that now you will be able to solve it. :)Demeter
I am sorry I must review my code but if I create an associativearray i only can add associativeentities but not associativearrays. so it is not possible to build this kind of datastructure you described. At last I will do a code review and post my progress tomorrow.Dextrorotation
I am sorry but the generate classes just offer the possibility to create an associativeArray which just can be filled entities holding string values. so it is not possible to create the described structure of an array which again holds arrays. Is there a way to force this structure. Which would mean i have to overwrite classes created by a standardized process which generated classes from a strict document describing an interface, in this case the wsdl?Dextrorotation
I added an call created by soapui if you scroll down you will see that the problem is there ... additional_attribute etc.Dextrorotation
Really helpful. It took me two days to discover that Magento's SOAP associativeArray is not really an associative array in PHP.Sanderling
P
2

stroisi is almost completely correct. Just one fix to that answer: the third condition you added will evaluate to true for the first two conditions too (thus adding those attributes twice in case you're using SOAPv2 in non-WSI-compliant mode).

That condition chain should look like this:

    // ...
        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;
            }
        }
    // ...

The third condition asserts that both 'single_data' and 'multi_data' are not properties of additional_attributes.


Though, in my opinion, the correct way to fix this bug is to edit the "wsi.xml" file so it is consistent with wsdl.xml (or vice versa).

Purim answered 10/9, 2013 at 10:17 Comment(0)
H
1

I am using SOAP API for entering products in magento shops. here is the full code

In the case of multiselect custom attribute.

                $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)))
                ));
Hautevienne answered 6/6, 2014 at 7:8 Comment(0)
I
0

Everyone, I spent a good amount of time while creating a product with multi_data additional attribute. Well finally I managed it to work with the following packet:

<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>

Hope it will save someone's time.

Impregnable answered 13/5, 2019 at 10:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.