feat: Mercuryo gateway, crypto QR deposit, mono products, wallet auto-refresh

- Replace Quickex/Guardarian with Mercuryo (https://mercuryo.io/)
- Add crypto QR code payment option in deposit flow (qrcode package)
- Add is_mono product flag for digital/infinite products
- Mono products: no quantity buttons in bot, always available
- Admin wallet page: auto-refresh balances from blockchain APIs
- Migration 010: add is_mono column to products
- i18n updates for en/de/es
This commit is contained in:
NW
2026-07-08 12:08:13 +01:00
parent 2b30bc4a91
commit f0afada884
24 changed files with 1393 additions and 268 deletions

View File

@@ -35,10 +35,10 @@ class ProductService {
throw new Error('Invalid location or category ID');
}
return await db.allAsync(
`SELECT id, name, price, description, quantity_in_stock, photo_url
`SELECT id, name, price, description, quantity_in_stock, photo_url, is_mono
FROM products
WHERE location_id = ? AND category_id = ?
AND quantity_in_stock > 0
AND (quantity_in_stock > 0 OR is_mono = 1)
ORDER BY name`,
[locationId, categoryId]
);
@@ -49,10 +49,10 @@ class ProductService {
throw new Error('Invalid category ID');
}
return await db.allAsync(
`SELECT id, name, price, description, quantity_in_stock, photo_url
`SELECT id, name, price, description, quantity_in_stock, photo_url, is_mono
FROM products
WHERE category_id = ?
AND quantity_in_stock > 0
AND (quantity_in_stock > 0 OR is_mono = 1)
ORDER BY name`,
[categoryId]
);

View File

@@ -55,7 +55,7 @@ class PurchaseService {
}
const product = await db.getAsync(
'SELECT id, quantity_in_stock FROM products WHERE id = ? AND quantity_in_stock >= ?',
'SELECT id, quantity_in_stock, is_mono FROM products WHERE id = ? AND (quantity_in_stock >= ? OR is_mono = 1)',
[productId, quantity]
);
if (!product) {
@@ -94,12 +94,14 @@ class PurchaseService {
sourceWalletType += sourceWalletType ? `, crypto_${usedCrypto}` : `crypto_${usedCrypto}`;
}
const stockResult = await db.runAsync(
'UPDATE products SET quantity_in_stock = quantity_in_stock - ? WHERE id = ? AND quantity_in_stock >= ?',
[quantity, productId, quantity]
);
if (stockResult.changes === 0) {
throw new Error('Insufficient stock');
if (!product.is_mono) {
const stockResult = await db.runAsync(
'UPDATE products SET quantity_in_stock = quantity_in_stock - ? WHERE id = ? AND quantity_in_stock >= ?',
[quantity, productId, quantity]
);
if (stockResult.changes === 0) {
throw new Error('Insufficient stock');
}
}
const txHash = crypto.randomUUID();