Passed
Push — master ( 48ec12...d2181c )
by Esteban De La Fuente
06:08
created

Caf::getPublicKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
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\Entity\Ambiente;
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, Ambiente>
67
     */
68
    private const AMBIENTES = [
69
        self::IDK_CERTIFICACION => Ambiente::CERTIFICACION,
70
        self::IDK_PRODUCCION => Ambiente::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 59
    public function __construct(string|XmlInterface $xml)
89
    {
90 59
        $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 59
    private function loadXml(string|XmlInterface $xml): static
100
    {
101 59
        if (is_string($xml)) {
102
            $this->xmlDocument = new XmlDocument();
103
            $this->xmlDocument->loadXml($xml);
104
        } else {
105 59
            $this->xmlDocument = $xml;
106
        }
107
108 59
        return $this;
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     */
114 54
    public function getXmlDocument(): XmlInterface
115
    {
116 54
        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 59
    public function getEmisor(): array
144
    {
145 59
        return [
146 59
            'rut' => $this->xmlDocument->query('//AUTORIZACION/CAF/DA/RE'),
147 59
            'razon_social' => $this->xmlDocument->query('//AUTORIZACION/CAF/DA/RS'),
148 59
        ];
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154 59
    public function getTipoDocumento(): int
155
    {
156 59
        return (int) $this->xmlDocument->query('//AUTORIZACION/CAF/DA/TD');
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162 56
    public function getFolioDesde(): int
163
    {
164 56
        return (int) $this->xmlDocument->query('//AUTORIZACION/CAF/DA/RNG/D');
165
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170 56
    public function getFolioHasta(): int
171
    {
172 56
        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 54
    public function enRango(int $folio): bool
190
    {
191 54
        return $folio >= $this->getFolioDesde() && $folio <= $this->getFolioHasta();
192
    }
193
194
    /**
195
     * {@inheritdoc}
196
     */
197 31
    public function getFechaAutorizacion(): string
198
    {
199 31
        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 30
    public function getFechaVencimiento(): ?string
206
    {
207 30
        if (!$this->vence()) {
208
            return null;
209
        }
210
211 30
        $fecha_autorizacion = $this->getFechaAutorizacion();
212 30
        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 30
        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 54
    public function vigente(?string $timestamp = null): bool
244
    {
245 54
        if (!$this->vence()) {
246 24
            return true;
247
        }
248
249 30
        if ($timestamp === null) {
250
            $timestamp = date('Y-m-d\TH:i:s');
251
        }
252
253 30
        if (!isset($timestamp[10])) {
254
            $timestamp .= 'T00:00:00';
255
        }
256
257 30
        return $timestamp < ($this->getFechaVencimiento() . 'T00:00:00');
258
    }
259
260
    /**
261
     * {@inheritdoc}
262
     */
263 54
    public function vence(): bool
264
    {
265 54
        $vencen = [33, 43, 46, 56, 61];
266
267 54
        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(): ?Ambiente
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 57
    public function getPrivateKey(): string
316
    {
317 57
        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