fillup / walmart-partner-api-sdk-php

PHP client for Walmart Partner APIs
MIT License
37 stars 51 forks source link

Bulk create multiple items #5

Closed rmarriott-db closed 8 years ago

rmarriott-db commented 8 years ago

Hi,

I'm having problems with the XML generated by the Item->bulk() method when MPItem contains more than one item (i.e. an array). The XML gets generated with extra <0> and/or <item> tags, which I don't believe are part of the XSD spec.

Even the sample multi-item code in the included item.md file generates output like the following:

`...<MPItemFeed><MPItemFeedHeader>...</MPItemFeedHeader> <MPItem>

<item>

<sku>NO11140_7022363</sku><Product><productName>Nourison Oasis Hand-Tufted Rectangle Rug</productName><longDescription>From its supremely plush pile to its satiny yarns and sublime patina, this sensational hand-tufted rug is truly an embarrassment of riches. This hibiscus floral print is certain to take center stage.</longDescription><shelfDescription>From its supremely plush pile to its satiny yarns and sublime patina, this sensational hand-tufted rug is truly an embarrassment of riches. This hibiscus floral print is certain to take center stage.</shelfDescription><shortDescription>From its supremely plush pile to its satiny yarns and sublime patina, this sensational hand-tufted rug is truly an embarrassment of riches.</shortDescription><mainImage><mainImageUrl>http://us-i5.tb.wal.co/dfw/dce07b8c-4239/k2-_b1ed5989-151a-4810-944b-35eee2c7b5b0.v1.jpg&lt;/mainImageUrl&gt;&lt;/mainImage&gt;&lt;productIdentifiers&gt;&lt;productIdentifier&gt;&lt;productIdType&gt;UPC&lt;/productIdType&gt;&lt;productId&gt;06108-OAS02-CHA&lt;/productId&gt;&lt;/productIdentifier&gt;&lt;/productIdentifiers&gt;&lt;productTaxCode&gt;203030&lt;/productTaxCode&gt;&lt;Home&gt;&lt;brand&gt;Nourison&lt;/brand&gt;&lt;/Home&gt;&lt;/Product&gt;&lt;price&gt;&lt;currency&gt;USD&lt;/currency&gt;&lt;amount&gt;198&lt;/amount&gt;&lt;/price&gt;&lt;shippingWeight&gt;&lt;value&gt;10&lt;/value&gt;&lt;unit&gt;LB&lt;/unit&gt;&lt;/shippingWeight&gt;

</item> <item>

<sku>NO11140_123123</sku><Product><productName>Fancy Rug</productName><longDescription>From its supremely plush pile to its satiny yarns and sublime patina, this sensational hand-tufted rug is truly an embarrassment of riches. This hibiscus floral print is certain to take center stage.</longDescription><shelfDescription>From its supremely plush pile to its satiny yarns and sublime patina, this sensational hand-tufted rug is truly an embarrassment of riches. This hibiscus floral print is certain to take center stage.</shelfDescription><shortDescription>From its supremely plush pile to its satiny yarns and sublime patina, this sensational hand-tufted rug is truly an embarrassment of riches.</shortDescription><mainImage><mainImageUrl>http://us-i5.tb.wal.co/dfw/dce07b8c-4239/k2-_b1ed5989-151a-4810-944b-35eee2c7b5b0.v1.jpg&lt;/mainImageUrl&gt;&lt;/mainImage&gt;&lt;productIdentifiers&gt;&lt;productIdentifier&gt;&lt;productIdType&gt;UPC&lt;/productIdType&gt;&lt;productId&gt;06108-OAS02-CHA&lt;/productId&gt;&lt;/productIdentifier&gt;&lt;/productIdentifiers&gt;&lt;productTaxCode&gt;203030&lt;/productTaxCode&gt;&lt;Home&gt;&lt;brand&gt;Nourison&lt;/brand&gt;&lt;/Home&gt;&lt;/Product&gt;&lt;price&gt;&lt;currency&gt;USD&lt;/currency&gt;&lt;amount&gt;198&lt;/amount&gt;&lt;/price&gt;&lt;shippingWeight&gt;&lt;value&gt;10&lt;/value&gt;&lt;unit&gt;LB&lt;/unit&gt;&lt;/shippingWeight&gt;

</item>

</MPItem> </MPItemFeed> ` Notice the <item> tags inside the <MPItem> tags. Walmart won't accept these additional tags when processing the feed. I think it's something A2X is adding?

Above is the XML generated when I tried the sample code in your documentation. In that case I literally just copied and pasted it and then captured the output XML.

However, this is how I'm trying to build the multi-item array in my production code: ` for ($i = 0; $i < $itemCount; $i++) { if ($feedCount >= $config->maxItemsFeeds) { break; }

$mpItems['MPItem'][] = [
    'mart' => 'WALMART_US',
    'sku' => $rows[$i]['sku_mapping_id'],
    'Product' => [
        'productName' => $rows[$i]['title'],
        'longDescription' => $rows[$i]['description_text'],
        'shelfDescription' => 'Shelf: description',
        'shortDescription' => 'Short: description',
        'mainImage' => ['mainImageUrl' => $rows[$i]['image_small']],
        'productIdentifiers' => [
            [
                'productIdType' => 'ISBN',
                'productId' => $rows[$i]['asin']
            ]
        ],
        'productTaxCode' => '2038013',
        'Media' => [
            'BooksAndMagazines' => [
                'condition' => $rows[$i]['condition_code_external'],
                'numberOfPages' => $rows[$i]['pages']
            ]
        ]
    ],
    'price' => [
        'currency' => 'USD',
        'amount' => $rows[$i]['price']
    ],
    'shippingWeight' => [
        'value' => $rows[$i]['weight_lbs'],
        'unit' => 'LB'
    ]
];

// Send in batches in accordance with the Walmart API spec
if ((0 === ($i + 1) % $config->maxItemsPerFeed) || ($i === ($itemCount - 1))) {
    $time = time();

    try {
        $feed = $client->bulk([
            'MPItemFeed' => [
                'MPItemFeedHeader' => [
                    'version' => '2.1',
                    'requestId' => $time,
                    'requestBatchId' => $time
                ],
                $mpItems
            ]
        ]);

        $feedCount++;
        $mpItem = [];
    } catch (Exception $e) {
        echo 'Caught exception: ', $e->getMessage(), PHP_EOL;
    }
}

} ` which results in output like this:

<?xml version="1.0" encoding="UTF-8"?> <MPItemFeed>...</MPItemFeedHeader> <0> <MPItem> <item> <mart>WALMART_US</mart><sku>2647167580</sku>... </item> <item> <mart>WALMART_US</mart><sku>2647167581</sku>... </item> </MPItem> </0> </MPItemFeed>

Everything looks good, except those extra <0> and <item> tags.

I've tried building the MPItems section/array like this:

$mpItems['MPItem'][] = [...];

and like this:

$mpItems[] = [ 'MPItems' => [...] ];

I'm not sure what I'm doing wrong, but I keep getting these extra <0> and/or <item> tags, which Walmart is complaining about. Sending a single item works fine if I do it like this:

$feed = $client->bulk([ 'MPItemFeed' => [ 'MPItemFeedHeader' => [ 'version' => '2.1', 'requestId' => $time, 'requestBatchId' => $time, ], 'MPItem' => [ 'sku' => 'NO11140_7022363',

If you check the example in item.md, you'll see that I changed 'MPItem' => [ [ to 'MPItem' => [ in order to prevent the <item> tags in the single item XML.

I hope that makes sense.

Thanks

PS. Sorry, I cannot seem to get XML tags and code to display properly here.

rmarriott-db commented 8 years ago

This is what Walmart returns after unsuccessfully trying to process the XML with the item tags:

Input XML validation failed. Expected attribute not found which is followed by: 'item'. Missing expected attribute name:mart, "http://walmart.com/":sku Input XML validation failed. Expected attribute not found which is followed by: 'item'. Missing expected attribute name:mart, "http://walmart.com/":sku

fillup commented 8 years ago

Thanks for the report @rmarriott-db, I'll look into this shortly. Can you check your composer.lock file and tell me what version of this library you're using? I think this is something I fixed a couple weeks back but not certain off hand.

rmarriott-db commented 8 years ago

Thanks for getting back to me so quickly. I tried to clean up my code a bit above, so it's at least semi-readable LOL. I'm new to composer, so might be easier for me to just attach my lock file (I had to rename it to .txt per github's rules). composer.txt

If it helps, this is my composer.json contents:

{
  "name": "fillup/walmart-partner-api-sdk-php",
  "description": "PHP client for Walmart Partner APIs",
  "type": "library",
  "license": "MIT",
  "authors": [
    {
      "name": "Phillip Shipley",
      "email": "phillip.shipley@gmail.com"
    }
  ],
  "minimum-stability": "stable",
  "require": {
    "php": ">=5.4",
    "guzzlehttp/guzzle": "^5.3",
    "guzzlehttp/guzzle-services": "dev-master",
    "guzzlehttp/retry-subscriber": "^2.0.2",
    "fillup/walmart-auth-signature-php": "^1.0.2",
    "fillup/array2xml": "^0.4.1",
    "roave/security-advisories": "dev-master",
    "fillup/walmart-partner-api-sdk-php": "^1.0.0"
  },
  "require-dev": {
    "phpunit/phpunit": "^4.8.24",
    "satooshi/php-coveralls": "^1.0.1"
  },
  "autoload": {
    "psr-4": {
      "Walmart\\": "src/"
    }
  }
}
fillup commented 8 years ago

Thanks. I think you're using an older version of the library before this was fixed. In your application folder in your composer.json file, update the version dependency for this library to be ^1.0.2 and run composer update to make sure you install the latest version. I should be releasing 1.0.3 in the next day or two so you'll want to update again when that is released. When you run composer update you should see a note about whatever version of this library you have being removed and a new one being installed, as long as you see 1.0.2 I think you'll be all set but let me know if you still have problems after that.

fillup commented 8 years ago

@rmarriott-db reading over your last comment again I saw your composer.json file which looks like you've just cloned this repository and are doing your development within the same folder structure. Composer is intended to be used as a way to pull dependencies into your project. So you should create a new folder and project repository for your own code, and in that project you can have a composer.json file with at least the following, however you may need to add more:

{
  "require": {
    "fillup/walmart-partner-api-sdk-php": "^1.0.2"
  }
}

Then with that file in place you can use composer to "install" your dependencies which will create a vendor/ directory and download all the dependent packages, which for this library will also include everything it depends on recursively.

rmarriott-db commented 8 years ago

Thanks! I thought I was doing something wrong with my project folder structure. I'll make those changes tomorrow and let you know how it goes.

rmarriott-db commented 8 years ago

I created a new folder and composer.json and installed v1.0.2. I verified this in the composer.lock file that was generated. Unfortunately I'm still getting the 0 and item tags in my XML. Is this the correct way to build the array?

$mpItem = [];

for ($i = 0; $i < $itemCount; $i++) {

    $mpItem['MPItem'][] = [
        'mart' => 'WALMART_US',
        'sku' => $rows[$i]['sku_mapping_id'],
        'Product' => [
            'productName' => $rows[$i]['title'],
            'longDescription' => $rows[$i]['description_text'],
            ...
    ];
}

$feed = $client->bulk([
    'MPItemFeed' => [
        'MPItemFeedHeader' => [
            'version' => '2.1',
            'requestId' => $time,
            'requestBatchId' => $time
        ],
        $mpItem
    ]
]);

I've tried different variations in the for loop, like $mpItem[] = [ 'MPItem' => [ ... ]];, but I always end up with item and 0 tags.

This is a print_r() dump of the final array structure passed into Item->bulk(), above:

Array
(
    [MPItemFeed] => Array
        (
            [MPItemFeedHeader] => Array
                (
                    [version] => 2.1
                    [requestId] => ...
                    [requestBatchId] => ...
                )

            [0] => Array
                (
                    [MPItem] => Array
                        (
                            [0] => Array
                                (
                                    [mart] => WALMART_US
                                    [sku] => 2647167580
                                    [Product] => Array
                                        (
                                            [productName] => Robin Hood: His Life and Legend
                                            ...
                                )

                            [1] => Array
                                (
                                    [mart] => WALMART_US
                                    [sku] => 2647167581
                                    [Product] => Array
                                        (
                                            [productName] => Family Reunion
                                            ...
                                )
                        )
                )
        )
)

and this is the XML that gets generated:

<?xml version="1.0" encoding="UTF-8"?>
<MPItemFeed>
<MPItemFeedHeader>
    <version>2.1</version>
    <requestId>...</requestId>
    <requestBatchId>...</requestBatchId>
</MPItemFeedHeader>
<0>
    <MPItem>
        <item>
            <mart>WALMART_US</mart>
            <sku>2647167580</sku>
            <Product>
                <productName>Robin Hood: His Life and Legend</productName>
                ...
            </Product>
            ...
        </item>
        <item>
            <mart>WALMART_US</mart>
            <sku>2647167581</sku>
            <Product>
                <productName>Family Reunion</productName>
                ...
            </Product>
            ...
        </item>
    </MPItem>
</0>
</MPItemFeed>

Perhaps I'm not building the array correctly? Since we pull the inventory from a table, building the array structure dynamically is my only option.

fillup commented 8 years ago

Hmm, I think the issue may be with how you're passing the into into the bulk function. You have:

$feed = $client->bulk([
    'MPItemFeed' => [
        'MPItemFeedHeader' => [
            'version' => '2.1',
            'requestId' => $time,
            'requestBatchId' => $time
        ],
        $mpItem
    ]
]);

I think maybe it should be:

$feed = $client->bulk([
    'MPItemFeed' => [
        'MPItemFeedHeader' => [
            'version' => '2.1',
            'requestId' => $time,
            'requestBatchId' => $time
        ],
        'MPItem' => $mpItem['MPItem'],
    ]
]);

I think the problem is with inserting an array that happens to have a key named MPItem rather than setting the key MPItem equal to an array of arrays of items. You can see the unit test for this function for an example of what the array needs to look like: https://github.com/fillup/walmart-partner-api-sdk-php/blob/master/tests/ItemTest.php#L85

fillup commented 8 years ago

Hi @rmarriott-db just wanted to let you know I just released version 1.0.3 which updates how calling list and listReleased methods on Orders works when no orders are found so you may want to update your composer.json to require ^1.0.3 now.

rmarriott-db commented 8 years ago

Good call. I think you're right. I'll make that change tomorrow and update my version while I'm at it. Thanks!

rmarriott-db commented 8 years ago

Thanks again! You're right about the issue being caused by the way I was assigning the array in the bulk() call. That fixed the problem. The XML is valid, and Walmart is accepting my feeds now. I also upgraded to 1.0.3 for good measures.