Pular para conteúdo

Geração de NF-e — TX2 (TecnoSpeed) — Mapeamento Profundo

Objetivo

Documentação rastreável, campo a campo, da geração da NF-e no formato TX2. Para cada campo TX2 documentamos: 1. De onde vem o valor (tabela Odoo + campo exato) 2. Quem preenche esse campo (motor fiscal, cadastro manual, regra automática) 3. Como alterar (configuração, parâmetro, ou código) 4. Cadeia de prioridade quando há múltiplas fontes


Método Principal

Método Arquivo Linha Descrição
_gerar_nfe_tx2(gerar_nf=True) account.py 2877 Monta o payload TX2 completo
action_gerar_nfe() account.py 5351 Orquestra: numeração + TX2 + envio API
action_previsualizar_danfe_nfe() account.py 5064 Usa _gerar_nfe_tx2(gerar_nf=False) para preview
action_validar_nfe() account.py 5280 Usa TX2 + endpoint nfe/valida

Autenticação TecnoSpeed (ManagerSaaS)

Parâmetro Cadeia de Origem Menu de Configuração
URL base Fatura → Operação Fiscal → Documento Fiscal → l10n_br_url Vendas → Configuração → Fiscal → Tipo Documento → URL
Grupo Fatura → Operação Fiscal → Documento Fiscal → l10n_br_grupo Idem → Grupo
Usuário Fatura → Operação Fiscal → Documento Fiscal → l10n_br_usuario Idem → Usuário
Senha Fatura → Operação Fiscal → Documento Fiscal → l10n_br_senha Idem → Senha
CNPJ Fatura → Empresa → l10n_br_cnpj (sem formatação) Configurações → Empresa

Método de autenticação: HTTP Basic Auth via HTTPBasicAuth(usuario, senha)


Estrutura TX2 — Blocos

INCLUIR                          ← Cabeçalho + Emitente + Destinatário + Totais + Frete
  INCLUIRPARTE=AUTXML            ← Autorizados XML (por empresa)
  SALVARPARTE=AUTXML
  INCLUIRITEM                    ← Para cada linha de produto
    INCLUIRPARTE=I80 / DI / ADI  ← Sub-blocos (lotes, DI, Adição)
    SALVARPARTE=I80 / DI / ADI
  SALVARITEM
  INCLUIRCOBRANCA                ← Duplicatas/parcelas
  SALVARCOBRANCA
  INCLUIRPARTE=YA                ← Meios de pagamento
  SALVARPARTE=YA
  INCLUIRPARTE=VOL               ← Volumes
  SALVARPARTE=VOL
  INCLUIRPARTE=NREF              ← NF-e referenciadas
  SALVARPARTE=NREF
SALVAR

Numeração e Data

Número da NF

Situação Comportamento
l10n_br_numero_nf vazio + gerar_nf=True Gera próximo número via l10n_br_documento_id.l10n_br_numero_nfe_id.next_by_id()
l10n_br_numero_nf preenchido Usa o número existente
gerar_nf=False (preview) Não gera, usa 0 OU gera se parâmetro gerar_sequencia_previsualizar_danfe=1

Onde configurar a sequência: Operação Fiscal → Documento Fiscal → campo "Sequência NF-e" (l10n_br_numero_nfe_id)

Série da NF

Situação Comportamento
l10n_br_serie_nf vazio Copia de l10n_br_documento_id.l10n_br_serie_nfe
l10n_br_serie_nf preenchido Usa o valor da fatura

Data de Emissão

Situação Comportamento
Normal datetime.now(tz='America/Sao_Paulo') — hora atual
l10n_br_data_retroativa = True Usa invoice_date da fatura

BLOCO B — Identificação da NF-e

Campo TX2 Valor Cadeia de Origem Completa Como Alterar
Id_A03 0 🔒 Fixo no código (linha 2955) ❌ Não configurável — código fixo
versao_A02 Ex: 4.00 Fatura → l10n_br_operacao_id → l10n_br_documento_id → l10n_br_versao ✅ Menu: Localização BR → Documentos Fiscais → campo "Versão"
cUF_B02 Ex: 35 Fatura → company_id → state_id → l10n_br_codigo_ibge ✅ Menu: Configurações → Empresa → Estado (o código IBGE vem do cadastro de estados)
cNF_B03 Ex: 12345 Fatura → id (ID interno do registro account.move) ❌ Gerado automaticamente pelo ORM, não configurável
natOp_B04 Ex: VENDA Fatura → l10n_br_operacao_id → descricao_nf ✅ Menu: Localização BR → Operações Fiscais → campo "Descrição na NF"
mod_B06 55 Fatura → l10n_br_operacao_id → l10n_br_documento_id → l10n_br_modelo ✅ Menu: Documentos Fiscais → campo "Modelo" (55=NF-e, 65=NFC-e)
serie_B07 Ex: 1 Prioridade: 1º Fatura.l10n_br_serie_nf → 2º Documento Fiscal.l10n_br_serie_nfe ✅ Menu: Fatura → campo "Série" ou Documentos Fiscais → "Série"
nNF_B08 Ex: 000123 Se vazio: Documento Fiscal → l10n_br_numero_nfe_id.next_by_id(). Se preenchido: Fatura.l10n_br_numero_nf ✅ Configurar sequência em Documentos Fiscais → "Sequência NF-e"
DHEMI_B09 ISO datetime Normal: datetime.now(tz='America/Sao_Paulo'). Retroativa (l10n_br_data_retroativa=True): Fatura.invoice_date com hora 12:00:00 ✅ Data retroativa: flag na fatura
DHSAIENT_B10 ISO datetime Controlado por parâmetro show_datasaida_nf. Se 1: usa Fatura.l10n_br_data_saida (fallback: data emissão) ✅ Parâmetro de sistema + campo na fatura
tpNF_B11 0 ou 1 TIPO_NF[move_type] — dicionário fixo: out_invoice/out_refund → 1 (saída), in_invoice/in_refund → 0 (entrada) ❌ Determinado pelo tipo do documento contábil
IDDEST_B11A 1,2,3 Fatura → l10n_br_cfop_id → l10n_br_destino_operacao — vem do CFOP determinado pelo motor fiscal ✅ Indiretamente via Operação Fiscal (que determina o CFOP)
cMunFG_B12 Ex: 3550308 Fatura → company_id → l10n_br_municipio_id → codigo_ibge ✅ Menu: Empresa → Município
tpImp_B21 1-5 Fatura → l10n_br_operacao_id → l10n_br_documento_id → l10n_br_formato_impressao ✅ Menu: Documentos Fiscais → "Formato de Impressão"
tpEmis_B22 1-9 Fatura → l10n_br_operacao_id → l10n_br_documento_id → l10n_br_tipo_emissao ✅ Menu: Documentos Fiscais → "Tipo de Emissão" (1=Normal, 6-9=Contingência)
tpAmb_B24 1 ou 2 Fatura → l10n_br_operacao_id → l10n_br_documento_id → l10n_br_ambiente ✅ Menu: Documentos Fiscais → "Ambiente" (1=Produção, 2=Homologação)
finNFe_B25 1-4 Fatura → l10n_br_operacao_id → l10n_br_finalidade ✅ Menu: Operações Fiscais → "Finalidade" (1=Normal, 2=Complementar, 3=Ajuste, 4=Devolução)
INDFINAL_B25A 0 ou 1 Fatura → l10n_br_operacao_consumidor — preenchido pelo motor fiscal via operação ✅ Configurável na fatura e controlado pela Operação Fiscal
INDPRES_B25B 0-9 Fatura → l10n_br_indicador_presenca ✅ Campo editável na fatura
procEmi_B26 0 🔒 Fixo no código ❌ Significa "aplicativo do contribuinte"
verProc_B27 Odoo 17 CIEL IT 🔒 Fixo no código (linha 2971) ❌ Para atualizar, exige alteração em código
CRT_C21 1,2,3 Fatura → company_id → l10n_br_regime_tributario ✅ Menu: Empresa → "Regime Tributário" (1=SN, 2=SN Excesso, 3=Lucro Presumido/Real)

BLOCO C — Emitente

Regra especial: Se a operação fiscal tem corredor_importacao_id preenchido, os dados do emitente são substituídos pelo parceiro do corredor de importação (CNPJ, razão social, endereço, IE, telefone).

Campo TX2 Cadeia de Origem Completa Como Alterar
CNPJ_C02 Fatura → company_id → l10n_br_cnpj (removidos ./-) ✅ Empresa → CNPJ
xNome_C03 company_id.l10n_br_razao_social ou company_id.name — formatado por _format_obs() ✅ Empresa → Razão Social
xFant_C04 company_id.name ✅ Empresa → Nome
xLgr_C06 company_id.street ✅ Empresa → Endereço
nro_C07 company_id.l10n_br_endereco_numero (fallback: vazio) ✅ Empresa → Número
xCpl_C08 company_id.street2 (fallback: vazio) ✅ Empresa → Complemento
xBairro_C09 company_id.l10n_br_endereco_bairrotruncado em 60 caracteres ✅ Empresa → Bairro
cMun_C10 company_id → l10n_br_municipio_id → codigo_ibge ✅ Empresa → Município
xMun_C11 company_id → l10n_br_municipio_id → name ✅ Empresa → Município
UF_C12 company_id → state_id → code ✅ Empresa → Estado
CEP_C13 company_id.zip (removidos - e .) ✅ Empresa → CEP
cPais_C14 company_id → country_id → l10n_br_codigo_bacen ✅ Empresa → País (código BACEN é do cadastro do país)
xPais_C15 company_id → country_id → name
fone_C16 company_id.phone — somente dígitos, sem +55 ✅ Empresa → Telefone
IE_C17 company_id.l10n_br_ie ✅ Empresa → Inscrição Estadual
IEST_C18 company_id → l10n_br_iest_ids filtrado por UF do destinatário — l10n_br_iest ✅ Empresa → IEST por UF. Preenchido somente se ICMS ST e parceiro em outra UF

BLOCO E — Destinatário

Campo TX2 Cadeia de Origem Completa Regra Especial Como Alterar
CNPJ_E02 Fatura → partner_id → l10n_br_cnpj Somente se PJ (CNPJ preenchido) ✅ Contatos → CNPJ
CPF_E03 Fatura → partner_id → l10n_br_cpf Somente se PF (CPF preenchido, sem CNPJ) ✅ Contatos → CPF
IDESTRANGEIRO_E03A partner_id → l10n_br_id_estrangeiro Somente se estrangeiro (sem CNPJ e sem CPF) ✅ Contatos → ID Estrangeiro
xNome_E04 Produção: partner_id.l10n_br_razao_social (formatado). Homologação: texto fixo SEFAZ "NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL" Ambiente detectado via l10n_br_documento_id.l10n_br_ambiente ✅ Contatos → Razão Social
INDIEDEST_E16A partner_id → l10n_br_indicador_ie OBRIGATÓRIO — erro se vazio para parceiro brasileiro ✅ Contatos → Indicador IE (1=Contribuinte, 2=Isento, 9=Não Contribuinte)
IE_E17 partner_id → l10n_br_ie Somente se INDIEDEST=1 ✅ Contatos → IE
ISUF_E18 partner_id → l10n_br_is Inscrição SUFRAMA ✅ Contatos → IS
IM_E18A partner_id → l10n_br_im Inscrição Municipal ✅ Contatos → IM
email_e19 partner_id.email Controlado por parâmetro show_email_xml_nf (se 0, não inclui) ✅ Parâmetro + Contatos → Email
Endereço partner_idstreet, l10n_br_endereco_numero, l10n_br_endereco_bairro, l10n_br_municipio_id, state_id, zip, country_id Se exterior: cMun=9999999, UF=EX ✅ Contatos → campos de endereço

BLOCO I — Itens (por linha da fatura)

Filtro de linhas: invoice.invoice_line_ids.filtered(lambda l: l.display_type == 'product'), ordenadas por sequence.

Identificação do Produto

Campo TX2 Cadeia de Origem Completa Quem Preenche Como Alterar
nItem_H02 Sequencial 1..N 🧮 Calculado automaticamente na iteração ❌ Automático
cProd_I02 invoice_line → product_id → default_code 👤 Usuário preenche no cadastro do produto ✅ Vendas → Produtos → "Referência Interna"
cEAN_I03 Se parâmetro ean_xml_nfe=1: product_id.barcode (fallback: SEM GTIN). Se ean_xml_nfe=0: sempre SEM GTIN 👤/🔧 Usuário + parâmetro ✅ Produtos → Código de Barras + Parâmetro l10n_br_ciel_it_account.ean_xml_nfe
cEANTrib_I12 Mesmo que cEAN_I03 Idem Idem
xProd_I04 Produção: invoice_line.name ou product_id.name — primeiros 120 chars, formatado. Homologação: texto fixo SEFAZ. Se split_infoadprod_xprod_xml_nfe=1: split de xProd > 120 chars para infAdProd_V01 👤 Descrição da linha + parâmetro ✅ Linha da fatura → "Descrição"
NCM_I05 invoice_line → product_id → l10n_br_ncm_id → codigo_ncm 👤 Cadastro do produto ✅ Produtos → NCM (obrigatório)
CEST_I05c product_id → l10n_br_ncm_id → codigo_cest 👤 Via NCM do produto ✅ Cadastro do NCM → CEST (somente se preenchido)
nFCI_I70 product_id → l10n_br_fci 👤 Cadastro do produto ✅ Produtos → FCI (Ficha Conteúdo Importação)

Código de Benefício Fiscal (cBenef_I05f)

Cadeia de determinação completa:

Motor fiscal (simulate_impostos) →
  Busca tabela "l10n_br_ciel_it_account.icms.beneficio" onde:
    company_id = empresa atual
    AND (l10n_br_ncm_id = NCM do produto OU l10n_br_ncm_id = vazio)
    AND (l10n_br_origem = origem do produto OU l10n_br_origem = vazio)
    AND (l10n_br_cfop_id = CFOP determinado OU l10n_br_cfop_id = vazio)
    AND l10n_br_icms_cst = CST ICMS determinado
  Prioridade de filtro:
    1º Registros com partner_ids que incluem o parceiro da operação
    2º Registros sem partner_ids (genérico)
    Se múltiplos: usa o primeiro (limit=1)
  Resultado → icms_beneficio.l10n_br_codigo_beneficio
  Se não encontrar → vazio ('')
Aspecto Detalhe
Model Odoo l10n_br_ciel_it_account.icms.beneficio (arquivo product.py linha 758)
Campos de busca company_id, l10n_br_ncm_id, l10n_br_origem, l10n_br_cfop_id, l10n_br_icms_cst, partner_ids
Quem preenche 👤 Equipe fiscal cadastra na tabela de Benefícios ICMS
Onde configurar ✅ Menu: Estoque → Configuração → Benefícios ICMS
Quando usar Quando há benefício fiscal estadual (redução de base, isenção, diferimento) vinculado a um código SEFAZ
Método que usa simulate_impostos() em sale_order.py linha 1295 / sale_order_line._compute_impostos() linha 4538 / account.move.line._compute_impostos() linhas 10231, 11314

CFOP (CFOP_I08)

Cadeia de determinação completa:

Motor fiscal (simulate_impostos) → Seção ##### CFOP #####:
  1. Busca a Operação Fiscal (l10n_br_operacao_id) pelo motor de prioridade
  2. Determina o CFOP por UF:
     - Se UF empresa = UF parceiro → l10n_br_operacao_id.l10n_br_intra_cfop_id (interna)
     - Se País empresa ≠ País parceiro → l10n_br_operacao_id.l10n_br_ext_cfop_id (exterior)
     - Senão → l10n_br_operacao_id.l10n_br_inter_cfop_id (interestadual)
  3. Resultado: CFOP da operação fiscal correspondente à UF da transação
Aspecto Detalhe
Quem preenche 🧮 Motor fiscal determina automaticamente
Onde configurar ✅ Operações Fiscais → CFOPs por tipo (Interno/Interestadual/Exterior)
Campo TX2 invoice_line.l10n_br_cfop_id.codigo_cfop

CST ICMS (CST_N12 / CSOSN_N12a)

Cadeia de prioridade (cada nível sobrescreve o anterior):

Prioridade Fonte Condição
1 (base) Regime tributário Se regime = '3' (Lucro Normal) → CST 00. Senão → CST 101 (SN)
2 Tabela NCM por UF l10n_br_ciel_it_account.ncm.uf filtrada por UF origem/destino + NCM do produto
3 NCM por Origem e UF l10n_br_ciel_it_account.ncm.origem.uf — mais específico que NCM/UF (inclui origem do produto)
4 NCM por IE e UF l10n_br_ciel_it_account.ncm.ie.uf — inclui indicador IE do parceiro
5 NCM por Cliente/UF l10n_br_ciel_it_account.ncm.cliente.uf — específico por parceiro
6 (final) Operação Fiscal l10n_br_operacao_id.l10n_br_icms_cstse preenchido, sempre sobrescreve
Aspecto Detalhe
Onde configurar nível 2-5 ✅ Localização BR → ICMS → NCM por UF / NCM por Origem por UF / NCM por IE por UF / NCM por Cliente por UF
Onde configurar nível 6 ✅ Operações Fiscais → campo "CST ICMS"
Campo na fatura invoice_line.l10n_br_icms_cst
Regra TX2: Se CST tem 2 dígitos → CST_N12. Se 3 dígitos (SN) → CSOSN_N12a

Alíquota e Base ICMS

Campo TX2 Cadeia de Origem Prioridade
pICMS_N16 icms_uf (tabela ICMS UF-UF). 2º ncm_uf (se preenchido). 3º operacao.l10n_br_icms_aliquota Operação sobrescreve, mas usa alíquota UF se não preencher modalidade
vBC_N15 l10n_br_total_nfe + desonerado - ICMSST - FCP_ST. Se contribuinte não final e não uso: subtrai IPI. Se redução: base × (1 - redução/100) 🧮 Calculado pelo motor fiscal
pRedBC_N14 ncm_uf.l10n_br_icms_reducao_base. 2º operacao.l10n_br_icms_reducao_base Operação sobrescreve
vICMS_N17 base × alíquota / 100 🧮 Calculado
orig_N11 invoice_line.l10n_br_origem. 2º fallback: product_id.l10n_br_origem. Erro se ambos vazios (RedirectWarning com link para produtos) ✅ Produtos → "Origem"

IPI

Campo TX2 Cadeia de Prioridade Onde Configurar
CST_O09 1º Default 99. 2º NCM.l10n_br_ipi_cst. 3º CFOP.l10n_br_ipi_cst. 4º (final) Operação.l10n_br_ipi_cst NCM → IPI CST / CFOP → IPI CST / Operação → IPI CST
vBC_O10 Se CST 50: total_nfe + desonerado - ICMSST - FCP_ST - IPI. Se empresa exclui frete: subtrai frete/seguro/desp 🧮 Calculado
pIPI_O13 product_id → l10n_br_ncm_id → l10n_br_ipi_aliquota ✅ NCM → Alíquota IPI
vIPI_O14 base × alíquota / 100 🧮 Calculado
cEnq_O06 ipi_enquadramento (tabela por NCM + CFOP + CST). 2º fallback: NCM.l10n_br_ipi_enq ✅ Localização BR → IPI → Enquadramentos

IPI Enquadramento — busca em cascata na tabela l10n_br_ciel_it_account.ipi.enquadramento: 1. NCM + CFOP + CST ← mais específico 2. (sem NCM) + CFOP + CST 3. (sem NCM) + (sem CFOP) + CST 4. (sem NCM) + (sem CFOP) + (sem CST) ← mais genérico

PIS e COFINS

Campo TX2 Cadeia de Prioridade Onde Configurar
CST_Q06 (PIS), CST_S06 (COFINS) 1º Default 99. 2º Se empresa regime 3: CST 01. 3º NCM.l10n_br_pis_cst / NCM.l10n_br_cofins_cst. 4º CFOP.l10n_br_pis_cst / CFOP.l10n_br_cofins_cst. 5º (final) Operação.l10n_br_pis_cst / Operação.l10n_br_cofins_cst NCM / CFOP / Operação
pPIS_Q08 company_id.l10n_br_pis_aliquota. 2º NCM.l10n_br_pis_aliquota. 3º (final) Operação.l10n_br_pis_aliquota Empresa / NCM / Operação
vBC_Q07 Base: total_nfe - desc. Se pis_inclui_ipi=True: inclui IPI na base 🧮 Calculado
vPIS_Q09 base × aliquota / 100 🧮 Calculado
Idem para COFINS (S06-S11) Mesma cadeia de prioridade mas com campos cofins_* Idem

Valores, Frete e Desconto

Campo TX2 Cadeia de Origem Regra
uCom_I09 invoice_line → infoclient_uom_sefaz (UdM do parceiro). 2º product_id → uom_id → l10n_br_codigo_sefaz_custom. 3º uom_id → l10n_br_codigo_sefaz. Erro se todos vazios ✅ UdM → "Código SEFAZ" ou Produto → Info Client → UdM SEFAZ
qCom_I10 invoice_line.quantity × infoclient_fator_un — formatado com N decimais (parâmetro num_decimal_quantidade_nfe) ✅ Linha → Quantidade + Fator UN
vUnCom_I10a invoice_line.price_unit / infoclient_fator_un — formatado com N decimais (parâmetro num_decimal_valor_unit_nfe) ✅ Linha → Preço Unitário
vProd_I11 invoice_line.l10n_br_prod_valor 🧮 Calculado pelo motor fiscal
vDesc_I17 invoice_line.l10n_br_desc_valor — somente se > 0 ✅ Linha → Desconto
vFrete_I15 invoice_line.l10n_br_frete — somente se > 0 ✅ Linha → Frete
vSeg_I16 invoice_line.l10n_br_seguro — somente se > 0 ✅ Linha → Seguro
vOutro_I17a invoice_line.l10n_br_despesas_acessorias — somente se > 0 ✅ Linha → Despesas Acessórias
indTot_I17b 1 🔒 Fixo — sempre soma no total da NF

Informação Adicional (infAdProd_V01)

Composição automática — concatenação de várias fontes:

Parte Condição Origem
Excedente de xProd Se split_infoadprod_xprod_xml_nfe=1 e descrição > 120 chars Resto da descrição
Info Adicional da linha Sempre invoice_line.l10n_br_informacao_adicional
Mensagem fiscal Se l10n_br_mensagem_fiscal_ids preenchido Textos das mensagens fiscais associadas
Dados de lote Se produto rastreável nLote, dFab, dVal, qLote (conforme parâmetros)
Customer Info Se parceiro tem info personalizada invoice_line.l10n_br_informacao_adicional_produto_ids
Pedido de compra Se imprimir_pedido_compra_item=1 xPed e nItemPed
IBPT (tributos) Se l10n_br_operacao_id.l10n_br_gera_ibpt=True Texto com % federal/estadual/municipal

BLOCO W — Totais

Todos os totais são campos consolidados da fatura (account.move), calculados automaticamente.

Campo TX2 Origem Observação
vBC_W03 invoice.l10n_br_icms_base Soma das bases ICMS
vICMS_W04 invoice.l10n_br_icms_valor Soma dos ICMS
vBCST_W05 invoice.l10n_br_icmsst_base Base ST
vST_W06 invoice.l10n_br_icmsst_valor Valor ST
vProd_W07 invoice.l10n_br_prod_valor Soma valores dos produtos
vFrete_W08 invoice.l10n_br_frete Total frete
vSeg_W09 invoice.l10n_br_seguro Total seguro
vOutro_W15 invoice.l10n_br_despesas_acessorias Total despesas
vDesc_W10 invoice.l10n_br_desc_valor Total desconto
vII_W11 invoice.l10n_br_ii_valor Total II
vIPI_W12 invoice.l10n_br_ipi_valor. Exceção: se in_refund com IPI > 0 → vIPI_W12 = 0, valor vai para vIPIDevol_W12a IPI normal ou devolução
vPIS_W13 invoice.l10n_br_pis_valor Total PIS
vCOFINS_W14 invoice.l10n_br_cofins_valor Total COFINS
vNF_W16 invoice.l10n_br_total_nfe Valor total da NF
vTotTrib_W16a Soma dos l10n_br_total_tributos de cada linha Cálculo IBPT

BLOCO X — Transporte

Campo TX2 Cadeia de Origem Como Alterar
modFrete_X02 Fatura → invoice_incoterm_id → l10n_br_modalidade_freteOBRIGATÓRIO (erro se vazio) ✅ Fatura → Incoterm. Menu: Incoterms → campo "Modalidade de Frete"

BLOCO Y — Cobrança e Pagamento (Dup + Pag)

Lógica de Seleção das Parcelas

O sistema percorre as linhas contábeis (invoice.line_ids) para montar duas listas separadas: Duplicatas (Dup — bloco INCLUIRCOBRANCA) e Pagamentos (Pag — bloco INCLUIRPARTE=YA).

Filtro base das parcelasaccount.py linha 3735:

for nItem, invoice_payment in enumerate(
    sorted(
        [line for line in invoice.line_ids
         if line.account_id.account_type == 'asset_receivable'
         and line.debit > 0.00
         and line.date_maturity],
        key=lambda l: l[0].date_maturity
    )
):

Apenas linhas contábeis que satisfazem todas as condições entram no loop:

Condição Descrição Efeito
account_type == 'asset_receivable' Conta do tipo "Recebível de Ativo" Exclui contas de despesa, receita, impostos, etc.
debit > 0.00 Somente linhas com débito positivo Exclui linhas zeradas e créditos
date_maturity preenchido Data de vencimento obrigatória Parcelas sem vencimento são ignoradas

A lista é ordenada por data de vencimento (date_maturity crescente).

Condição para Geração das Duplicatas (vDup)

Nem toda parcela gera uma duplicata. O condicional que controla a inclusão de duplicatas está na linha 3744:

if invoice.move_type != 'out_refund' and (invoice.invoice_payment_term_id.l10n_br_indicador or '1') != '0':

Uma duplicata só é gerada quando ambas as condições são verdadeiras:

# Condição Descrição Quando é False
1 invoice.move_type != 'out_refund' A fatura não é uma Nota de Crédito (devolução) NF-e de devolução/crédito — nunca gera duplicata
2 l10n_br_indicador != '0' O indicador de pagamento não é "Pagamento à Vista" Condição de pagamento com indicador 0 (à vista) não gera bloco de duplicatas

Valores do l10n_br_indicador

Valor Descrição Gera Dup?
0 Pagamento à Vista
1 Pagamento a Prazo
vazio/None Não configurado ✅ (or '1' → assume prazo)

Campo: account.payment.term → l10n_br_indicador (Selection de INDICADOR_PAGAMENTO)

Onde configurar: Contabilidade → Configurações → Condições de Pagamento → campo "Indicador do Pagamento"

Resumo de decisão

flowchart TD
    A["Parcela receivable\ncom debit > 0"] --> B{"move_type\n== out_refund?"}
    B -->|Sim| C["❌ NÃO gera Dup\n(apenas Pag)"]
    B -->|Não| D{"l10n_br_indicador\n== '0'?"}
    D -->|Sim - À Vista| E["❌ NÃO gera Dup\n(apenas Pag)"]
    D -->|Não - A Prazo/Vazio| F{"agrupar_parcelas\n_cartao == 1?"}
    F -->|Não| G["✅ Gera Dup\n(nDup, dVenc, vDup)"]
    F -->|Sim| H{"Meio == '03'/'04'\n(Cartão)?"}
    H -->|Sim| I["Agrupa em 1 Dup\n(soma vDup por meio)"]
    H -->|Não| G

Campos das Duplicatas (Dup)

Campo TX2 Cadeia de Origem Regra
nFat_Y03 invoice.l10n_br_numero_nf Número da fatura fiscal — preenchido no bloco fatura
vOrig_Y04 invoice.amount_total + invoice.l10n_br_desc_valor Valor original (antes do desconto)
vLiq_Y06 invoice.amount_total Valor líquido
vDesc_Y05 invoice.l10n_br_desc_valor Valor do desconto na fatura
nDup_Y08 Sequencial formatado 001, 002, ... Calculado via loop
dVenc_Y09 invoice_payment.date_maturity formatado YYYY-MM-DD Data de vencimento da parcela
vDup_Y10 invoice_payment.debit formatado 2 decimais Valor da parcela

Referência: Os campos nFat_Y03, vOrig_Y04, vLiq_Y06, vDesc_Y05 são emitidos somente se existirem parcelas (if invoice_payments:, linha 3788). Se não houver parcelas asset_receivable, o sistema emite apenas o bloco YA com vPag=0.00.

Agrupamento de Parcelas por Cartão

Controlado pelo parâmetro de sistema l10n_br_ciel_it_account.agrupar_parcelas_cartao:

Valor Comportamento
0 (default) Cada parcela gera uma duplicata separada
1 Parcelas com mesmo meio de cartão (03/04) e mesmo número de cartão são agrupadas em uma única duplicata, com vDup somado

Quando ativado, o agrupamento usa uma chave composta:

key = frozendict({
    'id': None if l10n_br_meio in ['03','04'] else invoice_payment.id,
    'l10n_br_meio': l10n_br_meio,
    'l10n_br_cobranca_numero_cartao': invoice_payment.l10n_br_cobranca_numero_cartao,
})
  • Parcelas de cartão: id=None → agrupa todas com mesmo meio+número
  • Parcelas de outros meios: id=invoice_payment.id → nunca agrupa

Geração no TX2

As duplicatas são renderizadas após os itens e antes dos meios de pagamento:

INCLUIRCOBRANCA
  nDup_Y08=001
  dVenc_Y09=2026-05-15
  vDup_Y10=1500.00
SALVARCOBRANCA

Referência: account.py linhas 3856–3860

Pagamentos (Bloco YA)

Os pagamentos são sempre gerados (independente do indicador), para todas as parcelas:

Campo TX2 Cadeia de Origem Como Alterar
indPag_YA01b invoice.invoice_payment_term_id.l10n_br_indicador (padrão: 1) ✅ Condição de Pagamento → "Indicador" (0=à vista, 1=a prazo)
tPag_YA02 Prioridade: 1º invoice.payment_provider_id.l10n_br_meio. 2º invoice_payment_term_id.l10n_br_meio. 3º invoice_payment.payment_provider_id.l10n_br_meio. OBRIGATÓRIO ✅ Condição de Pagamento ou Provedor → "Meio de Pagamento"
xPag_YA02a Outros Somente se tPag = 99
tpIntegra_YA04a 2 Somente se tPag in ['03','04'] (cartão) — sempre "não integrado"
vPag_YA03 invoice_payment.debit Valor da parcela

Fallback — Sem Parcelas Receivable

Se nenhuma parcela for encontrada (ex: fatura sem condição de pagamento ou sem linhas asset_receivable):

# Linha 3793 — Fallback
invoice_payment_vals = {}
invoice_payment_vals['indPag_YA01b'] = invoice.invoice_payment_term_id.l10n_br_indicador or '1'
invoice_payment_vals['tPag_YA02'] = l10n_br_meio
invoice_payment_vals['vPag_YA03'] = _format_decimal_2(0.00)  # Valor ZERO

Neste caso: - Não gera bloco de duplicatas (nFat, vOrig, vLiq) - Gera um único bloco YA com vPag=0.00 - O l10n_br_meio ainda é obrigatório — se não configurado, lança UserError


Parâmetros de Sistema Consolidados

Onde configurar: Configurações → Técnico → Parâmetros do Sistema Prefixo: l10n_br_ciel_it_account.

Parâmetro (sem prefixo) Padrão Efeito no TX2 Campo(s) afetado(s)
num_decimal_quantidade_nfe 4 Número de casas decimais qCom_I10, qTrib_I14
num_decimal_valor_unit_nfe 10 Decimais no valor unitário vUnCom_I10a, vUnTrib_I14a
show_datasaida_nf 1 Se inclui data de saída DHSAIENT_B10
show_email_xml_nf 1 Se inclui e-mail do parceiro email_e19
split_infoadprod_xprod_xml_nfe 0 Se split xProd > 120 chars xProd_I04, infAdProd_V01
qty_lot_xml_nfe 0 Se inclui quantidade no lote infAdProd_V01
ean_xml_nfe 1 Se envia EAN ou "SEM GTIN" cEAN_I03, cEANTrib_I12
imprimir_validade_danfe 1 Se inclui data validade lotes infAdProd_V01
imprimir_pedido_compra_item 1 Se inclui pedido de compra item infAdProd_V01
agrupar_parcelas_cartao 0 Se agrupa duplicatas cartão nDup_Y08, vDup_Y10
gerar_sequencia_previsualizar_danfe 0 Se gera número ao preview nNF_B08
email_nfe_automatico 0 Se envia e-mail pós-autorização Não afeta TX2, afeta pós-envio

Hooks de Herança (para desenvolvedores)

Hook Onde é chamado Para que serve
_get_l10n_br_invoice_vals(invoice_vals, invoice) Após montar todo o cabeçalho (linha 3811) Customizar/adicionar campos do cabeçalho sem mexer no core
_get_l10n_br_invoice_line_vals(invoice_line_vals, invoice_line) Após montar cada item Customizar campos dos itens
_get_l10n_br_invoice_payments(invoice_payments, invoice) Após montar pagamentos (linha 3812) Customizar pagamentos
_get_l10n_br_invoice_duplicates(invoice_duplicates, invoice) Após montar duplicatas (linha 3813) Customizar duplicatas

Como usar: Criar módulo de herança que sobrescreva o hook no account.move. O hook recebe o dicionário de valores já montado e deve retornar o dicionário modificado.


Fluxo Pós-Transmissão

flowchart TD
    A["action_gerar_nfe()"] --> B["_gerar_nfe_tx2()"]
    B --> C["POST nfe/envia"]
    C --> D{"Resposta?"}
    D -->|"Autorizado o uso da NF-e"| E["Extrai chave 44 dígitos"]
    E --> F["Atualiza: chave, cstat, situacao=autorizado"]
    F --> G["Gera XML + DANFE"]
    G --> H{"email_nfe_automatico?"}
    H -->|Sim| I["action_nfe_sent()"]
    D -->|"JaExisteException"| J["Extrai chave existente"]
    J --> K["action_resolver_nfe()"]
    D -->|Outro erro| L["situacao=excecao_autorizado"]
    L --> M["Log completo no chatter"]

Troubleshooting — Rastreabilidade

Sintoma Campo TX2 Investigar em Solução
"Operação Fiscal não informada" Fatura → Operação Fiscal Preencher operação fiscal na fatura
NCM vazio NCM_I05 Produto → NCM Preencher NCM no cadastro do produto
CST errado CST_N12 1º NCM/UF, 2º Operação Fiscal → CST ICMS Ajustar tabela NCM/UF ou operação fiscal
CFOP errado CFOP_I08 Operação Fiscal → CFOP Intra/Inter/Ext Verificar CFOPs cadastrados na operação
Alíquota ICMS incorreta pICMS_N16 1º Tabela ICMS UF-UF, 2º NCM/UF, 3º Operação Ajustar tabela ou operação
Benefício fiscal vazio cBenef_I05f Tabela ICMS Benefícios → NCM + CFOP + CST Cadastrar registro de benefício
Origem errada orig_N11 1º Linha fatura, 2º Produto → Origem Corrigir origem no produto
IPI enquadramento vazio cEnq_O06 Tabela IPI Enquadramento → NCM + CFOP + CST Cadastrar enquadramento
PIS CST incorreto CST_Q06 1º NCM, 2º CFOP, 3º Operação → PIS CST Ajustar na fonte certa conforme prioridade
EAN no XML indesejado cEAN_I03 Parâmetro ean_xml_nfe Alterar para 0
E-mail no XML email_e19 Parâmetro show_email_xml_nf Alterar para 0
Parcelas agrupadas nDup_Y08 Parâmetro agrupar_parcelas_cartao Alterar para 0 ou 1

Referências Cruzadas