rma-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.
data/docs/EXAMPLES.md ADDED
@@ -0,0 +1,650 @@
1
+ # Code Examples
2
+
3
+ This document provides practical code examples for common scenarios when using the RMA Payment Gateway gem.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Basic Examples](#basic-examples)
8
+ - [Rails Examples](#rails-examples)
9
+ - [Error Handling Examples](#error-handling-examples)
10
+ - [Testing Examples](#testing-examples)
11
+ - [Advanced Examples](#advanced-examples)
12
+
13
+ ## Basic Examples
14
+
15
+ ### Simple Payment Flow
16
+
17
+ ```ruby
18
+ require 'rma/payment/gateway'
19
+
20
+ # Initialize client
21
+ client = Rma::Payment::Gateway::Client.new
22
+
23
+ # Complete payment flow
24
+ def process_payment(order_no, amount, email, bank_id, account_no, otp)
25
+ # Step 1: Authorization
26
+ puts "Authorizing payment..."
27
+ auth_response = client.authorization.call(order_no, amount, email)
28
+ transaction_id = auth_response["bfs_bfsTxnId"]
29
+ puts "✓ Transaction ID: #{transaction_id}"
30
+
31
+ # Step 2: Account Inquiry
32
+ puts "Verifying account..."
33
+ inquiry_response = client.account_inquiry.call(transaction_id, bank_id, account_no)
34
+ puts "✓ Account holder: #{inquiry_response['bfs_remitterName']}"
35
+
36
+ # Step 3: Debit Request
37
+ puts "Completing payment..."
38
+ debit_response = client.debit_request.call(transaction_id, otp)
39
+ puts "✓ Payment successful!"
40
+
41
+ debit_response
42
+ end
43
+
44
+ # Usage
45
+ begin
46
+ result = process_payment(
47
+ "ORDER123",
48
+ 100.50,
49
+ "customer@email.com",
50
+ "1010",
51
+ "12345678",
52
+ "123456"
53
+ )
54
+ puts "Payment completed: #{result['bfs_orderNo']}"
55
+ rescue Rma::Payment::Gateway::Error => e
56
+ puts "Payment failed: #{e.message}"
57
+ end
58
+ ```
59
+
60
+ ### Step-by-Step Payment
61
+
62
+ ```ruby
63
+ require 'rma/payment/gateway'
64
+
65
+ client = Rma::Payment::Gateway::Client.new
66
+
67
+ # Step 1: Authorization
68
+ puts "Enter order number:"
69
+ order_no = gets.chomp
70
+
71
+ puts "Enter amount:"
72
+ amount = gets.chomp.to_f
73
+
74
+ puts "Enter email:"
75
+ email = gets.chomp
76
+
77
+ auth_response = client.authorization.call(order_no, amount, email)
78
+ transaction_id = auth_response["bfs_bfsTxnId"]
79
+ puts "Authorization successful! Transaction ID: #{transaction_id}"
80
+
81
+ # Step 2: Account Inquiry
82
+ puts "\nEnter bank code (1010-1060):"
83
+ bank_id = gets.chomp
84
+
85
+ puts "Enter account number:"
86
+ account_no = gets.chomp
87
+
88
+ inquiry_response = client.account_inquiry.call(transaction_id, bank_id, account_no)
89
+ puts "Account verified: #{inquiry_response['bfs_remitterName']}"
90
+ puts "OTP sent to your registered mobile number"
91
+
92
+ # Step 3: Debit Request
93
+ puts "\nEnter OTP:"
94
+ otp = gets.chomp
95
+
96
+ debit_response = client.debit_request.call(transaction_id, otp)
97
+ puts "Payment successful!"
98
+ puts "Amount: #{debit_response['bfs_txnAmount']} BTN"
99
+ ```
100
+
101
+ ## Rails Examples
102
+
103
+ ### Payment Model
104
+
105
+ ```ruby
106
+ # app/models/payment.rb
107
+ class Payment < ApplicationRecord
108
+ belongs_to :order
109
+ belongs_to :user
110
+
111
+ enum status: {
112
+ pending: 0,
113
+ authorized: 1,
114
+ account_verified: 2,
115
+ completed: 3,
116
+ failed: 4,
117
+ refunded: 5
118
+ }
119
+
120
+ validates :order_id, presence: true
121
+ validates :amount, presence: true, numericality: { greater_than: 0 }
122
+ validates :transaction_id, uniqueness: true, allow_nil: true
123
+
124
+ def rma_client
125
+ @rma_client ||= Rma::Payment::Gateway::Client.new
126
+ end
127
+
128
+ def authorize!
129
+ response = rma_client.authorization.call(
130
+ order.order_number,
131
+ amount,
132
+ user.email
133
+ )
134
+
135
+ update!(
136
+ transaction_id: response["bfs_bfsTxnId"],
137
+ status: :authorized,
138
+ authorized_at: Time.current
139
+ )
140
+
141
+ response
142
+ end
143
+
144
+ def verify_account!(bank_id, account_number)
145
+ response = rma_client.account_inquiry.call(
146
+ transaction_id,
147
+ bank_id,
148
+ account_number
149
+ )
150
+
151
+ update!(
152
+ bank_id: bank_id,
153
+ account_number: account_number,
154
+ account_holder_name: response["bfs_remitterName"],
155
+ status: :account_verified,
156
+ account_verified_at: Time.current
157
+ )
158
+
159
+ response
160
+ end
161
+
162
+ def complete!(otp)
163
+ response = rma_client.debit_request.call(transaction_id, otp)
164
+
165
+ update!(
166
+ status: :completed,
167
+ completed_at: Time.current
168
+ )
169
+
170
+ # Update order status
171
+ order.mark_as_paid!
172
+
173
+ response
174
+ end
175
+ end
176
+ ```
177
+
178
+ ### Payment Controller
179
+
180
+ ```ruby
181
+ # app/controllers/payments_controller.rb
182
+ class PaymentsController < ApplicationController
183
+ before_action :authenticate_user!
184
+ before_action :set_payment, only: [:show, :verify_account, :complete]
185
+
186
+ def new
187
+ @order = Order.find(params[:order_id])
188
+ @payment = @order.payments.build(
189
+ user: current_user,
190
+ amount: @order.total_amount
191
+ )
192
+ end
193
+
194
+ def create
195
+ @order = Order.find(params[:order_id])
196
+ @payment = @order.payments.build(payment_params)
197
+ @payment.user = current_user
198
+
199
+ if @payment.save
200
+ begin
201
+ @payment.authorize!
202
+ redirect_to verify_account_payment_path(@payment),
203
+ notice: 'Payment authorized. Please verify your account.'
204
+ rescue Rma::Payment::Gateway::Error => e
205
+ @payment.update(status: :failed, error_message: e.message)
206
+ flash.now[:error] = "Payment authorization failed: #{e.message}"
207
+ render :new
208
+ end
209
+ else
210
+ render :new
211
+ end
212
+ end
213
+
214
+ def verify_account
215
+ # Show account verification form
216
+ end
217
+
218
+ def submit_account
219
+ begin
220
+ @payment.verify_account!(
221
+ params[:bank_id],
222
+ params[:account_number]
223
+ )
224
+ redirect_to complete_payment_path(@payment),
225
+ notice: 'Account verified. OTP sent to your mobile.'
226
+ rescue Rma::Payment::Gateway::Error => e
227
+ flash.now[:error] = "Account verification failed: #{e.message}"
228
+ render :verify_account
229
+ end
230
+ end
231
+
232
+ def complete
233
+ # Show OTP form
234
+ end
235
+
236
+ def submit_otp
237
+ begin
238
+ @payment.complete!(params[:otp])
239
+ redirect_to order_path(@payment.order),
240
+ notice: 'Payment completed successfully!'
241
+ rescue Rma::Payment::Gateway::Error => e
242
+ flash.now[:error] = "Payment failed: #{e.message}"
243
+ render :complete
244
+ end
245
+ end
246
+
247
+ private
248
+
249
+ def set_payment
250
+ @payment = current_user.payments.find(params[:id])
251
+ end
252
+
253
+ def payment_params
254
+ params.require(:payment).permit(:amount)
255
+ end
256
+ end
257
+ ```
258
+
259
+ ### Payment Service Object
260
+
261
+ ```ruby
262
+ # app/services/payment_processor.rb
263
+ class PaymentProcessor
264
+ attr_reader :payment, :client, :errors
265
+
266
+ def initialize(payment)
267
+ @payment = payment
268
+ @client = Rma::Payment::Gateway::Client.new
269
+ @errors = []
270
+ end
271
+
272
+ def authorize
273
+ validate_authorization!
274
+
275
+ response = client.authorization.call(
276
+ payment.order.order_number,
277
+ payment.amount,
278
+ payment.user.email
279
+ )
280
+
281
+ payment.update!(
282
+ transaction_id: response["bfs_bfsTxnId"],
283
+ status: 'authorized'
284
+ )
285
+
286
+ log_event('authorized', response)
287
+ notify_user('authorization_success')
288
+
289
+ true
290
+ rescue Rma::Payment::Gateway::Error => e
291
+ handle_error('authorization', e)
292
+ false
293
+ end
294
+
295
+ def verify_account(bank_id, account_number)
296
+ validate_account_verification!
297
+
298
+ response = client.account_inquiry.call(
299
+ payment.transaction_id,
300
+ bank_id,
301
+ account_number
302
+ )
303
+
304
+ payment.update!(
305
+ bank_id: bank_id,
306
+ account_number: account_number,
307
+ account_holder_name: response["bfs_remitterName"],
308
+ status: 'account_verified'
309
+ )
310
+
311
+ log_event('account_verified', response)
312
+ notify_user('otp_sent')
313
+
314
+ true
315
+ rescue Rma::Payment::Gateway::Error => e
316
+ handle_error('account_verification', e)
317
+ false
318
+ end
319
+
320
+ def complete(otp)
321
+ validate_completion!
322
+
323
+ response = client.debit_request.call(
324
+ payment.transaction_id,
325
+ otp
326
+ )
327
+
328
+ payment.update!(
329
+ status: 'completed',
330
+ completed_at: Time.current
331
+ )
332
+
333
+ payment.order.mark_as_paid!
334
+
335
+ log_event('completed', response)
336
+ notify_user('payment_success')
337
+ send_receipt
338
+
339
+ true
340
+ rescue Rma::Payment::Gateway::Error => e
341
+ handle_error('completion', e)
342
+ false
343
+ end
344
+
345
+ private
346
+
347
+ def validate_authorization!
348
+ raise ArgumentError, "Payment already authorized" if payment.authorized?
349
+ raise ArgumentError, "Invalid amount" unless valid_amount?
350
+ end
351
+
352
+ def validate_account_verification!
353
+ raise ArgumentError, "Payment not authorized" unless payment.authorized?
354
+ end
355
+
356
+ def validate_completion!
357
+ raise ArgumentError, "Account not verified" unless payment.account_verified?
358
+ end
359
+
360
+ def valid_amount?
361
+ Rma::Payment::Gateway::Utils.valid_amount?(payment.amount)
362
+ end
363
+
364
+ def handle_error(step, error)
365
+ @errors << error.message
366
+ payment.update(
367
+ status: 'failed',
368
+ error_message: error.message,
369
+ failed_at: Time.current
370
+ )
371
+ log_event("#{step}_failed", { error: error.message })
372
+ notify_admin_of_failure(step, error)
373
+ end
374
+
375
+ def log_event(event, data)
376
+ PaymentLog.create!(
377
+ payment: payment,
378
+ event: event,
379
+ data: data.to_json,
380
+ created_at: Time.current
381
+ )
382
+ end
383
+
384
+ def notify_user(template)
385
+ PaymentMailer.send(template, payment).deliver_later
386
+ end
387
+
388
+ def notify_admin_of_failure(step, error)
389
+ AdminMailer.payment_failed(payment, step, error).deliver_later
390
+ end
391
+
392
+ def send_receipt
393
+ PaymentMailer.receipt(payment).deliver_later
394
+ end
395
+ end
396
+ ```
397
+
398
+ ## Error Handling Examples
399
+
400
+ ### Comprehensive Error Handling
401
+
402
+ ```ruby
403
+ def process_payment_with_error_handling(order_no, amount, email)
404
+ client = Rma::Payment::Gateway::Client.new
405
+
406
+ begin
407
+ response = client.authorization.call(order_no, amount, email)
408
+ { success: true, data: response }
409
+
410
+ rescue Rma::Payment::Gateway::ConfigurationError => e
411
+ # Configuration issue - needs admin attention
412
+ log_error("Configuration error", e)
413
+ notify_admin(e)
414
+ { success: false, error: "System configuration error. Please contact support." }
415
+
416
+ rescue Rma::Payment::Gateway::InvalidParameterError => e
417
+ # User input error - show to user
418
+ log_error("Invalid parameters", e)
419
+ { success: false, error: "Invalid input: #{e.message}" }
420
+
421
+ rescue Rma::Payment::Gateway::AuthenticationError => e
422
+ # Authentication failed - could be temporary
423
+ log_error("Authentication error", e)
424
+ { success: false, error: "Payment authorization failed. Please try again." }
425
+
426
+ rescue Rma::Payment::Gateway::NetworkError => e
427
+ # Network issue - retry might help
428
+ log_error("Network error", e)
429
+ { success: false, error: "Service temporarily unavailable. Please try again later." }
430
+
431
+ rescue Rma::Payment::Gateway::APIError => e
432
+ # API error - log and notify
433
+ log_error("API error", e)
434
+ notify_admin(e)
435
+ { success: false, error: "Payment processing error. Please contact support." }
436
+
437
+ rescue Rma::Payment::Gateway::Error => e
438
+ # Generic error - catch all
439
+ log_error("Unknown error", e)
440
+ notify_admin(e)
441
+ { success: false, error: "An unexpected error occurred. Please contact support." }
442
+ end
443
+ end
444
+ ```
445
+
446
+ ### Retry Logic
447
+
448
+ ```ruby
449
+ def authorize_with_retry(order_no, amount, email, max_retries: 3)
450
+ client = Rma::Payment::Gateway::Client.new
451
+ retries = 0
452
+
453
+ begin
454
+ client.authorization.call(order_no, amount, email)
455
+
456
+ rescue Rma::Payment::Gateway::NetworkError => e
457
+ retries += 1
458
+ if retries < max_retries
459
+ sleep(2 ** retries) # Exponential backoff
460
+ retry
461
+ else
462
+ raise e
463
+ end
464
+
465
+ rescue Rma::Payment::Gateway::InvalidParameterError => e
466
+ # Don't retry validation errors
467
+ raise e
468
+ end
469
+ end
470
+ ```
471
+
472
+ ## Testing Examples
473
+
474
+ ### RSpec Examples
475
+
476
+ ```ruby
477
+ # spec/services/payment_processor_spec.rb
478
+ require 'rails_helper'
479
+
480
+ RSpec.describe PaymentProcessor do
481
+ let(:user) { create(:user, email: 'test@example.com') }
482
+ let(:order) { create(:order, order_number: 'ORDER123') }
483
+ let(:payment) { create(:payment, user: user, order: order, amount: 100.50) }
484
+ let(:processor) { described_class.new(payment) }
485
+ let(:client) { instance_double(Rma::Payment::Gateway::Client) }
486
+
487
+ before do
488
+ allow(Rma::Payment::Gateway::Client).to receive(:new).and_return(client)
489
+ end
490
+
491
+ describe '#authorize' do
492
+ let(:auth_response) do
493
+ {
494
+ "bfs_bfsTxnId" => "TXN123",
495
+ "bfs_responseCode" => "00",
496
+ "bfs_responseDesc" => "Success"
497
+ }
498
+ end
499
+
500
+ context 'when successful' do
501
+ before do
502
+ allow(client).to receive_message_chain(:authorization, :call)
503
+ .and_return(auth_response)
504
+ end
505
+
506
+ it 'authorizes the payment' do
507
+ expect(processor.authorize).to be true
508
+ expect(payment.reload.transaction_id).to eq("TXN123")
509
+ expect(payment.status).to eq('authorized')
510
+ end
511
+ end
512
+
513
+ context 'when authorization fails' do
514
+ before do
515
+ allow(client).to receive_message_chain(:authorization, :call)
516
+ .and_raise(Rma::Payment::Gateway::AuthenticationError, "Failed")
517
+ end
518
+
519
+ it 'handles the error' do
520
+ expect(processor.authorize).to be false
521
+ expect(processor.errors).to include("Failed")
522
+ expect(payment.reload.status).to eq('failed')
523
+ end
524
+ end
525
+ end
526
+ end
527
+ ```
528
+
529
+ ### Mock Responses
530
+
531
+ ```ruby
532
+ # spec/support/rma_helpers.rb
533
+ module RmaHelpers
534
+ def mock_rma_authorization(transaction_id: "TXN123")
535
+ {
536
+ "bfs_bfsTxnId" => transaction_id,
537
+ "bfs_responseCode" => "00",
538
+ "bfs_responseDesc" => "Success",
539
+ "bfs_orderNo" => "ORDER123",
540
+ "bfs_txnAmount" => "100.50"
541
+ }
542
+ end
543
+
544
+ def mock_rma_account_inquiry(name: "John Doe")
545
+ {
546
+ "bfs_bfsTxnId" => "TXN123",
547
+ "bfs_responseCode" => "00",
548
+ "bfs_responseDesc" => "Success",
549
+ "bfs_remitterName" => name,
550
+ "bfs_remitterAccNo" => "12345678"
551
+ }
552
+ end
553
+
554
+ def mock_rma_debit_request
555
+ {
556
+ "bfs_bfsTxnId" => "TXN123",
557
+ "bfs_responseCode" => "00",
558
+ "bfs_responseDesc" => "Transaction Successful",
559
+ "bfs_txnAmount" => "100.50",
560
+ "bfs_orderNo" => "ORDER123"
561
+ }
562
+ end
563
+ end
564
+
565
+ RSpec.configure do |config|
566
+ config.include RmaHelpers
567
+ end
568
+ ```
569
+
570
+ ## Advanced Examples
571
+
572
+ ### Background Job Processing
573
+
574
+ ```ruby
575
+ # app/jobs/process_payment_job.rb
576
+ class ProcessPaymentJob < ApplicationJob
577
+ queue_as :payments
578
+ retry_on Rma::Payment::Gateway::NetworkError, wait: :exponentially_longer, attempts: 5
579
+ discard_on Rma::Payment::Gateway::InvalidParameterError
580
+
581
+ def perform(payment_id, step, params = {})
582
+ payment = Payment.find(payment_id)
583
+ processor = PaymentProcessor.new(payment)
584
+
585
+ case step
586
+ when 'authorize'
587
+ processor.authorize
588
+ when 'verify_account'
589
+ processor.verify_account(params[:bank_id], params[:account_number])
590
+ when 'complete'
591
+ processor.complete(params[:otp])
592
+ end
593
+ rescue Rma::Payment::Gateway::Error => e
594
+ payment.update(status: 'failed', error_message: e.message)
595
+ raise
596
+ end
597
+ end
598
+ ```
599
+
600
+ ### Webhook Handler
601
+
602
+ ```ruby
603
+ # app/controllers/webhooks/rma_controller.rb
604
+ module Webhooks
605
+ class RmaController < ApplicationController
606
+ skip_before_action :verify_authenticity_token
607
+
608
+ def payment_status
609
+ # Handle payment status webhook from RMA
610
+ transaction_id = params[:transaction_id]
611
+ status = params[:status]
612
+
613
+ payment = Payment.find_by(transaction_id: transaction_id)
614
+
615
+ if payment
616
+ payment.update_from_webhook(status, params)
617
+ head :ok
618
+ else
619
+ head :not_found
620
+ end
621
+ end
622
+ end
623
+ end
624
+ ```
625
+
626
+ ### Payment Analytics
627
+
628
+ ```ruby
629
+ # app/services/payment_analytics.rb
630
+ class PaymentAnalytics
631
+ def self.success_rate(period: 30.days)
632
+ total = Payment.where('created_at > ?', period.ago).count
633
+ successful = Payment.completed.where('created_at > ?', period.ago).count
634
+
635
+ return 0 if total.zero?
636
+ (successful.to_f / total * 100).round(2)
637
+ end
638
+
639
+ def self.average_completion_time
640
+ Payment.completed.average('EXTRACT(EPOCH FROM (completed_at - created_at))')
641
+ end
642
+
643
+ def self.failure_reasons
644
+ Payment.failed.group(:error_message).count
645
+ end
646
+ end
647
+ ```
648
+
649
+ For more examples, see the [Usage Guide](USAGE_GUIDE.md).
650
+