Batch Integration

The batch integration framework uses scheduled tasks to transfer data and maintain data consistency between a Dynamicweb solution and a remote system – typically a Dynamics NAV or AX solution, a CRM system or a product information management (PIM) system.

A batch integration consists of periodic updates, where data is retrieved from a remote system and imported into the Dynamicweb database – and exported from Dynamicweb and imported into a remote system. 

Figure 1.1 A batch integration

To outline the dataflow:

  • During an import, a call to the web service exposed by the Dynamicweb Connector retrieves the data to be imported and saves the file in XML format on disk – the content is then imported into the Dynamicweb database using the Data Integration module.
  • During an export, the Data Integration module is used to pull data from the database and save it in XML format in the file archive. The saved data is then sent via the web service to the remote system. When the remote system has received the data (e.g. new orders or users), it sends an acknowledgement back to Dynamicweb containing a list of IDs that the data items were saved with in the remote system. The remote system IDs are then added to the newly exported records in the Dynamicweb database.

In this article we will cover three things:

  • How to setup a batch integration on your remote system and in Dynamicweb
  • What kind of data formats Dynamicweb exports – and expects to receive
  • How to modify the data flowing between the remote system and Dynamicweb

Creating a batch integration involves:

  • Installing and configuring a plugin/code unit and the Dynamicweb Connector on a server which can access your remote system
  • Testing the connections using the Dynamicweb Service Test app
  • Creating and configuring integration activities in Dynamicweb
  • Scheduling the activities to run at appropriate intervals

Below, you can read through a typical implementation scenario to help you get started.

The first thing you need to do is ready your remote system – your NAV or AX solution, your CRM, or your PIM – for an integration with Dynamicweb.

In most cases that involves:

  • Installing and configuring a plugin on your remote system
  • Installing and configuring the Dynamicweb Connector web service on your remote environment

The setup procedure varies according to the particular remote system you want to integrate to – find the how-to for your system below.

Once you’ve completed the appropriate how-to, you can test the connection using the Dynamicweb Service Test app.

The Dynamicweb Service Test app (Figure 5.1) is a small tool for testing the web services exposed by the DynamicwebConnector, and by Microsoft NAV, AX and CRM when using the example plugins.

Which service you are testing the connection to is determined by which tab is active.

Figure 5.1 The Dynamicweb Service Test app

You can use the app for two things:

  • Testing the connection to NAV, CRM or AX during setup
  • Testing the connection to the DynamicwebConnector

When testing the connection to NAV, CRM or AX, the configuration (endpoint, username, password, etc.) is taken from the configuration file. This works identically to the configuration of the DynamicwebConnectorService. Basically, if you can connect to your AX, NAV or CRM web service using the Test App, you can copy the configuration directly into you DynamicwebConnectorService configuration file, and it should work.

When testing the connection to the DynamicwebConnector, the settings used are the ones visible in the "DynamicwebServiceTest" tab. The contents of the test app configuration file is ignored. The URL and secret fields should contain the same URL and secret you defined in the DynamicwebConnectorService configuration file.

The Dynamicweb Service Test app must be installed and run from the server on which the DynamicwebConnector is installed.

When you’ve completed the setup guide appropriate to your remote system, you are ready to set up your Dynamicweb solution.

This involves:

  • Populating the Dynamicweb database
  • Setting up continuous integration
  • Creating activities for continuous integration
  • Set up scheduled tasks for the initial and continuous integrations

To get things started you must first populate your Dynamicweb database with data from your remote system, i.e.:

  • Import products, languages, currencies, etc.
  • Import users

To do so you must create data integration activities and create and run a batch integration task.

To create the data integration activities:

  • Go to Settings > Data Integration
  • Click New activity from template
  • Create an activity based on the ErpDataImport template
  • Create an activity based on the ErpUserImport templates

The templates are set to use automatic mapping, which means that as long as the input data is named identically to the tables and columns in the database everything will work out of the box.

When you’ve created the integration activities you must create and run a batch integration task:

  • Go to Settings > Integration > Integration Framework Batch
  • Click Add in the toolbar to create a new batch integration task (Figure 7.1)
Figure 7.1 A batch integration task

To configure the batch integration task you must:

  • Name the task
  • Specify a start and end date (and time)
  • Specify at which interval you want the task to be run (once, every hour, every week, etc.). Since you are populating the database, run the job manually instead of scheduling it.

Using the type dropdown, select the import data add-in (Figure 7.2) and configure it

Figure 7.2 Configuring a batch integration task add-in

To configure the import add-in you must:

  • Enter the web service URL exposed by the DynamicwebConnector (which you also used in the test app). By default this is http://YourServerNameOrIP:8090/DynamicwebService .
  • Enter the security key which is the secret key from the DynamicwebConnector service configuration file (which you also used in the test app)
  • Select a user import activity and/or a data import activity to use (the ones you just created)

You can use the user import settings and data import settings to send data to the root node of the request XML. Make sure it is formatted as valid XML attributes, e.g. ShopId=”Shop1”, which will be sent as <GetEcomData ShopId=”Shop1><tables>…</tables></GetEcomData>. In the Data Integration activity settings field you should also correspondingly enter shopID=”SHOP1”.

In the initial phase you should enable logging – whereas email notifications are more useful for production scenarios. Log files can end up taking up a lot of space, so disable as soon as you have a stable setup.

It is important that you run the Data Integration activities via this batch integration task, or you will not properly connect to the DynamicwebConnector service, and your import will not behave as intended (old date, no updates, and fail without an error).

After the initial import, you may want to schedule import activities for weekly, daily or hourly updates from the remote system – so you have current and updated prices, stock levels, users, etc.

In short, this is done by creating integration activities similar to the ones used for populating the database, but adjusted to only update the desired fields.

The activities should usually cover:

  • Importing products
  • Importing users
  • Exporting users
  • Exporting orders

The Data Integration module contains templates for each of these activities, but you probably need to change or replace them with custom activities in some cases. For instance:

  • If you want to use (preserve) descriptions created in Dynamicweb, you should import products but not map to the ProductShortDescription and ProductLongDescription fields.
  • If you have a very large product catalog, and you only really need to update stock info and prices, you may want to create a custom import job which maps only to the key fields (ProductID, ProductVariantID & ProductLanguageID) and to the ProductStock and ProductPrice fields, in order to improve performance.

In principle, you can import and export anything you’d like using the Dynamicweb Provider – you just need to make sure your remote system is equipped to handle the data accordingly.

The activities for continuous integration are scheduled and run in exactly the same way as the initial import was – and the export data add-in is configured in the same manner as the import add-in.

All data entering and leaving Dynamicweb follows the same general structure:

<?xml version="1.0" encoding="utf-8"?> <tables> <table tableName="Table1"> <item table="Table1"> <column columnName="Column1"><![CDATA[5]]></column> <column columnName="Column2" isNull="true"/> <column columnName="Column3"><![CDATA[James]]></column> </item> </table> <table tableName="Table2"> <item table="Table2"> <column columnName="Column1"><![CDATA[7913]]></column> <column columnName="Column2"><![CDATA[VIP]]></column> </item> </table> </tables>

Additionally, most solutions employ some form of custom data – whether it’s custom product fields, custom user fields, or something else entirely – and this is especially true for solutions with integration, as you often need to create custom properties or fields for storing data from your remote system which are not present in Dynamicweb by default.

At any point in time, you can create a data integration activity (using the Dynamicweb provider as the source provider and the XML provider as the destination provider) and export the relevant parts of your Dynamicweb database to view the exact markup for your solution

When importing data, it’s sometimes necessary to create data integration activities using manual mapping, in order to make sure the data from the remote system is mapped correctly into the custom fields in Dynamicweb. However, if you are able to convince the remote system people to name the data in their custom fields exactly as they are named in the Dynamicweb database you can still use automatic mapping.

To help you get started, we’ve described some of the most common integration use case scenarios below.

For assortments, the data format is as follows:

<?xml version="1.0" encoding="utf-8"?> <tables> <table tableName="EcomAssortmentGroupRelations"> <item table="EcomAssortmentGroupRelations"> <column columnName="AssortmentGroupRelationAssortmentID"><![CDATA[ASSORTMENT1]]></column> <column columnName="AssortmentGroupRelationGroupID"><![CDATA[GROUP35]]></column> <column columnName="AssortmentGroupRelationAutoID"><![CDATA[1]]></column> </item> </table> <table tableName="EcomAssortmentPermissions"> <item table="EcomAssortmentPermissions"> <column columnName="AssortmentPermissionAssortmentID"><![CDATA[ASSORTMENT1]]></column> <column columnName="AssortmentPermissionAccessUserID"><![CDATA[363]]></column> <column columnName="AssortmentPermissionAutoID"><![CDATA[7]]></column> <column columnName="AssortmentPermissionCustomerNumber"><![CDATA[]]></column> </item> <item table="EcomAssortmentPermissions"> <column columnName="AssortmentPermissionAssortmentID"><![CDATA[ASSORTMENT2]]></column> <column columnName="AssortmentPermissionAccessUserID"><![CDATA[288]]></column> <column columnName="AssortmentPermissionAutoID"><![CDATA[3]]></column> <column columnName="AssortmentPermissionCustomerNumber"><![CDATA[]]></column> </item> <item table="EcomAssortmentPermissions"> <column columnName="AssortmentPermissionAssortmentID"><![CDATA[ASSORTMENT2]]></column> <column columnName="AssortmentPermissionAccessUserID"><![CDATA[326]]></column> <column columnName="AssortmentPermissionAutoID"><![CDATA[5]]></column> <column columnName="AssortmentPermissionCustomerNumber"><![CDATA[]]></column> </item> </table> <table tableName="EcomAssortmentProductRelations"> <item table="EcomAssortmentProductRelations"> <column columnName="AssortmentProductRelationAssortmentID"><![CDATA[ASSORTMENT1]]></column> <column columnName="AssortmentProductRelationProductID"><![CDATA[PROD16]]></column> <column columnName="AssortmentProductRelationProductVariantID"><![CDATA[]]></column> <column columnName="AssortmentProductRelationAutoID"><![CDATA[1]]></column> <column columnName="AssortmentProductRelationProductNumber" isNull="true" /> </item> </table> <table tableName="EcomAssortments"> <item table="EcomAssortments"> <column columnName="AssortmentID"><![CDATA[ASSORTMENT1]]></column> <column columnName="AssortmentLanguageID"><![CDATA[LANG1]]></column> <column columnName="AssortmentName"><![CDATA[My assortment]]></column> <column columnName="AssortmentNumber"><![CDATA[]]></column> <column columnName="AssortmentPeriodID" isNull="true" /> <column columnName="AssortmentLastBuildDate"><![CDATA[22-06-2016 16:00:01:623]]></column> <column columnName="AssortmentRebuildRequired"><![CDATA[False]]></column> <column columnName="AssortmentAutoID"><![CDATA[1]]></column> <column columnName="AssortmentActive"><![CDATA[True]]></column> <column columnName="AssortmentIncludeSubgroups"><![CDATA[False]]></column> <column columnName="AssortmentAllowAnonymousUsers"><![CDATA[False]]></column> </item> <item table="EcomAssortments"> <column columnName="AssortmentID"><![CDATA[ASSORTMENT2]]></column> <column columnName="AssortmentLanguageID"><![CDATA[LANG1]]></column> <column columnName="AssortmentName"><![CDATA[Customer 1 in FR]]></column> <column columnName="AssortmentNumber"><![CDATA[]]></column> <column columnName="AssortmentPeriodID" isNull="true" /> <column columnName="AssortmentLastBuildDate"><![CDATA[13-05-2015 12:55:09:090]]></column> <column columnName="AssortmentRebuildRequired"><![CDATA[False]]></column> <column columnName="AssortmentAutoID"><![CDATA[2]]></column> <column columnName="AssortmentActive"><![CDATA[False]]></column> <column columnName="AssortmentIncludeSubgroups"><![CDATA[False]]></column> <column columnName="AssortmentAllowAnonymousUsers"><![CDATA[False]]></column> </item> </table> <table tableName="EcomAssortmentShopRelations"> <item table="EcomAssortmentShopRelations"> <column columnName="AssortmentShopRelationAssortmentID"><![CDATA[ASSORTMENT1]]></column> <column columnName="AssortmentShopRelationShopID"><![CDATA[SHOP4]]></column> <column columnName="AssortmentShopRelationAutoID"><![CDATA[1]]></column> </item> </table> </tables>

The mandatory fields for each table are:

  •  EcomAssortmentGroupRelations:
    • AssortmentGroupRelationAssortmentID (ID of assortment)
    • AssortmentGroupRelationGroupID (ID of product group)
  • EcomAssortmentPermissions:
    • AssortmentPermissionAssortmentID (ID of assortment)
    • AssortmentPermissionCustomerNumber (customer number the assormtent is for)
  • EcomAssortmentProductRelations:
    • AssortmentProductRelationAssortmentID (id of assortment)
    • AssortmentProductRelationProductID (id of product in the assortment)
  • EcomAssortments:
    • AssortmentID
    • AssortmentActive
  • EcomAssortmentShopRelations:
    • AssortmentShopRelationAssortmentID
    • AssortmentShopRelationShopID

 

For currencies the data format is as follows:

<?xml version="1.0" encoding="utf-8"?> <tables> <table tableName="EcomCurrencies"> <item table="EcomCurrencies"> <column columnName="CurrencyCode"><![CDATA[DKK]]></column> <column columnName="CurrencyLanguageID"><![CDATA[LANG6]]></column> <column columnName="CurrencySymbol"><![CDATA[DKK ]]></column> <column columnName="CurrencyName"><![CDATA[Kroner]]></column> <column columnName="CurrencyRate"><![CDATA[100]]></column> <column columnName="CurrencyIsDefault"><![CDATA[False]]></column> <column columnName="CurrencyCultureInfo"><![CDATA[da-DK]]></column> <column columnName="CurrencyPayGatewayCode"><![CDATA[208]]></column> <column columnName="CurrencyRoundingID"><![CDATA[ROUNDING2]]></column> <column columnName="CurrencySymbolPlace"><![CDATA[0]]></column> <column columnName="CurrencyPositivePattern"><![CDATA[3]]></column> <column columnName="CurrencyNegativePattern"><![CDATA[8]]></column> </item> </table> </tables>

The only mandatory field is CurrencyCode (EUR, DKK, etc.).

For order and order lines, the data format is as follows:

<?xml version="1.0" encoding="utf-8"?> <tables> <table tableName="EcomOrders"> <item table="EcomOrders"> <column columnName="OrderID"><![CDATA[CART1513]]></column> <column columnName="OrderShopID"><![CDATA[]]></column> <column columnName="OrderDate"><![CDATA[06-03-2015 12:17:46:167]]></column> <column columnName="OrderModified"><![CDATA[06-03-2015 12:18:29:020]]></column> <column columnName="OrderComplete"><![CDATA[False]]></column> <column columnName="OrderDeleted"><![CDATA[False]]></column> <column columnName="OrderStateID" isNull="true"/> <column columnName="OrderVAT"><![CDATA[108,998]]></column> <column columnName="OrderIP"><![CDATA[93.178.190.58]]></column> <column columnName="OrderReferrer"><![CDATA[]]></column> <column columnName="OrderTransactionValue"><![CDATA[]]></column> <column columnName="OrderTransactionType"><![CDATA[]]></column> <column columnName="OrderTransactionStatus"><![CDATA[]]></column> <column columnName="OrderTransactionAmount"><![CDATA[0]]></column> <column columnName="OrderTransactionPayGatewayCode"><![CDATA[]]></column> <column columnName="OrderTrackTraceNumber"><![CDATA[]]></column> <column columnName="OrderShippingMethod"><![CDATA[]]></column> <column columnName="OrderShippingMethodFee"><![CDATA[8]]></column> <column columnName="OrderPaymentMethod"><![CDATA[]]></column> <column columnName="OrderPaymentMethodFee"><![CDATA[0]]></column> <column columnName="OrderSalesDiscount"><![CDATA[0]]></column> <column columnName="OrderCurrencyName"><![CDATA[Euro]]></column> <column columnName="OrderCurrencyRate"><![CDATA[750]]></column> <column columnName="OrderCurrencyCode"><![CDATA[EUR]]></column> <column columnName="OrderCart"><![CDATA[True]]></column> <column columnName="OrderFieldsXML"><![CDATA[]]></column> <column columnName="OrderReSendEmail"><![CDATA[]]></column> <column columnName="OrderCustomerNumber"><![CDATA[]]></column> <column columnName="OrderCustomerCompany"><![CDATA[]]></column> <column columnName="OrderCustomerName"><![CDATA[]]></column> <column columnName="OrderCustomerAddress"><![CDATA[]]></column> <column columnName="OrderCustomerAddress2"><![CDATA[]]></column> <column columnName="OrderCustomerZip"><![CDATA[]]></column> <column columnName="OrderCustomerCity"><![CDATA[]]></column> <column columnName="OrderCustomerCountry"><![CDATA[]]></column> <column columnName="OrderCustomerRegion"><![CDATA[]]></column> <column columnName="OrderCustomerPhone"><![CDATA[]]></column> <column columnName="OrderCustomerFax"><![CDATA[]]></column> <column columnName="OrderCustomerEmail"><![CDATA[]]></column> <column columnName="OrderCustomerCell"><![CDATA[]]></column> <column columnName="OrderCustomerRefID"><![CDATA[]]></column> <column columnName="OrderCustomerEAN"><![CDATA[]]></column> <column columnName="OrderCustomerVatRegNumber"><![CDATA[]]></column> <column columnName="OrderDeliveryCompany"><![CDATA[]]></column> <column columnName="OrderDeliveryName"><![CDATA[]]></column> <column columnName="OrderDeliveryAddress"><![CDATA[]]></column> <column columnName="OrderDeliveryAddress2"><![CDATA[]]></column> <column columnName="OrderDeliveryZip"><![CDATA[]]></column> <column columnName="OrderDeliveryCity"><![CDATA[]]></column> <column columnName="OrderDeliveryCountry"><![CDATA[]]></column> <column columnName="OrderDeliveryRegion"><![CDATA[]]></column> <column columnName="OrderDeliveryPhone"><![CDATA[]]></column> <column columnName="OrderDeliveryFax"><![CDATA[]]></column> <column columnName="OrderDeliveryEmail"><![CDATA[]]></column> <column columnName="OrderDeliveryCell"><![CDATA[]]></column> <column columnName="OrderTotalPrice"><![CDATA[0]]></column> <column columnName="OrderComment"><![CDATA[]]></column> <column columnName="OrderCustomerComment"><![CDATA[]]></column> <column columnName="OrderWeight"><![CDATA[0]]></column> <column columnName="OrderVolume"><![CDATA[0]]></column> <column columnName="OrderPriceWithVAT"><![CDATA[552,99]]></column> <column columnName="OrderPriceWithoutVAT"><![CDATA[443,992]]></column> <column columnName="OrderPriceVAT"><![CDATA[108,998]]></column> <column columnName="OrderPriceVATPercent"><![CDATA[24,549541433179]]></column> <column columnName="OrderShippingFeeWithVAT"><![CDATA[8]]></column> <column columnName="OrderShippingFeeWithoutVAT"><![CDATA[8]]></column> <column columnName="OrderShippingFeeVAT"><![CDATA[0]]></column> <column columnName="OrderShippingFeeVATPercent"><![CDATA[0]]></column> <column columnName="OrderPaymentFeeWithVAT"><![CDATA[0]]></column> <column columnName="OrderPaymentFeeWithoutVAT"><![CDATA[0]]></column> <column columnName="OrderPaymentFeeVAT"><![CDATA[0]]></column> <column columnName="OrderPaymentFeeVATPercent"><![CDATA[0]]></column> <column columnName="OrderPriceBeforeFeesWithVAT"><![CDATA[544,99]]></column> <column columnName="OrderPriceBeforeFeesWithoutVAT"><![CDATA[435,992]]></column> <column columnName="OrderPriceBeforeFeesVAT"><![CDATA[108,998]]></column> <column columnName="OrderPriceBeforeFeesVATPercent"><![CDATA[25]]></column> <column columnName="OrderCustomerAccessUserID"><![CDATA[0]]></column> <column columnName="OrderCustomerAccessUserUserName"><![CDATA[]]></column> <column columnName="OrderShippingMethodID"><![CDATA[]]></column> <column columnName="OrderPaymentMethodID"><![CDATA[]]></column> <column columnName="OrderGatewayResult" isNull="true"/> <column columnName="OrderStepNum"><![CDATA[0]]></column> <column columnName="OrderTransactionNumber" isNull="true"/> <column columnName="OrderCustomerCountryCode"><![CDATA[]]></column> <column columnName="OrderDeliveryCountryCode"><![CDATA[]]></column> <column columnName="OrderStepHistory"><![CDATA[]]></column> <column columnName="OrderLanguageID"><![CDATA[LANG1]]></column> <column columnName="OrderTransactionMailSend"><![CDATA[False]]></column> <column columnName="OrderShippingMethodDescription"><![CDATA[]]></column> <column columnName="OrderPaymentMethodDescription"><![CDATA[]]></column> <column columnName="OrderCustomerNewsletterSubcribe"><![CDATA[False]]></column> <column columnName="coupons"><![CDATA[]]></column> <column columnName="OrderGatewayPaymentStatus"><![CDATA[]]></column> <column columnName="upload"><![CDATA[]]></column> <column columnName="OrderGatewayTransactionProblems"><![CDATA[<?xml version="1.0" encoding="utf-16"?> <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />]]></column> <column columnName="catalog"><![CDATA[False]]></column> <column columnName="OrderCaptureInfo"><![CDATA[<?xml version="1.0" encoding="utf-8" standalone="yes"?><OrderCaptureInfo><Timestamp>-8587759662193095175</Timestamp><State>NotCaptured</State><Message></Message></OrderCaptureInfo>]]></column> <column columnName="OrderCartV2StepIndex"><![CDATA[0]]></column> <column columnName="OrderSecret"><![CDATA[23af9d144d63419fba08629c7409aee0]]></column> <column columnName="OrderShippingCountrySelection"><![CDATA[CustomerCountry]]></column> <column columnName="OrderPaymentCountrySelection"><![CDATA[CustomerCountry]]></column> <column columnName="OrderCustomerAccepted"><![CDATA[False]]></column> <column columnName="OrderDebuggingInfo"><![CDATA[]]></column> <column columnName="OrderHasSetUserDetails"><![CDATA[False]]></column> <column columnName="OrderGatewayUniqueID"><![CDATA[]]></column> <column columnName="OrderTrackAndTraceID"><![CDATA[0]]></column> <column columnName="OrderTrackAndTraceParameters"><![CDATA[]]></column> <column columnName="OrderIntegrationOrderID"><![CDATA[]]></column> <column columnName="OrderRequisition"><![CDATA[]]></column> <column columnName="OrderAXOrderID" isNull="true"/> <column columnName="OrderVisitorSessionID"><![CDATA[mu2apqsmr5cxk0cgtqehpv3r]]></column> <column columnName="OrderIsExported" isNull="true"/> <column columnName="OrderVoucherCode"><![CDATA[]]></column> <column columnName="OrderCustomerSurname"><![CDATA[]]></column> <column columnName="OrderCustomerInitials"><![CDATA[]]></column> <column columnName="OrderCustomerPrefix"><![CDATA[]]></column> <column columnName="OrderDeliverySurname"><![CDATA[]]></column> <column columnName="OrderDeliveryInitials"><![CDATA[]]></column> <column columnName="OrderDeliveryPrefix"><![CDATA[]]></column> <column columnName="OrderShippingDocumentData" isNull="true"/> <column columnName="OrderShippingProviderData" isNull="true"/> <column columnName="OrderCompletedDate" isNull="true"/> <column columnName="ReceiptShowCount"><![CDATA[0]]></column> <column columnName="OrderAccountAccessUserID" isNull="true"/> <column columnName="OrderImpersonatedUserID" isNull="true"/> <column columnName="OrderImpersonatingUserID" isNull="true"/> <column columnName="OrderSecondaryUserID"><![CDATA[0]]></column> <column columnName="OrderReceiptShowCount"><![CDATA[0]]></column> <column columnName="OrderCaptureAmount"><![CDATA[0]]></column> <column columnName="OrderTransactionCardType"><![CDATA[]]></column> <column columnName="OrderExternalPaymentFee"><![CDATA[0]]></column> <column columnName="OrderPriceCalculationDate"><![CDATA[06-03-2015 12:18:29:000]]></column> <column columnName="OrderCustomerTitle"><![CDATA[]]></column> <column columnName="OrderCustomerFirstName"><![CDATA[]]></column> <column columnName="OrderCustomerMiddleName"><![CDATA[]]></column> <column columnName="OrderCustomerHouseNumber"><![CDATA[]]></column> <column columnName="OrderDeliveryTitle"><![CDATA[]]></column> <column columnName="OrderDeliveryFirstName"><![CDATA[]]></column> <column columnName="OrderDeliveryMiddleName"><![CDATA[]]></column> <column columnName="OrderDeliveryHouseNumber"><![CDATA[]]></column> <column columnName="OrderTotalPoints"><![CDATA[0]]></column> <column columnName="OrderTotalRewardPoints"><![CDATA[0]]></column> <column columnName="OrderTotalDiscountWithVAT"><![CDATA[0]]></column> <column columnName="OrderTotalDiscountWithoutVAT"><![CDATA[0]]></column> <column columnName="OrderTotalDiscountVAT"><![CDATA[0]]></column> <column columnName="OrderTotalDiscountVATPercent"><![CDATA[0]]></column> <column columnName="OrderIsQuote"><![CDATA[False]]></column> <column columnName="OrderTransactionCardNumber"><![CDATA[]]></column> <column columnName="OrderCheckoutPageID"><![CDATA[0]]></column> <column columnName="OrderVisitorSessionDate"><![CDATA[06-03-2015 12:17:46:167]]></column> <column columnName="OrderPriceCalculatedByProvider"><![CDATA[False]]></column> <column columnName="OrderTaxTransactionNumber"><![CDATA[]]></column> <column columnName="OrderVoucherUseType"><![CDATA[0]]></column> <column columnName="OrderContextID" isNull="true"/> <column columnName="con" isNull="true"/> <column columnName="OrderGiftcardTransactionFailed"><![CDATA[False]]></column> <column columnName="OrderShippingFeeRuleName" isNull="true"/> <column columnName="OrderRecurringOrderId" isNull="true"/> <column columnName="OrderPaymentRecurringInfo" isNull="true"/> <column columnName="OrderSavedCardID" isNull="true"/> <column columnName="OrderIsRecurringOrderTemplate" isNull="true"/> <column columnName="OrderAutoID"><![CDATA[129]]></column> <column columnName="OrderCustomerAccessUserExternalId" isNull="true"/> </item> </table> <table tableName="EcomOrderLines"> <item table="EcomOrderLines"> <column columnName="OrderLineID"><![CDATA[OL4069]]></column> <column columnName="OrderLineOrderID"><![CDATA[CART1513]]></column> <column columnName="OrderLineParentLineID"><![CDATA[]]></column> <column columnName="OrderLineBOM"><![CDATA[False]]></column> <column columnName="OrderLineDate"><![CDATA[06-03-2015 12:17:46:497]]></column> <column columnName="OrderLineModified"><![CDATA[06-03-2015 12:17:46:513]]></column> <column columnName="OrderLineProductNumber"><![CDATA[10121]]></column> <column columnName="OrderLineProductID"><![CDATA[PROD132]]></column> <column columnName="OrderLineProductVariantID"><![CDATA[]]></column> <column columnName="OrderLineProductName"><![CDATA[Mongoose Supergoose Cruiser BMX]]></column> <column columnName="OrderLineProductVariantText"><![CDATA[]]></column> <column columnName="OrderLineUnitPrice" isNull="true"/> <column columnName="OrderLineVatPercent" isNull="true"/> <column columnName="OrderLineVatPrice" isNull="true"/> <column columnName="OrderLineQuantity"><![CDATA[1]]></column> <column columnName="OrderLineType"><![CDATA[0]]></column> <column columnName="OrderLineReference"><![CDATA[http://wrap.dynamicweb-cms.com/products-1/bikes/mongoose-supergoose-cruiser-bmx]]></column> <column columnName="OrderLineBOMItemID"><![CDATA[]]></column> <column columnName="OrderLineUnitID"><![CDATA[]]></column> <column columnName="OrderLineWeight"><![CDATA[0]]></column> <column columnName="OrderLineVolume"><![CDATA[0]]></column> <column columnName="OrderLinePriceWithVAT"><![CDATA[399,99]]></column> <column columnName="OrderLinePriceWithoutVAT"><![CDATA[319,992]]></column> <column columnName="OrderLinePriceVAT"><![CDATA[79,998]]></column> <column columnName="OrderLinePriceVATPercent"><![CDATA[25]]></column> <column columnName="OrderLineUnitPriceWithVAT"><![CDATA[399,99]]></column> <column columnName="OrderLineUnitPriceWithoutVAT"><![CDATA[319,992]]></column> <column columnName="OrderLineUnitPriceVAT"><![CDATA[79,998]]></column> <column columnName="OrderLineUnitPriceVATPercent"><![CDATA[25]]></column> <column columnName="OrderLinePageId"><![CDATA[8398]]></column> <column columnName="OrderLineDiscountID"><![CDATA[]]></column> <column columnName="OrderLineFieldValues"><![CDATA[<OrderLineFieldValueCollection />]]></column> <column columnName="OrderLineAttachment"><![CDATA[]]></column> <column columnName="OrderLineWishListID"><![CDATA[0]]></column> <column columnName="OrderLinePriceCalculationReference"><![CDATA[]]></column> <column columnName="OrderLineUnitPriceCalculationReference"><![CDATA[]]></column> <column columnName="OrderLineUnitPoints" isNull="true"/> <column columnName="OrderLineUnitRewardPoints" isNull="true"/> <column columnName="OrderLinePoints" isNull="true"/> <column columnName="OrderLineRewardPoints" isNull="true"/> <column columnName="OrderLineRewardId" isNull="true"/> <column columnName="OrderLineReverseChargeForVat"><![CDATA[False]]></column> <column columnName="OrderLineTotalDiscountWithVAT"><![CDATA[0]]></column> <column columnName="OrderLineTotalDiscountWithoutVAT"><![CDATA[0]]></column> <column columnName="OrderLineTotalDiscountVAT"><![CDATA[0]]></column> <column columnName="OrderLineTotalDiscountVATPercent"><![CDATA[0]]></column> <column columnName="OrderLineGiftCardCode" isNull="true"/> </item> </table> </tables>

The mandatory fields are:

  • EcomOrderlines
    • orderlineID (must be unique)
  • EcomOrders
    • orderID (must be unique)

 

In some cases, you will need to modify the data flowing between Dynamicweb and your remote system – either because you want to import or export data which is not covered by our standard functionality, because you need to send a non-standard set of parameters to your remote system, or because you are creating an integration with a remote system which is not included in the framework by default.

Broadly speaking there are three places to accomplish that:

  • Custom Scheduled task add-ins
    While there are several standard scheduled task add-ins available for batch integration, these may not be adequate for your needs. In that case, you can create custom scheduled task add-ins, which can handle and modify the data being sent to and received from the Dynamicweb Connector.
  • Data Integration tasks & custom data integration providers
    Both imported and exported data is handled by the Data Integration module. This means that you can customize the data flow here as well, either by configuring your data integration tasks – or by creating a custom Data Integration provider.
  • Custom Dynamicweb Connector add-ins
    If you customize the Dynamicweb Connector add-in you have full control over which data is returned by the Dynamicweb Connector, since your custom add-in code handles the dataflow to and from the remote system. Custom add-ins are usually only relevant if you are integrating with a remote system for which we do not provide a standard add-in, or if the remote system is heavily customized.

If you need to implement functionality which is not possible using our standard batch integration task add-ins – e.g. retrieve product images from an external system – you can create custom scheduled task add-ins.

A template for creating custom batch integration task add-ins are included in the Visual Studio templates available from the Downloads page. The template contains the full source code for one of the standard scheduled task add-ins that come with Dynamicweb – it should be fairly straight forward to adjust as needed.

You will be using the ErpServiceCaller helper class to communicate with the DynamicwebConnector.

Batch Integration tasks are executed using the Data Integration module, which means that you can modify data in all the standard ways associated with that module:

  •  Use the built-in mapping tools, such as conditionals, scripting and XSLT transformations
  • Use a different Data Integration provider, e.g. the Ecom provider, which can auto-generate product information from incomplete data
  • Creating a custom data integration provider – or extending an existing one

The Dynamicweb Connector receives and transmits data to and from a remote system and Dynamicweb.

The Dynamicweb Connector add-in interface is fairly simple; it has one method, which takes a string as an argument, and returns a string.

When you create your own version of the add-in, you must

  • Handle the incoming xml sent by Dynamicweb
  • Return xml in the format which Dynamicweb expects

A template for creating custom connector add-ins is included in the Dynamicweb templates for Visual Studio.

Have you considered using the Import data with custom request add-in? It may be an easier solution than creating a custom DynamicwebConnector add-in.

The request for data from the remote system is fairly simple:

<GetEcomData> <tables> <Products type="all"/> <Currencies type="all"/> <Countries type="all"/> <Languages type="all"/> <Manufacturers type="all"/> </tables> </GetEcomData>

Your code should capable of returning data for just one of the tables requested. So for an example like…

<GetEcomData> <tables> <Users type=”all”/> </tables> </GetEcomData>

..you should only return data for users – and not for products, currencies or any other tables.

You can safely ignore requests for data not used in your implementation (e.g. if you do not import currencies and languages but create them directly in Dynamicweb) – you should get no exceptions.

It is also ok to include more data than is requested when it makes sense – e.g. when you request ‘products type = “all”’, you can include groups, variants, variant options, etc. – as this data may be necessary to present products correctly.

The attribute “type” is used to indicate if this is a batch request (where you want to retrieve all data for a given table) or a live request (where you want to retrieve only a subset of the data, e.g. for the products shown in the page you are rendering).

Since batch integration imports data using the Data Integration module, the return format can be any format accepted by the data integration provider used – please see the Data Integration module documentation for a general overview of the standard providers, and each provider article for provider particular information. The basic format for needed for the return data can be seen in AllTables.xml and Users.xml .

Please note that these example XML files contain the columns accepted by Dynamicweb, they are not all mandatory - however:

  • When importing users using the default User Provider activity, the AccessUserUserName must be present and unique for each user, and the same applies to AccessUserExternalID (if you use the Dynamicweb provider, you can define your own keys)
  • When importing products the minimum amount of data which makes sense is a ProductID, alongside either ProductPrice or ProductStock. Usually employs the Dynamicweb Provider, although the Ecom Provider may be a valid alternative, depending on your needs.

Exporting orders from Dynamicweb to the remote system is done with PutEcomOrders – see PutEcomOrders.xml for an example. The example contains a single order, but could just as well contain more, and each order should be handled.

The return XML format which Dynamicweb expects to get back is fairly simple. If we export two orders (ORDER 19 and ORDER20), we expect to receive XML looking like this:

<?xml version="1.0" encoding="utf-8"?> <createdOrders> <order> <OrderID>ORDER19</OrderID> <externalOrderId>1041</externalOrderId> </order> <order> <OrderID>ORDER20</OrderID> <externalOrderId>1042</externalOrderId> </order> </createdOrders>

The ExternalOrderIDs are then saved to the Dynamicweb database, and used to ensure that the same order isn’t exported multiple times. Additionally, the external orderId is visible in the Dynamicweb backend, in order to make it easy to see how the orders in Dynamicweb relate to the orders in the remote system.

Exporting users from Dynamicweb to a remote system is done with PutUsers – see PutUsers.xml for an example.

The return xml format which Dynamicweb expects to get back is fairly simple. If we export two users, with AccessUserID 1 and 2, we expect to receive XML looking like this:

<createdUsers> <user> <userId>1</userid> <externalUserId>NavID1</externalUserID> </user> <user> <userId>2</userid> <externalUserId>NavID2</externalUserID> </user> </createdUsers>

The ExternalUserIDs are then saved to the Dynamicweb database.

Any settings you need in your custom add-in – e.g. connection strings for databases, references, login credentials, etc. – can be saved and loaded from the config file associated with the DynamicwebConnector.

The settings are retrieved as usual, from the configuration. Assuming you have a setting called “ConnectionString” in a section called “ExampleConnectorAddin”, you can retrieve it using the following code:

NameValueCollection connectorSettings = (NameValueCollection)ConfigurationManager.GetSection("ExampleConnectorAddin"); string connectionString = connectorSettings["ConnectionString"];

When you have created a custom add-in:

  • Copy the dll to the folder where your DynamicwebConnectorService is located
  • Open the DynamicwebConnectorService.exe.config file and locate the <appSettings> node
  • Change the value of <add key="ErpConnectorType" value="NavConnectorAddIn.NavConnector"/> to the fully qualified name of your custom connector, e.g.:
<appSettings> <add key="ServiceName" value="DynamicwebService" /> <add key="testMode" value="False" /> <add key="TestOutputFile" value="c:\exportContent.xml" /> <add key="Secret" value="test" /> <add key="DebugInfo" value="True"/> <add key="WebserviceURI" value="http://localhost:8090/DynamicwebService"/> <add key="ErpConnectorType" value="MyFancyCustomConnectorAddin.NavConnector"/> </appSettings>