pingpp 2.0.15 → 2.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.
- checksums.yaml +4 -4
- data/lib/data/ca-certificates.crt +4030 -89
- data/lib/pingpp/api_operations/create.rb +3 -9
- data/lib/pingpp/api_operations/delete.rb +4 -3
- data/lib/pingpp/api_operations/list.rb +6 -8
- data/lib/pingpp/api_operations/request.rb +46 -0
- data/lib/pingpp/api_operations/update.rb +18 -45
- data/lib/pingpp/api_resource.rb +28 -8
- data/lib/pingpp/batch_refund.rb +14 -0
- data/lib/pingpp/batch_transfer.rb +14 -0
- data/lib/pingpp/charge.rb +3 -4
- data/lib/pingpp/customs.rb +10 -0
- data/lib/pingpp/errors/channel_error.rb +3 -2
- data/lib/pingpp/errors/invalid_request_error.rb +3 -2
- data/lib/pingpp/errors/pingpp_error.rb +4 -1
- data/lib/pingpp/errors/rate_limit_error.rb +4 -0
- data/lib/pingpp/event.rb +1 -3
- data/lib/pingpp/identification.rb +4 -4
- data/lib/pingpp/list_object.rb +12 -12
- data/lib/pingpp/pingpp_object.rb +146 -44
- data/lib/pingpp/red_envelope.rb +7 -3
- data/lib/pingpp/refund.rb +15 -6
- data/lib/pingpp/singleton_api_resource.rb +6 -6
- data/lib/pingpp/transfer.rb +7 -3
- data/lib/pingpp/util.rb +52 -6
- data/lib/pingpp/version.rb +1 -1
- data/lib/pingpp/webhook.rb +3 -3
- data/lib/pingpp/wx_pub_oauth.rb +8 -4
- data/lib/pingpp.rb +178 -67
- metadata +10 -73
data/lib/pingpp.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# Pingpp Ruby bindings
|
2
|
-
# API spec at https://pingxx.com/
|
2
|
+
# API spec at https://www.pingxx.com/api
|
3
3
|
require 'cgi'
|
4
4
|
require 'set'
|
5
5
|
require 'openssl'
|
6
6
|
require 'rest-client'
|
7
7
|
require 'json'
|
8
8
|
require 'base64'
|
9
|
+
require 'socket'
|
10
|
+
require 'rbconfig'
|
9
11
|
|
10
12
|
# Version
|
11
13
|
require 'pingpp/version'
|
@@ -15,6 +17,7 @@ require 'pingpp/api_operations/create'
|
|
15
17
|
require 'pingpp/api_operations/update'
|
16
18
|
require 'pingpp/api_operations/delete'
|
17
19
|
require 'pingpp/api_operations/list'
|
20
|
+
require 'pingpp/api_operations/request'
|
18
21
|
|
19
22
|
# Resources
|
20
23
|
require 'pingpp/util'
|
@@ -29,6 +32,9 @@ require 'pingpp/event'
|
|
29
32
|
require 'pingpp/transfer'
|
30
33
|
require 'pingpp/webhook'
|
31
34
|
require 'pingpp/identification'
|
35
|
+
require 'pingpp/customs'
|
36
|
+
require 'pingpp/batch_refund'
|
37
|
+
require 'pingpp/batch_transfer'
|
32
38
|
|
33
39
|
# Errors
|
34
40
|
require 'pingpp/errors/pingpp_error'
|
@@ -37,27 +43,45 @@ require 'pingpp/errors/api_connection_error'
|
|
37
43
|
require 'pingpp/errors/invalid_request_error'
|
38
44
|
require 'pingpp/errors/authentication_error'
|
39
45
|
require 'pingpp/errors/channel_error'
|
46
|
+
require 'pingpp/errors/rate_limit_error'
|
40
47
|
|
41
48
|
# WxPubOauth
|
42
49
|
require 'pingpp/wx_pub_oauth'
|
43
50
|
|
44
51
|
module Pingpp
|
45
52
|
DEFAULT_CA_BUNDLE_PATH = File.dirname(__FILE__) + '/data/ca-certificates.crt'
|
46
|
-
@api_base = 'https://api.pingxx.com'
|
47
53
|
|
48
|
-
|
54
|
+
RETRY_EXCEPTIONS = [
|
55
|
+
Errno::ECONNREFUSED,
|
56
|
+
Errno::ECONNRESET,
|
57
|
+
Errno::ETIMEDOUT,
|
58
|
+
RestClient::Conflict,
|
59
|
+
RestClient::RequestTimeout,
|
60
|
+
].freeze
|
61
|
+
|
62
|
+
@api_base = 'https://api.pingxx.com'
|
49
63
|
|
50
|
-
@
|
64
|
+
@ca_bundle_path = DEFAULT_CA_BUNDLE_PATH
|
51
65
|
@verify_ssl_certs = true
|
52
66
|
|
67
|
+
@open_timeout = 30
|
68
|
+
@timeout = 80
|
69
|
+
|
70
|
+
@max_network_retries = 0
|
71
|
+
@max_network_retry_delay = 2
|
72
|
+
@initial_network_retry_delay = 0.5
|
73
|
+
|
53
74
|
HEADERS_TO_PARSE = [:pingpp_one_version, :pingpp_sdk_version]
|
54
75
|
|
55
76
|
class << self
|
56
|
-
attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version,
|
77
|
+
attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version,
|
78
|
+
:parsed_headers, :private_key, :pub_key, :app_id, :timeout,
|
79
|
+
:open_timeout
|
80
|
+
attr_reader :max_network_retry_delay, :initial_network_retry_delay
|
57
81
|
end
|
58
82
|
|
59
|
-
def self.api_url(url='')
|
60
|
-
@api_base + url
|
83
|
+
def self.api_url(url='', api_base_url=nil)
|
84
|
+
(api_base_url || @api_base) + url
|
61
85
|
end
|
62
86
|
|
63
87
|
def self.parse_headers(headers)
|
@@ -77,7 +101,9 @@ module Pingpp
|
|
77
101
|
end
|
78
102
|
end
|
79
103
|
|
80
|
-
def self.request(method, url, api_key, params={}, headers={})
|
104
|
+
def self.request(method, url, api_key, params={}, headers={}, api_base_url=nil)
|
105
|
+
api_base_url = api_base_url || @api_base
|
106
|
+
|
81
107
|
unless api_key ||= @api_key
|
82
108
|
raise AuthenticationError.new('No API key provided. ' +
|
83
109
|
'Set your API key using "Pingpp.api_key = <API-KEY>". ' +
|
@@ -93,7 +119,7 @@ module Pingpp
|
|
93
119
|
|
94
120
|
if verify_ssl_certs
|
95
121
|
request_opts = {:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
|
96
|
-
:ssl_ca_file => @
|
122
|
+
:ssl_ca_file => @ca_bundle_path,
|
97
123
|
:ssl_version => 'TLSv1'}
|
98
124
|
else
|
99
125
|
request_opts = {:verify_ssl => false,
|
@@ -107,46 +133,35 @@ module Pingpp
|
|
107
133
|
end
|
108
134
|
|
109
135
|
params = Util.objects_to_ids(params)
|
110
|
-
url = api_url(url)
|
136
|
+
url = api_url(url, api_base_url)
|
111
137
|
|
112
|
-
|
138
|
+
method_sym = method.to_s.downcase.to_sym
|
139
|
+
case method_sym
|
113
140
|
when :get, :head, :delete
|
114
141
|
# Make params into GET parameters
|
115
|
-
url += "#{URI.parse(url).query ? '&' : '?'}#{
|
142
|
+
url += "#{URI.parse(url).query ? '&' : '?'}#{Util.encode_parameters(params)}" if params && params.any?
|
116
143
|
payload = nil
|
117
144
|
else
|
118
145
|
payload = JSON.generate(params)
|
119
146
|
end
|
120
147
|
|
121
|
-
request_opts.update(:headers => request_headers(api_key,
|
122
|
-
:method => method, :open_timeout =>
|
123
|
-
:payload => payload, :url => url, :timeout =>
|
148
|
+
request_opts.update(:headers => request_headers(api_key, method_sym, payload, url).update(headers),
|
149
|
+
:method => method, :open_timeout => open_timeout,
|
150
|
+
:payload => payload, :url => url, :timeout => timeout)
|
124
151
|
|
125
|
-
|
126
|
-
response = execute_request(request_opts)
|
127
|
-
rescue SocketError => e
|
128
|
-
handle_restclient_error(e)
|
129
|
-
rescue NoMethodError => e
|
130
|
-
# Work around RestClient bug
|
131
|
-
if e.message =~ /\WRequestFailed\W/
|
132
|
-
e = APIConnectionError.new('Unexpected HTTP response code')
|
133
|
-
handle_restclient_error(e)
|
134
|
-
else
|
135
|
-
raise
|
136
|
-
end
|
137
|
-
rescue RestClient::ExceptionWithResponse => e
|
138
|
-
if rcode = e.http_code and rbody = e.http_body
|
139
|
-
handle_api_error(rcode, rbody)
|
140
|
-
else
|
141
|
-
handle_restclient_error(e)
|
142
|
-
end
|
143
|
-
rescue RestClient::Exception, Errno::ECONNREFUSED => e
|
144
|
-
handle_restclient_error(e)
|
145
|
-
end
|
152
|
+
response = execute_request_with_rescues(request_opts, api_base_url)
|
146
153
|
|
147
154
|
[parse(response), api_key]
|
148
155
|
end
|
149
156
|
|
157
|
+
def self.max_network_retries
|
158
|
+
@max_network_retries
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.max_network_retries=(val)
|
162
|
+
@max_network_retries = val.to_i
|
163
|
+
end
|
164
|
+
|
150
165
|
private
|
151
166
|
|
152
167
|
def self.user_agent
|
@@ -159,23 +174,75 @@ module Pingpp
|
|
159
174
|
:lang_version => lang_version,
|
160
175
|
:platform => RUBY_PLATFORM,
|
161
176
|
:publisher => 'pingpp',
|
162
|
-
:uname => @uname
|
177
|
+
:uname => @uname,
|
178
|
+
:hostname => Socket.gethostname,
|
179
|
+
:engine => defined?(RUBY_ENGINE) ? RUBY_ENGINE : '',
|
180
|
+
:openssl_version => OpenSSL::OPENSSL_VERSION
|
163
181
|
}
|
164
182
|
|
165
183
|
end
|
166
184
|
|
167
185
|
def self.get_uname
|
168
|
-
|
169
|
-
|
186
|
+
if File.exist?('/proc/version')
|
187
|
+
File.read('/proc/version').strip
|
188
|
+
else
|
189
|
+
case RbConfig::CONFIG['host_os']
|
190
|
+
when /linux|darwin|bsd|sunos|solaris|cygwin/i
|
191
|
+
_uname_uname
|
192
|
+
when /mswin|mingw/i
|
193
|
+
_uname_ver
|
194
|
+
else
|
195
|
+
"unknown platform"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def self._uname_uname
|
201
|
+
(`uname -a 2>/dev/null` || '').strip
|
202
|
+
rescue Errno::ENOMEM
|
170
203
|
"uname lookup failed"
|
171
204
|
end
|
172
205
|
|
173
|
-
def self.
|
174
|
-
|
175
|
-
|
206
|
+
def self._uname_ver
|
207
|
+
(`ver` || '').strip
|
208
|
+
rescue Errno::ENOMEM
|
209
|
+
"uname lookup failed"
|
176
210
|
end
|
177
211
|
|
178
|
-
def self.
|
212
|
+
def self.execute_request_with_rescues(request_opts, api_base_url, retry_count = 0)
|
213
|
+
begin
|
214
|
+
response = execute_request(request_opts)
|
215
|
+
|
216
|
+
rescue => e
|
217
|
+
if should_retry?(e, retry_count)
|
218
|
+
retry_count = retry_count + 1
|
219
|
+
sleep sleep_time(retry_count)
|
220
|
+
retry
|
221
|
+
end
|
222
|
+
|
223
|
+
case e
|
224
|
+
when SocketError
|
225
|
+
response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
|
226
|
+
|
227
|
+
when RestClient::ExceptionWithResponse
|
228
|
+
if e.response
|
229
|
+
handle_api_error(e.response)
|
230
|
+
else
|
231
|
+
response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
|
232
|
+
end
|
233
|
+
|
234
|
+
when RestClient::Exception, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError
|
235
|
+
response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
|
236
|
+
|
237
|
+
else
|
238
|
+
raise
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
response
|
243
|
+
end
|
244
|
+
|
245
|
+
def self.request_headers(api_key, method_sym, data, url)
|
179
246
|
post_or_put = (method_sym == :post or method_sym == :put)
|
180
247
|
headers = {
|
181
248
|
:user_agent => "Pingpp/v1 RubyBindings/#{Pingpp::VERSION}",
|
@@ -193,8 +260,17 @@ module Pingpp
|
|
193
260
|
:error => "#{e} (#{e.class})")
|
194
261
|
end
|
195
262
|
|
196
|
-
|
197
|
-
|
263
|
+
data_to_be_signed = data || ''
|
264
|
+
uri = URI.parse(url)
|
265
|
+
data_to_be_signed += uri.path
|
266
|
+
(!uri.query.nil?) && data_to_be_signed += '?' + uri.query
|
267
|
+
|
268
|
+
request_time = Time.now.to_i.to_s
|
269
|
+
headers.update(:pingplusplus_request_timestamp => request_time)
|
270
|
+
data_to_be_signed += request_time
|
271
|
+
|
272
|
+
if private_key
|
273
|
+
signature = sign_request(data_to_be_signed, private_key)
|
198
274
|
headers.update(:pingplusplus_signature => signature)
|
199
275
|
end
|
200
276
|
|
@@ -235,63 +311,81 @@ module Pingpp
|
|
235
311
|
"(HTTP response code was #{rcode})", rcode, rbody)
|
236
312
|
end
|
237
313
|
|
238
|
-
def self.handle_api_error(
|
314
|
+
def self.handle_api_error(resp)
|
239
315
|
begin
|
240
|
-
error_obj = JSON.parse(
|
316
|
+
error_obj = JSON.parse(resp.body)
|
241
317
|
error_obj = Util.symbolize_names(error_obj)
|
242
|
-
error = error_obj[:error]
|
318
|
+
error = error_obj[:error]
|
319
|
+
raise PingppError.new unless error && error.is_a?(Hash)
|
243
320
|
|
244
321
|
rescue JSON::ParserError, PingppError
|
245
|
-
raise general_api_error(
|
322
|
+
raise general_api_error(resp.code, resp.body)
|
246
323
|
end
|
247
324
|
|
248
|
-
case
|
325
|
+
case resp.code
|
249
326
|
when 400, 404
|
250
|
-
raise invalid_request_error
|
327
|
+
raise invalid_request_error(error, resp, error_obj)
|
251
328
|
when 401
|
252
|
-
raise authentication_error
|
329
|
+
raise authentication_error(error, resp, error_obj)
|
253
330
|
when 402
|
254
|
-
raise channel_error
|
331
|
+
raise channel_error(error, resp, error_obj)
|
332
|
+
when 403
|
333
|
+
raise rate_limit_error(error, resp, error_obj)
|
255
334
|
else
|
256
|
-
raise api_error
|
335
|
+
raise api_error(error, resp, error_obj)
|
257
336
|
end
|
258
337
|
|
259
338
|
end
|
260
339
|
|
261
|
-
def self.invalid_request_error(error,
|
262
|
-
InvalidRequestError.new(error[:message], error[:param],
|
263
|
-
|
340
|
+
def self.invalid_request_error(error, resp, error_obj)
|
341
|
+
InvalidRequestError.new(error[:message], error[:param], resp.code,
|
342
|
+
resp.body, error_obj, resp.headers)
|
343
|
+
end
|
344
|
+
|
345
|
+
def self.authentication_error(error, resp, error_obj)
|
346
|
+
AuthenticationError.new(error[:message], resp.code, resp.body, error_obj,
|
347
|
+
resp.headers)
|
264
348
|
end
|
265
349
|
|
266
|
-
def self.
|
267
|
-
|
350
|
+
def self.channel_error(error, resp, error_obj)
|
351
|
+
ChannelError.new(error[:message], error[:code], error[:param], resp.code,
|
352
|
+
resp.body, error_obj, resp.headers)
|
268
353
|
end
|
269
354
|
|
270
|
-
def self.
|
271
|
-
|
355
|
+
def self.rate_limit_error(error, resp, error_obj)
|
356
|
+
RateLimitError.new(error[:message], resp.code, resp.body, error_obj,
|
357
|
+
resp.headers)
|
272
358
|
end
|
273
359
|
|
274
|
-
def self.api_error(error,
|
275
|
-
APIError.new(error[:message],
|
360
|
+
def self.api_error(error, resp, error_obj)
|
361
|
+
APIError.new(error[:message], resp.code, resp.body, error_obj, resp.headers)
|
276
362
|
end
|
277
363
|
|
278
|
-
def self.handle_restclient_error(e)
|
364
|
+
def self.handle_restclient_error(e, request_opts, retry_count, api_base_url=nil)
|
365
|
+
api_base_url = @api_base unless api_base_url
|
366
|
+
|
279
367
|
connection_message = "Please check your internet connection and try again. " \
|
280
368
|
"If this problem persists, you should check Pingpp's service status at " \
|
281
369
|
"https://www.pingxx.com/status"
|
282
370
|
|
283
371
|
case e
|
284
372
|
when RestClient::RequestTimeout
|
285
|
-
message = "Could not connect to Pingpp (#{
|
373
|
+
message = "Could not connect to Pingpp (#{api_base_url}). #{connection_message}"
|
286
374
|
|
287
375
|
when RestClient::ServerBrokeConnection
|
288
|
-
message = "The connection to the server (#{
|
376
|
+
message = "The connection to the server (#{api_base_url}) broke before the " \
|
289
377
|
"request completed. #{connection_message}"
|
290
378
|
|
379
|
+
when OpenSSL::SSL::SSLError
|
380
|
+
message = "Could not establish a secure connection to Ping++, you may " \
|
381
|
+
"need to upgrade your OpenSSL version. To check, try running " \
|
382
|
+
"'openssl s_client -connect api.pingxx.com:443' from the " \
|
383
|
+
"command line."
|
384
|
+
|
291
385
|
when RestClient::SSLCertificateNotVerified
|
292
386
|
message = "Could not verify Pingpp's SSL certificate. " \
|
293
387
|
"Please make sure that your network is not intercepting certificates. " \
|
294
|
-
"(Try going to (#{
|
388
|
+
"(Try going to (#{api_base_url}) in your browser.)"
|
295
389
|
|
296
390
|
when SocketError
|
297
391
|
message = "Unexpected error communicating when trying to connect to Pingpp. " \
|
@@ -303,6 +397,23 @@ module Pingpp
|
|
303
397
|
|
304
398
|
end
|
305
399
|
|
400
|
+
if retry_count > 0
|
401
|
+
message += " Request was retried #{retry_count} times."
|
402
|
+
end
|
403
|
+
|
306
404
|
raise APIConnectionError.new(message + "\n\n(Network error: #{e.message})")
|
307
405
|
end
|
406
|
+
|
407
|
+
def self.should_retry?(e, retry_count)
|
408
|
+
retry_count < self.max_network_retries &&
|
409
|
+
RETRY_EXCEPTIONS.any? { |klass| e.is_a?(klass) }
|
410
|
+
end
|
411
|
+
|
412
|
+
def self.sleep_time(retry_count)
|
413
|
+
sleep_seconds = [initial_network_retry_delay * (2 ** (retry_count - 1)), max_network_retry_delay].min
|
414
|
+
sleep_seconds = sleep_seconds * (0.5 * (1 + rand()))
|
415
|
+
sleep_seconds = [initial_network_retry_delay, sleep_seconds].max
|
416
|
+
|
417
|
+
sleep_seconds
|
418
|
+
end
|
308
419
|
end
|
metadata
CHANGED
@@ -1,36 +1,22 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pingpp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xufeng Weng
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.4'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.4'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: mime-types
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
30
16
|
requirements:
|
31
17
|
- - ">="
|
32
18
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
19
|
+
version: '1.4'
|
34
20
|
- - "<"
|
35
21
|
- !ruby/object:Gem::Version
|
36
22
|
version: '4.0'
|
@@ -40,64 +26,10 @@ dependencies:
|
|
40
26
|
requirements:
|
41
27
|
- - ">="
|
42
28
|
- !ruby/object:Gem::Version
|
43
|
-
version: '1.
|
29
|
+
version: '1.4'
|
44
30
|
- - "<"
|
45
31
|
- !ruby/object:Gem::Version
|
46
32
|
version: '4.0'
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: json
|
49
|
-
requirement: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '1.8'
|
54
|
-
- - ">="
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
version: 1.8.1
|
57
|
-
type: :runtime
|
58
|
-
prerelease: false
|
59
|
-
version_requirements: !ruby/object:Gem::Requirement
|
60
|
-
requirements:
|
61
|
-
- - "~>"
|
62
|
-
- !ruby/object:Gem::Version
|
63
|
-
version: '1.8'
|
64
|
-
- - ">="
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version: 1.8.1
|
67
|
-
- !ruby/object:Gem::Dependency
|
68
|
-
name: mocha
|
69
|
-
requirement: !ruby/object:Gem::Requirement
|
70
|
-
requirements:
|
71
|
-
- - "~>"
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
version: 0.13.2
|
74
|
-
type: :development
|
75
|
-
prerelease: false
|
76
|
-
version_requirements: !ruby/object:Gem::Requirement
|
77
|
-
requirements:
|
78
|
-
- - "~>"
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
version: 0.13.2
|
81
|
-
- !ruby/object:Gem::Dependency
|
82
|
-
name: shoulda
|
83
|
-
requirement: !ruby/object:Gem::Requirement
|
84
|
-
requirements:
|
85
|
-
- - "~>"
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
version: '3.4'
|
88
|
-
- - ">="
|
89
|
-
- !ruby/object:Gem::Version
|
90
|
-
version: 3.4.0
|
91
|
-
type: :development
|
92
|
-
prerelease: false
|
93
|
-
version_requirements: !ruby/object:Gem::Requirement
|
94
|
-
requirements:
|
95
|
-
- - "~>"
|
96
|
-
- !ruby/object:Gem::Version
|
97
|
-
version: '3.4'
|
98
|
-
- - ">="
|
99
|
-
- !ruby/object:Gem::Version
|
100
|
-
version: 3.4.0
|
101
33
|
description: PingPlusPlus is the easiest way to accept payments online. See https://pingxx.com
|
102
34
|
for details.
|
103
35
|
email:
|
@@ -111,15 +43,20 @@ files:
|
|
111
43
|
- lib/pingpp/api_operations/create.rb
|
112
44
|
- lib/pingpp/api_operations/delete.rb
|
113
45
|
- lib/pingpp/api_operations/list.rb
|
46
|
+
- lib/pingpp/api_operations/request.rb
|
114
47
|
- lib/pingpp/api_operations/update.rb
|
115
48
|
- lib/pingpp/api_resource.rb
|
49
|
+
- lib/pingpp/batch_refund.rb
|
50
|
+
- lib/pingpp/batch_transfer.rb
|
116
51
|
- lib/pingpp/charge.rb
|
52
|
+
- lib/pingpp/customs.rb
|
117
53
|
- lib/pingpp/errors/api_connection_error.rb
|
118
54
|
- lib/pingpp/errors/api_error.rb
|
119
55
|
- lib/pingpp/errors/authentication_error.rb
|
120
56
|
- lib/pingpp/errors/channel_error.rb
|
121
57
|
- lib/pingpp/errors/invalid_request_error.rb
|
122
58
|
- lib/pingpp/errors/pingpp_error.rb
|
59
|
+
- lib/pingpp/errors/rate_limit_error.rb
|
123
60
|
- lib/pingpp/event.rb
|
124
61
|
- lib/pingpp/identification.rb
|
125
62
|
- lib/pingpp/list_object.rb
|
@@ -132,7 +69,7 @@ files:
|
|
132
69
|
- lib/pingpp/version.rb
|
133
70
|
- lib/pingpp/webhook.rb
|
134
71
|
- lib/pingpp/wx_pub_oauth.rb
|
135
|
-
homepage: https://pingxx.com/
|
72
|
+
homepage: https://www.pingxx.com/api
|
136
73
|
licenses:
|
137
74
|
- MIT
|
138
75
|
metadata: {}
|