Header/line data, like sales orders, invoices and financial entries, consists out of multiple records: 1 header record and 1 or more line records containing the details for that entry. To tie all these records together, the entity service uses a meta identifier, the transaction key, which uniquely identifies all records belonging to a single header/line entry. This key is returned in the dataset during the creation of the first line record and should be supplied for all other records. The entry is validated and created after the header record is created. The process for creating a new entry is therefore as follows:
Please note that at the time of writing this HOWTO, only Create and Delete are supported. Reading of header/line entries can be done through the Retrieve set service.
This HOWTO uses Exact.Services.Client.dll, which takes care of the binding and serialization towards the actual entity service. To that end, include a reference to Exact.Services.Client.dll, and to the standard System.ServiceModel and System.Runtime.Serialization libraries. Because the solution will most likely be built to either run from within an existing EGN installation, or be self contained, it is usually wise to turn off Copy local for the Exact assembly. With self contained solutions, it is best to include a copy of the assembly you built the solution against in your deployment set.The only global declare needed is an EntityClientEG instance, which you should reuse for all Create actions on the same database. The actual data object's lifespan depends on what is done before and after the creation, and as such can be done either globally or locally.
Private entityClient As Exact.Services.Client.Entity.EntityClientEGPrivate entityData As Exact.Services.Client.Data.EntityData
When instancing the entityClient, make sure to only point to the services folder on the server. The actual endpoint will be filled in by the class itself. Instancing the client class is unlikely to throw an exception. Any issues with the service endpoint or the database will not be reported until a method within the class is used. This is because the service is only accessed when an actual action has to be performed.
entityClient = New Exact.Services.Client.Entity.EntityClientEG("http://localhost:8010/services", ".\sql2008r2", "102")
After creating the first line, make sure to retrieve the TransactionKey. This will be a GUID, although it is ocasionally returned as a GUID formatted string.
Dim transactionKey As GuidentityData = New Exact.Services.Client.Data.EntityData()EntityData.EntityName = "FinancialLine"With entityData.Properties propertyData = New Exact.Services.Client.Data.PropertyData("GLAccount", "2300") .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("Amount", 100.0) .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("VATCode", "2") .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("ItemCode", "BEK0001") .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("Quantity", "5") .Add(propertyData)End WithTry entityData = entityClient.Create(entityData)Catch ex As Exact.Services.Client.Exceptions.EntityFunctionalException Dim fe As System.ServiceModel.FaultException(Of Exact.Services.Client.Data.EntityFault) fe = CType(ex.InnerException, System.ServiceModel.FaultException(Of Exact.Services.Client.Data.EntityFault)) MessageBox.Show("Validation error: " & ParseValidationError(fe.Detail)) Return FalseCatch ex As Exception MessageBox.Show("Exception occurred trying to create first line: " & ex.Message) Return FalseEnd TrytransactionKey = New Guid(entityData.Properties("TransactionKey").Value.ToString())
All subsequent lines should be entered using the same transaction key.
entityData = New Exact.Services.Client.Data.EntityData()entityData.EntityName = "FinancialLine"With entityData.Properties propertyData = New Exact.Services.Client.Data.PropertyData("GLAccount", "2300") .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("Amount", 50.0) .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("VATCode", "2") .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("ItemCode", "BEK0002") .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("Quantity", "3") .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("TransactionKey", transactionKey) .Add(propertyData)End WithTry entityData = entityClient.Create(entityData)Catch ex As Exact.Services.Client.Exceptions.EntityFunctionalException Dim fe As System.ServiceModel.FaultException(Of Exact.Services.Client.Data.EntityFault) fe = CType(ex.InnerException, System.ServiceModel.FaultException(Of Exact.Services.Client.Data.EntityFault)) MessageBox.Show("Validation error: " & ParseValidationError(fe.Detail)) Return FalseCatch ex As Exception MessageBox.Show("Exception occurred trying to create second line: " & ex.Message) Return FalseEnd Try
Uppon creating the header, the entry will be validated and created. This step is therefore most likely to throw an Exception.
entityData = New Exact.Services.Client.Data.EntityDataentityData.EntityName = "FinancialHeader"With entityData.PropertiespropertyData = New Exact.Services.Client.Data.PropertyData("Journal", " 70") .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("DebtorNumber", 60089) .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("EntryDate", DateTime.Now.Date) .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("YourReference", "ESTA0001") .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("Description", "Test entity services A0001") .Add(propertyData) propertyData = New Exact.Services.Client.Data.PropertyData("TransactionKey", transactionKey) .Add(propertyData)End WithTry entityData = entityClient.Create(entityData)Catch ex As Exact.Services.Client.Exceptions.EntityFunctionalException Dim fe As System.ServiceModel.FaultException(Of Exact.Services.Client.Data.EntityFault) fe = CType(ex.InnerException, System.ServiceModel.FaultException(Of Exact.Services.Client.Data.EntityFault)) MessageBox.Show("Validation error: " & ParseValidationError(fe.Detail)) Return FalseCatch ex As Exception MessageBox.Show("Exception occurred trying to create header: " & ex.Message) Return FalseEnd TryReturn True
Validation errors will be passed back as an instance of Exact.Services.Client.Exceptions.EntityFunctionalException. Within this Exception will be a Fault object containing a collection of each property/error combination.
Private Function ParseValidationError(ByVal entityFault As Exact.Services.Client.Data.EntityFault) As String Dim sb As New System.Text.StringBuilder() If entityFault.Exceptions.Count = 0 Then Return entityFault.Message End If For Each propFault As Exact.Services.Client.Data.WSExceptionInfo In entityFault.Exceptions sb.AppendFormat("Property:{0} Message:{1}", propFault.PropertyName, propFault.Message) sb.AppendLine() Next Return sb.ToString()End Function