tappay_ruby 0.6.0 → 0.8.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 +78 -254
- data/lib/tappay/configuration.rb +4 -1
- data/lib/tappay/credit_card/instalment.rb +10 -2
- data/lib/tappay/credit_card/pay.rb +6 -114
- data/lib/tappay/endpoints.rb +7 -3
- data/lib/tappay/line_pay/pay.rb +34 -0
- data/lib/tappay/payment_base.rb +136 -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: d18643889a68b9dab0c275a18940d220af312803ee0d7099d67c0b6a9444d32e
|
4
|
+
data.tar.gz: 13d363e73d4e0626054c1114fb3d4ca8c2e99cdce1801726322734b6fe4cd9e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 92b2a1264def50c34cb1ad8c970bc04d9b0c1784096e0afe1968923603158415ece5469f8242fa9a8968c0574a9e56586c24b71dcd1abc9059a2d85554eca1a2
|
7
|
+
data.tar.gz: cb67371f349e6e378fbbe93723ef7926db7bc49f5eb1a96fea0ea00a3af65c0a173aab1bf2aeb8b6772398d8ad7702c5058ff046a3015190f2fd7ad06f37e1e2
|
data/README.md
CHANGED
@@ -8,8 +8,10 @@ A Ruby library for integrating with TapPay payment services. This gem provides a
|
|
8
8
|
|
9
9
|
## Features
|
10
10
|
|
11
|
-
-
|
12
|
-
-
|
11
|
+
- Multiple payment methods:
|
12
|
+
- Credit card payments (one-time and tokenized)
|
13
|
+
- Instalment payments (3 to 24 months)
|
14
|
+
- Line Pay
|
13
15
|
- Refund processing
|
14
16
|
- Transaction status queries
|
15
17
|
- Comprehensive error handling
|
@@ -59,7 +61,10 @@ Tappay.configure do |config|
|
|
59
61
|
# OR
|
60
62
|
config.merchant_group_id = 'your_merchant_group_id'.freeze
|
61
63
|
|
64
|
+
# Payment-specific merchant IDs
|
62
65
|
config.instalment_merchant_id = 'your_instalment_merchant_id'.freeze
|
66
|
+
config.line_pay_merchant_id = 'your_line_pay_merchant_id'.freeze
|
67
|
+
|
63
68
|
config.currency = 'TWD'.freeze
|
64
69
|
config.vat_number = 'your_vat_number'.freeze
|
65
70
|
end
|
@@ -67,22 +72,44 @@ end
|
|
67
72
|
|
68
73
|
### Merchant ID Configuration
|
69
74
|
|
70
|
-
The gem supports
|
71
|
-
|
72
|
-
|
75
|
+
The gem supports flexible merchant ID configuration:
|
76
|
+
|
77
|
+
1. Global merchant ID:
|
78
|
+
- `merchant_id`: Default merchant ID for all payments
|
79
|
+
- `merchant_group_id`: Group merchant ID (mutually exclusive with merchant_id)
|
73
80
|
|
74
|
-
|
75
|
-
-
|
76
|
-
-
|
77
|
-
- If you provide merchant ID in the payment options, it will take precedence over any configuration
|
81
|
+
2. Payment-specific merchant IDs:
|
82
|
+
- `instalment_merchant_id`: Specific merchant ID for instalment payments
|
83
|
+
- `line_pay_merchant_id`: Specific merchant ID for Line Pay transactions
|
78
84
|
|
79
|
-
|
85
|
+
Merchant ID Priority:
|
86
|
+
1. Payment options merchant ID (if provided in the payment call)
|
87
|
+
2. Payment-specific merchant ID (if configured)
|
88
|
+
3. Global merchant ID
|
89
|
+
|
90
|
+
Example of merchant ID usage:
|
80
91
|
```ruby
|
81
|
-
# Using
|
92
|
+
# Using default merchant ID
|
93
|
+
result = Tappay::CreditCard::Pay.by_prime(
|
94
|
+
prime: 'prime_from_tappay_sdk',
|
95
|
+
amount: 100,
|
96
|
+
order_number: 'ORDER-123'
|
97
|
+
)
|
98
|
+
|
99
|
+
# Using payment-specific merchant ID
|
100
|
+
# This will automatically use line_pay_merchant_id if configured
|
101
|
+
result = Tappay::LinePay::Pay.new(
|
102
|
+
prime: 'line_pay_prime',
|
103
|
+
amount: 100,
|
104
|
+
frontend_redirect_url: 'https://example.com/line_pay/result',
|
105
|
+
backend_notify_url: 'https://example.com/line_pay/notify'
|
106
|
+
).execute
|
107
|
+
|
108
|
+
# Overriding merchant ID in payment options
|
82
109
|
result = Tappay::CreditCard::Pay.by_prime(
|
83
110
|
prime: 'prime_from_tappay_sdk',
|
84
111
|
amount: 100,
|
85
|
-
|
112
|
+
merchant_id: 'override_merchant_id', # This takes highest priority
|
86
113
|
order_number: 'ORDER-123'
|
87
114
|
)
|
88
115
|
```
|
@@ -97,236 +124,60 @@ Tappay.configure do |config|
|
|
97
124
|
config.partner_key = ENV['TAPPAY_PARTNER_KEY'].freeze
|
98
125
|
config.app_id = ENV['TAPPAY_APP_ID'].freeze
|
99
126
|
config.merchant_id = ENV['TAPPAY_MERCHANT_ID'].freeze
|
127
|
+
config.line_pay_merchant_id = ENV['TAPPAY_LINE_PAY_MERCHANT_ID'].freeze
|
128
|
+
config.instalment_merchant_id = ENV['TAPPAY_INSTALMENT_MERCHANT_ID'].freeze
|
100
129
|
# ... other configurations
|
101
130
|
end
|
102
131
|
```
|
103
132
|
|
104
|
-
### 3. Using Rails Credentials
|
105
|
-
|
106
|
-
If you're using Rails, you can use credentials:
|
107
|
-
|
108
|
-
```ruby
|
109
|
-
Tappay.configure do |config|
|
110
|
-
config.mode = Rails.env.production? ? :production : :sandbox
|
111
|
-
config.partner_key = Rails.application.credentials.tappay[:partner_key].freeze
|
112
|
-
config.app_id = Rails.application.credentials.tappay[:app_id].freeze
|
113
|
-
# ... other configurations
|
114
|
-
end
|
115
|
-
```
|
116
|
-
|
117
|
-
## Environment-based Endpoints
|
118
|
-
|
119
|
-
The gem automatically handles different endpoints for sandbox and production environments. You don't need to specify the full URLs - just set the mode:
|
120
|
-
|
121
|
-
```ruby
|
122
|
-
# For sandbox (default)
|
123
|
-
config.mode = :sandbox # Uses https://sandbox.tappaysdk.com/...
|
124
|
-
|
125
|
-
# For production
|
126
|
-
config.mode = :production # Uses https://prod.tappaysdk.com/...
|
127
|
-
```
|
128
|
-
|
129
|
-
## Card Holder Information
|
130
|
-
|
131
|
-
You can provide cardholder information in two ways:
|
132
|
-
|
133
|
-
### 1. Using CardHolder Object (Recommended)
|
134
|
-
|
135
|
-
```ruby
|
136
|
-
# Create a CardHolder object
|
137
|
-
card_holder = Tappay::CardHolder.new(
|
138
|
-
name: 'John Doe',
|
139
|
-
email: 'john@example.com',
|
140
|
-
phone_number: '+886923456789'
|
141
|
-
)
|
142
|
-
|
143
|
-
# Use in payment directly
|
144
|
-
result = Tappay::CreditCard::Pay.by_prime(
|
145
|
-
prime: 'prime_from_tappay_sdk',
|
146
|
-
amount: 100,
|
147
|
-
order_number: 'ORDER-123',
|
148
|
-
card_holder: card_holder # No need to call as_json
|
149
|
-
)
|
150
|
-
```
|
151
|
-
|
152
|
-
### 2. Using Hash Directly
|
153
|
-
|
154
|
-
```ruby
|
155
|
-
result = Tappay::CreditCard::Pay.by_prime(
|
156
|
-
prime: 'prime_from_tappay_sdk',
|
157
|
-
amount: 100,
|
158
|
-
order_number: 'ORDER-123',
|
159
|
-
card_holder: {
|
160
|
-
name: 'John Doe',
|
161
|
-
email: 'john@example.com',
|
162
|
-
phone_number: '+886923456789'
|
163
|
-
}
|
164
|
-
)
|
165
|
-
```
|
166
|
-
|
167
|
-
Both approaches are valid and will work the same way. The CardHolder object provides a more structured way to handle cardholder information and includes validation.
|
168
|
-
|
169
|
-
## Payment URL
|
170
|
-
|
171
|
-
When processing payments, the API response may include a `payment_url` field. This URL is used for redirecting users to complete their payment in scenarios such as:
|
172
|
-
|
173
|
-
- 3D Secure verification
|
174
|
-
- LINE Pay payment page
|
175
|
-
- JKO Pay payment page
|
176
|
-
|
177
|
-
Note: payment_url is not supported for:
|
178
|
-
- Apple Pay
|
179
|
-
- Google Pay
|
180
|
-
- Samsung Pay
|
181
|
-
|
182
|
-
Example of handling payment URL in response:
|
183
|
-
```ruby
|
184
|
-
result = Tappay::CreditCard::Pay.by_prime(
|
185
|
-
prime: 'prime_from_tappay_sdk',
|
186
|
-
amount: 100,
|
187
|
-
order_number: 'ORDER-123'
|
188
|
-
)
|
189
|
-
|
190
|
-
if result['status'] == 0
|
191
|
-
if result['payment_url']
|
192
|
-
# Redirect user to payment page for:
|
193
|
-
# - 3D Secure verification
|
194
|
-
# - LINE Pay payment
|
195
|
-
# - JKO Pay payment
|
196
|
-
redirect_to result['payment_url']
|
197
|
-
end
|
198
|
-
end
|
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
|
-
|
219
133
|
## Usage
|
220
134
|
|
221
|
-
###
|
222
|
-
|
223
|
-
Use this method when the customer wants to pay with their credit card without storing the card information. The customer will need to enter their card information for each transaction.
|
135
|
+
### Credit Card Payment
|
224
136
|
|
225
137
|
```ruby
|
226
|
-
#
|
138
|
+
# One-time payment
|
227
139
|
result = Tappay::CreditCard::Pay.by_prime(
|
228
140
|
prime: 'prime_from_tappay_sdk',
|
229
|
-
amount:
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
if result['status'] == 0
|
238
|
-
# Payment successful
|
239
|
-
transaction_id = result['rec_trade_id']
|
240
|
-
if result['card_secret']
|
241
|
-
# If remember is true, you'll get these tokens
|
242
|
-
card_key = result['card_secret']['card_key']
|
243
|
-
card_token = result['card_secret']['card_token']
|
244
|
-
# Store card_key and card_token securely for future payments
|
245
|
-
end
|
246
|
-
|
247
|
-
# Handle payment URL if present (for 3D Secure, LINE Pay, JKO Pay)
|
248
|
-
if result['payment_url']
|
249
|
-
redirect_to result['payment_url']
|
250
|
-
end
|
251
|
-
end
|
252
|
-
```
|
253
|
-
|
254
|
-
### Pay by Token
|
255
|
-
|
256
|
-
Use this method when the customer has opted to save their card information for future purchases. This provides a more convenient checkout experience as customers don't need to re-enter their card information.
|
257
|
-
|
258
|
-
```ruby
|
259
|
-
# Recurring payment with stored card token
|
260
|
-
result = Tappay::CreditCard::Pay.by_token(
|
261
|
-
card_key: 'stored_card_key',
|
262
|
-
card_token: 'stored_card_token',
|
263
|
-
amount: 100,
|
264
|
-
order_number: 'ORDER-124',
|
265
|
-
currency: 'TWD',
|
266
|
-
three_domain_secure: true, # Enable 3D secure if needed
|
267
|
-
card_holder: card_holder # Optional cardholder information
|
141
|
+
amount: 1000,
|
142
|
+
details: 'Order Details',
|
143
|
+
cardholder: {
|
144
|
+
phone_number: '0912345678',
|
145
|
+
name: 'Test User',
|
146
|
+
email: 'test@example.com'
|
147
|
+
}
|
268
148
|
)
|
269
149
|
|
270
|
-
|
271
|
-
|
272
|
-
transaction_id = result['rec_trade_id']
|
273
|
-
end
|
274
|
-
```
|
275
|
-
|
276
|
-
### Instalment Payment
|
277
|
-
|
278
|
-
```ruby
|
279
|
-
payment = Tappay::CreditCard::Instalment.new(
|
150
|
+
# Instalment payment (3-30 months)
|
151
|
+
result = Tappay::CreditCard::Instalment.by_prime(
|
280
152
|
prime: 'prime_from_tappay_sdk',
|
281
|
-
amount:
|
282
|
-
instalment:
|
283
|
-
details: '
|
153
|
+
amount: 1000,
|
154
|
+
instalment: 12, # 12 months instalment
|
155
|
+
details: 'Order Details',
|
284
156
|
cardholder: {
|
285
|
-
phone_number: '
|
286
|
-
name: '
|
287
|
-
email: '
|
157
|
+
phone_number: '0912345678',
|
158
|
+
name: 'Test User',
|
159
|
+
email: 'test@example.com'
|
288
160
|
}
|
289
161
|
)
|
290
|
-
|
291
|
-
begin
|
292
|
-
result = payment.execute
|
293
|
-
if result['status'] == 0
|
294
|
-
# Payment successful
|
295
|
-
instalment_info = result['instalment_info']
|
296
|
-
number_of_instalments = instalment_info['number_of_instalments']
|
297
|
-
first_payment = instalment_info['first_payment']
|
298
|
-
each_payment = instalment_info['each_payment']
|
299
|
-
|
300
|
-
# Handle payment URL if present (for 3D Secure)
|
301
|
-
if result['payment_url']
|
302
|
-
redirect_to result['payment_url']
|
303
|
-
end
|
304
|
-
end
|
305
|
-
rescue Tappay::PaymentError => e
|
306
|
-
# Handle payment error
|
307
|
-
end
|
308
162
|
```
|
309
163
|
|
310
|
-
###
|
164
|
+
### Line Pay
|
311
165
|
|
312
166
|
```ruby
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
# Refund successful
|
322
|
-
end
|
323
|
-
rescue Tappay::RefundError => e
|
324
|
-
# Handle refund error
|
325
|
-
end
|
167
|
+
# Create Line Pay payment
|
168
|
+
result = Tappay::LinePay::Pay.new(
|
169
|
+
prime: 'line_pay_prime',
|
170
|
+
amount: 1000,
|
171
|
+
details: 'Order Details',
|
172
|
+
frontend_redirect_url: 'https://example.com/line_pay/result',
|
173
|
+
backend_notify_url: 'https://example.com/line_pay/notify'
|
174
|
+
).execute
|
326
175
|
```
|
327
176
|
|
328
177
|
### Error Handling
|
329
178
|
|
179
|
+
The gem provides comprehensive error handling:
|
180
|
+
|
330
181
|
```ruby
|
331
182
|
begin
|
332
183
|
result = Tappay::CreditCard::Pay.by_prime(
|
@@ -334,48 +185,21 @@ begin
|
|
334
185
|
amount: 100,
|
335
186
|
order_number: 'ORDER-123'
|
336
187
|
)
|
337
|
-
rescue Tappay::PaymentError => e
|
338
|
-
# Handle payment error
|
339
|
-
puts e.message
|
340
188
|
rescue Tappay::ValidationError => e
|
341
|
-
# Handle validation
|
342
|
-
puts e.message
|
189
|
+
# Handle validation errors (e.g., missing required fields)
|
190
|
+
puts "Validation error: #{e.message}"
|
191
|
+
rescue Tappay::APIError => e
|
192
|
+
# Handle API errors (e.g., invalid prime, insufficient balance)
|
193
|
+
puts "API error: #{e.message}"
|
194
|
+
rescue Tappay::Error => e
|
195
|
+
# Handle other TapPay errors
|
196
|
+
puts "TapPay error: #{e.message}"
|
343
197
|
end
|
344
198
|
```
|
345
199
|
|
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
|
-
|
376
200
|
## Development
|
377
201
|
|
378
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
|
202
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
379
203
|
|
380
204
|
## Contributing
|
381
205
|
|
data/lib/tappay/configuration.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Tappay
|
2
4
|
class Configuration
|
3
|
-
attr_accessor :partner_key, :merchant_id, :merchant_group_id, :instalment_merchant_id,
|
5
|
+
attr_accessor :partner_key, :merchant_id, :merchant_group_id, :instalment_merchant_id,
|
6
|
+
:line_pay_merchant_id, :app_id, :currency, :vat_number
|
4
7
|
attr_writer :api_version
|
5
8
|
|
6
9
|
def initialize
|
@@ -23,7 +23,7 @@ module Tappay
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def endpoint_url
|
26
|
-
Tappay::Endpoints::
|
26
|
+
Tappay::Endpoints::Payment.pay_by_prime_url
|
27
27
|
end
|
28
28
|
|
29
29
|
def validate_options!
|
@@ -33,6 +33,10 @@ module Tappay
|
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
+
def get_merchant_id
|
37
|
+
Tappay.configuration.instalment_merchant_id || super
|
38
|
+
end
|
39
|
+
|
36
40
|
def additional_required_options
|
37
41
|
[:prime, :cardholder, :instalment]
|
38
42
|
end
|
@@ -60,7 +64,7 @@ module Tappay
|
|
60
64
|
end
|
61
65
|
|
62
66
|
def endpoint_url
|
63
|
-
Tappay::Endpoints::
|
67
|
+
Tappay::Endpoints::Payment.pay_by_token_url
|
64
68
|
end
|
65
69
|
|
66
70
|
def validate_options!
|
@@ -70,6 +74,10 @@ module Tappay
|
|
70
74
|
|
71
75
|
private
|
72
76
|
|
77
|
+
def get_merchant_id
|
78
|
+
Tappay.configuration.instalment_merchant_id || super
|
79
|
+
end
|
80
|
+
|
73
81
|
def additional_required_options
|
74
82
|
[:card_key, :card_token, :instalment]
|
75
83
|
end
|
@@ -1,117 +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
|
1
|
+
# frozen_string_literal: true
|
12
2
|
|
13
|
-
|
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
|
-
data[:result_url] = options[:result_url] if options[:result_url]
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def card_holder_data
|
69
|
-
return nil unless options[:cardholder]
|
70
|
-
|
71
|
-
case options[:cardholder]
|
72
|
-
when CardHolder
|
73
|
-
options[:cardholder].to_h
|
74
|
-
when Hash
|
75
|
-
options[:cardholder]
|
76
|
-
else
|
77
|
-
raise ValidationError, "Invalid cardholder format"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def validate_options!
|
82
|
-
required = base_required_options + additional_required_options
|
83
|
-
missing = required.select { |key| options[key].nil? }
|
84
|
-
raise ValidationError, "Missing required options: #{missing.join(', ')}" if missing.any?
|
85
|
-
|
86
|
-
validate_instalment! if options[:instalment]
|
87
|
-
validate_result_url! if options[:three_domain_secure]
|
88
|
-
end
|
89
|
-
|
90
|
-
private
|
91
|
-
|
92
|
-
def base_required_options
|
93
|
-
[:amount, :details]
|
94
|
-
end
|
95
|
-
|
96
|
-
def additional_required_options
|
97
|
-
[]
|
98
|
-
end
|
99
|
-
|
100
|
-
def validate_instalment!
|
101
|
-
unless options[:instalment].to_i.between?(1, 12)
|
102
|
-
raise ValidationError, "Invalid instalment value. Must be between 1 and 12"
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def validate_result_url!
|
107
|
-
return if options[:result_url] &&
|
108
|
-
options[:result_url][:frontend_redirect_url] &&
|
109
|
-
options[:result_url][:backend_notify_url]
|
110
|
-
|
111
|
-
raise ValidationError, "result_url with frontend_redirect_url and backend_notify_url is required when three_domain_secure is true"
|
112
|
-
end
|
113
|
-
end
|
3
|
+
require 'tappay/payment_base'
|
114
4
|
|
5
|
+
module Tappay
|
6
|
+
module CreditCard
|
115
7
|
class Pay < PaymentBase
|
116
8
|
def self.by_prime(options = {})
|
117
9
|
PayByPrime.new(options)
|
@@ -131,7 +23,7 @@ module Tappay
|
|
131
23
|
end
|
132
24
|
|
133
25
|
def endpoint_url
|
134
|
-
Tappay::Endpoints::
|
26
|
+
Tappay::Endpoints::Payment.pay_by_prime_url
|
135
27
|
end
|
136
28
|
|
137
29
|
private
|
@@ -150,7 +42,7 @@ module Tappay
|
|
150
42
|
end
|
151
43
|
|
152
44
|
def endpoint_url
|
153
|
-
Tappay::Endpoints::
|
45
|
+
Tappay::Endpoints::Payment.pay_by_token_url
|
154
46
|
end
|
155
47
|
|
156
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
|
@@ -0,0 +1,34 @@
|
|
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 get_merchant_id
|
26
|
+
Tappay.configuration.line_pay_merchant_id || super
|
27
|
+
end
|
28
|
+
|
29
|
+
def additional_required_options
|
30
|
+
[:prime, :frontend_redirect_url, :backend_notify_url]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tappay
|
4
|
+
class PaymentBase < Client
|
5
|
+
VALID_INSTALMENT_VALUES = [0, 3, 6, 12, 24, 30].freeze
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
super
|
9
|
+
validate_options!
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute
|
13
|
+
post(endpoint_url, payment_data)
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def endpoint_url
|
19
|
+
raise NotImplementedError, "Subclass must implement abstract method 'endpoint_url'"
|
20
|
+
end
|
21
|
+
|
22
|
+
def payment_data
|
23
|
+
# Check configuration conflicts first
|
24
|
+
if Tappay.configuration.merchant_group_id && Tappay.configuration.merchant_id
|
25
|
+
raise Tappay::ValidationError, "merchant_group_id and merchant_id cannot be used together"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get values from options
|
29
|
+
opt_group_id = options[:merchant_group_id]
|
30
|
+
opt_merchant_id = options[:merchant_id]
|
31
|
+
|
32
|
+
# Check for conflicts in options
|
33
|
+
if opt_group_id && opt_merchant_id
|
34
|
+
raise Tappay::ValidationError, "merchant_group_id and merchant_id cannot be used together"
|
35
|
+
end
|
36
|
+
|
37
|
+
# If options has any ID, use it exclusively
|
38
|
+
if opt_group_id || opt_merchant_id
|
39
|
+
merchant_group_id = opt_group_id
|
40
|
+
merchant_id = opt_merchant_id
|
41
|
+
else
|
42
|
+
# If no options, use configuration
|
43
|
+
merchant_group_id = Tappay.configuration.merchant_group_id
|
44
|
+
merchant_id = get_merchant_id
|
45
|
+
end
|
46
|
+
|
47
|
+
# Check if at least one is provided
|
48
|
+
unless merchant_group_id || merchant_id
|
49
|
+
raise Tappay::ValidationError, "Either merchant_group_id or merchant_id must be provided"
|
50
|
+
end
|
51
|
+
|
52
|
+
{
|
53
|
+
partner_key: Tappay.configuration.partner_key,
|
54
|
+
amount: options[:amount],
|
55
|
+
details: options[:details],
|
56
|
+
currency: options[:currency] || 'TWD',
|
57
|
+
order_number: options[:order_number],
|
58
|
+
three_domain_secure: options[:three_domain_secure] || false
|
59
|
+
}.tap do |data|
|
60
|
+
if merchant_group_id
|
61
|
+
data[:merchant_group_id] = merchant_group_id
|
62
|
+
else
|
63
|
+
data[:merchant_id] = merchant_id
|
64
|
+
end
|
65
|
+
data[:cardholder] = card_holder_data if options[:cardholder]
|
66
|
+
data[:result_url] = options[:result_url] if options[:result_url]
|
67
|
+
data[:instalment] = options[:instalment] || 0
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def card_holder_data
|
72
|
+
return nil unless options[:cardholder]
|
73
|
+
|
74
|
+
case options[:cardholder]
|
75
|
+
when CardHolder
|
76
|
+
options[:cardholder].to_h
|
77
|
+
when Hash
|
78
|
+
options[:cardholder]
|
79
|
+
else
|
80
|
+
raise ValidationError, "Invalid cardholder format"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def validate_options!
|
85
|
+
required = base_required_options + additional_required_options
|
86
|
+
missing = required.select { |key| options[key].nil? }
|
87
|
+
raise ValidationError, "Missing required options: #{missing.join(', ')}" if missing.any?
|
88
|
+
|
89
|
+
validate_amount!
|
90
|
+
validate_instalment! if options[:instalment]
|
91
|
+
validate_result_url! if options[:three_domain_secure]
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def validate_amount!
|
97
|
+
amount = options[:amount]
|
98
|
+
if !amount.is_a?(Numeric)
|
99
|
+
raise ValidationError, "amount must be a number"
|
100
|
+
elsif amount <= 0
|
101
|
+
raise ValidationError, "amount must be greater than 0"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def get_merchant_id
|
106
|
+
Tappay.configuration.merchant_id
|
107
|
+
end
|
108
|
+
|
109
|
+
def base_required_options
|
110
|
+
[:amount, :details]
|
111
|
+
end
|
112
|
+
|
113
|
+
def additional_required_options
|
114
|
+
[]
|
115
|
+
end
|
116
|
+
|
117
|
+
def validate_instalment!
|
118
|
+
instalment = options[:instalment].to_i
|
119
|
+
unless VALID_INSTALMENT_VALUES.include?(instalment)
|
120
|
+
raise ValidationError, "Instalment must be one of: #{VALID_INSTALMENT_VALUES.join(', ')}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def validate_result_url!
|
125
|
+
result_url = options[:result_url]
|
126
|
+
raise ValidationError, "result_url must be a hash" unless result_url.is_a?(Hash)
|
127
|
+
|
128
|
+
required_fields = %w[frontend_redirect_url backend_notify_url]
|
129
|
+
missing = required_fields.select { |field| result_url[field.to_sym].nil? && result_url[field].nil? }
|
130
|
+
|
131
|
+
if missing.any?
|
132
|
+
raise ValidationError, "result_url must contain both frontend_redirect_url and backend_notify_url"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
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.8.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
|