I am trying to call the update method of the Zuora Soap API so as to 'CloseAccountingPeriod'. What is the correct way to do this
require 'savon'
message = {'username' => 'username','password' => 'password' }
client = Savon.client(wsdl: 'zuora.a.75.0.wsdl')
response = client.call(:login, message: message)
#response = client.call :update do
soap.header = {
}
soap.body = {
:Status=> "closed",
:ids=>"4028e699235ea4de0123777131fd5d68"
}
end
The Zuora Soap looks like this:
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv=
"http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<ns1:SessionHeader xmlns:ns1=
"http://api.zuora.com/" soapenv:mustUnderstand="0">
<ns1:session>[replace with your session]</ns1:session>
</ns1:SessionHeader>
</soapenv:Header>
<soapenv:Body>
<ns1:update xmlns:ns1="http://api.zuora.com/">
<ns1:zObjects xmlns:ns2="http://object.api.zuora.com/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="ns2:AccountingPeriod">
<ns2:Id>402892a83711418b01371142cc5801a9</ns2:Id>
<ns2:Status>Closed</ns2:Status>
</ns1:zObjects>
</ns1:update>
</soapenv:Body>
</soapenv:Envelope>
That example is correct
The minimum required data is
session key
32 char id of the AccountingPeriod
Status "Closed"
I am trying to connect to this SOAP API. Specifically, I am trying to login via this login call.
The documentation states that I should make the following request:
POST /service/replicatorV4.asmx HTTP/1.1
Host: demo12231.srv106.webshopdemo.net
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/Login"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<Login xmlns="http://tempuri.org/">
<username>string</username>
<password>string</password>
</Login>
</soap:Body>
</soap:Envelope>
When I in e.g. SoapUI makes the following request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<tem:Login>
<tem:username>Administrator</tem:username>
<tem:password>passw0rd12</tem:password>
</tem:Login>
</soapenv:Body>
</soapenv:Envelope>
then I get this satisfying response:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<LoginResponse xmlns="http://tempuri.org/">
<LoginResult>48594fe6-41fd-45f9-9f84-89ef8c247b85</LoginResult>
</LoginResponse>
</soap:Body>
</soap:Envelope>
However, when I with Savon make a request like this:
require 'savon'
client = Savon.client( :wsdl => "http://demo12231.srv106.webshopdemo.net/service/replicatorV4.asmx?WSDL",
:open_timeout => 100,
:read_timeout => 100,
:ssl_verify_mode => :none,
:log_level => :debug,
:log => false,
:logger => Rails.logger,
:convert_request_keys_to => :camelcase)
response = client.call(:login, :message => {:username => "Administrator", :password => "passw0rd12"})
then I get this dissatisfying response:
#<Savon::Response:0x007ff78cfcc368
#globals=
#<Savon::GlobalOptions:0x007ff782fb8160
#option_type=:global,
#options=
{:encoding=>"UTF-8",
:soap_version=>1,
:namespaces=>{},
:logger=>
#<ActiveSupport::Logger:0x007ff78b136ea8
#default_formatter=
#<Logger::Formatter:0x007ff78b136e30 #datetime_format=nil>,
#formatter=
#<ActiveSupport::Logger::SimpleFormatter:0x007ff783e99f80
#datetime_format=nil>,
#level=0,
#logdev=
#<Logger::LogDevice:0x007ff78b136de0
#dev=
#<File:/Users/me/Projects/my_project/log/development.log>,
#filename=nil,
#mutex=
#<Logger::LogDevice::LogDeviceMutex:0x007ff78b136db8
#mon_count=0,
#mon_mutex=#<Mutex:0x007ff78b136d68>,
#mon_owner=nil>,
#shift_age=nil,
#shift_size=nil>,
#progname=nil>,
:log=>false,
:filters=>[],
:pretty_print_xml=>false,
:raise_errors=>true,
:strip_namespaces=>true,
:convert_response_tags_to=>
#<Proc:0x007ff782fc3e70#/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/savon-2.11.1/lib/savon/options.rb:85 (lambda)>,
:convert_attributes_to=>
#<Proc:0x007ff782fc3df8#/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/savon-2.11.1/lib/savon/options.rb:86 (lambda)>,
:multipart=>false,
:adapter=>nil,
:use_wsa_headers=>false,
:no_message_tag=>false,
:follow_redirects=>false,
:unwrap=>false,
:host=>nil,
:wsdl=>
"http://demo12231.srv106.webshopdemo.net/service/replicatorV4.asmx?WSDL",
:open_timeout=>100,
:read_timeout=>100,
:ssl_verify_mode=>:none,
:convert_request_keys_to=>:camelcase,
:endpoint=>
#<URI::HTTP:0x007ff78479cbf0 URL:http://demo12231.srv106.webshopdemo.net/service/replicatorV4.asmx>}>,
#http=
#<HTTPI::Response:0x007ff78cfcd2b8
#body=
"<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><LoginResponse xmlns=\"http://tempuri.org/\"><LoginResult xsi:nil=\"true\" /></LoginResponse></soap:Body></soap:Envelope>",
#code=200,
#headers=
{"Cache-Control"=>"private, max-age=0",
"Content-Type"=>"text/xml; charset=utf-8",
"Server"=>"Microsoft-IIS/8.5",
"Date"=>"Thu, 27 Aug 2015 05:29:42 GMT",
"Content-Length"=>"335"},
#raw_body=
"<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><LoginResponse xmlns=\"http://tempuri.org/\"><LoginResult xsi:nil=\"true\" /></LoginResponse></soap:Body></soap:Envelope>">,
#locals=
#<Savon::LocalOptions:0x007ff78ce7f550
#option_type=:local,
#options=
{:advanced_typecasting=>true,
:response_parser=>:nokogiri,
:multipart=>false,
:message=>{:username=>"Administrator", :password=>"passw0rd12"},
:soap_action=>"http://tempuri.org/Login"}>>
The body part of the response is:
{:login_response=>{:login_result=>nil, :#xmlns=>"http://tempuri.org/"}}
and this tells me that maybe the service did receive the overall request, but did not get the variables. The response looks a lot like the response when I in SoapUI make this request with wrong username and password:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<LoginResponse xmlns="http://tempuri.org/">
<LoginResult xsi:nil="true"/>
</LoginResponse>
</soap:Body>
</soap:Envelope>
I have noticed that the namespace tem is expected in variables. Could this have something to do with my issue? Or is there another explanation?
Create a pure Ruby script without Rails.
then check the output against what you've created with SoapUI. Post the differences and someone will be able to help.
when I run this script:
require 'savon'
c = Savon.client(wsdl:
"http://demo12231.srv106.webshopdemo.net/service/replicatorV4.asmx?WSDL",
log_level: :debug,
log: true,
pretty_print_xml: true)
response = c.call(:login,
:message => {:username => "Administrator", :password => "passw0rd12"})
it works for me. It might be something in your Rails part which interferes. I don't do Rails therefore I'll be of little help there (I prefer Sinatra :-)).
Here is my Savon 2
client = Savon::Client.new(wsdl: "http://www.webservicex.net/uszip.asmx?WSDL")
client.operations
response = client.call(:get_info_by_zip, :message => { us_zip: "90210" })
response.to_hash
And response is:
{:get_info_by_zip_response=>{:#xmlns=>"http://www.webserviceX.NET"}}
In the SoapUI:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET">
<soapenv:Header/>
<soapenv:Body>
<web:GetInfoByZIP>
<!--Optional:-->
<web:USZip>90210</web:USZip>
</web:GetInfoByZIP>
</soapenv:Body>
</soapenv:Envelope>
I get this response:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetInfoByZIPResponse xmlns="http://www.webserviceX.NET">
<GetInfoByZIPResult>
<NewDataSet xmlns="">
<Table>
<CITY>Beverly Hills</CITY>
<STATE>CA</STATE>
<ZIP>90210</ZIP>
<AREA_CODE>310</AREA_CODE>
<TIME_ZONE>P</TIME_ZONE>
</Table>
</NewDataSet>
</GetInfoByZIPResult>
</GetInfoByZIPResponse>
</soap:Body>
</soap:Envelope>
For the life of me I cant figure it out. Can someone please have a look and let me know what am I doing wrong?
Thanks
Your tag within the message seems wrong, instead us_zip you should use "USZip" (in quotes!).
This works for me:
#!ruby
require 'savon'
require 'pp'
WSDL_URL = 'http://www.webservicex.net/uszip.asmx?wsdl'
client = Savon.client(
wsdl: WSDL_URL,
log: true, # set true to switch on logging
log_level: :debug,
pretty_print_xml: true
)
zip = ARGV[0] || "98052"
response = client.call(:get_info_by_zip,
message: { "USZip" => zip }
)
pp response.to_hash
Can somebody convert this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://test.org/" xmlns:hon="http://schemas.datacontract.org/2004/07/TEST.RVU.Entity">
<soapenv:Header/>
<soapenv:Body>
<tem:Authenticate>
<!--Optional:-->
<tem:authenticationDet>
<!--Optional:-->
<hon:AccountType>0</hon:AccountType>
<!--Optional:-->
<hon:Password>bacon</hon:Password>
<!--Optional:-->
<hon:UserName>smith</hon:UserName>
</tem:authenticationDet>
</tem:Authenticate>
</soapenv:Body>
</soapenv:Envelope>
now using Soap gem SAVON, how can I write this in a correct syntax that the client.request method can deal with it?
I tried this:
client.request :tem, :authenticate, body: { "authenticationDet" => { "AccountType" => 0, "Password" => "bacon", "UserName" => "smith"}}
but I get a HTTP 400 error.
Any advice?
You need to set the additional namespace.
The SOAP action has to be in quotes to match yours.
The script could look like this:
#!ruby
require "savon"
Savon.configure do |c|
c.pretty_print_xml = true
c.env_namespace = :soapenv
end
client = Savon::Client.new do
wsdl.namespace = "http://test.org"
wsdl.endpoint = "http://localhost"
end
resp = client.request :tem, 'Authenticate' do
soap.namespaces["xmlns:hon"] = "http://schemas.datacontract.org/2004/08/TEST.RVU.Entity"
soap.body = { "tem:authenticationDet" =>
{ "hon:AccountType" => 0,
"hon:Password" => "bacon",
"hon:UserName" => "smith" }
}
end
If I have the following SOAP request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://test.org/" xmlns:hon="http://schemas.datacontract.org/2004/07/TEST.RVU.Entity">
<soapenv:Header/>
<soapenv:Body>
<tem:Authenticate>
<!--Optional:-->
<tem:authenticationDet>
<!--Optional:-->
<hon:AccountType>0</hon:AccountType>
<!--Optional:-->
<hon:Password>bacon</hon:Password>
<!--Optional:-->
<hon:UserName>smith</hon:UserName>
</tem:authenticationDet>
</tem:Authenticate>
</soapenv:Body>
</soapenv:Envelope>
How do I write down a valid soap request using the Savon gem that includes the tem: and hon: namespaces?
Thanks
You need to set the additional namespace.
The script could look like this:
#!ruby
require "savon"
Savon.configure do |c|
c.pretty_print_xml = true
c.env_namespace = :soapenv
end
client = Savon::Client.new do
wsdl.namespace = "http://test.org"
wsdl.endpoint = "http://www.your-real-endpoint.com"
end
resp = client.request :tem, 'Authenticate' do
soap.namespaces["xmlns:hon"] = "http://schemas.datacontract.org/2004/08/TEST.RVU.Entity"
soap.body = { "tem:authenticationDet" =>
{ "hon:AccountType" => 0,
"hon:Password" => "bacon",
"hon:UserName" => "smith" }
}
end