Visma Payroll-integrasjon¶
Visma Payroll (Lønn) er Visma sin SaaS-lønnsmotor i Norden. ePortal har én aktiv adapter mot Visma Payroll: VismaPayrollImport, som henter ansatt-master-data og skriver dem til wv_User + wv_user_Employment.
Type: REST-import (pull), OAuth2 Client Credentials Modul i ePortal: Konfigureres i Konti Connect, oppdaterer Brukere/Ansatte Karakteristisk: OAuth2 via Visma Connect; cursor-paginering; rikt sett med "preserve"-regler som beskytter ePortal-felt mot å bli overskrevet ved oppdatering
Merk: TypeCode
VismaPayrollExporter registrert iwv_IntegrationType(system DB) og finnes i Konti Connect-config-malen, men det er ingen aktiv adapter-implementasjon (VismaPayrollExportAdapter) i kodebasen per [2026-06-10]. Eksport-funksjonalitet til Visma Payroll håndteres i dag ikke via Konti Connect — vurder Visma Business NXT eller PowerOffice Go for full ERP-eksport. Denne siden dekker derfor kun importen.
Hva integrasjonen synker¶
| Retning | Entitet | Frekvens |
|---|---|---|
| Visma Payroll → ePortal | Ansatte (/v1/query/employees) → wv_User |
Konfigurerbart (typisk daglig) |
| Visma Payroll → ePortal | Ansettelseshistorikk → wv_user_Employment |
Sammen med ansatt-import |
Implementasjon: VismaPayrollImportAdapter.cs
Tilgang¶
| Hvem | Hva trengs |
|---|---|
| Hos kunden | Aktiv Visma Payroll-konto; admin-tilgang til Visma Developer Portal for å registrere en applikasjon med Client Credentials Flow |
| Hos Konti | Administrator-tilgang til Konti Connect |
Forutsetninger¶
- Visma Payroll-abonnement med API-tilgang aktivert
- OAuth2-applikasjon registrert i Visma Developer Portal med scope
payrollno:employees:readog Client Credentials Flow aktivert tenant_id(Visma sitt tenant-ID) som identifiserer kundens lønnsdatabase- ePortal-ansatte er forhåndsforberedt med
userEmplNolik VismaEmployeeNumberder eksisterende brukere skal oppdateres
Konfigurasjon — feltforklaring¶
Alle felter ligger i ConfigurationJson (ikke separat Authentication-objekt for denne adapteren).
| Felt | Type | Påkrevd | Hva det betyr |
|---|---|---|---|
ClientId |
String | Ja | OAuth2 client_id fra Visma Developer Portal |
ClientSecret |
String (hemmelighet) | Ja | OAuth2 client_secret. Krypteres ved lagring |
TenantId |
String | Anbefalt | Visma tenant_id. Påkrevd for multi-tenant-scenarier (validering varsler hvis tom) |
TimeoutSeconds |
Integer | Nei (default 60) |
HTTP-timeout per request |
DefaultUserLevelId |
Integer | Nei (default 2) |
Brukernivå for nye brukere |
DefaultUserLevelIntra |
Integer | Nei (default 2) |
Intranett-nivå for nye brukere |
DefaultUserLevelExtra |
Integer | Nei (default 2) |
Ekstranett-nivå for nye brukere |
DefaultUserIntra |
Boolean | Nei (default true) |
Intranett-tilgang for nye brukere |
DefaultUserExtra |
Boolean | Nei (default false) |
Ekstranett-tilgang for nye brukere |
DefaultUserAdmin |
Boolean | Nei (default false) |
Admin-flagg for nye brukere |
PreserveUsernameOnUpdate |
Boolean | Nei (default true) |
Hvis true: beholder ePortal userName ved oppdatering (typisk Entra ID/UPN, ikke ansattnummer) |
PreserveDeactivatedUsers |
Boolean | Nei (default true) |
Hvis true: en bruker som er deaktivert i ePortal (userDeActive=1) blir IKKE reaktivert selv om Visma fortsatt har dem aktive (typisk ved feriepengeutbetaling etter sluttdato) |
PreserveEmailOnUpdate |
Boolean | Nei (default true) |
Hvis true: beholder ePortal-e-post (typisk Entra ID-e-post) — overskriver ikke med Visma-e-posten (ofte privat e-post) |
PreserveMobileWhenSourceEmpty |
Boolean | Nei (default true) |
Hvis true: blank ikke ut eksisterende mobilnummer når Visma ikke har et |
PreserveDepartmentOnUpdate |
Boolean | Nei (default true) |
Hvis true: avdeling (userDepNo) styres i ePortal, ikke Visma — ikke overskriv |
DebugLogging |
Boolean | Nei (default false) |
Logger konfigurasjon (maskert), ansattpayload og dato-felter |
FieldMappings |
Liste | Nei | Tilleggsmapping. Source: EmployeeNumber, IdentityNumber, FirstName, LastName, DateOfBirth, StartDate, EndDate, EMailAddresses[0].EMailAddress, PhoneNumbers[0].PhoneNumber. Target: alle AddEditUser-properties (UserEmployeeNo, UserFullname, UserName, UserEmail, UserMobile, UserEmployeeDate, UserDeActive, UserPercent, UserLevelID, UserProjectNo, UserDepartmentNo, m.fl.) |
Eksempel ConfigurationJson:
{
"ClientId": "<din-visma-client-id>",
"ClientSecret": "<din-visma-client-secret>",
"TenantId": "<din-visma-tenant-id>",
"DefaultUserLevelId": 2,
"DefaultUserLevelIntra": 2,
"TimeoutSeconds": 60,
"PreserveUsernameOnUpdate": true,
"PreserveDeactivatedUsers": true,
"PreserveEmailOnUpdate": true,
"PreserveMobileWhenSourceEmpty": true,
"PreserveDepartmentOnUpdate": true,
"DebugLogging": false
}
Hemmelig håndtering:
ClientSecretkrypteres ved lagring og eies av det krypterte autentiseringslageret (AuthenticationJson); lagring fjerner den fra konfigurasjons-JSON-en. Ved kjøring leser adapteren hemmeligheten fra det dekrypterte autentiseringslageret først, med fallback til eldre konfigurasjonslagring. Tjenester som leser config må brukeGetDecryptedConfigAsync.
Slik gjør du — oppsett¶
1. Registrer applikasjon i Visma Developer Portal¶
- Logg inn på Visma Developer Portal som administrator
- Opprett en ny applikasjon med Client Credentials Flow aktivert
- Aktiver scope
payrollno:employees:read - Kopier
client_idogclient_secret - Bekreft kundens
tenant_id(typisk vises i lønnsadministrasjonen)
2. Opprett integrasjon i Konti Connect¶
I ePortal:
- Innstillinger → Konti Connect → Ny integrasjon
- Type: Visma Payroll Employee Import
- Fyll inn
ClientId,ClientSecret,TenantId - Vurder preserve-flaggene (standardene er trygge for de fleste kunder)
- Sett scheduler (typisk daglig om natten)
- Klikk Test tilkobling — adapteren henter token og kaller
/v1/query/employees?limit=1 - Lagre
3. Forhåndsforberedelse av ePortal-brukere¶
For at oppdateringer skal treffe riktig bruker må ePortal userEmplNo matche Visma EmployeeNumber. Hvis du har eksisterende brukere uten ansattnummer:
- Fyll inn
userEmplNomanuelt før første kjøring, eller - La adapteren opprette nye brukere (vil ha både
userNameoguserEmplNo= Visma-ansattnummer som default)
4. Test første kjøring¶
- Bruk Kjør nå i Konti Connect
- Følg kjøringsloggen
- Sjekk:
- Antall nye opprettede brukere vs. oppdaterte
- At eksisterende brukere ikke fikk overskrevet
userName/userEmail/userDepNo - At terminerte ansatte i Visma blir
userDeActive=1i ePortal (eller beholder verdien hvis allerede deaktivert)
Mapping-detaljer¶
- Nøkkel: Visma
EmployeeNumber↔ ePortaluserEmplNo - Navn:
FirstName + " " + LastName→userFullname - Brukernavn: ved opprettelse =
EmployeeNumber. Ved oppdatering: beholdes hvisPreserveUsernameOnUpdate=true(anbefalt — brukere logger ofte inn med Entra ID/UPN) - E-post:
- Ved opprettelse: foretrekker
EMailAddressesmed typeWork, ellers første tilgjengelige, ellers fallback<EmployeeNumber>@placeholder.com - Ved oppdatering: beholdes hvis
PreserveEmailOnUpdate=trueog eksisterende e-post finnes - Mobil:
- Foretrekker
PhoneNumbersmed typeMobile, ellers første tilgjengelige - Parses til kun siffer (8–12 lange), ellers default
00000000 - Beholdes hvis
PreserveMobileWhenSourceEmpty=trueog Visma har tom verdi - Datoer:
StartDate→userEmplDate(formatertyyyyMMdd).EndDate→userEmplEndDate+userDeActive=1. ManglendeStartDatefaller tilbake til dagens dato (forhindrer SQL CAST-feil) - Stillingsprosent: alltid 100 % (Visma Payroll API leverer ikke prosent via dette endepunktet)
- Avdeling:
userDepNostyres i ePortal — beholdes alltid ved oppdatering hvisPreserveDepartmentOnUpdate=true - Terminert + ny ansatt: hvis Visma melder en ansatt som har
EndDatesatt OG vedkommende ikke finnes i ePortal, hoppes opprettelsen over (ingen vits i å opprette en terminert bruker som ny) - Ansettelseshistorikk: opprettes første gang; oppdateres bare hvis
EndDateendrer seg (sluttet eller reaktivert). Andre verdier røres ikke
Forhåndsdefinerte mappings (HasPreconfiguredMapping = true)¶
| Source | Target | Type | Regel |
|---|---|---|---|
EmployeeNumber |
UserEmployeeNo |
Direct | Påkrevd nøkkel |
FirstName + LastName |
UserFullname |
Transform | Slå sammen med mellomrom |
EmployeeNumber |
UserName |
Direct | Default; beholdes på oppdatering hvis PreserveUsernameOnUpdate=true |
EMailAddresses[0].EMailAddress |
UserEmail |
Direct | Beholdes på oppdatering hvis PreserveEmailOnUpdate=true |
PhoneNumbers[0].PhoneNumber |
UserMobile |
Transform | Bare siffer; beholdes på oppdatering med tom kilde |
StartDate |
UserEmployeeDate |
Transform | yyyyMMdd |
EndDate |
UserEmployeeEndDate |
Transform | yyyyMMdd |
EndDate.HasValue |
UserDeActive |
Transform | 1 hvis sluttdato, ellers 0; beholdes ved oppdatering hvis allerede 1 og PreserveDeactivatedUsers=true |
Egne FieldMappings overstyrer disse for samme target-felt.
Frekvens og volum¶
- Sidestørrelse: 100 (
?limit=100), cursor-basert paginering viacursor.nextToken - 3 retries med eksponentiell backoff (2s, 4s, 8s) på 401/nettverksfeil ved token-forespørsel
- Token cacheres ikke per session — hentes hver kjøring
- Typisk volum: 50–2000 ansatte per kunde
Sikkerhet¶
ClientSecretlagres kryptert (AES viaEncryptionService)- Bruk en dedikert M2M-applikasjon i Visma Developer Portal — ikke gjenbruk personlige credentials
DebugLoggingmaskerClientSecretogJwtTokeni loggen, men logger ansattpayload — skru av i normal drift (GDPR)- Preserve-flaggene gir tydelig audit-trail på hva som er styrt fra hvor (Visma vs. ePortal/Entra ID)
Vanlige problemer¶
Visma Connect authentication failed: 401¶
- Feil
ClientIdellerClientSecret - Manglende scope
payrollno:employees:read— sjekk i Developer Portal - Manglende eller feil
TenantId
Brukere blir reaktivert hver natt selv om de er deaktivert i ePortal¶
PreserveDeactivatedUsers=false. Sett til true (default) — typisk ved feriepengeutbetalinger etter sluttdato hvor Visma fortsatt har ansatten aktiv mens ePortal har deaktivert.
Brukerens e-post endres til privat e-post fra Visma¶
PreserveEmailOnUpdate=false. Sett til true (default) hvis ePortal-brukerne logger på med Entra ID.
Brukernavn endres ved oppdatering — brukere får ikke logget inn¶
PreserveUsernameOnUpdate=false. Sett til true (default) — viktig hvis brukerne har Entra ID/UPN som userName.
SaveUser returned invalid UserID=0¶
Bug i wv_User_save-SP eller validering. Sjekk loggen for FK-feil eller manglende obligatoriske felter. Ansettelseshistorikk hoppes over for berørt rad.
Terminert ansatt blir opprettet¶
Adapteren skal hoppe over hvis EndDate.HasValue && existingUser == null. Hvis det skjer: sjekk om Visma har sendt EndDate blank for en person som faktisk er sluttet.
Avdeling overskrives av Visma¶
PreserveDepartmentOnUpdate=false. Sett til true (default) — avdeling styres i ePortal.
Telefon settes til 00000000¶
Visma har ingen mobil for denne ansatte, eller nummeret er kortere enn 8/lengre enn 12 siffer. Default-verdien beskytter mot null-feil. Aktiver PreserveMobileWhenSourceEmpty=true for å beholde eksisterende ePortal-verdi.