unionpei 1.1.0 → 1.2.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.
@@ -1,328 +1,309 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'singleton'
4
4
  require 'logger'
5
5
  require 'net/https'
6
6
  require 'uri'
7
7
  require 'base64'
8
- require "zlib"
8
+ require 'zlib'
9
9
  require_relative 'sdk_config'
10
10
  require_relative 'cert_util'
11
11
 
12
-
13
12
  module UnionPei
14
13
  class SDKUtil
15
-
16
- def SDKUtil.post(url, content)
17
- LogUtil.info("post url:["+url+"]")
18
- LogUtil.info("post content:["+content+"]")
14
+ def self.post(url, content)
15
+ LogUtil.info("post url:[#{url}]")
16
+ LogUtil.info("post content:[#{content}]")
19
17
  uri = URI.parse(url)
20
18
  http = Net::HTTP.new(uri.host, uri.port)
21
- http.use_ssl = true if uri.scheme == "https"
22
- if !SDKConfig.instance.ifValidateRemoteCert
23
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
24
- end
19
+ http.use_ssl = true if uri.scheme == 'https'
20
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless SDKConfig.instance.ifValidateRemoteCert
25
21
  res = http.post(uri.path, content).body.force_encoding(SDKConfig.instance.encoding)
26
- LogUtil.info('resp:['+res+']')
27
- return res
22
+ LogUtil.info("resp:[#{res}]")
23
+ res
28
24
  end
29
25
 
30
- def SDKUtil.createLinkString(para, sort, encode)
31
- linkString = ""
26
+ def self.createLinkString(para, sort, encode)
27
+ linkString = ''
32
28
  keys = para.keys
33
- if sort
34
- keys = keys.sort
35
- end
36
- for key in keys
29
+ keys = keys.sort if sort
30
+ keys.each do |key|
37
31
  value = para[key]
38
32
  # print(key + ":" + value)
39
- if encode
40
- value = URI.encode_www_form_component(value)
41
- end
33
+ value = URI.encode_www_form_component(value) if encode
42
34
  # print(str(type(key))+":"+str(type(value))+":"+str(key)+":"+str(value))
43
- linkString = linkString + key + "=" + value + "&"
35
+ linkString = "#{linkString}#{key}=#{value}&"
44
36
  end
45
- linkString = linkString[0, linkString.length - 1]
37
+ linkString[0, linkString.length - 1]
46
38
  # print (linkString)
47
- return linkString
48
39
  end
49
40
 
50
- def SDKUtil.filterNoneValue(para)
41
+ def self.filterNoneValue(para)
51
42
  keys = para.keys
52
- for key in keys
43
+ keys.each do |key|
53
44
  value = para[key]
54
- if !value or value == ""
55
- para.delete(key)
56
- end
45
+ para.delete(key) if !value || (value == '')
57
46
  end
58
47
  end
59
48
 
60
- def SDKUtil.buildSignature(req, signCertPath=SDKConfig.instance.signCertPath, signCertPwd=SDKConfig.instance.signCertPwd, secureKey=SDKConfig.instance.secureKey)
61
-
49
+ def self.buildSignature(req, signCertPath = SDKConfig.instance.signCertPath, signCertPwd = SDKConfig.instance.signCertPwd, secureKey = SDKConfig.instance.secureKey)
62
50
  SDKUtil.filterNoneValue(req)
63
- if !req["signMethod"]
64
- LogUtil.error("signMethod must not null")
51
+ unless req['signMethod']
52
+ LogUtil.error('signMethod must not null')
65
53
  return nil
66
54
  end
67
- if !req["version"]
68
- LogUtil.error("version must not null")
55
+ unless req['version']
56
+ LogUtil.error('version must not null')
69
57
  return nil
70
58
  end
71
- if "01" == req["signMethod"]
72
- req["certId"] = CertUtil.getSignCertId(signCertPath, signCertPwd)
73
- LogUtil.info("=== start to sign ===")
59
+ if req['signMethod'] == '01'
60
+ req['certId'] = CertUtil.getSignCertId(signCertPath, signCertPwd)
61
+ LogUtil.info('=== start to sign ===')
74
62
  prestr = SDKUtil.createLinkString(req, true, false)
75
- LogUtil.info("sorted: [" + prestr + "]")
63
+ LogUtil.info("sorted: [#{prestr}]")
76
64
  prestr = SDKUtil.sha256(prestr)
77
- LogUtil.info("sha256: [" + prestr + "]")
78
- LogUtil.info("sign cert: [" + signCertPath + "], pwd: [" + signCertPwd + "]")
65
+ LogUtil.info("sha256: [#{prestr}]")
66
+ LogUtil.info("sign cert: [#{signCertPath}], pwd: [#{signCertPwd}]")
79
67
  key = CertUtil.getSignPriKey(signCertPath, signCertPwd)
80
68
  signature = Base64.encode64(key.sign('sha256', prestr)).gsub(/\n|\r/, '')
81
- LogUtil.info("signature: [" + signature + "]")
82
- elsif "11" == req["signMethod"]
83
- LogUtil.info("=== start to sign ===")
69
+ LogUtil.info("signature: [#{signature}]")
70
+ elsif req['signMethod'] == '11'
71
+ LogUtil.info('=== start to sign ===')
84
72
  prestr = createLinkString(req, true, false)
85
- LogUtil.info("sorted: [" + prestr + "]")
73
+ LogUtil.info("sorted: [#{prestr}]")
86
74
  if secureKey.nil?
87
- LogUtil.error("secureKey must not null")
75
+ LogUtil.error('secureKey must not null')
88
76
  return nil
89
77
  end
90
- prestr = prestr + "&" + sha256(secureKey)
91
- LogUtil.debug("before final sha256: [" + prestr + "]")
78
+ prestr = "#{prestr}&#{sha256(secureKey)}"
79
+ LogUtil.debug("before final sha256: [#{prestr}]")
92
80
  signature = SDKUtil.sha256(prestr)
93
- LogUtil.info("signature: [" + signature + "]")
94
- elsif "12" == ["signMethod"]
95
- LogUtil.error("sm3算法暂未实现,请勿使用。")
81
+ LogUtil.info("signature: [#{signature}]")
82
+ elsif '12' == ['signMethod']
83
+ LogUtil.error('sm3算法暂未实现,请勿使用。')
96
84
  return nil
97
85
  else
98
- LogUtil.info("invalid signMethod: [" + req["signMethod"].to_s + "]")
86
+ LogUtil.info("invalid signMethod: [#{req['signMethod']}]")
99
87
  end
100
- LogUtil.info("=== end of sign ===")
101
- req["signature"] = signature
102
- return signature
88
+ LogUtil.info('=== end of sign ===')
89
+ req['signature'] = signature
90
+ signature
103
91
  end
104
92
 
105
- def SDKUtil.paraFilter(para)
93
+ def self.paraFilter(para)
106
94
  result = {}
107
- for key in para.keys
108
- if (key == "signature" or para[key] == "")
95
+ para.each_key do |key|
96
+ if (key == 'signature') || (para[key] == '')
109
97
  next
110
98
  else
111
99
  result[key] = para[key]
112
100
  end
113
101
  end
114
- return result
102
+ result
115
103
  end
116
104
 
117
- def SDKUtil.sha256(data)
118
- OpenSSL::Digest::SHA256.digest(data).unpack("H*")[0].downcase
105
+ def self.sha256(data)
106
+ OpenSSL::Digest::SHA256.digest(data).unpack1('H*').downcase
119
107
  end
120
108
 
121
- def SDKUtil.putKeyValueToMap(temp, isKey, key, m, decode)
109
+ def self.putKeyValueToMap(temp, isKey, key, m, decode)
122
110
  if isKey
123
- m[key.to_s] = ""
111
+ m[key.to_s] = ''
124
112
  else
125
- if decode
126
- temp = URI.decode_www_form_component(temp)
127
- end
113
+ temp = URI.decode_www_form_component(temp) if decode
128
114
  m[key.to_s] = temp
129
115
  end
130
116
  end
131
117
 
132
- def SDKUtil.parseQString(respString, decode=false)
118
+ def self.parseQString(respString, decode = false)
133
119
  resp = {}
134
- temp = ""
135
- key = ""
120
+ temp = ''
121
+ key = ''
136
122
  isKey = true
137
- isOpen = false;
138
- openName = "\0";
123
+ isOpen = false
124
+ openName = "\0"
139
125
 
140
- for curChar in respString.split("") #遍历整个带解析的字符串
141
- if (isOpen)
142
- if (curChar == openName)
143
- isOpen = false
144
- end
145
- temp = temp + curChar
146
- elsif (curChar == "{")
126
+ respString.split('').each do |curChar| # 遍历整个带解析的字符串
127
+ if isOpen
128
+ isOpen = false if curChar == openName
129
+ temp += curChar
130
+ elsif curChar == '{'
147
131
  isOpen = true
148
- openName = "}"
149
- temp = temp + curChar
150
- elsif (curChar == "[")
132
+ openName = '}'
133
+ temp += curChar
134
+ elsif curChar == '['
151
135
  isOpen = true
152
- openName = "]"
153
- temp = temp + curChar
154
- elsif (isKey and curChar == "=")
136
+ openName = ']'
137
+ temp += curChar
138
+ elsif isKey && (curChar == '=')
155
139
  key = temp
156
- temp = ""
140
+ temp = ''
157
141
  isKey = false
158
- elsif (curChar == "&" and not isOpen) # 如果读取到&分割符
142
+ elsif (curChar == '&') && !isOpen # 如果读取到&分割符
159
143
  SDKUtil.putKeyValueToMap(temp, isKey, key, resp, decode)
160
- temp = ""
144
+ temp = ''
161
145
  isKey = true
162
146
  else
163
- temp = temp + curChar
147
+ temp += curChar
164
148
  end
165
149
  end
166
150
  SDKUtil.putKeyValueToMap(temp, isKey, key, resp, decode)
167
- return resp
151
+ resp
168
152
  end
169
153
 
170
- def SDKUtil.verify(resp)
171
- if !resp["signMethod"]
172
- LogUtil.error("signMethod must not null")
154
+ def self.verify(resp)
155
+ unless resp['signMethod']
156
+ LogUtil.error('signMethod must not null')
173
157
  return nil
174
158
  end
175
- if !resp["version"]
176
- LogUtil.error("version must not null")
159
+ unless resp['version']
160
+ LogUtil.error('version must not null')
177
161
  return nil
178
162
  end
179
- if !resp["signature"]
180
- LogUtil.error("signature must not null")
163
+ unless resp['signature']
164
+ LogUtil.error('signature must not null')
181
165
  return nil
182
166
  end
183
- signMethod = resp["signMethod"]
184
- version = resp["version"]
167
+ signMethod = resp['signMethod']
168
+ version = resp['version']
185
169
  result = false
186
- if "01" == signMethod
187
- LogUtil.info("=== start to verify signature ===")
188
- signature = resp.delete("signature")
189
- LogUtil.info("signature: [" + signature + "]")
170
+ case signMethod
171
+ when '01'
172
+ LogUtil.info('=== start to verify signature ===')
173
+ signature = resp.delete('signature')
174
+ LogUtil.info("signature: [#{signature}]")
190
175
  prestr = SDKUtil.createLinkString(resp, true, false)
191
- LogUtil.info("sorted: [" + prestr + "]")
176
+ LogUtil.info("sorted: [#{prestr}]")
192
177
  prestr = SDKUtil.sha256(prestr)
193
- LogUtil.info("sha256: [" + prestr + "]")
194
- key = CertUtil.verifyAndGetVerifyKey(resp["signPubKeyCert"])
178
+ LogUtil.info("sha256: [#{prestr}]")
179
+ key = CertUtil.verifyAndGetVerifyKey(resp['signPubKeyCert'])
195
180
  if !key
196
- LogUtil.info("no cert was found by signPubKeyCert: " + resp["signPubKeyCert"])
181
+ LogUtil.info("no cert was found by signPubKeyCert: #{resp['signPubKeyCert']}")
197
182
  result = false
198
183
  else
199
184
  signature = Base64.decode64(signature)
200
- result = key.verify("sha256", signature, prestr)
185
+ result = key.verify('sha256', signature, prestr)
201
186
  end
202
- LogUtil.info("verify signature " + (result ? "succeed" : "fail"))
203
- LogUtil.info("=== end of verify signature ===")
204
- return result
205
- elsif "11" == signMethod or "12" == signMethod
206
- return SDKUtil.verifyBySecureKey(resp, SDKConfig.instance.secureKey)
187
+ LogUtil.info("verify signature #{result ? 'succeed' : 'fail'}")
188
+ LogUtil.info('=== end of verify signature ===')
189
+ result
190
+ when '11', '12'
191
+ SDKUtil.verifyBySecureKey(resp, SDKConfig.instance.secureKey)
207
192
  else
208
- LogUtil.info("Error signMethod [" + signMethod + "] in validate. ")
209
- return false
193
+ LogUtil.info("Error signMethod [#{signMethod}] in validate. ")
194
+ false
210
195
  end
211
196
  end
212
197
 
213
- def SDKUtil.verifyBySecureKey(resp, secureKey)
214
- if resp["signMethod"].nil?
215
- LogUtil.error("signMethod must not null")
198
+ def self.verifyBySecureKey(resp, secureKey)
199
+ if resp['signMethod'].nil?
200
+ LogUtil.error('signMethod must not null')
216
201
  return nil
217
202
  end
218
- if resp["signature"].nil?
219
- LogUtil.error("signature must not null")
203
+ if resp['signature'].nil?
204
+ LogUtil.error('signature must not null')
220
205
  return nil
221
206
  end
222
- signMethod = resp["signMethod"]
207
+ signMethod = resp['signMethod']
223
208
  result = false
224
- LogUtil.info("=== start to verify signature ===")
225
- if "11" == signMethod
226
- signature = resp.delete("signature")
227
- LogUtil.info("signature: [" + signature+ "]")
209
+ LogUtil.info('=== start to verify signature ===')
210
+ case signMethod
211
+ when '11'
212
+ signature = resp.delete('signature')
213
+ LogUtil.info("signature: [#{signature}]")
228
214
  prestr = createLinkString(resp, true, false)
229
- LogUtil.info("sorted: [" + prestr + "]")
230
- beforeSha256 = prestr + "&" + sha256(secureKey)
231
- LogUtil.debug("before final sha256: [" + beforeSha256 + "]")
215
+ LogUtil.info("sorted: [#{prestr}]")
216
+ beforeSha256 = "#{prestr}&#{sha256(secureKey)}"
217
+ LogUtil.debug("before final sha256: [#{beforeSha256}]")
232
218
  afterSha256 = sha256(beforeSha256)
233
219
  result = (afterSha256 == signature)
234
- if !result
235
- LogUtil.debug("after final sha256: [" + afterSha256 + "]")
236
- end
237
- elsif "12" == signMethod
238
- LogUtil.error("sm3算法暂未实现,请勿使用。")
220
+ LogUtil.debug("after final sha256: [#{afterSha256}]") unless result
221
+ when '12'
222
+ LogUtil.error('sm3算法暂未实现,请勿使用。')
239
223
  else
240
- LogUtil.info("Error signMethod [" + signMethod.to_s + "] in validate. ")
224
+ LogUtil.info("Error signMethod [#{signMethod}] in validate. ")
241
225
  end
242
- LogUtil.info("verify signature " + (result ? "succeed" : "fail"))
243
- LogUtil.info("=== end of verify signature ===")
244
- return result
226
+ LogUtil.info("verify signature #{result ? 'succeed' : 'fail'}")
227
+ LogUtil.info('=== end of verify signature ===')
228
+ result
245
229
  end
246
230
 
247
- def SDKUtil.createAutoFormHtml(params, reqUrl)
248
- result = "<html><head> <meta http-equiv=\"Content-Type\" content=\"text/html; charset=" + SDKConfig.instance.encoding + "\" /></head><body onload=\"javascript:document.pay_form.submit();\"> <form id=\"pay_form\" name=\"pay_form\" action=\"" + reqUrl + "\" method=\"post\">"
249
- for key in params.keys
231
+ def self.createAutoFormHtml(params, reqUrl)
232
+ result = "<html><head> <meta http-equiv=\"Content-Type\" content=\"text/html; charset=#{SDKConfig.instance.encoding}\" /></head><body onload=\"javascript:document.pay_form.submit();\"> <form id=\"pay_form\" name=\"pay_form\" action=\"#{reqUrl}\" method=\"post\">"
233
+ params.each_key do |key|
250
234
  value = params[key]
251
- result += " <input type=\"hidden\" name=\"" + key + "\" id=\"" + key +"\" value=\""+ value +"\" />\n"
235
+ result += " <input type=\"hidden\" name=\"#{key}\" id=\"#{key}\" value=\"#{value}\" />\n"
252
236
  end
253
- result += "<!-- <input type=\"submit\" type=\"hidden\">--> </form></body></html>"
254
- LogUtil.info("auto post html:" + result)
255
- return result
237
+ result += '<!-- <input type="submit" type="hidden">--> </form></body></html>'
238
+ LogUtil.info("auto post html:#{result}")
239
+ result
256
240
  end
257
241
 
258
- def SDKUtil.encryptPub(data, certPath=SDKConfig.instance.encryptCertPath)
242
+ def self.encryptPub(data, certPath = SDKConfig.instance.encryptCertPath)
259
243
  rsaKey = CertUtil.getEncryptKey(certPath)
260
244
  result = rsaKey.public_encrypt(data)
261
- result = Base64.encode64(result).gsub(/\n|\r/, '')
262
- return result
245
+ Base64.encode64(result).gsub(/\n|\r/, '')
263
246
  end
264
247
 
265
- def SDKUtil.decryptPri(data, certPath=SDKConfig.instance.signCertPath, certPwd=SDKConfig.instance.signCertPwd)
248
+ def self.decryptPri(data, certPath = SDKConfig.instance.signCertPath, certPwd = SDKConfig.instance.signCertPwd)
266
249
  pkey = CertUtil.getDecryptPriKey(certPath, certPwd)
267
250
  data = Base64.decode64(data)
268
- result = pkey.private_decrypt(data)
269
- return result
251
+ pkey.private_decrypt(data)
270
252
  end
271
253
 
272
- def SDKUtil.deCodeFileContent(params, fileDirectory)
273
- if !params["fileContent"]
274
- return false
275
- end
276
- LogUtil.info("---------处理后台报文返回的文件---------")
277
- fileContent = params["fileContent"]
278
- if !fileContent
279
- LogUtil.info("文件内容为空")
254
+ def self.deCodeFileContent(params, fileDirectory)
255
+ return false unless params['fileContent']
256
+
257
+ LogUtil.info('---------处理后台报文返回的文件---------')
258
+ fileContent = params['fileContent']
259
+ unless fileContent
260
+ LogUtil.info('文件内容为空')
280
261
  return false
281
262
  end
282
263
  fileContent = Zlib::Inflate.inflate(Base64.decode64(fileContent))
283
264
  filePath = ''
284
- if !params["fileName"]
285
- LogUtil.info("文件名为空")
286
- filePath = fileDirectory + "/" + params["merId"] + "_" + params["batchNo"] + "_" + params["txnTime"] + ".txt"
265
+ if !params['fileName']
266
+ LogUtil.info('文件名为空')
267
+ filePath = "#{fileDirectory}/#{params['merId']}_#{params['batchNo']}_#{params['txnTime']}.txt"
287
268
  else
288
- filePath = fileDirectory + "/" + params['fileName']
269
+ filePath = "#{fileDirectory}/#{params['fileName']}"
289
270
  end
290
271
  output = File.new(filePath, 'w')
291
- if !output
292
- LogUtil.error "Unable to open file!"
272
+ unless output
273
+ LogUtil.error 'Unable to open file!'
293
274
  return false
294
275
  end
295
276
  output.syswrite(fileContent)
296
- LogUtil.info "文件位置 >:" + filePath
277
+ LogUtil.info "文件位置 >:#{filePath}"
297
278
  output.close
298
- return true
279
+ true
299
280
  end
300
281
 
301
- def SDKUtil.enCodeFileContent(path)
282
+ def self.enCodeFileContent(path)
302
283
  fileContent = IO.binread(path)
303
284
  fileContent = Base64.encode64(Zlib::Deflate.deflate(fileContent)).gsub(/\n|\r/, '')
304
285
  end
305
286
 
306
- def SDKUtil.getEncryptCert(params)
307
- if params['encryptPubKeyCert'].nil? or params['certType'].nil?
308
- LogUtil.error("encryptPubKeyCert or certType is null")
287
+ def self.getEncryptCert(params)
288
+ if params['encryptPubKeyCert'].nil? || params['certType'].nil?
289
+ LogUtil.error('encryptPubKeyCert or certType is null')
309
290
  return -1
310
291
  end
311
292
  strCert = params['encryptPubKeyCert']
312
293
  certType = params['certType']
313
294
 
314
295
  x509Cert = CertUtil.getX509Cert(strCert)
315
- if "01" == certType
296
+ case certType
297
+ when '01'
316
298
  # 更新敏感信息加密公钥
317
- if x509Cert.serial.to_s == CertUtil.getEncryptCertId
318
- return 0
319
- end
299
+ return 0 if x509Cert.serial.to_s == CertUtil.getEncryptCertId
300
+
320
301
  localCertPath = SDKConfig.instance.encryptCertPath
321
302
  newLocalCertPath = SDKUtil.genBackupName(localCertPath)
322
303
  # 将本地证书进行备份存储
323
304
  File.rename(localCertPath, newLocalCertPath)
324
- f = File.new(localCertPath, "w")
325
- if !f
305
+ f = File.new(localCertPath, 'w')
306
+ unless f
326
307
  LogUtil.error 'Unable to open file!'
327
308
  return -1
328
309
  end
@@ -330,23 +311,20 @@ module UnionPei
330
311
  f.close
331
312
  LogUtil.info('save new encryptPubKeyCert success')
332
313
  CertUtil.resetEncryptCertPublicKey
333
- return 1
334
- elsif "02" == certType
335
- return 0
314
+ 1
315
+ when '02'
316
+ 0
336
317
  else
337
- LogUtil.error("unknown cerType:"+certType)
338
- return -1
318
+ LogUtil.error("unknown cerType:#{certType}")
319
+ -1
339
320
  end
340
321
  end
341
322
 
342
- def SDKUtil.genBackupName(fileName)
323
+ def self.genBackupName(fileName)
343
324
  i = fileName.rindex('.')
344
325
  leftFileName = fileName[0, i]
345
326
  rightFileName = fileName[i + 1, fileName.length - i]
346
- newFileName = leftFileName + '_backup' + '.' + rightFileName
347
- return newFileName
327
+ "#{leftFileName}_backup.#{rightFileName}"
348
328
  end
349
329
  end
350
330
  end
351
-
352
-
@@ -1,9 +1,5 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module UnionPei
4
- class Version
5
- def self.to_str
6
- "1.1.0"
7
- end
8
- end
4
+ VERSION = '1.2.0'
9
5
  end
data/lib/unionpei.rb CHANGED
@@ -1,4 +1,4 @@
1
- module UnionPei; end
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'unionpei/version'
4
4
  require 'unionpei/sdk_config'
@@ -6,4 +6,7 @@ require 'unionpei/log_util'
6
6
  require 'unionpei/cert_util'
7
7
  require 'unionpei/sdk_util'
8
8
  require 'unionpei/acp_service'
9
- require 'unionpei/payment'
9
+ require 'unionpei/payment'
10
+
11
+ module UnionPei
12
+ end
data/readme.txt ADDED
@@ -0,0 +1,25 @@
1
+ UnionPei - 非官方银联支付(UnionPay)SDK,使用MIT协议。
2
+
3
+ 免责声明
4
+
5
+ 本Gem对以下非官方代码进行封装和改造:
6
+ https://open.unionpay.com/tjweb/support/faq/mchlist?id=38
7
+ 代码仅供参考学习,生产环境请自行封装代码。
8
+
9
+ 参考文档
10
+
11
+ 银联测试参数:https://open.unionpay.com/tjweb/user/mchTest/param
12
+ 测试说明:https://open.unionpay.com/tjweb/support/faq/mchlist?id=516
13
+ 证书说明:https://open.unionpay.com/tjweb/support/faq/mchlist?id=21
14
+ API文档:https://open.unionpay.com/tjweb/acproduct/APIList?apiservId=448&acpAPIId=754&bussType=0
15
+ SDK下载:https://open.unionpay.com/tjweb/support/faq/mchlist?id=38
16
+ 测试卡信息:https://open.unionpay.com/tjweb/support/faq/mchlist?id=4
17
+ B2B:https://open.unionpay.com/tjweb/acproduct/list?apiSvcId=452&index=999
18
+
19
+ 快速开始(rails)
20
+
21
+ class PaymentsController < ApplicationController
22
+ def union_pay
23
+ render html: UnionPei::Payment.b2c.html_safe
24
+ end
25
+ end
data/unionpei.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'unionpei/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'unionpei'
9
+ s.version = UnionPei::VERSION
10
+ s.summary = 'An unofficial unionpay gem'
11
+ s.description = 'An unofficial unionpay gem'
12
+ s.authors = ['memorycancel', 'tianlu1677']
13
+ s.email = 'memorycancel@gmail.com'
14
+ s.files = `git ls-files -z`.split("\x0").reject do |f|
15
+ f.match(%r{^(test|spec|features)/})
16
+ end
17
+ s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
+ s.require_paths = ['lib']
19
+
20
+ s.homepage = 'https://rubygems.org/gems/unionpei'
21
+ s.license = 'MIT'
22
+ s.add_runtime_dependency 'iniparse'
23
+ s.add_runtime_dependency 'jruby-openssl' if RUBY_PLATFORM == 'java'
24
+ s.add_runtime_dependency 'openssl' if RUBY_PLATFORM == 'ruby'
25
+
26
+ s.add_development_dependency 'bundler'
27
+ s.add_development_dependency 'minitest'
28
+ s.add_development_dependency 'pry'
29
+ s.add_development_dependency 'rake'
30
+ s.add_development_dependency 'webmock'
31
+ end