926 lines
32 KiB
Markdown
926 lines
32 KiB
Markdown
# PRD — Comparador de Notas
|
||
|
||
**Versão:** 1.6
|
||
**Data:** 02/03/2026
|
||
**Status:** Planejamento
|
||
|
||
---
|
||
|
||
# 1. Visão Geral
|
||
|
||
## 1.1 Nome do Produto
|
||
|
||
Comparador de Notas
|
||
|
||
## 1.2 Descrição
|
||
|
||
Software desktop multiplataforma destinado à análise de sequências numéricas de notas fiscais (ou documentos equivalentes) a partir da importação de planilhas.
|
||
|
||
O sistema identifica quebras de sequência, duplicidades e inconsistências, além de calcular totais financeiros, permitindo auditoria rápida e confiável.
|
||
|
||
O software deve ser configurável para suportar diferentes formatos de planilhas sem depender de um layout fixo.
|
||
|
||
---
|
||
|
||
# 2. Problema
|
||
|
||
Muitos sistemas legados não fornecem ferramentas adequadas para validação da sequência de notas fiscais.
|
||
|
||
Como consequência, usuários precisam criar controles manuais em planilhas para:
|
||
|
||
* Detectar notas faltantes
|
||
* Conferir integridade da sequência
|
||
* Somar valores
|
||
* Separar por série
|
||
|
||
Esse processo é:
|
||
|
||
* Manual
|
||
* Repetitivo
|
||
* Suscetível a erro humano
|
||
* Ineficiente
|
||
|
||
O produto elimina esse processo manual.
|
||
|
||
---
|
||
|
||
# 3. Objetivos
|
||
|
||
## 3.1 Objetivo Principal
|
||
|
||
Permitir que o usuário importe uma planilha e obtenha automaticamente:
|
||
|
||
* Notas faltantes
|
||
* Notas duplicadas
|
||
* Soma total dos valores
|
||
* Agrupamento por série
|
||
|
||
## 3.2 Objetivos Secundários
|
||
|
||
* Permitir configuração flexível das colunas
|
||
* Permitir reutilização de configurações (presets)
|
||
* Reduzir tempo de auditoria
|
||
* Reduzir erros humanos
|
||
|
||
---
|
||
|
||
# 4. Escopo
|
||
|
||
## 4.1 Incluído
|
||
|
||
* Importação de arquivos CSV
|
||
* Importação de arquivos XLSX
|
||
* Interface gráfica
|
||
* Configuração de colunas (CSV por índice numérico; XLSX por letra+linha)
|
||
* Detecção de quebras de sequência
|
||
* Detecção de duplicidades
|
||
* Soma de valores
|
||
* Agrupamento por série
|
||
* Relatório visual com paginação
|
||
* Exportação de relatório para PDF
|
||
* Salvar layouts personalizados (exclusivos por tipo de arquivo)
|
||
* Carregar layouts salvos
|
||
* Selecionar layout por menu dropdown
|
||
* Excluir layouts
|
||
* Exportar layout para JSON
|
||
* Importar layout de JSON
|
||
|
||
## 4.2 Não Incluído (MVP)
|
||
|
||
* Integração com ERP
|
||
* Integração com banco de dados externo
|
||
* Multiusuário
|
||
* Acesso remoto
|
||
|
||
---
|
||
|
||
# 5. Modelo de Dados
|
||
|
||
O sistema trabalhará com os seguintes campos lógicos:
|
||
|
||
| Campo | Obrigatório | Descrição |
|
||
| ------ | ----------- | ------------------------------------------------------------------------- |
|
||
| Numero | Sim | Número incremental da nota. Junto com a Série forma o identificador único. Armazenado internamente como `u64`. |
|
||
| Serie | Sim | Série da nota. Deve conter de 1 a 3 dígitos numéricos (regex: `[0-9]{1,3}`, ex: `1`, `01`, `001`). Separa lotes de emissão. |
|
||
| Valor | Não | Valor monetário da nota. Armazenado internamente como decimal fixo (`rust_decimal`). |
|
||
| Data | Não | Data de emissão da nota. Quando mapeado, exibido como informação adicional no relatório PDF. Não participa de nenhuma regra de validação ou cálculo. |
|
||
|
||
Os campos serão mapeados pelo usuário conforme o tipo de arquivo: via **índice numérico** (base 0) para CSV, e via **notação LetraLinha** (ex: `B3`) para XLSX.
|
||
|
||
> **Identificador único de uma nota:** combinação de `Numero + Serie`. Duplicidade e sequência são sempre avaliadas dentro da mesma série.
|
||
|
||
---
|
||
|
||
# 6. Requisitos Funcionais
|
||
|
||
## RF01 — Importação de Arquivo
|
||
|
||
O sistema deve permitir importar arquivos:
|
||
|
||
* CSV
|
||
* XLSX
|
||
|
||
### RF01.1 — Configurações de Importação CSV
|
||
|
||
| Parâmetro | Comportamento |
|
||
| ----------------- | ----------------------------------------------------------------------------- |
|
||
| Delimitador | Configurável pelo usuário: vírgula, ponto e vírgula ou tabulação |
|
||
| Encoding | Suportados: UTF-8 e Windows-1252 (Latin-1). Configurável pelo usuário |
|
||
| Linha do cabeçalho| Configurável pelo usuário (pode estar na linha 1, 4, etc.) |
|
||
| Linhas em branco | Devem ser ignoradas silenciosamente |
|
||
| Linhas malformadas| Devem ser ignoradas; o sistema deve reportar ao usuário quais linhas foram descartadas, sem interromper a importação |
|
||
|
||
### RF01.2 — Configurações de Importação XLSX
|
||
|
||
| Parâmetro | Comportamento |
|
||
| ---------------------- | -------------------------------------------------------------------------------------------------- |
|
||
| Seleção de aba | Imediatamente após a seleção do arquivo, o sistema exibe a lista de abas disponíveis para o usuário selecionar, antes de qualquer configuração de campos |
|
||
| Coluna e linha de início | O usuário informa a posição inicial de cada campo no formato `LetraLinha` (ex: `B3`) |
|
||
| Linhas em branco | Devem ser ignoradas silenciosamente |
|
||
| Linhas malformadas | Devem ser ignoradas; o sistema deve reportar ao usuário quais linhas foram descartadas |
|
||
| Arquivo corrompido | Se o arquivo não puder ser lido, exibir mensagem de erro em modal e limpar o arquivo carregado; o estado anterior é descartado |
|
||
|
||
### RF01.3 — Limite de Tamanho de Arquivo
|
||
|
||
O sistema deve recusar arquivos maiores que **50 MB** e exibir mensagem de erro ao usuário.
|
||
|
||
> O limite refere-se ao **tamanho do arquivo no disco** (tamanho comprimido para XLSX, que é um arquivo ZIP internamente). Base de cálculo: 100.000 registros com 5–10 colunas geram aproximadamente 5–15 MB em CSV e até 30 MB em XLSX. O limite de 50 MB oferece margem adequada.
|
||
|
||
---
|
||
|
||
## RF02 — Configuração de Colunas
|
||
|
||
O mapeamento de colunas varia conforme o tipo de arquivo.
|
||
|
||
### RF02.1 — Mapeamento CSV (índice numérico)
|
||
|
||
O usuário define, via **índice numérico** (posição da coluna, base 0), qual coluna representa cada campo:
|
||
|
||
* Qual índice representa o número (obrigatório)
|
||
* Qual índice representa a série (obrigatório)
|
||
* Qual índice representa o valor (opcional)
|
||
* Qual índice representa a data (opcional)
|
||
|
||
### RF02.2 — Mapeamento XLSX (letra + linha)
|
||
|
||
O usuário define, no formato `LetraLinha`, a posição inicial de cada campo na planilha:
|
||
|
||
* Ex: `B3` indica coluna B a partir da linha 3
|
||
* Os campos mapeáveis são os mesmos: Numero (obrigatório), Serie (obrigatório), Valor (opcional) e Data (opcional)
|
||
|
||
> A linha informada é a **linha de início dos dados** (não o cabeçalho). O cabeçalho, se existir, é a linha imediatamente anterior.
|
||
|
||
### Comportamento de Memória
|
||
|
||
Após a importação, o arquivo permanece em memória e o usuário pode alterar o mapeamento de colunas e reprocessar sem selecionar o arquivo novamente. Ao importar um novo arquivo, os dados do arquivo anterior são descartados da memória.
|
||
|
||
### Tratamento de Erros de Configuração
|
||
|
||
| Situação | Comportamento |
|
||
| ----------------------------------------------------------- | ---------------------------------------------------------------- |
|
||
| Índice/posição configurado não existe no arquivo importado | Exibir erro ao usuário identificando qual campo está inválido |
|
||
| Campo obrigatório (Numero ou Serie) não mapeado | Bloquear execução da análise e solicitar configuração |
|
||
| Campo opcional não mapeado | Ignorar o campo; funcionalidades dependentes ficam desabilitadas |
|
||
| Dois campos mapeados para o mesmo índice/posição | Bloquear e exibir erro de validação imediatamente, antes de executar a análise |
|
||
|
||
---
|
||
|
||
## RF03 — Presets
|
||
|
||
O sistema deve permitir:
|
||
|
||
* Salvar configurações (armazenadas internamente via SQLite)
|
||
* Carregar configurações existentes
|
||
* Exportar um layout para arquivo JSON
|
||
* Importar um layout a partir de arquivo JSON
|
||
|
||
O formato JSON é utilizado exclusivamente para importação e exportação de layouts entre dispositivos ou sistemas.
|
||
|
||
O armazenamento interno dos layouts é realizado via SQLite (ver Seção 10).
|
||
|
||
### Tipo de Layout
|
||
|
||
Cada layout é exclusivo de um tipo de arquivo: **CSV** ou **XLSX**. Um layout CSV armazena configurações específicas de CSV (delimitador, encoding, índices de coluna). Um layout XLSX armazena configurações específicas de XLSX (aba, posições no formato `LetraLinha`).
|
||
|
||
### Conflito ao Importar Layout JSON
|
||
|
||
Se o usuário importar um arquivo JSON com o nome de um layout já existente no banco, o sistema deve perguntar ao usuário o que fazer, oferecendo as opções:
|
||
|
||
* Sobrescrever o layout existente
|
||
* Salvar com novo nome
|
||
|
||
### Erros na Importação de Layout JSON
|
||
|
||
Se o arquivo JSON estiver malformado ou com campos obrigatórios ausentes, o sistema deve exibir mensagem de erro descrevendo o problema e cancelar a importação. Nenhum dado parcial deve ser salvo.
|
||
|
||
### Nome do Arquivo ao Exportar Layout
|
||
|
||
Ao exportar um layout para JSON, o sistema deve sugerir o nome do arquivo com base no nome do layout (ex: layout `Padrão CSV` → `Padrão CSV.json`). O usuário pode alterar o nome antes de salvar.
|
||
|
||
### Limite de Layouts
|
||
|
||
Não há limite no número de layouts que podem ser armazenados.
|
||
|
||
---
|
||
|
||
## RF04 — Detecção de Sequência
|
||
|
||
O sistema deve:
|
||
|
||
* Ordenar os registros por número dentro de cada série
|
||
* Detectar números faltantes na sequência
|
||
|
||
### Regra de Detecção
|
||
|
||
A sequência é avaliada entre o **menor** e o **maior** número encontrado dentro de cada série. Qualquer número ausente nesse intervalo é considerado faltante.
|
||
|
||
Exemplo: série 001 contém os números `0001, 0002, 0003, 0005` → `0004` está faltando.
|
||
|
||
### Tratamento de Valores Não Numéricos
|
||
|
||
Se o valor de um campo Numero não for numérico (ex: `NF-001`, `ABC`):
|
||
|
||
1. O sistema deve tentar extrair apenas os dígitos do valor (ex: `NF-001` → `1`)
|
||
2. Se após a extração restar um número válido, utilizá-lo
|
||
3. Se não restar valor numérico utilizável, descartar o registro
|
||
4. Em ambos os casos, reportar ao usuário quais registros foram afetados
|
||
|
||
### Número Zero
|
||
|
||
Registros com o campo Numero igual a `0` devem ser descartados e reportados ao usuário. O valor `0` não é considerado um número de nota válido.
|
||
|
||
### Escopo da Detecção
|
||
|
||
Faltantes são detectados **por série**. Cada série possui sua própria sequência independente.
|
||
|
||
### Série com Apenas um Registro
|
||
|
||
Se uma série contiver apenas um registro, o intervalo de sequência é `numero..numero`. Não há faltantes nesse caso. A série é processada e exibida normalmente.
|
||
|
||
### Ordenação
|
||
|
||
A ordenação dos registros dentro de cada série é sempre **numérica crescente**, independentemente do formato original do campo Numero no arquivo de entrada.
|
||
|
||
### Exibição do Campo Numero
|
||
|
||
O campo Numero é armazenado e processado como inteiro. Na exibição (listas de faltantes, duplicatas e relatório PDF), o número é exibido **sem zeros à esquerda** (ex: `0001` é exibido como `1`). O formato de exibição não altera a lógica de detecção ou ordenação.
|
||
|
||
### Proteção contra Intervalos Anormalmente Grandes
|
||
|
||
Se o intervalo de faltantes de qualquer série exceder **10.000 registros**, o sistema deve:
|
||
|
||
1. Interromper o processamento dessa série
|
||
2. Exibir aviso informando o intervalo calculado (ex: "Série 001: intervalo de 999.996 faltantes detectado")
|
||
3. Solicitar confirmação do usuário antes de continuar
|
||
|
||
Se o usuário confirmar, o sistema deve listar todos os faltantes normalmente, com paginação. Não há truncamento da lista após a confirmação.
|
||
|
||
Esse comportamento protege contra mapeamentos incorretos de colunas que gerariam listas ilegíveis.
|
||
|
||
### Tratamento de Série com Valor Inválido
|
||
|
||
A Série é válida se e somente se corresponder à regex `[0-9]{1,3}` após remoção de espaços.
|
||
|
||
Se o campo Série de um registro estiver vazio, não corresponder à regex ou contiver valor não utilizável:
|
||
|
||
1. O registro deve ser descartado
|
||
2. O sistema deve reportar ao usuário quais linhas foram afetadas, sem interromper a importação
|
||
|
||
Exemplos de valores inválidos: `ABC`, `1A`, `1234` (4 dígitos), string vazia.
|
||
|
||
---
|
||
|
||
## RF05 — Detecção de Duplicidade
|
||
|
||
O sistema deve identificar registros duplicados.
|
||
|
||
Um registro é considerado duplicado quando existe mais de uma ocorrência da mesma combinação **Numero + Serie** no arquivo importado.
|
||
|
||
### Exibição das Duplicatas
|
||
|
||
A lista de duplicatas exibe o identificador (Numero + Serie) e a contagem de ocorrências por grupo. Exemplo: `NF 0004 / Série 001 — 3 ocorrências`. As ocorrências individuais não são listadas separadamente.
|
||
|
||
### Impacto na Soma de Valores
|
||
|
||
Todas as ocorrências de registros duplicados são incluídas na soma de valores, pois refletem os lançamentos reais presentes no arquivo.
|
||
|
||
---
|
||
|
||
## RF06 — Soma de Valores
|
||
|
||
O sistema deve calcular:
|
||
|
||
* Soma total
|
||
* Soma por série
|
||
|
||
### Formato de Valor Aceito
|
||
|
||
O sistema deve aceitar valores numéricos em formato brasileiro ou americano, detectando o formato automaticamente por registro seguindo o algoritmo abaixo.
|
||
|
||
#### Algoritmo de Parsing Monetário
|
||
|
||
**Regra 1 — Contém ambos ponto e vírgula:**
|
||
- O último separador encontrado é o decimal; o outro é o separador de milhar.
|
||
- Exemplos: `1.000,00` → 1.000,00 | `1,000.00` → 1.000,00
|
||
|
||
**Regra 2 — Contém apenas um separador:**
|
||
- Vírgula ou ponto com **exatamente 2 dígitos** após → separador decimal.
|
||
- Exemplos: `1000,00` → 1.000,00 | `1000.00` → 1.000,00
|
||
- Vírgula ou ponto com **exatamente 3 dígitos** após → separador de milhar.
|
||
- Exemplos: `1,234` → 1.234,00 | `1.234` → 1.234,00
|
||
- Demais casos → separador tratado como decimal.
|
||
|
||
**Regra 3 — Sem separador:**
|
||
- Interpretar como número inteiro.
|
||
- Exemplo: `1000` → 1.000,00
|
||
|
||
| Exemplo de entrada | Regra aplicada | Resultado parseado |
|
||
| ------------------ | ---------------------------------- | ------------------ |
|
||
| `1000.00` | Regra 2 (ponto + 2 dígitos) | 1.000,00 |
|
||
| `1000,00` | Regra 2 (vírgula + 2 dígitos) | 1.000,00 |
|
||
| `1.000,00` | Regra 1 (ambos separadores) | 1.000,00 |
|
||
| `1,000.00` | Regra 1 (ambos separadores) | 1.000,00 |
|
||
| `1.000` | Regra 2 (ponto + 3 dígitos) | 1.000,00 |
|
||
| `1,234` | Regra 2 (vírgula + 3 dígitos) | 1.234,00 |
|
||
| `1000` | Regra 3 (sem separador) | 1.000,00 |
|
||
|
||
Valores negativos (precedidos de `-`) devem ser rejeitados e reportados ao usuário como inválidos.
|
||
|
||
Valores que não puderem ser interpretados como número devem ser descartados e reportados ao usuário.
|
||
|
||
> **Nota de implementação:** O valor deve ser parseado e armazenado internamente como `rust_decimal::Decimal`, nunca como `f64`. Aritmética de ponto flutuante introduz erros de representação em valores monetários (ex: `0.1 + 0.2 ≠ 0.3` em IEEE 754). A soma total e as somas por série devem ser calculadas inteiramente em `Decimal`.
|
||
|
||
### Formato de Exibição de Valores
|
||
|
||
Todos os valores monetários são exibidos com **2 casas decimais fixas** no formato brasileiro (ex: `1.234,56`).
|
||
|
||
---
|
||
|
||
## RF07 — Exibição de Resultados
|
||
|
||
O sistema deve exibir:
|
||
|
||
* Lista de notas faltantes agrupadas por série
|
||
* Lista de duplicadas agrupadas por série
|
||
* Totais (soma total e soma por série)
|
||
|
||
### Organização dos Resultados
|
||
|
||
| Aspecto | Comportamento |
|
||
| ------------- | ----------------------------------------------------- |
|
||
| Agrupamento | Resultados sempre agrupados por série |
|
||
| Listas longas | Paginação — o usuário navega entre páginas de resultados |
|
||
| Itens por página | Selecionável via dropdown com as opções: 50, 100, 200, 1000 |
|
||
|
||
### RF07.1 — Exportação de Relatório
|
||
|
||
O sistema deve permitir exportar o relatório de resultados para **PDF** utilizando a biblioteca `genpdf`.
|
||
|
||
O PDF deve conter:
|
||
* Notas faltantes por série
|
||
* Duplicatas por série
|
||
* Totais por série e total geral
|
||
|
||
**Metadados do relatório:**
|
||
* Nome do arquivo importado
|
||
* Data e hora da geração
|
||
* Nome do layout utilizado
|
||
|
||
---
|
||
|
||
## RF08 — Gerenciamento de Layouts
|
||
|
||
* O sistema deve permitir salvar layouts personalizados.
|
||
* O sistema deve permitir listar layouts salvos.
|
||
* O sistema deve permitir selecionar layouts salvos.
|
||
* O sistema deve permitir excluir layouts.
|
||
* Os layouts devem ser armazenados localmente via SQLite.
|
||
|
||
> A exibição dos resultados de análise é coberta pelo RF07.
|
||
|
||
---
|
||
|
||
# 7. Requisitos Não Funcionais
|
||
|
||
## RNF01 — Plataforma
|
||
|
||
O sistema deve funcionar em:
|
||
|
||
* Windows
|
||
* Linux
|
||
* macOS
|
||
|
||
---
|
||
|
||
## RNF02 — Execução Offline
|
||
|
||
O sistema deve funcionar sem conexão com internet.
|
||
|
||
---
|
||
|
||
## RNF03 — Performance
|
||
|
||
O sistema deve suportar no mínimo:
|
||
|
||
100.000 registros por arquivo
|
||
|
||
> **Nota de implementação:** A detecção de faltantes deve ser implementada de forma **incremental** — ordenar a lista e percorrer comparando elementos consecutivos — evitando a geração de listas intermediárias completas antes da confirmação do usuário. Isso garante consumo de memória proporcional aos dados reais, não ao intervalo.
|
||
|
||
---
|
||
|
||
## RNF04 — Usabilidade
|
||
|
||
O sistema deve possuir interface simples.
|
||
|
||
---
|
||
|
||
## RNF05 — Idioma
|
||
|
||
O idioma da interface é **Português do Brasil (PT-BR)**.
|
||
|
||
---
|
||
|
||
## RNF06 — Mensagens de Erro e Aviso
|
||
|
||
Todas as mensagens de erro e aviso devem ser exibidas em **modal/popup bloqueante**. O usuário deve fechar o modal explicitamente para continuar.
|
||
|
||
### Consolidação de Mensagens
|
||
|
||
Quando múltiplos avisos forem gerados durante uma mesma operação (ex: múltiplas linhas malformadas, múltiplos registros descartados), esses avisos devem ser **consolidados em um único modal**, exibindo um resumo ao final da operação. Exemplo de conteúdo consolidado:
|
||
|
||
* "32 linhas descartadas por mal formação"
|
||
* "12 valores de Numero inválidos convertidos ou descartados"
|
||
* "5 registros com Série inválida descartados"
|
||
|
||
Cada categoria de problema deve ser exibida como um item separado dentro do mesmo modal. Nunca devem ser abertos múltiplos modais sequenciais para a mesma operação de importação.
|
||
|
||
---
|
||
|
||
# 8. Fluxo do Usuário
|
||
|
||
Fluxo principal:
|
||
|
||
1. Usuário abre o sistema
|
||
2. Usuário importa planilha
|
||
3. Usuário configura colunas
|
||
4. Usuário executa análise
|
||
5. Sistema exibe resultado
|
||
|
||
---
|
||
|
||
# 9. Arquitetura
|
||
|
||
Arquitetura desktop local com separação em quatro camadas: `domain`, `application`, `infrastructure` e `ui`.
|
||
|
||
Não é Clean Architecture radical. É apenas separação suficiente para manter fronteiras claras, domínio isolado e infraestrutura concreta sem vazar para a lógica de negócio.
|
||
|
||
---
|
||
|
||
## 9.1 Estrutura de Pastas
|
||
|
||
```
|
||
src/
|
||
├─ main.rs
|
||
├─ ui/
|
||
│ ├─ mod.rs
|
||
│ ├─ app.rs
|
||
│ ├─ screens/
|
||
│ │ ├─ import.rs
|
||
│ │ ├─ configuracao_colunas.rs
|
||
│ │ ├─ layouts.rs
|
||
│ │ ├─ resultado.rs
|
||
│
|
||
├─ application/
|
||
│ ├─ mod.rs
|
||
│ ├─ usecases/
|
||
│ │ ├─ importar_arquivo.rs
|
||
│ │ ├─ executar_analise.rs
|
||
│ │ ├─ exportar_pdf.rs
|
||
│
|
||
├─ domain/
|
||
│ ├─ mod.rs
|
||
│ ├─ errors.rs
|
||
│ ├─ entities/
|
||
│ │ ├─ nota.rs
|
||
│ │ ├─ serie.rs
|
||
│ │ ├─ layout.rs
|
||
│ │ ├─ resultado_analise.rs
|
||
│ │
|
||
│ ├─ services/
|
||
│ │ ├─ detector_sequencia.rs
|
||
│ │ ├─ detector_duplicidade.rs
|
||
│ │ ├─ parser_monetario.rs
|
||
│
|
||
├─ infrastructure/
|
||
│ ├─ mod.rs
|
||
│ ├─ csv_reader.rs
|
||
│ ├─ xlsx_reader.rs
|
||
│ ├─ pdf_generator.rs
|
||
│ ├─ sqlite/
|
||
│ │ ├─ mod.rs
|
||
│ │ ├─ connection.rs
|
||
│ │ ├─ migrations.rs
|
||
│ │ ├─ layout_repository.rs
|
||
```
|
||
|
||
---
|
||
|
||
## 9.2 Papel de Cada Camada
|
||
|
||
### Domain (núcleo puro)
|
||
|
||
Contém toda a lógica de negócio real.
|
||
|
||
**Não pode depender de:**
|
||
|
||
* egui
|
||
* rusqlite
|
||
* calamine
|
||
* csv
|
||
* genpdf
|
||
|
||
Apenas Rust puro + crates matemáticas (`rust_decimal`, `chrono`).
|
||
|
||
#### Entidades
|
||
|
||
**`Nota`**
|
||
|
||
| Campo | Tipo |
|
||
| ------ | ----------------- |
|
||
| numero | `u64` |
|
||
| serie | `String` |
|
||
| valor | `Option<Decimal>` |
|
||
| data | `Option<NaiveDate>` |
|
||
|
||
**`ResultadoAnalise`**
|
||
|
||
| Campo | Tipo |
|
||
| -------------------- | -------------------------------------- |
|
||
| faltantes_por_serie | `HashMap<String, Vec<u64>>` |
|
||
| duplicadas_por_serie | `HashMap<String, Vec<(u64, usize)>>` |
|
||
| soma_total | `Decimal` |
|
||
| soma_por_serie | `HashMap<String, Decimal>` |
|
||
|
||
> **Importante:** a geração dos faltantes não deve ser eager. O use case `executar_analise` deve primeiro calcular os intervalos por série e retornar um resultado intermediário (`ResultadoPreAnalise`) contendo o intervalo calculado. Somente após confirmação do usuário — quando algum intervalo exceder 10.000 registros (RF04) — o sistema expande e materializa a lista completa de faltantes. Isso evita alocar memória para intervalos gerados por mapeamento incorreto de colunas.
|
||
|
||
#### Services
|
||
|
||
`detector_sequencia` — recebe `Vec<Nota>` agrupadas por série, retorna faltantes.
|
||
|
||
`detector_duplicidade` — retorna mapa de contagem por `(numero, serie)`.
|
||
|
||
`parser_monetario` — implementa exatamente o algoritmo definido no RF06.
|
||
|
||
#### Erros
|
||
|
||
`domain/errors.rs` define os erros do domínio de forma tipada (ex: `ErroSerie::Invalida`, `ErroNumero::Zero`, `ErroValor::Negativo`). Nenhuma camada deve propagar `String` livre como erro de domínio.
|
||
|
||
---
|
||
|
||
### Application (orquestração)
|
||
|
||
Coordenam o fluxo entre domain e infrastructure.
|
||
|
||
Conhece o domain. O domain não conhece o application.
|
||
|
||
**`executar_analise.rs`**
|
||
|
||
1. Recebe dados crus
|
||
2. Chama `parser_monetario`
|
||
3. Chama `detector_sequencia`
|
||
4. Chama `detector_duplicidade`
|
||
5. Monta `ResultadoAnalise`
|
||
|
||
**`exportar_pdf.rs`**
|
||
|
||
Depende de uma trait abstrata (`PdfGenerator`) definida no próprio módulo application. A implementação concreta fica em `infrastructure/pdf_generator.rs`. Isso evita que o application dependa diretamente de `genpdf`.
|
||
|
||
---
|
||
|
||
### Infrastructure (implementações concretas)
|
||
|
||
Implementa leitores, persistência e geração de arquivos.
|
||
|
||
| Arquivo | Responsabilidade |
|
||
| -------------------------------- | ----------------------------------------- |
|
||
| `csv_reader.rs` | Leitura de arquivos CSV via `csv` |
|
||
| `xlsx_reader.rs` | Leitura de arquivos XLSX via `calamine` |
|
||
| `pdf_generator.rs` | Geração de PDF via `genpdf` |
|
||
| `sqlite/connection.rs` | Abertura e inicialização da conexão SQLite |
|
||
| `sqlite/migrations.rs` | Aplicação de migrations de schema |
|
||
| `sqlite/layout_repository.rs` | CRUD de layouts via `rusqlite` |
|
||
|
||
Nada de infrastructure sobe para domain.
|
||
|
||
#### Por que `layout_repository.rs` dentro de `sqlite/`
|
||
|
||
Manter o repositório dentro de `sqlite/` concentra todos os artefatos SQLite em um único módulo. Se futuramente o sistema armazenar histórico de análises ou configurações do usuário (RF14/10.8), novos repositórios são adicionados no mesmo lugar sem dispersão.
|
||
|
||
---
|
||
|
||
### UI (interface)
|
||
|
||
Apenas coleta input, chama use cases e renderiza resultado.
|
||
|
||
Nenhuma regra de sequência ou parsing monetário deve estar na camada de UI.
|
||
|
||
#### Screens
|
||
|
||
| Arquivo | Responsabilidade |
|
||
| ------------------------- | ----------------------------------------------------- |
|
||
| `import.rs` | Seleção de arquivo e configurações de importação |
|
||
| `configuracao_colunas.rs` | Mapeamento de colunas (RF02) |
|
||
| `layouts.rs` | Gerenciamento de layouts: salvar, carregar, excluir (RF08) |
|
||
| `resultado.rs` | Exibição de resultados com paginação (RF07) |
|
||
|
||
> `configuracao_colunas.rs` e `layouts.rs` são mantidos separados porque tratam de responsabilidades distintas do RF02 e RF08, evitando que uma única screen acumule lógica de mapeamento de colunas e gerenciamento de persistência.
|
||
|
||
---
|
||
|
||
## 9.3 Fluxo de Execução
|
||
|
||
```
|
||
UI → Application → Domain
|
||
Infrastructure entra apenas quando necessário.
|
||
```
|
||
|
||
Exemplo real:
|
||
|
||
1. UI chama `importar_arquivo`
|
||
2. Infrastructure lê CSV/XLSX
|
||
3. Application transforma registros em entidades `Nota`
|
||
4. Domain executa análise
|
||
5. Application retorna `ResultadoAnalise`
|
||
6. UI renderiza
|
||
|
||
---
|
||
|
||
## 9.4 Stack Tecnológica
|
||
|
||
| Camada | Tecnologia | Status |
|
||
| ---------------- | ------------------ | -------------- |
|
||
| Linguagem | Rust | Definido |
|
||
| Framework de UI | egui | Definido |
|
||
| SQLite | rusqlite | Definido |
|
||
| Leitura de CSV | csv | Definido |
|
||
| Leitura de XLSX | calamine | Definido |
|
||
| Decimal fixo | rust_decimal | Definido |
|
||
| Geração de PDF | genpdf | Definido |
|
||
|
||
---
|
||
|
||
# 10. Persistência de Dados
|
||
|
||
## 10.1 Visão Geral
|
||
|
||
O sistema deve possuir mecanismo de persistência de dados local para
|
||
armazenamento de layouts criados pelo usuário.
|
||
|
||
Esse mecanismo deve permitir que o usuário salve, carregue, selecione e
|
||
exclua layouts sem a necessidade de importar arquivos de configuração
|
||
manualmente.
|
||
|
||
------------------------------------------------------------------------
|
||
|
||
## 10.2 Tecnologia
|
||
|
||
O sistema deve utilizar banco de dados local SQLite.
|
||
|
||
Motivos:
|
||
|
||
- Não requer servidor
|
||
- Funciona offline
|
||
- Arquivo único
|
||
- Multiplataforma
|
||
- Alta confiabilidade
|
||
|
||
O banco de dados deve ser armazenado na **pasta de dados do usuário**, de acordo com o sistema operacional:
|
||
|
||
| Sistema Operacional | Caminho |
|
||
| ------------------- | ---------------------------------------------------- |
|
||
| Linux | `~/.config/comparador-notas/config.db` |
|
||
| Windows | `%APPDATA%\comparador-notas\config.db` |
|
||
| macOS | `~/Library/Application Support/comparador-notas/config.db` |
|
||
|
||
O diretório e o arquivo devem ser **criados automaticamente** pelo sistema na primeira execução.
|
||
|
||
------------------------------------------------------------------------
|
||
|
||
## 10.2.1 — Banco de Dados Corrompido
|
||
|
||
Se o arquivo `config.db` estiver ilegível ou corrompido ao iniciar o programa, o sistema deve:
|
||
|
||
1. Exibir aviso ao usuário informando que o banco de dados está corrompido e será recriado
|
||
2. Renomear o arquivo corrompido para `config.db.bak` (sobrescrevendo qualquer `.bak` anterior)
|
||
3. Criar um novo banco de dados vazio
|
||
4. Continuar a execução normalmente
|
||
|
||
Os layouts salvos anteriormente serão perdidos neste cenário. O arquivo `config.db.bak` permanece no disco e permite recuperação manual por usuários avançados.
|
||
|
||
------------------------------------------------------------------------
|
||
|
||
## 10.2.2 — Migração de Schema
|
||
|
||
O banco de dados deve conter uma tabela de controle de versão (`schema_version`) com o número da versão atual do schema. A cada inicialização, o sistema deve verificar a versão e aplicar migrations automáticas quando necessário, garantindo compatibilidade com versões anteriores do banco.
|
||
|
||
------------------------------------------------------------------------
|
||
|
||
## 10.3 Dados Armazenados
|
||
|
||
O sistema deve armazenar:
|
||
|
||
Layouts personalizados
|
||
|
||
------------------------------------------------------------------------
|
||
|
||
## 10.4 Entidade: Layout
|
||
|
||
Cada layout é exclusivo de um tipo de arquivo (`csv` ou `xlsx`). As configurações variam conforme o tipo.
|
||
|
||
**Campos comuns:**
|
||
|
||
| Campo | Tipo | Descrição |
|
||
| ---------- | ------- | -------------------------------------- |
|
||
| id | inteiro | Identificador único |
|
||
| nome | texto | Nome do layout |
|
||
| tipo | texto | Tipo do arquivo: `csv` ou `xlsx` |
|
||
|
||
**Campos exclusivos de layouts CSV:**
|
||
|
||
| Campo | Tipo | Descrição |
|
||
| ------------------ | ------ | -------------------------------------------------- |
|
||
| delimitador | texto | Caractere delimitador (`,`, `;`, `\t`) |
|
||
| encoding | texto | Encoding do arquivo (`utf-8` ou `windows-1252`) |
|
||
| linha_cabecalho | inteiro | Número da linha do cabeçalho (base 1) |
|
||
| indice_numero | inteiro | Índice da coluna Numero (base 0) |
|
||
| indice_serie | inteiro | Índice da coluna Serie (base 0) |
|
||
| indice_valor | inteiro | Índice da coluna Valor (base 0, nulo se ausente) |
|
||
| indice_data | inteiro | Índice da coluna Data (base 0, nulo se ausente) |
|
||
|
||
**Campos exclusivos de layouts XLSX:**
|
||
|
||
| Campo | Tipo | Descrição |
|
||
| -------------- | ------ | ---------------------------------------------------------------- |
|
||
| aba | texto | Nome ou índice da aba a ser processada |
|
||
| pos_numero | texto | Posição inicial da coluna Numero no formato `LetraLinha` (ex: `D3`) |
|
||
| pos_serie | texto | Posição inicial da coluna Serie no formato `LetraLinha` (ex: `B3`) |
|
||
| pos_valor | texto | Posição inicial da coluna Valor (nulo se ausente) |
|
||
| pos_data | texto | Posição inicial da coluna Data (nulo se ausente) |
|
||
|
||
------------------------------------------------------------------------
|
||
|
||
## 10.5 Requisitos Funcionais Relacionados
|
||
|
||
O sistema deve permitir:
|
||
|
||
Salvar layout
|
||
|
||
Listar layouts
|
||
|
||
Selecionar layout
|
||
|
||
Excluir layout
|
||
|
||
------------------------------------------------------------------------
|
||
|
||
## 10.6 Interface do Usuário
|
||
|
||
Os layouts salvos devem ser exibidos em um menu dropdown.
|
||
|
||
O usuário deve poder:
|
||
|
||
Selecionar layout existente
|
||
|
||
Criar novo layout
|
||
|
||
Excluir layout
|
||
|
||
------------------------------------------------------------------------
|
||
|
||
## 10.7 Requisitos Não Funcionais
|
||
|
||
O banco de dados deve:
|
||
|
||
Funcionar offline
|
||
|
||
Não depender de serviços externos
|
||
|
||
Não exigir configuração manual
|
||
|
||
Ser criado automaticamente pelo sistema
|
||
|
||
------------------------------------------------------------------------
|
||
|
||
## 10.8 Futuras Expansões
|
||
|
||
O banco de dados poderá armazenar futuramente:
|
||
|
||
Histórico de análises
|
||
|
||
Relatórios
|
||
|
||
Configurações do usuário
|
||
|
||
|
||
# 11. Formato de Configuração (Import/Export)
|
||
|
||
Quando o usuário exportar ou importar um layout, o arquivo gerado será no formato JSON.
|
||
|
||
Esse formato é usado apenas para portabilidade entre dispositivos.
|
||
O armazenamento interno é sempre via SQLite.
|
||
|
||
O campo `tipo` define qual conjunto de configurações está presente no arquivo.
|
||
|
||
**Exemplo — layout CSV:**
|
||
|
||
```json
|
||
{
|
||
"nome": "Layout Padrão CSV",
|
||
"tipo": "csv",
|
||
"delimitador": ";",
|
||
"encoding": "utf-8",
|
||
"linha_cabecalho": 1,
|
||
"indice_numero": 3,
|
||
"indice_serie": 1,
|
||
"indice_valor": 5,
|
||
"indice_data": null
|
||
}
|
||
```
|
||
|
||
**Exemplo — layout XLSX:**
|
||
|
||
```json
|
||
{
|
||
"nome": "Layout Padrão XLSX",
|
||
"tipo": "xlsx",
|
||
"aba": "Plan1",
|
||
"pos_numero": "D3",
|
||
"pos_serie": "B3",
|
||
"pos_valor": "F3",
|
||
"pos_data": null
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
# 12. Critérios de Aceite
|
||
|
||
O sistema será considerado funcional quando:
|
||
|
||
* Importar planilha CSV com configurações de delimitador, encoding e linha de cabeçalho
|
||
* Importar planilha XLSX com seleção de aba e posicionamento por `LetraLinha`
|
||
* Detectar notas faltantes por série corretamente
|
||
* Detectar duplicatas por série corretamente
|
||
* Calcular soma total e soma por série corretamente
|
||
* Exibir resultados agrupados por série com paginação
|
||
* Exportar relatório de resultados para PDF
|
||
* Salvar, carregar, selecionar e excluir layouts
|
||
* Exportar e importar layouts via JSON
|
||
* Exibir aviso de confirmação quando intervalo de faltantes exceder 10.000 por série
|
||
|
||
---
|
||
|
||
# 13. MVP — Versão Inicial
|
||
|
||
O MVP inclui o escopo completo descrito neste PRD:
|
||
|
||
* Importar CSV e XLSX
|
||
* Mapear colunas Numero, Serie, Valor e Data
|
||
* Detectar notas faltantes por série
|
||
* Detectar duplicatas por série
|
||
* Calcular soma total e por série
|
||
* Exibir resultados agrupados por série com paginação
|
||
* Exportar relatório para PDF
|
||
* Gerenciar layouts (salvar, carregar, excluir)
|
||
* Exportar e importar layouts via JSON
|
||
|
||
---
|
||
|
||
# 14. Evoluções Futuras
|
||
|
||
Possíveis melhorias:
|
||
|
||
* Integração com ERP
|
||
* Histórico de análises
|
||
* Automação de importação (monitorar pasta)
|
||
* Exportação para CSV
|
||
* Multiusuário
|
||
|
||
---
|
||
|
||
# 15. Definições
|
||
|
||
Nota
|
||
|
||
Documento com número sequencial.
|
||
|
||
Série
|
||
|
||
Agrupador independente de sequência.
|
||
|
||
Sequência
|
||
|
||
Ordem numérica crescente sem lacunas.
|
||
|
||
---
|