Completed
Push — master ( f59f35...5996f2 )
by Esteban De La Fuente
02:50
created

Dte::agregarNormal()   D

Complexity

Conditions 9
Paths 16

Size

Total Lines 43
Code Lines 31

Duplication

Lines 2
Ratio 4.65 %

Importance

Changes 0
Metric Value
dl 2
loc 43
rs 4.909
c 0
b 0
f 0
cc 9
eloc 31
nc 16
nop 2
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\PDF;
25
26
/**
27
 * Clase para generar el PDF de un documento tributario electrónico (DTE)
28
 * chileno.
29
 * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
30
 * @version 2016-11-18
31
 */
32
class Dte extends \sasco\LibreDTE\PDF
33
{
34
35
    private $dte; ///< Tipo de DTE que se está generando
36
    private $logo; ///< Datos del logo que se ubicará en el PDF (ruta, datos y/o posición)
37
    private $resolucion; ///< Arreglo con los datos de la resolución (índices: NroResol y FchResol)
38
    private $cedible = false; ///< Por defecto DTEs no son cedibles
39
    protected $papelContinuo = false; ///< Indica si se usa papel continuo o no
40
    private $sinAcuseRecibo = [39, 41, 56, 61, 110, 111, 112]; ///< Boletas, notas de crédito y notas de débito no tienen acuse de recibo
41
    private $web_verificacion = 'www.sii.cl'; ///< Página web para verificar el documento
42
    private $ecl = 5; ///< error correction level para PHP >= 7.0.0
43
44
    private $tipos = [
45
        // códigos oficiales SII
46
        29 => 'FACTURA DE INICIO',
47
        30 => 'FACTURA',
48
        32 => 'FACTURA DE VENTA BIENES Y SERVICIOS NO AFECTOS O EXENTOS DE IVA',
49
        33 => 'FACTURA ELECTRÓNICA',
50
        34 => 'FACTURA NO AFECTA O EXENTA ELECTRÓNICA',
51
        35 => 'BOLETA',
52
        38 => 'BOLETA EXENTA',
53
        39 => 'BOLETA ELECTRÓNICA',
54
        40 => 'LIQUIDACION FACTURA',
55
        41 => 'BOLETA NO AFECTA O EXENTA ELECTRÓNICA',
56
        43 => 'LIQUIDACIÓN FACTURA ELECTRÓNICA',
57
        45 => 'FACTURA DE COMPRA',
58
        46 => 'FACTURA DE COMPRA ELECTRÓNICA',
59
        48 => 'COMPROBANTE DE PAGO ELECTRÓNICO',
60
        50 => 'GUÍA DE DESPACHO',
61
        52 => 'GUÍA DE DESPACHO ELECTRÓNICA',
62
        55 => 'NOTA DE DÉBITO',
63
        56 => 'NOTA DE DÉBITO ELECTRÓNICA',
64
        60 => 'NOTA DE CRÉDITO',
65
        61 => 'NOTA DE CRÉDITO ELECTRÓNICA',
66
        101 => 'FACTURA DE EXPORTACIÓN',
67
        102 => 'FACTURA DE VENTA EXENTA A ZONA FRANCA PRIMARIA',
68
        103 => 'LIQUIDACIÓN',
69
        104 => 'NOTA DE DÉBITO DE EXPORTACIÓN',
70
        105 => 'BOLETA LIQUIDACIÓN',
71
        106 => 'NOTA DE CRÉDITO DE EXPORTACIÓN',
72
        108 => 'SOLICITUD REGISTRO DE FACTURA (SRF)',
73
        109 => 'FACTURA TURISTA',
74
        110 => 'FACTURA DE EXPORTACIÓN ELECTRÓNICA',
75
        111 => 'NOTA DE DÉBITO DE EXPORTACIÓN ELECTRÓNICA',
76
        112 => 'NOTA DE CRÉDITO DE EXPORTACIÓN ELECTRÓNICA',
77
        801 => 'ORDEN DE COMPRA',
78
        802 => 'NOTA DE PEDIDO',
79
        803 => 'CONTRATO',
80
        804 => 'RESOLUCIÓN',
81
        805 => 'PROCEDO CHILECOMPRA',
82
        806 => 'FICHA CHILECOMPRA',
83
        807 => 'DUS',
84
        808 => 'B/L (CONOCIMIENTO DE EMBARQUE)',
85
        809 => 'AWB',
86
        810 => 'MIC (MANIFIESTO INTERNACIONAL)',
87
        811 => 'CARTA DE PORTE',
88
        812 => 'RESOLUCION SNA',
89
        813 => 'PASAPORTE',
90
        814 => 'CERTIFICADO DE DEPÓSITO BOLSA PROD. CHILE',
91
        815 => 'VALE DE PRENDA BOLSA PROD. CHILE',
92
        901 => 'FACTURA DE VENTAS A EMPRESAS DEL TERRITORIO PREFERENCIAL',
93
        902 => 'CONOCIMIENTO DE EMBARQUE',
94
        903 => 'DOCUMENTO ÚNICO DE SALIDA (DUS)',
95
        904 => 'FACTURA DE TRASPASO',
96
        905 => 'FACTURA DE REEXPEDICIÓN',
97
        906 => 'BOLETAS VENTA MÓDULOS ZF (TODAS)',
98
        907 => 'FACTURAS VENTA MÓDULO ZF (TODAS)',
99
        909 => 'FACTURAS VENTA MÓDULO ZF',
100
        910 => 'SOLICITUD TRASLADO ZONA FRANCA (Z)',
101
        911 => 'DECLARACIÓN DE INGRESO A ZONA FRANCA PRIMARIA',
102
        914 => 'DECLARACIÓN DE INGRESO (DIN)',
103
        919 => 'RESUMEN VENTAS DE NACIONALES PASAJES SIN FACTURA',
104
        920 => 'OTROS REGISTROS NO DOCUMENTADOS (AUMENTA DÉBITO)',
105
        922 => 'OTROS REGISTROS (DISMINUYE DÉBITO)',
106
        924 => 'RESUMEN VENTAS DE INTERNACIONALES PASAJES SIN FACTURA',
107
        // códigos de LibreDTE
108
        0 => 'COTIZACIÓN',
109
        'HES' => 'HOJA DE ENTRADA DE SERVICIOS (HES)',
110
    ]; ///< Glosas para los tipos de documentos (DTE y otros)
111
112
    private $formas_pago = [
113
        1 => 'Contado',
114
        2 => 'Crédito',
115
        3 => 'Sin costo',
116
    ]; ///< Glosas de las formas de pago
117
118
    private $formas_pago_exportacion = [
119
        1 => 'Cobranza hasta 1 año',
120
        2 => 'Cobranza más de 1 año',
121
        11 => 'Acreditivo hasta 1 año',
122
        12 => 'Acreditivo más de 1 año',
123
        21 => 'Sin pago',
124
        32 => 'Pago anticipado a la fecha de embarque',
125
    ]; ///< Códigos de forma de pago (básicos) de la aduana para exportaciones
126
127
    private $detalle_cols = [
128
        'CdgItem' => ['title'=>'Código', 'align'=>'left', 'width'=>20],
129
        'NmbItem' => ['title'=>'Item', 'align'=>'left', 'width'=>0],
130
        'IndExe' => ['title'=>'IE', 'align'=>'left', 'width'=>'7'],
131
        'QtyItem' => ['title'=>'Cant.', 'align'=>'right', 'width'=>15],
132
        'UnmdItem' => ['title'=>'Unidad', 'align'=>'left', 'width'=>22],
133
        'PrcItem' => ['title'=>'P. unitario', 'align'=>'right', 'width'=>22],
134
        'DescuentoMonto' => ['title'=>'Descuento', 'align'=>'right', 'width'=>22],
135
        'RecargoMonto' => ['title'=>'Recargo', 'align'=>'right', 'width'=>22],
136
        'MontoItem' => ['title'=>'Total item', 'align'=>'right', 'width'=>22],
137
    ]; ///< Nombres de columnas detalle, alineación y ancho
138
139
    private $item_detalle_posicion = 0; ///< Posición del detalle del item respecto al nombre
140
    private $detalle_fuente = 10; ///< Tamaño de la fuente para el detalle en hoja carta
141
142
    private $traslados = [
143
        1 => 'Operación constituye venta',
144
        2 => 'Ventas por efectuar',
145
        3 => 'Consignaciones',
146
        4 => 'Entrega gratuita',
147
        5 => 'Traslados internos',
148
        6 => 'Otros traslados no venta',
149
        7 => 'Guía de devolución',
150
        8 => 'Traslado para exportación (no venta)',
151
        9 => 'Venta para exportación',
152
    ]; ///< Tipos de traslado para guías de despacho
153
154
    public static $papel = [
155
        0  => 'Hoja carta',
156
        75 => 'Papel contínuo 75mm',
157
        80 => 'Papel contínuo 80mm',
158
    ]; ///< Tamaño de papel que es soportado
159
160
    /**
161
     * Constructor de la clase
162
     * @param papelContinuo =true indica que el PDF se generará en formato papel continuo (si se pasa un número será el ancho del PDF en mm)
163
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
164
     * @version 2016-10-06
165
     */
166
    public function __construct($papelContinuo = false)
167
    {
168
        parent::__construct();
169
        $this->SetTitle('Documento Tributario Electrónico (DTE) de Chile by LibreDTE');
170
        $this->papelContinuo = $papelContinuo === true ? 80 : $papelContinuo;
0 ignored issues
show
Documentation Bug introduced by
It seems like $papelContinuo === true ? 80 : $papelContinuo can also be of type integer. However, the property $papelContinuo is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
171
    }
172
173
    /**
174
     * Método que asigna la ubicación del logo de la empresa
175
     * @param logo URI del logo (puede ser local o en una URL)
176
     * @param posicion Posición respecto a datos del emisor (=0 izq, =1 arriba)
177
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
178
     * @version 2016-08-04
179
     */
180
    public function setLogo($logo, $posicion = 0)
181
    {
182
        $this->logo = [
183
            'uri' => $logo,
184
            'posicion' => (int)$posicion,
185
        ];
186
    }
187
188
    /**
189
     * Método que asigna los datos de la resolución del SII que autoriza al
190
     * emisor a emitir DTEs
191
     * @param resolucion Arreglo con índices NroResol y FchResol
192
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
193
     * @version 2015-09-08
194
     */
195
    public function setResolucion(array $resolucion)
196
    {
197
        $this->resolucion = $resolucion;
198
    }
199
200
    /**
201
     * Método que asigna la página web que se debe utilizar para indicar donde
202
     * se puede verificar el DTE
203
     * @param web Página web donde se puede verificar el documento
204
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
205
     * @version 2015-12-11
206
     */
207
    public function setWebVerificacion($web)
208
    {
209
        $this->web_verificacion = $web;
0 ignored issues
show
Documentation Bug introduced by
It seems like $web of type object<sasco\LibreDTE\Sii\PDF\Página> is incompatible with the declared type string of property $web_verificacion.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
210
    }
211
212
    /**
213
     * Método que indica si el documento será o no cedible
214
     * @param cedible =true se incorporará leyenda de destino
215
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
216
     * @version 2015-09-09
217
     */
218
    public function setCedible($cedible = true)
219
    {
220
        $this->cedible = $cedible;
221
    }
222
223
    /**
224
     * Método que asigna la posición del detalle del Item respecto al nombre
225
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
226
     * @version 2016-08-05
227
     */
228
    public function setPosicionDetalleItem($posicion)
229
    {
230
        $this->item_detalle_posicion = (int)$posicion;
231
    }
232
233
    /**
234
     * Método que asigna el tamaño de la fuente para el detalle
235
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
236
     * @version 2016-08-03
237
     */
238
    public function setFuenteDetalle($fuente)
239
    {
240
        $this->detalle_fuente = (int)$fuente;
241
    }
242
243
    /**
244
     * Método que asigna el ancho e las columnas del detalle desde un arreglo
245
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
246
     * @version 2016-08-03
247
     */
248
    public function setAnchoColumnasDetalle(array $anchos)
249
    {
250
        foreach ($anchos as $col => $ancho) {
251
            if (isset($this->detalle_cols[$col]) and $ancho) {
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...
252
                $this->detalle_cols[$col]['width'] = (int)$ancho;
253
            }
254
        }
255
    }
256
257
    /**
258
     * Método que agrega un documento tributario, ya sea en formato de una
259
     * página o papel contínuo según se haya indicado en el constructor
260
     * @param dte Arreglo con los datos del XML (tag Documento)
261
     * @param timbre String XML con el tag TED del DTE
262
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
263
     * @version 2015-11-28
264
     */
265
    public function agregar(array $dte, $timbre = null)
266
    {
267
        $this->dte = $dte['Encabezado']['IdDoc']['TipoDTE'];
268
        if ($this->papelContinuo) {
269
            $this->agregarContinuo($dte, $timbre, $this->papelContinuo);
270
        } else {
271
            $this->agregarNormal($dte, $timbre);
272
        }
273
    }
274
275
    /**
276
     * Método que agrega una página con el documento tributario
277
     * @param dte Arreglo con los datos del XML (tag Documento)
278
     * @param timbre String XML con el tag TED del DTE
279
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
280
     * @version 2017-06-15
281
     */
282
    private function agregarNormal(array $dte, $timbre)
283
    {
284
        // agregar página para la factura
285
        $this->AddPage();
286
        // agregar cabecera del documento
287
        $y[] = $this->agregarEmisor($dte['Encabezado']['Emisor']);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$y was never initialized. Although not strictly required by PHP, it is generally a good practice to add $y = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
288
        $y[] = $this->agregarFolio(
289
            $dte['Encabezado']['Emisor']['RUTEmisor'],
290
            $dte['Encabezado']['IdDoc']['TipoDTE'],
291
            $dte['Encabezado']['IdDoc']['Folio'],
292
            $dte['Encabezado']['Emisor']['CmnaOrigen']
293
        );
294
        // datos del documento
295
        $this->setY(max($y));
296
        $this->Ln();
297
        $y = [];
298
        $y[] = $this->agregarDatosEmision($dte['Encabezado']['IdDoc'], !empty($dte['Encabezado']['Emisor']['CdgVendedor'])?$dte['Encabezado']['Emisor']['CdgVendedor']:null);
299
        $y[] = $this->agregarReceptor($dte['Encabezado']);
300
        $this->setY(max($y));
301
        $this->agregarTraslado(
302
            !empty($dte['Encabezado']['IdDoc']['IndTraslado']) ? $dte['Encabezado']['IdDoc']['IndTraslado'] : null,
303
            !empty($dte['Encabezado']['Transporte']) ? $dte['Encabezado']['Transporte'] : null
304
        );
305
        if (!empty($dte['Referencia']))
306
            $this->agregarReferencia($dte['Referencia']);
307
        $this->agregarDetalle($dte['Detalle']);
308
        if (!empty($dte['DscRcgGlobal'])) {
309
            $this->agregarSubTotal($dte['Detalle']);
310
            $this->agregarDescuentosRecargos($dte['DscRcgGlobal']);
311
        }
312 View Code Duplication
        if (!empty($dte['Encabezado']['IdDoc']['MntPagos']))
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...
313
            $this->agregarPagos($dte['Encabezado']['IdDoc']['MntPagos']);
314
        $this->agregarTotales($dte['Encabezado']['Totales']);
315
        // agregar observaciones
316
        $this->agregarObservacion($dte['Encabezado']['IdDoc']);
317
        // agregar timbre
318
        $this->agregarTimbre($timbre);
319
        // agregar acuse de recibo y leyenda cedible
320
        if ($this->cedible and !in_array($dte['Encabezado']['IdDoc']['TipoDTE'], $this->sinAcuseRecibo)) {
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...
321
            $this->agregarAcuseRecibo();
322
            $this->agregarLeyendaDestino($dte['Encabezado']['IdDoc']['TipoDTE']);
323
        }
324
    }
325
326
    /**
327
     * Método que agrega una página con el documento tributario en papel
328
     * contínuo
329
     * @param dte Arreglo con los datos del XML (tag Documento)
330
     * @param timbre String XML con el tag TED del DTE
331
     * @param width Ancho del papel contínuo en mm
332
     * @author Pablo Reyes (https://github.com/pabloxp)
333
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
334
     * @version 2017-06-15
335
     */
336
    private function agregarContinuo(array $dte, $timbre, $width)
337
    {
338
        $this->logo = null;
339
        $x_start = 1;
340
        $y_start = 1;
341
        $offset = 14;
342
        // determinar alto de la página y agregarla
343
        $height = 145;
344
        $n_detalle = count($dte['Detalle']);
345
        if ($n_detalle>1) $height += $n_detalle*20;
346
        if ($this->cedible) $height += 50;
347
        $this->AddPage('P', [$height, $width]);
348
        // agregar cabecera del documento
349
        $y = $this->agregarFolio(
350
            $dte['Encabezado']['Emisor']['RUTEmisor'],
351
            $dte['Encabezado']['IdDoc']['TipoDTE'],
352
            $dte['Encabezado']['IdDoc']['Folio'],
353
            $dte['Encabezado']['Emisor']['CmnaOrigen'],
354
            $x_start, $y_start, $width-($x_start*4), 10,
355
            [0,0,0]
356
        );
357
        $y = $this->agregarEmisor($dte['Encabezado']['Emisor'], $x_start, $y+2, 40, 8, 9, [0,0,0]);
358
        // datos del documento
359
        $this->SetY($y);
360
        $this->Ln();
361
        $this->setFont('', '', 8);
362
        $this->agregarDatosEmision($dte['Encabezado']['IdDoc'], !empty($dte['Encabezado']['Emisor']['CdgVendedor'])?$dte['Encabezado']['Emisor']['CdgVendedor']:null, $x_start, $offset, false);
363
        $this->agregarReceptor($dte['Encabezado'], $x_start, $offset);
364
        $this->agregarTraslado(
365
            !empty($dte['Encabezado']['IdDoc']['IndTraslado']) ? $dte['Encabezado']['IdDoc']['IndTraslado'] : null,
366
            !empty($dte['Encabezado']['Transporte']) ? $dte['Encabezado']['Transporte'] : null,
367
            $x_start, $offset
368
        );
369
        if (!empty($dte['Referencia'])) {
370
            $this->agregarReferencia($dte['Referencia'], $x_start, $offset);
371
        }
372
        $this->Ln();
373
        $this->agregarDetalleContinuo($dte['Detalle']);
374
        if (!empty($dte['DscRcgGlobal'])) {
375
            $this->Ln();
376
            $this->Ln();
377
            $this->agregarSubTotal($dte['Detalle'], $x_start);
378
            $this->agregarDescuentosRecargos($dte['DscRcgGlobal'], $x_start);
379
        }
380 View Code Duplication
        if (!empty($dte['Encabezado']['IdDoc']['MntPagos'])) {
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...
381
            $this->Ln();
382
            $this->Ln();
383
            $this->agregarPagos($dte['Encabezado']['IdDoc']['MntPagos'], $x_start);
384
        }
385
        $this->agregarTotales($dte['Encabezado']['Totales'], $this->y+6, 23, 17);
386
        // agregar acuse de recibo y leyenda cedible
387
        if ($this->cedible and !in_array($dte['Encabezado']['IdDoc']['TipoDTE'], $this->sinAcuseRecibo)) {
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...
388
            $this->agregarAcuseReciboContinuo(3, $this->y+6, 68, 34);
389
            $this->agregarLeyendaDestino($dte['Encabezado']['IdDoc']['TipoDTE'], $this->y+6, 8);
390
        }
391
        // agregar timbre
392
        $y = $this->agregarObservacion($dte['Encabezado']['IdDoc'], $x_start, $this->y+6);
393
        $this->agregarTimbre($timbre, 0, $x_start, $y+6, 70, 6);
394
    }
395
396
    /**
397
     * Método que agrega los datos de la empresa
398
     * Orden de los datos:
399
     *  - Razón social del emisor
400
     *  - Giro del emisor (sin abreviar)
401
     *  - Dirección casa central del emisor
402
     *  - Dirección sucursales
403
     * @param emisor Arreglo con los datos del emisor (tag Emisor del XML)
404
     * @param x Posición horizontal de inicio en el PDF
405
     * @param y Posición vertical de inicio en el PDF
406
     * @param w Ancho de la información del emisor
407
     * @param w_img Ancho máximo de la imagen
408
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
409
     * @version 2016-12-02
410
     */
411
    private function agregarEmisor(array $emisor, $x = 10, $y = 15, $w = 75, $w_img = 30, $font_size = null, array $color = null)
412
    {
413
        // logo del documento
414
        if (isset($this->logo)) {
415
            $this->Image(
416
                $this->logo['uri'],
417
                $x,
418
                $y,
419
                !$this->logo['posicion']?$w_img:null, $this->logo['posicion']?($w_img/2):null,
420
                'PNG',
421
                (isset($emisor['url'])?$emisor['url']:''),
422
                'T'
423
            );
424
            if ($this->logo['posicion']) {
425
                $this->SetY($this->y + ($w_img/2));
426
                $w += 40;
427
            } else {
428
                $x = $this->x+3;
429
            }
430
        } else {
431
            $this->y = $y-2;
432
            $w += 40;
433
        }
434
        // agregar datos del emisor
435
        $this->setFont('', 'B', $font_size ? $font_size : 14);
436
        $this->SetTextColorArray($color===null?[32, 92, 144]:$color);
437
        $this->MultiTexto(!empty($emisor['RznSoc']) ? $emisor['RznSoc'] : $emisor['RznSocEmisor'], $x, $this->y+2, 'L', $w);
438
        $this->setFont('', 'B', $font_size ? $font_size : 9);
439
        $this->SetTextColorArray([0,0,0]);
440
        $this->MultiTexto(!empty($emisor['GiroEmis']) ? $emisor['GiroEmis'] : $emisor['GiroEmisor'], $x, $this->y, 'L', $w);
441
        $ciudad = !empty($emisor['CiudadOrigen']) ? $emisor['CiudadOrigen'] : \sasco\LibreDTE\Chile::getCiudad($emisor['CmnaOrigen']);
442
        $this->MultiTexto($emisor['DirOrigen'].', '.$emisor['CmnaOrigen'].($ciudad?(', '.$ciudad):''), $x, $this->y, 'L', $w);
443
        if (!empty($emisor['Sucursal'])) {
444
            $this->MultiTexto('Sucursal: '.$emisor['Sucursal'], $x, $this->y, 'L', $w);
445
        }
446
        $contacto = [];
447
        if (!empty($emisor['Telefono'])) {
448
            if (!is_array($emisor['Telefono']))
449
                $emisor['Telefono'] = [$emisor['Telefono']];
450
            foreach ($emisor['Telefono'] as $t)
451
                $contacto[] = $t;
452
        }
453
        if (!empty($emisor['CorreoEmisor'])) {
454
            $contacto[] = $emisor['CorreoEmisor'];
455
        }
456
        if ($contacto) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $contacto 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...
457
            $this->MultiTexto(implode(' / ', $contacto), $x, $this->y, 'L', $w);
458
        }
459
        return $this->y;
460
    }
461
462
    /**
463
     * Método que agrega el recuadro con el folio
464
     * Recuadro:
465
     *  - Tamaño mínimo 1.5x5.5 cms
466
     *  - En lado derecho (negro o rojo)
467
     *  - Enmarcado por una línea de entre 0.5 y 1 mm de espesor
468
     *  - Tamaño máximo 4x8 cms
469
     *  - Letras tamaño 10 o superior en mayúsculas y negritas
470
     *  - Datos del recuadro: RUT emisor, nombre de documento en 2 líneas,
471
     *    folio.
472
     *  - Bajo el recuadro indicar la Dirección regional o Unidad del SII a la
473
     *    que pertenece el emisor
474
     * @param rut RUT del emisor
475
     * @param tipo Código o glosa del tipo de documento
476
     * @param sucursal_sii Código o glosa de la sucursal del SII del Emisor
477
     * @param x Posición horizontal de inicio en el PDF
478
     * @param y Posición vertical de inicio en el PDF
479
     * @param w Ancho de la información del emisor
480
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
481
     * @version 2016-12-02
482
     */
483
    private function agregarFolio($rut, $tipo, $folio, $sucursal_sii = null, $x = 130, $y = 15, $w = 70, $font_size = null, array $color = null)
484
    {
485
        if ($color===null) {
486
            $color = $tipo ? ($tipo==52 ? [0,172,140] : [255,0,0]) : [0,0,0];
487
        }
488
        $this->SetTextColorArray($color);
489
        // colocar rut emisor, glosa documento y folio
490
        list($rut, $dv) = explode('-', $rut);
491
        $this->setFont ('', 'B', $font_size ? $font_size : 15);
492
        $this->MultiTexto('R.U.T.: '.$this->num($rut).'-'.$dv, $x, $y+4, 'C', $w);
493
        $this->setFont('', 'B', $font_size ? $font_size : 12);
494
        $this->MultiTexto($this->getTipo($tipo), $x, null, 'C', $w);
495
        $this->setFont('', 'B', $font_size ? $font_size : 15);
496
        $this->MultiTexto('N° '.$folio, $x, null, 'C', $w);
497
        // dibujar rectángulo rojo
498
        $this->Rect($x, $y, $w, round($this->getY()-$y+3), 'D', ['all' => ['width' => 0.5, 'color' => $color]]);
499
        // colocar unidad del SII
500
        $this->setFont('', 'B', $font_size ? $font_size : 10);
501
        if ($tipo) {
502
            $this->Texto('S.I.I. - '.\sasco\LibreDTE\Sii::getDireccionRegional($sucursal_sii), $x, $this->getY()+4, 'C', $w);
0 ignored issues
show
Bug introduced by
It seems like $sucursal_sii defined by parameter $sucursal_sii on line 483 can also be of type null; however, sasco\LibreDTE\Sii::getDireccionRegional() does only seem to accept object<sasco\LibreDTE\de>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
503
        }
504
        $this->SetTextColorArray([0,0,0]);
505
        $this->Ln();
506
        return $this->y;
507
    }
508
509
    /**
510
     * Método que entrega la glosa del tipo de documento
511
     * @param tipo Código del tipo de documento
512
     * @return Glosa del tipo de documento
513
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
514
     * @version 2016-11-18
515
     */
516
    private function getTipo($tipo)
517
    {
518
        if (!is_numeric($tipo) and !isset($this->tipos[$tipo]))
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...
519
            return $tipo;
520
        return isset($this->tipos[$tipo]) ? strtoupper($this->tipos[$tipo]) : 'Documento '.$tipo;
521
    }
522
523
    /**
524
     * Método que agrega los datos de la emisión del DTE que no son los dato del
525
     * receptor
526
     * @param IdDoc Información general del documento
527
     * @param x Posición horizontal de inicio en el PDF
528
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
529
     * @version 2017-06-15
530
     */
531
    private function agregarDatosEmision($IdDoc, $CdgVendedor, $x = 10, $offset = 22, $mostrar_dia = true)
532
    {
533
        // si es hoja carta
534
        if ($x==10) {
535
            $y = $this->GetY();
536
            // fecha emisión
537
            $this->setFont('', 'B', null);
538
            $this->MultiTexto($this->date($IdDoc['FchEmis'], $mostrar_dia), $x, null, 'R');
539
            $this->setFont('', '', null);
540
            // período facturación
541
            if (!empty($IdDoc['PeriodoDesde']) and !empty($IdDoc['PeriodoHasta'])) {
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...
542
                $this->MultiTexto('Período del '.date('d/m/y', strtotime($IdDoc['PeriodoDesde'])).' al '.date('d/m/y', strtotime($IdDoc['PeriodoHasta'])), $x, null, 'R');
543
            }
544
            // pago anticicado
545 View Code Duplication
            if (!empty($IdDoc['FchCancel'])) {
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...
546
                $this->MultiTexto('Pagado el '.$this->date($IdDoc['FchCancel'], false), $x, null, 'R');
547
            }
548
            // fecha vencimiento
549 View Code Duplication
            if (!empty($IdDoc['FchVenc'])) {
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...
550
                $this->MultiTexto('Vence el '.$this->date($IdDoc['FchVenc'], false), $x, null, 'R');
551
            }
552
            // forma de pago nacional
553 View Code Duplication
            if (!empty($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...
554
                $this->MultiTexto('Venta: '.strtolower($this->formas_pago[$IdDoc['FmaPago']]), $x, null, 'R');
555
            }
556
            // forma de pago exportación
557 View Code Duplication
            if (!empty($IdDoc['FmaPagExp'])) {
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...
558
                $this->MultiTexto('Venta: '.strtolower($this->formas_pago_exportacion[$IdDoc['FmaPagExp']]), $x, null, 'R');
559
            }
560
            // vendedor
561
            if (!empty($CdgVendedor)) {
562
                $this->MultiTexto('Vendedor: '.$CdgVendedor, $x, null, 'R');
563
            }
564
            $y_end = $this->GetY();
565
            $this->SetY($y);
566
        }
567
        // papel contínuo
568
        else {
569
            // fecha de emisión
570
            $this->setFont('', 'B', null);
571
            $this->Texto('Emisión', $x);
572
            $this->Texto(':', $x+$offset);
573
            $this->setFont('', '', null);
574
            $this->MultiTexto($this->date($IdDoc['FchEmis'], $mostrar_dia), $x+$offset+2);
575
            // forma de pago nacional
576
            if (!empty($IdDoc['FmaPago'])) {
577
                $this->setFont('', 'B', null);
578
                $this->Texto('Venta', $x);
579
                $this->Texto(':', $x+$offset);
580
                $this->setFont('', '', null);
581
                $this->MultiTexto($this->formas_pago[$IdDoc['FmaPago']], $x+$offset+2);
582
            }
583
            // forma de pago exportación
584
            if (!empty($IdDoc['FmaPagExp'])) {
585
                $this->setFont('', 'B', null);
586
                $this->Texto('Venta', $x);
587
                $this->Texto(':', $x+$offset);
588
                $this->setFont('', '', null);
589
                $this->MultiTexto($this->formas_pago_exportacion[$IdDoc['FmaPagExp']], $x+$offset+2);
590
            }
591
            // pago anticicado
592
            if (!empty($IdDoc['FchCancel'])) {
593
                $this->setFont('', 'B', null);
594
                $this->Texto('Pagado el', $x);
595
                $this->Texto(':', $x+$offset);
596
                $this->setFont('', '', null);
597
                $this->MultiTexto($this->date($IdDoc['FchCancel'], $mostrar_dia), $x+$offset+2);
598
            }
599
            // fecha vencimiento
600
            if (!empty($IdDoc['FchVenc'])) {
601
                $this->setFont('', 'B', null);
602
                $this->Texto('Vence el', $x);
603
                $this->Texto(':', $x+$offset);
604
                $this->setFont('', '', null);
605
                $this->MultiTexto($this->date($IdDoc['FchVenc'], $mostrar_dia), $x+$offset+2);
606
            }
607
            $y_end = $this->GetY();
608
        }
609
        return $y_end;
610
    }
611
612
    /**
613
     * Método que agrega los datos del receptor
614
     * @param receptor Arreglo con los datos del receptor (tag Receptor del XML)
615
     * @param x Posición horizontal de inicio en el PDF
616
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
617
     * @version 2017-06-15
618
     */
619
    private function agregarReceptor(array $Encabezado, $x = 10, $offset = 22)
620
    {
621
        $receptor = $Encabezado['Receptor'];
622 View Code Duplication
        if (!empty($receptor['RUTRecep']) and $receptor['RUTRecep']!='66666666-6') {
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...
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...
623
            list($rut, $dv) = explode('-', $receptor['RUTRecep']);
624
            $this->setFont('', 'B', null);
625
            $this->Texto('R.U.T.', $x);
626
            $this->Texto(':', $x+$offset);
627
            $this->setFont('', '', null);
628
            $this->MultiTexto($this->num($rut).'-'.$dv, $x+$offset+2);
629
        }
630 View Code Duplication
        if (!empty($receptor['RznSocRecep'])) {
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...
631
            $this->setFont('', 'B', null);
632
            $this->Texto('Señor(es)', $x);
633
            $this->Texto(':', $x+$offset);
634
            $this->setFont('', '', null);
635
            $this->MultiTexto($receptor['RznSocRecep'], $x+$offset+2, null, '', $x==10?105:0);
636
        }
637 View Code Duplication
        if (!empty($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...
638
            $this->setFont('', 'B', null);
639
            $this->Texto('Giro', $x);
640
            $this->Texto(':', $x+$offset);
641
            $this->setFont('', '', null);
642
            $this->MultiTexto($receptor['GiroRecep'], $x+$offset+2);
643
        }
644
        if (!empty($receptor['DirRecep'])) {
645
            $this->setFont('', 'B', null);
646
            $this->Texto('Dirección', $x);
647
            $this->Texto(':', $x+$offset);
648
            $this->setFont('', '', null);
649
            $ciudad = !empty($receptor['CiudadRecep']) ? $receptor['CiudadRecep'] : (
650
                !empty($receptor['CmnaRecep']) ? \sasco\LibreDTE\Chile::getCiudad($receptor['CmnaRecep']) : ''
651
            );
652
            $this->MultiTexto($receptor['DirRecep'].(!empty($receptor['CmnaRecep'])?(', '.$receptor['CmnaRecep']):'').($ciudad?(', '.$ciudad):''), $x+$offset+2);
653
        }
654
        if (!empty($receptor['Extranjero']['Nacionalidad'])) {
655
            $this->setFont('', 'B', null);
656
            $this->Texto('Nacionalidad', $x);
657
            $this->Texto(':', $x+$offset);
658
            $this->setFont('', '', null);
659
            $this->MultiTexto(\sasco\LibreDTE\Sii\Aduana::getNacionalidad($receptor['Extranjero']['Nacionalidad']), $x+$offset+2);
660
        }
661
        $contacto = [];
662
        if (!empty($receptor['Contacto']))
663
            $contacto[] = $receptor['Contacto'];
664
        if (!empty($receptor['CorreoRecep']))
665
            $contacto[] = $receptor['CorreoRecep'];
666 View Code Duplication
        if (!empty($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...
667
            $this->setFont('', 'B', null);
668
            $this->Texto('Contacto', $x);
669
            $this->Texto(':', $x+$offset);
670
            $this->setFont('', '', null);
671
            $this->MultiTexto(implode(' / ', $contacto), $x+$offset+2);
672
        }
673 View Code Duplication
        if (!empty($Encabezado['RUTSolicita'])) {
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...
674
            list($rut, $dv) = explode('-', $Encabezado['RUTSolicita']);
675
            $this->setFont('', 'B', null);
676
            $this->Texto('RUT solicita', $x);
677
            $this->Texto(':', $x+$offset);
678
            $this->setFont('', '', null);
679
            $this->MultiTexto($this->num($rut).'-'.$dv, $x+$offset+2);
680
        }
681 View Code Duplication
        if (!empty($receptor['CdgIntRecep'])) {
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...
682
            $this->setFont('', 'B', null);
683
            $this->Texto('Cód. recep.', $x);
684
            $this->Texto(':', $x+$offset);
685
            $this->setFont('', '', null);
686
            $this->MultiTexto($receptor['CdgIntRecep'], $x+$offset+2, null, '', $x==10?105:0);
687
        }
688
        return $this->GetY();
689
    }
690
691
    /**
692
     * Método que agrega los datos del traslado
693
     * @param IndTraslado
694
     * @param Transporte
695
     * @param x Posición horizontal de inicio en el PDF
696
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
697
     * @version 2016-08-03
698
     */
699
    private function agregarTraslado($IndTraslado, array $Transporte = null, $x = 10, $offset = 22)
700
    {
701
        // agregar tipo de traslado
702 View Code Duplication
        if ($IndTraslado) {
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...
703
            $this->setFont('', 'B', null);
704
            $this->Texto('Tipo oper.', $x);
705
            $this->Texto(':', $x+$offset);
706
            $this->setFont('', '', null);
707
            $this->MultiTexto($this->traslados[$IndTraslado], $x+$offset+2);
708
        }
709
        // agregar información de transporte
710
        if ($Transporte) {
711
            $transporte = '';
712
            if (!empty($Transporte['DirDest']) and !empty($Transporte['CmnaDest'])) {
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...
713
                $transporte .= 'a '.$Transporte['DirDest'].', '.$Transporte['CmnaDest'];
714
            }
715
            if (!empty($Transporte['RUTTrans']))
716
                $transporte .= ' por '.$Transporte['RUTTrans'];
717
            if (!empty($Transporte['Patente']))
718
                $transporte .= ' en vehículo '.$Transporte['Patente'];
719
            if (isset($Transporte['Chofer']) and is_array($Transporte['Chofer'])) {
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...
720 View Code Duplication
                if (!empty($Transporte['Chofer']['NombreChofer']))
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...
721
                    $transporte .= ' con chofer '.$Transporte['Chofer']['NombreChofer'];
722 View Code Duplication
                if (!empty($Transporte['Chofer']['RUTChofer']))
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...
723
                    $transporte .= ' ('.$Transporte['Chofer']['RUTChofer'].')';
724
            }
725 View Code Duplication
            if ($transporte) {
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...
726
                $this->setFont('', 'B', null);
727
                $this->Texto('Traslado', $x);
728
                $this->Texto(':', $x+$offset);
729
                $this->setFont('', '', null);
730
                $this->MultiTexto(ucfirst(trim($transporte)), $x+$offset+2);
731
            }
732
        }
733
        // agregar información de aduana
734
        if (!empty($Transporte['Aduana']) and is_array($Transporte['Aduana'])) {
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...
735
            $col = 0;
736
            foreach ($Transporte['Aduana'] as $tag => $codigo) {
737
                if ($codigo===false)
738
                    continue;
739
                $glosa = \sasco\LibreDTE\Sii\Aduana::getGlosa($tag);
740
                $valor = \sasco\LibreDTE\Sii\Aduana::getValor($tag, $codigo);
741
                if ($glosa!==false and $valor!==false) {
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...
742
                    if ($tag=='TipoBultos' and $col) {
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...
743
                        $col = abs($col-110);
744
                        $this->Ln();
745
                    }
746
                    $this->setFont('', 'B', null);
747
                    $this->Texto($glosa, $x+$col);
748
                    $this->Texto(':', $x+$offset+$col);
749
                    $this->setFont('', '', null);
750
                    $this->Texto($valor, $x+$offset+2+$col);
751
                    if ($tag=='TipoBultos')
752
                        $col = abs($col-110);
753
                    if ($col)
754
                        $this->Ln();
755
                    $col = abs($col-110);
756
                }
757
            }
758
            if ($col)
759
                $this->Ln();
760
        }
761
    }
762
763
    /**
764
     * Método que agrega las referencias del documento
765
     * @param referencias Arreglo con las referencias del documento (tag Referencia del XML)
766
     * @param x Posición horizontal de inicio en el PDF
767
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
768
     * @version 2016-08-03
769
     */
770
    private function agregarReferencia($referencias, $x = 10, $offset = 22)
771
    {
772
        if (!isset($referencias[0]))
773
            $referencias = [$referencias];
774
        foreach($referencias as $r) {
775
            $texto = $r['NroLinRef'].' - '.$this->getTipo($r['TpoDocRef']).' N° '.$r['FolioRef'].' del '.$r['FchRef'];
776
            if (isset($r['RazonRef']) and $r['RazonRef']!==false)
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...
777
                $texto = $texto.': '.$r['RazonRef'];
778
            $this->setFont('', 'B', null);
779
            $this->Texto('Referencia', $x);
780
            $this->Texto(':', $x+$offset);
781
            $this->setFont('', '', null);
782
            $this->MultiTexto($texto, $x+$offset+2);
783
        }
784
    }
785
786
    /**
787
     * Método que agrega el detalle del documento
788
     * @param detalle Arreglo con el detalle del documento (tag Detalle del XML)
789
     * @param x Posición horizontal de inicio en el PDF
790
     * @param y Posición vertical de inicio en el PDF
791
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
792
     * @version 2016-08-05
793
     */
794
    private function agregarDetalle($detalle, $x = 10)
795
    {
796
        if (!isset($detalle[0]))
797
            $detalle = [$detalle];
798
        $this->setFont('', '', $this->detalle_fuente);
799
        // titulos
800
        $titulos = [];
801
        $titulos_keys = array_keys($this->detalle_cols);
802
        foreach ($this->detalle_cols as $key => $info) {
803
            $titulos[$key] = $info['title'];
804
        }
805
        // normalizar cada detalle
806
        $dte_exento = in_array($this->dte, [34, 110, 111, 112]);
807
        foreach ($detalle as &$item) {
808
            // quitar columnas
809
            foreach ($item as $col => $valor) {
810
                if ($col=='DscItem' and !empty($item['DscItem'])) {
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...
811
                    $item['NmbItem'] .= !$this->item_detalle_posicion ? '<br/>' : ': ';
812
                    $item['NmbItem'] .= '<span style="font-size:0.7em">'.$item['DscItem'].'</span>';
813
                }
814
                if (!in_array($col, $titulos_keys) or ($dte_exento and $col=='IndExe'))
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...
815
                    unset($item[$col]);
816
            }
817
            // ajustes a IndExe
818
            if (isset($item['IndExe'])) {
819
                if ($item['IndExe']==1)
820
                    $item['IndExe'] = 'EX';
821
                else if ($item['IndExe']==2)
822
                    $item['IndExe'] = 'NF';
823
            }
824
            // agregar todas las columnas que se podrían imprimir en la tabla
825
            $item_default = [];
826
            foreach ($this->detalle_cols as $key => $info)
827
                $item_default[$key] = false;
828
            $item = array_merge($item_default, $item);
829
            // si hay código de item se extrae su valor
830
            if ($item['CdgItem'])
831
                $item['CdgItem'] = $item['CdgItem']['VlrCodigo'];
832
            // dar formato a números
833
            foreach (['QtyItem', 'PrcItem', 'DescuentoMonto', 'RecargoMonto', 'MontoItem'] as $col) {
834
                if ($item[$col])
835
                    $item[$col] = $this->num($item[$col]);
836
            }
837
        }
838
        // opciones
839
        $options = ['align'=>[]];
840
        $i = 0;
841
        foreach ($this->detalle_cols as $info) {
842
            if (isset($info['width']))
843
                $options['width'][$i] = $info['width'];
844
            $options['align'][$i] = $info['align'];
845
            $i++;
846
        }
847
        // agregar tabla de detalle
848
        $this->Ln();
849
        $this->SetX($x);
850
        $this->addTableWithoutEmptyCols($titulos, $detalle, $options);
851
    }
852
853
    /**
854
     * Método que agrega el detalle del documento
855
     * @param detalle Arreglo con el detalle del documento (tag Detalle del XML)
856
     * @param x Posición horizontal de inicio en el PDF
857
     * @param y Posición vertical de inicio en el PDF
858
     * @author Pablo Reyes (https://github.com/pabloxp)
859
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
860
     * @version 2016-12-13
861
     */
862
    private function agregarDetalleContinuo($detalle, $x = 3)
863
    {
864
        $this->SetY($this->getY()+1);
865
        $p1x = $x;
866
        $p1y = $this->y;
867
        $p2x = $this->getPageWidth() - 2;
868
        $p2y = $p1y;  // Use same y for a straight line
869
        $style = array('width' => 0.2,'color' => array(0, 0, 0));
870
        $this->Line($p1x, $p1y, $p2x, $p2y, $style);
871
        $this->Texto($this->detalle_cols['NmbItem']['title'], $x+1, $this->y, ucfirst($this->detalle_cols['NmbItem']['align'][0]), $this->detalle_cols['NmbItem']['width']);
872
        $this->Texto($this->detalle_cols['PrcItem']['title'], $x+15, $this->y, ucfirst($this->detalle_cols['PrcItem']['align'][0]), $this->detalle_cols['PrcItem']['width']);
873
        $this->Texto($this->detalle_cols['QtyItem']['title'], $x+35, $this->y, ucfirst($this->detalle_cols['QtyItem']['align'][0]), $this->detalle_cols['QtyItem']['width']);
874
        $this->Texto($this->detalle_cols['MontoItem']['title'], $x+45, $this->y, ucfirst($this->detalle_cols['MontoItem']['align'][0]), $this->detalle_cols['MontoItem']['width']);
875
        $this->Line($p1x, $p1y+4, $p2x, $p2y+4, $style);
876
        if (!isset($detalle[0]))
877
            $detalle = [$detalle];
878
        $this->SetY($this->getY()+2);
879
        foreach($detalle as  &$d) {
880
            $this->MultiTexto($d['NmbItem'], $x+1, $this->y+4, ucfirst($this->detalle_cols['NmbItem']['align'][0]), $this->detalle_cols['NmbItem']['width']);
881
            $this->Texto(number_format($d['PrcItem'],0,',','.'), $x+15, $this->y, ucfirst($this->detalle_cols['PrcItem']['align'][0]), $this->detalle_cols['PrcItem']['width']);
882
            $this->Texto($this->num($d['QtyItem']), $x+35, $this->y, ucfirst($this->detalle_cols['QtyItem']['align'][0]), $this->detalle_cols['QtyItem']['width']);
883
            $this->Texto($this->num($d['MontoItem']), $x+45, $this->y, ucfirst($this->detalle_cols['MontoItem']['align'][0]), $this->detalle_cols['MontoItem']['width']);
884
        }
885
        $this->Line($p1x, $this->y+4, $p2x, $this->y+4, $style);
886
    }
887
888
    /**
889
     * Método que agrega el subtotal del DTE
890
     * @param detalle Arreglo con los detalles del documentos para poder
891
     * calcular subtotal
892
     * @param x Posición horizontal de inicio en el PDF
893
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
894
     * @version 2016-08-17
895
     */
896
    private function agregarSubTotal(array $detalle, $x = 10) {
897
        $subtotal = 0;
898
        if (!isset($detalle[0])) {
899
            $detalle = [$detalle];
900
        }
901
        foreach($detalle as  &$d) {
902
            if (!empty($d['MontoItem'])) {
903
                $subtotal += $d['MontoItem'];
904
            }
905
        }
906
        $this->Texto('Subtotal: $'.$this->num($subtotal).'.-', $x);
907
        $this->Ln();
908
    }
909
910
    /**
911
     * Método que agrega los descuentos y/o recargos globales del documento
912
     * @param descuentosRecargos Arreglo con los descuentos y/o recargos del documento (tag DscRcgGlobal del XML)
913
     * @param x Posición horizontal de inicio en el PDF
914
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
915
     * @version 2016-08-17
916
     */
917
    private function agregarDescuentosRecargos(array $descuentosRecargos, $x = 10)
918
    {
919
        if (!isset($descuentosRecargos[0]))
920
            $descuentosRecargos = [$descuentosRecargos];
921
        foreach($descuentosRecargos as $dr) {
922
            $tipo = $dr['TpoMov']=='D' ? 'Descuento' : 'Recargo';
923
            $valor = $dr['TpoValor']=='%' ? $dr['ValorDR'].'%' : '$'.$this->num($dr['ValorDR']).'.-';
924
            $this->Texto($tipo.' global: '.$valor.(!empty($dr['GlosaDR'])?(' ('.$dr['GlosaDR'].')'):''), $x);
925
            $this->Ln();
926
        }
927
    }
928
929
    /**
930
     * Método que agrega los pagos del documento
931
     * @param pagos Arreglo con los pagos del documento
932
     * @param x Posición horizontal de inicio en el PDF
933
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
934
     * @version 2016-07-24
935
     */
936
    private function agregarPagos(array $pagos, $x = 10)
937
    {
938
        if (!isset($pagos[0]))
939
            $pagos = [$pagos];
940
        $this->Texto('Pago(s) programado(s):', $x);
941
        $this->Ln();
942
        foreach($pagos as $p) {
943
            $this->Texto('  - '.$this->date($p['FchPago'], false).': $'.$this->num($p['MntPago']).'.-'.(!empty($p['GlosaPagos'])?(' ('.$p['GlosaPagos'].')'):''), $x);
944
            $this->Ln();
945
        }
946
    }
947
948
    /**
949
     * Método que agrega los totales del documento
950
     * @param totales Arreglo con los totales (tag Totales del XML)
951
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
952
     * @version 2017-04-17
953
     */
954
    private function agregarTotales(array $totales, $y = 190, $x = 145, $offset = 25)
955
    {
956
        // normalizar totales
957
        $totales = array_merge([
958
            'TpoMoneda' => false,
959
            'MntNeto' => false,
960
            'MntExe' => false,
961
            'TasaIVA' => false,
962
            'IVA' => false,
963
            'IVANoRet' => false,
964
            'CredEC' => false,
965
            'MntTotal' => false,
966
            'MontoNF' => false,
967
            'MontoPeriodo' => false,
968
            'SaldoAnterior' => false,
969
            'VlrPagar' => false,
970
        ], $totales);
971
        // glosas
972
        $glosas = [
973
            'TpoMoneda' => 'Moneda',
974
            'MntNeto' => 'Neto $',
975
            'MntExe' => 'Exento $',
976
            'IVA' => 'IVA ('.$totales['TasaIVA'].'%) $',
977
            'IVANoRet' => 'IVA no retenido $',
978
            'CredEC' => 'Desc. 65% IVA $',
979
            'MntTotal' => 'Total $',
980
            'MontoNF' => 'Monto no facturable $',
981
            'MontoPeriodo' => 'Monto período $',
982
            'SaldoAnterior' => 'Saldo anterior $',
983
            'VlrPagar' => 'Valor a pagar $',
984
        ];
985
        // agregar impuestos adicionales y retenciones
986
        if (!empty($totales['ImptoReten'])) {
987
            $ImptoReten = $totales['ImptoReten'];
988
            $MntTotal = $totales['MntTotal'];
989
            unset($totales['ImptoReten'], $totales['MntTotal']);
990
            if (!isset($ImptoReten[0])) {
991
                $ImptoReten = [$ImptoReten];
992
            }
993
            foreach($ImptoReten as $i) {
994
                $totales['ImptoReten_'.$i['TipoImp']] = $i['MontoImp'];
995
                if (!empty($i['TasaImp'])) {
996
                    $glosas['ImptoReten_'.$i['TipoImp']] = \sasco\LibreDTE\Sii\ImpuestosAdicionales::getGlosa($i['TipoImp']).' ('.$i['TasaImp'].'%) $';
997
                } else {
998
                    $glosas['ImptoReten_'.$i['TipoImp']] = \sasco\LibreDTE\Sii\ImpuestosAdicionales::getGlosa($i['TipoImp']).' $';
999
                }
1000
            }
1001
            $totales['MntTotal'] = $MntTotal;
1002
        }
1003
        // agregar cada uno de los totales
1004
        $this->setY($y);
1005
        $this->setFont('', 'B', null);
1006
        foreach ($totales as $key => $total) {
1007
            if ($total!==false and isset($glosas[$key])) {
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...
1008
                $y = $this->GetY();
1009
                if (!$this->cedible or $this->papelContinuo) {
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...
1010
                    $this->Texto($glosas[$key].' :', $x, null, 'R', 30);
1011
                    $this->Texto($this->num($total), $x+$offset, $y, 'R', 30);
1012
                    $this->Ln();
1013
                } else {
1014
                    $this->MultiTexto($glosas[$key].' :', $x, null, 'R', 30);
1015
                    $y_new = $this->GetY();
1016
                    $this->Texto($this->num($total), $x+$offset, $y, 'R', 30);
1017
                    $this->SetY($y_new);
1018
                }
1019
            }
1020
        }
1021
    }
1022
1023
    /**
1024
     * Método que coloca las diferentes observaciones que puede tener el documnto
1025
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1026
     * @version 2016-04-11
1027
     */
1028
    private function agregarObservacion($IdDoc, $x = 10, $y = 175)
1029
    {
1030
        $this->SetXY($x, $y);
1031
        if (!empty($IdDoc['TermPagoGlosa'])) {
1032
            $this->MultiTexto('Observación: '.$IdDoc['TermPagoGlosa']);
1033
        }
1034
        return $this->GetY();
1035
    }
1036
1037
    /**
1038
     * Método que agrega el timbre de la factura
1039
     *  - Se imprime en el tamaño mínimo: 2x5 cms
1040
     *  - En el lado de abajo con margen izquierdo mínimo de 2 cms
1041
     * @param timbre String con los datos del timbre
1042
     * @param x Posición horizontal de inicio en el PDF
1043
     * @param y Posición vertical de inicio en el PDF
1044
     * @param w Ancho del timbre
1045
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1046
     * @version 2016-12-02
1047
     */
1048
    private function agregarTimbre($timbre, $x_timbre = 20, $x = 20, $y = 190, $w = 70, $font_size = 8)
1049
    {
1050
        if ($timbre!==null) {
1051
            $style = [
1052
                'border' => false,
1053
                'padding' => 0,
1054
                'hpadding' => 0,
1055
                'vpadding' => 0,
1056
                'module_width' => 1, // width of a single module in points
1057
                'module_height' => 1, // height of a single module in points
1058
                'fgcolor' => [0,0,0],
1059
                'bgcolor' => false, // [255,255,255]
0 ignored issues
show
Unused Code Comprehensibility introduced by
88% 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...
1060
                'position' => $this->papelContinuo ? 'C' : 'S',
1061
            ];
1062
            $ecl = version_compare(phpversion(), '7.0.0', '<') ? -1 : $this->ecl;
1063
            $this->write2DBarcode($timbre, 'PDF417,,'.$ecl, $x_timbre, $y, $w, 0, $style, 'B');
1064
            $this->setFont('', 'B', $font_size);
1065
            $this->Texto('Timbre Electrónico SII', $x, null, 'C', $w);
1066
            $this->Ln();
1067
            $this->Texto('Resolución '.$this->resolucion['NroResol'].' de '.explode('-', $this->resolucion['FchResol'])[0], $x, null, 'C', $w);
1068
            $this->Ln();
1069
            $this->Texto('Verifique documento: '.$this->web_verificacion, $x, null, 'C', $w);
1070
        }
1071
    }
1072
1073
    /**
1074
     * Método que agrega el acuse de rebido
1075
     * @param x Posición horizontal de inicio en el PDF
1076
     * @param y Posición vertical de inicio en el PDF
1077
     * @param w Ancho del acuse de recibo
1078
     * @param h Alto del acuse de recibo
1079
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1080
     * @version 2015-09-08
1081
     */
1082
    private function agregarAcuseRecibo($x = 93, $y = 190, $w = 50, $h = 40)
1083
    {
1084
        $this->SetTextColorArray([0,0,0]);
1085
        $this->Rect($x, $y, $w, $h, 'D', ['all' => ['width' => 0.1, 'color' => [0, 0, 0]]]);
1086
        $this->setFont('', 'B', 10);
1087
        $this->Texto('Acuse de recibo', $x, $y+1, 'C', $w);
1088
        $this->setFont('', 'B', 8);
1089
        $this->Texto('Nombre', $x+2, $this->y+8);
1090
        $this->Texto('________________', $x+18);
1091
        $this->Texto('R.U.T.', $x+2, $this->y+6);
1092
        $this->Texto('________________', $x+18);
1093
        $this->Texto('Fecha', $x+2, $this->y+6);
1094
        $this->Texto('________________', $x+18);
1095
        $this->Texto('Recinto', $x+2, $this->y+6);
1096
        $this->Texto('________________', $x+18);
1097
        $this->Texto('Firma', $x+2, $this->y+8);
1098
        $this->Texto('________________', $x+18);
1099
        $this->setFont('', 'B', 7);
1100
        $this->MultiTexto('El acuse de recibo que se declara en este acto, de acuerdo a lo dispuesto en la letra b) del Art. 4°, y la letra c) del Art. 5° de la Ley 19.983, acredita que la entrega de mercaderías o servicio (s) prestado (s) ha (n) sido recibido (s).'."\n", $x, $this->y+6, 'J', $w);
1101
    }
1102
1103
    /**
1104
     * Método que agrega el acuse de rebido
1105
     * @param x Posición horizontal de inicio en el PDF
1106
     * @param y Posición vertical de inicio en el PDF
1107
     * @param w Ancho del acuse de recibo
1108
     * @param h Alto del acuse de recibo
1109
     * @author Pablo Reyes (https://github.com/pabloxp)
1110
     * @version 2015-11-17
1111
     */
1112
    private function agregarAcuseReciboContinuo($x = 3, $y = null, $w = 68, $h = 40)
1113
    {
1114
        $this->SetTextColorArray([0,0,0]);
1115
        $this->Rect($x, $y, $w, $h, 'D', ['all' => ['width' => 0.1, 'color' => [0, 0, 0]]]);
1116
        $style = array('width' => 0.2,'color' => array(0, 0, 0));
1117
        $this->Line($x, $y+22, $w+3, $y+22, $style);
1118
        //$this->setFont('', 'B', 10);
0 ignored issues
show
Unused Code Comprehensibility introduced by
77% 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...
1119
        //$this->Texto('Acuse de recibo', $x, $y+1, 'C', $w);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% 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...
1120
        $this->setFont('', 'B', 6);
1121
        $this->Texto('Nombre:', $x+2, $this->y+8);
1122
        $this->Texto('_____________________________________________', $x+12);
1123
        $this->Texto('R.U.T.:', $x+2, $this->y+6);
1124
        $this->Texto('________________', $x+12);
1125
        $this->Texto('Firma:', $x+32, $this->y+0.5);
1126
        $this->Texto('___________________', $x+42.5);
1127
        $this->Texto('Fecha:', $x+2, $this->y+6);
1128
        $this->Texto('________________', $x+12);
1129
        $this->Texto('Recinto:', $x+32, $this->y+0.5);
1130
        $this->Texto('___________________', $x+42.5);
1131
1132
        $this->setFont('', 'B', 5);
1133
        $this->MultiTexto('El acuse de recibo que se declara en este acto, de acuerdo a lo dispuesto en la letra b) del Art. 4°, y la letra c) del Art. 5° de la Ley 19.983, acredita que la entrega de mercaderías o servicio (s) prestado (s) ha (n) sido recibido (s).'."\n", $x+2, $this->y+8, 'J', $w-3);
1134
    }
1135
1136
    /**
1137
     * Método que agrega la leyenda de destino
1138
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1139
     * @version 2016-08-04
1140
     */
1141
    private function agregarLeyendaDestino($tipo, $y = 254, $font_size = 10)
1142
    {
1143
        $this->setFont('', 'B', $font_size);
1144
        $this->Texto('CEDIBLE'.($tipo==52?' CON SU FACTURA':''), null, $y, 'R');
1145
    }
1146
1147
    /**
1148
     * Método que formatea un número con separador de miles y decimales (si
1149
     * corresponden)
1150
     * @param n Número que se desea formatear
1151
     * @return Número formateado
1152
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1153
     * @version 2016-04-05
1154
     */
1155
    private function num($n)
1156
    {
1157
        if (!is_numeric($n))
1158
            return $n;
1159
        $broken_number = explode('.', (string)$n);
1160
        if (isset($broken_number[1]))
1161
            return number_format($broken_number[0], 0, ',', '.').','.$broken_number[1];
0 ignored issues
show
Bug Best Practice introduced by
The return type of return number_format($br...,' . $broken_number[1]; (string) is incompatible with the return type documented by sasco\LibreDTE\Sii\PDF\Dte::num of type sasco\LibreDTE\Sii\PDF\Número.

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...
1162
        return number_format($broken_number[0], 0, ',', '.');
0 ignored issues
show
Bug Best Practice introduced by
The return type of return number_format($br...umber[0], 0, ',', '.'); (string) is incompatible with the return type documented by sasco\LibreDTE\Sii\PDF\Dte::num of type sasco\LibreDTE\Sii\PDF\Número.

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...
1163
    }
1164
1165
    /**
1166
     * Método que formatea una fecha en formato YYYY-MM-DD a un string
1167
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1168
     * @version 2016-04-28
1169
     */
1170
    public function date($date, $mostrar_dia = true)
1171
    {
1172
        $dias = ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'];
1173
        $meses = ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'];
1174
        $unixtime = strtotime($date);
1175
        $fecha = date(($mostrar_dia?'\D\I\A ':'').'j \d\e \M\E\S \d\e\l Y', $unixtime);
1176
        $dia = $dias[date('w', $unixtime)];
1177
        $mes = $meses[date('n', $unixtime)-1];
1178
        return str_replace(array('DIA', 'MES'), array($dia, $mes), $fecha);
1179
    }
1180
1181
}
1182