Gå til innhold

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 VismaPayrollExport er registrert i wv_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:read og Client Credentials Flow aktivert
  • tenant_id (Visma sitt tenant-ID) som identifiserer kundens lønnsdatabase
  • ePortal-ansatte er forhåndsforberedt med userEmplNo lik Visma EmployeeNumber der 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: ClientSecret krypteres 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å bruke GetDecryptedConfigAsync.


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_id og client_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 userEmplNo manuelt før første kjøring, eller
  • La adapteren opprette nye brukere (vil ha både userName og userEmplNo = 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=1 i ePortal (eller beholder verdien hvis allerede deaktivert)

Mapping-detaljer

  • Nøkkel: Visma EmployeeNumber ↔ ePortal userEmplNo
  • Navn: FirstName + " " + LastNameuserFullname
  • Brukernavn: ved opprettelse = EmployeeNumber. Ved oppdatering: beholdes hvis PreserveUsernameOnUpdate=true (anbefalt — brukere logger ofte inn med Entra ID/UPN)
  • E-post:
  • Ved opprettelse: foretrekker EMailAddresses med type Work, ellers første tilgjengelige, ellers fallback <EmployeeNumber>@placeholder.com
  • Ved oppdatering: beholdes hvis PreserveEmailOnUpdate=true og eksisterende e-post finnes
  • Mobil:
  • Foretrekker PhoneNumbers med type Mobile, ellers første tilgjengelige
  • Parses til kun siffer (8–12 lange), ellers default 00000000
  • Beholdes hvis PreserveMobileWhenSourceEmpty=true og Visma har tom verdi
  • Datoer: StartDateuserEmplDate (formatert yyyyMMdd). EndDateuserEmplEndDate + userDeActive=1. Manglende StartDate faller tilbake til dagens dato (forhindrer SQL CAST-feil)
  • Stillingsprosent: alltid 100 % (Visma Payroll API leverer ikke prosent via dette endepunktet)
  • Avdeling: userDepNo styres i ePortal — beholdes alltid ved oppdatering hvis PreserveDepartmentOnUpdate=true
  • Terminert + ny ansatt: hvis Visma melder en ansatt som har EndDate satt 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 EndDate endrer 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 via cursor.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

  • ClientSecret lagres kryptert (AES via EncryptionService)
  • Bruk en dedikert M2M-applikasjon i Visma Developer Portal — ikke gjenbruk personlige credentials
  • DebugLogging masker ClientSecret og JwtToken i 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 ClientId eller ClientSecret
  • 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.


Relaterte sider