oddb2xml 2.7.1 → 2.7.2
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/.github/workflows/ruby.yml +1 -1
- data/.standard.yml +2 -0
- data/Gemfile +3 -3
- data/History.txt +8 -0
- data/README.md +1 -1
- data/Rakefile +24 -23
- data/bin/check_artikelstamm +11 -11
- data/bin/compare_v5 +23 -23
- data/bin/oddb2xml +14 -13
- data/lib/oddb2xml.rb +1 -1
- data/lib/oddb2xml/builder.rb +1070 -1038
- data/lib/oddb2xml/calc.rb +232 -233
- data/lib/oddb2xml/chapter_70_hack.rb +38 -32
- data/lib/oddb2xml/cli.rb +252 -236
- data/lib/oddb2xml/compare.rb +70 -59
- data/lib/oddb2xml/compositions_syntax.rb +448 -430
- data/lib/oddb2xml/compressor.rb +20 -20
- data/lib/oddb2xml/downloader.rb +153 -127
- data/lib/oddb2xml/extractor.rb +302 -289
- data/lib/oddb2xml/options.rb +34 -35
- data/lib/oddb2xml/parslet_compositions.rb +263 -269
- data/lib/oddb2xml/semantic_check.rb +39 -33
- data/lib/oddb2xml/util.rb +163 -163
- data/lib/oddb2xml/version.rb +1 -1
- data/lib/oddb2xml/xml_definitions.rb +32 -33
- data/oddb2xml.gemspec +31 -32
- data/spec/artikelstamm_spec.rb +111 -110
- data/spec/builder_spec.rb +489 -505
- data/spec/calc_spec.rb +552 -593
- data/spec/check_artikelstamm_spec.rb +26 -26
- data/spec/cli_spec.rb +173 -174
- data/spec/compare_spec.rb +9 -11
- data/spec/composition_syntax_spec.rb +390 -409
- data/spec/compressor_spec.rb +48 -48
- data/spec/data/transfer.dat +1 -0
- data/spec/data_helper.rb +47 -49
- data/spec/downloader_spec.rb +247 -260
- data/spec/extractor_spec.rb +171 -159
- data/spec/galenic_spec.rb +233 -256
- data/spec/options_spec.rb +116 -119
- data/spec/parslet_spec.rb +833 -861
- data/spec/spec_helper.rb +154 -153
- data/test_options.rb +39 -42
- data/tools/win_fetch_cacerts.rb +2 -3
- metadata +19 -3
@@ -1,41 +1,45 @@
|
|
1
|
-
|
2
|
-
require 'ox'
|
1
|
+
require "ox"
|
3
2
|
|
4
3
|
module Oddb2xml
|
5
4
|
def self.log_timestamp(msg)
|
6
5
|
full_msg = "#{Time.now.strftime("%H:%M:%S")}: #{msg}"
|
7
6
|
puts full_msg
|
8
|
-
|
7
|
+
$stdout.flush
|
9
8
|
full_msg
|
10
9
|
end
|
10
|
+
|
11
11
|
class SemanticCheckXML
|
12
12
|
attr_accessor :components
|
13
13
|
attr_reader :keys, :sub_key_names, :filename, :basename, :version, :hash
|
14
|
-
def initialize(filename, components = ["PRODUCTS", "LIMITATIONS", "ITEMS"
|
14
|
+
def initialize(filename, components = ["PRODUCTS", "LIMITATIONS", "ITEMS"])
|
15
15
|
raise "File #{filename} must exist" unless File.exist?(filename)
|
16
16
|
@filename = filename
|
17
17
|
@basename = File.basename(filename)
|
18
18
|
@components = components
|
19
19
|
@hash = load_file(@filename)
|
20
20
|
end
|
21
|
+
|
21
22
|
def self.get_component_key_name(component_name)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
return "LIMNAMEBAG" if /LIMITATION/i.match?(component_name)
|
24
|
+
return "PRODNO" if /PRODUCT/i.match?(component_name)
|
25
|
+
return "GTIN" if /ITEM/i.match?(component_name)
|
26
|
+
raise "Cannot determine keyname for component #{component_name}"
|
26
27
|
end
|
28
|
+
|
27
29
|
def get_items(component_name)
|
28
30
|
# hack to make it spec/check_artikelstamm.rb work if called alone or as part
|
29
31
|
# of the whole spec suite
|
30
|
-
xx= @hash[:ARTIKELSTAMM]
|
32
|
+
xx = @hash[:ARTIKELSTAMM] || @hash["ARTIKELSTAMM"]
|
31
33
|
comps = xx[component_name.to_sym] || xx[component_name]
|
32
34
|
comps.values.first
|
33
35
|
end
|
36
|
+
|
34
37
|
def load_file(name)
|
35
|
-
Oddb2xml.log_timestamp "Reading #{name} #{(File.size(name)/1024/1024).to_i} MB. This may take some time"
|
38
|
+
Oddb2xml.log_timestamp "Reading #{name} #{(File.size(name) / 1024 / 1024).to_i} MB. This may take some time"
|
36
39
|
Ox.load(IO.read(name), mode: :hash_no_attrs)
|
37
40
|
end
|
38
41
|
end
|
42
|
+
|
39
43
|
class SemanticCheck
|
40
44
|
attr_accessor :items, :products, :limitations
|
41
45
|
def initialize(filename)
|
@@ -45,20 +49,20 @@ module Oddb2xml
|
|
45
49
|
|
46
50
|
def everyProductNumberIsUnique
|
47
51
|
puts "#{Time.now.strftime("%H:%M:%S")}: everyProductNumberIsUnique"
|
48
|
-
return false unless
|
49
|
-
|
52
|
+
return false unless products.size > 0
|
53
|
+
products.collect { |x| x[:PRODNO] }.uniq.size == products.size
|
50
54
|
end
|
51
55
|
|
52
56
|
def everyGTINIsUnique
|
53
57
|
puts "#{Time.now.strftime("%H:%M:%S")}: everyGTINIsUnique"
|
54
|
-
return false unless
|
55
|
-
|
58
|
+
return false unless items.size > 0
|
59
|
+
items.collect { |x| x[:GTIN] }.uniq.size == items.size
|
56
60
|
end
|
57
61
|
|
58
62
|
def everyGTINIsNumericOnly
|
59
63
|
puts "#{Time.now.strftime("%H:%M:%S")}: everyGTINIsNumericOnly"
|
60
64
|
items.each do |item|
|
61
|
-
unless /^[0-9]+$/i.match(item[:GTIN])
|
65
|
+
unless /^[0-9]+$/i.match?(item[:GTIN])
|
62
66
|
puts "GTIN is not Numeric Only"
|
63
67
|
return false
|
64
68
|
end
|
@@ -68,13 +72,15 @@ module Oddb2xml
|
|
68
72
|
def everyPharmaArticleHasAProductItem
|
69
73
|
result = true
|
70
74
|
puts "#{Time.now.strftime("%H:%M:%S")}: everyPharmaArticleHasAProductItem"
|
71
|
-
|
75
|
+
all_product_numbers = products.collect { |product| product[:PRODNO] }
|
72
76
|
items.each do |item|
|
73
77
|
next unless item[:PRODNO]
|
74
|
-
unless
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
+
unless item[:Chapter70_HACK]
|
79
|
+
unless all_product_numbers.index(item[:PRODNO])
|
80
|
+
puts "Item #{item[:GTIN]} has no Product #{item[:PRODNO]} #{item[:DSCR]}"
|
81
|
+
result = false
|
82
|
+
end
|
83
|
+
end
|
78
84
|
end
|
79
85
|
result
|
80
86
|
end
|
@@ -82,9 +88,9 @@ module Oddb2xml
|
|
82
88
|
def everyProductHasAtLeastOneArticle
|
83
89
|
result = true
|
84
90
|
puts "#{Time.now.strftime("%H:%M:%S")}: veryProductHasAtLeastOneArticle"
|
85
|
-
|
91
|
+
all_product_numbers = items.collect { |item| item[:PRODNO] }
|
86
92
|
products.each do |product|
|
87
|
-
unless
|
93
|
+
unless all_product_numbers.index(product[:PRODNO])
|
88
94
|
puts "product #{product[:PRODNO]}: has no Item #{product[:DSCR]}"
|
89
95
|
result = false
|
90
96
|
end
|
@@ -95,10 +101,10 @@ module Oddb2xml
|
|
95
101
|
def everyReferencedLimitationIsIncluded
|
96
102
|
result = true
|
97
103
|
puts "#{Time.now.strftime("%H:%M:%S")}: everyReferencedLimitationIsIncluded"
|
98
|
-
|
104
|
+
all_limitations = limitations.collect { |lim| lim[:LIMNAMEBAG] }
|
99
105
|
products.each do |product|
|
100
106
|
next unless product[:LIMNAMEBAG]
|
101
|
-
unless
|
107
|
+
unless all_limitations.index(product[:LIMNAMEBAG])
|
102
108
|
puts "product #{product[:PRODNO]} has no limitation #{product[:LIMNAMEBAG]} #{product[:DSCR]}"
|
103
109
|
result = false
|
104
110
|
end
|
@@ -109,30 +115,30 @@ module Oddb2xml
|
|
109
115
|
def checkPackageSize
|
110
116
|
puts "#{Time.now.strftime("%H:%M:%S")}: checkPackageSize"
|
111
117
|
items.each do |item|
|
112
|
-
if item[
|
113
|
-
puts "WARNING possibly invalid package size #{item[
|
118
|
+
if item["PKG_SIZE"] && item["PKG_SIZE"].length >= 6
|
119
|
+
puts "WARNING possibly invalid package size #{item["PKG_SIZE"]}"
|
114
120
|
pp item
|
115
121
|
end
|
116
122
|
end
|
117
123
|
end
|
118
124
|
|
119
125
|
def allSemanticChecks
|
120
|
-
@limitations = @stammdaten.get_items(
|
121
|
-
@items = @stammdaten.get_items(
|
122
|
-
@products = @stammdaten.get_items(
|
126
|
+
@limitations = @stammdaten.get_items("LIMITATIONS")
|
127
|
+
@items = @stammdaten.get_items("ITEMS")
|
128
|
+
@products = @stammdaten.get_items("PRODUCTS")
|
123
129
|
puts "#{Time.now.strftime("%H:%M:%S")}: Running all semantic checks for #{@stammdaten.filename} for #{products.size} products and #{items.size} items"
|
124
|
-
|
130
|
+
if everyProductNumberIsUnique &&
|
125
131
|
everyGTINIsUnique &&
|
126
132
|
everyGTINIsNumericOnly &&
|
127
133
|
everyPharmaArticleHasAProductItem &&
|
128
134
|
everyProductHasAtLeastOneArticle &&
|
129
135
|
everyReferencedLimitationIsIncluded &&
|
130
136
|
checkPackageSize
|
131
|
-
puts "#{Time.now.strftime("%H:%M:%S")}: Checking #{@stammdaten.filename} failed"
|
132
|
-
false
|
133
|
-
else
|
134
137
|
puts "#{Time.now.strftime("%H:%M:%S")}: Everything is okay"
|
135
138
|
true
|
139
|
+
else
|
140
|
+
puts "#{Time.now.strftime("%H:%M:%S")}: Checking #{@stammdaten.filename} failed"
|
141
|
+
false
|
136
142
|
end
|
137
143
|
rescue => error
|
138
144
|
puts "Execution failed with #{error}"
|
data/lib/oddb2xml/util.rb
CHANGED
@@ -1,237 +1,233 @@
|
|
1
|
-
|
2
|
-
require
|
3
|
-
require 'htmlentities'
|
1
|
+
require "open-uri"
|
2
|
+
require "htmlentities"
|
4
3
|
|
5
4
|
module Oddb2xml
|
6
|
-
FAKE_GTIN_START =
|
7
|
-
def
|
8
|
-
|
5
|
+
FAKE_GTIN_START = "999999"
|
6
|
+
def self.gen_prodno(iksnr, seqnr)
|
7
|
+
sprintf("%05d", iksnr) + sprintf("%02d", seqnr)
|
9
8
|
end
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
|
10
|
+
def self.uri_open(url)
|
11
|
+
version = RUBY_VERSION.split(".").map { |x| x.to_i }
|
12
|
+
if (version <=> [2, 5, 0]) >= 0
|
13
|
+
URI.parse(url).open
|
14
14
|
else
|
15
|
-
|
15
|
+
IO.popen(url)
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
|
+
def self.calc_checksum(str)
|
19
20
|
str = str.strip
|
20
21
|
sum = 0
|
21
|
-
val =
|
22
|
+
val = str.split(//u)
|
22
23
|
12.times do |idx|
|
23
|
-
fct = ((idx%2)*2)+1
|
24
|
-
sum += fct*val[idx].to_i
|
24
|
+
fct = ((idx % 2) * 2) + 1
|
25
|
+
sum += fct * val[idx].to_i
|
25
26
|
end
|
26
|
-
((10-(sum%10))%10).to_s
|
27
|
+
((10 - (sum % 10)) % 10).to_s
|
27
28
|
end
|
28
29
|
|
29
30
|
unless defined?(RSpec)
|
30
|
-
|
31
|
-
|
31
|
+
WORK_DIR = Dir.pwd
|
32
|
+
DOWNLOADS = "#{Dir.pwd}/downloads"
|
32
33
|
end
|
33
34
|
@options = {}
|
34
|
-
@atc_csv_origin =
|
35
|
+
@atc_csv_origin = "https://github.com/zdavatz/cpp2sqlite/blob/master/input/atc_codes_multi_lingual.txt"
|
35
36
|
@atc_csv_content = {}
|
36
37
|
|
37
|
-
def
|
38
|
+
def self.html_decode(string)
|
38
39
|
german = string
|
39
|
-
german = string.force_encoding(
|
40
|
-
|
40
|
+
german = string.force_encoding("ISO-8859-1").encode("UTF-8") if string.encoding.to_s.eql?("ASCII")
|
41
|
+
until german.eql?(HTMLEntities.new.decode(german))
|
41
42
|
german = HTMLEntities.new.decode(german)
|
42
43
|
end
|
43
|
-
Oddb2xml.patch_some_utf8(german).gsub(
|
44
|
+
Oddb2xml.patch_some_utf8(german).gsub("<br>", "\n")
|
44
45
|
end
|
45
46
|
|
46
|
-
def
|
47
|
+
def self.patch_some_utf8(line)
|
47
48
|
begin
|
48
|
-
line = line.encode(
|
49
|
-
rescue
|
49
|
+
line = line.encode("utf-8")
|
50
|
+
rescue
|
50
51
|
end
|
51
52
|
begin
|
52
|
-
line.
|
53
|
+
line.tr("\u0089", "‰").tr("\u0092", "’").tr("\u0096", "-").tr("\u2013", "-").tr("\u201D", '"').chomp
|
53
54
|
rescue => error
|
54
55
|
puts "#{error}: in #{line}"
|
55
56
|
line
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
59
|
-
def
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
puts "#{error}: in #{line}"
|
66
|
-
end
|
60
|
+
def self.convert_to_8859_1(line)
|
61
|
+
# We want to ignore lines which are not really UTF-8 encoded
|
62
|
+
ausgabe = Oddb2xml.patch_some_utf8(line).encode("ISO-8859-1")
|
63
|
+
ausgabe.encode("ISO-8859-1")
|
64
|
+
rescue => error
|
65
|
+
puts "#{error}: in #{line}"
|
67
66
|
end
|
68
67
|
|
69
|
-
def
|
70
|
-
@atc_csv_content
|
68
|
+
def self.add_epha_changes_for_ATC(iksnr, atc_code, force_run: false)
|
69
|
+
@atc_csv_content = {} if force_run
|
71
70
|
if @atc_csv_content.size == 0
|
72
|
-
Oddb2xml.uri_open(@atc_csv_origin).readlines.each{
|
73
|
-
|
74
|
-
|
75
|
-
@atc_csv_content[[items[0], items[1]]] = items[2]
|
71
|
+
Oddb2xml.uri_open(@atc_csv_origin).readlines.each { |line|
|
72
|
+
items = line.split(",")
|
73
|
+
@atc_csv_content[[items[0], items[1]]] = items[2]
|
76
74
|
}
|
77
75
|
|
78
76
|
end
|
79
77
|
new_value = @atc_csv_content[[iksnr.to_s, atc_code]]
|
80
|
-
new_value
|
78
|
+
new_value || atc_code
|
81
79
|
end
|
82
80
|
|
83
|
-
def
|
81
|
+
def self.log(msg)
|
84
82
|
return unless @options[:log]
|
85
83
|
# TODO:: require 'pry'; binding.pry if msg.size > 1000
|
86
84
|
$stdout.puts "#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}: #{msg[0..250]}"
|
87
85
|
$stdout.flush
|
88
86
|
end
|
89
87
|
|
90
|
-
def
|
88
|
+
def self.save_options(options)
|
91
89
|
@options = options
|
92
90
|
end
|
93
91
|
|
94
|
-
def
|
92
|
+
def self.skip_download?
|
95
93
|
@options[:skip_download]
|
96
94
|
end
|
97
95
|
|
98
|
-
def
|
96
|
+
def self.skip_download(file)
|
99
97
|
return false if defined?(VCR)
|
100
|
-
dest = "#{
|
101
|
-
if File.
|
102
|
-
FileUtils.cp(dest, file, :
|
98
|
+
dest = "#{DOWNLOADS}/#{File.basename(file)}"
|
99
|
+
if File.exist?(dest)
|
100
|
+
FileUtils.cp(dest, file, verbose: false, preserve: true) unless File.expand_path(file).eql?(dest)
|
103
101
|
return true
|
104
102
|
end
|
105
103
|
false
|
106
104
|
end
|
107
105
|
|
108
|
-
def
|
109
|
-
src
|
110
|
-
dest = "#{
|
111
|
-
FileUtils.makedirs(
|
112
|
-
#return unless File.exists?(file)
|
113
|
-
return unless file
|
106
|
+
def self.download_finished(file, remove_file = true)
|
107
|
+
src = "#{WORK_DIR}/#{File.basename(file)}"
|
108
|
+
dest = "#{DOWNLOADS}/#{File.basename(file)}"
|
109
|
+
FileUtils.makedirs(DOWNLOADS)
|
110
|
+
# return unless File.exists?(file)
|
111
|
+
return unless file && File.exist?(file)
|
114
112
|
return if File.expand_path(file).eql?(dest)
|
115
|
-
FileUtils.cp(src, dest, :
|
113
|
+
FileUtils.cp(src, dest, verbose: false)
|
116
114
|
Oddb2xml.log("download_finished saved as #{dest} #{File.size(dest)} bytes.")
|
117
115
|
end
|
118
116
|
|
119
117
|
# please keep this constant in sync between (GEM) swissmedic-diff/lib/swissmedic-diff.rb and (GEM) oddb2xml/lib/oddb2xml/extractor.rb
|
120
|
-
def
|
118
|
+
def self.check_column_indices(sheet)
|
121
119
|
row = sheet[5] # Headers are found at row 5 since February 5
|
122
120
|
|
123
121
|
error_2019 = nil
|
124
|
-
0.upto(
|
125
|
-
COLUMNS_FEBRUARY_2019.each{
|
126
|
-
|key, value|
|
122
|
+
0.upto(COLUMNS_FEBRUARY_2019.size - 1).each { |idx| puts "#{idx}: #{row[idx].value}" } if $VERBOSE
|
123
|
+
COLUMNS_FEBRUARY_2019.each { |key, value|
|
127
124
|
header_name = row[COLUMNS_FEBRUARY_2019.keys.index(key)].value.to_s
|
128
125
|
unless value.match(header_name)
|
129
126
|
puts "#{__LINE__}: #{key} -> #{COLUMNS_FEBRUARY_2019.keys.index(key)} #{value}\nbut was #{header_name}" if $VERBOSE
|
130
|
-
error_2019 = "Packungen.xlslx_has_unexpected_column_#{COLUMNS_FEBRUARY_2019.keys.index(key)}_#{key}_#{value
|
127
|
+
error_2019 = "Packungen.xlslx_has_unexpected_column_#{COLUMNS_FEBRUARY_2019.keys.index(key)}_#{key}_#{value}_but_was_#{header_name}"
|
131
128
|
# require 'pry'; binding.pry
|
132
|
-
|
129
|
+
break
|
133
130
|
end
|
134
131
|
}
|
135
|
-
raise
|
132
|
+
raise error_2019.to_s if error_2019
|
136
133
|
end
|
137
134
|
|
138
135
|
# please keep this constant in sync between (GEM) swissmedic-diff/lib/swissmedic-diff.rb and (GEM) oddb2xml/lib/oddb2xml/extractor.rb
|
139
|
-
COLUMNS_FEBRUARY_2019= {
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
136
|
+
COLUMNS_FEBRUARY_2019 = {
|
137
|
+
iksnr: /Zulassungs-Nummer/i, # column-nr: 0
|
138
|
+
seqnr: /Dosisstärke-nummer/i,
|
139
|
+
name_base: /Bezeichnung des Arzneimittels/i,
|
140
|
+
company: /Zulassungsinhaberin/i,
|
141
|
+
production_science: /Heilmittelcode/i,
|
142
|
+
index_therapeuticus: /IT-Nummer/i, # column-nr: 5
|
143
|
+
atc_class: /ATC-Code/i,
|
144
|
+
registration_date: /Erstzul.datum Arzneimittel/i,
|
145
|
+
sequence_date: /Zul.datum Dosisstärke/i,
|
146
|
+
expiry_date: /Gültigkeitsdauer der Zulassung/i,
|
147
|
+
ikscd: /Packungscode/i, # column-nr: 10
|
148
|
+
size: /Packungsgrösse/i,
|
149
|
+
unit: /Einheit/i,
|
150
|
+
ikscat: /Abgabekategorie Packung/i,
|
151
|
+
ikscat_seq: /Abgabekategorie Dosisstärke/i,
|
152
|
+
ikscat_preparation: /Abgabekategorie Arzneimittel/i, # column-nr: 15
|
153
|
+
substances: /Wirkstoff/i,
|
154
|
+
composition: /Zusammensetzung/i,
|
155
|
+
composition_AMZV: /Volldeklaration rev. AMZV umgesetzt/i,
|
156
|
+
indication_registration: /Anwendungsgebiet Arzneimittel/i,
|
157
|
+
indication_sequence: /Anwendungsgebiet Dosisstärke/i, # column-nr 20
|
158
|
+
gen_production: /Gentechnisch hergestellte Wirkstoffe/i,
|
159
|
+
insulin_category: /Kategorie bei Insulinen/i,
|
160
|
+
# swissmedi corrected in february 2018 the typo betäubunsmittel to betäubungsmittel-
|
161
|
+
drug_index: /Verz. bei betäubungsmittel-haltigen Arzneimittel/i
|
162
|
+
}
|
166
163
|
|
167
164
|
COLUMNS_JULY_2015 = {
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
def
|
165
|
+
iksnr: /Zulassungs-Nummer/i, # column-nr: 0
|
166
|
+
seqnr: /Dosisstärke-nummer/i,
|
167
|
+
name_base: /Präparatebezeichnung/i,
|
168
|
+
company: /Zulassungsinhaberin/i,
|
169
|
+
production_science: /Heilmittelcode/i,
|
170
|
+
index_therapeuticus: /IT-Nummer/i, # column-nr: 5
|
171
|
+
atc_class: /ATC-Code/i,
|
172
|
+
registration_date: /Erstzulassungs-datum./i,
|
173
|
+
sequence_date: /Zul.datum Dosisstärke/i,
|
174
|
+
expiry_date: /Gültigkeitsdauer der Zulassung/i,
|
175
|
+
ikscd: /Packungscode/i, # column-nr: 10
|
176
|
+
size: /Packungsgrösse/i,
|
177
|
+
unit: /Einheit/i,
|
178
|
+
ikscat: /Abgabekategorie Arzneimittel/i,
|
179
|
+
ikscat_seq: /Abgabekategorie Dosisstärke/i,
|
180
|
+
ikscat_preparation: /Abgabekategorie Präparat/i, # column-nr: 15
|
181
|
+
substances: /Wirkstoff/i,
|
182
|
+
composition: /Zusammensetzung/i,
|
183
|
+
indication_registration: /Anwendungsgebiet Präparat/i,
|
184
|
+
indication_sequence: /Anwendungsgebiet Dosisstärke/i,
|
185
|
+
gen_production: /Gentechnisch hergestellte Wirkstoffe/i, # column-nr 20
|
186
|
+
insulin_category: /Kategorie bei Insulinen/i,
|
187
|
+
# swissmedi corrected in february 2018 the typo betäubunsmittel to betäubungsmittel-
|
188
|
+
drug_index: /Verz. bei betäubun.*smittel-haltigen Präparaten/i
|
189
|
+
}
|
190
|
+
def self.add_hash(string)
|
194
191
|
doc = Nokogiri::XML.parse(string) do |config|
|
195
192
|
config.huge
|
196
193
|
end
|
197
194
|
nr = 0
|
198
195
|
doc.root.elements.each do |node|
|
199
196
|
nr += 1
|
200
|
-
next if node.name.eql?(
|
201
|
-
node[
|
197
|
+
next if node.name.eql?("RESULT")
|
198
|
+
node["SHA256"] = Digest::SHA256.hexdigest node.text
|
202
199
|
end
|
203
200
|
doc.to_xml
|
204
201
|
end
|
205
202
|
|
206
|
-
def
|
203
|
+
def self.verify_sha256(file)
|
207
204
|
f = File.open(file)
|
208
205
|
doc = Nokogiri::XML(f)
|
209
206
|
nr = 0
|
210
207
|
doc.root.elements.each do |node|
|
211
208
|
nr += 1
|
212
|
-
next if node.name.eql?(
|
209
|
+
next if node.name.eql?("RESULT")
|
213
210
|
sha256 = Digest::SHA256.hexdigest node.text
|
214
|
-
unless node[
|
215
|
-
puts "Verifiying #{node[
|
216
|
-
exit
|
211
|
+
unless node["SHA256"].eql?(sha256)
|
212
|
+
puts "Verifiying #{node["SHA256"]} != expectd #{sha256} against node #{node.text} failed"
|
213
|
+
exit(3)
|
217
214
|
end
|
218
215
|
end
|
219
|
-
|
216
|
+
true
|
220
217
|
end
|
221
218
|
|
222
|
-
def
|
223
|
-
xsd =open(xsd_file).read
|
219
|
+
def self.validate_via_xsd(xsd_file, xml_file)
|
220
|
+
xsd = IO.open(xsd_file).read
|
224
221
|
xsd_rtikelstamm_xml = Nokogiri::XML::Schema(xsd)
|
225
222
|
doc = Nokogiri::XML(File.read(xml_file))
|
226
|
-
xsd_rtikelstamm_xml.validate(doc).each do
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
expect(error.message).to be_nil, msg
|
223
|
+
xsd_rtikelstamm_xml.validate(doc).each do |error|
|
224
|
+
if error.message
|
225
|
+
puts "Failed validating #{xml_file} with #{File.size(xml_file)} bytes using XSD from #{xsd_file}"
|
226
|
+
puts "CMD: xmllint --noout --schema #{xsd_file} #{xml_file}"
|
227
|
+
end
|
228
|
+
msg = "expected #{error.message} to be nil\nfor #{xml_file}"
|
229
|
+
puts msg
|
230
|
+
expect(error.message).to be_nil, msg
|
235
231
|
end
|
236
232
|
end
|
237
233
|
|
@@ -240,36 +236,40 @@ COLUMNS_FEBRUARY_2019= {
|
|
240
236
|
@@no8_to_ean13 = {}
|
241
237
|
@@ean13_to_prodno = {}
|
242
238
|
@@ean13_to_no8 = {}
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
end
|
247
|
-
@@prodno_to_ean13[prodno] ||= []
|
248
|
-
@@prodno_to_ean13[prodno] << ean13
|
249
|
-
@@ean13_to_prodno[ean13] = prodno
|
250
|
-
end
|
251
|
-
def Oddb2xml.setEan13forNo8(no8, ean13)
|
252
|
-
if ean13.to_i == 7680006660045 || ean13.to_i == 7680006660014
|
253
|
-
Oddb2xml.log "setEan13forNo8 #{no8} ean13 #{ean13}"
|
254
|
-
end
|
255
|
-
if @@no8_to_ean13[no8].nil?
|
256
|
-
@@no8_to_ean13[no8] = ean13
|
257
|
-
@@ean13_to_no8[ean13] = no8
|
258
|
-
elsif !@@no8_to_ean13[no8].eql?(ean13)
|
259
|
-
Oddb2xml.log "@@no8_to_ean13[no8] #{@@no8_to_ean13[no8]} not overridden by #{ean13}"
|
260
|
-
end
|
261
|
-
end
|
262
|
-
def Oddb2xml.getEan13forProdno(prodno)
|
263
|
-
@@prodno_to_ean13[prodno] || []
|
239
|
+
def self.setEan13forProdno(prodno, ean13)
|
240
|
+
if ean13.to_i == 7680006660045 || ean13.to_i == 7680006660014
|
241
|
+
Oddb2xml.log "setEan13forProdno #{prodno} ean13 #{ean13}"
|
264
242
|
end
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
243
|
+
@@prodno_to_ean13[prodno] ||= []
|
244
|
+
@@prodno_to_ean13[prodno] << ean13
|
245
|
+
@@ean13_to_prodno[ean13] = prodno
|
246
|
+
end
|
247
|
+
|
248
|
+
def self.setEan13forNo8(no8, ean13)
|
249
|
+
if ean13.to_i == 7680006660045 || ean13.to_i == 7680006660014
|
250
|
+
Oddb2xml.log "setEan13forNo8 #{no8} ean13 #{ean13}"
|
270
251
|
end
|
271
|
-
|
272
|
-
@@
|
252
|
+
if @@no8_to_ean13[no8].nil?
|
253
|
+
@@no8_to_ean13[no8] = ean13
|
254
|
+
@@ean13_to_no8[ean13] = no8
|
255
|
+
elsif !@@no8_to_ean13[no8].eql?(ean13)
|
256
|
+
Oddb2xml.log "@@no8_to_ean13[no8] #{@@no8_to_ean13[no8]} not overridden by #{ean13}"
|
273
257
|
end
|
258
|
+
end
|
274
259
|
|
260
|
+
def self.getEan13forProdno(prodno)
|
261
|
+
@@prodno_to_ean13[prodno] || []
|
262
|
+
end
|
263
|
+
|
264
|
+
def self.getEan13forNo8(no8)
|
265
|
+
@@no8_to_ean13[no8] || []
|
266
|
+
end
|
267
|
+
|
268
|
+
def self.getProdnoForEan13(ean13)
|
269
|
+
@@ean13_to_prodno[ean13]
|
270
|
+
end
|
271
|
+
|
272
|
+
def self.getNo8ForEan13(ean13)
|
273
|
+
@@ean13_to_no8[ean13]
|
274
|
+
end
|
275
275
|
end
|