/**
  * anfavea
  * Função para transformar o campo cdata do padrão ANFAVEA para
  * texto imprimível
  * @param string $cdata campo CDATA
  * @return string conteúdo do campo CDATA como string
  */
 private function pAnfavea($cdata = '')
 {
     if ($cdata == '') {
         return '';
     }
     return $cdata;
     //remove qualquer texto antes ou depois da tag CDATA
     $cdata = str_replace('<![CDATA[', '<CDATA>', $cdata);
     $cdata = str_replace(']]>', '</CDATA>', $cdata);
     $cdata = preg_replace('/\\s\\s+/', ' ', $cdata);
     $cdata = str_replace("> <", "><", $cdata);
     $len = strlen($cdata);
     $startPos = strpos($cdata, '<');
     if ($startPos === false) {
         return $cdata;
     }
     for ($x = $len; $x > 0; $x--) {
         if (substr($cdata, $x, 1) == '>') {
             $endPos = $x;
             break;
         }
     }
     if ($startPos > 0) {
         $parte1 = substr($cdata, 0, $startPos);
     } else {
         $parte1 = '';
     }
     $parte2 = substr($cdata, $startPos, $endPos - $startPos + 1);
     if ($endPos < $len) {
         $parte3 = substr($cdata, $endPos + 1, $len - $endPos - 1);
     } else {
         $parte3 = '';
     }
     $texto = trim($parte1) . ' ' . trim($parte3);
     if (strpos($parte2, '<CDATA>') === false) {
         $cdata = '<CDATA>' . $parte2 . '</CDATA>';
     } else {
         $cdata = $parte2;
     }
     //carrega o xml CDATA em um objeto DOM
     $dom = new DomDocumentNFePHP();
     $dom->loadXML($cdata, LIBXML_NOBLANKS | LIBXML_NOEMPTYTAG);
     //$xml = $dom->saveXML();
     //grupo CDATA infADprod
     $id = $dom->getElementsByTagName('id')->item(0);
     $div = $dom->getElementsByTagName('div')->item(0);
     $entg = $dom->getElementsByTagName('entg')->item(0);
     $dest = $dom->getElementsByTagName('dest')->item(0);
     $ctl = $dom->getElementsByTagName('ctl')->item(0);
     $ref = $dom->getElementsByTagName('ref')->item(0);
     if (isset($id)) {
         if ($id->hasAttributes()) {
             foreach ($id->attributes as $attr) {
                 $name = $attr->nodeName;
                 $value = $attr->nodeValue;
                 $texto .= " {$name} : {$value}";
             }
         }
     }
     if (isset($div)) {
         if ($div->hasAttributes()) {
             foreach ($div->attributes as $attr) {
                 $name = $attr->nodeName;
                 $value = $attr->nodeValue;
                 $texto .= " {$name} : {$value}";
             }
         }
     }
     if (isset($entg)) {
         if ($entg->hasAttributes()) {
             foreach ($entg->attributes as $attr) {
                 $name = $attr->nodeName;
                 $value = $attr->nodeValue;
                 $texto .= " {$name} : {$value}";
             }
         }
     }
     if (isset($dest)) {
         if ($dest->hasAttributes()) {
             foreach ($dest->attributes as $attr) {
                 $name = $attr->nodeName;
                 $value = $attr->nodeValue;
                 $texto .= " {$name} : {$value}";
             }
         }
     }
     if (isset($ctl)) {
         if ($ctl->hasAttributes()) {
             foreach ($ctl->attributes as $attr) {
                 $name = $attr->nodeName;
                 $value = $attr->nodeValue;
                 $texto .= " {$name} : {$value}";
             }
         }
     }
     if (isset($ref)) {
         if ($ref->hasAttributes()) {
             foreach ($ref->attributes as $attr) {
                 $name = $attr->nodeName;
                 $value = $attr->nodeValue;
                 $texto .= " {$name} : {$value}";
             }
         }
     }
     //grupo CADATA infCpl
     $t = $dom->getElementsByTagName('transmissor')->item(0);
     $r = $dom->getElementsByTagName('receptor')->item(0);
     $versao = !empty($dom->getElementsByTagName('versao')->item(0)->nodeValue) ? 'Versao:' . $dom->getElementsByTagName('versao')->item(0)->nodeValue . ' ' : '';
     $especieNF = !empty($dom->getElementsByTagName('especieNF')->item(0)->nodeValue) ? 'Especie:' . $dom->getElementsByTagName('especieNF')->item(0)->nodeValue . ' ' : '';
     $fabEntrega = !empty($dom->getElementsByTagName('fabEntrega')->item(0)->nodeValue) ? 'Entrega:' . $dom->getElementsByTagName('fabEntrega')->item(0)->nodeValue . ' ' : '';
     $dca = !empty($dom->getElementsByTagName('dca')->item(0)->nodeValue) ? 'dca:' . $dom->getElementsByTagName('dca')->item(0)->nodeValue . ' ' : '';
     $texto .= "" . $versao . $especieNF . $fabEntrega . $dca;
     if (isset($t)) {
         if ($t->hasAttributes()) {
             $texto .= " Transmissor ";
             foreach ($t->attributes as $attr) {
                 $name = $attr->nodeName;
                 $value = $attr->nodeValue;
                 $texto .= " {$name} : {$value}";
             }
         }
     }
     if (isset($r)) {
         if ($r->hasAttributes()) {
             $texto .= " Receptor ";
             foreach ($r->attributes as $attr) {
                 $name = $attr->nodeName;
                 $value = $attr->nodeValue;
                 $texto .= " {$name} : {$value}";
             }
         }
     }
     return $texto;
 }
 /**
  * manifDest
  * Manifestação do detinatário NT2012-002.
  *     210200 – Confirmação da Operação
  *     210210 – Ciência da Operação
  *     210220 – Desconhecimento da Operação
  *     210240 – Operação não Realizada
  *
  * @name manifDest
  * @param   string $chNFe Chave da NFe
  * @param   string $tpEvento Tipo do evento pode conter 2 ou 6 digitos ex. 00 ou 210200
  * @param   string $xJust Justificativa quando tpEvento = 40 ou 210240
  * @param   integer $tpAmb Tipo de ambiente
  * @param   mixed  $resp variável passada como referencia e irá conter o retorno da função em um array
  * @return false ou xml do retorno do webservice
  */
 public function manifDest($chNFe = '', $tpEvento = '', $xJust = '', $tpAmb = '', &$resp = array())
 {
     try {
         if ($chNFe == '') {
             $msg = "A chave da NFe recebida é obrigatória.";
             throw new nfephpException($msg);
         }
         if ($tpEvento == '') {
             $msg = "O tipo de evento não pode ser vazio.";
             throw new nfephpException($msg);
         }
         if (strlen($tpEvento) == 2) {
             $tpEvento = "2102$tpEvento";
         }
         if (strlen($tpEvento) != 6) {
             $msg = "O comprimento do código do tipo de evento está errado.";
             throw new nfephpException($msg);
         }
         switch ($tpEvento) {
             case '210200':
                 $descEvento = 'Confirmacao da Operacao';
                 //confirma a operação e o recebimento da mercadoria (para as operações
                 //com circulação de mercadoria)
                 //Após a Confirmação da Operação pelo destinatário, a empresa emitente
                 //fica automaticamente impedida de cancelar a NF-e
                 break;
             case '210210':
                 $descEvento = 'Ciencia da Operacao'; //encrenca !!! Não usar
                 //O evento de “Ciência da Operação” é um evento opcional e pode ser evitado
                 //Após um período determinado, todas as operações com “Ciência da Operação” deverão
                 //obrigatoriamente ter a manifestação final do destinatário declarada em um dos eventos de
                 //Confirmação da Operação, Desconhecimento ou Operação não Realizada
                 break;
             case '210220':
                 $descEvento = 'Desconhecimento da Operacao';
                 //Uma empresa pode ficar sabendo das operações destinadas a um determinado CNPJ
                 //consultando o “Serviço de Consulta da Relação de Documentos Destinados” ao seu CNPJ.
                 //O evento de “Desconhecimento da Operação” permite ao destinatário informar o seu
                 //desconhecimento de uma determinada operação que conste nesta relação, por exemplo
                 break;
             case '210240':
                 $descEvento = 'Operacao nao Realizada';
                 //não aceitação no recebimento que antes se fazia com apenas um carimbo na NF
                 //operação não foi realizada (com Recusa de Recebimento da mercadoria e outros motivos),
                 //não cabendo neste caso a emissão de uma Nota Fiscal de devolução.
                 break;
             default:
                 $msg = "O código do tipo de evento informado não corresponde a "
                     . "nenhum evento de manifestação de destinatário.";
                 throw new nfephpException($msg);
         }
         $resp = array('bStat'=>false,'cStat'=>'','xMotivo'=>'','arquivo'=>'');
         if ($tpEvento == '210240' && $xJust == '') {
                 $msg = "Uma Justificativa é obrigatória para o evento de Operação não Realizada.";
                 throw new nfephpException($msg);
         }
         //limpa o texto de correção para evitar surpresas
         $xJust = $this->pCleanString($xJust);
         //ajusta ambiente
         if ($tpAmb == '') {
             $tpAmb = $this->tpAmb;
         }
         //utilizar AN para enviar o manifesto
         $sigla = 'AN';
         $aURL = $this->pLoadSEFAZ($tpAmb, $sigla);
         $cOrgao='91';
         $numLote = $this->pGeraNumLote();
         //Data e hora do evento no formato AAAA-MM-DDTHH:MM:SSTZD (UTC)
         $dhEvento = date('Y-m-d').'T'.date('H:i:s').$this->timeZone;
         //montagem do namespace do serviço
         $servico = 'RecepcaoEvento';
         //recuperação da versão
         $versao = $aURL[$servico]['version'];
         //recuperação da url do serviço
         $urlservico = $aURL[$servico]['URL'];
         //recuperação do método
         $metodo = $aURL[$servico]['method'];
         //montagem do namespace do serviço
         $operation = $aURL[$servico]['operation'];
         $namespace = $this->URLPortal.'/wsdl/'.$operation;
         // 2   +    6     +    44         +   2  = 54 digitos
         //“ID” + tpEvento + chave da NF-e + nSeqEvento
         $nSeqEvento = '1';
         $id = "ID".$tpEvento.$chNFe.'0'.$nSeqEvento;
         //monta mensagem
         $Ev='';
         $Ev .= "<evento xmlns=\"$this->URLPortal\" versao=\"$versao\">";
         $Ev .= "<infEvento Id=\"$id\">";
         $Ev .= "<cOrgao>$cOrgao</cOrgao>";
         $Ev .= "<tpAmb>$tpAmb</tpAmb>";
         $Ev .= "<CNPJ>$this->cnpj</CNPJ>";
         $Ev .= "<chNFe>$chNFe</chNFe>";
         $Ev .= "<dhEvento>$dhEvento</dhEvento>";
         $Ev .= "<tpEvento>$tpEvento</tpEvento>";
         $Ev .= "<nSeqEvento>$nSeqEvento</nSeqEvento>";
         $Ev .= "<verEvento>$versao</verEvento>";
         $Ev .= "<detEvento versao=\"$versao\">";
         $Ev .= "<descEvento>$descEvento</descEvento>";
         if ($xJust != '') {
             $Ev .= "<xJust>$xJust</xJust>";
         }
         $Ev .= "</detEvento></infEvento></evento>";
         //assinatura dos dados
         $tagid = 'infEvento';
         $Ev = $this->signXML($Ev, $tagid);
         $Ev = $this->pClearXml($Ev, true);
         //montagem dos dados
         $dados = '';
         $dados .= "<envEvento xmlns=\"$this->URLPortal\" versao=\"$versao\">";
         $dados .= "<idLote>$numLote</idLote>";
         $dados .= $Ev;
         $dados .= "</envEvento>";
         //montagem da mensagem
         $cabec = "<nfeCabecMsg xmlns=\"$namespace\"><cUF>$this->cUF</cUF>"
                 . "<versaoDados>$versao</versaoDados></nfeCabecMsg>";
         $dados = "<nfeDadosMsg xmlns=\"$namespace\">$dados</nfeDadosMsg>";
         //grava solicitação em temp
         if (! file_put_contents($this->temDir."$chNFe-$nSeqEvento-envMDe.xml", $Ev)) {
             throw new nfephpException("Falha na gravacao do arquivo envMDe!!");
         }
         //envia dados via SOAP e verifica o retorno, se nao houve gera excecao
         if (!$retorno = $this->pSendSOAP($urlservico, $namespace, $cabec, $dados, $metodo, $tpAmb)) {
             throw new nfephpException("Nao houve retorno Soap verifique a mensagem de erro e o debug!!");
         }
         //tratar dados de retorno
         $xmlMDe = new DomDocumentNFePHP($retorno);
         $retEvento = $xmlMDe->getElementsByTagName("retEvento")->item(0);
         $infEvento = $xmlMDe->getElementsByTagName("infEvento")->item(0);
         $cStat = !empty($retEvento->getElementsByTagName('cStat')->item(0)->nodeValue) ?
                 $retEvento->getElementsByTagName('cStat')->item(0)->nodeValue : '';
         $xMotivo = !empty($retEvento->getElementsByTagName('xMotivo')->item(0)->nodeValue) ?
                 $retEvento->getElementsByTagName('xMotivo')->item(0)->nodeValue : '';
         if ($cStat == '') {
             //houve erro
             $msg = "cStat está em branco, houve erro na comunicação Soap "
                     . "verifique a mensagem de erro e o debug!!";
             throw new nfephpException($msg);
         }
         //tratar erro de versão do XML
         if ($cStat == '238' || $cStat == '239') {
             $this->pTrata239($retorno, $sigla, $tpAmb, $servico, $versao);
             $msg = "Versão do arquivo XML não suportada no webservice!!";
             throw new nfephpException($msg);
         }
         //erro no processamento
         if ($cStat != '135' && $cStat != '136') {
             //se cStat <> 135 houve erro e o lote foi rejeitado
             $msg = "O Lote foi rejeitado : $cStat - $xMotivo\n";
             throw new nfephpException($msg);
         }
         if ($cStat == '136') {
             $msg = "O Evento foi registrado mas a NFe não foi localizada : $cStat - $xMotivo\n";
             throw new nfephpException($msg);
         }
         //o evento foi aceito
         $xmlenvMDe = new DomDocumentNFePHP($Ev);
         $evento = $xmlenvMDe->getElementsByTagName("evento")->item(0);
         //Processo completo solicitação + protocolo
         $xmlprocMDe = new DomDocumentNFePHP();
         //cria a tag procEventoNFe
         $procEventoNFe = $xmlprocMDe->createElement('procEventoNFe');
         $xmlprocMDe->appendChild($procEventoNFe);
         //estabele o atributo de versão
         $eventProc_att1 = $procEventoNFe->appendChild($xmlprocMDe->createAttribute('versao'));
         $eventProc_att1->appendChild($xmlprocMDe->createTextNode($versao));
         //estabelece o atributo xmlns
         $eventProc_att2 = $procEventoNFe->appendChild($xmlprocMDe->createAttribute('xmlns'));
         $eventProc_att2->appendChild($xmlprocMDe->createTextNode($this->URLPortal));
         //carrega o node evento
         $node1 = $xmlprocMDe->importNode($evento, true);
         $procEventoNFe->appendChild($node1);
         //carrega o node retEvento
         $node2 = $xmlprocMDe->importNode($retEvento, true);
         $procEventoNFe->appendChild($node2);
         //salva o xml como string em uma variável
         $procXML = $xmlprocMDe->saveXML();
         //remove as informações indesejadas
         $procXML = $this->pClearXml($procXML, false);
         $filename = $this->evtDir."$chNFe-$tpEvento-$nSeqEvento-procMDe.xml";
         $resp = array('bStat'=>true,'cStat'=>$cStat,'xMotivo'=>$xMotivo,'arquivo'=>$filename);
         //salva o arquivo xml
         if (!file_put_contents($filename, $procXML)) {
             $msg = "Falha na gravacao do arquivo procMDe!!";
             throw new nfephpException($msg);
         }
     } catch (nfephpException $e) {
         $this->pSetError($e->getMessage());
         if ($this->exceptions) {
             throw $e;
         }
         $resp = array('bStat'=>false,'cStat'=>$cStat,'xMotivo'=>$xMotivo,'arquivo'=>'');
         return false;
     }
     return $retorno;
 } //fim manifDest