I have discovered a problem when calling an extension codeunit function via NAV 2009 SP1 web services. The function is coded to return a BigDecimal, but the result of the web service call is an array of BigDecimals. The array has two populated values (in positions 0 and 1) that are the same (each value is the result I would have expected).
Here is the code for the codeunit function.
PROCEDURE CustomerSalesToDate@1000000001(Cust@1000000000 : Record 18) ToDateSales : Decimal;
BEGIN
WITH Cust DO BEGIN
IF CurrentDate <> WORKDATE THEN BEGIN
CurrentDate := WORKDATE;
END;
SETRANGE("Date Filter",0D,CurrentDate);
CALCFIELDS("Sales (LCY)");
EXIT("Sales (LCY)");
END;
END;
Interrogation of the WSDL reveals that the operation should return a BigDecimal (not an Array of BigDecimals)
<xsd:element name="CustomerSalesToDate_Result">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1" name="return_value" type="xsd:decimal" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<operation name="CustomerSalesToDate">
<operation soapAction="urn:microsoft-dynamics-schemas/page/customerwidget:CustomerSalesToDate" style="document" xmlns="http://schemas.xmlsoap.org/wsdl/soap/" />
<input name="CustomerSalesToDate">
<body use="literal" xmlns="http://schemas.xmlsoap.org/wsdl/soap/" />
</input>
<output name="CustomerSalesToDate_Result">
<body use="literal" xmlns="http://schemas.xmlsoap.org/wsdl/soap/" />
</output>
</operation>
The result I am receiving from the above function is BigDecimal[] with two values {43356.45, 43356.45}
I have another function in this codeunit that returns an array of 5 BigDecimals. When calling the operation via a Web Service, it returns an array of 10 values (a pair of each value I was looking for.
Here is the first line of the codeunit function
PROCEDURE CustomerStats@1000000003(Cust@1000000000 : Record 18;CustDateChoice@1000000001 : 'Current,ThisFY,LastFY') CustStats : ARRAY [5] OF Decimal;
Here is the result that is returned.
[1896.6, 1896.6, 686.67, 686.67, 64.74, 64.74, 273849.72, 273849.72, 0, 0]
So, am I doing something wrong? Is this a bug in NAV Web Services? Or maybe it is an undocumented feature to insure the numbers accuracy by returning two of them so you can easily see that they are equal.
My development is done under Mac OS X in Java using the Eclipse IDE. I'm also calling the service using dynamic discovery / invocation (stubs? we don't need no stinking stubs!), So I would like to ask my .Net/C# Brethern if they have ran into this problem, or can it be duplicated in the .Net side of the house.
I'll append some Java code to show how the operation is constructed and the call is made.
public void initializeCustomerSalesToDateOperation() throws Exception{
// Customer Sales Operation (Returns Customer Sales for a date period for the customer key)
// Check the binding to make sure the anticipated operation exists and is consistent with our understanding
BindingOperation bindingOperation = navBinding.getBindingOperation("CustomerSalesToDate","CustomerSalesToDate", "CustomerSalesToDate_Result");
if (bindingOperation == null){
customerSalesToDateOperation = null;
return;
}
// Build the Operation
OperationDesc oper = new OperationDesc();
oper.setName("CustomerSales");
// Set the Input Parameters
ParameterDesc param;
param = new ParameterDesc(new QName(nameSpaceUri, "cust"),
org.apache.axis.description.ParameterDesc.IN,
new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"),
java.lang.String.class, false, false);
oper.addParameter(param);
// Set the Return Type
oper.setReturnType(new QName("http://www.w3.org/2001/XMLSchema", "decimal"));
oper.setReturnClass(java.math.BigDecimal.class);
oper.setReturnQName(new QName(nameSpaceUri,"return_value"));
oper.setStyle(org.apache.axis.constants.Style.WRAPPED);
oper.setUse(org.apache.axis.constants.Use.LITERAL);
customerSalesToDateOperation = oper;
}
Here is the actual call, hacked to return the first value in the array that was unexpectedly returned.
/**********************************************************************
*** CustomerSalesToDate - Extended (Codeunit) Method to retrieve ***
*** the value of flow field Sales To Date from a customer ***
*** parameter - key - a key from a retrieved ***
*** instance of a Customer (WMSNavRecordObject). ***
*** @throws AxisFault ***
* @throws Exception ***
*********************************************************************/
public BigDecimal customerSalesToDate (String key) throws AxisFault, Exception{
cardPageCall.setOperation(customerSalesToDateOperation);
cardPageCall.setUseSOAPAction(true);
cardPageCall.setSOAPActionURI(nameSpaceUri + ":CustomerSalesToDate");
cardPageCall.setEncodingStyle(null);
cardPageCall.setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR, Boolean.FALSE);
cardPageCall.setProperty(org.apache.axis.AxisEngine.PROP_DOMULTIREFS, Boolean.FALSE);
cardPageCall.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP11_CONSTANTS);
cardPageCall.setOperationName(new javax.xml.namespace.QName(nameSpaceUri, "CustomerSalesToDate"));
try {
java.lang.Object _resp = cardPageCall.invoke(new java.lang.Object[] {key});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
// extractAttachments(cardPageCall);
try {
ArrayList respArray = (ArrayList) _resp;
if (respArray.get(0) instanceof BigDecimal) return (BigDecimal)respArray.get(0);
else return new BigDecimal(0);
} catch (java.lang.Exception _exception) {
return (BigDecimal) org.apache.axis.utils.JavaUtils.convert(_resp, BigDecimal.class);
}
}
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
On the function that should return 5 but actually returns 10 values, I Hacked it by multiplying the index that the value should have been in by 2.
Here is the code for the codeunit function.
PROCEDURE CustomerSalesToDate@1000000001(Cust@1000000000 : Record 18) ToDateSales : Decimal;
BEGIN
WITH Cust DO BEGIN
IF CurrentDate <> WORKDATE THEN BEGIN
CurrentDate := WORKDATE;
END;
SETRANGE("Date Filter",0D,CurrentDate);
CALCFIELDS("Sales (LCY)");
EXIT("Sales (LCY)");
END;
END;
Interrogation of the WSDL reveals that the operation should return a BigDecimal (not an Array of BigDecimals)
<xsd:element name="CustomerSalesToDate_Result">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1" name="return_value" type="xsd:decimal" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<operation name="CustomerSalesToDate">
<operation soapAction="urn:microsoft-dynamics-schemas/page/customerwidget:CustomerSalesToDate" style="document" xmlns="http://schemas.xmlsoap.org/wsdl/soap/" />
<input name="CustomerSalesToDate">
<body use="literal" xmlns="http://schemas.xmlsoap.org/wsdl/soap/" />
</input>
<output name="CustomerSalesToDate_Result">
<body use="literal" xmlns="http://schemas.xmlsoap.org/wsdl/soap/" />
</output>
</operation>
The result I am receiving from the above function is BigDecimal[] with two values {43356.45, 43356.45}
I have another function in this codeunit that returns an array of 5 BigDecimals. When calling the operation via a Web Service, it returns an array of 10 values (a pair of each value I was looking for.
Here is the first line of the codeunit function
PROCEDURE CustomerStats@1000000003(Cust@1000000000 : Record 18;CustDateChoice@1000000001 : 'Current,ThisFY,LastFY') CustStats : ARRAY [5] OF Decimal;
Here is the result that is returned.
[1896.6, 1896.6, 686.67, 686.67, 64.74, 64.74, 273849.72, 273849.72, 0, 0]
So, am I doing something wrong? Is this a bug in NAV Web Services? Or maybe it is an undocumented feature to insure the numbers accuracy by returning two of them so you can easily see that they are equal.
My development is done under Mac OS X in Java using the Eclipse IDE. I'm also calling the service using dynamic discovery / invocation (stubs? we don't need no stinking stubs!), So I would like to ask my .Net/C# Brethern if they have ran into this problem, or can it be duplicated in the .Net side of the house.
I'll append some Java code to show how the operation is constructed and the call is made.
public void initializeCustomerSalesToDateOperation() throws Exception{
// Customer Sales Operation (Returns Customer Sales for a date period for the customer key)
// Check the binding to make sure the anticipated operation exists and is consistent with our understanding
BindingOperation bindingOperation = navBinding.getBindingOperation("CustomerSalesToDate","CustomerSalesToDate", "CustomerSalesToDate_Result");
if (bindingOperation == null){
customerSalesToDateOperation = null;
return;
}
// Build the Operation
OperationDesc oper = new OperationDesc();
oper.setName("CustomerSales");
// Set the Input Parameters
ParameterDesc param;
param = new ParameterDesc(new QName(nameSpaceUri, "cust"),
org.apache.axis.description.ParameterDesc.IN,
new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"),
java.lang.String.class, false, false);
oper.addParameter(param);
// Set the Return Type
oper.setReturnType(new QName("http://www.w3.org/2001/XMLSchema", "decimal"));
oper.setReturnClass(java.math.BigDecimal.class);
oper.setReturnQName(new QName(nameSpaceUri,"return_value"));
oper.setStyle(org.apache.axis.constants.Style.WRAPPED);
oper.setUse(org.apache.axis.constants.Use.LITERAL);
customerSalesToDateOperation = oper;
}
Here is the actual call, hacked to return the first value in the array that was unexpectedly returned.
/**********************************************************************
*** CustomerSalesToDate - Extended (Codeunit) Method to retrieve ***
*** the value of flow field Sales To Date from a customer ***
*** parameter - key - a key from a retrieved ***
*** instance of a Customer (WMSNavRecordObject). ***
*** @throws AxisFault ***
* @throws Exception ***
*********************************************************************/
public BigDecimal customerSalesToDate (String key) throws AxisFault, Exception{
cardPageCall.setOperation(customerSalesToDateOperation);
cardPageCall.setUseSOAPAction(true);
cardPageCall.setSOAPActionURI(nameSpaceUri + ":CustomerSalesToDate");
cardPageCall.setEncodingStyle(null);
cardPageCall.setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR, Boolean.FALSE);
cardPageCall.setProperty(org.apache.axis.AxisEngine.PROP_DOMULTIREFS, Boolean.FALSE);
cardPageCall.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP11_CONSTANTS);
cardPageCall.setOperationName(new javax.xml.namespace.QName(nameSpaceUri, "CustomerSalesToDate"));
try {
java.lang.Object _resp = cardPageCall.invoke(new java.lang.Object[] {key});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
// extractAttachments(cardPageCall);
try {
ArrayList respArray = (ArrayList) _resp;
if (respArray.get(0) instanceof BigDecimal) return (BigDecimal)respArray.get(0);
else return new BigDecimal(0);
} catch (java.lang.Exception _exception) {
return (BigDecimal) org.apache.axis.utils.JavaUtils.convert(_resp, BigDecimal.class);
}
}
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
On the function that should return 5 but actually returns 10 values, I Hacked it by multiplying the index that the value should have been in by 2.