Passed
Push — master ( 2751ee...58996b )
by
unknown
41s
created

Tools::tpEv()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 34
ccs 0
cts 29
cp 0
rs 9.0648
c 0
b 0
f 0
cc 5
nc 5
nop 1
crap 30
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;
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($cons, 9, FORCE_GZIP));
0 ignored issues
show
Bug introduced by
The variable $cons does not exist. Did you forget to declare it?

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

Loading history...
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
            . "<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 == 610110) {
538
            $xJust = Strings::replaceSpecialsChars(substr(trim($xJust), 0, 255));
539
            $tagAdic = "<evPrestDesacordo>"
540
                . "<descEvento>Prestação do Serviço em Desacordo</descEvento>"
541
                . "<indDesacordoOper>1</indDesacordoOper>"
542
                . "<xObs>$xJust</xObs>"
543
                . "</evPrestDesacordo>";
544
        }
545
        return $this->sefazEvento(
546
            $ufEvento,
547
            $chNFe,
548
            $tpEvento,
549
            $nSeqEvento,
550
            $tagAdic
551
        );
552
    }
553
554
    /**
555
     * Request authorization for issuance in contingency EPEC
556
     * @param  string $xml
557
     * @return string
558
     */
559
    public function sefazEPEC(&$xml)
560
    {
561
        $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...
562
        $tpEvento = 110140;
563
        $nSeqEvento = 1;
564
        if ($this->contingency->type !== 'EPEC') {
565
            throw new \RuntimeException('A contingência EPEC deve estar ativada.');
566
        }
567
        $xml = $this->correctNFeForContingencyMode($xml);
568
        $dom = new \DOMDocument('1.0', 'UTF-8');
569
        $dom->preserveWhiteSpace = false;
570
        $dom->formatOutput = false;
571
        $dom->loadXML($xml);
572
        $infNFe = $dom->getElementsByTagName('infNFe')->item(0);
573
        $emit = $dom->getElementsByTagName('emit')->item(0);
574
        $dest = $dom->getElementsByTagName('dest')->item(0);
575
        $cOrgaoAutor = UFList::getCodeByUF($this->config->siglaUF);
576
        $chNFe = substr($infNFe->getAttribute('Id'), 3, 44);
577
        // EPEC
578
        $dhEmi = $dom->getElementsByTagName('dhEmi')->item(0)->nodeValue;
579
        $tpNF = $dom->getElementsByTagName('tpNF')->item(0)->nodeValue;
580
        $emitIE = $emit->getElementsByTagName('IE')->item(0)->nodeValue;
581
        $destUF = $dest->getElementsByTagName('UF')->item(0)->nodeValue;
582
        $total = $dom->getElementsByTagName('total')->item(0);
583
        $vNF = $total->getElementsByTagName('vNF')->item(0)->nodeValue;
584
        $vICMS = $total->getElementsByTagName('vICMS')->item(0)->nodeValue;
585
        $vST = $total->getElementsByTagName('vST')->item(0)->nodeValue;
586
        $dID = $dest->getElementsByTagName('CNPJ')->item(0)->nodeValue;
587
        if (!empty($dID)) {
588
            $destID = "<CNPJ>$dID</CNPJ>";
589
        } else {
590
            $dID = $dest->getElementsByTagName('CPF')->item(0)->nodeValue;
591
            if (!empty($dID)) {
592
                $destID = "<CPF>$dID</CPF>";
593
            } else {
594
                $dID = $dest->getElementsByTagName('idEstrangeiro')
595
                    ->item(0)
596
                    ->nodeValue;
597
                $destID = "<idEstrangeiro>$dID</idEstrangeiro>";
598
            }
599
        }
600
        $dIE = !empty($dest->getElementsByTagName('IE')->item(0)->nodeValue) ?
601
                $dest->getElementsByTagName('IE')->item(0)->nodeValue : '';
602
        $destIE = '';
603
        if (!empty($dIE)) {
604
            $destIE = "<IE>$dIE</IE>";
605
        }
606
        $tagAdic = "<cOrgaoAutor>$cOrgaoAutor</cOrgaoAutor>"
607
            . "<tpAutor>1</tpAutor>"
608
            . "<verAplic>$this->verAplic</verAplic>"
609
            . "<dhEmi>$dhEmi</dhEmi>"
610
            . "<tpNF>$tpNF</tpNF>"
611
            . "<IE>$emitIE</IE>"
612
            . "<dest>"
613
            . "<UF>$destUF</UF>"
614
            . $destID
615
            . $destIE
616
            . "<vNF>$vNF</vNF>"
617
            . "<vICMS>$vICMS</vICMS>"
618
            . "<vST>$vST</vST>"
619
            . "</dest>";
620
621
        return $this->sefazEvento(
622
            'AN',
623
            $chNFe,
624
            $tpEvento,
625
            $nSeqEvento,
626
            $tagAdic
627
        );
628
    }
629
630
    /**
631
     * Send event to SEFAZ
632
     * @param string $uf
633
     * @param string $chave
634
     * @param int $tpEvento
635
     * @param int $nSeqEvento
636
     * @param string $tagAdic
637
     * @return string
638
     */
639
    public function sefazEvento(
640
        $uf,
641
        $chave,
642
        $tpEvento,
643
        $nSeqEvento = 1,
644
        $tagAdic = ''
645
    ) {
646
        $ignore = false;
647
        if ($tpEvento == 110140) {
648
            $ignore = true;
649
        }
650
        $servico = 'CteRecepcaoEvento';
651
        $this->checkContingencyForWebServices($servico);
652
        $this->servico(
653
            $servico,
654
            $uf,
655
            $this->tpAmb,
656
            $ignore
657
        );
658
        $ev = $this->tpEv($tpEvento);
659
        $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...
660
        $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...
661
        $cnpj = $this->config->cnpj;
662
        $dt = new \DateTime();
663
        $dhEvento = $dt->format('Y-m-d\TH:i:sP');
664
        $sSeqEvento = str_pad($nSeqEvento, 2, "0", STR_PAD_LEFT);
665
        $eventId = "ID".$tpEvento.$chave.$sSeqEvento;
666
        $cOrgao = UFList::getCodeByUF($uf);
667
668
        $request = "<eventoCTe xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
669
            . "<infEvento Id=\"$eventId\">"
670
            . "<cOrgao>$cOrgao</cOrgao>"
671
            . "<tpAmb>$this->tpAmb</tpAmb>"
672
            . "<CNPJ>$cnpj</CNPJ>"
673
            . "<chCTe>$chave</chCTe>"
674
            . "<dhEvento>$dhEvento</dhEvento>"
675
            . "<tpEvento>$tpEvento</tpEvento>"
676
            . "<nSeqEvento>$nSeqEvento</nSeqEvento>"
677
            . "<detEvento versaoEvento=\"$this->urlVersion\">"
678
            . "$tagAdic"
679
            . "</detEvento>"
680
            . "</infEvento>"
681
            . "</eventoCTe>";
682
683
        //assinatura dos dados
684
        $request = Signer::sign(
685
            $this->certificate,
686
            $request,
687
            'infEvento',
688
            'Id',
689
            $this->algorithm,
690
            $this->canonical
691
        );
692
693
        $request = Strings::clearXmlString($request, true);
694
        $this->isValid($this->urlVersion, $request, 'eventoCTe');
695
        $this->lastRequest = $request;
696
        $parameters = ['cteDadosMsg' => $request];
697
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
698
        $this->lastResponse = $this->sendRequest($body, $parameters);
699
        return $this->lastResponse;
700
    }
701
702
    /**
703
     * Request the NFe download already manifested by its recipient, by the key
704
     * using new service in CTeDistribuicaoDFe
705
     * @param  string $chave
706
     * @return string
707
     */
708
    public function sefazDownload($chave)
709
    {
710
        //carrega serviço
711
        $servico = 'CteDistribuicaoDFe';
712
        $this->checkContingencyForWebServices($servico);
713
        $this->servico(
714
            $servico,
715
            'AN',
716
            $this->tpAmb,
717
            true
718
        );
719
        $cUF = UFList::getCodeByUF($this->config->siglaUF);
720
        $tagChave = "<consChNFe><chNFe>$chave</chNFe></consChNFe>";
721
        //monta a consulta
722
        $consulta = "<distDFeInt xmlns=\"$this->urlPortal\" versao=\"$this->urlVersion\">"
723
            . "<tpAmb>".$this->tpAmb."</tpAmb>"
724
            . "<cUFAutor>$cUF</cUFAutor>"
725
            . "<CNPJ>".$this->config->cnpj."</CNPJ>$tagChave</distDFeInt>";
726
        //valida o xml da requisição
727
        $this->isValid($this->urlVersion, $consulta, 'distDFeInt');
728
        $this->lastRequest = $consulta;
729
        //montagem dos dados da mensagem SOAP
730
        $request = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$consulta</cteDadosMsg>";
731
        $parameters = ['cteDistDFeInteresse' => $request];
732
        $body = "<cteDistDFeInteresse xmlns=\"$this->urlNamespace\">"
733
            . $request
734
            . "</cteDistDFeInteresse>";
735
        //este webservice não requer cabeçalho
736
        $this->objHeader = null;
737
        $this->lastResponse = $this->sendRequest($body, $parameters);
738
        return $this->lastResponse;
739
    }
740
741
    /**
742
     * Maintenance of the Taxpayer Security Code - CSC (Old Token)
743
     * @param int $indOp Identificador do tipo de operação:
744
     *                   1 - Consulta CSC Ativos;
745
     *                   2 - Solicita novo CSC;
746
     *                   3 - Revoga CSC Ativo
747
     * @return string
748
     */
749
    public function sefazCsc($indOp)
750
    {
751
        if ($this->modelo != 65) {
752
            throw new RuntimeException(
753
                "Esta operação é exclusiva de NFCe modelo [65], "
754
                . "você está usando modelo [55]."
755
            );
756
        }
757
        $raizCNPJ = substr($this->config->cnpj, 0, -6);
758
        //carrega serviço
759
        $servico = 'CscNFCe';
760
        $this->checkContingencyForWebServices($servico);
761
        $this->servico(
762
            $servico,
763
            $this->config->siglaUF,
764
            $this->tpAmb
765
        );
766
        $request = "<admCscNFCe versao=\"$this->urlVersion\" xmlns=\"$this->urlPortal\">"
767
            . "<tpAmb>$this->tpAmb</tpAmb>"
768
            . "<indOp>$indOp</indOp>"
769
            . "<raizCNPJ>$raizCNPJ</raizCNPJ>"
770
            . "</admCscNFCe>";
771
        if ($indOp == 3) {
772
            $request = "<admCscNFCe versao=\"$this->urlVersion\" xmlns=\"$this->urlPortal\">"
773
            . "<tpAmb>$this->tpAmb</tpAmb>"
774
            . "<indOp>$indOp</indOp>"
775
            . "<raizCNPJ>$raizCNPJ</raizCNPJ>"
776
            . "<dadosCsc>"
777
            . "<idCsc>".$this->config->CSCid."</idCsc>"
778
            . "<codigoCsc>".$this->config->CSC."</codigoCsc>"
779
            . "</dadosCsc>"
780
            . "</admCscNFCe>";
781
        }
782
        //o xsd não está disponivel
783
        //$this->isValid($this->urlVersion, $request, 'cscNFCe');
0 ignored issues
show
Unused Code Comprehensibility introduced by
74% 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...
784
        $this->lastRequest = $request;
785
        $parameters = ['cteDadosMsg' => $request];
786
        $body = "<cteDadosMsg xmlns=\"$this->urlNamespace\">$request</cteDadosMsg>";
787
        $this->lastResponse = $this->sendRequest($body, $parameters);
788
        return $this->lastResponse;
789
    }
790
791
    /**
792
     * Checks the validity of an CTe, normally used for received CTe
793
     * @param  string $cte
794
     * @return boolean
795
     */
796
    public function sefazValidate($cte)
797
    {
798
        if (empty($cte)) {
799
            throw new InvalidArgumentException('Validacao CT-e: a string do CT-e esta vazio!');
800
        }
801
        //verifica a assinatura do CTe, exception caso de falha
802
        Signer::isSigned($cte, 'infCte');
803
        $dom = new \DOMDocument('1.0', 'utf-8');
804
        $dom->formatOutput = false;
805
        $dom->preserveWhiteSpace = false;
806
        $dom->loadXML($cte);
807
        //verifica a validade no webservice da SEFAZ
808
        $tpAmb = $dom->getElementsByTagName('tpAmb')->item(0)->nodeValue;
809
        $infCTe  = $dom->getElementsByTagName('infCte')->item(0);
810
        $chCTe = preg_replace('/[^0-9]/', '', $infCTe->getAttribute("Id"));
811
        $protocol = $dom->getElementsByTagName('nProt')->item(0)->nodeValue;
812
        $digval = $dom->getElementsByTagName('DigestValue')->item(0)->nodeValue;
813
        //consulta o CTe
814
        $response = $this->sefazConsultaChave($chCTe, $tpAmb);
815
        $ret = new \DOMDocument('1.0', 'UTF-8');
816
        $ret->preserveWhiteSpace = false;
817
        $ret->formatOutput = false;
818
        $ret->loadXML($response);
819
        $retProt = $ret->getElementsByTagName('protCTe')->item(0);
820
        if (!isset($retProt)) {
821
            $xMotivo = $ret->getElementsByTagName('xMotivo')->item(0);
822
            if (isset($xMotivo)) {
823
                throw new InvalidArgumentException('Validacao CT-e: ' . $xMotivo->nodeValue);
824
            } else {
825
                throw new InvalidArgumentException('O documento de resposta nao contem o node "protCTe".');
826
            }
827
        }
828
        $infProt = $ret->getElementsByTagName('infProt')->item(0);
829
        $dig = $infProt->getElementsByTagName("digVal")->item(0);
830
        $digProt = '000';
831
        if (isset($dig)) {
832
            $digProt = $dig->nodeValue;
833
        }
834
        $chProt = $infProt->getElementsByTagName("chCTe")->item(0)->nodeValue;
835
        $nProt = $infProt->getElementsByTagName("nProt")->item(0)->nodeValue;
836
        if ($protocol == $nProt && $digval == $digProt && $chCTe == $chProt) {
837
            return true;
838
        }
839
        return false;
840
    }
841
842
    /**
843
     *
844
     * @param  int $tpEvento
845
     * @return \stdClass
846
     * @throws Exception
847
     */
848
    private function tpEv($tpEvento)
849
    {
850
        $std = new \stdClass();
851
        $std->alias = '';
852
        $std->desc = '';
853
        switch ($tpEvento) {
854
            case 110110:
855
                //CCe
856
                $std->alias = 'CCe';
857
                $std->desc = 'Carta de Correcao';
858
                break;
859
            case 110111:
860
                //cancelamento
861
                $std->alias = 'CancCTe';
862
                $std->desc = 'Cancelamento';
863
                break;
864
            case 110113:
865
                //EPEC
866
                //emissão em contingência EPEC
867
                $std->alias = 'EPEC';
868
                $std->desc = 'EPEC';
869
                break;
870
            case 610110:
871
                //Serviço em desacordo
872
                $std->alias = 'EvPrestDesacordo';
873
                $std->desc = 'Servico em desacordo';
874
                break;
875
            default:
876
                $msg = "O código do tipo de evento informado não corresponde a "
877
                . "nenhum evento estabelecido.";
878
                throw new RuntimeException($msg);
879
        }
880
        return $std;
881
    }
882
883
    private static function serializerCCe(array $infCorrecoes)
884
    {
885
        // Grupo de Informações de Correção
886
        $correcoes = '';
887
        foreach ($infCorrecoes as $info) {
888
            $nroItemAlteradoOptionalElement = '';
889
            if (key_exists('nroItemAlterado', $info)) {
890
                $nroItemAlteradoOptionalElement = "<nroItemAlterado>{$info['nroItemAlterado']}</nroItemAlterado>";
891
            }
892
            $correcoes .= "<infCorrecao>" .
893
                "<grupoAlterado>{$info['grupoAlterado']}</grupoAlterado>" .
894
                "<campoAlterado>{$info['campoAlterado']}</campoAlterado>" .
895
                "<valorAlterado>{$info['valorAlterado']}</valorAlterado>" .
896
                "{$nroItemAlteradoOptionalElement}" .
897
                "</infCorrecao>";
898
        }
899
        //monta mensagem
900
        return "<evCCeCTe>" .
901
            "<descEvento>Carta de Correcao</descEvento>" .
902
            "{$correcoes}" .
903
            "<xCondUso>" .
904
            "A Carta de Correcao e disciplinada pelo Art. 58-B do " .
905
            "CONVENIO/SINIEF 06/89: Fica permitida a utilizacao de carta de " .
906
            "correcao, para regularizacao de erro ocorrido na emissao de " .
907
            "documentos fiscais relativos a prestacao de servico de transporte, " .
908
            "desde que o erro nao esteja relacionado com: I - as variaveis que " .
909
            "determinam o valor do imposto tais como: base de calculo, " .
910
            "aliquota, diferenca de preco, quantidade, valor da prestacao;II - " .
911
            "a correcao de dados cadastrais que implique mudanca do emitente, " .
912
            "tomador, remetente ou do destinatario;III - a data de emissao ou " .
913
            "de saida." .
914
            "</xCondUso>" .
915
        "</evCCeCTe>";
916
    }
917
}
918