diff --git a/server/mail-templates/K42 Webshop-Anfrage Abo.html b/server/mail-templates/K42 Webshop-Anfrage Abo.html
new file mode 100644
index 0000000..906f288
--- /dev/null
+++ b/server/mail-templates/K42 Webshop-Anfrage Abo.html
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+Deine Webshop-Anfrage für {{projekt}}
+
+
+
+
+Deine Webshop-Anfrage wurde bearbeitet. ͏ ͏ ͏
+
+
+
+
+ | WEBklar |
|
+Webshop |
+
|
+
+
+ |
+| Deine Webshop-Anfrage wurde angenommenZu Deiner Webshop-Anfrage |
+Hallo {{kunde_name}}, wir haben Deine Webshop-Anfrage für {{projekt}} angenommen. Du kannst den Webshop jetzt im Kundenportal einschalten; danach richten wir ihn ein.leider können wir Deine Webshop-Anfrage für {{projekt}} nicht annehmen. Den Grund findest Du unten. Wenn Du Fragen hast, antworte einfach auf diese E-Mail. |
+| Projekt | {{projekt}} | | Begründung | {{begruendung}} |
|
+ |
+Viele Grüße Dein WEBklar-Team |
+
+ |
+| Kundenportal |
+WEBklar GbR · Am Schwimmbad 10 · 67722 Winnweiler Telefon 0176 23726355 · support@webklar.com Vertreten durch die Gesellschafter Kenso Grimm und Justin Klein |
+
+ |
+
+
+
diff --git a/server/mail-templates/K43 Anfrage Buchungskalender Abo.html b/server/mail-templates/K43 Anfrage Buchungskalender Abo.html
new file mode 100644
index 0000000..2c799f5
--- /dev/null
+++ b/server/mail-templates/K43 Anfrage Buchungskalender Abo.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+Deine Anfrage zum Buchungskalender für {{projekt}}
+
+
+
+
+
+
+
+
+ | WEBklar |
|
+Buchungskalender |
+
|
+
+
+ |
+| Deine Anfrage wurde angenommenZu Deiner Anfrage |
+Hallo {{kunde_name}}, wir haben Deine Anfrage zum Buchungskalender für {{projekt}} angenommen. Du kannst ihn jetzt im Kundenportal einschalten; danach richten wir ihn ein.leider können wir Deine Anfrage zum Buchungskalender für {{projekt}} nicht annehmen. Den Grund findest Du unten. Wenn Du Fragen hast, antworte einfach auf diese E-Mail. |
+
+| Projekt | {{projekt}} |
+| Begründung | {{begruendung}} |
+ |
+ |
+Viele Grüße Dein WEBklar-Team |
+
+ |
+| Kundenportal |
+WEBklar GbR · Am Schwimmbad 10 · 67722 Winnweiler Telefon 0176 23726355 · support@webklar.com Vertreten durch die Gesellschafter Kenso Grimm und Justin Klein |
+
+ |
+
+
+
diff --git a/server/services/aboFunktionenMails.js b/server/services/aboFunktionenMails.js
index cd479e2..32bb542 100644
--- a/server/services/aboFunktionenMails.js
+++ b/server/services/aboFunktionenMails.js
@@ -9,7 +9,8 @@ import { datumKurz } from './termine/zeit.js'
* K38 Deine Funktion wird eingerichtet (Einschalten aus dem Abo oder durch das Team; nicht für Öffnungszeiten live, dort bleibt K27)
* K39 Deine Funktion wurde beendet (der Tagesabgleich beendet sie mit dem Abo)
* T24 Team-Hinweis: Funktion eingeschaltet (Einrichtung geht aufs Stundenkonto, Block vorschuss)
- * (K42 und K43, die Zusage-Mails der Webshop- und der Buchungskalender-Anfrage, folgen in Task 15.)
+ * K42, K43 Webshop- und Buchungskalender-Anfrage entschieden (Zusage oder Absage), Ersatz fuer K24 und K34 im Abo-Modell: ohne Preis und ohne
+ * das Wort "bestellen" (anfrageEntschiedenMail)
* Die Builder sind rein (kein Zugriff auf Appwrite, kein Versand) und liefern { template, values, blocks }, so wie
* zeiten/mails.js: die Werte decken genau die Platzhalter der Vorlage ab. Keine Preise, kein Wort „bestellen“.
*
@@ -110,6 +111,27 @@ export function t24Mail({ kunde, email, projekt, key, customerId, projectId, woi
}
}
+/**
+ * K42 (Webshop) oder K43 (Buchungskalender): die Anfrage wurde vom Team entschieden. Im Abo-Modell ohne Preiszeile und ohne "bestellen":
+ * bei Zusage kann der Kunde die Funktion im Kundenportal einschalten. Werte und Adresse wie die alten Mails K24 und K34 (sendeEntscheidung).
+ * @param {{ kunde: string | { name?: string }, projekt: string, key: 'shop' | 'unterkunft', projectId: string, angenommen: boolean, begruendung?: string }} p
+ * kunde_name ist der getrimmte Name, leer 'Kunde'; ein anderer key ist ein TypeError.
+ */
+export function anfrageEntschiedenMail({ kunde, projekt, key, projectId, angenommen, begruendung = '' }) {
+ if (key !== 'shop' && key !== 'unterkunft') throw new TypeError(`Keine Anfrage-Mail fuer die Funktion: ${String(key)}`)
+ const eintrag = funktion(key)
+ return {
+ template: key === 'shop' ? 'K42' : 'K43',
+ values: {
+ kunde_name: kundenName(kunde) || 'Kunde',
+ projekt,
+ begruendung,
+ portal_url: `${config.publicBaseUrl}/dashboard.html#${eintrag.returnHash}?projekt=${encodeURIComponent(projectId)}`,
+ },
+ blocks: { angenommen: Boolean(angenommen), abgelehnt: !angenommen },
+ }
+}
+
/** Tage zwischen dem Abschalten und der Löschung der Eingaben: news 30, termine 30, shop und unterkunft aus der Konfiguration; sonst TypeError. */
export function loeschFristTage(key) {
if (key === 'news') return 30
diff --git a/server/services/shop/anfrage.js b/server/services/shop/anfrage.js
index 788f406..73e7961 100644
--- a/server/services/shop/anfrage.js
+++ b/server/services/shop/anfrage.js
@@ -3,6 +3,8 @@ import { createDocument, getDocument, updateDocument } from '../appwriteAdmin.js
import { withLocks } from '../keyedLock.js'
import { sendAdminNotice, sendCustomerMail } from '../mailer.js'
import { assertOwnProject, customerOf, ensureFeatureDoc, getFeatureDoc } from '../siteFeatures.js'
+import { aboModellFuerKunde } from '../aboFunktionen.js'
+import { anfrageEntschiedenMail } from '../aboFunktionenMails.js'
import { shopFuerKunde } from './schalter.js'
import { NUR_BETRIEB_TEXT } from '../kundenart.js'
@@ -286,7 +288,11 @@ export async function entscheideAnfrage({ customerId, projectId, entscheidung, b
return { anfrage: anfrageAnsicht(gespeichert), mailFehler }
}
-/** K24 an den Kunden; true = gesendet. Jeder Fehler wird nur geloggt (die Entscheidung ist gespeichert). */
+/**
+ * K24 an den Kunden; true = gesendet. Jeder Fehler wird nur geloggt (die Entscheidung ist gespeichert). Fuer Kunden der neuen Ansicht
+ * (aboModellFuerKunde, Kundenansicht P6) geht stattdessen K42 ohne Preis und ohne "bestellen"; ist das nicht lesbar, geht keine Mail raus
+ * (lieber keine als eine mit Preis, die Antwort traegt mailFehler).
+ */
async function sendeEntscheidung({ customerId, projectId, project, angenommen, begruendung }) {
try {
const kunde = await customerOf(customerId)
@@ -294,6 +300,10 @@ async function sendeEntscheidung({ customerId, projectId, project, angenommen, b
console.warn(`[shop] K24 nicht gesendet: Kunde ${customerId} ohne E-Mail-Adresse`)
return false
}
+ if (await aboModellFuerKunde(customerId)) {
+ await sendCustomerMail(kunde.email, anfrageEntschiedenMail({ kunde, projekt: project?.projectName || projectId, key: 'shop', projectId, angenommen, begruendung }))
+ return true
+ }
await sendCustomerMail(kunde.email, {
template: 'K24',
values: {
diff --git a/server/services/unterkunft/anfrageFunktion.js b/server/services/unterkunft/anfrageFunktion.js
index 9561b7a..716864d 100644
--- a/server/services/unterkunft/anfrageFunktion.js
+++ b/server/services/unterkunft/anfrageFunktion.js
@@ -2,6 +2,8 @@ import { config } from '../../config.js'
import { withLocks } from '../keyedLock.js'
import { sendAdminNotice, sendCustomerMail } from '../mailer.js'
import { assertOwnProject, customerOf, ensureFeatureDoc, getFeatureDoc } from '../siteFeatures.js'
+import { aboModellFuerKunde } from '../aboFunktionen.js'
+import { anfrageEntschiedenMail } from '../aboFunktionenMails.js'
import { unterkunftFuerKunde } from './schalter.js'
import { ladeEinstellungen, speichereEinstellungen } from './speicher.js'
@@ -268,7 +270,11 @@ export async function entscheideAnfrage({ customerId, projectId, entscheidung, b
return { anfrage: anfrageAnsicht(gespeichert), mailFehler }
}
-/** K34 an den Kunden; true = gesendet. Jeder Fehler wird nur geloggt (die Entscheidung ist gespeichert). */
+/**
+ * K34 an den Kunden; true = gesendet. Jeder Fehler wird nur geloggt (die Entscheidung ist gespeichert). Fuer Kunden der neuen Ansicht
+ * (aboModellFuerKunde, Kundenansicht P6) geht stattdessen K43 ohne Preis und ohne "bestellen"; ist das nicht lesbar, geht keine Mail raus
+ * (lieber keine als eine mit Preis, die Antwort traegt mailFehler).
+ */
async function sendeEntscheidung({ customerId, projectId, project, angenommen, begruendung }) {
try {
const kunde = await customerOf(customerId)
@@ -276,6 +282,10 @@ async function sendeEntscheidung({ customerId, projectId, project, angenommen, b
console.warn(`[unterkunft] K34 nicht gesendet: Kunde ${customerId} ohne E-Mail-Adresse`)
return false
}
+ if (await aboModellFuerKunde(customerId)) {
+ await _versand.kunde(kunde.email, anfrageEntschiedenMail({ kunde, projekt: project?.projectName || projectId, key: 'unterkunft', projectId, angenommen, begruendung }))
+ return true
+ }
await _versand.kunde(kunde.email, {
template: 'K34',
values: {
diff --git a/test/aboFunktionenMails.test.js b/test/aboFunktionenMails.test.js
index d281e69..1675043 100644
--- a/test/aboFunktionenMails.test.js
+++ b/test/aboFunktionenMails.test.js
@@ -13,7 +13,7 @@ useTestEnv({ appwriteUrl: aw.url, stripeUrl: st.url })
const { config } = await import('../server/config.js')
const { renderMail } = await import('../server/services/mailTemplates.js')
const { anleitungsLink } = await import('../server/services/featureRegistry.js')
-const { k38Mail, k39Mail, t24Mail, loeschFristTage, kontostandText } = await import('../server/services/aboFunktionenMails.js')
+const { anfrageEntschiedenMail, k38Mail, k39Mail, t24Mail, loeschFristTage, kontostandText } = await import('../server/services/aboFunktionenMails.js')
const { k29Mail, k30Mail } = await import('../server/services/zeiten/mails.js')
test('k38Mail: Werte und Blöcke je Abrechnung', () => {
@@ -44,3 +44,12 @@ test('alle Builder-Ergebnisse rendern ohne Probleme und ohne €; Zeiten-Variant
const k41 = k30Mail({ kunde: 'K', projekt: 'P', loeschdatum: frist, preis: '30 €', modell: true }); assert.equal(k41.template, 'K41'); assert.equal(renderMail('K41', k41.values, k41.blocks).problems.length, 0)
assert.equal(k29Mail({ kunde: 'K', projekt: 'P', art: 'beendet', frist, preis: '30 €' }).template, 'K29') // Standard unverändert
})
+test('anfrageEntschiedenMail: K42 und K43, Werte, Blöcke, Adresse; ohne Preis', () => {
+ const m = anfrageEntschiedenMail({ kunde: { name: 'Erika' }, projekt: 'Töpferei', key: 'shop', projectId: 'pt1', angenommen: true })
+ assert.equal(m.template, 'K42'); assert.deepEqual(m.blocks, { angenommen: true, abgelehnt: false })
+ assert.deepEqual(m.values, { kunde_name: 'Erika', projekt: 'Töpferei', begruendung: '', portal_url: `${config.publicBaseUrl}/dashboard.html#webshop?projekt=pt1` })
+ const u = anfrageEntschiedenMail({ kunde: { name: ' ' }, projekt: 'Donau', key: 'unterkunft', projectId: 'a b', angenommen: false, begruendung: 'Passt nicht.' })
+ assert.deepEqual([u.template, u.blocks, u.values.kunde_name, u.values.begruendung, u.values.portal_url], ['K43', { angenommen: false, abgelehnt: true }, 'Kunde', 'Passt nicht.', `${config.publicBaseUrl}/dashboard.html#buchungen?projekt=a%20b`])
+ assert.throws(() => anfrageEntschiedenMail({ kunde: 'K', projekt: 'P', key: 'termine', projectId: 'p', angenommen: true }), TypeError)
+ for (const x of [m, u]) assert.deepEqual(renderMail(x.template, x.values, x.blocks).problems, [])
+})
diff --git a/test/aboFunktionenVorlagen.test.js b/test/aboFunktionenVorlagen.test.js
index decf2fe..e837897 100644
--- a/test/aboFunktionenVorlagen.test.js
+++ b/test/aboFunktionenVorlagen.test.js
@@ -8,6 +8,8 @@ const SOLL = { // [Datei, Betreff, Platzhalter, Blöcke]
K39: ['K39 Funktion beendet.html', 'Deine Funktion wurde beendet: {{funktion}}', ['kunde_name', 'projekt', 'funktion', 'loeschtag', 'portal_url'], ['abo_ende', 'hosting', 'termine', 'offene']],
K40: ['K40 Zeiten Abo-Ende.html', 'Dein Abo ist beendet – Öffnungszeiten live läuft noch bis {{frist}}', ['kunde_name', 'projekt', 'frist', 'portal_url'], ['abo_ende', 'hosting', 'wechsel_widerrufen']],
K41: ['K41 Zeiten abgeschaltet Abo.html', 'Öffnungszeiten live ist abgeschaltet', ['kunde_name', 'projekt', 'loeschdatum', 'portal_url'], []],
+ K42: ['K42 Webshop-Anfrage Abo.html', 'Deine Webshop-Anfrage für {{projekt}}', ['kunde_name', 'projekt', 'begruendung', 'portal_url'], ['angenommen', 'abgelehnt']],
+ K43: ['K43 Anfrage Buchungskalender Abo.html', 'Deine Anfrage zum Buchungskalender für {{projekt}}', ['kunde_name', 'projekt', 'begruendung', 'portal_url'], ['angenommen', 'abgelehnt']],
T24: ['T24 Funktion eingeschaltet.html', '[Abo] Funktion eingeschaltet: {{funktion}} – {{kunde_name}}', ['kunde_name', 'email', 'projekt', 'funktion', 'woid', 'kontostand', 'woms_url'], ['vorschuss', 'anhang_fehlt']],
}
const mail = (id, on) => { const t = loadTemplate(id); return renderMail(id, Object.fromEntries(t.placeholders.map((p) => [p, `W-${p}`])), Object.fromEntries(t.blocks.map((b) => [b, on]))) }
@@ -23,4 +25,13 @@ test('Festtexte', () => {
assert.match(mail('K39', true).text, /Bitte informiere deine Gäste selbst\./); assert.doesNotMatch(mail('K39', false).text, /CSV|Offene Bestellungen/)
assert.match(mail('T24', true).text, /Das Guthaben reicht voraussichtlich nicht \(W-kontostand\)\./); assert.doesNotMatch(mail('T24', false).text, /Vorschuss/)
})
-test('templateIds enthält K38 bis K41 und T24', () => { for (const id of Object.keys(SOLL)) assert.ok(templateIds().includes(id)) })
+test('K42, K43: Zusage ohne Preis und ohne „bestellen“, Absage mit Begründung wie K24 und K34', () => {
+ const werte = { kunde_name: 'Erika', projekt: 'Töpferei', begruendung: 'Wir verkaufen keine .', portal_url: 'https://portal.example/dashboard.html#x?projekt=p1' }
+ for (const [id, satz, knopf] of [['K42', 'Du kannst den Webshop jetzt im Kundenportal einschalten; danach richten wir ihn ein.', 'Webshop einschalten'], ['K43', 'Du kannst ihn jetzt im Kundenportal einschalten; danach richten wir ihn ein.', 'Zum Kundenportal']]) {
+ const zu = renderMail(id, werte, { angenommen: true, abgelehnt: false }); assert.deepEqual(zu.problems, [])
+ assert.doesNotMatch(zu.html + zu.text, /€|UStG|bestell|Preis|Waffen/i); assert.ok(zu.text.includes(satz), id); assert.ok(zu.text.includes(knopf), id)
+ const ab = renderMail(id, werte, { angenommen: false, abgelehnt: true }); assert.deepEqual(ab.problems, [])
+ assert.match(ab.text, /leider/); assert.match(ab.text, /Wir verkaufen keine \./); assert.doesNotMatch(ab.text + ab.html, /€|UStG|bestell/i)
+ }
+})
+test('templateIds enthält K38 bis K43 und T24', () => { for (const id of Object.keys(SOLL)) assert.ok(templateIds().includes(id)) })
diff --git a/test/mailTemplates.test.js b/test/mailTemplates.test.js
index f96f35e..2948f56 100644
--- a/test/mailTemplates.test.js
+++ b/test/mailTemplates.test.js
@@ -6,9 +6,9 @@ import { contractAttachmentFor, termsDocFor } from '../server/services/products.
const DIR = new URL('../server/mail-templates/', import.meta.url)
// G01–G08 Gästemails des Terminplaners (Task 9, neutrales Layout im Auftrag eines Betriebs), K20 und K21 Hinweise an den Betrieb;
-// K12, K14 und T12 (Wechsel ins Wartungs-Abo) aus Task 9, K13 und T13 (Zusatzspeicher) aus Task 8 (Fix 1); Endfassung der Texte in Task 12; T14 „Löschfristen“ aus Task 21 (F39); T15 Push-Zeitmail; K15, K16, T16 Funktionen (News-Pinnwand, Terminplaner; K15, K16 und T16 gelten je Funktion, Terminplaner TP2 B9a und B9b); T17 Repo zuordnen; K17 Chat-Hinweis an Kunden; K18, K19 Website-Analyse; K22, K23 Terminplaner beendet/läuft wieder (Terminplaner TP2 E3); T18 Bankzugang erneuern (Finanzen); T19 Erstattung fällig und T20 Terminplaner Betriebsmeldung (Terminplaner TP2, Team-Hinweise; T16 gilt je Funktion, T19 aus B9b); T21 Neue Webshop-Anfrage (Webshop B1, Team-Hinweis); K24 Webshop-Anfrage entschieden (Webshop B2, Kunde); G09–G14 Käufermails des Webshops (Bestellbestätigung, versendet, abholbereit, Eingang Widerruf, Erstattung, Zahlung fehlgeschlagen; Webshop E4, eigener Fuß statt Terminplaner-Fuß, Sie-Form) und K25, K26 an den Händler (neue Bestellung, Widerruf; Webshop E4); K27–K30 Öffnungszeiten live (eingeschaltet, Feiertage prüfen, Abo beendet, abgeschaltet; Öffnungszeiten live Task 13); K04 und T09 gelten beim Widerruf einer Funktion je Funktion (produkt, T09 zusätzlich preis; Terminplaner TP2 F9); K33–K37 und T23 Buchungskalender (K36 und K37 Neue Anfrage und Neue Buchung an den Vermieter, T23 Team-Hinweis; zuvor K31, K32, T22, die den Aufträgen gehören); K31, K32 und T22 Auftragsbestätigung (Aufträge und Rechnungen, Strang L5; K31 und K32 in Sie-Form, T22 mit [Aufträge]); K38–K41 und T24 Funktionen im Abo-Modell (Kundenansicht P6: K38 wird eingerichtet, K39 beendet, K40 und K41 Öffnungszeiten live Abo-Ende und abgeschaltet ohne Preis, T24 Team-Hinweis; Du-Form, Test in aboFunktionenVorlagen.test.js)
+// K12, K14 und T12 (Wechsel ins Wartungs-Abo) aus Task 9, K13 und T13 (Zusatzspeicher) aus Task 8 (Fix 1); Endfassung der Texte in Task 12; T14 „Löschfristen“ aus Task 21 (F39); T15 Push-Zeitmail; K15, K16, T16 Funktionen (News-Pinnwand, Terminplaner; K15, K16 und T16 gelten je Funktion, Terminplaner TP2 B9a und B9b); T17 Repo zuordnen; K17 Chat-Hinweis an Kunden; K18, K19 Website-Analyse; K22, K23 Terminplaner beendet/läuft wieder (Terminplaner TP2 E3); T18 Bankzugang erneuern (Finanzen); T19 Erstattung fällig und T20 Terminplaner Betriebsmeldung (Terminplaner TP2, Team-Hinweise; T16 gilt je Funktion, T19 aus B9b); T21 Neue Webshop-Anfrage (Webshop B1, Team-Hinweis); K24 Webshop-Anfrage entschieden (Webshop B2, Kunde); G09–G14 Käufermails des Webshops (Bestellbestätigung, versendet, abholbereit, Eingang Widerruf, Erstattung, Zahlung fehlgeschlagen; Webshop E4, eigener Fuß statt Terminplaner-Fuß, Sie-Form) und K25, K26 an den Händler (neue Bestellung, Widerruf; Webshop E4); K27–K30 Öffnungszeiten live (eingeschaltet, Feiertage prüfen, Abo beendet, abgeschaltet; Öffnungszeiten live Task 13); K04 und T09 gelten beim Widerruf einer Funktion je Funktion (produkt, T09 zusätzlich preis; Terminplaner TP2 F9); K33–K37 und T23 Buchungskalender (K36 und K37 Neue Anfrage und Neue Buchung an den Vermieter, T23 Team-Hinweis; zuvor K31, K32, T22, die den Aufträgen gehören); K31, K32 und T22 Auftragsbestätigung (Aufträge und Rechnungen, Strang L5; K31 und K32 in Sie-Form, T22 mit [Aufträge]); K42, K43 Zusage-Mails ohne Preis (Kundenansicht P6: Webshop- und Buchungskalender-Anfrage, Ersatz für K24 und K34 im Abo-Modell); K38–K41 und T24 Funktionen im Abo-Modell (Kundenansicht P6: K38 wird eingerichtet, K39 beendet, K40 und K41 Öffnungszeiten live Abo-Ende und abgeschaltet ohne Preis, T24 Team-Hinweis; Du-Form, Test in aboFunktionenVorlagen.test.js)
const ids = (prefix, count) => Array.from({ length: count }, (_, i) => `${prefix}${String(i + 1).padStart(2, '0')}`)
-const EXPECTED = [...ids('G', 22), ...ids('K', 41), ...ids('T', 24)]
+const EXPECTED = [...ids('G', 22), ...ids('K', 43), ...ids('T', 24)]
// GUEST = Gästemails des Terminplaners (gemeinsamer Fuß, Anrede-Blöcke); SHOP_GUEST = Käufermails des Webshops (G09–G14, siehe unten)
const GUEST = ids('G', 8)
const SHOP_GUEST = ['G09', 'G10', 'G11', 'G12', 'G13', 'G14', 'G15']
diff --git a/test/shopTeam.test.js b/test/shopTeam.test.js
index d36a76e..db3ac85 100644
--- a/test/shopTeam.test.js
+++ b/test/shopTeam.test.js
@@ -252,3 +252,17 @@ test('nach Ablehnung kann der Kunde neu anfragen, die alte Entscheidung ist gel
assert.equal(doc.anfrageBegruendung, '')
assert.equal((await entscheide({ entscheidung: 'annehmen' })).status, 200)
})
+
+const ansichtAlt = { ...config.kundenansichtNeu }; after(() => Object.assign(config.kundenansichtNeu, ansichtAlt))
+const neueAnsicht = (an) => { config.kundenansichtNeu.mode = an ? 'pilot' : 'off'; config.kundenansichtNeu.pilotEmails = [customers.c1.email] }
+test('Abo-Modell: Zusage als K42 ohne Preis und ohne „bestellen“, Absage mit Begründung; alte Ansicht bekommt weiter K24 mit 299 €', async () => {
+ for (const an of [true, false]) {
+ neueAnsicht(an); await leereAlles(); await stelle(); mails.sent.length = 0
+ assert.equal((await entscheide({ entscheidung: 'annehmen' })).status, 200)
+ const m = k24()[0]; assert.equal(m.subject, 'Deine Webshop-Anfrage für Töpferei'); assert.match(m.html, /dashboard\.html#webshop\?projekt=pt1"/)
+ if (an) { assert.doesNotMatch(m.text + m.html, /€|UStG|bestell/i); assert.match(m.text, /jetzt im Kundenportal einschalten/) } else { assert.match(m.text, /299 €/); assert.match(m.text, /bestellen/) }
+ }
+ neueAnsicht(true); await leereAlles(); await stelle(); mails.sent.length = 0
+ assert.equal((await entscheide({ entscheidung: 'ablehnen', begruendung: 'Passt nicht.' })).status, 200)
+ assert.match(k24()[0].text, /leider[\s\S]*Passt nicht\./); assert.doesNotMatch(k24()[0].text, /299 €/)
+})
diff --git a/test/unterkunftAnfrageFunktion.test.js b/test/unterkunftAnfrageFunktion.test.js
index 5ff0c19..7e54fe8 100644
--- a/test/unterkunftAnfrageFunktion.test.js
+++ b/test/unterkunftAnfrageFunktion.test.js
@@ -326,3 +326,17 @@ test('T23 und K34 (angenommen und abgelehnt) passen zu den Vorlagen: keine Platz
const k34 = renderMail('K34', aufrufe.kunde[1].values, aufrufe.kunde[1].blocks)
assert.match(k34.text, /199 €/)
})
+
+const ansichtAlt = { ...config.kundenansichtNeu }; after(() => Object.assign(config.kundenansichtNeu, ansichtAlt))
+const neueAnsicht = (an) => { config.kundenansichtNeu.mode = an ? 'pilot' : 'off'; config.kundenansichtNeu.pilotEmails = [customers.c1.email] }
+test('Abo-Modell: Zusage als K43 ohne Preis und ohne „bestellen“, Absage unverändert; alte Ansicht bekommt weiter K34 mit 199 €', async () => {
+ for (const an of [true, false]) {
+ neueAnsicht(an); aufrufe.kunde.length = 0; await deleteDocument(config.collections.ukEinstellungen, FEATURE).catch(() => {}); assert.equal((await stelle()).status, 200); assert.equal((await entscheide({ entscheidung: 'annehmen' })).status, 200)
+ const m = aufrufe.kunde[0]; const r = renderMail(m.template, m.values, m.blocks); assert.deepEqual(r.problems, [])
+ assert.deepEqual([m.template, 'preis' in m.values, 'ust_hinweis' in m.values], an ? ['K43', false, false] : ['K34', true, true])
+ assert.equal(m.values.portal_url, `${config.publicBaseUrl}/dashboard.html#buchungen?projekt=${P}`)
+ if (an) assert.doesNotMatch(r.text + r.html, /€|UStG|bestell/i); else { assert.match(r.text, /199 €/); assert.match(r.text, /bestellen/) }
+ }
+ neueAnsicht(true); aufrufe.kunde.length = 0; await deleteDocument(config.collections.ukEinstellungen, FEATURE).catch(() => {}); await stelle(); assert.equal((await entscheide({ entscheidung: 'ablehnen', begruendung: 'Passt nicht.' })).status, 200)
+ assert.deepEqual([aufrufe.kunde[0].template, aufrufe.kunde[0].values.begruendung, aufrufe.kunde[0].blocks], ['K43', 'Passt nicht.', { angenommen: false, abgelehnt: true }])
+})