sinopac-funbiz 0.0.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.env.example +8 -0
- data/.gitignore +2 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +103 -0
- data/Guardfile +5 -0
- data/README.md +13 -35
- data/lib/sinopac/funbiz/all.rb +17 -0
- data/lib/sinopac/funbiz/gateway.rb +186 -0
- data/lib/sinopac/funbiz/hash.rb +16 -0
- data/lib/sinopac/funbiz/message.rb +31 -0
- data/lib/sinopac/funbiz/nonce.rb +17 -0
- data/lib/sinopac/funbiz/order.rb +22 -0
- data/lib/sinopac/funbiz/order_result.rb +30 -0
- data/lib/sinopac/funbiz/result.rb +45 -0
- data/lib/sinopac/funbiz/sign.rb +17 -0
- data/lib/sinopac/funbiz/transaction_result.rb +32 -0
- data/lib/sinopac/funbiz/version.rb +1 -1
- data/lib/sinopac/funbiz.rb +1 -1
- data/sinopac-funbiz.gemspec +2 -2
- metadata +17 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12c404fe21accf3d76a8fc0a41b5cdfc4e0e390cf480d4f1cbb0876743952388
|
4
|
+
data.tar.gz: bb64402464a17a1896beb23754753f15923fb7ee69867d5e80250a2b37527355
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3bc24a526d6720c54c4c1d039ad6772ee53005f1ea9fbf73952fec61c52e19bd764858a1cd28f991b738469c76f2a3899d87315397be53aa8c5b43ab5826669f
|
7
|
+
data.tar.gz: 07d81fddd23449ae4e55df64bb109947beb7e8e9f06353318e04491eac4e58b653adc44ff6b848d7186274a5d141c570e05a160848c382644b782132eaa78dfb
|
data/.env.example
ADDED
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sinopac-funbiz (0.1.2)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activesupport (6.1.4.1)
|
10
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
11
|
+
i18n (>= 1.6, < 2)
|
12
|
+
minitest (>= 5.1)
|
13
|
+
tzinfo (~> 2.0)
|
14
|
+
zeitwerk (~> 2.3)
|
15
|
+
addressable (2.8.0)
|
16
|
+
public_suffix (>= 2.0.2, < 5.0)
|
17
|
+
coderay (1.1.3)
|
18
|
+
concurrent-ruby (1.1.9)
|
19
|
+
crack (0.4.5)
|
20
|
+
rexml
|
21
|
+
diff-lcs (1.4.4)
|
22
|
+
dotenv (2.7.6)
|
23
|
+
factory_bot (6.2.0)
|
24
|
+
activesupport (>= 5.0.0)
|
25
|
+
ffi (1.15.4)
|
26
|
+
formatador (0.3.0)
|
27
|
+
guard (2.18.0)
|
28
|
+
formatador (>= 0.2.4)
|
29
|
+
listen (>= 2.7, < 4.0)
|
30
|
+
lumberjack (>= 1.0.12, < 2.0)
|
31
|
+
nenv (~> 0.1)
|
32
|
+
notiffany (~> 0.0)
|
33
|
+
pry (>= 0.13.0)
|
34
|
+
shellany (~> 0.0)
|
35
|
+
thor (>= 0.18.1)
|
36
|
+
guard-compat (1.2.1)
|
37
|
+
guard-rspec (4.7.3)
|
38
|
+
guard (~> 2.1)
|
39
|
+
guard-compat (~> 1.1)
|
40
|
+
rspec (>= 2.99.0, < 4.0)
|
41
|
+
hashdiff (1.0.1)
|
42
|
+
i18n (1.8.10)
|
43
|
+
concurrent-ruby (~> 1.0)
|
44
|
+
listen (3.7.0)
|
45
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
46
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
47
|
+
lumberjack (1.2.8)
|
48
|
+
method_source (1.0.0)
|
49
|
+
minitest (5.14.4)
|
50
|
+
nenv (0.3.0)
|
51
|
+
notiffany (0.1.3)
|
52
|
+
nenv (~> 0.1)
|
53
|
+
shellany (~> 0.0)
|
54
|
+
pry (0.14.1)
|
55
|
+
coderay (~> 1.1)
|
56
|
+
method_source (~> 1.0)
|
57
|
+
public_suffix (4.0.6)
|
58
|
+
rake (12.3.3)
|
59
|
+
rb-fsevent (0.11.0)
|
60
|
+
rb-inotify (0.10.1)
|
61
|
+
ffi (~> 1.0)
|
62
|
+
rexml (3.2.5)
|
63
|
+
rspec (3.10.0)
|
64
|
+
rspec-core (~> 3.10.0)
|
65
|
+
rspec-expectations (~> 3.10.0)
|
66
|
+
rspec-mocks (~> 3.10.0)
|
67
|
+
rspec-core (3.10.1)
|
68
|
+
rspec-support (~> 3.10.0)
|
69
|
+
rspec-expectations (3.10.1)
|
70
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
71
|
+
rspec-support (~> 3.10.0)
|
72
|
+
rspec-mocks (3.10.2)
|
73
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
74
|
+
rspec-support (~> 3.10.0)
|
75
|
+
rspec-support (3.10.2)
|
76
|
+
shellany (0.0.1)
|
77
|
+
thor (1.1.0)
|
78
|
+
timecop (0.9.4)
|
79
|
+
tzinfo (2.0.4)
|
80
|
+
concurrent-ruby (~> 1.0)
|
81
|
+
vcr (6.0.0)
|
82
|
+
webmock (3.14.0)
|
83
|
+
addressable (>= 2.8.0)
|
84
|
+
crack (>= 0.3.2)
|
85
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
86
|
+
zeitwerk (2.4.2)
|
87
|
+
|
88
|
+
PLATFORMS
|
89
|
+
ruby
|
90
|
+
|
91
|
+
DEPENDENCIES
|
92
|
+
dotenv (~> 2.7)
|
93
|
+
factory_bot (~> 6.2)
|
94
|
+
guard-rspec (~> 4.7)
|
95
|
+
rake (~> 12.0)
|
96
|
+
rspec (~> 3.10)
|
97
|
+
sinopac-funbiz!
|
98
|
+
timecop (~> 0.9.4)
|
99
|
+
vcr (~> 6.0)
|
100
|
+
webmock (~> 3.14)
|
101
|
+
|
102
|
+
BUNDLED WITH
|
103
|
+
2.1.4
|
data/Guardfile
ADDED
data/README.md
CHANGED
@@ -1,40 +1,18 @@
|
|
1
|
-
# Sinopac
|
1
|
+
# API Wrapper for Sinopac FunBiz Payment (WIP)
|
2
2
|
|
3
|
-
|
3
|
+
- Ruby 2.7.4
|
4
4
|
|
5
|
-
|
5
|
+
## Environment Variables
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
```
|
8
|
+
FUNBIZ_SHOP_NO='YOUR-SHOP-NO'
|
9
|
+
FUNBIZ_END_POINT='https://apisbx.sinopac.com/funBIZ/QPay.WebAPI/api'
|
10
|
+
FUNBIZ_HASH_A1='YOUR-HASH-A1'
|
11
|
+
FUNBIZ_HASH_A2='YOUR-HASH-A2'
|
12
|
+
FUNBIZ_HASH_B1='YOUR-HASH-B1'
|
13
|
+
FUNBIZ_HASH_B2='YOUR-HASH-B2'
|
14
|
+
FUNBIZ_RETURN_URL='YOUR-RETURN-URL'
|
15
|
+
FUNBIZ_BACKEND_URL='YOUR-BACKEND-URL'
|
13
16
|
```
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
$ bundle install
|
18
|
-
|
19
|
-
Or install it yourself as:
|
20
|
-
|
21
|
-
$ gem install sinopac-funbiz
|
22
|
-
|
23
|
-
## Usage
|
24
|
-
|
25
|
-
TODO: Write usage instructions here
|
26
|
-
|
27
|
-
## Development
|
28
|
-
|
29
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
-
|
31
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
-
|
33
|
-
## Contributing
|
34
|
-
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/sinopac-funbiz.
|
36
|
-
|
37
|
-
|
38
|
-
## License
|
39
|
-
|
40
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
18
|
+
by eddie@5xcampus.com
|
@@ -0,0 +1,17 @@
|
|
1
|
+
[
|
2
|
+
"sinopac/funbiz/version",
|
3
|
+
"sinopac/funbiz/hash",
|
4
|
+
"sinopac/funbiz/nonce",
|
5
|
+
"sinopac/funbiz/sign",
|
6
|
+
"sinopac/funbiz/message",
|
7
|
+
"sinopac/funbiz/gateway",
|
8
|
+
"sinopac/funbiz/order",
|
9
|
+
"sinopac/funbiz/result",
|
10
|
+
"sinopac/funbiz/transaction_result",
|
11
|
+
"sinopac/funbiz/order_result",
|
12
|
+
].each do |mod|
|
13
|
+
begin
|
14
|
+
require mod
|
15
|
+
rescue LoadError
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'sinopac/funbiz/all'
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Sinopac::FunBiz
|
7
|
+
class Gateway
|
8
|
+
attr_reader :shop_no
|
9
|
+
|
10
|
+
def initialize(shop_no: nil, hashes: nil, end_point: nil, return_url: nil, backend_url: nil)
|
11
|
+
@shop_no = shop_no || ENV['FUNBIZ_SHOP_NO']
|
12
|
+
@hashes = hashes || {
|
13
|
+
a1: ENV['FUNBIZ_HASH_A1'],
|
14
|
+
a2: ENV['FUNBIZ_HASH_A2'],
|
15
|
+
b1: ENV['FUNBIZ_HASH_B1'],
|
16
|
+
b2: ENV['FUNBIZ_HASH_B2']
|
17
|
+
}
|
18
|
+
@end_point = end_point || ENV['FUNBIZ_END_POINT']
|
19
|
+
@return_url = return_url || ENV['FUNBIZ_RETURN_URL']
|
20
|
+
@backend_url = backend_url || ENV['FUNBIZ_BACKEND_URL']
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_nonce
|
24
|
+
@nonce ||= Nonce.get_nonce(shop_no: @shop_no, end_point: @end_point)
|
25
|
+
end
|
26
|
+
|
27
|
+
def hash_id
|
28
|
+
Hash.hash_id(@hashes)
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_atm_order(order:, **options)
|
32
|
+
build_order(order: order, type: :atm, **options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def build_creditcard_order(order:, **options)
|
36
|
+
build_order(order: order, type: :credit_card, **options)
|
37
|
+
end
|
38
|
+
|
39
|
+
def order_create_request_params(order_params:)
|
40
|
+
build_request_params(order_params: order_params, service_type: 'OrderCreate')
|
41
|
+
end
|
42
|
+
|
43
|
+
def order_pay_query_request_params(data:)
|
44
|
+
build_request_params(order_params: data, service_type: 'OrderPayQuery')
|
45
|
+
end
|
46
|
+
|
47
|
+
def order_query_request_params(data:)
|
48
|
+
build_request_params(order_params: data, service_type: 'OrderQuery')
|
49
|
+
end
|
50
|
+
|
51
|
+
def pay!(pay_type:, order:, **options)
|
52
|
+
order_params = case pay_type
|
53
|
+
when :credit_card
|
54
|
+
build_creditcard_order(order: order, **options)
|
55
|
+
when :atm
|
56
|
+
build_atm_order(order: order, **options)
|
57
|
+
else
|
58
|
+
raise "payment method is not supported yet!"
|
59
|
+
end
|
60
|
+
|
61
|
+
request_params = order_create_request_params(order_params: order_params)
|
62
|
+
|
63
|
+
url = URI("#{@end_point}/Order")
|
64
|
+
header = { "Content-Type" => "application/json" }
|
65
|
+
resp = Net::HTTP.post(url, request_params.to_json, header)
|
66
|
+
result = decrypt_message(content: JSON.parse(resp.body))
|
67
|
+
|
68
|
+
Result.new(result)
|
69
|
+
end
|
70
|
+
|
71
|
+
def query_order(shop_no: nil, order_no:)
|
72
|
+
data = {
|
73
|
+
ShopNo: shop_no || @shop_no,
|
74
|
+
OrderNo: order_no
|
75
|
+
}
|
76
|
+
|
77
|
+
request_params = order_query_request_params(data: data)
|
78
|
+
|
79
|
+
url = URI("#{@end_point}/Order")
|
80
|
+
header = { "Content-Type" => "application/json" }
|
81
|
+
resp = Net::HTTP.post(url, request_params.to_json, header)
|
82
|
+
result = decrypt_message(content: JSON.parse(resp.body))
|
83
|
+
|
84
|
+
OrderResult.new(result)
|
85
|
+
end
|
86
|
+
|
87
|
+
def query_pay_order(shop_no: nil, pay_token:)
|
88
|
+
data = {
|
89
|
+
ShopNo: shop_no || @shop_no,
|
90
|
+
PayToken: pay_token
|
91
|
+
}
|
92
|
+
|
93
|
+
request_params = order_pay_query_request_params(data: data)
|
94
|
+
|
95
|
+
url = URI("#{@end_point}/Order")
|
96
|
+
header = { "Content-Type" => "application/json" }
|
97
|
+
resp = Net::HTTP.post(url, request_params.to_json, header)
|
98
|
+
result = decrypt_message(content: JSON.parse(resp.body))
|
99
|
+
|
100
|
+
TransactionResult.new(result)
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
def encrypt_message(content:)
|
105
|
+
Message.encrypt(
|
106
|
+
content: content,
|
107
|
+
key: hash_id,
|
108
|
+
iv: Message.iv(nonce: get_nonce)
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
def decrypt_message(content:)
|
113
|
+
message = content["Message"]
|
114
|
+
nonce = content["Nonce"]
|
115
|
+
|
116
|
+
Message.decrypt(
|
117
|
+
content: message,
|
118
|
+
key: hash_id,
|
119
|
+
iv: Message.iv(nonce: nonce)
|
120
|
+
)
|
121
|
+
end
|
122
|
+
|
123
|
+
def sign(content:)
|
124
|
+
Sign.sign(
|
125
|
+
content: content,
|
126
|
+
nonce: get_nonce,
|
127
|
+
hash_id: hash_id
|
128
|
+
)
|
129
|
+
end
|
130
|
+
|
131
|
+
def build_order(order:, type:, **params)
|
132
|
+
content = {
|
133
|
+
ShopNo: @shop_no,
|
134
|
+
OrderNo: order.order_no,
|
135
|
+
Amount: order.amount * 100,
|
136
|
+
CurrencyID: params[:currency] || 'TWD',
|
137
|
+
PrdtName: order.product_name,
|
138
|
+
Memo: order.memo,
|
139
|
+
Param1: order.param1,
|
140
|
+
Param2: order.param2,
|
141
|
+
Param3: order.param3,
|
142
|
+
ReturnURL: @return_url,
|
143
|
+
BackendURL: @backend_url
|
144
|
+
}
|
145
|
+
|
146
|
+
case type
|
147
|
+
when :atm
|
148
|
+
expired_after = params[:expired_after] || 10
|
149
|
+
content.merge!(
|
150
|
+
{
|
151
|
+
PayType: 'A',
|
152
|
+
ATMParam: {
|
153
|
+
ExpireDate: (Date.today + expired_after).strftime('%Y%m%d')
|
154
|
+
}
|
155
|
+
}
|
156
|
+
)
|
157
|
+
|
158
|
+
when :credit_card
|
159
|
+
content.merge!(
|
160
|
+
{
|
161
|
+
PayType: 'C',
|
162
|
+
CardParam: {
|
163
|
+
AutoBilling: params[:auto_billing] ? 'Y' : 'N',
|
164
|
+
ExpBillingDays: params[:auto_billing] ? '' : params[:expired_billing_days] || 7,
|
165
|
+
ExpMinutes: params[:expired_minutes] || 10,
|
166
|
+
PayTypeSub: 'ONE'
|
167
|
+
}
|
168
|
+
}
|
169
|
+
)
|
170
|
+
else
|
171
|
+
raise "this payment method is not supported yet!"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def build_request_params(order_params:, service_type:)
|
176
|
+
{
|
177
|
+
Version: "1.0.0",
|
178
|
+
ShopNo: @shop_no,
|
179
|
+
APIService: service_type,
|
180
|
+
Sign: sign(content: order_params),
|
181
|
+
Nonce: get_nonce,
|
182
|
+
Message: encrypt_message(content: order_params)
|
183
|
+
}
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Sinopac::FunBiz
|
2
|
+
module Hash
|
3
|
+
def self.string_xor(str1:, str2:)
|
4
|
+
str1.chars.zip(str2.chars).map { |x, y|
|
5
|
+
(x.to_i(16) ^ y.to_i(16)).to_s(16).upcase
|
6
|
+
}.join
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.hash_id(a1:, a2:, b1:, b2:)
|
10
|
+
a1a2 = string_xor(str1: a1, str2: a2)
|
11
|
+
b1b2 = string_xor(str1: b1, str2: b2)
|
12
|
+
|
13
|
+
"#{a1a2}#{b1b2}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'openssl'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Sinopac::FunBiz
|
6
|
+
module Message
|
7
|
+
def self.iv(nonce:)
|
8
|
+
Digest::SHA256.hexdigest(nonce).upcase[-16..]
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.encrypt(content:, key:, iv:)
|
12
|
+
cipher = OpenSSL::Cipher.new('AES-256-CBC')
|
13
|
+
cipher.encrypt
|
14
|
+
cipher.key = key
|
15
|
+
cipher.iv = iv
|
16
|
+
|
17
|
+
encrypted_message = cipher.update(content.to_json) + cipher.final
|
18
|
+
encrypted_message.unpack('H*').first.upcase
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.decrypt(content:, key:, iv:)
|
22
|
+
cipher = OpenSSL::Cipher.new('AES-256-CBC')
|
23
|
+
cipher.decrypt
|
24
|
+
cipher.key = key
|
25
|
+
cipher.iv = iv
|
26
|
+
|
27
|
+
decrypted_message = cipher.update([content].pack('H*')) + cipher.final
|
28
|
+
JSON.parse(decrypted_message, { symbolize_names: true })
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Sinopac::FunBiz
|
6
|
+
module Nonce
|
7
|
+
def self.get_nonce(shop_no:, end_point:)
|
8
|
+
url = URI("#{end_point}/Nonce")
|
9
|
+
data = { ShopNo: shop_no }.to_json
|
10
|
+
header = { "Content-Type" => "application/json" }
|
11
|
+
|
12
|
+
resp = Net::HTTP.post(url, data, header)
|
13
|
+
|
14
|
+
JSON.parse(resp.body)["Nonce"]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Sinopac::FunBiz
|
2
|
+
class Order
|
3
|
+
attr_accessor :order_no, :amount, :product_name, :currency
|
4
|
+
attr_accessor :memo, :param1, :param2, :param3
|
5
|
+
|
6
|
+
def initialize(order_no:, amount:, product_name:, **params)
|
7
|
+
@order_no = order_no
|
8
|
+
@amount = amount
|
9
|
+
@product_name = product_name
|
10
|
+
@currency = params[:currency] || 'TWD'
|
11
|
+
|
12
|
+
@memo = params[:memo] || ''
|
13
|
+
@param1 = params[:param1] || ''
|
14
|
+
@param2 = params[:param2] || ''
|
15
|
+
@param3 = params[:param3] || ''
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid?
|
19
|
+
@amount > 0 && @order_no != '' && @product_name != ''
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Sinopac::FunBiz
|
2
|
+
class OrderResult
|
3
|
+
attr_reader :shop_no, :status, :description, :order_params
|
4
|
+
attr_reader :transaction_no, :order_no, :amount, :pay_status
|
5
|
+
|
6
|
+
def initialize(result)
|
7
|
+
@shop_no = result[:ShopNo]
|
8
|
+
@status = result[:Status]
|
9
|
+
@description = result[:Description]
|
10
|
+
@order_params = result[:OrderList].first
|
11
|
+
|
12
|
+
@transaction_no = order_params[:TSNo]
|
13
|
+
@order_no = order_params[:OrderNo]
|
14
|
+
case order_params[:PayType]
|
15
|
+
when 'A'
|
16
|
+
@pay_type = :atm
|
17
|
+
when 'C'
|
18
|
+
@pay_type = :credit_card
|
19
|
+
else
|
20
|
+
@pay_type = :unknown
|
21
|
+
end
|
22
|
+
@amount = order_params[:Amount].to_i / 100
|
23
|
+
@pay_status = order_params[:PayStatus]
|
24
|
+
end
|
25
|
+
|
26
|
+
def success?
|
27
|
+
@status == 'S'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Sinopac::FunBiz
|
2
|
+
class Result
|
3
|
+
attr_reader :order_no, :shop_no, :transaction_no, :amount, :status, :description
|
4
|
+
attr_reader :param1, :param2, :param3, :pay_type, :payment_params
|
5
|
+
def initialize(result)
|
6
|
+
@order_no = result[:OrderNo]
|
7
|
+
@shop_no = result[:ShopNo]
|
8
|
+
@transaction_no = result[:TSNo]
|
9
|
+
@amount = result[:Amount] / 100
|
10
|
+
@status = result[:Status]
|
11
|
+
@description = result[:Description]
|
12
|
+
@param1 = result[:Param1]
|
13
|
+
@param2 = result[:Param2]
|
14
|
+
@param3 = result[:Param3]
|
15
|
+
|
16
|
+
case result[:PayType]
|
17
|
+
when 'A'
|
18
|
+
@pay_type = :atm
|
19
|
+
@payment_params = result[:ATMParam]
|
20
|
+
when 'C'
|
21
|
+
@pay_type = :credit_card
|
22
|
+
@payment_params = result[:CardParam]
|
23
|
+
else
|
24
|
+
@pay_type = :unknown
|
25
|
+
@payment_params = {}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def success?
|
30
|
+
@status == 'S'
|
31
|
+
end
|
32
|
+
|
33
|
+
def payment_url
|
34
|
+
case @pay_type
|
35
|
+
when :atm
|
36
|
+
@payment_params[:WebAtmURL]
|
37
|
+
when :credit_card
|
38
|
+
@payment_params[:CardPayURL]
|
39
|
+
else
|
40
|
+
raise 'not supported'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "digest"
|
2
|
+
|
3
|
+
module Sinopac::FunBiz
|
4
|
+
module Sign
|
5
|
+
def self.to_query(content:)
|
6
|
+
content.sort.map { |k, v|
|
7
|
+
unless ([::Hash, ::Array].include?(v.class) || v == '')
|
8
|
+
"#{k}=#{v}"
|
9
|
+
end
|
10
|
+
}.compact.join("&")
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.sign(content:, nonce:, hash_id:)
|
14
|
+
Digest::SHA256.hexdigest("#{to_query(content: content)}#{nonce}#{hash_id}").upcase
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Sinopac::FunBiz
|
2
|
+
class TransactionResult
|
3
|
+
attr_reader :shop_no, :pay_token, :status, :description, :transaction_params
|
4
|
+
attr_reader :transaction_no, :order_no, :amount, :param1, :param2, :param3
|
5
|
+
|
6
|
+
def initialize(result)
|
7
|
+
@shop_no = result[:ShopNo]
|
8
|
+
@pay_token = result[:PayToken]
|
9
|
+
@status = result[:Status]
|
10
|
+
@description = result[:Description]
|
11
|
+
@transaction_params = result[:TSResultContent]
|
12
|
+
@transaction_no = transaction_params[:TSNo]
|
13
|
+
@order_no = transaction_params[:OrderNo]
|
14
|
+
case transaction_params[:PayType]
|
15
|
+
when 'A'
|
16
|
+
@pay_type = :atm
|
17
|
+
when 'C'
|
18
|
+
@pay_type = :credit_card
|
19
|
+
else
|
20
|
+
@pay_type = :unknown
|
21
|
+
end
|
22
|
+
@amount = transaction_params[:Amount].to_i / 100
|
23
|
+
@param1 = transaction_params[:Param1]
|
24
|
+
@param2 = transaction_params[:Param2]
|
25
|
+
@param3 = transaction_params[:Param3]
|
26
|
+
end
|
27
|
+
|
28
|
+
def success?
|
29
|
+
@status == 'S'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/sinopac/funbiz.rb
CHANGED
data/sinopac-funbiz.gemspec
CHANGED
@@ -6,8 +6,8 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.authors = ["eddie"]
|
7
7
|
spec.email = ["eddie@5xcampus.com"]
|
8
8
|
|
9
|
-
spec.summary = %q{API Wrapper for SinoPac FunBiz Payment
|
10
|
-
spec.description = %q{API Wrapper for SinoPac FunBiz Payment
|
9
|
+
spec.summary = %q{API Wrapper for SinoPac FunBiz Payment}
|
10
|
+
spec.description = %q{API Wrapper for SinoPac FunBiz Payment}
|
11
11
|
spec.homepage = "https://kaochenlong.com"
|
12
12
|
spec.license = "MIT"
|
13
13
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
metadata
CHANGED
@@ -1,32 +1,45 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sinopac-funbiz
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- eddie
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: API Wrapper for SinoPac FunBiz Payment
|
13
|
+
description: API Wrapper for SinoPac FunBiz Payment
|
14
14
|
email:
|
15
15
|
- eddie@5xcampus.com
|
16
16
|
executables: []
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
+
- ".env.example"
|
20
21
|
- ".gitignore"
|
21
22
|
- ".rspec"
|
22
23
|
- ".travis.yml"
|
23
24
|
- Gemfile
|
25
|
+
- Gemfile.lock
|
26
|
+
- Guardfile
|
24
27
|
- LICENSE.txt
|
25
28
|
- README.md
|
26
29
|
- Rakefile
|
27
30
|
- bin/console
|
28
31
|
- bin/setup
|
29
32
|
- lib/sinopac/funbiz.rb
|
33
|
+
- lib/sinopac/funbiz/all.rb
|
34
|
+
- lib/sinopac/funbiz/gateway.rb
|
35
|
+
- lib/sinopac/funbiz/hash.rb
|
36
|
+
- lib/sinopac/funbiz/message.rb
|
37
|
+
- lib/sinopac/funbiz/nonce.rb
|
38
|
+
- lib/sinopac/funbiz/order.rb
|
39
|
+
- lib/sinopac/funbiz/order_result.rb
|
40
|
+
- lib/sinopac/funbiz/result.rb
|
41
|
+
- lib/sinopac/funbiz/sign.rb
|
42
|
+
- lib/sinopac/funbiz/transaction_result.rb
|
30
43
|
- lib/sinopac/funbiz/version.rb
|
31
44
|
- sinopac-funbiz.gemspec
|
32
45
|
homepage: https://kaochenlong.com
|
@@ -52,5 +65,5 @@ requirements: []
|
|
52
65
|
rubygems_version: 3.1.6
|
53
66
|
signing_key:
|
54
67
|
specification_version: 4
|
55
|
-
summary: API Wrapper for SinoPac FunBiz Payment
|
68
|
+
summary: API Wrapper for SinoPac FunBiz Payment
|
56
69
|
test_files: []
|