eancom 0.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +190 -5
  3. data/.gitlab-ci.yml +25 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile.lock +22 -18
  6. data/README.md +46 -0
  7. data/bin/console +3 -2
  8. data/definitions/desadv/d01b.rb +251 -0
  9. data/definitions/desadv/d96a.rb +208 -87
  10. data/definitions/invoic/d01b.rb +559 -0
  11. data/definitions/invoic/d96a.rb +389 -0
  12. data/definitions/invrpt/d01b.rb +134 -0
  13. data/definitions/invrpt/d96a.rb +125 -0
  14. data/definitions/orders/d01b.rb +182 -0
  15. data/definitions/orders/d96b.rb +198 -0
  16. data/definitions/ordrsp/d01b.rb +251 -0
  17. data/definitions/ordrsp/d96b.rb +226 -0
  18. data/definitions/pricat/d01b.rb +225 -0
  19. data/definitions/pricat/d96b.rb +207 -0
  20. data/definitions/retann/d01b.rb +172 -0
  21. data/definitions/retann/d96b.rb +221 -0
  22. data/definitions/segments/ajt.rb +47 -0
  23. data/definitions/segments/alc.rb +328 -0
  24. data/definitions/segments/ali.rb +93 -0
  25. data/definitions/segments/bgm.rb +395 -0
  26. data/definitions/segments/cav.rb +122 -0
  27. data/definitions/segments/cci.rb +136 -0
  28. data/definitions/segments/cdi.rb +39 -0
  29. data/definitions/segments/cnt.rb +82 -0
  30. data/definitions/segments/cps.rb +76 -0
  31. data/definitions/segments/cta.rb +89 -0
  32. data/definitions/segments/cux.rb +174 -0
  33. data/definitions/segments/dgs.rb +34 -0
  34. data/definitions/segments/doc.rb +45 -0
  35. data/definitions/segments/dtm.rb +243 -0
  36. data/definitions/segments/efi.rb +67 -0
  37. data/definitions/segments/eqd.rb +37 -0
  38. data/definitions/segments/ftx.rb +165 -0
  39. data/definitions/segments/gin.rb +113 -0
  40. data/definitions/segments/imd.rb +360 -0
  41. data/definitions/segments/inv.rb +94 -0
  42. data/definitions/segments/lin.rb +133 -0
  43. data/definitions/segments/loc.rb +137 -0
  44. data/definitions/segments/mea.rb +189 -0
  45. data/definitions/segments/moa.rb +228 -0
  46. data/definitions/segments/nad.rb +314 -0
  47. data/definitions/segments/pac.rb +262 -0
  48. data/definitions/segments/pat.rb +171 -0
  49. data/definitions/segments/pcd.rb +72 -0
  50. data/definitions/segments/pci.rb +110 -0
  51. data/definitions/segments/pgi.rb +152 -0
  52. data/definitions/segments/pia.rb +501 -0
  53. data/definitions/segments/pri.rb +208 -0
  54. data/definitions/segments/qty.rb +293 -0
  55. data/definitions/segments/rff.rb +210 -0
  56. data/definitions/segments/rte.rb +52 -0
  57. data/definitions/segments/tax.rb +266 -0
  58. data/definitions/segments/tdt.rb +278 -0
  59. data/definitions/segments/tod.rb +64 -0
  60. data/definitions/segments/tru.rb +34 -0
  61. data/definitions/segments/una.rb +85 -0
  62. data/definitions/segments/unb.rb +284 -0
  63. data/definitions/segments/unh.rb +183 -0
  64. data/definitions/segments/uns.rb +40 -0
  65. data/definitions/segments/unt.rb +48 -0
  66. data/definitions/segments/unz.rb +48 -0
  67. data/definitions/slsrpt/d01b.rb +206 -0
  68. data/definitions/slsrpt/d96a.rb +199 -0
  69. data/eancom.gemspec +2 -1
  70. data/lib/eancom.rb +61 -16
  71. data/lib/eancom/definition.rb +1 -1
  72. data/lib/eancom/edifact.rb +60 -13
  73. data/lib/eancom/edifact/body.rb +63 -0
  74. data/lib/eancom/edifact/composite.rb +38 -0
  75. data/lib/eancom/edifact/data.rb +108 -0
  76. data/lib/eancom/edifact/document.rb +43 -11
  77. data/lib/eancom/edifact/document_element.rb +26 -0
  78. data/lib/eancom/edifact/footer.rb +7 -0
  79. data/lib/eancom/edifact/header.rb +15 -0
  80. data/lib/eancom/edifact/item.rb +40 -0
  81. data/lib/eancom/edifact/message.rb +24 -16
  82. data/lib/eancom/edifact/segment.rb +131 -12
  83. data/lib/eancom/edifact/segments/ajt.rb +32 -0
  84. data/lib/eancom/edifact/segments/alc.rb +61 -0
  85. data/lib/eancom/edifact/segments/ali.rb +50 -0
  86. data/lib/eancom/edifact/segments/bgm.rb +46 -0
  87. data/lib/eancom/edifact/segments/cav.rb +47 -0
  88. data/lib/eancom/edifact/segments/cci.rb +53 -0
  89. data/lib/eancom/edifact/segments/cdi.rb +30 -0
  90. data/lib/eancom/edifact/segments/cnt.rb +40 -0
  91. data/lib/eancom/edifact/segments/cps.rb +33 -0
  92. data/lib/eancom/edifact/segments/cta.rb +30 -0
  93. data/lib/eancom/edifact/segments/cux.rb +60 -0
  94. data/lib/eancom/edifact/segments/dgs.rb +31 -0
  95. data/lib/eancom/edifact/segments/doc.rb +30 -0
  96. data/lib/eancom/edifact/segments/dtm.rb +47 -0
  97. data/lib/eancom/edifact/segments/efi.rb +38 -0
  98. data/lib/eancom/edifact/segments/eqd.rb +30 -0
  99. data/lib/eancom/edifact/segments/ftx.rb +63 -0
  100. data/lib/eancom/edifact/segments/gin.rb +45 -0
  101. data/lib/eancom/edifact/segments/imd.rb +69 -0
  102. data/lib/eancom/edifact/segments/inv.rb +43 -0
  103. data/lib/eancom/edifact/segments/lin.rb +47 -0
  104. data/lib/eancom/edifact/segments/loc.rb +46 -0
  105. data/lib/eancom/edifact/segments/mea.rb +54 -0
  106. data/lib/eancom/edifact/segments/moa.rb +45 -0
  107. data/lib/eancom/edifact/segments/nad.rb +112 -0
  108. data/lib/eancom/edifact/segments/pac.rb +56 -0
  109. data/lib/eancom/edifact/segments/pat.rb +37 -0
  110. data/lib/eancom/edifact/segments/pcd.rb +33 -0
  111. data/lib/eancom/edifact/segments/pci.rb +40 -0
  112. data/lib/eancom/edifact/segments/pgi.rb +45 -0
  113. data/lib/eancom/edifact/segments/pia.rb +108 -0
  114. data/lib/eancom/edifact/segments/pri.rb +53 -0
  115. data/lib/eancom/edifact/segments/qty.rb +44 -0
  116. data/lib/eancom/edifact/segments/rff.rb +47 -0
  117. data/lib/eancom/edifact/segments/rte.rb +33 -0
  118. data/lib/eancom/edifact/segments/tax.rb +78 -0
  119. data/lib/eancom/edifact/segments/tdt.rb +57 -0
  120. data/lib/eancom/edifact/segments/tod.rb +33 -0
  121. data/lib/eancom/edifact/segments/tru.rb +31 -0
  122. data/lib/eancom/edifact/segments/una.rb +52 -0
  123. data/lib/eancom/edifact/segments/unb.rb +68 -0
  124. data/lib/eancom/edifact/segments/unh.rb +50 -0
  125. data/lib/eancom/edifact/segments/uns.rb +32 -0
  126. data/lib/eancom/edifact/segments/unt.rb +28 -0
  127. data/lib/eancom/edifact/segments/unz.rb +28 -0
  128. data/lib/eancom/edifact/structure.rb +90 -0
  129. data/lib/eancom/factory.rb +9 -8
  130. data/lib/eancom/parser.rb +7 -0
  131. data/lib/eancom/parser/document.rb +60 -0
  132. data/lib/eancom/parser/segment.rb +71 -0
  133. data/lib/eancom/version.rb +1 -1
  134. data/pricat.json +1 -0
  135. metadata +141 -9
  136. data/lib/eancom/edifact/element.rb +0 -16
  137. data/lib/eancom/edifact/envelope.rb +0 -24
data/eancom.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  require_relative 'lib/eancom/version'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
- spec.name = "eancom"
4
+ spec.name = 'eancom'
5
5
  spec.version = Eancom::VERSION
6
6
  spec.authors = ["Fadendaten GmbH"]
7
7
  spec.email = ["support@fadendaten.ch"]
@@ -27,4 +27,5 @@ Gem::Specification.new do |spec|
27
27
  spec.add_development_dependency "pry-remote"
28
28
  spec.add_development_dependency "pry-nav"
29
29
  spec.add_development_dependency "simplecov"
30
+ spec.add_development_dependency "timecop"
30
31
  end
data/lib/eancom.rb CHANGED
@@ -1,43 +1,88 @@
1
1
  require 'eancom/version'
2
- require 'eancom/edifact'
3
2
 
4
3
  module Eancom
5
4
 
6
5
  class Error < StandardError; end
6
+ class StructureNotFoundError < StandardError; end
7
+
8
+ FILE_TYPES = %I[
9
+ desadv
10
+ pricat
11
+ ordrsp
12
+ slsrpt
13
+ invrpt
14
+ orders
15
+ invoic
16
+ retann
17
+ ].freeze
7
18
 
8
- FILE_TYPES = [
9
- :desadv,
10
- :pricat,
11
- :ordrsp,
12
- :salsrp,
13
- :invrp,
14
- :orders
15
- ]
19
+ DELIMITERS = {
20
+ component: ':',
21
+ data: '+',
22
+ release: '?',
23
+ decimal: '.',
24
+ reserve: ' ',
25
+ segment: '\''
26
+ }.freeze
16
27
 
17
- attr_accessor :definitions
28
+ attr_accessor :definitions, :segments
18
29
 
19
30
  def self.definitions
20
- @@configs ||= Hash.new
31
+ @configs ||= {}
32
+ end
33
+
34
+ def self.segments
35
+ @segments ||= {}
36
+ end
37
+
38
+ def self.structures
39
+ @structures ||= {}
21
40
  end
22
41
 
23
42
  def self.register_definition(definition)
24
43
  type = definition.type
25
44
  name = definition.name
26
- definitions[type] ||= Hash.new
45
+ definitions[type] ||= {}
27
46
  definitions[type][name] = definition
28
47
  end
29
48
 
30
49
  def self.find_definition(name:, type:)
31
50
  definitions[type][name]
32
51
  end
52
+
53
+ def self.register_segment(tag:, klass:)
54
+ segments[tag] ||= klass
55
+ end
56
+
57
+ def self.find_segment(tag:)
58
+ segments[tag]
59
+ end
60
+
61
+ def self.register_structure(tag:, structure:)
62
+ structures[tag] ||= structure
63
+ end
64
+
65
+ def self.find_structure(tag:)
66
+ structure = structures[tag]
67
+ if structure.nil?
68
+ raise StructureNotFoundError.new(
69
+ "Structure for tag: #{tag} not found."
70
+ )
71
+ end
72
+ structure
73
+ end
33
74
  end
34
75
 
35
- require "eancom/factory"
36
- require "eancom/definition"
76
+ # TODO: Describe why loaded here...
77
+
78
+ require 'eancom/edifact'
79
+ require 'eancom/factory'
80
+ require 'eancom/parser'
81
+ require 'eancom/definition'
37
82
 
38
- spec = Gem::Specification.find_by_name("eancom")
83
+ spec = Gem::Specification.find_by_name('eancom')
39
84
  gem_root = spec.gem_dir
40
85
 
41
- Dir[File.join(gem_root, "definitions", "**/*.rb")].sort.each do |file|
86
+ Dir[File.join(gem_root, 'definitions', '**/*.rb')].sort.each do |file|
42
87
  require file
43
88
  end
@@ -5,7 +5,7 @@ module Eancom
5
5
 
6
6
  def self.create(name:, type:, &block)
7
7
  definition = new(name: name, type: type, &block)
8
- Eancom::register_definition(definition)
8
+ Eancom.register_definition(definition)
9
9
  end
10
10
 
11
11
  def initialize(name:, type:, &block)
@@ -1,19 +1,66 @@
1
- require 'eancom/edifact/element'
2
- require 'eancom/edifact/document'
3
- require 'eancom/edifact/envelope'
4
- require 'eancom/edifact/message'
5
1
  require 'eancom/edifact/segment'
6
2
 
3
+ require 'eancom/edifact/document_element'
4
+ require 'eancom/edifact/header'
5
+ require 'eancom/edifact/message'
6
+ require 'eancom/edifact/item'
7
+ require 'eancom/edifact/body'
8
+ require 'eancom/edifact/footer'
9
+
10
+ require 'eancom/edifact/document'
11
+
12
+ require 'eancom/edifact/structure'
13
+ require 'eancom/edifact/composite'
14
+ require 'eancom/edifact/data'
15
+
16
+ require 'eancom/edifact/segments/una'
17
+ require 'eancom/edifact/segments/unb'
18
+ require 'eancom/edifact/segments/unh'
19
+ require 'eancom/edifact/segments/uns'
20
+ require 'eancom/edifact/segments/unt'
21
+ require 'eancom/edifact/segments/unz'
22
+
23
+ require 'eancom/edifact/segments/alc'
24
+ require 'eancom/edifact/segments/ajt'
25
+ require 'eancom/edifact/segments/dgs'
26
+ require 'eancom/edifact/segments/efi'
27
+ require 'eancom/edifact/segments/tru'
28
+ require 'eancom/edifact/segments/cdi'
29
+ require 'eancom/edifact/segments/gin'
30
+ require 'eancom/edifact/segments/rte'
31
+ require 'eancom/edifact/segments/pcd'
32
+ require 'eancom/edifact/segments/eqd'
33
+ require 'eancom/edifact/segments/tod'
34
+ require 'eancom/edifact/segments/pat'
35
+ require 'eancom/edifact/segments/doc'
36
+ require 'eancom/edifact/segments/ali'
37
+ require 'eancom/edifact/segments/bgm'
38
+ require 'eancom/edifact/segments/cav'
39
+ require 'eancom/edifact/segments/cci'
40
+ require 'eancom/edifact/segments/cnt'
41
+ require 'eancom/edifact/segments/cps'
42
+ require 'eancom/edifact/segments/cux'
43
+ require 'eancom/edifact/segments/cta'
44
+ require 'eancom/edifact/segments/dtm'
45
+ require 'eancom/edifact/segments/ftx'
46
+ require 'eancom/edifact/segments/imd'
47
+ require 'eancom/edifact/segments/inv'
48
+ require 'eancom/edifact/segments/lin'
49
+ require 'eancom/edifact/segments/loc'
50
+ require 'eancom/edifact/segments/mea'
51
+ require 'eancom/edifact/segments/moa'
52
+ require 'eancom/edifact/segments/nad'
53
+ require 'eancom/edifact/segments/pac'
54
+ require 'eancom/edifact/segments/pci'
55
+ require 'eancom/edifact/segments/pgi'
56
+ require 'eancom/edifact/segments/pia'
57
+ require 'eancom/edifact/segments/pri'
58
+ require 'eancom/edifact/segments/qty'
59
+ require 'eancom/edifact/segments/rff'
60
+ require 'eancom/edifact/segments/tax'
61
+ require 'eancom/edifact/segments/tdt'
62
+
7
63
  module Eancom
8
64
  module Edifact
9
- DELIMITERS = {
10
- component: ':',
11
- data: '+',
12
- decimal: '.',
13
- release: '?',
14
- reserve: ' ',
15
- segment: "'"
16
- }
17
65
  end
18
66
  end
19
-
@@ -0,0 +1,63 @@
1
+ module Eancom
2
+ module Edifact
3
+ class Body < DocumentElement
4
+
5
+ attr_accessor :hash, :items, :messages
6
+
7
+ def initialize
8
+ super
9
+ @hash = {}
10
+ @messages = []
11
+ end
12
+
13
+ def to_json_hash
14
+ @segments.each do |segment|
15
+ start_message(segment) if segment.starts_message?
16
+ start_item(segment) if segment.starts_item?
17
+ if @item
18
+ @item << segment
19
+ else
20
+ @message << segment
21
+ end
22
+ end
23
+ @message.add_item(@item.to_json_hash)
24
+ @messages << @message.to_json_hash
25
+ hash.merge!({ messages: messages })
26
+ { body: hash }
27
+ end
28
+
29
+ def start_message(segment)
30
+ if @message
31
+ @messages << @message.to_json_hash
32
+ if @item && !@item.empty?
33
+ @message.add_item(@item.to_json_hash)
34
+ end
35
+ @item = nil
36
+ end
37
+ @message = Eancom::Edifact::Message.new()
38
+ end
39
+
40
+ def start_item(segment)
41
+ if @item && !@item.empty?
42
+ @message.add_item(@item.to_json_hash)
43
+ end
44
+ @item = Eancom::Edifact::Item.new()
45
+ end
46
+
47
+ private
48
+
49
+ def merge(hash, segment)
50
+ if name = group_name(segment)
51
+ hash[name] = [] if hash[name].nil?
52
+ hash[name] << segment.to_json_hash
53
+ else
54
+ hash.merge!(segment.to_json_hash)
55
+ end
56
+ end
57
+
58
+ def group_name(segment)
59
+ return segment.group_name
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,38 @@
1
+ module Eancom
2
+ module Edifact
3
+ class Composite
4
+ class DataTypeError < StandardError; end
5
+
6
+ attr_reader :data
7
+
8
+ def initialize
9
+ @data = {}
10
+ end
11
+
12
+ def add(key, value)
13
+ if value.kind_of?(Data)
14
+ @data[key] = value
15
+ else
16
+ raise DataTypeError.new('Added value is not of type Data.')
17
+ end
18
+ end
19
+
20
+ def get(key)
21
+ @data[key]
22
+ end
23
+
24
+ def delete(key)
25
+ @data.delete(key)
26
+ end
27
+
28
+ def to_array
29
+ array = []
30
+ @data.each do |key, value|
31
+ array << key
32
+ end
33
+ array
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,108 @@
1
+ module Eancom
2
+ module Edifact
3
+ class Data
4
+ class TypeError < StandardError; end
5
+ class LengthError < StandardError; end
6
+ class RequiredError < StandardError; end
7
+ class NotFoundInDictionary < StandardError; end
8
+
9
+ attr_accessor :type, :length, :dictionary, :description, :required
10
+
11
+ def initialize(type:,
12
+ length:,
13
+ dictionary: nil,
14
+ description:,
15
+ required:
16
+ )
17
+ @type = type
18
+ @length = length
19
+ @dictionary = dictionary
20
+ @description = description
21
+ @required = required
22
+ end
23
+
24
+ def valid?(key, value)
25
+ type?(key, value)
26
+ length?(key, value)
27
+ required?(key, value)
28
+ dictionary?(key, value) unless value.empty?
29
+ end
30
+
31
+
32
+ def identifier(value)
33
+ if @dictionary
34
+ hash = @dictionary[value]
35
+ unless hash
36
+ raise NotFoundInDictionary.new(
37
+ "Value not found for #{value}. Error in Data: #{self.to_s}"
38
+ )
39
+ else
40
+ hash[:identifier]
41
+ end
42
+ else
43
+ ""
44
+ end
45
+ end
46
+
47
+ def to_s
48
+ "type: #{@type} " \
49
+ "length: #{@length} " \
50
+ "dictionary: #{@dictionary} " \
51
+ "description: #{@description} " \
52
+ "required: #{required} "
53
+ end
54
+
55
+ private
56
+
57
+ def type?(key, value)
58
+ unless value.kind_of?(@type)
59
+ raise TypeError.new(
60
+ "Wrong type of #{key}: #{value}, should be #{@type}. Error in Data: #{self.to_s}"
61
+ )
62
+ end
63
+ end
64
+
65
+ def length?(key, value)
66
+ if @length.kind_of?(Range)
67
+ unless @length.include?(value.length)
68
+ raise LengthError.new(
69
+ "The value #{key}: #{value} is not in the range of #{@length}. Error in Data: #{self.to_s}")
70
+ end
71
+ elsif @length.kind_of?(Integer)
72
+ unless value.length == @length
73
+ raise LengthError.new(
74
+ "The length of #{key}: #{value} should be #{@length}. Error in Data: #{self.to_s}"
75
+ )
76
+ end
77
+ else
78
+ raise LengthError.new(
79
+ "Error in length definition. Error in Data: #{self.to_s}"
80
+ )
81
+ end
82
+ end
83
+
84
+ def required?(key, value)
85
+ unless (!@required || !value.nil?)
86
+ raise RequiredError.new(
87
+ "The field required. Error in #{self.to_s}"
88
+ )
89
+ end
90
+ end
91
+
92
+ def dictionary?(key, value)
93
+ unless @dictionary.nil?
94
+ unless @dictionary.key?(value)
95
+ if @dictionary.key?('*') # Bypass Validation
96
+ return true
97
+ else
98
+ raise NotFoundInDictionary.new(
99
+ "The value '#{key}: #{value}' is not in the dictionary. Error in #{self.to_s}"
100
+ )
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ end
107
+ end
108
+ end
@@ -2,27 +2,59 @@ module Eancom
2
2
  module Edifact
3
3
  class Document
4
4
 
5
+ attr_accessor :header_element, :body_element, :footer_element
6
+
5
7
  def initialize
6
- @envelope = Envelope.new
7
- @message = Message.new
8
+ @header_element = Header.new()
9
+ @body_element = Body.new()
10
+ @footer_element = Footer.new()
11
+ end
12
+
13
+ def header(&block)
14
+ yield(@header_element)
15
+ end
16
+
17
+ def body(&block)
18
+ yield(@body_element)
19
+ end
20
+
21
+ def footer(&block)
22
+ yield(@footer_element)
23
+ end
24
+
25
+ def add_to_header(segment)
26
+ @header_element.segment(segment)
8
27
  end
9
28
 
10
- def envelope(&block)
11
- yield(@envelope)
29
+ def add_to_body(segment)
30
+ @body_element.segment(segment)
12
31
  end
13
32
 
14
- def message(name, &block)
15
- @message.name = name
16
- yield(@message)
33
+ def add_to_footer(segment)
34
+ @footer_element.segment(segment)
17
35
  end
18
36
 
19
- def to_s
20
- stream = ""
21
- stream << @envelope.to_s
22
- stream << @message.to_s
37
+ # Should header and footer segments be added to total_segments?
38
+ def total_segments
39
+ total = 0
40
+ total += @body_element.segments.count
41
+ total
42
+ end
43
+
44
+ def to_s(debug: false)
45
+ stream = ''
46
+ stream << @header_element.to_s(debug: debug)
47
+ stream << @body_element.to_s(debug: debug)
48
+ stream << @footer_element.to_s(debug: debug)
23
49
  stream
24
50
  end
25
51
 
52
+ def to_json
53
+ hash = {}
54
+ hash.merge! @header_element.to_json_hash
55
+ hash.merge! @body_element.to_json_hash
56
+ hash.to_json
57
+ end
26
58
  end
27
59
  end
28
60
  end