my_data 0.1.0 → 0.9.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/lint.yml +37 -0
  3. data/.rubocop.yml +12 -2
  4. data/Gemfile +9 -4
  5. data/Guardfile +7 -0
  6. data/README.md +55 -8
  7. data/lib/my_data.rb +9 -10
  8. data/lib/my_data/client.rb +34 -11
  9. data/lib/my_data/resource.rb +43 -29
  10. data/lib/my_data/resources/continuation_token_type.rb +7 -0
  11. data/lib/my_data/resources/ecls/expenses_classification.rb +7 -0
  12. data/lib/my_data/resources/ecls/expenses_classification_type.rb +1 -1
  13. data/lib/my_data/resources/ecls/invoice_expenses_classification_type.rb +1 -1
  14. data/lib/my_data/resources/ecls/invoices_expenses_classification_detail_type.rb +1 -1
  15. data/lib/my_data/resources/error_type.rb +1 -2
  16. data/lib/my_data/resources/icls/income_classification.rb +7 -0
  17. data/lib/my_data/resources/icls/income_classification_type.rb +1 -1
  18. data/lib/my_data/resources/icls/invoice_income_classification_type.rb +1 -1
  19. data/lib/my_data/resources/icls/invoices_income_classification_detail_type.rb +1 -1
  20. data/lib/my_data/resources/inv/aade_book_invoice_type.rb +1 -1
  21. data/lib/my_data/resources/inv/address_type.rb +1 -1
  22. data/lib/my_data/resources/inv/cancelled_invoice_type.rb +7 -0
  23. data/lib/my_data/resources/inv/continuation_token_type.rb +7 -0
  24. data/lib/my_data/resources/inv/invoice_header_type.rb +1 -1
  25. data/lib/my_data/resources/inv/invoice_row_type.rb +1 -1
  26. data/lib/my_data/resources/inv/invoice_summary_type.rb +1 -1
  27. data/lib/my_data/resources/inv/invoices_doc.rb +1 -11
  28. data/lib/my_data/resources/inv/party_type.rb +1 -1
  29. data/lib/my_data/resources/inv/payment_method_detail_type.rb +1 -1
  30. data/lib/my_data/resources/inv/request_doc.rb +7 -0
  31. data/lib/my_data/resources/inv/requested_invoices_doc.rb +7 -0
  32. data/lib/my_data/resources/inv/ship_type.rb +1 -1
  33. data/lib/my_data/resources/inv/tax_totals_type.rb +1 -1
  34. data/lib/my_data/resources/invoice_provider_type.rb +7 -0
  35. data/lib/my_data/resources/requested_provider_doc.rb +7 -0
  36. data/lib/my_data/resources/response.rb +7 -0
  37. data/lib/my_data/resources/response_type.rb +1 -13
  38. data/lib/my_data/response_parser.rb +42 -0
  39. data/lib/my_data/type_caster.rb +5 -4
  40. data/lib/my_data/version.rb +1 -1
  41. data/lib/my_data/xml_generator.rb +29 -17
  42. data/lib/my_data/xml_parser.rb +37 -76
  43. data/lib/my_data/xsd/complex_type.rb +11 -3
  44. data/lib/my_data/xsd/doc.rb +77 -0
  45. data/lib/my_data/xsd/element.rb +20 -8
  46. data/lib/my_data/xsd/resource_generator.rb +26 -13
  47. data/lib/my_data/xsd/structure.rb +41 -35
  48. data/my_data.gemspec +4 -3
  49. metadata +41 -19
  50. data/lib/my_data/resources.rb +0 -10
  51. data/lib/my_data/resources/ecls.rb +0 -7
  52. data/lib/my_data/resources/icls.rb +0 -7
  53. data/lib/my_data/resources/inv.rb +0 -14
  54. data/lib/my_data/resources/responses_doc.rb +0 -8
  55. data/lib/my_data/xsd.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4eb6195b397b23da4c0756c94382ac9a245ea48ff07c7bcff7ce75d318750f55
4
- data.tar.gz: 2443d4836cecf9d08657e998a39ca73cdcdc58d131463b805be2c84a4429ed53
3
+ metadata.gz: 21734192525f3cdc66a24be64cfc3f147647f8decb6f71a6cd17094f5fc79bcb
4
+ data.tar.gz: ce56b3d0ec170898a593cbfab881e843c1a89a3e3de6a055dce39f0d302f6a67
5
5
  SHA512:
6
- metadata.gz: e3922efa99513f4222db05df50762d502252a99c0159ec11ae0ea35c2ceb5bd89612a54dac86d22e5ccaeca33f573aa58b7f011a00f7da09e65482bdd7e6693d
7
- data.tar.gz: 0135fb723a5e2f759bd5cab73c91c31ef1ef3a47303e111a02593d9589403dc07756e9353e3f3de11becbe84c08ccad4031e06ed61fd9a03ded8c666c2b994aa
6
+ metadata.gz: e18093c80a0108ee8fe815ab50ca359cc019e2346a297b62e45d7c27f83652cab79461c5549bf6e69cad6752a546ae536bf84a10ecf23e320b2bdbb426cb932b
7
+ data.tar.gz: 9d64a6162fbb18bb511159e8c43d2117c795e91e222ce7e5ca10523b6cc7aea72b6bf9412245185537dadd7a512ade270f46672278b982f8377e86a68d5e3ca1
@@ -0,0 +1,37 @@
1
+ name: Lint
2
+
3
+ on: push
4
+
5
+ jobs:
6
+ run-test-lint:
7
+ name: Run tests and linter
8
+ runs-on: ubuntu-latest
9
+
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ ruby: ['2.5', '2.6', '2.7', '3.0']
14
+ gemfile: ['Gemfile']
15
+
16
+ env:
17
+ BUNDLE_GEMFILE: ${{ matrix.gemfile }}
18
+
19
+ steps:
20
+ - name: Check out Git repository
21
+ uses: actions/checkout@v2
22
+
23
+ - name: Set up Ruby
24
+ uses: ruby/setup-ruby@v1
25
+ with:
26
+ ruby-version: ${{ matrix.ruby }}
27
+ bundler-cache: true
28
+
29
+ - name: Run Rubocop
30
+ uses: wearerequired/lint-action@v1
31
+ with:
32
+ rubocop: true
33
+ rubocop_command_prefix: bundle exec
34
+
35
+ - name: Run specs
36
+ run: bundle exec rake spec
37
+
data/.rubocop.yml CHANGED
@@ -1,11 +1,17 @@
1
+ require:
2
+ - rubocop-rake
3
+
4
+ AllCops:
5
+ NewCops: enable
6
+
1
7
  Metrics/ModuleLength:
2
8
  Max: 200
3
9
 
4
10
  Metrics/MethodLength:
5
- Max: 15
11
+ Max: 15
6
12
 
7
13
  Metrics/BlockLength:
8
- ExcludedMethods:
14
+ IgnoredMethods:
9
15
  - class_methods
10
16
 
11
17
  Style/Documentation:
@@ -30,3 +36,7 @@ Style/StringLiteralsInInterpolation:
30
36
 
31
37
  Layout/LineLength:
32
38
  Max: 120
39
+
40
+ Lint/UselessAccessModifier:
41
+ ContextCreatingMethods:
42
+ - class_methods
data/Gemfile CHANGED
@@ -7,9 +7,14 @@ gemspec
7
7
 
8
8
  gem "rake", "~> 13.0"
9
9
 
10
- gem "rspec", "~> 3.0"
11
-
12
- group :development do
10
+ group :development, :test do
11
+ gem "factory_bot"
12
+ gem "guard-rspec", require: false
13
13
  gem "pry"
14
- gem "rubocop", "~> 0.80"
14
+ gem "rspec", "~> 3.0"
15
+ gem "rubocop", "~> 1.0"
16
+ gem "rubocop-rake", "~> 0.5"
17
+ gem "rubocop-rspec", "~> 2.0"
18
+ gem "vcr"
19
+ gem "webmock"
15
20
  end
data/Guardfile ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ guard :rspec, cmd: "rspec" do
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
6
+ watch("spec/spec_helper.rb") { "spec" }
7
+ end
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
- # MyData
1
+ # AADE MyData ruby client
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/my_data`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ A Ruby client for [AADE myDATA](https://www.aade.gr/mydata) API
6
4
 
7
5
  ## Installation
8
6
 
@@ -20,15 +18,64 @@ Or install it yourself as:
20
18
 
21
19
  $ gem install my_data
22
20
 
21
+ ## Resources
22
+ There are all the [resources](https://github.com/mikezaby/my_data/tree/master/lib/my_data/resources)
23
+ that are specified by the given
24
+ [xsd files](https://www.aade.gr/sites/default/files/2020-11/version%20v1.0.2%20XSDs.zip) from AADE.
25
+
26
+ e.x.
27
+ ```irb
28
+ irb> MyData::Resources::Inv::PartyType
29
+ => MyData::Resources::Inv::PartyType vat_number: string, country: string, branch: integer, name: string, address: MyData::Resources::Inv::AddressType
30
+ ```
31
+
23
32
  ## Usage
24
33
 
25
- TODO: Write usage instructions here
34
+ ##### Initialize client
35
+ ```ruby
36
+ client = MyData::Client.new(user_id: "johndoe", subscription_key: "c9b79ff1841fb5cfecc66e1ea5a29b4d")
37
+ ```
26
38
 
27
- ## Development
39
+ ##### Send invoices
40
+ ```ruby
41
+ # send invoices
42
+ invoice_data = {
43
+ issuer: { vat_number: "111111111", country: "GR", branch: 0 },
44
+ invoice_header: { series: "A", aa: "1", issue_date: "2021-02-21", invoice_type: "11.2", currency: "EUR" },
45
+ invoice_details: [{
46
+ line_number: "1",
47
+ net_value: 100.00,
48
+ vat_category: 1,
49
+ vat_amount: 24.00,
50
+ income_classification: [{ classification_type: "E3_561_003", classification_category: "category1_3", amount: 100.00 }]
51
+ }],
52
+ invoice_summary: {
53
+ total_net_value: 100.00,
54
+ total_vat_amount: 24.00,
55
+ total_withheld_amount: 0.0,
56
+ total_fees_amount: 0.0,
57
+ total_stamp_duty_amount: 0.0,
58
+ total_other_taxes_amount: 0.0,
59
+ total_deductions_amount: 0.0,
60
+ total_gross_value: 124.00,
61
+ income_classification: [{ classification_type: "E3_561_003", classification_category: "category1_3", amount: 100.00 }]
62
+ },
63
+ payment_methods: [{ type: 3, amount: 124.00 }]
64
+ }
65
+
66
+ invoices_doc = MyData::Resources::Inv::InvoicesDoc.new(invoice: [invoice_data])
67
+ client.send_invoices(doc: invoices_doc.to_xml)
68
+ ```
28
69
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
70
+ ##### Request transmitted docs
71
+ ```ruby
72
+ client.request_transmitted_docs(mark: 1)
73
+ ```
30
74
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
75
+ ##### Cancel Invoice
76
+ ```ruby
77
+ client.cancel_invoice(mark: 400001831924171)
78
+ ```
32
79
 
33
80
  ## Contributing
34
81
 
data/lib/my_data.rb CHANGED
@@ -4,21 +4,20 @@ require "active_model"
4
4
  require "active_support/all"
5
5
  require "faraday"
6
6
  require "nokogiri"
7
-
8
- require_relative "my_data/version"
7
+ require "zeitwerk"
9
8
 
10
9
  module MyData
10
+ LOADER = Zeitwerk::Loader.for_gem
11
+ LOADER.enable_reloading
12
+ LOADER.setup
13
+
11
14
  class Error < StandardError; end
12
15
 
13
16
  def self.root
14
- File.expand_path '../..', __FILE__
17
+ File.expand_path "..", __dir__
15
18
  end
16
19
 
17
- autoload :Client, "my_data/client"
18
- autoload :Resource, "my_data/resource"
19
- autoload :Resources, "my_data/resources"
20
- autoload :TypeCaster, "my_data/type_caster"
21
- autoload :XmlGenerator, "my_data/xml_generator"
22
- autoload :XmlParser, "my_data/xml_parser"
23
- autoload :Xsd, "my_data/xsd"
20
+ def self.reload!
21
+ MyData::LOADER.reload
22
+ end
24
23
  end
@@ -9,25 +9,48 @@ module MyData
9
9
  @subscription_key = subscription_key
10
10
  end
11
11
 
12
- def connection
13
- @connection ||= Faraday.new(BASE_URL) do |conn|
14
- conn.headers = headers
15
- end
12
+ def send_invoices(doc:)
13
+ response = connection.post("SendInvoices", doc)
14
+
15
+ parse_response(
16
+ response,
17
+ resource: MyData::Resources::Response,
18
+ root: "response_doc"
19
+ )
20
+ end
21
+
22
+ def request_transmitted_docs(mark:)
23
+ response = connection.get("RequestTransmittedDocs", mark: mark)
24
+
25
+ parse_response(
26
+ response,
27
+ resource: MyData::Resources::Inv::RequestDoc,
28
+ root: "requested_doc"
29
+ )
16
30
  end
17
31
 
18
- def send_invoice(invoice_doc)
19
- response = connection.post("SendInvoices", invoice_doc)
32
+ def cancel_invoice(mark:)
33
+ response = connection.post("CancelInvoice") do |req|
34
+ req.params["mark"] = mark
35
+ end
20
36
 
21
- response_parser(response.body)
37
+ parse_response(
38
+ response,
39
+ resource: MyData::Resources::Response,
40
+ root: "response_doc"
41
+ )
22
42
  end
23
43
 
24
44
  private
25
45
 
26
- def response_parser(response)
27
- fixed_xml = response.sub(/^.+/, "").sub("</string>", "").strip
28
- .gsub("&lt;", "<").gsub("&gt;", ">")
46
+ def connection
47
+ @connection ||= Faraday.new(BASE_URL) do |conn|
48
+ conn.headers = headers
49
+ end
50
+ end
29
51
 
30
- Hash.from_xml(fixed_xml)
52
+ def parse_response(response, resource:, root:)
53
+ MyData::ResponseParser.new(response, resource: resource, root: root)
31
54
  end
32
55
 
33
56
  def headers
@@ -29,15 +29,15 @@ module MyData
29
29
  @container[:attributes] = opts
30
30
  end
31
31
 
32
- def xsd_structure
33
- MyData::Xsd::Structure.resource_attributes(name).each do |attrs|
34
- e_name, type, opts = attrs
35
- required = opts.delete :required
32
+ def xsd_doc
33
+ doc_name, doc = MyData::Xsd::Structure.doc(name)
34
+ container_tag(doc_name, doc.attributes)
36
35
 
37
- attribute(e_name, type, opts)
36
+ xsd_resource_attributes(name, :doc)
37
+ end
38
38
 
39
- validates_presence_of e_name if required
40
- end
39
+ def xsd_complex_type
40
+ xsd_resource_attributes(name, :complex_type)
41
41
  end
42
42
 
43
43
  # @param name [String] the name of the attribute
@@ -59,9 +59,8 @@ module MyData
59
59
  @attributes.push(name)
60
60
  attr_mappings(name, type, opts)
61
61
 
62
- attr_reader name
63
-
64
- define_attr_setter name, collection: !!opts[:collection]
62
+ define_attr_getter name, collection: opts[:collection]
63
+ define_attr_setter name, collection: opts[:collection]
65
64
  end
66
65
 
67
66
  def inspect
@@ -76,13 +75,19 @@ module MyData
76
75
  "#{name} #{format_attrs.join(", ")}"
77
76
  end
78
77
 
79
- def from_xml(doc_or_string)
80
- doc = doc_or_string.is_a?(String) ? Nokogiri::XML(doc_or_string).child : doc_or_string
81
- new(parse_xml(doc))
82
- end
83
-
84
78
  private
85
79
 
80
+ def xsd_resource_attributes(name, type)
81
+ MyData::Xsd::Structure.resource_attributes(name, type).each do |attrs|
82
+ e_name, type, opts = attrs
83
+ required = opts.delete :required
84
+
85
+ attribute(e_name, type, opts)
86
+
87
+ validates_presence_of e_name if required
88
+ end
89
+ end
90
+
86
91
  def attr_mappings(name, type, opts)
87
92
  resource =
88
93
  if type == :resource
@@ -98,6 +103,14 @@ module MyData
98
103
  }
99
104
  end
100
105
 
106
+ def define_attr_getter(name, collection: false)
107
+ define_method name do
108
+ value = instance_variable_get("@#{name}")
109
+
110
+ collection && value.nil? ? [] : value
111
+ end
112
+ end
113
+
101
114
  def define_attr_setter(name, collection: false)
102
115
  define_method "#{name}=" do |value|
103
116
  type, resource = self.class.mappings[name].values_at(:type, :resource)
@@ -112,11 +125,6 @@ module MyData
112
125
  instance_variable_set("@#{name}", type_casted_value)
113
126
  end
114
127
  end
115
-
116
- def parse_xml(doc)
117
- parser = MyData::XmlParser.new(doc, mappings, name)
118
- parser.parse_xml
119
- end
120
128
  end
121
129
 
122
130
  def initialize(attrs = {})
@@ -134,6 +142,8 @@ module MyData
134
142
  end
135
143
 
136
144
  def attributes=(attrs)
145
+ attrs = attrs.respond_to?(:attributes) ? attrs.attributes : attrs
146
+
137
147
  attrs.each do |key, value|
138
148
  next unless attribute_names.include?(key.to_s)
139
149
 
@@ -152,15 +162,7 @@ module MyData
152
162
 
153
163
  return true if is_valid
154
164
 
155
- resources.compact.each do |k, resource|
156
- rs = resource.is_a?(Array) ? resource : [resource]
157
-
158
- next if rs.all?(&:valid?)
159
-
160
- rs.each do |r|
161
- errors.add(k, :invalid_resource, message: r.errors.full_messages.join(", "))
162
- end
163
- end
165
+ add_nested_errors
164
166
 
165
167
  false
166
168
  end
@@ -187,5 +189,17 @@ module MyData
187
189
  generator = MyData::XmlGenerator.new(self)
188
190
  generator.to_xml
189
191
  end
192
+
193
+ private
194
+
195
+ def add_nested_errors
196
+ resources.compact.each do |k, resource|
197
+ rs = resource.is_a?(Array) ? resource : [resource]
198
+
199
+ rs.reject(&:valid?).each do |r|
200
+ errors.add(k, :invalid_resource, message: r.errors.full_messages.join(", "))
201
+ end
202
+ end
203
+ end
190
204
  end
191
205
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::ContinuationTokenType
4
+ include MyData::Resource
5
+
6
+ xsd_complex_type
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyData::Resources::Ecls::ExpensesClassification
4
+ include MyData::Resource
5
+
6
+ xsd_doc
7
+ end
@@ -3,5 +3,5 @@
3
3
  class MyData::Resources::Ecls::ExpensesClassificationType
4
4
  include MyData::Resource
5
5
 
6
- xsd_structure
6
+ xsd_complex_type
7
7
  end
@@ -3,5 +3,5 @@
3
3
  class MyData::Resources::Ecls::InvoiceExpensesClassificationType
4
4
  include MyData::Resource
5
5
 
6
- xsd_structure
6
+ xsd_complex_type
7
7
  end
@@ -3,5 +3,5 @@
3
3
  class MyData::Resources::Ecls::InvoicesExpensesClassificationDetailType
4
4
  include MyData::Resource
5
5
 
6
- xsd_structure
6
+ xsd_complex_type
7
7
  end