开发者

Has anyone been able to get the suds soap library to work with the NetSuite WSDL?

Has anyone been able to get the suds soap library to work with the NetSuite WSDL? I get this error when I try to create a client.

from suds.client import Client

#url = 'http://mssoapinter开发者_运维问答op.org/asmx/simple.asmx?WSDL'
url = 'https://webservices.netsuite.com/wsdl/v2009_2_0/netsuite.wsdl'
client = Client(url)
print client


Traceback (most recent call last):
client = Client(url)
File "build\bdist.win32\egg\suds\client.py", line 112, in __init__
File "build\bdist.win32\egg\suds\reader.py", line 152, in open
File "build\bdist.win32\egg\suds\wsdl.py", line 158, in __init__
File "build\bdist.win32\egg\suds\wsdl.py", line 207, in resolve
File "build\bdist.win32\egg\suds\wsdl.py", line 662, in resolve
File "build\bdist.win32\egg\suds\wsdl.py", line 757, in resolvefaults
Exception: fault 'ExceededRecordCountFault' not defined in portType 'NetSuitePortType'


Yes, suds can connect to NetSuite, but it takes a long time to process the WSDL.

Here's some sample code:

# Open NetSuite Session
wsdlNetSuite = 'https://webservices.netsuite.com/wsdl/v2010_1_0/netsuite.wsdl'
client = Client(wsdlNetSuite)

# Login
passport = client.factory.create('ns4:Passport')
passport.email = 'username@web.com'
passport.password = 'ABC123'
passport.account = 123
loginResponse = client.service.login(passport)
print 'Login Response: '
print loginResponse.status

# Get a record
recordRef = client.factory.create('ns4:RecordRef')
recordRef._internalId = 127842
recordRef._type = 'invoice'
record = client.service.get(recordRef)
print record

You might also need to try various combinations of Python and SUDS versions. It's not a particularly reliable library.


It is a bit late, but for the record I attach a way of how one can work with NetSuite SuiteTalk SOAP API using Python Zeep.

Example of NetSuite SOAP login with Python and Zeep followed by adding a customer.

# pip3 install zeep
from zeep import Client

WSDL_URL = 'https://webservices.sandbox.netsuite.com/wsdl/v2016_1_0/netsuite.wsdl'
NS_EMAIL = 'admin@example.com'
NS_PASSWORD = '*********'
NS_ROLE = '1111'
NS_ACCOUNT = '1111111'
NS_APPID = 'FFFFFFFF-FFFF-0000-0000-FFFFFFFFFFFF'


def login_client():
    client = Client(WSDL_URL)
    Passport = client.get_type('ns1:Passport')
    AppInfo = client.get_type('ns5:ApplicationInfo')
    passport = Passport(email=NS_EMAIL, password=NS_PASSWORD, account=NS_ACCOUNT)
    app_info = AppInfo(applicationId=NS_APPID)
    login = client.service.login(passport=passport,
                                 _soapheaders={'applicationInfo': app_info})
    print('Login Response: ', login.status)
    return client


# Example usage
client = login_client()

# add a customer
Customer = client.get_type('ns14:Customer')
customer = Customer(
    lastName='Joe',
    firstName='Bloggs',
    email='joe@example.com'
)
response = client.service.add(customer)
print(response)

See also: https://github.com/fmalina/python-netsuite


Though not the best way to do things, if you're desperate, you can keep trying different versions of their wsdl. I was getting the same error message, so I kept trying until one worked. I went in this order:

'https://webservices.netsuite.com/wsdl/v2010_2_0/netsuite.wsdl'
'https://webservices.netsuite.com/wsdl/v2010_1_0/netsuite.wsdl'
'https://webservices.netsuite.com/wsdl/v2009_2_0/netsuite.wsdl'
'https://webservices.netsuite.com/wsdl/v2009_1_0/netsuite.wsdl'

'https://webservices.netsuite.com/wsdl/v2009_1_0/netsuite.wsdl' finally worked for me

EDIT: Based on tponthieux's answer, I realize now that you can use the suds plugin feature to fix the wsdl (I would simply comment on his answer, but I don't have the reputation yet :( ):

import re

from suds.client import Client
from suds.plugin import DocumentPlugin

NetSuite_wsdl = 'https://webservices.netsuite.com/wsdl/v2010_2_0/netsuite.wsdl'


class Fix_NS_wsdl(DocumentPlugin):
    bad_fault = re.compile(r"(ExceededRequestLimitFault)"
            r"(\">\s*<soap:fault name=\")(ExceededRecordCountFault)")

    def loaded(self, context):
        if context.url == NetSuite_wsdl:
            context.document = self.bad_fault.sub(r"\1\2\1", context.document)

client = Client(NetSuite_wsdl, plugins=[Fix_NS_wsdl()])


If you want to do a one-off fix on a saved WSDL instead of doing the fix every time (which takes a while) here is a VIM substitution command that I used

:%s/RequestLimitFault">\n\t*<soap\:fault name=\"ExceededRecordCountFault/RequestLimitFault\"\>\r\t\t\t\t<soap\:fault name=\"Exce   ededRequestLimitFault/gc

This works on the 2010 Netsuite WSDL and also had to do it for the 2012 Netsuite WSDL (you think they would have fixed it after two years)


https://webservices.netsuite.com/wsdl/v2010_2_0/netsuite.wsdl

I found that it was failing on a validation between this part:

<operation name="checkAsyncStatus">
    <input name="checkAsyncStatusRequest" message="tns:checkAsyncStatusRequest"/>
    <output name="checkAsyncStatusResponse" message="tns:checkAsyncStatusResponse"/>
    <fault name="InvalidSessionFault" message="tns:InvalidSessionFault"/>
    <fault name="InvalidCredentialsFault" message="tns:InvalidCredentialsFault"/>
    <fault name="ExceededRequestLimitFault" message="tns:ExceededRequestLimitFault"/> -- mismatch
    <fault name="UnexpectedErrorFault" message="tns:UnexpectedErrorFault"/>
    <fault name="AsyncFault" message="tns:AsyncFault"/>
</operation>

and this part:

<operation name="checkAsyncStatus">
    <soap:operation soapAction="checkAsyncStatus"/>
    <input name="checkAsyncStatusRequest">
        <soap:header message="tns:headers" part="passport" use="literal"/>
        <soap:header message="tns:headers" part="applicationInfo" use="literal"/>
        <soap:header message="tns:headers" part="partnerInfo" use="literal"/>
        <soap:header message="tns:headers" part="preferences" use="literal"/>
        <soap:body use="literal"/>
    </input>
    <output name="checkAsyncStatusResponse">
        <soap:header message="tns:headers" part="documentInfo" use="literal"/>
        <soap:body use="literal"/>
    </output>
    <fault name="InvalidSessionFault">
        <soap:fault name="InvalidSessionFault" use="literal"/>
    </fault>
    <fault name="InvalidCredentialsFault">
        <soap:fault name="InvalidCredentialsFault" use="literal"/>
    </fault>
    <fault name="ExceededRequestLimitFault">
        <soap:fault name="ExceededRecordCountFault" use="literal"/> -- mismatch
    </fault>
    <fault name="UnexpectedErrorFault">
        <soap:fault name="UnexpectedErrorFault" use="literal"/>
    </fault>
    <fault name="AsyncFault">
        <soap:fault name="AsyncFault" use="literal"/>
    </fault>
</operation>

I changed this:

<fault name="ExceededRequestLimitFault">
    <soap:fault name="ExceededRecordCountFault" use="literal"/>
</fault>

to this:

<fault name="ExceededRequestLimitFault">
    <soap:fault name="ExceededRequestLimitFault" use="literal"/>
</fault>

The modification allows Suds to create the client. Like John mentioned, it does take forever to parse(more than two minutes). I haven't tried using checkAsyncStatus to see if it works.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜