# Smart Offers — Documentazione completa

> Guida completa al modulo Smart Offers per PrestaShop 8 e 9: i quattro tipi di offerte raggruppate, creazione passo passo, prodotti con varianti, aggiunta automatica al carrello, migrazione da PS8 a PS9, lingue e architettura tecnica.

- Pagina: <https://www.datafirefly.com/it/documentation/dfoffers/>
- Lingua: it
- Aggiornato il: 2026-09-10
- Altre lingue: [fr](https://www.datafirefly.com/documentation/dfoffers/index.md), [en](https://www.datafirefly.com/en/documentation/dfoffers/index.md), [es](https://www.datafirefly.com/es/documentation/dfoffers/index.md), [de](https://www.datafirefly.com/de/documentation/dfoffers/index.md), [pl](https://www.datafirefly.com/pl/documentation/dfoffers/index.md), [pt](https://www.datafirefly.com/pt/documentation/dfoffers/index.md), [nl](https://www.datafirefly.com/nl/documentation/dfoffers/index.md)
- Indice: <https://www.datafirefly.com/it/documentation/llms.txt>

Smart Offers è un modulo compatibile con PrestaShop 8 e 9 che permette di creare offerte 1+1, pacchi all'ingrosso, pacchetti multi-prodotto e offerte a scelta, con aggiunta automatica dei prodotti regalo al carrello e presentazione curata sulla scheda prodotto.

## Panoramica

Smart Offers copre i quattro formati di offerte raggruppate più utilizzati nell'e-commerce in un solo modulo, senza configurazione complessa. Il motore valuta il carrello ad ogni modifica, aggiunge automaticamente i prodotti regalo non appena le condizioni sono soddisfatte e crea una regola del carrello che rende quelle unità gratuite. L'esperienza del cliente è immediata e leggibile.

**In sintesi:** Il commerciante crea un'offerta in meno di un minuto tramite un'interfaccia visiva, il cliente vede apparire il regalo automaticamente nel suo carrello con un indicatore chiaro, e il tracking interno consente una revoca pulita se il cliente rimuove un trigger durante la sessione.

## Compatibilità con PrestaShop 8 e 9

Dalla versione 2.0.0, un solo file ZIP copre PrestaShop da 8.0 a 9.x. Non serve scegliere un ramo specifico al download: il modulo rileva la versione del negozio a runtime e adatta le sue chiamate alle API che sono cambiate tra le due generazioni.

| Elemento | PrestaShop 8 | PrestaShop 9 |
| --- | --- | --- |
| Versione PHP richiesta | da 7.4 a 8.3 | da 8.1 a 8.3 |
| Schema del database | Identico, sei tabelle ps_dfoffers_* |  |
| Hook utilizzati | Identici |  |
| Configurazione delle offerte | Identica, migrazione trasparente |  |

Le differenze di API sono raggruppate in una sola classe interna, `DfOfferCompat`. Se sovrascrivi codice del modulo in un progetto su misura, è l'unico file da consultare per capire le diramazioni di versione.

## Installazione

1. Scarica il file `dfoffers-vX.Y.Z.zip` dalla tua area cliente DataFirefly
2. Nel back office di PrestaShop, vai su **Moduli → Gestione moduli**
3. Clicca sul pulsante **Carica un modulo** in alto
4. Trascina il file ZIP o cliccaci sopra per selezionarlo
5. L'installazione è automatica: le tabelle vengono create, gli hook registrati, e una nuova scheda **Catalogo → Offerte raggruppate** appare nel menu

Non è richiesta nessuna dipendenza esterna. Il modulo utilizza le classi native di PrestaShop (Cart, CartRule, Product) e non aggiunge nulla al tuo composer.json.

## I quattro tipi di offerte

### 1+1 sullo stesso prodotto

Il formato virale del _buy-one-get-one_: il cliente acquista un'unità di un prodotto e riceve un'altra unità dello stesso prodotto in regalo. Configura:

- Un solo prodotto (utilizzato sia come trigger che come ricompensa)
- La quantità da acquistare per attivare l'offerta (in genere 1)
- La quantità in regalo (in genere 1)

Esempio tipico: "Per 1 paio di calzini acquistato, il secondo è in regalo." Quando il cliente aggiunge il paio al carrello, il motore aggiunge automaticamente un secondo e applica uno sconto pari al prezzo unitario.

### Compra X, ricevi Y in regalo (prodotti diversi)

Formato bundle: più prodotti trigger distinti devono essere presenti nel carrello affinché l'offerta si attivi, e uno o più prodotti diversi vengono allora regalati. Configura:

- L'elenco dei prodotti trigger con le rispettive quantità
- L'elenco dei prodotti regalo con le rispettive quantità

Esempio tipico: "Compra una crema giorno e un siero insieme, ricevi un campione di maschera in regalo." Il motore verifica che tutti i trigger siano presenti prima di attivare l'offerta.

### Scelta tra varianti

Formato di composizione libera: definisci un insieme di prodotti o varianti candidate tra cui il cliente compone il proprio lotto. Il motore identifica automaticamente le unità più economiche del carrello come unità regalate, cosa che corrisponde all'interpretazione commerciale standard del _buy-N-get-M_.

- L'elenco dei prodotti o varianti candidate
- Il numero di unità da acquistare in questo insieme
- Il numero di unità regalate (le più economiche)

Esempio tipico: "3 t-shirt acquistate dalla nostra selezione, la più economica è gratuita." Il cliente compone il proprio lotto, il motore non tocca il suo carrello ma applica uno sconto sulle unità più economiche.

### Pacco all'ingrosso

Formato B2B e smaltimento di magazzino: per ogni lotto di X unità acquistate di un prodotto, il cliente riceve Y unità gratuite di un altro prodotto. Configura:

- Il prodotto trigger con la quantità di scaglione (ad esempio 10)
- Il prodotto regalo con la quantità offerta (ad esempio 20)

Esempio tipico: "Per 10 bottiglie di vino acquistate, 2 bicchieri in regalo." Pratico per i fornitori che vogliono spingere un prodotto complementare o smaltire scorte ferme attaccandole a un prodotto che vende bene.

## Crea la tua prima offerta

Dal back office, vai su **Catalogo → Offerte raggruppate** poi clicca su **Nuova offerta**.

### Passo 1: scegliere il tipo

Quattro carte visive presentano i tipi disponibili con una breve descrizione. Clicca su quella che corrisponde alla tua operazione commerciale. Il modulo si adatta automaticamente e mostra solo i campi rilevanti per quel tipo.

### Passo 2: nominare e dare un badge all'offerta

Compila:

- **Nome dell'offerta** (obbligatorio): ciò che il cliente vede sul banner. Un campo per ogni lingua attiva del negozio.
- **Testo del badge** (opzionale, max 64 caratteri): breve messaggio mostrato nella pill in alto del banner (ad esempio _1+1 GRATIS_, _OFFERTA SPECIALE_, _BLACK FRIDAY_).
- **Colore del badge**: sei preset DataFirefly disponibili più un selettore di colore libero. Il colore è utilizzato sia per il banner della scheda prodotto SIA per l'etichetta regalo lato carrello.

### Passo 3: aggiungere i prodotti trigger

Clicca su **Aggiungi un prodotto trigger**. Si apre una modale di ricerca con un campo che interroga il tuo catalogo in tempo reale (debounce di 250 ms dopo l'ultimo tasto). Digita un nome, una referenza o un EAN; i risultati appaiono immediatamente.

Clicca su un prodotto per aggiungerlo. Se il prodotto ha varianti, queste appaiono come pulsanti sotto il risultato, clicca su quella che ti interessa per aggiungerla direttamente. Specifica la quantità richiesta nel campo a destra della riga.

**Prodotto con varianti:** il pulsante _Prodotto principale (senza variante)_ aggiunge il prodotto con un jolly. L'offerta si applica allora a tutte le sue varianti, e la quantità acquistata viene contata sommando tutte le varianti. Scegli una variante precisa solo se l'offerta deve limitarsi a quella.

### Passo 4: aggiungere i prodotti regalo

Stessa procedura per i prodotti regalo. Questa sezione è nascosta per il tipo _Scelta tra varianti_, poiché le varianti servono sia da candidate che da ricompense.

### Passo 5: regole specifiche

- **Cumulabile**: se attivato, l'offerta si applica più volte per ogni lotto trigger. Senza cumulo, l'offerta si applica una sola volta a prescindere dal numero di unità. Disattivato di default per proteggere i tuoi margini.
- Per il tipo _Scelta tra varianti_, appaiono due campi aggiuntivi: quante unità il cliente deve acquistare e quante sono in regalo.

### Passo 6: attivazione

- **Date di validità**: lascia vuoto per un'offerta permanente. Indica la data di inizio o di fine per automatizzare l'attivazione. Una data illeggibile viene rifiutata, e la data di fine deve essere successiva a quella di inizio.
- **Priorità**: se più offerte possono applicarsi simultaneamente, quella con la priorità più bassa viene valutata per prima.
- **Stato**: interruttore on/off, attivato di default. Pratico per disattivare temporaneamente un'offerta senza eliminarla.

### Passo 7: negozi (se multi-negozio)

Spunta i negozi su cui l'offerta deve essere disponibile. Non spuntare nulla equivale ad attivare l'offerta su tutti i negozi.

## Modificare o eliminare un'offerta

Da **Catalogo → Offerte raggruppate**, ogni riga dell'elenco ha un pulsante **Modifica** e, nel suo menu a tendina, **Elimina**. L'interruttore della colonna Attiva permette anche di sospendere un'offerta senza eliminarla. Per agire su più offerte contemporaneamente, spuntale e usa le azioni di gruppo in fondo all'elenco.

L'eliminazione è definitiva e ripulisce tutto ciò che dipende dall'offerta: trigger, ricompense, associazioni ai negozi e le regole del carrello che il motore aveva generato per i carrelli in corso. Un cliente che aveva il regalo nel carrello lo vedrà sparire alla sua prossima azione.

## Come funziona il motore di aggiunta automatica

Il motore si aggancia all'hook PrestaShop `actionCartSave` e si esegue ad ogni modifica del carrello (aggiunta, rimozione, cambio di quantità, fusione al login).

1. Recupera tutte le offerte attive per il negozio corrente
2. Per ogni offerta, calcola la **quantità pagata** di ciascun prodotto trigger (quantità totale del carrello meno ciò che il motore ha già aggiunto automaticamente in una valutazione precedente)
3. Valuta se le condizioni dell'offerta sono soddisfatte
4. In tal caso, aggiunge i prodotti regalo mancanti al carrello tramite `Cart::updateQty`
5. Crea o aggiorna una regola del carrello (`CartRule`) con uno sconto fisso IVA inclusa pari al valore delle unità offerte
6. Registra nella tabella `ps_dfoffers_cart_auto` le unità che ha aggiunto, per distinguerle dalle unità che il cliente ha aggiunto da solo

Il motore protegge contro i loop infiniti: `Cart::updateQty` riattiva l'hook `actionCartSave`, ma una protezione statica nel modulo impedisce la ricorsione.

### Revoca pulita

Se il cliente rimuove un prodotto trigger o riduce la sua quantità sotto la soglia, il motore rivaluta l'offerta al successivo `actionCartSave`. Se la condizione non è più soddisfatta, rimuove le unità che aveva aggiunto automaticamente (senza toccare le unità che il cliente aveva aggiunto da solo grazie al tracking) ed elimina la regola del carrello associata.

## Impostazioni del modulo

Da **Moduli → Gestione moduli → Smart Offers → Configura**, due impostazioni globali:

- **Posizione del banner sulla scheda prodotto**. Cinque posizioni, ciascuna corrispondente a un hook del tema Classic: Il modulo è registrato su tutti e cinque gli hook e solo quello scelto renderizza il banner. Se il tuo tema non chiama l'hook selezionato, il banner non apparirà: scegline un altro.
   - Sotto il blocco Aggiungi al carrello (predefinito): `displayProductAdditionalInfo`
   - Sotto il prezzo: `displayProductPriceBlock`, tipo `after_price`
   - Sotto le immagini del prodotto: `displayAfterProductThumbs`
   - Nel blocco rassicurazione, sotto le icone di pagamento: `displayReassurance`
   - Larghezza piena, sotto la scheda: `displayFooterProduct`
- **Banner compatto**. Forza ovunque il layout denso (spaziature ridotte, miniature da 92 px, gruppi affiancati). Senza questa opzione il banner adotta già da solo questo layout quando la sua colonna è più stretta di 520 px, e impila i gruppi sotto i 300 px. Il rilevamento si basa sulla larghezza della colonna, non su quella della finestra: una scheda prodotto stretta su un sito largo viene trattata come un telefono.

I browser precedenti al 2023 non gestiscono le container query; ripiegano su un rilevamento per larghezza della finestra (768 px e 400 px).

## Visualizzazione sulla scheda prodotto

Su ogni scheda prodotto trigger, un **banner con gradiente** viene mostrato nella posizione scelta nelle impostazioni (di default sotto il pulsante Aggiungi al carrello). Contiene:

- Un badge pill bianco con icona regalo, contenente il testo del badge
- Il titolo dell'offerta
- Un messaggio dinamico che dipende dal tipo di offerta ("Acquistane 1, ricevine 1 in più gratis", "Per ogni lotto di 10, ricevi 20 in più gratis", ecc.)
- Una griglia con le miniature cliccabili dei prodotti coinvolti, separate in due gruppi _Acquista_ / _Ricevi in regalo_ con un separatore SVG circolare tra di esse

Il colore del banner riprende quello del badge configurato nell'offerta. La presentazione è responsive: su mobile, i due gruppi si impilano verticalmente e il separatore ruota per puntare verso il basso.

## Visualizzazione nel carrello

Due indicatori distinti aiutano il cliente a identificare i prodotti regalo nel suo carrello.

### Etichetta regalo su ogni riga

Su ogni riga del carrello che contiene unità aggiunte automaticamente da un'offerta, appare una piccola etichetta colorata `🎁 ×N gratis` nella colonna info prodotto, sotto il prezzo e le varianti. Il colore riprende quello del badge dell'offerta, e l'etichetta indica quante unità di questa riga sono gratuite (utile quando una parte della quantità è pagata e l'altra offerta, ad esempio in un 1+1 stesso prodotto).

Dalla 2.1.2, questa etichetta viene resa tramite l'hook `displayProductPriceBlock` (tipo `unit_price`), che il tema Classic chiama nella colonna info di ogni riga del carrello. Per i temi che non chiamano quell'hook, il modulo ripiega su `displayCartExtraProductActions` nella colonna azioni. Un registro per richiesta garantisce che una riga venga decorata una sola volta, anche se il tema espone entrambi gli hook.

### Footer del carrello dettagliato

In fondo alla griglia dei prodotti, un blocco verde riepiloga le offerte attivate nel carrello. Per ogni offerta, il blocco mostra:

- Il nome dell'offerta e il suo testo di badge (in pill colorata)
- L'elenco dei prodotti offerti da questa offerta, sotto forma di chip visivi con miniatura rotonda, nome (con la sua variante, ad esempio "Cuscino orso bruno (Colore: Bianco)") e quantità
- Ogni chip è cliccabile e rimanda alla scheda del prodotto regalo

Il cliente può così verificare a colpo d'occhio cosa ha ottenuto gratuitamente e grazie a quale operazione commerciale.

## Casi particolari e comportamenti

### Perché 1+1 sullo stesso prodotto è gestito specificamente

Quando il prodotto trigger è anche il prodotto regalo, molti moduli di offerte raggruppate sul mercato commettono l'errore di identificare l'unità pagata del cliente come se fosse già l'unità offerta, e applicano lo sconto su quella unità. Alla fine, il cliente paga zero per un'unità invece di pagare per una e riceverne una seconda gratis.

Smart Offers gestisce questo caso con una logica precisa: la quantità target nel carrello vale _quantità pagata dal cliente_ + _quantità regalo_. Quando il cliente aggiunge un'unità, il motore ne aggiunge una seconda affinché il carrello contenga due unità, e lo sconto si applica solo sulla seconda unità. Il cliente paga quindi il prezzo di un'unità per averne due nel suo carrello.

### Offerte su prodotti con varianti

Un'offerta può puntare a una variante precisa o al prodotto nel suo insieme. Nel back office, aggiungere il prodotto tramite _Prodotto principale (senza variante)_ salva un jolly: il motore lo legge esattamente come il banner, cioè "qualsiasi variante".

- **Trigger con jolly**: la quantità acquistata è la somma di tutte le varianti del prodotto presenti nel carrello. Due cuscini bianchi e un cuscino nero contano come tre unità.
- **Ricompensa con jolly**: il motore deve scegliere una variante concreta prima di aggiungere al carrello. Prende prima quella che il cliente ha già nel suo carrello per quel prodotto (un 1+1 su un cuscino bianco aggiunge un cuscino bianco). Se il prodotto non è ancora nel carrello, prende la variante predefinita definita nel catalogo. Un prodotto senza varianti viene aggiunto così com'è.
- **Scelta tra varianti con jolly**: ogni variante presente nel carrello diventa una riga candidata a pieno titolo, il che permette all'ordinamento per prezzo di designare le più economiche.

Prima della 2.0.1, un'offerta salvata con jolly non si attivava mai quando il cliente aggiungeva una variante: il banner si mostrava ma nulla accadeva nel carrello. Se osservi questo sintomo, aggiorna il modulo.

### Cumulo dei lotti (opzione stackable)

Senza cumulo, l'offerta si applica una sola volta a prescindere dal numero di lotti trigger presenti nel carrello. Se il cliente acquista 5 unità di un prodotto con un'offerta 1+1 e stackable disattivato, riceverà 1 unità in regalo (non 5).

Con il cumulo attivato, il motore moltiplica il numero di lotti di ricompensa per il numero intero di lotti trigger presenti. Per la stessa offerta 1+1 con stackable attivato e 5 unità nel carrello, il cliente riceverà 5 unità in regalo (carrello finale: 10 unità, 5 pagate).

L'opzione stackable è disattivata di default. Attivala con cautela: può intaccare significativamente i tuoi margini su operazioni ad alto volume.

### Magazzino e indisponibilità

L'aggiunta dei prodotti regalo al carrello passa per `Cart::updateQty`, che rispetta le regole di magazzino native di PrestaShop. Se un prodotto regalo è esaurito e il negozio non consente l'ordine senza scorta, l'aggiunta fallisce silenziosamente e lo sconto non viene applicato. La condizione resta pronta ad attivarsi non appena il prodotto torna disponibile.

### Più offerte simultanee sullo stesso carrello

Ogni offerta genera la propria regola del carrello con `partial_use` attivato. Questo permette di accumulare più offerte concorrenti sullo stesso carrello senza conflitti, e resta compatibile con i codici sconto classici che i tuoi clienti possono inserire.

## Lingue del modulo

Dalla 2.1.2, la lingua sorgente del modulo è l'inglese e sette traduzioni vengono fornite nella cartella `translations/`: francese, tedesco, italiano, spagnolo, olandese, portoghese e polacco. Coprono il banner della scheda prodotto, il carrello, il nome della regola del carrello visto dal cliente, il modulo di creazione offerta e i messaggi del selettore prodotti.

Ogni stringa resta modificabile da **Internazionale → Traduzioni** scegliendo il modulo _dfoffers_. Un negozio in una lingua non fornita mostra l'inglese e può essere tradotto nello stesso punto.

Da non confondere con il nome, il badge e la descrizione di ogni offerta, che inserisci tu stesso in ogni lingua attiva del negozio al momento di creare l'offerta.

## Architettura tecnica

### Hook utilizzati

- `displayProductAdditionalInfo`, `displayProductPriceBlock` (tipo `after_price`), `displayAfterProductThumbs`, `displayReassurance`, `displayFooterProduct`: banner sulla scheda prodotto, uno solo attivo secondo le impostazioni
- `displayShoppingCartFooter`: footer dettagliato sulla pagina del carrello
- `displayProductPriceBlock`: etichetta regalo nella colonna info di ogni riga del carrello (tipo `unit_price`, solo pagina del carrello)
- `displayCartExtraProductActions`: etichetta regalo di ripiego, nella colonna azioni
- `actionCartSave`: motore di valutazione e aggiunta automatica
- `actionFrontControllerSetMedia` e `actionAdminControllerSetMedia`: iniezione di CSS e JS
- `actionObjectProductDeleteAfter`: pulizia automatica delle offerte che fanno riferimento a un prodotto eliminato

Solo `actionCartSave` e `actionFrontControllerSetMedia` sono considerati indispensabili per l'installazione. Gli hook di visualizzazione che un tema non implementa vengono registrati nel log senza far fallire l'installazione.

### Tabelle aggiunte

- `ps_dfoffers_offer`: configurazione di ciascuna offerta (tipo, date, priorità, cumulo)
- `ps_dfoffers_offer_lang`: nome, badge e descrizione tradotti per lingua
- `ps_dfoffers_trigger`: prodotti trigger di ciascuna offerta
- `ps_dfoffers_reward`: prodotti regalo di ciascuna offerta
- `ps_dfoffers_shop`: associazione offerta / negozio in multi-negozio
- `ps_dfoffers_cart_auto`: tracking delle unità aggiunte automaticamente per carrello e per offerta, con l'identificativo della regola del carrello generata

Tutte le tabelle utilizzano il prefisso configurato nella tua installazione PrestaShop (`ps_` di default). Lo schema è identico su PrestaShop 8 e 9, il che rende la migrazione trasparente.

### La classe DfOfferCompat

Tutte le differenze di API tra PrestaShop 8 e 9 sono concentrate in `classes/DfOfferCompat.php`. Il resto del modulo non verifica mai direttamente la versione di PrestaShop. I punti assorbiti da questa classe:

- **Lettura delle varianti**: PrestaShop 9 ha rimosso l'argomento della lingua da `Product::getAttributeCombinations()`, dove il primo parametro è ora il flag booleano di raggruppamento.
- **URL AJAX del backoffice**: su PrestaShop 9, la coppia `ajax` e `action` deve transitare dal quarto argomento di `getAdminLink()`, perché il token viene calcolato prima della fusione dei parametri.
- **Risposta JSON**: il metodo di invio porta volutamente un nome diverso da `ajaxRender()`, la cui firma ereditata non deve essere sovrascritta.
- **Scheda admin**: PrestaShop 9 ha introdotto colonne di traduzione aggiuntive, compilate sotto una verifica per non creare una proprietà dinamica su PrestaShop 8.

### Sovrascrivere i template nel tuo tema

Il CSS del modulo è isolato sotto il prefisso `.dfoffers-` per evitare conflitti con il tuo foglio di stile. Se desideri modificare il rendering, copia i template da `/modules/dfoffers/views/templates/hook/` verso `/themes/il-tuo-tema/modules/dfoffers/views/templates/hook/` e personalizzali. Tre template sono disponibili:

- `product-banner.tpl`: banner sulla scheda prodotto
- `cart-offer.tpl`: blocco riepilogo nel footer del carrello
- `cart-line-gift.tpl`: etichetta regalo inline sulle righe del carrello

## Aggiornare il modulo

Per aggiornare a una nuova versione, carica semplicemente il nuovo ZIP dal Gestore moduli. PrestaShop rileva il cambio di versione in `config.xml` ed esegue automaticamente gli script di aggiornamento presenti in `/upgrade/upgrade-X.Y.Z.php`, che si occupano ad esempio di registrare nuovi hook aggiunti tra le versioni.

Non è necessaria nessuna disinstallazione/reinstallazione tra le versioni, e le tue offerte esistenti sono preservate intatte.

### Migrare un negozio da PrestaShop 8 a PrestaShop 9

Essendo identico lo schema del database, le tue offerte, le tue traduzioni e le tue associazioni di negozi superano la migrazione senza trasformazione. La procedura consigliata:

1. Porta il modulo alla 2.x **prima** di migrare il negozio, mentre gira ancora su PrestaShop 8. Le versioni 2.x funzionano su entrambe le generazioni, quindi riduci il numero di variabili se qualcosa va storto.
2. Migra il negozio a PrestaShop 9 secondo la procedura ufficiale PrestaShop.
3. Vai su **Design → Posizioni** e verifica che gli hook del modulo siano ancora collegati. Una migrazione può perderne qualcuno.
4. Se mancano degli hook, ricarica lo ZIP: lo script di aggiornamento registra nuovamente ogni hook assente e ripulisce le righe di tracciamento il cui carrello non esiste più.

PrestaShop 9 richiede almeno PHP 8.1. Verifica la versione di PHP del tuo hosting prima di lanciare la migrazione: è la causa di errore più frequente, ben prima dei moduli.

## Risoluzione dei problemi

### I prodotti regalo non vengono aggiunti al carrello

1. Svuota la cache PrestaShop in **Parametri avanzati → Prestazioni**
2. Verifica che l'hook `actionCartSave` contenga il modulo in **Design → Posizioni**
3. Verifica che il prodotto regalo sia disponibile (non esaurito se gli ordini senza scorta sono vietati, non disattivato, assegnato al negozio corrente)
4. Se il prodotto trigger ha varianti e il banner si mostra correttamente sulla scheda, verifica che il modulo sia in 2.0.1 o superiore: le versioni precedenti non leggevano il jolly "tutte le varianti" lato motore
5. Consulta **Parametri avanzati → Log** cercando `dfoffers`: il motore traccia la sua esecuzione ad ogni modifica del carrello

### Lo sconto non viene applicato nonostante l'aggiunta del prodotto

Verifica nei log la riga `checkValidity` che segue la creazione della regola del carrello. PrestaShop indica con precisione perché una regola viene rifiutata (esaurito, restrizione cliente, valuta diversa, ecc.).

### L'etichetta regalo non appare sulle righe del carrello

Il modulo cerca prima l'hook `displayProductPriceBlock` in `cart-detailed-product-line.tpl`, poi `displayCartExtraProductActions`. I temi Classic di PrestaShop 8 e 9 e la maggior parte dei temi commerciali contengono almeno uno dei due. Se il tuo tema personalizzato non ne implementa nessuno, aggiungi una di queste righe nel file `cart-detailed-product-line.tpl`, preferibilmente la prima nella colonna info prodotto:

```
{hook h='displayProductPriceBlock' product=$product type="unit_price"}
{hook h='displayCartExtraProductActions' product=$product}
```

### L'etichetta è troncata o mostra solo l'icona

Sintomo delle versioni 2.1.0 e 2.1.1 sul tema Classic, dove l'etichetta veniva resa nella colonna azioni, troppo stretta per il testo. Corretto in 2.1.2 spostandola nella colonna info prodotto. Aggiorna il modulo.

### Errore 500 al salvataggio di un'offerta

Prima della 2.2.0, un nome o testo del badge contenente `=`, `;`, `#`, `{` o `}` veniva rifiutato dai validatori di PrestaShop e il salvataggio terminava con una pagina bianca. Dalla 2.2.0 questi caratteri sono accettati, e ogni valore davvero non valido viene segnalato nel modulo invece di provocare un errore. Se incontri ancora un 500, consulta **Parametri avanzati → Log**: la causa è registrata sotto `dfoffers save failed`.

### La ricerca prodotti del backoffice non restituisce nulla dopo una migrazione a PrestaShop 9

Svuota la cache PrestaShop poi ricarica la pagina di creazione offerta. L'URL dell'endpoint di ricerca viene costruito lato server al rendering del modulo; una pagina messa in cache prima della migrazione può ancora portare un vecchio URL. Se il problema persiste, apri la console del browser: una risposta 404 sulla richiesta di ricerca indica che la scheda del modulo non è stata ricreata correttamente, e una reinstallazione del modulo lo corregge senza perdere le offerte.

### L'installazione sembra riuscita ma non si può creare nessuna offerta

Prima della 2.0.0, un errore nella creazione delle tabelle durante l'installazione era silenzioso e il modulo appariva come installato. Dalla 2.0.0, questa situazione fa fallire l'installazione con un messaggio esplicito. Se incontri questo caso su una versione precedente, verifica i permessi dell'utente MySQL sulla creazione di tabelle, poi disinstalla e reinstalla il modulo.

## Domande frequenti

### Il modulo è compatibile con PrestaShop 9?

Sì, dalla versione 2.0.0. Lo stesso file ZIP si installa su PrestaShop 8.0 come su PrestaShop 9.x. Le differenze di API vengono assorbite dalla classe interna `DfOfferCompat`, quindi non serve scegliere un ramo specifico al download. Le versioni 1.x restavano limitate a PrestaShop da 8.0 a 8.99.

### Qual è l'impatto sulle prestazioni?

Il motore esegue una query SQL per offerta attiva sul negozio, poi valuta le condizioni in memoria. Su un catalogo con una decina di offerte attive, la valutazione completa richiede in media meno di cinquanta millisecondi. Questa cifra è identica su PrestaShop 8 e 9.

### Posso usare il modulo con un tema headless?

Il motore di aggiunta automatica è indipendente dal tema e funziona per qualsiasi front-end che passi per `Cart::updateQty` o l'API REST di PrestaShop. Il banner della scheda prodotto e l'etichetta regalo del carrello sono hook Smarty nativi che richiedono un tema classico per essere mostrati. Per un front headless, puoi esporre i dati tramite un'API custom che interroga direttamente `ps_dfoffers_offer` e `ps_dfoffers_cart_auto`.

### Il modulo gestisce più valute?

Sì. La regola del carrello generata per ciascuna offerta utilizza la valuta del carrello corrente. Se il cliente cambia valuta, la regola viene rigenerata al valore corretto al successivo `actionCartSave`.

### Cosa succede se clicco su Reimposta nel gestore moduli?

Il modulo viene disinstallato e reinstallato nella stessa richiesta, il che elimina e ricrea le tabelle: tutte le tue offerte vanno perse. Dalla 2.0.0 questa operazione ricrea correttamente le tabelle, mentre le versioni precedenti lasciavano il negozio del tutto senza tabelle. In entrambi i casi, fai un backup prima di reimpostare.
