From ec32296a1537ddbce37e9b25bf5d2b7decb61248 Mon Sep 17 00:00:00 2001 From: Gerson Felipe Schwinn Date: Fri, 7 Jun 2024 17:03:33 -0300 Subject: [PATCH 01/14] Validando pattern de TiposBasicos --- tests/TiposBasicosTest.php | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/TiposBasicosTest.php diff --git a/tests/TiposBasicosTest.php b/tests/TiposBasicosTest.php new file mode 100644 index 00000000..f81702a4 --- /dev/null +++ b/tests/TiposBasicosTest.php @@ -0,0 +1,35 @@ +markTestSkipped('Versão muito baixa do PHP para o teste'); + } + + $doc = new \DOMDocument(); + $xsdstring = file_get_contents(dirname(__DIR__) . '/schemes/PL_009_V4/tiposBasico_v4.00.xsd'); + $doc->loadXML(mb_convert_encoding($xsdstring, 'utf-8', mb_detect_encoding($xsdstring))); + $xpath = new \DOMXPath($doc); + $xpath->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema'); + + $item = $xpath->query('xs:simpleType[@name="TString"]/xs:restriction/xs:pattern')->item(0); + $this->assertNotNull($item, 'Não foi encontrado o simpleType TString'); + /** @var \DOMNamedNodeMap $atributos */ + $atributos = $item->attributes; + + /** @var \DOMAttr $node */ + $node = $atributos->getNamedItem('value'); + + $this->assertEquals( + '[!-ÿ]{1}[ -ÿ]*[!-ÿ]{1}|[!-ÿ]{1}', + $node->value, + 'Por favor, corrija o pattern no arquivo tiposBasico_v4.00.xsd. Issue #940' + ); + } +} From 6d4357fe484b74e18cffee67b4465aadeb489733 Mon Sep 17 00:00:00 2001 From: robmachado Date: Tue, 11 Jun 2024 16:01:09 -0300 Subject: [PATCH 02/14] =?UTF-8?q?Apenas=20o=20arquivo=20md=20relativo=20a?= =?UTF-8?q?=20opera=C3=A7=C3=A3o=20em=20contingencia=20SVC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Contingency.md | 232 +++++++++++++++++++++++++++----------------- 1 file changed, 145 insertions(+), 87 deletions(-) diff --git a/docs/Contingency.md b/docs/Contingency.md index f1ecb181..ad25f095 100755 --- a/docs/Contingency.md +++ b/docs/Contingency.md @@ -2,97 +2,111 @@ Em condições normais as NFe emitidas tem a propriedade <tpEmis> com o valor igual a 1-Emissão normal. -Quando a conexão via internet com a SEFAZ autorizadora não é possivel, existem alternativas para permitir a emissão dos documentos mesmo nessas condições (offline). - -Para uma melhor compreensão, o ENCAT lançou um documento que visa facilitar o entendimento, ele pode ser encontrado em: - -[Página Principal](http://www.nfe.fazenda.gov.br/portal/principal.aspx) > Documentos > Manuais > Manual de Boas Práticas no desenvolvimento de emissor de NFC-e – BP 2018.001 – versão 1.0 - -Após lê-lo, os procedimentos abaixo podem ser realizadas na biblioteca, há uma sessão interessante sobre contigência. +Quando a conexão via internet com a SEFAZ autorizadora não é possivel, existem alternativas para permitir a emissão dos documentos mesmo nessas condições. Ao ativar qualquer contigência o XML da NFe deve ser remontado ou modificado e assinado novamente com as seguintes alterações: - <tpEmis> indicar o número do modo de contingência utilizado - <dhCont> Data e Hora da entrada em contingência no formato com TZD - <xJust> Justificativa da entrada em contingência com 15 até 256 caracteres -### ~~FS-IA IMPRESSOR AUTÔNOMO (tpEmis = 2 OBSOLETO)~~ -Este modo de contingência permite que a NFe seja emitida sem que haja a prévia autorização pela SEFAZ autorizadora através da impressão do DANFE em formulário de segurança de impressor autônomo. +## FS-DA DOCUMENTO AUXILIAR (tpEmis = 5) *apenas NFe (mod 55)* +Este modo de contingência permite que a NFe seja emitida sem que haja a prévia autorização pela SEFAZ autorizadora através da impressão do DANFE em formulário de segurança. -**Uso: Não mais pode ser usado** +**Uso: Sem acesso a internet ou com a SEFAZ offline.** -**Este modelo de contingência está desabilitado desde 2011. E não pode mais ser usado** +Este modo de contingência permite que a NFe seja emitida sem que haja a prévia autorização pela SEFAZ autorizadora através da impressão do DANFE em formulário de segurança. -Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 2 +**E ao retornar o serviço da SEFAZ autorizadora estes documentos deverão ser enviados dentro do prazo limite de 24 horas**. -### ~~SCAN (tpEmis = 3 OBSOLETO)~~ -Sistema de Contingência do Ambiente Nacional, **este serviço foi desabilitado e portanto não está mais disponivel para uso**. +Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 5 +> Não é recomendável o uso desse tipo de contingência com a NFe, por vários motivos. O primeiro é o custo, pois os formulários de segurança são caros e deve-se manter controle estrito sobre os mesmos, pois cada folha é identificada individualmente e pode ser usada indevidamente. -**Uso: Não mais pode ser usado** +> Devemos considerar também a necessidade adicional de controle dessas notas e posterior envio à SEFAZ autorizadora quando o sistema estiver novamente on-line. -Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 3 +> Outro motivo é a possibilidade de a NFe ser reprovada após o processo posterior de envio a SEFAZ autorizadora, com isso o transporte e recebimento da mercadoria se torna uma operação "ilegal" e sujeita a punições. +> Se for usar esse método melhore o sistema emissão com muitas validações, para garantir que erros sejam identificados antes de geração do ducumento, para evitar problemas posteriores e multas. -### ~~DPEC (tpEmis = 4 OBSOLETO)~~ -Declaração Prévia da Emissão em Contingência -Este tipo de contingência foi substituido pelo modo EPEC que utiliza eventos para registrar a emissão. Veja EPEC. +## SVC-AN (tpEmis = 6) *Apenas NFe (modelo 55)* -**Uso: Não mais pode ser usado** +SEFAZ Virtual de Contingência do Ambiente Nacional -Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 4 +Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 6 -### EPEC (tpEmis = 4) *NFe e NFCe* -Evento Prévio da Emissão em Contingência +Este sistema de contingência é o **melhor de todos** e permite que as notas sejam emitidas com poucas alterações e sem a necessidade de reenvio posterior. Nesse modo as notas enviadas serão sincronizadas automaticamente pelos orgãos autorizadores sem a necessidade que qualquer outra ação pelo emitente. Este serviço atende: +AC, AL, AP, CE, DF, ES, MG, PA, PB, PI, RJ, RN, RO, RR, RS, SC, SE, SP, TO -**Uso: SEFAZ OFF e SVC OFF mas emitente com acesso à internet.** +> Este é o caso de uso da classe Contingency da nossa biblioteca, inclusive NFe emitidas em modo normal será automaticamente ajustadas para o ambiente de contingência e novamente assinadas quando contingencia SVCAN estiver ativada na class Tools. -Este modo de contingência é diferente dos demais por que na verdade irá enviar um evento especifico para o webservices de Registro de Eventos do Ambiente Nacional. Normalmente usa-se esse tipo de contingência em caso da SEFAZ autorizadora estar fora do ar, bem como o Serviço Virtual de Contingência também, e isso é uma situação muito rara de ocorrer. +> IMPORTANTE: este processo irá alterar a chave da NFe, e portanto deverá ser regravada em sua base de dados (com a chave nova gerada pelo processo de envio). -Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 4 +**Uso: SEFAZ OFFLINE, mas emitente com acesso à internet, e sistema de contigência SVCAN ativado pela SEFAZ autorizadora do seu estado.** -### FS-DA DOCUMENTO AUXILIAR (tpEmis = 5) *NFe e NFCe* -Este modo de contingência permite que a NFe seja emitida sem que haja a prévia autorização pela SEFAZ autorizadora através da impressão do DANFE em formulário de segurança. -**Uso: Sem acesso a internet.** +## SVC-RS (tpEmis = 7) *Apenas NFe (modelo 55)* -Este modo de contingência permite que a NFe seja emitida sem que haja a prévia autorização pela SEFAZ autorizadora através da impressão do DANFE em formulário de segurança. +SEFAZ Virtual de Contingência do RS -Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 2 -> Não é recomendável o uso desse tipo de contingência com a NFe, por vários motivos. O primeiro é o custo, pois os formulários de segurança são caros e deve-se manter controle estrito sobre os mesmos, pois cada folha é identificada individualmente e pode ser usada indevidamente. +Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 7 -> Devemos considerar também a necessidade adicional de controle dessas notas e posterior envio à SEFAZ autorizadora quando o sistema estiver novamente on-line. +Este sistema de contingência é o **melhor de todos** e permite que as notas sejam emitidas com poucas altereções e sem a necessidade de reenvio posterior. Nesse modo as notas enviadas serão sincronizadas automaticamente pelos orgãos autorizadores sem a necessidade que qualquer outra ação pelo emitente. Este serviço atende: +AM, BA, GO, MA, MS, MT, PE, PR -> Outro motivo é a possibilidade de a NFe ser reprovada após o processo posterior de envio a SEFAZ autorizadora, com isso o transporte e recebimento da mercadoria se torna uma operação "ilegal" e sujeita a punições. +> Este é o caso de uso da classe Contingency da nossa biblioteca, inclusive NFe emitidas em modo normal será automaticamente ajustadas para o ambiente de contingência e novamente assinadas quando contingencia SVCAN estiver ativada na class Tools. -Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 5 +> IMPORTANTE: este processo irá alterar a chave da NFe, e portanto deverá ser regravada em sua base de dados (com a chave nova gerada pelo processo de envio). -### SVC-AN (tpEmis = 6) *Apenas NFe (modelo 55)* -SEFAZ Virtual de Contingência do Ambiente Nacional +**Uso: SEFAZ OFFLINE, mas emitente com acesso à internet, e sistema de contigência SVCRS ativado pela SEFAZ autorizadora do seu estado.** -Este sistema de contingência é o **melhor de todos** e permite que as notas sejam emitidas com poucas alterações e sem a necessidade de reenvio posterior. Nesse modo as notas enviadas serão sincronizadas automaticamente pelos orgãos autorizadores sem a necessidade que qualquer outra ação pelo emitente. Este serviço atende: -AC, AL, AP, DF, ES, MG, PB, RJ, RN, RO, RR, RS, SC, SE, SP, TO -**Uso: SEFAZ OFF, mas emitente com acesso à internet.** +## OFF-LINE (tpEmis = 9) *EXCLUSIVO PARA NFCe* -Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 6 +Este modo de contingência permite que a NFCe seja emitida sem que haja a prévia autorização pela SEFAZ autorizadora através da impressão do DANFCE. -### SVC-RS (tpEmis = 7) *Apenas NFe (modelo 55)* -SEFAZ Virtual de Contingência do RS +**E ao retornar o serviço da SEFAZ autorizadora estes documentos deverão ser enviados dentro do prazo limite de 24 horas**. -Este sistema de contingência é o melhor de todos e permite que as notas sejam emitidas com poucas altereções e sem a necessidade de reenvio posterior. Nesse modo as notas enviadas serão sincronizadas automaticamente pelos orgãos autorizadores sem a necessidade que qualquer outra ação pelo emitente. Este serviço atende: -AM, BA, CE, GO, MA, MS, MT, PA, PE, PI, PR +Nesse caso o xml da NFCe deve indicar na propriedade <tpEmis> o valor 9 -**Uso: SEFAZ OFF, mas emitente com acesso à internet.** +> *IMPORTANTE*: Esse modo de contingência serve exclusivamente para as notas modelo 65 e não podem ser usadas em notas modelo 55. -Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 7 +> Todos os estados permitem a emissão de NFCe em modo OFFLINE, exceto SP, onde é obrigátorio o uso do SAT@ecf ou da emissão por EPEC NFCe -### OFF-LINE (tpEmis = 9) *EXCLUSIVO PARA NFCe* -Para a NFCe somente estão disponíveis e são válidas as opções de contingência 5 (FS-DA) e 9 (OFF-LINE). +**Uso: Sem acesso a internet ou com a SEFAZ offline.** -> *IMPORTANTE*: Esse modo de contingência serve exclusivamente para as notas modelo 65 e não podem ser usadas em notas modelo 55. -**Uso: Sem acesso a internet.** +## EPEC (tpEmis = 4) *NFe e NFCe* -Nesse caso o xml da NFCe deve indicar na propriedade <tpEmis> o valor 9 +Evento Prévio da Emissão em Contingência + +Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 4 + +Este é o processo mais complexo e "arriscado" entre todos os modos de contigência. + +São dois tipos diferentes mas que seguem basicamente as mesmas regras estruturas e condições, apenas são direcionados para webservices diferentes. + +Em ambos os casos são criados eventos EPEC Evento Prévio de Emissão em Contingência, para emitir em EPEC devem ser observados os seguintes passos: + +1. criar a NFe ou a NFCe já marcada em contignência EPEC com **tpEmis = 4**, **dhCont = data hora de entrada em contingência** e **xJust = justificativa** +2. criar e enviar o evento EPEC pelos métodos da classe Tools, sendo: + - $tools->sefazEPEC($xml, $verAplic) para NFe (mod 55) + - $tools->sefazEpecNfce($xml, $verAplic) para NFCe (mod 65) +3. verificar se o evento foi autorizado, se sim protocolar, se não tratar o erro até ser autorizado +4. usar o xml e os dados do EPEC autorizado para imprimir o DANFE ou DANFCE +5. enviar o xml assim que a SEFAZ autorizadora retornar a operção normal + +### EPEC NFe (mod 55) + +Este processo envia o EPEC para o ambiente nacional + +### EPEC NFCe (mod 65) + +Este processo envia o EPEC para o webservice de registro de EPEC especifico para NFCe exclusivamente no estado de São Paulo. + +> NOTA: não existe EPEC para NFCe em outros estados, neles deve ser usado a contingência OFFLINE + +Este modo de contingência é diferente dos demais por que na verdade irá enviar um evento especifico para o webservices de Registro de Eventos do Ambiente Nacional. Normalmente usa-se esse tipo de contingência em caso da SEFAZ autorizadora estar fora do ar, bem como o Serviço Virtual de Contingência também, e isso é uma situação muito rara de ocorrer. + +**Uso: SEFAZ OFF e SVC OFF mas emitente com acesso à internet.** # [Esclarecimentos sobre TIMEOUT](TimeOut.md) @@ -103,21 +117,63 @@ Nesse caso o xml da NFCe deve indicar na propriedade <tpEmis> o valor 9 **Habilitando o modo de contingência** +A classe Contingency somente será usada para envio de NFe (mod 55) para as contigências SVC-AN ou SVC-RS, que são substitutos diretos à emissão normal. + +Os demais tipos de contingência como: + +- FS-DA DOCUMENTO AUXILIAR (tpEmis = 5), o xml é criado em modo contigência e a NFe é impressa nesse formulário e posteriormente enviada para a SEFAZ autorizadora. +- OFFLINE NFCe (mod 65), o xml é criado já em modo de contingência OFFLINE (tpEmis = 9) e a NFCe é impressa e posteriormente enviada para a SEFAZ autorizadora. +- EPEC NFe (mod 55), o xml é criado em modo de contingência EPEC, e usado para criar o evento EPEC, se o evento for aceito poderá ser usado conjuntamente com a NFe para imprimir a DANFE e posteriormente enviar a NFe para a SEFAZ autorizadora. +- EPEC NFCe (mod 65) exclusivo para o estado de SP, o xml é criado em modo de contingência EPEC, e usado para criar o evento EPEC NFCe (apenas em SP), se o evento for aceito poderá ser usado conjuntamente com a NFCe para imprimir a DANFCE e posteriormente enviar a NFCe para a SEFAZ SP. + +Como deve ser feito o processo no seu sistema: + +1. ao entrar em contingência, sempre verifique se a mesma está ativa para o seu estado +2. ative o modo de contingência e grave o json retornado em um cache ou pbase de dados, para habilitar seu uso continuo +3. ao enviar uma NFe (mod 55), sempre verifique esse json no cache ou na base de dados e o recarregue em Contingency::class +4. injete a Contingency::class na classe principal Tools::class +```php + +$cert = Certificate::readPfx(file_get_contents('certificado.pfx'), 'senha'); +//recarrega a contingencia que foi enteriormente ativada e gravada em cache +$cont = null; +if (!empty($json_contingencia_do_cache)) { + $cont = new Contingency($json_contingencia_do_cache); +} +//inicia o serviço da Tools::class em contingência se ela estiver ativa +$tools = new Tools($configJson, $cert, $cont); +$tools->model(55); +``` +5. ou carregue a proriedade publica da classe $tools->contingency +```php +$cert = Certificate::readPfx(file_get_contents('certificado.pfx'), 'senha'); +//recarrega a contingencia que foi enteriormente ativada e gravada em cache +$cont = null; +if (!empty($json_contingencia_do_cache)) { + $cont = new Contingency($json_contingencia_do_cache); +} +//inicia o serviço da Tools::class em contingência se ela estiver ativa +$tools = new Tools($configJson, $cert); +$tools->contingency = $cont; +$tools->model(55); ``` + +```php use NFePHP\NFe\Factories\Contingency; $contingency = new Contingency(); -$acronym = 'SP'; -$motive = 'SEFAZ fora do AR'; -$type = 'SVCAN'; +$acronym = 'SP'; //Obrigatório +$motive = 'SEFAZ fora do AR'; //Obrigatório +$type = 'SVCAN'; //opcional, opções SVCAN ou SVCRS, se não informado será usado o tipo relativo à UF informada $status = $contingency->activate($acronym, $motive, $type); ``` -$status irá conter uma string JSON ENCODED, com as informações sobre a condição de contingência. +$status irá conter uma string JSON ENCODED, com as informações sobre a condição de contingência. -``` + +```json { "motive":"SEFAZ fora do AR", "timestamp":1484747583, @@ -127,24 +183,29 @@ $status irá conter uma string JSON ENCODED, com as informações sobre a condi ``` Essa string deverá ser arquivada, em disco ou em base de dados para uso posterior, até que o modo de contingencia seja desabilitado. Ou seja, a cada vez que carregar a classe Tools deverá ser passada a classe contingency, ou será considerado que o ambiente é normal. Exemplo: -``` +```php +$status_contingencia = '{ + "motive":"SEFAZ fora do AR", + "timestamp":1484747583, + "type":"SVCAN", + "tpEmis":6 +}'; + +$contingency = (new Contingency())->load($status_contingencia); $tools->contingency = $contingency; ``` - - **Desabilitando o modo de contingência** -``` +```php use NFePHP\NFe\Factories\Contingency; -//onde $status é a string obtida quando entrou em modo de contingência. +//onde $status é a string json obtida quando entrou em modo de contingência. $contingency = new Contingency($status); - $status = $contingency->deactivate(); ``` $status irá conter dados padrões em condições normais. -``` +```json { "motive":"", "timestamp":0, @@ -160,7 +221,7 @@ Essa string deverá ser arquivada, em disco ou em base de dados para uso posteri public $type; @var string -> Tipo da contingência FSDA, SVCAN, SVCRS, EPEC, OFFLINE +> Tipo da contingência SVCAN, SVCRS public $motive; @@ -168,12 +229,12 @@ public $motive; @var string > Motivo da entrada em contingência, texto com no minimo 15 caracteres e no máximo 255. -> NOTA: remova todo e qualquer caracter especial desse texto. +> NOTA: somente são aceitos caracteres UTF-8 e não devem ser usados simbolos. public $timestamp; @var int ->Timestmap do PHP que representa a data e hora em que a contignência foi ativada. +>Timestmap do PHP que representa a data e hora em que a contigência foi ativada (GMT). public $tpEmis; @@ -186,34 +247,31 @@ public $tpEmis; Construtor, caso seja passado o parametro, uma string JSON, a condição de contingência contida nessa string será registrada na classe. Caso nada seja passado a classe irá considerar condição de emissão normal. -``` -Contingency::construct($string) +```php +$cont = new Contingency($string_Json_Contingencia); ``` Essa é outra forma de passar o parametro (string JSON) para a classe. -``` -Contingency::load($string) +```php +$cont = (new Contingency())->load($string_Json_Contingencia); ``` Esse método ativa o modo de continência da classe. Os parametros são: +```php +$sigla = 'SP'; //a sigla do estado do emitente da NFe +$motivo = 'SEFAZ SP fora do ar por problemas técnicos'; //motivo da entrada em contingencia de 15 a 256 caracteres UTF-8 +$tipo = ''; //não é necessario de forma geral +$cont = (new Contingency())->activate($sigla, $motivo, $tipo); ``` -Contingency::activate($acronym, $motive, $type) -``` - -$acronym --- sigla do estado - -$motive --- texto com o motivo da entrada em contingência - -$type --- podem ser usadas as constantes: - -- Contingency::SVCAN -- Contingency::SVCRS -- Contingency::FSDA -- Contingency::OFFLINE -- Contingency::EPEC Esse método desativa o modo de contingência e retorna uma string json com os valores padrões. -``` -Contingency::deactivate() +```php +$sigla = 'SP'; //a sigla do estado do emitente da NFe +$motivo = 'SEFAZ SP fora do ar por problemas técnicos'; //motivo da entrada em contingencia de 15 a 256 caracteres UTF-8 +$tipo = ''; //não é necessario de forma geral +$cont = new Contingency(); +$status_json_contingencia_ativada = $cont->activate($sigla, $motivo, $tipo); + +$status_json_contingencia_desativada = $cont->deactivate(); ``` From c829248f374758091ce5e965387303fc7ce44a55 Mon Sep 17 00:00:00 2001 From: robmachado Date: Tue, 11 Jun 2024 16:02:46 -0300 Subject: [PATCH 03/14] =?UTF-8?q?Apenas=20o=20arquivo=20md=20relativo=20a?= =?UTF-8?q?=20opera=C3=A7=C3=A3o=20em=20contingencia=20SVC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Contingency.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/Contingency.md b/docs/Contingency.md index ad25f095..e655680e 100755 --- a/docs/Contingency.md +++ b/docs/Contingency.md @@ -14,8 +14,6 @@ Este modo de contingência permite que a NFe seja emitida sem que haja a prévia **Uso: Sem acesso a internet ou com a SEFAZ offline.** -Este modo de contingência permite que a NFe seja emitida sem que haja a prévia autorização pela SEFAZ autorizadora através da impressão do DANFE em formulário de segurança. - **E ao retornar o serviço da SEFAZ autorizadora estes documentos deverão ser enviados dentro do prazo limite de 24 horas**. Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 5 From 4a53d19e05713bfe4a931ea7255c7416616d5ab2 Mon Sep 17 00:00:00 2001 From: robmachado Date: Tue, 11 Jun 2024 17:08:44 -0300 Subject: [PATCH 04/14] =?UTF-8?q?Apenas=20o=20arquivo=20md=20relativo=20a?= =?UTF-8?q?=20opera=C3=A7=C3=A3o=20em=20contingencia=20SVC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Factories/Contingency.php | 75 ++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/src/Factories/Contingency.php b/src/Factories/Contingency.php index 78d3258a..74af382a 100755 --- a/src/Factories/Contingency.php +++ b/src/Factories/Contingency.php @@ -21,11 +21,6 @@ class Contingency { public const SVCAN = 'SVCAN'; public const SVCRS = 'SVCRS'; - public const OFFLINE = 'OFFLINE'; - public const EPEC = 'EPEC'; - public const FSDA = 'FS-DA'; - public const TPEMIS_FSDA = 5; - public const TPEMIS_OFFLINE = 9; /** * @var \stdClass @@ -73,13 +68,15 @@ public function load(string $contingency): void /** * Create a object with contingency data - * @param string $acronym Sigla do estado - * @param string $type Opcional parameter only used if FS-DA, EPEC or OFFLINE + * @param string $acronym sigla dos estados + * @param string $motive motivo de entrada em contingência + * @param string $type tipo de contingência SVCAN ou SVCRS + * @return string + * @throws \Exception */ public function activate(string $acronym, string $motive, string $type = ''): string { - $dt = new \DateTime('now'); - $list = array( + $list = [ 'AC' => 'SVCAN', 'AL' => 'SVCAN', 'AM' => 'SVCRS', @@ -107,13 +104,31 @@ public function activate(string $acronym, string $motive, string $type = ''): st 'SE' => 'SVCAN', 'SP' => 'SVCAN', 'TO' => 'SVCAN' - ); - $type = strtoupper(str_replace('-', '', $type)); + ]; + if (!empty($type)) { + $type = strtoupper(str_replace('-', '', $type)); + if (!in_array($type, ['SVCAN', 'SVCRS'])) { + throw new \RuntimeException( + "O tipo indicado de contingência não é aceito nesta operação. Usar apenas SVCAN ou SVCRS" + ); + } + $this->type = $type; + } + //gerar o timestamp para Greenwich (GMT). + $dt = new \DateTime(gmdate('Y-m-d H:i:s')); //data hora GMT + $this->motive = trim($motive); + $len = mb_strlen($this->motive); + if ($len < 15 || $len > 255) { + throw new \RuntimeException( + "A justificativa para entrada em contingência deve ter entre 15 e 256 caracteres UTF-8." + ); + } + $this->timestamp = $dt->getTimestamp(); if (empty($type)) { - $type = $list[$acronym]; + $this->type = $list[$acronym]; } - $this->config = $this->configBuild($dt->getTimestamp(), $motive, $type); + $this->config = $this->configBuild(); return $this->__toString(); } @@ -122,11 +137,11 @@ public function activate(string $acronym, string $motive, string $type = ''): st */ public function deactivate(): string { - $this->config = $this->configBuild(0, '', ''); $this->timestamp = 0; $this->motive = ''; $this->type = ''; $this->tpEmis = 1; + $this->config = $this->configBuild(); return $this->__toString(); } @@ -141,16 +156,10 @@ public function __toString(): string /** * Build parameter config as stdClass */ - private function configBuild(int $timestamp, string $motive, string $type): \stdClass + private function configBuild(): \stdClass { - switch ($type) { - case 'EPEC': - $tpEmis = 4; - break; - case 'FS-DA': - case 'FSDA': - $tpEmis = 5; - break; + $tpEmis = 1; + switch ($this->type) { case 'SVC-AN': case 'SVCAN': $tpEmis = 6; @@ -159,25 +168,19 @@ private function configBuild(int $timestamp, string $motive, string $type): \std case 'SVCRS': $tpEmis = 7; break; - case 'OFFLINE': //this is only to model 65 NFCe - $tpEmis = 9; - break; default: - if ($type == '') { + if ($this->type === '') { $tpEmis = 1; - $timestamp = 0; - $motive = ''; + $this->timestamp = 0; + $this->motive = ''; break; } - throw new \InvalidArgumentException( - "Tipo de contingência " - . "[$type] não está disponível;" - ); } + $this->tpEmis = $tpEmis; $config = new \stdClass(); - $config->motive = Strings::replaceUnacceptableCharacters(substr(trim($motive), 0, 256)); - $config->timestamp = $timestamp; - $config->type = $type; + $config->motive = Strings::replaceUnacceptableCharacters(substr(trim($this->motive), 0, 256)); + $config->timestamp = $this->timestamp; + $config->type = $this->type; $config->tpEmis = $tpEmis; $this->load(json_encode($config)); return $config; From bd1673b3a98e73b2e145f9da095c24c5a6f7113f Mon Sep 17 00:00:00 2001 From: robmachado Date: Tue, 11 Jun 2024 17:09:42 -0300 Subject: [PATCH 05/14] =?UTF-8?q?Apenas=20o=20arquivo=20md=20relativo=20a?= =?UTF-8?q?=20opera=C3=A7=C3=A3o=20em=20contingencia=20SVC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Contingency.md | 77 ++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/docs/Contingency.md b/docs/Contingency.md index e655680e..9f4601af 100755 --- a/docs/Contingency.md +++ b/docs/Contingency.md @@ -22,7 +22,7 @@ Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 5 > Devemos considerar também a necessidade adicional de controle dessas notas e posterior envio à SEFAZ autorizadora quando o sistema estiver novamente on-line. > Outro motivo é a possibilidade de a NFe ser reprovada após o processo posterior de envio a SEFAZ autorizadora, com isso o transporte e recebimento da mercadoria se torna uma operação "ilegal" e sujeita a punições. -> Se for usar esse método melhore o sistema emissão com muitas validações, para garantir que erros sejam identificados antes de geração do ducumento, para evitar problemas posteriores e multas. +> Se for usar esse método melhore o sistema emissão com muitas validações, para garantir que erros sejam identificados antes de geração do documento, para evitar problemas posteriores e multas. ## SVC-AN (tpEmis = 6) *Apenas NFe (modelo 55)* @@ -34,9 +34,9 @@ Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 6 Este sistema de contingência é o **melhor de todos** e permite que as notas sejam emitidas com poucas alterações e sem a necessidade de reenvio posterior. Nesse modo as notas enviadas serão sincronizadas automaticamente pelos orgãos autorizadores sem a necessidade que qualquer outra ação pelo emitente. Este serviço atende: AC, AL, AP, CE, DF, ES, MG, PA, PB, PI, RJ, RN, RO, RR, RS, SC, SE, SP, TO -> Este é o caso de uso da classe Contingency da nossa biblioteca, inclusive NFe emitidas em modo normal será automaticamente ajustadas para o ambiente de contingência e novamente assinadas quando contingencia SVCAN estiver ativada na class Tools. +> Este é o caso de uso da classe Contingency da nossa biblioteca, inclusive NFe emitida em modo normal será automaticamente ajustada para o ambiente de contingência e novamente assinada quando contingencia SVCAN estiver ativada na class Tools. -> IMPORTANTE: este processo irá alterar a chave da NFe, e portanto deverá ser regravada em sua base de dados (com a chave nova gerada pelo processo de envio). +> IMPORTANTE: este processo **irá alterar a chave da NFe**, e portanto deverá ser **regravada em sua base de dados** (com a chave nova gerada pelo processo de envio). **Uso: SEFAZ OFFLINE, mas emitente com acesso à internet, e sistema de contigência SVCAN ativado pela SEFAZ autorizadora do seu estado.** @@ -50,9 +50,9 @@ Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 7 Este sistema de contingência é o **melhor de todos** e permite que as notas sejam emitidas com poucas altereções e sem a necessidade de reenvio posterior. Nesse modo as notas enviadas serão sincronizadas automaticamente pelos orgãos autorizadores sem a necessidade que qualquer outra ação pelo emitente. Este serviço atende: AM, BA, GO, MA, MS, MT, PE, PR -> Este é o caso de uso da classe Contingency da nossa biblioteca, inclusive NFe emitidas em modo normal será automaticamente ajustadas para o ambiente de contingência e novamente assinadas quando contingencia SVCAN estiver ativada na class Tools. +> Este é o caso de uso da classe Contingency da nossa biblioteca, inclusive NFe emitida em modo normal será automaticamente ajustada para o ambiente de contingência e novamente assinada quando contingencia SVCRS estiver ativada na class Tools. -> IMPORTANTE: este processo irá alterar a chave da NFe, e portanto deverá ser regravada em sua base de dados (com a chave nova gerada pelo processo de envio). +> IMPORTANTE: este processo irá **alterar a chave da NFe**, e portanto deverá ser **regravada em sua base de dados** (com a chave nova gerada pelo processo de envio). **Uso: SEFAZ OFFLINE, mas emitente com acesso à internet, e sistema de contigência SVCRS ativado pela SEFAZ autorizadora do seu estado.** @@ -67,10 +67,13 @@ Nesse caso o xml da NFCe deve indicar na propriedade <tpEmis> o valor 9 > *IMPORTANTE*: Esse modo de contingência serve exclusivamente para as notas modelo 65 e não podem ser usadas em notas modelo 55. -> Todos os estados permitem a emissão de NFCe em modo OFFLINE, exceto SP, onde é obrigátorio o uso do SAT@ecf ou da emissão por EPEC NFCe +> Todos os estados permitem a emissão de NFCe em modo OFFLINE, exceto SP, onde é obrigátorio o uso do SAT@ecf ou da emissão por EPEC NFCe. -**Uso: Sem acesso a internet ou com a SEFAZ offline.** +> Outro problema com essas NFCe-OFFLINE é a possibilidade de a NFe ser reprovada após o processo posterior de envio a SEFAZ autorizadora, com isso o transporte e recebimento da mercadoria se torna uma operação "ilegal" e sujeita a punições. +> Se for usar esse método melhore o sistema emissão com muitas validações, para garantir que erros sejam identificados antes de geração do documento, para evitar problemas posteriores e multas. +> Mas em caso de erro detectado pela SEFAZ pode corrigir a mesma NFCe, assinar novamente e enviar dentro do prazo estabelecido, mas o documento impresso originalmente estará diferente da versão final e em principio deverá ser substituido com o consumidor. +**Uso: Sem acesso a internet ou com a SEFAZ offline.** ## EPEC (tpEmis = 4) *NFe e NFCe* @@ -78,42 +81,42 @@ Evento Prévio da Emissão em Contingência Nesse caso o xml da NFe deve indicar na propriedade <tpEmis> o valor 4 -Este é o processo mais complexo e "arriscado" entre todos os modos de contigência. +Este é o processo **mais complexo e "arriscado"** entre todos os modos de contigência. São dois tipos diferentes mas que seguem basicamente as mesmas regras estruturas e condições, apenas são direcionados para webservices diferentes. -Em ambos os casos são criados eventos EPEC Evento Prévio de Emissão em Contingência, para emitir em EPEC devem ser observados os seguintes passos: +Em ambos os casos são criados eventos EPEC Evento Prévio de Emissão em Contingência, e para emitir em EPEC devem ser observados os seguintes passos: 1. criar a NFe ou a NFCe já marcada em contignência EPEC com **tpEmis = 4**, **dhCont = data hora de entrada em contingência** e **xJust = justificativa** 2. criar e enviar o evento EPEC pelos métodos da classe Tools, sendo: - - $tools->sefazEPEC($xml, $verAplic) para NFe (mod 55) - - $tools->sefazEpecNfce($xml, $verAplic) para NFCe (mod 65) -3. verificar se o evento foi autorizado, se sim protocolar, se não tratar o erro até ser autorizado -4. usar o xml e os dados do EPEC autorizado para imprimir o DANFE ou DANFCE -5. enviar o xml assim que a SEFAZ autorizadora retornar a operção normal + - $tools->sefazEPEC($xml, $verAplic) para NFe (mod 55) + - $tools->sefazEpecNfce($xml, $verAplic) para NFCe (mod 65) +3. verificar se o evento foi autorizado, se sim protocolar, se não tratar o erro até o evento ser autorizado +4. usar o xml da NFe/NFCe e os dados do EPEC autorizado para imprimir o DANFE ou DANFCE +5. enviar o xml assim que a SEFAZ autorizadora retornar a operação normal ### EPEC NFe (mod 55) -Este processo envia o EPEC para o ambiente nacional +Este processo envia o EPEC para o ambiente nacional da NFe. ### EPEC NFCe (mod 65) -Este processo envia o EPEC para o webservice de registro de EPEC especifico para NFCe exclusivamente no estado de São Paulo. +Este processo envia o EPEC para o webservice de registro de EPEC especifico para NFCe, exclusivamente no estado de São Paulo. -> NOTA: não existe EPEC para NFCe em outros estados, neles deve ser usado a contingência OFFLINE +> NOTA: não existe EPEC para NFCe em outros estados, neles deve ser usada a contingência OFFLINE Este modo de contingência é diferente dos demais por que na verdade irá enviar um evento especifico para o webservices de Registro de Eventos do Ambiente Nacional. Normalmente usa-se esse tipo de contingência em caso da SEFAZ autorizadora estar fora do ar, bem como o Serviço Virtual de Contingência também, e isso é uma situação muito rara de ocorrer. -**Uso: SEFAZ OFF e SVC OFF mas emitente com acesso à internet.** +> IMPORTANTE: a emissão de um evento EPEC cria a pendência do envio de uma nota que seja autorizada ou denegada dentro do limite de 7 dias para que seja vinculada ao EPEC, caso contrario, se algum evento EPEC não for vinculado ao uma NFe/NFCe, o emitente ficará **bloqueado e não mais porderá enviar eventos EPEC**. -# [Esclarecimentos sobre TIMEOUT](TimeOut.md) +**Uso: NFe SEFAZ OFF e SVC OFF mas emitente com acesso à internet.** +**Uso: NFCe SEFAZ-SP OFF e EPEC-NFCe-SP ativo e emitente com acesso à internet.** -# Class Factories\Contingency +# [Esclarecimentos sobre TIMEOUT](TimeOut.md) -## USAGE -**Habilitando o modo de contingência** +## USO A classe Contingency somente será usada para envio de NFe (mod 55) para as contigências SVC-AN ou SVC-RS, que são substitutos diretos à emissão normal. @@ -126,9 +129,9 @@ Os demais tipos de contingência como: Como deve ser feito o processo no seu sistema: -1. ao entrar em contingência, sempre verifique se a mesma está ativa para o seu estado -2. ative o modo de contingência e grave o json retornado em um cache ou pbase de dados, para habilitar seu uso continuo -3. ao enviar uma NFe (mod 55), sempre verifique esse json no cache ou na base de dados e o recarregue em Contingency::class +1. ao entrar em contingência SVCAN ou SVCRS, sempre verifique se o webservice de contingência está ativo para o seu estado; +2. ative o modo de contingência e grave o json retornado em um cache ou base de dados, para habilitar seu uso continuo; +3. ao enviar uma NFe (mod 55), sempre verifique esse json no cache ou na base de dados, e o recarregue em Contingency::class 4. injete a Contingency::class na classe principal Tools::class ```php @@ -142,7 +145,7 @@ if (!empty($json_contingencia_do_cache)) { $tools = new Tools($configJson, $cert, $cont); $tools->model(55); ``` -5. ou carregue a proriedade publica da classe $tools->contingency +5. ou carregue diretamente a proriedade publica da classe $tools->contingency ```php $cert = Certificate::readPfx(file_get_contents('certificado.pfx'), 'senha'); //recarrega a contingencia que foi enteriormente ativada e gravada em cache @@ -156,6 +159,8 @@ $tools->contingency = $cont; $tools->model(55); ``` +## Habilitando o modo de contingência + ```php use NFePHP\NFe\Factories\Contingency; @@ -170,6 +175,7 @@ $status = $contingency->activate($acronym, $motive, $type); ``` $status irá conter uma string JSON ENCODED, com as informações sobre a condição de contingência. +Como mostrado abaixo: ```json { @@ -179,8 +185,12 @@ $status irá conter uma string JSON ENCODED, com as informações sobre a condi "tpEmis":6 } ``` -Essa string deverá ser arquivada, em disco ou em base de dados para uso posterior, até que o modo de contingencia seja desabilitado. -Ou seja, a cada vez que carregar a classe Tools deverá ser passada a classe contingency, ou será considerado que o ambiente é normal. Exemplo: + +Essa string deverá ser mantida, em disco, cache ou em base de dados para uso posterior, até que o modo de contingencia seja desabilitado. +Ou seja, a cada vez que carregar a classe Tools deverá ser passada a classe Contingency, ou será considerado que o ambiente está normal. + +Exemplo: + ```php $status_contingencia = '{ "motive":"SEFAZ fora do AR", @@ -194,12 +204,13 @@ $tools->contingency = $contingency; ``` **Desabilitando o modo de contingência** -```php -use NFePHP\NFe\Factories\Contingency; +Você pode simplesmente apagar o registro anterior da string json da contigência ou desativa-la como indicado abaixo, e gravar onde estava registrada a anterior. + +```php //onde $status é a string json obtida quando entrou em modo de contingência. $contingency = new Contingency($status); -$status = $contingency->deactivate(); +$status = $contingency->deactivate(); ///grave o retorno no cache ou na base de dados ``` $status irá conter dados padrões em condições normais. @@ -219,7 +230,7 @@ Essa string deverá ser arquivada, em disco ou em base de dados para uso posteri public $type; @var string -> Tipo da contingência SVCAN, SVCRS +> Tipo da contingência apenas SVCAN, SVCRS public $motive; @@ -241,7 +252,7 @@ public $tpEmis; > Codigo numerico que representa os tipos de contingência acima indicados. Esse codigo fará parte na montagem as NFe no campo <tpEmis>. -## Methods +## Métodos Construtor, caso seja passado o parametro, uma string JSON, a condição de contingência contida nessa string será registrada na classe. Caso nada seja passado a classe irá considerar condição de emissão normal. From b04784cf4d8e38577e2d1452e67da66d3bf1f015 Mon Sep 17 00:00:00 2001 From: robmachado Date: Wed, 12 Jun 2024 09:24:57 -0300 Subject: [PATCH 06/14] =?UTF-8?q?Inclus=C3=A3o=20das=20URLS=20do=20servi?= =?UTF-8?q?=C3=A7o=20EPEC=20NFCe=20em=20SP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- storage/wsnfe_4.00_mod65.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/storage/wsnfe_4.00_mod65.xml b/storage/wsnfe_4.00_mod65.xml index 9e28c5a1..b92228f6 100755 --- a/storage/wsnfe_4.00_mod65.xml +++ b/storage/wsnfe_4.00_mod65.xml @@ -334,6 +334,8 @@ https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeConsultaProtocolo4.asmx https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeStatusServico4.asmx https://homologacao.nfce.fazenda.sp.gov.br/ws/NFeRecepcaoEvento4.asmx + https://homologacao.nfce.epec.fazenda.sp.gov.br/EPECws/RecepcaoEPEC.asmx + https://homologacao.nfce.epec.fazenda.sp.gov.br/EPECws/EPECStatusServico.asmx https://www.homologacao.nfce.fazenda.sp.gov.br/qrcode @@ -343,6 +345,8 @@ https://nfce.fazenda.sp.gov.br/ws/NFeConsultaProtocolo4.asmx https://nfce.fazenda.sp.gov.br/ws/NFeStatusServico4.asmx https://nfce.fazenda.sp.gov.br/ws/NFeRecepcaoEvento4.asmx + https://nfce.epec.fazenda.sp.gov.br/EPECws/RecepcaoEPEC.asmx + https://nfce.epec.fazenda.sp.gov.br/EPECws/EPECStatusServico.asmx https://www.nfce.fazenda.sp.gov.br/qrcode From cc38069b211a9254fa9a269a8394d2c79f149ecc Mon Sep 17 00:00:00 2001 From: robmachado Date: Wed, 12 Jun 2024 09:31:21 -0300 Subject: [PATCH 07/14] =?UTF-8?q?EPEC=20NFCe=20em=20SP,=20corre=C3=A7?= =?UTF-8?q?=C3=A3o=20da=20Contengeny::class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 8 +- docs/Contingency.md | 2 +- docs/metodos/EPECNFCe_SP.md | 264 ++++++++++++++ .../EventoCancInsucessoNFe_v1.00.xsd | 0 .../PL_009_V4/EventoInsucessoNFe_v1.00.xsd | 0 schemes/PL_009_V4/e110192_v1.00.xsd | 11 +- schemes/PL_009_V4/e110193_v1.00.xsd | 0 .../envEventoCancInsucessoNFe_v1.00.xsd | 0 .../PL_009_V4/envEventoInsucessoNFe_v1.00.xsd | 0 schemes/PL_009_V4/eventoEPEC_v1.00.xsd | 38 +- .../leiauteEventoCancInsucessoNFe_v1.00.xsd | 0 .../leiauteEventoInsucessoNFe_v1.00.xsd | 0 .../procEventoCancInsucessoNFe_v1.00.xsd | 0 .../procEventoInsucessoNFe_v1.00.xsd | 0 .../retEventoCancInsucessoNFe_v1.00.xsd | 0 .../PL_009_V4/retEventoInsucessoNFe_v1.00.xsd | 0 schemes/PL_009_V4/tiposBasico_v1.03.xsd | 17 +- src/Common/Standardize.php | 4 +- src/Common/Tools.php | 41 +-- src/Complements.php | 2 +- src/Factories/Contingency.php | 1 - src/Factories/ContingencyNFe.php | 38 +- src/Tools.php | 3 + src/Traits/TraitEPECNfce.php | 200 +++++++++++ tests/Factories/ContingencyNFeTest.php | 45 +++ tests/Factories/ContingencyTest.php | 45 +++ tests/ToolsTest.php | 2 +- tests/fixtures/txt/nfe_4.0.json | 0 .../xml/exemplo_request_consulta_chave.xml | 0 .../xml/exemplo_request_consulta_recibo.xml | 0 .../exemplo_retorno_sucesso_envia_lote.xml | 0 .../xml/exemplo_xml_cadastro_cnpj.xml | 0 .../fixtures/xml/exemplo_xml_cadastro_cpf.xml | 0 .../fixtures/xml/exemplo_xml_cadastro_ie.xml | 0 tests/fixtures/xml/exemplo_xml_dist_dfe.xml | 0 .../xml/exemplo_xml_envia_lote_modelo_55.xml | 0 .../xml/exemplo_xml_envia_lote_modelo_65.xml | 0 tests/fixtures/xml/exemplo_xml_inutiliza.xml | 0 .../xml/exemplo_xml_request_cce_cnpj.xml | 0 ...emplo_xml_request_sefazAtorInteressado.xml | 0 ...ml_request_sefazCancelaPorSubstituicao.xml | 0 .../xml/exemplo_xml_request_sefazECPP.xml | 0 .../xml/exemplo_xml_request_sefazEPP.xml | 0 .../exemplo_xml_request_sefazManifesta.xml | 0 .../fixtures/xml/exemplo_xml_sefazCancela.xml | 0 tests/fixtures/xml/exemplo_xml_status.xml | 0 tests/fixtures/xml/nfce.xml | 325 ++++++++++++++++++ ...fe_layout4_contingencia_sem_assinatura.xml | 1 + tests/fixtures/xml/retEnviNFe.xml | 0 tests/fixtures/xml/retEnviNFe2.xml | 0 50 files changed, 946 insertions(+), 101 deletions(-) create mode 100644 docs/metodos/EPECNFCe_SP.md mode change 100644 => 100755 schemes/PL_009_V4/EventoCancInsucessoNFe_v1.00.xsd mode change 100644 => 100755 schemes/PL_009_V4/EventoInsucessoNFe_v1.00.xsd mode change 100644 => 100755 schemes/PL_009_V4/e110192_v1.00.xsd mode change 100644 => 100755 schemes/PL_009_V4/e110193_v1.00.xsd mode change 100644 => 100755 schemes/PL_009_V4/envEventoCancInsucessoNFe_v1.00.xsd mode change 100644 => 100755 schemes/PL_009_V4/envEventoInsucessoNFe_v1.00.xsd mode change 100644 => 100755 schemes/PL_009_V4/leiauteEventoCancInsucessoNFe_v1.00.xsd mode change 100644 => 100755 schemes/PL_009_V4/leiauteEventoInsucessoNFe_v1.00.xsd mode change 100644 => 100755 schemes/PL_009_V4/procEventoCancInsucessoNFe_v1.00.xsd mode change 100644 => 100755 schemes/PL_009_V4/procEventoInsucessoNFe_v1.00.xsd mode change 100644 => 100755 schemes/PL_009_V4/retEventoCancInsucessoNFe_v1.00.xsd mode change 100644 => 100755 schemes/PL_009_V4/retEventoInsucessoNFe_v1.00.xsd create mode 100644 src/Traits/TraitEPECNfce.php create mode 100644 tests/Factories/ContingencyNFeTest.php mode change 100644 => 100755 tests/fixtures/txt/nfe_4.0.json mode change 100644 => 100755 tests/fixtures/xml/exemplo_request_consulta_chave.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_request_consulta_recibo.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_retorno_sucesso_envia_lote.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_cadastro_cnpj.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_cadastro_cpf.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_cadastro_ie.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_dist_dfe.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_envia_lote_modelo_55.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_envia_lote_modelo_65.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_inutiliza.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_request_cce_cnpj.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_request_sefazAtorInteressado.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_request_sefazCancelaPorSubstituicao.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_request_sefazECPP.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_request_sefazEPP.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_request_sefazManifesta.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_sefazCancela.xml mode change 100644 => 100755 tests/fixtures/xml/exemplo_xml_status.xml create mode 100755 tests/fixtures/xml/nfce.xml create mode 100644 tests/fixtures/xml/nfe_layout4_contingencia_sem_assinatura.xml mode change 100644 => 100755 tests/fixtures/xml/retEnviNFe.xml mode change 100644 => 100755 tests/fixtures/xml/retEnviNFe2.xml diff --git a/composer.json b/composer.json index 207f4051..71661bcc 100755 --- a/composer.json +++ b/composer.json @@ -70,13 +70,13 @@ ], "test": "vendor/bin/phpunit -c phpunit.xml.dist", "test-with-coverage": "vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover=coverage.xml", - "phpcbf": "vendor/bin/phpcbf src/ tests/", - "phpcs": "vendor/bin/phpcs src/ tests/", - "stan": "vendor/bin/phpstan analyse src/ tests/" + "phpcbf": "vendor/bin/phpcbf src/", + "phpcs": "vendor/bin/phpcs src/", + "stan": "vendor/bin/phpstan analyse src/" }, "extra": { "branch-alias": { - "v5.0": "5.0-dev" + "v5.1": "5.1-dev" } }, "minimum-stability": "stable" diff --git a/docs/Contingency.md b/docs/Contingency.md index 9f4601af..c44e6038 100755 --- a/docs/Contingency.md +++ b/docs/Contingency.md @@ -225,7 +225,7 @@ $status irá conter dados padrões em condições normais. Essa string deverá ser arquivada, em disco ou em base de dados para uso posterior, ou apenas ignorada, e o arquivo ou registro da base de dados removida. -## Properties +## Propriedades public $type; diff --git a/docs/metodos/EPECNFCe_SP.md b/docs/metodos/EPECNFCe_SP.md new file mode 100644 index 00000000..b2269f15 --- /dev/null +++ b/docs/metodos/EPECNFCe_SP.md @@ -0,0 +1,264 @@ +# CONTINGENCIA EPEC Evento Prévio de Emissão em Contingência +# NFCe exclusivo para SP - Leia com muita atenção + +## Considerações Importantes + +- No ambiente de homologação a operação com EPEC para NFCe na SEFAZ-SP, está sempre em operação. +- No ambiente de produção o serviço de EPEC para NFCe somente estará ativo caso a SEFAZ-SP o ative. Como consequência é necessário que seja consultado o status do serviço EPEC antes do envio do evento. +- A contingência EPEC exige o processo de vinculação do Evento a NFCe, se essa vinculação não for realizada dentro do prazo de 24 horas, o emitente ficará bloqueado para emissão de novas EPEC. +- Em caso de ERRO na NFCe, a mesma deverá ser corrigida para poder ser autorizada, e alguns dados da NFCe não poderão ser modificados de forma alguma, como: + - chave da NFCe + - dhEmis (data de emissão da NFCe) + - cNF (codigo de controle da NFCe de 8 digitos, que compõe a chave) + - vNF (valor da NFCe) + - VICMS (valor do ICMS) + - todos os dados do destinatário (se existirem, não pode mudar uma virgula sequer) + +Nesses casos em que a NFCe é rejeitada, somente os motivos dessa rejeição poderão ser alterados e a rejeição corrigida, mas a NFCe ainda pode estar incorreta apesar de ter sido autorizada, neste caso a mesma deverá ser cancelada ou substituída por outra NFCe com os dados corretos no ambiente normal apenas. + +**Por exemplo:** + +Uma NFCe foi criada em contingência EPEC e o evento foi transmitido com sucesso. + +Uma hora depois a SEFAZ-SP retornou o serviço normal e desabilitou o serviço de EPEC, e o seu sistema fez o envio da NFCe que foi autorizada em contignencia EPEC, para ser validada e autorizada pelo sistema normal e **vincular o EPEC à NFCe, finalizando o processo**. + +Mas se a NFCe foi rejeitada devido ao **CFOP utilizado estar incorreto para esse tipo documento**, mas ocorre que por erro do operador a NFCe também foi gerada para um destinatário incorreto. + +Nesse caso devemos apenas corrigir o **CFOP incorreto** e todos os outros dados da NFCe deverão permanecer exatamente os mesmos, a NFCe deverá ser novamente assinda e enviada pelo ambiente de autorização (normal) para ser **vinculada ao EPEC previamente emitido**. + +Caso se autorizada, o evento também foi vinculado, então podemos proceder o **cancelamento (se ainda estiver no prazo, 30 min da hora de emissão)** ou a **substituição por outra NFCe (que pode ser feita em até 7 dias)** + +**Outro exemplo com o vNF incorreto** + +Uma NFCe foi criada em contingência EPEC e o evento foi transmitido com sucesso. + +Ao olhar o documento fiscal impresso foi verificado que o valor da NFCe está incorreto, e se for transmitido dessa forma será rejeitado pois o somatório dos itens diverge do total da NFCe. + +Para corrigir a NFCe tem que ser editada, alterando os itens, para que o valor dos itens resulte no valor total declarado no EPEC. + +*DADOS VERDADEIROS, que deveriam constar da NFCe* + +|item|Quantidade|Denominação|Valor Unitário|Valor Total| +|:---:|:---:|:---|---:|---:| +|item 1|1|5 kg Arroz Agulhinha Camil|R$ 34,49|R$ 34,49| +|item 2|2|1 kg feijáo Carioca Camil|R$ 8.99|R$ 17,98| +|item 2|10|1 kg refinado União valor|R$ 5,59|R$ 55,90| + +**Total Real vNF = 108,37** + +**Total declarado no EPEC = R$ 99,36** + +Então temos que alterar esses itens de forma que o total calculado pela SEFAZ seja exatamente esse de declarado na EPEC. + +*DADOS NA NFCe, ajustados para autorizar e vincular o EPEC* + +|item| Quantidade |Denominação|Valor Unitário| Valor Total | Ajuste | +|:---:|:----------:|:---|---:|------------:|:-----------------------------------------------------------------:| +|item 1| 1 |5 kg Arroz Agulhinha Camil|R$ 34,49| R$ 34,49 | -- | +|item 2| 1 |1 kg feijáo Carioca Camil|R$ 8.99| R$ 8,97 | reduzida a quantidade de 2 para 1 e reduzido o valor para R$ 8,97 | +|item 2| 10 |1 kg refinado União valor|R$ 5,59| R$ 55,90 | -- | + +**Total vNF para validar com o EPEC = 99,36** + +Agora o xml da NFCe pode ser gerado e assinado novemente com apenas estas alterações (lembrando que existem outras tags que não podem ser alteradas de forma alguma). + +Esse xml ajustado pode ser então enviado para autorização na SEFAZ. encerrando a pendência de vinculo com o EPEC. E uma vez que a mesma foi autorizada pode ser imediatamente **cancelada** ou **substituida** pela NFCe emitida corretamente com outro numero. + +### OS EPEC sempre tem que ser encerrados com uma NFCe válida e com os dados fornecidos na EPEC, portanto: +>## Todos os EPEC devem ser obrigatoriamente vinculados a uma NFCe autorizada. +# NUNCA ERRE NAS NFCe EMITIDAS COM EPEC !!! + + +## Consulta do Status do serviço EPEC + +```php +try { + $config = [ + "atualizacao" => "2024-06-08 09:29:21", + "tpAmb" => 2, + "razaosocial" => "FULANO DE TAL LTDA", + "fantasia" => "FULANO LTDA", + "siglaUF" => "SP", + "cnpj" => "12345678901234", + "ie" => "1234567890", + "schemes" => "PL_009_V4", + "versao" => "4.00", + "tokenIBPT" => "", + "CSC" => "33fe411e-ab44-2331-c320-c43ac568afe52", + "CSCid" => "1", + "aProxyConf" => [ + "proxyIp" => "", + "proxyPort" => "", + "proxyUser" => "", + "proxyPass" => "" + ] + ]; + $configJson = json_encode($config); + $config = json_decode($configJson); + + $cert = Certificate::readPfx(file_get_contents('certificado.pfx'), 'senha'); + + $tools = new Tools($configJson, $cert); + $tools->model(65); //OBRIGATÓRIO + + $resp = $tools->sefazStatusEpecNfce(); //caso o cStat = 107 então o serviço está disponivel, qualquer outro resultado não ! + + header('Content-Type: application/xml'); + echo $resp; + +} catch(\Exception $e) { + echo $e->getMessage(); +} +``` + +## Criação da NFCe em contingência EPEC + +Após a consulta do status do serviço EPEC em SP, e se o mesmo estiver ativo, então: + +- é o mesmo processo de criação de qualquer outra NFCe, exceto que tem que informar dados da contingência EPEC. +- criar a NFCe, a mesma já deverá ser registrada como em **contingência EPEC (tpEmis = 4)**, com **dhCont** e **xJust** também. +- assinar a NFCe com $tools->sigNFe($xml), e **gravar a NFCe criada**. (IMPORTANTISSIMO) + +## Envio do Evento EPEC para NFCe em SP + +Com a NFCe em contigência EPEC assinada, a mesma pode ser passada ao processo que fará o envio do evento EPEC dessa NFCe. + +```php +try { + $config = [ + "atualizacao" => "2024-06-08 09:29:21", + "tpAmb" => 2, + "razaosocial" => "FULANO DE TAL LTDA", + "fantasia" => "FULANO LTDA", + "siglaUF" => "SP", + "cnpj" => "12345678901234", + "ie" => "1234567890", + "schemes" => "PL_009_V4", + "versao" => "4.00", + "tokenIBPT" => "", + "CSC" => "33fe411e-ab44-2331-c320-c43ac568afe52", + "CSCid" => "1", + "aProxyConf" => [ + "proxyIp" => "", + "proxyPort" => "", + "proxyUser" => "", + "proxyPass" => "" + ] + ]; + $configJson = json_encode($config); + + $cert = Certificate::readPfx(file_get_contents('certificado.pfx'), 'senha'); + + $tools = new Tools($configJson, $cert); + $tools->model(65); //OBRIGATÓRIO + + $xml = 'nfce_criada_em_contingência_epec_assinada_e_gravada_para_uso_posterior'; //obrigatório + $veraplic = 'versão_do_aplicativo'; //opcional, caso não exista será usado o da NFCe + + $resp = $tools->sefazEpecNfce($xml, $veraplic); + + file_put_contents('evento_eped_nfce.xml', $tools->lastRequest); //o evento enviado deve ser gravado sempre + file_put_contents('resposta_eped_nfce.xml', $tools->lastResponse); //a resposta deve ser gravada sempre + + //a resposta deve ser verificada para checar o cStat da mesma, para saber se o evento foi ou não autorizado + $st = new Standardize(); + $std = $st->toStd($resp); + //como o envio de eventos é sincrono não é esperado codigo diferente de 128, se ocorrer foi algum erro + if ($std->cStat == 128) { + //o lote foi processado, nesse caso podemos verificar o resultado do processamento + if ($std->retEvento->infEvento->cStat == 136) { + //como o resultado do processamento do evento foi 136 Evento registrado, mas não vinculado a NF-e + //temos o evento EPEC autorizado + //devemos também protocolar o evento com sua respectiva autorização + $evento = file_get_contents(__DIR__."/envio_epec_nfce_{$numero}.xml"); + $resposta = file_get_contents(__DIR__."/resposta_epec_nfce_{$numero}.xml"); + $evento_autorizado = Complements::toAuthorize($evento, $resposta); + file_put_contents(__DIR__."/evento_epec_nfce_autorizado.xml", $evento_autorizado); //gravar + //nesse caso podemos imprimir o DANFCE com os dados do EPEC + //$danfce = new Danfce(file_get_contents($file); + //$danfce->epec(dados epec); + //$pdf = $danfce->render($logo); + } else { + $ret = $std->retEvento->infEvento; + //não é 136 então algum erro ocorreu na montagem do evento + //terá de ser analizado o motivo e feita a correção apropriada + throw new \Exception("Algum erro ocorreu cStat {$ret->cStat} {$ret->xMotivo}"); + } + } else { + throw new \Exception("Algum erro ocorreu cStat {$std->cStat} {$std->xMotivo}"); + } +} catch (\Exception $e) { + echo $e->getMessage(); +} +``` + +## Envio da NFCe criada em contingência EPEC + +Uma vez que a SEFAZ-SP NFCe voltou a operar, podemos enviar as NFCe emitidas por evento EPEC: + +```php +try { + $config = [ + "atualizacao" => "2024-06-08 09:29:21", + "tpAmb" => 2, + "razaosocial" => "FULANO DE TAL LTDA", + "fantasia" => "FULANO LTDA", + "siglaUF" => "SP", + "cnpj" => "12345678901234", + "ie" => "1234567890", + "schemes" => "PL_009_V4", + "versao" => "4.00", + "tokenIBPT" => "", + "CSC" => "33fe411e-ab44-2331-c320-c43ac568afe52", + "CSCid" => "1", + "aProxyConf" => [ + "proxyIp" => "", + "proxyPort" => "", + "proxyUser" => "", + "proxyPass" => "" + ] + ]; + $configJson = json_encode($config); + + $cert = Certificate::readPfx(file_get_contents('certificado.pfx'), 'senha'); + + $tools = new Tools($configJson, $cert); + $tools->model(65); //OBRIGATÓRIO + + $xml = 'nfce_criada_em_contingência_epec_assinada_e_gravada_para_uso_posterior'; //obrigatório + $lote = 123456; + $envio_sincrono = 1; + $resp = $tools->sefazEnviaLote([$xml], $lote, $envio_sincrono); + + $st = new Standardize(); + $std = $st->toStd($resp); + if ($std->cStat == 128) { + if (in_array($std->protNFe->infProt->cStat, [100, 110, 150, 205, 301, 302, 303])) + try { + //em todos esses casos a NFCe foi autorizada ou denegada + //então a nfce deve ser protocolada e já está vinculada ao EPEC + $prot = Complements::toAuthorize($xml, $resp); + file_put_contents('nfce_protocolo_de_autorizacao.xml', $resp); //deve ser gravado + file_put_contents('nfce_criada_em_contingência_epec_assinada_e_protocolada.xml', $prot); //obrigatório, manter por 5 anos + } catch (\Exception $e) { + //nesse ponto as falhas geralmente ocorrem devvido erros da propria SEFAZ + //como retornar dados de autorização de OUTRO documento e não o seu + //se isto ocorrer deverá ser feita a cunsulta pela chave do NFCe e se a mesma não estiver + //na base de dados da SEFAZ, deverá ser enviada novamente + throw new \Exception('FALHA AO PROTOCOLAR NFCE ' . $e->getMessage()); + } + } else { + $infProt = $std->protNFe->infProt; + throw new \Exception("Algum erro ocorreu cStat {$infProt->cStat} {$infProt->xMotivo}"); + //revisar o erro e enviar novamente até obter sucesso e a NFCe poder ser protocolada, você tem 24 horas para fazer isso !!! + } + } else { + throw new \Exception("Algum erro ocorreu cStat {$std->cStat} {$std->xMotivo}"); + } +} catch (\Exception $e) { + //as falhas devem ser tratadas, você tem 24 horas para fazer isso !!! + //nesse ponto os erros normalmente são referentes ao timeout estabelecido pela aplicação + //ou por falhas de acesso ao webservice como os SOAPExceptions + echo $e->getMessage(); +} +``` diff --git a/schemes/PL_009_V4/EventoCancInsucessoNFe_v1.00.xsd b/schemes/PL_009_V4/EventoCancInsucessoNFe_v1.00.xsd old mode 100644 new mode 100755 diff --git a/schemes/PL_009_V4/EventoInsucessoNFe_v1.00.xsd b/schemes/PL_009_V4/EventoInsucessoNFe_v1.00.xsd old mode 100644 new mode 100755 diff --git a/schemes/PL_009_V4/e110192_v1.00.xsd b/schemes/PL_009_V4/e110192_v1.00.xsd old mode 100644 new mode 100755 index e422f60a..946d7eff --- a/schemes/PL_009_V4/e110192_v1.00.xsd +++ b/schemes/PL_009_V4/e110192_v1.00.xsd @@ -40,9 +40,9 @@ - Motivo do insucesso - 1 – Recebedor não encontrado - 2 – Recusa do recebedor - 3 – Endereço inexistente + Motivo do insucesso - 1 – Recebedor não encontrado + 2 – Recusa do recebedor + 3 – Endereço inexistente 4 – Outros (exige informar justificativa) @@ -77,8 +77,7 @@ - Hash (SHA1) no formato Base64 resultante da concatenação: Chave de acesso da NFe + Base64 da imagem capturada da entrega (Exemplo: imagem capturada da assinatura eletrônica, digital do recebedor, foto, etc) - O hashCSRT é o resultado das funções SHA-1 e base64 do token CSRT fornecido pelo fisco + chave de acesso do DF-e. (Implementação em futura NT) + Hash (SHA1) no formato Base64 resultante da concatenação: Chave de acesso da NFe + Base64 da imagem capturada da entrega (Exemplo: imagem capturada da assinatura eletrônica, digital do recebedor, foto, etc) Observação: 28 caracteres são representados no schema como 20 bytes do tipo base64Binary @@ -89,7 +88,7 @@ Observação: 28 caracteres são representados no schema como 20 bytes do tipo b - Data e hora da geração do hash da tentativa de entrega. Formato AAAA-MMDDThh:mm:ssTZD. + Data e hora da geração do hash da tentativa de entrega. Formato AAAA-MMDDThh:mm:ssTZD. diff --git a/schemes/PL_009_V4/e110193_v1.00.xsd b/schemes/PL_009_V4/e110193_v1.00.xsd old mode 100644 new mode 100755 diff --git a/schemes/PL_009_V4/envEventoCancInsucessoNFe_v1.00.xsd b/schemes/PL_009_V4/envEventoCancInsucessoNFe_v1.00.xsd old mode 100644 new mode 100755 diff --git a/schemes/PL_009_V4/envEventoInsucessoNFe_v1.00.xsd b/schemes/PL_009_V4/envEventoInsucessoNFe_v1.00.xsd old mode 100644 new mode 100755 diff --git a/schemes/PL_009_V4/eventoEPEC_v1.00.xsd b/schemes/PL_009_V4/eventoEPEC_v1.00.xsd index 0d0a987f..aa65160b 100755 --- a/schemes/PL_009_V4/eventoEPEC_v1.00.xsd +++ b/schemes/PL_009_V4/eventoEPEC_v1.00.xsd @@ -227,41 +227,5 @@ - - - - Tipo Código de orgão (UF da tabela do IBGE + 91 RFB) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/schemes/PL_009_V4/leiauteEventoCancInsucessoNFe_v1.00.xsd b/schemes/PL_009_V4/leiauteEventoCancInsucessoNFe_v1.00.xsd old mode 100644 new mode 100755 diff --git a/schemes/PL_009_V4/leiauteEventoInsucessoNFe_v1.00.xsd b/schemes/PL_009_V4/leiauteEventoInsucessoNFe_v1.00.xsd old mode 100644 new mode 100755 diff --git a/schemes/PL_009_V4/procEventoCancInsucessoNFe_v1.00.xsd b/schemes/PL_009_V4/procEventoCancInsucessoNFe_v1.00.xsd old mode 100644 new mode 100755 diff --git a/schemes/PL_009_V4/procEventoInsucessoNFe_v1.00.xsd b/schemes/PL_009_V4/procEventoInsucessoNFe_v1.00.xsd old mode 100644 new mode 100755 diff --git a/schemes/PL_009_V4/retEventoCancInsucessoNFe_v1.00.xsd b/schemes/PL_009_V4/retEventoCancInsucessoNFe_v1.00.xsd old mode 100644 new mode 100755 diff --git a/schemes/PL_009_V4/retEventoInsucessoNFe_v1.00.xsd b/schemes/PL_009_V4/retEventoInsucessoNFe_v1.00.xsd old mode 100644 new mode 100755 diff --git a/schemes/PL_009_V4/tiposBasico_v1.03.xsd b/schemes/PL_009_V4/tiposBasico_v1.03.xsd index b65a4d27..a323acee 100755 --- a/schemes/PL_009_V4/tiposBasico_v1.03.xsd +++ b/schemes/PL_009_V4/tiposBasico_v1.03.xsd @@ -336,27 +336,27 @@ - Tipo Código do Pais + Tipo Código do Pais // PL_005d - 11/08/09 eliminado: - 4235-LEBUAN, ILHAS - + 4235-LEBUAN, ILHAS - acrescentado: 7200 SAO TOME E PRINCIPE, ILHAS, -8958 ZONA DO CANAL DO PANAMA -9903 PROVISAO DE NAVIOS E AERONAVES -9946 A DESIGNAR -9950 BANCOS CENTRAIS +8958 ZONA DO CANAL DO PANAMA +9903 PROVISAO DE NAVIOS E AERONAVES +9946 A DESIGNAR +9950 BANCOS CENTRAIS 9970 ORGANIZACOES INTERNACIONAIS // PL_005b - 24/10/08 // Acrescentado: 4235 - LEBUAN,ILHAS - 4885 - MAYOTTE (ILHAS FRANCESAS) + 4885 - MAYOTTE (ILHAS FRANCESAS) // NT2011/004 acrescentado a tabela de paises //PL_006t - 21/03/2014 acrescentado: 5780 - Palestina -7600 - Sudão do Sul +7600 - Sudão do Sul @@ -850,7 +850,6 @@ acrescentado: - diff --git a/src/Common/Standardize.php b/src/Common/Standardize.php index e415d6e5..be43c01e 100755 --- a/src/Common/Standardize.php +++ b/src/Common/Standardize.php @@ -82,8 +82,10 @@ public function whichIs(?string $xml = null): string $this->xml = $xml; } if (!Validator::isXML($this->xml)) { + $erro = Validator::$erro; + throw new DocumentsException($erro); //invalid document is not a XML - throw DocumentsException::wrongDocument(6); + //throw DocumentsException::wrongDocument(6); } $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->preserveWhiteSpace = false; diff --git a/src/Common/Tools.php b/src/Common/Tools.php index e85ac8f6..b33b758a 100755 --- a/src/Common/Tools.php +++ b/src/Common/Tools.php @@ -395,35 +395,19 @@ protected function isValid(string $version, string $body, string $method): bool */ protected function checkContingencyForWebServices(string $service) { - $permit = [ - 55 => ['SVCAN', 'SVCRS', 'EPEC', 'FSDA'], - 65 => ['FSDA', 'EPEC', 'OFFLINE'] - ]; - - $type = $this->contingency->type; + $type = $this->contingency->type ?? null; $mod = $this->modelo; if (!empty($type)) { - if (array_search($type, $permit[$mod]) === false) { + if ($this->modelo == 65) { throw new RuntimeException( - "Esse modo de contingência [$type] não é aceito " - . "para o modelo [$mod]" + "Não existe serviço para contingência SVCRS ou SVCAN para NFCe (modelo 65)." + ); + } + if ($type !== 'SVCRS' && $type !== 'SVCAN') { + throw new RuntimeException( + "Esse modo de contingência [$type] não possue webservice próprio, portanto não haverão envios." ); } - } - - //se a contingencia é OFFLINE ou FSDA nenhum servidor está disponivel - //se a contigencia EPEC está ativa apenas o envio de Lote está ativo, - //então gerar um RunTimeException - if ( - $type == 'FSDA' - || $type == 'OFFLINE' - || ($type == 'EPEC' && $service != 'RecepcaoEvento') - ) { - throw new RuntimeException( - "Quando operando em modo de contingência [" - . $this->contingency->type - . "], este serviço [$service] não está disponível." - ); } } @@ -460,13 +444,13 @@ protected function servico(string $service, string $uf, $tpAmb, bool $ignoreCont $sigla = $uf; if (!$ignoreContingency) { $contType = $this->contingency->type; - if (!empty($contType) && ($contType == 'SVCRS' || $contType == 'SVCAN')) { + if (!empty($contType) && ($contType === 'SVCRS' || $contType === 'SVCAN')) { $sigla = $contType; } } $stdServ = $webs->get($sigla, $tpAmb, $this->modelo); if (empty($stdServ->$service->url)) { - if ($sigla == 'SVCRS' || $sigla == 'SVCAN') { + if ($sigla === 'SVCRS' || $sigla === 'SVCAN') { throw new \RuntimeException("Servico [$service] indisponivel na Contingencia [$sigla]"); } else { throw new \RuntimeException("Servico [$service] indisponivel UF [$uf] ou modelo [$this->modelo]"); @@ -492,9 +476,6 @@ protected function servico(string $service, string $uf, $tpAmb, bool $ignoreCont */ protected function sendRequest(string $request, array $parameters = []): string { - if (in_array($this->contingency->tpEmis, [Contingency::TPEMIS_FSDA, Contingency::TPEMIS_OFFLINE])) { - throw new \RuntimeException('Em contingencia FSDA ou OFFLINE não é possivel acessar os webservices.'); - } $this->checkSoap(); $response = (string) $this->soap->send( $this->urlService, @@ -510,7 +491,7 @@ protected function sendRequest(string $request, array $parameters = []): string } /** - * Recover path to xml data base with list of soap services + * Recover path to xml database with list of soap services */ protected function getXmlUrlPath(): string { diff --git a/src/Complements.php b/src/Complements.php index c564e8fd..3e5555cc 100755 --- a/src/Complements.php +++ b/src/Complements.php @@ -26,7 +26,7 @@ public static function toAuthorize(string $request, string $response): string } $st = new Standardize(); $key = ucfirst($st->whichIs($request)); - if ($key != 'NFe' && $key != 'EnvEvento' && $key != 'InutNFe') { + if ($key !== 'NFe' && $key !== 'EnvEvento' && $key !== 'InutNFe') { //wrong document, this document is not able to recieve a protocol throw DocumentsException::wrongDocument(0, $key); } diff --git a/src/Factories/Contingency.php b/src/Factories/Contingency.php index 74af382a..eea6e214 100755 --- a/src/Factories/Contingency.php +++ b/src/Factories/Contingency.php @@ -113,7 +113,6 @@ public function activate(string $acronym, string $motive, string $type = ''): st ); } $this->type = $type; - } //gerar o timestamp para Greenwich (GMT). $dt = new \DateTime(gmdate('Y-m-d H:i:s')); //data hora GMT diff --git a/src/Factories/ContingencyNFe.php b/src/Factories/ContingencyNFe.php index 2981a972..87a284e0 100755 --- a/src/Factories/ContingencyNFe.php +++ b/src/Factories/ContingencyNFe.php @@ -17,25 +17,36 @@ class ContingencyNFe */ public static function adjust(string $xml, Contingency $contingency): string { - if ($contingency->type == '') { + if ($contingency->type === '') { return $xml; } $xml = Signer::removeSignature($xml); - $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->preserveWhiteSpace = false; $dom->formatOutput = false; $dom->loadXML($xml); - $ide = $dom->getElementsByTagName('ide')->item(0); $cUF = $ide->getElementsByTagName('cUF')->item(0)->nodeValue; $cNF = $ide->getElementsByTagName('cNF')->item(0)->nodeValue; $nNF = $ide->getElementsByTagName('nNF')->item(0)->nodeValue; $serie = $ide->getElementsByTagName('serie')->item(0)->nodeValue; $mod = $ide->getElementsByTagName('mod')->item(0)->nodeValue; + $tpEmis = $ide->getElementsByTagName('tpEmis')->item(0)->nodeValue; + $dhCont = $ide->getElementsByTagName('dhCont')->item(0)->nodeValue ?? null; + $xJust = $ide->getElementsByTagName('xJust')->item(0)->nodeValue ?? null; + if ($mod == 65) { + throw new \RuntimeException( + 'O xml pertence a um documento modelo 65 NFCe, incorreto para contingência SVCAN ou SVCRS.' + ); + } + if ($tpEmis != 1) { + //xml já foi emitido em contingência, não há a necessidade de ajuste dos dados do xml + return $xml; + } $dtEmi = new DateTime($ide->getElementsByTagName('dhEmi')->item(0)->nodeValue); $ano = $dtEmi->format('y'); $mes = $dtEmi->format('m'); + //altera o tpEmis de 1 para o modo SVCRS[7] ou SVCAN[6] $tpEmis = (string) $contingency->tpEmis; $emit = $dom->getElementsByTagName('emit')->item(0); if (!empty($emit->getElementsByTagName('CNPJ')->item(0)->nodeValue)) { @@ -44,21 +55,28 @@ public static function adjust(string $xml, Contingency $contingency): string $doc = $emit->getElementsByTagName('CPF')->item(0)->nodeValue; } $motivo = trim(Strings::replaceUnacceptableCharacters($contingency->motive)); - - $tz = TimeZoneByUF::get(UFList::getUFByCode((int)$cUF)); - $dt = new \DateTime(date("Y-m-d H:i:sP"), new \DateTimeZone($tz)); - - $dt->setTimestamp($contingency->timestamp); + //verifica o timezone no estado emitente + $tztext = TimeZoneByUF::get(UFList::getUFByCode((int)$cUF)); + $tz = new \DateTimeZone($tztext); + //cria um DateTime::class com o timestamp (GMT) + $dt = new \DateTime(gmdate("Y-m-d H:i:s", $contingency->timestamp)); + //seta o timezone no DateTime::class para o estado emissor + $dt->setTimezone($tz); + //gera a data de entrada em contingência no timezone do emitente baseado no do XML + $dthCont = $dt->format('Y-m-d\TH:i:sP'); + //modifica a tag $ide->getElementsByTagName('tpEmis') ->item(0) ->nodeValue = $contingency->tpEmis; + //verifica se existem documentos referenciados no xml $nfref = $ide->getElementsByTagName('NFref')->item(0) ?? null; if (!empty($ide->getElementsByTagName('dhCont')->item(0)->nodeValue)) { + //caso não tenha a tag , inserir na tag $ide->getElementsByTagName('dhCont') ->item(0) - ->nodeValue = $dt->format('Y-m-d\TH:i:sP'); + ->nodeValue = $dthCont; } else { - $dhCont = $dom->createElement('dhCont', $dt->format('Y-m-d\TH:i:sP')); + $dhCont = $dom->createElement('dhCont', $dthCont); if (!empty($nfref)) { $ide->insertBefore($dhCont, $nfref); } else { diff --git a/src/Tools.php b/src/Tools.php index e516bcef..dc3aac15 100755 --- a/src/Tools.php +++ b/src/Tools.php @@ -20,11 +20,14 @@ use NFePHP\Common\Signer; use NFePHP\Common\UFList; use NFePHP\NFe\Common\Tools as ToolsCommon; +use NFePHP\NFe\Traits\TraitEPECNfce; use RuntimeException; use InvalidArgumentException; class Tools extends ToolsCommon { + use TraitEPECNfce; + public const EVT_CONFIRMACAO = 210200; //only one per nfe seq=n public const EVT_CIENCIA = 210210; //only one per nfe seq=1 public const EVT_DESCONHECIMENTO = 210220; //only one per nfe seq=n diff --git a/src/Traits/TraitEPECNfce.php b/src/Traits/TraitEPECNfce.php new file mode 100644 index 00000000..e8517155 --- /dev/null +++ b/src/Traits/TraitEPECNfce.php @@ -0,0 +1,200 @@ +tpAmb; + } + if (empty($uf)) { + $uf = $this->config->siglaUF; + } + if ($this->modelo != 65) { + throw new \InvalidArgumentException( + 'A consulta de status do serviço EPEC existe apenas para NFCe (mod. 65).' + ); + } + if ($uf !== 'SP') { + throw new \InvalidArgumentException( + 'A consulta de status do serviço EPEC NFCe (mod. 65) existe apenas em SP,' + . ' os demais estados não implementaram o serviço EPEC para NFCe.' + ); + } + $servico = 'EPECStatusServico'; + $this->checkContingencyForWebServices($servico); + $this->servico($servico, $uf, $tpAmb, $ignoreContingency); + $request = "urlPortal\" versao=\"$this->urlVersion\">" + . "$tpAmb" + . "$this->urlcUF" + . "STATUS" + . ""; + $this->isValid($this->urlVersion, $request, 'consStatServ'); + $this->lastRequest = $request; + $parameters = ['nfeDadosMsg' => $request]; + $body = "urlNamespace\">$request"; + $this->lastResponse = $this->sendRequest($body, $parameters); + return $this->lastResponse; + } + + /** + * Request authorization for issuance in contingency EPEC for NFCe in SP only + * @param string $xml + * @param string|null $verAplic + * @return string + */ + public function sefazEpecNfce(string &$xml, string $verAplic = null): string + { + $uf = $this->config->siglaUF; + $eventos = [ + self::EVT_EPEC => ['versao' => '1.00', 'nome' => 'envEPEC'], + ]; + $nSeqEvento = 1; + //extrai os dados da NFe + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->preserveWhiteSpace = false; + $dom->formatOutput = false; + $dom->loadXML($xml); + $infNFe = $dom->getElementsByTagName('infNFe')->item(0); + $ide = $dom->getElementsByTagName('ide')->item(0); + $tpEmis = (int) $ide->getElementsByTagName('tpEmis')->item(0)->nodeValue ?? 0; + $dhCont = $ide->getElementsByTagName('dhCont')->item(0)->nodeValue ?? ''; + $xJust = $ide->getElementsByTagName('xJust')->item(0)->nodeValue ?? ''; + if ($tpEmis !== 4 || empty($dhCont) || empty($xJust)) { + throw new \Exception( + "A NFCe deve ser gerada em contingência EPEC para poder ser processada em contingência EPEC" + ); + } + $emit = $dom->getElementsByTagName('emit')->item(0); + $dest = $dom->getElementsByTagName('dest')->item(0); + $cOrgaoAutor = UFList::getCodeByUF($this->config->siglaUF); + $chNFe = substr($infNFe->getAttribute('Id'), 3, 44); + $ufchave = substr($chNFe, 0, 2); + if ($cOrgaoAutor != $ufchave) { + throw new \Exception("O autor [{$cOrgaoAutor}] não é da mesma UF que a NFe [{$ufchave}]"); + } + // EPEC + $verProc = $dom->getElementsByTagName('verProc')->item(0)->nodeValue; + $dhEmi = $dom->getElementsByTagName('dhEmi')->item(0)->nodeValue; + $tpNF = $dom->getElementsByTagName('tpNF')->item(0)->nodeValue; + $emitIE = $emit->getElementsByTagName('IE')->item(0)->nodeValue; + $destUF = $uf; + if (!empty($dest)) { + $destUF = $dest->getElementsByTagName('UF')->item(0)->nodeValue; + } + $total = $dom->getElementsByTagName('total')->item(0); + $vNF = $total->getElementsByTagName('vNF')->item(0)->nodeValue; + $vICMS = $total->getElementsByTagName('vICMS')->item(0)->nodeValue; + $desttag = ''; + if (!empty($dest)) { + $dID = $dest->getElementsByTagName('CNPJ')->item(0)->nodeValue ?? null; + if (!empty($dID)) { + $destID = "$dID"; + } else { + $dID = $dest->getElementsByTagName('CPF')->item(0)->nodeValue ?? null; + if (!empty($dID)) { + $destID = "$dID"; + } else { + $dID = $dest->getElementsByTagName('idEstrangeiro') + ->item(0) + ->nodeValue; + $destID = "$dID"; + } + } + $dIE = $dest->getElementsByTagName('IE')->item(0)->nodeValue ?? null; + $destIE = ''; + if (!empty($dIE)) { + $destIE = "{$dIE}"; + } + $desttag = "" + . "{$destUF}" + . $destID + . $destIE + . ""; + } + if (empty($verAplic)) { + if (!empty($this->verAplic)) { + $verAplic = $this->verAplic; + } else { + $verAplic = $verProc; + } + } + $tagAdic = "$cOrgaoAutor" + . "1" + . "{$verAplic}" + . "{$dhEmi}" + . "{$tpNF}" + . "{$emitIE}" + . $desttag + . "{$vNF}" + . "{$vICMS}"; + $servico = 'RecepcaoEPEC'; + $this->servico($servico, $uf, $this->tpAmb, true); + $descEvento = 'EPEC'; + $cnpj = $this->config->cnpj ?? ''; + $dt = new \DateTime(date("Y-m-d H:i:sP"), new \DateTimeZone($this->timezone)); + $dt->setTimezone(new \DateTimeZone($this->timezone)); + $dhEventoString = $dt->format('Y-m-d\TH:i:sP'); + $sSeqEvento = str_pad((string)$nSeqEvento, 2, "0", STR_PAD_LEFT); + $tpEvento = self::EVT_EPEC; + $verEvento = '1.00'; + $eventId = "ID" . self::EVT_EPEC . $chNFe . $sSeqEvento; + $cOrgao = UFList::getCodeByUF($uf); + $request = "" + . "" + . "$cOrgao" + . "$this->tpAmb"; + if ($this->typePerson === 'J') { + $request .= "$cnpj"; + } else { + $request .= "$cnpj"; + } + $request .= "$chNFe" + . "$dhEventoString" + . "$tpEvento" + . "$nSeqEvento" + . "$verEvento" + //em alguns casos haverá um verAplic nesta posição ??? ver xsd conciliação + . "" + . "$descEvento" + . "$tagAdic" + . "" + . "" + . ""; + $lote = $dt->format('YmdHis') . random_int(0, 9); + $request = "urlPortal\" versao=\"$verEvento\">" + . "$lote" + . $request + . ""; + $evt = $eventos[$tpEvento]; + //assinatura dos dados + $request = Signer::sign( + $this->certificate, + $request, + 'infEvento', + 'Id', + $this->algorithm, + $this->canonical, + 'evento' + ); + $this->isValid($evt['versao'], $request, 'eventoEPEC'); + $this->lastRequest = $request; + $parameters = ['nfeDadosMsg' => $request]; + $body = "urlNamespace\">$request"; + $this->lastResponse = $this->sendRequest($body, $parameters); + return $this->lastResponse; + } +} diff --git a/tests/Factories/ContingencyNFeTest.php b/tests/Factories/ContingencyNFeTest.php new file mode 100644 index 00000000..0354f774 --- /dev/null +++ b/tests/Factories/ContingencyNFeTest.php @@ -0,0 +1,45 @@ +activate('RS', 'Teste de uso da classe em contingência'); + $xml = file_get_contents(__DIR__ . '/../fixtures/xml/nfe_layout4.xml'); + $newxml = ContingencyNFe::adjust($xml, $cont); + } + + public function testAdjustNFeContingencyReady() + { + $cont = new Contingency(); + $json = $cont->activate('RS', 'Teste contingência SVCAN'); + $xml = file_get_contents(__DIR__ . '/../fixtures/xml/nfe_layout4_contingencia_sem_assinatura.xml'); + $newxml = ContingencyNFe::adjust($xml, $cont); + $dom = new \DOMDocument(); + $dom->loadXML($newxml); + //não deve haver alteração no xml, principalmente nesses 3 campos + $tpEmis = (string) $dom->getElementsByTagName('tpEmis')->item(0)->nodeValue; + $dhCont = (string) $dom->getElementsByTagName('dhCont')->item(0)->nodeValue; + $xJust = (string) $dom->getElementsByTagName('xJust')->item(0)->nodeValue; + $this->assertEquals($tpEmis, '6'); + $this->assertEquals($dhCont, '2024-06-11T23:30:41-03:00'); + $this->assertEquals($xJust, 'Teste de uso da classe em contingência'); + } + + public function testAdjustFailNFCe() + { + $this->expectException(\RuntimeException::class); + $cont = new Contingency(); + $json = $cont->activate('RS', 'Teste de uso da classe em contingência'); + $xml = file_get_contents(__DIR__ . '/../fixtures/xml/nfce.xml'); + $newxml = ContingencyNFe::adjust($xml, $cont); + } + + +} diff --git a/tests/Factories/ContingencyTest.php b/tests/Factories/ContingencyTest.php index d9c428ba..961bbc20 100755 --- a/tests/Factories/ContingencyTest.php +++ b/tests/Factories/ContingencyTest.php @@ -23,6 +23,51 @@ public function testActivate() $this->assertEquals($std->tpEmis, 6); } + public function testActivateExceptionFailForcedType() + { + $this->expectException(\RuntimeException::class); + $contingency = new Contingency(); + $result = $contingency->activate('SP', 'Testes Unitarios', 'SVAN'); + } + + public function testActivateExceptionFailIncorrectSmallerMotive() + { + $this->expectException(\RuntimeException::class); + $contingency = new Contingency(); + $result = $contingency->activate('SP', 'Testes'); + } + + public function testActivateExceptionFailIncorrectGreaterMotive() + { + $this->expectException(\RuntimeException::class); + $contingency = new Contingency(); + $motive = "Eu fui emitir uma NFe e a SEFAZ autorizadora estava fora do ar, " + . "entrei em contato com o técnico de informática que me mandou acionar o modo de contingência, " + . "indicando o motivo. Nosso diretor está exigindo a emissão da NFe agora, e sei não sei mais o que fazer." + ." Então fiz essa tentativa agora."; + $result = $contingency->activate('SP', $motive); + } + + public function testActivateForcedTypeSVCAN() + { + $contingency = new Contingency(); + $result = $contingency->activate('AM', 'Testes Unitarios', 'SVCAN'); + $std = json_decode($result); + $this->assertEquals($std->motive, 'Testes Unitarios'); + $this->assertEquals($std->type, 'SVCAN'); + $this->assertEquals($std->tpEmis, 6); + } + + public function testActivateForcedTypeSVCRS() + { + $contingency = new Contingency(); + $result = $contingency->activate('SP', 'Testes Unitarios', 'SVCRS'); + $std = json_decode($result); + $this->assertEquals($std->motive, 'Testes Unitarios'); + $this->assertEquals($std->type, 'SVCRS'); + $this->assertEquals($std->tpEmis, 7); + } + public function testLoad() { $cont = [ diff --git a/tests/ToolsTest.php b/tests/ToolsTest.php index d5cb8cf9..69db43ac 100755 --- a/tests/ToolsTest.php +++ b/tests/ToolsTest.php @@ -449,7 +449,7 @@ protected function getToolsForModelWithSuccessReturn($model = 55): ToolsFake */ protected function getCleanXml($filePath) { - $xml = simplexml_load_file($filePath, 'SimpleXMLElement', LIBXML_NOBLANKS); + $xml = simplexml_load_string(file_get_contents($filePath), 'SimpleXMLElement', LIBXML_NOBLANKS); $customXML = new \SimpleXMLElement($xml->asXML()); $dom = dom_import_simplexml($customXML); return $dom->ownerDocument->saveXML($dom->ownerDocument->documentElement); diff --git a/tests/fixtures/txt/nfe_4.0.json b/tests/fixtures/txt/nfe_4.0.json old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_request_consulta_chave.xml b/tests/fixtures/xml/exemplo_request_consulta_chave.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_request_consulta_recibo.xml b/tests/fixtures/xml/exemplo_request_consulta_recibo.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_retorno_sucesso_envia_lote.xml b/tests/fixtures/xml/exemplo_retorno_sucesso_envia_lote.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_cadastro_cnpj.xml b/tests/fixtures/xml/exemplo_xml_cadastro_cnpj.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_cadastro_cpf.xml b/tests/fixtures/xml/exemplo_xml_cadastro_cpf.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_cadastro_ie.xml b/tests/fixtures/xml/exemplo_xml_cadastro_ie.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_dist_dfe.xml b/tests/fixtures/xml/exemplo_xml_dist_dfe.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_envia_lote_modelo_55.xml b/tests/fixtures/xml/exemplo_xml_envia_lote_modelo_55.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_envia_lote_modelo_65.xml b/tests/fixtures/xml/exemplo_xml_envia_lote_modelo_65.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_inutiliza.xml b/tests/fixtures/xml/exemplo_xml_inutiliza.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_request_cce_cnpj.xml b/tests/fixtures/xml/exemplo_xml_request_cce_cnpj.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_request_sefazAtorInteressado.xml b/tests/fixtures/xml/exemplo_xml_request_sefazAtorInteressado.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_request_sefazCancelaPorSubstituicao.xml b/tests/fixtures/xml/exemplo_xml_request_sefazCancelaPorSubstituicao.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_request_sefazECPP.xml b/tests/fixtures/xml/exemplo_xml_request_sefazECPP.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_request_sefazEPP.xml b/tests/fixtures/xml/exemplo_xml_request_sefazEPP.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_request_sefazManifesta.xml b/tests/fixtures/xml/exemplo_xml_request_sefazManifesta.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_sefazCancela.xml b/tests/fixtures/xml/exemplo_xml_sefazCancela.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/exemplo_xml_status.xml b/tests/fixtures/xml/exemplo_xml_status.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/nfce.xml b/tests/fixtures/xml/nfce.xml new file mode 100755 index 00000000..70cba443 --- /dev/null +++ b/tests/fixtures/xml/nfce.xml @@ -0,0 +1,325 @@ + + + +41 +81782249 +Venda de mercadoria +65 +1 +1305 +2020-03-11T15:32:17-03:00 +1 +1 +4108809 +4 +7 +6 +1 +1 +1 +1 +0 +1.0.0 +2020-03-11T12:32:17-03:00 +Teste de contingência + + +23285089000185 +ANA F. ZCHROTKE MARTIN SORVETERIA +TUTTINUTTI GELADOS COMESTIVEIS + +AV CEL OTAVIO TOSTA +177 +SALA +Centro +4108809 +GUAIRA +PR +85980000 +1058 +Brasil +4499764041 + +9077361720 +1 + + + 10422724000187 + Lumer Informática Serviços Digitais LTDA + Compusoft + + Av. Rio de Janeiro + 1060 + Comercial + Centro + 4101903 + Santa Gertrudes do Assaí de Baixo + PR + 86220000 + 1058 + Brasil + 4332624001 + + 9045932653 + 14058 + 4751201 + 1 + + + +3 +SEM GTIN +NOTA FISCAL EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL +21050010 +2300100 +5405 +UN +1.0000 +12.0000000000 +12.00 +SEM GTIN +UN +1.0000 +12.0000000000 +1 + + +0.00 + + +0 +500 +0.00 +0.0000 +0.00 +0.00 + + + + +49 +0.00 +0.0000 +0.00 + + + + +49 +0.00 +0.0000 +0.00 + + + + + + +3 +SEM GTIN +Gelato Grande +21050010 +2300100 +5405 +UN +1.0000 +12.0000000000 +12.00 +SEM GTIN +UN +1.0000 +12.0000000000 +1 + + +0.00 + + +0 +500 +0.00 +0.0000 +0.00 +0.00 + + + + +49 +0.00 +0.0000 +0.00 + + + + +49 +0.00 +0.0000 +0.00 + + + + + + +8 +SEM GTIN +Agua Mineral 510 ml +22011000 +0300600 +5405 +UN +1.0000 +3.0000000000 +3.00 +SEM GTIN +UN +1.0000 +3.0000000000 +1 + + +0.00 + + +0 +500 +0.00 +0.0000 +0.00 +0.00 + + + + +49 +0.00 +0.0000 +0.00 + + + + +49 +0.00 +0.0000 +0.00 + + + + + + +8 +SEM GTIN +Agua Mineral 510 ml +22011000 +0300600 +5405 +UN +1.0000 +3.0000000000 +3.00 +SEM GTIN +UN +1.0000 +3.0000000000 +1 + + +0.00 + + +0 +500 +0.00 +0.0000 +0.00 +0.00 + + + + +49 +0.00 +0.0000 +0.00 + + + + +49 +0.00 +0.0000 +0.00 + + + + + + +0.00 +0.00 +0.00 +0.00 +0.00 +0.00 +0.00 +0.00 +30.00 +0.00 +0.00 +0.00 +0.00 +0.00 +0.00 +0.00 +0.00 +0.00 +30.00 + + + +9 + + + +0 +04 +30.00 + + + + +25447784000121 +MARKE SISTEMAS LTDA +contato@markesistemas.com.br +4436426822 + + + +http://www.fazenda.pr.gov.br/nfce/qrcode?p=41200323285089000185650010000013051817822496|2|2|1|9D6AB4765658166993902F7F7C26FCD0965E328F +http://www.fazenda.pr.gov.br/nfce/consulta + + + + + + + + + + + +OZImXzkhvK2D0ABoXkChyiO2KxQ= + + +ULhj6YOKvCCpVdRVIId/C1AxCXONExMKL8+cGCCtC2ttGOYScSQUD9t5XYyjTS5i2Vc8S9rrXp7YP09z1oB7rypEpRMpuzlEC5S8xEnfOYdDqnPKj2/t0ft9Ii7q22M+qO7ao0HDkWGBzfHaKuezVkK63nznDQAzh8oC2OmxBuGUVP8ssZENpupG2B58sHzBLrhGJbYe7s39UFO0SrEHcjKx/vAMQ5SsVtJhyWyz2P2nFeLWK/NvFpJSB7b5oc1+t2MMIBTlnYNez4TQL9h2qUlNMLqmBbxPxR16yR399jvX0js31HST3qel2z5GuHwabN6YmljcD709xoAIPhIQ3g== + + +MIIHpzCCBY+gAwIBAgIISvRX/DfGzc8wDQYJKoZIhvcNAQELBQAwdjELMAkGA1UEBhMCQlIxEzARBgNVBAoTCklDUC1CcmFzaWwxNjA0BgNVBAsTLVNlY3JldGFyaWEgZGEgUmVjZWl0YSBGZWRlcmFsIGRvIEJyYXNpbCAtIFJGQjEaMBgGA1UEAxMRQUMgU0FGRVdFQiBSRkIgdjUwHhcNMTkwNDI1MTk0NDQ0WhcNMjAwNDI1MTk0NDQ0WjCB4zELMAkGA1UEBhMCQlIxEzARBgNVBAoTCklDUC1CcmFzaWwxCzAJBgNVBAgTAlBSMQ8wDQYDVQQHEwZHVUE/UkExNjA0BgNVBAsTLVNlY3JldGFyaWEgZGEgUmVjZWl0YSBGZWRlcmFsIGRvIEJyYXNpbCAtIFJGQjEWMBQGA1UECxMNUkZCIGUtQ05QSiBBMTEXMBUGA1UECxMOMjU0NDc3ODQwMDAxMjExODA2BgNVBAMTL0FOQSBGIFpDSFJPVEtFIE1BUlRJTiBTT1JWRVRFUklBOjIzMjg1MDg5MDAwMTg1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv9W6sA7RBGK/vdOdlxiyS7WcS9y9XctqlrD+VZAY2LB833KdWMG095kETnMAfUJze9tg58U0vnrmoHc9oBBdqGEpsTWY7av7g4CWGxQK4Dy3AoUZVYSV2i+U13/A70uKMSnibLh2o6atrAQsMCFRYXPUj0xM3LVKYJDRKIo9h8fPGJw1YFi7mweooQqjhR+Sipk/rUZyR0IHvH8ZRaIaXN2v/9r37iaa74E5OCIg/cAoFRpVjJ7p7HQ9NZGnxFf8SJuL52EAXXZ9vvOQt1W8xvEYtbxV5SvmbkRqBcEutrFv2V102cSh4EZgkm6m8RcCFeLT7VIevDnXgv5lOZ2E6wIDAQABo4ICyTCCAsUwHwYDVR0jBBgwFoAUKV5L1UZMu/4Wp2PBHcQm8t3Y8wUwDgYDVR0PAQH/BAQDAgXgMG0GA1UdIARmMGQwYgYGYEwBAgEzMFgwVgYIKwYBBQUHAgEWSmh0dHA6Ly9yZXBvc2l0b3Jpby5hY3NhZmV3ZWIuY29tLmJyL2FjLXNhZmV3ZWJyZmIvYWMtc2FmZXdlYi1yZmItcGMtYTEucGRmMIGuBgNVHR8EgaYwgaMwT6BNoEuGSWh0dHA6Ly9yZXBvc2l0b3Jpby5hY3NhZmV3ZWIuY29tLmJyL2FjLXNhZmV3ZWJyZmIvbGNyLWFjLXNhZmV3ZWJyZmJ2NS5jcmwwUKBOoEyGSmh0dHA6Ly9yZXBvc2l0b3JpbzIuYWNzYWZld2ViLmNvbS5ici9hYy1zYWZld2VicmZiL2xjci1hYy1zYWZld2VicmZidjUuY3JsMIGLBggrBgEFBQcBAQR/MH0wUQYIKwYBBQUHMAKGRWh0dHA6Ly9yZXBvc2l0b3Jpby5hY3NhZmV3ZWIuY29tLmJyL2FjLXNhZmV3ZWJyZmIvYWMtc2FmZXdlYnJmYnY1LnA3YjAoBggrBgEFBQcwAYYcaHR0cDovL29jc3AuYWNzYWZld2ViLmNvbS5icjCBuQYDVR0RBIGxMIGugRdDT01QUkFTR1VBSVJBQEdNQUlMLkNPTaAlBgVgTAEDAqAcExpBTkEgRkxBVklBIFpDSFJPVEtFIE1BUlRJTqAZBgVgTAEDA6AQEw4yMzI4NTA4OTAwMDE4NaA4BgVgTAEDBKAvEy0yMDA3MTk3OTAzMjQ5MDMyOTQ4MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDCgFwYFYEwBAwegDhMMMDAwMDAwMDAwMDAwMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQBViPJqVgon1oscVcM7Cbw+M8ommOkOu3rEBGzd/EzHsopRng0njgzvmpj/dz9KuS3VzkIOJ+sLIc+/oHVr19xA4Wpi7JH8vQbn+/Fjrd5YVydjTBL9Z1vuxO5+uyyB7twiGgDKfKC+jhXV/Fx6Ozvic97Jbu55AIgDx+1hzlHNgcZ52wmdiVP15sWocWCES33ayhBlS5E19yvokfYrcwoJe3RM/KEPHzwrCp25EGXN1SqrmI6M3XrFgjkFUYOnO3A8WlndJVN4in81zW6H5kPQHHKbl2CCOtuE2nBl/3DygD3/1eO8FgOD+2NyKPK6S0h13A8u4H9uGXYAhm6RdN+i0WWUQewZ1af7rZjxFvx4XN93h36bjID6C1dG1Dy/X0tH3TSAW00QYuAhEz8IcSF+yqWwziCJ7H7dvCCc3Wval5wNSYFNfs8vhHkhHC1ArBvJ2eySj9wj1RFUDxao53xIyUx/CvVdI45p0DiLA+0rb443AjxRoahX2hT8wHF3Wj2VjKdUzMceg0kUlJeVtdb4dcKPopo2YmsqunvvQ6sXQgitx2jWUlkwUzjrkF79EPfn7RWm/pY2Dau5XNaH7RanGMO77jesWx27geY7i3xyJoxzqSMVxrYH9mS8LX6Zpo6UmjlLYq59Vh1okO03AJ8iwBiwegIu4BXM2/bx3v2+iQ== + + + + diff --git a/tests/fixtures/xml/nfe_layout4_contingencia_sem_assinatura.xml b/tests/fixtures/xml/nfe_layout4_contingencia_sem_assinatura.xml new file mode 100644 index 00000000..486b61f5 --- /dev/null +++ b/tests/fixtures/xml/nfe_layout4_contingencia_sem_assinatura.xml @@ -0,0 +1 @@ +4300001030Venda de producao do estabelecimento551262018-09-25T00:00:00-03:002018-09-25T15:14:00-03:0012430760916221010fernando2024-06-11T23:30:41-03:00Teste de uso da classe em contingência06929383000163UMA RAZAO SOCIAL DE TESTE QUALQUERRua dos Testes10200Centro4319901SAPIRANGARS938000001058BRASIL51909090900018000762158716523000119NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCALAv. Teste2040Centro3550308SAO PAULOSP042070401058BRASIL5190909090111200660311011007SEM GTINUM PRODUTO TESTE QUALQUER6401100012345676101UN10.000050500.00SEM GTINUN10.000050.000010.00020240.000.00000.00490.000.00000.00490.000.00000.000.000.000.000.000.000.000.000.000.000.000.00500.000.000.000.000.000.000.000.000.000.00500.000.0091731.000.001.000012018-12-311.0001500.00 \ No newline at end of file diff --git a/tests/fixtures/xml/retEnviNFe.xml b/tests/fixtures/xml/retEnviNFe.xml old mode 100644 new mode 100755 diff --git a/tests/fixtures/xml/retEnviNFe2.xml b/tests/fixtures/xml/retEnviNFe2.xml old mode 100644 new mode 100755 From 945d1ad6cfca4eabab56d116e730d85e88acaac4 Mon Sep 17 00:00:00 2001 From: robmachado Date: Wed, 12 Jun 2024 09:42:01 -0300 Subject: [PATCH 08/14] Ajustes phpstan --- phpstan-baseline.neon | 4 ---- src/Common/Tools.php | 6 +++--- src/Traits/TraitEPECNfce.php | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 6e466977..42432bbf 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -30,8 +30,4 @@ parameters: count: 1 path: src/Exception/DocumentsException.php - - - message: "#^Variable \\$tpEmis might not be defined\\.$#" - count: 1 - path: src/Factories/Contingency.php diff --git a/src/Common/Tools.php b/src/Common/Tools.php index b33b758a..3e3dd7bf 100755 --- a/src/Common/Tools.php +++ b/src/Common/Tools.php @@ -60,9 +60,9 @@ class Tools public $tpAmb = 2; /** * contingency class - * @var Contingency + * @var Contingency|null */ - public $contingency; + public $contingency = null; /** * soap class * @var ?SoapInterface @@ -395,7 +395,7 @@ protected function isValid(string $version, string $body, string $method): bool */ protected function checkContingencyForWebServices(string $service) { - $type = $this->contingency->type ?? null; + $type = !empty($this->contingency) ? $this->contingency->type : ''; $mod = $this->modelo; if (!empty($type)) { if ($this->modelo == 65) { diff --git a/src/Traits/TraitEPECNfce.php b/src/Traits/TraitEPECNfce.php index e8517155..aeefa0d2 100644 --- a/src/Traits/TraitEPECNfce.php +++ b/src/Traits/TraitEPECNfce.php @@ -70,7 +70,7 @@ public function sefazEpecNfce(string &$xml, string $verAplic = null): string $dom->loadXML($xml); $infNFe = $dom->getElementsByTagName('infNFe')->item(0); $ide = $dom->getElementsByTagName('ide')->item(0); - $tpEmis = (int) $ide->getElementsByTagName('tpEmis')->item(0)->nodeValue ?? 0; + $tpEmis = (int) $ide->getElementsByTagName('tpEmis')->item(0)->nodeValue; $dhCont = $ide->getElementsByTagName('dhCont')->item(0)->nodeValue ?? ''; $xJust = $ide->getElementsByTagName('xJust')->item(0)->nodeValue ?? ''; if ($tpEmis !== 4 || empty($dhCont) || empty($xJust)) { From 6d3337a65725292f3d8ec5da8ae2f845fa56a2c7 Mon Sep 17 00:00:00 2001 From: robmachado Date: Wed, 12 Jun 2024 10:19:25 -0300 Subject: [PATCH 09/14] Ajustes phpstan --- src/Common/Standardize.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Common/Standardize.php b/src/Common/Standardize.php index be43c01e..e00fdf18 100755 --- a/src/Common/Standardize.php +++ b/src/Common/Standardize.php @@ -82,10 +82,8 @@ public function whichIs(?string $xml = null): string $this->xml = $xml; } if (!Validator::isXML($this->xml)) { - $erro = Validator::$erro; - throw new DocumentsException($erro); //invalid document is not a XML - //throw DocumentsException::wrongDocument(6); + throw new DocumentsException('Documento inválido'); } $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->preserveWhiteSpace = false; From 140e1f33dd2f37e3b4584b349eeba84c7745544e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Gusm=C3=A3o?= Date: Fri, 12 Jul 2024 20:39:59 +0100 Subject: [PATCH 10/14] ajuste strutura txt add indDeduzDeson --- storage/txtstructure400.json | 2 +- storage/txtstructure400_sebrae.json | 2 +- storage/txtstructure400_v1.2.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/txtstructure400.json b/storage/txtstructure400.json index dd8c9ad0..7b920187 100755 --- a/storage/txtstructure400.json +++ b/storage/txtstructure400.json @@ -53,7 +53,7 @@ "N03":"N03|orig|CST|modBC|vBC|pICMS|vICMS|vBCFCP|pFCP|vFCP|modBCST|pMVAST|pRedBCST|vBCST|pICMSST|vICMSST|vBCFCPST|pFCPST|vFCPST|", "N04":"N04|orig|CST|modBC|pRedBC|vBC|pICMS|vICMS|vBCFCP|pFCP|vFCP|vICMSDeson|motDesICMS|", "N05":"N05|orig|CST|modBCST|pMVAST|pRedBCST|vBCST|pICMSST|vICMSST|vBCFCPST|pFCPST|vFCPST|vICMSDeson|motDesICMS|", - "N06":"N06|orig|CST|vICMSDeson|motDesICMS|", + "N06":"N06|orig|CST|vICMSDeson|motDesICMS|indDeduzDeson|", "N07":"N07|orig|CST|modBC|pRedBC|vBC|pICMS|vICMSOp|pDif|vICMSDif|vICMS|vBCFCP|pFCP|vFCP|", "N08":"N08|orig|CST|vBCSTRet|pST|vICMSSTRet|vBCFCPSTRet|pFCPSTRet|vFCPSTRet|pRedBCEfet|vBCEfet|pICMSEfet|vICMSEfet|vICMSSubstituto|", "N09":"N09|orig|CST|modBC|pRedBC|vBC|pICMS|vICMS|vBCFCP|pFCP|vFCP|modBCST|pMVAST|pRedBCST|vBCST|pICMSST|vICMSST|vBCFCPST|pFCPST|vFCPST|vICMSDeson|motDesICMS|", diff --git a/storage/txtstructure400_sebrae.json b/storage/txtstructure400_sebrae.json index 4c526736..88ea25a2 100755 --- a/storage/txtstructure400_sebrae.json +++ b/storage/txtstructure400_sebrae.json @@ -51,7 +51,7 @@ "N03":"N03|orig|CST|modBC|vBC|pICMS|vICMS|vBCFCP|pFCP|vFCP|modBCST|pMVAST|pRedBCST|vBCST|pICMSST|vICMSST|vBCFCPST|pFCPST|vFCPST|", "N04":"N04|orig|CST|modBC|pRedBC|vBC|pICMS|vICMS|vBCFCP|pFCP|vFCP|vICMSDeson|motDesICMS|", "N05":"N05|orig|CST|modBCST|pMVAST|pRedBCST|vBCST|pICMSST|vICMSST|vBCFCPST|pFCPST|vFCPST|vICMSDeson|motDesICMS|", - "N06":"N06|orig|CST|vICMSDeson|motDesICMS|", + "N06":"N06|orig|CST|vICMSDeson|motDesICMS|indDeduzDeson|", "N07":"N07|orig|CST|modBC|pRedBC|vBC|pICMS|vICMSOp|pDif|vICMSDif|vICMS|vBCFCP|pFCP|vFCP|", "N08":"N08|orig|CST|vBCSTRet|pST|vICMSSubstituto|vICMSSTRet|vBCFCPSTRet|pFCPSTRet|vFCPSTRet|pRedBCEfet|vBCEfet|pICMSEfet|vICMSEfet|", "N09":"N09|orig|CST|modBC|pRedBC|vBC|pICMS|vICMS|vBCFCP|pFCP|vFCP|modBCST|pMVAST|pRedBCST|vBCST|pICMSST|vICMSST|vBCFCPST|pFCPST|vFCPST|vICMSDeson|motDesICMS|", diff --git a/storage/txtstructure400_v1.2.json b/storage/txtstructure400_v1.2.json index f34b840d..e7fbc673 100755 --- a/storage/txtstructure400_v1.2.json +++ b/storage/txtstructure400_v1.2.json @@ -53,7 +53,7 @@ "N03":"N03|orig|CST|modBC|vBC|pICMS|vICMS|vBCFCP|pFCP|vFCP|modBCST|pMVAST|pRedBCST|vBCST|pICMSST|vICMSST|vBCFCPST|pFCPST|vFCPST|", "N04":"N04|orig|CST|modBC|pRedBC|vBC|pICMS|vICMS|vBCFCP|pFCP|vFCP|vICMSDeson|motDesICMS|", "N05":"N05|orig|CST|modBCST|pMVAST|pRedBCST|vBCST|pICMSST|vICMSST|vBCFCPST|pFCPST|vFCPST|vICMSDeson|motDesICMS|", - "N06":"N06|orig|CST|vICMSDeson|motDesICMS|", + "N06":"N06|orig|CST|vICMSDeson|motDesICMS|indDeduzDeson|", "N07":"N07|orig|CST|modBC|pRedBC|vBC|pICMS|vICMSOp|pDif|vICMSDif|vICMS|vBCFCP|pFCP|vFCP|", "N08":"N08|orig|CST|vBCSTRet|pST|vICMSSTRet|vBCFCPSTRet|pFCPSTRet|vFCPSTRet|pRedBCEfet|vBCEfet|pICMSEfet|vICMSEfet|vICMSSubstituto|", "N09":"N09|orig|CST|modBC|pRedBC|vBC|pICMS|vICMS|vBCFCP|pFCP|vFCP|modBCST|pMVAST|pRedBCST|vBCST|pICMSST|vICMSST|vBCFCPST|pFCPST|vFCPST|vICMSDeson|motDesICMS|", From 14ca3442645954e781a37a4d84707fc0359551cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Gusm=C3=A3o?= Date: Mon, 15 Jul 2024 19:23:13 +0100 Subject: [PATCH 11/14] Convert show errors --- src/Convert.php | 2 +- src/Factories/Parser.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Convert.php b/src/Convert.php index 831ff091..d40d3cca 100755 --- a/src/Convert.php +++ b/src/Convert.php @@ -74,7 +74,7 @@ public function toXml(): array $parser = new Parser($version, $this->baselayout); try { $this->xmls[] = $parser->toXml($nota); - } catch (\Exception $e) { + } catch (\Throwable $e) { if ($errors = $parser->getErrors()) { throw new ParserException(implode(', ', $errors)); } else { diff --git a/src/Factories/Parser.php b/src/Factories/Parser.php index 61d00420..22f14634 100755 --- a/src/Factories/Parser.php +++ b/src/Factories/Parser.php @@ -141,7 +141,7 @@ public function toXml(array $nota): ?string */ public function getErrors(): array { - return $this->make->errors; + return $this->make->getErrors(); } /** From 9b5cd5aa9a33f597dc19fce401a83a169791529a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Gusm=C3=A3o?= Date: Wed, 17 Jul 2024 10:57:11 +0100 Subject: [PATCH 12/14] phpunit convert error --- tests/ConvertTest.php | 10 +++ tests/fixtures/txt/nfe_4.00_local_error.txt | 70 +++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 tests/fixtures/txt/nfe_4.00_local_error.txt diff --git a/tests/ConvertTest.php b/tests/ConvertTest.php index dbdcc256..76be74c0 100644 --- a/tests/ConvertTest.php +++ b/tests/ConvertTest.php @@ -3,6 +3,7 @@ namespace NFePHP\NFe\Tests; use NFePHP\NFe\Convert; +use NFePHP\NFe\Exception\ParserException; use PHPUnit\Framework\TestCase; class ConvertTest extends TestCase @@ -30,6 +31,15 @@ public function test_convert() $this->assertInfoAdicional($nfe); } + public function test_convert_errors() + { + $this->expectException(ParserException::class); + $this->expectExceptionMessageMatches('/A chave informada está incorreta/'); + $txt = file_get_contents(__DIR__ . '/fixtures/txt/nfe_4.00_local_error.txt'); + $conv = new Convert($txt); + $conv->toXml(); + } + /** * @param \SimpleXMLElement $nfe * @return void diff --git a/tests/fixtures/txt/nfe_4.00_local_error.txt b/tests/fixtures/txt/nfe_4.00_local_error.txt new file mode 100644 index 00000000..0006016c --- /dev/null +++ b/tests/fixtures/txt/nfe_4.00_local_error.txt @@ -0,0 +1,70 @@ +NOTAFISCAL|1| +A|4.00|NFe3518082502833200010|| +B|35|00000501|VENDA MERC.SUB.TRIBUTARIA|55|1|502|2018-08-13T17:28:10-03:00|2018-08-14T09:00:00-03:00|1|1|3550308|1|1|8|1|1|0|3|0|0|3.2.1.1||| +C|GSMMY COMERCIO DE CHOCOLATES LTDA|GSMMY|140950881119||||3| +C02|25028332000105| +C05|RUA CAETEZAL|296||AGUA FRIA|3550308|SAO PAULO|SP|02334130||Brasil|1122813500| +E|SILVANA MARCONI - VL LEOPOLDINA|1|142304338112|||vilaleopoldina@munik.com.br| +E02|17812455000295| +E05|R SCHILLING|491||VILA LEOPOLDINA|3550308|SAO PAULO|SP|05302001|1058|BRASIL|1143053063| +H|3|| +I|11352|7897112913525|CX DE BOMBOM SORTIDO 105G - 11352|18069000|||5401|CX|10.0000|2.5300|25.30|7897112913525|CX|10.0000|2.5300|||||1||0|| +I05c|1700700||| +M|0.00| +N| +N03|0|10|3|25.30|18.00|4.55||||0|||42.27|18.00|3.06|||| +O|||0|999| +O07|50|0.12| +O10|25.30|0.00| +Q| +Q02|01|25.30|0.65|0.16| +S| +S02|01|25.30|3.00|0.76| +H|4|| +I|14169|SEM GTIN|BOLO MEL BRIGADEIRO 65G CELOFANE E FITA - 14169|19052090|||5401|UN|10.0000|1.1200|11.20|SEM GTIN|UN|10.0000|1.1200|||||1||0|| +I05c|1705600||| +M|0.00| +N| +N09|0|70|3|61.11|4.35|18.00|0.78||||0|||7.50|0.00|1.33|||||| +O|||0|999| +O08|53| +Q| +Q02|01|11.20|0.65|0.07| +S| +S02|01|11.20|3.00|0.34| +H|2|| +I|355|7897112903557|CX PAO DE MEL M/M 430 G - 355|19052090|||5401|CX|2.0000|11.2300|22.46|7897112903557|CX|2.0000|11.2300|||||1||0|| +I05c|1705600||| +M|0.00| +N| +N09|0|70|3|61.11|8.73|18.00|1.57||||0|||15.03|0.00|2.67|||||| +O|||0|999| +O08|53| +Q| +Q02|01|22.46|0.65|0.15| +S| +S02|01|22.46|3.00|0.67| +H|1|| +I|45|7897112900457|CX PAO DE MEL LEITE 430 G - 45|19052090|||5401|CX|4.0000|11.2300|44.92|7897112900457|CX|4.0000|11.2300|||||1||0|| +I05c|1705600||| +M|0.00| +N| +N09|0|70|3|61.11|17.46|18.00|3.14||||0|||30.07|0.00|5.33|||||| +O|||0|999| +O08|53| +Q| +Q02|01|44.92|0.65|0.29| +S| +S02|01|44.92|3.00|1.35| +W| +W02|55.84|10.04|0.00|0.00|94.87|12.39|0.00|0.00|103.88|0.00|0.00|0.00|0.00|0.12|0.00|0.67|3.12|0.00|116.39|0.00|0.00|0.00|0.00| +X|3| +X03|CARRO PROPRIO -MUNIK|111220540115|R CAITEZAL, 316|SAO PAULO|SP| +X04|47269568000257| +X26|1|VOLUME|MUNIK||4.230|4.230| +Y|| +Y02|502|116.39|0.00|116.39| +Y07|001|2018-08-13|116.39| +YA|0|01|116.39||00||0| +Z||BASE DO ICMS REDUZIDA EM 61,11 CF RICMS Pedido 000068| + From c94a586a823b5c2388a7852032b2d71b9485e00f Mon Sep 17 00:00:00 2001 From: robmachado Date: Tue, 30 Jul 2024 16:42:15 -0300 Subject: [PATCH 13/14] =?UTF-8?q?inclus=C3=A3o=20do=20evento=20de=20concil?= =?UTF-8?q?ia=C3=A7=C3=A3o=20financeira?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/5.0testSefazCadastro.php | 19 +- examples/5.0testSefazCancela.php | 32 +- fake/fakeSefazConcilicacao.php | 127 ++++++++ schemes/PL_009_V4/EventoCancEConf_v1.00.xsd | 9 + schemes/PL_009_V4/EventoEConf_v1.00.xsd | 9 + schemes/PL_009_V4/e110750_v1.00.xsd | 138 ++++++++ schemes/PL_009_V4/e110751_v1.00.xsd | 39 +++ .../PL_009_V4/envEventoCancEConf_v1.00.xsd | 10 + schemes/PL_009_V4/envEventoEConf_v1.00.xsd | 10 + .../leiauteEventoCancEConf_v1.00.xsd | 296 ++++++++++++++++++ .../PL_009_V4/leiauteEventoEConf_v1.00.xsd | 296 ++++++++++++++++++ .../PL_009_V4/procEventoCancEConf_v1.00.xsd | 9 + schemes/PL_009_V4/procEventoEConf_v1.00.xsd | 9 + .../PL_009_V4/retEventoCancEConf_v1.00.xsd | 9 + schemes/PL_009_V4/retEventoEConf_v1.00.xsd | 9 + src/Tools.php | 143 +++++++++ 16 files changed, 1144 insertions(+), 20 deletions(-) create mode 100644 fake/fakeSefazConcilicacao.php create mode 100644 schemes/PL_009_V4/EventoCancEConf_v1.00.xsd create mode 100644 schemes/PL_009_V4/EventoEConf_v1.00.xsd create mode 100644 schemes/PL_009_V4/e110750_v1.00.xsd create mode 100644 schemes/PL_009_V4/e110751_v1.00.xsd create mode 100644 schemes/PL_009_V4/envEventoCancEConf_v1.00.xsd create mode 100644 schemes/PL_009_V4/envEventoEConf_v1.00.xsd create mode 100644 schemes/PL_009_V4/leiauteEventoCancEConf_v1.00.xsd create mode 100644 schemes/PL_009_V4/leiauteEventoEConf_v1.00.xsd create mode 100644 schemes/PL_009_V4/procEventoCancEConf_v1.00.xsd create mode 100644 schemes/PL_009_V4/procEventoEConf_v1.00.xsd create mode 100644 schemes/PL_009_V4/retEventoCancEConf_v1.00.xsd create mode 100644 schemes/PL_009_V4/retEventoEConf_v1.00.xsd diff --git a/examples/5.0testSefazCadastro.php b/examples/5.0testSefazCadastro.php index 4f75079a..609057c6 100755 --- a/examples/5.0testSefazCadastro.php +++ b/examples/5.0testSefazCadastro.php @@ -8,8 +8,8 @@ use NFePHP\Common\Soap\SoapCurl; //tanto o config.json como o certificado.pfx podem estar -//armazenados em uma base de dados, então não é necessário -///trabalhar com arquivos, este script abaixo serve apenas como +//armazenados em uma base de dados, então não é necessário +///trabalhar com arquivos, este script abaixo serve apenas como //exemplo durante a fase de desenvolvimento e testes. $arr = [ "atualizacao" => "2016-11-03 18:01:21", @@ -27,21 +27,24 @@ "proxyPort" => "", "proxyUser" => "", "proxyPass" => "" - ] + ] ]; //monta o config.json $configJson = json_encode($arr); //carrega o conteudo do certificado. -$content = file_get_contents('expired_certificate.pfx'); +$content = file_get_contents('fixtures/expired_certificate.pfx'); +$soap = new \NFePHP\Common\Soap\SoapFake(); +$soap->disableCertValidation(true); $tools = new Tools($configJson, Certificate::readPfx($content, 'associacao')); +$tools->loadSoapClass($soap); -//Somente para modelo 55, o modelo 65 evidentemente não possue +//Somente para modelo 55, o modelo 65 evidentemente não possue //esse tipo de serviço $tools->model('55'); -//coloque a UF e escolha entre +//coloque a UF e escolha entre //CNPJ //IE //CPF @@ -53,6 +56,6 @@ $cpf = ''; $response = $tools->sefazCadastro($uf, $cnpj, $iest, $cpf); -header('Content-type: text/xml; charset=UTF-8'); -echo $response; +echo \NFePHP\NFe\Common\FakePretty::prettyPrint($response); + diff --git a/examples/5.0testSefazCancela.php b/examples/5.0testSefazCancela.php index 549b79b9..f5aa7ee8 100755 --- a/examples/5.0testSefazCancela.php +++ b/examples/5.0testSefazCancela.php @@ -9,15 +9,15 @@ use NFePHP\NFe\Complements; //tanto o config.json como o certificado.pfx podem estar -//armazenados em uma base de dados, então não é necessário -///trabalhar com arquivos, este script abaixo serve apenas como +//armazenados em uma base de dados, então não é necessário +///trabalhar com arquivos, este script abaixo serve apenas como //exemplo durante a fase de desenvolvimento e testes. $arr = [ "atualizacao" => "2016-11-03 18:01:21", "tpAmb" => 2, "razaosocial" => "SUA RAZAO SOCIAL LTDA", "cnpj" => "99999999999999", - "siglaUF" => "SP", + "siglaUF" => "MG", "schemes" => "PL_009_V4", "versao" => '4.00', "tokenIBPT" => "AAAAAAA", @@ -28,26 +28,34 @@ "proxyPort" => "", "proxyUser" => "", "proxyPass" => "" - ] + ] ]; //monta o config.json $configJson = json_encode($arr); //carrega o conteudo do certificado. -$content = file_get_contents('expired_certificate.pfx'); +$content = file_get_contents('fixtures/expired_certificate.pfx'); try { + $soap = new \NFePHP\Common\Soap\SoapFake(); + $soap->disableCertValidation(true); + + $tools = new Tools($configJson, Certificate::readPfx($content, 'associacao')); + $tools->loadSoapClass($soap); $tools->model('55'); - - $chave = '35170399999999999999550010000000301000000300'; + + $chave = '31170399999999999999550010000000301000000300'; $xJust = 'Desistencia do comprador no momento da retirada'; $nProt = '135170001136476'; $response = $tools->sefazCancela($chave, $xJust, $nProt); - + + echo \NFePHP\NFe\Common\FakePretty::prettyPrint($response); + + /* //você pode padronizar os dados de retorno atraves da classe abaixo //de forma a facilitar a extração dos dados do XML - //NOTA: mas lembre-se que esse XML muitas vezes será necessário, + //NOTA: mas lembre-se que esse XML muitas vezes será necessário, // quando houver a necessidade de protocolos $stdCl = new Standardize($response); //nesse caso $std irá conter uma representação em stdClass do XML retornado @@ -56,7 +64,7 @@ $arr = $stdCl->toArray(); //nesse caso o $json irá conter uma representação em JSON do XML retornado $json = $stdCl->toJson(); - + //verifique se o evento foi processado if ($std->cStat != 128) { //houve alguma falha e o evento não foi processado @@ -68,10 +76,10 @@ $xml = Complements::toAuthorize($tools->lastRequest, $response); //grave o XML protocolado e prossiga com outras tarefas de seu aplicativo } else { - //houve alguma falha no evento + //houve alguma falha no evento //TRATAR } - } + }*/ } catch (\Exception $e) { echo $e->getMessage(); //TRATAR diff --git a/fake/fakeSefazConcilicacao.php b/fake/fakeSefazConcilicacao.php new file mode 100644 index 00000000..435b03b9 --- /dev/null +++ b/fake/fakeSefazConcilicacao.php @@ -0,0 +1,127 @@ + "2016-11-03 18:01:21", + "tpAmb" => 2, + "razaosocial" => "SUA RAZAO SOCIAL LTDA", + "cnpj" => "99999999999999", + "siglaUF" => "SP", + "schemes" => "PL_009_V4", + "versao" => '4.00', + "tokenIBPT" => "AAAAAAA", + "CSC" => "GPB0JBWLUR6HWFTVEAS6RJ69GPCROFPBBB8G", + "CSCid" => "000001", + "proxyConf" => [ + "proxyIp" => "", + "proxyPort" => "", + "proxyUser" => "", + "proxyPass" => "" + ] + ]; + $configJson = json_encode($arr); + $soap = new SoapFake(); + $soap->disableCertValidation(true); + + $content = file_get_contents('expired_certificate.pfx'); + $tools = new Tools($configJson, Certificate::readPfx($content, 'associacao')); + $tools->model('55'); + $tools->setVerAplic('5.1.34'); + $tools->loadSoapClass($soap); + + $std = new \stdClass(); + //$std->verAplic = '1.2.3'; //opcional se declarado anteriormente - versão da aplicação que está gerando o evento + $std->nSeqEvento = 1; + $std->chNFe = '12345678901234567890123456789012345678901234'; //chave de 44 digitos da nota do fornecedor + $std->detPag[0] = new \stdClass(); + $std->detPag[0]->indPag = null; //opcional 0-Pagamento à Vista; 1-Pagamento à Prazo + $std->detPag[0]->tPag = '04'; //Obrigatório forma de pagamento + // '01' => 'Dinheiro', + // '02' => 'Cheque', + // '03' => 'Cartão de Crédito', + // '04' => 'Cartão de Débito', + // '05' => 'Cartão da Loja', + // '10' => 'Vale Alimentação', + // '11' => 'Vale Refeição', + // '12' => 'Vale Presente', + // '13' => 'Vale Combustível', + // '14' => 'Duplicata Mercantil', + // '15' => 'Boleto', + // '16' => 'Depósito Bancário', + // '17' => 'PIX Dinâmico', + // '18' => 'Transferência bancária, Carteira Digital', + // '19' => 'Programa fidelidade, Cashback, Créd Virt', + // '20' => 'PIX Estático', + // '21' => 'Crédito em Loja', + // '22' => 'Pagamento Eletrônico não Informado - Falha de hardware', + // '90' => 'Sem pagamento', + // '99' => 'Outros' + $std->detPag[0]->xPag = null; //opcional de 2 a 50 caracteres, usar quando tPag == 99 + $std->detPag[0]->vPag = 102.34; //Obrigatório valor pago + $std->detPag[0]->dPag = '2024-07-30'; //Obrigatório data do pagamento + + //grupo OPCIONAL de informações sobre envolvidos no pagamento + $std->detPag[0]->CNPJPag = '12345678901234'; //opcional, caso seja informado a UFPag também deverá ser informada + // CNPJ transacional do pagamento - Preencher informando o CNPJ do estabelecimento onde o pagamento foi + // processado/transacionado/recebido quando a emissão do documento fiscal ocorrer em estabelecimento distinto + $std->detPag[0]->UFPag = 'SP'; //opcional, caso seja informado a CNPJPag também deverá ser informada + // UF do CNPJ do estabelecimento onde o pagamento foi processado/transacionado/recebido + $std->detPag[0]->CNPJIF = '11111111111111'; //opcinal + //CNPJ da instituição financeira, de pagamento, adquirente ou subadquirente. + $std->detPag[0]->tBand = '20'; //opcional Bandeira da operadora de cartão + //01 Visa + //02 Mastercard + //03 American Express + //04 Sorocred + //05 Diners Club + //06 Elo + //07 Hipercard + //08 Aura + //09 Cabal + //10 Alelo + //11 Banes Card + //12 CalCard + //13 Credz + //14 Discover + //15 GoodCard + //16 GreenCard + //17 Hiper + //18 JcB + //19 Mais + //20 MaxVan + //21 Policard + //22 RedeCompras + //23 Sodexo + //24 ValeCard + //25 Verocheque + //26 VR + //27 Ticket + //99 Outros + $std->detPag[0]->cAut = 'a23232-49329fed'; //opcional Número de autorização da operação com cartões, PIX, boletos e outros + // pagamentos eletrônicos + + //grupo OPCIONAL de informações sobre o + $std->detPag[0]->CNPJReceb = '09876543210987';//opcional CNPJ do estab. benefic. do pag., se informado informar também a UFReceb + $std->detPag[0]->UFReceb = 'CE'; //opcional se informado informar também a CNPJReceb + + $std->cancelar = false; //permite cancelar um registro de conciliação financeira anterior + + //para cancelar + //$std->cancela = true; + //$std->protocolo = '750123456789012'; + + $response = $tools->sefazConciliacao($std); + + echo FakePretty::prettyPrint($response); +} catch (\Exception $e) { + echo $e->getMessage(); +} diff --git a/schemes/PL_009_V4/EventoCancEConf_v1.00.xsd b/schemes/PL_009_V4/EventoCancEConf_v1.00.xsd new file mode 100644 index 00000000..662ea235 --- /dev/null +++ b/schemes/PL_009_V4/EventoCancEConf_v1.00.xsd @@ -0,0 +1,9 @@ + + + + + + Schema XML de validação do evento de Cancelamento do Comprovante de Entrega da NFe + + + diff --git a/schemes/PL_009_V4/EventoEConf_v1.00.xsd b/schemes/PL_009_V4/EventoEConf_v1.00.xsd new file mode 100644 index 00000000..713a60fa --- /dev/null +++ b/schemes/PL_009_V4/EventoEConf_v1.00.xsd @@ -0,0 +1,9 @@ + + + + + + Schema XML de validação do evento de Conciliação Financeira + + + diff --git a/schemes/PL_009_V4/e110750_v1.00.xsd b/schemes/PL_009_V4/e110750_v1.00.xsd new file mode 100644 index 00000000..3633a856 --- /dev/null +++ b/schemes/PL_009_V4/e110750_v1.00.xsd @@ -0,0 +1,138 @@ + + + + + + + Schema XML de validação do evento de Conciliação Financeira – ECONF + + + + + + + + + + + + + Versão do Aplicativo do Autor do Evento + + + + + Grupo de detalhamento da forma de pagamento. + + + + + + Indicador da Forma de Pagamento:0-Pagamento à Vista;1-Pagamento à Prazo; + + + + + + + + + + + + Forma de Pagamento: + + + + + + + + + + + Descrição do Meio de Pagamento + + + + + + + + + + + Valor do Pagamento. Esta tag poderá ser omitida quando a tag tPag=90 (Sem Pagamento), caso contrário deverá ser preenchida. + + + + + Data do Pagamento + + + + + + CNPJ transacional do pagamento - Preencher informando o CNPJ do estabelecimento onde o pagamento foi processado/transacionado/recebido quando a emissão do documento fiscal ocorrer em estabelecimento distinto + + + + + UF do CNPJ do estabelecimento onde o pagamento foi processado/transacionado/recebido. + + + + + CNPJ da instituição financeira, de pagamento, adquirente ou subadquirente. + + + + + Bandeira da operadora de cartão + + + + + + + + + + + Número de autorização da operação com cartões, PIX, boletos e outros pagamentos eletrônicos + + + + + + + + + + + + + Informar o CNPJ do estabelecimento beneficiário do pagamento + + + + + UF do CNPJ do estabelecimento beneficiário do pagamento.. + + + + + + + + + + + + + + + + + + diff --git a/schemes/PL_009_V4/e110751_v1.00.xsd b/schemes/PL_009_V4/e110751_v1.00.xsd new file mode 100644 index 00000000..7543784a --- /dev/null +++ b/schemes/PL_009_V4/e110751_v1.00.xsd @@ -0,0 +1,39 @@ + + + + + + + Schema XML de validação do evento de Cancelamento do Comprovante de Entrega da NF-e + + + + + + + + + + + + + Versão do Aplicativo do Autor do Evento + + + + + Número do Protocolo de Autorização do Evento da NF-e a que se refere este cancelamento. + + + + + + + + + + + + + + diff --git a/schemes/PL_009_V4/envEventoCancEConf_v1.00.xsd b/schemes/PL_009_V4/envEventoCancEConf_v1.00.xsd new file mode 100644 index 00000000..bb050869 --- /dev/null +++ b/schemes/PL_009_V4/envEventoCancEConf_v1.00.xsd @@ -0,0 +1,10 @@ + + + + + + + Schema XML de validação do lote de envio do evento de Cancelamento de Conciliação Financeira + + + diff --git a/schemes/PL_009_V4/envEventoEConf_v1.00.xsd b/schemes/PL_009_V4/envEventoEConf_v1.00.xsd new file mode 100644 index 00000000..f4e5a28a --- /dev/null +++ b/schemes/PL_009_V4/envEventoEConf_v1.00.xsd @@ -0,0 +1,10 @@ + + + + + + + Schema XML de validação do lote de envio do evento de Conciliação Financeira + + + diff --git a/schemes/PL_009_V4/leiauteEventoCancEConf_v1.00.xsd b/schemes/PL_009_V4/leiauteEventoCancEConf_v1.00.xsd new file mode 100644 index 00000000..710d25de --- /dev/null +++ b/schemes/PL_009_V4/leiauteEventoCancEConf_v1.00.xsd @@ -0,0 +1,296 @@ + + + + + + + + Tipo Evento + + + + + + + + Código do órgão de recepção do Evento. Utilizar a Tabela do IBGE extendida, utilizar 90 para identificar o Ambiente Nacional + + + + + Identificação do Ambiente: +1 - Produção +2 - Homologação + + + + + Identificação do autor do evento + + + + CNPJ + + + + + CPF + + + + + + Chave de Acesso da NF-e vinculada ao evento + + + + + Data de emissão no formato UTC. AAAA-MM-DDThh:mm:ssTZD + + + + + Tipo do Evento + + + + + + + + + + + + Seqüencial do evento para o mesmo tipo de evento. Para maioria dos eventos será 1, nos casos em que possa existir mais de um evento, como é o caso da carta de correção, o autor do evento deve numerar de forma seqüencial. + + + + + + + + + + + Versão do Tipo do Evento + + + + + + + + + + + + + Identificador da TAG a ser assinada, a regra de formação do Id é: +“ID” + tpEvento + chave da NF-e + nSeqEvento + + + + + + + + + + + + + + + + Tipo Versão do Evento + + + + + + + + + Tipo retorno do Evento + + + + + + + + Identificação do Ambiente: +1 - Produção +2 - Homologação + + + + + Versão do Aplicativo que recebeu o Evento + + + + + Código do órgão de recepção do Evento. Utilizar a Tabela do IBGE extendida, utilizar 90 para identificar o Ambiente Nacional + + + + + Código do status da registro do Evento + + + + + Descrição literal do status do registro do Evento + + + + + Chave de Acesso NF-e vinculada + + + + + Tipo do Evento vinculado + + + + + + + + + + + Descrição do Evento + + + + + + + + + + + Seqüencial do evento + + + + + + + + + + + Data e Hora de do recebimento do evento ou do registro do evento formato UTC AAAA-MM-DDThh:mm:ssTZD. + + + + + + + + + + + Número do protocolo de registro do evento + + + + + + + + + + + + + + + + + + + Tipo Lote de Envio + + + + + + + + + + + + + + + + + Tipo Versão do EnvEvento + + + + + + + + + Tipo Retorno de Lote de Envio + + + + + + + + + + + + + Identificação do Ambiente: +1 - Produção +2 - Homologação + + + + + Versão do Aplicativo que recebeu o Evento + + + + + Código do òrgao que registrou o Evento + + + + + Código do status da registro do Evento + + + + + Descrição literal do status do registro do Evento + + + + + + + + + Tipo procEvento + + + + + + + + diff --git a/schemes/PL_009_V4/leiauteEventoEConf_v1.00.xsd b/schemes/PL_009_V4/leiauteEventoEConf_v1.00.xsd new file mode 100644 index 00000000..fe9d449d --- /dev/null +++ b/schemes/PL_009_V4/leiauteEventoEConf_v1.00.xsd @@ -0,0 +1,296 @@ + + + + + + + + Tipo Evento + + + + + + + + Código do órgão de recepção do Evento. Utilizar a Tabela do IBGE extendida, utilizar 91 para identificar o Ambiente Nacional + + + + + Identificação do Ambiente: +1 - Produção +2 - Homologação + + + + + Identificação do autor do evento + + + + CNPJ + + + + + CPF + + + + + + Chave de Acesso da NF-e vinculada ao evento + + + + + Data de emissão no formato UTC. AAAA-MM-DDThh:mm:ssTZD + + + + + Tipo do Evento + + + + + + + + + + + + Seqüencial do evento para o mesmo tipo de evento. Para maioria dos eventos será 1, nos casos em que possa existir mais de um evento, como é o caso da carta de correção, o autor do evento deve numerar de forma seqüencial. + + + + + + + + + + + Versão do Tipo do Evento + + + + + + + + + + + + + Identificador da TAG a ser assinada, a regra de formação do Id é: +“ID” + tpEvento + chave da NF-e + nSeqEvento + + + + + + + + + + + + + + + + Tipo Versão do Evento + + + + + + + + + Tipo retorno do Evento + + + + + + + + Identificação do Ambiente: +1 - Produção +2 - Homologação + + + + + Versão do Aplicativo que recebeu o Evento + + + + + Código do órgão de recepção do Evento. Utilizar a Tabela do IBGE extendida, utilizar 91 para identificar o Ambiente Nacional + + + + + Código do status da registro do Evento + + + + + Descrição literal do status do registro do Evento + + + + + Chave de Acesso NF-e vinculada + + + + + Tipo do Evento vinculado + + + + + + + + + + + Descrição do Evento + + + + + + + + + + + Seqüencial do evento + + + + + + + + + + + Data e Hora de do recebimento do evento ou do registro do evento formato UTC AAAA-MM-DDThh:mm:ssTZD. + + + + + + + + + + + Número do protocolo de registro do evento + + + + + + + + + + + + + + + + + + + Tipo Lote de Envio + + + + + + + + + + + + + + + + + Tipo Versão do EnvEvento + + + + + + + + + Tipo Retorno de Lote de Envio + + + + + + + + + + + + + Identificação do Ambiente: +1 - Produção +2 - Homologação + + + + + Versão do Aplicativo que recebeu o Evento + + + + + Código do òrgao que registrou o Evento + + + + + Código do status da registro do Evento + + + + + Descrição literal do status do registro do Evento + + + + + + + + + Tipo procEvento + + + + + + + + diff --git a/schemes/PL_009_V4/procEventoCancEConf_v1.00.xsd b/schemes/PL_009_V4/procEventoCancEConf_v1.00.xsd new file mode 100644 index 00000000..df783064 --- /dev/null +++ b/schemes/PL_009_V4/procEventoCancEConf_v1.00.xsd @@ -0,0 +1,9 @@ + + + + + + Schema XML de validação do proc do evento de Cancelamento de Conciliação financeira + + + diff --git a/schemes/PL_009_V4/procEventoEConf_v1.00.xsd b/schemes/PL_009_V4/procEventoEConf_v1.00.xsd new file mode 100644 index 00000000..d2607121 --- /dev/null +++ b/schemes/PL_009_V4/procEventoEConf_v1.00.xsd @@ -0,0 +1,9 @@ + + + + + + Schema XML de validação do proc do Evento de Conciliação Financeira + + + diff --git a/schemes/PL_009_V4/retEventoCancEConf_v1.00.xsd b/schemes/PL_009_V4/retEventoCancEConf_v1.00.xsd new file mode 100644 index 00000000..88791095 --- /dev/null +++ b/schemes/PL_009_V4/retEventoCancEConf_v1.00.xsd @@ -0,0 +1,9 @@ + + + + + + Schema XML de Retorno da envio do evento de Cancelamento de Conciliação Financeira + + + diff --git a/schemes/PL_009_V4/retEventoEConf_v1.00.xsd b/schemes/PL_009_V4/retEventoEConf_v1.00.xsd new file mode 100644 index 00000000..83b7352f --- /dev/null +++ b/schemes/PL_009_V4/retEventoEConf_v1.00.xsd @@ -0,0 +1,9 @@ + + + + + + Schema XML de Retorno da envio do evento de Conciliação Financeira + + + diff --git a/src/Tools.php b/src/Tools.php index dc3aac15..96ab0d38 100755 --- a/src/Tools.php +++ b/src/Tools.php @@ -16,6 +16,7 @@ namespace NFePHP\NFe; +use NFePHP\Common\DOMImproved; use NFePHP\Common\Strings; use NFePHP\Common\Signer; use NFePHP\Common\UFList; @@ -843,6 +844,47 @@ public function sefazInsucessoEntrega( ); } + /** + * Request event of financial reconciliation + * @param \stdClass $std + * @param \DateTimeInterface|null $dhEvento + * @param string|null $lote + * @return string + * @throws \DOMException + */ + public function sefazConciliacao( + \stdClass $std, + ?\DateTimeInterface $dhEvento = null, + ?string $lote = null + ): string { + if (empty($std->verAplic) && !empty($this->verAplic)) { + $std->verAplic = $this->verAplic; + } + $tpEvento = self::EVT_CONCILIACAO; + $cod = UFList::getCodeByUF($this->config->siglaUF); + $tagAdic = "{$std->verAplic}"; + if (!empty($std->detPag) && is_array($std->detPag)) { + foreach ($std->detPag as $pag) { + $tagAdic .= $this->tagdetPag($pag); + } + } + //cancela um evento anterior de conciliação financeira + if ($std->cancela) { + $tpEvento = self::EVT_CANCELA_CONCILIACAO; + $tagAdic = "{$std->verAplic}" + . "{$std->protocolo}"; + } + return $this->sefazEvento( + 'AN', + $std->chNFe, + $tpEvento, + $std->nSeqEvento, + $tagAdic, + $dhEvento, + $lote + ); + } + /** * Send event to SEFAZ in batch * @param string $uf @@ -1059,6 +1101,8 @@ public function sefazEvento( self::EVT_EPEC => ['versao' => '1.00', 'nome' => 'envEPEC'], self::EVT_INSUCESSO_ENTREGA => ['versao' => '1.00', 'nome' => 'envEventoInsucessoNFe'], self::EVT_CANCELA_INSUCESSO_ENTREGA => ['versao' => '1.00', 'nome' => 'envEventoCancInsucessoNFe'], + self::EVT_CONCILIACAO => ['versao' => '1.00', 'nome' => 'envEventoEConf'], + self::EVT_CANCELA_CONCILIACAO => ['versao' => '1.00', 'nome' => 'envEventoCancEConf'], ]; $verEvento = $this->urlVersion; if (!empty($eventos[$tpEvento])) { @@ -1357,6 +1401,14 @@ private function tpEv(int $tpEvento): \stdClass $std->alias = 'EventoCancInsucessoNFe'; $std->desc = 'Cancelamento Insucesso na Entrega da NF-e'; break; + case self::EVT_CONCILIACAO: + $std->alias = 'EventoEConf'; + $std->desc = 'ECONF'; + break; + case self::EVT_CANCELA_CONCILIACAO: + $std->alias = 'EventoCancEConf'; + $std->desc = 'Cancelamento Conciliação Financeira'; + break; default: $msg = "O código do tipo de evento informado não corresponde a " . "nenhum evento estabelecido."; @@ -1364,4 +1416,95 @@ private function tpEv(int $tpEvento): \stdClass } return $std; } + + /** + * Cria detPag para Consciliação financeira + * @param \stdClass $pag + * @return false|string + * @throws \DOMException + */ + private function tagdetPag(\stdClass $pag) + { + $dom = new DOMImproved('1.0', 'UTF-8'); + $dom->preserveWhiteSpace = false; + $dom->formatOutput = false; + $node = $dom->createElement('detPag'); + $dom->addChild( + $node, + "indPag", + $pag->indPag ?? null, + false + ); + $dom->addChild( + $node, + "tPag", + $pag->tPag ?? '', + true + ); + $dom->addChild( + $node, + "xPag", + !empty($pag->xPag) ? Strings::replaceUnacceptableCharacters($pag->xPag) : null, + false + ); + $dom->addChild( + $node, + "vPag", + number_format($pag->vPag, 2, '.', ''), + true + ); + $dom->addChild( + $node, + "dPag", + $pag->dPag ?? '', + true + ); + if (!empty($pag->CNPJPag) && !empty($pag->UFPag)) { + $dom->addChild( + $node, + "CNPJPag", + $pag->CNPJPag, + true + ); + $dom->addChild( + $node, + "UFPag", + $pag->UFPag, + true + ); + $dom->addChild( + $node, + "CNPJIF", + $pag->CNPJIF ?? null, + false + ); + } + $dom->addChild( + $node, + "tBand", + $pag->tBand ?? null, + false + ); + $dom->addChild( + $node, + "cAut", + $pag->cAut ?? null, + false + ); + if (!empty($pag->CNPJReceb) && !empty($pag->UFReceb)) { + $dom->addChild( + $node, + "CNPJReceb", + $pag->CNPJReceb, + true + ); + $dom->addChild( + $node, + "UFReceb", + $pag->UFReceb, + true + ); + } + return $dom->saveXML($node); + } } From a2cf2b45831566fc5f3e30b19a9b42873ec7b815 Mon Sep 17 00:00:00 2001 From: Gustavo Mews Date: Mon, 28 Oct 2024 11:03:34 -0300 Subject: [PATCH 14/14] FIX_CRED_PRESUMIDO - Ajustes para gerar TAG's credPresumido sem cBenef --- src/Make.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Make.php b/src/Make.php index 2868d16c..01c8e88b 100755 --- a/src/Make.php +++ b/src/Make.php @@ -8048,10 +8048,6 @@ protected function buildDet() $it = 0; foreach ($this->aProdCreditoPresumido as $key => $cps) { $prod = $this->aProd[$key]; - $cBenef = $prod->getElementsByTagName("cBenef")->item(0); - if (empty($cBenef)) { - break; - } if (!empty($prod->getElementsByTagName("EXTIPI")->item(0))) { $node = $prod->getElementsByTagName("EXTIPI")->item(0); } else {