From cdb09e003d208800328d93dc7d7f4245ea25ca6a Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Fri, 9 Oct 2026 11:41:36 +0000 Subject: [PATCH 1/2] feat: cover remaining NT009 Annex VI conditional groups (#95) Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- docs/NT009-CONTRACT-IMPLEMENTATION.md | 25 +- src/Dto/Nt009DeferralData.php | 21 ++ src/Dto/Nt009DpsPreviewData.php | 19 ++ src/Dto/Nt009RegularTaxData.php | 20 ++ src/Xml/Nt009DpsPreviewBuilder.php | 120 +++++++- tests/Unit/Xml/Nt009DpsPreviewBuilderTest.php | 257 ++++++++++++++++++ 6 files changed, 456 insertions(+), 6 deletions(-) create mode 100644 src/Dto/Nt009DeferralData.php create mode 100644 src/Dto/Nt009RegularTaxData.php diff --git a/docs/NT009-CONTRACT-IMPLEMENTATION.md b/docs/NT009-CONTRACT-IMPLEMENTATION.md index f710071..b84870d 100644 --- a/docs/NT009-CONTRACT-IMPLEMENTATION.md +++ b/docs/NT009-CONTRACT-IMPLEMENTATION.md @@ -49,7 +49,7 @@ Restricted production instead lists `esquemas-nfse-rtc-v1-01-20260727.zip`. They share a numeric schema version but not necessarily the same content or deployment semantics. -At review time (2026-10-08), the RTC portal published NT009 v1.01 but no +At re-verification (2026-10-09), the RTC portal published NT009 v1.01 but no NT009-specific XSD package or confirmed SEFIN deployment/effective date. The NT009 text points to a separately published rollout schedule. **Do not enable or claim production/homologation conformity for the draft NT009 @@ -135,6 +135,17 @@ It now includes explicitly typed, separately validated structural drafts for: optional detail and discount records, with exact-cent reconciliation of `gDetCobranca` to the charge and total charge values to `vServ`. +Additional optional, source-backed Annex VI groups are represented without +fiscal inference: `indZFMALC` (row 377, explicitly verified geography plus +published cIndOp whitelist), `tpOper`/`gRefNFSe` (rows 378-380, mandatory +reference for type 2/3), `tpEnteGov` (row 381, verified government purchase), +`indDoacao` (row 382, donation without consideration), `gTribRegular` +(rows 431-433) and `gDif` (rows 434-437). Existing callers are unaffected: +the `Nt009DpsPreviewData` constructor adds trailing optional arguments only. +The optional nested tax groups are rejected if the caller-verified +`ind_gIBSCBS` disallows `gIBSCBS`. Cross-domain applicability and +calculations remain caller responsibilities. + The preview also models `IBSCBS/valores/trib/gIBSCBS/gEstornoCred` (Annex VI rows 438-440), containing both decimal `vIBSEstCred` and `vCBSEstCred`. The caller must separately verify the official cClassTrib @@ -255,6 +266,18 @@ php tools/bin/domains.php schema-packages --report=/tmp/nfse-xsd-comparison.json These packages cannot independently prove an NT009 v1.04.01 rollout, which is a separate contractual/effective-date gate. +## Downstream adoption boundary + +`LibreCodeCoop/akaunting-nfse` currently pins +`librecodeoop/nfse-php: dev-main#f179d7f723bec80f5b19a25dfbc385a612c2447f` +in `3rdparty/composer.json`. The opt-in preview extends the constructor with +optional trailing parameters, leaving the current `DpsData` constructor, +`XmlBuilder::buildDps(DpsData)`, `DpsSchemaValidator` and +`NfseClient::emit()` unchanged. Existing consumers need no migration for +ordinary emission. **No NT009 commit should replace the consumer pin** until +an effective schema, correct environment and successful SEFIN contract tests +are evidenced. This library makes no downstream UI/persistence changes. + ## Cross-publication discrepancies requiring official confirmation The live, checksum-pinned XSD ZIP comparison on 2026-10-08 (Brazil local diff --git a/src/Dto/Nt009DeferralData.php b/src/Dto/Nt009DeferralData.php new file mode 100644 index 0000000..71c34cd --- /dev/null +++ b/src/Dto/Nt009DeferralData.php @@ -0,0 +1,21 @@ + $pagamentosVinculados * @param list $bensMoveis * @param list $notasPagamentoAntecipado + * @param list $notasFiscaisReferenciadas */ public function __construct( /** finNFSe: 0 regular, 1 credit, 2 debit. */ @@ -68,6 +69,24 @@ public function __construct( public ?string $valorEstornoCbs = null, /** 1-99 prior NFS-e payment-reference keys, 50 characters each. */ public array $notasPagamentoAntecipado = [], + /** indZFMALC, present only for the officially enumerated operations. */ + public ?int $indicadorZfmAlc = null, + /** Caller confirmed the location requirements in Annex VI row 377. */ + public ?bool $elegibilidadeZfmAlcConfirmada = null, + /** tpOper 1-5; externally verified applicable transaction. */ + public ?int $tipoOperacao = null, + /** Prior NFS-e references (gRefNFSe), 1-99 keys of 50 characters. */ + public array $notasFiscaisReferenciadas = [], + /** tpEnteGov 1-4, only in externally confirmed government purchases. */ + public ?int $tipoEnteGovernamental = null, + /** Whether the caller confirmed this is a government purchase. */ + public ?bool $compraGovernamentalConfirmada = null, + /** Presence means donor declares a transaction without consideration. */ + public ?bool $doacaoSemContraprestacao = null, + /** Explicit optional regular taxation group, not a tax calculation. */ + public ?Nt009RegularTaxData $tributacaoRegular = null, + /** Explicit optional deferral percentages, not tax calculation. */ + public ?Nt009DeferralData $diferimento = null, ) { } } diff --git a/src/Dto/Nt009RegularTaxData.php b/src/Dto/Nt009RegularTaxData.php new file mode 100644 index 0000000..574389e --- /dev/null +++ b/src/Dto/Nt009RegularTaxData.php @@ -0,0 +1,20 @@ +codigoIndicadorOperacao !== null) { $ibs->appendChild($document->createElement('cIndOp', $preview->codigoIndicadorOperacao)); } + if ($preview->indicadorZfmAlc !== null) { + $ibs->appendChild($document->createElement('indZFMALC', (string) $preview->indicadorZfmAlc)); + } + if ($preview->tipoOperacao !== null) { + $ibs->appendChild($document->createElement('tpOper', (string) $preview->tipoOperacao)); + } + if ($preview->notasFiscaisReferenciadas !== []) { + $references = $document->createElement('gRefNFSe'); + foreach ($preview->notasFiscaisReferenciadas as $key) { + $ref = $document->createElement('refNFSe'); + $ref->appendChild($document->createTextNode($key)); + $references->appendChild($ref); + } + $ibs->appendChild($references); + } + if ($preview->tipoEnteGovernamental !== null) { + $ibs->appendChild($document->createElement('tpEnteGov', (string) $preview->tipoEnteGovernamental)); + } + if ($preview->doacaoSemContraprestacao === true) { + $ibs->appendChild($document->createElement('indDoacao', '1')); + } if ($preview->imovel !== null) { $ibs->appendChild( (new Nt009RealEstatePreviewGroup())->build( @@ -153,6 +174,22 @@ public function build(DpsData $dps, Nt009DpsPreviewData $preview): Nt009DpsPrevi $adjustment->appendChild($document->createElement('vCBS', (string) $preview->valorAjusteCbs)); $group->appendChild($adjustment); } + if ($preview->tributacaoRegular !== null) { + $regular = $document->createElement('gTribRegular'); + $regular->appendChild($document->createElement('CSTReg', $preview->tributacaoRegular->cst)); + $regular->appendChild($document->createElement( + 'cClassTribReg', + $preview->tributacaoRegular->classificacao + )); + $group->appendChild($regular); + } + if ($preview->diferimento !== null) { + $deferral = $document->createElement('gDif'); + $deferral->appendChild($document->createElement('pDifUF', $preview->diferimento->percentualUf)); + $deferral->appendChild($document->createElement('pDifMun', $preview->diferimento->percentualMunicipio)); + $deferral->appendChild($document->createElement('pDifCBS', $preview->diferimento->percentualCbs)); + $group->appendChild($deferral); + } if ($preview->valorEstornoIbs !== null) { // Annex VI rows 438-440: allowed/required exclusively // by the caller-verified cClassTrib.ind_gEstornoCred. @@ -232,6 +269,13 @@ private function validatePreview(Nt009DpsPreviewData $preview): void || $preview->valorEstornoIbs !== null || $preview->valorEstornoCbs !== null || $preview->notasPagamentoAntecipado !== [] + || $preview->indicadorZfmAlc !== null + || $preview->tipoOperacao !== null + || $preview->notasFiscaisReferenciadas !== [] + || $preview->tipoEnteGovernamental !== null + || $preview->doacaoSemContraprestacao === true + || $preview->tributacaoRegular !== null + || $preview->diferimento !== null || $preview->exigeGrupoIbsCbs !== null || $preview->bensMoveis !== [] || $preview->pagamentosVinculados !== [] @@ -267,7 +311,9 @@ private function validatePreview(Nt009DpsPreviewData $preview): void || $preview->valorAjusteIbs !== null || $preview->valorAjusteCbs !== null || $preview->exigeEstornoCredito === true || $preview->valorEstornoIbs !== null || $preview->valorEstornoCbs !== null - || $preview->notasPagamentoAntecipado !== [])) { + || $preview->notasPagamentoAntecipado !== [] + || $preview->tributacaoRegular !== null + || $preview->diferimento !== null)) { throw new \InvalidArgumentException('NT009 forbids gIBSCBS children when ind_gIBSCBS is false'); } if ($preview->codigoCreditoPresumido !== null @@ -303,12 +349,76 @@ private function validatePreview(Nt009DpsPreviewData $preview): void throw new \InvalidArgumentException('NT009 gEstornoCred requires decimal vIBSEstCred and vCBSEstCred strings'); } } - if (count($preview->notasPagamentoAntecipado) > 99) { - throw new \InvalidArgumentException('NT009 gPagAntecipado allows at most 99 refNFSe keys'); + $this->validateInvoiceKeys($preview->notasPagamentoAntecipado, 'gPagAntecipado'); + + if ($preview->indicadorZfmAlc !== null) { + // Annex VI row 377: both operation-code whitelist and geographic + // requirements must hold; location is verified by the caller. + $eligibleOperations = [ + '010101', '010102', '010103', '010106', '020101', '020201', + '020301', '030101', '030102', '050101', '050102', '050201', + '060101', '070101', '070102', '100301', '100302', '100401', + '100501', '100502', '100601', + ]; + if (!in_array($preview->indicadorZfmAlc, [0, 1], true) + || !in_array($preview->codigoIndicadorOperacao, $eligibleOperations, true) + || $preview->elegibilidadeZfmAlcConfirmada !== true) { + throw new \InvalidArgumentException( + 'NT009 indZFMALC requires a published eligible cIndOp and caller-verified ZFM/ALC location' + ); + } + } + if ($preview->tipoOperacao !== null + && !in_array($preview->tipoOperacao, [1, 2, 3, 4, 5], true)) { + throw new \InvalidArgumentException('NT009 tpOper must be 1-5'); + } + if (in_array($preview->tipoOperacao, [2, 3], true) + && $preview->notasFiscaisReferenciadas === []) { + throw new \InvalidArgumentException('NT009 tpOper 2 or 3 requires gRefNFSe'); + } + $this->validateInvoiceKeys($preview->notasFiscaisReferenciadas, 'gRefNFSe'); + if ($preview->tipoEnteGovernamental !== null + && (!in_array($preview->tipoEnteGovernamental, [1, 2, 3, 4], true) + || $preview->compraGovernamentalConfirmada !== true)) { + throw new \InvalidArgumentException('NT009 tpEnteGov requires a government purchase and code 1-4'); } - foreach ($preview->notasPagamentoAntecipado as $key) { + if ($preview->doacaoSemContraprestacao === false) { + throw new \InvalidArgumentException( + 'NT009 indDoacao must be omitted for transactions with consideration' + ); + } + if ($preview->tributacaoRegular !== null) { + if (preg_match('/^[0-9]{3}$/D', $preview->tributacaoRegular->cst) !== 1 + || preg_match('/^[0-9]{6}$/D', $preview->tributacaoRegular->classificacao) !== 1) { + throw new \InvalidArgumentException('NT009 gTribRegular requires CSTReg (3) and cClassTribReg (6)'); + } + } + if ($preview->diferimento !== null) { + foreach ([ + $preview->diferimento->percentualUf, + $preview->diferimento->percentualMunicipio, + $preview->diferimento->percentualCbs, + ] as $percentual) { + if (preg_match('/^[0-9]{1,3}\.[0-9]{2}$/D', $percentual) !== 1) { + throw new \InvalidArgumentException('NT009 gDif requires three percentage strings (1-3V2)'); + } + } + } + } + + /** + * @param array $keys + */ + private function validateInvoiceKeys(array $keys, string $group): void + { + if (count($keys) > 99) { + throw new \InvalidArgumentException('NT009 ' . $group . ' allows at most 99 refNFSe keys'); + } + foreach ($keys as $key) { if (!is_string($key) || mb_strlen($key) !== 50 || preg_match('/\p{Cc}/u', $key) !== 0) { - throw new \InvalidArgumentException('NT009 gPagAntecipado/refNFSe must contain 50 valid characters'); + throw new \InvalidArgumentException( + 'NT009 ' . $group . '/refNFSe must contain 50 valid characters' + ); } } } diff --git a/tests/Unit/Xml/Nt009DpsPreviewBuilderTest.php b/tests/Unit/Xml/Nt009DpsPreviewBuilderTest.php index aa6cfe7..bfa46c9 100644 --- a/tests/Unit/Xml/Nt009DpsPreviewBuilderTest.php +++ b/tests/Unit/Xml/Nt009DpsPreviewBuilderTest.php @@ -16,6 +16,8 @@ use LibreCodeCoop\NfsePHP\Dto\Nt009CondominiumDetailData; use LibreCodeCoop\NfsePHP\Dto\Nt009DpsPreview; use LibreCodeCoop\NfsePHP\Dto\Nt009DpsPreviewData; +use LibreCodeCoop\NfsePHP\Dto\Nt009DeferralData; +use LibreCodeCoop\NfsePHP\Dto\Nt009RegularTaxData; use LibreCodeCoop\NfsePHP\Dto\Nt009LeaseData; use LibreCodeCoop\NfsePHP\Dto\Nt009LinkedPaymentData; use LibreCodeCoop\NfsePHP\Dto\Nt009MovableAssetData; @@ -1238,6 +1240,261 @@ classificacaoTributaria: '000001', )?->length); } + public function testNt009AddsRemainingOptionalAnnexViGroupsInDocumentOrder(): void + { + $invoice = str_repeat('A', 50); + $draft = $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + codigoIndicadorOperacao: '010101', + exigeGrupoIbsCbs: true, + indicadorZfmAlc: 1, + elegibilidadeZfmAlcConfirmada: true, + tipoOperacao: 2, + notasFiscaisReferenciadas: [$invoice], + tipoEnteGovernamental: 1, + compraGovernamentalConfirmada: true, + doacaoSemContraprestacao: true, + tributacaoRegular: new Nt009RegularTaxData('000', '000001'), + diferimento: new Nt009DeferralData('1.25', '2.50', '0.00'), + ) + ); + $xml = $draft->xml; + $root = '/n:DPS/n:infDPS/n:IBSCBS'; + self::assertSame('1', $this->first($xml, $root . '/n:indZFMALC')->textContent); + self::assertSame('2', $this->first($xml, $root . '/n:tpOper')->textContent); + self::assertSame($invoice, $this->first($xml, $root . '/n:gRefNFSe/n:refNFSe')->textContent); + self::assertSame('1', $this->first($xml, $root . '/n:tpEnteGov')->textContent); + self::assertSame('1', $this->first($xml, $root . '/n:indDoacao')->textContent); + self::assertSame('000', $this->first( + $xml, + $root . '/n:valores/n:trib/n:gIBSCBS/n:gTribRegular/n:CSTReg' + )->textContent); + self::assertSame('2.50', $this->first( + $xml, + $root . '/n:valores/n:trib/n:gIBSCBS/n:gDif/n:pDifMun' + )->textContent); + self::assertLessThan(strpos($xml, ''), strpos($xml, '')); + self::assertLessThan(strpos($xml, ''), strpos($xml, '')); + self::assertLessThan(strpos($xml, ''), strpos($xml, '')); + self::assertLessThan(strpos($xml, ''), strpos($xml, '')); + self::assertLessThan(strpos($xml, ''), strpos($xml, '')); + } + + public function testNt009OptionalGroupsAreOmittedForOrdinaryTaxpayer(): void + { + $xml = $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + exigeGrupoIbsCbs: false, + ) + )->xml; + foreach (['indZFMALC', 'tpOper', 'gRefNFSe', 'tpEnteGov', 'indDoacao', 'gTribRegular', 'gDif'] as $tag) { + self::assertStringNotContainsString('<' . $tag . '>', $xml); + } + } + + public function testNt009ZfmRequiresPublishedCodeAndGeographicEvidence(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('caller-verified ZFM/ALC location'); + $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + exigeGrupoIbsCbs: false, + indicadorZfmAlc: 1, + codigoIndicadorOperacao: null, + ) + ); + } + + public function testNt009ZfmRejectsUnlistedCIndOpEvenWithGeographicEvidence(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('eligible cIndOp'); + $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + codigoIndicadorOperacao: '010105', + exigeGrupoIbsCbs: true, + indicadorZfmAlc: 1, + elegibilidadeZfmAlcConfirmada: true, + ) + ); + } + + public function testNt009TpOperRequiresReferencesForTypesTwoAndThree(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('tpOper 2 or 3 requires gRefNFSe'); + $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + exigeGrupoIbsCbs: false, + tipoOperacao: 3, + ) + ); + } + + public function testNt009TpOperRejectsOutOfRangeValues(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('tpOper must be 1-5'); + $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + exigeGrupoIbsCbs: false, + tipoOperacao: 9, + ) + ); + } + + public function testNt009GovernmentEntityRequiresExplicitEvidence(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('requires a government purchase'); + $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + exigeGrupoIbsCbs: false, + tipoEnteGovernamental: 4, + ) + ); + } + + public function testNt009InvoiceReferencesMustHavePublishedLength(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('gRefNFSe/refNFSe must contain 50'); + $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + exigeGrupoIbsCbs: false, + tipoOperacao: 2, + notasFiscaisReferenciadas: ['too-short'], + ) + ); + } + + public function testNt009InvoiceReferencesRejectMoreThan99Keys(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('gRefNFSe allows at most 99'); + $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + exigeGrupoIbsCbs: false, + notasFiscaisReferenciadas: array_fill(0, 100, str_repeat('8', 50)), + ) + ); + } + + public function testNt009RegularTaxationRequiresExactPublishedCodes(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('gTribRegular requires CSTReg'); + $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + exigeGrupoIbsCbs: true, + codigoIndicadorOperacao: '010101', + tributacaoRegular: new Nt009RegularTaxData('00', '000001'), + ) + ); + } + + public function testNt009DeferralRequiresAllThreePercentages(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('gDif requires three percentage'); + $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + exigeGrupoIbsCbs: true, + codigoIndicadorOperacao: '010101', + diferimento: new Nt009DeferralData('1.25', '2.50', '7.123'), + ) + ); + } + + public function testNt009NestedTaxGroupsAreForbiddenWhenGIBSCBSIsFalse(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('forbids gIBSCBS children'); + $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + exigeGrupoIbsCbs: false, + diferimento: new Nt009DeferralData('1.25', '2.50', '0.00'), + ) + ); + } + + public function testNt009DonationWithoutConsiderationIsExplicit(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('indDoacao must be omitted'); + $this->builder->previewNt009Dps( + $this->makeDps(), + new Nt009DpsPreviewData( + finalidade: 0, + indicadorDestinatario: 0, + cst: '000', + classificacaoTributaria: '000001', + exigeGrupoIbsCbs: false, + doacaoSemContraprestacao: false, + ) + ); + } + private function makeDps( ?int $ibsCbsFinalidade = null, string $codigoTributacaoNacional = '010701', From fb5a87889ee860cea631c5b2a141c3bae9cae4c4 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Fri, 9 Oct 2026 13:44:50 +0000 Subject: [PATCH 2/2] style: fix NT009 preview test import order (#95) Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- tests/Unit/Xml/Nt009DpsPreviewBuilderTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Xml/Nt009DpsPreviewBuilderTest.php b/tests/Unit/Xml/Nt009DpsPreviewBuilderTest.php index bfa46c9..0bb5a04 100644 --- a/tests/Unit/Xml/Nt009DpsPreviewBuilderTest.php +++ b/tests/Unit/Xml/Nt009DpsPreviewBuilderTest.php @@ -14,10 +14,9 @@ use LibreCodeCoop\NfsePHP\Dto\Nt009CondominiumChargeData; use LibreCodeCoop\NfsePHP\Dto\Nt009CondominiumData; use LibreCodeCoop\NfsePHP\Dto\Nt009CondominiumDetailData; +use LibreCodeCoop\NfsePHP\Dto\Nt009DeferralData; use LibreCodeCoop\NfsePHP\Dto\Nt009DpsPreview; use LibreCodeCoop\NfsePHP\Dto\Nt009DpsPreviewData; -use LibreCodeCoop\NfsePHP\Dto\Nt009DeferralData; -use LibreCodeCoop\NfsePHP\Dto\Nt009RegularTaxData; use LibreCodeCoop\NfsePHP\Dto\Nt009LeaseData; use LibreCodeCoop\NfsePHP\Dto\Nt009LinkedPaymentData; use LibreCodeCoop\NfsePHP\Dto\Nt009MovableAssetData; @@ -29,6 +28,7 @@ use LibreCodeCoop\NfsePHP\Dto\Nt009RealEstateUnitData; use LibreCodeCoop\NfsePHP\Dto\Nt009RecipientAddressData; use LibreCodeCoop\NfsePHP\Dto\Nt009RecipientData; +use LibreCodeCoop\NfsePHP\Dto\Nt009RegularTaxData; use LibreCodeCoop\NfsePHP\Tests\TestCase; use LibreCodeCoop\NfsePHP\Xml\DpsSchemaValidator; use LibreCodeCoop\NfsePHP\Xml\XmlBuilder;