fix : qr code generation to be dynamic
This commit is contained in:
@@ -213,33 +213,38 @@ class Foodcourt::QrpayController < BaseFoodcourtController
|
||||
end
|
||||
end
|
||||
|
||||
qr_str = "00020101021226480015com.mmqrpay.www0115223743000377032020600000052045814530310454075000.005802MM5908Code2LAB6006Yangon61051101062730125ORDER_1747826957_5ae9cb900523MMQR1075L175919500000010813PAY_BY_QRCODE64300002MY0109ကုဒ်တူလက်0207ရန်ကုန်6304AD40";
|
||||
@string_to_encode = qr_str
|
||||
@paymethod = PaymentMethodSetting.find_by(payment_method: "MMQR")
|
||||
|
||||
qrcode = RQRCode::QRCode.new(@string_to_encode)
|
||||
|
||||
@qr_svg = qrcode.as_svg(
|
||||
color: "000", # Hex color for the QR code modules (black)
|
||||
shape_rendering: "crispEdges", # Renders sharp edges
|
||||
module_size: 2, # Size of each module (dot/square)
|
||||
standalone: true, # Outputs a complete SVG document
|
||||
use_path: true # Modern SVG path rendering
|
||||
)
|
||||
@merchant = KbzMerchant.new(@paymethod)
|
||||
|
||||
png_data = qrcode.as_png(
|
||||
bit_depth: 1,
|
||||
border_modules: 4,
|
||||
color_mode: ChunkyPNG::COLOR_GRAYSCALE,
|
||||
color: 'black',
|
||||
file: nil,
|
||||
fill: 'white',
|
||||
module_px_size: 8, # Pixel size of each module
|
||||
resize_exactly_to: false,
|
||||
resize_gte_to: false,
|
||||
size: 240 # Approximate size of the image in pixels (e.g., 240x240)
|
||||
).to_s
|
||||
@response = @merchant.create_order(amount: @sale_data.grand_total, merch_order_id: @sale_data.receipt_no)
|
||||
@qr_string = @response['qrCode']
|
||||
|
||||
ActionCable.server.broadcast('second_display_view_channel', { data: qr_str, qr_svg: @qr_svg })
|
||||
qrcode = RQRCode::QRCode.new(@qr_string)
|
||||
|
||||
@qr_svg = qrcode.as_svg(
|
||||
color: "000",
|
||||
shape_rendering: "crispEdges",
|
||||
module_size: 2,
|
||||
standalone: true,
|
||||
use_path: true
|
||||
)
|
||||
|
||||
# png_data = qrcode.as_png(
|
||||
# bit_depth: 1,
|
||||
# border_modules: 4,
|
||||
# color_mode: ChunkyPNG::COLOR_GRAYSCALE,
|
||||
# color: 'black',
|
||||
# file: nil,
|
||||
# fill: 'white',
|
||||
# module_px_size: 8, # Pixel size of each module
|
||||
# resize_exactly_to: false,
|
||||
# resize_gte_to: false,
|
||||
# size: 240 # Approximate size of the image in pixels (e.g., 240x240)
|
||||
# ).to_s
|
||||
|
||||
ActionCable.server.broadcast('second_display_view_channel', { data: @qr_string, qr_svg: @qr_svg })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,20 +5,18 @@ class KbzMerchant
|
||||
|
||||
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'
|
||||
@api_url ='http://api.kbzpay.com/payment/gateway/uat/precreate'
|
||||
end
|
||||
|
||||
def create_order(transaction_params)
|
||||
payload = build_payload(transaction_params)
|
||||
def create_order(amount:, merch_order_id:)
|
||||
payload = build_payload(amount, merch_order_id)
|
||||
response = send_request(payload)
|
||||
handle_response(response)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build_payload(params)
|
||||
def build_payload(amount, merch_order_id, timeout='120m')
|
||||
base_params = {
|
||||
method: 'kbz.payment.precreate',
|
||||
timestamp: Time.now.utc.to_i.to_s,
|
||||
@@ -27,13 +25,13 @@ class KbzMerchant
|
||||
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],
|
||||
appid: @payment_method.gateway_url,
|
||||
merch_code: @payment_method.merchant_account_id,
|
||||
merch_order_id: merch_order_id,
|
||||
trade_type: 'PAY_BY_QRCODE',
|
||||
total_amount: params[:total_amount].to_s,
|
||||
total_amount: amount.to_s,
|
||||
trans_currency: 'MMK',
|
||||
timeout_express: params[:timeout] || '120m'
|
||||
timeout_express: timeout || '120m'
|
||||
}.compact
|
||||
}
|
||||
|
||||
@@ -53,11 +51,10 @@ class KbzMerchant
|
||||
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}"
|
||||
string_to_sign = "#{string_a}&key=#{@payment_method.auth_token}"
|
||||
puts "String to sign: #{string_to_sign}"
|
||||
Digest::SHA256.hexdigest(string_to_sign).upcase
|
||||
end
|
||||
@@ -78,8 +75,8 @@ class KbzMerchant
|
||||
body: { Request: payload }.to_json,
|
||||
timeout: 15
|
||||
)
|
||||
|
||||
puts "Response: #{response}"
|
||||
response.body
|
||||
# puts "Response: #{response}"
|
||||
rescue HTTParty::Error => e
|
||||
raise PaymentError, "HTTP error: #{e.message}"
|
||||
rescue SocketError => e
|
||||
@@ -89,7 +86,7 @@ class KbzMerchant
|
||||
|
||||
|
||||
def handle_response(response)
|
||||
json_response = JSON.parse(response.body)
|
||||
json_response = JSON.parse(response)
|
||||
if json_response.dig('Response', 'result') == 'SUCCESS'
|
||||
json_response['Response']
|
||||
else
|
||||
|
||||
@@ -1,57 +1,125 @@
|
||||
<div class="row clearfix h-100">
|
||||
<div class="col-lg-6 col-md-6 col-sm-6 h-100">
|
||||
<div class="card h-100" style="opacity: 0.75;">
|
||||
<div class="card h-100" style="opacity: 0.85; background-color: #f8f9fa;">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h4 class="mb-0">Invoice Details</h4>
|
||||
</div>
|
||||
<div class="card-block h-100">
|
||||
<div class="card-text">
|
||||
<div id="order-detail-slimscroll" data-height="190">
|
||||
<div id="order-detail-slimscroll" style="max-height: 60vh; overflow-y: auto;">
|
||||
<table class="table table-striped second_display_items" id="order-items-table">
|
||||
<thead>
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th class="item-name">Items</th>
|
||||
<th class="item-">QTY</th>
|
||||
<th class="item-">Price</th>
|
||||
<th class="item-qty">QTY</th>
|
||||
<th class="item-price">Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<!-- Items will be populated here -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<table class="table" border="0">
|
||||
<div class="card-footer bg-light">
|
||||
<table class="table table-borderless">
|
||||
<tr>
|
||||
<td class="charges-name"><strong>Sub Total:</strong></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="item-attr"><strong id="s_sub_total">0.00</strong></td>
|
||||
<td class="text-right item-attr"><strong id="s_sub_total">0.00</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="charges-name"><strong>Discount Amount:</strong></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="item-attr"><strong id="s_total_discount">0.00</strong></td>
|
||||
<td class="charges-name"><strong>Discount:</strong></td>
|
||||
<td class="text-right item-attr"><strong id="s_total_discount">0.00</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="charges-name"><strong>Tax Amount:</strong></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="item-attr"><strong id="s_tatal_tax">0.00</strong></td>
|
||||
<td class="text-right item-attr"><strong id="s_tatal_tax">0.00</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="charges-name"><strong>Grand:</strong></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="item-attr"><strong id="s_grand_total">0.00</strong></td>
|
||||
<tr class="table-active">
|
||||
<td class="charges-name"><strong>Grand Total:</strong></td>
|
||||
<td class="text-right item-attr"><strong id="s_grand_total">0.00</strong></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-6 h-100">
|
||||
<div id="qrpay_svg" style="background-color: #ddd;">
|
||||
|
||||
<div class="col-lg-6 col-md-6 col-sm-6 h-100 d-flex flex-column">
|
||||
<div class="card h-100" style="opacity: 0.85;">
|
||||
<div class="card-header text-white" style="background-color: #ffc107;">
|
||||
<h4 class="mb-0">Payment Options</h4>
|
||||
</div>
|
||||
<div class="card-body d-flex flex-column align-items-center justify-content-center">
|
||||
<div class="text-center mb-4">
|
||||
<h5>Scan to Pay</h5>
|
||||
<p class="text-muted">Use your mobile wallet app</p>
|
||||
</div>
|
||||
|
||||
<!-- QR Code Container -->
|
||||
<div id="qr-payment-container" class="text-center p-3 bg-white rounded border" style="max-width: 300px;">
|
||||
<div id="qr-code" class="mb-2">
|
||||
<!-- QR Code will be generated here -->
|
||||
<div class="">
|
||||
<div id="qrpay_svg">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="payment-details">
|
||||
<p class="mb-1"><strong>Amount:</strong> <span id="qr-amount"><%= number_to_currency(@total_amount) %></span></p>
|
||||
<p class="mb-1"><strong>Invoice #:</strong> <span id="qr-invoice"><%= @invoice_id %></span></p>
|
||||
<p class="text-muted small">Expires in 15 minutes</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="payment-instructions mt-4 text-center">
|
||||
<h6>How to Pay:</h6>
|
||||
<ol class="text-left small pl-3">
|
||||
<li>Open your mobile wallet app</li>
|
||||
<li>Tap on 'Scan QR Code'</li>
|
||||
<li>Point your camera at this code</li>
|
||||
<li>Confirm the payment details</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Add these styles to your existing CSS */
|
||||
.card {
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
border-radius: 8px 8px 0 0 !important;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
|
||||
.table thead th {
|
||||
border-bottom: 2px solid #dee2e6;
|
||||
}
|
||||
|
||||
#qr-payment-container {
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.payment-instructions {
|
||||
background-color: #f8f9fa;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.table-active {
|
||||
background-color: rgba(0,0,0,0.05);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -677,6 +677,8 @@ scope "(:locale)", locale: /en|mm/ do
|
||||
get 'sale/:sale_id' => 'sales#show'
|
||||
get 'order/:order_id' => "orders#show"
|
||||
|
||||
get 'qrpay/payment_loading' => 'qrpay#payment_loading'
|
||||
|
||||
# Other Charges
|
||||
get "/:sale_id/:type/other_charges" => "other_charges#index"
|
||||
post "/:sale_id/other_charges" => "other_charges#create"
|
||||
|
||||
Reference in New Issue
Block a user