nexushub-commands 1.6.7 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/Client.d.ts CHANGED
@@ -7,6 +7,9 @@ export interface DepositConfig {
7
7
  deposit: string;
8
8
  depositCard: string;
9
9
  depositCrypto: string;
10
+ withdrawal: string;
11
+ withdrawalCard: string;
12
+ withdrawalCrypto: string;
10
13
  [key: string]: string;
11
14
  };
12
15
  support: {
package/lib/Client.js CHANGED
@@ -11,6 +11,9 @@ const defaultConfig = {
11
11
  deposit: 'deposit',
12
12
  depositCard: 'deposit-card',
13
13
  depositCrypto: 'deposit-crypto',
14
+ withdrawal: 'withdrawal',
15
+ withdrawalCard: 'withdrawal-card',
16
+ withdrawalCrypto: 'withdrawal-crypto',
14
17
  },
15
18
  support: {
16
19
  username: 'support',
@@ -1,2 +1,3 @@
1
1
  export * from './deposit';
2
2
  export * from './registration';
3
+ export * from './withdrawal';
@@ -3,3 +3,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./deposit"), exports);
5
5
  tslib_1.__exportStar(require("./registration"), exports);
6
+ tslib_1.__exportStar(require("./withdrawal"), exports);
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,8 @@
1
+ import { Command } from 'evogram';
2
+ import { CommandContext, InlineQueryContext } from 'evogram/lib/migrated';
3
+ export declare class WithdrawalCommand extends Command {
4
+ static processWithdrawal: (context: CommandContext, amount: number, requisites: any, method: string, coin?: string, bank?: string) => Promise<never>;
5
+ static BANKS: string[][];
6
+ execute(context: CommandContext, method: 'card' | 'sbp' | 'crypto', bank: string, coin: 'btc' | 'eth' | 'usdt-erc20' | 'usdt-trc20', requisites: any, amount: number, confirm: boolean): Promise<void>;
7
+ inlineExecute(context: InlineQueryContext): Promise<void>;
8
+ }
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+ var WithdrawalCommand_1;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.WithdrawalCommand = void 0;
5
+ const tslib_1 = require("tslib");
6
+ const evogram_1 = require("evogram");
7
+ const migrated_1 = require("evogram/lib/migrated");
8
+ const Client_1 = require("../../Client");
9
+ let WithdrawalCommand = WithdrawalCommand_1 = class WithdrawalCommand extends evogram_1.Command {
10
+ execute(context, method, bank, coin, requisites, amount, confirm) {
11
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
12
+ const config = Client_1.Client.config(context);
13
+ const amountInRUB = yield amount.convert({ from: config.currency, to: 'RUB' });
14
+ if (context.user.db.balance < amountInRUB)
15
+ throw new Error('Недостаточно средств');
16
+ const id = yield WithdrawalCommand_1.processWithdrawal(context, amount, requisites, method, coin, bank);
17
+ // context.user.db.balance -= amountInRUB;
18
+ // await context.user.db.save();
19
+ // const withdrawal = await DatabaseManager.getInstance()
20
+ // .dataSource.getRepository(Withdrawals)
21
+ // .save({
22
+ // amount: Number(amount),
23
+ // method,
24
+ // coin: method === 'crypto' ? coin : undefined,
25
+ // requisites: method === 'crypto' ? requisites.wallet : requisites.phone || requisites.card || requisites.formatted,
26
+ // user: context.user.db,
27
+ // });
28
+ // const _method = method === 'crypto' ? `Крипто-кошелек ${coin.toUpperCase()}` : method === 'sbp' ? 'Номер телефона' : 'Банковская карта';
29
+ // context.user.db.requisites = `${withdrawal.requisites} [${_method}${method === 'sbp' ? ` [${bank}]` : ''}]`;
30
+ context.user.log(0, `Заявка на вывод средств ${amountInRUB.toLocaleString('ru')} RUB`, {
31
+ // prettier-ignore
32
+ message: `💲 <b>Сумма:</b> <i>${amount.toLocaleString('ru')} ${config.currency.toUpperCase()} (${amountInRUB.toLocaleString('ru')} RUB)</i>\n` +
33
+ `💱 <b>Метод:</b> <i>${method === 'crypto' ? `Крипто-кошелек ${coin.toUpperCase()}` : method === 'sbp' ? 'Номер телефона' : 'Банковская карта'}</i>\n` +
34
+ `🔘 <b>Реквизиты:</b> <i><code>${method === 'crypto' ? requisites.wallet : requisites.phone || requisites.card || requisites.formatted}</code>${method === 'sbp' ? ` [${bank}]` : ''}</i>`,
35
+ keyboard: [
36
+ [
37
+ {
38
+ text: '🚀 Выплатить',
39
+ callback_data: `AdminWithdrawalCommand?id=${id}&decision=1`,
40
+ },
41
+ {
42
+ text: '❌ Отказать',
43
+ callback_data: `AdminWithdrawalCommand?id=${id}&decision=0`,
44
+ },
45
+ ],
46
+ ],
47
+ });
48
+ // prettier-ignore
49
+ context.sendFormatted({
50
+ photo: method === 'crypto' ? config.images.withdrawalCrypto : config.images.withdrawal,
51
+ header: '<blockquote><b>💸 Создана заявка на вывод средств</b></blockquote>\n\n' +
52
+ `<i>— Сумма: {{ ${amount.toLocaleString('ru')} ${config.currency.toUpperCase()} }}</i>\n` +
53
+ `<i>— Реквизиты: {{ ${method === 'crypto' ? requisites.wallet : requisites.phone || requisites.card || requisites.formatted} }}</i>\n` +
54
+ `<i>— Метод: {{ ${method === 'crypto' ? `Крипто-кошелек ${coin.toUpperCase()}` : requisites.card ? 'Банковская карта' : 'Номер телефона'} }}</i>\n` +
55
+ `<i>— Дата: {{ ${new Date().toLocaleString('ru')} }}</i>\n` +
56
+ (method === 'sbp' ? `<i>— Банк: {{ ${bank} }}</i>\n` : '') +
57
+ `\n<i>— Ваш баланс: {{ ${yield (context.user.db.balance - amountInRUB).convert({ from: 'RUB', to: config.currency, round: true })} }}</i>`,
58
+ }, {
59
+ noBackButton: true,
60
+ });
61
+ });
62
+ }
63
+ inlineExecute(context) {
64
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
65
+ context.answer(yield Promise.all(WithdrawalCommand_1.BANKS.map((x) => tslib_1.__awaiter(this, void 0, void 0, function* () {
66
+ return ({
67
+ type: 'article',
68
+ id: x[0],
69
+ title: x[0],
70
+ thumb_url: x[1] || 'https://s0.rbk.ru/v6_top_pics/media/img/6/03/754598843127036.jpeg',
71
+ input_message_content: {
72
+ message_text: x[0],
73
+ },
74
+ });
75
+ }))), {});
76
+ });
77
+ }
78
+ };
79
+ exports.WithdrawalCommand = WithdrawalCommand;
80
+ WithdrawalCommand.processWithdrawal = (context, amount, requisites, method, coin, bank) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
81
+ throw new Error('Not implemented');
82
+ });
83
+ WithdrawalCommand.BANKS = [
84
+ [
85
+ 'Тинькофф',
86
+ 'https://sun1-92.userapi.com/s/v1/ig2/EfdDUJFU4m19qq8PEU-naHEIdUglx65FzbNd2Z0rDfj5DCRUuPU9ky7bOGTY_y9hZR0bYvFFCdsnKOXgqEF5i7Pv.jpg?size=1080x1080&quality=95&crop=0,0,1080,1080&ava=1',
87
+ ],
88
+ ['Сбербанк', 'https://avatars.mds.yandex.net/get-altay/11047345/2a0000018d3fb02e7d90805b68eb881f54f2/diploma'],
89
+ ['Альфа-Банк', 'https://cc.guru/uploads/cca2025/thumb-36_12400_image_7232d25eff1891395d0505dfa93a2b26.jpg?1733242515'],
90
+ ['ВТБ', 'https://tc-maxima.ru/wp-content/uploads/2023/11/bazgazbzsfbawjmcmi7gmsrm4zir48_fq7wec-vqq_zqkj21r8cxfd3i-mfdhxebpqsrcgv2exup3veozmb56z33.jpg'],
91
+ ['Россельхозбанк', 'https://дворецкультуры.онлайн/upload/iblock/f44/f4441dc07f96bc108e43e4c859ec45b3.jpg'],
92
+ ['Райффайзенбанк', 'https://avatars.mds.yandex.net/i?id=61b52fabb12237bb017c4360112d14ac_l-5241671-images-thumbs&n=13'],
93
+ ['Русский Стандарт', 'https://lh3.googleusercontent.com/ACplx3IdF_Jq0h46AZRm8KIzBm1DkTwNfirSzhg1KPkBbGmH0TOobQO7zo85SXfVPQ'],
94
+ ['Промсвязьбанк', 'https://s3-figma-hubfile-images-production.figma.com/hub/file/carousel/img/0e5feb3fe24f75bcd08ef0e40da4c7fa7c207997'],
95
+ ['Газпромбанк', 'https://pic.rutubelist.ru/user/95/76/9576f91d2353ad868a0e365994e14ade.jpg'],
96
+ ['Банк Открытие', 'https://freesoft.ru/storage/images/704/7040/703927/703927_normal.png'],
97
+ ['Хоум Банк', 'http://brobank.ru/wp-content/uploads/2023/04/homebank-logo-icon.png'],
98
+ ['ОТП Банк', 'https://habrastorage.org/getpro/moikrug/uploads/company/996/859/586/logo/big_78497ffc0d25d89cc4af847b9c7a353b.png'],
99
+ [
100
+ 'Уралсиб',
101
+ 'https://static.rustore.ru/imgproxy/ygBp-kTr7gSoYBqCrb3xJ1GIXxMaE3q08ANNb_emdBA/preset:app_card_icon/aHR0cHM6Ly9zdGF0aWMucnVzdG9yZS5ydS9hcGsvMTY5MzkxODY1NS9jb250ZW50L0lDT04vNjVlZWU5NDAtOTQ1Zi00MzJhLWE2OWYtOWQyZTYyNzcxZjIwLnBuZw==.webp',
102
+ ],
103
+ [
104
+ 'Ozon Банк',
105
+ 'https://upload.wikimedia.org/wikipedia/commons/thumb/f/f2/%D0%9B%D0%BE%D0%B3%D0%BE%D1%82%D0%B8%D0%BF_Ozon_%D0%B1%D0%B0%D0%BD%D0%BA.jpg/1200px-%D0%9B%D0%BE%D0%B3%D0%BE%D1%82%D0%B8%D0%BF_Ozon_%D0%B1%D0%B0%D0%BD%D0%BA.jpg',
106
+ ],
107
+ ['МТС Банк', 'https://static.mts.ru/mts_rf/images/logo/new/mts_logo_cmyk.png'],
108
+ ['Почта Банк', 'https://berezovskoe-r04.gosweb.gosuslugi.ru/netcat_files/37/45/850original_06ecae.jpg'],
109
+ ['ЮMoney', 'https://bankinform.ru/images/logo/logo2/yandexpay.png?width=250'],
110
+ ];
111
+ tslib_1.__decorate([
112
+ tslib_1.__param(1, (0, evogram_1.CommandArgument)('method', (_a) => tslib_1.__awaiter(void 0, [_a], void 0, function* ({ context, value }) {
113
+ if (value)
114
+ return value;
115
+ const config = Client_1.Client.config(context);
116
+ yield context.sendFormatted({
117
+ photo: config.images.withdrawal,
118
+ header: '<b>📤 Выберите удобный для вас метод вывода.</b>',
119
+ }, {
120
+ reply_markup: {
121
+ inline_keyboard: [
122
+ [{ text: '💳 Банковская карта', command: 'withdrawal', payload: { method: 'card' } }],
123
+ ...(context.user.db.currency.toUpperCase() === 'RUB'
124
+ ? [[{ text: '📱 Система быстрых платежей', command: 'withdrawal', payload: { method: 'sbp' } }]]
125
+ : []),
126
+ [{ text: '🪙 Крипто-кошелек', command: 'withdrawal', payload: { method: 'crypto' } }],
127
+ ],
128
+ },
129
+ });
130
+ }))),
131
+ tslib_1.__param(2, (0, evogram_1.CommandArgument)({
132
+ name: 'bank',
133
+ question: (_a) => tslib_1.__awaiter(void 0, [_a], void 0, function* ({ context, args, error }) {
134
+ if (args.method !== 'sbp')
135
+ return 'none';
136
+ const config = Client_1.Client.config(context);
137
+ return (yield context.sendFormattedQuestion({
138
+ photo: config.images.withdrawal,
139
+ body: [
140
+ {
141
+ title: '💳 Банк для вывода',
142
+ data: [['Выберите банк для вывода или напишите свой']],
143
+ },
144
+ ],
145
+ error: error === null || error === void 0 ? void 0 : error.message,
146
+ }, {
147
+ reply_markup: {
148
+ inline_keyboard: [
149
+ [
150
+ {
151
+ text: '🏦 Выбрать банк',
152
+ command: WithdrawalCommand,
153
+ switch_inline_query_current_chat: ' ',
154
+ },
155
+ ],
156
+ ],
157
+ },
158
+ })).text;
159
+ }),
160
+ }, (0, evogram_1.stringValidator)({ maxLength: 16 }))),
161
+ tslib_1.__param(3, (0, evogram_1.CommandArgument)({
162
+ name: 'coin',
163
+ }, (_a) => tslib_1.__awaiter(void 0, [_a], void 0, function* ({ context, value, args }) {
164
+ if (value)
165
+ return value;
166
+ else if (args.method !== 'crypto')
167
+ return 'none';
168
+ const config = Client_1.Client.config(context);
169
+ yield context.sendFormatted({
170
+ photo: config.images.withdrawalCrypto,
171
+ header: '<b>🪙 Доступные сети для вывода:</b>',
172
+ }, {
173
+ reply_markup: {
174
+ inline_keyboard: [
175
+ [{ text: 'BTC', command: 'withdrawal', payload: { method: 'crypto', coin: 'btc' } }],
176
+ [{ text: 'ETH', command: 'withdrawal', payload: { method: 'crypto', coin: 'eth' } }],
177
+ [{ text: 'USDT (ERC-20)', command: 'withdrawal', payload: { method: 'crypto', coin: 'usdt-erc20' } }],
178
+ [{ text: 'USDT (TRC-20)', command: 'withdrawal', payload: { method: 'crypto', coin: 'usdt-trc20' } }],
179
+ ],
180
+ },
181
+ });
182
+ }))),
183
+ tslib_1.__param(4, (0, evogram_1.CommandArgument)({
184
+ name: 'requisites',
185
+ askAgain: true,
186
+ question: (_a) => tslib_1.__awaiter(void 0, [_a], void 0, function* ({ context, args, error }) {
187
+ var _b;
188
+ const config = Client_1.Client.config(context);
189
+ return (yield context.sendFormattedQuestion({
190
+ photo: args.method === 'crypto' ? config.images.withdrawalCrypto : config.images.withdrawal,
191
+ header: '<blockquote><b>✍️ Запрос на вывод средств</b></blockquote>',
192
+ footer: args.method === 'card'
193
+ ? '<i>ℹ️ Отправьте Ваш номер банковской карты</i>'
194
+ : args.method === 'sbp'
195
+ ? '<i>ℹ️ Отправьте Ваш номер телефона</i>'
196
+ : `<i>ℹ️ Отправьте Ваш адрес крипто-кошелька {{ ${(_b = args.coin) === null || _b === void 0 ? void 0 : _b.toUpperCase()} }}</i>`,
197
+ error: error === null || error === void 0 ? void 0 : error.message,
198
+ })).text;
199
+ }),
200
+ }, (params) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
201
+ if (typeof params.value === 'object')
202
+ return params.value;
203
+ if (params.args.method === 'card') {
204
+ const requisites = yield (0, evogram_1.cardValidator)({})(params).catch(() => undefined);
205
+ if (!requisites)
206
+ throw new Error('Неверный формат реквизитов');
207
+ return yield requisites;
208
+ }
209
+ else if (params.args.method === 'sbp') {
210
+ const requisites = yield (0, evogram_1.phoneValidator)({})(params).catch(() => undefined);
211
+ if (!requisites || !/^\+?[7-8]\d{10,14}$/.test(params.value.replace(/ /g, '')))
212
+ throw new Error('Неверный формат реквизитов');
213
+ return yield requisites;
214
+ }
215
+ else if (params.args.method === 'crypto') {
216
+ if (params.args.method === 'crypto') {
217
+ switch (params.args.coin) {
218
+ case 'btc':
219
+ if (!/^([13][a-km-zA-HJ-NP-Z1-9]{25,34})|^(bc1[pqzry9x8gf2tvdw0s3jn54khce6mua7l]([qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38}|[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{58}))$/.test(params.value))
220
+ throw new Error('Невалидный адрес BTC-кошелька');
221
+ break;
222
+ case 'usdt-erc20':
223
+ case 'eth':
224
+ if (!/^(?:0x)?[0-9a-fA-F]{40}$/.test(params.value))
225
+ throw new Error('Невалидный адрес ETH-кошелька');
226
+ break;
227
+ case 'usdt-trc20':
228
+ if (!/^T[a-zA-HJ-NP-Z0-9]{33}$/.test(params.value))
229
+ throw new Error('Невалидный адрес TRC-20-кошелька');
230
+ break;
231
+ }
232
+ return { wallet: params.value };
233
+ }
234
+ }
235
+ throw new Error('Неверный формат реквизитов.');
236
+ }))),
237
+ tslib_1.__param(5, (0, evogram_1.CommandArgument)({
238
+ name: 'amount',
239
+ question: (_a) => tslib_1.__awaiter(void 0, [_a], void 0, function* ({ context, args, error, validateArgs }) {
240
+ const config = Client_1.Client.config(context);
241
+ let minAmountSetting = JSON.parse(context.state.settings.find((x) => x.name === 'minWithdrawal').value);
242
+ let minAmount = minAmountSetting[config.currency] || (yield minAmountSetting['RUB'].convert({ from: 'RUB', to: config.currency }));
243
+ validateArgs.minAmount = minAmount;
244
+ // prettier-ignore
245
+ return (yield context.sendFormattedQuestion({
246
+ photo: args.method === 'crypto' ? config.images.withdrawalCrypto : config.images.withdrawal,
247
+ header: '<blockquote><b>✍️ Запрос на вывод средств</b></blockquote>\n\n' +
248
+ 'Введите сумму, которую хотите вывести.\n' +
249
+ `<b>Ваш текущий баланс:</b> {{ ${yield context.user.db.balance.convert({ from: 'RUB', to: config.currency })} }}\n\n` +
250
+ `ℹ️ <b>Минимальная сумма для вывода:</b> {{ ${Number(minAmount).toLocaleString('ru')} ${config.currency.toUpperCase()} }}`,
251
+ error: error === null || error === void 0 ? void 0 : error.message,
252
+ })).text;
253
+ }),
254
+ }, (0, evogram_1.numberValidator)({ allowFloat: true, min: 0 }), (_a) => tslib_1.__awaiter(void 0, [_a], void 0, function* ({ value, context, validateArgs }) {
255
+ const config = Client_1.Client.config(context);
256
+ const amountInRUB = yield value.convert({ from: config.currency, to: 'RUB' });
257
+ // prettier-ignore
258
+ if (value < validateArgs.minAmount)
259
+ throw new Error(`Минимальная сумма для вывода: ${Number(validateArgs.minAmount).toLocaleString('ru')} ${config.currency.toUpperCase()}`);
260
+ if (amountInRUB > context.user.db.balance)
261
+ throw new Error('Вы пытаетесь вывести больше, чем у вас есть');
262
+ return value;
263
+ }))),
264
+ tslib_1.__param(6, (0, evogram_1.CommandArgument)('confirm', (_a) => tslib_1.__awaiter(void 0, [_a], void 0, function* ({ context, value, validateArgs, args }) {
265
+ var _b, _c, _d;
266
+ if (value)
267
+ return value;
268
+ const config = Client_1.Client.config(context);
269
+ // prettier-ignore
270
+ context.sendFormatted({
271
+ photo: args.method === 'crypto' ? config.images.withdrawalCrypto : config.images.withdrawal,
272
+ header: '<blockquote><b>✍️ Запрос на вывод средств</b></blockquote>\n\n' +
273
+ `<i>— Сумма вывода: {{ ${Number(validateArgs.amount).toLocaleString('ru')} ${config.currency.toUpperCase()} }}</i>\n` +
274
+ `<i>— Реквизиты: {{ ${((_b = validateArgs.requisites) === null || _b === void 0 ? void 0 : _b.formatted) || ((_c = validateArgs.requisites) === null || _c === void 0 ? void 0 : _c.wallet)} }}</i>\n` +
275
+ `<i>— Метод: {{ ${validateArgs.method === 'crypto' ? `Крипто-кошелек ${(_d = validateArgs.coin) === null || _d === void 0 ? void 0 : _d.toUpperCase()}` : args.method === 'sbp' ? 'Номер телефона' : 'Банковская карта'} }}</i>\n` +
276
+ (args.bank ? `<i>— Банк: {{ ${args.bank} }}</i>\n` : '') +
277
+ `\n<i>— Ваш баланс после вывода: {{ ${yield (context.user.db.balance - (yield validateArgs.amount.convert({ from: config.currency, to: 'RUB' }))).convert({ from: 'RUB', to: config.currency })} }}</i>`,
278
+ }, {
279
+ reply_markup: {
280
+ inline_keyboard: [[{ text: '✅ Подтвердить', command: WithdrawalCommand, payload: Object.assign(Object.assign({}, args), { confirm: true }) }]],
281
+ },
282
+ });
283
+ }))),
284
+ tslib_1.__metadata("design:type", Function),
285
+ tslib_1.__metadata("design:paramtypes", [migrated_1.CommandContext, String, String, String, Object, Number, Boolean]),
286
+ tslib_1.__metadata("design:returntype", Promise)
287
+ ], WithdrawalCommand.prototype, "execute", null);
288
+ exports.WithdrawalCommand = WithdrawalCommand = WithdrawalCommand_1 = tslib_1.__decorate([
289
+ (0, evogram_1.CommandD)({ name: 'withdrawal', description: [{ text: 'Вывод средств' }, { language: 'en', text: 'Withdrawal' }], backButton: 'К выводу' })
290
+ ], WithdrawalCommand);
@@ -0,0 +1 @@
1
+ export * from './Withdrawal.command';
@@ -1 +1,4 @@
1
1
  "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./Withdrawal.command"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexushub-commands",
3
- "version": "1.6.7",
3
+ "version": "1.7.0",
4
4
  "main": "./lib/index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
package/src/Client.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import axios, { AxiosInstance } from 'axios';
2
- import { Evogram } from 'evogram';
3
2
  import { CommandContext } from 'evogram/lib/migrated';
4
3
 
5
4
  // Интерфейсы для настройки команды
@@ -13,6 +12,11 @@ export interface DepositConfig {
13
12
  deposit: string;
14
13
  depositCard: string;
15
14
  depositCrypto: string;
15
+
16
+ withdrawal: string;
17
+ withdrawalCard: string;
18
+ withdrawalCrypto: string;
19
+
16
20
  [key: string]: string;
17
21
  };
18
22
 
@@ -34,6 +38,10 @@ const defaultConfig: DepositConfig = {
34
38
  deposit: 'deposit',
35
39
  depositCard: 'deposit-card',
36
40
  depositCrypto: 'deposit-crypto',
41
+
42
+ withdrawal: 'withdrawal',
43
+ withdrawalCard: 'withdrawal-card',
44
+ withdrawalCrypto: 'withdrawal-crypto',
37
45
  },
38
46
 
39
47
  support: {
@@ -1,2 +1,3 @@
1
1
  export * from './deposit';
2
2
  export * from './registration';
3
+ export * from './withdrawal';
@@ -0,0 +1,339 @@
1
+ import { cardValidator, Command, CommandArgument, CommandD, numberValidator, phoneValidator, stringValidator } from 'evogram';
2
+ import { CommandContext, InlineQueryContext } from 'evogram/lib/migrated';
3
+ import { Client } from '../../Client';
4
+
5
+ @CommandD({ name: 'withdrawal', description: [{ text: 'Вывод средств' }, { language: 'en', text: 'Withdrawal' }], backButton: 'К выводу' })
6
+ export class WithdrawalCommand extends Command {
7
+ static processWithdrawal = async (context: CommandContext, amount: number, requisites: any, method: string, coin?: string, bank?: string) => {
8
+ throw new Error('Not implemented');
9
+ };
10
+
11
+ static BANKS = [
12
+ [
13
+ 'Тинькофф',
14
+ 'https://sun1-92.userapi.com/s/v1/ig2/EfdDUJFU4m19qq8PEU-naHEIdUglx65FzbNd2Z0rDfj5DCRUuPU9ky7bOGTY_y9hZR0bYvFFCdsnKOXgqEF5i7Pv.jpg?size=1080x1080&quality=95&crop=0,0,1080,1080&ava=1',
15
+ ],
16
+ ['Сбербанк', 'https://avatars.mds.yandex.net/get-altay/11047345/2a0000018d3fb02e7d90805b68eb881f54f2/diploma'],
17
+ ['Альфа-Банк', 'https://cc.guru/uploads/cca2025/thumb-36_12400_image_7232d25eff1891395d0505dfa93a2b26.jpg?1733242515'],
18
+ ['ВТБ', 'https://tc-maxima.ru/wp-content/uploads/2023/11/bazgazbzsfbawjmcmi7gmsrm4zir48_fq7wec-vqq_zqkj21r8cxfd3i-mfdhxebpqsrcgv2exup3veozmb56z33.jpg'],
19
+ ['Россельхозбанк', 'https://дворецкультуры.онлайн/upload/iblock/f44/f4441dc07f96bc108e43e4c859ec45b3.jpg'],
20
+ ['Райффайзенбанк', 'https://avatars.mds.yandex.net/i?id=61b52fabb12237bb017c4360112d14ac_l-5241671-images-thumbs&n=13'],
21
+ ['Русский Стандарт', 'https://lh3.googleusercontent.com/ACplx3IdF_Jq0h46AZRm8KIzBm1DkTwNfirSzhg1KPkBbGmH0TOobQO7zo85SXfVPQ'],
22
+ ['Промсвязьбанк', 'https://s3-figma-hubfile-images-production.figma.com/hub/file/carousel/img/0e5feb3fe24f75bcd08ef0e40da4c7fa7c207997'],
23
+ ['Газпромбанк', 'https://pic.rutubelist.ru/user/95/76/9576f91d2353ad868a0e365994e14ade.jpg'],
24
+ ['Банк Открытие', 'https://freesoft.ru/storage/images/704/7040/703927/703927_normal.png'],
25
+ ['Хоум Банк', 'http://brobank.ru/wp-content/uploads/2023/04/homebank-logo-icon.png'],
26
+ ['ОТП Банк', 'https://habrastorage.org/getpro/moikrug/uploads/company/996/859/586/logo/big_78497ffc0d25d89cc4af847b9c7a353b.png'],
27
+ [
28
+ 'Уралсиб',
29
+ 'https://static.rustore.ru/imgproxy/ygBp-kTr7gSoYBqCrb3xJ1GIXxMaE3q08ANNb_emdBA/preset:app_card_icon/aHR0cHM6Ly9zdGF0aWMucnVzdG9yZS5ydS9hcGsvMTY5MzkxODY1NS9jb250ZW50L0lDT04vNjVlZWU5NDAtOTQ1Zi00MzJhLWE2OWYtOWQyZTYyNzcxZjIwLnBuZw==.webp',
30
+ ],
31
+ [
32
+ 'Ozon Банк',
33
+ 'https://upload.wikimedia.org/wikipedia/commons/thumb/f/f2/%D0%9B%D0%BE%D0%B3%D0%BE%D1%82%D0%B8%D0%BF_Ozon_%D0%B1%D0%B0%D0%BD%D0%BA.jpg/1200px-%D0%9B%D0%BE%D0%B3%D0%BE%D1%82%D0%B8%D0%BF_Ozon_%D0%B1%D0%B0%D0%BD%D0%BA.jpg',
34
+ ],
35
+ ['МТС Банк', 'https://static.mts.ru/mts_rf/images/logo/new/mts_logo_cmyk.png'],
36
+ ['Почта Банк', 'https://berezovskoe-r04.gosweb.gosuslugi.ru/netcat_files/37/45/850original_06ecae.jpg'],
37
+ ['ЮMoney', 'https://bankinform.ru/images/logo/logo2/yandexpay.png?width=250'],
38
+ ];
39
+
40
+ public async execute(
41
+ context: CommandContext,
42
+
43
+ @CommandArgument('method', async ({ context, value }) => {
44
+ if (value) return value;
45
+ const config = Client.config(context);
46
+
47
+ await context.sendFormatted(
48
+ {
49
+ photo: config.images.withdrawal,
50
+ header: '<b>📤 Выберите удобный для вас метод вывода.</b>',
51
+ },
52
+ {
53
+ reply_markup: {
54
+ inline_keyboard: [
55
+ [{ text: '💳 Банковская карта', command: 'withdrawal', payload: { method: 'card' } }],
56
+ ...(context.user.db.currency.toUpperCase() === 'RUB'
57
+ ? [[{ text: '📱 Система быстрых платежей', command: 'withdrawal', payload: { method: 'sbp' } }]]
58
+ : []),
59
+ [{ text: '🪙 Крипто-кошелек', command: 'withdrawal', payload: { method: 'crypto' } }],
60
+ ],
61
+ },
62
+ }
63
+ );
64
+ })
65
+ method: 'card' | 'sbp' | 'crypto',
66
+ @CommandArgument(
67
+ {
68
+ name: 'bank',
69
+ question: async ({ context, args, error }) => {
70
+ if (args.method !== 'sbp') return 'none';
71
+ const config = Client.config(context);
72
+
73
+ return (
74
+ await context.sendFormattedQuestion(
75
+ {
76
+ photo: config.images.withdrawal,
77
+ body: [
78
+ {
79
+ title: '💳 Банк для вывода',
80
+ data: [['Выберите банк для вывода или напишите свой']],
81
+ },
82
+ ],
83
+ error: error?.message,
84
+ },
85
+ {
86
+ reply_markup: {
87
+ inline_keyboard: [
88
+ [
89
+ {
90
+ text: '🏦 Выбрать банк',
91
+ command: WithdrawalCommand,
92
+ switch_inline_query_current_chat: ' ',
93
+ },
94
+ ],
95
+ ],
96
+ },
97
+ }
98
+ )
99
+ ).text;
100
+ },
101
+ },
102
+ stringValidator({ maxLength: 16 })
103
+ )
104
+ bank: string,
105
+ @CommandArgument(
106
+ {
107
+ name: 'coin',
108
+ },
109
+ async ({ context, value, args }) => {
110
+ if (value) return value;
111
+ else if (args.method !== 'crypto') return 'none';
112
+
113
+ const config = Client.config(context);
114
+ await context.sendFormatted(
115
+ {
116
+ photo: config.images.withdrawalCrypto,
117
+ header: '<b>🪙 Доступные сети для вывода:</b>',
118
+ },
119
+ {
120
+ reply_markup: {
121
+ inline_keyboard: [
122
+ [{ text: 'BTC', command: 'withdrawal', payload: { method: 'crypto', coin: 'btc' } }],
123
+ [{ text: 'ETH', command: 'withdrawal', payload: { method: 'crypto', coin: 'eth' } }],
124
+ [{ text: 'USDT (ERC-20)', command: 'withdrawal', payload: { method: 'crypto', coin: 'usdt-erc20' } }],
125
+ [{ text: 'USDT (TRC-20)', command: 'withdrawal', payload: { method: 'crypto', coin: 'usdt-trc20' } }],
126
+ ],
127
+ },
128
+ }
129
+ );
130
+ }
131
+ )
132
+ coin: 'btc' | 'eth' | 'usdt-erc20' | 'usdt-trc20',
133
+ @CommandArgument(
134
+ {
135
+ name: 'requisites',
136
+ askAgain: true,
137
+ question: async ({ context, args, error }) => {
138
+ const config = Client.config(context);
139
+
140
+ return (
141
+ await context.sendFormattedQuestion({
142
+ photo: args.method === 'crypto' ? config.images.withdrawalCrypto : config.images.withdrawal,
143
+ header: '<blockquote><b>✍️ Запрос на вывод средств</b></blockquote>',
144
+ footer:
145
+ args.method === 'card'
146
+ ? '<i>ℹ️ Отправьте Ваш номер банковской карты</i>'
147
+ : args.method === 'sbp'
148
+ ? '<i>ℹ️ Отправьте Ваш номер телефона</i>'
149
+ : `<i>ℹ️ Отправьте Ваш адрес крипто-кошелька {{ ${args.coin?.toUpperCase()} }}</i>`,
150
+ error: error?.message,
151
+ })
152
+ ).text;
153
+ },
154
+ },
155
+ async (params) => {
156
+ if (typeof params.value === 'object') return params.value;
157
+
158
+ if (params.args.method === 'card') {
159
+ const requisites = await cardValidator({})(params).catch(() => undefined);
160
+ if (!requisites) throw new Error('Неверный формат реквизитов');
161
+
162
+ return await requisites;
163
+ } else if (params.args.method === 'sbp') {
164
+ const requisites = await phoneValidator({})(params).catch(() => undefined);
165
+ if (!requisites || !/^\+?[7-8]\d{10,14}$/.test(params.value.replace(/ /g, ''))) throw new Error('Неверный формат реквизитов');
166
+
167
+ return await requisites;
168
+ } else if (params.args.method === 'crypto') {
169
+ if (params.args.method === 'crypto') {
170
+ switch (params.args.coin) {
171
+ case 'btc':
172
+ if (
173
+ !/^([13][a-km-zA-HJ-NP-Z1-9]{25,34})|^(bc1[pqzry9x8gf2tvdw0s3jn54khce6mua7l]([qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38}|[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{58}))$/.test(
174
+ params.value
175
+ )
176
+ )
177
+ throw new Error('Невалидный адрес BTC-кошелька');
178
+ break;
179
+ case 'usdt-erc20':
180
+ case 'eth':
181
+ if (!/^(?:0x)?[0-9a-fA-F]{40}$/.test(params.value)) throw new Error('Невалидный адрес ETH-кошелька');
182
+ break;
183
+ case 'usdt-trc20':
184
+ if (!/^T[a-zA-HJ-NP-Z0-9]{33}$/.test(params.value)) throw new Error('Невалидный адрес TRC-20-кошелька');
185
+ break;
186
+ }
187
+
188
+ return { wallet: params.value };
189
+ }
190
+ }
191
+
192
+ throw new Error('Неверный формат реквизитов.');
193
+ }
194
+ )
195
+ requisites: any,
196
+ @CommandArgument(
197
+ {
198
+ name: 'amount',
199
+ question: async ({ context, args, error, validateArgs }) => {
200
+ const config = Client.config(context);
201
+
202
+ let minAmountSetting = JSON.parse(context.state.settings.find((x: any) => x.name === 'minWithdrawal').value);
203
+ let minAmount = minAmountSetting[config.currency] || (await minAmountSetting['RUB'].convert({ from: 'RUB', to: config.currency }));
204
+ validateArgs.minAmount = minAmount;
205
+
206
+ // prettier-ignore
207
+ return (
208
+ await context.sendFormattedQuestion({
209
+ photo: args.method === 'crypto' ? config.images.withdrawalCrypto : config.images.withdrawal,
210
+ header:
211
+ '<blockquote><b>✍️ Запрос на вывод средств</b></blockquote>\n\n' +
212
+
213
+ 'Введите сумму, которую хотите вывести.\n' +
214
+ `<b>Ваш текущий баланс:</b> {{ ${await context.user.db.balance.convert({ from: 'RUB', to: config.currency })} }}\n\n` +
215
+
216
+ `ℹ️ <b>Минимальная сумма для вывода:</b> {{ ${Number(minAmount).toLocaleString('ru')} ${config.currency.toUpperCase()} }}`,
217
+ error: error?.message,
218
+ })
219
+ ).text;
220
+ },
221
+ },
222
+ numberValidator({ allowFloat: true, min: 0 }),
223
+ async ({ value, context, validateArgs }) => {
224
+ const config = Client.config(context);
225
+ const amountInRUB = await value.convert({ from: config.currency, to: 'RUB' });
226
+
227
+ // prettier-ignore
228
+ if (value < validateArgs.minAmount) throw new Error(`Минимальная сумма для вывода: ${Number(validateArgs.minAmount).toLocaleString('ru')} ${config.currency.toUpperCase()}`);
229
+ if (amountInRUB > context.user.db.balance) throw new Error('Вы пытаетесь вывести больше, чем у вас есть');
230
+
231
+ return value;
232
+ }
233
+ )
234
+ amount: number,
235
+ @CommandArgument('confirm', async ({ context, value, validateArgs, args }) => {
236
+ if (value) return value;
237
+ const config = Client.config(context);
238
+
239
+ // prettier-ignore
240
+ context.sendFormatted(
241
+ {
242
+ photo: args.method === 'crypto' ? config.images.withdrawalCrypto : config.images.withdrawal,
243
+ header:
244
+ '<blockquote><b>✍️ Запрос на вывод средств</b></blockquote>\n\n' +
245
+
246
+ `<i>— Сумма вывода: {{ ${Number(validateArgs.amount).toLocaleString('ru')} ${config.currency.toUpperCase()} }}</i>\n` +
247
+ `<i>— Реквизиты: {{ ${validateArgs.requisites?.formatted || validateArgs.requisites?.wallet} }}</i>\n` +
248
+ `<i>— Метод: {{ ${validateArgs.method === 'crypto' ? `Крипто-кошелек ${validateArgs.coin?.toUpperCase()}` : args.method === 'sbp' ? 'Номер телефона' : 'Банковская карта'} }}</i>\n` +
249
+ (args.bank ? `<i>— Банк: {{ ${args.bank} }}</i>\n` : '') +
250
+
251
+ `\n<i>— Ваш баланс после вывода: {{ ${await (context.user.db.balance - (await validateArgs.amount.convert({ from: config.currency, to: 'RUB' }))).convert({ from: 'RUB', to: config.currency })} }}</i>`,
252
+ },
253
+ {
254
+ reply_markup: {
255
+ inline_keyboard: [[{ text: '✅ Подтвердить', command: WithdrawalCommand, payload: { ...args, confirm: true } }]],
256
+ },
257
+ }
258
+ );
259
+ })
260
+ confirm: boolean
261
+ ) {
262
+ const config = Client.config(context);
263
+
264
+ const amountInRUB = await amount.convert({ from: config.currency, to: 'RUB' });
265
+ if (context.user.db.balance < amountInRUB) throw new Error('Недостаточно средств');
266
+
267
+ const id = await WithdrawalCommand.processWithdrawal(context, amount, requisites, method, coin, bank);
268
+
269
+ // context.user.db.balance -= amountInRUB;
270
+ // await context.user.db.save();
271
+
272
+ // const withdrawal = await DatabaseManager.getInstance()
273
+ // .dataSource.getRepository(Withdrawals)
274
+ // .save({
275
+ // amount: Number(amount),
276
+ // method,
277
+ // coin: method === 'crypto' ? coin : undefined,
278
+ // requisites: method === 'crypto' ? requisites.wallet : requisites.phone || requisites.card || requisites.formatted,
279
+ // user: context.user.db,
280
+ // });
281
+
282
+ // const _method = method === 'crypto' ? `Крипто-кошелек ${coin.toUpperCase()}` : method === 'sbp' ? 'Номер телефона' : 'Банковская карта';
283
+ // context.user.db.requisites = `${withdrawal.requisites} [${_method}${method === 'sbp' ? ` [${bank}]` : ''}]`;
284
+
285
+ context.user.log(0, `Заявка на вывод средств ${amountInRUB.toLocaleString('ru')} RUB`, {
286
+ // prettier-ignore
287
+ message:
288
+ `💲 <b>Сумма:</b> <i>${amount.toLocaleString('ru')} ${config.currency.toUpperCase()} (${amountInRUB.toLocaleString('ru')} RUB)</i>\n` +
289
+ `💱 <b>Метод:</b> <i>${method === 'crypto' ? `Крипто-кошелек ${coin.toUpperCase()}` : method === 'sbp' ? 'Номер телефона' : 'Банковская карта'}</i>\n` +
290
+ `🔘 <b>Реквизиты:</b> <i><code>${method === 'crypto' ? requisites.wallet : requisites.phone || requisites.card || requisites.formatted}</code>${method === 'sbp' ? ` [${bank}]` : ''}</i>`,
291
+ keyboard: [
292
+ [
293
+ {
294
+ text: '🚀 Выплатить',
295
+ callback_data: `AdminWithdrawalCommand?id=${id}&decision=1`,
296
+ },
297
+ {
298
+ text: '❌ Отказать',
299
+ callback_data: `AdminWithdrawalCommand?id=${id}&decision=0`,
300
+ },
301
+ ],
302
+ ],
303
+ });
304
+
305
+ // prettier-ignore
306
+ context.sendFormatted({
307
+ photo: method === 'crypto' ? config.images.withdrawalCrypto : config.images.withdrawal,
308
+ header:
309
+ '<blockquote><b>💸 Создана заявка на вывод средств</b></blockquote>\n\n' +
310
+
311
+ `<i>— Сумма: {{ ${amount.toLocaleString('ru')} ${config.currency.toUpperCase()} }}</i>\n` +
312
+ `<i>— Реквизиты: {{ ${method === 'crypto' ? requisites.wallet : requisites.phone || requisites.card || requisites.formatted} }}</i>\n` +
313
+ `<i>— Метод: {{ ${method === 'crypto' ? `Крипто-кошелек ${coin.toUpperCase()}` : requisites.card ? 'Банковская карта' : 'Номер телефона'} }}</i>\n` +
314
+ `<i>— Дата: {{ ${new Date().toLocaleString('ru')} }}</i>\n` +
315
+ (method === 'sbp' ? `<i>— Банк: {{ ${bank} }}</i>\n` : '') +
316
+
317
+ `\n<i>— Ваш баланс: {{ ${await (context.user.db.balance - amountInRUB).convert({ from: 'RUB', to: config.currency, round: true })} }}</i>`,
318
+ }, {
319
+ noBackButton: true,
320
+ });
321
+ }
322
+
323
+ async inlineExecute(context: InlineQueryContext) {
324
+ context.answer(
325
+ await Promise.all(
326
+ WithdrawalCommand.BANKS.map(async (x) => ({
327
+ type: 'article',
328
+ id: x[0],
329
+ title: x[0],
330
+ thumb_url: x[1] || 'https://s0.rbk.ru/v6_top_pics/media/img/6/03/754598843127036.jpeg',
331
+ input_message_content: {
332
+ message_text: x[0],
333
+ },
334
+ }))
335
+ ),
336
+ {}
337
+ );
338
+ }
339
+ }
@@ -0,0 +1 @@
1
+ export * from './Withdrawal.command';