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
4 changes: 4 additions & 0 deletions src/Apps/W1/EDocument/App/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@
{
"from": 6401,
"to": 6410
},
{
"from": 6427,
"to": 6436
}
],
"resourceExposurePolicy": {
Expand Down
19 changes: 19 additions & 0 deletions src/Apps/W1/EDocument/App/src/Document/EDocument.Page.al
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ using Microsoft.eServices.EDocument.OrderMatch;
using Microsoft.eServices.EDocument.OrderMatch.Copilot;
using Microsoft.eServices.EDocument.Processing.Import;
using Microsoft.eServices.EDocument.Processing.Import.Purchase;
using Microsoft.eServices.EDocument.Processing.Message;
using Microsoft.eServices.EDocument.Service;
using Microsoft.Foundation.Attachment;
using System.Telemetry;
Expand Down Expand Up @@ -220,6 +221,12 @@ page 6121 "E-Document"
Enabled = Rec.Direction = Rec.Direction::Outgoing;
Visible = Rec.Direction = Rec.Direction::Outgoing;
}
part(EDocMessages; "E-Document Messages FactBox")
{
Caption = 'Messages';
SubPageLink = "E-Document Entry No." = field("Entry No");
ShowFilter = false;
}
}
}
actions
Expand Down Expand Up @@ -305,6 +312,18 @@ page 6121 "E-Document"
end
end;
}
action(RejectOrder)
{
Caption = 'Reject Order';
ToolTip = 'Sends a rejection response to the sender of this inbound order.';
Image = Reject;
Visible = IsIncomingDoc;

trigger OnAction()
begin
EDocumentHelper.SendOrderRejection(Rec);
end;
}
action(ViewFile)
{
ApplicationArea = Basic, Suite;
Expand Down
6 changes: 6 additions & 0 deletions src/Apps/W1/EDocument/App/src/Document/EDocument.Table.al
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ using Microsoft.eServices.EDocument.OrderMatch;
using Microsoft.eServices.EDocument.Processing.Import;
using Microsoft.eServices.EDocument.Processing.Import.Purchase;
using Microsoft.eServices.EDocument.Processing.Interfaces;
using Microsoft.eServices.EDocument.Processing.Message;
using Microsoft.Finance.Currency;
using Microsoft.Foundation.Attachment;
using Microsoft.Foundation.Reporting;
Expand Down Expand Up @@ -416,6 +417,7 @@ table 6121 "E-Document"
EDocumentIntegrationLog: Record "E-Document Integration Log";
EDocumentLog: Record "E-Document Log";
EDocImportedLine: Record "E-Doc. Imported Line";
EDocumentMessage: Record "E-Document Message";
EDocumentServiceStatus: Record "E-Document Service Status";
#if not CLEAN27
PurchaseHeader: Record "Purchase Header";
Expand Down Expand Up @@ -453,6 +455,10 @@ table 6121 "E-Document"
if not EDocImportedLine.IsEmpty() then
EDocImportedLine.DeleteAll(true);

EDocumentMessage.SetRange("E-Document Entry No.", Rec."Entry No");
if not EDocumentMessage.IsEmpty() then
EDocumentMessage.DeleteAll(true);

#if not CLEAN27
// Version 1 processing cleanup
// Can be removed soon as version 1 is fully migrated to version 2
Expand Down
46 changes: 44 additions & 2 deletions src/Apps/W1/EDocument/App/src/Document/EDocuments.Page.al
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
// ------------------------------------------------------------------------------------------------
namespace Microsoft.eServices.EDocument;

using Microsoft.eServices.EDocument.Processing.Message;
using Microsoft.eServices.EDocument.Service;
using Microsoft.Foundation.Attachment;

page 6122 "E-Documents"
{
ApplicationArea = Basic, Suite;
Expand Down Expand Up @@ -61,6 +65,39 @@ page 6122 "E-Documents"
}
}
}
area(FactBoxes)
{
part("Attached Documents List"; "Doc. Attachment List Factbox")
{
ApplicationArea = All;
Caption = 'Documents';
UpdatePropagation = Both;
SubPageLink = "E-Document Entry No." = field("Entry No"),
"E-Document Attachment" = const(true);
}
part(InboundEDocFactbox; "Inbound E-Doc. Factbox")
{
Caption = 'Details';
SubPageLink = "E-Document Entry No" = field("Entry No");
ShowFilter = false;
Enabled = Rec.Direction = Rec.Direction::Incoming;
Visible = Rec.Direction = Rec.Direction::Incoming;
}
part("Outbound E-Doc. Factbox"; "Outbound E-Doc. Factbox")
{
Caption = 'Details';
SubPageLink = "E-Document Entry No" = field("Entry No");
ShowFilter = false;
Enabled = Rec.Direction = Rec.Direction::Outgoing;
Visible = Rec.Direction = Rec.Direction::Outgoing;
}
part(EDocMessages; "E-Document Messages FactBox")
{
Caption = 'Messages';
SubPageLink = "E-Document Entry No." = field("Entry No");
ShowFilter = false;
}
}
}
actions
{
Expand Down Expand Up @@ -138,9 +175,14 @@ page 6122 "E-Documents"
EDocImport: Codeunit "E-Doc. Import";
begin
EDocImport.UploadDocument(EDocument);
if EDocument."Entry No" <> 0 then begin
EDocImport.ProcessIncomingEDocument(EDocument, EDocument.GetEDocumentService().GetDefaultImportParameters());
if EDocument."Entry No" = 0 then
exit;
if EDocument.Direction = EDocument.Direction::Outgoing then begin
// File was classified as a message (e.g. OrderResponse) linked to this outbound document.
Page.Run(Page::"E-Document", EDocument);
exit;
end;
EDocImport.ProcessIncomingEDocument(EDocument, EDocument.GetEDocumentService().GetDefaultImportParameters());
Page.Run(Page::"E-Document", EDocument);
end;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace Microsoft.eServices.EDocument;

using Microsoft.eServices.EDocument.Processing.Import;
using Microsoft.eServices.EDocument.Processing.Import.Purchase;
using Microsoft.EServices.EDocument.Processing.Import.Sales;
using Microsoft.eServices.EDocument.Processing.Message;
using Microsoft.Foundation.Attachment;
using Microsoft.Purchases.Vendor;
using System.Agents;
Expand Down Expand Up @@ -187,6 +189,12 @@ page 6105 "Inbound E-Documents"
SubPageLink = "E-Document Entry No" = field("Entry No");
ShowFilter = false;
}
part(EDocMessages; "E-Document Messages FactBox")
{
Caption = 'Messages';
SubPageLink = "E-Document Entry No." = field("Entry No");
ShowFilter = false;
}
}
}
actions
Expand Down
20 changes: 15 additions & 5 deletions src/Apps/W1/EDocument/App/src/Processing/EDocImport.Codeunit.al
Original file line number Diff line number Diff line change
Expand Up @@ -196,21 +196,26 @@ codeunit 6140 "E-Doc. Import"
InStr: InStream;
FileName: Text;
EDocumentServiceStatus: Enum "E-Document Service Status";
Handled: Boolean;
begin
if Page.RunModal(Page::"E-Document Services", EDocumentService) <> Action::LookupOK then
if not UploadIntoStream('', '', '', FileName, InStr) then
exit;

if not UploadIntoStream('', '', '', FileName, InStr) then
OutStr := TempBlob.CreateOutStream();
CopyStream(OutStr, InStr);

OnAfterUploadFile(TempBlob, FileName, EDocument, Handled);
if Handled then
exit;

if Page.RunModal(Page::"E-Document Services", EDocumentService) <> Action::LookupOK then
exit;

EDocument.Direction := EDocument.Direction::Incoming;
EDocument."Document Type" := Enum::"E-Document Type"::None;
EDocument.Service := EDocumentService.Code;
EDocumentServiceStatus := "E-Document Service Status"::Imported;

OutStr := TempBlob.CreateOutStream();
CopyStream(OutStr, InStr);

EDocument."File Name" := CopyStr(FileName, 1, 256);

if EDocument."Entry No" = 0 then begin
Expand All @@ -226,6 +231,11 @@ codeunit 6140 "E-Doc. Import"
EDocument.Modify();
end;

[IntegrationEvent(false, false)]
local procedure OnAfterUploadFile(var TempBlob: Codeunit "Temp Blob"; FileName: Text; var EDocument: Record "E-Document"; var Handled: Boolean)
begin
end;

internal procedure V1_GetBasicInfo(var EDocument: Record "E-Document")
var
EDocService: Record "E-Document Service";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ namespace Microsoft.eServices.EDocument;

using Microsoft.eServices.EDocument.Processing.Import;
using Microsoft.eServices.EDocument.Processing.Import.Purchase;
using Microsoft.eServices.EDocument.Processing.Interfaces;
using Microsoft.eServices.EDocument.Processing.Message;
using Microsoft.Finance.GeneralLedger.Journal;
using Microsoft.Finance.GeneralLedger.Ledger;
using Microsoft.Foundation.Reporting;
using Microsoft.Inventory.Location;
using Microsoft.Inventory.Transfer;
using Microsoft.Peppol.Response;
using Microsoft.Purchases.Document;
using Microsoft.Purchases.History;
using Microsoft.Purchases.Vendor;
Expand Down Expand Up @@ -744,6 +747,20 @@ codeunit 6108 "E-Document Processing"
exit(false);
end;

procedure SendOrderRejection(EDocument: Record "E-Document")
var
EDocMessageMgt: Codeunit "E-Doc. Message Mgt.";
ResponseBlob: Codeunit "Temp Blob";
IResponseBuilder: Interface IOrderResponseBuilder;
begin
EDocument.TestField(Direction, EDocument.Direction::Incoming);
IResponseBuilder := EDocument."Read into Draft Impl.";
if not IResponseBuilder.SupportsOrderResponse(EDocument) then
exit;
IResponseBuilder.BuildOrderResponse(EDocument, "E-Doc. Response Type"::Rejected, ResponseBlob);
EDocMessageMgt.CreateMessage(EDocument, "E-Document Message Type"::"PEPPOL Order Response", "E-Document Direction"::Outgoing, "E-Doc. Response Type"::Rejected, ResponseBlob);
end;

[IntegrationEvent(false, false)]
local procedure OnAfterGetTypeFromSourceDocument(RecordVariant: Variant; var EDocumentType: Enum "E-Document Type")
begin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ using Microsoft.eServices.EDocument.OrderMatch;
using Microsoft.EServices.EDocument.Processing;
using Microsoft.eServices.EDocument.Processing.Import;
using Microsoft.eServices.EDocument.Processing.Import.Purchase;
using Microsoft.eServices.EDocument.Processing.Interfaces;
using Microsoft.eServices.EDocument.Processing.Message;
using Microsoft.eServices.EDocument.Service.Participant;
using Microsoft.Finance.GeneralLedger.Journal;
using Microsoft.Finance.GeneralLedger.Ledger;
using Microsoft.Finance.GeneralLedger.Posting;
using Microsoft.Finance.VAT.Setup;
using Microsoft.Foundation.Reporting;
using Microsoft.Inventory.Transfer;
using Microsoft.Peppol.Response;
using Microsoft.Purchases.Document;
using Microsoft.Purchases.History;
using Microsoft.Purchases.Posting;
Expand Down Expand Up @@ -744,4 +747,27 @@ codeunit 6103 "E-Document Subscribers"
local procedure OnAfterUpdateToPostedPurchaseEDocument(var EDocument: Record "E-Document"; PostedRecord: Variant; PostedDocumentNo: Code[20]; DocumentType: Enum "E-Document Type")
begin
end;

[EventSubscriber(ObjectType::Codeunit, Codeunit::"Release Sales Document", 'OnAfterReleaseSalesDoc', '', false, false)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟠\ High\ Severity\ —\ Performance} \quad \color{gray}{\texttt{\small Iteration\ 1}}$

Sales release subscriber queries DB unconditionally

OnAfterReleaseSalesDoc fires on every Sales Document release and immediately executes two SetRange calls plus a FindLast() against the E-Document table, even when the E-Document feature is not in use. This adds measurable overhead to every Sales Order release across all companies.

Recommendation:

  • Add an early-exit guard using a feature flag or a cheap, indexed check (e.g., checking whether any E-Documents exist at all) before performing the full lookup.
Suggested change
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Release Sales Document", 'OnAfterReleaseSalesDoc', '', false, false)]
if PreviewMode then
exit;
// Early exit if EDocument feature is not active
if not EDocumentFeatureMgt.IsEnabled() then
exit;
SalesHeaderRef.GetTable(SalesHeader);
EDocument.SetRange("Document Record ID", SalesHeaderRef.RecordId);

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why

local procedure OnAfterReleaseSalesDoc(var SalesHeader: Record "Sales Header"; PreviewMode: Boolean; var LinesWereModified: Boolean; SkipWhseRequestOperations: Boolean)
var
EDocument: Record "E-Document";
EDocMessageMgt: Codeunit "E-Doc. Message Mgt.";
ResponseBlob: Codeunit "Temp Blob";
SalesHeaderRef: RecordRef;
IResponseBuilder: Interface IOrderResponseBuilder;
begin
if PreviewMode then
exit;
SalesHeaderRef.GetTable(SalesHeader);
EDocument.SetRange("Document Record ID", SalesHeaderRef.RecordId);
EDocument.SetRange(Direction, EDocument.Direction::Incoming);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Performance} \quad \color{gray}{\texttt{\small Iteration\ 1}}$

FindLast() skips all but last linked EDocument

EDocument.FindLast() in OnAfterReleaseSalesDoc silently processes only the most recently created EDocument linked to the Sales Header. If multiple EDocuments are associated with the same Sales Header, all but the last one never receive an acceptance response.

Recommendation:

  • Iterate over all matching EDocuments using a repeat…until loop to ensure every linked EDocument receives the acceptance response.
Suggested change
EDocument.SetRange(Direction, EDocument.Direction::Incoming);
if EDocument.FindSet() then
repeat
IResponseBuilder := EDocument."Read into Draft Impl.";
if IResponseBuilder.SupportsOrderResponse(EDocument) then begin
IResponseBuilder.BuildOrderResponse(EDocument, "E-Doc. Response Type"::Accepted, ResponseBlob);
EDocMessageMgt.CreateMessage(EDocument, "E-Document Message Type"::"PEPPOL Order Response", "E-Document Direction"::Outgoing, "E-Doc. Response Type"::Accepted, ResponseBlob);
end;
until EDocument.Next() = 0;

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why

if not EDocument.FindLast() then
exit;
IResponseBuilder := EDocument."Read into Draft Impl.";
if not IResponseBuilder.SupportsOrderResponse(EDocument) then
exit;
IResponseBuilder.BuildOrderResponse(EDocument, "E-Doc. Response Type"::Accepted, ResponseBlob);
EDocMessageMgt.CreateMessage(EDocument, "E-Document Message Type"::"PEPPOL Order Response", "E-Document Direction"::Outgoing, "E-Doc. Response Type"::Accepted, ResponseBlob);
end;
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,5 @@ codeunit 6193 "E-Doc. Empty Draft" implements IStructureReceivedEDocument, IStru
begin
Error(NoDataErr);
end;

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Microsoft.eServices.EDocument.Processing.Import;

using Microsoft.eServices.EDocument.Processing.Interfaces;
using Microsoft.eServices.EDocument.Processing.Message;

/// <summary>
/// Enum for E-Document Processing
Expand Down Expand Up @@ -33,4 +34,14 @@ enum 6107 "E-Doc. Process Draft" implements IProcessStructuredData
Caption = 'Purchase Credit Memo';
Implementation = IProcessStructuredData = "EDoc Prepare Cr. Memo Draft";
}
value(3; "Sales Order")
{
Caption = 'Sales Order';
Implementation = IProcessStructuredData = "Prepare Sales E-Doc. Draft";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟠\ High\ Severity\ —\ Performance} \quad \color{gray}{\texttt{\small Iteration\ 1}}$

Missing implementation codeunit breaks compile

The "Sales Order" enum value declares Implementation = IProcessStructuredData = "Prepare Sales E-Doc. Draft", but no codeunit with that name exists anywhere in the repository. This causes a compile error that prevents the EDocument app from building.

Recommendation:

  • Add the missing "Prepare Sales E-Doc. Draft" codeunit implementing IProcessStructuredData, or correct the implementation reference to an existing codeunit.
Suggested change
Implementation = IProcessStructuredData = "Prepare Sales E-Doc. Draft";
codeunit XXXXX "Prepare Sales E-Doc. Draft" implements IProcessStructuredData
{
Access = Internal;
InherentEntitlements = X;
InherentPermissions = X;
procedure PrepareDraft(EDocument: Record "E-Document"; EDocImportParameters: Record "E-Doc. Import Parameters"): Enum "E-Document Type"
begin
exit("E-Document Type"::"Sales Order");
end;
// ... remaining interface methods
}

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why

}
value(4; "E-Document Message")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets no do messages as drafts.

Drafts are for users to be able to edit before documents are created.
What is the ned for a message to be in a draft?

{
Caption = 'E-Document Message';
Implementation = IProcessStructuredData = "E-Doc. Message Draft Handler";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ using Microsoft.eServices.EDocument.Processing.Interfaces;
/// <summary>
/// Specifies how a structured data type should be interpreted and read into a draft.
/// </summary>
enum 6109 "E-Doc. Read into Draft" implements IStructuredFormatReader
enum 6109 "E-Doc. Read into Draft" implements IStructuredFormatReader, IOrderResponseBuilder
{
Extensible = true;
DefaultImplementation = IStructuredFormatReader = "E-Doc. Unspecified Impl.";
DefaultImplementation = IStructuredFormatReader = "E-Doc. Unspecified Impl.",
IOrderResponseBuilder = "E-Doc. Unspecified Impl.";

value(0; "Unspecified")
{
Expand All @@ -33,7 +34,8 @@ enum 6109 "E-Doc. Read into Draft" implements IStructuredFormatReader
value(3; "PEPPOL")
{
Caption = 'PEPPOL';
Implementation = IStructuredFormatReader = "E-Document PEPPOL Handler";
Implementation = IStructuredFormatReader = "E-Document PEPPOL Handler",
IOrderResponseBuilder = "E-Document PEPPOL Handler";
}
value(4; "MLLM")
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ namespace Microsoft.eServices.EDocument.Processing.Import;

using Microsoft.eServices.EDocument;
using Microsoft.eServices.EDocument.Processing.Interfaces;
using Microsoft.Peppol.Response;
using System.Utilities;

/// <summary>
/// Default implementations for E-Document interfaces.
/// </summary>
codeunit 6116 "E-Doc. Unspecified Impl." implements IStructureReceivedEDocument, IEDocumentFinishDraft, IStructuredFormatReader, IEDocFileFormat
codeunit 6116 "E-Doc. Unspecified Impl." implements IStructureReceivedEDocument, IEDocumentFinishDraft, IStructuredFormatReader, IOrderResponseBuilder, IEDocFileFormat
{
Access = Internal;
InherentEntitlements = X;
Expand Down Expand Up @@ -46,6 +47,15 @@ codeunit 6116 "E-Doc. Unspecified Impl." implements IStructureReceivedEDocument,
Error(EDocumentNoReadSpecifiedErr);
end;

procedure SupportsOrderResponse(EDocument: Record "E-Document"): Boolean
begin
exit(false);
end;

procedure BuildOrderResponse(EDocument: Record "E-Document"; ResponseType: Enum "E-Doc. Response Type"; var TempBlob: Codeunit "Temp Blob")
begin
end;

procedure FileExtension(): Text
begin
end;
Expand Down
Loading
Loading