Skip to content

Commit acaac80

Browse files
Groenbech96Magnus Hartvig GrønbechCopilot
authored
Default new E-Document services to import v2 and let users select the draft format (#9702)
## Why New E-Document services should default to the **v2 import pipeline** and let users actually configure it end-to-end. This needs two things that belong together: 1. Making the **Import Process** selector visible on the service card and defaulting new services to **Version 2.0**. 2. Letting the user pick the **format** v2 needs to read an incoming structured document into a draft. That format is the service-level `"Read into Draft Impl."` field (table 6103, field 33). For already-structured formats such as **PEPPOL XML** the "Structure received data" step returns `Unspecified`, so `ImportEDocumentProcess.ReadIntoDraft` falls back to this service field: ```al if EDocument."Read into Draft Impl." = "E-Doc. Read into Draft"::Unspecified then EDocument."Read into Draft Impl." := EDocument.GetEDocumentService()."Read into Draft Impl."; ``` If the service field is also `Unspecified`, `E-Doc. Unspecified Impl.` runs and import fails with **"No method to read the e-document has been provided."** Defaulting to v2 without exposing this field would leave users unable to make v2 work. ## What - Default new services to `Import Process` = **Version 2.0** (`InitValue`) and remove `Visible = false` on the selector. - Pin the **ForNAV** connector service to Version 1.0 at creation (its inbound is not migrated to v2). - Add `"Read into Draft Impl."` to the **Purchase Draft** group on the service card (shown only for Version 2.0), captioned **Draft Format**, with a tooltip covering PEPPOL vs. auto-resolved PDF/ADI. - Update module docs and add tests: new services default to v2, and the draft format is selectable and persisted for v2. [AB#580191](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/580191) --------- Co-authored-by: Magnus Hartvig Grønbech <magnushar@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 57f500b9-871d-4cf4-bdc1-751bea22d091
1 parent 7b0e5c1 commit acaac80

8 files changed

Lines changed: 68 additions & 4 deletions

File tree

src/Apps/W1/EDocument/App/CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ src/
5555
- The import pipeline implementation fields live directly on the E-Document table: `"Structure Data Impl."`, `"Read into Draft Impl."`, and `"Process Draft Impl."`. These enums determine which interface implementations run at each stage.
5656
- `"E-Document Service Status"` enum implements `IEDocumentStatus` interface -- each status value knows whether it means "in progress", "processed", or "error", via `EDocInProgressStatus`, `EDocProcessedStatus`, and `EDocErrorStatus` codeunits.
5757
- Batch processing and single-document processing are distinct code paths. Batch mode uses recurrent background jobs configured on the service (fields 21-26 on `"E-Document Service"`).
58-
- The V1.0 import process (`"Import Process" = "Version 1.0"`) collapses all pipeline stages into a single "Finish draft" step. V2.0 is the current architecture.
58+
- The V1.0 import process (`"Import Process" = "Version 1.0"`) collapses all pipeline stages into a single "Finish draft" step. V2.0 is the current architecture, and new services default to it. The import version is selectable on the service card. For V2.0 services the service-level `"Read into Draft Impl."` field ("Draft Format" on the card) selects how already-structured documents (e.g. PEPPOL XML) are read into a draft; it is the fallback used when neither the structuring step nor the receiving integration sets a reader, so leaving it `Unspecified` for such formats makes import fail.
5959
- `#if not CLEAN26` and `#if not CLEAN27` blocks mark deprecated code scheduled for removal. The old `"E-Document Integration"` enum and its `"Service Integration"` field on the service table are fully replaced by `"Service Integration V2"`.
6060
- The framework uses the "if codeunit.run" pattern extensively -- interface calls are wrapped in codeunits that run with error trapping, so a connector failure produces a logged error rather than a crash.
6161
- `"E-Document Background Jobs"` manages Job Queue Entries for recurrent import polling and batch send processing.

src/Apps/W1/EDocument/App/docs/business-logic.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ Beyond send and receive, the framework supports arbitrary actions on documents v
107107
- **Re-reading after interface calls**: After every interface call, the framework re-reads the E-Document and service records from the database (`EDocument.Get(EDocument."Entry No")`). This is because interface implementations may modify these records, and the framework needs the latest values. Note: this defensive re-read is most important when the interface parameter is **not** passed by `var`. The original intent of non-`var` parameters was to prevent implementations from modifying records through the parameter, but since AL code can always call `.Modify()` directly on any record, the protection is incomplete. When adding new interface methods, only apply this re-read pattern to procedures where the record is not passed by `var` -- if the signature already uses `var`, the caller expects modifications and re-reading is redundant.
108108
- **E-Document Status is derived**: The overall `E-Document Status` is derived from the service statuses. `EDocumentProcessing.ModifyEDocumentStatus()` computes it after every service status change using the `IEDocumentStatus` interface on the enum values.
109109
- **Import Processing Status is a FlowField**: On the E-Document table, `"Import Processing Status"` is a FlowField that reads from `"E-Document Service Status"`. You must call `CalcFields` before reading it.
110-
- **V1.0 and V2.0 coexistence**: The `"Import Process"` field on the service determines which path runs. V1.0 collapses everything into a single "Finish draft" step that calls the old `V1_ProcessEDocument` logic. The pipeline state machine still runs, but only the last step does anything for V1.0 documents.
110+
- **V1.0 and V2.0 coexistence**: The `"Import Process"` field on the service determines which path runs; new services default to Version 2.0, and the version is selectable on the service card. V1.0 collapses everything into a single "Finish draft" step that calls the old `V1_ProcessEDocument` logic. The pipeline state machine still runs, but only the last step does anything for V1.0 documents.
111+
- **Selecting the V2.0 draft format**: For Version 2.0 services the `"Read into Draft Impl."` field (shown as "Draft Format" on the service card) selects how the inbound structured e-document is read into a draft. For already-structured formats such as PEPPOL XML the structuring step returns `Unspecified`, so the read step falls back to the service's `"Read into Draft Impl."`; if that is also `Unspecified`, the `E-Doc. Unspecified Impl.` runs and import errors with "No method to read the e-document has been provided." PDF services (e.g. Azure Document Intelligence) resolve the reader automatically during structuring, so their format field can stay `Unspecified`.
111112

112113
## Inbound flow (V1.0 pipeline)
113114

src/Apps/W1/EDocument/App/src/Service/EDocumentService.Table.al

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ table 6103 "E-Document Service"
269269
{
270270
Caption = 'Import Process';
271271
DataClassification = SystemMetadata;
272+
InitValue = "Version 2.0";
272273
ToolTip = 'Specifies the import process for the document.';
273274
}
274275
field(32; "Automatic Import Processing"; Enum "E-Doc. Automatic Processing")

src/Apps/W1/EDocument/App/src/Service/EdocumentService.Page.al

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,16 @@ page 6133 "E-Document Service"
7272
field("Import Process"; Rec."Import Process")
7373
{
7474
ToolTip = 'Specifies the version of the import process to use for incoming e-documents.';
75-
Visible = false;
7675
}
7776
group(PurchaseDraft)
7877
{
7978
Caption = 'Purchase Draft';
8079
Visible = Rec."Import Process" = Enum::"E-Document Import Process"::"Version 2.0";
80+
field("Read into Draft Impl."; Rec."Read into Draft Impl.")
81+
{
82+
Caption = 'Draft Format';
83+
ToolTip = 'Specifies the format used to read the incoming structured e-document into a draft, for example PEPPOL for PEPPOL BIS invoices. Leave it as Unspecified only when the integration or a PDF reader (such as Azure Document Intelligence) determines the format automatically.';
84+
}
8185
field("Verify Totals When Posting"; Rec."Verify Purch. Total Amounts")
8286
{
8387
Caption = 'Verify totals when posting invoice.';

src/Apps/W1/EDocument/App/src/Service/docs/CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ A service is identified by a `Code[20]` primary key and configures two pluggable
88

99
For outbound documents, the service controls batch processing via `Use Batch Processing`, `Batch Mode`, `Batch Threshold`, and scheduling fields (`Batch Start Time`, `Batch Minutes between runs`). Enabling batch processing automatically creates a recurrent job queue entry (tracked by `Batch Recurrent Job Id`). For inbound documents, `Auto Import` plus `Import Start Time` and `Import Minutes between runs` configure a separate recurrent job (tracked by `Import Recurrent Job Id`). Both job queue entries are cleaned up automatically when the service is deleted.
1010

11-
The service also carries extensive inbound processing configuration: `Import Process` selects between Version 1.0 and 2.0 pipelines, `Automatic Import Processing` controls whether documents are fully processed on arrival or parked for manual review, and `Read into Draft Impl.` selects the strategy for converting structured content into draft purchase documents. A set of boolean flags (`Validate Receiving Company`, `Resolve Unit Of Measure`, `Lookup Item Reference`, `Lookup Item GTIN`, `Lookup Account Mapping`, `Validate Line Discount`, `Apply Invoice Discount`, `Verify Totals`, `Verify Purch. Total Amounts`) governs which validation and enrichment steps run during import.
11+
The service also carries extensive inbound processing configuration: `Import Process` selects between Version 1.0 and 2.0 pipelines (new services default to Version 2.0, and the version is selectable on the service card), `Automatic Import Processing` controls whether documents are fully processed on arrival or parked for manual review, and `Read into Draft Impl.` selects the strategy (the "Draft Format", e.g. PEPPOL) for converting structured content into draft purchase documents -- for Version 2.0 services this is exposed on the service card so users can pick the format their integration delivers. A set of boolean flags (`Validate Receiving Company`, `Resolve Unit Of Measure`, `Lookup Item Reference`, `Lookup Item GTIN`, `Lookup Account Mapping`, `Validate Line Discount`, `Apply Invoice Discount`, `Verify Totals`, `Verify Purch. Total Amounts`) governs which validation and enrichment steps run during import.
1212

1313
The `E-Doc. Service Supported Type` table (`EDocServiceSupportedType.Table.al`, table 6122) bridges services to document types -- a service can handle any subset of the `E-Document Type` enum values. The `Service Participant` table (`Participant/ServiceParticipant.Table.al`, table 6104) links customers or vendors to specific services with per-participant identifiers used for electronic addressing (e.g., PEPPOL participant IDs).
1414

src/Apps/W1/EDocument/Test/src/LibraryEDocument.Codeunit.al

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,7 @@ codeunit 139629 "Library - E-Document"
799799
EDocService.Code := LibraryUtility.GenerateRandomCode20(EDocService.FieldNo(Code), Database::"E-Document Service");
800800
EDocService."Document Format" := "E-Document Format"::Mock;
801801
EDocService."Service Integration" := Integration;
802+
EDocService."Import Process" := Enum::"E-Document Import Process"::"Version 1.0";
802803
EDocService.Insert();
803804

804805
CreateSupportedDocTypes(EDocService);
@@ -816,6 +817,7 @@ codeunit 139629 "Library - E-Document"
816817
EDocService.Code := LibraryUtility.GenerateRandomCode20(EDocService.FieldNo(Code), Database::"E-Document Service");
817818
EDocService."Document Format" := "E-Document Format"::Mock;
818819
EDocService."Service Integration V2" := Integration;
820+
EDocService."Import Process" := Enum::"E-Document Import Process"::"Version 1.0";
819821
EDocService.Insert();
820822

821823
CreateSupportedDocTypes(EDocService);
@@ -834,6 +836,7 @@ codeunit 139629 "Library - E-Document"
834836
EDocService.Code := LibraryUtility.GenerateRandomCode20(EDocService.FieldNo(Code), Database::"E-Document Service");
835837
EDocService."Document Format" := EDocDocumentFormat;
836838
EDocService."Service Integration" := EDocIntegration;
839+
EDocService."Import Process" := Enum::"E-Document Import Process"::"Version 1.0";
837840
EDocService.Insert();
838841

839842
CreateSupportedDocTypes(EDocService);
@@ -969,6 +972,7 @@ codeunit 139629 "Library - E-Document"
969972
EDocService.Code := 'TESTRECEIVE';
970973
EDocService."Document Format" := "E-Document Format"::Mock;
971974
EDocService."Service Integration V2" := Integration;
975+
EDocService."Import Process" := Enum::"E-Document Import Process"::"Version 1.0";
972976
EDocService.Insert();
973977
end;
974978
end;
@@ -983,6 +987,7 @@ codeunit 139629 "Library - E-Document"
983987
EDocService.Code := 'TESTRECEIVE';
984988
EDocService."Document Format" := "E-Document Format"::Mock;
985989
EDocService."Service Integration" := Integration;
990+
EDocService."Import Process" := Enum::"E-Document Import Process"::"Version 1.0";
986991
EDocService.Insert();
987992
end;
988993
end;
@@ -996,6 +1001,7 @@ codeunit 139629 "Library - E-Document"
9961001
EDocService.Code := 'BIERRRECEIVE';
9971002
EDocService."Document Format" := "E-Document Format"::Mock;
9981003
EDocService."Service Integration V2" := Integration;
1004+
EDocService."Import Process" := Enum::"E-Document Import Process"::"Version 1.0";
9991005
EDocService.Insert();
10001006
end;
10011007
end;
@@ -1010,6 +1016,7 @@ codeunit 139629 "Library - E-Document"
10101016
EDocService.Code := 'BIERRRECEIVE';
10111017
EDocService."Document Format" := "E-Document Format"::Mock;
10121018
EDocService."Service Integration" := Integration;
1019+
EDocService."Import Process" := Enum::"E-Document Import Process"::"Version 1.0";
10131020
EDocService.Insert();
10141021
end;
10151022
end;
@@ -1023,6 +1030,7 @@ codeunit 139629 "Library - E-Document"
10231030
EDocService.Code := 'CIERRRECEIVE';
10241031
EDocService."Document Format" := "E-Document Format"::Mock;
10251032
EDocService."Service Integration V2" := Integration;
1033+
EDocService."Import Process" := Enum::"E-Document Import Process"::"Version 1.0";
10261034
EDocService.Insert();
10271035
end;
10281036
end;
@@ -1037,6 +1045,7 @@ codeunit 139629 "Library - E-Document"
10371045
EDocService.Code := 'CIERRRECEIVE';
10381046
EDocService."Document Format" := "E-Document Format"::Mock;
10391047
EDocService."Service Integration" := Integration;
1048+
EDocService."Import Process" := Enum::"E-Document Import Process"::"Version 1.0";
10401049
EDocService.Insert();
10411050
end;
10421051
end;

src/Apps/W1/EDocument/Test/src/Processing/EDocProcessTest.Codeunit.al

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,4 +1443,49 @@ codeunit 139883 "E-Doc Process Test"
14431443
ItemReference.Insert();
14441444
end;
14451445

1446+
[Test]
1447+
procedure NewServiceDefaultsToImportProcessV2()
1448+
var
1449+
EDocumentService: Record "E-Document Service";
1450+
begin
1451+
// [WHEN] A new E-Document Service record is initialized
1452+
EDocumentService.Init();
1453+
// [THEN] Import Process defaults to Version 2.0
1454+
Assert.AreEqual(
1455+
EDocumentService."Import Process"::"Version 2.0", EDocumentService."Import Process",
1456+
'New services must default to the v2 draft pipeline.');
1457+
end;
1458+
1459+
[Test]
1460+
procedure DraftFormatSelectableForImportProcessV2()
1461+
var
1462+
EDocService: Record "E-Document Service";
1463+
EDocServicePage: TestPage "E-Document Service";
1464+
begin
1465+
// [FEATURE] [E-Document] [Import]
1466+
// [SCENARIO] The draft format ("Read into Draft Impl.") is selectable on the service card for Version 2.0 services
1467+
if EDocService.Get('V2DRAFTFMT') then
1468+
EDocService.Delete();
1469+
1470+
// [GIVEN] An E-Document Service using import process Version 2.0
1471+
EDocService.Init();
1472+
EDocService.Code := 'V2DRAFTFMT';
1473+
EDocService."Import Process" := EDocService."Import Process"::"Version 2.0";
1474+
EDocService.Insert();
1475+
1476+
// [WHEN] Opening the service card and selecting a draft format
1477+
EDocServicePage.OpenEdit();
1478+
EDocServicePage.GoToRecord(EDocService);
1479+
// [THEN] The draft format field is available so the user can tell v2 how to read the incoming document
1480+
Assert.IsTrue(EDocServicePage."Read into Draft Impl.".Editable(), 'Draft Format must be editable for Version 2.0 services.');
1481+
EDocServicePage."Read into Draft Impl.".SetValue(Enum::"E-Doc. Read into Draft"::PEPPOL);
1482+
EDocServicePage.Close();
1483+
1484+
// [THEN] The selected format is persisted on the service
1485+
EDocService.Find();
1486+
Assert.AreEqual(
1487+
Enum::"E-Doc. Read into Draft"::PEPPOL, EDocService."Read into Draft Impl.",
1488+
'The selected draft format must be stored on the service.');
1489+
end;
1490+
14461491
}

src/Apps/W1/EDocumentConnectors/ForNAV/App/src/Setup/ForNAVPeppolSetup.Table.al

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Microsoft.EServices.EDocumentConnector.ForNAV;
66

77
using Microsoft.eServices.EDocument;
8+
using Microsoft.eServices.EDocument.Processing.Import;
89
using Microsoft.Foundation.Address;
910
using Microsoft.Foundation.Company;
1011
using Microsoft.Foundation.Reporting;
@@ -445,6 +446,9 @@ table 6414 "ForNAV Peppol Setup"
445446
EDocumentService."Service Integration V2" := EDocumentService.ForNAVServiceIntegration();
446447
EDocumentService."Document Format" := "E-Document Format"::"PEPPOL BIS 3.0";
447448
EDocumentService."Use Batch Processing" := false;
449+
// ForNAV inbound import is not migrated to the v2 draft pipeline, so keep the service on Version 1.0
450+
// instead of inheriting the new default of the "Import Process" field.
451+
EDocumentService."Import Process" := "E-Document Import Process"::"Version 1.0";
448452
EDocumentService.Insert();
449453

450454
EDocServiceSupportedType.SetRange(EDocServiceSupportedType."E-Document Service Code", EDocumentService.Code);

0 commit comments

Comments
 (0)