Passed
Push — master ( 0522e2...cd53d2 )
by Francimar
13:18
created

Nota   F

Complexity

Total Complexity 285

Size/Duplication

Total Lines 2179
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 18

Importance

Changes 0
Metric Value
wmc 285
lcom 1
cbo 18
dl 0
loc 2179
rs 0.8
c 0
b 0
f 0

81 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getID() 0 7 2
A setID() 0 5 1
A getNumero() 0 7 2
A setNumero() 0 5 1
A getEmitente() 0 4 1
A setEmitente() 0 5 1
A getDestinatario() 0 4 1
A setDestinatario() 0 5 1
A getResponsavel() 0 4 1
A setResponsavel() 0 5 1
A getProdutos() 0 4 1
A setProdutos() 0 5 1
A addProduto() 0 5 1
A getIntermediador() 0 4 1
A setIntermediador() 0 5 1
A getTransporte() 0 4 1
A setTransporte() 0 5 1
A getPagamentos() 0 4 1
A setPagamentos() 0 5 1
A addPagamento() 0 5 1
A getDataMovimentacao() 0 7 3
A setDataMovimentacao() 0 8 3
A getDataContingencia() 0 7 3
A setDataContingencia() 0 8 3
A getJustificativa() 0 7 2
A setJustificativa() 0 5 1
A getModelo() 0 13 4
A setModelo() 0 13 3
A getTipo() 0 13 4
A setTipo() 0 13 3
A getDestino() 0 15 5
A setDestino() 0 16 4
A getNatureza() 0 7 2
A setNatureza() 0 5 1
A getCodigo() 0 7 2
A setCodigo() 0 5 1
A getDataEmissao() 0 7 2
A setDataEmissao() 0 8 2
A getSerie() 0 7 2
A setSerie() 0 5 1
B getFormato() 0 21 8
B setFormato() 0 25 7
A getEmissao() 0 13 4
A setEmissao() 0 13 3
A getDigitoVerificador() 0 7 2
A setDigitoVerificador() 0 5 1
A getAmbiente() 0 13 4
A setAmbiente() 0 13 3
A getFinalidade() 0 17 6
A setFinalidade() 0 19 5
A getConsumidorFinal() 0 13 4
A isConsumidorFinal() 0 4 1
A setConsumidorFinal() 0 8 3
B getPresenca() 0 23 9
B setPresenca() 0 28 8
A getIntermediacao() 0 13 4
A setIntermediacao() 0 13 3
A getTotal() 0 4 1
A setTotal() 0 5 1
A getAdicionais() 0 7 2
A setAdicionais() 0 5 1
A getObservacoes() 0 4 1
A setObservacoes() 0 5 1
A addObservacao() 0 5 1
A getInformacoes() 0 4 1
A setInformacoes() 0 5 1
A addInformacao() 0 5 1
A getProtocolo() 0 4 1
A setProtocolo() 0 5 1
F toArray() 0 83 19
F fromArray() 0 149 35
A gerarID() 0 18 1
C getTotais() 0 75 12
A getNodeTotal() 0 37 2
F getNode() 0 150 22
F loadNode() 0 266 21
A load() 0 10 2
A assinar() 0 17 2
A validar() 0 27 5
A addProtocolo() 0 30 2

How to fix   Complexity   

Complex Class

Complex classes like Nota often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Nota, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * MIT License
4
 *
5
 * Copyright (c) 2016 GrandChef 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\Responsavel;
40
use NFe\Entity\Destinatario;
41
use NFe\Entity\Intermediador;
42
use NFe\Exception\ValidationException;
43
use FR3D\XmlDSig\Adapter\AdapterInterface;
44
use FR3D\XmlDSig\Adapter\XmlseclibsAdapter;
45
46
/**
47
 * Classe base para a formação da nota fiscal
48
 */
49
abstract class Nota implements Node
50
{
51
52
    /**
53
     * Versão da nota fiscal
54
     */
55
    public const VERSAO = '4.00';
56
57
    /**
58
     * Versão do aplicativo gerador da nota
59
     */
60
    public const APP_VERSAO = '1.0';
61
62
    /**
63
     * Portal da nota fiscal
64
     */
65
    public const PORTAL = 'http://www.portalfiscal.inf.br/nfe';
66
67
    /**
68
     * Código do modelo do Documento Fiscal. 55 = NF-e; 65 = NFC-e.
69
     */
70
    public const MODELO_NFE = 'nfe';
71
    public const MODELO_NFCE = 'nfce';
72
73
    /**
74
     * Tipo do Documento Fiscal (0 - entrada; 1 - saída)
75
     */
76
    public const TIPO_ENTRADA = 'entrada';
77
    public const TIPO_SAIDA = 'saida';
78
79
    /**
80
     * Identificador de Local de destino da operação
81
     * (1-Interna;2-Interestadual;3-Exterior)
82
     */
83
    public const DESTINO_INTERNA = 'interna';
84
    public const DESTINO_INTERESTADUAL = 'interestadual';
85
    public const DESTINO_EXTERIOR = 'exterior';
86
87
    /**
88
     * Formato de impressão do DANFE (0-sem DANFE;1-DANFe Retrato; 2-DANFe
89
     * Paisagem;3-DANFe Simplificado;4-DANFe NFC-e;5-DANFe NFC-e em mensagem
90
     * eletrônica)
91
     */
92
    public const FORMATO_NENHUMA = 'nenhuma';
93
    public const FORMATO_RETRATO = 'retrato';
94
    public const FORMATO_PAISAGEM = 'paisagem';
95
    public const FORMATO_SIMPLIFICADO = 'simplificado';
96
    public const FORMATO_CONSUMIDOR = 'consumidor';
97
    public const FORMATO_MENSAGEM = 'mensagem';
98
99
    /**
100
     * Forma de emissão da NF-e
101
     */
102
    public const EMISSAO_NORMAL = 'normal';
103
    public const EMISSAO_CONTINGENCIA = 'contingencia';
104
105
    /**
106
     * Identificação do Ambiente: 1 - Produção, 2 - Homologação
107
     */
108
    public const AMBIENTE_PRODUCAO = 'producao';
109
    public const AMBIENTE_HOMOLOGACAO = 'homologacao';
110
111
    /**
112
     * Finalidade da emissão da NF-e: 1 - NFe normal, 2 - NFe complementar, 3 -
113
     * NFe de ajuste, 4 - Devolução/Retorno
114
     */
115
    public const FINALIDADE_NORMAL = 'normal';
116
    public const FINALIDADE_COMPLEMENTAR = 'complementar';
117
    public const FINALIDADE_AJUSTE = 'ajuste';
118
    public const FINALIDADE_RETORNO = 'retorno';
119
120
    /**
121
     * Indicador de presença do comprador no estabelecimento comercial no
122
     * momento da operação (0-Não se aplica ex.: Nota Fiscal complementar ou de
123
     * ajuste;1-Operação presencial;2-Não presencial, internet;3-Não
124
     * presencial, teleatendimento;4-NFC-e entrega em domicílio;5-Operação
125
     * presencial, fora do estabelecimento;9-Não presencial, outros)
126
     */
127
    public const PRESENCA_NENHUM = 'nenhum';
128
    public const PRESENCA_PRESENCIAL = 'presencial';
129
    public const PRESENCA_INTERNET = 'internet';
130
    public const PRESENCA_TELEATENDIMENTO = 'teleatendimento';
131
    public const PRESENCA_ENTREGA = 'entrega';
132
    public const PRESENCA_AMBULANTE = 'ambulante';
133
    public const PRESENCA_OUTROS = 'outros';
134
135
    /**
136
     * Indicador de intermediador/marketplace 0=Operação sem intermediador (em
137
     * site ou plataforma própria) 1=Operação em site ou plataforma de
138
     * terceiros (intermediadores/marketplace)
139
     */
140
    public const INTERMEDIACAO_NENHUM = 'nenhum';
141
    public const INTERMEDIACAO_TERCEIROS = 'terceiros';
142
143
    /**
144
     * Chave da nota fiscal
145
     */
146
    private $id;
147
148
    /**
149
     * Número do Documento Fiscal
150
     */
151
    private $numero;
152
153
    /**
154
     * Emitente da nota fiscal
155
     * 
156
     * @var Emitente
157
     */
158
    private $emitente;
159
160
    /**
161
     * Destinatário que receberá os produtos
162
     * 
163
     * @var Destinatario
164
     */
165
    private $destinatario;
166
167
    /**
168
     * Grupo de informações do responsável técnico pelo sistema
169
     *
170
     * @var Responsavel
171
     */
172
    private $responsavel;
173
174
    /**
175
     * Grupo de Informações do Intermediador da Transação
176
     *
177
     * @var Intermediador
178
     */
179
    private $intermediador;
180
181
    /**
182
     * Produtos adicionados na nota
183
     * 
184
     * @var Produto[]
185
     */
186
    private $produtos;
187
188
    /**
189
     * Informações de trasnporte da mercadoria
190
     * 
191
     * @var Transporte
192
     */
193
    private $transporte;
194
195
    /**
196
     * Pagamentos realizados
197
     * 
198
     * @var Pagamento[]
199
     */
200
    private $pagamentos;
201
202
    /**
203
     * Data e Hora da saída ou de entrada da mercadoria / produto
204
     */
205
    private $data_movimentacao;
206
207
    /**
208
     * Informar a data e hora de entrada em contingência
209
     */
210
    private $data_contingencia;
211
212
    /**
213
     * Informar a Justificativa da entrada em contingência
214
     */
215
    private $justificativa;
216
217
    /**
218
     * Código do modelo do Documento Fiscal. 55 = NF-e; 65 = NFC-e.
219
     */
220
    private $modelo;
221
222
    /**
223
     * Tipo do Documento Fiscal (0 - entrada; 1 - saída)
224
     */
225
    private $tipo;
226
227
    /**
228
     * Identificador de Local de destino da operação
229
     * (1-Interna;2-Interestadual;3-Exterior)
230
     */
231
    private $destino;
232
233
    /**
234
     * Descrição da Natureza da Operação
235
     */
236
    private $natureza;
237
238
    /**
239
     * Código numérico que compõe a Chave de Acesso. Número aleatório gerado
240
     * pelo emitente para cada NF-e.
241
     */
242
    private $codigo;
243
244
    /**
245
     * Data e Hora de emissão do Documento Fiscal
246
     */
247
    private $data_emissao;
248
249
    /**
250
     * Série do Documento Fiscal: série normal 0-889, Avulsa Fisco 890-899,
251
     * SCAN 900-999
252
     */
253
    private $serie;
254
255
    /**
256
     * Formato de impressão do DANFE (0-sem DANFE;1-DANFe Retrato; 2-DANFe
257
     * Paisagem;3-DANFe Simplificado;4-DANFe NFC-e;5-DANFe NFC-e em mensagem
258
     * eletrônica)
259
     */
260
    private $formato;
261
262
    /**
263
     * Forma de emissão da NF-e
264
     */
265
    private $emissao;
266
267
    /**
268
     * Digito Verificador da Chave de Acesso da NF-e
269
     */
270
    private $digito_verificador;
271
272
    /**
273
     * Identificação do Ambiente: 1 - Produção, 2 - Homologação
274
     */
275
    private $ambiente;
276
277
    /**
278
     * Finalidade da emissão da NF-e: 1 - NFe normal, 2 - NFe complementar, 3 -
279
     * NFe de ajuste, 4 - Devolução/Retorno
280
     */
281
    private $finalidade;
282
283
    /**
284
     * Indica operação com consumidor final (0-Não;1-Consumidor Final)
285
     */
286
    private $consumidor_final;
287
288
    /**
289
     * Indicador de presença do comprador no estabelecimento comercial no
290
     * momento da oepração (0-Não se aplica, ex.: Nota Fiscal complementar ou
291
     * de ajuste;1-Operação presencial;2-Não presencial, internet;3-Não
292
     * presencial, teleatendimento;4-NFC-e entrega em domicílio;9-Não
293
     * presencial, outros)
294
     */
295
    private $presenca;
296
297
    /**
298
     * Indicador de intermediador/marketplace 0=Operação sem intermediador (em
299
     * site ou plataforma própria) 1=Operação em site ou plataforma de
300
     * terceiros (intermediadores/marketplace)
301
     *
302
     * @var string
303
     */
304
    private $intermediacao;
305
306
    /**
307
     * Dados dos totais da NF-e
308
     */
309
    private $total;
310
311
    /**
312
     * Informações adicionais de interesse do Fisco
313
     */
314
    private $adicionais;
315
316
    /**
317
     * Campo de uso livre do contribuinte informar o nome do campo no atributo
318
     * xCampo e o conteúdo do campo no xTexto
319
     */
320
    private $observacoes;
321
322
    /**
323
     * Campo de uso exclusivo do Fisco informar o nome do campo no atributo
324
     * xCampo e o conteúdo do campo no xTexto
325
     */
326
    private $informacoes;
327
328
    /**
329
     * Protocolo de autorização da nota, informado apenas quando a nota for
330
     * enviada e autorizada
331
     * 
332
     * @var Protocolo
333
     */
334
    private $protocolo;
335
336
    /**
337
     * Constroi uma instância de Nota vazia
338
     * @param  array $nota Array contendo dados da Nota
339
     */
340
    public function __construct($nota = [])
341
    {
342
        $this->fromArray($nota);
343
    }
344
345
    /**
346
     * Chave da nota fiscal
347
     * @param boolean $normalize informa se o id deve estar no formato do XML
348
     * @return mixed id da Nota
349
     */
350
    public function getID($normalize = false)
351
    {
352
        if (!$normalize) {
353
            return $this->id;
354
        }
355
        return 'NFe' . $this->id;
356
    }
357
358
    /**
359
     * Altera o valor do ID para o informado no parâmetro
360
     * @param mixed $id novo valor para ID
361
     * @return self
362
     */
363
    public function setID($id)
364
    {
365
        $this->id = $id;
366
        return $this;
367
    }
368
369
    /**
370
     * Número do Documento Fiscal
371
     * @param boolean $normalize informa se o numero deve estar no formato do XML
372
     * @return mixed numero da Nota
373
     */
374
    public function getNumero($normalize = false)
375
    {
376
        if (!$normalize) {
377
            return $this->numero;
378
        }
379
        return $this->numero;
380
    }
381
382
    /**
383
     * Altera o valor do Numero para o informado no parâmetro
384
     * @param mixed $numero novo valor para Numero
385
     * @return self
386
     */
387
    public function setNumero($numero)
388
    {
389
        $this->numero = $numero;
390
        return $this;
391
    }
392
393
    /**
394
     * Emitente da nota fiscal
395
     * @return Emitente emitente da Nota
396
     */
397
    public function getEmitente()
398
    {
399
        return $this->emitente;
400
    }
401
402
    /**
403
     * Altera o valor do Emitente para o informado no parâmetro
404
     * @param Emitente $emitente novo valor para Emitente
405
     * @return self
406
     */
407
    public function setEmitente($emitente)
408
    {
409
        $this->emitente = $emitente;
410
        return $this;
411
    }
412
413
    /**
414
     * Destinatário que receberá os produtos
415
     * @return Destinatario destinatario da Nota
416
     */
417
    public function getDestinatario()
418
    {
419
        return $this->destinatario;
420
    }
421
422
    /**
423
     * Altera o valor do Destinatario para o informado no parâmetro
424
     * @param Destinatario $destinatario novo valor para Destinatario
425
     * @return self
426
     */
427
    public function setDestinatario($destinatario)
428
    {
429
        $this->destinatario = $destinatario;
430
        return $this;
431
    }
432
433
    /**
434
     * Grupo de informações do responsável técnico pelo sistema
435
     * @return Responsavel responsável da Nota
436
     */
437
    public function getResponsavel()
438
    {
439
        return $this->responsavel;
440
    }
441
442
    /**
443
     * Altera o valor do grupo de informações do responsável técnico pelo sistema
444
     * @param Responsavel $responsavel novo valor para grupo de informações do responsável
445
     * @return self
446
     */
447
    public function setResponsavel($responsavel)
448
    {
449
        $this->responsavel = $responsavel;
450
        return $this;
451
    }
452
453
    /**
454
     * Produtos adicionados na nota
455
     * @return Produto[] produtos da Nota
456
     */
457
    public function getProdutos()
458
    {
459
        return $this->produtos;
460
    }
461
462
    /**
463
     * Altera o valor do Produtos para o informado no parâmetro
464
     *
465
     * @param Produto[] $produtos
466
     *
467
     * @return self
468
     */
469
    public function setProdutos($produtos)
470
    {
471
        $this->produtos = $produtos;
472
        return $this;
473
    }
474
475
    /**
476
     * Adiciona um(a) Produto para a lista de produto
477
     * @param Produto $produto Instância do Produto que será adicionada
478
     * @return self
479
     */
480
    public function addProduto($produto)
481
    {
482
        $this->produtos[] = $produto;
483
        return $this;
484
    }
485
486
    /**
487
     * Grupo de Informações do Intermediador da Transação
488
     *
489
     * @return Intermediador
490
     */
491
    public function getIntermediador()
492
    {
493
        return $this->intermediador;
494
    }
495
    
496
    /**
497
     * Altera o valor do Intermediador para o informado no parâmetro
498
     *
499
     * @param Intermediador $intermediador
500
     *
501
     * @return self
502
     */
503
    public function setIntermediador($intermediador)
504
    {
505
        $this->intermediador = $intermediador;
506
        return $this;
507
    }
508
509
    /**
510
     * Informações de trasnporte da mercadoria
511
     * @return mixed transporte da Nota
512
     */
513
    public function getTransporte()
514
    {
515
        return $this->transporte;
516
    }
517
518
    /**
519
     * Altera o valor da Transporte para o informado no parâmetro
520
     * @param mixed $transporte novo valor para Transporte
521
     * @return self
522
     */
523
    public function setTransporte($transporte)
524
    {
525
        $this->transporte = $transporte;
526
        return $this;
527
    }
528
529
    /**
530
     * Pagamentos realizados
531
     * @return mixed pagamentos da Nota
532
     */
533
    public function getPagamentos()
534
    {
535
        return $this->pagamentos;
536
    }
537
538
    /**
539
     * Altera o valor do Pagamentos para o informado no parâmetro
540
     * @param mixed $pagamentos novo valor para Pagamentos
541
     * @return self
542
     */
543
    public function setPagamentos($pagamentos)
544
    {
545
        $this->pagamentos = $pagamentos;
0 ignored issues
show
Documentation Bug introduced by
It seems like $pagamentos of type * is incompatible with the declared type array<integer,object<NFe\Entity\Pagamento>> of property $pagamentos.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
546
        return $this;
547
    }
548
549
    /**
550
     * Adiciona um(a) Pagamento para a lista de pagamento
551
     * @param Pagamento $pagamento Instância do Pagamento que será adicionada
552
     * @return self
553
     */
554
    public function addPagamento($pagamento)
555
    {
556
        $this->pagamentos[] = $pagamento;
557
        return $this;
558
    }
559
560
    /**
561
     * Data e Hora da saída ou de entrada da mercadoria / produto
562
     * @param boolean $normalize informa se a data_movimentacao deve estar no formato do XML
563
     * @return mixed data_movimentacao da Nota
564
     */
565
    public function getDataMovimentacao($normalize = false)
566
    {
567
        if (!$normalize || is_null($this->data_movimentacao)) {
568
            return $this->data_movimentacao;
569
        }
570
        return Util::toDateTime($this->data_movimentacao);
571
    }
572
573
    /**
574
     * Altera o valor da DataMovimentacao para o informado no parâmetro
575
     * @param mixed $data_movimentacao novo valor para DataMovimentacao
576
     * @return self
577
     */
578
    public function setDataMovimentacao($data_movimentacao)
579
    {
580
        if (!is_null($data_movimentacao) && !is_numeric($data_movimentacao)) {
581
            $data_movimentacao = strtotime($data_movimentacao);
582
        }
583
        $this->data_movimentacao = $data_movimentacao;
584
        return $this;
585
    }
586
587
    /**
588
     * Informar a data e hora de entrada em contingência
589
     * @param boolean $normalize informa se a data_contingencia deve estar no formato do XML
590
     * @return mixed data_contingencia da Nota
591
     */
592
    public function getDataContingencia($normalize = false)
593
    {
594
        if (!$normalize || is_null($this->data_contingencia)) {
595
            return $this->data_contingencia;
596
        }
597
        return Util::toDateTime($this->data_contingencia);
598
    }
599
600
    /**
601
     * Altera o valor da DataContingencia para o informado no parâmetro
602
     * @param mixed $data_contingencia novo valor para DataContingencia
603
     * @return self
604
     */
605
    public function setDataContingencia($data_contingencia)
606
    {
607
        if (!is_null($data_contingencia) && !is_numeric($data_contingencia)) {
608
            $data_contingencia = strtotime($data_contingencia);
609
        }
610
        $this->data_contingencia = $data_contingencia;
611
        return $this;
612
    }
613
614
    /**
615
     * Informar a Justificativa da entrada em contingência
616
     * @param boolean $normalize informa se a justificativa deve estar no formato do XML
617
     * @return mixed justificativa da Nota
618
     */
619
    public function getJustificativa($normalize = false)
620
    {
621
        if (!$normalize) {
622
            return $this->justificativa;
623
        }
624
        return $this->justificativa;
625
    }
626
627
    /**
628
     * Altera o valor da Justificativa para o informado no parâmetro
629
     * @param mixed $justificativa novo valor para Justificativa
630
     * @return self
631
     */
632
    public function setJustificativa($justificativa)
633
    {
634
        $this->justificativa = $justificativa;
635
        return $this;
636
    }
637
638
    /**
639
     * Código do modelo do Documento Fiscal. 55 = NF-e; 65 = NFC-e.
640
     * @param boolean $normalize informa se o modelo deve estar no formato do XML
641
     * @return mixed modelo da Nota
642
     */
643
    public function getModelo($normalize = false)
644
    {
645
        if (!$normalize) {
646
            return $this->modelo;
647
        }
648
        switch ($this->modelo) {
649
            case self::MODELO_NFE:
650
                return '55';
651
            case self::MODELO_NFCE:
652
                return '65';
653
        }
654
        return $this->modelo;
655
    }
656
657
    /**
658
     * Altera o valor do Modelo para o informado no parâmetro
659
     * @param mixed $modelo novo valor para Modelo
660
     * @return self
661
     */
662
    public function setModelo($modelo)
663
    {
664
        switch ($modelo) {
665
            case '55':
666
                $modelo = self::MODELO_NFE;
667
                break;
668
            case '65':
669
                $modelo = self::MODELO_NFCE;
670
                break;
671
        }
672
        $this->modelo = $modelo;
673
        return $this;
674
    }
675
676
    /**
677
     * Tipo do Documento Fiscal (0 - entrada; 1 - saída)
678
     * @param boolean $normalize informa se o tipo deve estar no formato do XML
679
     * @return mixed tipo da Nota
680
     */
681
    public function getTipo($normalize = false)
682
    {
683
        if (!$normalize) {
684
            return $this->tipo;
685
        }
686
        switch ($this->tipo) {
687
            case self::TIPO_ENTRADA:
688
                return '0';
689
            case self::TIPO_SAIDA:
690
                return '1';
691
        }
692
        return $this->tipo;
693
    }
694
695
    /**
696
     * Altera o valor do Tipo para o informado no parâmetro
697
     * @param mixed $tipo novo valor para Tipo
698
     * @return self
699
     */
700
    public function setTipo($tipo)
701
    {
702
        switch ($tipo) {
703
            case '0':
704
                $tipo = self::TIPO_ENTRADA;
705
                break;
706
            case '1':
707
                $tipo = self::TIPO_SAIDA;
708
                break;
709
        }
710
        $this->tipo = $tipo;
711
        return $this;
712
    }
713
714
    /**
715
     * Identificador de Local de destino da operação
716
     * (1-Interna;2-Interestadual;3-Exterior)
717
     * @param boolean $normalize informa se o destino deve estar no formato do XML
718
     * @return mixed destino da Nota
719
     */
720
    public function getDestino($normalize = false)
721
    {
722
        if (!$normalize) {
723
            return $this->destino;
724
        }
725
        switch ($this->destino) {
726
            case self::DESTINO_INTERNA:
727
                return '1';
728
            case self::DESTINO_INTERESTADUAL:
729
                return '2';
730
            case self::DESTINO_EXTERIOR:
731
                return '3';
732
        }
733
        return $this->destino;
734
    }
735
736
    /**
737
     * Altera o valor do Destino para o informado no parâmetro
738
     * @param mixed $destino novo valor para Destino
739
     * @return self
740
     */
741
    public function setDestino($destino)
742
    {
743
        switch ($destino) {
744
            case '1':
745
                $destino = self::DESTINO_INTERNA;
746
                break;
747
            case '2':
748
                $destino = self::DESTINO_INTERESTADUAL;
749
                break;
750
            case '3':
751
                $destino = self::DESTINO_EXTERIOR;
752
                break;
753
        }
754
        $this->destino = $destino;
755
        return $this;
756
    }
757
758
    /**
759
     * Descrição da Natureza da Operação
760
     * @param boolean $normalize informa se a natureza deve estar no formato do XML
761
     * @return mixed natureza da Nota
762
     */
763
    public function getNatureza($normalize = false)
764
    {
765
        if (!$normalize) {
766
            return $this->natureza;
767
        }
768
        return $this->natureza;
769
    }
770
771
    /**
772
     * Altera o valor da Natureza para o informado no parâmetro
773
     * @param mixed $natureza novo valor para Natureza
774
     * @return self
775
     */
776
    public function setNatureza($natureza)
777
    {
778
        $this->natureza = $natureza;
779
        return $this;
780
    }
781
782
    /**
783
     * Código numérico que compõe a Chave de Acesso. Número aleatório gerado
784
     * pelo emitente para cada NF-e.
785
     * @param boolean $normalize informa se o codigo deve estar no formato do XML
786
     * @return mixed codigo da Nota
787
     */
788
    public function getCodigo($normalize = false)
789
    {
790
        if (!$normalize) {
791
            return $this->codigo;
792
        }
793
        return Util::padDigit($this->codigo % 100000000, 8);
794
    }
795
796
    /**
797
     * Altera o valor do Codigo para o informado no parâmetro
798
     * @param mixed $codigo novo valor para Codigo
799
     * @return self
800
     */
801
    public function setCodigo($codigo)
802
    {
803
        $this->codigo = $codigo;
804
        return $this;
805
    }
806
807
    /**
808
     * Data e Hora de emissão do Documento Fiscal
809
     * @param boolean $normalize informa se o data_emissao deve estar no formato do XML
810
     * @return mixed data_emissao da Nota
811
     */
812
    public function getDataEmissao($normalize = false)
813
    {
814
        if (!$normalize) {
815
            return $this->data_emissao;
816
        }
817
        return Util::toDateTime($this->data_emissao);
818
    }
819
820
    /**
821
     * Altera o valor do DataEmissao para o informado no parâmetro
822
     * @param mixed $data_emissao novo valor para DataEmissao
823
     * @return self
824
     */
825
    public function setDataEmissao($data_emissao)
826
    {
827
        if (!is_numeric($data_emissao)) {
828
            $data_emissao = strtotime($data_emissao);
829
        }
830
        $this->data_emissao = $data_emissao;
831
        return $this;
832
    }
833
834
    /**
835
     * Série do Documento Fiscal: série normal 0-889, Avulsa Fisco 890-899,
836
     * SCAN 900-999
837
     * @param boolean $normalize informa se o serie deve estar no formato do XML
838
     * @return mixed serie da Nota
839
     */
840
    public function getSerie($normalize = false)
841
    {
842
        if (!$normalize) {
843
            return $this->serie;
844
        }
845
        return $this->serie;
846
    }
847
848
    /**
849
     * Altera o valor do Serie para o informado no parâmetro
850
     * @param mixed $serie novo valor para Serie
851
     * @return self
852
     */
853
    public function setSerie($serie)
854
    {
855
        $this->serie = $serie;
856
        return $this;
857
    }
858
859
    /**
860
     * Formato de impressão do DANFE (0-sem DANFE;1-DANFe Retrato; 2-DANFe
861
     * Paisagem;3-DANFe Simplificado;4-DANFe NFC-e;5-DANFe NFC-e em mensagem
862
     * eletrônica)
863
     * @param boolean $normalize informa se o formato deve estar no formato do XML
864
     * @return mixed formato da Nota
865
     */
866
    public function getFormato($normalize = false)
867
    {
868
        if (!$normalize) {
869
            return $this->formato;
870
        }
871
        switch ($this->formato) {
872
            case self::FORMATO_NENHUMA:
873
                return '0';
874
            case self::FORMATO_RETRATO:
875
                return '1';
876
            case self::FORMATO_PAISAGEM:
877
                return '2';
878
            case self::FORMATO_SIMPLIFICADO:
879
                return '3';
880
            case self::FORMATO_CONSUMIDOR:
881
                return '4';
882
            case self::FORMATO_MENSAGEM:
883
                return '5';
884
        }
885
        return $this->formato;
886
    }
887
888
    /**
889
     * Altera o valor do Formato para o informado no parâmetro
890
     * @param mixed $formato novo valor para Formato
891
     * @return self
892
     */
893
    public function setFormato($formato)
894
    {
895
        switch ($formato) {
896
            case '0':
897
                $formato = self::FORMATO_NENHUMA;
898
                break;
899
            case '1':
900
                $formato = self::FORMATO_RETRATO;
901
                break;
902
            case '2':
903
                $formato = self::FORMATO_PAISAGEM;
904
                break;
905
            case '3':
906
                $formato = self::FORMATO_SIMPLIFICADO;
907
                break;
908
            case '4':
909
                $formato = self::FORMATO_CONSUMIDOR;
910
                break;
911
            case '5':
912
                $formato = self::FORMATO_MENSAGEM;
913
                break;
914
        }
915
        $this->formato = $formato;
916
        return $this;
917
    }
918
919
    /**
920
     * Forma de emissão da NF-e
921
     * @param boolean $normalize informa se o emissao deve estar no formato do XML
922
     * @return mixed emissao da Nota
923
     */
924
    public function getEmissao($normalize = false)
925
    {
926
        if (!$normalize) {
927
            return $this->emissao;
928
        }
929
        switch ($this->emissao) {
930
            case self::EMISSAO_NORMAL:
931
                return '1';
932
            case self::EMISSAO_CONTINGENCIA:
933
                return '9';
934
        }
935
        return $this->emissao;
936
    }
937
938
    /**
939
     * Altera o valor do Emissao para o informado no parâmetro
940
     * @param mixed $emissao novo valor para Emissao
941
     * @return self
942
     */
943
    public function setEmissao($emissao)
944
    {
945
        switch ($emissao) {
946
            case '1':
947
                $emissao = self::EMISSAO_NORMAL;
948
                break;
949
            case '9':
950
                $emissao = self::EMISSAO_CONTINGENCIA;
951
                break;
952
        }
953
        $this->emissao = $emissao;
954
        return $this;
955
    }
956
957
    /**
958
     * Digito Verificador da Chave de Acesso da NF-e
959
     * @param boolean $normalize informa se o digito_verificador deve estar no formato do XML
960
     * @return mixed digito_verificador da Nota
961
     */
962
    public function getDigitoVerificador($normalize = false)
963
    {
964
        if (!$normalize) {
965
            return $this->digito_verificador;
966
        }
967
        return $this->digito_verificador;
968
    }
969
970
    /**
971
     * Altera o valor do DigitoVerificador para o informado no parâmetro
972
     * @param mixed $digito_verificador novo valor para DigitoVerificador
973
     * @return self
974
     */
975
    public function setDigitoVerificador($digito_verificador)
976
    {
977
        $this->digito_verificador = $digito_verificador;
978
        return $this;
979
    }
980
981
    /**
982
     * Identificação do Ambiente: 1 - Produção, 2 - Homologação
983
     * @param boolean $normalize informa se o ambiente deve estar no formato do XML
984
     * @return mixed ambiente da Nota
985
     */
986
    public function getAmbiente($normalize = false)
987
    {
988
        if (!$normalize) {
989
            return $this->ambiente;
990
        }
991
        switch ($this->ambiente) {
992
            case self::AMBIENTE_PRODUCAO:
993
                return '1';
994
            case self::AMBIENTE_HOMOLOGACAO:
995
                return '2';
996
        }
997
        return $this->ambiente;
998
    }
999
1000
    /**
1001
     * Altera o valor do Ambiente para o informado no parâmetro
1002
     * @param mixed $ambiente novo valor para Ambiente
1003
     * @return self
1004
     */
1005
    public function setAmbiente($ambiente)
1006
    {
1007
        switch ($ambiente) {
1008
            case '1':
1009
                $ambiente = self::AMBIENTE_PRODUCAO;
1010
                break;
1011
            case '2':
1012
                $ambiente = self::AMBIENTE_HOMOLOGACAO;
1013
                break;
1014
        }
1015
        $this->ambiente = $ambiente;
1016
        return $this;
1017
    }
1018
1019
    /**
1020
     * Finalidade da emissão da NF-e: 1 - NFe normal, 2 - NFe complementar, 3 -
1021
     * NFe de ajuste, 4 - Devolução/Retorno
1022
     * @param boolean $normalize informa se a finalidade deve estar no formato do XML
1023
     * @return mixed finalidade da Nota
1024
     */
1025
    public function getFinalidade($normalize = false)
1026
    {
1027
        if (!$normalize) {
1028
            return $this->finalidade;
1029
        }
1030
        switch ($this->finalidade) {
1031
            case self::FINALIDADE_NORMAL:
1032
                return '1';
1033
            case self::FINALIDADE_COMPLEMENTAR:
1034
                return '2';
1035
            case self::FINALIDADE_AJUSTE:
1036
                return '3';
1037
            case self::FINALIDADE_RETORNO:
1038
                return '4';
1039
        }
1040
        return $this->finalidade;
1041
    }
1042
1043
    /**
1044
     * Altera o valor da Finalidade para o informado no parâmetro
1045
     * @param mixed $finalidade novo valor para Finalidade
1046
     * @return self
1047
     */
1048
    public function setFinalidade($finalidade)
1049
    {
1050
        switch ($finalidade) {
1051
            case '1':
1052
                $finalidade = self::FINALIDADE_NORMAL;
1053
                break;
1054
            case '2':
1055
                $finalidade = self::FINALIDADE_COMPLEMENTAR;
1056
                break;
1057
            case '3':
1058
                $finalidade = self::FINALIDADE_AJUSTE;
1059
                break;
1060
            case '4':
1061
                $finalidade = self::FINALIDADE_RETORNO;
1062
                break;
1063
        }
1064
        $this->finalidade = $finalidade;
1065
        return $this;
1066
    }
1067
1068
    /**
1069
     * Indica operação com consumidor final (0-Não;1-Consumidor Final)
1070
     * @param boolean $normalize informa se o consumidor_final deve estar no formato do XML
1071
     * @return mixed consumidor_final da Nota
1072
     */
1073
    public function getConsumidorFinal($normalize = false)
1074
    {
1075
        if (!$normalize) {
1076
            return $this->consumidor_final;
1077
        }
1078
        switch ($this->consumidor_final) {
1079
            case 'N':
1080
                return '0';
1081
            case 'Y':
1082
                return '1';
1083
        }
1084
        return $this->consumidor_final;
1085
    }
1086
1087
    /**
1088
     * Indica operação com consumidor final (0-Não;1-Consumidor Final)
1089
     * @return boolean informa se o ConsumidorFinal está habilitado
1090
     */
1091
    public function isConsumidorFinal()
1092
    {
1093
        return $this->consumidor_final == 'Y';
1094
    }
1095
1096
    /**
1097
     * Altera o valor do ConsumidorFinal para o informado no parâmetro
1098
     * @param mixed $consumidor_final novo valor para ConsumidorFinal
1099
     * @return self
1100
     */
1101
    public function setConsumidorFinal($consumidor_final)
1102
    {
1103
        if (is_bool($consumidor_final)) {
1104
            $consumidor_final = $consumidor_final ? 'Y' : 'N';
1105
        }
1106
        $this->consumidor_final = $consumidor_final;
1107
        return $this;
1108
    }
1109
1110
    /**
1111
     * Indicador de presença do comprador no estabelecimento comercial no
1112
     * momento da oepração (0-Não se aplica (ex.: Nota Fiscal complementar ou
1113
     * de ajuste;1-Operação presencial;2-Não presencial, internet;
1114
     * 3-Não presencial, teleatendimento;4-NFC-e entrega em domicílio;
1115
     * 5-Operação presencial, fora do estabelecimento;9-Não presencial, outros)
1116
     * @param boolean $normalize informa se a presenca deve estar no formato do XML
1117
     * @return mixed presenca da Nota
1118
     */
1119
    public function getPresenca($normalize = false)
1120
    {
1121
        if (!$normalize) {
1122
            return $this->presenca;
1123
        }
1124
        switch ($this->presenca) {
1125
            case self::PRESENCA_NENHUM:
1126
                return '0';
1127
            case self::PRESENCA_PRESENCIAL:
1128
                return '1';
1129
            case self::PRESENCA_INTERNET:
1130
                return '2';
1131
            case self::PRESENCA_TELEATENDIMENTO:
1132
                return '3';
1133
            case self::PRESENCA_ENTREGA:
1134
                return '4';
1135
            case self::PRESENCA_AMBULANTE:
1136
                return '5';
1137
            case self::PRESENCA_OUTROS:
1138
                return '9';
1139
        }
1140
        return $this->presenca;
1141
    }
1142
1143
    /**
1144
     * Altera o valor da Presenca para o informado no parâmetro
1145
     * @param mixed $presenca novo valor para Presenca
1146
     * @return self
1147
     */
1148
    public function setPresenca($presenca)
1149
    {
1150
        switch ($presenca) {
1151
            case '0':
1152
                $presenca = self::PRESENCA_NENHUM;
1153
                break;
1154
            case '1':
1155
                $presenca = self::PRESENCA_PRESENCIAL;
1156
                break;
1157
            case '2':
1158
                $presenca = self::PRESENCA_INTERNET;
1159
                break;
1160
            case '3':
1161
                $presenca = self::PRESENCA_TELEATENDIMENTO;
1162
                break;
1163
            case '4':
1164
                $presenca = self::PRESENCA_ENTREGA;
1165
                break;
1166
            case '5':
1167
                $presenca = self::PRESENCA_AMBULANTE;
1168
                break;
1169
            case '9':
1170
                $presenca = self::PRESENCA_OUTROS;
1171
                break;
1172
        }
1173
        $this->presenca = $presenca;
1174
        return $this;
1175
    }
1176
1177
    /**
1178
     * Indicador de intermediador/marketplace 0=Operação sem intermediador (em
1179
     * site ou plataforma própria) 1=Operação em site ou plataforma de
1180
     * terceiros (intermediadores/marketplace)
1181
     * @param boolean $normalize informa se a intermediacao deve estar no formato do XML
1182
     * @return string intermediacao of Nota
1183
     */
1184
    public function getIntermediacao($normalize = false)
1185
    {
1186
        if (!$normalize) {
1187
            return $this->intermediacao;
1188
        }
1189
        switch ($this->intermediacao) {
1190
            case self::INTERMEDIACAO_NENHUM:
1191
                return '0';
1192
            case self::INTERMEDIACAO_TERCEIROS:
1193
                return '1';
1194
        }
1195
        return $this->intermediacao;
1196
    }
1197
    
1198
    /**
1199
     * Altera o valor da Intermediacao para o informado no parâmetro
1200
     * @param mixed $intermediacao novo valor para Intermediacao
1201
     * @param string $intermediacao Novo intermediacao para Nota
1202
     * @return self
1203
     */
1204
    public function setIntermediacao($intermediacao)
1205
    {
1206
        switch ($intermediacao) {
1207
            case '0':
1208
                $intermediacao = self::INTERMEDIACAO_NENHUM;
1209
                break;
1210
            case '1':
1211
                $intermediacao = self::INTERMEDIACAO_TERCEIROS;
1212
                break;
1213
        }
1214
        $this->intermediacao = $intermediacao;
1215
        return $this;
1216
    }
1217
1218
    /**
1219
     * Dados dos totais da NF-e
1220
     * @return mixed total da Nota
1221
     */
1222
    public function getTotal()
1223
    {
1224
        return $this->total;
1225
    }
1226
    
1227
    /**
1228
     * Altera o valor do Total para o informado no parâmetro
1229
     * @param mixed $total novo valor para Total
1230
     * @return self
1231
     */
1232
    public function setTotal($total)
1233
    {
1234
        $this->total = $total;
1235
        return $this;
1236
    }
1237
1238
    /**
1239
     * Informações adicionais de interesse do Fisco
1240
     * @param boolean $normalize informa se a adicionais deve estar no formato do XML
1241
     * @return mixed adicionais da Nota
1242
     */
1243
    public function getAdicionais($normalize = false)
1244
    {
1245
        if (!$normalize) {
1246
            return $this->adicionais;
1247
        }
1248
        return $this->adicionais;
1249
    }
1250
    
1251
    /**
1252
     * Altera o valor da Adicionais para o informado no parâmetro
1253
     * @param mixed $adicionais novo valor para Adicionais
1254
     * @return self
1255
     */
1256
    public function setAdicionais($adicionais)
1257
    {
1258
        $this->adicionais = $adicionais;
1259
        return $this;
1260
    }
1261
1262
    /**
1263
     * Campo de uso livre do contribuinte informar o nome do campo no atributo
1264
     * xCampo e o conteúdo do campo no xTexto
1265
     * @return mixed observacoes da Nota
1266
     */
1267
    public function getObservacoes()
1268
    {
1269
        return $this->observacoes;
1270
    }
1271
    
1272
    /**
1273
     * Altera o valor da Observacoes para o informado no parâmetro
1274
     * @param mixed $observacoes novo valor para Observacoes
1275
     * @return self
1276
     */
1277
    public function setObservacoes($observacoes)
1278
    {
1279
        $this->observacoes = $observacoes;
1280
        return $this;
1281
    }
1282
1283
    /**
1284
     * Adiciona um(a) Observacao para a lista de observacao
1285
     * @param Observacao $observacao Instância da Observacao que será adicionada
1286
     * @return self
1287
     */
1288
    public function addObservacao($campo, $observacao)
1289
    {
1290
        $this->observacoes[] = ['campo' => $campo, 'valor' => $observacao];
1291
        return $this;
1292
    }
1293
1294
    /**
1295
     * Campo de uso exclusivo do Fisco informar o nome do campo no atributo
1296
     * xCampo e o conteúdo do campo no xTexto
1297
     * @return mixed informacoes da Nota
1298
     */
1299
    public function getInformacoes()
1300
    {
1301
        return $this->informacoes;
1302
    }
1303
    
1304
    /**
1305
     * Altera o valor da Informacoes para o informado no parâmetro
1306
     * @param mixed $informacoes novo valor para Informacoes
1307
     * @return self
1308
     */
1309
    public function setInformacoes($informacoes)
1310
    {
1311
        $this->informacoes = $informacoes;
1312
        return $this;
1313
    }
1314
1315
    /**
1316
     * Adiciona um(a) Informacao para a lista de informacao
1317
     * @param Informacao $informacao Instância da Informacao que será adicionada
1318
     * @return self
1319
     */
1320
    public function addInformacao($campo, $informacao)
1321
    {
1322
        $this->informacoes[] = ['campo' => $campo, 'valor' => $informacao];
1323
        return $this;
1324
    }
1325
1326
    /**
1327
     * Protocolo de autorização da nota, informado apenas quando a nota for
1328
     * enviada e autorizada
1329
     */
1330
    public function getProtocolo()
1331
    {
1332
        return $this->protocolo;
1333
    }
1334
1335
    public function setProtocolo($protocolo)
1336
    {
1337
        $this->protocolo = $protocolo;
1338
        return $this;
1339
    }
1340
1341
    public function toArray($recursive = false)
1342
    {
1343
        $nota = [];
1344
        $nota['id'] = $this->getID();
1345
        $nota['numero'] = $this->getNumero();
1346
        if (!is_null($this->getEmitente()) && $recursive) {
1347
            $nota['emitente'] = $this->getEmitente()->toArray($recursive);
1348
        } else {
1349
            $nota['emitente'] = $this->getEmitente();
1350
        }
1351
        if (!is_null($this->getDestinatario()) && $recursive) {
1352
            $nota['destinatario'] = $this->getDestinatario()->toArray($recursive);
1353
        } else {
1354
            $nota['destinatario'] = $this->getDestinatario();
1355
        }
1356
        if (!is_null($this->getResponsavel()) && $recursive) {
1357
            $nota['responsavel'] = $this->getResponsavel()->toArray($recursive);
1358
        } else {
1359
            $nota['responsavel'] = $this->getResponsavel();
1360
        }
1361
        if ($recursive) {
1362
            $produtos = [];
1363
            $_produtos = $this->getProdutos();
1364
            foreach ($_produtos as $_produto) {
1365
                $produtos[] = $_produto->toArray($recursive);
1366
            }
1367
            $nota['produtos'] = $produtos;
1368
        } else {
1369
            $nota['produtos'] = $this->getProdutos();
1370
        }
1371
        if (!is_null($this->getIntermediador()) && $recursive) {
1372
            $nota['intermediador'] = $this->getIntermediador()->toArray($recursive);
1373
        } else {
1374
            $nota['intermediador'] = $this->getIntermediador();
1375
        }
1376
        if (!is_null($this->getTransporte()) && $recursive) {
1377
            $nota['transporte'] = $this->getTransporte()->toArray($recursive);
1378
        } else {
1379
            $nota['transporte'] = $this->getTransporte();
1380
        }
1381
        if ($recursive) {
1382
            $pagamentos = [];
1383
            $_pagamentos = $this->getPagamentos();
1384
            foreach ($_pagamentos as $_pagamento) {
1385
                $pagamentos[] = $_pagamento->toArray($recursive);
1386
            }
1387
            $nota['pagamentos'] = $pagamentos;
1388
        } else {
1389
            $nota['pagamentos'] = $this->getPagamentos();
1390
        }
1391
        $nota['data_movimentacao'] = $this->getDataMovimentacao($recursive);
1392
        $nota['data_contingencia'] = $this->getDataContingencia($recursive);
1393
        $nota['justificativa'] = $this->getJustificativa();
1394
        $nota['modelo'] = $this->getModelo();
1395
        $nota['tipo'] = $this->getTipo();
1396
        $nota['destino'] = $this->getDestino();
1397
        $nota['natureza'] = $this->getNatureza();
1398
        $nota['codigo'] = $this->getCodigo();
1399
        $nota['data_emissao'] = $this->getDataEmissao($recursive);
1400
        $nota['serie'] = $this->getSerie();
1401
        $nota['formato'] = $this->getFormato();
1402
        $nota['emissao'] = $this->getEmissao();
1403
        $nota['digito_verificador'] = $this->getDigitoVerificador();
1404
        $nota['ambiente'] = $this->getAmbiente();
1405
        $nota['finalidade'] = $this->getFinalidade();
1406
        $nota['consumidor_final'] = $this->getConsumidorFinal();
1407
        $nota['presenca'] = $this->getPresenca();
1408
        $nota['intermediacao'] = $this->getIntermediacao();
1409
        if (!is_null($this->getTotal()) && $recursive) {
1410
            $nota['total'] = $this->getTotal()->toArray($recursive);
1411
        } else {
1412
            $nota['total'] = $this->getTotal();
1413
        }
1414
        $nota['adicionais'] = $this->getAdicionais();
1415
        $nota['observacoes'] = $this->getObservacoes();
1416
        $nota['informacoes'] = $this->getInformacoes();
1417
        if (!is_null($this->getProtocolo()) && $recursive) {
1418
            $nota['protocolo'] = $this->getProtocolo()->toArray($recursive);
1419
        } else {
1420
            $nota['protocolo'] = $this->getProtocolo();
1421
        }
1422
        return $nota;
1423
    }
1424
1425
    public function fromArray($nota = [])
1426
    {
1427
        if ($nota instanceof Nota) {
1428
            $nota = $nota->toArray();
1429
        } elseif (!is_array($nota)) {
1430
            return $this;
1431
        }
1432
        if (isset($nota['id'])) {
1433
            $this->setID($nota['id']);
1434
        } else {
1435
            $this->setID(null);
1436
        }
1437
        if (isset($nota['numero'])) {
1438
            $this->setNumero($nota['numero']);
1439
        } else {
1440
            $this->setNumero(null);
1441
        }
1442
        $this->setEmitente(new Emitente(isset($nota['emitente']) ? $nota['emitente'] : []));
1443
        $this->setDestinatario(new Destinatario(isset($nota['destinatario']) ? $nota['destinatario'] : []));
1444
        $this->setResponsavel(new Responsavel(isset($nota['responsavel']) ? $nota['responsavel'] : []));
1445
        if (!isset($nota['produtos'])) {
1446
            $this->setProdutos([]);
1447
        } else {
1448
            $this->setProdutos($nota['produtos']);
1449
        }
1450
        if (isset($nota['intermediador'])) {
1451
            $this->setIntermediador(new Intermediador(isset($nota['intermediador'])));
0 ignored issues
show
Documentation introduced by
isset($nota['intermediador']) is of type boolean, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1452
        } else {
1453
            $this->setIntermediador(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<NFe\Entity\Intermediador>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1454
        }
1455
        $this->setTransporte(new Transporte(isset($nota['transporte']) ? $nota['transporte'] : []));
1456
        if (!isset($nota['pagamentos'])) {
1457
            $this->setPagamentos([]);
1458
        } else {
1459
            $this->setPagamentos($nota['pagamentos']);
1460
        }
1461
        if (isset($nota['data_movimentacao'])) {
1462
            $this->setDataMovimentacao($nota['data_movimentacao']);
1463
        } else {
1464
            $this->setDataMovimentacao(null);
1465
        }
1466
        if (isset($nota['data_contingencia'])) {
1467
            $this->setDataContingencia($nota['data_contingencia']);
1468
        } else {
1469
            $this->setDataContingencia(null);
1470
        }
1471
        if (isset($nota['justificativa'])) {
1472
            $this->setJustificativa($nota['justificativa']);
1473
        } else {
1474
            $this->setJustificativa(null);
1475
        }
1476
        if (isset($nota['modelo'])) {
1477
            $this->setModelo($nota['modelo']);
1478
        } else {
1479
            $this->setModelo(null);
1480
        }
1481
        if (!isset($nota['tipo'])) {
1482
            $this->setTipo(self::TIPO_SAIDA);
1483
        } else {
1484
            $this->setTipo($nota['tipo']);
1485
        }
1486
        if (!isset($nota['destino'])) {
1487
            $this->setDestino(self::DESTINO_INTERNA);
1488
        } else {
1489
            $this->setDestino($nota['destino']);
1490
        }
1491
        if (!isset($nota['natureza'])) {
1492
            $this->setNatureza('VENDA PARA CONSUMIDOR FINAL');
1493
        } else {
1494
            $this->setNatureza($nota['natureza']);
1495
        }
1496
        if (isset($nota['codigo'])) {
1497
            $this->setCodigo($nota['codigo']);
1498
        } else {
1499
            $this->setCodigo(null);
1500
        }
1501
        if (isset($nota['data_emissao'])) {
1502
            $this->setDataEmissao($nota['data_emissao']);
1503
        } else {
1504
            $this->setDataEmissao(null);
1505
        }
1506
        if (isset($nota['serie'])) {
1507
            $this->setSerie($nota['serie']);
1508
        } else {
1509
            $this->setSerie(null);
1510
        }
1511
        if (!isset($nota['formato'])) {
1512
            $this->setFormato(self::FORMATO_NENHUMA);
1513
        } else {
1514
            $this->setFormato($nota['formato']);
1515
        }
1516
        if (!isset($nota['emissao'])) {
1517
            $this->setEmissao(self::EMISSAO_NORMAL);
1518
        } else {
1519
            $this->setEmissao($nota['emissao']);
1520
        }
1521
        if (isset($nota['digito_verificador'])) {
1522
            $this->setDigitoVerificador($nota['digito_verificador']);
1523
        } else {
1524
            $this->setDigitoVerificador(null);
1525
        }
1526
        if (!isset($nota['ambiente'])) {
1527
            $this->setAmbiente(self::AMBIENTE_HOMOLOGACAO);
1528
        } else {
1529
            $this->setAmbiente($nota['ambiente']);
1530
        }
1531
        if (!isset($nota['finalidade'])) {
1532
            $this->setFinalidade(self::FINALIDADE_NORMAL);
1533
        } else {
1534
            $this->setFinalidade($nota['finalidade']);
1535
        }
1536
        if (!isset($nota['consumidor_final'])) {
1537
            $this->setConsumidorFinal('Y');
1538
        } else {
1539
            $this->setConsumidorFinal($nota['consumidor_final']);
1540
        }
1541
        if (isset($nota['presenca'])) {
1542
            $this->setPresenca($nota['presenca']);
1543
        } else {
1544
            $this->setPresenca(null);
1545
        }
1546
        if (isset($nota['intermediacao'])) {
1547
            $this->setIntermediacao($nota['intermediacao']);
1548
        } else {
1549
            $this->setIntermediacao(null);
1550
        }
1551
        $this->setTotal(new Total(isset($nota['total']) ? $nota['total'] : []));
1552
        if (!array_key_exists('adicionais', $nota)) {
1553
            $this->setAdicionais(null);
1554
        } else {
1555
            $this->setAdicionais($nota['adicionais']);
1556
        }
1557
        if (!array_key_exists('observacoes', $nota)) {
1558
            $this->setObservacoes(null);
1559
        } else {
1560
            $this->setObservacoes($nota['observacoes']);
1561
        }
1562
        if (!array_key_exists('informacoes', $nota)) {
1563
            $this->setInformacoes(null);
1564
        } else {
1565
            $this->setInformacoes($nota['informacoes']);
1566
        }
1567
        if (isset($nota['protocolo'])) {
1568
            $this->setProtocolo($nota['protocolo']);
1569
        } else {
1570
            $this->setProtocolo(null);
1571
        }
1572
        return $this;
1573
    }
1574
1575
    public function gerarID()
1576
    {
1577
        $estado = $this->getEmitente()->getEndereco()->getMunicipio()->getEstado();
1578
        $estado->checkCodigos();
1579
        $id = sprintf(
1580
            '%02d%02d%02d%s%02d%03d%09d%01d%08d',
1581
            $estado->getCodigo(),
1582
            date('y', $this->getDataEmissao()), // Ano 2 dígitos
1583
            date('m', $this->getDataEmissao()), // Mês 2 dígitos
1584
            $this->getEmitente()->getCNPJ(),
1585
            $this->getModelo(true),
1586
            $this->getSerie(),
1587
            $this->getNumero(),
1588
            $this->getEmissao(true),
1589
            $this->getCodigo()
1590
        );
1591
        return $id . Util::getDAC($id, 11);
1592
    }
1593
1594
    public function getTotais()
1595
    {
1596
        $total = [];
1597
        $total['produtos'] = 0.00;
1598
        $total['desconto'] = 0.00;
1599
        $total['frete'] = 0.00;
1600
        $total['seguro'] = 0.00;
1601
        $total['despesas'] = 0.00;
1602
        $total['tributos'] = 0.00;
1603
        $total['icms'] = 0.00;
1604
        $total['icms.st'] = 0.00;
1605
        $total['base'] = 0.00;
1606
        $total['base.st'] = 0.00;
1607
        $total['ii'] = 0.00;
1608
        $total['ipi'] = 0.00;
1609
        $total['pis'] = 0.00;
1610
        $total['cofins'] = 0.00;
1611
        $total['desoneracao'] = 0.00;
1612
        $total['fundo'] = 0.00;
1613
        $total['fundo.st'] = 0.00;
1614
        $total['fundo.retido.st'] = 0.00;
1615
        $total['ipi.devolvido'] = 0.00;
1616
        $_produtos = $this->getProdutos();
1617
        foreach ($_produtos as $_produto) {
1618
            if (!$_produto->getMultiplicador()) {
1619
                continue;
1620
            }
1621
            $imposto_info = $_produto->getImpostoInfo();
1622
            $total['produtos'] += round($_produto->getPreco(), 2);
1623
            $total['desconto'] += round($_produto->getDesconto(), 2);
1624
            $total['frete'] += round($_produto->getFrete(), 2);
1625
            $total['seguro'] += round($_produto->getSeguro(), 2);
1626
            $total['despesas'] += round($_produto->getDespesas(), 2);
1627
            $total['tributos'] += round($imposto_info['total'], 2);
1628
            $_impostos = $_produto->getImpostos();
1629
            foreach ($_impostos as $_imposto) {
1630
                switch ($_imposto->getGrupo()) {
1631
                    case Imposto::GRUPO_ICMS:
1632
                        if (($_imposto instanceof \NFe\Entity\Imposto\ICMS\Cobranca) ||
1633
                                ($_imposto instanceof \NFe\Entity\Imposto\ICMS\Simples\Cobranca)
1634
                        ) {
1635
                            $total[$_imposto->getGrupo()] += round($_imposto->getNormal()->getValor(), 2);
1636
                            $total['base'] += round($_imposto->getNormal()->getBase(), 2);
1637
                        }
1638
                        if (($_imposto instanceof \NFe\Entity\Imposto\ICMS\Parcial) ||
1639
                                ($_imposto instanceof \NFe\Entity\Imposto\ICMS\Simples\Parcial)
1640
                        ) {
1641
                            $total['icms.st'] += round($_imposto->getValor(), 2);
1642
                            $total['base.st'] += round($_imposto->getBase(), 2);
1643
                        } else {
1644
                            $total[$_imposto->getGrupo()] += round($_imposto->getValor(), 2);
1645
                            $total['base'] += round($_imposto->getBase(), 2);
1646
                        }
1647
                        $fundo = $_imposto->getFundo();
1648
                        // a ordem de comparação importa pois uma classe estende da outra
1649
                        if ($fundo instanceof \NFe\Entity\Imposto\Fundo\Retido) {
1650
                            $total['fundo.retido.st'] += round($fundo->getTotal(), 2);
1651
                        } elseif ($fundo instanceof \NFe\Entity\Imposto\Fundo\Substituido) {
1652
                            $total['fundo.st'] += round($fundo->getTotal(), 2);
1653
                        } elseif ($fundo instanceof \NFe\Entity\Imposto\Fundo\Base) {
1654
                            $total['fundo'] += round($fundo->getTotal(), 2);
1655
                        }
1656
                        break;
1657
                    default:
1658
                        $total[$_imposto->getGrupo()] += round($_imposto->getValor(), 2);
1659
                }
1660
            }
1661
        }
1662
        $produtos = round($total['produtos'], 2) - round($total['desconto'], 2);
1663
        $servicos = round($total['frete'], 2) + round($total['seguro'], 2) + round($total['despesas'], 2);
1664
        $impostos = round($total['ii'], 2) + round($total['ipi'], 2) + round($total['icms.st'], 2);
1665
        $impostos = $impostos - round($total['desoneracao'], 2);
1666
        $total['nota'] = $produtos + $servicos + $impostos;
1667
        return $total;
1668
    }
1669
1670
    private function getNodeTotal($name = null)
1671
    {
1672
        $dom = new \DOMDocument('1.0', 'UTF-8');
1673
        $element = $dom->createElement(is_null($name) ? 'total' : $name);
1674
1675
        // Totais referentes ao ICMS
1676
        $total = $this->getTotais();
1677
        $icms = $dom->createElement('ICMSTot');
1678
        Util::appendNode($icms, 'vBC', Util::toCurrency($total['base']));
1679
        Util::appendNode($icms, 'vICMS', Util::toCurrency($total['icms']));
1680
        Util::appendNode($icms, 'vICMSDeson', Util::toCurrency($total['desoneracao']));
1681
        Util::appendNode($icms, 'vFCP', Util::toCurrency($total['fundo']));
1682
        Util::appendNode($icms, 'vBCST', Util::toCurrency($total['base.st']));
1683
        Util::appendNode($icms, 'vST', Util::toCurrency($total['icms.st']));
1684
        Util::appendNode($icms, 'vFCPST', Util::toCurrency($total['fundo.st']));
1685
        Util::appendNode($icms, 'vFCPSTRet', Util::toCurrency($total['fundo.retido.st']));
1686
        Util::appendNode($icms, 'vProd', Util::toCurrency($total['produtos']));
1687
        Util::appendNode($icms, 'vFrete', Util::toCurrency($total['frete']));
1688
        Util::appendNode($icms, 'vSeg', Util::toCurrency($total['seguro']));
1689
        Util::appendNode($icms, 'vDesc', Util::toCurrency($total['desconto']));
1690
        Util::appendNode($icms, 'vII', Util::toCurrency($total['ii']));
1691
        Util::appendNode($icms, 'vIPI', Util::toCurrency($total['ipi']));
1692
        Util::appendNode($icms, 'vIPIDevol', Util::toCurrency($total['ipi.devolvido']));
1693
        Util::appendNode($icms, 'vPIS', Util::toCurrency($total['pis']));
1694
        Util::appendNode($icms, 'vCOFINS', Util::toCurrency($total['cofins']));
1695
        Util::appendNode($icms, 'vOutro', Util::toCurrency($total['despesas']));
1696
        Util::appendNode($icms, 'vNF', Util::toCurrency($total['nota']));
1697
        Util::appendNode($icms, 'vTotTrib', Util::toCurrency($total['tributos']));
1698
        $element->appendChild($icms);
1699
        $this->setTotal(new Total($total));
1700
        $this->getTotal()->setProdutos($total['produtos']);
1701
1702
        // TODO: Totais referentes ao ISSQN
1703
1704
        // TODO: Retenção de Tributos Federais
1705
        return $element;
1706
    }
1707
1708
    public function getNode($name = null)
1709
    {
1710
        $this->getEmitente()->getEndereco()->checkCodigos();
1711
        $this->setID($this->gerarID());
1712
        $this->setDigitoVerificador(substr($this->getID(), -1, 1));
1713
1714
        $dom = new \DOMDocument('1.0', 'UTF-8');
1715
        $element = $dom->createElement(is_null($name) ? 'NFe' : $name);
1716
        $element->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', self::PORTAL);
1717
1718
        $info = $dom->createElement('infNFe');
1719
        $id = $dom->createAttribute('Id');
1720
        $id->value = $this->getID(true);
1721
        $info->appendChild($id);
1722
        $versao = $dom->createAttribute('versao');
1723
        $versao->value = self::VERSAO;
1724
        $info->appendChild($versao);
1725
1726
        $municipio = $this->getEmitente()->getEndereco()->getMunicipio();
1727
        $estado = $municipio->getEstado();
1728
        $ident = $dom->createElement('ide');
1729
        Util::appendNode($ident, 'cUF', $estado->getCodigo(true));
1730
        Util::appendNode($ident, 'cNF', $this->getCodigo(true));
1731
        Util::appendNode($ident, 'natOp', $this->getNatureza(true));
1732
        Util::appendNode($ident, 'mod', $this->getModelo(true));
1733
        Util::appendNode($ident, 'serie', $this->getSerie(true));
1734
        Util::appendNode($ident, 'nNF', $this->getNumero(true));
1735
        Util::appendNode($ident, 'dhEmi', $this->getDataEmissao(true));
1736
        Util::appendNode($ident, 'tpNF', $this->getTipo(true));
1737
        Util::appendNode($ident, 'idDest', $this->getDestino(true));
1738
        Util::appendNode($ident, 'cMunFG', $municipio->getCodigo(true));
1739
        Util::appendNode($ident, 'tpImp', $this->getFormato(true));
1740
        Util::appendNode($ident, 'tpEmis', $this->getEmissao(true));
1741
        Util::appendNode($ident, 'cDV', $this->getDigitoVerificador(true));
1742
        Util::appendNode($ident, 'tpAmb', $this->getAmbiente(true));
1743
        Util::appendNode($ident, 'finNFe', $this->getFinalidade(true));
1744
        Util::appendNode($ident, 'indFinal', $this->getConsumidorFinal(true));
1745
        Util::appendNode($ident, 'indPres', $this->getPresenca(true));
1746
        if (!is_null($this->getIntermediacao())) {
1747
            Util::appendNode($element, 'indIntermed', $this->getIntermediacao(true));
1748
        }
1749
        Util::appendNode($ident, 'procEmi', 0); // emissão de NF-e com aplicativo do contribuinte
1750
        Util::appendNode($ident, 'verProc', self::APP_VERSAO);
1751
        if (!is_null($this->getDataMovimentacao())) {
1752
            Util::appendNode($ident, 'dhSaiEnt', $this->getDataMovimentacao(true));
1753
        }
1754
        if ($this->getEmissao() != self::EMISSAO_NORMAL) {
1755
            Util::appendNode($ident, 'dhCont', $this->getDataContingencia(true));
1756
            Util::appendNode($ident, 'xJust', $this->getJustificativa(true));
1757
        }
1758
        $info->appendChild($ident);
1759
1760
        $emitente = $this->getEmitente()->getNode();
1761
        $emitente = $dom->importNode($emitente, true);
1762
        $info->appendChild($emitente);
1763
        if ($this->getAmbiente() == self::AMBIENTE_HOMOLOGACAO && !is_null($this->getDestinatario())) {
1764
            $this->getDestinatario()->setNome('NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL');
1765
        }
1766
        if (!is_null($this->getDestinatario())) {
1767
            $destinatario = $this->getDestinatario()->getNode();
1768
            $destinatario = $dom->importNode($destinatario, true);
1769
            $info->appendChild($destinatario);
1770
        }
1771
        $item = 0;
1772
        $tributos = [];
1773
        $_produtos = $this->getProdutos();
1774
        foreach ($_produtos as $_produto) {
1775
            if (is_null($_produto->getItem())) {
1776
                $item += 1;
1777
                $_produto->setItem($item);
1778
            } else {
1779
                $item = $_produto->getItem();
1780
            }
1781
            if ($this->getAmbiente() == self::AMBIENTE_HOMOLOGACAO) {
1782
                $_produto->setDescricao('NOTA FISCAL EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL');
1783
            }
1784
            $produto = $_produto->getNode();
1785
            $produto = $dom->importNode($produto, true);
1786
            $info->appendChild($produto);
1787
            // Soma os tributos aproximados dos produtos
1788
            $imposto_info = $_produto->getImpostoInfo();
1789
            $tributos['info'] = $imposto_info['info'];
1790
            foreach ($imposto_info as $key => $value) {
1791
                if (!is_numeric($value)) {
1792
                    continue;
1793
                }
1794
                if (!isset($tributos[$key])) {
1795
                    $tributos[$key] = 0.00;
1796
                }
1797
                $tributos[$key] += $value;
1798
            }
1799
        }
1800
        $total = $this->getNodeTotal();
1801
        $total = $dom->importNode($total, true);
1802
        $info->appendChild($total);
1803
        $transporte = $this->getTransporte()->getNode();
1804
        $transporte = $dom->importNode($transporte, true);
1805
        $info->appendChild($transporte);
1806
        // TODO: adicionar cobrança
1807
        $pag = $dom->createElement('pag');
1808
        $_pagamentos = $this->getPagamentos();
1809
        foreach ($_pagamentos as $_pagamento) {
1810
            $pagamento = $_pagamento->getNode();
1811
            $pagamento = $dom->importNode($pagamento, true);
1812
            $pag->appendChild($pagamento);
1813
        }
1814
        $info->appendChild($pag);
1815
        $info_adic = $dom->createElement('infAdic');
1816
        if (!is_null($this->getAdicionais())) {
1817
            Util::appendNode($info_adic, 'infAdFisco', $this->getAdicionais(true));
1818
        }
1819
        if (!is_null($this->getIntermediador())) {
1820
            $intermediador = $this->getIntermediador()->getNode();
1821
            $intermediador = $dom->importNode($intermediador, true);
1822
            $element->appendChild($intermediador);
1823
        }
1824
        // TODO: adicionar informações adicionais somente na NFC-e?
1825
        $_complemento = Produto::addNodeInformacoes($tributos, $info_adic, 'infCpl');
1826
        $this->getTotal()->setComplemento($_complemento);
1827
        if (!is_null($this->getObservacoes())) {
1828
            $_observacoes = $this->getObservacoes();
1829
            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...
1830
                $observacoes = $dom->createElement('obsCont');
1831
                Util::addAttribute($observacoes, 'xCampo', $_observacao['campo']);
1832
                Util::appendNode($observacoes, 'xTexto', $_observacao['valor']);
1833
                $info_adic->appendChild($observacoes);
1834
            }
1835
        }
1836
        if (!is_null($this->getInformacoes())) {
1837
            $_informacoes = $this->getInformacoes();
1838
            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...
1839
                $informacoes = $dom->createElement('obsFisco');
1840
                Util::addAttribute($informacoes, 'xCampo', $_informacao['campo']);
1841
                Util::appendNode($informacoes, 'xTexto', $_informacao['valor']);
1842
                $info_adic->appendChild($informacoes);
1843
            }
1844
        }
1845
        $info->appendChild($info_adic);
1846
        // TODO: adicionar exportação
1847
        // TODO: adicionar compra
1848
        // TODO: adicionar cana
1849
        if (!is_null($this->getResponsavel())) {
1850
            $responsavel = $this->getResponsavel()->getNode();
1851
            $responsavel = $dom->importNode($responsavel, true);
1852
            $info->appendChild($responsavel);
1853
        }
1854
        $element->appendChild($info);
1855
        $dom->appendChild($element);
1856
        return $element;
1857
    }
1858
1859
    public function loadNode($element, $name = null)
1860
    {
1861
        if (is_null($element)) {
1862
            throw new \Exception("Nota com XML mal formado ou vazio", 500);
1863
        }
1864
        $root = $element;
1865
        $name = is_null($name) ? 'NFe' : $name;
1866
        if ($element->nodeName != $name) {
1867
            $_fields = $element->getElementsByTagName($name);
1868
            if ($_fields->length == 0) {
1869
                throw new \Exception('Tag "' . $name . '" não encontrada', 404);
1870
            }
1871
            $element = $_fields->item(0);
1872
        }
1873
        $_fields = $element->getElementsByTagName('infNFe');
1874
        if ($_fields->length > 0) {
1875
            $info = $_fields->item(0);
1876
        } else {
1877
            throw new \Exception('Tag "infNFe" não encontrada', 404);
1878
        }
1879
        $id = $info->getAttribute('Id');
1880
        if (strlen($id) != 47) {
1881
            throw new \Exception('Atributo "Id" inválido, encontrado: "' . $id . '"', 500);
1882
        }
1883
        $this->setID(substr($id, 3));
1884
        $_fields = $info->getElementsByTagName('ide');
1885
        if ($_fields->length > 0) {
1886
            $ident = $_fields->item(0);
1887
        } else {
1888
            throw new \Exception('Tag "ide" não encontrada', 404);
1889
        }
1890
        $emitente = new Emitente();
1891
        $emitente->getEndereco()->getMunicipio()->getEstado()->setCodigo(
1892
            Util::loadNode(
1893
                $ident,
1894
                'cUF',
1895
                'Tag "cUF" do campo "Codigo IBGE da UF" não encontrada'
1896
            )
1897
        );
1898
        $this->setCodigo(
1899
            Util::loadNode(
1900
                $ident,
1901
                'cNF',
1902
                'Tag "cNF" do campo "Codigo" não encontrada'
1903
            )
1904
        );
1905
        $this->setNatureza(
1906
            Util::loadNode(
1907
                $ident,
1908
                'natOp',
1909
                'Tag "natOp" do campo "Natureza" não encontrada'
1910
            )
1911
        );
1912
        $this->setModelo(
1913
            Util::loadNode(
1914
                $ident,
1915
                'mod',
1916
                'Tag "mod" do campo "Modelo" não encontrada'
1917
            )
1918
        );
1919
        $this->setSerie(
1920
            Util::loadNode(
1921
                $ident,
1922
                'serie',
1923
                'Tag "serie" do campo "Serie" não encontrada'
1924
            )
1925
        );
1926
        $this->setNumero(
1927
            Util::loadNode(
1928
                $ident,
1929
                'nNF',
1930
                'Tag "nNF" do campo "Numero" não encontrada'
1931
            )
1932
        );
1933
        $this->setDataEmissao(
1934
            Util::loadNode(
1935
                $ident,
1936
                'dhEmi',
1937
                'Tag "dhEmi" do campo "DataEmissao" não encontrada'
1938
            )
1939
        );
1940
        $this->setTipo(
1941
            Util::loadNode(
1942
                $ident,
1943
                'tpNF',
1944
                'Tag "tpNF" do campo "Tipo" não encontrada'
1945
            )
1946
        );
1947
        $this->setDestino(
1948
            Util::loadNode(
1949
                $ident,
1950
                'idDest',
1951
                'Tag "idDest" do campo "Destino" não encontrada'
1952
            )
1953
        );
1954
        $emitente->getEndereco()->getMunicipio()->setCodigo(
1955
            Util::loadNode(
1956
                $ident,
1957
                'cMunFG',
1958
                'Tag "cMunFG" do campo "Codigo IBGE do município" não encontrada'
1959
            )
1960
        );
1961
        $this->setDataMovimentacao(Util::loadNode($ident, 'dhSaiEnt'));
1962
        $this->setFormato(
1963
            Util::loadNode(
1964
                $ident,
1965
                'tpImp',
1966
                'Tag "tpImp" do campo "Formato" não encontrada'
1967
            )
1968
        );
1969
        $this->setEmissao(
1970
            Util::loadNode(
1971
                $ident,
1972
                'tpEmis',
1973
                'Tag "tpEmis" do campo "Emissao" não encontrada'
1974
            )
1975
        );
1976
        $this->setDigitoVerificador(
1977
            Util::loadNode(
1978
                $ident,
1979
                'cDV',
1980
                'Tag "cDV" do campo "DigitoVerificador" não encontrada'
1981
            )
1982
        );
1983
        $this->setAmbiente(
1984
            Util::loadNode(
1985
                $ident,
1986
                'tpAmb',
1987
                'Tag "tpAmb" do campo "Ambiente" não encontrada'
1988
            )
1989
        );
1990
        $this->setFinalidade(
1991
            Util::loadNode(
1992
                $ident,
1993
                'finNFe',
1994
                'Tag "finNFe" do campo "Finalidade" não encontrada'
1995
            )
1996
        );
1997
        $this->setConsumidorFinal(
1998
            Util::loadNode(
1999
                $ident,
2000
                'indFinal',
2001
                'Tag "indFinal" do campo "ConsumidorFinal" não encontrada'
2002
            )
2003
        );
2004
        $this->setPresenca(
2005
            Util::loadNode(
2006
                $ident,
2007
                'indPres',
2008
                'Tag "indPres" do campo "Presenca" não encontrada'
2009
            )
2010
        );
2011
        $this->setIntermediacao(Util::loadNode($ident, 'indIntermed'));
2012
        $this->setDataContingencia(Util::loadNode($ident, 'dhCont'));
2013
        $this->setJustificativa(Util::loadNode($ident, 'xJust'));
2014
        $emitente->loadNode(
2015
            Util::findNode(
2016
                $info,
2017
                'emit',
2018
                'Tag "emit" do objeto "Emitente" não encontrada'
2019
            ),
2020
            'emit'
2021
        );
2022
        $this->setEmitente($emitente);
2023
        $_fields = $info->getElementsByTagName('dest');
2024
        $destinatario = null;
2025
        if ($_fields->length > 0) {
2026
            $destinatario = new Destinatario();
2027
            $destinatario->loadNode($_fields->item(0), 'dest');
2028
        }
2029
        $this->setDestinatario($destinatario);
0 ignored issues
show
Bug introduced by
It seems like $destinatario defined by null on line 2024 can be null; however, NFe\Core\Nota::setDestinatario() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
2030
        $_fields = $info->getElementsByTagName('infRespTec');
2031
        $responsavel = null;
2032
        if ($_fields->length > 0) {
2033
            $responsavel = new Responsavel();
2034
            $responsavel->loadNode($_fields->item(0), 'infRespTec');
2035
        }
2036
        $this->setResponsavel($responsavel);
0 ignored issues
show
Bug introduced by
It seems like $responsavel defined by null on line 2031 can be null; however, NFe\Core\Nota::setResponsavel() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
2037
        $produtos = [];
2038
        $_items = $info->getElementsByTagName('det');
2039
        foreach ($_items as $_item) {
2040
            $produto = new Produto();
2041
            $produto->loadNode($_item, 'det');
2042
            $produtos[] = $produto;
2043
        }
2044
        $this->setProdutos($produtos);
2045
        $_fields = $info->getElementsByTagName('infIntermed');
2046
        $intermediador = null;
2047
        if ($_fields->length > 0) {
2048
            $intermediador = new Intermediador();
2049
            $intermediador->loadNode($_fields->item(0), 'infIntermed');
2050
        }
2051
        $this->setIntermediador($intermediador);
0 ignored issues
show
Bug introduced by
It seems like $intermediador defined by null on line 2046 can be null; however, NFe\Core\Nota::setIntermediador() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
2052
        $_fields = $info->getElementsByTagName('transp');
2053
        $transporte = null;
2054
        if ($_fields->length > 0) {
2055
            $transporte = new Transporte();
2056
            $transporte->loadNode($_fields->item(0), 'transp');
2057
        }
2058
        $this->setTransporte($transporte);
2059
        $pagamentos = [];
2060
        $_items = $info->getElementsByTagName('pag');
2061
        foreach ($_items as $_item) {
2062
            $_det_items = $_item->getElementsByTagName('detPag');
2063
            foreach ($_det_items as $_det_item) {
2064
                $pagamento = new Pagamento();
2065
                $pagamento->loadNode($_det_item, 'detPag');
2066
                $pagamentos[] = $pagamento;
2067
            }
2068
            if (Util::nodeExists($_item, 'vTroco')) {
2069
                $pagamento = new Pagamento();
2070
                $pagamento->loadNode($_item, 'vTroco');
2071
                if ($pagamento->getValor() < 0) {
2072
                    $pagamentos[] = $pagamento;
2073
                }
2074
            }
2075
        }
2076
        $this->setPagamentos($pagamentos);
2077
        $_fields = $info->getElementsByTagName('total');
2078
        if ($_fields->length > 0) {
2079
            $total = new Total();
2080
            $total->loadNode($_fields->item(0), 'total');
2081
            $total->setComplemento(Util::loadNode($info, 'infCpl'));
2082
        } else {
2083
            throw new \Exception('Tag "total" do objeto "Total" não encontrada na Nota', 404);
2084
        }
2085
        $this->setTotal($total);
2086
        $this->setAdicionais(Util::loadNode($info, 'infAdFisco'));
2087
        $observacoes = [];
2088
        $_items = $info->getElementsByTagName('obsCont');
2089
        foreach ($_items as $_item) {
2090
            $observacao = [
2091
                'campo' => $_item->getAttribute('xCampo'),
2092
                'valor' => Util::loadNode(
2093
                    $_item,
2094
                    'xTexto',
2095
                    'Tag "xTexto" do campo "Observação" não encontrada'
2096
                )
2097
            ];
2098
            $observacoes[] = $observacao;
2099
        }
2100
        $this->setObservacoes($observacoes);
2101
        $informacoes = [];
2102
        $_items = $info->getElementsByTagName('obsFisco');
2103
        foreach ($_items as $_item) {
2104
            $informacao = [
2105
                'campo' => $_item->getAttribute('xCampo'),
2106
                'valor' => Util::loadNode(
2107
                    $_item,
2108
                    'xTexto',
2109
                    'Tag "xTexto" do campo "Informação" não encontrada'
2110
                )
2111
            ];
2112
            $informacoes[] = $informacao;
2113
        }
2114
        $this->setInformacoes($informacoes);
2115
2116
        $_fields = $root->getElementsByTagName('protNFe');
2117
        $protocolo = null;
2118
        if ($_fields->length > 0) {
2119
            $protocolo = new Protocolo();
2120
            $protocolo->loadNode($_fields->item(0), 'infProt');
2121
        }
2122
        $this->setProtocolo($protocolo);
2123
        return $element;
2124
    }
2125
2126
    /**
2127
     * Carrega um arquivo XML e preenche a nota com as informações dele
2128
     * @param  string $filename caminho do arquivo
2129
     * @return DOMDocument      objeto do documento carregado
2130
     */
2131
    public function load($filename)
2132
    {
2133
        $dom = new \DOMDocument();
2134
        if (!file_exists($filename)) {
2135
            throw new \Exception('Arquivo XML "' . $filename . '" não encontrado', 404);
2136
        }
2137
        $dom->load($filename);
2138
        $this->loadNode($dom->documentElement);
2139
        return $dom;
2140
    }
2141
2142
    /**
2143
     * Assina o XML com a assinatura eletrônica do tipo A1
2144
     */
2145
    public function assinar($dom = null)
2146
    {
2147
        if (is_null($dom)) {
2148
            $xml = $this->getNode();
2149
            $dom = $xml->ownerDocument;
2150
        }
2151
        $config = SEFAZ::getInstance()->getConfiguracao();
2152
        $config->verificaValidadeCertificado();
2153
2154
        $adapter = new XmlseclibsAdapter();
2155
        $adapter->setPrivateKey($config->getChavePrivada());
0 ignored issues
show
Deprecated Code introduced by
The method NFe\Common\Configuracao::getChavePrivada() has been deprecated with message: Use getCertificado()->getChavePrivada

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
2156
        $adapter->setPublicKey($config->getChavePublica());
0 ignored issues
show
Deprecated Code introduced by
The method NFe\Common\Configuracao::getChavePublica() has been deprecated with message: Use getCertificado()->getChavePublica

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
2157
        $adapter->addTransform(AdapterInterface::ENVELOPED);
2158
        $adapter->addTransform(AdapterInterface::XML_C14N);
2159
        $adapter->sign($dom, 'infNFe');
2160
        return $dom;
2161
    }
2162
2163
    /**
2164
     * Valida o documento após assinar
2165
     */
2166
    public function validar($dom)
2167
    {
2168
        $dom->loadXML($dom->saveXML());
2169
        $xsd_path = __DIR__ . '/schema';
2170
        if (is_null($this->getProtocolo())) {
2171
            $xsd_file = $xsd_path . '/nfe_v' . self::VERSAO . '.xsd';
2172
        } else {
2173
            $xsd_file = $xsd_path . '/procNFe_v' . self::VERSAO . '.xsd';
2174
        }
2175
        if (!file_exists($xsd_file)) {
2176
            throw new \Exception(sprintf('O arquivo "%s" de esquema XSD não existe!', $xsd_file), 404);
2177
        }
2178
        // Enable user error handling
2179
        $save = libxml_use_internal_errors(true);
2180
        if ($dom->schemaValidate($xsd_file)) {
2181
            libxml_use_internal_errors($save);
2182
            return $dom;
2183
        }
2184
        $msg = [];
2185
        $errors = libxml_get_errors();
2186
        foreach ($errors as $error) {
2187
            $msg[] = 'Não foi possível validar o XML: ' . $error->message;
2188
        }
2189
        libxml_clear_errors();
2190
        libxml_use_internal_errors($save);
2191
        throw new ValidationException($msg);
2192
    }
2193
2194
    /**
2195
     * Adiciona o protocolo no XML da nota
2196
     */
2197
    public function addProtocolo($dom)
2198
    {
2199
        if (is_null($this->getProtocolo())) {
2200
            throw new \Exception('O protocolo não foi informado na nota "' . $this->getID() . '"', 404);
2201
        }
2202
        $notae = $dom->getElementsByTagName('NFe')->item(0);
2203
        // Corrige xmlns:default
2204
        $notae_xml = $dom->saveXML($notae);
2205
2206
        $element = $dom->createElement('nfeProc');
2207
        $element->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', self::PORTAL);
2208
        $versao = $dom->createAttribute('versao');
2209
        $versao->value = self::VERSAO;
2210
        $element->appendChild($versao);
2211
        $dom->removeChild($notae);
2212
        // Corrige xmlns:default
2213
        $notae = $dom->createElement('NFe', 0);
2214
2215
        $element->appendChild($notae);
2216
        $info = $this->getProtocolo()->getNode();
2217
        $info = $dom->importNode($info, true);
2218
        $element->appendChild($info);
2219
        $dom->appendChild($element);
2220
        // Corrige xmlns:default
2221
        $xml = $dom->saveXML();
2222
        $xml = str_replace('<NFe>0</NFe>', $notae_xml, $xml);
2223
        $dom->loadXML($xml);
2224
2225
        return $dom;
2226
    }
2227
}
2228