Completed
Push — master ( 22c6f8...d26817 )
by Esteban De La Fuente
04:22
created

Dte::num()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
cc 3
nc 3
nop 1
1
<?php
2
3
/**
4
 * LibreDTE
5
 * Copyright (C) SASCO SpA (https://sasco.cl)
6
 *
7
 * Este programa es software libre: usted puede redistribuirlo y/o
8
 * modificarlo bajo los términos de la Licencia Pública General Affero de GNU
9
 * publicada por la Fundación para el Software Libre, ya sea la versión
10
 * 3 de la Licencia, o (a su elección) cualquier versión posterior de la
11
 * misma.
12
 *
13
 * Este programa se distribuye con la esperanza de que sea útil, pero
14
 * SIN GARANTÍA ALGUNA; ni siquiera la garantía implícita
15
 * MERCANTIL o de APTITUD PARA UN PROPÓSITO DETERMINADO.
16
 * Consulte los detalles de la Licencia Pública General Affero de GNU para
17
 * obtener una información más detallada.
18
 *
19
 * Debería haber recibido una copia de la Licencia Pública General Affero de GNU
20
 * junto a este programa.
21
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
22
 */
23
24
namespace sasco\LibreDTE\Sii\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-06-15
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 $casa_matriz = false; ///< Dirección de la casa matriz
43
    protected $ecl = 5; ///< error correction level para PHP >= 7.0.0
44
    protected $papel_continuo_alto = 5000; ///< Alto exageradamente grande para autocálculo de alto en papel continuo
45
    protected $timbre_pie = true; ///< Indica si el timbre va al pie o no (va pegado al detalle)
46
47
    private $tipos = [
48
        // códigos oficiales SII
49
        29 => 'FACTURA DE INICIO',
50
        30 => 'FACTURA',
51
        32 => 'FACTURA DE VENTA BIENES Y SERVICIOS NO AFECTOS O EXENTOS DE IVA',
52
        33 => 'FACTURA ELECTRÓNICA',
53
        34 => 'FACTURA NO AFECTA O EXENTA ELECTRÓNICA',
54
        35 => 'BOLETA',
55
        38 => 'BOLETA EXENTA',
56
        39 => 'BOLETA ELECTRÓNICA',
57
        40 => 'LIQUIDACION FACTURA',
58
        41 => 'BOLETA NO AFECTA O EXENTA ELECTRÓNICA',
59
        43 => 'LIQUIDACIÓN FACTURA ELECTRÓNICA',
60
        45 => 'FACTURA DE COMPRA',
61
        46 => 'FACTURA DE COMPRA ELECTRÓNICA',
62
        48 => 'COMPROBANTE DE PAGO ELECTRÓNICO',
63
        50 => 'GUÍA DE DESPACHO',
64
        52 => 'GUÍA DE DESPACHO ELECTRÓNICA',
65
        55 => 'NOTA DE DÉBITO',
66
        56 => 'NOTA DE DÉBITO ELECTRÓNICA',
67
        60 => 'NOTA DE CRÉDITO',
68
        61 => 'NOTA DE CRÉDITO ELECTRÓNICA',
69
        101 => 'FACTURA DE EXPORTACIÓN',
70
        102 => 'FACTURA DE VENTA EXENTA A ZONA FRANCA PRIMARIA',
71
        103 => 'LIQUIDACIÓN',
72
        104 => 'NOTA DE DÉBITO DE EXPORTACIÓN',
73
        105 => 'BOLETA LIQUIDACIÓN',
74
        106 => 'NOTA DE CRÉDITO DE EXPORTACIÓN',
75
        108 => 'SOLICITUD REGISTRO DE FACTURA (SRF)',
76
        109 => 'FACTURA TURISTA',
77
        110 => 'FACTURA DE EXPORTACIÓN ELECTRÓNICA',
78
        111 => 'NOTA DE DÉBITO DE EXPORTACIÓN ELECTRÓNICA',
79
        112 => 'NOTA DE CRÉDITO DE EXPORTACIÓN ELECTRÓNICA',
80
        801 => 'ORDEN DE COMPRA',
81
        802 => 'NOTA DE PEDIDO',
82
        803 => 'CONTRATO',
83
        804 => 'RESOLUCIÓN',
84
        805 => 'PROCEDO CHILECOMPRA',
85
        806 => 'FICHA CHILECOMPRA',
86
        807 => 'DUS',
87
        808 => 'B/L (CONOCIMIENTO DE EMBARQUE)',
88
        809 => 'AWB',
89
        810 => 'MIC (MANIFIESTO INTERNACIONAL)',
90
        811 => 'CARTA DE PORTE',
91
        812 => 'RESOLUCION SNA',
92
        813 => 'PASAPORTE',
93
        814 => 'CERTIFICADO DE DEPÓSITO BOLSA PROD. CHILE',
94
        815 => 'VALE DE PRENDA BOLSA PROD. CHILE',
95
        901 => 'FACTURA DE VENTAS A EMPRESAS DEL TERRITORIO PREFERENCIAL',
96
        902 => 'CONOCIMIENTO DE EMBARQUE',
97
        903 => 'DOCUMENTO ÚNICO DE SALIDA (DUS)',
98
        904 => 'FACTURA DE TRASPASO',
99
        905 => 'FACTURA DE REEXPEDICIÓN',
100
        906 => 'BOLETAS VENTA MÓDULOS ZF (TODAS)',
101
        907 => 'FACTURAS VENTA MÓDULO ZF (TODAS)',
102
        909 => 'FACTURAS VENTA MÓDULO ZF',
103
        910 => 'SOLICITUD TRASLADO ZONA FRANCA (Z)',
104
        911 => 'DECLARACIÓN DE INGRESO A ZONA FRANCA PRIMARIA',
105
        914 => 'DECLARACIÓN DE INGRESO (DIN)',
106
        919 => 'RESUMEN VENTAS DE NACIONALES PASAJES SIN FACTURA',
107
        920 => 'OTROS REGISTROS NO DOCUMENTADOS (AUMENTA DÉBITO)',
108
        922 => 'OTROS REGISTROS (DISMINUYE DÉBITO)',
109
        924 => 'RESUMEN VENTAS DE INTERNACIONALES PASAJES SIN FACTURA',
110
        // códigos de LibreDTE
111
        0 => 'COTIZACIÓN',
112
        'HES' => 'HOJA DE ENTRADA DE SERVICIOS (HES)',
113
        'EM' => 'Entrada de mercadería (EM)',
114
    ]; ///< Glosas para los tipos de documentos (DTE y otros)
115
116
    private $formas_pago = [
117
        1 => 'Contado',
118
        2 => 'Crédito',
119
        3 => 'Sin costo',
120
    ]; ///< Glosas de las formas de pago
121
122
    private $formas_pago_exportacion = [
123
        1 => 'Cobranza hasta 1 año',
124
        2 => 'Cobranza más de 1 año',
125
        11 => 'Acreditivo hasta 1 año',
126
        12 => 'Acreditivo más de 1 año',
127
        21 => 'Sin pago',
128
        32 => 'Pago anticipado a la fecha de embarque',
129
    ]; ///< Códigos de forma de pago (básicos) de la aduana para exportaciones
130
131
    private $detalle_cols = [
132
        'CdgItem' => ['title'=>'Código', 'align'=>'left', 'width'=>20],
133
        'NmbItem' => ['title'=>'Item', 'align'=>'left', 'width'=>0],
134
        'IndExe' => ['title'=>'IE', 'align'=>'left', 'width'=>'7'],
135
        'QtyItem' => ['title'=>'Cant.', 'align'=>'right', 'width'=>15],
136
        'UnmdItem' => ['title'=>'Unidad', 'align'=>'left', 'width'=>22],
137
        'PrcItem' => ['title'=>'P. unitario', 'align'=>'right', 'width'=>22],
138
        'DescuentoMonto' => ['title'=>'Descuento', 'align'=>'right', 'width'=>22],
139
        'RecargoMonto' => ['title'=>'Recargo', 'align'=>'right', 'width'=>22],
140
        'MontoItem' => ['title'=>'Total item', 'align'=>'right', 'width'=>22],
141
    ]; ///< Nombres de columnas detalle, alineación y ancho
142
143
    private $item_detalle_posicion = 0; ///< Posición del detalle del item respecto al nombre
144
    private $detalle_fuente = 10; ///< Tamaño de la fuente para el detalle en hoja carta
145
146
    private $traslados = [
147
        1 => 'Operación constituye venta',
148
        2 => 'Ventas por efectuar',
149
        3 => 'Consignaciones',
150
        4 => 'Entrega gratuita',
151
        5 => 'Traslados internos',
152
        6 => 'Otros traslados no venta',
153
        7 => 'Guía de devolución',
154
        8 => 'Traslado para exportación (no venta)',
155
        9 => 'Venta para exportación',
156
    ]; ///< Tipos de traslado para guías de despacho
157
158
    private $medios_pago = [
159
        'EF' => 'Efectivo',
160
        'PE' => 'Depósito o transferencia',
161
        'TC' => 'Tarjeta de crédito o débito',
162
        'CH' => 'Cheque',
163
        'CF' => 'Cheque a fecha',
164
        'LT' => 'Letra',
165
        'OT' => 'Otro',
166
    ]; ///< Medio de pago disponibles
167
168
    public static $papel = [
169
        0  => 'Hoja carta',
170
        57 => 'Papel contínuo 57mm',
171
        75 => 'Papel contínuo 75mm',
172
        80 => 'Papel contínuo 80mm',
173
    ]; ///< Tamaño de papel que es soportado
174
175
    /**
176
     * Constructor de la clase
177
     * @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)
178
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
179
     * @version 2016-10-06
180
     */
181
    public function __construct($papelContinuo = false)
182
    {
183
        parent::__construct();
184
        $this->SetTitle('Documento Tributario Electrónico (DTE) de Chile by LibreDTE');
185
        $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...
186
    }
187
188
    /**
189
     * Método que asigna la ubicación del logo de la empresa
190
     * @param logo URI del logo (puede ser local o en una URL)
191
     * @param posicion Posición respecto a datos del emisor (=0 izq, =1 arriba)
192
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
193
     * @version 2016-08-04
194
     */
195
    public function setLogo($logo, $posicion = 0)
196
    {
197
        $this->logo = [
198
            'uri' => $logo,
199
            'posicion' => (int)$posicion,
200
        ];
201
    }
202
203
    /**
204
     * Método que asigna los datos de la resolución del SII que autoriza al
205
     * emisor a emitir DTEs
206
     * @param resolucion Arreglo con índices NroResol y FchResol
207
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
208
     * @version 2015-09-08
209
     */
210
    public function setResolucion(array $resolucion)
211
    {
212
        $this->resolucion = $resolucion;
213
    }
214
215
    /**
216
     * Método que asigna la página web que se debe utilizar para indicar donde
217
     * se puede verificar el DTE
218
     * @param web Página web donde se puede verificar el documento
219
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
220
     * @version 2015-12-11
221
     */
222
    public function setWebVerificacion($web)
223
    {
224
        $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...
225
    }
226
227
    /**
228
     * Método que indica si el documento será o no cedible
229
     * @param cedible =true se incorporará leyenda de destino
230
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
231
     * @version 2015-09-09
232
     */
233
    public function setCedible($cedible = true)
234
    {
235
        $this->cedible = $cedible;
236
    }
237
238
    /**
239
     * Método que indica la dirección de la casa matriz
240
     * @param casa_matriz Dirección de la casa matriz que emite el DTE
241
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
242
     * @version 2018-06-15
243
     */
244
    public function setCasaMatriz($casa_matriz)
245
    {
246
        $this->casa_matriz = $casa_matriz;
0 ignored issues
show
Documentation Bug introduced by
It seems like $casa_matriz of type object<sasco\LibreDTE\Sii\PDF\Dirección> is incompatible with the declared type boolean of property $casa_matriz.

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...
247
    }
248
249
    /**
250
     * Método que asigna la posición del detalle del Item respecto al nombre
251
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
252
     * @version 2016-08-05
253
     */
254
    public function setPosicionDetalleItem($posicion)
255
    {
256
        $this->item_detalle_posicion = (int)$posicion;
257
    }
258
259
    /**
260
     * Método que asigna el tamaño de la fuente para el detalle
261
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
262
     * @version 2016-08-03
263
     */
264
    public function setFuenteDetalle($fuente)
265
    {
266
        $this->detalle_fuente = (int)$fuente;
267
    }
268
269
    /**
270
     * Método que asigna el ancho e las columnas del detalle desde un arreglo
271
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
272
     * @version 2016-08-03
273
     */
274
    public function setAnchoColumnasDetalle(array $anchos)
275
    {
276
        foreach ($anchos as $col => $ancho) {
277
            if (isset($this->detalle_cols[$col]) and $ancho) {
278
                $this->detalle_cols[$col]['width'] = (int)$ancho;
279
            }
280
        }
281
    }
282
283
    /**
284
     * Método que asigna si el tumbre va al pie (por defecto) o va pegado al detalle
285
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
286
     * @version 2017-10-05
287
     */
288
    public function setTimbrePie($timbre_pie = true)
289
    {
290
        $this->timbre_pie = (bool)$timbre_pie;
291
    }
292
293
    /**
294
     * Método que agrega un documento tributario, ya sea en formato de una
295
     * página o papel contínuo según se haya indicado en el constructor
296
     * @param dte Arreglo con los datos del XML (tag Documento)
297
     * @param timbre String XML con el tag TED del DTE
298
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
299
     * @version 2017-07-13
300
     */
301
    public function agregar(array $dte, $timbre = null)
302
    {
303
        $this->dte = $dte['Encabezado']['IdDoc']['TipoDTE'];
304
        // papel hoja carta
305
        if (!$this->papelContinuo) {
306
            $this->agregarNormal($dte, $timbre);
307
        }
308
        // papel contínuo 57mm
309
        else if ($this->papelContinuo==57) {
310
            $this->agregarContinuo57($dte, $timbre);
311
        }
312
        // papel contínuo 75 o 80mm
313
        else {
314
            $this->agregarContinuo($dte, $timbre, $this->papelContinuo);
315
        }
316
    }
317
318
    /**
319
     * Método que agrega una página con el documento tributario
320
     * @param dte Arreglo con los datos del XML (tag Documento)
321
     * @param timbre String XML con el tag TED del DTE
322
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
323
     * @version 2017-11-07
324
     */
325
    private function agregarNormal(array $dte, $timbre)
326
    {
327
        // agregar página para la factura
328
        $this->AddPage();
329
        // agregar cabecera del documento
330
        $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...
331
        $y[] = $this->agregarFolio(
332
            $dte['Encabezado']['Emisor']['RUTEmisor'],
333
            $dte['Encabezado']['IdDoc']['TipoDTE'],
334
            $dte['Encabezado']['IdDoc']['Folio'],
335
            !empty($dte['Encabezado']['Emisor']['CmnaOrigen']) ? $dte['Encabezado']['Emisor']['CmnaOrigen'] : null
336
        );
337
        // datos del documento
338
        $this->setY(max($y));
339
        $this->Ln();
340
        $y = [];
341
        $y[] = $this->agregarDatosEmision($dte['Encabezado']['IdDoc'], !empty($dte['Encabezado']['Emisor']['CdgVendedor'])?$dte['Encabezado']['Emisor']['CdgVendedor']:null);
342
        $y[] = $this->agregarReceptor($dte['Encabezado']);
343
        $this->setY(max($y));
344
        $this->agregarTraslado(
345
            !empty($dte['Encabezado']['IdDoc']['IndTraslado']) ? $dte['Encabezado']['IdDoc']['IndTraslado'] : null,
346
            !empty($dte['Encabezado']['Transporte']) ? $dte['Encabezado']['Transporte'] : null
347
        );
348
        if (!empty($dte['Referencia'])) {
349
            $this->agregarReferencia($dte['Referencia']);
350
        }
351
        $this->agregarDetalle($dte['Detalle']);
352
        if (!empty($dte['DscRcgGlobal'])) {
353
            $this->agregarSubTotal($dte['Detalle']);
354
            $this->agregarDescuentosRecargos($dte['DscRcgGlobal']);
355
        }
356 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...
357
            $this->agregarPagos($dte['Encabezado']['IdDoc']['MntPagos']);
358
        }
359
        // agregar observaciones
360
        $this->x_fin_datos = $this->getY();
361
        $this->agregarObservacion($dte['Encabezado']['IdDoc']);
362
        if (!$this->timbre_pie) {
363
            $this->Ln();
364
        }
365
        $this->x_fin_datos = $this->getY();
366
        $this->agregarTotales($dte['Encabezado']['Totales'], !empty($dte['Encabezado']['OtraMoneda']) ? $dte['Encabezado']['OtraMoneda'] : null);
367
        // agregar timbre
368
        $this->agregarTimbre($timbre);
369
        // agregar acuse de recibo y leyenda cedible
370
        if ($this->cedible and !in_array($dte['Encabezado']['IdDoc']['TipoDTE'], $this->sinAcuseRecibo)) {
371
            $this->agregarAcuseRecibo();
372
            $this->agregarLeyendaDestino($dte['Encabezado']['IdDoc']['TipoDTE']);
373
        }
374
    }
375
376
    /**
377
     * Método que agrega una página con el documento tributario en papel
378
     * contínuo
379
     * @param dte Arreglo con los datos del XML (tag Documento)
380
     * @param timbre String XML con el tag TED del DTE
381
     * @param width Ancho del papel contínuo en mm
382
     * @author Pablo Reyes (https://github.com/pabloxp)
383
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
384
     * @version 2017-10-24
385
     */
386
    private function agregarContinuo(array $dte, $timbre, $width, $height = 0)
387
    {
388
        // determinar alto de la página y agregarla
389
        $this->logo = null;
390
        $x_start = 1;
391
        $y_start = 1;
392
        $offset = 14;
393
        // determinar alto de la página y agregarla
394
        $this->AddPage('P', [$height ? $height : $this->papel_continuo_alto, $width]);
395
        // agregar cabecera del documento
396
        $y = $this->agregarFolio(
397
            $dte['Encabezado']['Emisor']['RUTEmisor'],
398
            $dte['Encabezado']['IdDoc']['TipoDTE'],
399
            $dte['Encabezado']['IdDoc']['Folio'],
400
            $dte['Encabezado']['Emisor']['CmnaOrigen'],
401
            $x_start, $y_start, $width-($x_start*4), 10,
402
            [0,0,0]
403
        );
404
        $y = $this->agregarEmisor($dte['Encabezado']['Emisor'], $x_start, $y+2, $width-($x_start*45), 8, 9, [0,0,0]);
405
        // datos del documento
406
        $this->SetY($y);
407
        $this->Ln();
408
        $this->setFont('', '', 8);
409
        $this->agregarDatosEmision($dte['Encabezado']['IdDoc'], !empty($dte['Encabezado']['Emisor']['CdgVendedor'])?$dte['Encabezado']['Emisor']['CdgVendedor']:null, $x_start, $offset, false);
410
        $this->agregarReceptor($dte['Encabezado'], $x_start, $offset);
411
        $this->agregarTraslado(
412
            !empty($dte['Encabezado']['IdDoc']['IndTraslado']) ? $dte['Encabezado']['IdDoc']['IndTraslado'] : null,
413
            !empty($dte['Encabezado']['Transporte']) ? $dte['Encabezado']['Transporte'] : null,
414
            $x_start, $offset
415
        );
416
        if (!empty($dte['Referencia'])) {
417
            $this->agregarReferencia($dte['Referencia'], $x_start, $offset);
418
        }
419
        $this->Ln();
420
        $this->agregarDetalleContinuo($dte['Detalle']);
421
        if (!empty($dte['DscRcgGlobal'])) {
422
            $this->Ln();
423
            $this->Ln();
424
            $this->agregarSubTotal($dte['Detalle'], $x_start);
425
            $this->agregarDescuentosRecargos($dte['DscRcgGlobal'], $x_start);
426
        }
427 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...
428
            $this->Ln();
429
            $this->Ln();
430
            $this->agregarPagos($dte['Encabezado']['IdDoc']['MntPagos'], $x_start);
431
        }
432
        $this->agregarTotales($dte['Encabezado']['Totales'], !empty($dte['Encabezado']['OtraMoneda']) ? $dte['Encabezado']['OtraMoneda'] : null, $this->y+6, 23, 17);
433
        // agregar acuse de recibo y leyenda cedible
434 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...
435
            $this->agregarAcuseReciboContinuo(3, $this->y+6, 68, 34);
436
            $this->agregarLeyendaDestinoContinuo($dte['Encabezado']['IdDoc']['TipoDTE']);
437
        }
438
        // agregar timbre
439
        $y = $this->agregarObservacion($dte['Encabezado']['IdDoc'], $x_start, $this->y+6);
440
        $this->agregarTimbre($timbre, -10, $x_start, $y+6, 70, 6);
441
        // si el alto no se pasó, entonces es con autocálculo, se elimina esta página y se pasa el alto
442
        // que se logró determinar para crear la página con el alto correcto
443 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...
444
            $this->deletePage($this->PageNo());
445
            $this->agregarContinuo($dte, $timbre, $width, $this->getY()+30);
446
        }
447
    }
448
449
    /**
450
     * Método que agrega una página con el documento tributario
451
     * @param dte Arreglo con los datos del XML (tag Documento)
452
     * @param timbre String XML con el tag TED del DTE
453
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
454
     * @version 2018-07-04
455
     */
456
    private function agregarContinuo57(array $dte, $timbre, $width = 57, $height = 0)
457
    {
458
        // determinar alto de la página y agregarla
459
        $this->AddPage('P', [$height ? $height : $this->papel_continuo_alto, $width]);
460
        $x = 1;
461
        $y = 5;
462
        $this->SetXY($x,$y);
463
        // agregar datos del documento
464
        $this->setFont('', '', 8);
465
        $this->MultiTexto(!empty($dte['Encabezado']['Emisor']['RznSoc']) ? $dte['Encabezado']['Emisor']['RznSoc'] : $dte['Encabezado']['Emisor']['RznSocEmisor'], $x, null, '', $width-2);
466
        $this->MultiTexto($dte['Encabezado']['Emisor']['RUTEmisor'], $x, null, '', $width-2);
467
        $this->MultiTexto('Giro: '.(!empty($dte['Encabezado']['Emisor']['GiroEmis']) ? $dte['Encabezado']['Emisor']['GiroEmis'] : $dte['Encabezado']['Emisor']['GiroEmisor']), $x, null, '', $width-2);
468
        $this->MultiTexto($dte['Encabezado']['Emisor']['DirOrigen'].', '.$dte['Encabezado']['Emisor']['CmnaOrigen'], $x, null, '', $width-2);
469
        if (!empty($this->casa_matriz)) {
470
            $this->MultiTexto('Casa matriz: '.$this->casa_matriz, $x, null, '', $width-2);
471
        }
472
        $this->MultiTexto($this->getTipo($dte['Encabezado']['IdDoc']['TipoDTE']).' N° '.$dte['Encabezado']['IdDoc']['Folio'], $x, null, '', $width-2);
473
        $this->MultiTexto('Fecha: '.date('d/m/Y', strtotime($dte['Encabezado']['IdDoc']['FchEmis'])), $x, null, '', $width-2);
474
        // si no es boleta no nominativa se agregan datos receptor
475
        if ($dte['Encabezado']['Receptor']['RUTRecep']!='66666666-6') {
476
            $this->Ln();
477
            $this->MultiTexto('Receptor: '.$dte['Encabezado']['Receptor']['RUTRecep'], $x, null, '', $width-2);
478
            $this->MultiTexto($dte['Encabezado']['Receptor']['RznSocRecep'], $x, null, '', $width-2);
479
            if (!empty($dte['Encabezado']['Receptor']['GiroRecep'])) {
480
                $this->MultiTexto('Giro: '.$dte['Encabezado']['Receptor']['GiroRecep'], $x, null, '', $width-2);
481
            }
482
            if (!empty($dte['Encabezado']['Receptor']['DirRecep'])) {
483
                $this->MultiTexto($dte['Encabezado']['Receptor']['DirRecep'].', '.$dte['Encabezado']['Receptor']['CmnaRecep'], $x, null, '', $width-2);
484
            }
485
        }
486
        $this->Ln();
487
        // hay un sólo detalle
488
        if (!isset($dte['Detalle'][0])) {
489
            $this->MultiTexto($dte['Detalle']['NmbItem'].': $'.$this->num($dte['Detalle']['MontoItem']), $x, null, '', $width-2);
490
        }
491
        // hay más de un detalle
492
        else {
493
            foreach ($dte['Detalle'] as $d) {
494
                $this->MultiTexto($d['NmbItem'].': $'.$this->num($d['MontoItem']), $x, null, '', $width-2);
495
            }
496
            if (in_array($dte['Encabezado']['IdDoc']['TipoDTE'], [39, 41])) {
497
                $this->MultiTexto('TOTAL: $'.$this->num($dte['Encabezado']['Totales']['MntTotal']), $x, null, '', $width-2);
498
            }
499
        }
500
        // si no es boleta se coloca EXENTO, NETO, IVA y TOTAL si corresponde
501
        if (!in_array($dte['Encabezado']['IdDoc']['TipoDTE'], [39, 41])) {
502 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...
503
                $this->MultiTexto('EXENTO: $'.$this->num($dte['Encabezado']['Totales']['MntExe']), $x, null, '', $width-2);
504
            }
505 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...
506
                $this->MultiTexto('NETO: $'.$this->num($dte['Encabezado']['Totales']['MntNeto']), $x, null, '', $width-2);
507
            }
508 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...
509
                $this->MultiTexto('IVA: $'.$this->num($dte['Encabezado']['Totales']['IVA']), $x, null, '', $width-2);
510
            }
511
            $this->MultiTexto('TOTAL: $'.$this->num($dte['Encabezado']['Totales']['MntTotal']), $x, null, '', $width-2);
512
        }
513
        // agregar acuse de recibo y leyenda cedible
514 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...
515
            $this->agregarAcuseReciboContinuo(-1, $this->y+6, $width+2, 34);
516
            $this->agregarLeyendaDestinoContinuo($dte['Encabezado']['IdDoc']['TipoDTE']);
517
        }
518
        // agregar timbre
519
        if (!empty($dte['Encabezado']['IdDoc']['TermPagoGlosa'])) {
520
            $this->Ln();
521
            $this->MultiTexto('Observación: '.$dte['Encabezado']['IdDoc']['TermPagoGlosa']."\n\n", $x);
522
        }
523
        $this->agregarTimbre($timbre, -11, $x, $this->GetY()+6, 55, 6);
524
        // si el alto no se pasó, entonces es con autocálculo, se elimina esta página y se pasa el alto
525
        // que se logró determinar para crear la página con el alto correcto
526 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...
527
            $this->deletePage($this->PageNo());
528
            $this->agregarContinuo57($dte, $timbre, $width, $this->getY()+30);
529
        }
530
    }
531
532
    /**
533
     * Método que agrega los datos de la empresa
534
     * Orden de los datos:
535
     *  - Razón social del emisor
536
     *  - Giro del emisor (sin abreviar)
537
     *  - Dirección casa central del emisor
538
     *  - Dirección sucursales
539
     * @param emisor Arreglo con los datos del emisor (tag Emisor del XML)
540
     * @param x Posición horizontal de inicio en el PDF
541
     * @param y Posición vertical de inicio en el PDF
542
     * @param w Ancho de la información del emisor
543
     * @param w_img Ancho máximo de la imagen
544
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
545
     * @version 2018-06-15
546
     */
547
    protected function agregarEmisor(array $emisor, $x = 10, $y = 15, $w = 75, $w_img = 30, $font_size = null, array $color = null)
548
    {
549
        // logo del documento
550
        if (isset($this->logo)) {
551
            $this->Image(
552
                $this->logo['uri'],
553
                $x,
554
                $y,
555
                !$this->logo['posicion']?$w_img:null, $this->logo['posicion']?($w_img/2):null,
556
                'PNG',
557
                (isset($emisor['url'])?$emisor['url']:''),
558
                'T'
559
            );
560
            if ($this->logo['posicion']) {
561
                $this->SetY($this->y + ($w_img/2));
562
                $w += 40;
563
            } else {
564
                $x = $this->x+3;
565
            }
566
        } else {
567
            $this->y = $y-2;
568
            $w += 40;
569
        }
570
        // agregar datos del emisor
571
        $this->setFont('', 'B', $font_size ? $font_size : 14);
572
        $this->SetTextColorArray($color===null?[32, 92, 144]:$color);
573
        $this->MultiTexto(!empty($emisor['RznSoc']) ? $emisor['RznSoc'] : $emisor['RznSocEmisor'], $x, $this->y+2, 'L', $w);
574
        $this->setFont('', 'B', $font_size ? $font_size : 9);
575
        $this->SetTextColorArray([0,0,0]);
576
        $this->MultiTexto(!empty($emisor['GiroEmis']) ? $emisor['GiroEmis'] : $emisor['GiroEmisor'], $x, $this->y, 'L', $w);
577
        $comuna = !empty($emisor['CmnaOrigen']) ? $emisor['CmnaOrigen'] : null;
578
        $ciudad = !empty($emisor['CiudadOrigen']) ? $emisor['CiudadOrigen'] : \sasco\LibreDTE\Chile::getCiudad($comuna);
579
        $this->MultiTexto($emisor['DirOrigen'].($comuna?(', '.$comuna):'').($ciudad?(', '.$ciudad):''), $x, $this->y, 'L', $w);
580
        if (!empty($emisor['Sucursal'])) {
581
            $this->MultiTexto('Sucursal: '.$emisor['Sucursal'], $x, $this->y, 'L', $w);
582
        }
583
        if (!empty($this->casa_matriz)) {
584
            $this->MultiTexto('Casa matriz: '.$this->casa_matriz, $x, $this->y, 'L', $w);
585
        }
586
        $contacto = [];
587
        if (!empty($emisor['Telefono'])) {
588
            if (!is_array($emisor['Telefono']))
589
                $emisor['Telefono'] = [$emisor['Telefono']];
590
            foreach ($emisor['Telefono'] as $t)
591
                $contacto[] = $t;
592
        }
593
        if (!empty($emisor['CorreoEmisor'])) {
594
            $contacto[] = $emisor['CorreoEmisor'];
595
        }
596
        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...
597
            $this->MultiTexto(implode(' / ', $contacto), $x, $this->y, 'L', $w);
598
        }
599
        return $this->y;
600
    }
601
602
    /**
603
     * Método que agrega el recuadro con el folio
604
     * Recuadro:
605
     *  - Tamaño mínimo 1.5x5.5 cms
606
     *  - En lado derecho (negro o rojo)
607
     *  - Enmarcado por una línea de entre 0.5 y 1 mm de espesor
608
     *  - Tamaño máximo 4x8 cms
609
     *  - Letras tamaño 10 o superior en mayúsculas y negritas
610
     *  - Datos del recuadro: RUT emisor, nombre de documento en 2 líneas,
611
     *    folio.
612
     *  - Bajo el recuadro indicar la Dirección regional o Unidad del SII a la
613
     *    que pertenece el emisor
614
     * @param rut RUT del emisor
615
     * @param tipo Código o glosa del tipo de documento
616
     * @param sucursal_sii Código o glosa de la sucursal del SII del Emisor
617
     * @param x Posición horizontal de inicio en el PDF
618
     * @param y Posición vertical de inicio en el PDF
619
     * @param w Ancho de la información del emisor
620
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
621
     * @version 2016-12-02
622
     */
623
    protected function agregarFolio($rut, $tipo, $folio, $sucursal_sii = null, $x = 130, $y = 15, $w = 70, $font_size = null, array $color = null)
624
    {
625
        if ($color===null) {
626
            $color = $tipo ? ($tipo==52 ? [0,172,140] : [255,0,0]) : [0,0,0];
627
        }
628
        $this->SetTextColorArray($color);
629
        // colocar rut emisor, glosa documento y folio
630
        list($rut, $dv) = explode('-', $rut);
631
        $this->setFont ('', 'B', $font_size ? $font_size : 15);
632
        $this->MultiTexto('R.U.T.: '.$this->num($rut).'-'.$dv, $x, $y+4, 'C', $w);
633
        $this->setFont('', 'B', $font_size ? $font_size : 12);
634
        $this->MultiTexto($this->getTipo($tipo), $x, null, 'C', $w);
635
        $this->setFont('', 'B', $font_size ? $font_size : 15);
636
        $this->MultiTexto('N° '.$folio, $x, null, 'C', $w);
637
        // dibujar rectángulo rojo
638
        $this->Rect($x, $y, $w, round($this->getY()-$y+3), 'D', ['all' => ['width' => 0.5, 'color' => $color]]);
639
        // colocar unidad del SII
640
        $this->setFont('', 'B', $font_size ? $font_size : 10);
641
        if ($tipo) {
642
            $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 623 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...
643
        }
644
        $this->SetTextColorArray([0,0,0]);
645
        $this->Ln();
646
        return $this->y;
647
    }
648
649
    /**
650
     * Método que entrega la glosa del tipo de documento
651
     * @param tipo Código del tipo de documento
652
     * @return Glosa del tipo de documento
653
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
654
     * @version 2016-11-18
655
     */
656
    private function getTipo($tipo)
657
    {
658
        if (!is_numeric($tipo) and !isset($this->tipos[$tipo])) {
659
            return $tipo;
660
        }
661
        return isset($this->tipos[$tipo]) ? strtoupper($this->tipos[$tipo]) : 'Documento '.$tipo;
662
    }
663
664
    /**
665
     * Método que agrega los datos de la emisión del DTE que no son los dato del
666
     * receptor
667
     * @param IdDoc Información general del documento
668
     * @param x Posición horizontal de inicio en el PDF
669
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
670
     * @version 2017-06-15
671
     */
672
    protected function agregarDatosEmision($IdDoc, $CdgVendedor, $x = 10, $offset = 22, $mostrar_dia = true)
673
    {
674
        // si es hoja carta
675
        if ($x==10) {
676
            $y = $this->GetY();
677
            // fecha emisión
678
            $this->setFont('', 'B', null);
679
            $this->MultiTexto($this->date($IdDoc['FchEmis'], $mostrar_dia), $x, null, 'R');
680
            $this->setFont('', '', null);
681
            // período facturación
682
            if (!empty($IdDoc['PeriodoDesde']) and !empty($IdDoc['PeriodoHasta'])) {
683
                $this->MultiTexto('Período del '.date('d/m/y', strtotime($IdDoc['PeriodoDesde'])).' al '.date('d/m/y', strtotime($IdDoc['PeriodoHasta'])), $x, null, 'R');
684
            }
685
            // pago anticicado
686 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...
687
                $this->MultiTexto('Pagado el '.$this->date($IdDoc['FchCancel'], false), $x, null, 'R');
688
            }
689
            // fecha vencimiento
690 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...
691
                $this->MultiTexto('Vence el '.$this->date($IdDoc['FchVenc'], false), $x, null, 'R');
692
            }
693
            // forma de pago nacional
694 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...
695
                $this->MultiTexto('Venta: '.strtolower($this->formas_pago[$IdDoc['FmaPago']]), $x, null, 'R');
696
            }
697
            // forma de pago exportación
698 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...
699
                $this->MultiTexto('Venta: '.strtolower($this->formas_pago_exportacion[$IdDoc['FmaPagExp']]), $x, null, 'R');
700
            }
701
            // vendedor
702
            if (!empty($CdgVendedor)) {
703
                $this->MultiTexto('Vendedor: '.$CdgVendedor, $x, null, 'R');
704
            }
705
            $y_end = $this->GetY();
706
            $this->SetY($y);
707
        }
708
        // papel contínuo
709
        else {
710
            // fecha de emisión
711
            $this->setFont('', 'B', null);
712
            $this->Texto('Emisión', $x);
713
            $this->Texto(':', $x+$offset);
714
            $this->setFont('', '', null);
715
            $this->MultiTexto($this->date($IdDoc['FchEmis'], $mostrar_dia), $x+$offset+2);
716
            // forma de pago nacional
717
            if (!empty($IdDoc['FmaPago'])) {
718
                $this->setFont('', 'B', null);
719
                $this->Texto('Venta', $x);
720
                $this->Texto(':', $x+$offset);
721
                $this->setFont('', '', null);
722
                $this->MultiTexto($this->formas_pago[$IdDoc['FmaPago']], $x+$offset+2);
723
            }
724
            // forma de pago exportación
725
            if (!empty($IdDoc['FmaPagExp'])) {
726
                $this->setFont('', 'B', null);
727
                $this->Texto('Venta', $x);
728
                $this->Texto(':', $x+$offset);
729
                $this->setFont('', '', null);
730
                $this->MultiTexto($this->formas_pago_exportacion[$IdDoc['FmaPagExp']], $x+$offset+2);
731
            }
732
            // pago anticicado
733
            if (!empty($IdDoc['FchCancel'])) {
734
                $this->setFont('', 'B', null);
735
                $this->Texto('Pagado el', $x);
736
                $this->Texto(':', $x+$offset);
737
                $this->setFont('', '', null);
738
                $this->MultiTexto($this->date($IdDoc['FchCancel'], $mostrar_dia), $x+$offset+2);
739
            }
740
            // fecha vencimiento
741
            if (!empty($IdDoc['FchVenc'])) {
742
                $this->setFont('', 'B', null);
743
                $this->Texto('Vence el', $x);
744
                $this->Texto(':', $x+$offset);
745
                $this->setFont('', '', null);
746
                $this->MultiTexto($this->date($IdDoc['FchVenc'], $mostrar_dia), $x+$offset+2);
747
            }
748
            $y_end = $this->GetY();
749
        }
750
        return $y_end;
751
    }
752
753
    /**
754
     * Método que agrega los datos del receptor
755
     * @param receptor Arreglo con los datos del receptor (tag Receptor del XML)
756
     * @param x Posición horizontal de inicio en el PDF
757
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
758
     * @version 2017-06-15
759
     */
760
    protected function agregarReceptor(array $Encabezado, $x = 10, $offset = 22)
761
    {
762
        $receptor = $Encabezado['Receptor'];
763 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...
764
            list($rut, $dv) = explode('-', $receptor['RUTRecep']);
765
            $this->setFont('', 'B', null);
766
            $this->Texto('R.U.T.', $x);
767
            $this->Texto(':', $x+$offset);
768
            $this->setFont('', '', null);
769
            $this->MultiTexto($this->num($rut).'-'.$dv, $x+$offset+2);
770
        }
771 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...
772
            $this->setFont('', 'B', null);
773
            $this->Texto('Señor(es)', $x);
774
            $this->Texto(':', $x+$offset);
775
            $this->setFont('', '', null);
776
            $this->MultiTexto($receptor['RznSocRecep'], $x+$offset+2, null, '', $x==10?105:0);
777
        }
778 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...
779
            $this->setFont('', 'B', null);
780
            $this->Texto('Giro', $x);
781
            $this->Texto(':', $x+$offset);
782
            $this->setFont('', '', null);
783
            $this->MultiTexto($receptor['GiroRecep'], $x+$offset+2);
784
        }
785
        if (!empty($receptor['DirRecep'])) {
786
            $this->setFont('', 'B', null);
787
            $this->Texto('Dirección', $x);
788
            $this->Texto(':', $x+$offset);
789
            $this->setFont('', '', null);
790
            $ciudad = !empty($receptor['CiudadRecep']) ? $receptor['CiudadRecep'] : (
791
                !empty($receptor['CmnaRecep']) ? \sasco\LibreDTE\Chile::getCiudad($receptor['CmnaRecep']) : ''
792
            );
793
            $this->MultiTexto($receptor['DirRecep'].(!empty($receptor['CmnaRecep'])?(', '.$receptor['CmnaRecep']):'').($ciudad?(', '.$ciudad):''), $x+$offset+2);
794
        }
795
        if (!empty($receptor['Extranjero']['Nacionalidad'])) {
796
            $this->setFont('', 'B', null);
797
            $this->Texto('Nacionalidad', $x);
798
            $this->Texto(':', $x+$offset);
799
            $this->setFont('', '', null);
800
            $this->MultiTexto(\sasco\LibreDTE\Sii\Aduana::getNacionalidad($receptor['Extranjero']['Nacionalidad']), $x+$offset+2);
801
        }
802
        if (!empty($receptor['Extranjero']['NumId'])) {
803
            $this->setFont('', 'B', null);
804
            $this->Texto('N° ID extranj.', $x);
805
            $this->Texto(':', $x+$offset);
806
            $this->setFont('', '', null);
807
            $this->MultiTexto($receptor['Extranjero']['NumId'], $x+$offset+2);
808
        }
809
        $contacto = [];
810
        if (!empty($receptor['Contacto']))
811
            $contacto[] = $receptor['Contacto'];
812
        if (!empty($receptor['CorreoRecep']))
813
            $contacto[] = $receptor['CorreoRecep'];
814 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...
815
            $this->setFont('', 'B', null);
816
            $this->Texto('Contacto', $x);
817
            $this->Texto(':', $x+$offset);
818
            $this->setFont('', '', null);
819
            $this->MultiTexto(implode(' / ', $contacto), $x+$offset+2);
820
        }
821 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...
822
            list($rut, $dv) = explode('-', $Encabezado['RUTSolicita']);
823
            $this->setFont('', 'B', null);
824
            $this->Texto('RUT solicita', $x);
825
            $this->Texto(':', $x+$offset);
826
            $this->setFont('', '', null);
827
            $this->MultiTexto($this->num($rut).'-'.$dv, $x+$offset+2);
828
        }
829 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...
830
            $this->setFont('', 'B', null);
831
            $this->Texto('Cód. recep.', $x);
832
            $this->Texto(':', $x+$offset);
833
            $this->setFont('', '', null);
834
            $this->MultiTexto($receptor['CdgIntRecep'], $x+$offset+2, null, '', $x==10?105:0);
835
        }
836
        return $this->GetY();
837
    }
838
839
    /**
840
     * Método que agrega los datos del traslado
841
     * @param IndTraslado
842
     * @param Transporte
843
     * @param x Posición horizontal de inicio en el PDF
844
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
845
     * @version 2016-08-03
846
     */
847
    protected function agregarTraslado($IndTraslado, array $Transporte = null, $x = 10, $offset = 22)
848
    {
849
        // agregar tipo de traslado
850 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...
851
            $this->setFont('', 'B', null);
852
            $this->Texto('Tipo oper.', $x);
853
            $this->Texto(':', $x+$offset);
854
            $this->setFont('', '', null);
855
            $this->MultiTexto($this->traslados[$IndTraslado], $x+$offset+2);
856
        }
857
        // agregar información de transporte
858
        if ($Transporte) {
859
            $transporte = '';
860
            if (!empty($Transporte['DirDest']) and !empty($Transporte['CmnaDest'])) {
861
                $transporte .= 'a '.$Transporte['DirDest'].', '.$Transporte['CmnaDest'];
862
            }
863
            if (!empty($Transporte['RUTTrans']))
864
                $transporte .= ' por '.$Transporte['RUTTrans'];
865
            if (!empty($Transporte['Patente']))
866
                $transporte .= ' en vehículo '.$Transporte['Patente'];
867
            if (isset($Transporte['Chofer']) and is_array($Transporte['Chofer'])) {
868 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...
869
                    $transporte .= ' con chofer '.$Transporte['Chofer']['NombreChofer'];
870 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...
871
                    $transporte .= ' ('.$Transporte['Chofer']['RUTChofer'].')';
872
            }
873 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...
874
                $this->setFont('', 'B', null);
875
                $this->Texto('Traslado', $x);
876
                $this->Texto(':', $x+$offset);
877
                $this->setFont('', '', null);
878
                $this->MultiTexto(ucfirst(trim($transporte)), $x+$offset+2);
879
            }
880
        }
881
        // agregar información de aduana
882
        if (!empty($Transporte['Aduana']) and is_array($Transporte['Aduana'])) {
883
            $col = 0;
884
            foreach ($Transporte['Aduana'] as $tag => $codigo) {
885
                if ($codigo===false)
886
                    continue;
887
                $glosa = \sasco\LibreDTE\Sii\Aduana::getGlosa($tag);
888
                $valor = \sasco\LibreDTE\Sii\Aduana::getValor($tag, $codigo);
889
                if ($glosa!==false and $valor!==false) {
890
                    if ($tag=='TipoBultos' and $col) {
891
                        $col = abs($col-110);
892
                        $this->Ln();
893
                    }
894
                    $this->setFont('', 'B', null);
895
                    $this->Texto($glosa, $x+$col);
896
                    $this->Texto(':', $x+$offset+$col);
897
                    $this->setFont('', '', null);
898
                    $this->Texto($valor, $x+$offset+2+$col);
899
                    if ($tag=='TipoBultos')
900
                        $col = abs($col-110);
901
                    if ($col)
902
                        $this->Ln();
903
                    $col = abs($col-110);
904
                }
905
            }
906
            if ($col)
907
                $this->Ln();
908
        }
909
    }
910
911
    /**
912
     * Método que agrega las referencias del documento
913
     * @param referencias Arreglo con las referencias del documento (tag Referencia del XML)
914
     * @param x Posición horizontal de inicio en el PDF
915
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
916
     * @version 2017-09-25
917
     */
918
    protected function agregarReferencia($referencias, $x = 10, $offset = 22)
919
    {
920
        if (!isset($referencias[0]))
921
            $referencias = [$referencias];
922
        foreach($referencias as $r) {
923
            $texto = $r['NroLinRef'].' - ';
924
            if (!empty($r['TpoDocRef'])) {
925
                $texto .= $this->getTipo($r['TpoDocRef']).' ';
926
            }
927
            if (!empty($r['FolioRef'])) {
928
                if (is_numeric($r['FolioRef'])) {
929
                    $texto .= ' N° '.$r['FolioRef'].' ';
930
                } else {
931
                    $texto .= ' '.$r['FolioRef'].' ';
932
                }
933
            }
934
            if (!empty($r['FchRef'])) {
935
                $texto .= 'del '.date('d/m/Y', strtotime($r['FchRef']));
936
            }
937
            if (isset($r['RazonRef']) and $r['RazonRef']!==false) {
938
                $texto = $texto.': '.$r['RazonRef'];
939
            }
940
            $this->setFont('', 'B', null);
941
            $this->Texto('Referencia', $x);
942
            $this->Texto(':', $x+$offset);
943
            $this->setFont('', '', null);
944
            $this->MultiTexto($texto, $x+$offset+2);
945
        }
946
    }
947
948
    /**
949
     * Método que agrega el detalle del documento
950
     * @param detalle Arreglo con el detalle del documento (tag Detalle del XML)
951
     * @param x Posición horizontal de inicio en el PDF
952
     * @param y Posición vertical de inicio en el PDF
953
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
954
     * @version 2018-04-15
955
     */
956
    protected function agregarDetalle($detalle, $x = 10, $html = true)
957
    {
958
        if (!isset($detalle[0]))
959
            $detalle = [$detalle];
960
        $this->setFont('', '', $this->detalle_fuente);
961
        // titulos
962
        $titulos = [];
963
        $titulos_keys = array_keys($this->detalle_cols);
964
        foreach ($this->detalle_cols as $key => $info) {
965
            $titulos[$key] = $info['title'];
966
        }
967
        // normalizar cada detalle
968
        $dte_exento = in_array($this->dte, [34, 110, 111, 112]);
969
        foreach ($detalle as &$item) {
970
            // quitar columnas
971
            foreach ($item as $col => $valor) {
972
                if ($col=='DscItem' and !empty($item['DscItem'])) {
973
                    $item['NmbItem'] .= !$this->item_detalle_posicion ? ($html?'<br/>':"\n") : ': ';
974
                    if ($html) {
975
                        $item['NmbItem'] .= '<span style="font-size:0.7em">'.$item['DscItem'].'</span>';
976
                    } else {
977
                        $item['NmbItem'] .= $item['DscItem'];
978
                    }
979
                }
980
                if (!in_array($col, $titulos_keys) or ($dte_exento and $col=='IndExe'))
981
                    unset($item[$col]);
982
            }
983
            // ajustes a IndExe
984
            if (isset($item['IndExe'])) {
985
                if ($item['IndExe']==1)
986
                    $item['IndExe'] = 'EX';
987
                else if ($item['IndExe']==2)
988
                    $item['IndExe'] = 'NF';
989
            }
990
            // agregar todas las columnas que se podrían imprimir en la tabla
991
            $item_default = [];
992
            foreach ($this->detalle_cols as $key => $info)
993
                $item_default[$key] = false;
994
            $item = array_merge($item_default, $item);
995
            // si hay código de item se extrae su valor
996
            if ($item['CdgItem'])
997
                $item['CdgItem'] = $item['CdgItem']['VlrCodigo'];
998
            // dar formato a números
999
            foreach (['QtyItem', 'PrcItem', 'DescuentoMonto', 'RecargoMonto', 'MontoItem'] as $col) {
1000
                if ($item[$col])
1001
                    $item[$col] = $this->num($item[$col]);
1002
            }
1003
        }
1004
        // opciones
1005
        $options = ['align'=>[]];
1006
        $i = 0;
1007
        foreach ($this->detalle_cols as $info) {
1008
            if (isset($info['width']))
1009
                $options['width'][$i] = $info['width'];
1010
            $options['align'][$i] = $info['align'];
1011
            $i++;
1012
        }
1013
        // agregar tabla de detalle
1014
        $this->Ln();
1015
        $this->SetX($x);
1016
        $this->addTableWithoutEmptyCols($titulos, $detalle, $options);
1017
    }
1018
1019
    /**
1020
     * Método que agrega el detalle del documento
1021
     * @param detalle Arreglo con el detalle del documento (tag Detalle del XML)
1022
     * @param x Posición horizontal de inicio en el PDF
1023
     * @param y Posición vertical de inicio en el PDF
1024
     * @author Pablo Reyes (https://github.com/pabloxp)
1025
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1026
     * @version 2016-12-13
1027
     */
1028
    protected function agregarDetalleContinuo($detalle, $x = 3)
1029
    {
1030
        $this->SetY($this->getY()+1);
1031
        $p1x = $x;
1032
        $p1y = $this->y;
1033
        $p2x = $this->getPageWidth() - 2;
1034
        $p2y = $p1y;  // Use same y for a straight line
1035
        $style = array('width' => 0.2,'color' => array(0, 0, 0));
1036
        $this->Line($p1x, $p1y, $p2x, $p2y, $style);
1037
        $this->Texto($this->detalle_cols['NmbItem']['title'], $x+1, $this->y, ucfirst($this->detalle_cols['NmbItem']['align'][0]), $this->detalle_cols['NmbItem']['width']);
1038
        $this->Texto($this->detalle_cols['PrcItem']['title'], $x+15, $this->y, ucfirst($this->detalle_cols['PrcItem']['align'][0]), $this->detalle_cols['PrcItem']['width']);
1039
        $this->Texto($this->detalle_cols['QtyItem']['title'], $x+35, $this->y, ucfirst($this->detalle_cols['QtyItem']['align'][0]), $this->detalle_cols['QtyItem']['width']);
1040
        $this->Texto($this->detalle_cols['MontoItem']['title'], $x+45, $this->y, ucfirst($this->detalle_cols['MontoItem']['align'][0]), $this->detalle_cols['MontoItem']['width']);
1041
        $this->Line($p1x, $p1y+4, $p2x, $p2y+4, $style);
1042
        if (!isset($detalle[0]))
1043
            $detalle = [$detalle];
1044
        $this->SetY($this->getY()+2);
1045
        foreach($detalle as  &$d) {
1046
            $this->MultiTexto($d['NmbItem'], $x+1, $this->y+4, ucfirst($this->detalle_cols['NmbItem']['align'][0]), $this->detalle_cols['NmbItem']['width']);
1047
            $this->Texto(number_format($d['PrcItem'],0,',','.'), $x+15, $this->y, ucfirst($this->detalle_cols['PrcItem']['align'][0]), $this->detalle_cols['PrcItem']['width']);
1048
            $this->Texto($this->num($d['QtyItem']), $x+35, $this->y, ucfirst($this->detalle_cols['QtyItem']['align'][0]), $this->detalle_cols['QtyItem']['width']);
1049
            $this->Texto($this->num($d['MontoItem']), $x+45, $this->y, ucfirst($this->detalle_cols['MontoItem']['align'][0]), $this->detalle_cols['MontoItem']['width']);
1050
        }
1051
        $this->Line($p1x, $this->y+4, $p2x, $this->y+4, $style);
1052
    }
1053
1054
    /**
1055
     * Método que agrega el subtotal del DTE
1056
     * @param detalle Arreglo con los detalles del documentos para poder
1057
     * calcular subtotal
1058
     * @param x Posición horizontal de inicio en el PDF
1059
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1060
     * @version 2016-08-17
1061
     */
1062
    protected function agregarSubTotal(array $detalle, $x = 10) {
1063
        $subtotal = 0;
1064
        if (!isset($detalle[0])) {
1065
            $detalle = [$detalle];
1066
        }
1067
        foreach($detalle as  &$d) {
1068
            if (!empty($d['MontoItem'])) {
1069
                $subtotal += $d['MontoItem'];
1070
            }
1071
        }
1072
        if ($this->papelContinuo) {
1073
            $this->Texto('Subtotal: '.$this->num($subtotal), $x);
1074
        } else {
1075
            $this->Texto('Subtotal:', 77, null, 'R', 100);
1076
            $this->Texto($this->num($subtotal), 177, null, 'R', 22);
1077
        }
1078
        $this->Ln();
1079
    }
1080
1081
    /**
1082
     * Método que agrega los descuentos y/o recargos globales del documento
1083
     * @param descuentosRecargos Arreglo con los descuentos y/o recargos del documento (tag DscRcgGlobal del XML)
1084
     * @param x Posición horizontal de inicio en el PDF
1085
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1086
     * @version 2018-05-29
1087
     */
1088
    protected function agregarDescuentosRecargos(array $descuentosRecargos, $x = 10)
1089
    {
1090
        if (!isset($descuentosRecargos[0])) {
1091
            $descuentosRecargos = [$descuentosRecargos];
1092
        }
1093
        foreach($descuentosRecargos as $dr) {
1094
            $tipo = $dr['TpoMov']=='D' ? 'Descuento' : 'Recargo';
1095
            if (!empty($dr['IndExeDR'])) {
1096
                $tipo .= ' EX';
1097
            }
1098
            $valor = $dr['TpoValor']=='%' ? $dr['ValorDR'].'%' : $this->num($dr['ValorDR']);
1099
            if ($this->papelContinuo) {
1100
                $this->Texto($tipo.' global: '.$valor.(!empty($dr['GlosaDR'])?(' ('.$dr['GlosaDR'].')'):''), $x);
1101
            } else {
1102
                $this->Texto($tipo.(!empty($dr['GlosaDR'])?(' ('.$dr['GlosaDR'].')'):'').':', 77, null, 'R', 100);
1103
                $this->Texto($valor, 177, null, 'R', 22);
1104
            }
1105
            $this->Ln();
1106
        }
1107
    }
1108
1109
    /**
1110
     * Método que agrega los pagos del documento
1111
     * @param pagos Arreglo con los pagos del documento
1112
     * @param x Posición horizontal de inicio en el PDF
1113
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1114
     * @version 2016-07-24
1115
     */
1116
    protected function agregarPagos(array $pagos, $x = 10)
1117
    {
1118
        if (!isset($pagos[0]))
1119
            $pagos = [$pagos];
1120
        $this->Texto('Pago(s) programado(s):', $x);
1121
        $this->Ln();
1122
        foreach($pagos as $p) {
1123
            $this->Texto('  - '.$this->date($p['FchPago'], false).': $'.$this->num($p['MntPago']).'.-'.(!empty($p['GlosaPagos'])?(' ('.$p['GlosaPagos'].')'):''), $x);
1124
            $this->Ln();
1125
        }
1126
    }
1127
1128
    /**
1129
     * Método que agrega los totales del documento
1130
     * @param totales Arreglo con los totales (tag Totales del XML)
1131
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1132
     * @version 2017-10-05
1133
     */
1134
    protected function agregarTotales(array $totales, $otra_moneda, $y = 190, $x = 145, $offset = 25)
1135
    {
1136
        $y = (!$this->papelContinuo and !$this->timbre_pie) ? $this->x_fin_datos : $y;
1137
        // normalizar totales
1138
        $totales = array_merge([
1139
            'TpoMoneda' => false,
1140
            'MntNeto' => false,
1141
            'MntExe' => false,
1142
            'TasaIVA' => false,
1143
            'IVA' => false,
1144
            'IVANoRet' => false,
1145
            'CredEC' => false,
1146
            'MntTotal' => false,
1147
            'MontoNF' => false,
1148
            'MontoPeriodo' => false,
1149
            'SaldoAnterior' => false,
1150
            'VlrPagar' => false,
1151
        ], $totales);
1152
        // glosas
1153
        $glosas = [
1154
            'TpoMoneda' => 'Moneda',
1155
            'MntNeto' => 'Neto $',
1156
            'MntExe' => 'Exento $',
1157
            'IVA' => 'IVA ('.$totales['TasaIVA'].'%) $',
1158
            'IVANoRet' => 'IVA no retenido $',
1159
            'CredEC' => 'Desc. 65% IVA $',
1160
            'MntTotal' => 'Total $',
1161
            'MontoNF' => 'Monto no facturable $',
1162
            'MontoPeriodo' => 'Monto período $',
1163
            'SaldoAnterior' => 'Saldo anterior $',
1164
            'VlrPagar' => 'Valor a pagar $',
1165
        ];
1166
        // agregar impuestos adicionales y retenciones
1167
        if (!empty($totales['ImptoReten'])) {
1168
            $ImptoReten = $totales['ImptoReten'];
1169
            $MntTotal = $totales['MntTotal'];
1170
            unset($totales['ImptoReten'], $totales['MntTotal']);
1171
            if (!isset($ImptoReten[0])) {
1172
                $ImptoReten = [$ImptoReten];
1173
            }
1174
            foreach($ImptoReten as $i) {
1175
                $totales['ImptoReten_'.$i['TipoImp']] = $i['MontoImp'];
1176
                if (!empty($i['TasaImp'])) {
1177
                    $glosas['ImptoReten_'.$i['TipoImp']] = \sasco\LibreDTE\Sii\ImpuestosAdicionales::getGlosa($i['TipoImp']).' ('.$i['TasaImp'].'%) $';
1178
                } else {
1179
                    $glosas['ImptoReten_'.$i['TipoImp']] = \sasco\LibreDTE\Sii\ImpuestosAdicionales::getGlosa($i['TipoImp']).' $';
1180
                }
1181
            }
1182
            $totales['MntTotal'] = $MntTotal;
1183
        }
1184
        // agregar cada uno de los totales
1185
        $this->setY($y);
1186
        $this->setFont('', 'B', null);
1187
        foreach ($totales as $key => $total) {
1188
            if ($total!==false and isset($glosas[$key])) {
1189
                $y = $this->GetY();
1190
                if (!$this->cedible or $this->papelContinuo) {
1191
                    $this->Texto($glosas[$key].' :', $x, null, 'R', 30);
1192
                    $this->Texto($this->num($total), $x+$offset, $y, 'R', 30);
1193
                    $this->Ln();
1194
                } else {
1195
                    $this->MultiTexto($glosas[$key].' :', $x, null, 'R', 30);
1196
                    $y_new = $this->GetY();
1197
                    $this->Texto($this->num($total), $x+$offset, $y, 'R', 30);
1198
                    $this->SetY($y_new);
1199
                }
1200
            }
1201
        }
1202
        // agregar totales en otra moneda
1203
        if (!empty($otra_moneda)) {
1204
            if (!isset($otra_moneda[0])) {
1205
                $otra_moneda = [$otra_moneda];
1206
            }
1207
            $this->setFont('', '', null);
1208
            $this->Ln();
1209
            foreach ($otra_moneda as $om) {
1210
                $y = $this->GetY();
1211
                if (!$this->cedible or $this->papelContinuo) {
1212
                    $this->Texto('Total '.$om['TpoMoneda'].' :', $x, null, 'R', 30);
1213
                    $this->Texto($this->num($om['MntTotOtrMnda']), $x+$offset, $y, 'R', 30);
1214
                    $this->Ln();
1215
                } else {
1216
                    $this->MultiTexto('Total '.$om['TpoMoneda'].' :', $x, null, 'R', 30);
1217
                    $y_new = $this->GetY();
1218
                    $this->Texto($this->num($om['MntTotOtrMnda']), $x+$offset, $y, 'R', 30);
1219
                    $this->SetY($y_new);
1220
                }
1221
            }
1222
            $this->setFont('', 'B', null);
1223
        }
1224
    }
1225
1226
    /**
1227
     * Método que coloca las diferentes observaciones que puede tener el documnto
1228
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1229
     * @version 2018-06-15
1230
     */
1231
    protected function agregarObservacion($IdDoc, $x = 10, $y = 190)
1232
    {
1233
        $y = (!$this->papelContinuo and !$this->timbre_pie) ? $this->x_fin_datos : $y;
1234
        if (!$this->papelContinuo and $this->timbre_pie) {
1235
            $y -= 15;
1236
        }
1237
        $this->SetXY($x, $y);
1238
        if (!empty($IdDoc['TermPagoGlosa'])) {
1239
            $this->MultiTexto('Observación: '.$IdDoc['TermPagoGlosa']);
1240
        }
1241
        if (!empty($IdDoc['MedioPago']) or !empty($IdDoc['TermPagoDias'])) {
1242
            $pago = [];
1243
            if (!empty($IdDoc['MedioPago'])) {
1244
                $medio = 'Medio de pago: '.(!empty($this->medios_pago[$IdDoc['MedioPago']]) ? $this->medios_pago[$IdDoc['MedioPago']] : $IdDoc['MedioPago']);
1245
                if (!empty($IdDoc['BcoPago'])) {
1246
                    $medio .= ' a '.$IdDoc['BcoPago'];
1247
                }
1248
                if (!empty($IdDoc['TpoCtaPago'])) {
1249
                    $medio .= ' en cuenta '.strtolower($IdDoc['TpoCtaPago']);
1250
                }
1251
                if (!empty($IdDoc['NumCtaPago'])) {
1252
                    $medio .= ' N° '.$IdDoc['NumCtaPago'];
1253
                }
1254
                $pago[] = $medio;
1255
            }
1256
            if (!empty($IdDoc['TermPagoDias'])) {
1257
                $pago[] = 'Días de pago: '.$IdDoc['TermPagoDias'];
1258
            }
1259
            $this->SetXY($x, $this->GetY());
1260
            $this->MultiTexto(implode(' / ', $pago));
1261
        }
1262
        return $this->GetY();
1263
    }
1264
1265
    /**
1266
     * Método que agrega el timbre de la factura
1267
     *  - Se imprime en el tamaño mínimo: 2x5 cms
1268
     *  - En el lado de abajo con margen izquierdo mínimo de 2 cms
1269
     * @param timbre String con los datos del timbre
1270
     * @param x Posición horizontal de inicio en el PDF
1271
     * @param y Posición vertical de inicio en el PDF
1272
     * @param w Ancho del timbre
1273
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1274
     * @version 2018-04-12
1275
     */
1276
    protected function agregarTimbre($timbre, $x_timbre = 10, $x = 10, $y = 190, $w = 70, $font_size = 8)
1277
    {
1278
        $y = (!$this->papelContinuo and !$this->timbre_pie) ? $this->x_fin_datos : $y;
1279
        if ($timbre!==null) {
1280
            $style = [
1281
                'border' => false,
1282
                'padding' => 0,
1283
                'hpadding' => 0,
1284
                'vpadding' => 0,
1285
                'module_width' => 1, // width of a single module in points
1286
                'module_height' => 1, // height of a single module in points
1287
                'fgcolor' => [0,0,0],
1288
                'bgcolor' => false, // [255,255,255]
1289
                'position' => $this->papelContinuo ? 'C' : 'S',
1290
            ];
1291
            $ecl = version_compare(phpversion(), '7.0.0', '<') ? -1 : $this->ecl;
1292
            $this->write2DBarcode($timbre, 'PDF417,,'.$ecl, $x_timbre, $y, $w, 0, $style, 'B');
1293
            $this->setFont('', 'B', $font_size);
1294
            $this->Texto('Timbre Electrónico SII', $x, null, 'C', $w);
1295
            $this->Ln();
1296
            $this->Texto('Resolución '.$this->resolucion['NroResol'].' de '.explode('-', $this->resolucion['FchResol'])[0], $x, null, 'C', $w);
1297
            $this->Ln();
1298
            if ($w>=60) {
1299
                $this->Texto('Verifique documento: '.$this->web_verificacion, $x, null, 'C', $w);
1300
            } else {
1301
                $this->Texto('Verifique documento:', $x, null, 'C', $w);
1302
                $this->Ln();
1303
                $this->Texto($this->web_verificacion, $x, null, 'C', $w);
1304
            }
1305
        }
1306
    }
1307
1308
    /**
1309
     * Método que agrega el acuse de rebido
1310
     * @param x Posición horizontal de inicio en el PDF
1311
     * @param y Posición vertical de inicio en el PDF
1312
     * @param w Ancho del acuse de recibo
1313
     * @param h Alto del acuse de recibo
1314
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1315
     * @version 2018-04-13
1316
     */
1317
    protected function agregarAcuseRecibo($x = 83, $y = 190, $w = 60, $h = 40)
1318
    {
1319
        $y = (!$this->papelContinuo and !$this->timbre_pie) ? $this->x_fin_datos : $y;
1320
        $this->SetTextColorArray([0,0,0]);
1321
        $this->Rect($x, $y, $w, $h, 'D', ['all' => ['width' => 0.1, 'color' => [0, 0, 0]]]);
1322
        $this->setFont('', 'B', 10);
1323
        $this->Texto('Acuse de recibo', $x, $y+1, 'C', $w);
1324
        $this->setFont('', 'B', 8);
1325
        $this->Texto('Nombre', $x+2, $this->y+8);
1326
        $this->Texto('_________________________', $x+18);
1327
        $this->Texto('RUN', $x+2, $this->y+6);
1328
        $this->Texto('_________________________', $x+18);
1329
        $this->Texto('Fecha', $x+2, $this->y+6);
1330
        $this->Texto('_________________________', $x+18);
1331
        $this->Texto('Recinto', $x+2, $this->y+6);
1332
        $this->Texto('_________________________', $x+18);
1333
        $this->Texto('Firma', $x+2, $this->y+8);
1334
        $this->Texto('_________________________', $x+18);
1335
        $this->setFont('', 'B', 7);
1336
        $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);
1337
    }
1338
1339
    /**
1340
     * Método que agrega el acuse de rebido
1341
     * @param x Posición horizontal de inicio en el PDF
1342
     * @param y Posición vertical de inicio en el PDF
1343
     * @param w Ancho del acuse de recibo
1344
     * @param h Alto del acuse de recibo
1345
     * @author Pablo Reyes (https://github.com/pabloxp)
1346
     * @version 2015-11-17
1347
     */
1348
    protected function agregarAcuseReciboContinuo($x = 3, $y = null, $w = 68, $h = 40)
1349
    {
1350
        $this->SetTextColorArray([0,0,0]);
1351
        $this->Rect($x, $y, $w, $h, 'D', ['all' => ['width' => 0.1, 'color' => [0, 0, 0]]]);
1352
        $style = array('width' => 0.2,'color' => array(0, 0, 0));
1353
        $this->Line($x, $y+22, $w+3, $y+22, $style);
1354
        //$this->setFont('', 'B', 10);
1355
        //$this->Texto('Acuse de recibo', $x, $y+1, 'C', $w);
1356
        $this->setFont('', 'B', 6);
1357
        $this->Texto('Nombre', $x+2, $this->y+8);
1358
        $this->Texto('_____________________________________________', $x+12);
1359
        $this->Texto('RUN', $x+2, $this->y+6);
1360
        $this->Texto('________________', $x+12);
1361
        $this->Texto('Firma', $x+32, $this->y+0.5);
1362
        $this->Texto('___________________', $x+42.5);
1363
        $this->Texto('Fecha', $x+2, $this->y+6);
1364
        $this->Texto('________________', $x+12);
1365
        $this->Texto('Recinto', $x+32, $this->y+0.5);
1366
        $this->Texto('___________________', $x+42.5);
1367
1368
        $this->setFont('', 'B', 5);
1369
        $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);
1370
    }
1371
1372
    /**
1373
     * Método que agrega la leyenda de destino
1374
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1375
     * @version 2018-09-10
1376
     */
1377
    protected function agregarLeyendaDestino($tipo, $y = 190, $font_size = 10)
1378
    {
1379
        $y = (!$this->papelContinuo and !$this->timbre_pie and $this->x_fin_datos<=$y) ? $this->x_fin_datos : $y;
1380
        $y += 48;
1381
        $this->setFont('', 'B', $font_size);
1382
        $this->Texto('CEDIBLE'.($tipo==52?' CON SU FACTURA':''), null, $y, 'R');
1383
    }
1384
1385
    /**
1386
     * Método que agrega la leyenda de destino
1387
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1388
     * @version 2017-10-05
1389
     */
1390
    protected function agregarLeyendaDestinoContinuo($tipo)
1391
    {
1392
        $this->setFont('', 'B', 8);
1393
        $this->Texto('CEDIBLE'.($tipo==52?' CON SU FACTURA':''), null, $this->y+6, 'R');
1394
    }
1395
1396
    /**
1397
     * Método que formatea un número con separador de miles y decimales (si
1398
     * corresponden)
1399
     * @param n Número que se desea formatear
1400
     * @return Número formateado
1401
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1402
     * @version 2016-04-05
1403
     */
1404
    protected function num($n)
1405
    {
1406
        if (!is_numeric($n))
1407
            return $n;
1408
        $broken_number = explode('.', (string)$n);
1409
        if (isset($broken_number[1]))
1410
            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...
1411
        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...
1412
    }
1413
1414
    /**
1415
     * Método que formatea una fecha en formato YYYY-MM-DD a un string
1416
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
1417
     * @version 2016-04-28
1418
     */
1419
    protected function date($date, $mostrar_dia = true)
1420
    {
1421
        $dias = ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'];
1422
        $meses = ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'];
1423
        $unixtime = strtotime($date);
1424
        $fecha = date(($mostrar_dia?'\D\I\A ':'').'j \d\e \M\E\S \d\e\l Y', $unixtime);
1425
        $dia = $dias[date('w', $unixtime)];
1426
        $mes = $meses[date('n', $unixtime)-1];
1427
        return str_replace(array('DIA', 'MES'), array($dia, $mes), $fecha);
1428
    }
1429
1430
}
1431