const db = require('../../database/database'); const { logger } = require('../../middleware/logger'); class DocumentTemplateRepository { async create(data, conn) { logger.info('DocumentTemplateRepository.create:start', { name: data.name, type: data.type }); // ADDED: validate required fields + normalize optional fields const required = ['name', 'type', 'storageKey', 'lang']; for (const k of required) { const v = data[k]; if (v === undefined || v === null || String(v).trim() === '') { const err = new Error(`Invalid document template: missing field "${k}"`); err.code = 'INVALID_TEMPLATE_DATA'; logger.error('DocumentTemplateRepository.create:invalid', { field: k }); throw err; } } const name = String(data.name); const type = String(data.type); const storageKey = String(data.storageKey); const description = data.description === undefined ? null : data.description; // avoid undefined bind const lang = String(data.lang); const allowedUserTypes = new Set(['personal', 'company', 'both']); const user_type = allowedUserTypes.has(data.user_type || data.userType) ? (data.user_type || data.userType) : 'both'; const query = ` INSERT INTO document_templates (name, type, storageKey, description, lang, user_type, version, state, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?, 1, 'inactive', NOW(), NOW()) `; try { if (conn) { const [res] = await conn.execute(query, [name, type, storageKey, description, lang, user_type]); const insertId = res && (res.insertId || res[0]?.insertId); logger.info('DocumentTemplateRepository.create:success', { id: insertId || res.insertId }); return { id: insertId || res.insertId, name, type, storageKey, description, lang, user_type, version: 1, state: 'inactive' }; } const result = await db.execute(query, [name, type, storageKey, description, lang, user_type]); const insertId = result && result.insertId ? result.insertId : (Array.isArray(result) && result[0] && result[0].insertId ? result[0].insertId : undefined); logger.info('DocumentTemplateRepository.create:success', { id: insertId }); return { id: insertId, name, type, storageKey, description, lang, user_type, version: 1, state: 'inactive' }; } catch (error) { logger.error('DocumentTemplateRepository.create:error', { error: error.message }); throw error; } } async findAll(conn) { logger.info('DocumentTemplateRepository.findAll:start'); const query = `SELECT * FROM document_templates ORDER BY createdAt DESC`; try { if (conn) { const [rows] = await conn.execute(query); logger.info('DocumentTemplateRepository.findAll:success'); return rows; } const result = await db.execute(query); // db.execute may return rows directly or [rows, fields] if (Array.isArray(result) && Array.isArray(result[0])) return result[0]; logger.info('DocumentTemplateRepository.findAll:success'); return result; } catch (error) { logger.error('DocumentTemplateRepository.findAll:error', { error: error.message }); throw error; } } async findById(id, conn) { logger.info('DocumentTemplateRepository.findById:start', { id }); const query = `SELECT * FROM document_templates WHERE id = ? LIMIT 1`; try { if (conn) { const [rows] = await conn.execute(query, [id]); logger.info('DocumentTemplateRepository.findById:success', { id }); return (rows && rows[0]) ? rows[0] : null; } const result = await db.execute(query, [id]); if (Array.isArray(result) && Array.isArray(result[0])) { return result[0][0] || null; } logger.info('DocumentTemplateRepository.findById:success', { id }); return (result && result[0]) ? result[0] : null; } catch (error) { logger.error('DocumentTemplateRepository.findById:error', { id, error: error.message }); throw error; } } async update(id, data, conn) { logger.info('DocumentTemplateRepository.update:start', { id, data }); // data: { name, type, storageKey, description, lang, version } const fields = []; const values = []; for (const key of ['name', 'type', 'storageKey', 'description', 'lang', 'version', 'user_type']) { if (data[key] !== undefined) { fields.push(`${key} = ?`); values.push(data[key]); } } // Support camelCase input if (data.userType !== undefined && data.user_type === undefined) { fields.push(`user_type = ?`); values.push(data.userType); } // Do not update state here if (!fields.length) return false; const query = ` UPDATE document_templates SET ${fields.join(', ')}, updatedAt = NOW() WHERE id = ? `; values.push(id); try { if (conn) await conn.execute(query, values); else await db.execute(query, values); logger.info('DocumentTemplateRepository.update:success', { id }); return true; } catch (error) { logger.error('DocumentTemplateRepository.update:error', { id, error: error.message }); throw error; } } async updateState(id, state, conn) { logger.info('DocumentTemplateRepository.updateState:start', { id, state }); const query = ` UPDATE document_templates SET state = ?, updatedAt = NOW() WHERE id = ? `; try { if (conn) await conn.execute(query, [state, id]); else await db.execute(query, [state, id]); logger.info('DocumentTemplateRepository.updateState:success', { id, state }); return true; } catch (error) { logger.error('DocumentTemplateRepository.updateState:error', { id, error: error.message }); throw error; } } async delete(id, conn) { logger.info('DocumentTemplateRepository.delete:start', { id }); const query = `DELETE FROM document_templates WHERE id = ?`; try { if (conn) await conn.execute(query, [id]); else await db.execute(query, [id]); logger.info('DocumentTemplateRepository.delete:success', { id }); return true; } catch (error) { logger.error('DocumentTemplateRepository.delete:error', { id, error: error.message }); throw error; } } async findActiveByUserType(userType, templateType = null, conn) { logger.info('DocumentTemplateRepository.findActiveByUserType:start', { userType, templateType }); const safeType = (userType === 'personal' || userType === 'company') ? userType : 'personal'; let query = `SELECT * FROM document_templates WHERE state = 'active' AND (user_type = ? OR user_type = 'both')`; const params = [safeType]; if (templateType) { query += ` AND type = ?`; params.push(templateType); } query += ` ORDER BY createdAt DESC`; try { if (conn) { const [rows] = await conn.execute(query, params); logger.info('DocumentTemplateRepository.findActiveByUserType:success', { count: rows.length }); return rows; } const result = await db.execute(query, params); const rows = Array.isArray(result) && Array.isArray(result[0]) ? result[0] : result; logger.info('DocumentTemplateRepository.findActiveByUserType:success', { count: rows.length }); return rows; } catch (error) { logger.error('DocumentTemplateRepository.findActiveByUserType:error', { error: error.message }); throw error; } } } module.exports = new DocumentTemplateRepository();