openpix-ruby_sdk 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: acb4367e543636c06a58f9b1e54a7461f050f655ee7a1049d658ba49e45307a3
4
+ data.tar.gz: 2030d59afb88e01194765d2d2ad4283e46d8bbc7a80bb9ce6c3351b2cb11906f
5
+ SHA512:
6
+ metadata.gz: aeda3c9f14a2fe7261ea5e10cf9d69ab519a422176d4d0b45694fedd3760bbaae4769386f2ee2278a1091aac6a4f491fb0cc141dbbc9f1039e5447fb00b1bf1e
7
+ data.tar.gz: 7db2b6adb11cf5b3cf00c0f652751b2b6dbaf91b57f027b75e91a76c477430519a5c04078407d1308e2f9098242fd608950c33d0b7976cbc113627e797fbb8bb
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ ## [Unreleased]
2
+
3
+ ## 1.0.0 (2023-06-13)
4
+
5
+
6
+ ### Features
7
+
8
+ * Trigger CI ([54531e8](https://github.com/Open-Pix/ruby-sdk/commit/54531e83fb3ebf520df077897de0f99488ded6db))
9
+
10
+ ## [0.1.0] - 2023-05-09
11
+
12
+ - Initial release
data/README.md ADDED
@@ -0,0 +1,146 @@
1
+ # OpenPix/Woovi Ruby SDK
2
+ Welcome to the Woovi Ruby SDK! This SDK provides convenient access to the Woovi REST API, allowing you to easily integrate Woovi's REST API into your Ruby applications.
3
+
4
+ ## Documentation
5
+ Documentation for Woovi REST API can be found [here](https://developers.woovi.com/api).
6
+ RDoc documentation for classes included in the gem can be found [here]().
7
+
8
+ ## Installation
9
+ To install this gem using Bundler, add this following line to your `Gemfile`.
10
+ ```shell
11
+ gem 'openpix-ruby_sdk', '~> 0.1.0'
12
+ ```
13
+
14
+ To manually install `openpix-ruby_sdk` via Rubygems simply:
15
+ ```shell
16
+ gem install openpix-ruby_sdk -v 0.1.0
17
+ ```
18
+
19
+ ## Usage
20
+ Main class `openpix/rubysdk/client` is your entrypoint to the endpoints.
21
+ ### Authenticating client
22
+ ```ruby
23
+ require 'openpix/rubysdk'
24
+
25
+ # Your AppID from https://app.woovi.com/home/applications/tab/list
26
+ app_id = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
27
+
28
+ client = Openpix::RubySdk::Client.new(app_id)
29
+ ```
30
+ ### Using resources
31
+ `Openpix::RubySdk::Client` has access to all resources available through a accessor method with resource name in plural form
32
+ E.g: Charge -> client.charges (returns the charge resource class with all available methods)
33
+ ```ruby
34
+ # Creating a Charge
35
+ client.charges.init_body(
36
+ params: {
37
+ correlation_id: 'my-correlation-id',
38
+ value: 50000
39
+ }
40
+ )
41
+ response = client.charges.save
42
+ response.success? # should yield true
43
+ response.resource_response # API response for this resource, example bellow \/
44
+ # {
45
+ # "status" => "ACTIVE",
46
+ # "value" => 100,
47
+ # "comment" => "good",
48
+ # "correlationID" => "9134e286-6f71-427a-bf00-241681624586",
49
+ # ... and so on
50
+ # }
51
+
52
+ # Listing Charges
53
+ # Default skip is 0 and limit is 100
54
+ response = client.charges.fetch(skip: 0, limit: 100) # skip and limit are pagination params, https://developers.woovi.com/api#tag/charge/paths/~1api~1v1~1charge/get
55
+ response.pagination_meta # holds information about pagination, like total, hasNextPage and so on
56
+ response.resource_response # API response for this resource, should be an array
57
+
58
+ # If next or previous pages available, there is a convenience method to fetch next or previous pages
59
+ # In order to call those methods, you need first to call #fetch or #fetch! to set the pagination params
60
+ # Those methods will preserve any :params sent to #fetch or #fetch! method
61
+ # BE CAREFUL, those methods only have bang! versions because they have a strong dependency on #fetch, handle properly their errors
62
+ client.charges.fetch_next_page!
63
+ client.charges.fetch_previous_page!
64
+
65
+ # Finding Charge
66
+ response = client.charges.find(id: 'my-charge-id')
67
+ # response has same attributes from save, since it is a single resource response
68
+
69
+ # Destroying Charge
70
+ response = client.charges.destroy(id: 'my-charge-id')
71
+ response.success? # this operations just returns success
72
+ ```
73
+ ### Available resources
74
+ The available resources are:
75
+ - Charge (charges)
76
+ - Customer (customers)
77
+ - Payment (payments)
78
+ - Refund (refunds)
79
+ - Subscription (subscriptions)
80
+ - Webhook (webhooks)
81
+ ### Handling errors
82
+ All available resource methods have their bang! version, which raises an error whenever something goes wrong so you can properly handle those cases
83
+ All errors have some helpful message, showing response status and error response from API
84
+
85
+ Error classes are:
86
+ **save!** -> `Openpix::RubySdk::Resources::RequestError`
87
+ **fetch!** -> `Openpix::RubySdk::Resources::RequestError`
88
+ **fetch_next_page!** -> `Openpix::RubySdk::Resources::RequestError`, `Openpix::RubySdk::Resources::NotFetchedError`, `Openpix::RubySdk::Resources::PageNotDefinedError`
89
+ **fetch_previous_page!** -> `Openpix::RubySdk::Resources::RequestError`, `Openpix::RubySdk::Resources::NotFetchedError`, `Openpix::RubySdk::Resources::PageNotDefinedError`
90
+ **find!** -> `Openpix::RubySdk::Resources::RequestError`
91
+ **destroy!** -> `Openpix::RubySdk::Resources::RequestError`
92
+
93
+ For the safe version (without bang!) there will be an `error_response` attribute setted in the API response whenever `success?` is false.
94
+ ```ruby
95
+ response = client.customers.save
96
+
97
+ unless response.success?
98
+ response.error_response # error response from API
99
+ end
100
+ ```
101
+
102
+ ## Contributing
103
+ We welcome contributions to the Woovi Ruby SDK! If you would like to contribute, please follow these steps:
104
+
105
+ - Fork the repository
106
+ - Create a new branch for your feature or bug fix
107
+ - Write your code and tests
108
+ - Commit your changes and push your branch to GitHub
109
+ - Submit a pull request
110
+
111
+ Please make sure to adhere to the [code of conduct](#code-of-conduct).
112
+
113
+ ## Code of Conduct
114
+ Our Pledge
115
+ We pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
116
+
117
+ Our Standards
118
+ Examples of behavior that contributes to creating a positive environment include:
119
+
120
+ Using welcoming and inclusive language
121
+ Being respectful of differing viewpoints and experiences
122
+ Gracefully accepting constructive criticism
123
+ Focusing on what is best for the community
124
+ Showing empathy towards other community members
125
+ Examples of unacceptable behavior by participants include:
126
+
127
+ The use of sexualized language or imagery and unwelcome sexual attention or advances
128
+ Trolling, insulting/derogatory comments, and personal or political attacks
129
+ Public or private harassment
130
+ Publishing others' private information, such as a physical or electronic address, without explicit permission
131
+ Other conduct which could reasonably be considered inappropriate in a professional setting
132
+ Our Responsibilities
133
+ As project maintainers, we are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
134
+
135
+ As contributors, you have the responsibility to adhere to these standards and report any instances of unacceptable behavior.
136
+
137
+ Enforcement
138
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the project team at <developers@woovi.com>. The project team will review and investigate all complaints and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
139
+
140
+ Project maintainers who do not follow or enforce the code of conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
141
+
142
+ Attribution
143
+ This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at http://contributor-covenant.org/version/1/4.
144
+
145
+ ## License
146
+ MIT License.
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/string/inflections'
5
+
6
+ module Openpix
7
+ module RubySdk
8
+ # Helper class to format body params before request
9
+ class ApiBodyFormatter
10
+ class << self
11
+ def format_entity_param(entity)
12
+ formatted_entity = {}
13
+
14
+ entity.each do |attr, value|
15
+ formatted_entity[transform_id_pattern(attr)] = value
16
+ end
17
+
18
+ remove_empty_values(formatted_entity)
19
+ end
20
+
21
+ def remove_empty_values(entity)
22
+ entity.compact.reject do |_key, value|
23
+ value.empty? if value.respond_to?(:empty?)
24
+ end
25
+ end
26
+
27
+ def transform_id_pattern(attr_key)
28
+ attr_key.camelize(:lower).gsub('Id', 'ID')
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openpix
4
+ module RubySdk
5
+ # An Object representing the response from a call to Woovi API
6
+ class ApiResponse
7
+ attr_reader :success, :resource_response, :pagination_meta, :error_response, :status
8
+
9
+ def initialize(status:, resource_response: nil, error_response: nil, pagination_meta: {})
10
+ @success = status == 200
11
+ @status = status
12
+ @resource_response = resource_response
13
+ @pagination_meta = pagination_meta
14
+ @error_response = error_response
15
+ end
16
+
17
+ def success?
18
+ success
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/string/inflections'
5
+
6
+ require 'openpix/ruby_sdk/http_client'
7
+ require 'openpix/ruby_sdk/resources'
8
+
9
+ module Openpix
10
+ module RubySdk
11
+ # Entrypoint class, expect to access resources and other classes just from this class
12
+ class Client
13
+ RESOURCES = %w[
14
+ Charge
15
+ Customer
16
+ Payment
17
+ Refund
18
+ Subscription
19
+ Webhook
20
+ ].freeze
21
+
22
+ def initialize(auth_token)
23
+ @auth_token = auth_token
24
+
25
+ init_http_client
26
+ end
27
+
28
+ RESOURCES.each do |resource|
29
+ pluralized_resource_name = resource.downcase.pluralize
30
+ define_method pluralized_resource_name do
31
+ return instance_variable_get("@#{pluralized_resource_name}") if instance_variable_get("@#{pluralized_resource_name}")
32
+
33
+ instance_variable_set(
34
+ "@#{pluralized_resource_name}",
35
+ "Openpix::RubySdk::Resources::#{resource}".constantize.new(@http_client)
36
+ )
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def init_http_client
43
+ @http_client = Openpix::RubySdk::HttpClient.instance
44
+
45
+ @http_client.initialize_http_client(@auth_token)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'faraday/httpclient'
5
+
6
+ module Openpix
7
+ module RubySdk
8
+ # Application HTTP Client to make requests, it uses Faraday as the wrapper and defaults to STD Lib client (Net::HTTP)
9
+ class HttpClient
10
+ BASE_URL = 'https://api.woovi.com/api'
11
+ API_VERSION = '/v1'
12
+
13
+ @instance = new
14
+
15
+ private_class_method :new
16
+
17
+ class << self
18
+ attr_reader :instance
19
+ end
20
+
21
+ def initialize_http_client(auth_token)
22
+ @http_client = Faraday.new(
23
+ url: "#{BASE_URL}#{API_VERSION}",
24
+ headers: {
25
+ 'Authorization' => auth_token
26
+ }
27
+ ) do |f|
28
+ f.request :json
29
+ f.response :json
30
+ f.adapter :httpclient
31
+ end
32
+ end
33
+
34
+ def post(resource, body:, headers: {}, params: {})
35
+ @http_client.post(resource) do |request|
36
+ request.params = params
37
+ request.headers = request.headers.merge(headers)
38
+ request.body = body
39
+ end
40
+ end
41
+
42
+ def get(resource, params: {}, headers: {})
43
+ @http_client.get(resource) do |request|
44
+ request.params = params
45
+ request.headers = request.headers.merge(headers)
46
+ end
47
+ end
48
+
49
+ def delete(resource, headers: {})
50
+ @http_client.delete(resource) do |request|
51
+ request.headers = request.headers.merge(headers)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openpix/ruby_sdk/resources/resource'
4
+ require 'openpix/ruby_sdk/api_body_formatter'
5
+
6
+ module Openpix
7
+ module RubySdk
8
+ module Resources
9
+ # Make API operations on Charge resource
10
+ class Charge < Resource
11
+ ATTRS = %w[
12
+ correlation_id
13
+ value
14
+ type
15
+ comment
16
+ identifier
17
+ expires_in
18
+ customer
19
+ days_for_due_date
20
+ days_after_due_date
21
+ interests
22
+ fines
23
+ additional_info
24
+ ].freeze
25
+
26
+ attr_accessor(*ATTRS)
27
+
28
+ # @param params [Hash] the attributes for creating a Charge
29
+ # @param rest [Hash] more attributes to be merged at the body, use this only for unsupported fields
30
+ def init_body(params: {}, rest: {})
31
+ super(base_attrs: ATTRS, params: params, rest: rest)
32
+ end
33
+
34
+ # attributes used on POST create method
35
+ def create_attributes
36
+ ATTRS
37
+ end
38
+
39
+ # URL for this resource
40
+ def to_url
41
+ 'charge'
42
+ end
43
+
44
+ # Converts its attributes into a hash
45
+ def to_body
46
+ body = super
47
+
48
+ return body if body['customer'].nil? || body['customer'].empty?
49
+
50
+ body['customer'] = Openpix::RubySdk::ApiBodyFormatter.format_entity_param(body['customer'])
51
+
52
+ return body if body['customer']['address'].nil? || body['customer']['address'].empty?
53
+
54
+ customer_address_parsed = Openpix::RubySdk::ApiBodyFormatter.format_entity_param(body['customer']['address'])
55
+ body['customer'] = body['customer'].merge({ 'address' => customer_address_parsed })
56
+
57
+ body
58
+ end
59
+
60
+ # add a new additional_info
61
+ # @param key [String] the key
62
+ # @param value [String] the value
63
+ def add_additional_info(key, value)
64
+ @additional_info = [] if @additional_info.nil?
65
+
66
+ @additional_info << { 'key' => key, 'value' => value }
67
+ end
68
+
69
+ # set interests configuration for creating this resource
70
+ # @param value [Number] value in basis points of interests to be applied daily after the charge hits the deadline
71
+ def set_interests(value)
72
+ @interests = { 'value' => value }
73
+ end
74
+
75
+ # set fines configuration for creating this resource
76
+ # @param value [Number] value in basis points of fines to be applied when the charge hits the deadline
77
+ def set_fines(value)
78
+ @fines = { 'value' => value }
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openpix/ruby_sdk/resources/resource'
4
+ require 'openpix/ruby_sdk/api_body_formatter'
5
+
6
+ module Openpix
7
+ module RubySdk
8
+ module Resources
9
+ # Make API operations on Customer resource
10
+ class Customer < Resource
11
+ ATTRS = %w[
12
+ name
13
+ email
14
+ phone
15
+ tax_id
16
+ correlation_id
17
+ address
18
+ ].freeze
19
+
20
+ attr_accessor(*ATTRS)
21
+
22
+ # @param params [Hash{String => String, Number, Hash{String, Number}, Array<Hash{String, String}>}] the attributes for creating a Charge
23
+ # @param rest [Hash] more attributes to be merged at the body, use this only for unsupported fields
24
+ def init_body(params: {}, rest: {})
25
+ super(base_attrs: ATTRS, params: params, rest: rest)
26
+ end
27
+
28
+ def create_attributes
29
+ ATTRS
30
+ end
31
+
32
+ def to_url
33
+ 'customer'
34
+ end
35
+
36
+ def to_body
37
+ body = super
38
+
39
+ return body if body['address'].nil? || body['address'].empty?
40
+
41
+ body['address'] = Openpix::RubySdk::ApiBodyFormatter.format_entity_param(body['address'])
42
+
43
+ body
44
+ end
45
+
46
+ # rubocop:disable Lint/UnusedMethodArgument
47
+ def destroy(id:)
48
+ raise(
49
+ ActionNotImplementedError,
50
+ 'customer does not implement DELETE action'
51
+ )
52
+ end
53
+
54
+ def destroy!(id:)
55
+ raise(
56
+ ActionNotImplementedError,
57
+ 'customer does not implement DELETE action'
58
+ )
59
+ end
60
+ # rubocop:enable Lint/UnusedMethodArgument
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/hash/except'
5
+
6
+ require 'openpix/ruby_sdk/resources/resource'
7
+
8
+ module Openpix
9
+ module RubySdk
10
+ module Resources
11
+ # Make API operations on Payment resource
12
+ class Payment < Resource
13
+ ATTRS = %w[
14
+ value
15
+ destination_alias
16
+ correlation_id
17
+ comment
18
+ source_account_id
19
+ ].freeze
20
+
21
+ attr_accessor(*ATTRS)
22
+
23
+ # @param params [Hash{String => String, Number, Hash{String, Number}, Array<Hash{String, String}>}] the attributes for creating a Charge
24
+ # @param rest [Hash] more attributes to be merged at the body, use this only for unsupported fields
25
+ def init_body(params: {}, rest: {})
26
+ super(base_attrs: ATTRS, params: params, rest: rest)
27
+ end
28
+
29
+ def create_attributes
30
+ ATTRS
31
+ end
32
+
33
+ def to_url
34
+ 'payment'
35
+ end
36
+
37
+ def to_body
38
+ body = super
39
+
40
+ return body unless body['sourceAccountID']
41
+
42
+ body['sourceAccountId'] = body['sourceAccountID']
43
+
44
+ body.except('sourceAccountID')
45
+ end
46
+
47
+ # rubocop:disable Lint/UnusedMethodArgument
48
+ def destroy(id:)
49
+ raise(
50
+ ActionNotImplementedError,
51
+ 'payment does not implement DELETE action'
52
+ )
53
+ end
54
+
55
+ def destroy!(id:)
56
+ raise(
57
+ ActionNotImplementedError,
58
+ 'payment does not implement DELETE action'
59
+ )
60
+ end
61
+ # rubocop:enable Lint/UnusedMethodArgument
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/hash/except'
5
+
6
+ require 'openpix/ruby_sdk/resources/resource'
7
+
8
+ module Openpix
9
+ module RubySdk
10
+ module Resources
11
+ # Make API operations on Refund resource
12
+ class Refund < Resource
13
+ ATTRS = %w[
14
+ value
15
+ transaction_end_to_end_id
16
+ correlation_id
17
+ comment
18
+ ].freeze
19
+
20
+ attr_accessor(*ATTRS)
21
+
22
+ # @param params [Hash{String => String, Number, Hash{String, Number}, Array<Hash{String, String}>}] the attributes for creating a Charge
23
+ # @param rest [Hash] more attributes to be merged at the body, use this only for unsupported fields
24
+ def init_body(params: {}, rest: {})
25
+ super(base_attrs: ATTRS, params: params, rest: rest)
26
+ end
27
+
28
+ def create_attributes
29
+ ATTRS
30
+ end
31
+
32
+ def to_url
33
+ 'refund'
34
+ end
35
+
36
+ def to_body
37
+ body = super
38
+
39
+ return body unless body['transactionEndToEndID']
40
+
41
+ body['transactionEndToEndId'] = body['transactionEndToEndID']
42
+
43
+ body.except('transactionEndToEndID')
44
+ end
45
+
46
+ # rubocop:disable Lint/UnusedMethodArgument
47
+ def destroy(id:)
48
+ raise(
49
+ ActionNotImplementedError,
50
+ 'refund does not implement DELETE action'
51
+ )
52
+ end
53
+
54
+ def destroy!(id:)
55
+ raise(
56
+ ActionNotImplementedError,
57
+ 'refund does not implement DELETE action'
58
+ )
59
+ end
60
+ # rubocop:enable Lint/UnusedMethodArgument
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,303 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/string/inflections'
5
+ require 'active_support/core_ext/hash/indifferent_access'
6
+
7
+ require 'openpix/ruby_sdk/api_response'
8
+ require 'openpix/ruby_sdk/api_body_formatter'
9
+
10
+ module Openpix
11
+ module RubySdk
12
+ module Resources
13
+ # Error returned when the required method is not implemented in the class child class
14
+ class NotImplementedError < StandardError
15
+ def initialize(msg: nil, method: 'nil')
16
+ super(msg) if msg.present?
17
+
18
+ super("#{method} not implemented")
19
+ end
20
+ end
21
+
22
+ # Error raised when there is a status != from 200 from the API response
23
+ # This is just raised in methods that calls the bang (with exclamation mark "!") version
24
+ class RequestError < StandardError
25
+ end
26
+
27
+ # Error raised when client is trying to fetch next/previous page without fetching without pagination first
28
+ class NotFetchedError < StandardError
29
+ end
30
+
31
+ # Error raised when client is trying to fetch next/previous page and page does not exists
32
+ class PageNotDefinedError < StandardError
33
+ end
34
+
35
+ # Error raised when client is trying to use a Restful action that is not implemented in the current resource
36
+ class ActionNotImplementedError < StandardError
37
+ end
38
+
39
+ # Base class for resources from the API
40
+ class Resource
41
+ def initialize(http_client)
42
+ @http_client = http_client
43
+ end
44
+
45
+ def init_body(base_attrs: [], params: {}, rest: {})
46
+ params = params.with_indifferent_access
47
+ base_attrs.each { |attr| instance_variable_set("@#{attr}", params[attr]) }
48
+ @rest = rest
49
+
50
+ self
51
+ end
52
+
53
+ def to_url
54
+ raise NotImplementedError.new(method: __method__)
55
+ end
56
+
57
+ def to_single_resource
58
+ to_url
59
+ end
60
+
61
+ def create_attributes
62
+ raise NotImplementedError.new(method: __method__)
63
+ end
64
+
65
+ def to_body
66
+ body = {}
67
+
68
+ create_attributes.each do |attr|
69
+ body[Openpix::RubySdk::ApiBodyFormatter.transform_id_pattern(attr)] = send(attr)
70
+ end
71
+
72
+ compacted_body = Openpix::RubySdk::ApiBodyFormatter.remove_empty_values(body)
73
+
74
+ return compacted_body unless @rest
75
+
76
+ compacted_body.merge(@rest)
77
+ end
78
+
79
+ def save(extra_headers: {}, return_existing: false)
80
+ response = post_request(extra_headers, return_existing)
81
+
82
+ Openpix::RubySdk::ApiResponse.new(
83
+ status: response.status,
84
+ resource_response: response.body[to_single_resource],
85
+ error_response: response.body['error']
86
+ )
87
+ end
88
+
89
+ def save!(extra_headers: {}, return_existing: false)
90
+ response = post_request(extra_headers, return_existing)
91
+
92
+ if response.status != 200
93
+ raise(
94
+ RequestError,
95
+ "Error while saving, API response: #{response.body['error']}, status: #{response.status}"
96
+ )
97
+ end
98
+
99
+ Openpix::RubySdk::ApiResponse.new(
100
+ status: response.status,
101
+ resource_response: response.body[to_single_resource]
102
+ )
103
+ end
104
+
105
+ def fetch(skip: nil, limit: nil, extra_headers: {}, params: {})
106
+ set_pagination(skip, limit)
107
+
108
+ response = get_request(extra_headers: extra_headers, params: @pagination_params.merge(params))
109
+
110
+ @fetched = response.status == 200
111
+
112
+ set_pagination_meta(response.body['pageInfo']) if @fetched
113
+ @last_fetched_params = params if @fetched && !params.empty?
114
+
115
+ Openpix::RubySdk::ApiResponse.new(
116
+ status: response.status,
117
+ resource_response: response.body[to_url.pluralize],
118
+ pagination_meta: response.body['pageInfo'],
119
+ error_response: response.body['error']
120
+ )
121
+ end
122
+
123
+ def fetch!(skip: nil, limit: nil, extra_headers: {}, params: {})
124
+ set_pagination(skip, limit)
125
+
126
+ response = get_request(extra_headers: extra_headers, params: @pagination_params.merge(params))
127
+
128
+ if response.status != 200
129
+ raise(
130
+ RequestError,
131
+ "Error while fetching, API response: #{response.body['error']}, status: #{response.status}"
132
+ )
133
+ end
134
+
135
+ @fetched = true
136
+ @last_fetched_params = params unless params.empty?
137
+ set_pagination_meta(response.body['pageInfo'])
138
+
139
+ Openpix::RubySdk::ApiResponse.new(
140
+ status: response.status,
141
+ pagination_meta: response.body['pageInfo'],
142
+ resource_response: response.body[to_url.pluralize]
143
+ )
144
+ end
145
+
146
+ def fetch_next_page!(extra_headers: {})
147
+ fetch_page!(:next, extra_headers)
148
+ end
149
+
150
+ def fetch_previous_page!(extra_headers: {})
151
+ fetch_page!(:previous, extra_headers)
152
+ end
153
+
154
+ def find(id:, extra_headers: {})
155
+ response = get_request(url: encoded_url(id), extra_headers: extra_headers)
156
+
157
+ Openpix::RubySdk::ApiResponse.new(
158
+ status: response.status,
159
+ resource_response: response.body[to_single_resource],
160
+ error_response: response.body['error']
161
+ )
162
+ end
163
+
164
+ def find!(id:, extra_headers: {})
165
+ response = get_request(url: encoded_url(id), extra_headers: extra_headers)
166
+
167
+ if response.status != 200
168
+ raise(
169
+ RequestError,
170
+ "Error while getting #{to_single_resource} of id = #{id}, API response: #{response.body['error']}, status: #{response.status}"
171
+ )
172
+ end
173
+
174
+ Openpix::RubySdk::ApiResponse.new(
175
+ status: response.status,
176
+ resource_response: response.body[to_single_resource]
177
+ )
178
+ end
179
+
180
+ def destroy(id:, extra_headers: {})
181
+ response = delete_request(url: encoded_url(id), extra_headers: extra_headers)
182
+
183
+ Openpix::RubySdk::ApiResponse.new(
184
+ status: response.status,
185
+ error_response: response.body['error']
186
+ )
187
+ end
188
+
189
+ def destroy!(id:, extra_headers: {})
190
+ response = delete_request(url: encoded_url(id), extra_headers: extra_headers)
191
+
192
+ if response.status != 200
193
+ raise(
194
+ RequestError,
195
+ "Error while deleting #{to_url} of id = #{id}, API response: #{response.body['error']}, status: #{response.status}"
196
+ )
197
+ end
198
+
199
+ Openpix::RubySdk::ApiResponse.new(
200
+ status: response.status
201
+ )
202
+ end
203
+
204
+ private
205
+
206
+ def post_request(extra_headers, return_existing)
207
+ @http_client.post(
208
+ to_url,
209
+ body: to_body,
210
+ headers: extra_headers,
211
+ params: { return_existing: return_existing }
212
+ )
213
+ end
214
+
215
+ def get_request(url: to_url, extra_headers: {}, params: {})
216
+ @http_client.get(
217
+ url,
218
+ headers: extra_headers,
219
+ params: params
220
+ )
221
+ end
222
+
223
+ def delete_request(url: to_url, extra_headers: {})
224
+ @http_client.delete(
225
+ url,
226
+ headers: extra_headers
227
+ )
228
+ end
229
+
230
+ def set_pagination(skip, limit)
231
+ @pagination_params = { skip: 0, limit: 100 } if @pagination_params.nil?
232
+ @pagination_params[:skip] = 0 if @pagination_params[:skip].nil?
233
+ @pagination_params[:limit] = 100 if @pagination_params[:limit].nil?
234
+
235
+ @pagination_params[:skip] = skip if skip
236
+
237
+ return unless limit
238
+
239
+ @pagination_params[:limit] = limit
240
+ end
241
+
242
+ def set_pagination_meta(pagination_meta)
243
+ @pagination_meta = {
244
+ total_count: pagination_meta['totalCount'],
245
+ has_previous_page: pagination_meta['hasPreviousPage'],
246
+ has_next_page: pagination_meta['hasNextPage']
247
+ }
248
+ end
249
+
250
+ def calculate_pagination_params(page_orientation)
251
+ if page_orientation == :next
252
+ @pagination_params[:skip] += @pagination_params[:limit]
253
+ elsif page_orientation == :previous
254
+ @pagination_params[:skip] -= @pagination_params[:limit]
255
+ end
256
+ end
257
+
258
+ def fetch_page!(page_orientation, extra_headers = {})
259
+ unless @fetched
260
+ raise(
261
+ NotFetchedError,
262
+ "#fetch needs to be called before trying to fetch #{page_orientation} page"
263
+ )
264
+ end
265
+
266
+ unless @pagination_meta["has_#{page_orientation}_page".to_sym]
267
+ raise(
268
+ PageNotDefinedError,
269
+ "There is no #{page_orientation} page defined for the skip: #{@pagination_params[:skip]} and " \
270
+ "limit: #{@pagination_params[:limit]} params requested"
271
+ )
272
+ end
273
+
274
+ calculate_pagination_params(page_orientation)
275
+ request_params = if @last_fetched_params.nil?
276
+ @pagination_params
277
+ else
278
+ @pagination_params.merge(@last_fetched_params)
279
+ end
280
+ response = get_request(extra_headers: extra_headers, params: request_params)
281
+
282
+ if response.status != 200
283
+ raise(
284
+ RequestError,
285
+ "Error while fetching #{page_orientation} page, API response: #{response.body['error']}, status: #{response.status}"
286
+ )
287
+ end
288
+
289
+ set_pagination_meta(response.body['pageInfo'])
290
+ Openpix::RubySdk::ApiResponse.new(
291
+ status: response.status,
292
+ pagination_meta: response.body['pageInfo'],
293
+ resource_response: response.body[to_url.pluralize]
294
+ )
295
+ end
296
+
297
+ def encoded_url(id)
298
+ "#{to_url}/#{URI.encode_www_form_component(id)}"
299
+ end
300
+ end
301
+ end
302
+ end
303
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openpix/ruby_sdk/resources/resource'
4
+ require 'openpix/ruby_sdk/api_body_formatter'
5
+
6
+ module Openpix
7
+ module RubySdk
8
+ module Resources
9
+ # Make API operations on Subscription resource
10
+ class Subscription < Resource
11
+ ATTRS = %w[
12
+ value
13
+ day_generate_charge
14
+ customer
15
+ ].freeze
16
+
17
+ attr_accessor(*ATTRS)
18
+
19
+ # @param params [Hash{String => String, Number, Hash{String, Number}, Array<Hash{String, String}>}] the attributes for creating a Charge
20
+ # @param rest [Hash] more attributes to be merged at the body, use this only for unsupported fields
21
+ def init_body(params: {}, rest: {})
22
+ super(base_attrs: ATTRS, params: params, rest: rest)
23
+ end
24
+
25
+ def create_attributes
26
+ ATTRS
27
+ end
28
+
29
+ def to_url
30
+ 'subscriptions'
31
+ end
32
+
33
+ def to_single_resource
34
+ 'subscription'
35
+ end
36
+
37
+ def to_body
38
+ body = super
39
+
40
+ return body if body['customer'].nil? || body['customer'].empty?
41
+
42
+ body['customer'] = Openpix::RubySdk::ApiBodyFormatter.format_entity_param(body['customer'])
43
+
44
+ body
45
+ end
46
+
47
+ # rubocop:disable Lint/UnusedMethodArgument
48
+ def fetch(skip: nil, limit: nil, extra_headers: {})
49
+ raise(
50
+ ActionNotImplementedError,
51
+ 'subscription does not implement GET index action'
52
+ )
53
+ end
54
+
55
+ def fetch!(skip: nil, limit: nil, extra_headers: {})
56
+ raise(
57
+ ActionNotImplementedError,
58
+ 'subscription does not implement GET index action'
59
+ )
60
+ end
61
+
62
+ def fetch_next_page!(extra_headers: {})
63
+ raise(
64
+ ActionNotImplementedError,
65
+ 'subscription does not implement GET index action'
66
+ )
67
+ end
68
+
69
+ def fetch_previous_page!(extra_headers: {})
70
+ raise(
71
+ ActionNotImplementedError,
72
+ 'subscription does not implement GET index action'
73
+ )
74
+ end
75
+
76
+ def destroy(id:)
77
+ raise(
78
+ ActionNotImplementedError,
79
+ 'subscription does not implement DELETE action'
80
+ )
81
+ end
82
+
83
+ def destroy!(id:)
84
+ raise(
85
+ ActionNotImplementedError,
86
+ 'subscription does not implement DELETE action'
87
+ )
88
+ end
89
+ # rubocop:enable Lint/UnusedMethodArgument
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openpix/ruby_sdk/resources/resource'
4
+
5
+ module Openpix
6
+ module RubySdk
7
+ module Resources
8
+ # Make API operations on Webhook resource
9
+ class Webhook < Resource
10
+ ATTRS = %w[
11
+ name
12
+ event
13
+ url
14
+ authorization
15
+ is_active
16
+ ].freeze
17
+
18
+ attr_accessor(*ATTRS)
19
+
20
+ # @param params [Hash{String => String, Number, Hash{String, Number}, Array<Hash{String, String}>}] the attributes for creating a Charge
21
+ # @param rest [Hash] more attributes to be merged at the body, use this only for unsupported fields
22
+ def init_body(params: {}, rest: {})
23
+ super(base_attrs: ATTRS, params: params, rest: rest)
24
+ end
25
+
26
+ def create_attributes
27
+ ATTRS
28
+ end
29
+
30
+ def to_url
31
+ 'webhook'
32
+ end
33
+
34
+ def to_body
35
+ body = super
36
+
37
+ { webhook: body }
38
+ end
39
+
40
+ # rubocop:disable Lint/UnusedMethodArgument
41
+ def find(id:, extra_headers: {})
42
+ raise(
43
+ ActionNotImplementedError,
44
+ 'webhook does not implement GET show action'
45
+ )
46
+ end
47
+
48
+ def find!(id:, extra_headers: {})
49
+ raise(
50
+ ActionNotImplementedError,
51
+ 'webhook does not implement GET show action'
52
+ )
53
+ end
54
+ # rubocop:enable Lint/UnusedMethodArgument
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openpix/ruby_sdk/resources/charge'
4
+ require 'openpix/ruby_sdk/resources/customer'
5
+ require 'openpix/ruby_sdk/resources/payment'
6
+ require 'openpix/ruby_sdk/resources/refund'
7
+ require 'openpix/ruby_sdk/resources/subscription'
8
+ require 'openpix/ruby_sdk/resources/webhook'
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openpix
4
+ module RubySdk
5
+ VERSION = '1.0.0'
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openpix/ruby_sdk/version'
4
+ require 'openpix/ruby_sdk/client'
5
+
6
+ module Openpix
7
+ # Main module
8
+ module RubySdk
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,215 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: openpix-ruby_sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Erick Takeshi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-06-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '6.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '6.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.7'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 2.7.4
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '2.7'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 2.7.4
47
+ - !ruby/object:Gem::Dependency
48
+ name: faraday-httpclient
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 2.0.1
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '2.0'
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 2.0.1
67
+ - !ruby/object:Gem::Dependency
68
+ name: pry
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: rack
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '3.0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '3.0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: rake
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ - !ruby/object:Gem::Dependency
110
+ name: rspec
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '3.12'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '3.12'
123
+ - !ruby/object:Gem::Dependency
124
+ name: rubocop
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '1.50'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '1.50'
137
+ - !ruby/object:Gem::Dependency
138
+ name: webrick
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '1.8'
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - "~>"
149
+ - !ruby/object:Gem::Version
150
+ version: '1.8'
151
+ - !ruby/object:Gem::Dependency
152
+ name: yard
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - "~>"
156
+ - !ruby/object:Gem::Version
157
+ version: 0.9.34
158
+ type: :development
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - "~>"
163
+ - !ruby/object:Gem::Version
164
+ version: 0.9.34
165
+ description: Ruby SDK for OpenPix/Woovi API
166
+ email:
167
+ - erick.tmr@outlook.com
168
+ executables: []
169
+ extensions: []
170
+ extra_rdoc_files:
171
+ - README.md
172
+ - CHANGELOG.md
173
+ files:
174
+ - CHANGELOG.md
175
+ - README.md
176
+ - lib/openpix/ruby_sdk.rb
177
+ - lib/openpix/ruby_sdk/api_body_formatter.rb
178
+ - lib/openpix/ruby_sdk/api_response.rb
179
+ - lib/openpix/ruby_sdk/client.rb
180
+ - lib/openpix/ruby_sdk/http_client.rb
181
+ - lib/openpix/ruby_sdk/resources.rb
182
+ - lib/openpix/ruby_sdk/resources/charge.rb
183
+ - lib/openpix/ruby_sdk/resources/customer.rb
184
+ - lib/openpix/ruby_sdk/resources/payment.rb
185
+ - lib/openpix/ruby_sdk/resources/refund.rb
186
+ - lib/openpix/ruby_sdk/resources/resource.rb
187
+ - lib/openpix/ruby_sdk/resources/subscription.rb
188
+ - lib/openpix/ruby_sdk/resources/webhook.rb
189
+ - lib/openpix/ruby_sdk/version.rb
190
+ homepage: https://github.com/Open-Pix/ruby-sdk
191
+ licenses: []
192
+ metadata:
193
+ homepage_uri: https://github.com/Open-Pix/ruby-sdk
194
+ source_code_uri: https://github.com/Open-Pix/ruby-sdk
195
+ changelog_uri: https://github.com/Open-Pix/ruby-sdk/blob/main/CHANGELOG.md
196
+ post_install_message:
197
+ rdoc_options: []
198
+ require_paths:
199
+ - lib
200
+ required_ruby_version: !ruby/object:Gem::Requirement
201
+ requirements:
202
+ - - ">="
203
+ - !ruby/object:Gem::Version
204
+ version: 2.6.0
205
+ required_rubygems_version: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
210
+ requirements: []
211
+ rubygems_version: 3.4.10
212
+ signing_key:
213
+ specification_version: 4
214
+ summary: Ruby SDK for OpenPix/Woovi API
215
+ test_files: []