oddb2xml 2.6.7 → 2.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  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 +30 -0
  7. data/README.md +1 -1
  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 +1077 -1039
  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 -233
  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 +155 -129
  21. data/lib/oddb2xml/extractor.rb +302 -296
  22. data/lib/oddb2xml/options.rb +34 -35
  23. data/lib/oddb2xml/parslet_compositions.rb +263 -265
  24. data/lib/oddb2xml/semantic_check.rb +39 -33
  25. data/lib/oddb2xml/util.rb +169 -159
  26. data/lib/oddb2xml/version.rb +1 -1
  27. data/lib/oddb2xml/xml_definitions.rb +32 -33
  28. data/oddb2xml.gemspec +32 -30
  29. data/spec/artikelstamm_spec.rb +139 -132
  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 +182 -157
  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/Preparations.xml +139 -3
  38. data/spec/data/refdata_NonPharma.xml +0 -3
  39. data/spec/data/refdata_Pharma.xml +10 -25
  40. data/spec/data/swissmedic_package.xlsx +0 -0
  41. data/spec/data/transfer.dat +3 -1
  42. data/spec/data/varia_De.htm +2 -2
  43. data/spec/data_helper.rb +47 -49
  44. data/spec/downloader_spec.rb +247 -260
  45. data/spec/extractor_spec.rb +173 -165
  46. data/spec/galenic_spec.rb +233 -256
  47. data/spec/options_spec.rb +116 -119
  48. data/spec/parslet_spec.rb +833 -861
  49. data/spec/spec_helper.rb +154 -153
  50. data/test_options.rb +39 -42
  51. data/tools/win_fetch_cacerts.rb +2 -3
  52. metadata +49 -5
  53. data/.travis.yml +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 070625b76250b6816b761d5e4f37474326218067dcdbd0a59824c2667e62e9b7
4
- data.tar.gz: 04af7deafbe8160ad3283b6edb9bae596d9782bad4c7a4be8facda175f062ac8
3
+ metadata.gz: d8da655dd712cff69591fb63c97ad9f0e61d1bf085fd03b4cc1af409c140fe31
4
+ data.tar.gz: ff287b7a4104e8a446a33d12d0f4a64e0741d390329a2fb2446647fb1b99014b
5
5
  SHA512:
6
- metadata.gz: 3616fc763495253e24a1176ccd5d2907e08b96860e87d79c5577b14b38826bf57aaa3aebbf7777fcde28cb2d243b379e25697ba943b1df921ea6cbe6ea16edca
7
- data.tar.gz: dba061cc87bd89396f38b792f51c9918a23f55d9452c9df9472b5a1e208859f729cbba868097763fc0364791fbb0900a6df97319525dc9721515ad921527c18c
6
+ metadata.gz: 13a5bf2653004efe4365ac0f869b329a0d23e94ef11c5501f03bab1253fa69170a7df0bb78f976dc9c946a4a5f2b5bad21e38f3b5bc24d1e566f5a303eb0bb2f
7
+ data.tar.gz: 5483ac6d5eaeaddf7800e7c1bad5245155b61c7025a2d1325790ebf3ed76e70b8b5b1bd262d35e81011109ccb59d304740d7954ee1bef06b61711012eb1f703c
@@ -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,33 @@
1
+ === 2.7.2 / 18.03.2021
2
+ * Added https://github.com/testdouble/standard and fixed all useful warnings
3
+ * Added standard to rake tasks
4
+ * Use ATC-code from refdata if available and show differences
5
+ * Get pharmacode from tranfer.dat for artikelstamm if possible
6
+ * We do not longer test Ruby 2.4 with github/actions
7
+ * Update build status to use github/actions instead of travis
8
+
9
+ === 2.7.1 / 03.02.2021
10
+ * travis-ci -> Github Actions
11
+ * limit DSCRD/DSCRF to 120 chars as specified in the XSD
12
+ * Use huge option for nokogiri as suggested by https://github.com/sparklemotion/nokogiri/issues/2187
13
+ * Adapt artikelstamm to refdata without pharmacode
14
+ * oddb_article get pharmacode where possible from transfer.dat
15
+
16
+ === 2.7.0 / 05.11.2020
17
+ * Chapter70 hack nur als Kommentar
18
+ * Avoid double hyphen in comment
19
+
20
+ === 2.6.9 / 29.06.2020
21
+
22
+ * Fix problem when running bin/oddb2xml -a -f dat. Thanks to Lukas Furre for reporting the problem
23
+ * Fix warning with regular expression thas has ']'
24
+
25
+ === 2.6.8 / 26.06.2020
26
+
27
+ * Re-Add support for Ruby Version 2.4
28
+ * Specified minimal ruby version in gemspec
29
+ * Patch artikelstamm build to emit a product for Varilrix
30
+
1
31
  === 2.6.7 / 25.06.2020
2
32
  * Added value 'C' (Co-marketing) for field GENERIC_TYPE Elexis_Artikelstamm_v5.xsd from BAG Preparations.xml
3
33
  * Fixed limitations coming from the chapte 70 hack
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
 
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::WORK_DIR, "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,547 +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).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']
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
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"]
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" : ""]
1550
1605
  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
- xml.PRODNO prodno if prodno
1561
- atc = package[:atc_code]
1562
- atc ||= @refdata[pkg_gtin][:seq][:atc_code] if @refdata[pkg_gtin]
1563
- csv = []
1564
- @csv_file << [pkg_gtin, name, package[:unit], measure,
1565
- pexf ? pexf : '',
1566
- ppub ? ppub : '',
1567
- prodno, atc, package[:substance_swissmedic],
1568
- sequence[:org_gen_code], package[:ith_swissmedic],
1569
- @items[pkg_gtin] ? 'SL' : '',
1570
- ]
1571
1606
  end
1572
- end
1573
- else # non pharma
1574
- if @@emitted_v5_gtins.index(ean13)
1575
- next
1576
- else
1577
- @@emitted_v5_gtins << ean13.clone
1578
- end
1579
- # Set the pharmatype to 'Y' for outdated products, which are no longer found
1580
- # in refdata/packungen
1581
- chap70 = nil
1582
- if @chapter70items.values.find {|x| x[:pharmacode] && x[:pharmacode].eql?(obj[:pharmacode])}
1583
- Oddb2xml.log "found chapter #{obj[:pharmacode]}" if $VERBOSE
1584
- chap70 = true
1585
- end
1586
- patched_pharma_type = (/^7680/.match(ean13.to_s.rjust(13, '0')) || chap70 ? 'P': 'N' )
1587
- next if /^#{Oddb2xml::FAKE_GTIN_START}/.match(ean13.to_s)
1588
- xml.ITEM({'PHARMATYPE' => patched_pharma_type }) do
1589
- xml.GTIN ean13.to_s.rjust(13, '0')
1590
- xml.PHAR obj[:pharmacode]
1591
- emit_salecd(xml, ean13, obj)
1592
- description = obj[:desc_de] || obj[:description] # for description for zur_rose
1593
- xml.DSCR(description)
1594
- xml.DSCRF(obj[:desc_fr] || '--missing--')
1595
- xml.COMP do
1596
- xml.GLN obj[:company_ean]
1597
- end if obj[:company_ean] && !obj[:company_ean].empty?
1598
- if !(obj[:price] && !obj[:price].empty?) || !(obj[:pub_price] && !obj[:pub_price].empty?)
1599
- 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
1600
1612
  end
1601
- ppub = nil; pexf=nil
1602
- if obj[:price] && !obj[:price].empty?
1603
- xml.PEXF (pexf = obj[:price])
1604
- elsif zur_rose_detail
1605
- if zur_rose_detail[:price] && !zur_rose_detail[:price].empty? && !zur_rose_detail[:price].eql?('0.00')
1606
- Oddb2xml.log "NonPharma: #{ean13} adding PEXF #{zur_rose_detail[:price]} #{description}"
1607
- xml.PEXF (pexf = zur_rose_detail[:price])
1608
- 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
1609
1619
  end
1610
- if obj[:pub_price] && !obj[:pub_price].empty?
1611
- xml.PPUB (ppub = obj[:pub_price])
1612
- elsif zur_rose_detail
1613
- if zur_rose_detail[:pub_price] && !zur_rose_detail[:pub_price].empty? && !zur_rose_detail[:pub_price].eql?('0.00')
1614
- Oddb2xml.log "NonPharma: #{ean13} adding PPUB #{zur_rose_detail[:pub_price]} #{description}"
1615
- 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]
1616
1668
  end
1617
- end
1618
- @csv_file << [ ean13, description, '', '', pexf, ppub, '', '', '', '', '', '' ]
1619
- if chap70
1620
- xml.comment "Chapter70 hack"
1621
- xml.SL_ENTRY 'true'
1622
- xml.PRODNO obj[:pharmacode]
1623
- xml.Chapter70_HACK 'true'
1624
1669
  end
1625
1670
  end
1626
1671
  end
1672
+ @csv_file.close if @csv_file && !@csv_file.closed?
1673
+ nr_items
1627
1674
  end
1628
- @csv_file.close if @csv_file && !@csv_file.closed?
1629
- nr_items
1630
1675
  end
1631
1676
  unless @prepared
1632
- require 'oddb2xml/chapter_70_hack'
1633
- Oddb2xml::Chapter70xtractor.parse()
1677
+ require "oddb2xml/chapter_70_hack"
1678
+ Oddb2xml::Chapter70xtractor.parse
1634
1679
  @chapter70items = Oddb2xml::Chapter70xtractor.items
1635
1680
  prepare_limitations
1636
1681
  prepare_articles
@@ -1639,33 +1684,25 @@ module Oddb2xml
1639
1684
  prepare_calc_items(suppress_composition_parsing: true)
1640
1685
  @prepared = true
1641
1686
  @old_rose_size = @infos_zur_rose.size
1642
- @infos_zur_rose.each do |ean13, value|
1643
- if /^7680/.match(ean13.to_s) && @options[:artikelstamm]
1644
- @infos_zur_rose.delete(ean13)
1645
- end
1646
- end if false
1647
- @new_rose_size = @infos_zur_rose.size
1648
1687
  end
1649
1688
  nr_products = 0
1650
1689
  nr_articles = 0
1651
1690
  @nr_articles = 0
1652
1691
  used_limitations = []
1653
- Oddb2xml.log "#{variant}: Deleted #{@old_rose_size - @new_rose_size} entries from ZurRose where GTIN start with 7680 (Swissmedic)"
1654
1692
  # Oddb2xml.log "#{variant} #{nr_products} of #{@products.size} articles and ignore #{@@gtin2ignore.size} gtins specified via #{@@ignore_file}"
1655
- _builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
1693
+ a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
1656
1694
  xml.doc.tag_suffix = @tag_suffix
1657
- datetime = Time.new.strftime('%FT%T%z')
1658
1695
  elexis_strftime_format = "%FT%T\.%L%:z"
1659
- @@cumul_ver = (Date.today.year-2013)*12+Date.today.month
1660
- options_xml = {
1661
- 'xmlns' => 'http://elexis.ch/Elexis_Artikelstamm_v5',
1662
- 'CREATION_DATETIME' => Time.new.strftime(elexis_strftime_format),
1663
- 'BUILD_DATETIME' => Time.new.strftime(elexis_strftime_format),
1664
- '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"
1665
1702
  }
1666
1703
  emitted_prodno = []
1667
1704
  no8_to_prodno = {}
1668
- @packs.collect{ |key, val| no8_to_prodno[key] = val [:prodno] }
1705
+ @packs.collect { |key, val| no8_to_prodno[key] = val [:prodno] }
1669
1706
  xml.comment("Produced by #{__FILE__} version #{VERSION} at #{Time.now}")
1670
1707
  xml.ARTIKELSTAMM(options_xml) do
1671
1708
  xml.PRODUCTS do
@@ -1673,22 +1710,22 @@ module Oddb2xml
1673
1710
  products.each do |product|
1674
1711
  ean13 = product[0]
1675
1712
  obj = product[1]
1676
- next if /^Q/i.match(obj[:atc])
1713
+ next if /^Q/i.match?(obj[:atc])
1677
1714
  ean = obj[:ean13]
1678
1715
  sequence = obj[:seq]
1679
1716
  sequence ||= @products[ean][:seq] if @products[ean]
1680
- next unless check_name(obj, :de)
1681
- ppac = ((_ppac = @packs[ean.to_s[4..11]] and !_ppac[:is_tier]) ? _ppac : {})
1682
- 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?
1683
1720
  prodno = obj[:pharmacode] if obj[:chapter70]
1684
- myPack = @packs.values.find{ |x| x[:iksnr].to_i == obj[:seq][:swissmedic_number5].to_i } if obj[:seq]
1685
- if myPack && !prodno
1686
- prodno ||= myPack[:prodno]
1687
- 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]}"
1688
1725
  end
1689
1726
  next unless prodno
1690
1727
  next if emitted_prodno.index(prodno)
1691
- sequence ||= @articles.find{|x| x[:ean13].eql?(ean)}
1728
+ sequence ||= @articles.find { |x| x[:ean13].eql?(ean) }
1692
1729
  unless obj[:chapter70]
1693
1730
  next unless sequence && (sequence[:name_de] || sequence[:desc_de])
1694
1731
  if Oddb2xml.getEan13forProdno(prodno).size == 0 && !obj[:no8].eql?(Oddb2xml.getNo8ForEan13(ean))
@@ -1701,44 +1738,43 @@ module Oddb2xml
1701
1738
  xml.PRODUCT do
1702
1739
  xml.PRODNO prodno
1703
1740
  if sequence
1704
- xml.SALECD('A') # these products are always active!
1741
+ xml.SALECD("A") # these products are always active!
1705
1742
  name_de = "#{sequence[:name_de]} #{sequence[:desc_de]}".strip if sequence[:name_de]
1706
- unless name_de # eg. 7680002770014 Coeur-Vaisseaux Sérocytol, suppositoire
1707
- if ppac && /stk/i.match( sequence[:desc_de])
1708
- name_de = ppac[:sequence_name]
1709
- else
1710
- name_de = sequence[:desc_de]
1711
- end
1743
+ name_de ||= if ppac && /stk/i.match(sequence[:desc_de])
1744
+ ppac[:sequence_name]
1745
+ else
1746
+ sequence[:desc_de]
1712
1747
  end
1713
1748
  name_fr = "#{sequence[:name_fr]} #{sequence[:desc_fr]}".strip if sequence[:name_fr]
1714
1749
  name_fr ||= (ppac && ppac[:sequence_name])
1715
- override(xml, prodno, :DSCR, name_de.strip)
1750
+ override(xml, prodno, :DSCR, name_de.strip)
1716
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?
1717
1755
  end
1718
- xml.ATC sequence[:atc_code] if sequence && sequence[:atc_code] && !sequence[:atc_code].empty?
1719
1756
  if sequence && sequence[:packages] && (first_package = sequence[:packages].values.first) &&
1720
- (first_limitation = first_package[:limitations].first)
1757
+ (first_limitation = first_package[:limitations].first)
1721
1758
  lim_code = first_limitation[:code]
1722
1759
  used_limitations << lim_code unless used_limitations.index(lim_code)
1723
1760
  xml.LIMNAMEBAG lim_code
1724
1761
  elsif obj[:chapter70]
1725
- xml.comment "Chapter70 hack"
1726
- 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!
1727
1764
  xml.DSCR obj[:description]
1728
- xml.DSCRF ''
1765
+ xml.DSCRF ""
1729
1766
  if @limitations.index(obj[:code])
1730
1767
  xml.LIMNAMEBAG obj[:code]
1731
1768
  used_limitations << obj[:code]
1732
1769
  end
1733
1770
  end
1734
1771
  if sequence && sequence[:substances]
1735
- value = nil
1736
- if sequence[:substances].size > 1
1737
- value = 'Verschiedene Kombinationen'
1772
+ value = if sequence[:substances].size > 1
1773
+ "Verschiedene Kombinationen"
1738
1774
  elsif sequence[:substances].first
1739
- value = sequence[:substances].first[:name]
1775
+ sequence[:substances].first[:name]
1740
1776
  else
1741
- value = obj[:sub]
1777
+ obj[:sub]
1742
1778
  end
1743
1779
  override(xml, prodno, :SUBSTANCE, value) if value
1744
1780
  end
@@ -1755,11 +1791,11 @@ module Oddb2xml
1755
1791
  end
1756
1792
  emitted_lim_code << lim[:code]
1757
1793
  xml.LIMITATION do
1758
- xml.comment "Chapter70 hack" if lim[:chap70]
1794
+ xml.comment "Chapter70 2 hack" if lim[:chap70]
1759
1795
  xml.LIMNAMEBAG lim[:code] # original LIMCD
1760
- xml.DSCR Oddb2xml.html_decode(lim[:desc_de])
1761
- xml.DSCRF Oddb2xml.html_decode(lim[:desc_fr])
1762
- 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)
1763
1799
  end
1764
1800
  end
1765
1801
  end
@@ -1770,17 +1806,19 @@ module Oddb2xml
1770
1806
  end
1771
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}"
1772
1808
  # we don't add a SHA256 hash for each element in the article
1773
- # Oddb2xml.add_hash(_builder.to_xml)
1809
+ # Oddb2xml.add_hash(a_builder.to_xml)
1774
1810
  # doc = REXML::Document.new( source, { :raw => :all })
1775
1811
  # doc.write( $stdout, 0 )
1776
1812
  lines = []
1777
- lines << " - #{sprintf('%5d', @products.size)} products"
1778
- lines << " - #{sprintf('%5d', @limitations.size)} limitations"
1779
- lines << " - #{sprintf('%5d', @nr_articles)} articles"
1780
- 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"
1781
1817
  @@articlestamm_v5_info_lines = lines
1782
- _builder.to_xml({:indent => 4, :encoding => 'UTF-8'})
1818
+ a_builder.to_xml({indent: 4, encoding: "UTF-8"})
1783
1819
  end
1820
+
1821
+ private_class_method
1784
1822
  def self.articlestamm_v5_info_lines
1785
1823
  @@articlestamm_v5_info_lines
1786
1824
  end