diff --git a/services/invoice/InvoiceService.js b/services/invoice/InvoiceService.js index 714836b..6d6a2c8 100644 --- a/services/invoice/InvoiceService.js +++ b/services/invoice/InvoiceService.js @@ -11,7 +11,6 @@ const fs = require('fs/promises'); const path = require('path'); const pool = require('../../database/database'); -const CompanySettingsRepository = require('../../repositories/settings/CompanySettingsRepository'); const CoffeeShippingFeeService = require('../subscriptions/CoffeeShippingFeeService'); class InvoiceService { @@ -19,15 +18,6 @@ class InvoiceService { this.repo = new InvoiceRepository(); } - _inferImageMimeFromBase64(base64) { - const s = String(base64 || '').trim(); - if (!s) return 'image/png'; - if (s.startsWith('iVBORw0KGgo')) return 'image/png'; - if (s.startsWith('/9j/')) return 'image/jpeg'; - if (s.startsWith('R0lGOD')) return 'image/gif'; - return 'image/png'; - } - _templateHasVars(template, varNames) { if (!template) return false; return varNames.every((name) => { @@ -47,15 +37,19 @@ class InvoiceService { } _resolvePieceCountForQr(abonement) { + const breakdown = Array.isArray(abonement?.pack_breakdown) ? abonement.pack_breakdown : []; + const totalPacks = breakdown.reduce((sum, item) => sum + Number(item?.packs || item?.quantity || 0), 0); + const piecesByPack = totalPacks ? totalPacks * 10 : null; + if (piecesByPack != null) { + if (piecesByPack >= 120) return 120; + if (piecesByPack >= 60) return 60; + return null; + } + const packGroup = String(abonement?.pack_group || '').toLowerCase(); if (packGroup.includes('120')) return 120; if (packGroup.includes('60')) return 60; - const breakdown = Array.isArray(abonement?.pack_breakdown) ? abonement.pack_breakdown : []; - const totalPacks = breakdown.reduce((sum, item) => sum + Number(item?.packs || 0), 0); - const piecesByPack = totalPacks ? totalPacks * 10 : null; - if (piecesByPack === 60 || piecesByPack === 120) return piecesByPack; - return null; } @@ -107,35 +101,8 @@ class InvoiceService { return items; } - async _getCompanySettingsQrDataUri(pieceCount) { - const safePieceCount = pieceCount === 120 ? 120 : 60; - try { - const repo = new CompanySettingsRepository(); - const row = await repo.get(); - if (!row) return null; - const raw = safePieceCount === 120 ? row?.qr_code_120_base64 : row?.qr_code_60_base64; - const value = (raw == null) ? '' : String(raw).trim(); - if (!value) return null; - if (value.startsWith('data:image/')) return value; - const mime = this._inferImageMimeFromBase64(value); - return `data:${mime};base64,${value}`; - } catch (e) { - logger.warn('InvoiceService._getCompanySettingsQrDataUri:error', { - pieceCount: safePieceCount, - message: e?.message, - }); - return null; - } - } - async _buildQrCodeImageTag({ abonement }) { - const pieceCount = this._resolvePieceCountForQr(abonement); - if (!pieceCount) return ''; - - const dataUri = await this._getCompanySettingsQrDataUri(pieceCount); - if (!dataUri) return ''; - - return `QR Code`; + return ''; } _escapeHtml(value) { @@ -312,11 +279,10 @@ class InvoiceService { _prepareVariablesForTemplate(templateHtml, variables) { // Ensure backwards compatibility with older templates that only contain {{paymentInfoText}} - // by injecting the Profit Planet bank block (and optionally QR) into paymentInfoText. + // by injecting the Profit Planet bank block into paymentInfoText. if (!templateHtml) return variables; const supportsBankVars = this._templateHasVars(templateHtml, ['bankAccountHolder', 'bankIban', 'bankBic']); - const supportsQrVar = this._templateHasVars(templateHtml, ['qrCodeImage']); const bankBlock = this._getProfitPlanetBankBlockHtml({ bankAccountHolder: variables.bankAccountHolder || 'Profit Planet GmbH', @@ -330,11 +296,6 @@ class InvoiceService { next.paymentInfoText = bankBlock; } - if (!supportsQrVar && variables.qrCodeImage) { - // Append QR under payment info text when there's no dedicated placeholder - next.paymentInfoText = `${next.paymentInfoText || ''}

${variables.qrCodeImage}`; - } - return next; } @@ -559,29 +520,14 @@ class InvoiceService { if (templateHtml) { const supportsBankVars = this._templateHasVars(templateHtml, ['bankAccountHolder', 'bankIban', 'bankBic']); - const supportsQrVar = this._templateHasVars(templateHtml, ['qrCodeImage']); - const pieceCountForQr = this._resolvePieceCountForQr(abonement); logger.info('InvoiceService._sendInvoiceEmail:template_compat', { invoiceId: invoice?.id, lang, supportsBankVars, - supportsQrVar, - pieceCountForQr, - hasQrImage: Boolean(variables?.qrCodeImage), }); const varsForTemplate = this._prepareVariablesForTemplate(templateHtml, variables); html = this._renderTemplate(templateHtml, varsForTemplate); - - // Final guard: if we still didn't embed QR but we expected one, force local template - const missingQr = variables.qrCodeImage && !html.includes('data:image/png;base64,'); - if (missingQr) { - const localTemplate = await this._loadLocalInvoiceTemplateHtml(); - if (localTemplate) { - const varsForLocal = this._prepareVariablesForTemplate(localTemplate, variables); - html = this._renderTemplate(localTemplate, varsForLocal); - } - } } const htmlForPdf = html || await this._buildFallbackInvoiceHtml({ invoice, items, abonement, lang });