Access Purchase Orders via web service - ruby

We are busy developing an interface between Acumatica and our application via the web services. We are developing it in Ruby using the Savon gem.
We've got some of the exports working for the information we need, like this one for Vendor data:
We post the following SOAP call (after logging in):
<?xml version="1.0"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.acumatica.com/typed/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<tns:Export>
<tns:commands>
<tns:Command>
<tns:FieldName>AcctCD</tns:FieldName>
<tns:ObjectName>BAccount</tns:ObjectName>
<tns:Value>Account code</tns:Value>
</tns:Command>
<tns:Command>
<tns:FieldName>AcctName</tns:FieldName>
<tns:ObjectName>BAccount</tns:ObjectName>
<tns:Value>Account name</tns:Value>
</tns:Command>
</tns:commands>
<tns:filters/>
<tns:startRow>0</tns:startRow>
<tns:topCount>0</tns:topCount>
<tns:includeHeaders>false</tns:includeHeaders>
<tns:breakOnError>false</tns:breakOnError>
</tns:Export>
</env:Body>
</env:Envelope>
to the testing endpoint:
http://p3.tryacumatica.com/(W(10003))/Soap/AP303000.asmx?WSDL
We are also able to do the same kind of thing for Inventory and Sites. However we're struggling to get it working for Purchase Orders.
We post the following:
<?xml version="1.0"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.acumatica.com/typed/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<tns:Export>
<tns:commands>
<tns:Command>
<tns:FieldName>Type</tns:FieldName>
<tns:ObjectName>POOrder</tns:ObjectName>
<tns:Value>Type</tns:Value>
</tns:Command>
<tns:Command>
<tns:FieldName>OrderNbr</tns:FieldName>
<tns:ObjectName>POOrder</tns:ObjectName>
<tns:Value>Order number</tns:Value>
</tns:Command>
</tns:commands>
<tns:filters/>
<tns:startRow>0</tns:startRow>
<tns:topCount>0</tns:topCount>
<tns:includeHeaders>false</tns:includeHeaders>
<tns:breakOnError>false</tns:breakOnError>
</tns:Export>
</env:Body>
</env:Envelope>
to the testing endpoint:
http://p3.tryacumatica.com/(W(3))/Soap/PO301000.asmx?WSDL
We always just get an empty respone. Any ideas?

Check to see if PO module is turned on. Also check to see if the user has rights to query the PO objects. Does the database receive a query? One option is debug from the database side. See if the database picks up an queries submitted from the web service input.
I know these are simple ideas, but it's worth a look.

Well, my first question is why do you need a FULL list PO ? it could be a huge data.
PO has a composite key - Type, OrderNbr and basically using Export command you have to specify value like EveryOrderNbr
see link below
link

+
old c# example for SO
Content SO301000 = context.GetSchema();
context.Clear();
string[][] data = context.Export(new Command[]
{
SO301000.OrderSummary.ServiceCommands.EveryOrderType,
SO301000.OrderSummary.ServiceCommands.EveryOrderNbr,
SO301000.OrderSummary.OrderType,
SO301000.OrderSummary.OrderNbr,
SO301000.OrderSummary.Description,
SO301000.OrderSummary.Hold,
}, null,
new Filter[]
{
new Filter { Field = SO301000.OrderSummary.OrderType, Condition = FilterCondition.Equals, Value = "IN", Operator = FilterOperator.And },
new Filter { Field = SO301000.OrderSummary.OrderNbr, Condition = FilterCondition.Equals, Value = "23630843", Operator = FilterOperator.And }
},
0, false, true);

Related

xpath assertion in soapui not working

I am reach up to this using xpath- //ns1:GetAtomicWeightResponse/ns1:GetAtomicWeightResult[1] but how to reach upto AtomicWeight.
<NewDataSet>
<Table>
<AtomicWeight>12.0115</AtomicWeight>
</Table>
</NewDataSet>
Here , I am not able to get value of AutomicWeight from table XML.
EDIT: Based on the comments from OP, adding the xml in the question.
<soap:Envelope
xmlns:soap="schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="w3.org/2001/XMLSchema-instance"
xmlns:xsd="w3.org/2001/XMLSchema">
<soap:Body>
<GetAtomicWeightResponse
xmlns="webserviceX.NET">
<GetAtomicWeightResult>
<![CDATA[<NewDataSet><Table><AtomicWeight>12.0115</AtomicWeight></Table></NewDataSet>]]>
</GetAtomicWeightResult>
</GetAtomicWeightResponse>
</soap:Body>
</soap:Envelope>
Consider Following response in your soap XML
<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>
<ConversionRateResponse xmlns="http://www.webserviceX.NET/">
<ConversionRateResult>1505.7</ConversionRateResult>
</ConversionRateResponse>
</soap:Body>
</soap:Envelope>
Xpath would be
declare namespace ns1='http://www.webserviceX.NET/';
//ns1:ConversionRateResponse[1]/ns1:ConversionRateResult[1]
Please use below xpath
//NewDataSet/Table/AtomicWeight
EDIT: Based on OP's data
Since, the data originally mentioned by you is in cdata that is why you were not able to get that value.
You can use below Groovy Script:
def xml = """<soap:Envelope xmlns:soap="schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="w3.org/2001/XMLSchema-instance" xmlns:xsd="w3.org/2001/XMLSchema">
<soap:Body>
<GetAtomicWeightResponse xmlns="webserviceX.NET">
<GetAtomicWeightResult><![CDATA[<NewDataSet><Table><AtomicWeight>12.0115</AtomicWeight></Table></NewDataSet>]]></GetAtomicWeightResult>
</GetAtomicWeightResponse>
</soap:Body>
</soap:Envelope>"""
def getData = { data, element -> new XmlSlurper().parseText(data).'**'.find{it.name() == element} }
def atomicWeight = getData((getData(xml, 'GetAtomicWeightResult') as String).trim(), 'AtomicWeight').text()
log.info atomicWeight
Or you can quickly try online Demo
If you are using it in SoapUI's test case, you do not have to add an additional Groovy Test step to get that value. Instead add the Script Assertion to the same request step (where you get that response) with below code(processing is same, but you do not have to use fixed xml, instead a dynamic response can be used).
Script Assertion
assert context.response, 'Response is empty or null'
def getData = { data, element -> new XmlSlurper().parseText(data).'**'.find{it.name() == element} }
def atomicWeight = getData((getData(context.response, 'GetAtomicWeightResult') as String).trim(), 'AtomicWeight').text()
log.info atomicWeight

Remove XML Namespaces from action Result

Using Web API and .NET Core and when I return an XML result I get the following:
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Response>
<Status>0</Status>
</Response>
</Test>
How do I remove the namespaces?
Here's part of my startup.cs file
services
.AddMvc(config =>
{
// Add XML Content Negotiation
config.RespectBrowserAcceptHeader = true;
config.InputFormatters.Add(new XmlSerializerInputFormatter());
config.OutputFormatters.Add(new XmlSerializerOutputFormatter(new XmlWriterSettings
{
OmitXmlDeclaration = true,
}));
})
.AddXmlDataContractSerializerFormatters()
.AddXmlSerializerFormatters()
.AddMvcOptions(opt => opt.FormatterMappings.SetMediaTypeMappingForFormat("xml", new MediaTypeHeaderValue("application/xml")));
Both XmlSerializer and DataContractSerializer formatters look for Content-Type or Accept header values for application/xml and text/xml. So if you register both the first formatters its possible that only one formatter in them would take effect.
If you want to support XmlSerializer, then register only that formatter and if you want to support both for some reason, make sure to change the content-types they look for. Example: application/xml-dcs, text/xml-dcs, application/xml-xmlser, text/xml-ser
In case of above issue, DataContractSerializerOutputFormatter is probably writing out the response and hence you are not seeing it take effect.

Ruby/Savon: Having trouble with namespace for a soap request

I'm having trouble changing the namespace for the SOAP xml I'm building. I'm not sure how to change "xmlns:env=" to "xmlns:soapenv=" and "xmlns:tns=" to "xmlns:web="
What I'm trying to build:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:web="http://www.webserviceX.NET/">
<soapenv:Header/>
<soapenv:Body>
<web:ConvertTemp>
<web:Temperature>100</web:Temperature>
<web:FromUnit>degreeCelsius</web:FromUnit>
<web:ToUnit>degreeFahrenheit</web:ToUnit>
</web:ConvertTemp>
</soapenv:Body>
</soapenv:Envelope>
What I'm currently getting
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://www.webserviceX.NET/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<tns:ConvertTemp>
<tns:temperature>100</tns:temperature>
<tns:fromUnit>degreeCelsius</tns:fromUnit>
<tns:toUnit>degreeFahrenheit</tns:toUnit>
</tns:ConvertTemp>
</env:Body>
</env:Envelope>
My code:
client = Savon.client(wsdl: "http://www.webservicex.net/ConvertTemperature.asmx?WSDL")
message = { temperature: '100',FromUnit: 'degreeCelsius' , ToUnit: 'degreeFahrenheit'}
response = client.call(:convert_temp, message: message)
Thanks for the help.
I was able to figure out how to change those. If anybody is interested the way to change those is:
client = Savon.client(env_namespace: :soapenv,namespace_identifier: :web)
That wasn't actually causing my problem though. Turns out that my fields were getting camelcased without me noticing. "FromUnit" became "fromUnit".

Camel Apache: xpath to extract some value out of received XML

during my Camel routes, I query a server (a HTTP GET) and as a result, I receive a 200 OK with a XML body looking similar like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<userProfiles xmlns="http://www.mycompany.com/AEContext/xmldata">
<userProfile name="guest">
<userProfileAttributes>
<userProfileAttribute name="parameter1" value="data1" nameVisibility="ALL"/>
<userProfileAttribute name="parameter2" value="data2" nameVisibility="ALL"/>
<userProfileAttribute name="parameter3" value="data3" nameVisibility="ALL"/>
</userProfileAttributes>
</userProfile>
</userProfiles>
Any idea how I would be able to get the value of "parameter2" in the XML part (in my example 'data2') and store that value in an exchange property ? I guess by using an xpath expression ? Or ...
Thanks for your help.
An easy way to retrieve the value would be to use the XPath Language. It will allow you to extract the data you want and set it somewhere (header, body , ...). Here is how to set a parameter2 header with the value:
<setHeader headerName="parameter2">
<xpath resultType="java.lang.String">
/userProfiles/userProfile/userProfileAttributes/userProfileAttribute[2]/#value
</xpath>
</setHeader>
Using Java DSL
An example using the Java DSL and setting the message body:
final Namespaces ns = new Namespaces("c", "http://www.mycompany.com/AEContext/xmldata");
// existing code
from(...)
.setBody(
ns.xpath(
"/c:userProfiles/userProfile/userProfileAttributes/userProfileAttribute[2]/#value",
String.class)
)
.to(...);

Having issue while using soap4r, unable to add namespace, encoding style to soap envelope

I am having problems with one of the soap service I'm using. I am using soap4r for consuming the soap service. But somehow they are expecting something else than what I am sending. This is what I'm sending:<?xml version="1.0" encoding="utf-8" ?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Header>
<authenticate env:mustUnderstand="0">
<username>USERNAME</username>
<apiKey>API_KEY</apiKey>
</authenticate>
<SoftLayer_Network_Media_Transcode_AccountInitParameters env:mustUnderstand="0">
<id>ID</id>
</SoftLayer_Network_Media_Transcode_AccountInitParameters>
<SoftLayer_Network_Media_Transcode_AccountObjectFilter env:mustUnderstand="0">
<transcodeJobs>
<transcodeStatus>
<name>
<operation>Complete</operation>
</name>
</transcodeStatus>
</transcodeJobs>
</SoftLayer_Network_Media_Transcode_AccountObjectFilter>
</env:Header>
<env:Body>
<n1:getTranscodeJobs xmlns:n1="http://api.service.softlayer.com/soap/v3/"
env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
</n1:getTranscodeJobs>
</env:Body>
</env:Envelope> Which does not return the desired output. What they are expecting is:<?xml version="1.0" encoding="utf-8" ?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:n1="http://api.service.softlayer.com/soap/v3/"
env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<env:Header>
<authenticate env:mustUnderstand="0">
<username>USER_NAME</username>
<apiKey>API_KEY</apiKey>
</authenticate>
<SoftLayer_Network_Media_Transcode_AccountInitParameters env:mustUnderstand="0">
<id>id</id>
</SoftLayer_Network_Media_Transcode_AccountInitParameters>
<n1:SoftLayer_Network_Media_Transcode_AccountObjectFilter env:mustUnderstand="0">
<transcodeJobs>
<transcodeStatus>
<name>
<operation>Complete</operation>
</name>
</transcodeStatus>
</transcodeJobs>
</n1:SoftLayer_Network_Media_Transcode_AccountObjectFilter>
</env:Header>
<env:Body>
<n1:getTranscodeJobs >
</n1:getTranscodeJobs>
</env:Body>
</env:Envelope> namespace and encoding style in the root (as they are using it in the header ObjectFilter). soap4r is generating the previous request, and i am not able to change it to the later one which actually works.
Here is how I am using soap4r:class SLHeader < SOAP::Header::SimpleHandler
def initialize(tag, out)
#out = out
super(XSD::QName.new(nil, tag))
end
def on_simple_outbound
#out
end
end
SOAP_WSDL_ENDPOINT = "endpoint"
service = "service name"
initParams = {'id' => ID}
objectFilter = {'transcodeJobs' => {'transcodeStatus' => {'name' => {'operation' => STATUS}}}}
driver = SOAP::WSDLDriverFactory.new(SOAP_WSDL_ENDPOINT + service + "?wsdl").create_rpc_driver
driver.headerhandler << SLHeader.new('authenticate', {'username' => #auth_user, 'apiKey' => #auth_key})
driver.headerhandler << SLHeader.new(service + 'InitParameters', initParam)
driver.headerhandler << SLHeader.new(service + 'ObjectFilter', objectFilter)
I strongly recommend that you don't waste too much time with soap4r.
If it works, then it's great. But if your SOAP service has particular expectations or is broken in some way, then it is absolutely useless (and impossible to fix without a large amount of monkey patches). The internal state of the library is also pretty bad, and it doesn't work in Ruby 1.9.
For SOAP interfaces I have started using handsoap, which allows you to manually construct SOAP messages that are exactly how your service expects them to be. It's a little more work, but it has saved me a lot of headaches similar to yours. It also works in Ruby 1.9. I have not looked back.

Resources