Appearance
Regras de Lojas & Aliases
Estrutura de lojas
Cada organização tem várias lojas/filiais. Uma loja pode ter:
- Número de WhatsApp associado (
StoreWhatsappNumber) - Caixa no Chatwoot (
chatwootInboxId) - Horários de funcionamento (
businessHours) - Flag de e-commerce (
isEcommerce) - Código do ERP (
code)
Hierarquia de aliases
Lojas podem ser agrupadas em hierarquia de principal/alias:
Loja Principal (primaryStoreId = null)
├─ Alias 1 (primaryStoreId = Loja Principal)
└─ Alias 2 (primaryStoreId = Loja Principal)Uso: Franquias ou filiais que reportam métricas consolidadas para a loja principal.
Regras:
- Sem chains: A → B, mas B não pode apontar para C
- Sem auto-referência
- Alias herda dados de relatório da principal
Endpoints: /config/store-aliases (permissão: app:store-aliases)
Loja e-commerce
A loja marcada com isEcommerce = true é o fallback padrão quando:
- Cliente não tem loja preferida E não responde ao menu
- Loja preferida não tem instância Evolution conectada
- Roteamento WABA sem caixa específica configurada
Somente uma loja por organização pode ser e-commerce (toggle PATCH /settings/stores/:id/ecommerce).
Resolução de alias
O StoreAliasResolverService tem cache de 60s e oferece:
| Método | Descrição |
|---|---|
expandStoreIds(ids) | Expande array de IDs de lojas para incluir seus aliases |
resolvePrimary(storeId) | Retorna o ID da loja principal para um alias |
getPrimaryMap() | Mapa completo de alias → principal |
Útil para queries de analytics — buscar dados de todas as filiais ao consultar a principal.
Loja preferida do cliente
Customer.preferredStoreId é atribuído de três formas:
- Pelo roteador: quando o cliente seleciona no menu
- Pelo sync ERP: via
PreferredAssignmentService(loja do vendedor que mais vendeu para o cliente) - Manualmente: via
PATCH /erp/customers/:id/preferences
Horários de funcionamento
Estrutura salva em Store.businessHours (campo JSON):
json
{
"schedule": {
"monday": { "active": true, "open": "09:00", "close": "18:00" },
"tuesday": { "active": true, "open": "09:00", "close": "18:00" },
"wednesday": { "active": true, "open": "09:00", "close": "18:00" },
"thursday": { "active": true, "open": "09:00", "close": "18:00" },
"friday": { "active": true, "open": "09:00", "close": "17:00" },
"saturday": { "active": true, "open": "09:00", "close": "13:00" },
"sunday": { "active": false, "open": "00:00", "close": "00:00" }
}
}Timezone: BRT (UTC-3) — hardcoded, sem DST desde 2019.
Loja sem configuração = sempre aberta.
Turno overnight: Suportado (ex: "open": "23:40", "close": "00:30").
Ao salvar: Flags Redis de business hours são limpas imediatamente para reprocessamento.
Cálculos de horário
O BusinessHoursService oferece:
| Método | Retorno |
|---|---|
isOpen(businessHours) | boolean — loja aberta agora? |
minutesUntilClose(businessHours) | number? — minutos até fechar |
minutesSinceClose(businessHours) | number? — minutos desde o fechamento |
todayCloseTime(businessHours) | string? — horário de fechamento hoje (HH:MM) |
formatHours(businessHours) | string — texto legível (ex: "Seg 09:00–18:00") |
Instâncias WhatsApp por loja
StoreWhatsappNumber vincula uma loja a um número de WhatsApp:
| Campo | Descrição |
|---|---|
phoneNumberId | ID do número no Meta (WABA mode) |
wabaId | ID da conta WABA |
accessToken | Token de acesso Meta (criptografado) |
provider | evolution ou meta_cloud |
evolutionInstanceName | Nome da instância Evolution (se provider = evolution) |
chatwootInboxId | ID da caixa no Chatwoot |
messagingLimitTier | Tier atual de envio |
qualityScore | Score de qualidade da conta Meta |
isDefault | Se é a instância padrão da loja |