Skip to content

Instantly share code, notes, and snippets.

@justpiple
Created March 28, 2025 14:56
QRIS (Quick Response Code Indonesian Standard). Convert Static QRIS to QRIS with nominal information.
export interface QrisSettings {
/** Payment amount (as string number) */
nominal: string;
/** Service fee type: 'p' for percentage, 'r' for fixed value (rupiah) */
feeType?: "p" | "r";
/** Service fee value (as string number) */
feeValue?: string;
}
function padLength(length: number): string {
return length < 10 ? "0" + length : length.toString();
}
/**
* Calculates CRC16 (Cyclic Redundancy Check) from input string
* CRC16 is a 16-bit error-detecting code used to verify data integrity
*/
function calculateCRC16(input: string): string {
let crc = 0xffff;
for (let i = 0; i < input.length; i++) {
crc ^= input.charCodeAt(i) << 8;
for (let j = 0; j < 8; j++) {
crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;
}
}
const hex = (crc & 0xffff).toString(16).toUpperCase();
return hex.padStart(4, "0");
}
function convertToDynamicQRIS(
staticQris: string,
settings: QrisSettings,
): string {
const { nominal, feeType = "p", feeValue = "0" } = settings;
const qris = staticQris.slice(0, -4).replace("010211", "010212");
const [prefix, suffix] = qris.split("5802ID");
const amountData = "54" + padLength(nominal.length) + nominal;
let feeData = "";
if (feeValue && feeValue !== "0") {
feeData =
feeType === "p"
? "55020357" + padLength(feeValue.length) + feeValue
: "55020256" + padLength(feeValue.length) + feeValue;
}
const resultQRIS = `${prefix}${amountData}${feeData}5802ID${suffix}`;
return resultQRIS + calculateCRC16(resultQRIS);
}
export { convertToDynamicQRIS };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment