Skip to content

[DE] Support registration numbers in E-Documents - #10349

Open
Milica Đukić (djukicmilica) wants to merge 13 commits into
microsoft:mainfrom
djukicmilica:bug/646793-edoc-de-registration-no
Open

[DE] Support registration numbers in E-Documents#10349
Milica Đukić (djukicmilica) wants to merge 13 commits into
microsoft:mainfrom
djukicmilica:bug/646793-edoc-de-registration-no

Conversation

@djukicmilica

@djukicmilica Milica Đukić (djukicmilica) commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add Registration No. as the final fallback when matching imported E-Document vendors
  • support German FC tax identifiers in XRechnung, ZUGFeRD, and PEPPOL exports
  • validate imported receiving-company Registration No. against Company Information
  • add focused coverage for Registration No. vendor matching and XRechnung/ZUGFeRD exports

Validation

  • AL editor diagnostics report no errors in all 12 changed files
  • git diff --check passes
  • package build was not available because the VS Code workspace root is a generic multi-project container and does not resolve an active app.json

Fixes
AB#646793

@djukicmilica
Milica Đukić (djukicmilica) requested a review from a team as a code owner August 18, 2026 11:12
@github-actions github-actions Bot added AL: Apps (W1) Add-on apps for W1 From Fork Pull request is coming from a fork Other GitHub request for other area than SCM, Finance or Integration Ownership: Needs Review Ownership is Other, low confidence, or needs manual correction Linked Issue is linked to a Azure Boards work item labels Aug 18, 2026
@github-actions github-actions Bot added this to the Version 29.0 milestone Aug 18, 2026
/// <param name="PhoneNo">Vendor's Phone number.</param>
/// <returns>Vendor number if exists or empty string.</returns>
procedure FindVendorByPhoneNo(PhoneNo: Text): Code[20]

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\ —\ Agent}$

The new OnBeforeValidateReceivingCompanyInfo integration event (with its [IntegrationEvent(false, false)] attribute, header, and empty begin...end; body) is inserted directly between the procedure FindVendorByPhoneNo(PhoneNo: Text): Code[20] header and its own var/begin section. A procedure header must be followed immediately by that procedure's own optional var section and begin...end — nesting a second, complete procedure declaration in between is invalid AL syntax and will fail to compile. Move the new event procedure to its own location (e.g. immediately after ValidateReceivingCompanyInfo, or at the end of the codeunit near other [IntegrationEvent] declarations) so FindVendorByPhoneNo's header is directly followed by its var/begin block.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

    procedure FindVendorByPhoneNo(PhoneNo: Text): Code[20]
    var
        Vendor: Record Vendor;
        RecordMatchMgt: Codeunit "Record Match Mgt.";
        PhoneNoNearness: Integer;
    begin

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4


if CompanyInfo.GLN + CompanyInfo."VAT Registration No." = '' then
Error(MissingCompInfGLNOrVATRegNoErr, CompanyInfo.TableCaption());
if CompanyInfo.GLN + CompanyInfo."VAT Registration No." + CompanyInfo."Registration No." = '' then

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\ —\ Error\ Handling}$

This validation raises a plain Error when Company Information has no GLN, VAT Registration No., or Registration No., but the user can correct that setup directly on the related record. Use ErrorInfo with a Show-it navigation action to Company Information instead of a dead-end dialog.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

CompanyInformation: Record "Company Information";
IsHandled: Boolean;
begin
OnBeforeValidateReceivingCompanyInfo(EDocument, IsHandled);

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\ —\ Events}$

ValidateReceivingCompanyInfo raises OnBeforeValidateReceivingCompanyInfo(…, IsHandled) without first resetting IsHandled := false;. That matches the IsHandled anti-pattern: the publisher becomes non-deterministic if this variable is ever reused, and subscribers can inherit a stale handled state. Reset IsHandled immediately before publishing.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

        IsHandled := false;
        OnBeforeValidateReceivingCompanyInfo(EDocument, IsHandled);
        if IsHandled then
            exit;

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

if RegistrationNo = '' then
exit('');

Vendor.SetRange("Registration No.", RegistrationNo);

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}$

FindVendorByRegistrationNo filters Vendor and reads only "No." from the first match, but it does not call SetLoadFields before FindFirst. On the wide Vendor table this still materializes the full row for a lookup that only needs the primary key.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

Vendor.SetLoadFields("No.");
        Vendor.SetRange("Registration No.", RegistrationNo);
        if Vendor.FindFirst() then

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

var
CompanyInformation: Record "Company Information";
EDocumentErrorHelper: Codeunit "E-Document Error Helper";
InvalidCompanyRegistrationNoErr: Label 'The receiving company registration number %1 does not match Company Information.', Comment = '%1 = Registration No.';

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\ —\ Privacy}$

This error message interpolates the receiving company registration number into the text passed to EDocumentErrorHelper.LogErrorMessage. That helper forwards Message as a FeatureTelemetry custom dimension and also uses it as the FeatureTelemetry.LogError ErrorText fallback, so the registration number is sent to telemetry verbatim.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

        InvalidCompanyRegistrationNoErr: Label 'The receiving company registration number does not match Company Information.';
    begin
        if EDocument."Receiving Company Reg. No. DE" = '' then
            exit;

        IsHandled := true;
        CompanyInformation.Get();
        if CompanyInformation."Registration No." <> EDocument."Receiving Company Reg. No. DE" then
            EDocumentErrorHelper.LogErrorMessage(
                EDocument, CompanyInformation, CompanyInformation.FieldNo("Registration No."),
                InvalidCompanyRegistrationNoErr);

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

field(13916; "Receiving Company Reg. No. DE"; Text[20])
{
Caption = 'Receiving Company Registration No.';
DataClassification = CustomerContent;

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\ —\ Privacy}$

The new "Receiving Company Reg. No. DE" field stores a company registration number, but privacy guidance classifies organization identifiers such as company registration numbers as OrganizationIdentifiableInformation rather than CustomerContent.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

            DataClassification = OrganizationIdentifiableInformation;

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

CompanyInformation: Record "Company Information";
IsHandled: Boolean;
begin
OnBeforeValidateReceivingCompanyInfo(EDocument, IsHandled);

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\ —\ Security}$

OnBeforeValidateReceivingCompanyInfo exposes a mutable var IsHandled gate, and ValidateReceivingCompanyInfo exits when a subscriber flips it to true. That makes the receiving-company validation advisory: any subscriber on the tenant can bypass the publisher's check instead of only tightening it. Keep the decision inside the publisher and expose a post-check or tighten-only hook instead.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

var
CompanyInformation: Record "Company Information";
EDocumentErrorHelper: Codeunit "E-Document Error Helper";
InvalidCompanyRegistrationNoErr: Label 'The receiving company registration number %1 does not match Company Information.', Comment = '%1 = Registration No.';

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\ —\ Style}$

InvalidCompanyRegistrationNoErr is declared inside the procedure-local var block. Per the style guidance, Labels should live in the codeunit's top-level var section so XLIFF extraction and translation review do not depend on fragile procedure-scope behavior.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

var
SalesInvoiceHeader: Record "Sales Invoice Header";
TempXMLBuffer: Record "XML Buffer" temporary;
SupplierTaxSchemeTok: Label '/ubl:Invoice/cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme', Locked = true;

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\ —\ Style}$

SupplierTaxSchemeTok is declared inside a test procedure's local var block. The style rule requires Labels at object scope so the token remains stable for XLIFF extraction and object-level review instead of being hidden inside one procedure.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

var
SalesInvoiceHeader: Record "Sales Invoice Header";
TempXMLBuffer: Record "XML Buffer" temporary;
SellerTaxRegistrationTok: Label '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID', Locked = true;

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\ —\ Style}$

SellerTaxRegistrationTok is declared inside a test procedure's local var block. Even in test code, procedure-scoped Labels are fragile for localization tooling; move the token Label to the codeunit's top-level var section.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4


[Test]
procedure FindVendorByRegistrationNo()
var

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\ —\ Testing}$

FindVendorByRegistrationNo hand-rolls a Vendor with Init/manual "No." assignment/Insert instead of creating it through a test Library codeunit. That bypasses number-series and mandatory-field setup, so the fixture can break as the vendor schema evolves rather than validating the registration-number lookup behavior.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

var
        Vendor: Record Vendor;
        EDocumentImportHelper: Codeunit "E-Document Import Helper";
        LibraryPurchase: Codeunit "Library - Purchase";
        LibraryUtility: Codeunit "Library - Utility";
        RegistrationNo: Text[20];
    begin
        // [SCENARIO 646793] A vendor can be resolved by Registration No. when other identifiers are unavailable.
        RegistrationNo := CopyStr(LibraryUtility.GenerateGUID(), 1, MaxStrLen(RegistrationNo));
        LibraryPurchase.CreateVendor(Vendor);
        Vendor.Validate("Registration No.", RegistrationNo);
        Vendor.Modify(true);

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

if EDocument."Receiving Company Reg. No. DE" = '' then
exit;

IsHandled := true;

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\ —\ Error\ Handling}$

ValidateReceivingCompanyInfoByRegistrationNo marks the event handled and then calls CompanyInformation.Get() unconditionally. If the Company Information record is missing, importing a document with "Receiving Company Reg. No. DE" now aborts with an unhandled record-not-found error instead of falling back to the standard validator or logging a setup problem. Guard Get() and surface missing setup explicitly before setting IsHandled.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

EDocument."Receiving Company Address" := CopyStr(GetNodeByPath(TempXMLBuffer, '/' + DocumentType + 'rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty/ram:PostalTradeAddress/ram:LineOne'), 1, MaxStrLen(EDocument."Receiving Company Address"));
EDocument."Receiving Company VAT Reg. No." := CopyStr(GetNodeByPath(TempXMLBuffer, '/' + DocumentType + '/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty/ram:SpecifiedTaxRegistration'), 1, MaxStrLen(EDocument."Receiving Company VAT Reg. No."));
TaxRegistrationPath := '/' + DocumentType + '/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty/ram:SpecifiedTaxRegistration/ram:ID';
case GetAttributeByPath(TempXMLBuffer, TaxRegistrationPath + '/@schemeID') of

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\ —\ Error\ Handling}$

ParseBuyerTradeParty handles only scheme IDs 'VA' and 'FC' and has no else/guard branch for any other or malformed value. When an incoming ZUGFeRD document carries an unexpected tax-registration scheme, the import silently drops the identifier and continues with blank receiving-company identifiers, which can lead to weaker matching and unclear downstream validation errors.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

if CompanyID <> '' then
exit;

CompanyInformation.SetLoadFields("Registration No.");

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\ —\ Error\ Handling}$

The new registration-number fallback in GetAccountingSupplierPartyTaxScheme calls CompanyInformation.Get() unconditionally after the standard provider leaves CompanyID blank. In a company without a Company Information record, PEPPOL export now fails with a raw record-not-found error instead of a clear setup/validation failure.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

if PartyLegalEntityCompanyID <> '' then
exit;

CompanyInformation.SetLoadFields("Registration No.");

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\ —\ Error\ Handling}$

SetRegistrationNoAsLegalEntityFallback also assumes Company Information always exists and calls Get() without a guard. If that singleton record is absent, the new legal-entity fallback throws an unhandled record-not-found error while composing PEPPOL party data.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

/// <param name="PhoneNo">Vendor's Phone number.</param>
/// <returns>Vendor number if exists or empty string.</returns>
procedure FindVendorByPhoneNo(PhoneNo: Text): Code[20]

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\ —\ Events}$

The new [IntegrationEvent(false, false)] publisher OnBeforeValidateReceivingCompanyInfo is physically inserted between the FindVendorByPhoneNo procedure signature (line 572) and that same procedure's var/begin/end body (lines 579-597) — i.e. a second procedure's full declaration (signature + begin/end) sits inside what should be one contiguous FindVendorByPhoneNo member. This is not merely a style nit: as written, FindVendorByPhoneNo's var section and body are separated from its own header by an entire nested procedure, which is not valid top-level AL member layout and blocks compilation of this codeunit. Move OnBeforeValidateReceivingCompanyInfo to its own standalone position in the codeunit, after a complete, uninterrupted FindVendorByPhoneNo procedure.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

IsHandled := true;
CompanyInformation.Get();
if CompanyInformation."Registration No." <> EDocument."Receiving Company Reg. No. DE" then
EDocumentErrorHelper.LogErrorMessage(

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\ —\ Privacy}$

The error message raised in ValidateReceivingCompanyInfoByRegistrationNo embeds the incoming receiving-company registration number and is passed to EDocumentErrorHelper.LogErrorMessage. That helper forwards Message to FeatureTelemetry.LogError, where it becomes telemetry payload (ErrorText/alErrorText), so the registration number is emitted to telemetry as system metadata rather than kept purely in the user-facing error.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

var
SalesInvoiceHeader: Record "Sales Invoice Header";
TempXMLBuffer: Record "XML Buffer" temporary;
SupplierTaxSchemeTok: Label '/ubl:Invoice/cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme', Locked = true;

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\ —\ Style}$

SupplierTaxSchemeTok is introduced as a procedure-local Label inside ExportPostedSalesInvoiceInXRechnungFormatVerifySupplierRegistrationNo. Per the referenced guidance, Labels should be declared at object scope rather than inside a procedure var block.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

begin
// [SCENARIO 646793] A vendor can be resolved by Registration No. when other identifiers are unavailable.
RegistrationNo := CopyStr(LibraryUtility.GenerateGUID(), 1, MaxStrLen(RegistrationNo));
Vendor.Init();

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\ —\ Testing}$

The new FindVendorByRegistrationNo test hand-rolls a Vendor with Init/Insert and an invented primary key. BCQuality testing guidance requires using the maintained test Library codeunits for fixtures so the record stays valid as table requirements evolve. Create the vendor through a library helper, then set the registration number needed by the scenario.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

ShipToAddress.SetLoadFields(GLN);
if (ShipToCode <> '') and ShipToAddress.Get(CustomerNo, ShipToCode) then
DeliveryGLN := ShipToAddress.GLN;
if DeliveryGLN = '' then

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\ —\ Testing}$

The new ZUGFeRD delivery branch falls back to the customer GLN when the ship-to GLN is blank, but the added ZUGFeRD tests only cover the ship-to-present and GLN-disabled cases. Add a case with a blank ship-to GLN and assert ShipToTradeParty/GlobalID falls back to the customer GLN so this new branch is exercised.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4


using Microsoft.Foundation.Company;

codeunit 13916 "E-Doc. Import Subscribers DE"

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\ —\ Upgrade}$

The PR introduces codeunit 13916 "E-Doc. Import Subscribers DE" (src/Apps/DE/EDocumentDE/app/src/EDocumentImportSubscribersDE.Codeunit.al), but the same EDocumentDE app already defines codeunit 13916 "Export XRechnung Document" (src/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al). Two codeunits in the same app cannot share an object ID; this blocks compilation/publishing of the app as-is. Assign the new subscriber codeunit an unused ID in the app's reserved range.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

/// <param name="PhoneNo">Vendor's Phone number.</param>
/// <returns>Vendor number if exists or empty string.</returns>
procedure FindVendorByPhoneNo(PhoneNo: Text): Code[20]

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\ —\ Style}$

Two leaves (al-style-review and al-events-review) independently flagged the same defect, merged here: the new OnBeforeValidateReceivingCompanyInfo integration-event publisher (with its [IntegrationEvent(false, false)] attribute) is inserted between FindVendorByPhoneNo's procedure signature and its own var/begin block. This nests one full procedure declaration inside another and leaves the codeunit syntactically malformed — the affected object will not compile as written. Real-world impact is build-breaking (would normally be blocker/major), but per the DO contract this is capped at minor because it has no direct BCQuality citation; it should be promoted to a knowledge-backed rule and treated as blocking before merge. Move the event publisher out from between FindVendorByPhoneNo's header and its var section so the phone-number procedure's var/begin/end stays contiguous.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

    procedure FindVendorByPhoneNo(PhoneNo: Text): Code[20]
    var
        Vendor: Record Vendor;
        RecordMatchMgt: Codeunit "Record Match Mgt.";
        PhoneNoNearness: Integer;
    begin
        if PhoneNo = '' then
            exit('');

        PhoneNo := DelChr(PhoneNo, '=', DelChr(PhoneNo, '=', '0123456789'));

        Vendor.SetCurrentKey(Blocked);
        Vendor.SetLoadFields("Phone No.");
        if Vendor.FindSet() then
            repeat
                PhoneNoNearness := RecordMatchMgt.CalculateStringNearness(PhoneNo, Vendor."Phone No.", MatchThreshold(), NormalizingFactor());
                if PhoneNoNearness >= RequiredNearness() then
                    exit(Vendor."No.");
            until Vendor.Next() = 0;
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeValidateReceivingCompanyInfo(EDocument: Record "E-Document"; var IsHandled: Boolean)
    begin
    end;

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

LibraryUtility: Codeunit "Library - Utility";
RegistrationNo: Text[20];
begin
// [SCENARIO 646793] A vendor can be resolved by Registration No. when other identifiers are unavailable.

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.

[AI test]?

until Vendor.Next() = 0;
end;

[IntegrationEvent(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\ —\ Events}$

The new integration event OnGetReceivingCompanyRegistrationNo fires at the start of ValidateReceivingCompanyInfo, but its name does not encode either the host routine or the firing position. Rename it to follow the OnBefore.../OnAfter... convention (e.g. OnValidateReceivingCompanyInfoOnBeforeCheckRegistrationNo or similar) so subscribers can tell when it runs without reading the publisher.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

OnGetReceivingCompanyRegistrationNo(EDocument, ReceivingCompanyRegistrationNo);
CompanyInformation.Get();

if ReceivingCompanyRegistrationNo <> '' then begin

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\ —\ Error\ Handling}$

When ReceivingCompanyRegistrationNo is present, the unconditional exit; stops validation immediately after the registration-number comparison. That means a matching registration number now suppresses the existing GLN/VAT checks, and a mismatch hides any additional identifier errors, so inbound documents can miss or under-report receiving-company validation failures. Continue into the existing identifier-validation path instead of exiting unconditionally.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

exit('');

Vendor.SetLoadFields("No.");
Vendor.SetRange("Registration Number", RegistrationNo);

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}$

The new Registration Number fallback filters Vendor on "Registration Number" and immediately calls FindFirst(), but the W1 Vendor table has no key on that field. That matches this article's anti-pattern: once the GLN/VAT lookups miss, FindFirst() has to read vendors through an unindexed filter instead of an indexed access path, which also scales poorly as vendor volume grows. Add a supporting key for "Registration Number" (for example via a Vendor tableextension) or route this match through an existing keyed lookup before using it in import matching.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

end;

procedure GetAccountingSupplierPartyTaxScheme(var CompanyID: Text; var CompanyIDSchemeID: Text; var TaxSchemeID: Text)
var

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\ —\ Testing}$

PEPPOL 3.0 DE now falls back to Company Information."Registration No." for supplier tax-scheme/legal-entity data, but the diff does not add a PEPPOL test that exports with blank GLN/VAT and asserts the new FC/legal-entity output. Because these DE-only fallback branches are new behavior, leaving them untested makes it easy to break the Registration No. mapping without any PEPPOL test failing.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

procedure ValidateReceivingCompanyInfo(EDocument: Record "E-Document")
var
CompanyInformation: Record "Company Information";
ReceivingCompanyRegistrationNo: Text[20];

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\ —\ Testing}$

The import flow now has a new registration-number path, but the diff only adds an isolated helper test for FindVendor('', '', '', RegistrationNo). There is still no test that imports an FC-identified XRechnung/ZUGFeRD document and verifies that the parsed registration number drives vendor matching and the new receiving-company registration-number validation/subscriber path. Without an end-to-end import test, regressions in the new DE wiring can ship unnoticed.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.33.4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AL: Apps (W1) Add-on apps for W1 From Fork Pull request is coming from a fork Linked Issue is linked to a Azure Boards work item Other GitHub request for other area than SCM, Finance or Integration Ownership: Needs Review Ownership is Other, low confidence, or needs manual correction

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants