eancom 0.1.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/.gitignore +187 -6
  4. data/.gitlab-ci.yml +27 -0
  5. data/.rspec_status +223 -0
  6. data/.rubocop.yml +2 -0
  7. data/.ruby-version +1 -0
  8. data/Gemfile +4 -2
  9. data/Gemfile.lock +87 -3
  10. data/bin/console +3 -2
  11. data/definitions/desadv/d01b.rb +205 -0
  12. data/definitions/desadv/d96a.rb +108 -73
  13. data/definitions/segments/alc.rb +236 -0
  14. data/definitions/segments/ali.rb +93 -0
  15. data/definitions/segments/bgm.rb +267 -0
  16. data/definitions/segments/cav.rb +122 -0
  17. data/definitions/segments/cci.rb +136 -0
  18. data/definitions/segments/cnt.rb +78 -0
  19. data/definitions/segments/cps.rb +76 -0
  20. data/definitions/segments/cux.rb +167 -0
  21. data/definitions/segments/dtm.rb +159 -0
  22. data/definitions/segments/ftx.rb +143 -0
  23. data/definitions/segments/imd.rb +356 -0
  24. data/definitions/segments/lin.rb +113 -0
  25. data/definitions/segments/loc.rb +89 -0
  26. data/definitions/segments/mea.rb +189 -0
  27. data/definitions/segments/moa.rb +144 -0
  28. data/definitions/segments/nad.rb +254 -0
  29. data/definitions/segments/pac.rb +250 -0
  30. data/definitions/segments/pgi.rb +148 -0
  31. data/definitions/segments/pia.rb +501 -0
  32. data/definitions/segments/pri.rb +188 -0
  33. data/definitions/segments/qty.rb +79 -0
  34. data/definitions/segments/rff.rb +166 -0
  35. data/definitions/segments/tax.rb +259 -0
  36. data/definitions/segments/tdt.rb +254 -0
  37. data/definitions/segments/una.rb +85 -0
  38. data/definitions/segments/unb.rb +284 -0
  39. data/definitions/segments/unh.rb +118 -0
  40. data/definitions/segments/uns.rb +40 -0
  41. data/definitions/segments/unt.rb +48 -0
  42. data/definitions/segments/unz.rb +48 -0
  43. data/definitions/slsrpt/d01b.rb +197 -0
  44. data/definitions/slsrpt/d96a.rb +194 -0
  45. data/eancom.gemspec +9 -5
  46. data/lib/eancom/definition.rb +1 -1
  47. data/lib/eancom/edifact/body.rb +63 -0
  48. data/lib/eancom/edifact/composite.rb +38 -0
  49. data/lib/eancom/edifact/data.rb +108 -0
  50. data/lib/eancom/edifact/document.rb +43 -11
  51. data/lib/eancom/edifact/document_element.rb +26 -0
  52. data/lib/eancom/edifact/footer.rb +6 -0
  53. data/lib/eancom/edifact/header.rb +15 -0
  54. data/lib/eancom/edifact/item.rb +40 -0
  55. data/lib/eancom/edifact/message.rb +24 -16
  56. data/lib/eancom/edifact/segment.rb +131 -12
  57. data/lib/eancom/edifact/segments/alc.rb +61 -0
  58. data/lib/eancom/edifact/segments/ali.rb +52 -0
  59. data/lib/eancom/edifact/segments/bgm.rb +45 -0
  60. data/lib/eancom/edifact/segments/cav.rb +47 -0
  61. data/lib/eancom/edifact/segments/cci.rb +53 -0
  62. data/lib/eancom/edifact/segments/cnt.rb +33 -0
  63. data/lib/eancom/edifact/segments/cps.rb +30 -0
  64. data/lib/eancom/edifact/segments/cux.rb +60 -0
  65. data/lib/eancom/edifact/segments/dtm.rb +43 -0
  66. data/lib/eancom/edifact/segments/ftx.rb +63 -0
  67. data/lib/eancom/edifact/segments/imd.rb +69 -0
  68. data/lib/eancom/edifact/segments/lin.rb +43 -0
  69. data/lib/eancom/edifact/segments/loc.rb +43 -0
  70. data/lib/eancom/edifact/segments/mea.rb +53 -0
  71. data/lib/eancom/edifact/segments/moa.rb +45 -0
  72. data/lib/eancom/edifact/segments/nad.rb +107 -0
  73. data/lib/eancom/edifact/segments/pac.rb +54 -0
  74. data/lib/eancom/edifact/segments/pgi.rb +45 -0
  75. data/lib/eancom/edifact/segments/pia.rb +107 -0
  76. data/lib/eancom/edifact/segments/pri.rb +54 -0
  77. data/lib/eancom/edifact/segments/qty.rb +40 -0
  78. data/lib/eancom/edifact/segments/rff.rb +41 -0
  79. data/lib/eancom/edifact/segments/tax.rb +72 -0
  80. data/lib/eancom/edifact/segments/tdt.rb +54 -0
  81. data/lib/eancom/edifact/segments/una.rb +51 -0
  82. data/lib/eancom/edifact/segments/unb.rb +66 -0
  83. data/lib/eancom/edifact/segments/unh.rb +46 -0
  84. data/lib/eancom/edifact/segments/uns.rb +29 -0
  85. data/lib/eancom/edifact/segments/unt.rb +28 -0
  86. data/lib/eancom/edifact/segments/unz.rb +28 -0
  87. data/lib/eancom/edifact/structure.rb +91 -0
  88. data/lib/eancom/edifact.rb +45 -12
  89. data/lib/eancom/factory.rb +8 -7
  90. data/lib/eancom/parser/document.rb +68 -0
  91. data/lib/eancom/parser/segment.rb +71 -0
  92. data/lib/eancom/parser.rb +7 -0
  93. data/lib/eancom/version.rb +1 -1
  94. data/lib/eancom.rb +59 -16
  95. metadata +138 -5
  96. data/lib/eancom/edifact/element.rb +0 -16
  97. data/lib/eancom/edifact/envelope.rb +0 -24
@@ -0,0 +1,66 @@
1
+ module Eancom
2
+ module Edifact
3
+ class UNB < Segment
4
+ TAG = 'UNB'.freeze
5
+ TYPE = :header.freeze
6
+
7
+ def initialize(tag: nil,
8
+ syntax_identifier:,
9
+ syntax_version_number:,
10
+ interchange_sender_identification:,
11
+ sender_identifiction_code_qualifier:,
12
+ interchange_sender_internal_identification: nil,
13
+ interchange_recipient_identification:,
14
+ recipient_identifiction_code_qualifier:,
15
+ interchange_recipient_internal_identification: nil,
16
+ date:,
17
+ time:,
18
+ interchange_control_reference:,
19
+ recipient_reference: nil,
20
+ recipient_reference_qualifier: nil,
21
+ application_reference: nil,
22
+ processing_priority_code: nil,
23
+ acknowledgement_request: nil,
24
+ interchange_agreement_identifier: nil,
25
+ test_indicator: nil
26
+ )
27
+ @tag = tag
28
+ @syntax_identifier = syntax_identifier
29
+ @syntax_version_number = syntax_version_number
30
+ @interchange_sender_identification = interchange_sender_identification
31
+ @sender_identifiction_code_qualifier = sender_identifiction_code_qualifier
32
+ @interchange_sender_internal_identification = interchange_sender_internal_identification
33
+ @interchange_recipient_identification = interchange_recipient_identification
34
+ @recipient_identifiction_code_qualifier = recipient_identifiction_code_qualifier
35
+ @interchange_recipient_internal_identification = interchange_recipient_internal_identification
36
+ @date = date
37
+ @time = time
38
+ @interchange_control_reference = interchange_control_reference
39
+ @recipient_reference = recipient_reference
40
+ @recipient_reference_qualifier = recipient_reference_qualifier
41
+ @application_reference = application_reference
42
+ @processing_priority_code = processing_priority_code
43
+ @acknowledgement_request = acknowledgement_request
44
+ @interchange_agreement_identifier = interchange_agreement_identifier
45
+ @test_indicator = test_indicator
46
+ super(tag: tag || TAG)
47
+ end
48
+
49
+ def to_json_hash
50
+ {
51
+ interchange_sender_identification: @interchange_sender_identification,
52
+ interchange_recipient_identification: @interchange_recipient_identification,
53
+ date: @date,
54
+ time: @time,
55
+ interchange_control_reference: @interchange_control_reference
56
+ }
57
+ end
58
+
59
+ def segment_type
60
+ TYPE
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+
@@ -0,0 +1,46 @@
1
+ module Eancom
2
+ module Edifact
3
+ class UNH < Segment
4
+ TAG = 'UNH'.freeze
5
+ TYPE = :header.freeze
6
+
7
+ def initialize(
8
+ tag: nil,
9
+ message_reference_number:,
10
+ message_type:,
11
+ message_version_number:,
12
+ message_release_number:,
13
+ controlling_agency:,
14
+ association_assigned_code:,
15
+ code_list_directory_version_number: nil
16
+ )
17
+
18
+ @tag = tag
19
+ @message_reference_number = message_reference_number
20
+ @message_type = message_type
21
+ @message_version_number = message_version_number
22
+ @message_release_number = message_release_number
23
+ @controlling_agency = controlling_agency
24
+ @association_assigned_code = association_assigned_code
25
+ @code_list_directory_version_number = code_list_directory_version_number
26
+ super(tag: tag || TAG)
27
+ end
28
+
29
+ def to_json_hash
30
+ {
31
+ message_reference_number: @message_reference_number,
32
+ message_type: @message_type,
33
+ message_version_number: @message_version_number,
34
+ message_release_number: @message_release_number,
35
+ controlling_agency: @controlling_agency,
36
+ association_assigned_code: @association_assigned_code
37
+ }
38
+ end
39
+
40
+ def segment_type
41
+ TYPE
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,29 @@
1
+ module Eancom
2
+ module Edifact
3
+ class UNS < Segment
4
+ TAG = 'UNS'.freeze
5
+ TYPE = :header.freeze
6
+
7
+ def initialize(
8
+ tag: nil,
9
+ section_identification:
10
+ )
11
+ @tag = tag
12
+ @section_identification = section_identification
13
+
14
+ super(tag: tag || TAG)
15
+ end
16
+
17
+ def to_json_hash
18
+ hash = {}
19
+ # hash.merge!(section_identification: find_identifier(:section_identification)) if @section_identification
20
+ hash
21
+ end
22
+
23
+ def segment_type
24
+ TYPE
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ module Eancom
2
+ module Edifact
3
+ class UNT < Segment
4
+ TAG = 'UNT'.freeze
5
+ TYPE = :footer.freeze
6
+
7
+ def initialize(
8
+ tag: nil,
9
+ number_of_segments_in_message:,
10
+ message_reference_number:
11
+ )
12
+ @tag = tag
13
+ @number_of_segments_in_message = number_of_segments_in_message
14
+ @message_reference_number = message_reference_number
15
+ super(tag: tag || TAG)
16
+ end
17
+
18
+ def to_json_hash
19
+ {}
20
+ end
21
+
22
+ def segment_type
23
+ TYPE
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ module Eancom
2
+ module Edifact
3
+ class UNZ < Segment
4
+ TAG = 'UNZ'.freeze
5
+ TYPE = :footer.freeze
6
+
7
+ def initialize(
8
+ tag: nil,
9
+ interchange_control_count:,
10
+ interchange_control_reference:
11
+ )
12
+ @tag = tag
13
+ @interchange_control_count = interchange_control_count
14
+ @interchange_control_reference = interchange_control_reference
15
+ super(tag: tag || TAG)
16
+ end
17
+
18
+ def to_json_hash
19
+ {}
20
+ end
21
+
22
+ def segment_type
23
+ TYPE
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,91 @@
1
+ module Eancom
2
+ module Edifact
3
+ class Structure
4
+
5
+ class KeyNotFoundError < StandardError; end
6
+
7
+ attr_reader :tag
8
+ attr_accessor :composites
9
+
10
+ def initialize(tag:)
11
+ @tag = tag
12
+ @composites = []
13
+ end
14
+
15
+ def <<(composite)
16
+ @composites << composite
17
+ end
18
+
19
+ def validate!(key, value)
20
+ data = find(key)
21
+ data.valid?(key, value)
22
+ end
23
+
24
+ # TODO: Find on Array??
25
+ def find(key)
26
+ @composites.each do |composite|
27
+ data = composite.get(key)
28
+ return data if data
29
+ end
30
+ raise KeyNotFoundError.new("Key #{key} not found.")
31
+ end
32
+
33
+ def build_hash(array)
34
+ hash = {}
35
+ structure_array = structure_array()
36
+ structure_array.each_with_index do |v1, i1|
37
+ v1.each_with_index do |v2, i2|
38
+ if array[i1] && array[i1][i2]
39
+ hash[structure_array[i1][i2]] = array[i1][i2]
40
+ end
41
+ end
42
+ end
43
+ hash
44
+ end
45
+
46
+ def build_array(hash)
47
+ array = []
48
+ structure_array = structure_array()
49
+ structure_array.each_with_index do |v1, i1|
50
+ inner_array = []
51
+ v1.each_with_index do |v2, i2|
52
+ inner_array << hash[v2]
53
+ end
54
+ array << inner_array
55
+ end
56
+ array
57
+ end
58
+
59
+ def to_s
60
+ structure_array
61
+ end
62
+
63
+ def dictionary_lookup(identifier, value)
64
+ if data = find(identifier)
65
+ dictionary = data.dictionary
66
+ dictionary.each do |k, v|
67
+ if v[:identifier] == value
68
+ return k
69
+ end
70
+ end
71
+ value
72
+ else
73
+ value
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def structure_array
80
+ array = []
81
+ @composites.each do |c|
82
+ array << c.to_array
83
+ end
84
+ array
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+ end
91
+
@@ -1,19 +1,52 @@
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/ali'
25
+ require 'eancom/edifact/segments/bgm'
26
+ require 'eancom/edifact/segments/cav'
27
+ require 'eancom/edifact/segments/cci'
28
+ require 'eancom/edifact/segments/cnt'
29
+ require 'eancom/edifact/segments/cps'
30
+ require 'eancom/edifact/segments/cux'
31
+ require 'eancom/edifact/segments/dtm'
32
+ require 'eancom/edifact/segments/ftx'
33
+ require 'eancom/edifact/segments/imd'
34
+ require 'eancom/edifact/segments/lin'
35
+ require 'eancom/edifact/segments/loc'
36
+ require 'eancom/edifact/segments/mea'
37
+ require 'eancom/edifact/segments/moa'
38
+ require 'eancom/edifact/segments/nad'
39
+ require 'eancom/edifact/segments/pac'
40
+ require 'eancom/edifact/segments/pgi'
41
+ require 'eancom/edifact/segments/pia'
42
+ require 'eancom/edifact/segments/pri'
43
+ require 'eancom/edifact/segments/qty'
44
+ require 'eancom/edifact/segments/rff'
45
+ require 'eancom/edifact/segments/tax'
46
+ require 'eancom/edifact/segments/tdt'
47
+
7
48
  module Eancom
8
49
  module Edifact
9
- DELIMITERS = {
10
- component: ':',
11
- data: '+',
12
- decimal: '.',
13
- release: '?',
14
- reserve: ' ',
15
- segment: "'"
16
- }
17
50
  end
18
51
  end
19
52
 
@@ -12,14 +12,14 @@ module Eancom
12
12
 
13
13
  def build
14
14
  @definition = Eancom.find_definition(name: name, type: type)
15
- @definition.run(document: document, config: message)
16
- puts document.to_s
15
+ @definition.run(document: document, config: config)
16
+ @document
17
17
  end
18
18
 
19
19
  private
20
20
 
21
21
  def type
22
- type = config.type.to_sym
22
+ type = header.message_type.downcase.to_sym
23
23
  if Eancom::FILE_TYPES.include?(type)
24
24
  type
25
25
  else
@@ -27,12 +27,13 @@ module Eancom
27
27
  end
28
28
  end
29
29
 
30
- def name
31
- config.name
30
+ def header
31
+ config.header
32
32
  end
33
33
 
34
- def message
35
- config.message
34
+ def name
35
+ header.message_version_number + header.message_release_number
36
36
  end
37
+
37
38
  end
38
39
  end
@@ -0,0 +1,68 @@
1
+ module Eancom
2
+ module Parser
3
+ class Document
4
+ class SegmentTypeNotDefined < StandardError; end
5
+
6
+ attr_reader :file, :document
7
+
8
+ def initialize(file:)
9
+ @file = file
10
+ @document = Eancom::Edifact::Document.new
11
+ end
12
+
13
+ def parse
14
+ content.split(segment_delimiter).each do |segment_string|
15
+ segment = Parser::Segment.new(segment_string)
16
+ segment = segment.parse
17
+ add(segment)
18
+ end
19
+ @document
20
+ end
21
+
22
+ private
23
+
24
+ def add(segment)
25
+ if segment.is_header?
26
+ @document.add_to_header(segment)
27
+ elsif segment.is_body?
28
+ @document.add_to_body(segment)
29
+ elsif segment.is_footer?
30
+ @document.add_to_body(segment)
31
+ else
32
+ raise SegmentTypeNotDefined.new
33
+ end
34
+ end
35
+
36
+ def content
37
+ @content ||= begin
38
+ @file.rewind
39
+ string = convert(@file.read)
40
+ string.delete!("\n")
41
+ string.delete!("\r")
42
+ string.chomp!
43
+ string
44
+ end
45
+ end
46
+
47
+ def composite_delimiter
48
+ DELIMITERS[:data]
49
+ end
50
+
51
+ def segment_delimiter
52
+ DELIMITERS[:segment]
53
+ end
54
+
55
+ def convert(string)
56
+ string = string.encode(
57
+ 'UTF-8',
58
+ 'binary',
59
+ invalid: :replace,
60
+ undef: :replace,
61
+ replace: ''
62
+ )
63
+ string
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,71 @@
1
+ module Eancom
2
+ module Parser
3
+ class Segment
4
+
5
+ attr_accessor :tag, :components, :string
6
+
7
+ def initialize(string)
8
+ @string = string
9
+ @components = []
10
+ end
11
+
12
+ def parse
13
+ parse_component
14
+ klass = find_segment_class
15
+ structure = find_structure
16
+ klass.initialize_by_components(structure, @components)
17
+ end
18
+
19
+ private
20
+
21
+ def parse_component
22
+ if string =~ /^UNA/
23
+ parse_una
24
+ else
25
+ string.split(data_delimiter).each do |data|
26
+ components << parse_data(data)
27
+ end
28
+ end
29
+ end
30
+
31
+ def parse_data(data)
32
+ component = []
33
+ data.split(component_delimiter).each do |c|
34
+ component << c
35
+ end
36
+ component
37
+ end
38
+
39
+ def parse_una
40
+ components << [string[0..2]]
41
+ components << [string[3]]
42
+ components << [string[4]]
43
+ components << [string[5]]
44
+ components << [string[6]]
45
+ components << [string[7]]
46
+ components << [DELIMITERS[:segment]]
47
+ end
48
+
49
+ def tag
50
+ components.first.first
51
+ end
52
+
53
+ def find_segment_class
54
+ Eancom.find_segment(tag: tag)
55
+ end
56
+
57
+ def find_structure
58
+ Eancom.find_structure(tag: tag)
59
+ end
60
+
61
+ def data_delimiter
62
+ DELIMITERS[:data]
63
+ end
64
+
65
+ def component_delimiter
66
+ DELIMITERS[:component]
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,7 @@
1
+ require 'eancom/parser/document'
2
+ require 'eancom/parser/segment'
3
+
4
+ module Eancom
5
+ module Parser
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module Eancom
2
- VERSION = "0.1.0"
2
+ VERSION = "1.1.0"
3
3
  end
data/lib/eancom.rb CHANGED
@@ -1,43 +1,86 @@
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
+ invrp
14
+ orders
15
+ ].freeze
7
16
 
8
- FILE_TYPES = [
9
- :desadv,
10
- :pricat,
11
- :ordrsp,
12
- :salsrp,
13
- :invrp,
14
- :orders
15
- ]
17
+ DELIMITERS = {
18
+ component: ':',
19
+ data: '+',
20
+ release: '?',
21
+ decimal: '.',
22
+ reserve: ' ',
23
+ segment: '\''
24
+ }.freeze
16
25
 
17
- attr_accessor :definitions
26
+ attr_accessor :definitions, :segments
18
27
 
19
28
  def self.definitions
20
- @@configs ||= Hash.new
29
+ @configs ||= {}
30
+ end
31
+
32
+ def self.segments
33
+ @segments ||= {}
34
+ end
35
+
36
+ def self.structures
37
+ @structures ||= {}
21
38
  end
22
39
 
23
40
  def self.register_definition(definition)
24
41
  type = definition.type
25
42
  name = definition.name
26
- definitions[type] ||= Hash.new
43
+ definitions[type] ||= {}
27
44
  definitions[type][name] = definition
28
45
  end
29
46
 
30
47
  def self.find_definition(name:, type:)
31
48
  definitions[type][name]
32
49
  end
50
+
51
+ def self.register_segment(tag:, klass:)
52
+ segments[tag] ||= klass
53
+ end
54
+
55
+ def self.find_segment(tag:)
56
+ segments[tag]
57
+ end
58
+
59
+ def self.register_structure(tag:, structure:)
60
+ structures[tag] ||= structure
61
+ end
62
+
63
+ def self.find_structure(tag:)
64
+ structure = structures[tag]
65
+ if structure.nil?
66
+ raise StructureNotFoundError.new(
67
+ "Structure for tag: #{tag} not found."
68
+ )
69
+ end
70
+ structure
71
+ end
33
72
  end
34
73
 
35
- require "eancom/factory"
36
- require "eancom/definition"
74
+ # TODO: Describe why loaded here...
75
+
76
+ require 'eancom/edifact'
77
+ require 'eancom/factory'
78
+ require 'eancom/parser'
79
+ require 'eancom/definition'
37
80
 
38
- spec = Gem::Specification.find_by_name("eancom")
81
+ spec = Gem::Specification.find_by_name('eancom')
39
82
  gem_root = spec.gem_dir
40
83
 
41
- Dir[File.join(gem_root, "definitions", "**/*.rb")].sort.each do |file|
84
+ Dir[File.join(gem_root, 'definitions', '**/*.rb')].sort.each do |file|
42
85
  require file
43
86
  end