Files
sx-fc/app/views/foodcourt/qrpay/init.html.erb
Dev Team 1768345299 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
2025-05-26 11:32:22 +06:30

353 lines
14 KiB
Plaintext

<style>
.processing-indicator {
display: flex;
gap: 6px;
}
.processing-dot {
width: 10px;
height: 10px;
background: #2196F3;
border-radius: 50%;
animation: bounce 1.4s infinite ease-in-out;
}
.processing-dot:nth-child(2) {
animation-delay: 0.2s;
}
.processing-dot:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes bounce {
0%, 80%, 100% {
transform: translateY(0);
}
40% {
transform: translateY(-12px);
}
}
</style>
<div class="container-fluid h-100">
<% if !@print_settings.nil? %>
<% if @print_settings.precision.to_i > 0
precision = @print_settings.precision
else
precision = 0
end
#check delimiter
if @print_settings.delimiter
delimiter = ","
else
delimiter = ""
end
%>
<% end %>
<div class="row clearfix h-100">
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6 d-flex flex-column h-100">
<div class="card h-100" style="margin-bottom: 15px">
<div class="card-header m-l-5 m-r-5">
<div id="order-title">
<div class="row p-l-5 p-r-5">
<div class="col-lg-6 col-md-6 col-sm-6"><strong>Receipt No :</strong> <span id="receipt_no"><%=@sale_data.receipt_no rescue ' '%></span></div>
<div class="col-lg-6 col-md-6 col-sm-6 text-left"><strong>Receipt Date :</strong> <span id="receipt_date"><%=@sale_data.receipt_date.strftime("%d/%m/%Y-%I:%M %p") rescue '-' %></span></div>
</div>
<div class="row p-l-5 p-r-5">
<div class="col-lg-6 col-md-6 col-sm-6"><strong>Table No :</strong> <%=@table_no%></div>
<span class="hidden" id="dining"><%if !@dining.nil?%><%= @dining.id%><%end%></span>
<div class="col-lg-6 col-md-6 col-sm-6 text-left"><strong>Sale ID :</strong> <span id="sale_id"><% if @sale_data %><%=@sale_data.sale_id %><% end %></span></div>
</div>
<div class="row p-l-5 p-r-5">
<div class="col-lg-6 col-md-6 col-sm-6">
<strong>Customer :</strong>
<% if @cashier_type == 'quick_service' || @cashier_type == 'food_court' %>
<button type="button" class="btn bg-info waves-effect" id='customer_name' data-toggle="modal" data-target="#read_modal"><%= @sale_data.customer.name%></button>
<input type="hidden" name="paypar_account_no" id="paypar_account_no" value='<%=@sale_data.customer.paypar_account_no%>' />
<% else %>
<input type="hidden" name="paypar_account_no" id="paypar_account_no" value='<%=@sale_data.customer.paypar_account_no%>' />
<span id="customer_name"><%= @sale_data.customer.name%></span>
<% end %>
<span class="hidden" id="membership_id"><%= @sale_data.customer.membership_id%></span>
<span class="hidden" id="member_discount"><%= @member_discount%></span></div>
<div class="col-lg-6 col-md-6 col-sm-6 text-left"><strong>Checkin Time : </strong> <%if !@checkin_time.nil?%><%= @checkin_time.strftime("%I:%M %p") %>
<%end%></div>
</div>
</div>
</div>
<div class="card-block m-l-5 m-r-5 m-t--10 d-flex flex-column h-100">
<div class="card-title">
<div class="card-text">
<table class="table" id="append-table">
<tr>
<!-- <tr> -->
<th>#</th>
<th class="item-name">Items</th>
<th class="item-attr">QTY</th>
<th class="item-attr">Price</th>
<!-- </tr> -->
</tr>
</table>
</div>
</div>
<div id="foodcourt-slimscroll" class="h-100">
<!-- <div id="table-details" class="card-text" style="min-height:400px; max-height:400px; overflow-x:scroll"> -->
<div id="table-details" class="card-text m-t--10" >
<table class="table summary-items" id="append-table">
<tbody>
<% sub_total = 0
count = 0
%>
<% @sale_data.sale_items.each do |sale_item|
count += 1
%>
<% sub_total += sale_item.price%>
<tr>
<td><%= count %></td>
<td class="item-name"><%=sale_item.product_name%>@<%=number_with_precision( sale_item.unit_price, precision: precision.to_i )%></td>
<td class="item-attr"><%=sale_item.qty%></td>
<td class="item-attr"><%=(number_with_precision(sale_item.price, precision: precision.to_i ))%></td>
</tr>
<%end %>
</tbody>
</table>
</div>
</div>
</div>
<div class="card-footer ">
<table class="table m-t--10 ">
<tfooter>
<tr>
<td class="charges-name"><strong>Sub Total</strong></td>
<td class="item-attr"><strong><span id="sub-total"><%=number_with_precision(sub_total, precision: precision.to_i)%></span></strong></td>
</tr>
<tr>
<%if @sale_data.discount_type == 'member_discount'%>
<td class="charges-name"><strong>Member Discount:</strong></td>
<%else%>
<td class="charges-name"><strong>(Discount)</strong></td>
<%end%>
<td class="item-attr"><strong><span>(<%= number_with_precision(@sale_data.total_discount, precision: precision.to_i ) rescue number_with_precision(0, precision: precision.to_i ) %>)</span></strong></td>
</tr>
<tr>
<td class="charges-name">
<strong>
<% if !@account_arr.empty? %>
Tax
(<% @i = 0
@account_arr.each do |ct| %>
<%=ct.tax_name%>
<% if @account_arr.count != @i+1%>
+ <% @i =+1 %>
<%end%>
<%end %>)
<% else %>
No Tax
<% end %></strong><br>
<%if @changable_tax %>
<% if @current_user.role == 'cashier' %>
<button class="btn btn-link waves-effect bg-info access_modal" data-type = 'change_tax' >Change Tax</button>
<% else %>
<button class="btn btn-link waves-effect bg-info change_tax">Change Tax</button>
<% end %>
<% end %>
</td>
<td class="item-attr"><strong><span id="total_tax"><%= number_with_precision(@sale_data.total_tax, precision: precision.to_i ) rescue number_with_precision(0, precision: precision.to_i )%></span></strong></td>
</tr>
<tr>
<td class="charges-name"><strong>Rounding Adj:</strong></td>
<td class="item-attr"><strong><%= number_with_precision(@sale_data.rounding_adjustment, precision: precision.to_i ) rescue number_with_precision(0, precision: precision.to_i )%></strong></td>
</tr>
<tr>
<td class="charges-name"><strong>Grand Total</strong></td>
<td class="item-attr"><strong><span><%= number_with_precision(@sale_data.grand_total, precision: precision.to_i ) rescue number_with_precision(0, precision: precision.to_i )%></span></strong></td>
</tr>
<%if @balance > 0%>
<tr>
<td class="charges-name"><strong><%= @accountable_type %></strong></td>
<td class="item-attr"><strong><span><%=number_with_precision(@balance, precision: precision.to_i )%></span></strong></td>
</tr>
<% end %>
<% if !@individual_total[0].nil? %>
<tr>
<td class="charges-name">
<strong>Split Bill for <%= @individual_total[0]['total_customer'] %> persons</strong>
</td>
<td></td>
</tr>
<tr>
<td class="charges-name">
<strong>Amount Due (per person)</strong>
</td>
<td class="item-attr"><strong><span><%= number_with_precision(@individual_total[0]['per_person_amount'], precision: precision.to_i )%></span></strong></td>
</tr>
<% end %>
</tfooter>
</table>
</div>
<!-- <div> -->
<!-- <INPUT TYPE="Button" class='btn btn-primary' VALUE="Reprint" onClick="" style='width:120px'/>
<INPUT TYPE="Submit" class='btn btn-primary' VALUE="CANCEL" action="foodcourt/index" style='width:120px'/> -->
<!-- </div> -->
</div>
</div>
<div class="col-lg-5 col-md-5 col-sm-5 col-xs-5 d-flex flex-column h-100" style="padding-right: 10px;">
<div class="card-block">
<div class="payment-waiting text-center" style="height: 400px; display: flex; flex-direction: column; justify-content: center; align-items: center;">
<h3 class="m-t-20" style="color: #555;">Waiting for Customer Payment</h3>
<p class="text-muted">Please ask customer to scan the QR code</p>
<div class="processing-indicator m-t-10">
<div class="processing-dot"></div>
<div class="processing-dot"></div>
<div class="processing-dot"></div>
</div>
</div>
<div class="d-flex">
<button class="btn btn-block btn-default waves-effect" id="cancel-btn">Cancel</button>
</div>
<input type="hidden" name="server_mode" value="<%=ENV["SERVER_MODE"]%>" id="server_mode">
<input type="hidden" name="display_type" id="display_type" value="<%= @display_type%>">
</div>
</div>
</div>
<input type="hidden" id="server_mode" value="<%= ENV["SERVER_MODE"] %>">
</div>
<div class="modal fade" id="voidModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="voidModalLabel">Please Enter Reason for Void</h4>
</div>
<div class="modal-body">
<input type="textarea" name="remark" class="form-control col-md-12 remark" id="remark">
</div>
<div class="modal-footer ">
<div class="row p-r-20">
<div class="col-md-5">
<button type="button" class="btn btn-link p-t-5 p-b-5 bg-red waves-effect " id="void" active="true">VOID</button>
</div>
<div class="col-md-5">
<button type="button" class="btn btn-link p-t-5 p-b-5 bg-blue waves-effect" data-dismiss="modal">CLOSE</button>
</div>
</div>
</div>
</div>
</div>
</div>
<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) %>;
const ws = new WebSocket("wss://juicecorner-0mo.sx-fc.app/cable");
ws.onopen = () => {
console.log("Nagato channel connected");
ws.send(JSON.stringify({
command: "subscribe",
identifier: JSON.stringify({
channel: "TestChannel"
})
}));
}
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 %>",
};
fetch('/foodcourt/qrpay/cancel', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content,
},
body: JSON.stringify(data)
}).then(function(res) {
return res.json();
}).then(function(data) {
if(data.status) {
window.location.href = "/"
}
});
});
});
</script>