Profit Connector - Create Customer
Overview
This document details the process by which new customer records or updates to existing customer records are synchronized from App4Sales to Profit via the Profit Connector. This function handles the incoming customer payload, performs validation, maps data to Profit's organizational, address, and contact person structures, and manages responses and error handling from the ERP.
Trigger & Permissions
The customer creation/update flow is triggered in App4Sales, typically when a user submits a new customer record or modifies an existing one. To execute this function, the connector must have the Core.Constants.ConnectorInfoInternalIds.EditCustomer permission enabled.
Data Source Configuration
The connector pulls customer data directly from the App4Sales internal database objects (Customer, Address, ContactPerson) and sends it to the Profit ERP system using update connectors. It also retrieves reference data (countries, book accounts) from Profit.
App4Sales Customer Object: Contains the primary customer data, contact persons, and addresses.
App4Sales Sales Rep Data: Used to identify the sales representative associated with the customer, which can influence default settings like price lists and customer/user managers in Profit.
Profit Get Connectors:
Routes.Get.Country: Used to retrieve country-specific information based on ISO-2 code.Routes.Get.Account: Used to retrieve book account details, typically filtered by "description" to find "debiteuren".Routes.Get.InsertedPerson: Used to check for existing contact persons by App4Sales Person GUID.Routes.Get.CustomerCode: Used to retrieve the Profit customer code (debtor number) using the App4Sales Customer GUID.Routes.Get.Contacts: Used to retrieve contact persons for a given customer code.Routes.Get.CustomerAddresses: Used to retrieve customer addresses from Profit.
Profit Update Connectors:
Routes.Update.Organisation: The primary update connector used to create or update the main customer (organization) record in Profit.Routes.Update.Person: Used to create or update individual person records (contact persons).Routes.Update.Contact: Used to link or update contact person information within an organization.
Payload Mapping
The App4Sales customer data is transformed into an XML structure for the Profit update connectors. The primary structure is AfasNewCustomer, which encapsulates various Profit-specific fields and sub-objects for the organization, addresses, and contact persons.
Customer (Debtor) Fields (
)
KnSalesRelationOrg -> Element -> Fields
App4Sales Field | Source Field (API/Excel/DB) | Logic/Notes |
Action | - |
|
IsDebtor | - | Hardcoded to "1". |
VatCode |
| Directly mapped. |
PaymentCondition |
| If |
ValutaCode | - | Defaulted to "EUR". Can be overridden if |
VatLiable |
| Derived from
|
PriceList |
|
|
AccountNumber |
| Mapped from the retrieved Profit book account ID. |
SaveMethod | - | Hardcoded to "E". |
IsConsumer |
| Set to |
Discount |
| Directly mapped (defaults to 0 if null). |
CustomerManager |
| Mapped from the sales representative's internal ID ( |
UserManager |
| Mapped from the sales representative's internal ID ( |
Language |
| Mapped if |
Dynamic Fields |
| Any other dynamic fields present in |
Organization Fields (
)
KnSalesRelationOrg -> Element -> Objects -> KnOrganisation -> Element -> Fields
App4Sales Field | Source Field (API/Excel/DB) | Logic/Notes |
AfasRowAction | - |
|
PadAdr | - | Hardcoded to "0". |
CreateNumber | - | Hardcoded to "1". |
OrganisationType | - | "6" for new customers (always add new), "9" for updates (use existing entity). |
TypeCrm | - | Hardcoded to "0". |
CustomerName |
| Directly mapped. |
EmailWork |
| Prioritizes |
Fax |
| Directly mapped. |
Telephone |
| Directly mapped. |
ChamberOfCommerce |
| Directly mapped. |
Statutair |
| Directly mapped to customer name. |
Description |
| Mapped from the App4Sales Customer GUID. |
Address Fields (Visit Address:
; Delivery Address:
)
KnSalesRelationOrg -> Element -> Objects -> KnOrganisation -> Element -> Objects -> KnBasicAddressAdr -> Element -> Fields -> AfasNewAddress
KnSalesRelationOrg -> Element -> Objects -> KnOrganisation -> Element -> Objects -> KnBasicAddressPad -> Element -> Fields -> AfasNewAddress
App4Sales Field | Source Field (API/Excel/DB) | Logic/Notes |
AfasRowAction | - |
|
AddressType | - | Hardcoded to "0". |
Street |
| The street and house number are parsed from |
HouseNumber |
| The house number is parsed from |
PostalCode |
| Directly mapped. |
IsoCode |
| Mapped from the retrieved Profit country code. |
City |
| Directly mapped. |
BeginDate | Current Date | Set to the current date in "YYYY-MM-DD" format. |
ResZip |
| "0" if postal code is empty or |
AdAd (Address Addition) |
| Only serialized if not empty. |
Special Logic: If delivery address is empty, it defaults to the visit address (controlled by | Special Logic: If delivery address is empty, it defaults to the visit address (controlled by | Special Logic: If delivery address is empty, it defaults to the visit address (controlled by |
Main Contact Person Fields (
)
KnSalesRelationOrg -> Element -> Objects -> KnOrganisation -> Element -> Objects -> KnContact -> Element -> Objects -> KnPerson -> Element -> Fields
App4Sales Field | Source Field (API/Excel/DB) | Logic/Notes |
AfasRowAction | - |
|
AddToPortal | - | Hardcoded to "0". |
AutoNum | - | Boolean value, true for new customers, false for updates. |
MatchPer | - | "0" (AddAlwaysANewPerson) for new customers, "1" (SearchingOnPersonNumber) for updates. |
BcId | - | Hardcoded to "1". |
CallName |
| Directly mapped. |
Corr | - | Hardcoded to "0". |
FirstName |
| Directly mapped. |
Initials |
| Directly mapped. |
LastName |
| Directly mapped. |
SpNm | - | Hardcoded to "0". |
ViGe | - | Hardcoded to "O". |
TtId | - | Hardcoded to "ONB". |
SearchName |
| First 10 characters of |
PersonId |
| Mapped from the App4Sales Contact Person GUID. |
BcCo (Profit Person Code) |
| For updates, this is mapped from the App4Sales |
Validation & Defaults
Required Connectors: Before processing, the system verifies the existence of necessary Get and Update connectors in Profit (e.g., Country, Account, Organisation, Person, Contact). If any are missing, the operation fails with a
MissingConnectorException.Payment Condition: If
customer.PaymentConditionCodeis not provided, the sales representative's default payment condition is used. If neither is available and no sales representative is linked, the process will halt and throw an exception.VAT Liable Status: Defaults to "1" if
customer.VatLiableis true, and "0" if false (unless specific settings for EU countries or a custom "not liable" code are configured).Price List: Defaults are applied based on sales representative settings, customer price field, or fallbacks to a null price list.
Addresses: If a delivery address is not explicitly provided, the visit address is used as the delivery address.
Customer Code: If
customer.CustomerCodeis empty for an insert operation, Profit is expected to generate a new customer code. The system then retrieves this generated code from Profit using the App4SalesCustomerGuidand updates the internal App4Sales customer record.Contact Person Duplication: When inserting a new contact person, the connector defaults to "Add Always a New Person" to avoid unintended merging with existing Profit records. For updates, it searches on the "Person Number".
Response & Error Handling
Profit Update Response: The
Updatemethod returns aProfitUpdateResponseobject. If itsErrorMessageproperty starts withCore.Constants.Error.ERROR, the operation is considered failed, and the error message is returned.Organization Code: Upon successful creation or update of the organization in Profit, the
OrganisationResult.OrganisationNumber(Profit's internal organization code) is stored incustomer.ExtraDataasOrganizationCode.Customer Code Retrieval: After the initial organization update, the system queries Profit for the newly created customer's
CustomerCode(debtor number) using the App4SalesCustomerGuid(stored as an "Opmerking" in Profit). If no customer code is found, an error is returned.Context Updates: The retrieved Profit
CustomerCodeandContactIdare used to update the App4Sales internal contexts (CustomersContextandContactPersonsContext) to maintain synchronization. Address IDs are also updated internally.Exception Handling: A general
try-catchblock surrounds the main customer creation logic. Any exceptions are logged and result in a generic error message returned to the user, indicating that the customer could not be added or updated.
Domain Specifics / Extension Section
Dynamic Fields: The connector supports dynamic fields by checking
customer.UnknownElementsfor additional data to send to Profit.Client-Specific Logic: The
SetCustomerDynamicFieldsmethod uses aClientFactory, allowing for client-specific implementations to handle dynamic fields, indicating that certain clients may have unique requirements for customer data.Customer GUID as Description: The App4Sales
CustomerGuidis sent as the "Description" for the organization in Profit. This is crucial for retrieving the ProfitCustomerCodelater using the GUID.
Related Settings & Prerequisites
The following connector settings significantly influence the customer creation process:
Edit Customer (Permission): Must be enabled for the connector to allow customer creation/updates.
Send manager to Profit as manager: If enabled, the sales representative's internal ID is sent as the customer manager in Profit.
Send manager to Profit as user: If enabled, the sales representative's internal ID is sent as the user manager in Profit.
Send Language Code For New Customer: Determines if the customer's language code from App4Sales is sent to Profit.
Use Sales Rep Default Price List For Create Customer: If enabled, and the sales rep has a default price list configured, it will be used for the new customer.
Price List Based On Currency Code: If enabled, the currency code will be appended to the price list code when sending to Profit.
Do Not Search City At Postal Code: If enabled, Profit will not attempt to auto-fill the city based on the postal code for addresses.
Vat Liable Code: Custom VAT code to use when a customer is VAT liable.
Vat Liable Code For EU Countries: Custom VAT code for EU countries when a customer is not VAT liable.
Not Vat Liable Code: Custom VAT code to use when a customer is not VAT liable.
Is Consumer Value: The specific string value in Profit that indicates a customer is a consumer.