timotheus / ebaysdk-python

eBay API SDK for Python
https://developer.ebay.com/tools/sdks
Other
809 stars 326 forks source link

Error 4 'Product ID is required.' using 'findItemsByProduct' when searching via UPC #277

Open miahnelson opened 5 years ago

miahnelson commented 5 years ago

I am having issues searching by UPC using findItemsByProduct. I am receiving the error message 'Product ID is required'. Can anyone tell me what I may be doing wrong?

I'm using Python 3.6.8, jupyter==1.0.0

from ebaysdk.finding import Connection as Finding
from ebaysdk.exception import ConnectionError
from bs4 import BeautifulSoup
from ebaysdk.utils import dict2xml
import pandas as pd
Domain = 'svcs.sandbox.ebay.com'

api = Finding(domain=Domain)
UPC = '89842208252'
request = {
            'productId': {
                '#text': UPC,
                '@attrs': {
                    'type': 'UPC'
                }
            },
            'paginationInput': {
                'entriesPerPage': 100,
                'pageNumber': 1
            },
            'itemFilter': [{
                'name': 'ListingType',
                'value': ['FixedPrice', 'StoreInventory', 'AuctionWithBIN']
            },
                {
                    'name': 'LocatedIn',
                    'value': 'US'
                }
            ],
            'sortOrder': 'PricePlusShippingLowest'
        }

display(dict2xml(request))
'<itemFilter><name>ListingType</name><value>FixedPrice</value><value>StoreInventory</value><value>AuctionWithBIN</value></itemFilter><itemFilter><name>LocatedIn</name><value>US</value></itemFilter><paginationInput><entriesPerPage>100</entriesPerPage><pageNumber>1</pageNumber></paginationInput><productId type="UPC">89842208252</productId><sortOrder>PricePlusShippingLowest</sortOrder>'
response = api.execute('findItemsByProduct', request)
display(response.dict())
{'ack': 'Failure',
 'errorMessage': {'error': {'errorId': '4',
   'domain': 'Marketplace',
   'severity': 'Error',
   'category': 'Request',
   'message': 'Product ID is required.',
   'subdomain': 'Search'}},
 'version': '1.13.0',
 'timestamp': '2019-05-31T03:41:53.304Z'}
miahnelson commented 5 years ago

A quick update to this issue. It appears the generated XML request may be wrong. The output of the request is

<?xml version=\'1.0\' encoding=\'utf-8\'?>
<findItemsByProductRequest
    xmlns="http://www.ebay.com/marketplace/search/v1/services">
    <productId>0885370808278</productId>
</findItemsByProductRequest>

I believe the xml should read

<?xml version=\'1.0\' encoding=\'utf-8\'?>
<findItemsByProductRequest
    xmlns="http://www.ebay.com/marketplace/search/v1/services">
    <productId  type="UPC">0885370808278</productId>
</findItemsByProductRequest>

adding in the type attribute

miahnelson commented 5 years ago

OK, now I'm really confused. I enabled debug to see what is happening. My request dictionary appears to be ok. The dict2xml appears to be working properly. api.execute passes the verb and the dict to log.debug before doing anything.

In the MD below you can see that the dict is a dict, dict2xml parses it properly, but when passing the dict to execute, the log indicates that the attributes (@attrs) is stripped from the dict.

Any ideas?

from ebaysdk.finding import Connection as Finding
from ebaysdk.exception import ConnectionError
from ebaysdk.utils import dict2xml
import pandas as pd
Domain = 'svcs.sandbox.ebay.com'

api = Finding(domain=Domain, appid='hiddenapi', debug=True)
UPC = '0885370808278'

request = {'productId': { '#text': UPC,'@attrs': {'type': 'UPC'}}}
display(request)
display(dict2xml(request))
response = api.execute('findItemsByProduct', request)
display(response.dict())
{'productId': {'#text': '0885370808278', '@attrs': {'type': 'UPC'}}}

'<productId type="UPC">0885370808278</productId>'

2019-05-31 11:37:13,774 ebaysdk [DEBUG]:execute: verb=findItemsByProduct data={'productId': {'#text': '0885370808278'}}

{'ack': 'Failure',
 'errorMessage': {'error': {'errorId': '4',
   'domain': 'Marketplace',
   'severity': 'Error',
   'category': 'Request',
   'message': 'Product ID is required.',
   'subdomain': 'Search'}},
 'version': '1.13.0',
 'timestamp': '2019-05-31T16:37:11.936Z'}
miahnelson commented 5 years ago

I managed to resolve my issue, but I'm not certain if the fix will break something else or not.

Changed

        if '#text' in root:
            value = root['#text']
        if '@attrs' in root:
-            for ak, av in sorted(root.pop('@attrs').items()):
+            for ak, av in sorted(root['@attrs'].items()):
                attrs.append(str('{0}="{1}"').format(ak, smart_encode(av)))
timotheus commented 5 years ago

This is has me confused as well. I don't see any difference in the output when running with your change. Maybe you were using an invalid product ID? what version of Python and OS were you on?

miahnelson commented 5 years ago

I tried with multiple product id's. I am running on Windows 10, Python 3.6.8.

phantomodm commented 5 years ago

I managed to resolve my issue, but I'm not certain if the fix will break something else or not.

Changed

        if '#text' in root:
            value = root['#text']
        if '@attrs' in root:
-            for ak, av in sorted(root.pop('@attrs').items()):
+            for ak, av in sorted(root['@attrs'].items()):
                attrs.append(str('{0}="{1}"').format(ak, smart_encode(av)))

Hello.. Having this same problem.. Where did you put your fix? and what is it running against? What is root? Thanks..

timotheus commented 4 years ago

@phantomodm are you also on a Windows 10 machine?

fsmosca commented 4 years ago

This works for me in production env on win10, python 3.7.4.

def find_items_by_product_demo():
    env = 'production'  # sandbox
    UPC = '0190198066572'

    request = {'productId': {'#text': UPC, '@attrs': {'type': 'UPC'}},
               'paginationInput': {'entriesPerPage': 2}}

    try:
        api = Finding(domain=domains[env], appid=appids[env],
                      config_file=None, siteid="EBAY-US", https=True,
                      debug=False)

        response = api.execute('findItemsByProduct', request)    

    except ConnectionError as e:
        print(e)
        print(e.response.dict())
        raise

    except Exception:
        print('Unexpected exception:')
        raise

    print(json.dumps(response.dict(), indent=4))