diff --git a/schemes/PL_009_V4/consReciNFe_v4.00.xsd b/schemes/PL_009_V4/consReciNFe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/consSitNFe_v4.00.xsd b/schemes/PL_009_V4/consSitNFe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/consStatServ_v4.00.xsd b/schemes/PL_009_V4/consStatServ_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/enviNFe_v4.00.xsd b/schemes/PL_009_V4/enviNFe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/inutNFe_v4.00.xsd b/schemes/PL_009_V4/inutNFe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/leiauteConsSitNFe_v4.00.xsd b/schemes/PL_009_V4/leiauteConsSitNFe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/leiauteConsStatServ_v4.00.xsd b/schemes/PL_009_V4/leiauteConsStatServ_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/leiauteInutNFe_v4.00.xsd b/schemes/PL_009_V4/leiauteInutNFe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/leiauteNFe_v4.00.xsd b/schemes/PL_009_V4/leiauteNFe_v4.00.xsd
old mode 100755
new mode 100644
index e2a44282..1c59fa9c
--- a/schemes/PL_009_V4/leiauteNFe_v4.00.xsd
+++ b/schemes/PL_009_V4/leiauteNFe_v4.00.xsd
@@ -1,5 +1,5 @@
-
+
@@ -556,7 +556,8 @@ Preencher com "2B", quando se tratar de Cupom Fiscal emitido por máqu
Este campo será obrigatoriamente preenchido com:
1 – Simples Nacional;
2 – Simples Nacional – excesso de sublimite de receita bruta;
-3 – Regime Normal.
+3 – Regime Normal.
+4 - Simples Nacional - Microempreendedor individual - MEI
@@ -564,6 +565,7 @@ Este campo será obrigatoriamente preenchido com:
+
@@ -2756,14 +2758,13 @@ Informar o motivo da desoneração:
origem da mercadoria: 0 - Nacional
-1 - Estrangeira - Importação direta
-2 - Estrangeira - Adquirida no mercado interno
+ 1 - Estrangeira - Importação direta
+ 2 - Estrangeira - Adquirida no mercado interno
- Tributção pelo ICMS
-20 - Com redução de base de cálculo
+ Tributação pelo ICMS 51 - Tributação com Diferimento
@@ -2775,10 +2776,10 @@ Informar o motivo da desoneração:
Modalidade de determinação da BC do ICMS:
-0 - Margem Valor Agregado (%);
-1 - Pauta (valor);
-2 - Preço Tabelado Máximo (valor);
-3 - Valor da Operação.
+ 0 - Margem Valor Agregado (%);
+ 1 - Pauta (valor);
+ 2 - Preço Tabelado Máximo (valor);
+ 3 - Valor da Operação.
@@ -3779,7 +3780,7 @@ Operação interestadual para consumidor final com partilha do ICMS devido na o
-
+
origem da mercadoria: 0 - Nacional
1 - Estrangeira - Importação direta
@@ -4098,11 +4099,11 @@ Operação interestadual para consumidor final com partilha do ICMS devido na o
- Tributação do ICMS pelo SIMPLES NACIONAL, CRT=1 – Simples Nacional e CSOSN=900 (v2.0)
+ Tributação do ICMS pelo SIMPLES NACIONAL, CRT=1 – Simples Nacional, CRT=4 - MEI e CSOSN=900 (v2.0)
-
+
origem da mercadoria: 0 - Nacional
1 - Estrangeira - Importação direta
diff --git a/schemes/PL_009_V4/nfe_v4.00.xsd b/schemes/PL_009_V4/nfe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/procInutNFe_v4.00.xsd b/schemes/PL_009_V4/procInutNFe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/procNFe_v4.00.xsd b/schemes/PL_009_V4/procNFe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/retConsReciNFe_v4.00.xsd b/schemes/PL_009_V4/retConsReciNFe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/retConsSitNFe_v4.00.xsd b/schemes/PL_009_V4/retConsSitNFe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/retConsStatServ_v4.00.xsd b/schemes/PL_009_V4/retConsStatServ_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/retEnviNFe_v4.00.xsd b/schemes/PL_009_V4/retEnviNFe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/retInutNFe_v4.00.xsd b/schemes/PL_009_V4/retInutNFe_v4.00.xsd
old mode 100755
new mode 100644
diff --git a/schemes/PL_009_V4/tiposBasico_v4.00.xsd b/schemes/PL_009_V4/tiposBasico_v4.00.xsd
old mode 100755
new mode 100644
index 872801e5..d51b658e
--- a/schemes/PL_009_V4/tiposBasico_v4.00.xsd
+++ b/schemes/PL_009_V4/tiposBasico_v4.00.xsd
@@ -521,7 +521,7 @@
-
+
diff --git a/schemes/PL_009_V4/xmldsig-core-schema_v1.01.xsd b/schemes/PL_009_V4/xmldsig-core-schema_v1.01.xsd
old mode 100755
new mode 100644
diff --git a/src/Make.php b/src/Make.php
index f8190b4d..bca97969 100755
--- a/src/Make.php
+++ b/src/Make.php
@@ -446,11 +446,6 @@ public function montaNFe(): string
*/
public function monta(): string
{
- if (!empty($this->errors)) {
- $this->errors = array_merge($this->errors, $this->dom->errors);
- } else {
- $this->errors = $this->dom->errors;
- }
//cria a tag raiz da Nfe
$this->buildNFe();
//processa nfeRef e coloca as tags na tag ide
@@ -516,9 +511,11 @@ public function monta(): string
// testa da chave
$this->checkNFeKey($this->dom);
$this->xml = $this->dom->saveXML();
- if (count($this->errors) > 0) {
+
+ if (count($this->getErrors()) > 0) {
throw new RuntimeException('Existem erros nas tags. Obtenha os erros com getErrors().');
}
+
return $this->xml;
}
@@ -1761,7 +1758,7 @@ public function tagCreditoPresumidoProd(stdClass $std)
$std->cCredPresumido,
true,
$identificador . "[item $std->item] cCredPresumido Código de Benefício Fiscal de Crédito "
- . "Presumido na UF aplicado ao item",
+ . "Presumido na UF aplicado ao item",
true
);
$this->dom->addChild(
@@ -1845,6 +1842,14 @@ public function tagprod(stdClass $std): DOMElement
$this->errors[] = "cEANTrib {$ceantrib} " . $e->getMessage();
}
+ $CRT = $this->emit->getElementsByTagName("CRT")->item(0)->nodeValue ?? null;
+ $idDest = $this->ide->getElementsByTagName("idDest")->item(0)->nodeValue ?? null;
+ $allowEmptyNcm = $CRT == 4 && $idDest == 1;
+
+ if ($allowEmptyNcm && empty($std->NCM)) {
+ $std->NCM = '00000000';
+ }
+
$identificador = 'I01 - ';
$prod = $this->dom->createElement("prod");
$this->dom->addChild(
@@ -2886,7 +2891,7 @@ public function tagcomb(stdClass $std): DOMElement
$this->conditionalNumberFormatting($std->pBio, 4),
false,
"$identificador [item $std->item] Percentual do índice de mistura do Biodiesel (B100) no Óleo Diesel B "
- . "instituído pelo órgão regulamentador"
+ . "instituído pelo órgão regulamentador"
);
$this->aComb[$std->item] = $comb;
return $comb;
@@ -3631,7 +3636,7 @@ public function tagICMS(stdClass $std): DOMElement
$std->indDeduzDeson,
false,
"$identificador [item $std->item] Indica se o valor do ICMS desonerado (vICMSDeson) "
- . "deduz do valor do item (vProd)."
+ . "deduz do valor do item (vProd)."
);
break;
case '40':
@@ -4181,7 +4186,7 @@ public function tagICMS(stdClass $std): DOMElement
$std->indDeduzDeson,
false,
"$identificador [item $std->item] Indica se o valor do ICMS desonerado (vICMSDeson) "
- . "deduz do valor do item (vProd)."
+ . "deduz do valor do item (vProd)."
);
$this->dom->addChild(
$icms,
@@ -4364,7 +4369,7 @@ public function tagICMS(stdClass $std): DOMElement
$std->indDeduzDeson,
false,
"$identificador [item $std->item] Indica se o valor do ICMS desonerado (vICMSDeson) "
- . "deduz do valor do item (vProd)."
+ . "deduz do valor do item (vProd)."
);
$this->dom->addChild(
$icms,
@@ -4528,7 +4533,7 @@ public function tagICMSPart(stdClass $std): DOMElement
$this->conditionalNumberFormatting($std->pFCPST, 4),
false,
"[item $std->item] Percentual do Fundo de "
- . "Combate à Pobreza (FCP) ST"
+ . "Combate à Pobreza (FCP) ST"
);
$this->dom->addChild(
$icmsPart,
@@ -4749,6 +4754,12 @@ public function tagICMSSN(stdClass $std): DOMElement
//totalizador generico
$this->stdTot->vFCPST += (float) !empty($std->vFCPST) ? $std->vFCPST : 0;
$this->stdTot->vFCPSTRet += (float) !empty($std->vFCPSTRet) ? $std->vFCPSTRet : 0;
+
+ $CRT = $this->emit->getElementsByTagName("CRT")->item(0)->nodeValue ?? null;
+ $allowEmptyOrig = $CRT == 4 && in_array($std->CSOSN, [
+ '102', '103', '300', '400', '900',
+ ]);
+
switch ($std->CSOSN) {
case '101':
$icmsSN = $this->dom->createElement("ICMSSN101");
@@ -4791,8 +4802,9 @@ public function tagICMSSN(stdClass $std): DOMElement
$icmsSN,
'orig',
$std->orig,
- true,
- "[item $std->item] Origem da mercadoria"
+ !$allowEmptyOrig,
+ "[item $std->item] Origem da mercadoria",
+ $allowEmptyOrig,
);
$this->dom->addChild(
$icmsSN,
@@ -5096,8 +5108,9 @@ public function tagICMSSN(stdClass $std): DOMElement
$icmsSN,
'orig',
$std->orig,
- true,
- "[item $std->item] Origem da mercadoria"
+ !$allowEmptyOrig,
+ "[item $std->item] Origem da mercadoria",
+ $allowEmptyOrig,
);
$this->dom->addChild(
$icmsSN,
@@ -8018,7 +8031,7 @@ protected function buildDet()
//incluso NT 2023.001-1.10 /1.20
if (!empty($this->aOrigComb[$nItem])) {
foreach ($this->aOrigComb[$nItem] as $origcomb) {
- $this->dom->appChild($child, $origcomb, "inclusão do node origComb na tag comb");
+ $this->dom->appChild($child, $origcomb, "inclusão do node origComb na tag comb");
}
}
$this->dom->appChild($prod, $child, "Inclusão do node combustivel");
@@ -8257,7 +8270,7 @@ protected function checkNFeKey(Dom $dom): void
*/
public function getErrors(): array
{
- return $this->errors;
+ return array_merge($this->errors, $this->dom->errors);
}
/**
diff --git a/tests/MakeTest.php b/tests/MakeTest.php
index 0a38572d..cc0d5f24 100755
--- a/tests/MakeTest.php
+++ b/tests/MakeTest.php
@@ -1019,6 +1019,9 @@ public function test_tagII(): void
public function test_tagISSQN(): void
{
+ $this->make->tagide(new \stdClass());
+ $this->make->tagemit(new \stdClass());
+
$std = new \stdClass();
$std->item = 1;
$std->cProd = '1111';
@@ -1156,6 +1159,9 @@ public function test_tagICMSST(): void
public function test_tagICMSSN_101(): void
{
+ $this->make->tagide(new \stdClass());
+ $this->make->tagemit(new \stdClass());
+
$std = new \stdClass();
$std->item = 1;
$std->orig = 0;
@@ -1173,6 +1179,9 @@ public function test_tagICMSSN_101(): void
public function test_tagICMSSN_102(): void
{
+ $this->make->tagide(new \stdClass());
+ $this->make->tagemit(new \stdClass());
+
$std = new \stdClass();
$std->item = 1;
$std->orig = 0;
@@ -1188,6 +1197,9 @@ public function test_tagICMSSN_102(): void
public function test_tagICMSSN_103(): void
{
+ $this->make->tagide(new \stdClass());
+ $this->make->tagemit(new \stdClass());
+
$std = new \stdClass();
$std->item = 1;
$std->orig = 0;
@@ -1203,6 +1215,9 @@ public function test_tagICMSSN_103(): void
public function test_tagICMSSN_300(): void
{
+ $this->make->tagide(new \stdClass());
+ $this->make->tagemit(new \stdClass());
+
$std = new \stdClass();
$std->item = 1;
$std->orig = 0;
@@ -1218,6 +1233,9 @@ public function test_tagICMSSN_300(): void
public function test_tagICMSSN_400(): void
{
+ $this->make->tagide(new \stdClass());
+ $this->make->tagemit(new \stdClass());
+
$std = new \stdClass();
$std->item = 1;
$std->orig = 0;
@@ -1233,6 +1251,9 @@ public function test_tagICMSSN_400(): void
public function test_tagICMSSN_201(): void
{
+ $this->make->tagide(new \stdClass());
+ $this->make->tagemit(new \stdClass());
+
$std = new \stdClass();
$std->item = 1;
$std->orig = 0;
@@ -1260,6 +1281,9 @@ public function test_tagICMSSN_201(): void
public function test_tagICMSSN_202(): void
{
+ $this->make->tagide(new \stdClass());
+ $this->make->tagemit(new \stdClass());
+
$std = new \stdClass();
$std->item = 1;
$std->orig = 0;
@@ -1284,6 +1308,9 @@ public function test_tagICMSSN_202(): void
public function test_tagICMSSN_203(): void
{
+ $this->make->tagide(new \stdClass());
+ $this->make->tagemit(new \stdClass());
+
$std = new \stdClass();
$std->item = 1;
$std->orig = 0;
@@ -1308,6 +1335,9 @@ public function test_tagICMSSN_203(): void
public function test_tagICMSSN_500(): void
{
+ $this->make->tagide(new \stdClass());
+ $this->make->tagemit(new \stdClass());
+
$std = new \stdClass();
$std->item = 1;
$std->orig = 0;
@@ -1335,6 +1365,9 @@ public function test_tagICMSSN_500(): void
public function test_tagICMSSN_900(): void
{
+ $this->make->tagide(new \stdClass());
+ $this->make->tagemit(new \stdClass());
+
$std = new \stdClass();
$std->item = 1;
$std->orig = 0;
@@ -1365,6 +1398,219 @@ public function test_tagICMSSN_900(): void
$this->validarExistenciaCampos($std, $tag2);
}
+ public function test_tagICMSSNShouldAcceptEmptyOrig_whenCrtIs4AndCsosnInAllowedList(): void
+ {
+ $std = new \stdClass();
+ $std->CRT = 4;
+ $this->make->tagemit($std);
+
+ $std = new \stdClass();
+ $std->item = 1;
+ $std->orig = null;
+ $std->CSOSN = '900';
+ $std->modBC = 3;
+ $std->vBC = 100;
+ $std->pRedBC = 1;
+ $std->pICMS = 1;
+ $std->vICMS = 1;
+ $std->pCredSN = 3;
+ $std->vCredICMSSN = 4;
+ $std->modBCST = 3;
+ $std->pMVAST = 1;
+ $std->pRedBCST = 1;
+ $std->vBCST = 1;
+ $std->pICMSST = 1;
+ $std->vICMSST = 1;
+ $std->vBCFCPST = 1;
+ $std->pFCPST = 1;
+ $std->vFCPST = 1;
+
+ $icmssn = $this->make->tagICMSSN($std);
+ $result = $icmssn->getElementsByTagName('ICMSSN900')->item(0);
+
+ $this->assertEquals('ICMS', $icmssn->nodeName);
+ $this->assertEquals('ICMSSN900', $result->nodeName);
+ $this->assertNull($result->getElementsByTagName('orig')->item(0));
+
+ $this->validarExistenciaCampos($std, $result);
+ }
+
+ public function test_tagICMSSNShouldNotAcceptEmptyOrig_whenCrtIs1(): void
+ {
+ $std = new \stdClass();
+ $std->CRT = 1;
+ $this->make->tagemit($std);
+
+ $std = new \stdClass();
+ $std->item = 1;
+ $std->orig = null;
+ $std->CSOSN = '900';
+ $std->modBC = 3;
+ $std->vBC = 100;
+ $std->pRedBC = 1;
+ $std->pICMS = 1;
+ $std->vICMS = 1;
+ $std->pCredSN = 3;
+ $std->vCredICMSSN = 4;
+ $std->modBCST = 3;
+ $std->pMVAST = 1;
+ $std->pRedBCST = 1;
+ $std->vBCST = 1;
+ $std->pICMSST = 1;
+ $std->vICMSST = 1;
+ $std->vBCFCPST = 1;
+ $std->pFCPST = 1;
+ $std->vFCPST = 1;
+
+ $icmssn = $this->make->tagICMSSN($std);
+ $result = $icmssn->getElementsByTagName('ICMSSN900')->item(0);
+
+ $this->assertEquals('ICMS', $icmssn->nodeName);
+ $this->assertEquals('ICMSSN900', $result->nodeName);
+ $this->assertContains(
+ 'Preenchimento Obrigatório! [orig] [item 1] Origem da mercadoria',
+ $this->make->getErrors()
+ );
+ $this->validarExistenciaCampos($std, $result);
+ }
+
+ public function test_tagICMSSNShouldNotAcceptEmptyOrig_whenCrtIs4AndCsosnIsNotInAllowedList(): void
+ {
+ $std = new \stdClass();
+ $std->CRT = 1;
+ $this->make->tagemit($std);
+
+ $std = new \stdClass();
+ $std->item = 1;
+ $std->orig = null;
+ $std->CSOSN = '500';
+ $std->modBC = 3;
+ $std->vBC = 100;
+ $std->pRedBC = 1;
+ $std->pICMS = 1;
+ $std->vICMS = 1;
+ $std->pCredSN = 3;
+ $std->vCredICMSSN = 4;
+ $std->modBCST = 3;
+ $std->pMVAST = 1;
+ $std->pRedBCST = 1;
+ $std->vBCST = 1;
+ $std->pICMSST = 1;
+ $std->vICMSST = 1;
+ $std->vBCFCPST = 1;
+ $std->pFCPST = 1;
+ $std->vFCPST = 1;
+
+ $icmssn = $this->make->tagICMSSN($std);
+ $result = $icmssn->getElementsByTagName('ICMSSN500')->item(0);
+
+ $this->assertEquals('ICMS', $icmssn->nodeName);
+ $this->assertEquals('ICMSSN500', $result->nodeName);
+ $this->assertContains(
+ 'Preenchimento Obrigatório! [orig] [item 1] Origem da mercadoria',
+ $this->make->getErrors()
+ );
+ }
+
+ public function test_tagNCMShouldAcceptEmptyValue_andChangeToDefaultValue_whenCrtIs4AndIdDestIs1(): void
+ {
+ $std = new \stdClass();
+ $std->idDest = 1;
+ $this->make->tagide($std);
+
+ $std = new \stdClass();
+ $std->CRT = 4;
+ $this->make->tagemit($std);
+
+ $std = new \stdClass();
+ $std->item = 1;
+ $std->cProd = '1111';
+ $std->cEAN = "SEM GTIN";
+ $std->xProd = 'CAMISETA REGATA GG';
+ $std->NCM = null;
+ $std->CFOP = 5101;
+ $std->uCom = 'UN';
+ $std->qCom = 1;
+ $std->vUnCom = 100.00;
+ $std->vProd = 100.00;
+ $std->cEANTrib = "SEM GTIN";
+ $std->uTrib = 'UN';
+ $std->qTrib = 1;
+ $std->vUnTrib = 100.00;
+ $std->indTot = 1;
+ $prod = $this->make->tagprod($std);
+
+ $this->assertEquals('00000000', $prod->getElementsByTagName('NCM')->item(0)->nodeValue);
+ }
+
+ public function test_tagNCMShouldNotAcceptEmptyValue_whenCrtIs1(): void
+ {
+ $std = new \stdClass();
+ $std->idDest = 1;
+ $this->make->tagide($std);
+
+ $std = new \stdClass();
+ $std->CRT = 1;
+ $this->make->tagemit($std);
+
+ $std = new \stdClass();
+ $std->item = 1;
+ $std->cProd = '1111';
+ $std->cEAN = "SEM GTIN";
+ $std->xProd = 'CAMISETA REGATA GG';
+ $std->NCM = null;
+ $std->CFOP = 5101;
+ $std->uCom = 'UN';
+ $std->qCom = 1;
+ $std->vUnCom = 100.00;
+ $std->vProd = 100.00;
+ $std->cEANTrib = "SEM GTIN";
+ $std->uTrib = 'UN';
+ $std->qTrib = 1;
+ $std->vUnTrib = 100.00;
+ $std->indTot = 1;
+ $this->make->tagprod($std);
+
+ $this->assertContains(
+ 'Preenchimento Obrigatório! [NCM] I01 - [item 1] Código NCM com 8 dígitos ou 2 dígitos (gênero)',
+ $this->make->getErrors()
+ );
+ }
+
+ public function test_tagNCMShouldNotAcceptEmptyValue_whenCrtIs4AndIdDestIsNot1(): void
+ {
+ $std = new \stdClass();
+ $std->idDest = 2;
+ $this->make->tagide($std);
+
+ $std = new \stdClass();
+ $std->CRT = 4;
+ $this->make->tagemit($std);
+
+ $std = new \stdClass();
+ $std->item = 1;
+ $std->cProd = '1111';
+ $std->cEAN = "SEM GTIN";
+ $std->xProd = 'CAMISETA REGATA GG';
+ $std->NCM = null;
+ $std->CFOP = 5101;
+ $std->uCom = 'UN';
+ $std->qCom = 1;
+ $std->vUnCom = 100.00;
+ $std->vProd = 100.00;
+ $std->cEANTrib = "SEM GTIN";
+ $std->uTrib = 'UN';
+ $std->qTrib = 1;
+ $std->vUnTrib = 100.00;
+ $std->indTot = 1;
+ $this->make->tagprod($std);
+
+ $this->assertContains(
+ 'Preenchimento Obrigatório! [NCM] I01 - [item 1] Código NCM com 8 dígitos ou 2 dígitos (gênero)',
+ $this->make->getErrors()
+ );
+ }
+
private function validarExistenciaCampos(\stdClass $std, \DOMElement $tag): void
{
$attributos = get_object_vars($std);