ethikdo 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 69e3c079fa419a6f528b987b6fd27532bbe32c13fc2edf835a2935b00d57e306
4
+ data.tar.gz: 36ba7a4fff07e5be5122067fda892a6dd2075c992f1f42e05ebb441e63773cb2
5
+ SHA512:
6
+ metadata.gz: 81e308089d0537a5bf6f9ee25ac3820beb314b5b9ab1b64bde9b9aa11352008ed48439c526f40216b298a5ce9616e46bb8d0d149ce176e770e24e8b2eca078cc
7
+ data.tar.gz: f3b88b0ebe7307840a433e584557f28962c6e38b7392d25542cbbdd3c8b942f06ca5515d4a985dea0a50e50658cfc4ae406900a6e0df3c8ca3d75789cab74a0a
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.0
6
+ before_install: gem install bundler -v 2.1.4
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,110 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ethikdo (0.0.1)
5
+ httparty (~> 0.16.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ actionpack (6.0.2.2)
11
+ actionview (= 6.0.2.2)
12
+ activesupport (= 6.0.2.2)
13
+ rack (~> 2.0, >= 2.0.8)
14
+ rack-test (>= 0.6.3)
15
+ rails-dom-testing (~> 2.0)
16
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
17
+ actionview (6.0.2.2)
18
+ activesupport (= 6.0.2.2)
19
+ builder (~> 3.1)
20
+ erubi (~> 1.4)
21
+ rails-dom-testing (~> 2.0)
22
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
23
+ activesupport (6.0.2.2)
24
+ concurrent-ruby (~> 1.0, >= 1.0.2)
25
+ i18n (>= 0.7, < 2)
26
+ minitest (~> 5.1)
27
+ tzinfo (~> 1.1)
28
+ zeitwerk (~> 2.2)
29
+ addressable (2.7.0)
30
+ public_suffix (>= 2.0.2, < 5.0)
31
+ builder (3.2.4)
32
+ concurrent-ruby (1.1.6)
33
+ crack (0.4.3)
34
+ safe_yaml (~> 1.0.0)
35
+ crass (1.0.6)
36
+ diff-lcs (1.3)
37
+ erubi (1.9.0)
38
+ generator_spec (0.9.4)
39
+ activesupport (>= 3.0.0)
40
+ railties (>= 3.0.0)
41
+ hashdiff (1.0.0)
42
+ httparty (0.16.4)
43
+ mime-types (~> 3.0)
44
+ multi_xml (>= 0.5.2)
45
+ i18n (1.8.2)
46
+ concurrent-ruby (~> 1.0)
47
+ loofah (2.5.0)
48
+ crass (~> 1.0.2)
49
+ nokogiri (>= 1.5.9)
50
+ method_source (1.0.0)
51
+ mime-types (3.3.1)
52
+ mime-types-data (~> 3.2015)
53
+ mime-types-data (3.2019.1009)
54
+ mini_portile2 (2.4.0)
55
+ minitest (5.14.0)
56
+ multi_xml (0.6.0)
57
+ nokogiri (1.10.9)
58
+ mini_portile2 (~> 2.4.0)
59
+ public_suffix (4.0.3)
60
+ rack (2.2.2)
61
+ rack-test (1.1.0)
62
+ rack (>= 1.0, < 3)
63
+ rails-dom-testing (2.0.3)
64
+ activesupport (>= 4.2.0)
65
+ nokogiri (>= 1.6)
66
+ rails-html-sanitizer (1.3.0)
67
+ loofah (~> 2.3)
68
+ railties (6.0.2.2)
69
+ actionpack (= 6.0.2.2)
70
+ activesupport (= 6.0.2.2)
71
+ method_source
72
+ rake (>= 0.8.7)
73
+ thor (>= 0.20.3, < 2.0)
74
+ rake (12.3.3)
75
+ rspec (3.9.0)
76
+ rspec-core (~> 3.9.0)
77
+ rspec-expectations (~> 3.9.0)
78
+ rspec-mocks (~> 3.9.0)
79
+ rspec-core (3.9.1)
80
+ rspec-support (~> 3.9.1)
81
+ rspec-expectations (3.9.0)
82
+ diff-lcs (>= 1.2.0, < 2.0)
83
+ rspec-support (~> 3.9.0)
84
+ rspec-mocks (3.9.1)
85
+ diff-lcs (>= 1.2.0, < 2.0)
86
+ rspec-support (~> 3.9.0)
87
+ rspec-support (3.9.2)
88
+ safe_yaml (1.0.5)
89
+ thor (1.0.1)
90
+ thread_safe (0.3.6)
91
+ tzinfo (1.2.7)
92
+ thread_safe (~> 0.1)
93
+ webmock (3.8.2)
94
+ addressable (>= 2.3.6)
95
+ crack (>= 0.3.2)
96
+ hashdiff (>= 0.4.0, < 2.0.0)
97
+ zeitwerk (2.3.0)
98
+
99
+ PLATFORMS
100
+ ruby
101
+
102
+ DEPENDENCIES
103
+ ethikdo!
104
+ generator_spec (~> 0.9)
105
+ rake (~> 12)
106
+ rspec (~> 3.2)
107
+ webmock (~> 3)
108
+
109
+ BUNDLED WITH
110
+ 2.1.4
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Benoit Baumann
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,202 @@
1
+ # Ethikdo
2
+
3
+ This gem provides an easy way to manage transactions for Ethi'kdo card holders through the Ethi'kdo v1 REST API.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'ethikdo'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install ethikdo
20
+
21
+ ## Usage
22
+
23
+ __Configuration__
24
+
25
+ The gem needs to be configured with your private API key. To do so, execute:
26
+
27
+ ```
28
+ rails generate ethikdo:install
29
+ ```
30
+
31
+ This will generate a file named `ethikdo.rb` in `config/initializers/` with the following content:
32
+
33
+ ```ruby
34
+ Ethikdo.configure do |config|
35
+ config.api_key = ENV["ETHIKDO_API_KEY"]
36
+ config.environment = Rails.env.production? ? :production : :development
37
+ end
38
+ ```
39
+
40
+ Now, set up your private key as an environment variable in your `.env` file:
41
+
42
+ ```
43
+ ETHIKDO_API_KEY = "Token XXXXXXX"
44
+ ```
45
+
46
+ The gem can be configured for two environments: _production_ and _development_. By default, the gem's environment is set to _production_ if Rails is in _production_, else it is set to _development_.
47
+
48
+ In _development_, the requests are sent to a test API provided by Ethi'kdo. The test API's url is:
49
+ ```
50
+ https://recette.ethikdo.co/api/v1/
51
+ ```
52
+
53
+ In _production_, the requests are sent to the real API:
54
+ ```
55
+ https://www.ethikdo.co/api/v1
56
+ ```
57
+
58
+
59
+ __Capture a paiement__
60
+
61
+ The first step to capture a paiement is to obtain a capture token. This is done through the `Ethikdo::Provision` class and requires the card's number (16 digits) and card's secret key (3 digits):
62
+
63
+ ```ruby
64
+ provision = Ethikdo::Provision.create(
65
+ card_number: card_number,
66
+ card_crypto: card_crypto
67
+ )
68
+ ```
69
+ If the card's credentials are correct, an `Ethikdo::Provision` object is returned:
70
+
71
+ ```ruby
72
+ # Ethikdo::Provision:0x0000555a80009698
73
+ @capture_token = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
74
+ @card_number = "1234123412341234",
75
+ @card_value = 500000,
76
+ @date_created = "2020-04-16T16:36:46.128007+02:00",
77
+ @date_used = nil,
78
+ @url = "https://recette.ethikdo.co/api/v1/provisions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/"
79
+ ```
80
+
81
+ Once you have obtained the capture token, you can now use the `Ethikdo::Transaction` class to capture the paiement:
82
+
83
+ ```ruby
84
+ transaction = Ethikdo::Transaction.create(
85
+ capture_token: capture_token,
86
+ amount_requested: order.total_price_cents,
87
+ amount_purchased: order.total_price_cents,
88
+ transaction_id: order.id,
89
+ customer_email: nil
90
+ )
91
+ ```
92
+
93
+ If the transaction succeeds, an `Ethikdo::Transaction` object is returned:
94
+
95
+ ```ruby
96
+ # Ethikdo::Transaction:0x0000555a82216f38
97
+ @amount_debited = 100000,
98
+ @amount_purchased = 100000,
99
+ @cancelled = false,
100
+ @card_number = "1234123412341234",
101
+ @date = "2020-04-16T15:25:56.451488Z",
102
+ @transaction_id = "1",
103
+ @url = "https://recette.ethikdo.co/api/v1/sales/1/" #/1 being the transaction id
104
+ ```
105
+
106
+ __Cancel a transaction__
107
+
108
+ You can cancel a transaction through the `Ethikdo::Transaction` class:
109
+
110
+ ```ruby
111
+ Ethikdo::Transaction.cancel(transaction_id: transaction_id)
112
+ ```
113
+
114
+ If the cancellation is successful, an `Ethikdo::Transaction` object is returned with a success message and the amount refunded:
115
+
116
+ ```ruby
117
+ # Ethikdo::Transaction:0x0000555a846ccb48
118
+ @message = "La vente a bien été annulée et la carte a été recréditée de 1000,00€.",
119
+ @refund_amount = 100000
120
+ ```
121
+
122
+ __List the provisions and transactions associated to your API key__
123
+
124
+ List all the provisions:
125
+ ```ruby
126
+ Ethikdo::Provision.all
127
+ ```
128
+
129
+ Example of an `Ethikdo::Provision` object returned:
130
+
131
+ ```ruby
132
+ # Ethikdo::Provision:0x0000555a82909390
133
+ @count = 1,
134
+ @next = nil,
135
+ @previous = nil,
136
+ @results =
137
+ [
138
+ {
139
+ "url"=>"https://recette.ethikdo.co/api/v1/provisions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/",
140
+ "capture_token"=>"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
141
+ "card_number"=>"1234123412341234",
142
+ "card_value"=>400000,
143
+ "date_created"=>"2020-04-16T16:36:46.128007+02:00",
144
+ "date_used"=>"2020-04-16T15:25:56.451488Z"
145
+ }
146
+ ]
147
+ ```
148
+
149
+ Similarly, list all the transactions:
150
+
151
+ ```ruby
152
+ Ethikdo::Transaction.all
153
+ ```
154
+
155
+ Example of an `Ethikdo::Transaction` object returned:
156
+
157
+ ```ruby
158
+ # Ethikdo::Transaction:0x0000555a835d68c0
159
+ @count = 1,
160
+ @next = nil,
161
+ @previous = nil,
162
+ @results =
163
+ [
164
+ {
165
+ "url"=>"https://recette.ethikdo.co/api/v1/sales/1/",
166
+ "transaction_id"=>"1",
167
+ "customer_email"=>nil,
168
+ "card_number"=>"1234123412341234",
169
+ "amount_purchased"=>100000,
170
+ "amount_debited"=>100000,
171
+ "cancelled"=>false,
172
+ "date"=>"2020-04-16T15:25:56.451488Z"
173
+ }
174
+ ]
175
+ ```
176
+
177
+ __Errors__
178
+
179
+ If a request returns an error (invalid card number, amount requested greater than card value, invalid capture token, etc.), an `Ethikdo::Error` is raised. This can be simply handled by a `begin/rescue` block:
180
+
181
+ ```ruby
182
+ begin
183
+ Ethikdo::transaction.cancel(transaction_id: 1)
184
+ rescue Ethikdo::Error => e
185
+ e.inspect
186
+ end
187
+ ```
188
+
189
+ ## Contributing
190
+
191
+ 1. Fork it
192
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
193
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
194
+ 4. Push to the branch (`git push origin my-new-feature`)
195
+ 5. Create new Pull Request
196
+
197
+ Don't forget to add tests and run rspec before creating a pull request :)
198
+
199
+
200
+ ## License
201
+
202
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ethikdo"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,31 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'ethikdo/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "ethikdo"
8
+ s.version = Ethikdo::VERSION
9
+ s.authors = ["Benoit Baumann", "Kevin Chavanne"]
10
+ s.email = ["baumann.benoit@gmail.com", "kevin.chavanne@gmail.com"]
11
+
12
+ s.summary = "A ruby wrapper for Ethikdo REST API "
13
+ s.description = "This gem provides an easy way to manage transactions for Ethi'kdo card holders through the Ethi'kdo REST API"
14
+ s.homepage = "https://github.com/wedressfair/ethikdo"
15
+ s.license = "MIT"
16
+ s.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
17
+
18
+ s.metadata["homepage_uri"] = s.homepage
19
+ s.metadata["source_code_uri"] = "https://github.com/wedressfair/ethikdo"
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+ s.require_paths = ["lib"]
25
+
26
+ s.add_development_dependency "rspec", "~> 3.2"
27
+ s.add_development_dependency 'rake', '~> 12'
28
+ s.add_development_dependency 'webmock', '~> 3'
29
+ s.add_development_dependency 'generator_spec', '~> 0.9'
30
+ s.add_runtime_dependency 'httparty', '~> 0.16.2'
31
+ end
@@ -0,0 +1,22 @@
1
+ require 'ethikdo/configuration'
2
+ require 'ethikdo/provision'
3
+ require 'ethikdo/transaction'
4
+ require 'ethikdo/version'
5
+
6
+ module Ethikdo
7
+ class << self
8
+ attr_accessor :configuration
9
+ end
10
+
11
+ def self.configuration
12
+ @configuration ||= Configuration.new
13
+ end
14
+
15
+ def self.reset_configuration
16
+ @configuration = Configuration.new
17
+ end
18
+
19
+ def self.configure
20
+ yield(configuration)
21
+ end
22
+ end
@@ -0,0 +1,65 @@
1
+ require_relative 'error'
2
+ require 'httparty'
3
+
4
+ module Ethikdo
5
+ class BaseModel
6
+ def initialize(attributes = {})
7
+ attributes.each do |key, value|
8
+ m = "#{key}=".to_sym
9
+ send(m, value) if respond_to?(m)
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ BASE_TEST_URL = "https://recette.ethikdo.co/api/v1"
16
+ BASE_URL = "https://www.ethikdo.co/api/v1"
17
+
18
+ def self.api_key
19
+ Ethikdo::configuration.api_key
20
+ end
21
+
22
+ def self.execute(method, path, options = {})
23
+ begin
24
+ response = request(method, path, options)
25
+ rescue *Error::NET_HTTP_ERRORS => err
26
+ raise ConnectionError.new, err.message
27
+ end
28
+
29
+ case response.code
30
+ when 200..299
31
+ response
32
+ when 400
33
+ raise BadRequestError.new(response)
34
+ when 401
35
+ raise AuthenticationError.new(response)
36
+ when 404
37
+ raise NotFoundError.new(response)
38
+ when 400..499
39
+ raise ResponseError.new(response)
40
+ when 500
41
+ raise InternalServerError.new(response)
42
+ when 500..599
43
+ raise ServerError.new(response)
44
+ end
45
+ end
46
+
47
+ def self.request(method, path, options = {})
48
+ HTTParty.send(method, base_url + path, base_options.merge(options))
49
+ end
50
+
51
+ def self.base_url
52
+ Ethikdo::configuration.environment == :production ? BASE_URL : BASE_TEST_URL
53
+ end
54
+
55
+ def self.base_options
56
+ {
57
+ format: :json,
58
+ headers: {
59
+ 'Accept' => 'application/json',
60
+ 'Authorization' => api_key
61
+ }
62
+ }
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,16 @@
1
+ module Ethikdo
2
+ class Configuration
3
+ attr_accessor :api_key
4
+ attr_reader :environment
5
+
6
+ def initialize
7
+ @api_key = nil
8
+ @environment = :production
9
+ end
10
+
11
+ def environment=(env)
12
+ env = env.to_sym
13
+ @environment = [:production, :development].include?(env)? env : nil
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,84 @@
1
+ require 'net/http'
2
+
3
+ module Ethikdo
4
+ class Error < StandardError
5
+ NET_HTTP_ERRORS = [
6
+ EOFError,
7
+ Errno::ECONNABORTED,
8
+ Errno::ECONNREFUSED,
9
+ Errno::ECONNRESET,
10
+ Errno::EHOSTUNREACH,
11
+ Errno::EINVAL,
12
+ Errno::ENETUNREACH,
13
+ Net::HTTPBadResponse,
14
+ Net::HTTPHeaderSyntaxError,
15
+ Net::ProtocolError,
16
+ Net::OpenTimeout,
17
+ Net::ReadTimeout,
18
+ SocketError,
19
+ Zlib::GzipFile::Error,
20
+ OpenSSL::SSL::SSLError
21
+ ]
22
+
23
+ attr_reader :http_response
24
+
25
+ def initialize(response = nil)
26
+ @http_response = response
27
+ super(build_error_message)
28
+ end
29
+
30
+ def http_request
31
+ http_response.request
32
+ end
33
+
34
+ private
35
+
36
+ def build_error_message
37
+ return nil if http_response.nil?
38
+
39
+ message = "#{http_request_method} "
40
+ message << "#{http_request.path} : "
41
+ message << "#{http_response.code} - "
42
+ message << response_message unless response_message.nil?
43
+ message
44
+ end
45
+
46
+ def http_request_method
47
+ http_request.http_method.name.split('::').last.upcase
48
+ end
49
+
50
+ def response_message
51
+ content_type = http_response.headers['Content-Type']
52
+ if content_type && content_type.start_with?('application/json')
53
+ http_response.parsed_response['message'] || http_response.parsed_response['detail']
54
+ else
55
+ net_http_response = http_response.response
56
+ "#{net_http_response.code} #{net_http_response.message}"
57
+ end
58
+ end
59
+ end
60
+
61
+ # Raised on errors in the 400-499 range
62
+ class ResponseError < Error; end
63
+
64
+ # Raised when the API returns a 400 HTTP status code
65
+ class BadRequestError < ResponseError; end
66
+
67
+ # Raised when the API returns a 401 HTTP status code
68
+ class AuthenticationError < ResponseError; end
69
+
70
+ # Raised when the API returns a 402 HTTP status code
71
+ class PaymentRequiredError < ResponseError; end
72
+
73
+ # Raised when the API returns a 404 HTTP status code
74
+ class NotFoundError < ResponseError; end
75
+
76
+ # Raised on errors in the 500-599 range
77
+ class ServerError < Error; end
78
+
79
+ # Raised when the API returns a 500 HTTP status code
80
+ class InternalServerError < ServerError; end
81
+
82
+ # Raised when we can't establish a connection to the API or if reading the reponse times out
83
+ class ConnectionError < Error; end
84
+ end
@@ -0,0 +1,29 @@
1
+ require_relative 'base_model'
2
+
3
+ module Ethikdo
4
+ class Provision < BaseModel
5
+ attr_accessor :card_number
6
+ attr_accessor :capture_token
7
+ attr_accessor :card_value
8
+ attr_accessor :date_created
9
+ attr_accessor :date_used
10
+ attr_accessor :url
11
+ attr_accessor :status_code
12
+ attr_accessor :error_code
13
+ attr_accessor :message
14
+ attr_accessor :count
15
+ attr_accessor :next
16
+ attr_accessor :previous
17
+ attr_accessor :results
18
+
19
+ def self.create(card_number:, card_crypto:)
20
+ response = execute("post", '/provisions/', body: { card_number: card_number, card_crypto: card_crypto })
21
+ self.new(response.parsed_response)
22
+ end
23
+
24
+ def self.all
25
+ response = execute('get', '/provisions/')
26
+ self.new(response.parsed_response)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,41 @@
1
+ require_relative 'base_model'
2
+
3
+ module Ethikdo
4
+ class Transaction < BaseModel
5
+ attr_accessor :url
6
+ attr_accessor :transaction_id
7
+ attr_accessor :card_number
8
+ attr_accessor :amount_purchased
9
+ attr_accessor :amount_debited
10
+ attr_accessor :cancelled
11
+ attr_accessor :date
12
+ attr_accessor :refund_amount
13
+ attr_accessor :message
14
+ attr_accessor :count
15
+ attr_accessor :next
16
+ attr_accessor :previous
17
+ attr_accessor :results
18
+ attr_accessor :customer_email
19
+
20
+ def self.create(capture_token:, amount_requested:, amount_purchased: 0, transaction_id:, customer_email: nil)
21
+ response = execute('post', '/sales/', body: {
22
+ capture_token: capture_token,
23
+ amount_requested: amount_requested,
24
+ amount_purchased: amount_purchased,
25
+ transaction_id: transaction_id,
26
+ customer_email: customer_email
27
+ })
28
+ self.new(response.parsed_response)
29
+ end
30
+
31
+ def self.cancel(transaction_id:)
32
+ response = execute('get', "/sales/#{transaction_id}/cancel")
33
+ self.new(response.parsed_response)
34
+ end
35
+
36
+ def self.all
37
+ response = execute('get', '/sales/')
38
+ self.new(response.parsed_response)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module Ethikdo
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails/generators'
2
+
3
+ module Ethikdo
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ desc "Creates an initializer file at config/initializers"
7
+ source_root File.expand_path('../templates', __dir__)
8
+
9
+ def create_initializer_file
10
+ copy_file "initializer.rb", "config/initializers/ethikdo.rb"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ Ethikdo.configure do |config|
2
+ config.api_key = ENV["ETHIKDO_API_KEY"]
3
+ config.environment = Rails.env.production? ? :production : :development
4
+ end
@@ -0,0 +1,34 @@
1
+ describe Ethikdo::BaseModel do
2
+ describe '.execute' do
3
+ it 'sends the request with the correct headers' do
4
+ stub_request(:get, /test/)
5
+ Ethikdo::configuration.api_key = '1234'
6
+
7
+ Ethikdo::BaseModel.execute('get', '/test/')
8
+
9
+ expect(WebMock).to have_requested(
10
+ :get,
11
+ 'https://www.ethikdo.co/api/v1/test/'
12
+ ).with(headers: {
13
+ 'Accept' => 'application/json',
14
+ 'Authorization' => '1234'
15
+ })
16
+ end
17
+
18
+ it 'raises a custom error when no api key is submitted' do
19
+ stub_request(:get, /test/).to_return(read_http_fixture('forbidden/no_token.http'))
20
+
21
+ expect do
22
+ Ethikdo::BaseModel.execute('get', '/test/')
23
+ end.to raise_error(Ethikdo::ResponseError)
24
+ end
25
+
26
+ it 'raises a custom when a wrong api key is submitted' do
27
+ stub_request(:get, /test/).to_return(read_http_fixture('forbidden/wrong_token.http'))
28
+
29
+ expect do
30
+ Ethikdo::BaseModel.execute('get', '/test/')
31
+ end.to raise_error(Ethikdo::ResponseError)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ describe Ethikdo do
2
+ after(:all) do
3
+ Ethikdo.reset_configuration
4
+ end
5
+
6
+ it "has a version number" do
7
+ expect(Ethikdo::VERSION).not_to be nil
8
+ end
9
+
10
+ describe Ethikdo::Configuration do
11
+ it 'has a configurable api key' do
12
+ Ethikdo.configuration.api_key = "42"
13
+ expect(Ethikdo.configuration.api_key).to eq("42")
14
+ end
15
+
16
+ it 'accepts only 2 values for its instance variable "environment": "production" and "development"' do
17
+ Ethikdo.configuration.environment = :development
18
+ expect(Ethikdo.configuration.environment).to eq(:development)
19
+
20
+ Ethikdo.configuration.environment = :foo
21
+ expect(Ethikdo.configuration.environment).to eq(nil)
22
+
23
+ Ethikdo.configuration.environment = :production
24
+ expect(Ethikdo.configuration.environment).to eq(:production)
25
+ end
26
+
27
+ it 'has different base url for the development and production environment' do
28
+ Ethikdo.configuration.environment = :development
29
+ expect(Ethikdo::BaseModel.base_url).to eq(Ethikdo::BaseModel::BASE_TEST_URL)
30
+
31
+ Ethikdo.configuration.environment = :production
32
+ expect(Ethikdo::BaseModel.base_url).to eq(Ethikdo::BaseModel::BASE_URL)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,8 @@
1
+ HTTP 403 Forbidden
2
+ Allow: GET, POST, HEAD, OPTIONS
3
+ Content-Type: application/json
4
+ Vary: Accept
5
+
6
+ {
7
+ "detail": "Informations d'authentification non fournies."
8
+ }
@@ -0,0 +1,8 @@
1
+ HTTP 403 Forbidden
2
+ Allow: GET, POST, HEAD, OPTIONS
3
+ Content-Type: application/json
4
+ Vary: Accept
5
+
6
+ {
7
+ "detail": "Token non valide."
8
+ }
@@ -0,0 +1,11 @@
1
+ HTTP/1.1 200
2
+ Content-Type: application/json; charset=utf-8
3
+
4
+ {
5
+ "url": "https://recette.ethikdo.co/api/v1/provisions/2faac91c-ffec-4329-b851-8695020faeee/",
6
+ "capture_token": "2faac91c-ffec-4329-b851-8695020faeee",
7
+ "card_number": "1234123412341234",
8
+ "card_value": 500000,
9
+ "date_created": "2020-02-27T12:30:58.760332+01:00",
10
+ "date_used": null
11
+ }
@@ -0,0 +1,26 @@
1
+ HTTP/1.1 200
2
+ Content-Type: application/json; charset=utf-8
3
+
4
+ {
5
+ "count": 2,
6
+ "next": null,
7
+ "previous": null,
8
+ "results": [
9
+ {
10
+ "url": "https://recette.ethikdo.co/api/v1/provisions/2faac91c-ffec-4329-b851-8695020faeee/",
11
+ "capture_token": "2faac91c-ffec-4329-b851-8695020faeee",
12
+ "card_number": "1234123412341234",
13
+ "card_value": 500000,
14
+ "date_created": "2020-02-27T12:30:58.760332+01:00",
15
+ "date_used": null
16
+ },
17
+ {
18
+ "url": "https://recette.ethikdo.co/api/v1/provisions/f93f0deb-1bdf-4c40-a19f-8bacf831f529/",
19
+ "capture_token": "f93f0deb-1bdf-4c40-a19f-8bacf831f529",
20
+ "card_number": "1234123412341234",
21
+ "card_value": 496000,
22
+ "date_created": "2020-02-27T11:06:34.285773+01:00",
23
+ "date_used": null
24
+ }
25
+ ]
26
+ }
@@ -0,0 +1,7 @@
1
+ HTTP/1.1 200
2
+ Content-Type: application/json; charset=utf-8
3
+
4
+ {
5
+ "message": "La vente a bien été annulée et la carte a été recréditée de 10,00&nbsp;€.",
6
+ "refund_amount": 1000
7
+ }
@@ -0,0 +1,13 @@
1
+ HTTP/1.1 200
2
+ Content-Type: application/json; charset=utf-8
3
+
4
+ {
5
+ "url": "https://recette.ethikdo.co/api/v1/sales/1/",
6
+ "transaction_id": "1",
7
+ "customer_email": null,
8
+ "card_number": "1010101010101010",
9
+ "amount_purchased": 1000,
10
+ "amount_debited": 1000,
11
+ "cancelled": false,
12
+ "date": "2020-02-27T11:38:19.684349Z"
13
+ }
@@ -0,0 +1,40 @@
1
+ HTTP/1.1 200
2
+ Content-Type: application/json; charset=utf-8
3
+
4
+ {
5
+ "count": 3,
6
+ "next": null,
7
+ "previous": null,
8
+ "results": [
9
+ {
10
+ "url": "https://recette.ethikdo.co/api/v1/sales/113/",
11
+ "transaction_id": "3",
12
+ "customer_email": null,
13
+ "card_number": "1234123412341234",
14
+ "amount_purchased": 0,
15
+ "amount_debited": 2000,
16
+ "cancelled": false,
17
+ "date": "2020-02-27T09:47:24.711443Z"
18
+ },
19
+ {
20
+ "url": "https://recette.ethikdo.co/api/v1/sales/112/",
21
+ "transaction_id": "2",
22
+ "customer_email": null,
23
+ "card_number": "1234123412341234",
24
+ "amount_purchased": 0,
25
+ "amount_debited": 2000,
26
+ "cancelled": false,
27
+ "date": "2020-02-27T09:25:21.702039Z"
28
+ },
29
+ {
30
+ "url": "https://recette.ethikdo.co/api/v1/sales/111/",
31
+ "transaction_id": "1",
32
+ "customer_email": null,
33
+ "card_number": "1234123412341234",
34
+ "amount_purchased": 0,
35
+ "amount_debited": 2000,
36
+ "cancelled": true,
37
+ "date": "2020-02-27T09:18:40.351488Z"
38
+ }
39
+ ]
40
+ }
@@ -0,0 +1,16 @@
1
+ describe Ethikdo::Generators::InstallGenerator, type: :generator do
2
+ destination File.expand_path('../tmp', __FILE__)
3
+
4
+ before(:all) do
5
+ prepare_destination
6
+ run_generator
7
+ end
8
+
9
+ after(:all) do
10
+ FileUtils.rm_rf destination_root
11
+ end
12
+
13
+ it "creates correctly the initializer file" do
14
+ assert_file "config/initializers/ethikdo.rb"
15
+ end
16
+ end
@@ -0,0 +1,54 @@
1
+ describe Ethikdo::Provision do
2
+ describe '.all' do
3
+ before do
4
+ stub_request(:get, /provisions/).to_return(read_http_fixture('provisions/get_provisions_success.http'))
5
+ end
6
+
7
+ it 'builds the correct request' do
8
+ Ethikdo::Provision.all
9
+
10
+ expect(WebMock).to have_requested(
11
+ :get,
12
+ 'https://www.ethikdo.co/api/v1/provisions/'
13
+ )
14
+ end
15
+
16
+ it 'returns the correct response' do
17
+ provisions = Ethikdo::Provision.all
18
+
19
+ expect(provisions).to be_a(Ethikdo::Provision)
20
+ expect(provisions.count).to eq(2)
21
+ expect(provisions.results[0]['card_number']).to eq('1234123412341234')
22
+ end
23
+ end
24
+
25
+ describe '.create' do
26
+ before do
27
+ Ethikdo::configuration.api_key = '1234'
28
+ stub_request(:post, /provisions/).to_return(read_http_fixture('provisions/create_success.http'))
29
+ end
30
+
31
+ it 'builds the correct request' do
32
+ Ethikdo::Provision.create(card_number: 1234123412341234, card_crypto: 123)
33
+
34
+ expect(WebMock).to have_requested(
35
+ :post,
36
+ 'https://www.ethikdo.co/api/v1/provisions/'
37
+ ).with(headers: {
38
+ 'Accept' => 'application/json',
39
+ 'Authorization' => '1234',
40
+ }, body: {
41
+ 'card_number' => '1234123412341234',
42
+ 'card_crypto' => '123'
43
+ })
44
+ end
45
+
46
+ it 'returns the correct response' do
47
+ provision = Ethikdo::Provision.create(card_number: 1234123412341234, card_crypto: 123)
48
+
49
+ expect(provision).to be_a(Ethikdo::Provision)
50
+ expect(provision.card_number).to eq('1234123412341234')
51
+ expect(provision.card_value).to eq(500000)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path("../../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require "bundler/setup"
5
+ require "ethikdo"
6
+ require "generator_spec"
7
+ require 'generators/ethikdo/install_generator'
8
+
9
+ RSpec.configure do |config|
10
+ config.example_status_persistence_file_path = ".rspec_status"
11
+
12
+ config.expect_with :rspec do |expectations|
13
+ expectations.syntax = :expect
14
+ end
15
+
16
+ config.mock_with :rspec do |mocks|
17
+ mocks.syntax = :expect
18
+ end
19
+ end
20
+
21
+ unless defined?(SPEC_ROOT)
22
+ SPEC_ROOT = File.expand_path('../', __FILE__)
23
+ end
24
+
25
+ Dir[File.join(SPEC_ROOT, 'support/**/*.rb')].each { |f| require f }
@@ -0,0 +1,15 @@
1
+ module RSpecSupportHelpers
2
+
3
+ def http_fixture(*names)
4
+ File.join(SPEC_ROOT, 'http_fixtures', *names)
5
+ end
6
+
7
+ def read_http_fixture(*names)
8
+ File.read(http_fixture(*names))
9
+ end
10
+
11
+ end
12
+
13
+ RSpec.configure do |config|
14
+ config.include RSpecSupportHelpers
15
+ end
@@ -0,0 +1,11 @@
1
+ require 'webmock/rspec'
2
+
3
+ RSpec.configure do |config|
4
+ config.before(:suite) do
5
+ WebMock.disable_net_connect!
6
+ end
7
+
8
+ config.after(:suite) do
9
+ WebMock.allow_net_connect!
10
+ end
11
+ end
@@ -0,0 +1,84 @@
1
+ describe Ethikdo::Transaction do
2
+ describe '.all' do
3
+ before do
4
+ stub_request(:get, /sales/).to_return(read_http_fixture('transactions/get_transactions_success.http'))
5
+ end
6
+
7
+ it 'builds the correct request' do
8
+ Ethikdo::Transaction.all
9
+
10
+ expect(WebMock).to have_requested(
11
+ :get,
12
+ 'https://www.ethikdo.co/api/v1/sales/'
13
+ )
14
+ end
15
+
16
+ it 'returns the correct response' do
17
+ transactions = Ethikdo::Transaction.all
18
+
19
+ expect(transactions).to be_a(Ethikdo::Transaction)
20
+ expect(transactions.count).to eq(3)
21
+ expect(transactions.results[0]['card_number']).to eq('1234123412341234')
22
+ end
23
+ end
24
+
25
+ describe '.create' do
26
+ before do
27
+ Ethikdo::configuration.api_key = '1234'
28
+ stub_request(:post, /sales/).to_return(read_http_fixture('transactions/create_success.http'))
29
+ end
30
+
31
+ it 'builds the correct request' do
32
+ Ethikdo::Transaction.create(capture_token: 'foo', amount_requested: 10000, amount_purchased: 10000, transaction_id: 1, customer_email: 'foo@bar.com')
33
+
34
+ expect(WebMock).to have_requested(
35
+ :post,
36
+ 'https://www.ethikdo.co/api/v1/sales/'
37
+ ).with(headers: {
38
+ 'Accept' => 'application/json',
39
+ 'Authorization' => '1234',
40
+ }, body: {
41
+ 'capture_token' => 'foo',
42
+ 'amount_requested' => '10000',
43
+ 'amount_purchased' => '10000',
44
+ 'transaction_id' => '1',
45
+ 'customer_email' => 'foo@bar.com'
46
+ })
47
+ end
48
+
49
+ it 'returns the correct response' do
50
+ transaction = Ethikdo::Transaction.create(capture_token: 'foo', amount_requested: 10000, amount_purchased: 10000, transaction_id: 1)
51
+
52
+ expect(transaction).to be_a(Ethikdo::Transaction)
53
+ expect(transaction.transaction_id).to eq('1')
54
+ expect(transaction.amount_purchased).to eq(1000)
55
+ end
56
+ end
57
+
58
+ describe '.cancel' do
59
+ before do
60
+ Ethikdo::configuration.api_key = '1234'
61
+ stub_request(:get, /sales/).to_return(read_http_fixture('transactions/cancel_success.http'))
62
+ end
63
+
64
+ it 'builds the correct request' do
65
+ Ethikdo::Transaction.cancel(transaction_id: 1)
66
+
67
+ expect(WebMock).to have_requested(
68
+ :get,
69
+ 'https://www.ethikdo.co/api/v1/sales/1/cancel'
70
+ ).with(headers: {
71
+ 'Accept' => 'application/json',
72
+ 'Authorization' => '1234',
73
+ })
74
+ end
75
+
76
+ it 'returns the correct response' do
77
+ transaction = Ethikdo::Transaction.cancel(transaction_id: 1)
78
+
79
+ expect(transaction).to be_a(Ethikdo::Transaction)
80
+ expect(transaction.message).to eq('La vente a bien été annulée et la carte a été recréditée de 10,00&nbsp;€.')
81
+ expect(transaction.refund_amount).to eq(1000)
82
+ end
83
+ end
84
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ethikdo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Benoit Baumann
8
+ - Kevin Chavanne
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2020-04-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '3.2'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '3.2'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '12'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '12'
42
+ - !ruby/object:Gem::Dependency
43
+ name: webmock
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '3'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '3'
56
+ - !ruby/object:Gem::Dependency
57
+ name: generator_spec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '0.9'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.9'
70
+ - !ruby/object:Gem::Dependency
71
+ name: httparty
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: 0.16.2
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: 0.16.2
84
+ description: This gem provides an easy way to manage transactions for Ethi'kdo card
85
+ holders through the Ethi'kdo REST API
86
+ email:
87
+ - baumann.benoit@gmail.com
88
+ - kevin.chavanne@gmail.com
89
+ executables:
90
+ - console
91
+ - setup
92
+ extensions: []
93
+ extra_rdoc_files: []
94
+ files:
95
+ - ".gitignore"
96
+ - ".rspec"
97
+ - ".travis.yml"
98
+ - Gemfile
99
+ - Gemfile.lock
100
+ - LICENSE.txt
101
+ - README.md
102
+ - Rakefile
103
+ - bin/console
104
+ - bin/setup
105
+ - ethikdo.gemspec
106
+ - lib/ethikdo.rb
107
+ - lib/ethikdo/base_model.rb
108
+ - lib/ethikdo/configuration.rb
109
+ - lib/ethikdo/error.rb
110
+ - lib/ethikdo/provision.rb
111
+ - lib/ethikdo/transaction.rb
112
+ - lib/ethikdo/version.rb
113
+ - lib/generators/ethikdo/install_generator.rb
114
+ - lib/generators/templates/initializer.rb
115
+ - spec/base_model_spec.rb
116
+ - spec/ethikdo_spec.rb
117
+ - spec/http_fixtures/forbidden/no_token.http
118
+ - spec/http_fixtures/forbidden/wrong_token.http
119
+ - spec/http_fixtures/provisions/create_success.http
120
+ - spec/http_fixtures/provisions/get_provisions_success.http
121
+ - spec/http_fixtures/transactions/cancel_success.http
122
+ - spec/http_fixtures/transactions/create_success.http
123
+ - spec/http_fixtures/transactions/get_transactions_success.http
124
+ - spec/install_generator_spec.rb
125
+ - spec/provision_spec.rb
126
+ - spec/spec_helper.rb
127
+ - spec/support/helpers.rb
128
+ - spec/support/webmock.rb
129
+ - spec/transaction_spec.rb
130
+ homepage: https://github.com/wedressfair/ethikdo
131
+ licenses:
132
+ - MIT
133
+ metadata:
134
+ homepage_uri: https://github.com/wedressfair/ethikdo
135
+ source_code_uri: https://github.com/wedressfair/ethikdo
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 2.3.0
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubygems_version: 3.1.2
152
+ signing_key:
153
+ specification_version: 4
154
+ summary: A ruby wrapper for Ethikdo REST API
155
+ test_files: []