tappay_ruby 0.5.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +50 -1
- data/lib/tappay/credit_card/instalment.rb +28 -2
- data/lib/tappay/credit_card/pay.rb +6 -104
- data/lib/tappay/endpoints.rb +19 -3
- data/lib/tappay/line_pay/pay.rb +30 -0
- data/lib/tappay/payment_base.rb +115 -0
- data/lib/tappay/version.rb +3 -1
- data/lib/tappay.rb +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef378bc35a591f5a2c295d7e2c530e174484e200fde3413978081103c4a7a8e3
|
4
|
+
data.tar.gz: b15ecfb7ad4c2f13093578a4bfc1a5468ad9b014b04fdc3e561128d6f33cfcbb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85a20b681bcd1ba1dd830506a3fab64c81652ae61703790f38866cc6d452926272151918914ffaca2d5f01b5dcdcf94cd251dfc707c77b7fa2926934f8622f8b
|
7
|
+
data.tar.gz: d72a42f89901fbe206b816d24397a6552326e509cb8c7959f05121091179fe0b50b7b61e075afc70a426e07ed1608e04cb1ae8c67a4c1cc50c3a8e7e3806b43f
|
data/README.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# TapPay Ruby Gem
|
2
2
|
|
3
|
+
![Gem Version](https://img.shields.io/gem/v/tappay_ruby)
|
3
4
|
[![RSpec](https://github.com/7a6163/tappay/actions/workflows/rspec.yml/badge.svg)](https://github.com/7a6163/tappay/actions/workflows/rspec.yml)
|
4
5
|
[![codecov](https://codecov.io/gh/7a6163/tappay/branch/main/graph/badge.svg)](https://codecov.io/gh/7a6163/tappay)
|
5
6
|
|
@@ -197,6 +198,24 @@ if result['status'] == 0
|
|
197
198
|
end
|
198
199
|
```
|
199
200
|
|
201
|
+
## URL Properties
|
202
|
+
|
203
|
+
The `result_url` (JSONObject) property is required when using LINE Pay, JKOPAY, 悠遊付, Atome, Pi錢包, 全盈支付, or when three_domain_secure is true. It contains the following URL fields:
|
204
|
+
|
205
|
+
```json
|
206
|
+
{
|
207
|
+
"frontend_redirect_url": "https://example.com/redirect", // Required - URL where consumer will be redirected after completing the transaction
|
208
|
+
"backend_notify_url": "https://example.com/notify", // Required - URL where your server receives transaction results (only port 443)
|
209
|
+
"go_back_url": "https://example.com/back" // Optional - URL for 3D verification error cases (E.SUN, Cathay United, Taishin banks)
|
210
|
+
}
|
211
|
+
```
|
212
|
+
|
213
|
+
- `frontend_redirect_url` (String): After the consumer completes the transaction process in LINE Pay, JKOPAY, 悠遊付, Atome, Pi錢包, 全盈支付, or 3D verification, they will be redirected to this frontend URL. Must start with https.
|
214
|
+
|
215
|
+
- `backend_notify_url` (String): URL where your server receives transaction results. Must start with https and only supports port 443.
|
216
|
+
|
217
|
+
- `go_back_url` (String): For 3D verification transactions, this URL is used when consumers are redirected to the TapPay Error page due to improper operation. This scenario only occurs with E.SUN Bank, Cathay United Bank, and Taishin Bank. You can define this URL in the transaction request or set it in TapPay Portal > Developer Content > System Settings > Redirect Link Settings. It's strongly recommended to define this field for 3D transactions to ensure consumers can return to complete the transaction or view results.
|
218
|
+
|
200
219
|
## Usage
|
201
220
|
|
202
221
|
### Pay by Prime
|
@@ -224,7 +243,7 @@ if result['status'] == 0
|
|
224
243
|
card_token = result['card_secret']['card_token']
|
225
244
|
# Store card_key and card_token securely for future payments
|
226
245
|
end
|
227
|
-
|
246
|
+
|
228
247
|
# Handle payment URL if present (for 3D Secure, LINE Pay, JKO Pay)
|
229
248
|
if result['payment_url']
|
230
249
|
redirect_to result['payment_url']
|
@@ -324,6 +343,36 @@ rescue Tappay::ValidationError => e
|
|
324
343
|
end
|
325
344
|
```
|
326
345
|
|
346
|
+
### Example Usage with result_url
|
347
|
+
|
348
|
+
```ruby
|
349
|
+
# Example of payment with result_url for LINE Pay
|
350
|
+
result = Tappay::LinePay::Pay.create(
|
351
|
+
prime: 'prime_from_tappay_sdk',
|
352
|
+
amount: 100,
|
353
|
+
merchant_id: 'your_merchant_id',
|
354
|
+
details: 'Product Item',
|
355
|
+
result_url: {
|
356
|
+
frontend_redirect_url: 'https://example.com/payment/complete',
|
357
|
+
backend_notify_url: 'https://example.com/payment/notify',
|
358
|
+
go_back_url: 'https://example.com/payment/error'
|
359
|
+
}
|
360
|
+
)
|
361
|
+
|
362
|
+
# Example of payment with result_url for 3D verification
|
363
|
+
result = Tappay::CreditCard::Pay.by_prime(
|
364
|
+
prime: 'prime_from_tappay_sdk',
|
365
|
+
amount: 100,
|
366
|
+
merchant_id: 'your_merchant_id',
|
367
|
+
three_domain_secure: true,
|
368
|
+
result_url: {
|
369
|
+
frontend_redirect_url: 'https://example.com/3d/complete',
|
370
|
+
backend_notify_url: 'https://example.com/3d/notify',
|
371
|
+
go_back_url: 'https://example.com/3d/error'
|
372
|
+
}
|
373
|
+
)
|
374
|
+
```
|
375
|
+
|
327
376
|
## Development
|
328
377
|
|
329
378
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
|
@@ -23,7 +23,12 @@ module Tappay
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def endpoint_url
|
26
|
-
Tappay::Endpoints::
|
26
|
+
Tappay::Endpoints::Payment.pay_by_prime_url
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate_options!
|
30
|
+
super
|
31
|
+
validate_result_url_for_instalment!
|
27
32
|
end
|
28
33
|
|
29
34
|
private
|
@@ -31,6 +36,14 @@ module Tappay
|
|
31
36
|
def additional_required_options
|
32
37
|
[:prime, :cardholder, :instalment]
|
33
38
|
end
|
39
|
+
|
40
|
+
def validate_result_url_for_instalment!
|
41
|
+
return if options[:result_url] &&
|
42
|
+
options[:result_url][:frontend_redirect_url] &&
|
43
|
+
options[:result_url][:backend_notify_url]
|
44
|
+
|
45
|
+
raise ValidationError, "result_url with frontend_redirect_url and backend_notify_url is required for instalment payments"
|
46
|
+
end
|
34
47
|
end
|
35
48
|
|
36
49
|
class InstalmentByToken < PaymentBase
|
@@ -47,7 +60,12 @@ module Tappay
|
|
47
60
|
end
|
48
61
|
|
49
62
|
def endpoint_url
|
50
|
-
Tappay::Endpoints::
|
63
|
+
Tappay::Endpoints::Payment.pay_by_token_url
|
64
|
+
end
|
65
|
+
|
66
|
+
def validate_options!
|
67
|
+
super
|
68
|
+
validate_result_url_for_instalment!
|
51
69
|
end
|
52
70
|
|
53
71
|
private
|
@@ -55,6 +73,14 @@ module Tappay
|
|
55
73
|
def additional_required_options
|
56
74
|
[:card_key, :card_token, :instalment]
|
57
75
|
end
|
76
|
+
|
77
|
+
def validate_result_url_for_instalment!
|
78
|
+
return if options[:result_url] &&
|
79
|
+
options[:result_url][:frontend_redirect_url] &&
|
80
|
+
options[:result_url][:backend_notify_url]
|
81
|
+
|
82
|
+
raise ValidationError, "result_url with frontend_redirect_url and backend_notify_url is required for instalment payments"
|
83
|
+
end
|
58
84
|
end
|
59
85
|
end
|
60
86
|
end
|
@@ -1,107 +1,9 @@
|
|
1
|
-
|
2
|
-
module CreditCard
|
3
|
-
class PaymentBase < Client
|
4
|
-
def initialize(options = {})
|
5
|
-
super
|
6
|
-
validate_options!
|
7
|
-
end
|
8
|
-
|
9
|
-
def execute
|
10
|
-
post(endpoint_url, payment_data)
|
11
|
-
end
|
12
|
-
|
13
|
-
protected
|
14
|
-
|
15
|
-
def endpoint_url
|
16
|
-
raise NotImplementedError, "Subclass must implement abstract method 'endpoint_url'"
|
17
|
-
end
|
18
|
-
|
19
|
-
def payment_data
|
20
|
-
# Check configuration conflicts first
|
21
|
-
if Tappay.configuration.merchant_group_id && Tappay.configuration.merchant_id
|
22
|
-
raise Tappay::ValidationError, "merchant_group_id and merchant_id cannot be used together"
|
23
|
-
end
|
24
|
-
|
25
|
-
# Get values from options
|
26
|
-
opt_group_id = options[:merchant_group_id]
|
27
|
-
opt_merchant_id = options[:merchant_id]
|
28
|
-
|
29
|
-
# Check for conflicts in options
|
30
|
-
if opt_group_id && opt_merchant_id
|
31
|
-
raise Tappay::ValidationError, "merchant_group_id and merchant_id cannot be used together"
|
32
|
-
end
|
33
|
-
|
34
|
-
# If options has any ID, use it exclusively
|
35
|
-
if opt_group_id || opt_merchant_id
|
36
|
-
merchant_group_id = opt_group_id
|
37
|
-
merchant_id = opt_merchant_id
|
38
|
-
else
|
39
|
-
# If no options, use configuration
|
40
|
-
merchant_group_id = Tappay.configuration.merchant_group_id
|
41
|
-
merchant_id = Tappay.configuration.merchant_id
|
42
|
-
end
|
43
|
-
|
44
|
-
# Check if at least one is provided
|
45
|
-
unless merchant_group_id || merchant_id
|
46
|
-
raise Tappay::ValidationError, "Either merchant_group_id or merchant_id must be provided"
|
47
|
-
end
|
48
|
-
|
49
|
-
{
|
50
|
-
partner_key: Tappay.configuration.partner_key,
|
51
|
-
amount: options[:amount],
|
52
|
-
details: options[:details],
|
53
|
-
currency: options[:currency] || 'TWD',
|
54
|
-
order_number: options[:order_number],
|
55
|
-
three_domain_secure: options[:three_domain_secure] || false
|
56
|
-
}.tap do |data|
|
57
|
-
if merchant_group_id
|
58
|
-
data[:merchant_group_id] = merchant_group_id
|
59
|
-
else
|
60
|
-
data[:merchant_id] = merchant_id
|
61
|
-
end
|
62
|
-
data[:cardholder] = card_holder_data if options[:cardholder]
|
63
|
-
data[:instalment] = options[:instalment] if options[:instalment]
|
64
|
-
end
|
65
|
-
end
|
1
|
+
# frozen_string_literal: true
|
66
2
|
|
67
|
-
|
68
|
-
return nil unless options[:cardholder]
|
69
|
-
|
70
|
-
case options[:cardholder]
|
71
|
-
when CardHolder
|
72
|
-
options[:cardholder].to_h
|
73
|
-
when Hash
|
74
|
-
options[:cardholder]
|
75
|
-
else
|
76
|
-
raise ValidationError, "Invalid cardholder format"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def validate_options!
|
81
|
-
required = base_required_options + additional_required_options
|
82
|
-
missing = required.select { |key| options[key].nil? }
|
83
|
-
raise ValidationError, "Missing required options: #{missing.join(', ')}" if missing.any?
|
84
|
-
|
85
|
-
validate_instalment! if options[:instalment]
|
86
|
-
end
|
87
|
-
|
88
|
-
private
|
89
|
-
|
90
|
-
def base_required_options
|
91
|
-
[:amount, :details]
|
92
|
-
end
|
93
|
-
|
94
|
-
def additional_required_options
|
95
|
-
[]
|
96
|
-
end
|
97
|
-
|
98
|
-
def validate_instalment!
|
99
|
-
unless options[:instalment].to_i.between?(1, 12)
|
100
|
-
raise ValidationError, "Invalid instalment value. Must be between 1 and 12"
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
3
|
+
require 'tappay/payment_base'
|
104
4
|
|
5
|
+
module Tappay
|
6
|
+
module CreditCard
|
105
7
|
class Pay < PaymentBase
|
106
8
|
def self.by_prime(options = {})
|
107
9
|
PayByPrime.new(options)
|
@@ -121,7 +23,7 @@ module Tappay
|
|
121
23
|
end
|
122
24
|
|
123
25
|
def endpoint_url
|
124
|
-
Tappay::Endpoints::
|
26
|
+
Tappay::Endpoints::Payment.pay_by_prime_url
|
125
27
|
end
|
126
28
|
|
127
29
|
private
|
@@ -140,7 +42,7 @@ module Tappay
|
|
140
42
|
end
|
141
43
|
|
142
44
|
def endpoint_url
|
143
|
-
Tappay::Endpoints::
|
45
|
+
Tappay::Endpoints::Payment.pay_by_token_url
|
144
46
|
end
|
145
47
|
|
146
48
|
private
|
data/lib/tappay/endpoints.rb
CHANGED
@@ -12,16 +12,20 @@ module Tappay
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
module
|
15
|
+
module Payment
|
16
16
|
class << self
|
17
|
-
def
|
17
|
+
def pay_by_prime_url
|
18
18
|
"#{Endpoints.base_url}/tpc/payment/pay-by-prime"
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
21
|
+
def pay_by_token_url
|
22
22
|
"#{Endpoints.base_url}/tpc/payment/pay-by-token"
|
23
23
|
end
|
24
|
+
end
|
25
|
+
end
|
24
26
|
|
27
|
+
module CreditCard
|
28
|
+
class << self
|
25
29
|
def refund_url
|
26
30
|
"#{Endpoints.base_url}/tpc/transaction/refund"
|
27
31
|
end
|
@@ -55,5 +59,17 @@ module Tappay
|
|
55
59
|
end
|
56
60
|
end
|
57
61
|
end
|
62
|
+
|
63
|
+
module LinePay
|
64
|
+
class << self
|
65
|
+
def redirect_url
|
66
|
+
"#{Endpoints.base_url}/tpc/payment/redirect"
|
67
|
+
end
|
68
|
+
|
69
|
+
def query_url
|
70
|
+
"#{Endpoints.base_url}/tpc/transaction/query"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
58
74
|
end
|
59
75
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tappay/payment_base'
|
4
|
+
|
5
|
+
module Tappay
|
6
|
+
module LinePay
|
7
|
+
class Pay < PaymentBase
|
8
|
+
def payment_data
|
9
|
+
super.merge(
|
10
|
+
prime: options[:prime],
|
11
|
+
result_url: {
|
12
|
+
frontend_redirect_url: options[:frontend_redirect_url],
|
13
|
+
backend_notify_url: options[:backend_notify_url]
|
14
|
+
},
|
15
|
+
remember: options[:remember] || false
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def endpoint_url
|
20
|
+
Tappay::Endpoints::Payment.pay_by_prime_url
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def additional_required_options
|
26
|
+
[:prime, :frontend_redirect_url, :backend_notify_url]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tappay
|
4
|
+
class PaymentBase < Client
|
5
|
+
def initialize(options = {})
|
6
|
+
super
|
7
|
+
validate_options!
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute
|
11
|
+
post(endpoint_url, payment_data)
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def endpoint_url
|
17
|
+
raise NotImplementedError, "Subclass must implement abstract method 'endpoint_url'"
|
18
|
+
end
|
19
|
+
|
20
|
+
def payment_data
|
21
|
+
# Check configuration conflicts first
|
22
|
+
if Tappay.configuration.merchant_group_id && Tappay.configuration.merchant_id
|
23
|
+
raise Tappay::ValidationError, "merchant_group_id and merchant_id cannot be used together"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Get values from options
|
27
|
+
opt_group_id = options[:merchant_group_id]
|
28
|
+
opt_merchant_id = options[:merchant_id]
|
29
|
+
|
30
|
+
# Check for conflicts in options
|
31
|
+
if opt_group_id && opt_merchant_id
|
32
|
+
raise Tappay::ValidationError, "merchant_group_id and merchant_id cannot be used together"
|
33
|
+
end
|
34
|
+
|
35
|
+
# If options has any ID, use it exclusively
|
36
|
+
if opt_group_id || opt_merchant_id
|
37
|
+
merchant_group_id = opt_group_id
|
38
|
+
merchant_id = opt_merchant_id
|
39
|
+
else
|
40
|
+
# If no options, use configuration
|
41
|
+
merchant_group_id = Tappay.configuration.merchant_group_id
|
42
|
+
merchant_id = Tappay.configuration.merchant_id
|
43
|
+
end
|
44
|
+
|
45
|
+
# Check if at least one is provided
|
46
|
+
unless merchant_group_id || merchant_id
|
47
|
+
raise Tappay::ValidationError, "Either merchant_group_id or merchant_id must be provided"
|
48
|
+
end
|
49
|
+
|
50
|
+
{
|
51
|
+
partner_key: Tappay.configuration.partner_key,
|
52
|
+
amount: options[:amount],
|
53
|
+
details: options[:details],
|
54
|
+
currency: options[:currency] || 'TWD',
|
55
|
+
order_number: options[:order_number],
|
56
|
+
three_domain_secure: options[:three_domain_secure] || false
|
57
|
+
}.tap do |data|
|
58
|
+
if merchant_group_id
|
59
|
+
data[:merchant_group_id] = merchant_group_id
|
60
|
+
else
|
61
|
+
data[:merchant_id] = merchant_id
|
62
|
+
end
|
63
|
+
data[:cardholder] = card_holder_data if options[:cardholder]
|
64
|
+
data[:instalment] = options[:instalment] if options[:instalment]
|
65
|
+
data[:result_url] = options[:result_url] if options[:result_url]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def card_holder_data
|
70
|
+
return nil unless options[:cardholder]
|
71
|
+
|
72
|
+
case options[:cardholder]
|
73
|
+
when CardHolder
|
74
|
+
options[:cardholder].to_h
|
75
|
+
when Hash
|
76
|
+
options[:cardholder]
|
77
|
+
else
|
78
|
+
raise ValidationError, "Invalid cardholder format"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def validate_options!
|
83
|
+
required = base_required_options + additional_required_options
|
84
|
+
missing = required.select { |key| options[key].nil? }
|
85
|
+
raise ValidationError, "Missing required options: #{missing.join(', ')}" if missing.any?
|
86
|
+
|
87
|
+
validate_instalment! if options[:instalment]
|
88
|
+
validate_result_url! if options[:three_domain_secure]
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def base_required_options
|
94
|
+
[:amount, :details]
|
95
|
+
end
|
96
|
+
|
97
|
+
def additional_required_options
|
98
|
+
[]
|
99
|
+
end
|
100
|
+
|
101
|
+
def validate_instalment!
|
102
|
+
unless options[:instalment].to_i.between?(1, 12)
|
103
|
+
raise ValidationError, "Invalid instalment value. Must be between 1 and 12"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def validate_result_url!
|
108
|
+
return if options[:result_url] &&
|
109
|
+
options[:result_url][:frontend_redirect_url] &&
|
110
|
+
options[:result_url][:backend_notify_url]
|
111
|
+
|
112
|
+
raise ValidationError, "result_url with frontend_redirect_url and backend_notify_url is required when three_domain_secure is true"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/lib/tappay/version.rb
CHANGED
data/lib/tappay.rb
CHANGED
@@ -10,6 +10,7 @@ require_relative "tappay/transaction/query"
|
|
10
10
|
require_relative "tappay/credit_card/pay"
|
11
11
|
require_relative "tappay/credit_card/refund"
|
12
12
|
require_relative "tappay/credit_card/instalment"
|
13
|
+
require_relative "tappay/line_pay/pay"
|
13
14
|
|
14
15
|
module Tappay
|
15
16
|
class Error < StandardError; end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tappay_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zac
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 2025-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: httparty
|
@@ -83,6 +83,8 @@ files:
|
|
83
83
|
- lib/tappay/credit_card/refund.rb
|
84
84
|
- lib/tappay/endpoints.rb
|
85
85
|
- lib/tappay/errors.rb
|
86
|
+
- lib/tappay/line_pay/pay.rb
|
87
|
+
- lib/tappay/payment_base.rb
|
86
88
|
- lib/tappay/transaction/query.rb
|
87
89
|
- lib/tappay/version.rb
|
88
90
|
- lib/tappay_ruby.rb
|