Коммит 06465863 создал по автору kravetsone's avatar kravetsone
Просмотр файлов

1.0.4: change events. add examples. and many other

владелец ff423dba
node_modules
dist
\ Нет новой строки в конце файла
node_modules
\ Нет новой строки в конце файла
......@@ -2,14 +2,24 @@
> NODE JS модуль, который позволит принимать оплату с помощью платёжного агрегатора [payok.io](https://payok.io/)
<center>
<img src="logo.png" alt="PAYOK" />
</center>
[![Downloads](https://img.shields.io/npm/dt/payok.svg)](https://npmjs.com/package/payok)
[![last commit](https://img.shields.io/github/last-commit/kravetsone/payok.svg)](https://github.com/kravetsone/payok)
[![GitHub](https://img.shields.io/github/stars/kravetsone/payok.svg)](https://github.com/kravetsone/payok)
[![npm](https://img.shields.io/npm/v/payok.svg)](https://npmjs.com/package/payok)
<div align='center'>
<img src="assets/logo.png" alt="PAYOK" />
</div>
<div align='center'>
<a href='https://github.com/kravetsone/payok/tree/main/examples'><b>examples</b></a>
<span>&nbsp;&nbsp;</span>
<a href='#changelog'><b>changelog</b></a>
</div>
<br>
<div align='center'>
<img src="https://img.shields.io/npm/dt/payok.svg" alt="Downloads" href="https://npmjs.com/package/payok" />
<img src="https://img.shields.io/npm/dm/payok.svg" alt="Downloads/month" href="https://npmjs.com/package/payok" />
<img src="https://img.shields.io/github/last-commit/kravetsone/payok.svg" alt="last commit" href="https://github.com/kravetsone/payok" />
<img src="https://img.shields.io/github/stars/kravetsone/payok.svg" alt="GitHub" href="https://github.com/kravetsone/payok" />
<img src="https://img.shields.io/npm/v/payok.svg" alt="npm" href="https://npmjs.com/package/payok" />
</div>
## 📦 Установка
......@@ -50,17 +60,15 @@ const payok = new PAYOK({
---
```js
payok
const link = payok
.getPaymentLink({
amount: 10,
desc: "Описание вашего товара",
success_url: `https://github.com/kravetsone/payok`,
email: "email@gmail.ru",
id: 123456,
})
.then((bill) => {
console.log(bill); // { payUrl: "https://payok.io/pay?...", paymentId: "98dd5-51e1-a0644"}
custom: {id: 123456},
});
console.log(link); // { payUrl: "https://payok.io/pay?...", paymentId: "98dd5-51e1-a0644"}
```
| Параметр | Тип | Описание | Обязательный |
......@@ -71,7 +79,7 @@ payok
| email | string | Email пользователя | - |
| method | string | [Способ оплаты](https://payok.io/cabinet/documentation/doc_methods.php) | - |
| lang | string | Язык интерфейса (`RU`/`ENG`) | - |
| \* | any | Любой ваш параметр, который придёт к вам на вебхук в случае оплаты | - |
| custom.\* | any | Любой ваш параметр, который придёт к вам на вебхук в случае оплаты | - |
## ⚙ [Создание вебхука (обработчик успешной оплаты)](https://payok.io/cabinet/documentation/doc_sendback.php)
......@@ -80,29 +88,33 @@ payok
> 🚧 Параметр sign, приходящий вместе с платежём, уже проверен библиотекой, так что с ним вам взаимодействовать не потребуется.
```js
payok.createWebhook(3000, (payment) => {
console.log(payment);
/*{
payment_id: '51387-77a3-d3724',
shop: '2000',
amount: '10',
profit: '10',
desc: 'Описание вашего товара',
currency: 'RUB',
currency_amount: '10.69',
sign: 'b7453a35683171d235dfb13a16b61f41',
email: 'email@gmail.ru',
date: '11.06.2022 12:13:15',
method: 'Qiwi',
custom: { id: '123456' }
}*/
// Запускаем сам веб-сервер
payok.createWebhook(3000, "/amazing-secret-url-path");
// Слушаем обработанное событие пополнения
payok.events.on("payment", (payment) => {
console.log(payment);
/*{
payment_id: '51387-77a3-d3724',
shop: '2000',
amount: '10',
profit: '10',
desc: 'Описание вашего товара',
currency: 'RUB',
currency_amount: '10.69',
sign: 'b7453a35683171d235dfb13a16b61f41',
email: 'email@gmail.ru',
date: '11.06.2022 12:13:15',
method: 'Qiwi',
custom: { id: '123456' }
}*/
});
});
```
| Параметр | Тип | Описание | Обязательный |
| -------- | -------- | ------------------------------------------------ | ------------ |
| port | number | Порт на котором вы хотите раскрыть вебхук | + |
| handler | function | Функция, которая выполниться при успешной оплате | + |
| path | string | Путь по которому будет доступен вебхук | - |
### 💰 [Получение баланса](https://payok.io/cabinet/documentation/doc_api_balance)
......@@ -121,7 +133,7 @@ payok.api.getBalance().then((res) => {
---
```js
payok.api.getTransaction({ offset: 1 }).then((res) => {
payok.api.getTransactions({ offset: 1 }).then((res) => {
console.log(res);
/*{
{
......@@ -235,6 +247,8 @@ payok.api
## Changelog:
**1.0.4** - Breaking Change. Поменяли систему событий. Добавили примеры и множество более скромных деяних. [Подробнее](https://github.com/kravetsone/payok/releases/tag/payok%401.0.4)
**1.0.3** - Поддержка `TypeScript`. Рефакторинг кода. Мелкие изменения в `Readme`. Зависимость `node-fetch` заменена на `axios`.
**1.0.2** - Исправлены проблемы с API запросами (был неверно передан `Content-Type`). Убраны лишние зависимости (7 => 3)
......
import { Axios } from "axios";
import { ICreatePayout, IGetPayout, IGetTransaction } from "./types";
export declare class API {
apiId: number;
apiKey: string;
secretKey: string;
shop: number;
request: Axios;
constructor(params: {
apiId: number;
apiKey: string;
secretKey: string;
shop: number;
});
/**
* [Получение баланса аккаунта.](https://payok.io/cabinet/documentation/doc_api_balance)
*
*/
getBalance(): Promise<any>;
/**
* [Получение списка транзакций.](https://payok.io/cabinet/documentation/doc_api_transaction)
* @param {number} params.payment ID платежа в вашей системе.
* @param {number} params.offset Отступ, пропуск указанного количества строк.
*/
getTransactions(params: IGetTransaction): Promise<any>;
/**
* [Получение списка транзакций.](https://payok.io/cabinet/documentation/doc_api_payout)
* @param {number} params.payment_id ID выплаты в системе Payok.
* @param {number} params.offset Отступ, пропуск указанного количества строк.
*/
getPayouts(params: IGetPayout): Promise<any>;
/**
* [Создание выплаты.](https://payok.io/cabinet/documentation/doc_api_payout_create)
* @param {number} params.amount Сумма выплаты. Обязателен.
* @param {string} params.method [Способ оплаты.](https://payok.io/cabinet/documentation/doc_methods.php) Обязателен.
* @param {string} params.reciever Реквезиты на которые придёт выплата. Обязателен.
* @param {string} params.comission_type Комиссия с баланса - `balance`, а если с выплаты - `payment`. Обязателен.
* @param {number} params.webhook_url URL вебхука для отправки статуса выплаты.
*/
createPayout(params: ICreatePayout): Promise<any>;
}
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.API = void 0;
const axios_1 = require("axios");
const qs_1 = require("qs");
class API {
constructor(params) {
this.apiId = params.apiId;
this.apiKey = params.apiKey;
this.secretKey = params.secretKey;
this.shop = params.shop;
this.request = new axios_1.Axios({
baseURL: "https://payok.io/api",
headers: {
"User-Agent": "kravetsone/payok",
"Content-type": "application/x-www-form-urlencoded",
Accept: "application/json",
},
transformRequest: [function (data, headers) {
return (0, qs_1.stringify)(Object.assign({
API_ID: params.apiId,
API_KEY: params.apiKey,
shop: params.shop,
}, Object.assign({}, data || {})));
}],
});
this.request.interceptors.response.use((response) => {
if (response.data.status == "error")
return Promise.reject(response.data);
return response;
});
}
/**
* [Получение баланса аккаунта.](https://payok.io/cabinet/documentation/doc_api_balance)
*
*/
getBalance() {
return __awaiter(this, void 0, void 0, function* () {
return this.request.post("/balance").then(response => response.data);
});
}
/**
* [Получение списка транзакций.](https://payok.io/cabinet/documentation/doc_api_transaction)
* @param {number} params.payment ID платежа в вашей системе.
* @param {number} params.offset Отступ, пропуск указанного количества строк.
*/
getTransactions(params) {
return __awaiter(this, void 0, void 0, function* () {
return this.request.post("/transaction", params).then(response => response.data);
});
}
/**
* [Получение списка транзакций.](https://payok.io/cabinet/documentation/doc_api_payout)
* @param {number} params.payment_id ID выплаты в системе Payok.
* @param {number} params.offset Отступ, пропуск указанного количества строк.
*/
getPayouts(params) {
return __awaiter(this, void 0, void 0, function* () {
return this.request.post("/payout", params).then(response => response.data);
});
}
/**
* [Создание выплаты.](https://payok.io/cabinet/documentation/doc_api_payout_create)
* @param {number} params.amount Сумма выплаты. Обязателен.
* @param {string} params.method [Способ оплаты.](https://payok.io/cabinet/documentation/doc_methods.php) Обязателен.
* @param {string} params.reciever Реквезиты на которые придёт выплата. Обязателен.
* @param {string} params.comission_type Комиссия с баланса - `balance`, а если с выплаты - `payment`. Обязателен.
* @param {number} params.webhook_url URL вебхука для отправки статуса выплаты.
*/
createPayout(params) {
return __awaiter(this, void 0, void 0, function* () {
return this.request.post("/payout_create", params).then(response => response.data);
});
}
}
exports.API = API;
/// <reference types="node" />
import { IGetPaymentLink } from "./types";
import { API } from "./api";
import EventEmitter from "events";
declare class Emitter extends EventEmitter {
}
export declare class PAYOK {
apiId: number;
apiKey: string;
secretKey: string;
shop: number;
cache: Map<any, any>;
api: API;
events: Emitter;
/**
*
* @param {number} params.apiId Идентификатор вашего API ключа.
* @param {number} params.apiKey Ваш API ключ.
* @param {string} params.secretKey Секретный ключ. Используется для создания и проверки поддписи.
* @param {number} params.shop Идентификатор вашего проекта.
*
*/
constructor(params: {
apiId: number;
apiKey: string;
secretKey: string;
shop: number;
});
generateSignature(params: any, type?: "paymentLink"): string;
/**
* Создание ссылки на форму оплаты
* @param {float} params.amount Сумма заказа. Обязателен.
* @param {string} params.desc Название или описание товара. Обязателен.
* @param {any} params.custom.* Ваш параметр, который вы хотите передать в уведомлении (любое количество).
* @param {string} params.payment Номер заказа, уникальный в вашей системе (если не укажите, то он заполнится автоматически), до 16 символов. (a-z0-9-_)
* @param {string} params.currency Валюта (RUB - Рубли, UAH - Гривны, USD - Доллары, EUR - Евро, RUB2 - Рубли, но альтернативный шлюз). По умолчанию RUB.
* @param {string} params.email Электронна почта покупателя.
* @param {string} params.success_url Ссылка для переадресации после оплаты.
* @param {string} params.method Способ оплаты
* @param {string} params.lang Язык интерфейса. RU или EN (Если не указан, берется язык браузера)
*
*
*/
getPaymentLink(params: IGetPaymentLink): {
payUrl: string;
paymentId: string;
};
/**
* Раскрытие сервера (вебхука) и принятие платежей.
* @param {number} port Порт, на котором создать вебхук. Обязателен
* @param {string} path Путь, на котором будет доступен вебхук.
*/
createWebhook(port: number, path?: string): Promise<string>;
}
export * from "./types";
export declare function generateUUID(): string;
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateUUID = exports.PAYOK = void 0;
const fastify_1 = __importDefault(require("fastify"));
const fastify = (0, fastify_1.default)();
const crypto_1 = require("crypto");
const qs_1 = require("qs");
const api_1 = require("./api");
const events_1 = __importDefault(require("events"));
class Emitter extends events_1.default {
}
;
class PAYOK {
/**
*
* @param {number} params.apiId Идентификатор вашего API ключа.
* @param {number} params.apiKey Ваш API ключ.
* @param {string} params.secretKey Секретный ключ. Используется для создания и проверки поддписи.
* @param {number} params.shop Идентификатор вашего проекта.
*
*/
constructor(params) {
this.apiId = params.apiId;
this.apiKey = params.apiKey;
this.secretKey = params.secretKey;
this.shop = params.shop;
this.events = new Emitter();
this.cache = new Map();
this.api = new api_1.API(params);
}
generateSignature(params, type) {
return type == "paymentLink"
? (0, crypto_1.createHash)("md5")
.update(`${params.amount}|${params.payment}|${this.shop}|${params.currency || "RUB"}|${params.desc}|${this.secretKey}`)
.digest("hex")
: (0, crypto_1.createHash)("md5")
.update(`${this.secretKey}|${params.desc}|${params.currency || "RUB"}|${this.shop}|${params.payment_id}|${params.amount}`)
.digest("hex");
}
/**
* Создание ссылки на форму оплаты
* @param {float} params.amount Сумма заказа. Обязателен.
* @param {string} params.desc Название или описание товара. Обязателен.
* @param {any} params.custom.* Ваш параметр, который вы хотите передать в уведомлении (любое количество).
* @param {string} params.payment Номер заказа, уникальный в вашей системе (если не укажите, то он заполнится автоматически), до 16 символов. (a-z0-9-_)
* @param {string} params.currency Валюта (RUB - Рубли, UAH - Гривны, USD - Доллары, EUR - Евро, RUB2 - Рубли, но альтернативный шлюз). По умолчанию RUB.
* @param {string} params.email Электронна почта покупателя.
* @param {string} params.success_url Ссылка для переадресации после оплаты.
* @param {string} params.method Способ оплаты
* @param {string} params.lang Язык интерфейса. RU или EN (Если не указан, берется язык браузера)
*
*
*/
getPaymentLink(params) {
const paymentId = params.payment || generateUUID();
return {
payUrl: `https://payok.io/pay?${(0, qs_1.stringify)(Object.assign({ sign: this.generateSignature(Object.assign({ payment: paymentId }, params), "paymentLink"), shop: this.shop, payment: paymentId, amount: params.amount, desc: params.desc, currency: params.currency, email: params.email, success_url: params.success_url, method: params.method, lang: params.lang }, params.custom))}`,
paymentId,
};
}
/**
* Раскрытие сервера (вебхука) и принятие платежей.
* @param {number} port Порт, на котором создать вебхук. Обязателен
* @param {string} path Путь, на котором будет доступен вебхук.
*/
createWebhook(port, path) {
return __awaiter(this, void 0, void 0, function* () {
fastify.addContentTypeParser("*", function (req, body, done) {
var data = "";
body.on("data", (chunk) => {
data += chunk;
});
body.on("end", () => {
done(null, data);
});
});
fastify.addContentTypeParser("application/x-www-form-urlencoded", { parseAs: "buffer", bodyLimit: 1048576 }, (req, body, done) => {
done(null, (0, qs_1.parse)(body.toString()));
});
fastify.post(path || "/", (req, res) => __awaiter(this, void 0, void 0, function* () {
var _a;
if (((_a = req.body) === null || _a === void 0 ? void 0 : _a.sign) !== this.generateSignature(req.body))
return res.status(400).send("NO");
res.status(200).send("OK");
this.events.emit("payment", req.body);
}));
return fastify.listen({ port, host: "::" });
});
}
}
exports.PAYOK = PAYOK;
__exportStar(require("./types"), exports);
const cache = new Map();
function byteToString(byte) {
const cached = cache.get(byte);
if (typeof cached === "string")
return cached;
const value = byte.toString(16).padStart(2, "0");
cache.set(byte, value);
return value;
}
function generateUUID() {
const bytes = (0, crypto_1.randomBytes)(16);
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const plain = Array.from(bytes)
.map((byte) => byteToString(byte))
.join("");
return (plain.slice(0, 5) +
"-" +
plain.slice(4, 8) +
"-" +
plain.slice(8, 13));
}
exports.generateUUID = generateUUID;
;
export declare type Currency = "RUB" | "UAH" | "USD" | "EUR" | "RUB2";
export declare type PaymentMethod = "cd" | "qw" | "ya" | "wm" | "pr" | "pm" | "ad" | "mg" | "bt" | "th" | "lt" | "dg";
export declare type PayoutMethod = "card" | "card_uah" | "card_foreign" | "qiwi" | "yoomoney" | "payeer" | "advcash" | "perfect_money" | "webmoney" | "bitcoin" | "litecoin" | "tether" | "tron" | "dogecoin";
export interface IGetPaymentLink {
amount: string;
desc: string;
payment?: string;
currency?: Currency;
email?: string;
success_url?: string;
method?: PaymentMethod;
lang?: "RU" | "EN";
custom: Record<string, any>;
}
export interface IGetTransaction {
payment?: string;
offset?: number;
}
export interface IGetPayout {
payment_id?: string;
offset?: number;
}
export interface ICreatePayout {
amount: string;
method: PayoutMethod;
reciever: string;
comission_type: "balance" | "payment";
webhook_url?: string;
}
export interface IPaymentHandler {
payment_id: string;
shop: number;
amount: string;
profit: string;
desc: string;
currency: Currency;
currency_amount: string;
sign: string;
email: string;
date: string;
method: string;
custom: any;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const { PAYOK } = require(".."); // require("payok");
const payok = new PAYOK({
apiId: 1,
apiKey: "",
secretKey: "",
shop: 1,
});
const link = payok
.getPaymentLink({
amount: 10,
desc: "Описание вашего товара",
success_url: `https://github.com/kravetsone/payok`,
email: "email@gmail.ru",
custom: {id: 123456},
});
console.log(link); // { payUrl: "https://payok.io/pay?...", paymentId: "98dd5-51e1-a0644"}
\ Нет новой строки в конце файла
const { PAYOK } = require(".."); // require("payok");
const payok = new PAYOK({
apiId: 1,
apiKey: "",
secretKey: "",
shop: 1,
});
payok.createWebhook(3000, "/amazing-secret-url-path").then(() => {
console.log("[PAYOK] Вебхук запущен по пути http://localhost:3000/amazing-secret-url-path на 3000 порту!")
payok.events.on("payment", (payment) => {
console.log(payment);
/*{
payment_id: '51387-77a3-d3724',
shop: '2000',
amount: '10',
profit: '10',
desc: 'Описание вашего товара',
currency: 'RUB',
currency_amount: '10.69',
sign: 'b7453a35683171d235dfb13a16b61f41',
email: 'email@gmail.ru',
date: '11.06.2022 12:13:15',
method: 'Qiwi',
custom: { id: '123456' }
}*/
});
});
\ Нет новой строки в конце файла
const { PAYOK } = require(".."); // require("payok");
const payok = new PAYOK({
apiId: 1,
apiKey: "",
secretKey: "",
shop: 1,
});
payok.api.getBalance().then((res) => {
console.log(res); //{ balance: "10.00", ref_balance: "0" }
}).catch(console.error);
payok.api.getTransactions({ offset: 1 }).then((res) => {
console.log(res);
/*{
{
"status": "success"
"1": {
"transaction": 10000,
"email": "example@ex.com",
"amount": "1065",
"currency": "USD",
"currency_amount": "14.26",
"comission_percent": 5 ,
"comission_fixed": "15",
"amount_profit": "1000",
"method": Visa/Mastercard,
"payment_id": "10500",
"description": "Описание транзакции",
"date": "26.09.2021 20:40:07",
"pay_date": "26.09.2021 21:00:00"
"transaction_status": 0
"custom_fields": null
"webhook_status": 1
"webhook_amount": 1
}
}
}*/
}).catch(console.error);
payok.api.getPayouts({ offset: 1 }).then((res) => {
console.log(res);
/*{
{
"status": "success"
"1": {
"payout": 10000,
"method": "card",
"reciever": "5000400030002000",
"type": "main",
"amount": "1000",
"comission_percent": 2 ,
"comission_fixed": "50",
"amount_profit": 930,
"date_create": "26.09.2021 20:40:07",
"date_pay": "26.09.2021 20:55:01",
"status": 0
}
}
}*/
}).catch(console.error);
payok.api
.createPayout({
amount: 10,
method: "qiwi",
reciever: "+79851628442",
comission_type: "balance",
})
.then((res) => {
console.log(res);
/*{
{
"status":"success",
"remain_balance":"229.44",
"data": {
"payout_id": 100,
"method": "card",
"reciever": "5000400030002000",
"amount": 1000,
"comission_percent": 2 ,
"comission_fixed": "50",
"amount_profit": 930,
"date": "26.09.2021 20:40:07",
"payout_status_code": 0,
"payout_status_text": "WAIT"
}
}
}*/
}).catch(console.error);
\ Нет новой строки в конце файла
const { PAYOK } = require(".."); // require("payok");
const { Telegram, InlineKeyboardBuilder } = require("puregram")
const payok = new PAYOK({
apiId: 1,
apiKey: "",
secretKey: "",
shop: 1,
});
const bot = new Telegram({
token: ""
});
const users = []; // Так как это простенький пример всякие базы данных здесь использоваться не будут
payok.events.on("payment", (payment) => {
const user = users.find(x => x.id == payment.custom.id);
user.balance += payment.amount;
return bot.api.sendMessage({
chat_id: payment.custom.id,
text: `✨ Спасибо за пополнение в 10 рублей! Теперь твой баланс составляет - ${user.balance}.`
});
});
bot.updates.on("message", (message) => {
message.user = users.find(x => x.id == message.from.id);
if(!message.user) {
users.push({
id: message.from.id,
balance: 0
});
return message.send(`❓ Добро пожаловать в бота с тестовым пополнением баланса с помощью https://github.com/kravetsone/payok. Напишите что-нибудь...`)
}
const link = payok.getPaymentLink({
amount: 10,
desc: `Пополнение 10 рублей для ${message.from.firstName}`,
success_url: `https://github.com/kravetsone/payok`,
custom: {id: message.from.id},
});
console.log(link); // { payUrl: "https://payok.io/pay?...", paymentId: "98dd5-51e1-a0644"}
return message.send(`Привет, ${message.from.firstName}! Твой баланс составляет - ${message.user.balance}.`, {reply_markup: new InlineKeyboardBuilder().urlButton({
url: link.payUrl,
text: "Пополнить свой баланс на 10 рублей"
})});
})
bot.updates.startPolling().then(() => {
console.log("Бот в телеграмме запущен.");
});
payok.createWebhook(3000, "/amazing-secret-url-path").then(() => {
console.log("[PAYOK] Вебхук запущен по пути http://localhost:3000/amazing-secret-url-path на 3000 порту!");
});
\ Нет новой строки в конце файла
......@@ -9,6 +9,7 @@
"version": "1.0.3",
"license": "ISC",
"dependencies": {
"axios": "^0.27.2",
"fastify": "^4.0.0",
"node-fetch": "^2.6.7",
"qs": "^6.10.5"
......@@ -184,6 +185,11 @@
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/atomic-sleep": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
......@@ -203,6 +209,15 @@
"queue-microtask": "^1.1.2"
}
},
"node_modules/axios": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
"dependencies": {
"follow-redirects": "^1.14.9",
"form-data": "^4.0.0"
}
},
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
......@@ -215,6 +230,17 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/cookie": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
......@@ -253,6 +279,14 @@
"node": ">=0.10.0"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
......@@ -361,6 +395,38 @@
"node": ">=12"
}
},
"node_modules/follow-redirects": {
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
......@@ -460,6 +526,25 @@
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
......@@ -1028,6 +1113,11 @@
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"atomic-sleep": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
......@@ -1044,6 +1134,15 @@
"queue-microtask": "^1.1.2"
}
},
"axios": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
"requires": {
"follow-redirects": "^1.14.9",
"form-data": "^4.0.0"
}
},
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
......@@ -1053,6 +1152,14 @@
"get-intrinsic": "^1.0.2"
}
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"cookie": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
......@@ -1077,6 +1184,11 @@
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
......@@ -1175,6 +1287,21 @@
"safe-regex2": "^2.0.0"
}
},
"follow-redirects": {
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
},
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
......@@ -1255,6 +1382,19 @@
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"mime-db": "1.52.0"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
......
{
"name": "payok",
"version": "1.0.3",
"description": "Node JS module for payok.io",
"version": "1.0.4",
"description": "Node JS module for payok.io with types",
"main": "./dist/index.js",
"module": "./dist/index.js",
"directories": {
"lib": "lib"
},
"typings": "./dist/index.d.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc"
......@@ -30,8 +31,8 @@
},
"homepage": "https://github.com/kravetsone/payok#readme",
"dependencies": {
"axios": "^0.27.2",
"fastify": "^4.0.0",
"node-fetch": "^2.6.7",
"qs": "^6.10.5"
},
"devDependencies": {
......
import axios, { AxiosInstance } from "axios";
import { IcreatePayout, IgetPayout, IgetTransaction } from "./types";
import axios, { Axios } from "axios";
import { ICreatePayout, IGetPayout, IGetTransaction } from "./types";
import { stringify, parse } from "qs";
export class API {
apiId: number;
apiKey: string;
secretKey: string;
shop: number;
request: AxiosInstance;
request: Axios;
constructor(params: {
apiId: number,
apiKey: string,
......@@ -16,22 +17,23 @@ export class API {
this.apiKey = params.apiKey;
this.secretKey = params.secretKey;
this.shop = params.shop;
this.request = axios.create({
this.request = new Axios({
baseURL: "https://payok.io/api",
timeout: 1000,
headers: {
"User-Agent": "kravetsone/payok",
"Content-type":
"application/x-www-form-urlencoded",
Accept: "application/json",
},
data: {
API_ID: this.apiId,
API_KEY: this.apiKey,
shop: this.shop,
},
transformRequest: [function (data, headers) {
return stringify(Object.assign({
API_ID: params.apiId,
API_KEY: params.apiKey,
shop: params.shop,
}, { ...data || {} }));
}],
});
this.request.interceptors.response.use(function (response) {
this.request.interceptors.response.use((response) => {
if (response.data.status == "error") return Promise.reject(response.data);
return response;
});
......@@ -41,23 +43,23 @@ export class API {
*
*/
async getBalance() {
return await this.request.post("/balance").then(response => response.data);
return this.request.post("/balance").then(response => response.data);
}
/**
* [Получение списка транзакций.](https://payok.io/cabinet/documentation/doc_api_transaction)
* @param {number} params.payment ID платежа в вашей системе.
* @param {number} params.offset Отступ, пропуск указанного количества строк.
*/
async getTransaction(params: IgetTransaction) {
return await this.request.post("/transaction", params).then(response => response.data);
async getTransactions(params: IGetTransaction) {
return this.request.post("/transaction", params).then(response => response.data);
}
/**
* [Получение списка транзакций.](https://payok.io/cabinet/documentation/doc_api_payout)
* @param {number} params.payment_id ID выплаты в системе Payok.
* @param {number} params.offset Отступ, пропуск указанного количества строк.
*/
async getPayout(params: IgetPayout) {
return await this.request.post("/payout", params).then(response => response.data);
async getPayouts(params: IGetPayout) {
return this.request.post("/payout", params).then(response => response.data);
}
/**
* [Создание выплаты.](https://payok.io/cabinet/documentation/doc_api_payout_create)
......@@ -67,7 +69,7 @@ export class API {
* @param {string} params.comission_type Комиссия с баланса - `balance`, а если с выплаты - `payment`. Обязателен.
* @param {number} params.webhook_url URL вебхука для отправки статуса выплаты.
*/
async createPayout(params: IcreatePayout) {
return await this.request.post("/payout_create", params).then(response => response.data);
async createPayout(params: ICreatePayout) {
return this.request.post("/payout_create", params).then(response => response.data);
}
}
\ Нет новой строки в конце файла
......@@ -2,8 +2,10 @@ import Fastify from "fastify";
const fastify = Fastify();
import { createHash, randomBytes } from "crypto";
import { stringify, parse } from "qs";
import { IgetPaymentLink } from "./types";
import { IGetPaymentLink, IPaymentHandler } from "./types";
import { API } from "./api";
import EventEmitter from "events";
class Emitter extends EventEmitter { };
export class PAYOK {
apiId: number;
apiKey: string;
......@@ -11,6 +13,7 @@ export class PAYOK {
shop: number;
cache: Map<any, any>;
api: API;
events: Emitter;
/**
*
* @param {number} params.apiId Идентификатор вашего API ключа.
......@@ -29,6 +32,7 @@ export class PAYOK {
this.apiKey = params.apiKey;
this.secretKey = params.secretKey;
this.shop = params.shop;
this.events = new Emitter();
this.cache = new Map();
this.api = new API(params);
}
......@@ -51,29 +55,30 @@ export class PAYOK {
* Создание ссылки на форму оплаты
* @param {float} params.amount Сумма заказа. Обязателен.
* @param {string} params.desc Название или описание товара. Обязателен.
* @param {any} params.custom.* Ваш параметр, который вы хотите передать в уведомлении (любое количество).
* @param {string} params.payment Номер заказа, уникальный в вашей системе (если не укажите, то он заполнится автоматически), до 16 символов. (a-z0-9-_)
* @param {string} params.currency Валюта (RUB - Рубли, UAH - Гривны, USD - Доллары, EUR - Евро, RUB2 - Рубли, но альтернативный шлюз). По умолчанию RUB.
* @param {string} params.email Электронна почта покупателя.
* @param {string} params.success_url Ссылка для переадресации после оплаты.
* @param {string} params.method Способ оплаты
* @param {string} params.lang Язык интерфейса. RU или EN (Если не указан, берется язык браузера)
* @param {any} params.custom Ваш параметр, который вы хотите передать в уведомлении (любое количество).
*
*
*/
async getPaymentLink(params: IgetPaymentLink): Promise<{ payUrl: string; paymentId?: string; }> {
getPaymentLink(params: IGetPaymentLink) {
const paymentId = params.payment || generateUUID();
return {
payUrl: `https://payok.io/pay?${stringify(Object.assign({ sign: this.generateSignature(params, "paymentLink"), shop: this.shop, payment: generateUUID() }, params))}`,
paymentId: params.payment,
payUrl: `https://payok.io/pay?${stringify({ sign: this.generateSignature(Object.assign({ payment: paymentId }, params), "paymentLink"), shop: this.shop, payment: paymentId, amount: params.amount, desc: params.desc, currency: params.currency, email: params.email, success_url: params.success_url, method: params.method, lang: params.lang, ...params.custom })
}`,
paymentId,
};
}
/**
* Раскрытие сервера (вебхука) и принятие платежей.
* @param {number} port Порт на котором создать вебхук.
* @param {function} handler Функция которая выполниться при переводе после проверки подписи.
* @param {number} port Порт, на котором создать вебхук. Обязателен
* @param {string} path Путь, на котором будет доступен вебхук.
*/
async createWebhook(port: number, handler: Function, path: "/") {
async createWebhook(port: number, path?: string) {
fastify.addContentTypeParser("*", function (req, body, done) {
var data = "";
body.on("data", (chunk) => {
......@@ -90,14 +95,13 @@ export class PAYOK {
done(null, parse(body.toString()));
}
);
fastify.post(path, async (req: any, res) => {
req.body = Object.assign({}, req.body);
if (req.body.sign !== this.generateSignature(req.body))
fastify.post(path || "/", async (req: any, res) => {
if (req.body?.sign !== this.generateSignature(req.body))
return res.status(400).send("NO");
res.status(200).send("OK");
await handler(req.body);
this.events.emit("payment", req.body);
});
return await fastify.listen({ port, host: "::" });
return fastify.listen({ port, host: "::" });
}
}
export * from "./types";
......
export interface IgetPaymentLink {
amount: number,
payment?: string,
export type Currency = "RUB" | "UAH" | "USD" | "EUR" | "RUB2"
export type PaymentMethod = "cd" | "qw" | "ya" | "wm" | "pr" | "pm" | "ad" | "mg" | "bt" | "th" | "lt" | "dg"
export type PayoutMethod = "card" | "card_uah" | "card_foreign" | "qiwi" | "yoomoney" | "payeer" | "advcash" | "perfect_money" | "webmoney" | "bitcoin" | "litecoin" | "tether" | "tron" | "dogecoin"
export interface IGetPaymentLink {
amount: string,
desc: string,
currency?: "RUB" | "UAH" | "USD" | "EUR" | "RUB2",
payment?: string,
currency?: Currency,
email?: string,
success_url?: string,
method?: "cd" | "qw" | "ya" | "wm" | "pr" | "pm" | "ad" | "mg" | "bt" | "th" | "lt" | "dg",
method?: PaymentMethod,
lang?: "RU" | "EN",
custom?: any
};
export interface IgetTransaction {
custom: Record<string, any>
}
export interface IGetTransaction {
payment?: string,
offset?: number,
}
export interface IgetPayout {
export interface IGetPayout {
payment_id?: string,
offset?: number,
}
export interface IcreatePayout {
amount: number,
method: "card" | "card_uah" | "card_foreign" | "qiwi" | "yoomoney" | "payeer" | "advcash" | "perfect_money" | "webmoney" | "bitcoin" | "litecoin" | "tether" | "tron" | "dogecoin",
export interface ICreatePayout {
amount: string,
method: PayoutMethod,
reciever: string,
comission_type: "balance" | "payment",
webhook_url?: string,
}
export interface IPaymentHandler {
payment_id: string,
shop: number,
amount: string,
profit: string,
desc: string,
currency: Currency,
currency_amount: string,
sign: string,
email: string,
date: string,
method: string,
custom: any
}
\ Нет новой строки в конце файла
......@@ -4,6 +4,7 @@
"module": "commonjs",
"rootDir": "./src",
"outDir": "./dist",
"declaration": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
......
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать