Visma Connector - Create Customer
This document details the process by which the App4Sales platform creates or updates customer records in the Visma ERP system via the AccountView connector. This process is initiated when a new customer is created or an existing customer is updated within App4Sales. The connector synchronizes core customer information, addresses, and contact details, ensuring consistency between App4Sales and Visma AccountView.
Trigger & Permissions
The customer creation/update flow is triggered by the OptA4SNewCustomers method within the App4Sales Visma connector. This functionality is enabled when the following connector info flags are active:
ConnectorInfoInternalIds.EditCustomerConnectorInfoInternalIds.CreateCustomer
Authentication to the Visma AccountView API is managed via an access token and company ID, which are configured in the connector settings and refreshed automatically as needed.
Data Source Configuration
Customer data originates from the App4Sales platform. The connector receives customer information in an XML format via an input stream (`request.inputStream`). This XML contains fields such as customer code, GUID, relation group, and search code. The connector then processes this data for submission to the Visma AccountView REST API.
Payload Mapping
The following tables detail the mapping of App4Sales customer fields to Visma AccountView API fields. Note that the App4Sales Customer object is first constructed from an AccountViewCustomer within the MapCustomer extension method, and then its properties are used to build the final API payload.
Core Customer Fields (Business Object: AR1 - Contact)
App4Sales Field | Source Field (Visma API) | Logic/Notes |
CustomerCode | sub_nr | If empty for a new customer, a sequential number is generated starting from |
CustomerName | acct_name | Directly mapped. |
Discount | disc_pct | Value of |
LanguageCode | lng_code | Mapped using |
VatCode | vat_nr | Mapped from |
VatLiable | (Not a direct field) | Determined by |
PaymentConditionCode | disc_code | Mapped from |
ChamberOfCommerceCode | coc_code | Directly mapped from |
CustomerManager | emp_nr | Directly mapped from |
Phone | tel_bus | Directly mapped from |
MobileNumber | tel_mob | Directly mapped from |
Currency | cur_code | Directly mapped from |
CountryCode | cnt_code | Mapped from |
SearchCode | SRC_CODE | If not provided in the input stream, it defaults to the first 4 characters of |
RelationGroup | RPL_GRP | Directly mapped if present in the input stream. |
UsesPriceField | APX_LIST | Determined by |
ERP Identifier | (Visma PrimaryKey) | After successful creation, the PrimaryKey returned by Visma is stored as the |
CollectionAccountCode | acct_nr | Value from |
Address Fields (Included within AR1 - Contact)
Both a visit address ("VIS") and a delivery address ("DEL") are generated from the source data. The connector prioritizes these based on the SwapDeliveryAndVisitAddress setting.
App4Sales Field | Source Field (Visma API) | Logic/Notes |
AddressLine1 | address1 | Mapped from |
PostCode | post_code | Mapped from |
City | city | Mapped from |
Fax | FAX_BUS | Mapped from |
Contact Person Fields (Business Object: PP1 - People, then linked to AR1 - Contact)
If SendContactAsAdministrationContact or SendContactAsMainContact settings are enabled, a separate request is made to create/update a contact person in Visma AccountView before linking it to the customer. The contact person details are taken from the first contact person in the App4Sales customer object (customer.ContactPersons[0]).
App4Sales Field | Source Field (Visma API) | Logic/Notes |
ContactId | pp_code | If empty for a new contact, a sequential number is generated starting from |
FirstName | fst_name | Directly mapped. |
LastName | lst_name | Directly mapped. |
FullName | dsp_name | If |
mail_bus | Directly mapped. | |
Phonenumber | tel_bus | Directly mapped. |
MobileNumber | tel_mob | Directly mapped. |
Visma PrimaryKey (from PP1) | main_pp / admin_pp | If |
Dynamic and Free Fields
App4Sales Field | Source Field | Logic/Notes |
DynamicFreeFields | AccountViewCustomer properties | Custom fields "SearchCode" and "RelationGroup" from the |
FreeFields | AccountViewCustomer properties | Includes "PriceList" and "PriceListPercentage" from the |
Validation & Defaults
**Customer Existence:** The connector first attempts to retrieve a customer using the provided
customerguid. If no customer is found, andcustomerCodeis empty, it proceeds with creating a new customer.**Code Generation:** For new customers, if
customerCodeis empty, a unique customer code is generated starting from the value in theAccountViewCustomerCodeStartingNumbersetting (defaulting to 500000 if not set). Similarly, for new contact persons, acontactIdis generated usingAccountViewContactCodeStartingNumber(defaulting to 500000).**Search Code Default:** If
searchCodeis not provided in the input, it defaults to the first four characters of theCustomerName, converted to uppercase.**VAT Liability:** The
CheckVatLiablemethod determines if a customer is VAT liable based on theVatCode, a list of VAT liable codes (CustomerVatLiableCodessetting), and whether a customer is considered VAT liable when their VAT code is empty (VatLiableWhenVatCodeIsEmptysetting). Specific VAT codes can also be marked as non-liable using theNoVatLiableCodessetting.**Price List Default:** If the `PriceListCode` from AccountViewCustomer does not match any configured price lists, the connector attempts to use the first available price list.
**Address Handling:** If address lines, postcode, or city are missing for either the visit or delivery address, empty strings are sent to the ERP.
Response & Error Handling
**API Responses:** The connector expects JSON responses from the AccountView API. Responses are deserialized into
AccountViewContactResponseobjects.**Customer Code Update:** Upon a successful customer creation in Visma AccountView, the ERP-assigned
PrimaryKey(customer code) is retrieved from the API response and used to update thecustomerCodein the App4Sales database for the corresponding customer GUID.**Error Logging:** API errors (non-OK HTTP status codes) are logged, including details from the AccountView API's error message.
**Exceptions:** If an API request fails, an exception is thrown, detailing the error.
**Return Value:** The method returns "ERROR: Customer could not be found in the database" if the initial customer retrieval fails, or "Succes: [New Customer PrimaryKey]" upon successful creation/update.
Special Logic & Filters
**Upsert Logic:** The connector implements an upsert (update or insert) mechanism. It first tries to find an existing customer by GUID. If found, it updates; otherwise, it creates a new customer.
**XML Input Parsing:** The incoming request stream is parsed as XML to extract key customer identifiers.
**Contact Person Update/Insert:** A contact person record (`PP1` business object) is created or updated separately if configured, and then linked to the main customer record (`AR1` business object).
**Address Swapping:** The
SwapDeliveryAndVisitAddresssetting allows the connector to swap the visit and delivery addresses when sending them to AccountView.
Related Settings & Prerequisites
The functionality of the Create Customer process is influenced by the following connector settings:
AccountViewCustomerCodeStartingNumber: The starting number for auto-generating customer codes.AccountViewContactCodeStartingNumber: The starting number for auto-generating contact person IDs.SendContactAsAdministrationContact: Boolean flag to determine if the contact person should be sent as the administration contact.SendContactAsMainContact: Boolean flag to determine if the contact person should be sent as the main contact.UseUsernameAsEmployeeForNewCustomer: Boolean flag to use the App4Sales username as the employee number for new customers in AccountView.CollectionAccountCodeForNewCustomer: The collection account code to be assigned to new customers.SwapDeliveryAndVisitAddress: Boolean flag to swap delivery and visit addresses when sending to AccountView.SkipPriceLists: Boolean flag to skip retrieving price lists.CustomerVatLiableCodes: Comma-separated list of VAT codes considered liable.VatLiableWhenVatCodeIsEmpty: Boolean flag indicating if a customer is VAT liable when the VAT code is empty.NoVatLiableCodes: Comma-separated list of VAT codes that are explicitly not considered liable.PriceListsBasedOnItemFields: Boolean flag indicating if price lists are based on item fields.PriceList1Code: Code for Price List 1.PriceList2Code: Code for Price List 2.PriceList3Code: Code for Price List 3.PriceList4Code: Code for Price List 4.