Integration With Odata : Data Entity Write Failed

D365 FO creates sales orders through Odata. I refer to the following project:

https://github.com/microsoft/Dynamics-AX-Integration/tree/master/ServiceSamples/ODataConsoleApplication

I always get the following error when using this code to create sales orders:

“message”:"Write failed for table row of type ‘SalesOrderHeaderEntity’. Infolog: Warning: Field ‘Currency’ must be filled in.; Warning: Field ‘Customer’ must be filled in.; Warning: Field ‘Group’ must be filled in.; Warning: Field ‘Requested ship date’ must be filled in.; Warning: validateWrite failed on data source ‘SalesLine (SalesLine)’.

My code is as follows:

public static void CreateSalesOrderInSingleChangeset(Resources context)
{
string salesOrderNumber = “100009”;
//try
//{
SalesOrderHeader salesOrder = new SalesOrderHeader();
DataServiceCollection salesOrderCollection = new DataServiceCollection(context);
salesOrderCollection.Add(salesOrder);

salesOrder.OrderingCustomerAccountNumber = “US-001”;
salesOrder.DataAreaId = “USMF”;
salesOrder.SalesOrderNumber = salesOrderNumber; // Change number sequence setting in AX to allow user to set values.
// salesOrder.OrderingCustomerAccountNumber = “US-001”;
// salesOrder.CurrencyCode = “USD”;
// salesOrder.SalesOrderName = “test”;
// salesOrder.CommissionCustomerGroupId = “”;
// salesOrder.RequestedShippingDate =DateTimeOffset.Parse(DateTime.Now.ToString());
// salesOrder.ConfirmedShippingDate = DateTimeOffset.Parse(DateTime.Now.ToString());
// // salesOrder = “”;
// salesOrder.ChargeCustomerGroupId = “”;
//// salesOrder.IsEInvoiceDimensionAccountCodeSpecifiedPerLine = “US-001”;
// salesOrder.InvoiceCustomerAccountNumber = “US-001”;

// salesOrder.LanguageId = “en-us”;

SalesOrderLine salesOrderLine = new SalesOrderLine();
DataServiceCollection salesOrderLineCollection = new DataServiceCollection(context);
salesOrderLineCollection.Add(salesOrderLine);

salesOrderLine.SalesOrderNumber = salesOrder.SalesOrderNumber;
salesOrderLine.ItemNumber = “1000”;
salesOrderLine.OrderedSalesQuantity = 1;
salesOrderLine.ShippingSiteId = “1”;
salesOrderLine.ShippingWarehouseId = “11”;
salesOrderLine.DataAreaId = “USMF”;

context.SaveChanges(SaveChangesOptions.PostOnlySetProperties | SaveChangesOptions.BatchWithSingleChangeset); // Batch with Single Changeset ensure the saved changed runs in all-or-nothing mode.
Console.WriteLine(string.Format(“Invoice {0} - Saved !”, salesOrderNumber));
//}
//catch (DataServiceRequestException e)
//{
// Console.WriteLine(string.Format(“Invoice {0} - Save Failed !”, salesOrderNumber));
//}
}

First of all, let me clean up your code and repost it via Insert > Insert Code, to make it easier to read. Please do it by yourself next time.

public static void CreateSalesOrderInSingleChangeset(Resources context)
{
	string salesOrderNumber = "100009";

	SalesOrderHeader salesOrder = new SalesOrderHeader();
	DataServiceCollection<SalesOrderHeader> salesOrderCollection = new DataServiceCollection<SalesOrderHeader>(context);
	salesOrderCollection.Add(salesOrder);

	salesOrder.OrderingCustomerAccountNumber = "US-001";
	salesOrder.DataAreaId = "USMF";
	salesOrder.SalesOrderNumber = salesOrderNumber; // Change number sequence setting in AX to allow user to set values.

	SalesOrderLine salesOrderLine = new SalesOrderLine();
	DataServiceCollection<SalesOrderLine> salesOrderLineCollection = new DataServiceCollection<SalesOrderLine>(context);
	salesOrderLineCollection.Add(salesOrderLine);

	salesOrderLine.SalesOrderNumber = salesOrder.SalesOrderNumber;
	salesOrderLine.ItemNumber = "1000";
	salesOrderLine.OrderedSalesQuantity = 1;
	salesOrderLine.ShippingSiteId = "1";
	salesOrderLine.ShippingWarehouseId = "11";
	salesOrderLine.DataAreaId = "USMF";

	// Batch with Single Changeset ensure the saved changed runs in all-or-nothing mode.
	context.SaveChanges(SaveChangesOptions.PostOnlySetProperties | SaveChangesOptions.BatchWithSingleChangeset); 
	Console.WriteLine(string.Format("Invoice {0} - Saved !", salesOrderNumber));
}

The problem is that you’re not providing values of certain mandatory fields.

By the way, you should be using V2 version of the entities (e.g. SalesOrderHeaderV2).

  • 好的,我将尝试SalesOrderHeaderV2,But what’s the difference between SalesOrderHeaderV2 and SalesOrderHeader

SalesOrderHeaderV2 is a newer version of SalesOrderHeader. SalesOrderHeader is obsolete and it’ll be deleted in a future version of F&O, therefore using it doesn’t make a good sense.

I don’t know the exact differences. You can compare them if you really need this informaton for something.

I’m using SalesOrderHeaderV2 ,

The current code is as follows:

public static void CreateSalesOrderInSingleChangeset(Resources context)
{
string salesOrderNumber = “100009”;
SalesOrderHeaderV2 salesOrder = new SalesOrderHeaderV2();
DataServiceCollection salesOrderCollection = new DataServiceCollection(context);
salesOrderCollection.Add(salesOrder);
salesOrder.OrderingCustomerAccountNumber = “US-001”;
salesOrder.DataAreaId = “USMF”;
salesOrder.SalesOrderNumber = salesOrderNumber; // Change number sequence setting in AX to allow user to set values.

SalesOrderLine salesOrderLine = new SalesOrderLine();
DataServiceCollection salesOrderLineCollection = new DataServiceCollection(context);
salesOrderLineCollection.Add(salesOrderLine);
salesOrderLine.SalesOrderNumber = salesOrder.SalesOrderNumber;
salesOrderLine.ItemNumber = “1000”;
salesOrderLine.OrderedSalesQuantity = 1;
salesOrderLine.ShippingSiteId = “1”;
salesOrderLine.ShippingWarehouseId = “11”;
salesOrderLine.DataAreaId = “USMF”;

context.SaveChanges(SaveChangesOptions.PostOnlySetProperties | SaveChangesOptions.BatchWithSingleChangeset); // Batch with Single Changeset ensure the saved changed runs in all-or-nothing mode.
Console.WriteLine(string.Format(“Invoice {0} - Saved !”, salesOrderNumber));
}

When I execute it, the following error will appear:

“message”:"Write failed for table row of type ‘SalesOrderHeaderV2Entity’. Infolog: Warning: insert not allowed for field ‘ContactPerson,CustAccount’.

But I didn’t add values to these two fields either.

What should i do next

Please use Insert > Insert Code to paste your code. It preserves indentation and you can also choose the programming language to get simple syntax highlighting.

public static void CreateSalesOrderInSingleChangeset(Resources context)
        {
            string salesOrderNumber = "100009";
            SalesOrderHeaderV2 salesOrder = new SalesOrderHeaderV2();
            DataServiceCollection<SalesOrderHeaderV2> salesOrderCollection = new DataServiceCollection<SalesOrderHeaderV2>(context);
            salesOrderCollection.Add(salesOrder);
            salesOrder.OrderingCustomerAccountNumber = "US-001";
            salesOrder.DataAreaId = "USMF";
            salesOrder.SalesOrderNumber = salesOrderNumber; // Change number sequence setting in AX to allow user to set values.

            SalesOrderLine salesOrderLine = new SalesOrderLine();
            DataServiceCollection<SalesOrderLine> salesOrderLineCollection = new DataServiceCollection<SalesOrderLine>(context);
            salesOrderLineCollection.Add(salesOrderLine);
            salesOrderLine.SalesOrderNumber = salesOrder.SalesOrderNumber;
            salesOrderLine.ItemNumber = "1000";
            salesOrderLine.OrderedSalesQuantity = 1;
            salesOrderLine.ShippingSiteId = "1";
            salesOrderLine.ShippingWarehouseId = "11";
            salesOrderLine.DataAreaId = "USMF";

            context.SaveChanges(SaveChangesOptions.PostOnlySetProperties | SaveChangesOptions.BatchWithSingleChangeset); // Batch with Single Changeset ensure the saved changed runs in all-or-nothing mode.
            Console.WriteLine(string.Format("Invoice {0} - Saved !", salesOrderNumber));
        }

This is how it looks with correct indentation and syntax hightlighting:

public static void CreateSalesOrderInSingleChangeset(Resources context)
{
	string salesOrderNumber = "100009";
	SalesOrderHeaderV2 salesOrder = new SalesOrderHeaderV2();
	DataServiceCollection<SalesOrderHeaderV2> salesOrderCollection = new DataServiceCollection<SalesOrderHeaderV2>(context);
	salesOrderCollection.Add(salesOrder);
	salesOrder.OrderingCustomerAccountNumber = "US-001";
	salesOrder.DataAreaId = "USMF";
	salesOrder.SalesOrderNumber = salesOrderNumber; // Change number sequence setting in AX to allow user to set values.

	SalesOrderLine salesOrderLine = new SalesOrderLine();
	DataServiceCollection<SalesOrderLine> salesOrderLineCollection = new DataServiceCollection<SalesOrderLine>(context);
	salesOrderLineCollection.Add(salesOrderLine);
	salesOrderLine.SalesOrderNumber = salesOrder.SalesOrderNumber;
	salesOrderLine.ItemNumber = "1000";
	salesOrderLine.OrderedSalesQuantity = 1;
	salesOrderLine.ShippingSiteId = "1";
	salesOrderLine.ShippingWarehouseId = "11";
	salesOrderLine.DataAreaId = "USMF";

	context.SaveChanges(SaveChangesOptions.PostOnlySetProperties | SaveChangesOptions.BatchWithSingleChangeset); // Batch with Single Changeset ensure the saved changed runs in all-or-nothing mode.
	Console.WriteLine(string.Format("Invoice {0} - Saved !", salesOrderNumber));
}

Is SalesOrderLine necessary to reproduce your problem? What if we simplify it to this?

SalesOrderHeaderV2 salesOrder = new SalesOrderHeaderV2()
{
	OrderingCustomerAccountNumber = "US-001",
	DataAreaId = "USMF",
	SalesOrderNumber = "100009"
};

DataServiceCollection<SalesOrderHeaderV2> salesOrderCollection = new DataServiceCollection<SalesOrderHeaderV2>(context);
salesOrderCollection.Add(salesOrder);

context.SaveChanges(SaveChangesOptions.PostOnlySetProperties);	

Ok i try

I tried it according to your code,

The error is as follows:

“message”:"Write failed for table row of type ‘SalesOrderHeaderV2Entity’. Infolog: Warning: Field ‘Sales order’ must be filled in.; Warning: Field ‘Currency’ must be filled in.; Warning: Field ‘Customer account’ must be filled in.; Warning: Field ‘Customer group’ must be filled in.; Warning: Field ‘Invoice account’ must be filled in.; Warning: Field ‘Language’ must be filled in.; Warning: validateWrite failed on data source ‘SalesTable (SalesTable)’.

Am I going to add these required fields

  • Could you tell me what to do next

You said you would add the required fields, so what’s your current code and the current error?

    public static void CreateSalesOrderInSingleChangeset(Resources context)
        {
            SalesOrderHeaderV2 salesOrder = new SalesOrderHeaderV2();
            DataServiceCollection<SalesOrderHeaderV2> salesOrderCollection = new DataServiceCollection<SalesOrderHeaderV2>(context);
            salesOrderCollection.Add(salesOrder);

            salesOrder.OrderingCustomerAccountNumber = "US-001";
            salesOrder.DataAreaId = "USMF";
            salesOrder.SalesOrderNumber = "100005";
            salesOrder.CurrencyCode = "USD";
            salesOrder.InvoiceCustomerAccountNumber = "US-001";
            salesOrder.LanguageId = "en-us";
           
            context.MergeOption = MergeOption.OverwriteChanges;
            context.SaveChanges(SaveChangesOptions.PostOnlySetProperties | SaveChangesOptions.BatchWithSingleChangeset);
        }

Above is my code,

The error is as follows:

6087.12.png

Microsoft.OData.Client.DataServiceRequestException
HResult=0x80131509
Message=An error occurred while processing this request.
Source=Microsoft.OData.Client
StackTrace:
at Microsoft.OData.Client.BatchSaveResult.HandleBatchResponseInternal(ODataBatchReader batchReader)
at Microsoft.OData.Client.BatchSaveResult.HandleBatchResponse()
at Microsoft.OData.Client.BatchSaveResult.HandleResponse()
at Microsoft.OData.Client.BaseSaveResult.EndRequest()
at Microsoft.OData.Client.DataServiceContext.SaveChanges(SaveChangesOptions options)
at ODataConsoleApplication.ODataChangesetsExample.CreateSalesOrderInSingleChangeset(Resources context) in C:\Temp\Dynamics-AX-Integration-master-Erick\Dynamics-AX-Integration-master\ServiceSamples\ODataConsoleApplication\ODataChangesetsExample.cs:line 27
at ODataConsoleApplication.Program.Main(String args) in C:\Temp\Dynamics-AX-Integration-master-Erick\Dynamics-AX-Integration-master\ServiceSamples\ODataConsoleApplication\Program.cs:line 46

Inner Exception 1:
DataServiceClientException: {
“error”:{
“code”:"",“message”:“An error has occurred.”,“innererror”:{
“message”:“Write failed for table row of type ‘SalesOrderHeaderV2Entity’. Infolog: Warning: insert not allowed for field ‘ContactPerson,CustAccount’.”,“type”:“Microsoft.Dynamics.Platform.Integration.Services.OData.AxODataWriteException”,“stacktrace”:" at Microsoft.Dynamics.Platform.Integration.Services.OData.Update.UpdateProcessor.CreateEntity_Save(ChangeOperationContext context, ChangeInfo changeInfo)\r\n at Microsoft.Dynamics.Platform.Integration.Services.OData.Update.UpdateManager.<>c__DisplayClass10_0.b__1(ChangeOperationContext context)\r\n at Microsoft.Dynamics.Platform.Integration.Services.OData.Update.ChangeInfo.ExecuteActionsInCompanyContext(IEnumerable`1 actionList, ChangeOperationContext operationContext)\r\n at Microsoft.Dynamics.Platform.Integration.Services.OData.Update.ChangeInfo.TrySave(ChangeOperationContext operationContext)\r\n at Microsoft.Dynamics.Platform.Integration.Services.OData.Update.UpdateManager.SaveChanges()\r\n at Microsoft.Dynamics.Platform.Integration.Services.OData.AxODataBatchHandler.d__8.MoveNext()"
}
}
}

Inner Exception 2:
ODataErrorException: An error was read from the payload. See the ‘Error’ property for more details.

I originally used the salesorderheaders entity, now I use the salesorderheadersV2 entity

It’s not clear to me why it’s trying to insert ContactPerson.

Try running it directly in X++ in a runnable class:

SalesOrderHeaderV2Entity salesOrder;

salesOrder.OrderingCustomerAccountNumber = "US-001";
salesOrder.SalesOrderNumber = "100005";
salesOrder.CurrencyCode = "USD";
salesOrder.InvoiceCustomerAccountNumber = "US-001";
salesOrder.LanguageId = "en-us";
if (salesOrder.validateWrite())
{
    salesOrder.insert();
}

If it doesn’t work either, you’ll have a simpler case to debug.

If it works there, you’ll at least know that the data is correct. Then you should debug the entity to see what exactly is going on there.

Thank you for providing this class. I found through debugging that it was indeed a problem with my extended entity. Now I have solved the problem, thank you