dk_payment_gateway 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +4 -0
- data/.rspec_status +11 -0
- data/API_REFERENCE.md +458 -0
- data/CHANGELOG.md +64 -0
- data/DEVELOPMENT.md +380 -0
- data/EXAMPLES.md +491 -0
- data/FILE_STRUCTURE.md +407 -0
- data/Gemfile +13 -0
- data/INSTALLATION.md +460 -0
- data/LICENSE +22 -0
- data/PROJECT_OVERVIEW.md +314 -0
- data/QUICK_START.md +186 -0
- data/README.md +296 -0
- data/Rakefile +9 -0
- data/SUMMARY.md +285 -0
- data/dk_payment_gateway.gemspec +40 -0
- data/examples/README.md +199 -0
- data/examples/generate_qr.rb +110 -0
- data/examples/intra_transfer.rb +114 -0
- data/examples/simple_payment.rb +102 -0
- data/lib/dk_payment_gateway/authentication.rb +102 -0
- data/lib/dk_payment_gateway/client.rb +139 -0
- data/lib/dk_payment_gateway/configuration.rb +32 -0
- data/lib/dk_payment_gateway/errors.rb +39 -0
- data/lib/dk_payment_gateway/intra_transaction.rb +147 -0
- data/lib/dk_payment_gateway/pull_payment.rb +155 -0
- data/lib/dk_payment_gateway/qr_payment.rb +98 -0
- data/lib/dk_payment_gateway/signature.rb +72 -0
- data/lib/dk_payment_gateway/transaction_status.rb +127 -0
- data/lib/dk_payment_gateway/utils.rb +161 -0
- data/lib/dk_payment_gateway/version.rb +5 -0
- data/lib/dk_payment_gateway.rb +28 -0
- metadata +160 -0
data/examples/README.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# DK Payment Gateway - Example Applications
|
|
2
|
+
|
|
3
|
+
This directory contains example applications demonstrating how to use the DK Payment Gateway gem.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Before running these examples, make sure you have:
|
|
8
|
+
|
|
9
|
+
1. Installed the gem:
|
|
10
|
+
```bash
|
|
11
|
+
gem install dk_payment_gateway
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
2. Set up your environment variables in a `.env` file:
|
|
15
|
+
```bash
|
|
16
|
+
DK_BASE_URL=http://internal-gateway.uat.digitalkidu.bt/api/dkpg
|
|
17
|
+
DK_API_KEY=your_api_key
|
|
18
|
+
DK_USERNAME=your_username
|
|
19
|
+
DK_PASSWORD=your_password
|
|
20
|
+
DK_CLIENT_ID=your_client_id
|
|
21
|
+
DK_CLIENT_SECRET=your_client_secret
|
|
22
|
+
DK_SOURCE_APP=SRC_AVS_0201
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
3. Install dotenv gem (optional, for loading .env files):
|
|
26
|
+
```bash
|
|
27
|
+
gem install dotenv
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Examples
|
|
31
|
+
|
|
32
|
+
### 1. Simple Payment (`simple_payment.rb`)
|
|
33
|
+
|
|
34
|
+
Demonstrates a complete pull payment flow:
|
|
35
|
+
- Authentication
|
|
36
|
+
- Payment authorization (sends OTP)
|
|
37
|
+
- OTP collection from user
|
|
38
|
+
- Payment completion with OTP
|
|
39
|
+
|
|
40
|
+
**Run:**
|
|
41
|
+
```bash
|
|
42
|
+
ruby examples/simple_payment.rb
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**What it does:**
|
|
46
|
+
1. Authenticates with the API
|
|
47
|
+
2. Initiates a payment authorization for BTN 100.00
|
|
48
|
+
3. Prompts for OTP
|
|
49
|
+
4. Completes the payment
|
|
50
|
+
|
|
51
|
+
### 2. Intra-Bank Transfer (`intra_transfer.rb`)
|
|
52
|
+
|
|
53
|
+
Demonstrates transferring funds between DK accounts:
|
|
54
|
+
- Account verification
|
|
55
|
+
- Fund transfer
|
|
56
|
+
- Transaction confirmation
|
|
57
|
+
|
|
58
|
+
**Run:**
|
|
59
|
+
```bash
|
|
60
|
+
ruby examples/intra_transfer.rb
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**What it does:**
|
|
64
|
+
1. Authenticates with the API
|
|
65
|
+
2. Verifies beneficiary account
|
|
66
|
+
3. Asks for confirmation
|
|
67
|
+
4. Executes the transfer
|
|
68
|
+
|
|
69
|
+
### 3. QR Code Generation (`generate_qr.rb`)
|
|
70
|
+
|
|
71
|
+
Demonstrates generating QR codes for payments:
|
|
72
|
+
- Static QR (customer enters amount)
|
|
73
|
+
- Dynamic QR (fixed amount)
|
|
74
|
+
- QR image saving
|
|
75
|
+
|
|
76
|
+
**Run:**
|
|
77
|
+
```bash
|
|
78
|
+
ruby examples/generate_qr.rb
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**What it does:**
|
|
82
|
+
1. Authenticates with the API
|
|
83
|
+
2. Asks user to choose QR type
|
|
84
|
+
3. Generates QR code
|
|
85
|
+
4. Saves QR image to file
|
|
86
|
+
|
|
87
|
+
## Customizing Examples
|
|
88
|
+
|
|
89
|
+
### Changing Payment Amounts
|
|
90
|
+
|
|
91
|
+
Edit the amount variables in each script:
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
# In simple_payment.rb
|
|
95
|
+
amount = 100.00 # Change this
|
|
96
|
+
fee = 5.00 # Change this
|
|
97
|
+
|
|
98
|
+
# In intra_transfer.rb
|
|
99
|
+
amount = 500.00 # Change this
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Changing Account Numbers
|
|
103
|
+
|
|
104
|
+
Update the account numbers to match your test accounts:
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
# Beneficiary account
|
|
108
|
+
account_number: "110158212197" # Change this
|
|
109
|
+
|
|
110
|
+
# Remitter account
|
|
111
|
+
remitter_account_number: "770182571" # Change this
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Changing Bank Codes
|
|
115
|
+
|
|
116
|
+
Use different bank codes as needed:
|
|
117
|
+
|
|
118
|
+
```ruby
|
|
119
|
+
remitter_bank_id: "1040" # 1010, 1040, 1060, etc.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Error Handling
|
|
123
|
+
|
|
124
|
+
All examples include error handling. If you encounter errors:
|
|
125
|
+
|
|
126
|
+
1. **Authentication Error**
|
|
127
|
+
- Check your credentials in .env file
|
|
128
|
+
- Verify API endpoint is accessible
|
|
129
|
+
|
|
130
|
+
2. **Transaction Error**
|
|
131
|
+
- Check account numbers are valid
|
|
132
|
+
- Verify sufficient balance
|
|
133
|
+
- Ensure OTP is correct
|
|
134
|
+
|
|
135
|
+
3. **Network Error**
|
|
136
|
+
- Check internet connection
|
|
137
|
+
- Verify API endpoint URL
|
|
138
|
+
|
|
139
|
+
## Testing in Development
|
|
140
|
+
|
|
141
|
+
For testing without affecting real accounts:
|
|
142
|
+
|
|
143
|
+
1. Use the UAT (User Acceptance Testing) environment
|
|
144
|
+
2. Use test account numbers provided by DK
|
|
145
|
+
3. Use small amounts for testing
|
|
146
|
+
|
|
147
|
+
## Creating Your Own Examples
|
|
148
|
+
|
|
149
|
+
Use these examples as templates:
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
#!/usr/bin/env ruby
|
|
153
|
+
require 'bundler/setup'
|
|
154
|
+
require 'dk_payment_gateway'
|
|
155
|
+
|
|
156
|
+
# Configure
|
|
157
|
+
DkPaymentGateway.configure do |config|
|
|
158
|
+
config.base_url = ENV['DK_BASE_URL']
|
|
159
|
+
config.api_key = ENV['DK_API_KEY']
|
|
160
|
+
# ... other config
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Your code here
|
|
164
|
+
client = DkPaymentGateway.client
|
|
165
|
+
client.authenticate!
|
|
166
|
+
|
|
167
|
+
# Use the client
|
|
168
|
+
# ...
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Additional Resources
|
|
172
|
+
|
|
173
|
+
- [Main README](../README.md) - Complete documentation
|
|
174
|
+
- [Quick Start Guide](../QUICK_START.md) - Get started in 5 minutes
|
|
175
|
+
- [API Reference](../API_REFERENCE.md) - Detailed API documentation
|
|
176
|
+
- [Examples Guide](../EXAMPLES.md) - More usage examples
|
|
177
|
+
|
|
178
|
+
## Support
|
|
179
|
+
|
|
180
|
+
If you encounter issues with these examples:
|
|
181
|
+
|
|
182
|
+
1. Check the error message
|
|
183
|
+
2. Review the documentation
|
|
184
|
+
3. Verify your credentials
|
|
185
|
+
4. Check account numbers and amounts
|
|
186
|
+
5. Ensure you're using the correct environment (UAT/Production)
|
|
187
|
+
|
|
188
|
+
## Security Note
|
|
189
|
+
|
|
190
|
+
⚠️ **Never commit your `.env` file or credentials to version control!**
|
|
191
|
+
|
|
192
|
+
Add to your `.gitignore`:
|
|
193
|
+
```
|
|
194
|
+
.env
|
|
195
|
+
.env.*
|
|
196
|
+
*.pem
|
|
197
|
+
*.key
|
|
198
|
+
```
|
|
199
|
+
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# QR code generation example using DK Payment Gateway
|
|
5
|
+
# This demonstrates generating both static and dynamic QR codes
|
|
6
|
+
|
|
7
|
+
require 'bundler/setup'
|
|
8
|
+
require 'dk_payment_gateway'
|
|
9
|
+
|
|
10
|
+
# Configure the client
|
|
11
|
+
DkPaymentGateway.configure do |config|
|
|
12
|
+
config.base_url = ENV['DK_BASE_URL'] || "http://internal-gateway.uat.digitalkidu.bt/api/dkpg"
|
|
13
|
+
config.api_key = ENV['DK_API_KEY']
|
|
14
|
+
config.username = ENV['DK_USERNAME']
|
|
15
|
+
config.password = ENV['DK_PASSWORD']
|
|
16
|
+
config.client_id = ENV['DK_CLIENT_ID']
|
|
17
|
+
config.client_secret = ENV['DK_CLIENT_SECRET']
|
|
18
|
+
config.source_app = ENV['DK_SOURCE_APP'] || "SRC_AVS_0201"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def main
|
|
22
|
+
puts "=== DK Payment Gateway - QR Code Generation Example ==="
|
|
23
|
+
puts
|
|
24
|
+
|
|
25
|
+
# Initialize client
|
|
26
|
+
client = DkPaymentGateway.client
|
|
27
|
+
|
|
28
|
+
# Authenticate
|
|
29
|
+
puts "Authenticating..."
|
|
30
|
+
client.authenticate!
|
|
31
|
+
puts "✓ Authentication successful"
|
|
32
|
+
puts
|
|
33
|
+
|
|
34
|
+
# Merchant details
|
|
35
|
+
merchant_account = "100100148337"
|
|
36
|
+
|
|
37
|
+
puts "Select QR type:"
|
|
38
|
+
puts "1. Static QR (customer enters amount)"
|
|
39
|
+
puts "2. Dynamic QR (fixed amount)"
|
|
40
|
+
print "Choice (1 or 2): "
|
|
41
|
+
choice = gets.chomp
|
|
42
|
+
puts
|
|
43
|
+
|
|
44
|
+
begin
|
|
45
|
+
case choice
|
|
46
|
+
when "1"
|
|
47
|
+
generate_static_qr(client, merchant_account)
|
|
48
|
+
when "2"
|
|
49
|
+
generate_dynamic_qr(client, merchant_account)
|
|
50
|
+
else
|
|
51
|
+
puts "Invalid choice"
|
|
52
|
+
end
|
|
53
|
+
rescue DkPaymentGateway::Error => e
|
|
54
|
+
puts "✗ Error: #{e.message}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def generate_static_qr(client, merchant_account)
|
|
59
|
+
puts "Generating Static QR Code..."
|
|
60
|
+
puts " Merchant Account: #{merchant_account}"
|
|
61
|
+
puts " Amount: Customer will enter"
|
|
62
|
+
puts
|
|
63
|
+
|
|
64
|
+
response = client.qr_payment.generate_qr(
|
|
65
|
+
request_id: DkPaymentGateway::Utils.generate_request_id("QR"),
|
|
66
|
+
currency: "BTN",
|
|
67
|
+
bene_account_number: merchant_account,
|
|
68
|
+
amount: 0, # 0 = static QR
|
|
69
|
+
mcc_code: "5411", # Grocery store
|
|
70
|
+
remarks: "Payment to merchant"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
filename = "static_qr_#{Time.now.to_i}.png"
|
|
74
|
+
client.qr_payment.save_qr_image(response['image'], filename)
|
|
75
|
+
|
|
76
|
+
puts "✓ Static QR code generated successfully!"
|
|
77
|
+
puts " Saved to: #{filename}"
|
|
78
|
+
puts " Customers can scan this QR and enter any amount"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def generate_dynamic_qr(client, merchant_account)
|
|
82
|
+
print "Enter amount (BTN): "
|
|
83
|
+
amount = gets.chomp.to_f
|
|
84
|
+
puts
|
|
85
|
+
|
|
86
|
+
puts "Generating Dynamic QR Code..."
|
|
87
|
+
puts " Merchant Account: #{merchant_account}"
|
|
88
|
+
puts " Amount: BTN #{DkPaymentGateway::Utils.format_amount(amount)}"
|
|
89
|
+
puts
|
|
90
|
+
|
|
91
|
+
response = client.qr_payment.generate_qr(
|
|
92
|
+
request_id: DkPaymentGateway::Utils.generate_request_id("QR"),
|
|
93
|
+
currency: "BTN",
|
|
94
|
+
bene_account_number: merchant_account,
|
|
95
|
+
amount: amount,
|
|
96
|
+
mcc_code: "5812", # Restaurant
|
|
97
|
+
remarks: "Invoice payment"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
filename = "dynamic_qr_#{amount.to_i}_#{Time.now.to_i}.png"
|
|
101
|
+
client.qr_payment.save_qr_image(response['image'], filename)
|
|
102
|
+
|
|
103
|
+
puts "✓ Dynamic QR code generated successfully!"
|
|
104
|
+
puts " Saved to: #{filename}"
|
|
105
|
+
puts " Amount is fixed at BTN #{DkPaymentGateway::Utils.format_amount(amount)}"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Run the example
|
|
109
|
+
main if __FILE__ == $PROGRAM_NAME
|
|
110
|
+
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Intra-bank transfer example using DK Payment Gateway
|
|
5
|
+
# This demonstrates transferring funds between DK accounts
|
|
6
|
+
|
|
7
|
+
require 'bundler/setup'
|
|
8
|
+
require 'dk_payment_gateway'
|
|
9
|
+
|
|
10
|
+
# Configure the client
|
|
11
|
+
DkPaymentGateway.configure do |config|
|
|
12
|
+
config.base_url = ENV['DK_BASE_URL'] || "http://internal-gateway.uat.digitalkidu.bt/api/dkpg"
|
|
13
|
+
config.api_key = ENV['DK_API_KEY']
|
|
14
|
+
config.username = ENV['DK_USERNAME']
|
|
15
|
+
config.password = ENV['DK_PASSWORD']
|
|
16
|
+
config.client_id = ENV['DK_CLIENT_ID']
|
|
17
|
+
config.client_secret = ENV['DK_CLIENT_SECRET']
|
|
18
|
+
config.source_app = ENV['DK_SOURCE_APP'] || "SRC_AVS_0201"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def main
|
|
22
|
+
puts "=== DK Payment Gateway - Intra-Bank Transfer Example ==="
|
|
23
|
+
puts
|
|
24
|
+
|
|
25
|
+
# Initialize client
|
|
26
|
+
client = DkPaymentGateway.client
|
|
27
|
+
|
|
28
|
+
# Authenticate
|
|
29
|
+
puts "Authenticating..."
|
|
30
|
+
client.authenticate!
|
|
31
|
+
puts "✓ Authentication successful"
|
|
32
|
+
puts
|
|
33
|
+
|
|
34
|
+
# Transfer details
|
|
35
|
+
source_account = "100100365856"
|
|
36
|
+
beneficiary_account = "100100148337"
|
|
37
|
+
amount = 500.00
|
|
38
|
+
|
|
39
|
+
puts "Transfer Details:"
|
|
40
|
+
puts " From: #{source_account}"
|
|
41
|
+
puts " To: #{beneficiary_account}"
|
|
42
|
+
puts " Amount: BTN #{amount}"
|
|
43
|
+
puts
|
|
44
|
+
|
|
45
|
+
begin
|
|
46
|
+
# Step 1: Verify beneficiary account
|
|
47
|
+
puts "Step 1: Verifying beneficiary account..."
|
|
48
|
+
|
|
49
|
+
inquiry_response = client.intra_transaction.account_inquiry(
|
|
50
|
+
request_id: DkPaymentGateway::Utils.generate_request_id("INQ"),
|
|
51
|
+
amount: amount,
|
|
52
|
+
currency: "BTN",
|
|
53
|
+
bene_bank_code: "1060",
|
|
54
|
+
bene_account_number: beneficiary_account,
|
|
55
|
+
source_account_number: source_account
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
puts "✓ Account verified"
|
|
59
|
+
puts " Inquiry ID: #{inquiry_response['inquiry_id']}"
|
|
60
|
+
puts " Beneficiary Name: #{inquiry_response['account_name']}"
|
|
61
|
+
puts
|
|
62
|
+
|
|
63
|
+
# Step 2: Confirm transfer
|
|
64
|
+
print "Proceed with transfer? (yes/no): "
|
|
65
|
+
confirmation = gets.chomp.downcase
|
|
66
|
+
|
|
67
|
+
unless confirmation == 'yes' || confirmation == 'y'
|
|
68
|
+
puts "Transfer cancelled"
|
|
69
|
+
return
|
|
70
|
+
end
|
|
71
|
+
puts
|
|
72
|
+
|
|
73
|
+
# Step 3: Execute transfer
|
|
74
|
+
puts "Step 2: Executing transfer..."
|
|
75
|
+
|
|
76
|
+
transfer_response = client.intra_transaction.fund_transfer(
|
|
77
|
+
request_id: DkPaymentGateway::Utils.generate_request_id("TXN"),
|
|
78
|
+
inquiry_id: inquiry_response['inquiry_id'],
|
|
79
|
+
transaction_datetime: Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
80
|
+
transaction_amount: amount,
|
|
81
|
+
currency: "BTN",
|
|
82
|
+
payment_type: "INTRA",
|
|
83
|
+
source_account_number: source_account,
|
|
84
|
+
bene_cust_name: inquiry_response['account_name'],
|
|
85
|
+
bene_account_number: beneficiary_account,
|
|
86
|
+
bene_bank_code: "1060",
|
|
87
|
+
narration: "Test transfer"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
puts "✓ Transfer completed successfully!"
|
|
91
|
+
puts " Transaction Status ID: #{transfer_response['txn_status_id']}"
|
|
92
|
+
puts
|
|
93
|
+
|
|
94
|
+
# Step 4: Verify transaction status
|
|
95
|
+
puts "Step 3: Verifying transaction status..."
|
|
96
|
+
|
|
97
|
+
# Wait a moment for transaction to process
|
|
98
|
+
sleep 2
|
|
99
|
+
|
|
100
|
+
# Note: You would use the actual transaction_id returned by the system
|
|
101
|
+
# This is just an example
|
|
102
|
+
puts "✓ Transfer processed"
|
|
103
|
+
|
|
104
|
+
rescue DkPaymentGateway::TransactionError => e
|
|
105
|
+
puts "✗ Transaction error: #{e.message}"
|
|
106
|
+
puts " Error code: #{e.response_code}"
|
|
107
|
+
rescue DkPaymentGateway::Error => e
|
|
108
|
+
puts "✗ Error: #{e.message}"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Run the example
|
|
113
|
+
main if __FILE__ == $PROGRAM_NAME
|
|
114
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Simple payment example using DK Payment Gateway
|
|
5
|
+
# This demonstrates a basic pull payment flow
|
|
6
|
+
|
|
7
|
+
require 'bundler/setup'
|
|
8
|
+
require 'dk_payment_gateway'
|
|
9
|
+
|
|
10
|
+
# Configure the client
|
|
11
|
+
DkPaymentGateway.configure do |config|
|
|
12
|
+
config.base_url = ENV['DK_BASE_URL'] || 'https://internal-gateway.uat.digitalkidu.bt'
|
|
13
|
+
config.api_key = ENV['DK_API_KEY']
|
|
14
|
+
config.username = ENV['DK_USERNAME']
|
|
15
|
+
config.password = ENV['DK_PASSWORD']
|
|
16
|
+
config.client_id = ENV['DK_CLIENT_ID']
|
|
17
|
+
config.client_secret = ENV['DK_CLIENT_SECRET']
|
|
18
|
+
config.source_app = ENV['DK_SOURCE_APP'] || 'SRC_AVS_0201'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def main
|
|
22
|
+
puts '=== DK Payment Gateway - Simple Payment Example ==='
|
|
23
|
+
puts
|
|
24
|
+
|
|
25
|
+
# Initialize client
|
|
26
|
+
client = DkPaymentGateway.client
|
|
27
|
+
|
|
28
|
+
# Authenticate
|
|
29
|
+
puts 'Authenticating...'
|
|
30
|
+
client.authenticate!
|
|
31
|
+
puts '✓ Authentication successful'
|
|
32
|
+
puts
|
|
33
|
+
|
|
34
|
+
# Payment details
|
|
35
|
+
amount = 100.00
|
|
36
|
+
fee = 5.00
|
|
37
|
+
|
|
38
|
+
puts 'Payment Details:'
|
|
39
|
+
puts " Amount: BTN #{amount}"
|
|
40
|
+
puts " Fee: BTN #{fee}"
|
|
41
|
+
puts " Total: BTN #{amount + fee}"
|
|
42
|
+
puts
|
|
43
|
+
|
|
44
|
+
# Step 1: Request authorization
|
|
45
|
+
puts 'Step 1: Requesting payment authorization...'
|
|
46
|
+
|
|
47
|
+
stan = DkPaymentGateway::PullPayment.generate_stan('0201')
|
|
48
|
+
|
|
49
|
+
begin
|
|
50
|
+
auth_response = client.pull_payment.authorize(
|
|
51
|
+
transaction_datetime: Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
|
52
|
+
stan_number: stan,
|
|
53
|
+
transaction_amount: amount,
|
|
54
|
+
transaction_fee: fee,
|
|
55
|
+
payment_desc: 'Test payment - Order #TEST001',
|
|
56
|
+
account_number: '110158212197',
|
|
57
|
+
account_name: 'Test Merchant',
|
|
58
|
+
phone_number: '17811440',
|
|
59
|
+
remitter_account_number: '770182571',
|
|
60
|
+
remitter_account_name: 'Test Customer',
|
|
61
|
+
remitter_bank_id: '1040'
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
puts '✓ Authorization successful'
|
|
65
|
+
puts " Transaction ID: #{auth_response['bfs_txn_id']}"
|
|
66
|
+
puts " STAN: #{auth_response['stan_number']}"
|
|
67
|
+
puts
|
|
68
|
+
|
|
69
|
+
# Step 2: Get OTP from user
|
|
70
|
+
puts "Step 2: OTP has been sent to customer's phone"
|
|
71
|
+
print 'Enter OTP: '
|
|
72
|
+
otp = gets.chomp
|
|
73
|
+
puts
|
|
74
|
+
|
|
75
|
+
# Step 3: Complete payment
|
|
76
|
+
puts 'Step 3: Completing payment with OTP...'
|
|
77
|
+
|
|
78
|
+
debit_response = client.pull_payment.debit(
|
|
79
|
+
request_id: DkPaymentGateway::Utils.generate_request_id('PAY'),
|
|
80
|
+
bfs_txn_id: auth_response['bfs_txn_id'],
|
|
81
|
+
bfs_remitter_otp: otp
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
if debit_response['code'] == '00'
|
|
85
|
+
puts '✓ Payment completed successfully!'
|
|
86
|
+
puts " Transaction ID: #{debit_response['bfs_txn_id']}"
|
|
87
|
+
puts " Status: #{debit_response['description']}"
|
|
88
|
+
else
|
|
89
|
+
puts '✗ Payment failed'
|
|
90
|
+
puts " Code: #{debit_response['code']}"
|
|
91
|
+
puts " Description: #{debit_response['description']}"
|
|
92
|
+
end
|
|
93
|
+
rescue DkPaymentGateway::TransactionError => e
|
|
94
|
+
puts "✗ Transaction error: #{e.message}"
|
|
95
|
+
puts " Error code: #{e.response_code}"
|
|
96
|
+
rescue DkPaymentGateway::Error => e
|
|
97
|
+
puts "✗ Error: #{e.message}"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Run the example
|
|
102
|
+
main if __FILE__ == $PROGRAM_NAME
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
require "securerandom"
|
|
5
|
+
|
|
6
|
+
module DkPaymentGateway
|
|
7
|
+
class Authentication
|
|
8
|
+
attr_reader :client
|
|
9
|
+
|
|
10
|
+
def initialize(client)
|
|
11
|
+
@client = client
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Fetch authorization token
|
|
15
|
+
# Returns the access token string
|
|
16
|
+
def fetch_token
|
|
17
|
+
response = client.post(
|
|
18
|
+
"/v1/auth/token",
|
|
19
|
+
body: token_request_body,
|
|
20
|
+
headers: token_request_headers,
|
|
21
|
+
skip_auth: true
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
validate_token_response!(response)
|
|
25
|
+
|
|
26
|
+
response["response_data"]["access_token"]
|
|
27
|
+
rescue => e
|
|
28
|
+
raise AuthenticationError, "Failed to fetch token: #{e.message}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Fetch RSA private key for signing requests
|
|
32
|
+
# Returns the private key as a string
|
|
33
|
+
def fetch_private_key
|
|
34
|
+
raise AuthenticationError, "Access token required to fetch private key" unless client.access_token
|
|
35
|
+
|
|
36
|
+
request_id = generate_request_id
|
|
37
|
+
|
|
38
|
+
response = client.post(
|
|
39
|
+
"/v1/sign/key",
|
|
40
|
+
body: {
|
|
41
|
+
request_id: request_id,
|
|
42
|
+
source_app: client.config.source_app
|
|
43
|
+
},
|
|
44
|
+
skip_auth: false
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# The response is plain text containing the private key
|
|
48
|
+
if response.is_a?(String) && response.include?("BEGIN RSA PRIVATE KEY")
|
|
49
|
+
response
|
|
50
|
+
elsif response.is_a?(Hash) && response["response_code"] == "3001"
|
|
51
|
+
raise AuthenticationError, "Private key not found: #{response['response_detail']}"
|
|
52
|
+
else
|
|
53
|
+
raise AuthenticationError, "Invalid private key response"
|
|
54
|
+
end
|
|
55
|
+
rescue DkPaymentGateway::Error => e
|
|
56
|
+
raise
|
|
57
|
+
rescue => e
|
|
58
|
+
raise AuthenticationError, "Failed to fetch private key: #{e.message}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def token_request_body
|
|
64
|
+
params = {
|
|
65
|
+
username: client.config.username,
|
|
66
|
+
password: client.config.password,
|
|
67
|
+
client_id: client.config.client_id,
|
|
68
|
+
client_secret: client.config.client_secret,
|
|
69
|
+
grant_type: "password",
|
|
70
|
+
scopes: "keys:read",
|
|
71
|
+
source_app: client.config.source_app,
|
|
72
|
+
request_id: generate_request_id
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# Convert to URL-encoded format
|
|
76
|
+
URI.encode_www_form(params)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def token_request_headers
|
|
80
|
+
{
|
|
81
|
+
"Content-Type" => "application/x-www-form-urlencoded",
|
|
82
|
+
"X-gravitee-api-key" => client.config.api_key
|
|
83
|
+
}
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def validate_token_response!(response)
|
|
87
|
+
unless response.is_a?(Hash) && response["response_code"] == "0000"
|
|
88
|
+
error_detail = response["response_detail"] || response["response_message"] || "Unknown error"
|
|
89
|
+
raise AuthenticationError, "Token request failed: #{error_detail}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
unless response["response_data"] && response["response_data"]["access_token"]
|
|
93
|
+
raise AuthenticationError, "No access token in response"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def generate_request_id
|
|
98
|
+
"#{Time.now.to_i}-#{SecureRandom.hex(8)}"
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|