Skip to main content

Afas - Create customer

AFAS Connector - Create/Update Customer This document describes the process by which customer information, originating from the App4Sales...

Updated over a week ago

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 into NewCustomers object containing XmlCustomer objects.

  • AFAS GetConnectors Used:

    • GetCountry: Used to fetch AFAS country details based on the incoming countryCode.

    • GetAccount: Used to fetch booking account details (filtered by "debiteuren").

    • GetCustomerCode: Used to retrieve the AFAS customer code after creation, using the App4Sales CustomerGuid as 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

CustomerCode

debCode

Used to determine if it's an insert (empty) or update (non-empty) operation. After successful insert, updated with the AFAS generated customer code.

CustomerName

customerName

Mapped directly to AFAS Organisation Name (CustomerName) and Statutair (Statutair).

CustomerGuid

customerGuid

Used as a unique identifier for internal tracking and as a reference in AFAS (mapped to Description field of the organisation).

Email

contactEmail

Mapped to AFAS Organisation Work Email (EmailWork).

CustomerEmail

customerEmail

Phone

contactPhone

Mapped to AFAS Organisation Telephone (Telephone).

CustomerPhone

customerPhone

Fax

contactFax

Mapped to AFAS Organisation Fax (Fax).

ChamberOfCommerceCode

chamberOfCommerceCode

Mapped to AFAS Organisation Chamber of Commerce (ChamberOfCommerce).

LanguageCode

languageCode

Mapped to AFAS Sales Relation Language Code (LanguageCode).

CountryCode

countryCode

Used to retrieve AFAS country details (AfasCountry.CountryCode) which are then used for address ISO codes.

Discount

discount

Parsed as a decimal value and mapped to AFAS Sales Relation Discount (kortingspercentage).

UsesPrice

usesPrice

Used to determine the Price List (PriceList) in AFAS based on internal price list IDs or SalesRep settings.

PaymentCondition

paymentCondition

Mapped to AFAS Sales Relation Payment Condition (PaymentCondition). If empty, defaults to user.DefaultPaymentConditionForNewCustomer.

IsVatLiable

isVATLiable

Used to determine VatLiable status. Mapped to AFAS Sales Relation VAT Liable (VatLiable) using settings.VatLiableCode or settings.NotVatLiableCode.

VatCode

vatCode

Mapped to AFAS Sales Relation VAT Code (VatCode).

Mobile

mobilePhone

Website

website

(Derived)

AFASRowAction

Set to insert for new customers, update for existing.

(Derived)

IsDebtor

Hardcoded to "1".

(Derived)

SaveMethod

Hardcoded to "E".

(Derived)

ValutaCode

Hardcoded to "EUR".

(Derived)

PadAdr

Hardcoded to "0" for both Organisation and Contact Person.

(Derived)

CreateNumber

Hardcoded to "1" for Organisation.

(Derived)

OrganisationType

Hardcoded to "3" for Organisation.

(Derived)

TypeCrm

Hardcoded to "0" for Organisation.

Visit and Delivery Addresses (XmlCustomer to AFAS KnAddress)

App4Sales Field (XmlCustomer)

Source Field (API/Excel/DB)

Logic/Notes

VisitAddress1

visitAddress1

Parsed to extract street and house number, mapped to AFAS Visit Address Street (Strt) and House Number (HsNb).

VisitPostCode

visitPostCode

Mapped to AFAS Visit Address Postal Code (PsCd). ResZip set to "1" if provided, "0" otherwise.

VisitCity

visitCity

Mapped to AFAS Visit Address City (Cty).

VisitState

visitState

DeliveryAddress1

deliveryAddress1

Parsed to extract street and house number, mapped to AFAS Delivery Address Street (Strt) and House Number (HsNb).

DeliveryPostCode

deliveryPostCode

Mapped to AFAS Delivery Address Postal Code (PsCd). ResZip set to "1" if provided, "0" otherwise.

DeliveryCity

deliveryCity

Mapped to AFAS Delivery Address City (Cty).

DeliveryState

deliveryState

CountryCode

countryCode

Used to determine IsoCode for both Delivery and Visit addresses from the AfasCountry object.

(Derived)

AddressType

Hardcoded to "0" for both Delivery and Visit addresses.

(Derived)

BeginDate

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

ContactFullName

contactFullName

Mapped to AFAS Person Call Name (CallName) and Search Name (SearchName, first 10 characters). Parsed to extract First Name (FirstName), Initials (Initials), and Last Name (LastName).

(Derived)

AddToPortal

Hardcoded to "0".

(Derived)

AutoNum

Set to true if `insert` is true, otherwise `false`.

(Derived)

MatchPer

Hardcoded to "3".

(Derived)

BcId

Hardcoded to "1".

(Derived)

Corr

Hardcoded to "0".

(Derived)

SpNm

Hardcoded to "0".

(Derived)

ViGe

Hardcoded to "O".

(Derived)

TtId

Hardcoded to "ONB".

contactPersonId

Internal DB

If it's an update, mapped to AFAS Person BC Code (BcCo). Otherwise, null.

Validation & Defaults

  • Required Fields: Implicitly, fields such as CustomerName are 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, TtId are hardcoded to specific values as shown in the mapping tables.

    • PaymentCondition defaults to the SalesRep's default if not provided in the incoming payload.

    • VatLiable uses connector settings (VatLiableCode, NotVatLiableCode) or defaults to "1" for liable and "0" for not liable.

    • BeginDate for 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 App4Sales CustomerGuid in 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 UpdateDatafromUpdateConnector method 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 in ConnectorBaseSettings).

  • AFAS environment and credentials (username, password, environment) configured in the Administration settings.

Known Limitations

  • The // TODO:update opmerking bij Afas comment in OptA4SNewCustomers suggests that updating the 'Opmerking' field in AFAS for existing customers is not yet fully implemented.

  • Only the first 10 characters of ContactFullName are used for SearchName in the contact person.

  • Date formats for BeginDate are 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.

Did this answer your question?