eancom 0.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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