Skip to content

DACTE: agrega componentes do valor além do 9º em vez de descartá-los - #191

Merged
CristianoMafraJunior merged 1 commit into
mainfrom
fix/dacte-comp-overflow
Aug 19, 2026
Merged

DACTE: agrega componentes do valor além do 9º em vez de descartá-los#191
CristianoMafraJunior merged 1 commit into
mainfrom
fix/dacte-comp-overflow

Conversation

@antoniospneto

@antoniospneto antoniospneto commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Segunda metade da #186, de @andmit10 — a parte que envolve decisão de layout. Os dois recortes de texto foram separados na #190.

Problema

O quadro "COMPONENTES DO VALOR DA PRESTAÇÃO DO SERVIÇO" é um retângulo fixo de 18 mm: os dados começam 6 mm abaixo do topo e cada linha ocupa 4 mm, então cabem 3 linhas × 3 colunas = 9 componentes. A distribuição era fixa:

col1 = self.comp_list[:3]
col2 = self.comp_list[3:6]
col3 = self.comp_list[6:9]

comp_list[9:] nunca era referenciado. Do 10º componente em diante o dado sumia — sem aviso.

E o efeito é pior que a omissão: o VALOR TOTAL DO SERVIÇO (vTPrest) é impresso na quarta coluna do mesmo retângulo. Então a conta não fecha na cara do documento:

FRETE PESO    1000.00  │ PEDAGIO      50.00  │ TDE          30.00  │ VALOR TOTAL DO SERVIÇO
FRETE VALOR    200.00  │ GRIS         40.00  │ ADEME        20.00  │ R$ 1.720,00
SEC/CAT        100.00  │ DESPACHO     60.00  │ ITR          10.00  │
                                                                     ↑ soma 1.510, mas diz 1.720

O XSD do CT-e (PL_CTe_400, cteTiposBasico_v4.00.xsd) define Comp como maxOccurs="unbounded" — um CT-e com mais de 9 componentes é perfeitamente válido.

O que muda

O excedente é agregado numa linha DEMAIS, preservando a soma. Nada muta self.comp_list — só o texto renderizado.

O rótulo não é OUTROS: xNome é texto livre de até 15 caracteres, então um componente real pode se chamar assim, e o PDF sairia com duas linhas homônimas e valores diferentes.

Prior art — nenhuma implementação resolve isto

Vale registrar, porque muda como esta PR deve ser lida:

limite além do limite
ACBr (ACBrCTeDACTeRLRetrato.pas) 12 descarta em silêncio
sped-da (nfephp-org, src/CTe/Dacte.php) desenha e vaza para fora do quadro
esta PR agrega em DEMAIS

O ACBr distribui com case i of 0,3,6,9 / 1,4,7,10 / 2,5,8,11 sem ramo else — em Delphi isso não faz nada, então do 13º em diante o dado é descartado, exatamente o mesmo bug com um teto maior. O sped-da percorre todos sem break e deixa o conteúdo transbordar do retângulo.

Ou seja: agregar coloca a lib à frente das duas referências. É uma escolha, não conformidade — e por isso está numa PR separada, fácil de recusar sem segurar o recorte de texto.

A alternativa conservadora seria empatar com o ACBr subindo o teto para 12 (4 linhas de 3 mm em vez de 3 de 4 mm). Custa mexer na geometria, muda todos os PDFs golden, e ainda descarta a partir do 13º — mais trabalho por menos cobertura.

Testes

Renderizam o PDF e leem de volta as posições do texto do content stream.

  • test_componentes_alem_do_nono_aparecem_agregados — 12 componentes: saem COMP 1..8 + DEMAIS, e a linha agregada vale 420.00 (= 90+100+110+120)
  • test_nove_componentes_saem_sem_agregacao — exatamente 9 cabem, nada é agregado
  • test_soma_dos_componentes_exibidos_bate_com_o_total — com 6, 9, 12 e 20 componentes, a soma do que está impresso fecha com o que o XML declara
  • test_to_float_tolera_valor_ausente_ou_invalido

PDFs de referência inalterados — as fixtures têm no máximo 6 componentes, que é por que os testes golden nunca pegaram isto.

O quadro "COMPONENTES DO VALOR DA PRESTAÇÃO DO SERVIÇO" é um retângulo fixo de
18 mm: os dados começam 6 mm abaixo do topo e cada linha ocupa 4 mm, então
cabem 3 linhas em 3 colunas. A distribuição era fixa em comp_list[:3], [3:6] e
[6:9] — o que passasse disso não era desenhado.

O XSD do CT-e (PL_CTe_400, cteTiposBasico_v4.00.xsd) define Comp como
maxOccurs="unbounded", então um CT-e com mais de 9 componentes é válido. O
efeito no PDF era pior que a omissão: o VALOR TOTAL DO SERVIÇO (vTPrest) é
impresso na quarta coluna do mesmo retângulo, então a soma dos componentes
exibidos deixava de bater com o total ao lado, sem nenhuma indicação de por quê.

O excedente passa a ser agregado numa linha "DEMAIS", preservando a soma. O
rótulo não é "OUTROS" porque xNome é texto livre de até 15 caracteres e um
componente real pode se chamar assim — o PDF sairia com duas linhas homônimas
e valores diferentes.

Nem self.comp_list nem self.emit_name são mutados: só o texto renderizado.

Vale registrar o que as outras implementações fazem, porque nenhuma resolve:
o ACBr (ACBrCTeDACTeRLRetrato.pas) distribui com `case i of 0,3,6,9 / 1,4,7,10
/ 2,5,8,11` sem ramo `else`, ou seja, descarta em silêncio a partir do 13º; o
sped-da (nfephp-org) desenha todos e deixa vazar para fora do quadro.

As fixtures têm no máximo 6 componentes, que é por que os testes golden nunca
pegaram isto: os PDFs de referência seguem inalterados.
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.44%. Comparing base (c6fcedc) to head (1eaa9bc).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #191   +/-   ##
=======================================
  Coverage   96.43%   96.44%           
=======================================
  Files          32       32           
  Lines        4375     4385   +10     
  Branches      348      349    +1     
=======================================
+ Hits         4219     4229   +10     
  Misses         92       92           
  Partials       64       64           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@CristianoMafraJunior
CristianoMafraJunior merged commit f444aad into main Aug 19, 2026
10 checks passed
@CristianoMafraJunior
CristianoMafraJunior deleted the fix/dacte-comp-overflow branch August 19, 2026 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants