openchs-models 1.33.65 → 1.33.67
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/dist/AbstractEncounter.js +4 -5
- package/dist/Individual.js +1 -4
- package/dist/ObservationsHolder.js +37 -166
- package/dist/ProgramEnrolment.js +4 -5
- package/package.json +1 -1
|
@@ -265,11 +265,10 @@ class AbstractEncounter extends _BaseEntity.default {
|
|
|
265
265
|
return (0, _Media.findMediaObservations)(_ObservationsHolder.default.clone(this.observations), _ObservationsHolder.default.clone(this.cancelObservations));
|
|
266
266
|
}
|
|
267
267
|
replaceMediaObservation(originalValue, newValue, conceptUUID) {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
new _ObservationsHolder.default(this.cancelObservations).updateObservationBasedOnValue(originalValue, newValue);
|
|
268
|
+
// Both collections, no short-circuit — findMediaObservations enqueues from both.
|
|
269
|
+
const inObservations = new _ObservationsHolder.default(this.observations).replaceMediaObservation(originalValue, newValue, conceptUUID);
|
|
270
|
+
const inCancelObservations = new _ObservationsHolder.default(this.cancelObservations).replaceMediaObservation(originalValue, newValue, conceptUUID);
|
|
271
|
+
return inObservations || inCancelObservations;
|
|
273
272
|
}
|
|
274
273
|
getEntityTypeName() {
|
|
275
274
|
return this.encounterType.name;
|
package/dist/Individual.js
CHANGED
|
@@ -640,10 +640,7 @@ class Individual extends _BaseEntity.default {
|
|
|
640
640
|
return (0, _Media.findMediaObservations)(this.observations);
|
|
641
641
|
}
|
|
642
642
|
replaceMediaObservation(originalValue, newValue, conceptUUID) {
|
|
643
|
-
new _ObservationsHolder.default(this.observations).replaceMediaObservation(originalValue, newValue, conceptUUID);
|
|
644
|
-
}
|
|
645
|
-
replaceObservation(originalValue, newValue) {
|
|
646
|
-
new _ObservationsHolder.default(this.observations).updateObservationBasedOnValue(originalValue, newValue);
|
|
643
|
+
return new _ObservationsHolder.default(this.observations).replaceMediaObservation(originalValue, newValue, conceptUUID);
|
|
647
644
|
}
|
|
648
645
|
|
|
649
646
|
//TODO use polymorphism to avoid if checks based on this
|
|
@@ -24,46 +24,6 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
24
24
|
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
25
25
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
26
26
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
27
|
-
// Helper function to find media observation by value
|
|
28
|
-
const findMediaObservationByValue = (observations, targetValue) => {
|
|
29
|
-
if (!observations || !Array.isArray(observations)) return null;
|
|
30
|
-
return _lodash.default.find(observations, obs => {
|
|
31
|
-
// Check direct value
|
|
32
|
-
if (obs.getValue && obs.getValue() === targetValue) return true;
|
|
33
|
-
|
|
34
|
-
// Check coded values (for MultipleCodedValues)
|
|
35
|
-
const valueJSON = obs.valueJSON;
|
|
36
|
-
if (valueJSON && valueJSON.answer && Array.isArray(valueJSON.answer)) {
|
|
37
|
-
return valueJSON.answer.includes(targetValue);
|
|
38
|
-
}
|
|
39
|
-
return false;
|
|
40
|
-
});
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// Helper function to update media value
|
|
44
|
-
const updateMediaValue = (mediaObs, oldVal, newVal) => {
|
|
45
|
-
if (!mediaObs) return false;
|
|
46
|
-
|
|
47
|
-
// For coded values, we need to update the array content
|
|
48
|
-
if (mediaObs.valueJSON && mediaObs.valueJSON.answer && Array.isArray(mediaObs.valueJSON.answer)) {
|
|
49
|
-
const answerIndex = mediaObs.valueJSON.answer.indexOf(oldVal);
|
|
50
|
-
if (answerIndex >= 0) {
|
|
51
|
-
mediaObs.valueJSON.answer[answerIndex] = newVal;
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
} else {
|
|
55
|
-
// Regular value update
|
|
56
|
-
mediaObs.setValue(mediaObs.concept.getValueWrapperFor(newVal));
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
return false;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
// Process each question group observation
|
|
63
|
-
const processQuestionGroupObservations = (observations, oldVal, newVal) => {
|
|
64
|
-
const mediaObs = findMediaObservationByValue(observations, oldVal);
|
|
65
|
-
return mediaObs ? updateMediaValue(mediaObs, oldVal, newVal) : false;
|
|
66
|
-
};
|
|
67
27
|
class ObservationsHolder {
|
|
68
28
|
constructor(observations) {
|
|
69
29
|
this.observations = observations;
|
|
@@ -84,9 +44,6 @@ class ObservationsHolder {
|
|
|
84
44
|
getObservation(concept) {
|
|
85
45
|
return this.findObservation(concept);
|
|
86
46
|
}
|
|
87
|
-
findObservationByValue(value) {
|
|
88
|
-
return _lodash.default.find(this.observations, observation => observation.getValue() === value);
|
|
89
|
-
}
|
|
90
47
|
|
|
91
48
|
/*
|
|
92
49
|
Called from the wizard on changes done by the user for primitive fields (including Date)
|
|
@@ -431,49 +388,6 @@ class ObservationsHolder {
|
|
|
431
388
|
}
|
|
432
389
|
}
|
|
433
390
|
|
|
434
|
-
//private
|
|
435
|
-
updateObservationBasedOnValue(oldValue, newValue) {
|
|
436
|
-
// Try to find at top level first
|
|
437
|
-
const observation = this.findObservationByValue(oldValue);
|
|
438
|
-
if (observation) {
|
|
439
|
-
observation.setValue(observation.concept.getValueWrapperFor(newValue));
|
|
440
|
-
return true;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// Search in nested structures if not found at top level
|
|
444
|
-
let updated = false;
|
|
445
|
-
|
|
446
|
-
// Iterate through all observations
|
|
447
|
-
_lodash.default.forEach(this.observations, obs => {
|
|
448
|
-
// Skip non-question group observations
|
|
449
|
-
if (obs.concept.datatype !== _Concept.default.dataType.QuestionGroup) return;
|
|
450
|
-
const valueWrapper = obs.getValueWrapper && obs.getValueWrapper();
|
|
451
|
-
if (!valueWrapper) return;
|
|
452
|
-
|
|
453
|
-
// Handle RepeatableQuestionGroup
|
|
454
|
-
if (valueWrapper.isRepeatable && valueWrapper.isRepeatable()) {
|
|
455
|
-
const allGroups = valueWrapper.getAllQuestionGroupObservations && valueWrapper.getAllQuestionGroupObservations();
|
|
456
|
-
if (allGroups && allGroups.length) {
|
|
457
|
-
// Check each group in the repeatable question group
|
|
458
|
-
allGroups.forEach(group => {
|
|
459
|
-
const groupObservations = group.getValue && group.getValue();
|
|
460
|
-
if (processQuestionGroupObservations(groupObservations, oldValue, newValue)) {
|
|
461
|
-
updated = true;
|
|
462
|
-
}
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
// Handle regular QuestionGroup
|
|
467
|
-
else {
|
|
468
|
-
const groupObservations = valueWrapper.getValue && valueWrapper.getValue();
|
|
469
|
-
if (processQuestionGroupObservations(groupObservations, oldValue, newValue)) {
|
|
470
|
-
updated = true;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
});
|
|
474
|
-
return updated;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
391
|
// Helper method to update media value in an observation
|
|
478
392
|
_updateMediaValueInObservation(observation, oldValue, newValue) {
|
|
479
393
|
if (!observation) return false;
|
|
@@ -482,7 +396,13 @@ class ObservationsHolder {
|
|
|
482
396
|
|
|
483
397
|
// Handle ImageV2 type
|
|
484
398
|
if (observation.concept.datatype === _Concept.default.dataType.ImageV2) {
|
|
485
|
-
|
|
399
|
+
let mediaObjects;
|
|
400
|
+
try {
|
|
401
|
+
mediaObjects = JSON.parse(valueWrapper.getValue());
|
|
402
|
+
} catch (e) {
|
|
403
|
+
// A malformed value can't reference the file; one bad obs must not crash the whole scan.
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
486
406
|
let updated = false;
|
|
487
407
|
const newAnswers = _lodash.default.map(mediaObjects, mediaObject => {
|
|
488
408
|
if (mediaObject.uri === oldValue) {
|
|
@@ -492,111 +412,62 @@ class ObservationsHolder {
|
|
|
492
412
|
return mediaObject;
|
|
493
413
|
});
|
|
494
414
|
if (updated) {
|
|
495
|
-
observation.valueJSON = new _PrimitiveValue.default(JSON.stringify(newAnswers), _Concept.default.dataType.ImageV2);
|
|
415
|
+
observation.valueJSON = new _PrimitiveValue.default(JSON.stringify(newAnswers), _Concept.default.dataType.ImageV2, valueWrapper.answerSource);
|
|
496
416
|
return true;
|
|
497
417
|
}
|
|
498
418
|
}
|
|
499
419
|
// Handle multiple coded values
|
|
500
420
|
else if (valueWrapper.isMultipleCoded) {
|
|
501
421
|
const answers = valueWrapper.getValue();
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
newAnswers.splice(oldValueIndex, 0, newValue);
|
|
506
|
-
observation.valueJSON = new _MultipleCodedValues.default(newAnswers);
|
|
422
|
+
if (_lodash.default.includes(answers, oldValue)) {
|
|
423
|
+
const newAnswers = _lodash.default.map(answers, answer => answer === oldValue ? newValue : answer);
|
|
424
|
+
observation.valueJSON = new _MultipleCodedValues.default(newAnswers, valueWrapper.answerSource);
|
|
507
425
|
return true;
|
|
508
426
|
}
|
|
509
427
|
}
|
|
510
428
|
// Handle single coded value
|
|
511
429
|
else if (valueWrapper.getValue() === oldValue) {
|
|
512
|
-
|
|
430
|
+
const newWrapper = observation.concept.getValueWrapperFor(newValue);
|
|
431
|
+
newWrapper.answerSource = valueWrapper.answerSource;
|
|
432
|
+
observation.valueJSON = newWrapper;
|
|
513
433
|
return true;
|
|
514
434
|
}
|
|
515
435
|
return false;
|
|
516
436
|
}
|
|
517
437
|
|
|
518
|
-
//
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
const
|
|
522
|
-
if (!groupObservations || !Array.isArray(groupObservations)) return false;
|
|
523
|
-
|
|
524
|
-
// Find media observation either by concept UUID or by value
|
|
525
|
-
const mediaObs = _lodash.default.find(groupObservations, obs => obs.concept.uuid === conceptUUID || _Concept.default.dataType.Media.includes(obs.concept.datatype) && obs.getValue && obs.getValue() === oldValue);
|
|
526
|
-
|
|
527
|
-
// Update if found
|
|
528
|
-
return this._updateMediaValueInObservation(mediaObs, oldValue, newValue);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
// Helper to find and update media in repeatable question group
|
|
532
|
-
_updateMediaInRepeatableQuestionGroup(repeatableGroup, conceptUUID, oldValue, newValue) {
|
|
533
|
-
if (!repeatableGroup || !repeatableGroup.getAllQuestionGroupObservations) return false;
|
|
534
|
-
const allGroups = repeatableGroup.getAllQuestionGroupObservations();
|
|
535
|
-
if (!allGroups || !allGroups.length) return false;
|
|
536
|
-
|
|
537
|
-
// Check each group in the repeatable question group
|
|
438
|
+
// Replaces oldValue in every matching media child of a question-group wrapper (regular or
|
|
439
|
+
// repeatable) — every group/row, every child; does not stop at the first match.
|
|
440
|
+
_replaceMediaInGroupWrapper(wrapper, oldValue, newValue) {
|
|
441
|
+
const groups = wrapper.isRepeatable && wrapper.isRepeatable() ? wrapper.getAllQuestionGroupObservations ? wrapper.getAllQuestionGroupObservations() : [] : [wrapper];
|
|
538
442
|
let updated = false;
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
443
|
+
_lodash.default.forEach(groups, group => {
|
|
444
|
+
const groupObservations = group && group.getValue && group.getValue();
|
|
445
|
+
if (!Array.isArray(groupObservations)) return;
|
|
446
|
+
_lodash.default.forEach(groupObservations, childObs => {
|
|
447
|
+
if (childObs.concept.isMediaConcept() && this._updateMediaValueInObservation(childObs, oldValue, newValue)) {
|
|
448
|
+
updated = true;
|
|
449
|
+
}
|
|
450
|
+
});
|
|
543
451
|
});
|
|
544
452
|
return updated;
|
|
545
453
|
}
|
|
546
454
|
|
|
547
|
-
//
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
const isRepeatable = wrapper.isRepeatable && wrapper.isRepeatable();
|
|
553
|
-
|
|
554
|
-
// Process the appropriate group type
|
|
555
|
-
return isRepeatable ? this._updateMediaInRepeatableQuestionGroup(wrapper, conceptUUID, oldValue, newValue) : this._updateMediaInQuestionGroup(wrapper, conceptUUID, oldValue, newValue);
|
|
556
|
-
}
|
|
455
|
+
// Replaces oldValue with newValue in EVERY observation referencing it — top-level media
|
|
456
|
+
// observations and those inside (repeatable) question groups. The same media value can be
|
|
457
|
+
// referenced by multiple concepts with different select types (e.g. a rule-copied read-only
|
|
458
|
+
// display element), so the scan is value-driven; conceptUUID is retained only for caller
|
|
459
|
+
// compatibility. Returns true if at least one observation was updated.
|
|
557
460
|
replaceMediaObservation(oldValue, newValue, conceptUUID) {
|
|
558
|
-
console.log(`[INFO] Replacing media: ${oldValue} → ${newValue}`);
|
|
559
|
-
|
|
560
|
-
// Since conceptUUID is always provided in practice, optimize for that case first
|
|
561
|
-
// Try to find direct top-level observation with matching concept UUID
|
|
562
|
-
const directObservation = _lodash.default.find(this.observations, obs => obs.concept.uuid === conceptUUID);
|
|
563
|
-
if (directObservation) {
|
|
564
|
-
// Direct media observation
|
|
565
|
-
if (_Concept.default.dataType.Media.includes(directObservation.concept.datatype)) {
|
|
566
|
-
if (this._updateMediaValueInObservation(directObservation, oldValue, newValue)) {
|
|
567
|
-
console.log(`[INFO] Updated media in direct observation`);
|
|
568
|
-
return true;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
// Question Group containing the media
|
|
572
|
-
else if (directObservation.concept.datatype === _Concept.default.dataType.QuestionGroup) {
|
|
573
|
-
const valueWrapper = directObservation.getValueWrapper();
|
|
574
|
-
if (this._processQuestionGroupWrapper(valueWrapper, conceptUUID, oldValue, newValue)) {
|
|
575
|
-
console.log(`[INFO] Updated media in question group`);
|
|
576
|
-
return true;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// Check nested structures (this works both with and without conceptUUID)
|
|
582
461
|
let updated = false;
|
|
583
462
|
_lodash.default.forEach(this.observations, obs => {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
updated = true;
|
|
463
|
+
if (obs.concept.isMediaConcept()) {
|
|
464
|
+
if (this._updateMediaValueInObservation(obs, oldValue, newValue)) updated = true;
|
|
465
|
+
} else if (obs.concept.datatype === _Concept.default.dataType.QuestionGroup) {
|
|
466
|
+
const wrapper = obs.getValueWrapper && obs.getValueWrapper();
|
|
467
|
+
if (wrapper && this._replaceMediaInGroupWrapper(wrapper, oldValue, newValue)) updated = true;
|
|
590
468
|
}
|
|
591
469
|
});
|
|
592
|
-
|
|
593
|
-
console.log(`[INFO] Updated media in nested structure`);
|
|
594
|
-
return true;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// As a fallback, use value-based replacement if we couldn't find it by concept
|
|
598
|
-
// This ensures backward compatibility and handles edge cases
|
|
599
|
-
return this.updateObservationBasedOnValue(oldValue, newValue);
|
|
470
|
+
return updated;
|
|
600
471
|
}
|
|
601
472
|
toString(I18n) {
|
|
602
473
|
let display = "";
|
package/dist/ProgramEnrolment.js
CHANGED
|
@@ -455,11 +455,10 @@ class ProgramEnrolment extends _BaseEntity.default {
|
|
|
455
455
|
return (0, _Media.findMediaObservations)(_ObservationsHolder.default.clone(this.observations), _ObservationsHolder.default.clone(this.programExitObservations));
|
|
456
456
|
}
|
|
457
457
|
replaceMediaObservation(originalValue, newValue, conceptUUID) {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
new _ObservationsHolder.default(this.programExitObservations).updateObservationBasedOnValue(originalValue, newValue);
|
|
458
|
+
// Both collections, no short-circuit — findMediaObservations enqueues from both.
|
|
459
|
+
const inObservations = new _ObservationsHolder.default(this.observations).replaceMediaObservation(originalValue, newValue, conceptUUID);
|
|
460
|
+
const inExitObservations = new _ObservationsHolder.default(this.programExitObservations).replaceMediaObservation(originalValue, newValue, conceptUUID);
|
|
461
|
+
return inObservations || inExitObservations;
|
|
463
462
|
}
|
|
464
463
|
getName() {
|
|
465
464
|
return "ProgramEnrolment";
|