Shop Review B I-5: Bestaetigen nur ohne Platzhalter, Musterkopf und mit Adresse der Widerrufsfunktion
pruefeBestaetigbar listet die Probleme in Du-Form; POST /api/shop/rechtstexte/bestaetigen antwortet 400 nicht_bestaetigbar mit der Liste, GET und PUT liefern sie als probleme mit. Der Reiter Rechtliches zeigt die Punkte im Bestaetigungsblock und sperrt den Knopf. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1f56b86791
commit
2f4f360a21
6 files changed
+169
-15
No files matched your search
@@ -19,7 +19,7 @@ import {
|
||||
} from '../services/shop/produkte.js'
|
||||
import {
|
||||
BESTAETIGUNG_TEXT, GEWAEHRLEISTUNG_BILD, gewaehrleistungsHinweis, musterAgb, musterWiderrufsbelehrung, musterWiderrufsformular,
|
||||
normalisiereRechtstexte, rechtstexteHash, versandUndZahlung, vollstaendig,
|
||||
normalisiereRechtstexte, pruefeBestaetigbar, rechtstexteHash, versandUndZahlung, vollstaendig,
|
||||
} from '../services/shop/rechtstexte.js'
|
||||
import {
|
||||
BILD_MAX_BYTES, beanspruche, bildLimitErreicht, bildMeta, bildPfad, loescheBild, setzeBildLimitZurueck, speichereBild,
|
||||
@@ -386,6 +386,8 @@ function rechtstexteAntwort(shop) {
|
||||
hash,
|
||||
bestaetigungText: BESTAETIGUNG_TEXT,
|
||||
vollstaendig: vollstaendig(entwurf),
|
||||
// Was das Bestaetigen des gespeicherten Entwurfs derzeit verhindert (Platzhalter, Musterkopf, fehlende Adresse der Widerrufsfunktion)
|
||||
probleme: pruefeBestaetigbar(entwurf, { widerrufUrl: widerrufUrl(shop.siteKey) }),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,6 +428,10 @@ router.post('/rechtstexte/bestaetigen', requireSession, nurKunde, limitWrites, r
|
||||
throw stop(409, 'Die Texte wurden inzwischen geändert. Bitte lies sie noch einmal durch und bestätige dann erneut.', 'texte_geaendert')
|
||||
}
|
||||
if (!vollstaendig(entwurf)) throw stop(400, 'Bitte fülle AGB, Widerrufsbelehrung, Widerrufsformular, Impressum und Datenschutz aus, bevor du bestätigst.')
|
||||
const probleme = pruefeBestaetigbar(entwurf, { widerrufUrl: widerrufUrl(aktuell.siteKey) })
|
||||
if (probleme.length) {
|
||||
throw Object.assign(stop(400, 'Die Texte können noch nicht bestätigt werden. Bitte behebe zuerst die genannten Punkte.', 'nicht_bestaetigbar'), { body: { code: 'nicht_bestaetigbar', probleme } })
|
||||
}
|
||||
const at = new Date().toISOString()
|
||||
const bestaetigt = { texte: { ...entwurf }, hash, at, von }
|
||||
const json = JSON.stringify({ entwurf, bestaetigt })
|
||||
|
||||
@@ -18,6 +18,8 @@ export const MAX_AGB = 30000
|
||||
export const MAX_WIDERRUFSBELEHRUNG = 20000
|
||||
export const MAX_WIDERRUFSFORMULAR = 5000
|
||||
const MAX_URL = 500
|
||||
/** Erste Zeile des vorbefuellten Muster-AGB: der Haendler muss sie nach der Pruefung loeschen. */
|
||||
export const MUSTER_KOPFZEILE = 'Muster – bitte prüfen und anpassen'
|
||||
|
||||
const LANDNAMEN = { DE: 'Deutschland', AT: 'Österreich' }
|
||||
const ZAHLUNGSARTEN_REIHENFOLGE = ['card', 'klarna', 'sepa_debit']
|
||||
@@ -133,7 +135,7 @@ export function musterAgb(e) {
|
||||
const arten = Array.isArray(e.zahlungsarten) ? e.zahlungsarten : []
|
||||
const zahlung = zahlungsartenText(e)
|
||||
const abs = []
|
||||
abs.push('Muster – bitte prüfen und anpassen')
|
||||
abs.push(MUSTER_KOPFZEILE)
|
||||
abs.push('Allgemeine Geschäftsbedingungen')
|
||||
abs.push(
|
||||
`§ 1 Geltung und Anbieter\n\nDiese Allgemeinen Geschäftsbedingungen gelten für alle Bestellungen von Verbrauchern in unserem Online-Shop. Anbieter und Vertragspartner ist ${anbieterZeile(a)}${text(a.ustId) ? `, USt-IdNr.: ${text(a.ustId)}` : ''}.`
|
||||
@@ -316,6 +318,40 @@ export function vollstaendig(rechtstexte) {
|
||||
return ['agb', 'widerrufsbelehrung', 'widerrufsformular', 'impressumUrl', 'datenschutzUrl'].every((k) => typeof r[k] === 'string' && r[k].trim() !== '')
|
||||
}
|
||||
|
||||
const PLATZHALTER_RE = /\[[^\]\n]{2,}\]/g
|
||||
const TEXT_IN = { agb: 'den AGB', widerrufsbelehrung: 'der Widerrufsbelehrung', widerrufsformular: 'dem Muster-Widerrufsformular' }
|
||||
|
||||
/**
|
||||
* Kann der Haendler diese Texte bestaetigen? Liefert die Probleme in Du-Form (leere Liste = ja): Platzhalter aus dem Muster
|
||||
* (`[Name]`, `[Anschrift]`, `[E-Mail-Adresse]`, `[Internetadresse der Widerrufsfunktion]` oder jede andere Angabe in eckigen Klammern),
|
||||
* die Kopfzeile "Muster – bitte prüfen und anpassen" und eine Widerrufsbelehrung ohne die Adresse der Widerrufsfunktion des Shops
|
||||
* (Art. 246a § 1 Abs. 2 S. 1 Nr. 1 EGBGB: ohne ordnungsgemaesse Belehrung beginnt die Widerrufsfrist nicht).
|
||||
* @param {object} rechtstexte Entwurf { agb, widerrufsbelehrung, widerrufsformular, ... }
|
||||
* @param {{ widerrufUrl?: string }} [opts] Adresse der Widerrufsfunktion des Shops
|
||||
* @returns {string[]}
|
||||
*/
|
||||
export function pruefeBestaetigbar(rechtstexte, { widerrufUrl = '' } = {}) {
|
||||
const r = rechtstexte && typeof rechtstexte === 'object' ? rechtstexte : {}
|
||||
const probleme = []
|
||||
for (const [key, wo] of Object.entries(TEXT_IN)) {
|
||||
const t = typeof r[key] === 'string' ? r[key] : ''
|
||||
const marken = [...new Set(t.match(PLATZHALTER_RE) ?? [])]
|
||||
if (marken.length) {
|
||||
const zeigen = marken.slice(0, 5).map((m) => `„${m}“`).join(', ')
|
||||
probleme.push(`In ${wo} stehen noch Platzhalter in eckigen Klammern: ${zeigen}${marken.length > 5 ? ' und weitere' : ''}. Ersetze sie durch deine Angaben. Fehlende Angaben ergänzt du in den Einstellungen, danach setzt du das Muster neu ein.`)
|
||||
}
|
||||
if (t.includes(MUSTER_KOPFZEILE)) {
|
||||
probleme.push(`In ${wo} steht noch die Zeile „${MUSTER_KOPFZEILE}“. Prüfe den Text, passe ihn an und lösche die Zeile.`)
|
||||
}
|
||||
}
|
||||
const url = text(widerrufUrl)
|
||||
// Eine leere Belehrung meldet vollstaendig(); hier nur eine vorhandene ohne die Adresse
|
||||
if (url && text(r.widerrufsbelehrung) !== '' && !r.widerrufsbelehrung.includes(url)) {
|
||||
probleme.push(`Die Widerrufsbelehrung muss die Adresse deiner Widerrufsfunktion enthalten: ${url}. Setze das Muster neu ein oder ergänze den Satz „Sie können Ihr Widerrufsrecht auch online unter ${url} ausüben.“`)
|
||||
}
|
||||
return probleme
|
||||
}
|
||||
|
||||
/** sha256 (hex) ueber kanonisches JSON der fuenf Felder plus erzeugtem Versand-/Zahlungstext und Gewaehrleistungshinweis. */
|
||||
export function rechtstexteHash(rechtstexte, einstellungen) {
|
||||
const r = rechtstexte && typeof rechtstexte === 'object' ? rechtstexte : {}
|
||||
|
||||
Reference in new issue
Block a user