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\BatchProcessor\Strategy\Spreadsheet; |
26
|
|
|
|
27
|
|
|
use Derafu\Lib\Core\Foundation\Abstract\AbstractStrategy; |
28
|
|
|
use Derafu\Lib\Core\Helper\Csv; |
29
|
|
|
use Derafu\Lib\Core\Helper\Date; |
30
|
|
|
use Derafu\Lib\Core\Package\Prime\Component\Entity\Contract\EntityComponentInterface; |
31
|
|
|
use libredte\lib\Core\Package\Billing\Component\Document\Contract\BatchProcessorStrategyInterface; |
32
|
|
|
use libredte\lib\Core\Package\Billing\Component\Document\Contract\DocumentBatchInterface; |
33
|
|
|
use libredte\lib\Core\Package\Billing\Component\Document\Entity\AduanaMoneda; |
34
|
|
|
use libredte\lib\Core\Package\Billing\Component\Document\Exception\BatchProcessorException; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Estrategia "billing.document.batch_processor.strategy:spreadsheet.csv". |
38
|
|
|
* |
39
|
|
|
* Procesa en lote los documentos tributarios de un archivo CSV con el formato |
40
|
|
|
* estándar de LibreDTE. |
41
|
|
|
*/ |
42
|
|
|
class CsvBatchProcessorStrategy extends AbstractStrategy implements BatchProcessorStrategyInterface |
43
|
|
|
{ |
44
|
|
|
/** |
45
|
|
|
* Constructor de la estrategia con sus dependencias. |
46
|
|
|
* |
47
|
|
|
* @param EntityComponentInterface $entityComponent |
48
|
|
|
*/ |
49
|
1 |
|
public function __construct( |
50
|
|
|
private EntityComponentInterface $entityComponent |
51
|
|
|
) { |
52
|
1 |
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* {@inheritDoc} |
56
|
|
|
*/ |
57
|
1 |
|
public function process(DocumentBatchInterface $batch): array |
58
|
|
|
{ |
59
|
|
|
// Cargar archivo CSV y obtener los datos. |
60
|
1 |
|
$datos = Csv::read($batch->getFile()); |
61
|
1 |
|
$n_datos = count($datos); |
62
|
1 |
|
$documentos = []; |
63
|
1 |
|
$documento = []; |
64
|
|
|
|
65
|
|
|
// Procesar cada fila del archivo. |
66
|
1 |
|
for ($i = 1; $i < $n_datos; $i++) { |
67
|
|
|
// Si la fila corresponde a un documento nuevo. |
68
|
1 |
|
if (!empty($datos[$i][0])) { |
69
|
|
|
// Agregar el documento actual al listado si existe. |
70
|
1 |
|
if ($documento) { |
|
|
|
|
71
|
1 |
|
$documentos[] = $documento; |
72
|
|
|
} |
73
|
|
|
// Crear un nuevo documento. |
74
|
1 |
|
$documento = $this->createDocument($datos[$i]); |
75
|
|
|
} else { |
76
|
|
|
// Si la fila no corresponde a un documento nuevo, agregar |
77
|
|
|
// detalles al documento actual. |
78
|
1 |
|
if (!empty($datos[$i][13])) { |
79
|
1 |
|
$datosItem = array_merge( |
80
|
|
|
// Datos originales del item (vienen juntos en el |
81
|
|
|
// archivo). |
82
|
1 |
|
array_slice($datos[$i], 11, 8), |
83
|
|
|
|
84
|
|
|
// Datos adicionales del item (vienen después del item, |
85
|
|
|
// "al final", porque se añadieron después de los |
86
|
|
|
// previos al archivo). |
87
|
1 |
|
[ |
88
|
|
|
// CodImpAdic. |
89
|
1 |
|
!empty($datos[$i][38]) ? $datos[$i][38] : null, |
90
|
1 |
|
] |
91
|
1 |
|
); |
92
|
|
|
|
93
|
1 |
|
$this->addItem($documento, $datosItem); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
// Agregar referencias al documento. |
97
|
1 |
|
$this->addReference($documento, array_slice($datos[$i], 28, 5)); |
98
|
|
|
} |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
// Agregar el último documento procesado al listado. |
102
|
1 |
|
$documentos[] = $documento; |
103
|
|
|
|
104
|
1 |
|
return $documentos; |
|
|
|
|
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Crea un documento a partir de los datos proporcionados. |
109
|
|
|
* |
110
|
|
|
* Verifica los datos mínimos requeridos y genera la estructura base. |
111
|
|
|
* |
112
|
|
|
* También agrega ítems, transporte y referencias al documento. |
113
|
|
|
* |
114
|
|
|
* @param array $datos Datos para crear el documento. Los índices corresponden a: |
115
|
|
|
* - 0: Tipo de documento (obligatorio). |
116
|
|
|
* - 1: Folio del documento (obligatorio). |
117
|
|
|
* - 2: Fecha de emisión (opcional). |
118
|
|
|
* - 3: Fecha de vencimiento (opcional). |
119
|
|
|
* - 4: RUT del receptor (obligatorio). |
120
|
|
|
* - 5: Razón social del receptor (obligatoria si no es boleta). |
121
|
|
|
* - 6: Giro del receptor (obligatorio si no es boleta). |
122
|
|
|
* - 7: Contacto del receptor (opcional). |
123
|
|
|
* - 8: Correo del receptor (opcional, validado si se proporciona). |
124
|
|
|
* - 9: Dirección del receptor (obligatoria si no es boleta). |
125
|
|
|
* - 10: Comuna del receptor (obligatoria si no es boleta). |
126
|
|
|
* - 33: Tipo de moneda (opcional, por defecto USD si aplica). |
127
|
|
|
* - 34: Número de identificación del receptor extranjero (opcional). |
128
|
|
|
* - 35: Descuento global (opcional, porcentaje o monto). |
129
|
|
|
* - 36: Nombre del PDF (opcional). |
130
|
|
|
* - 37: Forma de pago (opcional, 1, 2 o 3). |
131
|
|
|
* - 38: Código de impuesto adicional (opcional). |
132
|
|
|
* @return array Estructura del documento generado. |
133
|
|
|
* @throws BatchProcessorException Si faltan datos mínimos o son inválidos. |
134
|
|
|
*/ |
135
|
1 |
|
private function createDocument(array $datos): array |
136
|
|
|
{ |
137
|
|
|
// Verificar datos mínimos obligatorios. |
138
|
1 |
|
if (empty($datos[0])) { |
139
|
|
|
throw new BatchProcessorException('Falta tipo de documento.'); |
140
|
|
|
} |
141
|
1 |
|
if (empty($datos[1])) { |
142
|
|
|
throw new BatchProcessorException('Falta folio del documento.'); |
143
|
|
|
} |
144
|
1 |
|
if (empty($datos[4])) { |
145
|
|
|
throw new BatchProcessorException('Falta RUT del receptor.'); |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
// Verificar datos si no es boleta. |
149
|
1 |
|
if (!in_array($datos[0], [39, 41])) { |
150
|
1 |
|
if (empty($datos[5])) { |
151
|
|
|
throw new BatchProcessorException( |
152
|
|
|
'Falta razón social del receptor.' |
153
|
|
|
); |
154
|
|
|
} |
155
|
1 |
|
if (empty($datos[6])) { |
156
|
|
|
throw new BatchProcessorException( |
157
|
|
|
'Falta giro del receptor.' |
158
|
|
|
); |
159
|
|
|
} |
160
|
1 |
|
if (empty($datos[9])) { |
161
|
|
|
throw new BatchProcessorException( |
162
|
|
|
'Falta dirección del receptor.' |
163
|
|
|
); |
164
|
|
|
} |
165
|
1 |
|
if (empty($datos[10])) { |
166
|
|
|
throw new BatchProcessorException( |
167
|
|
|
'Falta comuna del receptor.' |
168
|
|
|
); |
169
|
|
|
} |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
// Crear la estructura base del documento. |
173
|
1 |
|
$documento = $this->setInitialDTE($datos); |
174
|
|
|
|
175
|
|
|
// Validar correo electrónico. |
176
|
1 |
|
if (!empty($datos[8])) { |
177
|
1 |
|
if (!filter_var($datos[8], FILTER_VALIDATE_EMAIL)) { |
178
|
|
|
throw new BatchProcessorException(sprintf( |
179
|
|
|
'Correo electrónico %s no es válido.', |
180
|
|
|
$datos[8] |
181
|
|
|
)); |
182
|
|
|
} |
183
|
1 |
|
$documento['Encabezado']['Receptor']['CorreoRecep'] = mb_substr( |
184
|
1 |
|
trim($datos[8]), |
185
|
1 |
|
0, |
186
|
1 |
|
80 |
187
|
1 |
|
); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
// Manejar tipos de moneda para documentos de exportación. |
191
|
1 |
|
if (in_array($documento['Encabezado']['IdDoc']['TipoDTE'], [110,111,112])) { |
192
|
|
|
// Agregar moneda. |
193
|
1 |
|
if (empty($datos[33])) { |
194
|
1 |
|
$datos[33] = 'USD'; |
195
|
|
|
} |
196
|
1 |
|
$moneda = $this->getCurrency($datos[33]); |
197
|
1 |
|
if (empty($moneda)) { |
198
|
|
|
throw new BatchProcessorException( |
199
|
|
|
sprintf( |
200
|
|
|
'El tipo de moneda %s no está permitido, solo: USD, EUR y CLP.', |
201
|
|
|
$datos[33] |
202
|
|
|
) |
203
|
|
|
); |
204
|
|
|
} |
205
|
1 |
|
$documento['Encabezado']['Totales']['TpoMoneda'] = $moneda; |
206
|
|
|
|
207
|
|
|
// Agregar ID del receptor. |
208
|
1 |
|
if (!empty($datos[34])) { |
209
|
1 |
|
$documento['Encabezado']['Receptor']['Extranjero']['NumId'] = mb_substr( |
210
|
1 |
|
trim($datos[34]), |
211
|
1 |
|
0, |
212
|
1 |
|
20 |
213
|
1 |
|
); |
214
|
|
|
} |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
// Procesar descuentos globales. |
218
|
1 |
|
if (!empty($datos[35])) { |
219
|
1 |
|
if (strpos($datos[35], '%')) { |
220
|
1 |
|
$TpoValor_global = '%'; |
221
|
1 |
|
$ValorDR_global = (float)substr($datos[35], 0, -1); |
222
|
|
|
} else { |
223
|
1 |
|
$TpoValor_global = '$'; |
224
|
1 |
|
$ValorDR_global = (float)$datos[35]; |
225
|
|
|
} |
226
|
1 |
|
$documento['DscRcgGlobal'][] = [ |
227
|
1 |
|
'TpoMov' => 'D', |
228
|
1 |
|
'TpoValor' => $TpoValor_global, |
229
|
1 |
|
'ValorDR' => $ValorDR_global, |
230
|
1 |
|
'IndExeDR' => 1, |
231
|
1 |
|
]; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
// Asignar el nombre del PDF si se proporciona. |
235
|
|
|
// Esto permite asociar un archivo PDF específico al documento. |
236
|
1 |
|
if (!empty($datos[36])) { |
237
|
|
|
$documento['LibreDTE']['pdf']['nombre'] = $datos[36]; |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
// Procesar forma de pago. |
241
|
1 |
|
if (!empty($datos[37])) { |
242
|
|
|
if (!in_array($datos[37], [1, 2, 3])) { |
243
|
|
|
throw new BatchProcessorException(sprintf( |
244
|
|
|
'Forma de pago de código %s es incorrecta, debe ser: 1 (contado), 2 (crédito) o 3 (sin costo).', |
245
|
|
|
$datos[37] |
246
|
|
|
)); |
247
|
|
|
} |
248
|
|
|
$documento['Encabezado']['IdDoc']['FmaPago'] = (int) $datos[37]; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
// Agregar ítems, transporte y referencias. |
252
|
1 |
|
$datosItem = array_merge( |
253
|
|
|
// Datos originales del item (vienen juntos en el archivo). |
254
|
1 |
|
array_slice($datos, 11, 8), |
255
|
|
|
|
256
|
|
|
// Datos adicionales del item (vienen después del item, "al final", |
257
|
|
|
// porque se añadieron después de los previos al archivo) |
258
|
1 |
|
[ |
259
|
|
|
// CodImpAdic. |
260
|
1 |
|
!empty($datos[38]) ? $datos[38] : null, |
261
|
1 |
|
] |
262
|
1 |
|
); |
263
|
|
|
|
264
|
1 |
|
$this->addItem($documento, $datosItem); |
265
|
1 |
|
$this->addTransport($documento, array_slice($datos, 22, 6)); |
266
|
1 |
|
$this->addReference($documento, array_slice($datos, 28, 5)); |
267
|
|
|
|
268
|
1 |
|
return $documento; |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* Genera la estructura inicial del DTE. |
273
|
|
|
* |
274
|
|
|
* Este método crea un arreglo con la estructura base del DTE, incluyendo |
275
|
|
|
* encabezado, emisor, receptor y detalles. Configura valores |
276
|
|
|
* predeterminados para los campos opcionales y procesa algunos datos de |
277
|
|
|
* entrada. |
278
|
|
|
* |
279
|
|
|
* @param array $datos Datos de entrada para generar la estructura del DTE. |
280
|
|
|
* @return array Arreglo con la estructura inicial del DTE. |
281
|
|
|
*/ |
282
|
1 |
|
private function setInitialDTE(array $datos): array |
283
|
|
|
{ |
284
|
1 |
|
return [ |
285
|
1 |
|
'Encabezado' => [ |
286
|
1 |
|
'IdDoc' => [ |
287
|
1 |
|
'TipoDTE' => (int) $datos[0], |
288
|
1 |
|
'Folio' => (int) $datos[1], |
289
|
1 |
|
'FchEmis' => ( |
290
|
1 |
|
!empty($datos[2]) && Date::validateAndConvert($datos[2], 'Y-m-d') !== null |
291
|
1 |
|
) ? $datos[2] : date('Y-m-d'), |
292
|
1 |
|
'TpoTranCompra' => false, |
293
|
1 |
|
'TpoTranVenta' => false, |
294
|
1 |
|
'FmaPago' => false, |
295
|
1 |
|
'FchCancel' => false, |
296
|
1 |
|
'PeriodoDesde' => !empty($datos[20]) && Date::validateAndConvert($datos[20], 'Y-m-d') !== null |
297
|
1 |
|
? $datos[20] |
298
|
|
|
: false, |
299
|
1 |
|
'PeriodoHasta' => !empty($datos[21]) && Date::validateAndConvert($datos[21], 'Y-m-d') !== null |
300
|
1 |
|
? $datos[21] |
301
|
|
|
: false, |
302
|
1 |
|
'MedioPago' => false, |
303
|
1 |
|
'TpoCtaPago' => false, |
304
|
1 |
|
'NumCtaPago' => false, |
305
|
1 |
|
'BcoPago' => false, |
306
|
1 |
|
'TermPagoGlosa' => !empty($datos[19]) |
307
|
1 |
|
? mb_substr(trim($datos[19]), 0, 100) |
308
|
|
|
: false, |
309
|
1 |
|
'FchVenc' => !empty($datos[3]) && Date::validateAndConvert($datos[3], 'Y-m-d') !== null |
310
|
1 |
|
? $datos[3] |
311
|
|
|
: false, |
312
|
1 |
|
], |
313
|
1 |
|
'Emisor' => [ |
314
|
1 |
|
'RUTEmisor' => false, |
315
|
1 |
|
'RznSoc' => false, |
316
|
1 |
|
'GiroEmis' => false, |
317
|
1 |
|
'Telefono' => false, |
318
|
1 |
|
'CorreoEmisor' => false, |
319
|
1 |
|
'Acteco' => false, |
320
|
1 |
|
'CdgSIISucur' => false, |
321
|
1 |
|
'DirOrigen' => false, |
322
|
1 |
|
'CmnaOrigen' => false, |
323
|
1 |
|
'CdgVendedor' => false, |
324
|
1 |
|
], |
325
|
1 |
|
'Receptor' => [ |
326
|
1 |
|
'RUTRecep' => str_replace('.', '', $datos[4]), |
327
|
1 |
|
'CdgIntRecep' => false, |
328
|
1 |
|
'RznSocRecep' => !empty($datos[5]) |
329
|
1 |
|
? mb_substr(trim($datos[5]), 0, 100) |
330
|
|
|
: false, |
331
|
1 |
|
'GiroRecep' => !empty($datos[6]) |
332
|
1 |
|
? mb_substr(trim($datos[6]), 0, 40) |
333
|
|
|
: false, |
334
|
1 |
|
'Contacto' => !empty($datos[7]) |
335
|
1 |
|
? mb_substr(trim($datos[7]), 0, 80) |
336
|
|
|
: false, |
337
|
1 |
|
'CorreoRecep' => false, |
338
|
1 |
|
'DirRecep' => !empty($datos[9]) |
339
|
1 |
|
? mb_substr(trim($datos[9]), 0, 70) |
340
|
|
|
: false, |
341
|
1 |
|
'CmnaRecep' => !empty($datos[10]) |
342
|
1 |
|
? mb_substr(trim($datos[10]), 0, 20) |
343
|
|
|
: false, |
344
|
1 |
|
'CiudadRecep' => false, |
345
|
1 |
|
], |
346
|
1 |
|
'RUTSolicita' => false, |
347
|
1 |
|
], |
348
|
1 |
|
'Detalle' => [], |
349
|
1 |
|
]; |
350
|
|
|
|
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
/** |
354
|
|
|
* Agrega un ítem al documento. |
355
|
|
|
* |
356
|
|
|
* Procesa los datos de un ítem y lo agrega al arreglo de detalles. Valida |
357
|
|
|
* que los campos mínimos estén presentes y ajusta la longitud de los datos. |
358
|
|
|
* |
359
|
|
|
* @param array &$documento Documento al que se agregará el ítem. Modificado |
360
|
|
|
* directamente. |
361
|
|
|
* @param array $item Datos del ítem. Los índices corresponden a: |
362
|
|
|
* - 0: Código del ítem (opcional). |
363
|
|
|
* - 1: Indicador de exención (opcional). |
364
|
|
|
* - 2: Nombre del ítem (obligatorio). |
365
|
|
|
* - 3: Descripción del ítem (opcional). |
366
|
|
|
* - 4: Cantidad del ítem (obligatorio). |
367
|
|
|
* - 5: Unidad de medida (opcional). |
368
|
|
|
* - 6: Precio del ítem (obligatorio). |
369
|
|
|
* - 7: Descuento (opcional, porcentaje o monto). |
370
|
|
|
* - 8: Código de impuesto adicional (opcional). |
371
|
|
|
* @return void |
372
|
|
|
* @throws BatchProcessorException Si faltan datos obligatorios. |
373
|
|
|
*/ |
374
|
1 |
|
private function addItem(array &$documento, array $item): void |
375
|
|
|
{ |
376
|
|
|
// Verificar datos mínimos obligatorios. |
377
|
1 |
|
if (empty($item[2])) { |
378
|
|
|
throw new BatchProcessorException( |
379
|
|
|
'Falta nombre del item.' |
380
|
|
|
); |
381
|
|
|
} |
382
|
1 |
|
if (empty($item[4])) { |
383
|
|
|
throw new BatchProcessorException( |
384
|
|
|
'Falta cantidad del item.' |
385
|
|
|
); |
386
|
|
|
} |
387
|
1 |
|
if (empty($item[6])) { |
388
|
|
|
throw new BatchProcessorException( |
389
|
|
|
'Falta precio del item.' |
390
|
|
|
); |
391
|
|
|
} |
392
|
|
|
|
393
|
|
|
// Crear el detalle del ítem. |
394
|
1 |
|
$detalle = [ |
395
|
1 |
|
'NmbItem' => mb_substr(trim($item[2]), 0, 80), |
396
|
1 |
|
'QtyItem' => (float)str_replace(',', '.', $item[4]), |
397
|
1 |
|
'PrcItem' => (float)str_replace(',', '.', $item[6]), |
398
|
1 |
|
]; |
399
|
|
|
|
400
|
|
|
// Agregar código del ítem si está presente. |
401
|
1 |
|
if (!empty($item[0])) { |
402
|
1 |
|
$detalle['CdgItem'] = [ |
403
|
1 |
|
'TpoCodigo' => 'INT1', |
404
|
1 |
|
'VlrCodigo' => mb_substr(trim($item[0]), 0, 35), |
405
|
1 |
|
]; |
406
|
|
|
} |
407
|
|
|
|
408
|
|
|
// Agregar indicador de exención si está presente. |
409
|
1 |
|
if (!empty($item[1])) { |
410
|
1 |
|
$detalle['IndExe'] = (int)$item[1]; |
411
|
|
|
} |
412
|
|
|
|
413
|
|
|
// Agregar descripción del ítem si está presente. |
414
|
1 |
|
if (!empty($item[3])) { |
415
|
1 |
|
$detalle['DscItem'] = mb_substr(trim($item[3]), 0, 1000); |
416
|
|
|
} |
417
|
|
|
|
418
|
|
|
// Agregar unidad de medida si está presente. |
419
|
1 |
|
if (!empty($item[5])) { |
420
|
1 |
|
$detalle['UnmdItem'] = mb_substr(trim($item[5]), 0, 4); |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
|
424
|
|
|
// Procesar y agregar descuento si está presente. |
425
|
1 |
|
if (!empty($item[7])) { |
426
|
1 |
|
if (strpos($item[7], '%')) { |
427
|
1 |
|
$detalle['DescuentoPct'] = (float)substr($item[7], 0, -1); |
428
|
|
|
} else { |
429
|
1 |
|
$detalle['DescuentoMonto'] = (float)$item[7]; |
430
|
|
|
} |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
// Agregar código de impuesto adicional si está presente. |
434
|
1 |
|
if (!empty($item[8])) { |
435
|
1 |
|
$detalle['CodImpAdic'] = (int)trim($item[8]); |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
// Agregar el detalle al documento. |
439
|
1 |
|
$documento['Detalle'][] = $detalle; |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
/** |
443
|
|
|
* Agrega información de transporte a un documento. |
444
|
|
|
* |
445
|
|
|
* Procesa los datos de transporte proporcionados y los agrega al arreglo |
446
|
|
|
* `Transporte` dentro del documento. Los datos incluyen información de |
447
|
|
|
* patente, transportista, chofer y destino. |
448
|
|
|
* |
449
|
|
|
* @param array &$documento Documento al que se agregará la información de |
450
|
|
|
* transporte. Se pasa por referencia para modificarlo. |
451
|
|
|
* @param array $transporte Datos de transporte a procesar. Los índices son: |
452
|
|
|
* - 0: Patente del vehículo (opcional). |
453
|
|
|
* - 1: RUT del transportista (opcional). |
454
|
|
|
* - 2: RUT del chofer (opcional). |
455
|
|
|
* - 3: Nombre del chofer (opcional). |
456
|
|
|
* - 4: Dirección del destino (opcional). |
457
|
|
|
* - 5: Comuna del destino (opcional). |
458
|
|
|
* @return void Modifica el documento directamente. |
459
|
|
|
*/ |
460
|
1 |
|
private function addTransport(array &$documento, array $transporte): void |
461
|
|
|
{ |
462
|
1 |
|
$vacios = true; |
463
|
|
|
|
464
|
|
|
// Verificar si todos los datos de transporte están vacíos. |
465
|
1 |
|
foreach ($transporte as $t) { |
466
|
1 |
|
if (!empty($t)) { |
467
|
1 |
|
$vacios = false; |
468
|
|
|
} |
469
|
|
|
} |
470
|
1 |
|
if ($vacios) { |
471
|
1 |
|
return; |
472
|
|
|
} |
473
|
|
|
|
474
|
|
|
// Procesar cada dato de transporte y agregarlo al documento si está |
475
|
|
|
// presente. |
476
|
1 |
|
if ($transporte[0]) { |
477
|
1 |
|
$documento['Encabezado']['Transporte']['Patente'] = mb_substr( |
478
|
1 |
|
trim($transporte[0]), |
479
|
1 |
|
0, |
480
|
1 |
|
8 |
481
|
1 |
|
); |
482
|
|
|
} |
483
|
1 |
|
if ($transporte[1]) { |
484
|
|
|
$documento['Encabezado']['Transporte']['RUTTrans'] = mb_substr( |
485
|
|
|
str_replace('.', '', trim($transporte[1])), |
486
|
|
|
0, |
487
|
|
|
10 |
488
|
|
|
); |
489
|
|
|
} |
490
|
1 |
|
if ($transporte[2] && $transporte[3]) { |
491
|
|
|
$documento['Encabezado']['Transporte']['Chofer']['RUTChofer'] = |
492
|
|
|
mb_substr( |
493
|
|
|
str_replace('.', '', trim($transporte[2])), |
494
|
|
|
0, |
495
|
|
|
10 |
496
|
|
|
) |
497
|
|
|
; |
498
|
|
|
$documento['Encabezado']['Transporte']['Chofer']['NombreChofer'] = |
499
|
|
|
mb_substr( |
500
|
|
|
trim($transporte[3]), |
501
|
|
|
0, |
502
|
|
|
30 |
503
|
|
|
) |
504
|
|
|
; |
505
|
|
|
} |
506
|
1 |
|
if ($transporte[4]) { |
507
|
1 |
|
$documento['Encabezado']['Transporte']['DirDest'] = mb_substr( |
508
|
1 |
|
trim($transporte[4]), |
509
|
1 |
|
0, |
510
|
1 |
|
70 |
511
|
1 |
|
); |
512
|
|
|
} |
513
|
1 |
|
if ($transporte[5]) { |
514
|
1 |
|
$documento['Encabezado']['Transporte']['CmnaDest'] = mb_substr( |
515
|
1 |
|
trim($transporte[5]), |
516
|
1 |
|
0, |
517
|
1 |
|
20 |
518
|
1 |
|
); |
519
|
|
|
} |
520
|
|
|
} |
521
|
|
|
|
522
|
|
|
/** |
523
|
|
|
* Agrega una referencia a un documento. |
524
|
|
|
* |
525
|
|
|
* Procesa los datos de referencia y los agrega al arreglo `Referencia` |
526
|
|
|
* dentro del documento. Valida los campos obligatorios y ajusta su longitud |
527
|
|
|
* si es necesario. |
528
|
|
|
* |
529
|
|
|
* @param array &$documento Documento al que se agregará la referencia. |
530
|
|
|
* Se pasa por referencia para modificarlo. |
531
|
|
|
* @param array $referencia Datos de la referencia a agregar. Los índices |
532
|
|
|
* deben ser: |
533
|
|
|
* - 0: Tipo del documento referenciado (obligatorio). |
534
|
|
|
* - 1: Folio del documento referenciado (obligatorio). |
535
|
|
|
* - 2: Fecha del documento en formato AAAA-MM-DD (obligatorio). |
536
|
|
|
* - 3: Código de referencia (opcional). |
537
|
|
|
* - 4: Razón de la referencia (opcional). |
538
|
|
|
* @return void Modifica el documento directamente. |
539
|
|
|
* @throws BatchProcessorException Si algún campo obligatorio está vacío o |
540
|
|
|
* no es válido. |
541
|
|
|
*/ |
542
|
1 |
|
private function addReference(array &$documento, array $referencia): void |
543
|
|
|
{ |
544
|
1 |
|
$Referencia = []; |
545
|
1 |
|
$vacios = true; |
546
|
1 |
|
foreach ($referencia as $r) { |
547
|
1 |
|
if (!empty($r)) { |
548
|
1 |
|
$vacios = false; |
549
|
|
|
} |
550
|
|
|
} |
551
|
1 |
|
if ($vacios) { |
552
|
1 |
|
return; |
553
|
|
|
} |
554
|
1 |
|
if (empty($referencia[0])) { |
555
|
|
|
throw new BatchProcessorException( |
556
|
|
|
'Tipo del documento de referencia no puede estar vacío.' |
557
|
|
|
); |
558
|
|
|
} |
559
|
1 |
|
$Referencia['TpoDocRef'] = mb_substr(trim($referencia[0]), 0, 3); |
560
|
1 |
|
if (empty($referencia[1])) { |
561
|
|
|
throw new BatchProcessorException( |
562
|
|
|
'Folio del documento de referencia no puede estar vacío.' |
563
|
|
|
); |
564
|
|
|
} |
565
|
1 |
|
$Referencia['FolioRef'] = mb_substr(trim($referencia[1]), 0, 18); |
566
|
|
|
|
567
|
|
|
if ( |
568
|
1 |
|
empty($referencia[2]) |
569
|
1 |
|
&& Date::validateAndConvert($referencia[2], 'Y-m-d') !== null |
570
|
|
|
) { |
571
|
|
|
throw new BatchProcessorException( |
572
|
|
|
'Fecha del documento de referencia debe ser en formato AAAA-MM-DD.' |
573
|
|
|
); |
574
|
|
|
} |
575
|
1 |
|
$Referencia['FchRef'] = $referencia[2]; |
576
|
1 |
|
if (!empty($referencia[3])) { |
577
|
1 |
|
$Referencia['CodRef'] = (int) $referencia[3]; |
578
|
|
|
} |
579
|
1 |
|
if (!empty($referencia[4])) { |
580
|
1 |
|
$Referencia['RazonRef'] = mb_substr(trim($referencia[4]), 0, 90); |
581
|
|
|
} |
582
|
1 |
|
$documento['Referencia'][] = $Referencia; |
583
|
|
|
} |
584
|
|
|
|
585
|
|
|
/** |
586
|
|
|
* Obtiene la glosa de una moneda a partir de su código ISO. |
587
|
|
|
* |
588
|
|
|
* Este método busca en el repositorio de la entidad `AduanaMoneda` un |
589
|
|
|
* registro que coincida con el código ISO proporcionado. Si encuentra un |
590
|
|
|
* resultado, devuelve la glosa asociada; de lo contrario, retorna `null`. |
591
|
|
|
* |
592
|
|
|
* @param string $moneda Código ISO de la moneda que se desea buscar. |
593
|
|
|
* @return string|null La glosa de la moneda o `null` si no existe. |
594
|
|
|
*/ |
595
|
1 |
|
private function getCurrency(string $moneda): ?string |
596
|
|
|
{ |
597
|
|
|
// Buscar la moneda a través del repositorio. |
598
|
1 |
|
$result = $this->entityComponent |
599
|
1 |
|
->getRepository(AduanaMoneda::class) |
600
|
1 |
|
->findBy([ |
601
|
1 |
|
'codigo_iso' => $moneda, |
602
|
1 |
|
]); |
603
|
|
|
|
604
|
|
|
// Retornar null si no se encuentra ningún resultado. |
605
|
1 |
|
if (empty($result)) { |
606
|
|
|
return null; |
607
|
|
|
} |
608
|
|
|
|
609
|
|
|
// Retornar la glosa de la primera coincidencia. |
610
|
1 |
|
return $result[0]->getGlosa(); |
611
|
|
|
} |
612
|
|
|
} |
613
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.