bitpay-client 2.4.0 → 2.5.1905
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +5 -1
- data/.travis.yml +6 -1
- data/CHANGELOG.md +24 -0
- data/GUIDE.md +233 -0
- data/Gemfile +0 -4
- data/LICENSE.md +2 -2
- data/README.md +8 -79
- data/Rakefile +57 -2
- data/bitpay-client.gemspec +15 -16
- data/config/constants.rb +12 -1
- data/features/creating_invoices.feature +28 -0
- data/features/pairing.feature +19 -0
- data/features/refunds.feature +23 -0
- data/features/retrieving_invoices.feature +11 -0
- data/features/step_definitions/invoice_steps.rb +31 -0
- data/features/step_definitions/keygen_steps.rb +56 -0
- data/features/step_definitions/refund_steps.rb +37 -0
- data/features/step_definitions/step_helpers.rb +31 -0
- data/lib/bitpay/cacert.pem +1295 -1760
- data/lib/bitpay/client.rb +175 -0
- data/lib/bitpay/rest_connector.rb +106 -0
- data/lib/bitpay/version.rb +2 -2
- data/lib/bitpay_sdk.rb +28 -0
- data/spec/client_spec.rb +153 -6
- data/spec/fixtures/invoices-POST.json +29 -0
- data/spec/fixtures/invoices_{id}-GET.json +35 -0
- data/spec/fixtures/invoices_{id}_refunds-GET.json +17 -0
- data/spec/fixtures/invoices_{id}_refunds-POST.json +9 -0
- data/spec/fixtures/invoices_{id}_refunds_{refund_id}-GET.json +11 -0
- data/spec/fixtures/response-nodata.json +10 -0
- data/spec/spec_helper.rb +16 -18
- metadata +77 -82
- data/bin/bitpay +0 -3
- data/lib/bitpay.rb +0 -21
- data/lib/bitpay/cli.rb +0 -64
- data/lib/bitpay/cli_client.rb +0 -24
- data/lib/bitpay/cli_key_utils.rb +0 -40
- data/spec/features/pair_spec.rb +0 -25
- data/spec/key_utils_spec.rb +0 -26
- data/spec/set_constants.sh +0 -4
@@ -0,0 +1,175 @@
|
|
1
|
+
# license Copyright 2011-2019 BitPay, Inc., MIT License
|
2
|
+
# see http://opensource.org/licenses/MIT
|
3
|
+
# or https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
|
4
|
+
|
5
|
+
require 'uri'
|
6
|
+
require 'net/https'
|
7
|
+
require 'json'
|
8
|
+
|
9
|
+
require 'bitpay_key_utils'
|
10
|
+
require_relative 'rest_connector'
|
11
|
+
|
12
|
+
module BitPay
|
13
|
+
# This class is used to instantiate a BitPay Client object. It is expected to be thread safe.
|
14
|
+
#
|
15
|
+
module SDK
|
16
|
+
class Client
|
17
|
+
include BitPay::RestConnector
|
18
|
+
# @return [Client]
|
19
|
+
# @example
|
20
|
+
# # Create a client with a pem file created by the bitpay client:
|
21
|
+
# client = BitPay::SDK::Client.new
|
22
|
+
def initialize(opts={})
|
23
|
+
@pem = opts[:pem] || ENV['BITPAY_PEM'] || KeyUtils.generate_pem
|
24
|
+
@key = KeyUtils.create_key @pem
|
25
|
+
@priv_key = KeyUtils.get_private_key @key
|
26
|
+
@pub_key = KeyUtils.get_public_key @key
|
27
|
+
@client_id = KeyUtils.generate_sin_from_pem @pem
|
28
|
+
@uri = URI.parse opts[:api_uri] || API_URI
|
29
|
+
@user_agent = opts[:user_agent] || USER_AGENT
|
30
|
+
@https = Net::HTTP.new @uri.host, @uri.port
|
31
|
+
@https.use_ssl = true
|
32
|
+
@https.open_timeout = 10
|
33
|
+
@https.read_timeout = 10
|
34
|
+
|
35
|
+
@https.ca_file = CA_FILE
|
36
|
+
@tokens = opts[:tokens] || {}
|
37
|
+
|
38
|
+
# Option to disable certificate validation in extraordinary circumstance. NOT recommended for production use
|
39
|
+
@https.verify_mode = opts[:insecure] == true ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
|
40
|
+
|
41
|
+
# Option to enable http request debugging
|
42
|
+
@https.set_debug_output($stdout) if opts[:debug] == true
|
43
|
+
end
|
44
|
+
|
45
|
+
## Pair client with BitPay service
|
46
|
+
# => Pass empty hash {} to retreive client-initiated pairing code
|
47
|
+
# => Pass {pairingCode: 'WfD01d2'} to claim a server-initiated pairing code
|
48
|
+
#
|
49
|
+
def pair_client(params={})
|
50
|
+
tokens = post(path: 'tokens', params: params)
|
51
|
+
return tokens["data"]
|
52
|
+
end
|
53
|
+
|
54
|
+
## Compatibility method for pos pairing
|
55
|
+
#
|
56
|
+
def pair_pos_client(claimCode)
|
57
|
+
raise BitPay::ArgumentError, "pairing code is not legal" unless verify_claim_code(claimCode)
|
58
|
+
pair_client({pairingCode: claimCode})
|
59
|
+
end
|
60
|
+
|
61
|
+
## Create bitcoin invoice
|
62
|
+
#
|
63
|
+
# Defaults to pos facade, also works with merchant facade
|
64
|
+
#
|
65
|
+
def create_invoice(price:, currency:, facade: 'pos', params:{})
|
66
|
+
raise BitPay::ArgumentError, "Illegal Argument: Price must be formatted as a float" unless
|
67
|
+
price.is_a?(Numeric) ||
|
68
|
+
/^[[:digit:]]+(\.[[:digit:]]{2})?$/.match(price) ||
|
69
|
+
currency == 'BTC' && /^[[:digit:]]+(\.[[:digit:]]{1,6})?$/.match(price)
|
70
|
+
raise BitPay::ArgumentError, "Illegal Argument: Currency is invalid." unless /^[[:upper:]]{3}$/.match(currency)
|
71
|
+
params.merge!({price: price, currency: currency})
|
72
|
+
token = get_token(facade)
|
73
|
+
invoice = post(path: "invoices", token: token, params: params)
|
74
|
+
invoice["data"]
|
75
|
+
end
|
76
|
+
|
77
|
+
## Gets the privileged merchant-version of the invoice
|
78
|
+
# Requires merchant facade token
|
79
|
+
#
|
80
|
+
def get_invoice(id:)
|
81
|
+
token = get_token('merchant')
|
82
|
+
invoice = get(path: "invoices/#{id}", token: token)
|
83
|
+
invoice["data"]
|
84
|
+
end
|
85
|
+
|
86
|
+
## Gets the public version of the invoice
|
87
|
+
#
|
88
|
+
def get_public_invoice(id:)
|
89
|
+
invoice = get(path: "invoices/#{id}", public: true)
|
90
|
+
invoice["data"]
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
## Refund paid BitPay invoice
|
95
|
+
#
|
96
|
+
# If invoice["data"]["flags"]["refundable"] == true the a refund address was
|
97
|
+
# provided with the payment and the refund_address parameter is an optional override
|
98
|
+
#
|
99
|
+
# Amount and Currency are required fields for fully paid invoices but optional
|
100
|
+
# for under or overpaid invoices which will otherwise be completely refunded
|
101
|
+
#
|
102
|
+
# Requires merchant facade token
|
103
|
+
#
|
104
|
+
# @example
|
105
|
+
# client.refund_invoice(id: 'JB49z2MsDH7FunczeyDS8j', params: {amount: 10, currency: 'USD', bitcoinAddress: '1Jtcygf8W3cEmtGgepggtjCxtmFFjrZwRV'})
|
106
|
+
#
|
107
|
+
def refund_invoice(id:, params:{})
|
108
|
+
invoice = get_invoice(id: id)
|
109
|
+
refund = post(path: "invoices/#{id}/refunds", token: invoice["token"], params: params)
|
110
|
+
refund["data"]
|
111
|
+
end
|
112
|
+
|
113
|
+
## Get All Refunds for Invoice
|
114
|
+
# Returns an array of all refund requests for a specific invoice,
|
115
|
+
#
|
116
|
+
# Requires merchant facade token
|
117
|
+
#
|
118
|
+
# @example:
|
119
|
+
# client.get_all_refunds_for_invoice(id: 'JB49z2MsDH7FunczeyDS8j')
|
120
|
+
#
|
121
|
+
def get_all_refunds_for_invoice(id:)
|
122
|
+
urlpath = "invoices/#{id}/refunds"
|
123
|
+
invoice = get_invoice(id: id)
|
124
|
+
refunds = get(path: urlpath, token: invoice["token"])
|
125
|
+
refunds["data"]
|
126
|
+
end
|
127
|
+
|
128
|
+
## Get Refund
|
129
|
+
# Requires merchant facade token
|
130
|
+
#
|
131
|
+
# @example:
|
132
|
+
# client.get_refund(id: 'JB49z2MsDH7FunczeyDS8j', request_id: '4evCrXq4EDXk4oqDXdWQhX')
|
133
|
+
#
|
134
|
+
def get_refund(invoice_id:, request_id:)
|
135
|
+
urlpath = "invoices/#{invoice_id}/refunds/#{request_id}"
|
136
|
+
invoice = get_invoice(id: invoice_id)
|
137
|
+
refund = get(path: urlpath, token: invoice["token"])
|
138
|
+
refund["data"]
|
139
|
+
end
|
140
|
+
|
141
|
+
## Cancel Refund
|
142
|
+
# Requires merchant facade token
|
143
|
+
#
|
144
|
+
# @example:
|
145
|
+
# client.cancel_refund(id: 'JB49z2MsDH7FunczeyDS8j', request_id: '4evCrXq4EDXk4oqDXdWQhX')
|
146
|
+
#
|
147
|
+
def cancel_refund(invoice_id:, request_id:)
|
148
|
+
urlpath = "invoices/#{invoice_id}/refunds/#{request_id}"
|
149
|
+
refund = get_refund(invoice_id: invoice_id, request_id: request_id)
|
150
|
+
deletion = delete(path: urlpath, token: refund["token"])
|
151
|
+
deletion["data"]
|
152
|
+
end
|
153
|
+
|
154
|
+
## Checks that the passed tokens are valid by
|
155
|
+
# comparing them to those that are authorized by the server
|
156
|
+
#
|
157
|
+
# Uses local @tokens variable if no tokens are passed
|
158
|
+
# in order to validate the connector is properly paired
|
159
|
+
#
|
160
|
+
def verify_tokens(tokens: @tokens)
|
161
|
+
server_tokens = refresh_tokens
|
162
|
+
tokens.each{|key, value| return false if server_tokens[key] != value}
|
163
|
+
return true
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def verify_claim_code(claim_code)
|
169
|
+
regex = /^[[:alnum:]]{7}$/
|
170
|
+
matches = regex.match(claim_code)
|
171
|
+
!(matches.nil?)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# license Copyright 2011-2019 BitPay, Inc., MIT License
|
2
|
+
# see http://opensource.org/licenses/MIT
|
3
|
+
# or https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
|
4
|
+
|
5
|
+
module BitPay
|
6
|
+
module RestConnector
|
7
|
+
def send_request(verb, path, facade: 'merchant', params: {}, token: nil)
|
8
|
+
token ||= get_token(facade)
|
9
|
+
case verb.upcase
|
10
|
+
when "GET"
|
11
|
+
return get(path: path, token: token)
|
12
|
+
when "POST"
|
13
|
+
return post(path: path, token: token, params: params)
|
14
|
+
else
|
15
|
+
raise(BitPayError, "Invalid HTTP verb: #{verb.upcase}")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def get(path:, token: nil, public: false)
|
20
|
+
urlpath = '/' + path
|
21
|
+
token_prefix = if urlpath.include? '?' then '&token=' else '?token=' end
|
22
|
+
urlpath = urlpath + token_prefix + token if token
|
23
|
+
request = Net::HTTP::Get.new urlpath
|
24
|
+
unless public
|
25
|
+
request['X-Signature'] = KeyUtils.sign(@uri.to_s + urlpath, @priv_key)
|
26
|
+
request['X-Identity'] = @pub_key
|
27
|
+
end
|
28
|
+
process_request(request)
|
29
|
+
end
|
30
|
+
|
31
|
+
def post(path:, token: nil, params:)
|
32
|
+
urlpath = '/' + path
|
33
|
+
request = Net::HTTP::Post.new urlpath
|
34
|
+
params[:token] = token if token
|
35
|
+
params[:guid] = SecureRandom.uuid
|
36
|
+
params[:id] = @client_id
|
37
|
+
request.body = params.to_json
|
38
|
+
if token
|
39
|
+
request['X-Signature'] = KeyUtils.sign(@uri.to_s + urlpath + request.body, @priv_key)
|
40
|
+
request['X-Identity'] = @pub_key
|
41
|
+
end
|
42
|
+
process_request(request)
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete(path:, token: nil)
|
46
|
+
urlpath = '/' + path
|
47
|
+
urlpath = urlpath + '?token=' + token if token
|
48
|
+
request = Net::HTTP::Delete.new urlpath
|
49
|
+
request['X-Signature'] = KeyUtils.sign(@uri.to_s + urlpath, @priv_key)
|
50
|
+
request['X-Identity'] = @pub_key
|
51
|
+
process_request(request)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
## Processes HTTP Request and returns parsed response
|
57
|
+
# Otherwise throws error
|
58
|
+
#
|
59
|
+
def process_request(request)
|
60
|
+
request['User-Agent'] = @user_agent
|
61
|
+
request['Content-Type'] = 'application/json'
|
62
|
+
request['X-BitPay-Plugin-Info'] = 'Rubylib' + VERSION
|
63
|
+
|
64
|
+
begin
|
65
|
+
response = @https.request request
|
66
|
+
rescue => error
|
67
|
+
raise BitPay::ConnectionError, "#{error.message}"
|
68
|
+
end
|
69
|
+
|
70
|
+
if response.kind_of? Net::HTTPSuccess
|
71
|
+
return JSON.parse(response.body)
|
72
|
+
elsif JSON.parse(response.body)["error"]
|
73
|
+
raise(BitPayError, "#{response.code}: #{JSON.parse(response.body)['error']}")
|
74
|
+
else
|
75
|
+
raise BitPayError, "#{response.code}: #{JSON.parse(response.body)}"
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
## Fetches the tokens hash from the server and
|
81
|
+
# updates @tokens
|
82
|
+
#
|
83
|
+
def refresh_tokens
|
84
|
+
response = get(path: 'tokens')["data"]
|
85
|
+
token_array = response || {}
|
86
|
+
tokens = {}
|
87
|
+
token_array.each do |t|
|
88
|
+
tokens[t.keys.first] = t.values.first
|
89
|
+
end
|
90
|
+
@tokens = tokens
|
91
|
+
return tokens
|
92
|
+
end
|
93
|
+
|
94
|
+
## Makes a request to /tokens for pairing
|
95
|
+
# Adds passed params as post parameters
|
96
|
+
# If empty params, retrieves server-generated pairing code
|
97
|
+
# If pairingCode key/value is passed, will pair client ID to this account
|
98
|
+
# Returns response hash
|
99
|
+
#
|
100
|
+
|
101
|
+
def get_token(facade)
|
102
|
+
token = @tokens[facade] || refresh_tokens[facade] || raise(BitPayError, "Not authorized for facade: #{facade}")
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
data/lib/bitpay/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
# license Copyright 2011-
|
1
|
+
# license Copyright 2011-2019 BitPay, Inc., MIT License
|
2
2
|
# see http://opensource.org/licenses/MIT
|
3
3
|
# or https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
|
4
4
|
|
5
5
|
module BitPay
|
6
|
-
VERSION = '2.
|
6
|
+
VERSION = '2.5.1905'
|
7
7
|
end
|
data/lib/bitpay_sdk.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# license Copyright 2011-2014 BitPay, Inc., MIT License
|
2
|
+
# see http://opensource.org/licenses/MIT
|
3
|
+
# or https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
|
4
|
+
|
5
|
+
libdir = File.dirname(__FILE__)
|
6
|
+
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
7
|
+
require 'bitpay/client'
|
8
|
+
require 'bitpay/version'
|
9
|
+
|
10
|
+
module BitPay
|
11
|
+
|
12
|
+
# Location of SSL Certificate Authority File
|
13
|
+
# As sourced from http://curl.haxx.se/ca/cacert.pem
|
14
|
+
CA_FILE = File.join File.dirname(__FILE__), 'bitpay','cacert.pem'
|
15
|
+
|
16
|
+
# Location of API
|
17
|
+
API_URI = 'https://bitpay.com'
|
18
|
+
TEST_API_URI = 'https://test.bitpay.com'
|
19
|
+
CLIENT_REGISTRATION_PATH = '/api-access-request'
|
20
|
+
|
21
|
+
|
22
|
+
# User agent reported to API
|
23
|
+
USER_AGENT = 'BitPay_Ruby_Client_v'+VERSION
|
24
|
+
|
25
|
+
class BitPayError < StandardError; end
|
26
|
+
class ConnectionError < Errno::ECONNREFUSED; end
|
27
|
+
|
28
|
+
end
|
data/spec/client_spec.rb
CHANGED
@@ -2,19 +2,82 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
def tokens
|
4
4
|
{"data" =>
|
5
|
-
[{"merchant" => "
|
6
|
-
{"pos" =>"
|
5
|
+
[{"merchant" => "MERCHANT_TOKEN"},
|
6
|
+
{"pos" =>"POS_TOKEN"},
|
7
7
|
{"merchant/invoice" => "9kv7gGqZLoQ2fxbKEgfgndLoxwjp5na6VtGSH3sN7buX"}
|
8
8
|
]
|
9
9
|
}
|
10
10
|
end
|
11
11
|
|
12
|
-
describe BitPay::Client do
|
13
|
-
let(:bitpay_client) { BitPay::Client.new({api_uri: BitPay::TEST_API_URI}) }
|
12
|
+
describe BitPay::SDK::Client do
|
13
|
+
let(:bitpay_client) { BitPay::SDK::Client.new({api_uri: BitPay::TEST_API_URI}) }
|
14
14
|
let(:claim_code) { "a12bc3d" }
|
15
15
|
|
16
16
|
before do
|
17
|
-
|
17
|
+
# Stub JSON responses from fixtures
|
18
|
+
stub_request(:get, /#{BitPay::TEST_API_URI}\/tokens.*/)
|
19
|
+
.to_return(:status => 200, :body => tokens.to_json, :headers => {})
|
20
|
+
stub_request(:get, "#{BitPay::TEST_API_URI}/invoices/TEST_INVOICE_ID?token=MERCHANT_TOKEN").
|
21
|
+
to_return(:body => get_fixture('invoices_{id}-GET.json'))
|
22
|
+
stub_request(:get, "#{BitPay::TEST_API_URI}/invoices/TEST_INVOICE_ID/refunds?token=MERCHANT_INVOICE_TOKEN").
|
23
|
+
to_return(:body => get_fixture('invoices_{id}_refunds-GET.json'))
|
24
|
+
stub_request(:get, "#{BitPay::TEST_API_URI}/invoices/TEST_INVOICE_ID/refunds/TEST_REQUEST_ID?token=MERCHANT_INVOICE_TOKEN").
|
25
|
+
to_return(:body => get_fixture('invoices_{id}_refunds-GET.json'))
|
26
|
+
stub_request(:post, "#{BitPay::TEST_API_URI}/invoices/TEST_INVOICE_ID/refunds").
|
27
|
+
to_return(:body => get_fixture('invoices_{id}_refunds-POST.json'))
|
28
|
+
stub_request(:post, "#{BitPay::TEST_API_URI}/nuttin").
|
29
|
+
to_return(:body => get_fixture('response-nodata.json'))
|
30
|
+
stub_request(:get, "#{BitPay::TEST_API_URI}/nuttin").
|
31
|
+
to_return(:body => get_fixture('response-nodata.json'))
|
32
|
+
stub_request(:delete, "#{BitPay::TEST_API_URI}/nuttin").
|
33
|
+
to_return(:body => get_fixture('response-nodata.json'))
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#initialize" do
|
37
|
+
|
38
|
+
it 'should be able to get pem file from the env' do
|
39
|
+
stub_const('ENV', {'BITPAY_PEM' => PEM})
|
40
|
+
expect {bitpay_client}.to_not raise_error
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "requests to endpoint without data field" do
|
46
|
+
it "should return the json body" do
|
47
|
+
expect(bitpay_client.post(path: "nuttin", params: {})["facile"]).to eq("is easy")
|
48
|
+
expect(bitpay_client.get(path: "nuttin")["facile"]).to eq("is easy")
|
49
|
+
expect(bitpay_client.delete(path: "nuttin")["facile"]).to eq( "is easy")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#send_request" do
|
54
|
+
before do
|
55
|
+
stub_const('ENV', {'BITPAY_PEM' => PEM})
|
56
|
+
end
|
57
|
+
|
58
|
+
context "GET" do
|
59
|
+
it 'should generate a get request' do
|
60
|
+
stub_request(:get, /#{BitPay::TEST_API_URI}\/whatever.*/).to_return(:body => '{"awesome": "json"}')
|
61
|
+
bitpay_client.send_request("GET", "whatever", facade: "merchant")
|
62
|
+
expect(WebMock).to have_requested(:get, "#{BitPay::TEST_API_URI}/whatever?token=MERCHANT_TOKEN")
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should handle query parameters gracefully' do
|
66
|
+
stub_request(:get, /#{BitPay::TEST_API_URI}\/ledgers.*/).to_return(:body => '{"awesome": "json"}')
|
67
|
+
bitpay_client.send_request("GET", "ledgers/BTC?startDate=2015-01-01&endDate=2015-02-01", facade: "merchant")
|
68
|
+
expect(WebMock).to have_requested(:get, "#{BitPay::TEST_API_URI}/ledgers/BTC?startDate=2015-01-01&endDate=2015-02-01&token=MERCHANT_TOKEN")
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
context "POST" do
|
74
|
+
it 'should generate a post request' do
|
75
|
+
stub_request(:post, /#{BitPay::TEST_API_URI}.*/).to_return(:body => '{"awesome": "json"}')
|
76
|
+
bitpay_client.send_request("POST", "whatever", facade: "merchant")
|
77
|
+
expect(WebMock).to have_requested(:post, "#{BitPay::TEST_API_URI}/whatever")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
18
81
|
end
|
19
82
|
|
20
83
|
describe "#pair_pos_client" do
|
@@ -35,9 +98,93 @@ describe BitPay::Client do
|
|
35
98
|
it 'short circuits on invalid pairing codes' do
|
36
99
|
100.times do
|
37
100
|
claim_code = an_illegal_claim_code
|
38
|
-
expect{bitpay_client.pair_pos_client(claim_code)}.to raise_error BitPay::ArgumentError, "pairing code is not legal"
|
101
|
+
expect { bitpay_client.pair_pos_client(claim_code) }.to raise_error BitPay::ArgumentError, "pairing code is not legal"
|
39
102
|
end
|
40
103
|
end
|
41
104
|
end
|
42
105
|
|
106
|
+
describe "#create_invoice" do
|
107
|
+
subject { bitpay_client }
|
108
|
+
before {stub_const('ENV', {'BITPAY_PEM' => PEM})}
|
109
|
+
it { is_expected.to respond_to(:create_invoice) }
|
110
|
+
|
111
|
+
describe "should make the call to the server to create an invoice" do
|
112
|
+
it 'allows numeric input for the price' do
|
113
|
+
stub_request(:post, /#{BitPay::TEST_API_URI}\/invoices.*/).to_return(:body => '{"data": "awesome"}')
|
114
|
+
bitpay_client.create_invoice(price: 20.00, currency: "USD")
|
115
|
+
assert_requested :post, "#{BitPay::TEST_API_URI}/invoices"
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'allows string input for the price' do
|
119
|
+
stub_request(:post, /#{BitPay::TEST_API_URI}\/invoices.*/).to_return(:body => '{"data": "awesome"}')
|
120
|
+
bitpay_client.create_invoice(price: "20.00", currency: "USD")
|
121
|
+
assert_requested :post, "#{BitPay::TEST_API_URI}/invoices"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should pass through the API error message from load_tokens' do
|
126
|
+
stub_request(:get, /#{BitPay::TEST_API_URI}\/tokens.*/).to_return(status: 500, body: '{"error": "load_tokens_error"}')
|
127
|
+
expect { bitpay_client.create_invoice(price: 20, currency: "USD") }.to raise_error(BitPay::BitPayError, '500: load_tokens_error')
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'verifies the validity of the price argument' do
|
131
|
+
expect { bitpay_client.create_invoice(price: "3,999", currency: "USD") }.to raise_error(BitPay::ArgumentError, 'Illegal Argument: Price must be formatted as a float')
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'verifies the validity of the currency argument' do
|
135
|
+
expect { bitpay_client.create_invoice(price: "3999", currency: "UASD") }.to raise_error(BitPay::ArgumentError, 'Illegal Argument: Currency is invalid.')
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#refund_invoice' do
|
140
|
+
subject { bitpay_client }
|
141
|
+
before { stub_const('ENV', {'BITPAY_PEM' => PEM}) }
|
142
|
+
it { is_expected.to respond_to(:refund_invoice) }
|
143
|
+
|
144
|
+
it 'should get the token for the invoice' do
|
145
|
+
bitpay_client.refund_invoice(id: 'TEST_INVOICE_ID')
|
146
|
+
expect(WebMock).to have_requested :get, "#{BitPay::TEST_API_URI}/invoices/TEST_INVOICE_ID?token=MERCHANT_TOKEN"
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'should generate a POST to the invoices/refund endpoint' do
|
150
|
+
bitpay_client.refund_invoice(id: 'TEST_INVOICE_ID')
|
151
|
+
expect(WebMock).to have_requested :post, "#{BitPay::TEST_API_URI}/invoices/TEST_INVOICE_ID/refunds"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe '#get_all_refunds_for_invoice' do
|
156
|
+
subject { bitpay_client }
|
157
|
+
before {stub_const('ENV', {'BITPAY_PEM' => PEM})}
|
158
|
+
it { is_expected.to respond_to(:get_all_refunds_for_invoice) }
|
159
|
+
|
160
|
+
it 'should get the token for the invoice' do
|
161
|
+
bitpay_client.get_all_refunds_for_invoice(id: 'TEST_INVOICE_ID')
|
162
|
+
expect(WebMock).to have_requested :get, "#{BitPay::TEST_API_URI}/invoices/TEST_INVOICE_ID?token=MERCHANT_TOKEN"
|
163
|
+
end
|
164
|
+
it 'should GET all refunds' do
|
165
|
+
bitpay_client.get_all_refunds_for_invoice(id: 'TEST_INVOICE_ID')
|
166
|
+
expect(WebMock).to have_requested :get, "#{BitPay::TEST_API_URI}/invoices/TEST_INVOICE_ID/refunds?token=MERCHANT_INVOICE_TOKEN"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe '#get_refund' do
|
171
|
+
subject { bitpay_client }
|
172
|
+
before {stub_const('ENV', {'BITPAY_PEM' => PEM})}
|
173
|
+
it { is_expected.to respond_to(:get_refund) }
|
174
|
+
it 'should get the token for the invoice' do
|
175
|
+
bitpay_client.get_refund(invoice_id: 'TEST_INVOICE_ID', request_id: 'TEST_REQUEST_ID')
|
176
|
+
expect(WebMock).to have_requested :get, "#{BitPay::TEST_API_URI}/invoices/TEST_INVOICE_ID?token=MERCHANT_TOKEN"
|
177
|
+
end
|
178
|
+
it 'should GET a single refund' do
|
179
|
+
bitpay_client.get_refund(invoice_id: 'TEST_INVOICE_ID', request_id: 'TEST_REQUEST_ID')
|
180
|
+
expect(WebMock).to have_requested :get, "#{BitPay::TEST_API_URI}/invoices/TEST_INVOICE_ID/refunds/TEST_REQUEST_ID?token=MERCHANT_INVOICE_TOKEN"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "#verify_tokens" do
|
185
|
+
subject { bitpay_client }
|
186
|
+
before {stub_const('ENV', {'BITPAY_PEM' => PEM})}
|
187
|
+
it { is_expected.to respond_to(:verify_tokens) }
|
188
|
+
end
|
43
189
|
end
|
190
|
+
|