Completed
Push — master ( fa85ab...eba127 )
by Roberto
113:14 queued 45:27
created

Base::setAddresses()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 0
cts 11
cp 0
rs 9.9
c 0
b 0
f 0
cc 4
nc 3
nop 2
crap 20
1
<?php
2
3
namespace NFePHP\Mail;
4
5
class Base
6
{
7
    /**
8
     * Html Templates
9
     * @var array
10
     */
11
    protected $templates = [
12
        'NFe'=> "<p><b>Prezados {destinatario},</b></p>" .
13
                "<p>Você está recebendo a Nota Fiscal Eletrônica emitida em {data} com o número " .
14
                "{numero}, de {emitente}, no valor de R$ {valor}. " .
15
                "Junto com a mercadoria, você receberá também um DANFE (Documento " .
16
                "Auxiliar da Nota Fiscal Eletrônica), que acompanha o trânsito das mercadorias.</p>" .
17
                "<p><i>Podemos conceituar a Nota Fiscal Eletrônica como um documento " .
18
                "de existência apenas digital, emitido e armazenado eletronicamente, " .
19
                "com o intuito de documentar, para fins fiscais, uma operação de " .
20
                "circulação de mercadorias, ocorrida entre as partes. Sua validade " .
21
                "jurídica garantida pela assinatura digital do remetente (garantia " .
22
                "de autoria e de integridade) e recepção, pelo Fisco, do documento " .
23
                "eletrônico, antes da ocorrência do Fato Gerador.</i></p>" .
24
                "<p><i>Os registros fiscais e contábeis devem ser feitos, a partir " .
25
                "do próprio arquivo da NF-e, anexo neste e-mail, ou utilizando o " .
26
                "DANFE, que representa graficamente a Nota Fiscal Eletrônica. " .
27
                "A validade e autenticidade deste documento eletrônico pode ser " .
28
                "verificada no site nacional do projeto (www.nfe.fazenda.gov.br), " .
29
                "através da chave de acesso contida no DANFE.</i></p>" .
30
                "<p><i>Para poder utilizar os dados descritos do DANFE na " .
31
                "escrituração da NF-e, tanto o contribuinte destinatário, " .
32
                "como o contribuinte emitente, terão de verificar a validade da NF-e. " .
33
                "Esta validade está vinculada à efetiva existência da NF-e nos " .
34
                "arquivos da SEFAZ, e comprovada através da emissão da Autorização de Uso.</i></p>" .
35
                "<p><b>O DANFE não é uma nota fiscal, nem substitui uma nota fiscal, " .
36
                "servindo apenas como instrumento auxiliar para consulta da NF-e no " .
37
                "Ambiente Nacional.</b></p>" .
38
                "<p>Para mais detalhes, consulte: <a href=\"http://www.nfe.fazenda.gov.br/\">" .
39
                "www.nfe.fazenda.gov.br</a></p>" .
40
                "<br>" .
41
                "<p>Atenciosamente,</p>" .
42
                "<p>{emitente}</p>",
43
        
44
        'CTe'=> "<p><b>Prezados {destinatario},</b></p>" .
45
                "<p>Você está recebendo um Conhecimento de Transporte Eletrônico emitido em {data} com o número " .
46
                "{numero}, de {emitente}, no valor de R$ {valor}. " .
47
                "Junto com a mercadoria, você receberá também um DACTE (Documento " .
48
                "Auxiliar do Conhecimento de Transporte Eletrônico), que acompanha o trânsito das mercadorias.</p>" .
49
                "<p><i>Podemos conceituar o CTe como um documento " .
50
                "de existência apenas digital, emitido e armazenado eletronicamente, " .
51
                "com o intuito de documentar, para fins fiscais, uma operação de " .
52
                "circulação de mercadorias, ocorrida entre as partes. Sua validade " .
53
                "jurídica garantida pela assinatura digital do remetente (garantia " .
54
                "de autoria e de integridade) e recepção, pelo Fisco, do documento " .
55
                "eletrônico, antes da ocorrência do Fato Gerador.</i></p>" .
56
                "<p><i>Os registros fiscais e contábeis devem ser feitos, a partir " .
57
                "do próprio arquivo da NF-e, anexo neste e-mail, ou utilizando o " .
58
                "DACTE, que representa graficamente o Conhecimento de Transporte Eletrônico. " .
59
                "A validade e autenticidade deste documento eletrônico pode ser " .
60
                "verificada no site nacional do projeto (www.cte.fazenda.gov.br), " .
61
                "através da chave de acesso contida no DACTE.</i></p>" .
62
                "<p><i>Para poder utilizar os dados descritos do DACTE na " .
63
                "escrituração do CT-e, tanto o contribuinte destinatário, " .
64
                "como o contribuinte emitente, terão de verificar a validade do CT-e. " .
65
                "Esta validade está vinculada à efetiva existência do CT-e nos " .
66
                "arquivos da SEFAZ, e comprovada através da emissão da Autorização de Uso.</i></p>" .
67
                "<p><b>O DACTE não é um Conhecimento de transporte, nem o substitui, " .
68
                "servindo apenas como instrumento auxiliar para consulta do CT-e no " .
69
                "Ambiente Nacional.</b></p>" .
70
                "<p>Para mais detalhes, consulte: <a href=\"http://www.cte.fazenda.gov.br/\">" .
71
                "www.cte.fazenda.gov.br</a></p>" .
72
                "<br>" .
73
                "<p>Atenciosamente,</p>" .
74
                "<p>{emitente}</p>",
75
                
76
        'CCe'=> "<p><b>Prezados,</b></p>" .
77
                "<p>Você está recebendo uma Carta de Correção referente ao nosso documento " .
78
                "{chave}.</p><p>Essa carta de correção datada de {data} procura corrigir:</p> " .
79
                "<p><b>{correcao}</b></p>" .
80
                "<p><i>{conduso}</i></p>" .
81
                "<p>Atenciosamente,</p>" .
82
                "<p>{emitente}</p>"
83
    ];
84
    
85
    /**
86
     * template user-defined
87
     * @var string
88
     */
89
    public $template;
90
    /**
91
     * Type from xml document NFe, CTe or CCe
92
     * @var string
93
     */
94
    protected $type;
95
    /**
96
     * Addresses to send mail
97
     * This array should be repeated fields removed
98
     * @var array
99
     */
100
    protected $addresses = [];
101
    /**
102
     * Fields from xml
103
     * @var \stdClass
104
     */
105
    public $fields;
106
    /**
107
     * PHPMailer class
108
     * @var \PHPMailer
109
     */
110
    protected $mail;
111
    /**
112
     * Xml content
113
     * @var string
114
     */
115
    public $xml;
116
    /**
117
     * PDF content
118
     * @var string
119
     */
120
    public $pdf;
121
    /**
122
     * config
123
     * @var \stdClass
124
     */
125
    protected $config;
126
    
127
    
128
    /**
129
     * Search xml for data
130
     * @param string $xml
131
     * @throws \InvalidArgumentException
132
     */
133
    protected function getXmlData($xml)
134
    {
135
        $dom = new \DOMDocument('1.0', 'UTF-8');
136
        $dom->preserveWhiteSpace = false;
137
        $dom->loadXML($xml);
138
        $root = $dom->documentElement;
139
        $name = $root->tagName;
140
        $dest = $dom->getElementsByTagName('dest')->item(0);
141
        $ide = $dom->getElementsByTagName('ide')->item(0);
142
        switch ($name) {
143
            case 'nfeProc':
144
            case 'NFe':
145
                $type = 'NFe';
146
                $infNFe = $dom->getElementsByTagName('infNFe')->item(0);
147
                $this->fields->id = substr($infNFe->getAttribute('Id'), 3) . '-' . strtolower($name);
148
                $this->fields->numero = $ide->getElementsByTagName('nNF')->item(0)->nodeValue;
149
                $this->fields->valor = $dom->getElementsByTagName('vNF')->item(0)->nodeValue;
150
                $this->fields->data = $ide->getElementsByTagName('dhEmi')->item(0)->nodeValue;
151
                $this->subject = "NFe n. " . $this->fields->numero . " - " . $this->config->fantasy;
0 ignored issues
show
Bug introduced by
The property subject does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
152
                break;
153
            case 'cteProc':
154
            case 'CTe':
155
                $type = 'CTe';
156
                $infCte = $dom->getElementsByTagName('infCte')->item(0);
0 ignored issues
show
Unused Code introduced by
$infCte is not used, you could remove the assignment.

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

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

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

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

Loading history...
157
                $this->fields->id = substr($infNFe->getAttribute('Id'), 3) . '-' . strtolower($name);
0 ignored issues
show
Bug introduced by
The variable $infNFe seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
158
                $this->fields->numero = $ide->getElementsByTagName('nCT')->item(0)->nodeValue;
159
                $this->fields->valor = $dom->getElementsByTagName('vRec')->item(0)->nodeValue;
160
                $this->fields->data = $ide->getElementsByTagName('dhEmi')->item(0)->nodeValue;
161
                $this->subject = "CTe n. " . $this->fields->numero . " - " . $this->config->fantasy;
162
                break;
163
            case 'procEventoNFe':
164
            case 'procEventoCTe':
165
                $type = 'CCe';
166
                $this->fields->chave = $dom->getElementsByTagName('chNFe')->item(0)->nodeValue;
167
                $this->fields->id = $this->fields->chave.'-procCCe-'.strtolower(substr($name, -3));
168
                $this->fields->data = $dom->getElementsByTagName('dhEvento')->item(0)->nodeValue;
169
                $this->fields->correcao = $dom->getElementsByTagName('xCorrecao')->item(0)->nodeValue;
170
                $this->fields->conduso = $dom->getElementsByTagName('xCondUso')->item(0)->nodeValue;
171
                if (empty($this->fields->chave)) {
172
                    $this->fields->chave = $dom->getElementsByTagName('chCTe')->item(0)->nodeValue;
173
                }
174
                $this->subject = "Carta de Correção " . $this->config->fantasy;
175
                break;
176
            default:
177
                $type = '';
178
        }
179
        //get email adresses from xml, if exists
180
        //may have one address in <dest><email>
181
        if (!empty($dest)) {
182
            $this->fields->destinatario = $dest->getElementsByTagName('xNome')->item(0)->nodeValue;
183
            $email = !empty($dest->getElementsByTagName('email')->item(0)->nodeValue) ?
184
                $dest->getElementsByTagName('email')->item(0)->nodeValue : '';
185
        }
186
        if (!empty($email)) {
187
            // if recieve more than one e-mail address.
188
            if (strpos($email, ';')) {
189
                $emails = explode(';', $email);
190
191
                $emails = array_map(function ($item) {
192
                    return trim($item);
193
                }, $emails);
194
195
                $this->addresses = array_merge($this->addresses, $emails);
196
            } else {
197
                $this->addresses[] = $email;
198
            }
199
        }
200
        //may have others in <obsCont xCampo="email"><xTexto>[email protected]</xTexto>
201
        $obs = $dom->getElementsByTagName('obsCont');
202
        foreach ($obs as $ob) {
203
            if (strtoupper($ob->getAttribute('xCampo')) === 'EMAIL') {
204
                $this->addresses[] = $ob->getElementsByTagName('xTexto')->item(0)->nodeValue;
205
            }
206
        }
207
        //xml may be a NFe or a CTe or a CCe nothing else
208
        if ($type != 'NFe' && $type != 'CTe' && $type != 'CCe') {
209
            $msg = "Você deve passar apenas uma NFe ou um CTe ou um CCe. "
210
                    . "Esse documento não foi reconhecido.";
211
            throw new \InvalidArgumentException($msg);
212
        }
213
        $this->type = $type;
214
    }
215
    
216
    /**
217
     * Set all addresses including those that exists in the xml document
218
     * Send email only to listed addresses ignoring all email addresses in xml
219
     * @param array $addresses
220
     * @param bool $include
221
     */
222
    protected function setAddresses(array $addresses = [], $include = true)
223
    {
224
        if (!empty($addresses)) {
225
            if (!empty($this->addresses) && $include) {
226
                $this->addresses = array_merge($this->addresses, $addresses);
227
            } else {
228
                $this->addresses = $addresses;
229
            }
230
        }
231
        $this->removeInvalidAdresses();
232
    }
233
234
    /**
235
     * Render a template with valid data
236
     * @param string $template
237
     * @param string $destinatario
238
     * @param string $data
239
     * @param string $numero
240
     * @param string $valor
241
     * @param string $chave
242
     * @param string $correcao
243
     * @param string $conduso
244
     * @return string
245
     */
246
    protected function renderTemplate(
247
        $template,
248
        $destinatario = '',
249
        $data = '',
250
        $numero = '',
251
        $valor = 0,
252
        $chave = '',
253
        $correcao = '',
254
        $conduso = ''
255
    ) {
256
        $dt = new \DateTime(str_replace('T', ' ', $data));
257
        $search = array(
258
            '{destinatario}',
259
            '{data}',
260
            '{numero}',
261
            '{valor}',
262
            '{emitente}',
263
            '{chave}',
264
            '{correcao}',
265
            '{conduso}'
266
        );
267
        $replace = array(
268
            $destinatario,
269
            $dt->format('d/m/Y'),
270
            $numero,
271
            number_format($valor, 2, ',', '.'),
272
            $this->config->fantasy,
273
            $chave,
274
            $correcao,
275
            $conduso
276
        );
277
        $template = str_replace($search, $replace, $template);
278
        return $template;
279
    }
280
    
281
    /**
282
     * Remove all invalid addresses
283
     */
284
    protected function removeInvalidAdresses()
285
    {
286
        //This resulted array should be repeated fields removed
287
        //and all not valid strings, and also trim and strtolower strings
288
        $this->addresses = array_unique($this->addresses);
289
        $this->addresses = array_map(array($this, 'clearAddressString'), $this->addresses);
290
        $this->addresses = array_filter($this->addresses, array($this, 'checkEmailAddress'));
291
    }
292
    
293
    /**
294
     * Build Message
295
     * @return string
296
     */
297
    protected function render()
298
    {
299
        //depending on the document a different template should be loaded
300
        //and having data patterns appropriately substituted
301
        $template = $this->templates[$this->type];
302
        if (!empty($this->template)) {
303
            $template = $this->template;
304
        }
305
        return $this->renderTemplate(
306
            $template,
307
            $this->fields->destinatario,
308
            $this->fields->data,
309
            $this->fields->numero,
310
            $this->fields->valor,
311
            $this->fields->chave,
312
            $this->fields->correcao,
313
            $this->fields->conduso
314
        );
315
    }
316
    
317
    /**
318
     * Attach all documents to message
319
     */
320
    protected function attach()
321
    {
322
        $this->mail->addStringAttachment(
323
            $this->xml,
324
            $this->fields->id . '.xml'
325
        );
326
        if (!empty($this->pdf)) {
327
            $this->mail->addStringAttachment(
328
                $this->pdf,
329
                $this->fields->id. '.pdf',
330
                'base64',
331
                'application/pdf'
332
            );
333
        }
334
    }
335
    
336
    /**
337
     * Returns only valid email string
338
     * @param string $email
339
     * @return boolean
340
     */
341
    protected function checkEmailAddress($email)
342
    {
343
        return filter_var($email, FILTER_VALIDATE_EMAIL);
344
    }
345
    
346
    /**
347
     * Format email address string removing garbage and
348
     * set to lower characters
349
     * @param string $email
350
     * @return string
351
     */
352
    protected function clearAddressString($email)
353
    {
354
        return preg_replace('/[ ,;:]+/', '', strtolower($email));
355
    }
356
}
357