@facturacr/atv-sdk 0.0.25-beta → 1.0.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/.github/workflows/ci.yml +2 -2
- package/.github/workflows/publish.yml +27 -0
- package/CHANGELOG.md +29 -0
- package/__tests__/stubs/commonExpectedXml.xml +13 -13
- package/__tests__/stubs/{createDocument.stub.ts → createDocument.data.ts} +23 -15
- package/__tests__/tests/ATV/__snapshots__/index.test.ts.snap +1 -1
- package/__tests__/tests/ATV/index.test.ts +5 -5
- package/dist/src/ATV/core/CreateDocFactory.d.ts +53 -0
- package/dist/src/ATV/core/CreateDocFactory.js +67 -0
- package/dist/src/ATV/core/CreateDocFactory.js.map +1 -0
- package/dist/src/ATV/core/Document.d.ts +3 -0
- package/dist/src/ATV/core/Document.js +3 -0
- package/dist/src/ATV/core/Document.js.map +1 -1
- package/dist/src/ATV/core/ReferenceInformation.d.ts +17 -0
- package/dist/src/ATV/core/ReferenceInformation.js +28 -0
- package/dist/src/ATV/core/ReferenceInformation.js.map +1 -0
- package/dist/src/ATV/index.d.ts +2 -1
- package/dist/src/ATV/index.js.map +1 -1
- package/dist/src/ATV/mappers/billDocToAtv.js +12 -0
- package/dist/src/ATV/mappers/billDocToAtv.js.map +1 -1
- package/dist/src/ATV/useCases/createDocument/index.d.ts +3 -8
- package/dist/src/ATV/useCases/createDocument/index.js +4 -68
- package/dist/src/ATV/useCases/createDocument/index.js.map +1 -1
- package/dist/src/ATV/useCases/createDocument/types.d.ts +0 -43
- package/dist/src/index.d.ts +1 -1
- package/dist/src/types/facturaInterfaces.d.ts +8 -0
- package/examples/createAndSend.ts +8 -5
- package/examples/createCreditNote.ts +52 -22
- package/package.json +1 -1
- package/src/ATV/core/CreateDocFactory.ts +117 -0
- package/src/ATV/core/Document.ts +6 -0
- package/src/ATV/core/ReferenceInformation.ts +41 -0
- package/src/ATV/index.ts +2 -1
- package/src/ATV/mappers/billDocToAtv.ts +15 -1
- package/src/ATV/useCases/createDocument/index.ts +9 -74
- package/src/ATV/useCases/createDocument/types.ts +2 -48
- package/src/index.ts +1 -1
- package/src/types/facturaInterfaces.ts +9 -0
|
@@ -10,14 +10,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.CreateDocumentCommand = void 0;
|
|
13
|
-
const Person_1 = require("../../core/Person");
|
|
14
|
-
const OrderLine_1 = require("../../core/OrderLine");
|
|
15
|
-
const FullConsecutive_1 = require("../../core/FullConsecutive");
|
|
16
|
-
const Document_1 = require("../../core/Document");
|
|
17
|
-
const Clave_1 = require("../../core/Clave");
|
|
18
13
|
const billDocToAtv_1 = require("../../mappers/billDocToAtv");
|
|
19
14
|
const genXML_1 = require("../../../lib/genXML");
|
|
20
|
-
const
|
|
15
|
+
const CreateDocFactory_1 = require("../../core/CreateDocFactory");
|
|
21
16
|
const options = {
|
|
22
17
|
prod: {
|
|
23
18
|
serviceUrl: 'https://api.comprobanteselectronicos.go.cr/v1/recepcion'
|
|
@@ -29,11 +24,12 @@ const options = {
|
|
|
29
24
|
class CreateDocumentCommand {
|
|
30
25
|
constructor(scope) {
|
|
31
26
|
this.serviceUrl = options[scope.mode].serviceUrl;
|
|
27
|
+
this.createDoc = new CreateDocFactory_1.CreateDocFactory();
|
|
32
28
|
}
|
|
33
29
|
execute(dto) {
|
|
34
30
|
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
-
const documentName = dto.document.documentName || 'FacturaElectronica';
|
|
36
|
-
const document = this.createDocument(dto.document);
|
|
31
|
+
const documentName = dto.document.documentName || 'FacturaElectronica'; //TODO NotaDebitoElectronica
|
|
32
|
+
const document = this.createDoc.createDocument(dto.document);
|
|
37
33
|
const atvDocument = (0, billDocToAtv_1.mapDocumentToAtvFormat)(documentName, document);
|
|
38
34
|
const xml = yield (0, genXML_1.genXML)(documentName, atvDocument, dto.signatureOptions);
|
|
39
35
|
const command = yield this.createDocumentCommand(document, xml, dto.token);
|
|
@@ -71,66 +67,6 @@ class CreateDocumentCommand {
|
|
|
71
67
|
};
|
|
72
68
|
});
|
|
73
69
|
}
|
|
74
|
-
createDocument(document) {
|
|
75
|
-
const documentType = DocumentType_1.DocumentType.create(document.documentName);
|
|
76
|
-
const emitter = this.createEmitter(document.emitter);
|
|
77
|
-
const receiver = this.createReceiver(document.receiver);
|
|
78
|
-
const clave = this.createClave(document, documentType);
|
|
79
|
-
const fullConsective = this.createFullConsecutive(document, documentType);
|
|
80
|
-
const orderLines = this.createOrderLines(document);
|
|
81
|
-
return Document_1.Document.create({
|
|
82
|
-
clave,
|
|
83
|
-
fullConsecutive: fullConsective,
|
|
84
|
-
orderLines,
|
|
85
|
-
activityCode: document.activityCode,
|
|
86
|
-
issueDate: new Date(),
|
|
87
|
-
emitter,
|
|
88
|
-
receiver,
|
|
89
|
-
conditionSale: '01',
|
|
90
|
-
paymentMethod: '01'
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
createEmitter(emitterInput) {
|
|
94
|
-
return Person_1.Person.create(emitterInput);
|
|
95
|
-
}
|
|
96
|
-
createReceiver(receiverInput) {
|
|
97
|
-
return Person_1.Person.create(receiverInput);
|
|
98
|
-
}
|
|
99
|
-
createOrderLines(dto) {
|
|
100
|
-
return dto.orderLines.map((orderLine, index) => {
|
|
101
|
-
return OrderLine_1.OrderLine.create({
|
|
102
|
-
detail: orderLine.detail,
|
|
103
|
-
unitaryPrice: orderLine.unitaryPrice,
|
|
104
|
-
lineNumber: orderLine.lineNumber || (index + 1).toString(),
|
|
105
|
-
code: orderLine.code,
|
|
106
|
-
quantity: orderLine.quantity,
|
|
107
|
-
measureUnit: orderLine.measureUnit,
|
|
108
|
-
totalAmount: orderLine.totalAmount,
|
|
109
|
-
tax: orderLine.tax
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
createFullConsecutive(dto, docType) {
|
|
114
|
-
return FullConsecutive_1.FullConsecutive.create({
|
|
115
|
-
consecutiveIdentifier: dto.consecutiveIdentifier,
|
|
116
|
-
branch: dto.branch.padStart(3, '0'),
|
|
117
|
-
terminal: dto.terminal.padStart(5, '0'),
|
|
118
|
-
documentType: docType.value
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
createClave(dto, docType) {
|
|
122
|
-
return Clave_1.Clave.create({
|
|
123
|
-
branch: dto.branch,
|
|
124
|
-
ceSituation: dto.ceSituation,
|
|
125
|
-
consecutiveIdentifier: dto.consecutiveIdentifier,
|
|
126
|
-
countryCode: dto.countryCode,
|
|
127
|
-
docKeyType: docType.value,
|
|
128
|
-
emitterIdentifier: dto.emitter.identifier.id,
|
|
129
|
-
identifierType: dto.emitter.identifier.type, // TODO add default
|
|
130
|
-
securityCode: dto.securityCode,
|
|
131
|
-
terminal: dto.terminal
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
70
|
encodeXML(xmlStr) {
|
|
135
71
|
const buffer = Buffer.from(xmlStr);
|
|
136
72
|
return buffer.toString('base64');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/ATV/useCases/createDocument/index.ts"],"names":[],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/ATV/useCases/createDocument/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAEA,6DAA4F;AAC5F,gDAAwC;AAGxC,kEAAsF;AAEtF,MAAM,OAAO,GAA4C;IACvD,IAAI,EAAE;QACJ,UAAU,EAAE,yDAAyD;KACtE;IACD,GAAG,EAAE;QACH,UAAU,EAAE,2EAA2E;KACxF;CACF,CAAA;AAED,MAAa,qBAAqB;IAKhC,YAAY,KAAU;QACpB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,UAAU,CAAA;QAChD,IAAI,CAAC,SAAS,GAAG,IAAI,mCAAgB,EAAE,CAAA;IACzC,CAAC;IAEY,OAAO,CAAC,GAAwB;;YAC3C,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,YAAY,IAAI,oBAAoB,CAAA,CAAC,4BAA4B;YACnG,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YAC5D,MAAM,WAAW,GAAG,IAAA,qCAAkB,EAAC,YAAY,EAAE,QAAQ,CAAC,CAAA;YAC9D,MAAM,GAAG,GAAG,MAAM,IAAA,eAAM,EAAC,YAAY,EAAE,WAAW,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAA;YACzE,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;YAC1E,OAAO;gBACL,OAAO;gBACP,SAAS,EAAE;oBACT,GAAG;oBACH,QAAQ,EAAE,WAAW;iBACtB;aACF,CAAA;QACH,CAAC;KAAA;IAEa,qBAAqB,CAAC,QAAkB,EAAE,GAAW,EAAE,KAAa;;YAChF,OAAO;gBACL,GAAG,EAAE,IAAI,CAAC,UAAU;gBACpB,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE;oBACJ,KAAK,EAAE,QAAQ,CAAC,KAAK;oBACrB,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE;oBACvC,MAAM,EAAE;wBACN,kBAAkB,EAAE,QAAQ,CAAC,OAAO,CAAC,cAAc;wBACnD,oBAAoB,EAAE,QAAQ,CAAC,OAAO,CAAC,YAAY;qBACpD;oBACD,QAAQ,EAAE;wBACR,kBAAkB,EAAE,QAAQ,CAAC,QAAQ,CAAC,cAAc;wBACpD,oBAAoB,EAAE,QAAQ,CAAC,QAAQ,CAAC,YAAY;qBACrD;oBACD,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;iBACpC;gBACD,OAAO,EAAE;oBACP,aAAa,EAAE,SAAS,GAAG,KAAK;oBAChC,cAAc,EAAE,kBAAkB;iBACnC;aACF,CAAA;QACH,CAAC;KAAA;IAIO,SAAS,CAAC,MAAc;QAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAClC,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAClC,CAAC;CACF;AAvDD,sDAuDC"}
|
|
@@ -1,48 +1,6 @@
|
|
|
1
|
-
import { PersonProps } from '@src/ATV/core/Person';
|
|
2
|
-
import { DocumentNames } from '@src/ATV/core/documentNames.types';
|
|
3
1
|
import { InvoiceDocumentContainer } from '@src/types/facturaInterfaces';
|
|
4
2
|
import { Method } from 'axios';
|
|
5
|
-
type PersonInput = PersonProps;
|
|
6
|
-
type TaxInput = {
|
|
7
|
-
code: string;
|
|
8
|
-
rateCode: string;
|
|
9
|
-
rate: number;
|
|
10
|
-
amount?: number;
|
|
11
|
-
};
|
|
12
|
-
type OrderInput = {
|
|
13
|
-
detail: string;
|
|
14
|
-
unitaryPrice: number;
|
|
15
|
-
lineNumber?: string;
|
|
16
|
-
code?: string;
|
|
17
|
-
quantity?: number;
|
|
18
|
-
measureUnit?: string;
|
|
19
|
-
totalAmount?: number;
|
|
20
|
-
subTotal?: number;
|
|
21
|
-
tax?: TaxInput;
|
|
22
|
-
totalOrderLineAmount?: number;
|
|
23
|
-
};
|
|
24
3
|
export type DocumentTypes = 'FE';
|
|
25
|
-
type DocumentInput = {
|
|
26
|
-
emitter: PersonInput;
|
|
27
|
-
receiver: PersonInput;
|
|
28
|
-
branch: string;
|
|
29
|
-
terminal: string;
|
|
30
|
-
documentName: DocumentNames;
|
|
31
|
-
countryCode: string;
|
|
32
|
-
securityCode: string;
|
|
33
|
-
activityCode: string;
|
|
34
|
-
consecutiveIdentifier: string;
|
|
35
|
-
ceSituation: string;
|
|
36
|
-
orderLines: OrderInput[];
|
|
37
|
-
};
|
|
38
|
-
export type CreateDocumentInput = {
|
|
39
|
-
document: DocumentInput;
|
|
40
|
-
token: string;
|
|
41
|
-
signatureOptions: {
|
|
42
|
-
buffer: string;
|
|
43
|
-
password: string;
|
|
44
|
-
};
|
|
45
|
-
};
|
|
46
4
|
export type Command = {
|
|
47
5
|
url: string;
|
|
48
6
|
method: Method;
|
|
@@ -71,4 +29,3 @@ export type CreateAndSendDocumentResponse = {
|
|
|
71
29
|
document: InvoiceDocumentContainer;
|
|
72
30
|
};
|
|
73
31
|
};
|
|
74
|
-
export {};
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { Document, InvoiceDocumentContainer, DetalleServicio, Resumen, Persona } from './types/facturaInterfaces';
|
|
2
|
-
export { CreateDocumentInput } from './ATV/
|
|
2
|
+
export { CreateDocumentInput } from './ATV/core/CreateDocFactory';
|
|
3
3
|
export { ATV } from './ATV';
|
|
@@ -66,6 +66,13 @@ export interface Message {
|
|
|
66
66
|
Mensaje: string;
|
|
67
67
|
DetalleMensaje: string;
|
|
68
68
|
}
|
|
69
|
+
export interface InformacionReferencia {
|
|
70
|
+
TipoDoc: string;
|
|
71
|
+
Numero: string;
|
|
72
|
+
FechaEmision: string;
|
|
73
|
+
Codigo: string;
|
|
74
|
+
Razon: string;
|
|
75
|
+
}
|
|
69
76
|
export interface Document {
|
|
70
77
|
Clave: string;
|
|
71
78
|
CodigoActividad: string;
|
|
@@ -81,6 +88,7 @@ export interface Document {
|
|
|
81
88
|
Otros?: {
|
|
82
89
|
OtroTexto: string;
|
|
83
90
|
};
|
|
91
|
+
InformacionReferencia?: InformacionReferencia;
|
|
84
92
|
}
|
|
85
93
|
export interface InvoiceDocumentContainer {
|
|
86
94
|
[key: string]: Document;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'fs'
|
|
2
|
-
import {
|
|
2
|
+
import { createDocumentInputExample } from '@test/stubs/createDocument.data'
|
|
3
3
|
import { ATV } from '../dist/src'
|
|
4
|
+
import { PersonProps } from 'dist/src/ATV/core/Person'
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
const IS_STG = process.env.IS_STG
|
|
@@ -17,10 +18,12 @@ if (!SOURCE_P12_PASSPORT || !SOURCE_P12_URI) {
|
|
|
17
18
|
|
|
18
19
|
const pem = fs.readFileSync(SOURCE_P12_URI, 'binary')
|
|
19
20
|
|
|
20
|
-
console.log('requestStub consecutivo', createDocumentInputStub.consecutiveIdentifier)
|
|
21
|
-
|
|
22
21
|
// TODO: dynamic param --identifier 1 args[x]
|
|
23
|
-
|
|
22
|
+
createDocumentInputExample.consecutiveIdentifier = process.env.TEST_CONSECUTIVE
|
|
23
|
+
createDocumentInputExample.emitter.identifier.id = process.env.EMITTER_IDENTIFIER_ID as string;
|
|
24
|
+
createDocumentInputExample.emitter.identifier.type = process.env.EMITTER_IDENTIFIER_TYPE as PersonProps['identifier']['type'];
|
|
25
|
+
|
|
26
|
+
console.log('requestStub consecutivo', createDocumentInputExample.consecutiveIdentifier)
|
|
24
27
|
|
|
25
28
|
function getConfimation(atv: ATV, token: string, location: string, ms: number): Promise<any> {
|
|
26
29
|
return new Promise((resolve, reject): any => {
|
|
@@ -45,7 +48,7 @@ async function main(): Promise<void> {
|
|
|
45
48
|
password: PASSWORD_TEST
|
|
46
49
|
})
|
|
47
50
|
const { command, extraData } = await atv.createDocumentCommand({
|
|
48
|
-
document:
|
|
51
|
+
document: createDocumentInputExample,
|
|
49
52
|
token: tokenData.accessToken,
|
|
50
53
|
signatureOptions: {
|
|
51
54
|
buffer: pem,
|
|
@@ -1,39 +1,69 @@
|
|
|
1
|
-
import { ClientPayload } from '@src/types/globalInterfaces'
|
|
2
|
-
import creditNote from '@src/creditNote'
|
|
3
|
-
import getToken from '@src/services/getToken'
|
|
4
|
-
import requestStub from '@test/stubs/frontendRequest.stub'
|
|
5
1
|
import fs from 'fs'
|
|
2
|
+
import { createDocumentInputExample, creditNoteReferenceInfoExample } from '@test/stubs/createDocument.data'
|
|
3
|
+
import { ATV } from '../dist/src'
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
|
|
6
|
+
const IS_STG = process.env.IS_STG
|
|
8
7
|
const USERNAME_TEST = process.env.USERNAME_TEST
|
|
9
8
|
const PASSWORD_TEST = process.env.PASSWORD_TEST
|
|
9
|
+
console.log('process.env.IS_STG', IS_STG)
|
|
10
|
+
|
|
10
11
|
const SOURCE_P12_URI = process.env.SOURCE_P12_URI
|
|
11
12
|
const SOURCE_P12_PASSPORT = process.env.SOURCE_P12_PASSPORT
|
|
13
|
+
|
|
14
|
+
if (!SOURCE_P12_PASSPORT || !SOURCE_P12_URI) {
|
|
15
|
+
throw new Error('No environment. For running examples set .env before.')
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
const pem = fs.readFileSync(SOURCE_P12_URI, 'binary')
|
|
13
19
|
|
|
20
|
+
console.log('requestStub consecutivo', createDocumentInputExample.consecutiveIdentifier)
|
|
21
|
+
|
|
22
|
+
// TODO: dynamic param --identifier 1 args[x]
|
|
23
|
+
createDocumentInputExample.consecutiveIdentifier = '5'
|
|
24
|
+
|
|
25
|
+
function getConfimation(atv: ATV, token: string, location: string, ms: number): Promise<any> {
|
|
26
|
+
return new Promise((resolve, reject): any => {
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
console.log('location', location)
|
|
29
|
+
atv.sendConfirmation({
|
|
30
|
+
url: location,
|
|
31
|
+
headers: {
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
Authorization: 'bearer ' + token
|
|
34
|
+
}
|
|
35
|
+
}).then(data => resolve(data))
|
|
36
|
+
.catch(err => reject(err))
|
|
37
|
+
}, ms)
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
14
41
|
async function main(): Promise<void> {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
client_secret: '', // eslint-disable-line
|
|
18
|
-
grant_type: 'password', // eslint-disable-line
|
|
42
|
+
const atv = new ATV({}, 'stg')
|
|
43
|
+
const tokenData = await atv.getToken({
|
|
19
44
|
username: USERNAME_TEST,
|
|
20
45
|
password: PASSWORD_TEST
|
|
21
46
|
})
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
47
|
+
const { command, extraData } = await atv.createDocumentCommand({
|
|
48
|
+
document: {
|
|
49
|
+
...createDocumentInputExample,
|
|
50
|
+
documentName: 'NotaCreditoElectronica',
|
|
51
|
+
referenceInfo: creditNoteReferenceInfoExample
|
|
52
|
+
},
|
|
53
|
+
token: tokenData.accessToken,
|
|
54
|
+
signatureOptions: {
|
|
55
|
+
buffer: pem,
|
|
56
|
+
password: SOURCE_P12_PASSPORT
|
|
57
|
+
}
|
|
32
58
|
})
|
|
33
|
-
console.log(
|
|
34
|
-
|
|
35
|
-
|
|
59
|
+
console.log('extraData', extraData.xml)
|
|
60
|
+
const response = await atv.sendDocument(command)
|
|
61
|
+
if (response.errorCause) {
|
|
62
|
+
console.log('error response', response)
|
|
63
|
+
return
|
|
36
64
|
}
|
|
65
|
+
const confirmationResponse = await getConfimation(atv, tokenData.accessToken, response.location, 2000)
|
|
66
|
+
console.log({ MensajeHacienda: confirmationResponse.confirmation })
|
|
37
67
|
}
|
|
38
68
|
|
|
39
69
|
main()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@facturacr/atv-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Librería (SDK) de Javascript/NodeJS para acceder al API de Administración Tributaria Virtual (ATV) del Ministerio de Hacienda.",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { PersonProps } from '@src/ATV/core/Person'
|
|
2
|
+
import { DocumentNames } from '@src/ATV/core/documentNames.types'
|
|
3
|
+
import { Person } from '@src/ATV/core/Person'
|
|
4
|
+
import { OrderLine } from '@src/ATV/core/OrderLine'
|
|
5
|
+
import { FullConsecutive } from '@src/ATV/core/FullConsecutive'
|
|
6
|
+
import { Document } from '@src/ATV/core/Document'
|
|
7
|
+
import { Clave } from '@src/ATV/core/Clave'
|
|
8
|
+
import { DocumentType } from '@src/ATV/core/DocumentType'
|
|
9
|
+
import { ReferenceInformation, ReferenceInformationProps } from './ReferenceInformation'
|
|
10
|
+
|
|
11
|
+
type PersonInput = PersonProps;
|
|
12
|
+
|
|
13
|
+
type TaxInput = {
|
|
14
|
+
code: string;
|
|
15
|
+
rateCode: string;
|
|
16
|
+
rate: number;
|
|
17
|
+
amount?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type OrderInput = {
|
|
21
|
+
detail: string;
|
|
22
|
+
unitaryPrice: number;
|
|
23
|
+
lineNumber?: string;
|
|
24
|
+
code?: string;
|
|
25
|
+
quantity?: number;
|
|
26
|
+
measureUnit?: string;
|
|
27
|
+
totalAmount?: number;
|
|
28
|
+
subTotal?: number;
|
|
29
|
+
tax?: TaxInput;
|
|
30
|
+
totalOrderLineAmount?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type DocumentInput = {
|
|
34
|
+
emitter: PersonInput;
|
|
35
|
+
receiver: PersonInput;
|
|
36
|
+
branch: string; // sucursal
|
|
37
|
+
terminal: string; // terminal
|
|
38
|
+
// documentType: DocumentTypes; // @deprecated
|
|
39
|
+
documentName: DocumentNames;
|
|
40
|
+
countryCode: string; // codigoPais
|
|
41
|
+
securityCode: string; // codigoSeguridad
|
|
42
|
+
activityCode: string;
|
|
43
|
+
consecutiveIdentifier: string; // consecutivo
|
|
44
|
+
ceSituation: string; // situacionCE
|
|
45
|
+
orderLines: OrderInput[];
|
|
46
|
+
referenceInfo?: ReferenceInfoInput;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type ReferenceInfoInput = ReferenceInformationProps;
|
|
50
|
+
|
|
51
|
+
export type CreateDocumentInput = {
|
|
52
|
+
document: DocumentInput;
|
|
53
|
+
token: string;
|
|
54
|
+
signatureOptions: {
|
|
55
|
+
buffer: string;
|
|
56
|
+
password: string;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export class CreateDocFactory {
|
|
61
|
+
public createDocument(document: CreateDocumentInput['document']): Document {
|
|
62
|
+
const documentType = DocumentType.create(document.documentName)
|
|
63
|
+
const clave = this.createClave(document, documentType)
|
|
64
|
+
const fullConsective = this.createFullConsecutive(document, documentType)
|
|
65
|
+
const orderLines = this.createOrderLines(document)
|
|
66
|
+
return Document.create({
|
|
67
|
+
clave,
|
|
68
|
+
fullConsecutive: fullConsective,
|
|
69
|
+
orderLines,
|
|
70
|
+
activityCode: document.activityCode,
|
|
71
|
+
issueDate: new Date(),
|
|
72
|
+
emitter: Person.create(document.emitter),
|
|
73
|
+
receiver: Person.create(document.receiver),
|
|
74
|
+
conditionSale: '01',
|
|
75
|
+
paymentMethod: '01',
|
|
76
|
+
referenceInformation: document.referenceInfo ? ReferenceInformation.create(document.referenceInfo) : undefined,
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private createOrderLines(dto: CreateDocumentInput['document']): OrderLine[] {
|
|
81
|
+
return dto.orderLines.map((orderLine, index) => {
|
|
82
|
+
return OrderLine.create({
|
|
83
|
+
detail: orderLine.detail,
|
|
84
|
+
unitaryPrice: orderLine.unitaryPrice,
|
|
85
|
+
lineNumber: orderLine.lineNumber || (index + 1).toString(),
|
|
86
|
+
code: orderLine.code,
|
|
87
|
+
quantity: orderLine.quantity,
|
|
88
|
+
measureUnit: orderLine.measureUnit,
|
|
89
|
+
totalAmount: orderLine.totalAmount,
|
|
90
|
+
tax: orderLine.tax
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private createFullConsecutive(dto: CreateDocumentInput['document'], docType: DocumentType): FullConsecutive {
|
|
96
|
+
return FullConsecutive.create({
|
|
97
|
+
consecutiveIdentifier: dto.consecutiveIdentifier,
|
|
98
|
+
branch: dto.branch.padStart(3, '0'),
|
|
99
|
+
terminal: dto.terminal.padStart(5, '0'),
|
|
100
|
+
documentType: docType.value
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private createClave(dto: CreateDocumentInput['document'], docType: DocumentType): Clave {
|
|
105
|
+
return Clave.create({
|
|
106
|
+
branch: dto.branch,
|
|
107
|
+
ceSituation: dto.ceSituation,
|
|
108
|
+
consecutiveIdentifier: dto.consecutiveIdentifier,
|
|
109
|
+
countryCode: dto.countryCode,
|
|
110
|
+
docKeyType: docType.value,
|
|
111
|
+
emitterIdentifier: dto.emitter.identifier.id,
|
|
112
|
+
identifierType: dto.emitter.identifier.type, // TODO add default
|
|
113
|
+
securityCode: dto.securityCode,
|
|
114
|
+
terminal: dto.terminal
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
}
|
package/src/ATV/core/Document.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Clave } from './Clave'
|
|
|
2
2
|
import { FullConsecutive } from './FullConsecutive'
|
|
3
3
|
import { OrderLine } from './OrderLine'
|
|
4
4
|
import { Person } from './Person'
|
|
5
|
+
import { ReferenceInformation } from './ReferenceInformation'
|
|
5
6
|
import { SummaryProps } from './Summary.type'
|
|
6
7
|
|
|
7
8
|
export type InvoiceProps = {
|
|
@@ -16,6 +17,7 @@ export type InvoiceProps = {
|
|
|
16
17
|
deadlineCredit?: string; // PlazoCredito
|
|
17
18
|
paymentMethod?: string; // MedioPago
|
|
18
19
|
summaryInvoice?: SummaryProps; // ResumenFactura
|
|
20
|
+
referenceInformation?: ReferenceInformation; // InformaciónReferencia
|
|
19
21
|
others?: { // Otros
|
|
20
22
|
OtroTexto: string;
|
|
21
23
|
};
|
|
@@ -110,6 +112,10 @@ export class Document {
|
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
114
|
|
|
115
|
+
get referenceInformation(): ReferenceInformation | undefined {
|
|
116
|
+
return this.props.referenceInformation
|
|
117
|
+
}
|
|
118
|
+
|
|
113
119
|
private isAService(orderLine: OrderLine): boolean {
|
|
114
120
|
const servicesMeasurementUnits = ['Sp', 'St', 'Spe'];
|
|
115
121
|
return servicesMeasurementUnits.includes(orderLine.measureUnit)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type ReferenceInformationProps = {
|
|
2
|
+
docType: string;
|
|
3
|
+
refNumber: string;
|
|
4
|
+
issueDate: Date;
|
|
5
|
+
code: string;
|
|
6
|
+
reason: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class ReferenceInformation {
|
|
10
|
+
private props: ReferenceInformationProps
|
|
11
|
+
|
|
12
|
+
constructor(props: ReferenceInformationProps) {
|
|
13
|
+
this.props = props
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get docType(): string {
|
|
17
|
+
return this.props.docType;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get refNumber(): string {
|
|
21
|
+
return this.props.refNumber;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get issueDate(): Date {
|
|
25
|
+
return this.props.issueDate;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get code(): string {
|
|
29
|
+
return this.props.code;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get reason(): string {
|
|
33
|
+
return this.props.reason;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public static create(props: ReferenceInformationProps): ReferenceInformation {
|
|
37
|
+
return new ReferenceInformation({
|
|
38
|
+
...props,
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/ATV/index.ts
CHANGED
|
@@ -5,8 +5,9 @@ import * as parser from 'fast-xml-parser'
|
|
|
5
5
|
import qs from 'querystring'
|
|
6
6
|
import { ConfirmationMessageRaw } from '@src/types/facturaInterfaces'
|
|
7
7
|
import { ATVOptions, ConfirmationMessage, Mode, SendConfirmationInput, SendResponse } from './types'
|
|
8
|
-
import { Command, CreateAndSendDocumentResponse
|
|
8
|
+
import { Command, CreateAndSendDocumentResponse } from './useCases/createDocument/types'
|
|
9
9
|
import { CreateDocumentCommand } from './useCases/createDocument'
|
|
10
|
+
import { CreateDocumentInput } from './core/CreateDocFactory'
|
|
10
11
|
|
|
11
12
|
export class ATV {
|
|
12
13
|
public readonly options: ATVOptions
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Document, InvoiceDocumentContainer, DetalleServicio, Resumen, Persona } from '@src/types/facturaInterfaces'
|
|
1
|
+
import { Document, InvoiceDocumentContainer, DetalleServicio, Resumen, Persona, InformacionReferencia } from '@src/types/facturaInterfaces'
|
|
2
2
|
import { Document as DomainDocument } from '../core/Document'
|
|
3
3
|
import { OrderLine } from '../core/OrderLine'
|
|
4
4
|
import { Person } from '../core/Person'
|
|
5
|
+
import { ReferenceInformation } from '../core/ReferenceInformation'
|
|
5
6
|
|
|
6
7
|
type AtvFormat = InvoiceDocumentContainer
|
|
7
8
|
|
|
@@ -86,6 +87,16 @@ const mapPerson = (person: Person): Persona => {
|
|
|
86
87
|
return atvPerson;
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
const mapReferenceInformation = (referenceInfo: ReferenceInformation): InformacionReferencia => {
|
|
91
|
+
return {
|
|
92
|
+
TipoDoc: referenceInfo.docType,
|
|
93
|
+
Numero: referenceInfo.refNumber,
|
|
94
|
+
FechaEmision: referenceInfo.issueDate.toISOString(),
|
|
95
|
+
Codigo: referenceInfo.code,
|
|
96
|
+
Razon: referenceInfo.reason
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
89
100
|
export const mapDocumentToAtvFormat = (docName: string, document: DomainDocument): AtvFormat => {
|
|
90
101
|
const key = docName
|
|
91
102
|
const doc: Document = {
|
|
@@ -102,6 +113,9 @@ export const mapDocumentToAtvFormat = (docName: string, document: DomainDocument
|
|
|
102
113
|
ResumenFactura: mapSummaryInvoice(document.summaryInvoice),
|
|
103
114
|
Otros: document.others
|
|
104
115
|
}
|
|
116
|
+
if (document.referenceInformation) {
|
|
117
|
+
doc.InformacionReferencia = mapReferenceInformation(document.referenceInformation);
|
|
118
|
+
}
|
|
105
119
|
return {
|
|
106
120
|
[key]: doc
|
|
107
121
|
}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import { Person } from '@src/ATV/core/Person'
|
|
2
|
-
import { OrderLine } from '@src/ATV/core/OrderLine'
|
|
3
|
-
import { FullConsecutive } from '@src/ATV/core/FullConsecutive'
|
|
4
1
|
import { Document } from '@src/ATV/core/Document'
|
|
5
|
-
|
|
2
|
+
|
|
6
3
|
import { mapDocumentToAtvFormat as mapBillToAtvFormat } from '@src/ATV/mappers/billDocToAtv'
|
|
7
4
|
import { genXML } from '@src/lib/genXML'
|
|
8
|
-
import { CreateAndSendDocumentResponse,
|
|
5
|
+
import { CreateAndSendDocumentResponse, Command } from './types'
|
|
9
6
|
import { ATV } from '@src/ATV'
|
|
10
|
-
import {
|
|
11
|
-
export type { CreateDocumentInput as CreateBillInput } from './types'
|
|
7
|
+
import { CreateDocFactory, CreateDocumentInput } from '@src/ATV/core/CreateDocFactory'
|
|
12
8
|
|
|
13
9
|
const options: { [key: string]: { serviceUrl: string}} = {
|
|
14
10
|
prod: {
|
|
@@ -22,13 +18,16 @@ const options: { [key: string]: { serviceUrl: string}} = {
|
|
|
22
18
|
export class CreateDocumentCommand {
|
|
23
19
|
private readonly serviceUrl: string
|
|
24
20
|
|
|
21
|
+
private readonly createDoc: CreateDocFactory;
|
|
22
|
+
|
|
25
23
|
constructor(scope: ATV) {
|
|
26
24
|
this.serviceUrl = options[scope.mode].serviceUrl
|
|
25
|
+
this.createDoc = new CreateDocFactory()
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
public async execute(dto: CreateDocumentInput): Promise<CreateAndSendDocumentResponse> {
|
|
30
|
-
const documentName = dto.document.documentName || 'FacturaElectronica'
|
|
31
|
-
const document = this.createDocument(dto.document)
|
|
29
|
+
const documentName = dto.document.documentName || 'FacturaElectronica' //TODO NotaDebitoElectronica
|
|
30
|
+
const document = this.createDoc.createDocument(dto.document)
|
|
32
31
|
const atvDocument = mapBillToAtvFormat(documentName, document)
|
|
33
32
|
const xml = await genXML(documentName, atvDocument, dto.signatureOptions)
|
|
34
33
|
const command = await this.createDocumentCommand(document, xml, dto.token)
|
|
@@ -65,71 +64,7 @@ export class CreateDocumentCommand {
|
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
const documentType = DocumentType.create(document.documentName)
|
|
70
|
-
const emitter = this.createEmitter(document.emitter)
|
|
71
|
-
const receiver = this.createReceiver(document.receiver)
|
|
72
|
-
const clave = this.createClave(document, documentType)
|
|
73
|
-
const fullConsective = this.createFullConsecutive(document, documentType)
|
|
74
|
-
const orderLines = this.createOrderLines(document)
|
|
75
|
-
return Document.create({
|
|
76
|
-
clave,
|
|
77
|
-
fullConsecutive: fullConsective,
|
|
78
|
-
orderLines,
|
|
79
|
-
activityCode: document.activityCode,
|
|
80
|
-
issueDate: new Date(),
|
|
81
|
-
emitter,
|
|
82
|
-
receiver,
|
|
83
|
-
conditionSale: '01',
|
|
84
|
-
paymentMethod: '01'
|
|
85
|
-
})
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
private createEmitter(emitterInput: CreateDocumentInput['document']['emitter']): Person {
|
|
89
|
-
return Person.create(emitterInput)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
private createReceiver(receiverInput: CreateDocumentInput['document']['receiver']): Person {
|
|
93
|
-
return Person.create(receiverInput)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private createOrderLines(dto: CreateDocumentInput['document']): OrderLine[] {
|
|
97
|
-
return dto.orderLines.map((orderLine, index) => {
|
|
98
|
-
return OrderLine.create({
|
|
99
|
-
detail: orderLine.detail,
|
|
100
|
-
unitaryPrice: orderLine.unitaryPrice,
|
|
101
|
-
lineNumber: orderLine.lineNumber || (index + 1).toString(),
|
|
102
|
-
code: orderLine.code,
|
|
103
|
-
quantity: orderLine.quantity,
|
|
104
|
-
measureUnit: orderLine.measureUnit,
|
|
105
|
-
totalAmount: orderLine.totalAmount,
|
|
106
|
-
tax: orderLine.tax
|
|
107
|
-
})
|
|
108
|
-
})
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
private createFullConsecutive(dto: CreateDocumentInput['document'], docType: DocumentType): FullConsecutive {
|
|
112
|
-
return FullConsecutive.create({
|
|
113
|
-
consecutiveIdentifier: dto.consecutiveIdentifier,
|
|
114
|
-
branch: dto.branch.padStart(3, '0'),
|
|
115
|
-
terminal: dto.terminal.padStart(5, '0'),
|
|
116
|
-
documentType: docType.value
|
|
117
|
-
})
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
private createClave(dto: CreateDocumentInput['document'], docType: DocumentType): Clave {
|
|
121
|
-
return Clave.create({
|
|
122
|
-
branch: dto.branch,
|
|
123
|
-
ceSituation: dto.ceSituation,
|
|
124
|
-
consecutiveIdentifier: dto.consecutiveIdentifier,
|
|
125
|
-
countryCode: dto.countryCode,
|
|
126
|
-
docKeyType: docType.value,
|
|
127
|
-
emitterIdentifier: dto.emitter.identifier.id,
|
|
128
|
-
identifierType: dto.emitter.identifier.type, // TODO add default
|
|
129
|
-
securityCode: dto.securityCode,
|
|
130
|
-
terminal: dto.terminal
|
|
131
|
-
})
|
|
132
|
-
}
|
|
67
|
+
|
|
133
68
|
|
|
134
69
|
private encodeXML(xmlStr: string): string {
|
|
135
70
|
const buffer = Buffer.from(xmlStr)
|