feat: contract adjustments + refferral adjustments

This commit is contained in:
DeathKaioken 2025-12-13 12:00:01 +01:00
parent b73f8b9b4b
commit 440aa8323b
5 changed files with 27 additions and 15 deletions

View File

@ -125,7 +125,8 @@ async function enrichTemplate(template, s3, serverBaseUrl = null) {
} }
if (serverBaseUrl) { if (serverBaseUrl) {
previewUrl = `${serverBaseUrl}/api/document-templates/${template.id}/preview`; // CHANGED: route path must match getRoutes.js
previewUrl = `${serverBaseUrl}/document-templates/${template.id}/preview`;
} else { } else {
previewUrl = fileUrl; previewUrl = fileUrl;
} }
@ -1253,7 +1254,7 @@ exports.previewPdf = async (req, res) => {
html = html.replace(/{{\s*currentDate\s*}}/g, formatDateTime()); html = html.replace(/{{\s*currentDate\s*}}/g, formatDateTime());
} }
// Apply stamps/signature placeholders where appropriate (harmless for sanitized content) // Apply stamps/signature where appropriate (harmless for sanitized content)
try { html = await applyCompanyStampPlaceholders(html, req); } catch (e) { logger.warn('[previewPdf] applyCompanyStampPlaceholders failed', e && e.message); } try { html = await applyCompanyStampPlaceholders(html, req); } catch (e) { logger.warn('[previewPdf] applyCompanyStampPlaceholders failed', e && e.message); }
try { html = await applyProfitPlanetSignature(html); } catch (e) { logger.warn('[previewPdf] applyProfitPlanetSignature failed', e && e.message); } try { html = await applyProfitPlanetSignature(html); } catch (e) { logger.warn('[previewPdf] applyProfitPlanetSignature failed', e && e.message); }

View File

@ -1,4 +1,4 @@
// This file is now just a field reference for document_templates table // This file is now just a field reference for document_templates table
module.exports = { module.exports = {
fields: ['id', 'name', 'type', 'storageKey', 'description', 'lang', 'version', 'state', 'createdAt', 'updatedAt'] fields: ['id', 'name', 'type', 'storageKey', 'description', 'lang', 'user_type', 'version', 'state', 'createdAt', 'updatedAt']
}; };

View File

@ -75,8 +75,6 @@ class ReferralTokenRepository {
rt.status, rt.status,
rt.created_at, rt.created_at,
rt.updated_at, rt.updated_at,
rt.max_uses_label AS max_uses_label,
rt.uses_remaining_label AS uses_remaining_label,
(SELECT COUNT(*) FROM referral_token_usage rtu WHERE rtu.referral_token_id = rt.id) AS usage_count, (SELECT COUNT(*) FROM referral_token_usage rtu WHERE rtu.referral_token_id = rt.id) AS usage_count,
CASE CASE
WHEN rt.max_uses = -1 THEN 0 WHEN rt.max_uses = -1 THEN 0
@ -94,8 +92,6 @@ class ReferralTokenRepository {
id: r.id, id: r.id,
max_uses: r.max_uses, max_uses: r.max_uses,
uses_remaining: r.uses_remaining, uses_remaining: r.uses_remaining,
max_uses_label: r.max_uses_label,
uses_remaining_label: r.uses_remaining_label,
used_count: r.used_count used_count: r.used_count
}); });
}); });
@ -191,8 +187,6 @@ class ReferralTokenRepository {
rt.expires_at, rt.expires_at,
rt.max_uses AS max_uses, rt.max_uses AS max_uses,
rt.uses_remaining AS uses_remaining, rt.uses_remaining AS uses_remaining,
rt.max_uses_label AS max_uses_label,
rt.uses_remaining_label AS uses_remaining_label,
CASE CASE
WHEN rt.max_uses = -1 THEN 0 WHEN rt.max_uses = -1 THEN 0
WHEN rt.max_uses IS NULL OR rt.uses_remaining IS NULL THEN 0 WHEN rt.max_uses IS NULL OR rt.uses_remaining IS NULL THEN 0
@ -215,8 +209,6 @@ class ReferralTokenRepository {
token: r.token, token: r.token,
max_uses: r.max_uses, max_uses: r.max_uses,
uses_remaining: r.uses_remaining, uses_remaining: r.uses_remaining,
max_uses_label: r.max_uses_label,
uses_remaining_label: r.uses_remaining_label,
used_count: r.used_count used_count: r.used_count
}); });
logger.info('ReferralTokenRepository.getReferrerInfoByToken:success', { token }); logger.info('ReferralTokenRepository.getReferrerInfoByToken:success', { token });

View File

@ -4,8 +4,25 @@ const { logger } = require('../../middleware/logger');
class DocumentTemplateRepository { class DocumentTemplateRepository {
async create(data, conn) { async create(data, conn) {
logger.info('DocumentTemplateRepository.create:start', { name: data.name, type: data.type }); logger.info('DocumentTemplateRepository.create:start', { name: data.name, type: data.type });
const { name, type, storageKey, description, lang } = data; // ADDED: validate required fields + normalize optional fields
const user_type = (data.user_type || data.userType || 'both'); 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 = ` const query = `
INSERT INTO document_templates (name, type, storageKey, description, lang, user_type, version, state, createdAt, updatedAt) INSERT INTO document_templates (name, type, storageKey, description, lang, user_type, version, state, createdAt, updatedAt)
VALUES (?, ?, ?, ?, ?, ?, 1, 'inactive', NOW(), NOW()) VALUES (?, ?, ?, ?, ?, ?, 1, 'inactive', NOW(), NOW())

View File

@ -103,6 +103,8 @@ router.get('/document-templates/:id', authMiddleware, DocumentTemplateController
router.get('/document-templates-public', authMiddleware, adminOnly, DocumentTemplateController.listTemplatesPublic); router.get('/document-templates-public', authMiddleware, adminOnly, DocumentTemplateController.listTemplatesPublic);
router.get('/document-templates/:id/generate-pdf', authMiddleware, DocumentTemplateController.generatePdf); router.get('/document-templates/:id/generate-pdf', authMiddleware, DocumentTemplateController.generatePdf);
router.get('/document-templates/:id/preview', authMiddleware, DocumentTemplateController.previewTemplate); router.get('/document-templates/:id/preview', authMiddleware, DocumentTemplateController.previewTemplate);
router.get('/document-templates/:id/preview-pdf', authMiddleware, DocumentTemplateController.previewPdf);
router.get('/document-templates/active/mine', authMiddleware, DocumentTemplateController.listMyActiveTemplates);
router.get('/document-templates/:id/download-pdf', authMiddleware, DocumentTemplateController.downloadPdf); router.get('/document-templates/:id/download-pdf', authMiddleware, DocumentTemplateController.downloadPdf);
router.get('/api/document-templates', authMiddleware, adminOnly, DocumentTemplateController.listTemplatesFiltered); router.get('/api/document-templates', authMiddleware, adminOnly, DocumentTemplateController.listTemplatesFiltered);