facturx 0.1.0 → 0.2.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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -1
  3. data/NOTICE.md +2 -0
  4. data/README.md +27 -1
  5. data/lib/facturx/coerce.rb +74 -0
  6. data/lib/facturx/diagnostic.rb +20 -0
  7. data/lib/facturx/document.rb +45 -0
  8. data/lib/facturx/group.rb +5 -0
  9. data/lib/facturx/model/common.rb +8 -0
  10. data/lib/facturx/model/immutable.rb +75 -0
  11. data/lib/facturx/model/line.rb +14 -0
  12. data/lib/facturx/model/party.rb +10 -0
  13. data/lib/facturx/model/payment.rb +9 -0
  14. data/lib/facturx/model/reference.rb +7 -0
  15. data/lib/facturx/model/trade.rb +9 -0
  16. data/lib/facturx/model.rb +9 -0
  17. data/lib/facturx/pdf/extractor.rb +7 -4
  18. data/lib/facturx/reader/semantic_mapper/delivery_mapping.rb +43 -0
  19. data/lib/facturx/reader/semantic_mapper/document_mapping.rb +109 -0
  20. data/lib/facturx/reader/semantic_mapper/helpers.rb +114 -0
  21. data/lib/facturx/reader/semantic_mapper/line_mapping.rb +120 -0
  22. data/lib/facturx/reader/semantic_mapper/party_mapping.rb +90 -0
  23. data/lib/facturx/reader/semantic_mapper/payment_mapping.rb +71 -0
  24. data/lib/facturx/reader/semantic_mapper/trade_mapping.rb +83 -0
  25. data/lib/facturx/reader/semantic_mapper.rb +67 -0
  26. data/lib/facturx/reader/term_reader/coercion.rb +69 -0
  27. data/lib/facturx/reader/term_reader/unmapped.rb +37 -0
  28. data/lib/facturx/reader/term_reader.rb +124 -0
  29. data/lib/facturx/reader.rb +101 -0
  30. data/lib/facturx/reading.rb +23 -0
  31. data/lib/facturx/source_reader.rb +30 -0
  32. data/lib/facturx/term.rb +5 -0
  33. data/lib/facturx/terms/declaration.rb +20 -0
  34. data/lib/facturx/terms/declarations/adjustments.rb +230 -0
  35. data/lib/facturx/terms/declarations/delivery.rb +83 -0
  36. data/lib/facturx/terms/declarations/document.rb +223 -0
  37. data/lib/facturx/terms/declarations/groups.rb +356 -0
  38. data/lib/facturx/terms/declarations/lines.rb +166 -0
  39. data/lib/facturx/terms/declarations/parties.rb +609 -0
  40. data/lib/facturx/terms/declarations/payment.rb +106 -0
  41. data/lib/facturx/terms/declarations/products.rb +103 -0
  42. data/lib/facturx/terms/declarations/references.rb +72 -0
  43. data/lib/facturx/terms/declarations/taxes.rb +92 -0
  44. data/lib/facturx/terms/declarations/totals.rb +107 -0
  45. data/lib/facturx/terms/reference.rb +21 -0
  46. data/lib/facturx/terms.rb +109 -0
  47. data/lib/facturx/version.rb +1 -1
  48. data/lib/facturx.rb +14 -0
  49. metadata +45 -4
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../coerce'
4
+ require_relative '../diagnostic'
5
+
6
+ module Facturx
7
+ class Reader
8
+ class TermReader
9
+ attr_reader :diagnostics
10
+
11
+ def initialize(document:, profile:, registry:, coercer:, diagnostics:)
12
+ @document = document
13
+ @profile = profile
14
+ @registry = registry
15
+ @coercer = coercer
16
+ @diagnostics = diagnostics
17
+ @matched_nodes = {}.compare_by_identity
18
+ end
19
+
20
+ def value(id, context: @document, base_xpath: nil, nodes: nil)
21
+ term = active_term(id)
22
+ return unless term
23
+
24
+ selected = nodes || context.xpath(relative_xpath(term.xpath, base_xpath), NAMESPACES)
25
+ selected.each { |node| mark(node) }
26
+ cardinality = term.cardinalities.fetch(@profile.id)
27
+ diagnose_cardinality(term, selected, cardinality)
28
+ materialize(term, selected, cardinality)
29
+ end
30
+
31
+ def group_nodes(id, context: @document, base_xpath: nil, &)
32
+ group = active_group(id)
33
+ return [].freeze unless group
34
+
35
+ nodes = context.xpath(relative_xpath(group.xpath, base_xpath), NAMESPACES).to_a
36
+ nodes.select!(&) if block_given?
37
+ cardinality = group.cardinalities.fetch(@profile.id)
38
+ diagnose_cardinality(group, nodes, cardinality)
39
+ nodes.each { |node| mark(node) }
40
+ nodes.freeze
41
+ end
42
+
43
+ def raw_value(xpath, context:, mark_node: true)
44
+ node = context.at_xpath(xpath, NAMESPACES)
45
+ mark(node) if node && mark_node
46
+ node&.text
47
+ end
48
+
49
+ def mark_value(id, context: @document, base_xpath: nil)
50
+ term = active_term(id)
51
+ return unless term
52
+
53
+ context.xpath(relative_xpath(term.xpath, base_xpath), NAMESPACES).each { |node| mark(node) }
54
+ end
55
+
56
+ def mark(node)
57
+ return unless node
58
+
59
+ @matched_nodes[node] = true
60
+ end
61
+
62
+ def add(code, term_id, path, message, details = {})
63
+ @diagnostics << Diagnostic.new(
64
+ code:,
65
+ term_id:,
66
+ path:,
67
+ message:,
68
+ details:
69
+ )
70
+ end
71
+
72
+ private
73
+
74
+ def active_term(id)
75
+ term = @registry.fetch(id)
76
+ term if term.cardinalities.key?(@profile.id)
77
+ end
78
+
79
+ def active_group(id)
80
+ group = @registry.group(id)
81
+
82
+ group if group.cardinalities.key?(@profile.id)
83
+ rescue KeyError
84
+ raise KeyError, "Unknown Factur-X group: #{id}"
85
+ end
86
+
87
+ def diagnose_cardinality(definition, nodes, cardinality)
88
+ missing(definition) if nodes.empty? && required?(cardinality)
89
+ multiple(definition, nodes.size) if nodes.size > 1 && !repeated?(cardinality)
90
+ end
91
+
92
+ def materialize(term, nodes, cardinality)
93
+ values = nodes.map { |node| coerce(node, term) }
94
+ return values.freeze if repeated?(cardinality)
95
+
96
+ values.first
97
+ end
98
+
99
+ def missing(definition)
100
+ add(:missing_required_term, definition.id, definition.xpath, 'Required value is missing')
101
+ end
102
+
103
+ def multiple(definition, count)
104
+ add(:multiple_values, definition.id, definition.xpath, 'Multiple values found for a scalar field', count:)
105
+ end
106
+
107
+ def relative_xpath(xpath, base_xpath)
108
+ return xpath unless base_xpath
109
+
110
+ suffix = xpath.delete_prefix(base_xpath)
111
+ raise ArgumentError, "#{xpath} is outside #{base_xpath}" if suffix == xpath
112
+
113
+ suffix.empty? ? '.' : ".#{suffix}"
114
+ end
115
+
116
+ def required?(cardinality) = cardinality.start_with?('1')
117
+
118
+ def repeated?(cardinality) = cardinality.end_with?('n')
119
+ end
120
+ end
121
+ end
122
+
123
+ require_relative 'term_reader/unmapped'
124
+ require_relative 'term_reader/coercion'
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'diagnostic'
4
+ require_relative 'document'
5
+ require_relative 'coerce'
6
+ require_relative 'error'
7
+ require_relative 'profiles'
8
+ require_relative 'reading'
9
+ require_relative 'source_reader'
10
+ require_relative 'terms'
11
+ require_relative 'xml/parser'
12
+ require_relative 'xml/profile_detector'
13
+
14
+ module Facturx
15
+ class Reader
16
+ CII_NAMESPACE = 'urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'
17
+ NAMESPACES = {
18
+ 'qdt' => 'urn:un:unece:uncefact:data:standard:QualifiedDataType:100',
19
+ 'ram' => 'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100',
20
+ 'rsm' => CII_NAMESPACE,
21
+ 'udt' => 'urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100'
22
+ }.freeze
23
+ UNKNOWN_PROFILE_POLICIES = %i[fallback raise].freeze
24
+
25
+ COLLABORATORS = %i[profile_resolver registry coercer profiles].freeze
26
+
27
+ def initialize(parser: Xml::Parser.new, extractor: Pdf::Extractor.new, **collaborators)
28
+ unknown = collaborators.keys - COLLABORATORS
29
+ raise ArgumentError, "Unknown collaborators: #{unknown.join(', ')}" unless unknown.empty?
30
+
31
+ @parser = parser
32
+ @source_reader = SourceReader.new(extractor:)
33
+ @profile_resolver = collaborators.fetch(:profile_resolver) { Xml::ProfileDetector.new }
34
+ @registry = collaborators.fetch(:registry, Terms)
35
+ @coercer = collaborators.fetch(:coercer, Coerce)
36
+ @profiles = collaborators.fetch(:profiles, Profiles)
37
+ end
38
+
39
+ def call(source, on_unknown_profile: :fallback)
40
+ validate_unknown_profile_policy!(on_unknown_profile)
41
+ input = @source_reader.call(source)
42
+ parsed = parse(input.xml)
43
+ diagnostics = []
44
+ profile = resolve_profile(parsed, on_unknown_profile, diagnostics)
45
+ document = map(parsed, profile, diagnostics)
46
+
47
+ Reading.new(document:, profile:, diagnostics:, source: input.xml, source_type: input.source_type)
48
+ end
49
+
50
+ private
51
+
52
+ def validate_unknown_profile_policy!(policy)
53
+ return if UNKNOWN_PROFILE_POLICIES.include?(policy)
54
+
55
+ raise ArgumentError, "on_unknown_profile must be one of #{UNKNOWN_PROFILE_POLICIES.inspect}"
56
+ end
57
+
58
+ def cross_industry_invoice(document)
59
+ root = document.root
60
+ return root if root&.name == 'CrossIndustryInvoice' && root.namespace&.href == CII_NAMESPACE
61
+
62
+ raise InvalidXmlError.new('XML is not a CrossIndustryInvoice', reason: :unsupported_document)
63
+ end
64
+
65
+ def parse(xml)
66
+ document = @parser.call(xml:)
67
+ cross_industry_invoice(document)
68
+ document
69
+ end
70
+
71
+ def map(parsed, profile, diagnostics)
72
+ mapper = SemanticMapper.new(
73
+ document: parsed, profile:, registry: @registry, coercer: @coercer, diagnostics:
74
+ )
75
+ document = mapper.call
76
+ mapper.add_unmapped(parsed.root)
77
+ document
78
+ end
79
+
80
+ def resolve_profile(document, policy, diagnostics)
81
+ @profile_resolver.call(document:)
82
+ rescue UnknownProfileError => e
83
+ raise if policy == :raise
84
+
85
+ diagnostics << profile_diagnostic(e)
86
+ @profiles.fetch(:extended)
87
+ end
88
+
89
+ def profile_diagnostic(error)
90
+ guideline_urn = error.details[:guideline_urn]
91
+ Diagnostic.new(
92
+ code: guideline_urn.nil? || guideline_urn.empty? ? :missing_profile : :unknown_profile,
93
+ term_id: 'BT-24', path: Xml::ProfileDetector::GUIDELINE_XPATH,
94
+ message: error.message, details: error.details
95
+ )
96
+ end
97
+ end
98
+ end
99
+
100
+ require_relative 'reader/term_reader'
101
+ require_relative 'reader/semantic_mapper'
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'model/immutable'
4
+
5
+ module Facturx
6
+ READING_SOURCE_TYPES = %i[xml pdf].freeze
7
+ private_constant :READING_SOURCE_TYPES
8
+
9
+ Reading = Data.define(:document, :profile, :diagnostics, :source, :source_type) do
10
+ include Model::ValidatedWith
11
+
12
+ def initialize(document:, profile:, source:, diagnostics: [], source_type: :xml)
13
+ raise TypeError, 'source must be a byte String' unless source.is_a?(String)
14
+ raise TypeError, 'diagnostics must be an Array' unless diagnostics.is_a?(Array)
15
+ unless READING_SOURCE_TYPES.include?(source_type)
16
+ raise ArgumentError, "Unknown source type: #{source_type.inspect}"
17
+ end
18
+
19
+ xml = source.dup.force_encoding(Encoding::BINARY).freeze
20
+ super(document:, profile:, diagnostics: Model.copy_and_freeze(diagnostics), source: xml, source_type:)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'error'
4
+ require_relative 'pdf/extractor'
5
+
6
+ module Facturx
7
+ class SourceReader
8
+ Result = Data.define(:xml, :source_type)
9
+
10
+ def initialize(extractor: Pdf::Extractor.new)
11
+ @extractor = extractor
12
+ end
13
+
14
+ def call(source)
15
+ unless source.is_a?(String)
16
+ raise InvalidXmlError.new('Source must be provided as a byte String', input_class: source.class.name)
17
+ end
18
+
19
+ return Result.new(xml: source, source_type: :xml) unless pdf?(source)
20
+
21
+ Result.new(xml: @extractor.call(source).xml, source_type: :pdf)
22
+ end
23
+
24
+ private
25
+
26
+ def pdf?(bytes)
27
+ bytes.byteslice(0, 1024).b.include?('%PDF-'.b)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facturx
4
+ Term = Data.define(:id, :model, :attribute, :group_id, :xpath, :type, :scale, :cardinalities)
5
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../term'
4
+ require_relative '../group'
5
+
6
+ module Facturx
7
+ module TermDeclarations
8
+ module Declaration
9
+ module_function
10
+
11
+ def term(*attributes, **cardinalities)
12
+ Term.new(*attributes, cardinalities.freeze).freeze
13
+ end
14
+
15
+ def group(*attributes, **cardinalities)
16
+ Group.new(*attributes, cardinalities.freeze).freeze
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,230 @@
1
+ # frozen_string_literal: true
2
+
3
+ Facturx::TermDeclarations::ADJUSTMENTS = [
4
+ Facturx::TermDeclarations::Declaration.term(
5
+ 'BT-138', :allowance_charge, :percentage, 'BG-27',
6
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem' \
7
+ '/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:CalculationPercent',
8
+ :decimal, nil,
9
+ en16931: '0..1',
10
+ extended: '0..1'
11
+ ),
12
+ Facturx::TermDeclarations::Declaration.term(
13
+ 'BT-137', :allowance_charge, :base_amount, 'BG-27',
14
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem' \
15
+ '/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:BasisAmount',
16
+ :decimal, 2,
17
+ en16931: '0..1',
18
+ extended: '0..1'
19
+ ),
20
+ Facturx::TermDeclarations::Declaration.term(
21
+ 'BT-136', :allowance_charge, :amount, 'BG-27',
22
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem' \
23
+ '/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:ActualAmount',
24
+ :decimal, 2,
25
+ basic: '1..1',
26
+ en16931: '1..1',
27
+ extended: '1..1'
28
+ ),
29
+ Facturx::TermDeclarations::Declaration.term(
30
+ 'BT-140', :allowance_charge, :reason_code, 'BG-27',
31
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem' \
32
+ '/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:ReasonCode',
33
+ :string, nil,
34
+ basic: '0..1',
35
+ en16931: '0..1',
36
+ extended: '0..1'
37
+ ),
38
+ Facturx::TermDeclarations::Declaration.term(
39
+ 'BT-139', :allowance_charge, :reason, 'BG-27',
40
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem' \
41
+ '/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:Reason',
42
+ :string, nil,
43
+ basic: '0..1',
44
+ en16931: '0..1',
45
+ extended: '0..1'
46
+ ),
47
+ Facturx::TermDeclarations::Declaration.term(
48
+ 'BT-143', :allowance_charge, :percentage, 'BG-28',
49
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem' \
50
+ '/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:CalculationPercent',
51
+ :decimal, nil,
52
+ en16931: '0..1',
53
+ extended: '0..1'
54
+ ),
55
+ Facturx::TermDeclarations::Declaration.term(
56
+ 'BT-142', :allowance_charge, :base_amount, 'BG-28',
57
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem' \
58
+ '/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:BasisAmount',
59
+ :decimal, 2,
60
+ en16931: '0..1',
61
+ extended: '0..1'
62
+ ),
63
+ Facturx::TermDeclarations::Declaration.term(
64
+ 'BT-141', :allowance_charge, :amount, 'BG-28',
65
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem' \
66
+ '/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:ActualAmount',
67
+ :decimal, 2,
68
+ basic: '1..1',
69
+ en16931: '1..1',
70
+ extended: '1..1'
71
+ ),
72
+ Facturx::TermDeclarations::Declaration.term(
73
+ 'BT-145', :allowance_charge, :reason_code, 'BG-28',
74
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem' \
75
+ '/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:ReasonCode',
76
+ :string, nil,
77
+ basic: '0..1',
78
+ en16931: '0..1',
79
+ extended: '0..1'
80
+ ),
81
+ Facturx::TermDeclarations::Declaration.term(
82
+ 'BT-144', :allowance_charge, :reason, 'BG-28',
83
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem' \
84
+ '/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeAllowanceCharge/ram:Reason',
85
+ :string, nil,
86
+ basic: '0..1',
87
+ en16931: '0..1',
88
+ extended: '0..1'
89
+ ),
90
+ Facturx::TermDeclarations::Declaration.term(
91
+ 'BT-94', :allowance_charge, :percentage, 'BG-20',
92
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
93
+ '/ram:SpecifiedTradeAllowanceCharge/ram:CalculationPercent',
94
+ :decimal, nil,
95
+ basic_wl: '0..1',
96
+ basic: '0..1',
97
+ en16931: '0..1',
98
+ extended: '0..1'
99
+ ),
100
+ Facturx::TermDeclarations::Declaration.term(
101
+ 'BT-93', :allowance_charge, :base_amount, 'BG-20',
102
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
103
+ '/ram:SpecifiedTradeAllowanceCharge/ram:BasisAmount',
104
+ :decimal, 2,
105
+ basic_wl: '0..1',
106
+ basic: '0..1',
107
+ en16931: '0..1',
108
+ extended: '0..1'
109
+ ),
110
+ Facturx::TermDeclarations::Declaration.term(
111
+ 'BT-92', :allowance_charge, :amount, 'BG-20',
112
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
113
+ '/ram:SpecifiedTradeAllowanceCharge/ram:ActualAmount',
114
+ :decimal, 2,
115
+ basic_wl: '1..1',
116
+ basic: '1..1',
117
+ en16931: '1..1',
118
+ extended: '1..1'
119
+ ),
120
+ Facturx::TermDeclarations::Declaration.term(
121
+ 'BT-98', :allowance_charge, :reason_code, 'BG-20',
122
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
123
+ '/ram:SpecifiedTradeAllowanceCharge/ram:ReasonCode',
124
+ :string, nil,
125
+ basic_wl: '0..1',
126
+ basic: '0..1',
127
+ en16931: '0..1',
128
+ extended: '0..1'
129
+ ),
130
+ Facturx::TermDeclarations::Declaration.term(
131
+ 'BT-97', :allowance_charge, :reason, 'BG-20',
132
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
133
+ '/ram:SpecifiedTradeAllowanceCharge/ram:Reason',
134
+ :string, nil,
135
+ basic_wl: '0..1',
136
+ basic: '0..1',
137
+ en16931: '0..1',
138
+ extended: '0..1'
139
+ ),
140
+ Facturx::TermDeclarations::Declaration.term(
141
+ 'BT-95', :allowance_charge, :tax, 'BG-20',
142
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
143
+ '/ram:SpecifiedTradeAllowanceCharge/ram:CategoryTradeTax/ram:CategoryCode',
144
+ :string, nil,
145
+ basic_wl: '1..1',
146
+ basic: '1..1',
147
+ en16931: '1..1',
148
+ extended: '1..1'
149
+ ),
150
+ Facturx::TermDeclarations::Declaration.term(
151
+ 'BT-96', :allowance_charge, :tax, 'BG-20',
152
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
153
+ '/ram:SpecifiedTradeAllowanceCharge/ram:CategoryTradeTax/ram:RateApplicablePercent',
154
+ :decimal, nil,
155
+ basic_wl: '0..1',
156
+ basic: '0..1',
157
+ en16931: '0..1',
158
+ extended: '0..1'
159
+ ),
160
+ Facturx::TermDeclarations::Declaration.term(
161
+ 'BT-101', :allowance_charge, :percentage, 'BG-21',
162
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
163
+ '/ram:SpecifiedTradeAllowanceCharge/ram:CalculationPercent',
164
+ :decimal, nil,
165
+ basic_wl: '0..1',
166
+ basic: '0..1',
167
+ en16931: '0..1',
168
+ extended: '0..1'
169
+ ),
170
+ Facturx::TermDeclarations::Declaration.term(
171
+ 'BT-100', :allowance_charge, :base_amount, 'BG-21',
172
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
173
+ '/ram:SpecifiedTradeAllowanceCharge/ram:BasisAmount',
174
+ :decimal, 2,
175
+ basic_wl: '0..1',
176
+ basic: '0..1',
177
+ en16931: '0..1',
178
+ extended: '0..1'
179
+ ),
180
+ Facturx::TermDeclarations::Declaration.term(
181
+ 'BT-99', :allowance_charge, :amount, 'BG-21',
182
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
183
+ '/ram:SpecifiedTradeAllowanceCharge/ram:ActualAmount',
184
+ :decimal, 2,
185
+ basic_wl: '1..1',
186
+ basic: '1..1',
187
+ en16931: '1..1',
188
+ extended: '1..1'
189
+ ),
190
+ Facturx::TermDeclarations::Declaration.term(
191
+ 'BT-105', :allowance_charge, :reason_code, 'BG-21',
192
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
193
+ '/ram:SpecifiedTradeAllowanceCharge/ram:ReasonCode',
194
+ :string, nil,
195
+ basic_wl: '0..1',
196
+ basic: '0..1',
197
+ en16931: '0..1',
198
+ extended: '0..1'
199
+ ),
200
+ Facturx::TermDeclarations::Declaration.term(
201
+ 'BT-104', :allowance_charge, :reason, 'BG-21',
202
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
203
+ '/ram:SpecifiedTradeAllowanceCharge/ram:Reason',
204
+ :string, nil,
205
+ basic_wl: '0..1',
206
+ basic: '0..1',
207
+ en16931: '0..1',
208
+ extended: '0..1'
209
+ ),
210
+ Facturx::TermDeclarations::Declaration.term(
211
+ 'BT-102', :allowance_charge, :tax, 'BG-21',
212
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
213
+ '/ram:SpecifiedTradeAllowanceCharge/ram:CategoryTradeTax/ram:CategoryCode',
214
+ :string, nil,
215
+ basic_wl: '1..1',
216
+ basic: '1..1',
217
+ en16931: '1..1',
218
+ extended: '1..1'
219
+ ),
220
+ Facturx::TermDeclarations::Declaration.term(
221
+ 'BT-103', :allowance_charge, :tax, 'BG-21',
222
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
223
+ '/ram:SpecifiedTradeAllowanceCharge/ram:CategoryTradeTax/ram:RateApplicablePercent',
224
+ :decimal, nil,
225
+ basic_wl: '0..1',
226
+ basic: '0..1',
227
+ en16931: '0..1',
228
+ extended: '0..1'
229
+ )
230
+ ].freeze
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ Facturx::TermDeclarations::DELIVERY = [
4
+ Facturx::TermDeclarations::Declaration.term(
5
+ 'BT-134', :period, :start_date, 'BG-26',
6
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem' \
7
+ '/ram:SpecifiedLineTradeSettlement/ram:BillingSpecifiedPeriod/ram:StartDateTime' \
8
+ '/udt:DateTimeString',
9
+ :date_102, nil,
10
+ basic: '0..1',
11
+ en16931: '0..1',
12
+ extended: '0..1'
13
+ ),
14
+ Facturx::TermDeclarations::Declaration.term(
15
+ 'BT-135', :period, :end_date, 'BG-26',
16
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem' \
17
+ '/ram:SpecifiedLineTradeSettlement/ram:BillingSpecifiedPeriod/ram:EndDateTime/udt:DateTimeString',
18
+ :date_102, nil,
19
+ basic: '0..1',
20
+ en16931: '0..1',
21
+ extended: '0..1'
22
+ ),
23
+ Facturx::TermDeclarations::Declaration.term(
24
+ 'BT-71', :delivery, :location_identifier, 'BG-13',
25
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery' \
26
+ '/ram:ShipToTradeParty/ram:ID',
27
+ :string, nil,
28
+ basic_wl: '0..1',
29
+ basic: '0..1',
30
+ en16931: '0..1',
31
+ extended: '0..1'
32
+ ),
33
+ Facturx::TermDeclarations::Declaration.term(
34
+ 'BT-71-1', :delivery, :location_identifier, 'BG-13',
35
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery' \
36
+ '/ram:ShipToTradeParty/ram:GlobalID/@schemeID',
37
+ :string, nil,
38
+ basic_wl: '0..1',
39
+ basic: '0..1',
40
+ en16931: '0..1',
41
+ extended: '0..1'
42
+ ),
43
+ Facturx::TermDeclarations::Declaration.term(
44
+ 'BT-70', :delivery, :party, 'BG-13',
45
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery' \
46
+ '/ram:ShipToTradeParty/ram:Name',
47
+ :string, nil,
48
+ basic_wl: '0..1',
49
+ basic: '0..1',
50
+ en16931: '0..1',
51
+ extended: '0..1'
52
+ ),
53
+ Facturx::TermDeclarations::Declaration.term(
54
+ 'BT-72', :delivery, :date, 'BG-13-00',
55
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery' \
56
+ '/ram:ActualDeliverySupplyChainEvent/ram:OccurrenceDateTime/udt:DateTimeString',
57
+ :date_102, nil,
58
+ basic_wl: '0..1',
59
+ basic: '0..1',
60
+ en16931: '0..1',
61
+ extended: '0..1'
62
+ ),
63
+ Facturx::TermDeclarations::Declaration.term(
64
+ 'BT-73', :period, :start_date, 'BG-14',
65
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
66
+ '/ram:BillingSpecifiedPeriod/ram:StartDateTime/udt:DateTimeString',
67
+ :date_102, nil,
68
+ basic_wl: '0..1',
69
+ basic: '0..1',
70
+ en16931: '0..1',
71
+ extended: '0..1'
72
+ ),
73
+ Facturx::TermDeclarations::Declaration.term(
74
+ 'BT-74', :period, :end_date, 'BG-14',
75
+ '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement' \
76
+ '/ram:BillingSpecifiedPeriod/ram:EndDateTime/udt:DateTimeString',
77
+ :date_102, nil,
78
+ basic_wl: '0..1',
79
+ basic: '0..1',
80
+ en16931: '0..1',
81
+ extended: '0..1'
82
+ )
83
+ ].freeze