QR Code Not Appearing on Invoice

Dear Developer,

I am currently experiencing an issue where the QR Code is not appearing on the invoice, despite it being generated and configured correctly within the system.

The invoice is being issued successfully, and the QR Code data appears to be available, however the QR Code image itself is not displayed on the printed invoice or PDF output.

Could you please investigate this issue and advise on the required steps to resolve it?

The invoice is CLEARED and the Base64 QR Code is available within the invoice form. However, the /api4/view-v1 API does not return the QR Code image field for newly generated invoices.

Older invoices still return the QR Code image correctly, and the current theme displays it without any issues.

Could you please investigate why the QR Code image is no longer being generated or saved into the “QR Code” Image Custom Field after invoice clearance in the latest version?

As a result, the QR Code does not appear on newly issued invoices, while it continues to appear correctly on older invoices. Thank you for your assistance.

/api4/view-v1 works fine on my side.

 "footers": [],
  "custom_fields": [
    {
      "key": "d2e9265a-460e-4a06-83f9-29a523a4d516",
      "label": "QR Code",
      "text": null,
      "image": {
        "url": "/image?ogYKMFphdGNhVGVzdA&key=019e8360-908a-7311-af3a-eb0a1b00e3c3",
        "width": 160,
        "height": 160
      },
      "displayAtTheTop": false,
      "emphasis": false,
      "link": null,
      "fields": null
    }
  ],
  "emphasis": {
    "text": "Overdue",
    "positive": false,
    "negative": true
  }

try these custom themes

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Invoice Document</title>
    <style>
        /* Print & reset styles */
        @page {
            size: A4;
            margin: 0mm;
        }

        :root {
            --bg: #f5f5f5;
            --paper: #ffffff;
            --border: #e5e5e5;
            --black: #000000;
        }

        body {
            background-color: var(--bg);
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            font-size: 0.875rem;
            line-height: 1.4rem;
            font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
        }

        main {
            background-color: var(--paper);
            margin: 6mm;
            border: 1px solid var(--border);
            border-radius: 5px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
            padding: 2rem;
            max-width: 210mm;
            width: 100%;
            box-sizing: border-box;
        }

        main > *:first-child {
            margin-top: 0;
            padding-top: 0;
        }

        @media print {
            body {
                background: none;
                margin: 0;
                padding: 0;
                display: block;
            }
            main {
                margin: 0;
                padding: 2rem;
                border: none;
                box-shadow: none;
                border-radius: 0;
                max-width: none;
                width: auto;
            }
        }

        address {
            font-style: normal;
            line-height: 1.4em;
        }

        /* Table styles */
        table {
            font-size: 14px;
            width: 100%;
            border-collapse: collapse;
        }

        #table-headers th {
            font-weight: bold;
            padding: 5px 10px;
            border: 1px solid var(--black);
            text-align: start;
        }

        #table-rows td {
            padding: 5px 5px;
            text-align: start;
            vertical-align: top;
        }

        #table-rows tr.row td {
            border-inline-start: 1px solid var(--black);
            border-inline-end: 1px solid var(--black);
        }

        #table-rows tr.last-row td {
            padding-bottom: 30px;
            border-bottom: 1px solid var(--black);
        }

        #table-rows tr.column-total td {
            font-weight: bold;
            border: 1px solid var(--black);
            white-space: nowrap;
            text-align: right;
        }

        #table-rows tr.total td {
            white-space: nowrap;
        }

        #table-rows tr.total td:first-child {
            text-align: end;
        }

        #table-rows tr.total td:last-child {
            border: 1px solid var(--black);
            text-align: right;
        }

        .business-logo-img {
            max-height: 75px;
            max-width: 150px;
            display: inline;
        }

        .separator-line {
            width: 1px;
            border-inline-start: 1px solid #000;
            align-self: stretch;
        }

        .section-flex {
            display: flex;
            margin-bottom: 20px;
            width: 100%;
            align-items: flex-start;
            gap: 20px;
        }

        .recipient-address {
            flex: 1;
        }

        /* Perbaikan: fields-right agar sejajar */
        .fields-right {
            flex: 1;
            text-align: end;
            margin: 0;
            padding: 0;
        }
        .fields-right dl {
            margin: 0;
            line-height: 1.4em; /* sama dengan address */
        }
        .fields-right dt {
            margin: 0;
            padding: 0;
            font-weight: bold;
            line-height: inherit;
        }
        .fields-right dd {
            margin: 0 0 8px 0;
            padding: 0;
            line-height: inherit;
        }
        .fields-right dd:last-child {
            margin-bottom: 0;
        }

        .business-address {
            white-space: nowrap;
        }

        .flex-between {
            display: flex;
            justify-content: space-between;
            align-items: flex-start;
        }

        .footer-text {
            margin-top: 20px;
        }

        .status-message {
            margin-top: 40px;
            text-align: center;
        }

        .status-span {
            border-width: 5px;
            border-style: solid;
            padding: 10px;
            font-size: 20px;
            text-transform: uppercase;
        }

        .status-positive {
            color: green;
            border-color: green;
        }

        .status-negative {
            color: red;
            border-color: red;
        }

        .amount-words {
            margin: 20px 0;
        }
        .amount-words div:first-child {
            font-weight: bold;
        }
    </style>
</head>
<body>
<main>
    <table style="width: 100%;">
        <thead>
        <tr>
            <td>
                <div class="flex-between">
                    <h1 id="title"></h1>
                    <div id="business-logo" style="text-align: end;"></div>
                </div>
                <div class="section-flex">
                    <address id="recipient-info" class="recipient-address"></address>
                    <div id="fields" class="fields-right"></div>
                    <div aria-hidden="true" class="separator-line"></div>
                    <address id="business-info" class="business-address"></address>
                </div>
                <p style="font-weight: bold; font-size: 14px; margin-bottom: 20px" id="description"></p>
            </td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td>
                <table style="border-collapse: collapse; width: 100%;">
                    <thead id="table-headers"></thead>
                    <tbody id="table-rows"></tbody>
                </table>
                <div id="amount-in-words" class="amount-words"></div>
                <div id="qrcode" style="margin-bottom: 20px;"></div>
                <div id="custom-fields"></div>
                <div id="footers"></div>
                <div id="status" class="status-message"></div>
            </td>
        </tr>
        </tbody>
    </table>
</main>

<script>
    // --------------------------------------------------------------
    // Helper: Convert number to words (English)
    // --------------------------------------------------------------
    function numberToWordsEn(num) {
        if (typeof num !== 'number' || !isFinite(num)) return '';

        function spellOutInteger(n) {
            if (n === 0) return 'zero';
            const ones = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine',
                          'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen',
                          'seventeen', 'eighteen', 'nineteen'];
            const tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'];
            const scales = ['', 'thousand', 'million', 'billion', 'trillion', 'quadrillion'];
            const under100 = (x) => x < 20 ? ones[x] : tens[Math.floor(x / 10)] + (x % 10 ? '-' + ones[x % 10] : '');
            const under1000 = (x) => x < 100 ? under100(x) : ones[Math.floor(x / 100)] + ' hundred' + (x % 100 ? ' ' + under100(x % 100) : '');
            const parts = [];
            let scale = 0;
            while (n > 0 && scale < scales.length) {
                const chunk = n % 1000;
                if (chunk > 0) parts.unshift(under1000(chunk) + (scales[scale] ? ' ' + scales[scale] : ''));
                n = Math.floor(n / 1000);
                scale++;
            }
            return parts.join(' ');
        }

        const negative = num < 0;
        const abs = Math.abs(num);
        const intPart = Math.floor(abs);
        const fracPart = Math.round((abs - intPart) * 100);
        let words = spellOutInteger(intPart);
        if (fracPart > 0) words += ' and ' + (fracPart < 10 ? '0' : '') + fracPart + '/100';
        if (negative) words = 'minus ' + words;
        return words.charAt(0).toUpperCase() + words.slice(1);
    }

    // --------------------------------------------------------------
    // Helper: Convert number to words (Arabic)
    // --------------------------------------------------------------
    function numberToWordsAr(num) {
        if (typeof num !== 'number' || !isFinite(num)) return '';

        function spellOutInteger(n) {
            if (n === 0) return 'صفر';
            const ones = ['', 'واحد', 'اثنان', 'ثلاثة', 'أربعة', 'خمسة', 'ستة', 'سبعة', 'ثمانية', 'تسعة'];
            const teens = ['عشرة', 'أحد عشر', 'إثنا عشر', 'ثلاثة عشر', 'أربعة عشر', 'خمسة عشر',
                           'ستة عشر', 'سبعة عشر', 'ثمانية عشر', 'تسعة عشر'];
            const tens = { 2: 'عشرون', 3: 'ثلاثون', 4: 'أربعون', 5: 'خمسون',
                           6: 'ستون', 7: 'سبعون', 8: 'ثمانون', 9: 'تسعون' };
            const hundreds = { 1: 'مائة', 2: 'مائتان', 3: 'ثلاثمائة', 4: 'أربعمائة',
                               5: 'خمسمائة', 6: 'ستمائة', 7: 'سبعمائة', 8: 'ثمانمائة', 9: 'تسعمائة' };
            function under100(x) {
                if (x === 0) return '';
                if (x < 10) return ones[x];
                if (x < 20) return teens[x - 10];
                const t = Math.floor(x / 10), o = x % 10;
                return o === 0 ? tens[t] : ones[o] + ' و' + tens[t];
            }
            function under1000(x) {
                if (x < 100) return under100(x);
                const h = Math.floor(x / 100), rest = x % 100;
                return rest === 0 ? hundreds[h] : hundreds[h] + ' و' + under100(rest);
            }
            function unitForm(count, singular, dual, plural) {
                if (count === 1) return singular;
                if (count === 2) return dual;
                if (count >= 3 && count <= 10) return under100(count) + ' ' + plural;
                return under1000(count) + ' ' + singular;
            }
            const parts = [];
            const tr = Math.floor(n / 1000000000000); n = n % 1000000000000;
            if (tr > 0) parts.push(unitForm(tr, 'تريليون', 'تريليونان', 'تريليونات'));
            const bn = Math.floor(n / 1000000000); n = n % 1000000000;
            if (bn > 0) parts.push(unitForm(bn, 'مليار', 'ملياران', 'ملايير'));
            const mn = Math.floor(n / 1000000); n = n % 1000000;
            if (mn > 0) parts.push(unitForm(mn, 'مليون', 'مليونان', 'ملايين'));
            const th = Math.floor(n / 1000); n = n % 1000;
            if (th > 0) parts.push(unitForm(th, 'ألف', 'ألفان', 'آلاف'));
            if (n > 0) parts.push(under1000(n));
            return parts.map((p, i) => i === 0 ? p : 'و' + p).join(' ');
        }

        const negative = num < 0;
        const abs = Math.abs(num);
        const intPart = Math.floor(abs);
        const fracPart = Math.round((abs - intPart) * 100);
        let words = spellOutInteger(intPart);
        if (fracPart > 0) words += ' و' + (fracPart < 10 ? '0' : '') + fracPart + '/100';
        if (negative) words = 'ناقص ' + words;
        return words;
    }

    // --------------------------------------------------------------
    // Utility: Transform API data
    // --------------------------------------------------------------
    function transformApiData(originalData) {
        const data = JSON.parse(JSON.stringify(originalData));
        const standardKeys = ['InvoiceDate', 'DueDate', 'InvoiceNumber'];
        const standardFields = [];
        const customFields = [];

        (data.fields || []).forEach(field => {
            if (standardKeys.includes(field.key)) standardFields.push(field);
            else customFields.push(field);
        });

        data.fields = standardFields;
        data.custom_fields = customFields;

        if (data.totals && !data.table.totals) data.table.totals = data.totals;
        if (data.table.rows) data.table.rows = data.table.rows.filter(row => !row.isTotalRow);
        if (!data.description && data.table.description) data.description = data.table.description;
        if (data.status && !data.emphasis) {
            data.emphasis = {
                text: data.status.text,
                positive: data.status.tone === 'positive',
                negative: data.status.tone === 'negative'
            };
        }
        if (!data.table.columns.some(col => col.sumText)) {
            data.table.columns.forEach(col => { col.sumText = ''; });
        }
        return data;
    }

    // --------------------------------------------------------------
    // Apply column style
    // --------------------------------------------------------------
    function applyColumnStyle(element, column, isLastColumn) {
        element.style.textAlign = column.align || 'start';
        if (column.shrinkToFit) {
            element.style.whiteSpace = 'nowrap';
            element.style.width = '1px';
            element.style.minWidth = '';
            return;
        }
        if (column.nowrap) {
            element.style.whiteSpace = 'normal';
            if (isLastColumn) {
                element.style.minWidth = '60px';
                element.style.width = 'auto';
            } else {
                element.style.width = 'auto';
                element.style.minWidth = '';
            }
        } else {
            element.style.whiteSpace = 'normal';
            element.style.width = 'auto';
            element.style.minWidth = '';
        }
    }

    // --------------------------------------------------------------
    // Main render function
    // --------------------------------------------------------------
    function renderDocument(data) {
        console.log(JSON.stringify(data,null,2));
        document.documentElement.dir = data.direction || 'ltr';

        const titleParts = [data?.business?.name, data?.title, data?.reference].filter(Boolean);
        document.title = titleParts.join(' - ');

        document.getElementById('title').innerHTML = data.title || 'No title';
        document.getElementById('description').innerHTML = data.description || '';

        // Business logo
        const businessLogoDiv = document.getElementById('business-logo');
        businessLogoDiv.innerHTML = '';
        if (data.business.logo) {
            const logoImg = document.createElement('img');
            logoImg.src = data.business.logo;
            logoImg.classList.add('business-logo-img');
            businessLogoDiv.appendChild(logoImg);
        }

        // Business info
        const business = data.business || {};
        const businessInfoElem = document.getElementById('business-info');
        businessInfoElem.innerHTML = `<strong>${business.name || ''}</strong><br>${business.address ? business.address.replace(/\n/g, '<br>') : ''}`;

        // Recipient info
        const recipient = data.recipient || {};
        let recipientAddress = recipient.address || '';
        recipientAddress = recipientAddress.replace(/\n/g, '<br>');
        const recipientElem = document.getElementById('recipient-info');
        recipientElem.innerHTML = `<strong>${recipient.name || ''}</strong><br>${recipientAddress}`;

        // ----------------------------------------------------------
        // Standard fields (gunakan dt/dd, tampilkan 2 baris per field)
        // ----------------------------------------------------------
        const fieldsContainer = document.getElementById('fields');
        fieldsContainer.innerHTML = '';
        const dl = document.createElement('dl');
        (data.fields || []).forEach(field => {
            const dt = document.createElement('dt');
            dt.innerHTML = field.label;
            const dd = document.createElement('dd');
            dd.innerHTML = field.text;
            dl.appendChild(dt);
            dl.appendChild(dd);
        });
        fieldsContainer.appendChild(dl);

        const columns = data.table.columns || [];
        const lastColumnIndex = columns.length - 1;

        // Table headers
        const headersRow = document.getElementById('table-headers');
        headersRow.innerHTML = '';
        columns.forEach((column, idx) => {
            const th = document.createElement('th');
            th.innerHTML = column.label;
            applyColumnStyle(th, column, idx === lastColumnIndex);
            headersRow.appendChild(th);
        });

        // Table rows
        const tableBody = document.getElementById('table-rows');
        tableBody.innerHTML = '';
        (data.table.rows || []).forEach(row => {
            const tr = document.createElement('tr');
            tr.className = 'row';
            row.cells.forEach((cell, idx) => {
                const column = columns[idx];
                const td = document.createElement('td');
                td.innerHTML = (cell.text || '').split('\n').join('<br/>');
                applyColumnStyle(td, column, idx === lastColumnIndex);
                tr.appendChild(td);
            });
            tableBody.appendChild(tr);
        });

        const allRows = tableBody.querySelectorAll('tr.row');
        if (allRows.length > 0) allRows[allRows.length - 1].classList.add('last-row');

        // Column totals row
        const totalRow = document.createElement('tr');
        totalRow.classList.add('column-total');
        columns.forEach(column => {
            const td = document.createElement('td');
            td.style.textAlign = column.align;
            if (column.label !== 'No.') td.innerHTML = column.sumText;
            totalRow.appendChild(td);
        });
        if (totalRow.innerText.trim() !== '') tableBody.appendChild(totalRow);

        // Additional totals
        (data.table.totals || []).forEach(total => {
            const tr = document.createElement('tr');
            tr.className = 'total';
            const labelCell = document.createElement('td');
            labelCell.innerHTML = total.label;
            labelCell.colSpan = columns.length - 1;
            const valueCell = document.createElement('td');
            valueCell.innerHTML = total.text;
            valueCell.id = total.key;
            if (total.class) valueCell.classList.add(total.class);
            valueCell.dataset.value = total.number;
            if (total.emphasis) {
                labelCell.style.fontWeight = 'bold';
                valueCell.style.fontWeight = 'bold';
            }
            tr.appendChild(labelCell);
            tr.appendChild(valueCell);
            tableBody.appendChild(tr);
        });

        // Amount in Words
        const amountWordsDiv = document.getElementById('amount-in-words');
        amountWordsDiv.innerHTML = '';
        let totalAmount = null;
        if (data.table.totals) {
            const totalEntry = data.table.totals.find(t => t.key === 'Total' || t.label === 'الإجمالي' || t.label === 'Total');
            if (totalEntry && typeof totalEntry.number === 'number') totalAmount = totalEntry.number;
        }
        if (totalAmount === null && data.table.totals) {
            const lastEmphasized = data.table.totals.filter(t => t.emphasis).pop();
            if (lastEmphasized && typeof lastEmphasized.number === 'number') totalAmount = lastEmphasized.number;
        }
        if (totalAmount !== null && !isNaN(totalAmount)) {
            const isArabic = data.language === 'ar' || data.direction === 'rtl';
            if (isArabic) {
                amountWordsDiv.innerHTML = `<div><strong>المبلغ بالكلمات</strong></div><div>${numberToWordsAr(totalAmount)}</div>`;
            } else {
                amountWordsDiv.innerHTML = `<div><strong>Amount in Words</strong></div><div>${numberToWordsEn(totalAmount)}</div>`;
            }
        }

        // Custom fields & QR code
        const customFieldsContainer = document.getElementById('custom-fields');
        const qrContainer = document.getElementById('qrcode');
        customFieldsContainer.innerHTML = '';
        qrContainer.innerHTML = '';
        const qrKey = 'd2e9265a-460e-4a06-83f9-29a523a4d516';

        (data.custom_fields || []).forEach(field => {
            if (field.key === qrKey && field.image?.url) {
                const div = document.createElement('div');
                const label = field.label || 'QR Code';
                div.innerHTML = `<strong>${label}</strong><br><img src="${field.image.url}" alt="QR Code" width="160" height="160">`;
                customFieldsContainer.appendChild(div);
            }
            else if (field.displayAtTheTop && field.key !== qrKey) {
                // Ini kemungkinan tidak terpakai karena sudah di standard fields
                // Tapi kita tetap proses
                const dt = document.createElement('dt');
                dt.innerHTML = field.label;
                const dd = document.createElement('dd');
                dd.innerHTML = field.text;
                fieldsContainer.appendChild(dt);
                fieldsContainer.appendChild(dd);
            }
            else if (field.key !== qrKey) {
                const div = document.createElement('div');
                div.innerHTML = `<strong>${field.label || ''}</strong><br>${(field.text || '').split('\n').join('<br>')}<br><br>`;
                customFieldsContainer.appendChild(div);
            }
        });

        // Footers
        const footersContainer = document.getElementById('footers');
        footersContainer.innerHTML = '';
        (data.footers || []).forEach(footerText => {
            const div = document.createElement('div');
            div.className = 'footer-text';
            div.innerHTML = footerText;
            footersContainer.appendChild(div);
            div.querySelectorAll('script').forEach(oldScript => {
                const newScript = document.createElement('script');
                for (const attr of oldScript.attributes) newScript.setAttribute(attr.name, attr.value);
                if (oldScript.textContent) newScript.textContent = oldScript.textContent;
                oldScript.parentNode.replaceChild(newScript, oldScript);
            });
        });

        // Status
        const statusDiv = document.getElementById('status');
        statusDiv.innerHTML = '';
        if (data.emphasis?.text) {
            const statusSpan = document.createElement('span');
            statusSpan.classList.add('status-span');
            if (data.emphasis.positive) statusSpan.classList.add('status-positive');
            if (data.emphasis.negative) statusSpan.classList.add('status-negative');
            statusSpan.innerHTML = data.emphasis.text;
            statusDiv.appendChild(statusSpan);
        }
    }

    // --------------------------------------------------------------
    // Fetch data and render
    // --------------------------------------------------------------
    window.addEventListener('load', () => {
        const apiUrl = '/api4/view-v1' + window.location.search;
        fetch(apiUrl, { headers: { 'Accept': 'application/json' }, credentials: 'same-origin' })
            .then(response => response.json())
            .then(data => renderDocument(transformApiData(data)))
            .catch(error => {
                console.error('Failed to load invoice data:', error);
                document.body.innerHTML += '<div style="color:red; padding:20px;">Failed to load invoice. Please try again.</div>';
            });
    });
</script>
</body>
</html>

The custom theme you provided still does not display the QR Code. I tested it on a newly cleared invoice, but the QR Code does not appear.

In the invoice form, the Base64 QRCode field contains a value, however the QR Code image field is empty.

Old invoices display the QR Code correctly because the image was successfully saved into the QR Code Image Custom Field. New invoices do not display the QR Code because no image is being saved in that field.

Could you please check why the extension is no longer converting and saving the Base64 QRCode into the QR Code Image Custom Field for newly generated invoices?

Thank you for your support.

Could you share information about your Manager Edition and Version?


I have tested the Cloud Edition as well as the Desktop Edition (version 26.5.29.3635). In both cases, the extension is functioning normally without issues.

26.5.29.3635 cloud edition

What happens if you press the ZATCA eInvoice button again on the invoice in question? Does it display the QR code?

  • For older invoices, the QR code is generated from the Base64 QRCode Text Customfields.
  • For new invoices, the QR code should already be stored as an image in the QRCode Image Customfields.

Alternatively, you can check the placement of the Base64 QRCode Text Customfields. The placement should be set to appear on both Sales Invoice and Credit Note.

Thank you for your support.

After pressing the ZATCA eInvoice button again and updating the QR Code, the QR Code appeared correctly on the invoice.

Thank you again for your assistance and support.

@Mabaega @lubos Phase I QR showing 0.00 SAR — URGENT

After extension update v26.05.31.0002, Phase I QR code generates but Invoice Total and VAT both show 0.00 SAR when scanned. Seller name and TRN are correct.

  • Version: 26.5.29.3635 Cloud Edition
  • Domain: dad.manager.io
  • Same issue reported by mam970 and Ibrahim_Alazman — still no fix

This is a ZATCA legal compliance issue. Every invoice we issue is non-compliant until this is fixed. Please prioritize urgently and advise on timeline.

This issue has been fixed.
try this method.

@Mabaega - Issue still NOT fixed. Two problems:

Problem 1 - New Invoices: Just tested on a brand new invoice. QR code generates but still shows 0.00 SAR for Invoice Total and VAT when scanned. The ZATCA page shows correct amounts but the QR encodes them as zero.

Problem 2 - Old Invoices: Cannot regenerate QR on old invoices at all. When clicking the ZATCA button it shows “QR Already Exists” with no option to update or regenerate. The QR Code image field inside the invoice edit form is not clickable and not clearable - completely read-only with no delete option.

So we are stuck:

  • New invoices → QR generates with 0.00
  • Old invoices → Cannot regenerate at all

Version: 26.5.29.3635 Cloud Edition

Please advise urgently. This is a ZATCA legal compliance issue affecting every invoice we issue.

Could you share the edit screen of the problematic invoice? I’m still confused whether you are working in Phase I or Phase II

@Mabaega — We are using Phase I only. Here is exactly what happens:

Step 1 — Open any Sales Invoice and click “QR Code Generator” button

Step 2 — The ZATCA Phase I page opens and shows correct data:

  • Seller Name :white_check_mark:
  • TRN :white_check_mark:
  • Invoice Total: 325.45 :white_check_mark:
  • VAT Total: 42.45 :white_check_mark:

Step 3 — When we scan the generated QR code with phone it shows:

  • Invoice Total: 0.00 SAR :cross_mark:
  • VAT Total: 0.00 SAR :cross_mark:

This happens on BOTH old and new invoices:

  • New invoice → Generate fresh QR → scan → still 0.00 SAR :cross_mark:
  • Old invoice → Cannot regenerate at all because QR Code field is read-only with no delete or clear option :cross_mark:

So the bug is in two places:

  1. The QR encoding is writing 0.00 instead of actual amounts — affects all new invoices
  2. Old invoices cannot be fixed because there is no way to clear the existing QR

We are NOT using Phase II. This is purely a Phase I QR encoding bug.

Please see attached screenshots and advise urgently.

Version: 26.5.29.3635 Cloud Edition

Endpoint: zatcaextension.azurewebsites.net

You can try again now.
It should be possible to regenerate the QR Code.

The same thing is happening with me too

The Seller name And TRN is showing perfectly but the invoice amount is 0.00 SAR and VAT Total is also 0.00 SAR

Use Extensions from the top dashboard and click on Zatca E-Invoice and install the extension on your specific business it will work again

@Farooq_Ahmed — Thank you so much brother! Your solution worked perfectly. For anyone else facing this issue - just go to Extensions from the top dashboard, click on ZATCA eInvoice and reinstall it on your business. QR code now shows correct amounts. Jazak ALLAH Khair

Currently, there is no dedicated field to enter the Tax Registration Number (TRN) and no option to select the Country within the Business Profile settings. As a result, the ZATCA e-Invoice extension is unable to read the TRN automatically, which prevents the system from generating the required QR code on invoices.

The TRN is currently being written manually inside the Address text field as plain text, which is not recognized by the system.

Please advise on how to resolve this, or add the missing fields (TRN and Country) to the Business Profile page as soon as possible.

Just click Zatca E-Invoice Extension, enter manually your business TRN, and click Generate QR Code.

Why doesn’t it appear like this