QrCode Without DateTime when using GenerateEInvoiceQRCode Method

When trying to use GenerateEInvoiceQRCode method to return QR Code from cleared Invoices, the QRcode appear without DateTime.

and after tracing the SDK Code(File Version 3.3.3.0), I found that the object GeneratedSignature is always become null by using GenerateEInvoiceQRCode method.
please review the attachment image file

Please advise if i missing something in my code.

Dear @ehabshqair ,

Thank you for reaching out,

I would like to inform you that the SDK functions are working correctly. However, to ensure optimal performance, I recommend that you use the latest version of the SDK.

If the issue persists after updating the SDK, we advise you to review your solution implementation for any potential inconsistencies.

Thanks,

Dear Zatca Support,
The below xml represents B2B invoice include the QRCode generated by zatca

<?xml version="1.0" encoding="UTF-8"?> urn:oasis:names:specification:ubl:dsig:enveloped:xades urn:oasis:names:specification:ubl:signature:1 urn:oasis:names:specification:ubl:signature:Invoice not(//ancestor-or-self::ext:UBLExtensions) not(//ancestor-or-self::cac:Signature) not(//ancestor-or-self::cac:AdditionalDocumentReference[cbc:ID='QR']) YaWEmTRRbnQ8KexbJ9MnpeK4OzwJjhcjBj9xZGd0Lro= NGUzMDMyNTA1NjJjOTNhNmRmMmFmZWM0NjQ1YjZlYzk4YzA0NmQwOTE4N2Q2YzcyNGIzYzJlYTUyYzQxOTc3NQ== MEQCIGf1tqSk3ye4aR0G9cvGGGr0Yi1xc1Hs/SwqOiDPpg9YAiBfIldoYTelc2kpCJnTW4EaI1z0DHH91EqXUZ2nfrSxeQ== MIIEOTCCA9+gAwIBAgITYwAAMNoaXxj6jHhzdQABAAAw2jAKBggqhkjOPQQDAjBiMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxEzARBgoJkiaJk/IsZAEZFgNnb3YxFzAVBgoJkiaJk/IsZAEZFgdleHRnYXp0MRswGQYDVQQDExJQRVpFSU5WT0lDRVNDQTEtQ0EwHhcNMjQwOTMwMDcxNzU5WhcNMjYwOTMwMDcyNzU5WjCBgTELMAkGA1UEBhMCU0ExHDAaBgNVBAoTE0Zhd2FsIEphcmF0IEFsYWZyYWgxNDAyBgNVBAsMK0Zvb2RzaW58fEZhd2FsYWZyYWh8fDEwMDAwMDA3NzF8fDEwMDAwMDA3NzExHjAcBgNVBAMTFVBSRVpBVENBLUNvZGUtU2lnbmluZzBWMBAGByqGSM49AgEGBSuBBAAKA0IABFJKd81aRsP+BWDberW2bMbL/M3NU8b5IfxLEM9LFYcdkm9XCajYUXOAa6+wV3xBKhFw5qLpW0hOfhfiM5RMOdqjggJVMIICUTCBpwYDVR0RBIGfMIGcpIGZMIGWMUIwQAYDVQQEDDkxLVRTVHwyLVRTVHwzLUZvb2RzaW58fEZhd2FsYWZyYWh8fDEwMDAwMDA3NzF8fDEwMDAwMDA3NzExHzAdBgoJkiaJk/IsZAEBDA8zMDAwMjI3NDY2MDAwMDMxDTALBgNVBAwMBDExMDAxDDAKBgNVBBoMA0tTQTESMBAGA1UEDwwJUmVzdHVyYW50MB0GA1UdDgQWBBRyR98tBzC07eYzcX3vRRGi4r8hgTAfBgNVHSMEGDAWgBSqWDiDqZYlTepUermUB+NXUPg76DCBzgYIKwYBBQUHAQEEgcEwgb4wgbsGCCsGAQUFBzAChoGubGRhcDovLy9DTj1QRVpFSU5WT0lDRVNDQTEtQ0EsQ049QUlBLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9ZXh0emF0Y2EsREM9Z292LERDPWxvY2FsP2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MA4GA1UdDwEB/wQEAwIHgDA8BgkrBgEEAYI3FQcELzAtBiUrBgEEAYI3FQiBhqgdhND7EobtnSSHzvsZ08BVZoGc2C2D5cVdAgFkAgEQMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDAzAnBgkrBgEEAYI3FQoEGjAYMAoGCCsGAQUFBwMCMAoGCCsGAQUFBwMDMAoGCCqGSM49BAMCA0gAMEUCIFvxMLtOVfup82ZTKX3fmrb4olZiJp1uM5IcbryOtbQ1AiEAsDKTdV0E9BLsMjarqP55vyZYWtdqyC7GMI+uJjAl0gQ= 2024-10-24T09:48:39 NWI1MGM0OWE5MWEwYzg0ODBhNDI2MTZkYzZlNjAzMTVmMDVmZTIwMWE5ODVmOGYwZTM3NmJhY2RiNzUyMjY4YQ== CN=PEZEINVOICESCA1-CA, DC=extgazt, DC=gov, DC=local 2207773839589931080904259273790054327006539994 reporting:1.02024/01/01125a9619d5e-ed92-4942-858e-8584974904222024-01-0116:41:16388SARSARICV9726PIHseyoOEfl33OiIb9Ufqg+bvf8k8LzSzNQ84sdq5FMJ58= QR ASJBbC1EdXJyYSBhbmQgQWwtU3VsdGFuIENvbXBhbnkgTHRkAg8zMDAwMjI3NDY2MDAwMDMDEzIwMjQtMDEtMDFUMTY6NDE6MTYEBDUuNTIFBDAuNzIGLFlhV0VtVFJSYm5ROEtleGJKOU1ucGVLNE96d0pqaGNqQmo5eFpHZDBMcm89B2BNRVFDSUdmMXRxU2szeWU0YVIwRzljdkdHR3IwWWkxeGMxSHMvU3dxT2lEUHBnOVlBaUJmSWxkb1lUZWxjMmtwQ0puVFc0RWFJMXowREhIOTFFcVhVWjJuZnJTeGVRPT0IWDBWMBAGByqGSM49AgEGBSuBBAAKA0IABFJKd81aRsP+BWDberW2bMbL/M3NU8b5IfxLEM9LFYcdkm9XCajYUXOAa6+wV3xBKhFw5qLpW0hOfhfiM5RMOdo= urn:oasis:names:specification:ubl:signature:Invoice urn:oasis:names:specification:ubl:dsig:enveloped:xades 123456StreetName00002223CitySubdivisionNameCityName12345SA300022746600003VATAl-Durra and Al-Sultan Company Ltd311732679400003StreetName00002223CitySubdivisionNameCityName12345SA3117326794000032024-01-010.720.724.800.72S15.00VAT4.804.805.520.000.005.5214.004.800.725.52item name1S15.00VAT1.200000

while trying to use this method GenerateEInvoiceQRCode to get QRCode from the above xml , the QRCode not include the Issue DateTime, the QRCode string show as below genereted by GenerateEInvoiceQRCode

“ASJBbC1EdXJyYSBhbmQgQWwtU3VsdGFuIENvbXBhbnkgTHRkAg8zMDAwMjI3NDY2MDAwMDMDAAQENS41MgUEMC43MgYsWWFXRW1UUlJiblE4S2V4Yko5TW5wZUs0T3p3SmpoY2pCajl4WkdkMExybz0HYE1FUUNJR2YxdHFTazN5ZTRhUjBHOWN2R0dHcjBZaTF4YzFIcy9Td3FPaURQcGc5WUFpQmZJbGRvWVRlbGMya3BDSm5UVzRFYUkxejBESEg5MUVxWFVaMm5mclN4ZVE9PQhYMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEUkp3zVpGw/4FYNt6tbZsxsv8zc1Txvkh/EsQz0sVhx2Sb1cJqNhRc4Brr7BXfEEqEXDmoulbSE5+F+IzlEw52g==”

I attached an image about my code using SDK File Version 3.3.3.0 (last version for .Net framework)

So why the QR code embedded inside the XML file does not match the one generated by the GenerateEInvoiceQRCode method. Specifically, when we extract the QR code from the XML and compare it to the output of the GenerateEInvoiceQRCode method, they are different.?

Thanks and please advice?

Hey were you able to resolve this Qr code date and time issue?

I am also facing same issue on .net 3.3.9. Did you find a solution?

Previously, I was using the QR code generated by calling the QR code method provided by the SDK. However, this QR code had an issue as it did not include the date and time details.

To resolve this, I switched to extracting the QR code directly from the signed XML after the invoice was signed (The approach we use for cleared invoice for extracting the QR code).

Now, I am getting
{“validationResults”:{“infoMessages”:[{“type”:“INFO”,“code”:“XSD_ZATCA_VALID”,“category”:“XSD validation”,“message”:“Complied with UBL 2.1 standards in line with ZATCA specifications”,“status”:“PASS”}],“warningMessages”:,“errorMessages”:[{“type”:“ERROR”,“code”:“invalid-invoice-hash”,“category”:“INVOICE_HASHING_ERRORS”,“message”:“The invoice hash API body does not match the (calculated) Hash of the XML”,“status”:“ERROR”}],“status”:“ERROR”},“reportingStatus”:“NOT_REPORTED”,“clearanceStatus”:null,“qrSellertStatus”:null,“qrBuyertStatus”:null}


//=================================

using Microsoft.Data.SqlClient;
using Org.BouncyCastle.X509;
using System.Data;
using System.Globalization;
using System.Reflection.Metadata;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Xml;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography;
using System.Xml.Xsl;



string XMLS = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<xsl:stylesheet xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
                xmlns:xs=""http://www.w3.org/2001/XMLSchema""
                xmlns=""urn:oasis:names:specification:ubl:schema:xsd:Invoice-2""
                xmlns:cac=""urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2""
                xmlns:cbc=""urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2""
                xmlns:ext=""urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2""
                exclude-result-prefixes=""xs""
                version=""2.0"">
    <xsl:output omit-xml-declaration=""yes"" indent=""no"" encoding=""utf-8""/>
    <xsl:template match=""node() | @*"">
        <xsl:copy>
            <xsl:apply-templates select=""node() | @*""/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match=""//*[local-name()='Invoice']//*[local-name()='UBLExtensions']""></xsl:template>
    <xsl:template match=""//*[local-name()='AdditionalDocumentReference'][cbc:ID[normalize-space(text()) = 'QR']]""></xsl:template>
    <xsl:template match=""//*[local-name()='Invoice']//*[local-name()='Signature']""></xsl:template>
</xsl:stylesheet>";


static string GetBase64InvoiceHash(string eInvoiceXml)
{
    using MemoryStream stream = new(Encoding.UTF8.GetBytes(eInvoiceXml));
    XmlDsigC14NTransform transform1 = new(false);
    transform1.LoadInput(stream);
    MemoryStream output = transform1.GetOutput() as MemoryStream;
    byte[] hashBytes = HashSha256(Encoding.UTF8.GetString(output.ToArray()));
    return Convert.ToBase64String(hashBytes);
}

static byte[] HashSha256(string rawData)
{
    return SHA256.HashData(Encoding.UTF8.GetBytes(rawData));
}
static string ApplyXSLT(string xml, string xsltFileContent, bool indent)
{
    StringBuilder output = new();
    XmlWriterSettings settings = new()
    {
        OmitXmlDeclaration = true,
        Encoding = Encoding.UTF8,
        ConformanceLevel = ConformanceLevel.Auto,
        Indent = indent
    };
    using (XmlWriter writer = XmlWriter.Create(output, settings))
    {
        XmlReader stylesheet = XmlReader.Create(new StringReader(xsltFileContent));
        XmlReader input = XmlReader.Create(new StringReader(xml));
        input.Read();
        XslCompiledTransform transform1 = new();
        transform1.Load(stylesheet);
        transform1.Transform(input, writer);
    }
    return output.ToString();
}

static XmlDocument PrettyXml(XmlDocument inputXml)
{


    static string GetBase64InvoiceHash(string eInvoiceXml)
    {
        using MemoryStream stream = new(Encoding.UTF8.GetBytes(eInvoiceXml));
        XmlDsigC14NTransform transform1 = new(false);
        transform1.LoadInput(stream);
        MemoryStream output = transform1.GetOutput() as MemoryStream;
        byte[] hashBytes = HashSha256(Encoding.UTF8.GetString(output.ToArray()));
        return Convert.ToBase64String(hashBytes);
    }
    static byte[] HashSha256(string rawData)
    {
        return SHA256.HashData(Encoding.UTF8.GetBytes(rawData));
    }


    XmlDocument formattedXml = new XmlDocument() { PreserveWhitespace = true };

    using (MemoryStream memoryStream = new MemoryStream())
    {
        using (StreamWriter streamWriter = new StreamWriter(memoryStream, new UTF8Encoding(false))) // false to exclude BOM
        {
            XmlWriterSettings settings = new XmlWriterSettings()
            {
                Indent = true,
                IndentChars = "    ",
                OmitXmlDeclaration = false,
                Encoding = Encoding.UTF8,
            };

            using (XmlWriter xmlWriter = XmlWriter.Create(streamWriter, settings))
            {
                inputXml.Save(xmlWriter);
            }
        }

        // Get the UTF-8 encoded string from the MemoryStream
        string utf8Xml = Encoding.UTF8.GetString(memoryStream.ToArray()).Trim();

        // Load the UTF-8 XML string into the new XmlDocument
        formattedXml.LoadXml(utf8Xml);
    }

    return formattedXml;

}
static string GetDateTime(string Date, string Time)
{
    if (Time.EndsWith("Z"))
    {
        DateTime dateTime = DateTime.ParseExact(Date + "T" + Time, "yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
        TimeZoneInfo destinationTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Arab Standard Time");
        return TimeZoneInfo.ConvertTimeFromUtc(dateTime, destinationTimeZone).ToString("yyyy-MM-ddTHH:mm:ss");
    }
    else
    {
        return DateTime.ParseExact(Date + "T" + Time, "yyyy-MM-ddTHH:mm:ss", null).ToString("yyyy-MM-ddTHH:mm:ss");
    }

}
static string GetNodeInnerText(XmlDocument doc, string xPath)
{
    XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(doc.NameTable);
    xmlNamespaceManager.AddNamespace("cac", "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2");
    xmlNamespaceManager.AddNamespace("cbc", "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2");
    xmlNamespaceManager.AddNamespace("ext", "urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2");
    XmlNode xmlNode = doc.SelectSingleNode(xPath, xmlNamespaceManager);
    if (xmlNode == null)
    {
        return "";
    }

    return xmlNode.InnerText;
}
static SortedDictionary<int, byte[]> GetInvoiceDetails(XmlDocument Invoice)
{

    string XpathSellerName = "/*[local-name() = 'Invoice']/*[local-name() = 'AccountingSupplierParty']/*[local-name() = 'Party']/*[local-name() = 'PartyLegalEntity']//*[local-name() = 'RegistrationName']";

    string XpathVatRegisteration = "/*[local-name() = 'Invoice']/*[local-name() = 'AccountingSupplierParty']/*[local-name() = 'Party']/*[local-name() = 'PartyTaxScheme']/*[local-name() = 'CompanyID']";

    string XpathInvoiceTotal = "/*[local-name() = 'Invoice']/*[local-name() = 'LegalMonetaryTotal']/*[local-name() = 'TaxInclusiveAmount']";

    string XpathPayableAmount = "/*[local-name() = 'Invoice']/*[local-name() = 'LegalMonetaryTotal']/*[local-name() = 'PayableAmount']";

    string XpathVatTotal = "/*[local-name() = 'Invoice']/*[local-name() = 'TaxTotal']/*[local-name() = 'TaxAmount']";

    string CERTIFICATE_XPATH = "/*[local-name() = 'Invoice']/*[local-name() = 'UBLExtensions']/*[local-name() = 'UBLExtension']/*[local-name() = 'ExtensionContent']/*[local-name() = 'UBLDocumentSignatures']/*[local-name() = 'SignatureInformation']/*[local-name() = 'Signature']/*[local-name() = 'KeyInfo']/*[local-name() = 'X509Data']/*[local-name() = 'X509Certificate']";
    string XpathSignature = "/*[local-name() = 'Invoice']/*[local-name() = 'UBLExtensions']/*[local-name() = 'UBLExtension']/*[local-name() = 'ExtensionContent']/*[local-name() = 'UBLDocumentSignatures']/*[local-name() = 'SignatureInformation']/*[local-name() = 'Signature']/*[local-name() = 'SignatureValue']";

    string XpathQR = "/*[local-name() = 'Invoice']/*[local-name() = 'AdditionalDocumentReference' and *[local-name()='ID' and .='QR']]/*[local-name() = 'Attachment']/*[local-name() = 'EmbeddedDocumentBinaryObject']";

    string XpathHash = "/*[local-name() = 'Invoice']/*[local-name() = 'UBLExtensions']/*[local-name() = 'UBLExtension']/*[local-name() = 'ExtensionContent']/*[local-name() = 'UBLDocumentSignatures']/*[local-name() = 'SignatureInformation']/*[local-name() = 'Signature']/*[local-name() = 'SignedInfo']/*[local-name() = 'Reference' and @Id='invoiceSignedData']/*[local-name() = 'DigestValue']";

    string XpathUuid = "//*[local-name()='Invoice']//*[local-name()='UUID']";

    string XpathPih = "/*[local-name() = 'Invoice']/*[local-name() = 'AdditionalDocumentReference' and *[local-name()='ID' and .='PIH']]/*[local-name() = 'Attachment']/*[local-name() = 'EmbeddedDocumentBinaryObject']";
    string ISSUE_DATE_XPATH = "/*[local-name() = 'Invoice']/*[local-name() = 'IssueDate']";

    string ISSUE_TIME_XPATH = "/*[local-name() = 'Invoice']/*[local-name() = 'IssueTime']";

    string ZatcaDataInvoice = @"<?xml version=""1.0"" encoding=""UTF-8""?>
                                                            <xsl:stylesheet xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
                                                                            xmlns:xs=""http://www.w3.org/2001/XMLSchema""
                                                                            xmlns=""urn:oasis:names:specification:ubl:schema:xsd:Invoice-2""
                                                                            xmlns:cac=""urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2""
                                                                            xmlns:cbc=""urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2""
                                                                            xmlns:ext=""urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2""
                                                                            exclude-result-prefixes=""xs""
                                                                            version=""2.0"">
                                                                <xsl:output omit-xml-declaration=""yes"" indent=""no"" encoding=""utf-8""/>
                                                                <xsl:template match=""node() | @*"">
                                                                    <xsl:copy>
                                                                        <xsl:apply-templates select=""node() | @*""/>
                                                                    </xsl:copy>
                                                                </xsl:template>
                                                                <xsl:template match=""//*[local-name()='Invoice']//*[local-name()='UBLExtensions']""></xsl:template>
                                                                <xsl:template match=""//*[local-name()='AdditionalDocumentReference'][cbc:ID[normalize-space(text()) = 'QR']]""></xsl:template>
                                                                <xsl:template match=""//*[local-name()='Invoice']//*[local-name()='Signature']""></xsl:template>
                                                            </xsl:stylesheet>";

    return new SortedDictionary<int, byte[]>
        {
            {
                1,
                Encoding.UTF8.GetBytes(GetNodeInnerText(Invoice,XpathSellerName))
            },
            {
                2,
                Encoding.UTF8.GetBytes(GetNodeInnerText(Invoice,XpathVatRegisteration))
            },
            {
                3,
                Encoding.UTF8.GetBytes( GetDateTime(GetNodeInnerText(Invoice,ISSUE_DATE_XPATH),GetNodeInnerText(Invoice,ISSUE_TIME_XPATH)))
            },
            {
                4,
                Encoding.UTF8.GetBytes(GetNodeInnerText(Invoice,XpathPayableAmount))
            },
            {
                5,
                Encoding.UTF8.GetBytes(GetNodeInnerText(Invoice,XpathVatTotal))
            },
            {
                6,
                Encoding.UTF8.GetBytes(GetNodeInnerText(Invoice,XpathHash))
            },
            {
                7,
                Encoding.UTF8.GetBytes(GetNodeInnerText(Invoice,XpathSignature))
                }
        };
}

static void WriteLength(MemoryStream stream, int? length)
{
    if (!length.HasValue)
    {
        stream.WriteByte(0x80);
    }
    else
    {
        int? nullable = length;
        int num2 = 0;
        if (!(nullable.GetValueOrDefault() < num2 & nullable.HasValue))
        {
            nullable = length;
            long? nullable2 = nullable.HasValue ? new long?(nullable.GetValueOrDefault()) : null;
            long num3 = 0xffff_ffff;
            if (!(nullable2.GetValueOrDefault() > num3 & nullable2.HasValue))
            {
                nullable = length;
                num2 = 0x7f;
                if (nullable.GetValueOrDefault() <= num2 & nullable.HasValue)
                {
                    stream.WriteByte((byte)length.Value);
                }
                else
                {
                    byte num;
                    nullable = length;
                    num2 = 0xff;
                    if (nullable.GetValueOrDefault() <= num2 & nullable.HasValue)
                    {
                        num = 1;
                    }
                    else
                    {
                        nullable = length;
                        num2 = 0xffff;
                        if (nullable.GetValueOrDefault() <= num2 & nullable.HasValue)
                        {
                            num = 2;
                        }
                        else
                        {
                            nullable = length;
                            num2 = 0xff_ffff;
                            if (nullable.GetValueOrDefault() <= num2 & nullable.HasValue)
                            {
                                num = 3;
                            }
                            else
                            {
                                nullable = length;
                                nullable2 = nullable.HasValue ? new long?(nullable.GetValueOrDefault()) : null;
                                num3 = 0xffff_ffff;
                                if (!(nullable2.GetValueOrDefault() <= num3 & nullable2.HasValue))
                                {
                                    throw new Exception($"[Error] Length value too big: {length}");
                                }
                                num = 4;
                            }
                        }
                    }
                    stream.WriteByte((byte)(num | 0x80));
                    for (int i = num - 1; i >= 0; i--)
                    {
                        nullable = length;
                        num2 = 8 * i;
                        int? nullable4 = nullable.HasValue ? new int?(nullable.GetValueOrDefault() >> (num2 & 0x1f)) : null;
                        byte num5 = (byte)nullable4.Value;
                        stream.WriteByte(num5);
                    }
                }
                return;
            }
        }
        throw new Exception($"[Error] Invalid length value: {length}");
    }
}
static void WriteTag(MemoryStream stream, uint tag)
{
    bool flag = true;
    for (int i = 3; i >= 0; i--)
    {
        byte num2 = (byte)(tag >> 8 * i);
        if (!(num2 == 0 & flag) || i <= 0)
        {
            if (flag)
            {
                if (i != 0)
                {
                    if ((num2 & 0x1f) != 0x1f)
                    {
                        throw new Exception("[Error] Invalid tag value: first octet indicates no subsequent octets, but subsequent octets found");
                    }
                }
                else if ((num2 & 0x1f) == 0x1f)
                {
                    throw new Exception("[Error] Invalid tag value: first octet indicates subsequent octets, but no subsequent octets found");
                }
            }
            else if (i == 0)
            {
                if ((num2 & 0x80) == 0x80)
                {
                    throw new Exception("[Error] Invalid tag value: last octet indicates subsequent octets");
                }
            }
            else if ((num2 & 0x80) != 0x80)
            {
                throw new Exception("[Error] Invalid tag value: non-last octet indicates no subsequent octets");
            }
            stream.WriteByte(num2);
            flag = false;
        }
    }
}

static byte[] WriteTlv(uint tag, byte[] value)
{
    if (value == null)
    {
        throw new Exception("[Error] Please provide a value!");
    }
    using MemoryStream stream = new();
    WriteTag(stream, tag);
    int num = value != null ? value.Length : 0;
    WriteLength(stream, new int?(num));
    stream.Write(value, 0, num);
    return stream.ToArray();
}
static void TryGetPublicKeySByteArray(string certificate, out byte[] publicKey, out byte[] certificateSignature)
{
    Org.BouncyCastle.X509.X509Certificate certificate2 = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(new X509Certificate2(Convert.FromBase64String(certificate)));
    publicKey = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(certificate2.GetPublicKey()).GetEncoded();
    certificateSignature = certificate2.GetSignature();
}
static string GenerateQRCodeFromValues(SortedDictionary<int, byte[]> invoiceDetails)
{
    List<byte> data = [];
    foreach (var item in invoiceDetails)
    {
        data.AddRange(WriteTlv((uint)item.Key, item.Value));

        var t = Convert.ToBase64String(item.Value);
    }
    return Convert.ToBase64String(data.ToArray());
}
static string GenerateQRCode(XmlDocument invoiceObject)
{
    string CERTIFICATE_XPATH = "/*[local-name() = 'Invoice']/*[local-name() = 'UBLExtensions']/*[local-name() = 'UBLExtension']/*[local-name() = 'ExtensionContent']/*[local-name() = 'UBLDocumentSignatures']/*[local-name() = 'SignatureInformation']/*[local-name() = 'Signature']/*[local-name() = 'KeyInfo']/*[local-name() = 'X509Data']/*[local-name() = 'X509Certificate']";
    SortedDictionary<int, byte[]> invoiceDetails = GetInvoiceDetails(invoiceObject);
    var stringCertificate = GetNodeInnerText(invoiceObject, CERTIFICATE_XPATH);
    TryGetPublicKeySByteArray(stringCertificate, out byte[] publicKey, out byte[] certificateSignature);

    invoiceDetails.Add(8, publicKey);


    invoiceDetails.Add(9, certificateSignature);


    return GenerateQRCodeFromValues(invoiceDetails);

}
static string Base64Encode(string plainText)
{
    var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
    return System.Convert.ToBase64String(plainTextBytes);
}
static string Base64Decode(string encodedString)
{
    byte[] data = Convert.FromBase64String(encodedString);
    string decodedString = System.Text.Encoding.UTF8.GetString(data);
    return decodedString;
}



static void LogWriter(string logMessage)
{
    LogWrite(logMessage);
}
static void LogWrite(string logMessage)
{
    string m_exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    try
    {
        using (StreamWriter w = File.AppendText(m_exePath + "\\" + "log.txt"))
        {
            Log(logMessage, w);
        }
    }
    catch (Exception ex)
    {
    }
}

static void Log(string logMessage, TextWriter txtWriter)
{
    try
    {
        txtWriter.Write("\r\nLog Entry : ");
        txtWriter.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
            DateTime.Now.ToLongDateString());
        txtWriter.WriteLine("  :");
        txtWriter.WriteLine("  :{0}", logMessage);
        txtWriter.WriteLine("-------------------------------");
    }
    catch (Exception ex)
    {
        LogWriter(ex.Message);
    }
}


while (true)
{
    Thread.Sleep(2000);
    DatabaseHandler.DataBaseCommands dataBaseCommands = new DatabaseHandler.DataBaseCommands();
    DataTable dataTables = dataBaseCommands.GetDataTable("SelectQRGeneratorFromCMD");
    if (dataTables.Rows.Count != 0)
    {
        foreach (DataRow item in dataTables.Rows)
        {
            try
            {
                XmlDocument xmlDocument = new XmlDocument();
                string invoice = Base64Decode(Convert.ToString(item["InvoiceBase64"]));
                invoice = invoice.Replace(" />", "/>");
                xmlDocument.LoadXml(invoice);
                xmlDocument = PrettyXml(xmlDocument);
                // string CleanInvoice = ApplyXSLT(xmlDocument.InnerXml, XMLS, true);
                //  string Hash = GetBase64InvoiceHash(CleanInvoice);
                Zatca.EInvoice.SDK.EInvoiceSigner eInvoiceSigner = new Zatca.EInvoice.SDK.EInvoiceSigner();
                var t = eInvoiceSigner.SignDocument(xmlDocument, Base64Decode(Convert.ToString(item["BinaryToken"])), Base64Decode(Convert.ToString(item["PrivetKey"])));
                if (!t.IsValid)
                {
                    Console.WriteLine("Error in Sign Process" + System.Environment.NewLine + "***********************");
                    LogWriter("Error in Sign Process" + System.Environment.NewLine + "***********************");

                }
                xmlDocument.LoadXml(t.SignedEInvoice.InnerXml);
                xmlDocument = PrettyXml(xmlDocument);
                string qRResult = GenerateQRCode(xmlDocument);
                string ReplaceString = GetNodeInnerText(xmlDocument, @"//cac:AdditionalDocumentReference[3]/cac:Attachment[1]/cbc:EmbeddedDocumentBinaryObject[1]");
                string FixedXML = xmlDocument.InnerXml;
                FixedXML = FixedXML.Replace(ReplaceString.Trim(), qRResult);
                xmlDocument.LoadXml(FixedXML);
                xmlDocument = PrettyXml(xmlDocument);
                Zatca.EInvoice.SDK.EInvoiceHashGenerator eInvoiceHashGenerator = new Zatca.EInvoice.SDK.EInvoiceHashGenerator();
                var x = eInvoiceHashGenerator.GenerateEInvoiceHashing(xmlDocument);
                ReplaceString = GetNodeInnerText(xmlDocument, @"/*[local-name() = 'Invoice']/*[local-name() = 'UBLExtensions']/*[local-name() = 'UBLExtension']/*[local-name() = 'ExtensionContent']/*[local-name() = 'UBLDocumentSignatures']/*[local-name() = 'SignatureInformation']/*[local-name() = 'Signature']/*[local-name() = 'SignedInfo']/*[local-name() = 'Reference' and @Id='invoiceSignedData']/*[local-name() = 'DigestValue']");
                FixedXML = xmlDocument.InnerXml;
                FixedXML = FixedXML.Replace(ReplaceString.Trim(), x.Hash);
                xmlDocument.LoadXml(FixedXML);
                xmlDocument = PrettyXml(xmlDocument);
                dataBaseCommands = new DatabaseHandler.DataBaseCommands();
                string Invoice = xmlDocument.InnerXml.Replace(" />", "/>");
                xmlDocument.LoadXml(Invoice);
                xmlDocument = PrettyXml(xmlDocument);
                string ttt = Convert.ToBase64String(Encoding.UTF8.GetBytes(xmlDocument.InnerXml));
                //File.WriteAllText(@"D:\Ayman123321.txt", Convert.ToBase64String(Encoding.UTF8.GetBytes(xmlDocument.InnerXml)));
                //File.WriteAllText(@"D:\Ayman123321Hash.txt", "Hash= " + GetNodeInnerText(xmlDocument, @"/*[local-name() = 'Invoice']/*[local-name() = 'UBLExtensions']/*[local-name() = 'UBLExtension']/*[local-name() = 'ExtensionContent']/*[local-name() = 'UBLDocumentSignatures']/*[local-name() = 'SignatureInformation']/*[local-name() = 'Signature']/*[local-name() = 'SignedInfo']/*[local-name() = 'Reference' and @Id='invoiceSignedData']/*[local-name() = 'DigestValue']"));
                //File.WriteAllText(@"D:\AymanXML.txt", xmlDocument.InnerXml);
                dataBaseCommands.ExcuteSPDateBase("UpdateQRGeneratorFromCMD", new SqlParameter[] { new SqlParameter("@QR", qRResult), new SqlParameter("@NewInvoice64", Convert.ToBase64String(Encoding.UTF8.GetBytes(xmlDocument.InnerXml))), new SqlParameter("@ID", Convert.ToString(item["ID"])) });
                Console.WriteLine("Time= " + DateTime.Now + System.Environment.NewLine + "Hash= " + GetNodeInnerText(xmlDocument, @"/*[local-name() = 'Invoice']/*[local-name() = 'UBLExtensions']/*[local-name() = 'UBLExtension']/*[local-name() = 'ExtensionContent']/*[local-name() = 'UBLDocumentSignatures']/*[local-name() = 'SignatureInformation']/*[local-name() = 'Signature']/*[local-name() = 'SignedInfo']/*[local-name() = 'Reference' and @Id='invoiceSignedData']/*[local-name() = 'DigestValue']") + System.Environment.NewLine + "QR= " + qRResult + System.Environment.NewLine + "ID= " + Convert.ToString(item["ID"]) + System.Environment.NewLine + "***********************");
                LogWriter("Time= " + DateTime.Now + System.Environment.NewLine + "Hash= " + GetNodeInnerText(xmlDocument, @"/*[local-name() = 'Invoice']/*[local-name() = 'UBLExtensions']/*[local-name() = 'UBLExtension']/*[local-name() = 'ExtensionContent']/*[local-name() = 'UBLDocumentSignatures']/*[local-name() = 'SignatureInformation']/*[local-name() = 'Signature']/*[local-name() = 'SignedInfo']/*[local-name() = 'Reference' and @Id='invoiceSignedData']/*[local-name() = 'DigestValue']") + System.Environment.NewLine + "QR= " + qRResult + System.Environment.NewLine + "ID= " + Convert.ToString(item["ID"]) + System.Environment.NewLine + "***********************");

            }
            catch (Exception ex)
            {
                LogWriter(ex.Message);

            }
        }
    }

}

Just Fix Xpath Links To match Your XML This Code i Use to Sign and Get QR