Skip to content

Commit

Permalink
Update API version, add payment models & tests
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
DarkGL committed Jan 7, 2025
1 parent 8baa687 commit 22184c3
Show file tree
Hide file tree
Showing 18 changed files with 1,743 additions and 128 deletions.
1,309 changes: 1,306 additions & 3 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{
"name": "simpay-typescript-api",
"author": "Rafał Więcek <r.wiecek@simpay.pl> (https://github.com/DarkGL)",
"version": "3.0.3",
"version": "3.1.0",
"description": "SimPay.pl API wrapper",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"scripts": {
"ci": "npm run build && npm run check && npm run check-exports",
"ci": "npm run build && npm run check && npm run check-exports && npm run test",
"lint": "npx @biomejs/biome lint --write ./src",
"format": "npx @biomejs/biome format --write ./src",
"check": "npx @biomejs/biome check --write ./src",
"build": "tsc --build",
"test": "npm run build && node --loader ts-node/esm ./tests/index.ts",
"test": "npm run build && vitest run",
"check-exports": "attw --pack . --ignore-rules=cjs-resolves-to-esm",
"local-release": "changeset version && changeset publish",
"prepublishOnly": "npm run ci"
Expand Down Expand Up @@ -50,7 +50,8 @@
"@changesets/cli": "^2.27.11",
"@types/node": "^22.10.5",
"ts-node": "^10.9.2",
"typescript": "^5.7.2"
"typescript": "^5.7.2",
"vitest": "^2.1.8"
},
"repository": {
"type": "git",
Expand Down
7 changes: 7 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ export type { SmsTransaction } from './models/sms/transaction/sms.transaction.js
export type { VerificationResponse } from './models/sms/verification.response.js';
export { SMSServiceStatus } from './models/sms/service/sms.service.status.js';

// Online Payments - Models
export type { TransactionRequest } from './models/payment/transaction/transaction-request.js';
export type { TransactionNotification } from './models/payment/transaction/transaction-notification.js';
export type { TransactionDetailsResponse } from './models/payment/transaction/transaction-details-response.js';
export type { TransactionStatus } from './models/payment/payment.provider.js';

// Payments
export { DirectBilling } from './payments/directbilling.js';
export { Sms } from './payments/sms.js';
export { SmsXml } from './payments/sms.xml.js';
export { Payment } from './payments/payment.js';
10 changes: 1 addition & 9 deletions src/lib/hashing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,6 @@ function sha256(text: string) {
return hash('sha256', text);
}

function sha1(text: string) {
return hash('sha1', text);
}

function md5(text: string) {
return hash('md5', text);
}

function hash(algorithm: string, text: string) {
const hash = createHash(algorithm);

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

export { sha256, sha1, md5 };
export { sha256 };
31 changes: 31 additions & 0 deletions src/models/directbilling/service/service-paginated.response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { DBServiceStatus } from './db.service.status.js';

interface DirectBillingServicePaginatedResponse {
success: boolean;
data: Datum[];
pagination: Pagination;
}

interface Datum {
id: string;
name: string;
suffix: string;
status: DBServiceStatus;
created_at: Date;
}

interface Pagination {
total: number;
count: number;
per_page: number;
current_page: number;
total_pages: number;
links: Links;
}

interface Links {
next_page: null;
prev_page: null;
}

export type { DirectBillingServicePaginatedResponse };
12 changes: 12 additions & 0 deletions src/models/payment/payment.provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
enum TransactionStatus {
NEW = 'transaction_new',
CONFIRMED = 'transaction_confirmed',
GENERATED = 'transaction_generated',
PAID = 'transaction_paid',
FAILED = 'transaction_failed',
EXPIRED = 'transaction_expired',
CANCELED = 'transaction_canceled',
REFUNDED = 'transaction_refunded',
}

export type { TransactionStatus };
51 changes: 51 additions & 0 deletions src/models/payment/transaction/transaction-details-response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
export interface TransactionDetailsResponse {
success: boolean;
data: Data;
}

export interface Data {
id: string;
status: string;
amount: Amount;
channel: string;
control: string;
description: string;
redirects: Redirects;
customer: Customer;
billing: Ing;
shipping: Ing;
cart: null;
paid_at: Date;
expires_at: string;
created_at: string;
updated_at: Date;
}

export interface Amount {
value: number;
currency: string;
commission: number;
}

export interface Ing {
name: string;
surname: string;
street: string;
building: string;
flat: string;
city: string;
region: string;
postalCode: string;
country: string;
company: string;
}

export interface Customer {
name: string;
email: string;
}

export interface Redirects {
success: string;
failure: string;
}
21 changes: 21 additions & 0 deletions src/models/payment/transaction/transaction-notification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
interface TransactionNotification {
id: string;
service_id: string;
status: string;
amount: {
value: number;
currency: string;
commission: number;
};
control: string;
channel: string;
environment: string;
originalAmount: {
value: number;
currency: string;
rate: number;
};
signature: string;
}

export type { TransactionNotification };
22 changes: 22 additions & 0 deletions src/models/payment/transaction/transaction-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
interface TransactionRequest {
amount: number;
currency?: string;
description?: string;
control?: string;
customer?: object;
antifraud?: object;
billing?: object;
shipping?: object;
cart?: object[];
returns?: {
success: string;
failure: string;
};
directChannel?: string;
channels?: string[];
channelTypes?: object;
referer?: string;
signature?: string;
}

export type { TransactionRequest };
17 changes: 9 additions & 8 deletions src/payments/directbilling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { sha256 } from '../lib/hashing.js';
import type { DbCalculation } from '../models/directbilling/service/db.calculation.js';
import type { DbService } from '../models/directbilling/service/db.service.js';
import type { PartialDbService } from '../models/directbilling/service/partial.db.service.js';
import type { DirectBillingServicePaginatedResponse } from '../models/directbilling/service/service-paginated.response.js';
import type { DbGenerationResponse } from '../models/directbilling/transaction/db.generation.response.js';
import type { DbNotificationRequest } from '../models/directbilling/transaction/db.notifications.request.js';
import type { DbTransaction } from '../models/directbilling/transaction/db.transaction.js';
Expand All @@ -25,7 +26,7 @@ export class DirectBilling {
headers: {
'X-SIM-KEY': this.key,
'X-SIM-PASSWORD': this.password,
'X-SIM-VERSION': '3.0.3',
'X-SIM-VERSION': '3.1.0',
'X-SIM-PLATFORM': 'TYPESCRIPT',
},
});
Expand Down Expand Up @@ -60,17 +61,17 @@ export class DirectBilling {
page?: number,
pageSize?: number,
): Promise<PaginatedResponse<PartialDbService>> {
const query: any = {};
const query: Record<string, string> = {};

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

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

const response = (await this.client.get(url)).data;
const response = (await this.client.get<DirectBillingServicePaginatedResponse>(url)).data;

response.data = response.data.map((e: any) => {
e.created_at = new Date(e.created_at.replace(' ', 'T'));
response.data = response.data.map((e) => {
e.created_at = new Date(e.created_at.toString().replace(' ', 'T'));

return e;
});
Expand Down Expand Up @@ -134,7 +135,7 @@ export class DirectBilling {
page?: number,
pageSize?: number,
): Promise<PaginatedResponse<PartialDbTransaction>> {
const query: any = {};
const query: Record<string, string> = {};

if (page) query.page = `${page}`;
if (pageSize) query.limit = `${pageSize}`;
Expand Down Expand Up @@ -185,12 +186,12 @@ export class DirectBilling {
/*
https://docs.simpay.pl/shell/?shell#directbilling-generowanie-transakcji
*/
checkNotification(key: string, body: any) {
checkNotification(key: string, body: DbNotificationRequest) {
const signature = this.generateSignatureNotification(key, body);

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

return <DbNotificationRequest>body;
return body as DbNotificationRequest;
}

/*
Expand Down
70 changes: 70 additions & 0 deletions src/payments/payment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import axios, { type AxiosInstance } from 'axios';
import { sha256 } from '../lib/hashing.js';
import type { TransactionNotification } from '../models/payment/transaction/transaction-notification.js';
import type { TransactionRequest } from '../models/payment/transaction/transaction-request.js';

export { Payment };

class Payment {
private readonly client: AxiosInstance;

constructor(
private readonly key: string,
private readonly password: string,
) {
this.client = axios.create({
baseURL: 'https://api.simpay.pl/payment',
headers: {
Authorization: `Bearer ${this.key}`,
},
});
}

// Generating transaction
// https://docs.simpay.pl/#tag/Payment/operation/paymentTransactionCreate
public async createTransaction(serviceId: string, request: TransactionRequest): Promise<any> {
try {
const response = await this.client.post(`/${serviceId}/transactions`, request);
return response.data;
} catch (error) {
console.error('Error creating transaction:', error);
throw error;
}
}

// Receive transaction details (Webhook)
// https://docs.simpay.pl/#tag/Payment/operation/paymentTransactionNotification
public verifyNotification(key: string, body: TransactionNotification): boolean {
const generatedSignature = this.generateSignatureNotification(key, body);
return body.signature === generatedSignature;
}

// Generate signature for webhook
private generateSignatureNotification(key: string, request: TransactionNotification): string {
const joinedElements = [
request.id,
request.service_id,
request.status,
request.amount.value,
request.amount.currency,
request.amount.commission,
request.control,
request.channel,
request.environment,
request.originalAmount.value,
request.originalAmount.currency,
request.originalAmount.rate,
key,
]
.filter((e) => e !== undefined && e !== null)
.join('|');

return sha256(joinedElements);
}

// Get transaction details
// https://docs.simpay.pl/#tag/Payment/operation/paymentGetTransaction
public getTransactionDetails(serviceId: string, transactionId: string): Promise<any> {
return this.client.get(`/${serviceId}/transactions/${transactionId}`);
}
}
10 changes: 5 additions & 5 deletions src/payments/sms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class Sms {
headers: {
'X-SIM-KEY': this.key,
'X-SIM-PASSWORD': this.password,
'X-SIM-VERSION': '3.0.3',
'X-SIM-VERSION': '3.1.0',
'X-SIM-PLATFORM': 'TYPESCRIPT',
},
});
Expand Down Expand Up @@ -52,7 +52,7 @@ export class Sms {
page?: number,
pageSize?: number,
): Promise<PaginatedResponse<SmsService>> {
const query: any = {};
const query: Record<string, string> = {};

if (page) query.page = `${page}`;
if (pageSize) query.limit = `${pageSize}`;
Expand Down Expand Up @@ -111,7 +111,7 @@ export class Sms {
page?: number,
pageSize?: number,
): Promise<PaginatedResponse<SmsTransaction>> {
const query: any = {};
const query: Record<string, string> = {};

if (page) query.page = `${page}`;
if (pageSize) query.limit = `${pageSize}`;
Expand Down Expand Up @@ -170,7 +170,7 @@ export class Sms {
page?: number,
pageSize?: number,
): Promise<PaginatedResponse<SmsNumber>> {
const query: any = {};
const query: Record<string, string> = {};

if (page) query.page = `${page}`;
if (pageSize) query.limit = `${pageSize}`;
Expand Down Expand Up @@ -212,7 +212,7 @@ export class Sms {
page?: number,
pageSize?: number,
): Promise<PaginatedResponse<SmsNumber>> {
const query: any = {};
const query: Record<string, string> = {};

if (page) query.page = `${page}`;
if (pageSize) query.limit = `${pageSize}`;
Expand Down
Loading

0 comments on commit 22184c3

Please sign in to comment.