From c6a22808c303271ffc1f17d691069e81f366a7a1 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:32:52 -0300 Subject: [PATCH 1/3] feat(dto): add optional tomador address and contact fields Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- src/Dto/DpsData.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Dto/DpsData.php b/src/Dto/DpsData.php index bfb281c..c15f1c2 100644 --- a/src/Dto/DpsData.php +++ b/src/Dto/DpsData.php @@ -60,6 +60,33 @@ public function __construct( /** Nome / Razão Social do tomador. */ public string $nomeTomador = '', + /** Código IBGE do município do tomador (7 digits). */ + public string $tomadorCodigoMunicipio = '', + + /** CEP do tomador (8 digits). */ + public string $tomadorCep = '', + + /** Logradouro do tomador. */ + public string $tomadorLogradouro = '', + + /** Número do tomador. */ + public string $tomadorNumero = '', + + /** Complemento do endereço do tomador. */ + public string $tomadorComplemento = '', + + /** Bairro do tomador. */ + public string $tomadorBairro = '', + + /** Inscrição municipal do tomador. */ + public string $tomadorInscricaoMunicipal = '', + + /** Telefone do tomador. */ + public string $tomadorTelefone = '', + + /** E-mail do tomador. */ + public string $tomadorEmail = '', + /** Whether the provider opts into Simples Nacional. */ public int $opcaoSimplesNacional = 1, From c5a53ee6b618d7d6b57dc382b7d022c0190bdd2f Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:32:52 -0300 Subject: [PATCH 2/3] feat(xml): serialize optional tomador address and contact tags Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- src/Xml/XmlBuilder.php | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/Xml/XmlBuilder.php b/src/Xml/XmlBuilder.php index dba82d1..2dabbc9 100644 --- a/src/Xml/XmlBuilder.php +++ b/src/Xml/XmlBuilder.php @@ -178,9 +178,53 @@ private function buildToma(\DOMDocument $doc, DpsData $dps): \DOMElement $toma->appendChild($doc->createElement('xNome', htmlspecialchars($dps->nomeTomador, ENT_XML1))); } + if ($dps->tomadorInscricaoMunicipal !== '') { + $toma->appendChild($doc->createElement('IM', $dps->tomadorInscricaoMunicipal)); + } + + if ($this->hasTomadorAddress($dps)) { + $end = $doc->createElement('end'); + $endNac = $doc->createElement('endNac'); + $endNac->appendChild($doc->createElement('cMun', $dps->tomadorCodigoMunicipio)); + $endNac->appendChild($doc->createElement('CEP', $dps->tomadorCep)); + $end->appendChild($endNac); + + if ($dps->tomadorLogradouro !== '') { + $end->appendChild($doc->createElement('xLgr', htmlspecialchars($dps->tomadorLogradouro, ENT_XML1))); + } + + if ($dps->tomadorNumero !== '') { + $end->appendChild($doc->createElement('nro', htmlspecialchars($dps->tomadorNumero, ENT_XML1))); + } + + if ($dps->tomadorComplemento !== '') { + $end->appendChild($doc->createElement('xCpl', htmlspecialchars($dps->tomadorComplemento, ENT_XML1))); + } + + if ($dps->tomadorBairro !== '') { + $end->appendChild($doc->createElement('xBairro', htmlspecialchars($dps->tomadorBairro, ENT_XML1))); + } + + $toma->appendChild($end); + } + + if ($dps->tomadorTelefone !== '') { + $toma->appendChild($doc->createElement('fone', $dps->tomadorTelefone)); + } + + if ($dps->tomadorEmail !== '') { + $toma->appendChild($doc->createElement('email', htmlspecialchars($dps->tomadorEmail, ENT_XML1))); + } + return $toma; } + private function hasTomadorAddress(DpsData $dps): bool + { + return $dps->tomadorCodigoMunicipio !== '' + && $dps->tomadorCep !== ''; + } + private function buildTribFederal(\DOMDocument $doc, DpsData $dps): \DOMElement { $tribFed = $doc->createElement('tribFed'); From 1e71b2bd7ae36b445633dabc7befe728f362d855 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:32:52 -0300 Subject: [PATCH 3/3] test(xml): cover tomador optional address phone and email Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- tests/Unit/Xml/XmlBuilderTest.php | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/Unit/Xml/XmlBuilderTest.php b/tests/Unit/Xml/XmlBuilderTest.php index fd8a0ae..4ceab09 100644 --- a/tests/Unit/Xml/XmlBuilderTest.php +++ b/tests/Unit/Xml/XmlBuilderTest.php @@ -183,6 +183,26 @@ public function testTomadorCpfBlockIsIncludedWhenDocumentHas11Digits(): void self::assertSame('12345678901', $nodes->item(0)->textContent); } + public function testTomadorAddressPhoneAndEmailAreIncludedWhenProvided(): void + { + $dps = $this->makeDps( + documentoTomador: '12345678000195', + nomeTomador: 'Empresa Tomadora S.A.', + tomadorCodigoMunicipio: '3303302', + tomadorCep: '24020077', + tomadorLogradouro: 'Avenida Rio Branco', + tomadorTelefone: '21988887777', + tomadorEmail: 'financeiro@example.test', + ); + + $xml = $this->builder->buildDps($dps); + + self::assertStringContainsString('', $xml); + self::assertStringContainsString('330330224020077Avenida Rio Branco', str_replace(["\n", ' '], '', $xml)); + self::assertStringContainsString('21988887777', $xml); + self::assertStringContainsString('financeiro@example.test', $xml); + } + public function testTomadorBlockIsAbsentWhenDocumentoTomadorIsEmpty(): void { $dps = $this->makeDps(documentoTomador: ''); @@ -350,6 +370,15 @@ private function makeDps( bool $issRetido = false, string $documentoTomador = '', string $nomeTomador = '', + string $tomadorCodigoMunicipio = '', + string $tomadorCep = '', + string $tomadorLogradouro = '', + string $tomadorNumero = '', + string $tomadorComplemento = '', + string $tomadorBairro = '', + string $tomadorInscricaoMunicipal = '', + string $tomadorTelefone = '', + string $tomadorEmail = '', int $regimeEspecialTributacao = 0, int $tipoRetencaoIss = 1, int $opcaoSimplesNacional = 1, @@ -380,6 +409,15 @@ private function makeDps( codigoTributacaoNacional: $codigoTributacaoNacional, documentoTomador: $documentoTomador, nomeTomador: $nomeTomador, + tomadorCodigoMunicipio: $tomadorCodigoMunicipio, + tomadorCep: $tomadorCep, + tomadorLogradouro: $tomadorLogradouro, + tomadorNumero: $tomadorNumero, + tomadorComplemento: $tomadorComplemento, + tomadorBairro: $tomadorBairro, + tomadorInscricaoMunicipal: $tomadorInscricaoMunicipal, + tomadorTelefone: $tomadorTelefone, + tomadorEmail: $tomadorEmail, regimeEspecialTributacao: $regimeEspecialTributacao, tipoRetencaoIss: $tipoRetencaoIss, issRetido: $issRetido,