Caf   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 284
Duplicated Lines 0 %

Test Coverage

Coverage 56.1%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 64
c 1
b 0
f 0
dl 0
loc 284
ccs 46
cts 82
cp 0.561
rs 9.84
wmc 32

23 Methods

Rating   Name   Duplication   Size   Complexity  
A vence() 0 5 1
A getPrivateKey() 0 3 1
A getTipoDocumento() 0 3 1
A enRango() 0 3 2
A __construct() 0 3 1
A getXmlDocument() 0 3 1
A getId() 0 7 1
A getFirma() 0 3 1
A loadXml() 0 10 2
A getXml() 0 3 1
A getEmisor() 0 5 1
A getCertificacion() 0 3 1
A getCantidadFolios() 0 6 1
A vigente() 0 15 4
A getFechaAutorizacion() 0 3 1
A getFolioDesde() 0 3 1
A getFechaVencimiento() 0 16 3
A getFolioHasta() 0 3 1
A getMesesAutorizacion() 0 12 2
A getAutorizacion() 0 3 1
A getPublicKey() 0 3 1
A getAmbiente() 0 5 2
A getIdk() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * LibreDTE: Biblioteca PHP (Núcleo).
7
 * Copyright (C) LibreDTE <https://www.libredte.cl>
8
 *
9
 * Este programa es software libre: usted puede redistribuirlo y/o modificarlo
10
 * bajo los términos de la Licencia Pública General Affero de GNU publicada por
11
 * la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, o
12
 * (a su elección) cualquier versión posterior de la misma.
13
 *
14
 * Este programa se distribuye con la esperanza de que sea útil, pero SIN
15
 * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD
16
 * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la Licencia Pública
17
 * General Affero de GNU para obtener una información más detallada.
18
 *
19
 * Debería haber recibido una copia de la Licencia Pública General Affero de
20
 * GNU junto a este programa.
21
 *
22
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
23
 */
24
25
namespace libredte\lib\Core\Package\Billing\Component\Identifier\Entity;
26
27
use DateTime;
28
use Derafu\Lib\Core\Package\Prime\Component\Xml\Contract\XmlInterface;
29
use Derafu\Lib\Core\Package\Prime\Component\Xml\Entity\Xml as XmlDocument;
30
use libredte\lib\Core\Package\Billing\Component\Identifier\Contract\CafInterface;
31
use libredte\lib\Core\Package\Billing\Component\Identifier\Exception\CafException;
32
use libredte\lib\Core\Package\Billing\Component\Identifier\Support\CafFaker;
33
use libredte\lib\Core\Package\Billing\Component\Integration\Enum\SiiAmbiente;
34
35
/**
36
 * Entidad que representa un Código de Autorización de Folios (CAF).
37
 *
38
 * Un CAF es un archivo XML que contiene los folios autorizados por el Servicio
39
 * de Impuestos Internos (SII) de Chile para la emisión de Documentos
40
 * Tributarios Electrónicos (DTE).
41
 */
42
class Caf implements CafInterface
43
{
44
    /**
45
     * Ambiente de certificación del SII.
46
     *
47
     * Este valor se utiliza para identificar que el CAF pertenece al ambiente
48
     * de pruebas o certificación.
49
     */
50
    private const IDK_CERTIFICACION = 100;
51
52
    /**
53
     * Ambiente de producción del SII.
54
     *
55
     * Este valor se utiliza para identificar que el CAF pertenece al ambiente
56
     * de producción.
57
     */
58
    private const IDK_PRODUCCION = 300;
59
60
    /**
61
     * Mapa de ambientes disponibles para el CAF.
62
     *
63
     * Asocia los valores de los ambientes con las configuraciones
64
     * correspondientes de conexión al SII (certificación o producción).
65
     *
66
     * @var array<int, SiiAmbiente>
67
     */
68
    private const AMBIENTES = [
69
        self::IDK_CERTIFICACION => SiiAmbiente::CERTIFICACION,
70
        self::IDK_PRODUCCION => SiiAmbiente::PRODUCCION,
71
    ];
72
73
    /**
74
     * Documento XML del CAF.
75
     *
76
     * Este objeto representa el XML cargado del CAF, utilizado para
77
     * interactuar con el contenido y extraer los datos necesarios.
78
     *
79
     * @var XmlInterface
80
     */
81
    private XmlInterface $xmlDocument;
82
83
    /**
84
     * Constructor del CAF.
85
     *
86
     * @param string|XmlInterface $xml Documento XML del CAF.
87
     */
88 108
    public function __construct(string|XmlInterface $xml)
89
    {
90 108
        $this->loadXml($xml);
91
    }
92
93
    /**
94
     * Carga un documento XML de un CAF en la instancia de la entidad Caf.
95
     *
96
     * @param string|XmlInterface $xml Documento XML del CAF.
97
     * @return static
98
     */
99 108
    private function loadXml(string|XmlInterface $xml): static
100
    {
101 108
        if (is_string($xml)) {
102
            $this->xmlDocument = new XmlDocument();
103
            $this->xmlDocument->loadXml($xml);
104
        } else {
105 108
            $this->xmlDocument = $xml;
106
        }
107
108 108
        return $this;
109
    }
110
111
    /**
112
     * {@inheritDoc}
113
     */
114 103
    public function getXmlDocument(): XmlInterface
115
    {
116 103
        return $this->xmlDocument;
117
    }
118
119
    /**
120
     * {@inheritDoc}
121
     */
122
    public function getXml(): string
123
    {
124
        return $this->xmlDocument->saveXml();
125
    }
126
127
    /**
128
     * {@inheritDoc}
129
     */
130
    public function getId(): string
131
    {
132
        return sprintf(
133
            'CAF%dD%dH%d',
134
            $this->getTipoDocumento(),
135
            $this->getFolioDesde(),
136
            $this->getFolioHasta()
137
        );
138
    }
139
140
    /**
141
     * {@inheritDoc}
142
     */
143 108
    public function getEmisor(): array
144
    {
145 108
        return [
146 108
            'rut' => $this->xmlDocument->query('//AUTORIZACION/CAF/DA/RE'),
147 108
            'razon_social' => $this->xmlDocument->query('//AUTORIZACION/CAF/DA/RS'),
148 108
        ];
149
    }
150
151
    /**
152
     * {@inheritDoc}
153
     */
154 108
    public function getTipoDocumento(): int
155
    {
156 108
        return (int) $this->xmlDocument->query('//AUTORIZACION/CAF/DA/TD');
157
    }
158
159
    /**
160
     * {@inheritDoc}
161
     */
162 105
    public function getFolioDesde(): int
163
    {
164 105
        return (int) $this->xmlDocument->query('//AUTORIZACION/CAF/DA/RNG/D');
165
    }
166
167
    /**
168
     * {@inheritDoc}
169
     */
170 105
    public function getFolioHasta(): int
171
    {
172 105
        return (int) $this->xmlDocument->query('//AUTORIZACION/CAF/DA/RNG/H');
173
    }
174
175
    /**
176
     * {@inheritDoc}
177
     */
178
    public function getCantidadFolios(): int
179
    {
180
        $desde = $this->getFolioDesde();
181
        $hasta = $this->getFolioHasta();
182
183
        return $hasta - $desde + 1;
184
    }
185
186
    /**
187
     * {@inheritDoc}
188
     */
189 103
    public function enRango(int $folio): bool
190
    {
191 103
        return $folio >= $this->getFolioDesde() && $folio <= $this->getFolioHasta();
192
    }
193
194
    /**
195
     * {@inheritDoc}
196
     */
197 58
    public function getFechaAutorizacion(): string
198
    {
199 58
        return $this->xmlDocument->query('//AUTORIZACION/CAF/DA/FA');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->xmlDocumen...UTORIZACION/CAF/DA/FA') could return the type array|null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
200
    }
201
202
    /**
203
     * {@inheritDoc}
204
     */
205 57
    public function getFechaVencimiento(): ?string
206
    {
207 57
        if (!$this->vence()) {
208
            return null;
209
        }
210
211 57
        $fecha_autorizacion = $this->getFechaAutorizacion();
212 57
        if (!$fecha_autorizacion) {
213
            throw new CafException(sprintf(
214
                'No fue posible obtener la fecha de autorización del CAF %s.',
215
                $this->getID()
216
            ));
217
        }
218
219
        // Los folios vencen en 6 meses (6 * 30 días).
220 57
        return date('Y-m-d', strtotime($fecha_autorizacion. ' + 180 days'));
221
    }
222
223
    /**
224
     * {@inheritDoc}
225
     */
226
    public function getMesesAutorizacion(): float
227
    {
228
        $d1 = new DateTime($this->getFechaAutorizacion());
229
        $d2 = new DateTime(date('Y-m-d'));
230
        $diff = $d1->diff($d2);
231
        $meses = $diff->m + ($diff->y * 12);
232
233
        if ($diff->d) {
234
            $meses += round($diff->d / 30, 2);
235
        }
236
237
        return $meses;
238
    }
239
240
    /**
241
     * {@inheritDoc}
242
     */
243 103
    public function vigente(?string $timestamp = null): bool
244
    {
245 103
        if (!$this->vence()) {
246 47
            return true;
247
        }
248
249 57
        if ($timestamp === null) {
250
            $timestamp = date('Y-m-d\TH:i:s');
251
        }
252
253 57
        if (!isset($timestamp[10])) {
254
            $timestamp .= 'T00:00:00';
255
        }
256
257 57
        return $timestamp < ($this->getFechaVencimiento() . 'T00:00:00');
258
    }
259
260
    /**
261
     * {@inheritDoc}
262
     */
263 103
    public function vence(): bool
264
    {
265 103
        $vencen = [33, 43, 46, 56, 61];
266
267 103
        return in_array($this->getTipoDocumento(), $vencen);
268
    }
269
270
    /**
271
     * {@inheritDoc}
272
     */
273 2
    public function getIdk(): int
274
    {
275 2
        return (int) $this->xmlDocument->query('//AUTORIZACION/CAF/DA/IDK');
276
    }
277
278
    /**
279
     * {@inheritDoc}
280
     */
281 1
    public function getAmbiente(): ?SiiAmbiente
282
    {
283 1
        $idk = $this->getIDK();
284
285 1
        return $idk === CafFaker::IDK ? null : self::AMBIENTES[$idk];
286
    }
287
288
    /**
289
     * {@inheritDoc}
290
     */
291
    public function getCertificacion(): ?int
292
    {
293
        return $this->getAmbiente()->value;
294
    }
295
296
    /**
297
     * {@inheritDoc}
298
     */
299
    public function getAutorizacion(): array
300
    {
301
        return $this->xmlDocument->query('//AUTORIZACION/CAF');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->xmlDocumen...y('//AUTORIZACION/CAF') could return the type null|string which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
302
    }
303
304
    /**
305
     * {@inheritDoc}
306
     */
307 3
    public function getPublicKey(): string
308
    {
309 3
        return $this->xmlDocument->query('//AUTORIZACION/RSAPUBK');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->xmlDocumen.../AUTORIZACION/RSAPUBK') could return the type array|null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
310
    }
311
312
    /**
313
     * {@inheritDoc}
314
     */
315 106
    public function getPrivateKey(): string
316
    {
317 106
        return $this->xmlDocument->query('//AUTORIZACION/RSASK');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->xmlDocumen...'//AUTORIZACION/RSASK') could return the type array|null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
318
    }
319
320
    /**
321
     * {@inheritDoc}
322
     */
323
    public function getFirma(): string
324
    {
325
        return $this->xmlDocument->query('//AUTORIZACION/CAF/FRMA');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->xmlDocumen...AUTORIZACION/CAF/FRMA') could return the type array|null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
326
    }
327
}
328