/** * Add Dutch translations for client-facing email templates * * Translates authentication, ticketing, and billing email templates to Dutch * for client portal users. */ exports.up = async function(knex) { console.log('Adding Dutch email templates...'); // Get notification subtypes const subtypes = await knex('notification_subtypes') .select('id', 'name') .whereIn('name', [ 'email-verification', 'password-reset', 'portal-invitation', 'tenant-recovery', 'no-account-found', 'Ticket Assigned', 'Ticket Created', 'Ticket Updated', 'Ticket Closed', 'Ticket Comment Added', 'Invoice Generated', 'Payment Received', 'Payment Overdue' ]); const getSubtypeId = (name) => { const subtype = subtypes.find(s => s.name === name); if (!subtype) { throw new Error(`Notification subtype '${name}' not found`); } return subtype.id; }; // Insert Dutch templates await knex('system_email_templates').insert([ // Authentication templates // NOTE: email-verification template is managed in migration 20251029100000 { name: 'password-reset', language_code: 'nl', subject: 'Verzoek tot Wachtwoordherstel', notification_subtype_id: getSubtypeId('password-reset'), html_content: ` Verzoek tot Wachtwoordherstel

Verzoek tot Wachtwoordherstel

Veilige wachtwoordherstel voor uw account

Hallo {{userName}},

We hebben een verzoek ontvangen om het wachtwoord voor uw account gekoppeld aan {{email}} opnieuw in te stellen.

🔐 Beveiligingscontrole Account

Aangevraagd: Zojuist

Account e-mail: {{email}}

Geldig voor: {{expirationTime}}

Om een nieuw wachtwoord voor uw account aan te maken, klikt u op de knop hieronder:

Wachtwoord Opnieuw Instellen

Of kopieer deze link naar uw browser:

⚠️ Belangrijke Beveiligingsinformatie

Wat Nu?

  1. Klik op de herstelknop hierboven of gebruik de verstrekte link
  2. Maak een sterk, uniek wachtwoord voor uw account
  3. U wordt automatisch ingelogd na het opnieuw instellen
  4. Alle bestaande sessies worden beëindigd voor de beveiliging
  5. Overweeg tweefactorauthenticatie in te schakelen voor extra bescherming

Hulp Nodig?

Als u problemen ondervindt bij het opnieuw instellen van uw wachtwoord, staat ons ondersteuningsteam voor u klaar.

Contact Ondersteuning: {{supportEmail}}

`, text_content: `Verzoek tot Wachtwoordherstel Hallo {{userName}}, We hebben een verzoek ontvangen om het wachtwoord voor uw account gekoppeld aan {{email}} opnieuw in te stellen. BEVEILIGINGSCONTROLE ACCOUNT - Aangevraagd: Zojuist - Account e-mail: {{email}} - Geldig voor: {{expirationTime}} Om een nieuw wachtwoord aan te maken, bezoekt u de volgende link: {{resetLink}} BELANGRIJKE BEVEILIGINGSINFORMATIE: - Deze link verloopt over {{expirationTime}} - Kan slechts één keer worden gebruikt - Als u dit niet heeft aangevraagd, negeer deze e-mail - Uw wachtwoord verandert pas als u een nieuw wachtwoord aanmaakt WAT NU: 1. Gebruik de verstrekte link hierboven 2. Maak een sterk, uniek wachtwoord 3. U wordt automatisch ingelogd 4. Alle bestaande sessies worden beëindigd 5. Overweeg tweefactorauthenticatie in te schakelen Hulp nodig? Contact Ondersteuning: {{supportEmail}} --- Dit is een geautomatiseerde beveiligingse-mail verzonden naar {{email}}. © {{currentYear}} {{clientName}}. Alle rechten voorbehouden.` }, // NOTE: portal-invitation template is managed in migration 20251029100000 { name: 'tenant-recovery', language_code: 'nl', subject: '{{platformName}} - Uw inloglinks', notification_subtype_id: getSubtypeId('tenant-recovery'), html_content: `

{{platformName}}

Hallo,

U heeft toegang aangevraagd tot uw klantenpor{{#if isMultiple}}talen{{else}}taal{{/if}}. {{#if isMultiple}}We hebben {{tenantCount}} organisaties gevonden die gekoppeld zijn aan uw e-mailadres.{{else}}Hier is uw inloglink:{{/if}}

{{tenantLinksHtml}}

Beveiligingsopmerking: Als u deze inloglinks niet heeft aangevraagd, kunt u deze e-mail veilig negeren. Uw account blijft beveiligd.

Als u vragen heeft of hulp nodig heeft, neem dan contact op met het ondersteuningsteam van uw organisatie.

© {{currentYear}} {{platformName}}. Alle rechten voorbehouden.

Dit is een geautomatiseerd bericht. Reageer alstublieft niet op deze e-mail.

`, text_content: `{{platformName}} - Uw inloglinks Hallo, U heeft toegang aangevraagd tot uw klantenpor{{#if isMultiple}}talen{{else}}taal{{/if}}. {{#if isMultiple}}We hebben {{tenantCount}} organisaties gevonden die gekoppeld zijn aan uw e-mailadres.{{else}}Hier is uw inloglink:{{/if}} Uw inloglinks: {{tenantLinksText}} Beveiligingsopmerking: Als u deze inloglinks niet heeft aangevraagd, kunt u deze e-mail veilig negeren. Als u vragen heeft of hulp nodig heeft, neem dan contact op met het ondersteuningsteam van uw organisatie. --- © {{currentYear}} {{platformName}}. Alle rechten voorbehouden. Dit is een geautomatiseerd bericht. Reageer alstublieft niet op deze e-mail.` }, { name: 'no-account-found', language_code: 'nl', subject: '{{platformName}} - Toegangsverzoek', notification_subtype_id: getSubtypeId('no-account-found'), html_content: `

{{platformName}}

Hallo,

We hebben een verzoek ontvangen voor toegang tot het klantenportaal met dit e-mailadres.

Als u een account bij ons heeft, zou u een aparte e-mail moeten hebben ontvangen met uw inloglinks.

Als u geen inlog-e-mail heeft ontvangen, kan dit betekenen:

Hulp nodig?

Als u denkt dat u toegang zou moeten hebben tot een klantenportaal, neem dan contact op met het ondersteuningsteam van uw serviceprovider voor hulp.

Beveiligingsopmerking: Als u geen toegang heeft aangevraagd, kunt u deze e-mail veilig negeren.

© {{currentYear}} {{platformName}}. Alle rechten voorbehouden.

Dit is een geautomatiseerd bericht. Reageer alstublieft niet op deze e-mail.

`, text_content: `{{platformName}} - Toegangsverzoek Hallo, We hebben een verzoek ontvangen voor toegang tot het klantenportaal met dit e-mailadres. Als u een account bij ons heeft, zou u een aparte e-mail moeten hebben ontvangen met uw inloglinks. Als u geen inlog-e-mail heeft ontvangen, kan dit betekenen: - Dit e-mailadres is niet gekoppeld aan een klantenportalaccount - Uw account kan inactief zijn - De e-mail kan zijn gefilterd naar uw spam-map Hulp nodig? Als u denkt dat u toegang zou moeten hebben tot een klantenportaal, neem dan contact op met het ondersteuningsteam van uw serviceprovider voor hulp. Beveiligingsopmerking: Als u geen toegang heeft aangevraagd, kunt u deze e-mail veilig negeren. --- © {{currentYear}} {{platformName}}. Alle rechten voorbehouden. Dit is een geautomatiseerd bericht. Reageer alstublieft niet op deze e-mail.` }, // Ticketing templates { name: 'ticket-assigned', language_code: 'nl', subject: 'Ticket Toegewezen • {{ticket.title}} ({{ticket.priority}})', notification_subtype_id: getSubtypeId('Ticket Assigned'), html_content: `
Ticket Toegewezen
{{ticket.title}}
{{ticket.metaLine}}

Dit ticket is aan u toegewezen voor {{ticket.clientName}}. Bekijk de details hieronder en onderneem actie.

Ticket #{{ticket.id}}
Prioriteit {{ticket.priority}}
Status {{ticket.status}}
Toegewezen door {{ticket.assignedBy}}
Toegewezen aan
{{ticket.assignedToName}}
{{ticket.assignedToEmail}}
Aanvrager
{{ticket.requesterName}}
{{ticket.requesterContact}}
Bord {{ticket.board}}
Categorie {{ticket.categoryDetails}}
Locatie {{ticket.locationSummary}}
Beschrijving
{{ticket.description}}
Ticket Bekijken
Powered by Alga PSA • Teams op één lijn houden
`, text_content: ` Ticket Toegewezen aan U {{ticket.metaLine}} Toegewezen door: {{ticket.assignedBy}} Prioriteit: {{ticket.priority}} Status: {{ticket.status}} Toegewezen aan: {{ticket.assignedDetails}} Aanvrager: {{ticket.requesterDetails}} Bord: {{ticket.board}} Categorie: {{ticket.categoryDetails}} Locatie: {{ticket.locationSummary}} Beschrijving: {{ticket.description}} Ticket bekijken: {{ticket.url}} ` }, { name: 'ticket-created', language_code: 'nl', subject: 'Nieuw Ticket • {{ticket.title}} ({{ticket.priority}})', notification_subtype_id: getSubtypeId('Ticket Created'), html_content: `
Nieuw Ticket Aangemaakt
{{ticket.title}}
{{ticket.metaLine}}

Een nieuw ticket is geregistreerd voor {{ticket.clientName}}. Bekijk de samenvatting hieronder en volg de link om actie te ondernemen.

Ticket #{{ticket.id}}
Prioriteit {{ticket.priority}}
Status {{ticket.status}}
Aangemaakt {{ticket.createdAt}} · {{ticket.createdBy}}
Toegewezen aan
{{ticket.assignedToName}}
{{ticket.assignedToEmail}}
Aanvrager
{{ticket.requesterName}}
{{ticket.requesterContact}}
Bord {{ticket.board}}
Categorie {{ticket.categoryDetails}}
Locatie {{ticket.locationSummary}}
Beschrijving
{{ticket.description}}
Ticket Bekijken
Powered by Alga PSA • Teams op één lijn houden
`, text_content: ` Nieuw Ticket Aangemaakt voor {{ticket.clientName}} {{ticket.metaLine}} Aangemaakt: {{ticket.createdAt}} · {{ticket.createdBy}} Prioriteit: {{ticket.priority}} Status: {{ticket.status}} Toegewezen aan: {{ticket.assignedDetails}} Aanvrager: {{ticket.requesterDetails}} Bord: {{ticket.board}} Categorie: {{ticket.categoryDetails}} Locatie: {{ticket.locationSummary}} Beschrijving: {{ticket.description}} Ticket bekijken: {{ticket.url}} ` }, { name: 'ticket-updated', language_code: 'nl', subject: 'Ticket Bijgewerkt • {{ticket.title}} ({{ticket.priority}})', notification_subtype_id: getSubtypeId('Ticket Updated'), html_content: `
Ticket Bijgewerkt
{{ticket.title}}
{{ticket.metaLine}}

Een ticket is bijgewerkt voor {{ticket.clientName}}. Bekijk de wijzigingen hieronder.

Ticket #{{ticket.id}}
Prioriteit {{ticket.priority}}
Status {{ticket.status}}
Bijgewerkt door {{ticket.updatedBy}}
Toegewezen aan
{{ticket.assignedToName}}
{{ticket.assignedToEmail}}
Aanvrager
{{ticket.requesterName}}
{{ticket.requesterContact}}
Bord {{ticket.board}}
Categorie {{ticket.categoryDetails}}
Locatie {{ticket.locationSummary}}
Wijzigingen
{{ticket.changes}}
Ticket Bekijken
Powered by Alga PSA • Teams op één lijn houden
`, text_content: ` Ticket Bijgewerkt {{ticket.metaLine}} Bijgewerkt door: {{ticket.updatedBy}} Prioriteit: {{ticket.priority}} Status: {{ticket.status}} Toegewezen aan: {{ticket.assignedDetails}} Aanvrager: {{ticket.requesterDetails}} Bord: {{ticket.board}} Categorie: {{ticket.categoryDetails}} Locatie: {{ticket.locationSummary}} Wijzigingen: {{ticket.changes}} Ticket bekijken: {{ticket.url}} ` }, { name: 'ticket-closed', language_code: 'nl', subject: 'Ticket Gesloten • {{ticket.title}}', notification_subtype_id: getSubtypeId('Ticket Closed'), html_content: `
Ticket Gesloten
{{ticket.title}}
{{ticket.metaLine}}

Een ticket is opgelost en gesloten voor {{ticket.clientName}}. Bekijk de oplossingsdetails hieronder.

Ticket #{{ticket.id}}
Status Gesloten
Gesloten door {{ticket.closedBy}}
Toegewezen aan
{{ticket.assignedToName}}
{{ticket.assignedToEmail}}
Aanvrager
{{ticket.requesterName}}
{{ticket.requesterContact}}
Bord {{ticket.board}}
Categorie {{ticket.categoryDetails}}
Locatie {{ticket.locationSummary}}
Oplossing
{{ticket.resolution}}
Ticket Bekijken
Powered by Alga PSA • Teams op één lijn houden
`, text_content: ` Ticket Gesloten {{ticket.metaLine}} Gesloten door: {{ticket.closedBy}} Status: Gesloten Toegewezen aan: {{ticket.assignedDetails}} Aanvrager: {{ticket.requesterDetails}} Bord: {{ticket.board}} Categorie: {{ticket.categoryDetails}} Locatie: {{ticket.locationSummary}} Oplossing: {{ticket.resolution}} Ticket bekijken: {{ticket.url}} ` }, { name: 'ticket-comment-added', language_code: 'nl', subject: 'Nieuwe Opmerking • {{ticket.title}}', notification_subtype_id: getSubtypeId('Ticket Comment Added'), html_content: `
Nieuwe Opmerking Toegevoegd
{{ticket.title}}
{{ticket.metaLine}}

Een nieuwe opmerking is toegevoegd aan een ticket voor {{ticket.clientName}}.

Ticket #{{ticket.id}}
Prioriteit {{ticket.priority}}
Status {{ticket.status}}
Opmerking van {{comment.author}}
Toegewezen aan
{{ticket.assignedToName}}
{{ticket.assignedToEmail}}
Aanvrager
{{ticket.requesterName}}
{{ticket.requesterContact}}
Bord {{ticket.board}}
Categorie {{ticket.categoryDetails}}
Locatie {{ticket.locationSummary}}
💬 Opmerking
{{comment.content}}
Ticket Bekijken
Powered by Alga PSA • Teams op één lijn houden
`, text_content: ` Nieuwe Opmerking Toegevoegd {{ticket.metaLine}} Opmerking van: {{comment.author}} Prioriteit: {{ticket.priority}} Status: {{ticket.status}} Toegewezen aan: {{ticket.assignedDetails}} Aanvrager: {{ticket.requesterDetails}} Bord: {{ticket.board}} Categorie: {{ticket.categoryDetails}} Locatie: {{ticket.locationSummary}} Opmerking: {{comment.content}} Ticket bekijken: {{ticket.url}} ` }, // Billing templates { name: 'invoice-generated', language_code: 'nl', subject: 'Nieuwe factuur #{{invoice.number}}', notification_subtype_id: getSubtypeId('Invoice Generated'), html_content: `

Factuur {{invoice.number}}

Een nieuwe factuur is aangemaakt voor uw controle:

Factuurnummer: {{invoice.number}}

Bedrag: {{invoice.amount}}

Vervaldatum: {{invoice.dueDate}}

Klant: {{invoice.clientName}}

Factuur bekijken `, text_content: ` Factuur {{invoice.number}} Een nieuwe factuur is aangemaakt voor uw controle: Factuurnummer: {{invoice.number}} Bedrag: {{invoice.amount}} Vervaldatum: {{invoice.dueDate}} Klant: {{invoice.clientName}} Factuur bekijken: {{invoice.url}} ` }, { name: 'payment-received', language_code: 'nl', subject: 'Betaling ontvangen: Factuur #{{invoice.number}}', notification_subtype_id: getSubtypeId('Payment Received'), html_content: `

Betaling ontvangen

Betaling is ontvangen voor factuur #{{invoice.number}}:

Factuurnummer: {{invoice.number}}

Betaald bedrag: {{invoice.amountPaid}}

Betaaldatum: {{invoice.paymentDate}}

Betaalmethode: {{invoice.paymentMethod}}

Factuur bekijken `, text_content: ` Betaling ontvangen Betaling is ontvangen voor factuur #{{invoice.number}}: Factuurnummer: {{invoice.number}} Betaald bedrag: {{invoice.amountPaid}} Betaaldatum: {{invoice.paymentDate}} Betaalmethode: {{invoice.paymentMethod}} Factuur bekijken: {{invoice.url}} ` }, { name: 'payment-overdue', language_code: 'nl', subject: 'Betaling achterstallig: Factuur #{{invoice.number}}', notification_subtype_id: getSubtypeId('Payment Overdue'), html_content: `

Betaling achterstallig

De betaling voor factuur #{{invoice.number}} is achterstallig:

Factuurnummer: {{invoice.number}}

Verschuldigd bedrag: {{invoice.amountDue}}

Vervaldatum: {{invoice.dueDate}}

Dagen achterstallig: {{invoice.daysOverdue}}

Factuur bekijken `, text_content: ` Betaling achterstallig De betaling voor factuur #{{invoice.number}} is achterstallig: Factuurnummer: {{invoice.number}} Verschuldigd bedrag: {{invoice.amountDue}} Vervaldatum: {{invoice.dueDate}} Dagen achterstallig: {{invoice.daysOverdue}} Factuur bekijken: {{invoice.url}} ` } ]).onConflict(['name', 'language_code']).merge({ subject: knex.raw('excluded.subject'), html_content: knex.raw('excluded.html_content'), text_content: knex.raw('excluded.text_content'), notification_subtype_id: knex.raw('excluded.notification_subtype_id') }); console.log('✓ Dutch email templates added (auth + notifications)'); }; exports.down = async function(knex) { // Remove Dutch email templates // NOTE: email-verification and portal-invitation are NOT removed as they're managed by migration 20251029100000 await knex('system_email_templates') .where({ language_code: 'nl' }) .whereIn('name', [ 'password-reset', 'tenant-recovery', 'no-account-found', 'ticket-assigned', 'ticket-created', 'ticket-updated', 'ticket-closed', 'ticket-comment-added', 'invoice-generated', 'payment-received', 'payment-overdue' ]) .del(); console.log('Dutch email templates removed'); };