/** * quiXzoom Frilans Payout — Database Layer * Raw SQL via pg (no ORM per REXO standards) */ import pg from 'pg'; const { Pool } = pg; const pool = new Pool({ connectionString: process.env.DATABASE_URL || 'postgresql://wavult_admin:EgoVVPQuVSioCiMgJWmMoVvnjgiJPaD6hPR8xkZo@wavult-identity-core.cvi0qcksmsfj.eu-north-1.rds.amazonaws.com:5432/wavult_identity', ssl: { rejectUnauthorized: false }, }); // ── Frilans Accounts ──────────────────────────────────────────────────────── export async function createAccount(data) { const { userId, country, currency, taxHandling, personalNumber, payoutMethod } = data; const result = await pool.query(` INSERT INTO frilans_accounts (user_id, country, currency, tax_handling, personal_number, payout_method) VALUES ($1, $2, $3, $4, $5, $6) RETURNING * `, [userId, country, currency, taxHandling, personalNumber, payoutMethod]); return result.rows[0]; } export async function getAccountByUserId(userId) { const result = await pool.query( 'SELECT * FROM frilans_accounts WHERE user_id = $1 AND status = $2', [userId, 'active'] ); return result.rows[0] || null; } export async function updateAccount(accountId, updates) { const fields = Object.keys(updates); const values = Object.values(updates); const setClause = fields.map((f, i) => `${f} = $${i + 2}`).join(', '); const result = await pool.query(` UPDATE frilans_accounts SET ${setClause}, updated_at = NOW() WHERE id = $1 RETURNING * `, [accountId, ...values]); return result.rows[0]; } // ── Payouts ───────────────────────────────────────────────────────────────── export async function createPayout(data) { const { accountId, amount, netAmount, currency, platformFee, processingFee, taxAmount, method, scheduledDate } = data; const result = await pool.query(` INSERT INTO frilans_payouts (account_id, amount, net_amount, currency, platform_fee, processing_fee, tax_amount, method, scheduled_date) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING * `, [accountId, amount, netAmount, currency, platformFee, processingFee, taxAmount, method, scheduledDate]); return result.rows[0]; } export async function listPayouts(accountId) { const result = await pool.query( 'SELECT * FROM frilans_payouts WHERE account_id = $1 ORDER BY created_at DESC', [accountId] ); return result.rows; } export async function getPayoutById(payoutId) { const result = await pool.query( 'SELECT * FROM frilans_payouts WHERE id = $1', [payoutId] ); return result.rows[0] || null; } // ── Documents ─────────────────────────────────────────────────────────────── export async function createDocument(data) { const { accountId, type, s3Url } = data; const result = await pool.query(` INSERT INTO frilans_documents (account_id, type, s3_url, status) VALUES ($1, $2, $3, $4) RETURNING * `, [accountId, type, s3Url, 'verified']); return result.rows[0]; } export async function listDocuments(accountId) { const result = await pool.query( 'SELECT * FROM frilans_documents WHERE account_id = $1 ORDER BY uploaded_at DESC', [accountId] ); return result.rows; } // ── Tax Summary ───────────────────────────────────────────────────────────── export async function getTaxSummary(accountId, year) { const result = await pool.query(` SELECT COALESCE(SUM(amount), 0) as total_earnings, COALESCE(SUM(tax_amount), 0) as total_tax_paid, COALESCE(SUM(platform_fee + processing_fee), 0) as total_fees_paid, COALESCE(SUM(net_amount), 0) as net_earnings FROM frilans_payouts WHERE account_id = $1 AND EXTRACT(YEAR FROM created_at) = $2 AND status = 'completed' `, [accountId, year]); return result.rows[0]; } // ── Health Check ──────────────────────────────────────────────────────────── export async function healthCheck() { const result = await pool.query('SELECT NOW()'); return result.rows[0]; }