Skip to content

Commit 22184c3

Browse files
committed
Update API version, add payment models & tests
- Bump version to 3.1.0 - Add new online payment models and types - Introduce `Payment` class for handling transactions - Replace `ts-node` with `vitest` for testing - Remove unused hashing functions (sha1, md5) - Refactor query parameter handling in services - Add paginated response type for direct billing service - Implement unit tests using `vitest` - Delete old test scripts
1 parent 8baa687 commit 22184c3

18 files changed

+1743
-128
lines changed

package-lock.json

+1,306-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
{
22
"name": "simpay-typescript-api",
33
"author": "Rafał Więcek <r.wiecek@simpay.pl> (https://github.com/DarkGL)",
4-
"version": "3.0.3",
4+
"version": "3.1.0",
55
"description": "SimPay.pl API wrapper",
66
"main": "dist/index.js",
77
"types": "dist/index.d.ts",
88
"type": "module",
99
"scripts": {
10-
"ci": "npm run build && npm run check && npm run check-exports",
10+
"ci": "npm run build && npm run check && npm run check-exports && npm run test",
1111
"lint": "npx @biomejs/biome lint --write ./src",
1212
"format": "npx @biomejs/biome format --write ./src",
1313
"check": "npx @biomejs/biome check --write ./src",
1414
"build": "tsc --build",
15-
"test": "npm run build && node --loader ts-node/esm ./tests/index.ts",
15+
"test": "npm run build && vitest run",
1616
"check-exports": "attw --pack . --ignore-rules=cjs-resolves-to-esm",
1717
"local-release": "changeset version && changeset publish",
1818
"prepublishOnly": "npm run ci"
@@ -50,7 +50,8 @@
5050
"@changesets/cli": "^2.27.11",
5151
"@types/node": "^22.10.5",
5252
"ts-node": "^10.9.2",
53-
"typescript": "^5.7.2"
53+
"typescript": "^5.7.2",
54+
"vitest": "^2.1.8"
5455
},
5556
"repository": {
5657
"type": "git",

src/index.ts

+7
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,14 @@ export type { SmsTransaction } from './models/sms/transaction/sms.transaction.js
2222
export type { VerificationResponse } from './models/sms/verification.response.js';
2323
export { SMSServiceStatus } from './models/sms/service/sms.service.status.js';
2424

25+
// Online Payments - Models
26+
export type { TransactionRequest } from './models/payment/transaction/transaction-request.js';
27+
export type { TransactionNotification } from './models/payment/transaction/transaction-notification.js';
28+
export type { TransactionDetailsResponse } from './models/payment/transaction/transaction-details-response.js';
29+
export type { TransactionStatus } from './models/payment/payment.provider.js';
30+
2531
// Payments
2632
export { DirectBilling } from './payments/directbilling.js';
2733
export { Sms } from './payments/sms.js';
2834
export { SmsXml } from './payments/sms.xml.js';
35+
export { Payment } from './payments/payment.js';

src/lib/hashing.ts

+1-9
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,6 @@ function sha256(text: string) {
44
return hash('sha256', text);
55
}
66

7-
function sha1(text: string) {
8-
return hash('sha1', text);
9-
}
10-
11-
function md5(text: string) {
12-
return hash('md5', text);
13-
}
14-
157
function hash(algorithm: string, text: string) {
168
const hash = createHash(algorithm);
179

@@ -20,4 +12,4 @@ function hash(algorithm: string, text: string) {
2012
return hash.digest('hex');
2113
}
2214

23-
export { sha256, sha1, md5 };
15+
export { sha256 };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { DBServiceStatus } from './db.service.status.js';
2+
3+
interface DirectBillingServicePaginatedResponse {
4+
success: boolean;
5+
data: Datum[];
6+
pagination: Pagination;
7+
}
8+
9+
interface Datum {
10+
id: string;
11+
name: string;
12+
suffix: string;
13+
status: DBServiceStatus;
14+
created_at: Date;
15+
}
16+
17+
interface Pagination {
18+
total: number;
19+
count: number;
20+
per_page: number;
21+
current_page: number;
22+
total_pages: number;
23+
links: Links;
24+
}
25+
26+
interface Links {
27+
next_page: null;
28+
prev_page: null;
29+
}
30+
31+
export type { DirectBillingServicePaginatedResponse };
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
enum TransactionStatus {
2+
NEW = 'transaction_new',
3+
CONFIRMED = 'transaction_confirmed',
4+
GENERATED = 'transaction_generated',
5+
PAID = 'transaction_paid',
6+
FAILED = 'transaction_failed',
7+
EXPIRED = 'transaction_expired',
8+
CANCELED = 'transaction_canceled',
9+
REFUNDED = 'transaction_refunded',
10+
}
11+
12+
export type { TransactionStatus };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
export interface TransactionDetailsResponse {
2+
success: boolean;
3+
data: Data;
4+
}
5+
6+
export interface Data {
7+
id: string;
8+
status: string;
9+
amount: Amount;
10+
channel: string;
11+
control: string;
12+
description: string;
13+
redirects: Redirects;
14+
customer: Customer;
15+
billing: Ing;
16+
shipping: Ing;
17+
cart: null;
18+
paid_at: Date;
19+
expires_at: string;
20+
created_at: string;
21+
updated_at: Date;
22+
}
23+
24+
export interface Amount {
25+
value: number;
26+
currency: string;
27+
commission: number;
28+
}
29+
30+
export interface Ing {
31+
name: string;
32+
surname: string;
33+
street: string;
34+
building: string;
35+
flat: string;
36+
city: string;
37+
region: string;
38+
postalCode: string;
39+
country: string;
40+
company: string;
41+
}
42+
43+
export interface Customer {
44+
name: string;
45+
email: string;
46+
}
47+
48+
export interface Redirects {
49+
success: string;
50+
failure: string;
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
interface TransactionNotification {
2+
id: string;
3+
service_id: string;
4+
status: string;
5+
amount: {
6+
value: number;
7+
currency: string;
8+
commission: number;
9+
};
10+
control: string;
11+
channel: string;
12+
environment: string;
13+
originalAmount: {
14+
value: number;
15+
currency: string;
16+
rate: number;
17+
};
18+
signature: string;
19+
}
20+
21+
export type { TransactionNotification };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
interface TransactionRequest {
2+
amount: number;
3+
currency?: string;
4+
description?: string;
5+
control?: string;
6+
customer?: object;
7+
antifraud?: object;
8+
billing?: object;
9+
shipping?: object;
10+
cart?: object[];
11+
returns?: {
12+
success: string;
13+
failure: string;
14+
};
15+
directChannel?: string;
16+
channels?: string[];
17+
channelTypes?: object;
18+
referer?: string;
19+
signature?: string;
20+
}
21+
22+
export type { TransactionRequest };

src/payments/directbilling.ts

+9-8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { sha256 } from '../lib/hashing.js';
33
import type { DbCalculation } from '../models/directbilling/service/db.calculation.js';
44
import type { DbService } from '../models/directbilling/service/db.service.js';
55
import type { PartialDbService } from '../models/directbilling/service/partial.db.service.js';
6+
import type { DirectBillingServicePaginatedResponse } from '../models/directbilling/service/service-paginated.response.js';
67
import type { DbGenerationResponse } from '../models/directbilling/transaction/db.generation.response.js';
78
import type { DbNotificationRequest } from '../models/directbilling/transaction/db.notifications.request.js';
89
import type { DbTransaction } from '../models/directbilling/transaction/db.transaction.js';
@@ -25,7 +26,7 @@ export class DirectBilling {
2526
headers: {
2627
'X-SIM-KEY': this.key,
2728
'X-SIM-PASSWORD': this.password,
28-
'X-SIM-VERSION': '3.0.3',
29+
'X-SIM-VERSION': '3.1.0',
2930
'X-SIM-PLATFORM': 'TYPESCRIPT',
3031
},
3132
});
@@ -60,17 +61,17 @@ export class DirectBilling {
6061
page?: number,
6162
pageSize?: number,
6263
): Promise<PaginatedResponse<PartialDbService>> {
63-
const query: any = {};
64+
const query: Record<string, string> = {};
6465

6566
if (page) query.page = `${page}`;
6667
if (pageSize) query.limit = `${pageSize}`;
6768

6869
const url = `/?${new URLSearchParams(query).toString()}`;
6970

70-
const response = (await this.client.get(url)).data;
71+
const response = (await this.client.get<DirectBillingServicePaginatedResponse>(url)).data;
7172

72-
response.data = response.data.map((e: any) => {
73-
e.created_at = new Date(e.created_at.replace(' ', 'T'));
73+
response.data = response.data.map((e) => {
74+
e.created_at = new Date(e.created_at.toString().replace(' ', 'T'));
7475

7576
return e;
7677
});
@@ -134,7 +135,7 @@ export class DirectBilling {
134135
page?: number,
135136
pageSize?: number,
136137
): Promise<PaginatedResponse<PartialDbTransaction>> {
137-
const query: any = {};
138+
const query: Record<string, string> = {};
138139

139140
if (page) query.page = `${page}`;
140141
if (pageSize) query.limit = `${pageSize}`;
@@ -185,12 +186,12 @@ export class DirectBilling {
185186
/*
186187
https://docs.simpay.pl/shell/?shell#directbilling-generowanie-transakcji
187188
*/
188-
checkNotification(key: string, body: any) {
189+
checkNotification(key: string, body: DbNotificationRequest) {
189190
const signature = this.generateSignatureNotification(key, body);
190191

191192
if (body.signature !== signature) return undefined;
192193

193-
return <DbNotificationRequest>body;
194+
return body as DbNotificationRequest;
194195
}
195196

196197
/*

src/payments/payment.ts

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import axios, { type AxiosInstance } from 'axios';
2+
import { sha256 } from '../lib/hashing.js';
3+
import type { TransactionNotification } from '../models/payment/transaction/transaction-notification.js';
4+
import type { TransactionRequest } from '../models/payment/transaction/transaction-request.js';
5+
6+
export { Payment };
7+
8+
class Payment {
9+
private readonly client: AxiosInstance;
10+
11+
constructor(
12+
private readonly key: string,
13+
private readonly password: string,
14+
) {
15+
this.client = axios.create({
16+
baseURL: 'https://api.simpay.pl/payment',
17+
headers: {
18+
Authorization: `Bearer ${this.key}`,
19+
},
20+
});
21+
}
22+
23+
// Generating transaction
24+
// https://docs.simpay.pl/#tag/Payment/operation/paymentTransactionCreate
25+
public async createTransaction(serviceId: string, request: TransactionRequest): Promise<any> {
26+
try {
27+
const response = await this.client.post(`/${serviceId}/transactions`, request);
28+
return response.data;
29+
} catch (error) {
30+
console.error('Error creating transaction:', error);
31+
throw error;
32+
}
33+
}
34+
35+
// Receive transaction details (Webhook)
36+
// https://docs.simpay.pl/#tag/Payment/operation/paymentTransactionNotification
37+
public verifyNotification(key: string, body: TransactionNotification): boolean {
38+
const generatedSignature = this.generateSignatureNotification(key, body);
39+
return body.signature === generatedSignature;
40+
}
41+
42+
// Generate signature for webhook
43+
private generateSignatureNotification(key: string, request: TransactionNotification): string {
44+
const joinedElements = [
45+
request.id,
46+
request.service_id,
47+
request.status,
48+
request.amount.value,
49+
request.amount.currency,
50+
request.amount.commission,
51+
request.control,
52+
request.channel,
53+
request.environment,
54+
request.originalAmount.value,
55+
request.originalAmount.currency,
56+
request.originalAmount.rate,
57+
key,
58+
]
59+
.filter((e) => e !== undefined && e !== null)
60+
.join('|');
61+
62+
return sha256(joinedElements);
63+
}
64+
65+
// Get transaction details
66+
// https://docs.simpay.pl/#tag/Payment/operation/paymentGetTransaction
67+
public getTransactionDetails(serviceId: string, transactionId: string): Promise<any> {
68+
return this.client.get(`/${serviceId}/transactions/${transactionId}`);
69+
}
70+
}

src/payments/sms.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class Sms {
1717
headers: {
1818
'X-SIM-KEY': this.key,
1919
'X-SIM-PASSWORD': this.password,
20-
'X-SIM-VERSION': '3.0.3',
20+
'X-SIM-VERSION': '3.1.0',
2121
'X-SIM-PLATFORM': 'TYPESCRIPT',
2222
},
2323
});
@@ -52,7 +52,7 @@ export class Sms {
5252
page?: number,
5353
pageSize?: number,
5454
): Promise<PaginatedResponse<SmsService>> {
55-
const query: any = {};
55+
const query: Record<string, string> = {};
5656

5757
if (page) query.page = `${page}`;
5858
if (pageSize) query.limit = `${pageSize}`;
@@ -111,7 +111,7 @@ export class Sms {
111111
page?: number,
112112
pageSize?: number,
113113
): Promise<PaginatedResponse<SmsTransaction>> {
114-
const query: any = {};
114+
const query: Record<string, string> = {};
115115

116116
if (page) query.page = `${page}`;
117117
if (pageSize) query.limit = `${pageSize}`;
@@ -170,7 +170,7 @@ export class Sms {
170170
page?: number,
171171
pageSize?: number,
172172
): Promise<PaginatedResponse<SmsNumber>> {
173-
const query: any = {};
173+
const query: Record<string, string> = {};
174174

175175
if (page) query.page = `${page}`;
176176
if (pageSize) query.limit = `${pageSize}`;
@@ -212,7 +212,7 @@ export class Sms {
212212
page?: number,
213213
pageSize?: number,
214214
): Promise<PaginatedResponse<SmsNumber>> {
215-
const query: any = {};
215+
const query: Record<string, string> = {};
216216

217217
if (page) query.page = `${page}`;
218218
if (pageSize) query.limit = `${pageSize}`;

0 commit comments

Comments
 (0)