feat: update invoice template loading to fetch from S3 and streamline user type handling

This commit is contained in:
seaznCode 2026-03-11 22:29:46 +01:00
parent bab648d3ca
commit 5232fb1f2d

View File

@ -8,8 +8,6 @@ const { GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
const { s3: sharedExoscaleClient } = require('../../utils/exoscaleUploader'); const { s3: sharedExoscaleClient } = require('../../utils/exoscaleUploader');
const { logger } = require('../../middleware/logger'); const { logger } = require('../../middleware/logger');
const puppeteer = require('puppeteer'); const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');
const CompanySettingsRepository = require('../../repositories/settings/CompanySettingsRepository'); const CompanySettingsRepository = require('../../repositories/settings/CompanySettingsRepository');
@ -165,10 +163,19 @@ class InvoiceService {
}).join(''); }).join('');
} }
_loadInvoiceHtmlTemplate() { async _loadInvoiceHtmlTemplate() {
// Load the latest active invoice template from the contract manager (S3)
try { try {
const templatePath = path.join(__dirname, '..', '..', 'templates', 'invoice', 'invoiceTemplate.html'); const templates = await DocumentTemplateService.getActiveTemplatesForUserType('both', 'invoice');
return fs.readFileSync(templatePath, 'utf8'); if (!Array.isArray(templates) || !templates.length) return null;
const selected = templates[0]; // latest active version
if (!selected?.storageKey) return null;
const command = new GetObjectCommand({
Bucket: process.env.EXOSCALE_BUCKET,
Key: selected.storageKey,
});
const obj = await sharedExoscaleClient.send(command);
return await this._s3BodyToString(obj.Body) || null;
} catch (e) { } catch (e) {
logger.warn('InvoiceService._loadInvoiceHtmlTemplate:error', { message: e?.message }); logger.warn('InvoiceService._loadInvoiceHtmlTemplate:error', { message: e?.message });
return null; return null;
@ -267,7 +274,7 @@ class InvoiceService {
async _buildFallbackInvoiceHtml({ invoice, items, abonement, lang }) { async _buildFallbackInvoiceHtml({ invoice, items, abonement, lang }) {
const variables = await this._buildInvoiceTemplateVariables({ invoice, items, abonement, lang }); const variables = await this._buildInvoiceTemplateVariables({ invoice, items, abonement, lang });
const template = this._loadInvoiceHtmlTemplate(); const template = await this._loadInvoiceHtmlTemplate();
if (template) { if (template) {
return this._renderTemplate(template, variables); return this._renderTemplate(template, variables);
} }
@ -288,9 +295,9 @@ class InvoiceService {
</html>`; </html>`;
} }
async _loadInvoiceTemplateHtml({ userType = 'personal', lang = 'en' } = {}) { async _loadInvoiceTemplateHtml({ lang = 'en' } = {}) {
try { try {
const templates = await DocumentTemplateService.getActiveTemplatesForUserType(userType, 'invoice'); const templates = await DocumentTemplateService.getActiveTemplatesForUserType('both', 'invoice');
if (!Array.isArray(templates) || !templates.length) return null; if (!Array.isArray(templates) || !templates.length) return null;
const selected = templates.find((t) => t.lang === lang) || templates.find((t) => t.lang === 'en') || templates[0]; const selected = templates.find((t) => t.lang === lang) || templates.find((t) => t.lang === 'en') || templates[0];
@ -347,7 +354,7 @@ class InvoiceService {
return key; return key;
} }
async _sendInvoiceEmail({ invoice, abonement, userType = 'personal', lang = 'en' }) { async _sendInvoiceEmail({ invoice, abonement, lang = 'en' }) {
const recipientEmail = invoice.buyer_email || abonement?.email; const recipientEmail = invoice.buyer_email || abonement?.email;
if (!recipientEmail) { if (!recipientEmail) {
logger.warn('InvoiceService._sendInvoiceEmail:missing_recipient', { invoiceId: invoice.id }); logger.warn('InvoiceService._sendInvoiceEmail:missing_recipient', { invoiceId: invoice.id });
@ -361,7 +368,7 @@ class InvoiceService {
// Build the full set of template variables once used by both S3 and local paths // Build the full set of template variables once used by both S3 and local paths
const variables = await this._buildInvoiceTemplateVariables({ invoice, items, abonement, lang }); const variables = await this._buildInvoiceTemplateVariables({ invoice, items, abonement, lang });
const templateHtml = await this._loadInvoiceTemplateHtml({ userType, lang }); const templateHtml = await this._loadInvoiceTemplateHtml({ lang });
let html = null; let html = null;
if (templateHtml) { if (templateHtml) {
@ -414,7 +421,7 @@ class InvoiceService {
} }
// Issue invoice for a subscription period, with items from pack_breakdown // Issue invoice for a subscription period, with items from pack_breakdown
async issueForAbonement(abonement, periodStart, periodEnd, { actorUserId, userType = 'personal', lang = 'en' } = {}) { async issueForAbonement(abonement, periodStart, periodEnd, { actorUserId, lang = 'en' } = {}) {
console.log('[INVOICE ISSUE] Inputs:', { console.log('[INVOICE ISSUE] Inputs:', {
abonement_id: abonement?.id, abonement_id: abonement?.id,
abonement_user_id: abonement?.user_id, abonement_user_id: abonement?.user_id,
@ -505,7 +512,6 @@ class InvoiceService {
await this._sendInvoiceEmail({ await this._sendInvoiceEmail({
invoice, invoice,
abonement, abonement,
userType,
lang, lang,
}); });
logger.info('InvoiceService.issueForAbonement:invoice_email_sent', { logger.info('InvoiceService.issueForAbonement:invoice_email_sent', {