Completed
Push — master ( 38c80c...b1cd06 )
by Esteban De La Fuente
01:45
created

Dte   F

Complexity

Total Complexity 305

Size/Duplication

Total Lines 1395
Duplicated Lines 6.16 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
wmc 305
lcom 1
cbo 6
dl 86
loc 1395
rs 0.8
c 0
b 0
f 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A setLogo() 0 7 1
A setPosicionDetalleItem() 0 4 1
A setFuenteDetalle() 0 4 1
A setAnchoColumnasDetalle() 0 8 4
A setTimbrePie() 0 4 1
A agregar() 0 11 3
C agregar_papel_0() 3 50 12
F agregar_papel_57() 13 79 20
A agregar_papel_75() 0 4 1
C agregar_papel_80() 15 65 13
C agregar_papel_110() 11 70 15
F agregarEmisor() 0 89 41
B agregarFolio() 0 25 9
C agregarDatosEmision() 12 80 13
F agregarReceptor() 14 78 22
F agregarTraslado() 18 72 23
B agregarReferencia() 0 29 9
F agregarDetalle() 0 100 38
B agregarDetalleContinuo() 0 45 8
A agregarSubTotal() 0 18 5
B agregarDescuentosRecargos() 0 20 9
A agregarPagos() 0 11 4
F agregarTotales() 0 91 17
F agregarObservacion() 0 33 14
B agregarTimbre() 0 31 8
A agregarAcuseRecibo() 0 21 3
A agregarAcuseReciboContinuo() 0 23 1
A agregarLeyendaDestino() 0 7 5
A agregarLeyendaDestinoContinuo() 0 5 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Dte often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Dte, and based on these observations, apply Extract Interface, too.

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