Completed
Push — master ( 703d5c...d006d0 )
by Esteban De La Fuente
02:13
created

Dte::normalizar_transporte()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
rs 9.4285
cc 2
eloc 11
nc 2
nop 1
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()) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
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-02-06
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], $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 (!$this->verificarDatos())
145
                return false;
146
            return $this->schemaValidate();
147
        }
148
        return false;
149
    }
150
151
    /**
152
     * Método que entrega el arreglo con los datos del DTE.
153
     * Si el DTE fue creado a partir de un arreglo serán los datos normalizados,
154
     * en cambio si se creó a partir de un XML serán todos los nodos del
155
     * documento sin cambios.
156
     * @return Arreglo con datos del DTE
157
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
158
     * @version 2016-07-04
159
     */
160
    public function getDatos()
161
    {
162
        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...
163
            $datos = $this->xml->toArray();
164
            if (!isset($datos['DTE'][$this->tipo_general])) {
165
                \sasco\LibreDTE\Log::write(
166
                    \sasco\LibreDTE\Estado::DTE_ERROR_GETDATOS,
167
                    \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...
168
                );
169
                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...
170
            }
171
            $this->datos = $datos['DTE'][$this->tipo_general];
172
            if (isset($datos['DTE']['Signature'])) {
173
                $this->Signature = $datos['DTE']['Signature'];
174
            }
175
        }
176
        return $this->datos;
177
    }
178
179
    /**
180
     * Método que entrega el arreglo con los datos de la firma del DTE
181
     * @return Arreglo con datos de la firma
182
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
183
     * @version 2016-06-11
184
     */
185
    public function getFirma()
186
    {
187
        if (!$this->Signature) {
188
            $this->getDatos();
189
        }
190
        return $this->Signature;
191
    }
192
193
    /**
194
     * Método que entrega los datos del DTE (tag Documento) como un string JSON
195
     * @return String JSON "lindo" con los datos del documento
196
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
197
     * @version 2015-09-08
198
     */
199
    public function getJSON()
200
    {
201
        if (!$this->getDatos())
202
            return false;
203
        return json_encode($this->datos, JSON_PRETTY_PRINT);
204
    }
205
206
    /**
207
     * Método que entrega el ID del documento
208
     * @return String con el ID del DTE
209
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
210
     * @version 2016-08-17
211
     */
212
    public function getID($estandar = false)
213
    {
214
        return $estandar ? ('T'.$this->tipo.'F'.$this->folio) : $this->id;
215
    }
216
217
    /**
218
     * Método que entrega el tipo general de documento, de acuerdo a
219
     * $this->tipos
220
     * @param dte Tipo númerico de DTE, ejemplo: 33 (factura electrónica)
221
     * @return String con el tipo general: Documento, Liquidacion o Exportaciones
222
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
223
     * @version 2015-09-17
224
     */
225
    private function getTipoGeneral($dte)
226
    {
227
        foreach ($this->tipos as $tipo => $codigos)
228
            if (in_array($dte, $codigos))
229
                return $tipo;
230
        \sasco\LibreDTE\Log::write(
231
            \sasco\LibreDTE\Estado::DTE_ERROR_TIPO,
232
            \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...
233
        );
234
        return false;
235
    }
236
237
    /**
238
     * Método que entrega el tipo de DTE
239
     * @return Tipo de dte, ej: 33 (factura electrónica)
240
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
241
     * @version 2015-09-02
242
     */
243
    public function getTipo()
244
    {
245
        return $this->tipo;
246
    }
247
248
    /**
249
     * Método que entrega el folio del DTE
250
     * @return Folio del DTE
251
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
252
     * @version 2015-09-02
253
     */
254
    public function getFolio()
255
    {
256
        return $this->folio;
257
    }
258
259
    /**
260
     * Método que entrega rut del emisor del DTE
261
     * @return RUT del emiro
262
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
263
     * @version 2015-09-07
264
     */
265 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...
266
    {
267
        $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...
268
        if ($nodo)
269
            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...
270
        if (!$this->getDatos())
271
            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...
272
        return $this->datos['Encabezado']['Emisor']['RUTEmisor'];
273
    }
274
275
    /**
276
     * Método que entrega rut del receptor del DTE
277
     * @return RUT del emiro
278
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
279
     * @version 2015-09-07
280
     */
281 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...
282
    {
283
        $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...
284
        if ($nodo)
285
            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...
286
        if (!$this->getDatos())
287
            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...
288
        return $this->datos['Encabezado']['Receptor']['RUTRecep'];
289
    }
290
291
    /**
292
     * Método que entrega fecha de emisión del DTE
293
     * @return Fecha de emisión en formato AAAA-MM-DD
294
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
295
     * @version 2015-09-07
296
     */
297 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...
298
    {
299
        $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...
300
        if ($nodo)
301
            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...
302
        if (!$this->getDatos())
303
            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...
304
        return $this->datos['Encabezado']['IdDoc']['FchEmis'];
305
    }
306
307
    /**
308
     * Método que entrega el monto total del DTE
309
     * @return Monto total del DTE
310
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
311
     * @version 2015-09-07
312
     */
313 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...
314
    {
315
        $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...
316
        if ($nodo)
317
            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...
318
        if (!$this->getDatos())
319
            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...
320
        return $this->datos['Encabezado']['Totales']['MntTotal'];
321
    }
322
323
    /**
324
     * Método que entrega el tipo de moneda del documento
325
     * @return String con el tipo de moneda
326
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
327
     * @version 2016-07-16
328
     */
329 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...
330
    {
331
        $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...
332
        if ($nodo)
333
            return $nodo->nodeValue;
334
        if (!$this->getDatos())
335
            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...
336
        return $this->datos['Encabezado']['Totales']['TpoMoneda'];
337
    }
338
339
    /**
340
     * Método que entrega el string XML del tag TED
341
     * @return String XML con tag TED
342
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
343
     * @version 2016-08-03
344
     */
345
    public function getTED()
346
    {
347
        /*$xml = new \sasco\LibreDTE\XML();
0 ignored issues
show
Unused Code Comprehensibility introduced by
68% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
348
        $xml->loadXML($this->xml->getElementsByTagName('TED')->item(0)->getElementsByTagName('DD')->item(0)->C14N());
349
        $xml->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi');
350
        $xml->documentElement->removeAttributeNS('http://www.sii.cl/SiiDte', '');
351
        $FRMT = $this->xml->getElementsByTagName('TED')->item(0)->getElementsByTagName('FRMT')->item(0)->nodeValue;
352
        $pub_key = '';
353
        if (openssl_verify($xml->getFlattened('/'), base64_decode($FRMT), $pub_key, OPENSSL_ALGO_SHA1)!==1);
354
            return false;*/
355
        $xml = new \sasco\LibreDTE\XML();
356
        $TED = $this->xml->getElementsByTagName('TED')->item(0);
357
        if (!$TED)
358
            return '<TED/>';
359
        $xml->loadXML($TED->C14N());
360
        $xml->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi');
361
        $xml->documentElement->removeAttributeNS('http://www.sii.cl/SiiDte', '');
362
        $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...
363
        return mb_detect_encoding($TED, ['UTF-8', 'ISO-8859-1']) != 'ISO-8859-1' ? utf8_decode($TED) : $TED;
364
    }
365
366
    /**
367
     * Método que indica si el DTE es de certificación o no
368
     * @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...
369
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
370
     * @version 2016-06-15
371
     */
372
    public function getCertificacion()
373
    {
374
        $datos = $this->getDatos();
375
        $idk = !empty($datos['TED']['DD']['CAF']['DA']['IDK']) ? (int)$datos['TED']['DD']['CAF']['DA']['IDK'] : null;
376
        return $idk ? $idk === 100 : null;
377
    }
378
379
    /**
380
     * Método que realiza el timbrado del DTE
381
     * @param Folios Objeto de los Folios con los que se desea timbrar
382
     * @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...
383
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
384
     * @version 2016-09-01
385
     */
386
    public function timbrar(Folios $Folios)
387
    {
388
        // verificar que el folio que se está usando para el DTE esté dentro
389
        // del rango de folios autorizados que se usarán para timbrar
390
        // Esta validación NO verifica si el folio ya fue usado, sólo si está
391
        // dentro del CAF que se está usando
392
        $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...
393
        if ($folio<$Folios->getDesde() or $folio>$Folios->getHasta()) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
394
            \sasco\LibreDTE\Log::write(
395
                \sasco\LibreDTE\Estado::DTE_ERROR_RANGO_FOLIO,
396
                \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...
397
            );
398
            return false;
399
        }
400
        // verificar que existan datos para el timbre
401 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...
402
            \sasco\LibreDTE\Log::write(
403
                \sasco\LibreDTE\Estado::DTE_FALTA_FCHEMIS,
404
                \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...
405
            );
406
            \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...
407
            return false;
408
        }
409 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...
410
            \sasco\LibreDTE\Log::write(
411
                \sasco\LibreDTE\Estado::DTE_FALTA_MNTTOTAL,
412
                \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...
413
            );
414
            return false;
415
        }
416
        // timbrar
417
        $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...
418
        $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...
419
        $RSR = $RSR_nodo->length ? trim(mb_substr($RSR_nodo->item(0)->nodeValue, 0, 40)) : $RR;
420
        $TED = new \sasco\LibreDTE\XML();
421
        $TED->generate([
422
            'TED' => [
423
                '@attributes' => [
424
                    'version' => '1.0',
425
                ],
426
                'DD' => [
427
                    '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...
428
                    '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...
429
                    'F' => $folio,
430
                    '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...
431
                    '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...
432
                    'RSR' => $RSR,
433
                    '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...
434
                    '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...
435
                    'CAF' => $Folios->getCaf(),
436
                    'TSTED' => $this->timestamp,
437
                ],
438
                'FRMT' => [
439
                    '@attributes' => [
440
                        'algoritmo' => 'SHA1withRSA'
441
                    ],
442
                ],
443
            ]
444
        ]);
445
        $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...
446
        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...
447
            \sasco\LibreDTE\Log::write(
448
                \sasco\LibreDTE\Estado::DTE_ERROR_TIMBRE,
449
                \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...
450
            );
451
            return false;
452
        }
453
        $TED->getElementsByTagName('FRMT')->item(0)->nodeValue = base64_encode($timbre);
454
        $xml = str_replace('<TED/>', trim(str_replace('<?xml version="1.0" encoding="ISO-8859-1"?>', '', $TED->saveXML())), $this->saveXML());
455 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...
456
            \sasco\LibreDTE\Log::write(
457
                \sasco\LibreDTE\Estado::DTE_ERROR_TIMBRE,
458
                \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...
459
            );
460
            return false;
461
        }
462
        return true;
463
    }
464
465
    /**
466
     * Método que realiza la firma del DTE
467
     * @param Firma objeto que representa la Firma Electrónca
468
     * @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...
469
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
470
     * @version 2015-09-17
471
     */
472
    public function firmar(\sasco\LibreDTE\FirmaElectronica $Firma)
473
    {
474
        $parent = $this->xml->getElementsByTagName($this->tipo_general)->item(0);
475
        $this->xml->generate(['TmstFirma'=>$this->timestamp], $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...
476
        $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...
477 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...
478
            \sasco\LibreDTE\Log::write(
479
                \sasco\LibreDTE\Estado::DTE_ERROR_FIRMA,
480
                \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...
481
            );
482
            return false;
483
        }
484
        $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 476 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...
485
        return true;
486
    }
487
488
    /**
489
     * Método que entrega el DTE en XML
490
     * @return XML con el DTE (podría: con o sin timbre y con o sin firma)
491
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
492
     * @version 2015-08-20
493
     */
494
    public function saveXML()
495
    {
496
        return $this->xml->saveXML();
497
    }
498
499
    /**
500
     * Método que genera un arreglo con el resumen del documento. Este resumen
501
     * puede servir, por ejemplo, para generar los detalles de los IECV
502
     * @return Arreglo con el resumen del DTE
503
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
504
     * @version 2016-07-15
505
     */
506
    public function getResumen()
507
    {
508
        $this->getDatos();
509
        // generar resumen
510
        $resumen =  [
511
            'TpoDoc' => (int)$this->datos['Encabezado']['IdDoc']['TipoDTE'],
512
            'NroDoc' => (int)$this->datos['Encabezado']['IdDoc']['Folio'],
513
            'TasaImp' => 0,
514
            'FchDoc' => $this->datos['Encabezado']['IdDoc']['FchEmis'],
515
            'CdgSIISucur' => !empty($this->datos['Encabezado']['Emisor']['CdgSIISucur']) ? $this->datos['Encabezado']['Emisor']['CdgSIISucur'] : false,
516
            'RUTDoc' => $this->datos['Encabezado']['Receptor']['RUTRecep'],
517
            'RznSoc' => isset($this->datos['Encabezado']['Receptor']['RznSocRecep']) ? $this->datos['Encabezado']['Receptor']['RznSocRecep'] : false,
518
            'MntExe' => false,
519
            'MntNeto' => false,
520
            'MntIVA' => 0,
521
            'MntTotal' => 0,
522
        ];
523
        // obtener montos si es que existen en el documento
524
        $montos = ['TasaImp'=>'TasaIVA', 'MntExe'=>'MntExe', 'MntNeto'=>'MntNeto', 'MntIVA'=>'IVA', 'MntTotal'=>'MntTotal'];
525
        foreach ($montos as $dest => $orig) {
526
            if (!empty($this->datos['Encabezado']['Totales'][$orig])) {
527
                $resumen[$dest] = !$this->esExportacion() ? round($this->datos['Encabezado']['Totales'][$orig]) : $this->datos['Encabezado']['Totales'][$orig];
528
            }
529
        }
530
        // si es una boleta se calculan los datos para el resumen
531
        if ($this->esBoleta()) {
532
            if (!$resumen['TasaImp']) {
533
                $resumen['TasaImp'] = \sasco\LibreDTE\Sii::getIVA();
534
            }
535
            $resumen['MntExe'] = (int)$resumen['MntExe'];
536
            if (!$resumen['MntNeto']) {
537
                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...
538
            }
539
        }
540
        // entregar resumen
541
        return $resumen;
542
    }
543
544
    /**
545
     * Método que permite obtener el monto neto y el IVA de ese neto a partir de
546
     * un monto total
547
     * @param total neto + iva
548
     * @param tasa Tasa del IVA
549
     * @return Arreglo con el neto y el iva
550
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
551
     * @version 2016-04-05
552
     */
553
    private function calcularNetoIVA($total, $tasa = null)
554
    {
555
        if ($tasa === 0 or $tasa === false)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
556
            return [0, 0];
557
        if ($tasa === null)
558
            $tasa = \sasco\LibreDTE\Sii::getIVA();
559
        // WARNING: el IVA obtenido puede no ser el NETO*(TASA/100)
560
        // se calcula el monto neto y luego se obtiene el IVA haciendo la resta
561
        // entre el total y el neto, ya que hay casos de borde como:
562
        //  - BRUTO:   680 => NETO:   571 e IVA:   108 => TOTAL:   679
563
        //  - BRUTO: 86710 => NETO: 72866 e IVA: 13845 => TOTAL: 86711
564
        $neto = round($total / (1+($tasa/100)));
565
        $iva = $total - $neto;
566
        return [$neto, $iva];
567
    }
568
569
    /**
570
     * Método que normaliza los datos de un documento tributario electrónico
571
     * @param datos Arreglo con los datos del documento que se desean normalizar
572
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
573
     * @version 2017-07-24
574
     */
575
    private function normalizar(array &$datos)
576
    {
577
        // completar con nodos por defecto
578
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
579
            'Encabezado' => [
580
                'IdDoc' => [
581
                    'TipoDTE' => false,
582
                    'Folio' => false,
583
                    'FchEmis' => date('Y-m-d'),
584
                    'IndNoRebaja' => false,
585
                    'TipoDespacho' => false,
586
                    'IndTraslado' => false,
587
                    'TpoImpresion' => false,
588
                    'IndServicio' => $this->esBoleta() ? 3 : false,
589
                    'MntBruto' => false,
590
                    'FmaPago' => false,
591
                    'FmaPagExp' => false,
592
                    'MntCancel' => false,
593
                    'SaldoInsol' => false,
594
                    'FchCancel' => false,
595
                    'MntPagos' => false,
596
                    'PeriodoDesde' => false,
597
                    'PeriodoHasta' => false,
598
                    'MedioPago' => false,
599
                    'TpoCtaPago' => false,
600
                    'NumCtaPago' => false,
601
                    'BcoPago' => false,
602
                    'TermPagoCdg' => false,
603
                    'TermPagoGlosa' => false,
604
                    'TermPagoDias' => false,
605
                    'FchVenc' => false,
606
                ],
607
                'Emisor' => [
608
                    'RUTEmisor' => false,
609
                    'RznSoc' => false,
610
                    'GiroEmis' => false,
611
                    'Telefono' => false,
612
                    'CorreoEmisor' => false,
613
                    'Acteco' => false,
614
                    'Sucursal' => false,
615
                    'CdgSIISucur' => false,
616
                    'DirOrigen' => false,
617
                    'CmnaOrigen' => false,
618
                    'CiudadOrigen' => false,
619
                    'CdgVendedor' => false,
620
                ],
621
                'Receptor' => [
622
                    'RUTRecep' => false,
623
                    'CdgIntRecep' => false,
624
                    'RznSocRecep' => false,
625
                    'Extranjero' => false,
626
                    'GiroRecep' => false,
627
                    'Contacto' => false,
628
                    'CorreoRecep' => false,
629
                    'DirRecep' => false,
630
                    'CmnaRecep' => false,
631
                    'CiudadRecep' => false,
632
                    'DirPostal' => false,
633
                    'CmnaPostal' => false,
634
                    'CiudadPostal' => false,
635
                ],
636
                'Totales' => [
637
                    'TpoMoneda' => false,
638
                ],
639
            ],
640
            'Detalle' => false,
641
            'SubTotInfo' => false,
642
            'DscRcgGlobal' => false,
643
            'Referencia' => false,
644
            'Comisiones' => false,
645
        ], $datos);
646
        // corregir algunos datos que podrían venir malos para no caer por schema
647
        $datos['Encabezado']['Emisor']['RUTEmisor'] = strtoupper($datos['Encabezado']['Emisor']['RUTEmisor']);
648
        $datos['Encabezado']['Receptor']['RUTRecep'] = strtoupper($datos['Encabezado']['Receptor']['RUTRecep']);
649
        $datos['Encabezado']['Receptor']['RznSocRecep'] = mb_substr($datos['Encabezado']['Receptor']['RznSocRecep'], 0, 100);
650 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...
651
            $datos['Encabezado']['Receptor']['GiroRecep'] = mb_substr($datos['Encabezado']['Receptor']['GiroRecep'], 0, 40);
652
        }
653 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...
654
            $datos['Encabezado']['Receptor']['Contacto'] = mb_substr($datos['Encabezado']['Receptor']['Contacto'], 0, 80);
655
        }
656 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...
657
            $datos['Encabezado']['Receptor']['CorreoRecep'] = mb_substr($datos['Encabezado']['Receptor']['CorreoRecep'], 0, 80);
658
        }
659 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...
660
            $datos['Encabezado']['Receptor']['DirRecep'] = mb_substr($datos['Encabezado']['Receptor']['DirRecep'], 0, 70);
661
        }
662 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...
663
            $datos['Encabezado']['Receptor']['CmnaRecep'] = mb_substr($datos['Encabezado']['Receptor']['CmnaRecep'], 0, 20);
664
        }
665
        // si existe descuento o recargo global se normalizan
666
        if (!empty($datos['DscRcgGlobal'])) {
667 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...
668
                $datos['DscRcgGlobal'] = [$datos['DscRcgGlobal']];
669
            $NroLinDR = 1;
670
            foreach ($datos['DscRcgGlobal'] as &$dr) {
671
                $dr = array_merge([
672
                    'NroLinDR' => $NroLinDR++,
673
                ], $dr);
674
            }
675
        }
676
        // si existe una o más referencias se normalizan
677
        if (!empty($datos['Referencia'])) {
678 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...
679
                $datos['Referencia'] = [$datos['Referencia']];
680
            $NroLinRef = 1;
681
            foreach ($datos['Referencia'] as &$r) {
682
                $r = array_merge([
683
                    'NroLinRef' => $NroLinRef++,
684
                    'TpoDocRef' => false,
685
                    'IndGlobal' => false,
686
                    'FolioRef' => false,
687
                    'RUTOtr' => false,
688
                    'FchRef' => date('Y-m-d'),
689
                    'CodRef' => false,
690
                    'RazonRef' => false,
691
                ], $r);
692
            }
693
        }
694
    }
695
696
    /**
697
     * Método que realiza la normalización final de los datos de un documento
698
     * tributario electrónico. Esto se aplica todos los documentos una vez que
699
     * ya se aplicaron las normalizaciones por tipo
700
     * @param datos Arreglo con los datos del documento que se desean normalizar
701
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
702
     * @version 2016-02-28
703
     */
704
    private function normalizar_final(array &$datos)
705
    {
706
        // normalizar montos de pagos programados
707
        if (is_array($datos['Encabezado']['IdDoc']['MntPagos'])) {
708
            $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...
709
            if (!isset($datos['Encabezado']['IdDoc']['MntPagos'][0]))
710
                $datos['Encabezado']['IdDoc']['MntPagos'] = [$datos['Encabezado']['IdDoc']['MntPagos']];
711
            foreach ($datos['Encabezado']['IdDoc']['MntPagos'] as &$MntPagos) {
712
                $MntPagos = array_merge([
713
                    'FchPago' => null,
714
                    'MntPago' => null,
715
                    'GlosaPagos' => false,
716
                ], $MntPagos);
717
                if ($MntPagos['MntPago']===null) {
718
                    $MntPagos['MntPago'] = $datos['Encabezado']['Totales']['MntTotal'];
719
                }
720
            }
721
        }
722
    }
723
724
    /**
725
     * Método que normaliza los datos de una factura electrónica
726
     * @param datos Arreglo con los datos del documento que se desean normalizar
727
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
728
     * @version 2017-09-01
729
     */
730
    private function normalizar_33(array &$datos)
731
    {
732
        // completar con nodos por defecto
733
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
734
            'Encabezado' => [
735
                'IdDoc' => false,
736
                'Emisor' => false,
737
                'RUTMandante' => false,
738
                'Receptor' => false,
739
                'RUTSolicita' => false,
740
                'Transporte' => false,
741
                'Totales' => [
742
                    'MntNeto' => 0,
743
                    'MntExe' => false,
744
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
745
                    'IVA' => 0,
746
                    'ImptoReten' => false,
747
                    'CredEC' => false,
748
                    'MntTotal' => 0,
749
                ],
750
                'OtraMoneda' => false,
751
            ],
752
        ], $datos);
753
        // normalizar datos
754
        $this->normalizar_detalle($datos);
755
        $this->normalizar_aplicar_descuentos_recargos($datos);
756
        $this->normalizar_impuesto_retenido($datos);
757
        $this->normalizar_agregar_IVA_MntTotal($datos);
758
        $this->normalizar_transporte($datos);
759
    }
760
761
    /**
762
     * Método que normaliza los datos de una factura exenta electrónica
763
     * @param datos Arreglo con los datos del documento que se desean normalizar
764
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
765
     * @version 2017-02-23
766
     */
767
    private function normalizar_34(array &$datos)
768
    {
769
        // completar con nodos por defecto
770
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
771
            'Encabezado' => [
772
                'IdDoc' => false,
773
                'Emisor' => false,
774
                'Receptor' => false,
775
                'RUTSolicita' => false,
776
                'Totales' => [
777
                    'MntExe' => false,
778
                    'MntTotal' => 0,
779
                ]
780
            ],
781
        ], $datos);
782
        // normalizar datos
783
        $this->normalizar_detalle($datos);
784
        $this->normalizar_aplicar_descuentos_recargos($datos);
785
        $this->normalizar_agregar_IVA_MntTotal($datos);
786
    }
787
788
    /**
789
     * Método que normaliza los datos de una boleta electrónica
790
     * @param datos Arreglo con los datos del documento que se desean normalizar
791
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
792
     * @version 2016-03-14
793
     */
794 View Code Duplication
    private function normalizar_39(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...
795
    {
796
        // completar con nodos por defecto
797
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
798
            'Encabezado' => [
799
                'IdDoc' => false,
800
                'Emisor' => [
801
                    'RUTEmisor' => false,
802
                    'RznSocEmisor' => false,
803
                    'GiroEmisor' => false,
804
                ],
805
                'Receptor' => false,
806
                'Totales' => [
807
                    'MntExe' => false,
808
                    'MntTotal' => 0,
809
                ]
810
            ],
811
        ], $datos);
812
        // normalizar datos
813
        $this->normalizar_boletas($datos);
814
        $this->normalizar_detalle($datos);
815
        $this->normalizar_aplicar_descuentos_recargos($datos);
816
        $this->normalizar_agregar_IVA_MntTotal($datos);
817
    }
818
819
    /**
820
     * Método que normaliza los datos de una boleta exenta electrónica
821
     * @param datos Arreglo con los datos del documento que se desean normalizar
822
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
823
     * @version 2016-03-14
824
     */
825 View Code Duplication
    private function normalizar_41(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...
826
    {
827
        // completar con nodos por defecto
828
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
829
            'Encabezado' => [
830
                'IdDoc' => false,
831
                'Emisor' => [
832
                    'RUTEmisor' => false,
833
                    'RznSocEmisor' => false,
834
                    'GiroEmisor' => false,
835
                ],
836
                'Receptor' => false,
837
                'Totales' => [
838
                    'MntExe' => 0,
839
                    'MntTotal' => 0,
840
                ]
841
            ],
842
        ], $datos);
843
        // normalizar datos
844
        $this->normalizar_boletas($datos);
845
        $this->normalizar_detalle($datos);
846
        $this->normalizar_aplicar_descuentos_recargos($datos);
847
        $this->normalizar_agregar_IVA_MntTotal($datos);
848
    }
849
850
    /**
851
     * Método que normaliza los datos de una factura de compra electrónica
852
     * @param datos Arreglo con los datos del documento que se desean normalizar
853
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
854
     * @version 2016-02-26
855
     */
856
    private function normalizar_46(array &$datos)
857
    {
858
        // completar con nodos por defecto
859
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
860
            'Encabezado' => [
861
                'IdDoc' => false,
862
                'Emisor' => false,
863
                'Receptor' => false,
864
                'RUTSolicita' => false,
865
                'Totales' => [
866
                    'MntNeto' => 0,
867
                    'MntExe' => false,
868
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
869
                    'IVA' => 0,
870
                    'ImptoReten' => false,
871
                    'IVANoRet' => false,
872
                    'MntTotal' => 0,
873
                ]
874
            ],
875
        ], $datos);
876
        // normalizar datos
877
        $this->normalizar_detalle($datos);
878
        $this->normalizar_aplicar_descuentos_recargos($datos);
879
        $this->normalizar_impuesto_retenido($datos);
880
        $this->normalizar_agregar_IVA_MntTotal($datos);
881
    }
882
883
    /**
884
     * Método que normaliza los datos de una guía de despacho electrónica
885
     * @param datos Arreglo con los datos del documento que se desean normalizar
886
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
887
     * @version 2017-09-01
888
     */
889
    private function normalizar_52(array &$datos)
890
    {
891
        // completar con nodos por defecto
892
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
893
            'Encabezado' => [
894
                'IdDoc' => false,
895
                'Emisor' => false,
896
                'Receptor' => false,
897
                'RUTSolicita' => false,
898
                'Transporte' => false,
899
                'Totales' => [
900
                    'MntNeto' => 0,
901
                    'MntExe' => false,
902
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
903
                    'IVA' => 0,
904
                    'ImptoReten' => false,
905
                    'CredEC' => false,
906
                    'MntTotal' => 0,
907
                ]
908
            ],
909
        ], $datos);
910
        // si es traslado interno se copia el emisor en el receptor sólo si el
911
        // receptor no está definido o bien si el receptor tiene RUT diferente
912
        // al emisor
913
        if ($datos['Encabezado']['IdDoc']['IndTraslado']==5) {
914
            if (!$datos['Encabezado']['Receptor'] or $datos['Encabezado']['Receptor']['RUTRecep']!=$datos['Encabezado']['Emisor']['RUTEmisor']) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
915
                $datos['Encabezado']['Receptor'] = [];
916
                $cols = [
917
                    'RUTEmisor'=>'RUTRecep',
918
                    'RznSoc'=>'RznSocRecep',
919
                    'GiroEmis'=>'GiroRecep',
920
                    'Telefono'=>'Contacto',
921
                    'CorreoEmisor'=>'CorreoRecep',
922
                    'DirOrigen'=>'DirRecep',
923
                    'CmnaOrigen'=>'CmnaRecep',
924
                ];
925
                foreach ($cols as $emisor => $receptor) {
926
                    if (!empty($datos['Encabezado']['Emisor'][$emisor])) {
927
                        $datos['Encabezado']['Receptor'][$receptor] = $datos['Encabezado']['Emisor'][$emisor];
928
                    }
929
                }
930 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...
931
                    $datos['Encabezado']['Receptor']['GiroRecep'] = mb_substr($datos['Encabezado']['Receptor']['GiroRecep'], 0, 40);
932
                }
933
            }
934
        }
935
        // normalizar datos
936
        $this->normalizar_detalle($datos);
937
        $this->normalizar_aplicar_descuentos_recargos($datos);
938
        $this->normalizar_impuesto_retenido($datos);
939
        $this->normalizar_agregar_IVA_MntTotal($datos);
940
        $this->normalizar_transporte($datos);
941
    }
942
943
    /**
944
     * Método que normaliza los datos de una nota de débito
945
     * @param datos Arreglo con los datos del documento que se desean normalizar
946
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
947
     * @version 2017-02-23
948
     */
949 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...
950
    {
951
        // completar con nodos por defecto
952
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
953
            'Encabezado' => [
954
                'IdDoc' => false,
955
                'Emisor' => false,
956
                'Receptor' => false,
957
                'RUTSolicita' => false,
958
                'Totales' => [
959
                    'MntNeto' => 0,
960
                    'MntExe' => 0,
961
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
962
                    'IVA' => false,
963
                    'ImptoReten' => false,
964
                    'IVANoRet' => false,
965
                    'CredEC' => false,
966
                    'MntTotal' => 0,
967
                ]
968
            ],
969
        ], $datos);
970
        // normalizar datos
971
        $this->normalizar_detalle($datos);
972
        $this->normalizar_aplicar_descuentos_recargos($datos);
973
        $this->normalizar_impuesto_retenido($datos);
974
        $this->normalizar_agregar_IVA_MntTotal($datos);
975
        if (!$datos['Encabezado']['Totales']['MntNeto']) {
976
            $datos['Encabezado']['Totales']['MntNeto'] = 0;
977
            $datos['Encabezado']['Totales']['TasaIVA'] = false;
978
        }
979
    }
980
981
    /**
982
     * Método que normaliza los datos de una nota de crédito
983
     * @param datos Arreglo con los datos del documento que se desean normalizar
984
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
985
     * @version 2017-02-23
986
     */
987 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...
988
    {
989
        // completar con nodos por defecto
990
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
991
            'Encabezado' => [
992
                'IdDoc' => false,
993
                'Emisor' => false,
994
                'Receptor' => false,
995
                'RUTSolicita' => false,
996
                'Totales' => [
997
                    'MntNeto' => 0,
998
                    'MntExe' => 0,
999
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
1000
                    'IVA' => false,
1001
                    'ImptoReten' => false,
1002
                    'IVANoRet' => false,
1003
                    'CredEC' => false,
1004
                    'MntTotal' => 0,
1005
                ]
1006
            ],
1007
        ], $datos);
1008
        // normalizar datos
1009
        $this->normalizar_detalle($datos);
1010
        $this->normalizar_aplicar_descuentos_recargos($datos);
1011
        $this->normalizar_impuesto_retenido($datos);
1012
        $this->normalizar_agregar_IVA_MntTotal($datos);
1013
        if (!$datos['Encabezado']['Totales']['MntNeto']) {
1014
            $datos['Encabezado']['Totales']['MntNeto'] = 0;
1015
            $datos['Encabezado']['Totales']['TasaIVA'] = false;
1016
        }
1017
    }
1018
1019
    /**
1020
     * Método que normaliza los datos de una factura electrónica de exportación
1021
     * @param datos Arreglo con los datos del documento que se desean normalizar
1022
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1023
     * @version 2016-04-05
1024
     */
1025 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...
1026
    {
1027
        // completar con nodos por defecto
1028
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1029
            'Encabezado' => [
1030
                'IdDoc' => false,
1031
                'Emisor' => false,
1032
                'Receptor' => false,
1033
                'Transporte' => [
1034
                    'Patente' => false,
1035
                    'RUTTrans' => false,
1036
                    'Chofer' => false,
1037
                    'DirDest' => false,
1038
                    'CmnaDest' => false,
1039
                    'CiudadDest' => false,
1040
                    'Aduana' => [
1041
                        'CodModVenta' => false,
1042
                        'CodClauVenta' => false,
1043
                        'TotClauVenta' => false,
1044
                        'CodViaTransp' => false,
1045
                        'NombreTransp' => false,
1046
                        'RUTCiaTransp' => false,
1047
                        'NomCiaTransp' => false,
1048
                        'IdAdicTransp' => false,
1049
                        'Booking' => false,
1050
                        'Operador' => false,
1051
                        'CodPtoEmbarque' => false,
1052
                        'IdAdicPtoEmb' => false,
1053
                        'CodPtoDesemb' => false,
1054
                        'IdAdicPtoDesemb' => false,
1055
                        'Tara' => false,
1056
                        'CodUnidMedTara' => false,
1057
                        'PesoBruto' => false,
1058
                        'CodUnidPesoBruto' => false,
1059
                        'PesoNeto' => false,
1060
                        'CodUnidPesoNeto' => false,
1061
                        'TotItems' => false,
1062
                        'TotBultos' => false,
1063
                        'TipoBultos' => false,
1064
                        'MntFlete' => false,
1065
                        'MntSeguro' => false,
1066
                        'CodPaisRecep' => false,
1067
                        'CodPaisDestin' => false,
1068
                    ],
1069
                ],
1070
                'Totales' => [
1071
                    'TpoMoneda' => null,
1072
                    'MntExe' => 0,
1073
                    'MntTotal' => 0,
1074
                ]
1075
            ],
1076
        ], $datos);
1077
        // normalizar datos
1078
        $this->normalizar_detalle($datos);
1079
        $this->normalizar_aplicar_descuentos_recargos($datos);
1080
        $this->normalizar_impuesto_retenido($datos);
1081
        $this->normalizar_agregar_IVA_MntTotal($datos);
1082
        $this->normalizar_exportacion($datos);
1083
    }
1084
1085
    /**
1086
     * Método que normaliza los datos de una nota de débito de exportación
1087
     * @param datos Arreglo con los datos del documento que se desean normalizar
1088
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1089
     * @version 2016-04-05
1090
     */
1091 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...
1092
    {
1093
        // completar con nodos por defecto
1094
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1095
            'Encabezado' => [
1096
                'IdDoc' => false,
1097
                'Emisor' => false,
1098
                'Receptor' => false,
1099
                'Transporte' => [
1100
                    'Patente' => false,
1101
                    'RUTTrans' => false,
1102
                    'Chofer' => false,
1103
                    'DirDest' => false,
1104
                    'CmnaDest' => false,
1105
                    'CiudadDest' => false,
1106
                    'Aduana' => [
1107
                        'CodModVenta' => false,
1108
                        'CodClauVenta' => false,
1109
                        'TotClauVenta' => false,
1110
                        'CodViaTransp' => false,
1111
                        'NombreTransp' => false,
1112
                        'RUTCiaTransp' => false,
1113
                        'NomCiaTransp' => false,
1114
                        'IdAdicTransp' => false,
1115
                        'Booking' => false,
1116
                        'Operador' => false,
1117
                        'CodPtoEmbarque' => false,
1118
                        'IdAdicPtoEmb' => false,
1119
                        'CodPtoDesemb' => false,
1120
                        'IdAdicPtoDesemb' => false,
1121
                        'Tara' => false,
1122
                        'CodUnidMedTara' => false,
1123
                        'PesoBruto' => false,
1124
                        'CodUnidPesoBruto' => false,
1125
                        'PesoNeto' => false,
1126
                        'CodUnidPesoNeto' => false,
1127
                        'TotItems' => false,
1128
                        'TotBultos' => false,
1129
                        'TipoBultos' => false,
1130
                        'MntFlete' => false,
1131
                        'MntSeguro' => false,
1132
                        'CodPaisRecep' => false,
1133
                        'CodPaisDestin' => false,
1134
                    ],
1135
                ],
1136
                'Totales' => [
1137
                    'TpoMoneda' => null,
1138
                    'MntExe' => 0,
1139
                    'MntTotal' => 0,
1140
                ]
1141
            ],
1142
        ], $datos);
1143
        // normalizar datos
1144
        $this->normalizar_detalle($datos);
1145
        $this->normalizar_aplicar_descuentos_recargos($datos);
1146
        $this->normalizar_impuesto_retenido($datos);
1147
        $this->normalizar_agregar_IVA_MntTotal($datos);
1148
        $this->normalizar_exportacion($datos);
1149
    }
1150
1151
    /**
1152
     * Método que normaliza los datos de una nota de crédito de exportación
1153
     * @param datos Arreglo con los datos del documento que se desean normalizar
1154
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1155
     * @version 2016-04-05
1156
     */
1157 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...
1158
    {
1159
        // completar con nodos por defecto
1160
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1161
            'Encabezado' => [
1162
                'IdDoc' => false,
1163
                'Emisor' => false,
1164
                'Receptor' => false,
1165
                'Transporte' => [
1166
                    'Patente' => false,
1167
                    'RUTTrans' => false,
1168
                    'Chofer' => false,
1169
                    'DirDest' => false,
1170
                    'CmnaDest' => false,
1171
                    'CiudadDest' => false,
1172
                    'Aduana' => [
1173
                        'CodModVenta' => false,
1174
                        'CodClauVenta' => false,
1175
                        'TotClauVenta' => false,
1176
                        'CodViaTransp' => false,
1177
                        'NombreTransp' => false,
1178
                        'RUTCiaTransp' => false,
1179
                        'NomCiaTransp' => false,
1180
                        'IdAdicTransp' => false,
1181
                        'Booking' => false,
1182
                        'Operador' => false,
1183
                        'CodPtoEmbarque' => false,
1184
                        'IdAdicPtoEmb' => false,
1185
                        'CodPtoDesemb' => false,
1186
                        'IdAdicPtoDesemb' => false,
1187
                        'Tara' => false,
1188
                        'CodUnidMedTara' => false,
1189
                        'PesoBruto' => false,
1190
                        'CodUnidPesoBruto' => false,
1191
                        'PesoNeto' => false,
1192
                        'CodUnidPesoNeto' => false,
1193
                        'TotItems' => false,
1194
                        'TotBultos' => false,
1195
                        'TipoBultos' => false,
1196
                        'MntFlete' => false,
1197
                        'MntSeguro' => false,
1198
                        'CodPaisRecep' => false,
1199
                        'CodPaisDestin' => false,
1200
                    ],
1201
                ],
1202
                'Totales' => [
1203
                    'TpoMoneda' => null,
1204
                    'MntExe' => 0,
1205
                    'MntTotal' => 0,
1206
                ]
1207
            ],
1208
        ], $datos);
1209
        // normalizar datos
1210
        $this->normalizar_detalle($datos);
1211
        $this->normalizar_aplicar_descuentos_recargos($datos);
1212
        $this->normalizar_impuesto_retenido($datos);
1213
        $this->normalizar_agregar_IVA_MntTotal($datos);
1214
        $this->normalizar_exportacion($datos);
1215
    }
1216
1217
    /**
1218
     * Método que normaliza los datos de exportacion de un documento
1219
     * @param datos Arreglo con los datos del documento que se desean normalizar
1220
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1221
     * @version 2016-04-04
1222
     */
1223
    public function normalizar_exportacion(array &$datos)
1224
    {
1225
        // agregar modalidad de venta por defecto si no existe
1226
        if (empty($datos['Encabezado']['Transporte']['Aduana']['CodModVenta']) and (!isset($datos['Encabezado']['IdDoc']['IndServicio']) or !in_array($datos['Encabezado']['IdDoc']['IndServicio'], [3, 4, 5]))) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1227
            $datos['Encabezado']['Transporte']['Aduana']['CodModVenta'] = 1;
1228
        }
1229
        // quitar campos que no son parte del documento de exportacion
1230
        $datos['Encabezado']['Receptor']['CmnaRecep'] = false;
1231
    }
1232
1233
    /**
1234
     * Método que normaliza los detalles del documento
1235
     * @param datos Arreglo con los datos del documento que se desean normalizar
1236
     * @warning Revisar como se aplican descuentos y recargos, ¿debería ser un porcentaje del monto original?
1237
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1238
     * @version 2017-07-24
1239
     */
1240
    private function normalizar_detalle(array &$datos)
1241
    {
1242
        if (!isset($datos['Detalle'][0]))
1243
            $datos['Detalle'] = [$datos['Detalle']];
1244
        $item = 1;
1245
        foreach ($datos['Detalle'] as &$d) {
1246
            $d = array_merge([
1247
                'NroLinDet' => $item++,
1248
                'CdgItem' => false,
1249
                'IndExe' => false,
1250
                'Retenedor' => false,
1251
                'NmbItem' => false,
1252
                'DscItem' => false,
1253
                'QtyRef' => false,
1254
                'UnmdRef' => false,
1255
                'PrcRef' => false,
1256
                'QtyItem' => false,
1257
                'UnmdItem' => false,
1258
                'PrcItem' => false,
1259
                'DescuentoPct' => false,
1260
                'DescuentoMonto' => false,
1261
                'RecargoPct' => false,
1262
                'RecargoMonto' => false,
1263
                'CodImpAdic' => false,
1264
                'MontoItem' => false,
1265
            ], $d);
1266
            // corregir datos
1267
            $d['NmbItem'] = mb_substr($d['NmbItem'], 0, 80);
1268
            if (!empty($d['DscItem'])) {
1269
                $d['DscItem'] = mb_substr($d['DscItem'], 0, 1000);
1270
            }
1271
            // normalizar
1272
            if ($this->esExportacion()) {
1273
                $d['IndExe'] = 1;
1274
            }
1275
            if (is_array($d['CdgItem'])) {
1276
                $d['CdgItem'] = array_merge([
1277
                    'TpoCodigo' => false,
1278
                    'VlrCodigo' => false,
1279
                ], $d['CdgItem']);
1280
                if ($d['Retenedor']===false and $d['CdgItem']['TpoCodigo']=='CPCS') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1281
                    $d['Retenedor'] = true;
1282
                }
1283
            }
1284
            if ($d['Retenedor']!==false) {
1285
                if (!is_array($d['Retenedor'])) {
1286
                    $d['Retenedor'] = ['IndAgente'=>'R'];
1287
                }
1288
                $d['Retenedor'] = array_merge([
1289
                    'IndAgente' => 'R',
1290
                    'MntBaseFaena' => false,
1291
                    'MntMargComer' => false,
1292
                    'PrcConsFinal' => false,
1293
                ], $d['Retenedor']);
1294
            }
1295
            if ($d['CdgItem']!==false and !is_array($d['CdgItem'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1296
                $d['CdgItem'] = [
1297
                    'TpoCodigo' => empty($d['Retenedor']['IndAgente']) ? 'INT1' : 'CPCS',
1298
                    'VlrCodigo' => $d['CdgItem'],
1299
                ];
1300
            }
1301
            if ($d['PrcItem']) {
1302
                if (!$d['QtyItem'])
1303
                    $d['QtyItem'] = 1;
1304
                if (empty($d['MontoItem'])) {
1305
                    $d['MontoItem'] = $this->round(
1306
                        $d['QtyItem'] * $d['PrcItem'],
0 ignored issues
show
Documentation introduced by
$d['QtyItem'] * $d['PrcItem'] 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...
1307
                        $datos['Encabezado']['Totales']['TpoMoneda']
1308
                    );
1309
                    // aplicar descuento
1310
                    if ($d['DescuentoPct']) {
1311
                        $d['DescuentoMonto'] = round($d['MontoItem'] * (int)$d['DescuentoPct']/100);
1312
                    }
1313
                    $d['MontoItem'] -= $d['DescuentoMonto'];
1314
                    // aplicar recargo
1315
                    if ($d['RecargoPct']) {
1316
                        $d['RecargoMonto'] = round($d['MontoItem'] * (int)$d['RecargoPct']/100);
1317
                    }
1318
                    $d['MontoItem'] += $d['RecargoMonto'];
1319
                    // aproximar monto del item
1320
                    $d['MontoItem'] = $this->round(
1321
                        $d['MontoItem'], $datos['Encabezado']['Totales']['TpoMoneda']
1322
                    );
1323
                }
1324
            } else if (empty($d['MontoItem'])) {
1325
                $d['MontoItem'] = 0;
1326
            }
1327
            // sumar valor del monto a MntNeto o MntExe según corresponda
1328
            if ($d['MontoItem']) {
1329
                // si no es boleta
1330
                if (!$this->esBoleta()) {
1331
                    if ((!isset($datos['Encabezado']['Totales']['MntNeto']) or $datos['Encabezado']['Totales']['MntNeto']===false) and isset($datos['Encabezado']['Totales']['MntExe'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1332
                        $datos['Encabezado']['Totales']['MntExe'] += $d['MontoItem'];
1333 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...
1334
                        if (!empty($d['IndExe'])) {
1335
                            if ($d['IndExe']==1) {
1336
                                $datos['Encabezado']['Totales']['MntExe'] += $d['MontoItem'];
1337
                            }
1338
                        } else {
1339
                            $datos['Encabezado']['Totales']['MntNeto'] += $d['MontoItem'];
1340
                        }
1341
                    }
1342
                }
1343
                // si es boleta
1344 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...
1345
                    // si es exento
1346
                    if (!empty($d['IndExe'])) {
1347
                        if ($d['IndExe']==1) {
1348
                            $datos['Encabezado']['Totales']['MntExe'] += $d['MontoItem'];
1349
                        }
1350
                    }
1351
                    // agregar al monto total
1352
                    $datos['Encabezado']['Totales']['MntTotal'] += $d['MontoItem'];
1353
                }
1354
            }
1355
        }
1356
    }
1357
1358
    /**
1359
     * Método que aplica los descuentos y recargos generales respectivos a los
1360
     * montos que correspondan según e indicador del descuento o recargo
1361
     * @param datos Arreglo con los datos del documento que se desean normalizar
1362
     * @warning Boleta afecta con algún item exento el descuento se podría estar aplicando mal
1363
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1364
     * @version 2016-10-18
1365
     */
1366
    private function normalizar_aplicar_descuentos_recargos(array &$datos)
1367
    {
1368
        if (!empty($datos['DscRcgGlobal'])) {
1369 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...
1370
                $datos['DscRcgGlobal'] = [$datos['DscRcgGlobal']];
1371
            foreach ($datos['DscRcgGlobal'] as $dr) {
1372
                $dr = array_merge([
1373
                    'NroLinDR' => false,
1374
                    'TpoMov' => false,
1375
                    'GlosaDR' => false,
1376
                    'TpoValor' => false,
1377
                    'ValorDR' => false,
1378
                    'ValorDROtrMnda' => false,
1379
                    'IndExeDR' => false,
1380
                ], $dr);
1381
                if ($this->esExportacion()) {
1382
                    $dr['IndExeDR'] = 1;
1383
                }
1384
                // determinar a que aplicar el descuento/recargo
1385
                if (!isset($dr['IndExeDR']) or $dr['IndExeDR']===false)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1386
                    $monto = $this->getTipo()==39 ? 'MntTotal' : 'MntNeto';
1387
                else if ($dr['IndExeDR']==1)
1388
                    $monto = 'MntExe';
1389
                else if ($dr['IndExeDR']==2)
1390
                    $monto = 'MontoNF';
1391
                // si no hay monto al que aplicar el descuento se omite
1392
                if (empty($datos['Encabezado']['Totales'][$monto]))
1393
                    continue;
1394
                // calcular valor del descuento o recargo
1395
                if ($dr['TpoValor']=='$')
1396
                    $dr['ValorDR'] = $this->round($dr['ValorDR'], $datos['Encabezado']['Totales']['TpoMoneda'], 2);
1397
                $valor =
1398
                    $dr['TpoValor']=='%'
1399
                    ? $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...
1400
                    : $dr['ValorDR']
1401
                ;
1402
                // aplicar descuento
1403
                if ($dr['TpoMov']=='D') {
1404
                    $datos['Encabezado']['Totales'][$monto] -= $valor;
1405
                }
1406
                // aplicar recargo
1407
                else if ($dr['TpoMov']=='R') {
1408
                    $datos['Encabezado']['Totales'][$monto] += $valor;
1409
                }
1410
                $datos['Encabezado']['Totales'][$monto] = $this->round(
1411
                    $datos['Encabezado']['Totales'][$monto],
1412
                    $datos['Encabezado']['Totales']['TpoMoneda']
1413
                );
1414
                // si el descuento global se aplica a una boleta exenta se copia el valor exento al total
1415
                if ($this->getTipo()==41 and isset($dr['IndExeDR']) and $dr['IndExeDR']==1) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1416
                    $datos['Encabezado']['Totales']['MntTotal'] = $datos['Encabezado']['Totales']['MntExe'];
1417
                }
1418
            }
1419
        }
1420
    }
1421
1422
    /**
1423
     * Método que calcula los montos de impuestos adicionales o retenciones
1424
     * @param datos Arreglo con los datos del documento que se desean normalizar
1425
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1426
     * @version 2016-04-05
1427
     */
1428
    private function normalizar_impuesto_retenido(array &$datos)
1429
    {
1430
        // copiar montos
1431
        $montos = [];
1432
        foreach ($datos['Detalle'] as &$d) {
1433
            if (!empty($d['CodImpAdic'])) {
1434
                if (!isset($montos[$d['CodImpAdic']]))
1435
                    $montos[$d['CodImpAdic']] = 0;
1436
                $montos[$d['CodImpAdic']] += $d['MontoItem'];
1437
            }
1438
        }
1439
        // si hay montos y no hay total para impuesto retenido se arma
1440
        if (!empty($montos)) {
1441 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...
1442
                $datos['Encabezado']['Totales']['ImptoReten'] = [];
1443
            } else if (!isset($datos['Encabezado']['Totales']['ImptoReten'][0])) {
1444
                $datos['Encabezado']['Totales']['ImptoReten'] = [$datos['Encabezado']['Totales']['ImptoReten']];
1445
            }
1446
        }
1447
        // armar impuesto adicional o retención en los totales
1448
        foreach ($montos as $codigo => $neto) {
1449
            // buscar si existe el impuesto en los totales
1450
            $i = 0;
1451
            foreach ($datos['Encabezado']['Totales']['ImptoReten'] as &$ImptoReten) {
1452
                if ($ImptoReten['TipoImp']==$codigo) {
1453
                    break;
1454
                }
1455
                $i++;
1456
            }
1457
            // si no existe se crea
1458 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...
1459
                $datos['Encabezado']['Totales']['ImptoReten'][] = [
1460
                    'TipoImp' => $codigo
1461
                ];
1462
            }
1463
            // se normaliza
1464
            $datos['Encabezado']['Totales']['ImptoReten'][$i] = array_merge([
1465
                'TipoImp' => $codigo,
1466
                'TasaImp' => ImpuestosAdicionales::getTasa($codigo),
1467
                'MontoImp' => null,
1468
            ], $datos['Encabezado']['Totales']['ImptoReten'][$i]);
1469
            // si el monto no existe se asigna
1470
            if ($datos['Encabezado']['Totales']['ImptoReten'][$i]['MontoImp']===null) {
1471
                $datos['Encabezado']['Totales']['ImptoReten'][$i]['MontoImp'] = round(
1472
                    $neto * $datos['Encabezado']['Totales']['ImptoReten'][$i]['TasaImp']/100
1473
                );
1474
            }
1475
        }
1476
        // quitar los codigos que no existen en el detalle
1477
        if (isset($datos['Encabezado']['Totales']['ImptoReten']) and is_array($datos['Encabezado']['Totales']['ImptoReten'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1478
            $codigos = array_keys($montos);
1479
            $n_impuestos = count($datos['Encabezado']['Totales']['ImptoReten']);
1480
            for ($i=0; $i<$n_impuestos; $i++) {
1481 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...
1482
                    unset($datos['Encabezado']['Totales']['ImptoReten'][$i]);
1483
                }
1484
            }
1485
            sort($datos['Encabezado']['Totales']['ImptoReten']);
1486
        }
1487
    }
1488
1489
    /**
1490
     * Método que calcula el monto del IVA y el monto total del documento a
1491
     * partir del monto neto y la tasa de IVA si es que existe
1492
     * @param datos Arreglo con los datos del documento que se desean normalizar
1493
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1494
     * @version 2016-04-05
1495
     */
1496
    private function normalizar_agregar_IVA_MntTotal(array &$datos)
1497
    {
1498
        // agregar IVA y monto total
1499
        if (!empty($datos['Encabezado']['Totales']['MntNeto'])) {
1500
            if ($datos['Encabezado']['IdDoc']['MntBruto']==1) {
1501
                list($datos['Encabezado']['Totales']['MntNeto'], $datos['Encabezado']['Totales']['IVA']) = $this->calcularNetoIVA(
1502
                    $datos['Encabezado']['Totales']['MntNeto'],
1503
                    $datos['Encabezado']['Totales']['TasaIVA']
1504
                );
1505
            } else {
1506
                if (empty($datos['Encabezado']['Totales']['IVA']) and !empty($datos['Encabezado']['Totales']['TasaIVA'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1507
                    $datos['Encabezado']['Totales']['IVA'] = round(
1508
                        $datos['Encabezado']['Totales']['MntNeto']*($datos['Encabezado']['Totales']['TasaIVA']/100)
1509
                    );
1510
                }
1511
            }
1512
            if (empty($datos['Encabezado']['Totales']['MntTotal'])) {
1513
                $datos['Encabezado']['Totales']['MntTotal'] = $datos['Encabezado']['Totales']['MntNeto'];
1514
                if (!empty($datos['Encabezado']['Totales']['IVA']))
1515
                    $datos['Encabezado']['Totales']['MntTotal'] += $datos['Encabezado']['Totales']['IVA'];
1516
                if (!empty($datos['Encabezado']['Totales']['MntExe']))
1517
                    $datos['Encabezado']['Totales']['MntTotal'] += $datos['Encabezado']['Totales']['MntExe'];
1518
            }
1519 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...
1520
            if (!$datos['Encabezado']['Totales']['MntTotal'] and !empty($datos['Encabezado']['Totales']['MntExe'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1521
                $datos['Encabezado']['Totales']['MntTotal'] = $datos['Encabezado']['Totales']['MntExe'];
1522
            }
1523
        }
1524
        // si hay impuesto retenido o adicional se contabiliza en el total
1525
        if (!empty($datos['Encabezado']['Totales']['ImptoReten'])) {
1526
            foreach ($datos['Encabezado']['Totales']['ImptoReten'] as &$ImptoReten) {
1527
                // si es retención se resta al total y se traspasaa IVA no retenido
1528
                // en caso que corresponda
1529
                if (ImpuestosAdicionales::getTipo($ImptoReten['TipoImp'])=='R') {
1530
                    $datos['Encabezado']['Totales']['MntTotal'] -= $ImptoReten['MontoImp'];
1531
                    if ($ImptoReten['MontoImp']!=$datos['Encabezado']['Totales']['IVA']) {
1532
                        $datos['Encabezado']['Totales']['IVANoRet'] = $datos['Encabezado']['Totales']['IVA'] - $ImptoReten['MontoImp'];
1533
                    }
1534
                }
1535
                // si es adicional se suma al total
1536
                else if (ImpuestosAdicionales::getTipo($ImptoReten['TipoImp'])=='A' and isset($ImptoReten['MontoImp'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1537
                    $datos['Encabezado']['Totales']['MntTotal'] += $ImptoReten['MontoImp'];
1538
                }
1539
            }
1540
        }
1541
        // si hay impuesto de crédito a constructoras del 65% se descuenta del total
1542
        if (!empty($datos['Encabezado']['Totales']['CredEC'])) {
1543
            if ($datos['Encabezado']['Totales']['CredEC']===true)
1544
                $datos['Encabezado']['Totales']['CredEC'] = round($datos['Encabezado']['Totales']['IVA'] * 0.65); // TODO: mover a constante o método
1545
            $datos['Encabezado']['Totales']['MntTotal'] -= $datos['Encabezado']['Totales']['CredEC'];
1546
        }
1547
    }
1548
1549
    /**
1550
     * Método que normaliza los datos de transporte
1551
     * @param datos Arreglo con los datos del documento que se desean normalizar
1552
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1553
     * @version 2017-09-01
1554
     */
1555
    private function normalizar_transporte(array &$datos)
1556
    {
1557
        if (!empty($datos['Encabezado']['Transporte'])) {
1558
            $datos['Encabezado']['Transporte'] = array_merge([
1559
                'Patente' => false,
1560
                'RUTTrans' => false,
1561
                'Chofer' => false,
1562
                'DirDest' => false,
1563
                'CmnaDest' => false,
1564
                'CiudadDest' => false,
1565
                'Aduana' => false,
1566
            ], $datos['Encabezado']['Transporte']);
1567
        }
1568
    }
1569
1570
    /**
1571
     * Método que normaliza las boletas electrónicas, dte 39 y 41
1572
     * @param datos Arreglo con los datos del documento que se desean normalizar
1573
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1574
     * @version 2017-08-17
1575
     */
1576
    private function normalizar_boletas(array &$datos)
1577
    {
1578
        // cambiar tags de DTE a boleta si se pasaron
1579 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...
1580
            $datos['Encabezado']['Emisor']['RznSocEmisor'] = $datos['Encabezado']['Emisor']['RznSoc'];
1581
            $datos['Encabezado']['Emisor']['RznSoc'] = false;
1582
        }
1583 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...
1584
            $datos['Encabezado']['Emisor']['GiroEmisor'] = $datos['Encabezado']['Emisor']['GiroEmis'];
1585
            $datos['Encabezado']['Emisor']['GiroEmis'] = false;
1586
        }
1587
        $datos['Encabezado']['Emisor']['Acteco'] = false;
1588
        $datos['Encabezado']['Emisor']['Telefono'] = false;
1589
        $datos['Encabezado']['Emisor']['CorreoEmisor'] = false;
1590
        $datos['Encabezado']['Emisor']['CdgVendedor'] = false;
1591
        $datos['Encabezado']['Receptor']['GiroRecep'] = false;
1592
        $datos['Encabezado']['Receptor']['CorreoRecep'] = false;
1593
        // quitar otros tags que no son parte de las boletas
1594
        $datos['Encabezado']['IdDoc']['FmaPago'] = false;
1595
        $datos['Encabezado']['IdDoc']['FchCancel'] = false;
1596
        $datos['Encabezado']['IdDoc']['TermPagoGlosa'] = false;
1597
        $datos['Encabezado']['RUTSolicita'] = false;
1598
        // si es boleta no nominativa se deja sólo el RUT en el campo del receptor
1599
        if ($datos['Encabezado']['Receptor']['RUTRecep']=='66666666-6') {
1600
            $datos['Encabezado']['Receptor'] = ['RUTRecep'=>'66666666-6'];
1601
        }
1602
        // ajustar las referencias si existen
1603
        if (!empty($datos['Referencia'])) {
1604 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...
1605
                $datos['Referencia'] = [$datos['Referencia']];
1606
            }
1607
            foreach ($datos['Referencia'] as &$r) {
1608
                foreach (['TpoDocRef', 'FolioRef', 'FchRef'] as $c) {
1609
                    if (isset($r[$c])) {
1610
                        unset($r[$c]);
1611
                    }
1612
                }
1613
            }
1614
        }
1615
    }
1616
1617
    /**
1618
     * Método que redondea valores. Si los montos son en pesos chilenos se
1619
     * redondea, si no se mantienen todos los decimales
1620
     * @param valor Valor que se desea redondear
1621
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1622
     * @version 2016-04-05
1623
     */
1624
    private function round($valor, $moneda = false, $decimal = 4)
1625
    {
1626
        return (!$moneda or $moneda=='PESO CL') ? (int)round($valor) : (float)round($valor, $decimal);
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1627
    }
1628
1629
    /**
1630
     * Método que determina el estado de validación sobre el DTE, se verifica:
1631
     *  - Firma del DTE
1632
     *  - RUT del emisor (si se pasó uno para comparar)
1633
     *  - RUT del receptor (si se pasó uno para comparar)
1634
     * @return Código del estado de la validación
1635
     * @warning No se está validando la firma
1636
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1637
     * @version 2015-09-08
1638
     */
1639
    public function getEstadoValidacion(array $datos = null)
1640
    {
1641
        /*if (!$this->checkFirma())
0 ignored issues
show
Unused Code Comprehensibility introduced by
74% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1642
            return 1;*/
1643
        if (is_array($datos)) {
1644
            if (isset($datos['RUTEmisor']) and $this->getEmisor()!=$datos['RUTEmisor'])
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1645
                return 2;
1646
            if (isset($datos['RUTRecep']) and $this->getReceptor()!=$datos['RUTRecep'])
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1647
                return 3;
1648
        }
1649
        return 0;
1650
    }
1651
1652
    /**
1653
     * Método que indica si la firma del DTE es o no válida
1654
     * @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...
1655
     * @warning No se está verificando el valor del DigestValue del documento (sólo la firma de ese DigestValue)
1656
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1657
     * @version 2015-09-08
1658
     */
1659
    public function checkFirma()
1660
    {
1661
        if (!$this->xml)
1662
            return null;
1663
        // obtener firma
1664
        $Signature = $this->xml->documentElement->getElementsByTagName('Signature')->item(0);
1665
        // preparar documento a validar
1666
        $D = $this->xml->documentElement->getElementsByTagName('Documento')->item(0);
1667
        $Documento = new \sasco\LibreDTE\XML();
1668
        $Documento->loadXML($D->C14N());
1669
        $Documento->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi');
1670
        $Documento->documentElement->removeAttributeNS('http://www.sii.cl/SiiDte', '');
1671
        $SignedInfo = new \sasco\LibreDTE\XML();
1672
        $SignedInfo->loadXML($Signature->getElementsByTagName('SignedInfo')->item(0)->C14N());
1673
        $SignedInfo->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi');
1674
        $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...
1675
        $SignatureValue = $Signature->getElementsByTagName('SignatureValue')->item(0)->nodeValue;
1676
        $X509Certificate = $Signature->getElementsByTagName('X509Certificate')->item(0)->nodeValue;
1677
        $X509Certificate = '-----BEGIN CERTIFICATE-----'."\n".wordwrap(trim($X509Certificate), 64, "\n", true)."\n".'-----END CERTIFICATE----- ';
1678
        $valid = openssl_verify($SignedInfo->C14N(), base64_decode($SignatureValue), $X509Certificate) === 1 ? true : false;
1679
        return $valid;
1680
        //return $valid and $DigestValue===base64_encode(sha1($Documento->C14N(), true));
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1681
    }
1682
1683
    /**
1684
     * Método que indica si el documento es o no cedible
1685
     * @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...
1686
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1687
     * @version 2015-09-10
1688
     */
1689
    public function esCedible()
1690
    {
1691
        return !in_array($this->getTipo(), $this->noCedibles);
1692
    }
1693
1694
    /**
1695
     * Método que indica si el documento es o no una boleta electrónica
1696
     * @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...
1697
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1698
     * @version 2015-12-11
1699
     */
1700
    public function esBoleta()
1701
    {
1702
        return in_array($this->getTipo(), [39, 41]);
1703
    }
1704
1705
    /**
1706
     * Método que indica si el documento es o no una exportación
1707
     * @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...
1708
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1709
     * @version 2016-04-05
1710
     */
1711
    public function esExportacion()
1712
    {
1713
        return in_array($this->getTipo(), $this->tipos['Exportaciones']);
1714
    }
1715
1716
    /**
1717
     * Método que valida el schema del DTE
1718
     * @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...
1719
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1720
     * @version 2015-12-15
1721
     */
1722
    public function schemaValidate()
1723
    {
1724
        return true;
1725
    }
1726
1727
    /**
1728
     * Método que valida los datos del DTE
1729
     * @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...
1730
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1731
     * @version 2017-02-06
1732
     */
1733
    public function verificarDatos()
1734
    {
1735
        if (class_exists('\sasco\LibreDTE\Sii\VerificadorDatos')) {
1736
            if (!\sasco\LibreDTE\Sii\VerificadorDatos::Dte($this->getDatos())) {
1737
                return false;
1738
            }
1739
        }
1740
        return true;
1741
    }
1742
1743
    /**
1744
     * Método que obtiene el estado del DTE
1745
     * @param Firma objeto que representa la Firma Electrónca
1746
     * @return Arreglo con el estado del DTE
1747
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1748
     * @version 2015-10-24
1749
     */
1750
    public function getEstado(\sasco\LibreDTE\FirmaElectronica $Firma)
1751
    {
1752
        // solicitar token
1753
        $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...
1754
        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...
1755
            return false;
1756
        // consultar estado dte
1757
        $run = $Firma->getID();
1758
        if ($run===false)
1759
            return false;
1760
        list($RutConsultante, $DvConsultante) = explode('-', $run);
1761
        list($RutCompania, $DvCompania) = explode('-', $this->getEmisor());
1762
        list($RutReceptor, $DvReceptor) = explode('-', $this->getReceptor());
1763
        list($Y, $m, $d) = explode('-', $this->getFechaEmision());
1764
        $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...
1765
            'RutConsultante'    => $RutConsultante,
1766
            'DvConsultante'     => $DvConsultante,
1767
            'RutCompania'       => $RutCompania,
1768
            'DvCompania'        => $DvCompania,
1769
            'RutReceptor'       => $RutReceptor,
1770
            'DvReceptor'        => $DvReceptor,
1771
            'TipoDte'           => $this->getTipo(),
1772
            'FolioDte'          => $this->getFolio(),
1773
            'FechaEmisionDte'   => $d.$m.$Y,
1774
            'MontoDte'          => $this->getMontoTotal(),
1775
            'token'             => $token,
1776
        ]);
1777
        // si el estado se pudo recuperar se muestra
1778
        if ($xml===false)
1779
            return false;
1780
        // entregar estado
1781
        return (array)$xml->xpath('/SII:RESPUESTA/SII:RESP_HDR')[0];
1782
    }
1783
1784
    /**
1785
     * Método que obtiene el estado avanzado del DTE
1786
     * @param Firma objeto que representa la Firma Electrónca
1787
     * @return Arreglo con el estado del DTE
1788
     * @todo Corregir warning y también definir que se retornará (sobre todo en caso de error)
1789
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1790
     * @version 2016-08-05
1791
     */
1792
    public function getEstadoAvanzado(\sasco\LibreDTE\FirmaElectronica $Firma)
1793
    {
1794
        // solicitar token
1795
        $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...
1796
        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...
1797
            return false;
1798
        // consultar estado dte
1799
        list($RutEmpresa, $DvEmpresa) = explode('-', $this->getEmisor());
1800
        list($RutReceptor, $DvReceptor) = explode('-', $this->getReceptor());
1801
        list($Y, $m, $d) = explode('-', $this->getFechaEmision());
1802
        $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...
1803
            'RutEmpresa'       => $RutEmpresa,
1804
            'DvEmpresa'        => $DvEmpresa,
1805
            'RutReceptor'       => $RutReceptor,
1806
            'DvReceptor'        => $DvReceptor,
1807
            'TipoDte'           => $this->getTipo(),
1808
            'FolioDte'          => $this->getFolio(),
1809
            'FechaEmisionDte'   => $d.'-'.$m.'-'.$Y,
1810
            'MontoDte'          => $this->getMontoTotal(),
1811
            'FirmaDte'          => str_replace("\n", '', $this->getFirma()['SignatureValue']),
1812
            'token'             => $token,
1813
        ]);
1814
        // si el estado se pudo recuperar se muestra
1815
        if ($xml===false)
1816
            return false;
1817
        // entregar estado
1818
        return (array)$xml->xpath('/SII:RESPUESTA/SII:RESP_BODY')[0];
1819
    }
1820
1821
    /**
1822
     * Método que entrega la última acción registrada para el DTE en el registro de compra y venta
1823
     * @return Arreglo con los datos de la última acción
1824
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1825
     * @version 2017-08-29
1826
     */
1827
    public function getUltimaAccionRCV(\sasco\LibreDTE\FirmaElectronica $Firma)
1828
    {
1829
        list($emisor_rut, $emisor_dv) = explode('-', $this->getEmisor());
1830
        $RCV = new \sasco\LibreDTE\Sii\RegistroCompraVenta($Firma);
1831
        try {
1832
            $eventos = $RCV->listarEventosHistDoc($emisor_rut, $emisor_dv, $this->getTipo(), $this->getFolio());
1833
            return $eventos ? $eventos[count($eventos)-1] : null;
1834
        } catch (\Exception $e) {
1835
            return null;
1836
        }
1837
    }
1838
1839
}
1840