feat : add kbz merchant service
This commit is contained in:
99
app/services/kbz_merchant.rb
Normal file
99
app/services/kbz_merchant.rb
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
require 'httparty'
|
||||||
|
|
||||||
|
class KbzMerchant
|
||||||
|
class PaymentError < StandardError; end
|
||||||
|
|
||||||
|
def initialize(payment_method)
|
||||||
|
@payment_method = payment_method
|
||||||
|
@api_url = payment_method.test_mode? ?
|
||||||
|
'http://api.kbzpay.com/payment/gateway/uat/precreate' :
|
||||||
|
'https://api.kbzpay.com/payment/gateway/precreate'
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_order(transaction_params)
|
||||||
|
payload = build_payload(transaction_params)
|
||||||
|
response = send_request(payload)
|
||||||
|
handle_response(response)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def build_payload(params)
|
||||||
|
base_params = {
|
||||||
|
method: 'kbz.payment.precreate',
|
||||||
|
timestamp: Time.now.utc.to_i.to_s,
|
||||||
|
nonce_str: SecureRandom.hex(16),
|
||||||
|
notify_url: @payment_method.notify_url,
|
||||||
|
sign_type: 'SHA256',
|
||||||
|
version: '1.0',
|
||||||
|
biz_content: {
|
||||||
|
appid: @payment_method.appid,
|
||||||
|
merch_code: @payment_method.merch_code,
|
||||||
|
merch_order_id: params[:merch_order_id],
|
||||||
|
trade_type: 'PAY_BY_QRCODE',
|
||||||
|
total_amount: params[:total_amount].to_s,
|
||||||
|
trans_currency: 'MMK',
|
||||||
|
timeout_express: params[:timeout] || '120m'
|
||||||
|
}.compact
|
||||||
|
}
|
||||||
|
|
||||||
|
flattened = flatten_hash(base_params)
|
||||||
|
base_params.merge(sign: generate_signature(flattened))
|
||||||
|
end
|
||||||
|
|
||||||
|
def flatten_hash(hash, parent_key = nil)
|
||||||
|
hash.each_with_object({}) do |(k, v), res|
|
||||||
|
key = parent_key ? "#{k}" : k.to_s
|
||||||
|
if v.is_a?(Hash)
|
||||||
|
res.merge!(flatten_hash(v, key))
|
||||||
|
else
|
||||||
|
res[key] = v.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_signature(flattened_params)
|
||||||
|
key = 'uatfoodcourt@12'
|
||||||
|
sorted_params = flattened_params.except('sign', 'sign_type').sort
|
||||||
|
string_a = sorted_params.map { |k, v| "#{k}=#{v}" }.join('&')
|
||||||
|
puts "String a: #{string_a}"
|
||||||
|
string_to_sign = "#{string_a}&key=#{key}"
|
||||||
|
puts "String to sign: #{string_to_sign}"
|
||||||
|
Digest::SHA256.hexdigest(string_to_sign).upcase
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_request(payload)
|
||||||
|
headers = {
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
'User-Agent' => 'KBZPay/1.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
puts "Headers: #{headers}"
|
||||||
|
puts "Payload: #{payload.to_json}"
|
||||||
|
|
||||||
|
begin
|
||||||
|
response = HTTParty.post(
|
||||||
|
@api_url,
|
||||||
|
headers: headers,
|
||||||
|
body: { Request: payload }.to_json,
|
||||||
|
timeout: 15
|
||||||
|
)
|
||||||
|
|
||||||
|
puts "Response: #{response}"
|
||||||
|
rescue HTTParty::Error => e
|
||||||
|
raise PaymentError, "HTTP error: #{e.message}"
|
||||||
|
rescue SocketError => e
|
||||||
|
raise PaymentError, "Network error: #{e.message}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def handle_response(response)
|
||||||
|
json_response = JSON.parse(response.body)
|
||||||
|
if json_response.dig('Response', 'result') == 'SUCCESS'
|
||||||
|
json_response['Response']
|
||||||
|
else
|
||||||
|
raise PaymentError, "Payment failed: #{json_response['Response']['msg']}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -21,6 +21,8 @@ module SXRestaurants
|
|||||||
config.active_record.time_zone_aware_types = [:datetime, :time]
|
config.active_record.time_zone_aware_types = [:datetime, :time]
|
||||||
config.active_job.queue_adapter = :sidekiq
|
config.active_job.queue_adapter = :sidekiq
|
||||||
config.time_zone = 'Asia/Rangoon'
|
config.time_zone = 'Asia/Rangoon'
|
||||||
|
config.autoload_paths << Rails.root.join('app/services')
|
||||||
|
|
||||||
|
|
||||||
config.middleware.insert_before ActionDispatch::Static, Rack::Cors do
|
config.middleware.insert_before ActionDispatch::Static, Rack::Cors do
|
||||||
allow do
|
allow do
|
||||||
|
|||||||
Reference in New Issue
Block a user