my_data 0.1.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 (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