我正在尝试使用Savon通过Magento SOAP API创建一个类别。在任何人建议之前,我不能使用Magento SOAP v2或REST API。
此代码设置我的客户端并登录:
@client = Savon.client(wsdl: "#{EnvConfig.base_url}/api/soap/?wsdl", log_level: :debug, raise_errors: true, pretty_print_xml: true)
response = @client.call(:login, message: {
username: EnvConfig.magento_api_user,
apiKey: EnvConfig.magento_api_key
})
@token = response.to_hash[:login_response][:login_return]
然后我可以调用magentos各种方法。致list all of the products,我可以致电:
@response = @client.call(:call, message: {session: @token, method: 'catalog_product.list'})
这一切都正常,所以上面的任何代码似乎都没有问题。
当我致电catalog_category.create时,我收到了错误消息。如果我只使用parentID参数调用该方法:
@response = @client.call(:call, message: {session: @token, method: 'catalog_category.create', parent_id: 90})
然后Savon发送以下XML:
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:typens="urn:Magento" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<typens:call>
<session>6939ace91ba26b1da9a21334d7ef2c13</session>
<method>catalog_category.create</method>
<parentId>90</parentId>
</typens:call>
</env:Body>
</env:Envelope>
这会返回响应Savon::SOAPFault: (103) Attribute "name" is required
:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>103</faultcode>
<faultstring>Attribute "name" is required.</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
我期待这一点,因为the API documentation清楚地表明以下属性不是可选的:
因此,如果我拨打包含name
的电话:
@response = @client.call(:call, message: {session: @token, method: 'catalog_category.create', parent_id: 90, category_data: {name: 'Fooooo'}})
发送此XML:
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:typens="urn:Magento" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<typens:call>
<session>6939ace91ba26b1da9a21334d7ef2c13</session>
<method>catalog_category.create</method>
<parentId>90</parentId>
<categoryData>
<name>Fooooo</name>
</categoryData>
</typens:call>
</env:Body>
</env:Envelope>
但我收到Savon::SOAPFault: (SOAP-ENV:Client) Error cannot find parameter
错误:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>Error cannot find parameter</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
我花了很长时间尝试解决这个问题,并尝试发送name
参数而不将其包装在categoryData中,以及其他参数。全部返回相同的错误消息。
至少,知道无法找到参数会很好!
真的很感激任何帮助:)
答案 0 :(得分:0)
我真的找不到合适的解决方案。最后,通过使用这个非常混乱的代码构建XML来解决它:
# Builds an XML Request for use with the Magento API
#-------------------------------------------------------------------------------------------------------------
# Usage:
#
# @m = MageAPI.new(token, call, params) Creates a new MageAPIRequest object with @call, @token, @data and
# @xml_data instance variables.
#
# Expects a hash of params like:
#
# { parentId: '90',
# categoryData: {
# name: 'OMG, does this work?',
# is_active: 1,
# available_sort_by: 'position',
# default_sort_by: 'position',
# description: 'Foo',
# url_key: 'url_key',
# include_in_menu: 1}
# }
#
#-------------------------------------------------------------------------------------------------------------
class MageAPIRequest
attr_reader :call, :token, :data, :xml_data
def initialize(token, call, params = {})
@call = call
@token = token
@data = params
@xml_data = build_xml
end
def to_s
return @xml_data
end
# Build out the xml string to send to the server, excluding the Envelope, body and call tags, which are added by Savon.
def build_xml
token = LibXML::XML::Node.new('sessionId', @token)
token['xsi:type']='xsd:string'
resourcePath = LibXML::XML::Node.new('resourcePath', @call)
resourcePath['xsi:type']='xsd:string'
unless @data.empty?
args = LibXML::XML::Node.new 'args'
args['SOAP-ENC:arrayType'] = "xsd:ur-type[#{@data.length}]"
args['xsi:type'] = 'SOAP-ENC:Array'
# Build the structure insude 'args', based on the Hash.
# TODO: Make this recursive, so it can work deeper than one level.
@data.each do |k,v|
if v.is_a? Hash
details = LibXML::XML::Node.new(k.to_s)
details["xsi:type"] = 'ns2:Map'
args << details
v.each do |key,value|
item_node = LibXML::XML::Node.new("item")
key_node = LibXML::XML::Node.new("key", key.to_s)
key_node['xsi:type'] = 'xsd:string'
if value.is_a? Fixnum
value_node = LibXML::XML::Node.new("value", value.to_s)
value_node['xsi:type'] = 'xsd:int'
elsif value.is_a? Float
value_node = LibXML::XML::Node.new("value", sprintf("%.2f", value))
value_node['xsi:type'] = 'xsd:string'
elsif value.is_a? Array
value_node = LibXML::XML::Node.new("value")
value_node['SOAP-ENC:arrayType'] = "xsd:int[#{value.length}]"
value_node['xsi:type'] = 'SOAP-ENC:Array'
value.each do |v|
v_node = LibXML::XML::Node.new("item", v.to_s)
v_node['xsi:type'] = 'xsd:string'
v_node['xsi:type'] = 'xsd:int' if v.is_a? Fixnum
value_node << v_node
end
else
value_node = LibXML::XML::Node.new("value", value.to_s)
value_node['xsi:type'] = 'xsd:string'
end
item_node << key_node
item_node << value_node
details << item_node
end
else
pair = LibXML::XML::Node.new(k.to_s, v.to_s)
# if v.is_a? Fixnum
# pair['xsi:type']='xsd:int'
# else
pair['xsi:type']='xsd:string'
# end
args << pair
end
end
end
xml_string = token.to_s
xml_string << resourcePath.to_s
xml_string << args.to_s
end
end
然后我在创建请求时使用了它:
request = MageAPIRequest.new(@token, call, params)
远非理想,但它有效。值得注意的是,我还必须构建一个解析器来转换响应,如下所示:
{:balance=>"10",
:exchange_rate=>"1.000000",
:response_type=>"ACCEPT",
:customer_data=>
{:item=>
[
{:key=>"iredeem_member_id", :value=>"110"},
{:key=>"prefix", :value=>"Ms."},
{:key=>"lastname", :value=>"Last name"},
{:key=>"firstname", :value=>"First name"},
{:key=>"iredeem_points_balance", :value=>"10"},
]
}
}
成为可用的东西:
{:balance=>"10",
:exchange_rate=>"1.000000",
:response_type=>"ACCEPT",
:customer_data=>
{:iredeem_member_id=>"110",
:prefix=>"Ms.",
:lastname=>"Last name",
:firstname=>"First name",
:iredeem_points_balance=>"10"
}
}