alipay_global 0.0.1

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.
@@ -0,0 +1,34 @@
1
+ require 'open-uri'
2
+
3
+ module AlipayGlobal
4
+ module Service
5
+ module Exchange
6
+
7
+ def self.current_rates
8
+ exchange_rates_resp = {}
9
+ open(build_request) do |file|
10
+ file.each_line do |line|
11
+ line = line.strip
12
+ rate_results = line.split("|")
13
+
14
+ exchange_rates_resp[rate_results[2]] = {
15
+ time: DateTime.strptime("#{rate_results[0]} #{rate_results[1]}","%Y%m%d %H%M%S"),
16
+ rate: rate_results[3].to_f
17
+ }
18
+ end
19
+ end
20
+ exchange_rates_resp
21
+ end
22
+
23
+ def self.build_request
24
+ params = {
25
+ 'service' => 'forex_rate_file',
26
+ 'partner' => AlipayGlobal.api_partner_id,
27
+ }
28
+
29
+ AlipayGlobal::Service.request_uri(params).to_s
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,18 @@
1
+ require 'open-uri'
2
+
3
+ module AlipayGlobal
4
+ module Service
5
+ module Notification
6
+
7
+ def self.check(params)
8
+ params = {
9
+ 'service' => 'notify_verify',
10
+ 'partner' => AlipayGlobal.api_partner_id,
11
+ }.merge(params)
12
+
13
+ Net::HTTP.get(AlipayGlobal::Service.request_uri(params,false))
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,73 @@
1
+ require 'open-uri'
2
+
3
+ module AlipayGlobal
4
+ module Service
5
+ module Reconciliation
6
+
7
+ RECONCILIATION_REQUIRED_PARAMS = %w( start_date end_date )
8
+
9
+ RECONCILIATION_ERROR_MESSAGES = [
10
+ "Over 10 days to Date period",
11
+ "Over limit balance amount record",
12
+ "System exception",
13
+ "<alipay><is_success>F</is_success><error>ILLEGAL_PARTNER</error></alipay>",
14
+ "Finish date not ahead of today",
15
+ "Finish date ahead of begin date",
16
+ "Illegal Date period!",
17
+ "Date format incorrect YYYYMMDD",
18
+ "Internet connected exception ,please try later"
19
+ ]
20
+
21
+ def self.request(params)
22
+ reconciliation_resp = []
23
+ open(build_request(params)) do |data|
24
+ results = data.read
25
+
26
+ return false if results.include? "No balance account data in the period"
27
+ raise ArgumentError, "#{results}" if error_check(results)
28
+
29
+ results.each_line do |line|
30
+ line = line.strip
31
+ transaction = line.split("|")
32
+
33
+ reconciliation_resp << {
34
+ partner_transaction_id: transaction[0],
35
+ amount: transaction[1],
36
+ currency: transaction[2],
37
+ transaction_time: valid_alipay_date(transaction[3]) ? DateTime.strptime(transaction[3],"%Y%m%d%H%M%S") : '',
38
+ settlement_time: valid_alipay_date(transaction[4]) ? DateTime.strptime(transaction[4],"%Y%m%d%H%M%S") : '',
39
+ transaction_type: transaction[5],
40
+ service_charge: transaction[6],
41
+ status: transaction[7],
42
+ remarks: transaction[8] ? transaction[8] : ''
43
+ }
44
+ end
45
+
46
+ end
47
+ reconciliation_resp
48
+ end
49
+
50
+ def self.build_request(params)
51
+ AlipayGlobal::Service.check_required_params(params, RECONCILIATION_REQUIRED_PARAMS)
52
+
53
+ params = AlipayGlobal::Utils.stringify_keys(params)
54
+
55
+ params = {
56
+ 'service' => 'forex_compare_file',
57
+ 'partner' => AlipayGlobal.api_partner_id,
58
+ }.merge(params)
59
+
60
+ AlipayGlobal::Service.request_uri(params).to_s
61
+ end
62
+
63
+ def self.error_check(data)
64
+ RECONCILIATION_ERROR_MESSAGES.any? { |w| data =~ /#{w}/ }
65
+ end
66
+
67
+ def self.valid_alipay_date(raw_date)
68
+ raw_date && raw_date.length > 0
69
+ end
70
+
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,67 @@
1
+ require "net/http"
2
+ require "uri"
3
+ require "nokogiri"
4
+
5
+ module AlipayGlobal
6
+ module Service
7
+ module Trade
8
+
9
+ CREATE_TRADE_REQUIRED_PARAMS = %w( notify_url subject out_trade_no currency )
10
+ CREATE_TRADE_OPTIONAL_PARAMS = %w( return_url body total_fee rmb_fee order_gmt_create order_valid_time timeout_rule auth_token supplier seller_id seller_name seller_industry )
11
+
12
+ def self.create(params)
13
+ is_mobile = params.delete(:mobile) || params.delete("mobile")
14
+ service_type = is_mobile ? "create_forex_trade_wap" : "create_forex_trade"
15
+
16
+ params = AlipayGlobal::Utils.stringify_keys(params)
17
+ AlipayGlobal::Service.check_required_params(params, CREATE_TRADE_REQUIRED_PARAMS)
18
+ AlipayGlobal::Service.check_optional_params(params, CREATE_TRADE_OPTIONAL_PARAMS)
19
+
20
+ params = {
21
+ 'service' => service_type,
22
+ '_input_charset' => 'utf-8',
23
+ 'partner' => AlipayGlobal.api_partner_id
24
+ }.merge(params)
25
+
26
+ AlipayGlobal::Service.request_uri(params).to_s
27
+ end
28
+
29
+ def self.refund(refunds)
30
+ file = build_refund_file(refunds)
31
+
32
+ params = {
33
+ 'service' => 'forex_refund_file',
34
+ 'partner' => AlipayGlobal.api_partner_id
35
+ }
36
+
37
+ uri = AlipayGlobal::Service.request_uri(params)
38
+
39
+ #p uri.to_s
40
+
41
+ form_params = { 'partner' => AlipayGlobal.api_partner_id, 'service' => 'forex_refund_file', 'refund_file' => IO.read(file.path) }
42
+
43
+ #p form_params
44
+
45
+ resp = Net::HTTP.post_form(uri, form_params)
46
+
47
+ #p resp.body
48
+
49
+ alipay_resp = Nokogiri::XML(resp.body)
50
+
51
+ alipay_results = alipay_resp.at_xpath('//alipay')
52
+ #puts "success = " + alipay_results.at_xpath('//is_success').content
53
+ #puts "error = " + alipay_results.at_xpath('//error').content
54
+
55
+ file.unlink
56
+ end
57
+
58
+ def self.build_refund_file(refunds)
59
+ file = Tempfile.new(['refund_file','.txt'])
60
+ refund_content = AlipayGlobal::Utils.write_refund_content(refunds)
61
+ file.write(refund_content)
62
+ file.close
63
+ file
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,47 @@
1
+ module AlipayGlobal
2
+ module Sign
3
+ @alipay_rsa_public_key = File.read("#{File.dirname __dir__}/../keys/alipay_public_key.pem")
4
+
5
+ def self.generate(params)
6
+ params = Utils.stringify_keys(params)
7
+ sign_type = AlipayGlobal.sign_type.upcase
8
+ key = AlipayGlobal.api_secret_key
9
+ string = params_to_string(params)
10
+
11
+ case sign_type
12
+ when 'MD5'
13
+ MD5.sign(string, key)
14
+ when 'RSA'
15
+ RSA.sign(string)
16
+ when 'DSA'
17
+ DSA.sign(string, key)
18
+ else
19
+ raise ArgumentError, "invalid sign_type #{sign_type}, allow value: 'MD5', 'RSA', 'DSA'"
20
+ end
21
+ end
22
+
23
+ def self.verify?(params)
24
+ params = Utils.stringify_keys(params)
25
+
26
+ sign_type = params.delete('sign_type')
27
+ signature = params.delete('sign')
28
+ string = params_to_string(params)
29
+
30
+ case sign_type
31
+ when 'MD5'
32
+ key = AlipayGlobal.api_secret_key
33
+ MD5.verify?(string, key, signature)
34
+ when 'RSA'
35
+ RSA.verify?(string, @alipay_rsa_public_key, signature)
36
+ when 'DSA'
37
+ DSA.verify?(string, signature)
38
+ else
39
+ false
40
+ end
41
+ end
42
+
43
+ def self.params_to_string(params)
44
+ params.sort.map { |item| item.join('=') }.join('&')
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,13 @@
1
+ module AlipayGlobal
2
+ module Sign
3
+ class DSA
4
+ def self.sign(string, private_key)
5
+ raise NotImplementedError, 'DSA is not implemented'
6
+ end
7
+
8
+ def self.verify?(string, sign)
9
+ raise NotImplementedError, 'DSA is not implemented'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ require 'digest/md5'
2
+
3
+ module AlipayGlobal
4
+ module Sign
5
+ class MD5
6
+ #pre-signed string should not be url encoded
7
+ def self.sign(string, secret_key)
8
+ Digest::MD5.hexdigest("#{string}#{secret_key}")
9
+ end
10
+
11
+ def self.verify?(string, secret_key, sign)
12
+ sign == sign(string, secret_key)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,24 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ module AlipayGlobal
5
+ module Sign
6
+ class RSA
7
+ def self.private_key
8
+ raise ArgumentError, "Assign valid location for RSA private key location :: #AlipayGlobal.private_key_location = #{AlipayGlobal.private_key_location}" if !AlipayGlobal.private_key_location
9
+ File.read(AlipayGlobal.private_key_location)
10
+ end
11
+
12
+ def self.sign(string, supplied_private_key = nil)
13
+ key = supplied_private_key || private_key
14
+ rsa = OpenSSL::PKey::RSA.new(key)
15
+ Base64.encode64(rsa.sign(OpenSSL::Digest::SHA256.new, string))
16
+ end
17
+
18
+ def self.verify?(string, public_key, sign)
19
+ rsa = OpenSSL::PKey::RSA.new(public_key)
20
+ rsa.verify(OpenSSL::Digest::SHA256.new, Base64.decode64(sign), string)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ module AlipayGlobal
2
+ module Utils
3
+ def self.stringify_keys(hash)
4
+ new_hash = {}
5
+ hash.each do |key, value|
6
+ case key
7
+ when :total_fee, :rmb_fee, :refund_sum
8
+ value = value.round(2)
9
+ value = '%.2f' % value
10
+ end
11
+ new_hash[(key.to_s rescue key) || key] = value
12
+ end
13
+ new_hash
14
+ end
15
+
16
+ def self.write_refund_content(refunds)
17
+ raise ArgumentException, "Refund content should contain at least 1 refund object" if refunds.length == 0
18
+ file_content = ""
19
+ refunds.each do |refund|
20
+ refund = stringify_keys(refund)
21
+ refund_reason = refund['refund_reason'] || ""
22
+ line_ending = stringify_keys(refunds.last) == refund ? "" : "\n"
23
+ raise ArgumentException, "Refund reason (#{refund_reason} cannot be more than 255 characters long)" if refund_reason.length > 255
24
+ file_content += "#{AlipayGlobal.api_partner_id}|#{refund['new_transaction_id']}|#{refund['old_transaction_id']}|#{refund['currency']}|#{refund['refund_sum']}|#{refund['refund_time']}|#{refund_reason}#{line_ending}"
25
+ end
26
+ file_content
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module AlipayGlobal
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,31 @@
1
+ require 'test_config'
2
+
3
+ describe "AlipayGlobal", "basic gem config" do
4
+
5
+ before do
6
+ @alipay = AlipayGlobal
7
+ end
8
+
9
+ it "has a basic debug mode default" do
10
+ assert @alipay.debug_mode?
11
+ end
12
+
13
+ it "has a default MD5 mode" do
14
+ assert_equal 'MD5', @alipay.sign_type
15
+ end
16
+
17
+ describe "api_partner_id & api_secret_key assignment" do
18
+
19
+ before do
20
+ @alipay.api_partner_id = '2088101122136241'
21
+ @alipay.api_secret_key = '760bdzec6y9goq7ctyx96ezkz78287de'
22
+ end
23
+
24
+ it "has assigned api_partner_id and api_secret_key" do
25
+ @alipay.api_partner_id.wont_be_nil true
26
+ @alipay.api_secret_key.wont_be_nil true
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,19 @@
1
+ require 'test_config'
2
+
3
+ describe "AlipayGlobal::Service::Exchange", "Forex exchange rates request" do
4
+
5
+ before do
6
+ @alipay = AlipayGlobal
7
+ @alipay.api_partner_id = '2088101122136241'
8
+ @alipay.api_secret_key = '760bdzec6y9goq7ctyx96ezkz78287de'
9
+ end
10
+
11
+ describe "#build_request" do
12
+
13
+ it "should create the correct rates url" do
14
+ assert_equal 'https://mapi.alipay.net/gateway.do?service=forex_rate_file&partner=2088101122136241&sign_type=MD5&sign=4051af1716d522b47acff927d4fb9781', @alipay::Service::Exchange.build_request()
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,21 @@
1
+ require 'test_config'
2
+
3
+ describe "AlipayGlobal::Service::Notification", "Notification request check" do
4
+
5
+ before do
6
+ @alipay = AlipayGlobal
7
+ @alipay.api_partner_id = '2088101122136241'
8
+ @alipay.api_secret_key = '760bdzec6y9goq7ctyx96ezkz78287de'
9
+
10
+ @params = {
11
+ notify_id: 'abcdefghijklmnopqrst'
12
+ }
13
+ end
14
+
15
+ describe "#check" do
16
+ it "should get params correctly" do
17
+ assert_equal "false", @alipay::Service::Notification.check(@params)
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,83 @@
1
+ require 'test_config'
2
+
3
+ describe "AlipayGlobal::Service::Reconciliation", "Reconciliation request check" do
4
+
5
+ before do
6
+ @alipay = AlipayGlobal
7
+ @alipay.api_partner_id = '2088101122136241'
8
+ @alipay.api_secret_key = '760bdzec6y9goq7ctyx96ezkz78287de'
9
+
10
+ @params = {
11
+ 'start_date'=> '20120202',
12
+ 'end_date'=> '20120205'
13
+ }
14
+ end
15
+
16
+ describe "#build_request" do
17
+ it "should get params correctly" do
18
+ assert_equal "https://mapi.alipay.net/gateway.do?service=forex_compare_file&partner=2088101122136241&start_date=20120202&end_date=20120205&sign_type=MD5&sign=3d09abe0980696bb39bb72c6137266ca", @alipay::Service::Reconciliation.build_request(@params)
19
+ end
20
+ end
21
+
22
+ describe "#request" do
23
+ #Alipay has some weird ass success parameter
24
+ describe "Success scenario" do
25
+ #this test is dependent on interfacing with alipay's test environment. The data may change/disappear over time. This test will fail if we get no data for the given parameter
26
+ it "should return the content parsed correctly" do
27
+ assert_operator 0, :<, @alipay::Service::Reconciliation.request({
28
+ 'start_date'=> '20122340',
29
+ 'end_date'=> '20122349'
30
+ }).length
31
+ end
32
+ end
33
+
34
+ describe "Error scenarios" do
35
+
36
+ it "return false for no records in period" do
37
+ assert_equal false, @alipay::Service::Reconciliation.request(@params)
38
+ end
39
+
40
+ it "should throw an ArgumentError for date range > 10 days" do
41
+ proc{ (@alipay::Service::Reconciliation.request({
42
+ 'start_date'=> '20120202',
43
+ 'end_date'=> '20120305'
44
+ })).call }.must_raise(ArgumentError)
45
+ end
46
+
47
+ it "should throw an ArgumentError for an errorneous date range" do
48
+ proc{ (@alipay::Service::Reconciliation.request({
49
+ 'start_date'=> '20130202',
50
+ 'end_date'=> '20120305'
51
+ })).call }.must_raise(ArgumentError)
52
+ end
53
+
54
+ it "should throw an ArgumentError for no dates supplied (or nil)" do
55
+ proc{ (@alipay::Service::Reconciliation.request({})).call }.must_raise(ArgumentError)
56
+ proc{ (@alipay::Service::Reconciliation.request(nil)).call }.must_raise(NoMethodError)
57
+ end
58
+
59
+ it "should throw an ArgumentError for finish date ahead of today" do
60
+ proc{ (@alipay::Service::Reconciliation.request({
61
+ 'start_date'=> '20151300',
62
+ 'end_date'=> '20151333'
63
+ })).call }.must_raise(ArgumentError)
64
+ end
65
+
66
+ describe "Incorrect Merchant" do
67
+ before do
68
+ @alipay.api_partner_id = 'daftpunk'
69
+ end
70
+
71
+ it "should throw an ArgumentError for Merchant ID incorrect" do
72
+ proc{ (@alipay::Service::Reconciliation.request(@params)).call }.must_raise(ArgumentError)
73
+ end
74
+
75
+ after do
76
+ @alipay.api_partner_id = '2088101122136241'
77
+ end
78
+ end
79
+
80
+ end
81
+ end
82
+
83
+ end