my_data 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +32 -0
  5. data/Gemfile +15 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +39 -0
  8. data/Rakefile +12 -0
  9. data/bin/console +15 -0
  10. data/bin/setup +8 -0
  11. data/lib/my_data.rb +24 -0
  12. data/lib/my_data/client.rb +42 -0
  13. data/lib/my_data/resource.rb +191 -0
  14. data/lib/my_data/resources.rb +10 -0
  15. data/lib/my_data/resources/ecls.rb +7 -0
  16. data/lib/my_data/resources/ecls/expenses_classification_type.rb +7 -0
  17. data/lib/my_data/resources/ecls/invoice_expenses_classification_type.rb +7 -0
  18. data/lib/my_data/resources/ecls/invoices_expenses_classification_detail_type.rb +7 -0
  19. data/lib/my_data/resources/error_type.rb +8 -0
  20. data/lib/my_data/resources/icls.rb +7 -0
  21. data/lib/my_data/resources/icls/income_classification_type.rb +7 -0
  22. data/lib/my_data/resources/icls/invoice_income_classification_type.rb +7 -0
  23. data/lib/my_data/resources/icls/invoices_income_classification_detail_type.rb +7 -0
  24. data/lib/my_data/resources/inv.rb +14 -0
  25. data/lib/my_data/resources/inv/aade_book_invoice_type.rb +7 -0
  26. data/lib/my_data/resources/inv/address_type.rb +7 -0
  27. data/lib/my_data/resources/inv/invoice_header_type.rb +7 -0
  28. data/lib/my_data/resources/inv/invoice_row_type.rb +7 -0
  29. data/lib/my_data/resources/inv/invoice_summary_type.rb +7 -0
  30. data/lib/my_data/resources/inv/invoices_doc.rb +17 -0
  31. data/lib/my_data/resources/inv/party_type.rb +7 -0
  32. data/lib/my_data/resources/inv/payment_method_detail_type.rb +7 -0
  33. data/lib/my_data/resources/inv/ship_type.rb +7 -0
  34. data/lib/my_data/resources/inv/tax_totals_type.rb +7 -0
  35. data/lib/my_data/resources/response_type.rb +19 -0
  36. data/lib/my_data/resources/responses_doc.rb +8 -0
  37. data/lib/my_data/type_caster.rb +58 -0
  38. data/lib/my_data/version.rb +5 -0
  39. data/lib/my_data/xml_generator.rb +80 -0
  40. data/lib/my_data/xml_parser.rb +96 -0
  41. data/lib/my_data/xsd.rb +7 -0
  42. data/lib/my_data/xsd/complex_type.rb +24 -0
  43. data/lib/my_data/xsd/docs/InvoicesDoc-v1.0.2.xsd +1088 -0
  44. data/lib/my_data/xsd/docs/RequestedProviderDoc-v1.0.2.xsd +44 -0
  45. data/lib/my_data/xsd/docs/expensesClassification-v1.0.2.xsd +193 -0
  46. data/lib/my_data/xsd/docs/incomeClassification-v1.0.2.xsd +141 -0
  47. data/lib/my_data/xsd/docs/requestDoc-v1.0.2.xsd +66 -0
  48. data/lib/my_data/xsd/docs/requestedInvoicesDoc-v1.0.2.xsd +66 -0
  49. data/lib/my_data/xsd/docs/response-v1.0.2.xsd +80 -0
  50. data/lib/my_data/xsd/element.rb +49 -0
  51. data/lib/my_data/xsd/resource_generator.rb +37 -0
  52. data/lib/my_data/xsd/structure.rb +80 -0
  53. data/my_data.gemspec +36 -0
  54. 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
+ class MyData::Resources::Ecls::ExpensesClassificationType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Ecls::InvoiceExpensesClassificationType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Ecls::InvoicesExpensesClassificationDetailType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::ErrorType
4
+ include MyData::Resource
5
+
6
+ attribute :message, :string
7
+ attribute :code, :integer
8
+ 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,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Icls::IncomeClassificationType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Icls::InvoiceIncomeClassificationType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Icls::InvoicesIncomeClassificationDetailType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
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,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Inv::AadeBookInvoiceType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Inv::AddressType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Inv::InvoiceHeaderType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Inv::InvoiceRowType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Inv::InvoiceSummaryType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ 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,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Inv::PartyType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Inv::PaymentMethodDetailType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Inv::ShipType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Inv::TaxTotalsType
4
+ include MyData::Resource
5
+
6
+ xsd_structure
7
+ 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,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::ResponsesDoc
4
+ include MyData::Resource
5
+
6
+ attribute :response, :resource, class_name: "ResponseType", collection: true
7
+ end
8
+
@@ -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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyData
4
+ VERSION = "0.1.0"
5
+ 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