213 lines
8.3 KiB
JavaScript
213 lines
8.3 KiB
JavaScript
// userService.js
|
||
|
||
import db from "../config/database.js";
|
||
import Wallet from "../models/Wallet.js";
|
||
import WalletUtils from "../utils/walletUtils.js";
|
||
|
||
|
||
class UserService {
|
||
// Функция для нормализации telegram_id
|
||
static normalizeTelegramId(telegramId) {
|
||
if (typeof telegramId === 'number') {
|
||
// Если это число, преобразуем его в строку и удаляем ".0"
|
||
return telegramId.toString().replace(/\.0$/, '');
|
||
}
|
||
// Если это уже строка, возвращаем как есть
|
||
return telegramId.toString();
|
||
}
|
||
|
||
// Функция для валидации telegram_id
|
||
static validateTelegramId(telegramId) {
|
||
if (typeof telegramId !== 'string') {
|
||
throw new Error('telegram_id должен быть строкой');
|
||
}
|
||
if (telegramId.includes('.0')) {
|
||
throw new Error('telegram_id не должен содержать ".0"');
|
||
}
|
||
}
|
||
|
||
static async createUser(userData) {
|
||
try {
|
||
// Нормализуем и валидируем telegram_id
|
||
const normalizedTelegramId = this.normalizeTelegramId(userData?.telegram_id);
|
||
// console.log("Normalized telegram_id:", normalizedTelegramId); // Отладочный вывод
|
||
this.validateTelegramId(normalizedTelegramId);
|
||
|
||
// Обновляем значение telegram_id в объекте userData
|
||
userData.telegram_id = normalizedTelegramId;
|
||
|
||
// Проверяем, существует ли пользователь с таким telegram_id
|
||
const existingUser = await this.getUserByTelegramId(normalizedTelegramId);
|
||
if (existingUser) {
|
||
console.log("User already exists with telegram_id:", normalizedTelegramId);
|
||
return existingUser.id;
|
||
}
|
||
|
||
// Подготавливаем данные для вставки в базу данных
|
||
const fields = Object.keys(userData);
|
||
const values = Object.values(userData);
|
||
const marks = Array(fields.length).fill('?');
|
||
|
||
const query = `
|
||
INSERT INTO users (${fields.join(', ')})
|
||
VALUES (${marks.join(', ')})
|
||
`;
|
||
|
||
// Выполняем запрос к базе данных
|
||
await db.runAsync('BEGIN TRANSACTION');
|
||
const result = await db.runAsync(query, values);
|
||
await db.runAsync('COMMIT');
|
||
|
||
return result.lastID;
|
||
} catch (error) {
|
||
await db.runAsync('ROLLBACK');
|
||
console.error('Error creating user:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
static async getUserByUserId(userId) {
|
||
try {
|
||
return await db.getAsync(
|
||
'SELECT * FROM users WHERE id = ?',
|
||
[String(userId)]
|
||
);
|
||
} catch (error) {
|
||
console.error('Error getting user:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
static async getUserByTelegramId(telegramId) {
|
||
try {
|
||
const normalizedTelegramId = this.normalizeTelegramId(telegramId);
|
||
return await db.getAsync(
|
||
'SELECT * FROM users WHERE telegram_id = ?',
|
||
[normalizedTelegramId]
|
||
);
|
||
} catch (error) {
|
||
console.error('Error getting user:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
static async getDetailedUserByTelegramId(telegramId) {
|
||
try {
|
||
const normalizedTelegramId = this.normalizeTelegramId(telegramId);
|
||
return await db.getAsync(`
|
||
SELECT
|
||
u.*,
|
||
COUNT(DISTINCT p.id) as purchase_count,
|
||
(SELECT COALESCE(SUM(p2.total_price), 0)
|
||
FROM purchases p2
|
||
WHERE p2.user_id = u.id) as total_spent,
|
||
COUNT(DISTINCT cw.id) as crypto_wallet_count,
|
||
COUNT(DISTINCT cw2.id) as archived_wallet_count
|
||
FROM users u
|
||
LEFT JOIN purchases p ON u.id = p.user_id
|
||
LEFT JOIN crypto_wallets cw ON u.id = cw.user_id AND cw.wallet_type NOT LIKE '%#_%' ESCAPE '#'
|
||
LEFT JOIN crypto_wallets cw2 ON u.id = cw2.user_id AND cw2.wallet_type LIKE '%#_%' ESCAPE '#'
|
||
WHERE u.telegram_id = ?
|
||
GROUP BY u.id
|
||
`, [normalizedTelegramId]);
|
||
} catch (error) {
|
||
console.error('Error getting user stats:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
static async updateUser(userId, newUserData) {}
|
||
|
||
static async deleteUser() {}
|
||
|
||
static async recalculateUserBalanceByTelegramId(telegramId) {
|
||
const normalizedTelegramId = this.normalizeTelegramId(telegramId);
|
||
const user = await this.getUserByTelegramId(normalizedTelegramId);
|
||
|
||
if (!user) {
|
||
return;
|
||
}
|
||
|
||
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) {
|
||
const normalizedTelegramId = this.normalizeTelegramId(telegramId);
|
||
await db.runAsync(
|
||
'UPDATE users SET country = ?, city = ?, district = ? WHERE telegram_id = ?',
|
||
[country, city, district, normalizedTelegramId]
|
||
);
|
||
}
|
||
|
||
static async updateUserStatus(telegramId, status) {
|
||
const normalizedTelegramId = this.normalizeTelegramId(telegramId);
|
||
try {
|
||
await db.runAsync('BEGIN TRANSACTION');
|
||
|
||
// Update user status
|
||
await db.runAsync('UPDATE users SET status = ? WHERE telegram_id = ?', [status, normalizedTelegramId]);
|
||
|
||
// Commit transaction
|
||
await db.runAsync('COMMIT');
|
||
} catch (e) {
|
||
await db.runAsync("ROLLBACK");
|
||
console.error('Error deleting user:', e);
|
||
throw e;
|
||
}
|
||
}
|
||
|
||
static async getUserBalance(userId) {
|
||
try {
|
||
const user = await this.getUserByUserId(userId);
|
||
if (!user) {
|
||
throw new Error('User not found');
|
||
}
|
||
|
||
// Возвращаем сумму доступного крипто-баланса и бонусного баланса
|
||
return user.total_balance + user.bonus_balance;
|
||
} catch (error) {
|
||
console.error('Error getting user balance:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
}
|
||
|
||
export default UserService; |