Sdk versions 3.2.6 and 3.3.3

Dear @aymannagy
No need of generating hash using hashing function ?

No if You Did That it Will Give u Same Hash. You Can Test it . Just Try what i told you and u Will See but tell me if it fixed

But using the hash from signing process i am getting error “The invoice hash API body does not match the (calculated) Hash of the XML”

i tried it but getting the same error

Just Try What i told you u will see

ok tell me the Steps How You Sign it ? and What you Did after Sign it

Dear i m trying this

SignResult signresult = new SignResult();
EInvoiceSigner Sign = new EInvoiceSigner();
signresult = Sign.SignDocument(xDoc, certificateContent, privateKeyContent);

List lstStepResults = new List();
lstStepResults = signresult.Steps;

xDoc = new XmlDocument();
xDoc = signresult.SignedEInvoice;;

string Invoicehash= lstStepResults[1].ResultedValue;

            QRResult QRresult = new QRResult();
            EInvoiceQRGenerator QRGen = new EInvoiceQRGenerator();
            QRresult = QRGen.GenerateEInvoiceQRCode(xDoc);


            string strNamespace_cbc = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2";
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(xDoc.NameTable);
            nsmgr.AddNamespace("cbc", strNamespace_cbc);
            XmlNode NodeQR = xDoc.SelectSingleNode("*[local-name()='Invoice']//*[local-name()='AdditionalDocumentReference'][cbc:ID='QR']//*[local-name()='Attachment']//*[local-name()='EmbeddedDocumentBinaryObject']", nsmgr);
            NodeQR.InnerText = QRresult.QR;

FinalJSON Final = new FinalJSON();
Final.invoiceHash = Invoicehash;
Final.uuid = UUID;
Final.invoice = Convert.ToBase64String(Encoding.UTF8.GetBytes(xDoc.OuterXml));
var strJson = JsonConvert.SerializeObject(Final);

Please check and advice

XmlDocument xmlDocument = new XmlDocument();
string invoice = Base64Decode(requestSignInvoiceB2B.XmlInvoice);
invoice = invoice.Replace(" />", "/>");
xmlDocument.LoadXml(invoice);
Zatca.EInvoice.SDK.EInvoiceSigner invoiceSigner = new Zatca.EInvoice.SDK.EInvoiceSigner();
SignResult signResult = invoiceSigner.SignDocument(xmlDocument, Base64Decode(requestSignInvoiceB2B.BinaryToken), Base64Decode(requestSignInvoiceB2B.PrivateKey));
xmlDocument.LoadXml(signResult.SignedEInvoice.InnerXml.Replace(" />", "/>"));
Zatca.EInvoice.SDK.EInvoiceQRGenerator eInvoiceQRGenerator = new Zatca.EInvoice.SDK.EInvoiceQRGenerator();
string qRResult = GenerateQRCode(xmlDocument);
string ReplaceString = GetNodeInnerText(xmlDocument, "//*[local-name()='AdditionalDocumentReference'][cbc:ID[normalize-space(text())='QR']]");
string FixedXML = signResult.SignedEInvoice.InnerXml;
FixedXML = FixedXML.Replace(ReplaceString, qRResult);
xmlDocument.LoadXml(FixedXML);
Zatca.EInvoice.SDK.EInvoiceHashGenerator invoiceHashGenerator = new Zatca.EInvoice.SDK.EInvoiceHashGenerator();
HashResult hashResult = invoiceHashGenerator.GenerateEInvoiceHashing(xmlDocument);
//var t = signResult.Steps.Where(x => x.StepName == "Generate EInvoice Hash").FirstOrDefault();
// FixedXML = FixedXML.Replace(t.ResultedValue, hashResult.Hash);
xmlDocument.LoadXml(FixedXML);
Models.ReciveSingDocument reciveSingDocument = new Models.ReciveSingDocument();
reciveSingDocument.Hash = hashResult.Hash;
reciveSingDocument.SignDocumentBase64 = Base64Encode(xmlDocument.InnerXml);
reciveSingDocument.QR = qRResult;
reciveSingDocument.SignDocument = xmlDocument.InnerXml;
//System.IO.File.WriteAllText(@"D:\AYman\Output\InoviceSingied.txt", xmlDocument.InnerXml);
//System.IO.File.WriteAllText(@"D:\AYman\Output\InoviceBase64Singied.txt", reciveSingDocument.SignDocumentBase64);
//System.IO.File.WriteAllText(@"D:\AYman\Output\Hash.txt", reciveSingDocument.Hash);
//System.IO.File.WriteAllText(@"D:\AYman\Output\QR.txt", reciveSingDocument.QR);
return JsonConvert.SerializeObject(reciveSingDocument);

Here you are generating hash separately in your code right ?

Zatca.EInvoice.SDK.EInvoiceHashGenerator invoiceHashGenerator = new Zatca.EInvoice.SDK.EInvoiceHashGenerator();
HashResult hashResult = invoiceHashGenerator.GenerateEInvoiceHashing(xmlDocument);

Can you please share the code of QR code generation ?

its Just to Save Hash but im not replace it

private static readonly string XpathSellerName = “/[local-name() = ‘Invoice’]/[local-name() = ‘AccountingSupplierParty’]/[local-name() = ‘Party’]/[local-name() = ‘PartyLegalEntity’]//*[local-name() = ‘RegistrationName’]”;

private static readonly string XpathVatRegisteration = “/[local-name() = ‘Invoice’]/[local-name() = ‘AccountingSupplierParty’]/[local-name() = ‘Party’]/[local-name() = ‘PartyTaxScheme’]/*[local-name() = ‘CompanyID’]”;

private static readonly string XpathInvoiceTotal = “/[local-name() = ‘Invoice’]/[local-name() = ‘LegalMonetaryTotal’]/*[local-name() = ‘TaxInclusiveAmount’]”;

private static readonly string XpathPayableAmount = “/[local-name() = ‘Invoice’]/[local-name() = ‘LegalMonetaryTotal’]/*[local-name() = ‘PayableAmount’]”;

private static readonly string XpathVatTotal = “/[local-name() = ‘Invoice’]/[local-name() = ‘TaxTotal’]/*[local-name() = ‘TaxAmount’]”;

private static readonly 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’]”;
private static readonly 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’]”;

private static readonly string XpathQR = “/[local-name() = ‘Invoice’]/[local-name() = ‘AdditionalDocumentReference’ and [local-name()=‘ID’ and .=‘QR’]]/[local-name() = ‘Attachment’]/*[local-name() = ‘EmbeddedDocumentBinaryObject’]”;

private static readonly 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’]”;

private static readonly string XpathUuid = “//[local-name()=‘Invoice’]//[local-name()=‘UUID’]”;

private static readonly string XpathPih = “/[local-name() = ‘Invoice’]/[local-name() = ‘AdditionalDocumentReference’ and [local-name()=‘ID’ and .=‘PIH’]]/[local-name() = ‘Attachment’]/[local-name() = ‘EmbeddedDocumentBinaryObject’]";
private static readonly string ISSUE_DATE_XPATH = "/
[local-name() = ‘Invoice’]/*[local-name() = ‘IssueDate’]”;

private static readonly string ISSUE_TIME_XPATH = “/[local-name() = ‘Invoice’]/[local-name() = ‘IssueTime’]”;
private static SortedDictionary<int, byte> GetInvoiceDetails(XmlDocument Invoice)
{
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))
}
};
}
private 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();

}
private 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}”);
}
}
private 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;
}
}
}

private 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();
}

private 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”);
}

}

private static string GenerateQRCodeFromValues(SortedDictionary<int, byte> invoiceDetails)
{
List data = ;
foreach (var item in invoiceDetails)
{
data.AddRange(WriteTlv((uint)item.Key, item.Value));
}
return Convert.ToBase64String(data.ToArray());
}

private static string GenerateQRCode(XmlDocument invoiceObject)
{
try
{
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);
   }
   catch (Exception exception)
   {
       throw new Exception("Error generating EInvoice QR Code", exception);
   }

}

private 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;

}

but you are sending that hash to ZATCA right ?

The Hash That Generates From Sign.

Both of them is same

i’m getting different one

its B2C ?? replace the old Hash With New one

yes B2C invoice. Ok let me try . thank you

Dear @aymannagy
Thank you for your previous supports. I followed your instructions and checked in simulation environment now i am getting “Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties” as error. Please advise on this .

Did u resolve this issue of Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties @anusv