AFAS Connector - Create/Update Customer
This document describes the process by which customer information, originating from the App4Sales platform (e.g., mobile app), is created or updated within the AFAS ERP system via the AFAS Connector. The process handles incoming XML payloads, validates data, performs transformations, and communicates with the AFAS Profit services. This functionality supports both the creation of new customers and the modification of existing customer records.
Trigger & Permissions
The customer creation/update process is triggered by an InternalRequest within the App4Sales platform, typically when a new customer is submitted from the mobile app or an existing customer's details are updated. This method is enabled if the connector has CreateCustomer or EditCustomer flags set in its configuration.
Data Source Configuration
Customer data is received as an XML payload within the InternalRequest. This XML adheres to the NewCustomers schema, containing one or more XmlCustomer entities. The connector communicates with AFAS Profit services using SOAP endpoints for GetConnectors (e.g., to retrieve country codes, book accounts, or existing customer IDs) and UpdateConnectors (to send the customer data for creation or update).
Incoming Payload: XML document in the
InternalRequest.inputStream, deserialized intoNewCustomersobject containingXmlCustomerobjects.AFAS GetConnectors Used:
GetCountry: Used to fetch AFAS country details based on the incomingcountryCode.GetAccount: Used to fetch booking account details (filtered by "debiteuren").GetCustomerCode: Used to retrieve the AFAS customer code after creation, using the App4SalesCustomerGuidas a reference in the "Opmerking" (remark) field.GetContacts: Used to retrieve existing contacts for a given customer code.
AFAS UpdateConnector Used:
UpdateOrganisation: Main update connector used to create or update customer (organisation) data in AFAS.
Internal Data Sources:
AdministrationSession.CurrentSession.PortalServerProvider: Used for retrieving existing contact person IDs from the App4Sales database via SQL query.CustomersContext.Instance: Used to update the internal App4Sales customer code after successful creation in AFAS.PriceListsContext.Instance: Used to resolve price list codes based on IDs or default settings.KeySettingsContext.Instance: Used to retrieve connector settings dynamically.
Payload Mapping
Core Customer Fields (XmlCustomer to AFAS FbSalesRelation and FbOrganisation)
App4Sales Field (XmlCustomer) | Source Field (API/Excel/DB) | Logic/Notes |
|
| Used to determine if it's an insert (empty) or update (non-empty) operation. After successful insert, updated with the AFAS generated customer code. |
|
| Mapped directly to AFAS Organisation Name ( |
|
| Used as a unique identifier for internal tracking and as a reference in AFAS (mapped to |
|
| Mapped to AFAS Organisation Work Email ( |
|
| |
|
| Mapped to AFAS Organisation Telephone ( |
|
| |
|
| Mapped to AFAS Organisation Fax ( |
|
| Mapped to AFAS Organisation Chamber of Commerce ( |
|
| Mapped to AFAS Sales Relation Language Code ( |
|
| Used to retrieve AFAS country details ( |
|
| Parsed as a decimal value and mapped to AFAS Sales Relation Discount ( |
|
| Used to determine the Price List ( |
|
| Mapped to AFAS Sales Relation Payment Condition ( |
|
| Used to determine |
|
| Mapped to AFAS Sales Relation VAT Code ( |
|
| |
|
| |
(Derived) |
| Set to |
(Derived) |
| Hardcoded to "1". |
(Derived) |
| Hardcoded to "E". |
(Derived) |
| Hardcoded to "EUR". |
(Derived) |
| Hardcoded to "0" for both Organisation and Contact Person. |
(Derived) |
| Hardcoded to "1" for Organisation. |
(Derived) |
| Hardcoded to "3" for Organisation. |
(Derived) |
| Hardcoded to "0" for Organisation. |
Visit and Delivery Addresses (XmlCustomer to AFAS KnAddress)
App4Sales Field (XmlCustomer) | Source Field (API/Excel/DB) | Logic/Notes |
|
| Parsed to extract street and house number, mapped to AFAS Visit Address Street ( |
|
| Mapped to AFAS Visit Address Postal Code ( |
|
| Mapped to AFAS Visit Address City ( |
|
| |
|
| Parsed to extract street and house number, mapped to AFAS Delivery Address Street ( |
|
| Mapped to AFAS Delivery Address Postal Code ( |
|
| Mapped to AFAS Delivery Address City ( |
|
| |
|
| Used to determine |
(Derived) |
| Hardcoded to "0" for both Delivery and Visit addresses. |
(Derived) |
| Set to current date (YYYY-MM-DD) for both Delivery and Visit addresses. |
(Conditional) | Delivery Address fallback | If Delivery Address is empty, it is populated with Visit Address details. |
Contact Person (XmlCustomer to AFAS KnContact and KnPerson)
App4Sales Field (XmlCustomer) | Source Field (API/Excel/DB) | Logic/Notes |
|
| Mapped to AFAS Person Call Name ( |
(Derived) |
| Hardcoded to "0". |
(Derived) |
| Set to |
(Derived) |
| Hardcoded to "3". |
(Derived) |
| Hardcoded to "1". |
(Derived) |
| Hardcoded to "0". |
(Derived) |
| Hardcoded to "0". |
(Derived) |
| Hardcoded to "O". |
(Derived) |
| Hardcoded to "ONB". |
| Internal DB | If it's an update, mapped to AFAS Person BC Code ( |
Validation & Defaults
Required Fields: Implicitly, fields such as
CustomerNameare critical for AFAS. Missing or invalid values for customer name, address components, or payment conditions may result in errors from the AFAS API.Default Values:
IsDebtor,SaveMethod,ValutaCode,PadAdr,CreateNumber,OrganisationType,TypeCrm,AddressType,AddToPortal,MatchPer,BcId,Corr,SpNm,ViGe,TtIdare hardcoded to specific values as shown in the mapping tables.PaymentConditiondefaults to the SalesRep's default if not provided in the incoming payload.VatLiableuses connector settings (VatLiableCode,NotVatLiableCode) or defaults to "1" for liable and "0" for not liable.BeginDatefor addresses defaults to the current date.
Transformations:
CustomerCode.IsEquals(string.Empty): Determines if it's an insert or update.customer.UsesPrice.TryParseStringToInt(): Converts string to integer for price list ID.customer.Discount?.TryParseStringToDecimal(): Parses discount string to decimal.GetFirstName(),GetInitials(),GetLastName(): Extension methods used to parse full name into components.SetStreetAndHouseNumber(): Parses address line into street and house number.CheckAddress(): If delivery address is empty, it reuses visit address details.
Response & Error Handling
The connector expects a response from the AFAS UpdateConnector.
Success: If the update is successful, the method attempts to retrieve the newly assigned AFAS customer code using
GetCustomerCode, filtering by the App4SalesCustomerGuidin the "Opmerking" field. The internal App4Sales customer code is then updated.Error Detection: The string "ERROR: " is checked in the message returned by AFAS.
Specific Error Messages: The
UpdateDatafromUpdateConnectormethod in the base class includes specific error handling for common AFAS validation messages (e.g., "visit adres not gevuld", "onvolledig adres", "betalingsvoorwaarde", "fieldid=woonplaats", "onvoldoende voorraad", "persoon" related errors for contact names).Logging: Exceptions are logged using
Log.Error().Rollback/Retry: The code does not explicitly show rollback mechanisms but errors are returned to the caller.
Related Settings & Prerequisites
UseSalesRepDefaultPriceListForCreateCustomer: If enabled, uses the sales representative's default price list for new customers.IsConsumerValue: Configurable value to identify consumers.VatLiableCode: Custom VAT liable code to send to AFAS.NotVatLiableCode: Custom VAT not liable code to send to AFAS.DefaultPaymentConditionForNewCustomer: Default payment condition used if not specified in the incoming data.DecimalPrecisionPrices: Used for rounding order line prices before sending to AFAS (configured inConnectorBaseSettings).AFAS environment and credentials (username, password, environment) configured in the Administration settings.
Known Limitations
The
// TODO:update opmerking bij Afascomment inOptA4SNewCustomerssuggests that updating the 'Opmerking' field in AFAS for existing customers is not yet fully implemented.Only the first 10 characters of
ContactFullNameare used forSearchNamein the contact person.Date formats for
BeginDateare hardcoded to "yyyy-MM-dd".Some specific error messages (e.g., "persoon" related) indicate string matching for error handling, which might be brittle.
The `customerEmail`, `mobilePhone`, and `website` fields from `XmlCustomer` are currently not explicitly mapped to AFAS fields in the `ConvertToAfasNewCustomer` method.