-
-
Save luizvaz/6c3e2c1e6bc7d310898107c9f95476bb to your computer and use it in GitHub Desktop.
<?php | |
/** | |
* User: LuizVAz | |
* Date: 28/02/2021 | |
* Time: 19:46 | |
*/ | |
namespace Provedores\webService; | |
use DOMDocument; | |
use DOMXPath; | |
use Exception; | |
use RobRichards\XMLSecLibs\XMLSecEnc; | |
use RobRichards\XMLSecLibs\XMLSecurityDSig; | |
use RobRichards\XMLSecLibs\XMLSecurityKey; | |
use Slim\App; | |
use Slim\Http\Request; | |
use Slim\Http\Response; | |
use stdClass; | |
class smarapd_v001 extends \Provedores\webService\webService | |
{ | |
private $cnpj; | |
private $dir; | |
private $nfs_dir; | |
private $rps_dir; | |
protected $rps_id; | |
protected $rps_serie; | |
private $user; | |
public function __construct(Request $request, Response $response, App $app){ | |
parent::__construct($request, $response, $app); | |
$ym = date('Ym'); | |
$this->dir = $dir = getenv('BASE_PATH'); | |
$this->user = "your_code"; | |
$this->cnpj = "your_code"; | |
$this->inscricaoMunicipal = "your_code"; | |
$this->rps_dir = "$dir/$cnpj/rps/$ym/"; | |
$this->nfs_dir = "$dir/$cnpj/nfse/$ym/"; | |
$this->rps_id = date('Ymd') . str_pad(time() - strtotime("today"), 5, '0'); | |
$this->rps_serie = "ws1"; | |
} | |
public function consultar(stdClass $rps){ | |
$this->rps = $rps; | |
return $this->consultaNFsePorRps(); | |
} | |
public function consultaNFsePorRps(): stdClass | |
{ | |
// Retorno | |
$return = new stdClass(); | |
$return->status = 500; | |
$return->data = array("success" => false); | |
// Parametros | |
$rps_numero = $this->rps_id; | |
$rps_serie = $this->rps_serie; | |
$rps_tipo = "1"; | |
$rps_cnpj = $this->cnpj; | |
$rps_im = $this->inscricaoMunicipal; | |
$envelope = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> | |
<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:nfse=\"http://nfse.abrasf.org.br\"> | |
<soapenv:Header/> | |
<soapenv:Body> | |
<nfse:consultarNfsePorRps> | |
<xml><![CDATA[<?xml version=\"1.0\" encoding=\"UTF-8\"?> | |
<ConsultarNfseRpsEnvio xmlns=\"http://www.abrasf.org.br/nfse.xsd\"> | |
<IdentificacaoRps> | |
<Numero>$rps_numero</Numero> | |
<Serie>$rps_serie</Serie> | |
<Tipo>$rps_tipo</Tipo> | |
</IdentificacaoRps> | |
<Prestador> | |
<CpfCnpj> | |
<Cnpj>$rps_cnpj</Cnpj> | |
</CpfCnpj> | |
<InscricaoMunicipal>$rps_im</InscricaoMunicipal> | |
</Prestador> | |
</ConsultarNfseRpsEnvio>]]></xml> | |
</nfse:consultarNfsePorRps> | |
</soapenv:Body> | |
</soapenv:Envelope>"; | |
$url = $this->end_prod; | |
if ($this->rps->ambienteEmissao && (strtolower($this->rps->ambienteEmissao) === "homologacao")){ | |
$url = $this->end_homo; | |
} | |
$ret = $this->sendRequest($envelope, "", $url); | |
$html = $ret['html']; | |
$httpcode = $ret['code']; | |
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 Retorno SOAP | |
preg_match_all('/<return>(.*?)<\/return>/s', html_entity_decode($html), $matches); | |
$response = (count($matches)&&count($matches[1])?$matches[1][0]:$html); | |
// Parse | |
$return->status = $httpcode; | |
$this->parseRetorno($response, $return); | |
return $return; | |
} | |
public function emitir(stdClass $rps){ | |
$this->rps = $rps; | |
return $this->gerarNfse(); | |
} | |
public function gerarNfse(): stdClass | |
{ | |
//Live Mode | |
$live = true; | |
//Retorno | |
$return = new stdClass(); | |
$return->status = 500; | |
$return->data = array("success" => false); | |
$rps_dir = $this->rps_dir; | |
//rps_id ou idExterno | |
$rps_id = (property_exists($this->rps, 'idExterno'))?$this->rps->idExterno:$this->rps_id; | |
if (!$rps_id){ | |
$rps_id = date('Ymd') . str_pad(time() - strtotime("today"), 5, '0'); | |
$this->rps_id = $rps_id; | |
} else | |
$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); | |
} | |
$envelope = | |
"<soapenv:Envelope ". | |
" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" ". | |
" xmlns:nfse=\"http://nfse.abrasf.org.br\">". | |
" <soapenv:Header/>". | |
" <soapenv:Body>". | |
" <nfse:recepcionarLoteRpsSincrono>". | |
" <xml><![CDATA[%DadosMsg%]]></xml>". | |
" </nfse:recepcionarLoteRpsSincrono>". | |
" </soapenv:Body>". | |
"</soapenv:Envelope>"; | |
//Ambiente: 1 = Produção, 2 = Homologação | |
$amb = '1'; | |
if ($this->rps->ambienteEmissao && (strtolower($this->rps->ambienteEmissao) === "homologacao")){ | |
$amb = '2'; | |
} | |
if ($live) { | |
//xml | |
$xml = $this->rpsAsXML(); | |
/* $xml = str_ireplace('<?xml version="1.0" encoding="utf-8"?>', '', $xml); */ | |
file_put_contents("$fname", $xml); | |
//$cab = htmlentities($cab, ENT_XML1 | ENT_NOQUOTES); | |
//$xml = htmlentities($xml, ENT_XML1 | ENT_NOQUOTES); | |
//$envelope = str_replace('%CabMsg%', $cab, $envelope); | |
$envelope = str_replace('%DadosMsg%', $xml, $envelope); | |
file_put_contents("${rps_dir}${rps_id}.soap", $envelope); | |
} | |
if ($live) { | |
//Live Mode | |
$url = $this->end_prod; | |
if ($this->rps->ambienteEmissao && (strtolower($this->rps->ambienteEmissao) === "homologacao")){ | |
$url = $this->end_homo; | |
} | |
$ret = $this->sendRequest($envelope, "", $url); | |
$html = $ret["html"]; | |
// Converte de UTF-8 para ISO-8859 | |
//$html = utf8_decode(curl_exec($ch)); | |
$httpcode = $ret["code"]; | |
$return->status = $httpcode; | |
file_put_contents("$fname.ret", $html); | |
$html = utf8_decode($html); //Converter Depois de Salvo | |
} else { | |
//Test Mode | |
$httpcode = 200; | |
$return->status = $httpcode; | |
$html = file_get_contents("$fname.ret"); | |
} | |
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 | |
preg_match_all('/<return>(.*?)<\/return>/s', html_entity_decode($html), $matches); | |
$response = (count($matches)&&count($matches[1])?$matches[1][0]:$html); | |
$return = $this->parseRetorno($response, $return); | |
return $return; | |
} | |
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('fake', "http://nfse.abrasf.org.br"); | |
// /retornoNfseLote/errors/erro | |
$nodes = $xp->query("/*/*/*[name()='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; | |
} | |
// Resposta EnviarLoteRpsSincrono | |
$nodes = $xp->query("/*[name()='EnviarLoteRpsSincronoResposta']"); | |
if ($nodes->length != 0){ | |
$nfseId = ""; | |
$msg = $nodes->item(0); | |
$proto = $msg->getElementsByTagName("Protocolo"); | |
$proto = ($proto->length>0)?$proto = $proto->item(0)->nodeValue:"0"; | |
$return->data['protocolo'] = $proto; | |
$lote = $msg->getElementsByTagName("NumeroLote"); | |
$lote = ($lote->length>0)?$lote = $lote->item(0)->nodeValue:"0"; | |
$return->data['numeroLote'] = $lote; | |
// Consulta por Lote não funciona | |
// Precisa pegar pelo RPS | |
$return = $this->consultaNFsePorRps(); | |
// Pussui Erros | |
if (array_key_exists('errors', $return->data)){ | |
return $return; | |
} | |
// Salva Retorno | |
$num = $return->data["numero"]; | |
$nfs_dir = $this->nfs_dir; | |
$fname = "${nfs_dir}${num}.xml"; | |
if (!file_exists(dirname("$fname"))) { | |
mkdir(dirname("$fname"), 0777, true); | |
} | |
file_put_contents($fname, $msg->ownerDocument->saveXML()); | |
$return->data['success'] = true; | |
} | |
// Possui Nota | |
$nodes = $xp->query("//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; | |
} | |
public function rpsAsXML() | |
{ | |
//DOM | |
$dom = new DOMDocument('1.0', 'utf-8'); | |
$dom->formatOutput = true; | |
$dom->preserveWhiteSpace = true; | |
$dom->appendChild($enviarLoteRpsSincronoEnvio = $dom->createElement("EnviarLoteRpsSincronoEnvio")); | |
$enviarLoteRpsSincronoEnvio->setAttribute("xmlns", "http://www.abrasf.org.br/nfse.xsd"); | |
// LoteRps | |
$enviarLoteRpsSincronoEnvio->appendChild($loteRps = $dom->createElement("LoteRps")); | |
$loteId = date('Ymd') . str_pad(time() - strtotime("today"), 5, '0'); | |
$loteRps->setAttribute("versao", "2.03"); | |
$loteRps->setAttribute("Id", "$loteId"); | |
$loteRps->appendChild( $dom->createElement("NumeroLote", "$loteId")); | |
$loteRps->appendChild( $cpfCnpj = $dom->createElement("CpfCnpj")); | |
$cpfCnpj->appendChild( $dom->createElement("Cnpj", $this->conf->cnpj)); | |
$loteRps->appendChild( $dom->createElement("InscricaoMunicipal", $this->conf->inscricaoMunicipal)); | |
$loteRps->appendChild( $dom->createElement("QuantidadeRps", "1")); | |
// ListaRps | |
$loteRps->appendChild( $listaRps = $dom->createElement("ListaRps")); | |
//Rps | |
$listaRps->appendChild( $rps1 = $dom->createElement("Rps")); | |
//InfDeclaracaoPrestacaoServico | |
$rps1->appendChild( $infDec = $dom->createElement("InfDeclaracaoPrestacaoServico")); | |
$infDec->setAttribute("Id", "A".$this->rps_id); | |
//Rps | |
$infDec->appendChild( $rps2 = $dom->createElement("Rps")); | |
$rps2->setAttribute("Id", "B".$this->rps_id); | |
//IdentificacaoRps | |
$rps2->appendChild( $identificacaoRps = $dom->createElement("IdentificacaoRps")); | |
$identificacaoRps->appendChild($dom->createElement("Numero",$this->rps_id)); | |
$identificacaoRps->appendChild($dom->createElement("Serie",$this->rps_serie)); | |
$identificacaoRps->appendChild($dom->createElement("Tipo","1")); | |
//Formato yyyy-mm-dd | |
$dataEmissao = date("Y-m-d"); | |
if ($this->rps->dataEmissao){ | |
$dataEmissao = new \DateTime($this->rps->dataEmissao); | |
$dataEmissao = $dataEmissao->format('Y-m-d'); | |
} | |
//DataEmissao | |
$rps2->appendChild($dom->createElement("DataEmissao",$dataEmissao)); | |
//Status | |
$rps2->appendChild($dom->createElement("Status","1")); | |
//Competencia | |
$infDec->appendChild($dom->createElement("Competencia",$dataEmissao)); | |
//Servico | |
$servico = $dom->createElement("Servico"); | |
//Valores | |
$valores = $dom->createElement("Valores"); | |
$valorTotal = 0.00; | |
$valor = (property_exists($this->rps->servico, 'valorServicos')?0.00+$this->rps->servico->valorServicos:0); | |
if (!$valor) | |
$valor = (property_exists($this->rps, 'valorTotal')?0.00+$this->rps->valorTotal:0); | |
if ($valor == 0) | |
throw new Exception("Informação servico->valorServicos não informada."); | |
$valores->appendChild( | |
$dom->createElement("ValorServicos", $this->formatValor($valor)) | |
); | |
$valorTotal += $valor; | |
$valor = (property_exists($this->rps->servico, 'valorDeducoes')?0.00+$this->rps->servico->valorDeducoes:0); | |
if ($valor) | |
$valores->appendChild( | |
$dom->createElement("ValorDeducoes", $this->formatValor($valor)) | |
); | |
$valorTotal -= $valor; | |
$aliquotaIss = 0; | |
if (property_exists($this->rps->servico, 'aliquotaIss')) | |
$aliquotaIss = 0.00+$this->rps->servico->aliquotaIss; | |
if ($aliquotaIss == 0) | |
if (property_exists($this->rps->servico, 'aliquota')) | |
$aliquotaIss = 0.00+$this->rps->servico->aliquota; | |
if ($aliquotaIss == 0) | |
throw new Exception("Informação aliquotaIss não encontrada."); | |
$valorIss = round($valorTotal * $aliquotaIss, 2, PHP_ROUND_HALF_EVEN); | |
$valores->appendChild($dom->createElement("ValorIss", $this->formatValor($valorIss*1))); | |
$valores->appendChild($dom->createElement("Aliquota", $this->formatValor($aliquotaIss*100))); | |
$servico->appendChild($valores); | |
//Servico | |
//issRetido | |
$issRetido = (property_exists($this->rps, 'issRetidoFonte')?$this->rps->issRetidoFonte:false); | |
$servico->appendChild($dom->createElement("IssRetido", $issRetido?'1':'2')); | |
//itemListaServicoLC116 | |
$itemListaServico = (property_exists($this->rps, 'itemListaServicoLC116')?$this->rps->itemListaServicoLC116:false); | |
if (!$itemListaServico) | |
$itemListaServico = (property_exists($this->rps->servico, 'itemListaServico')?$this->rps->servico->itemListaServico:false); | |
if (!$itemListaServico) | |
$itemListaServico = $this->conf->itemListaServicoLC116; | |
$servico->appendChild($dom->createElement("ItemListaServico", $itemListaServico)); | |
//cnae | |
/* | |
$cnae = (property_exists($this->rps, 'cnae')?$this->rps->cnae:false); | |
if (!$cnae) | |
$cnae = $this->conf->cnae; | |
$servico->appendChild($dom->createElement("CodigoCnae", $cnae)); | |
*/ | |
//codigoTributacaoMunicipio | |
$codigoTributacaoMunicipio = (property_exists($this->rps->servico, 'codigoTributacaoMunicipio')?$this->rps->servico->codigoTributacaoMunicipio:false); | |
if ($codigoTributacaoMunicipio) | |
$servico->appendChild($dom->createElement("CodigoTributacaoMunicipio", $codigoTributacaoMunicipio)); | |
//descricao | |
$descricao = (property_exists($this->rps->servico, 'discriminacao')?$this->rps->servico->discriminacao:""); | |
if (!$descricao) | |
$descricao = (property_exists($this->rps->servico, 'descricao')?$this->rps->servico->descricao:""); | |
if (!$descricao) | |
$descricao = $this->conf->descricaoServico; | |
$observacao = (property_exists($this->rps->servico, 'observacao')?$this->rps->servico->observacao:""); | |
$descricao = ($descricao) ? "$descricao\n$observacao" : $observacao; | |
if ($descricao) { | |
// Essa limpeza será feita logo abaixo | |
//$descricao = str_replace(array("\r\n", "\r", "\n", "\t"), "", $descricao); | |
//$descricao = $this->remove_accents($descricao); | |
$servico->appendChild($dom->createElement("Discriminacao", $descricao)); | |
} | |
//codigoMunicipio | |
$codigoMunicipio = (property_exists($this->rps->servico, 'codigoMunicipio')?$this->rps->servico->codigoMunicipio:0); | |
if (!$codigoMunicipio) | |
$codigoMunicipio = $this->conf->endereco->codigoIbgeCidade; | |
$servico->appendChild($dom->createElement("CodigoMunicipio", $codigoMunicipio)); | |
//exigibilidadeISS | |
$servico->appendChild($dom->createElement("ExigibilidadeISS", "1")); | |
//municipioIncidencia | |
$municipioIncidencia = (property_exists($this->rps->servico, 'municipioPrestacaoServico')?$this->rps->servico->municipioPrestacaoServico:0); | |
if (!$municipioIncidencia) | |
$municipioIncidencia = $codigoMunicipio; | |
$servico->appendChild($dom->createElement("MunicipioIncidencia", $municipioIncidencia)); | |
$infDec->appendChild($servico); | |
//prestador | |
$infDec->appendChild($prestador = $dom->createElement("Prestador")); | |
$cpfCnpj = $dom->createElement("CpfCnpj"); | |
$cnpj = $dom->createElement("Cnpj", $this->conf->cnpj); | |
$cpfCnpj->appendChild($cnpj); | |
$prestador->appendChild($cpfCnpj); | |
$im = $dom->createElement("InscricaoMunicipal", $this->conf->inscricaoMunicipal); | |
$prestador->appendChild($im); | |
//Tomador | |
$infDec->appendChild($tomador = $dom->createElement("Tomador")); | |
$identificacaoTomador = $dom->createElement("IdentificacaoTomador"); | |
$cpfCnpj = $dom->createElement("CpfCnpj"); | |
$doc = null; | |
$temp = (property_exists($this->rps->cliente, 'cpfCnpj')?$this->rps->cliente->cpfCnpj:""); | |
if (strlen($temp)==14) | |
$doc = $dom->createElement("Cnpj", $this->rps->cliente->cpfCnpj); | |
elseif (strlen($temp)==11) | |
$doc = $dom->createElement("Cpf", $this->rps->cliente->cpfCnpj); | |
if ($doc){ | |
$cpfCnpj->appendChild($doc); | |
$identificacaoTomador->appendChild($cpfCnpj); | |
} | |
if (property_exists($this->rps->cliente, 'inscricaoMunicipal')){ | |
$doc = $dom->createElement('InscricaoMunicipal', $this->rps->cliente->inscricaoMunicipal); | |
$identificacaoTomador->appendChild($doc); | |
} | |
$tomador->appendChild($identificacaoTomador); | |
$temp = (property_exists($this->rps->cliente, 'nome')?$this->rps->cliente->nome:""); | |
if (!$temp) | |
$temp = (property_exists($this->rps->cliente, 'razaoSocial')?$this->rps->cliente->razaoSocial:""); | |
if ($temp) | |
$tomador->appendChild($dom->createElement("RazaoSocial", $temp)); | |
//Endereço | |
$endereco = $dom->createElement("Endereco"); | |
$temp = (property_exists($this->rps->cliente->endereco, 'logradouro')?$this->rps->cliente->endereco->logradouro:""); | |
if ($temp) | |
$endereco->appendChild($dom->createElement("Endereco", $temp)); | |
$temp = (property_exists($this->rps->cliente->endereco, 'numero')?$this->rps->cliente->endereco->numero:""); | |
if ($temp) | |
$endereco->appendChild($dom->createElement("Numero", $temp)); | |
$temp = (property_exists($this->rps->cliente->endereco, 'bairro')?$this->rps->cliente->endereco->bairro:""); | |
if ($temp) | |
$endereco->appendChild($dom->createElement("Bairro", $temp)); | |
$temp = (property_exists($this->rps->cliente->endereco, 'cidade')?$this->rps->cliente->endereco->cidade:""); | |
if (!$temp) | |
$temp = (property_exists($this->rps->cliente->endereco, 'codigoMunicipio')?$this->rps->cliente->endereco->codigoMunicipio:""); | |
if ($temp) | |
$endereco->appendChild($dom->createElement("CodigoMunicipio", $temp)); | |
$temp = (property_exists($this->rps->cliente->endereco, 'UF')?$this->rps->cliente->endereco->UF:""); | |
if ($temp) | |
$endereco->appendChild($dom->createElement("Uf", $temp)); | |
$temp = (property_exists($this->rps->cliente->endereco, 'CEP')?$this->rps->cliente->endereco->CEP:""); | |
if ($temp) | |
$endereco->appendChild($dom->createElement("Cep", $temp)); | |
if ($endereco->childNodes->length > 0) | |
$tomador->appendChild($endereco); | |
//Contato | |
$contato = $dom->createElement("Contato"); | |
$temp = (property_exists($this->rps->cliente, 'telefone')?$this->rps->cliente->telefone:""); | |
if ($temp) | |
$contato->appendChild($dom->createElement("Telefone", $temp)); | |
$temp = (property_exists($this->rps->cliente, 'email')?$this->rps->cliente->email:""); | |
if ($temp) | |
$contato->appendChild($dom->createElement("Email", $temp)); | |
if ($tomador->childNodes->length > 0) | |
$tomador->appendChild($contato); | |
//RegimeEspecialTributacao | |
if ($this->conf->regimeEspecialTributacao) | |
$infDec->appendChild($dom->createElement("RegimeEspecialTributacao", $this->conf->regimeEspecialTributacao)); | |
//OptanteSimplesNacional | |
$infDec->appendChild($dom->createElement("OptanteSimplesNacional", $this->conf->optanteSimplesNacional?'1':'2')); | |
$infDec->appendChild($dom->createElement("IncentivoFiscal", $this->conf->incentivadorCultural?'1':'2')); | |
//Retorna o RPS em formato XML | |
// limpeza do xml com a retirada dos TAB e Acentos | |
$decl = str_replace(array("\t"), '', $dom->saveXML()); | |
$decl = $this->remove_accents($decl); | |
// Não remover a formatação depois de assinado | |
$decl = $this->assinaXML($decl, 'InfDeclaracaoPrestacaoServico'); | |
$decl = str_ireplace('<?xml version="1.0" encoding="UTF-8"?>', '', $decl); | |
$lote = $this->assinaXML($decl, 'LoteRps'); | |
return $lote; | |
} | |
function assinaXML($docxml, $tag){ | |
try { | |
$tagid = $tag; | |
$crt_dir = dirname(dirname($this->rps_dir)) . '/cert'; | |
$priKEY = "$crt_dir/pkey.pem"; | |
$keypass = file_get_contents("$crt_dir/pass.txt"); | |
$pubKEY = "$crt_dir/cert.pem"; | |
// 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($docxml, LIBXML_NOBLANKS | LIBXML_NOXMLDECL | LIBXML_BIGLINES)) { | |
$msg = "Erro ao carregar XML, provavel erro 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 | |
$xpath = new DOMXPath($xmldoc); | |
$xpath->registerNamespace('ns', "http://www.abrasf.org.br/nfse.xsd"); | |
$node = $xpath->query("//ns:{$tagid}")->item(0); | |
if (!isset($node)) { | |
$msg = "A tag <$tagid> não existe no XML!!"; | |
throw new Exception($msg); | |
} | |
// Cria novo Security object | |
$objDSig = new XMLSecurityDSig(''); | |
// Usa a c14n exclusive canonicalization | |
$objDSig->setCanonicalMethod(XMLSecurityDSig::C14N); | |
// Assina usando SHA-1 | |
$objDSig->addReference( | |
$node, | |
XMLSecurityDSig::SHA1, | |
[ | |
"http://www.w3.org/2000/09/xmldsig#enveloped-signature", | |
"http://www.w3.org/TR/2001/REC-xml-c14n-20010315" | |
], | |
[ | |
'id_name' => 'Id', | |
'overwrite' => false | |
] | |
); | |
// Cria nova (private) Security key | |
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); | |
$objKey->passphrase = "$keypass"; | |
$objKey->loadKey("$priKEY", TRUE); | |
// Assina o XML | |
$objDSig->sign($objKey); | |
// Adiciona a public key para a signature | |
$objDSig->add509Cert(file_get_contents("$pubKEY")); | |
// Acrescenta a signature para o XML | |
$objDSig->appendSignature($node->parentNode); | |
$objDSig = null; | |
//grava na string o objeto DOM | |
$xml = $xmldoc->saveXML(); | |
} catch (Exception $e) { | |
throw $e; | |
} | |
//retorna o documento assinado | |
return $xml; | |
} //fim signXML | |
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"); | |
//A prefeitura bloqueia os IPs externos | |
//$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 | |
//$html = utf8_decode(curl_exec($ch)); | |
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
curl_close($ch); | |
return [ | |
"html" => $html, | |
"code" => $httpcode | |
]; | |
} | |
} |
Eu também tive esse erro.
Verifica o tópico em:
https://comunidade.opennfse.com.br/t/padrao-smarapd-2-03-vila-velha-es-3205200/583
Luiz;
O envio sincrono foi obtido com sucesso, mas nenhuma consulta em modo de homologação retorna os documentos.
Essas consultas não localizam NADA !! e sempre retornam documento não localizado.
Está assim também em produção ??
Agradeço muito sua resposta meu amigo !
Em produção está OK.
Em homologação não adianda esperar muita coisa
Olá, Luiz tudo bem!
Estou integrando em minha aplicação Mogi das Cruzes o padão é o mesmo, como deve proceder com seu código.
Obrigado!
É só alterar rpsAsXML() de acordo com a sua necessidade, colocando as tags que não estão presentes que você precise.
Pode retirar o extends \Provedores\webService\webService
.
Basta chamar o gerarNfse() para gerar uma nova nota.
Note que eu uso alguns valores de uma propriedade rps, basta preencher essas propriedades usando um objeto stdClass.
Obrigado Luiz.!!
Abraço
Cara, você pode me ajudar com um projeto em que estou trabalhando? Por favor
Oi.
Preciso emitir notas pelo município de Viamão/RS, que usa o padrão ABRASF.
Baixei o teu código, fiz umas atualizações, porque o PHP não aceitou algumas coisas, removi o extends, mas parei em um erro:
Fatal error: Cannot use "parent" when current class scope has no parent in D:\Dropbox\www\nfse\smarapd_203.php on line 32
Tem algo que possa ser feito para resolver isso?
Luiz;
Estou usando o método gerarNFse (Vila Velha) e está retornando o erro javax.xml.crypto.URIReferenceException com referencia ao Id do Rps
Você pode compartilhar um xml de geração que tenha passado ?