Base legale (ANALISI-REQUISITI-LEGALI.md §5): il considerando 37 della Dir. (UE)
2023/2673 dice che il professionista *can* offrire il recesso su parte del
contratto, non che *deve*. Un pulsante a livello di ordine e' conforme. Ma il form
non lo diceva, mentre le automazioni agivano in modo totale.
- statementTemplate: 'relativo all'INTERO ordine #X' (la dichiarazione ora
corrisponde a cio' che l'app fa davvero).
- SCOPE_HINT sotto la dichiarazione: il recesso riguarda l'intero ordine, per il
parziale contattare il negozio (canale modulo tipo/email, sempre valido).
- Admin: banner quando autoCancelUnfulfilled e' attivo -> annulla e rimborsa
l'INTERO ordine, irreversibile; con ordini multi-articolo meglio tenerlo spento.
- PLAN: A6-ter (recesso parziale) come attivita' OPZIONALE con toggle per-shop
partialWithdrawalEnabled, default OFF. Include la nota che l'idempotenza
(shop, orderId) di fa8ee9c andra' riportata a (shop, orderId, articoli).
- ANALISI-REQUISITI-LEGALI.md §5: punto chiarito + panorama concorrenti (Revize
fa il parziale, Rescindly no, Shopify non ha pulsante nativo, LegalBlink non e'
un concorrente ma un generatore di documenti).
150 lines
6.5 KiB
TypeScript
150 lines
6.5 KiB
TypeScript
/**
|
|
* Copy deck IT. Stringhe visibili del flusso di recesso + template email.
|
|
* Testi legali vincolanti (non modificare senza verifica). Placeholder {{...}}.
|
|
* i18n multi-lingua = fase A7.
|
|
*/
|
|
|
|
// Etichetta pulsante di avvio (Theme App Extension / A2). Dicitura di legge.
|
|
export const BUTTON_LABEL = "Recedere dal contratto qui";
|
|
|
|
// Etichetta funzione di conferma (step 3). Funzione dedicata, non checkbox.
|
|
export const CONFIRM_LABEL = "Conferma recesso";
|
|
|
|
// Titolo del flusso.
|
|
export const PAGE_TITLE = "Recesso dal contratto";
|
|
|
|
// Label dei campi + placeholder.
|
|
export const FIELD = {
|
|
name: { label: "Nome e cognome", placeholder: "Mario Rossi" },
|
|
orderName: { label: "Numero dell'ordine", placeholder: "es. 1234" },
|
|
email: { label: "Email", placeholder: "La tua email" },
|
|
statement: { label: "Dichiarazione di recesso" },
|
|
} as const;
|
|
|
|
// Dichiarazione precompilata (editabile), deriva dall'Allegato I-B.
|
|
export function statementTemplate(orderName: string): string {
|
|
return `Con la presente comunico il recesso dal contratto di vendita relativo all'intero ordine ${orderName}.`;
|
|
}
|
|
|
|
/**
|
|
* Ambito del recesso esercitato tramite questa funzione. La funzione dell'art.
|
|
* 54-bis puo' legittimamente operare a livello di CONTRATTO (ordine): offrire
|
|
* il recesso parziale e' una facolta' del professionista (considerando 37 Dir.
|
|
* UE 2023/2673, "the trader CAN provide..."), non un obbligo. Il diritto al
|
|
* recesso parziale resta comunque esercitabile dagli altri canali (modulo tipo,
|
|
* email), che non vanno mai disabilitati: per questo li indichiamo.
|
|
*/
|
|
export const SCOPE_HINT =
|
|
"Questo recesso riguarda l'intero ordine. Per restituire solo alcuni articoli, contatta il negozio.";
|
|
|
|
// Informazioni sul diritto di recesso (Art. 49) + alternative (coesistenza).
|
|
// Mostrate su richiesta dal pulsante info "i", per non appesantire il flusso.
|
|
export const INFO_TITLE = "Il tuo diritto di recesso";
|
|
export const INFO_BODY =
|
|
"Hai 14 giorni per recedere da questo contratto senza dover fornire una motivazione. Il termine decorre dalla consegna del bene (o dalla conclusione del contratto per i servizi).\n\n" +
|
|
"Confermando il modulo eserciti il recesso: riceverai via email una ricevuta con la data e l'ora di trasmissione.\n\n" +
|
|
"Questa funzione è aggiuntiva: puoi comunque usare il modulo tipo (Allegato I, parte B) o inviare una dichiarazione via email.";
|
|
|
|
// Messaggi di errore.
|
|
export const ERROR = {
|
|
// Anti-enumeration: ordine inesistente ed email non combaciante mostrano lo
|
|
// stesso messaggio, stesso testo e stesso status 200.
|
|
lookupNoMatch:
|
|
"Non abbiamo trovato un ordine con questi dati. Controlla il numero dell'ordine e l'email dell'acquisto.",
|
|
missingField: "Compila tutti i campi per continuare.",
|
|
invalidEmail: "Inserisci un indirizzo email valido.",
|
|
windowClosed:
|
|
"Il termine di 14 giorni per il recesso su questo ordine è terminato. Contattaci per altre richieste.",
|
|
generic: "Si è verificato un problema. Riprova tra poco.",
|
|
} as const;
|
|
|
|
// Avvisi informativi (non bloccanti).
|
|
export const NOTICE = {
|
|
orderClosed:
|
|
"Questo ordine risulta già annullato o rimborsato. Puoi comunque registrare il recesso; il negozio ti contatterà per eventuali dettagli.",
|
|
} as const;
|
|
|
|
// Schermata finale (dopo "Conferma recesso").
|
|
export function successMessage(
|
|
orderName: string,
|
|
transmittedAt: string,
|
|
email: string,
|
|
receiptSent = true,
|
|
): { line1: string; line2: string; line3: string } {
|
|
return {
|
|
line1: "Recesso trasmesso",
|
|
line2: `Registrato per l'ordine ${orderName} il ${transmittedAt}.`,
|
|
line3: receiptSent
|
|
? `Ti abbiamo inviato una ricevuta a ${email}.`
|
|
: `La ricevuta verrà inviata a ${email}. Se non la ricevi a breve, contattaci.`,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Schermata per un recesso GIA' esercitato su quest'ordine. Il diritto si
|
|
* esercita una volta sola: non registriamo un secondo atto, ma confermiamo il
|
|
* primo (con il suo timestamp legale) invece di far finta di nulla.
|
|
*/
|
|
export function duplicateMessage(
|
|
orderName: string,
|
|
transmittedAt: string,
|
|
email: string,
|
|
receiptResent: boolean,
|
|
): { line1: string; line2: string; line3: string } {
|
|
return {
|
|
line1: "Recesso già registrato",
|
|
line2: `Risulta trasmesso per l'ordine ${orderName} il ${transmittedAt}. Non serve inviarlo di nuovo.`,
|
|
line3: receiptResent
|
|
? `Ti abbiamo re-inviato la ricevuta a ${email}.`
|
|
: `La ricevuta è stata inviata a ${email}. Controlla anche la posta indesiderata.`,
|
|
};
|
|
}
|
|
|
|
// Template email ricevuta su supporto durevole (usato da A4).
|
|
export function receiptEmailSubject(orderName: string): string {
|
|
return `Ricevuta della tua richiesta di recesso - Ordine ${orderName}`;
|
|
}
|
|
|
|
export function receiptEmailBody(params: {
|
|
customerName: string;
|
|
orderName: string;
|
|
transmittedAt: string; // formato leggibile con fuso orario esplicito (Europe/Rome)
|
|
statementText: string;
|
|
shopName: string;
|
|
}): string {
|
|
const { customerName, orderName, transmittedAt, statementText, shopName } =
|
|
params;
|
|
return `Gentile ${customerName},
|
|
|
|
confermiamo di aver ricevuto la Sua dichiarazione di recesso relativa all'ordine ${orderName}, trasmessa tramite la funzione di recesso presente sul nostro sito.
|
|
|
|
Dettagli della richiesta:
|
|
- Data e ora di trasmissione: ${transmittedAt}
|
|
- Ordine: ${orderName}
|
|
- Nome del consumatore: ${customerName}
|
|
|
|
Testo integrale della dichiarazione di recesso trasmessa:
|
|
"${statementText}"
|
|
|
|
Questa comunicazione costituisce la ricevuta su supporto durevole della Sua dichiarazione di recesso, ai sensi dell'art. 54-bis del Codice del Consumo. La data e l'ora sopra indicate attestano il momento della trasmissione della dichiarazione.
|
|
|
|
Le invieremo separatamente le istruzioni per l'eventuale restituzione dei beni e i tempi di rimborso.
|
|
|
|
Restano validi anche gli altri mezzi per esercitare il recesso (modulo tipo di cui all'Allegato I, parte B, o qualsiasi altra dichiarazione esplicita, anche via email): questa funzione è aggiuntiva e non li sostituisce.
|
|
|
|
${shopName}`;
|
|
}
|
|
|
|
// Messaggio prodotto escluso (Art. 59). Copy pronto; la LOGICA è in A6.
|
|
export const EXCLUSION_REASON = {
|
|
CUSTOM: "prodotto realizzato su misura o personalizzato",
|
|
PERISHABLE: "prodotto deperibile o a rapida scadenza",
|
|
HYGIENE:
|
|
"prodotto sigillato, aperto dopo la consegna, non restituibile per motivi igienici o di salute",
|
|
OTHER: "prodotto escluso dal diritto di recesso",
|
|
} as const;
|
|
|
|
export function exclusionMessage(motivoEsclusione: string): string {
|
|
return `Per questo prodotto il diritto di recesso non è previsto (${motivoEsclusione}, ai sensi dell'art. 59 del Codice del Consumo). Per informazioni o altre richieste, contattaci.`;
|
|
}
|