Skip to content

Commit 1701595

Browse files
authored
Merge pull request #7 from LibreCodeCoop/feat/xml-tomador
feat(xml): add tomador block and regEspTrib to XmlBuilder
2 parents a014c68 + 1ca0266 commit 1701595

File tree

2 files changed

+121
-7
lines changed

2 files changed

+121
-7
lines changed

src/Xml/XmlBuilder.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,22 @@ public function buildDps(DpsData $dps): string
5353
$serv->appendChild($doc->createElement('xDescServ', htmlspecialchars($dps->discriminacao, ENT_XML1)));
5454
$infDps->appendChild($serv);
5555

56+
// Tomador (optional — absent for foreign buyers with no document)
57+
if ($dps->documentoTomador !== '') {
58+
$infDps->appendChild($this->buildToma($doc, $dps));
59+
}
60+
5661
// Values
5762
$valores = $doc->createElement('valores');
5863
$valores->appendChild($doc->createElement('vServ', $dps->valorServico));
5964
$valores->appendChild($this->buildTrib($doc, $dps));
6065
$infDps->appendChild($valores);
6166

67+
// Regime especial de tributação (optional)
68+
if ($dps->regimeEspecialTributacao !== null) {
69+
$infDps->appendChild($doc->createElement('regEspTrib', (string) $dps->regimeEspecialTributacao));
70+
}
71+
6272
return $doc->saveXML() ?: '';
6373
}
6474

@@ -70,4 +80,23 @@ private function buildTrib(\DOMDocument $doc, DpsData $dps): \DOMElement
7080

7181
return $trib;
7282
}
83+
84+
private function buildToma(\DOMDocument $doc, DpsData $dps): \DOMElement
85+
{
86+
$toma = $doc->createElement('toma');
87+
88+
$docLen = strlen($dps->documentoTomador);
89+
90+
if ($docLen === 14) {
91+
$toma->appendChild($doc->createElement('CNPJ', $dps->documentoTomador));
92+
} elseif ($docLen === 11) {
93+
$toma->appendChild($doc->createElement('CPF', $dps->documentoTomador));
94+
}
95+
96+
if ($dps->nomeTomador !== '') {
97+
$toma->appendChild($doc->createElement('xNome', htmlspecialchars($dps->nomeTomador, ENT_XML1)));
98+
}
99+
100+
return $toma;
101+
}
73102
}

tests/Unit/Xml/XmlBuilderTest.php

Lines changed: 92 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,85 @@ public function testIssRetidoSetsTribCode(): void
8282

8383
// -------------------------------------------------------------------------
8484

85+
public function testTomadorCnpjBlockIsIncludedWhenDocumentHas14Digits(): void
86+
{
87+
$dps = $this->makeDps(documentoTomador: '12345678000195', nomeTomador: 'Empresa Tomadora S.A.');
88+
$xml = $this->builder->buildDps($dps);
89+
90+
$doc = new \DOMDocument();
91+
$doc->loadXML($xml);
92+
$xpath = new \DOMXPath($doc);
93+
$xpath->registerNamespace('n', 'http://www.sped.fazenda.gov.br/nfse');
94+
95+
$nodes = $xpath->query('//n:toma/n:CNPJ');
96+
self::assertSame(1, $nodes->length, '<toma><CNPJ> block expected');
97+
self::assertSame('12345678000195', $nodes->item(0)->textContent);
98+
99+
$nameNodes = $xpath->query('//n:toma/n:xNome');
100+
self::assertSame(1, $nameNodes->length, '<toma><xNome> block expected');
101+
self::assertSame('Empresa Tomadora S.A.', $nameNodes->item(0)->textContent);
102+
}
103+
104+
public function testTomadorCpfBlockIsIncludedWhenDocumentHas11Digits(): void
105+
{
106+
$dps = $this->makeDps(documentoTomador: '12345678901', nomeTomador: 'Pessoa Física Tomadora');
107+
$xml = $this->builder->buildDps($dps);
108+
109+
$doc = new \DOMDocument();
110+
$doc->loadXML($xml);
111+
$xpath = new \DOMXPath($doc);
112+
$xpath->registerNamespace('n', 'http://www.sped.fazenda.gov.br/nfse');
113+
114+
$nodes = $xpath->query('//n:toma/n:CPF');
115+
self::assertSame(1, $nodes->length, '<toma><CPF> block expected for 11-digit doc');
116+
self::assertSame('12345678901', $nodes->item(0)->textContent);
117+
}
118+
119+
public function testTomadorBlockIsAbsentWhenDocumentoTomadorIsEmpty(): void
120+
{
121+
$dps = $this->makeDps(documentoTomador: '');
122+
$xml = $this->builder->buildDps($dps);
123+
124+
$doc = new \DOMDocument();
125+
$doc->loadXML($xml);
126+
$xpath = new \DOMXPath($doc);
127+
$xpath->registerNamespace('n', 'http://www.sped.fazenda.gov.br/nfse');
128+
129+
$nodes = $xpath->query('//n:toma');
130+
self::assertSame(0, $nodes->length, '<toma> block must be absent when no buyer document');
131+
}
132+
133+
public function testRegimeEspecialTributacaoIsIncludedWhenSet(): void
134+
{
135+
$dps = $this->makeDps(regimeEspecialTributacao: 1);
136+
$xml = $this->builder->buildDps($dps);
137+
138+
$doc = new \DOMDocument();
139+
$doc->loadXML($xml);
140+
$xpath = new \DOMXPath($doc);
141+
$xpath->registerNamespace('n', 'http://www.sped.fazenda.gov.br/nfse');
142+
143+
$nodes = $xpath->query('//n:regEspTrib');
144+
self::assertSame(1, $nodes->length, '<regEspTrib> expected when regimeEspecialTributacao is set');
145+
self::assertSame('1', $nodes->item(0)->textContent);
146+
}
147+
148+
public function testRegimeEspecialTributacaoIsAbsentWhenNull(): void
149+
{
150+
$dps = $this->makeDps(regimeEspecialTributacao: null);
151+
$xml = $this->builder->buildDps($dps);
152+
153+
$doc = new \DOMDocument();
154+
$doc->loadXML($xml);
155+
$xpath = new \DOMXPath($doc);
156+
$xpath->registerNamespace('n', 'http://www.sped.fazenda.gov.br/nfse');
157+
158+
$nodes = $xpath->query('//n:regEspTrib');
159+
self::assertSame(0, $nodes->length, '<regEspTrib> must be absent when null');
160+
}
161+
162+
// -------------------------------------------------------------------------
163+
85164
private function makeDps(
86165
string $cnpjPrestador = '11222333000181',
87166
string $municipioIbge = '3303302',
@@ -90,15 +169,21 @@ private function makeDps(
90169
string $aliquota = '5.00',
91170
string $discriminacao = 'Consultoria em TI',
92171
bool $issRetido = false,
172+
string $documentoTomador = '',
173+
string $nomeTomador = '',
174+
?int $regimeEspecialTributacao = null,
93175
): DpsData {
94176
return new DpsData(
95-
cnpjPrestador: $cnpjPrestador,
96-
municipioIbge: $municipioIbge,
97-
itemListaServico: $itemListaServico,
98-
valorServico: $valorServico,
99-
aliquota: $aliquota,
100-
discriminacao: $discriminacao,
101-
issRetido: $issRetido,
177+
cnpjPrestador: $cnpjPrestador,
178+
municipioIbge: $municipioIbge,
179+
itemListaServico: $itemListaServico,
180+
valorServico: $valorServico,
181+
aliquota: $aliquota,
182+
discriminacao: $discriminacao,
183+
documentoTomador: $documentoTomador,
184+
nomeTomador: $nomeTomador,
185+
regimeEspecialTributacao: $regimeEspecialTributacao,
186+
issRetido: $issRetido,
102187
);
103188
}
104189
}

0 commit comments

Comments
 (0)