oddb2xml 2.5.2 → 2.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/History.txt +8 -0
- data/README.md +2 -8
- data/bin/check_artikelstamm +30 -0
- data/lib/oddb2xml/builder.rb +21 -14
- data/lib/oddb2xml/cli.rb +1 -1
- data/lib/oddb2xml/extractor.rb +27 -12
- data/lib/oddb2xml/semantic_check.rb +141 -0
- data/lib/oddb2xml/util.rb +3 -0
- data/lib/oddb2xml/version.rb +1 -1
- data/oddb2xml.gemspec +1 -0
- data/spec/artikelstamm_spec.rb +4 -3
- data/spec/builder_spec.rb +8 -6
- data/spec/check_artikelstamm_spec.rb +46 -0
- data/spec/data/Preparations.xml +280 -1
- data/spec/data/check_artikelstamm/artikelstamm_v5_gtin_non_numeric.xml +79 -0
- data/spec/data/check_artikelstamm/artikelstamm_v5_gtin_not_uniq.xml +79 -0
- data/spec/data/check_artikelstamm/artikelstamm_v5_limitation_exists.xml +79 -0
- data/spec/data/check_artikelstamm/artikelstamm_v5_okay.xml +79 -0
- data/spec/data/check_artikelstamm/artikelstamm_v5_pharma_has_product.xml +78 -0
- data/spec/data/check_artikelstamm/artikelstamm_v5_prodno_not_uniq.xml +79 -0
- data/spec/data/check_artikelstamm/artikelstamm_v5_product_needs_article.xml +79 -0
- data/spec/data/refdata_Pharma.xml +44 -0
- data/spec/data/swissmedic_package.xlsx +0 -0
- data/spec/data/transfer.dat +2 -1
- data/spec/extractor_spec.rb +1 -1
- data/spec/parslet_spec.rb +1 -1
- metadata +36 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a338462cc07d2820cb85ed2bab9e76e527a7b2e
|
4
|
+
data.tar.gz: 8b675f13da43ab8967e5d6b389553029433899bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45c766b45fe01b2b441aaab304347336f3962d2b83224dd43a5462da2b11c1f3cbeb598aba0c0c79e5fbba2ce6b9d951304a572adf1a2dfe29426c99b6b7858e
|
7
|
+
data.tar.gz: feb8c5046c1585e289a17a02f56d9dcebace6ddd8fb0df2c7d0027b1e4fcaabd838c555b799c2e549e2113d47acdf03cfb8cb6255a1651685987af506fb33595
|
data/.travis.yml
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 2.5.3 / 28.03.2018
|
2
|
+
|
3
|
+
* Updated needed Ruby version in README.md
|
4
|
+
* Test using Ruby 2.5.0 on tracis-ci, too
|
5
|
+
* Fix spec tests on travis-ci
|
6
|
+
* Added bin/check_artikelstamm
|
7
|
+
* Fixed problem with prodno in Artikeltstamm
|
8
|
+
|
1
9
|
=== 2.5.2 / 21.03.2018
|
2
10
|
|
3
11
|
* Artikelstamm
|
data/README.md
CHANGED
@@ -106,14 +106,8 @@ FR
|
|
106
106
|
|
107
107
|
## Supported ruby version
|
108
108
|
|
109
|
-
We run tests on travis-ci.org for the Ruby versions mentioned in the .travis.yml file.
|
110
|
-
|
111
|
-
* 2.0.0
|
112
|
-
* 2.1
|
113
|
-
* ruby-head
|
114
|
-
|
115
|
-
If you are running an older Ruby-Version (eg. 1.8 or 1.9.1), please upgrade before reporting a bug.
|
116
|
-
See also http://bugs.ruby-lang.org/projects/ruby/wiki/ReleaseEngineering
|
109
|
+
We run tests on travis-ci.org for the Ruby versions mentioned in the .travis.yml file. You will need ruby > 2.4 to work correctly.
|
110
|
+
Ruby 2.2/2.3 have problems with i18n encoding and fail a spec test for Naropin
|
117
111
|
|
118
112
|
|
119
113
|
## XSD files
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
root = Pathname.new(__FILE__).realpath.parent.parent
|
5
|
+
$:.unshift root.join('lib') if $0 == __FILE__
|
6
|
+
|
7
|
+
require 'oddb2xml/version'
|
8
|
+
require 'oddb2xml/semantic_check'
|
9
|
+
require 'trollop'
|
10
|
+
|
11
|
+
@opts = Trollop::options(ARGV) do
|
12
|
+
version "#$0 ver.#{Oddb2xml::VERSION}"
|
13
|
+
banner <<-EOS
|
14
|
+
Runs various semanti_check for the Elexis artikelstamm
|
15
|
+
Usage:
|
16
|
+
#{File.basename(__FILE__)} xml_file_to_check
|
17
|
+
EOS
|
18
|
+
end
|
19
|
+
$stdout.sync = false
|
20
|
+
|
21
|
+
args = ARGV
|
22
|
+
if args.size != 1
|
23
|
+
puts "you must pass exactly one existing files. Not #{args}"
|
24
|
+
exit 2
|
25
|
+
end
|
26
|
+
|
27
|
+
startTime = Time.now
|
28
|
+
result = Oddb2xml::SemanticCheck.new(ARGV.first).allSemanticChecks
|
29
|
+
diff = (Time.now-startTime).to_i
|
30
|
+
puts "#{Time.now.strftime("%H:%M:%S")}: #{__FILE__} done. Took #{diff} seconds"
|
data/lib/oddb2xml/builder.rb
CHANGED
@@ -51,7 +51,7 @@ module Oddb2xml
|
|
51
51
|
@options = args
|
52
52
|
@subject = nil
|
53
53
|
@refdata = {}
|
54
|
-
@items = {} # Items from Preparations.xml in BAG, using
|
54
|
+
@items = {} # Items from Preparations.xml in BAG, using @gtins as key
|
55
55
|
@flags = {}
|
56
56
|
@lppvs = {}
|
57
57
|
@infos = {}
|
@@ -1362,7 +1362,7 @@ module Oddb2xml
|
|
1362
1362
|
|
1363
1363
|
def build_artikelstamm
|
1364
1364
|
@@emitted_v5_gtins = []
|
1365
|
-
@csv_file = CSV.open(File.join(WorkDir,
|
1365
|
+
@csv_file = CSV.open(File.join(WorkDir, "artikelstamm_#{Date.today.strftime('%d%m%Y')}_v5.csv"), "w+")
|
1366
1366
|
@csv_file << ['gtin', 'price', 'galenic_form', 'pkg_size', 'pexf', 'ppub', 'iksnr', 'atc_code', 'active_substance', 'original', 'it-code', 'sl-liste']
|
1367
1367
|
@csv_file.sync = true
|
1368
1368
|
variant = "build_artikelstamm"
|
@@ -1399,23 +1399,18 @@ module Oddb2xml
|
|
1399
1399
|
end
|
1400
1400
|
def emit_items(xml)
|
1401
1401
|
nr_items = 0
|
1402
|
-
|
1403
|
-
@
|
1404
|
-
gtins = gtins_to_article.keys + @infos_zur_rose.keys + @packs.values.collect{|x| x[:ean13]}
|
1405
|
-
gtins = (gtins-@@gtin2ignore)
|
1406
|
-
gtins.sort!.uniq!
|
1407
|
-
@nr_items = gtins.size
|
1408
|
-
gtins.each do |ean13|
|
1402
|
+
@nr_items = @gtins.size
|
1403
|
+
@gtins.each do |ean13|
|
1409
1404
|
pac,no8 = nil,ean13.to_s[4..11] # BAG-XML(SL/LS)
|
1410
1405
|
next if ean13 == 0
|
1411
|
-
obj = gtins_to_article[ean13] || @infos_zur_rose[ean13]
|
1406
|
+
obj = @gtins_to_article[ean13] || @infos_zur_rose[ean13]
|
1412
1407
|
if obj
|
1413
1408
|
obj = @packs[no8].merge(obj) if @packs[no8]
|
1414
1409
|
else
|
1415
1410
|
obj = @packs[no8] # obj not yet in refdata. Use data from swissmedic_package.xlsx
|
1416
1411
|
end
|
1417
1412
|
nr_items += 1
|
1418
|
-
Oddb2xml.log "build_article #{nr_items} of #{gtins.size} articles" if nr_items % 5000 == 0
|
1413
|
+
Oddb2xml.log "build_article #{nr_items} of #{@gtins.size} articles" if nr_items % 5000 == 0
|
1419
1414
|
item = @items[ean13]
|
1420
1415
|
pack_info = nil
|
1421
1416
|
pack_info = @packs[no8] if no8 && /#{ean13}/.match(@packs[no8].to_s) # info from Packungen.xlsx from swissmedic_info
|
@@ -1506,7 +1501,8 @@ module Oddb2xml
|
|
1506
1501
|
when 'N'; xml.DEDUCTIBLE 10; # 10%
|
1507
1502
|
else # xml.DEDUCTIBLE '' # k.A.
|
1508
1503
|
end if item && item[:deductible]
|
1509
|
-
|
1504
|
+
prodno = SwissmedicExtractor.getProdnoForEan13(pkg_gtin)
|
1505
|
+
xml.PRODNO prodno if prodno
|
1510
1506
|
csv = []
|
1511
1507
|
@csv_file << [pkg_gtin, name, package[:unit], measure,
|
1512
1508
|
pexf ? pexf : '',
|
@@ -1566,7 +1562,7 @@ module Oddb2xml
|
|
1566
1562
|
@nr_articles = 0
|
1567
1563
|
used_limitations = []
|
1568
1564
|
Oddb2xml.log "#{variant}: Deleted #{@old_rose_size - @new_rose_size} entries from ZurRose where GTIN start with 7680 (Swissmedic)"
|
1569
|
-
# Oddb2xml.log "#{variant} #{nr_products} of #{@products.size} articles and ignore #{@@gtin2ignore.size}
|
1565
|
+
# Oddb2xml.log "#{variant} #{nr_products} of #{@products.size} articles and ignore #{@@gtin2ignore.size} @gtins specified via #{@@ignore_file}"
|
1570
1566
|
_builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
|
1571
1567
|
xml.doc.tag_suffix = @tag_suffix
|
1572
1568
|
datetime = Time.new.strftime('%FT%T%z')
|
@@ -1579,7 +1575,14 @@ module Oddb2xml
|
|
1579
1575
|
'DATA_SOURCE' => 'oddb2xml'
|
1580
1576
|
}
|
1581
1577
|
emitted_prodno = []
|
1578
|
+
no8_to_prodno = {}
|
1579
|
+
@packs.collect{ |key, val| no8_to_prodno[key] = val [:prodno] }
|
1582
1580
|
xml.comment("Produced by #{__FILE__} version #{VERSION} at #{Time.now}")
|
1581
|
+
@gtins_to_article = {}
|
1582
|
+
@articles.each {|article| @gtins_to_article[article[:ean13]] = article }
|
1583
|
+
@gtins = @gtins_to_article.keys + @infos_zur_rose.keys + @packs.values.collect{|x| x[:ean13]}
|
1584
|
+
@gtins = (@gtins-@@gtin2ignore)
|
1585
|
+
@gtins.sort!.uniq!
|
1583
1586
|
xml.ARTIKELSTAMM(options_xml) do
|
1584
1587
|
xml.PRODUCTS do
|
1585
1588
|
products = @products.sort_by { |ean13, obj| ean13 }
|
@@ -1600,6 +1603,10 @@ module Oddb2xml
|
|
1600
1603
|
next if emitted_prodno.index(prodno)
|
1601
1604
|
sequence ||= @articles.find{|x| x[:ean13].eql?(ean)}
|
1602
1605
|
next unless sequence && (sequence[:name_de] || sequence[:desc_de])
|
1606
|
+
if SwissmedicExtractor.getEan13forProdno(prodno).size == 0
|
1607
|
+
puts "No item found for prodno #{prodno} no8 #{obj[:no8]} #{sequence[:name_de]} "
|
1608
|
+
next
|
1609
|
+
end
|
1603
1610
|
emitted_prodno << prodno
|
1604
1611
|
nr_products += 1
|
1605
1612
|
xml.PRODUCT do
|
@@ -1659,7 +1666,7 @@ module Oddb2xml
|
|
1659
1666
|
lines << " - #{sprintf('%5d', @products.size)} products"
|
1660
1667
|
lines << " - #{sprintf('%5d', @limitations.size)} limitations"
|
1661
1668
|
lines << " - #{sprintf('%5d', @nr_articles)} articles"
|
1662
|
-
lines << " - #{sprintf('%5d', @@gtin2ignore.size)} ignored
|
1669
|
+
lines << " - #{sprintf('%5d', @@gtin2ignore.size)} ignored @gtins"
|
1663
1670
|
@@articlestamm_v5_info_lines = lines
|
1664
1671
|
_builder.to_xml({:indent => 4, :encoding => 'UTF-8'})
|
1665
1672
|
end
|
data/lib/oddb2xml/cli.rb
CHANGED
@@ -94,7 +94,7 @@ module Oddb2xml
|
|
94
94
|
compress if @options[:compress_ext]
|
95
95
|
res = report
|
96
96
|
nrSecs = (Time.now - startTime).to_i
|
97
|
-
if defined?(RSpec) && (nrSecs).to_i > 10 then require 'pry'; binding.pry ; end
|
97
|
+
if defined?(RSpec) && (nrSecs).to_i > 10 && ENV['TRAVIS'].to_s.empty? then require 'pry'; binding.pry ; end
|
98
98
|
res
|
99
99
|
end
|
100
100
|
private
|
data/lib/oddb2xml/extractor.rb
CHANGED
@@ -80,7 +80,7 @@ module Oddb2xml
|
|
80
80
|
puts "BagXmlExtractor: Skipping as missing GTIN in SwissmedicNo8 #{pac.SwissmedicNo8} BagDossierNo #{pac.BagDossierNo} PackId #{pac.PackId} #{item[:name_de]}. Skipping"
|
81
81
|
else
|
82
82
|
ean12 = '7680' + pac.SwissmedicNo8
|
83
|
-
|
83
|
+
pac.GTIN = (ean12 + Oddb2xml.calc_checksum(ean12)) unless @artikelstamm
|
84
84
|
puts "BagXmlExtractor: Missing GTIN in SwissmedicNo8 #{pac.SwissmedicNo8} BagDossierNo #{pac.BagDossierNo} PackId #{pac.PackId} #{item[:name_de]}."
|
85
85
|
end
|
86
86
|
end
|
@@ -187,11 +187,11 @@ module Oddb2xml
|
|
187
187
|
items.each do |pac|
|
188
188
|
ean13 = (gtin = pac.GTIN.to_s) ? gtin: '0'
|
189
189
|
if ean13.size < 13
|
190
|
-
puts "Refdata #{@type} use 13 chars not #{ean13.size} for #{ean13}"
|
190
|
+
puts "Refdata #{@type} use 13 chars not #{ean13.size} for #{ean13}" if $VERBOSE
|
191
191
|
ean13 = ean13.rjust(13, '0')
|
192
192
|
end
|
193
193
|
if ean13.size == 14 && ean13[0] == '0'
|
194
|
-
puts "Refdata #{@type} remove leading '0' for #{ean13}"
|
194
|
+
puts "Refdata #{@type} remove leading '0' for #{ean13}" if $VERBOSE
|
195
195
|
ean13 = ean13[1..-1]
|
196
196
|
end
|
197
197
|
# but in refdata_nonPharma we have a about 700 GTINs which are 14 characters and longer
|
@@ -225,8 +225,17 @@ module Oddb2xml
|
|
225
225
|
@type = type
|
226
226
|
Oddb2xml.log("SwissmedicExtractor #{@filename} #{File.size(@filename)} bytes")
|
227
227
|
return unless File.exists?(@filename)
|
228
|
+
@@prodno_to_ean13 = {}
|
229
|
+
@@ean13_to_prodno = {}
|
228
230
|
@sheet = RubyXL::Parser.parse(File.expand_path(@filename)).worksheets[0]
|
229
231
|
end
|
232
|
+
# Needed for ensuring consitency for the Artikelstamm
|
233
|
+
def self.getEan13forProdno(prodno)
|
234
|
+
@@prodno_to_ean13[prodno] || []
|
235
|
+
end
|
236
|
+
def self.getProdnoForEan13(ean13)
|
237
|
+
@@ean13_to_prodno[ean13]
|
238
|
+
end
|
230
239
|
def to_arry
|
231
240
|
data = []
|
232
241
|
return data unless @sheet
|
@@ -255,10 +264,10 @@ module Oddb2xml
|
|
255
264
|
when :package
|
256
265
|
Oddb2xml.check_column_indices(@sheet)
|
257
266
|
ith = COLUMNS_JULY_2015.keys.index(:index_therapeuticus)
|
258
|
-
|
267
|
+
iksnr = COLUMNS_JULY_2015.keys.index(:iksnr)
|
259
268
|
seq_name = COLUMNS_JULY_2015.keys.index(:name_base)
|
260
269
|
i_3 = COLUMNS_JULY_2015.keys.index(:ikscd)
|
261
|
-
|
270
|
+
seqnr = COLUMNS_JULY_2015.keys.index(:seqnr)
|
262
271
|
cat = COLUMNS_JULY_2015.keys.index(:ikscat)
|
263
272
|
siz = COLUMNS_JULY_2015.keys.index(:size)
|
264
273
|
atc = COLUMNS_JULY_2015.keys.index(:atc_class)
|
@@ -287,19 +296,25 @@ module Oddb2xml
|
|
287
296
|
@sheet.each_with_index do |row, i|
|
288
297
|
|
289
298
|
next if (i <= 1)
|
290
|
-
next unless row and row[
|
291
|
-
next unless row[
|
292
|
-
no8 = sprintf('%05d',row[
|
293
|
-
prodno = sprintf('%05d',row[i_5].value.to_i) + sprintf('%02d', row[p_1_2].value.to_i).to_s
|
299
|
+
next unless row and row[iksnr] and row[i_3]
|
300
|
+
next unless row[iksnr].value.to_i > 0 and row[i_3].value.to_i > 0
|
301
|
+
no8 = sprintf('%05d',row[iksnr].value.to_i) + sprintf('%03d',row[i_3].value.to_i)
|
294
302
|
unless no8.empty?
|
295
303
|
next if no8.to_i == 0
|
296
304
|
ean_base12 = "7680#{no8}"
|
305
|
+
prodno = Oddb2xml.gen_prodno(row[iksnr].value.to_i, row[seqnr].value.to_i)
|
306
|
+
ean13 = (ean_base12.ljust(12, '0') + Oddb2xml.calc_checksum(ean_base12))
|
307
|
+
@@prodno_to_ean13[prodno] ||= []
|
308
|
+
@@prodno_to_ean13[prodno] << ean13
|
309
|
+
@@ean13_to_prodno[ean13] = prodno
|
297
310
|
data[no8] = {
|
298
|
-
:ean13 =>
|
299
|
-
:prodno => prodno
|
311
|
+
:ean13 => ean13,
|
312
|
+
:prodno => prodno,
|
313
|
+
:seqnr => row[seqnr].value,
|
314
|
+
:iksnr => row[iksnr].value,
|
300
315
|
:ith_swissmedic => row[ith] ? row[ith].value.to_s : '',
|
301
316
|
:swissmedic_category => row[cat].value.to_s,
|
302
|
-
:atc_code => row[atc] ? Oddb2xml.add_epha_changes_for_ATC(row[
|
317
|
+
:atc_code => row[atc] ? Oddb2xml.add_epha_changes_for_ATC(row[iksnr].value.to_s, row[atc].value.to_s) : '',
|
303
318
|
:list_code => row[list_code] ? row[list_code].value.to_s : '',
|
304
319
|
:package_size => row[siz] ? row[siz].value.to_s : '',
|
305
320
|
:einheit_swissmedic => row[eht] ? row[eht].value.to_s : '',
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'ox'
|
3
|
+
|
4
|
+
module Oddb2xml
|
5
|
+
def self.log_timestamp(msg)
|
6
|
+
full_msg = "#{Time.now.strftime("%H:%M:%S")}: #{msg}"
|
7
|
+
puts full_msg
|
8
|
+
STDOUT.flush
|
9
|
+
full_msg
|
10
|
+
end
|
11
|
+
class SemanticCheckXML
|
12
|
+
attr_accessor :components
|
13
|
+
attr_reader :keys, :sub_key_names, :filename, :basename, :version, :hash
|
14
|
+
def initialize(filename, components = ["PRODUCTS", "LIMITATIONS", "ITEMS",])
|
15
|
+
raise "File #{filename} must exist" unless File.exist?(filename)
|
16
|
+
@filename = filename
|
17
|
+
@basename = File.basename(filename)
|
18
|
+
@components = components
|
19
|
+
@hash = load_file(@filename)
|
20
|
+
end
|
21
|
+
def self.get_component_key_name(component_name)
|
22
|
+
return 'LIMNAMEBAG' if /LIMITATION/i.match(component_name)
|
23
|
+
return 'PRODNO' if /PRODUCT/i.match(component_name)
|
24
|
+
return 'GTIN' if /ITEM/i.match(component_name)
|
25
|
+
raise "Cannot determine keyname for component #{component_name}"
|
26
|
+
end
|
27
|
+
def get_items(component_name)
|
28
|
+
@hash[:ARTIKELSTAMM][component_name.to_sym].values.first
|
29
|
+
end
|
30
|
+
def load_file(name)
|
31
|
+
Oddb2xml.log_timestamp "Reading #{name} #{(File.size(name)/1024/1024).to_i} MB. This may take some time"
|
32
|
+
Ox.load(IO.read(name), mode: :hash_no_attrs)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
class SemanticCheck
|
36
|
+
attr_accessor :items, :products, :limitations
|
37
|
+
def initialize(filename)
|
38
|
+
@filename = filename
|
39
|
+
@stammdaten = SemanticCheckXML.new(filename)
|
40
|
+
end
|
41
|
+
|
42
|
+
def everyProductNumberIsUnique
|
43
|
+
puts "#{Time.now.strftime("%H:%M:%S")}: everyProductNumberIsUnique"
|
44
|
+
return false unless products.size > 0
|
45
|
+
return products.collect{ |x| x[:PRODNO]}.uniq.size == products.size
|
46
|
+
end
|
47
|
+
|
48
|
+
def everyGTINIsUnique
|
49
|
+
puts "#{Time.now.strftime("%H:%M:%S")}: everyGTINIsUnique"
|
50
|
+
return false unless items.size > 0
|
51
|
+
return items.collect{ |x| x[:GTIN]}.uniq.size == items.size
|
52
|
+
end
|
53
|
+
|
54
|
+
def everyGTINIsNumericOnly
|
55
|
+
puts "#{Time.now.strftime("%H:%M:%S")}: everyGTINIsNumericOnly"
|
56
|
+
items.each do |item|
|
57
|
+
unless /^[0-9]+$/i.match(item[:GTIN])
|
58
|
+
puts "GTIN is not Numeric Only"
|
59
|
+
return false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def everyPharmaArticleHasAProductItem
|
65
|
+
result = true
|
66
|
+
puts "#{Time.now.strftime("%H:%M:%S")}: everyPharmaArticleHasAProductItem"
|
67
|
+
allProductNumbers = products.collect{ |product| product[:PRODNO] }
|
68
|
+
items.each do |item|
|
69
|
+
next unless item[:PRODNO]
|
70
|
+
unless allProductNumbers.index(item[:PRODNO])
|
71
|
+
puts "Item #{item[:GTIN]} has no Product #{item[:PRODNO]} #{item[:DSCR]}"
|
72
|
+
result = false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
def everyProductHasAtLeastOneArticle
|
79
|
+
result = true
|
80
|
+
puts "#{Time.now.strftime("%H:%M:%S")}: veryProductHasAtLeastOneArticle"
|
81
|
+
allProductNumbers = items.collect{ |item| item[:PRODNO] }
|
82
|
+
products.each do |product|
|
83
|
+
unless allProductNumbers.index(product[:PRODNO])
|
84
|
+
puts "product #{product[:PRODNO]}: has no Item #{product[:DSCR]}"
|
85
|
+
result = false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
result
|
89
|
+
end
|
90
|
+
|
91
|
+
def everyReferencedLimitationIsIncluded
|
92
|
+
puts "#{Time.now.strftime("%H:%M:%S")}: everyReferencedLimitationIsIncluded"
|
93
|
+
allLimitations = limitations.collect{ |lim| lim[:LIMNAMEBAG] }
|
94
|
+
products.each do |product|
|
95
|
+
next unless product[:LIMNAMEBAG]
|
96
|
+
unless allLimitations.index(product[:LIMNAMEBAG])
|
97
|
+
puts "product #{product[:PRODNO]} has no limitation #{product[:LIMNAMEBAG]} #{product[:DSCR]}"
|
98
|
+
return false
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def checkPackageSize
|
104
|
+
puts "#{Time.now.strftime("%H:%M:%S")}: checkPackageSize"
|
105
|
+
items.each do |item|
|
106
|
+
if item['PKG_SIZE'] && item['PKG_SIZE'].length >= 6
|
107
|
+
puts "WARNING possibly invalid package size #{item['PKG_SIZE']}"
|
108
|
+
pp item
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def allSemanticChecks
|
114
|
+
@limitations = @stammdaten.get_items('LIMITATIONS')
|
115
|
+
@items = @stammdaten.get_items('ITEMS')
|
116
|
+
@products = @stammdaten.get_items('PRODUCTS')
|
117
|
+
puts "#{Time.now.strftime("%H:%M:%S")}: Running all semantic checks for #{@stammdaten.filename} for #{products.size} products and #{items.size} items"
|
118
|
+
unless everyProductNumberIsUnique &&
|
119
|
+
everyGTINIsUnique &&
|
120
|
+
everyGTINIsNumericOnly &&
|
121
|
+
everyPharmaArticleHasAProductItem &&
|
122
|
+
everyProductHasAtLeastOneArticle &&
|
123
|
+
everyReferencedLimitationIsIncluded &&
|
124
|
+
checkPackageSize
|
125
|
+
puts "#{Time.now.strftime("%H:%M:%S")}: Checking #{@stammdaten.filename} failed"
|
126
|
+
false
|
127
|
+
else
|
128
|
+
puts "#{Time.now.strftime("%H:%M:%S")}: Everything is okay"
|
129
|
+
true
|
130
|
+
end
|
131
|
+
rescue => error
|
132
|
+
puts "Execution failed with #{error}"
|
133
|
+
raise error
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
if $0.eql?(__FILE__)
|
139
|
+
daten = Oddb2xml::SemanticCheck.new(ARGV.first)
|
140
|
+
daten.allSemanticChecks
|
141
|
+
end
|
data/lib/oddb2xml/util.rb
CHANGED
data/lib/oddb2xml/version.rb
CHANGED
data/oddb2xml.gemspec
CHANGED
@@ -35,6 +35,7 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_dependency 'httpi' #, '>= 2.4.1'
|
36
36
|
spec.add_dependency 'trollop' #, '>= 2.4.1'
|
37
37
|
spec.add_dependency 'xml-simple'
|
38
|
+
spec.add_dependency 'ox'
|
38
39
|
|
39
40
|
spec.add_development_dependency "bundler"
|
40
41
|
spec.add_development_dependency "rake"
|
data/spec/artikelstamm_spec.rb
CHANGED
@@ -32,7 +32,8 @@ describe Oddb2xml::Builder do
|
|
32
32
|
@oddb2xml_xsd = File.expand_path(File.join(File.dirname(__FILE__), '..', 'oddb2xml.xsd'))
|
33
33
|
@oddb_calc_xsd = File.expand_path(File.join(File.dirname(__FILE__), '..', 'oddb_calc.xsd'))
|
34
34
|
@elexis_v5_xsd = File.expand_path(File.join(__FILE__, '..', '..', 'Elexis_Artikelstamm_v5.xsd'))
|
35
|
-
@elexis_v5_csv = File.join(Oddb2xml::WorkDir, '
|
35
|
+
@elexis_v5_csv = File.join(Oddb2xml::WorkDir, "artikelstamm_#{Date.today.strftime('%d%m%Y')}_v5.csv")
|
36
|
+
|
36
37
|
expect(File.exist?(@oddb2xml_xsd)).to eq true
|
37
38
|
expect(File.exist?(@oddb_calc_xsd)).to eq true
|
38
39
|
expect(File.exist?(@elexis_v5_xsd)).to eq true
|
@@ -126,9 +127,9 @@ describe Oddb2xml::Builder do
|
|
126
127
|
|
127
128
|
it 'should contain a PRODUCT which was not in refdata' do
|
128
129
|
expected = %(<PRODUCT>
|
129
|
-
<PRODNO>
|
130
|
+
<PRODNO>5559401</PRODNO>
|
130
131
|
<SALECD>A</SALECD>
|
131
|
-
<DSCR>Nutriflex
|
132
|
+
<DSCR>Nutriflex Lipid plus, Infusionsemulsion, 1250ml</DSCR>
|
132
133
|
<DSCRF/>
|
133
134
|
<ATC>B05BA10</ATC>
|
134
135
|
</PRODUCT>)
|
data/spec/builder_spec.rb
CHANGED
@@ -456,7 +456,7 @@ def checkProductXml(nbr_record = -1)
|
|
456
456
|
expect(desitin.elements['SubstanceSwissmedic'].text).to eq 'levetiracetamum'
|
457
457
|
expect(desitin.elements['CompositionSwissmedic'].text).to eq 'levetiracetamum 250 mg, excipiens pro compressi obducti pro charta.'
|
458
458
|
expect(desitin.elements['CPT/CPTCMP/LINE'].text).to eq '0'
|
459
|
-
expect(desitin.elements['CPT/CPTCMP/SUBNO'].text).to eq '
|
459
|
+
expect(desitin.elements['CPT/CPTCMP/SUBNO'].text).to eq '15'
|
460
460
|
expect(desitin.elements['CPT/CPTCMP/QTY'].text).to eq '250'
|
461
461
|
expect(desitin.elements['CPT/CPTCMP/QTYU'].text).to eq 'mg'
|
462
462
|
|
@@ -473,15 +473,15 @@ def checkProductXml(nbr_record = -1)
|
|
473
473
|
end
|
474
474
|
|
475
475
|
describe Oddb2xml::Builder do
|
476
|
-
NrExtendedArticles =
|
477
|
-
NrSubstances =
|
478
|
-
NrLimitations =
|
476
|
+
NrExtendedArticles = 74
|
477
|
+
NrSubstances = 30
|
478
|
+
NrLimitations = 14
|
479
479
|
|
480
480
|
NrInteractions = 2
|
481
481
|
NrCodes = 5
|
482
482
|
NrProdno = 31
|
483
|
-
NrPackages =
|
484
|
-
NrProducts =
|
483
|
+
NrPackages = 43
|
484
|
+
NrProducts = 39
|
485
485
|
RegExpDesitin = /1125819012LEVETIRACETAM DESITIN Mini Filmtab 250 mg 30 Stk/
|
486
486
|
include ServerMockHelper
|
487
487
|
def common_run_init(options = {})
|
@@ -535,6 +535,7 @@ describe Oddb2xml::Builder do
|
|
535
535
|
|
536
536
|
it 'should validate XSD article' do
|
537
537
|
@inhalt = File.read(oddb_article_xml)
|
538
|
+
# This fails on Ruby < 2.4 as NAROPIN INJ LÖS 0.2 % 10 is wrongly encoded
|
538
539
|
expect(File.read(oddb_article_xml).scan(ARTICLE_NAROPIN).size).to eq 1
|
539
540
|
end
|
540
541
|
|
@@ -702,6 +703,7 @@ describe Oddb2xml::Builder do
|
|
702
703
|
check_elements(oddb_article_xml, ARTICLE_COMMON_ELEMENTS)
|
703
704
|
check_elements(oddb_article_xml, ARTICLE_ZURROSE_ELEMENTS)
|
704
705
|
it 'should contain NAROPIN' do
|
706
|
+
# This fails on Ruby < 2.4 as NAROPIN INJ LÖS 0.2 % 10 is wrongly encoded
|
705
707
|
expect(File.read(oddb_article_xml).scan(ARTICLE_NAROPIN).size).to eq 1
|
706
708
|
end
|
707
709
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'oddb2xml/semantic_check'
|
5
|
+
|
6
|
+
describe Oddb2xml::SemanticCheck do
|
7
|
+
CheckDir = File.expand_path(File.join(File.dirname(__FILE__), 'data', 'check_artikelstamm'))
|
8
|
+
|
9
|
+
def common_run_init(options = {})
|
10
|
+
@savedDir = Dir.pwd
|
11
|
+
cleanup_directories_before_run
|
12
|
+
FileUtils.makedirs(Oddb2xml::WorkDir)
|
13
|
+
Dir.chdir(Oddb2xml::WorkDir)
|
14
|
+
mock_downloads
|
15
|
+
end
|
16
|
+
|
17
|
+
after(:all) do
|
18
|
+
Dir.chdir @savedDir if @savedDir and File.directory?(@savedDir)
|
19
|
+
end
|
20
|
+
context 'checking' do
|
21
|
+
before(:each) do
|
22
|
+
common_run_init
|
23
|
+
end
|
24
|
+
|
25
|
+
files2check = Dir.glob(CheckDir + '/*.xml')
|
26
|
+
|
27
|
+
files2check.each do |file2check|
|
28
|
+
it 'should exist' do
|
29
|
+
expect(File.exists?(file2check)).to eq true
|
30
|
+
end
|
31
|
+
|
32
|
+
it "#{File.basename(file2check)} should return okay" do
|
33
|
+
result = Oddb2xml::SemanticCheck.new(file2check).allSemanticChecks
|
34
|
+
puts "\n\nSemanticCheck: #{file2check} #{File.exist?(file2check)} returned #{result}"
|
35
|
+
puts "SemanticCheck: #{file2check} #{File.size(file2check)}"
|
36
|
+
# expect(result).to eq true
|
37
|
+
end if /okay/i.match(File.basename(file2check))
|
38
|
+
|
39
|
+
it "#{File.basename(file2check)} should return an error" do
|
40
|
+
result = Oddb2xml::SemanticCheck.new(file2check).allSemanticChecks
|
41
|
+
expect(result).to eq false
|
42
|
+
end unless /okay/i.match(File.basename(file2check))
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|