BatchProcessorWorker   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 203
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 20
eloc 88
dl 0
loc 203
ccs 0
cts 90
cp 0
rs 10
c 1
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A loadDocumentsFromFile() 0 17 2
B completeParsedData() 0 48 11
B process() 0 68 6
A __construct() 0 11 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\Document\Worker;
26
27
use Derafu\Backbone\Abstract\AbstractWorker;
28
use Derafu\Backbone\Attribute\Worker;
29
use Derafu\Backbone\Trait\StrategiesAwareTrait;
30
use libredte\lib\Core\Package\Billing\Component\Document\Contract\BatchProcessorStrategyInterface;
31
use libredte\lib\Core\Package\Billing\Component\Document\Contract\BatchProcessorWorkerInterface;
32
use libredte\lib\Core\Package\Billing\Component\Document\Contract\BuilderWorkerInterface;
33
use libredte\lib\Core\Package\Billing\Component\Document\Contract\DocumentBagManagerWorkerInterface;
34
use libredte\lib\Core\Package\Billing\Component\Document\Contract\DocumentBatchInterface;
35
use libredte\lib\Core\Package\Billing\Component\Document\Exception\BatchProcessorException;
36
use libredte\lib\Core\Package\Billing\Component\Document\Support\DocumentBag;
37
use libredte\lib\Core\Package\Billing\Component\Identifier\Contract\CafProviderInterface;
38
use Throwable;
39
40
/**
41
 * Clase para los procesadores de documentos en lote.
42
 */
43
#[Worker(name: 'batch_processor', component: 'document', package: 'billing')]
44
class BatchProcessorWorker extends AbstractWorker implements BatchProcessorWorkerInterface
45
{
46
    use StrategiesAwareTrait;
47
48
    /**
49
     * Esquema de las opciones.
50
     *
51
     * @var array<string,array|bool>
52
     */
53
    protected array $optionsSchema = [
54
        '__allowUndefinedKeys' => true,
55
        'strategy' => [
56
            'types' => 'string',
57
            'default' => 'spreadsheet.csv',
58
        ],
59
        'complete' => [
60
            'types' => 'bool',
61
            'default' => true,
62
        ],
63
        'stamp' => [
64
            'types' => 'bool',
65
            'default' => true,
66
        ],
67
    ];
68
69
    /**
70
     * Constructor del worker y sus dependencias.
71
     *
72
     * @param CafProviderInterface $cafProvider
73
     * @param DocumentBagManagerWorkerInterface $documentBagManagerWorker
74
     * @param BuilderWorkerInterface $builderWorker
75
     * @param iterable $jobs
76
     * @param iterable $handlers
77
     * @param iterable $strategies
78
     */
79
    public function __construct(
80
        private CafProviderInterface $cafProvider,
81
        private DocumentBagManagerWorkerInterface $documentBagManagerWorker,
82
        private BuilderWorkerInterface $builderWorker,
83
        iterable $jobs = [],
84
        iterable $handlers = [],
85
        iterable $strategies = []
86
    ) {
87
        $this->setJobs($jobs);
88
        $this->setHandlers($handlers);
89
        $this->setStrategies($strategies);
90
    }
91
92
    /**
93
     * {@inheritDoc}
94
     */
95
    public function process(DocumentBatchInterface $batch): array
96
    {
97
        $emisor = $batch->getEmisor();
98
        $options = $this->resolveOptions($batch->getOptions());
99
100
        // Cargar documentos desde el archivo.
101
        $parsedDocuments = $this->loadDocumentsFromFile($batch);
102
103
        // Crear la bolsa de cada documento.
104
        $documentBags = [];
105
        foreach ($parsedDocuments as $parsedData) {
106
            $documentBag = new DocumentBag();
107
            $documentBag->setEmisor($emisor);
108
109
            // Completar el documento si así se solicitó.
110
            if ($options->get('complete')) {
111
                $parsedData = $this->completeParsedData(
112
                    $batch,
113
                    $parsedData
0 ignored issues
show
Bug introduced by
$parsedData of type libredte\lib\Core\Packag...tract\DocumentInterface is incompatible with the type array expected by parameter $data of libredte\lib\Core\Packag...r::completeParsedData(). ( Ignorable by Annotation )

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

113
                    /** @scrutinizer ignore-type */ $parsedData
Loading history...
114
                );
115
            }
116
117
            // Asignar documento parseado desde el archivo masivo.
118
            $documentBag->setParsedData($parsedData);
119
120
            // Normalizar lo básico de la bolsa del documento.
121
            // Esto es para poder tener el tipo de documento de los datos
122
            // parseados.
123
            $this->documentBagManagerWorker->normalize($documentBag);
124
125
            // Solicitar CAF al proveedor y asignar certificado si se solicitó.
126
            if ($options->get('stamp')) {
127
                // Buscar folio del documento (si existe) y obtener el CAF que
128
                // tiene ese folio.
129
                $folio = $documentBag->getFolio();
130
                $folio = is_int($folio) ? $folio : null;
131
                $cafBag = $this->cafProvider->retrieve(
132
                    $emisor,
0 ignored issues
show
Bug introduced by
It seems like $emisor can also be of type null; however, parameter $emisor of libredte\lib\Core\Packag...erInterface::retrieve() does only seem to accept libredte\lib\Core\Packag...ontract\EmisorInterface, maybe add an additional type check? ( Ignorable by Annotation )

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

132
                    /** @scrutinizer ignore-type */ $emisor,
Loading history...
133
                    $documentBag->getTipoDocumento(),
0 ignored issues
show
Bug introduced by
It seems like $documentBag->getTipoDocumento() can also be of type null; however, parameter $tipoDocumento of libredte\lib\Core\Packag...erInterface::retrieve() does only seem to accept libredte\lib\Core\Packag...\TipoDocumentoInterface, maybe add an additional type check? ( Ignorable by Annotation )

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

133
                    /** @scrutinizer ignore-type */ $documentBag->getTipoDocumento(),
Loading history...
134
                    $folio
135
                );
136
137
                // Si no había un folio en el documento se deberá asignar el
138
                // siguiente folio del CAF a los datos de la bolsa del
139
                // documento.
140
                if ($folio === null) {
141
                    $siguienteFolio = $cafBag->getSiguienteFolio();
142
                    $documentBag->setFolio($siguienteFolio);
143
                }
144
145
                // Asignar CAF y certificado a la bolsa del documento.
146
                $documentBag->setCaf($cafBag->getCaf());
147
                $documentBag->setCertificate($batch->getCertificate());
148
            }
149
150
            // Construir el documento a partir de los datos de la bolsa.
151
            $this->builderWorker->build($documentBag);
152
153
            // Agregar la bolsa al listado de bolsas que se generaron a partir
154
            // del archivo de emisión masiva.
155
            $documentBags[] = $documentBag;
156
        }
157
158
        // Asignar bolsas con los documentos al lote procesado.
159
        $batch->setDocumentBags($documentBags);
160
161
        // Entregar las bolsas de documentos.
162
        return $documentBags;
163
    }
164
165
    /**
166
     * Carga los documentos desde el archivo según la estrategia de
167
     * procesamiento en lote que se haya solicitado.
168
     *
169
     * @param DocumentBatchInterface $batch
170
     * @return array
171
     */
172
    private function loadDocumentsFromFile(DocumentBatchInterface $batch): array
173
    {
174
        $options = $this->resolveOptions($batch->getBatchProcessorOptions());
175
        $strategy = $this->getStrategy($options->get('strategy'));
176
177
        assert($strategy instanceof BatchProcessorStrategyInterface);
178
179
        try {
180
            $documents = $strategy->process($batch);
181
        } catch (Throwable $e) {
182
            throw new BatchProcessorException(
183
                message: $e->getMessage(),
184
                documentBatch: $batch
185
            );
186
        }
187
188
        return $documents;
189
    }
190
191
    /**
192
     * Completa los datos del documento parseado desde el archivo masivo.
193
     *
194
     * @param DocumentBatchInterface $batch
195
     * @param array $data
196
     * @return array
197
     */
198
    private function completeParsedData(
199
        DocumentBatchInterface $batch,
200
        array $data
201
    ): array {
202
        $emisor = $batch->getEmisor();
203
204
        $data['Encabezado']['Emisor']['RUTEmisor'] =
205
            ($data['Encabezado']['Emisor']['RUTEmisor'] ?? false)
206
            ?: $emisor->getRut()
207
        ;
208
        $data['Encabezado']['Emisor']['RznSoc'] =
209
            ($data['Encabezado']['Emisor']['RznSoc'] ?? false)
210
            ?: $emisor->getRazonSocial()
211
        ;
212
        $data['Encabezado']['Emisor']['GiroEmis'] =
213
            ($data['Encabezado']['Emisor']['GiroEmis'] ?? false)
214
            ?: ($emisor->getGiro() ?? false)
215
        ;
216
        $data['Encabezado']['Emisor']['Telefono'] =
217
            ($data['Encabezado']['Emisor']['Telefono'] ?? false)
218
            ?: ($emisor->getTelefono() ?? false)
219
        ;
220
        $data['Encabezado']['Emisor']['CorreoEmisor'] =
221
            ($data['Encabezado']['Emisor']['CorreoEmisor'] ?? false)
222
            ?: ($emisor->getEmail() ?? false)
223
        ;
224
        $data['Encabezado']['Emisor']['Acteco'] =
225
            ($data['Encabezado']['Emisor']['Acteco'] ?? false)
226
            ?: ($emisor->getActividadEconomica() ?? false)
227
        ;
228
        $data['Encabezado']['Emisor']['DirOrigen'] =
229
            ($data['Encabezado']['Emisor']['DirOrigen'] ?? false)
230
            ?: ($emisor->getDireccion() ?? false)
231
        ;
232
        $data['Encabezado']['Emisor']['CmnaOrigen'] =
233
            ($data['Encabezado']['Emisor']['CmnaOrigen'] ?? false)
234
            ?: ($emisor->getComuna() ?? false)
235
        ;
236
        $data['Encabezado']['Emisor']['CdgSIISucur'] =
237
            ($data['Encabezado']['Emisor']['CdgSIISucur'] ?? false)
238
            ?: ($emisor->getCodigoSucursal() ?? false)
239
        ;
240
        $data['Encabezado']['Emisor']['CdgVendedor'] =
241
            ($data['Encabezado']['Emisor']['CdgVendedor'] ?? false)
242
            ?: ($emisor->getVendedor() ?? false)
243
        ;
244
245
        return $data;
246
    }
247
}
248