qr pay updates
- subscribe to action cable from cloud and listen - callback from cloud to local and show success payment in real time - payment service and process payment after callback
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
class Foodcourt::QrpayController < BaseFoodcourtController
|
||||
require 'rqrcode'
|
||||
skip_before_action :authenticate, only: [:create]
|
||||
skip_before_action :verify_authenticity_token, only: [:create]
|
||||
|
||||
|
||||
def init
|
||||
@cash_exist = PaymentMethodSetting.cash_exist
|
||||
@@ -217,6 +220,28 @@ class Foodcourt::QrpayController < BaseFoodcourtController
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
sale_id = params[:sale_id]
|
||||
|
||||
unless current_login_employee
|
||||
render json: { status: false, message: "User not authenticated or employee context missing." }, status: :unauthorized
|
||||
return
|
||||
end
|
||||
|
||||
qrpayment_service = QrPaymentService.new(sale_id, current_login_employee)
|
||||
result = qrpayment_service.process
|
||||
|
||||
if result[:status]
|
||||
render json: result, status: :ok
|
||||
else
|
||||
status_code = result[:message].include?("not found") ? :not_found : :unprocessable_entity
|
||||
render json: result, status: status_code
|
||||
end
|
||||
end
|
||||
|
||||
def test_pay
|
||||
end
|
||||
|
||||
def cancel
|
||||
# cancel orders and related
|
||||
sale_id = params[:sale_id]
|
||||
|
||||
61
app/services/qr_payment_service.rb
Normal file
61
app/services/qr_payment_service.rb
Normal file
@@ -0,0 +1,61 @@
|
||||
class QrPaymentService
|
||||
attr_reader :sale_id, :current_login_employee, :sale, :booking, :processed_sale_payment
|
||||
|
||||
def initialize(sale_id, current_login_employee)
|
||||
@sale_id = sale_id
|
||||
@current_login_employee = current_login_employee
|
||||
end
|
||||
|
||||
def process
|
||||
return { status: false, message: "Sale ID is required." } unless sale_id.present?
|
||||
|
||||
SalePayment.transaction do
|
||||
find_sale_and_booking
|
||||
return { status: false, message: "There is no sale for '#{sale_id}'!" } unless sale
|
||||
return { status: false, message: "Already paid for '#{sale_id}'!" } unless sale.sale_status == "new"
|
||||
|
||||
status, payment_attempt = process_the_payment
|
||||
unless status
|
||||
error_message = payment_attempt&.errors&.full_messages&.join(', ') || "Payment processing failed."
|
||||
return { status: false, message: error_message }
|
||||
end
|
||||
|
||||
|
||||
process_orders_and_broadcast
|
||||
return { status: true, message: "Payment successful." }
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
{ status: false, message: "Sale not found for ID '#{sale_id}'." }
|
||||
rescue StandardError => e
|
||||
Rails.logger.error "QrPaymentService Error: #{e.message}\n#{e.backtrace.join("\n")}"
|
||||
{ status: false, message: "An unexpected error occurred: #{e.message}" }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_sale_and_booking
|
||||
@sale = Sale.find_by_sale_id(sale_id) # Consider find_by_sale_id! if you want RecordNotFound earlier
|
||||
@booking = @sale&.booking
|
||||
end
|
||||
|
||||
def process_the_payment
|
||||
sale_payment_creator = SalePayment.new
|
||||
status, payment = sale_payment_creator.process_payment(
|
||||
sale,
|
||||
current_login_employee,
|
||||
sale.grand_total,
|
||||
"MMQR"
|
||||
)
|
||||
[status, payment]
|
||||
end
|
||||
|
||||
def process_orders_and_broadcast
|
||||
booking.orders.each do |order|
|
||||
oqs = OrderQueueStation.new
|
||||
oqs.pay_process_order_queue(order.order_id, booking.dining_facility_id)
|
||||
|
||||
assign_order = AssignedOrderItem.assigned_order_item_by_job(order.order_id)
|
||||
ActionCable.server.broadcast "order_queue_station_channel", order: assign_order
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -247,29 +247,87 @@
|
||||
<script defer type="text/javascript">
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const paymentWaiting = document.querySelector('.payment-waiting');
|
||||
let amountToReceive = <%= number_with_precision(@sale_data.grand_total, precision: precision.to_i) %>
|
||||
let amountToReceive = <%= number_with_precision(@sale_data.grand_total, precision: precision.to_i) %>;
|
||||
const ws = new WebSocket("wss://juicecorner-0mo.sx-fc.app/cable");
|
||||
|
||||
function checkPaymentStatus() {
|
||||
// fetch('')
|
||||
// .then(response => response.json())
|
||||
// .then(data => {
|
||||
// if (data.paid) {
|
||||
// paymentWaiting.innerHTML = `
|
||||
// <div class="payment-success text-center">
|
||||
// <i class="material-icons" style="font-size: 50px; color: #4CAF50;">check_circle</i>
|
||||
// <h3 class="m-t-20" style="color: #4CAF50;">Payment Successful!</h3>
|
||||
// <p>Amount Received: ${amountToReceive}</p>
|
||||
// </div>
|
||||
// `;
|
||||
// } else {
|
||||
// setTimeout(checkPaymentStatus, 3000);
|
||||
// }
|
||||
// });
|
||||
ws.onopen = () => {
|
||||
console.log("Nagato channel connected");
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
command: "subscribe",
|
||||
identifier: JSON.stringify({
|
||||
channel: "TestChannel"
|
||||
})
|
||||
}));
|
||||
}
|
||||
|
||||
// Start checking payment status
|
||||
checkPaymentStatus();
|
||||
ws.onmessage = (e) => {
|
||||
const msg = JSON.parse(e.data);
|
||||
console.log("Received:", msg)
|
||||
|
||||
if(msg.type === 'confirm_subscription') {
|
||||
console.log("This world shall know pain");
|
||||
}
|
||||
|
||||
if(msg?.message?.status === "PAY_SUCCESS") {
|
||||
paymentWaiting.innerHTML = `
|
||||
<div class="payment-success text-center">
|
||||
<i class="material-icons" style="font-size: 50px; color: #4CAF50;">check_circle</i>
|
||||
<h3 class="m-t-20" style="color: #4CAF50;">Payment Successful!</h3>
|
||||
<p>Amount Received: ${amountToReceive}</p>
|
||||
</div>
|
||||
`;
|
||||
ws.close();
|
||||
|
||||
// fetch('/foodcourt/qrpay/process_payment', {
|
||||
// method: 'POST',
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content,
|
||||
// },
|
||||
// body: JSON.stringify({ sale_id: "SAL-0qg000000671" })
|
||||
// })
|
||||
|
||||
fetch('/foodcourt/qrpay/process_payment', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content,
|
||||
},
|
||||
body: JSON.stringify({ sale_id: "<%= @sale_data.sale_id %>" })
|
||||
}).then((res) => res.json())
|
||||
.then((data) => {
|
||||
if(data.status) {
|
||||
customer_display_view(null, "reload");
|
||||
setTimeout(() => {
|
||||
window.location.href = "/";
|
||||
}, 3000)
|
||||
}else {
|
||||
console.log("error:", data);
|
||||
}
|
||||
}).catch((e) => console.log(e))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
ws.onerror = (e) => {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
function customer_display_view(data, status) {
|
||||
let url = '/foodcourt/customer_view';
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: { data: data, status: status },
|
||||
dataType: "json",
|
||||
success:function(result){
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// cancel order
|
||||
document.querySelector('#cancel-btn').addEventListener('click', function(e) {
|
||||
const data = {
|
||||
sale_id: "<%= @sale_data.sale_id %>",
|
||||
|
||||
43
app/views/foodcourt/qrpay/test_payment.html.erb
Normal file
43
app/views/foodcourt/qrpay/test_payment.html.erb
Normal file
@@ -0,0 +1,43 @@
|
||||
<div id="status">Connecting...</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const ws = new WebSocket("wss://juicecorner-0mo.sx-fc.app/cable")
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log("WS Connected");
|
||||
ws.send(JSON.stringify({
|
||||
command: "subscribe",
|
||||
identifier: JSON.stringify({
|
||||
channel: "TestChannel"
|
||||
})
|
||||
}))
|
||||
document.getElementById('status').textContent = 'Waiting for payment...'
|
||||
}
|
||||
|
||||
ws.onmessage = (e) => {
|
||||
const msg = JSON.parse(e.data)
|
||||
console.log("Received:", msg)
|
||||
|
||||
// Handle subscription confirmation
|
||||
if(msg.type === "confirm_subscription") {
|
||||
console.log("Successfully subscribed!")
|
||||
return
|
||||
}
|
||||
|
||||
// Handle payment success
|
||||
if(msg?.message?.status === "PAY_SUCCESS") {
|
||||
document.getElementById('status').innerHTML = `
|
||||
<h3 style="color: green;">Payment Received!</h3>
|
||||
<p>Amount: ${msg.message.amount} ${msg.message.currency}</p>
|
||||
`
|
||||
ws.close()
|
||||
}
|
||||
}
|
||||
|
||||
ws.onerror = (e) => {
|
||||
console.error("WS Error:", e)
|
||||
document.getElementById('status').textContent = 'Connection failed'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user