ecpay_invoice 0.1.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.
@@ -0,0 +1,1075 @@
1
+
2
+ require "ecpay_invoice/error"
3
+ # require "../../../gem/lib/ecpay_invoice/error"
4
+ require "nokogiri"
5
+ require 'date'
6
+ module ECpayInvoice
7
+ class InvoiceVerifyBase
8
+ include ECpayErrorDefinition
9
+ @@param_xml = Nokogiri::XML(File.open(File.join(File.dirname(__FILE__), 'ECpayInvoice.xml')))
10
+
11
+ def get_svc_url(apiname, mode)
12
+ url = @@param_xml.xpath("/ecpayInvoice/#{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("/ecpayInvoice/#{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("/ecpayInvoice/#{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("/ecpayInvoice/#{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("/ecpayInvoice/#{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("/ecpayInvoice/#{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("/ecpayInvoice/#{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("/ecpayInvoice/#{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("/ecpayInvoice/#{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("/ecpayInvoice/#{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 InvoiceParamVerify < InvoiceVerifyBase
202
+ include ECpayErrorDefinition
203
+ def initialize(apiname)
204
+ @inv_basic_param = self.get_basic_params(apiname).freeze
205
+ @inv_conditional_param = self.get_cond_param(apiname).freeze
206
+ @all_param_pattern = self.get_all_pattern(apiname).freeze
207
+ end
208
+
209
+ def verify_inv_issue_param(params)
210
+ if params.is_a?(Hash)
211
+ #發票所有參數預設要全帶
212
+
213
+ if params.has_value?(nil)
214
+ raise ECpayInvalidParam, %Q{Parameter value cannot be nil}
215
+ end
216
+ #1. 比對欄位是否缺乏
217
+ param_diff = @inv_basic_param - params.keys()
218
+ unless param_diff == []
219
+ raise ECpayInvalidParam, %Q{Lack required invoice param #{param_diff}}
220
+ end
221
+
222
+ #2. 比對特殊欄位值相依需求
223
+ #a [CarruerType]為 1 => CustomerID 不能為空
224
+ if params['CarruerType'].to_s == '1'
225
+ if params['CustomerID'].to_s.empty?
226
+ raise ECpayInvoiceRuleViolate, "[CustomerID] can not be empty when [CarruerType] is 1."
227
+ end
228
+ # [CustomerID]不為空 => CarruerType 不能為空
229
+ elsif params['CarruerType'].to_s == ''
230
+ unless params['CustomerID'].to_s.empty?
231
+ raise ECpayInvoiceRuleViolate, "[CarruerType] can not be empty when [CustomerID] is not empty."
232
+ end
233
+ end
234
+ #b 列印註記[Print]為 1 => CustomerName, CustomerAddr
235
+ if params['Print'].to_s == '1'
236
+ if params['CustomerName'].to_s.empty? or params['CustomerAddr'].to_s.empty?
237
+ raise ECpayInvoiceRuleViolate, "[CustomerName] and [CustomerAddr] can not be empty when [Print] is 1."
238
+ end
239
+ unless params['CustomerID'].to_s.empty?
240
+ raise ECpayInvoiceRuleViolate, "[Print] can not be '1' when [CustomerID] is not empty."
241
+ end
242
+ unless params['CarruerType'].to_s.empty?
243
+ raise ECpayInvoiceRuleViolate, "[Print] can not be '1' when [CarruerType] is not empty."
244
+ end
245
+ unless params['CarruerNum'].to_s.empty?
246
+ raise ECpayInvoiceRuleViolate, "[Print] can not be '1' when [CarruerNum] is not empty."
247
+ end
248
+ end
249
+
250
+ #c CustomerPhone和CustomerEmail至少一個有值
251
+ if params['CustomerPhone'].to_s.empty? and params['CustomerEmail'].to_s.empty?
252
+ raise ECpayInvoiceRuleViolate, "[CustomerPhone] and [CustomerEmail] can not both be empty."
253
+ end
254
+
255
+ #d [TaxType]為 2 => ClearanceMark = 必須為 1 or 2,ItemTaxType 必須為空
256
+ if params['TaxType'].to_s == '2'
257
+ if !params['ItemRemark'].to_s.empty?
258
+ @item_params_list = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount', 'ItemRemark']
259
+ else
260
+ @item_params_list = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount']
261
+ end
262
+ @vat_params_list = ['ItemCount', 'ItemAmount']
263
+ unless ['1', '2'].include?(params['ClearanceMark'].to_s)
264
+ raise ECpayInvoiceRuleViolate, "[ClearanceMark] has to be 1 or 2 when [TaxType] is 2."
265
+ end
266
+ unless params['ItemTaxType'].to_s.empty?
267
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] must be empty when [TaxType] is 2."
268
+ end
269
+ # 當[TaxType]為2時為零稅率,vat為0時商品單價為免稅,不須再加稅
270
+ # 若vat為1時商品單價為含稅,須再退稅
271
+ if params['vat'].to_s == '0'
272
+ @tax_fee = 1
273
+ elsif params['vat'].to_s == '1'
274
+ @tax_fee = 1.05
275
+ end
276
+ #d.1 [TaxType]為 1 => ItemTaxType, ClearanceMark 必須為空
277
+ elsif params['TaxType'].to_s == '1'
278
+ if !params['ItemRemark'].to_s.empty?
279
+ @item_params_list = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount', 'ItemRemark']
280
+ else
281
+ @item_params_list = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount']
282
+ end
283
+ @vat_params_list = ['ItemCount', 'ItemAmount']
284
+ unless params['ItemTaxType'].to_s.empty?
285
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] must be empty when [TaxType] is 1."
286
+ end
287
+ unless params['ClearanceMark'].to_s.empty?
288
+ raise ECpayInvoiceRuleViolate, "[ClearanceMark] must be empty when [TaxType] is 1."
289
+ end
290
+ # 當[TaxType]為1時為應稅,vat為0時商品單價為免稅,須再加稅
291
+ # 若vat為1時商品單價為含稅,不須再加稅
292
+ if params['vat'].to_s == '0'
293
+ @tax_fee = 1.05
294
+ elsif params['vat'].to_s == '1'
295
+ @tax_fee = 1
296
+ end
297
+ #d.2 [TaxType]為 3 => ItemTaxType, ClearanceMark 必須為空
298
+ elsif params['TaxType'].to_s == '3'
299
+ if !params['ItemRemark'].to_s.empty?
300
+ @item_params_list = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount', 'ItemRemark']
301
+ else
302
+ @item_params_list = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount']
303
+ end
304
+ @vat_params_list = ['ItemCount', 'ItemAmount']
305
+ unless params['ItemTaxType'].to_s.empty?
306
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] must be empty when [TaxType] is 3."
307
+ end
308
+ unless params['ClearanceMark'].to_s.empty?
309
+ raise ECpayInvoiceRuleViolate, "[ClearanceMark] must be empty when [TaxType] is 3."
310
+ end
311
+ # 當[TaxType]為3時為免稅,vat為0時商品單價為免稅,不須再加稅
312
+ # 若vat為1時商品單價為含稅,須再退稅
313
+ if params['vat'].to_s == '0'
314
+ @tax_fee = 1
315
+ elsif params['vat'].to_s == '1'
316
+ @tax_fee = 1.05
317
+ end
318
+ #d.3 [TaxType]為 9 => ItemTaxType 必須為兩項商品(含)以上,且不可為空
319
+ elsif params['TaxType'].to_s == '9'
320
+ if !params['ItemRemark'].to_s.empty?
321
+ @item_params_list = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount', 'ItemRemark', 'ItemTaxType']
322
+ else
323
+ @item_params_list = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount', 'ItemTaxType']
324
+ end
325
+ @vat_params_list = ['ItemCount', 'ItemAmount', 'ItemTaxType']
326
+ unless params['ItemTaxType'].include?('|')
327
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] must contain at lease one '|'."
328
+ end
329
+ if params['ItemTaxType'].to_s.empty?
330
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] can not be empty when [TaxType] is 9."
331
+ end
332
+ # 當[ItmeTaxType]含2選項的話[ClearanceMark]須為1或2
333
+ if params['ItemTaxType'].include?('2')
334
+ unless ['1', '2'].include?(params['ClearanceMark'].to_s)
335
+ raise ECpayInvoiceRuleViolate, "[ClearanceMark] has to be 1 or 2 when [ItemTaxType] has 2."
336
+ end
337
+ end
338
+ end
339
+
340
+ #e 統一編號[CustomerIdentifier]有值時 => CarruerType != 1, 2 or 3, *Donation = 2, print = 1
341
+ unless params['CustomerIdentifier'].to_s.empty?
342
+ if ['1', '2', '3'].include?(params['CarruerType'].to_s)
343
+ raise ECpayInvoiceRuleViolate, "[CarruerType] Cannot be 1, 2 or 3 when [CustomerIdentifier] is given."
344
+ end
345
+ unless params['Donation'].to_s == '2' and params['Print'].to_s == '1'
346
+ raise ECpayInvoiceRuleViolate, "[Print] must be 1 and [Donation] must be 2 when [CustomerIdentifier] is given."
347
+ end
348
+ end
349
+
350
+ # [CarruerType]為'' or 1 時 => CarruerNum = '', [CarruerType]為 2, CarruerNum = 固定長度為 16 且格式為 2 碼大小寫字母加上 14 碼數字。 [CarruerType]為 3 ,帶固定長度為 8 且格式為 1 碼斜線「/」加上由 7 碼數字及大小寫字母組成
351
+ if ['', '1'].include?(params['CarruerType'].to_s)
352
+ unless params['CarruerNum'].to_s.empty?
353
+ raise ECpayInvoiceRuleViolate, "[CarruerNum] must be empty when [CarruerType] is empty or 1."
354
+ end
355
+ elsif params['CarruerType'].to_s == '2'
356
+ unless params['CustomerID'].to_s.empty?
357
+ raise ECpayInvoiceRuleViolate, "[CustomerID] must be empty when [CarruerType] is 2."
358
+ end
359
+ if /[A-Za-z]{2}[0-9]{14}/.match(params['CarruerNum']).nil?
360
+ raise ECpayInvoiceRuleViolate, "[CarruerNum] must be 2 alphabets and 14 numbers when [CarruerType] is 2."
361
+ end
362
+ elsif params['CarruerType'].to_s == '3'
363
+ unless params['CustomerID'].to_s.empty?
364
+ raise ECpayInvoiceRuleViolate, "[CustomerID] must be empty when [CarruerType] is 3."
365
+ end
366
+ if /^\/[A-Za-z0-9\s+-]{7}$/.match(params['CarruerNum']).nil?
367
+ raise ECpayInvoiceRuleViolate, "[CarruerNum] must start with '/' followed by 7 alphabet and number characters when [CarruerType] is 3."
368
+ end
369
+ else
370
+ raise ECpayInvoiceRuleViolate, "Unexpected value in [CarruerType]."
371
+ end
372
+
373
+ # Donation = 1 => LoveCode不能為空, print = 0
374
+ if params['Donation'].to_s == '1'
375
+ if params['LoveCode'].to_s.empty?
376
+ raise ECpayInvoiceRuleViolate, "[LoveCode] cannot be empty when [Donation] is 1."
377
+ end
378
+ unless params['Print'].to_s == '0'
379
+ raise ECpayInvoiceRuleViolate, "[Print] must be 0 when [Donation] is 1."
380
+ end
381
+ # Donation = 2 => LoveCode不能有值
382
+ elsif params['Donation'].to_s == '2'
383
+ unless params['LoveCode'].to_s.empty?
384
+ raise ECpayInvoiceRuleViolate, "[LoveCode] must be empty when [Donation] is 2."
385
+ end
386
+ end
387
+
388
+ # [vat]為0時 => ItemPrice = 未稅, ItemAmount = (ItemPrice * ItemCount) + (ItemPrice * ItemCount * tax(5%))
389
+ # 未稅加稅單一商品時直接四捨五入帶入ItemAmount,且ItemAmount等於SalesAmount
390
+ # 未稅加稅多樣商品時先算稅金加總帶入ItemAmount,且ItemAmount全部金額加總後帶入SalesAmount後四捨五入
391
+ vat_params = @vat_params_list
392
+ # 商品價錢含有管線 => 認為是多樣商品 *ItemCount , *ItemPrice , *ItemAmount 逐一用管線分割,計算數量後與第一個比對
393
+ if params['vat'].to_s == '0'
394
+ if !params['ItemPrice'].include?('|')
395
+ unless params['ItemAmount'].to_i == (params['ItemPrice'].to_i * params['ItemCount'].to_i * @tax_fee).round
396
+ raise ECpayInvoiceRuleViolate, %Q{[ItemPrice] (#{params['ItemPrice'].to_i}) times [ItemCount] (#{params['ItemCount'].to_i}) '*' tax (#{@tax_fee}) subtotal not equal [ItemAmount] (#{params['ItemAmount'].to_i})}
397
+ end
398
+ # 驗證單筆商品合計是否等於發票金額
399
+ unless params['SalesAmount'].to_i == params['ItemAmount'].to_i
400
+ raise ECpayInvoiceRuleViolate, %Q{[ItemAmount] (#{params['ItemAmount'].to_i}) not equal [SalesAmount] (#{params['SalesAmount'].to_i})}
401
+ end
402
+
403
+ elsif params['ItemPrice'].include?('|')
404
+ vat_cnt = params['ItemPrice'].split('|').length
405
+ vat_params.each do |param_name|
406
+ # Check if there's empty value.
407
+ unless /(\|\||^\||\|$)/.match(params[param_name]).nil?
408
+ raise ECpayInvoiceRuleViolate, "[#{param_name}] contains empty value."
409
+ end
410
+ p_cnt = params[param_name].split('|').length
411
+ unless vat_cnt == p_cnt
412
+ raise ECpayInvoiceRuleViolate, %Q{Count of item info [#{param_name}] (#{p_cnt}) not match item count from [ItemCount] (#{vat_cnt})}
413
+ end
414
+ end
415
+ vat_amount_arr = params['ItemAmount'].split('|')
416
+ vat_price_arr = params['ItemPrice'].split('|')
417
+ vat_count_arr = params['ItemCount'].split('|')
418
+ (1..vat_cnt).each do |index|
419
+ if @vat_params_list.length == 3
420
+ vat_tax_arr = params['ItemTaxType'].split('|')
421
+ if vat_tax_arr[index - 1].to_s == '1'
422
+ @tax_fee = 1.05
423
+ elsif vat_tax_arr[index - 1].to_s == '2' or vat_tax_arr[index - 1].to_s == '3'
424
+ @tax_fee = 1
425
+ else
426
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] can not be (#{vat_tax_arr[index - 1]}). Avaliable option: (1, 2, 3)."
427
+ end
428
+ end
429
+ unless vat_amount_arr[index - 1].to_f == (vat_price_arr[index - 1].to_i * vat_count_arr[index - 1].to_i * @tax_fee)
430
+ raise ECpayInvoiceRuleViolate, %Q{[ItemPrice] (#{vat_price_arr[index - 1].to_i}) times [ItemCount] (#{vat_count_arr[index - 1].to_i}) '*' tax(#{@tax_fee}) not match [ItemAmount] (#{vat_amount_arr[index - 1].to_f})}
431
+ end
432
+ #Verify ItemAmount subtotal equal SalesAmount
433
+ chk_amount_subtotal = 0
434
+ vat_amount_arr.each do |val|
435
+ chk_amount_subtotal += val.to_f
436
+ end
437
+ unless params['SalesAmount'].to_i == chk_amount_subtotal.round
438
+ raise ECpayInvoiceRuleViolate, %Q{[ItemAmount] (#{vat_amount_arr}) subtotal not equal [SalesAmount] (#{params['SalesAmount'].to_i})}
439
+ end
440
+ end
441
+ end
442
+ end
443
+
444
+ # [vat]為1時 => ItemPrice = 含稅, ItemAmount = ItemPrice * ItemCount
445
+ # 商品價錢含有管線 => 認為是多樣商品 *ItemCount , *ItemPrice , *ItemAmount 逐一用管線分割,計算數量後與第一個比對
446
+ # 含稅扣稅單一商品時直接四捨五入帶入ItemAmount,且ItemAmount等於SalesAmount
447
+ # 含稅扣稅多樣商品時先算稅金加總四捨五入後帶入ItemAmount,且ItemAmount全部金額加總後等於SalesAmount
448
+ if params['vat'].to_s == '1'
449
+ if !params['ItemPrice'].include?('|')
450
+
451
+ unless params['ItemAmount'].to_i == (params['ItemPrice'].to_i * params['ItemCount'].to_i / @tax_fee).round
452
+ raise ECpayInvoiceRuleViolate, %Q{[ItemPrice] (#{params['ItemPrice'].to_i}) times [ItemCount] (#{params['ItemCount'].to_i}) '/' tax (#{@tax_fee}) subtotal not equal [ItemAmount] (#{params['ItemAmount'].to_i})}
453
+ end
454
+ # 驗證單筆商品合計是否等於發票金額
455
+ unless params['SalesAmount'].to_i == params['ItemAmount'].to_i
456
+ raise ECpayInvoiceRuleViolate, %Q{[ItemAmount] (#{params['ItemAmount'].to_i}) not equal [SalesAmount] (#{params['SalesAmount'].to_i})}
457
+ end
458
+ elsif params['ItemPrice'].include?('|')
459
+ vat_cnt = params['ItemPrice'].split('|').length
460
+ vat_params.each do |param_name|
461
+ # Check if there's empty value.
462
+ unless /(\|\||^\||\|$)/.match(params[param_name]).nil?
463
+ raise ECpayInvoiceRuleViolate, "[#{param_name}] contains empty value."
464
+ end
465
+ p_cnt = params[param_name].split('|').length
466
+ unless vat_cnt == p_cnt
467
+ raise ECpayInvoiceRuleViolate, %Q{Count of item info [#{param_name}] (#{p_cnt}) not match item count from [ItemCount] (#{vat_cnt})}
468
+ end
469
+ end
470
+ vat_amount_arr = params['ItemAmount'].split('|')
471
+ vat_price_arr = params['ItemPrice'].split('|')
472
+ vat_count_arr = params['ItemCount'].split('|')
473
+ (1..vat_cnt).each do |index|
474
+ if @vat_params_list.length == 3
475
+ vat_tax_arr = params['ItemTaxType'].split('|')
476
+ if vat_tax_arr[index - 1].to_s == '1'
477
+ @tax_fee = 1
478
+ elsif vat_tax_arr[index - 1].to_s == '2' or vat_tax_arr[index - 1].to_s == '3'
479
+ @tax_fee = 1.05
480
+ else
481
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] can not be (#{vat_tax_arr[index - 1]}). Avaliable option: (1, 2, 3)."
482
+ end
483
+ end
484
+ unless vat_amount_arr[index - 1].to_i == (vat_price_arr[index - 1].to_i * vat_count_arr[index - 1].to_i / @tax_fee).round
485
+ raise ECpayInvoiceRuleViolate, %Q{[ItemPrice] (#{vat_price_arr[index - 1]}) times [ItemCount] (#{vat_count_arr[index - 1]}) '/' tax(#{@tax_fee}) not match [ItemAmount] (#{vat_amount_arr[index - 1].to_i})}
486
+ end
487
+ #Verify ItemAmount subtotal equal SalesAmount
488
+ chk_amount_subtotal = 0
489
+ vat_amount_arr.each do |val|
490
+ chk_amount_subtotal += val.to_i
491
+ end
492
+ unless params['SalesAmount'].to_i == chk_amount_subtotal
493
+ raise ECpayInvoiceRuleViolate, %Q{[ItemAmount] (#{vat_amount_arr}) subtotal not equal [SalesAmount] (#{params['SalesAmount'].to_i})}
494
+ end
495
+ end
496
+ end
497
+ end
498
+
499
+ #3. 比對商品名稱,數量,單位,價格,tax,合計,備註項目數量是否一致,欄位是否為空
500
+ if params['ItemName'].to_s.empty? or params['ItemWord'].to_s.empty?
501
+ raise ECpayInvoiceRuleViolate, "[ItemName] or [ItemWord] cannot be empty"
502
+ end
503
+
504
+ # ItemTaxType and ItemRemark會因為TaxType and ItemRemark is not empty 新增至@item_params_list
505
+ item_params = @item_params_list
506
+ #商品名稱含有管線 => 認為是多樣商品 *ItemName, *ItemCount ,*ItemWord, *ItemPrice, *ItemAmount, *ItemTaxType, *ItemRemark逐一用管線分割,計算數量後與第一個比對
507
+ if params['ItemName'].include?('|')
508
+ item_cnt = params['ItemName'].split('|').length
509
+ item_params.each do |param_name|
510
+ # Check if there's empty value.
511
+ unless /(\|\||^\||\|$)/.match(params[param_name]).nil?
512
+ raise ECpayInvoiceRuleViolate, "[#{param_name}] contains empty value."
513
+ end
514
+ p_cnt = params[param_name].split('|').length
515
+ unless item_cnt == p_cnt
516
+ raise ECpayInvoiceRuleViolate, %Q{Count of item info [#{param_name}] (#{p_cnt}) not match item count from [ItemCount] (#{item_cnt})}
517
+ end
518
+ end
519
+ # 課稅類別[TaxType] = 9 時 => ItemTaxType 能含有1,2 3(and at least contains one 1 and other)
520
+ if params['TaxType'].to_s == '9'
521
+ item_tax = params['ItemTaxType'].split('|')
522
+ p item_tax
523
+ aval_tax_type = ['1', '2', '3']
524
+ vio_tax_t = (item_tax - aval_tax_type)
525
+ unless vio_tax_t == []
526
+ raise ECpayInvoiceRuleViolate, "Ilegal [ItemTaxType]: #{vio_tax_t}"
527
+ end
528
+ unless item_tax.include?('1')
529
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] must contain at lease one '1'."
530
+ end
531
+ if item_cnt >= 2
532
+ if !item_tax.include?('2') and !item_tax.include?('3')
533
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] cannot be all 1 when [TaxType] is 9."
534
+ end
535
+ end
536
+ if item_tax.include?('2') and item_tax.include?('3')
537
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] cannot contain 2 and 3 at the same time."
538
+ end
539
+ end
540
+ else
541
+ #沒有管線 => 逐一檢查@item_params_list的欄位有無管線
542
+ item_params.each do |param_name|
543
+ if params[param_name].include?('|')
544
+ raise "Item info [#{param_name}] contains pipeline delimiter but there's only one item in param [ItemName]"
545
+ end
546
+ end
547
+ end
548
+
549
+ #4 比對所有欄位Pattern
550
+ self.verify_param_by_pattern(params, @all_param_pattern)
551
+
552
+ else
553
+ raise TypeError, "Recieved argument is not a hash"
554
+ end
555
+ end
556
+
557
+ def verify_inv_delay_param(params)
558
+ if params.is_a?(Hash)
559
+ #發票所有參數預設要全帶
560
+
561
+ if params.has_value?(nil)
562
+ raise ECpayInvalidParam, %Q{Parameter value cannot be nil}
563
+ end
564
+ #1. 比對欄位是否缺乏
565
+ param_diff = @inv_basic_param - params.keys()
566
+ unless param_diff == []
567
+ raise ECpayInvalidParam, %Q{Lack required invoice param #{param_diff}}
568
+ end
569
+
570
+ #2. 比對特殊欄位值相依需求
571
+ #a [CarruerType]為 1 => CustomerID 不能為空
572
+ if params['CarruerType'].to_s == '1'
573
+ if params['CustomerID'].to_s.empty?
574
+ raise ECpayInvoiceRuleViolate, "[CustomerID] can not be empty when [CarruerType] is 1."
575
+ end
576
+ # [CustomerID]不為空 => CarruerType 不能為空
577
+ elsif params['CarruerType'].to_s == ''
578
+ unless params['CustomerID'].to_s.empty?
579
+ raise ECpayInvoiceRuleViolate, "[CarruerType] can not be empty when [CustomerID] is not empty."
580
+ end
581
+ end
582
+ #b 列印註記[Print]為 1 => CustomerName, CustomerAddr
583
+ if params['Print'].to_s == '1'
584
+ if params['CustomerName'].to_s.empty? or params['CustomerAddr'].to_s.empty?
585
+ raise ECpayInvoiceRuleViolate, "[CustomerName] and [CustomerAddr] can not be empty when [Print] is 1."
586
+ end
587
+ unless params['CustomerID'].to_s.empty?
588
+ raise ECpayInvoiceRuleViolate, "[Print] can not be '1' when [CustomerID] is not empty."
589
+ end
590
+ unless params['CarruerType'].to_s.empty?
591
+ raise ECpayInvoiceRuleViolate, "[Print] can not be '1' when [CarruerType] is not empty."
592
+ end
593
+ unless params['CarruerNum'].to_s.empty?
594
+ raise ECpayInvoiceRuleViolate, "[Print] can not be '1' when [CarruerNum] is not empty."
595
+ end
596
+ end
597
+
598
+ #c CustomerPhone和CustomerEmail至少一個有值
599
+ if params['CustomerPhone'].to_s.empty? and params['CustomerEmail'].to_s.empty?
600
+ raise ECpayInvoiceRuleViolate, "[CustomerPhone] and [CustomerEmail] can not both be empty."
601
+ end
602
+
603
+ #d [TaxType]為 2 => ClearanceMark = 必須為 1 or 2,ItemTaxType 必須為空
604
+ if params['TaxType'].to_s == '2'
605
+ @tax_fee = 1.05
606
+ @item_params_list = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount']
607
+ @vat_params_list = ['ItemCount', 'ItemAmount']
608
+ unless ['1', '2'].include?(params['ClearanceMark'].to_s)
609
+ raise ECpayInvoiceRuleViolate, "[ClearanceMark] has to be 1 or 2 when [TaxType] is 2."
610
+ end
611
+ unless params['ItemTaxType'].to_s.empty?
612
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] must be empty when [TaxType] is 2."
613
+ end
614
+ #d.1 [TaxType]為 1 => ItemTaxType, ClearanceMark 必須為空
615
+ elsif params['TaxType'].to_s == '1'
616
+ @tax_fee = 1
617
+ @item_params_list = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount']
618
+ @vat_params_list = ['ItemCount', 'ItemAmount']
619
+ unless params['ItemTaxType'].to_s.empty?
620
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] must be empty when [TaxType] is 1."
621
+ end
622
+ unless params['ClearanceMark'].to_s.empty?
623
+ raise ECpayInvoiceRuleViolate, "[ClearanceMark] must be empty when [TaxType] is 1."
624
+ end
625
+ #d.2 [TaxType]為 3 => ItemTaxType, ClearanceMark 必須為空
626
+ elsif params['TaxType'].to_s == '3'
627
+ @tax_fee = 1.05
628
+ @item_params_list = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount']
629
+ @vat_params_list = ['ItemCount', 'ItemAmount']
630
+ unless params['ItemTaxType'].to_s.empty?
631
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] must be empty when [TaxType] is 3."
632
+ end
633
+ unless params['ClearanceMark'].to_s.empty?
634
+ raise ECpayInvoiceRuleViolate, "[ClearanceMark] must be empty when [TaxType] is 3."
635
+ end
636
+ #d.3 [TaxType]為 9 => ItemTaxType 必須為兩項商品(含)以上,且不可為空
637
+ elsif params['TaxType'].to_s == '9'
638
+ @item_params_list = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount', 'ItemTaxType']
639
+ @vat_params_list = ['ItemCount', 'ItemAmount', 'ItemTaxType']
640
+ unless params['ItemTaxType'].include?('|')
641
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] must contain at lease one '|'."
642
+ end
643
+ if params['ItemTaxType'].to_s.empty?
644
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] can not be empty when [TaxType] is 9."
645
+ end
646
+ end
647
+
648
+ #e 統一編號[CustomerIdentifier]有值時 => CarruerType != 1, 2 or 3, *Donation = 2, print = 1
649
+ unless params['CustomerIdentifier'].to_s.empty?
650
+ if ['1', '2', '3'].include?(params['CarruerType'].to_s)
651
+ raise ECpayInvoiceRuleViolate, "[CarruerType] Cannot be 1, 2 or 3 when [CustomerIdentifier] is given."
652
+ end
653
+ unless params['Donation'].to_s == '2' and params['Print'].to_s == '1'
654
+ raise ECpayInvoiceRuleViolate, "[Print] must be 1 and [Donation] must be 2 when [CustomerIdentifier] is given."
655
+ end
656
+ end
657
+
658
+ # DelayFlag Rules When [DelayFlag] is '1' the [DelayDay] range be between 1 and 15
659
+ # When [DelayFlag] is '2' the [DelayDay] range be between 0 and 15
660
+ if params['DelayFlag'].to_s == '1'
661
+ if params['DelayDay'].to_i > 15 or params['DelayDay'].to_i < 1
662
+ raise ECpayInvoiceRuleViolate, "[DelayDay] must be between 1 and 15 when [DelayFlag] is '1'."
663
+ end
664
+ elsif params['DelayFlag'].to_s == '2'
665
+ if params['DelayDay'].to_i > 15 or params['DelayDay'].to_i < 0
666
+ raise ECpayInvoiceRuleViolate, "[DelayDay] must be between 0 and 15 when [DelayFlag] is '2'."
667
+ end
668
+ end
669
+
670
+ # [CarruerType]為'' or 1 時 => CarruerNum = '', [CarruerType]為 2, CarruerNum = 固定長度為 16 且格式為 2 碼大小寫字母加上 14 碼數字。 [CarruerType]為 3 ,帶固定長度為 8 且格式為 1 碼斜線「/」加上由 7 碼數字及大小寫字母組成
671
+ if ['', '1'].include?(params['CarruerType'].to_s)
672
+ unless params['CarruerNum'].to_s == ''
673
+ raise ECpayInvoiceRuleViolate, "[CarruerNum] must be empty when [CarruerType] is empty or 1."
674
+ end
675
+ elsif params['CarruerType'].to_s == '2'
676
+ unless params['CustomerID'].to_s.empty?
677
+ raise ECpayInvoiceRuleViolate, "[CustomerID] must be empty when [CarruerType] is 3."
678
+ end
679
+ if /[A-Za-z]{2}[0-9]{14}/.match(params['CarruerNum']).nil?
680
+ raise ECpayInvoiceRuleViolate, "[CarruerNum] must be 2 alphabets and 14 numbers when [CarruerType] is 2."
681
+ end
682
+ elsif params['CarruerType'].to_s == '3'
683
+ unless params['CustomerID'].to_s.empty?
684
+ raise ECpayInvoiceRuleViolate, "[CustomerID] must be empty when [CarruerType] is 3."
685
+ end
686
+ if /^\/[A-Za-z0-9\s+-]{7}$/.match(params['CarruerNum']).nil?
687
+ raise ECpayInvoiceRuleViolate, "[CarruerNum] must start with '/' followed by 7 alphabet and number characters when [CarruerType] is 3."
688
+ end
689
+ else
690
+ raise ECpayInvoiceRuleViolate, "Unexpected value in [CarruerType]."
691
+ end
692
+
693
+ # Donation = 1 => LoveCode不能為空, print = 0
694
+ if params['Donation'].to_s == '1'
695
+ if params['LoveCode'].to_s.empty?
696
+ raise ECpayInvoiceRuleViolate, "[LoveCode] cannot be empty when [Donation] is 1."
697
+ end
698
+ unless params['Print'].to_s == '0'
699
+ raise ECpayInvoiceRuleViolate, "[Print] must be 0 when [Donation] is 1."
700
+ end
701
+ # Donation = 2 => LoveCode不能有值
702
+ elsif params['Donation'].to_s == '2'
703
+ unless params['LoveCode'].to_s.empty?
704
+ raise ECpayInvoiceRuleViolate, "[LoveCode] must be empty when [Donation] is 2."
705
+ end
706
+ end
707
+
708
+ vat_params = @vat_params_list
709
+ # 商品價錢含有管線 => 認為是多樣商品 *ItemCount , *ItemPrice , *ItemAmount 逐一用管線分割,計算數量後與第一個比對
710
+ if !params['ItemPrice'].include?('|')
711
+ unless params['ItemAmount'].to_i == (params['ItemPrice'].to_i * params['ItemCount'].to_i / @tax_fee).round
712
+ raise ECpayInvoiceRuleViolate, %Q{[ItemPrice] (#{params['ItemPrice'].to_i}) times [ItemCount] (#{params['ItemCount'].to_i}) '/' tax (#{@tax_fee}) subtotal not equal [ItemAmount] (#{params['ItemAmount'].to_i})}
713
+ end
714
+ # 驗證單筆商品合計是否等於發票金額
715
+ unless params['SalesAmount'].to_i == params['ItemAmount'].to_i
716
+ raise ECpayInvoiceRuleViolate, %Q{[ItemAmount] (#{params['ItemAmount'].to_i}) not equal [SalesAmount] (#{params['SalesAmount'].to_i})}
717
+ end
718
+ elsif params['ItemPrice'].include?('|')
719
+ vat_cnt = params['ItemPrice'].split('|').length
720
+ vat_params.each do |param_name|
721
+ # Check if there's empty value.
722
+ unless /(\|\||^\||\|$)/.match(params[param_name]).nil?
723
+ raise ECpayInvoiceRuleViolate, "[#{param_name}] contains empty value."
724
+ end
725
+ p_cnt = params[param_name].split('|').length
726
+ unless vat_cnt == p_cnt
727
+ raise ECpayInvoiceRuleViolate, %Q{Count of item info [#{param_name}] (#{p_cnt}) not match item count from [ItemCount] (#{vat_cnt})}
728
+ end
729
+ end
730
+ vat_amount_arr = params['ItemAmount'].split('|')
731
+ vat_price_arr = params['ItemPrice'].split('|')
732
+ vat_count_arr = params['ItemCount'].split('|')
733
+ (1..vat_cnt).each do |index|
734
+ if @vat_params_list.length == 3
735
+ vat_tax_arr = params['ItemTaxType'].split('|')
736
+ if vat_tax_arr[index - 1].to_s == '1'
737
+ @tax_fee = 1
738
+ elsif vat_tax_arr[index - 1].to_s == '2' or vat_tax_arr[index - 1].to_s == '3'
739
+ @tax_fee = 1.05
740
+ else
741
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] can not be (#{vat_tax_arr[index - 1]}). Avaliable option: (1, 2, 3)."
742
+ end
743
+ end
744
+ unless vat_amount_arr[index - 1].to_i == (vat_price_arr[index - 1].to_i * vat_count_arr[index - 1].to_i / @tax_fee).round
745
+ raise ECpayInvoiceRuleViolate, %Q{[ItemPrice] (#{vat_price_arr[index - 1]}) times [ItemCount] (#{vat_count_arr[index - 1]}) '/' tax(#{@tax_fee}) not match [ItemAmount] (#{vat_amount_arr[index - 1].to_i})}
746
+ end
747
+ #Verify ItemAmount subtotal equal SalesAmount
748
+ chk_amount_subtotal = 0
749
+ vat_amount_arr.each do |val|
750
+ chk_amount_subtotal += val.to_i
751
+ end
752
+ unless params['SalesAmount'].to_i == chk_amount_subtotal
753
+ raise ECpayInvoiceRuleViolate, %Q{[ItemAmount] (#{vat_amount_arr}) subtotal not equal [SalesAmount] (#{params['SalesAmount'].to_i})}
754
+ end
755
+ end
756
+ end
757
+
758
+ #3. 比對商品名稱,數量,單位,價格,tax,合計,備註項目數量是否一致,欄位是否為空
759
+ if params['ItemName'].to_s.empty? or params['ItemWord'].to_s.empty?
760
+ raise ECpayInvoiceRuleViolate, "[ItemName] or [ItemWord] cannot be empty"
761
+ end
762
+ item_params = @item_params_list
763
+ #商品名稱含有管線 => 認為是多樣商品 *ItemName, *ItemCount ,*ItemWord, *ItemPrice, *ItemAmount逐一用管線分割,計算數量後與第一個比對
764
+ if params['ItemName'].include?('|')
765
+ item_cnt = params['ItemName'].split('|').length
766
+ item_params.each do |param_name|
767
+ # Check if there's empty value.
768
+ unless /(\|\||^\||\|$)/.match(params[param_name]).nil?
769
+ raise ECpayInvoiceRuleViolate, "[#{param_name}] contains empty value."
770
+ end
771
+ p_cnt = params[param_name].split('|').length
772
+ unless item_cnt == p_cnt
773
+ raise ECpayInvoiceRuleViolate, %Q{Count of item info [#{param_name}] (#{p_cnt}) not match item count from [ItemCount] (#{item_cnt})}
774
+ end
775
+ end
776
+ # 課稅類別[TaxType] = 9 時 => ItemTaxType 能含有1,2 3(and at least contains one 1 and other)
777
+ if params['TaxType'].to_s == '9'
778
+ item_tax = params['ItemTaxType'].split('|')
779
+ p item_tax
780
+ aval_tax_type = ['1', '2', '3']
781
+ vio_tax_t = (item_tax - aval_tax_type)
782
+ unless vio_tax_t == []
783
+ raise ECpayInvoiceRuleViolate, "Ilegal [ItemTaxType]: #{vio_tax_t}"
784
+ end
785
+ unless item_tax.include?('1')
786
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] must contain at lease one '1'."
787
+ end
788
+ if !item_tax.include?('2') and !item_tax.include?('3')
789
+ raise ECpayInvoiceRuleViolate, "[ItemTaxType] cannot be all 1 when [TaxType] is 9."
790
+ end
791
+ end
792
+ else
793
+ #沒有管線 => 逐一檢查後6項有無管線
794
+ item_params.each do |param_name|
795
+ if params[param_name].include?('|')
796
+ raise "Item info [#{param_name}] contains pipeline delimiter but there's only one item in param [ItemName]"
797
+ end
798
+ end
799
+ end
800
+
801
+ #4 比對所有欄位Pattern
802
+ self.verify_param_by_pattern(params, @all_param_pattern)
803
+
804
+ else
805
+ raise TypeError, "Recieved argument is not a hash"
806
+ end
807
+ end
808
+
809
+ def verify_inv_trigger_param(params)
810
+ if params.is_a?(Hash)
811
+ param_diff = @inv_basic_param - params.keys
812
+ unless param_diff == []
813
+ raise ECpayInvalidParam, "Lack required param #{param_diff}"
814
+ end
815
+
816
+ #Verify Value pattern of each param
817
+ self.verify_param_by_pattern(params, @all_param_pattern)
818
+
819
+ else
820
+ raise TypeError, "Recieved argument is not a hash"
821
+ end
822
+
823
+ end
824
+
825
+ def verify_inv_allowance_param(params)
826
+ if params.is_a?(Hash)
827
+ #發票所有參數預設要全帶
828
+
829
+ if params.has_value?(nil)
830
+ raise ECpayInvalidParam, %Q{Parameter value cannot be nil}
831
+ end
832
+ #1. 比對欄位是否缺乏
833
+ param_diff = @inv_basic_param - params.keys()
834
+ unless param_diff == []
835
+ raise ECpayInvalidParam, %Q{Lack required invoice param #{param_diff}}
836
+ end
837
+
838
+ #2. 比對特殊欄位值相依需求
839
+ #NotifyPhone和NotifyMail至少一個有值
840
+ if params['AllowanceNotify'].to_s == 'S'
841
+ if params['NotifyPhone'].to_s.empty?
842
+ raise ECpayInvoiceRuleViolate, "[NotifyPhone] cannot be empty."
843
+ end
844
+ elsif params['AllowanceNotify'].to_s == 'E'
845
+ if params['NotifyMail'].to_s.empty?
846
+ raise ECpayInvoiceRuleViolate, "[NotifyMail] cannot be empty."
847
+ end
848
+ elsif params['AllowanceNotify'].to_s == 'A'
849
+ if params['NotifyPhone'].to_s.empty? or params['NotifyMail'].to_s.empty?
850
+ raise ECpayInvoiceRuleViolate, "[NotifyPhone] and [NotifyMail] can not be empty."
851
+ end
852
+ end
853
+
854
+ vat_params = ['ItemCount', 'ItemAmount']
855
+ # 商品價錢含有管線 => 認為是多樣商品 *ItemCount , *ItemPrice , *ItemAmount 逐一用管線分割,計算數量後與第一個比對
856
+ # 驗證單筆ItemAmount = (ItemPrice * ItemCount)
857
+ if !params['ItemPrice'].include?('|')
858
+ unless params['ItemAmount'].to_i == (params['ItemPrice'].to_i * params['ItemCount'].to_i).round
859
+ raise ECpayInvoiceRuleViolate, %Q{[ItemPrice] (#{params['ItemPrice'].to_i}) times [ItemCount] (#{params['ItemCount'].to_i}) subtotal not equal [ItemAmount] (#{params['ItemAmount'].to_i})}
860
+ end
861
+ # 驗證單筆商品合計是否等於發票金額
862
+ unless params['AllowanceAmount'].to_i == params['ItemAmount'].to_i
863
+ raise ECpayInvoiceRuleViolate, %Q{[ItemAmount] (#{params['ItemAmount'].to_i}) not equal [AllowanceAmount] (#{params['AllowanceAmount'].to_i})}
864
+ end
865
+ elsif params['ItemPrice'].include?('|')
866
+ vat_cnt = params['ItemPrice'].split('|').length
867
+ vat_params.each do |param_name|
868
+ # Check if there's empty value.
869
+ unless /(\|\||^\||\|$)/.match(params[param_name]).nil?
870
+ raise ECpayInvoiceRuleViolate, "[#{param_name}] contains empty value."
871
+ end
872
+ p_cnt = params[param_name].split('|').length
873
+ unless vat_cnt == p_cnt
874
+ raise ECpayInvoiceRuleViolate, %Q{Count of item info [#{param_name}] (#{p_cnt}) not match item count from [ItemCount] (#{vat_cnt})}
875
+ end
876
+ end
877
+ vat_amount_arr = params['ItemAmount'].split('|')
878
+ vat_price_arr = params['ItemPrice'].split('|')
879
+ vat_count_arr = params['ItemCount'].split('|')
880
+ (1..vat_cnt).each do |index|
881
+ unless vat_amount_arr[index - 1].to_i == (vat_price_arr[index - 1].to_i * vat_count_arr[index - 1].to_i).round
882
+ raise ECpayInvoiceRuleViolate, %Q{[ItemPrice] (#{vat_price_arr[index - 1]}) times [ItemCount] (#{vat_count_arr[index - 1]}) not match [ItemAmount] (#{vat_amount_arr[index - 1].to_i})}
883
+ end
884
+ #Verify ItemAmount subtotal equal SalesAmount
885
+ chk_amount_subtotal = 0
886
+ vat_amount_arr.each do |val|
887
+ chk_amount_subtotal += val.to_i
888
+ end
889
+ unless params['AllowanceAmount'].to_i == chk_amount_subtotal
890
+ raise ECpayInvoiceRuleViolate, %Q{[ItemAmount] (#{vat_amount_arr}) subtotal not equal [AllowanceAmount] (#{params['AllowanceAmount'].to_i})}
891
+ end
892
+ end
893
+ end
894
+
895
+ #3. 比對商品名稱,數量,單位,價格,tax,合計,備註項目數量是否一致,欄位是否為空
896
+ if params['ItemName'].to_s.empty? or params['ItemWord'].to_s.empty?
897
+ raise ECpayInvoiceRuleViolate, "[ItemName] or [ItemWord] cannot be empty"
898
+ end
899
+ item_params = ['ItemCount', 'ItemWord', 'ItemPrice', 'ItemAmount']
900
+ #商品名稱含有管線 => 認為是多樣商品 *ItemName, *ItemCount ,*ItemWord, *ItemPrice, *ItemAmount逐一用管線分割,計算數量後與第一個比對
901
+ if params['ItemName'].include?('|')
902
+ item_cnt = params['ItemName'].split('|').length
903
+ item_params.each do |param_name|
904
+ # Check if there's empty value.
905
+ unless /(\|\||^\||\|$)/.match(params[param_name]).nil?
906
+ raise ECpayInvoiceRuleViolate, "[#{param_name}] contains empty value."
907
+ end
908
+ p_cnt = params[param_name].split('|').length
909
+ unless item_cnt == p_cnt
910
+ raise ECpayInvoiceRuleViolate, %Q{Count of item info [#{param_name}] (#{p_cnt}) not match item count from [ItemCount] (#{item_cnt})}
911
+ end
912
+ end
913
+ # ItemTaxType 能含有1,2 3(and at least contains one 1 and other)
914
+ if params['ItemTaxType'].include?('|')
915
+ item_tax = params['ItemTaxType'].split('|')
916
+ aval_tax_type = ['1', '3']
917
+ vio_tax_t = (item_tax - aval_tax_type)
918
+ unless vio_tax_t == []
919
+ raise ECpayInvoiceRuleViolate, "Ilegal [ItemTaxType]: #{vio_tax_t}"
920
+ end
921
+ end
922
+ else
923
+ #沒有管線 => 逐一檢查後6項有無管線
924
+ item_params.each do |param_name|
925
+ if params[param_name].include?('|')
926
+ raise "Item info [#{param_name}] contains pipeline delimiter but there's only one item in param [ItemName]"
927
+ end
928
+ end
929
+ end
930
+
931
+ #4 比對所有欄位Pattern
932
+ self.verify_param_by_pattern(params, @all_param_pattern)
933
+
934
+ else
935
+ raise TypeError, "Recieved argument is not a hash"
936
+ end
937
+ end
938
+
939
+ def verify_inv_issue_invalid_param(params)
940
+ if params.is_a?(Hash)
941
+ param_diff = @inv_basic_param - params.keys
942
+ unless param_diff == []
943
+ raise ECpayInvalidParam, "Lack required param #{param_diff}"
944
+ end
945
+
946
+ #Verify Value pattern of each param
947
+ self.verify_param_by_pattern(params, @all_param_pattern)
948
+
949
+ else
950
+ raise TypeError, "Recieved argument is not a hash"
951
+ end
952
+
953
+ end
954
+
955
+ def verify_inv_allowance_invalid_param(params)
956
+ if params.is_a?(Hash)
957
+ param_diff = @inv_basic_param - params.keys
958
+ unless param_diff == []
959
+ raise ECpayInvalidParam, "Lack required param #{param_diff}"
960
+ end
961
+
962
+ #Verify Value pattern of each param
963
+ self.verify_param_by_pattern(params, @all_param_pattern)
964
+
965
+ else
966
+ raise TypeError, "Recieved argument is not a hash"
967
+ end
968
+
969
+ end
970
+ end
971
+
972
+ class QueryParamVerify < InvoiceVerifyBase
973
+ include ECpayErrorDefinition
974
+ def initialize(apiname)
975
+ @inv_basic_param = self.get_basic_params(apiname).freeze
976
+ @inv_conditional_param = self.get_cond_param(apiname).freeze
977
+ @all_param_pattern = self.get_all_pattern(apiname).freeze
978
+ end
979
+
980
+ def verify_query_param(params)
981
+ if params.is_a?(Hash)
982
+ param_diff = @inv_basic_param - params.keys
983
+ unless param_diff == []
984
+ raise ECpayInvalidParam, "Lack required param #{param_diff}"
985
+ end
986
+
987
+ #Verify Value pattern of each param
988
+ self.verify_param_by_pattern(params, @all_param_pattern)
989
+
990
+ else
991
+ raise TypeError, "Recieved argument is not a hash"
992
+ end
993
+
994
+ end
995
+ end
996
+
997
+ class NotifyParamVerify < InvoiceVerifyBase
998
+ include ECpayErrorDefinition
999
+ def initialize(apiname)
1000
+ @inv_basic_param = self.get_basic_params(apiname).freeze
1001
+ @inv_conditional_param = self.get_cond_param(apiname).freeze
1002
+ @all_param_pattern = self.get_all_pattern(apiname).freeze
1003
+ end
1004
+
1005
+ def verify_notify_param(params)
1006
+ if params.is_a?(Hash)
1007
+ #發送發票通知預設參數要全帶
1008
+
1009
+ if params.has_value?(nil)
1010
+ raise ECpayInvalidParam, %Q{Parameter value cannot be nil}
1011
+ end
1012
+ #1. 比對欄位是否缺乏
1013
+ param_diff = @inv_basic_param - params.keys()
1014
+ unless param_diff == []
1015
+ raise ECpayInvalidParam, %Q{Lack required invoice param #{param_diff}}
1016
+ end
1017
+
1018
+ #2. 比對特殊欄位值相依需求
1019
+ #a Phone和NotifyMail至少一個有值
1020
+ if params['Phone'].to_s.empty? and params['NotifyMail'].to_s.empty?
1021
+ raise ECpayInvoiceRuleViolate, "[Phone] and [NotifyMail] can not both be empty."
1022
+ end
1023
+
1024
+ #b [Notify] is S [Phone] can not be empty or [Notify] is E [NotifyMail] can not be empty
1025
+ # If [Notify] is A [Phone] and [NotifyMail] can not both be empty
1026
+ if params['Notify'].to_s == 'S'
1027
+ if params['Phone'].to_s.empty?
1028
+ raise ECpayInvoiceRuleViolate, "[Phone] can not be empty when [Notify] is 'S'."
1029
+ end
1030
+ elsif params['Notify'].to_s == 'E'
1031
+ if params['NotifyMail'].to_s.empty?
1032
+ raise ECpayInvoiceRuleViolate, "[NotifyMail] can not be empty when [Notify] is 'E'."
1033
+ end
1034
+ elsif params['Notify'].to_s == 'A'
1035
+ if params['Phone'].to_s.empty? or params['NotifyMail'].to_s.empty?
1036
+ raise ECpayInvoiceRuleViolate, "[Phone] and [NotifyMail] can not be empty when [Notify] is 'A'."
1037
+ end
1038
+ else
1039
+ raise ECpayInvoiceRuleViolate, "Unexpected value in [Notify]."
1040
+ end
1041
+
1042
+ #c [InvoiceTag] is I,II,A,AI,AW [InvoiceNo] can not be empty or [InvoiceTag] is A,AI [AllowanceNo] can not be empty
1043
+ if params['InvoiceTag'].to_s == 'I' or params['InvoiceTag'].to_s == 'II' or params['InvoiceTag'].to_s == 'AW'
1044
+ if params['InvoiceNo'].to_s.empty?
1045
+ raise ECpayInvoiceRuleViolate, "[InvoiceNo] can not be empty."
1046
+ end
1047
+ elsif params['InvoiceTag'].to_s == 'A' or params['InvoiceTag'].to_s == 'AI'
1048
+ if /^\d{16}$/.match(params['AllowanceNo']).nil?
1049
+ raise ECpayInvoiceRuleViolate, "[AllowanceNo] must followed by 16 number characters when [InvoiceTag] is 'A' or 'AI'."
1050
+ end
1051
+ if params['InvoiceNo'].to_s.empty?
1052
+ if params['AllowanceNo'].to_s.empty?
1053
+ raise ECpayInvoiceRuleViolate, "[InvoiceNo] and [AllowanceNo] can not be empty when [Notify] is 'A' or 'AI'."
1054
+ end
1055
+ raise ECpayInvoiceRuleViolate, "[InvoiceNo] can not be empty."
1056
+ end
1057
+ unless params['InvoiceNo'].to_s.empty?
1058
+ if params['AllowanceNo'].to_s.empty?
1059
+ raise ECpayInvoiceRuleViolate, "[AllowanceNo] can not be empty."
1060
+ end
1061
+ end
1062
+ else
1063
+ raise ECpayInvoiceRuleViolate, "Unexpected value in [InvoiceTag]."
1064
+ end
1065
+
1066
+ #Verify Value pattern of each param
1067
+ self.verify_param_by_pattern(params, @all_param_pattern)
1068
+
1069
+ else
1070
+ raise TypeError, "Recieved argument is not a hash"
1071
+ end
1072
+
1073
+ end
1074
+ end
1075
+ end