Completed
Push — master ( b75b92...1bcb4b )
by Esteban De La Fuente
01:45
created

Dte::setPapelContinuoItemDetalle()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
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\Dte\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 2020-08-21
31
 */
32
class Dte extends \sasco\LibreDTE\PDF
33
{
34
35
    use \sasco\LibreDTE\Sii\Dte\Base\DteImpreso;
36
37
    protected $logo; ///< Datos del logo que se ubicará en el PDF (ruta, datos y/o posición)
38
    protected $papelContinuo = false; ///< Indica si se usa papel continuo o no (=0 papel carta, otro valor contínuo en PDF)
39
    protected $ecl = 5; ///< error correction level para PHP >= 7.0.0
40
    protected $papel_continuo_alto = 5000; ///< Alto exageradamente grande para autocálculo de alto en papel continuo
41
    protected $timbre_pie = true; ///< Indica si el timbre va al pie o no (va pegado al detalle)
42
    protected $item_detalle_posicion = 0; ///< Posición del detalle del item respecto al nombre
43
    protected $detalle_fuente = 10; ///< Tamaño de la fuente para el detalle en hoja carta
44
    protected $papel_continuo_item_detalle = true; ///< Mostrar detalle en papel continuo
45
46
    protected $detalle_cols = [
47
        'CdgItem' => ['title'=>'Código', 'align'=>'left', 'width'=>20],
48
        'NmbItem' => ['title'=>'Item', 'align'=>'left', 'width'=>0],
49
        'IndExe' => ['title'=>'IE', 'align'=>'left', 'width'=>'7'],
50
        'QtyItem' => ['title'=>'Cant.', 'align'=>'right', 'width'=>15],
51
        'UnmdItem' => ['title'=>'Unidad', 'align'=>'left', 'width'=>22],
52
        'QtyRef' => ['title'=>'Cant. Ref.', 'align'=>'right', 'width'=>22],
53
        'PrcItem' => ['title'=>'P. unitario', 'align'=>'right', 'width'=>22],
54
        'DescuentoMonto' => ['title'=>'Descuento', 'align'=>'right', 'width'=>22],
55
        'RecargoMonto' => ['title'=>'Recargo', 'align'=>'right', 'width'=>22],
56
        'MontoItem' => ['title'=>'Total item', 'align'=>'right', 'width'=>22],
57
    ]; ///< Nombres de columnas detalle, alineación y ancho
58
59
    public static $papel = [
60
        0  => 'Hoja carta',
61
        57 => 'Papel contínuo 57mm',
62
        75 => 'Papel contínuo 75mm',
63
        80 => 'Papel contínuo 80mm',
64
        110 => 'Papel contínuo 110mm',
65
    ]; ///< Tamaño de papel que es soportado
66
67
    /**
68
     * Constructor de la clase
69
     * @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)
70
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
71
     * @version 2016-10-06
72
     */
73
    public function __construct($papelContinuo = false)
74
    {
75
        parent::__construct();
76
        $this->SetTitle('Documento Tributario Electrónico (DTE) de Chile by LibreDTE');
77
        $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...
78
    }
79
80
    /**
81
     * Método que asigna la ubicación del logo de la empresa
82
     * @param logo URI del logo (puede ser local o en una URL)
83
     * @param posicion Posición respecto a datos del emisor (=0 izq, =1 arriba). Nota: parámetro válido sólo para formato hoja carta
84
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
85
     * @version 2016-08-04
86
     */
87
    public function setLogo($logo, $posicion = 0)
88
    {
89
        $this->logo = [
90
            'uri' => $logo,
91
            'posicion' => (int)$posicion,
92
        ];
93
    }
94
95
    /**
96
     * Método que asigna la posición del detalle del Item respecto al nombre
97
     * Nota: método válido sólo para formato hoja carta
98
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
99
     * @version 2016-08-05
100
     */
101
    public function setPosicionDetalleItem($posicion)
102
    {
103
        $this->item_detalle_posicion = (int)$posicion;
104
    }
105
106
    /**
107
     * Método que asigna el tamaño de la fuente para el detalle
108
     * Nota: método válido sólo para formato hoja carta
109
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
110
     * @version 2016-08-03
111
     */
112
    public function setFuenteDetalle($fuente)
113
    {
114
        $this->detalle_fuente = (int)$fuente;
115
    }
116
117
    /**
118
     * Método que asigna el ancho e las columnas del detalle desde un arreglo
119
     * Nota: método válido sólo para formato hoja carta
120
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
121
     * @version 2016-08-03
122
     */
123
    public function setAnchoColumnasDetalle(array $anchos)
124
    {
125
        foreach ($anchos as $col => $ancho) {
126
            if (isset($this->detalle_cols[$col]) and $ancho) {
127
                $this->detalle_cols[$col]['width'] = (int)$ancho;
128
            }
129
        }
130
    }
131
132
    /**
133
     * Método que asigna si el tumbre va al pie (por defecto) o va pegado al detalle
134
     * Nota: método válido sólo para formato hoja carta
135
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
136
     * @version 2017-10-05
137
     */
138
    public function setTimbrePie($timbre_pie = true)
139
    {
140
        $this->timbre_pie = (bool)$timbre_pie;
141
    }
142
143
    /**
144
     * Indica si se debe mostrar o no el detalle en papel continuo
145
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
146
     * @version 2020-08-21
147
     */
148
    public function setPapelContinuoItemDetalle($mostrar = true)
149
    {
150
        $this->papel_continuo_item_detalle = (bool)$mostrar;
151
    }
152
153
    /**
154
     * Método que agrega un documento tributario, ya sea en formato de una
155
     * página o papel contínuo según se haya indicado en el constructor
156
     * @param dte Arreglo con los datos del XML (tag Documento)
157
     * @param timbre String XML con el tag TED del DTE
158
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
159
     * @version 2019-10-06
160
     */
161
    public function agregar(array $dte, $timbre = null)
162
    {
163
        $this->dte = $dte['Encabezado']['IdDoc']['TipoDTE'];
164
        $papel_tipo = (int)$this->papelContinuo;
165
        $method = 'agregar_papel_'.$papel_tipo;
166
        if (!method_exists($this, $method)) {
167
            $tipo = !empty(self::$papel[$papel_tipo]) ? self::$papel[$papel_tipo] : $papel_tipo;
168
            throw new \Exception('Papel de tipo "'.$tipo.'" no está disponible');
169
        }
170
        $this->$method($dte, $timbre);
171
    }
172
173
    /**
174
     * Método que agrega una página con el documento tributario
175
     * @param dte Arreglo con los datos del XML (tag Documento)
176
     * @param timbre String XML con el tag TED del DTE
177
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
178
     * @version 2017-11-07
179
     */
180
    private function agregar_papel_0(array $dte, $timbre)
181
    {
182
        // agregar página para la factura
183
        $this->AddPage();
184
        // agregar cabecera del documento
185
        $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...
186
        $y[] = $this->agregarFolio(
187
            $dte['Encabezado']['Emisor']['RUTEmisor'],
188
            $dte['Encabezado']['IdDoc']['TipoDTE'],
189
            $dte['Encabezado']['IdDoc']['Folio'],
190
            !empty($dte['Encabezado']['Emisor']['CmnaOrigen']) ? $dte['Encabezado']['Emisor']['CmnaOrigen'] : null
191
        );
192
        $this->setY(max($y));
193
        $this->Ln();
194
        // datos del documento
195
        $y = [];
196
        $y[] = $this->agregarDatosEmision($dte['Encabezado']['IdDoc'], !empty($dte['Encabezado']['Emisor']['CdgVendedor'])?$dte['Encabezado']['Emisor']['CdgVendedor']:null);
197
        $y[] = $this->agregarReceptor($dte['Encabezado']);
198
        $this->setY(max($y));
199
        $this->agregarTraslado(
200
            !empty($dte['Encabezado']['IdDoc']['IndTraslado']) ? $dte['Encabezado']['IdDoc']['IndTraslado'] : null,
201
            !empty($dte['Encabezado']['Transporte']) ? $dte['Encabezado']['Transporte'] : null
202
        );
203
        if (!empty($dte['Referencia'])) {
204
            $this->agregarReferencia($dte['Referencia']);
205
        }
206
        $this->agregarDetalle($dte['Detalle']);
207
        if (!empty($dte['DscRcgGlobal'])) {
208
            $this->agregarSubTotal($dte['Detalle']);
209
            $this->agregarDescuentosRecargos($dte['DscRcgGlobal']);
210
        }
211 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...
212
            $this->agregarPagos($dte['Encabezado']['IdDoc']['MntPagos']);
213
        }
214
        // agregar observaciones
215
        $this->x_fin_datos = $this->getY();
216
        $this->agregarObservacion($dte['Encabezado']['IdDoc']);
217
        if (!$this->timbre_pie) {
218
            $this->Ln();
219
        }
220
        $this->x_fin_datos = $this->getY();
221
        $this->agregarTotales($dte['Encabezado']['Totales'], !empty($dte['Encabezado']['OtraMoneda']) ? $dte['Encabezado']['OtraMoneda'] : null);
222
        // agregar timbre
223
        $this->agregarTimbre($timbre);
224
        // agregar acuse de recibo y leyenda cedible
225
        if ($this->cedible and !in_array($dte['Encabezado']['IdDoc']['TipoDTE'], $this->sinAcuseRecibo)) {
226
            $this->agregarAcuseRecibo();
227
            $this->agregarLeyendaDestino($dte['Encabezado']['IdDoc']['TipoDTE']);
228
        }
229
    }
230
231
    /**
232
     * Método que agrega una página con el documento tributario
233
     * @param dte Arreglo con los datos del XML (tag Documento)
234
     * @param timbre String XML con el tag TED del DTE
235
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
236
     * @version 2019-08-05
237
     */
238
    private function agregar_papel_57(array $dte, $timbre, $height = 0)
239
    {
240
        $width = 57;
241
        // determinar alto de la página y agregarla
242
        $this->AddPage('P', [$height ? $height : $this->papel_continuo_alto, $width]);
243
        $x = 1;
244
        $y = 5;
245
        $this->SetXY($x,$y);
246
        // agregar datos del documento
247
        $this->setFont('', '', 8);
248
        $this->MultiTexto(!empty($dte['Encabezado']['Emisor']['RznSoc']) ? $dte['Encabezado']['Emisor']['RznSoc'] : $dte['Encabezado']['Emisor']['RznSocEmisor'], $x, null, '', $width-2);
249
        $this->MultiTexto($dte['Encabezado']['Emisor']['RUTEmisor'], $x, null, '', $width-2);
250
        $this->MultiTexto('Giro: '.(!empty($dte['Encabezado']['Emisor']['GiroEmis']) ? $dte['Encabezado']['Emisor']['GiroEmis'] : $dte['Encabezado']['Emisor']['GiroEmisor']), $x, null, '', $width-2);
251
        $this->MultiTexto($dte['Encabezado']['Emisor']['DirOrigen'].', '.$dte['Encabezado']['Emisor']['CmnaOrigen'], $x, null, '', $width-2);
252
        if (!empty($dte['Encabezado']['Emisor']['Sucursal'])) {
253
            $this->MultiTexto('Sucursal: '.$dte['Encabezado']['Emisor']['Sucursal'], $x, null, '', $width-2);
254
        }
255
        if (!empty($this->casa_matriz)) {
256
            $this->MultiTexto('Casa matriz: '.$this->casa_matriz, $x, null, '', $width-2);
257
        }
258
        $this->MultiTexto($this->getTipo($dte['Encabezado']['IdDoc']['TipoDTE'], $dte['Encabezado']['IdDoc']['Folio']).' N° '.$dte['Encabezado']['IdDoc']['Folio'], $x, null, '', $width-2);
259
        $this->MultiTexto('Fecha: '.date('d/m/Y', strtotime($dte['Encabezado']['IdDoc']['FchEmis'])), $x, null, '', $width-2);
260
        // si no es boleta no nominativa se agregan datos receptor
261
        if ($dte['Encabezado']['Receptor']['RUTRecep']!='66666666-6') {
262
            $this->Ln();
263
            $this->MultiTexto('Receptor: '.$dte['Encabezado']['Receptor']['RUTRecep'], $x, null, '', $width-2);
264
            $this->MultiTexto($dte['Encabezado']['Receptor']['RznSocRecep'], $x, null, '', $width-2);
265
            if (!empty($dte['Encabezado']['Receptor']['GiroRecep'])) {
266
                $this->MultiTexto('Giro: '.$dte['Encabezado']['Receptor']['GiroRecep'], $x, null, '', $width-2);
267
            }
268
            if (!empty($dte['Encabezado']['Receptor']['DirRecep'])) {
269
                $this->MultiTexto($dte['Encabezado']['Receptor']['DirRecep'].', '.$dte['Encabezado']['Receptor']['CmnaRecep'], $x, null, '', $width-2);
270
            }
271
        }
272
        $this->Ln();
273
        // hay un sólo detalle
274
        if (!isset($dte['Detalle'][0])) {
275
            $this->MultiTexto($dte['Detalle']['NmbItem'].': $'.$this->num($dte['Detalle']['MontoItem']), $x, null, '', $width-2);
276
        }
277
        // hay más de un detalle
278
        else {
279
            foreach ($dte['Detalle'] as $d) {
280
                $this->MultiTexto($d['NmbItem'].': $'.$this->num($d['MontoItem']), $x, null, '', $width-2);
281
            }
282
            if (in_array($dte['Encabezado']['IdDoc']['TipoDTE'], [39, 41])) {
283
                $this->MultiTexto('TOTAL: $'.$this->num($dte['Encabezado']['Totales']['MntTotal']), $x, null, '', $width-2);
284
            }
285
        }
286
        // si no es boleta se coloca EXENTO, NETO, IVA y TOTAL si corresponde
287
        if (!in_array($dte['Encabezado']['IdDoc']['TipoDTE'], [39, 41])) {
288 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...
289
                $this->MultiTexto('EXENTO: $'.$this->num($dte['Encabezado']['Totales']['MntExe']), $x, null, '', $width-2);
290
            }
291 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...
292
                $this->MultiTexto('NETO: $'.$this->num($dte['Encabezado']['Totales']['MntNeto']), $x, null, '', $width-2);
293
            }
294 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...
295
                $this->MultiTexto('IVA: $'.$this->num($dte['Encabezado']['Totales']['IVA']), $x, null, '', $width-2);
296
            }
297
            $this->MultiTexto('TOTAL: $'.$this->num($dte['Encabezado']['Totales']['MntTotal']), $x, null, '', $width-2);
298
        }
299
        // agregar acuse de recibo y leyenda cedible
300 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...
301
            $this->agregarAcuseReciboContinuo(-1, $this->y+6, $width+2, 34);
302
            $this->agregarLeyendaDestinoContinuo($dte['Encabezado']['IdDoc']['TipoDTE']);
303
        }
304
        // agregar timbre
305
        if (!empty($dte['Encabezado']['IdDoc']['TermPagoGlosa'])) {
306
            $this->Ln();
307
            $this->MultiTexto('Observación: '.$dte['Encabezado']['IdDoc']['TermPagoGlosa']."\n\n", $x);
308
        }
309
        $this->agregarTimbre($timbre, -11, $x, $this->GetY()+6, 55, 6);
310
        // si el alto no se pasó, entonces es con autocálculo, se elimina esta página y se pasa el alto
311
        // que se logró determinar para crear la página con el alto correcto
312
        if (!$height) {
313
            $this->deletePage($this->PageNo());
314
            $this->agregar_papel_57($dte, $timbre, $this->getY()+30);
315
        }
316
    }
317
318
    /**
319
     * Método que agrega una página con el documento tributario en papel
320
     * contínuo de 75mm
321
     * @param dte Arreglo con los datos del XML (tag Documento)
322
     * @param timbre String XML con el tag TED del DTE
323
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
324
     * @version 2019-10-06
325
     */
326
    private function agregar_papel_75(array $dte, $timbre)
327
    {
328
        $this->agregar_papel_80($dte, $timbre, 75);
329
    }
330
331
    /**
332
     * Método que agrega una página con el documento tributario en papel
333
     * contínuo de 80mm
334
     * @param dte Arreglo con los datos del XML (tag Documento)
335
     * @param timbre String XML con el tag TED del DTE
336
     * @param width Ancho del papel contínuo en mm (es parámetro porque se usa el mismo método para 75mm)
337
     * @author Pablo Reyes (https://github.com/pabloxp)
338
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
339
     * @version 2020-03-11
340
     */
341
    private function agregar_papel_80(array $dte, $timbre, $width = 80, $height = 0)
342
    {
343
        // si hay logo asignado se usa centrado
344
        if (!empty($this->logo)) {
345
            $this->logo['posicion'] = 'C';
346
        }
347
        // determinar alto de la página y agregarla
348
        $x_start = 1;
349
        $y_start = 1;
350
        $offset = 16;
351
        // determinar alto de la página y agregarla
352
        $this->AddPage('P', [$height ? $height : $this->papel_continuo_alto, $width]);
353
        // agregar cabecera del documento
354
        $y = $this->agregarFolio(
355
            $dte['Encabezado']['Emisor']['RUTEmisor'],
356
            $dte['Encabezado']['IdDoc']['TipoDTE'],
357
            $dte['Encabezado']['IdDoc']['Folio'],
358
            $dte['Encabezado']['Emisor']['CmnaOrigen'],
359
            $x_start, $y_start, $width-($x_start*4), 10,
360
            [0,0,0]
361
        );
362
        $y = $this->agregarEmisor($dte['Encabezado']['Emisor'], $x_start, $y+2, $width-($x_start*45), 8, 9, [0,0,0]);
363
        // datos del documento
364
        $this->SetY($y);
365
        $this->Ln();
366
        $this->setFont('', '', 8);
367
        $this->agregarDatosEmision($dte['Encabezado']['IdDoc'], !empty($dte['Encabezado']['Emisor']['CdgVendedor'])?$dte['Encabezado']['Emisor']['CdgVendedor']:null, $x_start, $offset, false);
368
        $this->agregarReceptor($dte['Encabezado'], $x_start, $offset);
369
        $this->agregarTraslado(
370
            !empty($dte['Encabezado']['IdDoc']['IndTraslado']) ? $dte['Encabezado']['IdDoc']['IndTraslado'] : null,
371
            !empty($dte['Encabezado']['Transporte']) ? $dte['Encabezado']['Transporte'] : null,
372
            $x_start, $offset
373
        );
374
        if (!empty($dte['Referencia'])) {
375
            $this->agregarReferencia($dte['Referencia'], $x_start, $offset);
376
        }
377
        $this->Ln();
378
        $this->agregarDetalleContinuo($dte['Detalle']);
379 View Code Duplication
        if (!empty($dte['DscRcgGlobal'])) {
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...
380
            $this->Ln();
381
            $this->Ln();
382
            $this->agregarSubTotal($dte['Detalle'], $x_start);
383
            $this->agregarDescuentosRecargos($dte['DscRcgGlobal'], $x_start);
384
        }
385 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...
386
            $this->Ln();
387
            $this->Ln();
388
            $this->agregarPagos($dte['Encabezado']['IdDoc']['MntPagos'], $x_start);
389
        }
390
        $this->agregarTotales($dte['Encabezado']['Totales'], !empty($dte['Encabezado']['OtraMoneda']) ? $dte['Encabezado']['OtraMoneda'] : null, $this->y+6, 23, 17);
391
        // agregar acuse de recibo y leyenda cedible
392 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...
393
            $this->agregarAcuseReciboContinuo(3, $this->y+6, 68, 34);
394
            $this->agregarLeyendaDestinoContinuo($dte['Encabezado']['IdDoc']['TipoDTE']);
395
        }
396
        // agregar timbre
397
        $y = $this->agregarObservacion($dte['Encabezado']['IdDoc'], $x_start, $this->y+6);
398
        $this->agregarTimbre($timbre, -10, $x_start, $y+6, 70, 6);
399
        // si el alto no se pasó, entonces es con autocálculo, se elimina esta página y se pasa el alto
400
        // que se logró determinar para crear la página con el alto correcto
401
        if (!$height) {
402
            $this->deletePage($this->PageNo());
403
            $this->agregar_papel_80($dte, $timbre, $width, $this->getY()+30);
404
        }
405
    }
406
407
    /**
408
     * Método que agrega una página con el documento tributario en papel
409
     * contínuo de 110mm
410
     * @param dte Arreglo con los datos del XML (tag Documento)
411
     * @param timbre String XML con el tag TED del DTE
412
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
413
     * @version 2019-10-06
414
     */
415
    private function agregar_papel_110(array $dte, $timbre, $height = 0)
416
    {
417
        $width = 110;
418
        if (!empty($this->logo)) {
419
            $this->logo['posicion'] = 1;
420
        }
421
        // determinar alto de la página y agregarla
422
        $x_start = 1;
423
        $y_start = 1;
0 ignored issues
show
Unused Code introduced by
$y_start is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
424
        $offset = 14;
425
        // determinar alto de la página y agregarla
426
        $this->AddPage('P', [$height ? $height : $this->papel_continuo_alto, $width]);
427
        // agregar cabecera del documento
428
        $y[] = $this->agregarFolio(
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...
429
            $dte['Encabezado']['Emisor']['RUTEmisor'],
430
            $dte['Encabezado']['IdDoc']['TipoDTE'],
431
            $dte['Encabezado']['IdDoc']['Folio'],
432
            !empty($dte['Encabezado']['Emisor']['CmnaOrigen']) ? $dte['Encabezado']['Emisor']['CmnaOrigen'] : null,
433
            63,
434
            2,
435
            45,
436
            9,
437
            [0,0,0]
438
        );
439
        $y[] = $this->agregarEmisor($dte['Encabezado']['Emisor'], 1, 2, 20, 30, 9, [0,0,0], $y[0]);
440
        $this->SetY(max($y));
441
        $this->Ln();
442
        // datos del documento
443
        $this->setFont('', '', 8);
444
        $this->agregarDatosEmision($dte['Encabezado']['IdDoc'], !empty($dte['Encabezado']['Emisor']['CdgVendedor'])?$dte['Encabezado']['Emisor']['CdgVendedor']:null, $x_start, $offset, false);
445
        $this->agregarReceptor($dte['Encabezado'], $x_start, $offset);
446
        $this->agregarTraslado(
447
            !empty($dte['Encabezado']['IdDoc']['IndTraslado']) ? $dte['Encabezado']['IdDoc']['IndTraslado'] : null,
448
            !empty($dte['Encabezado']['Transporte']) ? $dte['Encabezado']['Transporte'] : null,
449
            $x_start, $offset
450
        );
451
        if (!empty($dte['Referencia'])) {
452
            $this->agregarReferencia($dte['Referencia'], $x_start, $offset);
453
        }
454
        $this->Ln();
455
        $this->agregarDetalleContinuo($dte['Detalle'], 3, [1, 53, 73, 83]);
456 View Code Duplication
        if (!empty($dte['DscRcgGlobal'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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