diff --git a/src/handlers/userHandlers/userHandler.js b/src/handlers/userHandlers/userHandler.js index a5948bf..60d3f39 100644 --- a/src/handlers/userHandlers/userHandler.js +++ b/src/handlers/userHandlers/userHandler.js @@ -47,8 +47,8 @@ export default class UserHandler { 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); + // Доступный баланс (bonus_balance + total_balance) + const availableBalance = userStats.bonus_balance + (userStats.total_balance || 0); const locationText = userStats.country && userStats.city && userStats.district ? `${userStats.country}, ${userStats.city}, ${userStats.district}` @@ -66,7 +66,7 @@ export default class UserHandler { ├ Active Wallets: ${userStats.crypto_wallet_count || 0} ($${activeWalletsBalance.toFixed(2)}) ├ Archived Wallets: ${userStats.archived_wallet_count || 0} ($${archivedWalletsBalance.toFixed(2)}) ├ Bonus Balance: $${userStats.bonus_balance || 0} - └ Available Balance: $${totalBalance.toFixed(2)} + └ Available Balance: $${availableBalance.toFixed(2)} 📅 Member since: ${new Date(userStats.created_at).toLocaleDateString()} `; diff --git a/src/handlers/userHandlers/userPurchaseHandler.js b/src/handlers/userHandlers/userPurchaseHandler.js index 7889a4f..990793b 100644 --- a/src/handlers/userHandlers/userPurchaseHandler.js +++ b/src/handlers/userHandlers/userPurchaseHandler.js @@ -248,26 +248,21 @@ export default class UserPurchaseHandler { return; } - // Логируем данные для отладки - console.log('Purchase data:', purchase); - console.log('User data:', user); - // Обновляем статус покупки в базе данных await PurchaseService.updatePurchaseStatus(purchaseId, 'received'); - // Добавляем транзакцию в таблицу transactions - await db.runAsync(` - INSERT INTO transactions (user_id, wallet_type, tx_hash, amount, created_at) - VALUES (?, ?, ?, ?, ?) - `, [ - user.id, // ID пользователя - purchase.wallet_type || 'unknown', // Тип кошелька (если не указан, то "unknown") - purchase.tx_hash || 'no_hash', // Хеш транзакции (если не указан, то "no_hash") - purchase.total_price, // Сумма транзакции - new Date().toISOString() // Дата создания транзакции - ]); - - console.log('Transaction added successfully'); // Логируем успешную вставку + // Добавляем запись в таблицу transactions + await db.runAsync( + `INSERT INTO transactions (user_id, wallet_type, tx_hash, amount, created_at) + VALUES (?, ?, ?, ?, ?)`, + [ + user.id, // ID пользователя + purchase.wallet_type, // Источник списания (например, "bonus_50, crypto_30") + purchase.tx_hash || 'no_hash', // Хеш транзакции (если не указан, то "no_hash") + purchase.total_price, // Сумма транзакции + new Date().toISOString() // Дата создания транзакции + ] + ); // Отправляем уведомление администраторам const adminIds = config.ADMIN_IDS; // Используем массив ADMIN_IDS diff --git a/src/handlers/userHandlers/userWalletsHandler.js b/src/handlers/userHandlers/userWalletsHandler.js index b6f1521..6583f4a 100644 --- a/src/handlers/userHandlers/userWalletsHandler.js +++ b/src/handlers/userHandlers/userWalletsHandler.js @@ -69,13 +69,9 @@ export default class UserWalletsHandler { // Бонусный баланс message += `🎁 *Bonus Balance:* $${updatedUser.bonus_balance.toFixed(2)}\n`; - // Общий баланс (крипто + бонусы + total_balance) - const totalBalance = totalUsdValue + updatedUser.bonus_balance + (updatedUser.total_balance || 0); - message += `💰 *Total Balance:* $${totalBalance.toFixed(2)}\n`; - - // Доступный баланс (общий баланс минус расходы на покупки) - const availableBalance = totalBalance; // Теперь availableBalance включает криптобаланс - message += `💳 *Available Balance:* $${availableBalance.toFixed(2)}\n`; + // Доступный баланс (bonus_balance + total_balance) + const availableBalance = updatedUser.bonus_balance + (updatedUser.total_balance || 0); + message += `💰 *Available Balance:* $${availableBalance.toFixed(2)}\n`; } else { message = 'You don\'t have any active wallets yet.'; } diff --git a/src/services/purchaseService.js b/src/services/purchaseService.js index e143121..95cb541 100644 --- a/src/services/purchaseService.js +++ b/src/services/purchaseService.js @@ -2,6 +2,8 @@ import db from "../config/database.js"; import CryptoJS from "crypto-js"; // Импортируем библиотеку crypto-js +import UserService from "../services/userService.js"; + class PurchaseService { static async getPurchasesByUserId(userId, limit, offset) { try { @@ -42,16 +44,62 @@ class PurchaseService { static async createPurchase(userId, productId, walletType, quantity, totalPrice) { try { + const user = await UserService.getUserByUserId(userId); + if (!user) { + throw new Error('User not found'); + } + + // Обновляем крипто-баланс пользователя перед началом покупки + await UserService.recalculateUserBalanceByTelegramId(user.telegram_id); + + let remainingAmount = totalPrice; + let usedBonus = 0; + let usedCrypto = 0; + let sourceWalletType = ''; + + // Сначала списываем с бонусного баланса + if (user.bonus_balance > 0) { + usedBonus = Math.min(user.bonus_balance, remainingAmount); + remainingAmount -= usedBonus; + + // Обновляем бонусный баланс пользователя + await db.runAsync( + 'UPDATE users SET bonus_balance = bonus_balance - ? WHERE id = ?', + [usedBonus, userId] + ); + + // Добавляем информацию о списании с бонусного баланса + sourceWalletType += `bonus_${usedBonus}`; + } + + // Если осталась сумма, списываем с крипто-баланса + if (remainingAmount > 0) { + usedCrypto = remainingAmount; + + // Обновляем крипто-баланс пользователя + await db.runAsync( + 'UPDATE users SET total_balance = total_balance - ? WHERE id = ?', + [usedCrypto, userId] + ); + + // Добавляем информацию о списании с крипто-баланса + if (sourceWalletType) { + sourceWalletType += `, crypto_${usedCrypto}`; + } else { + sourceWalletType = `crypto_${usedCrypto}`; + } + } + // Генерируем MD5-хеш для tx_hash const txHash = CryptoJS.MD5(Date.now().toString()).toString(); - - // Вставка новой покупки в базу данных + + // Вставляем новую покупку в базу данных const result = await db.runAsync( `INSERT INTO purchases (user_id, product_id, wallet_type, quantity, total_price, purchase_date, tx_hash) VALUES (?, ?, ?, ?, ?, ?, ?)`, - [userId, productId, walletType, quantity, totalPrice, new Date().toISOString(), txHash] + [userId, productId, sourceWalletType, quantity, totalPrice, new Date().toISOString(), txHash] ); - + // Возвращаем ID новой покупки return result.lastID; } catch (error) { @@ -62,6 +110,29 @@ class PurchaseService { static async updatePurchaseStatus(purchaseId, status) { try { + const purchase = await this.getPurchaseById(purchaseId); + if (!purchase) { + throw new Error('Purchase not found'); + } + + if (status === 'canceled') { + const user = await UserService.getUserByUserId(purchase.user_id); + + // Возвращаем средства на бонусный или крипто-баланс + if (purchase.wallet_type === 'bonus') { + await db.runAsync( + 'UPDATE users SET bonus_balance = bonus_balance + ? WHERE id = ?', + [purchase.total_price, user.id] + ); + } else { + await db.runAsync( + 'UPDATE users SET total_balance = total_balance + ? WHERE id = ?', + [purchase.total_price, user.id] + ); + } + } + + // Обновляем статус покупки await db.runAsync( 'UPDATE purchases SET status = ? WHERE id = ?', [status, purchaseId] diff --git a/src/services/userService.js b/src/services/userService.js index be7f7c8..430c7d8 100644 --- a/src/services/userService.js +++ b/src/services/userService.js @@ -1,5 +1,9 @@ +// userService.js + import db from "../config/database.js"; import Wallet from "../models/Wallet.js"; +import WalletUtils from "../utils/walletUtils.js"; + class UserService { // Функция для нормализации telegram_id @@ -119,22 +123,50 @@ class UserService { static async recalculateUserBalanceByTelegramId(telegramId) { const normalizedTelegramId = this.normalizeTelegramId(telegramId); const user = await this.getUserByTelegramId(normalizedTelegramId); - + if (!user) { return; } - - const archivedBalance = await Wallet.getArchivedWalletsBalance(user.id); - const activeBalance = await Wallet.getActiveWalletsBalance(user.id); - - const purchases = await db.getAsync( - `SELECT SUM(total_price) as total_sum FROM purchases WHERE user_id = ?`, - [user.id] - ); - - const userTotalBalance = (activeBalance + archivedBalance) - (purchases?.total_sum || 0); - - await db.runAsync(`UPDATE users SET total_balance = ? WHERE id = ?`, [userTotalBalance, user.id]); + + try { + // Получаем все крипто-балансы пользователя + const cryptoBalances = await db.allAsync( + `SELECT wallet_type, balance FROM crypto_wallets WHERE user_id = ?`, + [user.id] + ); + + // Получаем актуальные курсы криптовалют + const prices = await WalletUtils.getCryptoPrices(); + + // Пересчитываем балансы в доллары + let totalCryptoBalance = 0; + for (const wallet of cryptoBalances) { + const baseType = WalletUtils.getBaseWalletType(wallet.wallet_type); // Убираем суффиксы + const rate = prices[baseType.toLowerCase()] || 0; // Получаем курс для базового типа + totalCryptoBalance += wallet.balance * rate; + } + + // Получаем сумму всех покупок в крипте + const cryptoPurchases = await db.getAsync( + `SELECT SUM(total_price) as total_sum FROM purchases + WHERE user_id = ? AND wallet_type LIKE 'crypto%'`, + [user.id] + ); + + // Вычитаем сумму покупок из общего крипто-баланса + const remainingBalance = totalCryptoBalance - (cryptoPurchases?.total_sum || 0); + + // Обновляем поле total_balance в таблице users + await db.runAsync( + `UPDATE users SET total_balance = ? WHERE id = ?`, + [remainingBalance, user.id] + ); + + console.log(`[DEBUG] Updated total_balance for user ${user.id}: ${remainingBalance}`); + } catch (error) { + console.error('Error recalculating user balance:', error); + throw error; + } } static async updateUserLocation(telegramId, country, city, district) { @@ -164,28 +196,13 @@ class UserService { static async getUserBalance(userId) { try { - // Пересчитываем баланс перед получением const user = await this.getUserByUserId(userId); if (!user) { throw new Error('User not found'); } - await this.recalculateUserBalanceByTelegramId(user.telegram_id); - - // Получаем обновленный баланс - const updatedUser = await db.getAsync( - `SELECT total_balance, bonus_balance - FROM users - WHERE id = ?`, - [userId] - ); - - if (!updatedUser) { - throw new Error('User not found'); - } - - // Возвращаем сумму основного и бонусного баланса - return updatedUser.total_balance + updatedUser.bonus_balance; + // Возвращаем сумму доступного крипто-баланса и бонусного баланса + return user.total_balance + user.bonus_balance; } catch (error) { console.error('Error getting user balance:', error); throw error;