ecpay_payment 1.1.2

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,469 @@
1
+ # require "../../../gem/lib/ecpay_payment/error"
2
+ require "ecpay_payment/error"
3
+ require "nokogiri"
4
+ require 'date'
5
+
6
+ module ECpayPayment
7
+ class PaymentVerifyBase
8
+ include ECpayErrorDefinition
9
+ @@param_xml = Nokogiri::XML(File.open(File.join(File.dirname(__FILE__), 'ECpayPayment.xml')))
10
+
11
+ def get_svc_url(apiname, mode)
12
+ url = @@param_xml.xpath("/ECPayPayment/#{apiname}/ServiceAddress/url[@type=\"#{mode}\"]").text
13
+ return url
14
+ end
15
+
16
+ def get_special_encode_param(apiname)
17
+ ret = []
18
+ node = @@param_xml.xpath("/ECPayPayment/#{apiname}/Parameters//param[@urlencode=\"1\"]")
19
+ node.each {|elem| ret.push(elem.attributes['name'].value)}
20
+ return ret
21
+ end
22
+
23
+ def get_basic_params(apiname)
24
+ basic_param = []
25
+ @@param_xml.xpath("/ECPayPayment/#{apiname}/Parameters/param[@require=\"1\"]").each do |elem|
26
+ basic_param.push(elem.attributes['name'].value)
27
+ end
28
+ return basic_param
29
+ end
30
+
31
+ def get_cond_param(apiname)
32
+ aio_sw_param = []
33
+ conditional_param = {}
34
+ @@param_xml.xpath("/ECPayPayment/#{apiname}/Config/switchparam/n").each do |elem|
35
+ aio_sw_param.push(elem.text)
36
+ end
37
+ aio_sw_param.each do |pname|
38
+ opt_param = {}
39
+ node = @@param_xml.xpath("/ECPayPayment/#{apiname}/Parameters//param[@name=\"#{pname}\"]")
40
+ node.xpath('./condparam').each do |elem|
41
+ opt = elem.attributes['owner'].value
42
+ params = []
43
+ elem.xpath('./param[@require="1"]').each do |pa|
44
+ params.push(pa.attributes['name'].value)
45
+ end
46
+ opt_param[opt] = params
47
+ end
48
+ conditional_param[pname] = opt_param
49
+ end
50
+ return conditional_param
51
+ end
52
+
53
+ def get_param_type(apiname)
54
+ param_type = {}
55
+ @@param_xml.xpath("/ECPayPayment/#{apiname}/Parameters//param").each do |elem|
56
+ param_type[elem.attributes['name'].value] = elem.attributes['type'].value
57
+ end
58
+ return param_type
59
+ end
60
+
61
+ def get_opt_param_pattern(apiname)
62
+ pattern = {}
63
+ node = @@param_xml.xpath("/ECPayPayment/#{apiname}/Parameters//param[@type=\"Opt\"]")
64
+ node.each do |param_elem|
65
+ opt_elems = param_elem.xpath('./option')
66
+ opt = []
67
+ opt_elems.each{|oe|opt.push(oe.text)}
68
+ pattern[param_elem.attributes['name'].value] = opt
69
+ end
70
+ return pattern
71
+ end
72
+
73
+ def get_int_param_pattern(apiname)
74
+ pattern = {}
75
+ node = @@param_xml.xpath("/ECPayPayment/#{apiname}/Parameters//param[@type=\"Int\"]")
76
+ node.each do |param_elem|
77
+ mode = param_elem.xpath('./mode').text
78
+ mx = param_elem.xpath('./maximum').text
79
+ mn = param_elem.xpath('./minimal').text
80
+ a = []
81
+ [mode, mx, mn].each{|f|a.push(f)}
82
+ pattern[param_elem.attributes['name'].value] = a
83
+ end
84
+ return pattern
85
+ end
86
+
87
+ def get_str_param_pattern(apiname)
88
+ pattern = {}
89
+ node = @@param_xml.xpath("/ECPayPayment/#{apiname}/Parameters//param[@type=\"String\"]")
90
+ node.each do |param_elem|
91
+ p_name = param_elem.attributes['name'].value
92
+ pat_elems = param_elem.xpath('./pattern')
93
+ # if pat_elems.length > 1
94
+ # raise "Only 1 pattern tag is allowed for each parameter (#{p_name}) "
95
+ # elsif pat_elems.length = 0
96
+ # raise "No pattern tag found for parameter (#{p_name}) "
97
+ # end
98
+ pat = pat_elems.text
99
+ pattern[p_name] = pat
100
+ end
101
+ return pattern
102
+ end
103
+
104
+ def get_depopt_param_pattern(apiname)
105
+ pattern = {}
106
+
107
+ node = @@param_xml.xpath("/ECPayPayment/#{apiname}/Parameters//param[@type=\"DepOpt\"]")
108
+ node.each do |param_elem|
109
+ parent_n_opts = {}
110
+ sub_opts = {}
111
+ p_name = param_elem.attributes['name'].value
112
+ parent_name = param_elem.attributes['main'].value
113
+ param_elem.xpath('./mainoption').each do |elem|
114
+ k = elem.attributes['name'].value
115
+ opt = []
116
+ elem.element_children.each{|c|opt.push(c.text)}
117
+ sub_opts[k] = opt
118
+ end
119
+ parent_n_opts[parent_name] = sub_opts
120
+ pattern[p_name] = parent_n_opts
121
+ end
122
+ return pattern
123
+ end
124
+
125
+ def get_all_pattern(apiname)
126
+ res = {}
127
+ res['Type_idx'] = self.get_param_type(apiname)
128
+ res['Int'] = self.get_int_param_pattern(apiname)
129
+ res['String'] = self.get_str_param_pattern(apiname)
130
+ res['Opt'] = self.get_opt_param_pattern(apiname)
131
+ res['DepOpt'] = self.get_depopt_param_pattern(apiname)
132
+ return res
133
+ end
134
+
135
+ def verify_param_by_pattern(params, pattern)
136
+ type_index = pattern['Type_idx']
137
+ params.keys.each do |p_name|
138
+ p_type = type_index[p_name]
139
+ patt_container = pattern[p_type]
140
+ case
141
+ when p_type == 'String'
142
+ regex_patt = patt_container[p_name]
143
+ mat = /#{regex_patt}/.match(params[p_name])
144
+ if mat.nil?
145
+ raise ECpayInvalidParam, "Wrong format of param #{p_name} or length exceeded."
146
+ end
147
+ when p_type == 'Opt'
148
+ aval_opt = patt_container[p_name]
149
+ mat = aval_opt.include?(params[p_name])
150
+ if mat == false
151
+ raise ECpayInvalidParam, "Unexpected option of param #{p_name} (#{params[p_name]}). Avaliable option: (#{aval_opt})."
152
+ end
153
+ when p_type == 'Int'
154
+ criteria = patt_container[p_name]
155
+ mode = criteria[0]
156
+ max = criteria[1].to_i
157
+ min = criteria[2].to_i
158
+ val = params[p_name].to_i
159
+ case
160
+ when mode == 'BETWEEN'
161
+ if val < min or val > max
162
+ raise ECpayInvalidParam, "Value of #{p_name} should be between #{min} and #{max} ."
163
+ end
164
+ when mode == 'GE'
165
+ if val < min
166
+ raise ECpayInvalidParam, "Value of #{p_name} should be greater than or equal to #{min}."
167
+ end
168
+ when mode == 'LE'
169
+ if val > max
170
+ raise ECpayInvalidParam, "Value of #{p_name} should be less than or equal to #{max}."
171
+ end
172
+ when mode == 'EXCLUDE'
173
+ if val >= min and val <= max
174
+ raise ECpayInvalidParam, "Value of #{p_name} can NOT be between #{min} and #{max} .."
175
+ end
176
+ else
177
+ raise "Unexpected integer verification mode for parameter #{p_name}: #{mode}. "
178
+ end
179
+ when p_type == 'DepOpt'
180
+ dep_opt = patt_container[p_name]
181
+ parent_param = dep_opt.keys()[0]
182
+ all_dep_opt = dep_opt[parent_param]
183
+ parent_val = params[parent_param]
184
+ aval_opt = all_dep_opt[parent_val]
185
+ if aval_opt.nil? and pattern['Opt'][parent_param].include?(parent_val) == false
186
+ raise ECpayInvalidParam, "Cannot find avaliable option of [#{p_name}] by related param [#{parent_param}](Value: #{parent_val})."
187
+ elsif aval_opt.is_a?(Array)
188
+ unless aval_opt.include?(params[p_name])
189
+ raise ECpayInvalidParam, "Unexpected option of param #{p_name} (#{params[p_name]}). Avaliable option: (#{aval_opt})."
190
+ end
191
+ end
192
+
193
+ else
194
+ raise "Unexpected type (#{p_type}) for parameter #{p_name}. "
195
+
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ class AioCheckOutParamVerify < PaymentVerifyBase
202
+ include ECpayErrorDefinition
203
+ def initialize
204
+ @aio_basic_param = self.get_basic_params('AioCheckOut').freeze
205
+ @aio_conditional_param = self.get_cond_param('AioCheckOut').freeze
206
+ @all_param_pattern = self.get_all_pattern('AioCheckOut').freeze
207
+ end
208
+
209
+ def get_serialized_data
210
+ p @aio_basic_param
211
+ p '---'
212
+ p @aio_conditional_param
213
+ new_di = @aio_conditional_param
214
+ new_di.delete('InvoiceMark')
215
+ p @aio_conditional_param
216
+ p '-----'
217
+ p new_di
218
+ #return @aio_conditional_param['InvoiceMark']['Y']
219
+ #p @@param_xml
220
+ end
221
+
222
+ def verify_aio_payment_param(params)
223
+ if params.is_a?(Hash)
224
+ #Force specify : DeviceSource, IgnorePayment, PlatformID EncryptType
225
+ fix_params = {
226
+ 'DeviceSource' => '',
227
+ #'PlatformID' => '',
228
+ 'EncryptType' => '1',
229
+ 'PaymentType' => 'aio'
230
+ }
231
+ params.merge!(fix_params)
232
+ #Verify Basic param requirement
233
+ # if param == {}
234
+ # raise ECpayInvalidParam, %Q{Parameter hash is empty.}
235
+ # end
236
+ param_diff = @aio_basic_param - params.keys
237
+ unless param_diff == []
238
+ raise ECpayInvalidParam, "Lack required param #{param_diff}"
239
+ end
240
+
241
+ # Verify Extend param requirement
242
+ ext_param = @aio_conditional_param.dup
243
+ ext_param.delete('InvoiceMark')
244
+ ext_param.keys.each do |pa|
245
+ val = params[pa]
246
+ related_require_param = ext_param[pa][val]
247
+ if related_require_param.nil? == false and related_require_param != []
248
+ related_require_param.each do |e|
249
+ unless params.keys.include?(e)
250
+ raise ECpayInvalidParam, "Lack required parameter [#{e}] when [#{pa}] is set to [#{val}] "
251
+ end
252
+ end
253
+ end
254
+ end
255
+
256
+ #Verify Value pattern of each param
257
+ self.verify_param_by_pattern(params, @all_param_pattern)
258
+
259
+ else
260
+ raise TypeError, "Recieved argument is not a hash"
261
+ end
262
+
263
+ end
264
+
265
+ def verify_aio_inv_param(params)
266
+ if params.is_a?(Hash)
267
+ #發票所有參數預設要全帶
268
+
269
+ if params.has_value?(nil)
270
+ raise ECpayInvalidParam, %Q{Parameter value cannot be nil}
271
+ end
272
+ #1. 比對欄位是否缺乏
273
+ inv_param_names = @aio_conditional_param['InvoiceMark']['Y']
274
+ param_diff = inv_param_names - params.keys()
275
+ unless param_diff == []
276
+ raise ECpayInvalidParam, %Q{Lack required invoice param #{param_diff}}
277
+ end
278
+ unexp_param = params.keys() - inv_param_names
279
+ unless unexp_param == []
280
+ raise ECpayInvalidParam, %Q{Unexpected parameter in Invoice parameters #{unexp_param}}
281
+ end
282
+
283
+ #2. 比對特殊欄位值相依需求
284
+
285
+ #a [CarruerType]為 1 => CustomerID 不能為空
286
+ if params['CarruerType'].to_s == '1'
287
+ if params['CustomerID'].to_s.empty?
288
+ raise ECpayInvoiceRuleViolate, "[CustomerID] can not be empty when [CarruerType] is 1."
289
+ end
290
+ # [CustomerID]不為空 => CarruerType 不能為空
291
+ elsif params['CarruerType'].to_s == ''
292
+ unless params['CustomerID'].to_s.empty?
293
+ raise ECpayInvoiceRuleViolate, "[CarruerType] can not be empty when [CustomerID] is not empty."
294
+ end
295
+ end
296
+ #b 列印註記[Print]為 1 => CustomerName, CustomerAddr
297
+ if params['Print'].to_s == '1'
298
+ if params['CustomerName'].to_s.empty? or params['CustomerAddr'].to_s.empty?
299
+ raise ECpayInvoiceRuleViolate, "[CustomerName] and [CustomerAddr] can not be empty when [Print] is 1."
300
+ end
301
+ unless params['CustomerID'].to_s.empty?
302
+ raise ECpayInvoiceRuleViolate, "[Print] can not be '1' when [CustomerID] is not empty."
303
+ end
304
+ end
305
+ #c CustomerPhone和CustomerEmail至少一個有值
306
+ if params['CustomerPhone'].to_s.empty? and params['CustomerEmail'].to_s.empty?
307
+ raise ECpayInvoiceRuleViolate, "[CustomerPhone] and [CustomerEmail] can not both be empty."
308
+ end
309
+ #d 別[TaxType]為 2 => ClearanceMark = 1 or 2
310
+ if params['TaxType'].to_s == '2'
311
+ unless ['1', '2'].include?(params['ClearanceMark'].to_s)
312
+ raise ECpayInvoiceRuleViolate, "[ClearanceMark] has to be 1 or 2 when [TaxType] is 2."
313
+ end
314
+ end
315
+ #e 統一編號[CustomerIdentifier]有值時 => CarruerType != 1 or 2, *Donation = 0, Print = 1
316
+ # 統一編號為空值時剔除該欄位
317
+ #if params['CustomerIdentifier'].to_s.empty?
318
+ #params.delete('CustomerIdentifier')
319
+ #else
320
+ unless params['CustomerIdentifier'].to_s.empty?
321
+ if ['1', '2'].include?(params['CarruerType'].to_s)
322
+ raise ECpayInvoiceRuleViolate, "[CarruerType] Cannot be 1 or 2 when [CustomerIdentifier] is given."
323
+ end
324
+ unless params['Donation'].to_s == '2' and params['Print'].to_s == '1'
325
+ raise ECpayInvoiceRuleViolate, "[Print] must be 1 and [Donation] must be 2 when [CustomerIdentifier] is given."
326
+ end
327
+ end
328
+
329
+ # [CarruerType]為'' or 1 時 => CarruerNum = '', [CarruerType]為 2, CarruerNum = 固定長度為 16 且格式為 2 碼大小寫字母加上 14 碼數字。 [CarruerType]為 3 ,帶固定長度為 8 且格式為 1 碼斜線「/」加上由 7 碼數字及大小寫字母組成
330
+ if ['', '1'].include?(params['CarruerType'].to_s)
331
+ unless params['CarruerNum'].to_s == ''
332
+ raise ECpayInvoiceRuleViolate, "[CarruerNum] must be empty when [CarruerType] is empty or 1."
333
+ end
334
+ elsif params['CarruerType'].to_s == '2'
335
+ if /[A-Za-z]{2}[0-9]{14}/.match(params['CarruerNum']).nil?
336
+ raise ECpayInvoiceRuleViolate, "[CarruerNum] must be 2 alphabets and 14 numbers when [CarruerType] is 2."
337
+ end
338
+ elsif params['CarruerType'].to_s == '3'
339
+ if /^\/[A-Za-z0-9\s+-]{7}$/.match(params['CarruerNum']).nil?
340
+ raise ECpayInvoiceRuleViolate, "[CarruerNum] must start with '/' followed by 7 alphabet and number characters when [CarruerType] is 3."
341
+ end
342
+ else
343
+ raise ECpayInvoiceRuleViolate, "Unexpected value in [CarruerType]."
344
+ end
345
+
346
+ #[CarruerType]有值時,Print必須為0
347
+ if params['CarruerType'].to_s != '' and params['Print'].to_s != '0'
348
+ raise ECpayInvoiceRuleViolate, "[Print] must be 0 when [CarruerType] has value."
349
+ end
350
+
351
+ # Donation = 1 => LoveCode不能為空, Print = 0
352
+ if params['Donation'].to_s == '1'
353
+ if params['LoveCode'].to_s.empty?
354
+ raise ECpayInvoiceRuleViolate, "[LoveCode] cannot be empty when [Donation] is 1."
355
+ end
356
+ unless params['Print'].to_s == '0'
357
+ raise ECpayInvoiceRuleViolate, "[Print] must be 0 when [Donation] is 1."
358
+ end
359
+ end
360
+
361
+ #3. 比對商品名稱,數量,單位,價格,tax項目數量是否一致
362
+ item_params = ['InvoiceItemCount', 'InvoiceItemWord', 'InvoiceItemPrice', 'InvoiceItemTaxType']
363
+ #商品名稱含有管線 => 認為是多樣商品 *InvoiceItemName, *InvoiceItemCount ,*InvoiceItemWord, *InvoiceItemPrice InvoiceItemTaxType逐一用管線分割,計算數量後與第一個比對
364
+ if params['InvoiceItemName'].empty?
365
+ raise ECpayInvoiceRuleViolate, "[InvoiceItemName] is empty."
366
+ else
367
+ if params['InvoiceItemName'].include?('|')
368
+ item_cnt = params['InvoiceItemCount'].split('|').length
369
+ item_params.each do |param_name|
370
+ # Check if there's empty value.
371
+ unless /(\|\||^\||\|$)/.match(params[param_name]).nil?
372
+ raise ECpayInvoiceRuleViolate, "[#{param_name}] contains empty value."
373
+ end
374
+ p_cnt = params[param_name].split('|').length
375
+ unless item_cnt == p_cnt
376
+ raise ECpayInvoiceRuleViolate, %Q{Count of item info [#{param_name}] (#{p_cnt}) not match item count from [InvoiceItemCount] (#{item_cnt})}
377
+ end
378
+ end
379
+ # 課稅類別[TaxType] = 9 時 => InvoiceItemTaxType 能含有1,2 3(and at least contains one 1 and other)
380
+ item_tax = params['InvoiceItemTaxType'].split('|')
381
+ aval_tax_type = ['1', '2', '3']
382
+ vio_tax_t = (item_tax - aval_tax_type)
383
+ unless vio_tax_t == []
384
+ raise ECpayInvoiceRuleViolate, "Ilegal [InvoiceItemTaxType]: #{vio_tax_t}"
385
+ end
386
+ if params['TaxType'].to_s == '9'
387
+ unless item_tax.include?('1')
388
+ raise ECpayInvoiceRuleViolate, "[InvoiceItemTaxType] must contain at lease one '1'."
389
+ end
390
+ if item_tax.include?('2') and item_tax.include?('3')
391
+ raise ECpayInvoiceRuleViolate, "[InvoiceItemTaxType] cannot contain 2 and 3 at the same time."
392
+ end
393
+ end
394
+ else
395
+ #沒有管線 => 逐一檢查後4項有無管線
396
+ item_params.each do |param_name|
397
+ if params[param_name].include?('|')
398
+ raise "Item info [#{param_name}] contains pipeline delimiter but there's only one item in param [InvoiceItemName]"
399
+ end
400
+ end
401
+ end
402
+ end
403
+ #4 比對所有欄位Pattern
404
+ self.verify_param_by_pattern(params, @all_param_pattern)
405
+
406
+ else
407
+ raise TypeError, "Recieved argument is not a hash"
408
+ end
409
+ end
410
+
411
+ #可能要寫一個hash list 轉 這五個參數的method
412
+ # def hash_to_inv_item_params
413
+ # end
414
+
415
+
416
+ end
417
+
418
+ class QueryParamVerify < PaymentVerifyBase
419
+ include ECpayErrorDefinition
420
+ def initialize(apiname)
421
+ @aio_basic_param = self.get_basic_params(apiname).freeze
422
+ @aio_conditional_param = self.get_cond_param(apiname).freeze
423
+ @all_param_pattern = self.get_all_pattern(apiname).freeze
424
+ end
425
+
426
+ def verify_query_param(params)
427
+ if params.is_a?(Hash)
428
+ param_diff = @aio_basic_param - params.keys
429
+ unless param_diff == []
430
+ raise ECpayInvalidParam, "Lack required param #{param_diff}"
431
+ end
432
+
433
+ #Verify Value pattern of each param
434
+ self.verify_param_by_pattern(params, @all_param_pattern)
435
+
436
+ else
437
+ raise TypeError, "Recieved argument is not a hash"
438
+ end
439
+
440
+ end
441
+
442
+ end
443
+
444
+ class ActParamVerify < PaymentVerifyBase
445
+ include ECpayErrorDefinition
446
+ def initialize(apiname)
447
+ @aio_basic_param = self.get_basic_params(apiname).freeze
448
+ @aio_conditional_param = self.get_cond_param(apiname).freeze
449
+ @all_param_pattern = self.get_all_pattern(apiname).freeze
450
+ end
451
+
452
+ def verify_act_param(params)
453
+ if params.is_a?(Hash)
454
+ param_diff = @aio_basic_param - params.keys
455
+ unless param_diff == []
456
+ raise ECpayInvalidParam, "Lack required param #{param_diff}"
457
+ end
458
+
459
+ #Verify Value pattern of each param
460
+ self.verify_param_by_pattern(params, @all_param_pattern)
461
+
462
+ else
463
+ raise TypeError, "Recieved argument is not a hash"
464
+ end
465
+
466
+ end
467
+
468
+ end
469
+ end
@@ -0,0 +1,3 @@
1
+ module ECpayPayment
2
+ VERSION = "1.1.2"
3
+ end
@@ -0,0 +1,7 @@
1
+ require "ecpay_payment/version"
2
+ require "ecpay_payment/payment_client"
3
+ require "ecpay_payment/query_client"
4
+ require "ecpay_payment/exec_grant_refund"
5
+
6
+ module ECpayPayment
7
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ecpay_payment
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Ying Wu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-05-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '11.1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '11.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.4'
55
+ description: ''
56
+ email:
57
+ - ying.wu@ecpay.com.tw
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - Gemfile
63
+ - Rakefile
64
+ - conf/payment_conf.xml
65
+ - ecpay.gemspec
66
+ - lib/ecpay_payment.rb
67
+ - lib/ecpay_payment/ECpayPayment.xml
68
+ - lib/ecpay_payment/core_ext/hash.rb
69
+ - lib/ecpay_payment/core_ext/string.rb
70
+ - lib/ecpay_payment/error.rb
71
+ - lib/ecpay_payment/exec_grant_refund.rb
72
+ - lib/ecpay_payment/helper.rb
73
+ - lib/ecpay_payment/payment_client.rb
74
+ - lib/ecpay_payment/query_client.rb
75
+ - lib/ecpay_payment/verification.rb
76
+ - lib/ecpay_payment/version.rb
77
+ homepage: ''
78
+ licenses:
79
+ - MIT
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.6.14
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: 綠界全方位金流串接用SDK
101
+ test_files: []