oddb2xml 3.0.6 → 3.0.8
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.
- checksums.yaml +4 -4
- data/CLAUDE.md +1 -1
- data/Gemfile.lock +5 -5
- data/History.txt +6 -0
- data/README.md +62 -1
- data/lib/oddb2xml/builder.rb +8 -0
- data/lib/oddb2xml/fhir_support.rb +48 -6
- data/lib/oddb2xml/version.rb +1 -1
- data/spec/fhir_spec.rb +120 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a5391f07cc4388c80d6347856c433d40002143f8a368af6d45ceb3f0662861bf
|
|
4
|
+
data.tar.gz: c02c407165679d39512f8d23de883f870c0a9d89d723c85f1bd3172b73f3bbd4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 10f45b9f5aa5095073260bc034be15d643484fbb9e717b847e839ad04a508f121aa6c6ed6ab8efd0e64c7e3eebea7b839182dd5af70cbe9a30b38f7334f2ebd8
|
|
7
|
+
data.tar.gz: 69c6642e96ff6abb51ded2519f770e69e09d49a8b8b52c7121f287f47e34fccc4679f8643246d85ce74f32702cb0d26e53992140d19d6c0c4fcaab272bc459e1
|
data/CLAUDE.md
CHANGED
|
@@ -47,7 +47,7 @@ The system follows a **download → extract → build → compress** pipeline:
|
|
|
47
47
|
|
|
48
48
|
6. **Compressor** (`lib/oddb2xml/compressor.rb`) — Optional ZIP/TAR.GZ output compression.
|
|
49
49
|
|
|
50
|
-
7. **FHIR support** (`lib/oddb2xml/fhir_support.rb`) — Self-contained module providing `FhirDownloader` and FHIR NDJSON parsing. Activated via `--fhir` (or `--fhir-url=<URL>`). Downloads per-language NDJSON files (`foph-sl-export-latest-{de,fr,it}.ndjson`) from `epl.bag.admin.ch` to populate French and Italian product names/descriptions. Maps legal status codes `756005022007` and `756005022008` to Swissmedic category D.
|
|
50
|
+
7. **FHIR support** (`lib/oddb2xml/fhir_support.rb`) — Self-contained module providing `FhirDownloader` and FHIR NDJSON parsing. Activated via `--fhir` (or `--fhir-url=<URL>`). Downloads per-language NDJSON files (`foph-sl-export-latest-{de,fr,it}.ndjson`) from `epl.bag.admin.ch` to populate French and Italian product names/descriptions. Maps legal status codes `756005022007` and `756005022008` to Swissmedic category D. Parses `ClinicalUseDefinition` resources and combines each indication's `.NN` id-suffix with the reimbursement RA's `FOPHDossierNumber` to construct the BAG **Indikationscode** (`XXXXX.NN`); exposed as `item[:indication_codes]` and per-package `:indication_codes` (each entry a `{code:, cud_id:, text:}` hash). From 3.0.7 onwards, `Builder#build_product` emits one `<INDICATION_CODE code="XXXXX.NN" cud_id="DRUG.NN">limitation text</INDICATION_CODE>` child per indication on every `<PRD>` in `oddb_product.xml`; live feed numbers: 539 products / 1,293 codes / 100 % with non-empty indication text. Mandatory on prescriptions/invoices for SL price-model drugs from 2026-07-01 — see issue [#113](https://github.com/zdavatz/oddb2xml/issues/113). **Limitation texts** (3.0.8 onwards): the `regulatedAuthorization-limitation` extension has no inline `limitationText` in the live BAG feed — it carries a `limitationIndication` reference to a `ClinicalUseDefinition` whose `indication.diseaseSymptomProcedure.concept.text` is the actual text. The parser stores the ref as `cud_ref` on each Limitation, `Bundle#cud_text_by_id` resolves DE, and `merge_language` propagates FR/IT from the per-language NDJSON files via the same CUD id. Coverage on the live feed jumped from 0 / 9'108 to 9'108 / 9'108 (issue [#116](https://github.com/zdavatz/oddb2xml/issues/116)).
|
|
51
51
|
|
|
52
52
|
8. **Refdata cleanup** (`lib/oddb2xml/refdata_cleanup.rb`) — Compensates for known data-quality issues in upstream Refdata.Articles.xml before they reach the output. Each fix is guarded by a Swissmedic-side heuristic (e.g. comma in `substance_swissmedic` to distinguish mono products from real combinations). Currently fixes the doubled-dose template bug (`X mg / X mg / Stk`). Called from `Builder#apply_refdata_description_cleanups!` at the start of `prepare_articles`. See GitHub issue #112 for the catalogue.
|
|
53
53
|
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
oddb2xml (3.0.
|
|
4
|
+
oddb2xml (3.0.8)
|
|
5
5
|
csv
|
|
6
6
|
htmlentities
|
|
7
7
|
httpi
|
|
@@ -27,7 +27,7 @@ PATH
|
|
|
27
27
|
GEM
|
|
28
28
|
remote: https://rubygems.org/
|
|
29
29
|
specs:
|
|
30
|
-
addressable (2.
|
|
30
|
+
addressable (2.9.0)
|
|
31
31
|
public_suffix (>= 2.0.2, < 8.0)
|
|
32
32
|
akami (1.3.3)
|
|
33
33
|
base64
|
|
@@ -59,7 +59,7 @@ GEM
|
|
|
59
59
|
rack
|
|
60
60
|
socksify
|
|
61
61
|
io-console (0.8.2)
|
|
62
|
-
json (2.
|
|
62
|
+
json (2.19.5)
|
|
63
63
|
language_server-protocol (3.17.0.5)
|
|
64
64
|
lint_roller (1.1.0)
|
|
65
65
|
logger (1.7.0)
|
|
@@ -116,7 +116,7 @@ GEM
|
|
|
116
116
|
pry (~> 0.11)
|
|
117
117
|
yard (~> 0.9.21)
|
|
118
118
|
psych (3.3.4)
|
|
119
|
-
public_suffix (7.0.
|
|
119
|
+
public_suffix (7.0.5)
|
|
120
120
|
racc (1.8.1)
|
|
121
121
|
rack (3.2.6)
|
|
122
122
|
rainbow (3.1.1)
|
|
@@ -210,7 +210,7 @@ GEM
|
|
|
210
210
|
webrobots (0.1.2)
|
|
211
211
|
xml-simple (1.1.9)
|
|
212
212
|
rexml
|
|
213
|
-
yard (0.9.
|
|
213
|
+
yard (0.9.43)
|
|
214
214
|
|
|
215
215
|
PLATFORMS
|
|
216
216
|
arm64-darwin-25
|
data/History.txt
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
=== 3.0.8 / 28.05.2026
|
|
2
|
+
* FHIR: fix empty <DescriptionDe/Fr/It> on every <Limitation>. The live BAG FHIR feed does not carry limitation text inline; it stores a `limitationIndication` reference to a `ClinicalUseDefinition` whose `indication.diseaseSymptomProcedure.concept.text` holds the actual text (one per language). FR/IT come from the per-language NDJSON files and are merged via the CUD id. Result on the live feed: 9'108 / 9'108 limitations (100%) now carry text, up from 0% (issue #116).
|
|
3
|
+
|
|
4
|
+
=== 3.0.7 / 06.05.2026
|
|
5
|
+
* oddb_product.xml: emit one <INDICATION_CODE code="XXXXX.NN" cud_id="DRUG.NN">limitation text</INDICATION_CODE> child per indication on each <PRD>. Source: FHIR ClinicalUseDefinition resources joined with the reimbursement RegulatedAuthorization's FOPHDossierNumber. Counted on the live FOPH feed: 539 products carry a total of 1,293 codes; all have non-empty indication text. Resolves the missing wiring between FhirExtractor and Builder noted in 3.0.6 (issue #113).
|
|
6
|
+
|
|
1
7
|
=== 3.0.6 / 06.05.2026
|
|
2
8
|
* FHIR: extract Indikationscode (XXXXX.NN) from ClinicalUseDefinition resources by combining FOPHDossierNumber with each CUD's .NN id-suffix; expose as item[:indication_codes] (and per package) so downstream builders can include it on prescriptions and invoices as required by BAG from 2026-07-01 (issue #113)
|
|
3
9
|
* Declare csv as a runtime dependency in the gemspec (csv was removed from Ruby's default gems in 3.4)
|
data/README.md
CHANGED
|
@@ -51,7 +51,7 @@ HIN (http://hin.ch) creates daily the actual file. They can be downloaded from `
|
|
|
51
51
|
see `--help`.
|
|
52
52
|
|
|
53
53
|
```
|
|
54
|
-
/opt/src/oddb2xml/bin/oddb2xml version 3.0.
|
|
54
|
+
/opt/src/oddb2xml/bin/oddb2xml version 3.0.8
|
|
55
55
|
Usage:
|
|
56
56
|
oddb2xml [option]
|
|
57
57
|
produced files are found under data
|
|
@@ -292,6 +292,67 @@ We use the following files:
|
|
|
292
292
|
* https://epl.bag.admin.ch/static/fhir/foph-sl-export-latest-{de,fr,it}.ndjson (FHIR NDJSON, used with `--fhir`)
|
|
293
293
|
* https://id.gs1.ch/01/07612345000961 (GS1 Switzerland firstbase CSV — full barcode registry, used with `-b`/`--firstbase`)
|
|
294
294
|
|
|
295
|
+
## Indikationscode (BAG XXXXX.NN)
|
|
296
|
+
|
|
297
|
+
In `--fhir` mode, oddb2xml extracts the BAG **Indikationscode** for SL
|
|
298
|
+
price-model drugs and emits one repeated `<INDICATION_CODE>` child per
|
|
299
|
+
indication on each `<PRD>` in `oddb_product.xml`:
|
|
300
|
+
|
|
301
|
+
```xml
|
|
302
|
+
<PRD DT="...">
|
|
303
|
+
<GTIN>7680123456789</GTIN>
|
|
304
|
+
...
|
|
305
|
+
<INDICATION_CODE code="20403.01" cud_id="CYRAMZA.01">In Kombination mit Paclitaxel für die Behandlung ...</INDICATION_CODE>
|
|
306
|
+
<INDICATION_CODE code="20403.02" cud_id="CYRAMZA.02">In Kombination mit FOLFIRI ...</INDICATION_CODE>
|
|
307
|
+
<PackGrSwissmedic>...</PackGrSwissmedic>
|
|
308
|
+
</PRD>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
The code is built per FHIR bundle by combining the
|
|
312
|
+
`FOPHDossierNumber` from the reimbursement `RegulatedAuthorization`
|
|
313
|
+
(`XXXXX`) with the `.NN` suffix of each sibling
|
|
314
|
+
`ClinicalUseDefinition` whose `type == "indication"` (e.g.
|
|
315
|
+
`CYRAMZA.01` / `CYRAMZA.02` → `20403.01` / `20403.02`). The element
|
|
316
|
+
body carries the human-readable indication text from
|
|
317
|
+
`indication.diseaseSymptomProcedure.concept.text`.
|
|
318
|
+
|
|
319
|
+
The same data is also exposed in-memory on each item and package as
|
|
320
|
+
`item[:indication_codes]` (an array of `{code:, cud_id:, text:}`
|
|
321
|
+
hashes) for downstream consumers that build their own emitters.
|
|
322
|
+
|
|
323
|
+
Counted on the live FOPH feed (`foph-sl-export-latest-de.ndjson`,
|
|
324
|
+
6'775 bundles): **539** products carry a total of **1'293** codes.
|
|
325
|
+
|
|
326
|
+
Per BAG Rundschreiben vom 19. Februar 2026, the Indikationscode must
|
|
327
|
+
be transmitted with every prescription and invoice for SL price-model
|
|
328
|
+
drugs from **2026-07-01**; from **2027-01-01** insurers may reject
|
|
329
|
+
invoices without it. See issue
|
|
330
|
+
[#113](https://github.com/zdavatz/oddb2xml/issues/113).
|
|
331
|
+
|
|
332
|
+
## Limitation texts in `--fhir` mode
|
|
333
|
+
|
|
334
|
+
In 3.0.8 we fixed empty `<DescriptionDe/Fr/It>` on every `<Limitation>`
|
|
335
|
+
in the FHIR-built output. The live BAG FHIR feed does **not** carry
|
|
336
|
+
limitation text inline on the `regulatedAuthorization-limitation`
|
|
337
|
+
extension. Instead the extension holds a `limitationIndication`
|
|
338
|
+
reference to a `ClinicalUseDefinition` whose
|
|
339
|
+
`indication.diseaseSymptomProcedure.concept.text` is the actual text:
|
|
340
|
+
|
|
341
|
+
```
|
|
342
|
+
RegulatedAuthorization/65839
|
|
343
|
+
└─ indication.extension[limitation]
|
|
344
|
+
├─ status, statusDate, period, firstLimitationDate
|
|
345
|
+
└─ limitationIndication → ClinicalUseDefinition/NORDIMET
|
|
346
|
+
└─ concept.text = "Wird nicht ..."
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
The CUDs are identical in `id` across the three per-language NDJSON
|
|
350
|
+
files (`foph-sl-export-latest-{de,fr,it}.ndjson`); only the
|
|
351
|
+
`concept.text` differs. `FhirExtractor` resolves DE from the primary
|
|
352
|
+
file and merges FR/IT in via the same CUD id. Coverage on the live
|
|
353
|
+
feed went from 0 / 9'108 to 9'108 / 9'108 (100 %). See issue
|
|
354
|
+
[#116](https://github.com/zdavatz/oddb2xml/issues/116).
|
|
355
|
+
|
|
295
356
|
## Refdata data-quality compensation
|
|
296
357
|
|
|
297
358
|
Refdata.Articles.xml from `files.refdata.ch` ships with a number of recurring
|
data/lib/oddb2xml/builder.rb
CHANGED
|
@@ -780,6 +780,14 @@ module Oddb2xml
|
|
|
780
780
|
# xml.REMD
|
|
781
781
|
# xml.REMF
|
|
782
782
|
# }
|
|
783
|
+
# BAG Indikationscode (XXXXX.NN) for SL price-model drugs.
|
|
784
|
+
# Mandatory on prescriptions/invoices from 2026-07-01 — see
|
|
785
|
+
# GitHub issue #113.
|
|
786
|
+
if seq && seq[:indication_codes].is_a?(Array)
|
|
787
|
+
seq[:indication_codes].each do |ic|
|
|
788
|
+
xml.INDICATION_CODE ic[:text].to_s, code: ic[:code], cud_id: ic[:cud_id]
|
|
789
|
+
end
|
|
790
|
+
end
|
|
783
791
|
xml.PackGrSwissmedic obj[:siz] unless obj[:siz].empty?
|
|
784
792
|
xml.EinheitSwissmedic obj[:eht] unless obj[:eht].empty?
|
|
785
793
|
xml.SubstanceSwissmedic obj[:sub] unless obj[:sub].empty?
|
|
@@ -167,6 +167,16 @@ module Oddb2xml
|
|
|
167
167
|
parse_entries
|
|
168
168
|
end
|
|
169
169
|
|
|
170
|
+
# Lookup map: CUD id (e.g. "NORDIMET" or "GLIVEC.01") => indication text.
|
|
171
|
+
# Used to resolve limitation texts that are stored as a reference on
|
|
172
|
+
# the RegulatedAuthorization rather than inline.
|
|
173
|
+
def cud_text_by_id
|
|
174
|
+
@cud_text_by_id ||= @clinical_use_definitions.each_with_object({}) do |cud, acc|
|
|
175
|
+
next unless cud.id && cud.text
|
|
176
|
+
acc[cud.id] = cud.text
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
170
180
|
private
|
|
171
181
|
|
|
172
182
|
def parse_entries
|
|
@@ -383,7 +393,11 @@ module Oddb2xml
|
|
|
383
393
|
when "statusDate"
|
|
384
394
|
limitation[:status_date] = sub_ext["valueDate"]
|
|
385
395
|
when "limitationText"
|
|
396
|
+
# Not present in the live FHIR feed — kept for forward-compat.
|
|
386
397
|
limitation[:text] = sub_ext["valueString"]
|
|
398
|
+
when "limitationIndication"
|
|
399
|
+
ref = sub_ext.dig("valueReference", "reference")
|
|
400
|
+
limitation[:cud_ref] = ref&.sub(%r{\A.*ClinicalUseDefinition/}, "")
|
|
387
401
|
when "period"
|
|
388
402
|
limitation[:start_date] = sub_ext.dig("valuePeriod", "start")
|
|
389
403
|
limitation[:end_date] = sub_ext.dig("valuePeriod", "end")
|
|
@@ -467,11 +481,15 @@ module Oddb2xml
|
|
|
467
481
|
|
|
468
482
|
# Find prices and additional data for this package
|
|
469
483
|
pack.Prices = create_prices_for_package(bundle, pkg)
|
|
470
|
-
|
|
484
|
+
|
|
471
485
|
# Add limitations and cost share
|
|
472
486
|
pack.Limitations = create_limitations_for_package(bundle, pkg)
|
|
473
487
|
pack.CostShare = get_cost_share_for_package(bundle, pkg)
|
|
474
488
|
|
|
489
|
+
# Per-language CUD text map so merge_language can fill in
|
|
490
|
+
# DescriptionFr / DescriptionIt for limitations without re-parsing.
|
|
491
|
+
pack.CudTextById = bundle.cud_text_by_id
|
|
492
|
+
|
|
475
493
|
pack
|
|
476
494
|
end
|
|
477
495
|
|
|
@@ -533,23 +551,32 @@ module Oddb2xml
|
|
|
533
551
|
|
|
534
552
|
return nil unless reimbursement
|
|
535
553
|
return nil if reimbursement.limitations.empty?
|
|
536
|
-
|
|
554
|
+
|
|
555
|
+
cud_texts = bundle.cud_text_by_id
|
|
556
|
+
|
|
537
557
|
# Convert FHIR limitations to OpenStruct format
|
|
538
558
|
limitations = OpenStruct.new
|
|
539
559
|
limitations.Limitation = reimbursement.limitations.map do |lim|
|
|
560
|
+
# The actual limitation text lives in the referenced
|
|
561
|
+
# ClinicalUseDefinition (limitationIndication reference) — the
|
|
562
|
+
# `limitationText` sub-extension is absent in the live BAG feed.
|
|
563
|
+
cud_ref = lim[:cud_ref]
|
|
564
|
+
text_de = lim[:text] || (cud_ref && cud_texts[cud_ref]) || ""
|
|
565
|
+
|
|
540
566
|
limitation = OpenStruct.new
|
|
541
567
|
limitation.LimitationCode = "" # Not in FHIR
|
|
542
568
|
limitation.LimitationType = "" # Could derive from status
|
|
543
569
|
limitation.LimitationNiveau = "" # Not in FHIR
|
|
544
570
|
limitation.LimitationValue = "" # Not in FHIR
|
|
545
|
-
limitation.
|
|
546
|
-
limitation.
|
|
547
|
-
limitation.
|
|
571
|
+
limitation.LimitationCudRef = cud_ref # carried through for FR/IT resolution
|
|
572
|
+
limitation.DescriptionDe = text_de
|
|
573
|
+
limitation.DescriptionFr = "" # filled by merge_language from FR bundle
|
|
574
|
+
limitation.DescriptionIt = "" # filled by merge_language from IT bundle
|
|
548
575
|
limitation.ValidFromDate = lim[:status_date] || lim[:start_date] || ""
|
|
549
576
|
limitation.ValidThruDate = lim[:end_date] || ""
|
|
550
577
|
limitation
|
|
551
578
|
end
|
|
552
|
-
|
|
579
|
+
|
|
553
580
|
limitations
|
|
554
581
|
end
|
|
555
582
|
|
|
@@ -751,6 +778,7 @@ module Oddb2xml
|
|
|
751
778
|
desc_de: lim.DescriptionDe || "",
|
|
752
779
|
desc_fr: lim.DescriptionFr || "",
|
|
753
780
|
desc_it: lim.DescriptionIt || "",
|
|
781
|
+
cud_ref: lim.LimitationCudRef,
|
|
754
782
|
vdate: lim.ValidFromDate || "",
|
|
755
783
|
del: is_deleted
|
|
756
784
|
}
|
|
@@ -796,6 +824,7 @@ module Oddb2xml
|
|
|
796
824
|
name_accessor = "Name#{lang.capitalize}"
|
|
797
825
|
name_key = "name_#{lang}".to_sym
|
|
798
826
|
desc_key = "desc_#{lang}".to_sym
|
|
827
|
+
lim_desc_key = "desc_#{lang}".to_sym
|
|
799
828
|
|
|
800
829
|
result.Preparations.Preparation.each do |seq|
|
|
801
830
|
next unless seq && seq.Packs && seq.Packs.Pack
|
|
@@ -822,6 +851,19 @@ module Oddb2xml
|
|
|
822
851
|
if desc && !desc.empty? && item[:packages][ean13]
|
|
823
852
|
item[:packages][ean13][desc_key] = desc
|
|
824
853
|
end
|
|
854
|
+
|
|
855
|
+
# Resolve FR/IT limitation texts via the CUD reference captured
|
|
856
|
+
# during the DE pass. The CUD id (e.g. "NORDIMET") is identical
|
|
857
|
+
# across languages; only the text differs.
|
|
858
|
+
pkg_entry = item[:packages][ean13]
|
|
859
|
+
cud_texts = pac.respond_to?(:CudTextById) ? pac.CudTextById : nil
|
|
860
|
+
if pkg_entry && cud_texts && pkg_entry[:limitations]
|
|
861
|
+
pkg_entry[:limitations].each do |lim|
|
|
862
|
+
ref = lim[:cud_ref]
|
|
863
|
+
text = ref && cud_texts[ref]
|
|
864
|
+
lim[lim_desc_key] = text if text && !text.empty?
|
|
865
|
+
end
|
|
866
|
+
end
|
|
825
867
|
end
|
|
826
868
|
end
|
|
827
869
|
end
|
data/lib/oddb2xml/version.rb
CHANGED
data/spec/fhir_spec.rb
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
|
+
require "json"
|
|
3
|
+
require "tempfile"
|
|
2
4
|
require "oddb2xml/downloader"
|
|
3
5
|
require "oddb2xml/extractor"
|
|
4
6
|
require "oddb2xml/fhir_support"
|
|
7
|
+
require "oddb2xml/builder"
|
|
5
8
|
|
|
6
9
|
describe "FHIR Indikationscode support" do
|
|
7
10
|
let(:cyramza_fixture) { File.join(Oddb2xml::SpecData, "fhir", "cyramza.ndjson") }
|
|
@@ -50,4 +53,121 @@ describe "FHIR Indikationscode support" do
|
|
|
50
53
|
expect(pkg[:indication_codes]).to eq(item[:indication_codes])
|
|
51
54
|
end
|
|
52
55
|
end
|
|
56
|
+
|
|
57
|
+
describe Oddb2xml::FhirExtractor, "limitation text resolution" do
|
|
58
|
+
# Build language-variant copies of the Cyramza fixture in-memory:
|
|
59
|
+
# the live FHIR feed never stores limitation text inline, only a
|
|
60
|
+
# reference to a ClinicalUseDefinition whose `concept.text` differs
|
|
61
|
+
# per language. We translate the CUD text + MPD product name and
|
|
62
|
+
# write the modified bundle to a Tempfile so the multi-language
|
|
63
|
+
# path can be exercised end-to-end.
|
|
64
|
+
def language_variant(source_path, lang_code, cud_texts, product_name)
|
|
65
|
+
bundle = JSON.parse(File.read(source_path))
|
|
66
|
+
bundle["entry"].each do |entry|
|
|
67
|
+
res = entry["resource"]
|
|
68
|
+
case res["resourceType"]
|
|
69
|
+
when "MedicinalProductDefinition"
|
|
70
|
+
res["name"].each do |name|
|
|
71
|
+
usage = name.dig("usage", 0, "language", "coding", 0)
|
|
72
|
+
usage["code"] = lang_code if usage
|
|
73
|
+
name["productName"] = product_name
|
|
74
|
+
end
|
|
75
|
+
when "ClinicalUseDefinition"
|
|
76
|
+
text = cud_texts[res["id"]]
|
|
77
|
+
if text
|
|
78
|
+
res["indication"]["diseaseSymptomProcedure"]["concept"]["text"] = text
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
file = Tempfile.new(["cyramza-#{lang_code}", ".ndjson"])
|
|
83
|
+
file.write(JSON.generate(bundle))
|
|
84
|
+
file.flush
|
|
85
|
+
file
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
let(:fr_file) do
|
|
89
|
+
language_variant(
|
|
90
|
+
cyramza_fixture, "fr-CH",
|
|
91
|
+
{
|
|
92
|
+
"CYRAMZA.01" => "FR limitation pour CYRAMZA.01",
|
|
93
|
+
"CYRAMZA.02" => "FR limitation pour CYRAMZA.02"
|
|
94
|
+
},
|
|
95
|
+
"Cyramza FR"
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
let(:it_file) do
|
|
100
|
+
language_variant(
|
|
101
|
+
cyramza_fixture, "it-CH",
|
|
102
|
+
{
|
|
103
|
+
"CYRAMZA.01" => "IT limitazione per CYRAMZA.01",
|
|
104
|
+
"CYRAMZA.02" => "IT limitazione per CYRAMZA.02"
|
|
105
|
+
},
|
|
106
|
+
"Cyramza IT"
|
|
107
|
+
)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
after do
|
|
111
|
+
[fr_file, it_file].each do |f|
|
|
112
|
+
f.close
|
|
113
|
+
f.unlink
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "fills DescriptionDe from the referenced ClinicalUseDefinition" do
|
|
118
|
+
data = described_class.new(cyramza_fixture).to_hash
|
|
119
|
+
pkg = data.values.first[:packages].values.first
|
|
120
|
+
texts = pkg[:limitations].map { |l| l[:desc_de] }
|
|
121
|
+
expect(texts).to include(start_with("In Kombination mit Paclitaxel"))
|
|
122
|
+
expect(texts).to include(start_with("In Kombination mit FOLFIRI"))
|
|
123
|
+
# CUD reference is carried through so merge_language can resolve FR/IT.
|
|
124
|
+
expect(pkg[:limitations].map { |l| l[:cud_ref] }).to include("CYRAMZA.01", "CYRAMZA.02")
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "fills DescriptionFr / DescriptionIt from the language-specific bundles" do
|
|
128
|
+
files = {"de" => cyramza_fixture, "fr" => fr_file.path, "it" => it_file.path}
|
|
129
|
+
data = described_class.new(files).to_hash
|
|
130
|
+
pkg = data.values.first[:packages].values.first
|
|
131
|
+
|
|
132
|
+
by_ref = pkg[:limitations].each_with_object({}) { |l, h| h[l[:cud_ref]] = l }
|
|
133
|
+
|
|
134
|
+
expect(by_ref["CYRAMZA.01"][:desc_fr]).to eq("FR limitation pour CYRAMZA.01")
|
|
135
|
+
expect(by_ref["CYRAMZA.02"][:desc_fr]).to eq("FR limitation pour CYRAMZA.02")
|
|
136
|
+
expect(by_ref["CYRAMZA.01"][:desc_it]).to eq("IT limitazione per CYRAMZA.01")
|
|
137
|
+
expect(by_ref["CYRAMZA.02"][:desc_it]).to eq("IT limitazione per CYRAMZA.02")
|
|
138
|
+
# DE text is still there.
|
|
139
|
+
expect(by_ref["CYRAMZA.01"][:desc_de]).to start_with("In Kombination mit Paclitaxel")
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
describe Oddb2xml::Builder, "PRD INDICATION_CODE emission" do
|
|
144
|
+
it "emits one <INDICATION_CODE> child per indication on the PRD" do
|
|
145
|
+
items = Oddb2xml::FhirExtractor.new(cyramza_fixture).to_hash
|
|
146
|
+
builder = described_class.new
|
|
147
|
+
builder.instance_variable_set(:@items, items)
|
|
148
|
+
builder.instance_variable_set(:@refdata, {})
|
|
149
|
+
builder.instance_variable_set(:@packs, {})
|
|
150
|
+
builder.instance_variable_set(:@migel, {})
|
|
151
|
+
builder.instance_variable_set(:@interactions, [])
|
|
152
|
+
builder.instance_variable_set(:@flags, {})
|
|
153
|
+
builder.instance_variable_set(:@orphan, [])
|
|
154
|
+
builder.instance_variable_set(:@firstbase, {})
|
|
155
|
+
builder.instance_variable_set(:@substances, [])
|
|
156
|
+
builder.instance_variable_set(:@codes, {})
|
|
157
|
+
builder.instance_variable_set(:@missing, [])
|
|
158
|
+
builder.instance_variable_set(:@tag_suffix, nil)
|
|
159
|
+
|
|
160
|
+
xml = builder.send(:build_product)
|
|
161
|
+
expect(xml).to include("<INDICATION_CODE")
|
|
162
|
+
expect(xml).to include('code="20403.01"')
|
|
163
|
+
expect(xml).to include('code="20403.02"')
|
|
164
|
+
expect(xml).to include('cud_id="CYRAMZA.01"')
|
|
165
|
+
expect(xml).to include('cud_id="CYRAMZA.02"')
|
|
166
|
+
# The CUD's indication text travels into the element body so
|
|
167
|
+
# downstream consumers can show the human-readable indication
|
|
168
|
+
# next to the code.
|
|
169
|
+
expect(xml).to include("In Kombination mit Paclitaxel")
|
|
170
|
+
expect(xml).to include("In Kombination mit FOLFIRI")
|
|
171
|
+
end
|
|
172
|
+
end
|
|
53
173
|
end
|