mandarin-api 0.0.1

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
+ SHA1:
3
+ metadata.gz: 15f0096f101bdda10a4a47882006909f52ef444f
4
+ data.tar.gz: b4fa4f3db47d56941cb6f4e3f5dfd4bed2585c46
5
+ SHA512:
6
+ metadata.gz: 2be9a637c30f3b11e8e22de6de3b0e22c2f3c9816709e23431d26be138aedc65a6c31ad2c8aeca7b0c04cd2a097c4057722f650ab256d0d29f6699d824b9765c
7
+ data.tar.gz: 60c27b365ca7db424245972da36f246ac8bb34605c5008f8384587e6049782be68c1886cd665b842fa625b2c0b3f7a5ac33ab9ce6f79add886b5d17e885e2bee
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ log/*
2
+ !/log/.keep
3
+ /tmp
4
+ #/config/*.yml
5
+ #/config/unicorn.rb
6
+ .idea
7
+ .versions.conf
8
+ public/assets
9
+ public/system
10
+ vendor/bundle
11
+ #!public/favicon.ico
12
+ *.DS_Store
13
+ .env
14
+ rspec_results.html
15
+ backup/.*
16
+ coverage
17
+ .rubocop.yml
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec_helper
3
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec name: 'mandarin-api'
4
+
5
+ group :test do
6
+ gem 'rake'
7
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,99 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mandarin-api (0.0.1)
5
+ dry-configurable (>= 0.1.0, < 1.0)
6
+ rest-client (>= 2.0, < 3.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ addressable (2.4.0)
12
+ ast (2.3.0)
13
+ coderay (1.1.1)
14
+ concurrent-ruby (1.0.2)
15
+ crack (0.4.3)
16
+ safe_yaml (~> 1.0.0)
17
+ diff-lcs (1.2.5)
18
+ domain_name (0.5.20160826)
19
+ unf (>= 0.0.5, < 1.0.0)
20
+ dry-configurable (0.1.7)
21
+ concurrent-ruby (~> 1.0)
22
+ faker (1.6.6)
23
+ i18n (~> 0.5)
24
+ hashdiff (0.3.0)
25
+ http-cookie (1.0.3)
26
+ domain_name (~> 0.5)
27
+ i18n (0.7.0)
28
+ json (1.8.3)
29
+ method_source (0.8.2)
30
+ mime-types (3.1)
31
+ mime-types-data (~> 3.2015)
32
+ mime-types-data (3.2016.0521)
33
+ netrc (0.11.0)
34
+ parser (2.3.1.4)
35
+ ast (~> 2.2)
36
+ powerpack (0.1.1)
37
+ pry (0.10.4)
38
+ coderay (~> 1.1.0)
39
+ method_source (~> 0.8.1)
40
+ slop (~> 3.4)
41
+ pry-doc (0.9.0)
42
+ pry (~> 0.9)
43
+ yard (~> 0.8)
44
+ rainbow (2.1.0)
45
+ rake (11.3.0)
46
+ rdoc (4.2.2)
47
+ json (~> 1.4)
48
+ rest-client (2.0.0)
49
+ http-cookie (>= 1.0.2, < 2.0)
50
+ mime-types (>= 1.16, < 4.0)
51
+ netrc (~> 0.8)
52
+ rspec (3.5.0)
53
+ rspec-core (~> 3.5.0)
54
+ rspec-expectations (~> 3.5.0)
55
+ rspec-mocks (~> 3.5.0)
56
+ rspec-core (3.5.4)
57
+ rspec-support (~> 3.5.0)
58
+ rspec-expectations (3.5.0)
59
+ diff-lcs (>= 1.2.0, < 2.0)
60
+ rspec-support (~> 3.5.0)
61
+ rspec-mocks (3.5.0)
62
+ diff-lcs (>= 1.2.0, < 2.0)
63
+ rspec-support (~> 3.5.0)
64
+ rspec-support (3.5.0)
65
+ rubocop (0.44.1)
66
+ parser (>= 2.3.1.1, < 3.0)
67
+ powerpack (~> 0.1)
68
+ rainbow (>= 1.99.1, < 3.0)
69
+ ruby-progressbar (~> 1.7)
70
+ unicode-display_width (~> 1.0, >= 1.0.1)
71
+ ruby-progressbar (1.8.1)
72
+ safe_yaml (1.0.4)
73
+ slop (3.6.0)
74
+ unf (0.1.4)
75
+ unf_ext
76
+ unf_ext (0.0.7.2)
77
+ unicode-display_width (1.1.1)
78
+ webmock (2.1.0)
79
+ addressable (>= 2.3.6)
80
+ crack (>= 0.3.2)
81
+ hashdiff
82
+ yard (0.9.5)
83
+
84
+ PLATFORMS
85
+ ruby
86
+
87
+ DEPENDENCIES
88
+ faker (>= 1.6, < 1.7)
89
+ mandarin-api!
90
+ pry (~> 0)
91
+ pry-doc (~> 0)
92
+ rake
93
+ rdoc (>= 2.4.2, < 5.0)
94
+ rspec (~> 3.0)
95
+ rubocop (~> 0)
96
+ webmock (~> 2.1)
97
+
98
+ BUNDLED WITH
99
+ 1.12.5
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Bogaevsky
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 all
13
+ 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 THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # mandarin-api-rb
2
+ mandarinpay.com api wrapper for ruby
3
+ [![CodeClimate](https://codeclimate.com/github/vbogaevsky/mandarin-api-rb/badges/gpa.svg)](https://codeclimate.com/github/vbogaevsky/mandarin-api-rb)
4
+ **mandarin-api** provides necessary API to interact with **Mandarin**.
5
+ ##**Usage:**
6
+ To use mandarin-api you will need to specify config file with `merchant_id`, `secret`, and `request_url`.
7
+ ###**Example of config:**
8
+ ```
9
+ MandarinApi.configure do |config|
10
+ config.merchant_id = 123
11
+ config.secret = 'secret'
12
+ config.request_url = 'https://secure.mandarinpay.com'
13
+ end
14
+ ```
15
+ ###**Example of assigning a card:**
16
+ ```
17
+ MandarinApi.assign_card user
18
+ ```
19
+ `user` should be an instance or a Struct, and should respond to `#email` and `#phone` methods
20
+ `#phone` should be serialized, for example '+79091234567' is correctly serialized number.
21
+ `#assign_card` will return a hash.
22
+ ###**Example:**
23
+ ```
24
+ {
25
+ 'id' => '0eb51e74-e704-4c36-b5cb-8f0227621518',
26
+ 'userWebLink' => "https://secure.mandarinpay.com/CardBindings/New?' \
27
+ 'id=0eb51e74-e704-4c36-b5cb-8f0227621518"
28
+ }
29
+ ```
30
+ Keep id, it will be used for pay/payouts requests. Use userWebLink to redirect user to Mandarin page for card data input.
31
+
32
+ ###**Example of performing payout:**
33
+ ```
34
+ # order_id - id of order/bill, etc. in your system.
35
+ # amount - sum of payout
36
+ # assigned_card_uuid - the id you received assigning the card
37
+ MandarinApi.payout(order_id, amount, assigned_card_uuid)
38
+ ```
39
+ #payout will return a hash with transaction id.
40
+ ###**Example:**
41
+ ```
42
+ { 'id' => '721a5185314740aaa304278fb1d8ee63' }
43
+ ```
44
+ You will have to provide a link to receive callbacks from Mandarin.
45
+ MandarinApi.process_callback takes as arguments body of a callback serialized
46
+ to hash with symbolized keys and an instance with `#success` and `#failure` methods,
47
+ `#success` and `#failure` methods should take hash with symbolized keys as an argument.
48
+ ###**Example:**
49
+ ```
50
+ class Application
51
+ def assign_card(user)
52
+ MandarinApi.assign_card(user)
53
+ end
54
+ def transit(request)
55
+ MandarinApi.process_callback(request, ResponseHandler.new)
56
+ end
57
+ end
58
+ class ResponseHandler
59
+ def success(result)
60
+ # your code here
61
+ end
62
+ def failure(result)
63
+ # your code here
64
+ end
65
+ end
66
+ ```
@@ -0,0 +1,2 @@
1
+ # frozen_string_literal: true
2
+ require 'mandarin_api'
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-configurable'
4
+ # Main module
5
+ module MandarinApi
6
+ class << self
7
+ attr_accessor :config
8
+ end
9
+ def self.assign_card(user)
10
+ MandarinApi::CardManager.new.assign_card user
11
+ end
12
+
13
+ def self.pay(_client, _amount)
14
+ # call api
15
+ end
16
+
17
+ def self.payout(order_id, amount, assigned_card_uuid)
18
+ params = {
19
+ order_id: order_id, amount: amount,
20
+ assigned_card_uuid: assigned_card_uuid
21
+ }
22
+ MandarinApi::PaymentManager.new.perform_payout params
23
+ end
24
+
25
+ def self.process_callback(request_params, response_handler)
26
+ response = MandarinApi::Responder.new.process(request_params)
27
+ response_handler.success(response.data) if response.success
28
+ response_handler.failure(response.data) if response.failure
29
+ end
30
+
31
+ def self.config
32
+ @configuration ||= Configuration.new
33
+ end
34
+
35
+ def self.configure
36
+ yield(config)
37
+ end
38
+ end
39
+
40
+ require 'mandarin_api/card_manager'
41
+ require 'mandarin_api/payment_manager'
42
+ require 'mandarin_api/responder'
43
+ require 'mandarin_api/wrapper'
44
+ require 'mandarin_api/configuration'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ module MandarinApi
3
+ # Manages cards assignment
4
+ class CardManager
5
+ def assign_card(user)
6
+ params = { customer_info: { email: user.email, phone: user.phone } }
7
+ MandarinApi::Wrapper.new(merchant_id: MandarinApi.config.merchant_id,
8
+ secret: MandarinApi.config.secret)
9
+ .request('/api/card-bindings', params)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module MandarinApi
2
+ class Configuration
3
+ attr_accessor :merchant_id, :secret, :request_url
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ module MandarinApi
3
+ # Pergorms payouts and payins
4
+ class PaymentManager
5
+ def perform_payout(params)
6
+ MandarinApi::Wrapper.new(merchant_id: MandarinApi.config.merchant_id,
7
+ secret: MandarinApi.config.secret)
8
+ .request('/api/transactions', reques_body(params))
9
+ end
10
+
11
+ private
12
+
13
+ def reques_body(params)
14
+ {
15
+ payment: {
16
+ order_id: params[:order_id], action: 'payout', price: params[:amount]
17
+ },
18
+ target: {
19
+ card: params[:assigned_card_uuid]
20
+ }
21
+ }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ module MandarinApi
3
+ # Processes callbacks from mandarinpay
4
+ class Responder
5
+ def initialize(data)
6
+ @data = data
7
+ @secret = MandarinApi.config.secret
8
+ if sign_is_valid
9
+ @process_status = data[:status]
10
+ else
11
+ @process_status = 'failed'
12
+ @data = { sign: 'Wrong signature!' }
13
+ end
14
+ end
15
+
16
+ def success
17
+ @process_status == 'success'
18
+ end
19
+
20
+ def failure
21
+ @process_status == 'failed'
22
+ end
23
+
24
+ private
25
+
26
+ def sign_is_valid
27
+ return false if !(@data.nil? || @data.empty?) && @data.class != Hash
28
+ sign = @data.delete(:sign)
29
+ Digest::SHA256.hexdigest(temp_string) == sign
30
+ end
31
+
32
+ def temp_string
33
+ temp_string = ''
34
+ @data.sort.to_h.keys.each do |key|
35
+ temp_string += @data[key].to_s + '-'
36
+ end
37
+ temp_string + @secret
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+ require 'json'
3
+ require 'rest-client'
4
+ module MandarinApi
5
+ # Wraps request sending
6
+ class Wrapper
7
+ def initialize(merchant_id:, secret:)
8
+ @merchant_id = merchant_id
9
+ @secret = secret
10
+ end
11
+
12
+ def request(endpoint, params = {})
13
+ url = URI.join(MandarinApi.config.request_url, endpoint).to_s
14
+ RestClient.post(url, json(params), header) do |response|
15
+ case response.code
16
+ when 200
17
+ JSON.parse response.body
18
+ else
19
+ { 'status' => response.status, 'error' => 'Invalid request' }
20
+ end
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def header
27
+ {
28
+ content_type: :json,
29
+ x_auth: generate_x_auth_header(@merchant_id, @secret)
30
+ }
31
+ end
32
+
33
+ def generate_x_auth_header(merchant_id, secret)
34
+ request_id = SecureRandom.uuid
35
+ hash = Digest::SHA256.hexdigest "#{merchant_id}-#{request_id}-#{secret}"
36
+ "#{merchant_id}-#{hash}-#{request_id}"
37
+ end
38
+
39
+ def json(params = {})
40
+ JSON.generate(key_transform(params))
41
+ end
42
+
43
+ def key_transform(hash)
44
+ new_hash = {}
45
+ hash.keys.each do |key|
46
+ new_hash[camelize(key.to_s)] = if hash[key].class == Hash
47
+ key_transform hash[key]
48
+ else
49
+ hash[key]
50
+ end
51
+ end
52
+ new_hash
53
+ end
54
+
55
+ def camelize(str)
56
+ str.split('_').map.with_index(0) do |letter, index|
57
+ if index.zero?
58
+ letter
59
+ else
60
+ letter.capitalize
61
+ end
62
+ end.join
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ Gem::Specification.new do |s|
3
+ s.name = 'mandarin-api'
4
+ s.version = '0.0.1'
5
+ s.authors = ['Vladimir Bogaevsky', 'Boris Kraportov']
6
+ s.email = 'gitvbogaevsky@gmail.com'
7
+ s.licenses = ['MIT']
8
+ s.summary = 'mandarinpay.com api wrapper for ruby'
9
+ s.homepage = 'https://github.com/vbogaevsky/mandarin-api-rb'
10
+ s.files = `git ls-files`.split("\n")
11
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
12
+ s.extra_rdoc_files = ['README.md', 'plantuml/callbacks.puml']
13
+ s.require_paths = ['lib']
14
+
15
+ s.add_development_dependency('webmock', '~> 2.1')
16
+ s.add_development_dependency('rspec', '~> 3.0')
17
+ s.add_development_dependency('pry', '~> 0')
18
+ s.add_development_dependency('pry-doc', '~> 0')
19
+ s.add_development_dependency('rdoc', '>= 2.4.2', '< 5.0')
20
+ s.add_development_dependency('rubocop', '~> 0')
21
+ s.add_development_dependency('faker', '>= 1.6', '< 1.7')
22
+
23
+ s.add_dependency 'rest-client', '>= 2.0', '< 3.0'
24
+ s.add_dependency 'dry-configurable', '>= 0.1.0', '< 1.0'
25
+
26
+ s.required_ruby_version = '>= 2.2.0'
27
+ end
@@ -0,0 +1,18 @@
1
+ @startuml
2
+
3
+ boundary Mandarin
4
+
5
+ boundary Application
6
+ entity ResultProcessor
7
+ control ResponseHandler
8
+ boundary MandarinApiGem
9
+ control Responder
10
+
11
+ Mandarin -> Application : HttpRequest
12
+ Application -> MandarinApiGem : RequestParams
13
+ MandarinApiGem -> Responder : RequestParams
14
+ Responder -> ResponseHandler : "<font color=green><b>SuccessResponse"
15
+ Responder -> ResponseHandler : "<font color=red><b>FailureResponse"
16
+ ResponseHandler -> ResultProcessor : Result
17
+
18
+ @enduml
@@ -0,0 +1,23 @@
1
+ RSpec.describe MandarinApi::CardManager do
2
+ describe 'assign_card' do
3
+ let(:card_manager) { MandarinApi::CardManager.new }
4
+ let(:merchant_id) { 234 }
5
+ let(:secret) { 'secret' }
6
+ let(:params) do
7
+ { customer_info: { email: 'ololo@gmail.com', phone: '8-909-999-88-77' } }
8
+ end
9
+ it 'calls wrapper instance with args' do
10
+ User = Struct.new('User', :email, :phone)
11
+ user = User.new('ololo@gmail.com', '8-909-999-88-77')
12
+ allow(MandarinApi).to \
13
+ receive_message_chain(:config, :merchant_id).and_return(merchant_id)
14
+ allow(MandarinApi).to \
15
+ receive_message_chain(:config, :secret).and_return(merchant_id)
16
+ allow_any_instance_of(MandarinApi::Wrapper).to receive(:request)
17
+ .with('/api/card-bindings', params)
18
+ expect_any_instance_of(MandarinApi::Wrapper).to receive(:request)
19
+ .with('/api/card-bindings', params)
20
+ card_manager.assign_card user
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ RSpec.describe MandarinApi::Configuration do
2
+ let(:config) { MandarinApi::Configuration.new }
3
+ describe '#merchant_id=' do
4
+ it 'can set value' do
5
+ config.merchant_id = 123
6
+ expect(config.merchant_id).to eq 123
7
+ end
8
+ end
9
+ describe '#secret=' do
10
+ it 'can set value' do
11
+ config.secret = 'secret'
12
+ expect(config.secret).to eq 'secret'
13
+ end
14
+ end
15
+ describe '#request_url=' do
16
+ it 'can set value' do
17
+ config.request_url = 'www.google.com'
18
+ expect(config.request_url).to eq 'www.google.com'
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ RSpec.describe MandarinApi::PaymentManager do
3
+ describe '#perform_payout' do
4
+ let(:payment_manager) { MandarinApi::PaymentManager.new }
5
+ let(:merchant_id) { 234 }
6
+ let(:secret) { 'secret' }
7
+ let(:params) do
8
+ {
9
+ order_id: 123_321, amount: 35_000,
10
+ assigned_card_uuid: '0eb51e74-e704-4c36-b5cb-8f0227621518'
11
+ }
12
+ end
13
+ let(:request_body) do
14
+ {
15
+ payment: { order_id: 123_321, action: 'payout', price: 35_000 },
16
+ target: { card: '0eb51e74-e704-4c36-b5cb-8f0227621518' }
17
+ }
18
+ end
19
+ it 'calls wrapper instance with args' do
20
+ allow(MandarinApi).to \
21
+ receive_message_chain(:config, :merchant_id).and_return(merchant_id)
22
+ allow(MandarinApi).to \
23
+ receive_message_chain(:config, :secret).and_return(merchant_id)
24
+ allow_any_instance_of(MandarinApi::Wrapper).to receive(:request)
25
+ .with('/api/transactions', request_body)
26
+ expect_any_instance_of(MandarinApi::Wrapper).to receive(:request)
27
+ .with('/api/transactions', request_body)
28
+ payment_manager.perform_payout params
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+ RSpec.describe MandarinApi::Responder do
3
+ let(:data) { unsign_data.merge(sign: sign) }
4
+ let(:responder) { MandarinApi::Responder.new(data) }
5
+ describe '#success' do
6
+ context 'success' do
7
+ let(:unsign_data) do
8
+ {
9
+ card_holder: 'VASILY PUPKIN',
10
+ card_number: '123456XXXXXX7890',
11
+ card_expiration_year: 18,
12
+ card_expiration_month: 9,
13
+ status: 'success'
14
+ }
15
+ end
16
+ let(:sign) do
17
+ Digest::SHA256.hexdigest(
18
+ '9-18-VASILY PUPKIN-123456XXXXXX7890-success-secret'
19
+ )
20
+ end
21
+ it 'returns true' do
22
+ allow(MandarinApi).to \
23
+ receive_message_chain(:config, :secret).and_return('secret')
24
+ expect(responder.success).to eq true
25
+ end
26
+ end
27
+ context 'failure' do
28
+ let(:unsign_data) do
29
+ {
30
+ card_holder: 'VASILY PUPKIN',
31
+ card_number: '123456XXXXXX7890',
32
+ card_expiration_year: 18,
33
+ card_expiration_month: 9,
34
+ status: 'failed'
35
+ }
36
+ end
37
+ let(:sign) do
38
+ Digest::SHA256.hexdigest(
39
+ '9-18-VASILY PUPKIN-123456XXXXXX7890-failed-secret'
40
+ )
41
+ end
42
+ it 'returns true' do
43
+ allow(MandarinApi).to \
44
+ receive_message_chain(:config, :secret).and_return('secret')
45
+ expect(responder.success).to eq false
46
+ end
47
+ end
48
+ end
49
+ describe '#failure' do
50
+ context 'success' do
51
+ let(:unsign_data) do
52
+ {
53
+ card_holder: 'VASILY PUPKIN',
54
+ card_number: '123456XXXXXX7890',
55
+ card_expiration_year: 18,
56
+ card_expiration_month: 9,
57
+ status: 'success'
58
+ }
59
+ end
60
+ let(:sign) do
61
+ Digest::SHA256.hexdigest(
62
+ '9-18-VASILY PUPKIN-123456XXXXXX7890-success-secret'
63
+ )
64
+ end
65
+ it 'returns true' do
66
+ allow(MandarinApi).to \
67
+ receive_message_chain(:config, :secret).and_return('secret')
68
+ expect(responder.failure).to eq false
69
+ end
70
+ end
71
+ context 'failure' do
72
+ let(:unsign_data) do
73
+ {
74
+ card_holder: 'VASILY PUPKIN',
75
+ card_number: '123456XXXXXX7890',
76
+ card_expiration_year: 18,
77
+ card_expiration_month: 9,
78
+ status: 'failed'
79
+ }
80
+ end
81
+ let(:sign) do
82
+ Digest::SHA256.hexdigest(
83
+ '9-18-VASILY PUPKIN-123456XXXXXX7890-failed-secret'
84
+ )
85
+ end
86
+ it 'returns true' do
87
+ allow(MandarinApi).to \
88
+ receive_message_chain(:config, :secret).and_return('secret')
89
+ expect(responder.failure).to eq true
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe MandarinApi::Wrapper do
4
+ include_context 'mocks'
5
+
6
+ let(:wrapper) do
7
+ MandarinApi::Wrapper
8
+ .new(merchant_id: rand(1000), secret: SecureRandom.hex(5))
9
+ end
10
+ describe 'request' do
11
+ let(:params) do
12
+ {
13
+ customer_info: {
14
+ email: 'ololo@gmail.com', phone: '8-909-999-88-77'
15
+ }
16
+ }
17
+ end
18
+ let(:x_auth) { 'x-auth' }
19
+ let(:mandarin_adress) { 'https://secure.mandarinpay.com/' }
20
+ let(:expected) do
21
+ {
22
+ 'id' => '0eb51e74-e704-4c36-b5cb-8f0227621518',
23
+ 'userWebLink' => 'https://secure.mandarinpay.com/CardBindings/New' \
24
+ '?id=0eb51e74-e704-4c36-b5cb-8f0227621518'
25
+ }
26
+ end
27
+ it 'sends request with passed action' do
28
+ allow(wrapper).to receive(:generate_x_auth_header).and_return(x_auth)
29
+ allow(MandarinApi).to \
30
+ receive_message_chain(:config, :request_url).and_return(mandarin_adress)
31
+ expect(wrapper.request('api/card-bindings', params)).to eq expected
32
+ end
33
+ end
34
+ describe 'camelize' do
35
+ let(:input) { 's_tri_ng' }
36
+ let(:output) { 'sTriNg' }
37
+ it 'input: underscored string, output: camelized string' do
38
+ expect(wrapper.send(:camelize, input)).to eq output
39
+ end
40
+ end
41
+ describe 'key_transform' do
42
+ let(:input) do
43
+ {
44
+ big_key_one: {
45
+ key_one: 1, key_two: 2, key_three: 3
46
+ },
47
+ big_key_two: {
48
+ key_a: 'a', key_b: 'b'
49
+ }
50
+ }
51
+ end
52
+ let(:output) do
53
+ {
54
+ 'bigKeyOne' => {
55
+ 'keyOne' => 1, 'keyTwo' => 2, 'keyThree' => 3
56
+ },
57
+ 'bigKeyTwo' => {
58
+ 'keyA' => 'a', 'keyB' => 'b'
59
+ }
60
+ }
61
+ end
62
+ it 'input: multilevel hash with underscored keys-symbols, ' \
63
+ 'output: multilevel hash with camelized keys-strings' do
64
+ expect(wrapper.send(:key_transform, input)).to eq output
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ RSpec.describe MandarinApi do
5
+ describe '#configure' do
6
+ let(:wrapper) do
7
+ MandarinApi::Wrapper.new(merchant_id: MandarinApi.config.merchant_id,
8
+ secret: MandarinApi.config.secret)
9
+ end
10
+ before do
11
+ MandarinApi.configure do |config|
12
+ config.merchant_id = 123
13
+ config.secret = 'secret'
14
+ end
15
+ end
16
+ it 'calls MandarinApi::CardManager' do
17
+ expect(wrapper.instance_variable_get(:@merchant_id)).to eq 123
18
+ expect(wrapper.instance_variable_get(:@secret)).to eq 'secret'
19
+ end
20
+ end
21
+ end
data/spec/mocks.rb ADDED
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ RSpec.shared_context 'mocks', shared_contex: :metadata do
3
+ before :each do
4
+ user_agent = "rest-client/#{Gem.loaded_specs['rest-client'].version} " \
5
+ "(#{RbConfig::CONFIG['host_os']} #{RbConfig::CONFIG['host_cpu']}) " \
6
+ "ruby/#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}"
7
+ card_assign_body = JSON.generate(customerInfo: { email: 'ololo@gmail.com',
8
+ phone: '8-909-999-88-77' })
9
+ payout_body =
10
+ JSON.generate(
11
+ payment: { orderId: 123_321, action: 'payout', price: 35_000 },
12
+ target: { card: '0eb51e74-e704-4c36-b5cb-8f0227621518' }
13
+ )
14
+ header = {
15
+ 'Accept' => '*/*', 'Accept-Encoding' => 'gzip, deflate',
16
+ 'Content-Length' => '70', 'Content-Type' => 'application/json',
17
+ 'Host' => 'secure.mandarinpay.com',
18
+ 'User-Agent' => user_agent,
19
+ 'X-Auth' => 'x-auth'
20
+ }
21
+ stub_request(:post, 'https://secure.mandarinpay.com/api/card-bindings')
22
+ .with(
23
+ body: card_assign_body,
24
+ headers: header
25
+ )
26
+ .to_return(
27
+ status: 200,
28
+ body:
29
+ JSON.generate(
30
+ id: '0eb51e74-e704-4c36-b5cb-8f0227621518',
31
+ userWebLink: 'https://secure.mandarinpay.com/CardBindings/' \
32
+ 'New?id=0eb51e74-e704-4c36-b5cb-8f0227621518'
33
+ ),
34
+ headers: {}
35
+ )
36
+ stub_request(:post, 'https://secure.mandarinpay.com/api/transactions')
37
+ .with(
38
+ body: payout_body,
39
+ headers: header
40
+ )
41
+ .to_return(
42
+ status: 200,
43
+ body:
44
+ JSON.generate(
45
+ id: '43913ddc000c4d3990fddbd3980c1725'
46
+ ),
47
+ headers: {}
48
+ )
49
+ end
50
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ require 'webmock/rspec'
3
+ require 'mocks'
4
+ require 'faker'
5
+
6
+ Dir['./lib/**/*.rb'].each { |f| require f }
7
+
8
+ RSpec.configure do |config|
9
+ config.expect_with :rspec do |expectations|
10
+ # This option will default to `true` in RSpec 4.
11
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
12
+ end
13
+
14
+ config.mock_with :rspec do |mocks|
15
+ # Prevents you from mocking or stubbing a method that does not exist on a
16
+ # real object. This is generally recommended, and will default to `true`
17
+ # in RSpec 4.
18
+ mocks.verify_partial_doubles = true
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,227 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mandarin-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Vladimir Bogaevsky
8
+ - Boris Kraportov
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-10-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: webmock
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '2.1'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '2.1'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '3.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '3.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: pry
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: pry-doc
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rdoc
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 2.4.2
77
+ - - "<"
78
+ - !ruby/object:Gem::Version
79
+ version: '5.0'
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 2.4.2
87
+ - - "<"
88
+ - !ruby/object:Gem::Version
89
+ version: '5.0'
90
+ - !ruby/object:Gem::Dependency
91
+ name: rubocop
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ - !ruby/object:Gem::Dependency
105
+ name: faker
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '1.6'
111
+ - - "<"
112
+ - !ruby/object:Gem::Version
113
+ version: '1.7'
114
+ type: :development
115
+ prerelease: false
116
+ version_requirements: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '1.6'
121
+ - - "<"
122
+ - !ruby/object:Gem::Version
123
+ version: '1.7'
124
+ - !ruby/object:Gem::Dependency
125
+ name: rest-client
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '2.0'
131
+ - - "<"
132
+ - !ruby/object:Gem::Version
133
+ version: '3.0'
134
+ type: :runtime
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '2.0'
141
+ - - "<"
142
+ - !ruby/object:Gem::Version
143
+ version: '3.0'
144
+ - !ruby/object:Gem::Dependency
145
+ name: dry-configurable
146
+ requirement: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: 0.1.0
151
+ - - "<"
152
+ - !ruby/object:Gem::Version
153
+ version: '1.0'
154
+ type: :runtime
155
+ prerelease: false
156
+ version_requirements: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: 0.1.0
161
+ - - "<"
162
+ - !ruby/object:Gem::Version
163
+ version: '1.0'
164
+ description:
165
+ email: gitvbogaevsky@gmail.com
166
+ executables: []
167
+ extensions: []
168
+ extra_rdoc_files:
169
+ - README.md
170
+ - plantuml/callbacks.puml
171
+ files:
172
+ - ".gitignore"
173
+ - ".rspec"
174
+ - Gemfile
175
+ - Gemfile.lock
176
+ - LICENSE
177
+ - README.md
178
+ - lib/mandarin-api.rb
179
+ - lib/mandarin_api.rb
180
+ - lib/mandarin_api/card_manager.rb
181
+ - lib/mandarin_api/configuration.rb
182
+ - lib/mandarin_api/payment_manager.rb
183
+ - lib/mandarin_api/responder.rb
184
+ - lib/mandarin_api/wrapper.rb
185
+ - mandarin-api.gemspec
186
+ - plantuml/callbacks.puml
187
+ - spec/lib/mandarin_api/card_manager_spec.rb
188
+ - spec/lib/mandarin_api/configuration_spec.rb
189
+ - spec/lib/mandarin_api/payment_manager_spec.rb
190
+ - spec/lib/mandarin_api/responder_spec.rb
191
+ - spec/lib/mandarin_api/wrapper_spec.rb
192
+ - spec/lib/mandarin_api_spec.rb
193
+ - spec/mocks.rb
194
+ - spec/spec_helper.rb
195
+ homepage: https://github.com/vbogaevsky/mandarin-api-rb
196
+ licenses:
197
+ - MIT
198
+ metadata: {}
199
+ post_install_message:
200
+ rdoc_options: []
201
+ require_paths:
202
+ - lib
203
+ required_ruby_version: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: 2.2.0
208
+ required_rubygems_version: !ruby/object:Gem::Requirement
209
+ requirements:
210
+ - - ">="
211
+ - !ruby/object:Gem::Version
212
+ version: '0'
213
+ requirements: []
214
+ rubyforge_project:
215
+ rubygems_version: 2.6.7
216
+ signing_key:
217
+ specification_version: 4
218
+ summary: mandarinpay.com api wrapper for ruby
219
+ test_files:
220
+ - spec/lib/mandarin_api/card_manager_spec.rb
221
+ - spec/lib/mandarin_api/configuration_spec.rb
222
+ - spec/lib/mandarin_api/payment_manager_spec.rb
223
+ - spec/lib/mandarin_api/responder_spec.rb
224
+ - spec/lib/mandarin_api/wrapper_spec.rb
225
+ - spec/lib/mandarin_api_spec.rb
226
+ - spec/mocks.rb
227
+ - spec/spec_helper.rb