Passed
Push — master ( 52e4d7...cef415 )
by Roberto
01:14 queued 11s
created

Tools::sefazCancelaComprovanteEntrega()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 0
cts 19
cp 0
rs 9.568
c 0
b 0
f 0
cc 3
nc 2
nop 1
crap 12
1
<?php
2
3
namespace NFePHP\NFe;
4
5
/**
6
 * Class responsible for communication with SEFAZ extends
7
 * NFePHP\NFe\Common\Tools
8
 *
9
 * @category  NFePHP
10
 * @package   NFePHP\NFe\Tools
11
 * @copyright NFePHP Copyright (c) 2008-2020
12
 * @license   http://www.gnu.org/licenses/lgpl.txt LGPLv3+
13
 * @license   https://opensource.org/licenses/MIT MIT
14
 * @license   http://www.gnu.org/licenses/gpl.txt GPLv3+
15
 * @author    Roberto L. Machado <linux.rlm at gmail dot com>
16
 * @link      http://github.com/nfephp-org/sped-nfe for the canonical source repository
17
 */
18
19
use NFePHP\Common\Strings;
20
use NFePHP\Common\Signer;
21
use NFePHP\Common\UFList;
22
use NFePHP\NFe\Common\Tools as ToolsCommon;
23
use RuntimeException;
24
use InvalidArgumentException;
25
26
class Tools extends ToolsCommon
27
{
28
    const EVT_CONFIRMACAO = 210200; //only one per nfe seq=n
29
    const EVT_CIENCIA = 210210; //only one per nfe seq=1
30
    const EVT_DESCONHECIMENTO = 210220; //only one per nfe seq=n
31
    const EVT_NAO_REALIZADA = 210240; //only one per nfe but seq=n
32
    const EVT_CCE = 110110; //many seq=n
33
    const EVT_CANCELA = 110111; //only seq=1
34
    const EVT_CANCELASUBSTITUICAO = 110112;
35
    const EVT_EPEC = 110140; //only seq=1
36
    const EVT_ATORINTERESSADO = 110150;
37
    const EVT_COMPROVANTE_ENTREGA = 110130;
38
    const EVT_CANCELAMENTO_COMPROVANTE_ENTREGA = 110131;
39
40
    /**
41
     * Request authorization to issue NFe in batch with one or more documents
42
     * @param array $aXml array of nfe's xml
43
     * @param string $idLote lote number
44
     * @param int $indSinc flag to use synchronous communication
45
     * @param bool $compactar flag to compress data with gzip
46
     * @param array $xmls array with xmls substitutes if contigency is on
47
     * @return string soap response xml
48
     * @throws InvalidArgumentException
49
     */
50
    public function sefazEnviaLote(
51
        $aXml,
52
        $idLote = '',
53
        $indSinc = 0,
54
        $compactar = false,
55
        &$xmls = []
56
    ) {
57
        if (!is_array($aXml)) {
58
            throw new InvalidArgumentException('Envia Lote: XMLs de NF-e deve ser um array!');
59
        }
60
        if ($indSinc == 1 && count($aXml) > 1) {
61
            throw new InvalidArgumentException('Envio sincrono deve ser usado para enviar '
62
                . 'uma UNICA nota por vez. Você está tentando enviar varias.');
63
        }
64
        $servico = 'NfeAutorizacao';
65
        $this->checkContingencyForWebServices($servico);
66
        if ($this->contingency->type != '') {
67
            // Em modo de contingencia esses XMLs deverão ser modificados e re-assinados e retornados
68
            // no parametro $xmls para serem armazenados pelo aplicativo pois serão alterados.
69
            foreach ($aXml as $doc) {
70
                //corrigir o xml para o tipo de contigência setado
71
                $xmls[] = $this->correctNFeForContingencyMode($doc);
72
            }
73
            $aXml = $xmls;
74
        }
75
        $ax = [];
76
        foreach ($aXml as $xml) {
77
            //verifica se o modelo do XML é o mesmo setado na classe
78
            //gera um exception se não for
79
            $this->checkModelFromXml($xml);
80
            $ax[] = trim(preg_replace("/<\?xml.*?\?>/", "", $xml));
81
        }
82
        $sxml = trim(implode("", $ax));
83
        $this->servico($servico, $this->config->siglaUF, $this->tpAmb);
84
        $request = "<enviNFe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
85
            . "<idLote>$idLote</idLote>"
86
            . "<indSinc>$indSinc</indSinc>"
87
            . "$sxml"
88
            . "</enviNFe>";
89
        $this->isValid($this->urlVersion, $request, 'enviNFe');
90
        $this->lastRequest = $request;
91
        //montagem dos dados da mensagem SOAP
92
        $parameters = ['nfeDadosMsg' => $request];
93
        $body = "<nfeDadosMsg xmlns=\"$this->urlNamespace\">$request</nfeDadosMsg>";
94
        if ($compactar) {
95
            $gzdata = base64_encode(gzencode($request, 9, FORCE_GZIP));
96
            $parameters = ['nfeDadosMsgZip' => $gzdata];
97
            $body = "<nfeDadosMsgZip xmlns=\"$this->urlNamespace\">$gzdata</nfeDadosMsgZip>";
98
        }
99
        $this->lastResponse = $this->sendRequest($body, $parameters);
100
        return $this->lastResponse;
101
    }
102
103
    /**
104
     * Check status of Batch of NFe sent by receipt of this shipment
105
     * @param string $recibo
106
     * @param int $tpAmb
107
     * @return string
108
     * @throws InvalidArgumentException
109
     */
110 1
    public function sefazConsultaRecibo($recibo, $tpAmb = null)
111
    {
112 1
        if (empty($recibo)) {
113 1
            throw new InvalidArgumentException('Consulta Recibo: numero do recibo vazio!');
114
        }
115
        if (empty($tpAmb)) {
116
            $tpAmb = $this->tpAmb;
117
        }
118
        //carrega serviço
119
        $servico = 'NfeRetAutorizacao';
120
        $this->checkContingencyForWebServices($servico);
121
        $this->servico($servico, $this->config->siglaUF, $tpAmb);
122
        if ($this->urlService == '') {
123
            $msg = "A consulta de NFe nao esta disponivel na SEFAZ {$this->config->siglaUF}!";
124
            throw new RuntimeException($msg);
125
        }
126
        $request = "<consReciNFe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
127
            . "<tpAmb>$tpAmb</tpAmb>"
128
            . "<nRec>$recibo</nRec>"
129
            . "</consReciNFe>";
130
        $this->isValid($this->urlVersion, $request, 'consReciNFe');
131
        $this->lastRequest = $request;
132
        $parameters = ['nfeDadosMsg' => $request];
133
        $body = "<nfeDadosMsg xmlns=\"$this->urlNamespace\">$request</nfeDadosMsg>";
134
        $this->lastResponse = $this->sendRequest($body, $parameters);
135
        return $this->lastResponse;
136
    }
137
138
    /**
139
     * Check the NFe status for the 44-digit key and retrieve the protocol
140
     * @param string $chave
141
     * @param int $tpAmb
142
     * @return string
143
     * @throws InvalidArgumentException
144
     */
145 3
    public function sefazConsultaChave($chave, $tpAmb = null)
146
    {
147 3
        if (empty($chave)) {
148 1
            throw new InvalidArgumentException('Consulta chave: a chave esta vazia!');
149
        }
150 2
        if (strlen($chave) != 44 || !is_numeric($chave)) {
151 2
            throw new InvalidArgumentException("Consulta chave: chave \"$chave\" invalida!");
152
        }
153
        $uf = UFList::getUFByCode(substr($chave, 0, 2));
154
        if (empty($tpAmb)) {
155
            $tpAmb = $this->tpAmb;
156
        }
157
        //carrega serviço
158
        $servico = 'NfeConsultaProtocolo';
159
        $this->checkContingencyForWebServices($servico);
160
        $this->servico($servico, $uf, $tpAmb);
161
        $request = "<consSitNFe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
162
            . "<tpAmb>$tpAmb</tpAmb>"
163
            . "<xServ>CONSULTAR</xServ>"
164
            . "<chNFe>$chave</chNFe>"
165
            . "</consSitNFe>";
166
        $this->isValid($this->urlVersion, $request, 'consSitNFe');
167
        $this->lastRequest = $request;
168
        $parameters = ['nfeDadosMsg' => $request];
169
        $body = "<nfeDadosMsg xmlns=\"$this->urlNamespace\">$request</nfeDadosMsg>";
170
        $this->lastResponse = $this->sendRequest($body, $parameters);
171
        return $this->lastResponse;
172
    }
173
174
    /**
175
     * Request to disable one or an NFe sequence of a given series
176
     * @param int $nSerie
177
     * @param int $nIni
178
     * @param int $nFin
179
     * @param string $xJust
180
     * @param int $tpAmb
181
     * @param string $ano
182
     * @return string
183
     * @throws InvalidArgumentException
184
     */
185
    public function sefazInutiliza($nSerie, $nIni, $nFin, $xJust, $tpAmb = null, $ano = null)
186
    {
187
        if (empty($nIni) || empty($nFin) || empty($xJust)) {
188
            throw new InvalidArgumentException('Inutilizacao: parametros incompletos!');
189
        }
190
        if (empty($tpAmb)) {
191
            $tpAmb = $this->tpAmb;
192
        }
193
        $xJust = Strings::replaceUnacceptableCharacters($xJust);
194
        $servico = 'NfeInutilizacao';
195
        $this->checkContingencyForWebServices($servico);
196
        //carrega serviço
197
        $this->servico($servico, $this->config->siglaUF, $tpAmb);
198
        $cnpj = $this->config->cnpj;
199
        $strAno = $ano;
200
        if (empty($ano)) {
201
            $strAno = (string) date('y');
202
        }
203
        $strSerie = str_pad($nSerie, 3, '0', STR_PAD_LEFT);
204
        $strInicio = str_pad($nIni, 9, '0', STR_PAD_LEFT);
205
        $strFinal = str_pad($nFin, 9, '0', STR_PAD_LEFT);
206
        $idInut = "ID"
207
            . $this->urlcUF
208
            . $strAno
209
            . $cnpj
210
            . $this->modelo
211
            . $strSerie
212
            . $strInicio
213
            . $strFinal;
214
        //limpa os caracteres indesejados da justificativa
215
        $xJust = Strings::replaceUnacceptableCharacters($xJust);
216
        //montagem do corpo da mensagem
217
        $msg = "<inutNFe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">" .
218
            "<infInut Id=\"$idInut\">" .
219
            "<tpAmb>$tpAmb</tpAmb>" .
220
            "<xServ>INUTILIZAR</xServ>" .
221
            "<cUF>$this->urlcUF</cUF>" .
222
            "<ano>$strAno</ano>" .
223
            "<CNPJ>$cnpj</CNPJ>" .
224
            "<mod>$this->modelo</mod>" .
225
            "<serie>$nSerie</serie>" .
226
            "<nNFIni>$nIni</nNFIni>" .
227
            "<nNFFin>$nFin</nNFFin>" .
228
            "<xJust>$xJust</xJust>" .
229
            "</infInut></inutNFe>";
230
        //assina a solicitação
231
        $request = Signer::sign(
232
            $this->certificate,
233
            $msg,
234
            'infInut',
235
            'Id',
236
            $this->algorithm,
237
            $this->canonical
238
        );
239
        $request = Strings::clearXmlString($request, true);
240
        $this->isValid($this->urlVersion, $request, 'inutNFe');
241
        $this->lastRequest = $request;
242
        $parameters = ['nfeDadosMsg' => $request];
243
        $body = "<nfeDadosMsg xmlns=\"$this->urlNamespace\">$request</nfeDadosMsg>";
244
        $this->lastResponse = $this->sendRequest($body, $parameters);
245
        return $this->lastResponse;
246
    }
247
248
    /**
249
     * Search for the registration data of an NFe issuer,
250
     * if in contingency mode this service will cause a
251
     * Exception and remember not all Sefaz have this service available,
252
     * so it will not work in some cases.
253
     * @param string $uf federation unit (abbreviation)
254
     * @param string $cnpj CNPJ number (optional)
255
     * @param string $iest IE number (optional)
256
     * @param string $cpf CPF number (optional)
257
     * @return string xml soap response
258
     * @throws InvalidArgumentException
259
     */
260
    public function sefazCadastro($uf, $cnpj = '', $iest = '', $cpf = '')
261
    {
262
        $filter = '';
263
        if (!empty($cnpj)) {
264
            $filter = "<CNPJ>$cnpj</CNPJ>";
265
        } elseif (!empty($iest)) {
266
            $filter = "<IE>$iest</IE>";
267
        } elseif (!empty($cpf)) {
268
            $filter = "<CPF>$cpf</CPF>";
269
        }
270
        if (empty($uf) || empty($filter)) {
271
            throw new InvalidArgumentException('Sigla UF esta vazia ou CNPJ+IE+CPF vazios!');
272
        }
273
        //carrega serviço
274
        $servico = 'NfeConsultaCadastro';
275
        $this->checkContingencyForWebServices($servico);
276
        $this->servico($servico, $uf, $this->tpAmb, true);
277
        $request = "<ConsCad xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
278
            . "<infCons>"
279
            . "<xServ>CONS-CAD</xServ>"
280
            . "<UF>$uf</UF>"
281
            . "$filter"
282
            . "</infCons>"
283
            . "</ConsCad>";
284
        if (strtoupper($uf) == 'MT') {
285
            $request = "<nfeDadosMsg>$request</nfeDadosMsg>" ;
286
        }
287
        $this->isValid($this->urlVersion, $request, 'consCad');
288
        $this->lastRequest = $request;
289
        $parameters = ['nfeDadosMsg' => $request];
290
        if ($this->urlVersion === '2.00') {
291
            $this->objHeader = new \SOAPHeader(
292
                $this->urlNamespace,
293
                'nfeCabecMsg',
294
                ['cUF' => $this->urlcUF, 'versaoDados' => $this->urlVersion]
295
            );
296
        }
297
        $body = "<nfeDadosMsg xmlns=\"$this->urlNamespace\">$request</nfeDadosMsg>";
298
        $this->lastResponse = $this->sendRequest($body, $parameters);
299
        return $this->lastResponse;
300
    }
301
302
    /**
303
     * Check services status SEFAZ/SVC
304
     * If $uf is empty use normal check with contingency
305
     * If $uf is NOT empty ignore contingency mode
306
     * @param string $uf  initials of federation unit
307
     * @param int $tpAmb
308
     * @return string xml soap response
309
     */
310
    public function sefazStatus($uf = '', $tpAmb = null)
311
    {
312
        if (empty($tpAmb)) {
313
            $tpAmb = $this->tpAmb;
314
        }
315
        $ignoreContingency = true;
316
        if (empty($uf)) {
317
            $uf = $this->config->siglaUF;
318
            $ignoreContingency = false;
319
        }
320
        $servico = 'NfeStatusServico';
321
        $this->checkContingencyForWebServices($servico);
322
        $this->servico($servico, $uf, $tpAmb, $ignoreContingency);
323
        $request = "<consStatServ xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
324
            . "<tpAmb>$tpAmb</tpAmb>"
325
            . "<cUF>$this->urlcUF</cUF>"
326
            . "<xServ>STATUS</xServ>"
327
            . "</consStatServ>";
328
        $this->isValid($this->urlVersion, $request, 'consStatServ');
329
        $this->lastRequest = $request;
330
        $parameters = ['nfeDadosMsg' => $request];
331
        $body = "<nfeDadosMsg xmlns=\"$this->urlNamespace\">$request</nfeDadosMsg>";
332
        $this->lastResponse = $this->sendRequest($body, $parameters);
333
        return $this->lastResponse;
334
    }
335
336
    /**
337
     * Service for the distribution of summary information and
338
     * electronic tax documents of interest to an actor.
339
     * @param integer $ultNSU  last NSU number recived
340
     * @param integer $numNSU  NSU number you wish to consult
341
     * @param string $fonte data source 'AN' and for some cases it may be 'RS'
342
     * @return string
343
     */
344
    public function sefazDistDFe($ultNSU = 0, $numNSU = 0, $fonte = 'AN')
345
    {
346
        //carrega serviço
347
        $servico = 'NfeDistribuicaoDFe';
348
        $this->checkContingencyForWebServices($servico);
349
        $this->servico($servico, $fonte, $this->tpAmb, true);
350
        $cUF = UFList::getCodeByUF($this->config->siglaUF);
351
        $cnpj = $this->config->cnpj;
352
        $ultNSU = str_pad($ultNSU, 15, '0', STR_PAD_LEFT);
353
        $tagNSU = "<distNSU><ultNSU>$ultNSU</ultNSU></distNSU>";
354
        if ($numNSU != 0) {
355
            $numNSU = str_pad($numNSU, 15, '0', STR_PAD_LEFT);
356
            $tagNSU = "<consNSU><NSU>$numNSU</NSU></consNSU>";
357
        }
358
        //monta a consulta
359
        $consulta = "<distDFeInt xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
360
            . "<tpAmb>".$this->tpAmb."</tpAmb>"
361
            . "<cUFAutor>$cUF</cUFAutor>";
362
        if ($this->typePerson === 'J') {
363
            $consulta .= "<CNPJ>$cnpj</CNPJ>";
364
        } else {
365
            $consulta .= "<CPF>$cnpj</CPF>";
366
        }
367
        $consulta .= "$tagNSU"
368
            . "</distDFeInt>";
369
        //valida o xml da requisição
370
        $this->isValid($this->urlVersion, $consulta, 'distDFeInt');
371
        $this->lastRequest = $consulta;
372
        //montagem dos dados da mensagem SOAP
373
        $request = "<nfeDadosMsg xmlns=\"$this->urlNamespace\">$consulta</nfeDadosMsg>";
374
        $parameters = ['nfeDistDFeInteresse' => $request];
375
        $body = "<nfeDistDFeInteresse xmlns=\"$this->urlNamespace\">"
376
            . $request
377
            . "</nfeDistDFeInteresse>";
378
        //este webservice não requer cabeçalho
379
        $this->objHeader = null;
380
        $this->lastResponse = $this->sendRequest($body, $parameters);
381
        return $this->lastResponse;
382
    }
383
384
    /**
385
     * Request authorization for Letter of Correction
386
     * @param string $chave
387
     * @param string $xCorrecao
388
     * @param int $nSeqEvento
389
     * @return string
390
     * @throws InvalidArgumentException
391
     */
392
    public function sefazCCe($chave, $xCorrecao, $nSeqEvento = 1)
393
    {
394
        if (empty($chave) || empty($xCorrecao)) {
395
            throw new InvalidArgumentException('CC-e: chave ou motivo da correcao vazio!');
396
        }
397
        $uf = $this->validKeyByUF($chave);
398
        $xCorrecao = Strings::replaceUnacceptableCharacters(substr(trim($xCorrecao), 0, 1000));
399
        $xCondUso = 'A Carta de Correcao e disciplinada pelo paragrafo '
400
            . '1o-A do art. 7o do Convenio S/N, de 15 de dezembro de 1970 '
401
            . 'e pode ser utilizada para regularizacao de erro ocorrido '
402
            . 'na emissao de documento fiscal, desde que o erro nao esteja '
403
            . 'relacionado com: I - as variaveis que determinam o valor '
404
            . 'do imposto tais como: base de calculo, aliquota, '
405
            . 'diferenca de preco, quantidade, valor da operacao ou da '
406
            . 'prestacao; II - a correcao de dados cadastrais que implique '
407
            . 'mudanca do remetente ou do destinatario; III - a data de '
408
            . 'emissao ou de saida.';
409
        $tagAdic = "<xCorrecao>"
410
            . $xCorrecao
411
            . "</xCorrecao><xCondUso>$xCondUso</xCondUso>";
412
        return $this->sefazEvento($uf, $chave, self::EVT_CCE, $nSeqEvento, $tagAdic);
413
    }
414
    
415
    /**
416
     * Evento do Ator Interessado
417
     * NOTA: NT2020.007
418
     * @param string $chave
419
     * @param int $tpAutor
420
     * @param string $verAplic
421
     * @param int $nSeqEvento
422
     * @param array $interessados
423
     * @return string
424
     */
425
    public function sefazAtorInteressado(
426
        $chave,
427
        $tpAutor,
428
        $verAplic,
429
        $nSeqEvento = 1,
430
        $interessados = []
431
    ) {
432
        $xCondUso = 'O emitente ou destinatário da NF-e, declara que permite o '
433
            . 'transportador declarado no campo CNPJ/CPF deste evento a '
434
            . 'autorizar os transportadores subcontratados ou redespachados '
435
            . 'a terem acesso ao download da NFe';
436
        $tagAdic = "<cOrgaoAutor>{$this->urlcUF}</cOrgaoAutor>"
437
            . "<tpAutor>{$tpAutor}</tpAutor>"
438
            . "<verAplic>{$verAplic}</verAplic>";
439
        foreach ($interessados as $aut) {
440
            $obj = (object) $aut;
441
            $tagAdic .= "<autXML>";
442
            $tagAdic .=  !empty($obj->CNPJ)
443
                ? "<CNPJ>{$obj->CNPJ}</CNPJ>"
444
                : "<CPF>{$obj->CPF}</CPF>";
445
            $tagAdic .= "<tpAutorizacao>{$obj->tpAutorizacao}</tpAutorizacao>"
446
                . "</autXML>";
447
        }
448
        $tagAdic .= "<xCondUso>$xCondUso</xCondUso>";
449
        return $this->sefazEvento($uf, $chave, self::EVT_ATORINTERESSADO, $nSeqEvento, $tagAdic);
0 ignored issues
show
Bug introduced by
The variable $uf does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
450
    }
451
452
    /**
453
     * Request extension of the term of return of products of an NF-e of
454
     * consignment for industrialization to order with suspension of ICMS
455
     * in interstate operations
456
     * @param  string  $chNFe
457
     * @param  string  $nProt
458
     * @param  integer $tipo 1-primerio prazo, 2-segundo prazo
459
     * @param  array   $itens
460
     * @param  integer $nSeqEvento
461
     * @return string
462
     */
463
    public function sefazEPP(
464
        $chNFe,
465
        $nProt,
466
        $itens = array(),
467
        $tipo = 1,
468
        $nSeqEvento = 1
469
    ) {
470
        $uf = UFList::getUFByCode(substr($chNFe, 0, 2));
471
        $tpEvento = 111500;
472
        if ($tipo == 2) {
473
            $tpEvento = 111501;
474
        }
475
        $tagAdic = "<nProt>$nProt</nProt>";
476
        foreach ($itens as $item) {
477
            $tagAdic .= "<itemPedido numItem=\""
478
                . $item[0]
479
                . "\"><qtdeItem>"
480
                . $item[1]
481
                ."</qtdeItem></itemPedido>";
482
        }
483
        return $this->sefazEvento(
484
            $uf,
485
            $chNFe,
486
            $tpEvento,
487
            $nSeqEvento,
488
            $tagAdic
489
        );
490
    }
491
492
    /**
493
     * Request the cancellation of the request for an extension of the term
494
     * of return of products of an NF-e of consignment for industrialization
495
     * by order with suspension of ICMS in interstate operations
496
     * @param string $chave
497
     * @param string $nProt
498
     * @param integer $nSeqEvento
499
     * @return string
500
     * @throws InvalidArgumentException
501
     */
502
    public function sefazECPP($chave, $nProt, $nSeqEvento = 1)
503
    {
504
        if (empty($chave) || empty($nProt)) {
505
            throw new InvalidArgumentException('A chave ou o numero do protocolo estao vazios!');
506
        }
507
        $uf = UFList::getUFByCode(substr($chave, 0, 2));
508
        $tpEvento = 111502;
509
        $origEvent = 111500;
510
        if ($nSeqEvento == 2) {
511
            $tpEvento = 111503;
512
            $origEvent = 111501;
513
        }
514
        $sSeqEvento = str_pad($nSeqEvento, 2, "0", STR_PAD_LEFT);
515
        $idPedidoCancelado = "ID$origEvent$chave$sSeqEvento";
516
        $tagAdic = "<idPedidoCancelado>"
517
                . "$idPedidoCancelado"
518
                . "</idPedidoCancelado>"
519
                . "<nProt>$nProt</nProt>";
520
        return $this->sefazEvento($uf, $chave, $tpEvento, $nSeqEvento, $tagAdic);
521
    }
522
523
    /**
524
     * Requires nfe cancellation
525
     * @param  string $chave key of NFe
526
     * @param  string $xJust justificative 255 characters max
527
     * @param  string $nProt protocol number
528
     * @return string
529
     * @throws InvalidArgumentException
530
     */
531
    public function sefazCancela($chave, $xJust, $nProt)
532
    {
533
        if (empty($chave) || empty($xJust) || empty($nProt)) {
534
            throw new InvalidArgumentException('Cancelamento: chave, just ou numprot vazio!');
535
        }
536
        $uf = $this->validKeyByUF($chave);
537
        $xJust = Strings::replaceUnacceptableCharacters(substr(trim($xJust), 0, 255));
538
        $nSeqEvento = 1;
539
        $tagAdic = "<nProt>$nProt</nProt><xJust>$xJust</xJust>";
540
        return $this->sefazEvento($uf, $chave, self::EVT_CANCELA, $nSeqEvento, $tagAdic);
541
    }
542
543
    /**
544
     * Requires nfe cancellation by substitution
545
     * @param  string $chave key of NFe
546
     * @param  string $xJust justificative 255 characters max
547
     * @param  string $nProt protocol number
548
     * @param  string $chNFeRef key of New NFe
549
     * @param  string $verAplic version of applicative
550
     * @return string
551
     * @throws InvalidArgumentException
552
     */
553
    public function sefazCancelaPorSubstituicao($chave, $xJust, $nProt, $chNFeRef, $verAplic)
554
    {
555
        if ($this->modelo != 65) {
556
            throw new InvalidArgumentException(
557
                'Cancelamento pro Substituição deve ser usado apenas para '
558
                . 'operações com modelo 65 NFCe'
559
            );
560
        }
561
        if (empty($chave) || empty($xJust) || empty($nProt)
562
            || empty($chNFeRef) || empty($verAplic)) {
563
            throw new InvalidArgumentException(
564
                'CancelamentoPorSubs: chave da NFCe cancelada, justificativa, '
565
                . 'protocolo, chave da NFCe substituta, ou versão do aplicativo '
566
                . 'emissor não podem ser vazios!'
567
            );
568
        }
569
        $uf = $this->validKeyByUF($chave);
570
        $xJust = Strings::replaceUnacceptableCharacters(substr(trim($xJust), 0, 255));
571
        $nSeqEvento = 1;
572
        $cOrgao = substr($chave, 0, 2);
573
        $tagAdic = "<cOrgaoAutor>$cOrgao</cOrgaoAutor>"
574
            . "<tpAutor>1</tpAutor>"
575
            . "<verAplic>$verAplic</verAplic>"
576
            . "<nProt>$nProt</nProt>"
577
            . "<xJust>$xJust</xJust>"
578
            . "<chNFeRef>$chNFeRef</chNFeRef>";
579
        return $this->sefazEvento($uf, $chave, self::EVT_CANCELASUBSTITUICAO, $nSeqEvento, $tagAdic);
580
    }
581
582
    /**
583
     * Request the registration of the manifestation of recipient
584
     * @param string $chave
585
     * @param int $tpEvento
586
     * @param string $xJust Justification for not carrying out the operation
587
     * @param int $nSeqEvento
588
     * @return string
589
     * @throws InvalidArgumentException
590
     */
591
    public function sefazManifesta($chave, $tpEvento, $xJust = '', $nSeqEvento = 1)
592
    {
593
        if (empty($chave) || empty($tpEvento)) {
594
            throw new InvalidArgumentException('Manifestacao: chave ou tipo de evento vazio!');
595
        }
596
        $tagAdic = '';
597
        if ($tpEvento == self::EVT_NAO_REALIZADA) {
598
            $xJust = Strings::replaceUnacceptableCharacters(substr(trim($xJust), 0, 255));
599
            $tagAdic = "<xJust>$xJust</xJust>";
600
        }
601
        return $this->sefazEvento('AN', $chave, $tpEvento, $nSeqEvento, $tagAdic);
602
    }
603
604
    /**
605
     * Request the registration of the manifestation of recipient in batch
606
     * @param \stdClass $std
607
     * @return string
608
     * @throws InvalidArgumentException
609
     * @throws RuntimeException
610
     */
611
    public function sefazManifestaLote(\stdClass $std)
612
    {
613
        $allowed = [
614
            self::EVT_CONFIRMACAO,
615
            self::EVT_CIENCIA,
616
            self::EVT_DESCONHECIMENTO,
617
            self::EVT_NAO_REALIZADA,
618
        ];
619
        if (empty($std) || empty($std->evento)) {
620
            throw new InvalidArgumentException('Manifestacao: parametro "std" ou evento estao vazios!');
621
        }
622
        if (count($std->evento) > 20) {
623
            throw new RuntimeException('Manifestacao: o lote de eventos esta limitado a 20!');
624
        }
625
        $evt = new \stdClass();
626
        $i = 0;
627
        foreach ($std->evento as $s) {
628
            if (!in_array($s->tpEvento, $allowed)) { // se o evento não estiver entre os permitidos ignore
629
                continue;
630
            }
631
            $tagAdic = '';
632
            if ($s->tpEvento == self::EVT_NAO_REALIZADA) {
633
                $xJust = Strings::replaceUnacceptableCharacters(substr(trim($s->xJust), 0, 255));
634
                $tagAdic = "<xJust>$xJust</xJust>";
635
            }
636
            $evt->evento[$i] = new \stdClass();
637
            $evt->evento[$i]->chave = $s->chNFe;
638
            $evt->evento[$i]->tpEvento = $s->tpEvento;
639
            $evt->evento[$i]->nSeqEvento = $s->nSeqEvento;
640
            $evt->evento[$i]->tagAdic = $tagAdic;
641
            $i++;
642
        }
643
        return $this->sefazEventoLote('AN', $evt);
644
    }
645
    
646
    /**
647
     * Send event for delivery receipt
648
     * @param \stdClass $std
649
     * @return string
650
     */
651
    public function sefazComprovanteEntrega(\stdClass $std)
652
    {
653
        $hash = sha1($std->chave . $std->imagem);
654
        $datahash = date('Y-m-d\TH:i:sP');
655
        $cod = UFList::getCodeByUF($this->config->siglaUF);
656
        $tagAdic = "<cOrgaoAutor>{$cod}</cOrgaoAutor>"
657
            . "<tpAutor>{$std->tipo_autor}</tpAutor>"
658
            . "<verAplic>{$std->verAplic}</verAplic>"
659
            . "<dhEntrega>{$std->data_recebimento}</dhEntrega>"
660
            . "<nDoc>{$std->documento_recebedor}</nDoc>"
661
            . "<xNome>{$std->nome_recebedor}</xNome>";
662
        if (!empty($std->latitude) && !empty($std->longitude)) {
663
            $tagAdic .= "<latGPS>{$std->latitude}</latGPS>"
664
            . "<longGPS>{$std->longitude}</longGPS>";
665
        }
666
        $tagAdic .= "<hashComprovante>{$hash}</hashComprovante>"
667
            . "<dhHashComprovante>{$datahash}</dhHashComprovante>";
668
        $tpEvento = self::EVT_COMPROVANTE_ENTREGA;
669
        $chave = $std->chave;
670
        $nSeqEvento = 1;
671
        return $this->sefazEvento('AN', $chave, $tpEvento, $nSeqEvento, $tagAdic);
672
    }
673
    
674
    /**
675
     * Send event for cancel delivery receipt
676
     * @param \stdClass $std
677
     * @return string
678
     */
679
    public function sefazCancelaComprovanteEntrega(\stdClass $std)
680
    {
681
        $hash = sha1($std->chave . $std->imagem);
682
        $datahash = date('Y-m-d\TH:i:sP');
683
        $cod = UFList::getCodeByUF($this->config->siglaUF);
684
        $tagAdic = "<cOrgaoAutor>{$cod}</cOrgaoAutor>"
685
            . "<tpAutor>{$std->tipo_autor}</tpAutor>"
686
            . "<verAplic>{$std->verAplic}</verAplic>"
687
            . "<dhEntrega>{$std->data_recebimento}</dhEntrega>"
688
            . "<nDoc>{$std->documento_recebedor}</nDoc>"
689
            . "<xNome>{$std->nome_recebedor}</xNome>";
690
        if (!empty($std->latitude) && !empty($std->longitude)) {
691
            $tagAdic .= "<latGPS>{$std->latitude}</latGPS>"
692
            . "<longGPS>{$std->longitude}</longGPS>";
693
        }
694
        $tagAdic .= "<hashComprovante>{$hash}</hashComprovante>"
695
            . "<dhHashComprovante>{$datahash}</dhHashComprovante>";
696
        $tpEvento = self::EVT_CANCELAMENTO_COMPROVANTE_ENTREGA;
697
        $chave = $std->chave;
698
        $nSeqEvento = 1;
699
        return $this->sefazEvento('AN', $chave, $tpEvento, $nSeqEvento, $tagAdic);
700
    }
701
702
    /**
703
     * Send event to SEFAZ in batch
704
     * @param string $uf
705
     * @param \stdClass $std
706
     * @return string
707
     * @throws RuntimeException
708
     * @throws InvalidArgumentException
709
     */
710
    public function sefazEventoLote($uf, \stdClass $std)
711
    {
712
        if (empty($uf) || empty($std)) {
713
            throw new InvalidArgumentException('Evento Lote: UF ou parametro "std" vazio!');
714
        }
715
        if (count($std->evento) > 20) {
716
            throw new RuntimeException('Evento Lote: o lote de eventos esta limitado a 20!');
717
        }
718
        $servico = 'RecepcaoEvento';
719
        $this->checkContingencyForWebServices($servico);
720
        $this->servico($servico, $uf, $this->tpAmb, false);
721
        $batchRequest = '';
722
        foreach ($std->evento as $evt) {
723
            if ($evt->tpEvento == self::EVT_EPEC) {
724
                continue; //não é possivel enviar EPEC com outros eventos
725
            }
726
            $ev = $this->tpEv($evt->tpEvento);
727
            $descEvento = $ev->desc;
728
            $cnpj = $this->config->cnpj;
729
            $dt = new \DateTime('now', new \DateTimeZone($this->timezone));
730
            $dhEvento = $dt->format('Y-m-d\TH:i:sP');
731
            $sSeqEvento = str_pad($evt->nSeqEvento, 2, "0", STR_PAD_LEFT);
732
            $eventId = "ID".$evt->tpEvento.$evt->chave.$sSeqEvento;
733
            $cOrgao = UFList::getCodeByUF($uf);
734
            $request = "<evento xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
735
                . "<infEvento Id=\"$eventId\">"
736
                . "<cOrgao>$cOrgao</cOrgao>"
737
                . "<tpAmb>$this->tpAmb</tpAmb>";
738
            if ($this->typePerson === 'J') {
739
                $request .= "<CNPJ>$cnpj</CNPJ>";
740
            } else {
741
                $request .= "<CPF>$cnpj</CPF>";
742
            }
743
            $request .= "<chNFe>$evt->chave</chNFe>"
744
                . "<dhEvento>$dhEvento</dhEvento>"
745
                . "<tpEvento>$evt->tpEvento</tpEvento>"
746
                . "<nSeqEvento>$evt->nSeqEvento</nSeqEvento>"
747
                . "<verEvento>$this->urlVersion</verEvento>"
748
                . "<detEvento versao=\"$this->urlVersion\">"
749
                . "<descEvento>$descEvento</descEvento>"
750
                . "$evt->tagAdic"
751
                . "</detEvento>"
752
                . "</infEvento>"
753
                . "</evento>";
754
            //assinatura dos dados
755
            $request = Signer::sign(
756
                $this->certificate,
757
                $request,
758
                'infEvento',
759
                'Id',
760
                $this->algorithm,
761
                $this->canonical
762
            );
763
            $batchRequest .= Strings::clearXmlString($request, true);
764
        }
765
        $dt = new \DateTime('now', new \DateTimeZone($this->timezone));
766
        $lote = $dt->format('YmdHis') . rand(0, 9);
767
        $request = "<envEvento xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
768
            . "<idLote>$lote</idLote>"
769
            . $batchRequest
770
            . "</envEvento>";
771
        $this->isValid($this->urlVersion, $request, 'envEvento');
772
        $this->lastRequest = $request;
773
        $parameters = ['nfeDadosMsg' => $request];
774
        $body = "<nfeDadosMsg xmlns=\"$this->urlNamespace\">$request</nfeDadosMsg>";
775
        $this->lastResponse = $this->sendRequest($body, $parameters);
776
        return $this->lastResponse;
777
    }
778
779
    /**
780
     * Request authorization for issuance in contingency EPEC
781
     * @param  string $xml
782
     * @return string
783
     * @throws InvalidArgumentException
784
     * @throws RuntimeException
785
     */
786
    public function sefazEPEC(&$xml)
787
    {
788
        if (empty($xml)) {
789
            throw new InvalidArgumentException('EPEC: parametro xml esta vazio!');
790
        }
791
        $nSeqEvento = 1;
792
        if ($this->contingency->type !== 'EPEC') {
793
            throw new RuntimeException('A contingencia EPEC deve estar ativada!');
794
        }
795
        $xml = $this->correctNFeForContingencyMode($xml);
796
        $dom = new \DOMDocument('1.0', 'UTF-8');
797
        $dom->preserveWhiteSpace = false;
798
        $dom->formatOutput = false;
799
        $dom->loadXML($xml);
800
        $infNFe = $dom->getElementsByTagName('infNFe')->item(0);
801
        $emit = $dom->getElementsByTagName('emit')->item(0);
802
        $dest = $dom->getElementsByTagName('dest')->item(0);
803
        $cOrgaoAutor = UFList::getCodeByUF($this->config->siglaUF);
804
        $chNFe = substr($infNFe->getAttribute('Id'), 3, 44);
805
        // EPEC
806
        $dhEmi = $dom->getElementsByTagName('dhEmi')->item(0)->nodeValue;
807
        $tpNF = $dom->getElementsByTagName('tpNF')->item(0)->nodeValue;
808
        $emitIE = $emit->getElementsByTagName('IE')->item(0)->nodeValue;
809
        $destUF = $dest->getElementsByTagName('UF')->item(0)->nodeValue;
810
        $total = $dom->getElementsByTagName('total')->item(0);
811
        $vNF = $total->getElementsByTagName('vNF')->item(0)->nodeValue;
812
        $vICMS = $total->getElementsByTagName('vICMS')->item(0)->nodeValue;
813
        $vST = $total->getElementsByTagName('vST')->item(0)->nodeValue;
814
        $dID = !empty($dest->getElementsByTagName('CNPJ')->item(0)) ?
815
                $dest->getElementsByTagName('CNPJ')->item(0)->nodeValue : null;
816
        if (!empty($dID)) {
817
            $destID = "<CNPJ>$dID</CNPJ>";
818
        } else {
819
            $dID = $dest->getElementsByTagName('CPF')->item(0)->nodeValue;
820
            if (!empty($dID)) {
821
                $destID = "<CPF>$dID</CPF>";
822
            } else {
823
                $dID = $dest->getElementsByTagName('idEstrangeiro')
824
                    ->item(0)
825
                    ->nodeValue;
826
                $destID = "<idEstrangeiro>$dID</idEstrangeiro>";
827
            }
828
        }
829
        $dIE = !empty($dest->getElementsByTagName('IE')->item(0)->nodeValue) ?
830
                $dest->getElementsByTagName('IE')->item(0)->nodeValue : '';
831
        $destIE = '';
832
        if (!empty($dIE)) {
833
            $destIE = "<IE>$dIE</IE>";
834
        }
835
        $tagAdic = "<cOrgaoAutor>$cOrgaoAutor</cOrgaoAutor>"
836
            . "<tpAutor>1</tpAutor>"
837
            . "<verAplic>$this->verAplic</verAplic>"
838
            . "<dhEmi>$dhEmi</dhEmi>"
839
            . "<tpNF>$tpNF</tpNF>"
840
            . "<IE>$emitIE</IE>"
841
            . "<dest>"
842
            . "<UF>$destUF</UF>"
843
            . $destID
844
            . $destIE
845
            . "<vNF>$vNF</vNF>"
846
            . "<vICMS>$vICMS</vICMS>"
847
            . "<vST>$vST</vST>"
848
            . "</dest>";
849
850
        return $this->sefazEvento('AN', $chNFe, self::EVT_EPEC, $nSeqEvento, $tagAdic);
851
    }
852
853
    /**
854
     * Send event to SEFAZ
855
     * @param string $uf
856
     * @param string $chave
857
     * @param int $tpEvento
858
     * @param int $nSeqEvento
859
     * @param string $tagAdic
860
     * @return string
861
     */
862
    public function sefazEvento(
863
        $uf,
864
        $chave,
865
        $tpEvento,
866
        $nSeqEvento = 1,
867
        $tagAdic = ''
868
    ) {
869
        $ignore = $tpEvento == self::EVT_EPEC;
870
        $servico = 'RecepcaoEvento';
871
        $this->checkContingencyForWebServices($servico);
872
        $this->servico($servico, $uf, $this->tpAmb, $ignore);
873
        $ev = $this->tpEv($tpEvento);
874
        $descEvento = $ev->desc;
875
        $cnpj = isset($this->config->cnpj) ? $this->config->cnpj : '';
876
        $dt = new \DateTime(date("Y-m-d H:i:sP"), new \DateTimeZone($this->timezone));
877
        $dhEvento = $dt->format('Y-m-d\TH:i:sP');
878
        $sSeqEvento = str_pad($nSeqEvento, 2, "0", STR_PAD_LEFT);
879
        $eventId = "ID".$tpEvento.$chave.$sSeqEvento;
880
        $cOrgao = UFList::getCodeByUF($uf);
881
        $request = "<evento xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
882
            . "<infEvento Id=\"$eventId\">"
883
            . "<cOrgao>$cOrgao</cOrgao>"
884
            . "<tpAmb>$this->tpAmb</tpAmb>";
885
        if ($this->typePerson === 'J') {
886
            $request .= "<CNPJ>$cnpj</CNPJ>";
887
        } else {
888
            $request .= "<CPF>$cnpj</CPF>";
889
        }
890
        $request .= "<chNFe>$chave</chNFe>"
891
            . "<dhEvento>$dhEvento</dhEvento>"
892
            . "<tpEvento>$tpEvento</tpEvento>"
893
            . "<nSeqEvento>$nSeqEvento</nSeqEvento>"
894
            . "<verEvento>$this->urlVersion</verEvento>"
895
            . "<detEvento versao=\"$this->urlVersion\">"
896
            . "<descEvento>$descEvento</descEvento>"
897
            . "$tagAdic"
898
            . "</detEvento>"
899
            . "</infEvento>"
900
            . "</evento>";
901
        //assinatura dos dados
902
        $request = Signer::sign(
903
            $this->certificate,
904
            $request,
905
            'infEvento',
906
            'Id',
907
            $this->algorithm,
908
            $this->canonical
909
        );
910
        $request = Strings::clearXmlString($request, true);
911
        $lote = $dt->format('YmdHis').rand(0, 9);
912
        $request = "<envEvento xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
913
            . "<idLote>$lote</idLote>"
914
            . $request
915
            . "</envEvento>";
916
        $this->isValid($this->urlVersion, $request, 'envEvento');
917
        $this->lastRequest = $request;
918
        //return $request;
919
        $parameters = ['nfeDadosMsg' => $request];
920
        $body = "<nfeDadosMsg xmlns=\"$this->urlNamespace\">$request</nfeDadosMsg>";
921
        $this->lastResponse = $this->sendRequest($body, $parameters);
922
        return $this->lastResponse;
923
    }
924
925
    /**
926
     * Request the NFe download already manifested by its recipient, by the key
927
     * using new service in NfeDistribuicaoDFe
928
     * NOTA: NfeDownloadNF is deactivated
929
     * @param  string $chave
930
     * @return string
931
     * @throws InvalidArgumentException
932
     */
933
    public function sefazDownload($chave)
934
    {
935
        if (empty($chave)) {
936
            throw new InvalidArgumentException('Download: chave esta vazia!');
937
        }
938
        //carrega serviço
939
        $servico = 'NfeDistribuicaoDFe';
940
        $this->checkContingencyForWebServices($servico);
941
        $this->servico($servico, 'AN', $this->tpAmb, true);
942
        $cUF = UFList::getCodeByUF($this->config->siglaUF);
943
        $tagChave = "<consChNFe><chNFe>$chave</chNFe></consChNFe>";
944
        $cnpj = $this->config->cnpj;
945
        //monta a consulta
946
        $request = "<distDFeInt xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
947
            . "<tpAmb>".$this->tpAmb."</tpAmb>"
948
            . "<cUFAutor>$cUF</cUFAutor>";
949
        if ($this->typePerson === 'J') {
950
            $request .= "<CNPJ>$cnpj</CNPJ>";
951
        } else {
952
            $request .= "<CPF>$cnpj</CPF>";
953
        }
954
        $request .= "$tagChave"
955
            . "</distDFeInt>";
956
        //valida o xml da requisição
957
        $this->isValid($this->urlVersion, $request, 'distDFeInt');
958
        $this->lastRequest = $request;
959
        //montagem dos dados da mensagem SOAP
960
        $request = "<nfeDadosMsg xmlns=\"$this->urlNamespace\">$request</nfeDadosMsg>";
961
        $parameters = ['nfeDistDFeInteresse' => $request];
962
        $body = "<nfeDistDFeInteresse xmlns=\"$this->urlNamespace\">"
963
            . $request
964
            . "</nfeDistDFeInteresse>";
965
        //este webservice não requer cabeçalho
966
        $this->objHeader = null;
967
        $this->lastResponse = $this->sendRequest($body, $parameters);
968
        return $this->lastResponse;
969
    }
970
971
    /**
972
     * Maintenance of the Taxpayer Security Code - CSC (Old Token)
973
     * @param int $indOp Identificador do tipo de operação:
974
     *                   1 - Consulta CSC Ativos;
975
     *                   2 - Solicita novo CSC;
976
     *                   3 - Revoga CSC Ativo
977
     * @return string
978
     * @throws InvalidArgumentException
979
     * @throws RuntimeException
980
     */
981
    public function sefazCsc($indOp)
982
    {
983
        if (empty($indOp) || $indOp < 1 || $indOp > 3) {
984
            throw new InvalidArgumentException('CSC: identificador operacao invalido!');
985
        }
986
        if ($this->modelo != 65) {
987
            throw new RuntimeException('CSC: modelo diferente de 65!');
988
        }
989
        $raizCNPJ = substr($this->config->cnpj, 0, -6);
990
        //carrega serviço
991
        $servico = 'CscNFCe';
992
        $this->checkContingencyForWebServices($servico);
993
        $this->servico($servico, $this->config->siglaUF, $this->tpAmb);
994
        $request = "<admCscNFCe versao=\"$this->urlVersion\" xmlns=\"$this->urlPortal\">"
995
            . "<tpAmb>$this->tpAmb</tpAmb>"
996
            . "<indOp>$indOp</indOp>"
997
            . "<raizCNPJ>$raizCNPJ</raizCNPJ>"
998
            . "</admCscNFCe>";
999
        if ($indOp == 3) {
1000
            $request = "<admCscNFCe versao=\"$this->urlVersion\" xmlns=\"$this->urlPortal\">"
1001
            . "<tpAmb>$this->tpAmb</tpAmb>"
1002
            . "<indOp>$indOp</indOp>"
1003
            . "<raizCNPJ>$raizCNPJ</raizCNPJ>"
1004
            . "<dadosCsc>"
1005
            . "<idCsc>".$this->config->CSCid."</idCsc>"
1006
            . "<codigoCsc>".$this->config->CSC."</codigoCsc>"
1007
            . "</dadosCsc>"
1008
            . "</admCscNFCe>";
1009
        }
1010
        //o xsd não está disponivel
1011
        //$this->isValid($this->urlVersion, $request, 'cscNFCe');
1012
        $this->lastRequest = $request;
1013
        $parameters = ['nfeDadosMsg' => $request];
1014
        $body = "<nfeDadosMsg xmlns=\"$this->urlNamespace\">$request</nfeDadosMsg>";
1015
        $this->lastResponse = $this->sendRequest($body, $parameters);
1016
        return $this->lastResponse;
1017
    }
1018
1019
    /**
1020
     * Checks the validity of an NFe, normally used for received NFe
1021
     * @param string $nfe
1022
     * @return bool
1023
     * @throws InvalidArgumentException
1024
     */
1025
    public function sefazValidate($nfe)
1026
    {
1027
        if (empty($nfe)) {
1028
            throw new InvalidArgumentException('Validacao NF-e: a string da NF-e esta vazia!');
1029
        }
1030
        //verifica a assinatura da NFe, exception caso de falha
1031
        Signer::isSigned($nfe);
1032
        $dom = new \DOMDocument('1.0', 'utf-8');
1033
        $dom->formatOutput = false;
1034
        $dom->preserveWhiteSpace = false;
1035
        $dom->loadXML($nfe);
1036
        //verifica a validade no webservice da SEFAZ
1037
        $tpAmb = $dom->getElementsByTagName('tpAmb')->item(0)->nodeValue;
1038
        $infNFe  = $dom->getElementsByTagName('infNFe')->item(0);
1039
        $chNFe = preg_replace('/[^0-9]/', '', $infNFe->getAttribute("Id"));
1040
        $protocol = $dom->getElementsByTagName('nProt')->item(0)->nodeValue;
1041
        $digval = $dom->getElementsByTagName('DigestValue')->item(0)->nodeValue;
1042
        //consulta a NFe
1043
        $response = $this->sefazConsultaChave($chNFe, $tpAmb);
1044
        $ret = new \DOMDocument('1.0', 'UTF-8');
1045
        $ret->preserveWhiteSpace = false;
1046
        $ret->formatOutput = false;
1047
        $ret->loadXML($response);
1048
        $retProt = $ret->getElementsByTagName('protNFe')->item(0);
1049
        if (!isset($retProt)) {
1050
            $xMotivo = $ret->getElementsByTagName('xMotivo')->item(0);
1051
            if (isset($xMotivo)) {
1052
                throw new InvalidArgumentException('Validacao NF-e: ' . $xMotivo->nodeValue);
1053
            } else {
1054
                throw new InvalidArgumentException('O documento de resposta nao contem o node "protNFe".');
1055
            }
1056
        }
1057
        $infProt = $ret->getElementsByTagName('infProt')->item(0);
1058
        $dig = $infProt->getElementsByTagName("digVal")->item(0);
1059
        $digProt = '000';
1060
        if (isset($dig)) {
1061
            $digProt = $dig->nodeValue;
1062
        }
1063
        $chProt = $infProt->getElementsByTagName("chNFe")->item(0)->nodeValue;
1064
        $nProt = $infProt->getElementsByTagName("nProt")->item(0)->nodeValue;
1065
        if ($protocol == $nProt && $digval == $digProt && $chNFe == $chProt) {
1066
            return true;
1067
        }
1068
        return false;
1069
    }
1070
1071
    /**
1072
     * Returns alias and description event from event code.
1073
     * @param  int $tpEvento
1074
     * @return \stdClass
1075
     * @throws \RuntimeException
1076
     */
1077
    private function tpEv($tpEvento)
1078
    {
1079
        $std = new \stdClass();
1080
        $std->alias = '';
1081
        $std->desc = '';
1082
        switch ($tpEvento) {
1083
            case self::EVT_CCE:
1084
                $std->alias = 'CCe';
1085
                $std->desc = 'Carta de Correcao';
1086
                break;
1087
            case self::EVT_CANCELA:
1088
                $std->alias = 'CancNFe';
1089
                $std->desc = 'Cancelamento';
1090
                break;
1091
            case self::EVT_CANCELASUBSTITUICAO:
1092
                $std->alias = 'CancNFe';
1093
                $std->desc = 'Cancelamento por substituicao';
1094
                break;
1095
            case self::EVT_EPEC: // Emissão em contingência EPEC
1096
                $std->alias = 'EPEC';
1097
                $std->desc = 'EPEC';
1098
                break;
1099
            case self::EVT_COMPROVANTE_ENTREGA:
1100
                $std->alias = 'CompEntrega';
1101
                $std->desc = 'Comprovante de Entrega';
1102
                break;
1103
            case self::EVT_CANCELAMENTO_COMPROVANTE_ENTREGA:
1104
                $std->alias = 'CancCompEntrega';
1105
                $std->desc = 'Cancelamento do Comprovante de Entrega';
1106
                break;
1107
            case 111500:
1108
            case 111501:
1109
                //EPP
1110
                //Pedido de prorrogação
1111
                $std->alias = 'EPP';
1112
                $std->desc = 'Pedido de Prorrogacao';
1113
                break;
1114
            case 111502:
1115
            case 111503:
1116
                //ECPP
1117
                //Cancelamento do Pedido de prorrogação
1118
                $std->alias = 'ECPP';
1119
                $std->desc = 'Cancelamento de Pedido de Prorrogacao';
1120
                break;
1121
            case self::EVT_CONFIRMACAO: // Manifestação Confirmacao da Operação
1122
                $std->alias = 'EvConfirma';
1123
                $std->desc = 'Confirmacao da Operacao';
1124
                break;
1125
            case self::EVT_CIENCIA: // Manifestação Ciencia da Operação
1126
                $std->alias = 'EvCiencia';
1127
                $std->desc = 'Ciencia da Operacao';
1128
                $std->tpAutor = 2;
1129
                break;
1130
            case self::EVT_DESCONHECIMENTO: // Manifestação Desconhecimento da Operação
1131
                $std->alias = 'EvDesconh';
1132
                $std->desc = 'Desconhecimento da Operacao';
1133
                break;
1134
            case self::EVT_NAO_REALIZADA: // Manifestação Operacao não Realizada
1135
                $std->alias = 'EvNaoRealizada';
1136
                $std->desc = 'Operacao nao Realizada';
1137
                break;
1138
            case self::EVT_ATORINTERESSADO: //ator interessado
1139
                $std->alias = 'EvAtorInteressado';
1140
                $std->desc = 'Ator interessado na NF-e';
1141
                break;
1142
            default:
1143
                $msg = "O código do tipo de evento informado não corresponde a "
1144
                . "nenhum evento estabelecido.";
1145
                throw new RuntimeException($msg);
1146
        }
1147
        return $std;
1148
    }
1149
}
1150