Abo-Angebote: Gültigkeit überall sichtbar

Das "Angebot gültig bis" stand bisher nur in der Angebotsliste, auf der
Bestellseite und in der Mail. Jetzt auch:
- Admin, Formular "Neues Angebot": eigene Zeile "Angebot gültig bis
  TT.MM.JJJJ" in der Vorschau, in der Bestätigungsabfrage und in der
  Erfolgsmeldung (bei laufendem Abo nicht, dort gilt das Angebot sofort)
- Kundenbereich, Abo-Karte (Seitenleiste bzw. Tab "Wartung"): Zeile
  "Angebot gültig bis TT.MM.JJJJ" unter dem Preis

Das Datum aus dem Datumsfeld wird ohne Date-Umweg formatiert, im Portal
nach Berliner Kalender (wie bisher). Nebenbei: "danach 50 €" mit
geschütztem Leerzeichen, damit das € auf dem Handy nicht allein umbricht.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-09-26 22:42:37 +00:00
1 parent d5eb908cb6
commit c600118374
3 files changed
+13 -5

No files matched your search

+8 -3
View File
@@ -802,6 +802,9 @@ function offerPreviewText(price, months, regular, running) {
return `${lead} ${amount}, danach ${eur(regular)} pro Monat`
}
// Datumsfeld "2026-10-27" -> "27.10.2026", ohne Umweg über Date (keine Zeitzonen-Verschiebung)
const fmtYmd = (ymd) => String(ymd || '').split('-').reverse().join('.')
function showOfferMessage(text) {
const el = document.getElementById('offer-message')
el.textContent = text
@@ -899,6 +902,7 @@ function renderOfferPreview(form) {
}
if (ok) {
lines.push(`${offerPreviewText(v.monthlyPriceCents, v.months, regular, running)} · Ersparnis ${euroFromCents((regular - v.monthlyPriceCents) * v.months)}`)
if (!running) lines.push(`Angebot gültig bis ${fmtYmd(v.validUntil)}`)
}
lines.push(running
? `Laufendes Abo: gilt ab der nächsten Abbuchung${ctx.subscription.currentPeriodEnd ? ` (${fmtDate(ctx.subscription.currentPeriodEnd)})` : ''} und wird sofort in Stripe angewendet.`
@@ -930,8 +934,9 @@ async function saveOffer(form) {
errEl.classList.add('hidden')
const v = offerFormValues(form)
const ctx = offerState.context
const text = offerPreviewText(v.monthlyPriceCents, v.months, ctx.regularPriceCents, Boolean(ctx.subscription?.active))
if (!window.confirm(`Angebot für ${ctx.customer.name || 'den Kunden'} anlegen?\n\n${text}\n\nDer Coupon wird sofort in Stripe angelegt${ctx.subscription?.active ? ' und auf das laufende Abo angewendet' : ''}.`)) return
const running = Boolean(ctx.subscription?.active)
const text = offerPreviewText(v.monthlyPriceCents, v.months, ctx.regularPriceCents, running)
if (!window.confirm(`Angebot für ${ctx.customer.name || 'den Kunden'} anlegen?\n\n${text}${running ? '' : `\nGültig bis ${fmtYmd(v.validUntil)}`}\n\nDer Coupon wird sofort in Stripe angelegt${running ? ' und auf das laufende Abo angewendet' : ''}.`)) return
const save = form.querySelector('#offer-save')
save.disabled = true
try {
@@ -939,7 +944,7 @@ async function saveOffer(form) {
const o = result.offer
form.classList.add('hidden')
showOfferMessage([
`Angebot ${o.ref} für ${o.customerName} angelegt: ${o.text}.`,
`Angebot ${o.ref} für ${o.customerName} angelegt: ${o.text}${o.scope === 'laufend' ? '' : `, gültig bis ${fmtDate(o.validUntil)}`}.`,
`Stripe-Coupon ${o.stripeCouponId} ist eingerichtet${o.status === 'aktiv' ? ' und am laufenden Abo aktiv' : ''}.`,
v.notifyCustomer ? (result.mailSent ? 'Die E-Mail an den Kunden ist raus.' : `E-Mail an den Kunden fehlgeschlagen (${result.mailError}).`) : '',
].filter(Boolean).join(' '))