consultame-sdk 1.1.2 → 1.2.1
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.
- package/README.md +168 -5
- package/dist/index.js +163 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +163 -2
- package/dist/index.mjs.map +1 -1
- package/dist/shared/functions/functions.utils.d.ts +2 -1
- package/dist/shared/functions/functions.utils.d.ts.map +1 -1
- package/dist/sifen/applications/dtos/index.d.ts +1 -0
- package/dist/sifen/applications/dtos/index.d.ts.map +1 -1
- package/dist/sifen/applications/dtos/nominationInvoice.dto.d.ts +31 -0
- package/dist/sifen/applications/dtos/nominationInvoice.dto.d.ts.map +1 -0
- package/dist/sifen/applications/services/sifen.service.d.ts +3 -1
- package/dist/sifen/applications/services/sifen.service.d.ts.map +1 -1
- package/dist/sifen/domain/repository/sifen.repository.d.ts +2 -1
- package/dist/sifen/domain/repository/sifen.repository.d.ts.map +1 -1
- package/dist/sifen/domain/useCases/index.d.ts +1 -0
- package/dist/sifen/domain/useCases/index.d.ts.map +1 -1
- package/dist/sifen/domain/useCases/nominationInvoice.useCase.d.ts +8 -0
- package/dist/sifen/domain/useCases/nominationInvoice.useCase.d.ts.map +1 -0
- package/dist/sifen/infrastructure/persistence/sifen.persistence.d.ts +2 -1
- package/dist/sifen/infrastructure/persistence/sifen.persistence.d.ts.map +1 -1
- package/package.json +1 -3
package/README.md
CHANGED
|
@@ -5,7 +5,8 @@ que se necesitan para interactuar con **SIFEN** (Sistema Integrado de Facturaci
|
|
|
5
5
|
Nacional de Paraguay – SET).
|
|
6
6
|
|
|
7
7
|
La librería **no** hace las peticiones HTTP al web service de SIFEN: su responsabilidad es
|
|
8
|
-
**construir los sobres XML** (consulta de RUC, consulta de lote, consulta de documento
|
|
8
|
+
**construir los sobres XML** (consulta de RUC, consulta de lote, consulta de documento y
|
|
9
|
+
evento de nominación de un documento ya emitido),
|
|
9
10
|
**extraer el certificado y la llave privada** desde un archivo de firma digital `.p12`/`.pfx`,
|
|
10
11
|
**firmar digitalmente (XMLDSig)** el Documento Electrónico generado y **generar el código QR**
|
|
11
12
|
que se incrusta en el documento electrónico ya firmado.
|
|
@@ -25,6 +26,7 @@ Con esa salida, la aplicación consumidora envía los mensajes por su cuenta.
|
|
|
25
26
|
- [`generateQr`](#generateqrgenerationqrdto)
|
|
26
27
|
- [`generateDocument`](#generatedocumentgeneratedocumentoelectronicodto)
|
|
27
28
|
- [`signedXml`](#signedxmlxml-tag-responsedigitalsign)
|
|
29
|
+
- [`nominationInvoice`](#nominationinvoicenominationinvoicedto)
|
|
28
30
|
- [DTOs (contratos de entrada)](#dtos-contratos-de-entrada)
|
|
29
31
|
- [Funciones utilitarias internas](#funciones-utilitarias-internas)
|
|
30
32
|
- [Arquitectura del proyecto](#arquitectura-del-proyecto)
|
|
@@ -49,7 +51,6 @@ Dependencias en tiempo de ejecución:
|
|
|
49
51
|
| [`node-forge`](https://www.npmjs.com/package/node-forge) | Leer los certificados `.p12`/`.pfx` y exportarlos a PEM. |
|
|
50
52
|
| [`xml2js`](https://www.npmjs.com/package/xml2js) | Parsear el XML firmado al generar el QR. |
|
|
51
53
|
| [`xml-crypto`](https://www.npmjs.com/package/xml-crypto) | Firmar digitalmente (XMLDSig) el Documento Electrónico generado. |
|
|
52
|
-
| [`crypto-js`](https://www.npmjs.com/package/crypto-js) | Calcular el hash SHA-256 (`cHashQR`) del código QR. |
|
|
53
54
|
|
|
54
55
|
La librería se publica en formato dual **CommonJS + ESM** con tipos incluidos:
|
|
55
56
|
|
|
@@ -69,7 +70,7 @@ Todo el punto de entrada público es la clase **`SifenService`**. Se instancia s
|
|
|
69
70
|
argumentos y ya arma internamente sus casos de uso y dependencias.
|
|
70
71
|
|
|
71
72
|
```ts
|
|
72
|
-
import { SifenService } from "consultame-
|
|
73
|
+
import { SifenService } from "consultame-sdk";
|
|
73
74
|
|
|
74
75
|
const sifen = new SifenService();
|
|
75
76
|
|
|
@@ -170,6 +171,21 @@ const xmlConQr = await sifen.generateQr({
|
|
|
170
171
|
idCsc: "0001",
|
|
171
172
|
ambiente: "test", // "test" | "produccion"
|
|
172
173
|
});
|
|
174
|
+
|
|
175
|
+
// 8) Nominar un documento ya emitido a un receptor (evento de nominación, sin firmar)
|
|
176
|
+
const xmlNominacion = sifen.nominationInvoice({
|
|
177
|
+
id: 4,
|
|
178
|
+
cdc: "01800123456001001000000012023052212345678901",
|
|
179
|
+
motivo: "Nominación solicitada por el cliente",
|
|
180
|
+
idTipoReceptor: 1, // 1 = contribuyente
|
|
181
|
+
idTipoOperacion: 1, // 1 = B2B
|
|
182
|
+
idPais: "PRY",
|
|
183
|
+
esContribuyente: true,
|
|
184
|
+
idTipoContribuyente: 2,
|
|
185
|
+
ruc: "80099999",
|
|
186
|
+
digitoVerificado: "1",
|
|
187
|
+
razonSocial: "Cliente Ejemplo S.R.L.",
|
|
188
|
+
});
|
|
173
189
|
```
|
|
174
190
|
|
|
175
191
|
---
|
|
@@ -342,7 +358,7 @@ Toma un documento electrónico (`rDE`) **ya firmado digitalmente**, calcula el e
|
|
|
342
358
|
código QR exigido por SIFEN y devuelve el **mismo XML con el nodo `<gCamFuFD><dCarQR>`
|
|
343
359
|
incrustado**.
|
|
344
360
|
|
|
345
|
-
> ⚠️
|
|
361
|
+
> ⚠️ Método **asíncrono**: devuelve `Promise<string>`.
|
|
346
362
|
|
|
347
363
|
| Parámetro | Tipo | Descripción |
|
|
348
364
|
| ---------- | -------- | ---------------------------------------------------------------------- |
|
|
@@ -634,6 +650,131 @@ try {
|
|
|
634
650
|
|
|
635
651
|
---
|
|
636
652
|
|
|
653
|
+
### `nominationInvoice(nominationInvoiceDto)`
|
|
654
|
+
|
|
655
|
+
Genera el sobre SOAP `rEnviEventoDe` con el **evento de nominación** (`rGEveNom`): asocia los
|
|
656
|
+
datos de un receptor a un documento electrónico ya emitido, identificado por su **CDC**.
|
|
657
|
+
|
|
658
|
+
> ⚠️ El XML devuelto **no está firmado**: la aplicación consumidora debe firmar el evento y
|
|
659
|
+
> enviarlo a SIFEN por su cuenta.
|
|
660
|
+
|
|
661
|
+
Método **síncrono** que valida el DTO antes de armar el XML.
|
|
662
|
+
|
|
663
|
+
| Parámetro | Tipo | Descripción |
|
|
664
|
+
| --------------------- | ------------------- | --------------------------------------------------------------------------------------------- |
|
|
665
|
+
| `id` | `number` | Identificador de la petición (`dId`); también se usa como `Id` del evento (`rEve`). |
|
|
666
|
+
| `cdc` | `string` | CDC de 44 dígitos del documento a nominar (`Id` de `rGEveNom`). |
|
|
667
|
+
| `motivo` | `string` | Motivo del evento (`mOtEve`), de 5 a 500 caracteres. |
|
|
668
|
+
| `idTipoReceptor` | `number` | `1` = contribuyente, `2` = no contribuyente (`iNatRec`). |
|
|
669
|
+
| `idTipoOperacion` | `number` | `1` = B2B, `2` = B2C, `4` = B2F (`iTiOpe`). |
|
|
670
|
+
| `idPais` | `string` | Código de país del receptor (ej. `"PRY"`); debe existir en `PAISES`. |
|
|
671
|
+
| `esContribuyente` | `boolean` | Si el receptor es contribuyente. |
|
|
672
|
+
| `razonSocial` | `string` | Nombre o razón social del receptor (`dNomRec`), de 4 a 255 caracteres. |
|
|
673
|
+
| `idTipoContribuyente` | `number?` | `1` = persona física, `2` = persona jurídica. Obligatorio si `esContribuyente`. |
|
|
674
|
+
| `ruc` | `string?` | RUC del receptor. Obligatorio si `esContribuyente`. |
|
|
675
|
+
| `digitoVerificado` | `string \| number?` | Dígito verificador del RUC. Obligatorio si `esContribuyente`. |
|
|
676
|
+
| `idTipoDocumento` | `number?` | Tipo de documento de identidad. Obligatorio si **no** es contribuyente. |
|
|
677
|
+
| `numeroDocumento` | `string?` | Número de documento. Obligatorio si **no** es contribuyente. |
|
|
678
|
+
| `otroTipoDocumento` | `string?` | Descripción del tipo de documento cuando `idTipoDocumento = 9` (Otro). |
|
|
679
|
+
| `nombreFantasia` | `string?` | Nombre de fantasía del receptor. |
|
|
680
|
+
| `direccion` | `string?` | Dirección del receptor. Obligatoria si `idTipoOperacion = 4` (B2F). |
|
|
681
|
+
| `numeroCasa` | `string?` | Obligatorio si se informa `direccion`. |
|
|
682
|
+
| `idDepartamento`, `idDistricto`, `idCiudad` | `number?` | Ubicación del receptor. **Se ignoran en B2F.** |
|
|
683
|
+
| `telefono`, `celular`, `email`, `codigoCliente` | `string?` | Datos de contacto opcionales. |
|
|
684
|
+
|
|
685
|
+
> El campo se llama `idDistricto` (con esa grafía) en el DTO.
|
|
686
|
+
|
|
687
|
+
**Retorna:** `string` — XML SOAP normalizado (una sola línea), con `dFecFirma` tomado de la
|
|
688
|
+
fecha/hora actual y `dVerFor` = `150`.
|
|
689
|
+
|
|
690
|
+
```ts
|
|
691
|
+
const xml = sifen.nominationInvoice({
|
|
692
|
+
id: 4,
|
|
693
|
+
cdc: "01800123456001001000000012023052212345678901",
|
|
694
|
+
motivo: "Nominación solicitada por el cliente",
|
|
695
|
+
idTipoReceptor: 1,
|
|
696
|
+
idTipoOperacion: 1,
|
|
697
|
+
idPais: "PRY",
|
|
698
|
+
esContribuyente: true,
|
|
699
|
+
idTipoContribuyente: 2,
|
|
700
|
+
ruc: "80099999",
|
|
701
|
+
digitoVerificado: "1",
|
|
702
|
+
razonSocial: "Cliente Ejemplo S.R.L.",
|
|
703
|
+
});
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
<details>
|
|
707
|
+
<summary>Ejemplo de salida (formateada para lectura)</summary>
|
|
708
|
+
|
|
709
|
+
```xml
|
|
710
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
711
|
+
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
|
|
712
|
+
<env:Header/>
|
|
713
|
+
<env:Body>
|
|
714
|
+
<rEnviEventoDe xmlns="http://ekuatia.set.gov.py/sifen/xsd">
|
|
715
|
+
<dId>4</dId>
|
|
716
|
+
<dEvReg>
|
|
717
|
+
<gGroupGesEve xmlns="http://ekuatia.set.gov.py/sifen/xsd"
|
|
718
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
719
|
+
xsi:schemaLocation="http://ekuatia.set.gov.py/sifen/xsd siRecepEvento_v150.xsd">
|
|
720
|
+
<rGesEve xsi:schemaLocation="http://ekuatia.set.gov.py/sifen/xsd siRecepEvento_v150.xsd">
|
|
721
|
+
<rEve Id="4">
|
|
722
|
+
<dFecFirma>2026-10-14T16:43:03</dFecFirma>
|
|
723
|
+
<dVerFor>150</dVerFor>
|
|
724
|
+
<gGroupTiEvt>
|
|
725
|
+
<rGEveNom>
|
|
726
|
+
<Id>01800123456001001000000012023052212345678901</Id>
|
|
727
|
+
<mOtEve>Nominación solicitada por el cliente</mOtEve>
|
|
728
|
+
<iNatRec>1</iNatRec>
|
|
729
|
+
<iTiOpe>1</iTiOpe>
|
|
730
|
+
<cPaisRec>PRY</cPaisRec>
|
|
731
|
+
<dDesPaisRe>Paraguay</dDesPaisRe>
|
|
732
|
+
<iTiContRec>2</iTiContRec>
|
|
733
|
+
<dRucRec>80099999</dRucRec>
|
|
734
|
+
<dDVRec>1</dDVRec>
|
|
735
|
+
<dNomRec>Cliente Ejemplo S.R.L.</dNomRec>
|
|
736
|
+
</rGEveNom>
|
|
737
|
+
</gGroupTiEvt>
|
|
738
|
+
</rEve>
|
|
739
|
+
</rGesEve>
|
|
740
|
+
</gGroupGesEve>
|
|
741
|
+
</dEvReg>
|
|
742
|
+
</rEnviEventoDe>
|
|
743
|
+
</env:Body>
|
|
744
|
+
</env:Envelope>
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
</details>
|
|
748
|
+
|
|
749
|
+
#### Reglas de validación
|
|
750
|
+
|
|
751
|
+
Antes de armar el XML se valida el DTO y se lanza un `Error` con un mensaje descriptivo si
|
|
752
|
+
algo no cumple:
|
|
753
|
+
|
|
754
|
+
- `cdc` debe tener exactamente 44 dígitos.
|
|
755
|
+
- `motivo` de 5 a 500 caracteres y `razonSocial` de 4 a 255 (ambos sin contar espacios en los extremos).
|
|
756
|
+
- `idTipoReceptor` debe ser coherente con `esContribuyente` (`1` ⇔ contribuyente).
|
|
757
|
+
- `idTipoOperacion` debe ser `1`, `2` o `4`; B2B (`1`) exige receptor contribuyente, y B2C (`2`) /
|
|
758
|
+
B2F (`4`) exigen no contribuyente.
|
|
759
|
+
- `idPais` debe ser `"PRY"`, salvo en B2F (`4`), donde debe ser **distinto** de `"PRY"`.
|
|
760
|
+
- Contribuyente: `idTipoContribuyente`, `ruc` y `digitoVerificado` son obligatorios.
|
|
761
|
+
- No contribuyente: `idTipoDocumento` y `numeroDocumento` son obligatorios.
|
|
762
|
+
- B2F: `direccion` es obligatoria; y si se informa `direccion`, también `numeroCasa`.
|
|
763
|
+
|
|
764
|
+
También lanza error si algún código (`idPais`, `idTipoDocumento`, `idDepartamento`, `idDistricto`,
|
|
765
|
+
`idCiudad`) no existe en los catálogos de
|
|
766
|
+
[`src/shared/utils/dictionary.utils.ts`](src/shared/utils/dictionary.utils.ts).
|
|
767
|
+
|
|
768
|
+
```ts
|
|
769
|
+
try {
|
|
770
|
+
const xml = sifen.nominationInvoice({ ... });
|
|
771
|
+
} catch (error) {
|
|
772
|
+
// DTO inválido (ver reglas de validación) o código inexistente en el diccionario
|
|
773
|
+
}
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
---
|
|
777
|
+
|
|
637
778
|
## DTOs (contratos de entrada)
|
|
638
779
|
|
|
639
780
|
Todos los DTOs de consulta extienden `GenerateIdDto`, que aporta el campo `id`.
|
|
@@ -666,6 +807,18 @@ interface GenerationQrDto {
|
|
|
666
807
|
idCsc: string; // Identificador del CSC
|
|
667
808
|
ambiente: string; // "test" | "produccion"
|
|
668
809
|
}
|
|
810
|
+
|
|
811
|
+
// Campos completos y reglas en la sección `nominationInvoice`
|
|
812
|
+
interface NominationInvoiceDto extends GenerateIdDto {
|
|
813
|
+
cdc: string;
|
|
814
|
+
motivo: string;
|
|
815
|
+
idTipoReceptor: number;
|
|
816
|
+
idTipoOperacion: number;
|
|
817
|
+
idPais: string;
|
|
818
|
+
esContribuyente: boolean;
|
|
819
|
+
razonSocial: string;
|
|
820
|
+
// ...y los campos opcionales del receptor (ruc, direccion, idDistricto, email, etc.)
|
|
821
|
+
}
|
|
669
822
|
```
|
|
670
823
|
|
|
671
824
|
Enums disponibles en [`src/shared/utils/dictionary.utils.ts`](src/shared/utils/dictionary.utils.ts):
|
|
@@ -725,6 +878,8 @@ No forman parte de la API pública, pero es útil conocerlas:
|
|
|
725
878
|
| `generateConsultRucXml` | Arma el string XML de consulta de RUC. |
|
|
726
879
|
| `generateConsultDocumentXml` | Arma el string XML de consulta de documento por CDC. |
|
|
727
880
|
| `generateConsultBatchXml` | Arma el string XML de consulta de lote. |
|
|
881
|
+
| `generateNominationInvoiceXml` | Valida el `NominationInvoiceDto` y arma el sobre `rEnviEventoDe` del evento de nominación con `xml2js.Builder`, ya normalizado. |
|
|
882
|
+
| `convertToFormatDateSET` | Formatea una `Date` como fecha/hora SIFEN (usada para `dFecFirma` del evento). |
|
|
728
883
|
| `normalizeXML` | Colapsa el XML a una sola línea: elimina saltos, tabulaciones y espacios entre etiquetas. |
|
|
729
884
|
| `readDigitalSign` | Lee el `.p12` con `node-forge` y extrae certificado + llave privada en PEM, emparejando el certificado correcto por módulo RSA cuando hay varios. |
|
|
730
885
|
| `signXml` | Firma un XML (XMLDSig) con `xml-crypto`: `enveloped-signature` + `exc-c14n`, digest SHA-256, firma RSA-SHA256. _(async)_ |
|
|
@@ -787,6 +942,11 @@ mantener estado intermedio (`jsonFactura`) mientras se arma cada sección del XM
|
|
|
787
942
|
`SifenRepository` → `SifenPersistence.signedXml`), delegando en la función utilitaria `signXml`
|
|
788
943
|
(`src/shared/functions/functions.utils.ts`), que envuelve `xml-crypto`.
|
|
789
944
|
|
|
945
|
+
`nominationInvoice` también sigue el mismo flujo (`SifenService.nominationInvoice` →
|
|
946
|
+
`NominationInvoiceUseCase` → `SifenRepository` → `SifenPersistence.nominationInvoice`),
|
|
947
|
+
delegando en `generateNominationInvoiceXml`, que valida el DTO y arma el evento con
|
|
948
|
+
`xml2js.Builder` (a diferencia de las consultas simples, que son strings de plantilla).
|
|
949
|
+
|
|
790
950
|
**Por qué esta separación:**
|
|
791
951
|
|
|
792
952
|
- **`domain`** no depende de nada externo: define _qué_ se hace (casos de uso) y el
|
|
@@ -830,6 +990,7 @@ consultame-sdk/
|
|
|
830
990
|
│ │ │ ├── consultBatch.dto.ts
|
|
831
991
|
│ │ │ ├── digitalSign.dto.ts
|
|
832
992
|
│ │ │ ├── generationQr.dto.ts
|
|
993
|
+
│ │ │ ├── nominationInvoice.dto.ts
|
|
833
994
|
│ │ │ ├── cancelDocument.dto.ts
|
|
834
995
|
│ │ │ └── invalidationInvoice.dto.ts
|
|
835
996
|
│ │ └── services/
|
|
@@ -846,6 +1007,7 @@ consultame-sdk/
|
|
|
846
1007
|
│ │ ├── obtainDigitalSign.useCase.ts
|
|
847
1008
|
│ │ ├── generateQr.useCase.ts
|
|
848
1009
|
│ │ ├── generateDocument.useCase.ts
|
|
1010
|
+
│ │ ├── nominationInvoice.useCase.ts
|
|
849
1011
|
│ │ └── signedXml.useCase.ts
|
|
850
1012
|
│ │
|
|
851
1013
|
│ └── infrastructure/ # Detalles concretos (ADAPTADORES)
|
|
@@ -886,6 +1048,7 @@ Funcionalidades **implementadas**:
|
|
|
886
1048
|
- ✅ Generación del XML completo del Documento Electrónico — Factura, Autofactura, Nota de
|
|
887
1049
|
Crédito/Débito y Remisión (`generateDocument`)
|
|
888
1050
|
- ✅ Firma digital XMLDSig del Documento Electrónico (`signedXml`)
|
|
1051
|
+
- ✅ Evento de nominación de un documento emitido (`nominationInvoice`)
|
|
889
1052
|
|
|
890
1053
|
Definidas pero **pendientes de implementación** (hoy lanzan `Method not implemented`
|
|
891
1054
|
o aún no están expuestas en `SifenService`):
|
|
@@ -897,5 +1060,5 @@ o aún no están expuestas en `SifenService`):
|
|
|
897
1060
|
|
|
898
1061
|
> **Nota:** esta librería genera insumos (XML, credenciales, firma XMLDSig y el QR) para SIFEN,
|
|
899
1062
|
> pero no realiza el envío HTTP de los documentos — eso queda a cargo de la aplicación
|
|
900
|
-
> consumidora. `generateQr` **requiere** que el XML ya venga firmado (con `signedXml` o por
|
|
1063
|
+
> consumidora. El evento que devuelve `nominationInvoice` tampoco viene firmado. `generateQr` **requiere** que el XML ya venga firmado (con `signedXml` o por
|
|
901
1064
|
> cualquier otro medio), porque toma el `DigestValue` de la firma para calcular el hash del QR.
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var fs = require('fs');
|
|
4
4
|
var forge = require('node-forge');
|
|
5
5
|
var xml2js = require('xml2js');
|
|
6
|
-
var
|
|
6
|
+
var crypto = require('crypto');
|
|
7
7
|
var xmlCrypto = require('xml-crypto');
|
|
8
8
|
|
|
9
9
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -28,7 +28,6 @@ function _interopNamespace(e) {
|
|
|
28
28
|
|
|
29
29
|
var forge__default = /*#__PURE__*/_interopDefault(forge);
|
|
30
30
|
var xml2js__namespace = /*#__PURE__*/_interopNamespace(xml2js);
|
|
31
|
-
var sha256__default = /*#__PURE__*/_interopDefault(sha256);
|
|
32
31
|
|
|
33
32
|
// src/sifen/domain/useCases/consultBatch.useCase.ts
|
|
34
33
|
var ConsultBatchUseCase = class {
|
|
@@ -120,6 +119,18 @@ var SignedXmlUseCase = class {
|
|
|
120
119
|
}
|
|
121
120
|
};
|
|
122
121
|
|
|
122
|
+
// src/sifen/domain/useCases/nominationInvoice.useCase.ts
|
|
123
|
+
var NominationInvoiceUseCase = class {
|
|
124
|
+
constructor(sifenRepository) {
|
|
125
|
+
this.sifenRepository = sifenRepository;
|
|
126
|
+
}
|
|
127
|
+
sifenRepository;
|
|
128
|
+
execute(nominationInvoiceDto) {
|
|
129
|
+
const xml = this.sifenRepository.nominationInvoice(nominationInvoiceDto);
|
|
130
|
+
return xml;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
123
134
|
// src/shared/utils/dictionary.utils.ts
|
|
124
135
|
var TIPOS_DOCUMENTOS = [
|
|
125
136
|
{
|
|
@@ -8157,6 +8168,139 @@ var generateConsultBatchXml = (consultBatchDto) => {
|
|
|
8157
8168
|
</env:Envelope>
|
|
8158
8169
|
`;
|
|
8159
8170
|
};
|
|
8171
|
+
var validateNominationInvoice = (dto) => {
|
|
8172
|
+
if (!/^\d{44}$/.test(dto.cdc)) {
|
|
8173
|
+
throw new Error("El CDC debe tener 44 d\xEDgitos");
|
|
8174
|
+
}
|
|
8175
|
+
if (dto.motivo.trim().length < 5 || dto.motivo.trim().length > 500) {
|
|
8176
|
+
throw new Error("El motivo debe tener entre 5 y 500 caracteres");
|
|
8177
|
+
}
|
|
8178
|
+
if (dto.razonSocial.trim().length < 4 || dto.razonSocial.trim().length > 255) {
|
|
8179
|
+
throw new Error("La raz\xF3n social debe tener entre 4 y 255 caracteres");
|
|
8180
|
+
}
|
|
8181
|
+
if (dto.esContribuyente !== (dto.idTipoReceptor === 1)) {
|
|
8182
|
+
throw new Error(
|
|
8183
|
+
"idTipoReceptor (1 = contribuyente, 2 = no contribuyente) no coincide con esContribuyente"
|
|
8184
|
+
);
|
|
8185
|
+
}
|
|
8186
|
+
if (![1, 2, 4].includes(dto.idTipoOperacion)) {
|
|
8187
|
+
throw new Error("idTipoOperacion debe ser 1 (B2B), 2 (B2C) o 4 (B2F)");
|
|
8188
|
+
}
|
|
8189
|
+
if (dto.esContribuyente !== (dto.idTipoOperacion === 1)) {
|
|
8190
|
+
throw new Error(
|
|
8191
|
+
"B2B exige receptor contribuyente; B2C y B2F exigen no contribuyente"
|
|
8192
|
+
);
|
|
8193
|
+
}
|
|
8194
|
+
if (dto.idTipoOperacion === 4 === (dto.idPais === "PRY")) {
|
|
8195
|
+
throw new Error(
|
|
8196
|
+
"idPais debe ser PRY, salvo en B2F donde debe ser distinto de PRY"
|
|
8197
|
+
);
|
|
8198
|
+
}
|
|
8199
|
+
if (dto.esContribuyente) {
|
|
8200
|
+
if (!dto.idTipoContribuyente || !dto.ruc || dto.digitoVerificado === void 0) {
|
|
8201
|
+
throw new Error(
|
|
8202
|
+
"Receptor contribuyente: idTipoContribuyente, ruc y digitoVerificado son obligatorios"
|
|
8203
|
+
);
|
|
8204
|
+
}
|
|
8205
|
+
} else if (!dto.idTipoDocumento || !dto.numeroDocumento) {
|
|
8206
|
+
throw new Error(
|
|
8207
|
+
"Receptor no contribuyente: idTipoDocumento y numeroDocumento son obligatorios"
|
|
8208
|
+
);
|
|
8209
|
+
}
|
|
8210
|
+
if (dto.idTipoOperacion === 4 && !dto.direccion) {
|
|
8211
|
+
throw new Error("B2F: la direcci\xF3n del receptor es obligatoria");
|
|
8212
|
+
}
|
|
8213
|
+
if (dto.direccion && !dto.numeroCasa) {
|
|
8214
|
+
throw new Error("numeroCasa es obligatorio si se informa la direcci\xF3n");
|
|
8215
|
+
}
|
|
8216
|
+
};
|
|
8217
|
+
var generateNominationInvoiceXml = (dto) => {
|
|
8218
|
+
validateNominationInvoice(dto);
|
|
8219
|
+
const pais = PAISES.find((item) => item.codigo === dto.idPais).descripcion;
|
|
8220
|
+
const rGEveNom = {
|
|
8221
|
+
Id: dto.cdc,
|
|
8222
|
+
mOtEve: dto.motivo.trim(),
|
|
8223
|
+
iNatRec: dto.idTipoReceptor,
|
|
8224
|
+
iTiOpe: dto.idTipoOperacion,
|
|
8225
|
+
cPaisRec: dto.idPais,
|
|
8226
|
+
dDesPaisRe: pais
|
|
8227
|
+
};
|
|
8228
|
+
if (dto.esContribuyente) {
|
|
8229
|
+
rGEveNom.iTiContRec = dto.idTipoContribuyente;
|
|
8230
|
+
rGEveNom.dRucRec = dto.ruc;
|
|
8231
|
+
rGEveNom.dDVRec = dto.digitoVerificado;
|
|
8232
|
+
} else {
|
|
8233
|
+
rGEveNom.iTipIDRec = dto.idTipoDocumento;
|
|
8234
|
+
rGEveNom.dDTipIDRec = dto.idTipoDocumento === 9 && dto.otroTipoDocumento ? dto.otroTipoDocumento : TIPOS_DOCUMENTOS.find((item) => item.codigo === dto.idTipoDocumento).descripcion;
|
|
8235
|
+
rGEveNom.dNumIDRec = dto.numeroDocumento.trim();
|
|
8236
|
+
}
|
|
8237
|
+
rGEveNom.dNomRec = dto.razonSocial.trim();
|
|
8238
|
+
if (dto.nombreFantasia) rGEveNom.dNomFanRec = dto.nombreFantasia.trim();
|
|
8239
|
+
if (dto.direccion) {
|
|
8240
|
+
rGEveNom.dDirRec = dto.direccion.trim();
|
|
8241
|
+
rGEveNom.dNumCasRec = dto.numeroCasa.trim();
|
|
8242
|
+
}
|
|
8243
|
+
if (dto.idTipoOperacion !== 4) {
|
|
8244
|
+
if (dto.idDepartamento) {
|
|
8245
|
+
rGEveNom.cDepRec = dto.idDepartamento;
|
|
8246
|
+
rGEveNom.dDesDepRec = DEPARTAMENTOS.find(
|
|
8247
|
+
(item) => item.codigo === dto.idDepartamento
|
|
8248
|
+
).descripcion;
|
|
8249
|
+
}
|
|
8250
|
+
if (dto.idDistricto) {
|
|
8251
|
+
rGEveNom.cDisRec = dto.idDistricto;
|
|
8252
|
+
rGEveNom.dDesDisRec = DISTRICTOS.find(
|
|
8253
|
+
(item) => item.codigo === dto.idDistricto
|
|
8254
|
+
).descripcion;
|
|
8255
|
+
}
|
|
8256
|
+
if (dto.idCiudad) {
|
|
8257
|
+
rGEveNom.cCiuRec = dto.idCiudad;
|
|
8258
|
+
rGEveNom.dDesCiuRec = CIUDADES.find(
|
|
8259
|
+
(item) => item.codigo === dto.idCiudad
|
|
8260
|
+
).descripcion;
|
|
8261
|
+
}
|
|
8262
|
+
}
|
|
8263
|
+
if (dto.telefono) rGEveNom.dTelRec = dto.telefono.trim();
|
|
8264
|
+
if (dto.celular) rGEveNom.dCelRec = dto.celular.trim();
|
|
8265
|
+
if (dto.email) rGEveNom.dEmailRec = dto.email.trim();
|
|
8266
|
+
if (dto.codigoCliente) rGEveNom.dCodCliente = dto.codigoCliente.trim();
|
|
8267
|
+
const xsd = "http://ekuatia.set.gov.py/sifen/xsd";
|
|
8268
|
+
const schemaLocation = `${xsd} siRecepEvento_v150.xsd`;
|
|
8269
|
+
const envelope = {
|
|
8270
|
+
"env:Envelope": {
|
|
8271
|
+
$: { "xmlns:env": "http://www.w3.org/2003/05/soap-envelope" },
|
|
8272
|
+
"env:Header": {},
|
|
8273
|
+
"env:Body": {
|
|
8274
|
+
rEnviEventoDe: {
|
|
8275
|
+
$: { xmlns: xsd },
|
|
8276
|
+
dId: dto.id,
|
|
8277
|
+
dEvReg: {
|
|
8278
|
+
gGroupGesEve: {
|
|
8279
|
+
$: {
|
|
8280
|
+
xmlns: xsd,
|
|
8281
|
+
"xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
|
8282
|
+
"xsi:schemaLocation": schemaLocation
|
|
8283
|
+
},
|
|
8284
|
+
rGesEve: {
|
|
8285
|
+
$: { "xsi:schemaLocation": schemaLocation },
|
|
8286
|
+
rEve: {
|
|
8287
|
+
$: { Id: dto.id },
|
|
8288
|
+
dFecFirma: convertToFormatDateSET(/* @__PURE__ */ new Date()),
|
|
8289
|
+
dVerFor: 150,
|
|
8290
|
+
gGroupTiEvt: { rGEveNom }
|
|
8291
|
+
}
|
|
8292
|
+
}
|
|
8293
|
+
}
|
|
8294
|
+
}
|
|
8295
|
+
}
|
|
8296
|
+
}
|
|
8297
|
+
}
|
|
8298
|
+
};
|
|
8299
|
+
const builder = new xml2js__namespace.Builder({
|
|
8300
|
+
xmldec: { version: "1.0", encoding: "UTF-8", standalone: false }
|
|
8301
|
+
});
|
|
8302
|
+
return normalizeXML(builder.buildObject(envelope));
|
|
8303
|
+
};
|
|
8160
8304
|
var OIDS_KEYS = [forge__default.default.pki.oids.pkcs8ShroudedKeyBag, forge__default.default.pki.oids.keyBag];
|
|
8161
8305
|
var obtainBags = (almacen) => almacen.safeContents.flatMap((contenido) => contenido.safeBags);
|
|
8162
8306
|
var readDigitalSign = (digitalSignDto) => {
|
|
@@ -8243,7 +8387,7 @@ var generateQr = async (generationQrDto) => {
|
|
|
8243
8387
|
qr += "DigestValue=" + digestValue + "&";
|
|
8244
8388
|
qr += "IdCSC=" + idCsc;
|
|
8245
8389
|
const valueForHash = qr;
|
|
8246
|
-
const valueHashed =
|
|
8390
|
+
const valueHashed = crypto.createHash("sha256").update(valueForHash + csc, "utf8").digest("hex");
|
|
8247
8391
|
qr += "&cHashQR=" + valueHashed;
|
|
8248
8392
|
const dCarQR = (linkQr + qr).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
8249
8393
|
const cierreRDE = xml.lastIndexOf("</rDE>");
|
|
@@ -9976,6 +10120,14 @@ var SifenPersistence = class {
|
|
|
9976
10120
|
throw error;
|
|
9977
10121
|
}
|
|
9978
10122
|
}
|
|
10123
|
+
nominationInvoice(nominationInvoiceDto) {
|
|
10124
|
+
try {
|
|
10125
|
+
return generateNominationInvoiceXml(nominationInvoiceDto);
|
|
10126
|
+
} catch (error) {
|
|
10127
|
+
console.log(error);
|
|
10128
|
+
throw error;
|
|
10129
|
+
}
|
|
10130
|
+
}
|
|
9979
10131
|
obtainDigitalSign(digitalSignDto) {
|
|
9980
10132
|
try {
|
|
9981
10133
|
const digitalSign = readDigitalSign(digitalSignDto);
|
|
@@ -10026,6 +10178,7 @@ var SifenService = class {
|
|
|
10026
10178
|
generateQrUseCase;
|
|
10027
10179
|
generateDocumentUseCase;
|
|
10028
10180
|
signedXmlUseCase;
|
|
10181
|
+
nominationInvoiceUseCase;
|
|
10029
10182
|
sifenRepository;
|
|
10030
10183
|
constructor() {
|
|
10031
10184
|
this.sifenRepository = new SifenPersistence();
|
|
@@ -10042,6 +10195,9 @@ var SifenService = class {
|
|
|
10042
10195
|
);
|
|
10043
10196
|
this.signedXmlUseCase = new SignedXmlUseCase(this.sifenRepository);
|
|
10044
10197
|
this.generateQrUseCase = new GenerateQrUseCase(this.sifenRepository);
|
|
10198
|
+
this.nominationInvoiceUseCase = new NominationInvoiceUseCase(
|
|
10199
|
+
this.sifenRepository
|
|
10200
|
+
);
|
|
10045
10201
|
}
|
|
10046
10202
|
consultRuc(consultRucDto) {
|
|
10047
10203
|
const ruc = this.consultRucUseCase.execute(consultRucDto);
|
|
@@ -10055,6 +10211,10 @@ var SifenService = class {
|
|
|
10055
10211
|
const invoice = this.consultDocumentUseCase.execute(consultDocumentDto);
|
|
10056
10212
|
return invoice;
|
|
10057
10213
|
}
|
|
10214
|
+
nominationInvoice(nominationInvoiceDto) {
|
|
10215
|
+
const xml = this.nominationInvoiceUseCase.execute(nominationInvoiceDto);
|
|
10216
|
+
return xml;
|
|
10217
|
+
}
|
|
10058
10218
|
obtainDigitalSign(digitalSignDto) {
|
|
10059
10219
|
const digitalSign = this.obtainDigitalSignUseCase.execute(digitalSignDto);
|
|
10060
10220
|
return digitalSign;
|