kuaiqian 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,58 @@
1
+ 快钱
2
+ ======
3
+
4
+ 用于支持快钱(http://99bill.com/)支付网关的Rails插件。
5
+ 演示站点:http://kqdemo.zaituu.com
6
+ 演示代码:http://github.com/yzhang/kuaiqian_demo
7
+
8
+ 安装
9
+ =======
10
+
11
+ $ script/plugin install git://github.com/yzhang/kuaiqian.git
12
+
13
+ 集成
14
+ =======
15
+
16
+ 1. 安装完成后,插件会自动在你的应用的config目录创建一个kuaiqian.yml文件,默认是快钱提供的测试帐号(关于测试帐号的使用方法请参看测试章节)
17
+ 将kuaiqian.yml中的商户ID和密钥替换为快钱提供给你的真实ID和密钥然后进行下一步。
18
+
19
+ 2. 下面的代码会创建一笔新订单:
20
+
21
+ @request = Kuaiqian::Request.new('产品名称', # 产品名称
22
+ 1, # 订单ID,必须全局唯一
23
+ Time.now.strftime("%Y%m%d%H%M%S"), # 订单生成时间,格式为20091104174132
24
+ 4500, # 订单金额,以分为单位
25
+ 'http://return', # 通知地址,用户支付成功后快钱会通过此地址通知商户支付结果
26
+ '00', # 支付类型,00显示所有方式,10只显示银行卡方式,11只显示电话银行方式,12只显示快钱帐户支付方式,13只显示线下方式
27
+ 'attach') #自定义数据,会在返回URL中原样返回
28
+ redirect_to @request.url
29
+
30
+ 上面的代码会将用户重定向到快钱的支付页面。
31
+
32
+ 3. 在用户完成支付后,快钱会调用你在支付请求中提供的返回URL:
33
+
34
+ @response = Kuaiqian::Response.new(params)
35
+ if @response.successful?
36
+ # 支付成功
37
+ else
38
+ # 支付失败
39
+ end
40
+
41
+ 注意,快钱可能会多次调用你的返回URL,并将结果展现给用户,因此你的代码要考虑多次执行后的输出对用户的有好度。
42
+
43
+ 测试
44
+ =======
45
+
46
+ 要使用快钱提供的测试ID,需要修改你的hosts文件,将快钱的域名指向测试服务器:
47
+
48
+ 218.242.247.5 www.99bill.com
49
+
50
+ 然后使用下面的帐号进行支付:
51
+
52
+ 用户名:kquser02@sina.com
53
+ 密码:99bill
54
+
55
+ ----------------
56
+ 如果在使用中遇到任何的问题或者建议,欢迎和我联系: zhangyuanyi@gmail.com
57
+
58
+ Copyright (c) 2009 Yuanyi Zhang, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ require 'rake'
2
+ require 'rake/rdoctask'
3
+
4
+ desc 'Default: run specs.'
5
+ task :default => :spec
6
+
7
+ desc 'Generate documentation for the kuaiqian plugin.'
8
+ Rake::RDocTask.new(:rdoc) do |rdoc|
9
+ rdoc.rdoc_dir = 'rdoc'
10
+ rdoc.title = 'Tenpay'
11
+ rdoc.options << '--line-numbers' << '--inline-source'
12
+ rdoc.rdoc_files.include('README')
13
+ rdoc.rdoc_files.include('lib/**/*.rb')
14
+ end
15
+
16
+ begin
17
+ require 'jeweler'
18
+ Jeweler::Tasks.new do |s|
19
+ s.name = "kuaiqian"
20
+ s.summary = "A Ruby wrapper of Kauqian(快钱) Payment API"
21
+ s.email = "zhangyuanyi@gmail.com"
22
+ s.homepage = "http://github.com/yzhang/kuaiqian"
23
+ s.description = "A Ruby wrapper of Kauqian(快钱) Payment API"
24
+ s.authors = ["Yuanyi Zhang"]
25
+ s.files = FileList["[A-Z]*", "{lib}/**/*", '.gitignore']
26
+ end
27
+ rescue LoadError
28
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
29
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,11 @@
1
+ require 'rails/generators'
2
+
3
+ class KuaiqianGenerator < Rails::Generators::Base
4
+ def install_douban
5
+ copy_file("kuaiqian.yml", 'config/kuaiqian.yml')
6
+ end
7
+
8
+ def self.source_root
9
+ File.join(File.dirname(__FILE__), 'templates')
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ test:
2
+ spid: '1001153656201'
3
+ key: 'ZUZNJB8MF63GA83J'
4
+ development:
5
+ spid: '1001153656201'
6
+ key: 'ZUZNJB8MF63GA83J'
7
+ production:
8
+ spid: '1001153656201'
9
+ key: 'ZUZNJB8MF63GA83J'
data/lib/kuaiqian.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'kuaiqian/config'
2
+ require 'kuaiqian/request'
3
+ require 'kuaiqian/response'
@@ -0,0 +1,18 @@
1
+ module Kuaiqian
2
+ class Config
3
+ class << self
4
+ def spid; config['spid']; end
5
+ def key; config['key']; end
6
+
7
+ def config
8
+ @@config ||= lambda do
9
+ require 'yaml'
10
+ filename = "#{Rails.root}/config/kuaiqian.yml"
11
+ file = File.open(filename)
12
+ yaml = YAML.load(file)
13
+ return yaml[Rails.env]
14
+ end.call
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,73 @@
1
+ require 'digest/md5'
2
+ require 'cgi'
3
+ require 'iconv'
4
+
5
+ module Kuaiqian
6
+ class Request
7
+ GATEWAY_URL = "https://www.99bill.com/gateway/recvMerchantInfoAction.htm"
8
+ PARAMS = %w(inputCharset bgUrl version language signType merchantAcctId payerName payerContactType payerContact orderId orderAmount orderTime productName productNum productId productDesc ext1 ext2 payType redoFlag pid)
9
+
10
+ def initialize(product_name, order_id, order_time, total_fee,
11
+ return_url, pay_type='00', attach=nil, payer_name='用户')
12
+ @bank_type = 0
13
+ @fee_type = 1
14
+
15
+ @order_id = order_id.to_s
16
+ @total_fee = total_fee.to_i.to_s
17
+ @order_time = order_time.strftime("%Y%m%d%H%M%S")
18
+ @product_name = product_name
19
+
20
+ @pay_type = pay_type
21
+ @return_url = return_url
22
+ @ext1 = attach || ''
23
+
24
+ @payer_name = payer_name
25
+ end
26
+
27
+ def url
28
+ "#{GATEWAY_URL}?#{html_params}&signMsg=#{sign_msg}"
29
+ end
30
+
31
+ def input_charset; '1'; end
32
+ def bg_url; @return_url; end
33
+ def page_url; ''; end
34
+ def version; 'v2.0'; end
35
+ def language; '1'; end
36
+ def sign_type; '1'; end
37
+ def merchant_acct_id; Kuaiqian::Config.spid; end
38
+ def payer_name; @payer_name; end
39
+ def payer_contact_type; '1'; end
40
+ def payer_contact; ''; end
41
+ def key; Kuaiqian::Config.key; end
42
+ def order_id; @order_id; end
43
+ def order_amount; @total_fee; end
44
+ def order_time; @order_time; end
45
+ def product_name; @product_name; end
46
+ def product_num; '1'; end
47
+ def product_id; ''; end
48
+ def product_desc; ''; end
49
+ def ext1; @ext1; end
50
+ def ext2; ''; end
51
+ def pay_type; @pay_type; end
52
+ def redo_flag; "0"; end
53
+ def pid; ''; end
54
+
55
+ def sign_params
56
+ (PARAMS + ['key']).map do |param|
57
+ value = send(param.underscore)
58
+ value == '' ? nil : "#{param}=#{value}"
59
+ end.compact.join('&')
60
+ end
61
+
62
+ def sign_msg
63
+ Digest::MD5.hexdigest(sign_params).upcase
64
+ end
65
+
66
+ def html_params
67
+ PARAMS.map do |param|
68
+ value = send(param.underscore)
69
+ value == '' ? nil : "#{param}=#{CGI.escape(value)}"
70
+ end.compact.join('&')
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,61 @@
1
+ require 'digest/md5'
2
+ require 'cgi'
3
+ require 'iconv'
4
+
5
+ module Kuaiqian
6
+ class Response
7
+ attr_reader :order_id, :total_fee, :attach, :pay_time
8
+
9
+ BANK_NAMES = {'ICBC' => '中国工商银行', 'CMB' => '招商银行', 'CCB' => '中国建设银行',
10
+ 'ABC' => '中国农业银行', 'BOC_SH' => '中国银行(上海)', 'BOC_GZ' => '中国银行(广州)',
11
+ 'SPDB' => '上海浦东发展银行', 'BCOM' => '交通银行', 'CMBC' => '中国民生银行',
12
+ 'SDB' => '深圳发展银行', 'GDB' => '广东发展银行', 'CITIC' => '中信银行',
13
+ 'HXB' => '华夏银行', 'CIB' => '兴业银行', 'GZRCC' => '广州市农村信用合作社',
14
+ 'GZCB' => '广州市商业银行', 'SHRCC' => '上海农村商业银行', 'CPSRB' => '中国邮政储蓄',
15
+ 'CEB' => '中国光大银行', 'BOB' => '北京银行', 'CBHB' => '渤海银行',
16
+ 'BJRCB' => '北京农村商业银行', 'CNPY' => '中国银联'}
17
+
18
+ SIGN_PARAMS = %w(merchantAcctId version language signType payType bankId orderId orderTime orderAmount dealId bankDealId dealTime payAmount fee ext1 ext2 payResult errCode key)
19
+ def initialize(params)
20
+ @params = params
21
+ end
22
+
23
+ def successful?
24
+ pay_result == '10' && valid_sign?
25
+ end
26
+
27
+ def valid_sign?
28
+ sign_msg == Digest::MD5.hexdigest(sign_params).upcase
29
+ end
30
+
31
+ def sign_params
32
+ SIGN_PARAMS.map do |param|
33
+ value = send(param.underscore)
34
+ value == '' ? nil : "#{param}=#{value}"
35
+ end.compact.join('&')
36
+ end
37
+
38
+ def version; @params[:version]; end
39
+ def language; @params[:language]; end
40
+ def sign_type; @params[:signType]; end
41
+ def merchant_acct_id; @params[:merchantAcctId]; end
42
+ def key; Kuaiqian::Config.key; end
43
+ def order_id; @params[:orderId]; end
44
+ def order_amount; @params[:orderAmount]; end
45
+ def order_time; @params[:orderTime]; end
46
+ def deal_id; @params[:dealId]; end
47
+ def bank_deal_id; @params[:bankDealId]; end
48
+ def deal_time; @params[:dealTime]; end
49
+ def pay_amount; @params[:payAmount]; end
50
+ def fee; @params[:fee]; end
51
+ def attach; @params[:ext1]; end
52
+ def ext1; @params[:ext1]; end
53
+ def ext2; @params[:ext1]; end
54
+ def pay_result; @params[:payResult]; end
55
+ def err_code; @params[:errCode]; end
56
+ def sign_msg; @params[:signMsg]; end
57
+ def pay_type; @params[:payType]; end
58
+ def bank_id; @params[:bankId]; end
59
+ def bank_name; BANK_NAMES[bank_id]; end
60
+ end
61
+ end
@@ -0,0 +1,105 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment")
3
+ require 'spec'
4
+ require "kuaiqian"
5
+
6
+ describe Kuaiqian::Request do
7
+ before do
8
+ Kuaiqian::Config.stub!(:spid).and_return('1001153656201')
9
+ Kuaiqian::Config.stub!(:key).and_return('ZUZNJB8MF63GA83J')
10
+
11
+ time = Time.local(2009, 10, 28, 12, 03, 45)
12
+ @request = Kuaiqian::Request.new('productName', '20091028120345', time,
13
+ 2, 'http://return', '00')
14
+ @order_time = "20091028120345"
15
+
16
+ @valid_params = "inputCharset=1&bgUrl=http%3A%2F%2Freturn&version=v2.0&language=1&signType=1&merchantAcctId=1001153656201&payerName=payerName&payerContactType=1&orderId=20091028120345&orderAmount=2&orderTime=20091028120345&productName=productName&productNum=1&payType=00&redoFlag=0"
17
+ @valid_sign_params = "inputCharset=1&bgUrl=http://return&version=v2.0&language=1&signType=1&merchantAcctId=1001153656201&payerName=payerName&payerContactType=1&orderId=20091028120345&orderAmount=2&orderTime=20091028120345&productName=productName&productNum=1&payType=00&redoFlag=0&key=ZUZNJB8MF63GA83J"
18
+ end
19
+
20
+ describe "url generation" do
21
+ it "should generate sign_params correctly" do
22
+ @request.sign_params.should == @valid_sign_params
23
+ end
24
+
25
+ it "should construct url params correctly" do
26
+ @request.params.should == @valid_params
27
+ end
28
+ end
29
+
30
+ describe "basic params" do
31
+ it "should set input charset to 1" do
32
+ @request.input_charset.should == '1'
33
+ end
34
+
35
+ it "should set page url empty" do
36
+ @request.page_url.should == ''
37
+ end
38
+
39
+ it "should set bg_url properly" do
40
+ @request.bg_url.should == 'http://return'
41
+ end
42
+
43
+ it "should set version to v2.0" do
44
+ @request.version.should == 'v2.0'
45
+ end
46
+
47
+ it "should set language to 1" do
48
+ @request.language.should == '1'
49
+ end
50
+
51
+ it "should set signType to '1'" do
52
+ @request.sign_type.should == '1'
53
+ end
54
+
55
+ it "should set merchantAcctId properly" do
56
+ @request.merchant_acct_id.should == '1001153656201'
57
+ end
58
+
59
+ it "should set payer info empty" do
60
+ @request.payer_name.should == 'payerName'
61
+ @request.payer_contact_type.should == '1'
62
+ @request.payer_contact.should == ''
63
+ end
64
+
65
+ it "should set key properly" do
66
+ @request.key.should == 'ZUZNJB8MF63GA83J'
67
+ end
68
+
69
+ it "should set order id properly" do
70
+ @request.order_id.should == '20091028120345'
71
+ end
72
+
73
+ it "should set order amount properly" do
74
+ @request.order_amount.should == '2'
75
+ end
76
+
77
+ it "should set order time properly" do
78
+ @request.order_time.should == '20091028120345'
79
+ end
80
+
81
+ it "should set product info properly" do
82
+ @request.product_name.should == 'productName'
83
+ @request.product_num.should == '1'
84
+ @request.product_id.should == ''
85
+ @request.product_desc.should == ''
86
+ end
87
+
88
+ it "should set ext properly" do
89
+ @request.ext1.should == ''
90
+ @request.ext2.should == ''
91
+ end
92
+
93
+ it "should set payType properly" do
94
+ @request.pay_type.should == '00'
95
+ end
96
+
97
+ it "should set redo flag to zero" do
98
+ @request.redo_flag.should == '0'
99
+ end
100
+
101
+ it "should set pid empty" do
102
+ @request.pid.should == ''
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,75 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment")
3
+ require 'spec'
4
+ require "kuaiqian"
5
+
6
+ describe Kuaiqian::Response do
7
+ before(:each) do
8
+ Kuaiqian::Config.stub!(:spid).and_return('1001153656201')
9
+ Kuaiqian::Config.stub!(:key).and_return('ZUZNJB8MF63GA83J')
10
+ end
11
+
12
+ it "should be a valid response with valid params" do
13
+ response = Kuaiqian::Response.new(params)
14
+ response.should be_successful
15
+ end
16
+
17
+ it "should be an invalid response with wrong pay result" do
18
+ response = Kuaiqian::Response.new(params(:payResult => '00'))
19
+ response.should_not be_successful
20
+ end
21
+
22
+ it "should be an invalid response with wrong sign msg" do
23
+ response = Kuaiqian::Response.new(params(:signMsg => 'wrong'))
24
+ response.should_not be_successful
25
+ end
26
+
27
+ def params(options={})
28
+ {
29
+ :merchantAcctId => "1001153656201",
30
+ :payAmount =>"100",
31
+ :bankId => "",
32
+ :language => "1",
33
+ :orderId =>"20091103164410",
34
+ :id => "1",
35
+ :signType =>"1",
36
+ :orderTime =>"20091103164410",
37
+ :payResult =>"10",
38
+ :version =>"v2.0",
39
+ :payType =>"12",
40
+ :fee =>"1",
41
+ :dealId =>"5696344",
42
+ :bankDealId =>"",
43
+ :dealTime =>"20091104004452",
44
+ :errCode =>"",
45
+ :signMsg =>"361A184B9157BBEAA3627B1B0D6412D6",
46
+ :ext1 =>"",
47
+ :orderAmount =>"100",
48
+ :ext2 =>""
49
+ }.merge(options)
50
+ end
51
+
52
+ # def params(options={})
53
+ # {:merchantAcctId => 'testid',
54
+ # :version => 'v2.0',
55
+ # :language => '1',
56
+ # :signType => '1',
57
+ # :payType => '00',
58
+ # :bankId => 'ICBC',
59
+ # :orderId => '1',
60
+ # :orderTime => '20091021123200',
61
+ # :orderAmount => '4500',
62
+ # :dealId => 'testdealid',
63
+ # :bankDealId => 'testbankdeal',
64
+ # :dealTime => '20091021123203',
65
+ # :payAmount => '4500',
66
+ # :fee => '100',
67
+ # :ext1 => 'nil',
68
+ # :ext2 => '',
69
+ # :payResult => '10',
70
+ # :errCode => '',
71
+ # :key => '',
72
+ # :signMsg => '1D060818424C1335C157B1FA5A9A7551'
73
+ # }.merge(options)
74
+ # end
75
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kuaiqian
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Yuanyi Zhang
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-04 00:00:00 +08:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: "A Ruby wrapper of Kauqian(\xE5\xBF\xAB\xE9\x92\xB1) Payment API"
22
+ email: zhangyuanyi@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README
29
+ files:
30
+ - MIT-LICENSE
31
+ - README
32
+ - Rakefile
33
+ - VERSION
34
+ - lib/generators/kuaiqian/kuaiqian_generator.rb
35
+ - lib/generators/kuaiqian/templates/kuaiqian.yml
36
+ - lib/kuaiqian.rb
37
+ - lib/kuaiqian/config.rb
38
+ - lib/kuaiqian/request.rb
39
+ - lib/kuaiqian/response.rb
40
+ has_rdoc: true
41
+ homepage: http://github.com/yzhang/kuaiqian
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options:
46
+ - --charset=UTF-8
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.6
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: "A Ruby wrapper of Kauqian(\xE5\xBF\xAB\xE9\x92\xB1) Payment API"
70
+ test_files:
71
+ - spec/request_spec.rb
72
+ - spec/response_spec.rb