Completed
Push — master ( 8695ae...9675a7 )
by Esteban De La Fuente
01:49
created

EnvioDte   F

Complexity

Total Complexity 65

Size/Duplication

Total Lines 410
Duplicated Lines 3.41 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
wmc 65
lcom 1
cbo 6
dl 14
loc 410
rs 3.2
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A agregar() 7 21 4
A setCaratula() 7 34 4
A enviar() 0 9 2
B generar() 0 41 5
A getSubTotDTE() 0 17 4
B loadXML() 0 33 7
A getCaratula() 0 4 2
A getID() 0 4 2
A getDigest() 0 4 2
A getEmisor() 0 5 2
A getReceptor() 0 5 2
A getFechaEmisionInicial() 0 9 3
A getFechaEmisionFinal() 0 9 3
A getDocumentos() 0 21 5
B getDocumento() 0 25 7
A esBoleta() 0 4 2
A getEstadoValidacion() 0 13 5
A checkFirma() 0 17 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EnvioDte 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 EnvioDte, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * LibreDTE
5
 * Copyright (C) SASCO SpA (https://sasco.cl)
6
 *
7
 * Este programa es software libre: usted puede redistribuirlo y/o
8
 * modificarlo bajo los términos de la Licencia Pública General Affero de GNU
9
 * publicada por la Fundación para el Software Libre, ya sea la versión
10
 * 3 de la Licencia, o (a su elección) cualquier versión posterior de la
11
 * misma.
12
 *
13
 * Este programa se distribuye con la esperanza de que sea útil, pero
14
 * SIN GARANTÍA ALGUNA; ni siquiera la garantía implícita
15
 * MERCANTIL o de APTITUD PARA UN PROPÓSITO DETERMINADO.
16
 * Consulte los detalles de la Licencia Pública General Affero de GNU para
17
 * obtener una información más detallada.
18
 *
19
 * Debería haber recibido una copia de la Licencia Pública General Affero de GNU
20
 * junto a este programa.
21
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
22
 */
23
24
namespace sasco\LibreDTE\Sii;
25
26
/**
27
 * Clase que representa el envío de un DTE
28
 * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
29
 * @version 2016-08-10
30
 */
31
class EnvioDte extends \sasco\LibreDTE\Sii\Base\Envio
32
{
33
34
    private $dtes = []; ///< Objetos con los DTE que se enviarán
35
    private $config = [ // 0: DTE, 1: boleta
36
        'SubTotDTE_max' => [20, 2], ///< máxima cantidad de tipos de documentos en el envío
37
        'DTE_max' => [2000, 1000], ///< máxima cantidad de DTE en un envío
38
        'tipos' => ['EnvioDTE', 'EnvioBOLETA'], ///< Tag para el envío, según si son Boletas o no
39
        'schemas' => ['EnvioDTE_v10', 'EnvioBOLETA_v11'], ///< Schema (XSD) que se deberá usar para validar según si son boletas o no
40
    ]; ///< Configuración/reglas para el documento XML
41
    private $tipo = null; ///< =0 DTE, =1 boleta
42
43
    /**
44
     * Método que agrega un DTE al listado que se enviará
45
     * @param DTE Objeto del DTE
46
     * @return =true si se pudo agregar el DTE o =false si no se agregó por exceder el límite de un envío
0 ignored issues
show
Documentation introduced by
The doc-type =true could not be parsed: Unknown type name "=true" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
47
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
48
     * @version 2015-12-11
49
     */
50
    public function agregar(Dte $DTE)
51
    {
52
        // determinar el tipo del envío (DTE o boleta)
53
        if ($this->tipo === null) {
54
            $this->tipo = (int)$DTE->esBoleta();
55
        }
56
        // validar que el tipo de documento sea del tipo que se espera
57
        else if ((int)$DTE->esBoleta() != $this->tipo) {
58
            return false;
59
        }
60
        //
61 View Code Duplication
        if (isset($this->dtes[$this->config['DTE_max'][$this->tipo]-1])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

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

Loading history...
62
            \sasco\LibreDTE\Log::write(
63
                \sasco\LibreDTE\Estado::ENVIODTE_DTE_MAX,
64
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::ENVIODTE_DTE_MAX, $this->config['DTE_max'][$this->tipo])
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...DTE_max'][$this->tipo]) is of type integer|string, but the function expects a object<sasco\LibreDTE\Mensaje>|null.

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...
65
            );
66
            return false;
67
        }
68
        $this->dtes[] = $DTE;
69
        return true;
70
    }
71
72
    /**
73
     * Método para asignar la caratula
74
     * @param caratula Arreglo con datos del envío: RutEnvia, FchResol y NroResol
75
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
76
     * @version 2015-12-11
77
     */
78
    public function setCaratula(array $caratula)
79
    {
80
        // si no hay DTEs para generar entregar falso
81
        if (!isset($this->dtes[0])) {
82
            \sasco\LibreDTE\Log::write(
83
                \sasco\LibreDTE\Estado::ENVIODTE_FALTA_DTE,
84
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::ENVIODTE_FALTA_DTE)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...do::ENVIODTE_FALTA_DTE) is of type integer|string, but the function expects a object<sasco\LibreDTE\Mensaje>|null.

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...
85
            );
86
            return false;
87
        }
88
        // si se agregaron demasiados DTE error
89
        $SubTotDTE = $this->getSubTotDTE();
90 View Code Duplication
        if (isset($SubTotDTE[$this->config['SubTotDTE_max'][$this->tipo]])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

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

Loading history...
91
            \sasco\LibreDTE\Log::write(
92
                \sasco\LibreDTE\Estado::ENVIODTE_TIPO_DTE_MAX,
93
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::ENVIODTE_TIPO_DTE_MAX, $this->config['SubTotDTE_max'][$this->tipo])
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...DTE_max'][$this->tipo]) is of type integer|string, but the function expects a object<sasco\LibreDTE\Mensaje>|null.

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...
94
            );
95
            return false;
96
        }
97
        // generar caratula
98
        $this->caratula = array_merge([
99
            '@attributes' => [
100
                'version' => '1.0'
101
            ],
102
            'RutEmisor' => $this->dtes[0]->getEmisor(),
103
            'RutEnvia' => isset($this->Firma) ? $this->Firma->getID() : false,
104
            'RutReceptor' => $this->dtes[0]->getReceptor(),
105
            'FchResol' => '',
106
            'NroResol' => '',
107
            'TmstFirmaEnv' => date('Y-m-d\TH:i:s'),
108
            'SubTotDTE' => $SubTotDTE,
109
        ], $caratula);
110
        return true;
111
    }
112
113
    /**
114
     * Método que realiza el envío del sobre con el o los DTEs al SII
115
     * @return Track ID del envío o =false si hubo algún problema al enviar el documento
116
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
117
     * @version 2015-12-15
118
     */
119
    public function enviar()
120
    {
121
        // si es boleta no se envía al SII
122
        if ($this->tipo) {
123
            return false;
124
        }
125
        // enviar al SII
126
        return parent::enviar();
127
    }
128
129
    /**
130
     * Método que genera el XML para el envío del DTE al SII
131
     * @return XML con el envio del DTE firmado o =false si no se pudo generar o firmar el envío
132
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
133
     * @version 2016-08-06
134
     */
135
    public function generar()
136
    {
137
        // si ya se había generado se entrega directamente
138
        if ($this->xml_data)
139
            return $this->xml_data;
140
        // si no hay DTEs para generar entregar falso
141
        if (!isset($this->dtes[0])) {
142
            \sasco\LibreDTE\Log::write(
143
                \sasco\LibreDTE\Estado::ENVIODTE_FALTA_DTE,
144
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::ENVIODTE_FALTA_DTE)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...do::ENVIODTE_FALTA_DTE) is of type integer|string, but the function expects a object<sasco\LibreDTE\Mensaje>|null.

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...
145
            );
146
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type declared by the abstract method sasco\LibreDTE\Sii\Base\Documento::generar of type sasco\LibreDTE\Sii\Base\XML.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
147
        }
148
        // genear XML del envío
149
        $xmlEnvio = (new \sasco\LibreDTE\XML())->generate([
150
            $this->config['tipos'][$this->tipo] => [
151
                '@attributes' => [
152
                    'xmlns' => 'http://www.sii.cl/SiiDte',
153
                    'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
154
                    'xsi:schemaLocation' => 'http://www.sii.cl/SiiDte '.$this->config['schemas'][$this->tipo].'.xsd',
155
                    'version' => '1.0'
156
                ],
157
                'SetDTE' => [
158
                    '@attributes' => [
159
                        'ID' => 'LibreDTE_SetDoc'
160
                    ],
161
                    'Caratula' => $this->caratula,
162
                    'DTE' => null,
163
                ]
164
            ]
165
        ])->saveXML();
166
        // generar XML de los DTE que se deberán incorporar
167
        $DTEs = [];
168
        foreach ($this->dtes as &$DTE) {
169
            $DTEs[] = trim(str_replace(['<?xml version="1.0" encoding="ISO-8859-1"?>', '<?xml version="1.0"?>'], '', $DTE->saveXML()));
170
        }
171
        // firmar XML del envío y entregar
172
        $xml = str_replace('<DTE/>', implode("\n", $DTEs), $xmlEnvio);
173
        $this->xml_data = $this->Firma ? $this->Firma->signXML($xml, '#LibreDTE_SetDoc', 'SetDTE', true) : $xml;
0 ignored issues
show
Documentation introduced by
$xml is of type string, but the function expects a object<sasco\LibreDTE\Datos>.

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...
174
        return $this->xml_data;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->xml_data; (boolean|string) is incompatible with the return type declared by the abstract method sasco\LibreDTE\Sii\Base\Documento::generar of type sasco\LibreDTE\Sii\Base\XML.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
175
    }
176
177
    /**
178
     * Método que obtiene los datos para generar los tags SubTotDTE
179
     * @return Arreglo con los datos para generar los tags SubTotDTE
180
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
181
     * @version 2015-09-02
182
     */
183
    private function getSubTotDTE()
184
    {
185
        $SubTotDTE = [];
186
        $subtotales = [];
187
        foreach ($this->dtes as &$DTE) {
188
            if (!isset($subtotales[$DTE->getTipo()]))
189
                $subtotales[$DTE->getTipo()] = 0;
190
            $subtotales[$DTE->getTipo()]++;
191
        }
192
        foreach ($subtotales as $tipo => $subtotal) {
193
            $SubTotDTE[] = [
194
                'TpoDTE' => $tipo,
195
                'NroDTE' => $subtotal,
196
            ];
197
        }
198
        return $SubTotDTE;
199
    }
200
201
    /**
202
     * Método que carga un XML de EnvioDte y asigna el objeto XML correspondiente
203
     * para poder obtener los datos del envío
204
     * @return Objeto XML
205
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
206
     * @version 2016-11-21
207
     */
208
    public function loadXML($xml_data)
209
    {
210
        if (!parent::loadXML($xml_data)) {
211
            return false;
212
        }
213
        $tagName = $this->xml->documentElement->tagName;
214
        if ($tagName=='DTE') {
215
            $this->xml = null;
216
            $this->xml_data = null;
217
            $this->arreglo = null;
218
            $Dte = new Dte($xml_data, false);
219
            $this->agregar($Dte);
220
            $this->setCaratula([
221
                'RutEnvia' => $Dte->getEmisor(),
222
                'RutReceptor' => $Dte->getReceptor(),
223
                'FchResol' => date('Y-m-d'),
224
                'NroResol' => ($Dte->getCertificacion()?'0':'').'9999',
225
            ]);
226
            if (!parent::loadXML($this->generar())) {
227
                return false;
228
            }
229
            $tagName = $this->xml->documentElement->tagName;
230
        }
231
        if ($tagName=='EnvioDTE') {
232
            $this->tipo = 0;
233
            return $this->xml;
234
        }
235
        if ($tagName=='EnvioBOLETA') {
236
            $this->tipo = 1;
237
            return $this->xml;
238
        }
239
        return false;
240
    }
241
242
    /**
243
     * Método que entrega un arreglo con los datos de la carátula del envío
244
     * @return Arreglo con datos de carátula
245
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
246
     * @version 2015-12-11
247
     */
248
    public function getCaratula()
249
    {
250
        return isset($this->arreglo[$this->config['tipos'][$this->tipo]]['SetDTE']['Caratula']) ? $this->arreglo[$this->config['tipos'][$this->tipo]]['SetDTE']['Caratula'] : false;
251
    }
252
253
    /**
254
     * Método que entrega el ID de SetDTE
255
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
256
     * @version 2015-12-11
257
     */
258
    public function getID()
259
    {
260
        return isset($this->arreglo[$this->config['tipos'][$this->tipo]]['SetDTE']['@attributes']['ID']) ? $this->arreglo[$this->config['tipos'][$this->tipo]]['SetDTE']['@attributes']['ID'] : false;
261
    }
262
263
    /**
264
     * Método que entrega el DigestValue de la firma del envío
265
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
266
     * @version 2015-12-11
267
     */
268
    public function getDigest()
269
    {
270
        return isset($this->arreglo[$this->config['tipos'][$this->tipo]]['Signature']['SignedInfo']['Reference']['DigestValue']) ? $this->arreglo[$this->config['tipos'][$this->tipo]]['Signature']['SignedInfo']['Reference']['DigestValue'] : false;
271
    }
272
273
    /**
274
     * Método que entrega el rut del emisor del envío
275
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
276
     * @version 2015-09-07
277
     */
278
    public function getEmisor()
279
    {
280
        $Caratula = $this->getCaratula();
281
        return $Caratula ? $Caratula['RutEmisor'] : false;
282
    }
283
284
    /**
285
     * Método que entrega el rut del receptor del envío
286
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
287
     * @version 2015-09-07
288
     */
289
    public function getReceptor()
290
    {
291
        $Caratula = $this->getCaratula();
292
        return $Caratula ? $Caratula['RutReceptor'] : false;
293
    }
294
295
    /**
296
     * Método que entrega la fecha del DTE más antiguo del envio
297
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
298
     * @version 2015-12-12
299
     */
300
    public function getFechaEmisionInicial()
301
    {
302
        $fecha = '9999-12-31';
303
        foreach ($this->getDocumentos() as $Dte) {
0 ignored issues
show
Bug introduced by
The expression $this->getDocumentos() of type false|array 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...
304
            if ($Dte->getFechaEmision() < $fecha)
305
                $fecha = $Dte->getFechaEmision();
306
        }
307
        return $fecha;
308
    }
309
310
    /**
311
     * Método que entrega la fecha del DTE más nuevo del envio
312
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
313
     * @version 2015-12-12
314
     */
315
    public function getFechaEmisionFinal()
316
    {
317
        $fecha = '0000-01-01';
318
        foreach ($this->getDocumentos() as $Dte) {
0 ignored issues
show
Bug introduced by
The expression $this->getDocumentos() of type false|array 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...
319
            if ($Dte->getFechaEmision() > $fecha)
320
                $fecha = $Dte->getFechaEmision();
321
        }
322
        return $fecha;
323
    }
324
325
    /**
326
     * Método que entrega el arreglo con los objetos DTE del envío
327
     * @return Arreglo de objetos DTE
328
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
329
     * @version 2016-11-21
330
     */
331
    public function getDocumentos($c14n = true)
332
    {
333
        // si no hay documentos se deben crear
334
        if (!$this->dtes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->dtes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
335
            // si no hay XML no se pueden crear los documentos
336
            if (!$this->xml) {
337
                \sasco\LibreDTE\Log::write(
338
                    \sasco\LibreDTE\Estado::ENVIODTE_GETDOCUMENTOS_FALTA_XML,
339
                    \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::ENVIODTE_GETDOCUMENTOS_FALTA_XML)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...ETDOCUMENTOS_FALTA_XML) is of type integer|string, but the function expects a object<sasco\LibreDTE\Mensaje>|null.

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...
340
                );
341
                return false;
342
            }
343
            // crear documentos a partir del XML
344
            $DTEs = $this->xml->getElementsByTagName('DTE');
345
            foreach ($DTEs as $nodo_dte) {
346
                $xml = $c14n ? $nodo_dte->C14N() : $this->xml->saveXML($nodo_dte);
347
                $this->dtes[] = new Dte($xml, false); // cargar DTE sin normalizar
348
            }
349
        }
350
        return $this->dtes;
351
    }
352
353
    /**
354
     * Método que entrega el objeto DTE solicitado del envío
355
     * @return Objeto DTE
356
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
357
     * @version 2016-11-21
358
     */
359
    public function getDocumento($emisor, $dte, $folio)
360
    {
361
        $emisor = str_replace('.', '', $emisor);
362
        // si no hay XML no se pueden crear los documentos
363
        if (!$this->xml) {
364
            \sasco\LibreDTE\Log::write(
365
                \sasco\LibreDTE\Estado::ENVIODTE_GETDOCUMENTOS_FALTA_XML,
366
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::ENVIODTE_GETDOCUMENTOS_FALTA_XML)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...ETDOCUMENTOS_FALTA_XML) is of type integer|string, but the function expects a object<sasco\LibreDTE\Mensaje>|null.

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...
367
            );
368
            return false;
369
        }
370
        // buscar documento
371
        $DTEs = $this->xml->getElementsByTagName('DTE');
372
        foreach ($DTEs as $nodo_dte) {
373
            $e = $nodo_dte->getElementsByTagName('RUTEmisor')->item(0)->nodeValue;
374
            if (is_numeric($emisor))
375
                $e = substr($e, 0, -2);
376
            $d = (int)$nodo_dte->getElementsByTagName('TipoDTE')->item(0)->nodeValue;
377
            $f = (int)$nodo_dte->getElementsByTagName('Folio')->item(0)->nodeValue;
378
            if ($folio == $f and $dte == $d and $emisor == $e) {
379
                return new Dte($nodo_dte->C14N(), false); // cargar DTE sin normalizar
380
            }
381
        }
382
        return false;
383
    }
384
385
    /**
386
     * Método que indica si es EnvioDTE o EnvioBOLETA
387
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
388
     * @version 2018-08-27
389
     */
390
    public function esBoleta()
391
    {
392
        return $this->tipo!==null ? (bool)$this->tipo : null;
393
    }
394
395
    /**
396
     * Método que determina el estado de validación sobre el envío
397
     * @param datos Arreglo con datos para hacer las validaciones
398
     * @return Código del estado de la validación
399
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
400
     * @version 2019-07-03
401
     */
402
    public function getEstadoValidacion(array $datos = null)
403
    {
404
        if (!$this->schemaValidate()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->schemaValidate() of type null|boolean is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
405
            return 1;
406
        }
407
        if (!$this->checkFirma()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->checkFirma() of type null|boolean is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
408
            return 2;
409
        }
410
        if ($datos and $this->getReceptor()!=$datos['RutReceptor']) {
411
            return 3;
412
        }
413
        return 0;
414
    }
415
416
    /**
417
     * Método que indica si la firma del documento es o no válida
418
     * @return =true si la firma del documento del envío es válida, =null si no se pudo determinar
0 ignored issues
show
Documentation introduced by
The doc-type =true could not be parsed: Unknown type name "=true" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
419
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
420
     * @version 2017-04-07
421
     */
422
    public function checkFirma()
423
    {
424
        if (!$this->xml) {
425
            return null;
426
        }
427
        // listado de firmas del XML
428
        $Signatures = $this->xml->documentElement->getElementsByTagName('Signature');
429
        // verificar firma de SetDTE
430
        $SetDTE = $this->xml->documentElement->getElementsByTagName('SetDTE')->item(0)->C14N();
431
        $SignedInfo = $Signatures->item($Signatures->length-1)->getElementsByTagName('SignedInfo')->item(0);
432
        $DigestValue = $Signatures->item($Signatures->length-1)->getElementsByTagName('DigestValue')->item(0)->nodeValue;
433
        $SignatureValue = trim(str_replace(["\n", ' ', "\t"], '', $Signatures->item($Signatures->length-1)->getElementsByTagName('SignatureValue')->item(0)->nodeValue));
434
        $X509Certificate = trim(str_replace(["\n", ' ', "\t"], '', $Signatures->item($Signatures->length-1)->getElementsByTagName('X509Certificate')->item(0)->nodeValue));
435
        $X509Certificate = '-----BEGIN CERTIFICATE-----'."\n".wordwrap($X509Certificate, 64, "\n", true)."\n".'-----END CERTIFICATE-----';
436
        $valid = openssl_verify($SignedInfo->C14N(), base64_decode($SignatureValue), $X509Certificate) === 1 ? true : false;
437
        return $valid and $DigestValue===base64_encode(sha1($SetDTE, true));
438
    }
439
440
}
441