easybill-rest-client 2.0.2

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 (87) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +6 -0
  3. data/Gemfile.lock +152 -0
  4. data/README.md +8 -0
  5. data/Rakefile +4 -0
  6. data/config.json +5 -0
  7. data/easybill-rest-client.gemspec +29 -0
  8. data/lib/easybill-rest-client.rb +15 -0
  9. data/lib/easybill_rest_client/.document_address.rb.swp +0 -0
  10. data/lib/easybill_rest_client/.document_item.rb.swp +0 -0
  11. data/lib/easybill_rest_client/.document_payment.rb.swp +0 -0
  12. data/lib/easybill_rest_client/.document_recurring_options.rb.swp +0 -0
  13. data/lib/easybill_rest_client/.easybill_error.rb.swp +0 -0
  14. data/lib/easybill_rest_client/.log_formatter.rb.swp +0 -0
  15. data/lib/easybill_rest_client/.request_builder.rb.swp +0 -0
  16. data/lib/easybill_rest_client/.too_many_requests_error.rb.swp +0 -0
  17. data/lib/easybill_rest_client/api_client.rb +61 -0
  18. data/lib/easybill_rest_client/client.rb +39 -0
  19. data/lib/easybill_rest_client/customer.rb +70 -0
  20. data/lib/easybill_rest_client/customer_api.rb +15 -0
  21. data/lib/easybill_rest_client/document.rb +53 -0
  22. data/lib/easybill_rest_client/document_address.rb +19 -0
  23. data/lib/easybill_rest_client/document_api.rb +31 -0
  24. data/lib/easybill_rest_client/document_item.rb +34 -0
  25. data/lib/easybill_rest_client/document_payment.rb +15 -0
  26. data/lib/easybill_rest_client/document_payment_api.rb +15 -0
  27. data/lib/easybill_rest_client/document_recurring_options.rb +23 -0
  28. data/lib/easybill_rest_client/document_service_date.rb +12 -0
  29. data/lib/easybill_rest_client/generic_api.rb +39 -0
  30. data/lib/easybill_rest_client/pdf.rb +21 -0
  31. data/lib/easybill_rest_client/post_box.rb +24 -0
  32. data/lib/easybill_rest_client/post_box_api.rb +15 -0
  33. data/lib/easybill_rest_client/request.rb +107 -0
  34. data/lib/easybill_rest_client/request_logger.rb +24 -0
  35. data/lib/easybill_rest_client/response.rb +36 -0
  36. data/lib/easybill_rest_client/retry_on.rb +46 -0
  37. data/lib/easybill_rest_client/version.rb +5 -0
  38. data/log/.gitkeep +0 -0
  39. data/log/test.log +5723 -0
  40. data/script/.generate.swo +0 -0
  41. data/spec/.spec_helper.rb.swp +0 -0
  42. data/spec/fixtures/vcr/EasybillRestClient_CustomerApi/_customers_get/.returns_customers.yml.swo +0 -0
  43. data/spec/fixtures/vcr/EasybillRestClient_CustomerApi/_customers_get/.returns_customers.yml.swp +0 -0
  44. data/spec/fixtures/vcr/EasybillRestClient_CustomerApi/a_list_of_customers/gets_all_customers.yml +84 -0
  45. data/spec/fixtures/vcr/EasybillRestClient_CustomerApi/a_list_of_customers/gets_customers_matching_a_filter.yml +72 -0
  46. data/spec/fixtures/vcr/EasybillRestClient_CustomerApi/creates_updates_and_deletes_customer.yml +377 -0
  47. data/spec/fixtures/vcr/EasybillRestClient_Document/_all/returns_documents.yml +44 -0
  48. data/spec/fixtures/vcr/EasybillRestClient_DocumentApi/_cancel/cancels_a_document.yml +212 -0
  49. data/spec/fixtures/vcr/EasybillRestClient_DocumentApi/_create/creates_a_document.yml +53 -0
  50. data/spec/fixtures/vcr/EasybillRestClient_DocumentApi/_delete/deletes_a_document.yml +174 -0
  51. data/spec/fixtures/vcr/EasybillRestClient_DocumentApi/_find/returns_a_document.yml +57 -0
  52. data/spec/fixtures/vcr/EasybillRestClient_DocumentApi/_find_all/paid_and_unpaid_documents_exist/returns_only_unpaid_documents.yml +795 -0
  53. data/spec/fixtures/vcr/EasybillRestClient_DocumentApi/_find_all/returns_documents.yml +58 -0
  54. data/spec/fixtures/vcr/EasybillRestClient_DocumentApi/_find_all/returns_documents_by_number.yml +58 -0
  55. data/spec/fixtures/vcr/EasybillRestClient_DocumentApi/_finish/marks_a_drafted_document_as_finished.yml +212 -0
  56. data/spec/fixtures/vcr/EasybillRestClient_DocumentApi/_get_pdf/returns_a_PDF.yml +3889 -0
  57. data/spec/fixtures/vcr/EasybillRestClient_DocumentApi/_send_email/passes_on_additional_params.yml +63 -0
  58. data/spec/fixtures/vcr/EasybillRestClient_DocumentApi/_send_email/sends_an_email.yml +63 -0
  59. data/spec/fixtures/vcr/EasybillRestClient_DocumentApi/_update/updates_a_document.yml +107 -0
  60. data/spec/fixtures/vcr/EasybillRestClient_DocumentPaymentApi/_create/creates_a_document_payment.yml +195 -0
  61. data/spec/fixtures/vcr/EasybillRestClient_DocumentPaymentApi/_delete/deletes_a_document_payment.yml +168 -0
  62. data/spec/fixtures/vcr/EasybillRestClient_DocumentPaymentApi/_document_payments_get/returns_a_document_s_payments.yml +460 -0
  63. data/spec/fixtures/vcr/EasybillRestClient_DocumentPaymentApi/_document_payments_post/creates_a_document_payment.yml +47 -0
  64. data/spec/fixtures/vcr/EasybillRestClient_DocumentPaymentApi/_find/returns_a_document_payment.yml +66 -0
  65. data/spec/fixtures/vcr/EasybillRestClient_DocumentPaymentApi/_find_all/returns_document_payments.yml +66 -0
  66. data/spec/fixtures/vcr/EasybillRestClient_PostBoxApi/_delete/deletes_a_post_box.yml +174 -0
  67. data/spec/fixtures/vcr/EasybillRestClient_PostBoxApi/_find/returns_a_post_box.yml +72 -0
  68. data/spec/fixtures/vcr/EasybillRestClient_PostBoxApi/_find_all/returns_post_boxes.yml +73 -0
  69. data/spec/fixtures/vcr/EasybillRestClient_PostBoxApi/_post_boxes_get/returns_post_boxes.yml +52 -0
  70. data/spec/integration/.customer_api_spec.rb.swn +0 -0
  71. data/spec/integration/.customer_api_spec.rb.swo +0 -0
  72. data/spec/integration/customer_api_spec.rb +47 -0
  73. data/spec/integration/easybill_rest_client/document_api_spec.rb +129 -0
  74. data/spec/integration/easybill_rest_client/document_payment_api_spec.rb +55 -0
  75. data/spec/integration/easybill_rest_client/post_box_api_spec.rb +31 -0
  76. data/spec/lib/easybill_rest_client/.api_client_spec.rb.swp +0 -0
  77. data/spec/lib/easybill_rest_client/easybill_rest_api/.generic_api_spec.rb.swp +0 -0
  78. data/spec/lib/easybill_rest_client/generic_api_spec.rb +55 -0
  79. data/spec/lib/easybill_rest_client/pdf_spec.rb +29 -0
  80. data/spec/lib/easybill_rest_client/request_logger_spec.rb +14 -0
  81. data/spec/lib/easybill_rest_client/request_spec.rb +32 -0
  82. data/spec/lib/easybill_rest_client/retry_on_spec.rb +37 -0
  83. data/spec/spec_helper.rb +33 -0
  84. data/spec/support/.setup_api_client.rb.swo +0 -0
  85. data/spec/support/setup_client.rb +12 -0
  86. data/swagger.json +3964 -0
  87. metadata +257 -0
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EasybillRestClient
4
+ class GenericApi
5
+ def initialize(api_client)
6
+ @api_client = api_client
7
+ end
8
+
9
+ def find(id)
10
+ build(api_client.request(:get, "/#{resource_name}/#{id}"))
11
+ end
12
+
13
+ def find_all(params = {})
14
+ api_client.request_collection(:get, "/#{resource_name}", params).map { |d| build(d) }
15
+ end
16
+
17
+ def save(entity)
18
+ entity.id ? update(entity) : create(entity)
19
+ end
20
+
21
+ def create(entity)
22
+ build(api_client.request(:post, "/#{resource_name}", entity.attributes))
23
+ end
24
+
25
+ def update(entity)
26
+ build(api_client.request(:put, "/#{resource_name}/#{entity.id}", entity.attributes))
27
+ end
28
+
29
+ def delete(id)
30
+ api_client.request(:delete, "/#{resource_name}/#{id}")
31
+ end
32
+
33
+ def build(params)
34
+ resource_class.new(params)
35
+ end
36
+
37
+ attr_reader :api_client
38
+ end
39
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EasybillRestClient
4
+ class Pdf
5
+ attr_reader :content
6
+ attr_writer :filename
7
+
8
+ def initialize(filename:, content:)
9
+ @filename = filename
10
+ @content = content
11
+ end
12
+
13
+ def empty?
14
+ content.empty?
15
+ end
16
+
17
+ def filename
18
+ @filename[/\.pdf\Z/i] ? @filename : "#{@filename}.pdf"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EasybillRestClient
4
+ class PostBox
5
+ include Virtus.model
6
+ values do
7
+ attribute :id, Integer
8
+ end
9
+ attribute :cc, String
10
+ attribute :created_at, DateTime
11
+ attribute :date, Date
12
+ attribute :document_id, Integer
13
+ attribute :from, String
14
+ attribute :message, String
15
+ attribute :processed_at, DateTime
16
+ attribute :send_by_self, Boolean
17
+ attribute :send_with_attachment, Boolean
18
+ attribute :status_info, String
19
+ attribute :status, String
20
+ attribute :subject, String
21
+ attribute :to, String
22
+ attribute :type, String
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easybill_rest_client/generic_api'
4
+
5
+ module EasybillRestClient
6
+ class PostBoxApi < GenericApi
7
+ def resource_name
8
+ 'post-boxes'
9
+ end
10
+
11
+ def resource_class
12
+ PostBox
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'easybill_rest_client/request_logger'
4
+ require 'easybill_rest_client/retry_on'
5
+
6
+ module EasybillRestClient
7
+ class Request
8
+ BASE_URL = 'https://api.easybill.de/rest/v1'
9
+ USERNAME = 'rest-api@easybill.de'
10
+ SUPPORTED_METHODS = %i[get post put delete].freeze
11
+ OPEN_TIMEOUT = 30
12
+
13
+ def initialize(opts = {})
14
+ unless SUPPORTED_METHODS.include?(opts.fetch(:method).to_sym)
15
+ raise ArgumentError, "Unsupported HTTP method '#{method}'"
16
+ end
17
+
18
+ @api_key = opts.fetch(:api_key)
19
+ @method = opts.fetch(:method)
20
+ @endpoint = opts.fetch(:endpoint)
21
+ @params = opts.fetch(:params)
22
+ @logger = opts.fetch(:logger)
23
+ @tries = opts.fetch(:tries)
24
+ @retry_cool_off_time = opts.fetch(:retry_cool_off_time)
25
+ end
26
+
27
+ def run
28
+ request_logger.info("#{method.to_s.upcase} #{endpoint} #{request_details}")
29
+ retry_on(TooManyRequests) do
30
+ retry_on(Net::OpenTimeout) do
31
+ response = perform_request
32
+ raise TooManyRequests if response.is_a?(Net::HTTPTooManyRequests)
33
+ response
34
+ end
35
+ end
36
+ end
37
+
38
+ def request_details
39
+ body_allowed? ? request.body : uri.query
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :api_key, :method, :endpoint, :params, :logger, :tries, :retry_cool_off_time
45
+
46
+ def perform_request
47
+ http_opts = { use_ssl: uri.scheme == 'https', open_timeout: OPEN_TIMEOUT }
48
+ Net::HTTP.start(uri.host, uri.port, http_opts) do |http|
49
+ http.request(request)
50
+ end
51
+ end
52
+
53
+ def uri
54
+ return @uri if @uri
55
+ @uri = URI.parse(BASE_URL)
56
+ @uri.path << endpoint
57
+ @uri.query = URI.encode_www_form(query_params) unless body_allowed?
58
+ @uri
59
+ end
60
+
61
+ def query_params
62
+ params.map { |key, value| [key, translate_query_value(value)] }.to_h
63
+ end
64
+
65
+ def translate_query_value(value)
66
+ case value
67
+ when Array
68
+ value.join(',')
69
+ when nil
70
+ 'null'
71
+ else
72
+ value
73
+ end
74
+ end
75
+
76
+ def request
77
+ return @request if @request
78
+ @request = request_class.new(uri)
79
+ @request.body = params.reject { |_k, v| v.nil? }.to_json if body_allowed?
80
+ @request.basic_auth(USERNAME, api_key)
81
+ @request
82
+ end
83
+
84
+ def request_class
85
+ Net::HTTP.const_get(method.to_s.capitalize)
86
+ end
87
+
88
+ def body_allowed?
89
+ request_class::REQUEST_HAS_BODY
90
+ end
91
+
92
+ def retry_on(exception, &block)
93
+ @retry_on ||= RetryOn.new(request_logger, tries, retry_cool_off_time)
94
+ @retry_on.retry_on(exception, &block)
95
+ end
96
+
97
+ def request_logger
98
+ @request_logger ||= RequestLogger.new(logger: logger, request_id: request_id)
99
+ end
100
+
101
+ def request_id
102
+ @request_id ||= SecureRandom.hex(3)
103
+ end
104
+ end
105
+
106
+ class TooManyRequests < StandardError; end
107
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EasybillRestClient
4
+ class RequestLogger
5
+ def initialize(logger:, request_id:)
6
+ @logger = logger
7
+ @request_id = request_id
8
+ end
9
+
10
+ %i[info warn error].each do |method|
11
+ define_method(method) do |msg|
12
+ logger.public_send(method, format_message(msg))
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :request_id, :logger
19
+
20
+ def format_message(msg)
21
+ "[easybill-rest-client] RequestId=#{request_id} #{msg}"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EasybillRestClient
4
+ class Response
5
+ def initialize(response)
6
+ @response = response
7
+ end
8
+
9
+ def body
10
+ body = extract_response_body(response)
11
+ unless response.is_a?(Net::HTTPSuccess)
12
+ raise ApiError, body.inspect
13
+ end
14
+ body && !body.empty? ? body : nil
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :response
20
+
21
+ def extract_response_body(response)
22
+ return unless response.class.body_permitted?
23
+ case response.content_type
24
+ when 'application/json'
25
+ JSON.parse(response.body, symbolize_names: true)
26
+ when 'application/pdf'
27
+ /\Wfilename="(?<filename>.*?)"/ =~ response.fetch('content-disposition')
28
+ Pdf.new(filename: filename, content: response.body)
29
+ else
30
+ response.body
31
+ end
32
+ end
33
+ end
34
+
35
+ class ApiError < RuntimeError; end
36
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'retryable'
4
+
5
+ module EasybillRestClient
6
+ class RetryOn
7
+ def initialize(logger, tries, retry_cool_off_time)
8
+ @logger = logger
9
+ @tries = tries
10
+ @retry_cool_off_time = retry_cool_off_time
11
+ end
12
+
13
+ def retry_on(klass, &block)
14
+ Retryable.retryable(retryable_opts(klass), &block)
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :logger, :tries, :retry_cool_off_time
20
+
21
+ def retryable_opts(klass)
22
+ {
23
+ EasybillRestClient::TooManyRequests => {
24
+ tries: tries,
25
+ sleep: retry_cool_off_time,
26
+ on: klass,
27
+ exception_cb: method(:log_too_many_requests)
28
+ },
29
+ Net::OpenTimeout => {
30
+ tries: tries,
31
+ sleep: 0,
32
+ on: klass,
33
+ exception_cb: method(:log_open_timeout)
34
+ }
35
+ }.fetch(klass)
36
+ end
37
+
38
+ def log_open_timeout(_exception)
39
+ logger.warn("Unable to open connection after #{Request::OPEN_TIMEOUT}s, retrying...")
40
+ end
41
+
42
+ def log_too_many_requests(_exception)
43
+ logger.warn('Too many requests!')
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EasybillRestClient
4
+ VERSION = '2.0.2'
5
+ end
data/log/.gitkeep ADDED
File without changes