bitpay-client 2.4.0 → 2.5.1905
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 +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
|
+
|