Completed
Push — master ( 427926...362d6c )
by Esteban De La Fuente
01:42
created

Dte::normalizar()   C

Complexity

Conditions 10
Paths 18

Size

Total Lines 110

Duplication

Lines 5
Ratio 4.55 %

Importance

Changes 0
Metric Value
dl 5
loc 110
rs 6.1333
c 0
b 0
f 0
cc 10
nc 18
nop 1

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
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 un DTE y permite trabajar con el
28
 * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
29
 * @version 2017-08-29
30
 */
31
class Dte
32
{
33
34
    private $tipo; ///< Identificador del tipo de DTE: 33 (factura electrónica)
35
    private $folio; ///< Folio del documento
36
    private $xml; ///< Objeto XML que representa el DTE
37
    private $id; ///< Identificador único del DTE
38
    private $tipo_general; ///< Tipo general de DTE: Documento, Liquidacion o Exportaciones
39
    private $timestamp; ///< Timestamp del DTE
40
    private $datos = null; ///< Datos normalizados que se usaron para crear el DTE
41
    private $Signature = null; ///< Datos de la firma del DTE
42
43
    private $tipos = [
44
        'Documento' => [33, 34, 39, 41, 46, 52, 56, 61],
45
        'Liquidacion' => [43],
46
        'Exportaciones' => [110, 111, 112],
47
    ]; ///< Tipos posibles de documentos tributarios electrónicos
48
49
    private $noCedibles = [39, 41, 56, 61, 110, 111, 112]; ///< Documentos que no son cedibles
50
51
    /**
52
     * Constructor de la clase DTE
53
     * @param datos Arreglo con los datos del DTE o el XML completo del DTE
54
     * @param normalizar Si se pasa un arreglo permitirá indicar si el mismo se debe o no normalizar
55
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
56
     * @version 2015-09-03
57
     */
58
    public function __construct($datos, $normalizar = true)
59
    {
60
        if (is_array($datos))
61
            $this->setDatos($datos, $normalizar);
62
        else if (is_string($datos))
63
            $this->loadXML($datos);
64
        $this->timestamp = date('Y-m-d\TH:i:s');
65
    }
66
67
    /**
68
     * Método que carga el DTE ya armado desde un archivo XML
69
     * @param xml String con los datos completos del XML del DTE
70
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
71
     * @version 2016-09-01
72
     */
73
    private function loadXML($xml)
74
    {
75
        if (!empty($xml)) {
76
            $this->xml = new \sasco\LibreDTE\XML();
77
            if (!$this->xml->loadXML($xml) or !$this->schemaValidate()) {
78
                \sasco\LibreDTE\Log::write(
79
                    \sasco\LibreDTE\Estado::DTE_ERROR_LOADXML,
80
                    \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::DTE_ERROR_LOADXML)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...ado::DTE_ERROR_LOADXML) 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...
81
                );
82
                return false;
83
            }
84
            $TipoDTE = $this->xml->getElementsByTagName('TipoDTE')->item(0);
85
            if (!$TipoDTE) {
86
                return false;
87
            }
88
            $this->tipo = $TipoDTE->nodeValue;
89
            $this->tipo_general = $this->getTipoGeneral($this->tipo);
0 ignored issues
show
Documentation introduced by
$this->tipo is of type string, but the function expects a object<sasco\LibreDTE\Sii\Tipo>.

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...
90
            if (!$this->tipo_general) {
91
                return false;
92
            }
93
            $Folio = $this->xml->getElementsByTagName('Folio')->item(0);
94
            if (!$Folio) {
95
                return false;
96
            }
97
            $this->folio = $Folio->nodeValue;
98
            if (isset($this->getDatos()['@attributes'])) {
99
                $this->id = $this->getDatos()['@attributes']['ID'];
100
            } else {
101
                $this->id = 'LibreDTE_T'.$this->tipo.'F'.$this->folio;
102
            }
103
            return true;
104
        }
105
        return false;
106
    }
107
108
    /**
109
     * Método que asigna los datos del DTE
110
     * @param datos Arreglo con los datos del DTE que se quire generar
111
     * @param normalizar Si se pasa un arreglo permitirá indicar si el mismo se debe o no normalizar
112
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
113
     * @version 2017-10-22
114
     */
115
    private function setDatos(array $datos, $normalizar = true)
116
    {
117
        if (!empty($datos)) {
118
            $this->tipo = $datos['Encabezado']['IdDoc']['TipoDTE'];
119
            $this->folio = $datos['Encabezado']['IdDoc']['Folio'];
120
            $this->id = 'LibreDTE_T'.$this->tipo.'F'.$this->folio;
121
            if ($normalizar) {
122
                $this->normalizar($datos);
123
                $method = 'normalizar_'.$this->tipo;
124
                if (method_exists($this, $method))
125
                    $this->$method($datos);
126
                $this->normalizar_final($datos);
127
            }
128
            $this->tipo_general = $this->getTipoGeneral($this->tipo);
129
            $this->xml = (new \sasco\LibreDTE\XML())->generate([
130
                'DTE' => [
131
                    '@attributes' => [
132
                        'version' => '1.0',
133
                    ],
134
                    $this->tipo_general => [
135
                        '@attributes' => [
136
                            'ID' => $this->id
137
                        ],
138
                    ]
139
                ]
140
            ]);
141
            $parent = $this->xml->getElementsByTagName($this->tipo_general)->item(0);
142
            $this->xml->generate($datos + ['TED' => null], null, $parent);
0 ignored issues
show
Documentation introduced by
$parent is of type object<DOMNode>, but the function expects a null|object<DOMElement>.

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...
143
            $this->datos = $datos;
144
            if ($normalizar and !$this->verificarDatos()) {
145
                return false;
146
            }
147
            return $this->schemaValidate();
148
        }
149
        return false;
150
    }
151
152
    /**
153
     * Método que entrega el arreglo con los datos del DTE.
154
     * Si el DTE fue creado a partir de un arreglo serán los datos normalizados,
155
     * en cambio si se creó a partir de un XML serán todos los nodos del
156
     * documento sin cambios.
157
     * @return Arreglo con datos del DTE
158
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
159
     * @version 2016-07-04
160
     */
161
    public function getDatos()
162
    {
163
        if (!$this->datos) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->datos 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...
164
            $datos = $this->xml->toArray();
165
            if (!isset($datos['DTE'][$this->tipo_general])) {
166
                \sasco\LibreDTE\Log::write(
167
                    \sasco\LibreDTE\Estado::DTE_ERROR_GETDATOS,
168
                    \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::DTE_ERROR_GETDATOS)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...do::DTE_ERROR_GETDATOS) 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...
169
                );
170
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getDatos of type sasco\LibreDTE\Sii\Arreglo.

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...
171
            }
172
            $this->datos = $datos['DTE'][$this->tipo_general];
173
            if (isset($datos['DTE']['Signature'])) {
174
                $this->Signature = $datos['DTE']['Signature'];
175
            }
176
        }
177
        return $this->datos;
178
    }
179
180
    /**
181
     * Método que entrega el arreglo con los datos de la firma del DTE
182
     * @return Arreglo con datos de la firma
183
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
184
     * @version 2016-06-11
185
     */
186
    public function getFirma()
187
    {
188
        if (!$this->Signature) {
189
            $this->getDatos();
190
        }
191
        return $this->Signature;
192
    }
193
194
    /**
195
     * Método que entrega los datos del DTE (tag Documento) como un string JSON
196
     * @return String JSON "lindo" con los datos del documento
197
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
198
     * @version 2015-09-08
199
     */
200
    public function getJSON()
201
    {
202
        if (!$this->getDatos())
203
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getJSON of type string.

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...
204
        return json_encode($this->datos, JSON_PRETTY_PRINT);
205
    }
206
207
    /**
208
     * Método que entrega el ID del documento
209
     * @return String con el ID del DTE
210
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
211
     * @version 2016-08-17
212
     */
213
    public function getID($estandar = false)
214
    {
215
        return $estandar ? ('T'.$this->tipo.'F'.$this->folio) : $this->id;
216
    }
217
218
    /**
219
     * Método que entrega el tipo general de documento, de acuerdo a
220
     * $this->tipos
221
     * @param dte Tipo númerico de DTE, ejemplo: 33 (factura electrónica)
222
     * @return String con el tipo general: Documento, Liquidacion o Exportaciones
223
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
224
     * @version 2015-09-17
225
     */
226
    private function getTipoGeneral($dte)
227
    {
228
        foreach ($this->tipos as $tipo => $codigos)
229
            if (in_array($dte, $codigos))
230
                return $tipo;
231
        \sasco\LibreDTE\Log::write(
232
            \sasco\LibreDTE\Estado::DTE_ERROR_TIPO,
233
            \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::DTE_ERROR_TIPO, $dte)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...::DTE_ERROR_TIPO, $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...
234
        );
235
        return false;
236
    }
237
238
    /**
239
     * Método que entrega el tipo de DTE
240
     * @return Tipo de dte, ej: 33 (factura electrónica)
241
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
242
     * @version 2015-09-02
243
     */
244
    public function getTipo()
245
    {
246
        return $this->tipo;
247
    }
248
249
    /**
250
     * Método que entrega el folio del DTE
251
     * @return Folio del DTE
252
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
253
     * @version 2015-09-02
254
     */
255
    public function getFolio()
256
    {
257
        return $this->folio;
258
    }
259
260
    /**
261
     * Método que entrega rut del emisor del DTE
262
     * @return RUT del emiro
263
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
264
     * @version 2015-09-07
265
     */
266 View Code Duplication
    public function getEmisor()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
267
    {
268
        $nodo = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Emisor/RUTEmisor')->item(0);
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...ezado/Emisor/RUTEmisor' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
269
        if ($nodo)
270
            return $nodo->nodeValue;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $nodo->nodeValue; (string) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getEmisor of type sasco\LibreDTE\Sii\RUT.

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...
271
        if (!$this->getDatos())
272
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getEmisor of type sasco\LibreDTE\Sii\RUT.

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...
273
        return $this->datos['Encabezado']['Emisor']['RUTEmisor'];
274
    }
275
276
    /**
277
     * Método que entrega rut del receptor del DTE
278
     * @return RUT del emiro
279
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
280
     * @version 2015-09-07
281
     */
282 View Code Duplication
    public function getReceptor()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
283
    {
284
        $nodo = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Receptor/RUTRecep')->item(0);
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...zado/Receptor/RUTRecep' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
285
        if ($nodo)
286
            return $nodo->nodeValue;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $nodo->nodeValue; (string) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getReceptor of type sasco\LibreDTE\Sii\RUT.

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...
287
        if (!$this->getDatos())
288
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getReceptor of type sasco\LibreDTE\Sii\RUT.

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...
289
        return $this->datos['Encabezado']['Receptor']['RUTRecep'];
290
    }
291
292
    /**
293
     * Método que entrega fecha de emisión del DTE
294
     * @return Fecha de emisión en formato AAAA-MM-DD
295
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
296
     * @version 2015-09-07
297
     */
298 View Code Duplication
    public function getFechaEmision()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
299
    {
300
        $nodo = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/IdDoc/FchEmis')->item(0);
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...cabezado/IdDoc/FchEmis' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
301
        if ($nodo)
302
            return $nodo->nodeValue;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $nodo->nodeValue; (string) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getFechaEmision of type sasco\LibreDTE\Sii\Fecha.

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...
303
        if (!$this->getDatos())
304
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getFechaEmision of type sasco\LibreDTE\Sii\Fecha.

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...
305
        return $this->datos['Encabezado']['IdDoc']['FchEmis'];
306
    }
307
308
    /**
309
     * Método que entrega el monto total del DTE
310
     * @return Monto total del DTE
311
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
312
     * @version 2015-09-07
313
     */
314 View Code Duplication
    public function getMontoTotal()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
315
    {
316
        $nodo = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Totales/MntTotal')->item(0);
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...ezado/Totales/MntTotal' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
317
        if ($nodo)
318
            return $nodo->nodeValue;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $nodo->nodeValue; (string) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getMontoTotal of type sasco\LibreDTE\Sii\Monto.

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...
319
        if (!$this->getDatos())
320
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getMontoTotal of type sasco\LibreDTE\Sii\Monto.

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...
321
        return $this->datos['Encabezado']['Totales']['MntTotal'];
322
    }
323
324
    /**
325
     * Método que entrega el tipo de moneda del documento
326
     * @return String con el tipo de moneda
327
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
328
     * @version 2016-07-16
329
     */
330 View Code Duplication
    public function getMoneda()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
331
    {
332
        $nodo = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Totales/TpoMoneda')->item(0);
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...zado/Totales/TpoMoneda' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
333
        if ($nodo)
334
            return $nodo->nodeValue;
335
        if (!$this->getDatos())
336
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getMoneda of type string.

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...
337
        return $this->datos['Encabezado']['Totales']['TpoMoneda'];
338
    }
339
340
    /**
341
     * Método que entrega las referencias del DTE si existen
342
     * @return Arreglo con las referencias
343
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
344
     * @version 2017-11-17
345
     */
346
    public function getReferencias()
347
    {
348
        if (!$this->getDatos()) {
349
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getReferencias of type sasco\LibreDTE\Sii\Arreglo.

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...
350
        }
351
        $referencias = !empty($this->datos['Referencia']) ? $this->datos['Referencia'] : false;
352
        if (!$referencias) {
353
            return [];
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array(); (array) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getReferencias of type sasco\LibreDTE\Sii\Arreglo.

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...
354
        }
355
        if (!isset($referencias[0])) {
356
            $referencias = [$referencias];
357
        }
358
        return $referencias;
359
    }
360
361
    /**
362
     * Método que entrega el string XML del tag TED
363
     * @return String XML con tag TED
364
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
365
     * @version 2016-08-03
366
     */
367
    public function getTED()
368
    {
369
        /*$xml = new \sasco\LibreDTE\XML();
370
        $xml->loadXML($this->xml->getElementsByTagName('TED')->item(0)->getElementsByTagName('DD')->item(0)->C14N());
371
        $xml->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi');
372
        $xml->documentElement->removeAttributeNS('http://www.sii.cl/SiiDte', '');
373
        $FRMT = $this->xml->getElementsByTagName('TED')->item(0)->getElementsByTagName('FRMT')->item(0)->nodeValue;
374
        $pub_key = '';
375
        if (openssl_verify($xml->getFlattened('/'), base64_decode($FRMT), $pub_key, OPENSSL_ALGO_SHA1)!==1);
376
            return false;*/
377
        $xml = new \sasco\LibreDTE\XML();
378
        $TED = $this->xml->getElementsByTagName('TED')->item(0);
379
        if (!$TED)
380
            return '<TED/>';
381
        $xml->loadXML($TED->C14N());
382
        $xml->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi');
383
        $xml->documentElement->removeAttributeNS('http://www.sii.cl/SiiDte', '');
384
        $TED = $xml->getFlattened('/');
0 ignored issues
show
Documentation introduced by
'/' is of type string, but the function expects a object<sasco\LibreDTE\XPath>|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...
385
        return mb_detect_encoding($TED, ['UTF-8', 'ISO-8859-1']) != 'ISO-8859-1' ? utf8_decode($TED) : $TED;
386
    }
387
388
    /**
389
     * Método que indica si el DTE es de certificación o no
390
     * @return =true si el DTE es de certificación, =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...
391
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
392
     * @version 2016-06-15
393
     */
394
    public function getCertificacion()
395
    {
396
        $datos = $this->getDatos();
397
        $idk = !empty($datos['TED']['DD']['CAF']['DA']['IDK']) ? (int)$datos['TED']['DD']['CAF']['DA']['IDK'] : null;
398
        return $idk ? $idk === 100 : null;
399
    }
400
401
    /**
402
     * Método que realiza el timbrado del DTE
403
     * @param Folios Objeto de los Folios con los que se desea timbrar
404
     * @return =true si se pudo timbrar o =false en caso de error
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...
405
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
406
     * @version 2016-09-01
407
     */
408
    public function timbrar(Folios $Folios)
409
    {
410
        // verificar que el folio que se está usando para el DTE esté dentro
411
        // del rango de folios autorizados que se usarán para timbrar
412
        // Esta validación NO verifica si el folio ya fue usado, sólo si está
413
        // dentro del CAF que se está usando
414
        $folio = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/IdDoc/Folio')->item(0)->nodeValue;
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...Encabezado/IdDoc/Folio' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
415
        if ($folio<$Folios->getDesde() or $folio>$Folios->getHasta()) {
416
            \sasco\LibreDTE\Log::write(
417
                \sasco\LibreDTE\Estado::DTE_ERROR_RANGO_FOLIO,
418
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::DTE_ERROR_RANGO_FOLIO, $this->getID())
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::..._FOLIO, $this->getID()) 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...
419
            );
420
            return false;
421
        }
422
        // verificar que existan datos para el timbre
423 View Code Duplication
        if (!$this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/IdDoc/FchEmis')->item(0)) {
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...cabezado/IdDoc/FchEmis' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
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...
424
            \sasco\LibreDTE\Log::write(
425
                \sasco\LibreDTE\Estado::DTE_FALTA_FCHEMIS,
426
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::DTE_FALTA_FCHEMIS, $this->getID())
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...CHEMIS, $this->getID()) 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...
427
            );
428
            \sasco\LibreDTE\Log::write('Falta FchEmis del DTE '.$this->getID());
0 ignored issues
show
Documentation introduced by
'Falta FchEmis del DTE ' . $this->getID() is of type string, but the function expects a object<sasco\LibreDTE\Código>.

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...
429
            return false;
430
        }
431 View Code Duplication
        if (!$this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Totales/MntTotal')->item(0)) {
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...ezado/Totales/MntTotal' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
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...
432
            \sasco\LibreDTE\Log::write(
433
                \sasco\LibreDTE\Estado::DTE_FALTA_MNTTOTAL,
434
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::DTE_FALTA_MNTTOTAL, $this->getID())
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...TTOTAL, $this->getID()) 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...
435
            );
436
            return false;
437
        }
438
        // timbrar
439
        $RR = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Receptor/RUTRecep')->item(0)->nodeValue;
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...zado/Receptor/RUTRecep' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
440
        $RSR_nodo = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Receptor/RznSocRecep');
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...o/Receptor/RznSocRecep' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
441
        $RSR = $RSR_nodo->length ? trim(mb_substr($RSR_nodo->item(0)->nodeValue, 0, 40)) : $RR;
442
        if (!$RSR) {
443
            $RSR = $RR;
444
        }
445
        $TED = new \sasco\LibreDTE\XML();
446
        $TED->generate([
447
            'TED' => [
448
                '@attributes' => [
449
                    'version' => '1.0',
450
                ],
451
                'DD' => [
452
                    'RE' => $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Emisor/RUTEmisor')->item(0)->nodeValue,
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...ezado/Emisor/RUTEmisor' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
453
                    'TD' => $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/IdDoc/TipoDTE')->item(0)->nodeValue,
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...cabezado/IdDoc/TipoDTE' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
454
                    'F' => $folio,
455
                    'FE' => $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/IdDoc/FchEmis')->item(0)->nodeValue,
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...cabezado/IdDoc/FchEmis' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
456
                    'RR' => $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Receptor/RUTRecep')->item(0)->nodeValue,
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...zado/Receptor/RUTRecep' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
457
                    'RSR' => $RSR,
458
                    'MNT' => $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Totales/MntTotal')->item(0)->nodeValue,
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...ezado/Totales/MntTotal' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
459
                    'IT1' => trim(mb_substr($this->xml->xpath('/DTE/'.$this->tipo_general.'/Detalle')->item(0)->getElementsByTagName('NmbItem')->item(0)->nodeValue, 0, 40)),
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_general . '/Detalle' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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...
460
                    'CAF' => $Folios->getCaf(),
461
                    'TSTED' => $this->timestamp,
462
                ],
463
                'FRMT' => [
464
                    '@attributes' => [
465
                        'algoritmo' => 'SHA1withRSA'
466
                    ],
467
                ],
468
            ]
469
        ]);
470
        $DD = $TED->getFlattened('/TED/DD');
0 ignored issues
show
Documentation introduced by
'/TED/DD' is of type string, but the function expects a object<sasco\LibreDTE\XPath>|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...
471
        if (openssl_sign($DD, $timbre, $Folios->getPrivateKey(), OPENSSL_ALGO_SHA1)==false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
472
            \sasco\LibreDTE\Log::write(
473
                \sasco\LibreDTE\Estado::DTE_ERROR_TIMBRE,
474
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::DTE_ERROR_TIMBRE, $this->getID())
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...TIMBRE, $this->getID()) 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...
475
            );
476
            return false;
477
        }
478
        $TED->getElementsByTagName('FRMT')->item(0)->nodeValue = base64_encode($timbre);
479
        $xml = str_replace('<TED/>', trim(str_replace('<?xml version="1.0" encoding="ISO-8859-1"?>', '', $TED->saveXML())), $this->saveXML());
480 View Code Duplication
        if (!$this->loadXML($xml)) {
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...
481
            \sasco\LibreDTE\Log::write(
482
                \sasco\LibreDTE\Estado::DTE_ERROR_TIMBRE,
483
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::DTE_ERROR_TIMBRE, $this->getID())
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...TIMBRE, $this->getID()) 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...
484
            );
485
            return false;
486
        }
487
        return true;
488
    }
489
490
    /**
491
     * Método que realiza la firma del DTE
492
     * @param Firma objeto que representa la Firma Electrónca
493
     * @return =true si el DTE pudo ser fimado o =false si no se pudo firmar
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...
494
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
495
     * @version 2017-10-22
496
     */
497
    public function firmar(\sasco\LibreDTE\FirmaElectronica $Firma)
498
    {
499
        $parent = $this->xml->getElementsByTagName($this->tipo_general)->item(0);
500
        $this->xml->generate(['TmstFirma'=>$this->timestamp], null, $parent);
0 ignored issues
show
Documentation introduced by
$parent is of type object<DOMNode>, but the function expects a null|object<DOMElement>.

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...
501
        $xml = $Firma->signXML($this->xml->saveXML(), '#'.$this->id, $this->tipo_general);
0 ignored issues
show
Documentation introduced by
$this->xml->saveXML() 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...
502 View Code Duplication
        if (!$xml) {
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...
503
            \sasco\LibreDTE\Log::write(
504
                \sasco\LibreDTE\Estado::DTE_ERROR_FIRMA,
505
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::DTE_ERROR_FIRMA, $this->getID())
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::..._FIRMA, $this->getID()) 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...
506
            );
507
            return false;
508
        }
509
        $this->loadXML($xml);
0 ignored issues
show
Bug introduced by
It seems like $xml defined by $Firma->signXML($this->x...d, $this->tipo_general) on line 501 can also be of type boolean; however, sasco\LibreDTE\Sii\Dte::loadXML() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
510
        return true;
511
    }
512
513
    /**
514
     * Método que entrega el DTE en XML
515
     * @return XML con el DTE (podría: con o sin timbre y con o sin firma)
516
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
517
     * @version 2015-08-20
518
     */
519
    public function saveXML()
520
    {
521
        return $this->xml->saveXML();
522
    }
523
524
    /**
525
     * Método que genera un arreglo con el resumen del documento. Este resumen
526
     * puede servir, por ejemplo, para generar los detalles de los IECV
527
     * @return Arreglo con el resumen del DTE
528
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
529
     * @version 2016-07-15
530
     */
531
    public function getResumen()
532
    {
533
        $this->getDatos();
534
        // generar resumen
535
        $resumen =  [
536
            'TpoDoc' => (int)$this->datos['Encabezado']['IdDoc']['TipoDTE'],
537
            'NroDoc' => (int)$this->datos['Encabezado']['IdDoc']['Folio'],
538
            'TasaImp' => 0,
539
            'FchDoc' => $this->datos['Encabezado']['IdDoc']['FchEmis'],
540
            'CdgSIISucur' => !empty($this->datos['Encabezado']['Emisor']['CdgSIISucur']) ? $this->datos['Encabezado']['Emisor']['CdgSIISucur'] : false,
541
            'RUTDoc' => $this->datos['Encabezado']['Receptor']['RUTRecep'],
542
            'RznSoc' => isset($this->datos['Encabezado']['Receptor']['RznSocRecep']) ? $this->datos['Encabezado']['Receptor']['RznSocRecep'] : false,
543
            'MntExe' => false,
544
            'MntNeto' => false,
545
            'MntIVA' => 0,
546
            'MntTotal' => 0,
547
        ];
548
        // obtener montos si es que existen en el documento
549
        $montos = ['TasaImp'=>'TasaIVA', 'MntExe'=>'MntExe', 'MntNeto'=>'MntNeto', 'MntIVA'=>'IVA', 'MntTotal'=>'MntTotal'];
550
        foreach ($montos as $dest => $orig) {
551
            if (!empty($this->datos['Encabezado']['Totales'][$orig])) {
552
                $resumen[$dest] = !$this->esExportacion() ? round($this->datos['Encabezado']['Totales'][$orig]) : $this->datos['Encabezado']['Totales'][$orig];
553
            }
554
        }
555
        // si es una boleta se calculan los datos para el resumen
556
        if ($this->esBoleta()) {
557
            if (!$resumen['TasaImp']) {
558
                $resumen['TasaImp'] = \sasco\LibreDTE\Sii::getIVA();
559
            }
560
            $resumen['MntExe'] = (int)$resumen['MntExe'];
561
            if (!$resumen['MntNeto']) {
562
                list($resumen['MntNeto'], $resumen['MntIVA']) = $this->calcularNetoIVA($resumen['MntTotal']-$resumen['MntExe'], $resumen['TasaImp']);
0 ignored issues
show
Documentation introduced by
$resumen['MntTotal'] - $resumen['MntExe'] is of type integer|double, but the function expects a object<sasco\LibreDTE\Sii\neto>.

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...
563
            }
564
        }
565
        // entregar resumen
566
        return $resumen;
567
    }
568
569
    /**
570
     * Método que permite obtener el monto neto y el IVA de ese neto a partir de
571
     * un monto total
572
     * @param total neto + iva
573
     * @param tasa Tasa del IVA
574
     * @return Arreglo con el neto y el iva
575
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
576
     * @version 2016-04-05
577
     */
578
    private function calcularNetoIVA($total, $tasa = null)
579
    {
580
        if ($tasa === 0 or $tasa === false) {
581
            return [0, 0];
582
        }
583
        if ($tasa === null) {
584
            $tasa = \sasco\LibreDTE\Sii::getIVA();
585
        }
586
        // WARNING: el IVA obtenido puede no ser el NETO*(TASA/100)
587
        // se calcula el monto neto y luego se obtiene el IVA haciendo la resta
588
        // entre el total y el neto, ya que hay casos de borde como:
589
        //  - BRUTO:   680 => NETO:   571 e IVA:   108 => TOTAL:   679
590
        //  - BRUTO: 86710 => NETO: 72866 e IVA: 13845 => TOTAL: 86711
591
        $neto = round($total / (1+($tasa/100)));
592
        $iva = $total - $neto;
593
        return [$neto, $iva];
594
    }
595
596
    /**
597
     * Método que normaliza los datos de un documento tributario electrónico
598
     * @param datos Arreglo con los datos del documento que se desean normalizar
599
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
600
     * @version 2021-02-14
601
     */
602
    private function normalizar(array &$datos)
603
    {
604
        // completar con nodos por defecto
605
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
606
            'Encabezado' => [
607
                'IdDoc' => [
608
                    'TipoDTE' => false,
609
                    'Folio' => false,
610
                    'FchEmis' => date('Y-m-d'),
611
                    'IndNoRebaja' => false,
612
                    'TipoDespacho' => false,
613
                    'IndTraslado' => false,
614
                    'TpoImpresion' => false,
615
                    'IndServicio' => $this->esBoleta() ? 3 : false,
616
                    'MntBruto' => false,
617
                    'TpoTranCompra' => false,
618
                    'TpoTranVenta' => false,
619
                    'FmaPago' => false,
620
                    'FmaPagExp' => false,
621
                    'MntCancel' => false,
622
                    'SaldoInsol' => false,
623
                    'FchCancel' => false,
624
                    'MntPagos' => false,
625
                    'PeriodoDesde' => false,
626
                    'PeriodoHasta' => false,
627
                    'MedioPago' => false,
628
                    'TpoCtaPago' => false,
629
                    'NumCtaPago' => false,
630
                    'BcoPago' => false,
631
                    'TermPagoCdg' => false,
632
                    'TermPagoGlosa' => false,
633
                    'TermPagoDias' => false,
634
                    'FchVenc' => false,
635
                ],
636
                'Emisor' => [
637
                    'RUTEmisor' => false,
638
                    'RznSoc' => false,
639
                    'GiroEmis' => false,
640
                    'Telefono' => false,
641
                    'CorreoEmisor' => false,
642
                    'Acteco' => false,
643
                    'GuiaExport' => false,
644
                    'Sucursal' => false,
645
                    'CdgSIISucur' => false,
646
                    'DirOrigen' => false,
647
                    'CmnaOrigen' => false,
648
                    'CiudadOrigen' => false,
649
                    'CdgVendedor' => false,
650
                    'IdAdicEmisor' => false,
651
                ],
652
                'Receptor' => [
653
                    'RUTRecep' => false,
654
                    'CdgIntRecep' => false,
655
                    'RznSocRecep' => false,
656
                    'Extranjero' => false,
657
                    'GiroRecep' => false,
658
                    'Contacto' => false,
659
                    'CorreoRecep' => false,
660
                    'DirRecep' => false,
661
                    'CmnaRecep' => false,
662
                    'CiudadRecep' => false,
663
                    'DirPostal' => false,
664
                    'CmnaPostal' => false,
665
                    'CiudadPostal' => false,
666
                ],
667
                'Totales' => [
668
                    'TpoMoneda' => false,
669
                ],
670
            ],
671
            'Detalle' => false,
672
            'SubTotInfo' => false,
673
            'DscRcgGlobal' => false,
674
            'Referencia' => false,
675
            'Comisiones' => false,
676
        ], $datos);
677
        // si existe descuento o recargo global se normalizan
678
        if (!empty($datos['DscRcgGlobal'])) {
679 View Code Duplication
            if (!isset($datos['DscRcgGlobal'][0]))
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...
680
                $datos['DscRcgGlobal'] = [$datos['DscRcgGlobal']];
681
            $NroLinDR = 1;
682
            foreach ($datos['DscRcgGlobal'] as &$dr) {
683
                $dr = array_merge([
684
                    'NroLinDR' => $NroLinDR++,
685
                ], $dr);
686
            }
687
        }
688
        // si existe una o más referencias se normalizan
689
        if (!empty($datos['Referencia'])) {
690 View Code Duplication
            if (!isset($datos['Referencia'][0])) {
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...
691
                $datos['Referencia'] = [$datos['Referencia']];
692
            }
693
            $NroLinRef = 1;
694
            foreach ($datos['Referencia'] as &$r) {
695
                $r = array_merge([
696
                    'NroLinRef' => $NroLinRef++,
697
                    'TpoDocRef' => false,
698
                    'IndGlobal' => false,
699
                    'FolioRef' => false,
700
                    'RUTOtr' => false,
701
                    'FchRef' => date('Y-m-d'),
702
                    'CodRef' => false,
703
                    'RazonRef' => false,
704
                ], $r);
705
            }
706
        }
707
        // verificar que exista TpoTranVenta
708
        if (!in_array($datos['Encabezado']['IdDoc']['TipoDTE'], [39, 41, 110, 111, 112]) and empty($datos['Encabezado']['IdDoc']['TpoTranVenta'])) {
709
            $datos['Encabezado']['IdDoc']['TpoTranVenta'] = 1; // ventas del giro
710
        }
711
    }
712
713
    /**
714
     * Método que realiza la normalización final de los datos de un documento
715
     * tributario electrónico. Esto se aplica todos los documentos una vez que
716
     * ya se aplicaron las normalizaciones por tipo
717
     * @param datos Arreglo con los datos del documento que se desean normalizar
718
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
719
     * @version 2021-02-14
720
     */
721
    private function normalizar_final(array &$datos)
722
    {
723
        // normalizar montos de pagos programados
724
        if (is_array($datos['Encabezado']['IdDoc']['MntPagos'])) {
725
            $montos = 0;
0 ignored issues
show
Unused Code introduced by
$montos 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...
726
            if (!isset($datos['Encabezado']['IdDoc']['MntPagos'][0])) {
727
                $datos['Encabezado']['IdDoc']['MntPagos'] = [$datos['Encabezado']['IdDoc']['MntPagos']];
728
            }
729
            foreach ($datos['Encabezado']['IdDoc']['MntPagos'] as &$MntPagos) {
730
                $MntPagos = array_merge([
731
                    'FchPago' => null,
732
                    'MntPago' => null,
733
                    'GlosaPagos' => false,
734
                ], $MntPagos);
735
                if ($MntPagos['MntPago']===null) {
736
                    $MntPagos['MntPago'] = $datos['Encabezado']['Totales']['MntTotal'];
737
                }
738
            }
739
        }
740
        // si existe OtraMoneda se verifican los tipos de cambio y totales
741
        if (!empty($datos['Encabezado']['OtraMoneda'])) {
742 View Code Duplication
            if (!isset($datos['Encabezado']['OtraMoneda'][0])) {
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...
743
                $datos['Encabezado']['OtraMoneda'] = [$datos['Encabezado']['OtraMoneda']];
744
            }
745
            foreach ($datos['Encabezado']['OtraMoneda'] as &$OtraMoneda) {
746
                // colocar campos por defecto
747
                $OtraMoneda = array_merge([
748
                    'TpoMoneda' => false,
749
                    'TpoCambio' => false,
750
                    'MntNetoOtrMnda' => false,
751
                    'MntExeOtrMnda' => false,
752
                    'MntFaeCarneOtrMnda' => false,
753
                    'MntMargComOtrMnda' => false,
754
                    'IVAOtrMnda' => false,
755
                    'ImpRetOtrMnda' => false,
756
                    'IVANoRetOtrMnda' => false,
757
                    'MntTotOtrMnda' => false,
758
                ], $OtraMoneda);
759
                // si no hay tipo de cambio no seguir
760
                if (!isset($OtraMoneda['TpoCambio'])) {
761
                    continue;
762
                }
763
                // buscar si los valores están asignados, si no lo están asignar
764
                // usando el tipo de cambio que existe para la moneda
765
                foreach (['MntNeto', 'MntExe', 'IVA', 'IVANoRet'] as $monto) {
766
                    if (empty($OtraMoneda[$monto.'OtrMnda']) and !empty($datos['Encabezado']['Totales'][$monto])) {
767
                        $OtraMoneda[$monto.'OtrMnda'] = round($datos['Encabezado']['Totales'][$monto] * $OtraMoneda['TpoCambio'], 4);
768
                    }
769
                }
770
                // calcular MntFaeCarneOtrMnda, MntMargComOtrMnda, ImpRetOtrMnda
771
                if (empty($OtraMoneda['MntFaeCarneOtrMnda'])) {
772
                    $OtraMoneda['MntFaeCarneOtrMnda'] = false; // TODO
773
                }
774
                if (empty($OtraMoneda['MntMargComOtrMnda'])) {
775
                    $OtraMoneda['MntMargComOtrMnda'] = false; // TODO
776
                }
777
                if (empty($OtraMoneda['ImpRetOtrMnda'])) {
778
                    $OtraMoneda['ImpRetOtrMnda'] = false; // TODO
779
                }
780
                // calcular monto total
781
                if (empty($OtraMoneda['MntTotOtrMnda'])) {
782
                    $OtraMoneda['MntTotOtrMnda'] = 0;
783
                    $cols = ['MntNetoOtrMnda', 'MntExeOtrMnda', 'MntFaeCarneOtrMnda', 'MntMargComOtrMnda', 'IVAOtrMnda', 'IVANoRetOtrMnda'];
784
                    foreach ($cols as $monto) {
785
                        if (!empty($OtraMoneda[$monto])) {
786
                            $OtraMoneda['MntTotOtrMnda'] += $OtraMoneda[$monto];
787
                        }
788
                    }
789
                    // agregar total de impuesto retenido otra moneda
790
                    if (!empty($OtraMoneda['ImpRetOtrMnda'])) {
791
                        // TODO
792
                    }
793
                    // aproximar el total si es en pesos chilenos
794
                    if ($OtraMoneda['TpoMoneda']=='PESO CL') {
795
                        $OtraMoneda['MntTotOtrMnda'] = round($OtraMoneda['MntTotOtrMnda']);
796
                    }
797
                }
798
                // si el tipo de cambio es 0, se quita
799
                if ($OtraMoneda['TpoCambio']==0) {
800
                    $OtraMoneda['TpoCambio'] = false;
801
                }
802
            }
803
        }
804
        // corregir algunos datos que podrían venir malos para no caer por schema
805
        $this->sanitizar($datos);
806
    }
807
808
    /**
809
     * Método que normaliza los datos de una factura electrónica
810
     * @param datos Arreglo con los datos del documento que se desean normalizar
811
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
812
     * @version 2017-09-01
813
     */
814
    private function normalizar_33(array &$datos)
815
    {
816
        // completar con nodos por defecto
817
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
818
            'Encabezado' => [
819
                'IdDoc' => false,
820
                'Emisor' => false,
821
                'RUTMandante' => false,
822
                'Receptor' => false,
823
                'RUTSolicita' => false,
824
                'Transporte' => false,
825
                'Totales' => [
826
                    'MntNeto' => 0,
827
                    'MntExe' => false,
828
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
829
                    'IVA' => 0,
830
                    'ImptoReten' => false,
831
                    'CredEC' => false,
832
                    'MntTotal' => 0,
833
                ],
834
                'OtraMoneda' => false,
835
            ],
836
        ], $datos);
837
        // normalizar datos
838
        $this->normalizar_detalle($datos);
839
        $this->normalizar_aplicar_descuentos_recargos($datos);
840
        $this->normalizar_impuesto_retenido($datos);
841
        $this->normalizar_agregar_IVA_MntTotal($datos);
842
        $this->normalizar_transporte($datos);
843
    }
844
845
    /**
846
     * Método que normaliza los datos de una factura exenta electrónica
847
     * @param datos Arreglo con los datos del documento que se desean normalizar
848
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
849
     * @version 2017-02-23
850
     */
851
    private function normalizar_34(array &$datos)
852
    {
853
        // completar con nodos por defecto
854
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
855
            'Encabezado' => [
856
                'IdDoc' => false,
857
                'Emisor' => false,
858
                'Receptor' => false,
859
                'RUTSolicita' => false,
860
                'Totales' => [
861
                    'MntExe' => false,
862
                    'MntTotal' => 0,
863
                ]
864
            ],
865
        ], $datos);
866
        // normalizar datos
867
        $this->normalizar_detalle($datos);
868
        $this->normalizar_aplicar_descuentos_recargos($datos);
869
        $this->normalizar_agregar_IVA_MntTotal($datos);
870
    }
871
872
    /**
873
     * Método que normaliza los datos de una boleta electrónica
874
     * @param datos Arreglo con los datos del documento que se desean normalizar
875
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
876
     * @version 2020-10-12
877
     */
878
    private function normalizar_39(array &$datos)
879
    {
880
        // completar con nodos por defecto
881
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
882
            'Encabezado' => [
883
                'IdDoc' => false,
884
                'Emisor' => [
885
                    'RUTEmisor' => false,
886
                    'RznSocEmisor' => false,
887
                    'GiroEmisor' => false,
888
                ],
889
                'Receptor' => false,
890
                'Totales' => [
891
                    'MntNeto' => false,
892
                    'MntExe' => false,
893
                    'IVA' => false,
894
                    'MntTotal' => 0,
895
                ]
896
            ],
897
        ], $datos);
898
        // normalizar datos
899
        $this->normalizar_boletas($datos);
900
        $this->normalizar_detalle($datos);
901
        $this->normalizar_aplicar_descuentos_recargos($datos);
902
        $this->normalizar_agregar_IVA_MntTotal($datos);
903
    }
904
905
    /**
906
     * Método que normaliza los datos de una boleta exenta electrónica
907
     * @param datos Arreglo con los datos del documento que se desean normalizar
908
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
909
     * @version 2016-03-14
910
     */
911
    private function normalizar_41(array &$datos)
912
    {
913
        // completar con nodos por defecto
914
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
915
            'Encabezado' => [
916
                'IdDoc' => false,
917
                'Emisor' => [
918
                    'RUTEmisor' => false,
919
                    'RznSocEmisor' => false,
920
                    'GiroEmisor' => false,
921
                ],
922
                'Receptor' => false,
923
                'Totales' => [
924
                    'MntExe' => 0,
925
                    'MntTotal' => 0,
926
                ]
927
            ],
928
        ], $datos);
929
        // normalizar datos
930
        $this->normalizar_boletas($datos);
931
        $this->normalizar_detalle($datos);
932
        $this->normalizar_aplicar_descuentos_recargos($datos);
933
        $this->normalizar_agregar_IVA_MntTotal($datos);
934
    }
935
936
    /**
937
     * Método que normaliza los datos de una factura de compra electrónica
938
     * @param datos Arreglo con los datos del documento que se desean normalizar
939
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
940
     * @version 2016-02-26
941
     */
942
    private function normalizar_46(array &$datos)
943
    {
944
        // completar con nodos por defecto
945
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
946
            'Encabezado' => [
947
                'IdDoc' => false,
948
                'Emisor' => false,
949
                'Receptor' => false,
950
                'RUTSolicita' => false,
951
                'Totales' => [
952
                    'MntNeto' => 0,
953
                    'MntExe' => false,
954
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
955
                    'IVA' => 0,
956
                    'ImptoReten' => false,
957
                    'IVANoRet' => false,
958
                    'MntTotal' => 0,
959
                ]
960
            ],
961
        ], $datos);
962
        // normalizar datos
963
        $this->normalizar_detalle($datos);
964
        $this->normalizar_aplicar_descuentos_recargos($datos);
965
        $this->normalizar_impuesto_retenido($datos);
966
        $this->normalizar_agregar_IVA_MntTotal($datos);
967
    }
968
969
    /**
970
     * Método que normaliza los datos de una guía de despacho electrónica
971
     * @param datos Arreglo con los datos del documento que se desean normalizar
972
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
973
     * @version 2017-09-01
974
     */
975
    private function normalizar_52(array &$datos)
976
    {
977
        // completar con nodos por defecto
978
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
979
            'Encabezado' => [
980
                'IdDoc' => false,
981
                'Emisor' => false,
982
                'Receptor' => false,
983
                'RUTSolicita' => false,
984
                'Transporte' => false,
985
                'Totales' => [
986
                    'MntNeto' => 0,
987
                    'MntExe' => false,
988
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
989
                    'IVA' => 0,
990
                    'ImptoReten' => false,
991
                    'CredEC' => false,
992
                    'MntTotal' => 0,
993
                ]
994
            ],
995
        ], $datos);
996
        // si es traslado interno se copia el emisor en el receptor sólo si el
997
        // receptor no está definido o bien si el receptor tiene RUT diferente
998
        // al emisor
999
        if ($datos['Encabezado']['IdDoc']['IndTraslado']==5) {
1000
            if (!$datos['Encabezado']['Receptor'] or $datos['Encabezado']['Receptor']['RUTRecep']!=$datos['Encabezado']['Emisor']['RUTEmisor']) {
1001
                $datos['Encabezado']['Receptor'] = [];
1002
                $cols = [
1003
                    'RUTEmisor'=>'RUTRecep',
1004
                    'RznSoc'=>'RznSocRecep',
1005
                    'GiroEmis'=>'GiroRecep',
1006
                    'Telefono'=>'Contacto',
1007
                    'CorreoEmisor'=>'CorreoRecep',
1008
                    'DirOrigen'=>'DirRecep',
1009
                    'CmnaOrigen'=>'CmnaRecep',
1010
                ];
1011
                foreach ($cols as $emisor => $receptor) {
1012
                    if (!empty($datos['Encabezado']['Emisor'][$emisor])) {
1013
                        $datos['Encabezado']['Receptor'][$receptor] = $datos['Encabezado']['Emisor'][$emisor];
1014
                    }
1015
                }
1016 View Code Duplication
                if (!empty($datos['Encabezado']['Receptor']['GiroRecep'])) {
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...
1017
                    $datos['Encabezado']['Receptor']['GiroRecep'] = mb_substr($datos['Encabezado']['Receptor']['GiroRecep'], 0, 40);
1018
                }
1019
            }
1020
        }
1021
        // normalizar datos
1022
        $this->normalizar_detalle($datos);
1023
        $this->normalizar_aplicar_descuentos_recargos($datos);
1024
        $this->normalizar_impuesto_retenido($datos);
1025
        $this->normalizar_agregar_IVA_MntTotal($datos);
1026
        $this->normalizar_transporte($datos);
1027
    }
1028
1029
    /**
1030
     * Método que normaliza los datos de una nota de débito
1031
     * @param datos Arreglo con los datos del documento que se desean normalizar
1032
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1033
     * @version 2017-02-23
1034
     */
1035 View Code Duplication
    private function normalizar_56(array &$datos)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1036
    {
1037
        // completar con nodos por defecto
1038
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1039
            'Encabezado' => [
1040
                'IdDoc' => false,
1041
                'Emisor' => false,
1042
                'Receptor' => false,
1043
                'RUTSolicita' => false,
1044
                'Totales' => [
1045
                    'MntNeto' => 0,
1046
                    'MntExe' => 0,
1047
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
1048
                    'IVA' => false,
1049
                    'ImptoReten' => false,
1050
                    'IVANoRet' => false,
1051
                    'CredEC' => false,
1052
                    'MntTotal' => 0,
1053
                ]
1054
            ],
1055
        ], $datos);
1056
        // normalizar datos
1057
        $this->normalizar_detalle($datos);
1058
        $this->normalizar_aplicar_descuentos_recargos($datos);
1059
        $this->normalizar_impuesto_retenido($datos);
1060
        $this->normalizar_agregar_IVA_MntTotal($datos);
1061
        if (!$datos['Encabezado']['Totales']['MntNeto']) {
1062
            $datos['Encabezado']['Totales']['MntNeto'] = 0;
1063
            $datos['Encabezado']['Totales']['TasaIVA'] = false;
1064
        }
1065
    }
1066
1067
    /**
1068
     * Método que normaliza los datos de una nota de crédito
1069
     * @param datos Arreglo con los datos del documento que se desean normalizar
1070
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1071
     * @version 2017-02-23
1072
     */
1073 View Code Duplication
    private function normalizar_61(array &$datos)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1074
    {
1075
        // completar con nodos por defecto
1076
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1077
            'Encabezado' => [
1078
                'IdDoc' => false,
1079
                'Emisor' => false,
1080
                'Receptor' => false,
1081
                'RUTSolicita' => false,
1082
                'Totales' => [
1083
                    'MntNeto' => 0,
1084
                    'MntExe' => 0,
1085
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
1086
                    'IVA' => false,
1087
                    'ImptoReten' => false,
1088
                    'IVANoRet' => false,
1089
                    'CredEC' => false,
1090
                    'MntTotal' => 0,
1091
                ]
1092
            ],
1093
        ], $datos);
1094
        // normalizar datos
1095
        $this->normalizar_detalle($datos);
1096
        $this->normalizar_aplicar_descuentos_recargos($datos);
1097
        $this->normalizar_impuesto_retenido($datos);
1098
        $this->normalizar_agregar_IVA_MntTotal($datos);
1099
        if (!$datos['Encabezado']['Totales']['MntNeto']) {
1100
            $datos['Encabezado']['Totales']['MntNeto'] = 0;
1101
            $datos['Encabezado']['Totales']['TasaIVA'] = false;
1102
        }
1103
    }
1104
1105
    /**
1106
     * Método que normaliza los datos de una factura electrónica de exportación
1107
     * @param datos Arreglo con los datos del documento que se desean normalizar
1108
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1109
     * @version 2016-04-05
1110
     */
1111 View Code Duplication
    private function normalizar_110(array &$datos)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1112
    {
1113
        // completar con nodos por defecto
1114
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1115
            'Encabezado' => [
1116
                'IdDoc' => false,
1117
                'Emisor' => false,
1118
                'Receptor' => false,
1119
                'Transporte' => [
1120
                    'Patente' => false,
1121
                    'RUTTrans' => false,
1122
                    'Chofer' => false,
1123
                    'DirDest' => false,
1124
                    'CmnaDest' => false,
1125
                    'CiudadDest' => false,
1126
                    'Aduana' => [
1127
                        'CodModVenta' => false,
1128
                        'CodClauVenta' => false,
1129
                        'TotClauVenta' => false,
1130
                        'CodViaTransp' => false,
1131
                        'NombreTransp' => false,
1132
                        'RUTCiaTransp' => false,
1133
                        'NomCiaTransp' => false,
1134
                        'IdAdicTransp' => false,
1135
                        'Booking' => false,
1136
                        'Operador' => false,
1137
                        'CodPtoEmbarque' => false,
1138
                        'IdAdicPtoEmb' => false,
1139
                        'CodPtoDesemb' => false,
1140
                        'IdAdicPtoDesemb' => false,
1141
                        'Tara' => false,
1142
                        'CodUnidMedTara' => false,
1143
                        'PesoBruto' => false,
1144
                        'CodUnidPesoBruto' => false,
1145
                        'PesoNeto' => false,
1146
                        'CodUnidPesoNeto' => false,
1147
                        'TotItems' => false,
1148
                        'TotBultos' => false,
1149
                        'TipoBultos' => false,
1150
                        'MntFlete' => false,
1151
                        'MntSeguro' => false,
1152
                        'CodPaisRecep' => false,
1153
                        'CodPaisDestin' => false,
1154
                    ],
1155
                ],
1156
                'Totales' => [
1157
                    'TpoMoneda' => null,
1158
                    'MntExe' => 0,
1159
                    'MntTotal' => 0,
1160
                ]
1161
            ],
1162
        ], $datos);
1163
        // normalizar datos
1164
        $this->normalizar_detalle($datos);
1165
        $this->normalizar_aplicar_descuentos_recargos($datos);
1166
        $this->normalizar_impuesto_retenido($datos);
1167
        $this->normalizar_agregar_IVA_MntTotal($datos);
1168
        $this->normalizar_exportacion($datos);
1169
    }
1170
1171
    /**
1172
     * Método que normaliza los datos de una nota de débito de exportación
1173
     * @param datos Arreglo con los datos del documento que se desean normalizar
1174
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1175
     * @version 2016-04-05
1176
     */
1177 View Code Duplication
    private function normalizar_111(array &$datos)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1178
    {
1179
        // completar con nodos por defecto
1180
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1181
            'Encabezado' => [
1182
                'IdDoc' => false,
1183
                'Emisor' => false,
1184
                'Receptor' => false,
1185
                'Transporte' => [
1186
                    'Patente' => false,
1187
                    'RUTTrans' => false,
1188
                    'Chofer' => false,
1189
                    'DirDest' => false,
1190
                    'CmnaDest' => false,
1191
                    'CiudadDest' => false,
1192
                    'Aduana' => [
1193
                        'CodModVenta' => false,
1194
                        'CodClauVenta' => false,
1195
                        'TotClauVenta' => false,
1196
                        'CodViaTransp' => false,
1197
                        'NombreTransp' => false,
1198
                        'RUTCiaTransp' => false,
1199
                        'NomCiaTransp' => false,
1200
                        'IdAdicTransp' => false,
1201
                        'Booking' => false,
1202
                        'Operador' => false,
1203
                        'CodPtoEmbarque' => false,
1204
                        'IdAdicPtoEmb' => false,
1205
                        'CodPtoDesemb' => false,
1206
                        'IdAdicPtoDesemb' => false,
1207
                        'Tara' => false,
1208
                        'CodUnidMedTara' => false,
1209
                        'PesoBruto' => false,
1210
                        'CodUnidPesoBruto' => false,
1211
                        'PesoNeto' => false,
1212
                        'CodUnidPesoNeto' => false,
1213
                        'TotItems' => false,
1214
                        'TotBultos' => false,
1215
                        'TipoBultos' => false,
1216
                        'MntFlete' => false,
1217
                        'MntSeguro' => false,
1218
                        'CodPaisRecep' => false,
1219
                        'CodPaisDestin' => false,
1220
                    ],
1221
                ],
1222
                'Totales' => [
1223
                    'TpoMoneda' => null,
1224
                    'MntExe' => 0,
1225
                    'MntTotal' => 0,
1226
                ]
1227
            ],
1228
        ], $datos);
1229
        // normalizar datos
1230
        $this->normalizar_detalle($datos);
1231
        $this->normalizar_aplicar_descuentos_recargos($datos);
1232
        $this->normalizar_impuesto_retenido($datos);
1233
        $this->normalizar_agregar_IVA_MntTotal($datos);
1234
        $this->normalizar_exportacion($datos);
1235
    }
1236
1237
    /**
1238
     * Método que normaliza los datos de una nota de crédito de exportación
1239
     * @param datos Arreglo con los datos del documento que se desean normalizar
1240
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1241
     * @version 2016-04-05
1242
     */
1243 View Code Duplication
    private function normalizar_112(array &$datos)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1244
    {
1245
        // completar con nodos por defecto
1246
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1247
            'Encabezado' => [
1248
                'IdDoc' => false,
1249
                'Emisor' => false,
1250
                'Receptor' => false,
1251
                'Transporte' => [
1252
                    'Patente' => false,
1253
                    'RUTTrans' => false,
1254
                    'Chofer' => false,
1255
                    'DirDest' => false,
1256
                    'CmnaDest' => false,
1257
                    'CiudadDest' => false,
1258
                    'Aduana' => [
1259
                        'CodModVenta' => false,
1260
                        'CodClauVenta' => false,
1261
                        'TotClauVenta' => false,
1262
                        'CodViaTransp' => false,
1263
                        'NombreTransp' => false,
1264
                        'RUTCiaTransp' => false,
1265
                        'NomCiaTransp' => false,
1266
                        'IdAdicTransp' => false,
1267
                        'Booking' => false,
1268
                        'Operador' => false,
1269
                        'CodPtoEmbarque' => false,
1270
                        'IdAdicPtoEmb' => false,
1271
                        'CodPtoDesemb' => false,
1272
                        'IdAdicPtoDesemb' => false,
1273
                        'Tara' => false,
1274
                        'CodUnidMedTara' => false,
1275
                        'PesoBruto' => false,
1276
                        'CodUnidPesoBruto' => false,
1277
                        'PesoNeto' => false,
1278
                        'CodUnidPesoNeto' => false,
1279
                        'TotItems' => false,
1280
                        'TotBultos' => false,
1281
                        'TipoBultos' => false,
1282
                        'MntFlete' => false,
1283
                        'MntSeguro' => false,
1284
                        'CodPaisRecep' => false,
1285
                        'CodPaisDestin' => false,
1286
                    ],
1287
                ],
1288
                'Totales' => [
1289
                    'TpoMoneda' => null,
1290
                    'MntExe' => 0,
1291
                    'MntTotal' => 0,
1292
                ]
1293
            ],
1294
        ], $datos);
1295
        // normalizar datos
1296
        $this->normalizar_detalle($datos);
1297
        $this->normalizar_aplicar_descuentos_recargos($datos);
1298
        $this->normalizar_impuesto_retenido($datos);
1299
        $this->normalizar_agregar_IVA_MntTotal($datos);
1300
        $this->normalizar_exportacion($datos);
1301
    }
1302
1303
    /**
1304
     * Método que normaliza los datos de exportacion de un documento
1305
     * @param datos Arreglo con los datos del documento que se desean normalizar
1306
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1307
     * @version 2017-10-15
1308
     */
1309
    public function normalizar_exportacion(array &$datos)
1310
    {
1311
        // agregar modalidad de venta por defecto si no existe
1312
        if (empty($datos['Encabezado']['Transporte']['Aduana']['CodModVenta']) and (!isset($datos['Encabezado']['IdDoc']['IndServicio']) or !in_array($datos['Encabezado']['IdDoc']['IndServicio'], [3, 4, 5]))) {
1313
            $datos['Encabezado']['Transporte']['Aduana']['CodModVenta'] = 1;
1314
        }
1315
        // quitar campos que no son parte del documento de exportacion
1316
        $datos['Encabezado']['Receptor']['CmnaRecep'] = false;
1317
        // colocar forma de pago de exportación
1318
        if (!empty($datos['Encabezado']['IdDoc']['FmaPago'])) {
1319
            $formas = [3 => 21];
1320
            if (isset($formas[$datos['Encabezado']['IdDoc']['FmaPago']])) {
1321
                $datos['Encabezado']['IdDoc']['FmaPagExp'] = $formas[$datos['Encabezado']['IdDoc']['FmaPago']];
1322
            }
1323
            $datos['Encabezado']['IdDoc']['FmaPago'] = false;
1324
        }
1325
        // si es entrega gratuita se coloca el tipo de cambio en CLP en 0 para que total sea 0
1326
        if (!empty($datos['Encabezado']['IdDoc']['FmaPagExp']) and $datos['Encabezado']['IdDoc']['FmaPagExp']==21 and !empty($datos['Encabezado']['OtraMoneda'])) {
1327 View Code Duplication
            if (!isset($datos['Encabezado']['OtraMoneda'][0])) {
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...
1328
                $datos['Encabezado']['OtraMoneda'] = [$datos['Encabezado']['OtraMoneda']];
1329
            }
1330
            foreach ($datos['Encabezado']['OtraMoneda'] as &$OtraMoneda) {
1331
                if ($OtraMoneda['TpoMoneda']=='PESO CL') {
1332
                    $OtraMoneda['TpoCambio'] = 0;
1333
                }
1334
            }
1335
        }
1336
    }
1337
1338
    /**
1339
     * Método que normaliza los detalles del documento
1340
     * @param datos Arreglo con los datos del documento que se desean normalizar
1341
     * @warning Revisar como se aplican descuentos y recargos, ¿debería ser un porcentaje del monto original?
1342
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1343
     * @version 2017-07-24
1344
     */
1345
    private function normalizar_detalle(array &$datos)
1346
    {
1347
        if (!isset($datos['Detalle'][0]))
1348
            $datos['Detalle'] = [$datos['Detalle']];
1349
        $item = 1;
1350
        foreach ($datos['Detalle'] as &$d) {
1351
            $d = array_merge([
1352
                'NroLinDet' => $item++,
1353
                'CdgItem' => false,
1354
                'IndExe' => false,
1355
                'Retenedor' => false,
1356
                'NmbItem' => false,
1357
                'DscItem' => false,
1358
                'QtyRef' => false,
1359
                'UnmdRef' => false,
1360
                'PrcRef' => false,
1361
                'QtyItem' => false,
1362
                'Subcantidad' => false,
1363
                'FchElabor' => false,
1364
                'FchVencim' => false,
1365
                'UnmdItem' => false,
1366
                'PrcItem' => false,
1367
                'DescuentoPct' => false,
1368
                'DescuentoMonto' => false,
1369
                'RecargoPct' => false,
1370
                'RecargoMonto' => false,
1371
                'CodImpAdic' => false,
1372
                'MontoItem' => false,
1373
            ], $d);
1374
            // corregir datos
1375
            $d['NmbItem'] = mb_substr($d['NmbItem'], 0, 80);
1376
            if (!empty($d['DscItem'])) {
1377
                $d['DscItem'] = mb_substr($d['DscItem'], 0, 1000);
1378
            }
1379
            // normalizar
1380
            if ($this->esExportacion()) {
1381
                $d['IndExe'] = 1;
1382
            }
1383
            if (is_array($d['CdgItem'])) {
1384
                $d['CdgItem'] = array_merge([
1385
                    'TpoCodigo' => false,
1386
                    'VlrCodigo' => false,
1387
                ], $d['CdgItem']);
1388
                if ($d['Retenedor']===false and $d['CdgItem']['TpoCodigo']=='CPCS') {
1389
                    $d['Retenedor'] = true;
1390
                }
1391
            }
1392
            if ($d['Retenedor']!==false) {
1393
                if (!is_array($d['Retenedor'])) {
1394
                    $d['Retenedor'] = ['IndAgente'=>'R'];
1395
                }
1396
                $d['Retenedor'] = array_merge([
1397
                    'IndAgente' => 'R',
1398
                    'MntBaseFaena' => false,
1399
                    'MntMargComer' => false,
1400
                    'PrcConsFinal' => false,
1401
                ], $d['Retenedor']);
1402
            }
1403
            if ($d['CdgItem']!==false and !is_array($d['CdgItem'])) {
1404
                $d['CdgItem'] = [
1405
                    'TpoCodigo' => empty($d['Retenedor']['IndAgente']) ? 'INT1' : 'CPCS',
1406
                    'VlrCodigo' => $d['CdgItem'],
1407
                ];
1408
            }
1409
            if ($d['PrcItem']) {
1410
                if (!$d['QtyItem'])
1411
                    $d['QtyItem'] = 1;
1412
                if (empty($d['MontoItem'])) {
1413
                    $d['MontoItem'] = $this->round(
1414
                        (float)$d['QtyItem'] * (float)$d['PrcItem'],
0 ignored issues
show
Documentation introduced by
(double) $d['QtyItem'] * (double) $d['PrcItem'] is of type double, but the function expects a object<sasco\LibreDTE\Sii\Valor>.

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...
1415
                        $datos['Encabezado']['Totales']['TpoMoneda']
1416
                    );
1417
                    // aplicar descuento
1418
                    if ($d['DescuentoPct']) {
1419
                        $d['DescuentoMonto'] = round($d['MontoItem'] * (float)$d['DescuentoPct']/100);
1420
                    }
1421
                    $d['MontoItem'] -= $d['DescuentoMonto'];
1422
                    // aplicar recargo
1423
                    if ($d['RecargoPct']) {
1424
                        $d['RecargoMonto'] = round($d['MontoItem'] * (float)$d['RecargoPct']/100);
1425
                    }
1426
                    $d['MontoItem'] += $d['RecargoMonto'];
1427
                    // aproximar monto del item
1428
                    $d['MontoItem'] = $this->round(
1429
                        $d['MontoItem'], $datos['Encabezado']['Totales']['TpoMoneda']
1430
                    );
1431
                }
1432
            } else if (empty($d['MontoItem'])) {
1433
                $d['MontoItem'] = 0;
1434
            }
1435
            // sumar valor del monto a MntNeto o MntExe según corresponda
1436
            if ($d['MontoItem']) {
1437
                // si no es boleta
1438
                if (!$this->esBoleta()) {
1439
                    if ((!isset($datos['Encabezado']['Totales']['MntNeto']) or $datos['Encabezado']['Totales']['MntNeto']===false) and isset($datos['Encabezado']['Totales']['MntExe'])) {
1440
                        $datos['Encabezado']['Totales']['MntExe'] += $d['MontoItem'];
1441 View Code Duplication
                    } else {
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...
1442
                        if (!empty($d['IndExe'])) {
1443
                            if ($d['IndExe']==1) {
1444
                                $datos['Encabezado']['Totales']['MntExe'] += $d['MontoItem'];
1445
                            }
1446
                        } else {
1447
                            $datos['Encabezado']['Totales']['MntNeto'] += $d['MontoItem'];
1448
                        }
1449
                    }
1450
                }
1451
                // si es boleta
1452 View Code Duplication
                else {
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...
1453
                    // si es exento
1454
                    if (!empty($d['IndExe'])) {
1455
                        if ($d['IndExe']==1) {
1456
                            $datos['Encabezado']['Totales']['MntExe'] += $d['MontoItem'];
1457
                        }
1458
                    }
1459
                    // agregar al monto total
1460
                    $datos['Encabezado']['Totales']['MntTotal'] += $d['MontoItem'];
1461
                }
1462
            }
1463
        }
1464
    }
1465
1466
    /**
1467
     * Método que aplica los descuentos y recargos generales respectivos a los
1468
     * montos que correspondan según e indicador del descuento o recargo
1469
     * @param datos Arreglo con los datos del documento que se desean normalizar
1470
     * @warning Boleta afecta con algún item exento el descuento se podría estar aplicando mal
1471
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1472
     * @version 2017-09-06
1473
     */
1474
    private function normalizar_aplicar_descuentos_recargos(array &$datos)
1475
    {
1476
        if (!empty($datos['DscRcgGlobal'])) {
1477 View Code Duplication
            if (!isset($datos['DscRcgGlobal'][0]))
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...
1478
                $datos['DscRcgGlobal'] = [$datos['DscRcgGlobal']];
1479
            foreach ($datos['DscRcgGlobal'] as &$dr) {
1480
                $dr = array_merge([
1481
                    'NroLinDR' => false,
1482
                    'TpoMov' => false,
1483
                    'GlosaDR' => false,
1484
                    'TpoValor' => false,
1485
                    'ValorDR' => false,
1486
                    'ValorDROtrMnda' => false,
1487
                    'IndExeDR' => false,
1488
                ], $dr);
1489
                if ($this->esExportacion()) {
1490
                    $dr['IndExeDR'] = 1;
1491
                }
1492
                // determinar a que aplicar el descuento/recargo
1493
                if (!isset($dr['IndExeDR']) or $dr['IndExeDR']===false) {
1494
                    $monto = $this->getTipo()==39 ? 'MntTotal' : 'MntNeto';
1495
                } else if ($dr['IndExeDR']==1) {
1496
                    $monto = 'MntExe';
1497
                } else if ($dr['IndExeDR']==2) {
1498
                    $monto = 'MontoNF';
1499
                }
1500
                // si no hay monto al que aplicar el descuento se omite
1501
                if (empty($datos['Encabezado']['Totales'][$monto])) {
1502
                    continue;
1503
                }
1504
                // calcular valor del descuento o recargo
1505
                if ($dr['TpoValor']=='$') {
1506
                    $dr['ValorDR'] = $this->round($dr['ValorDR'], $datos['Encabezado']['Totales']['TpoMoneda'], 2);
1507
                }
1508
                $valor =
1509
                    $dr['TpoValor']=='%'
1510
                    ? $this->round(($dr['ValorDR']/100)*$datos['Encabezado']['Totales'][$monto], $datos['Encabezado']['Totales']['TpoMoneda'])
0 ignored issues
show
Bug introduced by
The variable $monto does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Documentation introduced by
$dr['ValorDR'] / 100 * $...do']['Totales'][$monto] is of type integer|double, but the function expects a object<sasco\LibreDTE\Sii\Valor>.

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...
1511
                    : $dr['ValorDR']
1512
                ;
1513
                // aplicar descuento
1514
                if ($dr['TpoMov']=='D') {
1515
                    $datos['Encabezado']['Totales'][$monto] -= $valor;
1516
                }
1517
                // aplicar recargo
1518
                else if ($dr['TpoMov']=='R') {
1519
                    $datos['Encabezado']['Totales'][$monto] += $valor;
1520
                }
1521
                $datos['Encabezado']['Totales'][$monto] = $this->round(
1522
                    $datos['Encabezado']['Totales'][$monto],
1523
                    $datos['Encabezado']['Totales']['TpoMoneda']
1524
                );
1525
                // si el descuento global se aplica a una boleta exenta se copia el valor exento al total
1526
                if ($this->getTipo()==41 and isset($dr['IndExeDR']) and $dr['IndExeDR']==1) {
1527
                    $datos['Encabezado']['Totales']['MntTotal'] = $datos['Encabezado']['Totales']['MntExe'];
1528
                }
1529
            }
1530
        }
1531
    }
1532
1533
    /**
1534
     * Método que calcula los montos de impuestos adicionales o retenciones
1535
     * @param datos Arreglo con los datos del documento que se desean normalizar
1536
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1537
     * @version 2016-04-05
1538
     */
1539
    private function normalizar_impuesto_retenido(array &$datos)
1540
    {
1541
        // copiar montos
1542
        $montos = [];
1543
        foreach ($datos['Detalle'] as &$d) {
1544
            if (!empty($d['CodImpAdic'])) {
1545
                if (!isset($montos[$d['CodImpAdic']]))
1546
                    $montos[$d['CodImpAdic']] = 0;
1547
                $montos[$d['CodImpAdic']] += $d['MontoItem'];
1548
            }
1549
        }
1550
        // si hay montos y no hay total para impuesto retenido se arma
1551
        if (!empty($montos)) {
1552 View Code Duplication
            if (!is_array($datos['Encabezado']['Totales']['ImptoReten'])) {
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...
1553
                $datos['Encabezado']['Totales']['ImptoReten'] = [];
1554
            } else if (!isset($datos['Encabezado']['Totales']['ImptoReten'][0])) {
1555
                $datos['Encabezado']['Totales']['ImptoReten'] = [$datos['Encabezado']['Totales']['ImptoReten']];
1556
            }
1557
        }
1558
        // armar impuesto adicional o retención en los totales
1559
        foreach ($montos as $codigo => $neto) {
1560
            // buscar si existe el impuesto en los totales
1561
            $i = 0;
1562
            foreach ($datos['Encabezado']['Totales']['ImptoReten'] as &$ImptoReten) {
1563
                if ($ImptoReten['TipoImp']==$codigo) {
1564
                    break;
1565
                }
1566
                $i++;
1567
            }
1568
            // si no existe se crea
1569 View Code Duplication
            if (!isset($datos['Encabezado']['Totales']['ImptoReten'][$i])) {
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...
1570
                $datos['Encabezado']['Totales']['ImptoReten'][] = [
1571
                    'TipoImp' => $codigo
1572
                ];
1573
            }
1574
            // se normaliza
1575
            $datos['Encabezado']['Totales']['ImptoReten'][$i] = array_merge([
1576
                'TipoImp' => $codigo,
1577
                'TasaImp' => ImpuestosAdicionales::getTasa($codigo),
1578
                'MontoImp' => null,
1579
            ], $datos['Encabezado']['Totales']['ImptoReten'][$i]);
1580
            // si el monto no existe se asigna
1581
            if ($datos['Encabezado']['Totales']['ImptoReten'][$i]['MontoImp']===null) {
1582
                $datos['Encabezado']['Totales']['ImptoReten'][$i]['MontoImp'] = round(
1583
                    $neto * $datos['Encabezado']['Totales']['ImptoReten'][$i]['TasaImp']/100
1584
                );
1585
            }
1586
        }
1587
        // quitar los codigos que no existen en el detalle
1588
        if (isset($datos['Encabezado']['Totales']['ImptoReten']) and is_array($datos['Encabezado']['Totales']['ImptoReten'])) {
1589
            $codigos = array_keys($montos);
1590
            $n_impuestos = count($datos['Encabezado']['Totales']['ImptoReten']);
1591
            for ($i=0; $i<$n_impuestos; $i++) {
1592 View Code Duplication
                if (!in_array($datos['Encabezado']['Totales']['ImptoReten'][$i]['TipoImp'], $codigos)) {
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...
1593
                    unset($datos['Encabezado']['Totales']['ImptoReten'][$i]);
1594
                }
1595
            }
1596
            sort($datos['Encabezado']['Totales']['ImptoReten']);
1597
        }
1598
    }
1599
1600
    /**
1601
     * Método que calcula el monto del IVA y el monto total del documento a
1602
     * partir del monto neto y la tasa de IVA si es que existe
1603
     * @param datos Arreglo con los datos del documento que se desean normalizar
1604
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1605
     * @version 2020-10-12
1606
     */
1607
    private function normalizar_agregar_IVA_MntTotal(array &$datos)
1608
    {
1609
        // si es una boleta y no están los datos de monto neto ni IVA se obtienen
1610
        // WARNING: no considera los casos donde hay impuestos adicionales en las boletas
1611
        //          si la boleta tiene impuestos adicionales, se deben indicar MntNeto e IVA
1612
        //          y no se usará esta parte de la normalización
1613
        // valor IndMntNeto = 2 indica que los montosde las líneas on netos en cuyo caso no aplica el cálculo
1614
        // de neto e iva a partir del total y deberá venir informado de otra forma (aun no definido)
1615
        if ($this->esBoleta() and (empty($datos['Encabezado']['IdDoc']['IndMntNeto']) or $datos['Encabezado']['IdDoc']['IndMntNeto']!=2)) {
1616
            $total = (int)$datos['Encabezado']['Totales']['MntTotal'] - (int)$datos['Encabezado']['Totales']['MntExe'];
1617
            if ($total and (empty($datos['Encabezado']['Totales']['MntNeto']) or empty($datos['Encabezado']['Totales']['IVA']))) {
1618
                list($datos['Encabezado']['Totales']['MntNeto'], $datos['Encabezado']['Totales']['IVA']) = $this->calcularNetoIVA($total);
0 ignored issues
show
Documentation introduced by
$total is of type integer, but the function expects a object<sasco\LibreDTE\Sii\neto>.

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...
1619
            }
1620
        }
1621
        // agregar IVA y monto total
1622
        if (!empty($datos['Encabezado']['Totales']['MntNeto'])) {
1623
            if ($datos['Encabezado']['IdDoc']['MntBruto']==1) {
1624
                list($datos['Encabezado']['Totales']['MntNeto'], $datos['Encabezado']['Totales']['IVA']) = $this->calcularNetoIVA(
1625
                    $datos['Encabezado']['Totales']['MntNeto'],
1626
                    $datos['Encabezado']['Totales']['TasaIVA']
1627
                );
1628
            } else {
1629
                if (empty($datos['Encabezado']['Totales']['IVA']) and !empty($datos['Encabezado']['Totales']['TasaIVA'])) {
1630
                    $datos['Encabezado']['Totales']['IVA'] = round(
1631
                        $datos['Encabezado']['Totales']['MntNeto']*($datos['Encabezado']['Totales']['TasaIVA']/100)
1632
                    );
1633
                }
1634
            }
1635
            if (empty($datos['Encabezado']['Totales']['MntTotal'])) {
1636
                $datos['Encabezado']['Totales']['MntTotal'] = $datos['Encabezado']['Totales']['MntNeto'];
1637
                if (!empty($datos['Encabezado']['Totales']['IVA'])) {
1638
                    $datos['Encabezado']['Totales']['MntTotal'] += $datos['Encabezado']['Totales']['IVA'];
1639
                }
1640
                if (!empty($datos['Encabezado']['Totales']['MntExe'])) {
1641
                    $datos['Encabezado']['Totales']['MntTotal'] += $datos['Encabezado']['Totales']['MntExe'];
1642
                }
1643
            }
1644 View Code Duplication
        } else {
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...
1645
            if (!$datos['Encabezado']['Totales']['MntTotal'] and !empty($datos['Encabezado']['Totales']['MntExe'])) {
1646
                $datos['Encabezado']['Totales']['MntTotal'] = $datos['Encabezado']['Totales']['MntExe'];
1647
            }
1648
        }
1649
        // si hay impuesto retenido o adicional se contabiliza en el total
1650
        if (!empty($datos['Encabezado']['Totales']['ImptoReten'])) {
1651
            foreach ($datos['Encabezado']['Totales']['ImptoReten'] as &$ImptoReten) {
1652
                // si es retención se resta al total y se traspasaa IVA no retenido
1653
                // en caso que corresponda
1654
                if (ImpuestosAdicionales::getTipo($ImptoReten['TipoImp'])=='R') {
1655
                    $datos['Encabezado']['Totales']['MntTotal'] -= $ImptoReten['MontoImp'];
1656
                    if ($ImptoReten['MontoImp']!=$datos['Encabezado']['Totales']['IVA']) {
1657
                        $datos['Encabezado']['Totales']['IVANoRet'] = $datos['Encabezado']['Totales']['IVA'] - $ImptoReten['MontoImp'];
1658
                    }
1659
                }
1660
                // si es adicional se suma al total
1661
                else if (ImpuestosAdicionales::getTipo($ImptoReten['TipoImp'])=='A' and isset($ImptoReten['MontoImp'])) {
1662
                    $datos['Encabezado']['Totales']['MntTotal'] += $ImptoReten['MontoImp'];
1663
                }
1664
            }
1665
        }
1666
        // si hay impuesto de crédito a constructoras del 65% se descuenta del total
1667
        if (!empty($datos['Encabezado']['Totales']['CredEC'])) {
1668
            if ($datos['Encabezado']['Totales']['CredEC']===true) {
1669
                $datos['Encabezado']['Totales']['CredEC'] = round($datos['Encabezado']['Totales']['IVA'] * 0.65); // TODO: mover a constante o método
1670
            }
1671
            $datos['Encabezado']['Totales']['MntTotal'] -= $datos['Encabezado']['Totales']['CredEC'];
1672
        }
1673
    }
1674
1675
    /**
1676
     * Método que normaliza los datos de transporte
1677
     * @param datos Arreglo con los datos del documento que se desean normalizar
1678
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1679
     * @version 2017-09-01
1680
     */
1681
    private function normalizar_transporte(array &$datos)
1682
    {
1683
        if (!empty($datos['Encabezado']['Transporte'])) {
1684
            $datos['Encabezado']['Transporte'] = array_merge([
1685
                'Patente' => false,
1686
                'RUTTrans' => false,
1687
                'Chofer' => false,
1688
                'DirDest' => false,
1689
                'CmnaDest' => false,
1690
                'CiudadDest' => false,
1691
                'Aduana' => false,
1692
            ], $datos['Encabezado']['Transporte']);
1693
        }
1694
    }
1695
1696
    /**
1697
     * Método que normaliza las boletas electrónicas, dte 39 y 41
1698
     * @param datos Arreglo con los datos del documento que se desean normalizar
1699
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1700
     * @version 2020-10-11
1701
     */
1702
    private function normalizar_boletas(array &$datos)
1703
    {
1704
        // cambiar tags de DTE a boleta si se pasaron
1705 View Code Duplication
        if ($datos['Encabezado']['Emisor']['RznSoc']) {
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...
1706
            $datos['Encabezado']['Emisor']['RznSocEmisor'] = $datos['Encabezado']['Emisor']['RznSoc'];
1707
            $datos['Encabezado']['Emisor']['RznSoc'] = false;
1708
        }
1709 View Code Duplication
        if ($datos['Encabezado']['Emisor']['GiroEmis']) {
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...
1710
            $datos['Encabezado']['Emisor']['GiroEmisor'] = $datos['Encabezado']['Emisor']['GiroEmis'];
1711
            $datos['Encabezado']['Emisor']['GiroEmis'] = false;
1712
        }
1713
        $datos['Encabezado']['Emisor']['Acteco'] = false;
1714
        $datos['Encabezado']['Emisor']['Telefono'] = false;
1715
        $datos['Encabezado']['Emisor']['CorreoEmisor'] = false;
1716
        $datos['Encabezado']['Emisor']['CdgVendedor'] = false;
1717
        $datos['Encabezado']['Receptor']['GiroRecep'] = false;
1718
        if (!empty($datos['Encabezado']['Receptor']['CorreoRecep'])) {
1719
            $datos['Referencia'][] = [
1720
                'NroLinRef' => !empty($datos['Referencia']) ? (count($datos['Referencia'])+1) : 1,
1721
                'RazonRef' => mb_substr('Email receptor: '.$datos['Encabezado']['Receptor']['CorreoRecep'], 0, 90),
1722
            ];
1723
        }
1724
        $datos['Encabezado']['Receptor']['CorreoRecep'] = false;
1725
        // quitar otros tags que no son parte de las boletas
1726
        $datos['Encabezado']['IdDoc']['FmaPago'] = false;
1727
        $datos['Encabezado']['IdDoc']['FchCancel'] = false;
1728
        $datos['Encabezado']['IdDoc']['MedioPago'] = false;
1729
        $datos['Encabezado']['IdDoc']['TpoCtaPago'] = false;
1730
        $datos['Encabezado']['IdDoc']['NumCtaPago'] = false;
1731
        $datos['Encabezado']['IdDoc']['BcoPago'] = false;
1732
        $datos['Encabezado']['IdDoc']['TermPagoGlosa'] = false;
1733
        $datos['Encabezado']['RUTSolicita'] = false;
1734
        $datos['Encabezado']['IdDoc']['TpoTranCompra'] = false;
1735
        $datos['Encabezado']['IdDoc']['TpoTranVenta'] = false;
1736
        $datos['Encabezado']['Transporte'] = false;
1737
        // ajustar las referencias si existen
1738
        if (!empty($datos['Referencia'])) {
1739 View Code Duplication
            if (!isset($datos['Referencia'][0])) {
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...
1740
                $datos['Referencia'] = [$datos['Referencia']];
1741
            }
1742
            foreach ($datos['Referencia'] as &$r) {
1743
                foreach (['FchRef'] as $c) {
1744
                    if (isset($r[$c])) {
1745
                        unset($r[$c]);
1746
                    }
1747
                }
1748
            }
1749
        }
1750
    }
1751
1752
    /**
1753
     * Método que limpia los datos, el objetivo es reducir los problemas por
1754
     * errores de esquema que se pueden dar por los datos enviados
1755
     * @param datos Arreglo con los datos del documento que se desean limpiar
1756
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1757
     * @version 2021-02-14
1758
     */
1759
    private function sanitizar(array &$datos)
1760
    {
1761
        // correcciones básicas
1762
        $datos['Encabezado']['Emisor']['RUTEmisor'] = strtoupper(trim(str_replace('.', '', $datos['Encabezado']['Emisor']['RUTEmisor'])));
1763
        $datos['Encabezado']['Receptor']['RUTRecep'] = strtoupper(trim(str_replace('.', '', $datos['Encabezado']['Receptor']['RUTRecep'])));
1764
        $datos['Encabezado']['Receptor']['RznSocRecep'] = mb_substr($datos['Encabezado']['Receptor']['RznSocRecep'], 0, 100);
1765 View Code Duplication
        if (!empty($datos['Encabezado']['Receptor']['GiroRecep'])) {
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...
1766
            $datos['Encabezado']['Receptor']['GiroRecep'] = mb_substr($datos['Encabezado']['Receptor']['GiroRecep'], 0, 40);
1767
        }
1768 View Code Duplication
        if (!empty($datos['Encabezado']['Receptor']['Contacto'])) {
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...
1769
            $datos['Encabezado']['Receptor']['Contacto'] = mb_substr($datos['Encabezado']['Receptor']['Contacto'], 0, 80);
1770
        }
1771 View Code Duplication
        if (!empty($datos['Encabezado']['Receptor']['CorreoRecep'])) {
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...
1772
            $datos['Encabezado']['Receptor']['CorreoRecep'] = mb_substr($datos['Encabezado']['Receptor']['CorreoRecep'], 0, 80);
1773
        }
1774 View Code Duplication
        if (!empty($datos['Encabezado']['Receptor']['DirRecep'])) {
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...
1775
            $datos['Encabezado']['Receptor']['DirRecep'] = mb_substr($datos['Encabezado']['Receptor']['DirRecep'], 0, 70);
1776
        }
1777 View Code Duplication
        if (!empty($datos['Encabezado']['Receptor']['CmnaRecep'])) {
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...
1778
            $datos['Encabezado']['Receptor']['CmnaRecep'] = mb_substr($datos['Encabezado']['Receptor']['CmnaRecep'], 0, 20);
1779
        }
1780
        if (!empty($datos['Encabezado']['Emisor']['Acteco'])) {
1781
            if (strlen((string)$datos['Encabezado']['Emisor']['Acteco'])==5) {
1782
                $datos['Encabezado']['Emisor']['Acteco'] = '0'.$datos['Encabezado']['Emisor']['Acteco'];
1783
            }
1784
        }
1785
        // correcciones más específicas
1786
        if (class_exists('\sasco\LibreDTE\Extra\Sii\Dte\VerificadorDatos')) {
1787
            \sasco\LibreDTE\Extra\Sii\Dte\VerificadorDatos::sanitize($datos);
1788
        }
1789
    }
1790
1791
    /**
1792
     * Método que valida los datos del DTE
1793
     * @return =true si no hay errores de validación, =false si se encontraron errores al validar
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...
1794
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1795
     * @version 2020-03-13
1796
     */
1797
    public function verificarDatos()
1798
    {
1799
        if (class_exists('\sasco\LibreDTE\Extra\Sii\Dte\VerificadorDatos')) {
1800
            if (!\sasco\LibreDTE\Extra\Sii\Dte\VerificadorDatos::check($this->getDatos())) {
1801
                return false;
1802
            }
1803
        }
1804
        return true;
1805
    }
1806
1807
    /**
1808
     * Método que redondea valores. Si los montos son en pesos chilenos se
1809
     * redondea, si no se mantienen todos los decimales
1810
     * @param valor Valor que se desea redondear
1811
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1812
     * @version 2016-04-05
1813
     */
1814
    private function round($valor, $moneda = false, $decimal = 4)
1815
    {
1816
        return (!$moneda or $moneda=='PESO CL') ? (int)round($valor) : (float)round($valor, $decimal);
1817
    }
1818
1819
    /**
1820
     * Método que determina el estado de validación sobre el DTE, se verifica:
1821
     *  - Firma del DTE
1822
     *  - RUT del emisor (si se pasó uno para comparar)
1823
     *  - RUT del receptor (si se pasó uno para comparar)
1824
     * @return Código del estado de la validación
1825
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1826
     * @version 2019-07-03
1827
     */
1828
    public function getEstadoValidacion(array $datos = null)
1829
    {
1830
        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...
1831
            return 1;
1832
        }
1833
        if (is_array($datos)) {
1834
            if (isset($datos['RUTEmisor']) and $this->getEmisor()!=$datos['RUTEmisor']) {
1835
                return 2;
1836
            }
1837
            if (isset($datos['RUTRecep']) and $this->getReceptor()!=$datos['RUTRecep']) {
1838
                return 3;
1839
            }
1840
        }
1841
        return 0;
1842
    }
1843
1844
    /**
1845
     * Método que indica si la firma del DTE es o no válida
1846
     * @return =true si la firma del DTE 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...
1847
     * @warning No se está verificando el valor del DigestValue del documento (sólo la firma de ese DigestValue)
1848
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1849
     * @version 2021-01-26
1850
     */
1851
    public function checkFirma()
1852
    {
1853
        if (!$this->xml) {
1854
            return null;
1855
        }
1856
        // obtener firma
1857
        $Signature = $this->xml->documentElement->getElementsByTagName('Signature')->item(0);
1858
        if (!$Signature) {
1859
            return null; // no viene el nodo Signature (XML del DTE no está firmado)
1860
        }
1861
        // preparar documento a validar
1862
        $D = $this->xml->documentElement->getElementsByTagName($this->tipo_general)->item(0);
1863
        $Documento = new \sasco\LibreDTE\XML();
1864
        $Documento->loadXML($D->C14N());
1865
        $Documento->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi');
1866
        $SignedInfo = new \sasco\LibreDTE\XML();
1867
        $SignedInfo->loadXML($Signature->getElementsByTagName('SignedInfo')->item(0)->C14N());
1868
        $SignedInfo->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi');
1869
        $DigestValue = $Signature->getElementsByTagName('DigestValue')->item(0)->nodeValue;
0 ignored issues
show
Unused Code introduced by
$DigestValue 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...
1870
        $SignatureValue = trim(str_replace(["\n", ' ', "\t"], '', $Signature->getElementsByTagName('SignatureValue')->item(0)->nodeValue));
1871
        $X509Certificate = trim(str_replace(["\n", ' ', "\t"], '', $Signature->getElementsByTagName('X509Certificate')->item(0)->nodeValue));
1872
        $X509Certificate = '-----BEGIN CERTIFICATE-----'."\n".wordwrap($X509Certificate, 64, "\n", true)."\n".'-----END CERTIFICATE----- ';
1873
        $valid = openssl_verify($SignedInfo->C14N(), base64_decode($SignatureValue), $X509Certificate) === 1 ? true : false;
1874
        return $valid;
1875
        //return $valid and $DigestValue===base64_encode(sha1($Documento->C14N(), true));
1876
    }
1877
1878
    /**
1879
     * Método que indica si el documento es o no cedible
1880
     * @return =true si el documento es cedible
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...
1881
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1882
     * @version 2015-09-10
1883
     */
1884
    public function esCedible()
1885
    {
1886
        return !in_array($this->getTipo(), $this->noCedibles);
1887
    }
1888
1889
    /**
1890
     * Método que indica si el documento es o no una boleta electrónica
1891
     * @return =true si el documento es una boleta electrónica
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...
1892
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1893
     * @version 2015-12-11
1894
     */
1895
    public function esBoleta()
1896
    {
1897
        return in_array($this->getTipo(), [39, 41]);
1898
    }
1899
1900
    /**
1901
     * Método que indica si el documento es o no una exportación
1902
     * @return =true si el documento es una exportación
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...
1903
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1904
     * @version 2016-04-05
1905
     */
1906
    public function esExportacion()
1907
    {
1908
        return in_array($this->getTipo(), $this->tipos['Exportaciones']);
1909
    }
1910
1911
    /**
1912
     * Método que valida el schema del DTE
1913
     * @return =true si el schema del documento del DTE es válido, =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...
1914
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1915
     * @version 2015-12-15
1916
     */
1917
    public function schemaValidate()
1918
    {
1919
        return true;
1920
    }
1921
1922
    /**
1923
     * Método que obtiene el estado del DTE
1924
     * @param Firma objeto que representa la Firma Electrónca
1925
     * @return Arreglo con el estado del DTE
1926
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1927
     * @version 2015-10-24
1928
     */
1929
    public function getEstado(\sasco\LibreDTE\FirmaElectronica $Firma)
1930
    {
1931
        // solicitar token
1932
        $token = \sasco\LibreDTE\Sii\Autenticacion::getToken($Firma);
0 ignored issues
show
Documentation introduced by
$Firma is of type object<sasco\LibreDTE\FirmaElectronica>, but the function expects a object<sasco\LibreDTE\Sii\objeto>|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...
1933
        if (!$token) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $token of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1934
            return false;
1935
        }
1936
        // consultar estado dte
1937
        $run = $Firma->getID();
1938
        if ($run===false) {
1939
            return false;
1940
        }
1941
        list($RutConsultante, $DvConsultante) = explode('-', $run);
1942
        list($RutCompania, $DvCompania) = explode('-', $this->getEmisor());
1943
        list($RutReceptor, $DvReceptor) = explode('-', $this->getReceptor());
1944
        list($Y, $m, $d) = explode('-', $this->getFechaEmision());
1945
        $xml = \sasco\LibreDTE\Sii::request('QueryEstDte', 'getEstDte', [
0 ignored issues
show
Documentation introduced by
'QueryEstDte' is of type string, but the function expects a object<sasco\LibreDTE\Nombre>.

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...
Documentation introduced by
'getEstDte' is of type string, but the function expects a object<sasco\LibreDTE\Nombre>.

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...
Documentation introduced by
array('RutConsultante' =...l(), 'token' => $token) is of type array<string,?,{"RutCons...to>","token":"string"}>, but the function expects a object<sasco\LibreDTE\Argumentos>|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...
1946
            'RutConsultante'  => $RutConsultante,
1947
            'DvConsultante'   => $DvConsultante,
1948
            'RutCompania'     => $RutCompania,
1949
            'DvCompania'      => $DvCompania,
1950
            'RutReceptor'     => $RutReceptor,
1951
            'DvReceptor'      => $DvReceptor,
1952
            'TipoDte'         => $this->getTipo(),
1953
            'FolioDte'        => $this->getFolio(),
1954
            'FechaEmisionDte' => $d.$m.$Y,
1955
            'MontoDte'        => $this->getMontoTotal(),
1956
            'token'           => $token,
1957
        ]);
1958
        // si el estado se pudo recuperar se muestra
1959
        if ($xml===false) {
1960
            return false;
1961
        }
1962
        // entregar estado
1963
        return (array)$xml->xpath('/SII:RESPUESTA/SII:RESP_HDR')[0];
1964
    }
1965
1966
    /**
1967
     * Método que obtiene el estado avanzado del DTE
1968
     * @param Firma objeto que representa la Firma Electrónca
1969
     * @return Arreglo con el estado del DTE
1970
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1971
     * @version 2016-08-05
1972
     */
1973
    public function getEstadoAvanzado(\sasco\LibreDTE\FirmaElectronica $Firma)
1974
    {
1975
        // solicitar token
1976
        $token = \sasco\LibreDTE\Sii\Autenticacion::getToken($Firma);
0 ignored issues
show
Documentation introduced by
$Firma is of type object<sasco\LibreDTE\FirmaElectronica>, but the function expects a object<sasco\LibreDTE\Sii\objeto>|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...
1977
        if (!$token) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $token of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1978
            return false;
1979
        }
1980
        // consultar estado dte
1981
        list($RutEmpresa, $DvEmpresa) = explode('-', $this->getEmisor());
1982
        list($RutReceptor, $DvReceptor) = explode('-', $this->getReceptor());
1983
        list($Y, $m, $d) = explode('-', $this->getFechaEmision());
1984
        $xml = \sasco\LibreDTE\Sii::request('QueryEstDteAv', 'getEstDteAv', [
0 ignored issues
show
Documentation introduced by
'QueryEstDteAv' is of type string, but the function expects a object<sasco\LibreDTE\Nombre>.

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...
Documentation introduced by
'getEstDteAv' is of type string, but the function expects a object<sasco\LibreDTE\Nombre>.

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...
Documentation introduced by
array('RutEmpresa' => $R...']), 'token' => $token) is of type array<string,?,{"RutEmpr...:"?","token":"string"}>, but the function expects a object<sasco\LibreDTE\Argumentos>|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...
1985
            'RutEmpresa'      => $RutEmpresa,
1986
            'DvEmpresa'       => $DvEmpresa,
1987
            'RutReceptor'     => $RutReceptor,
1988
            'DvReceptor'      => $DvReceptor,
1989
            'TipoDte'         => $this->getTipo(),
1990
            'FolioDte'        => $this->getFolio(),
1991
            'FechaEmisionDte' => $d.'-'.$m.'-'.$Y,
1992
            'MontoDte'        => $this->getMontoTotal(),
1993
            'FirmaDte'        => str_replace("\n", '', $this->getFirma()['SignatureValue']),
1994
            'token'           => $token,
1995
        ]);
1996
        // si el estado se pudo recuperar se muestra
1997
        if ($xml===false) {
1998
            return false;
1999
        }
2000
        // entregar estado
2001
        return (array)$xml->xpath('/SII:RESPUESTA/SII:RESP_BODY')[0];
2002
    }
2003
2004
    /**
2005
     * Método que entrega la última acción registrada para el DTE en el registro de compra y venta
2006
     * @return Arreglo con los datos de la última acción
2007
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
2008
     * @version 2017-08-29
2009
     */
2010
    public function getUltimaAccionRCV(\sasco\LibreDTE\FirmaElectronica $Firma)
2011
    {
2012
        list($emisor_rut, $emisor_dv) = explode('-', $this->getEmisor());
2013
        $RCV = new \sasco\LibreDTE\Sii\RegistroCompraVenta($Firma);
2014
        try {
2015
            $eventos = $RCV->listarEventosHistDoc($emisor_rut, $emisor_dv, $this->getTipo(), $this->getFolio());
2016
            return $eventos ? $eventos[count($eventos)-1] : null;
2017
        } catch (\Exception $e) {
2018
            return null;
2019
        }
2020
    }
2021
2022
}
2023