facturx 0.1.0 → 1.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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -2
  3. data/NOTICE.md +2 -0
  4. data/README.md +62 -4
  5. data/lib/facturx/builders/association.rb +8 -0
  6. data/lib/facturx/builders/base.rb +129 -0
  7. data/lib/facturx/builders/schema.rb +112 -0
  8. data/lib/facturx/builders.rb +25 -0
  9. data/lib/facturx/coerce.rb +74 -0
  10. data/lib/facturx/conformance.rb +163 -0
  11. data/lib/facturx/diagnostic.rb +20 -0
  12. data/lib/facturx/document.rb +45 -0
  13. data/lib/facturx/error.rb +3 -0
  14. data/lib/facturx/format.rb +85 -0
  15. data/lib/facturx/generate.rb +21 -0
  16. data/lib/facturx/group.rb +5 -0
  17. data/lib/facturx/model/common.rb +8 -0
  18. data/lib/facturx/model/immutable.rb +75 -0
  19. data/lib/facturx/model/line.rb +14 -0
  20. data/lib/facturx/model/party.rb +10 -0
  21. data/lib/facturx/model/payment.rb +9 -0
  22. data/lib/facturx/model/reference.rb +7 -0
  23. data/lib/facturx/model/trade.rb +9 -0
  24. data/lib/facturx/model.rb +9 -0
  25. data/lib/facturx/pdf/extractor.rb +7 -4
  26. data/lib/facturx/profile_resolver.rb +40 -0
  27. data/lib/facturx/reader/semantic_mapper/delivery_mapping.rb +43 -0
  28. data/lib/facturx/reader/semantic_mapper/document_mapping.rb +109 -0
  29. data/lib/facturx/reader/semantic_mapper/helpers.rb +114 -0
  30. data/lib/facturx/reader/semantic_mapper/line_mapping.rb +120 -0
  31. data/lib/facturx/reader/semantic_mapper/line_references.rb +19 -0
  32. data/lib/facturx/reader/semantic_mapper/party_mapping.rb +90 -0
  33. data/lib/facturx/reader/semantic_mapper/payment_mapping.rb +108 -0
  34. data/lib/facturx/reader/semantic_mapper/trade_mapping.rb +83 -0
  35. data/lib/facturx/reader/semantic_mapper.rb +76 -0
  36. data/lib/facturx/reader/term_reader/coercion.rb +69 -0
  37. data/lib/facturx/reader/term_reader/unmapped.rb +37 -0
  38. data/lib/facturx/reader/term_reader.rb +132 -0
  39. data/lib/facturx/reader.rb +97 -0
  40. data/lib/facturx/reading.rb +23 -0
  41. data/lib/facturx/source_reader.rb +30 -0
  42. data/lib/facturx/term.rb +5 -0
  43. data/lib/facturx/terms/declaration.rb +20 -0
  44. data/lib/facturx/terms/declarations/adjustments.rb +230 -0
  45. data/lib/facturx/terms/declarations/delivery.rb +83 -0
  46. data/lib/facturx/terms/declarations/document.rb +223 -0
  47. data/lib/facturx/terms/declarations/groups.rb +356 -0
  48. data/lib/facturx/terms/declarations/lines.rb +166 -0
  49. data/lib/facturx/terms/declarations/parties.rb +609 -0
  50. data/lib/facturx/terms/declarations/payment.rb +106 -0
  51. data/lib/facturx/terms/declarations/products.rb +103 -0
  52. data/lib/facturx/terms/declarations/references.rb +72 -0
  53. data/lib/facturx/terms/declarations/taxes.rb +92 -0
  54. data/lib/facturx/terms/declarations/totals.rb +107 -0
  55. data/lib/facturx/terms/reference.rb +21 -0
  56. data/lib/facturx/terms.rb +109 -0
  57. data/lib/facturx/version.rb +1 -1
  58. data/lib/facturx/writer/context.rb +53 -0
  59. data/lib/facturx/writer/stage.rb +47 -0
  60. data/lib/facturx/writer/stage_support/contact_details.rb +57 -0
  61. data/lib/facturx/writer/stage_support/emission.rb +78 -0
  62. data/lib/facturx/writer/stage_support/identifiers.rb +129 -0
  63. data/lib/facturx/writer/stage_support/structure.rb +88 -0
  64. data/lib/facturx/writer/stages/document_context.rb +31 -0
  65. data/lib/facturx/writer/stages/exchanged_document.rb +32 -0
  66. data/lib/facturx/writer/stages/trade_agreement/parties.rb +105 -0
  67. data/lib/facturx/writer/stages/trade_agreement/references.rb +92 -0
  68. data/lib/facturx/writer/stages/trade_agreement.rb +45 -0
  69. data/lib/facturx/writer/stages/trade_delivery.rb +77 -0
  70. data/lib/facturx/writer/stages/trade_lines/agreement.rb +92 -0
  71. data/lib/facturx/writer/stages/trade_lines/product.rb +78 -0
  72. data/lib/facturx/writer/stages/trade_lines/quantity.rb +17 -0
  73. data/lib/facturx/writer/stages/trade_lines/settlement.rb +89 -0
  74. data/lib/facturx/writer/stages/trade_lines.rb +67 -0
  75. data/lib/facturx/writer/stages/trade_settlement/parties.rb +33 -0
  76. data/lib/facturx/writer/stages/trade_settlement/payment.rb +97 -0
  77. data/lib/facturx/writer/stages/trade_settlement/summary.rb +88 -0
  78. data/lib/facturx/writer/stages/trade_settlement/taxes.rb +121 -0
  79. data/lib/facturx/writer/stages/trade_settlement.rb +70 -0
  80. data/lib/facturx/writer.rb +68 -0
  81. data/lib/facturx/xml/namespaces.rb +19 -0
  82. data/lib/facturx/xml/profile_detector.rb +2 -4
  83. data/lib/facturx.rb +42 -0
  84. data/rbi/facturx.rbi +1090 -0
  85. metadata +79 -4
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Facturx
4
+ class Reader
5
+ class TermReader
6
+ IGNORED_ATTRIBUTES = %w[currencyID schemeID].freeze
7
+
8
+ def add_unmapped(root)
9
+ add_unmapped_elements(root)
10
+ add_unmapped_attributes(root)
11
+ end
12
+
13
+ private
14
+
15
+ def add_unmapped_elements(root)
16
+ root.xpath('.//*[not(*)]').each do |node|
17
+ next if node.text.empty? || matched?(node)
18
+
19
+ add(:unmapped_element, nil, node.path, 'Element is not mapped to the EN16931 model', value: node.text)
20
+ end
21
+ end
22
+
23
+ def add_unmapped_attributes(root)
24
+ root.xpath('.//@*').each do |attribute|
25
+ next if IGNORED_ATTRIBUTES.include?(attribute.name) || matched?(attribute)
26
+
27
+ add(:unmapped_element, nil, attribute.path, 'Attribute is not mapped to the EN16931 model',
28
+ value: attribute.value)
29
+ end
30
+ end
31
+
32
+ def matched?(node)
33
+ @matched_nodes.key?(node)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,132 @@
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, collapse_if: nil, &)
32
+ group = active_group(id)
33
+ return [].freeze unless group
34
+
35
+ nodes = select_group_nodes(group, context, base_xpath, &)
36
+ cardinality = group.cardinalities.fetch(@profile.id)
37
+ diagnose_cardinality(group, cardinality_nodes(nodes, collapse_if), cardinality)
38
+ nodes.each { |node| mark(node) }
39
+ nodes.freeze
40
+ end
41
+
42
+ def raw_value(xpath, context:, mark_node: true)
43
+ node = context.at_xpath(xpath, NAMESPACES)
44
+ mark(node) if node && mark_node
45
+ node&.text
46
+ end
47
+
48
+ def mark_value(id, context: @document, base_xpath: nil)
49
+ term = active_term(id)
50
+ return unless term
51
+
52
+ context.xpath(relative_xpath(term.xpath, base_xpath), NAMESPACES).each { |node| mark(node) }
53
+ end
54
+
55
+ def mark(node)
56
+ return unless node
57
+
58
+ @matched_nodes[node] = true
59
+ end
60
+
61
+ def add(code, term_id, path, message, details = {})
62
+ @diagnostics << Diagnostic.new(
63
+ code:,
64
+ term_id:,
65
+ path:,
66
+ message:,
67
+ details:
68
+ )
69
+ end
70
+
71
+ private
72
+
73
+ def select_group_nodes(group, context, base_xpath, &filter)
74
+ nodes = context.xpath(relative_xpath(group.xpath, base_xpath), NAMESPACES).to_a
75
+ filter ? nodes.select(&filter) : nodes
76
+ end
77
+
78
+ def cardinality_nodes(nodes, collapse_if)
79
+ collapse_if&.call(nodes) ? [nodes.first] : nodes
80
+ end
81
+
82
+ def active_term(id)
83
+ term = @registry.fetch(id)
84
+ term if term.cardinalities.key?(@profile.id)
85
+ end
86
+
87
+ def active_group(id)
88
+ group = @registry.group(id)
89
+
90
+ group if group.cardinalities.key?(@profile.id)
91
+ rescue KeyError
92
+ raise KeyError, "Unknown Factur-X group: #{id}"
93
+ end
94
+
95
+ def diagnose_cardinality(definition, nodes, cardinality)
96
+ missing(definition) if nodes.empty? && required?(cardinality)
97
+ multiple(definition, nodes.size) if nodes.size > 1 && !repeated?(cardinality)
98
+ end
99
+
100
+ def materialize(term, nodes, cardinality)
101
+ values = nodes.map { |node| coerce(node, term) }
102
+ return values.freeze if repeated?(cardinality)
103
+
104
+ values.first
105
+ end
106
+
107
+ def missing(definition)
108
+ add(:missing_required_term, definition.id, definition.xpath, 'Required value is missing')
109
+ end
110
+
111
+ def multiple(definition, count)
112
+ add(:multiple_values, definition.id, definition.xpath, 'Multiple values found for a scalar field', count:)
113
+ end
114
+
115
+ def relative_xpath(xpath, base_xpath)
116
+ return xpath unless base_xpath
117
+
118
+ suffix = xpath.delete_prefix(base_xpath)
119
+ raise ArgumentError, "#{xpath} is outside #{base_xpath}" if suffix == xpath
120
+
121
+ suffix.empty? ? '.' : ".#{suffix}"
122
+ end
123
+
124
+ def required?(cardinality) = cardinality.start_with?('1')
125
+
126
+ def repeated?(cardinality) = cardinality.end_with?('n')
127
+ end
128
+ end
129
+ end
130
+
131
+ require_relative 'term_reader/unmapped'
132
+ require_relative 'term_reader/coercion'
@@ -0,0 +1,97 @@
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/namespaces'
13
+ require_relative 'xml/profile_detector'
14
+
15
+ module Facturx
16
+ class Reader
17
+ CII_NAMESPACE = Xml::Namespaces::CII
18
+ NAMESPACES = Xml::Namespaces::MAP
19
+ UNKNOWN_PROFILE_POLICIES = %i[fallback raise].freeze
20
+
21
+ COLLABORATORS = %i[profile_resolver registry coercer profiles].freeze
22
+
23
+ def initialize(parser: Xml::Parser.new, extractor: Pdf::Extractor.new, **collaborators)
24
+ unknown = collaborators.keys - COLLABORATORS
25
+ raise ArgumentError, "Unknown collaborators: #{unknown.join(', ')}" unless unknown.empty?
26
+
27
+ @parser = parser
28
+ @source_reader = SourceReader.new(extractor:)
29
+ @profile_resolver = collaborators.fetch(:profile_resolver) { Xml::ProfileDetector.new }
30
+ @registry = collaborators.fetch(:registry, Terms)
31
+ @coercer = collaborators.fetch(:coercer, Coerce)
32
+ @profiles = collaborators.fetch(:profiles, Profiles)
33
+ end
34
+
35
+ def call(source, on_unknown_profile: :fallback)
36
+ validate_unknown_profile_policy!(on_unknown_profile)
37
+ input = @source_reader.call(source)
38
+ parsed = parse(input.xml)
39
+ diagnostics = []
40
+ profile = resolve_profile(parsed, on_unknown_profile, diagnostics)
41
+ document = map(parsed, profile, diagnostics)
42
+
43
+ Reading.new(document:, profile:, diagnostics:, source: input.xml, source_type: input.source_type)
44
+ end
45
+
46
+ private
47
+
48
+ def validate_unknown_profile_policy!(policy)
49
+ return if UNKNOWN_PROFILE_POLICIES.include?(policy)
50
+
51
+ raise ArgumentError, "on_unknown_profile must be one of #{UNKNOWN_PROFILE_POLICIES.inspect}"
52
+ end
53
+
54
+ def cross_industry_invoice(document)
55
+ root = document.root
56
+ return root if root&.name == 'CrossIndustryInvoice' && root.namespace&.href == CII_NAMESPACE
57
+
58
+ raise InvalidXmlError.new('XML is not a CrossIndustryInvoice', reason: :unsupported_document)
59
+ end
60
+
61
+ def parse(xml)
62
+ document = @parser.call(xml:)
63
+ cross_industry_invoice(document)
64
+ document
65
+ end
66
+
67
+ def map(parsed, profile, diagnostics)
68
+ mapper = SemanticMapper.new(
69
+ document: parsed, profile:, registry: @registry, coercer: @coercer, diagnostics:
70
+ )
71
+ document = mapper.call
72
+ mapper.add_unmapped(parsed.root)
73
+ document
74
+ end
75
+
76
+ def resolve_profile(document, policy, diagnostics)
77
+ @profile_resolver.call(document:)
78
+ rescue UnknownProfileError => e
79
+ raise if policy == :raise
80
+
81
+ diagnostics << profile_diagnostic(e)
82
+ @profiles.fetch(:extended)
83
+ end
84
+
85
+ def profile_diagnostic(error)
86
+ guideline_urn = error.details[:guideline_urn]
87
+ Diagnostic.new(
88
+ code: guideline_urn.nil? || guideline_urn.empty? ? :missing_profile : :unknown_profile,
89
+ term_id: 'BT-24', path: Xml::ProfileDetector::GUIDELINE_XPATH,
90
+ message: error.message, details: error.details
91
+ )
92
+ end
93
+ end
94
+ end
95
+
96
+ require_relative 'reader/term_reader'
97
+ 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