/**
* 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
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:
Of kopieer deze link naar uw browser:
{{resetLink}}
⚠️ Belangrijke Beveiligingsinformatie
- Deze wachtwoordherstellink verloopt over {{expirationTime}}
- Om beveiligingsredenen kan deze link slechts één keer worden gebruikt
- Als u dit herstel niet heeft aangevraagd, kunt u deze e-mail negeren
- Uw wachtwoord verandert pas als u een nieuw wachtwoord aanmaakt
Wat Nu?
- Klik op de herstelknop hierboven of gebruik de verstrekte link
- Maak een sterk, uniek wachtwoord voor uw account
- U wordt automatisch ingelogd na het opnieuw instellen
- Alle bestaande sessies worden beëindigd voor de beveiliging
- 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}}
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:
- 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.
`,
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.
| 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.
| 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.
| 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.
| 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}}.
| 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');
};