@icure/be-fhc-api 0.4.4 → 0.4.7

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 (65) hide show
  1. package/api/fhcDataAttributeServiceApi.d.ts +37 -0
  2. package/api/fhcDataAttributeServiceApi.js +65 -0
  3. package/api/fhcEhboxV3Api.d.ts +10 -0
  4. package/api/fhcEhboxV3Api.js +23 -0
  5. package/api/fhcSchematronApi.d.ts +29 -0
  6. package/api/fhcSchematronApi.js +53 -0
  7. package/fhcApi.d.ts +2 -6
  8. package/fhcApi.js +2 -7
  9. package/model/Acknowledgement.d.ts +19 -0
  10. package/model/Acknowledgement.js +9 -0
  11. package/model/ActivePattern.d.ts +18 -0
  12. package/model/ActivePattern.js +20 -0
  13. package/model/DaasResponse.d.ts +20 -0
  14. package/model/DaasResponse.js +9 -0
  15. package/model/DiagnosticReference.d.ts +16 -0
  16. package/model/DiagnosticReference.js +20 -0
  17. package/model/EhboxIdentifierType.d.ts +20 -0
  18. package/model/EhboxIdentifierType.js +9 -0
  19. package/model/FailedAssert.d.ts +22 -0
  20. package/model/FailedAssert.js +9 -0
  21. package/model/FiredRule.d.ts +18 -0
  22. package/model/FiredRule.js +20 -0
  23. package/model/ItemType.d.ts +2 -2
  24. package/model/KmehrRegimen.d.ts +16 -0
  25. package/model/KmehrRegimen.js +9 -0
  26. package/model/Mapstringstring.d.ts +15 -0
  27. package/model/Mapstringstring.js +20 -0
  28. package/model/MessageOperationResponse.d.ts +1 -0
  29. package/model/MessageStatusOperationResponse.d.ts +19 -0
  30. package/model/MessageStatusOperationResponse.js +9 -0
  31. package/model/Ns.d.ts +16 -0
  32. package/model/Ns.js +20 -0
  33. package/model/NsPrefixInAttributeValues.d.ts +16 -0
  34. package/model/NsPrefixInAttributeValues.js +20 -0
  35. package/model/SchematronOutput.d.ts +30 -0
  36. package/model/SchematronOutput.js +9 -0
  37. package/model/SchematronValidationResult.d.ts +20 -0
  38. package/model/SchematronValidationResult.js +9 -0
  39. package/model/SuccessfulReport.d.ts +22 -0
  40. package/model/SuccessfulReport.js +9 -0
  41. package/model/User.d.ts +17 -0
  42. package/model/User.js +20 -0
  43. package/model/models.d.ts +19 -0
  44. package/model/models.js +19 -0
  45. package/package.json +1 -1
  46. package/x-api/message-x-api.d.ts +0 -35
  47. package/x-api/message-x-api.js +0 -790
  48. package/x-api/receipt-x-api.d.ts +0 -10
  49. package/x-api/receipt-x-api.js +0 -42
  50. package/x-api/utils/efact-parser.d.ts +0 -234
  51. package/x-api/utils/efact-parser.js +0 -1121
  52. package/x-api/utils/efact-util.d.ts +0 -28
  53. package/x-api/utils/efact-util.js +0 -316
  54. package/x-api/utils/fhc-invoice-sender-util.d.ts +0 -3
  55. package/x-api/utils/fhc-invoice-sender-util.js +0 -31
  56. package/x-api/utils/fhc-patient-util.d.ts +0 -3
  57. package/x-api/utils/fhc-patient-util.js +0 -20
  58. package/x-api/utils/formatting-util.d.ts +0 -76
  59. package/x-api/utils/formatting-util.js +0 -218
  60. package/x-api/utils/hcp-util.d.ts +0 -16
  61. package/x-api/utils/hcp-util.js +0 -131
  62. package/x-api/utils/insurability-util.d.ts +0 -22
  63. package/x-api/utils/insurability-util.js +0 -56
  64. package/x-api/utils/uuid-encoder.d.ts +0 -44
  65. package/x-api/utils/uuid-encoder.js +0 -110
@@ -1,790 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MessageXApi = void 0;
4
- const api_1 = require("@icure/api");
5
- const _ = require("lodash");
6
- const moment = require("moment");
7
- const efact_util_1 = require("./utils/efact-util");
8
- const formatting_util_1 = require("./utils/formatting-util");
9
- const models_1 = require("../model/models");
10
- const efact_parser_1 = require("./utils/efact-parser");
11
- class EfactSendResponseWithError extends models_1.EfactSendResponse {
12
- constructor(json) {
13
- super(json);
14
- }
15
- }
16
- class MessageXApi {
17
- constructor(api, crypto, documentXApi, insuranceApi, entityReferenceApi, fhcReceiptXApi, invoiceXApi, patientApi) {
18
- this.api = api;
19
- this.documentXApi = documentXApi;
20
- this.insuranceApi = insuranceApi;
21
- this.entityReferenceApi = entityReferenceApi;
22
- this.receiptXApi = fhcReceiptXApi;
23
- this.invoiceXApi = invoiceXApi;
24
- this.patientApi = patientApi;
25
- this.crypto = crypto;
26
- }
27
- saveDmgsListRequest(user, req, requestDate) {
28
- return this.api
29
- .newInstance(user, {
30
- // tslint:disable-next-line:no-bitwise
31
- transportGuid: "GMD:OUT:" +
32
- ((req.commonOutput && req.commonOutput.inputReference) ||
33
- req.tack.appliesTo ||
34
- "").replace("urn:nip:reference:input:", ""),
35
- fromHealthcarePartyId: user.healthcarePartyId,
36
- sent: +new Date(),
37
- metas: {
38
- type: "listrequest",
39
- date: moment().format("DD/MM/YYYY"),
40
- requestDate: requestDate ? moment(requestDate).format("DD/MM/YYYY") : ""
41
- },
42
- subject: "Lists request",
43
- senderReferences: req.commonOutput
44
- })
45
- .then(msg => this.api.createMessage(msg))
46
- .then(msg => {
47
- return this.documentXApi
48
- .newInstance(user, msg, {
49
- mainUti: "public.json",
50
- name: `${msg.subject}_content.json`
51
- })
52
- .then(doc => this.documentXApi.createDocument(doc))
53
- .then(doc => this.documentXApi.setDocumentAttachment(doc.id, undefined /*TODO provide keys for encryption*/, (0, api_1.ua2ab)((0, api_1.string2ua)(JSON.stringify(req)))))
54
- .then(() => msg);
55
- });
56
- }
57
- processDmgMessagesList(user, hcp, list, docXApi) {
58
- const ackHashes = [];
59
- let promAck = Promise.resolve(null);
60
- _.each(list.acks, ack => {
61
- const ref = (ack.appliesTo || "").replace("urn:nip:reference:input:", "");
62
- promAck = promAck
63
- .then(() => this.api.findMessagesByTransportGuid(`GMD:OUT:${ref}`, false, undefined, undefined, 100))
64
- .then(parents => {
65
- const msgsForHcp = ((parents && parents.rows) || []).filter((p) => p.responsible === hcp.id);
66
- if (!msgsForHcp.length) {
67
- throw new Error(`Cannot find parent with ref ${ref}`);
68
- }
69
- const parent = msgsForHcp[0];
70
- (parent.metas || (parent.metas = {}))[`tack.${ack.io}`] = ((ack.date && moment(ack.date)) ||
71
- moment()).format("YYYYMMDDHHmmss");
72
- return this.api.modifyMessage(parent);
73
- })
74
- .catch(e => {
75
- console.log(e.message);
76
- return null;
77
- })
78
- .then(() => this.receiptXApi.logSCReceipt(ack, user, hcp.id, "dmg", "listAck", [
79
- `nip:pin:valuehash:${ack.valueHash}`
80
- ]))
81
- .then(receipt => {
82
- ack.valueHash && ackHashes.push(ack.valueHash);
83
- return receipt;
84
- });
85
- });
86
- const patsDmgs = {};
87
- const msgHashes = [];
88
- let promMsg = promAck.then(() => []);
89
- _.each(list.lists, dmgsMsgList => {
90
- const metas = { type: "list" };
91
- _.each(dmgsMsgList.inscriptions, i => {
92
- i.inss &&
93
- (patsDmgs[i.inss] || (patsDmgs[i.inss] = [])).push({
94
- date: moment(i.from).format("DD/MM/YYYY"),
95
- from: moment(i.from).format("DD/MM/YYYY"),
96
- to: i.to,
97
- hcp: this.makeHcp(i.hcParty),
98
- payments: (i.payment1Amount
99
- ? [
100
- {
101
- amount: i.payment1Amount,
102
- currency: i.payment1Currency,
103
- date: i.payment1Date,
104
- ref: i.payment1Ref
105
- }
106
- ]
107
- : []).concat(i.payment2Amount
108
- ? [
109
- {
110
- amount: i.payment2Amount,
111
- currency: i.payment2Currency,
112
- date: i.payment2Date,
113
- ref: i.payment2Ref
114
- }
115
- ]
116
- : [])
117
- });
118
- });
119
- promMsg = promMsg.then(acc => {
120
- let ref = (dmgsMsgList.appliesTo || "").replace("urn:nip:reference:input:", "");
121
- return this.api
122
- .findMessagesByTransportGuid(`GMD:OUT:${ref}`, false, undefined, undefined, 100)
123
- .then(parents => {
124
- const msgsForHcp = ((parents && parents.rows) || []).filter((p) => p.responsible === hcp.id);
125
- if (!msgsForHcp.length) {
126
- throw new Error(`Cannot find parent with ref ${ref}`);
127
- }
128
- const parent = msgsForHcp[0];
129
- return this.saveMessageInDb(user, "List", dmgsMsgList, hcp, metas, docXApi, dmgsMsgList.date, undefined, parent && parent.id).then(msg => {
130
- dmgsMsgList.valueHash && msgHashes.push(dmgsMsgList.valueHash);
131
- acc.push(msg);
132
- return acc;
133
- });
134
- })
135
- .catch(e => {
136
- console.log(e.message);
137
- return acc;
138
- });
139
- });
140
- });
141
- _.each(list.closures, closure => {
142
- const metas = {
143
- type: "closure",
144
- date: (closure.endOfPreviousDmg && moment(closure.endOfPreviousDmg).format("DD/MM/YYYY")) ||
145
- null,
146
- closure: "true",
147
- endOfPreviousDmg: (closure.endOfPreviousDmg && moment(closure.endOfPreviousDmg).format("DD/MM/YYYY")) ||
148
- null,
149
- beginOfNewDmg: (closure.beginOfNewDmg && moment(closure.beginOfNewDmg).format("DD/MM/YYYY")) || null,
150
- previousHcp: this.makeHcp(closure.previousHcParty),
151
- newHcp: this.makeHcp(closure.newHcParty),
152
- ssin: closure.inss || null,
153
- firstName: closure.firstName || null,
154
- lastName: closure.lastName || null,
155
- io: closure.io || null
156
- };
157
- closure.inss && (patsDmgs[closure.inss] || (patsDmgs[closure.inss] = [])).push(metas);
158
- promMsg = promMsg.then(acc => {
159
- return this.saveMessageInDb(user, "Closure", closure, hcp, metas, docXApi, closure.endOfPreviousDmg, closure.inss).then(msg => {
160
- closure.valueHash && msgHashes.push(closure.valueHash);
161
- acc.push(msg);
162
- return acc;
163
- });
164
- });
165
- });
166
- _.each(list.extensions, ext => {
167
- const metas = {
168
- type: "extension",
169
- date: (ext.encounterDate && moment(ext.encounterDate).format("DD/MM/YYYY")) || null,
170
- from: (ext.encounterDate && moment(ext.encounterDate).format("DD/MM/YYYY")) || null,
171
- hcp: this.makeHcp(ext.hcParty),
172
- claim: ext.claim || null,
173
- ssin: ext.inss || null,
174
- firstName: ext.firstName || null,
175
- lastName: ext.lastName || null,
176
- io: ext.io || null
177
- };
178
- ext.inss && (patsDmgs[ext.inss] || (patsDmgs[ext.inss] = [])).push(metas);
179
- promMsg = promMsg.then(acc => {
180
- return this.saveMessageInDb(user, "Extension", ext, hcp, metas, docXApi, ext.encounterDate, ext.inss).then(msg => {
181
- ext.valueHash && msgHashes.push(ext.valueHash);
182
- acc.push(msg);
183
- return acc;
184
- });
185
- });
186
- });
187
- return promMsg.then(() => Promise.all(_.chunk(Object.keys(patsDmgs), 100).map(ssins => this.patientApi
188
- .filterByWithUser(user, new api_1.FilterChainPatient({
189
- filter: new api_1.AbstractFilterPatient({
190
- $type: "PatientByHcPartyAndSsinsFilter",
191
- healthcarePartyId: user.healthcarePartyId,
192
- ssins: ssins
193
- })
194
- }), undefined, undefined, 1000, 0, undefined, false)
195
- .then((pats) => this.patientApi.bulkUpdatePatients((pats.rows || []).map(p => {
196
- const actions = _.sortBy(patsDmgs[p.ssin], a => moment(a.date, "DD/MM/YYYY").format("YYYYMMDD"));
197
- const latestAction = actions.length && actions[actions.length - 1];
198
- let phcp = (p.patientHealthCareParties || (p.patientHealthCareParties = [])) &&
199
- p.patientHealthCareParties.find(phcp => phcp.healthcarePartyId === user.healthcarePartyId);
200
- if (!phcp) {
201
- p.patientHealthCareParties.push((phcp = new api_1.PatientHealthCareParty({
202
- healthcarePartyId: user.healthcarePartyId,
203
- referralPeriods: []
204
- })));
205
- }
206
- if (!phcp.referralPeriods) {
207
- phcp.referralPeriods = [];
208
- }
209
- const rp = (phcp.referralPeriods && phcp.referralPeriods.find(per => !per.endDate)) ||
210
- (phcp.referralPeriods[phcp.referralPeriods.length] = new api_1.ReferralPeriod({}));
211
- const actionDate = Number(moment(latestAction.date, "DD/MM/YYYY").format("YYYYMMDD"));
212
- if (latestAction) {
213
- if (latestAction.closure) {
214
- rp.endDate = actionDate;
215
- rp.comment = `-> ${latestAction.newHcp}`;
216
- }
217
- else {
218
- if (actionDate > (rp.startDate || 0)) {
219
- rp.endDate = actionDate;
220
- phcp.referralPeriods.push(new api_1.ReferralPeriod({ startDate: actionDate }));
221
- }
222
- }
223
- }
224
- return p;
225
- }))))).then(() => [ackHashes, msgHashes]));
226
- }
227
- makeHcp(hcParty) {
228
- if (!hcParty) {
229
- return null;
230
- }
231
- return `${hcParty.firstname || ""} ${hcParty.familyname || ""} ${hcParty.name ||
232
- ""} [${(hcParty.ids &&
233
- (hcParty.ids.find(id => id.s === models_1.IDHCPARTY.SEnum.IDHCPARTY) || {}).value) ||
234
- "-"}]`;
235
- }
236
- saveMessageInDb(user, msgName, dmgMessage, hcp, metas, docXApi, date, inss, parentId) {
237
- return this.api
238
- .newInstance(user, {
239
- // tslint:disable-next-line:no-bitwise
240
- transportGuid: "GMD:IN:" + dmgMessage.reference,
241
- fromAddress: dmgMessage.io,
242
- sent: date && +date,
243
- toHealthcarePartyId: hcp.id,
244
- recipients: [hcp.id],
245
- recipientsType: "org.taktik.icure.entities.HealthcareParty",
246
- received: +new Date(),
247
- metas: metas,
248
- parentId: parentId,
249
- subject: inss
250
- ? `${msgName} from IO ${dmgMessage.io} for ${inss}`
251
- : `${msgName} from IO ${dmgMessage.io}`,
252
- senderReferences: {
253
- inputReference: dmgMessage.commonOutput && dmgMessage.commonOutput.inputReference,
254
- outputReference: dmgMessage.commonOutput && dmgMessage.commonOutput.outputReference,
255
- nipReference: dmgMessage.commonOutput && dmgMessage.commonOutput.nipReference
256
- }
257
- })
258
- .then(msg => this.api.createMessage(msg))
259
- .then(msg => {
260
- return docXApi
261
- .newInstance(user, msg, {
262
- mainUti: "public.json",
263
- name: `${msg.subject}_content.json`
264
- })
265
- .then(doc => docXApi.createDocument(doc))
266
- .then(doc => docXApi.setDocumentAttachment(doc.id, undefined /*TODO provide keys for encryption*/, (0, api_1.ua2ab)((0, api_1.string2ua)(JSON.stringify(dmgMessage)))))
267
- .then(() => msg);
268
- });
269
- }
270
- saveDmgListRequestInDb(user, tack, resultMajor, appliesTo, hcp, date, inss) {
271
- return this.api
272
- .newInstance(user, {
273
- // tslint:disable-next-line:no-bitwise
274
- transportGuid: "GMD:OUT:LIST" + appliesTo,
275
- sent: date && +date,
276
- toHealthcarePartyId: hcp.id,
277
- recipients: [hcp.id],
278
- recipientsType: "org.taktik.icure.entities.HealthcareParty",
279
- received: +new Date(),
280
- metas: { tack: tack, resultMajor: resultMajor },
281
- subject: inss ? `Dmg list request for ${inss}` : `Dmg list request`,
282
- senderReferences: {
283
- inputReference: appliesTo && _.last(appliesTo.split(":"))
284
- }
285
- })
286
- .then(msg => this.api.createMessage(msg));
287
- }
288
- extractErrorMessage(error) {
289
- if (!error)
290
- return;
291
- const code1 = Number(error.rejectionCode1);
292
- const code2 = Number(error.rejectionCode2);
293
- const code3 = Number(error.rejectionCode3);
294
- const desc1 = (error.rejectionDescr1 && error.rejectionDescr1.trim()) || "";
295
- const desc2 = (error.rejectionDescr2 && error.rejectionDescr2.trim()) || "";
296
- const desc3 = (error.rejectionDescr3 && error.rejectionDescr3.trim()) || "";
297
- return code1 || code2 || code3 || desc1 || desc2 || desc3
298
- ? _([
299
- code1 || desc1.length ? `${code1 || "XXXXXX"}: ${desc1 || " — "}` : null,
300
- code2 || desc2.length ? `${code2 || "XXXXXX"}: ${desc2 || " — "}` : null,
301
- code3 || desc3.length ? `${code3 || "XXXXXX"}: ${desc3 || " — "}` : null
302
- ])
303
- .compact()
304
- .uniq()
305
- .filter(err => err.indexOf("510119") < 0)
306
- .join("; ")
307
- : undefined;
308
- }
309
- extractErrors(parsedRecords) {
310
- const errors = (parsedRecords.et10 && parsedRecords.et10.errorDetail
311
- ? [parsedRecords.et10.errorDetail]
312
- : [])
313
- .concat(_.flatMap(parsedRecords.records, r => {
314
- const errors = [];
315
- if (r.et20 && r.et20.errorDetail) {
316
- errors.push(r.et20.errorDetail);
317
- }
318
- _.each(r.items, i => {
319
- if (i.et50 && i.et50.errorDetail)
320
- errors.push(i.et50.errorDetail);
321
- if (i.et51 && i.et51.errorDetail)
322
- errors.push(i.et51.errorDetail);
323
- if (i.et52 && i.et52.errorDetail)
324
- errors.push(i.et52.errorDetail);
325
- });
326
- if (r.et80 && r.et80.errorDetail) {
327
- errors.push(r.et80.errorDetail);
328
- }
329
- return errors;
330
- }))
331
- .concat(parsedRecords.et90 && parsedRecords.et90.errorDetail ? [parsedRecords.et90.errorDetail] : []);
332
- return _.compact(_.map(errors, error => this.extractErrorMessage(error)));
333
- }
334
- processTack(user, hcp, efactMessage) {
335
- if (!efactMessage.tack) {
336
- return Promise.reject(new Error("Invalid tack"));
337
- }
338
- const refStr = _.get(efactMessage, "tack.appliesTo", "")
339
- .split(":")
340
- .pop();
341
- if (!refStr) {
342
- return Promise.reject(new Error(`Cannot find input reference from tack: ${_.get(efactMessage, "tack.appliesTo")}`));
343
- }
344
- const ref = Number(refStr) % 10000000000;
345
- return this.api
346
- .findMessagesByTransportGuid("EFACT:BATCH:" + ref, false, undefined, undefined, 100)
347
- .then(parents => {
348
- const msgsForHcp = ((parents && parents.rows) || []).filter((p) => p.responsible === hcp.id);
349
- if (!msgsForHcp.length) {
350
- throw new Error(`Cannot find parent with ref ${ref}`);
351
- }
352
- const parentMessage = msgsForHcp[0];
353
- return this.receiptXApi.iccApi
354
- .createReceipt(new api_1.Receipt({
355
- documentId: parentMessage.id,
356
- references: [
357
- `mycarenet:efact:inputReference:${ref}`,
358
- efactMessage.tack.appliesTo,
359
- efactMessage.tack.reference
360
- ]
361
- }))
362
- .then((rcpt) => this.receiptXApi.iccApi.setReceiptAttachment(rcpt.id, "tack", "", (0, api_1.ua2ab)((0, api_1.string2ua)(JSON.stringify(efactMessage)))))
363
- .then(() => {
364
- parentMessage.status = parentMessage.status | (1 << 8); /*STATUS_SUBMITTED*/
365
- // Reset error
366
- if (parentMessage.metas && parentMessage.metas.errors) {
367
- parentMessage.metas.sendingError = parentMessage.metas.errors;
368
- delete parentMessage.metas.errors;
369
- }
370
- return this.api.modifyMessage(parentMessage);
371
- });
372
- });
373
- }
374
- // Pass invoicePrefix if you want to generate the invoice reference from entityRef
375
- processEfactMessage(user, hcp, efactMessage, invoicePrefix, invoicePrefixer) {
376
- const ref = efactMessage.commonOutput.inputReference
377
- ? Number(efactMessage.commonOutput.inputReference) % 10000000000
378
- : Number(efactMessage.commonOutput.outputReference.replace(/\D+/g, "")) % 10000000000;
379
- return this.api
380
- .findMessagesByTransportGuid("EFACT:BATCH:" + ref, false, undefined, undefined, 100)
381
- .then(parents => {
382
- const msgsForHcp = _.filter(parents && parents.rows, (p) => p.responsible === hcp.id);
383
- if (!msgsForHcp.length) {
384
- throw new Error(`Cannot find parent with ref ${ref}`);
385
- }
386
- const messageType = efactMessage.detail.substr(0, 6);
387
- const parser = messageType === "920098"
388
- ? new efact_parser_1.EfactMessage920098Reader(efactMessage)
389
- : messageType === "920099"
390
- ? new efact_parser_1.EfactMessage920099Reader(efactMessage)
391
- : messageType === "920900"
392
- ? new efact_parser_1.EfactMessage920900Reader(efactMessage)
393
- : messageType === "920999"
394
- ? new efact_parser_1.EfactMessage920999Reader(efactMessage)
395
- : messageType === "931000"
396
- ? new efact_parser_1.EfactMessage931000Reader(efactMessage)
397
- : null;
398
- if (!parser) {
399
- throw Error(`Unsupported message type ${messageType}`);
400
- }
401
- const parsedRecords = parser.read();
402
- if (!parsedRecords) {
403
- throw new Error("Cannot parse...");
404
- }
405
- // Find message for Hcp based on the invoiceReference if present (!931000)
406
- const fileReference = _.get(parsedRecords, "et10.invoiceReference");
407
- const parentMessage = fileReference
408
- ? _.find(msgsForHcp, m => (0, efact_util_1.uuidBase36)(m.id) === fileReference.trim())
409
- : msgsForHcp[0];
410
- if (!parentMessage) {
411
- throw new Error(`Cannot match parent with fileReference for file with ref ${ref}`);
412
- }
413
- const errors = this.extractErrors(parsedRecords);
414
- const statuses = (["920999", "920099"].includes(messageType) ? 1 << 17 /*STATUS_FULL_ERROR*/ : 0) |
415
- (["920900"].includes(messageType) && errors.length
416
- ? 1 << 16 /*STATUS_PARTIAL_SUCCESS*/
417
- : 0) |
418
- (["920900"].includes(messageType) && !errors.length
419
- ? 1 << 15 /*STATUS_FULL_SUCCESS*/
420
- : 0) |
421
- (["920999"].includes(messageType) ? 1 << 12 /*STATUS_REJECTED*/ : 0) |
422
- (["920900", "920098", "920099"].includes(messageType) ? 1 << 11 /*STATUS_ACCEPTED*/ : 0) |
423
- (["920098"].includes(messageType) && errors.length
424
- ? 1 << 22 /*STATUS_ERRORS_IN_PRELIMINARY_CONTROL*/
425
- : 0) |
426
- (["931000"].includes(messageType) ? 1 << 10 /*STATUS_ACCEPTED_FOR_TREATMENT*/ : 0) |
427
- (["931000", "920999"].includes(messageType) ? 1 << 9 /*STATUS_RECEIVED*/ : 0);
428
- const batchErrors = _.compact([
429
- _.get(parsedRecords, "zone200.errorDetail"),
430
- _.get(parsedRecords, "zone300.errorDetail"),
431
- _.get(parsedRecords, "et10.errorDetail"),
432
- _.get(parsedRecords, "et90.errorDetail")
433
- ]);
434
- const invoicingErrors = parsedRecords.records
435
- ? _.compact(_.flatMap(parsedRecords.records, r => {
436
- const errors = [];
437
- let refEt20 = r.et20 && r.et20.reference.trim();
438
- if (r.et20 && r.et20.errorDetail) {
439
- errors.push({
440
- itemId: (0, efact_util_1.decodeBase36Uuid)(refEt20),
441
- error: r.et20.errorDetail,
442
- record: "ET20"
443
- });
444
- if (r.et80 && r.et80.errorDetail) {
445
- errors.push({
446
- itemId: (0, efact_util_1.decodeBase36Uuid)(refEt20),
447
- error: r.et80.errorDetail,
448
- record: "ET80"
449
- });
450
- }
451
- }
452
- _.each(r.items, i => {
453
- let ref = (i.et50 && i.et50.itemReference.trim()) || refEt20; //fallback
454
- if (i.et50 && i.et50.errorDetail) {
455
- errors.push({
456
- itemId: ref && (0, efact_util_1.decodeBase36Uuid)(ref),
457
- error: i.et50.errorDetail,
458
- record: "ET50"
459
- });
460
- }
461
- if (i.et51 && i.et51.errorDetail) {
462
- errors.push({
463
- itemId: ref && (0, efact_util_1.decodeBase36Uuid)(ref),
464
- error: i.et51.errorDetail,
465
- record: "ET51"
466
- });
467
- }
468
- if (i.et52 && i.et52.errorDetail) {
469
- errors.push({
470
- itemId: ref && (0, efact_util_1.decodeBase36Uuid)(ref),
471
- error: i.et52.errorDetail,
472
- record: "ET52"
473
- });
474
- }
475
- });
476
- return errors;
477
- }))
478
- : [];
479
- return this.api
480
- .newInstance(user, {
481
- // tslint:disable-next-line:no-bitwise
482
- status: (1 << 1) /*STATUS_UNREAD*/ | statuses,
483
- transportGuid: "EFACT:IN:" + ref,
484
- fromAddress: "EFACT",
485
- sent: (0, formatting_util_1.timeEncode)(new Date()),
486
- fromHealthcarePartyId: hcp.id,
487
- recipients: [hcp.id],
488
- recipientsType: "org.taktik.icure.entities.HealthcareParty",
489
- received: +new Date(),
490
- subject: messageType,
491
- parentId: parentMessage.id,
492
- senderReferences: {
493
- inputReference: efactMessage.commonOutput.inputReference,
494
- outputReference: efactMessage.commonOutput.outputReference,
495
- nipReference: efactMessage.commonOutput.nipReference
496
- }
497
- })
498
- .then(msg => this.api.createMessage(msg))
499
- .then(msg => Promise.all([
500
- this.documentXApi.newInstance(user, msg, {
501
- mainUti: "public.plain-text",
502
- name: msg.subject
503
- }),
504
- this.documentXApi.newInstance(user, msg, {
505
- mainUti: "public.json",
506
- name: `${msg.subject}_records`
507
- }),
508
- this.documentXApi.newInstance(user, msg, {
509
- mainUti: "public.json",
510
- name: `${msg.subject}_parsed_records`
511
- })
512
- ])
513
- .then(([doc, jsonDoc, jsonParsedDoc]) => Promise.all([
514
- this.documentXApi.createDocument(doc),
515
- this.documentXApi.createDocument(jsonDoc),
516
- this.documentXApi.createDocument(jsonParsedDoc)
517
- ]))
518
- .then(([doc, jsonDoc, jsonParsedDoc]) => Promise.all([
519
- this.documentXApi.setDocumentAttachment(doc.id, undefined /*TODO provide keys for encryption*/, (0, api_1.ua2ab)((0, api_1.string2ua)(efactMessage.detail))),
520
- this.documentXApi.setDocumentAttachment(jsonDoc.id, undefined /*TODO provide keys for encryption*/, (0, api_1.ua2ab)((0, api_1.string2ua)(JSON.stringify(efactMessage)))),
521
- this.documentXApi.setDocumentAttachment(jsonParsedDoc.id, undefined /*TODO provide keys for encryption*/, (0, api_1.ua2ab)((0, api_1.string2ua)(JSON.stringify(parsedRecords))))
522
- ]))
523
- .then(() => ["920999", "920099", "920900"].includes(messageType)
524
- ? this.invoiceXApi.getInvoices(new api_1.ListOfIds({ ids: parentMessage.invoiceIds }))
525
- : Promise.resolve([]))
526
- .then((invoices) => {
527
- // RejectAll if "920999", "920099"
528
- const rejectAll = (statuses & (1 << 17)) /*STATUS_ERROR*/ > 0;
529
- let promise = Promise.resolve([]);
530
- _.forEach(invoices, iv => {
531
- iv.error =
532
- _(invoicingErrors)
533
- .filter(it => it.itemId === iv.id)
534
- .map(e => this.extractErrorMessage(e.error))
535
- .compact()
536
- .join("; ") || undefined;
537
- let newInvoicePromise = null;
538
- _.each(iv.invoicingCodes, ic => {
539
- // If the invoicing code is already treated, do not treat it
540
- if (ic.canceled || ic.accepted) {
541
- return;
542
- }
543
- // Error from the ET50/51/52 linked to the invoicingCode
544
- const codeError = _(invoicingErrors)
545
- .filter(it => it.itemId === ic.id)
546
- .map(e => this.extractErrorMessage(e.error))
547
- .compact()
548
- .join("; ") || undefined;
549
- const record50 = messageType === "920900" &&
550
- _.compact(_.flatMap(parsedRecords.records, r => r.items.map(i => _.get(i, "et50.itemReference") &&
551
- (0, efact_util_1.decodeBase36Uuid)(i.et50.itemReference.trim()) === ic.id &&
552
- i.et50)))[0];
553
- const zone114amount = record50 &&
554
- _.get(record50, "errorDetail.zone114") &&
555
- Number(record50.errorDetail.zone114);
556
- if (rejectAll || codeError) {
557
- ic.accepted = false;
558
- ic.canceled = true;
559
- ic.pending = false;
560
- ic.resent = false;
561
- ic.error = codeError;
562
- ic.paid = zone114amount ? Number((zone114amount / 100).toFixed(2)) : 0;
563
- newInvoicePromise = (newInvoicePromise ||
564
- this.patientApi
565
- .getPatientIdOfChildDocumentForHcpAndHcpParents(iv, user.healthcarePartyId)
566
- .then(patientId => this.patientApi.getPatientWithUser(user, patientId))
567
- .then(pat => this.invoiceXApi.newInstance(user, pat, _.omit(iv, [
568
- "id",
569
- "rev",
570
- "deletionDate",
571
- "created",
572
- "modified",
573
- "sentDate",
574
- "printedDate",
575
- "secretForeignKeys",
576
- "cryptedForeignKeys",
577
- "delegations",
578
- "encryptionKeys",
579
- "invoicingCodes",
580
- "error",
581
- "receipts",
582
- "encryptedSelf"
583
- ])))
584
- .then(niv => {
585
- iv.correctiveInvoiceId = niv.id;
586
- niv.correctedInvoiceId = iv.id;
587
- return niv;
588
- })).then(niv => {
589
- niv.invoicingCodes = (niv.invoicingCodes || []).concat(_.assign({}, ic, {
590
- id: this.crypto.randomUuid(),
591
- accepted: false,
592
- canceled: false,
593
- pending: true,
594
- resent: true,
595
- archived: false
596
- }));
597
- return niv;
598
- });
599
- }
600
- else {
601
- ic.accepted = true;
602
- ic.canceled = false;
603
- ic.pending = false;
604
- ic.resent = false;
605
- ic.error = undefined;
606
- ic.paid = zone114amount
607
- ? Number((zone114amount / 100).toFixed(2))
608
- : ic.reimbursement;
609
- }
610
- });
611
- promise = promise.then(invoices => {
612
- return (newInvoicePromise
613
- ? newInvoicePromise
614
- .then(niv => (invoicePrefixer
615
- ? invoicePrefixer(niv, user.healthcarePartyId)
616
- : Promise.resolve(invoicePrefix)).then(pfx => this.invoiceXApi.createInvoice(niv, pfx)))
617
- .then(niv => invoices.push(niv))
618
- : Promise.resolve(0))
619
- .then(() => this.invoiceXApi.modifyInvoice(iv))
620
- .then(iv => invoices.push(iv))
621
- .then(() => invoices);
622
- });
623
- });
624
- return promise;
625
- })
626
- .then(invoices => {
627
- parentMessage.status = (parentMessage.status || 0) | statuses;
628
- if (batchErrors.length) {
629
- parentMessage.metas = _.assign(parentMessage.metas || {}, {
630
- errors: _(batchErrors)
631
- .map(this.extractErrorMessage)
632
- .uniq()
633
- .compact()
634
- .value()
635
- .join("; ")
636
- });
637
- }
638
- if (parsedRecords.et91) {
639
- let et91s = parsedRecords.et91;
640
- parentMessage.metas = _.assign(parentMessage.metas || {}, {
641
- paymentReferenceAccount1: _(et91s)
642
- .map(et91 => et91.paymentReferenceAccount1)
643
- .uniq()
644
- .value()
645
- .join(", ")
646
- });
647
- }
648
- if (parsedRecords.et92) {
649
- let et92 = parsedRecords.et92;
650
- parentMessage.metas = _.assign(parentMessage.metas || {}, {
651
- totalAskedAmount: Number(et92.totalAskedAmount) / 100,
652
- totalAcceptedAmount: Number(et92.totalAcceptedAmount) / 100,
653
- totalRejectedAmount: Number(et92.totalRejectedAmount) / 100
654
- });
655
- }
656
- return this.api
657
- .modifyMessage(parentMessage)
658
- .then(message => ({ message, invoices }));
659
- }));
660
- });
661
- }
662
- sendBatch(user, hcp, invoices, xFHCKeystoreId, xFHCTokenId, xFHCPassPhrase, efactApi, fhcServer = undefined, prefixer, isConnectedAsPmg = false, medicalLocationId = null) {
663
- const uuid = this.crypto.randomUuid();
664
- const smallBase36 = (0, efact_util_1.uuidBase36Half)(uuid);
665
- const fullBase36 = (0, efact_util_1.uuidBase36)(uuid);
666
- const sentDate = +new Date();
667
- const errors = [];
668
- const year = moment().year();
669
- return (0, efact_util_1.getFederaton)(invoices, this.insuranceApi).then(fed => {
670
- return (prefixer
671
- ? prefixer(fed, hcp.id)
672
- : Promise.resolve(`efact:${hcp.id}:${year}:${fed.code === "306" ? "300" : fed.code === "675" ? "600" : fed.code}:`)).then(prefix => {
673
- return this.entityReferenceApi
674
- .getLatest(prefix)
675
- .then((er) => {
676
- let nextSeqNumber = er && er.id && er.id.startsWith(prefix)
677
- ? (Number(er.id.split(":").pop()) || 0) + 1
678
- : 1;
679
- return this.entityReferenceApi.createEntityReference(new api_1.EntityReference({
680
- id: prefix + _.padStart("" + (nextSeqNumber % 1000000000), 9, "0"),
681
- docId: uuid
682
- }));
683
- })
684
- .then(er => (0, efact_util_1.toInvoiceBatch)(invoices, hcp, fullBase36, er && er.id ? Number(er.id.substr(prefix.length)) % 1000 : 0, smallBase36, this.insuranceApi, this.invoiceXApi, this.api, medicalLocationId === "medicalhouse"))
685
- .then(batch => efactApi
686
- .sendBatchUsingPOST(xFHCKeystoreId, xFHCTokenId, xFHCPassPhrase, batch)
687
- //.then(() => { throw "ERREUR FORCEE" })
688
- .catch(err => {
689
- // The FHC has crashed but the batch could be sent, so be careful !
690
- const errorMessage = _.get(err, "message", err.toString ? err.toString() : "Server error");
691
- const blockingErrors = [
692
- "Gateway Timeout",
693
- "Failed to fetch" // is due to internet connection lost (shutdown wifi just before sending batch)
694
- ];
695
- if (_.includes(blockingErrors, errorMessage.trim())) {
696
- throw errorMessage;
697
- }
698
- return { error: errorMessage };
699
- })
700
- .then((r) => {
701
- const res = r;
702
- if (res.success || res.error) {
703
- let promise = Promise.resolve(true);
704
- let totalAmount = 0;
705
- _.forEach(invoices, iv => {
706
- promise = promise.then(() => {
707
- _.forEach(iv.invoice.invoicingCodes, code => {
708
- code.pending = true; // STATUS_PENDING
709
- totalAmount += code.reimbursement || 0;
710
- });
711
- iv.invoice.sentDate = sentDate;
712
- return !!this.invoiceXApi.modifyInvoice(iv.invoice).catch(() => {
713
- errors.push(`efac-management.CANNOT_UPDATE_INVOICE.${iv.invoice.id}`);
714
- });
715
- });
716
- });
717
- return promise
718
- .then(() => this.api.newInstance(user, {
719
- id: uuid,
720
- medicalLocationId,
721
- invoiceIds: invoices.map(i => i.invoice.id),
722
- // tslint:disable-next-line:no-bitwise
723
- status: 1 << 6,
724
- externalRef: _.padStart("" + batch.uniqueSendNumber, 3, "0"),
725
- transportGuid: "EFACT:BATCH:" + batch.numericalRef,
726
- sent: (0, formatting_util_1.timeEncode)(new Date()),
727
- fromHealthcarePartyId: hcp.id,
728
- recipients: [fed.id],
729
- recipientsType: "org.taktik.icure.entities.Insurance"
730
- }))
731
- .then(message => this.api.createMessage(Object.assign(message, {
732
- sent: sentDate,
733
- status: (message.status || 0) | (res.success ? 1 << 7 : 0) /*STATUS_SENT*/,
734
- metas: {
735
- ioFederationCode: batch.ioFederationCode,
736
- numericalRef: batch.numericalRef,
737
- invoiceMonth: _.padStart("" + batch.invoicingMonth, 2, "0"),
738
- invoiceYear: _.padStart("" + batch.invoicingYear, 4, "0"),
739
- totalAmount: totalAmount,
740
- fhc_server: fhcServer,
741
- errors: res.error
742
- }
743
- })))
744
- .then((msg) => {
745
- if (res.success) {
746
- // Continue even if error ...
747
- this.saveMessageAttachment(user, msg, res);
748
- }
749
- return msg;
750
- });
751
- }
752
- else {
753
- throw "Cannot send batch";
754
- }
755
- }))
756
- .catch(err => {
757
- console.log(err);
758
- errors.push(err);
759
- throw new Error(errors.join(","));
760
- });
761
- });
762
- });
763
- }
764
- saveMessageAttachment(user, msg, res) {
765
- return Promise.all([
766
- this.documentXApi.newInstance(user, msg, {
767
- mainUti: "public.json",
768
- name: "920000_records"
769
- }),
770
- this.documentXApi.newInstance(user, msg, {
771
- mainUti: "public.plain-text",
772
- name: "920000"
773
- })
774
- ])
775
- .then(([jsonDoc, doc]) => Promise.all([
776
- this.documentXApi.createDocument(jsonDoc),
777
- this.documentXApi.createDocument(doc)
778
- ]))
779
- .then(([jsonDoc, doc]) => Promise.all([
780
- this.documentXApi.setDocumentAttachment(jsonDoc.id, undefined /*TODO provide keys for encryption*/, (0, api_1.ua2ab)((0, api_1.string2ua)(JSON.stringify(res.records)))),
781
- this.documentXApi.setDocumentAttachment(doc.id, undefined /*TODO provide keys for encryption*/, (0, api_1.ua2ab)((0, api_1.string2ua)(res.detail)))
782
- ]))
783
- .then(() => this.receiptXApi.iccApi.logReceipt(user, msg.id, [
784
- `mycarenet:efact:inputReference:${res.inputReference}`,
785
- res.tack.appliesTo,
786
- res.tack.reference
787
- ], "tack", (0, api_1.ua2ab)((0, api_1.string2ua)(JSON.stringify(res.tack)))));
788
- }
789
- }
790
- exports.MessageXApi = MessageXApi;