Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1162,28 +1162,35 @@ codeunit 13916 "Export XRechnung Document"
AttachmentElement: XmlElement;
OutStream: OutStream;
InStream: InStream;
MimeCode: Text;
FileName: Text;
begin
MimeCode := GetMimeCode(DocumentAttachment);
if not IsValidMimeCode(MimeCode) then
exit;

TempBlob.CreateOutStream(OutStream);
DocumentAttachment.ExportToStream(OutStream);
TempBlob.CreateInStream(InStream);

FileName := DocumentAttachment."File Name" + '.' + DocumentAttachment."File Extension";
AttachmentElement := XmlElement.Create('AdditionalDocumentReference', XmlNamespaceCAC);
AttachmentElement.Add(XmlElement.Create('ID', XmlNamespaceCBC, DocumentAttachment."File Name" + '.' + DocumentAttachment."File Extension"));
AttachmentElement.Add(XmlElement.Create('ID', XmlNamespaceCBC, FileName));
AttachmentElement.Add(XmlElement.Create('DocumentDescription', XmlNamespaceCBC, DocumentAttachment."File Name"));
AddAttachmentObject(AttachmentElement, InStream, DocumentAttachment);
AddAttachmentObject(AttachmentElement, InStream, MimeCode, FileName);

RootElement.Add(AttachmentElement);
end;

local procedure AddAttachmentObject(var AttachmentElement: XmlElement; var InStream: InStream; var DocumentAttachment: Record "Document Attachment");
local procedure AddAttachmentObject(var AttachmentElement: XmlElement; var InStream: InStream; MimeCode: Text; FileName: Text);
var
Base64Convert: Codeunit "Base64 Convert";
AttachmentObjectElement: XmlElement;
begin
AttachmentObjectElement := XmlElement.Create('Attachment', XmlNamespaceCAC);
AttachmentObjectElement.Add(XmlElement.Create('EmbeddedDocumentBinaryObject', XmlNamespaceCBC,
XmlAttribute.Create('mimeCode', GetMimeCode(DocumentAttachment)),
XmlAttribute.Create('filename', DocumentAttachment."File Name" + '.' + DocumentAttachment."File Extension"),
XmlAttribute.Create('mimeCode', MimeCode),
XmlAttribute.Create('filename', FileName),
Base64Convert.ToBase64(InStream)));
AttachmentElement.Add(AttachmentObjectElement);
end;
Expand All @@ -1192,9 +1199,14 @@ codeunit 13916 "Export XRechnung Document"
begin
case DocumentAttachment."File Type" of
"Document Attachment File Type"::Image:
exit('image/' + LowerCase(DocumentAttachment."File Extension"));
case LowerCase(DocumentAttachment."File Extension") of
'png':
exit('image/png');
'jpeg', 'jpg':
exit('image/jpeg');
end;
"Document Attachment File Type"::PDF:
exit('application/' + LowerCase(DocumentAttachment."File Extension"));
exit('application/pdf');
"Document Attachment File Type"::Excel:
exit('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
"Document Attachment File Type"::Other:
Expand All @@ -1212,6 +1224,20 @@ codeunit 13916 "Export XRechnung Document"
end;
end;

local procedure IsValidMimeCode(MimeCode: Text): Boolean
begin
case MimeCode of
'application/pdf',
'image/png',
'image/jpeg',
'text/csv',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.oasis.opendocument.spreadsheet':
exit(true);
end;
exit(false);
end;

local procedure CalculateLineAmounts(SalesInvoiceHeader: Record "Sales Invoice Header"; var SalesInvLine: Record "Sales Invoice Line"; Currency: Record Currency; var LineAmounts: Dictionary of [Text, Decimal])
var
TotalInvDiscountAmount: Decimal;
Expand Down
Binary file added Apps/DE/EDocumentDE/test/.resources/CRONUS.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
3 changes: 3 additions & 0 deletions Apps/DE/EDocumentDE/test/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,8 @@
"allowDownloadingSource": true,
"includeSourceInSymbolFile": true
},
"resourceFolders": [
".resources"
],
"application": "29.0.0.0"
}
102 changes: 96 additions & 6 deletions Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,67 @@ codeunit 13918 "XRechnung XML Document Tests"
end;
#endregion

#region DocumentAttachmentFiltering
[Test]
procedure ExportPostedSalesInvoiceInXRechnungFormatVerifyUnsupportedAttachmentIsSkipped();
var
SalesInvoiceHeader: Record "Sales Invoice Header";
TempXMLBuffer: Record "XML Buffer" temporary;
RecRef: RecordRef;
CSVText: Text;
begin
// [SCENARIO] Attachments with unsupported MIME types are not exported in XRechnung format
Initialize();

// [GIVEN] Create and Post Sales Invoice
SalesInvoiceHeader.Get(CreateAndPostSalesDocument("Sales Document Type"::Invoice, "Sales Line Type"::Item, false));
RecRef.GetTable(SalesInvoiceHeader);

// [GIVEN] Create one supported CSV attachment and one unsupported TXT attachment
CSVText := CreateCSVDocumentAttachment(RecRef, 'data.csv');
CreateDocumentAttachment(RecRef, 'report.txt', 'Some text content');

// [WHEN] Export XRechnung Electronic Document
ExportInvoice(SalesInvoiceHeader, TempXMLBuffer);

// [THEN] Only the CSV attachment (supported) is present; TXT is skipped
VerifyAdditionalDocumentReferenceCount(TempXMLBuffer, 1);
VerifyCSVAttachmentInXML(TempXMLBuffer, 'data.csv', 'text/csv', CSVText);
end;

[Test]
procedure ExportPostedSalesInvoiceInXRechnungFormatVerifyUnsupportedImageExtensionIsSkipped();
var
DocumentAttachment: Record "Document Attachment";
SalesInvoiceHeader: Record "Sales Invoice Header";
TempXMLBuffer: Record "XML Buffer" temporary;
Base64Convert: Codeunit "Base64 Convert";
TempBlob: Codeunit "Temp Blob";
RecRef: RecordRef;
begin
// [SCENARIO] Image attachments with unsupported extensions (e.g. bmp) are skipped; supported ones (jpg) are exported
Initialize();

// [GIVEN] Create and Post Sales Invoice
SalesInvoiceHeader.Get(CreateAndPostSalesDocument("Sales Document Type"::Invoice, "Sales Line Type"::Item, false));
RecRef.GetTable(SalesInvoiceHeader);

// [GIVEN] Create one unsupported BMP image and one supported JGP image attachment
LoadFileFromResourceFolders('d365businesscentral.bmp', TempBlob);
DocumentAttachment.SaveAttachment(RecRef, 'd365businesscentral.bmp', TempBlob);
LoadFileFromResourceFolders('CRONUS.jpg', TempBlob);
Clear(DocumentAttachment);
DocumentAttachment.SaveAttachment(RecRef, 'CRONUS.jpg', TempBlob);

// [WHEN] Export XRechnung Electronic Document
ExportInvoice(SalesInvoiceHeader, TempXMLBuffer);

// [THEN] Only the JPG attachment (supported) is present; BMP is skipped
VerifyAdditionalDocumentReferenceCount(TempXMLBuffer, 1);
VerifyAttachmentInXML(TempXMLBuffer, 'CRONUS.jpg', 'image/jpeg', '');
end;
#endregion

local procedure CreateAndPostSalesDocument(DocumentType: Enum "Sales Document Type"; LineType: Enum "Sales Line Type"; InvoiceDiscount: Boolean): Code[20];
var
SalesHeader: Record "Sales Header";
Expand Down Expand Up @@ -2421,10 +2482,10 @@ codeunit 13918 "XRechnung XML Document Tests"
VerifyAdditionalDocumentReferenceCount(TempXMLBuffer, 2);

// [THEN] First attachment is verified in XML with correct ID, MIME type, and content
VerifyAttachmentInXML(TempXMLBuffer, FileName1, 'text/csv', CSVText1);
VerifyCSVAttachmentInXML(TempXMLBuffer, FileName1, 'text/csv', CSVText1);

// [THEN] Second attachment is verified in XML with correct ID, MIME type, and content
VerifyAttachmentInXML(TempXMLBuffer, FileName2, 'text/csv', CSVText2);
VerifyCSVAttachmentInXML(TempXMLBuffer, FileName2, 'text/csv', CSVText2);
end;


Expand All @@ -2436,9 +2497,17 @@ codeunit 13918 "XRechnung XML Document Tests"
Assert.AreEqual(ExpectedCount, TempXMLBuffer.Count, 'Incorrect number of AdditionalDocumentReference nodes');
end;

local procedure VerifyAttachmentInXML(var TempXMLBuffer: Record "XML Buffer" temporary; AttachmentID: Text; ExpectedMIMEType: Text; ExpectedCSVText: Text)

local procedure VerifyCSVAttachmentInXML(var TempXMLBuffer: Record "XML Buffer" temporary; AttachmentID: Text; ExpectedMIMEType: Text; ExpectedCSVText: Text)
var
Base64Convert: Codeunit "Base64 Convert";
Base64EncodedContent: Text;
begin
Base64EncodedContent := Base64Convert.ToBase64(ExpectedCSVText);
end;

local procedure VerifyAttachmentInXML(var TempXMLBuffer: Record "XML Buffer" temporary; AttachmentID: Text; ExpectedMIMEType: Text; ExpectedBase64Content: Text)
var
TempXMLBufferAttachment: Record "XML Buffer" temporary;
TempXMLBufferChild: Record "XML Buffer" temporary;
DecodedText: Text;
Expand Down Expand Up @@ -2488,9 +2557,8 @@ codeunit 13918 "XRechnung XML Document Tests"
if TempXMLBufferChild.FindFirst() then
Assert.AreEqual(ExpectedMIMEType, TempXMLBufferChild.Value, 'Incorrect MIME type');

// Verify decoded content
DecodedText := Base64Convert.FromBase64(EncodedContent);
Assert.AreEqual(ExpectedCSVText, DecodedText, 'Decoded attachment content does not match original CSV text');
if ExpectedBase64Content <> '' then
Assert.AreEqual(ExpectedBase64Content, EncodedContent, 'Attachment content does not match original value');
end else
Error('EmbeddedDocumentBinaryObject not found for attachment %1', AttachmentID);
end else
Expand Down Expand Up @@ -2767,6 +2835,28 @@ codeunit 13918 "XRechnung XML Document Tests"
exit(CSVText);
end;

local procedure CreateDocumentAttachment(RecRef: RecordRef; FileName: Text; ContentText: Text)
var
DocumentAttachment: Record "Document Attachment";
TempBlob: Codeunit "Temp Blob";
OutStream: OutStream;
begin
TempBlob.CreateOutStream(OutStream, TextEncoding::UTF8);
OutStream.WriteText(ContentText);
DocumentAttachment.SaveAttachment(RecRef, FileName, TempBlob);
end;

local procedure LoadFileFromResourceFolders(FilePath: Text; var TempBlob: Codeunit "Temp Blob")
var
ImageOutStream: OutStream;
FileInStream: InStream;
begin
Clear(TempBlob);
NavApp.GetResource(FilePath, FileInStream);
ImageOutStream := TempBlob.CreateOutStream();
CopyStream(ImageOutStream, FileInStream);
end;

local procedure GetCurrencyCode(DocumentCurrencyCode: Code[10]; var Currency: Record Currency): Code[10]
begin
if DocumentCurrencyCode = '' then begin
Expand Down
Loading