Visma Business NXT-integrasjon¶
Visma Business NXT er Visma sin skybaserte ERP-plattform. ePortal integrerer mot NXT via GraphQL API for synkronisering av timer, bilag, aktører (kunder/leverandører), bank- og hovedboksdata, samt org-enheter (avdelinger/prosjekter).
Type: GraphQL, OAuth2 (Visma Connect), per-adapter integrasjon Modul i ePortal: Konfigureres og overvåkes i Konti Connect-modulen Vs. klassisk: Visma Business klassisk er on-premise ERP via PortalConnector WinService. NXT er moderne, skyhostet, GraphQL.
Adaptere — hva som finnes i koden¶
Hver NXT-adapter har en egen IntegrationTypeCode og registreres som en separat integrasjon i Konti Connect:
| Adapter | Type-kode | Retning | Hovedoppgave |
|---|---|---|---|
| Tidsregistreringer | VismaBusinessNXT_TimeRegs |
ePortal → NXT | Eksporter timer som freeInformation3-rader |
| Bilag | VismaBusinessNXT_Vouchers |
ePortal → NXT | Opprett bilag i batcher, valgfri "bokfør"-mutasjon |
| Aktører | VismaBusinessNXT_Actors |
Toveis | Synke kunder/leverandører via associate-entiteten |
| Kontoplan | VismaBusinessNXT_Accounts |
NXT → ePortal | Hent hovedbokskontoer |
| Org-enheter | VismaBusinessNXT_OrgUnits |
Toveis | Synke avdelinger/prosjekter (orgUnit1, orgUnit2) |
| Ordrer | VismaBusinessNXT_Orders |
(per adapter) | Ordrelinjer |
| Produkter | VismaBusinessNXT_Products |
(per adapter) | Produkter/varer |
Aktør-import (retning Import) skriver direkte til ePortals aktørregister. Hver kunde/leverandør hentet fra associate upsertes rett inn i wv_Actor via en felles, testet aktør-upsert (ActorUpsertRepository.cs, kalt fra VismaBusinessNXTActorAdapter.cs), ikke lenger via et HTTP-kall til KontiConnect. Upserten matcher på kunde-/leverandørnummer, slår sammen kunde- og leverandørrolle på samme organisasjonsnummer (ingen dupliserte rader for samme juridiske enhet), renser e-post, og hopper over aktører uten navn eller med «0»/tomt referansenummer — per aktør, så én dårlig aktør stopper ikke resten. Eksport-retningen (ePortal → NXT) er uendret.
Aktør-klassifisering (IMO/type/BPP/flåte/kundestatus). Aktør-synkroniseringen skriver også klassifiseringsfelt fra NXT sin associate-entitet inn i wv_Actor, overskrevet ved hver kjøring (NXT er kilde for sannhet):
| ePortal-kolonne | NXT-felt | Betydning |
|---|---|---|
actInfo1 |
information1 (String) |
IMO-nummer |
actGroup2 |
group2 (Int) |
Kundetype-kode |
actGroup3 |
group3 (Int) |
BPP-status-kode |
actGroup7 |
group7 (Int) |
Flåte-kode |
actGroup9 |
group9 (Int) |
Kundestatus-kode (Aktiv/Ekstern/Sluttet/Solgt…) |
MO-126 (retting): Kundetype er NXT
group2(actGroup2) og Flåte er NXTgroup7(actGroup7). Tidligere pekte Kundetype pågroup1(actGroup1) og Flåte påemployeePriceGroup(actEmployeePriceGroup) — feil NXT-felt (verifisert mot NXT).actGroup1er nå en generisk gruppe, ogactEmployeePriceGrouper en reell prisgruppe (ikke en klassifisering).MO-126 Slice 2 (nytt felt): Kundestatus = NXT
group9(actGroup9, kolonnen lagt til i migrasjon20261016900083) hentes nå også. Kundestatus flyter foreløpig kun via den direkte NXT GraphQL-synken; KontiConnect Integration-API-produsenten (eget repo) eksponerer ikkegroup9ennå — klienter som synkroniseres via KontiConnect får Kundestatus først når produsenten utvides (samme åpne port som gruppe 1–8-produsenten).
0/tom verdi normaliseres til NULL (ActorUpsertRepository.cs:313-329). Feltene skrives fra både kunde- og leverandør-passet, slik at en aktør med begge roller ikke mister verdien avhengig av rekkefølgen (VismaBusinessNXTActorAdapter.cs:520-525). «IMO-nummer»/«Kundetype»/«BPP-status»/«Flåte»/«Kundestatus» er standardetikettene — visningsnavnene kan tilpasses per kunde i etikett-katalogen (Innstillinger → Abonnement – feltoppsett, feltnøklene ActorInfo1/ActorGroup2/ActorGroup3/ActorGroup7/ActorGroup9; standardetikettene rettet i migrasjon 20261016900082, Kundestatus-etiketten seedet i 20261016900083).
Alle åtte klassifiseringsgruppene (group1–group8, alle Int) synkroniseres nå inn i wv_Actor.actGroup1…actGroup8 (group2/4/5/6/7/8 i tillegg til de to over).
Skriv-tilbake av klassifiseringskoder (ePortal → NXT). Kodene skrives tilbake til NXT via associate-entiteten på to måter:
- Aktør-eksport/-synk (
associate_create/associate_update) tar med gruppekodene sist i payloaden (NXT bryr seg om feltrekkefølgen) — kun satte koder skrives, en ukjent/uendret gruppe utelates (klobrer aldri en gruppe den ikke kjenner). - Kundekortet (CRM → «ERP-klassifisering», redigerbare nedtrekk) gjør en synkron skriv-før-lagring: de åtte kodene pushes til NXT (
associate_update, filtrert påcustomerNo/supplierNo) og lagres kun iwv_Actorhvis NXT godtar dem. Her betyr «(ingen)» en eksplisitt tømming som skrives som0(NXTs «ingen verdi»; leses tilbake somNULL). Uten en NXT-integrasjon er kortets klassifiseringsblokk skrivebeskyttet (VismaBusinessNXTActorAdapter.PushClassificationUpdateAsync,NxtActorClassificationPusher.cs).
Tømming (bekreftet): å skrive
0tømmer gruppen i NXT — det setter ikke kategori 0. «(ingen)» i kortet er derfor en reell tømming som leses tilbake somNULL. Verifisert mot NXT (eier-bekreftet).
Avstemming ved full synk (MO-091 #13). Når aktør-importen kjører som full synk (EnableDeltaSync = false), avstemmes aktørregisteret mot det komplette NXT-uttrekket per rolle: aktører hvis kunde-/leverandørnummer ikke lenger finnes i NXT får ERP-koblingsfeltene fjernet — kundenummer (actCustNo + actErpCustomerNo) hhv. leverandørnummer (actSupNo + actSupplierCode), og klassifiseringsfeltene over når aktøren mister sin siste ERP-rolle (de er NXT-eide). Aktøren slettes eller deaktiveres aldri — den lever videre i CRM uten ERP-kobling. Sikkerhetsgrense: avstemmingen hoppes over (med advarsel i kjøringsloggen) hvis uttrekket dekker under 50 % av lokalt koblede aktører for rollen (ActorErpReconciliationLogic.MinimumFetchCoverageRatio — beskytter mot at en delvis/feilet henting nuller hele registeret). Delta-synk kan ikke observere fravær og kjører aldri avstemmingen. Slås av med integrasjonsinnstillingen ReconcileMissingActors = false. Kjøringsloggen viser «X aktører fikk fjernet ERP-kobling (finnes ikke lenger i NXT)» (VismaBusinessNXTActorAdapter.cs, ReconcileErpLinkageAsync).
Masterordre-søkekolonner oppdateres ved aktørsynk (MO-116). Etter en fullført aktør-import/-synk kjører adapteren en full gjenoppbygging av masterordre-listens denormaliserte søkekolonner (SearchText/SearchNumbers på wv_Subscription_MasterOrder), slik at NXT-drevne kunde-/management-navneendringer blir søkbare i masterordre-listen. Ren tilleggseffekt — påvirker ikke aktør-import, klassifisering eller avstemming over (VismaBusinessNXTActorAdapter.cs, RecomputeSearchTextForAllAsync; se Masterordre-datamodell).
Feltmapping av klassifisering og egendefinerte felt (MO-130, fase 1). Feltmapper-fanen på en NXT aktørintegrasjon (Konti Connect → integrasjon → Feltmapping) tilbyr nå:
- Klassifiseringskilder: NXT
associate-felteneinformation1oggroup1–group9. - Faste klassifiseringsmål:
ImoNo,Kundetype,BppStatus,Fleet,CustomerStatus— med forhåndsutfylte standardrader (information1→ImoNo,group2→Kundetype,group3→BppStatus,group7→Fleet,group9→CustomerStatus). Radene vises uten lagret databaserad; en rad lagres kun når en administrator overstyrer via «Legg til ekstra mapping». - Egendefinerte CRM-kundefelt som mål: hvert aktivt
wv_CRM_CustomFieldmedEntityType='Customer'tilbys som mål (nøkkelcustomField:{FieldId}).
Fase 1 endrer ikke selve klassifiserings-synken — de faste identitetene følger fortsatt de generiske actGroup/actInfo-kolonnene 1:1 (fase 2 lar lese-flatene respektere en om-mapping). Den eneste nye synk-oppførselen er skriving til egendefinerte felt: når en mapping peker et NXT-kildefelt til et egendefinert kundefelt, skrives NXT-verdien til wv_CRM_CustomFieldValue for den synkroniserte aktøren (nøkkel EntityType='Customer', EntityId = actID) og vises på kundekortet. Skrivingen er robust per aktør (én feilende skriving stopper ikke synken), typekonverterer NXT-verdien til feltets FieldType, respekterer ValidationRegex, hopper over slettede felt, og er idempotent (upsert). NXTs numeriske «ingen verdi»-sentinel 0 skrives ikke. Referanse: VismaBusinessNXTActorAdapter.cs (BuildCustomFieldValueUpserts, ApplyCustomFieldMappingsAsync).
I tillegg leveres NXT bank- og hovedboksdata til Bankavstemming og hovedboksdata til KAI Live regnskap via en egen tjeneste (VismaBusinessNXTBankDataProvider) som bruker samme NXT-integrasjon, men er ikke en IntegrationAdapter.
Referanse: api/ePortal.API/ePortal.Base/Services/Integration/VismaBusinessNXT/ og api/ePortal.API/ePortal.Base/Services/BankReconciliation/VismaBusinessNXTBankDataProvider.cs.
Tilgang¶
| Hvem | Hva trengs |
|---|---|
| Hos Visma | NXT-abonnement med tilgang til Visma Connect (OAuth2) — ClientId, ClientSecret, TenantId |
| Hos Konti | Administrator-tilgang til Konti Connect |
| Hos kunden | NXT selskapsnummer (CompanyNo); for bilag i tillegg VoucherSeriesNo |
CompanyNo resolves enten via eksplisitt erpClientCode-override, via wv_Domain.ErpClientNumber, eller fra integrasjonskonfigurasjonen (VismaBusinessNXTBankDataProvider.cs:60-79).
Slik gjør du — første oppsett¶
1. Generer NXT API-tilgang (hos Visma)¶
I Visma Connect / NXT-administrasjon: opprett en applikasjon for ePortal og noter ClientId, ClientSecret, TenantId. Velg scope som dekker de adaptere som er aktuelle (timer, bilag, hovedbok, bank, aktører, org-enheter).
2. Konfigurer i Konti Connect¶
For hver adapter du vil aktivere: opprett en separat integrasjon i Konti Connect (type = adapter-koden over) og legg inn:
ClientId,ClientSecret,TenantId— Visma Connect-credentialsCompanyNo— NXT selskapsnummer- Adapter-spesifikke nøkler (se neste seksjon)
ePortal lagrer ClientSecret kryptert. IntegrationService.GetDecryptedConfigAsync brukes ved hver kjøring — egen-kode som leser credentials direkte fra wv_Integration får kryptert verdi og feiler med 401.
3. Verifiser tilkobling¶
Tidsregistrerings-adapteren har en ConnectionTestResult-test som spør freeInformation3(first: 1) { totalCount } for å bekrefte at token og scope fungerer (VismaBusinessNXTTimeRegistrationAdapter.cs:803).
Konfigurasjon — feltforklaring¶
Felles autentiserings-felter (alle NXT-adaptere)¶
| Felt | Plassering | Type | Påkrevd | Hva det betyr |
|---|---|---|---|---|
ClientId |
Auth eller Config | String (GUID) | Ja | OAuth2 client_id fra Visma Connect Developer Portal. Adapter leser Auth.ClientId med fallback til Config.ClientId (VismaBusinessNXTHttpHelper.cs:59) |
ClientSecret |
Auth (krypteres) | String | Ja | OAuth2 client_secret. Lagres kryptert. Krever GetDecryptedConfigAsync ved lesing (VismaBusinessNXTHttpHelper.cs:50) |
TenantId |
Auth eller Config | String | Ja | Visma Connect tenant-ID (kundens NXT-tenant) |
CompanyNo |
Config | Integer | Ja | NXT-selskapsnummer. Verifiseres som heltall i hver adapter — feiler hard om verdien ikke kan parses (VismaBusinessNXTVoucherAdapter.cs:1511, VismaBusinessNXTTimeRegistrationAdapter.cs:863) |
Auth-flyt: POST https://connect.visma.com/connect/token med grant_type=client_credentials + scope business-graphql-service-api:access-group-based. Token brukes som Authorization: Bearer <token> mot https://business.visma.net/api/graphql-service. Token caches per credential-sett — nøkkelen er et ikke-reversibelt digest av token-endepunkt, scope, ClientId og ClientSecret (NxtTokenCacheIdentity.cs), og invalideres ved 401 (VismaBusinessNXTHttpHelper.cs). En konfigurasjon som oppgir riktig ClientId men feil ClientSecret treffer derfor ikke et eksisterende token: forespørselen går til Visma Connect, som avviser den. Hemmeligheten lagres aldri i nøkkelen, loggen eller feilmeldinger.
Eksempel ConfigurationJson (felles for alle NXT-adaptere)¶
{
"ClientId": "<visma-connect-client-id>",
"ClientSecret": "<visma-connect-client-secret>",
"TenantId": "<tenant-id>",
"CompanyNo": "12345",
"EnableDeltaSync": true
}
Adapter-spesifikke felter (VoucherSeriesNo, MaxRowsPerRun, BatchSize osv.) legges på toppen av dette.
Felles for de fleste adaptere¶
| Nøkkel | Standard | Hva den gjør |
|---|---|---|
EnableDeltaSync |
true |
Når aktivert henter adapteren kun rader endret siden forrige kjøring. Aktor-, konto-, ordre- og org-enhets-adapterne sjekker denne flaggen direkte (VismaBusinessNXTActorAdapter.cs:1144, VismaBusinessNXTAccountAdapter.cs:455) |
MaxRowsPerRun |
25000 (timer) |
Begrenser hvor mange rader som behandles per kjøring. Tidsregistrerings-adapteren stopper ved grensen og fortsetter fra cursor neste kjøring (VismaBusinessNXTTimeRegistrationAdapter.cs:177-201) |
Varslingsinnstillinger (alle NXT-adaptere)¶
E-postvarsling ved feilede kjøringer styres per integrasjon med tre nøkler i ConfigurationJson. De godtas på alle NXT-typene og lagres alltid med akkurat disse navnene — skriver du dem med annen bruk av store/små bokstaver, rettes navnet automatisk ved lagring, og en konfigurasjon som inneholder samme nøkkel i to skrivemåter avvises (NxtIntegrationConfigurationPolicy.cs:19-20, :192-210).
| Nøkkel | Type | Hva den gjør |
|---|---|---|
NotificationEmails |
tekst | Mottakere, komma- eller semikolonseparert (f.eks. "drift@firma.no;vakt@firma.no"). Må være en tekstverdi — andre JSON-typer avvises ved lagring (NxtIntegrationConfigurationPolicy.cs:220-228) |
AlertLevel |
tekst | Når det varsles: None (aldri), Error (kun feilede kjøringer), Warning (feilede og delvis vellykkede) eller All (alle). Andre verdier avvises ved lagring; skrivemåten rettes til disse (NxtIntegrationConfigurationPolicy.cs:220-228, IntegrationAlertService.cs:145-153) |
AlertDigestMinutes |
heltall ≥ 1 | Minste antall minutter mellom to varsler fra samme integrasjon (standard 60). Skriver du verdien som tekst i JSON-fanen (f.eks. "30"), gjøres den om til et ekte tall ved lagring; null og negative verdier avvises (NxtIntegrationConfigurationPolicy.cs:249-253, IntegrationAlertService.cs:161-169) |
Varselvurderingen kjører for alle avsluttede kjøringer som er logget — også når kjøringen stopper før adapteren kommer i gang, for eksempel når ingen adapter finnes for typen, konfigurasjonen avvises av adapterens validering, eller kjøringen kaster en feil (IntegrationService.cs:1120-1128).
Bilags-adapter (VismaBusinessNXT_Vouchers)¶
Konfigurasjonsnøkler (VismaBusinessNXTVoucherAdapter.cs:24-38):
| Nøkkel | Standard | Hva den gjør |
|---|---|---|
VoucherSeriesNo |
(påkrevd) | Bilagsserie i NXT som batcher opprettes mot |
AutomaticBatchUpdates |
false |
Når sann: kjører "bokfør" (batch_update-processing) automatisk etter opprettelse |
EnableBookkeepingControl |
true |
Validerer mot bokføringsregler før posting |
EnableProjectBlocking |
false |
For avskrivningsprosjekter: leser nåværende status på orgUnit2, setter midlertidig status=0 under eksport, gjenoppretter etterpå (VismaBusinessNXTVoucherAdapter.cs:1303-1451) |
DepreciationVoucherSeries |
600 |
Bilagsserie (VoSerie) som identifiserer avskrivningsbilag |
BatchSize |
500 |
Maks antall bilagslinjer per NXT-batch |
DebugLogging |
false |
Skrur på utvidet loggning |
Eldre bilagsintegrasjoner migreres automatisk. Integrasjoner opprettet før bilagseksporten ble skrevet om, har DepreciationVoucherType, EnableDimensionMapping og PageSize liggende i konfigurasjonen. Disse feltene finnes ikke lenger. Ved første lagring eller kjøring blir DepreciationVoucherType overført til DepreciationVoucherSeries (verdien beholdes), de to andre fjernes, og SyncDirection: "Import" rettes til "Export" — adapteren har alltid vært eksport-only. Ingen handling kreves.
Hvert bilag som eksporteres får sitt eget bilagsnummer reservert atomisk hos NXT rett før det opprettes, via _suggest: { voucherNo: true } med temporary: true mot en midlertidig, aldri-lagret enkeltlinje (samme konto på debet og kredit — ingen økonomisk effekt uansett beløp; kontoen gjenbrukes fra bilagets egne linjer, så ingen ny konfigurasjon kreves). Det reserverte tallet skrives deretter, én gang, til det ekte bilaget — ingen egen "reservasjonsbilag" opprettes eller blir liggende synlig i NXT-boken. Implementert i ReserveVoucherNoAsync (VismaBusinessNXTVoucherAdapter.cs), kalt fra CreateBatchWithVouchersAsync for hvert bilag i chunken før batchen opprettes. Hvis reservasjonen feiler for ett eneste bilag, avbrytes hele chunken (ingen batch opprettes) og alt i den prøves igjen ved neste kjøring — ingen fallback til NXTs egen auto-nummerering, som ikke garanterer ett felles nummer per flerlinjers bilag.
Dette erstatter en tidligere metode som leste voucherSeries { nextVoucherNo } direkte og skrev tallet eksplisitt — live-testet 2026-08-05 og bekreftet utrygt: NXT validerer ikke at et eksplisitt angitt bilagsnummer faktisk er ledig, så to bilag registrert omtrent samtidig (f.eks. ett fra ePortal og ett manuelt i NXT-klienten) kunne stille få samme nummer. En mellomliggende variant (reservasjon via ett synlig ekstra "reservasjonsbilag" per kjøring) ble forkastet etter Codex-review 2026-08-05: den kunne i praksis gjenbruke reservasjonens eget nummer på det første ekte bilaget, altså nøyaktig samme kollisjon fiksen skulle løse.
Valutafelt på bilagslinjer (BRQ-11)¶
MapSingleVoucherLine sender nå ett felles beløpsfelt for alle bilag denne adapteren
eksporterer (bankavstemming, bilagsimport, lagertransaksjon-til-bokføring —
VismaBusinessNXTVoucherAdapter.cs:1330-1402):
| NXT-felt | Sendes | Verdi |
|---|---|---|
currencyNo |
kun når linjen har en registrert valuta (i dag kun bankavstemmingsbilag) | NXTs eget valutanummer — se advarsel under |
exchangeRate |
kun sammen med currencyNo |
kursen fra banktransaksjonen |
amountInCurrency |
alltid | valutabeløpet; uten currencyNo leses det av NXT som det domestiske (NOK) beløpet — derfor er ett felles felt trygt for alle produsenter |
amountDomestic |
alltid (uendret felt) | NOK-beløpet |
⚠️ Feltrekkefølgen er bindende. currencyNo MÅ skrives før exchangeRate i den serialiserte
GraphQL-payloaden — å sette valuta gjør at NXT slår opp valutaens standardkurs, som overskriver en
kurs skrevet tidligere (live-API-verifisert). Begge må skrives før beløpsfeltene, ellers leser NXT
beløpet i feil enhet før valutakonteksten er satt — nøyaktig den opprinnelige feilen dette elementet
fikser. Rekkefølgen er pinnet av en regresjonstest på den serialiserte JSON-en, ikke bare
konstruksjonsrekkefølgen i C#-koden (en Dictionary kan i prinsippet endre rekkefølge).
⚠️ currencyNo er et NUMMER, ikke en ISO-kode, og nummereringen er tenant-spesifikk — én
kundes «1 = USD» kan være en annen kundes annen valuta. Nummeret slås derfor opp live per tenant mot
NXTs egen currency-entitet (INxtCurrencyLookupService, samme mekanisme masterordre-importen
bruker) — aldri en hardkodet oversettelsestabell. Finnes ingen match, opprettes ikke bilaget (se
Bankavstemming: Manuell matching → «Konto i utenlandsk valuta»).
Se også Bilagskø og bilagsarkiv (ExtCache) — datamodell for kolonnene på kø- og arkivtabellen.
Ordre-adapter (VismaBusinessNXT_Orders)¶
| Nøkkel | Standard | Hva den gjør |
|---|---|---|
OrderType |
2 |
Ordretypen i Visma Business NXT. Velges i editoren: 1 eller 2. Begge er ordre — den ene har logistikk aktivert, den andre ikke. Velg den typen firmaet bruker (VismaBusinessNXTOrderAdapter.cs:26) |
SyncDirection |
Export |
Eneste lovlige verdi — adapteren importerer ikke ordre |
Overføring på forespørsel fra Bankavstemming (BRQ-8)¶
Når en bruker oppretter et bilag fra bankavstemmingens arbeidsbenk («Opprett bilag»), overføres det nå umiddelbart til denne adapteren i stedet for å vente på neste planlagte kjøring av VismaBusinessNXT_Vouchers — se Bankavstemming: Manuell matching → «Opprett bilag og overfør til Visma» for utfallene brukeren ser. AutomaticBatchUpdates avgjør utfallet på nøyaktig samme måte som ved en planlagt kjøring:
AutomaticBatchUpdates = true(og bokføringskontrollen godkjenner batchen): bilaget bokføres, brukeren ser «Bokført i Visma».AutomaticBatchUpdates = false, eller bokføringskontrollen (EnableBookkeepingControl) avviser batchen: bilaget forblir kun overført (opprettet i NXT, ikke bokført), brukeren ser «Overført, men ikke bokført» og må bokføre det manuelt i Visma.- Feiler selve bokførings-steget i Visma etter en vellykket overføring, ser brukeren «Overført, men bokføringen feilet» med Vismas feiltekst — bilaget er allerede ute av ePortals kø på dette tidspunktet, så det finnes ingen retry-vei i ePortal for den kjøringen.
Denne umiddelbare overføringen bruker samme adapter, kø (wv_ExtCache_Voucher/wv_ExtCache_VoucherLine) og dobbeltkjøringsbeskyttelse (sp_getapplock) som den planlagte kjøringen — er en planlagt kjøring allerede i gang for integrasjonen, legges bilaget i kø og tas med av den i stedet (brukeren ser «Ligger i kø»). Tenanter uten en aktiv VismaBusinessNXT_Vouchers-integrasjon påvirkes ikke — bilaget legges i den vanlige køen som før.
Bilagstype som sendes til NXT for bankavstemmings-bilag (BRQ-9)¶
Adapteren leser bilagstype (voucherType) fra samme rad i wv_ExtCache_VoucherLine som alle andre bilag (VismaBusinessNXTVoucherAdapter.cs:554): VoucherType = (first.VoType ?? 0) > 0 ? first.VoType : null. For bilag opprettet fra Bankavstemming settes denne verdien av innstillingen Accounting.BankReconciliationVoucherType (BankReconciliationController.cs:3084), lest på samme måte som Accounting.DefaultVoucherSeries:
- Standard
0— ingenvoucherTypesendes til NXT i det hele tatt, og NXT bruker seriens standard bilagstype. Dette er riktig for de fleste selskaper. - Verdi > 0 — sendes verbatim som NXT sin
voucherType. Sett denne kun hvis selskapet i NXT krever en spesifikk bilagstype for disse bilagene.
Ingen migrasjon seeder denne innstillingen — den leses via ISettingsService, som returnerer standardverdien 0 når nøkkelen ikke finnes i wv_SystemConfiguration.
Historikk: før BRQ-9 var bilagstypen hardkodet til 700 som en intern ePortal-markør for "dette er et bankavstemmings-bilag". NXT tolker imidlertid VoType som en reell bilagstype, og et selskap uten type 700 (f.eks. selskap 6106857) fikk hele batchen avvist med «Voucher type 700 does not exist» — hver eneste «Opprett bilag»-overføring feilet. Bankavstemmings-bilag identifiseres uansett unikt via ExtID = "BR{banktransaksjonID}", så bilagstype-feltet var aldri nødvendig som markør.
Tidsregistrerings-adapter (VismaBusinessNXT_TimeRegs)¶
Bruker NXT-entiteten freeInformation3 ("Fri informasjon 3"). ePortal sin wrID lagres som primaryKey for å gi 1:1 oppslag mellom systemene (VismaBusinessNXTTimeRegistrationAdapter.cs:21).
Felt-mapping (ePortal → NXT) (VismaBusinessNXTTimeRegistrationAdapter.cs:621-660):
| ePortal-felt | NXT-felt | Notat |
|---|---|---|
wrID |
primaryKey |
Idempotent nøkkel |
wrEmplNo |
employeeNo |
|
wrDate |
date1 (YYYYMMDD int) + realisedYearAndPeriod (YYYYMM int) |
|
wrDep |
orgUnit1 |
Avdeling |
wrProj |
orgUnit2 |
Prosjekt |
wrWorkOrd |
orgUnit5 |
Arbeidsordre |
wrAccX |
orgUnit9 (string) |
KontoX |
wrQty |
value1 |
Antall timer |
| Lønnsart | text1 |
|
| Beskrivelse | text2 |
Operasjoner: freeInformation3_create(values: [...]), freeInformation3_update(filters, values), freeInformation3_delete(filter: { primaryKey: { _in: [...] } }).
Bilags-vedlegg (Excel/PDF)¶
Vedlegg legges til NXT-bilaget via mutasjonen voucher_processings.addNewDocument(...) med base64-innhold. Mutasjonen ligger i den delte NxtVoucherDocumentGateway (BRQ-10) — ett sted som brukes av to kallsteder: den planlagte kø-eksporten (VismaBusinessNXTVoucherAdapter.UploadVoucherDocumentsAsync, for vedlegg med UploadToNxt = 1) og bankavstemmingens direkte post-overføringsopplasting (se under). NXT begrenser én GraphQL-forespørsel til ~15 MB; ePortal kaster vedlegg over MAX_VOUCHER_DOCUMENT_BASE64_LENGTH = 14_000_000 (VismaBusinessNXTVoucherAdapter.cs:76) — denne grensen gjelder foreløpig ikke bankavstemmingens direkte opplasting (se under).
Bankavstemmings-vedlegg til et allerede overført bilag (BRQ-10)¶
Etter at et bilag fra bankavstemmingen er overført (se BRQ-8 over), kan brukeren laste opp vedlegg direkte til det NXT-bilaget mens bokføringsmodalen er åpen — se Bankavstemming: Manuell matching → «Vedlegg til bilaget». Dette er en egen, direkte vei til samme mutasjon — ikke den delte kø-eksporten over:
- Backend-endepunktet
UploadVoucherAttachmentToNxtvaliderer eierskap likt BRQ-8sPostVoucher(bilaget må tilhøre den oppgitte banktransaksjonen) — og at det valgte vedlegget faktisk tilhører DEN bilagslinjen (VoucherLineAttachmentBelongsToAsync, R1-review-funn: enAttachmentIDer global, ikke voucher-scoped, så uten denne sjekken kunne en person med tilgang til én egen bankavstemmings-voucher pushe et hvilket som helst vedlegg i tenanten til et hvilket som helst bilag). Endepunktet tar ikke imot batch-/bilagsnummer fra klienten (samme review-funn) — det slår opp det virkelige(batchNo, voucherNo)selv viaNxtVoucherDocumentGateway.ResolveVoucherCoordinatesByVolIdAsync(sammeexternalReference3 = "EPVOL:{VolID}"-markør adapteren stempler på eksport) og kaller såAddDocumentAsyncmed de server-utledede tallene — ingen kø. - Bankavstemmings-vedlegg lagres alltid med
UploadToNxt = 0og går aldri inn i den delte kø-eksporten over — den køen laster ned blob'en fra det lagredeBlobContainer-navnet uendret, mens bankavstemming lagrer det uprefikserte navnet (seExtCacheVoucherDocumentRepository-klassekommentaren og "Vedlegg" i Bilagshistorikk-seksjonen for hvorfor de to ikke kan blandes). SentToNxtsettes kun etter en vellykket opplasting, gjenbruker samme kolonne som kø-veien.- Vinduet er den åpne dialogen — en produktbeslutning, ikke en teknisk begrensning: frontenden forsøker kun å pushe et vedlegg mens den fortsatt har et bilagsnummer fra denne sesjonens
PostVoucher-svar; lukkes bokføringsmodalen, slutter frontenden å prøve. Serveren selv trenger ikke dette tallet — den slår opp de virkelige NXT-koordinatene på nytt hver gang, uavhengig av om modalen er åpen. Et vedlegg lastet opp før en vellykket overføring, eller mens frontenden ikke har et kjent bilagsnummer, forblir derfor lagret i ePortal uten å nå Visma i denne sesjonen.
Bilagshistorikk og re-kjøring («Bilagshistorikk»-fanen)¶
Bilags-integrasjonen har en egen Bilagshistorikk-fane som viser alle bilag som er
eksportert til Business NXT. Ved eksport flyttes bilaget fra den aktive køen
(wv_ExtCache_Voucher / wv_ExtCache_VoucherLine) til arkivtabellene
(wv_ExtCache_Voucher_imported / wv_ExtCache_VoucherLine_imported) av databasetriggeren
trg_Voucher_delete. Fanen leser arkivet og viser eksporttidspunkt, linjeantall, beløp og
eventuelle re-kjøringer (hvem/når).
Kjør på nytt: velg ett eller flere bilag og trykk «Kjør på nytt». Bilaget legges da
tilbake i eksportkøen med sine originale ID-er, og dukker opp under «Nye bilag».
Arkivkopien blir liggende med stempel for re-kjøringen (RestoredDate/RestoredBy).
- Duplikatvern: eksporten dedupliserer mot NXT på
externalReference3(EPVOL:<VolID>). Et bilag som fortsatt finnes i NXT blir derfor ikke bokført på nytt — det ryddes bare fra køen igjen ved neste kjøring. Re-kjøring har kun effekt når bilaget faktisk er slettet i NXT. - Vedlegg: bilagsvedlegg (f.eks. Aktivering-timer-Excel) re-armes ved re-kjøring
(
SentToNxtnullstilles) og lastes opp på nytt hvis bilaget gjenopprettes i NXT. - Hoppet over: bilag som allerede ligger i køen («allerede i kø») eller mangler arkiverte linjer («ingen arkiverte linjer») hoppes over med begrunnelse i varselet.
Kilde: api/ePortal.API/ePortal.Base/Repository/ExtCacheVoucherHistoryRepository.cs
(restore/lesing), api/ePortal.API/ePortal.Base/Services/Integration/VismaBusinessNXT/VismaBusinessNXTVoucherAdapter.cs
(dedup og vedleggsopplasting), api/ePortal.API/ePortal.DbUp/v1/Migration_20261016900021.cs
(arkiv-audit og trigger).
Vanlige spørsmål om re-kjøring¶
| Situasjon | Forklaring |
|---|---|
| Re-kjørt bilag forsvinner fra køen uten å dukke opp i NXT | Bilaget finnes fortsatt i NXT — duplikatvernet ryddet det fra køen. Slett bilaget i NXT først hvis det skal bokføres på nytt. |
| Eldre bilag mangler serie/tekst i historikken | Bilagshoder eksportert før v-migrasjonen 20261016900021 kunne gå tapt (trigger-feil, nå fikset). Bilaget kan fortsatt kjøres på nytt; eksporten bruker da konfigurert VoucherSeriesNo. |
| Eldre bilag mangler eksportdato | Eksporter gjort før migrasjonen har ingen tidsstempel i arkivet. |
| Re-kjørt bilag ble ryddet av duplikatvernet — hva skjer med vedlegg? | Vedleggene forblir re-armet (SentToNxt = 0) til en senere re-kjøring der bilaget faktisk gjenopprettes i NXT. Opplasting skjer kun etter at bilaget er opprettet i NXT, så ingenting lastes opp dobbelt. |
OrgUnit-mapping (avdelinger / prosjekter / arbeidsordre)¶
NXT bruker orgUnit1–orgUnit12 som ressursdimensjoner. Standardene ePortal sender er konsekvente på tvers av adaptere:
| ePortal-konsept | NXT-felt |
|---|---|
| Avdeling | orgUnit1 |
| Prosjekt | orgUnit2 |
| Arbeidsordre | orgUnit5 |
| KontoX | orgUnit9 (string) |
Standardmapping passer Vismas typiske R-matrise for konsulent-/installasjonsfirmaer. Egne integrasjons-spesifikke field-mapping kan settes per integrasjon — adapterne eksponerer en liste av FieldMappingOption for tilgjengelige NXT-felt.
GraphQL-filter syntax — _and-array¶
NXT GraphQL krever _and-array-syntax når flere felt skal filtreres. Flere betingelser som ikke pakkes i _and, ignoreres stille av NXT — spørringen returnerer da alle rader.
_or finnes i operatortabellen, men ePortal sender det ikke. Vismas egen dokumentasjon beskriver at et _or-deluttrykk kan bli stille fjernet fra filteret, og et filter som mister en betingelse utvider resultatsettet i stedet for å feile høylytt. På en hentegrense som avgjør hvilke regnskapsposter som i det hele tatt kommer inn, er stille utvidelse den verste feilmåten. Samme valg er tatt i NxtPriceLookupService, NxtProductLookupService og VismaBusinessNXTBudgetLineProvider. _is_null sendes heller ikke — operatoren står i tabellen, men har ingen dokumentert argumentform.
I stedet kjøres to enkle spørringer per entitet, én per datoakse, som slås sammen og dedupliseres i C#. Hovedboken bruker BuildLedgerTransactionQueryByValueDate og BuildLedgerTransactionQueryByVoucherDate (banksiden tilsvarende ...ByInterestDate / ...ByBookingDate); BuildLedgerTransactionQuery og BuildBankTransactionsQuery er interne hjelpere bak disse, ikke inngangspunkter.
Verdiaksen — bare rader som faktisk har en valuteringsdato:
filter: {
_and: [
{ accountNo: { _eq: $accountNo } }
{ valueDate: { _gt: 0 } }
{ valueDate: { _gte: $fromDate } }
{ valueDate: { _lte: $toDate } }
]
}
Bilagsaksen — ingen betingelse på valuteringsdato i det hele tatt:
filter: {
_and: [
{ accountNo: { _eq: $accountNo } }
{ voucherDate: { _gte: $fromDate } }
{ voucherDate: { _lte: $toDate } }
]
}
Unionen er et supersett av de radene som hører til perioden: har raden valuteringsdato, returnerer verdiaksen den; mangler den, er bilagsdatoen den effektive datoen og bilagsaksen returnerer den. Fordi bilagsaksen med vilje henter for mye, trimmes unionen etterpå i C# på den effektive datoen (IsInEffectiveNxtWindow), og dedupliseres på radens primærnøkkel — den sammensatte (voucherJournalNo, auditNo) for hovedbok, accountStatementTransactionNo for bank. Ingen del av regelen avhenger av hvordan NXT sammenligner NULL.
Datoformat er int YYYYMMDD (eks. 20260131). Strenger eller ISO-format gir filterfeil.
Paginering¶
Alle GraphQL-queryer i VismaBusinessNXTBankDataProvider (og adapterne) paginerer via pageInfo { hasNextPage endCursor } med first: 500 per side (VismaBusinessNXTBankDataProvider.cs). Cursor sendes som after-variabel ved påfølgende sider.
Bank- og hovedboks-data (for Bankavstemming og KAI Live regnskap)¶
VismaBusinessNXTBankDataProvider leverer data via GraphQL — ikke via CAMT-filer:
| Funksjon | NXT-entitet (alias) |
|---|---|
| Hovedbokstransaksjoner | generalLedgerTransaction (acTr68) |
| Hovedbokssaldo | generalLedgerTransaction (acTr68) — summert i ePortal, se under |
| Reskontro (kunde) | customerTransaction (custTr54) |
| Reskontro (leverandør) | supplierTransaction (supTr61) |
| Bank-utdrag (transaksjonshode) | accountStatementTransaction (acStmtTr434) |
| Bank-utdrag (detaljlinjer) | accountStatementDetail (acStmtDe437) |
| Aktører (kunde/leverandør master) | associate (Actor, tabell 152) |
| Hovedbokskontoer | generalLedgerAccount |
Hovedbokssaldo beregnes i ePortal, ikke lest fra NXT sin egen periodesaldo. GetLedgerAccountBalanceAsync summerer enteredAmountDomestic fra generalLedgerTransaction for alle rader med effektiv dato til og med den forespurte datoen — samme to-spørrings-mekanikk (verdidato-akse og bilagsdato-akse, slått sammen og deduplisert) og samme effektive-dato-regel som Hovedbokstransaksjoner under, bare uten noen nedre datogrense (VismaBusinessNXTBankDataProvider.cs:634-675). NXT sin egen generalLedgerBalance-entitet (periodegranulær, følger bokføringsdatoen) brukes ikke.
Viktig: Det er ingen customer- eller supplier-rotfelt på useCompany — kunde- og leverandør-navn slås opp via den unifiserte associate-entiteten filtrert på customerNo/supplierNo (VismaBusinessNXTBankDataProvider.cs:583-611).
Periodefilteret bruker valuteringsdato, med bilags-/bokføringsdato som reserve. Alle spørringene under henter på den effektive datoen: valuteringsdato når raden har en, ellers bilags-/bokføringsdato. Det er samme datoakse som resten av bankavstemmingsmodulen bruker når den avgjør hvilke rader som hører til perioden — henter vi på en annen akse enn vi slipper inn på, forsvinner rader vi skulle hatt, og de kan aldri hentes igjen (eierbeslutning 2026-08-05, BRQ-32).
| Spørring | Valuteringsdato | Reserve når valuteringsdato mangler |
|---|---|---|
Hovedbok (generalLedgerTransaction) |
valueDate (kode) |
voucherDate (kode) |
Reskontro (customerTransaction/supplierTransaction) |
valueDate (kode) |
voucherDate (kode) |
Banktransaksjoner (accountStatementTransaction) |
interestDate (kode) |
bookingDate (kode) |
accountStatementTransaction har ikke noe valueDate-felt — interestDate er NXT-navnet på valuteringsdato der (samme felt som IntDt on-prem). Reserveaksen er nødvendig fordi rene GL-posteringer (konsernmellomværende, periodiseringskonto-bevegelser) mangler valuteringsdato, og et filter på valuteringsdato alene ville returnert tomt for dem.
En manglende dato har to mulige representasjoner: 0 (heltallsstandarden fra on-prem) og GraphQL null. Introspeksjonen viser at både valueDate og voucherDate er nullbare Int (SCALAR Int, uten NON_NULL-innpakning), så null er en reell verdi og ikke bare en teoretisk mulighet. Begge betyr det samme her, og begge håndteres: DTO-feltene er int? — som non-nullable int ville en JSON-null fått hele siden til å feile under deserialisering — og den effektive datoen regnes som «satt» bare når verdien er større enn 0.
CAMT 053/054 er en separat, manuell bank-fil-import (
CamtFileParser,api/ePortal.API/ePortal.Base/Services/BankReconciliation/CamtFileParser.cs) — ikke noe NXT-integrasjonen leverer.
Sikkerhet og driftsbeskyttelse¶
Krypterte credentials¶
Tjenester som henter NXT-credentials utenfor IntegrationService må bruke GetDecryptedConfigAsync(integrationId). FromIntegration returnerer fortsatt kryptert ClientSecret → kallet til Visma Connect svarer 401.
Dobbeltkjøringsbeskyttelse¶
IntegrationLockRepository bruker sp_getapplock med LockMode = 'Exclusive', LockOwner = 'Session', LockTimeout = 0 per integrasjon (IntegrationLockRepository.cs:23-28). Hvis samme integrasjon allerede kjører, gir låsen < 0 retur og forsøket avvises umiddelbart — uten å vente.
Vanlige problemer¶
"Cannot query field 'X' on type 'Y'"¶
NXT GraphQL endrer feltnavn av og til (Visma oppgraderer skjema). Sjekk at ePortal-versjonen er oppdatert.
Hovedboks tom — for streng datofilter¶
Rene GL-posteringer og konsernmellomværende-konti har ofte ingen valuteringsdato (0 eller null). Et filter som bare ser på valuteringsdato returnerer derfor tomt for disse. ePortal håndterer dette selv — bilagsaksen (BuildLedgerTransactionQueryByVoucherDate) henter disse radene uavhengig av valuteringsdato — så dette skal ikke lenger være årsaken. Er hovedboken likevel tom, sjekk kontonummer, selskapsnummer og at datointervallet faktisk dekker perioden.
"401 Unauthorized" mot Visma Connect¶
ClientSecret brukt direkte uten dekryptering. Bruk IntegrationService.GetDecryptedConfigAsync (eller hjelpere i VismaBusinessNXTHttpHelper som invaliderer cached token ved 401 og henter friskt).
Aktør-synk finner ikke kunde/leverandør¶
customer/supplier finnes ikke som rotfelt på useCompany. Bruk associate(filter: { customerNo: { _eq: $no } }) eller tilsvarende for leverandør (VismaBusinessNXTBankDataProvider.cs:583-611).
Tidseksport stopper midt i kjøringen¶
Når MaxRowsPerRun (standard 25 000) nås, stopper adapteren og fortsetter fra cursor ved neste planlagte kjøring. Dette er forventet for store backfills — loggen sier "Nådde MaxRowsPerRun (...) — fortsetter fra cursor ved neste kjøring".
Bilagsvedlegg avvises av NXT¶
Base64-innhold over ~14 MB avvises lokalt før send (NXT cap ~15 MB per GraphQL-request). Komprimer vedlegget eller del det opp.
"Dobbeltkjøring forhindret"¶
sp_getapplock per integrasjon avviser samtidige kjøringer av samme integrasjon. Vent på pågående kjøring; den slipper låsen ved fullføring.
"Konfigurasjonsfeltet «...» må være et positivt tall" ved lagring¶
Rettet. Tidligere kunne denne meldingen komme selv om feltet inneholdt et gyldig tall: skjemavisningen sendte tallfeltene som tekst i konfigurasjonen, og valideringen krevde et ekte tall. Den slo bare til på felt du faktisk hadde redigert, så en urørt integrasjon fortsatte å virke mens den samme integrasjonen ikke lot seg lagre etter en endring.
Kommer meldingen fortsatt, er verdien reelt ugyldig: feltet er tomt, inneholder noe annet enn siffer, eller er null eller negativt. Feltet må ha et helt tall som er 1 eller høyere. Meldingen navngir hvilket felt det gjelder. Gjelder DeltaSyncLookbackDays, ExportBatchSize, MaxRowsPerRun, BatchSize, AlertDigestMinutes, MaxPagesPerRun, MaxRuntimeSeconds, ReconcileEveryNRuns og CompanyNo (NxtIntegrationConfigurationPolicy.cs:249-253).
OrderType og OrgUnitLevel har egne meldinger og er strengere med vilje — de bestemmer hvilke poster adapteren skriver, så bare de gyldige kodene godtas (OrderType 1 eller 2, OrgUnitLevel 1–12).
"VoucherSeriesNo ikke konfigurert"¶
Bilags-adapteren krever VoucherSeriesNo i integrasjonens config — "VoucherSeriesNo '...' er ikke et gyldig heltall" kastes hvis verdien mangler eller ikke kan parses (VismaBusinessNXTVoucherAdapter.cs:250-252).
Migrering fra Visma Business klassisk¶
Hvis kunden migrerer fra klassisk Visma Business (PortalConnector WinService) til NXT:
- Ikke kjør begge adapter-sett samtidig på samme datatype — risiko for konfliktende skriv
- Aktiver NXT-adaptere i parallell, men hold dem på lese-bare områder først (hovedbok, aktører) for sammenligning
- Bytte over én datatype om gangen (timer → bilag → ordre)
- Pause klassisk-integrasjonen når NXT-eksporten er bekreftet
Konti har egen rutine for migrering — kontakt support før du starter.
Relaterte sider¶
- Konti Connect-modulen
- Integrasjoner — oversikt
- Visma.net — Visma SaaS-regnskap (annen integrasjon)
- Visma Business klassisk — desktop-versjon via PortalConnector WinService
- Bankavstemming — bruker NXT som data-kilde for hovedbok og bank

