Completed
Push — master ( 62ce4c...4dae1d )
by Esteban De La Fuente
02:14
created

Dte::agregarEmisor()   D

Complexity

Conditions 21
Paths 288

Size

Total Lines 51
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 51
rs 4.187
c 0
b 0
f 0
cc 21
eloc 40
nc 288
nop 7

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * LibreDTE
5
 * Copyright (C) SASCO SpA (https://sasco.cl)
6
 *
7
 * Este programa es software libre: usted puede redistribuirlo y/o
8
 * modificarlo bajo los términos de la Licencia Pública General Affero de GNU
9
 * publicada por la Fundación para el Software Libre, ya sea la versión
10
 * 3 de la Licencia, o (a su elección) cualquier versión posterior de la
11
 * misma.
12
 *
13
 * Este programa se distribuye con la esperanza de que sea útil, pero
14
 * SIN GARANTÍA ALGUNA; ni siquiera la garantía implícita
15
 * MERCANTIL o de APTITUD PARA UN PROPÓSITO DETERMINADO.
16
 * Consulte los detalles de la Licencia Pública General Affero de GNU para
17
 * obtener una información más detallada.
18
 *
19
 * Debería haber recibido una copia de la Licencia Pública General Affero de GNU
20
 * junto a este programa.
21
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
22
 */
23
24
namespace sasco\LibreDTE\Sii\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 2018-04-13
31
 */
32
class Dte extends \sasco\LibreDTE\PDF
33
{
34
35
    protected $dte; ///< Tipo de DTE que se está generando
36
    protected $logo; ///< Datos del logo que se ubicará en el PDF (ruta, datos y/o posición)
37
    protected $resolucion; ///< Arreglo con los datos de la resolución (índices: NroResol y FchResol)
38
    protected $cedible = false; ///< Por defecto DTEs no son cedibles
39
    protected $papelContinuo = false; ///< Indica si se usa papel continuo o no
40
    protected $sinAcuseRecibo = [39, 41, 56, 61, 110, 111, 112]; ///< Boletas, notas de crédito y notas de débito no tienen acuse de recibo
41
    protected $web_verificacion = 'www.sii.cl'; ///< Página web para verificar el documento
42
    protected $ecl = 5; ///< error correction level para PHP >= 7.0.0
43
    protected $papel_continuo_alto = 5000; ///< Alto exageradamente grande para autocálculo de alto en papel continuo
44
    protected $timbre_pie = true; ///< Indica si el timbre va al pie o no (va pegado al detalle)
45
46
    private $tipos = [
47
        // códigos oficiales SII
48
        29 => 'FACTURA DE INICIO',
49
        30 => 'FACTURA',
50
        32 => 'FACTURA DE VENTA BIENES Y SERVICIOS NO AFECTOS O EXENTOS DE IVA',
51
        33 => 'FACTURA ELECTRÓNICA',
52
        34 => 'FACTURA NO AFECTA O EXENTA ELECTRÓNICA',
53
        35 => 'BOLETA',
54
        38 => 'BOLETA EXENTA',
55
        39 => 'BOLETA ELECTRÓNICA',
56
        40 => 'LIQUIDACION FACTURA',
57
        41 => 'BOLETA NO AFECTA O EXENTA ELECTRÓNICA',
58
        43 => 'LIQUIDACIÓN FACTURA ELECTRÓNICA',
59
        45 => 'FACTURA DE COMPRA',
60
        46 => 'FACTURA DE COMPRA ELECTRÓNICA',
61
        48 => 'COMPROBANTE DE PAGO ELECTRÓNICO',
62
        50 => 'GUÍA DE DESPACHO',
63
        52 => 'GUÍA DE DESPACHO ELECTRÓNICA',
64
        55 => 'NOTA DE DÉBITO',
65
        56 => 'NOTA DE DÉBITO ELECTRÓNICA',
66
        60 => 'NOTA DE CRÉDITO',
67
        61 => 'NOTA DE CRÉDITO ELECTRÓNICA',
68
        101 => 'FACTURA DE EXPORTACIÓN',
69
        102 => 'FACTURA DE VENTA EXENTA A ZONA FRANCA PRIMARIA',
70
        103 => 'LIQUIDACIÓN',
71
        104 => 'NOTA DE DÉBITO DE EXPORTACIÓN',
72
        105 => 'BOLETA LIQUIDACIÓN',
73
        106 => 'NOTA DE CRÉDITO DE EXPORTACIÓN',
74
        108 => 'SOLICITUD REGISTRO DE FACTURA (SRF)',
75
        109 => 'FACTURA TURISTA',
76
        110 => 'FACTURA DE EXPORTACIÓN ELECTRÓNICA',
77
        111 => 'NOTA DE DÉBITO DE EXPORTACIÓN ELECTRÓNICA',
78
        112 => 'NOTA DE CRÉDITO DE EXPORTACIÓN ELECTRÓNICA',
79
        801 => 'ORDEN DE COMPRA',
80
        802 => 'NOTA DE PEDIDO',
81
        803 => 'CONTRATO',
82
        804 => 'RESOLUCIÓN',
83
        805 => 'PROCEDO CHILECOMPRA',
84
        806 => 'FICHA CHILECOMPRA',
85
        807 => 'DUS',
86
        808 => 'B/L (CONOCIMIENTO DE EMBARQUE)',
87
        809 => 'AWB',
88
        810 => 'MIC (MANIFIESTO INTERNACIONAL)',
89
        811 => 'CARTA DE PORTE',
90
        812 => 'RESOLUCION SNA',
91
        813 => 'PASAPORTE',
92
        814 => 'CERTIFICADO DE DEPÓSITO BOLSA PROD. CHILE',
93
        815 => 'VALE DE PRENDA BOLSA PROD. CHILE',
94
        901 => 'FACTURA DE VENTAS A EMPRESAS DEL TERRITORIO PREFERENCIAL',
95
        902 => 'CONOCIMIENTO DE EMBARQUE',
96
        903 => 'DOCUMENTO ÚNICO DE SALIDA (DUS)',
97
        904 => 'FACTURA DE TRASPASO',
98
        905 => 'FACTURA DE REEXPEDICIÓN',
99
        906 => 'BOLETAS VENTA MÓDULOS ZF (TODAS)',
100
        907 => 'FACTURAS VENTA MÓDULO ZF (TODAS)',
101
        909 => 'FACTURAS VENTA MÓDULO ZF',
102
        910 => 'SOLICITUD TRASLADO ZONA FRANCA (Z)',
103
        911 => 'DECLARACIÓN DE INGRESO A ZONA FRANCA PRIMARIA',
104
        914 => 'DECLARACIÓN DE INGRESO (DIN)',
105
        919 => 'RESUMEN VENTAS DE NACIONALES PASAJES SIN FACTURA',
106
        920 => 'OTROS REGISTROS NO DOCUMENTADOS (AUMENTA DÉBITO)',
107
        922 => 'OTROS REGISTROS (DISMINUYE DÉBITO)',
108
        924 => 'RESUMEN VENTAS DE INTERNACIONALES PASAJES SIN FACTURA',
109
        // códigos de LibreDTE
110
        0 => 'COTIZACIÓN',
111
        'HES' => 'HOJA DE ENTRADA DE SERVICIOS (HES)',
112
        'EM' => 'Entrada de mercadería (EM)',
113
    ]; ///< Glosas para los tipos de documentos (DTE y otros)
114
115
    private $formas_pago = [
116
        1 => 'Contado',
117
        2 => 'Crédito',
118
        3 => 'Sin costo',
119
    ]; ///< Glosas de las formas de pago
120
121
    private $formas_pago_exportacion = [
122
        1 => 'Cobranza hasta 1 año',
123
        2 => 'Cobranza más de 1 año',
124
        11 => 'Acreditivo hasta 1 año',
125
        12 => 'Acreditivo más de 1 año',
126
        21 => 'Sin pago',
127
        32 => 'Pago anticipado a la fecha de embarque',
128
    ]; ///< Códigos de forma de pago (básicos) de la aduana para exportaciones
129
130
    private $detalle_cols = [
131
        'CdgItem' => ['title'=>'Código', 'align'=>'left', 'width'=>20],
132
        'NmbItem' => ['title'=>'Item', 'align'=>'left', 'width'=>0],
133
        'IndExe' => ['title'=>'IE', 'align'=>'left', 'width'=>'7'],
134
        'QtyItem' => ['title'=>'Cant.', 'align'=>'right', 'width'=>15],
135
        'UnmdItem' => ['title'=>'Unidad', 'align'=>'left', 'width'=>22],
136
        'PrcItem' => ['title'=>'P. unitario', 'align'=>'right', 'width'=>22],
137
        'DescuentoMonto' => ['title'=>'Descuento', 'align'=>'right', 'width'=>22],
138
        'RecargoMonto' => ['title'=>'Recargo', 'align'=>'right', 'width'=>22],
139
        'MontoItem' => ['title'=>'Total item', 'align'=>'right', 'width'=>22],
140
    ]; ///< Nombres de columnas detalle, alineación y ancho
141
142
    private $item_detalle_posicion = 0; ///< Posición del detalle del item respecto al nombre
143
    private $detalle_fuente = 10; ///< Tamaño de la fuente para el detalle en hoja carta
144
145
    private $traslados = [
146
        1 => 'Operación constituye venta',
147
        2 => 'Ventas por efectuar',
148
        3 => 'Consignaciones',
149
        4 => 'Entrega gratuita',
150
        5 => 'Traslados internos',
151
        6 => 'Otros traslados no venta',
152
        7 => 'Guía de devolución',
153
        8 => 'Traslado para exportación (no venta)',
154
        9 => 'Venta para exportación',
155
    ]; ///< Tipos de traslado para guías de despacho
156
157
    private $medios_pago = [
158
        'CH' => 'Cheque',
159
        'CF' => 'Cheque a fecha',
160
        'LT' => 'Letra',
161
        'EF' => 'Efectivo',
162
        'PE' => 'Pago a cuenta corriente',
163
        'TC' => 'Tarjeta de crédito',
164
        'OT' => 'Otro',
165
    ]; ///< Medio de pago disponibles
166
167
    public static $papel = [
168
        0  => 'Hoja carta',
169
        57 => 'Papel contínuo 57mm',
170
        75 => 'Papel contínuo 75mm',
171
        80 => 'Papel contínuo 80mm',
172
    ]; ///< Tamaño de papel que es soportado
173
174
    /**
175
     * Constructor de la clase
176
     * @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)
177
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
178
     * @version 2016-10-06
179
     */
180
    public function __construct($papelContinuo = false)
181
    {
182
        parent::__construct();
183
        $this->SetTitle('Documento Tributario Electrónico (DTE) de Chile by LibreDTE');
184
        $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...
185
    }
186
187
    /**
188
     * Método que asigna la ubicación del logo de la empresa
189
     * @param logo URI del logo (puede ser local o en una URL)
190
     * @param posicion Posición respecto a datos del emisor (=0 izq, =1 arriba)
191
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
192
     * @version 2016-08-04
193
     */
194
    public function setLogo($logo, $posicion = 0)
195
    {
196
        $this->logo = [
197
            'uri' => $logo,
198
            'posicion' => (int)$posicion,
199
        ];
200
    }
201
202
    /**
203
     * Método que asigna los datos de la resolución del SII que autoriza al
204
     * emisor a emitir DTEs
205
     * @param resolucion Arreglo con índices NroResol y FchResol
206
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
207
     * @version 2015-09-08
208
     */
209
    public function setResolucion(array $resolucion)
210
    {
211
        $this->resolucion = $resolucion;
212
    }
213
214
    /**
215
     * Método que asigna la página web que se debe utilizar para indicar donde
216
     * se puede verificar el DTE
217
     * @param web Página web donde se puede verificar el documento
218
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
219
     * @version 2015-12-11
220
     */
221
    public function setWebVerificacion($web)
222
    {
223
        $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...
224
    }
225
226
    /**
227
     * Método que indica si el documento será o no cedible
228
     * @param cedible =true se incorporará leyenda de destino
229
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
230
     * @version 2015-09-09
231
     */
232
    public function setCedible($cedible = true)
233
    {
234
        $this->cedible = $cedible;
235
    }
236
237
    /**
238
     * Método que asigna la posición del detalle del Item respecto al nombre
239
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
240
     * @version 2016-08-05
241
     */
242
    public function setPosicionDetalleItem($posicion)
243
    {
244
        $this->item_detalle_posicion = (int)$posicion;
245
    }
246
247
    /**
248
     * Método que asigna el tamaño de la fuente para el detalle
249
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
250
     * @version 2016-08-03
251
     */
252
    public function setFuenteDetalle($fuente)
253
    {
254
        $this->detalle_fuente = (int)$fuente;
255
    }
256
257
    /**
258
     * Método que asigna el ancho e las columnas del detalle desde un arreglo
259
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
260
     * @version 2016-08-03
261
     */
262
    public function setAnchoColumnasDetalle(array $anchos)
263
    {
264
        foreach ($anchos as $col => $ancho) {
265
            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...
266
                $this->detalle_cols[$col]['width'] = (int)$ancho;
267
            }
268
        }
269
    }
270
271
    /**
272
     * Método que asigna si el tumbre va al pie (por defecto) o va pegado al detalle
273
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
274
     * @version 2017-10-05
275
     */
276
    public function setTimbrePie($timbre_pie = true)
277
    {
278
        $this->timbre_pie = (bool)$timbre_pie;
279
    }
280
281
    /**
282
     * Método que agrega un documento tributario, ya sea en formato de una
283
     * página o papel contínuo según se haya indicado en el constructor
284
     * @param dte Arreglo con los datos del XML (tag Documento)
285
     * @param timbre String XML con el tag TED del DTE
286
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
287
     * @version 2017-07-13
288
     */
289
    public function agregar(array $dte, $timbre = null)
290
    {
291
        $this->dte = $dte['Encabezado']['IdDoc']['TipoDTE'];
292
        // papel hoja carta
293
        if (!$this->papelContinuo) {
294
            $this->agregarNormal($dte, $timbre);
295
        }
296
        // papel contínuo 57mm
297
        else if ($this->papelContinuo==57) {
298
            $this->agregarContinuo57($dte, $timbre);
299
        }
300
        // papel contínuo 75 o 80mm
301
        else {
302
            $this->agregarContinuo($dte, $timbre, $this->papelContinuo);
303
        }
304
    }
305
306
    /**
307
     * Método que agrega una página con el documento tributario
308
     * @param dte Arreglo con los datos del XML (tag Documento)
309
     * @param timbre String XML con el tag TED del DTE
310
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
311
     * @version 2017-11-07
312
     */
313
    private function agregarNormal(array $dte, $timbre)
314
    {
315
        // agregar página para la factura
316
        $this->AddPage();
317
        // agregar cabecera del documento
318
        $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...
319
        $y[] = $this->agregarFolio(
320
            $dte['Encabezado']['Emisor']['RUTEmisor'],
321
            $dte['Encabezado']['IdDoc']['TipoDTE'],
322
            $dte['Encabezado']['IdDoc']['Folio'],
323
            !empty($dte['Encabezado']['Emisor']['CmnaOrigen']) ? $dte['Encabezado']['Emisor']['CmnaOrigen'] : null
324
        );
325
        // datos del documento
326
        $this->setY(max($y));
327
        $this->Ln();
328
        $y = [];
329
        $y[] = $this->agregarDatosEmision($dte['Encabezado']['IdDoc'], !empty($dte['Encabezado']['Emisor']['CdgVendedor'])?$dte['Encabezado']['Emisor']['CdgVendedor']:null);
330
        $y[] = $this->agregarReceptor($dte['Encabezado']);
331
        $this->setY(max($y));
332
        $this->agregarTraslado(
333
            !empty($dte['Encabezado']['IdDoc']['IndTraslado']) ? $dte['Encabezado']['IdDoc']['IndTraslado'] : null,
334
            !empty($dte['Encabezado']['Transporte']) ? $dte['Encabezado']['Transporte'] : null
335
        );
336
        if (!empty($dte['Referencia'])) {
337
            $this->agregarReferencia($dte['Referencia']);
338
        }
339
        $this->agregarDetalle($dte['Detalle']);
340
        if (!empty($dte['DscRcgGlobal'])) {
341
            $this->agregarSubTotal($dte['Detalle']);
342
            $this->agregarDescuentosRecargos($dte['DscRcgGlobal']);
343
        }
344 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...
345
            $this->agregarPagos($dte['Encabezado']['IdDoc']['MntPagos']);
346
        }
347
        // agregar observaciones
348
        $this->x_fin_datos = $this->getY();
349
        $this->agregarObservacion($dte['Encabezado']['IdDoc']);
350
        if (!$this->timbre_pie) {
351
            $this->Ln();
352
        }
353
        $this->x_fin_datos = $this->getY();
354
        $this->agregarTotales($dte['Encabezado']['Totales'], !empty($dte['Encabezado']['OtraMoneda']) ? $dte['Encabezado']['OtraMoneda'] : null);
355
        // agregar timbre
356
        $this->agregarTimbre($timbre);
357
        // agregar acuse de recibo y leyenda cedible
358
        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...
359
            $this->agregarAcuseRecibo();
360
            $this->agregarLeyendaDestino($dte['Encabezado']['IdDoc']['TipoDTE']);
361
        }
362
    }
363
364
    /**
365
     * Método que agrega una página con el documento tributario en papel
366
     * contínuo
367
     * @param dte Arreglo con los datos del XML (tag Documento)
368
     * @param timbre String XML con el tag TED del DTE
369
     * @param width Ancho del papel contínuo en mm
370
     * @author Pablo Reyes (https://github.com/pabloxp)
371
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
372
     * @version 2017-10-24
373
     */
374
    private function agregarContinuo(array $dte, $timbre, $width, $height = 0)
375
    {
376
        // determinar alto de la página y agregarla
377
        $this->logo = null;
378
        $x_start = 1;
379
        $y_start = 1;
380
        $offset = 14;
381
        // determinar alto de la página y agregarla
382
        $this->AddPage('P', [$height ? $height : $this->papel_continuo_alto, $width]);
383
        // agregar cabecera del documento
384
        $y = $this->agregarFolio(
385
            $dte['Encabezado']['Emisor']['RUTEmisor'],
386
            $dte['Encabezado']['IdDoc']['TipoDTE'],
387
            $dte['Encabezado']['IdDoc']['Folio'],
388
            $dte['Encabezado']['Emisor']['CmnaOrigen'],
389
            $x_start, $y_start, $width-($x_start*4), 10,
390
            [0,0,0]
391
        );
392
        $y = $this->agregarEmisor($dte['Encabezado']['Emisor'], $x_start, $y+2, $width-($x_start*4), 8, 9, [0,0,0]);
393
        // datos del documento
394
        $this->SetY($y);
395
        $this->Ln();
396
        $this->setFont('', '', 8);
397
        $this->agregarDatosEmision($dte['Encabezado']['IdDoc'], !empty($dte['Encabezado']['Emisor']['CdgVendedor'])?$dte['Encabezado']['Emisor']['CdgVendedor']:null, $x_start, $offset, false);
398
        $this->agregarReceptor($dte['Encabezado'], $x_start, $offset);
399
        $this->agregarTraslado(
400
            !empty($dte['Encabezado']['IdDoc']['IndTraslado']) ? $dte['Encabezado']['IdDoc']['IndTraslado'] : null,
401
            !empty($dte['Encabezado']['Transporte']) ? $dte['Encabezado']['Transporte'] : null,
402
            $x_start, $offset
403
        );
404
        if (!empty($dte['Referencia'])) {
405
            $this->agregarReferencia($dte['Referencia'], $x_start, $offset);
406
        }
407
        $this->Ln();
408
        $this->agregarDetalleContinuo($dte['Detalle']);
409
        if (!empty($dte['DscRcgGlobal'])) {
410
            $this->Ln();
411
            $this->Ln();
412
            $this->agregarSubTotal($dte['Detalle'], $x_start);
413
            $this->agregarDescuentosRecargos($dte['DscRcgGlobal'], $x_start);
414
        }
415 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...
416
            $this->Ln();
417
            $this->Ln();
418
            $this->agregarPagos($dte['Encabezado']['IdDoc']['MntPagos'], $x_start);
419
        }
420
        $this->agregarTotales($dte['Encabezado']['Totales'], !empty($dte['Encabezado']['OtraMoneda']) ? $dte['Encabezado']['OtraMoneda'] : null, $this->y+6, 23, 17);
421
        // agregar acuse de recibo y leyenda cedible
422 View Code Duplication
        if ($this->cedible and !in_array($dte['Encabezado']['IdDoc']['TipoDTE'], $this->sinAcuseRecibo)) {
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...
423
            $this->agregarAcuseReciboContinuo(3, $this->y+6, 68, 34);
424
            $this->agregarLeyendaDestinoContinuo($dte['Encabezado']['IdDoc']['TipoDTE']);
425
        }
426
        // agregar timbre
427
        $y = $this->agregarObservacion($dte['Encabezado']['IdDoc'], $x_start, $this->y+6);
428
        $this->agregarTimbre($timbre, -10, $x_start, $y+6, 70, 6);
429
        // si el alto no se pasó, entonces es con autocálculo, se elimina esta página y se pasa el alto
430
        // que se logró determinar para crear la página con el alto correcto
431 View Code Duplication
        if (!$height) {
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...
432
            $this->deletePage($this->PageNo());
433
            $this->agregarContinuo($dte, $timbre, $width, $this->getY()+30);
434
        }
435
    }
436
437
    /**
438
     * Método que agrega una página con el documento tributario
439
     * @param dte Arreglo con los datos del XML (tag Documento)
440
     * @param timbre String XML con el tag TED del DTE
441
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
442
     * @version 2017-10-24
443
     */
444
    private function agregarContinuo57(array $dte, $timbre, $width = 57, $height = 0)
445
    {
446
        // determinar alto de la página y agregarla
447
        $this->AddPage('P', [$height ? $height : $this->papel_continuo_alto, $width]);
448
        $x = 1;
449
        $y = 5;
450
        $this->SetXY($x,$y);
451
        // agregar datos del documento
452
        $this->setFont('', '', 8);
453
        $this->MultiTexto(!empty($dte['Encabezado']['Emisor']['RznSoc']) ? $dte['Encabezado']['Emisor']['RznSoc'] : $dte['Encabezado']['Emisor']['RznSocEmisor'], $x, null, '', $width-2);
454
        $this->MultiTexto($dte['Encabezado']['Emisor']['RUTEmisor'], $x, null, '', $width-2);
455
        $this->MultiTexto('Giro: '.(!empty($dte['Encabezado']['Emisor']['GiroEmis']) ? $dte['Encabezado']['Emisor']['GiroEmis'] : $dte['Encabezado']['Emisor']['GiroEmisor']), $x, null, '', $width-2);
456
        $this->MultiTexto($dte['Encabezado']['Emisor']['DirOrigen'].', '.$dte['Encabezado']['Emisor']['CmnaOrigen'], $x, null, '', $width-2);
457
        $this->MultiTexto($this->getTipo($dte['Encabezado']['IdDoc']['TipoDTE']).' N° '.$dte['Encabezado']['IdDoc']['Folio'], $x, null, '', $width-2);
458
        $this->MultiTexto('Fecha: '.date('d/m/Y', strtotime($dte['Encabezado']['IdDoc']['FchEmis'])), $x, null, '', $width-2);
459
        // si no es boleta no nominativa se agregan datos receptor
460
        if ($dte['Encabezado']['Receptor']['RUTRecep']!='66666666-6') {
461
            $this->Ln();
462
            $this->MultiTexto('Receptor: '.$dte['Encabezado']['Receptor']['RUTRecep'], $x, null, '', $width-2);
463
            $this->MultiTexto($dte['Encabezado']['Receptor']['RznSocRecep'], $x, null, '', $width-2);
464
            if (!empty($dte['Encabezado']['Receptor']['GiroRecep'])) {
465
                $this->MultiTexto('Giro: '.$dte['Encabezado']['Receptor']['GiroRecep'], $x, null, '', $width-2);
466
            }
467
            if (!empty($dte['Encabezado']['Receptor']['DirRecep'])) {
468
                $this->MultiTexto($dte['Encabezado']['Receptor']['DirRecep'].', '.$dte['Encabezado']['Receptor']['CmnaRecep'], $x, null, '', $width-2);
469
            }
470
        }
471
        $this->Ln();
472
        // hay un sólo detalle
473
        if (!isset($dte['Detalle'][0])) {
474
            $this->MultiTexto($dte['Detalle']['NmbItem'].': $'.$this->num($dte['Detalle']['MontoItem']), $x, null, '', $width-2);
475
        }
476
        // hay más de un detalle
477
        else {
478
            foreach ($dte['Detalle'] as $d) {
479
                $this->MultiTexto($d['NmbItem'].': $'.$this->num($d['MontoItem']), $x, null, '', $width-2);
480
            }
481
            if (in_array($dte['Encabezado']['IdDoc']['TipoDTE'], [39, 41])) {
482
                $this->MultiTexto('TOTAL: $'.$this->num($dte['Encabezado']['Totales']['MntTotal']), $x, null, '', $width-2);
483
            }
484
        }
485
        // si no es boleta se coloca EXENTO, NETO, IVA y TOTAL si corresponde
486
        if (!in_array($dte['Encabezado']['IdDoc']['TipoDTE'], [39, 41])) {
487 View Code Duplication
            if (!empty($dte['Encabezado']['Totales']['MntExe'])) {
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...
488
                $this->MultiTexto('EXENTO: $'.$this->num($dte['Encabezado']['Totales']['MntExe']), $x, null, '', $width-2);
489
            }
490 View Code Duplication
            if (!empty($dte['Encabezado']['Totales']['MntNeto'])) {
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...
491
                $this->MultiTexto('NETO: $'.$this->num($dte['Encabezado']['Totales']['MntNeto']), $x, null, '', $width-2);
492
            }
493 View Code Duplication
            if (!empty($dte['Encabezado']['Totales']['IVA'])) {
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...
494
                $this->MultiTexto('IVA: $'.$this->num($dte['Encabezado']['Totales']['IVA']), $x, null, '', $width-2);
495
            }
496
            $this->MultiTexto('TOTAL: $'.$this->num($dte['Encabezado']['Totales']['MntTotal']), $x, null, '', $width-2);
497
        }
498
        // agregar acuse de recibo y leyenda cedible
499 View Code Duplication
        if ($this->cedible and !in_array($dte['Encabezado']['IdDoc']['TipoDTE'], $this->sinAcuseRecibo)) {
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...
500
            $this->agregarAcuseReciboContinuo(-1, $this->y+6, $width+2, 34);
501
            $this->agregarLeyendaDestinoContinuo($dte['Encabezado']['IdDoc']['TipoDTE']);
502
        }
503
        // agregar timbre
504
        if (!empty($dte['Encabezado']['IdDoc']['TermPagoGlosa'])) {
505
            $this->Ln();
506
            $this->MultiTexto('Observación: '.$dte['Encabezado']['IdDoc']['TermPagoGlosa']."\n\n", $x);
507
        }
508
        $this->agregarTimbre($timbre, -11, $x, $this->GetY()+6, 55, 6);
509
        // si el alto no se pasó, entonces es con autocálculo, se elimina esta página y se pasa el alto
510
        // que se logró determinar para crear la página con el alto correcto
511 View Code Duplication
        if (!$height) {
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...
512
            $this->deletePage($this->PageNo());
513
            $this->agregarContinuo57($dte, $timbre, $width, $this->getY()+30);
514
        }
515
    }
516
517
    /**
518
     * Método que agrega los datos de la empresa
519
     * Orden de los datos:
520
     *  - Razón social del emisor
521
     *  - Giro del emisor (sin abreviar)
522
     *  - Dirección casa central del emisor
523
     *  - Dirección sucursales
524
     * @param emisor Arreglo con los datos del emisor (tag Emisor del XML)
525
     * @param x Posición horizontal de inicio en el PDF
526
     * @param y Posición vertical de inicio en el PDF
527
     * @param w Ancho de la información del emisor
528
     * @param w_img Ancho máximo de la imagen
529
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
530
     * @version 2018-04-13
531
     */
532
    protected function agregarEmisor(array $emisor, $x = 10, $y = 15, $w = 75, $w_img = 30, $font_size = null, array $color = null)
533
    {
534
        // logo del documento
535
        if (isset($this->logo)) {
536
            $this->Image(
537
                $this->logo['uri'],
538
                $x,
539
                $y,
540
                !$this->logo['posicion']?$w_img:null, $this->logo['posicion']?($w_img/2):null,
541
                'PNG',
542
                (isset($emisor['url'])?$emisor['url']:''),
543
                'T'
544
            );
545
            if ($this->logo['posicion']) {
546
                $this->SetY($this->y + ($w_img/2));
547
                $w += 40;
548
            } else {
549
                $x = $this->x+3;
550
            }
551
        } else {
552
            $this->y = $y-2;
553
            $w += 40;
554
        }
555
        // agregar datos del emisor
556
        $this->setFont('', 'B', $font_size ? $font_size : 14);
557
        $this->SetTextColorArray($color===null?[32, 92, 144]:$color);
558
        $this->MultiTexto(!empty($emisor['RznSoc']) ? $emisor['RznSoc'] : $emisor['RznSocEmisor'], $x, $this->y+2, 'L', $w);
559
        $this->setFont('', 'B', $font_size ? $font_size : 9);
560
        $this->SetTextColorArray([0,0,0]);
561
        $this->MultiTexto(!empty($emisor['GiroEmis']) ? $emisor['GiroEmis'] : $emisor['GiroEmisor'], $x, $this->y, 'L', $w);
562
        $comuna = !empty($emisor['CmnaOrigen']) ? $emisor['CmnaOrigen'] : null;
563
        $ciudad = !empty($emisor['CiudadOrigen']) ? $emisor['CiudadOrigen'] : \sasco\LibreDTE\Chile::getCiudad($comuna);
564
        $this->MultiTexto($emisor['DirOrigen'].($comuna?(', '.$comuna):'').($ciudad?(', '.$ciudad):''), $x, $this->y, 'L', $w);
565
        if (!empty($emisor['Sucursal'])) {
566
            $this->MultiTexto('Sucursal: '.$emisor['Sucursal'], $x, $this->y, 'L', $w);
567
        }
568
        $contacto = [];
569
        if (!empty($emisor['Telefono'])) {
570
            if (!is_array($emisor['Telefono']))
571
                $emisor['Telefono'] = [$emisor['Telefono']];
572
            foreach ($emisor['Telefono'] as $t)
573
                $contacto[] = $t;
574
        }
575
        if (!empty($emisor['CorreoEmisor'])) {
576
            $contacto[] = $emisor['CorreoEmisor'];
577
        }
578
        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...
579
            $this->MultiTexto(implode(' / ', $contacto), $x, $this->y, 'L', $w);
580
        }
581
        return $this->y;
582
    }
583
584
    /**
585
     * Método que agrega el recuadro con el folio
586
     * Recuadro:
587
     *  - Tamaño mínimo 1.5x5.5 cms
588
     *  - En lado derecho (negro o rojo)
589
     *  - Enmarcado por una línea de entre 0.5 y 1 mm de espesor
590
     *  - Tamaño máximo 4x8 cms
591
     *  - Letras tamaño 10 o superior en mayúsculas y negritas
592
     *  - Datos del recuadro: RUT emisor, nombre de documento en 2 líneas,
593
     *    folio.
594
     *  - Bajo el recuadro indicar la Dirección regional o Unidad del SII a la
595
     *    que pertenece el emisor
596
     * @param rut RUT del emisor
597
     * @param tipo Código o glosa del tipo de documento
598
     * @param sucursal_sii Código o glosa de la sucursal del SII del Emisor
599
     * @param x Posición horizontal de inicio en el PDF
600
     * @param y Posición vertical de inicio en el PDF
601
     * @param w Ancho de la información del emisor
602
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
603
     * @version 2016-12-02
604
     */
605
    protected function agregarFolio($rut, $tipo, $folio, $sucursal_sii = null, $x = 130, $y = 15, $w = 70, $font_size = null, array $color = null)
606
    {
607
        if ($color===null) {
608
            $color = $tipo ? ($tipo==52 ? [0,172,140] : [255,0,0]) : [0,0,0];
609
        }
610
        $this->SetTextColorArray($color);
611
        // colocar rut emisor, glosa documento y folio
612
        list($rut, $dv) = explode('-', $rut);
613
        $this->setFont ('', 'B', $font_size ? $font_size : 15);
614
        $this->MultiTexto('R.U.T.: '.$this->num($rut).'-'.$dv, $x, $y+4, 'C', $w);
615
        $this->setFont('', 'B', $font_size ? $font_size : 12);
616
        $this->MultiTexto($this->getTipo($tipo), $x, null, 'C', $w);
617
        $this->setFont('', 'B', $font_size ? $font_size : 15);
618
        $this->MultiTexto('N° '.$folio, $x, null, 'C', $w);
619
        // dibujar rectángulo rojo
620
        $this->Rect($x, $y, $w, round($this->getY()-$y+3), 'D', ['all' => ['width' => 0.5, 'color' => $color]]);
621
        // colocar unidad del SII
622
        $this->setFont('', 'B', $font_size ? $font_size : 10);
623
        if ($tipo) {
624
            $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 605 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...
625
        }
626
        $this->SetTextColorArray([0,0,0]);
627
        $this->Ln();
628
        return $this->y;
629
    }
630
631
    /**
632
     * Método que entrega la glosa del tipo de documento
633
     * @param tipo Código del tipo de documento
634
     * @return Glosa del tipo de documento
635
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
636
     * @version 2016-11-18
637
     */
638
    private function getTipo($tipo)
639
    {
640
        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...
641
            return $tipo;
642
        }
643
        return isset($this->tipos[$tipo]) ? strtoupper($this->tipos[$tipo]) : 'Documento '.$tipo;
644
    }
645
646
    /**
647
     * Método que agrega los datos de la emisión del DTE que no son los dato del
648
     * receptor
649
     * @param IdDoc Información general del documento
650
     * @param x Posición horizontal de inicio en el PDF
651
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
652
     * @version 2017-06-15
653
     */
654
    protected function agregarDatosEmision($IdDoc, $CdgVendedor, $x = 10, $offset = 22, $mostrar_dia = true)
655
    {
656
        // si es hoja carta
657
        if ($x==10) {
658
            $y = $this->GetY();
659
            // fecha emisión
660
            $this->setFont('', 'B', null);
661
            $this->MultiTexto($this->date($IdDoc['FchEmis'], $mostrar_dia), $x, null, 'R');
662
            $this->setFont('', '', null);
663
            // período facturación
664
            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...
665
                $this->MultiTexto('Período del '.date('d/m/y', strtotime($IdDoc['PeriodoDesde'])).' al '.date('d/m/y', strtotime($IdDoc['PeriodoHasta'])), $x, null, 'R');
666
            }
667
            // pago anticicado
668 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...
669
                $this->MultiTexto('Pagado el '.$this->date($IdDoc['FchCancel'], false), $x, null, 'R');
670
            }
671
            // fecha vencimiento
672 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...
673
                $this->MultiTexto('Vence el '.$this->date($IdDoc['FchVenc'], false), $x, null, 'R');
674
            }
675
            // forma de pago nacional
676 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...
677
                $this->MultiTexto('Venta: '.strtolower($this->formas_pago[$IdDoc['FmaPago']]), $x, null, 'R');
678
            }
679
            // forma de pago exportación
680 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...
681
                $this->MultiTexto('Venta: '.strtolower($this->formas_pago_exportacion[$IdDoc['FmaPagExp']]), $x, null, 'R');
682
            }
683
            // vendedor
684
            if (!empty($CdgVendedor)) {
685
                $this->MultiTexto('Vendedor: '.$CdgVendedor, $x, null, 'R');
686
            }
687
            $y_end = $this->GetY();
688
            $this->SetY($y);
689
        }
690
        // papel contínuo
691
        else {
692
            // fecha de emisión
693
            $this->setFont('', 'B', null);
694
            $this->Texto('Emisión', $x);
695
            $this->Texto(':', $x+$offset);
696
            $this->setFont('', '', null);
697
            $this->MultiTexto($this->date($IdDoc['FchEmis'], $mostrar_dia), $x+$offset+2);
698
            // forma de pago nacional
699
            if (!empty($IdDoc['FmaPago'])) {
700
                $this->setFont('', 'B', null);
701
                $this->Texto('Venta', $x);
702
                $this->Texto(':', $x+$offset);
703
                $this->setFont('', '', null);
704
                $this->MultiTexto($this->formas_pago[$IdDoc['FmaPago']], $x+$offset+2);
705
            }
706
            // forma de pago exportación
707
            if (!empty($IdDoc['FmaPagExp'])) {
708
                $this->setFont('', 'B', null);
709
                $this->Texto('Venta', $x);
710
                $this->Texto(':', $x+$offset);
711
                $this->setFont('', '', null);
712
                $this->MultiTexto($this->formas_pago_exportacion[$IdDoc['FmaPagExp']], $x+$offset+2);
713
            }
714
            // pago anticicado
715
            if (!empty($IdDoc['FchCancel'])) {
716
                $this->setFont('', 'B', null);
717
                $this->Texto('Pagado el', $x);
718
                $this->Texto(':', $x+$offset);
719
                $this->setFont('', '', null);
720
                $this->MultiTexto($this->date($IdDoc['FchCancel'], $mostrar_dia), $x+$offset+2);
721
            }
722
            // fecha vencimiento
723
            if (!empty($IdDoc['FchVenc'])) {
724
                $this->setFont('', 'B', null);
725
                $this->Texto('Vence el', $x);
726
                $this->Texto(':', $x+$offset);
727
                $this->setFont('', '', null);
728
                $this->MultiTexto($this->date($IdDoc['FchVenc'], $mostrar_dia), $x+$offset+2);
729
            }
730
            $y_end = $this->GetY();
731
        }
732
        return $y_end;
733
    }
734
735
    /**
736
     * Método que agrega los datos del receptor
737
     * @param receptor Arreglo con los datos del receptor (tag Receptor del XML)
738
     * @param x Posición horizontal de inicio en el PDF
739
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
740
     * @version 2017-06-15
741
     */
742
    protected function agregarReceptor(array $Encabezado, $x = 10, $offset = 22)
743
    {
744
        $receptor = $Encabezado['Receptor'];
745 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...
746
            list($rut, $dv) = explode('-', $receptor['RUTRecep']);
747
            $this->setFont('', 'B', null);
748
            $this->Texto('R.U.T.', $x);
749
            $this->Texto(':', $x+$offset);
750
            $this->setFont('', '', null);
751
            $this->MultiTexto($this->num($rut).'-'.$dv, $x+$offset+2);
752
        }
753 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...
754
            $this->setFont('', 'B', null);
755
            $this->Texto('Señor(es)', $x);
756
            $this->Texto(':', $x+$offset);
757
            $this->setFont('', '', null);
758
            $this->MultiTexto($receptor['RznSocRecep'], $x+$offset+2, null, '', $x==10?105:0);
759
        }
760 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...
761
            $this->setFont('', 'B', null);
762
            $this->Texto('Giro', $x);
763
            $this->Texto(':', $x+$offset);
764
            $this->setFont('', '', null);
765
            $this->MultiTexto($receptor['GiroRecep'], $x+$offset+2);
766
        }
767
        if (!empty($receptor['DirRecep'])) {
768
            $this->setFont('', 'B', null);
769
            $this->Texto('Dirección', $x);
770
            $this->Texto(':', $x+$offset);
771
            $this->setFont('', '', null);
772
            $ciudad = !empty($receptor['CiudadRecep']) ? $receptor['CiudadRecep'] : (
773
                !empty($receptor['CmnaRecep']) ? \sasco\LibreDTE\Chile::getCiudad($receptor['CmnaRecep']) : ''
774
            );
775
            $this->MultiTexto($receptor['DirRecep'].(!empty($receptor['CmnaRecep'])?(', '.$receptor['CmnaRecep']):'').($ciudad?(', '.$ciudad):''), $x+$offset+2);
776
        }
777
        if (!empty($receptor['Extranjero']['Nacionalidad'])) {
778
            $this->setFont('', 'B', null);
779
            $this->Texto('Nacionalidad', $x);
780
            $this->Texto(':', $x+$offset);
781
            $this->setFont('', '', null);
782
            $this->MultiTexto(\sasco\LibreDTE\Sii\Aduana::getNacionalidad($receptor['Extranjero']['Nacionalidad']), $x+$offset+2);
783
        }
784
        if (!empty($receptor['Extranjero']['NumId'])) {
785
            $this->setFont('', 'B', null);
786
            $this->Texto('N° ID extranj.', $x);
787
            $this->Texto(':', $x+$offset);
788
            $this->setFont('', '', null);
789
            $this->MultiTexto($receptor['Extranjero']['NumId'], $x+$offset+2);
790
        }
791
        $contacto = [];
792
        if (!empty($receptor['Contacto']))
793
            $contacto[] = $receptor['Contacto'];
794
        if (!empty($receptor['CorreoRecep']))
795
            $contacto[] = $receptor['CorreoRecep'];
796 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...
797
            $this->setFont('', 'B', null);
798
            $this->Texto('Contacto', $x);
799
            $this->Texto(':', $x+$offset);
800
            $this->setFont('', '', null);
801
            $this->MultiTexto(implode(' / ', $contacto), $x+$offset+2);
802
        }
803 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...
804
            list($rut, $dv) = explode('-', $Encabezado['RUTSolicita']);
805
            $this->setFont('', 'B', null);
806
            $this->Texto('RUT solicita', $x);
807
            $this->Texto(':', $x+$offset);
808
            $this->setFont('', '', null);
809
            $this->MultiTexto($this->num($rut).'-'.$dv, $x+$offset+2);
810
        }
811 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...
812
            $this->setFont('', 'B', null);
813
            $this->Texto('Cód. recep.', $x);
814
            $this->Texto(':', $x+$offset);
815
            $this->setFont('', '', null);
816
            $this->MultiTexto($receptor['CdgIntRecep'], $x+$offset+2, null, '', $x==10?105:0);
817
        }
818
        return $this->GetY();
819
    }
820
821
    /**
822
     * Método que agrega los datos del traslado
823
     * @param IndTraslado
824
     * @param Transporte
825
     * @param x Posición horizontal de inicio en el PDF
826
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
827
     * @version 2016-08-03
828
     */
829
    protected function agregarTraslado($IndTraslado, array $Transporte = null, $x = 10, $offset = 22)
830
    {
831
        // agregar tipo de traslado
832 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...
833
            $this->setFont('', 'B', null);
834
            $this->Texto('Tipo oper.', $x);
835
            $this->Texto(':', $x+$offset);
836
            $this->setFont('', '', null);
837
            $this->MultiTexto($this->traslados[$IndTraslado], $x+$offset+2);
838
        }
839
        // agregar información de transporte
840
        if ($Transporte) {
841
            $transporte = '';
842
            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...
843
                $transporte .= 'a '.$Transporte['DirDest'].', '.$Transporte['CmnaDest'];
844
            }
845
            if (!empty($Transporte['RUTTrans']))
846
                $transporte .= ' por '.$Transporte['RUTTrans'];
847
            if (!empty($Transporte['Patente']))
848
                $transporte .= ' en vehículo '.$Transporte['Patente'];
849
            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...
850 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...
851
                    $transporte .= ' con chofer '.$Transporte['Chofer']['NombreChofer'];
852 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...
853
                    $transporte .= ' ('.$Transporte['Chofer']['RUTChofer'].')';
854
            }
855 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...
856
                $this->setFont('', 'B', null);
857
                $this->Texto('Traslado', $x);
858
                $this->Texto(':', $x+$offset);
859
                $this->setFont('', '', null);
860
                $this->MultiTexto(ucfirst(trim($transporte)), $x+$offset+2);
861
            }
862
        }
863
        // agregar información de aduana
864
        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...
865
            $col = 0;
866
            foreach ($Transporte['Aduana'] as $tag => $codigo) {
867
                if ($codigo===false)
868
                    continue;
869
                $glosa = \sasco\LibreDTE\Sii\Aduana::getGlosa($tag);
870
                $valor = \sasco\LibreDTE\Sii\Aduana::getValor($tag, $codigo);
871
                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...
872
                    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...
873
                        $col = abs($col-110);
874
                        $this->Ln();
875
                    }
876
                    $this->setFont('', 'B', null);
877
                    $this->Texto($glosa, $x+$col);
878
                    $this->Texto(':', $x+$offset+$col);
879
                    $this->setFont('', '', null);
880
                    $this->Texto($valor, $x+$offset+2+$col);
881
                    if ($tag=='TipoBultos')
882
                        $col = abs($col-110);
883
                    if ($col)
884
                        $this->Ln();
885
                    $col = abs($col-110);
886
                }
887
            }
888
            if ($col)
889
                $this->Ln();
890
        }
891
    }
892
893
    /**
894
     * Método que agrega las referencias del documento
895
     * @param referencias Arreglo con las referencias del documento (tag Referencia del XML)
896
     * @param x Posición horizontal de inicio en el PDF
897
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
898
     * @version 2017-09-25
899
     */
900
    protected function agregarReferencia($referencias, $x = 10, $offset = 22)
901
    {
902
        if (!isset($referencias[0]))
903
            $referencias = [$referencias];
904
        foreach($referencias as $r) {
905
            $texto = $r['NroLinRef'].' - ';
906
            if (!empty($r['TpoDocRef'])) {
907
                $texto .= $this->getTipo($r['TpoDocRef']).' ';
908
            }
909
            if (!empty($r['FolioRef'])) {
910
                if (is_numeric($r['FolioRef'])) {
911
                    $texto .= ' N° '.$r['FolioRef'].' ';
912
                } else {
913
                    $texto .= ' '.$r['FolioRef'].' ';
914
                }
915
            }
916
            if (!empty($r['FchRef'])) {
917
                $texto .= 'del '.date('d/m/Y', strtotime($r['FchRef']));
918
            }
919
            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...
920
                $texto = $texto.': '.$r['RazonRef'];
921
            }
922
            $this->setFont('', 'B', null);
923
            $this->Texto('Referencia', $x);
924
            $this->Texto(':', $x+$offset);
925
            $this->setFont('', '', null);
926
            $this->MultiTexto($texto, $x+$offset+2);
927
        }
928
    }
929
930
    /**
931
     * Método que agrega el detalle del documento
932
     * @param detalle Arreglo con el detalle del documento (tag Detalle del XML)
933
     * @param x Posición horizontal de inicio en el PDF
934
     * @param y Posición vertical de inicio en el PDF
935
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
936
     * @version 2016-08-05
937
     */
938
    protected function agregarDetalle($detalle, $x = 10)
939
    {
940
        if (!isset($detalle[0]))
941
            $detalle = [$detalle];
942
        $this->setFont('', '', $this->detalle_fuente);
943
        // titulos
944
        $titulos = [];
945
        $titulos_keys = array_keys($this->detalle_cols);
946
        foreach ($this->detalle_cols as $key => $info) {
947
            $titulos[$key] = $info['title'];
948
        }
949
        // normalizar cada detalle
950
        $dte_exento = in_array($this->dte, [34, 110, 111, 112]);
951
        foreach ($detalle as &$item) {
952
            // quitar columnas
953
            foreach ($item as $col => $valor) {
954
                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...
955
                    $item['NmbItem'] .= !$this->item_detalle_posicion ? '<br/>' : ': ';
956
                    $item['NmbItem'] .= '<span style="font-size:0.7em">'.$item['DscItem'].'</span>';
957
                }
958
                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...
959
                    unset($item[$col]);
960
            }
961
            // ajustes a IndExe
962
            if (isset($item['IndExe'])) {
963
                if ($item['IndExe']==1)
964
                    $item['IndExe'] = 'EX';
965
                else if ($item['IndExe']==2)
966
                    $item['IndExe'] = 'NF';
967
            }
968
            // agregar todas las columnas que se podrían imprimir en la tabla
969
            $item_default = [];
970
            foreach ($this->detalle_cols as $key => $info)
971
                $item_default[$key] = false;
972
            $item = array_merge($item_default, $item);
973
            // si hay código de item se extrae su valor
974
            if ($item['CdgItem'])
975
                $item['CdgItem'] = $item['CdgItem']['VlrCodigo'];
976
            // dar formato a números
977
            foreach (['QtyItem', 'PrcItem', 'DescuentoMonto', 'RecargoMonto', 'MontoItem'] as $col) {
978
                if ($item[$col])
979
                    $item[$col] = $this->num($item[$col]);
980
            }
981
        }
982
        // opciones
983
        $options = ['align'=>[]];
984
        $i = 0;
985
        foreach ($this->detalle_cols as $info) {
986
            if (isset($info['width']))
987
                $options['width'][$i] = $info['width'];
988
            $options['align'][$i] = $info['align'];
989
            $i++;
990
        }
991
        // agregar tabla de detalle
992
        $this->Ln();
993
        $this->SetX($x);
994
        $this->addTableWithoutEmptyCols($titulos, $detalle, $options);
995
    }
996
997
    /**
998
     * Método que agrega el detalle del documento
999
     * @param detalle Arreglo con el detalle del documento (tag Detalle del XML)
1000
     * @param x Posición horizontal de inicio en el PDF
1001
     * @param y Posición vertical de inicio en el PDF
1002
     * @author Pablo Reyes (https://github.com/pabloxp)
1003
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1004
     * @version 2016-12-13
1005
     */
1006
    protected function agregarDetalleContinuo($detalle, $x = 3)
1007
    {
1008
        $this->SetY($this->getY()+1);
1009
        $p1x = $x;
1010
        $p1y = $this->y;
1011
        $p2x = $this->getPageWidth() - 2;
1012
        $p2y = $p1y;  // Use same y for a straight line
1013
        $style = array('width' => 0.2,'color' => array(0, 0, 0));
1014
        $this->Line($p1x, $p1y, $p2x, $p2y, $style);
1015
        $this->Texto($this->detalle_cols['NmbItem']['title'], $x+1, $this->y, ucfirst($this->detalle_cols['NmbItem']['align'][0]), $this->detalle_cols['NmbItem']['width']);
1016
        $this->Texto($this->detalle_cols['PrcItem']['title'], $x+15, $this->y, ucfirst($this->detalle_cols['PrcItem']['align'][0]), $this->detalle_cols['PrcItem']['width']);
1017
        $this->Texto($this->detalle_cols['QtyItem']['title'], $x+35, $this->y, ucfirst($this->detalle_cols['QtyItem']['align'][0]), $this->detalle_cols['QtyItem']['width']);
1018
        $this->Texto($this->detalle_cols['MontoItem']['title'], $x+45, $this->y, ucfirst($this->detalle_cols['MontoItem']['align'][0]), $this->detalle_cols['MontoItem']['width']);
1019
        $this->Line($p1x, $p1y+4, $p2x, $p2y+4, $style);
1020
        if (!isset($detalle[0]))
1021
            $detalle = [$detalle];
1022
        $this->SetY($this->getY()+2);
1023
        foreach($detalle as  &$d) {
1024
            $this->MultiTexto($d['NmbItem'], $x+1, $this->y+4, ucfirst($this->detalle_cols['NmbItem']['align'][0]), $this->detalle_cols['NmbItem']['width']);
1025
            $this->Texto(number_format($d['PrcItem'],0,',','.'), $x+15, $this->y, ucfirst($this->detalle_cols['PrcItem']['align'][0]), $this->detalle_cols['PrcItem']['width']);
1026
            $this->Texto($this->num($d['QtyItem']), $x+35, $this->y, ucfirst($this->detalle_cols['QtyItem']['align'][0]), $this->detalle_cols['QtyItem']['width']);
1027
            $this->Texto($this->num($d['MontoItem']), $x+45, $this->y, ucfirst($this->detalle_cols['MontoItem']['align'][0]), $this->detalle_cols['MontoItem']['width']);
1028
        }
1029
        $this->Line($p1x, $this->y+4, $p2x, $this->y+4, $style);
1030
    }
1031
1032
    /**
1033
     * Método que agrega el subtotal del DTE
1034
     * @param detalle Arreglo con los detalles del documentos para poder
1035
     * calcular subtotal
1036
     * @param x Posición horizontal de inicio en el PDF
1037
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1038
     * @version 2016-08-17
1039
     */
1040
    protected function agregarSubTotal(array $detalle, $x = 10) {
1041
        $subtotal = 0;
1042
        if (!isset($detalle[0])) {
1043
            $detalle = [$detalle];
1044
        }
1045
        foreach($detalle as  &$d) {
1046
            if (!empty($d['MontoItem'])) {
1047
                $subtotal += $d['MontoItem'];
1048
            }
1049
        }
1050
        if ($this->papelContinuo) {
1051
            $this->Texto('Subtotal: '.$this->num($subtotal), $x);
1052
        } else {
1053
            $this->Texto('Subtotal:', 77, null, 'R', 100);
1054
            $this->Texto($this->num($subtotal), 177, null, 'R', 22);
1055
        }
1056
        $this->Ln();
1057
    }
1058
1059
    /**
1060
     * Método que agrega los descuentos y/o recargos globales del documento
1061
     * @param descuentosRecargos Arreglo con los descuentos y/o recargos del documento (tag DscRcgGlobal del XML)
1062
     * @param x Posición horizontal de inicio en el PDF
1063
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1064
     * @version 2016-08-17
1065
     */
1066
    protected function agregarDescuentosRecargos(array $descuentosRecargos, $x = 10)
1067
    {
1068
        if (!isset($descuentosRecargos[0]))
1069
            $descuentosRecargos = [$descuentosRecargos];
1070
        foreach($descuentosRecargos as $dr) {
1071
            $tipo = $dr['TpoMov']=='D' ? 'Descuento' : 'Recargo';
1072
            $valor = $dr['TpoValor']=='%' ? $dr['ValorDR'].'%' : $this->num($dr['ValorDR']);
1073
            if ($this->papelContinuo) {
1074
                $this->Texto($tipo.' global: '.$valor.(!empty($dr['GlosaDR'])?(' ('.$dr['GlosaDR'].')'):''), $x);
1075
            } else {
1076
                $this->Texto($tipo.(!empty($dr['GlosaDR'])?(' ('.$dr['GlosaDR'].')'):'').':', 77, null, 'R', 100);
1077
                $this->Texto($valor, 177, null, 'R', 22);
1078
            }
1079
            $this->Ln();
1080
        }
1081
    }
1082
1083
    /**
1084
     * Método que agrega los pagos del documento
1085
     * @param pagos Arreglo con los pagos del documento
1086
     * @param x Posición horizontal de inicio en el PDF
1087
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1088
     * @version 2016-07-24
1089
     */
1090
    protected function agregarPagos(array $pagos, $x = 10)
1091
    {
1092
        if (!isset($pagos[0]))
1093
            $pagos = [$pagos];
1094
        $this->Texto('Pago(s) programado(s):', $x);
1095
        $this->Ln();
1096
        foreach($pagos as $p) {
1097
            $this->Texto('  - '.$this->date($p['FchPago'], false).': $'.$this->num($p['MntPago']).'.-'.(!empty($p['GlosaPagos'])?(' ('.$p['GlosaPagos'].')'):''), $x);
1098
            $this->Ln();
1099
        }
1100
    }
1101
1102
    /**
1103
     * Método que agrega los totales del documento
1104
     * @param totales Arreglo con los totales (tag Totales del XML)
1105
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1106
     * @version 2017-10-05
1107
     */
1108
    protected function agregarTotales(array $totales, $otra_moneda, $y = 190, $x = 145, $offset = 25)
1109
    {
1110
        $y = (!$this->papelContinuo and !$this->timbre_pie) ? $this->x_fin_datos : $y;
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...
1111
        // normalizar totales
1112
        $totales = array_merge([
1113
            'TpoMoneda' => false,
1114
            'MntNeto' => false,
1115
            'MntExe' => false,
1116
            'TasaIVA' => false,
1117
            'IVA' => false,
1118
            'IVANoRet' => false,
1119
            'CredEC' => false,
1120
            'MntTotal' => false,
1121
            'MontoNF' => false,
1122
            'MontoPeriodo' => false,
1123
            'SaldoAnterior' => false,
1124
            'VlrPagar' => false,
1125
        ], $totales);
1126
        // glosas
1127
        $glosas = [
1128
            'TpoMoneda' => 'Moneda',
1129
            'MntNeto' => 'Neto $',
1130
            'MntExe' => 'Exento $',
1131
            'IVA' => 'IVA ('.$totales['TasaIVA'].'%) $',
1132
            'IVANoRet' => 'IVA no retenido $',
1133
            'CredEC' => 'Desc. 65% IVA $',
1134
            'MntTotal' => 'Total $',
1135
            'MontoNF' => 'Monto no facturable $',
1136
            'MontoPeriodo' => 'Monto período $',
1137
            'SaldoAnterior' => 'Saldo anterior $',
1138
            'VlrPagar' => 'Valor a pagar $',
1139
        ];
1140
        // agregar impuestos adicionales y retenciones
1141
        if (!empty($totales['ImptoReten'])) {
1142
            $ImptoReten = $totales['ImptoReten'];
1143
            $MntTotal = $totales['MntTotal'];
1144
            unset($totales['ImptoReten'], $totales['MntTotal']);
1145
            if (!isset($ImptoReten[0])) {
1146
                $ImptoReten = [$ImptoReten];
1147
            }
1148
            foreach($ImptoReten as $i) {
1149
                $totales['ImptoReten_'.$i['TipoImp']] = $i['MontoImp'];
1150
                if (!empty($i['TasaImp'])) {
1151
                    $glosas['ImptoReten_'.$i['TipoImp']] = \sasco\LibreDTE\Sii\ImpuestosAdicionales::getGlosa($i['TipoImp']).' ('.$i['TasaImp'].'%) $';
1152
                } else {
1153
                    $glosas['ImptoReten_'.$i['TipoImp']] = \sasco\LibreDTE\Sii\ImpuestosAdicionales::getGlosa($i['TipoImp']).' $';
1154
                }
1155
            }
1156
            $totales['MntTotal'] = $MntTotal;
1157
        }
1158
        // agregar cada uno de los totales
1159
        $this->setY($y);
1160
        $this->setFont('', 'B', null);
1161
        foreach ($totales as $key => $total) {
1162
            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...
1163
                $y = $this->GetY();
1164
                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...
1165
                    $this->Texto($glosas[$key].' :', $x, null, 'R', 30);
1166
                    $this->Texto($this->num($total), $x+$offset, $y, 'R', 30);
1167
                    $this->Ln();
1168
                } else {
1169
                    $this->MultiTexto($glosas[$key].' :', $x, null, 'R', 30);
1170
                    $y_new = $this->GetY();
1171
                    $this->Texto($this->num($total), $x+$offset, $y, 'R', 30);
1172
                    $this->SetY($y_new);
1173
                }
1174
            }
1175
        }
1176
        // agregar totales en otra moneda
1177
        if (!empty($otra_moneda)) {
1178
            if (!isset($otra_moneda[0])) {
1179
                $otra_moneda = [$otra_moneda];
1180
            }
1181
            $this->setFont('', '', null);
1182
            $this->Ln();
1183
            foreach ($otra_moneda as $om) {
1184
                $y = $this->GetY();
1185
                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...
1186
                    $this->Texto('Total '.$om['TpoMoneda'].' :', $x, null, 'R', 30);
1187
                    $this->Texto($this->num($om['MntTotOtrMnda']), $x+$offset, $y, 'R', 30);
1188
                    $this->Ln();
1189
                } else {
1190
                    $this->MultiTexto('Total '.$om['TpoMoneda'].' :', $x, null, 'R', 30);
1191
                    $y_new = $this->GetY();
1192
                    $this->Texto($this->num($om['MntTotOtrMnda']), $x+$offset, $y, 'R', 30);
1193
                    $this->SetY($y_new);
1194
                }
1195
            }
1196
            $this->setFont('', 'B', null);
1197
        }
1198
    }
1199
1200
    /**
1201
     * Método que coloca las diferentes observaciones que puede tener el documnto
1202
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1203
     * @version 2018-01-26
1204
     */
1205
    protected function agregarObservacion($IdDoc, $x = 10, $y = 190)
1206
    {
1207
        $y = (!$this->papelContinuo and !$this->timbre_pie) ? $this->x_fin_datos : $y;
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...
1208
        if (!$this->papelContinuo and $this->timbre_pie) {
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...
1209
            $y -= 15;
1210
        }
1211
        $this->SetXY($x, $y);
1212
        if (!empty($IdDoc['TermPagoGlosa'])) {
1213
            $this->MultiTexto('Observación: '.$IdDoc['TermPagoGlosa']);
1214
        }
1215
        if (!empty($IdDoc['MedioPago']) or !empty($IdDoc['TermPagoDias'])) {
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...
1216
            $pago = [];
1217
            if (!empty($IdDoc['MedioPago'])) {
1218
                $medio = !empty($this->medios_pago[$IdDoc['MedioPago']]) ? $this->medios_pago[$IdDoc['MedioPago']] : $IdDoc['MedioPago'];
1219
                $pago[] = 'Medio de pago: '.$medio;
1220
            }
1221
            if (!empty($IdDoc['TermPagoDias'])) {
1222
                $pago[] = 'Días de pago: '.$IdDoc['TermPagoDias'];
1223
            }
1224
            $this->SetXY($x, $this->GetY());
1225
            $this->MultiTexto(implode(' / ', $pago));
1226
        }
1227
        return $this->GetY();
1228
    }
1229
1230
    /**
1231
     * Método que agrega el timbre de la factura
1232
     *  - Se imprime en el tamaño mínimo: 2x5 cms
1233
     *  - En el lado de abajo con margen izquierdo mínimo de 2 cms
1234
     * @param timbre String con los datos del timbre
1235
     * @param x Posición horizontal de inicio en el PDF
1236
     * @param y Posición vertical de inicio en el PDF
1237
     * @param w Ancho del timbre
1238
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1239
     * @version 2018-04-12
1240
     */
1241
    protected function agregarTimbre($timbre, $x_timbre = 10, $x = 10, $y = 190, $w = 70, $font_size = 8)
1242
    {
1243
        $y = (!$this->papelContinuo and !$this->timbre_pie) ? $this->x_fin_datos : $y;
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...
1244
        if ($timbre!==null) {
1245
            $style = [
1246
                'border' => false,
1247
                'padding' => 0,
1248
                'hpadding' => 0,
1249
                'vpadding' => 0,
1250
                'module_width' => 1, // width of a single module in points
1251
                'module_height' => 1, // height of a single module in points
1252
                'fgcolor' => [0,0,0],
1253
                '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...
1254
                'position' => $this->papelContinuo ? 'C' : 'S',
1255
            ];
1256
            $ecl = version_compare(phpversion(), '7.0.0', '<') ? -1 : $this->ecl;
1257
            $this->write2DBarcode($timbre, 'PDF417,,'.$ecl, $x_timbre, $y, $w, 0, $style, 'B');
1258
            $this->setFont('', 'B', $font_size);
1259
            $this->Texto('Timbre Electrónico SII', $x, null, 'C', $w);
1260
            $this->Ln();
1261
            $this->Texto('Resolución '.$this->resolucion['NroResol'].' de '.explode('-', $this->resolucion['FchResol'])[0], $x, null, 'C', $w);
1262
            $this->Ln();
1263
            if ($w>=60) {
1264
                $this->Texto('Verifique documento: '.$this->web_verificacion, $x, null, 'C', $w);
1265
            } else {
1266
                $this->Texto('Verifique documento:', $x, null, 'C', $w);
1267
                $this->Ln();
1268
                $this->Texto($this->web_verificacion, $x, null, 'C', $w);
1269
            }
1270
        }
1271
    }
1272
1273
    /**
1274
     * Método que agrega el acuse de rebido
1275
     * @param x Posición horizontal de inicio en el PDF
1276
     * @param y Posición vertical de inicio en el PDF
1277
     * @param w Ancho del acuse de recibo
1278
     * @param h Alto del acuse de recibo
1279
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1280
     * @version 2018-04-13
1281
     */
1282
    protected function agregarAcuseRecibo($x = 83, $y = 190, $w = 60, $h = 40)
1283
    {
1284
        $y = (!$this->papelContinuo and !$this->timbre_pie) ? $this->x_fin_datos : $y;
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...
1285
        $this->SetTextColorArray([0,0,0]);
1286
        $this->Rect($x, $y, $w, $h, 'D', ['all' => ['width' => 0.1, 'color' => [0, 0, 0]]]);
1287
        $this->setFont('', 'B', 10);
1288
        $this->Texto('Acuse de recibo', $x, $y+1, 'C', $w);
1289
        $this->setFont('', 'B', 8);
1290
        $this->Texto('Nombre', $x+2, $this->y+8);
1291
        $this->Texto('_________________________', $x+18);
1292
        $this->Texto('RUN', $x+2, $this->y+6);
1293
        $this->Texto('_________________________', $x+18);
1294
        $this->Texto('Fecha', $x+2, $this->y+6);
1295
        $this->Texto('_________________________', $x+18);
1296
        $this->Texto('Recinto', $x+2, $this->y+6);
1297
        $this->Texto('_________________________', $x+18);
1298
        $this->Texto('Firma', $x+2, $this->y+8);
1299
        $this->Texto('_________________________', $x+18);
1300
        $this->setFont('', 'B', 7);
1301
        $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);
1302
    }
1303
1304
    /**
1305
     * Método que agrega el acuse de rebido
1306
     * @param x Posición horizontal de inicio en el PDF
1307
     * @param y Posición vertical de inicio en el PDF
1308
     * @param w Ancho del acuse de recibo
1309
     * @param h Alto del acuse de recibo
1310
     * @author Pablo Reyes (https://github.com/pabloxp)
1311
     * @version 2015-11-17
1312
     */
1313
    protected function agregarAcuseReciboContinuo($x = 3, $y = null, $w = 68, $h = 40)
1314
    {
1315
        $this->SetTextColorArray([0,0,0]);
1316
        $this->Rect($x, $y, $w, $h, 'D', ['all' => ['width' => 0.1, 'color' => [0, 0, 0]]]);
1317
        $style = array('width' => 0.2,'color' => array(0, 0, 0));
1318
        $this->Line($x, $y+22, $w+3, $y+22, $style);
1319
        //$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...
1320
        //$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...
1321
        $this->setFont('', 'B', 6);
1322
        $this->Texto('Nombre', $x+2, $this->y+8);
1323
        $this->Texto('_____________________________________________', $x+12);
1324
        $this->Texto('RUN', $x+2, $this->y+6);
1325
        $this->Texto('________________', $x+12);
1326
        $this->Texto('Firma', $x+32, $this->y+0.5);
1327
        $this->Texto('___________________', $x+42.5);
1328
        $this->Texto('Fecha', $x+2, $this->y+6);
1329
        $this->Texto('________________', $x+12);
1330
        $this->Texto('Recinto', $x+32, $this->y+0.5);
1331
        $this->Texto('___________________', $x+42.5);
1332
1333
        $this->setFont('', 'B', 5);
1334
        $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);
1335
    }
1336
1337
    /**
1338
     * Método que agrega la leyenda de destino
1339
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1340
     * @version 2017-10-05
1341
     */
1342
    protected function agregarLeyendaDestino($tipo, $y = 190, $font_size = 10)
1343
    {
1344
        $y = (!$this->papelContinuo and !$this->timbre_pie) ? $this->x_fin_datos : $y;
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...
1345
        $y += 64;
1346
        $this->setFont('', 'B', $font_size);
1347
        $this->Texto('CEDIBLE'.($tipo==52?' CON SU FACTURA':''), null, $y, 'R');
1348
    }
1349
1350
    /**
1351
     * Método que agrega la leyenda de destino
1352
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1353
     * @version 2017-10-05
1354
     */
1355
    protected function agregarLeyendaDestinoContinuo($tipo)
1356
    {
1357
        $this->setFont('', 'B', 8);
1358
        $this->Texto('CEDIBLE'.($tipo==52?' CON SU FACTURA':''), null, $this->y+6, 'R');
1359
    }
1360
1361
    /**
1362
     * Método que formatea un número con separador de miles y decimales (si
1363
     * corresponden)
1364
     * @param n Número que se desea formatear
1365
     * @return Número formateado
1366
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1367
     * @version 2016-04-05
1368
     */
1369
    protected function num($n)
1370
    {
1371
        if (!is_numeric($n))
1372
            return $n;
1373
        $broken_number = explode('.', (string)$n);
1374
        if (isset($broken_number[1]))
1375
            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...
1376
        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...
1377
    }
1378
1379
    /**
1380
     * Método que formatea una fecha en formato YYYY-MM-DD a un string
1381
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1382
     * @version 2016-04-28
1383
     */
1384
    protected function date($date, $mostrar_dia = true)
1385
    {
1386
        $dias = ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'];
1387
        $meses = ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'];
1388
        $unixtime = strtotime($date);
1389
        $fecha = date(($mostrar_dia?'\D\I\A ':'').'j \d\e \M\E\S \d\e\l Y', $unixtime);
1390
        $dia = $dias[date('w', $unixtime)];
1391
        $mes = $meses[date('n', $unixtime)-1];
1392
        return str_replace(array('DIA', 'MES'), array($dia, $mes), $fecha);
1393
    }
1394
1395
}
1396