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 | Uses the value from 'name' if available, otherwise falls back to 'name2'. |
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 | 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: |
ActionPriceList | Connector Setting: DefaultActionPriceListCode | 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". |
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. |
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. |
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`).