GAP Detector
Documentação — Lógica do sistema

Nesta página

1. O que é um Gap? 2. Algoritmo de detecção 3. Sazonalidade por imóvel 4. Lead time 5. Matriz de urgência 6. Descontos Gapper 7. Cálculo do preço Gapper 8. min_stay travando o gap 9. Fontes de dados

📖 1. O que é um Gap?

Um gap é uma janela de 1, 2 ou 3 noites disponíveis encravada entre dois períodos ocupados ou bloqueados. Essas noites têm probabilidade muito baixa de venda ao preço normal — o hóspede precisaria encaixar exatamente o check-in e checkout entre reservas vizinhas.

A estratégia Gapper aplica um desconto pontual nessas datas para torná-las vendáveis, sem comprometer o ADR das reservas adjacentes.

Exemplo visual

QuaReserva
QuiReserva
Sex⚠ GAP
Sáb⚠ GAP
DomReserva
SegReserva
TerLivre
QuaLivre
QuiLivre

Sex-Sáb = gap de 2 noites (bounded). Ter-Qui = disponibilidade normal (não é gap — sem vizinho bloqueado na direita).

Regra: Acima de 3 noites disponíveis consecutivas, o período é disponibilidade normal e não é tratado como gap.

⚙️ 2. Algoritmo de detecção

A detecção roda sobre a tabela daily_revenue_sapron_active (Sirius/Athena). O algoritmo usa a técnica de date − row_number para agrupar dias consecutivos disponíveis:

-- Passo 1: marcar cada dia como ocupado (1) ou disponível (0) CASE WHEN blocked = true OR occupied = true THEN 1 ELSE 0 END AS ocupado -- Passo 2: agrupar sequências consecutivas de dias disponíveis -- date - row_number() é constante para dias consecutivos DATE_ADD('day', -ROW_NUMBER() OVER (PARTITION BY listing ORDER BY date), date) AS grupo_id -- Passo 3: candidatos a gap = grupos com 1, 2 ou 3 dias HAVING COUNT(*) BETWEEN 1 AND 3 -- Passo 4: bounded check — só é gap se tem vizinhos ocupados JOIN dias ant ON ant.date = first_day - 1 AND ant.ocupado = 1 JOIN dias prox ON prox.date = last_day + 1 AND prox.ocupado = 1

Critérios de inclusão

Validação: A tabela gaps.gaps_rm (GCP) contém a visão do robô de Gapper. Os resultados desta detecção podem ser comparados como sanity check, mas a lógica própria dá controle total sobre os critérios.

🌡️ 3. Sazonalidade por imóvel

Cada imóvel tem um tipo de sazonalidade registrado na rm_controle. O sistema usa esse tipo + o mês do gap para determinar em qual temporada o gap cai.

Tipos de sazonalidade

🌊 Região quente ⛰️ Região fria 📍 Não sazonal 📍 Clima-CO

Não sazonal e Clima-CO são tratados de forma idêntica — sem variação por mês.

Mapeamento mês → temporada

Tipo JanFevMarAbr MaiJunJulAgo SetOutNovDez
🌊 Quente Alta Alta Alta Média Baixa Baixa Baixa Baixa Baixa Média Média Alta
⛰️ Fria Baixa Baixa Baixa Baixa Média Alta Alta Alta Média Baixa Baixa Média
📍 Não sazonal Não sazonal — desconto fixo por lead time, sem variação mensal

⏱️ 4. Lead time

O lead time é calculado como days_until_gap = first_day − hoje. É dividido em 4 buckets:

Bucket Dias até o gap Significado
⚡ Extremamente curto 0 – 2 dias Última chance — decisão imediata
🔴 Curto 3 – 14 dias Janela de ação urgente
🟡 Médio 15 – 45 dias Ação recomendada com antecedência
⚪ Longo > 45 dias Aguardar — normalmente Ignorar

🚨 5. Matriz de urgência

A urgência combina temporada × lead time:

Temporada ↓ / Lead time → ⚡ Ext. curto
< 3 dias
🔴 Curto
3-14 dias
🟡 Médio
15-45 dias
⚪ Longo
> 45 dias
🌊⛰️ Alta temporada CRÍTICO CRÍTICO ALTO Informativo
Média temporada CRÍTICO CRÍTICO Informativo Ignorar
Baixa temporada CRÍTICO ALTO Informativo Ignorar
📍 Não sazonal ALTO ALTO Informativo Ignorar
⚠ Gaps "Ignorar" não são exibidos por padrão no dashboard. Use o filtro de urgência para visualizá-los.

💸 6. Descontos Gapper

O desconto é aplicado sobre o preço base (sem qualquer desconto de Gapper existente). A tabela abaixo define o desconto por combinação temporada × lead time:

Temporada ↓ / Lead time → ⚡ Ext. curto
< 3 dias
🔴 Curto
3-14 dias
🟡 Médio
15-45 dias
⚪ Longo
> 45 dias
Alta temporada 5% 10% 15% N/A
Média temporada 10% 15% 20% N/A
Baixa temporada 15% 20% 25% N/A
Não sazonal 10% 15% 20% N/A
Princípio: Em alta temporada o gap ainda tem valor — descontos menores. Em baixa, priorizamos ocupação sobre ADR. Os valores acima são defaults iniciais e serão refinados com análise histórica de conversão de gaps.
Robô de Gapper: Existe um robô (~3h/ciclo) que aplica descontos com thresholds estáticos. Ele é ignorado no cálculo deste sistema — o preço base sempre vem das tabelas raw (sem o desconto do robô) para garantir que o Gapper seja calculado sobre o preço original.

🧮 7. Cálculo do preço Gapper

preco_gapper = max( preco_base × (1 - desconto_matriz[temporada][lead_time]), min_price ← floor operacional )
Nota sobre disponibilidade: O preço base vem da view last_offered_raw_price (lookback de ~7 dias de atualização). Imóveis não precificados recentemente podem aparecer sem preço — nesse caso o campo fica em branco no dashboard.

🔒 8. min_stay travando o gap

Quando min_stay_vigente > gap_nights, o hóspede não consegue reservar — o sistema exige mais noites do que o gap tem. Nesse caso, o desconto de preço não resolve: a ação é reduzir o min_stay pontualmente.

SE min_stay_vigente > gap_nights: → Marcar como "gap travado" → Sugestão: reduzir min_stay para gap_nights nas datas do gap → Prioridade: verificar origin (proprietário vs sistema)
Se a regra de min_stay foi definida pelo proprietário, o alinhamento deve passar pelo anfitrião antes de qualquer alteração.

🗄️ 9. Fontes de dados

Athena
daily_revenue_sapron_active
Calendário diário por imóvel: blocked, occupied, min_stay, preço, OTA. Base da detecção de gaps.
Athena
last_offered_raw_price
Preço base por imóvel × data, sem desconto Gapper. View com lookback ~7 dias. Fonte primária para preco_base.
Athena
last_offered_price
Preço final com todos os descontos aplicados. Usado exclusivamente para min_price (floor operacional).
Athena
listing_status
Status do imóvel (Active / Inactive) e flag de churn. Usado para filtrar escopo ativo (~2.900 imóveis).
Sheets
rm_controle — Sumário ‖ Imóveis
Sazonalidade por imóvel (Região quente, Região fria, Não sazonal, Clima-CO), categoria e carteira do precificador.