<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>PromptPay QR Generator</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body {
font-family: sans-serif;
background: #f2f2f2;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.container {
background: white;
padding: 2rem;
border-radius: 16px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
text-align: center;
max-width: 360px;
width: 100%;
}
h1 {
font-size: 1.4rem;
margin-bottom: 1rem;
color: #333;
}
input, button {
width: 100%;
padding: 10px;
margin-bottom: 1rem;
font-size: 1rem;
border-radius: 8px;
border: 1px solid #ccc;
}
button {
background-color: #007bff;
color: white;
border: none;
cursor: pointer;
}
#qrcode {
margin-top: 1rem;
}
</style>
</head>
<body>
<div class="container">
<h1>PromptPay QR</h1>
<input type="text" id="recipient" placeholder="Phone (08xxxxxxxx) or Thai ID" />
<input type="number" id="amount" placeholder="Amount (e.g. 999.00)" />
<input type="text" id="merchant" placeholder="Your Name (A-Z only)" />
<button onclick="generateQR()">Generate QR</button>
<div id="qrcode"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcode-generator/1.4.4/qrcode.min.js"></script>
<script>
function formatTLV(id, value) {
const length = value.length.toString().padStart(2, '0');
return id + length + value;
}
function formatPromptPayQR(recipient, amount, merchantName = 'PromptPay') {
recipient = recipient.replace(/[^0-9]/g, '');
if (recipient.length === 10 && recipient.startsWith('0')) {
recipient = '0066' + recipient.substring(1);
}
let payload = '';
payload += formatTLV('00', '01'); // Format Indicator
payload += formatTLV('01', '11'); // Dynamic QR
let merchantAccount = '';
merchantAccount += formatTLV('00', 'A000000677010111');
merchantAccount += formatTLV('01', recipient);
payload += formatTLV('29', merchantAccount);
payload += formatTLV('52', '0000');
payload += formatTLV('53', '764');
if (amount && parseFloat(amount) > 0) {
const fixedAmount = parseFloat(amount).toFixed(2);
payload += formatTLV('54', fixedAmount);
}
payload += formatTLV('58', 'TH');
// ใส่ชื่อผู้รับ (ต้องเป็นตัวอักษร A-Z เท่านั้น)
merchantName = merchantName.replace(/[^A-Za-z0-9 ]/g, '').substring(0, 25);
payload += formatTLV('59', merchantName || 'PromptPay');
payload += formatTLV('60', 'Bangkok');
payload += '6304';
const crc = crc16(payload);
return payload + crc.toUpperCase();
}
function crc16(s) {
let crc = 0xFFFF;
for (let i = 0; i < s.length; i++) {
crc ^= s.charCodeAt(i) << 8;
for (let j = 0; j < 8; j++) {
if ((crc & 0x8000) !== 0) {
crc = (crc << 1) ^ 0x1021;
} else {
crc <<= 1;
}
crc &= 0xffff;
}
}
return crc.toString(16).padStart(4, '0');
}
function generateQR() {
const recipient = document.getElementById('recipient').value.trim();
const amount = document.getElementById('amount').value.trim();
const merchant = document.getElementById('merchant').value.trim();
if (!recipient) {
alert("Please enter a phone number or Thai ID.");
return;
}
const payload = formatPromptPayQR(recipient, amount, merchant);
const qr = qrcode(0, 'M');
qr.addData(payload);
qr.make();
document.getElementById('qrcode').innerHTML = qr.createImgTag(6, 8);
}
</script>
</body>
</html>