Test Failed
Push — master ( 59e870...659f9a )
by Esteban De La Fuente
04:33
created

DocumentBag::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 12
nc 1
nop 11
dl 0
loc 25
ccs 13
cts 13
cp 1
crap 1
rs 9.8666
c 1
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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\Document\Support;
26
27
use Derafu\Lib\Core\Package\Prime\Component\Certificate\Contract\CertificateInterface;
28
use Derafu\Lib\Core\Package\Prime\Component\Xml\Contract\XmlInterface;
29
use Derafu\Lib\Core\Support\Store\Contract\DataContainerInterface;
30
use Derafu\Lib\Core\Support\Store\DataContainer;
31
use libredte\lib\Core\Package\Billing\Component\Identifier\Contract\CafInterface;
32
use libredte\lib\Core\Package\Billing\Component\Document\Contract\DocumentBagInterface;
33
use libredte\lib\Core\Package\Billing\Component\Document\Contract\DocumentInterface;
34
use libredte\lib\Core\Package\Billing\Component\Document\Contract\TipoDocumentoInterface;
35
use libredte\lib\Core\Package\Billing\Component\Document\Exception\DocumentException;
36
use libredte\lib\Core\Package\Billing\Component\TradingParties\Contract\EmisorInterface;
37
use libredte\lib\Core\Package\Billing\Component\TradingParties\Contract\ReceptorInterface;
38
use stdClass;
39
40
/**
41
 * Contenedor de datos del documento tributario electrónico.
42
 *
43
 * Permite "mover" un documento, junto a otros datos asociados, por métodos de
44
 * manera sencilla y, sobre todo, extensible.
45
 */
46
class DocumentBag implements DocumentBagInterface
47
{
48
    /**
49
     * Datos originales de entrada que se utilizarán para construir el
50
     * documento tributario.
51
     *
52
     * El formato de estos datos puede ser cualquiera soportado por los parsers.
53
     *
54
     * @var string|null
55
     */
56
    private ?string $inputData;
57
58
    /**
59
     * Datos de entrada procesados (parseados).
60
     *
61
     * Están en el formato estándar de LibreDTE. Que es básicamente el oficial
62
     * del SII. Con algunas extensiones, como los datos "extras".
63
     *
64
     * Estos son los datos que se usarán para construir el documento. Estos
65
     * datos no están normaliados, solo parseados.
66
     *
67
     * @var array|null
68
     */
69
    private ?array $parsedData;
70
71
    /**
72
     * Datos normalizados del documento tributario.
73
     *
74
     * Son los datos con todos sus campos necesarios ya determinados, calculados
75
     * y validados.
76
     *
77
     * La estructura de estos datos depende de los normalizadores.
78
     *
79
     * Importante: si se desactiva la normalización este arreglo contendrá lo
80
     * mismo que $parsedData pues no se tocarán los datos de entrada procesados.
81
     *
82
     * @var array|null
83
     */
84
    private ?array $normalizedData;
85
86
    /**
87
     * Opciones para los workers asociados al documento.
88
     *
89
     * Se definen los siguientes índices para las opciones:
90
     *
91
     *   - `builder`: Opciones para los constructores.
92
     *   - `normalizer`: Opciones para los normalizadores.
93
     *   - `parser`: Opciones para los analizadores sintácticos.
94
     *   - `renderer`: Opciones para los renderizadores.
95
     *   - `sanitizer`: Opciones para los sanitizadores.
96
     *   - `validator`: Opciones para los validadores.
97
     *
98
     * Se usarán las opciones por defecto en cada worker si no se indican los
99
     * índices en el arreglo $options.
100
     *
101
     * @param DataContainerInterface|null
102
     */
103
    private ?DataContainerInterface $options;
104
105
    /**
106
     * Reglas de esquema de las opciones del documento.
107
     *
108
     * El formato del esquema es el utilizado por
109
     * Symfony\Component\OptionsResolver\OptionsResolver.
110
     *
111
     * Acá solo se indicarán los índices que deben pueden existir en las
112
     * opciones. No se define el esquema de cada opción pues cada clase que
113
     * utilice estas opciones deberá resolver y validar sus propias opciones.
114
     *
115
     * @var array
116
     */
117
    protected array $optionsSchema = [
118
        'builder' => [
119
            'types' => 'array',
120
            'default' => [],
121
        ],
122
        'normalizer' => [
123
            'types' => 'array',
124
            'default' => [],
125
        ],
126
        'parser' => [
127
            'types' => 'array',
128
            'default' => [],
129
        ],
130
        'renderer' => [
131
            'types' => 'array',
132
            'default' => [],
133
        ],
134
        'sanitizer' => [
135
            'types' => 'array',
136
            'default' => [],
137
        ],
138
        'validator' => [
139
            'types' => 'array',
140
            'default' => [],
141
        ],
142
    ];
143
144
    /**
145
     * Instancia del documento XML asociada al DTE.
146
     *
147
     * @var XmlInterface|null
148
     */
149
    private ?XmlInterface $xmlDocument;
150
151
    /**
152
     * Código de Asignación de Folios (CAF) para timbrar el Documento Tributario
153
     * Electrónico (DTE) que se generará.
154
     *
155
     * @var CafInterface|null
156
     */
157
    private ?CafInterface $caf;
158
159
    /**
160
     * Certificado digital (firma electrónica) para la firma del documento.
161
     *
162
     * @var CertificateInterface|null
163
     */
164
    private ?CertificateInterface $certificate;
165
166
    /**
167
     * Entidad con el documento tributario electrónico generado.
168
     *
169
     * @var DocumentInterface|null
170
     */
171
    private ?DocumentInterface $document;
172
173
    /**
174
     * Entidad que representa al tipo de documento tributario que está contenido
175
     * en esta bolsa.
176
     *
177
     * @var TipoDocumentoInterface|null
178
     */
179
    private ?TipoDocumentoInterface $documentType = null;
180
181
    /**
182
     * Emisor del documento tributario.
183
     *
184
     * @var EmisorInterface|null
185
     */
186
    private ?EmisorInterface $emisor = null;
187
188
    /**
189
     * Receptor del documento tributario.
190
     *
191
     * @var ReceptorInterface|null
192
     */
193
    private ?ReceptorInterface $receptor = null;
194
195
    /**
196
     * Arreglo con la estructura del nodo TED del documento.
197
     *
198
     * @var array|null
199
     */
200
    private ?array $timbre = null;
201
202
    /**
203
     * Arreglo con los datos normalizados consolidados con el timbre y la firma
204
     * si existen en la bolsa.
205
     *
206
     * @var array|null
207
     */
208
    private ?array $data = null;
209
210
    /**
211
     * Constructor del contenedor.
212
     *
213
     * Recibe los datos en diferentes formatos para pasarlos a los setters que
214
     * los normalizan y asignan al contenedor.
215
     *
216
     * @param string|array|stdClass|null $inputData
217
     * @param array|null $parsedData
218
     * @param array|null $normalizedData
219
     * @param array|DataContainerInterface|null $options
220
     * @param XmlInterface|null $xmlDocument
221
     * @param CafInterface|null $caf
222
     * @param CertificateInterface|null $certificate
223
     * @param DocumentInterface|null $document
224
     * @param TipoDocumentoInterface|null $documentType
225
     * @param EmisorInterface|null $emisor
226
     * @param ReceptorInterface|null $receptor
227
     */
228 68
    public function __construct(
229
        string|array|stdClass $inputData = null,
230
        array $parsedData = null,
231
        array $normalizedData = null,
232
        array|DataContainerInterface $options = null,
233
        XmlInterface $xmlDocument = null,
234
        CafInterface $caf = null,
235
        CertificateInterface $certificate = null,
236
        DocumentInterface $document = null,
237
        TipoDocumentoInterface $documentType = null,
238
        EmisorInterface $emisor = null,
239
        ReceptorInterface $receptor = null
240
    ) {
241 68
        $this
242 68
            ->setInputData($inputData)
243 68
            ->setParsedData($parsedData)
244 68
            ->setNormalizedData($normalizedData)
245 68
            ->setOptions($options)
246 68
            ->setXmlDocument($xmlDocument)
247 68
            ->setCaf($caf)
248 68
            ->setCertificate($certificate)
249 68
            ->setDocument($document)
250 68
            ->setDocumentType($documentType)
251 68
            ->setEmisor($emisor)
252 68
            ->setReceptor($receptor)
253 68
        ;
254
    }
255
256
    /**
257
     * {@inheritdoc}
258
     */
259 68
    public function setInputData(string|array|stdClass|null $inputData): static
260
    {
261 68
        if ($inputData === null) {
0 ignored issues
show
introduced by
The condition $inputData === null is always false.
Loading history...
262 59
            $this->inputData = null;
263
264 59
            return $this;
265
        }
266
267 13
        if (!is_string($inputData)) {
0 ignored issues
show
introduced by
The condition is_string($inputData) is always false.
Loading history...
268 6
            $inputData = json_encode($inputData);
269
        }
270
271 13
        $this->inputData = $inputData;
272
273 13
        return $this;
274
    }
275
276
    /**
277
     * {@inheritdoc}
278
     */
279 68
    public function getInputData(): ?string
280
    {
281 68
        return $this->inputData;
282
    }
283
284
    /**
285
     * {@inheritdoc}
286
     */
287 68
    public function setParsedData(?array $parsedData): static
288
    {
289 68
        $this->parsedData = $parsedData;
290
291 68
        return $this;
292
    }
293
294
    /**
295
     * {@inheritdoc}
296
     */
297 67
    public function getParsedData(): ?array
298
    {
299 67
        return $this->parsedData;
300
    }
301
302
    /**
303
     * {@inheritdoc}
304
     */
305 68
    public function setNormalizedData(?array $normalizedData): static
306
    {
307 68
        $this->normalizedData = $normalizedData;
308
309 68
        return $this;
310
    }
311
312
    /**
313
     * {@inheritdoc}
314
     */
315 63
    public function getNormalizedData(): ?array
316
    {
317 63
        return $this->normalizedData;
318
    }
319
320
    /**
321
     * {@inheritdoc}
322
     */
323 68
    public function setOptions(array|DataContainerInterface|null $options): static
324
    {
325 68
        if ($options === null) {
0 ignored issues
show
introduced by
The condition $options === null is always false.
Loading history...
326 66
            $options = [];
327
        }
328
329 68
        if (is_array($options)) {
0 ignored issues
show
introduced by
The condition is_array($options) is always true.
Loading history...
330 66
            $options = new DataContainer($options, $this->optionsSchema);
331
        }
332
333 68
        $this->options = $options;
334
335 68
        return $this;
336
    }
337
338
    /**
339
     * {@inheritdoc}
340
     */
341 3
    public function getOptions(): ?DataContainerInterface
342
    {
343 3
        return $this->options;
344
    }
345
346
    /**
347
     * {@inheritdoc}
348
     */
349 13
    public function getParserOptions(): array
350
    {
351 13
        return (array) $this->options?->get('parser');
352
    }
353
354
    /**
355
     * {@inheritdoc}
356
     */
357 54
    public function getBuilderOptions(): array
358
    {
359 54
        return (array) $this->options?->get('builder');
360
    }
361
362
    /**
363
     * {@inheritdoc}
364
     */
365 58
    public function getNormalizerOptions(): array
366
    {
367 58
        return (array) $this->options?->get('normalizer');
368
    }
369
370
    /**
371
     * {@inheritdoc}
372
     */
373
    public function getSanitizerOptions(): array
374
    {
375
        return (array) $this->options?->get('sanitizer');
376
    }
377
378
    /**
379
     * {@inheritdoc}
380
     */
381
    public function getValidatorOptions(): array
382
    {
383
        return (array) $this->options?->get('validator');
384
    }
385
386
    /**
387
     * {@inheritdoc}
388
     */
389 54
    public function getRendererOptions(): array
390
    {
391 54
        return (array) $this->options?->get('renderer');
392
    }
393
394
    /**
395
     * {@inheritdoc}
396
     */
397 68
    public function setXmlDocument(?XmlInterface $xmlDocument): static
398
    {
399 68
        $this->xmlDocument = $xmlDocument;
400
401 68
        return $this;
402
    }
403
404
    /**
405
     * {@inheritdoc}
406
     */
407 63
    public function getXmlDocument(): ?XmlInterface
408
    {
409 63
        return $this->xmlDocument;
410
    }
411
412
    /**
413
     * {@inheritdoc}
414
     */
415 68
    public function setCaf(?CafInterface $caf): static
416
    {
417 68
        $this->caf = $caf;
418
419 68
        return $this;
420
    }
421
422
    /**
423
     * {@inheritdoc}
424
     */
425 58
    public function getCaf(): ?CafInterface
426
    {
427 58
        return $this->caf;
428
    }
429
430
    /**
431
     * {@inheritdoc}
432
     */
433 68
    public function setCertificate(?CertificateInterface $certificate): static
434
    {
435 68
        $this->certificate = $certificate;
436
437 68
        return $this;
438
    }
439
440
    /**
441
     * {@inheritdoc}
442
     */
443 58
    public function getCertificate(): ?CertificateInterface
444
    {
445 58
        return $this->certificate;
446
    }
447
448
    /**
449
     * {@inheritdoc}
450
     */
451 68
    public function setDocument(?DocumentInterface $document): static
452
    {
453 68
        $this->document = $document;
454
455 68
        return $this;
456
    }
457
458
    /**
459
     * {@inheritdoc}
460
     */
461 63
    public function getDocument(): ?DocumentInterface
462
    {
463 63
        return $this->document;
464
    }
465
466
    /**
467
     * {@inheritdoc}
468
     */
469 68
    public function setDocumentType(?TipoDocumentoInterface $documentType): static
470
    {
471 68
        $this->documentType = $documentType;
472
473 68
        return $this;
474
    }
475
476
    /**
477
     * {@inheritdoc}
478
     */
479 64
    public function setTipoDocumento(?TipoDocumentoInterface $tipoDocumento): static
480
    {
481 64
        return $this->setDocumentType($tipoDocumento);
482
    }
483
484
    /**
485
     * {@inheritdoc}
486
     */
487 67
    public function getDocumentType(): ?TipoDocumentoInterface
488
    {
489 67
        return $this->documentType;
490
    }
491
492
    /**
493
     * {@inheritdoc}
494
     */
495 67
    public function getTipoDocumento(): ?TipoDocumentoInterface
496
    {
497 67
        return $this->getDocumentType();
498
    }
499
500
    /**
501
     * {@inheritdoc}
502
     */
503 67
    public function getDocumentTypeId(): ?int
504
    {
505 67
        $TipoDTE = $this->parsedData['Encabezado']['IdDoc']['TipoDTE']
506 67
            ?? $this->normalizedData['Encabezado']['IdDoc']['TipoDTE']
507 67
            ?? $this->xmlDocument?->query('//Encabezado/IdDoc/TipoDTE')
508 67
            ?? $this->document?->getCodigo()
509 60
            ?? null
510 67
        ;
511
512 67
        if (!$TipoDTE) {
513 2
            throw new DocumentException(
514 2
                'Falta indicar el tipo de documento (TipoDTE) en los datos del DTE.'
515 2
            );
516
        }
517
518 65
        return (int) $TipoDTE;
519
    }
520
521
    /**
522
     * {@inheritdoc}
523
     */
524 67
    public function getCodigoTipoDocumento(): ?int
525
    {
526 67
        return $this->getDocumentTypeId();
527
    }
528
529
    /**
530
     * {@inheritdoc}
531
     */
532 68
    public function setEmisor(?EmisorInterface $emisor): static
533
    {
534 68
        $this->emisor = $emisor;
535
536 68
        return $this;
537
    }
538
539
    /**
540
     * {@inheritdoc}
541
     */
542 63
    public function getEmisor(): ?EmisorInterface
543
    {
544 63
        return $this->emisor;
545
    }
546
547
    /**
548
     * {@inheritdoc}
549
     */
550 68
    public function setReceptor(?ReceptorInterface $receptor): static
551
    {
552 68
        $this->receptor = $receptor;
553
554 68
        return $this;
555
    }
556
557
    /**
558
     * {@inheritdoc}
559
     */
560 63
    public function getReceptor(): ?ReceptorInterface
561
    {
562 63
        return $this->receptor;
563
    }
564
565
    /**
566
     * {@inheritdoc}
567
     */
568 54
    public function setTimbre(?array $timbre): static
569
    {
570 54
        $this->timbre = $timbre;
571
572 54
        return $this;
573
    }
574
575
    /**
576
     * {@inheritdoc}
577
     */
578 58
    public function getTimbre(): ?array
579
    {
580 58
        return $this->timbre;
581
    }
582
583
    /**
584
     * {@inheritdoc}
585
     */
586 58
    public function getData(): ?array
587
    {
588
        // Si los datos ya estaban generados se entregan.
589 58
        if ($this->data !== null) {
590
            return $this->data;
591
        }
592
593
        // Si no hay datos normalizados se entrega `null`.
594 58
        if (!$this->getNormalizedData()) {
595
            return null;
596
        }
597
598
        // Se arma la estructura del nodo Documento.
599 58
        $tagXml = $this->getTipoDocumento()->getTagXml()->getNombre();
600 58
        $this->data = [
601 58
            'DTE' => [
602 58
                '@attributes' => [
603 58
                    'version' => '1.0',
604 58
                    'xmlns' => 'http://www.sii.cl/SiiDte',
605 58
                ],
606 58
                $tagXml => array_merge(
607 58
                    [
608 58
                        '@attributes' => [
609 58
                            'ID' => $this->getId(),
610 58
                        ],
611 58
                    ],
612 58
                    $this->getNormalizedData(),
613 58
                    (array) $this->getTimbre(),
614 58
                ),
615 58
                //'Signature' => '', // Se agrega al firmar (NO INCLUIR ACÁ).
616 58
            ],
617 58
        ];
618
619
        // Se entrega la estructura con los datos.
620 58
        return $this->data;
621
    }
622
623
    /**
624
     * {@inheritdoc}
625
     */
626 58
    public function getId(): string
627
    {
628 58
        return sprintf(
629 58
            'LibreDTE_%s_T%dF%d',
630 58
            $this->getNormalizedData()['Encabezado']['Emisor']['RUTEmisor'],
631 58
            $this->getNormalizedData()['Encabezado']['IdDoc']['TipoDTE'],
632 58
            $this->getNormalizedData()['Encabezado']['IdDoc']['Folio']
633 58
        );
634
    }
635
636
    /**
637
     * {@inheritdoc}
638
     */
639 3
    public function withCaf(CafInterface $caf): DocumentBagInterface
640
    {
641 3
        return new static(
642 3
            inputData: $this->getInputData(),
643 3
            parsedData: $this->getParsedData(),
644 3
            normalizedData: $this->getNormalizedData(),
645 3
            options: $this->getOptions() ,
646 3
            caf: $caf,
647 3
            certificate: $this->getCertificate(),
648 3
            documentType: $this->getDocumentType(),
649 3
            emisor: $this->getEmisor(),
650 3
            receptor: $this->getReceptor()
651 3
        );
652
    }
653
654
    /**
655
     * {@inheritdoc}
656
     */
657 3
    public function withCertificate(
658
        CertificateInterface $certificate
659
    ): DocumentBagInterface {
660 3
        return new static(
661 3
            inputData: $this->getInputData(),
662 3
            parsedData: $this->getParsedData(),
663 3
            normalizedData: $this->getNormalizedData(),
664 3
            options: $this->getOptions() ,
665 3
            caf: $this->getCaf(),
666 3
            certificate: $certificate,
667 3
            documentType: $this->getDocumentType(),
668 3
            emisor: $this->getEmisor(),
669 3
            receptor: $this->getReceptor()
670 3
        );
671
    }
672
673
    /**
674
     * {@inheritdoc}
675
     */
676 60
    public function getAlias(): string
677
    {
678 60
        return $this->getTipoDocumento()?->getAlias()
679 60
            ?? (
680 60
                $this->getTipoDocumento()?->getCodigo()
681 1
                    ? 'documento_' .  $this->getTipoDocumento()?->getCodigo()
682 2
                    : null
683 60
            )
684 60
            ?? $this->getParsedData()['Encabezado']['IdDoc']['TipoDTE']
685 60
            ?? 'documento_desconocido'
686 60
        ;
687
    }
688
}
689