my_data 0.1.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/lint.yml +37 -0
- data/.rubocop.yml +12 -2
- data/Gemfile +9 -4
- data/Guardfile +7 -0
- data/README.md +55 -8
- data/lib/my_data.rb +9 -10
- data/lib/my_data/client.rb +34 -11
- data/lib/my_data/resource.rb +43 -29
- data/lib/my_data/resources/continuation_token_type.rb +7 -0
- data/lib/my_data/resources/ecls/expenses_classification.rb +7 -0
- data/lib/my_data/resources/ecls/expenses_classification_type.rb +1 -1
- data/lib/my_data/resources/ecls/invoice_expenses_classification_type.rb +1 -1
- data/lib/my_data/resources/ecls/invoices_expenses_classification_detail_type.rb +1 -1
- data/lib/my_data/resources/error_type.rb +1 -2
- data/lib/my_data/resources/icls/income_classification.rb +7 -0
- data/lib/my_data/resources/icls/income_classification_type.rb +1 -1
- data/lib/my_data/resources/icls/invoice_income_classification_type.rb +1 -1
- data/lib/my_data/resources/icls/invoices_income_classification_detail_type.rb +1 -1
- data/lib/my_data/resources/inv/aade_book_invoice_type.rb +1 -1
- data/lib/my_data/resources/inv/address_type.rb +1 -1
- data/lib/my_data/resources/inv/cancelled_invoice_type.rb +7 -0
- data/lib/my_data/resources/inv/continuation_token_type.rb +7 -0
- data/lib/my_data/resources/inv/invoice_header_type.rb +1 -1
- data/lib/my_data/resources/inv/invoice_row_type.rb +1 -1
- data/lib/my_data/resources/inv/invoice_summary_type.rb +1 -1
- data/lib/my_data/resources/inv/invoices_doc.rb +1 -11
- data/lib/my_data/resources/inv/party_type.rb +1 -1
- data/lib/my_data/resources/inv/payment_method_detail_type.rb +1 -1
- data/lib/my_data/resources/inv/request_doc.rb +7 -0
- data/lib/my_data/resources/inv/requested_invoices_doc.rb +7 -0
- data/lib/my_data/resources/inv/ship_type.rb +1 -1
- data/lib/my_data/resources/inv/tax_totals_type.rb +1 -1
- data/lib/my_data/resources/invoice_provider_type.rb +7 -0
- data/lib/my_data/resources/requested_provider_doc.rb +7 -0
- data/lib/my_data/resources/response.rb +7 -0
- data/lib/my_data/resources/response_type.rb +1 -13
- data/lib/my_data/response_parser.rb +42 -0
- data/lib/my_data/type_caster.rb +5 -4
- data/lib/my_data/version.rb +1 -1
- data/lib/my_data/xml_generator.rb +29 -17
- data/lib/my_data/xml_parser.rb +37 -76
- data/lib/my_data/xsd/complex_type.rb +11 -3
- data/lib/my_data/xsd/doc.rb +77 -0
- data/lib/my_data/xsd/element.rb +20 -8
- data/lib/my_data/xsd/resource_generator.rb +26 -13
- data/lib/my_data/xsd/structure.rb +41 -35
- data/my_data.gemspec +4 -3
- metadata +41 -19
- data/lib/my_data/resources.rb +0 -10
- data/lib/my_data/resources/ecls.rb +0 -7
- data/lib/my_data/resources/icls.rb +0 -7
- data/lib/my_data/resources/inv.rb +0 -14
- data/lib/my_data/resources/responses_doc.rb +0 -8
- data/lib/my_data/xsd.rb +0 -7
@@ -3,15 +3,5 @@
|
|
3
3
|
class MyData::Resources::Inv::InvoicesDoc
|
4
4
|
include MyData::Resource
|
5
5
|
|
6
|
-
|
7
|
-
xmlns: "http://www.aade.gr/myDATA/invoice/v1.0",
|
8
|
-
"xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
9
|
-
"xsi:schemaLocation": "http://www.aade.gr/myDATA/invoice/v1.0 schema.xsd",
|
10
|
-
"xmlns:icls": "https://www.aade.gr/myDATA/incomeClassificaton/v1.0"
|
11
|
-
}
|
12
|
-
|
13
|
-
attribute :invoice, :resource,
|
14
|
-
class_name: "Inv::AadeBookInvoiceType", collection: true
|
15
|
-
|
16
|
-
validates_presence_of :invoice
|
6
|
+
xsd_doc
|
17
7
|
end
|
@@ -3,17 +3,5 @@
|
|
3
3
|
class MyData::Resources::ResponseType
|
4
4
|
include MyData::Resource
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
attribute :invoice_uid, :string
|
9
|
-
attribute :invoice_mark, :integer
|
10
|
-
attribute :classification_mark, :integer
|
11
|
-
attribute :cancellation_mark, :integer
|
12
|
-
attribute :authentication_code, :string
|
13
|
-
|
14
|
-
attribute :errors, :resource,
|
15
|
-
class_name: "ErrorType",
|
16
|
-
collection: true, collection_element_name: "error"
|
17
|
-
|
18
|
-
attribute :status_code, :string
|
6
|
+
xsd_complex_type
|
19
7
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class MyData::ResponseParser
|
4
|
+
def initialize(response, resource: nil, root: nil)
|
5
|
+
@original_response = response
|
6
|
+
@resource = resource
|
7
|
+
@root = root
|
8
|
+
end
|
9
|
+
|
10
|
+
def success?
|
11
|
+
original_response.status == 200 &&
|
12
|
+
(!response_type? || response.response.all? { |r| r.status_code == "Success" })
|
13
|
+
end
|
14
|
+
|
15
|
+
def errors
|
16
|
+
@errors ||=
|
17
|
+
if success?
|
18
|
+
[]
|
19
|
+
elsif response_type?
|
20
|
+
response.response.map(&:errors).flatten
|
21
|
+
else
|
22
|
+
[MyData::Resources::ErrorType.new(JSON.parse(original_response.body))]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def response
|
27
|
+
return @response if defined? @response
|
28
|
+
|
29
|
+
@response =
|
30
|
+
if original_response.status == 200
|
31
|
+
MyData::XmlParser.xml_to_resource(xml: original_response.body, resource: resource, root: root)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def response_type?
|
38
|
+
response&.is_a?(MyData::Resources::Response)
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_reader :original_response, :resource, :root
|
42
|
+
end
|
data/lib/my_data/type_caster.rb
CHANGED
@@ -11,8 +11,7 @@ module MyData
|
|
11
11
|
:date,
|
12
12
|
:time,
|
13
13
|
:boolean,
|
14
|
-
:resource
|
15
|
-
:ignore
|
14
|
+
:resource
|
16
15
|
].freeze
|
17
16
|
|
18
17
|
def valid_type?(type)
|
@@ -28,7 +27,7 @@ module MyData
|
|
28
27
|
private
|
29
28
|
|
30
29
|
def type_cast_string(value)
|
31
|
-
value.to_s.strip
|
30
|
+
value ? value.to_s.strip : nil
|
32
31
|
end
|
33
32
|
|
34
33
|
def type_cast_integer(value)
|
@@ -48,7 +47,9 @@ module MyData
|
|
48
47
|
end
|
49
48
|
|
50
49
|
def type_cast_boolean(value)
|
51
|
-
value
|
50
|
+
return value if value.nil?
|
51
|
+
|
52
|
+
value.is_a?(String) ? value.downcase == "true" : value == true
|
52
53
|
end
|
53
54
|
|
54
55
|
def type_cast_resource(value, resource)
|
data/lib/my_data/version.rb
CHANGED
@@ -22,28 +22,40 @@ module MyData
|
|
22
22
|
|
23
23
|
def to_xml_structure
|
24
24
|
resource.attributes.each_with_object([]) do |(key, value), structure|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
if attr_mappings[:collection_element_name]
|
32
|
-
struct = val.map { |v| attr_structure(attr_mappings[:collection_element_name], v) }
|
33
|
-
structure.push(attr_structure(key, struct))
|
34
|
-
else
|
35
|
-
struct = val.map { |v| attr_structure(key, v) }
|
36
|
-
structure.push(*struct)
|
37
|
-
end
|
38
|
-
else
|
39
|
-
val = attr_mappings[:resource] ? self.class.new(value, parent_namespace: namespace).to_xml_structure : value.to_s
|
40
|
-
structure.push(attr_structure(key, val))
|
41
|
-
end
|
25
|
+
next if value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
26
|
+
|
27
|
+
value = value_to_xml_structure(key, value)
|
28
|
+
|
29
|
+
structure.push(*extract_attributes(key, value))
|
42
30
|
end
|
43
31
|
end
|
44
32
|
|
45
33
|
private
|
46
34
|
|
35
|
+
def value_to_xml_structure(key, value)
|
36
|
+
is_resource = mappings[key][:resource].present?
|
37
|
+
|
38
|
+
transform = lambda do |v|
|
39
|
+
is_resource ? self.class.new(v, parent_namespace: namespace).to_xml_structure : v.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
value.is_a?(Array) ? value.map(&transform) : transform.call(value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def extract_attributes(key, value)
|
46
|
+
collection, collection_element_name = mappings[key].values_at(:collection, :collection_element_name)
|
47
|
+
|
48
|
+
if !collection
|
49
|
+
[attr_structure(key, value)]
|
50
|
+
elsif collection_element_name
|
51
|
+
attrs = value.map { |v| attr_structure(collection_element_name, v) }
|
52
|
+
|
53
|
+
[attr_structure(key, attrs)]
|
54
|
+
else
|
55
|
+
value.map { |v| attr_structure(key, v) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
47
59
|
def attr_structure(key, value)
|
48
60
|
prefix = parent_namespace && namespace != parent_namespace ? "#{namespace}:" : ""
|
49
61
|
|
data/lib/my_data/xml_parser.rb
CHANGED
@@ -1,96 +1,57 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module MyData
|
4
|
-
|
5
|
-
attr_reader :doc, :mappings, :class_name
|
3
|
+
module MyData::XmlParser
|
4
|
+
extend self
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
@class_name = class_name
|
11
|
-
end
|
12
|
-
|
13
|
-
def parse_xml
|
14
|
-
doc.children.select(&:element?).each_with_object({}) do |element, parse_attrs|
|
15
|
-
attr_names = extract_attr_names(element)
|
16
|
-
|
17
|
-
attr_names.each do |attr_name|
|
18
|
-
value = extract_value(element, attr_name)
|
19
|
-
parse_attrs[attr_name] = value if value
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
6
|
+
def xml_to_resource(xml:, resource:, root: nil)
|
7
|
+
h = transofrm_xml_to_hash(fix_xml(xml))
|
8
|
+
h = h[root] if root
|
23
9
|
|
24
|
-
|
25
|
-
|
26
|
-
def extract_attr_names(element)
|
27
|
-
posible_attrs = mappings.select { |_, opts| element.name == opts[:tag_name] }
|
10
|
+
resource.new hash_mapping(h, resource)
|
11
|
+
end
|
28
12
|
|
29
|
-
|
30
|
-
attr_names = posible_attrs
|
31
|
-
.select { |_name, opts| match_static_tag_attributes?(element, opts[:static_tag_attrs]) }
|
32
|
-
else
|
33
|
-
attr_names = []
|
34
|
-
# raise "Not implemented: #{class_name}: #{element.name}"
|
35
|
-
end
|
13
|
+
private
|
36
14
|
|
37
|
-
|
38
|
-
|
39
|
-
|
15
|
+
def hash_mapping(hash, resource)
|
16
|
+
flatten(hash, resource).each_with_object({}) do |(key, value), h|
|
17
|
+
mappings = resource.mappings[key]
|
40
18
|
|
41
|
-
|
19
|
+
h[key] = value_mapping(value, mappings)
|
42
20
|
end
|
21
|
+
end
|
43
22
|
|
44
|
-
|
45
|
-
|
46
|
-
attr_opts = mappings[attr_name]
|
47
|
-
|
48
|
-
# TODO: current we dont check that the attribute setting matcing the elements
|
49
|
-
if attr_opts[:nested_tags].present?
|
50
|
-
attr_opts[:nested_tags].each do |tag|
|
51
|
-
return if value.nil?
|
23
|
+
def value_mapping(value, mappings)
|
24
|
+
return value if mappings[:resource].nil?
|
52
25
|
|
53
|
-
|
54
|
-
|
26
|
+
if mappings[:collection]
|
27
|
+
value = value.is_a?(Array) ? value : [value]
|
28
|
+
value.map { |v| hash_mapping(v, mappings[:resource]) }
|
29
|
+
else
|
30
|
+
hash_mapping(value, mappings[:resource])
|
31
|
+
end
|
32
|
+
end
|
55
33
|
|
56
|
-
|
57
|
-
|
34
|
+
def fix_xml(xml)
|
35
|
+
xml.strip.gsub("<", "<").gsub(">", ">")
|
36
|
+
end
|
58
37
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
38
|
+
def transofrm_xml_to_hash(xml)
|
39
|
+
Hash
|
40
|
+
.from_xml(xml)
|
41
|
+
.deep_transform_keys(&:underscore)["string"]
|
42
|
+
end
|
65
43
|
|
66
|
-
|
67
|
-
|
68
|
-
nested_parser = self.class.new(
|
69
|
-
value,
|
70
|
-
attr_opts[:class_name].mappings,
|
71
|
-
attr_opts[:class_name].name
|
72
|
-
)
|
73
|
-
value = nested_parser.parse_xml
|
74
|
-
else
|
75
|
-
value = if attr_opts[:dynamic_tag_attr].present?
|
76
|
-
value.attributes[attr_opts[:dynamic_tag_attr]].value
|
77
|
-
else
|
78
|
-
value.text
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
44
|
+
def flatten(hash, resource)
|
45
|
+
return {} unless hash
|
82
46
|
|
83
|
-
|
84
|
-
|
85
|
-
element_attr = element.attributes[tag_attribute.name]
|
47
|
+
hash.each_with_object({}) do |(k, v), h|
|
48
|
+
next if resource.attributes.none?(k) || !v
|
86
49
|
|
87
|
-
|
50
|
+
mappings = resource.mappings[k]
|
88
51
|
|
89
|
-
|
90
|
-
(tag_attribute.namespace.nil? || tag_attribute.namespace == element_attr.namespace.prefix)
|
52
|
+
next h[k] = v unless mappings[:collection] && mappings[:collection_element_name]
|
91
53
|
|
92
|
-
|
93
|
-
end
|
54
|
+
h[k] = v[mappings[:collection_element_name]]
|
94
55
|
end
|
95
56
|
end
|
96
57
|
end
|