wechat-api 0.1.1 → 0.1.3
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/Gemfile +1 -1
- data/lib/wechat-api.rb +1 -0
- data/lib/wechat/api/client.rb +1 -1
- data/lib/wechat/api/util.rb +5 -0
- data/lib/wechat/api/version.rb +1 -1
- data/lib/wechat/pay.rb +7 -0
- data/lib/wechat/pay/client.rb +116 -0
- data/lib/wechat/pay/redpack.rb +39 -0
- data/spec/wechat/pay/client_spec.rb +24 -0
- data/wechat-api.gemspec +5 -2
- metadata +53 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a1da7465e7436ff9a4d1f959f198a63ffc3e028
|
4
|
+
data.tar.gz: 4bfc9ba3e18733fe9146679b32b295665934d2d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d79b3b01a2fbb922ea6019af273d12244cdda7e15bc250e30f648a2c9c7a94c76f8759619304edb91f911563a5c5e4e47ff62c035e70bab10bdd00abaaab2bf7
|
7
|
+
data.tar.gz: 4a7aba85ce5c46fb22b8101c25b97c28330b9795db8cbeaf5acb2fc1da5fd2526ae3fbef4279bf7b520c0454ca1392ca76ff1aae4f024bfcff5d1fdc3fe36ec4
|
data/Gemfile
CHANGED
data/lib/wechat-api.rb
CHANGED
data/lib/wechat/api/client.rb
CHANGED
@@ -42,7 +42,7 @@ module Wechat
|
|
42
42
|
response = MultiJson.load(resp.body)
|
43
43
|
return handle_error(response) if response['errcode']
|
44
44
|
@access_token = response['access_token']
|
45
|
-
File.open(@token_file, 'w') { |f| f.write(resp.body) } if
|
45
|
+
File.open(@token_file, 'w') { |f| f.write(resp.body) } if @access_token
|
46
46
|
@access_token
|
47
47
|
end
|
48
48
|
|
data/lib/wechat/api/util.rb
CHANGED
data/lib/wechat/api/version.rb
CHANGED
data/lib/wechat/pay.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'logger'
|
3
|
+
require 'multi_json'
|
4
|
+
require 'openssl'
|
5
|
+
require 'nori'
|
6
|
+
require 'gyoku'
|
7
|
+
|
8
|
+
require 'wechat/pay/redpack'
|
9
|
+
|
10
|
+
module Wechat
|
11
|
+
module Pay
|
12
|
+
class PayError < StandardError; end
|
13
|
+
class NoAuthError < PayError; end
|
14
|
+
class NotEnoughError < PayError; end
|
15
|
+
class TimeLimitedError < PayError; end
|
16
|
+
class MoneyLimitedError < PayError; end
|
17
|
+
|
18
|
+
#
|
19
|
+
class Client
|
20
|
+
include Redpack
|
21
|
+
BASE_URL = 'https://api.mch.weixin.qq.com'
|
22
|
+
REQUIRED_OPTS = %w(key password cert sign_key).map(&:to_sym).freeze
|
23
|
+
ERRORS = {
|
24
|
+
'NO_AUTH' => NoAuthError,
|
25
|
+
'NOTENOUGH' => NotEnoughError,
|
26
|
+
'TIME_LIMITED' => TimeLimitedError,
|
27
|
+
'MONEY_LIMITED' => MoneyLimitedError
|
28
|
+
}
|
29
|
+
|
30
|
+
attr_accessor :logger
|
31
|
+
|
32
|
+
def initialize(mch_id, wxappid, opts = {})
|
33
|
+
@mch_id = mch_id
|
34
|
+
@wxappid = wxappid
|
35
|
+
@opts = Hash[opts.map { |k, v| [k.to_sym, v] }]
|
36
|
+
unless (REQUIRED_OPTS - @opts.keys).empty?
|
37
|
+
fail format('%s required', REQUIRED_OPTS.join(','))
|
38
|
+
end
|
39
|
+
@logger = Logger.new(STDOUT)
|
40
|
+
rsa_setup
|
41
|
+
@parser = Nori.new
|
42
|
+
end
|
43
|
+
|
44
|
+
def post(path, params)
|
45
|
+
merged_params = merge(params)
|
46
|
+
logger.debug { merged_params }
|
47
|
+
resp = resource(path).post(xml(sign(merged_params)))
|
48
|
+
handle(resp)
|
49
|
+
rescue RestClient::ExceptionWithResponse => err
|
50
|
+
raise PayError, err.response
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def handle(resp)
|
56
|
+
response = parser.parse(resp)
|
57
|
+
check(response)
|
58
|
+
response
|
59
|
+
end
|
60
|
+
|
61
|
+
def check(r)
|
62
|
+
return if r['xml']['result_code'] == 'SUCCESS'
|
63
|
+
handle_error(r['xml']['err_code'], r)
|
64
|
+
end
|
65
|
+
|
66
|
+
def handle_error(error_code, response)
|
67
|
+
fail ERRORS[error_code] || PayError, response.inspect
|
68
|
+
end
|
69
|
+
|
70
|
+
def rsa_setup
|
71
|
+
@rsa_key = OpenSSL::PKey::RSA.new @opts[:key], @opts[:password]
|
72
|
+
@rsa_cert = OpenSSL::X509::Certificate.new @opts[:cert]
|
73
|
+
rescue StandardError => e
|
74
|
+
logger.error { e.inspect }
|
75
|
+
end
|
76
|
+
|
77
|
+
def resource(path)
|
78
|
+
RestClient.log = logger
|
79
|
+
RestClient::Resource.new\
|
80
|
+
[BASE_URL, path].join,
|
81
|
+
ssl_client_key: @rsa_key,
|
82
|
+
ssl_client_cert: @rsa_cert,
|
83
|
+
verify_ssl: OpenSSL::SSL::VERIFY_NONE
|
84
|
+
end
|
85
|
+
|
86
|
+
def xml(hash)
|
87
|
+
Gyoku.xml({ xml: hash }, key_converter: :none)
|
88
|
+
end
|
89
|
+
|
90
|
+
def sign(params)
|
91
|
+
ordered = trim_and_sort(params)
|
92
|
+
keystr = format('key=%s', @opts[:sign_key])
|
93
|
+
origin =
|
94
|
+
ordered.map { |k, v| [k, v].join('=') }.push(keystr).join('&')
|
95
|
+
sign = Digest::MD5.hexdigest(origin).upcase
|
96
|
+
logger.debug { format('origin: %s, sign: %s', origin, sign) }
|
97
|
+
params.merge(sign: sign)
|
98
|
+
end
|
99
|
+
|
100
|
+
def trim_and_sort(params)
|
101
|
+
params.delete_if { |_k, v| v.blank? }
|
102
|
+
Hash[params.sort]
|
103
|
+
end
|
104
|
+
|
105
|
+
def merge(params)
|
106
|
+
params.reverse_merge\
|
107
|
+
mch_id: @mch_id,
|
108
|
+
nonce_str: nonce_str
|
109
|
+
end
|
110
|
+
|
111
|
+
def nonce_str
|
112
|
+
SecureRandom.hex
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Wechat
|
4
|
+
module Pay
|
5
|
+
#
|
6
|
+
module Redpack
|
7
|
+
def redpack(transaction_id, openid, params = {})
|
8
|
+
post\
|
9
|
+
'/mmpaymkttransfers/sendredpack',
|
10
|
+
params.merge(
|
11
|
+
mch_billno: tran_id(transaction_id),
|
12
|
+
wxappid: @wxappid, re_openid: openid
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def group_redpack(transaction_id, openid, params = {})
|
17
|
+
post\
|
18
|
+
'/mmpaymkttransfers/sendgroupredpack',
|
19
|
+
params.merge(
|
20
|
+
mch_billno: tran_id(transaction_id),
|
21
|
+
wxappid: @wxappid, re_openid: openid
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def redpack_info(transaction_id)
|
26
|
+
post\
|
27
|
+
'/mmpaymkttransfers/gethbinfo',
|
28
|
+
mch_billno: tran_id(transaction_id),
|
29
|
+
bill_type: 'MCHT', appid: @wxappid
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def tran_id(origin)
|
35
|
+
format('%s%s', @mch_id, origin)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
RSpec.describe Wechat::Pay::Client do
|
4
|
+
subject do
|
5
|
+
described_class.new\
|
6
|
+
'mch_id', 'wxappid',
|
7
|
+
key: 'key', password: 'password', cert: 'cert',
|
8
|
+
sign_key: 'sign_key'
|
9
|
+
end
|
10
|
+
|
11
|
+
it :trim_and_sort do
|
12
|
+
expect(
|
13
|
+
subject.send(:trim_and_sort, b: 2, c: 3, a: 1).values
|
14
|
+
).to start_with(1)
|
15
|
+
end
|
16
|
+
|
17
|
+
it :sign do
|
18
|
+
expect(subject.send(:sign, b: 2, a: 1)).to have_key(:sign)
|
19
|
+
end
|
20
|
+
|
21
|
+
it :xml do
|
22
|
+
expect(subject.send(:xml, b_1: 2, a: 1)).to match(/xml/)
|
23
|
+
end
|
24
|
+
end
|
data/wechat-api.gemspec
CHANGED
@@ -17,8 +17,11 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
-
spec.add_runtime_dependency "faraday", "
|
21
|
-
spec.add_runtime_dependency "
|
20
|
+
spec.add_runtime_dependency "faraday", ">= 0.9"
|
21
|
+
spec.add_runtime_dependency "rest-client", ">= 1.7.0"
|
22
|
+
spec.add_runtime_dependency "multi_json", ">= 1.2"
|
23
|
+
spec.add_runtime_dependency 'gyoku', '>= 1.0.0'
|
24
|
+
spec.add_runtime_dependency 'nori'
|
22
25
|
spec.add_development_dependency "bundler"
|
23
26
|
spec.add_development_dependency "rake"
|
24
27
|
spec.add_development_dependency "pry"
|
metadata
CHANGED
@@ -1,43 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wechat-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Wong
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0.9'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0.9'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rest-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.7.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.7.0
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: multi_json
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
|
-
- - "
|
45
|
+
- - ">="
|
32
46
|
- !ruby/object:Gem::Version
|
33
47
|
version: '1.2'
|
34
48
|
type: :runtime
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
|
-
- - "
|
52
|
+
- - ">="
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '1.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: gyoku
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.0.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: nori
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
41
83
|
- !ruby/object:Gem::Dependency
|
42
84
|
name: bundler
|
43
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,8 +171,12 @@ files:
|
|
129
171
|
- lib/wechat/api/user.rb
|
130
172
|
- lib/wechat/api/util.rb
|
131
173
|
- lib/wechat/api/version.rb
|
174
|
+
- lib/wechat/pay.rb
|
175
|
+
- lib/wechat/pay/client.rb
|
176
|
+
- lib/wechat/pay/redpack.rb
|
132
177
|
- spec/spec_helper.rb
|
133
178
|
- spec/wechat/api/client_spec.rb
|
179
|
+
- spec/wechat/pay/client_spec.rb
|
134
180
|
- wechat-api.gemspec
|
135
181
|
homepage: https://github.com/lazing/wechat-api
|
136
182
|
licenses:
|
@@ -159,4 +205,5 @@ summary: Wechat API wrapper
|
|
159
205
|
test_files:
|
160
206
|
- spec/spec_helper.rb
|
161
207
|
- spec/wechat/api/client_spec.rb
|
208
|
+
- spec/wechat/pay/client_spec.rb
|
162
209
|
has_rdoc:
|