update planned wallets function

This commit is contained in:
NW
2025-01-08 16:20:43 +00:00
parent 66f5251795
commit 5ae148a2ba
7 changed files with 278 additions and 181 deletions

View File

@@ -1,3 +1,5 @@
// database.js
import sqlite3 from 'sqlite3'; import sqlite3 from 'sqlite3';
import { promisify } from 'util'; import { promisify } from 'util';
import { dirname } from 'path'; import { dirname } from 'path';

View File

@@ -15,90 +15,145 @@ export default class AdminUserHandler {
static async calculateStatistics() { static async calculateStatistics() {
try { try {
// Получаем общую статистику по пользователям
const users = await db.allAsync(` const users = await db.allAsync(`
SELECT SELECT
u.*, u.*,
COUNT(DISTINCT p.id) as total_purchases, COUNT(DISTINCT p.id) as total_purchases,
COUNT(DISTINCT cw.id) as total_wallets COUNT(DISTINCT cw.id) as total_wallets
FROM users u FROM users u
LEFT JOIN purchases p ON u.id = p.user_id LEFT JOIN purchases p ON u.id = p.user_id
LEFT JOIN crypto_wallets cw ON u.id = cw.user_id LEFT JOIN crypto_wallets cw ON u.id = cw.user_id
LEFT JOIN transactions t ON u.id = t.user_id LEFT JOIN transactions t ON u.id = t.user_id
GROUP BY u.id GROUP BY u.id
ORDER BY u.created_at DESC ORDER BY u.created_at DESC
` ); `);
// Calculate general statistics // Общие метрики
const totalUsers = users.length; const totalUsers = users.length;
const activeUsers = users.filter(u => u.total_purchases > 0).length; const activeUsers = users.filter(u => u.total_purchases > 0).length;
const totalBalance = users.reduce((sum, u) => sum + (u.total_balance || 0), 0);
const bonusBalance = users.reduce((sum, u) => sum + (u.bonus_balance || 0), 0); const bonusBalance = users.reduce((sum, u) => sum + (u.bonus_balance || 0), 0);
const totalPurchases = users.reduce((sum, u) => sum + (u.total_purchases || 0), 0); const totalPurchases = users.reduce((sum, u) => sum + (u.total_purchases || 0), 0);
// Create statistics message // Рассчитываем общий баланс активных и архивных кошельков
let totalActiveWalletsBalance = 0;
let totalArchivedWalletsBalance = 0;
for (const user of users) {
const activeWalletsBalance = await WalletService.getActiveWalletsBalance(user.id);
const archivedWalletsBalance = await WalletService.getArchivedWalletsBalance(user.id);
totalActiveWalletsBalance += activeWalletsBalance;
totalArchivedWalletsBalance += archivedWalletsBalance;
}
// Рассчитываем общий реальный баланс (крипто + бонусы)
const totalRealBalance = totalActiveWalletsBalance + totalArchivedWalletsBalance + bonusBalance;
// Получаем статистику по транзакциям
const totalTransactions = await db.getAsync(`
SELECT COUNT(*) as total_transactions FROM transactions
`);
// Получаем статистику по продуктам
const totalProducts = await db.getAsync(`
SELECT COUNT(*) as total_products FROM products
`);
// Получаем статистику по локациям
const totalLocations = await db.getAsync(`
SELECT COUNT(*) as total_locations FROM locations
`);
// Получаем статистику по категориям
const totalCategories = await db.getAsync(`
SELECT COUNT(*) as total_categories FROM categories
`);
// Формируем сообщение со статистикой
let message = `📊 System Statistics\n\n`; let message = `📊 System Statistics\n\n`;
message += `👥 Total Users: ${totalUsers}\n`; message += `👥 Total Users: ${totalUsers}\n`;
message += `✅ Active Users: ${activeUsers}\n`; message += `✅ Active Users: ${activeUsers}\n`;
message += `💰 Bonus Balance: $${bonusBalance.toFixed(2)}\n`; message += `💰 Total All Users Balance: $${totalRealBalance.toFixed(2)}\n`;
message += `💰 Total Balance: $${(totalBalance + bonusBalance).toFixed(2)}\n`; message += ` ├ Active Wallets Balance: $${totalActiveWalletsBalance.toFixed(2)}\n`;
message += `🛍 Total Purchases: ${totalPurchases}`; message += ` ├ Archived Wallets Balance: $${totalArchivedWalletsBalance.toFixed(2)}\n`;
message += ` └ Bonus Balance: $${bonusBalance.toFixed(2)}\n`;
message += `🛍 Total Purchases: ${totalPurchases}\n`;
message += `💸 Total Transactions: ${totalTransactions.total_transactions}\n`;
message += `📦 Total Products: ${totalProducts.total_products}\n`;
message += `📍 Total Locations: ${totalLocations.total_locations}\n`;
message += `📂 Total Categories: ${totalCategories.total_categories}\n`;
return message; return message;
} catch (error) { } catch (error) {
return null console.error('Error in calculateStatistics:', error);
return 'Error loading statistics. Please try again.';
} }
} }
static async viewUserPage(page) { static async viewUserPage(page) {
const limit = 10; const limit = 10;
const offset = (page || 0) * limit; const offset = (page || 0) * limit;
const previousPage = page > 0 ? page - 1 : 0; const previousPage = page > 0 ? page - 1 : 0;
const nextPage = page + 1; const nextPage = page + 1;
try { try {
const users = await db.allAsync(` const users = await db.allAsync(`
SELECT SELECT
u.*, u.*,
COUNT(DISTINCT p.id) as total_purchases, COUNT(DISTINCT p.id) as total_purchases,
COUNT(DISTINCT cw.id) as total_wallets COUNT(DISTINCT cw.id) as total_wallets
FROM users u FROM users u
LEFT JOIN purchases p ON u.id = p.user_id LEFT JOIN purchases p ON u.id = p.user_id
LEFT JOIN crypto_wallets cw ON u.id = cw.user_id LEFT JOIN crypto_wallets cw ON u.id = cw.user_id
LEFT JOIN transactions t ON u.id = t.user_id LEFT JOIN transactions t ON u.id = t.user_id
GROUP BY u.id GROUP BY u.id
ORDER BY u.created_at DESC ORDER BY u.created_at DESC
LIMIT ? LIMIT ?
OFFSET ? OFFSET ?
`, [limit, offset]); `, [limit, offset]);
if ((users.length === 0) && (page == 0)) { if ((users.length === 0) && (page == 0)) {
return {text: 'No users registered yet.'}; return { text: 'No users registered yet.' };
} }
if ((users.length === 0) && (page > 0)) { if ((users.length === 0) && (page > 0)) {
return await this.viewUserPage(page - 1); return await this.viewUserPage(page - 1);
} }
const statistics = await this.calculateStatistics() // Calculate balances for each user
const usersWithBalances = await Promise.all(users.map(async (user) => {
const activeWalletsBalance = await WalletService.getActiveWalletsBalance(user.id);
const archivedWalletsBalance = await WalletService.getArchivedWalletsBalance(user.id);
const totalBalance = (user.total_balance || 0) + (user.bonus_balance || 0) + activeWalletsBalance + archivedWalletsBalance;
return {
...user,
activeWalletsBalance,
archivedWalletsBalance,
totalBalance
};
}));
const statistics = await this.calculateStatistics();
const message = `${statistics}\n\nSelect a user from the list below:`; const message = `${statistics}\n\nSelect a user from the list below:`;
// Create inline keyboard with user list // Create inline keyboard with user list
const keyboard = { const keyboard = {
inline_keyboard: users.map(user => [{ inline_keyboard: usersWithBalances.map(user => [{
text: `ID: ${user.telegram_id} | Nickname: ${user.username ? "@" + user.username : "None"} | Balance: $${(user.total_balance || 0) + (user.bonus_balance || 0)}`, text: `ID: ${user.telegram_id} | Nickname: ${user.username ? "@" + user.username : "None"} | Balance: $${user.totalBalance.toFixed(2)}`,
callback_data: `view_user_${user.telegram_id}` callback_data: `view_user_${user.telegram_id}`
}]) }])
}; };
keyboard.inline_keyboard.push([ keyboard.inline_keyboard.push([
{text: `«`, callback_data: `list_users_${previousPage}`}, { text: `«`, callback_data: `list_users_${previousPage}` },
{text: `»`, callback_data: `list_users_${nextPage}`}, { text: `»`, callback_data: `list_users_${nextPage}` },
]) ]);
return {text: message, markup: keyboard} return { text: message, markup: keyboard };
} catch (error) { } catch (error) {
console.error('Error in handleUserList:', error); console.error('Error in handleUserList:', error);
return {text: 'Error loading user list. Please try again.'} return { text: 'Error loading user list. Please try again.' };
} }
} }
@@ -135,19 +190,19 @@ export default class AdminUserHandler {
static async handleViewUser(callbackQuery) { static async handleViewUser(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) return; if (!this.isAdmin(callbackQuery.from.id)) return;
const telegramId = callbackQuery.data.replace('view_user_', ''); const telegramId = callbackQuery.data.replace('view_user_', '');
const chatId = callbackQuery.message.chat.id; const chatId = callbackQuery.message.chat.id;
try { try {
const detailedUser = await UserService.getDetailedUserByTelegramId(telegramId); const detailedUser = await UserService.getDetailedUserByTelegramId(telegramId);
const user = await UserService.getUserByTelegramId(telegramId); const user = await UserService.getUserByTelegramId(telegramId);
if (!detailedUser) { if (!detailedUser) {
await bot.sendMessage(chatId, 'User not found.'); await bot.sendMessage(chatId, 'User not found.');
return; return;
} }
// Get recent transactions // Get recent transactions
const transactions = await db.allAsync(` const transactions = await db.allAsync(`
SELECT t.amount, t.created_at, t.wallet_type, t.tx_hash SELECT t.amount, t.created_at, t.wallet_type, t.tx_hash
@@ -157,7 +212,7 @@ export default class AdminUserHandler {
ORDER BY t.created_at DESC ORDER BY t.created_at DESC
LIMIT 5 LIMIT 5
`, [telegramId]); `, [telegramId]);
// Get recent purchases // Get recent purchases
const purchases = await db.allAsync(` const purchases = await db.allAsync(`
SELECT p.quantity, p.total_price, p.purchase_date, SELECT p.quantity, p.total_price, p.purchase_date,
@@ -169,7 +224,7 @@ export default class AdminUserHandler {
ORDER BY p.purchase_date DESC ORDER BY p.purchase_date DESC
LIMIT 5 LIMIT 5
`, [telegramId]); `, [telegramId]);
// Get pending purchases // Get pending purchases
const pendingPurchases = await db.allAsync(` const pendingPurchases = await db.allAsync(`
SELECT p.quantity, p.total_price, p.purchase_date, SELECT p.quantity, p.total_price, p.purchase_date,
@@ -180,37 +235,40 @@ export default class AdminUserHandler {
WHERE u.telegram_id = ? AND p.status = 'pending' WHERE u.telegram_id = ? AND p.status = 'pending'
ORDER BY p.purchase_date DESC ORDER BY p.purchase_date DESC
`, [telegramId]); `, [telegramId]);
// Get wallet balances // Get wallet balances
const activeWalletsBalance = await WalletService.getActiveWalletsBalance(user.id); const activeWalletsBalance = await WalletService.getActiveWalletsBalance(user.id);
const archivedWalletsBalance = await WalletService.getArchivedWalletsBalance(user.id); const archivedWalletsBalance = await WalletService.getArchivedWalletsBalance(user.id);
// Общий баланс (крипто + бонусы + total_balance)
const totalBalance = activeWalletsBalance + archivedWalletsBalance + user.bonus_balance + (user.total_balance || 0);
const message = ` const message = `
👤 User Profile: 👤 User Profile:
ID: ${telegramId} ID: ${telegramId}
📍 Location: ${detailedUser.country || 'Not set'}, ${detailedUser.city || 'Not set'}, ${detailedUser.district || 'Not set'} 📍 Location: ${detailedUser.country || 'Not set'}, ${detailedUser.city || 'Not set'}, ${detailedUser.district || 'Not set'}
📊 Activity: 📊 Activity:
- Total Purchases: ${detailedUser.purchase_count} - Total Purchases: ${detailedUser.purchase_count}
- Total Spent: $${detailedUser.total_spent || 0} - Total Spent: $${detailedUser.total_spent || 0}
- Active Wallets: ${detailedUser.crypto_wallet_count} ($${activeWalletsBalance.toFixed(2)}) - Active Wallets: ${detailedUser.crypto_wallet_count} ($${activeWalletsBalance.toFixed(2)})
- Archived Wallets: ${detailedUser.archived_wallet_count} ($${archivedWalletsBalance.toFixed(2)}) - Archived Wallets: ${detailedUser.archived_wallet_count} ($${archivedWalletsBalance.toFixed(2)})
- Bonus Balance: $${user.bonus_balance || 0} - Bonus Balance: $${user.bonus_balance || 0}
- Total Balance: $${((user.total_balance || 0) + (user.bonus_balance || 0)).toFixed(2)} - Total Balance: $${totalBalance.toFixed(2)}
💰 Recent Transactions (Last 5 of ${transactions.length}): 💰 Recent Transactions (Last 5 of ${transactions.length}):
${transactions.map(t => `$${t.amount} ${t.wallet_type} (${t.tx_hash}) at ${new Date(t.created_at).toLocaleString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' })}`).join('\n')} ${transactions.map(t => `$${t.amount} ${t.wallet_type} (${t.tx_hash}) at ${new Date(t.created_at).toLocaleString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' })}`).join('\n')}
🛍 Recent Purchases (Last 5 of ${purchases.length}): 🛍 Recent Purchases (Last 5 of ${purchases.length}):
${purchases.map(p => `${p.product_name} x${p.quantity} - $${p.total_price}`).join('\n')} ${purchases.map(p => `${p.product_name} x${p.quantity} - $${p.total_price}`).join('\n')}
🕒 Pending Purchases: 🕒 Pending Purchases:
${pendingPurchases.map(p => `${p.product_name} x${p.quantity} - $${p.total_price}`).join('\n') || ' • No pending purchases'} ${pendingPurchases.map(p => `${p.product_name} x${p.quantity} - $${p.total_price}`).join('\n') || ' • No pending purchases'}
📅 Registered: ${new Date(detailedUser.created_at).toLocaleString()} 📅 Registered: ${new Date(detailedUser.created_at).toLocaleString()}
`; `;
const keyboard = { const keyboard = {
inline_keyboard: [ inline_keyboard: [
[ [
@@ -224,7 +282,7 @@ ${pendingPurchases.map(p => ` • ${p.product_name} x${p.quantity} - $${p.total
[{text: '« Back to User List', callback_data: `list_users_0`}] [{text: '« Back to User List', callback_data: `list_users_0`}]
] ]
}; };
await bot.editMessageText(message, { await bot.editMessageText(message, {
chat_id: chatId, chat_id: chatId,
message_id: callbackQuery.message.message_id, message_id: callbackQuery.message.message_id,

View File

@@ -43,22 +43,22 @@ export default class AdminWalletsHandler {
const action = callbackQuery.data; const action = callbackQuery.data;
const chatId = callbackQuery.message.chat.id; const chatId = callbackQuery.message.chat.id;
const walletType = action.split('_').pop(); const walletType = action.split('_').pop();
try { try {
// Удаляем предыдущее сообщение перед отправкой нового // Удаляем предыдущее сообщение перед отправкой нового
await bot.deleteMessage(chatId, callbackQuery.message.message_id); await bot.deleteMessage(chatId, callbackQuery.message.message_id);
// Получаем все кошельки выбранного типа // Получаем все кошельки выбранного типа (активные и архивные)
const wallets = await WalletService.getWalletsByType(walletType); const wallets = await WalletService.getWalletsByType(walletType);
if (wallets.length === 0) { if (wallets.length === 0) {
await bot.sendMessage(chatId, `No wallets found for ${walletType}.`); await bot.sendMessage(chatId, `No wallets found for ${walletType}.`);
return; return;
} }
// Вычисляем суммарный баланс // Вычисляем суммарный баланс
const totalBalance = await this.calculateTotalBalance(wallets); const totalBalance = await this.calculateTotalBalance(wallets);
// Отображаем первую страницу с пагинацией // Отображаем первую страницу с пагинацией
await this.displayWalletsPage(chatId, wallets, walletType, totalBalance, 0); await this.displayWalletsPage(chatId, wallets, walletType, totalBalance, 0);
} catch (error) { } catch (error) {
@@ -72,7 +72,7 @@ export default class AdminWalletsHandler {
const startIndex = page * pageSize; const startIndex = page * pageSize;
const endIndex = startIndex + pageSize; const endIndex = startIndex + pageSize;
const walletsPage = wallets.slice(startIndex, endIndex); const walletsPage = wallets.slice(startIndex, endIndex);
// Формируем список кошельков с балансами // Формируем список кошельков с балансами
let walletList = ''; let walletList = '';
for (const wallet of walletsPage) { for (const wallet of walletsPage) {
@@ -83,16 +83,17 @@ export default class AdminWalletsHandler {
null, // userId не нужен для админки null, // userId не нужен для админки
Date.now() - 30 * 24 * 60 * 60 * 1000 Date.now() - 30 * 24 * 60 * 60 * 1000
); );
const balances = await walletUtilsInstance.getAllBalances(); const balances = await walletUtilsInstance.getAllBalances();
const balance = balances[wallet.wallet_type] || { amount: 0, usdValue: 0 }; const baseType = WalletUtils.getBaseWalletType(wallet.wallet_type);
const balance = balances[baseType] || { amount: 0, usdValue: 0 };
walletList += `💰 *${wallet.wallet_type}*\n`; walletList += `💰 *${wallet.wallet_type}*\n`;
walletList += `├ Balance: ${balance.amount.toFixed(8)} ${wallet.wallet_type}\n`; walletList += `├ Balance: ${balance.amount.toFixed(8)} ${wallet.wallet_type}\n`;
walletList += `├ Value: $${balance.usdValue.toFixed(2)}\n`; walletList += `├ Value: $${balance.usdValue.toFixed(2)}\n`;
walletList += `└ Address: \`${wallet.address}\`\n\n`; walletList += `└ Address: \`${wallet.address}\`\n\n`;
} }
// Создаем клавиатуру с пагинацией // Создаем клавиатуру с пагинацией
const keyboard = { const keyboard = {
inline_keyboard: [ inline_keyboard: [
@@ -106,17 +107,17 @@ export default class AdminWalletsHandler {
] ]
] ]
}; };
// Убираем кнопку "Назад", если это первая страница // Убираем кнопку "Назад", если это первая страница
if (page === 0) { if (page === 0) {
keyboard.inline_keyboard[0].shift(); keyboard.inline_keyboard[0].shift();
} }
// Убираем кнопку "Далее", если это последняя страница // Убираем кнопку "Далее", если это последняя страница
if (endIndex >= wallets.length) { if (endIndex >= wallets.length) {
keyboard.inline_keyboard[0].pop(); keyboard.inline_keyboard[0].pop();
} }
// Отправляем сообщение с суммарным балансом и списком кошельков // Отправляем сообщение с суммарным балансом и списком кошельков
await bot.sendMessage( await bot.sendMessage(
chatId, chatId,
@@ -139,12 +140,13 @@ export default class AdminWalletsHandler {
null, // userId не нужен для админки null, // userId не нужен для админки
Date.now() - 30 * 24 * 60 * 60 * 1000 Date.now() - 30 * 24 * 60 * 60 * 1000
); );
const balances = await walletUtilsInstance.getAllBalances(); const balances = await walletUtilsInstance.getAllBalances();
const balance = balances[wallet.wallet_type] || { usdValue: 0 }; const baseType = WalletUtils.getBaseWalletType(wallet.wallet_type);
const balance = balances[baseType] || { usdValue: 0 };
totalBalance += balance.usdValue; totalBalance += balance.usdValue;
} }
return totalBalance; return totalBalance;
} }

View File

@@ -1,6 +1,9 @@
// userHandler.js
import config from "../../config/config.js"; import config from "../../config/config.js";
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
import UserService from "../../services/userService.js"; import UserService from "../../services/userService.js";
import WalletService from "../../services/walletService.js";
export default class UserHandler { export default class UserHandler {
static async canUseBot(msg) { static async canUseBot(msg) {
@@ -30,44 +33,51 @@ export default class UserHandler {
static async showProfile(msg) { static async showProfile(msg) {
const chatId = msg.chat.id; const chatId = msg.chat.id;
const telegramId = msg.from.id; const telegramId = msg.from.id;
try { try {
await UserService.recalculateUserBalanceByTelegramId(telegramId); await UserService.recalculateUserBalanceByTelegramId(telegramId);
const userStats = await UserService.getDetailedUserByTelegramId(telegramId); const userStats = await UserService.getDetailedUserByTelegramId(telegramId);
if (!userStats) { if (!userStats) {
await bot.sendMessage(chatId, 'Profile not found. Please use /start to create one.'); await bot.sendMessage(chatId, 'Profile not found. Please use /start to create one.');
return; return;
} }
// Получаем балансы активных и архивных кошельков
const activeWalletsBalance = await WalletService.getActiveWalletsBalance(userStats.id);
const archivedWalletsBalance = await WalletService.getArchivedWalletsBalance(userStats.id);
// Общий баланс (крипто + бонусы + total_balance)
const totalBalance = activeWalletsBalance + archivedWalletsBalance + userStats.bonus_balance + (userStats.total_balance || 0);
const locationText = userStats.country && userStats.city && userStats.district const locationText = userStats.country && userStats.city && userStats.district
? `${userStats.country}, ${userStats.city}, ${userStats.district}` ? `${userStats.country}, ${userStats.city}, ${userStats.district}`
: 'Not set'; : 'Not set';
const text = ` const text = `
👤 *Your Profile* 👤 *Your Profile*
📱 Telegram ID: \`${telegramId}\` 📱 Telegram ID: \`${telegramId}\`
📍 Location: ${locationText} 📍 Location: ${locationText}
📊 Statistics: 📊 Statistics:
├ Total Purchases: ${userStats.purchase_count || 0} ├ Total Purchases: ${userStats.purchase_count || 0}
├ Total Spent: $${userStats.total_spent || 0} ├ Total Spent: $${userStats.total_spent || 0}
├ Active Wallets: ${userStats.crypto_wallet_count || 0} ├ Active Wallets: ${userStats.crypto_wallet_count || 0} ($${activeWalletsBalance.toFixed(2)})
├ Archived Wallets: ${userStats.archived_wallet_count || 0} ├ Archived Wallets: ${userStats.archived_wallet_count || 0} ($${archivedWalletsBalance.toFixed(2)})
├ Bonus Balance: $${userStats.bonus_balance || 0} ├ Bonus Balance: $${userStats.bonus_balance || 0}
└ Available Balance: $${(userStats.total_balance || 0) + (userStats.bonus_balance || 0)} └ Available Balance: $${totalBalance.toFixed(2)}
📅 Member since: ${new Date(userStats.created_at).toLocaleDateString()} 📅 Member since: ${new Date(userStats.created_at).toLocaleDateString()}
`; `;
const keyboard = { const keyboard = {
inline_keyboard: [ inline_keyboard: [
[{text: '📍 Set Location', callback_data: 'set_location'}], [{text: '📍 Set Location', callback_data: 'set_location'}],
[{text: '❌ Delete Account', callback_data: 'delete_account'}] [{text: '❌ Delete Account', callback_data: 'delete_account'}]
] ]
}; };
await bot.sendMessage(chatId, text, { await bot.sendMessage(chatId, text, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
reply_markup: keyboard reply_markup: keyboard

View File

@@ -1,3 +1,5 @@
// userWalletsHandler.js
import db from '../../config/database.js'; import db from '../../config/database.js';
import WalletGenerator from '../../utils/walletGenerator.js'; import WalletGenerator from '../../utils/walletGenerator.js';
import WalletUtils from '../../utils/walletUtils.js'; import WalletUtils from '../../utils/walletUtils.js';
@@ -27,7 +29,7 @@ export default class UserWalletsHandler {
// Получаем активные криптокошельки // Получаем активные криптокошельки
const cryptoWallets = await db.allAsync(` const cryptoWallets = await db.allAsync(`
SELECT wallet_type, address SELECT wallet_type, address, balance
FROM crypto_wallets FROM crypto_wallets
WHERE user_id = ? WHERE user_id = ?
ORDER BY wallet_type ORDER BY wallet_type
@@ -42,11 +44,10 @@ export default class UserWalletsHandler {
cryptoWallets.find(w => w.wallet_type === 'ETH')?.address, // ETH address cryptoWallets.find(w => w.wallet_type === 'ETH')?.address, // ETH address
cryptoWallets.find(w => w.wallet_type === 'USDT')?.address, // USDT address cryptoWallets.find(w => w.wallet_type === 'USDT')?.address, // USDT address
cryptoWallets.find(w => w.wallet_type === 'USDC')?.address, // USDC address cryptoWallets.find(w => w.wallet_type === 'USDC')?.address, // USDC address
updatedUser.id, updatedUser.id
Date.now() - 30 * 24 * 60 * 60 * 1000
); );
const balances = await walletUtilsInstance.getAllBalances(); const balances = await walletUtilsInstance.getAllBalancesFromDB();
let totalUsdValue = 0; let totalUsdValue = 0;
// Отображаем активные кошельки // Отображаем активные кошельки
@@ -68,12 +69,12 @@ export default class UserWalletsHandler {
// Бонусный баланс // Бонусный баланс
message += `🎁 *Bonus Balance:* $${updatedUser.bonus_balance.toFixed(2)}\n`; message += `🎁 *Bonus Balance:* $${updatedUser.bonus_balance.toFixed(2)}\n`;
// Общий баланс (крипто + бонусы) // Общий баланс (крипто + бонусы + total_balance)
const totalBalance = totalUsdValue + updatedUser.bonus_balance; const totalBalance = totalUsdValue + updatedUser.bonus_balance + (updatedUser.total_balance || 0);
message += `💰 *Total Balance:* $${totalBalance.toFixed(2)}\n`; message += `💰 *Total Balance:* $${totalBalance.toFixed(2)}\n`;
// Доступный баланс (общий баланс минус расходы на покупки) // Доступный баланс (общий баланс минус расходы на покупки)
const availableBalance = updatedUser.total_balance + updatedUser.bonus_balance; const availableBalance = totalBalance; // Теперь availableBalance включает криптобаланс
message += `💳 *Available Balance:* $${availableBalance.toFixed(2)}\n`; message += `💳 *Available Balance:* $${availableBalance.toFixed(2)}\n`;
} else { } else {
message = 'You don\'t have any active wallets yet.'; message = 'You don\'t have any active wallets yet.';
@@ -112,7 +113,7 @@ export default class UserWalletsHandler {
console.error('Error in showBalance:', error); console.error('Error in showBalance:', error);
await bot.sendMessage(chatId, 'Error loading balance. Please try again.'); await bot.sendMessage(chatId, 'Error loading balance. Please try again.');
} }
} }
static async handleTransactionHistory(callbackQuery, page = 0) { static async handleTransactionHistory(callbackQuery, page = 0) {
const chatId = callbackQuery.message.chat.id; const chatId = callbackQuery.message.chat.id;
@@ -259,10 +260,10 @@ export default class UserWalletsHandler {
case 'ETH': case 'ETH':
address = walletAddresses.eth; address = walletAddresses.eth;
break; break;
case 'USDT ERC-20': case 'USDT':
address = walletAddresses.usdt; address = walletAddresses.usdt;
break; break;
case 'USDC ERC-20': case 'USDC':
address = walletAddresses.usdc; address = walletAddresses.usdc;
break; break;
default: default:

View File

@@ -22,58 +22,80 @@ class WalletService {
static async getActiveWalletsBalance(userId) { static async getActiveWalletsBalance(userId) {
try { try {
const wallets = await db.allAsync( const wallets = await db.allAsync(
`SELECT wallet_type, address `SELECT wallet_type, balance
FROM crypto_wallets FROM crypto_wallets
WHERE user_id = ? AND wallet_type NOT LIKE '%#_%' ESCAPE '#'`, WHERE user_id = ? AND wallet_type NOT LIKE '%#_%' ESCAPE '#'`,
[userId] [userId]
); );
const prices = await WalletUtils.getCryptoPrices();
let totalBalance = 0; let totalBalance = 0;
for (const wallet of wallets) { for (const wallet of wallets) {
const walletUtils = new WalletUtils( const baseType = WalletUtils.getBaseWalletType(wallet.wallet_type);
wallet.wallet_type === 'BTC' ? wallet.address : null, const balance = wallet.balance || 0;
wallet.wallet_type === 'LTC' ? wallet.address : null,
wallet.wallet_type === 'ETH' ? wallet.address : null, switch (baseType) {
wallet.wallet_type === 'USDT' ? wallet.address : null, case 'BTC':
wallet.wallet_type === 'USDC' ? wallet.address : null, totalBalance += balance * prices.btc;
userId break;
); case 'LTC':
totalBalance += balance * prices.ltc;
const balances = await walletUtils.getAllBalances(); break;
totalBalance += balances[wallet.wallet_type]?.usdValue || 0; case 'ETH':
totalBalance += balance * prices.eth;
break;
case 'USDT':
totalBalance += balance; // USDT is 1:1 with USD
break;
case 'USDC':
totalBalance += balance; // USDC is 1:1 with USD
break;
}
} }
return totalBalance; return totalBalance;
} catch (error) { } catch (error) {
console.error('Error fetching active wallets balance:', error); console.error('Error fetching active wallets balance:', error);
throw new Error('Failed to fetch active wallets balance'); throw new Error('Failed to fetch active wallets balance');
} }
} }
static async getArchivedWalletsBalance(userId) { static async getArchivedWalletsBalance(userId) {
try { try {
const wallets = await db.allAsync( const wallets = await db.allAsync(
`SELECT wallet_type, address `SELECT wallet_type, balance
FROM crypto_wallets FROM crypto_wallets
WHERE user_id = ? AND wallet_type LIKE '%#_%' ESCAPE '#'`, WHERE user_id = ? AND wallet_type LIKE '%#_%' ESCAPE '#'`,
[userId] [userId]
); );
const prices = await WalletUtils.getCryptoPrices();
let totalBalance = 0; let totalBalance = 0;
for (const wallet of wallets) { for (const wallet of wallets) {
const walletUtils = new WalletUtils( const baseType = WalletUtils.getBaseWalletType(wallet.wallet_type);
wallet.wallet_type === 'BTC' ? wallet.address : null, const balance = wallet.balance || 0;
wallet.wallet_type === 'LTC' ? wallet.address : null,
wallet.wallet_type === 'ETH' ? wallet.address : null, switch (baseType) {
wallet.wallet_type === 'USDT' ? wallet.address : null, case 'BTC':
wallet.wallet_type === 'USDC' ? wallet.address : null, totalBalance += balance * prices.btc;
userId break;
); case 'LTC':
totalBalance += balance * prices.ltc;
const balances = await walletUtils.getAllBalances(); break;
totalBalance += balances[wallet.wallet_type]?.usdValue || 0; case 'ETH':
totalBalance += balance * prices.eth;
break;
case 'USDT':
totalBalance += balance; // USDT is 1:1 with USD
break;
case 'USDC':
totalBalance += balance; // USDC is 1:1 with USD
break;
}
} }
return totalBalance; return totalBalance;
} catch (error) { } catch (error) {
console.error('Error fetching archived wallets balance:', error); console.error('Error fetching archived wallets balance:', error);
@@ -87,10 +109,10 @@ class WalletService {
const wallets = await db.allAsync( const wallets = await db.allAsync(
`SELECT * `SELECT *
FROM crypto_wallets FROM crypto_wallets
WHERE wallet_type = ?`, WHERE wallet_type = ? OR wallet_type LIKE ?`,
[walletType] [walletType, `${walletType}_%`]
); );
return wallets; return wallets;
} catch (error) { } catch (error) {
console.error('Error fetching wallets by type:', error); console.error('Error fetching wallets by type:', error);

View File

@@ -1,3 +1,5 @@
// walletUtils.js
import axios from 'axios'; import axios from 'axios';
import db from '../config/database.js'; // Импортируем базу данных import db from '../config/database.js'; // Импортируем базу данных
@@ -264,24 +266,24 @@ export default class WalletUtils {
async getAllBalancesFromDB() { async getAllBalancesFromDB() {
const prices = await WalletUtils.getCryptoPrices(); const prices = await WalletUtils.getCryptoPrices();
const balances = { const balances = {
BTC: { amount: 0, usdValue: 0 }, BTC: { amount: 0, usdValue: 0 },
LTC: { amount: 0, usdValue: 0 }, LTC: { amount: 0, usdValue: 0 },
ETH: { amount: 0, usdValue: 0 }, ETH: { amount: 0, usdValue: 0 },
'USDT ERC-20': { amount: 0, usdValue: 0 }, USDT: { amount: 0, usdValue: 0 },
'USDC ERC-20': { amount: 0, usdValue: 0 } USDC: { amount: 0, usdValue: 0 }
}; };
// Получаем балансы из таблицы crypto_wallets // Получаем балансы из таблицы crypto_wallets
const wallets = await db.allAsync(` const wallets = await db.allAsync(`
SELECT wallet_type, balance FROM crypto_wallets WHERE user_id = ? SELECT wallet_type, balance FROM crypto_wallets WHERE user_id = ?
`, [this.userId]); `, [this.userId]);
for (const wallet of wallets) { for (const wallet of wallets) {
const baseType = WalletUtils.getBaseWalletType(wallet.wallet_type); const [baseType] = wallet.wallet_type.split('_'); // Учитываем только базовый тип
const balance = wallet.balance || 0; const balance = wallet.balance || 0;
switch (baseType) { switch (baseType) {
case 'BTC': case 'BTC':
balances.BTC.amount += balance; balances.BTC.amount += balance;
@@ -296,16 +298,16 @@ export default class WalletUtils {
balances.ETH.usdValue += balance * prices.eth; balances.ETH.usdValue += balance * prices.eth;
break; break;
case 'USDT': case 'USDT':
balances['USDT ERC-20'].amount += balance; balances.USDT.amount += balance;
balances['USDT ERC-20'].usdValue += balance; balances.USDT.usdValue += balance;
break; break;
case 'USDC': case 'USDC':
balances['USDC ERC-20'].amount += balance; balances.USDC.amount += balance;
balances['USDC ERC-20'].usdValue += balance; balances.USDC.usdValue += balance;
break; break;
} }
} }
return balances; return balances;
} }
@@ -315,7 +317,7 @@ export default class WalletUtils {
async getAllBalancesExt() { async getAllBalancesExt() {
console.log('[DEBUG] getAllBalancesExt called'); // Логируем вызов метода console.log('[DEBUG] getAllBalancesExt called'); // Логируем вызов метода
const [ const [
btcBalance, btcBalance,
ltcBalance, ltcBalance,
@@ -331,7 +333,7 @@ export default class WalletUtils {
this.getUsdcErc20Balance(), this.getUsdcErc20Balance(),
WalletUtils.getCryptoPrices() WalletUtils.getCryptoPrices()
]); ]);
console.log('[DEBUG] Balances fetched:', { // Логируем полученные балансы console.log('[DEBUG] Balances fetched:', { // Логируем полученные балансы
btcBalance, btcBalance,
ltcBalance, ltcBalance,
@@ -340,13 +342,13 @@ export default class WalletUtils {
usdcErc20Balance, usdcErc20Balance,
prices prices
}); });
return { return {
BTC: { amount: btcBalance, usdValue: btcBalance * prices.btc }, BTC: { amount: btcBalance, usdValue: btcBalance * prices.btc },
LTC: { amount: ltcBalance, usdValue: ltcBalance * prices.ltc }, LTC: { amount: ltcBalance, usdValue: ltcBalance * prices.ltc },
ETH: { amount: ethBalance, usdValue: ethBalance * prices.eth }, ETH: { amount: ethBalance, usdValue: ethBalance * prices.eth },
'USDT ERC-20': { amount: usdtErc20Balance, usdValue: usdtErc20Balance }, USDT: { amount: usdtErc20Balance, usdValue: usdtErc20Balance },
'USDC ERC-20': { amount: usdcErc20Balance, usdValue: usdcErc20Balance } USDC: { amount: usdcErc20Balance, usdValue: usdcErc20Balance }
}; };
} }
} }