Passed
Push — master ( d4f5be...652757 )
by
unknown
02:22 queued 14s
created

Tools::sefazCadastro()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 37
ccs 0
cts 36
cp 0
rs 9.328
c 0
b 0
f 0
cc 3
nc 3
nop 4
crap 12
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->correctCTeForContingencyMode($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
            . ((strlen($this->config->cnpj)==14) ? 
380
                "<CNPJ>".$this->config->cnpj."</CNPJ>" : 
381
                "<CPF>".$this->config->cnpj."</CPF>"
382
              )
383
            . $tagNSU."</distDFeInt>";
384
        //valida o xml da requisição
385
        $this->isValid($this->urlVersion, $consulta, 'distDFeInt');
386
        $this->lastRequest = $consulta;
387
        //montagem dos dados da mensagem SOAP
388
        $request = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$consulta</cteDadosMsg>";
389
        $parameters = ['cteDistDFeInteresse' => $request];
390
        $body = "<cteDistDFeInteresse xmlns=\"$this->urlNamespace\">"
391
            . $request
392
            . "</cteDistDFeInteresse>";
393
        //este webservice não requer cabeçalho
394
        $this->objHeader = null;
395
        $this->lastResponse = $this->sendRequest($body, $parameters);
396
        return $this->lastResponse;
397
    }
398
399
    /**
400
     * Request authorization for Letter of Correction
401
     * @param  string $chave
402
     * @param  array $infCorrecao
403
     * @param  int $nSeqEvento
404
     * @return string
405
     */
406
    public function sefazCCe($chave, $infCorrecao = [], $nSeqEvento = 1)
407
    {
408
        $uf = $this->validKeyByUF($chave);
409
        $tpEvento = 110110;
410
        $tagAdic = self::serializerCCe($infCorrecao);
411
        return $this->sefazEvento(
412
            $uf,
413
            $chave,
414
            $tpEvento,
415
            $nSeqEvento,
416
            $tagAdic
417
        );
418
    }
419
420
    /**
421
     * Request extension of the term of return of products of an NF-e of
422
     * consignment for industrialization to order with suspension of ICMS
423
     * in interstate operations
424
     * @param  string  $chNFe
425
     * @param  string  $nProt
426
     * @param  integer $tipo 1-primerio prazo, 2-segundo prazo
427
     * @param  array   $itens
428
     * @param  integer $nSeqEvento
429
     * @return string
430
     */
431
    public function sefazEPP(
432
        $chNFe,
433
        $nProt,
434
        $itens = array(),
435
        $tipo = 1,
436
        $nSeqEvento = 1
437
    ) {
438
        $uf = UFList::getUFByCode(substr($chNFe, 0, 2));
439
        $tpEvento = 111500;
440
        if ($tipo == 2) {
441
            $tpEvento = 111501;
442
        }
443
        $tagAdic = "<nProt>$nProt</nProt>";
444
        foreach ($itens as $item) {
445
            $tagAdic .= "<itemPedido numItem=\""
446
                . $item[0]
447
                . "\"><qtdeItem>"
448
                . $item[1]
449
                ."</qtdeItem></itemPedido>";
450
        }
451
        return $this->sefazEvento(
452
            $uf,
453
            $chNFe,
454
            $tpEvento,
455
            $nSeqEvento,
456
            $tagAdic
457
        );
458
    }
459
460
    /**
461
     * Request the cancellation of the request for an extension of the term
462
     * of return of products of an NF-e of consignment for industrialization
463
     * by order with suspension of ICMS in interstate operations
464
     * @param  string  $chNFe
465
     * @param  string  $nProt
466
     * @param  integer $nSeqEvento
467
     * @return string
468
     */
469
    public function sefazECPP(
470
        $chNFe,
471
        $nProt,
472
        $nSeqEvento = 1
473
    ) {
474
        $uf = UFList::getUFByCode(substr($chNFe, 0, 2));
475
        $tpEvento = 111502;
476
        $origEvent = 111500;
477
        if ($nSeqEvento == 2) {
478
            $tpEvento = 111503;
479
            $origEvent = 111501;
480
        }
481
        $sSeqEvento = str_pad($nSeqEvento, 2, "0", STR_PAD_LEFT);
482
        $idPedidoCancelado = "ID$origEvent$chNFe$sSeqEvento";
483
        $tagAdic = "<idPedidoCancelado>"
484
                . "$idPedidoCancelado"
485
                . "</idPedidoCancelado>"
486
                . "<nProt>$nProt</nProt>";
487
        return $this->sefazEvento(
488
            $uf,
489
            $chNFe,
490
            $tpEvento,
491
            $nSeqEvento,
492
            $tagAdic
493
        );
494
    }
495
496
    /**
497
     * Requires cte cancellation
498
     * @param  string $chave key of CTe
499
     * @param  string $xJust justificative 255 characters max
500
     * @param  string $nProt protocol number
501
     * @return string
502
     */
503
    public function sefazCancela($chave, $xJust, $nProt)
504
    {
505
        $uf = $this->validKeyByUF($chave);
506
        $xJust = Strings::replaceSpecialsChars(
507
            substr(trim($xJust), 0, 255)
508
        );
509
        $tpEvento = 110111;
510
        $nSeqEvento = 1;
511
        $tagAdic = "<evCancCTe>"
512
            . "<descEvento>Cancelamento</descEvento>"
513
            . "<nProt>$nProt</nProt>"
514
            . "<xJust>$xJust</xJust>"
515
            . "</evCancCTe>";
516
        return $this->sefazEvento(
517
            $uf,
518
            $chave,
519
            $tpEvento,
520
            $nSeqEvento,
521
            $tagAdic
522
        );
523
    }
524
525
    /**
526
     * Request the registration of the manifestation of recipient
527
     * @param string $chNFe
528
     * @param int $tpEvento
529
     * @param string $xJust Justification for not carrying out the operation
530
     * @param int $nSeqEvento
531
     * @return string
532
     */
533
    public function sefazManifesta(
534
        $chNFe,
535
        $tpEvento,
536
        $xJust = '',
537
        $nSeqEvento = 1,
538
        $ufEvento = 'RS'
539
    ) {
540
        $tagAdic = '';
541
        if ($tpEvento == 610110) {
542
            $xJust = Strings::replaceSpecialsChars(substr(trim($xJust), 0, 255));
543
            $tagAdic = "<evPrestDesacordo>"
544
                . "<descEvento>Prestacao do Servico 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->correctCTeForContingencyMode($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
        $this->isValid($this->urlVersion, $request, 'eventoCTe');
699
        $this->lastRequest = $request;
700
        $parameters = ['cteDadosMsg' => $request];
701
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
702
        $this->lastResponse = $this->sendRequest($body, $parameters);
703
        return $this->lastResponse;
704
    }
705
706
    /**
707
     * Request the NFe download already manifested by its recipient, by the key
708
     * using new service in CTeDistribuicaoDFe
709
     * @param  string $chave
710
     * @return string
711
     */
712
    public function sefazDownload($chave)
713
    {
714
        //carrega serviço
715
        $servico = 'CteDistribuicaoDFe';
716
        $this->checkContingencyForWebServices($servico);
717
        $this->servico(
718
            $servico,
719
            'AN',
720
            $this->tpAmb,
721
            true
722
        );
723
        $cUF = UFList::getCodeByUF($this->config->siglaUF);
724
        $tagChave = "<consChNFe><chNFe>$chave</chNFe></consChNFe>";
725
        //monta a consulta
726
            . ((strlen($this->config->cnpj)==14) ? 
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected '.'
Loading history...
727
                "<CNPJ>".$this->config->cnpj."</CNPJ>" : 
728
                "<CPF>".$this->config->cnpj."</CPF>"
729
              )
730
            . $tagChave."</distDFeInt>";
731
        //valida o xml da requisição
732
        $this->isValid($this->urlVersion, $consulta, 'distDFeInt');
733
        $this->lastRequest = $consulta;
734
        //montagem dos dados da mensagem SOAP
735
        $request = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$consulta</cteDadosMsg>";
736
        $parameters = ['cteDistDFeInteresse' => $request];
737
        $body = "<cteDistDFeInteresse xmlns=\"$this->urlNamespace\">"
738
            . $request
739
            . "</cteDistDFeInteresse>";
740
        //este webservice não requer cabeçalho
741
        $this->objHeader = null;
742
        $this->lastResponse = $this->sendRequest($body, $parameters);
743
        return $this->lastResponse;
744
    }
745
746
    /**
747
     * Maintenance of the Taxpayer Security Code - CSC (Old Token)
748
     * @param int $indOp Identificador do tipo de operação:
749
     *                   1 - Consulta CSC Ativos;
750
     *                   2 - Solicita novo CSC;
751
     *                   3 - Revoga CSC Ativo
752
     * @return string
753
     */
754
    public function sefazCsc($indOp)
755
    {
756
        if ($this->modelo != 65) {
757
            throw new RuntimeException(
758
                "Esta operação é exclusiva de NFCe modelo [65], "
759
                . "você está usando modelo [55]."
760
            );
761
        }
762
        $raizCNPJ = substr($this->config->cnpj, 0, -6);
763
        //carrega serviço
764
        $servico = 'CscNFCe';
765
        $this->checkContingencyForWebServices($servico);
766
        $this->servico(
767
            $servico,
768
            $this->config->siglaUF,
769
            $this->tpAmb
770
        );
771
        $request = "<admCscNFCe versao=\"$this->urlVersion\" xmlns=\"$this->urlPortal\">"
772
            . "<tpAmb>$this->tpAmb</tpAmb>"
773
            . "<indOp>$indOp</indOp>"
774
            . "<raizCNPJ>$raizCNPJ</raizCNPJ>"
775
            . "</admCscNFCe>";
776
        if ($indOp == 3) {
777
            $request = "<admCscNFCe versao=\"$this->urlVersion\" xmlns=\"$this->urlPortal\">"
778
            . "<tpAmb>$this->tpAmb</tpAmb>"
779
            . "<indOp>$indOp</indOp>"
780
            . "<raizCNPJ>$raizCNPJ</raizCNPJ>"
781
            . "<dadosCsc>"
782
            . "<idCsc>".$this->config->CSCid."</idCsc>"
783
            . "<codigoCsc>".$this->config->CSC."</codigoCsc>"
784
            . "</dadosCsc>"
785
            . "</admCscNFCe>";
786
        }
787
        //o xsd não está disponivel
788
        //$this->isValid($this->urlVersion, $request, 'cscNFCe');
789
        $this->lastRequest = $request;
790
        $parameters = ['cteDadosMsg' => $request];
791
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
792
        $this->lastResponse = $this->sendRequest($body, $parameters);
793
        return $this->lastResponse;
794
    }
795
796
    /**
797
     * Checks the validity of an CTe, normally used for received CTe
798
     * @param  string $cte
799
     * @return boolean
800
     */
801
    public function sefazValidate($cte)
802
    {
803
        if (empty($cte)) {
804
            throw new InvalidArgumentException('Validacao CT-e: a string do CT-e esta vazio!');
805
        }
806
        //verifica a assinatura do CTe, exception caso de falha
807
        Signer::isSigned($cte, 'infCte');
808
        $dom = new \DOMDocument('1.0', 'utf-8');
809
        $dom->formatOutput = false;
810
        $dom->preserveWhiteSpace = false;
811
        $dom->loadXML($cte);
812
        //verifica a validade no webservice da SEFAZ
813
        $tpAmb = $dom->getElementsByTagName('tpAmb')->item(0)->nodeValue;
814
        $infCTe  = $dom->getElementsByTagName('infCte')->item(0);
815
        $chCTe = preg_replace('/[^0-9]/', '', $infCTe->getAttribute("Id"));
816
        $protocol = $dom->getElementsByTagName('nProt')->item(0)->nodeValue;
817
        $digval = $dom->getElementsByTagName('DigestValue')->item(0)->nodeValue;
818
        //consulta o CTe
819
        $response = $this->sefazConsultaChave($chCTe, $tpAmb);
820
        $ret = new \DOMDocument('1.0', 'UTF-8');
821
        $ret->preserveWhiteSpace = false;
822
        $ret->formatOutput = false;
823
        $ret->loadXML($response);
824
        $retProt = $ret->getElementsByTagName('protCTe')->item(0);
825
        if (!isset($retProt)) {
826
            $xMotivo = $ret->getElementsByTagName('xMotivo')->item(0);
827
            if (isset($xMotivo)) {
828
                throw new InvalidArgumentException('Validacao CT-e: ' . $xMotivo->nodeValue);
829
            } else {
830
                throw new InvalidArgumentException('O documento de resposta nao contem o node "protCTe".');
831
            }
832
        }
833
        $infProt = $ret->getElementsByTagName('infProt')->item(0);
834
        $dig = $infProt->getElementsByTagName("digVal")->item(0);
835
        $digProt = '000';
836
        if (isset($dig)) {
837
            $digProt = $dig->nodeValue;
838
        }
839
        $chProt = $infProt->getElementsByTagName("chCTe")->item(0)->nodeValue;
840
        $nProt = $infProt->getElementsByTagName("nProt")->item(0)->nodeValue;
841
        if ($protocol == $nProt && $digval == $digProt && $chCTe == $chProt) {
842
            return true;
843
        }
844
        return false;
845
    }
846
847
    /**
848
     * Requires CE
849
     * @param  string $chave key of CTe
850
     * @param  string $nProt Protocolo do CTe
851
     * @param  string $xNome Nome de quem recebeu a entrega
852
     * @param  string $nDoc  Documento de quem recebeu a entrega
853
     * @param  string $hash  Hash da Chave de acesso do CT-e + Imagem da assinatura no formato Base64
854
     * @param  int    $latitude  Latitude do ponto da entrega
855
     * @param  int    $longitude  Longitude do ponto da entrega
856
     * @param  int    $nSeqEvento No. sequencial do evento
857
     * @param  string $dhEventoEntrega Data e hora da geração do hash da entrega
858
     * @param  array  $aNFes Chave das NFes entregues
859
     * @return string
860
     */
861
    public function sefazCE(
862
        $chave,
863
        $nProt,
864
        $xNome,
865
        $nDoc,
866
        $hash,
867
        $latitude,
868
        $longitude,
869
        $nSeqEvento,
870
        $dhEventoEntrega,
871
        $aNFes = []
872
    ) {
873
        $uf = $this->validKeyByUF($chave);
874
        $tpEvento = 110180;
875
        
876
        /* relaciona as chaves das NFes */
877
        $infEntrega = '';
878
        foreach ($aNFes as $NFe) {
879
            $infEntrega .= "<infEntrega>"
880
                . "<chNFe>$NFe</chNFe>"
881
                . "</infEntrega>";
882
        }
883
884
        $tagAdic = "<evCECTe>"
885
            . "<descEvento>Comprovante de Entrega do CT-e</descEvento>"
886
            . "<nProt>$nProt</nProt>"
887
            . "<dhEntrega>$dhEventoEntrega</dhEntrega>"
888
            . "<nDoc>$nDoc</nDoc>"
889
            . "<xNome>$xNome</xNome>"
890
            . "<latitude>$latitude</latitude>"
891
            . "<longitude>$longitude</longitude>"
892
            . "<hashEntrega>$hash</hashEntrega>"
893
            . "<dhHashEntrega>$dhEventoEntrega</dhHashEntrega>"
894
            . $infEntrega
895
            . "</evCECTe>";
896
        return $this->sefazEvento(
897
            $uf,
898
            $chave,
899
            $tpEvento,
900
            $nSeqEvento,
901
            $tagAdic
902
        );
903
    }
904
905
    /**
906
     * Requires CE cancellation
907
     * @param  string $chave key of CTe
908
     * @param  string $nProt protocolo do CTe
909
     * @param  string $nProtCE protocolo do CE
910
     * @param  int    $nSeqEvento No. sequencial do evento
911
     * @return string
912
     */
913
    public function sefazCancelaCE($chave, $nProt, $nProtCE, $nSeqEvento)
914
    {
915
        $uf = $this->validKeyByUF($chave);
916
        $tpEvento = 110181;
917
        $tagAdic = "<evCancCECTe>"
918
            . "<descEvento>Cancelamento do Comprovante de Entrega do CT-e</descEvento>"
919
            . "<nProt>$nProt</nProt>"
920
            . "<nProtCE>$nProtCE</nProtCE>"
921
            . "</evCancCECTe>";
922
        return $this->sefazEvento(
923
            $uf,
924
            $chave,
925
            $tpEvento,
926
            $nSeqEvento,
927
            $tagAdic
928
        );
929
    }
930
931
    /**
932
     *
933
     * @param  int $tpEvento
934
     * @return \stdClass
935
     * @throws Exception
936
     */
937
    private function tpEv($tpEvento)
938
    {
939
        $std = new \stdClass();
940
        $std->alias = '';
941
        $std->desc = '';
942
        switch ($tpEvento) {
943
            case 110110:
944
                //CCe
945
                $std->alias = 'CCe';
946
                $std->desc = 'Carta de Correcao';
947
                break;
948
            case 110111:
949
                //cancelamento
950
                $std->alias = 'CancCTe';
951
                $std->desc = 'Cancelamento';
952
                break;
953
            case 110113:
954
                //EPEC
955
                //emissão em contingência EPEC
956
                $std->alias = 'EPEC';
957
                $std->desc = 'EPEC';
958
                break;
959
            case 110180:
960
                //comprovante de entrega
961
                $std->alias = 'evCECTe';
962
                $std->desc = 'Comprovante de Entrega';
963
                break;
964
            case 110181:
965
                //cancelamento do comprovante de entrega
966
                $std->alias = 'evCancCECTe';
967
                $std->desc = 'Cancelamento do Comprovante de Entrega';
968
                break;
969
            case 610110:
970
                //Serviço em desacordo
971
                $std->alias = 'EvPrestDesacordo';
972
                $std->desc = 'Servico em desacordo';
973
                break;
974
            default:
975
                $msg = "O código do tipo de evento informado não corresponde a "
976
                . "nenhum evento estabelecido.";
977
                throw new RuntimeException($msg);
978
        }
979
        return $std;
980
    }
981
982
    private static function serializerCCe(array $infCorrecoes)
983
    {
984
        // Grupo de Informações de Correção
985
        $correcoes = '';
986
        foreach ($infCorrecoes as $info) {
987
            $nroItemAlteradoOptionalElement = '';
988
            if (key_exists('nroItemAlterado', $info)) {
989
                $nroItemAlteradoOptionalElement = "<nroItemAlterado>{$info['nroItemAlterado']}</nroItemAlterado>";
990
            }
991
            $correcoes .= "<infCorrecao>" .
992
                "<grupoAlterado>{$info['grupoAlterado']}</grupoAlterado>" .
993
                "<campoAlterado>{$info['campoAlterado']}</campoAlterado>" .
994
                "<valorAlterado>{$info['valorAlterado']}</valorAlterado>" .
995
                "{$nroItemAlteradoOptionalElement}" .
996
                "</infCorrecao>";
997
        }
998
        //monta mensagem
999
        return "<evCCeCTe>" .
1000
            "<descEvento>Carta de Correcao</descEvento>" .
1001
            "{$correcoes}" .
1002
            "<xCondUso>" .
1003
            "A Carta de Correcao e disciplinada pelo Art. 58-B do " .
1004
            "CONVENIO/SINIEF 06/89: Fica permitida a utilizacao de carta de " .
1005
            "correcao, para regularizacao de erro ocorrido na emissao de " .
1006
            "documentos fiscais relativos a prestacao de servico de transporte, " .
1007
            "desde que o erro nao esteja relacionado com: I - as variaveis que " .
1008
            "determinam o valor do imposto tais como: base de calculo, " .
1009
            "aliquota, diferenca de preco, quantidade, valor da prestacao;II - " .
1010
            "a correcao de dados cadastrais que implique mudanca do emitente, " .
1011
            "tomador, remetente ou do destinatario;III - a data de emissao ou " .
1012
            "de saida." .
1013
            "</xCondUso>" .
1014
        "</evCCeCTe>";
1015
    }
1016
}
1017