my_data 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.rubocop.yml +32 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/my_data.rb +24 -0
- data/lib/my_data/client.rb +42 -0
- data/lib/my_data/resource.rb +191 -0
- data/lib/my_data/resources.rb +10 -0
- data/lib/my_data/resources/ecls.rb +7 -0
- data/lib/my_data/resources/ecls/expenses_classification_type.rb +7 -0
- data/lib/my_data/resources/ecls/invoice_expenses_classification_type.rb +7 -0
- data/lib/my_data/resources/ecls/invoices_expenses_classification_detail_type.rb +7 -0
- data/lib/my_data/resources/error_type.rb +8 -0
- data/lib/my_data/resources/icls.rb +7 -0
- data/lib/my_data/resources/icls/income_classification_type.rb +7 -0
- data/lib/my_data/resources/icls/invoice_income_classification_type.rb +7 -0
- data/lib/my_data/resources/icls/invoices_income_classification_detail_type.rb +7 -0
- data/lib/my_data/resources/inv.rb +14 -0
- data/lib/my_data/resources/inv/aade_book_invoice_type.rb +7 -0
- data/lib/my_data/resources/inv/address_type.rb +7 -0
- data/lib/my_data/resources/inv/invoice_header_type.rb +7 -0
- data/lib/my_data/resources/inv/invoice_row_type.rb +7 -0
- data/lib/my_data/resources/inv/invoice_summary_type.rb +7 -0
- data/lib/my_data/resources/inv/invoices_doc.rb +17 -0
- data/lib/my_data/resources/inv/party_type.rb +7 -0
- data/lib/my_data/resources/inv/payment_method_detail_type.rb +7 -0
- data/lib/my_data/resources/inv/ship_type.rb +7 -0
- data/lib/my_data/resources/inv/tax_totals_type.rb +7 -0
- data/lib/my_data/resources/response_type.rb +19 -0
- data/lib/my_data/resources/responses_doc.rb +8 -0
- data/lib/my_data/type_caster.rb +58 -0
- data/lib/my_data/version.rb +5 -0
- data/lib/my_data/xml_generator.rb +80 -0
- data/lib/my_data/xml_parser.rb +96 -0
- data/lib/my_data/xsd.rb +7 -0
- data/lib/my_data/xsd/complex_type.rb +24 -0
- data/lib/my_data/xsd/docs/InvoicesDoc-v1.0.2.xsd +1088 -0
- data/lib/my_data/xsd/docs/RequestedProviderDoc-v1.0.2.xsd +44 -0
- data/lib/my_data/xsd/docs/expensesClassification-v1.0.2.xsd +193 -0
- data/lib/my_data/xsd/docs/incomeClassification-v1.0.2.xsd +141 -0
- data/lib/my_data/xsd/docs/requestDoc-v1.0.2.xsd +66 -0
- data/lib/my_data/xsd/docs/requestedInvoicesDoc-v1.0.2.xsd +66 -0
- data/lib/my_data/xsd/docs/response-v1.0.2.xsd +80 -0
- data/lib/my_data/xsd/element.rb +49 -0
- data/lib/my_data/xsd/resource_generator.rb +37 -0
- data/lib/my_data/xsd/structure.rb +80 -0
- data/my_data.gemspec +36 -0
- metadata +153 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyData::Resources
|
4
|
+
autoload :ResponsesDoc, "my_data/resources/responses_doc"
|
5
|
+
autoload :ResponseType, "my_data/resources/response_type"
|
6
|
+
autoload :ErrorType, "my_data/resources/error_type"
|
7
|
+
autoload :Inv, "my_data/resources/inv"
|
8
|
+
autoload :Ecls, "my_data/resources/ecls"
|
9
|
+
autoload :Icls, "my_data/resources/icls"
|
10
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyData::Resources::Ecls
|
4
|
+
autoload :ExpensesClassificationType, "my_data/resources/ecls/expenses_classification_type"
|
5
|
+
autoload :InvoiceExpensesClassificationType, "my_data/resources/ecls/invoice_expenses_classification_type"
|
6
|
+
autoload :InvoicesIncomeClassificationDetailType, "my_data/resources/ecls/invoices_expenses_classification_detail_type"
|
7
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyData::Resources::Icls
|
4
|
+
autoload :IncomeClassificationType, "my_data/resources/icls/income_classification_type"
|
5
|
+
autoload :InvoiceIncomeClassificationType, "my_data/resources/icls/invoice_income_classification_type"
|
6
|
+
autoload :InvoicesIncomeClassificationDetailType, "my_data/resources/icls/invoices_income_classification_detail_type"
|
7
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyData::Resources::Inv
|
4
|
+
autoload :InvoicesDoc, "my_data/resources/inv/invoices_doc"
|
5
|
+
autoload :AadeBookInvoiceType, "my_data/resources/inv/aade_book_invoice_type"
|
6
|
+
autoload :AddressType, "my_data/resources/inv/address_type"
|
7
|
+
autoload :InvoiceHeaderType, "my_data/resources/inv/invoice_header_type"
|
8
|
+
autoload :InvoiceRowType, "my_data/resources/inv/invoice_row_type"
|
9
|
+
autoload :InvoiceSummaryType, "my_data/resources/inv/invoice_summary_type"
|
10
|
+
autoload :PartyType, "my_data/resources/inv/party_type"
|
11
|
+
autoload :PaymentMethodDetailType, "my_data/resources/inv/payment_method_detail_type"
|
12
|
+
autoload :ShipType, "my_data/resources/inv/ship_type"
|
13
|
+
autoload :TaxTotalsType, "my_data/resources/inv/tax_totals_type"
|
14
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class MyData::Resources::Inv::InvoicesDoc
|
4
|
+
include MyData::Resource
|
5
|
+
|
6
|
+
container_tag "InvoicesDoc", {
|
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
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class MyData::Resources::ResponseType
|
4
|
+
include MyData::Resource
|
5
|
+
|
6
|
+
attribute :index, :integer
|
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
|
19
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyData
|
4
|
+
module TypeCaster
|
5
|
+
extend self
|
6
|
+
|
7
|
+
ALLOWED_TYPES = [
|
8
|
+
:string,
|
9
|
+
:integer,
|
10
|
+
:float,
|
11
|
+
:date,
|
12
|
+
:time,
|
13
|
+
:boolean,
|
14
|
+
:resource,
|
15
|
+
:ignore
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
def valid_type?(type)
|
19
|
+
ALLOWED_TYPES.include?(type)
|
20
|
+
end
|
21
|
+
|
22
|
+
def cast(value:, type:, resource: nil)
|
23
|
+
return type_cast_resource(value, resource) if type == :resource
|
24
|
+
|
25
|
+
send("type_cast_#{type}", value)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def type_cast_string(value)
|
31
|
+
value.to_s.strip
|
32
|
+
end
|
33
|
+
|
34
|
+
def type_cast_integer(value)
|
35
|
+
value.present? ? value.to_i : nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def type_cast_float(value)
|
39
|
+
value.present? ? value.to_f : nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def type_cast_date(value)
|
43
|
+
value.present? ? value.to_date : nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def type_cast_time(value)
|
47
|
+
value.present? ? value.to_time : nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def type_cast_boolean(value)
|
51
|
+
value.downcase == "true"
|
52
|
+
end
|
53
|
+
|
54
|
+
def type_cast_resource(value, resource)
|
55
|
+
value.present? ? resource.new(value) : nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyData
|
4
|
+
class XmlGenerator
|
5
|
+
attr_reader :resource, :mappings, :class_name, :container, :parent_namespace
|
6
|
+
|
7
|
+
def initialize(resource, parent_namespace: nil)
|
8
|
+
@resource = resource
|
9
|
+
@mappings = resource.class.mappings
|
10
|
+
@class_name = resource.class.name
|
11
|
+
@container = resource.class.container
|
12
|
+
@parent_namespace = parent_namespace
|
13
|
+
end
|
14
|
+
|
15
|
+
def namespace
|
16
|
+
@namespace ||= resource.class.module_parent_name.split("::").last.downcase
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_xml
|
20
|
+
to_doc.parent.to_xml
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_xml_structure
|
24
|
+
resource.attributes.each_with_object([]) do |(key, value), structure|
|
25
|
+
attr_mappings = mappings[key]
|
26
|
+
next if value.nil?
|
27
|
+
|
28
|
+
if attr_mappings[:collection]
|
29
|
+
val = value.map { |v| attr_mappings[:resource] ? self.class.new(v, parent_namespace: namespace).to_xml_structure : v.to_s }
|
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
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def attr_structure(key, value)
|
48
|
+
prefix = parent_namespace && namespace != parent_namespace ? "#{namespace}:" : ""
|
49
|
+
|
50
|
+
{
|
51
|
+
name: [prefix, key.camelize(:lower)].join,
|
52
|
+
value: value
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_doc
|
57
|
+
Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
58
|
+
xml.send(container[:name], container[:attributes]) do
|
59
|
+
create_nodes(xml, to_xml_structure)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_nodes(xml, structure)
|
65
|
+
if structure.is_a?(Array)
|
66
|
+
structure.each do |es|
|
67
|
+
create_node(xml, es[:name], es[:value])
|
68
|
+
end
|
69
|
+
else
|
70
|
+
create_node(xml, structure[:name], structure[:value])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_node(xml, name, value)
|
75
|
+
xml.send(name) do
|
76
|
+
value.is_a?(String) ? (xml << value) : create_nodes(xml, value)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyData
|
4
|
+
class XmlParser
|
5
|
+
attr_reader :doc, :mappings, :class_name
|
6
|
+
|
7
|
+
def initialize(doc, mappings, class_name)
|
8
|
+
@doc = doc
|
9
|
+
@mappings = mappings
|
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
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def extract_attr_names(element)
|
27
|
+
posible_attrs = mappings.select { |_, opts| element.name == opts[:tag_name] }
|
28
|
+
|
29
|
+
if posible_attrs.present?
|
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
|
36
|
+
|
37
|
+
if attr_names.empty?
|
38
|
+
# raise("Tag attributes not matched: #{class_name}: #{element.name}, element attrs: #{element.attributes}")
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_names.map(&:first)
|
42
|
+
end
|
43
|
+
|
44
|
+
def extract_value(element, attr_name)
|
45
|
+
value = element
|
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?
|
52
|
+
|
53
|
+
value = value.children.select(&:element?).find { |element| element.name == tag[:name].to_s }
|
54
|
+
end
|
55
|
+
|
56
|
+
return value if value.nil?
|
57
|
+
end
|
58
|
+
|
59
|
+
if attr_opts[:collection]
|
60
|
+
value.children.select(&:element?).map { |val| get_value(val, attr_opts) }
|
61
|
+
else
|
62
|
+
get_value(value, attr_opts)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_value(value, attr_opts)
|
67
|
+
if attr_opts[:type] == :model
|
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
|
82
|
+
|
83
|
+
def match_static_tag_attributes?(element, static_tag_attributes)
|
84
|
+
static_tag_attributes.all? do |tag_attribute|
|
85
|
+
element_attr = element.attributes[tag_attribute.name]
|
86
|
+
|
87
|
+
next false unless element_attr
|
88
|
+
|
89
|
+
matched = (element_attr.value == tag_attribute.value) &&
|
90
|
+
(tag_attribute.namespace.nil? || tag_attribute.namespace == element_attr.namespace.prefix)
|
91
|
+
|
92
|
+
matched
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|