-
-
Save luizvaz/30c083573353073716e14ddbaa8a67fc to your computer and use it in GitHub Desktop.
| <?php | |
| /** | |
| * User: LuizVAz | |
| * Date: 26/09/2022 | |
| * Time: 12:46 | |
| */ | |
| class fiorilli_v001 | |
| { | |
| private $rps_id; | |
| private $rps_serie; | |
| private $usuario; | |
| private $senha; | |
| public function __construct(){ | |
| $this->rps_id = date('Ymd') . str_pad(time() - strtotime("today"), 5, '0'); | |
| $this->rps_serie = "3"; | |
| // As credenciais de homologação são sempre as mesmas | |
| // mas precisa solicitar para a Fiorilli a inscrição | |
| // municipal para ser usada no arquivo XML. | |
| $this->usuario = "01001001000113"; | |
| $this->senha = "123456"; | |
| } | |
| public function gerarNfse(): stdClass | |
| { | |
| //Live Mode | |
| $live = true; | |
| //Retorno | |
| $return = new stdClass(); | |
| $return->status = 500; | |
| $return->data = array("success" => false); | |
| $rps_dir = getcwd().DIRECTORY_SEPARATOR."xml".DIRECTORY_SEPARATOR."envio".DIRECTORY_SEPARATOR; | |
| $rps_id = $this->rps_id; | |
| // Homologação | |
| $url = 'http://fi1.fiorilli.com.br:5663/IssWeb-ejb/IssWebWS/IssWebWS?wsdl'; | |
| //rps_id | |
| $this->rps_id = "$rps_id"; | |
| //Garante que o diretório exista | |
| $fname = "${rps_dir}${rps_id}.xml"; | |
| if (!file_exists("${rps_dir}")) { | |
| mkdir("${rps_dir}", 0777, true); | |
| } | |
| //Usuário e Senha do portal | |
| $user = $this->usuario; | |
| $pass = $this->senha; | |
| $envelope = | |
| "<soapenv:Envelope \n". | |
| " xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \n". | |
| " xmlns:ws=\"http://ws.issweb.fiorilli.com.br/\">\n". | |
| " xmlns:xd=\"http://www.w3.org/2000/09/xmldsig#\"\n". | |
| " <soapenv:Header/>\n". | |
| " <soapenv:Body>\n". | |
| " <ws:gerarNfse>%DadosMsg%<username>$user</username><password>$pass</password></ws:gerarNfse>\n". | |
| " </soapenv:Body>\n". | |
| "</soapenv:Envelope>"; | |
| // Arquivo pronto | |
| $xml = file_get_contents(dirname($rps_dir)."\GerarNFSe.xml"); | |
| // Assinatura | |
| $xml = str_replace(array("\t"), '', $xml); | |
| $xml = $this->remove_accents($xml); | |
| // Não remover a formatação depois de assinado | |
| $xml = $this->assinaXML($xml, 'InfDeclaracaoPrestacaoServico'); | |
| file_put_contents("${rps_dir}${rps_id}.sign.xml", $xml); | |
| //Envio | |
| if ($live) { | |
| //Live Mode | |
| $envelope = str_replace('%DadosMsg%', $xml, $envelope); | |
| file_put_contents("${rps_dir}${rps_id}.soap", $envelope); | |
| $ret = $this->sendRequest($envelope, "http://ws.issweb.fiorilli.com.br/gerarNfse", $url); | |
| $html = $ret["html"]; | |
| $httpcode = $ret["code"]; | |
| $return->status = $httpcode; | |
| file_put_contents("$fname.ret", $html); | |
| } else { | |
| //Test Mode | |
| $fname = "${rps_dir}2022092719685.xml"; | |
| $html = file_get_contents("$fname.ret"); | |
| $return->status = $httpcode = 200; | |
| } | |
| // Converte de UTF-8 para ISO-8859 se necessário | |
| // $html = utf8_decode($html); | |
| if ($httpcode!=200){ | |
| preg_match_all('/<faultstring>(.*?)<\/faultstring>/s', html_entity_decode($html), $matches); | |
| $response = (count($matches)&&count($matches[1])?$matches[1][0]:$html); | |
| $return->data['errors'][] = [ | |
| "codigo" => $httpcode, | |
| "mensagem" => $response, | |
| "correcao" => "" | |
| ]; | |
| return $return; | |
| } | |
| //Extrai | |
| $return = $this->parseRetorno($html, $return); | |
| return $return; | |
| } | |
| function assinaXML($docxml, $tagid){ | |
| $URLdsig='http://www.w3.org/2000/09/xmldsig#'; | |
| $URLCanonMeth='http://www.w3.org/TR/2001/REC-xml-c14n-20010315'; | |
| $URLSigMeth='http://www.w3.org/2000/09/xmldsig#rsa-sha1'; | |
| $URLTransfMeth_1='http://www.w3.org/2000/09/xmldsig#enveloped-signature'; | |
| $URLTransfMeth_2='http://www.w3.org/TR/2001/REC-xml-c14n-20010315'; | |
| $URLDigestMeth='http://www.w3.org/2000/09/xmldsig#sha1'; | |
| try { | |
| //Certificado | |
| $crt_dir = getcwd().DIRECTORY_SEPARATOR.'cert'.DIRECTORY_SEPARATOR; | |
| $priKEY = "{$crt_dir}pkey.pem"; | |
| $keypass = file_get_contents("{$crt_dir}pass.txt"); | |
| $pubKEY = "{$crt_dir}cert.pem"; | |
| $xml = $docxml; | |
| // obter o chave privada para a ssinatura | |
| $prikeyid = openssl_pkey_get_private(file_get_contents($priKEY), $keypass); | |
| // limpeza do xml com a retirada dos CR, LF e TAB | |
| $order = array("\r\n", "\n", "\r", "\t"); | |
| $replace = ''; | |
| $xml = str_replace($order, $replace, $xml); | |
| // Habilita a manipulação de erros da libxml | |
| libxml_use_internal_errors(true); | |
| //limpar erros anteriores que possam estar em memória | |
| libxml_clear_errors(); | |
| // carrega o documento no DOM | |
| $xmldoc = new DOMDocument('1.0', 'utf-8'); | |
| $xmldoc->preservWhiteSpace = true; //elimina espaços em branco | |
| $xmldoc->formatOutput = false; | |
| // muito importante deixar ativadas as opções para limpar os espacos em branco | |
| // e as tags vazias | |
| if ($xmldoc->loadXML($xml, LIBXML_NOBLANKS | LIBXML_NOEMPTYTAG)) { | |
| $root = $xmldoc->documentElement; | |
| } else { | |
| $msg = "Erro ao carregar XML, provavel erro na passagem do parametro docxml ou no proprio xml!!"; | |
| $errors = libxml_get_errors(); | |
| if (!empty($errors)) { | |
| $i = 1; | |
| foreach ($errors as $error) { | |
| $msg .= "\n [$i]-" . trim($error->message); | |
| } | |
| libxml_clear_errors(); | |
| } | |
| throw new Exception($msg); | |
| } | |
| //extrair a tag com os dados a serem assinados | |
| $node = $xmldoc->getElementsByTagName($tagid)->item(0); | |
| if (!isset($node)) { | |
| $msg = "A tag < $tagid > não existe no XML!!"; | |
| throw new Exception($msg); | |
| } | |
| $id = trim($node->getAttribute("Id")); | |
| $idnome = preg_replace('/[^0-9]/', '', $id); | |
| //extrai os dados da tag para uma string | |
| $dados = $node->C14N(false, false, NULL, NULL); | |
| //calcular o hash dos dados | |
| $hashValue = hash('sha1', $dados, true); | |
| //converte o valor para base64 para serem colocados no xml | |
| $digValue = base64_encode($hashValue); | |
| //monta a tag da assinatura digital | |
| $Signature = $xmldoc->createElementNS($URLdsig, 'Signature'); | |
| //adiciona a assinatura | |
| $node->parentNode->appendChild($Signature); | |
| $SignedInfo = $xmldoc->createElement('SignedInfo'); | |
| $Signature->appendChild($SignedInfo); | |
| //Cannocalization | |
| $newNode = $xmldoc->createElement('CanonicalizationMethod'); | |
| $SignedInfo->appendChild($newNode); | |
| $newNode->setAttribute('Algorithm', $URLCanonMeth); | |
| //SignatureMethod | |
| $newNode = $xmldoc->createElement('SignatureMethod'); | |
| $SignedInfo->appendChild($newNode); | |
| $newNode->setAttribute('Algorithm', $URLSigMeth); | |
| //Reference | |
| $Reference = $xmldoc->createElement('Reference'); | |
| $SignedInfo->appendChild($Reference); | |
| $Reference->setAttribute('URI', '#' . $id); | |
| //Transforms | |
| $Transforms = $xmldoc->createElement('Transforms'); | |
| $Reference->appendChild($Transforms); | |
| //Transform | |
| $newNode = $xmldoc->createElement('Transform'); | |
| $Transforms->appendChild($newNode); | |
| $newNode->setAttribute('Algorithm', $URLTransfMeth_1); | |
| //Transform | |
| $newNode = $xmldoc->createElement('Transform'); | |
| $Transforms->appendChild($newNode); | |
| $newNode->setAttribute('Algorithm', $URLTransfMeth_2); | |
| //DigestMethod | |
| $newNode = $xmldoc->createElement('DigestMethod'); | |
| $Reference->appendChild($newNode); | |
| $newNode->setAttribute('Algorithm', $URLDigestMeth); | |
| //DigestValue | |
| $newNode = $xmldoc->createElement('DigestValue', $digValue); | |
| $Reference->appendChild($newNode); | |
| // extrai os dados a serem assinados para uma string | |
| $dados = $SignedInfo->C14N(false, false, NULL, NULL); | |
| //inicializa a variavel que irá receber a assinatura | |
| $signature = ''; | |
| //executa a assinatura digital usando o resource da chave privada | |
| $resp = openssl_sign($dados, $signature, $prikeyid); | |
| //codifica assinatura para o padrao base64 | |
| $signatureValue = base64_encode($signature); | |
| //SignatureValue | |
| $newNode = $xmldoc->createElement('SignatureValue', $signatureValue); | |
| $Signature->appendChild($newNode); | |
| //KeyInfo | |
| $KeyInfo = $xmldoc->createElement('KeyInfo'); | |
| $Signature->appendChild($KeyInfo); | |
| //X509Data | |
| $X509Data = $xmldoc->createElement('X509Data'); | |
| $KeyInfo->appendChild($X509Data); | |
| //carrega o certificado sem as tags de inicio e fim | |
| $cert = str_replace("\r", '', file_get_contents($pubKEY)); | |
| $cert = str_replace("\n", '', $cert); | |
| $cert = str_replace('-----BEGIN CERTIFICATE-----', '', $cert); | |
| $cert = wordwrap(trim(str_replace('-----END CERTIFICATE-----', '', $cert)), 64, "\n", true); | |
| //X509Certificate | |
| $newNode = $xmldoc->createElement('X509Certificate', $cert); | |
| $X509Data->appendChild($newNode); | |
| //grava na string o objeto DOM | |
| $xml = $xmldoc->saveXML($xmldoc->documentElement); | |
| // libera a memoria | |
| openssl_free_key($prikeyid); | |
| } catch (Exception $e) { | |
| throw $e; | |
| } | |
| //retorna o documento assinado | |
| return $xml; | |
| } //fim signXML | |
| public function parseRetorno($response, $return): stdClass | |
| { | |
| $dom = new DOMDocument(); | |
| $dom->preserveWhiteSpace = false; | |
| //Verifica falha ao processar XML de RETORNO | |
| if (@$dom->loadXML($response) === false){ | |
| //Retorno | |
| $return->data['errors'][] = [ | |
| "codigo" => "500", | |
| "mensagem" => "$response", | |
| "correcao" => "Contate o suporte!" | |
| ]; | |
| return $return; | |
| } | |
| $xp = new DOMXPath($dom); | |
| $xp->registerNamespace('soap', "http://schemas.xmlsoap.org/soap/envelope/"); | |
| $xp->registerNamespace('ns2', "http://www.abrasf.org.br/nfse.xsd"); | |
| $xp->registerNamespace('ns3', "http://ws.issweb.fiorilli.com.br/"); | |
| // MensagemRetorno | |
| $nodes = $xp->query("//ns2:MensagemRetorno"); | |
| if ($nodes->length != 0){ | |
| if (!array_key_exists('errors', $return->data)) | |
| $return->data['errors'] = []; | |
| for ($i = 0; $i<$nodes->length; $i++){ | |
| $msg = $nodes->item($i); | |
| //Tags | |
| $cod = $msg->getElementsByTagName("Codigo"); | |
| if ($cod->length>0) { | |
| $cod = $cod->item(0); | |
| $cod = $cod->nodeValue; | |
| if (strlen($cod)>5) $cod = "E00"; //Texto redundante | |
| } else | |
| $cod = "E00"; | |
| $txt = $msg->getElementsByTagName("Mensagem"); | |
| if ($txt->length>0) { | |
| $txt = $txt->item(0); | |
| $txt = $txt->nodeValue; | |
| } else | |
| $txt = ""; | |
| $cor = $msg->getElementsByTagName("Correcao"); | |
| if ($cor->length>0) { | |
| $cor = $cor->item(0); | |
| $cor = $cor->nodeValue; | |
| } else | |
| $cor = ""; | |
| //Retorno | |
| $return->data['errors'][] = [ | |
| "codigo" => $cod, | |
| "mensagem" => $txt, | |
| "correcao" => $cor | |
| ]; | |
| } | |
| return $return; | |
| } | |
| // Possui Nota | |
| $nodes = $xp->query("//ns2:CompNfse"); | |
| if ($nodes->length != 0) { | |
| $nfseId = ""; | |
| $msg = $nodes->item(0); | |
| $id = $msg->getElementsByTagName("InfNfse"); | |
| $id = ($id->length && ($id = $id->item(0)->getAttribute("Id")))?$id:$this->rps_id; | |
| $num = $msg->getElementsByTagName("Numero"); | |
| $num = ($num->length)?$num->item(0)->nodeValue:$this->rps_id; | |
| $cod = $msg->getElementsByTagName("CodigoVerificacao"); | |
| $cod = ($cod->length)?$cod->item(0)->nodeValue:"N/D"; | |
| $dat = $msg->getElementsByTagName("DataEmissao"); | |
| $dat = ($dat->length)?$dat->item(0)->nodeValue:""; | |
| $dat = str_ireplace(' ', 'T', $dat); | |
| $return->data['nfseId'] = $id; | |
| $return->data['numero'] = $num; | |
| $return->data['codigoVerificacao'] = $cod; | |
| $return->data['dataEmissao'] = $dat; | |
| $return->data['success'] = true; | |
| } | |
| return $return; | |
| } | |
| function remove_accents($string) { | |
| if ( !preg_match('/[\x80-\xff]/', $string) ) | |
| return $string; | |
| $chars = array( | |
| // Decompositions for Latin-1 Supplement | |
| chr(195).chr(128) => 'A', chr(195).chr(129) => 'A', | |
| chr(195).chr(130) => 'A', chr(195).chr(131) => 'A', | |
| chr(195).chr(132) => 'A', chr(195).chr(133) => 'A', | |
| chr(195).chr(135) => 'C', chr(195).chr(136) => 'E', | |
| chr(195).chr(137) => 'E', chr(195).chr(138) => 'E', | |
| chr(195).chr(139) => 'E', chr(195).chr(140) => 'I', | |
| chr(195).chr(141) => 'I', chr(195).chr(142) => 'I', | |
| chr(195).chr(143) => 'I', chr(195).chr(145) => 'N', | |
| chr(195).chr(146) => 'O', chr(195).chr(147) => 'O', | |
| chr(195).chr(148) => 'O', chr(195).chr(149) => 'O', | |
| chr(195).chr(150) => 'O', chr(195).chr(153) => 'U', | |
| chr(195).chr(154) => 'U', chr(195).chr(155) => 'U', | |
| chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y', | |
| chr(195).chr(159) => 's', chr(195).chr(160) => 'a', | |
| chr(195).chr(161) => 'a', chr(195).chr(162) => 'a', | |
| chr(195).chr(163) => 'a', chr(195).chr(164) => 'a', | |
| chr(195).chr(165) => 'a', chr(195).chr(167) => 'c', | |
| chr(195).chr(168) => 'e', chr(195).chr(169) => 'e', | |
| chr(195).chr(170) => 'e', chr(195).chr(171) => 'e', | |
| chr(195).chr(172) => 'i', chr(195).chr(173) => 'i', | |
| chr(195).chr(174) => 'i', chr(195).chr(175) => 'i', | |
| chr(195).chr(177) => 'n', chr(195).chr(178) => 'o', | |
| chr(195).chr(179) => 'o', chr(195).chr(180) => 'o', | |
| chr(195).chr(181) => 'o', chr(195).chr(182) => 'o', | |
| chr(195).chr(182) => 'o', chr(195).chr(185) => 'u', | |
| chr(195).chr(186) => 'u', chr(195).chr(187) => 'u', | |
| chr(195).chr(188) => 'u', chr(195).chr(189) => 'y', | |
| chr(195).chr(191) => 'y', | |
| // Decompositions for Latin Extended-A | |
| chr(196).chr(128) => 'A', chr(196).chr(129) => 'a', | |
| chr(196).chr(130) => 'A', chr(196).chr(131) => 'a', | |
| chr(196).chr(132) => 'A', chr(196).chr(133) => 'a', | |
| chr(196).chr(134) => 'C', chr(196).chr(135) => 'c', | |
| chr(196).chr(136) => 'C', chr(196).chr(137) => 'c', | |
| chr(196).chr(138) => 'C', chr(196).chr(139) => 'c', | |
| chr(196).chr(140) => 'C', chr(196).chr(141) => 'c', | |
| chr(196).chr(142) => 'D', chr(196).chr(143) => 'd', | |
| chr(196).chr(144) => 'D', chr(196).chr(145) => 'd', | |
| chr(196).chr(146) => 'E', chr(196).chr(147) => 'e', | |
| chr(196).chr(148) => 'E', chr(196).chr(149) => 'e', | |
| chr(196).chr(150) => 'E', chr(196).chr(151) => 'e', | |
| chr(196).chr(152) => 'E', chr(196).chr(153) => 'e', | |
| chr(196).chr(154) => 'E', chr(196).chr(155) => 'e', | |
| chr(196).chr(156) => 'G', chr(196).chr(157) => 'g', | |
| chr(196).chr(158) => 'G', chr(196).chr(159) => 'g', | |
| chr(196).chr(160) => 'G', chr(196).chr(161) => 'g', | |
| chr(196).chr(162) => 'G', chr(196).chr(163) => 'g', | |
| chr(196).chr(164) => 'H', chr(196).chr(165) => 'h', | |
| chr(196).chr(166) => 'H', chr(196).chr(167) => 'h', | |
| chr(196).chr(168) => 'I', chr(196).chr(169) => 'i', | |
| chr(196).chr(170) => 'I', chr(196).chr(171) => 'i', | |
| chr(196).chr(172) => 'I', chr(196).chr(173) => 'i', | |
| chr(196).chr(174) => 'I', chr(196).chr(175) => 'i', | |
| chr(196).chr(176) => 'I', chr(196).chr(177) => 'i', | |
| chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij', | |
| chr(196).chr(180) => 'J', chr(196).chr(181) => 'j', | |
| chr(196).chr(182) => 'K', chr(196).chr(183) => 'k', | |
| chr(196).chr(184) => 'k', chr(196).chr(185) => 'L', | |
| chr(196).chr(186) => 'l', chr(196).chr(187) => 'L', | |
| chr(196).chr(188) => 'l', chr(196).chr(189) => 'L', | |
| chr(196).chr(190) => 'l', chr(196).chr(191) => 'L', | |
| chr(197).chr(128) => 'l', chr(197).chr(129) => 'L', | |
| chr(197).chr(130) => 'l', chr(197).chr(131) => 'N', | |
| chr(197).chr(132) => 'n', chr(197).chr(133) => 'N', | |
| chr(197).chr(134) => 'n', chr(197).chr(135) => 'N', | |
| chr(197).chr(136) => 'n', chr(197).chr(137) => 'N', | |
| chr(197).chr(138) => 'n', chr(197).chr(139) => 'N', | |
| chr(197).chr(140) => 'O', chr(197).chr(141) => 'o', | |
| chr(197).chr(142) => 'O', chr(197).chr(143) => 'o', | |
| chr(197).chr(144) => 'O', chr(197).chr(145) => 'o', | |
| chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe', | |
| chr(197).chr(148) => 'R',chr(197).chr(149) => 'r', | |
| chr(197).chr(150) => 'R',chr(197).chr(151) => 'r', | |
| chr(197).chr(152) => 'R',chr(197).chr(153) => 'r', | |
| chr(197).chr(154) => 'S',chr(197).chr(155) => 's', | |
| chr(197).chr(156) => 'S',chr(197).chr(157) => 's', | |
| chr(197).chr(158) => 'S',chr(197).chr(159) => 's', | |
| chr(197).chr(160) => 'S', chr(197).chr(161) => 's', | |
| chr(197).chr(162) => 'T', chr(197).chr(163) => 't', | |
| chr(197).chr(164) => 'T', chr(197).chr(165) => 't', | |
| chr(197).chr(166) => 'T', chr(197).chr(167) => 't', | |
| chr(197).chr(168) => 'U', chr(197).chr(169) => 'u', | |
| chr(197).chr(170) => 'U', chr(197).chr(171) => 'u', | |
| chr(197).chr(172) => 'U', chr(197).chr(173) => 'u', | |
| chr(197).chr(174) => 'U', chr(197).chr(175) => 'u', | |
| chr(197).chr(176) => 'U', chr(197).chr(177) => 'u', | |
| chr(197).chr(178) => 'U', chr(197).chr(179) => 'u', | |
| chr(197).chr(180) => 'W', chr(197).chr(181) => 'w', | |
| chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y', | |
| chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z', | |
| chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z', | |
| chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z', | |
| chr(197).chr(190) => 'z', chr(197).chr(191) => 's' | |
| ); | |
| $string = strtr($string, $chars); | |
| return $string; | |
| } | |
| public function sendRequest(string $envelope, string $action, string $url): array | |
| { | |
| $headers = array( | |
| "Content-type: text/xml;charset=UTF-8", | |
| "Accept-Encoding: gzip,deflate", | |
| "SOAPAction: \"$action\"", | |
| "Content-length: " . strlen($envelope), | |
| ); | |
| $ch = curl_init(); | |
| curl_setopt($ch, CURLOPT_URL, $url); | |
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
| curl_setopt($ch, CURLOPT_TIMEOUT, 300); | |
| curl_setopt($ch, CURLOPT_POST, true); | |
| curl_setopt($ch, CURLOPT_POSTFIELDS, $envelope); | |
| curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); | |
| curl_setopt($ch, CURLOPT_ENCODING, "identity, deflate, gzip"); | |
| //Usar proxy se a prefeitura bloquear IPs estrangeiros | |
| //$proxy = '200.255.122.174:8080'; | |
| //curl_setopt($ch, CURLOPT_PROXY, $proxy); | |
| //curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); | |
| $html = curl_exec($ch); | |
| // Converte de UTF-8 para ISO-8859 | |
| $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
| curl_close($ch); | |
| return [ | |
| "html" => $html, | |
| "code" => $httpcode | |
| ]; | |
| } | |
| } |
É possível gerar nfse nesse mesmo padrão mas com o campo DataEmissao com data e hora? quando eu uso o formato data e hora no xml dá erro de assinatura.
No schema nfse.xsd da Fiorilli o formato do campo DataEmissao está como:
<xsd:element name="DataEmissao" type="xsd:dateTime" minOccurs="1" maxOccurs="1" />
O tipo xsd:dateTime possui aceita seguinte formato:
2022-12-15T08:50:1
Só que atualmente depende de como a empresa está tratando o campo.
Vi que foi enviado como <DataEmissao>2022-09-26</DataEmissao>
Tente fazer o teste, usando o formato.
Se não funcionar, infelizmente não aceita mesmo.
Quando eu coloco essa data, retorna esse erro:
array(2) {
["success"]=>
bool(false)
["errors"]=>
array(1) {
[0]=>
array(3) {
["codigo"]=>
int(500)
["mensagem"]=>
string(40) "Unmarshalling Error: 2022-12-15T08:50:1 "
["correcao"]=>
string(0) ""
}
}
}
Realmente não aceita então?
Na verdade, o campo DataEmissao dentro da tag rps só aceita date mesmo. O que aceita dateTime é o dentro da tag Infse mas esse campo é gerado automaticamente, como posso alterar ela?
Esse é o arquivo XML usado no envio:
GerarNFSe.xml