Test Failed
Push — master ( 0741dd...48ec12 )
by Esteban De La Fuente
08:16 queued 02:11
created

TemplateDataHandler::getHandler()   A

Complexity

Conditions 6
Paths 8

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 11.9895

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 17
c 1
b 0
f 0
nc 8
nop 1
dl 0
loc 30
ccs 9
cts 20
cp 0.45
crap 11.9895
rs 9.0777
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\Date;
29
use Derafu\Lib\Core\Helper\Rut;
30
use Derafu\Lib\Core\Package\Prime\Component\Entity\Contract\EntityComponentInterface;
31
use Derafu\Lib\Core\Package\Prime\Component\Template\Contract\DataHandlerInterface;
32
use Derafu\Lib\Core\Package\Prime\Component\Template\Service\DataHandler;
33
use Derafu\Lib\Core\Support\Store\Contract\RepositoryInterface;
34
use libredte\lib\Core\Package\Billing\Component\Document\Contract\TipoDocumentoInterface;
35
use libredte\lib\Core\Package\Billing\Component\Document\Entity\AduanaMoneda;
36
use libredte\lib\Core\Package\Billing\Component\Document\Entity\AduanaPais;
37
use libredte\lib\Core\Package\Billing\Component\Document\Entity\AduanaTransporte;
38
use libredte\lib\Core\Package\Billing\Component\Document\Entity\Comuna;
39
use libredte\lib\Core\Package\Billing\Component\Document\Entity\FormaPago;
40
use libredte\lib\Core\Package\Billing\Component\Document\Entity\ImpuestoAdicionalRetencion;
41
use libredte\lib\Core\Package\Billing\Component\Document\Entity\MedioPago;
42
use libredte\lib\Core\Package\Billing\Component\Document\Entity\Moneda;
43
use libredte\lib\Core\Package\Billing\Component\Document\Entity\TagXml;
44
use libredte\lib\Core\Package\Billing\Component\Document\Entity\Traslado;
45
use libredte\lib\Core\Package\Billing\Component\Document\Exception\RendererException;
46
use TCPDF2DBarcode;
47
48
/**
49
 * Servicio para traducir los datos de los documentos a su representación para
50
 * ser utilizada en la renderización del documento.
51
 */
52
class TemplateDataHandler implements DataHandlerInterface
53
{
54
    /**
55
     * Mapa de handlers.
56
     *
57
     * @var array
58
     */
59
    private array $handlers;
60
61
    /**
62
     * Handler por defecto para manejar los casos.
63
     *
64
     * @var DataHandlerInterface
65
     */
66
    private DataHandlerInterface $handler;
67
68
    /**
69
     * Constructor del handler.
70
     *
71
     * @param EntityComponentInterface $entityComponent
72
     * @param DataHandlerInterface|null $handler
73
     */
74 54
    public function __construct(
75
        private EntityComponentInterface $entityComponent,
76
        DataHandlerInterface $handler = null
77
    ) {
78 54
        $this->handler = $handler ?? new DataHandler();
79
    }
80
81
    /**
82
     * @inheritDoc
83
     */
84 54
    public function handle(string $id, mixed $data): string
85
    {
86
        // Si no hay valor asignado en los datos se entrega un string vacio.
87 54
        if (!$data) {
88 18
            return '';
89
        }
90
91
        // Buscar el handler.
92 54
        $handler = $this->getHandler($id);
93
94
        // Ejecutar el handler sobre los datos para formatearlos.
95 54
        assert($this->handler instanceof DataHandler);
96 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

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

240
                $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...
241
                $num = round((float) $num, $moneda->getDecimales());
242
                return number_format($num, $moneda->getDecimales(), ',', '.');
243 54
            },
244 54
        ];
245
    }
246
}
247