Bug update function

This commit is contained in:
NW 2024-12-14 23:12:36 +00:00
parent 682246675e
commit 9d9e0e80ad
9 changed files with 474 additions and 201 deletions

View File

@ -183,19 +183,30 @@ const initDb = async () => {
// Create purchases table
await db.runAsync(`
CREATE TABLE IF NOT EXISTS purchases (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
product_id INTEGER NOT NULL,
wallet_type TEXT NOT NULL,
tx_hash TEXT NOT NULL,
quantity INTEGER NOT NULL CHECK (quantity > 0),
total_price REAL NOT NULL CHECK (total_price > 0),
purchase_date DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
product_id INTEGER NOT NULL,
wallet_type TEXT NOT NULL,
tx_hash TEXT NOT NULL,
quantity INTEGER NOT NULL CHECK (quantity > 0),
total_price REAL NOT NULL CHECK (total_price > 0),
purchase_date DATETIME DEFAULT CURRENT_TIMESTAMP,
status TEXT DEFAULT 'pending',
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE
)
`);
// Проверка наличия поля status в таблице purchases
const statusExists = await checkColumnExists('purchases', 'status');
if (!statusExists) {
await db.runAsync(`
ALTER TABLE purchases
ADD COLUMN status TEXT DEFAULT 'pending'
`);
console.log('Column status added to purchases table');
}
// Create locations table
await db.runAsync(`
CREATE TABLE IF NOT EXISTS locations (

View File

@ -176,15 +176,29 @@ export default class UserProductHandler {
const [locationId, categoryId] = callbackQuery.data.replace('shop_category_', '').split('_');
try {
// Удаляем текущее сообщение
await bot.deleteMessage(chatId, messageId);
// Получаем состояние пользователя
const state = userStates.get(chatId);
// Удаляем сообщение с фотографией, если оно существует
if (state && state.photoMessageId) {
try {
await bot.deleteMessage(chatId, state.photoMessageId);
} catch (error) {
console.error('Error deleting photo message:', error);
}
}
// Получаем товары для выбранной категории
const products = await ProductService.getProductsByCategoryId(categoryId);
if (products.length === 0) {
await bot.editMessageText(
await bot.sendMessage(
chatId,
'No products available in this category.',
{
chat_id: chatId,
message_id: messageId,
reply_markup: {
inline_keyboard: [[
{ text: '« Back', callback_data: `shop_district_${locationId}` }
@ -211,14 +225,16 @@ export default class UserProductHandler {
]);
// Отправляем сообщение с товарами
await bot.editMessageText(
await bot.sendMessage(
chatId,
'Select a product:',
{
chat_id: chatId,
message_id: messageId,
reply_markup: keyboard
}
);
// Удаляем состояние пользователя
userStates.delete(chatId);
} catch (error) {
console.error('Error in handleCategorySelection:', error);
await bot.sendMessage(chatId, 'Error loading products. Please try again.');
@ -290,71 +306,82 @@ export default class UserProductHandler {
const chatId = callbackQuery.message.chat.id;
const messageId = callbackQuery.message.message_id;
const productId = callbackQuery.data.replace('shop_product_', '');
try {
const product = await ProductService.getDetailedProductById(productId);
if (!product) {
throw new Error('Product not found');
}
// Delete the previous message
// Удаляем предыдущее сообщение
await bot.deleteMessage(chatId, messageId);
// Получаем состояние пользователя
const state = userStates.get(chatId);
// Удаляем сообщение с фотографией, если оно существует
if (state?.photoMessageId) {
try {
await bot.deleteMessage(chatId, state.photoMessageId);
} catch (error) {
console.error('Error deleting photo message:', error);
}
}
const message = `
📦 ${product.name}
💰 Price: $${product.price}
📝 Description: ${product.description}
📦 Available: ${product.quantity_in_stock} pcs
Category: ${product.category_name}
`;
let photoMessageId = null;
// First send the photo if it exists
📦 ${product.name}
💰 Price: $${product.price}
📝 Description: ${product.description}
📦 Available: ${product.quantity_in_stock} pcs
Category: ${product.category_name}
`;
// Отправляем фото, если оно существует
let photoMessage;
if (product.photo_url) {
try {
photoMessage = await bot.sendPhoto(chatId, product.photo_url, {caption: 'Public photo'});
photoMessage = await bot.sendPhoto(chatId, product.photo_url, { caption: 'Public photo' });
} catch (e) {
photoMessage = await bot.sendPhoto(chatId, "./corrupt-photo.jpg", {caption: 'Public photo'})
photoMessage = await bot.sendPhoto(chatId, "./corrupt-photo.jpg", { caption: 'Public photo' });
}
}
const keyboard = {
inline_keyboard: [
[{text: '🛒 Buy Now', callback_data: `buy_product_${productId}`}],
[{ text: '🛒 Buy Now', callback_data: `buy_product_${productId}` }],
[
{
text: '',
callback_data: `decrease_quantity_${productId}`,
callback_game: {} // Initially disabled as quantity starts at 1
callback_game: {} // Изначально отключено, так как количество начинается с 1
},
{text: '1', callback_data: 'current_quantity'},
{ text: '1', callback_data: 'current_quantity' },
{
text: '',
callback_data: `increase_quantity_${productId}`,
callback_game: product.quantity_in_stock <= 1 ? {} : null // Disabled if stock is 1 or less
callback_game: product.quantity_in_stock <= 1 ? {} : null // Отключено, если остаток 1 или меньше
}
],
[{ text: `« Back ${product.category_name}`, callback_data: `shop_category_${product.location_id}_${product.category_id}` }] // Возврат к категории
]
};
// Then send the message with controls
await bot.sendMessage(chatId, message, {
// Отправляем сообщение с кнопками
const productMessage = await bot.sendMessage(chatId, message, {
reply_markup: keyboard,
parse_mode: 'HTML'
});
// Store the current quantity and photo message ID in user state
// Сохраняем ID сообщения с фотографией и ID сообщения с товаром в состояние пользователя
userStates.set(chatId, {
action: 'buying_product',
productId,
quantity: 1,
photoMessageId
photoMessageId: photoMessage ? photoMessage.message_id : null,
productMessageId: productMessage.message_id
});
} catch (error) {
console.error('Error in handleProductSelection:', error);
@ -502,8 +529,9 @@ Category: ${product.category_name}
const quantity = state?.quantity || 1;
const totalPrice = product.price * quantity;
// Проверка баланса пользователя
// Получение баланса пользователя
const userBalance = await UserService.getUserBalance(user.id);
if (userBalance < totalPrice) {
await bot.sendMessage(
chatId,
@ -545,11 +573,12 @@ Category: ${product.category_name}
const keyboard = {
inline_keyboard: [
[{ text: `Pay`, callback_data: `pay_with_main_${productId}_${quantity}` }],
[{ text: '« Cancel', callback_data: `shop_product_${productId}` }]
[{ text: '« Cancel', callback_data: `shop_product_${productId}` }] // Кнопка "Back"
]
};
await bot.editMessageText(
// Отправка сообщения с кнопками
const purchaseMessage = await bot.editMessageText(
`🛒 Purchase Summary:\n\n` +
`Product: ${product.name}\n` +
`Quantity: ${quantity}\n` +
@ -560,6 +589,13 @@ Category: ${product.category_name}
reply_markup: keyboard
}
);
// Сохранение ID сообщения с фотографией в состояние пользователя
userStates.set(chatId, {
...state,
photoMessageId: state?.photoMessageId || null,
purchaseMessageId: purchaseMessage.message_id
});
} catch (error) {
console.error('Error in handleBuyProduct:', error);
await bot.sendMessage(chatId, 'Error processing purchase. Please try again.');
@ -571,23 +607,23 @@ Category: ${product.category_name}
const telegramId = callbackQuery.from.id;
const [walletType, productId, quantity] = callbackQuery.data.replace('pay_with_', '').split('_');
const state = userStates.get(chatId);
try {
await UserService.recalculateUserBalanceByTelegramId(telegramId);
const user = await UserService.getUserByTelegramId(telegramId)
const user = await UserService.getUserByTelegramId(telegramId);
if (!user) {
throw new Error('User not found');
}
const product = await ProductService.getProductById(productId);
if (!product) {
throw new Error('Product not found');
}
const totalPrice = product.price * quantity;
const balance = user.total_balance + user.bonus_balance;
if (totalPrice > balance) {
userStates.delete(chatId);
await bot.editMessageText(`Not enough money`, {
@ -596,45 +632,74 @@ Category: ${product.category_name}
});
return;
}
await PurchaseService.createPurchase(user.id, product.id, walletType, quantity, totalPrice)
// Проверка наличия товара
if (product.quantity_in_stock < quantity) {
await bot.sendMessage(chatId, `❌ Not enough items in stock. Only ${product.quantity_in_stock} available.`);
return;
}
// Создаем покупку и получаем её ID
const purchaseId = await PurchaseService.createPurchase(user.id, productId, walletType, quantity, totalPrice);
// Уменьшаем количество товара в базе данных
await ProductService.decreaseProductQuantity(productId, quantity);
// Извлекаем данные о локации
const location = await LocationService.getLocationById(product.location_id);
const category = await CategoryService.getCategoryById(product.category_id);
// Удаляем сообщение с Public Photo, если оно существует
if (state?.photoMessageId) {
try {
await bot.deleteMessage(chatId, state.photoMessageId);
} catch (error) {
console.error('Error deleting Public Photo message:', error);
}
}
// Отправляем Hidden Photo
let hiddenPhotoMessage;
if (product.hidden_photo_url) {
try {
hiddenPhotoMessage = await bot.sendPhoto(chatId, product.hidden_photo_url, {caption: 'Hidden photo'});
hiddenPhotoMessage = await bot.sendPhoto(chatId, product.hidden_photo_url, { caption: 'Hidden photo' });
} catch (e) {
hiddenPhotoMessage = await bot.sendPhoto(chatId, "./corrupt-photo.jpg", {caption: 'Hidden photo'})
hiddenPhotoMessage = await bot.sendPhoto(chatId, "./corrupt-photo.jpg", { caption: 'Hidden photo' });
}
}
const message = `
📦 Product Details:
Name: ${product.name}
Price: $${product.price}
Description: ${product.description}
Stock: ${product.quantity_in_stock}
Location: ${product.country}, ${product.city}, ${product.district}
Category: ${product.category_name}
🔒 Private Information:
${product.private_data}
Hidden Location: ${product.hidden_description}
Coordinates: ${product.hidden_coordinates}
`;
📦 Purchase Details:
Name: ${product.name}
Quantity: ${quantity}
Total: $${totalPrice}
Location: ${location?.country || 'N/A'}, ${location?.city || 'N/A'}, ${location?.district || 'N/A'}
Category: ${category?.name || 'N/A'}
🔒 Private Information:
${product.private_data || 'N/A'}
Hidden Location: ${product.hidden_description || 'N/A'}
Coordinates: ${product.hidden_coordinates || 'N/A'}
`;
const keyboard = {
inline_keyboard: [
[{text: "I've got it!", callback_data: "Asdasdasd"}],
[{text: "Contact support", url: config.SUPPORT_LINK}]
[{ text: 'View new purchase', callback_data: `view_purchase_${purchaseId}` }], // Переход к покупке
[{ text: "Contact support", url: config.SUPPORT_LINK }] // Сохранение кнопки "Contact support"
]
};
await bot.sendMessage(chatId, message, {reply_markup: keyboard});
await bot.sendMessage(chatId, message, { reply_markup: keyboard });
await bot.deleteMessage(chatId, callbackQuery.message.message_id);
// Сохраняем ID сообщения с Hidden Photo в состояние пользователя
userStates.set(chatId, {
action: 'viewing_purchase',
purchaseId,
hiddenPhotoMessageId: hiddenPhotoMessage ? hiddenPhotoMessage.message_id : null
});
} catch (error) {
console.error('Error in handleBuyProduct:', error);
console.error('Error in handlePay:', error);
await bot.sendMessage(chatId, 'Error processing purchase. Please try again.');
}
}

View File

@ -1,160 +1,279 @@
import config from "../../config/config.js";
import PurchaseService from "../../services/purchaseService.js";
import UserService from "../../services/userService.js";
import bot from "../../context/bot.js";
import LocationService from "../../services/locationService.js";
import ProductService from "../../services/productService.js";
import CategoryService from "../../services/categoryService.js";
import bot from "../../context/bot.js";
import userStates from "../../context/userStates.js";
export default class UserPurchaseHandler {
static async viewPurchasePage(userId, page) {
try {
const limit = 10;
const offset = (page || 0) * limit;
const previousPage = page > 0 ? page - 1 : 0;
const nextPage = page + 1;
const limit = 10; // Количество покупок на странице
const offset = page * limit;
// Получаем покупки пользователя с учетом пагинации
const purchases = await PurchaseService.getPurchasesByUserId(userId, limit, offset);
if ((purchases.length === 0) && (page == 0)) {
// Получаем общее количество покупок пользователя
const totalPurchases = await PurchaseService.getTotalPurchasesByUserId(userId);
// Вычисляем общее количество страниц
const totalPages = Math.ceil(totalPurchases / limit);
// Если покупок нет, возвращаем сообщение о пустом архиве
if (totalPurchases === 0) {
return {
text: 'You haven\'t made any purchases yet.',
markup: [[
{text: '🛍 Browse Products', callback_data: 'shop_start'}
]]
}
text: 'Your purchase history is empty.',
markup: {
inline_keyboard: [
[{ text: '🛍 Browse Products', callback_data: 'shop_start' }]
]
}
};
}
if ((purchases.length === 0) && (page > 0)) {
return await this.viewPurchasePage(userId, previousPage);
// Если покупок нет на текущей странице, но это не первая страница, переходим на предыдущую страницу
if (purchases.length === 0 && page > 0) {
return await this.viewPurchasePage(userId, page - 1);
}
const keyboard = {
inline_keyboard: [
...purchases.map(item => [{
text: `${item.product_name} [${new Date(item.purchase_date).toLocaleString()}]`,
callback_data: `view_purchase_${item.id}`
}]),
[
{
text: page > 0 ? `« Back (Page ${page})` : '« Back',
callback_data: page > 0 ? `list_purchases_${page - 1}` : 'no_action', // Если на первой странице, то "no_action"
hide: page === 0 // Скрываем кнопку "Назад", если на первой странице
},
{
text: `Page ${page + 1} of ${totalPages}`,
callback_data: 'current_page'
},
{
text: page < totalPages - 1 ? `Next » (Page ${page + 2})` : 'Next »',
callback_data: page < totalPages - 1 ? `list_purchases_${page + 1}` : 'no_action', // Если на последней странице, то "no_action"
hide: page === totalPages - 1 // Скрываем кнопку "Вперед", если на последней странице
}
]
]
};
keyboard.inline_keyboard.push([
{text: `«`, callback_data: `list_purchases_${previousPage}`},
{text: `»`, callback_data: `list_purchases_${nextPage}`},
]);
keyboard.inline_keyboard.push([
{text: '🛍 Browse Products', callback_data: 'shop_start'}
]);
return {
text: `📦 Select purchase to view detailed information:`,
text: `📦 Select purchase to view detailed information (Page ${page + 1} of ${totalPages}):`,
markup: keyboard
}
};
} catch (error) {
console.error('Error in showPurchases:', error);
return {text: 'Error loading purchase history. Please try again.'};
console.error('Error in viewPurchasePage:', error);
return { text: 'Error loading purchase history. Please try again.' };
}
}
static async handlePurchaseListPage(callbackQuery) {
const telegramId = callbackQuery.from.id;
const chatId = callbackQuery.message.chat.id;
const page = callbackQuery.data.replace('list_purchases_', '');
const page = parseInt(callbackQuery.data.replace('list_purchases_', ''));
try {
const user = await UserService.getUserByTelegramId(telegramId);
if (!user) {
await bot.sendMessage(chatId, 'User not found.');
return;
}
const {text, markup} = await this.viewPurchasePage(user.id, parseInt(page));
// Удаляем сообщение с Hidden Photo, если оно существует
const state = userStates.get(chatId);
if (state?.hiddenPhotoMessageId) {
try {
await bot.deleteMessage(chatId, state.hiddenPhotoMessageId);
} catch (error) {
console.error('Error deleting Hidden Photo message:', error);
}
}
const { text, markup } = await this.viewPurchasePage(user.id, page);
await bot.editMessageText(text, {
chat_id: chatId,
message_id: callbackQuery.message.message_id,
reply_markup: markup,
parse_mode: 'Markdown',
parse_mode: 'Markdown'
});
// Удаляем состояние пользователя
userStates.delete(chatId);
} catch (e) {
return;
console.error('Error in handlePurchaseListPage:', e);
await bot.sendMessage(chatId, 'Error loading purchase history. Please try again.');
}
}
static async showPurchases(msg) {
const chatId = msg.chat.id;
const telegramId = msg.from.id;
try {
const user = await UserService.getUserByTelegramId(telegramId);
if (!user) {
await bot.sendMessage(chatId, 'User not found.');
return;
}
const {text, markup} = await this.viewPurchasePage(user.id, 0);
await bot.sendMessage(chatId, text, {reply_markup: markup, parse_mode: 'Markdown'});
const { text, markup } = await this.viewPurchasePage(user.id, 0);
await bot.sendMessage(chatId, text, { reply_markup: markup, parse_mode: 'Markdown' });
} catch (error) {
console.error('Error in handleSubcategorySelection:', error);
await bot.sendMessage(chatId, 'Error loading products. Please try again.');
console.error('Error in showPurchases:', error);
await bot.sendMessage(chatId, 'Error loading purchase history. Please try again.');
}
}
static async viewPurchase(callbackQuery) {
const chatId = callbackQuery.message.chat.id;
const purchaseId = callbackQuery.data.replace('view_purchase_', '');
const purchase = await PurchaseService.getPurchaseById(purchaseId);
if (!purchase) {
await bot.sendMessage(chatId, "No such purchase");
return;
}
const product = await ProductService.getProductById(purchase.product_id)
if (!product) {
await bot.sendMessage(chatId, "No such product");
return;
}
let hiddenPhotoMessage;
if (product.hidden_photo_url) {
try {
hiddenPhotoMessage = await bot.sendPhoto(chatId, product.hidden_photo_url, {caption: 'Hidden photo'});
} catch (e) {
hiddenPhotoMessage = await bot.sendPhoto(chatId, "./corrupt-photo.jpg", {caption: 'Hidden photo'})
try {
// Получаем данные покупки
const purchase = await PurchaseService.getPurchaseById(purchaseId);
if (!purchase) {
await bot.sendMessage(chatId, "No such purchase");
return;
}
// Получаем данные товара по product_id
const product = await ProductService.getProductById(purchase.product_id);
if (!product) {
await bot.sendMessage(chatId, "No such product");
return;
}
// Получаем данные локации по location_id
const location = await LocationService.getLocationById(product.location_id);
// Получаем данные категории по category_id
const category = await CategoryService.getCategoryById(product.category_id);
// Удаляем старое сообщение с Hidden Photo, если оно существует
const state = userStates.get(chatId);
if (state?.hiddenPhotoMessageId) {
try {
await bot.deleteMessage(chatId, state.hiddenPhotoMessageId);
} catch (error) {
console.error('Error deleting Hidden Photo message:', error);
}
}
// Отправляем Hidden Photo
let hiddenPhotoMessage;
if (product.hidden_photo_url) {
try {
hiddenPhotoMessage = await bot.sendPhoto(chatId, product.hidden_photo_url, { caption: 'Hidden photo' });
} catch (e) {
hiddenPhotoMessage = await bot.sendPhoto(chatId, "./corrupt-photo.jpg", { caption: 'Hidden photo' });
}
}
// Формируем сообщение с деталями покупки
const message = `
📦 Purchase Details:
Name: ${product.name || 'N/A'}
Quantity: ${purchase.quantity}
Total: $${purchase.total_price}
Location: ${location?.country || 'N/A'}, ${location?.city || 'N/A'}, ${location?.district || 'N/A'}
Category: ${category?.name || 'N/A'}
🔒 Private Information:
${product.private_data || 'N/A'}
Hidden Location: ${product.hidden_description || 'N/A'}
Coordinates: ${product.hidden_coordinates || 'N/A'}
`;
// Создаем клавиатуру с кнопками
const keyboard = {
inline_keyboard: [
// Проверяем статус покупки перед добавлением кнопки "I've got it!"
...(purchase.status !== 'received' ? [[{ text: "I've got it!", callback_data: `confirm_received_${purchaseId}` }]] : []),
[{ text: "« Back to Purchase List", callback_data: `list_purchases_0` }], // Кнопка "Назад к списку покупок"
[{ text: "Contact support", url: config.SUPPORT_LINK }]
]
};
// Отправляем сообщение с деталями покупки
await bot.sendMessage(chatId, message, { reply_markup: keyboard });
// Удаляем предыдущее сообщение
await bot.deleteMessage(chatId, callbackQuery.message.message_id);
// Сохраняем ID сообщения с Hidden Photo в состояние пользователя
userStates.set(chatId, {
action: 'viewing_purchase',
purchaseId,
hiddenPhotoMessageId: hiddenPhotoMessage ? hiddenPhotoMessage.message_id : null
});
} catch (error) {
console.error('Error in viewPurchase:', error);
await bot.sendMessage(chatId, 'Error loading purchase details. Please try again.');
}
}
const message = `
📦 Purchase Details:
Name: ${purchase.product_name}
Quantity: ${purchase.quantity}
Total: $${purchase.total_price}
Location: ${purchase.country}, ${purchase.city}
Payment: ${purchase.wallet_type}
Date: ${new Date(purchase.purchase_date).toLocaleString()}
🔒 Private Information:
${product.private_data}
Hidden Location: ${product.hidden_description}
Coordinates: ${product.hidden_coordinates}
`;
const keyboard = {
inline_keyboard: [
[{text: "I've got it!", callback_data: "Asdasdasd"}],
[{text: "Contact support", url: config.SUPPORT_LINK}]
]
};
await bot.sendMessage(chatId, message, {reply_markup: keyboard});
await bot.deleteMessage(chatId, callbackQuery.message.message_id);
static async handleConfirmReceived(callbackQuery) {
const chatId = callbackQuery.message.chat.id;
const messageId = callbackQuery.message.message_id;
const purchaseId = callbackQuery.data.replace('confirm_received_', '');
try {
// Проверяем, подтверждена ли покупка уже
const purchase = await PurchaseService.getPurchaseById(purchaseId);
if (!purchase) {
await bot.sendMessage(chatId, "Purchase not found.");
return;
}
if (purchase.status === 'received') {
await bot.sendMessage(chatId, "This purchase has already been confirmed.");
return;
}
// Обновляем статус покупки в базе данных
await PurchaseService.updatePurchaseStatus(purchaseId, 'received');
// Отправляем уведомление администраторам
const adminIds = config.ADMIN_IDS; // Используем массив ADMIN_IDS
for (const adminId of adminIds) {
await bot.sendMessage(adminId, `User ${callbackQuery.from.username} has confirmed receiving purchase #${purchaseId}.`);
}
// Уведомляем пользователя
await bot.sendMessage(chatId, "Thank you! Your purchase has been marked as received.");
// Удаляем сообщение с карточкой товара
await bot.deleteMessage(chatId, messageId);
// Удаляем Hidden Photo, если оно существует
const state = userStates.get(chatId);
if (state?.hiddenPhotoMessageId) {
try {
await bot.deleteMessage(chatId, state.hiddenPhotoMessageId);
} catch (error) {
console.error('Error deleting Hidden Photo message:', error);
}
}
// Удаляем состояние пользователя
userStates.delete(chatId);
// Открываем список покупок для пользователя
await this.showPurchases({ chat: { id: chatId }, from: { id: callbackQuery.from.id } });
} catch (error) {
console.error('Error in handleConfirmReceived:', error);
await bot.sendMessage(chatId, 'Error confirming receipt. Please try again.');
}
}
}

View File

@ -233,6 +233,9 @@ bot.on('callback_query', async (callbackQuery) => {
} else if (action.startsWith('view_purchase_')) {
logDebug(action, 'viewPurchase');
await userPurchaseHandler.viewPurchase(callbackQuery);
} else if (action.startsWith('confirm_received_')) {
logDebug(action, 'handleConfirmReceived');
await userPurchaseHandler.handleConfirmReceived(callbackQuery);
}
// Admin location management
else if (action === 'add_location') {

View File

@ -16,7 +16,16 @@ class CategoryService {
}
static async getCategoryById(categoryId) {
return await db.getAsync('SELECT id, name FROM categories WHERE id = ?', [categoryId]);
try {
const category = await db.getAsync(
'SELECT * FROM categories WHERE id = ?',
[categoryId]
);
return category;
} catch (error) {
console.error('Error fetching category by ID:', error);
throw new Error('Failed to fetch category');
}
}
static async getSubcategoryById(subcategoryId) {

View File

@ -27,10 +27,16 @@ class LocationService {
}
static async getLocationById(locationId) {
return await db.getAsync(
'SELECT country, city, district FROM locations WHERE id = ?',
[locationId]
);
try {
const location = await db.getAsync(
'SELECT * FROM locations WHERE id = ?',
[locationId]
);
return location;
} catch (error) {
console.error('Error fetching location by ID:', error);
throw new Error('Failed to fetch location');
}
}
}

View File

@ -42,6 +42,17 @@ class ProductService {
);
}
static async decreaseProductQuantity(productId, quantity) {
try {
await db.runAsync(
'UPDATE products SET quantity_in_stock = quantity_in_stock - ? WHERE id = ?',
[quantity, productId]
);
} catch (error) {
console.error('Error decreasing product quantity:', error);
throw new Error('Failed to update product quantity');
}
}
}
export default ProductService

View File

@ -1,5 +1,5 @@
import db from "../config/database.js";
import CryptoJS from "crypto-js"; // Импортируем библиотеку crypto-js
class PurchaseService {
static async getPurchasesByUserId(userId, limit, offset) {
try {
@ -28,31 +28,59 @@ class PurchaseService {
static async getPurchaseById(purchaseId) {
try {
return await db.getAsync(`
SELECT
p.*,
pr.name as product_name,
pr.description,
l.country,
l.city,
l.district
FROM purchases p
JOIN products pr ON p.product_id = pr.id
JOIN locations l ON pr.location_id = l.id
WHERE p.id = ?
`, [purchaseId]);
return await db.getAsync(
`SELECT * FROM purchases WHERE id = ?`,
[purchaseId]
);
} catch (error) {
console.error('Error get purchase:', error);
console.error('Error getting purchase by ID:', error);
throw error;
}
}
static async createPurchase(userId, productId, walletType, quantity, totalPrice) {
await db.runAsync(
'INSERT INTO purchases (user_id, product_id, wallet_type, tx_hash, quantity, total_price) VALUES (?, ?, ?, ?, ?, ?)',
[userId, productId, walletType, "null", quantity, totalPrice]
);
try {
// Генерируем 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]
);
// Возвращаем ID новой покупки
return result.lastID;
} catch (error) {
console.error('Error creating purchase:', error);
throw error;
}
}
static async updatePurchaseStatus(purchaseId, status) {
try {
await db.runAsync(
'UPDATE purchases SET status = ? WHERE id = ?',
[status, purchaseId]
);
} catch (error) {
console.error('Error updating purchase status:', error);
throw new Error('Failed to update purchase status');
}
}
static async getTotalPurchasesByUserId(userId) {
try {
const total = await db.getAsync(
`SELECT COUNT(*) AS total FROM purchases WHERE user_id = ?`,
[userId]
);
return total.total;
} catch (error) {
console.error('Error fetching total purchases by user ID:', error);
throw new Error('Failed to fetch total purchases');
}
}
}

View File

@ -135,6 +135,27 @@ class UserService {
throw e;
}
}
static async getUserBalance(userId) {
try {
const user = await db.getAsync(
`SELECT total_balance, bonus_balance
FROM users
WHERE id = ?`,
[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;