# dfomnibus — Conformité Directive Omnibus PrestaShop

> Le module dfomnibus met votre boutique PrestaShop en conformité avec la directive européenne 2019/2161 dite Omnibus, en vigueur dans toute l'Union européenne depuis le 28 mai 2022. Il construit automatiquement…

- Page: <https://www.datafirefly.com/documentation/dfomnibus/>
- Langue: fr
- Mis à jour le: 2026-07-02
- Autres langues: [en](https://www.datafirefly.com/en/documentation/dfomnibus/index.md), [es](https://www.datafirefly.com/es/documentation/dfomnibus/index.md), [de](https://www.datafirefly.com/de/documentation/dfomnibus/index.md), [it](https://www.datafirefly.com/it/documentation/dfomnibus/index.md), [pl](https://www.datafirefly.com/pl/documentation/dfomnibus/index.md), [nl](https://www.datafirefly.com/nl/documentation/dfomnibus/index.md), [pt](https://www.datafirefly.com/pt/documentation/dfomnibus/index.md)
- Index: <https://www.datafirefly.com/documentation/llms.txt>

Le module **dfomnibus** met votre boutique PrestaShop en conformité avec la directive européenne 2019/2161 dite Omnibus, en vigueur dans toute l'Union européenne depuis le 28 mai 2022. Il construit automatiquement l'historique de prix de chaque produit et affiche, dès qu'une promotion est active, le prix le plus bas constaté pendant les 30 jours précédents.

**Compatibilité :** PrestaShop 8.0 à 9.x. PHP 7.4 à 8.3. Multi-boutique, multi-devise et multi-déclinaison pris en charge nativement. Aucun composant tiers, aucun CDN, RGPD-friendly.

## Installation

L'installation prend moins de cinq minutes.

1. Téléchargez le fichier `dfomnibus_v1.0.1.zip` depuis votre espace client DataFirefly.
2. Dans le back-office PrestaShop, allez dans **Modules → Gestionnaire de modules → Installer un module**.
3. Uploadez le ZIP. PrestaShop crée les tables, génère un jeton cron et enregistre les hooks nécessaires.
4. Cliquez sur **Configurer** pour ouvrir l'écran de paramétrage.

**Deux tables créées :** `ps_dfomnibus_price_history` pour les snapshots et `ps_dfomnibus_compliance_log` pour les événements de conformité (réservée à des évolutions futures). Le préfixe `ps_` est remplacé automatiquement par le vôtre.

## Programmation du cron quotidien

Le cron amorce l'historique de votre catalogue et garantit la continuité des snapshots quotidiens, même pour les produits dont le prix ne change jamais. Sans cron actif, le module fonctionne mais son historique reste limité aux produits modifiés manuellement.

### Récupération du jeton

Ouvrez la page de configuration du module. Le jeton cron affiché est unique à votre installation. Vous obtenez une URL de la forme :

```
https://votre-boutique.com/modules/dfomnibus/cron.php?token=VOTRE_JETON
```

### Programmation via cron Unix

Ajoutez la ligne suivante à votre crontab, ajustez l'heure selon votre trafic (idéalement en heures creuses) :

```
15 3 * * * curl -s "https://votre-boutique.com/modules/dfomnibus/cron.php?token=VOTRE_JETON" > /dev/null
```

### Programmation via CLI

Si vous préférez éviter toute exposition HTTP, exécutez le cron directement en ligne de commande :

```
php /chemin/vers/votre-boutique/modules/dfomnibus/cron.php token=VOTRE_JETON
```

**Sécurité du jeton :** le module utilise `hash_equals()` pour comparer les jetons, ce qui protège contre les attaques par timing. Ne partagez jamais ce jeton et régénérez-le si vous suspectez une compromission (bouton _Régénérer le jeton_ dans la configuration).

## Configuration des options

### Activation de l'affichage

La bascule **Activer l'affichage** contrôle l'insertion du message de conformité sous le prix produit. Vous pouvez la désactiver temporairement pour maintenir la collecte de l'historique sans afficher la mention en frontend (utile lors d'une bascule ou pendant les tests).

### Mode de calcul

Deux modes sont disponibles :

- **Strict** : le prix de référence est le minimum constaté pendant les 30 jours qui précèdent le début effectif de la promotion en cours. Correspond à la lettre de la directive.
- **Conservateur** (recommandé par défaut) : le prix de référence est le minimum sur les 30 derniers jours glissants. Interprétation plus défavorable au commerçant mais plus défensive en cas de contrôle.

**Quel mode choisir ?** Si votre boutique a une politique promotionnelle claire, avec des dates de début et fin bien tracées, le mode strict est parfait. En cas de doute, ou si vos règles SpecificPrice sont modifiées fréquemment sans discontinuité franche entre les périodes promo et non-promo, le mode conservateur est plus sûr.

### Période de référence

La période est fixée à 30 jours par défaut, conformément à la directive. Vous pouvez l'augmenter (60, 90 jours) pour être encore plus prudent, mais la valeur minimale reste à 30 jours.

### Exclusion des produits récents

L'option **Exclure les produits de moins de X jours** masque l'affichage sur les produits trop récents. Valeur par défaut : 30 jours. C'est cohérent avec l'esprit de la directive, qui ne s'applique qu'aux produits dont l'historique de prix est significatif.

### Restriction UE

Si vous vendez dans et hors UE, cochez **Restreindre l'affichage à l'Union européenne**. Le module détecte le pays du client dans cet ordre :

1. Adresse de livraison du client connecté
2. Adresse du panier en cours
3. Pays par défaut de la boutique

Si aucune de ces informations n'est disponible, l'affichage est actif par défaut pour éviter tout risque de non-conformité involontaire.

### Masquer lorsque prix égal

L'option **Masquer si prix identique** supprime le message lorsque le prix actuel correspond exactement au prix le plus bas des 30 derniers jours. Utile pour éviter d'afficher une information sans valeur ajoutée pour le consommateur.

### Remise réelle

Activez **Afficher la remise réelle** pour compléter le message par le pourcentage calculé sur la base du prix Omnibus, et non du prix barré. Exemple : un produit à 89 €, en promo à 59 €, avec un prix Omnibus de 65 € affichera _-9,2 %_ de remise réelle au lieu du -33 % calculé sur le prix barré. C'est plus honnête, mais chaque commerçant est libre de choisir.

### Graphique

Le graphique 30 jours peut s'afficher dans un onglet dédié de la fiche produit ou en ligne sous le prix. Il est lazy-loaded via IntersectionObserver et ne se déclenche qu'à l'entrée dans le viewport, ce qui garantit un impact nul sur le Core Web Vitals de vos fiches produit.

### Suivi par déclinaison

Cochez **Suivre les déclinaisons** si vos produits ont des prix différents par combinaison (par exemple des tailles XL avec supplément). L'historique est alors segmenté par `id_product_attribute` et la mention Omnibus s'adapte au prix de la déclinaison sélectionnée.

### Rétention

La durée de conservation par défaut est de 365 jours. Au-delà, l'historique est purgé automatiquement lors de l'exécution du cron. La valeur minimale est de 60 jours pour garantir une marge de sécurité par rapport à la fenêtre légale de 30 jours.

## Tableau de bord de conformité

Accessible via **Modules → Tableau de bord DataFirefly Omnibus**, le tableau de bord regroupe :

- Le nombre de produits suivis
- Le total de snapshots enregistrés
- La date et l'heure du dernier passage du cron
- La liste des produits avec, pour chacun, la date de première capture, la date de dernière capture, le prix le plus bas des 30 derniers jours et un indicateur de promotion active

Pour chaque produit, trois actions sont disponibles :

- **Voir l'historique** : affiche jusqu'à 1000 snapshots horodatés
- **Snapshot manuel** : force la capture immédiate
- **Supprimer l'historique** : réinitialise le suivi pour ce produit (à utiliser avec prudence)

### Export CSV

Depuis la vue d'historique d'un produit, le bouton **Exporter en CSV** génère un fichier avec toutes les colonnes horodatées (date, prix HT, prix TTC, devise, boutique, déclinaison, indicateur promo, source de la capture). Format prêt à archiver ou à transmettre à un contrôleur DGCCRF.

## Comportement en frontend

Sur la fiche produit, dès qu'une promotion est active, la mention suivante s'affiche automatiquement sous le prix :

> Prix le plus bas des 30 derniers jours : 65,00 €

Le message est traduit selon la langue de la boutique (français, anglais, espagnol, allemand). L'affichage utilise le hook standard `displayProductPriceBlock` et fonctionne avec tous les thèmes respectant les standards PrestaShop (Classic, Hummingbird, Warehouse, Transformer, Panda).

**Rendu unique par page :** le module inclut une protection `static $rendered` qui garantit que la mention n'apparaît qu'une seule fois par page, même si le hook `displayProductPriceBlock` est appelé plusieurs fois (blocs récapitulatifs, sticky, etc.).

## Multi-boutique et multi-devise

L'historique est stocké par combinaison unique `(id_product, id_product_attribute, id_shop, id_currency)`. Chaque boutique de votre installation conserve donc son historique propre, et chaque devise active a sa propre courbe de prix. Aucune conversion à la volée : les montants affichés correspondent exactement à ce qui a été enregistré au moment de la capture.

## Dépannage

### La mention n'apparaît pas sur la fiche produit

Vérifiez dans l'ordre :

1. L'option **Activer l'affichage** est-elle bien cochée dans la configuration ?
2. Un cron a-t-il été exécuté au moins une fois ? Sinon, aucun historique n'existe.
3. La restriction UE est-elle activée alors que vous testez depuis un pays hors UE ?
4. L'option **Masquer si prix identique** est-elle activée et le prix actuel correspond-il au prix minimum ?
5. Le produit a-t-il moins de 30 jours (avec l'option d'exclusion des nouveautés active) ?

### Le graphique ne se charge pas

Ouvrez la console navigateur. Le module attend un point d'entrée AJAX exposé par le contrôleur front `pricehistory`. Vérifiez qu'aucun système de cache ou pare-feu n'intercepte cette route. Si vous utilisez un CDN, autorisez explicitement les URL `/module/dfomnibus/pricehistory`.

### Le cron retourne une erreur 403 ou 401

Le jeton dans l'URL ne correspond pas à celui enregistré. Retournez dans la configuration du module et copiez le jeton actuel. Si vous suspectez une fuite, cliquez sur **Régénérer le jeton** et mettez à jour votre cron Unix.

### Erreur SQL au moment du snapshot

Si vous êtes sur la version 1.0.0, mettez à jour vers la 1.0.1. La version initiale contenait un défaut sur trois requêtes `Db::getRow()` qui ajoutaient un `LIMIT 1` manuel alors que PrestaShop en ajoute déjà un automatiquement, ce qui produisait un `LIMIT 1 LIMIT 1` invalide en SQL. Voir le changelog.

## FAQ

### Le module est-il obligatoire pour ma boutique ?

Oui, si vous vendez à des consommateurs établis dans l'Union européenne et que vous affichez des prix réduits, des promotions, des codes promo, des soldes ou toute mention de réduction. La directive Omnibus s'applique sans seuil de chiffre d'affaires.

### Quelle différence avec les CartRule ?

Le module suit uniquement les prix issus des `SpecificPrice` de PrestaShop (remises produit, remises quantité, remises groupe client). Les règles de panier (`CartRule`) s'appliquent au checkout et ne modifient pas le prix unitaire affiché en fiche produit : elles sortent donc du périmètre de la directive.

### Comment fonctionne le mode strict précisément ?

Le module cherche dans l'historique le dernier snapshot non-promo, puis le premier snapshot promo qui suit. Cette date est le début de la promotion en cours. La fenêtre de référence est alors les 30 jours qui précèdent cette date. Si aucune bascule non-promo vers promo n'est détectable, le module bascule automatiquement sur le mode conservateur.

### Puis-je masquer le message sur certains produits ?

Le module s'applique globalement, mais l'option d'exclusion des produits récents et l'option de masquage si prix égal couvrent la majorité des cas où l'affichage n'apporte pas d'information utile.

### Compatible avec les prix HT/TTC ?

Oui. Le module enregistre les deux montants (`price_tax_excl` et `price_tax_incl`) à chaque snapshot et affiche celui utilisé par la boutique. Si vous basculez d'un mode à l'autre, l'historique reste exploitable.

## Changelog

### 1.0.1 — 14 mai 2026

- Correction : suppression du `LIMIT 1` manuel dans trois requêtes `Db::getRow()` qui produisaient un `LIMIT 1 LIMIT 1` invalide en SQL. Affectait la garde d'idempotence de l'enregistrement et la détection du début de promo en mode strict.

### 1.0.0 — 14 mai 2026

- Sortie initiale
- Capture automatique de l'historique de prix via hooks et cron quotidien
- Affichage du prix le plus bas sur 30 jours sur la fiche produit
- Graphique 30 jours en canvas vanilla, lazy-load, environ 3 Ko
- Tableau de bord de conformité avec statistiques et export CSV
- Modes de calcul strict et conservateur
- Support multi-boutique, multi-devise, multi-déclinaison
- Restriction UE configurable, exclusion des produits récents, option de masquage si prix identique
- Traductions FR, EN, ES, DE
