# dfomnibus: conformidade com a diretiva Omnibus no PrestaShop

> O módulo dfomnibus coloca a sua loja PrestaShop em conformidade com a diretiva europeia 2019/2161, conhecida por Omnibus, em vigor em toda a União Europeia desde 28 de maio de…

- Página: <https://www.datafirefly.com/pt/documentation/dfomnibus/>
- Idioma: pt
- Atualizado em: 2026-09-09
- Outros idiomas: [fr](https://www.datafirefly.com/documentation/dfomnibus/index.md), [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)
- Índice: <https://www.datafirefly.com/pt/documentation/llms.txt>

O módulo **dfomnibus** coloca a sua loja PrestaShop em conformidade com a diretiva europeia 2019/2161, conhecida por Omnibus, em vigor em toda a União Europeia desde 28 de maio de 2022. Constrói automaticamente o histórico de preços de cada produto e mostra, sempre que houver uma promoção ativa, o preço mais baixo praticado nos 30 dias anteriores.

Em Portugal, a diretiva Omnibus foi transposta pelo **Decreto-Lei n.º 66/2021**, que alterou o regime dos preços e das reduções: qualquer anúncio de redução de preço tem de indicar o preço mais baixo praticado nos 30 dias anteriores. A fiscalização cabe à ASAE. É exatamente esta obrigação que o módulo automatiza.

**Compatibilidade:** PrestaShop 8.0 a 9.x. PHP 7.4 a 8.3. Multiloja, multimoeda e multicombinação suportados nativamente. Sem componentes de terceiros, sem CDN e compatível com o RGPD.

## Instalação

A instalação demora menos de cinco minutos.

1. Descarregue o ficheiro `dfomnibus_v1.0.1.zip` a partir da sua área de cliente DataFirefly.
2. No back-office do PrestaShop, vá a **Módulos → Gestor de módulos → Carregar um módulo**.
3. Envie o ZIP. O PrestaShop cria as tabelas, gera um token de cron e regista os hooks necessários.
4. Clique em **Configurar** para abrir o ecrã de definições.

**Duas tabelas criadas:** `ps_dfomnibus_price_history`, para os instantâneos, e `ps_dfomnibus_compliance_log`, para os eventos de conformidade (reservada para evoluções futuras). O prefixo `ps_` é automaticamente substituído pelo seu.

## Agendamento do cron diário

O cron inicia o histórico do seu catálogo e garante a continuidade dos instantâneos diários, mesmo nos produtos cujo preço nunca muda. Sem cron ativo, o módulo funciona, mas o histórico fica limitado aos produtos alterados manualmente.

### Obter o token

Abra a página de configuração do módulo. O token de cron apresentado é único para a sua instalação. Obtém um URL com esta forma:

```
https://a-sua-loja.pt/modules/dfomnibus/cron.php?token=O_SEU_TOKEN
```

### Agendamento por cron Unix

Acrescente a linha seguinte ao seu crontab e ajuste a hora conforme o seu tráfego (idealmente, em horas de menor movimento):

```
15 3 * * * curl -s "https://a-sua-loja.pt/modules/dfomnibus/cron.php?token=O_SEU_TOKEN" > /dev/null
```

### Agendamento por CLI

Se preferir evitar qualquer exposição por HTTP, execute o cron diretamente na linha de comandos:

```
php /caminho/para/a-sua-loja/modules/dfomnibus/cron.php token=O_SEU_TOKEN
```

**Segurança do token:** o módulo usa `hash_equals()` para comparar os tokens, o que protege contra ataques por medição de tempo. Nunca partilhe este token e gere um novo se suspeitar de compromisso (botão _Gerar novo token_ na configuração).

Confirme que o fuso horário do servidor está em Europe/Lisbon. A janela dos 30 dias é calculada a partir das datas dos instantâneos: com o servidor em UTC, no horário de verão os instantâneos das primeiras horas do dia ficam registados na véspera, o que desloca a fronteira da janela num controlo ao dia.

## Configuração das opções

### Ativação da apresentação

O interruptor **Ativar a apresentação** controla a inserção da mensagem de conformidade por baixo do preço do produto. Pode desativá-lo temporariamente para manter a recolha do histórico sem mostrar a menção no front-office, o que é útil durante uma migração ou nos testes.

### Modo de cálculo

Há dois modos disponíveis:

- **Estrito**: o preço de referência é o mínimo verificado nos 30 dias que antecedem o início efetivo da promoção em curso. Corresponde à letra da diretiva.
- **Conservador** (recomendado por predefinição): o preço de referência é o mínimo dos últimos 30 dias corridos. É uma interpretação menos favorável ao comerciante, mas mais defensável numa inspeção.

**Que modo escolher?** Se a sua loja tem uma política promocional clara, com datas de início e de fim bem registadas, o modo estrito serve. Em caso de dúvida, ou se as suas regras de SpecificPrice mudam com frequência sem uma fronteira nítida entre períodos com e sem promoção, o modo conservador é mais seguro.

### Período de referência

O período está fixado em 30 dias por predefinição, em conformidade com a diretiva. Pode aumentá-lo (60 ou 90 dias) para ser ainda mais prudente, mas o valor mínimo continua a ser 30 dias.

### Exclusão dos produtos recentes

A opção **Excluir os produtos com menos de X dias** oculta a apresentação nos produtos demasiado recentes. O valor predefinido são 30 dias, o que é coerente com o espírito da diretiva, que só se aplica a produtos com um histórico de preços significativo.

### Restrição à UE

Se vende dentro e fora da UE, assinale **Restringir a apresentação à União Europeia**. O módulo deteta o país do cliente por esta ordem:

1. Morada de entrega do cliente com sessão iniciada
2. Morada do carrinho em curso
3. País predefinido da loja

Se nenhuma destas informações estiver disponível, a apresentação fica ativa por predefinição, para evitar qualquer risco de incumprimento involuntário.

Os Açores e a Madeira são território nacional e da UE: uma entrega nas ilhas está abrangida pela obrigação exatamente como uma entrega no continente. A restrição à UE destina-se a mercados fora da União, não às regiões autónomas.

### Ocultar quando o preço é igual

A opção **Ocultar se o preço for idêntico** retira a mensagem quando o preço atual corresponde exatamente ao preço mais baixo dos últimos 30 dias. É útil para não mostrar uma informação sem valor acrescentado para o consumidor.

### Desconto real

Ative **Mostrar o desconto real** para completar a mensagem com a percentagem calculada sobre o preço Omnibus, e não sobre o preço riscado. Por exemplo, um produto a 89 €, em promoção a 59 €, com um preço Omnibus de 65 €, mostra _-9,2 %_ de desconto real, em vez dos -33 % calculados sobre o preço riscado. É mais honesto, mas cada comerciante decide.

Anunciar uma percentagem calculada sobre um preço riscado que já não corresponde à realidade aproxima-se do que o Decreto-Lei n.º 57/2008 trata como prática enganosa. Se a diferença entre as duas percentagens for grande, é sinal de que o preço riscado ficou desatualizado: mostrar o desconto real é a opção mais defensável.

### Gráfico

O gráfico de 30 dias pode aparecer num separador dedicado da ficha de produto ou em linha, por baixo do preço. É carregado de forma diferida por IntersectionObserver e só é acionado quando entra no viewport, o que garante impacto nulo nos Core Web Vitals das suas fichas de produto.

### Seguimento por combinação

Assinale **Seguir as combinações** se os seus produtos tiverem preços diferentes por combinação (por exemplo, tamanhos XL com suplemento). O histórico passa então a ser segmentado por `id_product_attribute` e a menção Omnibus adapta-se ao preço da combinação selecionada.

### Retenção

A duração de conservação predefinida é de 365 dias. Depois disso, o histórico é limpo automaticamente na execução do cron. O valor mínimo é de 60 dias, para garantir margem de segurança face à janela legal de 30 dias.

Uma retenção de 365 dias é uma boa escolha: dá-lhe folga para responder a uma reclamação ou a um pedido da ASAE meses depois da campanha, sem guardar dados pessoais, já que o histórico só contém preços.

## Painel de conformidade

Acessível em **Módulos → Painel DataFirefly Omnibus**, o painel reúne:

- O número de produtos acompanhados
- O total de instantâneos registados
- A data e a hora da última passagem do cron
- A lista de produtos com, em cada um, a data da primeira captura, a data da última captura, o preço mais baixo dos últimos 30 dias e um indicador de promoção ativa

Em cada produto, há três ações disponíveis:

- **Ver o histórico**: mostra até 1000 instantâneos com data e hora
- **Instantâneo manual**: força uma captura imediata
- **Eliminar o histórico**: repõe o seguimento deste produto (a usar com prudência)

### Exportação CSV

Na vista de histórico de um produto, o botão **Exportar em CSV** gera um ficheiro com todas as colunas com data e hora (data, preço sem IVA, preço com IVA, moeda, loja, combinação, indicador de promoção e origem da captura). O formato está pronto a arquivar ou a entregar num controlo da ASAE.

## Comportamento no front-office

Na ficha de produto, assim que houver uma promoção ativa, aparece automaticamente esta menção por baixo do preço:

> Preço mais baixo dos últimos 30 dias: 65,00 €

A mensagem é traduzida segundo o idioma da loja (francês, inglês, espanhol e alemão). A apresentação usa o hook padrão `displayProductPriceBlock` e funciona com todos os temas que respeitem os padrões do PrestaShop (Classic, Hummingbird, Warehouse, Transformer e Panda).

O português não está entre os quatro idiomas fornecidos: traduza a menção em **Internacional > Traduções** antes de a ativar. Aqui, isso não é uma questão de conforto, mas de conformidade: é esta frase que cumpre a obrigação do Decreto-Lei n.º 66/2021 perante o consumidor português, e uma informação obrigatória apresentada noutra língua dificilmente será considerada prestada de forma clara e compreensível.

**Apresentação única por página:** o módulo inclui uma proteção `static $rendered`, que garante que a menção aparece apenas uma vez por página, mesmo que o hook `displayProductPriceBlock` seja chamado várias vezes (blocos de resumo, barra fixa e outros).

## Multiloja e multimoeda

O histórico é guardado por combinação única de `(id_product, id_product_attribute, id_shop, id_currency)`. Cada loja da sua instalação conserva, por isso, o seu próprio histórico, e cada moeda ativa tem a sua curva de preços. Não há conversão instantânea: os montantes apresentados correspondem exatamente ao que foi registado no momento da captura.

## Resolução de problemas

### A menção não aparece na ficha de produto

Verifique por esta ordem:

1. A opção **Ativar a apresentação** está assinalada na configuração?
2. O cron já correu pelo menos uma vez? Se não, não existe qualquer histórico.
3. A restrição à UE está ativa e está a testar a partir de um país fora da UE?
4. A opção **Ocultar se o preço for idêntico** está ativa e o preço atual corresponde ao mínimo?
5. O produto tem menos de 30 dias, com a opção de exclusão de novidades ativa?

### O gráfico não carrega

Abra a consola do navegador. O módulo espera um ponto de entrada AJAX exposto pelo controlador de front-office `pricehistory`. Confirme que nenhum sistema de cache ou firewall interceta esta rota. Se usar um CDN, autorize explicitamente os URL `/module/dfomnibus/pricehistory`.

### O cron devolve um erro 403 ou 401

O token do URL não corresponde ao registado. Volte à configuração do módulo e copie o token atual. Se suspeitar de uma fuga, clique em **Gerar novo token** e atualize o seu cron Unix.

### Erro de SQL no momento do instantâneo

Se estiver na versão 1.0.0, atualize para a 1.0.1. A versão inicial tinha um defeito em três consultas `Db::getRow()`, que acrescentavam um `LIMIT 1` manual quando o PrestaShop já acrescenta um automaticamente, produzindo um `LIMIT 1 LIMIT 1` inválido em SQL. Ver o registo de alterações.

## Perguntas frequentes

### O módulo é obrigatório para a minha loja?

Sim, se vende a consumidores estabelecidos na União Europeia e mostra preços reduzidos, promoções, códigos de desconto, saldos ou qualquer menção de redução. A obrigação aplica-se sem limiar de volume de negócios.

### Qual é a diferença face às CartRule?

O módulo acompanha apenas os preços vindos dos `SpecificPrice` do PrestaShop (descontos de produto, descontos por quantidade, descontos por grupo de clientes). As regras de carrinho (`CartRule`) aplicam-se no checkout e não alteram o preço unitário apresentado na ficha de produto, pelo que ficam fora do âmbito da diretiva.

### Como funciona exatamente o modo estrito?

O módulo procura no histórico o último instantâneo sem promoção e depois o primeiro instantâneo com promoção que se lhe segue. Essa data é o início da promoção em curso. A janela de referência passa a ser os 30 dias anteriores a essa data. Se não for possível detetar uma passagem de sem promoção para com promoção, o módulo muda automaticamente para o modo conservador.

### Posso ocultar a mensagem em certos produtos?

O módulo aplica-se globalmente, mas a opção de exclusão dos produtos recentes e a opção de ocultar quando o preço é igual cobrem a maioria dos casos em que a apresentação não traz informação útil.

### É compatível com preços com e sem IVA?

Sim. O módulo regista os dois montantes (`price_tax_excl` e `price_tax_incl`) em cada instantâneo e mostra o que a loja usa. Se mudar de um modo para o outro, o histórico continua aproveitável.

Numa loja portuguesa que vende a consumidores, o preço a apresentar é o preço com IVA: é esse que deve figurar na menção. Confirme a definição de apresentação dos preços da sua loja antes de publicar a campanha, para que o preço mais baixo indicado esteja na mesma base do preço que o cliente vê.

## Registo de alterações

### 1.0.1, 14 de maio de 2026

- Correção: remoção do `LIMIT 1` manual em três consultas `Db::getRow()`, que produziam um `LIMIT 1 LIMIT 1` inválido em SQL. Afetava a proteção de idempotência do registo e a deteção do início da promoção no modo estrito.

### 1.0.0, 14 de maio de 2026

- Lançamento inicial
- Captura automática do histórico de preços por hooks e cron diário
- Apresentação do preço mais baixo dos 30 dias na ficha de produto
- Gráfico de 30 dias em canvas nativo, com carregamento diferido e cerca de 3 KB
- Painel de conformidade com estatísticas e exportação CSV
- Modos de cálculo estrito e conservador
- Suporte de multiloja, multimoeda e multicombinação
- Restrição à UE configurável, exclusão dos produtos recentes e opção de ocultar quando o preço é idêntico
- Traduções em FR, EN, ES e DE
