From 1dc66d9365a990a3e3e37cb355bcd3adb97705b0 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Tue, 31 Mar 2026 16:04:41 -0300 Subject: [PATCH 1/3] feat(dto): add federal piscofins irrf csll cp properties to DpsData Add 10 optional string properties for federal taxation: - federalPiscofinsSituacaoTributaria (CST) - federalPiscofinsTipoRetencao - federalPiscofinsBaseCalculo - federalPiscofinsAliquotaPis / federalPiscofinsValorPis - federalPiscofinsAliquotaCofins / federalPiscofinsValorCofins - federalValorIrrf, federalValorCsll, federalValorCp All default to empty string to preserve backward compatibility. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- src/Dto/DpsData.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/Dto/DpsData.php b/src/Dto/DpsData.php index 40be054..bd51b83 100644 --- a/src/Dto/DpsData.php +++ b/src/Dto/DpsData.php @@ -74,6 +74,36 @@ public function __construct( /** Whether ISS is retained at source. */ public bool $issRetido = false, + + /** Situação Tributária do PIS/COFINS (CST). */ + public string $federalPiscofinsSituacaoTributaria = '', + + /** Tipo de retenção do PIS/COFINS/CSLL. */ + public string $federalPiscofinsTipoRetencao = '', + + /** Base de cálculo do PIS/COFINS. */ + public string $federalPiscofinsBaseCalculo = '', + + /** Alíquota do PIS. */ + public string $federalPiscofinsAliquotaPis = '', + + /** Valor do PIS. */ + public string $federalPiscofinsValorPis = '', + + /** Alíquota do COFINS. */ + public string $federalPiscofinsAliquotaCofins = '', + + /** Valor do COFINS. */ + public string $federalPiscofinsValorCofins = '', + + /** Valor do IRRF. */ + public string $federalValorIrrf = '', + + /** Valor das contribuições sociais retidas (CSLL). */ + public string $federalValorCsll = '', + + /** Valor da contribuição previdenciária retida. */ + public string $federalValorCp = '', ) { } } From ab156d441ad03fe9164bdd50beeb2f7dc0f33b51 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Tue, 31 Mar 2026 16:04:57 -0300 Subject: [PATCH 2/3] feat(xml): serialize tribFed block when federal taxation data is present Add buildTribFederal() and hasFederalTaxationData() private methods to XmlBuilder. The tribFed XML element is appended to totTrib when any of the federal properties on DpsData are non-empty, following the NFS-e Nacional schema (tiDPS v1.00). Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- src/Xml/XmlBuilder.php | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/Xml/XmlBuilder.php b/src/Xml/XmlBuilder.php index fe162a6..61a37ee 100644 --- a/src/Xml/XmlBuilder.php +++ b/src/Xml/XmlBuilder.php @@ -101,6 +101,10 @@ private function buildTotTrib(\DOMDocument $doc, DpsData $dps): \DOMElement $totTrib->appendChild($tribMun); + if ($this->hasFederalTaxationData($dps)) { + $totTrib->appendChild($this->buildTribFederal($doc, $dps)); + } + // E0715: indTotTrib is ALWAYS included to avoid schema validation errors $totTrib->appendChild($doc->createElement('indTotTrib', (string) $dps->indicadorTributacao)); @@ -133,4 +137,48 @@ private function buildToma(\DOMDocument $doc, DpsData $dps): \DOMElement return $toma; } + + private function buildTribFederal(\DOMDocument $doc, DpsData $dps): \DOMElement + { + $tribFed = $doc->createElement('tribFed'); + + if ($dps->federalPiscofinsSituacaoTributaria !== '') { + $tribFed->appendChild($doc->createElement('sitTribPISCOFINS', $dps->federalPiscofinsSituacaoTributaria)); + } + + if ($dps->federalPiscofinsTipoRetencao !== '') { + $tribFed->appendChild($doc->createElement('tpRetPISCOFINSCSLL', $dps->federalPiscofinsTipoRetencao)); + } + + foreach ([ + 'vBCPISCOFINS' => $dps->federalPiscofinsBaseCalculo, + 'pAliqPIS' => $dps->federalPiscofinsAliquotaPis, + 'vPIS' => $dps->federalPiscofinsValorPis, + 'pAliqCOFINS' => $dps->federalPiscofinsAliquotaCofins, + 'vCOFINS' => $dps->federalPiscofinsValorCofins, + 'vIRRF' => $dps->federalValorIrrf, + 'vCSLL' => $dps->federalValorCsll, + 'vCP' => $dps->federalValorCp, + ] as $tag => $value) { + if ($value !== '') { + $tribFed->appendChild($doc->createElement($tag, $value)); + } + } + + return $tribFed; + } + + private function hasFederalTaxationData(DpsData $dps): bool + { + return $dps->federalPiscofinsSituacaoTributaria !== '' + || $dps->federalPiscofinsTipoRetencao !== '' + || $dps->federalPiscofinsBaseCalculo !== '' + || $dps->federalPiscofinsAliquotaPis !== '' + || $dps->federalPiscofinsValorPis !== '' + || $dps->federalPiscofinsAliquotaCofins !== '' + || $dps->federalPiscofinsValorCofins !== '' + || $dps->federalValorIrrf !== '' + || $dps->federalValorCsll !== '' + || $dps->federalValorCp !== ''; + } } From d61cf67c57a27059e430d9fa90936993f7031c8d Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Tue, 31 Mar 2026 16:05:08 -0300 Subject: [PATCH 3/3] test(xml): cover tribFed serialization in XmlBuilderTest Add testBuildDpsIncludesFederalTaxationBlockWhenConfigured verifying that tribFed XML element with all expected child nodes is emitted when federal DpsData fields are populated. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- tests/Unit/Xml/XmlBuilderTest.php | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/Unit/Xml/XmlBuilderTest.php b/tests/Unit/Xml/XmlBuilderTest.php index 57b6345..ee22abe 100644 --- a/tests/Unit/Xml/XmlBuilderTest.php +++ b/tests/Unit/Xml/XmlBuilderTest.php @@ -195,6 +195,36 @@ public function testBuildDpsAlwaysIncludesProviderTaxRegime(): void self::assertSame('0', $nodes->item(0)->textContent); } + public function testBuildDpsIncludesFederalTaxationBlockWhenConfigured(): void + { + $dps = $this->makeDps( + federalPiscofinsSituacaoTributaria: '1', + federalPiscofinsTipoRetencao: '3', + federalPiscofinsBaseCalculo: '1000.00', + federalPiscofinsAliquotaPis: '1.65', + federalPiscofinsValorPis: '16.50', + federalPiscofinsAliquotaCofins: '7.60', + federalPiscofinsValorCofins: '76.00', + federalValorIrrf: '15.00', + federalValorCsll: '10.00', + federalValorCp: '5.00', + ); + + $xml = $this->builder->buildDps($dps); + + self::assertStringContainsString('', $xml); + self::assertStringContainsString('1', $xml); + self::assertStringContainsString('3', $xml); + self::assertStringContainsString('1000.00', $xml); + self::assertStringContainsString('1.65', $xml); + self::assertStringContainsString('16.50', $xml); + self::assertStringContainsString('7.60', $xml); + self::assertStringContainsString('76.00', $xml); + self::assertStringContainsString('15.00', $xml); + self::assertStringContainsString('10.00', $xml); + self::assertStringContainsString('5.00', $xml); + } + // ------------------------------------------------------------------------- public function testNonSimplesnacionalMustNotIncludeIndtottribAndPaliq(): void @@ -261,6 +291,16 @@ private function makeDps( int $tipoRetencaoIss = 1, int $opcaoSimplesNacional = 1, int $indicadorTributacao = 0, + string $federalPiscofinsSituacaoTributaria = '', + string $federalPiscofinsTipoRetencao = '', + string $federalPiscofinsBaseCalculo = '', + string $federalPiscofinsAliquotaPis = '', + string $federalPiscofinsValorPis = '', + string $federalPiscofinsAliquotaCofins = '', + string $federalPiscofinsValorCofins = '', + string $federalValorIrrf = '', + string $federalValorCsll = '', + string $federalValorCp = '', ): DpsData { return new DpsData( cnpjPrestador: $cnpjPrestador, @@ -279,6 +319,16 @@ private function makeDps( issRetido: $issRetido, opcaoSimplesNacional: $opcaoSimplesNacional, indicadorTributacao: $indicadorTributacao, + federalPiscofinsSituacaoTributaria: $federalPiscofinsSituacaoTributaria, + federalPiscofinsTipoRetencao: $federalPiscofinsTipoRetencao, + federalPiscofinsBaseCalculo: $federalPiscofinsBaseCalculo, + federalPiscofinsAliquotaPis: $federalPiscofinsAliquotaPis, + federalPiscofinsValorPis: $federalPiscofinsValorPis, + federalPiscofinsAliquotaCofins: $federalPiscofinsAliquotaCofins, + federalPiscofinsValorCofins: $federalPiscofinsValorCofins, + federalValorIrrf: $federalValorIrrf, + federalValorCsll: $federalValorCsll, + federalValorCp: $federalValorCp, ); } }