Slik setter du opp betaling i appen
Slik setter du opp betaling med Nets Easy i appen din.
1. Før du starter
Organisasjonen du lager appen for, må ha en Nets Easy-avtale. Les hvordan du oppretter avtalen på nettsidene til Nets.
2. Legge til en betalingsoppgave i appens prosess, med tilhørende konfigurasjon
Du gjør oppsettet i denne delen på siden Arbeidsflyt i Altinn Studio. Klikk på Arbeidsflyt i toppmenyen for å komme dit.
1. Legg til en betalingsoppgave
Legg til en betalingsoppgave ved å dra Lag betalingsoppgave fra menyen til venstre inn i arbeidsflyten.
Altinn Studio legger da automatisk til
- to datatyper for betaling (en for betalingsdata og en for betalingskvitteringen)
- sider for betalingsoppgaven, med én ferdig oppsatt side
- en regel for tilgangsstyring for betalingsoppgaven, som du setter opp i steget «Gi tilgang til den som skal betale og tjenesteeieren»
2. Legge til en gateway etter betalingsoppgaven
Gatewayen skal ha to piler (sekvensflyter) ut:
- En som peker videre i arbeidsflyten.
- En som peker tilbake til forrige oppgave i arbeidsflyten (før betaling).
3. Sett opp regler for pilene ut av gatewayen
For pilen som går videre:
- Klikk på pilen som går videre i arbeidsflyten.
- I panelet til høyre klikker du på Lag en ny logikkregel. Regelen får handlingen Avvise (
reject) som utgangspunkt. - Klikk på Endre, og bytt handlingen fra Avvise til Bekrefte.
- Klikk på Lagre og lukk for å lagre regelen.
For pilen som går tilbake:
- Klikk på pilen som går tilbake i arbeidsflyten.
- Gjenta stegene over, men ikke endre handlingen. Den skal være Avvise.
Her beskrives hvordan du setter opp en betalingsoppgave i prosessen. Dette involverer flere steg i flere konfigurasjonsfiler. Hvis du bruker Altinn Studio Designer, setter systemet opp all denne konfigurasjonen automatisk når du legger til betalingsoppgaven i prosessen.
Opprette to datatyper for å lagre betalingsinformasjon
Betalingssteget bruker den første datatypen for å lagre informasjon og status om betalingen. Legg den i dataTypes-arrayen i App/config/applicationmetadata.json.
App/config/applicationmetadata.json{
"id": "paymentInformation",
"allowedContentTypes": [
"application/json"
],
"allowedContributors": [
"app:owned"
],
"maxCount": 1,
"minCount": 0,
}
Systemet bruker den andre datatypen for å lagre PDF-kvittering for betalingen. Legg den inn på samme sted.
App/config/applicationmetadata.json{
"id": "paymentReceiptPdf",
"allowedContentTypes": [
"application/pdf"
],
"allowedContributors": [
"app:owned"
],
"maxCount": 1,
"minCount": 0,
}
Det er viktig å sette allowedContributors til "app:owned". Det gjør at du ikke kan redigere disse dataene via appens API, men bare via appen selv. Før versjon 8.6 var denne konfigurasjonen feilstavet allowedContributers.
ID-ene kan settes til noe annet, men de må være de samme som ID-ene du legger inn i paymentDataType og paymentReceiptPdfDataType i prosessteget, som vist i punktet under.
Utvide app-prosessen med payment task
Du må legge til et prosessteg og en gateway i App/config/process/process.bpmn, som i eksemplet nedenfor.
Betaling bruker tre user actions. Hvis appen bruker Altinn-brukergrensesnittet, kaller systemet disse automatisk når du står i betalingssteget. Hvis du bare bruker API-et, må du kalle disse manuelt via /actions-endepunktet.
pay: Setter i gang betalingen, ofte ved å gjøre API-kall til betalingsbehandler. Systemet lagrer informasjon og status om den igangsatte betalingen i en JSON-datatype som du angir i prosesssteget for betaling.confirm: Du kaller denne når betalingen er ferdig gjennomført, for å drive prosessen videre til neste steg.reject: Hvis sluttbrukeren ser noe feil med ordren, kan vedkommende trykke Tilbake i betalingssteget. Da kansellerer systemet betalingen og sletter informasjon om den avbrutte betalingen. En gateway angir hvilket prosessteg du deretter går til, som eksemplifisert nedenfor.
App/config/process/process.bpmn <bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_start_t1</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_start_t1" sourceRef="StartEvent_1" targetRef="Task_1" />
<bpmn:task id="Task_1" name="Utfylling">
<bpmn:incoming>Flow_start_t1</bpmn:incoming>
<bpmn:incoming>Flow_g1_t1</bpmn:incoming>
<bpmn:outgoing>Flow_t1_t2</bpmn:outgoing>
<bpmn:extensionElements>
<altinn:taskExtension>
<altinn:taskType>data</altinn:taskType>
</altinn:taskExtension>
</bpmn:extensionElements>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_t1_t2" sourceRef="Task_1" targetRef="Task_2" />
<bpmn:task id="Task_2" name="Betaling">
<bpmn:incoming>Flow_t1_t2</bpmn:incoming>
<bpmn:outgoing>Flow_t2_g1</bpmn:outgoing>
<bpmn:extensionElements>
<altinn:taskExtension>
<altinn:taskType>payment</altinn:taskType>
<altinn:actions>
<altinn:action>confirm</altinn:action>
<altinn:action>pay</altinn:action>
<altinn:action>reject</altinn:action>
</altinn:actions>
<altinn:paymentConfig>
<altinn:paymentDataType>paymentInformation</altinn:paymentDataType>
<altinn:paymentReceiptPdfDataType>paymentReceiptPdf</altinn:paymentReceiptPdfDataType>
</altinn:paymentConfig>
</altinn:taskExtension>
</bpmn:extensionElements>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_t2_g1" sourceRef="Task_2" targetRef="Gateway_1" />
<bpmn:exclusiveGateway id="Gateway_1">
<bpmn:incoming>Flow_t2_g1</bpmn:incoming>
<bpmn:outgoing>Flow_g1_t1</bpmn:outgoing>
<bpmn:outgoing>Flow_g1_end</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_g1_t1" sourceRef="Gateway_1" targetRef="Task_1">
<bpmn:conditionExpression>["equals", ["gatewayAction"], "reject"]</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_g1_end" sourceRef="Gateway_1" targetRef="EndEvent_1">
<bpmn:conditionExpression>["equals", ["gatewayAction"], "confirm"]</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:endEvent id="EndEvent_1">
<bpmn:incoming>Flow_g1_end</bpmn:incoming>
</bpmn:endEvent>
NB: Verdien til noden <altinn:paymentDataType>paymentInformation</altinn:paymentDataType> må være den samme som ID-en til datatypen du konfigurerte i forrige steg. Det samme gjelder datatypen for PDF-kvittering.
Legge til sidegruppe for betaling
Legg til en mappe under
App/uimed samme navn som ID-en til betalingsoppgaven. I eksempelet over er ID-enTask_2, så mappen må heteTask_2.Legg til
Settings.jsoni mappen. SettdefaultDataTypetil datamodellen som betalingssteget skal bruke:App/ui/Task_2/Settings.json{ "$schema": "https://altinncdn.no/schemas/json/layout/layoutSettings.schema.v1.json", "defaultDataType": "model", "pages": { "order": ["payment"] } }Opprett mappen
App/ui/Task_2/layouts, og legg til layout-filenpayment.jsonmed dette innholdet:App/ui/Task_2/layouts/payment.json{ "$schema": "https://altinncdn.no/toolkits/altinn-app-frontend/4/schemas/json/layout/layout.schema.v1.json", "data": { "layout": [ { "id": "payment-test-component", "type": "Payment", "textResourceBindings": { "title": "Oppsummering" } } ] } }Dette er nødvendig for at betaling skal fungere. Uten dette viser betalingssteget ditt bare en hvit side.
3. Gi tilgang til den som skal betale og tjenesteeieren
Du gjør dette steget på siden Arbeidsflyt i Altinn Studio. Klikk på Arbeidsflyt i toppmenyen.
- Klikk på betalingsoppgaven i arbeidsflyten.
- Åpne Tilganger i panelet til høyre, og klikk på Gå til Tilganger. Siden Innstillinger åpner seg med Tilganger valgt.
- Velg fanen Regler. Regelen for betalingsoppgaven er markert med rødt og har feilmeldingen «Du må velge minst én rolle eller tilgangspakke.»
- Under Hvem skal ha disse rettighetene? legger du til tilgangspakkene eller rollene som skal ha tilgang til betalingsoppgaven, under For virksomheter eller For privatpersoner. Når du har lagt til minst én, er regelen gyldig og ikke lenger markert med rødt.
- Klikk på Arbeidsflyt i toppmenyen for å gå tilbake.
read, write, pay, confirm og reject på betalingsprosessteget.Når Nets varsler appen om at betalingen er fullført, oppdaterer appen betalingsinformasjonen og fører prosessen videre på vegne av tjenesteeieren. I App/config/authorization/policy.xml må [org] derfor ha handlingene read og write for appen og confirm for betalingsoppgaven.
Altinn Studio legger automatisk til standardscopene for tjenesteeier i Maskinporten for apper som bruker Altinn App v9. Kontroller likevel at autorisasjonspolicyen gir tjenesteeieren de nødvendige handlingene. Se integrasjon med Maskinporten. Bygg og publiser appen på nytt etter at du har endret scopene eller autorisasjonspolicyen.
4. Konfigurere visning for betalingsinformasjon
Du gjør det meste av oppsettet i denne delen på siden Utforming i Altinn Studio. Klikk på Utforming i toppmenyen. Noe av oppsettet gjør du manuelt i layoutfilene, som beskrevet nedenfor.
Slik viser du betalingsinformasjon i skjemaet
Du gjør dette steget i skjemaoppgaven. Layoutfilene til oppgaven ligger i
App/ui/{taskId}/layouts/. Skjemaoppgaven som følger med appen når du oppretter den, har ID-enTask_1. Hvis du har lagt til andre skjemaoppgaver i arbeidsflyten, bruker du mappen med samme ID som oppgaven.
Legg til en komponent av typen
PaymentDetailsi layoutfilen til siden der brukeren skal se betalingen. Komponenten viser en tabell over det brukeren skal betale for. I Altinn Studio heter den Betalingsdetaljer, men du finner den ikke i Velg komponent, så du legger den til manuelt, som i eksempelet nedenfor.Du kan plassere komponenten hvor som helst i skjemaet, men vi anbefaler å sette den på den siste siden før brukeren skal betale.
Appen beregner ordrelinjene ut fra data i skjemaet. Når brukeren endrer disse dataene, må appen hente ordrelinjene på nytt. Derfor legger du til datafeltene som appen bruker i beregningen, i
refetchDependencies. Hver verdi er et uttrykk som peker på et felt i datamodellen. Du kan velge navnet på nøkkelen fritt, og appen sender ikke verdiene til serveren. Du legger dem inn i layoutfilen, som i eksempelet nedenfor:
App/ui/{taskId}/layouts/{page}.json{
"id": "paymentDetails",
"type": "PaymentDetails",
"textResourceBindings": {
"title": "Oversikt over betaling",
"description": "Her er en oversikt over hva du skal betale for."
},
"refetchDependencies": {
"inventory": ["dataModel", "GoodsAndServicesProperties.Inventory.InventoryProperties"]
}
}
Slik viser du betalingsinformasjon i betalingsoppgaven
Altinn Studio setter dette opp automatisk når du legger til betalingsoppgaven i Arbeidsflyt.
Slik lager du en egen kvittering for betalingen (valgfritt)
Hvis du hopper over dette steget, bruker appen oppsettet fra betalingsoppgaven i kvitteringen.
Klikk på Utforming i toppmenyen, og klikk på Utform på kortet Oppgave: Betaling. Hvis du allerede står i en oppgave, klikker du først på Oversikt øverst på siden for å komme tilbake til kortene.
Klikk på Legg til ny side.
I panelet til høyre åpner du PDF og klikker på Gjør om siden til PDF.
Legg til komponenten Betaling, og eventuelt andre tekster og komponenter du vil ha på PDF-siden.
Åpne utviklerverktøyet i forhåndsvisningen med knappen nederst til høyre, eller med hurtigtasten Ctrl+Shift+K (⌘+Shift+K på Mac). Klikk deretter på Generer PDF under Forhåndsvis PDF.
Legge til PaymentDetails-komponenten i skjemaet ditt
Dette viser en tabell som viser elementene brukeren må betale for. Du kan plassere dette hvor som helst i appen din, men vi anbefaler å sette det på den siste siden før brukeren blir bedt om å betale.
Systemet beregner ordrelinjene ut fra data i skjemaet. Når brukeren endrer disse dataene, må appen hente ordrelinjene på nytt. Derfor legger du til datafeltene som systemet bruker i beregningen, i refetchDependencies. Hver verdi er et uttrykk som peker på et felt i datamodellen. Navnet på nøkkelen kan du velge fritt, og verdiene sendes ikke til serveren.
App/ui/{taskId}/layouts/{page}.json{
"id": "paymentDetails",
"type": "PaymentDetails",
"textResourceBindings": {
"title": "Oversikt over betaling",
"description": "Her er en oversikt over hva du skal betale for."
},
"refetchDependencies": {
"inventory": ["dataModel", "GoodsAndServicesProperties.Inventory.InventoryProperties"]
}
}
Legge til layout for kvitteringen (valgfritt)
Hvis du vil vise mer informasjon på kvitteringen som vises til kunden, må du legge til en egen tilpasset layout for den.
Legg til en layout-fil, for eksempel receiptLayout.json.
Her er et minimalt eksempel:
App/ui/{taskId}/layouts/receiptLayout.json{
"$schema": "https://altinncdn.no/toolkits/altinn-app-frontend/4/schemas/json/layout/layout.schema.v1.json",
"data": {
"layout": [
{
"id": "test",
"type": "Payment",
"renderAsSummary": true
}
]
}
}
Oppdater Settings.json i UI-mappen til betalingsoppgaven (App/ui/<taskId>/Settings.json), og angi kvitteringslayouten din i feltet pdfLayoutName:
App/ui/{taskId}/Settings.json{
"$schema": "https://altinncdn.no/toolkits/altinn-app-frontend/4/schemas/json/layout/layoutSettings.schema.v1.json",
"defaultDataType": "model",
"pages": {
"order": [
"payment"
],
"pdfLayoutName": "receiptLayout",
"showProgress": true,
"showLanguageSelector": true
}
}
Dette er alt du trenger for å vise en gyldig kvittering, men du kan også tilpasse receiptLayout.json ved å legge til ytterligere komponenter, for eksempel en paragrafkomponent hvis du ønsker å legge til mer informasjon.
5. Beregne hva som skal betales
Altinn Studio har ikke innstillinger for dette. Du gjør dette steget i koden til appen. Se fanen Manuelt oppsett for dette steget.
Implementere IOrderDetailsCalculator-interfacet i C#
Legg til en ny klasse der du har din custom-kode, for eksempel App/logic/OrderDetailsCalculator.cs.
Her implementerer du logikken din for å regne ut hva brukeren skal betale for. Du kan for eksempel aksessere skjemadata, legge til obligatoriske avgifter eller bare legge til en fast kostnad for skjemaet.
Returverdien fra metoden CalculateOrderDetails angir:
- Betalingsbehandler som ordren skal bruke. Du gjør disse tilgjengelige ved å implementere interfacet
IPaymentProcessorog registrere dem somtransientiprogram.cs. Fyll utNets Easyfor å bruke standardimplementasjonen for Nets Easy. - Valuta
- Ordrelinjer
- Detaljer om betalingsmottaker. Brukes i kvittering.
- Detaljer om betaler (valgfritt), hvis du ønsker å forhåndsutfylle denne informasjonen hos Nets Easy. Du kan bruke dette i kombinasjon med Nets Easy sitt flagg
MerchantHandlesConsumerData, som vi har eksponert via appsettings.jsonNetsPaymentSettings.MerchantHandlesConsumerData. Hvis du setter den tiltrue, må du sende med detaljer om betaler, ellers feiler det.
I dette eksempelet regner systemet ut ordrelinjene basert på skjemadata:
public class OrderDetailsCalculator : IOrderDetailsCalculator
{
private readonly IDataClient _dataClient;
public OrderDetailsCalculator(IDataClient dataClient)
{
_dataClient = dataClient;
}
public async Task<OrderDetails> CalculateOrderDetails(Instance instance, string? language)
{
DataElement modelData = instance.Data.Single(x => x.DataType == "model");
InstanceIdentifier instanceIdentifier = new(instance);
Form formData = (Form) await _dataClient.GetFormData(instanceIdentifier.InstanceGuid, typeof(Form), instance.Org, instance.AppId,
instanceIdentifier.InstanceOwnerPartyId, new Guid(modelData.Id));
List<PaymentOrderLine> paymentOrderLines = formData.GoodsAndServicesProperties.Inventory.InventoryProperties
.Where(x => !string.IsNullOrEmpty(x.NiceClassification) && !string.IsNullOrEmpty(x.GoodsAndServices))
.Select((x, index) =>
new PaymentOrderLine
{
Id = index.ToString(), Name = $"{GetLocalizedName(x.Id, language)}", PriceExVat = GetPriceForInventoryItem(x), Quantity = 1, VatPercent = 0M
})
.ToList();
return new OrderDetails {
PaymentProcessorId = "Nets Easy",
Currency = "NOK",
OrderLines = paymentOrderLines,
Receiver = GetReceiverDetails(),
Payer = GetPayerDetails()};
}
}
Registrer IOrderDetailsCalculator-implementasjonen i program.cs:
App/Program.csvoid RegisterCustomAppServices(IServiceCollection services, IConfiguration config, IWebHostEnvironment env)
{
// Register your apps custom service implementations here.
services.AddTransient<IOrderDetailsCalculator, OrderDetailsCalculator>();
}
6. Koble appen til Nets Easy-avtalen
Altinn Studio har ikke innstillinger for dette. Du kobler appen til Nets Easy-avtalen manuelt: Du legger den hemmelige nøkkelen fra Nets i Azure Key Vault og legger til innstillingene i
appsettings.json. Se fanen Manuelt oppsett for dette steget.
Legge til config i appSettings.json
Hent din hemmelige nøkkel fra Nets. Pass på at du bruker testnøkkelen under utvikling.
Gjør appen din klar for bruk av Azure Key Vault som konfigurasjonskilde, hvis du ikke har gjort det allerede. Se Hemmeligheter.
Legg til din hemmelige nøkkel i Key Vault med variabelnavnet
NetsPaymentSettings--SecretApiKey. På denne måten overstyrer denSecretApiKeyiappsettings.json.Legg til
NetsPaymentSettingsi dinappsettings.json.App/appsettings.json{ "NetsPaymentSettings": { "SecretApiKey": "In keyvault", "BaseUrl": "https://test.api.dibspayment.eu/", "TermsUrl": "https://www.yourwebsite.com/terms", "ShowOrderSummary": true, "ShowMerchantName": true, "MerchantHandlesConsumerData": true, "PaymentMethodsConfiguration": [ { "Name": "Visa", "Enabled": true }, { "Name": "MasterCard", "Enabled": true } ] } }- Husk å sette riktig
baseUrliappsettings.Production.json. Eksemplet ovenfor inneholder URL til test-API-et. - Feltet
MerchantHandlesConsumerDataer frivillig og styrer om du skal sende med detaljer om betaleren, eller om det skal fylles ut i Nets Easy sin betalingsside. - PaymentMethodsConfiguration fungerer som beskrevet i Nets sin dokumentasjon her.
- Husk å sette riktig
Du kan gjøre lokal mocking for
SecretApiKeyved hjelp av user secrets.dotnet user-secrets init dotnet user-secrets set "NetsPaymentSettings:SecretApiKey" "test-secret-key-used-for-documentation"
7. Automatisk videreføring etter fullført betaling
Den innebygde Nets Easy-integrasjonen registrerer en webhook når den oppretter en betaling. Når Nets varsler om en fullført betaling, kontrollerer appen betalingsstatusen hos Nets, oppdaterer betalingsinformasjonen og fører betalingsoppgaven videre hvis statusen er Paid. Dette skjer på serveren og er ikke avhengig av at brukeren returnerer til appen etter betalingen.
Appen fullfører betalingsoppgaven automatisk. Hvis neste steg i prosessen er en slutthendelse, blir også instansen fullført. Ellers går instansen videre til neste prosessteg.
For at automatisk videreføring skal fungere:
- Sett opp tilgangene for tjenesteeieren som beskrevet i steg 3.
- Bygg og publiser appen på nytt etter konfigurasjonsendringer.
- Start en ny betaling etter publisering. Appen registrerer webhooken når den oppretter betalingen, så betalinger som ble opprettet før endringen, får ikke den nye callbacken.
Appen registrerer ikke webhooken når du kjører den lokalt. Test derfor denne flyten i et publisert testmiljø.

