Completed
Push — master ( 9fc349...910333 )
by Esteban De La Fuente
05:10
created

Dte::normalizar_final()   F

Complexity

Conditions 20
Paths 1887

Size

Total Lines 80
Code Lines 49

Duplication

Lines 3
Ratio 3.75 %

Importance

Changes 0
Metric Value
dl 3
loc 80
rs 2.1875
c 0
b 0
f 0
cc 20
eloc 49
nc 1887
nop 1

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * LibreDTE
5
 * Copyright (C) SASCO SpA (https://sasco.cl)
6
 *
7
 * Este programa es software libre: usted puede redistribuirlo y/o
8
 * modificarlo bajo los términos de la Licencia Pública General Affero de GNU
9
 * publicada por la Fundación para el Software Libre, ya sea la versión
10
 * 3 de la Licencia, o (a su elección) cualquier versión posterior de la
11
 * misma.
12
 *
13
 * Este programa se distribuye con la esperanza de que sea útil, pero
14
 * SIN GARANTÍA ALGUNA; ni siquiera la garantía implícita
15
 * MERCANTIL o de APTITUD PARA UN PROPÓSITO DETERMINADO.
16
 * Consulte los detalles de la Licencia Pública General Affero de GNU para
17
 * obtener una información más detallada.
18
 *
19
 * Debería haber recibido una copia de la Licencia Pública General Affero de GNU
20
 * junto a este programa.
21
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
22
 */
23
24
namespace sasco\LibreDTE\Sii;
25
26
/**
27
 * Clase que representa un DTE y permite trabajar con el
28
 * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
29
 * @version 2017-08-29
30
 */
31
class Dte
32
{
33
34
    private $tipo; ///< Identificador del tipo de DTE: 33 (factura electrónica)
35
    private $folio; ///< Folio del documento
36
    private $xml; ///< Objeto XML que representa el DTE
37
    private $id; ///< Identificador único del DTE
38
    private $tipo_general; ///< Tipo general de DTE: Documento, Liquidacion o Exportaciones
39
    private $timestamp; ///< Timestamp del DTE
40
    private $datos = null; ///< Datos normalizados que se usaron para crear el DTE
41
    private $Signature = null; ///< Datos de la firma del DTE
42
43
    private $tipos = [
44
        'Documento' => [33, 34, 39, 41, 46, 52, 56, 61],
45
        'Liquidacion' => [43],
46
        'Exportaciones' => [110, 111, 112],
47
    ]; ///< Tipos posibles de documentos tributarios electrónicos
48
49
    private $noCedibles = [39, 41, 56, 61, 110, 111, 112]; ///< Documentos que no son cedibles
50
51
    /**
52
     * Constructor de la clase DTE
53
     * @param datos Arreglo con los datos del DTE o el XML completo del DTE
54
     * @param normalizar Si se pasa un arreglo permitirá indicar si el mismo se debe o no normalizar
55
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
56
     * @version 2015-09-03
57
     */
58
    public function __construct($datos, $normalizar = true)
59
    {
60
        if (is_array($datos))
61
            $this->setDatos($datos, $normalizar);
62
        else if (is_string($datos))
63
            $this->loadXML($datos);
64
        $this->timestamp = date('Y-m-d\TH:i:s');
65
    }
66
67
    /**
68
     * Método que carga el DTE ya armado desde un archivo XML
69
     * @param xml String con los datos completos del XML del DTE
70
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
71
     * @version 2016-09-01
72
     */
73
    private function loadXML($xml)
74
    {
75
        if (!empty($xml)) {
76
            $this->xml = new \sasco\LibreDTE\XML();
77
            if (!$this->xml->loadXML($xml) or !$this->schemaValidate()) {
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-09-14
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 ($normalizar and !$this->verificarDatos()) {
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...
145
                return false;
146
            }
147
            return $this->schemaValidate();
148
        }
149
        return false;
150
    }
151
152
    /**
153
     * Método que entrega el arreglo con los datos del DTE.
154
     * Si el DTE fue creado a partir de un arreglo serán los datos normalizados,
155
     * en cambio si se creó a partir de un XML serán todos los nodos del
156
     * documento sin cambios.
157
     * @return Arreglo con datos del DTE
158
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
159
     * @version 2016-07-04
160
     */
161
    public function getDatos()
162
    {
163
        if (!$this->datos) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->datos of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
164
            $datos = $this->xml->toArray();
165
            if (!isset($datos['DTE'][$this->tipo_general])) {
166
                \sasco\LibreDTE\Log::write(
167
                    \sasco\LibreDTE\Estado::DTE_ERROR_GETDATOS,
168
                    \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::DTE_ERROR_GETDATOS)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...do::DTE_ERROR_GETDATOS) is of type integer|string, but the function expects a object<sasco\LibreDTE\Mensaje>|null.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
169
                );
170
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getDatos of type sasco\LibreDTE\Sii\Arreglo.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
171
            }
172
            $this->datos = $datos['DTE'][$this->tipo_general];
173
            if (isset($datos['DTE']['Signature'])) {
174
                $this->Signature = $datos['DTE']['Signature'];
175
            }
176
        }
177
        return $this->datos;
178
    }
179
180
    /**
181
     * Método que entrega el arreglo con los datos de la firma del DTE
182
     * @return Arreglo con datos de la firma
183
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
184
     * @version 2016-06-11
185
     */
186
    public function getFirma()
187
    {
188
        if (!$this->Signature) {
189
            $this->getDatos();
190
        }
191
        return $this->Signature;
192
    }
193
194
    /**
195
     * Método que entrega los datos del DTE (tag Documento) como un string JSON
196
     * @return String JSON "lindo" con los datos del documento
197
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
198
     * @version 2015-09-08
199
     */
200
    public function getJSON()
201
    {
202
        if (!$this->getDatos())
203
            return false;
204
        return json_encode($this->datos, JSON_PRETTY_PRINT);
205
    }
206
207
    /**
208
     * Método que entrega el ID del documento
209
     * @return String con el ID del DTE
210
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
211
     * @version 2016-08-17
212
     */
213
    public function getID($estandar = false)
214
    {
215
        return $estandar ? ('T'.$this->tipo.'F'.$this->folio) : $this->id;
216
    }
217
218
    /**
219
     * Método que entrega el tipo general de documento, de acuerdo a
220
     * $this->tipos
221
     * @param dte Tipo númerico de DTE, ejemplo: 33 (factura electrónica)
222
     * @return String con el tipo general: Documento, Liquidacion o Exportaciones
223
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
224
     * @version 2015-09-17
225
     */
226
    private function getTipoGeneral($dte)
227
    {
228
        foreach ($this->tipos as $tipo => $codigos)
229
            if (in_array($dte, $codigos))
230
                return $tipo;
231
        \sasco\LibreDTE\Log::write(
232
            \sasco\LibreDTE\Estado::DTE_ERROR_TIPO,
233
            \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::DTE_ERROR_TIPO, $dte)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...::DTE_ERROR_TIPO, $dte) is of type integer|string, but the function expects a object<sasco\LibreDTE\Mensaje>|null.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
234
        );
235
        return false;
236
    }
237
238
    /**
239
     * Método que entrega el tipo de DTE
240
     * @return Tipo de dte, ej: 33 (factura electrónica)
241
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
242
     * @version 2015-09-02
243
     */
244
    public function getTipo()
245
    {
246
        return $this->tipo;
247
    }
248
249
    /**
250
     * Método que entrega el folio del DTE
251
     * @return Folio del DTE
252
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
253
     * @version 2015-09-02
254
     */
255
    public function getFolio()
256
    {
257
        return $this->folio;
258
    }
259
260
    /**
261
     * Método que entrega rut del emisor del DTE
262
     * @return RUT del emiro
263
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
264
     * @version 2015-09-07
265
     */
266 View Code Duplication
    public function getEmisor()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
267
    {
268
        $nodo = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Emisor/RUTEmisor')->item(0);
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...ezado/Emisor/RUTEmisor' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
269
        if ($nodo)
270
            return $nodo->nodeValue;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $nodo->nodeValue; (string) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getEmisor of type sasco\LibreDTE\Sii\RUT.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

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

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
273
        return $this->datos['Encabezado']['Emisor']['RUTEmisor'];
274
    }
275
276
    /**
277
     * Método que entrega rut del receptor del DTE
278
     * @return RUT del emiro
279
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
280
     * @version 2015-09-07
281
     */
282 View Code Duplication
    public function getReceptor()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
283
    {
284
        $nodo = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Receptor/RUTRecep')->item(0);
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...zado/Receptor/RUTRecep' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
285
        if ($nodo)
286
            return $nodo->nodeValue;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $nodo->nodeValue; (string) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getReceptor of type sasco\LibreDTE\Sii\RUT.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

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

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
289
        return $this->datos['Encabezado']['Receptor']['RUTRecep'];
290
    }
291
292
    /**
293
     * Método que entrega fecha de emisión del DTE
294
     * @return Fecha de emisión en formato AAAA-MM-DD
295
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
296
     * @version 2015-09-07
297
     */
298 View Code Duplication
    public function getFechaEmision()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
299
    {
300
        $nodo = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/IdDoc/FchEmis')->item(0);
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...cabezado/IdDoc/FchEmis' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
301
        if ($nodo)
302
            return $nodo->nodeValue;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $nodo->nodeValue; (string) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getFechaEmision of type sasco\LibreDTE\Sii\Fecha.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

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

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
305
        return $this->datos['Encabezado']['IdDoc']['FchEmis'];
306
    }
307
308
    /**
309
     * Método que entrega el monto total del DTE
310
     * @return Monto total del DTE
311
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
312
     * @version 2015-09-07
313
     */
314 View Code Duplication
    public function getMontoTotal()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
315
    {
316
        $nodo = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Totales/MntTotal')->item(0);
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...ezado/Totales/MntTotal' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
317
        if ($nodo)
318
            return $nodo->nodeValue;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $nodo->nodeValue; (string) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getMontoTotal of type sasco\LibreDTE\Sii\Monto.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

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

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
321
        return $this->datos['Encabezado']['Totales']['MntTotal'];
322
    }
323
324
    /**
325
     * Método que entrega el tipo de moneda del documento
326
     * @return String con el tipo de moneda
327
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
328
     * @version 2016-07-16
329
     */
330 View Code Duplication
    public function getMoneda()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
331
    {
332
        $nodo = $this->xml->xpath('/DTE/'.$this->tipo_general.'/Encabezado/Totales/TpoMoneda')->item(0);
0 ignored issues
show
Documentation introduced by
'/DTE/' . $this->tipo_ge...zado/Totales/TpoMoneda' is of type string, but the function expects a object<sasco\LibreDTE\Expresión>.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
333
        if ($nodo)
334
            return $nodo->nodeValue;
335
        if (!$this->getDatos())
336
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by sasco\LibreDTE\Sii\Dte::getMoneda of type string.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
337
        return $this->datos['Encabezado']['Totales']['TpoMoneda'];
338
    }
339
340
    /**
341
     * Método que entrega el string XML del tag TED
342
     * @return String XML con tag TED
343
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
344
     * @version 2016-08-03
345
     */
346
    public function getTED()
347
    {
348
        /*$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...
349
        $xml->loadXML($this->xml->getElementsByTagName('TED')->item(0)->getElementsByTagName('DD')->item(0)->C14N());
350
        $xml->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi');
351
        $xml->documentElement->removeAttributeNS('http://www.sii.cl/SiiDte', '');
352
        $FRMT = $this->xml->getElementsByTagName('TED')->item(0)->getElementsByTagName('FRMT')->item(0)->nodeValue;
353
        $pub_key = '';
354
        if (openssl_verify($xml->getFlattened('/'), base64_decode($FRMT), $pub_key, OPENSSL_ALGO_SHA1)!==1);
355
            return false;*/
356
        $xml = new \sasco\LibreDTE\XML();
357
        $TED = $this->xml->getElementsByTagName('TED')->item(0);
358
        if (!$TED)
359
            return '<TED/>';
360
        $xml->loadXML($TED->C14N());
361
        $xml->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi');
362
        $xml->documentElement->removeAttributeNS('http://www.sii.cl/SiiDte', '');
363
        $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...
364
        return mb_detect_encoding($TED, ['UTF-8', 'ISO-8859-1']) != 'ISO-8859-1' ? utf8_decode($TED) : $TED;
365
    }
366
367
    /**
368
     * Método que indica si el DTE es de certificación o no
369
     * @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...
370
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
371
     * @version 2016-06-15
372
     */
373
    public function getCertificacion()
374
    {
375
        $datos = $this->getDatos();
376
        $idk = !empty($datos['TED']['DD']['CAF']['DA']['IDK']) ? (int)$datos['TED']['DD']['CAF']['DA']['IDK'] : null;
377
        return $idk ? $idk === 100 : null;
378
    }
379
380
    /**
381
     * Método que realiza el timbrado del DTE
382
     * @param Folios Objeto de los Folios con los que se desea timbrar
383
     * @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...
384
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
385
     * @version 2016-09-01
386
     */
387
    public function timbrar(Folios $Folios)
388
    {
389
        // verificar que el folio que se está usando para el DTE esté dentro
390
        // del rango de folios autorizados que se usarán para timbrar
391
        // Esta validación NO verifica si el folio ya fue usado, sólo si está
392
        // dentro del CAF que se está usando
393
        $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...
394
        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...
395
            \sasco\LibreDTE\Log::write(
396
                \sasco\LibreDTE\Estado::DTE_ERROR_RANGO_FOLIO,
397
                \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...
398
            );
399
            return false;
400
        }
401
        // verificar que existan datos para el timbre
402 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...
403
            \sasco\LibreDTE\Log::write(
404
                \sasco\LibreDTE\Estado::DTE_FALTA_FCHEMIS,
405
                \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...
406
            );
407
            \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...
408
            return false;
409
        }
410 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...
411
            \sasco\LibreDTE\Log::write(
412
                \sasco\LibreDTE\Estado::DTE_FALTA_MNTTOTAL,
413
                \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...
414
            );
415
            return false;
416
        }
417
        // timbrar
418
        $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...
419
        $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...
420
        $RSR = $RSR_nodo->length ? trim(mb_substr($RSR_nodo->item(0)->nodeValue, 0, 40)) : $RR;
421
        $TED = new \sasco\LibreDTE\XML();
422
        $TED->generate([
423
            'TED' => [
424
                '@attributes' => [
425
                    'version' => '1.0',
426
                ],
427
                'DD' => [
428
                    '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...
429
                    '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...
430
                    'F' => $folio,
431
                    '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...
432
                    '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...
433
                    'RSR' => $RSR,
434
                    '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...
435
                    '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...
436
                    'CAF' => $Folios->getCaf(),
437
                    'TSTED' => $this->timestamp,
438
                ],
439
                'FRMT' => [
440
                    '@attributes' => [
441
                        'algoritmo' => 'SHA1withRSA'
442
                    ],
443
                ],
444
            ]
445
        ]);
446
        $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...
447
        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...
448
            \sasco\LibreDTE\Log::write(
449
                \sasco\LibreDTE\Estado::DTE_ERROR_TIMBRE,
450
                \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...
451
            );
452
            return false;
453
        }
454
        $TED->getElementsByTagName('FRMT')->item(0)->nodeValue = base64_encode($timbre);
455
        $xml = str_replace('<TED/>', trim(str_replace('<?xml version="1.0" encoding="ISO-8859-1"?>', '', $TED->saveXML())), $this->saveXML());
456 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...
457
            \sasco\LibreDTE\Log::write(
458
                \sasco\LibreDTE\Estado::DTE_ERROR_TIMBRE,
459
                \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...
460
            );
461
            return false;
462
        }
463
        return true;
464
    }
465
466
    /**
467
     * Método que realiza la firma del DTE
468
     * @param Firma objeto que representa la Firma Electrónca
469
     * @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...
470
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
471
     * @version 2015-09-17
472
     */
473
    public function firmar(\sasco\LibreDTE\FirmaElectronica $Firma)
474
    {
475
        $parent = $this->xml->getElementsByTagName($this->tipo_general)->item(0);
476
        $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...
477
        $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...
478 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...
479
            \sasco\LibreDTE\Log::write(
480
                \sasco\LibreDTE\Estado::DTE_ERROR_FIRMA,
481
                \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...
482
            );
483
            return false;
484
        }
485
        $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 477 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...
486
        return true;
487
    }
488
489
    /**
490
     * Método que entrega el DTE en XML
491
     * @return XML con el DTE (podría: con o sin timbre y con o sin firma)
492
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
493
     * @version 2015-08-20
494
     */
495
    public function saveXML()
496
    {
497
        return $this->xml->saveXML();
498
    }
499
500
    /**
501
     * Método que genera un arreglo con el resumen del documento. Este resumen
502
     * puede servir, por ejemplo, para generar los detalles de los IECV
503
     * @return Arreglo con el resumen del DTE
504
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
505
     * @version 2016-07-15
506
     */
507
    public function getResumen()
508
    {
509
        $this->getDatos();
510
        // generar resumen
511
        $resumen =  [
512
            'TpoDoc' => (int)$this->datos['Encabezado']['IdDoc']['TipoDTE'],
513
            'NroDoc' => (int)$this->datos['Encabezado']['IdDoc']['Folio'],
514
            'TasaImp' => 0,
515
            'FchDoc' => $this->datos['Encabezado']['IdDoc']['FchEmis'],
516
            'CdgSIISucur' => !empty($this->datos['Encabezado']['Emisor']['CdgSIISucur']) ? $this->datos['Encabezado']['Emisor']['CdgSIISucur'] : false,
517
            'RUTDoc' => $this->datos['Encabezado']['Receptor']['RUTRecep'],
518
            'RznSoc' => isset($this->datos['Encabezado']['Receptor']['RznSocRecep']) ? $this->datos['Encabezado']['Receptor']['RznSocRecep'] : false,
519
            'MntExe' => false,
520
            'MntNeto' => false,
521
            'MntIVA' => 0,
522
            'MntTotal' => 0,
523
        ];
524
        // obtener montos si es que existen en el documento
525
        $montos = ['TasaImp'=>'TasaIVA', 'MntExe'=>'MntExe', 'MntNeto'=>'MntNeto', 'MntIVA'=>'IVA', 'MntTotal'=>'MntTotal'];
526
        foreach ($montos as $dest => $orig) {
527
            if (!empty($this->datos['Encabezado']['Totales'][$orig])) {
528
                $resumen[$dest] = !$this->esExportacion() ? round($this->datos['Encabezado']['Totales'][$orig]) : $this->datos['Encabezado']['Totales'][$orig];
529
            }
530
        }
531
        // si es una boleta se calculan los datos para el resumen
532
        if ($this->esBoleta()) {
533
            if (!$resumen['TasaImp']) {
534
                $resumen['TasaImp'] = \sasco\LibreDTE\Sii::getIVA();
535
            }
536
            $resumen['MntExe'] = (int)$resumen['MntExe'];
537
            if (!$resumen['MntNeto']) {
538
                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...
539
            }
540
        }
541
        // entregar resumen
542
        return $resumen;
543
    }
544
545
    /**
546
     * Método que permite obtener el monto neto y el IVA de ese neto a partir de
547
     * un monto total
548
     * @param total neto + iva
549
     * @param tasa Tasa del IVA
550
     * @return Arreglo con el neto y el iva
551
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
552
     * @version 2016-04-05
553
     */
554
    private function calcularNetoIVA($total, $tasa = null)
555
    {
556
        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...
557
            return [0, 0];
558
        if ($tasa === null)
559
            $tasa = \sasco\LibreDTE\Sii::getIVA();
560
        // WARNING: el IVA obtenido puede no ser el NETO*(TASA/100)
561
        // se calcula el monto neto y luego se obtiene el IVA haciendo la resta
562
        // entre el total y el neto, ya que hay casos de borde como:
563
        //  - BRUTO:   680 => NETO:   571 e IVA:   108 => TOTAL:   679
564
        //  - BRUTO: 86710 => NETO: 72866 e IVA: 13845 => TOTAL: 86711
565
        $neto = round($total / (1+($tasa/100)));
566
        $iva = $total - $neto;
567
        return [$neto, $iva];
568
    }
569
570
    /**
571
     * Método que normaliza los datos de un documento tributario electrónico
572
     * @param datos Arreglo con los datos del documento que se desean normalizar
573
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
574
     * @version 2017-07-24
575
     */
576
    private function normalizar(array &$datos)
577
    {
578
        // completar con nodos por defecto
579
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
580
            'Encabezado' => [
581
                'IdDoc' => [
582
                    'TipoDTE' => false,
583
                    'Folio' => false,
584
                    'FchEmis' => date('Y-m-d'),
585
                    'IndNoRebaja' => false,
586
                    'TipoDespacho' => false,
587
                    'IndTraslado' => false,
588
                    'TpoImpresion' => false,
589
                    'IndServicio' => $this->esBoleta() ? 3 : false,
590
                    'MntBruto' => false,
591
                    'FmaPago' => false,
592
                    'FmaPagExp' => false,
593
                    'MntCancel' => false,
594
                    'SaldoInsol' => false,
595
                    'FchCancel' => false,
596
                    'MntPagos' => false,
597
                    'PeriodoDesde' => false,
598
                    'PeriodoHasta' => false,
599
                    'MedioPago' => false,
600
                    'TpoCtaPago' => false,
601
                    'NumCtaPago' => false,
602
                    'BcoPago' => false,
603
                    'TermPagoCdg' => false,
604
                    'TermPagoGlosa' => false,
605
                    'TermPagoDias' => false,
606
                    'FchVenc' => false,
607
                ],
608
                'Emisor' => [
609
                    'RUTEmisor' => false,
610
                    'RznSoc' => false,
611
                    'GiroEmis' => false,
612
                    'Telefono' => false,
613
                    'CorreoEmisor' => false,
614
                    'Acteco' => false,
615
                    'Sucursal' => false,
616
                    'CdgSIISucur' => false,
617
                    'DirOrigen' => false,
618
                    'CmnaOrigen' => false,
619
                    'CiudadOrigen' => false,
620
                    'CdgVendedor' => false,
621
                ],
622
                'Receptor' => [
623
                    'RUTRecep' => false,
624
                    'CdgIntRecep' => false,
625
                    'RznSocRecep' => false,
626
                    'Extranjero' => false,
627
                    'GiroRecep' => false,
628
                    'Contacto' => false,
629
                    'CorreoRecep' => false,
630
                    'DirRecep' => false,
631
                    'CmnaRecep' => false,
632
                    'CiudadRecep' => false,
633
                    'DirPostal' => false,
634
                    'CmnaPostal' => false,
635
                    'CiudadPostal' => false,
636
                ],
637
                'Totales' => [
638
                    'TpoMoneda' => false,
639
                ],
640
            ],
641
            'Detalle' => false,
642
            'SubTotInfo' => false,
643
            'DscRcgGlobal' => false,
644
            'Referencia' => false,
645
            'Comisiones' => false,
646
        ], $datos);
647
        // corregir algunos datos que podrían venir malos para no caer por schema
648
        $datos['Encabezado']['Emisor']['RUTEmisor'] = strtoupper($datos['Encabezado']['Emisor']['RUTEmisor']);
649
        $datos['Encabezado']['Receptor']['RUTRecep'] = strtoupper($datos['Encabezado']['Receptor']['RUTRecep']);
650
        $datos['Encabezado']['Receptor']['RznSocRecep'] = mb_substr($datos['Encabezado']['Receptor']['RznSocRecep'], 0, 100);
651 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...
652
            $datos['Encabezado']['Receptor']['GiroRecep'] = mb_substr($datos['Encabezado']['Receptor']['GiroRecep'], 0, 40);
653
        }
654 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...
655
            $datos['Encabezado']['Receptor']['Contacto'] = mb_substr($datos['Encabezado']['Receptor']['Contacto'], 0, 80);
656
        }
657 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...
658
            $datos['Encabezado']['Receptor']['CorreoRecep'] = mb_substr($datos['Encabezado']['Receptor']['CorreoRecep'], 0, 80);
659
        }
660 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...
661
            $datos['Encabezado']['Receptor']['DirRecep'] = mb_substr($datos['Encabezado']['Receptor']['DirRecep'], 0, 70);
662
        }
663 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...
664
            $datos['Encabezado']['Receptor']['CmnaRecep'] = mb_substr($datos['Encabezado']['Receptor']['CmnaRecep'], 0, 20);
665
        }
666
        // si existe descuento o recargo global se normalizan
667
        if (!empty($datos['DscRcgGlobal'])) {
668 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...
669
                $datos['DscRcgGlobal'] = [$datos['DscRcgGlobal']];
670
            $NroLinDR = 1;
671
            foreach ($datos['DscRcgGlobal'] as &$dr) {
672
                $dr = array_merge([
673
                    'NroLinDR' => $NroLinDR++,
674
                ], $dr);
675
            }
676
        }
677
        // si existe una o más referencias se normalizan
678
        if (!empty($datos['Referencia'])) {
679 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...
680
                $datos['Referencia'] = [$datos['Referencia']];
681
            }
682
            $NroLinRef = 1;
683
            foreach ($datos['Referencia'] as &$r) {
684
                $r = array_merge([
685
                    'NroLinRef' => $NroLinRef++,
686
                    'TpoDocRef' => false,
687
                    'IndGlobal' => false,
688
                    'FolioRef' => false,
689
                    'RUTOtr' => false,
690
                    'FchRef' => date('Y-m-d'),
691
                    'CodRef' => false,
692
                    'RazonRef' => false,
693
                ], $r);
694
            }
695
        }
696
    }
697
698
    /**
699
     * Método que realiza la normalización final de los datos de un documento
700
     * tributario electrónico. Esto se aplica todos los documentos una vez que
701
     * ya se aplicaron las normalizaciones por tipo
702
     * @param datos Arreglo con los datos del documento que se desean normalizar
703
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
704
     * @version 2017-09-23
705
     */
706
    private function normalizar_final(array &$datos)
707
    {
708
        // normalizar montos de pagos programados
709
        if (is_array($datos['Encabezado']['IdDoc']['MntPagos'])) {
710
            $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...
711 View Code Duplication
            if (!isset($datos['Encabezado']['IdDoc']['MntPagos'][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...
712
                $datos['Encabezado']['IdDoc']['MntPagos'] = [$datos['Encabezado']['IdDoc']['MntPagos']];
713
            }
714
            foreach ($datos['Encabezado']['IdDoc']['MntPagos'] as &$MntPagos) {
715
                $MntPagos = array_merge([
716
                    'FchPago' => null,
717
                    'MntPago' => null,
718
                    'GlosaPagos' => false,
719
                ], $MntPagos);
720
                if ($MntPagos['MntPago']===null) {
721
                    $MntPagos['MntPago'] = $datos['Encabezado']['Totales']['MntTotal'];
722
                }
723
            }
724
        }
725
        // si existe OtraMoneda se verifican los tipos de cambio y totales
726
        if (!empty($datos['Encabezado']['OtraMoneda'])) {
727
            if (!isset($datos['Encabezado']['OtraMoneda'][0])) {
728
                $datos['Encabezado']['OtraMoneda'] = [$datos['Encabezado']['OtraMoneda']];
729
            }
730
            foreach ($datos['Encabezado']['OtraMoneda'] as &$OtraMoneda) {
731
                // colocar campos por defecto
732
                $OtraMoneda = array_merge([
733
                    'TpoMoneda' => false,
734
                    'TpoCambio' => false,
735
                    'MntNetoOtrMnda' => false,
736
                    'MntExeOtrMnda' => false,
737
                    'MntFaeCarneOtrMnda' => false,
738
                    'MntMargComOtrMnda' => false,
739
                    'IVAOtrMnda' => false,
740
                    'ImpRetOtrMnda' => false,
741
                    'IVANoRetOtrMnda' => false,
742
                    'MntTotOtrMnda' => false,
743
                ], $OtraMoneda);
744
                // si no hay tipo de cambio no seguir
745
                if (empty($OtraMoneda['TpoCambio'])) {
746
                    continue;
747
                }
748
                // buscar si los valores están asignados, si no lo están asignar
749
                // usando el tipo de cambio que existe para la moneda
750
                foreach (['MntNeto', 'MntExe', 'IVA', 'IVANoRet'] as $monto) {
751
                    if (empty($OtraMoneda[$monto.'OtrMnda']) and !empty($datos['Encabezado']['Totales'][$monto])) {
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...
752
                        $OtraMoneda[$monto.'OtrMnda'] = round($datos['Encabezado']['Totales'][$monto] * $OtraMoneda['TpoCambio'], 4);
753
                    }
754
                }
755
                // calcular MntFaeCarneOtrMnda, MntMargComOtrMnda, ImpRetOtrMnda
756
                if (empty($OtraMoneda['MntFaeCarneOtrMnda'])) {
757
                    $OtraMoneda['MntFaeCarneOtrMnda'] = false; // TODO
758
                }
759
                if (empty($OtraMoneda['MntMargComOtrMnda'])) {
760
                    $OtraMoneda['MntMargComOtrMnda'] = false; // TODO
761
                }
762
                if (empty($OtraMoneda['ImpRetOtrMnda'])) {
763
                    $OtraMoneda['ImpRetOtrMnda'] = false; // TODO
764
                }
765
                // calcular monto total
766
                if (empty($OtraMoneda['MntTotOtrMnda'])) {
767
                    $OtraMoneda['MntTotOtrMnda'] = 0;
768
                    $cols = ['MntNetoOtrMnda', 'MntExeOtrMnda', 'MntFaeCarneOtrMnda', 'MntMargComOtrMnda', 'IVAOtrMnda', 'IVANoRetOtrMnda'];
769
                    foreach ($cols as $monto) {
770
                        if (!empty($OtraMoneda[$monto])) {
771
                            $OtraMoneda['MntTotOtrMnda'] += $OtraMoneda[$monto];
772
                        }
773
                    }
774
                    // agregar total de impuesto retenido otra moneda
775
                    if (!empty($OtraMoneda['ImpRetOtrMnda'])) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
776
                        // TODO
777
                    }
778
                    // aproximar el total si es en pesos chilenos
779
                    if ($OtraMoneda['TpoMoneda']=='PESO CL') {
780
                        $OtraMoneda['MntTotOtrMnda'] = round($OtraMoneda['MntTotOtrMnda']);
781
                    }
782
                }
783
            }
784
        }
785
    }
786
787
    /**
788
     * Método que normaliza los datos de una factura electrónica
789
     * @param datos Arreglo con los datos del documento que se desean normalizar
790
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
791
     * @version 2017-09-01
792
     */
793
    private function normalizar_33(array &$datos)
794
    {
795
        // completar con nodos por defecto
796
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
797
            'Encabezado' => [
798
                'IdDoc' => false,
799
                'Emisor' => false,
800
                'RUTMandante' => false,
801
                'Receptor' => false,
802
                'RUTSolicita' => false,
803
                'Transporte' => false,
804
                'Totales' => [
805
                    'MntNeto' => 0,
806
                    'MntExe' => false,
807
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
808
                    'IVA' => 0,
809
                    'ImptoReten' => false,
810
                    'CredEC' => false,
811
                    'MntTotal' => 0,
812
                ],
813
                'OtraMoneda' => false,
814
            ],
815
        ], $datos);
816
        // normalizar datos
817
        $this->normalizar_detalle($datos);
818
        $this->normalizar_aplicar_descuentos_recargos($datos);
819
        $this->normalizar_impuesto_retenido($datos);
820
        $this->normalizar_agregar_IVA_MntTotal($datos);
821
        $this->normalizar_transporte($datos);
822
    }
823
824
    /**
825
     * Método que normaliza los datos de una factura exenta electrónica
826
     * @param datos Arreglo con los datos del documento que se desean normalizar
827
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
828
     * @version 2017-02-23
829
     */
830
    private function normalizar_34(array &$datos)
831
    {
832
        // completar con nodos por defecto
833
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
834
            'Encabezado' => [
835
                'IdDoc' => false,
836
                'Emisor' => false,
837
                'Receptor' => false,
838
                'RUTSolicita' => false,
839
                'Totales' => [
840
                    'MntExe' => false,
841
                    'MntTotal' => 0,
842
                ]
843
            ],
844
        ], $datos);
845
        // normalizar datos
846
        $this->normalizar_detalle($datos);
847
        $this->normalizar_aplicar_descuentos_recargos($datos);
848
        $this->normalizar_agregar_IVA_MntTotal($datos);
849
    }
850
851
    /**
852
     * Método que normaliza los datos de una boleta electrónica
853
     * @param datos Arreglo con los datos del documento que se desean normalizar
854
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
855
     * @version 2016-03-14
856
     */
857 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...
858
    {
859
        // completar con nodos por defecto
860
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
861
            'Encabezado' => [
862
                'IdDoc' => false,
863
                'Emisor' => [
864
                    'RUTEmisor' => false,
865
                    'RznSocEmisor' => false,
866
                    'GiroEmisor' => false,
867
                ],
868
                'Receptor' => false,
869
                'Totales' => [
870
                    'MntExe' => false,
871
                    'MntTotal' => 0,
872
                ]
873
            ],
874
        ], $datos);
875
        // normalizar datos
876
        $this->normalizar_boletas($datos);
877
        $this->normalizar_detalle($datos);
878
        $this->normalizar_aplicar_descuentos_recargos($datos);
879
        $this->normalizar_agregar_IVA_MntTotal($datos);
880
    }
881
882
    /**
883
     * Método que normaliza los datos de una boleta exenta electrónica
884
     * @param datos Arreglo con los datos del documento que se desean normalizar
885
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
886
     * @version 2016-03-14
887
     */
888 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...
889
    {
890
        // completar con nodos por defecto
891
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
892
            'Encabezado' => [
893
                'IdDoc' => false,
894
                'Emisor' => [
895
                    'RUTEmisor' => false,
896
                    'RznSocEmisor' => false,
897
                    'GiroEmisor' => false,
898
                ],
899
                'Receptor' => false,
900
                'Totales' => [
901
                    'MntExe' => 0,
902
                    'MntTotal' => 0,
903
                ]
904
            ],
905
        ], $datos);
906
        // normalizar datos
907
        $this->normalizar_boletas($datos);
908
        $this->normalizar_detalle($datos);
909
        $this->normalizar_aplicar_descuentos_recargos($datos);
910
        $this->normalizar_agregar_IVA_MntTotal($datos);
911
    }
912
913
    /**
914
     * Método que normaliza los datos de una factura de compra electrónica
915
     * @param datos Arreglo con los datos del documento que se desean normalizar
916
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
917
     * @version 2016-02-26
918
     */
919
    private function normalizar_46(array &$datos)
920
    {
921
        // completar con nodos por defecto
922
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
923
            'Encabezado' => [
924
                'IdDoc' => false,
925
                'Emisor' => false,
926
                'Receptor' => false,
927
                'RUTSolicita' => false,
928
                'Totales' => [
929
                    'MntNeto' => 0,
930
                    'MntExe' => false,
931
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
932
                    'IVA' => 0,
933
                    'ImptoReten' => false,
934
                    'IVANoRet' => false,
935
                    'MntTotal' => 0,
936
                ]
937
            ],
938
        ], $datos);
939
        // normalizar datos
940
        $this->normalizar_detalle($datos);
941
        $this->normalizar_aplicar_descuentos_recargos($datos);
942
        $this->normalizar_impuesto_retenido($datos);
943
        $this->normalizar_agregar_IVA_MntTotal($datos);
944
    }
945
946
    /**
947
     * Método que normaliza los datos de una guía de despacho electrónica
948
     * @param datos Arreglo con los datos del documento que se desean normalizar
949
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
950
     * @version 2017-09-01
951
     */
952
    private function normalizar_52(array &$datos)
953
    {
954
        // completar con nodos por defecto
955
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
956
            'Encabezado' => [
957
                'IdDoc' => false,
958
                'Emisor' => false,
959
                'Receptor' => false,
960
                'RUTSolicita' => false,
961
                'Transporte' => false,
962
                'Totales' => [
963
                    'MntNeto' => 0,
964
                    'MntExe' => false,
965
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
966
                    'IVA' => 0,
967
                    'ImptoReten' => false,
968
                    'CredEC' => false,
969
                    'MntTotal' => 0,
970
                ]
971
            ],
972
        ], $datos);
973
        // si es traslado interno se copia el emisor en el receptor sólo si el
974
        // receptor no está definido o bien si el receptor tiene RUT diferente
975
        // al emisor
976
        if ($datos['Encabezado']['IdDoc']['IndTraslado']==5) {
977
            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...
978
                $datos['Encabezado']['Receptor'] = [];
979
                $cols = [
980
                    'RUTEmisor'=>'RUTRecep',
981
                    'RznSoc'=>'RznSocRecep',
982
                    'GiroEmis'=>'GiroRecep',
983
                    'Telefono'=>'Contacto',
984
                    'CorreoEmisor'=>'CorreoRecep',
985
                    'DirOrigen'=>'DirRecep',
986
                    'CmnaOrigen'=>'CmnaRecep',
987
                ];
988
                foreach ($cols as $emisor => $receptor) {
989
                    if (!empty($datos['Encabezado']['Emisor'][$emisor])) {
990
                        $datos['Encabezado']['Receptor'][$receptor] = $datos['Encabezado']['Emisor'][$emisor];
991
                    }
992
                }
993 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...
994
                    $datos['Encabezado']['Receptor']['GiroRecep'] = mb_substr($datos['Encabezado']['Receptor']['GiroRecep'], 0, 40);
995
                }
996
            }
997
        }
998
        // normalizar datos
999
        $this->normalizar_detalle($datos);
1000
        $this->normalizar_aplicar_descuentos_recargos($datos);
1001
        $this->normalizar_impuesto_retenido($datos);
1002
        $this->normalizar_agregar_IVA_MntTotal($datos);
1003
        $this->normalizar_transporte($datos);
1004
    }
1005
1006
    /**
1007
     * Método que normaliza los datos de una nota de débito
1008
     * @param datos Arreglo con los datos del documento que se desean normalizar
1009
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1010
     * @version 2017-02-23
1011
     */
1012 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...
1013
    {
1014
        // completar con nodos por defecto
1015
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1016
            'Encabezado' => [
1017
                'IdDoc' => false,
1018
                'Emisor' => false,
1019
                'Receptor' => false,
1020
                'RUTSolicita' => false,
1021
                'Totales' => [
1022
                    'MntNeto' => 0,
1023
                    'MntExe' => 0,
1024
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
1025
                    'IVA' => false,
1026
                    'ImptoReten' => false,
1027
                    'IVANoRet' => false,
1028
                    'CredEC' => false,
1029
                    'MntTotal' => 0,
1030
                ]
1031
            ],
1032
        ], $datos);
1033
        // normalizar datos
1034
        $this->normalizar_detalle($datos);
1035
        $this->normalizar_aplicar_descuentos_recargos($datos);
1036
        $this->normalizar_impuesto_retenido($datos);
1037
        $this->normalizar_agregar_IVA_MntTotal($datos);
1038
        if (!$datos['Encabezado']['Totales']['MntNeto']) {
1039
            $datos['Encabezado']['Totales']['MntNeto'] = 0;
1040
            $datos['Encabezado']['Totales']['TasaIVA'] = false;
1041
        }
1042
    }
1043
1044
    /**
1045
     * Método que normaliza los datos de una nota de crédito
1046
     * @param datos Arreglo con los datos del documento que se desean normalizar
1047
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1048
     * @version 2017-02-23
1049
     */
1050 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...
1051
    {
1052
        // completar con nodos por defecto
1053
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1054
            'Encabezado' => [
1055
                'IdDoc' => false,
1056
                'Emisor' => false,
1057
                'Receptor' => false,
1058
                'RUTSolicita' => false,
1059
                'Totales' => [
1060
                    'MntNeto' => 0,
1061
                    'MntExe' => 0,
1062
                    'TasaIVA' => \sasco\LibreDTE\Sii::getIVA(),
1063
                    'IVA' => false,
1064
                    'ImptoReten' => false,
1065
                    'IVANoRet' => false,
1066
                    'CredEC' => false,
1067
                    'MntTotal' => 0,
1068
                ]
1069
            ],
1070
        ], $datos);
1071
        // normalizar datos
1072
        $this->normalizar_detalle($datos);
1073
        $this->normalizar_aplicar_descuentos_recargos($datos);
1074
        $this->normalizar_impuesto_retenido($datos);
1075
        $this->normalizar_agregar_IVA_MntTotal($datos);
1076
        if (!$datos['Encabezado']['Totales']['MntNeto']) {
1077
            $datos['Encabezado']['Totales']['MntNeto'] = 0;
1078
            $datos['Encabezado']['Totales']['TasaIVA'] = false;
1079
        }
1080
    }
1081
1082
    /**
1083
     * Método que normaliza los datos de una factura electrónica de exportación
1084
     * @param datos Arreglo con los datos del documento que se desean normalizar
1085
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1086
     * @version 2016-04-05
1087
     */
1088 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...
1089
    {
1090
        // completar con nodos por defecto
1091
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1092
            'Encabezado' => [
1093
                'IdDoc' => false,
1094
                'Emisor' => false,
1095
                'Receptor' => false,
1096
                'Transporte' => [
1097
                    'Patente' => false,
1098
                    'RUTTrans' => false,
1099
                    'Chofer' => false,
1100
                    'DirDest' => false,
1101
                    'CmnaDest' => false,
1102
                    'CiudadDest' => false,
1103
                    'Aduana' => [
1104
                        'CodModVenta' => false,
1105
                        'CodClauVenta' => false,
1106
                        'TotClauVenta' => false,
1107
                        'CodViaTransp' => false,
1108
                        'NombreTransp' => false,
1109
                        'RUTCiaTransp' => false,
1110
                        'NomCiaTransp' => false,
1111
                        'IdAdicTransp' => false,
1112
                        'Booking' => false,
1113
                        'Operador' => false,
1114
                        'CodPtoEmbarque' => false,
1115
                        'IdAdicPtoEmb' => false,
1116
                        'CodPtoDesemb' => false,
1117
                        'IdAdicPtoDesemb' => false,
1118
                        'Tara' => false,
1119
                        'CodUnidMedTara' => false,
1120
                        'PesoBruto' => false,
1121
                        'CodUnidPesoBruto' => false,
1122
                        'PesoNeto' => false,
1123
                        'CodUnidPesoNeto' => false,
1124
                        'TotItems' => false,
1125
                        'TotBultos' => false,
1126
                        'TipoBultos' => false,
1127
                        'MntFlete' => false,
1128
                        'MntSeguro' => false,
1129
                        'CodPaisRecep' => false,
1130
                        'CodPaisDestin' => false,
1131
                    ],
1132
                ],
1133
                'Totales' => [
1134
                    'TpoMoneda' => null,
1135
                    'MntExe' => 0,
1136
                    'MntTotal' => 0,
1137
                ]
1138
            ],
1139
        ], $datos);
1140
        // normalizar datos
1141
        $this->normalizar_detalle($datos);
1142
        $this->normalizar_aplicar_descuentos_recargos($datos);
1143
        $this->normalizar_impuesto_retenido($datos);
1144
        $this->normalizar_agregar_IVA_MntTotal($datos);
1145
        $this->normalizar_exportacion($datos);
1146
    }
1147
1148
    /**
1149
     * Método que normaliza los datos de una nota de débito de exportación
1150
     * @param datos Arreglo con los datos del documento que se desean normalizar
1151
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1152
     * @version 2016-04-05
1153
     */
1154 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...
1155
    {
1156
        // completar con nodos por defecto
1157
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1158
            'Encabezado' => [
1159
                'IdDoc' => false,
1160
                'Emisor' => false,
1161
                'Receptor' => false,
1162
                'Transporte' => [
1163
                    'Patente' => false,
1164
                    'RUTTrans' => false,
1165
                    'Chofer' => false,
1166
                    'DirDest' => false,
1167
                    'CmnaDest' => false,
1168
                    'CiudadDest' => false,
1169
                    'Aduana' => [
1170
                        'CodModVenta' => false,
1171
                        'CodClauVenta' => false,
1172
                        'TotClauVenta' => false,
1173
                        'CodViaTransp' => false,
1174
                        'NombreTransp' => false,
1175
                        'RUTCiaTransp' => false,
1176
                        'NomCiaTransp' => false,
1177
                        'IdAdicTransp' => false,
1178
                        'Booking' => false,
1179
                        'Operador' => false,
1180
                        'CodPtoEmbarque' => false,
1181
                        'IdAdicPtoEmb' => false,
1182
                        'CodPtoDesemb' => false,
1183
                        'IdAdicPtoDesemb' => false,
1184
                        'Tara' => false,
1185
                        'CodUnidMedTara' => false,
1186
                        'PesoBruto' => false,
1187
                        'CodUnidPesoBruto' => false,
1188
                        'PesoNeto' => false,
1189
                        'CodUnidPesoNeto' => false,
1190
                        'TotItems' => false,
1191
                        'TotBultos' => false,
1192
                        'TipoBultos' => false,
1193
                        'MntFlete' => false,
1194
                        'MntSeguro' => false,
1195
                        'CodPaisRecep' => false,
1196
                        'CodPaisDestin' => false,
1197
                    ],
1198
                ],
1199
                'Totales' => [
1200
                    'TpoMoneda' => null,
1201
                    'MntExe' => 0,
1202
                    'MntTotal' => 0,
1203
                ]
1204
            ],
1205
        ], $datos);
1206
        // normalizar datos
1207
        $this->normalizar_detalle($datos);
1208
        $this->normalizar_aplicar_descuentos_recargos($datos);
1209
        $this->normalizar_impuesto_retenido($datos);
1210
        $this->normalizar_agregar_IVA_MntTotal($datos);
1211
        $this->normalizar_exportacion($datos);
1212
    }
1213
1214
    /**
1215
     * Método que normaliza los datos de una nota de crédito de exportación
1216
     * @param datos Arreglo con los datos del documento que se desean normalizar
1217
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1218
     * @version 2016-04-05
1219
     */
1220 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...
1221
    {
1222
        // completar con nodos por defecto
1223
        $datos = \sasco\LibreDTE\Arreglo::mergeRecursiveDistinct([
1224
            'Encabezado' => [
1225
                'IdDoc' => false,
1226
                'Emisor' => false,
1227
                'Receptor' => false,
1228
                'Transporte' => [
1229
                    'Patente' => false,
1230
                    'RUTTrans' => false,
1231
                    'Chofer' => false,
1232
                    'DirDest' => false,
1233
                    'CmnaDest' => false,
1234
                    'CiudadDest' => false,
1235
                    'Aduana' => [
1236
                        'CodModVenta' => false,
1237
                        'CodClauVenta' => false,
1238
                        'TotClauVenta' => false,
1239
                        'CodViaTransp' => false,
1240
                        'NombreTransp' => false,
1241
                        'RUTCiaTransp' => false,
1242
                        'NomCiaTransp' => false,
1243
                        'IdAdicTransp' => false,
1244
                        'Booking' => false,
1245
                        'Operador' => false,
1246
                        'CodPtoEmbarque' => false,
1247
                        'IdAdicPtoEmb' => false,
1248
                        'CodPtoDesemb' => false,
1249
                        'IdAdicPtoDesemb' => false,
1250
                        'Tara' => false,
1251
                        'CodUnidMedTara' => false,
1252
                        'PesoBruto' => false,
1253
                        'CodUnidPesoBruto' => false,
1254
                        'PesoNeto' => false,
1255
                        'CodUnidPesoNeto' => false,
1256
                        'TotItems' => false,
1257
                        'TotBultos' => false,
1258
                        'TipoBultos' => false,
1259
                        'MntFlete' => false,
1260
                        'MntSeguro' => false,
1261
                        'CodPaisRecep' => false,
1262
                        'CodPaisDestin' => false,
1263
                    ],
1264
                ],
1265
                'Totales' => [
1266
                    'TpoMoneda' => null,
1267
                    'MntExe' => 0,
1268
                    'MntTotal' => 0,
1269
                ]
1270
            ],
1271
        ], $datos);
1272
        // normalizar datos
1273
        $this->normalizar_detalle($datos);
1274
        $this->normalizar_aplicar_descuentos_recargos($datos);
1275
        $this->normalizar_impuesto_retenido($datos);
1276
        $this->normalizar_agregar_IVA_MntTotal($datos);
1277
        $this->normalizar_exportacion($datos);
1278
    }
1279
1280
    /**
1281
     * Método que normaliza los datos de exportacion de un documento
1282
     * @param datos Arreglo con los datos del documento que se desean normalizar
1283
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1284
     * @version 2017-10-03
1285
     */
1286
    public function normalizar_exportacion(array &$datos)
1287
    {
1288
        // agregar modalidad de venta por defecto si no existe
1289
        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...
1290
            $datos['Encabezado']['Transporte']['Aduana']['CodModVenta'] = 1;
1291
        }
1292
        // quitar campos que no son parte del documento de exportacion
1293
        $datos['Encabezado']['Receptor']['CmnaRecep'] = false;
1294
        // colocar forma de pago de exportación
1295
        if (!empty($datos['Encabezado']['IdDoc']['FmaPago'])) {
1296
            $formas = [3 => 21];
1297 View Code Duplication
            if (isset($formas[$datos['Encabezado']['IdDoc']['FmaPago']])) {
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...
1298
                $datos['Encabezado']['IdDoc']['FmaPagExp'] = $formas[$datos['Encabezado']['IdDoc']['FmaPago']];
1299
            }
1300
            $datos['Encabezado']['IdDoc']['FmaPago'] = false;
1301
        }
1302
    }
1303
1304
    /**
1305
     * Método que normaliza los detalles del documento
1306
     * @param datos Arreglo con los datos del documento que se desean normalizar
1307
     * @warning Revisar como se aplican descuentos y recargos, ¿debería ser un porcentaje del monto original?
1308
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1309
     * @version 2017-07-24
1310
     */
1311
    private function normalizar_detalle(array &$datos)
1312
    {
1313
        if (!isset($datos['Detalle'][0]))
1314
            $datos['Detalle'] = [$datos['Detalle']];
1315
        $item = 1;
1316
        foreach ($datos['Detalle'] as &$d) {
1317
            $d = array_merge([
1318
                'NroLinDet' => $item++,
1319
                'CdgItem' => false,
1320
                'IndExe' => false,
1321
                'Retenedor' => false,
1322
                'NmbItem' => false,
1323
                'DscItem' => false,
1324
                'QtyRef' => false,
1325
                'UnmdRef' => false,
1326
                'PrcRef' => false,
1327
                'QtyItem' => false,
1328
                'Subcantidad' => false,
1329
                'FchElabor' => false,
1330
                'FchVencim' => false,
1331
                'UnmdItem' => false,
1332
                'PrcItem' => false,
1333
                'DescuentoPct' => false,
1334
                'DescuentoMonto' => false,
1335
                'RecargoPct' => false,
1336
                'RecargoMonto' => false,
1337
                'CodImpAdic' => false,
1338
                'MontoItem' => false,
1339
            ], $d);
1340
            // corregir datos
1341
            $d['NmbItem'] = mb_substr($d['NmbItem'], 0, 80);
1342
            if (!empty($d['DscItem'])) {
1343
                $d['DscItem'] = mb_substr($d['DscItem'], 0, 1000);
1344
            }
1345
            // normalizar
1346
            if ($this->esExportacion()) {
1347
                $d['IndExe'] = 1;
1348
            }
1349
            if (is_array($d['CdgItem'])) {
1350
                $d['CdgItem'] = array_merge([
1351
                    'TpoCodigo' => false,
1352
                    'VlrCodigo' => false,
1353
                ], $d['CdgItem']);
1354
                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...
1355
                    $d['Retenedor'] = true;
1356
                }
1357
            }
1358
            if ($d['Retenedor']!==false) {
1359
                if (!is_array($d['Retenedor'])) {
1360
                    $d['Retenedor'] = ['IndAgente'=>'R'];
1361
                }
1362
                $d['Retenedor'] = array_merge([
1363
                    'IndAgente' => 'R',
1364
                    'MntBaseFaena' => false,
1365
                    'MntMargComer' => false,
1366
                    'PrcConsFinal' => false,
1367
                ], $d['Retenedor']);
1368
            }
1369
            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...
1370
                $d['CdgItem'] = [
1371
                    'TpoCodigo' => empty($d['Retenedor']['IndAgente']) ? 'INT1' : 'CPCS',
1372
                    'VlrCodigo' => $d['CdgItem'],
1373
                ];
1374
            }
1375
            if ($d['PrcItem']) {
1376
                if (!$d['QtyItem'])
1377
                    $d['QtyItem'] = 1;
1378
                if (empty($d['MontoItem'])) {
1379
                    $d['MontoItem'] = $this->round(
1380
                        $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...
1381
                        $datos['Encabezado']['Totales']['TpoMoneda']
1382
                    );
1383
                    // aplicar descuento
1384
                    if ($d['DescuentoPct']) {
1385
                        $d['DescuentoMonto'] = round($d['MontoItem'] * (int)$d['DescuentoPct']/100);
1386
                    }
1387
                    $d['MontoItem'] -= $d['DescuentoMonto'];
1388
                    // aplicar recargo
1389
                    if ($d['RecargoPct']) {
1390
                        $d['RecargoMonto'] = round($d['MontoItem'] * (int)$d['RecargoPct']/100);
1391
                    }
1392
                    $d['MontoItem'] += $d['RecargoMonto'];
1393
                    // aproximar monto del item
1394
                    $d['MontoItem'] = $this->round(
1395
                        $d['MontoItem'], $datos['Encabezado']['Totales']['TpoMoneda']
1396
                    );
1397
                }
1398
            } else if (empty($d['MontoItem'])) {
1399
                $d['MontoItem'] = 0;
1400
            }
1401
            // sumar valor del monto a MntNeto o MntExe según corresponda
1402
            if ($d['MontoItem']) {
1403
                // si no es boleta
1404
                if (!$this->esBoleta()) {
1405
                    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...
1406
                        $datos['Encabezado']['Totales']['MntExe'] += $d['MontoItem'];
1407 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...
1408
                        if (!empty($d['IndExe'])) {
1409
                            if ($d['IndExe']==1) {
1410
                                $datos['Encabezado']['Totales']['MntExe'] += $d['MontoItem'];
1411
                            }
1412
                        } else {
1413
                            $datos['Encabezado']['Totales']['MntNeto'] += $d['MontoItem'];
1414
                        }
1415
                    }
1416
                }
1417
                // si es boleta
1418 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...
1419
                    // si es exento
1420
                    if (!empty($d['IndExe'])) {
1421
                        if ($d['IndExe']==1) {
1422
                            $datos['Encabezado']['Totales']['MntExe'] += $d['MontoItem'];
1423
                        }
1424
                    }
1425
                    // agregar al monto total
1426
                    $datos['Encabezado']['Totales']['MntTotal'] += $d['MontoItem'];
1427
                }
1428
            }
1429
        }
1430
    }
1431
1432
    /**
1433
     * Método que aplica los descuentos y recargos generales respectivos a los
1434
     * montos que correspondan según e indicador del descuento o recargo
1435
     * @param datos Arreglo con los datos del documento que se desean normalizar
1436
     * @warning Boleta afecta con algún item exento el descuento se podría estar aplicando mal
1437
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1438
     * @version 2017-09-06
1439
     */
1440
    private function normalizar_aplicar_descuentos_recargos(array &$datos)
1441
    {
1442
        if (!empty($datos['DscRcgGlobal'])) {
1443 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...
1444
                $datos['DscRcgGlobal'] = [$datos['DscRcgGlobal']];
1445
            foreach ($datos['DscRcgGlobal'] as &$dr) {
1446
                $dr = array_merge([
1447
                    'NroLinDR' => false,
1448
                    'TpoMov' => false,
1449
                    'GlosaDR' => false,
1450
                    'TpoValor' => false,
1451
                    'ValorDR' => false,
1452
                    'ValorDROtrMnda' => false,
1453
                    'IndExeDR' => false,
1454
                ], $dr);
1455
                if ($this->esExportacion()) {
1456
                    $dr['IndExeDR'] = 1;
1457
                }
1458
                // determinar a que aplicar el descuento/recargo
1459
                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...
1460
                    $monto = $this->getTipo()==39 ? 'MntTotal' : 'MntNeto';
1461
                } else if ($dr['IndExeDR']==1) {
1462
                    $monto = 'MntExe';
1463
                } else if ($dr['IndExeDR']==2) {
1464
                    $monto = 'MontoNF';
1465
                }
1466
                // si no hay monto al que aplicar el descuento se omite
1467
                if (empty($datos['Encabezado']['Totales'][$monto])) {
1468
                    continue;
1469
                }
1470
                // calcular valor del descuento o recargo
1471
                if ($dr['TpoValor']=='$') {
1472
                    $dr['ValorDR'] = $this->round($dr['ValorDR'], $datos['Encabezado']['Totales']['TpoMoneda'], 2);
1473
                }
1474
                $valor =
1475
                    $dr['TpoValor']=='%'
1476
                    ? $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...
1477
                    : $dr['ValorDR']
1478
                ;
1479
                // aplicar descuento
1480
                if ($dr['TpoMov']=='D') {
1481
                    $datos['Encabezado']['Totales'][$monto] -= $valor;
1482
                }
1483
                // aplicar recargo
1484
                else if ($dr['TpoMov']=='R') {
1485
                    $datos['Encabezado']['Totales'][$monto] += $valor;
1486
                }
1487
                $datos['Encabezado']['Totales'][$monto] = $this->round(
1488
                    $datos['Encabezado']['Totales'][$monto],
1489
                    $datos['Encabezado']['Totales']['TpoMoneda']
1490
                );
1491
                // si el descuento global se aplica a una boleta exenta se copia el valor exento al total
1492
                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...
1493
                    $datos['Encabezado']['Totales']['MntTotal'] = $datos['Encabezado']['Totales']['MntExe'];
1494
                }
1495
            }
1496
        }
1497
    }
1498
1499
    /**
1500
     * Método que calcula los montos de impuestos adicionales o retenciones
1501
     * @param datos Arreglo con los datos del documento que se desean normalizar
1502
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1503
     * @version 2016-04-05
1504
     */
1505
    private function normalizar_impuesto_retenido(array &$datos)
1506
    {
1507
        // copiar montos
1508
        $montos = [];
1509
        foreach ($datos['Detalle'] as &$d) {
1510
            if (!empty($d['CodImpAdic'])) {
1511
                if (!isset($montos[$d['CodImpAdic']]))
1512
                    $montos[$d['CodImpAdic']] = 0;
1513
                $montos[$d['CodImpAdic']] += $d['MontoItem'];
1514
            }
1515
        }
1516
        // si hay montos y no hay total para impuesto retenido se arma
1517
        if (!empty($montos)) {
1518 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...
1519
                $datos['Encabezado']['Totales']['ImptoReten'] = [];
1520
            } else if (!isset($datos['Encabezado']['Totales']['ImptoReten'][0])) {
1521
                $datos['Encabezado']['Totales']['ImptoReten'] = [$datos['Encabezado']['Totales']['ImptoReten']];
1522
            }
1523
        }
1524
        // armar impuesto adicional o retención en los totales
1525
        foreach ($montos as $codigo => $neto) {
1526
            // buscar si existe el impuesto en los totales
1527
            $i = 0;
1528
            foreach ($datos['Encabezado']['Totales']['ImptoReten'] as &$ImptoReten) {
1529
                if ($ImptoReten['TipoImp']==$codigo) {
1530
                    break;
1531
                }
1532
                $i++;
1533
            }
1534
            // si no existe se crea
1535 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...
1536
                $datos['Encabezado']['Totales']['ImptoReten'][] = [
1537
                    'TipoImp' => $codigo
1538
                ];
1539
            }
1540
            // se normaliza
1541
            $datos['Encabezado']['Totales']['ImptoReten'][$i] = array_merge([
1542
                'TipoImp' => $codigo,
1543
                'TasaImp' => ImpuestosAdicionales::getTasa($codigo),
1544
                'MontoImp' => null,
1545
            ], $datos['Encabezado']['Totales']['ImptoReten'][$i]);
1546
            // si el monto no existe se asigna
1547
            if ($datos['Encabezado']['Totales']['ImptoReten'][$i]['MontoImp']===null) {
1548
                $datos['Encabezado']['Totales']['ImptoReten'][$i]['MontoImp'] = round(
1549
                    $neto * $datos['Encabezado']['Totales']['ImptoReten'][$i]['TasaImp']/100
1550
                );
1551
            }
1552
        }
1553
        // quitar los codigos que no existen en el detalle
1554
        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...
1555
            $codigos = array_keys($montos);
1556
            $n_impuestos = count($datos['Encabezado']['Totales']['ImptoReten']);
1557
            for ($i=0; $i<$n_impuestos; $i++) {
1558 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...
1559
                    unset($datos['Encabezado']['Totales']['ImptoReten'][$i]);
1560
                }
1561
            }
1562
            sort($datos['Encabezado']['Totales']['ImptoReten']);
1563
        }
1564
    }
1565
1566
    /**
1567
     * Método que calcula el monto del IVA y el monto total del documento a
1568
     * partir del monto neto y la tasa de IVA si es que existe
1569
     * @param datos Arreglo con los datos del documento que se desean normalizar
1570
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1571
     * @version 2016-04-05
1572
     */
1573
    private function normalizar_agregar_IVA_MntTotal(array &$datos)
1574
    {
1575
        // agregar IVA y monto total
1576
        if (!empty($datos['Encabezado']['Totales']['MntNeto'])) {
1577
            if ($datos['Encabezado']['IdDoc']['MntBruto']==1) {
1578
                list($datos['Encabezado']['Totales']['MntNeto'], $datos['Encabezado']['Totales']['IVA']) = $this->calcularNetoIVA(
1579
                    $datos['Encabezado']['Totales']['MntNeto'],
1580
                    $datos['Encabezado']['Totales']['TasaIVA']
1581
                );
1582
            } else {
1583
                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...
1584
                    $datos['Encabezado']['Totales']['IVA'] = round(
1585
                        $datos['Encabezado']['Totales']['MntNeto']*($datos['Encabezado']['Totales']['TasaIVA']/100)
1586
                    );
1587
                }
1588
            }
1589
            if (empty($datos['Encabezado']['Totales']['MntTotal'])) {
1590
                $datos['Encabezado']['Totales']['MntTotal'] = $datos['Encabezado']['Totales']['MntNeto'];
1591
                if (!empty($datos['Encabezado']['Totales']['IVA']))
1592
                    $datos['Encabezado']['Totales']['MntTotal'] += $datos['Encabezado']['Totales']['IVA'];
1593
                if (!empty($datos['Encabezado']['Totales']['MntExe']))
1594
                    $datos['Encabezado']['Totales']['MntTotal'] += $datos['Encabezado']['Totales']['MntExe'];
1595
            }
1596 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...
1597
            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...
1598
                $datos['Encabezado']['Totales']['MntTotal'] = $datos['Encabezado']['Totales']['MntExe'];
1599
            }
1600
        }
1601
        // si hay impuesto retenido o adicional se contabiliza en el total
1602
        if (!empty($datos['Encabezado']['Totales']['ImptoReten'])) {
1603
            foreach ($datos['Encabezado']['Totales']['ImptoReten'] as &$ImptoReten) {
1604
                // si es retención se resta al total y se traspasaa IVA no retenido
1605
                // en caso que corresponda
1606
                if (ImpuestosAdicionales::getTipo($ImptoReten['TipoImp'])=='R') {
1607
                    $datos['Encabezado']['Totales']['MntTotal'] -= $ImptoReten['MontoImp'];
1608
                    if ($ImptoReten['MontoImp']!=$datos['Encabezado']['Totales']['IVA']) {
1609
                        $datos['Encabezado']['Totales']['IVANoRet'] = $datos['Encabezado']['Totales']['IVA'] - $ImptoReten['MontoImp'];
1610
                    }
1611
                }
1612
                // si es adicional se suma al total
1613
                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...
1614
                    $datos['Encabezado']['Totales']['MntTotal'] += $ImptoReten['MontoImp'];
1615
                }
1616
            }
1617
        }
1618
        // si hay impuesto de crédito a constructoras del 65% se descuenta del total
1619
        if (!empty($datos['Encabezado']['Totales']['CredEC'])) {
1620
            if ($datos['Encabezado']['Totales']['CredEC']===true)
1621
                $datos['Encabezado']['Totales']['CredEC'] = round($datos['Encabezado']['Totales']['IVA'] * 0.65); // TODO: mover a constante o método
1622
            $datos['Encabezado']['Totales']['MntTotal'] -= $datos['Encabezado']['Totales']['CredEC'];
1623
        }
1624
    }
1625
1626
    /**
1627
     * Método que normaliza los datos de transporte
1628
     * @param datos Arreglo con los datos del documento que se desean normalizar
1629
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1630
     * @version 2017-09-01
1631
     */
1632
    private function normalizar_transporte(array &$datos)
1633
    {
1634
        if (!empty($datos['Encabezado']['Transporte'])) {
1635
            $datos['Encabezado']['Transporte'] = array_merge([
1636
                'Patente' => false,
1637
                'RUTTrans' => false,
1638
                'Chofer' => false,
1639
                'DirDest' => false,
1640
                'CmnaDest' => false,
1641
                'CiudadDest' => false,
1642
                'Aduana' => false,
1643
            ], $datos['Encabezado']['Transporte']);
1644
        }
1645
    }
1646
1647
    /**
1648
     * Método que normaliza las boletas electrónicas, dte 39 y 41
1649
     * @param datos Arreglo con los datos del documento que se desean normalizar
1650
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1651
     * @version 2017-10-04
1652
     */
1653
    private function normalizar_boletas(array &$datos)
1654
    {
1655
        // cambiar tags de DTE a boleta si se pasaron
1656 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...
1657
            $datos['Encabezado']['Emisor']['RznSocEmisor'] = $datos['Encabezado']['Emisor']['RznSoc'];
1658
            $datos['Encabezado']['Emisor']['RznSoc'] = false;
1659
        }
1660 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...
1661
            $datos['Encabezado']['Emisor']['GiroEmisor'] = $datos['Encabezado']['Emisor']['GiroEmis'];
1662
            $datos['Encabezado']['Emisor']['GiroEmis'] = false;
1663
        }
1664
        $datos['Encabezado']['Emisor']['Acteco'] = false;
1665
        $datos['Encabezado']['Emisor']['Telefono'] = false;
1666
        $datos['Encabezado']['Emisor']['CorreoEmisor'] = false;
1667
        $datos['Encabezado']['Emisor']['CdgVendedor'] = false;
1668
        $datos['Encabezado']['Receptor']['GiroRecep'] = false;
1669
        if (!empty($datos['Encabezado']['Receptor']['CorreoRecep'])) {
1670
            $datos['Referencia'][] = [
1671
                'NroLinRef' => !empty($datos['Referencia']) ? (count($datos['Referencia'])+1) : 1,
1672
                'RazonRef' => mb_substr('Email receptor: '.$datos['Encabezado']['Receptor']['CorreoRecep'], 0, 90),
1673
            ];
1674
        }
1675
        $datos['Encabezado']['Receptor']['CorreoRecep'] = false;
1676
        // quitar otros tags que no son parte de las boletas
1677
        $datos['Encabezado']['IdDoc']['FmaPago'] = false;
1678
        $datos['Encabezado']['IdDoc']['FchCancel'] = false;
1679
        $datos['Encabezado']['IdDoc']['TermPagoGlosa'] = false;
1680
        $datos['Encabezado']['RUTSolicita'] = false;
1681
        // si es boleta no nominativa se deja sólo el RUT en el campo del receptor
1682
        if ($datos['Encabezado']['Receptor']['RUTRecep']=='66666666-6') {
1683
            $datos['Encabezado']['Receptor'] = ['RUTRecep'=>'66666666-6'];
1684
        }
1685
        // ajustar las referencias si existen
1686
        if (!empty($datos['Referencia'])) {
1687 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...
1688
                $datos['Referencia'] = [$datos['Referencia']];
1689
            }
1690
            foreach ($datos['Referencia'] as &$r) {
1691
                foreach (['TpoDocRef', 'FolioRef', 'FchRef'] as $c) {
1692
                    if (isset($r[$c])) {
1693
                        unset($r[$c]);
1694
                    }
1695
                }
1696
            }
1697
        }
1698
    }
1699
1700
    /**
1701
     * Método que redondea valores. Si los montos son en pesos chilenos se
1702
     * redondea, si no se mantienen todos los decimales
1703
     * @param valor Valor que se desea redondear
1704
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1705
     * @version 2016-04-05
1706
     */
1707
    private function round($valor, $moneda = false, $decimal = 4)
1708
    {
1709
        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...
1710
    }
1711
1712
    /**
1713
     * Método que determina el estado de validación sobre el DTE, se verifica:
1714
     *  - Firma del DTE
1715
     *  - RUT del emisor (si se pasó uno para comparar)
1716
     *  - RUT del receptor (si se pasó uno para comparar)
1717
     * @return Código del estado de la validación
1718
     * @warning No se está validando la firma
1719
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1720
     * @version 2015-09-08
1721
     */
1722
    public function getEstadoValidacion(array $datos = null)
1723
    {
1724
        /*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...
1725
            return 1;*/
1726
        if (is_array($datos)) {
1727
            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...
1728
                return 2;
1729
            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...
1730
                return 3;
1731
        }
1732
        return 0;
1733
    }
1734
1735
    /**
1736
     * Método que indica si la firma del DTE es o no válida
1737
     * @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...
1738
     * @warning No se está verificando el valor del DigestValue del documento (sólo la firma de ese DigestValue)
1739
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1740
     * @version 2015-09-08
1741
     */
1742
    public function checkFirma()
1743
    {
1744
        if (!$this->xml)
1745
            return null;
1746
        // obtener firma
1747
        $Signature = $this->xml->documentElement->getElementsByTagName('Signature')->item(0);
1748
        // preparar documento a validar
1749
        $D = $this->xml->documentElement->getElementsByTagName('Documento')->item(0);
1750
        $Documento = new \sasco\LibreDTE\XML();
1751
        $Documento->loadXML($D->C14N());
1752
        $Documento->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi');
1753
        $Documento->documentElement->removeAttributeNS('http://www.sii.cl/SiiDte', '');
1754
        $SignedInfo = new \sasco\LibreDTE\XML();
1755
        $SignedInfo->loadXML($Signature->getElementsByTagName('SignedInfo')->item(0)->C14N());
1756
        $SignedInfo->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi');
1757
        $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...
1758
        $SignatureValue = $Signature->getElementsByTagName('SignatureValue')->item(0)->nodeValue;
1759
        $X509Certificate = $Signature->getElementsByTagName('X509Certificate')->item(0)->nodeValue;
1760
        $X509Certificate = '-----BEGIN CERTIFICATE-----'."\n".wordwrap(trim($X509Certificate), 64, "\n", true)."\n".'-----END CERTIFICATE----- ';
1761
        $valid = openssl_verify($SignedInfo->C14N(), base64_decode($SignatureValue), $X509Certificate) === 1 ? true : false;
1762
        return $valid;
1763
        //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...
1764
    }
1765
1766
    /**
1767
     * Método que indica si el documento es o no cedible
1768
     * @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...
1769
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1770
     * @version 2015-09-10
1771
     */
1772
    public function esCedible()
1773
    {
1774
        return !in_array($this->getTipo(), $this->noCedibles);
1775
    }
1776
1777
    /**
1778
     * Método que indica si el documento es o no una boleta electrónica
1779
     * @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...
1780
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1781
     * @version 2015-12-11
1782
     */
1783
    public function esBoleta()
1784
    {
1785
        return in_array($this->getTipo(), [39, 41]);
1786
    }
1787
1788
    /**
1789
     * Método que indica si el documento es o no una exportación
1790
     * @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...
1791
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1792
     * @version 2016-04-05
1793
     */
1794
    public function esExportacion()
1795
    {
1796
        return in_array($this->getTipo(), $this->tipos['Exportaciones']);
1797
    }
1798
1799
    /**
1800
     * Método que valida el schema del DTE
1801
     * @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...
1802
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1803
     * @version 2015-12-15
1804
     */
1805
    public function schemaValidate()
1806
    {
1807
        return true;
1808
    }
1809
1810
    /**
1811
     * Método que valida los datos del DTE
1812
     * @return =true si no hay errores de validación, =false si se encontraron errores al validar
0 ignored issues
show
Documentation introduced by
The doc-type =true could not be parsed: Unknown type name "=true" at position 0. (view supported doc-types)

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

Loading history...
1813
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1814
     * @version 2017-02-06
1815
     */
1816
    public function verificarDatos()
1817
    {
1818
        if (class_exists('\sasco\LibreDTE\Sii\VerificadorDatos')) {
1819
            if (!\sasco\LibreDTE\Sii\VerificadorDatos::Dte($this->getDatos())) {
1820
                return false;
1821
            }
1822
        }
1823
        return true;
1824
    }
1825
1826
    /**
1827
     * Método que obtiene el estado del DTE
1828
     * @param Firma objeto que representa la Firma Electrónca
1829
     * @return Arreglo con el estado del DTE
1830
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1831
     * @version 2015-10-24
1832
     */
1833
    public function getEstado(\sasco\LibreDTE\FirmaElectronica $Firma)
1834
    {
1835
        // solicitar token
1836
        $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...
1837
        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...
1838
            return false;
1839
        // consultar estado dte
1840
        $run = $Firma->getID();
1841
        if ($run===false)
1842
            return false;
1843
        list($RutConsultante, $DvConsultante) = explode('-', $run);
1844
        list($RutCompania, $DvCompania) = explode('-', $this->getEmisor());
1845
        list($RutReceptor, $DvReceptor) = explode('-', $this->getReceptor());
1846
        list($Y, $m, $d) = explode('-', $this->getFechaEmision());
1847
        $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...
1848
            'RutConsultante'    => $RutConsultante,
1849
            'DvConsultante'     => $DvConsultante,
1850
            'RutCompania'       => $RutCompania,
1851
            'DvCompania'        => $DvCompania,
1852
            'RutReceptor'       => $RutReceptor,
1853
            'DvReceptor'        => $DvReceptor,
1854
            'TipoDte'           => $this->getTipo(),
1855
            'FolioDte'          => $this->getFolio(),
1856
            'FechaEmisionDte'   => $d.$m.$Y,
1857
            'MontoDte'          => $this->getMontoTotal(),
1858
            'token'             => $token,
1859
        ]);
1860
        // si el estado se pudo recuperar se muestra
1861
        if ($xml===false)
1862
            return false;
1863
        // entregar estado
1864
        return (array)$xml->xpath('/SII:RESPUESTA/SII:RESP_HDR')[0];
1865
    }
1866
1867
    /**
1868
     * Método que obtiene el estado avanzado del DTE
1869
     * @param Firma objeto que representa la Firma Electrónca
1870
     * @return Arreglo con el estado del DTE
1871
     * @todo Corregir warning y también definir que se retornará (sobre todo en caso de error)
1872
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1873
     * @version 2016-08-05
1874
     */
1875
    public function getEstadoAvanzado(\sasco\LibreDTE\FirmaElectronica $Firma)
1876
    {
1877
        // solicitar token
1878
        $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...
1879
        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...
1880
            return false;
1881
        // consultar estado dte
1882
        list($RutEmpresa, $DvEmpresa) = explode('-', $this->getEmisor());
1883
        list($RutReceptor, $DvReceptor) = explode('-', $this->getReceptor());
1884
        list($Y, $m, $d) = explode('-', $this->getFechaEmision());
1885
        $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...
1886
            'RutEmpresa'       => $RutEmpresa,
1887
            'DvEmpresa'        => $DvEmpresa,
1888
            'RutReceptor'       => $RutReceptor,
1889
            'DvReceptor'        => $DvReceptor,
1890
            'TipoDte'           => $this->getTipo(),
1891
            'FolioDte'          => $this->getFolio(),
1892
            'FechaEmisionDte'   => $d.'-'.$m.'-'.$Y,
1893
            'MontoDte'          => $this->getMontoTotal(),
1894
            'FirmaDte'          => str_replace("\n", '', $this->getFirma()['SignatureValue']),
1895
            'token'             => $token,
1896
        ]);
1897
        // si el estado se pudo recuperar se muestra
1898
        if ($xml===false)
1899
            return false;
1900
        // entregar estado
1901
        return (array)$xml->xpath('/SII:RESPUESTA/SII:RESP_BODY')[0];
1902
    }
1903
1904
    /**
1905
     * Método que entrega la última acción registrada para el DTE en el registro de compra y venta
1906
     * @return Arreglo con los datos de la última acción
1907
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1908
     * @version 2017-08-29
1909
     */
1910
    public function getUltimaAccionRCV(\sasco\LibreDTE\FirmaElectronica $Firma)
1911
    {
1912
        list($emisor_rut, $emisor_dv) = explode('-', $this->getEmisor());
1913
        $RCV = new \sasco\LibreDTE\Sii\RegistroCompraVenta($Firma);
1914
        try {
1915
            $eventos = $RCV->listarEventosHistDoc($emisor_rut, $emisor_dv, $this->getTipo(), $this->getFolio());
1916
            return $eventos ? $eventos[count($eventos)-1] : null;
1917
        } catch (\Exception $e) {
1918
            return null;
1919
        }
1920
    }
1921
1922
}
1923