Passed
Push — master ( dd77fa...4239ab )
by
unknown
02:11
created

Tools::sefazCancelaCE()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 0
cts 17
cp 0
rs 9.7
c 0
b 0
f 0
cc 1
nc 1
nop 4
crap 2
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;
0 ignored issues
show
Unused Code introduced by
$method is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
81
        if ($compactar) {
82
            $gzdata = base64_encode(gzencode($request, 9, FORCE_GZIP));
83
            $body = "<cteDadosMsgZip xmlns=\"$this->urlNamespace\">$gzdata</cteDadosMsgZip>";
0 ignored issues
show
Unused Code introduced by
$body is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
84
            $method = $this->urlMethod."Zip";
0 ignored issues
show
Unused Code introduced by
$method is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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');
0 ignored issues
show
Bug introduced by
It seems like $request defined by preg_replace('/<\\?xml.*\\?>/', '', $xml) on line 107 can also be of type array<integer,string>; however, NFePHP\CTe\Common\Tools::isValid() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
109
        $this->lastRequest = $request;
0 ignored issues
show
Documentation Bug introduced by
It seems like $request can also be of type array<integer,string>. However, the property $lastRequest is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
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";
0 ignored issues
show
Unused Code introduced by
$txtFile is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
280
        } elseif ($iest != '') {
281
            $filter = "<IE>$iest</IE>";
282
            $txtFile = "IE_$iest";
0 ignored issues
show
Unused Code introduced by
$txtFile is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
283
        } else {
284
            $filter = "<CPF>$cpf</CPF>";
285
            $txtFile = "CPF_$cpf";
0 ignored issues
show
Unused Code introduced by
$txtFile is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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 = '';
0 ignored issues
show
Unused Code introduced by
$tagAdic is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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;
0 ignored issues
show
Unused Code introduced by
$aliasEvento is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
664
        $descEvento = $ev->desc;
0 ignored issues
show
Unused Code introduced by
$descEvento is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

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