|
|
| from __future__ import annotations |
|
|
| import math |
| from dataclasses import dataclass |
| from datetime import date |
| from decimal import Decimal |
| from pathlib import Path |
| from typing import Any, Optional |
|
|
| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
|
|
|
|
| |
| |
| |
|
|
| class TokenizadorFiscal: |
| VOCAB_ESPECIAL = ["<PAD>", "<UNK>", "<BOS>", "<EOS>", "<SEP>", "<MASK>"] |
|
|
| def __init__(self, vocab_size: int = 2048): |
| self.vocab_size = vocab_size |
| self._char2idx: dict[str, int] = {} |
| self._idx2char: dict[int, str] = {} |
| self._construir_vocab_base() |
|
|
| def _construir_vocab_base(self) -> None: |
| idx = 0 |
| for tok in self.VOCAB_ESPECIAL: |
| self._char2idx[tok] = idx |
| self._idx2char[idx] = tok |
| idx += 1 |
| for c in range(32, 127): |
| ch = chr(c) |
| self._char2idx[ch] = idx |
| self._idx2char[idx] = ch |
| idx += 1 |
| for ch in "áéíóúâêîôûãõàèìòùäëïöüçñÁÉÍÓÚÂÊÎÔÛÃÕÀÈÌÒÙÄËÏÖÜÇÑ": |
| if ch not in self._char2idx: |
| self._char2idx[ch] = idx |
| self._idx2char[idx] = ch |
| idx += 1 |
| self.pad_id = self._char2idx["<PAD>"] |
| self.unk_id = self._char2idx["<UNK>"] |
| self.bos_id = self._char2idx["<BOS>"] |
| self.eos_id = self._char2idx["<EOS>"] |
| self.sep_id = self._char2idx["<SEP>"] |
| self.mask_id = self._char2idx["<MASK>"] |
| self._vocab_atual = idx |
|
|
| def encode(self, texto: str, max_len: int = 512, add_special: bool = True) -> list[int]: |
| ids: list[int] = [] |
| if add_special: |
| ids.append(self.bos_id) |
| for ch in texto[: max_len - (2 if add_special else 0)]: |
| ids.append(self._char2idx.get(ch, self.unk_id)) |
| if add_special: |
| ids.append(self.eos_id) |
| return ids |
|
|
| def decode(self, ids: list[int]) -> str: |
| especiais = {self.pad_id, self.bos_id, self.eos_id, self.sep_id} |
| return "".join(self._idx2char.get(i, "?") for i in ids if i not in especiais) |
|
|
| def __len__(self) -> int: |
| return self._vocab_atual |
|
|
|
|
| |
| |
| |
|
|
| class PositionalEncoding(nn.Module): |
| def __init__(self, d_model: int, max_len: int = 1024, dropout: float = 0.1): |
| super().__init__() |
| self.dropout = nn.Dropout(p=dropout) |
| pe = torch.zeros(max_len, d_model) |
| pos = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1) |
| div = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) |
| pe[:, 0::2] = torch.sin(pos * div) |
| pe[:, 1::2] = torch.cos(pos * div) |
| self.register_buffer("pe", pe.unsqueeze(0)) |
|
|
| def forward(self, x: torch.Tensor) -> torch.Tensor: |
| x = x + self.pe[:, : x.size(1)] |
| return self.dropout(x) |
|
|
|
|
| |
| |
| |
|
|
| class TransformerFiscal(nn.Module): |
| """ |
| Transformer encoder compacto para análise de texto fiscal. |
| Usado para: embeddings, classificação de obrigações, extração de entidades. |
| |
| Arquitetura: |
| - 4 camadas encoder, d_model=256, 8 cabeças de atenção |
| - Pre-LN (norm_first=True) para estabilidade de treinamento |
| - Cabeça de classificação linear (256 → 128 → num_classes) |
| - Cabeça de extração de valor escalar (256 → 64 → 1) |
| """ |
|
|
| def __init__( |
| self, |
| vocab_size: int = 2048, |
| d_model: int = 256, |
| nhead: int = 8, |
| num_layers: int = 4, |
| dim_feedforward: int = 1024, |
| dropout: float = 0.1, |
| max_len: int = 1024, |
| num_classes: int = 16, |
| ): |
| super().__init__() |
| self.d_model = d_model |
| self.embedding = nn.Embedding(vocab_size, d_model, padding_idx=0) |
| self.pos_enc = PositionalEncoding(d_model, max_len, dropout) |
| encoder_layer = nn.TransformerEncoderLayer( |
| d_model=d_model, |
| nhead=nhead, |
| dim_feedforward=dim_feedforward, |
| dropout=dropout, |
| batch_first=True, |
| norm_first=True, |
| ) |
| self.encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_layers) |
| self.norm = nn.LayerNorm(d_model) |
| self.classificador = nn.Sequential( |
| nn.Linear(d_model, d_model // 2), |
| nn.GELU(), |
| nn.Dropout(dropout), |
| nn.Linear(d_model // 2, num_classes), |
| ) |
| self.extrator_valor = nn.Sequential( |
| nn.Linear(d_model, d_model // 4), |
| nn.GELU(), |
| nn.Linear(d_model // 4, 1), |
| ) |
| self._init_weights() |
|
|
| def _init_weights(self) -> None: |
| for p in self.parameters(): |
| if p.dim() > 1: |
| nn.init.xavier_uniform_(p) |
|
|
| def encode(self, input_ids: torch.Tensor, attention_mask: Optional[torch.Tensor] = None) -> torch.Tensor: |
| """Retorna embeddings de sequência (shape: B × L × d_model).""" |
| x = self.embedding(input_ids) * math.sqrt(self.d_model) |
| x = self.pos_enc(x) |
| key_padding_mask = (attention_mask == 0) if attention_mask is not None else None |
| x = self.encoder(x, src_key_padding_mask=key_padding_mask) |
| return self.norm(x) |
|
|
| def cls_embedding(self, input_ids: torch.Tensor, attention_mask: Optional[torch.Tensor] = None) -> torch.Tensor: |
| """Embedding CLS (primeiro token) como representação da sentença.""" |
| return self.encode(input_ids, attention_mask)[:, 0, :] |
|
|
| def forward( |
| self, |
| input_ids: torch.Tensor, |
| attention_mask: Optional[torch.Tensor] = None, |
| task: str = "classificar", |
| ) -> torch.Tensor: |
| cls = self.cls_embedding(input_ids, attention_mask) |
| if task == "classificar": |
| return self.classificador(cls) |
| if task == "extrair_valor": |
| return self.extrator_valor(cls) |
| return cls |
|
|
| def save(self, path: str | Path) -> None: |
| torch.save({ |
| "state_dict": self.state_dict(), |
| "config": { |
| "vocab_size": self.embedding.num_embeddings, |
| "d_model": self.d_model, |
| }, |
| }, path) |
|
|
| @classmethod |
| def load(cls, path: str | Path, **kwargs) -> "TransformerFiscal": |
| ckpt = torch.load(path, map_location="cpu", weights_only=False) |
| cfg = {**ckpt.get("config", {}), **kwargs} |
| model = cls(**cfg) |
| model.load_state_dict(ckpt["state_dict"]) |
| return model |
|
|
|
|
| |
| |
| |
|
|
| class BancoEmbeddingsFiscais: |
| """ |
| Armazena embeddings de conhecimento fiscal para recuperação semântica (RAG). |
| Usa cosine similarity para busca eficiente. |
| """ |
|
|
| def __init__(self, modelo: TransformerFiscal, tokenizador: TokenizadorFiscal, device: str = "cpu"): |
| self.modelo = modelo |
| self.tokenizador = tokenizador |
| self.device = device |
| self._textos: list[str] = [] |
| self._embeddings: Optional[torch.Tensor] = None |
| self.modelo.to(device) |
| self.modelo.eval() |
|
|
| def _embed(self, textos: list[str]) -> torch.Tensor: |
| ids_list = [self.tokenizador.encode(t, max_len=512) for t in textos] |
| max_len = max(len(i) for i in ids_list) |
| padded = torch.zeros(len(ids_list), max_len, dtype=torch.long) |
| mask = torch.zeros(len(ids_list), max_len, dtype=torch.long) |
| for k, ids in enumerate(ids_list): |
| padded[k, : len(ids)] = torch.tensor(ids) |
| mask[k, : len(ids)] = 1 |
| padded = padded.to(self.device) |
| mask = mask.to(self.device) |
| with torch.no_grad(): |
| embs = self.modelo.cls_embedding(padded, mask) |
| return F.normalize(embs, dim=-1) |
|
|
| def indexar(self, textos: list[str]) -> None: |
| self._textos = textos |
| self._embeddings = self._embed(textos) |
|
|
| def buscar(self, query: str, top_k: int = 5) -> list[tuple[str, float]]: |
| if self._embeddings is None or not self._textos: |
| return [] |
| q_emb = self._embed([query]) |
| scores = (self._embeddings @ q_emb.T).squeeze(-1) |
| top_idx = scores.argsort(descending=True)[:top_k] |
| return [(self._textos[i], float(scores[i])) for i in top_idx] |
|
|
|
|
| |
| |
| |
|
|
| CLASSES_OBRIGACAO = [ |
| "EFD_ICMS_IPI", |
| "EFD_CONTRIBUICOES", |
| "ECD", |
| "ECF", |
| "NFe", |
| "NFSe", |
| "CTe", |
| "eSocial", |
| "EFD_REINF", |
| "DCTF", |
| "PGDAS", |
| "calculo_icms", |
| "calculo_ipi", |
| "calculo_pis_cofins", |
| "calculo_irpj_csll", |
| "calculo_iss", |
| ] |
|
|
|
|
| class ClassificadorIntencaoFiscal: |
| """Classifica intenções em consultas fiscais usando o TransformerFiscal.""" |
|
|
| def __init__(self, modelo: TransformerFiscal, tokenizador: TokenizadorFiscal, device: str = "cpu"): |
| self.modelo = modelo |
| self.tokenizador = tokenizador |
| self.device = device |
| self.classes = CLASSES_OBRIGACAO |
| self.modelo.to(device) |
| self.modelo.eval() |
|
|
| def classificar(self, texto: str, top_k: int = 3) -> list[tuple[str, float]]: |
| ids = self.tokenizador.encode(texto, max_len=256) |
| t = torch.tensor([ids], dtype=torch.long).to(self.device) |
| mask = torch.ones_like(t) |
| with torch.no_grad(): |
| logits = self.modelo(t, mask, task="classificar") |
| probs = F.softmax(logits[0], dim=-1) |
| top = probs.argsort(descending=True)[:top_k] |
| return [(self.classes[i], float(probs[i])) for i in top] |
|
|
|
|
| |
| |
| |
|
|
| @dataclass |
| class ResultadoFiscal: |
| """Resultado de uma operação processada pelo PipelineFiscal.""" |
| operacao: str |
| dados: dict[str, Any] |
| contexto_rag: list[tuple[str, float]] |
| intencoes: list[tuple[str, float]] |
| arquivos_gerados: list[str] |
|
|
| def sucesso(self) -> bool: |
| return "erro" not in self.dados |
|
|
| def resumo(self) -> str: |
| linhas = [f"[{self.operacao}]"] |
| for k, v in self.dados.items(): |
| if k in ("instrucoes", "partilha", "atividades"): |
| continue |
| if isinstance(v, float): |
| linhas.append(f" {k}: R$ {v:,.2f}") |
| elif isinstance(v, list): |
| linhas.append(f" {k}: {len(v)} item(ns)") |
| else: |
| linhas.append(f" {k}: {v}") |
| if self.arquivos_gerados: |
| linhas.append(f" arquivos: {', '.join(self.arquivos_gerados)}") |
| return "\n".join(linhas) |
|
|
|
|
| |
| |
| |
|
|
| class PipelineFiscal: |
| """ |
| Pipeline LLM completo para obrigações fiscais brasileiras. |
| |
| Combina: |
| - TransformerFiscal (PyTorch): classificação de intenção + embeddings RAG |
| - Calculadores tributários: ICMS, IPI, PIS/COFINS, IRPJ/CSLL, ISS, Simples Nacional |
| - Geradores SPED: EFD ICMS/IPI, EFD Contribuições, ECD, ECF, DCTF, EFD-Reinf, e-Social |
| - Transmissor NF-e: SEFAZ SOAP webservices |
| |
| Uso básico:: |
| |
| pipeline = PipelineFiscal(diretorio_saida="./output") |
| resultado = pipeline.processar( |
| "calcule o ICMS de uma venda", |
| {"valor_mercadoria": 10000, "aliquota": 18}, |
| ) |
| print(resultado.resumo()) |
| |
| # Geração de todas as obrigações de um período |
| arquivos = pipeline.gerar_obrigacoes(periodo) |
| |
| Uso com modelo treinado:: |
| |
| pipeline = PipelineFiscal(caminho_modelo="modelo_fiscal.pt") |
| """ |
|
|
| _MAPA_PALAVRAS: dict[str, list[str]] = { |
| "calcular_icms": ["icms", "difal", "substituição tributária", "icms-st"], |
| "calcular_ipi": ["ipi", "industrializado", "tipi"], |
| "calcular_pis_cofins": ["pis", "cofins", "contribuição pis", "contribuição cofins"], |
| "calcular_irpj_csll": ["irpj", "csll", "lucro real", "lucro presumido", "imposto renda"], |
| "calcular_iss": ["iss", "imposto serviços", "serviço municipal"], |
| "calcular_simples": ["simples nacional", "das", "mei", "microempresa"], |
| "calcular_pgdas": ["pgdas", "pgdas-d", "declaração simples"], |
| "gerar_efd_icms_ipi": ["efd icms", "sped icms", "escrituração fiscal digital icms", "bloco k", "ciap"], |
| "gerar_efd_contribuicoes":["efd contribuições", "sped pis", "sped cofins"], |
| "gerar_ecd": ["ecd", "escrituração contábil digital", "livro diário"], |
| "gerar_ecf": ["ecf", "escrituração contábil fiscal", "lalur", "dipj"], |
| "gerar_dctf": ["dctf", "declaração débitos", "débitos tributários federais"], |
| "gerar_efd_reinf": ["reinf", "efd-reinf", "retenção previdenciária"], |
| "gerar_esocial": ["esocial", "e-social", "folha pagamento", "admissão", "rescisão"], |
| "gerar_cte": ["cte", "ct-e", "conhecimento transporte", "frete eletrônico"], |
| "gerar_nfce": ["nfce", "nfc-e", "modelo 65", "nota consumidor", "pdv"], |
| "gerar_mdfe": ["mdfe", "mdf-e", "manifesto documentos fiscais"], |
| "gerar_dirf": ["dirf", "imposto renda retido fonte", "declaração irrf anual"], |
| "gerar_defis": ["defis", "declaração informações simples nacional", "defis anual"], |
| "gerar_destda": ["destda", "de-stda", "icms-st simples", "diferencial alíquota simples"], |
| "gerar_gia": ["gia", "gia-st", "guia informação apuração icms sp", "scanc"], |
| "verificar_sefaz": ["sefaz", "status nfe", "autorizar nfe"], |
| } |
|
|
| def __init__( |
| self, |
| diretorio_saida: str | Path = "./output", |
| caminho_modelo: Optional[str | Path] = None, |
| device: Optional[str] = None, |
| ): |
| self.diretorio_saida = Path(diretorio_saida) |
| self.diretorio_saida.mkdir(parents=True, exist_ok=True) |
| self.device = device or ("cuda" if torch.cuda.is_available() else "cpu") |
|
|
| |
| self.tokenizador = TokenizadorFiscal() |
| if caminho_modelo and Path(caminho_modelo).exists(): |
| self.modelo = TransformerFiscal.load(caminho_modelo, num_classes=len(CLASSES_OBRIGACAO)) |
| else: |
| self.modelo = TransformerFiscal( |
| vocab_size=len(self.tokenizador), |
| d_model=256, |
| nhead=8, |
| num_layers=4, |
| dim_feedforward=1024, |
| num_classes=len(CLASSES_OBRIGACAO), |
| ) |
|
|
| self.rag = BancoEmbeddingsFiscais(self.modelo, self.tokenizador, self.device) |
| self.classificador = ClassificadorIntencaoFiscal(self.modelo, self.tokenizador, self.device) |
| self.rag.indexar(BASE_CONHECIMENTO_FISCAL) |
|
|
| |
| |
| |
|
|
| def processar(self, query: str, params: Optional[dict] = None) -> ResultadoFiscal: |
| """ |
| Processa uma consulta fiscal em linguagem natural. |
| |
| Args: |
| query: Texto em português descrevendo a operação desejada. |
| params: Dicionário com os parâmetros numéricos/fiscais necessários. |
| |
| Returns: |
| ResultadoFiscal com dados calculados, contexto RAG e intenções. |
| """ |
| intencoes = self.classificador.classificar(query, top_k=3) |
| contexto = self.rag.buscar(query, top_k=2) |
| operacao = self._detectar_operacao(query, intencoes) |
| dados: dict[str, Any] = {} |
| arquivos: list[str] = [] |
|
|
| if operacao and params is not None: |
| dados = self._executar(operacao, params) |
| if "arquivo" in dados: |
| arquivos = [dados["arquivo"]] |
| elif "arquivos" in dados: |
| arquivos = dados.get("arquivos", []) |
|
|
| return ResultadoFiscal( |
| operacao=operacao or "consulta", |
| dados=dados, |
| contexto_rag=contexto, |
| intencoes=intencoes, |
| arquivos_gerados=arquivos, |
| ) |
|
|
| def gerar_obrigacoes(self, periodo: Any, obrigacoes: Optional[list[str]] = None) -> dict[str, ResultadoFiscal]: |
| """ |
| Gera automaticamente todos os arquivos SPED do período conforme o regime tributário. |
| |
| Args: |
| periodo: PeriodoApuracao com dados da empresa e notas fiscais. |
| obrigacoes: Lista opcional de obrigações específicas. |
| Se None, determina automaticamente pelo regime. |
| |
| Returns: |
| Dicionário {nome_obrigacao: ResultadoFiscal}. |
| """ |
| from src.fiscal.entities import RegimeTributario |
|
|
| regime = periodo.empresa.regime_tributario |
| if obrigacoes is None: |
| if regime == RegimeTributario.LUCRO_REAL: |
| obrigacoes = ["EFD_ICMS_IPI", "EFD_CONTRIBUICOES", "ECD", "ECF", "DCTF"] |
| elif regime == RegimeTributario.LUCRO_PRESUMIDO: |
| obrigacoes = ["EFD_ICMS_IPI", "EFD_CONTRIBUICOES", "DCTF"] |
| else: |
| obrigacoes = [] |
|
|
| resultados: dict[str, ResultadoFiscal] = {} |
| for ob in obrigacoes: |
| dados = self._gerar_sped(ob, periodo) |
| arquivos = [dados.get("arquivo", "")] if "arquivo" in dados else dados.get("arquivos", []) |
| resultados[ob] = ResultadoFiscal( |
| operacao=ob, |
| dados=dados, |
| contexto_rag=[], |
| intencoes=[], |
| arquivos_gerados=[a for a in arquivos if a], |
| ) |
| return resultados |
|
|
| def gerar_cte(self, params: dict) -> dict: |
| """Gera o CT-e (Conhecimento de Transporte Eletrônico) XML v4.00.""" |
| from src.generators.cte import GeradorCTe, CargaCTe, ParteCTe, DadosTransporte, DocumentoReferenciado |
| from datetime import date as _date |
| emitente = params.get("_emitente_obj") |
| if emitente is None: |
| return {"erro": "Emitente (objeto Empresa) não fornecido em params['_emitente_obj']"} |
| rem_d = params.get("remetente", {}) |
| dest_d = params.get("destinatario", {}) |
| remetente = ParteCTe( |
| cnpj=rem_d.get("cnpj", ""), |
| razao_social=rem_d.get("razao_social", "REMETENTE"), |
| endereco=rem_d.get("endereco", ""), |
| municipio=rem_d.get("municipio", ""), |
| uf=rem_d.get("uf", "SP"), |
| cep=rem_d.get("cep", ""), |
| cod_municipio=rem_d.get("cod_municipio", ""), |
| ) |
| destinatario = ParteCTe( |
| cnpj=dest_d.get("cnpj", ""), |
| razao_social=dest_d.get("razao_social", "DESTINATÁRIO"), |
| endereco=dest_d.get("endereco", ""), |
| municipio=dest_d.get("municipio", ""), |
| uf=dest_d.get("uf", "SP"), |
| cep=dest_d.get("cep", ""), |
| cod_municipio=dest_d.get("cod_municipio", ""), |
| ) |
| carga_d = params.get("carga", {}) |
| carga = CargaCTe( |
| descricao=carga_d.get("descricao", "CARGA GERAL"), |
| produto=carga_d.get("produto", "00"), |
| valor_carga=Decimal(str(carga_d.get("valor_carga", 0))), |
| peso_kg=Decimal(str(carga_d.get("peso_kg", 0))), |
| ) |
| transp_d = params.get("transporte", {}) |
| transporte = DadosTransporte( |
| rntrc=transp_d.get("rntrc", "00000000"), |
| placa_veiculo=transp_d.get("placa", "AAA0000"), |
| uf_veiculo=transp_d.get("uf_veiculo", "SP"), |
| data_prevista_entrega=_date.today(), |
| ) |
| documentos = [ |
| DocumentoReferenciado(chave_nfe=c) |
| for c in params.get("chaves_nfe", []) |
| ] |
| gerador = GeradorCTe( |
| emitente=emitente, |
| remetente=remetente, |
| destinatario=destinatario, |
| carga=carga, |
| documentos=documentos, |
| transporte=transporte, |
| numero=str(params.get("numero", "1")), |
| ambiente=str(params.get("ambiente", "2")), |
| ) |
| caminho = gerador.salvar(self.diretorio_saida) |
| return {"tipo": "CTe", "arquivo": str(caminho), "valido": True, "erros": []} |
|
|
| def gerar_nfce(self, params: dict) -> dict: |
| """Gera a NFC-e (Nota Fiscal do Consumidor Eletrônica, modelo 65).""" |
| from src.generators.nfce_xml import GeradorNFCeXML, ConsumidorNFCe |
| emitente = params.get("_emitente_obj") |
| itens = params.get("_itens_obj", []) |
| if emitente is None or not itens: |
| return {"erro": "Forneça '_emitente_obj' e '_itens_obj' em params"} |
| cons_d = params.get("consumidor", {}) |
| consumidor = ConsumidorNFCe( |
| cpf=cons_d.get("cpf", ""), |
| nome=cons_d.get("nome", "CONSUMIDOR"), |
| uf=cons_d.get("uf", "SP"), |
| ) |
| gerador = GeradorNFCeXML( |
| emitente=emitente, |
| itens=itens, |
| consumidor=consumidor, |
| numero=str(params.get("numero", "1")), |
| forma_pagamento=str(params.get("forma_pagamento", "01")), |
| ambiente=str(params.get("ambiente", "2")), |
| ) |
| caminho = gerador.salvar(self.diretorio_saida) |
| return {"tipo": "NFCe", "arquivo": str(caminho), "valido": True, "erros": []} |
|
|
| def gerar_mdfe(self, params: dict) -> dict: |
| """Gera o MDF-e (Manifesto de Documentos Fiscais Eletrônicos).""" |
| from src.generators.mdfe import GeradorMDFe, MunicipioDescarga, DocumentoMDFe, ConductorMDFe, SeguroMDFe |
| emitente = params.get("_emitente_obj") |
| if emitente is None: |
| return {"erro": "Forneça '_emitente_obj' em params"} |
| municipios = [ |
| MunicipioDescarga( |
| cod_municipio=m.get("cod_municipio", ""), |
| nome_municipio=m.get("nome", ""), |
| uf=m.get("uf", "SP"), |
| documentos=[DocumentoMDFe(chave=d["chave"], tipo=d.get("tipo", "NFe")) |
| for d in m.get("documentos", [])], |
| ) |
| for m in params.get("municipios", []) |
| ] |
| condutores = [ |
| ConductorMDFe(nome=c.get("nome", ""), cpf=c.get("cpf", "")) |
| for c in params.get("condutores", []) |
| ] |
| seg_d = params.get("seguro", {}) |
| seguro = SeguroMDFe( |
| resp_seg=seg_d.get("resp_seg", "1"), |
| cnpj_seg=seg_d.get("cnpj_seg", ""), |
| nome_seg=seg_d.get("nome_seg", ""), |
| nApol=seg_d.get("nApol", ""), |
| nCT=seg_d.get("nCT", []), |
| ) |
| gerador = GeradorMDFe( |
| emitente=emitente, |
| municipios_descarrega=municipios, |
| condutores=condutores, |
| seguro=seguro, |
| uf_ini=params.get("uf_ini", "SP"), |
| uf_fim=params.get("uf_fim", "SP"), |
| placa_veiculo=params.get("placa", "AAA0000"), |
| uf_veiculo=params.get("uf_veiculo", "SP"), |
| rntrc=params.get("rntrc", "00000000"), |
| numero=str(params.get("numero", "1")), |
| ambiente=str(params.get("ambiente", "2")), |
| ) |
| caminho = gerador.salvar(self.diretorio_saida) |
| return {"tipo": "MDFe", "arquivo": str(caminho), "valido": True, "erros": []} |
|
|
| def gerar_dirf(self, params: dict) -> dict: |
| """Gera o arquivo DIRF (Declaração do IR Retido na Fonte) anual.""" |
| from src.generators.dirf import GeradorDIRF, BeneficiarioDIRF, ResponsavelDIRF |
| empresa = params.get("_empresa_obj") |
| if empresa is None: |
| return {"erro": "Forneça '_empresa_obj' em params"} |
| resp_d = params.get("responsavel", {}) |
| responsavel = ResponsavelDIRF( |
| cpf=resp_d.get("cpf", ""), |
| nome=resp_d.get("nome", "RESPONSÁVEL"), |
| cargo=resp_d.get("cargo", "CONTADOR"), |
| ddd=resp_d.get("ddd", "11"), |
| telefone=resp_d.get("telefone", ""), |
| ) |
| bens = [ |
| BeneficiarioDIRF( |
| cpf_cnpj=b.get("cpf_cnpj", ""), |
| nome=b.get("nome", ""), |
| tipo=b.get("tipo", "PF"), |
| cod_receita=b.get("cod_receita", "0561"), |
| rendimentos_por_mes={int(k): Decimal(str(v)) for k, v in b.get("rendimentos", {}).items()}, |
| ir_retido_por_mes={int(k): Decimal(str(v)) for k, v in b.get("ir_retido", {}).items()}, |
| ) |
| for b in params.get("beneficiarios", []) |
| ] |
| gerador = GeradorDIRF( |
| empresa=empresa, |
| ano_calendario=int(params.get("ano", date.today().year - 1)), |
| beneficiarios=bens, |
| responsavel=responsavel, |
| ) |
| caminho = gerador.salvar(self.diretorio_saida) |
| return {"tipo": "DIRF", "arquivo": str(caminho), "valido": True, "erros": []} |
|
|
| def gerar_defis(self, params: dict) -> dict: |
| """Gera o XML DEFIS (Declaração Anual do Simples Nacional).""" |
| from src.generators.defis import GeradorDEFIS, ReceitaMensalDEFIS, SocioDEFIS |
| empresa = params.get("_empresa_obj") |
| if empresa is None: |
| return {"erro": "Forneça '_empresa_obj' em params"} |
| receitas = [ |
| ReceitaMensalDEFIS( |
| mes=r["mes"], |
| receita_bruta_total=Decimal(str(r.get("receita_bruta_total", 0))), |
| receita_bruta_exportacao=Decimal(str(r.get("receita_bruta_exportacao", 0))), |
| receita_bruta_isenta=Decimal(str(r.get("receita_bruta_isenta", 0))), |
| ) |
| for r in params.get("receitas_mensais", []) |
| ] |
| socios = [ |
| SocioDEFIS( |
| cpf_cnpj=s.get("cpf_cnpj", ""), |
| nome=s.get("nome", ""), |
| percentual_capital=Decimal(str(s.get("percentual_capital", 100))), |
| ) |
| for s in params.get("socios", []) |
| ] |
| gerador = GeradorDEFIS( |
| empresa=empresa, |
| ano_calendario=int(params.get("ano", date.today().year - 1)), |
| receitas_mensais=receitas, |
| socios=socios, |
| ) |
| caminho = gerador.salvar(self.diretorio_saida) |
| return {"tipo": "DEFIS", "arquivo": str(caminho), "valido": True, "erros": [], |
| "relatorio": gerador.relatorio_resumo()} |
|
|
| def gerar_destda(self, params: dict) -> dict: |
| """Gera o XML DeSTDA (ICMS-ST e DIFAL do Simples Nacional).""" |
| from src.generators.destda import GeradorDeSTDA, OperacaoSTDeSTDA |
| empresa = params.get("_empresa_obj") |
| if empresa is None: |
| return {"erro": "Forneça '_empresa_obj' em params"} |
| operacoes = [ |
| OperacaoSTDeSTDA( |
| uf_origem=o.get("uf_origem", "SP"), |
| uf_destino=o.get("uf_destino", "SP"), |
| tipo=o.get("tipo", "ST"), |
| base_calculo=Decimal(str(o.get("base_calculo", 0))), |
| aliquota=Decimal(str(o.get("aliquota", 18))), |
| valor_imposto=Decimal(str(o.get("valor_imposto", 0))), |
| valor_pago=Decimal(str(o.get("valor_pago", 0))), |
| ) |
| for o in params.get("operacoes", []) |
| ] |
| gerador = GeradorDeSTDA( |
| empresa=empresa, |
| periodo=params.get("periodo", date.today().strftime("%Y-%m")), |
| operacoes=operacoes, |
| uf_declarante=params.get("uf_declarante", "SP"), |
| ) |
| caminho = gerador.salvar(self.diretorio_saida) |
| return {"tipo": "DeSTDA", "arquivo": str(caminho), "valido": True, "erros": [], |
| "relatorio": gerador.relatorio_resumo(), "vencimento": gerador.data_vencimento().isoformat()} |
|
|
| def gerar_gia(self, params: dict) -> dict: |
| """Gera o arquivo AIE da GIA/GIA-ST (São Paulo).""" |
| from src.generators.gia import GeradorGIA, ApuracaoGIA, ApuracaoGIAST |
| empresa = params.get("_empresa_obj") |
| if empresa is None: |
| return {"erro": "Forneça '_empresa_obj' em params"} |
| apur_d = params.get("apuracao", {}) |
| apuracao = ApuracaoGIA( |
| debitos_operacoes_proprias=Decimal(str(apur_d.get("debitos_operacoes_proprias", 0))), |
| debitos_st_retencao=Decimal(str(apur_d.get("debitos_st_retencao", 0))), |
| estorno_credito=Decimal(str(apur_d.get("estorno_credito", 0))), |
| outros_debitos=Decimal(str(apur_d.get("outros_debitos", 0))), |
| creditos_entradas=Decimal(str(apur_d.get("creditos_entradas", 0))), |
| creditos_outros=Decimal(str(apur_d.get("creditos_outros", 0))), |
| estorno_debito=Decimal(str(apur_d.get("estorno_debito", 0))), |
| outros_creditos=Decimal(str(apur_d.get("outros_creditos", 0))), |
| compensacoes=Decimal(str(apur_d.get("compensacoes", 0))), |
| saldo_credor_anterior=Decimal(str(apur_d.get("saldo_credor_anterior", 0))), |
| ) |
| sts = [ |
| ApuracaoGIAST( |
| uf_substituto=s.get("uf", ""), |
| base_calculo=Decimal(str(s.get("base_calculo", 0))), |
| aliquota=Decimal(str(s.get("aliquota", 18))), |
| imposto_retido=Decimal(str(s.get("imposto_retido", 0))), |
| valor_entradas_st=Decimal(str(s.get("valor_entradas_st", 0))), |
| ) |
| for s in params.get("apuracoes_st", []) |
| ] |
| gerador = GeradorGIA( |
| empresa=empresa, |
| periodo=params.get("periodo", date.today().strftime("%Y-%m")), |
| apuracao=apuracao, |
| apuracoes_st=sts, |
| ) |
| caminho = gerador.salvar(self.diretorio_saida) |
| return {"tipo": "GIA", "arquivo": str(caminho), "valido": True, "erros": [], |
| "relatorio": gerador.relatorio_resumo(), |
| "icms_a_recolher": float(gerador.icms_a_recolher)} |
|
|
| def verificar_sefaz(self, uf: str = "SP", ambiente: str = "2") -> dict: |
| """Verifica a disponibilidade dos serviços SEFAZ para a UF.""" |
| from src.transmitters.receita_federal import TransmissorNFe |
| t = TransmissorNFe(uf=uf, ambiente=ambiente) |
| r = t.verificar_status_servico() |
| return { |
| "uf": uf, |
| "ambiente": "homologação" if ambiente == "2" else "produção", |
| "sucesso": r.sucesso, |
| "codigo": r.codigo_retorno, |
| "mensagem": r.mensagem, |
| "timestamp": r.timestamp.isoformat(), |
| } |
|
|
| def treinar( |
| self, |
| exemplos: Optional[list] = None, |
| epochs: int = 30, |
| caminho_saida: str = "modelo_fiscal.pt", |
| ) -> dict: |
| """ |
| Treina o TransformerFiscal com exemplos de classificação. |
| |
| Args: |
| exemplos: Lista de ExemploTreinamento. Se None, usa os 70+ exemplos padrão. |
| epochs: Número de épocas de treinamento. |
| caminho_saida: Caminho para salvar o modelo treinado. |
| |
| Returns: |
| Histórico de treinamento com loss e acurácia por época. |
| """ |
| from src.models.trainer import TrainerFiscal, EXEMPLOS_CLASSIFICACAO |
| exemplos = exemplos or EXEMPLOS_CLASSIFICACAO |
| trainer = TrainerFiscal(self.modelo, self.tokenizador, epochs=epochs, device=self.device) |
| historico = trainer.treinar(exemplos, caminho_saida=caminho_saida) |
| return historico |
|
|
| |
| |
| |
|
|
| def calcular_icms(self, params: dict) -> dict: |
| from src.calculators.icms import ParametrosICMS, calcular_icms |
| p = ParametrosICMS( |
| valor_mercadoria=Decimal(str(params.get("valor_mercadoria", 0))), |
| aliquota=Decimal(str(params.get("aliquota", 18))), |
| cst=params.get("cst", "000"), |
| uf_origem=params.get("uf_origem", "SP"), |
| uf_destino=params.get("uf_destino", "SP"), |
| reducao_base=Decimal(str(params.get("reducao_base", 0))), |
| frete=Decimal(str(params.get("frete", 0))), |
| seguro=Decimal(str(params.get("seguro", 0))), |
| outras_despesas=Decimal(str(params.get("outras_despesas", 0))), |
| desconto=Decimal(str(params.get("desconto", 0))), |
| calcular_difal=params.get("calcular_difal", False), |
| consumidor_final=params.get("consumidor_final", False), |
| ) |
| r = calcular_icms(p) |
| return { |
| "base_calculo": float(r.base_calculo), |
| "aliquota": float(r.aliquota), |
| "valor_icms": float(r.valor_icms), |
| "valor_icms_st": float(r.valor_st), |
| "valor_fcp": float(r.valor_fcp), |
| "valor_difal": float(r.valor_difal_destino + r.valor_difal_origem), |
| "valor_total_icms": float(r.valor_total_icms), |
| } |
|
|
| def calcular_ipi(self, params: dict) -> dict: |
| from src.calculators.ipi import ParametrosIPI, calcular_ipi |
| p = ParametrosIPI( |
| valor_produtos=Decimal(str(params.get("valor_produtos", 0))), |
| aliquota=Decimal(str(params.get("aliquota", 5))), |
| cst=params.get("cst", "50"), |
| frete=Decimal(str(params.get("frete", 0))), |
| ) |
| r = calcular_ipi(p) |
| return { |
| "base_calculo": float(r.base_calculo), |
| "aliquota": float(r.aliquota), |
| "valor_ipi": float(r.valor_tributo), |
| } |
|
|
| def calcular_pis_cofins(self, params: dict) -> dict: |
| from src.calculators.pis_cofins import ReceitaBruta, calcular_pis_cofins |
| from src.fiscal.entities import RegimeTributario |
| receitas = [ |
| ReceitaBruta( |
| descricao=r.get("descricao", "Receita"), |
| valor=Decimal(str(r.get("valor", 0))), |
| cst_pis=r.get("cst_pis", "01"), |
| cst_cofins=r.get("cst_cofins", "01"), |
| ) |
| for r in params.get( |
| "receitas", |
| [{"descricao": "Receita", "valor": params.get("valor", 0)}], |
| ) |
| ] |
| regime_map = { |
| "lucro_real": RegimeTributario.LUCRO_REAL, |
| "lucro_presumido": RegimeTributario.LUCRO_PRESUMIDO, |
| "simples": RegimeTributario.SIMPLES_NACIONAL, |
| } |
| regime = regime_map.get(params.get("regime", "lucro_presumido"), RegimeTributario.LUCRO_PRESUMIDO) |
| r = calcular_pis_cofins(receitas, regime) |
| return { |
| "regime": r.regime, |
| "base_pis": float(r.base_pis), |
| "aliquota_pis": float(r.aliq_pis), |
| "valor_pis": float(r.valor_pis_debito), |
| "creditos_pis": float(r.creditos_pis), |
| "pis_a_recolher": float(r.pis_a_recolher), |
| "base_cofins": float(r.base_cofins), |
| "aliquota_cofins": float(r.aliq_cofins), |
| "valor_cofins": float(r.valor_cofins_debito), |
| "creditos_cofins": float(r.creditos_cofins), |
| "cofins_a_recolher": float(r.cofins_a_recolher), |
| } |
|
|
| def calcular_irpj_csll(self, params: dict) -> dict: |
| from src.calculators.irpj_csll import ( |
| calcular_csll_lucro_presumido, calcular_csll_lucro_real, |
| calcular_irpj_lucro_presumido, calcular_irpj_lucro_real, |
| ) |
| regime = params.get("regime", "lucro_presumido") |
| valor = Decimal(str(params.get("valor", 0))) |
| atividade = params.get("atividade", "venda_mercadorias") |
| if regime == "lucro_real": |
| irpj = calcular_irpj_lucro_real(lucro_antes_ir=valor) |
| csll = calcular_csll_lucro_real(lucro_antes_csll=valor) |
| else: |
| irpj = calcular_irpj_lucro_presumido(receita_bruta=valor, atividade=atividade) |
| csll = calcular_csll_lucro_presumido( |
| receita_bruta=valor, |
| atividade="comercio_industria" if atividade != "servicos_em_geral" else "servicos_em_geral", |
| ) |
| return { |
| "regime": regime, |
| "base_irpj": float(irpj.base_calculo), |
| "valor_irpj_base": float(irpj.valor_base), |
| "valor_irpj_adicional": float(irpj.valor_adicional), |
| "irpj_total": float(irpj.valor_irpj_total), |
| "irpj_a_recolher": float(irpj.irpj_a_recolher), |
| "base_csll": float(csll.base_calculo), |
| "aliquota_csll": float(csll.aliquota), |
| "csll_total": float(csll.valor_csll), |
| "csll_a_recolher": float(csll.csll_a_recolher), |
| "total_impostos": float(irpj.irpj_a_recolher + csll.csll_a_recolher), |
| } |
|
|
| def calcular_iss(self, params: dict) -> dict: |
| from src.calculators.iss import ParametrosISS, calcular_iss |
| p = ParametrosISS( |
| valor_servico=Decimal(str(params.get("valor_servico", 0))), |
| codigo_servico=params.get("codigo_servico", "17"), |
| aliquota_municipal=Decimal(str(params["aliquota"])) if "aliquota" in params else None, |
| retencao_fonte=params.get("retencao_fonte", False), |
| ) |
| r = calcular_iss(p) |
| return { |
| "base_calculo": float(r.base_calculo), |
| "aliquota": float(r.aliquota), |
| "valor_iss": float(r.valor_tributo), |
| "retencao_na_fonte": p.retencao_fonte, |
| } |
|
|
| def calcular_simples(self, params: dict) -> dict: |
| from src.calculators.simples_nacional import calcular_das |
| receita_mes = Decimal(str(params.get("receita_mes", 0))) |
| rbt12 = Decimal(str(params.get("rbt12", receita_mes * 12))) |
| anexo = params.get("anexo", "I") |
| r = calcular_das(receita_mes=receita_mes, rbt12=rbt12, anexo=anexo) |
| return { |
| "receita_mes": float(receita_mes), |
| "rbt12": float(rbt12), |
| "anexo": anexo, |
| "faixa": r.faixa, |
| "aliquota_nominal": float(r.aliquota_nominal), |
| "aliquota_efetiva": float(r.aliquota_efetiva), |
| "valor_das": float(r.valor_das), |
| "partilha": {k: float(v) for k, v in r.partilha.items()}, |
| } |
|
|
| def calcular_pgdas(self, params: dict) -> dict: |
| from src.calculators.simples_nacional import calcular_pgdas |
| periodo = params.get("periodo", date.today().strftime("%Y-%m")) |
| atividades = params.get("atividades", [{"tipo": "comercio", "receita": params.get("receita_mes", 0)}]) |
| rbt12 = Decimal(str(params.get("rbt12", 0))) |
| r = calcular_pgdas( |
| periodo=periodo, |
| atividades=[{"tipo": a["tipo"], "receita": Decimal(str(a["receita"]))} for a in atividades], |
| rbt12=rbt12, |
| ) |
| return { |
| "periodo": r.periodo, |
| "rbt12": float(r.rbt12), |
| "receita_total_mes": float(r.receita_total_mes), |
| "valor_total_das": float(r.valor_total_das), |
| "data_vencimento": r.data_vencimento.isoformat(), |
| "atividades": [ |
| { |
| "tipo": a.tipo, |
| "receita": float(a.receita), |
| "anexo": a.anexo, |
| "aliquota_efetiva": float(a.resultado.aliquota_efetiva), |
| "valor_das": float(a.resultado.valor_das), |
| } |
| for a in r.atividades |
| ], |
| } |
|
|
| |
| |
| |
|
|
| def _gerar_sped(self, obrigacao: str, periodo: Any) -> dict: |
| from src.generators.efd_icms_ipi import GeradorEFDICMSIPI |
| from src.generators.efd_contribuicoes import GeradorEFDContribuicoes |
| from src.generators.ecd import GeradorECD |
| from src.generators.ecf import GeradorECF |
| from src.generators.dctf import montar_dctf_do_periodo |
| from src.transmitters.receita_federal import TransmissorSPEDLocal, ValidadorArquivoSPED |
|
|
| transmissor = TransmissorSPEDLocal(self.diretorio_saida) |
|
|
| if obrigacao == "EFD_ICMS_IPI": |
| caminho = GeradorEFDICMSIPI(periodo).gerar(self.diretorio_saida) |
| return transmissor.preparar_efd_icms_ipi(caminho) |
|
|
| if obrigacao == "EFD_CONTRIBUICOES": |
| caminho = GeradorEFDContribuicoes(periodo).gerar(self.diretorio_saida) |
| return transmissor.preparar_efd_contribuicoes(caminho) |
|
|
| if obrigacao == "ECD": |
| caminho = GeradorECD(periodo).gerar(self.diretorio_saida) |
| return transmissor.preparar_ecd(caminho) |
|
|
| if obrigacao == "ECF": |
| caminho = GeradorECF(periodo).gerar(self.diretorio_saida) |
| _, erros = ValidadorArquivoSPED().validar(caminho) |
| import hashlib |
| return { |
| "tipo": "ECF", |
| "arquivo": str(caminho), |
| "valido": not erros, |
| "erros": erros, |
| "hash_md5": hashlib.md5(caminho.read_bytes()).hexdigest(), |
| "tamanho_bytes": caminho.stat().st_size, |
| } |
|
|
| if obrigacao == "DCTF": |
| gerador = montar_dctf_do_periodo( |
| empresa=periodo.empresa, |
| periodo=periodo.data_inicio.strftime("%Y-%m"), |
| ) |
| caminho = gerador.salvar(self.diretorio_saida) |
| return { |
| "tipo": "DCTF", |
| "arquivo": str(caminho), |
| "valido": True, |
| "erros": [], |
| "relatorio": gerador.relatorio_resumo(), |
| "tamanho_bytes": caminho.stat().st_size, |
| } |
|
|
| return {"erro": f"Obrigação desconhecida: {obrigacao}"} |
|
|
| |
| |
| |
|
|
| def _detectar_operacao(self, query: str, intencoes: list[tuple[str, float]]) -> Optional[str]: |
| q = query.lower() |
| for operacao, palavras in self._MAPA_PALAVRAS.items(): |
| if any(p in q for p in palavras): |
| return operacao |
| if intencoes: |
| top = intencoes[0][0] |
| if "calculo" in top: |
| return f"calcular_{top.replace('calculo_', '')}" |
| mapa = { |
| "EFD_ICMS_IPI": "gerar_efd_icms_ipi", |
| "EFD_CONTRIBUICOES": "gerar_efd_contribuicoes", |
| "ECD": "gerar_ecd", |
| "ECF": "gerar_ecf", |
| "DCTF": "gerar_dctf", |
| "eSocial": "gerar_esocial", |
| "EFD_REINF": "gerar_efd_reinf", |
| "PGDAS": "calcular_pgdas", |
| } |
| return mapa.get(top) |
| return None |
|
|
| def _executar(self, operacao: str, params: dict) -> dict: |
| metodos = { |
| "calcular_icms": self.calcular_icms, |
| "calcular_ipi": self.calcular_ipi, |
| "calcular_pis_cofins": self.calcular_pis_cofins, |
| "calcular_irpj_csll": self.calcular_irpj_csll, |
| "calcular_iss": self.calcular_iss, |
| "calcular_simples": self.calcular_simples, |
| "calcular_pgdas": self.calcular_pgdas, |
| "gerar_cte": self.gerar_cte, |
| "gerar_nfce": self.gerar_nfce, |
| "gerar_mdfe": self.gerar_mdfe, |
| "gerar_dirf": self.gerar_dirf, |
| "gerar_defis": self.gerar_defis, |
| "gerar_destda": self.gerar_destda, |
| "gerar_gia": self.gerar_gia, |
| "verificar_sefaz": self.verificar_sefaz, |
| } |
| if operacao in metodos: |
| try: |
| return metodos[operacao](params) |
| except Exception as e: |
| return {"erro": str(e)} |
| return {"erro": f"Operação '{operacao}' requer PeriodoApuracao — use gerar_obrigacoes()"} |
|
|
|
|
| |
| |
| |
|
|
| def criar_pipeline_fiscal( |
| caminho_modelo: Optional[str | Path] = None, |
| device: Optional[str] = None, |
| ) -> tuple[TransformerFiscal, TokenizadorFiscal, BancoEmbeddingsFiscais, ClassificadorIntencaoFiscal]: |
| """Instancia os componentes individuais do pipeline (uso avançado).""" |
| pipeline = PipelineFiscal(caminho_modelo=caminho_modelo, device=device) |
| return pipeline.modelo, pipeline.tokenizador, pipeline.rag, pipeline.classificador |
|
|
|
|
| |
| |
| |
|
|
| BASE_CONHECIMENTO_FISCAL = [ |
| "A EFD ICMS IPI é a Escrituração Fiscal Digital que substitui os livros fiscais de ICMS e IPI. " |
| "Deve ser entregue mensalmente até o 15º dia útil do mês subsequente. " |
| "Obrigatória para contribuintes do ICMS e IPI, exceto optantes do Simples Nacional.", |
|
|
| "O arquivo EFD ICMS IPI é composto pelos blocos: 0 (identificação), C (NF-e mercadorias), " |
| "D (documentos de transporte), E (apuração ICMS e IPI), G (CIAP), H (inventário), " |
| "K (produção), 1 (outros), 9 (controle). Cada bloco começa com registro X001 e termina com X990.", |
|
|
| "No Bloco E da EFD ICMS IPI, o registro E110 contém a apuração do ICMS: " |
| "VL_TOT_DEBITOS - VL_TOT_CREDITOS = saldo devedor (ICMS a recolher) ou credor (transportar).", |
|
|
| "A EFD Contribuições escritura a apuração de PIS/PASEP e COFINS. " |
| "Entregue mensalmente até o 10º dia útil do 2º mês subsequente. " |
| "Obrigatória para pessoas jurídicas sujeitas ao IRPJ (Lucro Real e Presumido).", |
|
|
| "PIS não-cumulativo (Lucro Real): alíquota 1,65%. " |
| "COFINS não-cumulativa (Lucro Real): alíquota 7,60%. " |
| "PIS cumulativo (Lucro Presumido): alíquota 0,65%. " |
| "COFINS cumulativa (Lucro Presumido): alíquota 3,00%.", |
|
|
| "Créditos de PIS/COFINS (regime não-cumulativo, Lucro Real) podem ser tomados sobre: " |
| "aquisições de mercadorias para revenda, insumos, energia elétrica, aluguéis, " |
| "depreciação de máquinas e equipamentos, entre outros (Lei 10.637/2002 e 10.833/2003).", |
|
|
| "A ECD (Escrituração Contábil Digital) é obrigatória para todas as pessoas jurídicas " |
| "sujeitas ao IRPJ pelo Lucro Real. Entregue até o último dia útil de junho do ano seguinte. " |
| "Contém livro diário, razão e balancetes.", |
|
|
| "A ECF (Escrituração Contábil Fiscal) substitui a DIPJ. " |
| "Obrigatória para pessoas jurídicas tributadas pelo IRPJ (Lucro Real, Presumido ou Arbitrado). " |
| "Entregue até o último dia útil de julho do ano seguinte.", |
|
|
| "O ICMS (Imposto sobre Circulação de Mercadorias e Serviços) é estadual. " |
| "Base de cálculo: valor da mercadoria + frete + seguro + outras despesas. " |
| "Alíquotas internas variam por estado (17% a 22%). " |
| "Alíquotas interestaduais: 4%, 7% ou 12%.", |
|
|
| "Substituição Tributária (ST) de ICMS: o responsável tributário recolhe o imposto " |
| "de toda a cadeia. A base ST é calculada pela MVA (Margem de Valor Agregado): " |
| "Base ST = Base ICMS próprio × (1 + MVA%). ICMS ST = Base ST × alíquota interna - ICMS próprio.", |
|
|
| "DIFAL (Diferencial de Alíquota - EC 87/2015): aplicável em operações interestaduais " |
| "para consumidor final não contribuinte. DIFAL = Base × (alíquota interna - alíquota interestadual). " |
| "100% para o estado de destino a partir de 2019.", |
|
|
| "O IPI (Imposto sobre Produtos Industrializados) é federal, incide na saída de produtos " |
| "do estabelecimento industrial ou a ele equiparado. " |
| "Alíquotas variam por produto conforme a TIPI (Tabela de Incidência do IPI). " |
| "Base de cálculo: valor total da operação.", |
|
|
| "IRPJ (Lucro Real): 15% sobre lucro real + adicional de 10% sobre lucro que exceder " |
| "R$20.000/mês ou R$60.000/trimestre. " |
| "Lucro real = lucro contábil + adições - exclusões - compensações de prejuízos.", |
|
|
| "IRPJ (Lucro Presumido): alíquota 15% + adicional 10% sobre lucro presumido. " |
| "Lucro presumido = % sobre receita bruta: 8% para comércio/indústria, 32% para serviços. " |
| "Apuração trimestral.", |
|
|
| "CSLL: alíquota 9% para empresas em geral, 15% para instituições financeiras. " |
| "No Lucro Presumido: base de presunção 12% (comércio/indústria) ou 32% (serviços).", |
|
|
| "ISS (Imposto sobre Serviços): municipal, regido pela LC 116/2003. " |
| "Alíquota mínima 2%, máxima 5%. " |
| "Incide sobre prestação de serviços da lista anexa à LC 116/2003. " |
| "Retenção obrigatória pelo tomador para serviços específicos.", |
|
|
| "NF-e (Nota Fiscal Eletrônica - Modelo 55): documento fiscal eletrônico para operações " |
| "com mercadorias. Autorização via SEFAZ (webservice). " |
| "Chave de acesso: 44 dígitos. Protocolada com nProt. " |
| "Validade: 24 horas após emissão (cancelamento).", |
|
|
| "NFC-e (Nota Fiscal de Consumidor Eletrônica - Modelo 65): para vendas a consumidor final " |
| "presencial (PDV/frente de caixa). Substituiu o ECF (cupom fiscal).", |
|
|
| "e-Social: escrituração digital das obrigações fiscais, previdenciárias e trabalhistas. " |
| "Substitui GFIP, RAIS, CAGED, DIRF, MANAD, PPP, SEFIP entre outros. " |
| "Grupos de eventos: S-1000 (empregador), S-2200 (trabalhadores), S-2299/2399 (rescisão).", |
|
|
| "EFD-Reinf: escrituração de retenções e informações da previdência social. " |
| "Substitui parte da GFIP. Obrigatória para empresas que retêm IR, CSLL, PIS, COFINS " |
| "de serviços prestados por PJ, e que pagam rendimentos a PF/PJ sujeitos a retenção.", |
|
|
| "DCTF (Declaração de Débitos e Créditos Tributários Federais): informa débitos apurados " |
| "e pagamentos/compensações dos tributos federais. " |
| "Entregue mensalmente até o 15º dia útil do 2º mês subsequente.", |
|
|
| "Simples Nacional: regime unificado de arrecadação. " |
| "Abrange IRPJ, CSLL, PIS, COFINS, IPI, CPP, ICMS e ISS em documento único (DAS). " |
| "Obrigações acessórias: PGDAS-D (mensal, até dia 20), DEFIS (anual, até 31/03), " |
| "e-Social simplificado para folha.", |
|
|
| "DARF (Documento de Arrecadação de Receitas Federais): guia de recolhimento para tributos federais. " |
| "Código de receita identifica o tributo: 6912=IRPJ estimativa, 2089=IRPJ LP, " |
| "8109=PIS não-cumulativo, 2172=COFINS não-cumulativa.", |
|
|
| "Calendário fiscal mensal: DAS Simples até dia 20; DARF IRPJ estimativa até último dia útil; " |
| "DARF PIS/COFINS até dia 25; EFD ICMS/IPI até 15º dia útil; DCTF até 15º dia útil do 2º mês.", |
|
|
| "Calendário fiscal anual: ECF até último dia útil de julho; ECD até último dia útil de junho; " |
| "DIRF até último dia útil de fevereiro; RAIS até data definida pelo MT.", |
| ] |
|
|