Files
telegram-shop/src/services/userService.js
2025-01-09 20:07:44 +00:00

213 lines
8.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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;