Skip to main content

EzXml - Customer sync

EzXml Connector - CustomerUpdate Function The CustomerUpdate function for the EzXml connector is responsible for synchronizing customer ...

Updated over a week ago

EzXml Connector - CustomerUpdate Function

The CustomerUpdate function for the EzXml connector is responsible for synchronizing customer data from an external EzXml system into the internal App4Sales database. This includes core customer information, associated addresses, contact persons, item class discounts, free fields, and customer dashboards. The process involves retrieving customer data from an XML file via FTP, transforming this raw data into App4Sales's internal customer model, and then applying a comprehensive set of business rules, validations, and updates to persist the data.

Customer Core Fields

App4Sales Field

Source Field (API/Excel/DB)

Logic/Notes

CustomerCode

FD_customers.xml: /customers/data/customer/customer_no

Direct mapping from the XML 'customer_no' element.

CustomerName

FD_customers.xml: /customers/data/customer/name
FD_customers.xml: /customers/data/customer/name2

Uses the value from 'name' if available, otherwise falls back to 'name2'.

Email

FD_customers.xml: /customers/data/customer/e-mail

Direct mapping from the XML 'e-mail' element. Trimmed before saving to database.

Phone

FD_customers.xml: /customers/data/customer/telephone

Direct mapping from the XML 'telephone' element.

VatCode

FD_customers.xml: /customers/data/customer/vat_registration_no

Direct mapping from the XML 'vat_registration_no' element. Set to NULL if the administration is configured for USA.

LanguageCode

FD_customers.xml: /customers/data/customer/language_code

Direct mapping from the XML 'language_code' element. Mapped to an internal App4Sales language code via `MappedLanguages` configuration. If no mapping or empty mapped language, the original code is kept.

Discount

FD_customers.xml: /customers/data/customer/invoice_discount_perc

Parsed from the XML 'invoice_discount_perc' element (string to decimal). Uses InvariantCulture for parsing.

Currency

FD_customers.xml: /customers/data/customer/currency_code

Direct mapping from the XML 'currency_code' element.

VatLiable

FD_customers.xml: /customers/data/customer/country
Connector Setting: VatLiableCountryCode

Set to True if the 'country' element from XML matches the 'VatLiableCountryCode' specified in the connector settings (case-insensitive). Set to False if the administration is configured for USA.

UsesPriceField

Derived (from CustomerCode, CurrencyCode, PriceGroup, PriceLists)

Priority-based assignment of a PriceList ID:
1. Attempts to find a PriceList with Code = "{CustomerCode}-{CurrencyCode}".
2. If not found, and 'price_group' is not empty, attempts to find a PriceList with Code = "{PriceGroup}-{CurrencyCode}".
3. If neither found, attempts to find a PriceList with Code = "D" (DefaultPriceType).
4. If price deduplication is enabled, the PriceList ID might be migrated to a deduplicated version. If the original PriceList ID no longer exists after migration, it defaults to PriceList ID 1.

ActionPriceList

Connector Setting: DefaultActionPriceListCode
Derived (from ActionPriceList)

If the 'DefaultActionPriceListCode' connector setting is specified and no action price list is set, it defaults to the PriceList ID associated with this code. If price deduplication is enabled, the PriceList ID might be migrated to a deduplicated version. If the original ActionPriceList ID no longer exists after migration, it defaults to NULL.

PaymentConditionCode

FD_customers.xml: /customers/data/customer/payment_terms_text

Direct mapping from 'payment_terms_text'. If empty, it's set to NULL to prevent foreign key issues in the database.

CustomerGuid

Derived

First attempts to reuse GUIDs of previously inactive customers (if `Updater` mode). Then tries to retrieve from Portal API using CustomerCode and CustomerName. If still not found, a new GUID is generated.

Created

System Date/Time

If not explicitly set in the source, defaults to the current system date/time. Truncated to seconds precision.

Sysmodified

System Date/Time

Truncated to seconds precision.

PasswordWebshop

NULL

Always set to NULL when in Updater mode.

InternalCode

Existing Customer Data

If not in Updater mode and the incoming customer's InternalCode is empty, it inherits the InternalCode from the existing customer record in the database.

ExtraData

Existing Customer Data

If not in Updater mode and the incoming customer's ExtraData is empty, it inherits the ExtraData from the existing customer record in the database.

Addresses

App4Sales Field

Source Field (API/Excel/DB)

Logic/Notes

AddressType

FD_customers.xml: /customers/data/customer/ship_to_code

If 'ship_to_code' is empty or whitespace, AddressType is "Visit". Otherwise, it's "Delivery".
Guaranteed to have at least one "Visit" and one "Delivery" address type by creating dummy entries if necessary.

AddressLine1

FD_customers.xml: /customers/data/customer/address

Direct mapping from the XML 'address' element. Parsed into Street, HouseNumber, and Addition components.

AddressLine2

FD_customers.xml: /customers/data/customer/address2

Direct mapping from the XML 'address2' element.

City

FD_customers.xml: /customers/data/customer/city

Direct mapping from the XML 'city' element.

Country

FD_customers.xml: /customers/data/customer/country

Direct mapping from the XML 'country' element. If ISO2 is empty, it is derived from this field. If this field is empty, it defaults to ISO2.

PostCode

FD_customers.xml: /customers/data/customer/post_code

Direct mapping from the XML 'post_code' element.

Email

FD_customers.xml: /customers/data/customer/e-mail

Direct mapping from the XML 'e-mail' element. Unicode unit separators are removed. If an address is marked as main and its email is empty, it attempts to inherit the email from the customer or other contact persons.

Phone

FD_customers.xml: /customers/data/customer/telephone

Direct mapping from the XML 'telephone' element.

CustomerGuid

Derived (from associated Customer)

Inherits the CustomerGuid from the parent customer record.

Iso2

Derived (from Country, MappedCountryCodes)

If a mapped country exists for the given `Iso2` (or inferred from `Country`), the mapped country code is used. Otherwise, it is trimmed. If empty, it's derived from the `Country` field.

IsMainAddress

Derived

At least one "Visit" and one "Delivery" address will be marked as main if they exist.

Contacts

App4Sales Field

Source Field (API/Excel/DB)

Logic/Notes

FullName

FD_customers.xml: /customers/data/customer/contact

Direct mapping from the XML 'contact' element. Defaults to "--" if empty. If FirstName, LastName, MiddleName are empty but FullName is present, FullName is parsed to populate them. If FullName is empty, it's constructed from FirstName, MiddleName, and LastName.

Email

FD_customers.xml: /customers/data/customer/e-mail

Direct mapping from the XML 'e-mail' element. Trimmed before saving to database.

Phonenumber

FD_customers.xml: /customers/data/customer/telephone

Direct mapping from the XML 'telephone' element.

Language_iso2

FD_customers.xml: /customers/data/customer/language_code

Direct mapping from the XML 'language_code' element.

UserName

FD_customers.xml: /customers/data/customer/login_id

Direct mapping from the XML 'login_id' element.

CustomerGuid

Derived (from associated Customer)

Inherits the CustomerGuid from the parent customer record.

ContactId

Derived

If in Updater mode and ContactId is empty, a unique ID is generated using the contact's hash code.

IsMainContactPerson

Derived

If `customer.MainContactPerson` is set, that contact is marked as main. Otherwise, the first contact in `customer.ContactPersons` is marked as main.

PasswordWebshop

NULL

Always set to NULL when in Updater mode.

Extra Data & Free Fields

App4Sales Field

Source Field (API/Excel/DB)

Logic/Notes

Various Customer Fields

CsvCustomer properties (from FTP/CSV extraCustomerData)

Properties of the `Customer` object can be overwritten by corresponding properties in `CsvCustomer` (from `extraCustomerData`) if they share the same name.

FreeFieldList (parsed into FreeFields)

CsvCustomer: UnknownElements (keys starting with "FreeField_")

XML elements from `extraCustomerData` with keys starting with "FreeField_" (case-insensitive) are extracted. The part after "FreeField_" becomes the `Caption`, and the element's value becomes the `Content` of a `CustomerFreeField` object. These are then serialized into the `FreeFields` XML column.

ItemFilter

CsvCustomer: UnknownElements (keys starting with "ItemFilter_")

If `SyncSettings.CustomerItemFilter` is enabled, XML elements from `extraCustomerData` with keys starting with "ItemFilter_" (case-insensitive) are processed. The value of these elements (expected to be '~' separated) is used to construct item filters based on the `ItemClassMap`.

DynamicFreeFields (Customer)

FD_customers.xml: /customers/data/customer/[any dynamic field]

If `customer.DynamicFreeFields` contains XML, it's deserialized into `DynamicFreeFields`, which are then converted into a standardized extra fields format using `customerExtraFields` and re-serialized.

DynamicFreeFields (ContactPerson)

FD_customers.xml: /customers/data/customer/[any dynamic contact field]

Similar to customer dynamic free fields, but uses `contactPersonExtraFields` for conversion.

Discounts & Dashboards

App4Sales Field

Source Field (API/Excel/DB)

Logic/Notes

DiscountsPerItemClassValue

EzCustomer (implied, as part of the customer object coming into the handler)

Discounts with a value greater than 0 are stored in the database via the `OPTA4SUpdateItemClassValueDiscountsBatch` stored procedure. `CustomerGuid` is assigned to each discount.

CustomerDashboard

FD_customers.xml: /customers/data/customer/[dashboard_data]

If `customer.CustomerDashboard` (expected to be a Base64 string) is not empty or whitespace, it's decoded and stored as a `Dashboard` object via `_customerDataManager.SaveDashboards()`. The `CustomerDashboard` field on the customer object is then cleared to prevent excessive memory usage.

Customer Notes

Customer.CustomerNote (from the incoming customer object)

If `customer.CustomerNote` is not empty, all existing notes for that customer from 'BackOffice' are deleted from the `CustomerNotes` table, and a new note with subject "Backoffice note" and the content of `CustomerNote` is inserted.

Settings & Scripts

The following settings and script hooks influence the Customer Update process:

  • VatLiableCountryCode: (Connector Setting) Used to determine if a customer is VAT liable based on their country.

  • EnablePriceDeduplication: (General Sync Setting) When enabled, PriceList IDs on customers are migrated to deduplicated versions.

  • DefaultActionPriceListCode: (General Connector Base Setting) Provides a default action price list for customers if none is specified.

  • CustomerItemFilter: (General Sync Setting) Enables the processing of fixed item filters from `extraCustomerData`.

  • BeforeUpdateCustomers: (Script Hook) A script with this name is executed before the batch processing of customers begins. It receives the list of `Customer` objects.

  • UpdateCustomers: (Script Hook) A script with this name is executed twice: once after each batch of customers has been processed (receiving the `Customer` objects for that batch), and once after all customers and their related entities have been updated (receiving all `Customer` objects, with a boolean parameter set to `true` for the final execution).

Known Limitations

The connector processes customer data from a single XML file (`FD_customers.xml`).

Did this answer your question?