Skip to content

Commit 3508f68

Browse files
authored
Merge pull request #2 from aphp/ngr/relec
relecture
2 parents 80cc3a4 + 915f275 commit 3508f68

File tree

13 files changed

+2526
-515
lines changed

13 files changed

+2526
-515
lines changed

input/fml/usages/core/StructureMap-CorePhysical2Business.fml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/*
12
map "https://aphp.fr/ig/fhir/dm/StructureMap/CorePhysical2Business" = "CorePhysical2Business"
23

34
/// name = 'CorePhysical2Business'

input/fml/usages/core/StructureMap-CorePhysical2FHIR.fml

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@ uses "http://hl7.org/fhir/StructureDefinition/Meta" alias FHIRMeta as target
2121

2222
group dataSet(source srcDataSet : DataSet, target tgtBundle : FHIRBundle) <<types>> {
2323
srcDataSet -> tgtBundle.id = uuid() "setId";
24-
srcDataSet.patient as srcPatient -> tgtBundle.entry as tgtEntry, tgtEntry.resource = create("Patient") as newPatient then {
24+
srcDataSet -> tgtBundle.type = 'transaction' "setType";
25+
srcDataSet.patient as srcPatient -> tgtBundle.entry as tgtPatientEntry, tgtPatientEntry.resource = create("Patient") as newPatient then {
2526
srcPatient then patient(srcPatient, newPatient) "setPatient";
26-
srcDataSet.sejour as srcSejour -> tgtBundle.entry as tgtEntry, tgtEntry.resource = create("Encounter") as newEncounter then {
27+
srcPatient then setEntryRequestAndFullUrl(newPatient,tgtPatientEntry) "setRequestAndFullUrl";
28+
srcDataSet.sejour as srcSejour where patientNi.reference = ('PatientCore/' + %srcPatient.patientNi.toString()) -> tgtBundle.entry as tgtEncounterEntry, tgtEncounterEntry.resource = create("Encounter") as newEncounter then {
2729
srcSejour then encounter(srcSejour, newPatient, newEncounter) "setEncounter";
28-
srcDataSet.biology as srcBiology where sejourNi.reference = ('SejourCore/' + %srcSejour.sejourNi.toString()) -> tgtBundle.entry as tgtEntry, tgtEntry.resource = create("Observation") as newObservation then {
29-
srcBiology then observation(srcBiology, newPatient, newEncounter, newObservation) "setBiology";
30+
srcSejour then setEntryRequestAndFullUrl(newEncounter,tgtEncounterEntry) "setRequestAndFullUrl";
31+
srcDataSet.biology as srcBiology where sejourNi.reference = ('SejourCore/' + %srcSejour.sejourNi.toString()) -> tgtBundle.entry as tgtBiologyEntry, tgtBiologyEntry.resource = create("Observation") as newObservation then {
32+
srcBiology then observationBiol(srcBiology, newPatient, newEncounter, newObservation) "setBiology";
33+
srcBiology then setEntryRequestAndFullUrl(newObservation,tgtBiologyEntry) "setRequestAndFullUrl";
3034
} "createObservation";
3135
} "createEncounter";
3236
} "createPatient";
@@ -41,43 +45,47 @@ group patient(source srcPatient : PatientTable, target tgtPatient : FHIRPatient)
4145
}
4246

4347
group setPatientMeta(source srcNi, target tgtMeta : FHIRMeta) {
44-
srcNi -> tgtMeta.source = ('https://aphp.fr/fhir/Endpoint/dpi/PatientTable' + '/' + srcNi.toString()) "setSource";
48+
srcNi -> tgtMeta.source = ('https://aphp.fr/fhir/Endpoint/dpi/PatientTable' + '/' + %srcNi.toString()) "setSource";
4549
}
4650

4751
group setHumainName(source srcPatient : PatientTable, target tgtPatientName) {
4852
srcPatient -> tgtPatientName.use = c('http://hl7.org/fhir/name-use', 'usual') "setUse";
49-
srcPatient -> tgtPatientName.text = (%srcPatient.firstName + ' ' + %srcPatient.name) "setText";
50-
srcPatient.name as srcPatientName -> tgtPatientName.family = srcPatientName "setName";
51-
srcPatient.firstName as srcPatientFirstName -> tgtPatientName.given = srcPatientFirstName "setFirstName";
52-
}
53+
// srcPatient -> tgtPatientName.text = (%srcPatient.firstName + ' ' + %srcPatient.name) "setText";
54+
// srcPatient.name as srcPatientName -> tgtPatientName.family = srcPatientName "setName";
55+
// srcPatient.firstName as srcPatientFirstName -> tgtPatientName.given = srcPatientFirstName "setFirstName";
56+
// les trois lignes précédentes marchent dans matchbox mais génèrent une erreur au QA. La solution ci dessous marche dans matchbox et ne génère pas d'erreur au QA.
57+
srcPatient.name as srcPatientName -> tgtPatientName.family = srcPatientName then {
58+
srcPatient.firstName as srcPatientFirstName -> tgtPatientName.given = srcPatientFirstName,
59+
tgtPatientName.text = (%srcPatientFirstName + ' ' + %srcPatientName) "setFirstNameAndText";
60+
} "setName";}
5361

5462
group encounter(source srcSejour : SejourTable, source srcPatient : FHIRPatient, target tgtEncounter : FHIREncounter) {
5563
srcSejour -> tgtEncounter.id = uuid() "setId";
5664
srcSejour.sejourNi as srcNi -> tgtEncounter.meta as tgtMeta then setEncounterMeta(srcNi, tgtMeta) "setMeta"; // copie la valeur du champ patientNi de la table Patient dans l'élément id de la ressource FHIR Patient
5765
srcSejour -> tgtEncounter.status = c('http://hl7.org/fhir/encounter-status', 'completed') "setStatus";
5866
srcSejour.sejourType as srcSejourType -> tgtEncounter.type = translate(srcSejourType, 'https://aphp.fr/ig/fhir/dm/ConceptMap/DpiEncounterType2SemanticLayerEncounterType', 'CodeableConcept') "setEncounterType";
5967
srcPatient.id as patientId -> tgtEncounter.subject = create("Reference") as newSubject then setSubjectReference(patientId, newSubject) "setSubjectReference";
60-
srcSejour.patientNi "patientNi";// fk vers le patient
68+
srcSejour.patientNi "patientNi";// fk vers le patient à conserver pour la construction auto du périmètre final
6169
srcSejour -> tgtEncounter.period = create("Period") as newActualPeriod then {
6270
srcSejour.sejourStart as srcPeriodStart -> newActualPeriod.start = srcPeriodStart "setStart";
6371
srcSejour.sejourEnd as srcPeriodEnd -> newActualPeriod.end = srcPeriodEnd "setEnd";
6472
} "setPeriod";
6573
}
6674

6775
group setEncounterMeta(source srcNi, target tgtMeta : FHIRMeta) {
68-
srcNi -> tgtMeta.source = ('https://aphp.fr/fhir/Endpoint/dpi/SejourTable' + '/' + srcNi.toString()) "setSource";
76+
srcNi -> tgtMeta.source = ('https://aphp.fr/fhir/Endpoint/dpi/SejourTable' + '/' + %srcNi.toString()) "setSource";
6977
}
7078

7179
group setSubjectReference(source srcPatientId , target newSubject) {
7280
srcPatientId -> newSubject.reference = ('Patient/' + %srcPatientId.toString()) "setReference";
7381
}
7482

75-
group observation(source srcBiology : BiologyTable, source srcPatient : FHIRPatient, source srcEncounter : FHIREncounter, target tgtObservation : FHIRObservation) {
83+
group observationBiol(source srcBiology : BiologyTable, source srcPatient : FHIRPatient, source srcEncounter : FHIREncounter, target tgtObservation : FHIRObservation) {
7684
srcBiology -> tgtObservation.id = uuid() "setId";
7785
srcBiology.biologyNi as srcNi -> tgtObservation.meta as tgtMeta then setBiologyMeta(srcNi, tgtMeta) "setMeta";
7886
srcPatient.id as patientId -> tgtObservation.subject = create("Reference") as newSubject then setSubjectReference(patientId, newSubject) "setSubjectReference";
7987
srcEncounter.id as encounterId -> tgtObservation.encounter = create("Reference") as newEncounter then setEncounterReference(encounterId, newEncounter) "setEncounterReference";
80-
srcBiology.biologyDate as biologyDate -> tgtObservation.effective = biologyDate "setDate";
88+
srcBiology.biologyDatePrel as biologyDatePrel -> tgtObservation.effective = biologyDatePrel "setDate";
8189
srcBiology.biologyCode as biologyCode -> tgtObservation.code = cc('http://loinc.org', biologyCode) "setCode";
8290
srcBiology.biologyValue -> tgtObservation.value = create('Quantity') as tgtObsQuantity then {
8391
srcBiology.biologyValue as biologyValue -> tgtObsQuantity.value = biologyValue "setValue";
@@ -86,9 +94,18 @@ group observation(source srcBiology : BiologyTable, source srcPatient : FHIRPati
8694
}
8795

8896
group setBiologyMeta(source srcNi, target tgtMeta : FHIRMeta) {
89-
srcNi -> tgtMeta.source = ('https://aphp.fr/fhir/Endpoint/dpi/BiologyTable' + '/' + srcNi.toString()) "setSource";
97+
srcNi -> tgtMeta.source = ('https://aphp.fr/fhir/Endpoint/dpi/BiologyTable' + '/' + %srcNi.toString()) "setSource";
9098
}
9199

92100
group setEncounterReference(source srcEncounterId, target newEncounter) {
93101
srcEncounterId -> newEncounter.reference = ('Encounter/' + %srcEncounterId.toString()) "setReference";
94102
}
103+
104+
group setEntryRequestAndFullUrl(source newRes, target tgtEntry) {
105+
newRes.id as newResId then {
106+
newResId -> tgtEntry.fullUrl = (%newRes.type().name + '/' + %newResId) "setFullUrl";
107+
newResId -> tgtEntry.request as tgtEntryRequest,
108+
tgtEntryRequest.method = 'POST',
109+
tgtEntryRequest.url = (%newRes.type().name + '/' + %newResId) "setRequest" ;
110+
} "setResourceType" ;
111+
}

input/fsh/applications/dpi/logicals/StructureDefinition-CoreBiology.fsh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,8 @@ Table CORE.BIOLOGY (DDL)
1414
* biologyCode 0..1 string "null"
1515
* biologyValue 0..1 decimal "null"
1616
* biologyUnit 0..1 string "null"
17-
* biologyDate 0..1 date "null"
17+
* biologyDatePrel 0..1 date "null"
18+
* biologyDateEnr 0..1 date "null"
19+
* biologyDateValTech 0..1 date "null"
20+
* biologyDateValBiol 0..1 date "null"
1821
* sejourNi 1..1 Reference(CoreSejour) "null"

input/fsh/semantic-layer/codesystems/CodeSystem-FrClaimType.fsh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ Description: "Typage des claim en France, dans le cadre du PMSI"
99

1010
* #PMSIMCO "PMSI - MCO"
1111
* #PMSIHAD "PMSI - HAD"
12-
* #PMSISSR "PMSI - SSR"
12+
* #PMSISSR "PMSI - SMR" // anciennement PMSI SSR ?
1313
* #PMSIPSY "PMSI - PSY"

input/images-source/core-map.plantuml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ entity CORE.SEJOUR {
2626

2727
entity CORE.BIOLOGY {
2828
* {field} BIOLOGY_NI NUMBER (38, 0) NOT NULL
29-
* {field} BIOLOGY_DATE DATE NULL
29+
* {field} BIOLOGY_DATE_PREL DATE NULL
3030
* {field} BIOLOGY_CODE VARCHAR2 (50) NULL
3131
* {field} BIOLOGY_VALUE NUMBER (4, 2) NULL
3232
* {field} BIOLOGY_UNIT VARCHAR2 (10) NULL

input/images-source/core-mpd.plantuml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ entity CORE.BIOLOGY {
4848
* {field} DATE_CREAT DATE NOT NULL
4949
* {field} DATE_MODIF DATE NOT NULL
5050
* {field} DATE_REMOVE DATE NULL
51-
* {field} BIOLOGY_DATE DATE NULL
51+
* {field} BIOLOGY_DATE_PREL DATE NULL
52+
* {field} BIOLOGY_DATE_ENR DATE NULL
53+
* {field} BIOLOGY_DATE_VAL_TECH DATE NULL
54+
* {field} BIOLOGY_DATE_VAL_BIOL DATE NULL
5255
* {field} BIOLOGY_CODE VARCHAR2 (50) NULL
5356
* {field} BIOLOGY_VALUE NUMBER (4, 2) NULL
5457
* {field} BIOLOGY_UNIT VARCHAR2 (10) NULL
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
@startuml
2+
3+
start
4+
floating note
5+
Some user need some
6+
data in the CDW
7+
end note
8+
9+
group Qualification
10+
:Qualification;
11+
end group
12+
13+
group Instruction
14+
:Création du modèle métier;
15+
note right: en utilisant le FormBuilder
16+
group Data discovery
17+
:Identification et collecte des données;
18+
floating note
19+
Périmètre initial (Usage-Synchro
20+
utilise des ddl pour représenter
21+
la source)
22+
end note
23+
:Profilage et analyse des données;
24+
floating note
25+
- Data structure analysis;
26+
- Column analysis;
27+
- Relationship analysis;
28+
end note
29+
:Visualisation et exploration;
30+
:Sécurisation et conformité;
31+
group Gestion des données de référence
32+
:Spécification de la génération des ressources terminologiques depuis les sources;
33+
:Génération des ressources terminologiques;
34+
:Intégration dans le Guide d'Implémentation;
35+
:Enrichir le modèle métier avec les ressources terminologiques créées;
36+
end group
37+
:Alignement Source to Métier;
38+
floating note
39+
Périmètre final (Usage-Synchro
40+
utilise la map pour restreindre
41+
le périmètre initial)
42+
end note
43+
note right: en utilisant le MapBuilder
44+
end group
45+
:Validation;
46+
group Couche sémantique
47+
:Élaboration des patrons de conception;
48+
:Définition des bindings terminologiques;
49+
:Élaboration des alignements sémantiques;
50+
:Élaboration de l'alignement syntaxique;
51+
note right: en utilisant le MapBuilder
52+
end group
53+
end group
54+
55+
:Réalisation;
56+
:Recette;
57+
:Mise en production;
58+
:Amélioration continue;
59+
60+
stop
61+
floating note
62+
Requested data are
63+
integrated in CDW
64+
with documentation
65+
end note
66+
@enduml

input/pagecontent/dm-delivery-process.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
Cette page décrit le processus de livraison de données faisant suite aux traitement d'un cas d'usage (expression de besoins).
22

3+
<div style="text-align: center;">{%include delivery-process.svg%}</div>
4+
35
### Qualification
46

57
La description du processus de "Qualification" est hors sujet pour le moment. Néanmoins, nous pouvons préciser que

input/pagecontent/dm-instruction.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Le processus d'instruction se compose de 5 étapes :
22

33
#### Modèle métier
44

5-
À l'aide du [FormBuilder](), une ressource `Questionnaire` est produite en tenant compte des exigences.
5+
À l'aide du [FormBuilder](https://formbuilder-prod-ext-k8s.eds.aphp.fr/), une ressource `Questionnaire` est produite en tenant compte des exigences.
66

77
#### Data discovery
88

@@ -62,8 +62,8 @@ point que le résultat peut provoquer l'abandon du cas d'usage.
6262

6363
#### Conception de la couche sémantique
6464

65-
À l'issue de la "Data Discovery" et une fois avoir apporter la preuve que le cas d'usage peut se faire, l'identification
66-
des ressources FHIR est réalisé. En priorité, nous choisissons les ressources compatibles avec l'écosystème français
65+
À l'issue de la "Data Discovery" et une fois avoir apporté la preuve que le cas d'usage peut se faire, l'identification
66+
des ressources FHIR est réalisée. En priorité, nous choisissons les ressources compatibles avec l'écosystème français
6767
(guides d'implémentation de l'ANS et d'Interop'santé). Récemment, de nombreux efforts ont été réalisés au niveau européen
6868
et par conséquent et de plus en plus, nous devons également tenir compte des guides d'implémentation FHIR européen, nous
6969
préparant ainsi à l'European Health Data Space (EHDS).

input/pagecontent/glossary.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Par exemple, pour le questionnaire de représentation du modèle métier de l'us
2222

2323
##### Cas particulier des StructureDefinition
2424

25-
- id doit préciser à quel type il sapplique (cest-à-dire son Base)
25+
- id doit préciser à quel type il s'applique (c'est-à-dire son Base)
2626

2727
Par exemple pour le profil dédié au poids :
2828
- id = name = DMObservationBodyWeight
@@ -33,6 +33,28 @@ Par exemple pour le profil dédié au poids :
3333
Id est un UUID.
3434
On pourra colliger les ressources afférentes à un cas d'usage dans un fichier dont le nom explicitera le cas d'usage.
3535

36+
#### NammingSystem
37+
38+
La plupart des ressources FHIR propose un attribut `identifier` qui permet de renseigner 0 à n identifiants métiers a une ressource. Ces identifiants permettent notamment de créer des liens logiques entre les ressources (via les attributs de type `reference` et leur attribut `identifier`).
39+
40+
Cet attribut `identifier` est particulièrement intéressant pour le lineage des ressources, lorsqu'il s'agit de créer une ressource FHIR à partir d'un objet déjà existant, dans un autre format, au sein du système d'information.
41+
42+
Cela impose néanmoins une gestion rigoureuse des namespace. On part sur le principe que les namespaces seront défini comme suit :
43+
44+
[base APHP]/[type de ressource FHIR]/[identifiant unique d'un processus de génération d'identifiant unique]
45+
46+
avec :
47+
- [base APHP] = `https://aphp.fr/meta`
48+
- [type de ressource FHIR] appartient au ValueSet [ResourceType](http://hl7.org/fhir/ValueSet/resource-types)
49+
- [identifiant de processus] est à construire en interne, par exemple : `ipp` (il n'y a qu'un processus de création d'ipp à l'APHP : par le SIU Orbis), `ProduitChimioAVC` (il y a des médicament dans CHIMIO et dans d'autres outils, plusieurs CHIMIO et plusieurs 'type' de médicament dans chaque CHIMIO)
50+
51+
Plusieurs stratégies sont envisageable pour s'assurer de l'unicité des namespace _by design_ :
52+
- mettre en oeuvre un registre interne des namespace : un serveur FHIR dans lequel chaque responsable de namespace enregistrerait une ressource NamingSystem pour chacun des namespace qu'il gère, en s'assurant qu'il n'existe pas déjà.
53+
- fournir à chaque responsable de namespace un code unique qui serait inclus dans l'identifiant de processus du namespace
54+
- consolider un codesystem contenant tous les namespace utiles, charge à chaque responsable de namespace d'enrichir ce CS en tant que de besoin.
55+
56+
Une difficulté réside dans le souhait, exprimé par des responsable de namespace, de ne pas publicisé, auprès de partenaires extérieurs, certains namespace.
57+
3658
#### uri des sources
3759
On décide, pour chaque ressource FHIR intégrée dans le Hub de donnée, de préciser l'application source de cette ressource via l'attribut `meta.source`. Cet attribut attend une uri qui sera, autant que possible, créée selon la convention suivante :
3860
1. https://

0 commit comments

Comments
 (0)