Passed
Push — master ( 302920...b82b1f )
by
unknown
54s
created

src/Tools.php (1 issue)

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\CTe;
4
5
/**
6
 * Class responsible for communication with SEFAZ extends
7
 * NFePHP\CTe\Common\Tools
8
 *
9
 * @category  NFePHP
10
 * @package   NFePHP\CTe\Tools
11
 * @copyright NFePHP Copyright (c) 2008-2017
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-cte 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\CTe\Factories\Events;
23
use NFePHP\CTe\Common\Tools as ToolsCommon;
24
use RuntimeException;
25
use InvalidArgumentException;
26
27
class Tools extends ToolsCommon
28
{
29
    const EVT_CONFIRMACAO = 210200;
30
    const EVT_CIENCIA = 210210;
31
    const EVT_DESCONHECIMENTO = 210220;
32
    const EVT_NAO_REALIZADA = 210240;
33
34
    /**
35
     * Request authorization to issue CTe in batch with one or more documents
36
     * @param array $aXml array of cte's xml
37
     * @param string $idLote lote number
38
     * @param bool $compactar flag to compress data with gzip
39
     * @return string soap response xml
40
     */
41
    public function sefazEnviaLote(
42
        $aXml,
43
        $idLote = '',
44
        $compactar = false,
45
        &$xmls = []
46
    ) {
47
        if (!is_array($aXml)) {
48
            throw new \InvalidArgumentException('Os XML das CTe devem ser passados em um array.');
49
        }
50
        $servico = 'CteRecepcao';
51
        $this->checkContingencyForWebServices($servico);
52
        if ($this->contingency->type != '') {
53
            //em modo de contingencia
54
            //esses xml deverão ser modificados e re-assinados e retornados
55
            //no parametro $xmls para serem armazenados pelo aplicativo
56
            //pois serão alterados
57
            foreach ($aXml as $doc) {
58
                //corrigir o xml para o tipo de contigência setado
59
                $xmls[] = $this->correctNFeForContingencyMode($doc);
60
            }
61
            $aXml = $xmls;
62
        }
63
64
        $sxml = implode("", $aXml);
65
        $sxml = preg_replace("/<\?xml.*?\?>/", "", $sxml);
66
        $this->servico(
67
            $servico,
68
            $this->config->siglaUF,
69
            $this->tpAmb
70
        );
71
        $request = "<enviCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
72
            . "<idLote>$idLote</idLote>"
73
            . "$sxml"
74
            . "</enviCTe>";
75
        $this->isValid($this->urlVersion, $request, 'enviCTe');
76
        $this->lastRequest = $request;
77
        //montagem dos dados da mensagem SOAP
78
        $parameters = ['cteDadosMsg' => $request];
79
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
80
        $method = $this->urlMethod;
81
        if ($compactar) {
82
            $gzdata = base64_encode(gzencode($cons, 9, FORCE_GZIP));
83
            $body = "<cteDadosMsgZip xmlns=\"$this->urlNamespace\">$gzdata</cteDadosMsgZip>";
84
            $method = $this->urlMethod."Zip";
85
            $parameters = ['cteDadosMsgZip' => $gzdata];
86
            $body = "<cteDadosMsgZip xmlns=\"$this->urlNamespace\">$gzdata</cteDadosMsgZip>";
87
        }
88
        $this->lastResponse = $this->sendRequest($body, $parameters);
89
        return $this->lastResponse;
90
    }
91
    
92
    /**
93
     * Request authorization to issue CTe OS with one document only
94
     * @param type $xml
95
     * @return type
96
     */
97
    public function sefazEnviaCTeOS($xml)
98
    {
99
        //carrega serviço
100
        $servico = 'CteRecepcaoOS';
101
        $this->checkContingencyForWebServices($servico);
102
        $this->servico(
103
            $servico,
104
            $this->config->siglaUF,
105
            $this->tpAmb
106
        );
107
        $request = preg_replace("/<\?xml.*\?>/", "", $xml);
108
        $this->isValid($this->urlVersion, $request, 'cteOS');
109
        $this->lastRequest = $request;
110
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
111
        $this->lastResponse = $this->sendRequest($body);
112
        return $this->lastResponse;
113
    }
114
115
    /**
116
     * Check status of Batch of CTe sent by receipt of this shipment
117
     * @param string $recibo
118
     * @param int $tpAmb
119
     * @return string
120
     */
121
    public function sefazConsultaRecibo($recibo, $tpAmb = null)
122
    {
123
        if (empty($tpAmb)) {
124
            $tpAmb = $this->tpAmb;
125
        }
126
        //carrega serviço
127
        $servico = 'CteRetRecepcao';
128
        $this->checkContingencyForWebServices($servico);
129
        $this->servico(
130
            $servico,
131
            $this->config->siglaUF,
132
            $tpAmb
133
        );
134
        if ($this->urlService == '') {
135
            $msg = "A consulta de CTe não está disponível na SEFAZ {$this->config->siglaUF}!!!";
136
            throw new RuntimeException($msg);
137
        }
138
        $request = "<consReciCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
139
            . "<tpAmb>$tpAmb</tpAmb>"
140
            . "<nRec>$recibo</nRec>"
141
            . "</consReciCTe>";
142
        $this->isValid($this->urlVersion, $request, 'consReciCTe');
143
        $this->lastRequest = $request;
144
        $parameters = ['cteDadosMsg' => $request];
145
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
146
        $this->lastResponse = $this->sendRequest($body, $parameters);
147
        return $this->lastResponse;
148
    }
149
150
    /**
151
     * Check the CTe status for the 44-digit key and retrieve the protocol
152
     * @param string $chave
153
     * @param int $tpAmb
154
     * @return string
155
     */
156
    public function sefazConsultaChave($chave, $tpAmb = null)
157
    {
158
        $uf = UFList::getUFByCode(substr($chave, 0, 2));
159
        if (empty($tpAmb)) {
160
            $tpAmb = $this->tpAmb;
161
        }
162
        //carrega serviço
163
        $servico = 'CteConsultaProtocolo';
164
        $this->checkContingencyForWebServices($servico);
165
        $this->servico(
166
            $servico,
167
            $uf,
168
            $tpAmb
169
        );
170
        $request = "<consSitCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
171
            . "<tpAmb>$tpAmb</tpAmb>"
172
            . "<xServ>CONSULTAR</xServ>"
173
            . "<chCTe>$chave</chCTe>"
174
            . "</consSitCTe>";
175
        $this->isValid($this->urlVersion, $request, 'consSitCTe');
176
        $this->lastRequest = $request;
177
        $parameters = ['cteDadosMsg' => $request];
178
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
179
        $this->lastResponse = $this->sendRequest($body, $parameters);
180
        return $this->lastResponse;
181
    }
182
183
    /**
184
     * Request to disable one or an NFe sequence of a given series
185
     * @param int $nSerie
186
     * @param int $nIni
187
     * @param int $nFin
188
     * @param string $xJust
189
     * @param int $tpAmb
190
     * @return string
191
     */
192
    public function sefazInutiliza(
193
        $nSerie,
194
        $nIni,
195
        $nFin,
196
        $xJust,
197
        $tpAmb = null
198
    ) {
199
        if (empty($tpAmb)) {
200
            $tpAmb = $this->tpAmb;
201
        }
202
        $xJust = Strings::replaceSpecialsChars($xJust);
203
        $nSerie = (integer) $nSerie;
204
        $nIni = (integer) $nIni;
205
        $nFin = (integer) $nFin;
206
        $servico = 'CteInutilizacao';
207
        $this->checkContingencyForWebServices($servico);
208
        //carrega serviço
209
        $this->servico(
210
            $servico,
211
            $this->config->siglaUF,
212
            $tpAmb
213
        );
214
        $cnpj = $this->config->cnpj;
215
        $strAno = (string) date('y');
216
        $strSerie = str_pad($nSerie, 3, '0', STR_PAD_LEFT);
217
        $strInicio = str_pad($nIni, 9, '0', STR_PAD_LEFT);
218
        $strFinal = str_pad($nFin, 9, '0', STR_PAD_LEFT);
219
        $idInut = "ID"
220
            . $this->urlcUF
221
            . $cnpj
222
            . $this->modelo
223
            . $strSerie
224
            . $strInicio
225
            . $strFinal;
226
        //limpa os caracteres indesejados da justificativa
227
        $xJust = Strings::replaceSpecialsChars($xJust);
228
        //montagem do corpo da mensagem
229
        $msg = "<inutCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">" .
230
            "<infInut Id=\"$idInut\">" .
231
            "<tpAmb>$tpAmb</tpAmb>" .
232
            "<xServ>INUTILIZAR</xServ>" .
233
            "<cUF>$this->urlcUF</cUF>" .
234
            "<ano>$strAno</ano>" .
235
            "<CNPJ>$cnpj</CNPJ>" .
236
            "<mod>$this->modelo</mod>" .
237
            "<serie>$nSerie</serie>" .
238
            "<nCTIni>$nIni</nCTIni>" .
239
            "<nCTFin>$nFin</nCTFin>" .
240
            "<xJust>$xJust</xJust>" .
241
            "</infInut></inutCTe>";
242
        //assina a solicitação
243
        $request = Signer::sign(
244
            $this->certificate,
245
            $msg,
246
            'infInut',
247
            'Id',
248
            $this->algorithm,
249
            $this->canonical
250
        );
251
        $request = Strings::clearXmlString($request, true);
252
        $this->isValid($this->urlVersion, $request, 'inutCTe');
253
        $this->lastRequest = $request;
254
        $parameters = ['cteDadosMsg' => $request];
255
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
256
        $this->lastResponse = $this->sendRequest($body, $parameters);
257
        return $this->lastResponse;
258
    }
259
260
    /**
261
     * Search for the registration data of an NFe issuer,
262
     * if in contingency mode this service will cause a
263
     * Exception and remember not all Sefaz have this service available,
264
     * so it will not work in some cases.
265
     * @param string $uf  federation unit
266
     * @param string $cnpj CNPJ number (optional)
267
     * @param string $iest IE number (optional)
268
     * @param string $cpf  CPF number (optional)
269
     * @return string xml soap response
270
     */
271
    public function sefazCadastro(
272
        $uf,
273
        $cnpj = '',
274
        $iest = '',
275
        $cpf = ''
276
    ) {
277
        if ($cnpj != '') {
278
            $filter = "<CNPJ>$cnpj</CNPJ>";
279
            $txtFile = "CNPJ_$cnpj";
280
        } elseif ($iest != '') {
281
            $filter = "<IE>$iest</IE>";
282
            $txtFile = "IE_$iest";
283
        } else {
284
            $filter = "<CPF>$cpf</CPF>";
285
            $txtFile = "CPF_$cpf";
286
        }
287
        //carrega serviço
288
        $servico = 'CteConsultaCadastro';
289
        $this->checkContingencyForWebServices($servico);
290
        $this->servico(
291
            $servico,
292
            $uf,
293
            $this->tpAmb,
294
            true
295
        );
296
        $request = "<ConsCad xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
297
            . "<infCons>"
298
            . "<xServ>CONS-CAD</xServ>"
299
            . "<UF>$uf</UF>"
300
            . "$filter</infCons></ConsCad>";
301
        $this->isValid($this->urlVersion, $request, 'consCad');
302
        $this->lastRequest = $request;
303
        $parameters = ['cteDadosMsg' => $request];
304
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
305
        $this->lastResponse = $this->sendRequest($body, $parameters);
306
        return $this->lastResponse;
307
    }
308
309
    /**
310
     * Check services status SEFAZ/SVC
311
     * If $uf is empty use normal check with contingency
312
     * If $uf is NOT empty ignore contingency mode
313
     * @param string $uf  initials of federation unit
314
     * @param int $tpAmb
315
     * @return string xml soap response
316
     */
317
    public function sefazStatus($uf = '', $tpAmb = null)
318
    {
319
        if (empty($tpAmb)) {
320
            $tpAmb = $this->tpAmb;
321
        }
322
        $ignoreContingency = true;
323
        if (empty($uf)) {
324
            $uf = $this->config->siglaUF;
325
            $ignoreContingency = false;
326
        }
327
        $servico = 'CteStatusServico';
328
        $this->checkContingencyForWebServices($servico);
329
        $this->servico(
330
            $servico,
331
            $uf,
332
            $tpAmb,
333
            $ignoreContingency
334
        );
335
        $request = "<consStatServCte xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
336
            . "<tpAmb>$tpAmb</tpAmb>"
337
            . "<xServ>STATUS</xServ></consStatServCte>";
338
        $this->isValid($this->urlVersion, $request, 'consStatServCte');
339
        $this->lastRequest = $request;
340
        $parameters = ['cteDadosMsg' => $request];
341
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
342
        $this->lastResponse = $this->sendRequest($body, $parameters);
343
        return $this->lastResponse;
344
    }
345
346
    /**
347
     * Service for the distribution of summary information and
348
     * electronic tax documents of interest to an actor.
349
     * @param integer $ultNSU  last NSU number recived
350
     * @param integer $numNSU  NSU number you wish to consult
351
     * @param string $fonte data source 'AN' and for some cases it may be 'RS'
352
     * @return string
353
     */
354
    public function sefazDistDFe(
355
        $ultNSU = 0,
356
        $numNSU = 0,
357
        $fonte = 'AN'
358
    ) {
359
        //carrega serviço
360
        $servico = 'CTeDistribuicaoDFe';
361
        $this->checkContingencyForWebServices($servico);
362
        $this->servico(
363
            $servico,
364
            $fonte,
365
            $this->tpAmb,
366
            true
367
        );
368
        $cUF = UFList::getCodeByUF($this->config->siglaUF);
369
        $ultNSU = str_pad($ultNSU, 15, '0', STR_PAD_LEFT);
370
        $tagNSU = "<distNSU><ultNSU>$ultNSU</ultNSU></distNSU>";
371
        if ($numNSU != 0) {
372
            $numNSU = str_pad($numNSU, 15, '0', STR_PAD_LEFT);
373
            $tagNSU = "<consNSU><NSU>$numNSU</NSU></consNSU>";
374
        }
375
        //monta a consulta
376
        $consulta = "<distDFeInt xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
377
            . "<tpAmb>".$this->tpAmb."</tpAmb>"
378
            . "<cUFAutor>$cUF</cUFAutor>"
379
            . "<CNPJ>".$this->config->cnpj."</CNPJ>$tagNSU</distDFeInt>";
380
        //valida o xml da requisição
381
        $this->isValid($this->urlVersion, $consulta, 'distDFeInt');
382
        $this->lastRequest = $consulta;
383
        //montagem dos dados da mensagem SOAP
384
        $request = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$consulta</cteDadosMsg>";
385
        $parameters = ['cteDistDFeInteresse' => $request];
386
        $body = "<cteDistDFeInteresse xmlns=\"$this->urlNamespace\">"
387
            . $request
388
            . "</cteDistDFeInteresse>";
389
        //este webservice não requer cabeçalho
390
        $this->objHeader = null;
391
        $this->lastResponse = $this->sendRequest($body, $parameters);
392
        return $this->lastResponse;
393
    }
394
395
    /**
396
     * Request authorization for Letter of Correction
397
     * @param  string $chave
398
     * @param  array $infCorrecao
399
     * @param  int $nSeqEvento
400
     * @return string
401
     */
402
    public function sefazCCe($chave, $infCorrecao = [], $nSeqEvento = 1)
403
    {
404
        $uf = $this->validKeyByUF($chave);
405
        $tpEvento = 110110;
406
        $tagAdic = self::serializerCCe($infCorrecao);
407
        return $this->sefazEvento(
408
            $uf,
409
            $chave,
410
            $tpEvento,
411
            $nSeqEvento,
412
            $tagAdic
413
        );
414
    }
415
416
    /**
417
     * Request extension of the term of return of products of an NF-e of
418
     * consignment for industrialization to order with suspension of ICMS
419
     * in interstate operations
420
     * @param  string  $chNFe
421
     * @param  string  $nProt
422
     * @param  integer $tipo 1-primerio prazo, 2-segundo prazo
423
     * @param  array   $itens
424
     * @param  integer $nSeqEvento
425
     * @return string
426
     */
427
    public function sefazEPP(
428
        $chNFe,
429
        $nProt,
430
        $itens = array(),
431
        $tipo = 1,
432
        $nSeqEvento = 1
433
    ) {
434
        $uf = UFList::getUFByCode(substr($chNFe, 0, 2));
435
        $tpEvento = 111500;
436
        if ($tipo == 2) {
437
            $tpEvento = 111501;
438
        }
439
        $tagAdic = "<nProt>$nProt</nProt>";
440
        foreach ($itens as $item) {
441
            $tagAdic .= "<itemPedido numItem=\""
442
                . $item[0]
443
                . "\"><qtdeItem>"
444
                . $item[1]
445
                ."</qtdeItem></itemPedido>";
446
        }
447
        return $this->sefazEvento(
448
            $uf,
449
            $chNFe,
450
            $tpEvento,
451
            $nSeqEvento,
452
            $tagAdic
453
        );
454
    }
455
456
    /**
457
     * Request the cancellation of the request for an extension of the term
458
     * of return of products of an NF-e of consignment for industrialization
459
     * by order with suspension of ICMS in interstate operations
460
     * @param  string  $chNFe
461
     * @param  string  $nProt
462
     * @param  integer $nSeqEvento
463
     * @return string
464
     */
465
    public function sefazECPP(
466
        $chNFe,
467
        $nProt,
468
        $nSeqEvento = 1
469
    ) {
470
        $uf = UFList::getUFByCode(substr($chNFe, 0, 2));
471
        $tpEvento = 111502;
472
        $origEvent = 111500;
473
        if ($nSeqEvento == 2) {
474
            $tpEvento = 111503;
475
            $origEvent = 111501;
476
        }
477
        $sSeqEvento = str_pad($nSeqEvento, 2, "0", STR_PAD_LEFT);
478
        $idPedidoCancelado = "ID$origEvent$chNFe$sSeqEvento";
479
        $tagAdic = "<idPedidoCancelado>"
480
                . "$idPedidoCancelado"
481
                . "</idPedidoCancelado>"
482
                . "<nProt>$nProt</nProt>";
483
        return $this->sefazEvento(
484
            $uf,
485
            $chNFe,
486
            $tpEvento,
487
            $nSeqEvento,
488
            $tagAdic
489
        );
490
    }
491
492
    /**
493
     * Requires cte cancellation
494
     * @param  string $chave key of CTe
495
     * @param  string $xJust justificative 255 characters max
496
     * @param  string $nProt protocol number
497
     * @return string
498
     */
499
    public function sefazCancela($chave, $xJust, $nProt)
500
    {
501
        $uf = $this->validKeyByUF($chave);
502
        $xJust = Strings::replaceSpecialsChars(
503
            substr(trim($xJust), 0, 255)
504
        );
505
        $tpEvento = 110111;
506
        $nSeqEvento = 1;
507
        $tagAdic = "<evCancCTe>"
508
            . "<descEvento>Cancelamento</descEvento>"
509
            . "<nProt>$nProt</nProt>"
510
            . "<xJust>$xJust</xJust>"
511
            . "</evCancCTe>";
512
        return $this->sefazEvento(
513
            $uf,
514
            $chave,
515
            $tpEvento,
516
            $nSeqEvento,
517
            $tagAdic
518
        );
519
    }
520
521
    /**
522
     * Request the registration of the manifestation of recipient
523
     * @param string $chNFe
524
     * @param int $tpEvento
525
     * @param string $xJust Justification for not carrying out the operation
526
     * @param int $nSeqEvento
527
     * @return string
528
     */
529
    public function sefazManifesta(
530
        $chNFe,
531
        $tpEvento,
532
        $xJust = '',
533
        $nSeqEvento = 1,
534
        $ufEvento = 'RS'
535
    ) {
536
        $tagAdic = '';
537
        if ($tpEvento == 210240) {
538
            $xJust = Strings::replaceSpecialsChars(substr(trim($xJust), 0, 255));
539
            $tagAdic = "<xJust>$xJust</xJust>";
540
        }
541
        if ($tpEvento == 610110) {
542
            $xJust = Strings::replaceSpecialsChars(substr(trim($xJust), 0, 255));
543
            $tagAdic = "<evPrestDesacordo>"
544
                . "<descEvento>Prestação do Serviço em Desacordo</descEvento>"
545
                . "<indDesacordoOper>1</indDesacordoOper>"
546
                . "<xObs>$xJust</xObs>"
547
                . "</evPrestDesacordo>";
548
        }
549
        return $this->sefazEvento(
550
            $ufEvento,
551
            $chNFe,
552
            $tpEvento,
553
            $nSeqEvento,
554
            $tagAdic
555
        );
556
    }
557
558
    /**
559
     * Request authorization for issuance in contingency EPEC
560
     * @param  string $xml
561
     * @return string
562
     */
563
    public function sefazEPEC(&$xml)
564
    {
565
        $tagAdic = '';
566
        $tpEvento = 110140;
567
        $nSeqEvento = 1;
568
        if ($this->contingency->type !== 'EPEC') {
569
            throw new \RuntimeException('A contingência EPEC deve estar ativada.');
570
        }
571
        $xml = $this->correctNFeForContingencyMode($xml);
572
        $dom = new \DOMDocument('1.0', 'UTF-8');
573
        $dom->preserveWhiteSpace = false;
574
        $dom->formatOutput = false;
575
        $dom->loadXML($xml);
576
        $infNFe = $dom->getElementsByTagName('infNFe')->item(0);
577
        $emit = $dom->getElementsByTagName('emit')->item(0);
578
        $dest = $dom->getElementsByTagName('dest')->item(0);
579
        $cOrgaoAutor = UFList::getCodeByUF($this->config->siglaUF);
580
        $chNFe = substr($infNFe->getAttribute('Id'), 3, 44);
581
        // EPEC
582
        $dhEmi = $dom->getElementsByTagName('dhEmi')->item(0)->nodeValue;
583
        $tpNF = $dom->getElementsByTagName('tpNF')->item(0)->nodeValue;
584
        $emitIE = $emit->getElementsByTagName('IE')->item(0)->nodeValue;
585
        $destUF = $dest->getElementsByTagName('UF')->item(0)->nodeValue;
586
        $total = $dom->getElementsByTagName('total')->item(0);
587
        $vNF = $total->getElementsByTagName('vNF')->item(0)->nodeValue;
588
        $vICMS = $total->getElementsByTagName('vICMS')->item(0)->nodeValue;
589
        $vST = $total->getElementsByTagName('vST')->item(0)->nodeValue;
590
        $dID = $dest->getElementsByTagName('CNPJ')->item(0)->nodeValue;
591
        if (!empty($dID)) {
592
            $destID = "<CNPJ>$dID</CNPJ>";
593
        } else {
594
            $dID = $dest->getElementsByTagName('CPF')->item(0)->nodeValue;
595
            if (!empty($dID)) {
596
                $destID = "<CPF>$dID</CPF>";
597
            } else {
598
                $dID = $dest->getElementsByTagName('idEstrangeiro')
599
                    ->item(0)
600
                    ->nodeValue;
601
                $destID = "<idEstrangeiro>$dID</idEstrangeiro>";
602
            }
603
        }
604
        $dIE = !empty($dest->getElementsByTagName('IE')->item(0)->nodeValue) ?
605
                $dest->getElementsByTagName('IE')->item(0)->nodeValue : '';
606
        $destIE = '';
607
        if (!empty($dIE)) {
608
            $destIE = "<IE>$dIE</IE>";
609
        }
610
        $tagAdic = "<cOrgaoAutor>$cOrgaoAutor</cOrgaoAutor>"
611
            . "<tpAutor>1</tpAutor>"
612
            . "<verAplic>$this->verAplic</verAplic>"
613
            . "<dhEmi>$dhEmi</dhEmi>"
614
            . "<tpNF>$tpNF</tpNF>"
615
            . "<IE>$emitIE</IE>"
616
            . "<dest>"
617
            . "<UF>$destUF</UF>"
618
            . $destID
619
            . $destIE
620
            . "<vNF>$vNF</vNF>"
621
            . "<vICMS>$vICMS</vICMS>"
622
            . "<vST>$vST</vST>"
623
            . "</dest>";
624
625
        return $this->sefazEvento(
626
            'AN',
627
            $chNFe,
628
            $tpEvento,
629
            $nSeqEvento,
630
            $tagAdic
631
        );
632
    }
633
634
    /**
635
     * Send event to SEFAZ
636
     * @param string $uf
637
     * @param string $chave
638
     * @param int $tpEvento
639
     * @param int $nSeqEvento
640
     * @param string $tagAdic
641
     * @return string
642
     */
643
    public function sefazEvento(
644
        $uf,
645
        $chave,
646
        $tpEvento,
647
        $nSeqEvento = 1,
648
        $tagAdic = ''
649
    ) {
650
        $ignore = false;
651
        if ($tpEvento == 110140) {
652
            $ignore = true;
653
        }
654
        $servico = 'CteRecepcaoEvento';
655
        $this->checkContingencyForWebServices($servico);
656
        $this->servico(
657
            $servico,
658
            $uf,
659
            $this->tpAmb,
660
            $ignore
661
        );
662
        $ev = $this->tpEv($tpEvento);
663
        $aliasEvento = $ev->alias;
664
        $descEvento = $ev->desc;
665
        $cnpj = $this->config->cnpj;
666
        $dt = new \DateTime();
667
        $dhEvento = $dt->format('Y-m-d\TH:i:sP');
668
        $sSeqEvento = str_pad($nSeqEvento, 2, "0", STR_PAD_LEFT);
669
        $eventId = "ID".$tpEvento.$chave.$sSeqEvento;
670
        $cOrgao = UFList::getCodeByUF($uf);
671
672
        $request = "<eventoCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
673
            . "<infEvento Id=\"$eventId\">"
674
            . "<cOrgao>$cOrgao</cOrgao>"
675
            . "<tpAmb>$this->tpAmb</tpAmb>"
676
            . "<CNPJ>$cnpj</CNPJ>"
677
            . "<chCTe>$chave</chCTe>"
678
            . "<dhEvento>$dhEvento</dhEvento>"
679
            . "<tpEvento>$tpEvento</tpEvento>"
680
            . "<nSeqEvento>$nSeqEvento</nSeqEvento>"
681
            . "<detEvento versaoEvento=\"$this->urlVersion\">"
682
            . "$tagAdic"
683
            . "</detEvento>"
684
            . "</infEvento>"
685
            . "</eventoCTe>";
686
687
        //assinatura dos dados
688
        $request = Signer::sign(
689
            $this->certificate,
690
            $request,
691
            'infEvento',
692
            'Id',
693
            $this->algorithm,
694
            $this->canonical
695
        );
696
697
        $request = Strings::clearXmlString($request, true);
698
//        if ($tpEvento != 610110) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
699
//            $lote = $dt->format('YmdHis').rand(0, 9);
700
//            $request = "<envEventoCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
701
//                . "<idLote>$lote</idLote>"
702
//                . $request
703
//                . "</envEventoCTe>";
704
//        }
705
        $this->isValid($this->urlVersion, $request, 'eventoCTe');
706
        $this->lastRequest = $request;
707
        $parameters = ['cteDadosMsg' => $request];
708
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
709
        $this->lastResponse = $this->sendRequest($body, $parameters);
710
        return $this->lastResponse;
711
    }
712
713
    /**
714
     * Request the NFe download already manifested by its recipient, by the key
715
     * using new service in CTeDistribuicaoDFe
716
     * @param  string $chave
717
     * @return string
718
     */
719
    public function sefazDownload($chave)
720
    {
721
        //carrega serviço
722
        $servico = 'CteDistribuicaoDFe';
723
        $this->checkContingencyForWebServices($servico);
724
        $this->servico(
725
            $servico,
726
            'AN',
727
            $this->tpAmb,
728
            true
729
        );
730
        $cUF = UFList::getCodeByUF($this->config->siglaUF);
731
        $tagChave = "<consChNFe><chNFe>$chave</chNFe></consChNFe>";
732
        //monta a consulta
733
        $consulta = "<distDFeInt xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
734
            . "<tpAmb>".$this->tpAmb."</tpAmb>"
735
            . "<cUFAutor>$cUF</cUFAutor>"
736
            . "<CNPJ>".$this->config->cnpj."</CNPJ>$tagChave</distDFeInt>";
737
        //valida o xml da requisição
738
        $this->isValid($this->urlVersion, $consulta, 'distDFeInt');
739
        $this->lastRequest = $consulta;
740
        //montagem dos dados da mensagem SOAP
741
        $request = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$consulta</cteDadosMsg>";
742
        $parameters = ['cteDistDFeInteresse' => $request];
743
        $body = "<cteDistDFeInteresse xmlns=\"$this->urlNamespace\">"
744
            . $request
745
            . "</cteDistDFeInteresse>";
746
        //este webservice não requer cabeçalho
747
        $this->objHeader = null;
748
        $this->lastResponse = $this->sendRequest($body, $parameters);
749
        return $this->lastResponse;
750
    }
751
752
    /**
753
     * Maintenance of the Taxpayer Security Code - CSC (Old Token)
754
     * @param int $indOp Identificador do tipo de operação:
755
     *                   1 - Consulta CSC Ativos;
756
     *                   2 - Solicita novo CSC;
757
     *                   3 - Revoga CSC Ativo
758
     * @return string
759
     */
760
    public function sefazCsc($indOp)
761
    {
762
        if ($this->modelo != 65) {
763
            throw new RuntimeException(
764
                "Esta operação é exclusiva de NFCe modelo [65], "
765
                . "você está usando modelo [55]."
766
            );
767
        }
768
        $raizCNPJ = substr($this->config->cnpj, 0, -6);
769
        //carrega serviço
770
        $servico = 'CscNFCe';
771
        $this->checkContingencyForWebServices($servico);
772
        $this->servico(
773
            $servico,
774
            $this->config->siglaUF,
775
            $this->tpAmb
776
        );
777
        $request = "<admCscNFCe versao=\"$this->urlVersion\" xmlns=\"$this->urlPortal\">"
778
            . "<tpAmb>$this->tpAmb</tpAmb>"
779
            . "<indOp>$indOp</indOp>"
780
            . "<raizCNPJ>$raizCNPJ</raizCNPJ>"
781
            . "</admCscNFCe>";
782
        if ($indOp == 3) {
783
            $request = "<admCscNFCe versao=\"$this->urlVersion\" xmlns=\"$this->urlPortal\">"
784
            . "<tpAmb>$this->tpAmb</tpAmb>"
785
            . "<indOp>$indOp</indOp>"
786
            . "<raizCNPJ>$raizCNPJ</raizCNPJ>"
787
            . "<dadosCsc>"
788
            . "<idCsc>".$this->config->CSCid."</idCsc>"
789
            . "<codigoCsc>".$this->config->CSC."</codigoCsc>"
790
            . "</dadosCsc>"
791
            . "</admCscNFCe>";
792
        }
793
        //o xsd não está disponivel
794
        //$this->isValid($this->urlVersion, $request, 'cscNFCe');
795
        $this->lastRequest = $request;
796
        $parameters = ['cteDadosMsg' => $request];
797
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
798
        $this->lastResponse = $this->sendRequest($body, $parameters);
799
        return $this->lastResponse;
800
    }
801
802
    /**
803
     * Checks the validity of an NFe, normally used for received NFe
804
     * @param  string $cte
805
     * @return boolean
806
     */
807
    public function sefazValidate($cte)
808
    {
809
        //verifica a assinatura da NFe, exception caso de falha
810
        Signer::isSigned($cte);
811
        $dom = new \DOMDocument('1.0', 'utf-8');
812
        $dom->formatOutput = false;
813
        $dom->preserveWhiteSpace = false;
814
        $dom->loadXML($cte);
815
        //verifica a validade no webservice da SEFAZ
816
        $tpAmb = $dom->getElementsByTagName('tpAmb')->item(0)->nodeValue;
817
        $infNFe  = $dom->getElementsByTagName('infNFe')->item(0);
818
        $chNFe = preg_replace('/[^0-9]/', '', $infNFe->getAttribute("Id"));
819
        $protocol = $dom->getElementsByTagName('nProt')->item(0)->nodeValue;
820
        $digval = $dom->getElementsByTagName('DigestValue')->item(0)->nodeValue;
821
        //consulta a NFe
822
        $response = $this->sefazConsultaChave($chNFe, $tpAmb);
823
        $ret = new \DOMDocument('1.0', 'UTF-8');
824
        $ret->preserveWhiteSpace = false;
825
        $ret->formatOutput = false;
826
        $ret->loadXML($response);
827
        $retProt = $ret->getElementsByTagName('protNFe')->item(0);
828
        if (!isset($retProt)) {
829
            throw new InvalidArgumentException(
830
                'O documento de resposta não contêm o NODE "protNFe".'
831
            );
832
        }
833
        $infProt = $ret->getElementsByTagName('infProt')->item(0);
834
        $cStat  = $infProt->getElementsByTagName('cStat')->item(0)->nodeValue;
835
        $xMotivo = $infProt->getElementsByTagName('xMotivo')->item(0)->nodeValue;
836
        $dig = $infProt->getElementsByTagName("digVal")->item(0);
837
        $digProt = '000';
838
        if (isset($dig)) {
839
            $digProt = $dig->nodeValue;
840
        }
841
        $chProt = $infProt->getElementsByTagName("chNFe")->item(0)->nodeValue;
842
        $nProt = $infProt->getElementsByTagName("nProt")->item(0)->nodeValue;
843
        if ($protocol == $nProt
844
            && $digval == $digProt
845
            && $chNFe == $chProt
846
        ) {
847
            return true;
848
        }
849
        return false;
850
    }
851
852
    /**
853
     *
854
     * @param  int $tpEvento
855
     * @return \stdClass
856
     * @throws Exception
857
     */
858
    private function tpEv($tpEvento)
859
    {
860
        $std = new \stdClass();
861
        $std->alias = '';
862
        $std->desc = '';
863
        switch ($tpEvento) {
864
            case 110110:
865
                //CCe
866
                $std->alias = 'CCe';
867
                $std->desc = 'Carta de Correcao';
868
                break;
869
            case 110111:
870
                //cancelamento
871
                $std->alias = 'CancCTe';
872
                $std->desc = 'Cancelamento';
873
                break;
874
            case 110140:
875
                //EPEC
876
                //emissão em contingência EPEC
877
                $std->alias = 'EPEC';
878
                $std->desc = 'EPEC';
879
                break;
880
            case 111500:
881
            case 111501:
882
                //EPP
883
                //Pedido de prorrogação
884
                $std->alias = 'EPP';
885
                $std->desc = 'Pedido de Prorrogacao';
886
                break;
887
            case 111502:
888
            case 111503:
889
                //ECPP
890
                //Cancelamento do Pedido de prorrogação
891
                $std->alias = 'ECPP';
892
                $std->desc = 'Cancelamento de Pedido de Prorrogacao';
893
                break;
894
            case 210200:
895
                //Confirmacao da Operacao
896
                $std->alias = 'EvConfirma';
897
                $std->desc = 'Confirmacao da Operacao';
898
                break;
899
            case 210210:
900
                //Ciencia da Operacao
901
                $std->alias = 'EvCiencia';
902
                $std->desc = 'Ciencia da Operacao';
903
                $std->tpAutor = 2;
904
                break;
905
            case 210220:
906
                //Desconhecimento da Operacao
907
                $std->alias = 'EvDesconh';
908
                $std->desc = 'Desconhecimento da Operacao';
909
                break;
910
            case 210240:
911
                //Operacao não Realizada
912
                $std->alias = 'EvNaoRealizada';
913
                $std->desc = 'Operacao nao Realizada';
914
                break;
915
            case 610110:
916
                //Serviço em desacordo
917
                $std->alias = 'EvPrestDesacordo';
918
                $std->desc = 'Servico em desacordo';
919
                break;
920
            default:
921
                $msg = "O código do tipo de evento informado não corresponde a "
922
                . "nenhum evento estabelecido.";
923
                throw new RuntimeException($msg);
924
        }
925
        return $std;
926
    }
927
928
    private static function serializerCCe(array $infCorrecoes)
929
    {
930
        // Grupo de Informações de Correção
931
        $correcoes = '';
932
        foreach ($infCorrecoes as $info) {
933
            $nroItemAlteradoOptionalElement = '';
934
            if (key_exists('nroItemAlterado', $info)) {
935
                $nroItemAlteradoOptionalElement = "<nroItemAlterado>{$info['nroItemAlterado']}</nroItemAlterado>";
936
            }
937
            $correcoes .= "<infCorrecao>" .
938
                "<grupoAlterado>{$info['grupoAlterado']}</grupoAlterado>" .
939
                "<campoAlterado>{$info['campoAlterado']}</campoAlterado>" .
940
                "<valorAlterado>{$info['valorAlterado']}</valorAlterado>" .
941
                "{$nroItemAlteradoOptionalElement}" .
942
                "</infCorrecao>";
943
        }
944
        //monta mensagem
945
        return "<evCCeCTe>" .
946
            "<descEvento>Carta de Correcao</descEvento>" .
947
            "{$correcoes}" .
948
            "<xCondUso>" .
949
            "A Carta de Correcao e disciplinada pelo Art. 58-B do " .
950
            "CONVENIO/SINIEF 06/89: Fica permitida a utilizacao de carta de " .
951
            "correcao, para regularizacao de erro ocorrido na emissao de " .
952
            "documentos fiscais relativos a prestacao de servico de transporte, " .
953
            "desde que o erro nao esteja relacionado com: I - as variaveis que " .
954
            "determinam o valor do imposto tais como: base de calculo, " .
955
            "aliquota, diferenca de preco, quantidade, valor da prestacao;II - " .
956
            "a correcao de dados cadastrais que implique mudanca do emitente, " .
957
            "tomador, remetente ou do destinatario;III - a data de emissao ou " .
958
            "de saida." .
959
            "</xCondUso>" .
960
        "</evCCeCTe>";
961
    }
962
}
963