# VC Digital: grade SEFIN e pedido direto de guia

## Objetivo

Documentar:

- quais campos o `sefin_browser` extrai da grade da SEFIN em `/app/consultadebitos/lista.jsp`
- como esses campos viram dados operacionais no ICMS
- quando o `app.vcnodigital.com` consegue pedir uma guia sem depender de uma ressincronização prévia da vitrine

## Resposta curta sobre o pedido direto

### Guia específica sem ressincronizar antes

Sim, é possível no fluxo atual, com estas condições:

- o contato no `app.vcnodigital.com` precisa estar vinculado ao `CNPJ` correto, ou o pedido precisa informar `cnpj/companyId`
- o pedido precisa informar pelo menos `numeroDocumento`
- para precisão máxima, o pedido deve informar também `parcela`
- se for reemissão pontual, deve informar `targetDueDate` dentro de `availableDueDates[]`

Fluxo técnico atual:

1. o app chama `POST /contacts/:contactId/fiscal-pending-documents/request-provider-artifacts`
2. o backend do app transforma isso em `guide-lifecycle job` ou `orchestrator job`
3. o ICMS recebe o job
4. o `sefin_browser` faz o claim do job
5. o desktop abre a empresa no portal da SEFIN, localiza a guia e tenta emitir/baixar
6. o resultado sobe novamente para o ICMS
7. o app reconsulta a vitrine

Importante:

- esse fluxo não depende da vitrine já estar previamente populada com aquela guia
- ele depende de o pedido ter escopo fiscal suficiente para o desktop achar a empresa e a obrigação correta

### Todas as guias do mês vigente sem ressincronizar antes

Agora existe um contrato operacional publicado de `pedido por mês` reaproveitando o mesmo endpoint do app.

Como funciona:

- o app continua chamando `POST /contacts/:contactId/fiscal-pending-documents/request-provider-artifacts`
- para descoberta mensal, envia `dueMonth` em `YYYY-MM` ou `MM/YYYY`
- o backend do app publica `DISCOVER_GUIDES` e `fetch_company_documents` com esse mesmo recorte
- o ICMS persiste `dueMonth`
- o `sefin_browser` abre a empresa/ano e filtra a grade local por `vencimento_lista` no mês pedido antes de concluir o job

Resumo:

- pedido direto de uma guia específica: `sim`
- pedido direto das guias de um mês como comando único do app: `sim`, usando `dueMonth`

## Origem dos dados

Página base:

- `https://portalcontribuinte.sefin.ro.gov.br/app/consultadebitos/lista.jsp`

Rotinas do desktop envolvidas:

- captura de screenshot bruto da lista
- leitura estruturada da grade com colunas fixas
- extração de links `DARE` e `Extrato`
- derivação de vencimento, valor, pareamento e modo fiscal

## Campos brutos extraídos da grade SEFIN

### Metadados do cabeçalho

Campos identificáveis na tela:

- `cnpj`
- `inscricao_estadual`
- `razao_social`
- `ano`
- data de impressão/atualização do documento

Metadados auxiliares capturados pelo desktop:

- `url`
- `titulo`
- `coletado_em`
- `lista_screenshot_path` local

Observação:

- o screenshot bruto da lista é capturado localmente pelo desktop
- ele serve como auditoria visual local
- hoje o contrato público do ICMS para o app deve consumir primeiro os campos estruturados, não o print

### Colunas estruturadas por linha

Parser de grade do desktop reconhece estas colunas:

- `dare`
- `extrato`
- `nr_lancamento`
- `parcela`
- `referencia`
- `complemento`
- `receita`
- `situacao`
- `data_vencimento`
- `valor_lancamento`
- `data_atualizacao`
- `valor_atualizado`

### Links e identificadores capturados

Por linha, o desktop também deriva:

- `dare_href`
- `extrato_href`
- `guia_candidates[]`
- `numero_documento`

## Campos operacionais derivados pelo desktop

Depois de ler a grade, o `sefin_browser` monta um job local com estes campos:

- `guia`
- `parc`
- `reference_year`
- `vencimento_lista`
- `vencimentos_disponiveis`
- `vencimento_escolhido`
- `datas_marcadas`
- `datas_emitidas`
- `recalculo_aplicado`
- `row_signature_text`
- `extrato_mode`
- `extrato_expected`
- `dare_self_contained`
- `guide_content_fingerprint`
- `extrato_fingerprint`
- `extrato_refresh_reason`
- `dare_pdf`
- `extrato_pdf`
- `extrato_json`
- `extrato_screenshot`
- `valor_lancado`
- `valor_total`

## Semântica importante

### `dare_self_contained`

Quando `true`:

- a própria guia já contém as informações complementares suficientes
- o app não deve ficar esperando `extrato` separado para liberar o envio

### `extrato_mode`

Valores operacionais típicos:

- `separate`
- `embedded_in_dare`
- `reused`
- `unknown`

### `extrato_reusable`

Quando o pareamento indicar reutilização:

- o extrato pode continuar válido para a mesma família fiscal
- a guia pode vencer e ser recalculada sem exigir novo extrato em todos os casos

## Como isso aparece no ICMS SaaS

O ICMS transforma o scrape e os artefatos emitidos em campos públicos de API.

Campos principais entregues ao app:

- `numeroDocumento`
- `parcela`
- `dueDate`
- `dueDateReal`
- `displayDueDate`
- `displayDueDateLabel`
- `showVencimentoOriginal`
- `dueDatePresentation`
- `dueDateSource`
- `vencimentoOriginal`
- `vencimentoEmitido`
- `availableDueDates[]`
- `valorTotal`
- `recalculada`
- `extratoMode`
- `extratoExpected`
- `dareSelfContained`
- `extratoReusable`
- `guideContentFingerprint`
- `extratoFingerprint`
- `extratoRefreshReason`
- `workflowStatus`
- `delivery`
- `documents[]`
- `auditArtifacts[]`

## Contrato mensal publicado

Payload mínimo para descoberta por mês:

```json
{
  "controladoraId": 1,
  "cnpj": "34754978000160",
  "dueMonth": "2026-04",
  "year": 2026,
  "requestedBy": "VC Digital",
  "priority": 85
}
```

Regras:

- `dueMonth` aceita `YYYY-MM` ou `MM/YYYY`
- o ano operacional passa a ser o próprio ano de `dueMonth`
- o recorte mensal só vale para jobs de empresa, não para reemissão pontual por `numeroDocumento`
- se houver `dueMonth`, o ICMS não bloqueia o job com `already_fresh` por uma sincronização genérica do mesmo dia
- a consulta de jobs também aceita `GET /api/internal/guide-lifecycle/jobs?dueMonth=2026-04`
- a consulta de jobs também aceita `GET /api/internal/orchestrator/jobs?dueMonth=2026-04`

## Regras para o app consumir corretamente

### Nova guia

Se entrar uma nova guia no ICMS:

- consumir pelo endpoint principal
- usar `numeroDocumento + parcela + documentType` como chave fiscal
- substituir o arquivo anterior se vier `artifactId` mais novo

### Guia vencida

Se a guia estiver vencida:

- consultar primeiro `due-options`
- usar apenas datas presentes em `availableDueDates[]`
- depois pedir a emissão pontual

### Guia sem extrato separado

Se `dareSelfContained = true` ou `extratoExpected = false`:

- o app não deve bloquear a vitrine pedindo extrato
- o DARE já é o documento fiscal suficiente naquele contexto

## Endpoints relevantes

### Leitura da vitrine fiscal

- `GET /api/internal/fiscal-documents`

### Datas reais disponíveis na SEFIN

- `GET /api/internal/fiscal-documents/due-options`

### Pedido direto ao desktop

- `POST /api/internal/guide-lifecycle/jobs`
- `POST /api/internal/orchestrator/jobs`

### Acompanhamento do job

- `GET /api/internal/guide-lifecycle/jobs`
- `GET /api/internal/orchestrator/jobs`
- `POST /api/internal/guide-lifecycle/jobs/heartbeat`
- `POST /api/internal/orchestrator/jobs/heartbeat`

## Payload recomendado para guia específica

```json
{
  "controladoraId": "1",
  "jobType": "EMIT_GUIDE",
  "companyId": 97,
  "cnpj": "34754978000160",
  "ie": "00000000285056",
  "numeroDocumento": "20261200124319",
  "parcela": "00",
  "year": 2026,
  "priority": 85,
  "requestedBy": "VC Digital",
  "source": "vcnodigital",
  "notes": "Pedido direto sem depender de ressincronizacao previa da vitrine."
}
```

## Payload recomendado para reemissão pontual com nova data

```json
{
  "controladoraId": "1",
  "jobType": "RECALCULATE_GUIDE",
  "companyId": 97,
  "cnpj": "34754978000160",
  "ie": "00000000285056",
  "numeroDocumento": "20261200124319",
  "parcela": "00",
  "targetDueDate": "2026-04-30",
  "forceRefresh": true,
  "consumeAvailableDueDates": true,
  "priority": 90,
  "requestedBy": "VC Digital",
  "source": "vcnodigital"
}
```

## Observação sobre screenshot da lista

Status atual:

- o desktop já captura `lista_screenshot`
- o contrato principal recomendado para o app continua sendo a leitura estruturada da grade e dos artefatos emitidos
- se o ecossistema quiser publicar o screenshot bruto da lista no futuro, o nome recomendado é `lista_debitos_screenshot`
- esse screenshot deve ser tratado como auditoria visual, não como fonte principal de consumo

## Resultado esperado para o ecossistema

Com esse contrato, os três blocos passam a conversar melhor:

- `sefin_browser` descobre e emite
- `icms.vcnodigital.com` normaliza e publica
- `app.vcnodigital.com` consome sem depender de interpretação manual da tela

Isso ajuda a identificar:

- novos boletos/guias
- pendências vencidas
- guias recalculadas
- casos em que não existe extrato separado
- diferenças entre `vencimentoOriginal` e `vencimentoEmitido`
- status de importação e entrega final ao cliente
