const assert = require('node:assert/strict'); const http = require('node:http'); const test = require('node:test'); const { closeDbPool, getDb } = require('../src/config/db'); const { syncOrderStatuses } = require('../src/services/orders.service'); const createdUserIds = []; const createdServiceIds = []; let providerMock; const statuses = new Map(); function unique(prefix) { return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2)}`; } function startProviderMock() { const server = http.createServer(async (req, res) => { const chunks = []; for await (const chunk of req) { chunks.push(chunk); } const body = new URLSearchParams(Buffer.concat(chunks).toString()); const orderId = body.get('order'); const payload = statuses.get(orderId) || { status: 'Processing', remains: 10 }; res.setHeader('content-type', 'application/json'); if (body.get('action') !== 'status') { res.end(JSON.stringify({ error: 'unsupported action' })); return; } res.end(JSON.stringify(payload)); }); return new Promise((resolve) => { server.listen(0, '127.0.0.1', () => { resolve({ url: `http://127.0.0.1:${server.address().port}`, close: () => new Promise((done) => server.close(done)) }); }); }); } async function createUser(balance = '0.0000') { const username = unique('status_user'); const [id] = await getDb()('users').insert({ username, email: `${username}@example.com`, password_hash: 'hash', balance }); createdUserIds.push(id); return id; } async function createService() { const [id] = await getDb()('services').insert({ provider_service_id: unique('status_provider_service'), name: 'Status Test Service', category: 'Status', provider_price: '2.0000', markup_percent: '25.0000', sell_price: '2.5000', min: 10, max: 10000, is_active: true }); createdServiceIds.push(id); return id; } async function createTrackedOrder(userId, serviceId, providerOrderId, status = 'processing') { const [id] = await getDb()('orders').insert({ user_id: userId, service_id: serviceId, link: 'https://example.com/status-order', quantity: 1000, charge: '2.5000', provider_order_id: providerOrderId, status }); return id; } test.before(async () => { providerMock = await startProviderMock(); process.env.PROVIDER_API_URL = providerMock.url; process.env.PROVIDER_API_KEY = 'mock-key'; }); test.after(async () => { const db = getDb(); if (createdUserIds.length > 0) { await db('orders').whereIn('user_id', createdUserIds).del(); await db('transactions').whereIn('user_id', createdUserIds).del(); await db('users').whereIn('id', createdUserIds).del(); } if (createdServiceIds.length > 0) { await db('services').whereIn('id', createdServiceIds).del(); } await closeDbPool(); await providerMock.close(); }); test('syncOrderStatuses updates completed orders with remains and provider charge', async () => { const userId = await createUser(); const serviceId = await createService(); const providerOrderId = unique('provider_completed'); const orderId = await createTrackedOrder(userId, serviceId, providerOrderId); statuses.set(providerOrderId, { status: 'Completed', charge: '1.7500', start_count: 100, remains: 0 }); const result = await syncOrderStatuses(); const order = await getDb()('orders').where({ id: orderId }).first(); assert.equal(result.updated >= 1, true); assert.equal(order.status, 'completed'); assert.equal(order.start_count, 100); assert.equal(order.remains, 0); assert.equal(order.provider_charge, '1.7500'); assert.ok(order.last_status_check_at); }); test('partial status is recorded without automatic wallet refund', async () => { const userId = await createUser('7.5000'); const serviceId = await createService(); const providerOrderId = unique('provider_partial'); const orderId = await createTrackedOrder(userId, serviceId, providerOrderId); statuses.set(providerOrderId, { status: 'Partial', charge: '1.0000', start_count: 55, remains: 400 }); await syncOrderStatuses(); const order = await getDb()('orders').where({ id: orderId }).first(); const user = await getDb()('users').where({ id: userId }).first(); const refunds = await getDb()('transactions').where({ user_id: userId, type: 'refund' }); assert.equal(order.status, 'partial'); assert.equal(order.remains, 400); assert.equal(user.balance, '7.5000'); assert.equal(refunds.length, 0); });