mandarin-api 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.
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