nihaopay-ruby 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE +22 -0
  4. data/README.md +344 -0
  5. data/lib/nihaopay-ruby.rb +29 -0
  6. data/lib/nihaopay/configure.rb +14 -0
  7. data/lib/nihaopay/credit_card.rb +27 -0
  8. data/lib/nihaopay/errors.rb +6 -0
  9. data/lib/nihaopay/merchant.rb +47 -0
  10. data/lib/nihaopay/mixins/api.rb +41 -0
  11. data/lib/nihaopay/mixins/queryable.rb +41 -0
  12. data/lib/nihaopay/query.rb +61 -0
  13. data/lib/nihaopay/secure_pay/ali_pay.rb +11 -0
  14. data/lib/nihaopay/secure_pay/base.rb +48 -0
  15. data/lib/nihaopay/secure_pay/union_pay.rb +11 -0
  16. data/lib/nihaopay/secure_pay/we_chat_pay.rb +11 -0
  17. data/lib/nihaopay/transactions/authorize.rb +37 -0
  18. data/lib/nihaopay/transactions/base.rb +78 -0
  19. data/lib/nihaopay/transactions/cancel.rb +28 -0
  20. data/lib/nihaopay/transactions/capture.rb +29 -0
  21. data/lib/nihaopay/transactions/purchase.rb +11 -0
  22. data/lib/nihaopay/transactions/refund.rb +31 -0
  23. data/lib/nihaopay/transactions/release.rb +28 -0
  24. data/lib/nihaopay/util/hash_util.rb +30 -0
  25. data/lib/nihaopay/version.rb +3 -0
  26. data/spec/credit_card_spec.rb +56 -0
  27. data/spec/merchant_spec.rb +142 -0
  28. data/spec/mixins/api_spec.rb +81 -0
  29. data/spec/mixins/queryable_spec.rb +95 -0
  30. data/spec/query_spec.rb +129 -0
  31. data/spec/secure_pay/ali_pay_spec.rb +112 -0
  32. data/spec/secure_pay/union_pay_spec.rb +13 -0
  33. data/spec/secure_pay/we_chat_pay_spec.rb +13 -0
  34. data/spec/spec_helper.rb +7 -0
  35. data/spec/transactions/authorize_spec.rb +115 -0
  36. data/spec/transactions/base_spec.rb +184 -0
  37. data/spec/transactions/cancel_spec.rb +83 -0
  38. data/spec/transactions/capture_spec.rb +85 -0
  39. data/spec/transactions/purchase_spec.rb +7 -0
  40. data/spec/transactions/refund_spec.rb +98 -0
  41. data/spec/transactions/release_spec.rb +83 -0
  42. data/spec/util/hash_util_spec.rb +22 -0
  43. metadata +187 -0
@@ -0,0 +1,6 @@
1
+ module Nihaopay
2
+ TransactionError = Class.new(StandardError)
3
+ SecurePayTransactionError = Class.new(TransactionError)
4
+ ExpressPayTransactionError = Class.new(TransactionError)
5
+ TransactionLookUpError = Class.new(TransactionError)
6
+ end
@@ -0,0 +1,47 @@
1
+ module Nihaopay
2
+ class Merchant
3
+ attr_accessor :token
4
+
5
+ def initialize(token)
6
+ self.token = token
7
+ end
8
+
9
+ def union_pay(amount, currency, options = {})
10
+ options[:token] = token
11
+ Nihaopay::SecurePay::UnionPay.start(amount, currency, options)
12
+ end
13
+
14
+ def ali_pay(amount, currency, options = {})
15
+ options[:token] = token
16
+ Nihaopay::SecurePay::AliPay.start(amount, currency, options)
17
+ end
18
+
19
+ def wechat_pay(amount, currency, options = {})
20
+ options[:token] = token
21
+ Nihaopay::SecurePay::WeChatPay.start(amount, currency, options)
22
+ end
23
+
24
+ def authorize(amount, credit_card, options = {})
25
+ options[:token] = token
26
+ Nihaopay::Transactions::Authorize.start(amount, credit_card, options)
27
+ end
28
+
29
+ def capture(transaction_id, amount, currency)
30
+ Nihaopay::Transactions::Capture.start(transaction_id, amount, currency, token: token)
31
+ end
32
+
33
+ def purchase(amount, credit_card, options = {})
34
+ options[:token] = token
35
+ Nihaopay::Transactions::Purchase.start(amount, credit_card, options)
36
+ end
37
+
38
+ def release(transaction_id)
39
+ Nihaopay::Transactions::Release.start(transaction_id, token: token)
40
+ end
41
+
42
+ def refund(transaction_id, amount, currency, options = {})
43
+ options[:token] = token
44
+ Nihaopay::Transactions::Refund.start(transaction_id, amount, currency, options)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,41 @@
1
+ module Nihaopay
2
+ module Api
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ LIVE_HOST = 'https://api.nihaopay.com'.freeze
8
+ TEST_HOST = 'http://api.test.nihaopay.com'.freeze
9
+ VERSION = 'v1.1'.freeze
10
+
11
+ module ClassMethods
12
+ def host
13
+ Nihaopay.test_mode ? TEST_HOST : LIVE_HOST
14
+ end
15
+
16
+ def base_url
17
+ "#{host}/#{VERSION}"
18
+ end
19
+
20
+ def authorization
21
+ { 'Authorization' => "Bearer #{merchant_token}" }
22
+ end
23
+
24
+ def merchant_token
25
+ @token || Nihaopay.token
26
+ end
27
+
28
+ def validate_resource!(response)
29
+ return if response.parsed_response['id']
30
+ parsed_response = response.parsed_response.map { |k, v| "#{k}: #{v}" }.join(', ')
31
+ fail Nihaopay::TransactionError, parsed_response
32
+ end
33
+
34
+ def validate_collection!(response)
35
+ return if response.parsed_response['transactions']
36
+ parsed_response = response.parsed_response.map { |k, v| "#{k}: #{v}" }.join(', ')
37
+ fail Nihaopay::TransactionError, parsed_response
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ module Nihaopay
2
+ module Queryable
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ def find(transaction_id)
9
+ url = "#{base_url}/transactions/#{transaction_id}"
10
+ response = HTTParty.get(url, headers: request_headers)
11
+ build_from_response!(response)
12
+ rescue Nihaopay::TransactionError => e
13
+ raise Nihaopay::TransactionLookUpError, e.message
14
+ end
15
+
16
+ def fetch(options = {})
17
+ options[:starting_after] = options.delete(:after) if options[:after]
18
+ options[:ending_before] = options.delete(:before) if options[:before]
19
+ q.fetch(options)
20
+ end
21
+
22
+ def limit(num)
23
+ q.limit(num)
24
+ end
25
+
26
+ def before(time)
27
+ q.before(time)
28
+ end
29
+
30
+ def after(time)
31
+ q.after(time)
32
+ end
33
+
34
+ private
35
+
36
+ def q
37
+ Nihaopay::Query.new
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,61 @@
1
+ module Nihaopay
2
+ class Query
3
+ include ::Nihaopay::Api
4
+
5
+ VALID_OPTIONS = %i(limit starting_after ending_before).freeze
6
+
7
+ def limit(num)
8
+ @limit = num
9
+ self
10
+ end
11
+
12
+ def before(time)
13
+ @ending_before = time
14
+ self
15
+ end
16
+
17
+ def after(time)
18
+ @starting_after = time
19
+ self
20
+ end
21
+
22
+ def fetch(options = nil)
23
+ options ||= { limit: @limit, starting_after: @starting_after, ending_before: @ending_before }
24
+ self.class.fetch(options)
25
+ end
26
+
27
+ class << self
28
+ def fetch(options = {})
29
+ query = query_params(options)
30
+ response = if query && !query.empty?
31
+ HTTParty.get(url, headers: request_headers, query: query)
32
+ else
33
+ HTTParty.get(url, headers: request_headers)
34
+ end
35
+ build_transactions(response)
36
+ rescue Nihaopay::TransactionError => e
37
+ raise Nihaopay::TransactionLookUpError, e.message
38
+ end
39
+
40
+ def url
41
+ "#{base_url}/transactions"
42
+ end
43
+
44
+ def request_headers
45
+ authorization
46
+ end
47
+
48
+ def query_params(options)
49
+ Nihaopay::HashUtil.slice(options, *VALID_OPTIONS).select { |_, v| v && (!v.respond_to?(:empty?) || !v.empty?) }
50
+ end
51
+
52
+ def build_transactions(response)
53
+ validate_collection!(response)
54
+ transactions = response.parsed_response['transactions']
55
+ transactions.map do |transaction|
56
+ Nihaopay::Transactions::Base.build(transaction)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,11 @@
1
+ module Nihaopay
2
+ module SecurePay
3
+ class AliPay < Base
4
+ class << self
5
+ def vendor
6
+ :alipay
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,48 @@
1
+ module Nihaopay
2
+ module SecurePay
3
+ class Base
4
+ include ::Nihaopay::Api
5
+
6
+ class << self
7
+ def with_failure(&_)
8
+ response = yield
9
+ if response.code != 200
10
+ message = response.parsed_response.map { |k, v| "#{k}: #{v}" }.join(', ')
11
+ fail SecurePayTransactionError, message
12
+ end
13
+ response
14
+ end
15
+
16
+ def start(amount, currency, options = {})
17
+ with_failure do
18
+ @token = options.delete(:token)
19
+ params = request_params(amount, currency, options)
20
+ body = request_body(params)
21
+ HTTParty.post(request_url, headers: request_headers, body: body)
22
+ end
23
+ end
24
+
25
+ def request_url
26
+ "#{base_url}/transactions/securepay"
27
+ end
28
+
29
+ def request_headers
30
+ authorization
31
+ end
32
+
33
+ def request_params(amount, currency, options)
34
+ { amount: amount.to_i,
35
+ currency: currency.to_s,
36
+ vendor: vendor.to_s,
37
+ reference: options[:reference].to_s.slice(0, 30),
38
+ ipn_url: options[:ipn_url].to_s,
39
+ callback_url: options[:callback_url].to_s }
40
+ end
41
+
42
+ def request_body(params = {})
43
+ params.map { |k, v| "#{k}=#{v}" }.join('&')
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,11 @@
1
+ module Nihaopay
2
+ module SecurePay
3
+ class UnionPay < Base
4
+ class << self
5
+ def vendor
6
+ :unionpay
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Nihaopay
2
+ module SecurePay
3
+ class WeChatPay < Base
4
+ class << self
5
+ def vendor
6
+ :wechatpay
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,37 @@
1
+ module Nihaopay
2
+ module Transactions
3
+ class Authorize < Base
4
+ class << self
5
+ def start(amount, credit_card, options = {})
6
+ @token = options.delete(:token)
7
+ params = request_params(amount, credit_card, options)
8
+ body = request_body(params)
9
+ response = HTTParty.post(request_url, headers: request_headers, body: body)
10
+ build_from_response!(response)
11
+ end
12
+
13
+ def request_url
14
+ "#{base_url}/transactions/expresspay"
15
+ end
16
+
17
+ def request_params(amount, credit_card, options)
18
+ params = {}
19
+ params.merge! credit_card.to_params_hash
20
+ params.merge! Nihaopay::HashUtil.slice(options, *valid_options)
21
+ params[:capture] = capture_param
22
+ params[:amount] = amount
23
+ params[:currency] ||= Nihaopay.currency
24
+ params
25
+ end
26
+
27
+ def valid_options
28
+ %i(currency description note reference)
29
+ end
30
+
31
+ def capture_param
32
+ false
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,78 @@
1
+ module Nihaopay
2
+ module Transactions
3
+ class Base
4
+ include ::Nihaopay::Api
5
+ include ::Nihaopay::Queryable
6
+
7
+ attr_accessor :token, :transaction_id, :type, :status
8
+ attr_accessor :captured, :reference, :currency, :amount, :note, :time
9
+
10
+ def initialize(attributes = {})
11
+ assign_attributes(attributes)
12
+ end
13
+
14
+ def capture
15
+ Nihaopay::Transactions::Capture.start(transaction_id, amount, currency, token: token)
16
+ end
17
+
18
+ def partial_capture(capture_amount)
19
+ Nihaopay::Transactions::Capture.start(transaction_id, capture_amount, currency, token: token)
20
+ end
21
+
22
+ def release
23
+ Nihaopay::Transactions::Release.start(transaction_id, token: token)
24
+ end
25
+
26
+ def cancel
27
+ Nihaopay::Transactions::Cancel.start(transaction_id, token: token)
28
+ end
29
+
30
+ def refund(options = {})
31
+ options[:token] = token
32
+ Nihaopay::Transactions::Refund.start(transaction_id, amount, currency, options)
33
+ end
34
+
35
+ def partial_refund(refund_amount, options = {})
36
+ options[:token] = token
37
+ Nihaopay::Transactions::Refund.start(transaction_id, refund_amount, currency, options)
38
+ end
39
+
40
+ class << self
41
+ def request_headers
42
+ authorization.merge('Content-Type' => 'application/x-www-form-urlencoded')
43
+ end
44
+
45
+ def request_body(params = {})
46
+ params.map { |k, v| "#{k}=#{v}" }.join('&')
47
+ end
48
+
49
+ def build_from_response!(response)
50
+ validate_resource!(response)
51
+ build(response.parsed_response)
52
+ end
53
+
54
+ def build(options = {})
55
+ options = Nihaopay::HashUtil.symbolize_keys(options)
56
+ attributes = Nihaopay::HashUtil.slice(options, *valid_attributes)
57
+ attributes[:token] ||= merchant_token
58
+ response_keys_map.each { |k, v| attributes[v] = options[k] }
59
+ new(attributes)
60
+ end
61
+
62
+ def valid_attributes
63
+ %i(token transaction_id type status captured currency reference amount note time)
64
+ end
65
+
66
+ def response_keys_map
67
+ { id: :transaction_id }
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def assign_attributes(attributes)
74
+ self.class.valid_attributes.each { |f| send("#{f}=", attributes[f]) }
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,28 @@
1
+ module Nihaopay
2
+ module Transactions
3
+ class Cancel < Base
4
+ attr_accessor :cancelled, :cancel_transaction_id
5
+
6
+ class << self
7
+ def start(transaction_id, options = {})
8
+ @token = options.delete(:token)
9
+ url = request_url(transaction_id)
10
+ response = HTTParty.post(url, headers: request_headers, body: request_body)
11
+ build_from_response!(response)
12
+ end
13
+
14
+ def request_url(transaction_id)
15
+ "#{base_url}/transactions/#{transaction_id}/cancel"
16
+ end
17
+
18
+ def valid_attributes
19
+ %i(transaction_id status cancelled cancel_transaction_id)
20
+ end
21
+
22
+ def response_keys_map
23
+ { id: :transaction_id, transaction_id: :cancel_transaction_id }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ module Nihaopay
2
+ module Transactions
3
+ class Capture < Base
4
+ attr_accessor :captured, :capture_transaction_id
5
+
6
+ class << self
7
+ def start(transaction_id, amount, currency, options = {})
8
+ @token = options.delete(:token)
9
+ url = request_url(transaction_id)
10
+ params = request_body(amount: amount, currency: currency)
11
+ response = HTTParty.post(url, headers: request_headers, body: params)
12
+ build_from_response!(response)
13
+ end
14
+
15
+ def request_url(transaction_id)
16
+ "#{base_url}/transactions/#{transaction_id}/capture"
17
+ end
18
+
19
+ def valid_attributes
20
+ %i(transaction_id status captured capture_transaction_id)
21
+ end
22
+
23
+ def response_keys_map
24
+ { id: :transaction_id, transaction_id: :capture_transaction_id }
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end