Test Failed
Push — master ( 8dc6a9...a5e9ad )
by Esteban De La Fuente
06:42
created

TemplateDataHandler::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
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 2
dl 0
loc 5
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\Document\Service;
26
27
use Closure;
28
use Derafu\Lib\Core\Helper\Rut;
29
use Derafu\Lib\Core\Package\Prime\Component\Entity\Contract\EntityComponentInterface;
30
use Derafu\Lib\Core\Package\Prime\Component\Template\Contract\DataHandlerInterface;
31
use Derafu\Lib\Core\Package\Prime\Component\Template\Service\DataHandler;
32
use Derafu\Lib\Core\Support\Store\Contract\RepositoryInterface;
33
use libredte\lib\Core\Package\Billing\Component\Document\Contract\TipoDocumentoInterface;
34
use libredte\lib\Core\Package\Billing\Component\Document\Entity\AduanaMoneda;
35
use libredte\lib\Core\Package\Billing\Component\Document\Entity\AduanaPais;
36
use libredte\lib\Core\Package\Billing\Component\Document\Entity\AduanaTransporte;
37
use libredte\lib\Core\Package\Billing\Component\Document\Entity\Comuna;
38
use libredte\lib\Core\Package\Billing\Component\Document\Entity\FormaPago;
39
use libredte\lib\Core\Package\Billing\Component\Document\Entity\Moneda;
40
use libredte\lib\Core\Package\Billing\Component\Document\Entity\TagXml;
41
use libredte\lib\Core\Package\Billing\Component\Document\Entity\Traslado;
42
use libredte\lib\Core\Package\Billing\Component\Document\Exception\RendererException;
43
use TCPDF2DBarcode;
44
45
/**
46
 * Servicio para traducir los datos de los documentos a su representación para
47
 * ser utilizada en la renderización del documento.
48
 */
49
class TemplateDataHandler implements DataHandlerInterface
50
{
51
    /**
52
     * Mapa de handlers.
53
     *
54
     * @var array
55
     */
56
    private array $handlers;
57
58
    /**
59
     * Handler por defecto para manejar los casos.
60
     *
61
     * @var DataHandlerInterface
62
     */
63
    private DataHandlerInterface $handler;
64
65
    /**
66
     * Constructor del handler.
67
     *
68
     * @param EntityComponentInterface $entityComponent
69
     * @param DataHandlerInterface|null $handler
70
     */
71 54
    public function __construct(
72
        private EntityComponentInterface $entityComponent,
73
        DataHandlerInterface $handler = null
74
    ) {
75 54
        $this->handler = $handler ?? new DataHandler();
76
    }
77
78
    /**
79
     * @inheritDoc
80
     */
81 54
    public function handle(string $id, mixed $data): string
82
    {
83
        // Si no hay valor asignado en los datos se entrega un string vacio.
84 54
        if (!$data) {
85 18
            return '';
86
        }
87
88
        // Buscar el handler.
89 54
        $handler = $this->getHandler($id);
90
91
        // Ejecutar el handler sobre los datos para formatearlos.
92 54
        assert($this->handler instanceof DataHandler);
93 54
        return $this->handler->handle($id, $data, $handler);
0 ignored issues
show
Unused Code introduced by
The call to Derafu\Lib\Core\Package\...dlerInterface::handle() has too many arguments starting with $handler. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

93
        return $this->handler->/** @scrutinizer ignore-call */ handle($id, $data, $handler);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
94
    }
95
96
    /**
97
     * Obtiene el handler de un campo a partir de su ID.
98
     *
99
     * @param string $id
100
     * @return Closure|RepositoryInterface
101
     */
102 54
    private function getHandler(string $id): Closure|RepositoryInterface
103
    {
104 54
        if (!isset($this->handlers)) {
105 54
            $this->handlers = $this->createHandlers();
106
        }
107
108 54
        if (!isset($this->handlers[$id])) {
109
            throw new RendererException(sprintf(
110
                'El formato para %s no está definido. Los disponibles son: %s.',
111
                $id,
112
                implode(', ', array_keys($this->handlers))
113
            ));
114
        }
115
116 54
        if (is_string($this->handlers[$id]) && str_starts_with($this->handlers[$id], 'alias:')) {
117 50
            [$alias, $handler] = explode(':', $this->handlers[$id], 2);
118
119 50
            if (!isset($this->handlers[$handler])) {
120
                throw new RendererException(sprintf(
121
                    'El alias %s del formato para %s no está definido. Los disponibles son: %s.',
122
                    $handler,
123
                    $id,
124
                    implode(', ', array_keys($this->handlers))
125
                ));
126
            }
127
128 50
            return $this->handlers[$handler];
129
        }
130
131 54
        return $this->handlers[$id];
132
    }
133
134
    /**
135
     * Mapa de campos a handlers para los documentos tributarios electrónicos.
136
     *
137
     * @return array
138
     */
139 54
    private function createHandlers(): array
140
    {
141 54
        return [
142
            // Tipos de documento.
143 54
            'TipoDTE' => $this->entityComponent->getRepository(
144 54
                TipoDocumentoInterface::class
145 54
            ),
146 54
            'TpoDocRef' => 'alias:TipoDTE',
147
            // RUT.
148 54
            'RUTEmisor' => fn (string $rut) => Rut::formatFull($rut),
149 54
            'RUTRecep' => 'alias:RUTEmisor',
150 54
            'RUTSolicita' => 'alias:RUTEmisor',
151 54
            'RUTTrans' => 'alias:RUTEmisor',
152 54
            'RUTChofer' => 'alias:RUTEmisor',
153
            // Comuna.
154 54
            'CdgSIISucur' => fn (string $comuna) =>
155 53
                $this->entityComponent->getRepository(
156 53
                    Comuna::class
157 53
                )->find($comuna)->getDireccionRegional()
158 54
            ,
159 54
            'CiudadOrigen' => fn (string $comuna) =>
160
                $this->entityComponent->getRepository(
161
                    Comuna::class
162
                )->find($comuna)->getCiudad()
163 54
            ,
164 54
            'CiudadRecep' => 'alias:CiudadOrigen',
165
            // Fechas largas.
166 54
            'FchEmis' => function (string $fecha) {
167 54
                $timestamp = strtotime($fecha);
168 54
                return date('d/m/Y', $timestamp); // TODO: Formato largo.
169 54
            },
170 54
            'FchRef' => 'alias:FchEmis',
171 54
            'FchVenc' => 'alias:FchEmis',
172
            // Fechas cortas.
173 54
            'PeriodoDesde' => function (string $fecha) {
174 1
                $timestamp = strtotime($fecha);
175 1
                return date('d/m/Y', $timestamp);
176 54
            },
177 54
            'PeriodoHasta' => 'alias:PeriodoDesde',
178
            // Solo año de una fecha.
179 54
            'FchResol' => fn (string $fecha) => explode('-', $fecha, 2)[0],
180
            // Datos de Aduana.
181 54
            'Aduana' => function (string $tagXmlAndValue) {
182
                [$tagXml, $value] = explode(':', $tagXmlAndValue);
183
                $xmlTagEntity = $this->entityComponent->getRepository(
184
                    TagXml::class
185
                )->find($tagXml);
186
                $name = $xmlTagEntity->getGlosa();
187
                $entityClass = $xmlTagEntity->getEntity();
188
                if ($entityClass) {
189
                    $description = $this->entityComponent->getRepository(
190
                        $entityClass
191
                    )->find($value)->getGlosa();
192
                } else {
193
                    $description = $this->handle($tagXml, $value);
194
                }
195
                if ($name && !in_array($description, [false, null, ''], true)) {
196
                    return $name . ': ' . $description;
197
                }
198
                return '';
199 54
            },
200
            // Otros datos que se mapean de un código a su glosa usando un
201
            // repositorio.
202 54
            'FmaPago' => $this->entityComponent->getRepository(
203 54
                FormaPago::class
204 54
            ),
205 54
            'Nacionalidad' => $this->entityComponent->getRepository(
206 54
                AduanaPais::class
207 54
            ),
208 54
            'CodPaisRecep' => 'alias:Nacionalidad',
209 54
            'IndTraslado' => $this->entityComponent->getRepository(
210 54
                Traslado::class
211 54
            ),
212 54
            'CodViaTransp' => $this->entityComponent->getRepository(
213 54
                AduanaTransporte::class
214 54
            ),
215
            //  Timbre Electrónico del Documento (TED).
216 54
            'TED' => function (string $timbre) {
217 54
                $pdf417 = new TCPDF2DBarcode($timbre, 'PDF417,,5');
218 54
                $png = $pdf417->getBarcodePngData(1, 1, [0,0,0]);
219 54
                return 'data:image/png;base64,' . base64_encode($png);
220 54
            },
221
            // Montos sin decimales.
222 54
            'Number' => function (int|float|string $num) {
223
                $num = round((float) $num);
224
                return number_format($num, 0, ',', '.');
225 54
            },
226
            // Montos según moneda.
227 54
            'MontoMoneda' => function (string $value) {
228
                [$codigo, $num] = explode(':', $value);
229
                $result = $this->entityComponent->getRepository(
230
                    AduanaMoneda::class
231
                )->findBy(['glosa' => $codigo]);
232
                $moneda = ($result[0] ?? null)->getMoneda() ?? Moneda::XXX;
0 ignored issues
show
Bug introduced by
The method getMoneda() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

232
                $moneda = ($result[0] ?? null)->/** @scrutinizer ignore-call */ getMoneda() ?? Moneda::XXX;

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
233
                $num = round((float) $num, $moneda->getDecimales());
234
                return number_format($num, $moneda->getDecimales(), ',', '.');
235 54
            },
236 54
        ];
237
    }
238
}
239