Quirinopolis/GO - 5218508 - Ajuda envio em php

Bom dia, acabo de me cadastrar, fui indicado a colocar a abri um tópico aqui coso tivesse um problema.

minha pergunta era quanto a fazer a integração em php pra um servidor e o Luiz Vaz me respondeu com a url correta: http://servicos.quirinopolis.go.gov.br:8115/prodataws/services/NfseWSService?wsdl

mandou o exemplo de SOAP de envio e o cabeçalho.

baseado no que foi passado eu fiz um exemplo:

        $xmlEnvio = new DOMDocument("1.0");		
        //Carrega o xml a ser assinado
        $xmlEnvio->load($arquivoRPSAssinado);
        //Carrega o conteudo do XML
        $XmlAssinado = $xmlEnvio->saveXML();
        $cabecalho = '<cabecalho versao="2.01" xmlns="http://www.abrasf.org.br/nfse.xsd"><versaoDados>2.01</versaoDados></cabecalho>';
        $envelope = '<?xml version="1.0" encoding="UTF-8"?>
            <x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.nfse">
            <x:Header/>
            <x:Body>
               <ser:RecepcionarLoteRpsRequest>
                   <nfseCabecMsg>'.$cabecalho.'</nfseCabecMsg>
                   <nfseDadosMsg>'.$XmlAssinado.'</nfseDadosMsg>
               </ser:RecepcionarLoteRpsRequest>
            </x:Body>
            </x:Envelope>';
        
        $url = 'http://servicos.quirinopolis.go.gov.br:8115/prodataws/services/NfseWSService?wsdl';
        $options = array(
            'location' => $url
        );
        
        $param = array("arg0"=>$envelope);
        
        try {
            $SoapClient = new SoapClient($url, $options);
            $objRetorno = $SoapClient->__soapCall('RecepcionarLoteRps', $param); 
            return $objRetorno;
        } catch (SoapFault $ex) {
            echo 'Falha no SOAP: ' . '[' . $ex->getCode() . '] ' . $ex->getMessage() . '<br>';
            echo '<pre>';
            var_dump($ex);
            echo '</pre>';
        };

quando dou o __soapCall(‘RecepcionarLoteRps’, $param) me mostra o erro

org.apache.axis2.databinding.ADBException: Unexpected subelement {http://services.nfse}RecepcionarLoteRpsRequest

quando dou o __soapCall(‘RecepcionarLoteRps’, $param) me mostra o erro

Function ("RecepcionarLoteRpsRequest") is not a valid method for this service

é a primeira vez estou fazendo essa transmissão de xml por isso estou sofrendo e enchendo tanto.

Grato pela ajuda.

Olá Dásio, Bem Vindo.

Primeira dica, não carregar um arquivo XML usando o DOMDocument.
Você vai perder a forma original e ele não será mais válido de acordo com a assinatura.
Apenas leia o mesmo para uma varíavel string.

Segunda dica, as vezes você não pode anexar um documento XML integralmente na chamada do SOAP. Você precisa converter para texto ou usar o .
Para converter em texto, você troca as entidades XML “>” e “<” por "&gt;" e “&lt;” respectivamente.
Somente alguns webservices permitem o CDATA e quando é caso, está explicito no esquema WSDL.
Para converter de XML para TEXTO use:

$cabec = htmlentities($cabecalho);
$dados = htmlentities($XmlAssinado);

Terceira dica, você não faz a chamada para o WSDL, mas para o webservice:

http://servicos.quirinopolis.go.gov.br:8115/prodataws/services/NfseWSService

Quarta dica, quando você usa o SoapClient, você chama diretamente o método exposto pela API.
No caso seria:

$SoapClient->RecepcionarLoteRps($cabec, $dados);

Eu te passei o envelope completo do SOAP.
Dessa forma você pode apenas usar o cURL.
Eu particularmente prefiro o cURL, pois embora você escreva mais, o processamento é mais rápido e confiável. O SoapClient precisa fazer muita mágica para funcionar certinho.

Segue um SO explicando exatamente como usar o cURL com SOAP:
SOAP request in PHP with CURL - Stack Overflow

Repare que no header você tem um SOAPAction.
Essa é a URL do seu OP, ou seja:

SOAPAction http://services.nfse/RecepcionarLoteRps 

Pode perguntar, caso apareçam mais dúvidas.

Obrigado pelas boas vindas, baseado no que vc informou antes e agora eu fiz esse codigo, gostaria se saber o motivo de estar dando Resource #id 110

$XmlAssinado = htmlentities(file_get_contents($arquivoRPSAssinado));
$cabecalho = htmlentities('<cabecalho versao="2.01" xmlns="http://www.abrasf.org.br/nfse.xsd"><versaoDados>2.01</versaoDados></cabecalho>');
        
//exit($cabecalho.'<br><br>'.$XmlAssinado);
$envelope = '<?xml version="1.0" encoding="UTF-8"?>
             <x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.nfse">
             <x:Header/>
             <x:Body>
                <ser:RecepcionarLoteRpsRequest>
                   <nfseCabecMsg>'.$cabecalho.'</nfseCabecMsg>
                   <nfseDadosMsg>'.$XmlAssinado.'</nfseDadosMsg>
               </ser:RecepcionarLoteRpsRequest>
            </x:Body>
            </x:Envelope>';

$url = 'http://servicos.quirinopolis.go.gov.br:8115/prodataws/services/NfseWSService?wsdl';
        
$headers = array(
            "Content-type: text/xml;charset=\"utf-8\"",
            "Accept: text/xml",
            "Cache-Control: no-cache",
            "Pragma: no-cache",
            "SOAPAction: http://services.nfse/RecepcionarLoteRps", 
            "Content-length: ".strlen($envelope),
); //SOAPAction: your op URL

$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_URL, 'http://servicos.quirinopolis.go.gov.br:8115/prodataws/services/NfseWSService?wsdl');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//curl_setopt($ch, CURLOPT_USERPWD, $soapUser.":".$soapPassword); 
// username and password - declared at the top of the doc
//curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $envelope); // the SOAP request
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        
exit(var_dump($ch));
// converting
$response = curl_exec($ch); 
curl_close($ch);
        
$response1 = str_replace("<soap:Body>","",$response);
echo $response1;

Dásio,

Conferindo o código de Catalão, eu notei que lá eles usam CDATA.
No entanto no caso de Quirinópolis, já usa TEXTO conforme eu te passei.
Ou seja, padrão ZERO de conformidade.

Revendo o seu código, notei alguns pequenos erros.
Usei o arquivo de exemplo abaixo:
RPS1789456.xml (6,4 KB)

Segue o corrigido e funcionando:

<?php
                             
$arquivoRPSAssinado = dirname(__FILE__).'\\RPS1789456.xml';
$XmlAssinado = htmlentities(file_get_contents($arquivoRPSAssinado));
$cabecalho = htmlentities('<cabecalho versao="2.01" xmlns="http://www.abrasf.org.br/nfse.xsd"><versaoDados>2.01</versaoDados></cabecalho>');
    
$envelope = 
'<?xml version="1.0" encoding="UTF-8"?>
 <x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/" xmln s:ser="http://services.nfse">
 <x:Header/>
 <x:Body>
 <ser:RecepcionarLoteRpsRequest>
    <nfseCabecMsg>'.$cabecalho.'</nfseCabecMsg>
    <nfseDadosMsg>'.$XmlAssinado.'</nfseDadosMsg>
 </ser:RecepcionarLoteRpsRequest>
 </x:Body>
 </x:Envelope>';

$url = 'http://servicos.quirinopolis.go.gov.br:8115/prodataws/services/NfseWSService';
    
$headers = array(
        "Content-type: text/xml; charset=utf-8",
        "SOAPAction: http://services.nfse/RecepcionarLoteRps", 
        "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);
    
// converting
$html = utf8_decode(curl_exec($ch));
file_put_contents("$arquivoRPSAssinado.ret", $html);
curl_close($ch);

preg_match_all('/<outputXML>(.*?)<\/outputXML>/s', $html, $matches);

$response = html_entity_decode(count($matches)&&count($matches[1])?$matches[1][0]:$html);
    
echo "<pre>$response</pre>";  

?>

O retorno abaixo está correto, pois passei uma empresa que não existe na cidade.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<EnviarLoteRpsResposta xmlns="http://www.abrasf.org.br/nfse.xsd">
    <ListaMensagemRetorno>
        <MensagemRetorno>
            <Codigo>E45</Codigo>
            <Mensagem>CNPJ não encontrado na base de dados</Mensagem>
            <Correcao>Confira o numero do CNPJ informado. Caso esteja correto, o prestador não está inscrito no município.</Correcao>
        </MensagemRetorno>
        <MensagemRetorno>
            <Codigo>L2</Codigo>
            <Mensagem>A Alíquota informada não foi encontrada na base de dados da Prefeitura.</Mensagem>
            <Correcao>Exemplo: Alíquota 5% utilizar o formato 5.00 .</Correcao>
        </MensagemRetorno>
        <MensagemRetorno>
            <Codigo>E43</Codigo>
            <Mensagem>Inscrição Municipal do prestador não encontrada na base de dados do município. 12345678909</Mensagem>
            <Correcao>Informe a inscrição municipal correta do prestador.</Correcao>
        </MensagemRetorno>
     </ListaMensagemRetorno>
</EnviarLoteRpsResposta>

Agora o interessante é que o webservice nem verificou a assinatura.
Tente enviar assinado e depois sem assinar o XML para ver se passa.

Outra dica, eu sugiro sempre salvar o retorno em um arquivo.
Com isso caso ocorra algum erro você tem como verificar o original.
Conforme o Exemplo:

file_put_contents("$arquivoRPSAssinado.ret", $html);

Teste e nos dê um retorno.

Nossa funcionou perfeito com seus ajustes, agora o erro que tbm não entendi pois esta gerando o xml e validando mendiante o “nfse_v201.xsd” (renomeei pois não permitiu enviar ele como xsd)
nfse_v201.xml (37,9 KB)
esse é o modelo que esta sendo gerado utilizando
$xmlRPS = new DOMDocument(“1.0”, “utf-8”);
$xmlRPS->formatOutput = true;

 $LoteRps = $xmlRPS->createElementNS($this->urlWebService, 'LoteRps');
 $IdLoteRps = $xmlRPS->createAttribute('Id');

rps_0000002619.xml (2,7 KB)
nesse arquivo tem um cnpj de teste ja cadastrado na prefeitura, mas fica falando que o erro

soapenv:ServerRecepcionarLoteRpsResponse cannot be null!

faço a validação utilizando
$objDom->schemaValidate($schema);
// a mensagem apos a validação é sempre
$return[‘mensagem’] = ‘XML obedece às regras definidas no arquivo XSD (’.$schema.’)’;

Olhe a tag <IdentificacaoTomador> do XML rps_0000002619.xml, ela está vazia.
Isso não pode.

Mas, nem perde tempo validando XML pelo XSD.
Esse provedor PRODATA, bem como a maioria são totalmente sem lógica.
Além do mais, isso vai aumentar o tempo de processamento para gerar a NOTA.

Com respeito a usar o DOMDocument, evite o uso.
Crie as tags concatenando via string mesmo.

É muito trabalhoso acertar os NameSpaces e os atributos corretamente, de forma que fiquem EXATAMENTE do jeito que o webservice espera.

E no final usando:

$xmlRPS->formatOutput = true

Vai fazer com que seu XML seja reformatado, perdendo a validade da assinatura.

Certo estou fazendo sem passar por essas funções, estou escrevendo o XML na mão, baseado em um exemplo que recebi aqui de outro forum.

ao passar o envelope ele esta indo assim.

<?xml version="1.0" encoding="UTF-8"?>
            <x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.nfse">
            <x:Header/>
            <x:Body>
               <ser:RecepcionarLoteRpsRequest>
                   <nfseCabecMsg>&lt;cabecalho versao=&quot;2.01&quot; xmlns=&quot;http://www.abrasf.org.br/nfse.xsd&quot;&gt;&lt;versaoDados&gt;2.01&lt;/versaoDados&gt;&lt;/cabecalho&gt;</nfseCabecMsg>
                   <nfseDadosMsg>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
            &lt;EnviarLoteRpsEnvio xmlns=&quot;http://www.abrasf.org.br/nfse.xsd&quot;&gt;
            &lt;LoteRps Id=&quot;ID1&quot; versao=&quot;2.01&quot;&gt;
                &lt;NumeroLote&gt;1&lt;/NumeroLote&gt;
                &lt;CpfCnpj&gt;
                    &lt;Cnpj&gt;&lt;/Cnpj&gt;
                &lt;/CpfCnpj&gt;
                &lt;InscricaoMunicipal&gt;540458&lt;/InscricaoMunicipal&gt;
                &lt;QuantidadeRps&gt;1&lt;/QuantidadeRps&gt;
                &lt;ListaRps&gt;
                    &lt;Rps&gt;
                        &lt;InfDeclaracaoPrestacaoServico Id=&quot;0000002621&quot;&gt;
                            &lt;Rps&gt;
                                &lt;IdentificacaoRps&gt;
                                    &lt;Numero&gt;0000002621&lt;/Numero&gt;
                                    &lt;Serie&gt;NFSE&lt;/Serie&gt;
                                    &lt;Tipo&gt;1&lt;/Tipo&gt;
                                &lt;/IdentificacaoRps&gt;
                                &lt;DataEmissao&gt;2018-03-07&lt;/DataEmissao&gt;
                                &lt;Status&gt;1&lt;/Status&gt;
                            &lt;/Rps&gt;
                            &lt;Competencia&gt;2018-03-07&lt;/Competencia&gt;
                            &lt;Servico&gt;
                                &lt;Valores&gt;
                                    &lt;ValorServicos&gt;10.00&lt;/ValorServicos&gt;
                                    
                                &lt;/Valores&gt;
                                &lt;IssRetido&gt;2&lt;/IssRetido&gt;
                                &lt;ItemListaServico&gt;1.03&lt;/ItemListaServico&gt;
                                &lt;CodigoCnae&gt;0001&lt;/CodigoCnae&gt;
                                &lt;Discriminacao&gt;PRESTACAO DE SERVICO EM PROCESSAMENTO DE DADOS&lt;/Discriminacao&gt;
                                &lt;CodigoMunicipio&gt;&lt;/CodigoMunicipio&gt;
                                &lt;ExigibilidadeISS&gt;1&lt;/ExigibilidadeISS&gt;
                                &lt;MunicipioIncidencia&gt;3134202&lt;/MunicipioIncidencia&gt;
                            &lt;/Servico&gt;
                            &lt;Prestador&gt;
                                &lt;CpfCnpj&gt;
                                    &lt;Cnpj&gt;&lt;/Cnpj&gt;
                                &lt;/CpfCnpj&gt;
                                &lt;InscricaoMunicipal&gt;&lt;/InscricaoMunicipal&gt;
                            &lt;/Prestador&gt;
                            &lt;Tomador&gt;
                                &lt;IdentificacaoTomador&gt;
                                    &lt;CpfCnpj&gt;
                                        &lt;Cnpj&gt;60722711115&lt;/Cnpj&gt;
                                    &lt;/CpfCnpj&gt;
                                &lt;/IdentificacaoTomador&gt;
                                &lt;RazaoSocial&gt;AUREO NEVES DE SOUZA JUNIO&lt;/RazaoSocial&gt;
                                &lt;Endereco&gt;
                                    &lt;Endereco&gt;Avenida Treze&lt;/Endereco&gt;
                                    &lt;Numero&gt;&lt;/Numero&gt;
                                    &lt;Bairro&gt;Centro&lt;/Bairro&gt;
                                    &lt;CodigoMunicipio&gt;3134202&lt;/CodigoMunicipio&gt;
                                    &lt;Uf&gt;MG&lt;/Uf&gt;
                                    &lt;CodigoPais&gt;01058&lt;/CodigoPais&gt;
                                    &lt;Cep&gt;38300140&lt;/Cep&gt;
                                &lt;/Endereco&gt;
                                &lt;Contato&gt;&lt;/Contato&gt;
                            &lt;/Tomador&gt;
                            &lt;OptanteSimplesNacional&gt;2&lt;/OptanteSimplesNacional&gt;
                            &lt;IncentivoFiscal&gt;2&lt;/IncentivoFiscal&gt;
                        &lt;/InfDeclaracaoPrestacaoServico&gt;
                    &lt;/Rps&gt;
                &lt;/ListaRps&gt;
            &lt;/LoteRps&gt;
        &lt;/EnviarLoteRpsEnvio&gt;</nfseDadosMsg>
               </ser:RecepcionarLoteRpsRequest>
            </x:Body>
            </x:Envelope>

e ele insiste que o RecepcionarLoteRpsRequest não pode ser nulo, ma esta com valores.

A resposta do erro nem sempre ajuda.

Essa resposta

soapenv:ServerRecepcionarLoteRpsResponse cannot be null!

Quer dizer que a nota foi gerada.
Pode conferir no site que ela está lá.

Essa :poop: de provedor não retorna o número da nota.

Dárcio,

Depois de quase um ano descobri como resolver esse erro.
O XML de exemplo deles está errado.

XML de exemplo para consulta de lote:

<ConsultarLoteRpsEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd">
	<Prestador>
		<CpfCnpj>
			<Cnpj>01976860001604</Cnpj>
		</CpfCnpj>
		<InscricaoMunicipal>2994275</InscricaoMunicipal>
	</Prestador>
	<Protocolo>750</Protocolo>
</ConsultarLoteRpsEnvio>

Repare no namespace http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd
Está errado de acordo com o schema, o certo é: http://www.abrasf.org.br/nfse.xsd

Portanto o método correto é:

<ConsultarLoteRpsEnvio xmlns="http://www.abrasf.org.br/nfse.xsd">
	<Prestador>
		<CpfCnpj>
			<Cnpj>01976860001604</Cnpj>
		</CpfCnpj>
		<InscricaoMunicipal>2994275</InscricaoMunicipal>
	</Prestador>
	<Protocolo>750</Protocolo>
</ConsultarLoteRpsEnvio>