{/* PLANO-NFSE.mdx — Plano de Implementação da NFS-e Avulsa (Release 1) */}
NFS-e Avulsa — Plano de Implementação
Visão Geral
Nova funcionalidade no Módulo Fiscal da SMB Store para emissão manual de Notas Fiscais de Serviço Eletrônicas (NFSe). O prestador seleciona um tomador, adiciona serviços, preenche dados fiscais e transmite a nota à prefeitura — tudo dentro do sistema.
Estado atual: o Módulo Fiscal suporta apenas NFe e NFCe (produtos). Esta release adiciona cobertura para serviços.
Integração: API Focus NFe — endpoints /v2/nfse (próprio) e /v2/nfsen (nacional).
Arquitetura de Referência do Codebase
| Camada | Padrão Atual | Arquivos-chave |
|---|---|---|
| API Focus | Factory + Contracts (third_party/NotaFiscal/) | Notafiscal.php, CreateNfe.php, CancelNfe.php |
| Controllers | CodeIgniter + Ws.php como hub de operações | Ws.php, Nfes_manual.php, Dados_fiscais_v.php |
| Models | Generic_model com enums internos | Notas_fiscais_model.php, Empresa_model.php |
| Helpers | Funções procedurais por domínio | my_nota_fiscal_helper.php, my_webhook_nfe_helper.php |
| Frontend | Vue 3 (Composition API) + Mixins + Materialize CSS | DadosFiscaisController_v.js, Mixin_nota_fiscal.js |
| Permissões | Constantes no Permissao_model (430–433 usados) | Permissao_model.php |
| Rotas | routes.php + controllers nomeados | $route['nfes-manual/(:num)'] |
Mapeamento de Ambiente — API Focus
O campo nac do endpoint de municípios da Focus determina o cenário:
Regra MEI: empresas com regime tributário MEI (código 4) obrigatoriamente usam Ambiente Nacional, independente da configuração.
Seleção de Ambiente pelo Usuário
Na tela de Dados Fiscais, um dropdown permite escolher:
| Opção | Flags na API de Empresas Focus | Endpoint de emissão |
|---|---|---|
| Ambiente Nacional | habilita_nfsen_producao: true, habilita_nfse: false | /v2/nfsen |
| Ambiente Próprio | habilita_nfsen_producao: false, habilita_nfse: true | /v2/nfse |
Para municípios com
nac: proxy, mesmo selecionando "Ambiente Próprio", o endpoint correto é/v2/nfsen. O sistema deve resolver isso automaticamente.
Fase 1 — Configuração e Cadastros
Entrega: A empresa está configurada para emitir NFSe. Serviços e clientes possuem dados fiscais completos. Permissões estão ativas.
1.1 Estrutura de Dados Base
Escopo: Migrações de banco, models, enums, constantes de permissão. Pré-requisito para tudo.
Novas colunas — tabela empresas
| Coluna | Tipo | Descrição |
|---|---|---|
ativar_nfse | tinyint(1) default 0 | Switch habilitar NFSe |
is_nfse_prod | tinyint(1) default 0 | Ambiente: 0=homolog, 1=prod |
nfse_ambiente | enum('nacional','proprio') | Tipo de ambiente |
inscricao_municipal | varchar(30) | Inscrição municipal |
nfse_numero_rps | int unsigned | Próximo número RPS |
nfse_login_prefeitura | varchar(100) | Login prefeitura |
nfse_senha_prefeitura | text | Senha prefeitura (encriptada) |
nfse_codigo_ibge | varchar(7) | Código IBGE do município |
nfse_info_adicionais | text | Informações adicionais padrão |
Novas colunas — tabela notas_fiscais
| Coluna | Tipo | Descrição |
|---|---|---|
nfse_numero | varchar(20) | Número oficial da NFSe |
nfse_numero_rps | int | Número RPS usado |
nfse_codigo_verificacao | varchar(50) | Código de verificação |
nfse_url | text | URL da nota na prefeitura |
xml_nfse | longtext | XML armazenado localmente |
nfse_natureza_operacao | tinyint | Enum 1–6 |
nfse_regime_tributacao | tinyint | Enum 1–6 |
nfse_data_competencia | date | Data de competência |
nfse_discriminacao | text | Discriminação dos serviços |
nfse_substituida_id | int unsigned null | FK nota substituída |
nfse_valor_pis | decimal(15,2) | Retenção PIS |
nfse_valor_cofins | decimal(15,2) | Retenção COFINS |
nfse_valor_ir | decimal(15,2) | Retenção IR |
nfse_valor_csll | decimal(15,2) | Retenção CSLL |
nfse_valor_inss | decimal(15,2) | Retenção INSS |
nfse_valor_iss | decimal(15,2) | Valor ISS |
nfse_valor_iss_retido | decimal(15,2) | ISS retido |
Novas colunas — tabela nota_fiscal_itens
| Coluna | Tipo | Descrição |
|---|---|---|
servico_codigo_lc116 | varchar(10) | Código LC 116 |
servico_cnae | varchar(10) | CNAE |
servico_codigo_tributario_municipio | varchar(20) | CTM |
servico_aliquota_iss | decimal(5,2) | Alíquota ISS |
servico_iss_retido | tinyint(1) default 0 | ISS retido |
servico_descricao_manual | text | Descrição (serviço manual) |
is_servico_manual | tinyint(1) default 0 | Flag serviço avulso |
Novas colunas — tabela produtos
| Coluna | Tipo | Descrição |
|---|---|---|
servico_codigo_lc116 | varchar(10) | Código LC 116 |
servico_cnae | varchar(10) | CNAE |
servico_codigo_tributario_municipio | varchar(20) | CTM |
servico_aliquota_iss | decimal(5,2) | Alíquota ISS |
servico_iss_retido | tinyint(1) default 0 | ISS retido |
servico_nbs | varchar(20) | NBS |
servico_reter_pis | tinyint(1) default 0 | Reter PIS |
servico_reter_cofins | tinyint(1) default 0 | Reter COFINS |
servico_reter_ir | tinyint(1) default 0 | Reter IR |
servico_reter_csll | tinyint(1) default 0 | Reter CSLL |
servico_reter_inss | tinyint(1) default 0 | Reter INSS |
Novas colunas — tabela clientes
| Coluna | Tipo | Descrição |
|---|---|---|
codigo_ibge_municipio | varchar(7) | Código IBGE do município |
Nova tabela — servicos_lc116
| Coluna | Tipo |
|---|---|
id | int PK auto_increment |
codigo | varchar(10) unique |
descricao | text |
Nova tabela — municipios_nfse
| Coluna | Tipo |
|---|---|
id | int PK auto_increment |
codigo_municipio | varchar(7) unique |
nome_municipio | varchar(100) |
sigla_uf | char(2) |
nfse_habilitada | tinyint(1) |
requer_certificado_nfse | tinyint(1) |
possui_ambiente_homologacao_nfse | tinyint(1) |
possui_cancelamento_nfse | tinyint(1) |
provedor_nfse | varchar(50) |
codigo_cnae_obrigatorio_nfse | tinyint(1) null |
item_lista_servico_obrigatorio_nfse | tinyint(1) null |
codigo_tributario_municipio_obrigatorio_nfse | tinyint(1) null |
status_nfse | varchar(20) |
nac | enum('none','proxy','oficial') |
atualizado_em | datetime |
Colunas reservadas — Reforma Tributária (IBS/CBS)
Adicionar nas tabelas notas_fiscais e nota_fiscal_itens sem lógica:
| Coluna | Tipo |
|---|---|
ibs_valor | decimal(15,2) null |
cbs_valor | decimal(15,2) null |
Enums
1class NfseNaturezaOperacaoEnum {
2 const TRIBUTACAO_MUNICIPIO = 1;
3 const TRIBUTACAO_FORA_MUNICIPIO = 2;
4 const ISENCAO = 3;
5 const IMUNE = 4;
6 const EXIGIBILIDADE_SUSPENSA_JUDICIAL = 5;
7 const EXIGIBILIDADE_SUSPENSA_ADMINISTRATIVA = 6;
8}
9
10class NfseRegimeTributacaoEnum {
11 const MICROEMPRESA_MUNICIPAL = 1;
12 const ESTIMATIVA = 2;
13 const SOCIEDADE_PROFISSIONAIS = 3;
14 const COOPERATIVA = 4;
15 const MEI_SIMPLES_NACIONAL = 5;
16 const ME_EPP_SIMPLES_NACIONAL = 6;
17}Adicionar alias NFSE = 'nfse' no NotaFiscalTipoEnum.
Adicionar status SUBSTITUIDO = '7' no NotaFiscalStatusEnum.
Constantes de Permissão
1const PERMISSAO_EMITIR_NFSE = 435;
2const PERMISSAO_CANCELAR_NFSE = 436;
3const PERMISSAO_GERENCIAR_CONF_NFSE = 437;1.2 Configuração NFSe da Empresa
Escopo: Backend + Frontend para a tela de Dados Fiscais.
Wireframe — Seção NFSe em Dados Fiscais
1┌─────────────────────────────────────────────────────────────────┐
2│ DADOS FISCAIS DA EMPRESA │
3│ ┌──────────┬──────────────┬───────────────┬──────────────────┐ │
4│ │ Empresa │ Config Notas │ Certificado │ Backup Fiscal │ │
5│ └──────────┴──────────────┴───────────────┴──────────────────┘ │
6│ │
7│ ═══ Configuração de Notas ═══ │
8│ │
9│ --- NFe / NFCe (existente) --- │
10│ [campos existentes...] │
11│ │
12│ ─── NFS-e ─────────────────────────────────────────────────── │
13│ │
14│ ┌───────────────────────────────────────────────┐ │
15│ │ Habilitar emissão de NFSe [ OFF ] │ │
16│ └───────────────────────────────────────────────┘ │
17│ │
18│ ▼ (campos visíveis somente com switch ON) │
19│ │
20│ ┌─────────────────────────┐ ┌──────────────────────────────┐ │
21│ │ Inscrição Municipal │ │ Número Inicial do RPS │ │
22│ │ [________________] │ │ [________] │ │
23│ │ Máx 30 chars, numérico │ │ Inteiro positivo, mín 1 │ │
24│ └─────────────────────────┘ └──────────────────────────────┘ │
25│ │
26│ ┌──────────────────────────────────────────────┐ │
27│ │ Município (Código IBGE) │ │
28│ │ [🔍 Buscar município...__________________ ] │ │
29│ │ Autocomplete via cache de municípios Focus │ │
30│ └──────────────────────────────────────────────┘ │
31│ │
32│ ┌─────────────────────────┐ ┌──────────────────────────────┐ │
33│ │ Ambiente de Emissão │ │ Tipo de Ambiente │ │
34│ │ [▾ Homologação ] │ │ [▾ Ambiente Próprio ] │ │
35│ │ Homologação / Produção │ │ Nacional / Próprio │ │
36│ └─────────────────────────┘ └──────────────────────────────┘ │
37│ │
38│ ─── Dados para Autenticação ─── │
39│ │
40│ ┌─────────────────────────┐ ┌──────────────────────────────┐ │
41│ │ Login da Prefeitura │ │ Senha da Prefeitura │ │
42│ │ [________________] │ │ [********] 👁 │ │
43│ │ Opcional (máx 100) │ │ Opcional (máx 100, mascarado)│ │
44│ └─────────────────────────┘ └──────────────────────────────┘ │
45│ │
46│ ┌──────────────────────────────────────────────────────────┐ │
47│ │ Informações Adicionais Padrão │ │
48│ │ [ ] │ │
49│ │ [ ] │ │
50│ └──────────────────────────────────────────────────────────┘ │
51│ │
52│ ⚠ Município sem homologação: "O município configurado não │
53│ possui ambiente de homologação. Notas em modo teste serão │
54│ transmitidas para produção." │
55│ │
56│ [ Salvar Configuração ] │
57└─────────────────────────────────────────────────────────────────┘Fluxo de preenchimento do Código IBGE
Validações
- Ativar switch: Inscrição Municipal deve estar preenchida. Caso contrário, alerta com link.
- Número RPS: inteiro positivo, mínimo 1, obrigatório.
- Senha da prefeitura: encriptada no backend antes de persistir.
- Ambiente: seleção dispara
UpdateCompanyna Focus com flags corretas.
Backend
- Endpoints em
Ws.php:set/salvar_config_nfse,get/config_nfse - Validação em
my_nfse_helper.php:validar_empresa_nfse() - Encriptação da senha via helper existente do CodeIgniter
Frontend
- Nova seção no
DadosFiscaisController_v.js - Novo mixin
Mixin_nfse.jscom métodos de API - Campos condicionais vinculados ao switch
ativar_nfse
1.3 Catálogo LC 116 e Dados Fiscais do Serviço
Escopo: Seed da LC 116, autocomplete, aba fiscal no cadastro de serviço.
Wireframe — Aba Dados Fiscais do Serviço
1┌────────────────────────────────────────────────────────────┐
2│ CADASTRO DE PRODUTO/SERVIÇO │
3│ ┌──────────┬──────────────┬──────────────┐ │
4│ │ Geral │ Preços │ Dados Fiscais│ ← Nova aba │
5│ └──────────┴──────────────┴──────────────┘ │
6│ │
7│ (Aba visível APENAS se Tipo = Serviço E Módulo Fiscal ON) │
8│ │
9│ ┌──────────────────────────────────────────────────────┐ │
10│ │ Código do Serviço (LC 116) │ │
11│ │ [🔍 Buscar código ou descrição...______________ ] │ │
12│ │ Autocomplete do catálogo (~200 itens) │ │
13│ │ Ex: 17.06 - Propaganda e publicidade │ │
14│ └──────────────────────────────────────────────────────┘ │
15│ │
16│ ┌────────────────────┐ ┌───────────────────────────┐ │
17│ │ CNAE │ │ Alíquota ISS (%) │ │
18│ │ [__________] │ │ [_____] 0–100, 2 decimais │ │
19│ └────────────────────┘ └───────────────────────────┘ │
20│ │
21│ ┌────────────────────┐ ┌───────────────────────────┐ │
22│ │ Código Trib. Munic.│ │ NBS │ │
23│ │ [__________] │ │ [__________] │ │
24│ └────────────────────┘ └───────────────────────────┘ │
25│ │
26│ ─── Retenções ─── │
27│ ☐ Reter ISS ☐ Reter PIS ☐ Reter COFINS │
28│ ☐ Reter IR ☐ Reter CSLL ☐ Reter INSS │
29│ │
30│ [ Salvar ] │
31└────────────────────────────────────────────────────────────┘Backend
- Seed script: popular
servicos_lc116com ~200 itens da LC 116/2003 - Endpoint:
ws/get/ac_servicos_lc116?q=— busca por código ou texto - Método
cadastro_completo_nfse()no model de produto: valida LC 116 + alíquota ISS preenchidos - Campos opcionais no cadastro — obrigatoriedade validada apenas na emissão
Frontend
- Nova aba condicional no formulário de produto (visível quando
is_servico = '1'e módulo fiscal ativo) - Autocomplete para LC 116 consumindo endpoint do catálogo
- Indicador visual de cadastro fiscal incompleto (badge "Pendente")
1.4 Dados Fiscais do Cliente (Tomador)
Escopo: Campo Código IBGE no cadastro de cliente + auto-preenchimento via CEP.
Wireframe — Campo IBGE no Cadastro de Cliente
1┌────────────────────────────────────────────────────────────┐
2│ CADASTRO DE CLIENTE — Endereço │
3│ │
4│ ┌────────────┐ ┌──────────────────────────────────────┐ │
5│ │ CEP │ │ Logradouro │ │
6│ │ [________] │ │ [________________________________] │ │
7│ └────────────┘ └──────────────────────────────────────┘ │
8│ │
9│ ┌─────────────┐ ┌───────────┐ ┌────────┐ ┌──────────┐ │
10│ │ Bairro │ │ Cidade │ │ UF │ │ Número │ │
11│ │ [_________] │ │ [_______] │ │ [__] │ │ [_____] │ │
12│ └─────────────┘ └───────────┘ └────────┘ └──────────┘ │
13│ │
14│ ┌──────────────────────────────────────────────────────┐ │
15│ │ Código IBGE do Município ← NOVO CAMPO │ │
16│ │ [_______] (auto-preenchido via CEP) │ │
17│ │ Obrigatório para emissão de NFSe │ │
18│ └──────────────────────────────────────────────────────┘ │
19│ │
20└────────────────────────────────────────────────────────────┘Backend
- Método
cadastro_completo_nfse()no model de cliente: valida CPF/CNPJ + endereço + código IBGE - Lógica: ao receber CEP, buscar código IBGE via tabela
municipios_nfseou fonte externa - Referência: municipios-brasileiros JSON
Frontend
- Novo campo no bloco de endereço do
ClienteController_v.js - Auto-preenchimento do IBGE ao completar CEP
- Sinalização visual quando cadastro incompleto para NFSe
1.5 Permissões de Usuário
Escopo: 3 novas permissões no sistema existente.
| ID | Constante | Descrição |
|---|---|---|
| 435 | PERMISSAO_EMITIR_NFSE | Emitir NFSe Manual |
| 436 | PERMISSAO_CANCELAR_NFSE | Cancelar NFSe |
| 437 | PERMISSAO_GERENCIAR_CONF_NFSE | Gerenciar Configuração NFSe |
- Checkboxes na tela de permissões, visíveis apenas quando NFSe habilitada no tenant.
- Permissão 435 controla acesso ao módulo inteiro (menu, listagem, emissão).
- Validação no backend via
$this->session->permissoes.
1.6 Cache de Municípios Suportados
Escopo: Integração com GET /v2/municipios da Focus + cache local.
Backend
- Nova classe
ListMunicipios.phpemthird_party/NotaFiscal/seguindo padrão factory - Contrato
ListMunicipiosContract.php - Novo método
listMunicipios()naNotafiscal.php - Sincronização: cache com validade de 30 dias na tabela
municipios_nfse - Endpoint:
ws/get/ac_municipios_nfsepara autocomplete
Dados armazenados do município
Além dos campos da tabela, o campo nac deve ser derivado do provedor_nfse:
- Provedores com "Nacional" no nome →
nac = 'proxy'ou'oficial' - Demais →
nac = 'none'
A fonte mais confiável para o campo
nacé o JSON de cidades integradas da Focus. Script de seed inicial pode popular com base nesse JSON.
Entrega da Fase 1
- Migrações executadas e models atualizados
- Tela de Dados Fiscais com seção NFSe funcional
- Autocomplete de município com cache Focus
- Catálogo LC 116 populado e endpoint de busca funcionando
- Aba Dados Fiscais no cadastro de serviço
- Campo Código IBGE no cadastro de cliente
- Permissões 435/436/437 registradas e funcionais
Fase 2 — Emissão de NFSe Manual
Entrega: Usuário pode emitir NFSe selecionando tomador e serviços. Nota transmitida de forma assíncrona com retorno automático de status via webhook. XML armazenado localmente.
2.1 Integração com API Focus NFSe
Escopo: Classes de integração — backend puro, sem frontend.
Novos arquivos em third_party/NotaFiscal/
| Arquivo | Contrato | Método HTTP | Endpoint Focus |
|---|---|---|---|
CreateNfse.php | CreateNfseContract.php | POST | /v2/nfse?ref={REF} |
CreateNfsen.php | CreateNfsenContract.php | POST | /v2/nfsen?ref={REF} |
DetailNfse.php | DetailNfseContract.php | GET | /v2/nfse/{REF} |
CancelNfse.php | CancelNfseContract.php | DELETE | /v2/nfse/{REF} |
SubstituteNfse.php | SubstituteNfseContract.php | POST | /v2/nfse/{REF}/substitucao |
DownloadNfsePdf.php | — | GET | URL retornada pela Focus |
DownloadNfseXml.php | — | GET | URL retornada pela Focus |
ListMunicipios.php | ListMunicipiosContract.php | GET | /v2/municipios |
Factory — novos métodos em Notafiscal.php
1// Novos métodos — usam is_nfse_prod em vez de is_nf_prod
2public function createNfse($apiToken) { ... }
3public function createNfsen($apiToken) { ... }
4public function detailNfse($apiToken) { ... }
5public function cancelNfse($apiToken) { ... }
6public function substituteNfse($apiToken) { ... }
7public function listMunicipios() { ... }Importante: o ambiente NFSe (is_nfse_prod) é independente do ambiente NFe (is_nf_prod).
Resolução automática de endpoint
2.2 Webhook de Autorização NFSe
Escopo: Receber callback da Focus e atualizar status + armazenar XML.
Fluxo do Webhook
Backend
- Novo helper:
my_webhook_nfse_helper.phpseguindo padrão demy_webhook_nfe_helper.php - Novo case em
Ws.php:case "webhook_nfse": - Obrigatório: ao receber autorização, fazer GET no XML e armazenar na coluna
xml_nfse(Focus só gera backups mensais) - Armazenar:
nfse_url,nfse_codigo_verificacao,nfse_numero - Idempotência: verificar se já processou o webhook (status já AUTORIZADO → ignorar)
2.3 Formulário de Emissão — Dados Gerais e Tomador
Escopo: Página de NFSe Manual + etapas 1 e 2 do formulário.
Wireframe — Listagem de NFSe (página principal)
1┌─────────────────────────────────────────────────────────────────┐
2│ NFSe Manual [ + Nova NFSe ] │
3│ │
4│ ┌──────────┐ ┌──────────────────┐ ┌─────────────┐ │
5│ │ Status │ │ Tomador │ │ Período │ [Buscar] │
6│ │ [▾Todos] │ │ [🔍___________] │ │ [__] a [__] │ │
7│ └──────────┘ └──────────────────┘ └─────────────┘ │
8│ │
9│ ┌─────┬────────┬────────────┬─────────────┬──────────┬───────┐│
10│ │ Nº │ RPS │ Data │ Tomador │ Valor │Status ││
11│ ├─────┼────────┼────────────┼─────────────┼──────────┼───────┤│
12│ │ 42 │ 15 │ 01/04/2026 │ Empresa ABC │ R$500,00 │🟢 Aut││
13│ │ — │ 16 │ 01/04/2026 │ João Silva │ R$200,00 │🔄 Proc││
14│ │ 41 │ 14 │ 31/03/2026 │ Maria LTDA │ R$1.000 │🔴 Erro││
15│ │ 40 │ 13 │ 30/03/2026 │ Tech Corp │ R$750,00 │⚫ Canc││
16│ └─────┴────────┴────────────┴─────────────┴──────────┴───────┘│
17│ │
18│ ← 1 2 3 ... → 20 itens por página │
19│ │
20│ Estado vazio: "Nenhuma NFSe emitida ainda. Clique em │
21│ 'Nova NFSe' para começar." │
22└─────────────────────────────────────────────────────────────────┘Wireframe — Modal de Emissão: Etapa 1 (Dados Gerais)
1┌─────────────────────────────────────────────────────────────┐
2│ Nova NFSe ✕ │
3│ ═══════════════════════════════════════════════════════════ │
4│ [1. Dados Gerais] → 2. Tomador → 3. Serviços → 4. Revisão│
5│ ─────────────────────────────────────────────────────────── │
6│ │
7│ ┌────────────────────────┐ ┌───────────────────────────┐ │
8│ │ Número RPS │ │ Data de Competência │ │
9│ │ [ 16 ] (automático) │ │ [ 01/04/2026 ] 📅 │ │
10│ │ Somente leitura │ │ Não pode ser futura │ │
11│ └────────────────────────┘ └───────────────────────────┘ │
12│ │
13│ ┌──────────────────────────────────────────────────────┐ │
14│ │ Natureza da Operação │ │
15│ │ [▾ 1 - Tributação no município ] │ │
16│ │ Enum: 1=Trib. município, 2=Fora, 3=Isenção, │ │
17│ │ 4=Imune, 5=Susp. judicial, 6=Susp. administrativa │ │
18│ └──────────────────────────────────────────────────────┘ │
19│ │
20│ ┌──────────────────────────────────────────────────────┐ │
21│ │ Regime Especial de Tributação │ │
22│ │ [▾ 5 - MEI - Simples Nacional ] │ │
23│ │ Enum: 1=Microempresa, 2=Estimativa, 3=Soc. prof., │ │
24│ │ 4=Cooperativa, 5=MEI-SN, 6=ME EPP-SN │ │
25│ └──────────────────────────────────────────────────────┘ │
26│ │
27│ ┌──────────────────────────────────────────────────────┐ │
28│ │ Discriminação dos Serviços │ │
29│ │ [ ] │ │
30│ │ [ ] │ │
31│ │ Máx 2000 caracteres. Opcional. │ │
32│ └──────────────────────────────────────────────────────┘ │
33│ │
34│ [ Próximo → ] │
35└─────────────────────────────────────────────────────────────┘Wireframe — Modal de Emissão: Etapa 2 (Tomador)
1┌─────────────────────────────────────────────────────────────┐
2│ Nova NFSe ✕ │
3│ ═══════════════════════════════════════════════════════════ │
4│ 1. Dados Gerais → [2. Tomador] → 3. Serviços → 4. Revisão│
5│ ─────────────────────────────────────────────────────────── │
6│ │
7│ ┌──────────────────────────────────────────────────────┐ │
8│ │ Buscar tomador │ │
9│ │ [🔍 Nome, CPF ou CNPJ...________________________ ] │ │
10│ │ Autocomplete no cadastro de clientes │ │
11│ └──────────────────────────────────────────────────────┘ │
12│ [ + Cadastrar novo cliente ] │
13│ │
14│ ┌──────────────────────────────────────────────────────┐ │
15│ │ ✓ Tomador selecionado │ │
16│ │ ┌──────────────────────────────────────────────────┐ │ │
17│ │ │ Nome: Empresa ABC LTDA │ │ │
18│ │ │ CNPJ: 12.345.678/0001-90 │ │ │
19│ │ │ Município: Fortaleza - CE (IBGE: 2304400) │ │ │
20│ │ │ Endereço: Rua X, 100 - Centro │ │ │
21│ │ └──────────────────────────────────────────────────┘ │ │
22│ └──────────────────────────────────────────────────────┘ │
23│ │
24│ ⚠ ALERTA (se cadastro incompleto): │
25│ ┌──────────────────────────────────────────────────────┐ │
26│ │ ⚠ Cadastro incompleto para NFSe. │ │
27│ │ Campos faltantes: Código IBGE do Município │ │
28│ │ [Corrigir cadastro ↗] (abre nova aba) │ │
29│ │ │ │
30│ │ Após corrigir: [ 🔄 Revalidar tomador ] │ │
31│ └──────────────────────────────────────────────────────┘ │
32│ │
33│ [ ← Voltar ] [ Próximo → ] │
34└─────────────────────────────────────────────────────────────┘Backend
- Controller:
Nfse_manual.php+ rotanfse-manual - Helper:
my_nfse_helper.phpcomvalidar_empresa_nfse(),validar_tomador_nfse() - Endpoint:
ws/get/dados_iniciais_nfse(empresa, enums, próximo RPS)
Frontend
- Nova página:
application/views/paginas/nfse-manual.php - Controller Vue:
NfseManualController.js - Modal Controller:
ModalEmitirNfseController.js - Mixin:
Mixin_nfse.js - Item no menu: sidebar abaixo de "NF-e Manual", visível com permissão 435
2.4 Formulário de Emissão — Serviços e Retenções
Escopo: Etapas 3 e 4 do formulário de emissão.
Wireframe — Modal de Emissão: Etapa 3 (Serviços)
1┌─────────────────────────────────────────────────────────────┐
2│ Nova NFSe ✕ │
3│ ═══════════════════════════════════════════════════════════ │
4│ 1. Dados Gerais → 2. Tomador → [3. Serviços] → 4. Revisão│
5│ ─────────────────────────────────────────────────────────── │
6│ │
7│ ┌──────────────────────────────────────────────────────┐ │
8│ │ Buscar serviço do catálogo │ │
9│ │ [🔍 Nome ou código do serviço..._______________ ] │ │
10│ └──────────────────────────────────────────────────────┘ │
11│ [ + Cadastrar novo serviço ] [ + Adicionar serviço manual]│
12│ │
13│ ── Serviços adicionados ── │
14│ ┌──────────────────────────────────────────────────────┐ │
15│ │ # │ Serviço │ LC116 │ Qtd │ V.Unit │Total │ │
16│ │ 1 │ Consultoria TI │ 17.06 │ 10h │ R$150 │1.500 │ │
17│ │ │ ISS: 5% │ ISS Retido: Não [✏🗑]│ │
18│ │ 2 │ Suporte técnico │ 17.06 │ 5h │ R$100 │ 500 │ │
19│ │ │ ISS: 5% │ ISS Retido: Não [✏🗑]│ │
20│ │ 3 │ ⚠ Design gráfico │ — │ 2 │ R$500 │1.000 │ │
21│ │ │ ⚠ Dados fiscais pendentes [Completar ↗] [✏🗑]│ │
22│ └──────────────────────────────────────────────────────┘ │
23│ │
24│ ⚠ ALERTA LC 116 (se tentar misturar códigos): │
25│ ┌──────────────────────────────────────────────────────┐ │
26│ │ ⚠ Este serviço possui LC 116 diferente (14.01) dos │ │
27│ │ já adicionados (17.06). Uma NFSe só aceita um código.│ │
28│ │ Selecione 17.06 ou remova os serviços atuais. │ │
29│ └──────────────────────────────────────────────────────┘ │
30│ │
31│ Subtotal: R$ 3.000,00 │
32│ [ ← Voltar ] [ Próximo → ] │
33└─────────────────────────────────────────────────────────────┘Wireframe — Modal de Emissão: Etapa 4 (Revisão e Retenções)
1┌─────────────────────────────────────────────────────────────┐
2│ Nova NFSe ✕ │
3│ ═══════════════════════════════════════════════════════════ │
4│ 1. Dados Gerais → 2. Tomador → 3. Serviços → [4. Revisão]│
5│ ─────────────────────────────────────────────────────────── │
6│ │
7│ ── Resumo ── │
8│ Tomador: Empresa ABC LTDA (12.345.678/0001-90) │
9│ RPS: 16 │ Competência: 04/2026 │ Nat. Op.: Trib. munic. │
10│ │
11│ ── Serviços ── │
12│ │ Consultoria TI (17.06) │ 10h × R$150 = R$ 1.500,00 │
13│ │ Suporte técnico (17.06) │ 5h × R$100 = R$ 500,00 │
14│ │────────────────────────────────────────────────────│ │
15│ │ Subtotal Serviços R$ 2.000,00 │ │
16│ │
17│ ── Retenções (editáveis) ── │
18│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
19│ │ ISS (R$) │ │ PIS (R$) │ │ COFINS(R$) │ │
20│ │ [ 100,00] │ │ [ 0,00] │ │ [ 0,00] │ │
21│ └────────────┘ └────────────┘ └────────────┘ │
22│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
23│ │ IR (R$) │ │ CSLL (R$) │ │ INSS (R$) │ │
24│ │ [ 0,00] │ │ [ 0,00] │ │ [ 0,00] │ │
25│ └────────────┘ └────────────┘ └────────────┘ │
26│ │
27│ ⚠ Banner MEI (se aplicável): │
28│ ┌──────────────────────────────────────────────────────┐ │
29│ │ ℹ Esta nota será transmitida pelo Ambiente Nacional │ │
30│ │ NFSe, conforme obrigatoriedade para emitentes MEI. │ │
31│ └──────────────────────────────────────────────────────┘ │
32│ │
33│ ┌──────────────────────────────────────────────────────┐ │
34│ │ VALOR TOTAL: R$ 1.900,00 │ │
35│ │ (Serviços - Retenções = Líquido) │ │
36│ └──────────────────────────────────────────────────────┘ │
37│ │
38│ [ ← Voltar ] [ 🚀 Transmitir NFSe ] │
39└─────────────────────────────────────────────────────────────┘Regras de negócio — Serviços
- Restrição LC 116: todos os serviços de uma nota devem ter o mesmo código LC 116
- Serviço manual: dados efêmeros (não salva no catálogo), mas LC 116 e alíquota são obrigatórios
- Pendência fiscal: serviço do catálogo sem LC 116 ou alíquota → badge de pendência + link para edição
Backend
validar_servicos_nfse(): cadastro fiscal completo + bloqueio de mix LC 116- Validação por item:
codigo_servico_lc116eservico_aliquota_issobrigatórios
2.5 Transmissão e Acompanhamento de Status
Escopo: Envio à Focus, polling de status, atualização na listagem.
Fluxo completo de emissão
Backend — Funções principais
| Função | Responsabilidade |
|---|---|
set_emitir_nfse() | Orquestra validação → gravação → transmissão |
montar_payload_nfse() | JSON conforme formato Focus |
get_consultar_nfse() | Consulta manual de status (fallback ao webhook) |
resolver_endpoint_nfse() | Determina /v2/nfse ou /v2/nfsen com base no município + regime |
Payload da Focus — Formato (endpoint /v2/nfse)
1{
2 "data_emissao": "2026-04-01T10:00:00-03:00",
3 "prestador": {
4 "cnpj": "07504505000132",
5 "inscricao_municipal": "12345",
6 "codigo_municipio": "2304400"
7 },
8 "tomador": {
9 "cnpj": "12345678000190",
10 "razao_social": "Empresa ABC LTDA",
11 "endereco": { ... },
12 "codigo_municipio": "3550308"
13 },
14 "servico": {
15 "aliquota": 5.0,
16 "discriminacao": "Consultoria em TI...",
17 "iss_retido": false,
18 "item_lista_servico": "1706",
19 "codigo_cnae": "6201501",
20 "codigo_tributario_municipio": "123",
21 "valor_servicos": 2000.00
22 },
23 "natureza_operacao": "1",
24 "regime_especial_tributacao": "5",
25 "valor_pis": 0,
26 "valor_cofins": 0,
27 "valor_ir": 0,
28 "valor_csll": 0,
29 "valor_inss": 0
30}Cota mensal
NFSe consome a mesma franquia do pacote mensal (mesma contagem de NFe/NFCe). Verificar saldo antes de emitir.
Entrega da Fase 2
- Classes Focus NFSe criadas e funcionais (Create, Detail, Cancel, Substitute)
- Webhook NFSe processando autorizações e armazenando XML
- Formulário completo de emissão (4 etapas)
- Transmissão assíncrona com retorno de status
- Polling + consulta manual de status
- Regra MEI forçando Ambiente Nacional
- Resolução automática de endpoint (nfse vs nfsen)
Fase 3 — Gestão de NFSe
Entrega: Usuário pode listar, filtrar, visualizar detalhes, baixar PDF/XML, cancelar e substituir notas.
3.1 Listagem e Filtros
Wireframe da listagem já apresentado na Fase 2 (seção 2.3). Complementos:
- Filtros: período (data início/fim), status (dropdown), tomador (busca por nome/CPF/CNPJ)
- Busca textual: por número da nota, número RPS, nome do tomador
- Paginação: 20 itens por página
3.2 Visualização Detalhada e Downloads
Wireframe — Modal de Detalhes da NFSe
1┌─────────────────────────────────────────────────────────────┐
2│ Detalhes da NFSe #42 ✕ │
3│ ═══════════════════════════════════════════════════════════ │
4│ │
5│ Status: 🟢 Autorizada │
6│ Nº NFSe: 42 │ RPS: 15 │ Código Verificação: ABC123 │
7│ Data Emissão: 01/04/2026 │ Competência: 04/2026 │
8│ │
9│ ── Prestador ── │
10│ SMB Store LTDA │ CNPJ: 07.504.505/0001-32 │
11│ Inscrição Municipal: 12345 │
12│ │
13│ ── Tomador ── │
14│ Empresa ABC LTDA │ CNPJ: 12.345.678/0001-90 │
15│ Fortaleza - CE (IBGE: 2304400) │
16│ │
17│ ── Serviços ── │
18│ │ Consultoria TI (LC 116: 17.06) │
19│ │ CNAE: 6201501 │ ISS: 5% │ ISS Retido: Não │
20│ │ 10h × R$150,00 = R$ 1.500,00 │
21│ │──────────────────────────────────────────────────│ │
22│ │ Suporte técnico (LC 116: 17.06) │
23│ │ 5h × R$100,00 = R$ 500,00 │
24│ │
25│ ── Retenções ── │
26│ ISS: R$100,00 │ PIS: R$0 │ COFINS: R$0 │
27│ IR: R$0 │ CSLL: R$0 │ INSS: R$0 │
28│ │
29│ ── Valor Total: R$ 1.900,00 ── │
30│ │
31│ ── Notas Vinculadas ── (se houver substituição) │
32│ │ NFSe #41 │ 31/03/2026 │ Status: Substituído │ [Ver ↗] │
33│ │
34│ 🔗 Ver na prefeitura: https://... │
35│ │
36│ [ 📄 Baixar XML ] [ 📄 Baixar PDF ] [ ✕ Cancelar ] │
37└─────────────────────────────────────────────────────────────┘Matriz de ações por status
| Ação | Em processamento | Autorizado | Erro | Cancelado | Substituído |
|---|---|---|---|---|---|
| Baixar XML | — | ✓ | — | ✓ | ✓ |
| Baixar PDF | — | ✓ | — | — | — |
| Cancelar | — | ✓ | — | — | — |
| Substituir | — | — | ✓ | ✓ | — |
Backend — Downloads
- XML: prioriza coluna
xml_nfse(local); fallback viaDetailNfse.php+ GET - PDF: chama Focus API; se município não suporta PDF, redireciona para
nfse_url - Cases em
Ws.php:nfse_pdf,nfse_xml
3.3 Cancelamento
Wireframe — Modal de Cancelamento
1┌─────────────────────────────────────────────────────┐
2│ Cancelar NFSe #42 ✕ │
3│ ═══════════════════════════════════════════════════ │
4│ │
5│ Tomador: Empresa ABC LTDA │
6│ Valor: R$ 1.900,00 │
7│ Data: 01/04/2026 │
8│ │
9│ ⚠ Esta ação é irreversível. │
10│ │
11│ ┌──────────────────────────────────────────────┐ │
12│ │ Justificativa de cancelamento * │ │
13│ │ [ ] │ │
14│ │ [ ] │ │
15│ │ Máx 255 caracteres │ │
16│ └──────────────────────────────────────────────┘ │
17│ │
18│ [ Voltar ] [ Confirmar Cancel.] │
19└─────────────────────────────────────────────────────┘- Município sem suporte a cancelamento: botão desabilitado com tooltip.
- Backend:
CancelNfse.php→ DELETE/v2/nfse/REFcom justificativa. - Case
Ws.php:cancelar_nfse
3.4 Substituição
- Disponível para notas com status Erro ou Cancelado.
- Abre formulário de nova NFSe pré-preenchido com dados da nota original.
- Banner: "Você está substituindo a nota nº X."
- Após transmissão: nota original → status SUBSTITUÍDO; nova nota → PROCESSANDO.
- Backend:
SubstituteNfse.php→ POST/v2/nfse/REF/substitucao - Vínculo:
nfse_substituida_idna nova nota. - Case
Ws.php:substituir_nfse
Entrega da Fase 3
- Listagem com filtros e paginação
- Busca por número, RPS, tomador
- Modal de detalhes com todos os dados
- Download XML (local) e PDF (Focus)
- Cancelamento com justificativa
- Substituição com pré-preenchimento
- Cadeia de notas vinculadas
Fase 4 — Dashboard Fiscal Unificado
Entrega: Dashboard apresenta visão consolidada de NFe + NFCe + NFSe com métricas, filtros e exportação de XMLs.
4.1 Métricas e Contadores NFSe
Wireframe — Cards no Dashboard
1┌─────────────────────────────────────────────────────────────────┐
2│ DASHBOARD FISCAL │
3│ │
4│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────┐│
5│ │ NFCe │ │ NFe Norm │ │ NFe Dev │ │ NFe Ajus │ │ NFSe ││
6│ │ 142 │ │ 28 │ │ 3 │ │ 1 │ │ 12 ││
7│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────┘│
8│ │
9│ ┌─────────────────────┐ ┌──────────────────────────────────┐ │
10│ │ Notas no período │ │ Cota mensal: 186/500 (37%) │ │
11│ │ 186 │ │ ████████░░░░░░░░░░░░░░ │ │
12│ │ (inclui NFSe) │ │ (NFe + NFCe + NFSe) │ │
13│ └─────────────────────┘ └──────────────────────────────────┘ │
14│ │
15│ Tipo: [▾ Todas ▾] inclui opção "NFSe" [ 🚀 Emitir NFSe]│
16│ │
17└─────────────────────────────────────────────────────────────────┘- Card "NFSe" visível apenas com switch ativo.
- NFSe autorizadas contam no total de "Notas emitidas no período".
- Cota mensal inclui NFSe na contagem total.
4.2 Filtros e Navegação
- Nova opção "NFSe" no seletor de tipo de documento no dashboard.
- Link rápido "Emitir NFSe" na barra de ações.
- Menu lateral: item "NFSe Manual" no grupo Módulo Fiscal.
4.3 Exportação de XMLs por Período
- Botão "Exportar XMLs" com seletor de período.
- Consulta coluna
xml_nfselocal, gera ZIP, serve para download. - Não depende da API Focus.
Entrega da Fase 4
- Card contador "NFSe" no dashboard
- NFSe na cota mensal
- Filtro por tipo de documento incluindo NFSe
- Link rápido "Emitir NFSe"
- Exportação de XMLs em ZIP
Fase 5 — Testes, Validação e Rollout
Entrega: Módulo validado em homologação, regressão NFe/NFCe íntegra, rollout gradual para produção.
5.1 Testes Funcionais em Homologação
| Cenário | Descrição |
|---|---|
| Emissão básica | Empresa SN, serviço simples, tomador PJ |
| Emissão MEI | Sistema força Ambiente Nacional |
| ISS retido + retenções | PIS, COFINS, CSLL, IR, INSS preenchidos |
| Bloqueio dados incompletos | Serviço sem LC 116 → orientação |
| Bloqueio mix LC 116 | 2 serviços com códigos diferentes → bloqueio |
| Webhook autorização | Status atualizado + XML armazenado |
| Webhook erro | Status erro + mensagem da Focus |
| Consulta manual status | Fallback ao webhook |
| Cancelamento | Justificativa + Focus API |
| Substituição | Pré-preenchimento + vínculo |
| Download PDF | Município com e sem suporte |
| Download XML | Base local e via API |
| Cota | NFSe decrementa saldo do pacote |
| Permissões | Sem permissão → menu oculto + rota bloqueada |
| Multi-tenant | NFSe empresa A ≠ empresa B |
| Tomador sem IBGE | Bloqueio + orientação |
| Sem Inscrição Municipal | Bloqueio ao ativar switch |
| Município não suportado | Mensagem clara |
5.2 Testes de Regressão
- NFe/NFCe continua emitindo normalmente
- Dashboard sem NFSe ativa não quebra
- Produto tipo mercadoria não exibe aba serviço
- Webhooks NFe/NFCe inalterados
5.3 Testes de Borda
- Timeout da Focus → tratamento gracioso
- NFSe com valor zero → bloqueio
- Emissões simultâneas → sem duplicidade no RPS (lock/transação atômica)
- Webhook duplicado → idempotência
5.4 Rollout Gradual
| Fase | Escopo | Critério de entrada |
|---|---|---|
| Alpha | 3–5 clientes em municípios estáveis (SP, CWB) | Testes em homolog aprovados |
| Beta | Clientes em cidades homologadas como estáveis | Alpha sem bugs críticos |
| GA (Disponibilidade Geral) | Toda a base | Beta estável por 2 semanas |
Entrega da Fase 5
- Todos os cenários de teste aprovados em homologação
- Regressão NFe/NFCe sem impacto
- Payloads validados com consultoria fiscal
- Webhook NFSe configurado no painel Focus (homolog + prod)
- Alpha concluído com sucesso
- GA liberado
Fluxo Geral — Diagrama Completo
Dependências e Paralelismo
| Atividade | Depende de | Pode rodar em paralelo com |
|---|---|---|
| 1.1 Estrutura de dados | — | — |
| 1.2 Config empresa | 1.1 | 1.3, 1.4, 1.5, 1.6 |
| 1.3 Catálogo LC 116 | 1.1 | 1.2, 1.4, 1.5, 1.6 |
| 1.4 Dados cliente | 1.1 | 1.2, 1.3, 1.5, 1.6 |
| 1.5 Permissões | 1.1 | 1.2, 1.3, 1.4, 1.6 |
| 1.6 Cache municípios | 1.1 | 1.2, 1.3, 1.4, 1.5 |
| 2.1 Classes Focus | 1.1 | 2.2 |
| 2.2 Webhook | 1.1 | 2.1 |
| 2.3 Form (dados/tomador) | 1.2–1.6 | — |
| 2.4 Form (serviços) | 2.3 | — |
| 2.5 Transmissão | 2.1, 2.2, 2.4 | — |
| 3.1–3.4 | 2.5 | 3.3 ∥ 3.4 |
| 4.1–4.3 | 3.1 | 4.1 ∥ 4.2 ∥ 4.3 |
| 5.x | 4.x | — |
Funcionalidades Futuras (pós Release 1)
| Feature | Release |
|---|---|
| Emissão de NFSe a partir de Ordem de Serviço | Release 2 |
| Clonagem de NFSe recorrente | Futuro |
| Cálculo automático de retenções federais | Futuro |
| Envio automático de e-mail com nota | Futuro |
| Cálculo IBS/CBS (reforma tributária) | Quando obrigatório |