Completed
Push — master ( 489be2...ffa839 )
by Roberto
12s
created

src/Tools.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace NFePHP\MDFe;
4
5
/**
6
 * Classe principal para a comunicação com a SEFAZ
7
 *
8
 * @category  Library
9
 * @package   nfephp-org/sped-mdfe
10
 * @copyright 2008-2016 NFePHP
11
 * @license   http://www.gnu.org/licenses/lesser.html LGPL v3
12
 * @link      http://github.com/nfephp-org/sped-mdfe for the canonical source repository
13
 * @author    Roberto L. Machado <linux.rlm at gmail dot com>
14
 */
15
16
use NFePHP\Common\Base\BaseTools;
17
use NFePHP\Common\DateTime\DateTime;
18
use NFePHP\Common\LotNumber\LotNumber;
19
use NFePHP\Common\Strings\Strings;
20
use NFePHP\Common\Files;
21
use NFePHP\Common\Exception;
22
use NFePHP\Common\Dom\Dom;
23
use NFePHP\Common\Dom\ValidXsd;
24
use NFePHP\MDFe\Auxiliar\Response;
25
use NFePHP\MDFe\Mail;
26
use NFePHP\MDFe\Auxiliar\Identify;
27
28 3
if (!defined('NFEPHP_ROOT')) {
29 3
    define('NFEPHP_ROOT', dirname(dirname(__FILE__)));
30 2
}
31
32
class Tools extends BaseTools
33
{
34
    /**
35
     * errrors
36
     *
37
     * @var string
38
     */
39
    public $errors = array();
40
    /**
41
     * soapDebug
42
     *
43
     * @var string
44
     */
45
    public $soapDebug = '';
46
    /**
47
     * urlPortal
48
     * Instância do WebService
49
     *
50
     * @var string
51
     */
52
    protected $urlPortal = 'http://www.portalfiscal.inf.br/mdfe';
53
    /**
54
     * aLastRetEvent
55
     *
56
     * @var array
57
     */
58
    private $aLastRetEvent = array();
59
    /**
60
     * imprime
61
     * Imprime o documento eletrônico (MDFe, CCe, Inut.)
62
     *
63
     * @param  string $pathXml
64
     * @param  string $pathDestino
65
     * @param  string $printer
66
     * @return string
67
     */
68
    public function imprime($pathXml = '', $pathDestino = '', $printer = '')
69
    {
70
        //TODO : falta implementar esse método para isso é necessária a classe
71
        //PrintMDFe
72
        return "$pathXml $pathDestino $printer";
73
    }
74
    /**
75
     * enviaMail
76
     * Envia a MDFe por email aos destinatários
77
     * Caso $aMails esteja vazio serão obtidos os email do destinatário  e
78
     * os emails que estiverem registrados nos campos obsCont do xml
79
     *
80
     * @param  string  $pathXml
81
     * @param  array   $aMails
82
     * @param  string  $templateFile path completo ao arquivo template html do corpo do email
83
     * @param  boolean $comPdf       se true o sistema irá renderizar o DANFE e anexa-lo a mensagem
84
     * @return boolean
85
     */
86
    public function enviaMail($pathXml = '', $aMails = array(), $templateFile = '', $comPdf = false)
87
    {
88
        $mail = new Mail($this->aMailConf);
89
        if ($templateFile != '') {
90
            $mail->setTemplate($templateFile);
91
        }
92
        return $mail->envia($pathXml, $aMails, $comPdf);
93
    }
94
95
    /**
96
     * addProtocolo
97
     * Adiciona o protocolo de autorização de uso da MDFe
98
     * NOTA: exigência da SEFAZ, a MDFe somente é válida com o seu respectivo protocolo
99
     *
100
     * @param  string  $pathMDFefile
101
     * @param  string  $pathProtfile
102
     * @param  boolean $saveFile
103
     * @return string
104
     * @throws Exception\RuntimeException
105
     */
106
    public function addProtocolo($pathMDFefile = '', $pathProtfile = '', $saveFile = false)
107
    {
108
        //carrega a MDFe
109
        $docmdfe = new Dom();
110
        $docmdfe->loadXMLFile($pathMDFefile);
111
        $nodemdfe = $docmdfe->getNode('MDFe', 0);
112
        if ($nodemdfe == '') {
113
            $msg = "O arquivo indicado como MDFe não é um xml de MDFe!";
114
            throw new Exception\RuntimeException($msg);
115
        }
116
        if ($docmdfe->getNode('Signature') == '') {
117
            $msg = "O MDFe não está assinado!";
118
            throw new Exception\RuntimeException($msg);
119
        }
120
        //carrega o protocolo
121
        $docprot = new Dom();
122
        $docprot->loadXMLFile($pathProtfile);
123
        $nodeprots = $docprot->getElementsByTagName('protMDFe');
124
        if ($nodeprots->length == 0) {
125
            $msg = "O arquivo indicado não contêm um protocolo de autorização!";
126
            throw new Exception\RuntimeException($msg);
127
        }
128
        //carrega dados da MDFe
129
        $tpAmb = $docmdfe->getNodeValue('tpAmb');
130
        $anomes = date(
131
            'Ym',
132
            DateTime::convertSefazTimeToTimestamp($docmdfe->getNodeValue('dhEmi'))
133
        );
134
        $infMDFe = $docmdfe->getNode("infMDFe", 0);
135
        $versao = $infMDFe->getAttribute("versao");
136
        $chaveId = $infMDFe->getAttribute("Id");
137
        $chaveMDFe = preg_replace('/[^0-9]/', '', $chaveId);
138
        $digValueMDFe = $docmdfe->getNodeValue('DigestValue');
139
        //carrega os dados do protocolo
140
        for ($i = 0; $i < $nodeprots->length; $i++) {
141
            $nodeprot = $nodeprots->item($i);
142
            $protver = $nodeprot->getAttribute("versao");
143
            $chaveProt = $nodeprot->getElementsByTagName("chMDFe")->item(0)->nodeValue;
144
            $digValueProt = $nodeprot->getElementsByTagName("digVal")->item(0)->nodeValue;
145
            $infProt = $nodeprot->getElementsByTagName("infProt")->item(0);
146
            if ($digValueMDFe == $digValueProt && $chaveMDFe == $chaveProt) {
147
                break;
148
            }
149
        }
150
        if ($digValueMDFe != $digValueProt) {
151
            $msg = "Inconsistência! O DigestValue do MDFe não combina com o"
152
                . " do digVal do protocolo indicado!";
153
            throw new Exception\RuntimeException($msg);
154
        }
155
        if ($chaveMDFe != $chaveProt) {
156
            $msg = "O protocolo indicado pertence a outro MDFe. Os números das chaves não combinam !";
157
            throw new Exception\RuntimeException($msg);
158
        }
159
        //cria a MDFe processada com a tag do protocolo
160
        $procmdfe = new \DOMDocument('1.0', 'utf-8');
161
        $procmdfe->formatOutput = false;
162
        $procmdfe->preserveWhiteSpace = false;
163
        //cria a tag mdfeProc
164
        $mdfeProc = $procmdfe->createElement('mdfeProc');
165
        $procmdfe->appendChild($mdfeProc);
166
        //estabele o atributo de versão
167
        $mdfeProcAtt1 = $mdfeProc->appendChild($procmdfe->createAttribute('versao'));
168
        $mdfeProcAtt1->appendChild($procmdfe->createTextNode($protver));
169
        //estabelece o atributo xmlns
170
        $mdfeProcAtt2 = $mdfeProc->appendChild($procmdfe->createAttribute('xmlns'));
171
        $mdfeProcAtt2->appendChild($procmdfe->createTextNode($this->urlPortal));
172
        //inclui a tag MDFe
173
        $node = $procmdfe->importNode($nodemdfe, true);
174
        $mdfeProc->appendChild($node);
175
        //cria tag protMDFe
176
        $protMDFe = $procmdfe->createElement('protMDFe');
177
        $mdfeProc->appendChild($protMDFe);
178
        //estabele o atributo de versão
179
        $protMDFeAtt1 = $protMDFe->appendChild($procmdfe->createAttribute('versao'));
180
        $protMDFeAtt1->appendChild($procmdfe->createTextNode($versao));
181
        //cria tag infProt
182
        $nodep = $procmdfe->importNode($infProt, true);
183
        $protMDFe->appendChild($nodep);
184
        //salva o xml como string em uma variável
185
        $procXML = $procmdfe->saveXML();
186
        //remove as informações indesejadas
187
        $procXML = Strings::clearProt($procXML);
188 View Code Duplication
        if ($saveFile) {
189
            $filename = "$chaveMDFe-protMDFe.xml";
190
            $this->zGravaFile(
191
                'mdfe',
192
                $tpAmb,
193
                $filename,
194
                $procXML,
195
                'enviadas'.DIRECTORY_SEPARATOR.'aprovadas',
196
                $anomes
197
            );
198
        }
199
        return $procXML;
200
    }
201
202
    /**
203
     * addCancelamento
204
     * Adiciona a tga de cancelamento a uma MDFe já autorizada
205
     * NOTA: não é requisito da SEFAZ, mas auxilia na identificação das MDFe que foram canceladas
206
     *
207
     * @param  string $pathMDFefile
208
     * @param  string $pathCancfile
209
     * @param  bool   $saveFile
210
     * @return string
211
     * @throws Exception\RuntimeException
212
     */
213
    public function addCancelamento($pathMDFefile = '', $pathCancfile = '', $saveFile = false)
214
    {
215
        $procXML = '';
216
        //carrega a MDFe
217
        $docmdfe = new Dom();
218
        $docmdfe->loadXMLFile($pathMDFefile);
219
        $nodemdfe = $docmdfe->getNode('MDFe', 0);
220
        if ($nodemdfe == '') {
221
            $msg = "O arquivo indicado como MDFe não é um xml de MDFe!";
222
            throw new Exception\RuntimeException($msg);
223
        }
224
        $proMDFe = $docmdfe->getNode('protMDFe');
225
        if ($proMDFe == '') {
226
            $msg = "O MDFe não está protocolado ainda!!";
227
            throw new Exception\RuntimeException($msg);
228
        }
229
        $chaveMDFe = $proMDFe->getElementsByTagName('chMDFe')->item(0)->nodeValue;
230
        //$nProtMDFe = $proMDFe->getElementsByTagName('nProt')->item(0)->nodeValue;
231
        $tpAmb = $docmdfe->getNodeValue('tpAmb');
232
        $anomes = date(
233
            'Ym',
234
            DateTime::convertSefazTimeToTimestamp($docmdfe->getNodeValue('dhEmi'))
235
        );
236
        //carrega o cancelamento
237
        //pode ser um evento ou resultado de uma consulta com multiplos eventos
238
        $doccanc = new Dom();
239
        $doccanc->loadXMLFile($pathCancfile);
240
        $eventos = $doccanc->getElementsByTagName('infEvento');
241
        foreach ($eventos as $evento) {
242
            //evento
243
            $cStat = $evento->getElementsByTagName('cStat')->item(0)->nodeValue;
244
            $tpAmb = $evento->getElementsByTagName('tpAmb')->item(0)->nodeValue;
245
            $chaveEvento = $evento->getElementsByTagName('chMDFe')->item(0)->nodeValue;
246
            $tpEvento = $evento->getElementsByTagName('tpEvento')->item(0)->nodeValue;
247
            //$nProtEvento = $evento->getElementsByTagName('nProt')->item(0)->nodeValue;
248
            //verifica se conferem os dados
249
            //cStat = 135 ==> evento homologado
250
            //tpEvento = 110111 ==> Cancelamento
251
            //chave do evento == chave da NFe
252
            //protocolo do evento ==  protocolo da NFe
253
            if ($cStat == '135'
254
                && $tpEvento == '110111'
255
                && $chaveEvento == $chaveMDFe
256
            ) {
257
                $proMDFe->getElementsByTagName('cStat')->item(0)->nodeValue = '101';
258
                $proMDFe->getElementsByTagName('xMotivo')->item(0)->nodeValue = 'Cancelamento de MDF-e homologado';
259
                $procXML = $docmdfe->saveXML();
260
                //remove as informações indesejadas
261
                $procXML = Strings::clearProt($procXML);
262 View Code Duplication
                if ($saveFile) {
263
                    $filename = "$chaveMDFe-protMDFe.xml";
264
                    $this->zGravaFile(
265
                        'mdfe',
266
                        $tpAmb,
267
                        $filename,
268
                        $procXML,
269
                        'enviadas'.DIRECTORY_SEPARATOR.'aprovadas',
270
                        $anomes
271
                    );
272
                }
273
                break;
274
            }
275
        }
276
        return (string) $procXML;
277
    }
278
279
280
    /**
281
     * verificaValidade
282
     *
283
     * @param  string $pathXmlFile
284
     * @param  array  $aRetorno
285
     * @return boolean
286
     * @throws Exception\InvalidArgumentException
287
     */
288
    public function verificaValidade($pathXmlFile = '', &$aRetorno = array())
289
    {
290
        $aRetorno = array();
291
        if (!file_exists($pathXmlFile)) {
292
            $msg = "Arquivo não localizado!!";
293
            throw new Exception\InvalidArgumentException($msg);
294
        }
295
        //carrega a MDFe
296
        $xml = Files\FilesFolders::readFile($pathXmlFile);
297
        $this->oCertificate->verifySignature($xml, 'infMDFe');
298
        //obtem o chave da MDFe
299
        $docmdfe = new Dom();
300
        $docmdfe->loadXMLFile($pathXmlFile);
301
        $tpAmb = $docmdfe->getNodeValue('tpAmb');
302
        $chMDFe  = $docmdfe->getChave('infMDFe');
303
        $this->sefazConsultaChave($chMDFe, $tpAmb, $aRetorno);
304
        if ($aRetorno['cStat'] != '100') {
305
            return false;
306
        }
307
        return true;
308
    }
309
310
    /**
311
     * assina
312
     *
313
     * @param  string  $xml
314
     * @param  boolean $saveFile
315
     * @return string
316
     * @throws Exception\RuntimeException
317
     */
318
    public function assina($xml = '', $saveFile = false)
319
    {
320
        return $this->assinaDoc($xml, 'mdfe', 'infMDFe', $saveFile);
321
    }
322
323
    /**
324
     * sefazEnviaLote
325
     *
326
     * @param    string $xml
327
     * @param    string $tpAmb
328
     * @param    string $idLote
329
     * @param    array  $aRetorno
330
     * @return   string
331
     * @throws   Exception\InvalidArgumentException
332
     * @throws   Exception\RuntimeException
333
     * @internal function zLoadServico (Common\Base\BaseTools)
334
     */
335
    public function sefazEnviaLote(
336
        $xml,
337
        $tpAmb = '2',
338
        $idLote = '',
339
        &$aRetorno = array()
340
    ) {
341
        if (empty($xml)) {
342
            $msg = "Pelo menos uma MDFe deve ser informada.";
343
            throw new Exception\InvalidArgumentException($msg);
344
        }
345
        $sxml = preg_replace("/<\?xml.*\?>/", "", $xml);
346
        $siglaUF = $this->aConfig['siglaUF'];
347
        if ($tpAmb == '') {
348
            $tpAmb = $this->aConfig['tpAmb'];
349
        }
350
        if ($idLote == '') {
351
            $idLote = LotNumber::geraNumLote(15);
352
        }
353
        //carrega serviço
354
        $servico = 'MDFeRecepcao';
355
        $this->zLoadServico(
356
            'mdfe',
357
            $servico,
358
            $siglaUF,
359
            $tpAmb
360
        );
361
        if ($this->urlService == '') {
362
            $msg = "O envio de lote não está disponível na SEFAZ $siglaUF!!!";
363
            throw new Exception\RuntimeException($msg);
364
        }
365
        //montagem dos dados da mensagem SOAP
366
        $cons = "<enviMDFe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
367
                . "<idLote>$idLote</idLote>$sxml</enviMDFe>";
368
        //valida a mensagem com o xsd
369
        //if (! $this->zValidMessage($cons, 'mdfe', 'enviMDFe', $version)) {
370
        //    $msg = 'Falha na validação. '.$this->error;
371
        //    throw new Exception\RuntimeException($msg);
372
        //}
373
        //montagem dos dados da mensagem SOAP
374
        $body = "<mdfeDadosMsg xmlns=\"$this->urlNamespace\">$cons</mdfeDadosMsg>";
375
        $method = $this->urlMethod;
376
        //envia a solicitação via SOAP
377
        $retorno = $this->oSoap->send($this->urlService, $this->urlNamespace, $this->urlHeader, $body, $method);
378
        $lastMsg = $this->oSoap->lastMsg;
379
        $this->soapDebug = $this->oSoap->soapDebug;
380
        //salva mensagens
381
        $filename = "$idLote-enviMDFe.xml";
382
        $this->zGravaFile('mdfe', $tpAmb, $filename, $lastMsg);
383
        $filename = "$idLote-retEnviMDFe.xml";
384
        $this->zGravaFile('mdfe', $tpAmb, $filename, $retorno);
385
        //tratar dados de retorno
386
        $aRetorno = Response::readReturnSefaz($servico, $retorno);
387
        return (string) $retorno;
388
    }
389
390
    /**
391
     * sefazConsultaRecibo
392
     *
393
     * @param    string $recibo
394
     * @param    string $tpAmb
395
     * @param    array  $aRetorno
396
     * @return   string
397
     * @throws   Exception\InvalidArgumentException
398
     * @throws   Exception\RuntimeException
399
     * @internal function zLoadServico (Common\Base\BaseTools)
400
     */
401
    public function sefazConsultaRecibo($recibo = '', $tpAmb = '2', &$aRetorno = array())
402
    {
403
        if ($recibo == '') {
404
            $msg = "Deve ser informado um recibo.";
405
            throw new Exception\InvalidArgumentException($msg);
406
        }
407
        if ($tpAmb == '') {
408
            $tpAmb = $this->aConfig['tpAmb'];
409
        }
410
        $siglaUF = $this->aConfig['siglaUF'];
411
        //carrega serviço
412
        $servico = 'MDFeRetRecepcao';
413
        $this->zLoadServico(
414
            'mdfe',
415
            $servico,
416
            $siglaUF,
417
            $tpAmb
418
        );
419
        if ($this->urlService == '') {
420
            $msg = "A consulta de MDFe não está disponível na SEFAZ $siglaUF!!!";
421
            throw new Exception\RuntimeException($msg);
422
        }
423
        $cons = "<consReciMDFe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
424
            . "<tpAmb>$tpAmb</tpAmb>"
425
            . "<nRec>$recibo</nRec>"
426
            . "</consReciMDFe>";
427
        //valida a mensagem com o xsd
428
        //if (! $this->zValidMessage($cons, 'mdfe', 'consReciMDFe', $version)) {
429
        //    $msg = 'Falha na validação. '.$this->error;
430
        //    throw new Exception\RuntimeException($msg);
431
        //}
432
        //montagem dos dados da mensagem SOAP
433
        $body = "<mdfeDadosMsg xmlns=\"$this->urlNamespace\">$cons</mdfeDadosMsg>";
434
        //envia a solicitação via SOAP
435
        $retorno = $this->oSoap->send(
436
            $this->urlService,
437
            $this->urlNamespace,
438
            $this->urlHeader,
439
            $body,
440
            $this->urlMethod
441
        );
442
        $lastMsg = $this->oSoap->lastMsg;
443
        $this->soapDebug = $this->oSoap->soapDebug;
444
        //salva mensagens
445
        $filename = "$recibo-consReciMDFe.xml";
446
        $this->zGravaFile('mdfe', $tpAmb, $filename, $lastMsg);
447
        $filename = "$recibo-retConsReciMDFe.xml";
448
        $this->zGravaFile('mdfe', $tpAmb, $filename, $retorno);
449
        //tratar dados de retorno
450
        $aRetorno = Response::readReturnSefaz($servico, $retorno);
451
        return (string) $retorno;
452
    }
453
454
    /**
455
     * sefazConsultaChave
456
     * Consulta o status da MDFe pela chave de 44 digitos
457
     *
458
     * @param    string $chave
459
     * @param    string $tpAmb
460
     * @param    array  $aRetorno
461
     * @return   string
462
     * @throws   Exception\InvalidArgumentException
463
     * @throws   Exception\RuntimeException
464
     * @internal function zLoadServico (Common\Base\BaseTools)
465
     */
466
    public function sefazConsultaChave($chave = '', $tpAmb = '2', &$aRetorno = array())
467
    {
468
        $chMDFe = preg_replace('/[^0-9]/', '', $chave);
469
        if (strlen($chMDFe) != 44) {
470
            $msg = "Uma chave de 44 dígitos da MDFe deve ser passada.";
471
            throw new Exception\InvalidArgumentException($msg);
472
        }
473
        if ($tpAmb == '') {
474
            $tpAmb = $this->aConfig['tpAmb'];
475
        }
476
        $cUF = substr($chMDFe, 0, 2);
477
        $siglaUF = self::zGetSigla($cUF);
478
        //carrega serviço
479
        $servico = 'MDFeConsulta';
480
        $this->zLoadServico(
481
            'mdfe',
482
            $servico,
483
            $siglaUF,
484
            $tpAmb
485
        );
486
        if ($this->urlService == '') {
487
            $msg = "A consulta de MDFe não está disponível na SEFAZ $siglaUF!!!";
488
            throw new Exception\RuntimeException($msg);
489
        }
490
        $cons = "<consSitMDFe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
491
                . "<tpAmb>$tpAmb</tpAmb>"
492
                . "<xServ>CONSULTAR</xServ>"
493
                . "<chMDFe>$chMDFe</chMDFe>"
494
                . "</consSitMDFe>";
495
        //valida a mensagem com o xsd
496
        //if (! $this->zValidMessage($cons, 'mdfe', 'consSitMDFe', $version)) {
497
        //    $msg = 'Falha na validação. '.$this->error;
498
        //    throw new Exception\RuntimeException($msg);
499
        //}
500
        //montagem dos dados da mensagem SOAP
501
        $body = "<mdfeDadosMsg xmlns=\"$this->urlNamespace\">$cons</mdfeDadosMsg>";
502
        //envia a solicitação via SOAP
503
        $retorno = $this->oSoap->send(
504
            $this->urlService,
505
            $this->urlNamespace,
506
            $this->urlHeader,
507
            $body,
508
            $this->urlMethod
509
        );
510
        $lastMsg = $this->oSoap->lastMsg;
511
        $this->soapDebug = $this->oSoap->soapDebug;
512
        //salva mensagens
513
        $filename = "$chMDFe-consSitMDFe.xml";
514
        $this->zGravaFile('mdfe', $tpAmb, $filename, $lastMsg);
515
        $filename = "$chMDFe-retConsSitMDFe.xml";
516
        $this->zGravaFile('mdfe', $tpAmb, $filename, $retorno);
517
        //tratar dados de retorno
518
        $aRetorno = Response::readReturnSefaz($servico, $retorno);
519
        return (string) $retorno;
520
    }
521
522
    /**
523
     * sefazStatus
524
     * Verifica o status do serviço da SEFAZ
525
     * NOTA : Este serviço será removido no futuro, segundo da Receita/SEFAZ devido
526
     * ao excesso de mau uso !!!
527
     *
528
     * @param    string $siglaUF  sigla da unidade da Federação
529
     * @param    string $tpAmb    tipo de ambiente 1-produção e 2-homologação
530
     * @param    array  $aRetorno parametro passado por referencia contendo a resposta da consulta em um array
531
     * @return   mixed string XML do retorno do webservice, ou false se ocorreu algum erro
532
     * @throws   Exception\RuntimeException
533
     * @internal function zLoadServico (Common\Base\BaseTools)
534
     */
535 View Code Duplication
    public function sefazStatus($siglaUF = '', $tpAmb = '2', &$aRetorno = array())
536
    {
537
        if ($tpAmb == '') {
538
            $tpAmb = $this->aConfig['tpAmb'];
539
        }
540
        if ($siglaUF == '') {
541
            $siglaUF = $this->aConfig['siglaUF'];
542
        }
543
        //carrega serviço
544
        $servico = 'MDFeStatusServico';
545
        $this->zLoadServico(
546
            'mdfe',
547
            $servico,
548
            $siglaUF,
549
            $tpAmb
550
        );
551
        if ($this->urlService == '') {
552
            $msg = "O status não está disponível na SEFAZ $siglaUF!!!";
553
            throw new Exception\RuntimeException($msg);
554
        }
555
        $cons = "<consStatServMDFe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
556
            . "<tpAmb>$tpAmb</tpAmb>"
557
            . "<xServ>STATUS</xServ></consStatServMDFe>";
558
        //valida mensagem com xsd
559
        //if (! $this->zValidMessage($cons, 'mdfe', 'consStatServMDFe', $version)) {
560
        //    $msg = 'Falha na validação. '.$this->error;
561
        //    throw new Exception\RuntimeException($msg);
562
        //}
563
        //montagem dos dados da mensagem SOAP
564
        $body = "<mdfeDadosMsg xmlns=\"$this->urlNamespace\">$cons</mdfeDadosMsg>";
565
        //consome o webservice e verifica o retorno do SOAP
566
        $retorno = $this->oSoap->send(
567
            $this->urlService,
568
            $this->urlNamespace,
569
            $this->urlHeader,
570
            $body,
571
            $this->urlMethod
572
        );
573
        $lastMsg = $this->oSoap->lastMsg;
574
        $this->soapDebug = $this->oSoap->soapDebug;
575
        $datahora = date('Ymd_His');
576
        $filename = $siglaUF."_"."$datahora-consStatServ.xml";
577
        $this->zGravaFile('mdfe', $tpAmb, $filename, $lastMsg);
578
        $filename = $siglaUF."_"."$datahora-retConsStatServ.xml";
579
        $this->zGravaFile('mdfe', $tpAmb, $filename, $retorno);
580
        //tratar dados de retorno
581
        $aRetorno = Response::readReturnSefaz($servico, $retorno);
582
        return (string) $retorno;
583
    }
584
585
    /**
586
     * sefazCancela
587
     *
588
     * @param  string $chave
589
     * @param  string $tpAmb
590
     * @param  string $xJust
591
     * @param  string $nProt
592
     * @param  array  $aRetorno
593
     * @return string
594
     * @throws Exception\InvalidArgumentException
595
     */
596
    public function sefazCancela(
597
        $chave = '',
598
        $tpAmb = '2',
599
        $nSeqEvento = '1',
600
        $nProt = '',
601
        $xJust = '',
602
        &$aRetorno = array()
603
    ) {
604
        if ($tpAmb == '') {
605
            $tpAmb = $this->aConfig['tpAmb'];
606
        }
607
        $chMDFe = preg_replace('/[^0-9]/', '', $chave);
608
        $nProt = preg_replace('/[^0-9]/', '', $nProt);
609
        $xJust = Strings::cleanString($xJust);
610
        if (strlen($chMDFe) != 44) {
611
            $msg = "Uma chave de MDFe válida não foi passada como parâmetro $chMDFe.";
612
            throw new Exception\InvalidArgumentException($msg);
613
        }
614
        if ($nProt == '') {
615
            $msg = "Não foi passado o numero do protocolo!!";
616
            throw new Exception\InvalidArgumentException($msg);
617
        }
618
        if (strlen($xJust) < 15 || strlen($xJust) > 255) {
619
            $msg = "A justificativa deve ter pelo menos 15 digitos e no máximo 255!!";
620
            throw new Exception\InvalidArgumentException($msg);
621
        }
622
        $siglaUF = self::zGetSigla(substr($chMDFe, 0, 2));
623
        //estabelece o codigo do tipo de evento CANCELAMENTO
624
        $tpEvento = '110111';
625
        if ($nSeqEvento == '') {
626
            $nSeqEvento = '1';
627
        }
628
        $tagAdic = "<evCancMDFe><descEvento>Cancelamento</descEvento>"
629
                . "<nProt>$nProt</nProt><xJust>$xJust</xJust></evCancMDFe>";
630
        $retorno = $this->zSefazEvento($siglaUF, $chMDFe, $tpAmb, $tpEvento, $nSeqEvento, $tagAdic);
631
        $aRetorno = $this->aLastRetEvent;
632
        return $retorno;
633
    }
634
635
    /**
636
     * sefazEncerra
637
     *
638
     * @param  string $chave
639
     * @param  string $tpAmb
640
     * @param  string $nProt
641
     * @param  string $cUF
642
     * @param  string $cMun
643
     * @param  array  $aRetorno
644
     * @return string
645
     * @throws Exception\InvalidArgumentException
646
     */
647 View Code Duplication
    public function sefazEncerra(
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
648
        $chave = '',
649
        $tpAmb = '2',
650
        $nSeqEvento = '1',
651
        $nProt = '',
652
        $cUF = '',
653
        $cMun = '',
654
        &$aRetorno = array()
655
    ) {
656
        if ($tpAmb == '') {
657
            $tpAmb = $this->aConfig['tpAmb'];
658
        }
659
        $chMDFe = preg_replace('/[^0-9]/', '', $chave);
660
        $nProt = preg_replace('/[^0-9]/', '', $nProt);
661
        if (strlen($chMDFe) != 44) {
662
            $msg = "Uma chave de MDFe válida não foi passada como parâmetro $chMDFe.";
663
            throw new Exception\InvalidArgumentException($msg);
664
        }
665
        if ($nProt == '') {
666
            $msg = "Não foi passado o numero do protocolo!!";
667
            throw new Exception\InvalidArgumentException($msg);
668
        }
669
        $siglaUF = self::zGetSigla(substr($chMDFe, 0, 2));
670
        //estabelece o codigo do tipo de evento CANCELAMENTO
671
        $tpEvento = '110112';
672
        if ($nSeqEvento == '') {
673
            $nSeqEvento = '1';
674
        }
675
        $dtEnc = date('Y-m-d');
676
        $tagAdic = "<evEncMDFe><descEvento>Encerramento</descEvento>"
677
                . "<nProt>$nProt</nProt><dtEnc>$dtEnc</dtEnc><cUF>$cUF</cUF>"
678
                . "<cMun>$cMun</cMun></evEncMDFe>";
679
        $retorno = $this->zSefazEvento($siglaUF, $chMDFe, $tpAmb, $tpEvento, $nSeqEvento, $tagAdic);
680
        $aRetorno = $this->aLastRetEvent;
681
        return $retorno;
682
    }
683
684
    /**
685
     * sefazIncluiCondutor
686
     *
687
     * @param  string $chave
688
     * @param  string $tpAmb
689
     * @param  string $nSeqEvento
690
     * @param  string $xNome
691
     * @param  string $cpf
692
     * @param  array  $aRetorno
693
     * @return string
694
     * @throws Exception\InvalidArgumentException
695
     */
696 View Code Duplication
    public function sefazIncluiCondutor(
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
697
        $chave = '',
698
        $tpAmb = '2',
699
        $nSeqEvento = '1',
700
        $xNome = '',
701
        $cpf = '',
702
        &$aRetorno = array()
703
    ) {
704
        if ($tpAmb == '') {
705
            $tpAmb = $this->aConfig['tpAmb'];
706
        }
707
        $chMDFe = preg_replace('/[^0-9]/', '', $chave);
708
        $nProt = preg_replace('/[^0-9]/', '', $nProt);
0 ignored issues
show
The variable $nProt seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
709
        if (strlen($chMDFe) != 44) {
710
            $msg = "Uma chave de MDFe válida não foi passada como parâmetro $chMDFe.";
711
            throw new Exception\InvalidArgumentException($msg);
712
        }
713
        if ($nProt == '') {
714
            $msg = "Não foi passado o numero do protocolo!!";
715
            throw new Exception\InvalidArgumentException($msg);
716
        }
717
        $siglaUF = self::zGetSigla(substr($chMDFe, 0, 2));
718
        //estabelece o codigo do tipo de evento Inclusão de condutor
719
        $tpEvento = '110114';
720
        if ($nSeqEvento == '') {
721
            $nSeqEvento = '1';
722
        }
723
        //monta mensagem
724
        $tagAdic = "<evIncCondutorMDFe><descEvento>Inclusao Condutor</descEvento>"
725
                . "<Condutor><xNome>$xNome</xNome><CPF>$cpf</CPF></Condutor></evIncCondutorMDFe>";
726
727
        $cOrgao = '';
728
729
        $retorno = $this->zSefazEvento($siglaUF, $chMDFe, $cOrgao, $tpAmb, $tpEvento, $nSeqEvento, $tagAdic);
730
        $aRetorno = $this->aLastRetEvent;
731
        return $retorno;
732
    }
733
734
    /**
735
     * sefazConsultaNaoEncerrados
736
     *
737
     * @param  string $tpAmb
738
     * @param  string $cnpj
739
     * @param  array  $aRetorno
740
     * @return string
741
     * @throws Exception\RuntimeException
742
     */
743 View Code Duplication
    public function sefazConsultaNaoEncerrados($tpAmb = '2', $cnpj = '', &$aRetorno = array())
744
    {
745
        if ($tpAmb == '') {
746
            $tpAmb = $this->aConfig['tpAmb'];
747
        }
748
        if ($cnpj == '') {
749
            $cnpj = $this->aConfig['cnpj'];
750
        }
751
        $siglaUF = $this->aConfig['siglaUF'];
752
        //carrega serviço
753
        $servico = 'MDFeConsNaoEnc';
754
        $this->zLoadServico(
755
            'mdfe',
756
            $servico,
757
            $siglaUF,
758
            $tpAmb
759
        );
760
        if ($this->urlService == '') {
761
            $msg = "O serviço não está disponível na SEFAZ $siglaUF!!!";
762
            throw new Exception\RuntimeException($msg);
763
        }
764
        $cons = "<consMDFeNaoEnc xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
765
            . "<tpAmb>$tpAmb</tpAmb>"
766
            . "<xServ>CONSULTAR NÃO ENCERRADOS</xServ><CNPJ>$cnpj</CNPJ></consMDFeNaoEnc>";
767
        //valida mensagem com xsd
768
        //if (! $this->zValidMessage($cons, 'mdfe', 'consMDFeNaoEnc', $version)) {
769
        //    $msg = 'Falha na validação. '.$this->error;
770
        //    throw new Exception\RuntimeException($msg);
771
        //}
772
        //montagem dos dados da mensagem SOAP
773
        $body = "<mdefDadosMsg xmlns=\"$this->urlNamespace\">$cons</mdfeDadosMsg>";
774
        //consome o webservice e verifica o retorno do SOAP
775
        $retorno = $this->oSoap->send(
776
            $this->urlService,
777
            $this->urlNamespace,
778
            $this->urlHeader,
779
            $body,
780
            $this->urlMethod
781
        );
782
        $lastMsg = $this->oSoap->lastMsg;
783
        $this->soapDebug = $this->oSoap->soapDebug;
784
        $datahora = date('Ymd_His');
785
        $filename = $siglaUF."_"."$datahora-consNaoEnc.xml";
786
        $this->zGravaFile('mdfe', $tpAmb, $filename, $lastMsg);
787
        $filename = $siglaUF."_"."$datahora-retConsNaoEnc.xml";
788
        $this->zGravaFile('mdfe', $tpAmb, $filename, $retorno);
789
        //tratar dados de retorno
790
        $aRetorno = Response::readReturnSefaz($servico, $retorno);
791
        return (string) $retorno;
792
    }
793
794
    /**
795
     * zSefazEvento
796
     *
797
     * @param    string $siglaUF
798
     * @param    string $chave
799
     * @param    string $cOrgao
800
     * @param    string $tpAmb
801
     * @param    string $tpEvento
802
     * @param    string $nSeqEvento
803
     * @param    string $tagAdic
804
     * @return   string
805
     * @throws   Exception\RuntimeException
806
     * @internal function zLoadServico (Common\Base\BaseTools)
807
     */
808
    protected function zSefazEvento(
809
        $siglaUF = '',
810
        $chave = '',
811
        $cOrgao = '',
812
        $tpAmb = '2',
813
        $tpEvento = '',
814
        $nSeqEvento = '1',
815
        $tagAdic = ''
816
    ) {
817
        if ($tpAmb == '') {
818
            $tpAmb = $this->aConfig['tpAmb'];
819
        }
820
        //carrega serviço
821
        $servico = 'MDFeRecepcaoEvento';
822
        $this->zLoadServico(
823
            'mdfe',
824
            $servico,
825
            $siglaUF,
826
            $tpAmb
827
        );
828
        if ($this->urlService == '') {
829
            $msg = "A recepção de eventos não está disponível na SEFAZ $siglaUF!!!";
830
            throw new Exception\RuntimeException($msg);
831
        }
832
        $aRet = $this->zTpEv($tpEvento);
833
        $aliasEvento = $aRet['alias'];
834
        $cnpj = $this->aConfig['cnpj'];
835
        $dhEvento = (string) str_replace(' ', 'T', date('Y-m-d H:i:s'));
836
        $sSeqEvento = str_pad($nSeqEvento, 2, "0", STR_PAD_LEFT);
837
        $eventId = "ID".$tpEvento.$chave.$sSeqEvento;
838
        if ($cOrgao == '') {
839
            $cOrgao = $this->urlcUF;
840
        }
841
        $mensagem = "<eventoMDFe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
842
            . "<infEvento Id=\"$eventId\">"
843
            . "<cOrgao>$cOrgao</cOrgao>"
844
            . "<tpAmb>$tpAmb</tpAmb>"
845
            . "<CNPJ>$cnpj</CNPJ>"
846
            . "<chMDFe>$chave</chMDFe>"
847
            . "<dhEvento>$dhEvento</dhEvento>"
848
            . "<tpEvento>$tpEvento</tpEvento>"
849
            . "<nSeqEvento>$nSeqEvento</nSeqEvento>"
850
            . "<detEvento versaoEvento=\"$this->urlVersion\">"
851
            . "$tagAdic"
852
            . "</detEvento>"
853
            . "</infEvento>"
854
            . "</eventoMDFe>";
855
        //assinatura dos dados
856
        $signedMsg = $this->oCertificate->signXML($mensagem, 'infEvento');
857
        $cons = Strings::clearXml($signedMsg, true);
858
        //valida mensagem com xsd
859
        //no caso do evento nao tem xsd organizado, esta fragmentado
860
        //e por vezes incorreto por isso essa validação está desabilitada
861
        //if (! $this->zValidMessage($cons, 'mdfe', 'eventoMDFe', $version)) {
862
        //    $msg = 'Falha na validação. '.$this->error;
863
        //    throw new Exception\RuntimeException($msg);
864
        //}
865
        $body = "<mdfeDadosMsg xmlns=\"$this->urlNamespace\">$cons</mdfeDadosMsg>";
866
        //envia a solicitação via SOAP
867
        $retorno = $this->oSoap->send(
868
            $this->urlService,
869
            $this->urlNamespace,
870
            $this->urlHeader,
871
            $body,
872
            $this->urlMethod
873
        );
874
        $lastMsg = $this->oSoap->lastMsg;
875
        $this->soapDebug = $this->oSoap->soapDebug;
876
        //salva mensagens
877
        $filename = "$chave-$aliasEvento-eventoMDFe.xml";
878
        $this->zGravaFile('mdfe', $tpAmb, $filename, $lastMsg);
879
        $filename = "$chave-$aliasEvento-retEventoMDFe.xml";
880
        $this->zGravaFile('mdfe', $tpAmb, $filename, $retorno);
881
        //tratar dados de retorno
882
        $this->aLastRetEvent = Response::readReturnSefaz($servico, $retorno);
883
        return (string) $retorno;
884
    }
885
886
    /**
887
     * zTpEv
888
     *
889
     * @param  string $tpEvento
890
     * @return array
891
     * @throws Exception\RuntimeException
892
     */
893
    private function zTpEv($tpEvento = '')
894
    {
895
        //montagem dos dados da mensagem SOAP
896
        switch ($tpEvento) {
897
            case '110111':
898
                //cancelamento
899
                $aliasEvento = 'CancMDFe';
900
                $descEvento = 'Cancelamento';
901
                break;
902
            case '110112':
903
                //encerramento
904
                $aliasEvento = 'EncMDFe';
905
                $descEvento = 'Encerramento';
906
                break;
907
            case '110114':
908
                //inclusao do condutor
909
                $aliasEvento = 'EvIncCondut';
910
                $descEvento = 'Inclusao Condutor';
911
                break;
912
            default:
913
                $msg = "O código do tipo de evento informado não corresponde a "
914
                . "nenhum evento estabelecido.";
915
                throw new Exception\RuntimeException($msg);
916
        }
917
        return array('alias' => $aliasEvento, 'desc' => $descEvento);
918
    }
919
920
    /**
921
     * validarXml
922
     * Valida qualquer xml do sistema MDFe com seu xsd
923
     * NOTA: caso não exista um arquivo xsd apropriado retorna false
924
     *
925
     * @param  string $xml path ou conteudo do xml
926
     * @return boolean
927
     */
928
    public function validarXml($xml = '')
929
    {
930
        $aResp = array();
931
        $schem = Identify::identificar($xml, $aResp);
932
        if ($schem == '') {
933
            return true;
934
        }
935
        $xsdFile = $aResp['Id'].'_v'.$aResp['versao'].'.xsd';
936
        $xsdPath = NFEPHP_ROOT.DIRECTORY_SEPARATOR .
937
            'schemes' .
938
            DIRECTORY_SEPARATOR .
939
            $this->aConfig['schemesMDFe'] .
940
            DIRECTORY_SEPARATOR .
941
            $xsdFile;
942
        if (! is_file($xsdPath)) {
943
            $this->errors[] = "O arquivo XSD $xsdFile não foi localizado.";
944
            return false;
945
        }
946
        if (! ValidXsd::validar($aResp['xml'], $xsdPath)) {
947
            $this->errors[] = ValidXsd::$errors;
948
            return false;
949
        }
950
        return true;
951
    }
952
}
953