feat: improve template variable handling and add Profit Planet signature stamp functionality

This commit is contained in:
seaznCode 2026-01-19 20:49:22 +01:00
parent 46b36d7edd
commit 25c67783d4
2 changed files with 56 additions and 27 deletions

View File

@ -1619,17 +1619,35 @@ exports.previewLatestForMe = async (req, res) => {
const [rows] = await db.execute('SELECT * FROM company_profiles WHERE user_id = ? LIMIT 1', [targetUserId]);
const c = rows && rows[0] ? rows[0] : null;
if (c) {
vars.companyName = c.company_name || '';
vars.registrationNumber = c.registration_number || '';
vars.companyAddress = c.address || '';
vars.address = vars.companyAddress;
vars.zip_code = c.zip_code || '';
vars.city = c.city || '';
vars.country = c.country || '';
vars.contactPersonName = c.contact_person_name || '';
vars.contactPersonPhone = c.contact_person_phone || c.phone || '';
vars.companyEmail = c.email || c.company_email || c.contact_email || req.user.email || '';
vars.companyPhone = c.phone || c.contact_person_phone || '';
setIfEmpty('companyName', c.company_name);
setIfEmpty('registrationNumber', c.registration_number);
setIfEmpty('companyAddress', c.address);
setIfEmpty('address', c.address);
setIfEmpty('zip_code', c.zip_code);
setIfEmpty('city', c.city);
setIfEmpty('country', c.country);
setIfEmpty('contactPersonName', c.contact_person_name);
setIfEmpty('contactPersonPhone', c.contact_person_phone || c.phone);
setIfEmpty('companyEmail', c.email || c.company_email || c.contact_email || req.user.email);
setIfEmpty('companyPhone', c.phone || c.contact_person_phone);
}
// Fallbacks from authenticated user payload (helps dummy/local users without profile rows)
setIfEmpty('companyName', req.user.companyName || req.user.company_name || req.user.company);
setIfEmpty('registrationNumber', req.user.registrationNumber || req.user.registration_number || req.user.vatNumber);
setIfEmpty('companyAddress', req.user.address || req.user.street || req.user.street_address);
setIfEmpty('address', req.user.address || req.user.street || req.user.street_address);
setIfEmpty('zip_code', req.user.zip_code || req.user.zip || req.user.postalCode || req.user.postal_code);
setIfEmpty('city', req.user.city || req.user.town);
setIfEmpty('country', req.user.country);
setIfEmpty('contactPersonName', req.user.contactPersonName || req.user.contact_person_name);
setIfEmpty('contactPersonPhone', req.user.contactPersonPhone || req.user.contact_person_phone || req.user.companyPhone || req.user.phone);
setIfEmpty('companyEmail', req.user.companyEmail || req.user.email);
setIfEmpty('companyPhone', req.user.companyPhone || req.user.phone);
if (!vars.companyAddress) setIfEmpty('companyAddress', vars.address);
if (!vars.address) setIfEmpty('address', vars.companyAddress);
const parts = [];
if (vars.companyAddress) parts.push(vars.companyAddress);
const zipCity = [vars.zip_code, vars.city].filter(Boolean).join(' ');
@ -1637,14 +1655,13 @@ exports.previewLatestForMe = async (req, res) => {
vars.companyFullAddress = parts.join(', ');
// Ensure template-prefixed company placeholders are populated
vars.companyCompanyName = vars.companyName;
vars.companyRegistrationNumber = vars.registrationNumber;
vars.companyZipCode = vars.zip_code;
vars.companyCity = vars.city;
vars.companyCompanyName = vars.companyName || '';
vars.companyRegistrationNumber = vars.registrationNumber || '';
vars.companyZipCode = vars.zip_code || '';
vars.companyCity = vars.city || '';
// Signature/display name for company preview
vars.fullName = vars.contactPersonName || vars.companyName || '';
}
vars.fullName = vars.contactPersonName || vars.companyName || vars.fullName || '';
logger.debug('[previewLatestForMe] company vars', { userId: targetUserId, found: !!c, vars });
} catch (e) {
logger.warn('[previewLatestForMe] company profile lookup failed', e && e.message);

View File

@ -3,6 +3,7 @@ const { uploadBuffer, s3: exoS3 } = require('../../utils/exoscaleUploader');
const PDFDocument = require('pdfkit');
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
const DocumentTemplateService = require('../template/DocumentTemplateService');
const CompanyStampService = require('../stamp/company/CompanyStampService');
const db = require('../../database/database');
const fs = require('fs');
const path = require('path');
@ -49,7 +50,7 @@ async function streamToBuffer(body) {
}
function fillTemplate(template, data) {
return template.replace(/{{(\w+)}}/g, (_, key) => data[key] || '');
return template.replace(/{{\s*(\w+)\s*}}/g, (_, key) => data[key] || '');
}
// Build placeholder variables by combining DB profile data with any contractData overrides (for both personal/company).
@ -310,7 +311,7 @@ class ContractUploadService {
// Merge DB-derived vars with request data so placeholders fill like the preview endpoint
const vars = await buildTemplateVars({ userId, user_type, contractData, unitOfWork });
Object.entries(vars).forEach(([key, value]) => {
const re = new RegExp(`{{\s*${key}\s*}}`, 'g');
const re = new RegExp(`{{\\s*${key}\\s*}}`, 'g');
htmlTemplate = htmlTemplate.replace(re, String(value ?? ''));
});
if (signatureImage) {
@ -319,6 +320,17 @@ class ContractUploadService {
htmlTemplate = htmlTemplate.replace(/{{\s*signatureImage\s*}}/g, tag);
}
// Apply Profit Planet signature stamp if placeholder exists
try {
if (htmlTemplate.match(/{{\s*profitplanetSignature\s*}}/i)) {
const tag = await CompanyStampService.getProfitPlanetSignatureTag({ maxW: 300, maxH: 300 });
htmlTemplate = htmlTemplate.replace(/{{\s*profitplanetSignature\s*}}/gi, tag || '');
}
} catch (e) {
logger.warn('ContractUploadService.uploadContract:profitplanetSignature failed', { userId, msg: e.message });
htmlTemplate = htmlTemplate.replace(/{{\s*profitplanetSignature\s*}}/gi, '');
}
// Render HTML to PDF via Puppeteer (closest to preview output)
const browser = await puppeteer.launch({ headless: 'new', args: ['--no-sandbox', '--disable-setuid-sandbox'] });
const page = await browser.newPage();