Test Failed
Push — master ( 4eeb09...90eaf0 )
by Francimar
08:25
created

Nota::getNode()   F

Complexity

Conditions 19
Paths 4352

Size

Total Lines 140
Code Lines 112

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 107
CRAP Score 19.0168

Importance

Changes 0
Metric Value
dl 0
loc 140
ccs 107
cts 111
cp 0.964
rs 2
c 0
b 0
f 0
cc 19
eloc 112
nc 4352
nop 1
crap 19.0168

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * MIT License
4
 *
5
 * Copyright (c) 2016 MZ Desenvolvimento de Sistemas LTDA
6
 *
7
 * @author Francimar Alves <[email protected]>
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy
10
 * of this software and associated documentation files (the "Software"), to deal
11
 * in the Software without restriction, including without limitation the rights
12
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
 * copies of the Software, and to permit persons to whom the Software is
14
 * furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included in all
17
 * copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
 * SOFTWARE.
26
 *
27
 */
28
namespace NFe\Core;
29
30
use NFe\Common\Util;
31
use NFe\Common\Node;
32
use NFe\Task\Protocolo;
33
use NFe\Entity\Total;
34
use NFe\Entity\Imposto;
35
use NFe\Entity\Produto;
36
use NFe\Entity\Emitente;
37
use NFe\Entity\Pagamento;
38
use NFe\Entity\Transporte;
39
use NFe\Entity\Destinatario;
40
use NFe\Exception\ValidationException;
41
use FR3D\XmlDSig\Adapter\AdapterInterface;
42
use FR3D\XmlDSig\Adapter\XmlseclibsAdapter;
43
44
/**
45
 * Classe base para a formação da nota fiscal
46
 */
47
abstract class Nota implements Node
0 ignored issues
show
Complexity introduced by
This class has 75 public methods and attributes which exceeds the configured maximum of 45.

The number of this metric differs depending on the chosen design (inheritance vs. composition). For inheritance, the number should generally be a bit lower.

A high number indicates a reusable class. It might also make the class harder to change without breaking other classes though.

Loading history...
Complexity introduced by
This class has 30 fields which exceeds the configured maximum of 15.

Too many fields generally indicate a class which does too much and does not follow the single responsibility principle.

We suggest taking a look at the “Code” section for further suggestions on how to fix this.

Loading history...
Complexity introduced by
This class has a complexity of 280 which exceeds the configured maximum of 50.

The class complexity is the sum of the complexity of all methods. A very high value is usually an indication that your class does not follow the single reponsibility principle and does more than one job.

Some resources for further reading:

You can also find more detailed suggestions for refactoring in the “Code” section of your repository.

Loading history...
Complexity introduced by
The class Nota has a coupling between objects value of 20. Consider to reduce the number of dependencies under 13.
Loading history...
Complexity introduced by
This class has 2021 lines of code which exceeds the configured maximum of 1000.

Really long classes often contain too much logic and violate the single responsibility principle.

We suggest to take a look at the “Code” section for options on how to refactor this code.

Loading history...
48
{
49
50
    /**
51
     * Versão da nota fiscal
52
     */
53
    const VERSAO = '3.10';
54
55
    /**
56
     * Versão do aplicativo gerador da nota
57
     */
58
    const APP_VERSAO = '1.0';
59
60
    /**
61
     * Portal da nota fiscal
62
     */
63
    const PORTAL = 'http://www.portalfiscal.inf.br/nfe';
64
65
    /**
66
     * Código do modelo do Documento Fiscal. 55 = NF-e; 65 = NFC-e.
67
     */
68
    const MODELO_NFE = 'nfe';
69
    const MODELO_NFCE = 'nfce';
70
71
    /**
72
     * Tipo do Documento Fiscal (0 - entrada; 1 - saída)
73
     */
74
    const TIPO_ENTRADA = 'entrada';
75
    const TIPO_SAIDA = 'saida';
76
77
    /**
78
     * Identificador de Local de destino da operação
79
     * (1-Interna;2-Interestadual;3-Exterior)
80
     */
81
    const DESTINO_INTERNA = 'interna';
82
    const DESTINO_INTERESTADUAL = 'interestadual';
83
    const DESTINO_EXTERIOR = 'exterior';
84
85
    /**
86
     * Indicador da forma de pagamento: 0 – pagamento à vista; 1 – pagamento à
87
     * prazo; 2 – outros.
88
     */
89
    const INDICADOR_AVISTA = 'avista';
90
    const INDICADOR_APRAZO = 'aprazo';
91
    const INDICADOR_OUTROS = 'outros';
92
93
    /**
94
     * Formato de impressão do DANFE (0-sem DANFE;1-DANFe Retrato; 2-DANFe
95
     * Paisagem;3-DANFe Simplificado;4-DANFe NFC-e;5-DANFe NFC-e em mensagem
96
     * eletrônica)
97
     */
98
    const FORMATO_NENHUMA = 'nenhuma';
99
    const FORMATO_RETRATO = 'retrato';
100
    const FORMATO_PAISAGEM = 'paisagem';
101
    const FORMATO_SIMPLIFICADO = 'simplificado';
102
    const FORMATO_CONSUMIDOR = 'consumidor';
103
    const FORMATO_MENSAGEM = 'mensagem';
104
105
    /**
106
     * Forma de emissão da NF-e
107
     */
108
    const EMISSAO_NORMAL = 'normal';
109
    const EMISSAO_CONTINGENCIA = 'contingencia';
110
111
    /**
112
     * Identificação do Ambiente: 1 - Produção, 2 - Homologação
113
     */
114
    const AMBIENTE_PRODUCAO = 'producao';
115
    const AMBIENTE_HOMOLOGACAO = 'homologacao';
116
117
    /**
118
     * Finalidade da emissão da NF-e: 1 - NFe normal, 2 - NFe complementar, 3 -
119
     * NFe de ajuste, 4 - Devolução/Retorno
120
     */
121
    const FINALIDADE_NORMAL = 'normal';
122
    const FINALIDADE_COMPLEMENTAR = 'complementar';
123
    const FINALIDADE_AJUSTE = 'ajuste';
124
    const FINALIDADE_RETORNO = 'retorno';
125
126
    /**
127
     * Indicador de presença do comprador no estabelecimento comercial no
128
     * momento da oepração (0-Não se aplica, ex.: Nota Fiscal complementar ou
129
     * de ajuste;1-Operação presencial;2-Não presencial, internet;3-Não
130
     * presencial, teleatendimento;4-NFC-e entrega em domicílio;9-Não
131
     * presencial, outros)
132
     */
133
    const PRESENCA_NENHUM = 'nenhum';
134
    const PRESENCA_PRESENCIAL = 'presencial';
135
    const PRESENCA_INTERNET = 'internet';
136
    const PRESENCA_TELEATENDIMENTO = 'teleatendimento';
137
    const PRESENCA_ENTREGA = 'entrega';
138
    const PRESENCA_OUTROS = 'outros';
139
140
    /**
141
     * Chave da nota fiscal
142
     */
143
    private $id;
144
    /**
145
     * Número do Documento Fiscal
146
     */
147
    private $numero;
148
    /**
149
     * Emitente da nota fiscal
150
     */
151
    private $emitente;
152
    /**
153
     * Destinatário que receberá os produtos
154
     */
155
    private $destinatario;
156
    /**
157
     * Produtos adicionados na nota
158
     */
159
    private $produtos;
160
    /**
161
     * Informações de trasnporte da mercadoria
162
     */
163
    private $transporte;
164
    /**
165
     * Pagamentos realizados
166
     */
167
    private $pagamentos;
168
    /**
169
     * Data e Hora da saída ou de entrada da mercadoria / produto
170
     */
171
    private $data_movimentacao;
172
    /**
173
     * Informar a data e hora de entrada em contingência
174
     */
175
    private $data_contingencia;
176
    /**
177
     * Informar a Justificativa da entrada em contingência
178
     */
179
    private $justificativa;
180
    /**
181
     * Código do modelo do Documento Fiscal. 55 = NF-e; 65 = NFC-e.
182
     */
183
    private $modelo;
184
    /**
185
     * Tipo do Documento Fiscal (0 - entrada; 1 - saída)
186
     */
187
    private $tipo;
188
    /**
189
     * Identificador de Local de destino da operação
190
     * (1-Interna;2-Interestadual;3-Exterior)
191
     */
192
    private $destino;
193
    /**
194
     * Descrição da Natureza da Operação
195
     */
196
    private $natureza;
197
    /**
198
     * Código numérico que compõe a Chave de Acesso. Número aleatório gerado
199
     * pelo emitente para cada NF-e.
200
     */
201
    private $codigo;
202
    /**
203
     * Indicador da forma de pagamento: 0 – pagamento à vista; 1 – pagamento à
204
     * prazo; 2 – outros.
205
     */
206
    private $indicador;
207
    /**
208
     * Data e Hora de emissão do Documento Fiscal
209
     */
210
    private $data_emissao;
211
    /**
212
     * Série do Documento Fiscal: série normal 0-889, Avulsa Fisco 890-899,
213
     * SCAN 900-999
214
     */
215
    private $serie;
216
    /**
217
     * Formato de impressão do DANFE (0-sem DANFE;1-DANFe Retrato; 2-DANFe
218
     * Paisagem;3-DANFe Simplificado;4-DANFe NFC-e;5-DANFe NFC-e em mensagem
219
     * eletrônica)
220
     */
221
    private $formato;
222
    /**
223
     * Forma de emissão da NF-e
224
     */
225
    private $emissao;
226
    /**
227
     * Digito Verificador da Chave de Acesso da NF-e
228
     */
229
    private $digito_verificador;
230
    /**
231
     * Identificação do Ambiente: 1 - Produção, 2 - Homologação
232
     */
233
    private $ambiente;
234
    /**
235
     * Finalidade da emissão da NF-e: 1 - NFe normal, 2 - NFe complementar, 3 -
236
     * NFe de ajuste, 4 - Devolução/Retorno
237
     */
238
    private $finalidade;
239
    /**
240
     * Indica operação com consumidor final (0-Não;1-Consumidor Final)
241
     */
242
    private $consumidor_final;
243
    /**
244
     * Indicador de presença do comprador no estabelecimento comercial no
245
     * momento da oepração (0-Não se aplica, ex.: Nota Fiscal complementar ou
246
     * de ajuste;1-Operação presencial;2-Não presencial, internet;3-Não
247
     * presencial, teleatendimento;4-NFC-e entrega em domicílio;9-Não
248
     * presencial, outros)
249
     */
250
    private $presenca;
251
    /**
252
     * Dados dos totais da NF-e
253
     */
254
    private $total;
255
    /**
256
     * Informações adicionais de interesse do Fisco
257
     */
258
    private $adicionais;
259
    /**
260
     * Campo de uso livre do contribuinte informar o nome do campo no atributo
261
     * xCampo e o conteúdo do campo no xTexto
262
     */
263
    private $observacoes;
264
    /**
265
     * Campo de uso exclusivo do Fisco informar o nome do campo no atributo
266
     * xCampo e o conteúdo do campo no xTexto
267
     */
268
    private $informacoes;
269
    /**
270
     * Protocolo de autorização da nota, informado apenas quando a nota for
271
     * enviada e autorizada
272
     */
273
    private $protocolo;
274
275
    /**
276
     * Constroi uma instância de Nota vazia
277
     * @param  array $nota Array contendo dados da Nota
278
     */
279 7
    public function __construct($nota = array())
280
    {
281 7
        $this->fromArray($nota);
282 7
    }
283
284
    /**
285
     * Chave da nota fiscal
286
     * @param boolean $normalize informa se o id deve estar no formato do XML
287
     * @return mixed id da Nota
288
     */
289 5
    public function getID($normalize = false)
290
    {
291 5
        if (!$normalize) {
292 5
            return $this->id;
293
        }
294 5
        return 'NFe'.$this->id;
295
    }
296
297
    /**
298
     * Altera o valor do ID para o informado no parâmetro
299
     * @param mixed $id novo valor para ID
300
     * @return Nota A própria instância da classe
301
     */
302 7
    public function setID($id)
303
    {
304 7
        $this->id = $id;
305 7
        return $this;
306
    }
307
308
    /**
309
     * Número do Documento Fiscal
310
     * @param boolean $normalize informa se o numero deve estar no formato do XML
311
     * @return mixed numero da Nota
312
     */
313 5
    public function getNumero($normalize = false)
314
    {
315 5
        if (!$normalize) {
316 5
            return $this->numero;
317
        }
318 5
        return $this->numero;
319
    }
320
321
    /**
322
     * Altera o valor do Numero para o informado no parâmetro
323
     * @param mixed $numero novo valor para Numero
324
     * @return Nota A própria instância da classe
325
     */
326 7
    public function setNumero($numero)
327
    {
328 7
        $this->numero = $numero;
329 7
        return $this;
330
    }
331
332
    /**
333
     * Emitente da nota fiscal
334
     * @return mixed emitente da Nota
335
     */
336 5
    public function getEmitente()
337
    {
338 5
        return $this->emitente;
339
    }
340
341
    /**
342
     * Altera o valor do Emitente para o informado no parâmetro
343
     * @param mixed $emitente novo valor para Emitente
344
     * @return Nota A própria instância da classe
345
     */
346 7
    public function setEmitente($emitente)
347
    {
348 7
        $this->emitente = $emitente;
349 7
        return $this;
350
    }
351
352
    /**
353
     * Destinatário que receberá os produtos
354
     * @return mixed destinatario da Nota
355
     */
356 5
    public function getDestinatario()
357
    {
358 5
        return $this->destinatario;
359
    }
360
361
    /**
362
     * Altera o valor do Destinatario para o informado no parâmetro
363
     * @param mixed $destinatario novo valor para Destinatario
364
     * @return Nota A própria instância da classe
365
     */
366 7
    public function setDestinatario($destinatario)
367
    {
368 7
        $this->destinatario = $destinatario;
369 7
        return $this;
370
    }
371
372
    /**
373
     * Produtos adicionados na nota
374
     * @return mixed produtos da Nota
375
     */
376 5
    public function getProdutos()
377
    {
378 5
        return $this->produtos;
379
    }
380
381
    /**
382
     * Altera o valor do Produtos para o informado no parâmetro
383
     * @param mixed $produtos novo valor para Produtos
384
     * @return Nota A própria instância da classe
385
     */
386 7
    public function setProdutos($produtos)
387
    {
388 7
        $this->produtos = $produtos;
389 7
        return $this;
390
    }
391
392
    /**
393
     * Adiciona um(a) Produto para a lista de produto
394
     * @param Produto $produto Instância do Produto que será adicionada
395
     * @return Nota A própria instância da classe
396
     */
397 2
    public function addProduto($produto)
398
    {
399 2
        $this->produtos[] = $produto;
400 2
        return $this;
401
    }
402
403
    /**
404
     * Informações de trasnporte da mercadoria
405
     * @return mixed transporte da Nota
406
     */
407 5
    public function getTransporte()
408
    {
409 5
        return $this->transporte;
410
    }
411
412
    /**
413
     * Altera o valor da Transporte para o informado no parâmetro
414
     * @param mixed $transporte novo valor para Transporte
415
     * @return Nota A própria instância da classe
416
     */
417 7
    public function setTransporte($transporte)
418
    {
419 7
        $this->transporte = $transporte;
420 7
        return $this;
421
    }
422
423
    /**
424
     * Pagamentos realizados
425
     * @return mixed pagamentos da Nota
426
     */
427 5
    public function getPagamentos()
428
    {
429 5
        return $this->pagamentos;
430
    }
431
432
    /**
433
     * Altera o valor do Pagamentos para o informado no parâmetro
434
     * @param mixed $pagamentos novo valor para Pagamentos
435
     * @return Nota A própria instância da classe
436
     */
437 7
    public function setPagamentos($pagamentos)
438
    {
439 7
        $this->pagamentos = $pagamentos;
440 7
        return $this;
441
    }
442
443
    /**
444
     * Adiciona um(a) Pagamento para a lista de pagamento
445
     * @param Pagamento $pagamento Instância do Pagamento que será adicionada
446
     * @return Nota A própria instância da classe
447
     */
448 2
    public function addPagamento($pagamento)
449
    {
450 2
        $this->pagamentos[] = $pagamento;
451 2
        return $this;
452
    }
453
454
    /**
455
     * Data e Hora da saída ou de entrada da mercadoria / produto
456
     * @param boolean $normalize informa se a data_movimentacao deve estar no formato do XML
457
     * @return mixed data_movimentacao da Nota
458
     */
459 5
    public function getDataMovimentacao($normalize = false)
460
    {
461 5
        if (!$normalize || is_null($this->data_movimentacao)) {
462 5
            return $this->data_movimentacao;
463
        }
464
        return Util::toDateTime($this->data_movimentacao);
465
    }
466
467
    /**
468
     * Altera o valor da DataMovimentacao para o informado no parâmetro
469
     * @param mixed $data_movimentacao novo valor para DataMovimentacao
470
     * @return Nota A própria instância da classe
471
     */
472 7
    public function setDataMovimentacao($data_movimentacao)
473
    {
474 7
        if (!is_null($data_movimentacao) && !is_numeric($data_movimentacao)) {
475
            $data_movimentacao = strtotime($data_movimentacao);
476
        }
477 7
        $this->data_movimentacao = $data_movimentacao;
478 7
        return $this;
479
    }
480
481
    /**
482
     * Informar a data e hora de entrada em contingência
483
     * @param boolean $normalize informa se a data_contingencia deve estar no formato do XML
484
     * @return mixed data_contingencia da Nota
485
     */
486 2
    public function getDataContingencia($normalize = false)
487
    {
488 2
        if (!$normalize || is_null($this->data_contingencia)) {
489 2
            return $this->data_contingencia;
490
        }
491
        return Util::toDateTime($this->data_contingencia);
492
    }
493
494
    /**
495
     * Altera o valor da DataContingencia para o informado no parâmetro
496
     * @param mixed $data_contingencia novo valor para DataContingencia
497
     * @return Nota A própria instância da classe
498
     */
499 7
    public function setDataContingencia($data_contingencia)
500
    {
501 7
        if (!is_null($data_contingencia) && !is_numeric($data_contingencia)) {
502
            $data_contingencia = strtotime($data_contingencia);
503
        }
504 7
        $this->data_contingencia = $data_contingencia;
505 7
        return $this;
506
    }
507
508
    /**
509
     * Informar a Justificativa da entrada em contingência
510
     * @param boolean $normalize informa se a justificativa deve estar no formato do XML
511
     * @return mixed justificativa da Nota
512
     */
513 2
    public function getJustificativa($normalize = false)
514
    {
515 2
        if (!$normalize) {
516 2
            return $this->justificativa;
517
        }
518
        return $this->justificativa;
519
    }
520
521
    /**
522
     * Altera o valor da Justificativa para o informado no parâmetro
523
     * @param mixed $justificativa novo valor para Justificativa
524
     * @return Nota A própria instância da classe
525
     */
526 7
    public function setJustificativa($justificativa)
527
    {
528 7
        $this->justificativa = $justificativa;
529 7
        return $this;
530
    }
531
532
    /**
533
     * Código do modelo do Documento Fiscal. 55 = NF-e; 65 = NFC-e.
534
     * @param boolean $normalize informa se o modelo deve estar no formato do XML
535
     * @return mixed modelo da Nota
536
     */
537 5
    public function getModelo($normalize = false)
538
    {
539 5
        if (!$normalize) {
540 4
            return $this->modelo;
541
        }
542 5
        switch ($this->modelo) {
543 5
            case self::MODELO_NFE:
544
                return '55';
545 5
            case self::MODELO_NFCE:
546 5
                return '65';
547
        }
548
        return $this->modelo;
549
    }
550
551
    /**
552
     * Altera o valor do Modelo para o informado no parâmetro
553
     * @param mixed $modelo novo valor para Modelo
554
     * @return Nota A própria instância da classe
555
     */
556 7
    public function setModelo($modelo)
557
    {
558
        switch ($modelo) {
559 7
            case '55':
560
                $modelo = self::MODELO_NFE;
561
                break;
562 7
            case '65':
563 3
                $modelo = self::MODELO_NFCE;
564 3
                break;
565
        }
566 7
        $this->modelo = $modelo;
567 7
        return $this;
568
    }
569
570
    /**
571
     * Tipo do Documento Fiscal (0 - entrada; 1 - saída)
572
     * @param boolean $normalize informa se o tipo deve estar no formato do XML
573
     * @return mixed tipo da Nota
574
     */
575 5
    public function getTipo($normalize = false)
576
    {
577 5
        if (!$normalize) {
578 2
            return $this->tipo;
579
        }
580 5
        switch ($this->tipo) {
581 5
            case self::TIPO_ENTRADA:
582
                return '0';
583 5
            case self::TIPO_SAIDA:
584 5
                return '1';
585
        }
586
        return $this->tipo;
587
    }
588
589
    /**
590
     * Altera o valor do Tipo para o informado no parâmetro
591
     * @param mixed $tipo novo valor para Tipo
592
     * @return Nota A própria instância da classe
593
     */
594 7
    public function setTipo($tipo)
595
    {
596
        switch ($tipo) {
597 7
            case '0':
598
                $tipo = self::TIPO_ENTRADA;
599
                break;
600 7
            case '1':
601 3
                $tipo = self::TIPO_SAIDA;
602 3
                break;
603
        }
604 7
        $this->tipo = $tipo;
605 7
        return $this;
606
    }
607
608
    /**
609
     * Identificador de Local de destino da operação
610
     * (1-Interna;2-Interestadual;3-Exterior)
611
     * @param boolean $normalize informa se o destino deve estar no formato do XML
612
     * @return mixed destino da Nota
613
     */
614 5
    public function getDestino($normalize = false)
615
    {
616 5
        if (!$normalize) {
617 2
            return $this->destino;
618
        }
619 5
        switch ($this->destino) {
620 5
            case self::DESTINO_INTERNA:
621 5
                return '1';
622
            case self::DESTINO_INTERESTADUAL:
623
                return '2';
624
            case self::DESTINO_EXTERIOR:
625
                return '3';
626
        }
627
        return $this->destino;
628
    }
629
630
    /**
631
     * Altera o valor do Destino para o informado no parâmetro
632
     * @param mixed $destino novo valor para Destino
633
     * @return Nota A própria instância da classe
634
     */
635 7
    public function setDestino($destino)
636
    {
637
        switch ($destino) {
638 7
            case '1':
639 3
                $destino = self::DESTINO_INTERNA;
640 3
                break;
641 7
            case '2':
642
                $destino = self::DESTINO_INTERESTADUAL;
643
                break;
644 7
            case '3':
645
                $destino = self::DESTINO_EXTERIOR;
646
                break;
647
        }
648 7
        $this->destino = $destino;
649 7
        return $this;
650
    }
651
652
    /**
653
     * Descrição da Natureza da Operação
654
     * @param boolean $normalize informa se a natureza deve estar no formato do XML
655
     * @return mixed natureza da Nota
656
     */
657 5
    public function getNatureza($normalize = false)
658
    {
659 5
        if (!$normalize) {
660 2
            return $this->natureza;
661
        }
662 5
        return $this->natureza;
663
    }
664
665
    /**
666
     * Altera o valor da Natureza para o informado no parâmetro
667
     * @param mixed $natureza novo valor para Natureza
668
     * @return Nota A própria instância da classe
669
     */
670 7
    public function setNatureza($natureza)
671
    {
672 7
        $this->natureza = $natureza;
673 7
        return $this;
674
    }
675
676
    /**
677
     * Código numérico que compõe a Chave de Acesso. Número aleatório gerado
678
     * pelo emitente para cada NF-e.
679
     * @param boolean $normalize informa se o codigo deve estar no formato do XML
680
     * @return mixed codigo da Nota
681
     */
682 5
    public function getCodigo($normalize = false)
683
    {
684 5
        if (!$normalize) {
685 5
            return $this->codigo;
686
        }
687 5
        return Util::padDigit($this->codigo % 100000000, 8);
688
    }
689
690
    /**
691
     * Altera o valor do Codigo para o informado no parâmetro
692
     * @param mixed $codigo novo valor para Codigo
693
     * @return Nota A própria instância da classe
694
     */
695 7
    public function setCodigo($codigo)
696
    {
697 7
        $this->codigo = $codigo;
698 7
        return $this;
699
    }
700
701
    /**
702
     * Indicador da forma de pagamento: 0 – pagamento à vista; 1 – pagamento à
703
     * prazo; 2 – outros.
704
     * @param boolean $normalize informa se o indicador deve estar no formato do XML
705
     * @return mixed indicador da Nota
706
     */
707 5
    public function getIndicador($normalize = false)
708
    {
709 5
        if (!$normalize) {
710 2
            return $this->indicador;
711
        }
712 5
        switch ($this->indicador) {
713 5
            case self::INDICADOR_AVISTA:
714 5
                return '0';
715
            case self::INDICADOR_APRAZO:
716
                return '1';
717
            case self::INDICADOR_OUTROS:
718
                return '2';
719
        }
720
        return $this->indicador;
721
    }
722
723
    /**
724
     * Altera o valor do Indicador para o informado no parâmetro
725
     * @param mixed $indicador novo valor para Indicador
726
     * @return Nota A própria instância da classe
727
     */
728 7
    public function setIndicador($indicador)
729
    {
730
        switch ($indicador) {
731 7
            case '0':
732 3
                $indicador = self::INDICADOR_AVISTA;
733 3
                break;
734 7
            case '1':
735
                $indicador = self::INDICADOR_APRAZO;
736
                break;
737 7
            case '2':
738
                $indicador = self::INDICADOR_OUTROS;
739
                break;
740
        }
741 7
        $this->indicador = $indicador;
742 7
        return $this;
743
    }
744
745
    /**
746
     * Data e Hora de emissão do Documento Fiscal
747
     * @param boolean $normalize informa se o data_emissao deve estar no formato do XML
748
     * @return mixed data_emissao da Nota
749
     */
750 5
    public function getDataEmissao($normalize = false)
751
    {
752 5
        if (!$normalize) {
753 5
            return $this->data_emissao;
754
        }
755 5
        return Util::toDateTime($this->data_emissao);
756
    }
757
758
    /**
759
     * Altera o valor do DataEmissao para o informado no parâmetro
760
     * @param mixed $data_emissao novo valor para DataEmissao
761
     * @return Nota A própria instância da classe
762
     */
763 7
    public function setDataEmissao($data_emissao)
764
    {
765 7
        if (!is_numeric($data_emissao)) {
766 7
            $data_emissao = strtotime($data_emissao);
767
        }
768 7
        $this->data_emissao = $data_emissao;
769 7
        return $this;
770
    }
771
772
    /**
773
     * Série do Documento Fiscal: série normal 0-889, Avulsa Fisco 890-899,
774
     * SCAN 900-999
775
     * @param boolean $normalize informa se o serie deve estar no formato do XML
776
     * @return mixed serie da Nota
777
     */
778 5
    public function getSerie($normalize = false)
779
    {
780 5
        if (!$normalize) {
781 5
            return $this->serie;
782
        }
783 5
        return $this->serie;
784
    }
785
786
    /**
787
     * Altera o valor do Serie para o informado no parâmetro
788
     * @param mixed $serie novo valor para Serie
789
     * @return Nota A própria instância da classe
790
     */
791 7
    public function setSerie($serie)
792
    {
793 7
        $this->serie = $serie;
794 7
        return $this;
795
    }
796
797
    /**
798
     * Formato de impressão do DANFE (0-sem DANFE;1-DANFe Retrato; 2-DANFe
799
     * Paisagem;3-DANFe Simplificado;4-DANFe NFC-e;5-DANFe NFC-e em mensagem
800
     * eletrônica)
801
     * @param boolean $normalize informa se o formato deve estar no formato do XML
802
     * @return mixed formato da Nota
803
     */
804 5
    public function getFormato($normalize = false)
805
    {
806 5
        if (!$normalize) {
807 2
            return $this->formato;
808
        }
809 5
        switch ($this->formato) {
810 5
            case self::FORMATO_NENHUMA:
811
                return '0';
812 5
            case self::FORMATO_RETRATO:
813
                return '1';
814 5
            case self::FORMATO_PAISAGEM:
815
                return '2';
816 5
            case self::FORMATO_SIMPLIFICADO:
817
                return '3';
818 5
            case self::FORMATO_CONSUMIDOR:
819 5
                return '4';
820
            case self::FORMATO_MENSAGEM:
821
                return '5';
822
        }
823
        return $this->formato;
824
    }
825
826
    /**
827
     * Altera o valor do Formato para o informado no parâmetro
828
     * @param mixed $formato novo valor para Formato
829
     * @return Nota A própria instância da classe
830
     */
831 7
    public function setFormato($formato)
832
    {
833
        switch ($formato) {
834 7
            case '0':
835
                $formato = self::FORMATO_NENHUMA;
836
                break;
837 7
            case '1':
838
                $formato = self::FORMATO_RETRATO;
839
                break;
840 7
            case '2':
841
                $formato = self::FORMATO_PAISAGEM;
842
                break;
843 7
            case '3':
844
                $formato = self::FORMATO_SIMPLIFICADO;
845
                break;
846 7
            case '4':
847 3
                $formato = self::FORMATO_CONSUMIDOR;
848 3
                break;
849 7
            case '5':
850
                $formato = self::FORMATO_MENSAGEM;
851
                break;
852
        }
853 7
        $this->formato = $formato;
854 7
        return $this;
855
    }
856
857
    /**
858
     * Forma de emissão da NF-e
859
     * @param boolean $normalize informa se o emissao deve estar no formato do XML
860
     * @return mixed emissao da Nota
861
     */
862 5
    public function getEmissao($normalize = false)
863
    {
864 5
        if (!$normalize) {
865 5
            return $this->emissao;
866
        }
867 5
        switch ($this->emissao) {
868 5
            case self::EMISSAO_NORMAL:
869 5
                return '1';
870
            case self::EMISSAO_CONTINGENCIA:
871
                return '9';
872
        }
873
        return $this->emissao;
874
    }
875
876
    /**
877
     * Altera o valor do Emissao para o informado no parâmetro
878
     * @param mixed $emissao novo valor para Emissao
879
     * @return Nota A própria instância da classe
880
     */
881 7
    public function setEmissao($emissao)
882
    {
883
        switch ($emissao) {
884 7
            case '1':
885 3
                $emissao = self::EMISSAO_NORMAL;
886 3
                break;
887 7
            case '9':
888
                $emissao = self::EMISSAO_CONTINGENCIA;
889
                break;
890
        }
891 7
        $this->emissao = $emissao;
892 7
        return $this;
893
    }
894
895
    /**
896
     * Digito Verificador da Chave de Acesso da NF-e
897
     * @param boolean $normalize informa se o digito_verificador deve estar no formato do XML
898
     * @return mixed digito_verificador da Nota
899
     */
900 5
    public function getDigitoVerificador($normalize = false)
901
    {
902 5
        if (!$normalize) {
903 2
            return $this->digito_verificador;
904
        }
905 5
        return $this->digito_verificador;
906
    }
907
908
    /**
909
     * Altera o valor do DigitoVerificador para o informado no parâmetro
910
     * @param mixed $digito_verificador novo valor para DigitoVerificador
911
     * @return Nota A própria instância da classe
912
     */
913 7
    public function setDigitoVerificador($digito_verificador)
914
    {
915 7
        $this->digito_verificador = $digito_verificador;
916 7
        return $this;
917
    }
918
919
    /**
920
     * Identificação do Ambiente: 1 - Produção, 2 - Homologação
921
     * @param boolean $normalize informa se o ambiente deve estar no formato do XML
922
     * @return mixed ambiente da Nota
923
     */
924 5
    public function getAmbiente($normalize = false)
925
    {
926 5
        if (!$normalize) {
927 5
            return $this->ambiente;
928
        }
929 5
        switch ($this->ambiente) {
930 5
            case self::AMBIENTE_PRODUCAO:
931
                return '1';
932 5
            case self::AMBIENTE_HOMOLOGACAO:
933 5
                return '2';
934
        }
935
        return $this->ambiente;
936
    }
937
938
    /**
939
     * Altera o valor do Ambiente para o informado no parâmetro
940
     * @param mixed $ambiente novo valor para Ambiente
941
     * @return Nota A própria instância da classe
942
     */
943 7
    public function setAmbiente($ambiente)
944
    {
945
        switch ($ambiente) {
946 7
            case '1':
947
                $ambiente = self::AMBIENTE_PRODUCAO;
948
                break;
949 7
            case '2':
950 3
                $ambiente = self::AMBIENTE_HOMOLOGACAO;
951 3
                break;
952
        }
953 7
        $this->ambiente = $ambiente;
954 7
        return $this;
955
    }
956
957
    /**
958
     * Finalidade da emissão da NF-e: 1 - NFe normal, 2 - NFe complementar, 3 -
959
     * NFe de ajuste, 4 - Devolução/Retorno
960
     * @param boolean $normalize informa se a finalidade deve estar no formato do XML
961
     * @return mixed finalidade da Nota
962
     */
963 5
    public function getFinalidade($normalize = false)
964
    {
965 5
        if (!$normalize) {
966 2
            return $this->finalidade;
967
        }
968 5
        switch ($this->finalidade) {
969 5
            case self::FINALIDADE_NORMAL:
970 5
                return '1';
971
            case self::FINALIDADE_COMPLEMENTAR:
972
                return '2';
973
            case self::FINALIDADE_AJUSTE:
974
                return '3';
975
            case self::FINALIDADE_RETORNO:
976
                return '4';
977
        }
978
        return $this->finalidade;
979
    }
980
981
    /**
982
     * Altera o valor da Finalidade para o informado no parâmetro
983
     * @param mixed $finalidade novo valor para Finalidade
984
     * @return Nota A própria instância da classe
985
     */
986 7
    public function setFinalidade($finalidade)
987
    {
988
        switch ($finalidade) {
989 7
            case '1':
990 3
                $finalidade = self::FINALIDADE_NORMAL;
991 3
                break;
992 7
            case '2':
993
                $finalidade = self::FINALIDADE_COMPLEMENTAR;
994
                break;
995 7
            case '3':
996
                $finalidade = self::FINALIDADE_AJUSTE;
997
                break;
998 7
            case '4':
999
                $finalidade = self::FINALIDADE_RETORNO;
1000
                break;
1001
        }
1002 7
        $this->finalidade = $finalidade;
1003 7
        return $this;
1004
    }
1005
1006
    /**
1007
     * Indica operação com consumidor final (0-Não;1-Consumidor Final)
1008
     * @param boolean $normalize informa se o consumidor_final deve estar no formato do XML
1009
     * @return mixed consumidor_final da Nota
1010
     */
1011 5
    public function getConsumidorFinal($normalize = false)
1012
    {
1013 5
        if (!$normalize) {
1014 2
            return $this->consumidor_final;
1015
        }
1016 5
        switch ($this->consumidor_final) {
1017 5
            case 'N':
1018
                return '0';
1019 5
            case 'Y':
1020 5
                return '1';
1021
        }
1022
        return $this->consumidor_final;
1023
    }
1024
1025
    /**
1026
     * Indica operação com consumidor final (0-Não;1-Consumidor Final)
1027
     * @return boolean informa se o ConsumidorFinal está habilitado
1028
     */
1029
    public function isConsumidorFinal()
1030
    {
1031
        return $this->consumidor_final == 'Y';
1032
    }
1033
1034
    /**
1035
     * Altera o valor do ConsumidorFinal para o informado no parâmetro
1036
     * @param mixed $consumidor_final novo valor para ConsumidorFinal
1037
     * @return Nota A própria instância da classe
1038
     */
1039 7
    public function setConsumidorFinal($consumidor_final)
1040
    {
1041 7
        if (!in_array($consumidor_final, array('N', 'Y'))) {
1042 3
            $consumidor_final = $consumidor_final?'Y':'N';
1043
        }
1044 7
        $this->consumidor_final = $consumidor_final;
1045 7
        return $this;
1046
    }
1047
1048
    /**
1049
     * Indicador de presença do comprador no estabelecimento comercial no
1050
     * momento da oepração (0-Não se aplica, ex.: Nota Fiscal complementar ou
1051
     * de ajuste;1-Operação presencial;2-Não presencial, internet;3-Não
1052
     * presencial, teleatendimento;4-NFC-e entrega em domicílio;9-Não
1053
     * presencial, outros)
1054
     * @param boolean $normalize informa se a presenca deve estar no formato do XML
1055
     * @return mixed presenca da Nota
1056
     */
1057 5
    public function getPresenca($normalize = false)
1058
    {
1059 5
        if (!$normalize) {
1060 2
            return $this->presenca;
1061
        }
1062 5
        switch ($this->presenca) {
1063 5
            case self::PRESENCA_NENHUM:
1064
                return '0';
1065 5
            case self::PRESENCA_PRESENCIAL:
1066 5
                return '1';
1067
            case self::PRESENCA_INTERNET:
1068
                return '2';
1069
            case self::PRESENCA_TELEATENDIMENTO:
1070
                return '3';
1071
            case self::PRESENCA_ENTREGA:
1072
                return '4';
1073
            case self::PRESENCA_OUTROS:
1074
                return '9';
1075
        }
1076
        return $this->presenca;
1077
    }
1078
1079
    /**
1080
     * Altera o valor da Presenca para o informado no parâmetro
1081
     * @param mixed $presenca novo valor para Presenca
1082
     * @return Nota A própria instância da classe
1083
     */
1084 7
    public function setPresenca($presenca)
1085
    {
1086
        switch ($presenca) {
1087 7
            case '0':
1088
                $presenca = self::PRESENCA_NENHUM;
1089
                break;
1090 7
            case '1':
1091 3
                $presenca = self::PRESENCA_PRESENCIAL;
1092 3
                break;
1093 7
            case '2':
1094
                $presenca = self::PRESENCA_INTERNET;
1095
                break;
1096 7
            case '3':
1097
                $presenca = self::PRESENCA_TELEATENDIMENTO;
1098
                break;
1099 7
            case '4':
1100
                $presenca = self::PRESENCA_ENTREGA;
1101
                break;
1102 7
            case '9':
1103
                $presenca = self::PRESENCA_OUTROS;
1104
                break;
1105
        }
1106 7
        $this->presenca = $presenca;
1107 7
        return $this;
1108
    }
1109
1110
    /**
1111
     * Dados dos totais da NF-e
1112
     * @return mixed total da Nota
1113
     */
1114 5
    public function getTotal()
1115
    {
1116 5
        return $this->total;
1117
    }
1118
    
1119
    /**
1120
     * Altera o valor do Total para o informado no parâmetro
1121
     * @param mixed $total novo valor para Total
1122
     * @return Nota A própria instância da classe
1123
     */
1124 7
    public function setTotal($total)
1125
    {
1126 7
        $this->total = $total;
1127 7
        return $this;
1128
    }
1129
1130
    /**
1131
     * Informações adicionais de interesse do Fisco
1132
     * @param boolean $normalize informa se a adicionais deve estar no formato do XML
1133
     * @return mixed adicionais da Nota
1134
     */
1135 5
    public function getAdicionais($normalize = false)
1136
    {
1137 5
        if (!$normalize) {
1138 5
            return $this->adicionais;
1139
        }
1140
        return $this->adicionais;
1141
    }
1142
    
1143
    /**
1144
     * Altera o valor da Adicionais para o informado no parâmetro
1145
     * @param mixed $adicionais novo valor para Adicionais
1146
     * @return Nota A própria instância da classe
1147
     */
1148 7
    public function setAdicionais($adicionais)
1149
    {
1150 7
        $this->adicionais = $adicionais;
1151 7
        return $this;
1152
    }
1153
1154
    /**
1155
     * Campo de uso livre do contribuinte informar o nome do campo no atributo
1156
     * xCampo e o conteúdo do campo no xTexto
1157
     * @return mixed observacoes da Nota
1158
     */
1159 5
    public function getObservacoes()
1160
    {
1161 5
        return $this->observacoes;
1162
    }
1163
    
1164
    /**
1165
     * Altera o valor da Observacoes para o informado no parâmetro
1166
     * @param mixed $observacoes novo valor para Observacoes
1167
     * @return Nota A própria instância da classe
1168
     */
1169 7
    public function setObservacoes($observacoes)
1170
    {
1171 7
        $this->observacoes = $observacoes;
1172 7
        return $this;
1173
    }
1174
1175
    /**
1176
     * Adiciona um(a) Observacao para a lista de observacao
1177
     * @param Observacao $observacao Instância da Observacao que será adicionada
1178
     * @return Nota A própria instância da classe
1179
     */
1180 2
    public function addObservacao($campo, $observacao)
1181
    {
1182 2
        $this->observacoes[] = array('campo' => $campo, 'valor' => $observacao);
1183 2
        return $this;
1184
    }
1185
1186
    /**
1187
     * Campo de uso exclusivo do Fisco informar o nome do campo no atributo
1188
     * xCampo e o conteúdo do campo no xTexto
1189
     * @return mixed informacoes da Nota
1190
     */
1191 5
    public function getInformacoes()
1192
    {
1193 5
        return $this->informacoes;
1194
    }
1195
    
1196
    /**
1197
     * Altera o valor da Informacoes para o informado no parâmetro
1198
     * @param mixed $informacoes novo valor para Informacoes
1199
     * @return Nota A própria instância da classe
1200
     */
1201 7
    public function setInformacoes($informacoes)
1202
    {
1203 7
        $this->informacoes = $informacoes;
1204 7
        return $this;
1205
    }
1206
1207
    /**
1208
     * Adiciona um(a) Informacao para a lista de informacao
1209
     * @param Informacao $informacao Instância da Informacao que será adicionada
1210
     * @return Nota A própria instância da classe
1211
     */
1212 2
    public function addInformacao($campo, $informacao)
1213
    {
1214 2
        $this->informacoes[] = array('campo' => $campo, 'valor' => $informacao);
1215 2
        return $this;
1216
    }
1217
1218
    /**
1219
     * Protocolo de autorização da nota, informado apenas quando a nota for
1220
     * enviada e autorizada
1221
     */
1222 3
    public function getProtocolo()
1223
    {
1224 3
        return $this->protocolo;
1225
    }
1226
1227 7
    public function setProtocolo($protocolo)
1228
    {
1229 7
        $this->protocolo = $protocolo;
1230 7
        return $this;
1231
    }
1232
1233 2
    public function toArray($recursive = false)
0 ignored issues
show
Complexity introduced by
This operation has 2187 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

You can also find more information in the “Code” section of your repository.

Loading history...
1234
    {
1235 2
        $nota = array();
1236 2
        $nota['id'] = $this->getID();
1237 2
        $nota['numero'] = $this->getNumero();
1238 2
        if (!is_null($this->getEmitente()) && $recursive) {
1239
            $nota['emitente'] = $this->getEmitente()->toArray($recursive);
1240
        } else {
1241 2
            $nota['emitente'] = $this->getEmitente();
1242
        }
1243 2
        if (!is_null($this->getDestinatario()) && $recursive) {
1244
            $nota['destinatario'] = $this->getDestinatario()->toArray($recursive);
1245
        } else {
1246 2
            $nota['destinatario'] = $this->getDestinatario();
1247
        }
1248 2
        if ($recursive) {
1249
            $produtos = array();
1250
            $_produtos = $this->getProdutos();
1251
            foreach ($_produtos as $_produto) {
1252
                $produtos[] = $_produto->toArray($recursive);
1253
            }
1254
            $nota['produtos'] = $produtos;
1255
        } else {
1256 2
            $nota['produtos'] = $this->getProdutos();
1257
        }
1258 2
        if (!is_null($this->getTransporte()) && $recursive) {
1259
            $nota['transporte'] = $this->getTransporte()->toArray($recursive);
1260
        } else {
1261 2
            $nota['transporte'] = $this->getTransporte();
1262
        }
1263 2
        if ($recursive) {
1264
            $pagamentos = array();
1265
            $_pagamentos = $this->getPagamentos();
1266
            foreach ($_pagamentos as $_pagamento) {
1267
                $pagamentos[] = $_pagamento->toArray($recursive);
1268
            }
1269
            $nota['pagamentos'] = $pagamentos;
1270
        } else {
1271 2
            $nota['pagamentos'] = $this->getPagamentos();
1272
        }
1273 2
        $nota['data_movimentacao'] = $this->getDataMovimentacao($recursive);
1274 2
        $nota['data_contingencia'] = $this->getDataContingencia($recursive);
1275 2
        $nota['justificativa'] = $this->getJustificativa();
1276 2
        $nota['modelo'] = $this->getModelo();
1277 2
        $nota['tipo'] = $this->getTipo();
1278 2
        $nota['destino'] = $this->getDestino();
1279 2
        $nota['natureza'] = $this->getNatureza();
1280 2
        $nota['codigo'] = $this->getCodigo();
1281 2
        $nota['indicador'] = $this->getIndicador();
1282 2
        $nota['data_emissao'] = $this->getDataEmissao($recursive);
1283 2
        $nota['serie'] = $this->getSerie();
1284 2
        $nota['formato'] = $this->getFormato();
1285 2
        $nota['emissao'] = $this->getEmissao();
1286 2
        $nota['digito_verificador'] = $this->getDigitoVerificador();
1287 2
        $nota['ambiente'] = $this->getAmbiente();
1288 2
        $nota['finalidade'] = $this->getFinalidade();
1289 2
        $nota['consumidor_final'] = $this->getConsumidorFinal();
1290 2
        $nota['presenca'] = $this->getPresenca();
1291 2
        if (!is_null($this->getTotal()) && $recursive) {
1292
            $nota['total'] = $this->getTotal()->toArray($recursive);
1293
        } else {
1294 2
            $nota['total'] = $this->getTotal();
1295
        }
1296 2
        $nota['adicionais'] = $this->getAdicionais();
1297 2
        $nota['observacoes'] = $this->getObservacoes();
1298 2
        $nota['informacoes'] = $this->getInformacoes();
1299 2
        if (!is_null($this->getProtocolo()) && $recursive) {
1300
            $nota['protocolo'] = $this->getProtocolo()->toArray($recursive);
1301
        } else {
1302 2
            $nota['protocolo'] = $this->getProtocolo();
1303
        }
1304 2
        return $nota;
1305
    }
1306
1307 7
    public function fromArray($nota = array())
0 ignored issues
show
Complexity introduced by
This operation has 940369969152 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

You can also find more information in the “Code” section of your repository.

Loading history...
1308
    {
1309 7
        if ($nota instanceof Nota) {
1310
            $nota = $nota->toArray();
1311 7
        } elseif (!is_array($nota)) {
1312
            return $this;
1313
        }
1314 7
        if (isset($nota['id'])) {
1315
            $this->setID($nota['id']);
1316
        } else {
1317 7
            $this->setID(null);
1318
        }
1319 7
        if (isset($nota['numero'])) {
1320 2
            $this->setNumero($nota['numero']);
1321
        } else {
1322 7
            $this->setNumero(null);
1323
        }
1324 7
        if (!isset($nota['emitente']) || is_null($nota['emitente'])) {
1325 7
            $this->setEmitente(new Emitente());
1326
        } else {
1327 2
            $this->setEmitente($nota['emitente']);
1328
        }
1329 7
        if (!isset($nota['destinatario']) || is_null($nota['destinatario'])) {
1330 7
            $this->setDestinatario(new Destinatario());
1331
        } else {
1332 2
            $this->setDestinatario($nota['destinatario']);
1333
        }
1334 7
        if (!isset($nota['produtos']) || is_null($nota['produtos'])) {
1335 7
            $this->setProdutos(array());
1336
        } else {
1337 2
            $this->setProdutos($nota['produtos']);
1338
        }
1339 7
        if (!isset($nota['transporte']) || is_null($nota['transporte'])) {
1340 7
            $this->setTransporte(new Transporte());
1341
        } else {
1342 2
            $this->setTransporte($nota['transporte']);
1343
        }
1344 7
        if (!isset($nota['pagamentos']) || is_null($nota['pagamentos'])) {
1345 7
            $this->setPagamentos(array());
1346
        } else {
1347 2
            $this->setPagamentos($nota['pagamentos']);
1348
        }
1349 7
        if (isset($nota['data_movimentacao'])) {
1350
            $this->setDataMovimentacao($nota['data_movimentacao']);
1351
        } else {
1352 7
            $this->setDataMovimentacao(null);
1353
        }
1354 7
        if (isset($nota['data_contingencia'])) {
1355
            $this->setDataContingencia($nota['data_contingencia']);
1356
        } else {
1357 7
            $this->setDataContingencia(null);
1358
        }
1359 7
        if (isset($nota['justificativa'])) {
1360
            $this->setJustificativa($nota['justificativa']);
1361
        } else {
1362 7
            $this->setJustificativa(null);
1363
        }
1364 7
        if (isset($nota['modelo'])) {
1365 2
            $this->setModelo($nota['modelo']);
1366
        } else {
1367 7
            $this->setModelo(null);
1368
        }
1369 7
        if (!isset($nota['tipo']) || is_null($nota['tipo'])) {
1370 7
            $this->setTipo(self::TIPO_SAIDA);
1371
        } else {
1372 2
            $this->setTipo($nota['tipo']);
1373
        }
1374 7
        if (!isset($nota['destino']) || is_null($nota['destino'])) {
1375 7
            $this->setDestino(self::DESTINO_INTERNA);
1376
        } else {
1377 2
            $this->setDestino($nota['destino']);
1378
        }
1379 7
        if (!isset($nota['natureza']) || is_null($nota['natureza'])) {
1380 7
            $this->setNatureza('VENDA PARA CONSUMIDOR FINAL');
1381
        } else {
1382 2
            $this->setNatureza($nota['natureza']);
1383
        }
1384 7
        if (isset($nota['codigo'])) {
1385 2
            $this->setCodigo($nota['codigo']);
1386
        } else {
1387 7
            $this->setCodigo(null);
1388
        }
1389 7
        if (!isset($nota['indicador']) || is_null($nota['indicador'])) {
1390 7
            $this->setIndicador(self::INDICADOR_AVISTA);
1391
        } else {
1392 2
            $this->setIndicador($nota['indicador']);
1393
        }
1394 7
        if (isset($nota['data_emissao'])) {
1395 2
            $this->setDataEmissao($nota['data_emissao']);
1396
        } else {
1397 7
            $this->setDataEmissao(null);
1398
        }
1399 7
        if (isset($nota['serie'])) {
1400 2
            $this->setSerie($nota['serie']);
1401
        } else {
1402 7
            $this->setSerie(null);
1403
        }
1404 7
        if (!isset($nota['formato']) || is_null($nota['formato'])) {
1405 7
            $this->setFormato(self::FORMATO_NENHUMA);
1406
        } else {
1407 2
            $this->setFormato($nota['formato']);
1408
        }
1409 7
        if (!isset($nota['emissao']) || is_null($nota['emissao'])) {
1410 7
            $this->setEmissao(self::EMISSAO_NORMAL);
1411
        } else {
1412 2
            $this->setEmissao($nota['emissao']);
1413
        }
1414 7
        if (isset($nota['digito_verificador'])) {
1415
            $this->setDigitoVerificador($nota['digito_verificador']);
1416
        } else {
1417 7
            $this->setDigitoVerificador(null);
1418
        }
1419 7
        if (!isset($nota['ambiente']) || is_null($nota['ambiente'])) {
1420 7
            $this->setAmbiente(self::AMBIENTE_HOMOLOGACAO);
1421
        } else {
1422 2
            $this->setAmbiente($nota['ambiente']);
1423
        }
1424 7
        if (!isset($nota['finalidade']) || is_null($nota['finalidade'])) {
1425 7
            $this->setFinalidade(self::FINALIDADE_NORMAL);
1426
        } else {
1427 2
            $this->setFinalidade($nota['finalidade']);
1428
        }
1429 7
        if (!isset($nota['consumidor_final']) || is_null($nota['consumidor_final'])) {
1430 7
            $this->setConsumidorFinal('Y');
1431
        } else {
1432 2
            $this->setConsumidorFinal($nota['consumidor_final']);
1433
        }
1434 7
        if (isset($nota['presenca'])) {
1435 2
            $this->setPresenca($nota['presenca']);
1436
        } else {
1437 7
            $this->setPresenca(null);
1438
        }
1439 7
        if (!isset($nota['total'])) {
1440 7
            $this->setTotal(new Total());
1441
        } else {
1442 2
            $this->setTotal($nota['total']);
1443
        }
1444 7
        if (!array_key_exists('adicionais', $nota)) {
1445 7
            $this->setAdicionais(null);
1446
        } else {
1447 2
            $this->setAdicionais($nota['adicionais']);
1448
        }
1449 7
        if (!array_key_exists('observacoes', $nota)) {
1450 7
            $this->setObservacoes(null);
1451
        } else {
1452 2
            $this->setObservacoes($nota['observacoes']);
1453
        }
1454 7
        if (!array_key_exists('informacoes', $nota)) {
1455 7
            $this->setInformacoes(null);
1456
        } else {
1457 2
            $this->setInformacoes($nota['informacoes']);
1458
        }
1459 7
        if (isset($nota['protocolo'])) {
1460
            $this->setProtocolo($nota['protocolo']);
1461
        } else {
1462 7
            $this->setProtocolo(null);
1463
        }
1464 7
        return $this;
1465
    }
1466
1467 5
    public function gerarID()
1468
    {
1469 5
        $estado = $this->getEmitente()->getEndereco()->getMunicipio()->getEstado();
1470 5
        $estado->checkCodigos();
1471 5
        $id = sprintf(
1472 5
            '%02d%02d%02d%s%02d%03d%09d%01d%08d',
1473 5
            $estado->getCodigo(),
1474 5
            date('y', $this->getDataEmissao()), // Ano 2 dígitos
1475 5
            date('m', $this->getDataEmissao()), // Mês 2 dígitos
1476 5
            $this->getEmitente()->getCNPJ(),
1477 5
            $this->getModelo(true),
1478 5
            $this->getSerie(),
1479 5
            $this->getNumero(),
1480 5
            $this->getEmissao(true),
1481 5
            $this->getCodigo()
1482
        );
1483 5
        return $id.Util::getDAC($id, 11);
1484
    }
1485
1486 5
    protected function getTotais()
1487
    {
1488 5
        $total = array();
1489 5
        $total['produtos'] = 0.00;
1490 5
        $total['desconto'] = 0.00;
1491 5
        $total['frete'] = 0.00;
1492 5
        $total['seguro'] = 0.00;
1493 5
        $total['despesas'] = 0.00;
1494 5
        $total['tributos'] = 0.00;
1495 5
        $total['icms'] = 0.00;
1496 5
        $total['icms.st'] = 0.00;
1497 5
        $total['base'] = 0.00;
1498 5
        $total['base.st'] = 0.00;
1499 5
        $total['ii'] = 0.00;
1500 5
        $total['ipi'] = 0.00;
1501 5
        $total['pis'] = 0.00;
1502 5
        $total['cofins'] = 0.00;
1503 5
        $total['desoneracao'] = 0.00;
1504 5
        $_produtos = $this->getProdutos();
1505 5
        foreach ($_produtos as $_produto) {
1506 5
            if (!$_produto->getMultiplicador()) {
1507
                continue;
1508
            }
1509 5
            $imposto_info = $_produto->getImpostoInfo();
1510 5
            $total['produtos'] += round($_produto->getPreco(), 2);
1511 5
            $total['desconto'] += round($_produto->getDesconto(), 2);
1512 5
            $total['frete'] += round($_produto->getFrete(), 2);
1513 5
            $total['seguro'] += round($_produto->getSeguro(), 2);
1514 5
            $total['despesas'] += round($_produto->getDespesas(), 2);
1515 5
            $total['tributos'] += round($imposto_info['total'], 2);
1516 5
            $_impostos = $_produto->getImpostos();
1517 5
            foreach ($_impostos as $_imposto) {
1518 5
                switch ($_imposto->getGrupo()) {
1519 5
                    case Imposto::GRUPO_ICMS:
1520 5
                        if (($_imposto instanceof \NFe\Entity\Imposto\ICMS\Cobranca) ||
1521 5
                                ($_imposto instanceof \NFe\Entity\Imposto\ICMS\Simples\Cobranca)) {
1522 5
                            $total[$_imposto->getGrupo()] += round($_imposto->getNormal()->getValor(), 2);
1523 5
                            $total['base'] += round($_imposto->getNormal()->getBase(), 2);
1524
                        }
1525 5
                        if (($_imposto instanceof \NFe\Entity\Imposto\ICMS\Parcial) ||
1526 5
                                ($_imposto instanceof \NFe\Entity\Imposto\ICMS\Simples\Parcial)) {
1527 5
                            $total['icms.st'] += round($_imposto->getValor(), 2);
1528 5
                            $total['base.st'] += round($_imposto->getBase(), 2);
1529
                        } else {
1530
                            $total[$_imposto->getGrupo()] += round($_imposto->getValor(), 2);
1531
                            $total['base'] += round($_imposto->getBase(), 2);
1532
                        }
1533 5
                        break;
1534
                    default:
1535 5
                        $total[$_imposto->getGrupo()] += round($_imposto->getValor(), 2);
1536
                }
1537
            }
1538
        }
1539 5
        $produtos = round($total['produtos'], 2) - round($total['desconto'], 2);
1540 5
        $servicos = round($total['frete'], 2) + round($total['seguro'], 2) + round($total['despesas'], 2);
1541 5
        $impostos = round($total['ii'], 2) + round($total['ipi'], 2) + round($total['icms.st'], 2);
1542 5
        $impostos = $impostos - round($total['desoneracao'], 2);
1543 5
        $total['nota'] = $produtos + $servicos + $impostos;
1544 5
        return $total;
1545
    }
1546
1547 5
    private function getNodeTotal($name = null)
1548
    {
1549 5
        $dom = new \DOMDocument('1.0', 'UTF-8');
1550 5
        $element = $dom->createElement(is_null($name)?'total':$name);
1551
1552
        // Totais referentes ao ICMS
1553 5
        $total = $this->getTotais();
1554 5
        $icms = $dom->createElement('ICMSTot');
1555 5
        Util::appendNode($icms, 'vBC', Util::toCurrency($total['base']));
1556 5
        Util::appendNode($icms, 'vICMS', Util::toCurrency($total['icms']));
1557 5
        Util::appendNode($icms, 'vICMSDeson', Util::toCurrency($total['desoneracao']));
1558 5
        Util::appendNode($icms, 'vBCST', Util::toCurrency($total['base.st']));
1559 5
        Util::appendNode($icms, 'vST', Util::toCurrency($total['icms.st']));
1560 5
        Util::appendNode($icms, 'vProd', Util::toCurrency($total['produtos']));
1561 5
        Util::appendNode($icms, 'vFrete', Util::toCurrency($total['frete']));
1562 5
        Util::appendNode($icms, 'vSeg', Util::toCurrency($total['seguro']));
1563 5
        Util::appendNode($icms, 'vDesc', Util::toCurrency($total['desconto']));
1564 5
        Util::appendNode($icms, 'vII', Util::toCurrency($total['ii']));
1565 5
        Util::appendNode($icms, 'vIPI', Util::toCurrency($total['ipi']));
1566 5
        Util::appendNode($icms, 'vPIS', Util::toCurrency($total['pis']));
1567 5
        Util::appendNode($icms, 'vCOFINS', Util::toCurrency($total['cofins']));
1568 5
        Util::appendNode($icms, 'vOutro', Util::toCurrency($total['despesas']));
1569 5
        Util::appendNode($icms, 'vNF', Util::toCurrency($total['nota']));
1570 5
        Util::appendNode($icms, 'vTotTrib', Util::toCurrency($total['tributos']));
1571 5
        $element->appendChild($icms);
1572 5
        $this->setTotal(new Total($total));
1573 5
        $this->getTotal()->setProdutos($total['produtos']);
1574
1575
        // TODO: Totais referentes ao ISSQN
1576
1577
        // TODO: Retenção de Tributos Federais
1578 5
        return $element;
1579
    }
1580
1581 5
    public function getNode($name = null)
0 ignored issues
show
Complexity introduced by
This operation has 90720 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

You can also find more information in the “Code” section of your repository.

Loading history...
1582
    {
1583 5
        $this->getEmitente()->getEndereco()->checkCodigos();
1584 5
        $this->setID($this->gerarID());
1585 5
        $this->setDigitoVerificador(substr($this->getID(), -1, 1));
1586
1587 5
        $dom = new \DOMDocument('1.0', 'UTF-8');
1588 5
        $element = $dom->createElement(is_null($name)?'NFe':$name);
1589 5
        $element->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', self::PORTAL);
1590
1591 5
        $info = $dom->createElement('infNFe');
1592 5
        $id = $dom->createAttribute('Id');
1593 5
        $id->value = $this->getID(true);
1594 5
        $info->appendChild($id);
1595 5
        $versao = $dom->createAttribute('versao');
1596 5
        $versao->value = self::VERSAO;
1597 5
        $info->appendChild($versao);
1598
1599 5
        $municipio = $this->getEmitente()->getEndereco()->getMunicipio();
1600 5
        $estado = $municipio->getEstado();
1601 5
        $ident = $dom->createElement('ide');
1602 5
        Util::appendNode($ident, 'cUF', $estado->getCodigo(true));
1603 5
        Util::appendNode($ident, 'cNF', $this->getCodigo(true));
1604 5
        Util::appendNode($ident, 'natOp', $this->getNatureza(true));
1605 5
        Util::appendNode($ident, 'indPag', $this->getIndicador(true));
1606 5
        Util::appendNode($ident, 'mod', $this->getModelo(true));
1607 5
        Util::appendNode($ident, 'serie', $this->getSerie(true));
1608 5
        Util::appendNode($ident, 'nNF', $this->getNumero(true));
1609 5
        Util::appendNode($ident, 'dhEmi', $this->getDataEmissao(true));
1610 5
        Util::appendNode($ident, 'tpNF', $this->getTipo(true));
1611 5
        Util::appendNode($ident, 'idDest', $this->getDestino(true));
1612 5
        Util::appendNode($ident, 'cMunFG', $municipio->getCodigo(true));
1613 5
        Util::appendNode($ident, 'tpImp', $this->getFormato(true));
1614 5
        Util::appendNode($ident, 'tpEmis', $this->getEmissao(true));
1615 5
        Util::appendNode($ident, 'cDV', $this->getDigitoVerificador(true));
1616 5
        Util::appendNode($ident, 'tpAmb', $this->getAmbiente(true));
1617 5
        Util::appendNode($ident, 'finNFe', $this->getFinalidade(true));
1618 5
        Util::appendNode($ident, 'indFinal', $this->getConsumidorFinal(true));
1619 5
        Util::appendNode($ident, 'indPres', $this->getPresenca(true));
1620 5
        Util::appendNode($ident, 'procEmi', 0); // emissão de NF-e com aplicativo do contribuinte
1621 5
        Util::appendNode($ident, 'verProc', self::APP_VERSAO);
1622 5
        if (!is_null($this->getDataMovimentacao())) {
1623
            Util::appendNode($ident, 'dhSaiEnt', $this->getDataMovimentacao(true));
1624
        }
1625 5
        if ($this->getEmissao() != self::EMISSAO_NORMAL) {
1626
            Util::appendNode($ident, 'dhCont', $this->getDataContingencia(true));
1627
            Util::appendNode($ident, 'xJust', $this->getJustificativa(true));
1628
        }
1629 5
        $info->appendChild($ident);
1630
1631 5
        $emitente = $this->getEmitente()->getNode();
1632 5
        $emitente = $dom->importNode($emitente, true);
1633 5
        $info->appendChild($emitente);
1634 5
        if ($this->getAmbiente() == self::AMBIENTE_HOMOLOGACAO && !is_null($this->getDestinatario())) {
1635 5
            $this->getDestinatario()->setNome('NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL');
1636
        }
1637 5
        if (!is_null($this->getDestinatario())) {
1638 5
            $destinatario = $this->getDestinatario()->getNode();
1639 5
            $destinatario = $dom->importNode($destinatario, true);
1640 5
            $info->appendChild($destinatario);
1641
        }
1642 5
        $item = 0;
1643 5
        $tributos = array();
1644 5
        $_produtos = $this->getProdutos();
1645 5
        foreach ($_produtos as $_produto) {
1646 5
            if (is_null($_produto->getItem())) {
1647 2
                $item += 1;
1648 2
                $_produto->setItem($item);
1649
            } else {
1650 3
                $item = $_produto->getItem();
1651
            }
1652 5
            if ($this->getAmbiente() == self::AMBIENTE_HOMOLOGACAO) {
1653 5
                $_produto->setDescricao('NOTA FISCAL EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL');
1654
            }
1655 5
            $produto = $_produto->getNode();
1656 5
            $produto = $dom->importNode($produto, true);
1657 5
            $info->appendChild($produto);
1658
            // Soma os tributos aproximados dos produtos
1659 5
            $imposto_info = $_produto->getImpostoInfo();
1660 5
            $tributos['info'] = $imposto_info['info'];
1661 5
            foreach ($imposto_info as $key => $value) {
1662 5
                if (!is_numeric($value)) {
1663 5
                    continue;
1664
                }
1665 5
                if (!isset($tributos[$key])) {
1666 5
                    $tributos[$key] = 0.00;
1667
                }
1668 5
                $tributos[$key] += $value;
1669
            }
1670
        }
1671 5
        $total = $this->getNodeTotal();
1672 5
        $total = $dom->importNode($total, true);
1673 5
        $info->appendChild($total);
1674 5
        $transporte = $this->getTransporte()->getNode();
1675 5
        $transporte = $dom->importNode($transporte, true);
1676 5
        $info->appendChild($transporte);
1677
        // TODO: adicionar cobrança
1678 5
        $_pagamentos = $this->getPagamentos();
1679 5
        foreach ($_pagamentos as $_pagamento) {
1680 5
            $pagamento = $_pagamento->getNode();
1681 5
            $pagamento = $dom->importNode($pagamento, true);
1682 5
            $info->appendChild($pagamento);
1683
        }
1684 5
        $info_adic = $dom->createElement('infAdic');
1685 5
        if (!is_null($this->getAdicionais())) {
1686
            Util::appendNode($info_adic, 'infAdFisco', $this->getAdicionais(true));
1687
        }
1688
        // TODO: adicionar informações adicionais somente na NFC-e?
1689 5
        $_complemento = Produto::addNodeInformacoes($tributos, $info_adic, 'infCpl');
1690 5
        $this->getTotal()->setComplemento($_complemento);
1691 5
        if (!is_null($this->getObservacoes())) {
1692 5
            $_observacoes = $this->getObservacoes();
1693 5
            foreach ($_observacoes as $_observacao) {
0 ignored issues
show
Bug introduced by
The expression $_observacoes of type object|integer|double|string|array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1694 5
                $observacoes = $dom->createElement('obsCont');
1695 5
                $campo = $dom->createAttribute('xCampo');
1696 5
                $campo->value = $_observacao['campo'];
1697 5
                $observacoes->appendChild($campo);
1698 5
                Util::appendNode($observacoes, 'xTexto', $_observacao['valor']);
1699 5
                $info_adic->appendChild($observacoes);
1700
            }
1701
        }
1702 5
        if (!is_null($this->getInformacoes())) {
1703 5
            $_informacoes = $this->getInformacoes();
1704 5
            foreach ($_informacoes as $_informacao) {
0 ignored issues
show
Bug introduced by
The expression $_informacoes of type object|integer|double|string|array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1705 5
                $informacoes = $dom->createElement('obsFisco');
1706 5
                $campo = $dom->createAttribute('xCampo');
1707 5
                $campo->value = $_informacao['campo'];
1708 5
                $informacoes->appendChild($campo);
1709 5
                Util::appendNode($informacoes, 'xTexto', $_informacao['valor']);
1710 5
                $info_adic->appendChild($informacoes);
1711
            }
1712
        }
1713 5
        $info->appendChild($info_adic);
1714
        // TODO: adicionar exportação
1715
        // TODO: adicionar compra
1716
        // TODO: adicionar cana
1717 5
        $element->appendChild($info);
1718 5
        $dom->appendChild($element);
1719 5
        return $element;
1720
    }
1721
1722 3
    public function loadNode($element, $name = null)
0 ignored issues
show
Complexity introduced by
This operation has 245760 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

You can also find more information in the “Code” section of your repository.

Loading history...
1723
    {
1724 3
        $root = $element;
1725 3
        $name = is_null($name)?'NFe':$name;
1726 3
        if ($element->tagName != $name) {
1727
            $_fields = $element->getElementsByTagName($name);
1728
            if ($_fields->length == 0) {
1729
                throw new \Exception('Tag "'.$name.'" não encontrada', 404);
1730
            }
1731
            $element = $_fields->item(0);
1732
        }
1733 3
        $_fields = $element->getElementsByTagName('infNFe');
1734 3
        if ($_fields->length > 0) {
1735 3
            $info = $_fields->item(0);
1736
        } else {
1737
            throw new \Exception('Tag "infNFe" não encontrada', 404);
1738
        }
1739 3
        $id = $info->getAttribute('Id');
1740 3
        if (strlen($id) != 47) {
1741
            throw new \Exception('Atributo "Id" inválido, encontrado: "'.$id.'"', 500);
1742
        }
1743 3
        $this->setID(substr($id, 3));
1744 3
        $_fields = $info->getElementsByTagName('ide');
1745 3
        if ($_fields->length > 0) {
1746 3
            $ident = $_fields->item(0);
1747
        } else {
1748
            throw new \Exception('Tag "ide" não encontrada', 404);
1749
        }
1750 3
        $emitente = new Emitente();
1751 3
        $_fields = $ident->getElementsByTagName('cUF');
1752 3
        if ($_fields->length > 0) {
1753 3
            $codigo = $_fields->item(0)->nodeValue;
1754
        } else {
1755
            throw new \Exception('Tag "cUF" do campo "Codigo IBGE da UF" não encontrada', 404);
1756
        }
1757 3
        $emitente->getEndereco()->getMunicipio()->getEstado()->setCodigo($codigo);
1758 3
        $this->setCodigo(
1759 3
            Util::loadNode(
1760
                $ident,
1761 3
                'cNF',
1762 3
                'Tag "cNF" do campo "Codigo" não encontrada'
1763
            )
1764
        );
1765 3
        $this->setNatureza(
1766 3
            Util::loadNode(
1767
                $ident,
1768 3
                'natOp',
1769 3
                'Tag "natOp" do campo "Natureza" não encontrada'
1770
            )
1771
        );
1772 3
        $this->setIndicador(
1773 3
            Util::loadNode(
1774
                $ident,
1775 3
                'indPag',
1776 3
                'Tag "indPag" do campo "Indicador" não encontrada'
1777
            )
1778
        );
1779 3
        $this->setModelo(
1780 3
            Util::loadNode(
1781
                $ident,
1782 3
                'mod',
1783 3
                'Tag "mod" do campo "Modelo" não encontrada'
1784
            )
1785
        );
1786 3
        $this->setSerie(
1787 3
            Util::loadNode(
1788
                $ident,
1789 3
                'serie',
1790 3
                'Tag "serie" do campo "Serie" não encontrada'
1791
            )
1792
        );
1793 3
        $this->setNumero(
1794 3
            Util::loadNode(
1795
                $ident,
1796 3
                'nNF',
1797 3
                'Tag "nNF" do campo "Numero" não encontrada'
1798
            )
1799
        );
1800 3
        $this->setDataEmissao(
1801 3
            Util::loadNode(
1802
                $ident,
1803 3
                'dhEmi',
1804 3
                'Tag "dhEmi" do campo "DataEmissao" não encontrada'
1805
            )
1806
        );
1807 3
        $this->setTipo(
1808 3
            Util::loadNode(
1809
                $ident,
1810 3
                'tpNF',
1811 3
                'Tag "tpNF" do campo "Tipo" não encontrada'
1812
            )
1813
        );
1814 3
        $this->setDestino(
1815 3
            Util::loadNode(
1816
                $ident,
1817 3
                'idDest',
1818 3
                'Tag "idDest" do campo "Destino" não encontrada'
1819
            )
1820
        );
1821 3
        $_fields = $ident->getElementsByTagName('cMunFG');
1822 3
        if ($_fields->length > 0) {
1823 3
            $codigo = $_fields->item(0)->nodeValue;
1824
        } else {
1825
            throw new \Exception('Tag "cMunFG" do campo "Codigo IBGE do município" não encontrada', 404);
1826
        }
1827 3
        $emitente->getEndereco()->getMunicipio()->setCodigo($codigo);
1828 3
        $this->setDataMovimentacao(Util::loadNode($ident, 'dhSaiEnt'));
1829 3
        $this->setFormato(
1830 3
            Util::loadNode(
1831
                $ident,
1832 3
                'tpImp',
1833 3
                'Tag "tpImp" do campo "Formato" não encontrada'
1834
            )
1835
        );
1836 3
        $this->setEmissao(
1837 3
            Util::loadNode(
1838
                $ident,
1839 3
                'tpEmis',
1840 3
                'Tag "tpEmis" do campo "Emissao" não encontrada'
1841
            )
1842
        );
1843 3
        $this->setDigitoVerificador(
1844 3
            Util::loadNode(
1845
                $ident,
1846 3
                'cDV',
1847 3
                'Tag "cDV" do campo "DigitoVerificador" não encontrada'
1848
            )
1849
        );
1850 3
        $this->setAmbiente(
1851 3
            Util::loadNode(
1852
                $ident,
1853 3
                'tpAmb',
1854 3
                'Tag "tpAmb" do campo "Ambiente" não encontrada'
1855
            )
1856
        );
1857 3
        $this->setFinalidade(
1858 3
            Util::loadNode(
1859
                $ident,
1860 3
                'finNFe',
1861 3
                'Tag "finNFe" do campo "Finalidade" não encontrada'
1862
            )
1863
        );
1864 3
        $this->setConsumidorFinal(
1865 3
            Util::loadNode(
1866
                $ident,
1867 3
                'indFinal',
1868 3
                'Tag "indFinal" do campo "ConsumidorFinal" não encontrada'
1869
            )
1870
        );
1871 3
        $this->setPresenca(
1872 3
            Util::loadNode(
1873
                $ident,
1874 3
                'indPres',
1875 3
                'Tag "indPres" do campo "Presenca" não encontrada'
1876
            )
1877
        );
1878 3
        $this->setDataContingencia(Util::loadNode($ident, 'dhCont'));
1879 3
        $this->setJustificativa(Util::loadNode($ident, 'xJust'));
1880
1881 3
        $_fields = $info->getElementsByTagName('emit');
1882 3
        if ($_fields->length > 0) {
1883 3
            $emitente->loadNode($_fields->item(0), 'emit');
1884
        } else {
1885
            throw new \Exception('Tag "emit" do objeto "Emitente" não encontrada', 404);
1886
        }
1887 3
        $this->setEmitente($emitente);
1888 3
        $_fields = $info->getElementsByTagName('dest');
1889 3
        $destinatario = null;
1890 3
        if ($_fields->length > 0) {
1891 3
            $destinatario = new Destinatario();
1892 3
            $destinatario->loadNode($_fields->item(0), 'dest');
1893
        }
1894 3
        $this->setDestinatario($destinatario);
1895 3
        $produtos = array();
1896 3
        $_items = $info->getElementsByTagName('det');
1897 3
        foreach ($_items as $_item) {
1898 3
            $produto = new Produto();
1899 3
            $produto->loadNode($_item, 'det');
1900 3
            $produtos[] = $produto;
1901
        }
1902 3
        $this->setProdutos($produtos);
1903 3
        $_fields = $info->getElementsByTagName('transp');
1904 3
        $transporte = null;
1905 3
        if ($_fields->length > 0) {
1906 3
            $transporte = new Transporte();
1907 3
            $transporte->loadNode($_fields->item(0), 'transp');
1908
        }
1909 3
        $this->setTransporte($transporte);
1910 3
        $pagamentos = array();
1911 3
        $_items = $info->getElementsByTagName('pag');
1912 3
        foreach ($_items as $_item) {
1913 3
            $pagamento = new Pagamento();
1914 3
            $pagamento->loadNode($_item, 'pag');
1915 3
            $pagamentos[] = $pagamento;
1916
        }
1917 3
        $this->setPagamentos($pagamentos);
1918 3
        $_fields = $info->getElementsByTagName('total');
1919 3
        if ($_fields->length > 0) {
1920 3
            $total = new Total();
1921 3
            $total->loadNode($_fields->item(0), 'total');
1922 3
            $total->setComplemento(Util::loadNode($info, 'infCpl'));
1923
        } else {
1924
            throw new \Exception('Tag "total" do objeto "Total" não encontrada na Nota', 404);
1925
        }
1926 3
        $this->setTotal($total);
1927 3
        $this->setAdicionais(Util::loadNode($info, 'infAdFisco'));
1928 3
        $observacoes = array();
1929 3
        $_items = $info->getElementsByTagName('obsCont'); // TODO: predictable tag name
1930 3
        foreach ($_items as $_item) {
1931
            $observacao = array(
1932 3
                'campo' => $_item->getAttribute('xCampo'),
1933 3
                'valor' => Util::loadNode(
1934
                    $_item,
1935 3
                    'xTexto',
1936 3
                    'Tag "xTexto" do campo "Observação" não encontrada'
1937
                )
1938
            );
1939 3
            $observacoes[] = $observacao;
1940
        }
1941 3
        $this->setObservacoes($observacoes);
1942 3
        $informacoes = array();
1943 3
        $_items = $info->getElementsByTagName('obsFisco'); // TODO: predictable tag name
1944 3
        foreach ($_items as $_item) {
1945
            $informacao = array(
1946 3
                'campo' => $_item->getAttribute('xCampo'),
1947 3
                'valor' => Util::loadNode(
1948
                    $_item,
1949 3
                    'xTexto',
1950 3
                    'Tag "xTexto" do campo "Informação" não encontrada'
1951
                )
1952
            );
1953 3
            $informacoes[] = $informacao;
1954
        }
1955 3
        $this->setInformacoes($informacoes);
1956
1957 3
        $_fields = $root->getElementsByTagName('protNFe');
1958 3
        $protocolo = null;
1959 3
        if ($_fields->length > 0) {
1960
            $protocolo = new Protocolo();
1961
            $protocolo->loadNode($_fields->item(0), 'infProt');
1962
        }
1963 3
        $this->setProtocolo($protocolo);
1964 3
        return $element;
1965
    }
1966
1967
    /**
1968
     * Carrega um arquivo XML e preenche a nota com as informações dele
1969
     * @param  string $filename caminho do arquivo
1970
     * @return DOMDocument      objeto do documento carregado
1971
     */
1972 1
    public function load($filename)
1973
    {
1974 1
        $dom = new \DOMDocument();
1975 1
        if (!file_exists($filename)) {
1976
            throw new \Exception('Arquivo XML "'.$filename.'" não encontrado', 404);
1977
        }
1978 1
        $dom->load($filename);
1979 1
        $this->loadNode($dom->documentElement);
1980 1
        return $dom;
1981
    }
1982
1983
    /**
1984
     * Assina o XML com a assinatura eletrônica do tipo A1
1985
     */
1986 3
    public function assinar($dom = null)
1987
    {
1988 3
        if (is_null($dom)) {
1989 1
            $xml = $this->getNode();
1990 1
            $dom = $xml->ownerDocument;
1991
        }
1992 3
        $config = SEFAZ::getInstance()->getConfiguracao();
1993
1994 3
        $adapter = new XmlseclibsAdapter();
1995 3
        $adapter->setPrivateKey($config->getChavePrivada());
1996 3
        $adapter->setPublicKey($config->getChavePublica());
1997 3
        $adapter->addTransform(AdapterInterface::ENVELOPED);
1998 3
        $adapter->addTransform(AdapterInterface::XML_C14N);
1999 3
        $adapter->sign($dom, 'infNFe');
2000 3
        return $dom;
2001
    }
2002
2003
    /**
2004
     * Valida o documento após assinar
2005
     */
2006 1
    public function validar($dom)
2007
    {
2008 1
        $dom->loadXML($dom->saveXML());
2009 1
        $xsd_path = __DIR__ . '/schema';
2010 1
        if (is_null($this->getProtocolo())) {
2011 1
            $xsd_file = $xsd_path . '/nfe_v3.10.xsd';
2012
        } else {
2013
            $xsd_file = $xsd_path . '/procNFe_v3.10.xsd';
2014
        }
2015 1
        if (!file_exists($xsd_file)) {
2016
            throw new \Exception('O arquivo "'.$xsd_file.'" de esquema XSD não existe!', 404);
2017
        }
2018
        // Enable user error handling
2019 1
        $save = libxml_use_internal_errors(true);
2020 1
        if ($dom->schemaValidate($xsd_file)) {
2021 1
            libxml_use_internal_errors($save);
2022 1
            return $dom;
2023
        }
2024
        $msg = array();
2025
        $errors = libxml_get_errors();
2026
        foreach ($errors as $error) {
2027
            $msg[] = 'Não foi possível validar o XML: '.$error->message;
2028
        }
2029
        libxml_clear_errors();
2030
        libxml_use_internal_errors($save);
2031
        throw new ValidationException($msg);
2032
    }
2033
2034
    /**
2035
     * Adiciona o protocolo no XML da nota
2036
     */
2037
    public function addProtocolo($dom)
2038
    {
2039
        if (is_null($this->getProtocolo())) {
2040
            throw new \Exception('O protocolo não foi informado na nota "'.$this->getID().'"', 404);
2041
        }
2042
        $notae = $dom->getElementsByTagName('NFe')->item(0);
2043
        // Corrige xmlns:default
2044
        $notae_xml = $dom->saveXML($notae);
2045
2046
        $element = $dom->createElement('nfeProc');
2047
        $element->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', self::PORTAL);
2048
        $versao = $dom->createAttribute('versao');
2049
        $versao->value = self::VERSAO;
2050
        $element->appendChild($versao);
2051
        $dom->removeChild($notae);
2052
        // Corrige xmlns:default
2053
        $notae = $dom->createElement('NFe', 0);
2054
2055
        $element->appendChild($notae);
2056
        $info = $this->getProtocolo()->getNode();
2057
        $info = $dom->importNode($info, true);
2058
        $element->appendChild($info);
2059
        $dom->appendChild($element);
2060
        // Corrige xmlns:default
2061
        $xml = $dom->saveXML();
2062
        $xml = str_replace('<NFe>0</NFe>', $notae_xml, $xml);
2063
        $dom->loadXML($xml);
2064
2065
        return $dom;
2066
    }
2067
}
2068