const db = require('../../database/database'); const { logger } = require('../../middleware/logger'); exports.list = async () => { const [rows] = await db.query('SELECT * FROM affiliates ORDER BY created_at DESC'); return rows.map(r => ({ id: r.id, name: r.name, description: r.description, url: r.url, object_storage_id: r.object_storage_id, original_filename: r.original_filename, category: r.category, is_active: !!r.is_active, commission_rate: r.commission_rate, created_at: r.created_at, updated_at: r.updated_at })); }; exports.get = async (id) => { const [rows] = await db.query('SELECT * FROM affiliates WHERE id = ?', [id]); if (!rows[0]) return null; const r = rows[0]; return { id: r.id, name: r.name, description: r.description, url: r.url, object_storage_id: r.object_storage_id, original_filename: r.original_filename, category: r.category, is_active: !!r.is_active, commission_rate: r.commission_rate, created_at: r.created_at, updated_at: r.updated_at }; }; exports.create = async ({ name, description, url, category, is_active, commission_rate, object_storage_id, original_filename }) => { // Validation if (!name || name.trim() === '') { const e = new Error('Affiliate name is required'); e.code = 'VALIDATION_ERROR'; throw e; } if (!url || url.trim() === '') { const e = new Error('Affiliate URL is required'); e.code = 'VALIDATION_ERROR'; throw e; } if (!category || category.trim() === '') { const e = new Error('Affiliate category is required'); e.code = 'VALIDATION_ERROR'; throw e; } // Validate URL format try { new URL(url); } catch (err) { const e = new Error('Invalid URL format'); e.code = 'VALIDATION_ERROR'; throw e; } const [result] = await db.query( `INSERT INTO affiliates (name, description, url, category, is_active, commission_rate, object_storage_id, original_filename) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [ name.trim(), description ? description.trim() : null, url.trim(), category.trim(), is_active !== undefined ? is_active : true, commission_rate || null, object_storage_id || null, original_filename || null ] ); logger.info('[AffiliateService.create] created', { id: result.insertId }); return await exports.get(result.insertId); }; exports.update = async (id, { name, description, url, category, is_active, commission_rate, object_storage_id, original_filename }) => { const updates = []; const values = []; if (name !== undefined) { updates.push('name = ?'); values.push(name.trim()); } if (description !== undefined) { updates.push('description = ?'); values.push(description ? description.trim() : null); } if (url !== undefined) { // Validate URL format try { new URL(url); } catch (err) { const e = new Error('Invalid URL format'); e.code = 'VALIDATION_ERROR'; throw e; } updates.push('url = ?'); values.push(url.trim()); } if (category !== undefined) { updates.push('category = ?'); values.push(category.trim()); } if (is_active !== undefined) { updates.push('is_active = ?'); values.push(is_active); } if (commission_rate !== undefined) { updates.push('commission_rate = ?'); values.push(commission_rate); } if (object_storage_id !== undefined) { updates.push('object_storage_id = ?'); values.push(object_storage_id); } if (original_filename !== undefined) { updates.push('original_filename = ?'); values.push(original_filename); } if (updates.length === 0) { logger.warn('[AffiliateService.update] no fields to update', { id }); return await exports.get(id); } updates.push('updated_at = NOW()'); values.push(id); await db.query(`UPDATE affiliates SET ${updates.join(', ')} WHERE id = ?`, values); logger.info('[AffiliateService.update] updated', { id }); return await exports.get(id); }; exports.updateStatus = async (id, is_active) => { await db.query('UPDATE affiliates SET is_active = ?, updated_at = NOW() WHERE id = ?', [is_active, id]); logger.info('[AffiliateService.updateStatus] updated', { id, is_active }); return await exports.get(id); }; exports.delete = async (id) => { await db.query('DELETE FROM affiliates WHERE id = ?', [id]); logger.info('[AffiliateService.delete] deleted', { id }); };