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_idpreenchido, 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_bairro — truncado 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_id → street, 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 porsequence.
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_cst — se 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 |
1º 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 |
1º 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 |
1º 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 |
1º 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 |
1º 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 |
1º 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_frete — OBRIGATÓ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 parcelas — account.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 deINDICADOR_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_Y05são emitidos somente se existirem parcelas (if invoice_payments:, linha 3788). Se não houver parcelasasset_receivable, o sistema emite apenas o blocoYAcomvPag=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:
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¶
- NFS-e TX2 — formato diferente (TX2 + JSON), variações por município
- NFC-e TX2 — similar à NF-e (modelo 65), usa o mesmo método
_gerar_nfe_tx2()commod_B06=65 - Cobrança Escritural — boletos via PlugBoleto
- Cancelamentos e Eventos — cancelar, CCe, resolver
- TX2 Campos e Origens — mapeamento consolidado
- Como Alterar TX2 — guia por nível de intervenção
- TX2 Erros Comuns — 19 erros com solução
- Índice