diff --git a/src/Danfse/DanfseTemplate.php b/src/Danfse/DanfseTemplate.php
index d3f49bd..b9e42e6 100644
--- a/src/Danfse/DanfseTemplate.php
+++ b/src/Danfse/DanfseTemplate.php
@@ -150,7 +150,13 @@ public function buildData(array $nfse): array
'servico' => [
'codigo_trib_nacional' => $this->formatter->codTribNacional($this->val($cServ, 'cTribNac')),
- 'desc_trib_nacional' => $this->formatter->limit(trim($this->val($infNfse, 'xTribNac')), 60),
+ // NT008 2.4.5 prefers an authorized municipal description
+ // over the national one. The length is suggested, not a new
+ // tax-code validation or data mutation.
+ 'desc_trib_nacional' => $this->formatter->limit(
+ $this->val($infNfse, 'xTribMun') ?: $this->val($infNfse, 'xTribNac'),
+ 167,
+ ),
'codigo_trib_municipal' => $this->val($cServ, 'cTribMun') ?: '-',
'codigo_nbs' => $this->formattedNbs($this->val($cServ, 'cNBS')),
'desc_trib_municipal' => $this->formatter->limit(trim($this->val($infNfse, 'xTribMun')), 60),
@@ -179,6 +185,11 @@ public function buildData(array $nfse): array
],
'tributacao_federal' => [
+ // NT008 note 6: optional PIS/COFINS line is present only
+ // for actual issue competence through calendar year 2026.
+ 'mostrar_linha_2026' => $this->showFederalDetailsForCompetence(
+ $this->val($infDps, 'dCompet'),
+ ),
'irrf' => $this->currencyOrDash($this->val($tribFed, 'vRetIRRF')),
'cp' => $this->currencyOrDash($this->val($tribFed, 'vRetCP')),
'csll' => $this->currencyOrDash($this->val($tribFed, 'vRetCSLL')),
@@ -417,6 +428,17 @@ private function purposeLabel(string $value): string
};
}
+ private function showFederalDetailsForCompetence(string $competence): bool
+ {
+ // Do not use today's date: printing an older authorized invoice
+ // must reproduce the display rules for its original competence.
+ if (preg_match('/^(\\d{4})-\\d{2}-\\d{2}$/D', $competence, $matches) !== 1) {
+ return false;
+ }
+
+ return (int) $matches[1] <= 2026;
+ }
+
private function pisCofinsRetentionLabel(string $value): string
{
return match ($value) {
diff --git a/src/Danfse/HTMLTemplate.php b/src/Danfse/HTMLTemplate.php
index 266ef91..0383ad0 100644
--- a/src/Danfse/HTMLTemplate.php
+++ b/src/Danfse/HTMLTemplate.php
@@ -366,11 +366,13 @@
Contribuição Previdenciária - Retida= $data['tributacao_federal']['cp'] ?> |
Contribuições Sociais - Retidas= $data['tributacao_federal']['csll'] ?> |
-
+
+
| PIS - Débito Apuração Própria= $data['tributacao_federal']['pis'] ?> |
COFINS - Débito Apuração Própria= $data['tributacao_federal']['cofins'] ?> |
Tipo de retenção PIS/COFINS/CSLL= $data['tributacao_federal']['descricao_retencao'] ?> |
+
diff --git a/tests/Unit/Danfse/DanfseGoldenReferenceTest.php b/tests/Unit/Danfse/DanfseGoldenReferenceTest.php
index bfabaac..2c485ab 100644
--- a/tests/Unit/Danfse/DanfseGoldenReferenceTest.php
+++ b/tests/Unit/Danfse/DanfseGoldenReferenceTest.php
@@ -104,7 +104,7 @@ public function testLongOfficialDescriptionsUseStableSixtyCharacterSummary(): vo
$data = (new DanfseTemplate())->buildData($nfse);
- self::assertSame(63, mb_strlen($data['servico']['desc_trib_nacional']));
+ self::assertSame(170, mb_strlen($data['servico']['desc_trib_nacional']));
self::assertSame(63, mb_strlen($data['servico']['desc_trib_municipal']));
self::assertStringEndsWith('...', $data['servico']['desc_trib_nacional']);
self::assertStringEndsWith('...', $data['servico']['desc_trib_municipal']);
diff --git a/tests/Unit/Danfse/DanfseTemplateTest.php b/tests/Unit/Danfse/DanfseTemplateTest.php
index f0dfabe..d0666cc 100644
--- a/tests/Unit/Danfse/DanfseTemplateTest.php
+++ b/tests/Unit/Danfse/DanfseTemplateTest.php
@@ -135,6 +135,40 @@ public function testAuthorizedMunicipalTotalsUseNfseValuesNotDpsTaxFlags(): void
self::assertSame('R$ 630,00', $data['tributacao_municipal']['issqn_apurado']);
}
+ public function testMunicipalTaxDescriptionWinsButNationalIsFallback(): void
+ {
+ $nfse = $this->fixtureNfseData();
+ $nfse['infNFSe']['xTribNac'] = 'Descricao nacional sintetica';
+ $nfse['infNFSe']['xTribMun'] = 'Descricao municipal sintetica';
+
+ $template = new DanfseTemplate();
+ self::assertSame('Descricao municipal sintetica', $template->buildData($nfse)['servico']['desc_trib_nacional']);
+ self::assertStringContainsString('Descricao municipal sintetica', $template->render($nfse, new DanfseConfig()));
+ self::assertStringNotContainsString('Descricao nacional sintetica', $template->render($nfse, new DanfseConfig()));
+
+ unset($nfse['infNFSe']['xTribMun']);
+ self::assertSame('Descricao nacional sintetica', $template->buildData($nfse)['servico']['desc_trib_nacional']);
+ }
+
+ public function testFederalDetailRowFollowsOriginalFiscalCompetence(): void
+ {
+ $nfse = $this->fixtureNfseData();
+ $template = new DanfseTemplate();
+
+ $nfse['infNFSe']['DPS']['infDPS']['dCompet'] = '2026-12-31';
+ self::assertTrue($template->buildData($nfse)['tributacao_federal']['mostrar_linha_2026']);
+ self::assertStringContainsString('class="federal-competence-2026"', $template->render($nfse, new DanfseConfig()));
+
+ $nfse['infNFSe']['DPS']['infDPS']['dCompet'] = '2027-01-01';
+ self::assertFalse($template->buildData($nfse)['tributacao_federal']['mostrar_linha_2026']);
+ $html = $template->render($nfse, new DanfseConfig());
+ self::assertStringNotContainsString('class="federal-competence-2026"', $html);
+ self::assertStringContainsString('Contribuições Sociais - Retidas', $html);
+
+ unset($nfse['infNFSe']['DPS']['infDPS']['dCompet']);
+ self::assertFalse($template->buildData($nfse)['tributacao_federal']['mostrar_linha_2026']);
+ }
+
public function testDescriptionPreservesNewlinesWithoutRenderingMarkup(): void
{
$nfse = $this->fixtureNfseData();