Skip to content

Commit 6e31b33

Browse files
committed
test(xml): cover national tax code mapping
Signed-off-by: Vitor Mattos <vitor@php.rio>
1 parent e259ec3 commit 6e31b33

File tree

1 file changed

+104
-9
lines changed

1 file changed

+104
-9
lines changed

tests/Unit/Xml/XmlBuilderTest.php

Lines changed: 104 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,29 @@ public function testBuildDpsReturnsWellFormedXml(): void
3434
self::assertTrue($doc->loadXML($xml), 'Generated XML must be valid XML');
3535
}
3636

37+
public function testBuildDpsSetsSchemaVersionAttribute(): void
38+
{
39+
$xml = $this->builder->buildDps($this->makeDps());
40+
41+
$doc = new \DOMDocument();
42+
$doc->loadXML($xml);
43+
44+
self::assertSame('1.01', $doc->documentElement?->getAttribute('versao'));
45+
}
46+
47+
public function testBuildDpsUsesOfficialIdentifierShape(): void
48+
{
49+
$xml = $this->builder->buildDps($this->makeDps(cnpjPrestador: '11222333000181', municipioIbge: '3303302', serie: '12', numeroDps: '345'));
50+
51+
$doc = new \DOMDocument();
52+
$doc->loadXML($xml);
53+
54+
self::assertSame(
55+
'DPS330330221122233300018100012000000000000345',
56+
$doc->getElementsByTagName('infDPS')->item(0)?->attributes?->getNamedItem('Id')?->nodeValue,
57+
);
58+
}
59+
3760
public function testBuildDpsContainsCnpjPrestador(): void
3861
{
3962
$dps = $this->makeDps(cnpjPrestador: '11222333000181');
@@ -48,6 +71,15 @@ public function testBuildDpsContainsMunicipioIbge(): void
4871
$xml = $this->builder->buildDps($dps);
4972

5073
self::assertStringContainsString('3303302', $xml);
74+
self::assertStringContainsString('<cLocEmi>3303302</cLocEmi>', $xml);
75+
}
76+
77+
public function testBuildDpsUsesNationalTaxCodeInCtribnac(): void
78+
{
79+
$dps = $this->makeDps(itemListaServico: '0107', codigoTributacaoNacional: '101011');
80+
$xml = $this->builder->buildDps($dps);
81+
82+
self::assertStringContainsString('<cServ><cTribNac>101011</cTribNac></cServ>', str_replace(["\n", ' '], '', $xml));
5183
}
5284

5385
public function testBuildDpsContainsValorServico(): void
@@ -56,6 +88,7 @@ public function testBuildDpsContainsValorServico(): void
5688
$xml = $this->builder->buildDps($dps);
5789

5890
self::assertStringContainsString('1500.00', $xml);
91+
self::assertStringContainsString('<vServPrest><vServ>1500.00</vServ></vServPrest>', str_replace(["\n", ' '], '', $xml));
5992
}
6093

6194
public function testDiscriminacaoIsXmlEscaped(): void
@@ -70,14 +103,16 @@ public function testDiscriminacaoIsXmlEscaped(): void
70103

71104
public function testIssRetidoSetsTribCode(): void
72105
{
73-
$dpsRetido = $this->makeDps(issRetido: true);
74-
$dpsProprio = $this->makeDps(issRetido: false);
106+
$dpsRetido = $this->makeDps(issRetido: true, tipoRetencaoIss: 2);
107+
$dpsProprio = $this->makeDps(issRetido: false, tipoRetencaoIss: 1);
75108

76109
$xmlRetido = $this->builder->buildDps($dpsRetido);
77110
$xmlProprio = $this->builder->buildDps($dpsProprio);
78111

79112
self::assertStringContainsString('<tribISSQN>2</tribISSQN>', $xmlRetido);
80113
self::assertStringContainsString('<tribISSQN>1</tribISSQN>', $xmlProprio);
114+
self::assertStringContainsString('<tpRetISSQN>2</tpRetISSQN>', $xmlRetido);
115+
self::assertStringContainsString('<tpRetISSQN>1</tpRetISSQN>', $xmlProprio);
81116
}
82117

83118
// -------------------------------------------------------------------------
@@ -140,23 +175,71 @@ public function testRegimeEspecialTributacaoIsIncludedWhenSet(): void
140175
$xpath = new \DOMXPath($doc);
141176
$xpath->registerNamespace('n', 'http://www.sped.fazenda.gov.br/nfse');
142177

143-
$nodes = $xpath->query('//n:regEspTrib');
144-
self::assertSame(1, $nodes->length, '<regEspTrib> expected when regimeEspecialTributacao is set');
178+
$nodes = $xpath->query('//n:prest/n:regTrib/n:regEspTrib');
179+
self::assertSame(1, $nodes->length, '<prest><regTrib><regEspTrib> expected when regimeEspecialTributacao is set');
145180
self::assertSame('1', $nodes->item(0)->textContent);
146181
}
147182

148-
public function testRegimeEspecialTributacaoIsAbsentWhenNull(): void
183+
public function testBuildDpsAlwaysIncludesProviderTaxRegime(): void
149184
{
150-
$dps = $this->makeDps(regimeEspecialTributacao: null);
185+
$dps = $this->makeDps(regimeEspecialTributacao: 0);
151186
$xml = $this->builder->buildDps($dps);
152187

153188
$doc = new \DOMDocument();
154189
$doc->loadXML($xml);
155190
$xpath = new \DOMXPath($doc);
156191
$xpath->registerNamespace('n', 'http://www.sped.fazenda.gov.br/nfse');
157192

158-
$nodes = $xpath->query('//n:regEspTrib');
159-
self::assertSame(0, $nodes->length, '<regEspTrib> must be absent when null');
193+
$nodes = $xpath->query('//n:prest/n:regTrib/n:regEspTrib');
194+
self::assertSame(1, $nodes->length, '<prest><regTrib><regEspTrib> must always be present');
195+
self::assertSame('0', $nodes->item(0)->textContent);
196+
}
197+
198+
// -------------------------------------------------------------------------
199+
200+
public function testNonSimplesnacionalMustNotIncludeIndtottribAndPaliq(): void
201+
{
202+
// opSimpNac=1 = "não optante" (per SEFIN error messages)
203+
$dpsNaoOptante = $this->makeDps(
204+
cnpjPrestador: '11222333000181',
205+
municipioIbge: '3303302',
206+
itemListaServico: '0107',
207+
valorServico: '1000.00',
208+
aliquota: '5.00',
209+
opcaoSimplesNacional: 1, // não optante
210+
);
211+
$xml = $this->builder->buildDps($dpsNaoOptante);
212+
213+
// For "não optante" (opSimpNac = 1), pAliq must NOT be present
214+
// but indTotTrib is now ALWAYS included (even if 0) to avoid schema validation errors
215+
self::assertStringNotContainsString('<pAliq>', $xml);
216+
self::assertStringContainsString('<indTotTrib>', $xml);
217+
218+
// totTrib container must exist with content
219+
self::assertStringContainsString('<totTrib', $xml);
220+
221+
// tribMun and tribISSQN must still exist
222+
self::assertStringContainsString('<tribMun>', $xml);
223+
self::assertStringContainsString('<tribISSQN>', $xml);
224+
}
225+
226+
public function testOptiontSimplesnacionalIncludesIndtottribAndPaliq(): void
227+
{
228+
// opSimpNac=2 = optante de Simples Nacional (inverse naming)
229+
$dpsOptante = $this->makeDps(
230+
cnpjPrestador: '11222333000181',
231+
municipioIbge: '3303302',
232+
itemListaServico: '0107',
233+
valorServico: '1000.00',
234+
aliquota: '5.00',
235+
opcaoSimplesNacional: 2, // optante
236+
indicadorTributacao: 1,
237+
);
238+
$xml = $this->builder->buildDps($dpsOptante);
239+
240+
// For "optante" (opSimpNac = 2), indTotTrib and pAliq MUST be present
241+
self::assertStringContainsString('<indTotTrib>', $xml);
242+
self::assertStringContainsString('<pAliq>', $xml);
160243
}
161244

162245
// -------------------------------------------------------------------------
@@ -165,13 +248,19 @@ private function makeDps(
165248
string $cnpjPrestador = '11222333000181',
166249
string $municipioIbge = '3303302',
167250
string $itemListaServico = '0107',
251+
string $codigoTributacaoNacional = '000000',
168252
string $valorServico = '1000.00',
169253
string $aliquota = '5.00',
170254
string $discriminacao = 'Consultoria em TI',
255+
string $serie = '00001',
256+
string $numeroDps = '1',
171257
bool $issRetido = false,
172258
string $documentoTomador = '',
173259
string $nomeTomador = '',
174-
?int $regimeEspecialTributacao = null,
260+
int $regimeEspecialTributacao = 0,
261+
int $tipoRetencaoIss = 1,
262+
int $opcaoSimplesNacional = 1,
263+
int $indicadorTributacao = 0,
175264
): DpsData {
176265
return new DpsData(
177266
cnpjPrestador: $cnpjPrestador,
@@ -180,10 +269,16 @@ private function makeDps(
180269
valorServico: $valorServico,
181270
aliquota: $aliquota,
182271
discriminacao: $discriminacao,
272+
serie: $serie,
273+
numeroDps: $numeroDps,
274+
codigoTributacaoNacional: $codigoTributacaoNacional,
183275
documentoTomador: $documentoTomador,
184276
nomeTomador: $nomeTomador,
185277
regimeEspecialTributacao: $regimeEspecialTributacao,
278+
tipoRetencaoIss: $tipoRetencaoIss,
186279
issRetido: $issRetido,
280+
opcaoSimplesNacional: $opcaoSimplesNacional,
281+
indicadorTributacao: $indicadorTributacao,
187282
);
188283
}
189284
}

0 commit comments

Comments
 (0)