232 lines
9.7 KiB
JavaScript
232 lines
9.7 KiB
JavaScript
const DocumentTemplateRepository = require('../../repositories/template/DocumentTemplateRepository');
|
|
const UnitOfWork = require('../../database/UnitOfWork');
|
|
const { logger } = require('../../middleware/logger');
|
|
|
|
class DocumentTemplateService {
|
|
async listTemplates() {
|
|
logger.info('DocumentTemplateService.listTemplates:start');
|
|
try {
|
|
const templates = await DocumentTemplateRepository.findAll();
|
|
logger.info('DocumentTemplateService.listTemplates:success', { count: templates.length });
|
|
return templates.map(t => ({
|
|
...t,
|
|
lang: t.lang
|
|
}));
|
|
} catch (error) {
|
|
logger.error('DocumentTemplateService.listTemplates:error', { error: error.message });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async uploadTemplate(data) {
|
|
logger.info('DocumentTemplateService.uploadTemplate:start', { name: data.name, type: data.type });
|
|
const uow = new UnitOfWork();
|
|
try {
|
|
await uow.start();
|
|
const allowed = ['personal','company','both'];
|
|
const user_type = allowed.includes(data.user_type || data.userType) ? (data.user_type || data.userType) : 'both';
|
|
const created = await DocumentTemplateRepository.create({ ...data, user_type }, uow.connection);
|
|
await uow.commit();
|
|
logger.info('DocumentTemplateService.uploadTemplate:success', { id: created.id });
|
|
return created;
|
|
} catch (err) {
|
|
logger.error('DocumentTemplateService.uploadTemplate:error', { error: err.message });
|
|
await uow.rollback(err);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
async getTemplate(id) {
|
|
logger.info('DocumentTemplateService.getTemplate:start', { id });
|
|
try {
|
|
const template = await DocumentTemplateRepository.findById(id);
|
|
if (!template) {
|
|
logger.warn('DocumentTemplateService.getTemplate:not_found', { id });
|
|
return null;
|
|
}
|
|
logger.debug('DocumentTemplateService.getTemplate:meta', { id, storageKey: template.storageKey, lang: template.lang, version: template.version });
|
|
logger.info('DocumentTemplateService.getTemplate:success', { id });
|
|
return { ...template, lang: template.lang };
|
|
} catch (error) {
|
|
logger.error('DocumentTemplateService.getTemplate:error', { id, error: error.message });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async deleteTemplate(id) {
|
|
logger.info('DocumentTemplateService.deleteTemplate:start', { id });
|
|
const uow = new UnitOfWork();
|
|
try {
|
|
await uow.start();
|
|
await DocumentTemplateRepository.delete(id, uow.connection);
|
|
await uow.commit();
|
|
logger.info('DocumentTemplateService.deleteTemplate:success', { id });
|
|
return true;
|
|
} catch (err) {
|
|
logger.error('DocumentTemplateService.deleteTemplate:error', { id, error: err.message });
|
|
await uow.rollback(err);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
async updateTemplate(id, data) {
|
|
logger.info('DocumentTemplateService.updateTemplate:start', { id });
|
|
const uow = new UnitOfWork();
|
|
try {
|
|
await uow.start();
|
|
const current = await DocumentTemplateRepository.findById(id, uow.connection);
|
|
if (!current) {
|
|
logger.warn('DocumentTemplateService.updateTemplate:not_found', { id });
|
|
await uow.rollback();
|
|
return null;
|
|
}
|
|
const allowed = ['personal','company','both'];
|
|
if (data.userType && !allowed.includes(data.userType)) delete data.userType;
|
|
if (data.user_type && !allowed.includes(data.user_type)) delete data.user_type;
|
|
const newVersion = (current.version || 1) + 1;
|
|
await DocumentTemplateRepository.update(
|
|
id,
|
|
{ ...data, version: newVersion, user_type: data.user_type || data.userType || current.user_type },
|
|
uow.connection
|
|
);
|
|
const updated = await DocumentTemplateRepository.findById(id, uow.connection);
|
|
await uow.commit();
|
|
logger.info('DocumentTemplateService.updateTemplate:success', { id, version: newVersion });
|
|
return updated;
|
|
} catch (err) {
|
|
logger.error('DocumentTemplateService.updateTemplate:error', { id, error: err.message });
|
|
await uow.rollback(err);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
async updateTemplateState(id, state) {
|
|
logger.info('DocumentTemplateService.updateTemplateState:start', { id, state });
|
|
const uow = new UnitOfWork();
|
|
try {
|
|
await uow.start();
|
|
await DocumentTemplateRepository.updateState(id, state, uow.connection);
|
|
const updated = await DocumentTemplateRepository.findById(id, uow.connection);
|
|
await uow.commit();
|
|
logger.info('DocumentTemplateService.updateTemplateState:success', { id, state });
|
|
return updated;
|
|
} catch (err) {
|
|
logger.error('DocumentTemplateService.updateTemplateState:error', { id, state, error: err.message });
|
|
await uow.rollback(err);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
async getActiveTemplatesForUserType(userType, templateType = null) {
|
|
logger.info('DocumentTemplateService.getActiveTemplatesForUserType:start', { userType, templateType });
|
|
try {
|
|
const rows = await DocumentTemplateRepository.findActiveByUserType(userType, templateType);
|
|
logger.info('DocumentTemplateService.getActiveTemplatesForUserType:success', { count: rows.length });
|
|
return rows.map(t => ({ ...t, lang: t.lang }));
|
|
} catch (error) {
|
|
logger.error('DocumentTemplateService.getActiveTemplatesForUserType:error', { error: error.message });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// NEW: Retrieve Profit Planet signature (company stamp) as <img> tag
|
|
// Fallback order:
|
|
// 1) Active stamp for provided companyId
|
|
// 2) Any stamp for provided companyId
|
|
// 3) Any active stamp globally
|
|
// 4) Any stamp globally
|
|
async getProfitPlanetSignatureTag({ companyId = null, maxW = 300, maxH = 300 } = {}) {
|
|
const uow = new UnitOfWork();
|
|
const result = { tag: '', reason: 'not_started' };
|
|
logger.debug('DocumentTemplateService.getProfitPlanetSignatureTag:enter', { companyId, maxW, maxH });
|
|
try {
|
|
await uow.start();
|
|
const conn = uow.connection;
|
|
|
|
const safeRowMeta = (row) => {
|
|
if (!row) return null;
|
|
return {
|
|
has_image: !!row.image_base64,
|
|
mime: row.mime_type,
|
|
image_len: row.image_base64 ? row.image_base64.length : 0,
|
|
image_head: row.image_base64 ? row.image_base64.slice(0, 30) : ''
|
|
};
|
|
};
|
|
|
|
// Helper to run single-row query safely
|
|
const fetchOne = async (sql, params, reasonCode) => {
|
|
logger.debug('DocumentTemplateService.getProfitPlanetSignatureTag:query:start', { reasonCode, sql, params });
|
|
try {
|
|
const started = Date.now();
|
|
const [rows] = await conn.execute(sql, params);
|
|
const ms = Date.now() - started;
|
|
const rowCount = rows ? rows.length : 0;
|
|
logger.debug('DocumentTemplateService.getProfitPlanetSignatureTag:query:result', {
|
|
reasonCode,
|
|
duration_ms: ms,
|
|
rowCount,
|
|
firstRow: safeRowMeta(rows && rows[0])
|
|
});
|
|
if (rows && rows[0] && rows[0].image_base64) {
|
|
const mime = rows[0].mime_type || 'image/png';
|
|
const dataUri = `data:${mime};base64,${rows[0].image_base64}`;
|
|
result.tag = `<img src="${dataUri}" style="max-width:${maxW}px;max-height:${maxH}px;">`;
|
|
result.reason = reasonCode;
|
|
logger.debug('DocumentTemplateService.getProfitPlanetSignatureTag:query:match', {
|
|
reasonCode,
|
|
mime,
|
|
dataUri_len: dataUri.length,
|
|
dataUri_head: dataUri.slice(0, 45)
|
|
});
|
|
return true;
|
|
}
|
|
} catch (e) {
|
|
logger.warn('DocumentTemplateService.getProfitPlanetSignatureTag:query_error', { reason: reasonCode, error: e.message });
|
|
}
|
|
return false;
|
|
};
|
|
|
|
if (companyId) {
|
|
if (await fetchOne(
|
|
'SELECT mime_type,image_base64 FROM company_stamps WHERE company_id = ? AND is_active = 1 ORDER BY id DESC LIMIT 1',
|
|
[companyId],
|
|
'company_active'
|
|
)) { await uow.commit(); logger.debug('DocumentTemplateService.getProfitPlanetSignatureTag:exit', { reason: result.reason }); return result; }
|
|
|
|
if (await fetchOne(
|
|
'SELECT mime_type,image_base64 FROM company_stamps WHERE company_id = ? ORDER BY is_active DESC, id DESC LIMIT 1',
|
|
[companyId],
|
|
'company_any'
|
|
)) { await uow.commit(); logger.debug('DocumentTemplateService.getProfitPlanetSignatureTag:exit', { reason: result.reason }); return result; }
|
|
}
|
|
|
|
if (await fetchOne(
|
|
'SELECT mime_type,image_base64 FROM company_stamps WHERE is_active = 1 ORDER BY id DESC LIMIT 1',
|
|
[],
|
|
'global_active'
|
|
)) { await uow.commit(); logger.debug('DocumentTemplateService.getProfitPlanetSignatureTag:exit', { reason: result.reason }); return result; }
|
|
|
|
if (await fetchOne(
|
|
'SELECT mime_type,image_base64 FROM company_stamps ORDER BY is_active DESC, id DESC LIMIT 1',
|
|
[],
|
|
'global_any'
|
|
)) { await uow.commit(); logger.debug('DocumentTemplateService.getProfitPlanetSignatureTag:exit', { reason: result.reason }); return result; }
|
|
|
|
result.reason = 'not_found';
|
|
await uow.commit();
|
|
logger.debug('DocumentTemplateService.getProfitPlanetSignatureTag:not_found', { companyId });
|
|
return result;
|
|
} catch (err) {
|
|
result.reason = 'error';
|
|
logger.error('DocumentTemplateService.getProfitPlanetSignatureTag:error', { error: err.message, companyId });
|
|
try { await uow.rollback(err); } catch (rbErr) {
|
|
logger.error('DocumentTemplateService.getProfitPlanetSignatureTag:rollback_error', { error: rbErr.message });
|
|
}
|
|
return result;
|
|
} finally {
|
|
logger.debug('DocumentTemplateService.getProfitPlanetSignatureTag:final', { reason: result.reason, hasTag: !!result.tag });
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = new DocumentTemplateService(); |