Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/v0/configurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,24 @@ export interface BulkUpdateResponse {
metadata?: Record<string, unknown>
}

export type PaymentLinkDefaultUsageMode = 'single_use' | 'multi_use'

export interface PaymentLinksConfigurationSettings {
default_expiry_days?: number
default_usage_mode?: PaymentLinkDefaultUsageMode
}

export interface ConfigurationSettings {
payment_links?: PaymentLinksConfigurationSettings
[key: string]: unknown
}

export interface Configuration {
id?: string
vouchers?: Record<string, unknown>
scan_prefixes?: Array<Record<string, unknown>>
voucher_actions?: Array<Record<string, unknown>>
settings?: Record<string, unknown>
settings?: ConfigurationSettings
hooks?: Array<Record<string, unknown>>
themes?: Record<string, unknown>
name?: string
Expand Down
27 changes: 23 additions & 4 deletions src/v0/payment_links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import {
} from '../errors'

declare type PaymentLinkType = 'items_sale' | 'quick_charge'
declare type PaymentLinkStatus = 'open' | 'expired' | 'closed'
declare type PaymentLinkStatus = 'sent' | 'paid' | 'expired' | 'authorized' | 'cancelled' | 'refunded' | 'failed'
declare type BasketItemType = 'goods' | 'shipment' | 'voucher' | 'digital'
declare type PaymentLinkSolutionType = 'BNPL_INSTORE' | 'LINKPAY'

export interface PaymentLinkDto {
id?: string | null
Expand All @@ -23,6 +24,7 @@ export interface PaymentLinkDto {
linkedOrderId?: string | null
branch?: string | null
branchId?: string | null
branchName?: string | null
businessUnitUnzerId: string
externalInvoiceId?: string
externalOrderId?: string
Expand All @@ -33,12 +35,18 @@ export interface PaymentLinkDto {
currency?: string | null
customer?: PaymentLinkCustomer | null
items?: PaymentLinkItem[] | null
paymentPageId?: string | null
paymentPageUrl?: string | null
createdAt: string | {
start: Date
end: Date
} | null
updatedAt?: string | null
solutionType?: PaymentLinkSolutionType
multiUse?: boolean
expiresAt?: string | Date | null
Comment thread
denis-shtupa-unzer marked this conversation as resolved.
alias?: string | null
orderCount?: number
}

export interface PaymentLinksOptions {
Expand Down Expand Up @@ -95,14 +103,19 @@ export interface CreatePaymentLinkRequest {

export interface PaymentLinkQuery {
branch?: string | null
branchId?: string | null
customerEmail?: string | null
createdBy?: string | null
createdAt?: string | {
start: Date
end: Date
} | null
status?: string | null
status?: PaymentLinkStatus | null
amount?: number | null
paymentLinkDescription?: string | null
linkedOrderId?: string | null
externalOrderId?: string | null
deleted?: boolean | null
}

export interface SendSmsRequest {
Expand All @@ -128,6 +141,12 @@ export interface PaymentLinksResponse {
next?: () => Promise<PaymentLinksResponse>
}

export interface PaymentLinkDetailResponse {
results?: PaymentLinkDto[]
msg?: string
count?: number
}

export interface PaymentPageResponse {
paymentPageUrl: string
id: string
Expand Down Expand Up @@ -308,7 +327,7 @@ export class PaymentLinks extends ThBaseHandler {
}
}

async getById (id: string): Promise<PaymentLinkDto> {
async getById (id: string): Promise<PaymentLinkDetailResponse> {
try {
const base = this.uriHelper.generateBaseUri()
const uri = `${base}/${id}`
Expand All @@ -318,7 +337,7 @@ export class PaymentLinks extends ThBaseHandler {
throw new PaymentLinksGetByIdFailed(undefined, { status: response.status })
}

return response.data as PaymentLinkDto
return response.data as PaymentLinkDetailResponse
} catch (error: any) {
throw new PaymentLinksGetByIdFailed(error.message, { error })
}
Expand Down
134 changes: 134 additions & 0 deletions test/payment_links/get-by-id.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import * as dotenv from 'dotenv'
import axios from 'axios'
import MockAdapter from 'axios-mock-adapter'
import { TillhubClient, v0 } from '../../src/tillhub-js'
dotenv.config()

const user = {
username: 'test@example.com',
password: '12345678',
clientAccount: 'someuuid',
apiKey: '12345678'
}

if (process.env.SYSTEM_TEST) {
user.username = process.env.SYSTEM_TEST_USERNAME ?? user.username
user.password = process.env.SYSTEM_TEST_PASSWORD ?? user.password
user.clientAccount = process.env.SYSTEM_TEST_CLIENT_ACCOUNT_ID ?? user.clientAccount
user.apiKey = process.env.SYSTEM_TEST_API_KEY ?? user.apiKey
}

describe('v0: paymentLinks: can get payment link by id', () => {
const legacyId = '4564'
const paymentLinkId = 'pl-1'
const mock = new MockAdapter(axios)
afterEach(() => {
mock.reset()
})

const paymentLink = {
id: paymentLinkId,
paymentLinkType: 'quick_charge',
businessUnitUnzerId: 'bu-1',
createdBy: 'test@example.com',
createdAt: '2026-08-01T00:00:00.000Z',
solutionType: 'LINKPAY',
multiUse: true,
expiresAt: '2026-09-01T00:00:00.000Z',
alias: 'summer-sale',
orderCount: 3
}

it('returns the extended detail envelope', async () => {
if (process.env.SYSTEM_TEST !== 'true') {
mock.onPost('https://api.tillhub.com/api/v0/users/login').reply(() => {
Comment thread
denis-shtupa-unzer marked this conversation as resolved.
return [
200,
{
token: '',
user: {
id: '123',
legacy_id: legacyId
}
}
]
})

mock.onGet(`https://api.tillhub.com/api/v0/payment-links/${legacyId}/${paymentLinkId}`).reply(() => {
return [
200,
{
msg: 'Success',
count: 1,
results: [paymentLink]
}
]
})
}

const options = {
credentials: {
username: user.username,
password: user.password
},
base: process.env.TILLHUB_BASE
}

const th = new TillhubClient()

th.init(options)
await th.auth.loginUsername({
username: user.username,
password: user.password
})

const paymentLinks = th.paymentLinks()

expect(paymentLinks).toBeInstanceOf(v0.PaymentLinks)

const result = await paymentLinks.getById(paymentLinkId)

expect(result).toEqual(paymentLink)
})

it('rejects on status codes that are not 200', async () => {
if (process.env.SYSTEM_TEST !== 'true') {
mock.onPost('https://api.tillhub.com/api/v0/users/login').reply(() => {
return [
200,
{
token: '',
user: {
id: '123',
legacy_id: legacyId
}
}
]
})

mock.onGet(`https://api.tillhub.com/api/v0/payment-links/${legacyId}/${paymentLinkId}`).reply(() => {
return [404]
})
}

const options = {
credentials: {
username: user.username,
password: user.password
},
base: process.env.TILLHUB_BASE
}

const th = new TillhubClient()

th.init(options)
await th.auth.loginUsername({
username: user.username,
password: user.password
})

await expect(th.paymentLinks().getById(paymentLinkId)).rejects.toMatchObject({
name: 'PaymentLinksGetByIdFailed'
})
})
})