我在使用NetSuite SOAP API很好地使用SUDS时遇到了一些麻烦。我已经玩过SoapUI来发送NetSuite XML,它可以用于我想要的调用,但是我无法使用Python。这是有效的XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:urn="urn:messages_2015_1.platform.webservices.netsuite.com"
xmlns:urn1="urn:core_2015_1.platform.webservices.netsuite.com"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<soapenv:Header>
<urn:preferences>
</urn:preferences>
<urn:partnerInfo>
</urn:partnerInfo>
<urn:applicationInfo>
</urn:applicationInfo>
<urn:passport>
<urn1:email>*****</urn1:email>
<urn1:password>*****</urn1:password>
<urn1:account>*****</urn1:account>
<!--Optional:-->
<urn1:role internalId=*****>
</urn1:role>
</urn:passport>
</soapenv:Header>
<soapenv:Body>
<urn:get>
<urn1:baseRef internalId="2026" type="customer" xsi:type="urn1:RecordRef"/>
</urn:get>
</soapenv:Body>
</soapenv:Envelope>
在Python中,我已经生成了一个RecordRef对象并填充了它,但它并不关心我的输入:
>>> recordRef = client.factory.create('ns4:RecordRef')
>>> recordRef
(RecordRef){
name = None
_internalId = ""
_externalId = ""
_type = ""
}
>>> recordRef._internalId = 2026
>>> recordRef._type = 'customer'
>>> recordRef
(RecordRef){
name = None
_internalId = 2026
_externalId = ""
_type = "customer"
}
>>> client.service.get(recordRef)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/suds/client.py", line 521, in __call__
return client.invoke(args, kwargs)
File "/usr/local/lib/python2.7/dist-packages/suds/client.py", line 581, in invoke
result = self.send(soapenv)
File "/usr/local/lib/python2.7/dist-packages/suds/client.py", line 619, in send
description=tostr(e), original_soapenv=original_soapenv)
File "/usr/local/lib/python2.7/dist-packages/suds/client.py", line 670, in process_reply
raise WebFault(fault, replyroot)
suds.WebFault: Server raised fault: 'org.xml.sax.SAXException: Invalid type: customer'
>>>
当我查看发送出去的XML时,我注意到xsi:type正在设置,但类型不是。
如果我将客户(真的是xsi:customer)设置为在SoapUI中使用的相同值,我会收到有关未设置客户的错误:
(ReadResponse){
status =
(Status){
_isSuccess = False
statusDetail[] =
(StatusDetail){
_type = "ERROR"
code = "RCRD_TYPE_REQD"
message = "The record type is required."
},
}
}
>>> recordRef
(RecordRef){
name = None
_internalId = 2026
_externalId = ""
_type = "ns1:RecordRef"
}
我在大约五年内没有使用SOAP做过任何事情,而且之前从未在Python中做过任何事情。任何建议将不胜感激。
答案 0 :(得分:0)
想出来,我需要编写一个调用marshalled()方法的插件:
class FixXML(suds.plugin.MessagePlugin):
def __init__(self):
pass
def marshalled(self, context):
#the attribute type is really xsi:type, which we need to set but is being handled wrong
#get the Netsuite data type
wsdlDataType = context.envelope.getChild('Body').getChild('get').getChild('baseRef').getAttribute('type').getValue()
#now rewrite xsi:type so its something namespacey
context.envelope.getChild('Body').getChild('get').getChild('baseRef').getAttribute('type').setValue('ns0:RecordRef')
#next we need to add a type attribute without a namespace that contains the data type from the wsdl
typeAttr = suds.sax.attribute.Attribute('type')
typeAttr.setValue(wsdlDataType)
context.envelope.getChild('Body').getChild('get').getChild('baseRef').append(typeAttr)