@devlas/dte-sii 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/BoletaService.js +109 -0
  2. package/CAF.js +173 -0
  3. package/CafSolicitor.js +380 -0
  4. package/Certificado.js +123 -0
  5. package/ConsumoFolio.js +376 -0
  6. package/DTE.js +399 -0
  7. package/EnviadorSII.js +1304 -0
  8. package/Envio.js +196 -0
  9. package/FolioRegistry.js +553 -0
  10. package/FolioService.js +703 -0
  11. package/LICENSE +27 -0
  12. package/LibroBase.js +134 -0
  13. package/LibroCompraVenta.js +205 -0
  14. package/LibroGuia.js +225 -0
  15. package/README.md +239 -0
  16. package/Signer.js +94 -0
  17. package/SiiCertificacion.js +1189 -0
  18. package/SiiPortalAuth.js +460 -0
  19. package/SiiSession.js +499 -0
  20. package/cert/BoletaCert.js +731 -0
  21. package/cert/CertFolioHelper.js +185 -0
  22. package/cert/CertRunner.js +2658 -0
  23. package/cert/ConfigLoader.js +133 -0
  24. package/cert/IntercambioCert.js +429 -0
  25. package/cert/LibroCompras.js +359 -0
  26. package/cert/LibroGuias.js +171 -0
  27. package/cert/LibroVentas.js +153 -0
  28. package/cert/MuestrasImpresas.js +676 -0
  29. package/cert/SetBase.js +321 -0
  30. package/cert/SetBasico.js +413 -0
  31. package/cert/SetCompra.js +472 -0
  32. package/cert/SetExenta.js +490 -0
  33. package/cert/SetGuia.js +283 -0
  34. package/cert/SetParser.js +1184 -0
  35. package/cert/SetsProvider.js +499 -0
  36. package/cert/Simulacion.js +521 -0
  37. package/cert/comunaOficina.js +460 -0
  38. package/cert/index.js +124 -0
  39. package/cert/types.js +330 -0
  40. package/dte-sii.d.ts +458 -0
  41. package/index.js +428 -0
  42. package/package.json +48 -0
  43. package/utils/c14n.js +275 -0
  44. package/utils/calculo.js +396 -0
  45. package/utils/config.js +276 -0
  46. package/utils/constants.js +302 -0
  47. package/utils/emisor.js +174 -0
  48. package/utils/endpoints.js +225 -0
  49. package/utils/error.js +235 -0
  50. package/utils/index.js +339 -0
  51. package/utils/logger.js +239 -0
  52. package/utils/pfx.js +203 -0
  53. package/utils/receptor.js +218 -0
  54. package/utils/referencia.js +169 -0
  55. package/utils/resolucion.js +119 -0
  56. package/utils/rut.js +169 -0
  57. package/utils/sanitize.js +124 -0
  58. package/utils/tokenCache.js +214 -0
  59. package/utils/xml.js +358 -0
  60. package/utils.js +4 -0
@@ -0,0 +1,521 @@
1
+ // Copyright (c) 2026 Devlas SpA — https://devlas.cl
2
+ // Licencia MIT. Ver archivo LICENSE para mas detalles.
3
+ /**
4
+ * Simulación - Generador del Set de Simulación para certificación SII
5
+ *
6
+ * La etapa de Simulación requiere enviar múltiples DTEs en un solo envío,
7
+ * simulando la operación real de la empresa. Usa todos los tipos de DTE
8
+ * de los sets anteriores.
9
+ *
10
+ * @module dte-sii/cert/Simulacion
11
+ */
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+
16
+ // Core
17
+ const { Certificado, CAF, DTE, EnvioDTE } = require('../index');
18
+ const { buildDetalle, buildDetalleGuia, buildDetalleCompra, calcularTotalesDesdeDetalle } = require('../index');
19
+
20
+ const normalizeText = (value) => String(value || '').trim();
21
+ const TASA_IVA = 19;
22
+
23
+ class Simulacion {
24
+ /**
25
+ * @param {Object} config
26
+ * @param {Object} config.emisor - { rut, razon_social, giro, acteco, direccion, comuna, ciudad, fch_resol, nro_resol }
27
+ * @param {Object} config.receptor - { rut, razon_social, giro, direccion, comuna, ciudad }
28
+ * @param {Object} config.certificado - Instancia de Certificado
29
+ * @param {Object} [config.resolucion] - { fecha, numero }
30
+ */
31
+ constructor(config) {
32
+ this.emisor = config.emisor;
33
+ this.receptor = config.receptor;
34
+ this.certificado = config.certificado;
35
+ this.resolucion = config.resolucion || {
36
+ fecha: config.emisor.fch_resol,
37
+ numero: config.emisor.nro_resol,
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Genera el EnvioDTE de simulación a partir de las estructuras
43
+ * @param {Object} estructuras - Estructuras del set de pruebas
44
+ * @param {Object} cafs - { tipoDte: CAF } pre-cargados
45
+ * @param {Object} folioHelper - Helper para gestionar folios
46
+ * @param {Object} [options] - Opciones
47
+ * @param {string} [options.fechaEmision] - Fecha de emisión (default: hoy)
48
+ * @returns {Object} { envioDte, dtes, xmlPath, plan }
49
+ */
50
+ generar(estructuras, cafs, folioHelper, options = {}) {
51
+ const fechaEmision = options.fechaEmision || this._getFechaHoy();
52
+ const plan = this._buildPlan(estructuras);
53
+ const docRefs = {};
54
+
55
+ if (plan.length < 10) {
56
+ console.warn('⚠️ Se recomienda mínimo 10 documentos para simulación.');
57
+ }
58
+
59
+ const envioDte = new EnvioDTE({ certificado: this.certificado });
60
+ const generatedDtes = [];
61
+
62
+ for (const doc of plan) {
63
+ const tipoDte = Number(doc.tipoDte || 33);
64
+ const caf = cafs[tipoDte];
65
+ if (!caf) {
66
+ throw new Error(`No hay CAF para tipo ${tipoDte}`);
67
+ }
68
+
69
+ // Obtener folio desde el CAF
70
+ const folio = folioHelper.reserveNextFolio({
71
+ tipoDte,
72
+ folioDesde: caf.getFolioDesde(),
73
+ folioHasta: caf.getFolioHasta(),
74
+ });
75
+ const base = doc.referenciaCaso ? docRefs[doc.referenciaCaso] : null;
76
+
77
+ // Resolver items
78
+ let items = doc.items || [];
79
+ if (doc.kind === 'basico' || doc.kind === 'exenta') {
80
+ items = this._resolveItems(doc, base, doc.kind === 'exenta');
81
+ }
82
+ if (doc.kind === 'compra' && base?.items?.length) {
83
+ items = items.map((item) => {
84
+ const original = base.items.find((i) => normalizeText(i.nombre) === normalizeText(item.nombre));
85
+ return { ...item, precio: item.precio ?? original?.precio ?? 1 };
86
+ });
87
+ }
88
+
89
+ // Receptor (para compra o guía con indTraslado=5, usar emisor)
90
+ const receptor = (doc.kind === 'compra' || this._shouldUseEmisorAsReceptor(doc)) ? {
91
+ rut: this.emisor.rut,
92
+ razon_social: this.emisor.razon_social,
93
+ giro: this.emisor.giro,
94
+ direccion: this.emisor.direccion,
95
+ comuna: this.emisor.comuna,
96
+ ciudad: this.emisor.ciudad || this.emisor.comuna,
97
+ } : this.receptor;
98
+
99
+ // Construir detalle y totales según tipo
100
+ const { detalle, totales } = this._buildDetalleYTotales(doc, items, tipoDte);
101
+
102
+ // Construir DTE
103
+ const dteDatos = {
104
+ Encabezado: {
105
+ IdDoc: {
106
+ TipoDTE: tipoDte,
107
+ Folio: folio,
108
+ FchEmis: fechaEmision,
109
+ ...(tipoDte === 33 ? { TpoTranVenta: 1 } : {}),
110
+ ...(tipoDte === 52 ? {
111
+ IndTraslado: doc.indTraslado,
112
+ ...(doc.tpoDespacho ? { TpoDespacho: doc.tpoDespacho } : {}),
113
+ } : {}),
114
+ },
115
+ Emisor: {
116
+ RUTEmisor: this.emisor.rut,
117
+ RznSoc: this.emisor.razon_social,
118
+ GiroEmis: this.emisor.giro,
119
+ Acteco: this.emisor.acteco,
120
+ DirOrigen: this.emisor.direccion,
121
+ CmnaOrigen: this.emisor.comuna,
122
+ CiudadOrigen: this.emisor.ciudad || this.emisor.comuna || 'Santiago',
123
+ },
124
+ Receptor: {
125
+ RUTRecep: receptor.rut,
126
+ RznSocRecep: receptor.razon_social,
127
+ GiroRecep: receptor.giro,
128
+ DirRecep: receptor.direccion,
129
+ CmnaRecep: receptor.comuna,
130
+ CiudadRecep: receptor.ciudad || receptor.comuna,
131
+ },
132
+ Totales: totales,
133
+ },
134
+ Detalle: detalle,
135
+ };
136
+
137
+ // Descuento global
138
+ if (doc.descuentoGlobalPct) {
139
+ dteDatos.DscRcgGlobal = [{
140
+ NroLinDR: 1,
141
+ TpoMov: 'D',
142
+ TpoValor: '%',
143
+ ValorDR: Number(doc.descuentoGlobalPct),
144
+ }];
145
+ }
146
+
147
+ // Referencia
148
+ if (doc.referenciaCaso && base) {
149
+ dteDatos.Referencia = [{
150
+ NroLinRef: 1,
151
+ TpoDocRef: base.tipoDte,
152
+ FolioRef: base.folio,
153
+ FchRef: base.fecha,
154
+ CodRef: doc.codRef,
155
+ RazonRef: doc.razonRef,
156
+ }];
157
+ }
158
+
159
+ // Generar DTE
160
+ const dte = new DTE(dteDatos);
161
+ dte.generarXML().timbrar(caf).firmar(this.certificado);
162
+ envioDte.agregar(dte);
163
+
164
+ generatedDtes.push({
165
+ tipoDte,
166
+ folio,
167
+ xml: dte.getXML(),
168
+ });
169
+
170
+ // Guardar referencia para NC/ND
171
+ if (doc.id) {
172
+ docRefs[doc.id] = {
173
+ tipoDte,
174
+ folio,
175
+ fecha: fechaEmision,
176
+ items,
177
+ };
178
+ }
179
+ }
180
+
181
+ // Carátula del envío
182
+ envioDte.setCaratula({
183
+ RutEmisor: this.emisor.rut,
184
+ RutEnvia: this.certificado.rut || this.emisor.rut,
185
+ RutReceptor: '60803000-K', // SII
186
+ FchResol: this.resolucion.fecha,
187
+ NroResol: this.resolucion.numero,
188
+ });
189
+ envioDte.generar();
190
+
191
+ return {
192
+ envioDte,
193
+ dtes: generatedDtes,
194
+ xml: envioDte.getXML(),
195
+ plan,
196
+ tiposUsados: [...new Set(plan.map(d => d.tipoDte))],
197
+ };
198
+ }
199
+
200
+ /**
201
+ * Construye el plan de documentos a generar
202
+ * @private
203
+ */
204
+ _buildPlan(estructuras) {
205
+ const plan = [];
206
+ const setBasico = estructuras?.setBasico;
207
+ const setExenta = estructuras?.setFacturaExenta;
208
+ const setGuia = estructuras?.setGuiaDespacho;
209
+ const setCompra = estructuras?.setFacturaCompra;
210
+
211
+ // Set Básico
212
+ (setBasico?.casosFactura || []).forEach((caso) => plan.push({
213
+ kind: 'basico', tipoDte: 33, id: caso.id,
214
+ items: caso.items || [], descuentoGlobalPct: caso.descuentoGlobalPct,
215
+ }));
216
+ (setBasico?.casosNC || []).forEach((caso) => plan.push({
217
+ kind: 'basico', tipoDte: 61, id: caso.id,
218
+ referenciaCaso: caso.referenciaCaso, codRef: caso.codRef,
219
+ razonRef: caso.razonRef, items: caso.items || [], itemsFromCaso: caso.itemsFromCaso,
220
+ }));
221
+ (setBasico?.casosND || []).forEach((caso) => plan.push({
222
+ kind: 'basico', tipoDte: 56, id: caso.id,
223
+ referenciaCaso: caso.referenciaCaso, codRef: caso.codRef,
224
+ razonRef: caso.razonRef, items: caso.items || [],
225
+ }));
226
+
227
+ // Set Factura Exenta
228
+ (setExenta?.casosFactura || []).forEach((caso) => plan.push({
229
+ kind: 'exenta', tipoDte: 34, id: caso.id, items: caso.items || [],
230
+ }));
231
+ (setExenta?.casosNC || []).forEach((caso) => plan.push({
232
+ kind: 'exenta', tipoDte: 61, id: caso.id,
233
+ referenciaCaso: caso.referenciaCaso, codRef: caso.codRef,
234
+ razonRef: caso.razonRef, items: caso.items || [],
235
+ }));
236
+ (setExenta?.casosND || []).forEach((caso) => plan.push({
237
+ kind: 'exenta', tipoDte: 56, id: caso.id,
238
+ referenciaCaso: caso.referenciaCaso, codRef: caso.codRef,
239
+ razonRef: caso.razonRef, items: caso.items || [],
240
+ }));
241
+
242
+ // Set Guía Despacho
243
+ (setGuia?.casos || []).forEach((caso) => plan.push({
244
+ kind: 'guia', tipoDte: 52, id: caso.id,
245
+ indTraslado: caso.indTraslado, tpoDespacho: caso.tpoDespacho, items: caso.items || [],
246
+ }));
247
+
248
+ // Set Factura Compra
249
+ if (setCompra?.casoFactura) {
250
+ plan.push({
251
+ kind: 'compra', tipoDte: 46, id: setCompra.casoFactura.id,
252
+ items: setCompra.casoFactura.items || [],
253
+ });
254
+ }
255
+ if (setCompra?.casoNC) {
256
+ plan.push({
257
+ kind: 'compra', tipoDte: 61, id: setCompra.casoNC.id,
258
+ referenciaCaso: setCompra.casoNC.referenciaCaso, codRef: setCompra.casoNC.codRef,
259
+ razonRef: setCompra.casoNC.razonRef, items: setCompra.casoNC.items || [],
260
+ });
261
+ }
262
+ if (setCompra?.casoND) {
263
+ plan.push({
264
+ kind: 'compra', tipoDte: 56, id: setCompra.casoND.id,
265
+ referenciaCaso: setCompra.casoND.referenciaCaso, codRef: setCompra.casoND.codRef,
266
+ razonRef: setCompra.casoND.razonRef, items: setCompra.casoND.items || [],
267
+ });
268
+ }
269
+
270
+ return plan;
271
+ }
272
+
273
+ /**
274
+ * Resuelve items heredados del caso referenciado
275
+ * @private
276
+ */
277
+ _resolveItems(caso, base, exentoDefault) {
278
+ let items = caso.items || [];
279
+
280
+ if (caso.itemsFromCaso && base?.items?.length) {
281
+ items = base.items;
282
+ }
283
+
284
+ if (!items || items.length === 0) {
285
+ items = [{
286
+ nombre: caso.razonRef || 'CORRECCION',
287
+ cantidad: 1,
288
+ precio: 0,
289
+ exento: !!exentoDefault,
290
+ }];
291
+ }
292
+
293
+ const razon = (caso.razonRef || '').toUpperCase();
294
+ const esDevolucion = razon.includes('DEVOLUCION') || razon.includes('DEVOLUCIÓN');
295
+ const esModificaMonto = razon.includes('MODIFICA MONTO');
296
+
297
+ if (caso.codRef === 3 && esDevolucion && base?.items?.length) {
298
+ items = base.items.map((bi) => ({ ...bi, exento: exentoDefault || bi.exento }));
299
+ } else if (caso.codRef === 3 && esModificaMonto && base?.items?.length && items.length > 0) {
300
+ items = items.map((ncItem) => {
301
+ const nombreNc = normalizeText(ncItem.nombre).toUpperCase();
302
+ const itemOriginal = base.items.find((bi) => normalizeText(bi.nombre).toUpperCase() === nombreNc);
303
+ if (itemOriginal?.cantidad) {
304
+ return { ...ncItem, cantidad: itemOriginal.cantidad, exento: exentoDefault || ncItem.exento };
305
+ }
306
+ return { ...ncItem, exento: exentoDefault || ncItem.exento };
307
+ });
308
+ }
309
+
310
+ if (exentoDefault) {
311
+ items = items.map((i) => ({ ...i, exento: true }));
312
+ }
313
+
314
+ return items;
315
+ }
316
+
317
+ /**
318
+ * Construye detalle y totales según tipo de documento
319
+ * @private
320
+ */
321
+ _buildDetalleYTotales(doc, items, tipoDte) {
322
+ let detalle, totales;
323
+
324
+ if (doc.kind === 'guia') {
325
+ detalle = this._buildDetalleGuia(items);
326
+ totales = this._calcularTotalesGuia(detalle);
327
+ } else if (doc.kind === 'compra') {
328
+ detalle = this._buildDetalleCompra(items);
329
+ totales = this._calcularTotalesFacturaCompra(detalle);
330
+ } else {
331
+ detalle = this._buildDetalleGeneral(items, { allowIndExe: doc.kind === 'exenta' || doc.kind === 'basico' });
332
+ totales = this._calcularTotalesGeneral(items, doc.descuentoGlobalPct);
333
+ }
334
+
335
+ return { detalle, totales };
336
+ }
337
+
338
+ /**
339
+ * Construye detalle para factura/NC/ND general
340
+ * @private
341
+ */
342
+ _buildDetalleGeneral(items = [], options = {}) {
343
+ return items.map((i, idx) => {
344
+ const qty = i.cantidad ?? 1;
345
+ const prc = i.precio ?? 0;
346
+ const base = Math.round(qty * prc);
347
+ const descuentoPct = Number(i.descuentoPct || 0);
348
+ const descuentoMonto = descuentoPct > 0 ? Math.round(base * (descuentoPct / 100)) : 0;
349
+ const monto = base - descuentoMonto;
350
+ const det = {
351
+ NroLinDet: idx + 1,
352
+ ...(options.allowIndExe && i.exento ? { IndExe: 1 } : {}),
353
+ NmbItem: normalizeText(i.nombre),
354
+ };
355
+ if (prc > 0 || options.forcePriced) {
356
+ det.QtyItem = qty;
357
+ if (i.unidad) det.UnmdItem = i.unidad;
358
+ det.PrcItem = prc;
359
+ if (descuentoPct > 0) {
360
+ det.DescuentoPct = descuentoPct;
361
+ det.DescuentoMonto = descuentoMonto;
362
+ }
363
+ }
364
+ det.MontoItem = monto;
365
+ return det;
366
+ });
367
+ }
368
+
369
+ /**
370
+ * Construye detalle para Guía de Despacho
371
+ * @private
372
+ */
373
+ _buildDetalleGuia(items = []) {
374
+ return items.map((i, idx) => {
375
+ const qty = i.cantidad ?? 1;
376
+ const prc = i.precio ?? null;
377
+ const monto = prc !== null ? Math.round(qty * prc) : (i.monto ?? undefined);
378
+ return {
379
+ NroLinDet: idx + 1,
380
+ NmbItem: normalizeText(i.nombre),
381
+ QtyItem: qty,
382
+ UnmdItem: i.unidad || 'UN',
383
+ ...(prc !== null && prc > 0 ? { PrcItem: prc } : {}),
384
+ ...(monto !== undefined ? { MontoItem: monto } : {}),
385
+ ...(i.exento ? { IndExe: 1 } : {}),
386
+ };
387
+ });
388
+ }
389
+
390
+ /**
391
+ * Construye detalle para Factura de Compra
392
+ * @private
393
+ */
394
+ _buildDetalleCompra(items = []) {
395
+ return items.map((i, idx) => {
396
+ const qty = i.cantidad ?? 1;
397
+ const prc = i.precio ?? 0;
398
+ const monto = Math.round(qty * prc);
399
+ // Para facturas de compra, siempre agregar CodImpAdic: 15 a items afectos
400
+ const codImpAdic = i.exento ? null : (i.codImpAdic ?? 15);
401
+ return {
402
+ NroLinDet: idx + 1,
403
+ NmbItem: normalizeText(i.nombre),
404
+ QtyItem: qty,
405
+ UnmdItem: i.unidad || 'UN',
406
+ PrcItem: prc,
407
+ ...(codImpAdic ? { CodImpAdic: codImpAdic } : {}),
408
+ MontoItem: monto,
409
+ ...(i.exento ? { IndExe: 1 } : {}),
410
+ };
411
+ });
412
+ }
413
+
414
+ /**
415
+ * Calcula totales para factura general
416
+ * @private
417
+ */
418
+ _calcularTotalesGeneral(items = [], descuentoGlobalPct = 0) {
419
+ let mntNeto = 0;
420
+ let mntExe = 0;
421
+
422
+ for (const item of items) {
423
+ const qty = Number(item.cantidad || 1);
424
+ const precio = Number(item.precio || 0);
425
+ const descuento = Number(item.descuentoPct || 0);
426
+ const base = Math.round(qty * precio);
427
+ const descuentoMonto = descuento > 0 ? Math.round(base * (descuento / 100)) : 0;
428
+ const linea = base - descuentoMonto;
429
+ if (item.exento) mntExe += linea;
430
+ else mntNeto += linea;
431
+ }
432
+
433
+ const descGlobalMonto = descuentoGlobalPct ? Math.round(mntNeto * (descuentoGlobalPct / 100)) : 0;
434
+ mntNeto = Math.max(0, mntNeto - descGlobalMonto);
435
+
436
+ const iva = Math.round(mntNeto * (TASA_IVA / 100));
437
+ const total = mntNeto + iva + mntExe;
438
+
439
+ const totales = {};
440
+ if (mntNeto > 0) totales.MntNeto = mntNeto;
441
+ if (mntExe > 0) totales.MntExe = mntExe;
442
+ if (mntNeto > 0) {
443
+ totales.TasaIVA = TASA_IVA;
444
+ totales.IVA = iva;
445
+ }
446
+ totales.MntTotal = total;
447
+ return totales;
448
+ }
449
+
450
+ /**
451
+ * Calcula totales para Guía de Despacho
452
+ * @private
453
+ */
454
+ _calcularTotalesGuia(detalle = []) {
455
+ let mntNeto = 0;
456
+ let mntExe = 0;
457
+
458
+ detalle.forEach((det) => {
459
+ if (det.IndExe === 1) mntExe += det.MontoItem || 0;
460
+ else mntNeto += det.MontoItem || 0;
461
+ });
462
+
463
+ if (mntNeto === 0 && mntExe === 0) {
464
+ return { TasaIVA: TASA_IVA, MntTotal: 0 };
465
+ }
466
+
467
+ const iva = mntNeto > 0 ? Math.round(mntNeto * (TASA_IVA / 100)) : 0;
468
+ const mntTotal = mntNeto + iva + mntExe;
469
+
470
+ const totales = {};
471
+ if (mntNeto > 0) totales.MntNeto = mntNeto;
472
+ if (mntExe > 0) totales.MntExe = mntExe;
473
+ if (mntNeto > 0) totales.TasaIVA = TASA_IVA;
474
+ if (mntNeto > 0) totales.IVA = iva;
475
+ totales.MntTotal = mntTotal;
476
+ return totales;
477
+ }
478
+
479
+ /**
480
+ * Calcula totales para Factura de Compra
481
+ * @private
482
+ */
483
+ _calcularTotalesFacturaCompra(detalle = []) {
484
+ let mntNeto = 0;
485
+ let mntExe = 0;
486
+
487
+ detalle.forEach((det) => {
488
+ if (det.IndExe === 1) mntExe += det.MontoItem || 0;
489
+ else mntNeto += det.MontoItem || 0;
490
+ });
491
+
492
+ const iva = mntNeto > 0 ? Math.round(mntNeto * (TASA_IVA / 100)) : 0;
493
+ const mntTotal = mntNeto + mntExe;
494
+
495
+ const totales = {};
496
+ if (mntNeto > 0) totales.MntNeto = mntNeto;
497
+ if (mntExe > 0) totales.MntExe = mntExe;
498
+ if (mntNeto > 0) totales.TasaIVA = TASA_IVA;
499
+ if (mntNeto > 0) totales.IVA = iva;
500
+ if (iva > 0) {
501
+ totales.ImptoReten = [{
502
+ TipoImp: 15,
503
+ TasaImp: TASA_IVA,
504
+ MontoImp: iva,
505
+ }];
506
+ }
507
+ totales.MntTotal = mntTotal;
508
+ return totales;
509
+ }
510
+
511
+ _shouldUseEmisorAsReceptor(doc) {
512
+ return Number(doc.indTraslado) === 5;
513
+ }
514
+
515
+ _getFechaHoy() {
516
+ const now = new Date();
517
+ return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
518
+ }
519
+ }
520
+
521
+ module.exports = Simulacion;