allpay-web-service 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 43e586806a13c853f21f18869707f437a60d1163
4
+ data.tar.gz: 39294aba6f7fa33e05ed321d00e7f574bf68c8fd
5
+ SHA512:
6
+ metadata.gz: 7453658150d048516fe614e8fbb18549582b511f0ce7137bb2bce6290941e73fc3770236f350d4f04c44ad105ab48c092aacbdc3b1658bc397a20122d7b14636
7
+ data.tar.gz: 70ed0871eb41979e7fab154eba46b5b796d8bac842dc2dd44148f5c5f4c0e9b8baeb99aeab3bf1dd7b56321b7157972bf5d9dde789664fd35a1b3eb3129f6666
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ - 2.2.0
5
+ - 2.1.5
6
+ before_install: gem install bundler -v 1.12.5
data/CHANGELOG.md ADDED
@@ -0,0 +1,2 @@
1
+ 1.0.0 May 26th, 2016
2
+ * Created initial version
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Calvert
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,150 @@
1
+ [![Gem Version](https://badge.fury.io/rb/simple-allpay.svg)](http://badge.fury.io/rb/allpay-web-service)
2
+ ![Analytics](https://ga-beacon.appspot.com/UA-44933497-3/CalvertYang/allpay-web-service?pixel)
3
+
4
+ # Allpay Web Service
5
+
6
+ Basic API client for Allpay credit card Web Service.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'allpay-web-service'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ ```bash
19
+ $ bundle
20
+ ```
21
+
22
+ Or install it yourself as:
23
+
24
+ ```bash
25
+ $ gem install allpay-web-service
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ #### Initialize
31
+
32
+ ```ruby
33
+ require "allpay-web-service"
34
+
35
+ client = AllpayWebService::Client.new(
36
+ merchant_id: "2000214",
37
+ hash_key: "ejCk326UnaZWKisg",
38
+ hash_iv: "q9jcZX8Ib9LM8wYk"
39
+ )
40
+ ```
41
+
42
+ ## Example
43
+
44
+ #### Create Trade
45
+
46
+ * OTP Trade
47
+
48
+ ```ruby
49
+ result = client.create_trade(
50
+ ServiceURL: "http://pay-stage.allpay.com.tw/merchantapi/creditcard.asmx?op=CreateTrade",
51
+ MerchantTradeNo: "TEST000001",
52
+ MerchantTradeDate: "2016/05/26 00:00:00",
53
+ TotalAmount: 100,
54
+ TradeDesc: "OTP Trade Test",
55
+ CardNo: 4311952222222222,
56
+ CardValidMM: "12",
57
+ CardValidYY: "20",
58
+ CardCVV2: 222,
59
+ PhoneNumber: "0987654321"
60
+ )
61
+ ```
62
+
63
+ * Non-OTP Trade
64
+
65
+ ```ruby
66
+ result = client.create_trade(
67
+ ServiceURL: "http://pay-stage.allpay.com.tw/merchantapi/creditcard.asmx?op=CreateTrade",
68
+ MerchantTradeNo: "TEST000001",
69
+ MerchantTradeDate: "2016/05/26 00:00:00",
70
+ TotalAmount: 100,
71
+ TradeDesc: "Non-OTP Trade Test",
72
+ CardNo: 4311952222222222,
73
+ CardValidMM: "12",
74
+ CardValidYY: "20",
75
+ CardCVV2: 222
76
+ )
77
+ ```
78
+
79
+ #### Verify Order By OTP
80
+
81
+ ```ruby
82
+ result = client.verify_order_by_otp(
83
+ ServiceURL: "http://pay-stage.allpay.com.tw/merchantapi/creditcard.asmx?op=QueryTrade",
84
+ MerchantTradeNo: "TEST000001",
85
+ TradeNo: "3c4c591f65153095b01",
86
+ OtpCode: "1234"
87
+ )
88
+ ```
89
+
90
+ #### Resend OTP code
91
+
92
+ ```ruby
93
+ result = client.resend_otp(
94
+ ServiceURL: "http://pay-stage.allpay.com.tw/merchantapi/creditcard.asmx?op=ResendOtp",
95
+ MerchantTradeNo: "TEST000001",
96
+ TradeNo: "3c4c591f65153095b01"
97
+ )
98
+ ```
99
+
100
+ #### Query Trade / Platform Query Trade
101
+
102
+ * Query Trade
103
+
104
+ ```ruby
105
+ result = client.query_trade(
106
+ ServiceURL: "http://pay-stage.allpay.com.tw/merchantapi/creditcard.asmx?op=QueryTrade",
107
+ MerchantTradeNo: "TEST000001"
108
+ )
109
+ ```
110
+
111
+ * Platform Query Trade
112
+
113
+ ```ruby
114
+ result = client.query_trade(
115
+ ServiceURL: "http://pay-stage.allpay.com.tw/merchantapi/creditcard.asmx?op=QueryTrade",
116
+ MerchantTradeNo: "TEST000001",
117
+ PlatformID: "9999999"
118
+ )
119
+ ```
120
+
121
+ #### Do Action
122
+
123
+ ```ruby
124
+ result = client.do_action(
125
+ ServiceURL: "http://pay-stage.allpay.com.tw/CreditDetail/DoAction",
126
+ MerchantTradeNo: "TEST000001",
127
+ TradeNo: "3c4c591f65153095b01",
128
+ Action: "C",
129
+ TotalAmount: 100
130
+ )
131
+ ```
132
+
133
+ ---
134
+
135
+ #### Result
136
+
137
+ All methods are return XML/Hash format result.
138
+
139
+ `result["Xml"]`: XML format result.
140
+
141
+ `result["Hash"]`: Hash format result.
142
+
143
+ ## Contributing
144
+
145
+ Bug reports and pull requests are welcome on GitHub at https://github.com/CalvertYang/allpay-web-service.
146
+
147
+
148
+ ## License
149
+
150
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'allpay/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "allpay-web-service"
8
+ spec.version = AllpayWebService::VERSION
9
+ spec.authors = ["Calvert"]
10
+ spec.email = [""]
11
+
12
+ spec.summary = "Basic API client for Allpay credit card Web Service."
13
+ spec.description = ""
14
+ spec.homepage = "https://github.com/CalvertYang/allpay-web-service"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "bin"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "nori", "~> 2.6"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.12"
25
+ spec.add_development_dependency "rake", "~> 11.1"
26
+ spec.add_development_dependency "rspec", "~> 3.4"
27
+ spec.add_development_dependency "nokogiri", "~> 1.6.7.2"
28
+
29
+ spec.required_ruby_version = ">= 2.1.5"
30
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "allpay-web-service"
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
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
@@ -0,0 +1,464 @@
1
+ require "base64"
2
+ require "uri"
3
+ require "net/http"
4
+ require "net/https"
5
+ require "nori"
6
+
7
+ module AllpayWebService
8
+ class Response
9
+ attr_accessor :hash, :xml, :errors
10
+ end
11
+
12
+ class ErrorMessage
13
+ def self.generate params
14
+ case params[:msg]
15
+ when :missing_parameter
16
+ "Missing required parameter: #{params[:field]}"
17
+ when :wrong_parameter_type
18
+ "Parameter should be #{params[:type]}"
19
+ when :wrong_data
20
+ "#{params[:field]} should be #{params[:data]}"
21
+ when :wrong_length
22
+ "The maximum length for #{params[:field]} is #{params[:length]}"
23
+ when :wrong_format
24
+ "The format for #{params[:field]} is wrong"
25
+ when :cannot_be_empty
26
+ "#{params[:field]} cannot be empty"
27
+ end
28
+ end
29
+ end
30
+
31
+ class Client
32
+ attr_accessor :merchant_id, :hash_key, :hash_iv
33
+
34
+ def initialize merchant_id:, hash_key:, hash_iv:
35
+ raise_argument_error(msg: :missing_parameter, field: :merchant_id) if merchant_id.nil?
36
+ raise_argument_error(msg: :wrong_data, field: :merchant_id, data: "String") unless merchant_id.is_a? String
37
+ raise_argument_error(msg: :cannot_be_empty, field: :merchant_id) if merchant_id.empty?
38
+ raise_argument_error(msg: :wrong_length, field: :merchant_id, length: 10) if merchant_id.size > 10
39
+
40
+ raise_argument_error(msg: :missing_parameter, field: :hash_key) if hash_key.nil?
41
+ raise_argument_error(msg: :wrong_data, field: :hash_key, data: "String") unless hash_key.is_a? String
42
+ raise_argument_error(msg: :cannot_be_empty, field: :hash_key) if hash_key.empty?
43
+
44
+ raise_argument_error(msg: :missing_parameter, field: :hash_iv) if hash_iv.nil?
45
+ raise_argument_error(msg: :wrong_data, field: :hash_iv, data: "String") unless hash_iv.is_a? String
46
+ raise_argument_error(msg: :cannot_be_empty, field: :hash_iv) if hash_iv.empty?
47
+
48
+ @merchant_id = merchant_id
49
+ @hash_key = hash_key
50
+ @hash_iv = hash_iv
51
+ end
52
+
53
+ # Create trade
54
+ #
55
+ # @param params [Hash] The params to create trade.
56
+ # @return [Response] response data
57
+ def create_trade params = {}
58
+ raise_argument_error(msg: :wrong_parameter_type, type: "Hash") unless params.is_a? Hash
59
+
60
+ raise_argument_error(msg: :missing_parameter, field: :ServiceURL) if params[:ServiceURL].nil?
61
+ raise_argument_error(msg: :wrong_data, field: :ServiceURL, data: "String") unless params[:ServiceURL].is_a? String
62
+
63
+ raise_argument_error(msg: :missing_parameter, field: :MerchantTradeNo) if params[:MerchantTradeNo].nil?
64
+ raise_argument_error(msg: :wrong_data, field: :MerchantTradeNo, data: "String") unless params[:MerchantTradeNo].is_a? String
65
+ raise_argument_error(msg: :wrong_length, field: :MerchantTradeNo, length: 20) if params[:MerchantTradeNo].size > 20
66
+
67
+ raise_argument_error(msg: :missing_parameter, field: :MerchantTradeDate) if params[:MerchantTradeDate].nil?
68
+ raise_argument_error(msg: :wrong_data, field: :MerchantTradeDate, data: "String") unless params[:MerchantTradeDate].is_a? String
69
+ raise_argument_error(msg: :wrong_length, field: :MerchantTradeDate, length: 20) if params[:MerchantTradeDate].size > 20
70
+ raise_argument_error(msg: :wrong_format, field: :MerchantTradeDate) unless /\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2}/.match(params[:MerchantTradeDate])
71
+
72
+ raise_argument_error(msg: :missing_parameter, field: :TotalAmount) if params[:TotalAmount].nil?
73
+ raise_argument_error(msg: :wrong_data, field: :TotalAmount, data: "Integer") unless params[:TotalAmount].is_a? Fixnum
74
+
75
+ raise_argument_error(msg: :missing_parameter, field: :TradeDesc) if params[:TradeDesc].nil?
76
+ raise_argument_error(msg: :wrong_data, field: :TradeDesc, data: "String") unless params[:TradeDesc].is_a? String
77
+ raise_argument_error(msg: :wrong_length, field: :TradeDesc, length: 200) if params[:TradeDesc].size > 200
78
+
79
+ raise_argument_error(msg: :missing_parameter, field: :CardNo) if params[:CardNo].nil?
80
+ raise_argument_error(msg: :wrong_data, field: :CardNo, data: "Integer") unless params[:CardNo].is_a? Fixnum
81
+
82
+ raise_argument_error(msg: :missing_parameter, field: :CardValidMM) if params[:CardValidMM].nil?
83
+ raise_argument_error(msg: :wrong_data, field: :CardValidMM, data: "String") unless params[:CardValidMM].is_a? String
84
+ raise_argument_error(msg: :wrong_length, field: :CardValidMM, length: 2) if params[:CardValidMM].size > 2
85
+
86
+ raise_argument_error(msg: :missing_parameter, field: :CardValidYY) if params[:CardValidYY].nil?
87
+ raise_argument_error(msg: :wrong_data, field: :CardValidYY, data: "String") unless params[:CardValidYY].is_a? String
88
+ raise_argument_error(msg: :wrong_length, field: :CardValidYY, length: 2) if params[:CardValidYY].size > 2
89
+
90
+ if params.has_key? :CardCVV2
91
+ raise_argument_error(msg: :wrong_data, field: :CardCVV2, data: "Integer") unless params[:CardCVV2].is_a? Fixnum
92
+ end
93
+
94
+ if params.has_key? :UnionPay
95
+ raise_argument_error(msg: :wrong_data, field: :UnionPay, data: "Integer") unless params[:UnionPay].is_a? Fixnum
96
+ end
97
+
98
+ if params.has_key? :Installment
99
+ raise_argument_error(msg: :wrong_data, field: :Installment, data: "Integer") unless params[:Installment].is_a? Fixnum
100
+ end
101
+
102
+ if params.has_key? :ThreeD
103
+ raise_argument_error(msg: :wrong_data, field: :ThreeD, data: "Integer") unless params[:ThreeD].is_a? Fixnum
104
+ end
105
+
106
+ if params.has_key? :CharSet
107
+ raise_argument_error(msg: :wrong_data, field: :CharSet, data: "String") unless params[:CharSet].is_a? String
108
+ raise_argument_error(msg: :wrong_length, field: :CharSet, length: 10) if params[:CharSet].size > 10
109
+ end
110
+
111
+ if params.has_key? :Enn
112
+ raise_argument_error(msg: :wrong_data, field: :Enn, data: "String") unless params[:Enn].is_a? String
113
+ raise_argument_error(msg: :wrong_length, field: :Enn, length: 1) if params[:Enn].size > 1
114
+ end
115
+
116
+ if params.has_key? :BankOnly
117
+ raise_argument_error(msg: :wrong_data, field: :BankOnly, data: "String") unless params[:BankOnly].is_a? String
118
+ raise_argument_error(msg: :wrong_length, field: :BankOnly, length: 120) if params[:BankOnly].size > 120
119
+ end
120
+
121
+ if params.has_key? :Redeem
122
+ raise_argument_error(msg: :wrong_data, field: :Redeem, data: "String") unless params[:Redeem].is_a? String
123
+ raise_argument_error(msg: :wrong_length, field: :Redeem, length: 1) if params[:Redeem].size > 1
124
+ end
125
+
126
+ if params.has_key? :PhoneNumber
127
+ raise_argument_error(msg: :wrong_data, field: :PhoneNumber, data: "String") unless params[:PhoneNumber].is_a? String
128
+ raise_argument_error(msg: :wrong_length, field: :PhoneNumber, length: 10) if params[:PhoneNumber].size > 10
129
+ end
130
+
131
+ if params.has_key? :AddMember
132
+ raise_argument_error(msg: :wrong_data, field: :AddMember, data: "String") unless params[:AddMember].is_a? String
133
+ raise_argument_error(msg: :wrong_length, field: :AddMember, length: 1) if params[:AddMember].size > 1
134
+ end
135
+
136
+ if params[:AddMember] == 1
137
+ raise_argument_error(msg: :missing_parameter, field: :CName) if params[:CName].nil?
138
+ raise_argument_error(msg: :wrong_data, field: :CName, data: "String") unless params[:CName].is_a? String
139
+ raise_argument_error(msg: :cannot_be_empty, field: :CName) if params[:CName].empty?
140
+ raise_argument_error(msg: :wrong_length, field: :CName, length: 60) if params[:CName].size > 60
141
+ end
142
+
143
+ if params.has_key? :Email
144
+ raise_argument_error(msg: :wrong_data, field: :Email, data: "String") unless params[:Email].is_a? String
145
+ raise_argument_error(msg: :wrong_length, field: :Email, length: 100) if params[:Email].size > 100
146
+ end
147
+
148
+ if params.has_key? :Remark
149
+ raise_argument_error(msg: :wrong_data, field: :Remark, data: "String") unless params[:Remark].is_a? String
150
+ raise_argument_error(msg: :wrong_length, field: :Remark, length: 200) if params[:Remark].size > 200
151
+ end
152
+
153
+ if params.has_key? :PlatformID
154
+ raise_argument_error(msg: :wrong_data, field: :PlatformID, data: "String") unless params[:PlatformID].is_a? String
155
+ raise_argument_error(msg: :wrong_length, field: :PlatformID, length: 9) if params[:PlatformID].size > 9
156
+ end
157
+
158
+ data = {
159
+ MerchantID: @merchant_id,
160
+ TradeDesc: "",
161
+ CardCVV2: "",
162
+ UnionPay: 0,
163
+ Installment: 0,
164
+ ThreeD: 0,
165
+ CharSet: "utf-8",
166
+ Enn: "",
167
+ BankOnly: "",
168
+ Redeem: "",
169
+ PhoneNumber: "",
170
+ AddMember: "0",
171
+ CName: "",
172
+ Email: "",
173
+ Remark: "",
174
+ PlatformID: ""
175
+ }.merge(params)
176
+ data[:TradeDesc] = CGI.escape(data[:TradeDesc])[0...200]
177
+ data[:CardValidMM] = data[:CardValidMM].to_s.rjust(2, "0")
178
+ data[:Remark] = CGI.escape(data[:Remark])[0...200]
179
+
180
+ post_data = build_post_data trade_type: :create_trade, params: data
181
+
182
+ response = request(service_url: params[:ServiceURL], data: post_data, is_soap_request: true)
183
+
184
+ parse trade_type: :create_trade, response: response
185
+ end
186
+
187
+ # Verify order by otp code
188
+ #
189
+ # @param params [Hash] The params to verify order by otp code.
190
+ # @return [Response] response data
191
+ def verify_order_by_otp params = {}
192
+ raise_argument_error(msg: :wrong_parameter_type, type: "Hash") unless params.is_a? Hash
193
+
194
+ raise_argument_error(msg: :missing_parameter, field: :ServiceURL) if params[:ServiceURL].nil?
195
+ raise_argument_error(msg: :wrong_data, field: :ServiceURL, data: "String") unless params[:ServiceURL].is_a? String
196
+
197
+ raise_argument_error(msg: :missing_parameter, field: :MerchantTradeNo) if params[:MerchantTradeNo].nil?
198
+ raise_argument_error(msg: :wrong_data, field: :MerchantTradeNo, data: "String") unless params[:MerchantTradeNo].is_a? String
199
+ raise_argument_error(msg: :wrong_length, field: :MerchantTradeNo, length: 20) if params[:MerchantTradeNo].size > 20
200
+
201
+ raise_argument_error(msg: :missing_parameter, field: :TradeNo) if params[:TradeNo].nil?
202
+ raise_argument_error(msg: :wrong_data, field: :TradeNo, data: "String") unless params[:TradeNo].is_a? String
203
+ raise_argument_error(msg: :wrong_length, field: :TradeNo, length: 20) if params[:TradeNo].size > 20
204
+
205
+ raise_argument_error(msg: :missing_parameter, field: :OtpCode) if params[:OtpCode].nil?
206
+ raise_argument_error(msg: :wrong_data, field: :OtpCode, data: "String") unless params[:OtpCode].is_a? String
207
+ raise_argument_error(msg: :wrong_length, field: :OtpCode, length: 10) if params[:OtpCode].size > 10
208
+
209
+ if params.has_key? :PlatformID
210
+ raise_argument_error(msg: :wrong_data, field: :PlatformID, data: "String") unless params[:PlatformID].is_a? String
211
+ raise_argument_error(msg: :wrong_length, field: :PlatformID, length: 9) if params[:PlatformID].size > 9
212
+ end
213
+
214
+ data = {
215
+ MerchantID: @merchant_id,
216
+ PlatformID: ""
217
+ }.merge(params)
218
+
219
+ post_data = build_post_data trade_type: :verify_order_by_otp, params: data
220
+
221
+ response = request(service_url: params[:ServiceURL], data: post_data, is_soap_request: true)
222
+
223
+ parse trade_type: :verify_order_by_otp, response: response
224
+ end
225
+
226
+ # Resend otp code
227
+ #
228
+ # @param params [Hash] The params to resend otp code.
229
+ # @return [Response] response data
230
+ def resend_otp params = {}
231
+ raise_argument_error(msg: :wrong_parameter_type, type: "Hash") unless params.is_a? Hash
232
+
233
+ raise_argument_error(msg: :missing_parameter, field: :ServiceURL) if params[:ServiceURL].nil?
234
+ raise_argument_error(msg: :wrong_data, field: :ServiceURL, data: "String") unless params[:ServiceURL].is_a? String
235
+
236
+ raise_argument_error(msg: :missing_parameter, field: :MerchantTradeNo) if params[:MerchantTradeNo].nil?
237
+ raise_argument_error(msg: :wrong_data, field: :MerchantTradeNo, data: "String") unless params[:MerchantTradeNo].is_a? String
238
+ raise_argument_error(msg: :wrong_length, field: :MerchantTradeNo, length: 20) if params[:MerchantTradeNo].size > 20
239
+
240
+ raise_argument_error(msg: :missing_parameter, field: :TradeNo) if params[:TradeNo].nil?
241
+ raise_argument_error(msg: :wrong_data, field: :TradeNo, data: "String") unless params[:TradeNo].is_a? String
242
+ raise_argument_error(msg: :wrong_length, field: :TradeNo, length: 20) if params[:TradeNo].size > 20
243
+
244
+ if params.has_key? :PlatformID
245
+ raise_argument_error(msg: :wrong_data, field: :PlatformID, data: "String") unless params[:PlatformID].is_a? String
246
+ raise_argument_error(msg: :wrong_length, field: :PlatformID, length: 9) if params[:PlatformID].size > 9
247
+ end
248
+
249
+ data = {
250
+ MerchantID: @merchant_id,
251
+ PlatformID: ""
252
+ }.merge(params)
253
+
254
+ post_data = build_post_data trade_type: :resend_otp, params: data
255
+
256
+ response = request(service_url: params[:ServiceURL], data: post_data, is_soap_request: true)
257
+
258
+ parse trade_type: :resend_otp, response: response
259
+ end
260
+
261
+ # Query trade information
262
+ #
263
+ # @param params [Hash] The params to query trade information.
264
+ # @return [Response] response data
265
+ def query_trade params = {}
266
+ raise_argument_error(msg: :wrong_parameter_type, type: "Hash") unless params.is_a? Hash
267
+
268
+ raise_argument_error(msg: :missing_parameter, field: :ServiceURL) if params[:ServiceURL].nil?
269
+ raise_argument_error(msg: :wrong_data, field: :ServiceURL, data: "String") unless params[:ServiceURL].is_a? String
270
+
271
+ raise_argument_error(msg: :missing_parameter, field: :MerchantTradeNo) if params[:MerchantTradeNo].nil?
272
+ raise_argument_error(msg: :wrong_data, field: :MerchantTradeNo, data: "String") unless params[:MerchantTradeNo].is_a? String
273
+ raise_argument_error(msg: :wrong_length, field: :MerchantTradeNo, length: 20) if params[:MerchantTradeNo].size > 20
274
+
275
+ if params.has_key? :PlatformID
276
+ raise_argument_error(msg: :wrong_data, field: :PlatformID, data: "String") unless params[:PlatformID].is_a? String
277
+ raise_argument_error(msg: :cannot_be_empty, field: :PlatformID) if params[:PlatformID].nil? or params[:PlatformID].empty?
278
+ raise_argument_error(msg: :wrong_length, field: :PlatformID, length: 9) if params[:PlatformID].size > 9
279
+ end
280
+
281
+ trade_type = params[:PlatformID].nil? ? :query_trade : :platform_query_trade
282
+
283
+ data = {
284
+ PlatformID: ""
285
+ }.merge(params)
286
+
287
+ post_data = build_post_data trade_type: trade_type, params: data
288
+
289
+ response = request(service_url: params[:ServiceURL], data: post_data, is_soap_request: true)
290
+
291
+ parse trade_type: :query_trade, response: response
292
+ end
293
+
294
+ # Execute action for trade
295
+ #
296
+ # @param params [Hash] The params to execute action for trade. See the official manual for more information.
297
+ # @return [Response] response data
298
+ def do_action params = {}
299
+ raise_argument_error(msg: :wrong_parameter_type, type: "Hash") unless params.is_a? Hash
300
+
301
+ raise_argument_error(msg: :missing_parameter, field: :ServiceURL) if params[:ServiceURL].nil?
302
+ raise_argument_error(msg: :wrong_data, field: :ServiceURL, data: "String") unless params[:ServiceURL].is_a? String
303
+
304
+ raise_argument_error(msg: :missing_parameter, field: :MerchantTradeNo) if params[:MerchantTradeNo].nil?
305
+ raise_argument_error(msg: :wrong_data, field: :MerchantTradeNo, data: "String") unless params[:MerchantTradeNo].is_a? String
306
+ raise_argument_error(msg: :wrong_length, field: :MerchantTradeNo, length: 20) if params[:MerchantTradeNo].size > 20
307
+
308
+ raise_argument_error(msg: :missing_parameter, field: :TradeNo) if params[:TradeNo].nil?
309
+ raise_argument_error(msg: :wrong_data, field: :TradeNo, data: "String") unless params[:TradeNo].is_a? String
310
+ raise_argument_error(msg: :wrong_length, field: :TradeNo, length: 20) if params[:TradeNo].size > 20
311
+
312
+ raise_argument_error(msg: :missing_parameter, field: :Action) if params[:Action].nil?
313
+ raise_argument_error(msg: :wrong_data, field: :Action, data: "String") unless params[:Action].is_a? String
314
+ raise_argument_error(msg: :wrong_length, field: :Action, length: 1) if params[:Action].size > 1
315
+
316
+ raise_argument_error(msg: :missing_parameter, field: :TotalAmount) if params[:TotalAmount].nil?
317
+ raise_argument_error(msg: :wrong_data, field: :TotalAmount, data: "Integer") unless params[:TotalAmount].is_a? Fixnum
318
+
319
+ if params.has_key? :PlatformID
320
+ raise_argument_error(msg: :wrong_data, field: :PlatformID, data: "String") unless params[:PlatformID].is_a? String
321
+ raise_argument_error(msg: :wrong_length, field: :PlatformID, length: 9) if params[:PlatformID].size > 9
322
+ end
323
+
324
+ data = {}.merge(params)
325
+
326
+ post_data = build_post_data trade_type: :do_action, params: data
327
+
328
+ response = request service_url: params[:ServiceURL], data: post_data, platform_id: params[:PlatformID]
329
+
330
+ parse trade_type: :do_action, response: response
331
+ end
332
+
333
+ private
334
+
335
+ def raise_argument_error params
336
+ raise ArgumentError, ErrorMessage.generate(params)
337
+ end
338
+
339
+ # Encode(by base64) and encrypt(by AES-128-CBC) data
340
+ def encrypt plain_data
341
+ cipher = OpenSSL::Cipher::AES128.new(:CBC)
342
+ cipher.encrypt
343
+ cipher.key = @hash_key
344
+ cipher.iv = @hash_iv
345
+ encrypted_data = cipher.update(plain_data) + cipher.final
346
+ Base64.strict_encode64(encrypted_data)
347
+ end
348
+
349
+ # Decrypt(by AES-128-CBC) and decode(by base64) data
350
+ def decrypt encrypted_data
351
+ encrypted_data = Base64.strict_decode64(encrypted_data)
352
+
353
+ decipher = OpenSSL::Cipher::AES128.new(:CBC)
354
+ decipher.decrypt
355
+ decipher.key = @hash_key
356
+ decipher.iv = @hash_iv
357
+ plain_data = decipher.update(encrypted_data) + decipher.final
358
+ CGI.unescape plain_data
359
+ end
360
+
361
+ def build_post_data trade_type:, params:
362
+ case trade_type
363
+ when :create_trade
364
+ xml_data= "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Root><Data><MerchantID>#{@merchant_id}</MerchantID><MerchantTradeNo>#{params[:MerchantTradeNo]}</MerchantTradeNo><MerchantTradeDate>#{params[:MerchantTradeDate]}</MerchantTradeDate><TotalAmount>#{params[:TotalAmount]}</TotalAmount><TradeDesc>#{params[:TradeDesc]}</TradeDesc><CardNo>#{params[:CardNo]}</CardNo><CardValidMM>#{params[:CardValidMM]}</CardValidMM><CardValidYY>#{params[:CardValidYY]}</CardValidYY><CardCVV2>#{params[:CardCVV2]}</CardCVV2><UnionPay>#{params[:UnionPay]}</UnionPay><Installment>#{params[:Installment]}</Installment><ThreeD>#{params[:ThreeD]}</ThreeD><CharSet>#{params[:CharSet]}</CharSet><Enn>#{params[:Enn]}</Enn><BankOnly>#{params[:BankOnly]}</BankOnly><Redeem>#{params[:Redeem]}</Redeem><PhoneNumber>#{params[:PhoneNumber]}</PhoneNumber><AddMember>#{params[:AddMember]}</AddMember><CName>#{params[:CName]}</CName><Email>#{params[:Email]}</Email><Remark>#{params[:Remark]}</Remark><PlatformID>#{params[:PlatformID]}</PlatformID></Data></Root>"
365
+ encrypted_data = encrypt(xml_data)
366
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\"><soap12:Body><CreateTrade xmlns=\"http://PaymentCenter.AllPay.com.tw/\"><merchantID>#{@merchant_id}</merchantID><xmlData>#{encrypted_data}</xmlData></CreateTrade></soap12:Body></soap12:Envelope>"
367
+ when :verify_order_by_otp
368
+ xml_data = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Root><Data><MerchantID>#{params[:MerchantID]}</MerchantID><MerchantTradeNo>#{params[:MerchantTradeNo]}</MerchantTradeNo><TradeNo>#{params[:TradeNo]}</TradeNo><OtpCode>#{params[:OtpCode]}</OtpCode><PlatformID>#{params[:PlatformID]}</PlatformID></Data></Root>"
369
+ encrypted_data = encrypt(xml_data)
370
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\"><soap12:Body><VerifyOrderByOtp xmlns=\"http://PaymentCenter.AllPay.com.tw/\"><merchantID>#{@merchant_id}</merchantID><xmlData>#{encrypted_data}</xmlData></VerifyOrderByOtp></soap12:Body></soap12:Envelope>"
371
+ when :resend_otp
372
+ xml_data = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Root><Data><MerchantID>#{params[:MerchantID]}</MerchantID><MerchantTradeNo>#{params[:MerchantTradeNo]}</MerchantTradeNo><TradeNo>#{params[:TradeNo]}</TradeNo><PlatformID></PlatformID></Data></Root>"
373
+ encrypted_data = encrypt(xml_data)
374
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\"><soap12:Body><ResendOtp xmlns=\"http://PaymentCenter.AllPay.com.tw/\"><merchantID>#{@merchant_id}</merchantID><xmlData>#{encrypted_data}</xmlData></ResendOtp></soap12:Body></soap12:Envelope>"
375
+ when :query_trade
376
+ merchant_trade_no = encrypt(params[:MerchantTradeNo])
377
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\"><soap12:Body><QueryTrade xmlns=\"http://PaymentCenter.AllPay.com.tw/\"><merchantID>#{@merchant_id}</merchantID><merchantTradeNo>#{merchant_trade_no}</merchantTradeNo></QueryTrade></soap12:Body></soap12:Envelope>"
378
+ when :platform_query_trade
379
+ merchant_trade_no = encrypt(params[:MerchantTradeNo])
380
+ platform_id = encrypt(params[:PlatformID])
381
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\"><soap12:Body><PlatformQueryTrade xmlns=\"http://PaymentCenter.AllPay.com.tw/\"><merchantID>#{@merchant_id}</merchantID><merchantTradeNo>#{merchant_trade_no}</merchantTradeNo><PlatformID>#{platform_id}</PlatformID></PlatformQueryTrade></soap12:Body></soap12:Envelope>"
382
+ when :do_action
383
+ encrypt("<?xml version=\"1.0\" encoding=\"utf-8\" ?><Root><Data><MerchantID>#{@merchant_id}</MerchantID><MerchantTradeNo>#{params[:MerchantTradeNo]}</MerchantTradeNo><TradeNo>#{params[:TradeNo]}</TradeNo><Action>#{params[:Action]}</Action><TotalAmount>#{params[:TotalAmount]}</TotalAmount></Data></Root>")
384
+ end
385
+ end
386
+
387
+ def request method: "POST", service_url:, data:, is_soap_request: false, platform_id: nil
388
+ api_url = URI.parse(service_url)
389
+
390
+ http = Net::HTTP.new(api_url.host, api_url.port)
391
+ http.use_ssl = true if api_url.scheme == "https"
392
+
393
+ req = Net::HTTP::Post.new(api_url.request_uri, initheader = {
394
+ "Accept-Language" => "zh-tw",
395
+ "Accept-Charset" => "utf-8",
396
+ "Content-Type" => is_soap_request ? "application/soap+xml" : "application/x-www-form-urlencoded",
397
+ "Host" => api_url.host
398
+ })
399
+
400
+ if is_soap_request
401
+ req.body = data
402
+ else
403
+ form_data = {
404
+ "MerchantID" => @merchant_id,
405
+ "XMLData" => data
406
+ }
407
+ form_data["PlatformID"] = platform_id unless platform_id.nil?
408
+
409
+ req.set_form_data(form_data)
410
+ end
411
+
412
+ http_response = http.request(req)
413
+
414
+ case http_response
415
+ when Net::HTTPOK
416
+ http_response
417
+ when Net::HTTPClientError, Net::HTTPInternalServerError
418
+ raise Net::HTTPError, http_response.message
419
+ else
420
+ raise Net::HTTPError, "Unexpected HTTP response."
421
+ end
422
+ end
423
+
424
+ def parse trade_type:, response:
425
+ res_xml = nil
426
+ res_hash = nil
427
+
428
+ case trade_type
429
+ when :create_trade, :verify_order_by_otp, :resend_otp
430
+ if trade_type == :create_trade
431
+ pattern = /<CreateTradeResult>(.+)<\/CreateTradeResult>/
432
+ elsif trade_type == :verify_order_by_otp
433
+ pattern = /<VerifyOrderByOtpResult>(.+)<\/VerifyOrderByOtpResult>/
434
+ elsif trade_type == :resend_otp
435
+ pattern = /<ResendOtpResult>(.+)<\/ResendOtpResult>/
436
+ end
437
+
438
+ match_result = pattern.match response.body
439
+
440
+ unless match_result.nil?
441
+ encrypted_result = match_result[1]
442
+ res_xml = decrypt(encrypted_result)
443
+ end
444
+ when :query_trade
445
+ pattern = /<QueryTradeResult>(.+)<\/QueryTradeResult>/
446
+
447
+ match_result = pattern.match response.body
448
+
449
+ unless match_result.nil?
450
+ res_xml = CGI.unescapeHTML match_result[1]
451
+ end
452
+ when :do_action
453
+ res_xml = decrypt(response.body)
454
+ end
455
+
456
+ begin
457
+ parser = Nori.new(:advanced_typecasting => false)
458
+ res_hash = parser.parse(res_xml)['Root']['Data'] unless res_xml.nil?
459
+ end
460
+
461
+ { "Xml" => res_xml, "Hash" => res_hash }
462
+ end
463
+ end
464
+ end
@@ -0,0 +1,3 @@
1
+ module AllpayWebService
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,5 @@
1
+ require "allpay/version"
2
+ require "allpay/client"
3
+
4
+ module AllpayWebService
5
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: allpay-web-service
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Calvert
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nori
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.12'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.12'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '11.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '11.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: nokogiri
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.6.7.2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.6.7.2
83
+ description: ''
84
+ email:
85
+ - ''
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - CHANGELOG.md
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - allpay-web-service.gemspec
99
+ - bin/console
100
+ - bin/setup
101
+ - lib/allpay-web-service.rb
102
+ - lib/allpay/client.rb
103
+ - lib/allpay/version.rb
104
+ homepage: https://github.com/CalvertYang/allpay-web-service
105
+ licenses:
106
+ - MIT
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 2.1.5
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 2.5.1
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Basic API client for Allpay credit card Web Service.
128
+ test_files: []