suning_pay 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.1
5
+ before_install: gem install bundler -v 1.15.2
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at tuminfei1981@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in suning_pay.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 tarzansos
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # SuningPay
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/suning_pay`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'suning_pay'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install suning_pay
22
+
23
+ Add init file (suning_pay.rb) to Rails config/initializers
24
+
25
+ rake suning_pay:init:create
26
+
27
+ ## API-委托代收
28
+
29
+ 1. 签约请求_发送短信接口
30
+ 2. 签约请求_验证短信接口
31
+ 3. 签约请求接口(易付宝不发短信)
32
+ 4. 解约请求接口
33
+ 5. 支付订单请求(已签约)
34
+ 6. 支付订单查询接口
35
+ 7. 支持银行查询接口
36
+
37
+ ```
38
+ SuningPay::Service.post_send_msg
39
+ SuningPay::Service.post_validate_sign
40
+ SuningPay::Service.post_sign
41
+ SuningPay::Service.post_cancel
42
+ SuningPay::Service.post_pay
43
+ SuningPay::Service.post_query_merchant_order
44
+ SuningPay::Service.post_query_channel
45
+ ```
46
+
47
+ ## API-企业批量付款
48
+
49
+ 1. 批量转账下单接口
50
+ 2. 批量出款到卡接口
51
+ 3. 转账批次查询接口
52
+ 4. 出款批次查询接口
53
+
54
+ ```
55
+ SuningPay::EntService.post_transfer_acquire
56
+ SuningPay::EntService.post_withdraw
57
+ SuningPay::EntService.post_transfer_query
58
+ SuningPay::EntService.post_withdraw_query
59
+ ```
60
+
61
+ ## Usage
62
+
63
+ TODO: Write usage instructions here
64
+
65
+ ## Development
66
+
67
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
68
+
69
+ 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).
70
+
71
+ ## Contributing
72
+
73
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/suning_pay. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
74
+
75
+ ## License
76
+
77
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
78
+
79
+ ## Code of Conduct
80
+
81
+ Everyone interacting in the SuningPay project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/suning_pay/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ import "./lib/tasks/suning_pay.rake"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "suning_pay"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/bin/suning_pay ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env ruby
@@ -0,0 +1,13 @@
1
+ require 'fileutils'
2
+
3
+ namespace :suning_pay do
4
+ namespace :init do
5
+ desc "Generate suning_pay init file from example"
6
+ task :create do
7
+ source = File.join(Gem.loaded_specs["suning_pay"].full_gem_path, "suning_pay.rb")
8
+ target = File.join(Rails.root, "config", "initializers", "suning_pay.rb")
9
+ FileUtils.cp_r source, target
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,164 @@
1
+ #encoding: utf-8
2
+ require 'json/ext'
3
+
4
+ module SuningPay
5
+ class EntService
6
+ CURRENCY_CNY = 'CNY'
7
+ PAY_CHARGE_MODE_OUT = '01'
8
+ PAY_CHARGE_MODE_IN = '02'
9
+ PAY_CHARGE_MODE_TRAN = '03'
10
+ ACCOUNT_TYPE_PERSON = 'PERSON'
11
+ ACCOUNT_TYPE_CORP = 'CORP'
12
+
13
+ #1.批量转账下单接口
14
+ # batch_list格式为交易数组。
15
+ # [
16
+ # [转账流水号1, 收款方易付宝登录名, 收款方商户号, 收款方姓名, 转账金额, 收款方类型, 备注信息, 订单名称],
17
+ # [转账流水号2, 收款方易付宝登录名, 收款方商户号, 收款方姓名, 转账金额, 收款方类型, 备注信息, 订单名称],
18
+ # ..
19
+ # ]
20
+ def self.post_transfer_acquire(batch_no, product_code, charge_mode, goods_type, batch_order_name, batch_list = [], notify_url = nil, tunnel_data = nil, options = {})
21
+
22
+ raise ArgumentError, "Argument batch_list error" if batch_list.nil? or batch_list.empty?
23
+
24
+ raise ArgumentError, "Argument batch_list count limit 1000" if batch_list.size > 1000
25
+
26
+ body = {}
27
+ detail_data = []
28
+ #合计交易数据
29
+ total_num = batch_list.size
30
+ total_amount = 0
31
+ batch_list.each {|x| total_amount += x[4]}
32
+ raise ArgumentError, "Argument batch_list total_amount limit 100000000000 yuan" if total_amount > 10000000000000
33
+
34
+ batch_list.each do |tran|
35
+ detail_line = {
36
+ "serialNo" => tran[0],
37
+ "receiverLoginName" => tran[1],
38
+ "receiverNo" => tran[2],
39
+ "receiverName" => tran[3],
40
+ "amount" => tran[4],
41
+ "receiverType" => tran[5],
42
+ "remark" => tran[6],
43
+ "orderName" => tran[7]
44
+ }
45
+ detail_data << detail_line
46
+ end
47
+
48
+ #body参数
49
+ body = {
50
+ :batchNo => batch_no,
51
+ :merchantNo => SuningPay.merchant_no,
52
+ :productCode => product_code,
53
+ :totalNum => total_num,
54
+ :totalAmount => total_amount,
55
+ :currency => SuningPay::EntService::CURRENCY_CNY,
56
+ :chargeMode => charge_mode,
57
+ :payDate => Time.now.strftime("%Y%m%d"),
58
+ :tunnelData => tunnel_data,
59
+ :detailData => detail_data,
60
+ :goodsType => goods_type,
61
+ :batchOrderName => batch_order_name,
62
+ :notifyUrl => notify_url
63
+ }
64
+
65
+ input_hash = {:merchantNo => SuningPay.merchant_no,
66
+ :body => body.to_json.to_s.gsub("\\", '')}
67
+ post_params = SuningPay.ent_options.merge(options).merge(input_hash)
68
+
69
+ #调用查询接口
70
+ msg = SuningPay::Util.send_post('transferAcquire.htm', post_params, SuningPay::API_CODE_TRANSFER)
71
+ msg
72
+ end
73
+
74
+ #2.批量出款到卡接口
75
+ # batch_list格式为交易数组。
76
+ # [
77
+ # [流水号1, 收款方卡号, 收款方户名, 收款方类型, 收款方币种, 开户行名称, 开户行编号, 开户行省, 开户行市, 联行号, 付款金额, 备注, 订单名称],
78
+ # [流水号2, 收款方卡号, 收款方户名, 收款方类型, 收款方币种, 开户行名称, 开户行编号, 开户行省, 开户行市, 联行号, 付款金额, 备注, 订单名称],
79
+ # ..
80
+ # ]
81
+ def self.post_withdraw(batch_no, product_code, charge_mode, goods_type, batch_order_name, batch_list = [], notify_url = nil, tunnel_data = nil, options = {})
82
+
83
+ raise ArgumentError, "Argument batch_list error" if batch_list.nil? or batch_list.empty?
84
+
85
+ raise ArgumentError, "Argument batch_list count limit 1000" if batch_list.size > 1000
86
+
87
+ body = {}
88
+ detail_data = []
89
+ #合计交易数据
90
+ total_num = batch_list.size
91
+ total_amount = 0
92
+ batch_list.each {|x| total_amount += x[10]}
93
+ raise ArgumentError, "Argument batch_list total_amount limit 100000000000 yuan" if total_amount > 10000000000000
94
+
95
+ batch_list.each do |tran|
96
+ detail_line = {
97
+ "serialNo" => tran[0],
98
+ "receiverCardNo" => tran[1],
99
+ "receiverName" => tran[2],
100
+ "receiverType" => tran[3],
101
+ "receiverCurrency" => tran[4],
102
+ "bankName" => tran[5],
103
+ "bankCode" => tran[6],
104
+ "bankProvince" => tran[7],
105
+ "bankCity" => tran[8],
106
+ "payeeBankLinesNo" => tran[9],
107
+ "amount" => tran[10],
108
+ "remark" => tran[11],
109
+ "orderName" => tran[12]
110
+ }
111
+ detail_data << detail_line
112
+ end
113
+ #body参数
114
+ body = {
115
+ :batchNo => batch_no,
116
+ :merchantNo => SuningPay.merchant_no,
117
+ :productCode => product_code,
118
+ :totalNum => total_num,
119
+ :totalAmount => total_amount,
120
+ :currency => SuningPay::EntService::CURRENCY_CNY,
121
+ :chargeMode => charge_mode,
122
+ :payDate => Time.now.strftime("%Y%m%d"),
123
+ :tunnelData => tunnel_data,
124
+ :detailData => detail_data,
125
+ :goodsType => goods_type,
126
+ :batchOrderName => batch_order_name,
127
+ :notifyUrl => notify_url
128
+ }
129
+
130
+ input_hash = {:merchantNo => SuningPay.merchant_no,
131
+ :body => body.to_json.to_s.gsub("\\", '')}
132
+ post_params = SuningPay.ent_options.merge(options).merge(input_hash)
133
+
134
+ #调用查询接口
135
+ msg = SuningPay::Util.send_post('withdraw.htm', post_params, SuningPay::API_CODE_TRANSFER_CARD)
136
+ msg
137
+ end
138
+
139
+ #3.转账批次查询接口
140
+ def self.post_transfer_query(batch_no, pay_merchant_no, options = {})
141
+ input_hash = {:merchantNo => SuningPay.merchant_no,
142
+ :batchNo => batch_no,
143
+ :payMerchantNo => pay_merchant_no}
144
+ post_params = SuningPay.ent_options.merge(options).merge(input_hash)
145
+
146
+ #调用查询接口
147
+ msg = SuningPay::Util.send_post('transferQuery.htm', post_params, SuningPay::API_CODE_TRANSFER)
148
+ msg
149
+ end
150
+
151
+ #4.出款批次查询接口
152
+ def self.post_withdraw_query(batch_no, pay_merchant_no, options = {})
153
+ input_hash = {:merchantNo => SuningPay.merchant_no,
154
+ :batchNo => batch_no,
155
+ :payMerchantNo => pay_merchant_no}
156
+ post_params = SuningPay.ent_options.merge(options).merge(input_hash)
157
+
158
+ #调用查询接口
159
+ msg = SuningPay::Util.send_post('withdrawQuery.htm', post_params, SuningPay::API_CODE_TRANSFER_CARD)
160
+ msg
161
+ end
162
+
163
+ end
164
+ end
@@ -0,0 +1,6 @@
1
+ #encoding: utf-8
2
+ class SuningPay::Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ load 'rake/suning_pay.rake'
5
+ end
6
+ end
@@ -0,0 +1,73 @@
1
+ #encoding: utf-8
2
+ module SuningPay
3
+ module RSA
4
+ #SuningPay 提供的KEY长度为2048
5
+ MAX_ENCRYPT_LENGTH = 245
6
+ MAX_DECRYPT_LENGTH = 256
7
+ #MAX_ENCRYPT_LENGTH = 117
8
+ #MAX_DECRYPT_LENGTH = 128
9
+
10
+ #分段加密:加密后结果转16进制
11
+ def self.encrypt_msg(key, message)
12
+ bytes_array = message.unpack("C*")
13
+ input_length = bytes_array.length
14
+ encryt_str, offset, i = "", 0, 0
15
+ begin
16
+ encryt_bytes = bytes_array[offset, MAX_ENCRYPT_LENGTH]
17
+ encryt_str << key.public_encrypt(encryt_bytes.pack("C*")) #加密
18
+ offset = (i += 1) * MAX_ENCRYPT_LENGTH
19
+ end while input_length - offset > 0
20
+
21
+ encryt_str.unpack("H*")[0].upcase
22
+ #Base64::strict_encode64(encryt_str)
23
+ end
24
+
25
+ #分段解密:解密前转回2进制
26
+ def self.decrypt_msg(key, message)
27
+ #bytes_array = Base64::decode64 message
28
+ message_arr = [message]
29
+ bytes_array = message_arr.pack("H*")
30
+
31
+ input_length = bytes_array.length
32
+ decryt_str, offset, i = "", 0, 0
33
+ begin
34
+ decryt_bytes = bytes_array[offset, MAX_DECRYPT_LENGTH]
35
+ decryt_str << key.private_decrypt(decryt_bytes) #解密
36
+ offset = (i += 1) * MAX_DECRYPT_LENGTH
37
+ end while input_length - offset > 0
38
+
39
+ decryt_str
40
+ end
41
+
42
+ #分段加密:加密后Base64
43
+ def self.encrypt_base64_msg(key, message)
44
+ bytes_array = message.unpack("C*")
45
+ input_length = bytes_array.length
46
+ encryt_str, offset, i = "", 0, 0
47
+ begin
48
+ encryt_bytes = bytes_array[offset, MAX_ENCRYPT_LENGTH]
49
+ encryt_str << key.public_encrypt(encryt_bytes.pack("C*")) #加密
50
+ offset = (i += 1) * MAX_ENCRYPT_LENGTH
51
+ end while input_length - offset > 0
52
+
53
+ Base64::strict_encode64(encryt_str)
54
+ end
55
+
56
+ #分段解密:解密前Base64解码
57
+ def self.decrypt_base64_msg(key, message)
58
+ bytes_array = Base64::decode64 message
59
+
60
+ input_length = bytes_array.length
61
+ decryt_str, offset, i = "", 0, 0
62
+ begin
63
+ decryt_bytes = bytes_array[offset, MAX_DECRYPT_LENGTH]
64
+ decryt_str << key.private_decrypt(decryt_bytes) #解密
65
+ offset = (i += 1) * MAX_DECRYPT_LENGTH
66
+ end while input_length - offset > 0
67
+
68
+ decryt_str
69
+ end
70
+
71
+ end
72
+ end
73
+
@@ -0,0 +1,104 @@
1
+ #encoding: utf-8
2
+ module SuningPay
3
+ class Service
4
+ CURRENCY_CNY = 'CNY'
5
+ PAYTYPE_IM = '01'
6
+
7
+ #1.签约请求_发送短信接口
8
+ def self.post_send_msg(bank_code, card_type, card_info, tunnel_data=nil, options = {})
9
+ #加密cardinfo
10
+ suning_pub_key = SuningPay.api_suning_public_key
11
+ encr_msg = SuningPay::RSA.encrypt_msg(suning_pub_key, card_info)
12
+
13
+ input_hash = {:bankCode => bank_code,
14
+ :cardType => card_type,
15
+ :cardInfo => encr_msg,
16
+ :tunnelData => Base64.urlsafe_encode64(tunnel_data)}
17
+
18
+ post_params = SuningPay.client_options.merge(options).merge(input_hash)
19
+ #调用查询接口
20
+ msg = SuningPay::Util.send_post('sendMsg', post_params)
21
+ msg
22
+ end
23
+
24
+ #2.签约请求_验证短信接口
25
+ def self.post_validate_sign(smg_code, serial_no, tunnel_data=nil, options = {})
26
+ input_hash = {:smgCode => smg_code,
27
+ :serialNo => serial_no,
28
+ :tunnelData => Base64.urlsafe_encode64(tunnel_data)}
29
+ post_params = SuningPay.client_options.merge(options).merge(input_hash)
30
+ #调用查询接口
31
+ msg = SuningPay::Util.send_post('validateSign', post_params)
32
+ msg
33
+ end
34
+
35
+ #3.签约请求接口(易付宝不发短信)
36
+ def self.post_sign(bank_code, card_type, card_info, tunnel_data=nil, options = {})
37
+ #加密cardinfo
38
+ suning_pub_key = SuningPay.api_suning_public_key
39
+ encr_msg = SuningPay::RSA.encrypt_msg(suning_pub_key, card_info)
40
+
41
+ input_hash = {:bankCode => bank_code,
42
+ :cardType => card_type,
43
+ :cardInfo => encr_msg,
44
+ :tunnelData => Base64.urlsafe_encode64(tunnel_data)}
45
+
46
+ post_params = SuningPay.client_options.merge(options).merge(input_hash)
47
+ #调用查询接口
48
+ msg = SuningPay::Util.send_post('sign', post_params)
49
+
50
+ end
51
+
52
+ #4.解约请求接口
53
+ def self.post_cancel(contract_no, tunnel_data=nil, options = {})
54
+ input_hash = {:contractNo => contract_no,
55
+ :tunnelData => Base64.urlsafe_encode64(tunnel_data)}
56
+ post_params = SuningPay.client_options.merge(options).merge(input_hash)
57
+ #调用查询接口
58
+ msg = SuningPay::Util.send_post('cancel', post_params)
59
+ msg
60
+ end
61
+
62
+ #5.支付订单请求
63
+ def self.post_pay(contract_no, out_order_no, order_type, order_amount, order_time, saler_merchant_no, goods_type, goods_name, pay_timeout, remark, tunnel_data=nil, options = {})
64
+ input_hash = {:contractNo => contract_no,
65
+ :outOrderNo => out_order_no,
66
+ :orderType => order_type,
67
+ :orderAmount => order_amount,
68
+ :orderTime => order_time,
69
+ :currency => CURRENCY_CNY,
70
+ :salerMerchantNo => saler_merchant_no,
71
+ :goodsType => goods_type,
72
+ :goodsName => Base64.urlsafe_encode64(goods_name),
73
+ :payTimeout => pay_timeout,
74
+ :remark => remark,
75
+ :tunnelData => Base64.urlsafe_encode64(tunnel_data)}
76
+
77
+ post_params = SuningPay.client_options.merge(options).merge(input_hash)
78
+ #调用查询接口
79
+ msg = SuningPay::Util.send_post('pay', post_params)
80
+ msg
81
+ end
82
+
83
+ #6.支付订单查询接口
84
+ def self.post_query_merchant_order(out_order_no, order_time, options = {})
85
+ input_hash = {:outOrderNo => out_order_no,
86
+ :orderTime => order_time}
87
+
88
+ post_params = SuningPay.client_options.merge(options).merge(input_hash)
89
+ #调用查询接口
90
+ msg = SuningPay::Util.send_post('queryMerchantOrder.do', post_params, SuningPay::API_CODE_Q_PAY)
91
+ msg
92
+ end
93
+
94
+ #7.支持银行查询接口
95
+ def self.post_query_channel(product_code, options = {})
96
+ input_hash = {:productCode => product_code}
97
+ post_params = SuningPay.client_options.merge(options).merge(input_hash)
98
+ #调用查询接口
99
+ msg = SuningPay::Util.send_post('queryChannel', post_params)
100
+ msg
101
+ end
102
+
103
+ end
104
+ end
@@ -0,0 +1,73 @@
1
+ #encoding: utf-8
2
+ require 'logger'
3
+
4
+ module SuningPay
5
+ class Util
6
+ #生成md5摘要信息
7
+ def self.get_summary(params)
8
+ #排序
9
+ data_hash = sorted_hash(params)
10
+ #拼接
11
+ data_arr = []
12
+ data_hash.each do |k,v|
13
+ data_arr << k.to_s + '=' + v.to_s
14
+ end
15
+ data_str = data_arr.join('&')
16
+ #MD5摘要
17
+ data_md5 = Digest::MD5.hexdigest(data_str).upcase
18
+ data_md5
19
+ end
20
+
21
+ #生成带摘要签名的查询参数
22
+ def self.signature_param(prams, summary)
23
+ #私钥加密
24
+ private_key = SuningPay.api_client_private_key
25
+ sign = private_key.sign('sha1',summary.force_encoding("utf-8"))
26
+ #Base64编码后取出后'-'
27
+ signature = Base64.urlsafe_encode64(sign).gsub!(/=+$/, "")
28
+ data_sign = {:signature => signature, :signAlgorithm => 'RSA'}
29
+ params_signed = prams.merge(data_sign)
30
+ params_signed
31
+ end
32
+
33
+ #排序
34
+ def self.sorted_hash(in_hash)
35
+ return in_hash.sort{|a,b| a.to_s <=> b.to_s }
36
+ end
37
+
38
+ #发送请求
39
+ def self.send_post(func_name, func_params_hash, api_code=SuningPay::API_CODE_PAY)
40
+ api_url = ''
41
+
42
+ case api_code
43
+ when SuningPay::API_CODE_PAY
44
+ api_url = SuningPay.api_base_url + func_name
45
+ when SuningPay::API_CODE_Q_PAY
46
+ api_url = SuningPay.api_query_base_url + func_name
47
+ when SuningPay::API_CODE_TRANSFER
48
+ api_url = SuningPay.api_tranfer_url + func_name
49
+ when SuningPay::API_CODE_TRANSFER_CARD
50
+ api_url = SuningPay.api_card_tranfer_url + func_name
51
+ else
52
+ api_url = SuningPay.api_base_url + func_name
53
+ end
54
+
55
+ #对params就行摘要并签名
56
+ summary = get_summary(func_params_hash)
57
+ #加签名的查询参数
58
+ func_params = signature_param(func_params_hash, summary)
59
+ if SuningPay.debug_mode
60
+ logger = Logger.new('suning_pay.log')
61
+ logger.info('--------------SUNING PAY DEBUG--------------')
62
+ logger.info("URL:#{api_url.to_s}")
63
+ logger.info("PARAMS:#{func_params.to_s}")
64
+ end
65
+
66
+ conn = Faraday.new(:url => api_url)
67
+
68
+ response = conn.post '', func_params
69
+ html_response = response.body
70
+ html_response
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,3 @@
1
+ module SuningPay
2
+ VERSION = "0.2.0"
3
+ end