/** * Converte para Objetos RPS * @param string $txt lote de RPS em TXT formatado ou path para o arquivo * @return array * @throws InvalidArgumentException */ public static function toRps($txt = '') { if (empty($txt)) { throw new InvalidArgumentException('Algum dado deve ser passado para converter.'); } $aRps = array(); if (is_file($txt)) { //extrai cada linha do arquivo em um campo de matriz $aDados = file($txt, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES | FILE_TEXT); } elseif (is_array($txt)) { //carrega a matriz $aDados = $txt; } else { if (strlen($txt) > 0) { //carrega a matriz com as linha do arquivo $aDados = explode("\n", $txt); } else { return $aRps; } } $total = count($aDados); for ($x = 0; $x < $total; $x++) { $aDados[$x] = str_replace("\r", '', $aDados[$x]); $aDados[$x] = Strings::cleanString($aDados[$x]); $tipo = substr($aDados[$x], 0, 1); self::$contTipos[$tipo] += 1; } self::validTipos(); //o numero de notas criadas será a quantidade de tipo 2 ou 3 ou 6 self::$numRps = self::$contTipos['2'] + self::$contTipos['3'] + self::$contTipos['6']; for ($x = 0; $x < self::$numRps; $x++) { self::$aRps[] = new Rps(); } self::zArray2Rps($aDados); self::loadRPS(); return self::$aRps; }
/** * Clear the string of unwanted characters * Will remove all duplicated spaces and if wanted * replace all accented characters by their originals * and all the special ones * @param string $field string to be cleaned */ private function clearFieldString(&$field) { $field = trim(preg_replace('/\\s+/', ' ', $field)); if ($this->limparString) { $field = Strings::cleanString($field); } }
/** * zSefazEvento * @param string $siglaUF * @param string $chNFe * @param string $tpAmb * @param string $tpEvento * @param string $nSeqEvento * @param string $tagAdic * @return string * @throws Exception\RuntimeException * @internal function zLoadServico (Common\Base\BaseTools) */ protected function zSefazEvento($siglaUF = '', $chNFe = '', $tpAmb = '2', $tpEvento = '', $nSeqEvento = '1', $tagAdic = '') { if ($tpAmb == '') { $tpAmb = $this->aConfig['tpAmb']; } //carrega serviço $servico = 'RecepcaoEvento'; $this->zLoadServico('nfe', $servico, $siglaUF, $tpAmb); if ($this->urlService == '') { $msg = "A recepção de eventos não está disponível na SEFAZ {$siglaUF}!!!"; throw new Exception\RuntimeException($msg); } $aRet = $this->zTpEv($tpEvento); $aliasEvento = $aRet['alias']; $descEvento = $aRet['desc']; $cnpj = $this->aConfig['cnpj']; $dhEvento = (string) str_replace(' ', 'T', date('Y-m-d H:i:sP')); $sSeqEvento = str_pad($nSeqEvento, 2, "0", STR_PAD_LEFT); $eventId = "ID" . $tpEvento . $chNFe . $sSeqEvento; $cOrgao = $this->urlcUF; if ($siglaUF == 'AN') { $cOrgao = '91'; } $mensagem = "<evento xmlns=\"{$this->urlPortal}\" versao=\"{$this->urlVersion}\">" . "<infEvento Id=\"{$eventId}\">" . "<cOrgao>{$cOrgao}</cOrgao>" . "<tpAmb>{$tpAmb}</tpAmb>" . "<CNPJ>{$cnpj}</CNPJ>" . "<chNFe>{$chNFe}</chNFe>" . "<dhEvento>{$dhEvento}</dhEvento>" . "<tpEvento>{$tpEvento}</tpEvento>" . "<nSeqEvento>{$nSeqEvento}</nSeqEvento>" . "<verEvento>{$this->urlVersion}</verEvento>" . "<detEvento versao=\"{$this->urlVersion}\">" . "<descEvento>{$descEvento}</descEvento>" . "{$tagAdic}" . "</detEvento>" . "</infEvento>" . "</evento>"; //assinatura dos dados $signedMsg = $this->oCertificate->signXML($mensagem, 'infEvento'); $signedMsg = Strings::clearXml($signedMsg, true); $numLote = LotNumber::geraNumLote(); $cons = "<envEvento xmlns=\"{$this->urlPortal}\" versao=\"{$this->urlVersion}\">" . "<idLote>{$numLote}</idLote>" . "{$signedMsg}" . "</envEvento>"; //valida mensagem com xsd //no caso do evento nao tem xsd organizado, esta fragmentado //e por vezes incorreto por isso essa validação está desabilitada //if (! $this->zValidMessage($cons, 'nfe', 'envEvento', $version)) { // $msg = 'Falha na validação. '.$this->error; // throw new Exception\RuntimeException($msg); //} $body = "<nfeDadosMsg xmlns=\"{$this->urlNamespace}\">{$cons}</nfeDadosMsg>"; //envia a solicitação via SOAP $retorno = $this->oSoap->send($this->urlService, $this->urlNamespace, $this->urlHeader, $body, $this->urlMethod); $lastMsg = $this->oSoap->lastMsg; $this->soapDebug = $this->oSoap->soapDebug; //salva mensagens $filename = "{$chNFe}-{$aliasEvento}-envEvento.xml"; $this->zGravaFile('nfe', $tpAmb, $filename, $lastMsg); $filename = "{$chNFe}-{$aliasEvento}-retEnvEvento.xml"; $this->zGravaFile('nfe', $tpAmb, $filename, $retorno); //tratar dados de retorno $this->aLastRetEvent = ReturnNFe::readReturnSefaz($servico, $retorno); if ($this->aLastRetEvent['cStat'] == '128') { if ($this->aLastRetEvent['evento'][0]['cStat'] == '135' || $this->aLastRetEvent['evento'][0]['cStat'] == '136' || $this->aLastRetEvent['evento'][0]['cStat'] == '155') { $pasta = 'eventos'; //default if ($aliasEvento == 'CancNFe') { $pasta = 'canceladas'; $filename = "{$chNFe}-{$aliasEvento}-procEvento.xml"; } elseif ($aliasEvento == 'CCe') { $pasta = 'cartacorrecao'; $filename = "{$chNFe}-{$aliasEvento}-{$nSeqEvento}-procEvento.xml"; } $retorno = $this->zAddProtMsg('procEventoNFe', 'evento', $signedMsg, 'retEvento', $retorno); $this->zGravaFile('nfe', $tpAmb, $filename, $retorno, $pasta); } } return (string) $retorno; }
/** * zClean * Efetua limpeza dos campos * * @param array $aCampos * @return array */ protected function zClean($aCampos = array()) { foreach ($aCampos as $campo) { $campo = trim(preg_replace('/\\s+/', ' ', $campo)); if ($this->limparString) { $campo = Strings::cleanString($campo); } } return $aCampos; }
/** * Envia mensagem ao webservice * @param string $urlsevice * @param string $namespace * @param string $header * @param string $body * @param string $method * @return boolean|string */ public function send($urlservice, $namespace, $header, $body, $method) { //monta a mensagem ao webservice $data = '<?xml version="1.0" encoding="utf-8"?>' . '<soap12:Envelope '; $data .= 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '; $data .= 'xmlns:xsd="http://www.w3.org/2001/XMLSchema" '; $data .= 'xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">'; $data .= '<soap12:Header>' . $header . '</soap12:Header>'; $data .= '<soap12:Body>' . $body . '</soap12:Body>'; $data .= '</soap12:Envelope>'; $data = Strings::clearMsg($data); $this->lastMsg = $data; //tamanho da mensagem $tamanho = strlen($data); //estabelecimento dos parametros da mensagem //$parametros = array( // 'Content-Type: application/soap+xml;charset=utf-8;action="'.$namespace."/".$method.'"', // 'SOAPAction: "'.$method.'"', // "Content-length: $tamanho"); $parametros = array('Content-Type: application/soap+xml;charset=utf-8', 'SOAPAction: "' . $method . '"', "Content-length: {$tamanho}"); //solicita comunicação via cURL $resposta = $this->zCommCurl($urlservice, $data, $parametros); if (empty($resposta)) { $msg = "Não houve retorno do Curl.\n {$this->errorCurl}"; throw new Exception\RuntimeException($msg); } //obtem o bloco html da resposta $xPos = stripos($resposta, "<"); $blocoHtml = substr($resposta, 0, $xPos); if ($this->infoCurl["http_code"] != '200') { //se não é igual a 200 houve erro $msg = $blocoHtml; throw new Exception\RuntimeException($msg); } //obtem o tamanho da resposta $lenresp = strlen($resposta); //localiza a primeira marca de tag $xPos = stripos($resposta, "<"); //se não existir não é um xml nem um html if ($xPos !== false) { $xml = substr($resposta, $xPos, $lenresp - $xPos); } else { $xml = ''; } //testa para saber se é um xml mesmo ou é um html $result = simplexml_load_string($xml, 'SimpleXmlElement', LIBXML_NOERROR + LIBXML_ERR_FATAL + LIBXML_ERR_NONE); if ($result === false) { //não é um xml então pode limpar $xml = ''; } if ($xml == '') { $msg = "Não houve retorno de um xml verifique soapDebug!!"; throw new Exception\RuntimeException($msg); } if ($xml != '' && substr($xml, 0, 5) != '<?xml') { $xml = '<?xml version="1.0" encoding="utf-8"?>' . $xml; } return $xml; }
/** * Carga tributária total estimada * Dados normalmente obtidos no IBPT * @param float $valor * @param float $percentual * @param string $fonte */ public function cargaTributaria($valor, $percentual, $fonte) { $this->valorCargaTributariaRPS = number_format($valor, 2, '.', ''); $this->percentualCargaTributariaRPS = number_format($percentual, 4, '.', ''); $this->fonteCargaTributariaRPS = substr(Strings::cleanString($fonte), 0, 10); }
public function cancelamento($motivo) { $this->motCancelamento = Strings::cleanString($motivo); }
/** * addCancelamento * Adiciona a tga de cancelamento a uma CTe já autorizada * NOTA: não é requisito da SEFAZ, mas auxilia na identificação das CTe que foram canceladas * @param string $pathCTefile * @param string $pathCancfile * @param bool $saveFile * @return string * @throws Exception\RuntimeException */ public function addCancelamento($pathCTefile = '', $pathCancfile = '', $saveFile = false) { $procXML = ''; //carrega a CTe $docCTe = new Dom(); if (file_exists($pathCTefile)) { //carrega o XML pelo caminho do arquivo informado $docCTe->loadXMLFile($pathCTefile); } else { //carrega o XML pelo conteúdo $docCTe->loadXMLString($pathCTefile); } $nodeCTe = $docCTe->getNode('CTe', 0); if ($nodeCTe == '') { $msg = "O arquivo indicado como CTe não é um xml de CTe!"; throw new Exception\RuntimeException($msg); } $proCTe = $docCTe->getNode('protCTe'); if ($proCTe == '') { $msg = "A CTe não está protocolada ainda!!"; throw new Exception\RuntimeException($msg); } $chaveCTe = $proCTe->getElementsByTagName('chCTe')->item(0)->nodeValue; //$nProtCTe = $proCTe->getElementsByTagName('nProt')->item(0)->nodeValue; $tpAmb = $docCTe->getNodeValue('tpAmb'); $anomes = date('Ym', DateTime::convertSefazTimeToTimestamp($docCTe->getNodeValue('dhEmi'))); //carrega o cancelamento //pode ser um evento ou resultado de uma consulta com multiplos eventos $doccanc = new Dom(); if (file_exists($pathCancfile)) { //carrega o XML pelo caminho do arquivo informado $doccanc->loadXMLFile($pathCancfile); } else { //carrega o XML pelo conteúdo $doccanc->loadXMLString($pathCancfile); } $retEvento = $doccanc->getElementsByTagName('retEventoCTe')->item(0); $eventos = $retEvento->getElementsByTagName('infEvento'); foreach ($eventos as $evento) { //evento $cStat = $evento->getElementsByTagName('cStat')->item(0)->nodeValue; $tpAmb = $evento->getElementsByTagName('tpAmb')->item(0)->nodeValue; $chaveEvento = $evento->getElementsByTagName('chCTe')->item(0)->nodeValue; $tpEvento = $evento->getElementsByTagName('tpEvento')->item(0)->nodeValue; //$nProtEvento = $evento->getElementsByTagName('nProt')->item(0)->nodeValue; //verifica se conferem os dados //cStat = 135 ==> evento homologado //cStat = 136 ==> vinculação do evento à respectiva NF-e prejudicada //cStat = 155 ==> Cancelamento homologado fora de prazo //tpEvento = 110111 ==> Cancelamento //chave do evento == chave da CTe //protocolo do evneto == protocolo da CTe if (($cStat == '135' || $cStat == '136' || $cStat == '155') && $tpEvento == '110111' && $chaveEvento == $chaveCTe) { $proCTe->getElementsByTagName('cStat')->item(0)->nodeValue = '101'; $proCTe->getElementsByTagName('xMotivo')->item(0)->nodeValue = 'Cancelamento de CT-e homologado'; $procXML = $docCTe->saveXML(); //remove as informações indesejadas $procXML = Strings::clearProt($procXML); if ($saveFile) { $filename = "{$chaveCTe}-protCTe.xml"; $this->zGravaFile('cte', $tpAmb, $filename, $procXML, 'canceladas', $anomes); } break; } } return (string) $procXML; }
/** * zSefazEvento * * @param string $siglaUF * @param string $chave * @param string $cOrgao * @param string $tpAmb * @param string $tpEvento * @param string $nSeqEvento * @param string $tagAdic * @return string * @throws Exception\RuntimeException * @internal function zLoadServico (Common\Base\BaseTools) */ protected function zSefazEvento($siglaUF = '', $chave = '', $cOrgao = '', $tpAmb = '2', $tpEvento = '', $nSeqEvento = '1', $tagAdic = '') { if ($tpAmb == '') { $tpAmb = $this->aConfig['tpAmb']; } //carrega serviço $servico = 'MDFeRecepcaoEvento'; $this->zLoadServico('mdfe', $servico, $siglaUF, $tpAmb); if ($this->urlService == '') { $msg = "A recepção de eventos não está disponível na SEFAZ {$siglaUF}!!!"; throw new Exception\RuntimeException($msg); } $aRet = $this->zTpEv($tpEvento); $aliasEvento = $aRet['alias']; $cnpj = $this->aConfig['cnpj']; $dhEvento = (string) str_replace(' ', 'T', date('Y-m-d H:i:s')); $sSeqEvento = str_pad($nSeqEvento, 2, "0", STR_PAD_LEFT); $eventId = "ID" . $tpEvento . $chave . $sSeqEvento; if ($cOrgao == '') { $cOrgao = $this->urlcUF; } $mensagem = "<eventoMDFe xmlns=\"{$this->urlPortal}\" versao=\"{$this->urlVersion}\">" . "<infEvento Id=\"{$eventId}\">" . "<cOrgao>{$cOrgao}</cOrgao>" . "<tpAmb>{$tpAmb}</tpAmb>" . "<CNPJ>{$cnpj}</CNPJ>" . "<chMDFe>{$chave}</chMDFe>" . "<dhEvento>{$dhEvento}</dhEvento>" . "<tpEvento>{$tpEvento}</tpEvento>" . "<nSeqEvento>{$nSeqEvento}</nSeqEvento>" . "<detEvento versaoEvento=\"{$this->urlVersion}\">" . "{$tagAdic}" . "</detEvento>" . "</infEvento>" . "</eventoMDFe>"; //assinatura dos dados $signedMsg = $this->oCertificate->signXML($mensagem, 'infEvento'); $cons = Strings::clearXml($signedMsg, true); //valida mensagem com xsd //no caso do evento nao tem xsd organizado, esta fragmentado //e por vezes incorreto por isso essa validação está desabilitada //if (! $this->zValidMessage($cons, 'mdfe', 'eventoMDFe', $version)) { // $msg = 'Falha na validação. '.$this->error; // throw new Exception\RuntimeException($msg); //} $body = "<mdfeDadosMsg xmlns=\"{$this->urlNamespace}\">{$cons}</mdfeDadosMsg>"; //envia a solicitação via SOAP $retorno = $this->oSoap->send($this->urlService, $this->urlNamespace, $this->urlHeader, $body, $this->urlMethod); $lastMsg = $this->oSoap->lastMsg; $this->soapDebug = $this->oSoap->soapDebug; //salva mensagens $filename = "{$chave}-{$aliasEvento}-eventoMDFe.xml"; $this->zGravaFile('mdfe', $tpAmb, $filename, $lastMsg); $filename = "{$chave}-{$aliasEvento}-retEventoMDFe.xml"; $this->zGravaFile('mdfe', $tpAmb, $filename, $retorno); //tratar dados de retorno $this->aLastRetEvent = Response::readReturnSefaz($servico, $retorno); return (string) $retorno; }