magpie 0.8.6.2 → 0.8.8
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.
- data/README.md +86 -11
- data/Rakefile +7 -0
- data/bin/mag +3 -1
- data/lib/apps.rb +43 -0
- data/lib/magpie.rb +15 -25
- data/lib/magpie/goose.rb +88 -0
- data/lib/magpie/mouse.rb +43 -0
- data/lib/magpie/rubber.rb +16 -0
- data/lib/magpie/server.rb +18 -2
- data/lib/magpie/utils.rb +73 -22
- data/lib/middles/alipay.rb +3 -13
- data/lib/middles/chinabank.rb +3 -13
- data/lib/middles/snake.rb +116 -0
- data/lib/middles/tenpay.rb +22 -0
- data/lib/models/alipay.rb +96 -127
- data/lib/models/chinabank.rb +64 -99
- data/lib/models/dung.rb +66 -0
- data/lib/models/tenpay.rb +89 -0
- data/lib/views/fail.html.erb +12 -0
- data/lib/views/layouts/app.html.erb +42 -0
- data/lib/views/success.html.erb +34 -0
- data/magpie.gemspec +46 -4
- data/test/helper.rb +6 -1
- data/test/partner.yml +3 -0
- data/test/test.log +3152 -0
- data/test/test_alipay.rb +6 -15
- data/test/test_chinabank.rb +13 -5
- data/test/test_dung.rb +80 -0
- data/test/test_object.rb +18 -0
- data/test/test_snake.rb +55 -0
- data/test/test_tenpay.rb +144 -0
- data/test/test_utils.rb +35 -0
- metadata +43 -60
- data/doc/AlipayModel.html +0 -2010
- data/doc/ChinabankModel.html +0 -1245
- data/doc/Magpie.html +0 -255
- data/doc/Magpie/Alipay.html +0 -254
- data/doc/Magpie/Chinabank.html +0 -252
- data/doc/Magpie/Mothlog.html +0 -252
- data/doc/Magpie/Server.html +0 -241
- data/doc/Magpie/Server/Options.html +0 -245
- data/doc/Magpie/Utils.html +0 -85
- data/doc/_index.html +0 -186
- data/doc/class_list.html +0 -36
- data/doc/css/common.css +0 -1
- data/doc/css/full_list.css +0 -53
- data/doc/css/style.css +0 -307
- data/doc/file.COPYING.html +0 -78
- data/doc/file.README.html +0 -162
- data/doc/file_list.html +0 -38
- data/doc/frames.html +0 -13
- data/doc/index.html +0 -162
- data/doc/js/app.js +0 -202
- data/doc/js/full_list.js +0 -149
- data/doc/js/jquery.js +0 -154
- data/doc/method_list.html +0 -499
- data/doc/top-level-namespace.html +0 -90
- data/lib/doc/_index.html +0 -72
- data/lib/doc/class_list.html +0 -36
- data/lib/doc/css/common.css +0 -1
- data/lib/doc/css/full_list.css +0 -53
- data/lib/doc/css/style.css +0 -307
- data/lib/doc/file_list.html +0 -35
- data/lib/doc/frames.html +0 -13
- data/lib/doc/index.html +0 -72
- data/lib/doc/js/app.js +0 -202
- data/lib/doc/js/full_list.js +0 -149
- data/lib/doc/js/jquery.js +0 -154
- data/lib/doc/method_list.html +0 -35
- data/lib/doc/top-level-namespace.html +0 -78
- data/lib/middles/mothlog.rb +0 -33
data/lib/magpie/utils.rb
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'open-uri'
|
|
3
|
+
require 'hpricot'
|
|
4
|
+
require 'iconv'
|
|
2
5
|
require 'net/https'
|
|
3
6
|
require 'uri'
|
|
4
7
|
|
|
5
8
|
module Magpie
|
|
6
9
|
module Utils
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
def dig(env)
|
|
12
|
+
status, header, body = @app.call env
|
|
13
|
+
req = Rack::Request.new env
|
|
14
|
+
doc = send_req_to @pay_gateway, req
|
|
15
|
+
red_text = (doc/@red_xpath).inner_text
|
|
16
|
+
red_text = (doc/@error_xpath).inner_text if red_text.blank? and @error_xpath
|
|
17
|
+
red_text = Iconv.iconv("UTF-8//IGNORE","GBK//IGNORE", red_text).to_s
|
|
18
|
+
return status, header, body, req, red_text
|
|
19
|
+
end
|
|
20
|
+
|
|
9
21
|
def send_req_to(gw, req)
|
|
10
22
|
text = case req.request_method
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
23
|
+
when "GET"; get_query(gw, req.query_string).body
|
|
24
|
+
when "POST"; post_query(gw, req.params).body
|
|
25
|
+
end
|
|
14
26
|
doc = Hpricot text
|
|
15
27
|
end
|
|
16
28
|
|
|
@@ -23,31 +35,50 @@ module Magpie
|
|
|
23
35
|
|
|
24
36
|
def hash_to_xml(h = { })
|
|
25
37
|
h.inject(""){ |xml, (k, v)|
|
|
26
|
-
|
|
27
|
-
Hash
|
|
28
|
-
|
|
38
|
+
case v
|
|
39
|
+
when Hash, String
|
|
40
|
+
xml << "<#{k}>"
|
|
41
|
+
xml << (Hash === v ? hash_to_xml(v) : v)
|
|
42
|
+
xml << "</#{k}>"
|
|
43
|
+
when Array
|
|
44
|
+
v.each{ |vv| xml << hash_to_xml(k => vv)}
|
|
45
|
+
xml
|
|
46
|
+
end
|
|
47
|
+
|
|
29
48
|
}
|
|
30
49
|
end
|
|
31
50
|
|
|
32
51
|
def get_xml_body(env, am, red_text)
|
|
33
|
-
if red_text
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
xml_body = build_xml(:is_success => "F", :errors => am.errors.merge(:final => final_error))
|
|
37
|
-
env["magpie.errors.info"] = am.errors.merge(:final => final_error)
|
|
52
|
+
if red_text.blank?
|
|
53
|
+
notify_res = get_notify_res(am)
|
|
54
|
+
xml_body = build_xml(:payment_success => "Yes", :business => notify_res )
|
|
38
55
|
else
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
env["magpie.notify"] = ["POST", am.notify_url, now.strftime("%d/%b/%Y %H:%M:%S"), now - begin_at, am.notify.inspect, notify_res ]
|
|
43
|
-
xml_body = build_xml(:is_success => "T")
|
|
56
|
+
am.valid?
|
|
57
|
+
xml_body = build_xml(:payment_success => "No", :errors => am.errors.merge(:final => red_text))
|
|
58
|
+
log_errors(am.errors.merge(:final => red_text))
|
|
44
59
|
end
|
|
45
60
|
xml_body
|
|
46
61
|
end
|
|
47
62
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
63
|
+
def get_notify_res(am)
|
|
64
|
+
case am
|
|
65
|
+
when AlipayModel, ChinabankModel
|
|
66
|
+
notify_res = send_notify("POST", am.notify_url, am.notify).gsub(/<[^>]*>|<\/[^>]*> |\s/m, '')
|
|
67
|
+
method = "POST"
|
|
68
|
+
when TenpayModel
|
|
69
|
+
notify_res = send_notify("GET", am.notify_url, am.notify_string).gsub(/<[^>]*>|<\/[^>]*>|\s/m, '')
|
|
70
|
+
method = "GET"
|
|
71
|
+
end
|
|
72
|
+
log_notify(method, am.notify_url, am.notify, notify_res)
|
|
73
|
+
notify_res
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def log_notify(method, notify_url, notify_params, notify_res)
|
|
77
|
+
Magpie.logger.info(FORMAT_NOTIFY % [method, notify_url, Time.now.strftime("%d/%b/%Y %H:%M:%S"), notify_params.inspect, notify_res])
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def log_errors(errors = { })
|
|
81
|
+
Magpie.logger.info(errors.map{ |kv| "%s: %s" % kv }.join("\n"))
|
|
51
82
|
end
|
|
52
83
|
|
|
53
84
|
def start_http(url, req)
|
|
@@ -63,7 +94,6 @@ module Magpie
|
|
|
63
94
|
url = URI.parse(url + "?" + q_string)
|
|
64
95
|
req = Net::HTTP::Get.new("#{url.path}?#{url.query}")
|
|
65
96
|
res = start_http(url, req)
|
|
66
|
-
res.body
|
|
67
97
|
end
|
|
68
98
|
|
|
69
99
|
def post_query(url, params)
|
|
@@ -71,7 +101,28 @@ module Magpie
|
|
|
71
101
|
req = Net::HTTP::Post.new(url.path)
|
|
72
102
|
req.set_form_data params
|
|
73
103
|
res = start_http(url, req)
|
|
74
|
-
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# 向商户系统发送通知
|
|
107
|
+
# @param [String, String, Hash] url是商户系统用来接收通知的url, notify是支付平台发过来的参数
|
|
108
|
+
# @return [String] 如果有异常需要你确认url是否有效
|
|
109
|
+
def send_notify(method, url, notify)
|
|
110
|
+
times = [4, 6, 2]
|
|
111
|
+
Rubber.try(3){|i|
|
|
112
|
+
timeout(times[3-i]) do
|
|
113
|
+
res = case method.to_s.upcase
|
|
114
|
+
when "GET"; get_query(url, notify)
|
|
115
|
+
when "POST"; post_query(url, notify)
|
|
116
|
+
end
|
|
117
|
+
case res
|
|
118
|
+
when Net::HTTPSuccess, Net::HTTPRedirection; res.body
|
|
119
|
+
else
|
|
120
|
+
raise "#{res.class}@#{res.code}"
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
}
|
|
124
|
+
rescue Exception => e
|
|
125
|
+
"发送通知时出现异常#{e}, 请确认#{url}在你的商户系统中可用, 比如#{url}是否可以#{method.upcase}方式接收其他应用的请求"
|
|
75
126
|
end
|
|
76
127
|
|
|
77
128
|
end
|
data/lib/middles/alipay.rb
CHANGED
|
@@ -9,22 +9,12 @@ module Magpie
|
|
|
9
9
|
def initialize(app, pay_gateway = "https://www.alipay.com/cooperate/gateway.do")
|
|
10
10
|
@app = app
|
|
11
11
|
@pay_gateway = pay_gateway
|
|
12
|
+
@red_xpath = "//div[@id='Info']/div[@class='ErrorInfo']/div[@class='Todo']"
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def call(env)
|
|
15
|
-
status, header, body =
|
|
16
|
-
|
|
17
|
-
doc = send_req_to @pay_gateway, req
|
|
18
|
-
red_text = (doc/"//div[@id='Info']/div[@class='ErrorInfo']/div[@class='Todo']").inner_text
|
|
19
|
-
red_text = Iconv.iconv("UTF-8//IGNORE","GBK//IGNORE", red_text).to_s
|
|
20
|
-
am = AlipayModel.new(req.params)
|
|
21
|
-
[status, header, get_xml_body(env, am, red_text)]
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
private
|
|
25
|
-
|
|
26
|
-
def get_final_error(red_text)
|
|
27
|
-
red_text
|
|
16
|
+
status, header, body, req, red_text = dig env
|
|
17
|
+
[status, header, get_xml_body(env, AlipayModel.new(req.params), red_text)]
|
|
28
18
|
end
|
|
29
19
|
|
|
30
20
|
end
|
data/lib/middles/chinabank.rb
CHANGED
|
@@ -9,23 +9,13 @@ module Magpie
|
|
|
9
9
|
def initialize(app, pay_gateway = "https://pay3.chinabank.com.cn/PayGate")
|
|
10
10
|
@app = app
|
|
11
11
|
@pay_gateway = pay_gateway
|
|
12
|
+
@red_xpath = "//strong[@class='red']"
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def call(env)
|
|
15
|
-
status, header, body =
|
|
16
|
-
|
|
17
|
-
doc = send_req_to @pay_gateway, req
|
|
18
|
-
red_text = Iconv.iconv("UTF-8//IGNORE","GBK//IGNORE", (doc/"//strong[@class='red']").inner_text).to_s
|
|
19
|
-
am = ChinabankModel.new(req.params)
|
|
20
|
-
[status, header, get_xml_body(env, am, red_text)]
|
|
16
|
+
status, header, body, req, red_text = dig env
|
|
17
|
+
[status, header, get_xml_body(env, ChinabankModel.new(req.params), red_text)]
|
|
21
18
|
end
|
|
22
19
|
|
|
23
|
-
private
|
|
24
|
-
|
|
25
|
-
def get_final_error(red_text)
|
|
26
|
-
red_text.match(/出错了!(.*)/)[1]
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
|
|
30
20
|
end
|
|
31
21
|
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'erb'
|
|
3
|
+
|
|
4
|
+
module Magpie
|
|
5
|
+
|
|
6
|
+
class Snake
|
|
7
|
+
include Utils
|
|
8
|
+
|
|
9
|
+
def self.reg(snake, target, state)
|
|
10
|
+
proc{ instance_method("#{target}_#{state}").bind(snake).call}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def initialize(app, &block)
|
|
14
|
+
@app = app
|
|
15
|
+
@block = block
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def call(env)
|
|
19
|
+
state, header, body = @app.call(env)
|
|
20
|
+
@block.call(self)
|
|
21
|
+
@req = Rack::Request.new(env)
|
|
22
|
+
@urls[@req.request_method].each { |path, lamb|
|
|
23
|
+
if @req.path_info =~ Regexp.new("^#{path}$")
|
|
24
|
+
body = lamb.call
|
|
25
|
+
break
|
|
26
|
+
end
|
|
27
|
+
}
|
|
28
|
+
[state, header, body]
|
|
29
|
+
rescue Exception => e
|
|
30
|
+
Magpie.logger.info(e.inspect + ":\n" + e.backtrace[0..8].join("\n"))
|
|
31
|
+
[500, header, "500, 请查看日志,了解异常原因"]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def tongue(target, contents = { })
|
|
35
|
+
@urls ||= { "GET" => { }, "POST" => { }}
|
|
36
|
+
states = [contents[:states]].flatten.compact
|
|
37
|
+
route("GET", target, states)
|
|
38
|
+
actions = [contents[:actions]].flatten.compact
|
|
39
|
+
route("POST", target, actions)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def reg(target, state)
|
|
43
|
+
self.class.reg(self, target, state)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def route(method, target, states)
|
|
47
|
+
routes = states.inject({ }){ |h, state|
|
|
48
|
+
url_path = "/#{target}/#{state}"
|
|
49
|
+
h[url_path] = reg(target, state)
|
|
50
|
+
h["/#{target}"] = reg(target, state) if state.to_s == "index"
|
|
51
|
+
h
|
|
52
|
+
}
|
|
53
|
+
@urls[method.to_s.upcase].merge!(routes)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def alipay_index
|
|
57
|
+
@am = AlipayModel.new(@req.params)
|
|
58
|
+
@title = "支付宝-收银台"
|
|
59
|
+
render_success_or_fail
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def chinabank_index
|
|
63
|
+
@am = ChinabankModel.new(@req.params)
|
|
64
|
+
@title = "网银在线-收银台"
|
|
65
|
+
render_success_or_fail
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def tenpay_index
|
|
69
|
+
@am = TenpayModel.new(@req.params)
|
|
70
|
+
@title = "财付通-收银台"
|
|
71
|
+
render_success_or_fail
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def order_pay
|
|
75
|
+
return "支付失败, 缺少足够的参数" if @req.params.blank?
|
|
76
|
+
case @req.params["notify_kind"]
|
|
77
|
+
when "alipay", "chinabank"
|
|
78
|
+
notify_res = send_notify("POST", @req.params["notify_url"], query_to_hash(@req.params["notify"]))
|
|
79
|
+
method = "POST"
|
|
80
|
+
when "tenpay"
|
|
81
|
+
notify_res = send_notify("GET", @req.params["notify_url"], @req.params["notify"])
|
|
82
|
+
method = "GET"
|
|
83
|
+
end
|
|
84
|
+
log_notify(method, @req.params["notify_url"], query_to_hash(@req.params["notify"]), notify_res)
|
|
85
|
+
notify_res
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def render(file_name, options = { })
|
|
91
|
+
layout = options["layout"] || "layouts/app.html.erb"
|
|
92
|
+
file_path = File.join(File.dirname(__FILE__), "../..", "lib", "views", "#{file_name}.html.erb")
|
|
93
|
+
layout_path = File.join(File.dirname(__FILE__), "../..", "lib", "views", layout)
|
|
94
|
+
template = ERB.new(File.read(file_path))
|
|
95
|
+
layout = ERB.new(File.read(layout_path))
|
|
96
|
+
@yield = template.result(binding)
|
|
97
|
+
layout.result(binding)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def query_to_hash(query)
|
|
101
|
+
hash_params = query.split("&").inject({ }){ |h, q| qs = q.split("="); h[qs[0]] = qs[1]; h }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def render_success_or_fail
|
|
105
|
+
if @am.valid?
|
|
106
|
+
@dung = Dung.new(@am)
|
|
107
|
+
render("success")
|
|
108
|
+
else
|
|
109
|
+
log_errors(@am.errors)
|
|
110
|
+
render("fail")
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
require 'models/tenpay'
|
|
3
|
+
|
|
4
|
+
module Magpie
|
|
5
|
+
|
|
6
|
+
class Tenpay
|
|
7
|
+
include Utils
|
|
8
|
+
|
|
9
|
+
def initialize(app, pay_gateway = "http://service.tenpay.com/cgi-bin/v3.0/payservice.cgi")
|
|
10
|
+
@app = app
|
|
11
|
+
@pay_gateway = pay_gateway
|
|
12
|
+
@red_xpath = "//div[@id='error-info']"
|
|
13
|
+
@error_xpath = "//td[@class='font_14']"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def call(env)
|
|
17
|
+
status, header, body, req, red_text = dig env
|
|
18
|
+
[status, header, get_xml_body(env, TenpayModel.new(req.params), red_text)]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/models/alipay.rb
CHANGED
|
@@ -1,151 +1,92 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
include ActiveModel::Validations
|
|
5
|
-
attr_accessor :service,
|
|
6
|
-
:partner,
|
|
7
|
-
:notify_url,
|
|
8
|
-
:return_url,
|
|
9
|
-
:sign,
|
|
10
|
-
:sign_type,
|
|
11
|
-
:subject,
|
|
12
|
-
:out_trade_no,
|
|
13
|
-
:payment_type,
|
|
14
|
-
:show_url,
|
|
15
|
-
:body,
|
|
16
|
-
:price,
|
|
17
|
-
:total_fee,
|
|
18
|
-
:quantity,
|
|
19
|
-
:seller_email,
|
|
20
|
-
:seller_id,
|
|
21
|
-
:_input_charset
|
|
22
|
-
|
|
23
|
-
validates_presence_of :service, :partner, :notify_url, :return_url, :sign, :sign_type, :subject, :out_trade_no, :payment_type
|
|
24
|
-
validates_length_of :partner, :maximum => 16
|
|
25
|
-
validates_length_of :notify_url, :return_url, :maximum => 190
|
|
26
|
-
validates_length_of :show_url, :maximum => 400
|
|
27
|
-
validates_length_of :body, :maximum => 1000
|
|
28
|
-
validates_length_of :out_trade_no, :maximum => 64
|
|
29
|
-
validates_length_of :payment_type, :maximum => 4
|
|
30
|
-
validates_format_of :price, :total_fee,
|
|
31
|
-
:with => /^[0-9]{1,9}\.[0-9]{1,2}$/,
|
|
32
|
-
:allow_blank => true,
|
|
33
|
-
:message => "format should be Number(13, 2)"
|
|
34
|
-
validates_numericality_of :price, :total_fee,
|
|
35
|
-
:greater_than_or_equal_to => 0.01,
|
|
36
|
-
:less_than_or_equal_to => 100000000.00,
|
|
37
|
-
:allow_blank => true,
|
|
38
|
-
:message => "should between 0.01~100000000.00"
|
|
39
|
-
validates_numericality_of :quantity,
|
|
40
|
-
:only_integer => true,
|
|
41
|
-
:greater_than => 0,
|
|
42
|
-
:less_than => 1000000,
|
|
43
|
-
:allow_blank => true,
|
|
44
|
-
:message => "should be integer and between 1~999999"
|
|
45
|
-
validates_inclusion_of :_input_charset, :in => %w(utf-8 gb2312), :message => "should be utf-8 or gb2312", :allow_blank => true
|
|
46
|
-
|
|
47
|
-
validate do |am|
|
|
48
|
-
am.errors[:money] << "price和total_fee不能同时出现" if am.repeat_money?
|
|
49
|
-
am.errors[:money] << "price and total_fee can not both be blank" if am.money_blank?
|
|
50
|
-
am.errors[:quantity] << "if price is not blank, must input quantity" if am.price_missing_quantity?
|
|
51
|
-
am.errors[:seller] << "seller_email and seller_id can not both be blank" if am.seller_blank?
|
|
52
|
-
am.errors[:sign] << "invalid sign" if am.invalid_sign?
|
|
53
|
-
am.errors[:partner] << "not exist" if am.missing_partner?
|
|
54
|
-
end
|
|
3
|
+
module Magpie
|
|
55
4
|
|
|
56
|
-
|
|
57
|
-
@attributes = attributes
|
|
58
|
-
attributes.each do |name, value|
|
|
59
|
-
send("#{name}=", value) if respond_to? name
|
|
60
|
-
end
|
|
61
|
-
end
|
|
5
|
+
class AlipayModel
|
|
62
6
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
end
|
|
7
|
+
include Goose
|
|
8
|
+
include Mouse
|
|
66
9
|
|
|
67
|
-
|
|
68
|
-
self.price.to_s.length > 0 and self.quantity.to_s.length == 0
|
|
69
|
-
end
|
|
10
|
+
set_accounts_kind :alipay
|
|
70
11
|
|
|
71
|
-
|
|
72
|
-
return if self.partner.to_s.length == 0
|
|
73
|
-
self.account == [] ? true : false
|
|
74
|
-
end
|
|
12
|
+
attr_accessor :service, :partner, :notify_url, :return_url, :sign, :sign_type, :subject, :out_trade_no
|
|
75
13
|
|
|
76
|
-
|
|
77
|
-
self.seller_id.to_s.length == 0 and self.seller_email.to_s.length == 0
|
|
78
|
-
end
|
|
14
|
+
attr_accessor :payment_type, :show_url, :body, :price, :total_fee, :quantity, :seller_email, :seller_id
|
|
79
15
|
|
|
80
|
-
|
|
81
|
-
self.price.to_s.length == 0 and self.total_fee.to_s.length == 0
|
|
82
|
-
end
|
|
16
|
+
attr_accessor :_input_charset
|
|
83
17
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
18
|
+
goose_validate :presence_attributes, :length_attributes, :format_attributes do |am|
|
|
19
|
+
am.errors[:money] << "price和total_fee不能同时出现" if am.repeat_money?
|
|
20
|
+
am.errors[:money] << "price and total_fee can not both be blank" if am.money_blank?
|
|
21
|
+
am.errors[:quantity] << "if price is not blank, must input quantity" if am.price_missing_quantity?
|
|
22
|
+
am.errors[:seller] << "seller_email and seller_id can not both be blank" if am.seller_blank?
|
|
23
|
+
am.errors[:sign] << "invalid sign" if am.invalid_sign?
|
|
24
|
+
am.errors[:partner] << "not exist" if !am.partner.blank? and am.missing_partner?
|
|
25
|
+
am.errors[:_input_charset] << "should be utf-8 or gb2312" unless am._input_charset.blank? or %w(utf-8 gb2312).member?(am._input_charset)
|
|
26
|
+
end
|
|
91
27
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
end
|
|
28
|
+
def repeat_money?
|
|
29
|
+
self.price.to_s.length > 0 and self.total_fee.to_s.length > 0
|
|
30
|
+
end
|
|
96
31
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
32
|
+
def price_missing_quantity?
|
|
33
|
+
self.price.to_s.length > 0 and self.quantity.blank?
|
|
34
|
+
end
|
|
100
35
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
end
|
|
36
|
+
def seller_blank?
|
|
37
|
+
self.seller_id.blank? and self.seller_email.blank?
|
|
38
|
+
end
|
|
105
39
|
|
|
40
|
+
def money_blank?
|
|
41
|
+
self.price.blank? and self.total_fee.blank?
|
|
42
|
+
end
|
|
106
43
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
44
|
+
def invalid_sign?
|
|
45
|
+
attrs = @attributes.dup
|
|
46
|
+
attrs.delete("sign")
|
|
47
|
+
attrs.delete("sign_type")
|
|
48
|
+
text = attrs.delete_if{ |k, v| v.blank? }.sort.collect{ |s| s[0] + "=" + URI.decode(s[1]) }.join("&") + self.key
|
|
49
|
+
self.sign == Digest::MD5.hexdigest(text) ? false : true
|
|
50
|
+
end
|
|
113
51
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
52
|
+
def notify
|
|
53
|
+
@notify ||= notify_attrs.inject({ }){ |notify, attr|
|
|
54
|
+
notify[attr] = self.send(attr)
|
|
55
|
+
notify
|
|
56
|
+
}.merge("sign_type" => sign_type, "sign" => notify_sign)
|
|
57
|
+
end
|
|
119
58
|
|
|
120
|
-
private
|
|
121
|
-
def notify_id
|
|
122
|
-
@notify_id ||= Time.now.to_i
|
|
123
|
-
end
|
|
124
59
|
|
|
125
|
-
|
|
126
|
-
@notify_time ||= Time.now.strftime("%Y-%m-%d %H:%M:%S")
|
|
127
|
-
end
|
|
60
|
+
private
|
|
128
61
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
62
|
+
def notify_id
|
|
63
|
+
@notify_id ||= Time.now.to_i
|
|
64
|
+
end
|
|
132
65
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}.join("&") + self.key
|
|
137
|
-
end
|
|
66
|
+
def notify_time
|
|
67
|
+
@notify_time ||= Time.now.strftime("%Y-%m-%d %H:%M:%S")
|
|
68
|
+
end
|
|
138
69
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
70
|
+
def notify_sign
|
|
71
|
+
@notify_sign ||= Digest::MD5.hexdigest(notify_text).downcase
|
|
72
|
+
end
|
|
142
73
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
74
|
+
def notify_text
|
|
75
|
+
@notify_text ||= notify_attrs.sort.collect{ |attr|
|
|
76
|
+
"#{attr}=#{self.send(attr)}"
|
|
77
|
+
}.join("&") + self.key
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def trade_no
|
|
81
|
+
@trade_no ||= Time.now.to_i.to_s + rand(1000000).to_s
|
|
82
|
+
end
|
|
146
83
|
|
|
147
|
-
|
|
148
|
-
|
|
84
|
+
def trade_status
|
|
85
|
+
@trade_status ||= %w(TRADE_FINISHED TRADE_SUCCESS)[rand(2)]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def notify_attrs
|
|
89
|
+
@notify_attrs ||= %w{ notify_id
|
|
149
90
|
notify_time
|
|
150
91
|
trade_no
|
|
151
92
|
out_trade_no
|
|
@@ -166,7 +107,35 @@ class AlipayModel
|
|
|
166
107
|
gmt_refund
|
|
167
108
|
use_coupon
|
|
168
109
|
}.select{ |attr| self.respond_to?(attr, true) && self.send(attr).to_s.length > 0 }
|
|
169
|
-
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def presence_attributes
|
|
114
|
+
[:service, :partner, :notify_url, :return_url, :sign, :sign_type, :subject, :out_trade_no, :payment_type].each {|attr|
|
|
115
|
+
self.errors[attr] << "can't be blank" if self.send(attr).blank?
|
|
116
|
+
}
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def length_attributes
|
|
120
|
+
errors[:partner] << length_error_msg(16) if self.partner.to_s.length > 16
|
|
121
|
+
[:notify_url, :return_url].each { |attr| self.errors[attr] << length_error_msg(190) if self.send(attr).to_s.length > 190}
|
|
122
|
+
errors[:show_url] << length_error_msg(400) if self.show_url.to_s.length > 400
|
|
123
|
+
errors[:body] << length_error_msg(1000) if body.to_s.length > 1000
|
|
124
|
+
errors[:out_trade_no] << length_error_msg(64) if out_trade_no.to_s.length > 64
|
|
125
|
+
errors[:payment_type] << length_error_msg(4) if payment_type.to_s.length > 4
|
|
126
|
+
end
|
|
170
127
|
|
|
128
|
+
def format_attributes
|
|
129
|
+
[:price, :total_fee].each { |attr|
|
|
130
|
+
self.errors[attr] << "format should be Number(13, 2)" unless self.send(attr).blank? or self.send(attr) =~ /^[0-9]{1,9}\.[0-9]{1,2}$/
|
|
131
|
+
}
|
|
132
|
+
self.errors[:quantity] << "should be integer and between 1~999999" unless self.quantity.blank? or self.quantity =~ /^[1-9]{1,6}$/
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def length_error_msg(length)
|
|
136
|
+
"is too long (maximum is #{length} characters)"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
end
|
|
171
140
|
|
|
172
141
|
end
|