oddb2xml 2.6.9 → 2.7.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +40 -0
- data/.standard.yml +2 -0
- data/Elexis_Artikelstamm_v5.xsd +0 -3
- data/Gemfile +3 -3
- data/History.txt +28 -0
- data/README.md +3 -3
- data/Rakefile +24 -23
- data/bin/check_artikelstamm +11 -11
- data/bin/compare_v5 +23 -23
- data/bin/oddb2xml +14 -13
- data/lib/oddb2xml.rb +1 -1
- data/lib/oddb2xml/builder.rb +1075 -1048
- data/lib/oddb2xml/calc.rb +232 -233
- data/lib/oddb2xml/chapter_70_hack.rb +38 -32
- data/lib/oddb2xml/cli.rb +252 -235
- data/lib/oddb2xml/compare.rb +70 -59
- data/lib/oddb2xml/compositions_syntax.rb +448 -430
- data/lib/oddb2xml/compressor.rb +20 -20
- data/lib/oddb2xml/downloader.rb +156 -128
- data/lib/oddb2xml/extractor.rb +295 -302
- data/lib/oddb2xml/options.rb +34 -35
- data/lib/oddb2xml/parslet_compositions.rb +263 -269
- data/lib/oddb2xml/semantic_check.rb +39 -33
- data/lib/oddb2xml/util.rb +166 -164
- data/lib/oddb2xml/version.rb +1 -1
- data/lib/oddb2xml/xml_definitions.rb +32 -33
- data/oddb2xml.gemspec +32 -31
- data/spec/artikelstamm_spec.rb +116 -135
- data/spec/builder_spec.rb +495 -524
- data/spec/calc_spec.rb +552 -593
- data/spec/check_artikelstamm_spec.rb +26 -26
- data/spec/cli_spec.rb +173 -174
- data/spec/compare_spec.rb +9 -11
- data/spec/composition_syntax_spec.rb +390 -409
- data/spec/compressor_spec.rb +48 -48
- data/spec/data/refdata_NonPharma.xml +0 -3
- data/spec/data/refdata_Pharma.xml +0 -26
- data/spec/data/transfer.dat +1 -0
- data/spec/data/varia_De.htm +2 -2
- data/spec/data_helper.rb +47 -49
- data/spec/downloader_spec.rb +251 -260
- data/spec/extractor_spec.rb +172 -164
- data/spec/galenic_spec.rb +233 -256
- data/spec/options_spec.rb +116 -119
- data/spec/parslet_spec.rb +833 -861
- data/spec/spec_helper.rb +153 -153
- data/test_options.rb +39 -42
- data/tools/win_fetch_cacerts.rb +2 -3
- metadata +48 -5
- data/.travis.yml +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: af1cbeb37bf057e98955776c87dd5092fc5706af18d00ba818efccd2c52a076e
|
4
|
+
data.tar.gz: 1f4faf8f73b2cffa14bd3dda23dad4e401b524587c0f95d80e0cc9cbd4ba5d2b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ace048c855b3711fd6b75692373318fe992a5c6529d322c13b516a7bd09390e36efec3f14edaa91ddeb223438d74c97c15ba4691077e9c77ce5063a10bdcc423
|
7
|
+
data.tar.gz: 9dcf787039edc02a56b7301f6849e76259628ac55da598a2878e4a08c63fd3c3aaef35bfea6bda8184c6e3552314fba7bb028962d81151ca98bf76f830c3303f
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Ruby
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ master ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ master ]
|
15
|
+
|
16
|
+
jobs:
|
17
|
+
test:
|
18
|
+
runs-on: ubuntu-latest
|
19
|
+
# Using a matrix fails, because /setup-ruby always invokes bundle install without any additional args
|
20
|
+
# Fixed by adding not defining the debugger group in the Gemfile
|
21
|
+
strategy:
|
22
|
+
fail-fast: false
|
23
|
+
matrix:
|
24
|
+
os: [ ubuntu]
|
25
|
+
ruby: [2.5, 2.6, 2.7, 3.0, head]
|
26
|
+
continue-on-error: ${{ endsWith(matrix.ruby, 'head') }}
|
27
|
+
steps:
|
28
|
+
- uses: actions/checkout@v2
|
29
|
+
- uses: ruby/setup-ruby@v1
|
30
|
+
with:
|
31
|
+
ruby-version: ${{ matrix.ruby }}
|
32
|
+
bundler-cache: true
|
33
|
+
|
34
|
+
- name: Install dependencies
|
35
|
+
run: |
|
36
|
+
bundle config set path .bundle/gems --local
|
37
|
+
bundle config set without debugger --local
|
38
|
+
bundle install
|
39
|
+
- name: Test with RSpec
|
40
|
+
run: bundle exec rspec
|
data/.standard.yml
ADDED
data/Elexis_Artikelstamm_v5.xsd
CHANGED
data/Gemfile
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
=== 2.7.4 / 30.03.2021
|
2
|
+
* Update needed Ruby-Version to 2.5.0 in gemspec
|
3
|
+
* Ensure downloads directory is created at first run
|
4
|
+
|
5
|
+
=== 2.7.3 / 29.03.2021
|
6
|
+
* Do not delete swissmedic_package.xlsx and swissmedic_orphan.xlsx
|
7
|
+
* Save swissmedic_package.xlsx and swissmedic_orphan.xlsx under downloads
|
8
|
+
* Log removing files
|
9
|
+
|
10
|
+
=== 2.7.2 / 18.03.2021
|
11
|
+
* Added https://github.com/testdouble/standard and fixed all useful warnings
|
12
|
+
* Added standard to rake tasks
|
13
|
+
* Use ATC-code from refdata if available and show differences
|
14
|
+
* Get pharmacode from tranfer.dat for artikelstamm if possible
|
15
|
+
* We do not longer test Ruby 2.4 with github/actions
|
16
|
+
* Update build status to use github/actions instead of travis
|
17
|
+
|
18
|
+
=== 2.7.1 / 03.02.2021
|
19
|
+
* travis-ci -> Github Actions
|
20
|
+
* limit DSCRD/DSCRF to 120 chars as specified in the XSD
|
21
|
+
* Use huge option for nokogiri as suggested by https://github.com/sparklemotion/nokogiri/issues/2187
|
22
|
+
* Adapt artikelstamm to refdata without pharmacode
|
23
|
+
* oddb_article get pharmacode where possible from transfer.dat
|
24
|
+
|
25
|
+
=== 2.7.0 / 05.11.2020
|
26
|
+
* Chapter70 hack nur als Kommentar
|
27
|
+
* Avoid double hyphen in comment
|
28
|
+
|
1
29
|
=== 2.6.9 / 29.06.2020
|
2
30
|
|
3
31
|
* Fix problem when running bin/oddb2xml -a -f dat. Thanks to Lukas Furre for reporting the problem
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# oddb2xml
|
2
2
|
|
3
|
-
[![Build Status](https://
|
3
|
+
[![Build Status](https://github.com/zdavatz/oddb2xml/workflows/Ruby/badge.svg)](https://github.com/zdavatz/oddb2xml/actions)
|
4
4
|
|
5
5
|
* oddb2xml -a nonpharma -o fi
|
6
6
|
|
@@ -106,8 +106,8 @@ FR
|
|
106
106
|
|
107
107
|
## Supported ruby version
|
108
108
|
|
109
|
-
We run tests on travis-ci.org for the Ruby versions mentioned in the .travis.yml file. You will need ruby > 2.
|
110
|
-
|
109
|
+
We run tests on travis-ci.org for the Ruby versions mentioned in the .travis.yml file. You will need ruby > 2.5 to work correctly.
|
110
|
+
Look at the github actions to see the spec test results. We ignore errors against ruby head, as it is sometimes unstable.
|
111
111
|
|
112
112
|
|
113
113
|
## XSD files
|
data/Rakefile
CHANGED
@@ -1,25 +1,26 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
lib = File.expand_path(
|
2
|
+
|
3
|
+
lib = File.expand_path("../lib", __FILE__)
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
-
require
|
5
|
+
require "oddb2xml/version"
|
6
6
|
require "bundler/gem_tasks"
|
7
|
-
require
|
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
|
14
|
-
task :
|
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 :
|
19
|
+
task spec: :clean
|
19
20
|
|
20
|
-
desc
|
21
|
-
task :
|
22
|
-
log_file =
|
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
|
32
|
-
CLEAN.include FileList[
|
33
|
-
CLEAN.include FileList[
|
34
|
-
CLEAN.include FileList[
|
35
|
-
CLEAN.include FileList[
|
36
|
-
CLEAN.include FileList[
|
37
|
-
CLEAN.include FileList[
|
38
|
-
CLEAN.include FileList[
|
39
|
-
CLEAN.include FileList[
|
40
|
-
CLEAN.include FileList[
|
41
|
-
CLEAN.include FileList[
|
42
|
-
CLEAN.include FileList[
|
43
|
-
CLEAN.include FileList[
|
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"]
|
data/bin/check_artikelstamm
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require
|
2
|
+
require "pathname"
|
3
3
|
|
4
4
|
root = Pathname.new(__FILE__).realpath.parent.parent
|
5
|
-
$:.unshift root.join(
|
5
|
+
$:.unshift root.join("lib") if $0 == __FILE__
|
6
6
|
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
7
|
+
require "oddb2xml/version"
|
8
|
+
require "oddb2xml/semantic_check"
|
9
|
+
require "optimist"
|
10
10
|
|
11
|
-
@opts = Optimist
|
12
|
-
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
|
-
|
28
|
-
|
29
|
-
diff = (Time.now-
|
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
|
2
|
+
require "pathname"
|
3
3
|
|
4
4
|
root = Pathname.new(__FILE__).realpath.parent.parent
|
5
|
-
$:.unshift root.join(
|
5
|
+
$:.unshift root.join("lib") if $0 == __FILE__
|
6
6
|
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
19
|
-
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,
|
25
|
-
opt :fields_as_floats,
|
26
|
-
opt :fields_to_ignore,
|
27
|
-
opt :min_diff_for_floats, "Minimal difference when comparing floats", :
|
28
|
-
opt :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
|
-
|
39
|
-
|
40
|
-
diff = (Time.now-
|
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
|
3
|
+
require "pathname"
|
4
4
|
root = Pathname.new(__FILE__).realpath.parent.parent
|
5
|
-
$:.unshift root.join(
|
5
|
+
$:.unshift root.join("lib") if $0 == __FILE__
|
6
6
|
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
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
|
-
|
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 =
|
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-
|
43
|
-
puts "#{Time.now}: #{__LINE__} done. Took #{diff} seconds"
|
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
data/lib/oddb2xml/builder.rb
CHANGED
@@ -1,21 +1,22 @@
|
|
1
|
-
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
|
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
|
-
|
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
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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__),
|
37
|
-
@@article_overrides
|
38
|
-
@@product_overrides
|
39
|
-
@@ignore_file
|
40
|
-
@@gtin2ignore
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
50
|
-
@subject
|
51
|
-
@refdata
|
52
|
-
@items
|
53
|
-
@flags
|
54
|
-
@lppvs
|
55
|
-
@infos
|
56
|
-
@packs
|
57
|
-
@migel
|
58
|
-
@infos_zur_rose
|
59
|
-
@actions
|
60
|
-
@orphan
|
61
|
-
@ean14
|
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
|
-
|
71
|
+
|
72
|
+
def to_xml(subject = nil)
|
71
73
|
Oddb2xml.log "to_xml subject #{subject || @subject}"
|
72
74
|
if subject
|
73
|
-
|
75
|
+
send("build_" + subject.to_s)
|
74
76
|
elsif @subject
|
75
|
-
|
77
|
+
send("build_" + @subject.to_s)
|
76
78
|
end
|
77
79
|
end
|
78
|
-
|
79
|
-
|
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
|
-
|
84
|
+
send("build_" + subject.to_s)
|
82
85
|
elsif @subject
|
83
|
-
|
86
|
+
send("build_" + @subject.to_s)
|
84
87
|
end
|
85
88
|
end
|
86
|
-
|
87
|
-
|
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 :
|
95
|
+
Oddb2xml.log("prepare_articles starting with #{@articles ? @articles.size : "no"} articles.")
|
91
96
|
@articles = []
|
92
97
|
@refdata.each do |ean13, obj|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
119
|
-
|
120
|
-
|
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
|
-
|
132
|
+
nr_items = 0
|
124
133
|
@infos_zur_rose.each do |ean13, info|
|
125
|
-
|
134
|
+
nr_items += 1
|
126
135
|
pharmacode = info[:pharmacode]
|
127
136
|
if @pharmacode[pharmacode]
|
128
|
-
@pharmacode[pharmacode][: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]
|
146
|
+
existing[:price] = info[:price]
|
138
147
|
existing[:pub_price] = info[:pub_price]
|
139
148
|
else
|
140
149
|
entry = {
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|
167
|
+
if !found && (obj.size > 0)
|
159
168
|
@articles << obj unless @options[:artikelstamm]
|
160
|
-
|
169
|
+
nr_added += 1
|
161
170
|
end
|
162
171
|
end
|
163
172
|
end
|
164
173
|
end
|
165
|
-
Oddb2xml.log("prepare_articles done. Added #{
|
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])
|
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
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
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<< {:
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
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]
|
235
|
-
ean13 =
|
236
|
-
ean13 ||=
|
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
|
-
:
|
240
|
-
:
|
241
|
-
:
|
242
|
-
:
|
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
|
250
|
-
next if 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
|
-
:
|
253
|
-
:
|
254
|
-
:
|
255
|
-
:
|
256
|
-
:
|
257
|
-
:
|
258
|
-
:
|
259
|
-
:
|
260
|
-
:
|
261
|
-
:
|
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?
|
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] ==
|
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
|
-
|
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
|
-
|
309
|
-
|
310
|
-
|
311
|
-
xml.SB(
|
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
|
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(
|
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
|
-
|
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
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
xml.LIM(
|
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
|
372
|
+
xml.Pharmacode lim[:id]
|
351
373
|
end
|
352
|
-
xml.IT
|
353
|
-
xml.LIMTYP
|
354
|
-
xml.LIMVAL
|
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
|
357
|
-
xml.DSCRD
|
358
|
-
xml.DSCRF
|
359
|
-
xml.VDAT
|
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
|
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(
|
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
|
-
|
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(
|
384
|
-
xml.IXNO
|
385
|
-
xml.TITD
|
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
|
392
|
-
#xml.EFFF
|
393
|
-
if @codes
|
394
|
-
if dict = @codes[ix[:grad].upcase]
|
395
|
-
xml.RLV
|
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
|
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(
|
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
|
-
|
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(
|
443
|
-
xml.CDTYP
|
444
|
-
xml.CDVAL
|
445
|
-
xml.DSCRSD
|
446
|
-
#xml.DSCRSF
|
447
|
-
#xml.DSCRMD
|
448
|
-
#xml.DSCRMF
|
449
|
-
#xml.DSCRD
|
450
|
-
#xml.DSCRF
|
451
|
-
xml.DEL
|
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
|
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(
|
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
|
-
|
470
|
-
|
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(
|
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
|
503
|
+
next if list_code && /Tierarzneimittel/.match(list_code)
|
482
504
|
if add_to_products
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
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 #{
|
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
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
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
|
532
|
-
|
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(
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
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
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
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 = ((
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
xml.
|
576
|
-
xml.
|
577
|
-
xml.
|
578
|
-
#xml.
|
579
|
-
#xml.
|
580
|
-
#xml.
|
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]
|
585
|
-
xml.ADINFF seq[:comment_fr]
|
586
|
-
xml.GENCD
|
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
|
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
|
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
|
650
|
-
xml.QTYU
|
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
|
675
|
+
# xml.GRP
|
676
|
+
xml.RLV @codes[ix[:grad]]
|
660
677
|
}
|
661
678
|
end
|
662
679
|
end
|
663
680
|
end
|
664
|
-
#xml.CPTROA {
|
665
|
-
|
666
|
-
|
667
|
-
#}
|
681
|
+
# xml.CPTROA {
|
682
|
+
# xml.SYSLOC
|
683
|
+
# xml.ROA
|
684
|
+
# }
|
668
685
|
}
|
669
|
-
#xml.PRDICD { # currently empty
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
#}
|
676
|
-
xml.PackGrSwissmedic
|
677
|
-
xml.EinheitSwissmedic
|
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
|
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(
|
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::
|
696
|
-
|
697
|
-
return unless File.exists?(packungen_xlsx)
|
712
|
+
packungen_xlsx = File.join(Oddb2xml::DOWNLOADS, "swissmedic_package.xlsx")
|
713
|
+
return unless File.exist?(packungen_xlsx)
|
698
714
|
workbook = RubyXL::Parser.parse(packungen_xlsx)
|
699
715
|
row_nr = 0
|
700
716
|
workbook.worksheets[0].each do |row|
|
701
717
|
row_nr += 1
|
702
|
-
next unless row
|
703
|
-
iksnr
|
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
|
-
|
707
|
-
|
721
|
+
puts "#{Time.now}: At row #{row_nr} iksnr #{iksnr}"
|
722
|
+
$stdout.flush
|
708
723
|
end
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
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
|
718
|
-
sub
|
719
|
-
comp
|
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
|
722
|
-
name
|
723
|
-
atc_code
|
724
|
-
list_code
|
725
|
-
package_size
|
726
|
-
unit
|
727
|
-
active_substance
|
728
|
-
composition
|
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
|
732
|
-
next if 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
|
-
|
747
|
+
info = if suppress_composition_parsing
|
748
|
+
Calc.new(name, package_size, unit)
|
737
749
|
else
|
738
|
-
|
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 =
|
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
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
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
|
-
|
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
|
-
|
783
|
-
xml.
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
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
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
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
|
826
|
+
end
|
812
827
|
end
|
813
828
|
end
|
814
829
|
end
|
815
830
|
|
816
|
-
csv_name = File.join(
|
817
|
-
CSV.open(csv_name, "w+", :
|
818
|
-
csv << [
|
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
|
821
|
-
csv <<
|
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(
|
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
|
-
|
852
|
+
a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
|
838
853
|
xml.doc.tag_suffix = @tag_suffix
|
839
|
-
|
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] ||=
|
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] +
|
851
|
-
item[:desc_fr] = item[:name_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
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
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
|
880
|
+
ppac = nil # Packungen
|
868
881
|
ean = obj[:ean13]
|
869
|
-
next if pack_info
|
870
|
-
next if 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
|
876
|
-
|
877
|
-
pac = @items[ean][:packages][ean]
|
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 = ((
|
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(
|
899
|
+
xml.ART("DT" => obj[:last_change] || "") do
|
887
900
|
nbr_records += 1
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
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
|
896
|
-
xml.GEN_PRODUCTION
|
897
|
-
xml.INSULIN_CATEGORY
|
898
|
-
xml.DRUG_INDEX
|
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
|
901
|
-
if ean
|
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]
|
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
|
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 =
|
941
|
+
flag = ppac && !ppac[:drug_index].empty? ? true : false
|
924
942
|
# as same flag
|
925
|
-
xml.CDBG(flag ?
|
926
|
-
xml.BG(flag ?
|
943
|
+
xml.CDBG(flag ? "Y" : "N")
|
944
|
+
xml.BG(flag ? "Y" : "N")
|
927
945
|
end
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
xml.
|
933
|
-
xml.
|
934
|
-
xml.
|
935
|
-
xml.
|
936
|
-
xml.
|
937
|
-
xml.
|
938
|
-
#xml.
|
939
|
-
#xml.
|
940
|
-
#xml.
|
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
|
952
|
-
when
|
953
|
-
else
|
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]
|
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]
|
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
|
-
|
988
|
-
xml.
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
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
|
1003
|
-
xml.PTYP
|
1004
|
-
xml.PRICE price[:price]
|
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
|
1020
|
+
xml.PTYP "ZURROSE"
|
1012
1021
|
xml.PRICE price
|
1013
1022
|
}
|
1014
1023
|
xml.ARTPRI {
|
1015
|
-
xml.PTYP
|
1024
|
+
xml.PTYP "ZURROSEPUB"
|
1016
1025
|
xml.PRICE zur_rose[:pub_price]
|
1017
1026
|
}
|
1018
|
-
|
1019
|
-
xml.
|
1020
|
-
|
1021
|
-
|
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
|
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(
|
1051
|
+
Oddb2xml.add_hash(a_builder.to_xml)
|
1041
1052
|
end
|
1053
|
+
|
1042
1054
|
def build_fi
|
1043
1055
|
nbr_records = 0
|
1044
|
-
|
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
|
-
|
1053
|
-
|
1054
|
-
|
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
|
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(:
|
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
|
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(
|
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
|
-
|
1094
|
+
a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
|
1083
1095
|
xml.doc.tag_suffix = @tag_suffix
|
1084
|
-
datetime = Time.new.strftime('%FT%T%z')
|
1085
1096
|
xml.KOMPENDIUM_PRODUCT(XML_OPTIONS) {
|
1086
1097
|
info_index = {}
|
1087
1098
|
%w[de fr].each do |lang|
|
@@ -1090,558 +1101,581 @@ module Oddb2xml
|
|
1090
1101
|
end
|
1091
1102
|
# prod
|
1092
1103
|
@products.each do |ean13, prod|
|
1093
|
-
next unless
|
1104
|
+
next unless prod[:seq] && prod[:seq][:packages]
|
1094
1105
|
seq = prod[:seq]
|
1095
|
-
prod[:seq][:packages].each {
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
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
|
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(
|
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
|
-
|
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(
|
1132
|
-
xml.GLN_Betrieb
|
1133
|
-
xml.Betriebsname_1
|
1134
|
-
xml.Betriebsname_2
|
1135
|
-
xml.Strasse
|
1136
|
-
xml.Nummer
|
1137
|
-
xml.PLZ
|
1138
|
-
xml.Ort
|
1139
|
-
xml.Bewilligungskanton c[:region]
|
1140
|
-
xml.Land
|
1141
|
-
xml.Betriebstyp
|
1142
|
-
xml.BTM_Berechtigung
|
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
|
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(
|
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
|
-
|
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(
|
1165
|
-
xml.GLN_Person
|
1166
|
-
xml.Name
|
1167
|
-
xml.Vorname
|
1168
|
-
xml.PLZ
|
1169
|
-
xml.Ort
|
1170
|
-
xml.Bewilligungskanton p[:region]
|
1171
|
-
xml.Land
|
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
|
1174
|
-
xml.BTM_Berechtigung
|
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
|
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(
|
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
|
1194
|
-
|
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.
|
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
|
-
:
|
1213
|
-
:
|
1214
|
-
:
|
1215
|
-
:
|
1216
|
-
:
|
1217
|
-
:
|
1218
|
-
:
|
1219
|
-
:
|
1220
|
-
:
|
1221
|
-
:
|
1222
|
-
:
|
1223
|
-
:
|
1224
|
-
:
|
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
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
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
|
-
|
1243
|
-
|
1249
|
+
|
1250
|
+
def format_date(date_str, len = 7)
|
1251
|
+
date = date_str.delete(".")
|
1244
1252
|
if date.size < len
|
1245
|
-
date
|
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
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
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
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
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
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
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 = !!(
|
1386
|
-
status =
|
1387
|
-
|
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(
|
1406
|
+
xml.SALECD("A") { xml.comment(msg) }
|
1392
1407
|
else
|
1393
|
-
xml.SALECD(status) { xml.comment(
|
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(
|
1400
|
-
@csv_file << [
|
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
|
-
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
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
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
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
|
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
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
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
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1488
|
-
|
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
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1499
|
-
|
1500
|
-
|
1501
|
-
|
1502
|
-
|
1503
|
-
|
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
|
-
|
1527
|
-
ppub ||= obj[:pub_price]
|
1502
|
+
@@emitted_v5_gtins << pkg_gtin.clone
|
1528
1503
|
end
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
xml.
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
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
|
-
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
1561
|
-
|
1562
|
-
|
1563
|
-
|
1564
|
-
|
1565
|
-
|
1566
|
-
|
1567
|
-
|
1568
|
-
|
1569
|
-
|
1530
|
+
pexf = ppub = nil
|
1531
|
+
if package[:prices]
|
1532
|
+
pexf ||= package[:prices][:exf_price][:price]
|
1533
|
+
ppub ||= package[:prices][:pub_price][:price]
|
1534
|
+
elsif @items[ean13] && @items[ean13][:packages] && @items[ean13][:packages][ean13] && (bag_prices = @items[ean13][:packages][ean13][:prices])
|
1535
|
+
pexf ||= bag_prices[:exf_price][:price]
|
1536
|
+
ppub ||= bag_prices[:pub_price][:price]
|
1537
|
+
else
|
1538
|
+
pexf ||= obj[:price]
|
1539
|
+
ppub ||= obj[:pub_price]
|
1540
|
+
end
|
1541
|
+
ppub = nil if ppub && ppub.size == 0
|
1542
|
+
pexf = nil if pexf && pexf.size == 0
|
1543
|
+
if !(obj[:price] && !obj[:price].empty?) || !(obj[:pub_price] && !obj[:pub_price].empty?)
|
1544
|
+
zur_rose_detail = @infos_zur_rose.values.find { |x| x[:ean13].to_i == ean13.to_i }
|
1545
|
+
if zur_rose_detail
|
1546
|
+
pexf ||= zur_rose_detail[:price]
|
1547
|
+
ppub ||= zur_rose_detail[:pub_price]
|
1548
|
+
end
|
1549
|
+
end
|
1550
|
+
xml.PEXF pexf if pexf
|
1551
|
+
xml.PPUB ppub if ppub
|
1552
|
+
measure = ""
|
1553
|
+
if info
|
1554
|
+
# MEASSURE Measurement Unit,e.g. Pills or milliliters
|
1555
|
+
# <DSCR>HIRUDOID Creme 3 mg/g 40 g</DSCR>
|
1556
|
+
xml.PKG_SIZE info.pkg_size.to_i if info.pkg_size
|
1557
|
+
if info.measure
|
1558
|
+
measure = info.measure
|
1559
|
+
elsif info.pkg_size && info.unit
|
1560
|
+
measure = info.pkg_size + " " + info.unit
|
1561
|
+
elsif info.pkg_size
|
1562
|
+
measure = info.pkg_size
|
1570
1563
|
end
|
1564
|
+
xml.MEASURE measure
|
1565
|
+
xml.MEASUREF measure
|
1566
|
+
# Die Darreichungsform dieses Items. zB Tablette(n) oder Spritze(n)
|
1567
|
+
xml.DOSAGE_FORM info.galenic_form.descriptions["de"] if info.galenic_form.descriptions["de"]
|
1568
|
+
xml.DOSAGE_FORMF info.galenic_form.descriptions["fr"] if info.galenic_form.descriptions["fr"]
|
1571
1569
|
end
|
1570
|
+
xml.SL_ENTRY "true" if sl_gtins.index(pkg_gtin)
|
1571
|
+
xml.IKSCAT package[:swissmedic_category] if package[:swissmedic_category] && package[:swissmedic_category].length > 0
|
1572
|
+
xml.GENERIC_TYPE sequence[:org_gen_code] if sequence[:org_gen_code] && !sequence[:org_gen_code].empty?
|
1573
|
+
xml.LPPV "true" if @lppvs[pkg_gtin.to_s] # detect_nincd
|
1574
|
+
if item && item[:deductible]
|
1575
|
+
case item[:deductible]
|
1576
|
+
when "Y" then xml.DEDUCTIBLE 20; # 20%
|
1577
|
+
when "N" then xml.DEDUCTIBLE 10; # 10%
|
1578
|
+
end
|
1579
|
+
end
|
1580
|
+
prodno = Oddb2xml.getProdnoForEan13(pkg_gtin)
|
1581
|
+
atc = package[:atc_code]
|
1582
|
+
refdata_atc = @refdata[pkg_gtin][:atc_code] if @refdata && @refdata[pkg_gtin] && @refdata[pkg_gtin]
|
1583
|
+
if refdata_atc && atc.nil?
|
1584
|
+
puts "WARNING: #{pkg_gtin} ATC-code from refdata #{refdata_atc} as Swissmedic ATC is nil #{name}"
|
1585
|
+
atc = refdata_atc
|
1586
|
+
end
|
1587
|
+
unless prodno # find a prodno from packages for vaccinations
|
1588
|
+
if atc && /^J07/.match(atc) && !/^J07AX/.match(atc)
|
1589
|
+
pack = @packs.values.find { |v| v && v[:atc_code].eql?(atc) }
|
1590
|
+
if pack
|
1591
|
+
prodno = pack[:prodno]
|
1592
|
+
Oddb2xml.log "Patching vaccination for #{pkg_gtin} #{atc} #{name} via prodno #{prodno}"
|
1593
|
+
else
|
1594
|
+
Oddb2xml.log "unable to find a pack/prodno for vaccination for #{pkg_gtin} #{atc} #{name}"
|
1595
|
+
end
|
1596
|
+
end
|
1597
|
+
end
|
1598
|
+
xml.PRODNO prodno if prodno
|
1599
|
+
@csv_file << [pkg_gtin, name, package[:unit], measure,
|
1600
|
+
pexf || "",
|
1601
|
+
ppub || "",
|
1602
|
+
prodno, atc, package[:substance_swissmedic],
|
1603
|
+
sequence[:org_gen_code], package[:ith_swissmedic],
|
1604
|
+
@items[pkg_gtin] ? "SL" : ""]
|
1572
1605
|
end
|
1573
|
-
xml.PRODNO prodno if prodno
|
1574
|
-
csv = []
|
1575
|
-
@csv_file << [pkg_gtin, name, package[:unit], measure,
|
1576
|
-
pexf ? pexf : '',
|
1577
|
-
ppub ? ppub : '',
|
1578
|
-
prodno, atc, package[:substance_swissmedic],
|
1579
|
-
sequence[:org_gen_code], package[:ith_swissmedic],
|
1580
|
-
@items[pkg_gtin] ? 'SL' : '',
|
1581
|
-
]
|
1582
1606
|
end
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
@@emitted_v5_gtins << ean13.clone
|
1589
|
-
end
|
1590
|
-
# Set the pharmatype to 'Y' for outdated products, which are no longer found
|
1591
|
-
# in refdata/packungen
|
1592
|
-
chap70 = nil
|
1593
|
-
if @chapter70items.values.find {|x| x[:pharmacode] && x[:pharmacode].eql?(obj[:pharmacode])}
|
1594
|
-
Oddb2xml.log "found chapter #{obj[:pharmacode]}" if $VERBOSE
|
1595
|
-
chap70 = true
|
1596
|
-
end
|
1597
|
-
patched_pharma_type = (/^7680/.match(ean13.to_s.rjust(13, '0')) || chap70 ? 'P': 'N' )
|
1598
|
-
next if /^#{Oddb2xml::FAKE_GTIN_START}/.match(ean13.to_s)
|
1599
|
-
xml.ITEM({'PHARMATYPE' => patched_pharma_type }) do
|
1600
|
-
xml.GTIN ean13.to_s.rjust(13, '0')
|
1601
|
-
xml.PHAR obj[:pharmacode]
|
1602
|
-
emit_salecd(xml, ean13, obj)
|
1603
|
-
description = obj[:desc_de] || obj[:description] # for description for zur_rose
|
1604
|
-
xml.DSCR(description)
|
1605
|
-
xml.DSCRF(obj[:desc_fr] || '--missing--')
|
1606
|
-
xml.COMP do
|
1607
|
-
xml.GLN obj[:company_ean]
|
1608
|
-
end if obj[:company_ean] && !obj[:company_ean].empty?
|
1609
|
-
if !(obj[:price] && !obj[:price].empty?) || !(obj[:pub_price] && !obj[:pub_price].empty?)
|
1610
|
-
zur_rose_detail = @infos_zur_rose.values.find{|x| x[:ean13].to_i == ean13.to_i}
|
1607
|
+
else # non pharma
|
1608
|
+
if @@emitted_v5_gtins.index(ean13)
|
1609
|
+
next
|
1610
|
+
else
|
1611
|
+
@@emitted_v5_gtins << ean13.clone
|
1611
1612
|
end
|
1612
|
-
|
1613
|
-
|
1614
|
-
|
1615
|
-
|
1616
|
-
|
1617
|
-
|
1618
|
-
xml.PEXF (pexf = zur_rose_detail[:price])
|
1619
|
-
end
|
1613
|
+
# Set the pharmatype to 'Y' for outdated products, which are no longer found
|
1614
|
+
# in refdata/packungen
|
1615
|
+
chap70 = nil
|
1616
|
+
if @chapter70items.values.find { |x| x[:pharmacode]&.eql?(obj[:pharmacode]) }
|
1617
|
+
Oddb2xml.log "found chapter #{obj[:pharmacode]}" if $VERBOSE
|
1618
|
+
chap70 = true
|
1620
1619
|
end
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1620
|
+
patched_pharma_type = (/^7680/.match(ean13.to_s.rjust(13, "0")) || chap70 ? "P" : "N")
|
1621
|
+
next if /^#{Oddb2xml::FAKE_GTIN_START}/o.match?(ean13.to_s)
|
1622
|
+
next if obj[:data_origin].eql?("zur_rose") && /^7680/.match(ean13) # must skip inactiv items
|
1623
|
+
xml.ITEM({"PHARMATYPE" => patched_pharma_type}) do
|
1624
|
+
xml.GTIN ean13.to_s.rjust(13, "0")
|
1625
|
+
if obj[:pharmacode] && obj[:pharmacode].length > 0
|
1626
|
+
xml.PHAR obj[:pharmacode]
|
1627
|
+
elsif (zur_rose = @infos_zur_rose[ean13])
|
1628
|
+
puts "Artikelstamm: Adding #{zur_rose[:pharmacode]} to article GTIN #{ean13}"
|
1629
|
+
xml.PHAR zur_rose[:pharmacode]
|
1630
|
+
elsif /^7680/.match?(ean13)
|
1631
|
+
puts "Artikelstamm: No pharmacode for article GTIN #{ean13} via ZurRose"
|
1632
|
+
end
|
1633
|
+
emit_salecd(xml, ean13, obj)
|
1634
|
+
description = obj[:desc_de] || obj[:description] # for description for zur_rose
|
1635
|
+
xml.DSCR(description)
|
1636
|
+
xml.DSCRF(obj[:desc_fr] || "--missing--")
|
1637
|
+
if obj[:company_ean] && !obj[:company_ean].empty?
|
1638
|
+
xml.COMP do
|
1639
|
+
xml.GLN obj[:company_ean]
|
1640
|
+
end
|
1641
|
+
end
|
1642
|
+
if !(obj[:price] && !obj[:price].empty?) || !(obj[:pub_price] && !obj[:pub_price].empty?)
|
1643
|
+
zur_rose_detail = @infos_zur_rose.values.find { |x| x[:ean13].to_i == ean13.to_i }
|
1644
|
+
end
|
1645
|
+
ppub = nil
|
1646
|
+
pexf = nil
|
1647
|
+
if obj[:price] && !obj[:price].empty?
|
1648
|
+
xml.PEXF(pexf = obj[:price])
|
1649
|
+
elsif zur_rose_detail
|
1650
|
+
if zur_rose_detail[:price] && !zur_rose_detail[:price].empty? && !zur_rose_detail[:price].eql?("0.00")
|
1651
|
+
# Oddb2xml.log "NonPharma: #{ean13} adding PEXF #{zur_rose_detail[:price]} #{description}"
|
1652
|
+
xml.PEXF(pexf = zur_rose_detail[:price])
|
1653
|
+
end
|
1654
|
+
end
|
1655
|
+
if obj[:pub_price] && !obj[:pub_price].empty?
|
1656
|
+
xml.PPUB(ppub = obj[:pub_price])
|
1657
|
+
elsif zur_rose_detail
|
1658
|
+
if zur_rose_detail[:pub_price] && !zur_rose_detail[:pub_price].empty? && !zur_rose_detail[:pub_price].eql?("0.00")
|
1659
|
+
# Oddb2xml.log "NonPharma: #{ean13} adding PPUB #{zur_rose_detail[:pub_price]} #{description}"
|
1660
|
+
xml.PPUB(ppub = zur_rose_detail[:pub_price])
|
1661
|
+
end
|
1662
|
+
end
|
1663
|
+
@csv_file << [ean13, description, "", "", pexf, ppub, "", "", "", "", "", ""]
|
1664
|
+
if chap70
|
1665
|
+
xml.comment "Chapter70 hack #{ean13.to_s.rjust(13, "0")} #{description.encode(xml: :text).gsub("--", "-")}"
|
1666
|
+
xml.SL_ENTRY "true"
|
1667
|
+
xml.PRODNO obj[:pharmacode]
|
1627
1668
|
end
|
1628
|
-
end
|
1629
|
-
@csv_file << [ ean13, description, '', '', pexf, ppub, '', '', '', '', '', '' ]
|
1630
|
-
if chap70
|
1631
|
-
xml.comment "Chapter70 hack"
|
1632
|
-
xml.SL_ENTRY 'true'
|
1633
|
-
xml.PRODNO obj[:pharmacode]
|
1634
|
-
xml.Chapter70_HACK 'true'
|
1635
1669
|
end
|
1636
1670
|
end
|
1637
1671
|
end
|
1672
|
+
@csv_file.close if @csv_file && !@csv_file.closed?
|
1673
|
+
nr_items
|
1638
1674
|
end
|
1639
|
-
@csv_file.close if @csv_file && !@csv_file.closed?
|
1640
|
-
nr_items
|
1641
1675
|
end
|
1642
1676
|
unless @prepared
|
1643
|
-
require
|
1644
|
-
Oddb2xml::Chapter70xtractor.parse
|
1677
|
+
require "oddb2xml/chapter_70_hack"
|
1678
|
+
Oddb2xml::Chapter70xtractor.parse
|
1645
1679
|
@chapter70items = Oddb2xml::Chapter70xtractor.items
|
1646
1680
|
prepare_limitations
|
1647
1681
|
prepare_articles
|
@@ -1650,33 +1684,25 @@ module Oddb2xml
|
|
1650
1684
|
prepare_calc_items(suppress_composition_parsing: true)
|
1651
1685
|
@prepared = true
|
1652
1686
|
@old_rose_size = @infos_zur_rose.size
|
1653
|
-
@infos_zur_rose.each do |ean13, value|
|
1654
|
-
if /^7680/.match(ean13.to_s) && @options[:artikelstamm]
|
1655
|
-
@infos_zur_rose.delete(ean13)
|
1656
|
-
end
|
1657
|
-
end if false
|
1658
|
-
@new_rose_size = @infos_zur_rose.size
|
1659
1687
|
end
|
1660
1688
|
nr_products = 0
|
1661
1689
|
nr_articles = 0
|
1662
1690
|
@nr_articles = 0
|
1663
1691
|
used_limitations = []
|
1664
|
-
Oddb2xml.log "#{variant}: Deleted #{@old_rose_size - @new_rose_size} entries from ZurRose where GTIN start with 7680 (Swissmedic)"
|
1665
1692
|
# Oddb2xml.log "#{variant} #{nr_products} of #{@products.size} articles and ignore #{@@gtin2ignore.size} gtins specified via #{@@ignore_file}"
|
1666
|
-
|
1693
|
+
a_builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
|
1667
1694
|
xml.doc.tag_suffix = @tag_suffix
|
1668
|
-
datetime = Time.new.strftime('%FT%T%z')
|
1669
1695
|
elexis_strftime_format = "%FT%T\.%L%:z"
|
1670
|
-
@@cumul_ver = (Date.today.year-2013)*12+Date.today.month
|
1671
|
-
options_xml =
|
1672
|
-
|
1673
|
-
|
1674
|
-
|
1675
|
-
|
1696
|
+
@@cumul_ver = (Date.today.year - 2013) * 12 + Date.today.month
|
1697
|
+
options_xml = {
|
1698
|
+
"xmlns" => "http://elexis.ch/Elexis_Artikelstamm_v5",
|
1699
|
+
"CREATION_DATETIME" => Time.new.strftime(elexis_strftime_format),
|
1700
|
+
"BUILD_DATETIME" => Time.new.strftime(elexis_strftime_format),
|
1701
|
+
"DATA_SOURCE" => "oddb2xml"
|
1676
1702
|
}
|
1677
1703
|
emitted_prodno = []
|
1678
1704
|
no8_to_prodno = {}
|
1679
|
-
@packs.collect{ |key, val| no8_to_prodno[key] = val [:prodno] }
|
1705
|
+
@packs.collect { |key, val| no8_to_prodno[key] = val [:prodno] }
|
1680
1706
|
xml.comment("Produced by #{__FILE__} version #{VERSION} at #{Time.now}")
|
1681
1707
|
xml.ARTIKELSTAMM(options_xml) do
|
1682
1708
|
xml.PRODUCTS do
|
@@ -1684,22 +1710,22 @@ module Oddb2xml
|
|
1684
1710
|
products.each do |product|
|
1685
1711
|
ean13 = product[0]
|
1686
1712
|
obj = product[1]
|
1687
|
-
next if /^Q/i.match(obj[:atc])
|
1713
|
+
next if /^Q/i.match?(obj[:atc])
|
1688
1714
|
ean = obj[:ean13]
|
1689
1715
|
sequence = obj[:seq]
|
1690
1716
|
sequence ||= @products[ean][:seq] if @products[ean]
|
1691
|
-
next unless
|
1692
|
-
ppac = ((
|
1693
|
-
prodno = ppac[:prodno] if ppac[:prodno]
|
1717
|
+
next unless check_article_name(obj, :de)
|
1718
|
+
ppac = ((a_ppac = @packs[ean.to_s[4..11]]) && !a_ppac[:is_tier] ? a_ppac : {})
|
1719
|
+
prodno = ppac[:prodno] if ppac[:prodno] && !ppac[:prodno].empty?
|
1694
1720
|
prodno = obj[:pharmacode] if obj[:chapter70]
|
1695
|
-
|
1696
|
-
if
|
1697
|
-
prodno ||=
|
1698
|
-
puts "Setting prodno #{prodno} for #{ean13} #{
|
1721
|
+
my_pack = @packs.values.find { |x| x[:iksnr].to_i == obj[:seq][:swissmedic_number5].to_i } if obj[:seq]
|
1722
|
+
if my_pack && !prodno
|
1723
|
+
prodno ||= my_pack[:prodno]
|
1724
|
+
puts "Setting prodno #{prodno} for #{ean13} #{my_pack[:sequence_name]}"
|
1699
1725
|
end
|
1700
1726
|
next unless prodno
|
1701
1727
|
next if emitted_prodno.index(prodno)
|
1702
|
-
sequence ||= @articles.find{|x| x[:ean13].eql?(ean)}
|
1728
|
+
sequence ||= @articles.find { |x| x[:ean13].eql?(ean) }
|
1703
1729
|
unless obj[:chapter70]
|
1704
1730
|
next unless sequence && (sequence[:name_de] || sequence[:desc_de])
|
1705
1731
|
if Oddb2xml.getEan13forProdno(prodno).size == 0 && !obj[:no8].eql?(Oddb2xml.getNo8ForEan13(ean))
|
@@ -1712,44 +1738,43 @@ module Oddb2xml
|
|
1712
1738
|
xml.PRODUCT do
|
1713
1739
|
xml.PRODNO prodno
|
1714
1740
|
if sequence
|
1715
|
-
xml.SALECD(
|
1741
|
+
xml.SALECD("A") # these products are always active!
|
1716
1742
|
name_de = "#{sequence[:name_de]} #{sequence[:desc_de]}".strip if sequence[:name_de]
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
name_de = sequence[:desc_de]
|
1722
|
-
end
|
1743
|
+
name_de ||= if ppac && /stk/i.match(sequence[:desc_de])
|
1744
|
+
ppac[:sequence_name]
|
1745
|
+
else
|
1746
|
+
sequence[:desc_de]
|
1723
1747
|
end
|
1724
1748
|
name_fr = "#{sequence[:name_fr]} #{sequence[:desc_fr]}".strip if sequence[:name_fr]
|
1725
1749
|
name_fr ||= (ppac && ppac[:sequence_name])
|
1726
|
-
override(xml, prodno, :DSCR,
|
1750
|
+
override(xml, prodno, :DSCR, name_de.strip)
|
1727
1751
|
override(xml, prodno, :DSCRF, name_fr.strip)
|
1752
|
+
# use overriden ATC if possibel
|
1753
|
+
atc = sequence[:atc] || sequence[:atc_code]
|
1754
|
+
xml.ATC atc if atc && !atc.empty?
|
1728
1755
|
end
|
1729
|
-
xml.ATC sequence[:atc_code] if sequence && sequence[:atc_code] && !sequence[:atc_code].empty?
|
1730
1756
|
if sequence && sequence[:packages] && (first_package = sequence[:packages].values.first) &&
|
1731
|
-
|
1757
|
+
(first_limitation = first_package[:limitations].first)
|
1732
1758
|
lim_code = first_limitation[:code]
|
1733
1759
|
used_limitations << lim_code unless used_limitations.index(lim_code)
|
1734
1760
|
xml.LIMNAMEBAG lim_code
|
1735
1761
|
elsif obj[:chapter70]
|
1736
|
-
xml.comment "Chapter70 hack"
|
1737
|
-
xml.SALECD(
|
1762
|
+
xml.comment "Chapter70 hack prodno #{prodno} #{obj[:description].encode(xml: :text).gsub("--", "-")}"
|
1763
|
+
xml.SALECD("A") # these products are always active!
|
1738
1764
|
xml.DSCR obj[:description]
|
1739
|
-
xml.DSCRF
|
1765
|
+
xml.DSCRF ""
|
1740
1766
|
if @limitations.index(obj[:code])
|
1741
1767
|
xml.LIMNAMEBAG obj[:code]
|
1742
1768
|
used_limitations << obj[:code]
|
1743
1769
|
end
|
1744
1770
|
end
|
1745
1771
|
if sequence && sequence[:substances]
|
1746
|
-
value =
|
1747
|
-
|
1748
|
-
value = 'Verschiedene Kombinationen'
|
1772
|
+
value = if sequence[:substances].size > 1
|
1773
|
+
"Verschiedene Kombinationen"
|
1749
1774
|
elsif sequence[:substances].first
|
1750
|
-
|
1775
|
+
sequence[:substances].first[:name]
|
1751
1776
|
else
|
1752
|
-
|
1777
|
+
obj[:sub]
|
1753
1778
|
end
|
1754
1779
|
override(xml, prodno, :SUBSTANCE, value) if value
|
1755
1780
|
end
|
@@ -1766,11 +1791,11 @@ module Oddb2xml
|
|
1766
1791
|
end
|
1767
1792
|
emitted_lim_code << lim[:code]
|
1768
1793
|
xml.LIMITATION do
|
1769
|
-
xml.comment "Chapter70 hack" if lim[:chap70]
|
1794
|
+
xml.comment "Chapter70 2 hack" if lim[:chap70]
|
1770
1795
|
xml.LIMNAMEBAG lim[:code] # original LIMCD
|
1771
|
-
xml.DSCR
|
1772
|
-
xml.DSCRF
|
1773
|
-
xml.LIMITATION_PTS
|
1796
|
+
xml.DSCR Oddb2xml.html_decode(lim[:desc_de])
|
1797
|
+
xml.DSCRF Oddb2xml.html_decode(lim[:desc_fr])
|
1798
|
+
xml.LIMITATION_PTS(lim[:value].to_s.length > 1 ? lim[:value] : 1)
|
1774
1799
|
end
|
1775
1800
|
end
|
1776
1801
|
end
|
@@ -1781,17 +1806,19 @@ module Oddb2xml
|
|
1781
1806
|
end
|
1782
1807
|
Oddb2xml.log "#{variant}. Done #{nr_products} of #{@products.size} products, #{@limitations.size} limitations and #{nr_articles}/#{@nr_articles} articles. @@emitted_v5_gtins #{@@emitted_v5_gtins.size}"
|
1783
1808
|
# we don't add a SHA256 hash for each element in the article
|
1784
|
-
# Oddb2xml.add_hash(
|
1809
|
+
# Oddb2xml.add_hash(a_builder.to_xml)
|
1785
1810
|
# doc = REXML::Document.new( source, { :raw => :all })
|
1786
1811
|
# doc.write( $stdout, 0 )
|
1787
1812
|
lines = []
|
1788
|
-
lines << " - #{sprintf(
|
1789
|
-
lines << " - #{sprintf(
|
1790
|
-
lines << " - #{sprintf(
|
1791
|
-
lines << " - #{sprintf(
|
1813
|
+
lines << " - #{sprintf("%5d", @products.size)} products"
|
1814
|
+
lines << " - #{sprintf("%5d", @limitations.size)} limitations"
|
1815
|
+
lines << " - #{sprintf("%5d", @nr_articles)} articles"
|
1816
|
+
lines << " - #{sprintf("%5d", @@gtin2ignore.size)} ignored GTINS"
|
1792
1817
|
@@articlestamm_v5_info_lines = lines
|
1793
|
-
|
1818
|
+
a_builder.to_xml({indent: 4, encoding: "UTF-8"})
|
1794
1819
|
end
|
1820
|
+
|
1821
|
+
private_class_method
|
1795
1822
|
def self.articlestamm_v5_info_lines
|
1796
1823
|
@@articlestamm_v5_info_lines
|
1797
1824
|
end
|