@mia-burton/klarna-node
Version:
A Node.js module for Klarna
150 lines (141 loc) • 5.54 kB
text/typescript
import { ClientInterface } from './client.interface'
import axios, { AxiosInstance } from 'axios'
import { Location, OrderResponse, SessionResponse, OrderInput, Order, UrlsInput, PaymentSession } from './types'
import { CreateOrderError, CreateSessionError, ReadOrderError, ReadSessionError } from './errors'
import { SessionBodyBuilder } from './builders'
import { PaymentSessionMapper } from './mappers'
import { OrderBodyBuilder } from './builders'
import { OrderMapper } from './mappers/order.mapper'
import { Utils } from './utils'
export class Client implements ClientInterface {
private readonly uid: string
private readonly password: string
private readonly live: boolean
private baseUrl: string|undefined
private restClient: AxiosInstance
/**
* Create a Klarna client
* @param uid string - Api key given from Klarna
* @param password string - Password given from Klarna
* @param live boolean - Switch live sandbox env
*/
constructor(uid: string, password: string, location: Location, live: boolean = true) {
this.uid = uid
this.password = password
this.live = live
this.setLocation(location)
this.restClient = this.initAxios()
}
private setLocation(location: Location): void {
switch (location) {
case Location.America:
this.baseUrl = this.live ? 'https://api-na.klarna.com/' : 'https://api-na.playground.klarna.com/'
break;
case Location.Europe:
this.baseUrl = this.live ? 'https://api.klarna.com/' : 'https://api.playground.klarna.com/'
break;
case Location.Oceania:
this.baseUrl = this.live ? 'https://api-oc.klarna.com/' : 'https://api-oc.playground.klarna.com/'
break
default:
throw new Error('Invalid location')
}
this.restClient = this.initAxios()
}
/**
* @param theOrder
* @param urls Insert {session.id} and/or {order.id} as placeholder
* @return Promise<SessionResponse>
* @throws CreateSessionError
*/
public async createPaymentSession(theOrder: OrderInput, urls: UrlsInput): Promise<SessionResponse> {
try {
const bodyBuilder = new SessionBodyBuilder()
const body = bodyBuilder.build(theOrder, urls)
const res = await this.restClient.post('payments/v1/sessions', body)
const session = new SessionResponse(res.data.session_id, res.data.client_token)
return session
} catch(err) {
if (axios.isAxiosError(err)) {
throw new CreateSessionError(err.message, err.response ? err.response.data : {})
}
throw new CreateSessionError((err as Error).message, err as Error)
}
}
public async getPaymentSession(theId: string): Promise<PaymentSession> {
try {
const res = await this.restClient.get(`payments/v1/sessions/${theId}`)
return new PaymentSessionMapper().map(res.data)
} catch(err) {
if (axios.isAxiosError(err)) {
throw new ReadSessionError(err.message, err.response ? err.response.data : {})
}
throw new ReadSessionError((err as Error).message, err as Error)
}
}
/**
* @param theOrder
* @returns Promise<OrderResponse>
* @throws CreateOrderError
*/
public async createOrder(theSessionId: string): Promise<OrderResponse> {
try {
const paymentSesison = await this.getPaymentSession(theSessionId)
if (paymentSesison.status === 'incomplete' && paymentSesison.clientToken && paymentSesison.authorizationToken) {
const bodyBuilder = new OrderBodyBuilder()
const body = bodyBuilder.build(paymentSesison)
const res = await this.restClient.post(`payments/v1/authorizations/${paymentSesison.authorizationToken}/order`, body)
const order = new OrderResponse(res.data.order_id, res.data.fraud_status)
return order
}
throw new CreateOrderError('Session not valid', {})
} catch(err) {
if (axios.isAxiosError(err)) {
throw new CreateOrderError(err.message, err.response ? err.response.data : {})
}
throw new CreateOrderError((err as Error).message, err as Error)
}
}
/**
* @param theId
* @returns {Promise<Order>}
*/
public async getOrder(theId: string): Promise<Order> {
try {
const res = await this.restClient.get(`ordermanagement/v1/orders/${theId}`)
return new OrderMapper().map(res.data)
} catch(err) {
if (axios.isAxiosError(err)) {
throw new ReadOrderError(err.message, err.response ? err.response.data : {})
}
throw new ReadOrderError((err as Error).message, err as Error)
}
}
/**
* Create a capture for the givend order of the given amount
* @param theOrderId
* @param theAmount
* @returns {Promise<string>}
*/
public async captureOrder(theOrderId: string, theAmount: number): Promise<string> {
try {
const res = await this.restClient.post(`ordermanagement/v1/orders/${theOrderId}/captures`, { captured_amount: Utils.formatPrice(theAmount) })
return res.headers['capture-id']
} catch(err) {
if (axios.isAxiosError(err)) {
throw new ReadOrderError(err.message, err.response ? err.response.data : {})
}
throw new ReadOrderError((err as Error).message, err as Error)
}
}
private initAxios(): AxiosInstance {
return axios.create({
baseURL: this.baseUrl,
headers: {
Authorization: `Basic ${Buffer.from(`${this.uid}:${this.password}`).toString('base64')}`,
Accept: 'application/json',
'Content-Type': 'application/json'
}
})
}
}