> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fire.rest/llms.txt
> Use this file to discover all available pages before exploring further.

# store.business_day_closed

> Uma loja fechou seu dia de negócio — um evento thin com a identidade do fechamento, timing, quem fechou e uma ref mínima de loja.

<Tabs>
  <Tab title="v1 · current">
    Você está vendo o contrato **atual (v1)** de `store.business_day_closed` — um **payload thin**: identidade do fechamento, timing, `closedBy` e uma **`store` mínima**. Já não carrega as métricas agregadas do dia, os breakdowns nem o detalhe de anomalias — isso você consulta por `businessDayId` quando precisar.
  </Tab>

  <Tab title="v0 · deprecated">
    <Warning>O contrato **v0** (o snapshot completo com `sales`/`metrics`/breakdowns embutidos) está **deprecado** — mantido apenas como referência histórica. Abra aqui: [store.business\_day\_closed — v0](/pt/events-v0/store-day-closed).</Warning>
  </Tab>
</Tabs>

`store.business_day_closed` dispara quando o pipeline automático de fechamento de dia do Fire termina de construir o snapshot imutável do dia operacional de uma loja. O payload é **thin**: carrega a **identidade** do fechamento (`businessDayId`), o **timing**, **quem fechou** e uma **ref mínima de loja** — o suficiente para reagir a "o dia fechou" e fazer o match do seu lado. Os agregados pesados (vendas, métricas, breakdowns por canal/pagamento, detalhe de force-closed e cancelamentos) vivem no snapshot e são obtidos por `businessDayId` — **não** vêm embutidos no evento.

Diferente dos eventos a nível pedido, este é um evento **a nível loja**: um por loja fechada, não um por pedido.

## Condição de disparo

O Fire emite `store.business_day_closed` uma vez por snapshot `(storeId, businessDayDate)`, na primeira vez que **tudo** a seguir é verdadeiro:

* A loja tinha um dia de negócio aberto (`isBusinessDayOpen === true`) para a data sendo fechada
* O pipeline de fechamento (`CloseBusinessDayService.execute()`) completou todos os passos sem erro (force-close, cálculo de métricas, persistência do snapshot)
* Não existe já um snapshot para esse par `(storeId, businessDayDate)` (guard de idempotência)

|                             |                                                                       |
| --------------------------- | --------------------------------------------------------------------- |
| Cobertura                   | **Universal** — todos os países. Sem gating por país.                 |
| Chave de idempotência       | `event.id` (também `trigger.data.businessDayId`)                      |
| Dispara mais de uma vez     | Não, salvo retentativa. Um snapshot por (storeId, data).              |
| Origem                      | Pipeline cron (v1). O fechamento manual ainda não emite.              |
| Latência vs fechamento real | Síncrono — o evento é enfileirado assim que `saveSnapshot()` retorna. |

## O que vem em `trigger.data`

Um payload **thin**: identidade (`businessDayId`, `businessDayDate`, `timezone`, `status`), timing (`openedAt`, `closedAt`), o `closedBy` resolvido, e uma ref mínima de `store` (`uid`, `code`, `externalId`, `countryCode`, `timezone`, `currencyCode`). Sem métricas, breakdowns nem arrays de anomalias — consulte o snapshot por `businessDayId` se precisar do detalhe.

## Exemplo — payload real (sanitizado)

```json theme={null}
{
  "event": {
    "id": "43214dd1-e260-4245-945d-5bbdfc4a54be",
    "type": "store.business_day_closed",
    "createdAt": "2026-05-18T21:59:01.306Z"
  },
  "data": {
    "businessDayId": "2c332116-79ec-4c63-a53d-8b87fff5a654",
    "businessDayDate": "2026-03-31",
    "timezone": "America/Sao_Paulo",
    "status": "CLOSED",
    "openedAt": "2026-03-31T09:00:02.55Z",
    "closedAt": "2026-05-18T21:58:09.882Z",
    "closedBy": {
      "uid": "00000000-0000-0000-0000-000000000000",
      "name": "Cierre Automático — Sandbox",
      "type": "system"
    },
    "store": {
      "uid": "a4019cad-bbac-4269-9f8d-f29654e92c45",
      "code": "BR-SP-001",
      "externalId": "200400500",
      "countryCode": "BR",
      "timezone": "America/Sao_Paulo",
      "currencyCode": "BRL"
    }
  },
  "_meta": { "executionId": "...", "flowId": "...", "flowName": "...", "attempt": 0, "triggerEntityId": "2c332116-79ec-4c63-a53d-8b87fff5a654" }
}
```

## Referência de `data.*`

### Identidade e temporal

<ResponseField name="businessDayId" type="string">
  UUID do snapshot de dia de negócio persistido na base do Fire. Também aparece como `_meta.triggerEntityId`. Use-o como chave de idempotência do seu lado — reenvios do mesmo fechamento compartilham o mesmo `businessDayId` — e como chave de lookup para buscar os agregados do dia na API de snapshots do Fire quando precisar.
</ResponseField>

<ResponseField name="businessDayDate" type="string">
  Data de calendário que o fechamento representa, no fuso da loja (ex. `"2026-03-31"`). **Não** a data UTC em que o evento disparou.
</ResponseField>

<ResponseField name="timezone" type="string">
  Fuso IANA da loja (ex. `"America/Sao_Paulo"`). Use-o para interpretar `businessDayDate`.
</ResponseField>

<ResponseField name="status" type="string">
  Sempre `"CLOSED"` para este evento. Nenhum outro valor é possível.
</ResponseField>

<ResponseField name="openedAt" type="string | null">
  Timestamp ISO 8601 UTC de abertura do dia. Pode ser `null` para lojas que nunca abriram explicitamente (dados legados); para lojas fechadas por cron v1 está sempre presente.
</ResponseField>

<ResponseField name="closedAt" type="string">
  Timestamp ISO 8601 UTC em que o pipeline persistiu o snapshot. Use-o para medir SLI/SLO em vez de `event.createdAt` (que é o momento do dispatch da fila).
</ResponseField>

### `closedBy` — identidade do operador

<ResponseField name="closedBy" type="object">
  Identidade do operador já resolvida. **Sem lookups em runtime downstream.**

  <Expandable title="closedBy">
    <ResponseField name="uid" type="string">
      Para `type: "system"` (v1): o UUID `accounts.id` (ou um nil UUID estável `"00000000-0000-0000-0000-000000000000"` para contas sem system-user configurado). Para `type: "user"` (v2, ainda não emitido): o UUID do usuário na tabela de auth do Fire.
    </ResponseField>

    <ResponseField name="name" type="string">
      Label legível. Para system: tipicamente `"Cierre Automático — {accountName}"`. Para user: o display name do usuário.
    </ResponseField>

    <ResponseField name="type" type="string">
      `"system"` para fechamentos automáticos por cron (v1). `"user"` fica reservado para fechamentos manuais (v2, não implementado).
    </ResponseField>
  </Expandable>
</ResponseField>

### `store` — ref mínima de loja

<ResponseField name="store" type="object">
  Uma referência mínima de loja — identidade mais país/fuso/moeda. O bloco store canônico completo (name, address, vendor, account, fiscal config) **não** vem aqui; se precisar, pegue-o dos eventos [`order.completed`](/pt/events/order-completed#store) da mesma loja.

  <Expandable title="store">
    <ResponseField name="uid" type="string | null">UUID da loja no Fire.</ResponseField>
    <ResponseField name="code" type="string | null">Código legível da loja (ex. `"BR-SP-001"`).</ResponseField>
    <ResponseField name="externalId" type="string | null">O identificador externo controlado pelo Fire (`settings.externalId`), não o que algum POS injetou. Use-o como chave de reconciliação do seu lado.</ResponseField>
    <ResponseField name="countryCode" type="string | null">Código de país ISO da loja (ex. `"BR"`).</ResponseField>
    <ResponseField name="timezone" type="string | null">Fuso IANA da loja. Espelha `data.timezone`.</ResponseField>
    <ResponseField name="currencyCode" type="string | null">Código de moeda ISO 4217 da loja (ex. `"BRL"`).</ResponseField>
  </Expandable>
</ResponseField>

## Exemplo de handler

```js theme={null}
async function onStoreDayClosed(data) {
  const { businessDayId, businessDayDate, timezone, store, closedBy } = data;

  // 1. Idempotência — pular se já processamos este fechamento
  const existing = await db.dayCloses.findUnique({ where: { businessDayId } });
  if (existing) return;

  // 2. Registrar o fechamento (lean — identidade + ref de loja)
  await db.dayCloses.create({
    data: {
      businessDayId,
      businessDayDate,
      timezone,
      storeExternalId: store.externalId,
      storeCode: store.code,
      countryCode: store.countryCode,
      currencyCode: store.currencyCode,
      closedByName: closedBy.name,
      closedByType: closedBy.type,
    },
  });

  // 3. Precisa dos agregados do dia (sales, metrics, anomalias)? Busque por businessDayId.
  //    NÃO estão neste evento — consulte a API de snapshots do Fire on demand.
  // const snapshot = await fire.businessDay.get(businessDayId);
}
```

## Erros comuns

* **As métricas do dia NÃO estão neste evento.** `sales`, `metrics`, `byChannel`, `byPaymentMethod`, `forceClosedOrders`, `closureStats`, `cancelledOrders` e `metadata` já não viajam inline. Se você dependia deles, busque o snapshot por `businessDayId`.
* **`snapshotId` foi renomeado para `businessDayId`.** Se você parseava `data.snapshotId`, mude para `data.businessDayId` (mesmo valor — o id da linha do snapshot).
* **`closedBy.uid` pode ser o nil UUID `"00000000-0000-0000-0000-000000000000"`** — em fechamentos system onde a conta não configurou um system user. Detecte fechamentos system com `closedBy.type === "system"`, não parseando o `uid`.
* **`businessDayDate` é a data de calendário da loja, não UTC.** Interprete-a com `timezone`.
* **Os campos `store.*` podem ser `null`** com configuração de loja incompleta. Não assuma non-null.

## Eventos relacionados

<CardGroup cols={2}>
  <Card title="order.completed" icon="receipt" href="/pt/events/order-completed">
    Dispara por cada pedido ao completar. O bloco store completo vive aqui.
  </Card>

  <Card title="order.cancelled" icon="circle-xmark" href="/pt/events/order-cancelled">
    Evento por cancelamento. Use-o para o detalhe de cancelamentos em vez do payload de fechamento.
  </Card>
</CardGroup>
