@facturacr/atv-sdk 2.0.0 → 2.0.2-alpha
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/.eslintignore +3 -0
- package/.eslintrc.js +23 -23
- package/.github/dependabot.yml +11 -0
- package/.github/workflows/ci.yml +14 -12
- package/README.md +9 -2
- package/__tests__/stubs/commonExpectedXml.xml +14 -16
- package/__tests__/stubs/createDocument.data.ts +18 -1
- package/__tests__/stubs/frontendRequest.stub.ts +0 -1
- package/__tests__/stubs/token.stub.ts +9 -9
- package/__tests__/tests/ATV/__snapshots__/create-document.test.ts.snap +1 -1
- package/__tests__/tests/ATV/create-document.test.ts +8 -8
- package/__tests__/tests/ATV/create-receptor-message.test.ts +41 -36
- package/dist/src/ATV/core/CreateDocFactory.d.ts +11 -3
- package/dist/src/ATV/core/CreateDocFactory.js +3 -3
- package/dist/src/ATV/core/CreateDocFactory.js.map +1 -1
- package/dist/src/ATV/core/Document.d.ts +2 -2
- package/dist/src/ATV/core/Document.js +15 -5
- package/dist/src/ATV/core/Document.js.map +1 -1
- package/dist/src/ATV/core/DocumentType.d.ts +2 -3
- package/dist/src/ATV/core/DocumentType.js +1 -0
- package/dist/src/ATV/core/DocumentType.js.map +1 -1
- package/dist/src/ATV/core/FullConsecutive.d.ts +2 -1
- package/dist/src/ATV/core/FullConsecutive.js.map +1 -1
- package/dist/src/ATV/core/OrderLine.js +8 -1
- package/dist/src/ATV/core/OrderLine.js.map +1 -1
- package/dist/src/ATV/core/Person.d.ts +2 -2
- package/dist/src/ATV/core/ReceptorConsecutive.js.map +1 -1
- package/dist/src/ATV/core/ReferenceInformation.js.map +1 -1
- package/dist/src/ATV/core/Summary.type.d.ts +5 -0
- package/dist/src/ATV/core/types.d.ts +3 -2
- package/dist/src/ATV/core/types.js.map +1 -1
- package/dist/src/ATV/index.d.ts +2 -2
- package/dist/src/ATV/index.js +2 -2
- package/dist/src/ATV/mappers/billDocToAtv.js +32 -26
- package/dist/src/ATV/mappers/billDocToAtv.js.map +1 -1
- package/dist/src/ATV/types.d.ts +1 -1
- package/dist/src/ATV/useCases/createDocument/index.js +5 -9
- package/dist/src/ATV/useCases/createDocument/index.js.map +1 -1
- package/dist/src/ATV/useCases/createDocument/types.d.ts +4 -3
- package/dist/src/ATV/useCases/createReceptorMessage/index.d.ts +6 -5
- package/dist/src/ATV/useCases/createReceptorMessage/index.js +3 -3
- package/dist/src/ATV/useCases/createReceptorMessage/index.js.map +1 -1
- package/dist/src/helpers/comprobantes.js +10 -1
- package/dist/src/helpers/comprobantes.js.map +1 -1
- package/dist/src/lib/genClave/index.d.ts +8 -1
- package/dist/src/lib/genClave/index.js +5 -0
- package/dist/src/lib/genClave/index.js.map +1 -1
- package/dist/src/lib/genXML/index.js +6 -4
- package/dist/src/lib/genXML/index.js.map +1 -1
- package/dist/src/lib/genXML/sigXML/index.js +7 -4
- package/dist/src/lib/genXML/sigXML/index.js.map +1 -1
- package/dist/src/services/getToken/GetToken.js +0 -3
- package/dist/src/services/getToken/GetToken.js.map +1 -1
- package/dist/src/services/getToken/__tests__/GetToken.test.js +0 -1
- package/dist/src/services/getToken/__tests__/GetToken.test.js.map +1 -1
- package/dist/src/types/facturaInterfaces.d.ts +9 -3
- package/dist/src/xmlSchemaHeaderMap.d.ts +70 -0
- package/dist/src/xmlSchemaHeaderMap.js +30 -0
- package/dist/src/xmlSchemaHeaderMap.js.map +1 -0
- package/doc/atv-structures/4.3/FacturaElectronica_V4.3.xsd.xml +1633 -478
- package/doc/atv-structures/4.4/TiqueteElectronico_V4.4.xsd.xml +2817 -0
- package/doc/json-schemas/4.4/fe.json +544 -0
- package/doc/json-schemas/4.4/te.json +420 -0
- package/doc/testing.md +27 -0
- package/examples/README.md +10 -35
- package/examples/atvAccept.ts +18 -9
- package/examples/consultXML.ts +1 -0
- package/examples/{createAndSend.ts → createAndSendFE.ts} +11 -8
- package/examples/createAndSendTE.ts +73 -0
- package/examples/createCreditNote.ts +10 -6
- package/examples/createDebitNote.ts +2 -0
- package/examples/getToken.ts +2 -0
- package/package.json +3 -2
- package/src/ATV/core/CreateDocFactory.ts +32 -23
- package/src/ATV/core/Document.ts +15 -8
- package/src/ATV/core/DocumentType.ts +10 -3
- package/src/ATV/core/FullConsecutive.ts +2 -1
- package/src/ATV/core/OrderLine.ts +7 -1
- package/src/ATV/core/Person.ts +2 -2
- package/src/ATV/core/ReceptorConsecutive.ts +16 -16
- package/src/ATV/core/ReferenceInformation.ts +6 -6
- package/src/ATV/core/Summary.type.ts +5 -0
- package/src/ATV/core/types.ts +7 -6
- package/src/ATV/index.ts +3 -3
- package/src/ATV/mappers/billDocToAtv.ts +35 -15
- package/src/ATV/types.ts +1 -1
- package/src/ATV/useCases/createDocument/index.ts +8 -8
- package/src/ATV/useCases/createDocument/types.ts +5 -6
- package/src/ATV/useCases/createReceptorMessage/index.ts +94 -93
- package/src/helpers/comprobantes.ts +10 -1
- package/src/lib/genClave/index.ts +10 -3
- package/src/lib/genXML/index.ts +3 -1
- package/src/lib/genXML/sigXML/index.ts +6 -3
- package/src/services/getToken/GetToken.ts +0 -3
- package/src/services/getToken/__tests__/GetToken.test.ts +0 -1
- package/src/types/facturaInterfaces.ts +10 -4
- package/src/xmlSchemaHeaderMap.ts +37 -0
- package/tools/readXML.ts +2 -0
- package/tools/xsdToJsonSchema.ts +1 -0
- package/tsconfig.json +1 -0
- package/dist/src/ATV/core/documentNames.types.d.ts +0 -1
- package/dist/src/ATV/core/documentNames.types.js +0 -3
- package/dist/src/ATV/core/documentNames.types.js.map +0 -1
- package/dist/src/lib/genXML/xmlConfig.d.ts +0 -55
- package/dist/src/lib/genXML/xmlConfig.js +0 -42
- package/dist/src/lib/genXML/xmlConfig.js.map +0 -1
- package/src/ATV/core/documentNames.types.ts +0 -6
- package/src/lib/genXML/xmlConfig.ts +0 -60
|
@@ -29,9 +29,11 @@ const mapOrderLinesToAtvFormat = (orderLines: OrderLine[]): DetalleServicio => {
|
|
|
29
29
|
Impuesto: {
|
|
30
30
|
Codigo: orderLine.tax.code,
|
|
31
31
|
Tarifa: orderLine.tax.rate,
|
|
32
|
+
// @ts-expect-error pending-to-fix
|
|
32
33
|
Monto: parseAtvMoneyFormat(orderLine.tax.amount)
|
|
33
34
|
},
|
|
34
35
|
ImpuestoAsumidoEmisorFabrica: 0,
|
|
36
|
+
// @ts-expect-error pending-to-fix
|
|
35
37
|
ImpuestoNeto: parseAtvMoneyFormat(orderLine.tax.amount),
|
|
36
38
|
MontoTotalLinea: parseAtvMoneyFormat(orderLine.totalOrderLineAmount)
|
|
37
39
|
}
|
|
@@ -43,21 +45,28 @@ const mapSummaryInvoice = (document: DomainDocument): Resumen => {
|
|
|
43
45
|
const summaryInvoice = document.summaryInvoice
|
|
44
46
|
return {
|
|
45
47
|
CodigoTipoMoneda: {
|
|
48
|
+
// @ts-expect-error pending-to-fix
|
|
46
49
|
CodigoMoneda: summaryInvoice.currency.code,
|
|
50
|
+
// @ts-expect-error pending-to-fix
|
|
47
51
|
TipoCambio: summaryInvoice.currency.exchangeRate
|
|
48
52
|
},
|
|
49
53
|
TotalServGravados: parseAtvMoneyFormat(summaryInvoice.totalEncumberedServices),
|
|
50
54
|
TotalServExentos: parseAtvMoneyFormat(summaryInvoice.totalExemptServices),
|
|
55
|
+
// @ts-expect-error pending-to-fix
|
|
51
56
|
TotalMercanciasGravadas: parseAtvMoneyFormat(summaryInvoice.totalEncumberedMerchandise),
|
|
57
|
+
// @ts-expect-error pending-to-fix
|
|
52
58
|
TotalMercanciasExentas: parseAtvMoneyFormat(summaryInvoice.totalExemptMerchandise),
|
|
53
59
|
TotalGravado: parseAtvMoneyFormat(summaryInvoice.totalEncumbered),
|
|
54
60
|
TotalExento: parseAtvMoneyFormat(summaryInvoice.totalExempt),
|
|
55
61
|
TotalExonerado: parseAtvMoneyFormat(summaryInvoice.totalExonerated),
|
|
56
62
|
TotalVenta: parseAtvMoneyFormat(summaryInvoice.totalSale),
|
|
63
|
+
// @ts-expect-error pending-to-fix
|
|
57
64
|
TotalDescuentos: parseAtvMoneyFormat(summaryInvoice.totalDiscounts),
|
|
65
|
+
// @ts-expect-error pending-to-fix
|
|
58
66
|
TotalVentaNeta: parseAtvMoneyFormat(summaryInvoice.totalNetSale),
|
|
59
67
|
TotalImpuesto: parseAtvMoneyFormat(summaryInvoice.totalTaxes),
|
|
60
68
|
MedioPago: {
|
|
69
|
+
// @ts-expect-error pending-to-fix
|
|
61
70
|
TipoMedioPago: document.paymentMethod
|
|
62
71
|
},
|
|
63
72
|
TotalComprobante: parseAtvMoneyFormat(summaryInvoice.totalVoucher)
|
|
@@ -76,17 +85,24 @@ const mapPerson = (person: Person): Persona => {
|
|
|
76
85
|
Telefono: undefined,
|
|
77
86
|
CorreoElectronico: undefined
|
|
78
87
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
// @ts-expect-error pending-to-fix
|
|
89
|
+
atvPerson.Ubicacion = person.location
|
|
90
|
+
? {
|
|
91
|
+
Provincia: person.location?.province,
|
|
92
|
+
Canton: person.location?.canton?.padStart(2, '0'),
|
|
93
|
+
Distrito: person.location?.district?.padStart(2, '0'),
|
|
94
|
+
Barrio: person.location?.neighborhood?.padStart(5, '0'),
|
|
95
|
+
OtrasSenas: person.location?.details
|
|
96
|
+
}
|
|
97
|
+
: undefined
|
|
98
|
+
// @ts-expect-error pending-to-fix
|
|
99
|
+
atvPerson.Telefono = person.phone
|
|
100
|
+
? {
|
|
101
|
+
CodigoPais: person.phone?.countryCode,
|
|
102
|
+
NumTelefono: person.phone?.number
|
|
103
|
+
}
|
|
104
|
+
: undefined
|
|
105
|
+
// @ts-expect-error pending-to-fix
|
|
90
106
|
atvPerson.CorreoElectronico = person.email
|
|
91
107
|
|
|
92
108
|
return atvPerson
|
|
@@ -103,16 +119,20 @@ const mapReferenceInformation = (referenceInfo: ReferenceInformation): Informaci
|
|
|
103
119
|
}
|
|
104
120
|
|
|
105
121
|
export const mapDocumentToAtvFormat = (docName: string, document: DomainDocument): AtvFormat => {
|
|
106
|
-
const key = docName
|
|
122
|
+
const key = docName
|
|
107
123
|
const doc: AtvDocument = {
|
|
108
124
|
Clave: document.clave,
|
|
109
125
|
ProveedorSistemas: document.providerId,
|
|
110
126
|
CodigoActividadEmisor: document.emitter.activityCode.padStart(6, '0'),
|
|
111
|
-
|
|
127
|
+
...(document.receiver && { // TODO add && document.name === 'FacturaElectronica'
|
|
128
|
+
CodigoActividadReceptor: document.receiver.activityCode.padStart(6, '0')
|
|
129
|
+
}),
|
|
112
130
|
NumeroConsecutivo: document.fullConsecutive,
|
|
113
131
|
FechaEmision: document.issueDate.toISOString(),
|
|
114
132
|
Emisor: mapPerson(document.emitter),
|
|
115
|
-
|
|
133
|
+
...(document.receiver && {
|
|
134
|
+
Receptor: mapPerson(document.receiver)
|
|
135
|
+
}),
|
|
116
136
|
CondicionVenta: document.conditionSale,
|
|
117
137
|
PlazoCredito: document.deadlineCredit,
|
|
118
138
|
DetalleServicio: mapOrderLinesToAtvFormat(document.orderLines),
|
|
@@ -120,7 +140,7 @@ export const mapDocumentToAtvFormat = (docName: string, document: DomainDocument
|
|
|
120
140
|
Otros: document.others
|
|
121
141
|
}
|
|
122
142
|
if (document.referenceInformation) {
|
|
123
|
-
doc.InformacionReferencia = mapReferenceInformation(document.referenceInformation)
|
|
143
|
+
doc.InformacionReferencia = mapReferenceInformation(document.referenceInformation)
|
|
124
144
|
}
|
|
125
145
|
return {
|
|
126
146
|
[key]: doc
|
package/src/ATV/types.ts
CHANGED
|
@@ -18,7 +18,7 @@ const options: { [key: string]: { serviceUrl: string}} = {
|
|
|
18
18
|
export class CreateDocumentCommand {
|
|
19
19
|
private readonly serviceUrl: string
|
|
20
20
|
|
|
21
|
-
private readonly createDoc: CreateDocFactory
|
|
21
|
+
private readonly createDoc: CreateDocFactory
|
|
22
22
|
|
|
23
23
|
constructor(scope: ATV) {
|
|
24
24
|
this.serviceUrl = options[scope.mode].serviceUrl
|
|
@@ -26,7 +26,7 @@ export class CreateDocumentCommand {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
public async execute(dto: CreateDocumentInput): Promise<CreateAndSendDocumentResponse> {
|
|
29
|
-
const documentName = dto.document.documentName || 'FacturaElectronica' //TODO NotaDebitoElectronica
|
|
29
|
+
const documentName = dto.document.documentName || 'FacturaElectronica' // TODO NotaDebitoElectronica
|
|
30
30
|
const document = this.createDoc.createDocument(dto.document)
|
|
31
31
|
const atvDocument = mapBillToAtvFormat(documentName, document)
|
|
32
32
|
const xml = await genXML(documentName, atvDocument, dto.signatureOptions)
|
|
@@ -51,10 +51,12 @@ export class CreateDocumentCommand {
|
|
|
51
51
|
tipoIdentificacion: document.emitter.identifierType,
|
|
52
52
|
numeroIdentificacion: document.emitter.identifierId
|
|
53
53
|
},
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
...(document.receiver && {
|
|
55
|
+
receptor: {
|
|
56
|
+
tipoIdentificacion: document.receiver.identifierType,
|
|
57
|
+
numeroIdentificacion: document.receiver.identifierId
|
|
58
|
+
}
|
|
59
|
+
}),
|
|
58
60
|
comprobanteXml: this.encodeXML(xml)
|
|
59
61
|
},
|
|
60
62
|
headers: {
|
|
@@ -64,8 +66,6 @@ export class CreateDocumentCommand {
|
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
69
|
private encodeXML(xmlStr: string): string {
|
|
70
70
|
const buffer = Buffer.from(xmlStr)
|
|
71
71
|
return buffer.toString('base64')
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { InvoiceDocumentContainer } from '@src/types/facturaInterfaces';
|
|
1
|
+
import { PersonProps } from '@src/ATV/core/Person'
|
|
2
|
+
import { InvoiceDocumentContainer } from '@src/types/facturaInterfaces'
|
|
4
3
|
import { Method } from 'axios'
|
|
5
4
|
|
|
6
5
|
export type DocumentTypes = 'FE'
|
|
@@ -9,11 +8,11 @@ type CommandData = {
|
|
|
9
8
|
clave: string;
|
|
10
9
|
fecha: string;
|
|
11
10
|
emisor: {
|
|
12
|
-
tipoIdentificacion:
|
|
11
|
+
tipoIdentificacion: PersonProps['identifier']['type'];
|
|
13
12
|
numeroIdentificacion: string;
|
|
14
13
|
};
|
|
15
|
-
receptor
|
|
16
|
-
tipoIdentificacion:
|
|
14
|
+
receptor?: {
|
|
15
|
+
tipoIdentificacion: PersonProps['identifier']['type'];
|
|
17
16
|
numeroIdentificacion: string;
|
|
18
17
|
};
|
|
19
18
|
comprobanteXml: string;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { AceptationStates, ReceptorMessageProps } from
|
|
2
|
-
import { mapReceptorMessageToAtvFormat } from
|
|
3
|
-
import { genXML
|
|
4
|
-
import { Command } from
|
|
5
|
-
import { ATV } from
|
|
6
|
-
import { ReceptorConsecutive } from
|
|
1
|
+
import { AceptationStates, ReceptorMessageProps } from '@src/ATV/core/types'
|
|
2
|
+
import { mapReceptorMessageToAtvFormat } from '@src/ATV/mappers/billDocToAtv'
|
|
3
|
+
import { genXML } from '@src/lib/genXML'
|
|
4
|
+
import { Command } from '../createDocument/types'
|
|
5
|
+
import { ATV } from '@src/ATV'
|
|
6
|
+
import { ReceptorConsecutive } from '@src/ATV/core/ReceptorConsecutive'
|
|
7
|
+
import { PersonProps } from '@src/ATV/core/Person'
|
|
7
8
|
|
|
8
9
|
export type CreateReceptorMessageCommandInput = {
|
|
9
10
|
clave: string;
|
|
10
11
|
emitterIdentifier: string;
|
|
11
|
-
emitterIdentifierType:
|
|
12
|
+
emitterIdentifierType: PersonProps['identifier']['type'];
|
|
12
13
|
receptorIdentifier: string;
|
|
13
|
-
receptorIdentifierType:
|
|
14
|
+
receptorIdentifierType: PersonProps['identifier']['type'];
|
|
14
15
|
documentIssueDate: Date;
|
|
15
16
|
activityCode: string;
|
|
16
17
|
taxCondition: string;
|
|
@@ -29,101 +30,101 @@ export type CreateReceptorMessageCommandInput = {
|
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
const options: { [key: string]: { serviceUrl: string}} = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
33
|
+
prod: {
|
|
34
|
+
serviceUrl: 'https://api.comprobanteselectronicos.go.cr/recepcion/v1/recepcion'
|
|
35
|
+
},
|
|
36
|
+
stg: {
|
|
37
|
+
serviceUrl: 'https://api-sandbox.comprobanteselectronicos.go.cr/recepcion/v1/recepcion'
|
|
38
38
|
}
|
|
39
|
+
}
|
|
39
40
|
|
|
40
41
|
export class CreateReceptorMessageCommand {
|
|
41
|
-
|
|
42
|
+
private readonly serviceUrl: string
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
constructor(scope: ATV) {
|
|
45
|
+
this.serviceUrl = options[scope.mode].serviceUrl
|
|
46
|
+
}
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
48
|
+
public async execute(input: CreateReceptorMessageCommandInput) {
|
|
49
|
+
const receptorMessageProps = this.processDocument(input)
|
|
50
|
+
const atvDocument = mapReceptorMessageToAtvFormat(receptorMessageProps)
|
|
51
|
+
const xml = await genXML('MensajeReceptor', atvDocument, input.signatureOptions)
|
|
52
|
+
const command = await this.createDocumentCommand(receptorMessageProps, xml, input.token)
|
|
53
|
+
return {
|
|
54
|
+
command,
|
|
55
|
+
extraData: {
|
|
56
|
+
xml,
|
|
57
|
+
document: atvDocument
|
|
58
|
+
}
|
|
59
59
|
}
|
|
60
|
+
}
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
62
|
+
private async createDocumentCommand(receptorMessageProps: ReceptorMessageProps, xml: string, token: string): Promise<Command> {
|
|
63
|
+
return {
|
|
64
|
+
url: this.serviceUrl,
|
|
65
|
+
method: 'post',
|
|
66
|
+
data: {
|
|
67
|
+
clave: receptorMessageProps.clave,
|
|
68
|
+
fecha: receptorMessageProps.documentIssueDate.toISOString(),
|
|
69
|
+
emisor: {
|
|
70
|
+
tipoIdentificacion: receptorMessageProps.emitterIdentifierType,
|
|
71
|
+
numeroIdentificacion: receptorMessageProps.emitterIdentifier
|
|
72
|
+
},
|
|
73
|
+
receptor: {
|
|
74
|
+
tipoIdentificacion: receptorMessageProps.receptorIdentifierType,
|
|
75
|
+
numeroIdentificacion: receptorMessageProps.receptorIdentifier
|
|
76
|
+
},
|
|
77
|
+
comprobanteXml: this.encodeXML(xml),
|
|
78
|
+
consecutivoReceptor: receptorMessageProps.receptorConcecutive
|
|
79
|
+
},
|
|
80
|
+
headers: {
|
|
81
|
+
Authorization: 'bearer ' + token,
|
|
82
|
+
'Content-Type': 'application/json'
|
|
83
|
+
}
|
|
84
84
|
}
|
|
85
|
+
}
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
private encodeXML(xmlStr: string): string {
|
|
88
|
+
const buffer = Buffer.from(xmlStr)
|
|
89
|
+
return buffer.toString('base64')
|
|
90
|
+
}
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
92
|
+
private acceptationStateToDocumentType(aceptationState: AceptationStates) {
|
|
93
|
+
switch (aceptationState) {
|
|
94
|
+
case AceptationStates.ACCEPTED:
|
|
95
|
+
return '05'
|
|
96
|
+
case AceptationStates.PARTIALLY_ACCEPTED:
|
|
97
|
+
return '06'
|
|
98
|
+
default:
|
|
99
|
+
return '07'
|
|
100
100
|
}
|
|
101
|
+
}
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
103
|
+
private processDocument(input: CreateReceptorMessageCommandInput): ReceptorMessageProps {
|
|
104
|
+
try {
|
|
105
|
+
const receptorConsecutive = ReceptorConsecutive.create({
|
|
106
|
+
branch: input.branch,
|
|
107
|
+
terminal: input.terminal,
|
|
108
|
+
documentType: this.acceptationStateToDocumentType(input.aceptationState),
|
|
109
|
+
consecutive: input.consecutive
|
|
110
|
+
})
|
|
111
|
+
return {
|
|
112
|
+
clave: input.clave,
|
|
113
|
+
emitterIdentifier: input.emitterIdentifier,
|
|
114
|
+
emitterIdentifierType: input.emitterIdentifierType,
|
|
115
|
+
receptorIdentifier: input.receptorIdentifier,
|
|
116
|
+
receptorIdentifierType: input.receptorIdentifierType,
|
|
117
|
+
documentIssueDate: input.documentIssueDate,
|
|
118
|
+
activityCode: input.activityCode,
|
|
119
|
+
taxCondition: input.taxCondition,
|
|
120
|
+
totalTaxes: input.totalTaxes,
|
|
121
|
+
totalSale: input.totalSale,
|
|
122
|
+
aceptationState: input.aceptationState,
|
|
123
|
+
aceptationDetailMessage: input.aceptationDetailMessage,
|
|
124
|
+
receptorConcecutive: receptorConsecutive.value
|
|
125
|
+
}
|
|
126
|
+
} catch (err) {
|
|
127
|
+
throw new Error(`Error parsing the document ${err}`)
|
|
128
128
|
}
|
|
129
|
-
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -12,6 +12,7 @@ const DEFAULT_VALUES = {
|
|
|
12
12
|
export function getSimpleSender(frontEndRequest: ClientPayload): FinalMessagePerson {
|
|
13
13
|
const sender = frontEndRequest.Emisor
|
|
14
14
|
return {
|
|
15
|
+
// @ts-expect-error pending-to-fix
|
|
15
16
|
tipoIdentificacion: sender.Identificacion.Tipo || DEFAULT_VALUES.tipoIdentificacion,
|
|
16
17
|
numeroIdentificacion: sender.Identificacion.Numero
|
|
17
18
|
}
|
|
@@ -20,6 +21,7 @@ export function getSimpleSender(frontEndRequest: ClientPayload): FinalMessagePer
|
|
|
20
21
|
export function getSimpleReceiver(frontEndRequest: ClientPayload): FinalMessagePerson {
|
|
21
22
|
const receiver = frontEndRequest.Receptor
|
|
22
23
|
return {
|
|
24
|
+
// @ts-expect-error pending-to-fix
|
|
23
25
|
tipoIdentificacion: receiver.Identificacion.Tipo || DEFAULT_VALUES.tipoIdentificacion,
|
|
24
26
|
numeroIdentificacion: receiver.Identificacion.Numero
|
|
25
27
|
}
|
|
@@ -31,11 +33,12 @@ function calculateTaxes(billTotal: number, billTaxes: number): number {
|
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
export function getBillResum(frontEndRequest: ClientPayload): Resumen {
|
|
36
|
+
// @ts-expect-error pending-to-fix
|
|
34
37
|
const taxes = calculateTaxes(frontEndRequest.total, frontEndRequest.impuesto)
|
|
35
38
|
return {
|
|
36
39
|
CodigoTipoMoneda: {
|
|
37
40
|
CodigoMoneda: 'CRC',
|
|
38
|
-
TipoCambio: '
|
|
41
|
+
TipoCambio: '1'
|
|
39
42
|
},
|
|
40
43
|
TotalServGravados: 0,
|
|
41
44
|
TotalServExentos: 0,
|
|
@@ -45,10 +48,12 @@ export function getBillResum(frontEndRequest: ClientPayload): Resumen {
|
|
|
45
48
|
TotalGravado: frontEndRequest.total,
|
|
46
49
|
TotalExento: 0,
|
|
47
50
|
TotalExonerado: 0,
|
|
51
|
+
// @ts-expect-error pending-to-fix
|
|
48
52
|
TotalVenta: frontEndRequest.total,
|
|
49
53
|
TotalDescuentos: 0,
|
|
50
54
|
TotalVentaNeta: frontEndRequest.total,
|
|
51
55
|
TotalImpuesto: taxes,
|
|
56
|
+
// @ts-expect-error pending-to-fix
|
|
52
57
|
TotalComprobante: frontEndRequest.total + taxes
|
|
53
58
|
}
|
|
54
59
|
}
|
|
@@ -64,11 +69,15 @@ export function getSender(frontEndRequest: ClientPayload): Persona {
|
|
|
64
69
|
NombreComercial: sender.Nombre,
|
|
65
70
|
Ubicacion: sender.Ubicacion,
|
|
66
71
|
Telefono: {
|
|
72
|
+
// @ts-expect-error pending-to-fix
|
|
67
73
|
CodigoPais: sender.Telefono.CodigoPais,
|
|
74
|
+
// @ts-expect-error pending-to-fix
|
|
68
75
|
NumTelefono: sender.Telefono.NumTelefono
|
|
69
76
|
},
|
|
70
77
|
Fax: {
|
|
78
|
+
// @ts-expect-error pending-to-fix
|
|
71
79
|
CodigoPais: sender.Telefono.CodigoPais,
|
|
80
|
+
// @ts-expect-error pending-to-fix
|
|
72
81
|
NumTelefono: sender.Telefono.NumTelefono
|
|
73
82
|
},
|
|
74
83
|
CorreoElectronico: sender.CorreoElectronico
|
|
@@ -8,12 +8,15 @@ const DEFAULT_VALUES = {
|
|
|
8
8
|
codigoPais: '506'
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
type ConsecutivoInput = {
|
|
12
12
|
tipoDocKey?: string;
|
|
13
13
|
sucursal?: string;
|
|
14
14
|
terminal?: string;
|
|
15
15
|
consecutivo: string;
|
|
16
|
-
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getConsecutivo(opts: ConsecutivoInput): Consecutivo {
|
|
19
|
+
// @ts-expect-error pending-to-fix
|
|
17
20
|
const tipoDocNum = tipoDocumento[opts.tipoDocKey]
|
|
18
21
|
return {
|
|
19
22
|
sucursal: opts.sucursal || '001',
|
|
@@ -23,7 +26,7 @@ function getConsecutivo(opts: {
|
|
|
23
26
|
}
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
export function consecutivoStr(consecutivoObj:
|
|
29
|
+
export function consecutivoStr(consecutivoObj: ConsecutivoInput): string {
|
|
27
30
|
const cons = getConsecutivo(consecutivoObj)
|
|
28
31
|
return Object.values(cons).join('')
|
|
29
32
|
}
|
|
@@ -111,13 +114,17 @@ export function parseOptions(frontEndRequest: ClientPayload): ClaveOpts {
|
|
|
111
114
|
const sender = getSender(frontEndRequest)
|
|
112
115
|
return {
|
|
113
116
|
cedulaEmisor: sender.numeroIdentificacion,
|
|
117
|
+
// @ts-expect-error pending-to-fix
|
|
114
118
|
codigoPais: frontEndRequest.codigoPais,
|
|
115
119
|
codigoSeguridad: frontEndRequest.codigoSeguridad,
|
|
116
120
|
consecutivo: frontEndRequest.consecutivo,
|
|
117
121
|
situacionCE: frontEndRequest.situationEC,
|
|
122
|
+
// @ts-expect-error pending-to-fix
|
|
118
123
|
sucursal: frontEndRequest.sucursal,
|
|
124
|
+
// @ts-expect-error pending-to-fix
|
|
119
125
|
terminal: frontEndRequest.terminal,
|
|
120
126
|
tipoCedula: sender.tipoIdentificacion,
|
|
127
|
+
// @ts-expect-error pending-to-fix
|
|
121
128
|
tipoDocKey: frontEndRequest.tipoDocumento
|
|
122
129
|
}
|
|
123
130
|
}
|
package/src/lib/genXML/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { j2xParser, parse } from 'fast-xml-parser'
|
|
2
|
-
import { declaration, defaultOptions, xmlExtructures } from '@src/
|
|
2
|
+
import { declaration, defaultOptions, xmlExtructures } from '@src/xmlSchemaHeaderMap'
|
|
3
3
|
import sigXML from '@src/lib/genXML/sigXML/index'
|
|
4
4
|
import { XMLRawDocument } from '@src/types/facturaInterfaces'
|
|
5
5
|
|
|
@@ -18,6 +18,7 @@ export async function genXML(xmlStructure: string, obj: object, options?: {
|
|
|
18
18
|
}): Promise<string> {
|
|
19
19
|
const xml = objToXML(xmlStructure, obj)
|
|
20
20
|
if (!options) return xml
|
|
21
|
+
// @ts-expect-error pending-to-fix
|
|
21
22
|
const signedXML = await sigXML(xml, options.buffer, options.password)
|
|
22
23
|
return signedXML
|
|
23
24
|
}
|
|
@@ -31,6 +32,7 @@ export const parseElectronicBillXML = (xml: string): XMLRawDocument => {
|
|
|
31
32
|
})
|
|
32
33
|
return json.FacturaElectronica
|
|
33
34
|
} catch (err) {
|
|
35
|
+
// @ts-expect-error pending-to-fix
|
|
34
36
|
return null
|
|
35
37
|
}
|
|
36
38
|
}
|
|
@@ -2,7 +2,7 @@ import { Application, SignedXml, Parse, OptionsXAdES } from 'xadesjs'
|
|
|
2
2
|
import { Crypto } from '@peculiar/webcrypto'
|
|
3
3
|
import { genKeysAndCert } from '@src/lib/genXML/sigXML/genKeysAndCert'
|
|
4
4
|
import { XMLSerializer } from 'xmldom-alpha'
|
|
5
|
-
import { ATV_VERSION } from '
|
|
5
|
+
import { ATV_VERSION } from '@src/xmlSchemaHeaderMap'
|
|
6
6
|
|
|
7
7
|
function addSigToXML(xml: Document, signature: any): string {
|
|
8
8
|
xml.documentElement.appendChild(signature.GetXml())
|
|
@@ -58,15 +58,18 @@ function getAlgorithm(): any {
|
|
|
58
58
|
export default async function signXML(xmlStr: string, p12: string, p12Password: string): Promise<string> {
|
|
59
59
|
if (!p12 || !p12Password) {
|
|
60
60
|
console.log('p12 options undefined')
|
|
61
|
+
// @ts-expect-error pending-to-fix
|
|
61
62
|
return
|
|
62
63
|
}
|
|
63
64
|
const crypto = new Crypto()
|
|
64
65
|
const referenceId = generateId(crypto)
|
|
65
|
-
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
67
|
+
// @ts-expect-error
|
|
66
68
|
Application.setEngine('OpenSSL', crypto)
|
|
67
69
|
const xadesXml = new SignedXml()
|
|
68
70
|
const algorithm = getAlgorithm()
|
|
69
|
-
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
72
|
+
// @ts-expect-error
|
|
70
73
|
const result = genKeysAndCert(crypto, {
|
|
71
74
|
algorithm,
|
|
72
75
|
keyStr: p12,
|
|
@@ -23,11 +23,8 @@ export class GetToken {
|
|
|
23
23
|
|
|
24
24
|
public async execute({ username, password }: GetTokenDto): Promise<GetTokenResponse> {
|
|
25
25
|
const fetchResponse = await axios.post<GetTokenRawResponse>(this.props.serviceUrl, qs.stringify({
|
|
26
|
-
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
27
26
|
client_id: this.props.clientId,
|
|
28
|
-
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
29
27
|
grant_type: 'password',
|
|
30
|
-
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
31
28
|
client_secret: '',
|
|
32
29
|
username,
|
|
33
30
|
password
|
|
@@ -20,7 +20,7 @@ export interface LineaDetalle {
|
|
|
20
20
|
SubTotal?: number;
|
|
21
21
|
BaseImponible?: number;
|
|
22
22
|
Impuesto?: Impuesto;
|
|
23
|
-
ImpuestoAsumidoEmisorFabrica
|
|
23
|
+
ImpuestoAsumidoEmisorFabrica?: number;
|
|
24
24
|
MontoTotalLinea?: number;
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -28,6 +28,12 @@ export interface DetalleServicio {
|
|
|
28
28
|
LineaDetalle: Array<LineaDetalle>;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
export interface TotalDesgloseImpuesto {
|
|
32
|
+
Codigo: string; // Representa el tipo "CodigoImpuestoType"
|
|
33
|
+
CodigoTarifaIVA?: string; // Representa el tipo "CodigoTarifaIVAType"
|
|
34
|
+
TotalMontoImpuesto: number; // Representa el tipo "DecimalDineroType"
|
|
35
|
+
}
|
|
36
|
+
|
|
31
37
|
export interface Resumen {
|
|
32
38
|
CodigoTipoMoneda?: {
|
|
33
39
|
CodigoMoneda: string;
|
|
@@ -49,6 +55,7 @@ export interface Resumen {
|
|
|
49
55
|
TipoMedioPago: string;
|
|
50
56
|
};
|
|
51
57
|
TotalComprobante: number;
|
|
58
|
+
TotalDesgloseImpuesto?: Array<TotalDesgloseImpuesto>; // Agregado aquí
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
export interface Persona {
|
|
@@ -93,14 +100,13 @@ export interface AtvDocument {
|
|
|
93
100
|
Clave: string;
|
|
94
101
|
ProveedorSistemas: string;
|
|
95
102
|
CodigoActividadEmisor: string;
|
|
96
|
-
CodigoActividadReceptor
|
|
103
|
+
CodigoActividadReceptor?: string; // TODO check supported docs
|
|
97
104
|
NumeroConsecutivo: string;
|
|
98
105
|
FechaEmision?: string;
|
|
99
106
|
Emisor: Persona;
|
|
100
|
-
Receptor
|
|
107
|
+
Receptor?: Persona;
|
|
101
108
|
CondicionVenta?: string;
|
|
102
109
|
PlazoCredito?: string;
|
|
103
|
-
|
|
104
110
|
DetalleServicio?: DetalleServicio;
|
|
105
111
|
ResumenFactura: Resumen;
|
|
106
112
|
Otros?: {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const ATV_VERSION = '4.4'
|
|
2
|
+
|
|
3
|
+
const BASE_DOMAIN = 'https://cdn.comprobanteselectronicos.go.cr/xml-schemas'
|
|
4
|
+
|
|
5
|
+
const buildNs = (type: string) =>
|
|
6
|
+
`${BASE_DOMAIN}/v${ATV_VERSION}/${type}`
|
|
7
|
+
|
|
8
|
+
export const declaration = '<?xml version="1.0" encoding="utf-8"?>'
|
|
9
|
+
|
|
10
|
+
export const defaultOptions = {
|
|
11
|
+
attrNodeName: 'attr'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const COMMON_STRUCTURE = {
|
|
15
|
+
'xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#',
|
|
16
|
+
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
|
|
17
|
+
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function buildAttrs(type: string) {
|
|
21
|
+
return Object.assign(
|
|
22
|
+
{ xmlns: buildNs(type) },
|
|
23
|
+
COMMON_STRUCTURE
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const xmlExtructures = {
|
|
28
|
+
FacturaElectronica: buildAttrs('facturaElectronica'),
|
|
29
|
+
TiqueteElectronico: buildAttrs('tiqueteElectronico'),
|
|
30
|
+
FacturaElectronicaExportacion: buildAttrs('facturaElectronica'),
|
|
31
|
+
NotaCreditoElectronica: buildAttrs('notaCreditoElectronica'),
|
|
32
|
+
NotaDebitoElectronica: buildAttrs('notaCreditoElectronica'),
|
|
33
|
+
MensajeReceptor: buildAttrs('mensajeReceptor'),
|
|
34
|
+
CCE: buildAttrs('mensajeReceptor'),
|
|
35
|
+
CPCE: buildAttrs('mensajeReceptor'),
|
|
36
|
+
RCE: buildAttrs('mensajeReceptor')
|
|
37
|
+
}
|