oddb2xml 2.6.9 → 2.7.4

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.
Files changed (51) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ruby.yml +40 -0
  3. data/.standard.yml +2 -0
  4. data/Elexis_Artikelstamm_v5.xsd +0 -3
  5. data/Gemfile +3 -3
  6. data/History.txt +28 -0
  7. data/README.md +3 -3
  8. data/Rakefile +24 -23
  9. data/bin/check_artikelstamm +11 -11
  10. data/bin/compare_v5 +23 -23
  11. data/bin/oddb2xml +14 -13
  12. data/lib/oddb2xml.rb +1 -1
  13. data/lib/oddb2xml/builder.rb +1075 -1048
  14. data/lib/oddb2xml/calc.rb +232 -233
  15. data/lib/oddb2xml/chapter_70_hack.rb +38 -32
  16. data/lib/oddb2xml/cli.rb +252 -235
  17. data/lib/oddb2xml/compare.rb +70 -59
  18. data/lib/oddb2xml/compositions_syntax.rb +448 -430
  19. data/lib/oddb2xml/compressor.rb +20 -20
  20. data/lib/oddb2xml/downloader.rb +156 -128
  21. data/lib/oddb2xml/extractor.rb +295 -302
  22. data/lib/oddb2xml/options.rb +34 -35
  23. data/lib/oddb2xml/parslet_compositions.rb +263 -269
  24. data/lib/oddb2xml/semantic_check.rb +39 -33
  25. data/lib/oddb2xml/util.rb +166 -164
  26. data/lib/oddb2xml/version.rb +1 -1
  27. data/lib/oddb2xml/xml_definitions.rb +32 -33
  28. data/oddb2xml.gemspec +32 -31
  29. data/spec/artikelstamm_spec.rb +116 -135
  30. data/spec/builder_spec.rb +495 -524
  31. data/spec/calc_spec.rb +552 -593
  32. data/spec/check_artikelstamm_spec.rb +26 -26
  33. data/spec/cli_spec.rb +173 -174
  34. data/spec/compare_spec.rb +9 -11
  35. data/spec/composition_syntax_spec.rb +390 -409
  36. data/spec/compressor_spec.rb +48 -48
  37. data/spec/data/refdata_NonPharma.xml +0 -3
  38. data/spec/data/refdata_Pharma.xml +0 -26
  39. data/spec/data/transfer.dat +1 -0
  40. data/spec/data/varia_De.htm +2 -2
  41. data/spec/data_helper.rb +47 -49
  42. data/spec/downloader_spec.rb +251 -260
  43. data/spec/extractor_spec.rb +172 -164
  44. data/spec/galenic_spec.rb +233 -256
  45. data/spec/options_spec.rb +116 -119
  46. data/spec/parslet_spec.rb +833 -861
  47. data/spec/spec_helper.rb +153 -153
  48. data/test_options.rb +39 -42
  49. data/tools/win_fetch_cacerts.rb +2 -3
  50. metadata +48 -5
  51. data/.travis.yml +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 57997dab6b06c6ad0aa8bff72b8fb5050f025255
4
- data.tar.gz: 57b14760b0448b1cc5a24b4fd7f5f313f3257a19
2
+ SHA256:
3
+ metadata.gz: af1cbeb37bf057e98955776c87dd5092fc5706af18d00ba818efccd2c52a076e
4
+ data.tar.gz: 1f4faf8f73b2cffa14bd3dda23dad4e401b524587c0f95d80e0cc9cbd4ba5d2b
5
5
  SHA512:
6
- metadata.gz: 4b2e2bd8a4ffa584e74422da0c77cf9755c48908bc3c82210a71848109704a59a918bda7092ba3c056dc9e1423317b8ceb94b715639d08e19ecd8b9e95db4e7c
7
- data.tar.gz: c277c5c81259a52031f97ce7b346c80e124385efc128f549c97ed4e7f26ab739316ab7dae1b1315842c310c4028dae2db0d1a372a44ea429e3e70382c0acdd4f
6
+ metadata.gz: ace048c855b3711fd6b75692373318fe992a5c6529d322c13b516a7bd09390e36efec3f14edaa91ddeb223438d74c97c15ba4691077e9c77ce5063a10bdcc423
7
+ data.tar.gz: 9dcf787039edc02a56b7301f6849e76259628ac55da598a2878e4a08c63fd3c3aaef35bfea6bda8184c6e3552314fba7bb028962d81151ca98bf76f830c3303f
@@ -0,0 +1,40 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ master ]
13
+ pull_request:
14
+ branches: [ master ]
15
+
16
+ jobs:
17
+ test:
18
+ runs-on: ubuntu-latest
19
+ # Using a matrix fails, because /setup-ruby always invokes bundle install without any additional args
20
+ # Fixed by adding not defining the debugger group in the Gemfile
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ os: [ ubuntu]
25
+ ruby: [2.5, 2.6, 2.7, 3.0, head]
26
+ continue-on-error: ${{ endsWith(matrix.ruby, 'head') }}
27
+ steps:
28
+ - uses: actions/checkout@v2
29
+ - uses: ruby/setup-ruby@v1
30
+ with:
31
+ ruby-version: ${{ matrix.ruby }}
32
+ bundler-cache: true
33
+
34
+ - name: Install dependencies
35
+ run: |
36
+ bundle config set path .bundle/gems --local
37
+ bundle config set without debugger --local
38
+ bundle install
39
+ - name: Test with RSpec
40
+ run: bundle exec rspec
data/.standard.yml ADDED
@@ -0,0 +1,2 @@
1
+ ignore: # default: []
2
+ - 'vendor/**/*'
@@ -431,9 +431,6 @@
431
431
  </xs:documentation>
432
432
  </xs:annotation>
433
433
  </xs:element>
434
- <xs:element name="Chapter70_HACK"
435
- type="xs:string" minOccurs="0" maxOccurs="1">
436
- </xs:element>
437
434
  </xs:sequence>
438
435
 
439
436
 
data/Gemfile CHANGED
@@ -1,8 +1,8 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
5
  group :debugger do
6
- gem 'pry-byebug'
7
- gem 'pry-doc'
6
+ gem "pry-byebug"
7
+ gem "pry-doc"
8
8
  end
data/History.txt CHANGED
@@ -1,3 +1,31 @@
1
+ === 2.7.4 / 30.03.2021
2
+ * Update needed Ruby-Version to 2.5.0 in gemspec
3
+ * Ensure downloads directory is created at first run
4
+
5
+ === 2.7.3 / 29.03.2021
6
+ * Do not delete swissmedic_package.xlsx and swissmedic_orphan.xlsx
7
+ * Save swissmedic_package.xlsx and swissmedic_orphan.xlsx under downloads
8
+ * Log removing files
9
+
10
+ === 2.7.2 / 18.03.2021
11
+ * Added https://github.com/testdouble/standard and fixed all useful warnings
12
+ * Added standard to rake tasks
13
+ * Use ATC-code from refdata if available and show differences
14
+ * Get pharmacode from tranfer.dat for artikelstamm if possible
15
+ * We do not longer test Ruby 2.4 with github/actions
16
+ * Update build status to use github/actions instead of travis
17
+
18
+ === 2.7.1 / 03.02.2021
19
+ * travis-ci -> Github Actions
20
+ * limit DSCRD/DSCRF to 120 chars as specified in the XSD
21
+ * Use huge option for nokogiri as suggested by https://github.com/sparklemotion/nokogiri/issues/2187
22
+ * Adapt artikelstamm to refdata without pharmacode
23
+ * oddb_article get pharmacode where possible from transfer.dat
24
+
25
+ === 2.7.0 / 05.11.2020
26
+ * Chapter70 hack nur als Kommentar
27
+ * Avoid double hyphen in comment
28
+
1
29
  === 2.6.9 / 29.06.2020
2
30
 
3
31
  * Fix problem when running bin/oddb2xml -a -f dat. Thanks to Lukas Furre for reporting the problem
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # oddb2xml
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/zdavatz/oddb2xml.png)](http://travis-ci.org/zdavatz/oddb2xml)
3
+ [![Build Status](https://github.com/zdavatz/oddb2xml/workflows/Ruby/badge.svg)](https://github.com/zdavatz/oddb2xml/actions)
4
4
 
5
5
  * oddb2xml -a nonpharma -o fi
6
6
 
@@ -106,8 +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. 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
109
+ We run tests on travis-ci.org for the Ruby versions mentioned in the .travis.yml file. You will need ruby > 2.5 to work correctly.
110
+ Look at the github actions to see the spec test results. We ignore errors against ruby head, as it is sometimes unstable.
111
111
 
112
112
 
113
113
  ## XSD files
data/Rakefile CHANGED
@@ -1,25 +1,26 @@
1
1
  #!/usr/bin/env ruby
2
- # encoding: utf-8
3
- lib = File.expand_path('../lib', __FILE__)
2
+
3
+ lib = File.expand_path("../lib", __FILE__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'oddb2xml/version'
5
+ require "oddb2xml/version"
6
6
  require "bundler/gem_tasks"
7
- require 'rspec/core/rake_task'
7
+ require "standard/rake"
8
+ require "rspec/core/rake_task"
8
9
 
9
10
  RSpec::Core::RakeTask.new(:spec)
10
11
 
11
12
  # dependencies are now declared in oddb2xml.gemspec
12
13
 
13
- desc 'Offer a gem task like hoe'
14
- task :gem => :build do
14
+ desc "Offer a gem task like hoe"
15
+ task gem: :build do
15
16
  Rake::Task[:build].invoke
16
17
  end
17
18
 
18
- task :spec => :clean
19
+ task spec: :clean
19
20
 
20
- desc 'Run oddb2xml with all commonly used combinations'
21
- task :test => [:clean, :spec, :gem] do
22
- log_file = 'test_options.log'
21
+ desc "Run oddb2xml with all commonly used combinations"
22
+ task test: [:clean, :spec, :gem] do
23
+ log_file = "test_options.log"
23
24
  puts "Running test_options.rb with Output redirected to #{log_file}. This will take some time (e.g. 20 minutes)"
24
25
  # must use bash -o pipefail to catch error in test_options.rb and not tee
25
26
  # see http://stackoverflow.com/questions/985876/tee-and-exit-status
@@ -28,16 +29,16 @@ task :test => [:clean, :spec, :gem] do
28
29
  exit 1 unless res
29
30
  end
30
31
 
31
- require 'rake/clean'
32
- CLEAN.include FileList['pkg/*.gem']
33
- CLEAN.include FileList['*.zip*']
34
- CLEAN.include FileList['*.xls*']
35
- CLEAN.include FileList['*.xml*']
36
- CLEAN.include FileList['*.dat*']
37
- CLEAN.include FileList['*.tar.gz']
38
- CLEAN.include FileList['*.txt.*']
39
- CLEAN.include FileList['*.csv.*']
40
- CLEAN.include FileList['*.zip.*']
41
- CLEAN.include FileList['ruby*.tmp']
42
- CLEAN.include FileList['data/download']
43
- CLEAN.include FileList['duplicate_ean13_from_zur_rose.txt']
32
+ require "rake/clean"
33
+ CLEAN.include FileList["pkg/*.gem"]
34
+ CLEAN.include FileList["*.zip*"]
35
+ CLEAN.include FileList["*.xls*"]
36
+ CLEAN.include FileList["*.xml*"]
37
+ CLEAN.include FileList["*.dat*"]
38
+ CLEAN.include FileList["*.tar.gz"]
39
+ CLEAN.include FileList["*.txt.*"]
40
+ CLEAN.include FileList["*.csv.*"]
41
+ CLEAN.include FileList["*.zip.*"]
42
+ CLEAN.include FileList["ruby*.tmp"]
43
+ CLEAN.include FileList["data/download"]
44
+ CLEAN.include FileList["duplicate_ean13_from_zur_rose.txt"]
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env ruby
2
- require 'pathname'
2
+ require "pathname"
3
3
 
4
4
  root = Pathname.new(__FILE__).realpath.parent.parent
5
- $:.unshift root.join('lib') if $0 == __FILE__
5
+ $:.unshift root.join("lib") if $0 == __FILE__
6
6
 
7
- require 'oddb2xml/version'
8
- require 'oddb2xml/semantic_check'
9
- require 'optimist'
7
+ require "oddb2xml/version"
8
+ require "oddb2xml/semantic_check"
9
+ require "optimist"
10
10
 
11
- @opts = Optimist::options(ARGV) do
12
- version "#$0 ver.#{Oddb2xml::VERSION}"
11
+ @opts = Optimist.options(ARGV) do
12
+ version "#{$0} ver.#{Oddb2xml::VERSION}"
13
13
  banner <<-EOS
14
14
  Runs various semanti_check for the Elexis artikelstamm
15
15
  Usage:
16
16
  #{File.basename(__FILE__)} xml_file_to_check
17
- EOS
17
+ EOS
18
18
  end
19
19
  $stdout.sync = true
20
20
 
@@ -24,7 +24,7 @@ if args.size != 1
24
24
  exit 2
25
25
  end
26
26
 
27
- startTime = Time.now
28
- result = Oddb2xml::SemanticCheck.new(ARGV.first).allSemanticChecks
29
- diff = (Time.now-startTime).to_i
27
+ start_time = Time.now
28
+ Oddb2xml::SemanticCheck.new(ARGV.first).allSemanticChecks
29
+ diff = (Time.now - start_time).to_i
30
30
  puts "#{Time.now.strftime("%H:%M:%S")}: #{__FILE__} done. Took #{diff} seconds"
data/bin/compare_v5 CHANGED
@@ -1,31 +1,31 @@
1
1
  #!/usr/bin/env ruby
2
- require 'pathname'
2
+ require "pathname"
3
3
 
4
4
  root = Pathname.new(__FILE__).realpath.parent.parent
5
- $:.unshift root.join('lib') if $0 == __FILE__
5
+ $:.unshift root.join("lib") if $0 == __FILE__
6
6
 
7
- require 'oddb2xml/version'
8
- require 'oddb2xml/compare'
9
- require 'optimist'
10
- DEFAULTSx = {
11
- :components => ["PRODUCTS", "LIMITATIONS", "ITEMS",],
12
- :fields_to_ignore => ['COMP', 'DOSAGE_FORMF', 'MEASUREF'],
13
- :fields_as_floats => [ 'PEXT', 'PEXF', 'PPUB' ],
14
- :min_diff_for_floats => 0.01,
15
- :case_insensitive => true,
16
- }
7
+ require "oddb2xml/version"
8
+ require "oddb2xml/compare"
9
+ require "optimist"
10
+ DEFAULTS_X = {
11
+ components: ["PRODUCTS", "LIMITATIONS", "ITEMS"],
12
+ fields_to_ignore: ["COMP", "DOSAGE_FORMF", "MEASUREF"],
13
+ fields_as_floats: ["PEXT", "PEXF", "PPUB"],
14
+ min_diff_for_floats: 0.01,
15
+ case_insensitive: true
16
+ }
17
17
 
18
- @opts = Optimist::options(ARGV) do
19
- version "#$0 ver.#{Oddb2xml::VERSION}"
18
+ @opts = Optimist.options(ARGV) do
19
+ version "#{$0} ver.#{Oddb2xml::VERSION}"
20
20
  banner <<-EOS
21
21
  Usage:
22
22
  compare_v5 [option] first_v5_xml second_v5_xml
23
- EOS
24
- opt :components, "components to compare", :default => Oddb2xml::CompareV5::DEFAULTS[:components]
25
- opt :fields_as_floats, "Fields that should be compared as floats", :default => Oddb2xml::CompareV5::DEFAULTS[:fields_as_floats]
26
- opt :fields_to_ignore, "Ignore these fields", :default => Oddb2xml::CompareV5::DEFAULTS[:fields_to_ignore]
27
- opt :min_diff_for_floats, "Minimal difference when comparing floats", :default => Oddb2xml::CompareV5::DEFAULTS[:min_diff_for_floats]
28
- opt :case_insensitive, "case_insensitive comparison", :default => Oddb2xml::CompareV5::DEFAULTS[:case_insensitive]
23
+ EOS
24
+ opt :components, "components to compare", default: Oddb2xml::CompareV5::DEFAULTS[:components]
25
+ opt :fields_as_floats, "Fields that should be compared as floats", default: Oddb2xml::CompareV5::DEFAULTS[:fields_as_floats]
26
+ opt :fields_to_ignore, "Ignore these fields", default: Oddb2xml::CompareV5::DEFAULTS[:fields_to_ignore]
27
+ opt :min_diff_for_floats, "Minimal difference when comparing floats", default: Oddb2xml::CompareV5::DEFAULTS[:min_diff_for_floats]
28
+ opt :case_insensitive, "case_insensitive comparison", default: Oddb2xml::CompareV5::DEFAULTS[:case_insensitive]
29
29
  end
30
30
  $stdout.sync = false
31
31
 
@@ -35,7 +35,7 @@ if args.size != 2
35
35
  exit 2
36
36
  end
37
37
 
38
- startTime = Time.now
39
- result = Oddb2xml::CompareV5.new(ARGV.first, ARGV.last, @opts).compare
40
- diff = (Time.now-startTime).to_i
38
+ start_time = Time.now
39
+ Oddb2xml::CompareV5.new(ARGV.first, ARGV.last, @opts).compare
40
+ diff = (Time.now - start_time).to_i
41
41
  puts "#{Time.now.strftime("%H:%M:%S")}: #{__FILE__} done. Took #{diff} seconds"
data/bin/oddb2xml CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'pathname'
3
+ require "pathname"
4
4
  root = Pathname.new(__FILE__).realpath.parent.parent
5
- $:.unshift root.join('lib') if $0 == __FILE__
5
+ $:.unshift root.join("lib") if $0 == __FILE__
6
6
 
7
- require 'mechanize'
8
- require 'oddb2xml'
9
- require 'oddb2xml/options'
7
+ require "mechanize"
8
+ require "oddb2xml"
9
+ require "oddb2xml/options"
10
10
  $stdout.sync = true
11
11
 
12
12
  opts = Oddb2xml::Options.parse(ARGV)
@@ -17,21 +17,21 @@ if args.size > 0
17
17
  exit 2
18
18
  end
19
19
  # TEMP
20
- if path = args.first
20
+ if (path = args.first)
21
21
  opts[:transfer_dat] = path
22
22
  end
23
23
 
24
- startTime = Time.now
24
+ start_time = Time.now
25
25
  ui = Oddb2xml::Cli.new(opts)
26
26
  begin
27
27
  if opts[:format] == :xml
28
28
  opts[:ean14] = true # force
29
29
  end
30
- #puts opts if opts[:debug]
30
+ # puts opts if opts[:debug]
31
31
  if RUBY_VERSION.to_f < 1.9
32
- message = <<-MES
33
- Once you find some time, please upgrade your Ruby to 1.9.3 ;)
34
- then you will not see anymore warnings
32
+ message = <<~MES
33
+ Once you find some time, please upgrade your Ruby to 1.9.3 ;)
34
+ then you will not see anymore warnings
35
35
  MES
36
36
  warn message
37
37
  end
@@ -39,5 +39,6 @@ then you will not see anymore warnings
39
39
  rescue Interrupt
40
40
  exit
41
41
  end
42
- diff = (Time.now-startTime).to_i
43
- puts "#{Time.now}: #{__LINE__} done. Took #{diff} seconds"; $stdout.sync
42
+ diff = (Time.now - start_time).to_i
43
+ puts "#{Time.now}: #{__LINE__} done. Took #{diff} seconds"
44
+ $stdout.sync
data/lib/oddb2xml.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require "oddb2xml/version"
2
- require 'oddb2xml/cli'
2
+ require "oddb2xml/cli"
3
3
 
4
4
  module Oddb2xml
5
5
  end
@@ -1,21 +1,22 @@
1
- # encoding: utf-8
2
- require 'nokogiri'
3
- require 'oddb2xml/util'
4
- require 'oddb2xml/calc'
5
- require 'csv'
1
+ require "nokogiri"
2
+ require "oddb2xml/util"
3
+ require "oddb2xml/calc"
4
+ require "csv"
5
+
6
6
  class Numeric
7
7
  # round a given number to the nearest step
8
8
  def round_by(increment)
9
9
  (self / increment).round * increment
10
10
  end
11
11
  end
12
+
12
13
  module Nokogiri
13
14
  module XML
14
15
  class Document < Nokogiri::XML::Node
15
16
  attr_writer :tag_suffix
16
- alias :create_element_origin :create_element
17
+ alias_method :create_element_origin, :create_element
17
18
  def create_element name, *args, &block
18
- name += (@tag_suffix || '')
19
+ name += (@tag_suffix || "")
19
20
  create_element_origin(name, *args, &block)
20
21
  end
21
22
  end
@@ -24,108 +25,116 @@ end
24
25
 
25
26
  module Oddb2xml
26
27
  XML_OPTIONS = {
27
- 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
28
- 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
29
- 'xmlns' => 'http://wiki.oddb.org/wiki.php?pagename=Swissmedic.Datendeklaration',
30
- 'CREATION_DATETIME' => Time.new.strftime('%FT%T%z'),
31
- 'PROD_DATE' => Time.new.strftime('%FT%T%z'),
32
- 'VALID_DATE' => Time.new.strftime('%FT%T%z'),
33
- 'GENERATED_BY' => "oddb2xml #{VERSION}"
28
+ "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
29
+ "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
30
+ "xmlns" => "http://wiki.oddb.org/wiki.php?pagename=Swissmedic.Datendeklaration",
31
+ "CREATION_DATETIME" => Time.new.strftime("%FT%T%z"),
32
+ "PROD_DATE" => Time.new.strftime("%FT%T%z"),
33
+ "VALID_DATE" => Time.new.strftime("%FT%T%z"),
34
+ "GENERATED_BY" => "oddb2xml #{VERSION}"
34
35
  }
35
36
  class Builder
36
- Data_dir = File.expand_path(File.join(File.dirname(__FILE__),'..','..', 'data'))
37
- @@article_overrides = YAML.load_file(File.join(Data_dir, 'article_overrides.yaml'))
38
- @@product_overrides = YAML.load_file(File.join(Data_dir, 'product_overrides.yaml'))
39
- @@ignore_file = File.join(Data_dir, 'gtin2ignore.yaml')
40
- @@gtin2ignore = YAML.load_file(@@ignore_file) if File.exist?(@@ignore_file)
37
+ Data_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "data"))
38
+ @@article_overrides = YAML.load_file(File.join(Data_dir, "article_overrides.yaml"))
39
+ @@product_overrides = YAML.load_file(File.join(Data_dir, "product_overrides.yaml"))
40
+ @@ignore_file = File.join(Data_dir, "gtin2ignore.yaml")
41
+ @@gtin2ignore = YAML.load_file(@@ignore_file) if File.exist?(@@ignore_file)
41
42
  @@gtin2ignore ||= []
42
43
  attr_accessor :subject, :refdata, :items, :flags, :lppvs,
43
- :actions, :migel, :orphan,
44
- :infos, :packs, :infos_zur_rose,
45
- :ean14, :tag_suffix,
46
- :companies, :people,
47
- :xsd
44
+ :actions, :migel, :orphan,
45
+ :infos, :packs, :infos_zur_rose,
46
+ :ean14, :tag_suffix,
47
+ :companies, :people,
48
+ :xsd
48
49
  def initialize(args = {})
49
- @options = args
50
- @subject = nil
51
- @refdata = {}
52
- @items = {} # Spezailitäteniste: SL-Items from Preparations.xml in BAG, using GTINS as key
53
- @flags = {}
54
- @lppvs = {}
55
- @infos = {}
56
- @packs = {}
57
- @migel = {}
58
- @infos_zur_rose ||= {}
59
- @actions = []
60
- @orphan = []
61
- @ean14 = false
62
- @companies = []
63
- @people = []
50
+ @options = args
51
+ @subject = nil
52
+ @refdata = {}
53
+ @items = {} # Spezailitäteniste: SL-Items from Preparations.xml in BAG, using GTINS as key
54
+ @flags = {}
55
+ @lppvs = {}
56
+ @infos = {}
57
+ @packs = {}
58
+ @migel = {}
59
+ @infos_zur_rose ||= {}
60
+ @actions = []
61
+ @orphan = []
62
+ @ean14 = false
63
+ @companies = []
64
+ @people = []
64
65
  @tag_suffix = nil
65
66
  @pharmacode = {} # index pharmacode => item
66
67
  if block_given?
67
68
  yield self
68
69
  end
69
70
  end
70
- def to_xml(subject=nil)
71
+
72
+ def to_xml(subject = nil)
71
73
  Oddb2xml.log "to_xml subject #{subject || @subject}"
72
74
  if subject
73
- self.send('build_' + subject.to_s)
75
+ send("build_" + subject.to_s)
74
76
  elsif @subject
75
- self.send('build_' + @subject.to_s)
77
+ send("build_" + @subject.to_s)
76
78
  end
77
79
  end
78
- def to_dat(subject=nil)
79
- Oddb2xml.log "to_dat subject #{subject ? subject.to_s : @subject.to_s} for #{self.class}"
80
+
81
+ def to_dat(subject = nil)
82
+ Oddb2xml.log "to_dat subject #{subject ? subject.to_s : @subject.to_s} for #{self.class}"
80
83
  if subject
81
- self.send('build_' + subject.to_s)
84
+ send("build_" + subject.to_s)
82
85
  elsif @subject
83
- self.send('build_' + @subject.to_s)
86
+ send("build_" + @subject.to_s)
84
87
  end
85
88
  end
86
- private
87
- def prepare_articles(reset=false)
89
+
90
+ private_class_method
91
+
92
+ def prepare_articles(reset = false)
88
93
  @articles = nil if reset
89
94
  unless @articles
90
- Oddb2xml.log("prepare_articles starting with #{@articles ? @articles.size : 'no'} articles.")
95
+ Oddb2xml.log("prepare_articles starting with #{@articles ? @articles.size : "no"} articles.")
91
96
  @articles = []
92
97
  @refdata.each do |ean13, obj|
93
- if migel = @migel[ean13]
94
- # delete duplicates
95
- @migel[ean13] = nil
96
- end unless SkipMigelDownloader
97
- if seq = @items[obj[:ean13]]
98
+ unless SKIP_MIGEL_DOWNLOADER
99
+ if @migel[ean13]
100
+ # delete duplicates
101
+ @migel[ean13] = nil
102
+ end
103
+ end
104
+ if (seq = @items[obj[:ean13]])
98
105
  obj[:seq] = seq.clone
99
106
  end
100
107
  @articles << obj
101
108
  @pharmacode[obj[:pharmacode]] = obj
102
109
  end
103
110
  # add
104
- @migel.values.compact.each do |migel|
105
- next unless migel[:pharmacode]
106
- entry = {
107
- :ean13 => migel[:ean13],
108
- :pharmacode => migel[:pharmacode],
109
- :stat_date => '',
110
- :desc_de => migel[:desc_de],
111
- :desc_fr => migel[:desc_fr],
112
- :atc_code => '',
113
- :quantity => migel[:quantity],
114
- :company_ean => migel[:company_ean],
115
- :company_name => migel[:company_name],
116
- :migel => true,
111
+ unless SKIP_MIGEL_DOWNLOADER
112
+ @migel.values.compact.each do |migel|
113
+ next unless migel[:pharmacode]
114
+ entry = {
115
+ ean13: migel[:ean13],
116
+ pharmacode: migel[:pharmacode],
117
+ stat_date: "",
118
+ desc_de: migel[:desc_de],
119
+ desc_fr: migel[:desc_fr],
120
+ atc_code: "",
121
+ quantity: migel[:quantity],
122
+ company_ean: migel[:company_ean],
123
+ company_name: migel[:company_name],
124
+ migel: true
117
125
  }
118
- @articles << entry
119
- end unless SkipMigelDownloader
120
- nrAdded = 0
126
+ @articles << entry
127
+ end
128
+ end
129
+ nr_added = 0
121
130
  if @options[:extended] || @options[:artikelstamm]
122
131
  Oddb2xml.log("prepare_articles extended prepare_local_index having already #{@articles.size} articles")
123
- nrItems = 0
132
+ nr_items = 0
124
133
  @infos_zur_rose.each do |ean13, info|
125
- nrItems += 1
134
+ nr_items += 1
126
135
  pharmacode = info[:pharmacode]
127
136
  if @pharmacode[pharmacode]
128
- @pharmacode[pharmacode][:price] = info[:price]
137
+ @pharmacode[pharmacode][:price] = info[:price]
129
138
  @pharmacode[pharmacode][:pub_price] = info[:pub_price]
130
139
  next
131
140
  end
@@ -134,20 +143,20 @@ module Oddb2xml
134
143
  existing = @refdata[ean13]
135
144
  if existing
136
145
  found = true
137
- existing[:price] = info[:price]
146
+ existing[:price] = info[:price]
138
147
  existing[:pub_price] = info[:pub_price]
139
148
  else
140
149
  entry = {
141
- :desc => info[:description],
142
- :desc_de => info[:description],
143
- :status => info[:status] == '3' ? 'I' : 'A', # from ZurRose, we got 1,2 or 3 means aktive, aka available in trade
144
- :atc_code => '',
145
- :ean13 => ean13,
146
- :pharmacode => pharmacode,
147
- :price => info[:price],
148
- :pub_price => info[:pub_price],
149
- :type => info[:type],
150
- }
150
+ desc: info[:description],
151
+ desc_de: info[:description],
152
+ status: info[:status] == "3" ? "I" : "A", # from ZurRose, we got 1,2 or 3 means aktive, aka available in trade
153
+ atc_code: "",
154
+ ean13: ean13,
155
+ pharmacode: pharmacode,
156
+ price: info[:price],
157
+ pub_price: info[:pub_price],
158
+ type: info[:type]
159
+ }
151
160
  if pharmacode
152
161
  @refdata[pharmacode] = entry
153
162
  else
@@ -155,15 +164,16 @@ module Oddb2xml
155
164
  end
156
165
  obj = entry
157
166
  end
158
- if not found and obj.size > 0
167
+ if !found && (obj.size > 0)
159
168
  @articles << obj unless @options[:artikelstamm]
160
- nrAdded += 1
169
+ nr_added += 1
161
170
  end
162
171
  end
163
172
  end
164
173
  end
165
- Oddb2xml.log("prepare_articles done. Added #{nrAdded} prices. Total #{@articles.size}")
174
+ Oddb2xml.log("prepare_articles done. Added #{nr_added} prices. Total #{@articles.size}")
166
175
  end
176
+
167
177
  def prepare_substances
168
178
  unless @substances
169
179
  Oddb2xml.log("prepare_substances from #{@items.size} items")
@@ -177,9 +187,10 @@ module Oddb2xml
177
187
  @substances.uniq!
178
188
  @substances.sort!
179
189
  Oddb2xml.log("prepare_substances done. Total #{@substances.size} from #{@items.size} items")
180
- exit 2 if (@options[:extended] || @options[:artikelstamm]) and @substances.size == 0
190
+ exit 2 if (@options[:extended] || @options[:artikelstamm]) && (@substances.size == 0)
181
191
  end
182
192
  end
193
+
183
194
  def prepare_limitations
184
195
  unless @limitations
185
196
  Oddb2xml.log("prepare_limitations from #{@items.size} items")
@@ -193,10 +204,11 @@ module Oddb2xml
193
204
  # ID is no longer fixed TAG (swissmedicNo8, swissmedicNo5, pharmacode)
194
205
  # limitation.xml needs all duplicate entries by this keys.
195
206
  limitations.uniq! { |lim| lim[:id].to_s + lim[:code] + lim[:type] }
196
- @limitations = limitations.sort_by {|lim| lim[:code] }
207
+ @limitations = limitations.sort_by { |lim| lim[:code] }
197
208
  Oddb2xml.log("prepare_limitations done. Total #{@limitations.size} from #{@items.size} items")
198
209
  end
199
210
  end
211
+
200
212
  def prepare_interactions
201
213
  unless @interactions
202
214
  @interactions = []
@@ -205,60 +217,61 @@ module Oddb2xml
205
217
  end
206
218
  end
207
219
  end
220
+
208
221
  def prepare_codes
209
- unless @codes
210
- @codes = {
211
- 'X' => {:int => 11, :txt => 'Kontraindiziert'},
212
- 'D' => {:int => 13, :txt => 'Kombination meiden'},
213
- 'C' => {:int => 14, :txt => 'Monitorisieren'},
214
- 'B' => {:int => 15, :txt => 'Vorsichtsmassnahmen'},
215
- 'A' => {:int => 16, :txt => 'keine Massnahmen'}
216
- }
217
- end
222
+ @codes ||= {
223
+ "X" => {int: 11, txt: "Kontraindiziert"},
224
+ "D" => {int: 13, txt: "Kombination meiden"},
225
+ "C" => {int: 14, txt: "Monitorisieren"},
226
+ "B" => {int: 15, txt: "Vorsichtsmassnahmen"},
227
+ "A" => {int: 16, txt: "keine Massnahmen"}
228
+ }
218
229
  end
230
+
219
231
  def prepare_products
220
232
  unless @products
221
233
  @products = {}
222
234
  if @chapter70items
223
235
  Chapter70xtractor::LIMITATIONS.each do |key, desc_de|
224
236
  puts "Chapter70: Adding lim #{key} #{desc_de}" if $VERBOSE
225
- @limitations<< {:code => key,
226
- :id => ( key.eql?('L') ? '70.02' :'70.01'),
227
- :desc_de => desc_de,
228
- :desc_fr => '',
229
- :chap70 => true,
230
- }
237
+ @limitations << {code: key,
238
+ id: (key.eql?("L") ? "70.02" : "70.01"),
239
+ desc_de: desc_de,
240
+ desc_fr: "",
241
+ chap70: true}
231
242
  end
232
243
  @chapter70items.values.each do |item|
233
244
  next unless item[:limitation] && item[:limitation].length > 0
234
- rose = @infos_zur_rose.values.find {|x| x[:pharmacode] && x[:pharmacode].eql?(item[:pharmacode])}
235
- ean13 = rose[:ean13] if rose
236
- ean13 ||= '9999'+item[:pharmacode]
245
+ rose = @infos_zur_rose.values.find { |x| x[:pharmacode]&.eql?(item[:pharmacode]) }
246
+ ean13 = rose[:ean13] if rose
247
+ ean13 ||= "9999" + item[:pharmacode]
237
248
  prodno = item[:pharmacode]
238
249
  obj = {
239
- :chapter70 => true,
240
- :ean13 => ean13,
241
- :description => item[:description],
242
- :code => item[:limitation], # LIMNAMEBAG
250
+ chapter70: true,
251
+ ean13: ean13,
252
+ description: item[:description],
253
+ code: item[:limitation] # LIMNAMEBAG
243
254
  }
244
255
  @products[prodno] = obj
245
256
  puts "Chapter70: Adding product #{ean13} #{obj}" if $VERBOSE
246
257
  end
247
258
  end
248
259
  @refdata.each_pair do |ean13, item|
249
- next if item and item.is_a?(Hash) and item[:atc_code] and /^Q/i.match(item[:atc_code])
250
- next if item[:prodno] and @products[item[:prodno]]
260
+ next if item&.is_a?(Hash) && item[:atc_code] && /^Q/i.match(item[:atc_code])
261
+ next if item[:prodno] && @products[item[:prodno]]
262
+ refdata_atc = item[:atc_code]
251
263
  obj = {
252
- :seq => @items[ean13] ? @items[ean13] : @items[item[:ean13]],
253
- :pac => nil,
254
- :no8 => nil,
255
- :ean13 => item[:ean13],
256
- :atc => item[:atc_code],
257
- :ith => '',
258
- :siz => '',
259
- :eht => '',
260
- :sub => '',
261
- :comp => '',
264
+ seq: @items[ean13] || @items[item[:ean13]],
265
+ pac: nil,
266
+ no8: nil,
267
+ ean13: item[:ean13],
268
+ atc: refdata_atc,
269
+ ith: "",
270
+ siz: "",
271
+ eht: "",
272
+ sub: "",
273
+ comp: "",
274
+ data_origin: "refdata-product"
262
275
  }
263
276
  # obj[:pexf_refdata] = item[:price]
264
277
  # obj[:ppub_refdata] = item[:pub_price=]
@@ -266,6 +279,15 @@ module Oddb2xml
266
279
  if obj[:ean13] # via EAN-Code
267
280
  obj[:no8] = obj[:ean13].to_s[4..11]
268
281
  end
282
+ swissmedic_pack = @packs[item[:no8]]
283
+ if swissmedic_pack
284
+ swissmedic_atc = swissmedic_pack[:atc_code]
285
+ if swissmedic_atc && swissmedic_atc.length >= 3 && (refdata_atc.nil? || !refdata_atc.eql?(swissmedic_atc))
286
+ puts "WARNING: #{ean13} ATC-code #{swissmedic_atc} from swissmedic overrides #{refdata_atc} one from refdata #{item[:desc_de]}"
287
+ item[:data_origin] += "-swissmedic-ATC"
288
+ item[:atc] = swissmedic_atc
289
+ end
290
+ end
269
291
  if obj[:no8] && (ppac = @packs[obj[:no8]]) && # Packungen.xls
270
292
  !ppac[:is_tier]
271
293
  # If RefData does not have EAN
@@ -273,7 +295,7 @@ module Oddb2xml
273
295
  obj[:ean13] = ppac[:ean13]
274
296
  end
275
297
  # If RefData dose not have ATC-Code
276
- if obj[:atc].nil? or obj[:atc].empty?
298
+ if obj[:atc].nil? || obj[:atc].empty?
277
299
  obj[:atc] = ppac[:atc_code].to_s
278
300
  end
279
301
  obj[:ith] = ppac[:ith_swissmedic]
@@ -285,7 +307,7 @@ module Oddb2xml
285
307
  obj[:price] = item[:price]
286
308
  obj[:pub_price] = item[:pub_price]
287
309
 
288
- if obj[:ean13].to_s[0..3] == '7680'
310
+ if obj[:ean13].to_s[0..3] == "7680"
289
311
  if item[:prodno]
290
312
  @products[item[:prodno]] = obj
291
313
  else
@@ -296,118 +318,118 @@ module Oddb2xml
296
318
  end
297
319
  @products
298
320
  end
321
+
299
322
  def build_substance
300
323
  prepare_substances
301
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
324
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
302
325
  xml.doc.tag_suffix = @tag_suffix
303
- datetime = Time.new.strftime('%FT%T%z')
304
326
  xml.SUBSTANCE(
305
327
  XML_OPTIONS
306
328
  ) {
307
329
  Oddb2xml.log "build_substance #{@substances.size} substances"
308
- exit 2 if (@options[:extended] || @options[:artikelstamm]) and @substances.size == 0
309
- nbr_records = 0
310
- @substances.each_with_index do |sub_name, i|
311
- xml.SB('DT' => '') do
330
+ exit 2 if (@options[:extended] || @options[:artikelstamm]) && (@substances.size == 0)
331
+ nbr_records = 0
332
+ @substances.each_with_index do |sub_name, i|
333
+ xml.SB("DT" => "") do
312
334
  xml.SUBNO((i + 1).to_i)
313
- #xml.NAMD
314
- #xml.ANAMD
315
- #xml.NAMF
335
+ # xml.NAMD
336
+ # xml.ANAMD
337
+ # xml.NAMF
316
338
  xml.NAML sub_name
317
339
  nbr_records += 1
318
340
  end
319
341
  end
320
342
  xml.RESULT {
321
- xml.OK_ERROR 'OK'
343
+ xml.OK_ERROR "OK"
322
344
  xml.NBR_RECORD nbr_records
323
- xml.ERROR_CODE ''
324
- xml.MESSAGE ''
345
+ xml.ERROR_CODE ""
346
+ xml.MESSAGE ""
325
347
  }
326
348
  }
327
349
  end
328
- Oddb2xml.add_hash(_builder.to_xml)
350
+ Oddb2xml.add_hash(a_builder.to_xml)
329
351
  end
352
+
330
353
  def build_limitation
331
354
  prepare_limitations
332
355
  Oddb2xml.log "build_limitation #{@limitations.size} limitations"
333
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
356
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
334
357
  xml.doc.tag_suffix = @tag_suffix
335
- datetime = Time.new.strftime('%FT%T%z')
336
358
  xml.LIMITATION(XML_OPTIONS) do
337
- nbr_records = 0
338
- @limitations.each do |lim|
339
- if lim[:id].empty?
340
- puts "Skipping empty id of #{lim}"
341
- next
342
- end
343
- xml.LIM('DT' => '') do
359
+ nbr_records = 0
360
+ @limitations.each do |lim|
361
+ if lim[:id].empty?
362
+ puts "Skipping empty id of #{lim}"
363
+ next
364
+ end
365
+ xml.LIM("DT" => "") do
344
366
  case lim[:key]
345
367
  when :swissmedic_number8
346
368
  xml.SwissmedicNo8 lim[:id]
347
369
  when :swissmedic_number5
348
370
  xml.SwissmedicNo5 lim[:id]
349
371
  when :pharmacode
350
- xml.Pharmacode lim[:id]
372
+ xml.Pharmacode lim[:id]
351
373
  end
352
- xml.IT lim[:it]
353
- xml.LIMTYP lim[:type]
354
- xml.LIMVAL lim[:value]
374
+ xml.IT lim[:it]
375
+ xml.LIMTYP lim[:type]
376
+ xml.LIMVAL lim[:value]
355
377
  xml.LIMNAMEBAG lim[:code] # original LIMCD
356
- xml.LIMNIV lim[:niv]
357
- xml.DSCRD lim[:desc_de]
358
- xml.DSCRF lim[:desc_fr]
359
- xml.VDAT lim[:vdate]
378
+ xml.LIMNIV lim[:niv]
379
+ xml.DSCRD lim[:desc_de]
380
+ xml.DSCRF lim[:desc_fr]
381
+ xml.VDAT lim[:vdate]
360
382
  nbr_records += 1
361
383
  end
362
384
  end
363
385
  xml.RESULT do
364
- xml.OK_ERROR 'OK'
386
+ xml.OK_ERROR "OK"
365
387
  xml.NBR_RECORD nbr_records
366
- xml.ERROR_CODE ''
367
- xml.MESSAGE ''
388
+ xml.ERROR_CODE ""
389
+ xml.MESSAGE ""
368
390
  end
369
391
  end
370
392
  end
371
- Oddb2xml.add_hash(_builder.to_xml)
393
+ Oddb2xml.add_hash(a_builder.to_xml)
372
394
  end
395
+
373
396
  def build_interaction
374
397
  prepare_interactions
375
398
  prepare_codes
376
399
  nbr_records = 0
377
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
400
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
378
401
  xml.doc.tag_suffix = @tag_suffix
379
- datetime = Time.new.strftime('%FT%T%z')
380
402
  xml.INTERACTION(XML_OPTIONS) {
381
403
  Oddb2xml.log "build_interaction #{@interactions.size} interactions"
382
- @interactions.sort_by{|ix| ix[:ixno] }.each do |ix|
383
- xml.IX('DT' => '') {
384
- xml.IXNO ix[:ixno]
385
- xml.TITD ix[:title]
386
- #xml.TITF
404
+ @interactions.sort_by { |ix| ix[:ixno] }.each do |ix|
405
+ xml.IX("DT" => "") {
406
+ xml.IXNO ix[:ixno]
407
+ xml.TITD ix[:title]
408
+ # xml.TITF
387
409
  xml.GRP1D ix[:atc1]
388
- #xml.GRP1F
410
+ # xml.GRP1F
389
411
  xml.GRP2D ix[:atc2]
390
- #xml.GRP2F
391
- xml.EFFD ix[:effect]
392
- #xml.EFFF
393
- if @codes and ix[:grad]
394
- if dict = @codes[ix[:grad].upcase]
395
- xml.RLV dict[:int]
412
+ # xml.GRP2F
413
+ xml.EFFD ix[:effect]
414
+ # xml.EFFF
415
+ if @codes && ix[:grad]
416
+ if (dict = @codes[ix[:grad].upcase])
417
+ xml.RLV dict[:int]
396
418
  xml.RLVD dict[:txt]
397
- #xml.RLVF
419
+ # xml.RLVF
398
420
  end
399
421
  end
400
- #xml.EFFTXTD
401
- #xml.EFFTXTF
422
+ # xml.EFFTXTD
423
+ # xml.EFFTXTF
402
424
  xml.MECHD ix[:mechanism]
403
- #xml.MECHF
425
+ # xml.MECHF
404
426
  xml.MEASD ix[:measures]
405
- #xml.MEASF
406
- #xml.REMD
407
- #xml.REMF
408
- #xml.LIT
427
+ # xml.MEASF
428
+ # xml.REMD
429
+ # xml.REMF
430
+ # xml.LIT
409
431
  xml.DEL false
410
- #xml.IXMCH {
432
+ # xml.IXMCH {
411
433
  # xml.TYP
412
434
  # xml.TYPD
413
435
  # xml.TYPF
@@ -416,61 +438,61 @@ module Oddb2xml
416
438
  # xml.CDF
417
439
  # xml.TXTD
418
440
  # xml.TXTF
419
- #}
441
+ # }
420
442
  nbr_records += 1
421
443
  }
422
444
  end
423
445
  xml.RESULT {
424
- xml.OK_ERROR 'OK'
446
+ xml.OK_ERROR "OK"
425
447
  xml.NBR_RECORD nbr_records
426
- xml.ERROR_CODE ''
427
- xml.MESSAGE ''
448
+ xml.ERROR_CODE ""
449
+ xml.MESSAGE ""
428
450
  }
429
451
  }
430
452
  end
431
- Oddb2xml.add_hash(_builder.to_xml)
453
+ Oddb2xml.add_hash(a_builder.to_xml)
432
454
  end
455
+
433
456
  def build_code
434
457
  prepare_codes
435
458
  nbr_records = 0
436
459
  Oddb2xml.log "build_code #{@codes.size} codes"
437
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
460
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
438
461
  xml.doc.tag_suffix = @tag_suffix
439
- datetime = Time.new.strftime('%FT%T%z')
440
462
  xml.CODE(XML_OPTIONS) {
441
463
  @codes.each_pair do |val, definition|
442
- xml.CD('DT' => '') {
443
- xml.CDTYP definition[:int]
444
- xml.CDVAL val
445
- xml.DSCRSD definition[:txt]
446
- #xml.DSCRSF
447
- #xml.DSCRMD
448
- #xml.DSCRMF
449
- #xml.DSCRD
450
- #xml.DSCRF
451
- xml.DEL false
464
+ xml.CD("DT" => "") {
465
+ xml.CDTYP definition[:int]
466
+ xml.CDVAL val
467
+ xml.DSCRSD definition[:txt]
468
+ # xml.DSCRSF
469
+ # xml.DSCRMD
470
+ # xml.DSCRMF
471
+ # xml.DSCRD
472
+ # xml.DSCRF
473
+ xml.DEL false
452
474
  nbr_records += 1
453
475
  }
454
476
  end
455
477
  xml.RESULT {
456
- xml.OK_ERROR 'OK'
478
+ xml.OK_ERROR "OK"
457
479
  xml.NBR_RECORD nbr_records
458
- xml.ERROR_CODE ''
459
- xml.MESSAGE ''
480
+ xml.ERROR_CODE ""
481
+ xml.MESSAGE ""
460
482
  }
461
483
  }
462
484
  end
463
- Oddb2xml.add_hash(_builder.to_xml)
485
+ Oddb2xml.add_hash(a_builder.to_xml)
464
486
  end
487
+
465
488
  def add_missing_products_from_swissmedic(add_to_products = false)
466
489
  Oddb2xml.log "build_product add_missing_products_from_swissmedic. Starting with #{@products.size} products and #{@packs.size} @packs"
467
490
  ean13_to_product = {}
468
- @products.each{
469
- |ean13, obj|
470
- ean13_to_product[ean13] = obj
471
- obj[:pharmacode] ||= @refdata[ean13][:pharmacode] if @refdata[ean13]
491
+ @products.each { |ean13, obj|
492
+ ean13_to_product[ean13] = obj
493
+ obj[:pharmacode] ||= @refdata[ean13][:pharmacode] if @refdata[ean13]
472
494
  }
473
- ausgabe = File.open(File.join(WorkDir, 'missing_in_refdata.txt'), 'w+')
495
+ ausgabe = File.open(File.join(WORK_DIR, "missing_in_refdata.txt"), "w+")
474
496
  size_old = ean13_to_product.size
475
497
  @missing = []
476
498
  Oddb2xml.log "build_product add_missing_products_from_swissmedic. Imported #{size_old} ean13_to_product from @products. Checking #{@packs.size} @packs"
@@ -478,49 +500,48 @@ module Oddb2xml
478
500
  ean = de_idx[1][:ean13]
479
501
  next if @refdata[ean]
480
502
  list_code = de_idx[1][:list_code]
481
- next if list_code and /Tierarzneimittel/.match(list_code)
503
+ next if list_code && /Tierarzneimittel/.match(list_code)
482
504
  if add_to_products
483
- @products[ean] = { :seq=>
484
- {:name_de => de_idx.last[:sequence_name],
485
- :desc_de => '',
486
- :name_fr => '',
487
- :desc_fr => '',
488
- :atc_code => de_idx.last[:atc_code],
489
- },
490
- :pac=>nil,
491
- :sequence_name => de_idx.last[:sequence_name],
492
- :no8=> de_idx.last[:prodno],
493
- :ean13=> ean,
494
- :atc=> de_idx.last[:atc_code],
495
- :ith=> de_idx.last[:ith_swissmedic],
496
- :siz=> de_idx.last[:package_size],
497
- :eht=> de_idx.last[:einheit_swissmedic],
498
- :sub=> de_idx.last[:substance_swissmedic],
499
- :comp=> de_idx.last[:composition_swissmedic],
500
- :drug_index => de_idx.last[:drug_index],
501
- }
505
+ @products[ean] = {seq: {name_de: de_idx.last[:sequence_name],
506
+ desc_de: "",
507
+ name_fr: "",
508
+ desc_fr: "",
509
+ atc_code: de_idx.last[:atc_code]},
510
+ pac: nil,
511
+ sequence_name: de_idx.last[:sequence_name],
512
+ no8: de_idx.last[:prodno],
513
+ ean13: ean,
514
+ atc: de_idx.last[:atc_code],
515
+ ith: de_idx.last[:ith_swissmedic],
516
+ siz: de_idx.last[:package_size],
517
+ eht: de_idx.last[:einheit_swissmedic],
518
+ sub: de_idx.last[:substance_swissmedic],
519
+ comp: de_idx.last[:composition_swissmedic],
520
+ drug_index: de_idx.last[:drug_index]}
502
521
  end
503
522
  ean13_to_product[ean] = de_idx[1]
504
523
  @missing << de_idx[1]
505
524
  ausgabe.puts "#{ean},#{de_idx[1][:sequence_name]}"
506
525
  end
507
526
  corrected_size = ean13_to_product.size
508
- Oddb2xml.log "build_product add_missing_products_from_swissmedic. Added #{(corrected_size - size_old)} corrected_size #{corrected_size} size_old #{size_old} ean13_to_product."
527
+ Oddb2xml.log "build_product add_missing_products_from_swissmedic. Added #{corrected_size - size_old} corrected_size #{corrected_size} size_old #{size_old} ean13_to_product."
509
528
  end
510
529
 
511
530
  def build_product
512
- def check_name(obj, lang = :de)
513
- ean = obj[:ean13]
514
- refdata = @refdata[ean]
515
- if lang == :de
516
- name = (refdata && refdata[:desc_de]) ? refdata[:desc_de] : obj[:sequence_name]
517
- elsif lang == :fr
518
- name = (refdata && refdata[:desc_fr]) ? refdata[:desc_fr] : obj[:sequence_name]
519
- else
520
- return false
531
+ self.class.class_eval do
532
+ def check_name(obj, lang = :de)
533
+ ean = obj[:ean13]
534
+ refdata = @refdata[ean]
535
+ if lang == :de
536
+ name = refdata && refdata[:desc_de] ? refdata[:desc_de] : obj[:sequence_name]
537
+ elsif lang == :fr
538
+ name = refdata && refdata[:desc_fr] ? refdata[:desc_fr] : obj[:sequence_name]
539
+ else
540
+ return false
541
+ end
542
+ return false if !name || name.empty? || name.length < 3
543
+ name[0..119] # limit to maximal 120 chars as specified in the XSD
521
544
  end
522
- return false if !name || name.empty? || name.length < 3
523
- name
524
545
  end
525
546
  prepare_substances
526
547
  prepare_products
@@ -528,303 +549,297 @@ module Oddb2xml
528
549
  prepare_codes
529
550
  add_missing_products_from_swissmedic
530
551
  nbr_products = 0
531
- Oddb2xml.log "build_product #{@products.size+@missing.size} products"
532
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
552
+ Oddb2xml.log "build_product #{@products.size + @missing.size} products"
553
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
533
554
  xml.doc.tag_suffix = @tag_suffix
534
- datetime = Time.new.strftime('%FT%T%z')
535
555
  emitted = []
536
556
  xml.PRODUCT(XML_OPTIONS) {
537
- list = []
538
557
  @missing.each do |obj|
539
558
  ean = obj[:ean13]
540
559
  next unless check_name(obj, :de)
541
560
  next unless check_name(obj, :fr)
542
- next if /^Q/i.match(obj[:atc])
561
+ next if /^Q/i.match?(obj[:atc])
543
562
  if obj[:prodno]
544
563
  next if emitted.index(obj[:prodno])
545
564
  emitted << obj[:prodno]
546
565
  end
547
- xml.PRD('DT' => obj[:last_change]) {
548
- nbr_products += 1
549
- xml.GTIN ean
550
- xml.PRODNO obj[:prodno] if obj[:prodno]
551
- xml.DSCRD check_name(obj, :de)
552
- xml.DSCRF check_name(obj, :fr)
553
- xml.ATC obj[:atc_code] unless obj[:atc_code].empty?
554
- xml.IT obj[:ith_swissmedic] if obj[:ith_swissmedic]
555
- xml.CPT
556
- xml.PackGrSwissmedic obj[:package_size] if obj[:package_size]
557
- xml.EinheitSwissmedic obj[:einheit_swissmedic] if obj[:einheit_swissmedic]
558
- xml.SubstanceSwissmedic obj[:substance_swissmedic] if obj[:substance_swissmedic]
559
- xml.CompositionSwissmedic obj[:composition_swissmedic] if obj[:composition_swissmedic]
560
- }
566
+ xml.PRD("DT" => obj[:last_change]) {
567
+ nbr_products += 1
568
+ xml.GTIN ean
569
+ xml.PRODNO obj[:prodno] if obj[:prodno]
570
+ xml.DSCRD check_name(obj, :de)
571
+ xml.DSCRF check_name(obj, :fr)
572
+ xml.ATC obj[:atc_code] unless obj[:atc_code].empty?
573
+ xml.IT obj[:ith_swissmedic] if obj[:ith_swissmedic]
574
+ xml.CPT
575
+ xml.PackGrSwissmedic obj[:package_size] if obj[:package_size]
576
+ xml.EinheitSwissmedic obj[:einheit_swissmedic] if obj[:einheit_swissmedic]
577
+ xml.SubstanceSwissmedic obj[:substance_swissmedic] if obj[:substance_swissmedic]
578
+ xml.CompositionSwissmedic obj[:composition_swissmedic] if obj[:composition_swissmedic]
579
+ }
561
580
  end
562
581
  @products.sort.to_h.each do |ean13, obj|
563
- next if /^Q/i.match(obj[:atc])
582
+ next if /^Q/i.match?(obj[:atc])
564
583
  seq = obj[:seq]
565
- ean = obj[:ean13]
566
- next unless check_name(obj, :de)
567
- next unless check_name(obj, :fr)
568
- xml.PRD('DT' => obj[:last_change]) do
584
+ ean = obj[:ean13]
585
+ next unless check_name(obj, :de)
586
+ next unless check_name(obj, :fr)
587
+ xml.PRD("DT" => obj[:last_change]) do
569
588
  nbr_products += 1
570
589
  xml.GTIN ean
571
- ppac = ((_ppac = @packs[ean.to_s[4..11]] and !_ppac[:is_tier]) ? _ppac : {})
572
- unless ppac
573
- ppac = @packs.find{|pac| pac.ean == ean }.first
574
- end
575
- xml.PRODNO ppac[:prodno] if ppac[:prodno] and !ppac[:prodno].empty?
576
- xml.DSCRD check_name(obj, :de)
577
- xml.DSCRF check_name(obj, :fr)
578
- #xml.BNAMD
579
- #xml.BNAMF
580
- #xml.ADNAMD
581
- #xml.ADNAMF
582
- #xml.SIZE
590
+ ppac = ((a_ppac = @packs[ean.to_s[4..11]]) && !a_ppac[:is_tier] ? a_ppac : {})
591
+ ppac ||= @packs.find { |pac| pac.ean == ean }.first
592
+ xml.PRODNO ppac[:prodno] if ppac[:prodno] && !ppac[:prodno].empty?
593
+ xml.DSCRD check_name(obj, :de)
594
+ xml.DSCRF check_name(obj, :fr)
595
+ # xml.BNAMD
596
+ # xml.BNAMF
597
+ # xml.ADNAMD
598
+ # xml.ADNAMF
599
+ # xml.SIZE
583
600
  if seq
584
- xml.ADINFD seq[:comment_de] unless seq[:comment_de] && seq[:comment_de].empty?
585
- xml.ADINFF seq[:comment_fr] unless seq[:comment_fr] && seq[:comment_fr].empty?
586
- xml.GENCD seq[:org_gen_code] unless seq[:org_gen_code] && seq[:org_gen_code].empty?
601
+ xml.ADINFD seq[:comment_de] unless seq[:comment_de] && seq[:comment_de].empty?
602
+ xml.ADINFF seq[:comment_fr] unless seq[:comment_fr] && seq[:comment_fr].empty?
603
+ xml.GENCD seq[:org_gen_code] unless seq[:org_gen_code] && seq[:org_gen_code].empty?
587
604
  end
588
- #xml.GENGRP
605
+ # xml.GENGRP
589
606
  xml.ATC obj[:atc] unless obj[:atc].empty?
590
- xml.IT obj[:ith] unless obj[:ith].empty?
591
- #xml.ITBAG
592
- #xml.KONO
593
- #xml.TRADE
594
- #xml.PRTNO
595
- #xml.MONO
596
- #xml.CDGALD
597
- #xml.CDGALF
598
- #xml.FORMD
599
- #xml.FORMF
600
- #xml.DOSE
601
- #xml.DOSEU
602
- #xml.DRGFD
603
- #xml.DRGFF
607
+ xml.IT obj[:ith] unless obj[:ith].empty?
608
+ # xml.ITBAG
609
+ # xml.KONO
610
+ # xml.TRADE
611
+ # xml.PRTNO
612
+ # xml.MONO
613
+ # xml.CDGALD
614
+ # xml.CDGALF
615
+ # xml.FORMD
616
+ # xml.FORMF
617
+ # xml.DOSE
618
+ # xml.DOSEU
619
+ # xml.DRGFD
620
+ # xml.DRGFF
604
621
  obj[:no8] =~ /(\d{5})(\d{3})/
605
622
  if @orphan.include?($1.to_s)
606
623
  xml.ORPH true
607
624
  end
608
- #xml.BIOPHA
609
- #xml.BIOSIM
610
- #xml.BFS
611
- #xml.BLOOD
612
- #xml.MSCD # always empty
613
- #xml.DEL
625
+ # xml.BIOPHA
626
+ # xml.BIOSIM
627
+ # xml.BFS
628
+ # xml.BLOOD
629
+ # xml.MSCD # always empty
630
+ # xml.DEL
614
631
  xml.CPT {
615
- #xml.CPTLNO
616
- #xml.CNAMED
617
- #xml.CNAMEF
618
- #xml.IDXIND
619
- #xml.DDDD
620
- #xml.DDDU
621
- #xml.DDDA
622
- #xml.IDXIA
623
- #xml.IXREL
624
- #xml.GALF
625
- #xml.DRGGRPCD
626
- #xml.PRBSUIT
627
- #xml.CSOLV
628
- #xml.CSOLVQ
629
- #xml.CSOLVQU
630
- #xml.PHVAL
631
- #xml.LSPNSOL
632
- #xml.APDURSOL
633
- #xml.EXCIP
634
- #xml.EXCIPQ
635
- #xml.EXCIPCD
636
- #xml.EXCIPCF
637
- #xml.PQTY
638
- #xml.PQTYU
639
- #xml.SIZEMM
640
- #xml.WEIGHT
641
- #xml.LOOKD
642
- #xml.LOOKF
643
- #xml.IMG2
632
+ # xml.CPTLNO
633
+ # xml.CNAMED
634
+ # xml.CNAMEF
635
+ # xml.IDXIND
636
+ # xml.DDDD
637
+ # xml.DDDU
638
+ # xml.DDDA
639
+ # xml.IDXIA
640
+ # xml.IXREL
641
+ # xml.GALF
642
+ # xml.DRGGRPCD
643
+ # xml.PRBSUIT
644
+ # xml.CSOLV
645
+ # xml.CSOLVQ
646
+ # xml.CSOLVQU
647
+ # xml.PHVAL
648
+ # xml.LSPNSOL
649
+ # xml.APDURSOL
650
+ # xml.EXCIP
651
+ # xml.EXCIPQ
652
+ # xml.EXCIPCD
653
+ # xml.EXCIPCF
654
+ # xml.PQTY
655
+ # xml.PQTYU
656
+ # xml.SIZEMM
657
+ # xml.WEIGHT
658
+ # xml.LOOKD
659
+ # xml.LOOKF
660
+ # xml.IMG2
644
661
  if seq
645
662
  seq[:substances].each do |sub|
646
663
  xml.CPTCMP {
647
- xml.LINE sub[:index] unless sub[:index].empty?
664
+ xml.LINE sub[:index] unless sub[:index].empty?
648
665
  xml.SUBNO(@substances.index(sub[:name]) + 1) if @substances.include?(sub[:name])
649
- xml.QTY sub[:quantity] unless sub[:quantity].empty?
650
- xml.QTYU sub[:unit] unless sub[:unit].empty?
651
- #xml.WHK
666
+ xml.QTY sub[:quantity] unless sub[:quantity].empty?
667
+ xml.QTYU sub[:unit] unless sub[:unit].empty?
668
+ # xml.WHK
652
669
  }
653
670
  end
654
671
  @interactions.each do |ix|
655
672
  if [ix[:act1], ix[:act2]].include?(seq[:atc_code])
656
673
  xml.CPTIX {
657
674
  xml.IXNO ix[:ixno]
658
- #xml.GRP
659
- xml.RLV @codes[ix[:grad]]
675
+ # xml.GRP
676
+ xml.RLV @codes[ix[:grad]]
660
677
  }
661
678
  end
662
679
  end
663
680
  end
664
- #xml.CPTROA {
665
- #xml.SYSLOC
666
- #xml.ROA
667
- #}
681
+ # xml.CPTROA {
682
+ # xml.SYSLOC
683
+ # xml.ROA
684
+ # }
668
685
  }
669
- #xml.PRDICD { # currently empty
670
- #xml.ICD
671
- #xml.RTYP
672
- #xml.RSIG
673
- #xml.REMD
674
- #xml.REMF
675
- #}
676
- xml.PackGrSwissmedic obj[:siz] unless obj[:siz].empty?
677
- xml.EinheitSwissmedic obj[:eht] unless obj[:eht].empty?
686
+ # xml.PRDICD { # currently empty
687
+ # xml.ICD
688
+ # xml.RTYP
689
+ # xml.RSIG
690
+ # xml.REMD
691
+ # xml.REMF
692
+ # }
693
+ xml.PackGrSwissmedic obj[:siz] unless obj[:siz].empty?
694
+ xml.EinheitSwissmedic obj[:eht] unless obj[:eht].empty?
678
695
  xml.SubstanceSwissmedic obj[:sub] unless obj[:sub].empty?
679
696
  xml.CompositionSwissmedic obj[:comp] unless obj[:comp].empty?
680
697
  end
681
698
  end
682
699
  xml.RESULT {
683
- xml.OK_ERROR 'OK'
700
+ xml.OK_ERROR "OK"
684
701
  xml.NBR_RECORD nbr_products
685
- xml.ERROR_CODE ''
686
- xml.MESSAGE ''
702
+ xml.ERROR_CODE ""
703
+ xml.MESSAGE ""
687
704
  }
688
705
  }
689
706
  end
690
- Oddb2xml.add_hash(_builder.to_xml)
707
+ Oddb2xml.add_hash(a_builder.to_xml)
691
708
  end
692
709
 
693
710
  def prepare_calc_items(suppress_composition_parsing: false)
694
711
  @calc_items = {}
695
- packungen_xlsx = File.join(Oddb2xml::WorkDir, "swissmedic_package.xlsx")
696
- idx = 0
697
- return unless File.exists?(packungen_xlsx)
712
+ packungen_xlsx = File.join(Oddb2xml::DOWNLOADS, "swissmedic_package.xlsx")
713
+ return unless File.exist?(packungen_xlsx)
698
714
  workbook = RubyXL::Parser.parse(packungen_xlsx)
699
715
  row_nr = 0
700
716
  workbook.worksheets[0].each do |row|
701
717
  row_nr += 1
702
- next unless row and row.cells[0] and row.cells[0].value and row.cells[0].value.to_i > 0
703
- iksnr = "%05i" % row.cells[0].value.to_i
704
- seqnr = "%02d" % row.cells[1].value.to_i
718
+ next unless row && row.cells[0] && row.cells[0].value && (row.cells[0].value.to_i > 0)
719
+ iksnr = "%05i" % row.cells[0].value.to_i
705
720
  if row_nr % 250 == 0
706
- puts "#{Time.now}: At row #{row_nr} iksnr #{iksnr}";
707
- $stdout.flush
721
+ puts "#{Time.now}: At row #{row_nr} iksnr #{iksnr}"
722
+ $stdout.flush
708
723
  end
709
- ith = COLUMNS_FEBRUARY_2019.keys.index(:index_therapeuticus)
710
- seq_name = COLUMNS_FEBRUARY_2019.keys.index(:name_base)
711
- i_3 = COLUMNS_FEBRUARY_2019.keys.index(:ikscd)
712
- p_1_2 = COLUMNS_FEBRUARY_2019.keys.index(:seqnr)
713
- cat = COLUMNS_FEBRUARY_2019.keys.index(:ikscat)
714
- siz = COLUMNS_FEBRUARY_2019.keys.index(:size)
715
- atc = COLUMNS_FEBRUARY_2019.keys.index(:atc_class)
724
+ seq_name = COLUMNS_FEBRUARY_2019.keys.index(:name_base)
725
+ i_3 = COLUMNS_FEBRUARY_2019.keys.index(:ikscd)
726
+ siz = COLUMNS_FEBRUARY_2019.keys.index(:size)
727
+ atc = COLUMNS_FEBRUARY_2019.keys.index(:atc_class)
716
728
  list_code = COLUMNS_FEBRUARY_2019.keys.index(:production_science)
717
- unit = COLUMNS_FEBRUARY_2019.keys.index(:unit)
718
- sub = COLUMNS_FEBRUARY_2019.keys.index(:substances)
719
- comp = COLUMNS_FEBRUARY_2019.keys.index(:composition)
729
+ unit = COLUMNS_FEBRUARY_2019.keys.index(:unit)
730
+ sub = COLUMNS_FEBRUARY_2019.keys.index(:substances)
731
+ comp = COLUMNS_FEBRUARY_2019.keys.index(:composition)
720
732
 
721
- no8 = iksnr + sprintf('%03d',row.cells[i_3].value.to_i)
722
- name = row.cells[seq_name] ? row.cells[seq_name].value : nil
723
- atc_code = row.cells[atc] ? row.cells[atc].value : nil
724
- list_code = row.cells[list_code] ? row.cells[list_code].value : nil
725
- package_size = row.cells[siz] ? row.cells[siz].value : nil
726
- unit = row.cells[unit] ? row.cells[unit].value : nil
727
- active_substance = row.cells[sub] ? row.cells[sub].value : nil
728
- composition = row.cells[comp] ? row.cells[comp].value : nil
733
+ no8 = iksnr + sprintf("%03d", row.cells[i_3].value.to_i)
734
+ name = row.cells[seq_name] ? row.cells[seq_name].value : nil
735
+ atc_code = row.cells[atc] ? row.cells[atc].value : nil
736
+ list_code = row.cells[list_code] ? row.cells[list_code].value : nil
737
+ package_size = row.cells[siz] ? row.cells[siz].value : nil
738
+ unit = row.cells[unit] ? row.cells[unit].value : nil
739
+ active_substance = row.cells[sub] ? row.cells[sub].value : nil
740
+ composition = row.cells[comp] ? row.cells[comp].value : nil
729
741
 
730
742
  # skip veterinary product
731
- next if atc_code and /^Q/i.match(atc_code)
732
- next if list_code and /Tierarzneimittel/.match(list_code)
743
+ next if atc_code && /^Q/i.match(atc_code)
744
+ next if list_code && /Tierarzneimittel/.match(list_code)
733
745
  info = nil
734
746
  begin
735
- if suppress_composition_parsing
736
- info = Calc.new(name, package_size, unit)
747
+ info = if suppress_composition_parsing
748
+ Calc.new(name, package_size, unit)
737
749
  else
738
- info = Calc.new(name, package_size, unit, active_substance, composition)
750
+ Calc.new(name, package_size, unit, active_substance, composition)
739
751
  end
740
752
  rescue
741
753
  puts "#{Time.now}: #{row_nr} iksnr #{iksnr} rescue from Calc.new"
742
754
  end
743
- ean12 = '7680' + no8
755
+ ean12 = "7680" + no8
744
756
  ean13 = (ean12 + Oddb2xml.calc_checksum(ean12))
745
757
  @calc_items[ean13] = info
746
758
  end
747
759
  end
748
- def build_calc
749
- def emit_substance(xml, substance, emit_active=false)
750
- xml.MORE_INFO substance.more_info if substance.more_info
751
- xml.SUBSTANCE_NAME substance.name
752
- xml.IS_ACTIVE_AGENT substance.is_active_agent if emit_active
753
- if substance.dose
754
- if substance.qty.is_a?(Float) or substance.qty.is_a?(Integer)
755
- xml.QTY substance.qty
756
- xml.UNIT substance.unit
757
- else
758
- xml.DOSE_TEXT substance.dose.to_s
759
- end
760
- end
761
- if substance.chemical_substance
762
- xml.CHEMICAL_SUBSTANCE {
763
- emit_substance(xml, substance.chemical_substance)
764
- }
765
- end
766
- if substance.salts and substance.salts.size > 0
767
- xml.SALTS do
768
- substance.salts.each do |salt|
769
- xml.SALT do
770
- emit_substance(xml, salt)
771
- end
772
- end
760
+
761
+ def emit_substance(xml, substance, emit_active = false)
762
+ xml.MORE_INFO substance.more_info if substance.more_info
763
+ xml.SUBSTANCE_NAME substance.name
764
+ xml.IS_ACTIVE_AGENT substance.is_active_agent if emit_active
765
+ if substance.dose
766
+ if substance.qty.is_a?(Float) || substance.qty.is_a?(Integer)
767
+ xml.QTY substance.qty
768
+ xml.UNIT substance.unit
769
+ else
770
+ xml.DOSE_TEXT substance.dose.to_s
771
+ end
772
+ end
773
+ if substance.chemical_substance
774
+ xml.CHEMICAL_SUBSTANCE {
775
+ emit_substance(xml, substance.chemical_substance)
776
+ }
777
+ end
778
+ if substance.salts && (substance.salts.size > 0)
779
+ xml.SALTS do
780
+ substance.salts.each do |salt|
781
+ xml.SALT do
782
+ emit_substance(xml, salt)
773
783
  end
774
784
  end
785
+ end
775
786
  end
787
+ end
788
+
789
+ def build_calc
776
790
  prepare_calc_items
777
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
791
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
778
792
  xml.doc.tag_suffix = @tag_suffix
779
- datetime = Time.new.strftime('%FT%T%z')
780
793
  xml.ARTICLES(XML_OPTIONS) do
781
794
  @calc_items.each do |ean13, info|
782
- xml.ARTICLE do
783
- xml.GTIN ean13
784
- xml.NAME info.column_c
785
- xml.PKG_SIZE info.pkg_size
786
- xml.SELLING_UNITS info.selling_units
787
- xml.MEASURE info.measure # Nur wenn Lösung wen Spalte M ml, Spritze
795
+ if info&.compositions
796
+ xml.ARTICLE do
797
+ xml.GTIN ean13
798
+ xml.NAME info.column_c
799
+ xml.PKG_SIZE info.pkg_size
800
+ xml.SELLING_UNITS info.selling_units
801
+ xml.MEASURE info.measure # Nur wenn Lösung wen Spalte M ml, Spritze
788
802
 
789
- if info.galenic_form.is_a?(String)
790
- xml.GALENIC_FORM info.galenic_form
791
- xml.GALENIC_GROUP "Unknown"
792
- else
793
- xml.GALENIC_FORM info.galenic_form.description
794
- xml.GALENIC_GROUP info.galenic_group ? info.galenic_group.description : "Unknown"
795
- end
796
- xml.COMPOSITIONS do
797
- info.compositions.each do |composition|
798
- xml.COMPOSITION do
799
- xml.EXCIPIENS { emit_substance(xml, composition.excipiens) } if composition.excipiens
800
- xml.LABEL composition.label if composition.label
801
- xml.LABEL_DESCRIPTION composition.label_description if composition.label_description
802
- xml.CORRESP composition.corresp if composition.corresp
803
- if composition.substances and composition.substances.size > 0
804
- xml.SUBSTANCES do
805
- composition.substances.each { |substance| xml.SUBSTANCE { emit_substance(xml, substance, true) }}
803
+ if info.galenic_form.is_a?(String)
804
+ xml.GALENIC_FORM info.galenic_form
805
+ xml.GALENIC_GROUP "Unknown"
806
+ else
807
+ xml.GALENIC_FORM info.galenic_form.description
808
+ xml.GALENIC_GROUP info.galenic_group ? info.galenic_group.description : "Unknown"
809
+ end
810
+ xml.COMPOSITIONS do
811
+ info.compositions.each do |composition|
812
+ xml.COMPOSITION do
813
+ xml.EXCIPIENS { emit_substance(xml, composition.excipiens) } if composition.excipiens
814
+ xml.LABEL composition.label if composition.label
815
+ xml.LABEL_DESCRIPTION composition.label_description if composition.label_description
816
+ xml.CORRESP composition.corresp if composition.corresp
817
+ if composition.substances && (composition.substances.size > 0)
818
+ xml.SUBSTANCES do
819
+ composition.substances.each { |substance| xml.SUBSTANCE { emit_substance(xml, substance, true) } }
820
+ end
806
821
  end
807
822
  end
808
823
  end
809
824
  end
810
825
  end
811
- end if info and info.compositions
826
+ end
812
827
  end
813
828
  end
814
829
  end
815
830
 
816
- csv_name = File.join(WorkDir, 'oddb_calc.csv')
817
- CSV.open(csv_name, "w+", :col_sep => ';') do |csv|
818
- csv << ['gtin'] + @calc_items.values.first.headers
831
+ csv_name = File.join(WORK_DIR, "oddb_calc.csv")
832
+ CSV.open(csv_name, "w+", col_sep: ";") do |csv|
833
+ csv << ["gtin"] + @calc_items.values.first.headers
819
834
  @calc_items.each do |key, value|
820
- if value and value.to_array
821
- csv << [key] + value.to_array
835
+ if value&.to_array
836
+ csv << [key] + value.to_array
822
837
  else
823
838
  puts "key #{key.inspect} WITHOUT #{value.inspect}"
824
839
  end
825
840
  end
826
841
  end
827
- Oddb2xml.add_hash(_builder.to_xml)
842
+ Oddb2xml.add_hash(a_builder.to_xml)
828
843
  end
829
844
 
830
845
  def build_article
@@ -834,21 +849,20 @@ module Oddb2xml
834
849
  idx = 0
835
850
  nbr_records = 0
836
851
  Oddb2xml.log "build_article #{idx} of #{@articles.size} articles"
837
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
852
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
838
853
  xml.doc.tag_suffix = @tag_suffix
839
- datetime = Time.new.strftime('%FT%T%z')
840
- eans_from_refdata = @articles.collect{|refdata| refdata[:ean13] }
854
+ eans_from_refdata = @articles.collect { |refdata| refdata[:ean13] }
841
855
  eans_from_preparations = @items.keys
842
856
  missing_eans = []
843
857
  eans_from_preparations.each do |ean|
844
858
  next if ean.to_i == 0
845
- unless @articles.collect {|x| x[:ean13] }.index(ean)
859
+ unless @articles.collect { |x| x[:ean13] }.index(ean)
846
860
  item = @items[ean].clone
847
- item[:pharmacode] ||= '123456' if defined?(RSpec)
861
+ item[:pharmacode] ||= "123456" if defined?(RSpec)
848
862
  item[:ean13] = ean
849
863
  item[:_type] = :preparations_xml
850
- item[:desc_de] = item[:name_de] + ' ' + item[:desc_de]
851
- item[:desc_fr] = item[:name_fr] + ' ' + item[:desc_fr]
864
+ item[:desc_de] = item[:name_de] + " " + item[:desc_de]
865
+ item[:desc_fr] = item[:name_fr] + " " + item[:desc_fr]
852
866
  @articles << item
853
867
  end
854
868
  unless eans_from_refdata.index(ean)
@@ -856,169 +870,166 @@ module Oddb2xml
856
870
  end
857
871
  end
858
872
  xml.ARTICLE(XML_OPTIONS) {
859
- @articles.sort! { |a,b| a[:ean13] <=> b[:ean13] }
860
- @articles.each do |obj|
861
- idx += 1
862
- Oddb2xml.log "build_article #{obj[:ean13]}: #{idx} of #{@articles.size} articles" if idx % 500 == 0
863
- item = @items[obj[:ean13]]
864
- pac,no8 = nil,obj[:ean13].to_s[4..11] # BAG-XML(SL/LS)
873
+ @articles.sort! { |a, b| a[:ean13] <=> b[:ean13] }
874
+ @articles.each do |obj|
875
+ idx += 1
876
+ Oddb2xml.log "build_article #{obj[:ean13]}: #{idx} of #{@articles.size} articles" if idx % 500 == 0
877
+ pac, no8 = nil, obj[:ean13].to_s[4..11] # BAG-XML(SL/LS)
865
878
  pack_info = nil
866
879
  pack_info = @packs[no8] if no8 # info from Packungen.xlsx from swissmedic_info
867
- ppac = nil # Packungen
880
+ ppac = nil # Packungen
868
881
  ean = obj[:ean13]
869
- next if pack_info and /Tierarzneimittel/.match(pack_info[:list_code])
870
- next if obj[:desc_de] and /ad us vet/i.match(obj[:desc_de])
882
+ next if pack_info && /Tierarzneimittel/.match(pack_info[:list_code])
883
+ next if obj[:desc_de] && /ad us vet/i.match(obj[:desc_de])
871
884
  pharma_code = obj[:pharmacode]
872
885
  # ean = 0 if sprintf('%013d', ean).match(/^000000/)
873
886
  if obj[:seq]
874
887
  pac = obj[:seq][:packages][obj[:pharmacode]]
875
- pac = obj[:seq][:packages][ean] unless pac
876
- else
877
- pac = @items[ean][:packages][ean] if @items and ean and @items[ean] and @items[ean][:packages]
888
+ pac ||= obj[:seq][:packages][ean]
889
+ elsif @items && ean && @items[ean] && @items[ean][:packages]
890
+ pac = @items[ean][:packages][ean]
878
891
  end
879
892
  if no8
880
- ppac = ((_ppac = pack_info and !_ppac[:is_tier]) ? _ppac : nil)
893
+ ppac = ((a_ppac = pack_info) && !a_ppac[:is_tier] ? a_ppac : nil)
881
894
  end
882
895
  zur_rose = nil
883
896
  if !@infos_zur_rose.empty? && ean && @infos_zur_rose[ean]
884
897
  zur_rose = @infos_zur_rose[ean] # zurrose
885
898
  end
886
- xml.ART('DT' => obj[:last_change] ? obj[:last_change] : '') do
899
+ xml.ART("DT" => obj[:last_change] || "") do
887
900
  nbr_records += 1
888
- xml.REF_DATA (obj[:refdata] || @migel[pharma_code]) ? '1' : '0'
889
- # xml.PHAR sprintf('%07d', obj[:pharmacode]) if obj[:pharmacode]
890
- xml.PHAR obj[:pharmacode] if obj[:pharmacode]
891
- #xml.GRPCD
892
- #xml.CDS01
893
- #xml.CDS02
901
+ # Ignore Lint/RequireParentheses warning on next line!
902
+ xml.REF_DATA obj[:refdata] || @migel[pharma_code] ? "1" : "0"
903
+ if obj[:pharmacode] && obj[:pharmacode].length > 0
904
+ xml.PHAR obj[:pharmacode]
905
+ elsif zur_rose
906
+ puts "Adding #{zur_rose[:pharmacode]} to article GTIN #{ean}"
907
+ xml.PHAR zur_rose[:pharmacode]
908
+ end
909
+ # xml.GRPCD
910
+ # xml.CDS01
911
+ # xml.CDS02
894
912
  if ppac
895
- xml.SMCAT ppac[:swissmedic_category] unless ppac[:swissmedic_category].empty?
896
- xml.GEN_PRODUCTION ppac[:gen_production] unless ppac[:gen_production].empty?
897
- xml.INSULIN_CATEGORY ppac[:insulin_category] unless ppac[:insulin_category].empty?
898
- xml.DRUG_INDEX ppac[:drug_index] unless ppac[:drug_index].empty?
913
+ xml.SMCAT ppac[:swissmedic_category] unless ppac[:swissmedic_category].empty?
914
+ xml.GEN_PRODUCTION ppac[:gen_production] unless ppac[:gen_production].empty?
915
+ xml.INSULIN_CATEGORY ppac[:insulin_category] unless ppac[:insulin_category].empty?
916
+ xml.DRUG_INDEX ppac[:drug_index] unless ppac[:drug_index].empty?
899
917
  end
900
- if no8 and !no8.to_s.empty?
901
- if ean and ean.to_s[0..3] == "7680"
918
+ if no8 && !no8.to_s.empty?
919
+ if ean && (ean.to_s[0..3] == "7680")
902
920
  xml.SMNO no8.to_s
903
921
  end
904
922
  end
905
923
  if ppac
906
- xml.PRODNO ppac[:prodno] if ppac[:prodno] and !ppac[:prodno].empty?
924
+ xml.PRODNO ppac[:prodno] if ppac[:prodno] && !ppac[:prodno].empty?
907
925
  end
908
- #xml.HOSPCD
909
- #xml.CLINCD
910
- #xml.ARTTYP
926
+ # xml.HOSPCD
927
+ # xml.CLINCD
928
+ # xml.ARTTYP
911
929
  if zur_rose
912
930
  xml.VAT zur_rose[:vat]
913
931
  end
914
932
  emit_salecd(xml, ean, obj)
915
- if pac and pac[:limitation_points]
916
- #xml.INSLIM
933
+ if pac && pac[:limitation_points]
934
+ # xml.INSLIM
917
935
  xml.LIMPTS pac[:limitation_points] unless pac[:limitation_points].empty?
918
936
  end
919
- #xml.GRDFR
937
+ # xml.GRDFR
920
938
  xml.COOL 1 if ppac && /Blutprodukte|impfstoffe/.match(ppac[:list_code])
921
- #xml.TEMP
939
+ # xml.TEMP
922
940
  if ean
923
- flag = (ppac && !ppac[:drug_index].empty?) ? true : false
941
+ flag = ppac && !ppac[:drug_index].empty? ? true : false
924
942
  # as same flag
925
- xml.CDBG(flag ? 'Y' : 'N')
926
- xml.BG(flag ? 'Y' : 'N')
943
+ xml.CDBG(flag ? "Y" : "N")
944
+ xml.BG(flag ? "Y" : "N")
927
945
  end
928
- #xml.EXP
929
- if item and item[:substances] and substance = item[:substances].first
930
- xml.QTY "#{substance[:quantity]}#{substance[:unit] ? ' ' + substance[:unit] : ''}"
931
- end if false # TODO: get qty/unit from refdata name
932
- xml.DSCRD obj[:desc_de] if obj[:desc_de] and not obj[:desc_de].empty?
933
- xml.DSCRF obj[:desc_fr] if obj[:desc_fr] and not obj[:desc_fr].empty?
934
- xml.DSCRF obj[:desc_de] if !obj[:desc_fr] or obj[:desc_fr].empty?
935
- xml.SORTD obj[:desc_de].upcase if obj[:desc_de] and not obj[:desc_de].empty?
936
- xml.SORTF obj[:desc_fr].upcase if obj[:desc_fr] and not obj[:desc_fr].empty?
937
- xml.SORTF obj[:desc_de].upcase if !obj[:desc_fr] or obj[:desc_fr].empty?
938
- #xml.QTYUD
939
- #xml.QTYUF
940
- #xml.IMG
941
- #xml.IMG2
942
- #xml.PCKTYPD
943
- #xml.PCKTYPF
944
- #xml.MULT
946
+ xml.DSCRD obj[:desc_de] if obj[:desc_de] && !obj[:desc_de].empty?
947
+ xml.DSCRF obj[:desc_fr] if obj[:desc_fr] && !obj[:desc_fr].empty?
948
+ xml.DSCRF obj[:desc_de] if !obj[:desc_fr] || obj[:desc_fr].empty?
949
+ xml.SORTD obj[:desc_de].upcase if obj[:desc_de] && !obj[:desc_de].empty?
950
+ xml.SORTF obj[:desc_fr].upcase if obj[:desc_fr] && !obj[:desc_fr].empty?
951
+ xml.SORTF obj[:desc_de].upcase if !obj[:desc_fr] || obj[:desc_fr].empty?
952
+ # xml.QTYUD
953
+ # xml.QTYUF
954
+ # xml.IMG
955
+ # xml.IMG2
956
+ # xml.PCKTYPD
957
+ # xml.PCKTYPF
958
+ # xml.MULT
945
959
  if obj[:seq]
946
960
  xml.SYN1D obj[:seq][:name_de] unless obj[:seq][:name_de].empty?
947
961
  xml.SYN1F obj[:seq][:name_fr] unless obj[:seq][:name_fr].empty?
948
962
  end
949
963
  if obj[:seq]
950
964
  case obj[:seq][:deductible]
951
- when 'Y'; xml.SLOPLUS 1; # 20%
952
- when 'N'; xml.SLOPLUS 2; # 10%
953
- else xml.SLOPLUS '' # k.A.
965
+ when "Y" then xml.SLOPLUS 1; # 20%
966
+ when "N" then xml.SLOPLUS 2; # 10%
967
+ else xml.SLOPLUS "" # k.A.
954
968
  end
955
969
  end
956
- #xml.NOPCS
957
- #xml.HSCD
958
- #xml.MINI
959
- #xml.DEPCD
960
- #xml.DEPOT
961
- #xml.BAGSL
962
- #xml.BAGSLC
963
- #xml.LOACD
970
+ # xml.NOPCS
971
+ # xml.HSCD
972
+ # xml.MINI
973
+ # xml.DEPCD
974
+ # xml.DEPOT
975
+ # xml.BAGSL
976
+ # xml.BAGSLC
977
+ # xml.LOACD
964
978
  if obj[:stat_date]
965
- xml.OUTSAL obj[:stat_date] if obj[:stat_date] and not obj[:stat_date].empty?
979
+ xml.OUTSAL obj[:stat_date] if obj[:stat_date] && !obj[:stat_date].empty?
966
980
  end
967
- #xml.STTOX
968
- #xml.NOTI
969
- #xml.GGL
970
- #xml.CE
971
- #xml.SMDAT
972
- #xml.SMCDAT
973
- #xml.SIST
974
- #xml.ESIST
975
- #xml.BIOCID
976
- #xml.BAGNO
977
- #xml.LIGHT
978
- #xml.DEL
981
+ # xml.STTOX
982
+ # xml.NOTI
983
+ # xml.GGL
984
+ # xml.CE
985
+ # xml.SMDAT
986
+ # xml.SMCDAT
987
+ # xml.SIST
988
+ # xml.ESIST
989
+ # xml.BIOCID
990
+ # xml.BAGNO
991
+ # xml.LIGHT
992
+ # xml.DEL
979
993
  xml.ARTCOMP {
980
994
  # use ean13(gln) as COMPNO
981
- xml.COMPNO obj[:company_ean] if obj[:company_ean] and obj[:company_ean].to_s.length > 1
982
- #xml.ROLE
983
- #xml.ARTNO1
984
- #xml.ARTNO2
985
- #xml.ARTNO3
995
+ xml.COMPNO obj[:company_ean] if obj[:company_ean] && (obj[:company_ean].to_s.length > 1)
996
+ # xml.ROLE
997
+ # xml.ARTNO1
998
+ # xml.ARTNO2
999
+ # xml.ARTNO3
986
1000
  }
987
- xml.ARTBAR {
988
- xml.CDTYP 'E13'
989
- xml.BC ean # /^9999|^0000|^0$/.match(ean.to_s) ? 0 : sprintf('%013d', ean)
990
- xml.BCSTAT 'A' # P is alternative
991
- #xml.PHAR2
992
- } if ean
993
- #xml.ARTCH {
994
- #xml.PHAR2
995
- #xml.CHTYPE
996
- #xml.LINENO
997
- #xml.NOUNITS
998
- #}
999
- if pac and pac[:prices]
1001
+ if ean
1002
+ xml.ARTBAR {
1003
+ xml.CDTYP "E13"
1004
+ xml.BC ean # /^9999|^0000|^0$/.match(ean.to_s) ? 0 : sprintf('%013d', ean)
1005
+ xml.BCSTAT "A" # P is alternative
1006
+ }
1007
+ end
1008
+ if pac && pac[:prices]
1000
1009
  pac[:prices].each_pair do |key, price|
1001
1010
  xml.ARTPRI {
1002
- xml.VDAT price[:valid_date] unless price[:valid_date].empty?
1003
- xml.PTYP price[:price_code] unless price[:price_code].empty?
1004
- xml.PRICE price[:price] unless price[:price].empty?
1011
+ xml.VDAT price[:valid_date] unless price[:valid_date].empty?
1012
+ xml.PTYP price[:price_code] unless price[:price_code].empty?
1013
+ xml.PRICE price[:price] unless price[:price].empty?
1005
1014
  }
1006
1015
  end
1007
1016
  end
1008
1017
  if zur_rose
1009
1018
  price = zur_rose[:price]
1010
1019
  xml.ARTPRI {
1011
- xml.PTYP "ZURROSE"
1020
+ xml.PTYP "ZURROSE"
1012
1021
  xml.PRICE price
1013
1022
  }
1014
1023
  xml.ARTPRI {
1015
- xml.PTYP "ZURROSEPUB"
1024
+ xml.PTYP "ZURROSEPUB"
1016
1025
  xml.PRICE zur_rose[:pub_price]
1017
1026
  }
1018
- xml.ARTPRI {
1019
- xml.PTYP "RESELLERPUB"
1020
- xml.PRICE (price.to_f*(1 + (@options[:percent].to_f/100))).round_by(0.05).round(2)
1021
- } if @options[:percent] != nil
1027
+ unless @options[:percent].nil?
1028
+ xml.ARTPRI {
1029
+ xml.PTYP "RESELLERPUB"
1030
+ xml.PRICE (price.to_f * (1 + (@options[:percent].to_f / 100))).round_by(0.05).round(2)
1031
+ }
1032
+ end
1022
1033
  end
1023
1034
  nincd = detect_nincd(obj)
1024
1035
  if nincd
@@ -1029,29 +1040,29 @@ module Oddb2xml
1029
1040
  end
1030
1041
  end
1031
1042
  xml.RESULT {
1032
- xml.OK_ERROR 'OK'
1043
+ xml.OK_ERROR "OK"
1033
1044
  xml.NBR_RECORD nbr_records
1034
- xml.ERROR_CODE ''
1035
- xml.MESSAGE ''
1045
+ xml.ERROR_CODE ""
1046
+ xml.MESSAGE ""
1036
1047
  }
1037
1048
  }
1038
1049
  end
1039
1050
  Oddb2xml.log "build_article. Done #{idx} of #{@articles.size} articles. Overrode #{@overriden_salecd.size} SALECD"
1040
- Oddb2xml.add_hash(_builder.to_xml)
1051
+ Oddb2xml.add_hash(a_builder.to_xml)
1041
1052
  end
1053
+
1042
1054
  def build_fi
1043
1055
  nbr_records = 0
1044
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
1056
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
1045
1057
  xml.doc.tag_suffix = @tag_suffix
1046
- datetime = Time.new.strftime('%FT%T%z')
1047
1058
  xml.KOMPENDIUM(XML_OPTIONS) {
1048
1059
  %w[de fr].each do |lang|
1049
- infos = @infos[lang].uniq {|i| i[:monid] }
1060
+ infos = @infos[lang].uniq { |i| i[:monid] }
1050
1061
  infos.each do |info|
1051
1062
  xml.KMP(
1052
- 'MONTYPE' => 'fi', # only
1053
- 'LANG' => lang.upcase,
1054
- 'DT' => ''
1063
+ "MONTYPE" => "fi", # only
1064
+ "LANG" => lang.upcase,
1065
+ "DT" => ""
1055
1066
  ) {
1056
1067
  unless info[:name].empty?
1057
1068
  xml.name info[:name]
@@ -1059,29 +1070,29 @@ module Oddb2xml
1059
1070
  unless info[:owner].empty?
1060
1071
  xml.owner info[:owner]
1061
1072
  end
1062
- xml.monid info[:monid] unless info[:monid].empty?
1073
+ xml.monid info[:monid] unless info[:monid].empty?
1063
1074
  xml.style { xml.cdata(info[:style]) } if info[:style]
1064
- xml.paragraph { xml.cdata(Nokogiri::HTML.fragment(info[:paragraph].to_html).to_html(:encoding => 'UTF-8')) } if info[:paragraph]
1075
+ xml.paragraph { xml.cdata(Nokogiri::HTML.fragment(info[:paragraph].to_html).to_html(encoding: "UTF-8")) } if info[:paragraph]
1065
1076
  nbr_records += 1
1066
1077
  }
1067
1078
  end
1068
1079
  end
1069
1080
  xml.RESULT {
1070
- xml.OK_ERROR 'OK'
1081
+ xml.OK_ERROR "OK"
1071
1082
  xml.NBR_RECORD nbr_records
1072
- xml.ERROR_CODE ''
1073
- xml.MESSAGE ''
1083
+ xml.ERROR_CODE ""
1084
+ xml.MESSAGE ""
1074
1085
  }
1075
1086
  }
1076
1087
  end
1077
- Oddb2xml.add_hash(_builder.to_xml)
1088
+ Oddb2xml.add_hash(a_builder.to_xml)
1078
1089
  end
1090
+
1079
1091
  def build_fi_product
1080
1092
  prepare_products
1081
1093
  nbr_records = 0
1082
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
1094
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
1083
1095
  xml.doc.tag_suffix = @tag_suffix
1084
- datetime = Time.new.strftime('%FT%T%z')
1085
1096
  xml.KOMPENDIUM_PRODUCT(XML_OPTIONS) {
1086
1097
  info_index = {}
1087
1098
  %w[de fr].each do |lang|
@@ -1090,558 +1101,581 @@ module Oddb2xml
1090
1101
  end
1091
1102
  # prod
1092
1103
  @products.each do |ean13, prod|
1093
- next unless prod[:seq] and prod[:seq][:packages]
1104
+ next unless prod[:seq] && prod[:seq][:packages]
1094
1105
  seq = prod[:seq]
1095
- prod[:seq][:packages].each {
1096
- |phar, package|
1097
- next unless package[:swissmedic_number8]
1098
- m = /(\d{5})(\d{3})/.match(package[:swissmedic_number8])
1099
- next unless m
1100
- number = m[1].to_s
1101
- idx = info_index[number]
1102
- next unless idx
1103
- xml.KP('DT' => '') {
1104
- xml.MONID @infos[lang][idx][:monid]
1105
- xml.PRDNO seq[:product_key] unless seq[:product_key].empty?
1106
- # as orphan ?
1107
- xml.DEL @orphan.include?(number) ? true : false
1108
- nbr_records += 1
1109
- }
1110
- }
1111
- end
1106
+ prod[:seq][:packages].each { |phar, package|
1107
+ next unless package[:swissmedic_number8]
1108
+ m = /(\d{5})(\d{3})/.match(package[:swissmedic_number8])
1109
+ next unless m
1110
+ number = m[1].to_s
1111
+ idx = info_index[number]
1112
+ next unless idx
1113
+ xml.KP("DT" => "") {
1114
+ xml.MONID @infos[lang][idx][:monid]
1115
+ xml.PRDNO seq[:product_key] unless seq[:product_key].empty?
1116
+ # as orphan ?
1117
+ xml.DEL @orphan.include?(number) ? true : false
1118
+ nbr_records += 1
1119
+ }
1120
+ }
1112
1121
  end
1122
+ end
1113
1123
  xml.RESULT {
1114
- xml.OK_ERROR 'OK'
1124
+ xml.OK_ERROR "OK"
1115
1125
  xml.NBR_RECORD nbr_records
1116
- xml.ERROR_CODE ''
1117
- xml.MESSAGE ''
1126
+ xml.ERROR_CODE ""
1127
+ xml.MESSAGE ""
1118
1128
  }
1119
1129
  }
1120
1130
  end
1121
- Oddb2xml.add_hash(_builder.to_xml)
1131
+ Oddb2xml.add_hash(a_builder.to_xml)
1122
1132
  end
1133
+
1123
1134
  def build_company
1124
1135
  nbr_records = 0
1125
1136
  Oddb2xml.log "build_company #{@companies.size} companies"
1126
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
1137
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
1127
1138
  xml.doc.tag_suffix = @tag_suffix
1128
- datetime = Time.new.strftime('%FT%T%z')
1129
1139
  xml.Betriebe(XML_OPTIONS) {
1130
1140
  @companies.each do |c|
1131
- xml.Betrieb('DT' => '') {
1132
- xml.GLN_Betrieb c[:gln] unless c[:gln].empty?
1133
- xml.Betriebsname_1 c[:name_1] unless c[:name_1].empty?
1134
- xml.Betriebsname_2 c[:name_2] unless c[:name_2].empty?
1135
- xml.Strasse c[:address] unless c[:address].empty?
1136
- xml.Nummer c[:number] unless c[:number].empty?
1137
- xml.PLZ c[:post] unless c[:post].empty?
1138
- xml.Ort c[:place] unless c[:place].empty?
1139
- xml.Bewilligungskanton c[:region] unless c[:region].empty?
1140
- xml.Land c[:country] unless c[:country].empty?
1141
- xml.Betriebstyp c[:type] unless c[:type].empty?
1142
- xml.BTM_Berechtigung c[:authorization] unless c[:authorization].empty?
1141
+ xml.Betrieb("DT" => "") {
1142
+ xml.GLN_Betrieb c[:gln] unless c[:gln].empty?
1143
+ xml.Betriebsname_1 c[:name_1] unless c[:name_1].empty?
1144
+ xml.Betriebsname_2 c[:name_2] unless c[:name_2].empty?
1145
+ xml.Strasse c[:address] unless c[:address].empty?
1146
+ xml.Nummer c[:number] unless c[:number].empty?
1147
+ xml.PLZ c[:post] unless c[:post].empty?
1148
+ xml.Ort c[:place] unless c[:place].empty?
1149
+ xml.Bewilligungskanton c[:region] unless c[:region].empty?
1150
+ xml.Land c[:country] unless c[:country].empty?
1151
+ xml.Betriebstyp c[:type] unless c[:type].empty?
1152
+ xml.BTM_Berechtigung c[:authorization] unless c[:authorization].empty?
1143
1153
  nbr_records += 1
1144
1154
  }
1145
1155
  end
1146
1156
  xml.RESULT {
1147
- xml.OK_ERROR 'OK'
1157
+ xml.OK_ERROR "OK"
1148
1158
  xml.NBR_RECORD nbr_records
1149
- xml.ERROR_CODE ''
1150
- xml.MESSAGE ''
1159
+ xml.ERROR_CODE ""
1160
+ xml.MESSAGE ""
1151
1161
  }
1152
1162
  }
1153
1163
  end
1154
- Oddb2xml.add_hash(_builder.to_xml)
1164
+ Oddb2xml.add_hash(a_builder.to_xml)
1155
1165
  end
1166
+
1156
1167
  def build_person
1157
1168
  nbr_records = 0
1158
1169
  Oddb2xml.log "build_person #{@people.size} persons"
1159
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
1170
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
1160
1171
  xml.doc.tag_suffix = @tag_suffix
1161
- datetime = Time.new.strftime('%FT%T%z')
1162
1172
  xml.Personen(XML_OPTIONS) {
1163
1173
  @people.each do |p|
1164
- xml.Person('DT' => '') {
1165
- xml.GLN_Person p[:gln] unless p[:gln].empty?
1166
- xml.Name p[:last_name] unless p[:last_name].empty?
1167
- xml.Vorname p[:first_name] unless p[:first_name].empty?
1168
- xml.PLZ p[:post] unless p[:post].empty?
1169
- xml.Ort p[:place] unless p[:place].empty?
1170
- xml.Bewilligungskanton p[:region] unless p[:region].empty?
1171
- xml.Land p[:country] unless p[:country].empty?
1174
+ xml.Person("DT" => "") {
1175
+ xml.GLN_Person p[:gln] unless p[:gln].empty?
1176
+ xml.Name p[:last_name] unless p[:last_name].empty?
1177
+ xml.Vorname p[:first_name] unless p[:first_name].empty?
1178
+ xml.PLZ p[:post] unless p[:post].empty?
1179
+ xml.Ort p[:place] unless p[:place].empty?
1180
+ xml.Bewilligungskanton p[:region] unless p[:region].empty?
1181
+ xml.Land p[:country] unless p[:country].empty?
1172
1182
  xml.Bewilligung_Selbstdispensation p[:license] unless p[:license].empty?
1173
- xml.Diplom p[:certificate] unless p[:certificate].empty?
1174
- xml.BTM_Berechtigung p[:authorization] unless p[:authorization].empty?
1183
+ xml.Diplom p[:certificate] unless p[:certificate].empty?
1184
+ xml.BTM_Berechtigung p[:authorization] unless p[:authorization].empty?
1175
1185
  nbr_records += 1
1176
1186
  }
1177
1187
  end
1178
1188
  xml.RESULT {
1179
- xml.OK_ERROR 'OK'
1189
+ xml.OK_ERROR "OK"
1180
1190
  xml.NBR_RECORD nbr_records
1181
- xml.ERROR_CODE ''
1182
- xml.MESSAGE ''
1191
+ xml.ERROR_CODE ""
1192
+ xml.MESSAGE ""
1183
1193
  }
1184
1194
  }
1185
1195
  end
1186
- Oddb2xml.add_hash(_builder.to_xml)
1196
+ Oddb2xml.add_hash(a_builder.to_xml)
1187
1197
  end
1198
+
1188
1199
  def detect_nincd(de_idx)
1189
1200
  if @lppvs[de_idx[:ean13].to_s] # LPPV
1190
1201
  20
1191
1202
  elsif @items[de_idx[:pharmacode]] # BAG-XML (SL/LS)
1192
1203
  10
1193
- elsif (de_idx[:migel] or # MiGel (xls)
1194
- de_idx[:_type] == :nonpharma) # MiGel (swissindex)
1204
+ elsif de_idx[:migel] || # MiGel (xls)
1205
+ (de_idx[:_type] == :nonpharma) # MiGel (swissindex)
1195
1206
  13
1196
1207
  else
1197
1208
  # fallback via EAN
1198
1209
  bag_entry_via_ean = @items.values.select do |item|
1199
1210
  next unless item[:packages]
1200
- item[:packages].values.select {|_pac| _pac[:ean13].to_s.eql?(de_idx[:ean13].to_s) }.length != 0
1211
+ item[:packages].values.count { |a_pac| a_pac[:ean13].to_s.eql?(de_idx[:ean13].to_s) } != 0
1201
1212
  end
1202
1213
  if bag_entry_via_ean.length > 0
1203
1214
  10
1204
- else
1205
- nil
1206
1215
  end
1207
1216
  end
1208
1217
  end
1209
1218
 
1210
1219
  ### --- see oddb2tdat
1211
1220
  DAT_LEN = {
1212
- :RECA => 2,
1213
- :CMUT => 1,
1214
- :PHAR => 7,
1215
- :ABEZ => 50,
1216
- :PRMO => 6,
1217
- :PRPU => 6,
1218
- :CKZL => 1,
1219
- :CLAG => 1,
1220
- :CBGG => 1,
1221
- :CIKS => 1,
1222
- :ITHE => 7,
1223
- :CEAN => 13,
1224
- :CMWS => 1,
1221
+ RECA: 2,
1222
+ CMUT: 1,
1223
+ PHAR: 7,
1224
+ ABEZ: 50,
1225
+ PRMO: 6,
1226
+ PRPU: 6,
1227
+ CKZL: 1,
1228
+ CLAG: 1,
1229
+ CBGG: 1,
1230
+ CIKS: 1,
1231
+ ITHE: 7,
1232
+ CEAN: 13,
1233
+ CMWS: 1
1225
1234
  }
1226
- def format_price(price_str, len=6, int_len=4, frac_len=2)
1227
- price = price_str.split('.')
1228
- pre = ''
1229
- las = ''
1230
- pre = "%0#{int_len}d" % (price[0] ? price[0] : '0')
1235
+ def format_price(price_str, len = 6, int_len = 4, frac_len = 2)
1236
+ price = price_str.split(".")
1237
+ pre = "%0#{int_len}d" % (price[0] || "0")
1231
1238
  las = if price[1]
1232
- if price[1].size < frac_len
1233
- price[1] + "0"*(frac_len-price[2].to_s.size)
1234
- else
1235
- price[1][0,frac_len]
1236
- end
1237
- else
1238
- '0'*frac_len
1239
- end
1240
- (pre.to_s + las.to_s)[0,len]
1239
+ if price[1].size < frac_len
1240
+ price[1] + "0" * (frac_len - price[2].to_s.size)
1241
+ else
1242
+ price[1][0, frac_len]
1243
+ end
1244
+ else
1245
+ "0" * frac_len
1246
+ end
1247
+ (pre.to_s + las.to_s)[0, len]
1241
1248
  end
1242
- def format_date(date_str, len=7)
1243
- date = date_str.gsub('.','')
1249
+
1250
+ def format_date(date_str, len = 7)
1251
+ date = date_str.delete(".")
1244
1252
  if date.size < len
1245
- date = date + '0'*(len-date.size)
1253
+ date += "0" * (len - date.size)
1246
1254
  end
1247
- date[0,len]
1255
+ date[0, len]
1248
1256
  end
1249
1257
 
1250
1258
  # The migel name must be always 50 chars wide and in ISO 8859-1 format
1251
1259
  def format_name(name, length)
1252
- ("%-#{length}s" % name)[0..length-1]
1260
+ ("%-#{length}s" % name)[0..length - 1]
1253
1261
  end
1262
+
1254
1263
  def build_dat
1255
1264
  prepare_articles
1256
1265
  rows = []
1257
1266
  @articles.each do |obj|
1258
- ean = obj[:ean13]
1259
- next if ((ean.to_s.length != 13) and !ean14)
1260
- next if obj[:type] == :nonpharma
1261
- row = ''
1262
- pack_info = nil
1263
- if (x = @packs.find{|k,v| v[:ean13].eql?(ean)})
1264
- pack_info = x[1]
1265
- end
1266
- # Oddb2tdat.parse
1267
- pac,no8 = nil,nil
1268
- if obj[:seq] and obj[:seq][:packages]
1269
- pac = obj[:seq][:packages][obj[:pharmacode]]
1270
- pac = obj[:seq][:packages][ean] unless pac
1271
- else
1272
- pac = @items[ean][:packages][ean] if @items and @items[ean] and @items[ean][:packages]
1273
- end
1274
- # :swissmedic_numbers
1275
- if pac
1276
- no8 = pac[:swissmedic_number8]
1277
- end
1278
- if pac and pac[:prices] == nil and no8
1279
- ppac = ((ppac = pack_info and ppac[:is_tier]) ? ppac : nil)
1280
- pac = ppac if ppac
1281
- end
1282
- row << "%#{DAT_LEN[:RECA]}s" % '11'
1283
- zur_rose = @infos_zur_rose[ean] # zurrose
1284
- if zur_rose && zur_rose[:cmut]
1285
- row << zur_rose[:cmut]
1286
- else
1287
- row << '1'
1288
- end
1289
- row << "%0#{DAT_LEN[:PHAR]}d" % obj[:pharmacode].to_i
1290
- abez = ( # de name
1291
- obj[:desc_de].to_s + " " +
1292
- (pac ? pac[:name_de].to_s : '') +
1293
- (obj[:quantity] ? obj[:quantity] : '')
1294
- ).gsub(/"/, '')
1295
- if @infos_zur_rose[ean]
1296
- price_exf = sprintf('%06i', ((@infos_zur_rose[ean][:price].to_f)*100).to_i)
1297
- price_public = sprintf('%06i', ((@infos_zur_rose[ean][:pub_price].to_f)*100).to_i)
1298
- if @options[:percent] != nil
1299
- price_public = sprintf('%06i', (price_exf.to_f*(1 + (@options[:percent].to_f/100))).round_by(0.05).round(2))
1300
- end
1301
- elsif pac and pac[:prices]
1302
- price_exf = sprintf('%06i', (pac[:prices][:exf_price][:price].to_f*100).to_i) if pac[:prices][:exf_price] and pac[:prices][:exf_price][:price]
1303
- price_public = sprintf('%06i', (pac[:prices][:pub_price][:price].to_f*100).to_i) if pac[:prices][:pub_price] and pac[:prices][:pub_price][:price]
1304
- end
1305
- row << format_name(Oddb2xml.patch_some_utf8(abez), DAT_LEN[:ABEZ])
1306
- if price_exf.to_s.length > DAT_LEN[:PRMO] ||
1307
- price_public.to_s.length > DAT_LEN[:PRPU]
1308
- puts "Price exfactory #{price_exf} or public #{price_public} is too high to be added into transfer.dat"
1309
- break
1267
+ ean = obj[:ean13]
1268
+ next if (ean.to_s.length != 13) && !ean14
1269
+ next if obj[:type] == :nonpharma
1270
+ row = ""
1271
+ pack_info = nil
1272
+ if (x = @packs.find { |k, v| v[:ean13].eql?(ean) })
1273
+ pack_info = x[1]
1274
+ end
1275
+ # Oddb2tdat.parse
1276
+ pac, no8 = nil, nil
1277
+ if obj[:seq] && obj[:seq][:packages]
1278
+ pac = obj[:seq][:packages][obj[:pharmacode]]
1279
+ pac ||= obj[:seq][:packages][ean]
1280
+ elsif @items && @items[ean] && @items[ean][:packages]
1281
+ pac = @items[ean][:packages][ean]
1282
+ end
1283
+ # :swissmedic_numbers
1284
+ if pac
1285
+ no8 = pac[:swissmedic_number8]
1286
+ end
1287
+ if pac && pac[:prices].nil? && no8
1288
+ ppac = ((ppac = pack_info) && ppac[:is_tier] ? ppac : nil)
1289
+ pac = ppac if ppac
1290
+ end
1291
+ row << "%#{DAT_LEN[:RECA]}s" % "11"
1292
+ zur_rose = @infos_zur_rose[ean] # zurrose
1293
+ row << if zur_rose && zur_rose[:cmut]
1294
+ zur_rose[:cmut]
1295
+ else
1296
+ "1"
1297
+ end
1298
+ row << "%0#{DAT_LEN[:PHAR]}d" % obj[:pharmacode].to_i
1299
+ abez = ( # de name
1300
+ obj[:desc_de].to_s + " " +
1301
+ (pac ? pac[:name_de].to_s : "") +
1302
+ (obj[:quantity] || "")
1303
+ ).delete('"')
1304
+ if @infos_zur_rose[ean]
1305
+ price_exf = sprintf("%06i", (@infos_zur_rose[ean][:price].to_f * 100).to_i)
1306
+ price_public = sprintf("%06i", (@infos_zur_rose[ean][:pub_price].to_f * 100).to_i)
1307
+ if !@options[:percent].nil?
1308
+ price_public = sprintf("%06i", (price_exf.to_f * (1 + (@options[:percent].to_f / 100))).round_by(0.05).round(2))
1310
1309
  end
1311
- row << "%#{DAT_LEN[:PRMO]}s" % (price_exf ? price_exf.to_s : ('0' * DAT_LEN[:PRMO]))
1312
- row << "%#{DAT_LEN[:PRPU]}s" % (price_public ? price_public.to_s : ('0' * DAT_LEN[:PRPU]))
1313
- row << "%#{DAT_LEN[:CKZL]}s" % if (@lppvs[ean])
1314
- '2'
1315
- elsif pac # sl_entry
1316
- '1'
1317
- else
1318
- '3'
1319
- end
1320
- row << "%#{DAT_LEN[:CLAG]}s" % if ppac && /Blutproduct|impfstoffe/.match(ppac[:list_code]) # COOL
1321
- '1'
1322
- else
1323
- '0'
1324
- end
1325
- row << "%#{DAT_LEN[:CBGG]}s" % if (pack_info && pack_info[:drug_index])
1326
- '3'
1327
- else
1328
- '0'
1329
- end
1330
- row << "%#{DAT_LEN[:CIKS]}s" % if (no8 && pack_info && !pack_info[:is_tier]) # Packungen.xls
1331
- pack_info[:swissmedic_category]
1332
- else
1333
- '0'
1334
- end.gsub(/(\+|\s)/, '')
1335
- row << "%0#{DAT_LEN[:ITHE]}d" % if (no8 && pack_info && !pack_info[:is_tier])
1336
- format_date(pack_info[:ith_swissmedic])
1337
- else
1338
- ('0' * DAT_LEN[:ITHE])
1339
- end.to_i
1340
- row << "%0#{DAT_LEN[:CEAN]}d" % (sprintf('%013d', ean.to_i).match(/^000000/) ? 0 : ean.to_i)
1341
- row << "%#{DAT_LEN[:CMWS]}s" % '2' # pharma
1342
- rows << row
1310
+ elsif pac && pac[:prices]
1311
+ price_exf = sprintf("%06i", (pac[:prices][:exf_price][:price].to_f * 100).to_i) if pac[:prices][:exf_price] && pac[:prices][:exf_price][:price]
1312
+ price_public = sprintf("%06i", (pac[:prices][:pub_price][:price].to_f * 100).to_i) if pac[:prices][:pub_price] && pac[:prices][:pub_price][:price]
1313
+ end
1314
+ row << format_name(Oddb2xml.patch_some_utf8(abez), DAT_LEN[:ABEZ])
1315
+ if price_exf.to_s.length > DAT_LEN[:PRMO] ||
1316
+ price_public.to_s.length > DAT_LEN[:PRPU]
1317
+ puts "Price exfactory #{price_exf} or public #{price_public} is too high to be added into transfer.dat"
1318
+ break
1319
+ end
1320
+ row << "%#{DAT_LEN[:PRMO]}s" % (price_exf ? price_exf.to_s : ("0" * DAT_LEN[:PRMO]))
1321
+ row << "%#{DAT_LEN[:PRPU]}s" % (price_public ? price_public.to_s : ("0" * DAT_LEN[:PRPU]))
1322
+ row << "%#{DAT_LEN[:CKZL]}s" % if @lppvs[ean]
1323
+ "2"
1324
+ elsif pac # sl_entry
1325
+ "1"
1326
+ else
1327
+ "3"
1328
+ end
1329
+ row << "%#{DAT_LEN[:CLAG]}s" % if ppac && /Blutproduct|impfstoffe/.match(ppac[:list_code]) # COOL
1330
+ "1"
1331
+ else
1332
+ "0"
1333
+ end
1334
+ row << "%#{DAT_LEN[:CBGG]}s" % if pack_info && pack_info[:drug_index]
1335
+ "3"
1336
+ else
1337
+ "0"
1338
+ end
1339
+ row << "%#{DAT_LEN[:CIKS]}s" % if no8 && pack_info && !pack_info[:is_tier] # Packungen.xls
1340
+ pack_info[:swissmedic_category]
1341
+ else
1342
+ "0"
1343
+ end.gsub(/(\+|\s)/, "")
1344
+ row << "%0#{DAT_LEN[:ITHE]}d" % if no8 && pack_info && !pack_info[:is_tier]
1345
+ format_date(pack_info[:ith_swissmedic])
1346
+ else
1347
+ ("0" * DAT_LEN[:ITHE])
1348
+ end.to_i
1349
+ row << "%0#{DAT_LEN[:CEAN]}d" % (/^000000/.match?(sprintf("%013d", ean.to_i)) ? 0 : ean.to_i)
1350
+ row << "%#{DAT_LEN[:CMWS]}s" % "2" # pharma
1351
+ rows << row
1343
1352
  end
1344
1353
  rows.join("\n")
1345
1354
  end
1355
+
1346
1356
  def build_with_migel_dat
1347
1357
  reset = true
1348
1358
  prepare_articles(reset)
1349
1359
  rows = []
1350
1360
  @articles.each do |obj|
1351
- row = ''
1352
- next if ((obj[:ean13].to_s.length != 13) and !ean14)
1353
- # Oddb2tdat.parse_migel
1354
- row << "%#{DAT_LEN[:RECA]}s" % '11'
1355
- row << "%#{DAT_LEN[:CMUT]}s" % if (phar = obj[:pharmacode] and phar.size > 3)
1356
- '1'
1357
- else
1358
- '3'
1359
- end
1360
- row << "%0#{DAT_LEN[:PHAR]}d" % obj[:pharmacode].to_i
1361
- abez = ( # de name
1362
- obj[:desc_de].to_s + " " +
1363
- (obj[:quantity] ? obj[:quantity] : '')
1364
- ).gsub(/"/, '')
1365
- row << format_name(Oddb2xml.patch_some_utf8(abez), DAT_LEN[:ABEZ])
1366
- row << '0' * DAT_LEN[:PRMO]
1367
- row << '0' * DAT_LEN[:PRPU]
1368
- row << "%#{DAT_LEN[:CKZL]}s" % '3' # sl_entry and lppv
1369
- row << "%#{DAT_LEN[:CLAG]}s" % '0'
1370
- row << "%#{DAT_LEN[:CBGG]}s" % '0'
1371
- row << "%#{DAT_LEN[:CIKS]}s" % ' ' # no category
1372
- row << "%0#{DAT_LEN[:ITHE]}d" % 0
1373
- row << obj[:ean13].to_s.rjust(DAT_LEN[:CEAN], '0')
1374
- row << "%#{DAT_LEN[:CMWS]}s" % '1' # nonpharma
1375
- rows << row
1376
- end
1361
+ row = ""
1362
+ next if (obj[:ean13].to_s.length != 13) && !ean14
1363
+ # Oddb2tdat.parse_migel
1364
+ row << "%#{DAT_LEN[:RECA]}s" % "11"
1365
+ row << "%#{DAT_LEN[:CMUT]}s" % if (phar = obj[:pharmacode]) && (phar.size > 3)
1366
+ "1"
1367
+ else
1368
+ "3"
1369
+ end
1370
+ row << "%0#{DAT_LEN[:PHAR]}d" % obj[:pharmacode].to_i
1371
+ abez = ( # de name
1372
+ obj[:desc_de].to_s + " " +
1373
+ (obj[:quantity] || "")
1374
+ ).delete('"')
1375
+ row << format_name(Oddb2xml.patch_some_utf8(abez), DAT_LEN[:ABEZ])
1376
+ row << "0" * DAT_LEN[:PRMO]
1377
+ row << "0" * DAT_LEN[:PRPU]
1378
+ row << "%#{DAT_LEN[:CKZL]}s" % "3" # sl_entry and lppv
1379
+ row << "%#{DAT_LEN[:CLAG]}s" % "0"
1380
+ row << "%#{DAT_LEN[:CBGG]}s" % "0"
1381
+ row << "%#{DAT_LEN[:CIKS]}s" % " " # no category
1382
+ row << "%0#{DAT_LEN[:ITHE]}d" % 0
1383
+ row << obj[:ean13].to_s.rjust(DAT_LEN[:CEAN], "0")
1384
+ row << "%#{DAT_LEN[:CMWS]}s" % "1" # nonpharma
1385
+ rows << row
1386
+ end
1377
1387
  rows.join("\n")
1378
1388
  end
1389
+
1379
1390
  def emit_salecd(xml, ean13, obj)
1380
1391
  zur_rose = nil
1381
1392
  if !@infos_zur_rose.empty? && ean13 && @infos_zur_rose[ean13]
1382
1393
  zur_rose = @infos_zur_rose[ean13] # zurrose
1383
1394
  end
1384
1395
  nincd = detect_nincd(obj)
1385
- in_refdata = !!( obj[:seq] && obj[:seq][:packages] && obj[:seq][:packages][ean13] && obj[:seq][:packages][ean13][:swissmedic_number8])
1386
- status = (nincd && nincd == 13) ? 'A' : (zur_rose && zur_rose[:cmut] != '3') ? 'A' : 'I'
1387
- if in_refdata && !'A'.eql?(status)
1396
+ in_refdata = !!(obj[:seq] && obj[:seq][:packages] && obj[:seq][:packages][ean13] && obj[:seq][:packages][ean13][:swissmedic_number8])
1397
+ status = if nincd && nincd == 13
1398
+ "A"
1399
+ else
1400
+ zur_rose && zur_rose[:cmut] != "3" ? "A" : "I"
1401
+ end
1402
+ if in_refdata && !"A".eql?(status)
1388
1403
  msg = "Overriding status #{status} nincd #{nincd} for #{ean13} as in refdata_pharma"
1389
1404
  # Oddb2xml.log msg
1390
1405
  @overriden_salecd << ean13
1391
- xml.SALECD('A') { xml.comment(msg)}
1406
+ xml.SALECD("A") { xml.comment(msg) }
1392
1407
  else
1393
- xml.SALECD(status) { xml.comment( "expiry_date #{obj[:expiry_date]}") if obj[:expiry_date] }
1408
+ xml.SALECD(status) { xml.comment("expiry_date #{obj[:expiry_date]}") if obj[:expiry_date] }
1394
1409
  end
1395
1410
  end
1396
1411
 
1397
1412
  def build_artikelstamm
1398
1413
  @@emitted_v5_gtins = []
1399
- @csv_file = CSV.open(File.join(WorkDir, "artikelstamm_#{Date.today.strftime('%d%m%Y')}_v5.csv"), "w+")
1400
- @csv_file << ['gtin', 'name', 'pkg_size', 'galenic_form', 'price_ex_factory', 'price_public', 'prodno', 'atc_code', 'active_substance', 'original', 'it-code', 'sl-liste']
1414
+ @csv_file = CSV.open(File.join(WORK_DIR, "artikelstamm_#{Date.today.strftime("%d%m%Y")}_v5.csv"), "w+")
1415
+ @csv_file << ["gtin", "name", "pkg_size", "galenic_form", "price_ex_factory", "price_public", "prodno", "atc_code", "active_substance", "original", "it-code", "sl-liste"]
1401
1416
  @csv_file.sync = true
1402
1417
  variant = "build_artikelstamm"
1403
1418
  # @infos_zur_rose.delete_if { |key, val| val[:cmut].eql?('3') } # collect only active zur rose item
1404
1419
  # No. Marco did not filter it, eg. 8804121 in rtikelstamm_oddb2xml_051217_v5.xm
1405
- def check_name(obj, lang = :de)
1406
- ean = obj[:ean13]
1407
- refdata = @refdata[ean]
1408
- if lang == :de
1409
- name = (refdata && refdata[:desc_de]) ? refdata[:desc_de] : obj[:sequence_name]
1410
- elsif lang == :fr
1411
- name = (refdata && refdata[:desc_fr]) ? refdata[:desc_fr] : obj[:sequence_name]
1412
- else
1413
- return '--missing--'
1420
+ self.class.class_eval do
1421
+ def check_article_name(obj, lang = :de)
1422
+ ean = obj[:ean13]
1423
+ refdata = @refdata[ean]
1424
+ if lang == :de
1425
+ name = refdata && refdata[:desc_de] ? refdata[:desc_de] : obj[:sequence_name]
1426
+ elsif lang == :fr
1427
+ name = refdata && refdata[:desc_fr] ? refdata[:desc_fr] : obj[:sequence_name]
1428
+ else
1429
+ return "--missing--"
1430
+ end
1431
+ return "--missing--" if !name || name.empty? || name.length < 3
1432
+ name[0..119] # limit to maximal 120 chars as specified in the XSD
1414
1433
  end
1415
- return '--missing--' if !name || name.empty? || name.length < 3
1416
- name
1417
1434
  end
1418
- def override(xml, id, field, default_value)
1419
- has_overrides = /\d{13}/.match(id.to_s) ? @@article_overrides[id.to_i] : @@product_overrides[id.to_i]
1420
- unless (has_overrides && has_overrides[field.to_s])
1421
- cmd = "xml.#{field} \"#{default_value.to_s.gsub('"','')}\""
1422
- else
1423
- new_value = has_overrides[field.to_s]
1424
- if new_value.to_s.eql?(default_value.to_s)
1425
- xml.comment('obsolete override')
1435
+ self.class.class_eval do
1436
+ def override(xml, id, field, default_value)
1437
+ has_overrides = /\d{13}/.match?(id.to_s) ? @@article_overrides[id.to_i] : @@product_overrides[id.to_i]
1438
+ if has_overrides && has_overrides[field.to_s]
1439
+ new_value = has_overrides[field.to_s]
1440
+ if new_value.to_s.eql?(default_value.to_s)
1441
+ xml.comment("obsolete override")
1442
+ else
1443
+ xml.comment("override #{default_value} with")
1444
+ end
1426
1445
  cmd = "xml.#{field} \"#{new_value}\""
1427
1446
  else
1428
- xml.comment("override #{default_value.to_s} with")
1429
- cmd ="xml.#{field} \"#{new_value}\""
1447
+ cmd = "xml.#{field} \"#{default_value.to_s.delete('"')}\""
1430
1448
  end
1449
+ eval cmd if default_value
1431
1450
  end
1432
- eval cmd if default_value
1433
1451
  end
1434
- def emit_items(xml)
1435
- nr_items = 0
1436
- gtins_to_article = {}
1437
- @articles.each {|article| gtins_to_article[article[:ean13]] = article }
1438
- sl_gtins = @items.values.collect{|x| x[:packages].keys}.flatten.uniq;
1439
- gtins = gtins_to_article.keys + @infos_zur_rose.keys + @packs.values.collect{|x| x[:ean13]} + sl_gtins
1440
- gtins = (gtins-@@gtin2ignore)
1441
- gtins.sort!.uniq!
1442
- gtins.each do |ean13|
1443
- pac,no8 = nil,ean13.to_s[4..11] # BAG-XML(SL/LS)
1444
- next if ean13 == 0
1445
- obj = gtins_to_article[ean13] || @items.values.find{|x| x[:packages].keys.index(ean13) } || @infos_zur_rose[ean13]
1446
- if obj
1447
- obj = @packs[no8].merge(obj) if @packs[no8]
1448
- else
1449
- obj = @packs[no8] # obj not yet in refdata. Use data from swissmedic_package.xlsx
1450
- end
1451
- nr_items += 1
1452
- Oddb2xml.log "build_artikelstamm #{ean13}: #{nr_items} of #{gtins.size} articles" if nr_items % 5000 == 0
1453
- item = @items[ean13]
1454
- pack_info = nil
1455
- pack_info = @packs[no8] if no8 && /#{ean13}/.match(@packs[no8].to_s) # info from Packungen.xlsx from swissmedic_info
1456
- next if pack_info && /Tierarzneimittel/.match(pack_info[:list_code])
1457
- next if obj[:desc_de] && /ad us vet/i.match(obj[:desc_de])
1458
- sequence = obj[:seq]
1459
- if sequence.nil? && @packs[no8] && /#{ean13}/.match(@packs[no8].to_s)
1460
- sequence = {:packages =>{ean13 => @packs[no8]}}
1461
- obj[:seq] = sequence.clone
1462
- end
1463
- if sequence.nil? && @items[ean13] && @items[ean13][:packages][ean13]
1464
- sequence = @items[ean13]
1465
- end
1466
- if sequence
1467
- if obj[:seq] && !obj[:seq][:packages].keys.index(ean13)
1468
- # puts "unable to find #{ean13} in #{obj[:seq][:packages].keys}"
1469
- next
1452
+ self.class.class_eval do
1453
+ def emit_items(xml)
1454
+ nr_items = 0
1455
+ gtins_to_article = {}
1456
+ @articles.each { |article| gtins_to_article[article[:ean13]] = article }
1457
+ sl_gtins = @items.values.collect { |x| x[:packages].keys }.flatten.uniq
1458
+ gtins = gtins_to_article.keys + @infos_zur_rose.keys + @packs.values.collect { |x| x[:ean13] } + sl_gtins
1459
+ gtins = (gtins - @@gtin2ignore)
1460
+ gtins.sort!.uniq!
1461
+ gtins.each do |ean13|
1462
+ no8 = ean13.to_s[4..11] # BAG-XML(SL/LS)
1463
+ next if ean13 == 0
1464
+ obj = gtins_to_article[ean13] || @items.values.find { |x| x[:packages].keys.index(ean13) } || @infos_zur_rose[ean13]
1465
+ if obj
1466
+ obj = @packs[no8].merge(obj) if @packs[no8]
1467
+ else
1468
+ obj = @packs[no8] # obj not yet in refdata. Use data from swissmedic_package.xlsx
1470
1469
  end
1471
- sequence[:packages].each do |gtin, package|
1472
- pkg_gtin = package[:ean13].clone
1473
- if package[:no8] && (newEan13 = Oddb2xml.getEan13forNo8(package[:no8]))
1474
- if !newEan13.eql?(pkg_gtin)
1475
- puts "Setting #{newEan13} for #{pkg_gtin}"
1476
- pkg_gtin = newEan13
1477
- end
1478
- end
1479
- pharma_code = @refdata[pkg_gtin]
1480
- if @refdata[pkg_gtin] && @refdata[pkg_gtin][:pharmacode]
1481
- pharma_code = @refdata[pkg_gtin][:pharmacode]
1482
- elsif obj[:pharmacode]
1483
- pharma_code = obj[:pharmacode]
1484
- elsif @infos_zur_rose[ean13]
1485
- pharma_code = @infos_zur_rose[ean13][:pharmacode]
1486
- end
1487
- info = @calc_items[pkg_gtin]
1488
- if @@emitted_v5_gtins.index(pkg_gtin)
1470
+ nr_items += 1
1471
+ Oddb2xml.log "build_artikelstamm #{ean13}: #{nr_items} of #{gtins.size} articles" if nr_items % 5000 == 0
1472
+ item = @items[ean13]
1473
+ pack_info = nil
1474
+ pack_info = @packs[no8] if no8 && /#{ean13}/.match(@packs[no8].to_s) # info from Packungen.xlsx from swissmedic_info
1475
+ next if pack_info && /Tierarzneimittel/.match(pack_info[:list_code])
1476
+ next if obj[:desc_de] && /ad us vet/i.match(obj[:desc_de])
1477
+ sequence = obj[:seq]
1478
+ if sequence.nil? && @packs[no8] && /#{ean13}/.match(@packs[no8].to_s)
1479
+ sequence = {packages: {ean13 => @packs[no8]}}
1480
+ obj[:seq] = sequence.clone
1481
+ end
1482
+ if sequence.nil? && @items[ean13] && @items[ean13][:packages][ean13]
1483
+ sequence = @items[ean13]
1484
+ end
1485
+ if sequence
1486
+ if obj[:seq] && !obj[:seq][:packages].keys.index(ean13)
1487
+ # puts "unable to find #{ean13} in #{obj[:seq][:packages].keys}"
1489
1488
  next
1490
- else
1491
- @@emitted_v5_gtins << pkg_gtin.clone
1492
1489
  end
1493
- options = {'PHARMATYPE' => 'P'}
1494
- xml.ITEM(options) do
1495
- name = item[:name_de] + ' ' + item[:desc_de].strip + ' ' + package[:desc_de] if package && package[:desc_de]
1496
- name ||= @refdata[pkg_gtin] ? @refdata[pkg_gtin][:desc_de] : nil
1497
- name ||= @infos_zur_rose[ean13][:description] if @infos_zur_rose[ean13]
1498
- name ||= obj[:name_de] + ', ' + obj[:desc_de].strip if obj[:name_de]
1499
- name ||= (item[:desc_de] + item[:name_de]) if item
1500
- name ||= obj[:sequence_name]
1501
- xml.GTIN pkg_gtin.to_s.rjust(13, '0')
1502
- override(xml, pkg_gtin, :PHAR, pharma_code)
1503
- xml.SALECD('A')
1504
- # maxLength for DSCR is 50 for Artikelstamm v3
1505
- xml.DSCR(name) # for description for zur_rose
1506
- name_fr = item[:name_fr] + ' ' + item[:desc_fr].strip + ' ' + package[:desc_fr] if package && package[:desc_fr]
1507
- name_fr ||= @refdata[pkg_gtin] ? @refdata[pkg_gtin][:desc_fr] : nil
1508
- # Zugelassenen Packungen has only german names
1509
- name_fr ||= (obj[:name_fr] + ', ' + obj[:desc_fr]).strip if obj[:name_fr]
1510
- # ZuRorse has only german names
1511
- name_fr ||= (item[:name_fr] + ', ' + item[:desc_fr]) if item
1512
- name_fr ||= name
1513
- xml.DSCRF(name_fr)
1514
- xml.COMP do # Manufacturer
1515
- xml.NAME obj[:company_name]
1516
- xml.GLN obj[:company_ean]
1517
- end if obj[:company_name] || obj[:company_ean]
1518
- pexf = ppub = nil
1519
- if package[:prices]
1520
- pexf ||= package[:prices][:exf_price][:price]
1521
- ppub ||= package[:prices][:pub_price][:price]
1522
- elsif @items[ean13] && @items[ean13][:packages] && @items[ean13][:packages][ean13] && (bag_prices = @items[ean13][:packages][ean13][:prices])
1523
- pexf ||= bag_prices[:exf_price][:price]
1524
- ppub ||= bag_prices[:pub_price][:price]
1490
+ sequence[:packages].each do |gtin, package|
1491
+ pkg_gtin = package[:ean13].clone
1492
+ if package[:no8] && (new_ean_13 = Oddb2xml.getEan13forNo8(package[:no8]))
1493
+ if !new_ean_13.eql?(pkg_gtin)
1494
+ puts "Setting #{new_ean_13} for #{pkg_gtin}"
1495
+ pkg_gtin = new_ean_13
1496
+ end
1497
+ end
1498
+ info = @calc_items[pkg_gtin]
1499
+ if @@emitted_v5_gtins.index(pkg_gtin)
1500
+ next
1525
1501
  else
1526
- pexf ||= obj[:price]
1527
- ppub ||= obj[:pub_price]
1502
+ @@emitted_v5_gtins << pkg_gtin.clone
1528
1503
  end
1529
- ppub = nil if ppub && ppub.size == 0
1530
- pexf = nil if pexf && pexf.size == 0
1531
- xml.PEXF pexf if pexf
1532
- xml.PPUB ppub if ppub
1533
- measure = ''
1534
- if info
1535
- # MEASSURE Measurement Unit,e.g. Pills or milliliters
1536
- # <DSCR>HIRUDOID Creme 3 mg/g 40 g</DSCR>
1537
- xml.PKG_SIZE info.pkg_size.to_i if info.pkg_size
1538
- if info.measure
1539
- measure = info.measure
1540
- elsif info.pkg_size && info.unit
1541
- measure = info.pkg_size + ' ' + info.unit
1542
- elsif info.pkg_size
1543
- measure = info.pkg_size
1504
+ options = {"PHARMATYPE" => "P"}
1505
+ xml.ITEM(options) do
1506
+ name = item[:name_de] + " " + item[:desc_de].strip + " " + package[:desc_de] if package && package[:desc_de]
1507
+ name ||= @refdata[pkg_gtin] ? @refdata[pkg_gtin][:desc_de] : nil
1508
+ name ||= @infos_zur_rose[ean13][:description] if @infos_zur_rose[ean13]
1509
+ name ||= obj[:name_de] + ", " + obj[:desc_de].strip if obj[:name_de]
1510
+ name ||= (item[:desc_de] + item[:name_de]) if item
1511
+ name ||= obj[:sequence_name]
1512
+ xml.GTIN pkg_gtin.to_s.rjust(13, "0")
1513
+ xml.SALECD("A")
1514
+ # maxLength for DSCR is 50 for Artikelstamm v3
1515
+ xml.DSCR(name) # for description for zur_rose
1516
+ name_fr = item[:name_fr] + " " + item[:desc_fr].strip + " " + package[:desc_fr] if package && package[:desc_fr]
1517
+ name_fr ||= @refdata[pkg_gtin] ? @refdata[pkg_gtin][:desc_fr] : nil
1518
+ # Zugelassenen Packungen has only german names
1519
+ name_fr ||= (obj[:name_fr] + ", " + obj[:desc_fr]).strip if obj[:name_fr]
1520
+ # ZuRorse has only german names
1521
+ name_fr ||= (item[:name_fr] + ", " + item[:desc_fr]) if item
1522
+ name_fr ||= name
1523
+ xml.DSCRF(name_fr)
1524
+ if obj[:company_name] || obj[:company_ean]
1525
+ xml.COMP do # Manufacturer
1526
+ xml.NAME obj[:company_name][0..99] # limit to 100 chars as in XSD
1527
+ xml.GLN obj[:company_ean]
1528
+ end
1544
1529
  end
1545
- xml.MEASURE measure
1546
- xml.MEASUREF measure
1547
- # Die Darreichungsform dieses Items. zB Tablette(n) oder Spritze(n)
1548
- xml.DOSAGE_FORM info.galenic_form.descriptions['de'] if info.galenic_form.descriptions['de']
1549
- xml.DOSAGE_FORMF info.galenic_form.descriptions['fr'] if info.galenic_form.descriptions['fr']
1550
- end
1551
- xml.SL_ENTRY 'true' if sl_gtins.index(pkg_gtin)
1552
- xml.IKSCAT package[:swissmedic_category] if package[:swissmedic_category] && package[:swissmedic_category].length > 0
1553
- xml.GENERIC_TYPE sequence[:org_gen_code] if sequence[:org_gen_code] && !sequence[:org_gen_code].empty?
1554
- xml.LPPV 'true' if @lppvs[pkg_gtin.to_s] # detect_nincd
1555
- case item[:deductible]
1556
- when 'Y'; xml.DEDUCTIBLE 20; # 20%
1557
- when 'N'; xml.DEDUCTIBLE 10; # 10%
1558
- end if item && item[:deductible]
1559
- prodno = Oddb2xml.getProdnoForEan13(pkg_gtin)
1560
- atc = package[:atc_code]
1561
- atc ||= @refdata[pkg_gtin][:seq][:atc_code] if @refdata[pkg_gtin]
1562
- unless prodno # find a prodno from packages for vaccinations
1563
- if atc && /^J07/.match(atc) && !/^J07AX/.match(atc)
1564
- pack = @packs.values.find{ |v| v && v[:atc_code].eql?(atc)}
1565
- if pack
1566
- prodno = pack[:prodno]
1567
- Oddb2xml.log "Patching vaccination for #{pkg_gtin} #{atc} #{name} via prodno #{prodno}"
1568
- else
1569
- Oddb2xml.log "unable to find a pack/prodno for vaccination for #{pkg_gtin} #{atc} #{name}"
1530
+ pexf = ppub = nil
1531
+ if package[:prices]
1532
+ pexf ||= package[:prices][:exf_price][:price]
1533
+ ppub ||= package[:prices][:pub_price][:price]
1534
+ elsif @items[ean13] && @items[ean13][:packages] && @items[ean13][:packages][ean13] && (bag_prices = @items[ean13][:packages][ean13][:prices])
1535
+ pexf ||= bag_prices[:exf_price][:price]
1536
+ ppub ||= bag_prices[:pub_price][:price]
1537
+ else
1538
+ pexf ||= obj[:price]
1539
+ ppub ||= obj[:pub_price]
1540
+ end
1541
+ ppub = nil if ppub && ppub.size == 0
1542
+ pexf = nil if pexf && pexf.size == 0
1543
+ if !(obj[:price] && !obj[:price].empty?) || !(obj[:pub_price] && !obj[:pub_price].empty?)
1544
+ zur_rose_detail = @infos_zur_rose.values.find { |x| x[:ean13].to_i == ean13.to_i }
1545
+ if zur_rose_detail
1546
+ pexf ||= zur_rose_detail[:price]
1547
+ ppub ||= zur_rose_detail[:pub_price]
1548
+ end
1549
+ end
1550
+ xml.PEXF pexf if pexf
1551
+ xml.PPUB ppub if ppub
1552
+ measure = ""
1553
+ if info
1554
+ # MEASSURE Measurement Unit,e.g. Pills or milliliters
1555
+ # <DSCR>HIRUDOID Creme 3 mg/g 40 g</DSCR>
1556
+ xml.PKG_SIZE info.pkg_size.to_i if info.pkg_size
1557
+ if info.measure
1558
+ measure = info.measure
1559
+ elsif info.pkg_size && info.unit
1560
+ measure = info.pkg_size + " " + info.unit
1561
+ elsif info.pkg_size
1562
+ measure = info.pkg_size
1570
1563
  end
1564
+ xml.MEASURE measure
1565
+ xml.MEASUREF measure
1566
+ # Die Darreichungsform dieses Items. zB Tablette(n) oder Spritze(n)
1567
+ xml.DOSAGE_FORM info.galenic_form.descriptions["de"] if info.galenic_form.descriptions["de"]
1568
+ xml.DOSAGE_FORMF info.galenic_form.descriptions["fr"] if info.galenic_form.descriptions["fr"]
1571
1569
  end
1570
+ xml.SL_ENTRY "true" if sl_gtins.index(pkg_gtin)
1571
+ xml.IKSCAT package[:swissmedic_category] if package[:swissmedic_category] && package[:swissmedic_category].length > 0
1572
+ xml.GENERIC_TYPE sequence[:org_gen_code] if sequence[:org_gen_code] && !sequence[:org_gen_code].empty?
1573
+ xml.LPPV "true" if @lppvs[pkg_gtin.to_s] # detect_nincd
1574
+ if item && item[:deductible]
1575
+ case item[:deductible]
1576
+ when "Y" then xml.DEDUCTIBLE 20; # 20%
1577
+ when "N" then xml.DEDUCTIBLE 10; # 10%
1578
+ end
1579
+ end
1580
+ prodno = Oddb2xml.getProdnoForEan13(pkg_gtin)
1581
+ atc = package[:atc_code]
1582
+ refdata_atc = @refdata[pkg_gtin][:atc_code] if @refdata && @refdata[pkg_gtin] && @refdata[pkg_gtin]
1583
+ if refdata_atc && atc.nil?
1584
+ puts "WARNING: #{pkg_gtin} ATC-code from refdata #{refdata_atc} as Swissmedic ATC is nil #{name}"
1585
+ atc = refdata_atc
1586
+ end
1587
+ unless prodno # find a prodno from packages for vaccinations
1588
+ if atc && /^J07/.match(atc) && !/^J07AX/.match(atc)
1589
+ pack = @packs.values.find { |v| v && v[:atc_code].eql?(atc) }
1590
+ if pack
1591
+ prodno = pack[:prodno]
1592
+ Oddb2xml.log "Patching vaccination for #{pkg_gtin} #{atc} #{name} via prodno #{prodno}"
1593
+ else
1594
+ Oddb2xml.log "unable to find a pack/prodno for vaccination for #{pkg_gtin} #{atc} #{name}"
1595
+ end
1596
+ end
1597
+ end
1598
+ xml.PRODNO prodno if prodno
1599
+ @csv_file << [pkg_gtin, name, package[:unit], measure,
1600
+ pexf || "",
1601
+ ppub || "",
1602
+ prodno, atc, package[:substance_swissmedic],
1603
+ sequence[:org_gen_code], package[:ith_swissmedic],
1604
+ @items[pkg_gtin] ? "SL" : ""]
1572
1605
  end
1573
- xml.PRODNO prodno if prodno
1574
- csv = []
1575
- @csv_file << [pkg_gtin, name, package[:unit], measure,
1576
- pexf ? pexf : '',
1577
- ppub ? ppub : '',
1578
- prodno, atc, package[:substance_swissmedic],
1579
- sequence[:org_gen_code], package[:ith_swissmedic],
1580
- @items[pkg_gtin] ? 'SL' : '',
1581
- ]
1582
1606
  end
1583
- end
1584
- else # non pharma
1585
- if @@emitted_v5_gtins.index(ean13)
1586
- next
1587
- else
1588
- @@emitted_v5_gtins << ean13.clone
1589
- end
1590
- # Set the pharmatype to 'Y' for outdated products, which are no longer found
1591
- # in refdata/packungen
1592
- chap70 = nil
1593
- if @chapter70items.values.find {|x| x[:pharmacode] && x[:pharmacode].eql?(obj[:pharmacode])}
1594
- Oddb2xml.log "found chapter #{obj[:pharmacode]}" if $VERBOSE
1595
- chap70 = true
1596
- end
1597
- patched_pharma_type = (/^7680/.match(ean13.to_s.rjust(13, '0')) || chap70 ? 'P': 'N' )
1598
- next if /^#{Oddb2xml::FAKE_GTIN_START}/.match(ean13.to_s)
1599
- xml.ITEM({'PHARMATYPE' => patched_pharma_type }) do
1600
- xml.GTIN ean13.to_s.rjust(13, '0')
1601
- xml.PHAR obj[:pharmacode]
1602
- emit_salecd(xml, ean13, obj)
1603
- description = obj[:desc_de] || obj[:description] # for description for zur_rose
1604
- xml.DSCR(description)
1605
- xml.DSCRF(obj[:desc_fr] || '--missing--')
1606
- xml.COMP do
1607
- xml.GLN obj[:company_ean]
1608
- end if obj[:company_ean] && !obj[:company_ean].empty?
1609
- if !(obj[:price] && !obj[:price].empty?) || !(obj[:pub_price] && !obj[:pub_price].empty?)
1610
- zur_rose_detail = @infos_zur_rose.values.find{|x| x[:ean13].to_i == ean13.to_i}
1607
+ else # non pharma
1608
+ if @@emitted_v5_gtins.index(ean13)
1609
+ next
1610
+ else
1611
+ @@emitted_v5_gtins << ean13.clone
1611
1612
  end
1612
- ppub = nil; pexf=nil
1613
- if obj[:price] && !obj[:price].empty?
1614
- xml.PEXF (pexf = obj[:price])
1615
- elsif zur_rose_detail
1616
- if zur_rose_detail[:price] && !zur_rose_detail[:price].empty? && !zur_rose_detail[:price].eql?('0.00')
1617
- Oddb2xml.log "NonPharma: #{ean13} adding PEXF #{zur_rose_detail[:price]} #{description}"
1618
- xml.PEXF (pexf = zur_rose_detail[:price])
1619
- end
1613
+ # Set the pharmatype to 'Y' for outdated products, which are no longer found
1614
+ # in refdata/packungen
1615
+ chap70 = nil
1616
+ if @chapter70items.values.find { |x| x[:pharmacode]&.eql?(obj[:pharmacode]) }
1617
+ Oddb2xml.log "found chapter #{obj[:pharmacode]}" if $VERBOSE
1618
+ chap70 = true
1620
1619
  end
1621
- if obj[:pub_price] && !obj[:pub_price].empty?
1622
- xml.PPUB (ppub = obj[:pub_price])
1623
- elsif zur_rose_detail
1624
- if zur_rose_detail[:pub_price] && !zur_rose_detail[:pub_price].empty? && !zur_rose_detail[:pub_price].eql?('0.00')
1625
- Oddb2xml.log "NonPharma: #{ean13} adding PPUB #{zur_rose_detail[:pub_price]} #{description}"
1626
- xml.PPUB (ppub = zur_rose_detail[:pub_price])
1620
+ patched_pharma_type = (/^7680/.match(ean13.to_s.rjust(13, "0")) || chap70 ? "P" : "N")
1621
+ next if /^#{Oddb2xml::FAKE_GTIN_START}/o.match?(ean13.to_s)
1622
+ next if obj[:data_origin].eql?("zur_rose") && /^7680/.match(ean13) # must skip inactiv items
1623
+ xml.ITEM({"PHARMATYPE" => patched_pharma_type}) do
1624
+ xml.GTIN ean13.to_s.rjust(13, "0")
1625
+ if obj[:pharmacode] && obj[:pharmacode].length > 0
1626
+ xml.PHAR obj[:pharmacode]
1627
+ elsif (zur_rose = @infos_zur_rose[ean13])
1628
+ puts "Artikelstamm: Adding #{zur_rose[:pharmacode]} to article GTIN #{ean13}"
1629
+ xml.PHAR zur_rose[:pharmacode]
1630
+ elsif /^7680/.match?(ean13)
1631
+ puts "Artikelstamm: No pharmacode for article GTIN #{ean13} via ZurRose"
1632
+ end
1633
+ emit_salecd(xml, ean13, obj)
1634
+ description = obj[:desc_de] || obj[:description] # for description for zur_rose
1635
+ xml.DSCR(description)
1636
+ xml.DSCRF(obj[:desc_fr] || "--missing--")
1637
+ if obj[:company_ean] && !obj[:company_ean].empty?
1638
+ xml.COMP do
1639
+ xml.GLN obj[:company_ean]
1640
+ end
1641
+ end
1642
+ if !(obj[:price] && !obj[:price].empty?) || !(obj[:pub_price] && !obj[:pub_price].empty?)
1643
+ zur_rose_detail = @infos_zur_rose.values.find { |x| x[:ean13].to_i == ean13.to_i }
1644
+ end
1645
+ ppub = nil
1646
+ pexf = nil
1647
+ if obj[:price] && !obj[:price].empty?
1648
+ xml.PEXF(pexf = obj[:price])
1649
+ elsif zur_rose_detail
1650
+ if zur_rose_detail[:price] && !zur_rose_detail[:price].empty? && !zur_rose_detail[:price].eql?("0.00")
1651
+ # Oddb2xml.log "NonPharma: #{ean13} adding PEXF #{zur_rose_detail[:price]} #{description}"
1652
+ xml.PEXF(pexf = zur_rose_detail[:price])
1653
+ end
1654
+ end
1655
+ if obj[:pub_price] && !obj[:pub_price].empty?
1656
+ xml.PPUB(ppub = obj[:pub_price])
1657
+ elsif zur_rose_detail
1658
+ if zur_rose_detail[:pub_price] && !zur_rose_detail[:pub_price].empty? && !zur_rose_detail[:pub_price].eql?("0.00")
1659
+ # Oddb2xml.log "NonPharma: #{ean13} adding PPUB #{zur_rose_detail[:pub_price]} #{description}"
1660
+ xml.PPUB(ppub = zur_rose_detail[:pub_price])
1661
+ end
1662
+ end
1663
+ @csv_file << [ean13, description, "", "", pexf, ppub, "", "", "", "", "", ""]
1664
+ if chap70
1665
+ xml.comment "Chapter70 hack #{ean13.to_s.rjust(13, "0")} #{description.encode(xml: :text).gsub("--", "-")}"
1666
+ xml.SL_ENTRY "true"
1667
+ xml.PRODNO obj[:pharmacode]
1627
1668
  end
1628
- end
1629
- @csv_file << [ ean13, description, '', '', pexf, ppub, '', '', '', '', '', '' ]
1630
- if chap70
1631
- xml.comment "Chapter70 hack"
1632
- xml.SL_ENTRY 'true'
1633
- xml.PRODNO obj[:pharmacode]
1634
- xml.Chapter70_HACK 'true'
1635
1669
  end
1636
1670
  end
1637
1671
  end
1672
+ @csv_file.close if @csv_file && !@csv_file.closed?
1673
+ nr_items
1638
1674
  end
1639
- @csv_file.close if @csv_file && !@csv_file.closed?
1640
- nr_items
1641
1675
  end
1642
1676
  unless @prepared
1643
- require 'oddb2xml/chapter_70_hack'
1644
- Oddb2xml::Chapter70xtractor.parse()
1677
+ require "oddb2xml/chapter_70_hack"
1678
+ Oddb2xml::Chapter70xtractor.parse
1645
1679
  @chapter70items = Oddb2xml::Chapter70xtractor.items
1646
1680
  prepare_limitations
1647
1681
  prepare_articles
@@ -1650,33 +1684,25 @@ module Oddb2xml
1650
1684
  prepare_calc_items(suppress_composition_parsing: true)
1651
1685
  @prepared = true
1652
1686
  @old_rose_size = @infos_zur_rose.size
1653
- @infos_zur_rose.each do |ean13, value|
1654
- if /^7680/.match(ean13.to_s) && @options[:artikelstamm]
1655
- @infos_zur_rose.delete(ean13)
1656
- end
1657
- end if false
1658
- @new_rose_size = @infos_zur_rose.size
1659
1687
  end
1660
1688
  nr_products = 0
1661
1689
  nr_articles = 0
1662
1690
  @nr_articles = 0
1663
1691
  used_limitations = []
1664
- Oddb2xml.log "#{variant}: Deleted #{@old_rose_size - @new_rose_size} entries from ZurRose where GTIN start with 7680 (Swissmedic)"
1665
1692
  # Oddb2xml.log "#{variant} #{nr_products} of #{@products.size} articles and ignore #{@@gtin2ignore.size} gtins specified via #{@@ignore_file}"
1666
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
1693
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
1667
1694
  xml.doc.tag_suffix = @tag_suffix
1668
- datetime = Time.new.strftime('%FT%T%z')
1669
1695
  elexis_strftime_format = "%FT%T\.%L%:z"
1670
- @@cumul_ver = (Date.today.year-2013)*12+Date.today.month
1671
- options_xml = {
1672
- 'xmlns' => 'http://elexis.ch/Elexis_Artikelstamm_v5',
1673
- 'CREATION_DATETIME' => Time.new.strftime(elexis_strftime_format),
1674
- 'BUILD_DATETIME' => Time.new.strftime(elexis_strftime_format),
1675
- 'DATA_SOURCE' => 'oddb2xml'
1696
+ @@cumul_ver = (Date.today.year - 2013) * 12 + Date.today.month
1697
+ options_xml = {
1698
+ "xmlns" => "http://elexis.ch/Elexis_Artikelstamm_v5",
1699
+ "CREATION_DATETIME" => Time.new.strftime(elexis_strftime_format),
1700
+ "BUILD_DATETIME" => Time.new.strftime(elexis_strftime_format),
1701
+ "DATA_SOURCE" => "oddb2xml"
1676
1702
  }
1677
1703
  emitted_prodno = []
1678
1704
  no8_to_prodno = {}
1679
- @packs.collect{ |key, val| no8_to_prodno[key] = val [:prodno] }
1705
+ @packs.collect { |key, val| no8_to_prodno[key] = val [:prodno] }
1680
1706
  xml.comment("Produced by #{__FILE__} version #{VERSION} at #{Time.now}")
1681
1707
  xml.ARTIKELSTAMM(options_xml) do
1682
1708
  xml.PRODUCTS do
@@ -1684,22 +1710,22 @@ module Oddb2xml
1684
1710
  products.each do |product|
1685
1711
  ean13 = product[0]
1686
1712
  obj = product[1]
1687
- next if /^Q/i.match(obj[:atc])
1713
+ next if /^Q/i.match?(obj[:atc])
1688
1714
  ean = obj[:ean13]
1689
1715
  sequence = obj[:seq]
1690
1716
  sequence ||= @products[ean][:seq] if @products[ean]
1691
- next unless check_name(obj, :de)
1692
- ppac = ((_ppac = @packs[ean.to_s[4..11]] and !_ppac[:is_tier]) ? _ppac : {})
1693
- prodno = ppac[:prodno] if ppac[:prodno] and !ppac[:prodno].empty?
1717
+ next unless check_article_name(obj, :de)
1718
+ ppac = ((a_ppac = @packs[ean.to_s[4..11]]) && !a_ppac[:is_tier] ? a_ppac : {})
1719
+ prodno = ppac[:prodno] if ppac[:prodno] && !ppac[:prodno].empty?
1694
1720
  prodno = obj[:pharmacode] if obj[:chapter70]
1695
- myPack = @packs.values.find{ |x| x[:iksnr].to_i == obj[:seq][:swissmedic_number5].to_i } if obj[:seq]
1696
- if myPack && !prodno
1697
- prodno ||= myPack[:prodno]
1698
- puts "Setting prodno #{prodno} for #{ean13} #{myPack[:sequence_name]}"
1721
+ my_pack = @packs.values.find { |x| x[:iksnr].to_i == obj[:seq][:swissmedic_number5].to_i } if obj[:seq]
1722
+ if my_pack && !prodno
1723
+ prodno ||= my_pack[:prodno]
1724
+ puts "Setting prodno #{prodno} for #{ean13} #{my_pack[:sequence_name]}"
1699
1725
  end
1700
1726
  next unless prodno
1701
1727
  next if emitted_prodno.index(prodno)
1702
- sequence ||= @articles.find{|x| x[:ean13].eql?(ean)}
1728
+ sequence ||= @articles.find { |x| x[:ean13].eql?(ean) }
1703
1729
  unless obj[:chapter70]
1704
1730
  next unless sequence && (sequence[:name_de] || sequence[:desc_de])
1705
1731
  if Oddb2xml.getEan13forProdno(prodno).size == 0 && !obj[:no8].eql?(Oddb2xml.getNo8ForEan13(ean))
@@ -1712,44 +1738,43 @@ module Oddb2xml
1712
1738
  xml.PRODUCT do
1713
1739
  xml.PRODNO prodno
1714
1740
  if sequence
1715
- xml.SALECD('A') # these products are always active!
1741
+ xml.SALECD("A") # these products are always active!
1716
1742
  name_de = "#{sequence[:name_de]} #{sequence[:desc_de]}".strip if sequence[:name_de]
1717
- unless name_de # eg. 7680002770014 Coeur-Vaisseaux Sérocytol, suppositoire
1718
- if ppac && /stk/i.match( sequence[:desc_de])
1719
- name_de = ppac[:sequence_name]
1720
- else
1721
- name_de = sequence[:desc_de]
1722
- end
1743
+ name_de ||= if ppac && /stk/i.match(sequence[:desc_de])
1744
+ ppac[:sequence_name]
1745
+ else
1746
+ sequence[:desc_de]
1723
1747
  end
1724
1748
  name_fr = "#{sequence[:name_fr]} #{sequence[:desc_fr]}".strip if sequence[:name_fr]
1725
1749
  name_fr ||= (ppac && ppac[:sequence_name])
1726
- override(xml, prodno, :DSCR, name_de.strip)
1750
+ override(xml, prodno, :DSCR, name_de.strip)
1727
1751
  override(xml, prodno, :DSCRF, name_fr.strip)
1752
+ # use overriden ATC if possibel
1753
+ atc = sequence[:atc] || sequence[:atc_code]
1754
+ xml.ATC atc if atc && !atc.empty?
1728
1755
  end
1729
- xml.ATC sequence[:atc_code] if sequence && sequence[:atc_code] && !sequence[:atc_code].empty?
1730
1756
  if sequence && sequence[:packages] && (first_package = sequence[:packages].values.first) &&
1731
- (first_limitation = first_package[:limitations].first)
1757
+ (first_limitation = first_package[:limitations].first)
1732
1758
  lim_code = first_limitation[:code]
1733
1759
  used_limitations << lim_code unless used_limitations.index(lim_code)
1734
1760
  xml.LIMNAMEBAG lim_code
1735
1761
  elsif obj[:chapter70]
1736
- xml.comment "Chapter70 hack"
1737
- xml.SALECD('A') # these products are always active!
1762
+ xml.comment "Chapter70 hack prodno #{prodno} #{obj[:description].encode(xml: :text).gsub("--", "-")}"
1763
+ xml.SALECD("A") # these products are always active!
1738
1764
  xml.DSCR obj[:description]
1739
- xml.DSCRF ''
1765
+ xml.DSCRF ""
1740
1766
  if @limitations.index(obj[:code])
1741
1767
  xml.LIMNAMEBAG obj[:code]
1742
1768
  used_limitations << obj[:code]
1743
1769
  end
1744
1770
  end
1745
1771
  if sequence && sequence[:substances]
1746
- value = nil
1747
- if sequence[:substances].size > 1
1748
- value = 'Verschiedene Kombinationen'
1772
+ value = if sequence[:substances].size > 1
1773
+ "Verschiedene Kombinationen"
1749
1774
  elsif sequence[:substances].first
1750
- value = sequence[:substances].first[:name]
1775
+ sequence[:substances].first[:name]
1751
1776
  else
1752
- value = obj[:sub]
1777
+ obj[:sub]
1753
1778
  end
1754
1779
  override(xml, prodno, :SUBSTANCE, value) if value
1755
1780
  end
@@ -1766,11 +1791,11 @@ module Oddb2xml
1766
1791
  end
1767
1792
  emitted_lim_code << lim[:code]
1768
1793
  xml.LIMITATION do
1769
- xml.comment "Chapter70 hack" if lim[:chap70]
1794
+ xml.comment "Chapter70 2 hack" if lim[:chap70]
1770
1795
  xml.LIMNAMEBAG lim[:code] # original LIMCD
1771
- xml.DSCR Oddb2xml.html_decode(lim[:desc_de])
1772
- xml.DSCRF Oddb2xml.html_decode(lim[:desc_fr])
1773
- xml.LIMITATION_PTS (lim[:value].to_s.length > 1 ? lim[:value] : 1)
1796
+ xml.DSCR Oddb2xml.html_decode(lim[:desc_de])
1797
+ xml.DSCRF Oddb2xml.html_decode(lim[:desc_fr])
1798
+ xml.LIMITATION_PTS(lim[:value].to_s.length > 1 ? lim[:value] : 1)
1774
1799
  end
1775
1800
  end
1776
1801
  end
@@ -1781,17 +1806,19 @@ module Oddb2xml
1781
1806
  end
1782
1807
  Oddb2xml.log "#{variant}. Done #{nr_products} of #{@products.size} products, #{@limitations.size} limitations and #{nr_articles}/#{@nr_articles} articles. @@emitted_v5_gtins #{@@emitted_v5_gtins.size}"
1783
1808
  # we don't add a SHA256 hash for each element in the article
1784
- # Oddb2xml.add_hash(_builder.to_xml)
1809
+ # Oddb2xml.add_hash(a_builder.to_xml)
1785
1810
  # doc = REXML::Document.new( source, { :raw => :all })
1786
1811
  # doc.write( $stdout, 0 )
1787
1812
  lines = []
1788
- lines << " - #{sprintf('%5d', @products.size)} products"
1789
- lines << " - #{sprintf('%5d', @limitations.size)} limitations"
1790
- lines << " - #{sprintf('%5d', @nr_articles)} articles"
1791
- lines << " - #{sprintf('%5d', @@gtin2ignore.size)} ignored GTINS"
1813
+ lines << " - #{sprintf("%5d", @products.size)} products"
1814
+ lines << " - #{sprintf("%5d", @limitations.size)} limitations"
1815
+ lines << " - #{sprintf("%5d", @nr_articles)} articles"
1816
+ lines << " - #{sprintf("%5d", @@gtin2ignore.size)} ignored GTINS"
1792
1817
  @@articlestamm_v5_info_lines = lines
1793
- _builder.to_xml({:indent => 4, :encoding => 'UTF-8'})
1818
+ a_builder.to_xml({indent: 4, encoding: "UTF-8"})
1794
1819
  end
1820
+
1821
+ private_class_method
1795
1822
  def self.articlestamm_v5_info_lines
1796
1823
  @@articlestamm_v5_info_lines
1797
1824
  end