Skip to content

[main] bug 644746 - Add configurable EPO Service Setup for gov.cz domain migration - #9857

Open
DavidHolusa wants to merge 5 commits into
mainfrom
bugs/644746-main-NewEPOAPIUrl
Open

[main] bug 644746 - Add configurable EPO Service Setup for gov.cz domain migration#9857
DavidHolusa wants to merge 5 commits into
mainfrom
bugs/644746-main-NewEPOAPIUrl

Conversation

@DavidHolusa

@DavidHolusa DavidHolusa commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

What & why

The Czech Financial Administration is migrating from the adisspr.mfcr.cz domain to mojedane.gov.cz. The EPO (Electronic Filing Office) endpoint URL was previously hardcoded in the EPO API Submission CZL codeunit. This change introduces a configurable EPO Service Setup CZL table and page so the endpoint URL can be managed by administrators without a code change. The default URL is updated to the new https://mojedane.gov.cz/dpr/ domain. The EPO service is also registered as a Service Connection for discoverability. A typo in GetHttpResonse() → GetHttpResponse() is fixed as well.

Linked work

Fixes AB#644746

How I validated this

  • I read the full diff and it contains only changes I intended.
  • I built the affected app(s) locally with no new analyzer warnings.
  • I ran the change in Business Central and confirmed it behaves as expected.
  • I added or updated tests for the new behavior, or explained below why none are needed.

What I tested and the outcome

Opened the new EPO Service Setup page; verified the default URL is set to https://mojedane.gov.cz/dpr/epo_podani?otevriFormular=1 on first insert.
Toggled the Enabled flag on/off; confirmed the endpoint field becomes non-editable when enabled and the warning text is shown.
Used Set URL to Default action to restore the URL after manual edits.
Verified the EPO service appears in the Service Connections page with the correct status and URL.
Submitted a VAT report via EPO and confirmed the form URL is returned correctly from the new endpoint.
No tests added — test coverage for EPO submission will be addressed in a follow-up.

Risk & compatibility

Breaking change: The GetHttpResonse() method was renamed to GetHttpResponse() (typo fix). Since the codeunit has Access = Internal, this does not affect external consumers.
Data migration: On first access the EPO Service Setup CZL record is auto-initialized with the new default URL, so no upgrade codeunit is needed.
URL transition: The Czech Financial Administration will maintain both old and new URLs during a transitional period. Existing installations that upgrade will automatically use the new default URL on first setup record creation.

- Introduced new table and page for EPO Service Setup.
- Updated EPO API Submission and VAT Report Submit codeunits to utilize new service setup.
- Enhanced permission sets to include access to EPO Service Setup.
@DavidHolusa
DavidHolusa requested a review from a team July 30, 2026 12:16
@github-actions github-actions Bot added the Finance GitHub request for Finance area label Jul 30, 2026
@github-actions github-actions Bot modified the milestone: Version 29.0 Jul 30, 2026
ventselartur
ventselartur previously approved these changes Aug 3, 2026
- Replace TestField with ErrorInfo including navigation action to EPO Service Setup page
- Extract GetOrInitEPOServiceSetup() helper procedure to avoid code duplication
- Add customer consent confirmation when enabling EPO service
- Move DataClassification to table level (SystemMetadata) and remove redundant field-level declarations
- Move Label variables from local procedure vars to global var section (page and codeunit level)
- Fix alphabetical ordering in permission set
@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Agentic PR Review - Round 1

Recommendation: Request Changes

What this PR does

This PR moves the Czech EPO open-form endpoint from a hardcoded URL into a new EPO Service Setup CZL table/page and registers it in Service Connections. The domain migration itself is valid, and the Service Connection event pattern matches existing CZ setup patterns. The fix is not correct yet because the submission path now depends on setup data that may not exist, and one auto-create path can create the setup without the default URL.

Suggestions

S1 - Setup defaults are not reliable
Create or update the EPO setup record before TrySend reads it, and make every auto-create path run the defaulting logic. Today TrySend can fail if no setup page was opened first, and Service Connections uses Insert() so it can create a record with a blank endpoint.

S2 - Missing regression test for first use
Add a CZ test for first use with no existing EPO setup record. It should prove that the default endpoint is created and that Service Connections cannot leave a blank endpoint.

Risk assessment and necessity

Risk: The regression surface is the CZ VAT report EPO submission flow. Existing tenants could move from a working hardcoded URL to an error about a missing or disabled setup record, or to a blank endpoint if Service Connections creates the record first. The procedure rename is internal, and no BaseApp event publisher change was found in this diff.

Necessity: The work item describes a real government domain migration, so changing the endpoint and allowing configuration is justified. The scope is acceptable for the bug, but it must preserve first-use behavior for existing customers and create a valid default setup record on every entry point.


[AI-PR-REVIEW] version=1 system=github pr=9857 round=1 by=alexei-dobriansky at=2026-08-03T10:03:14.847Z lastSha=b48b5fddb719073d19d41c2625e4a489158a2aec suggestions=S1,S2

var
EPOServiceSetupRecordRef: RecordRef;
begin
GetOrInitEPOServiceSetup();

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

HandleEPOServiceConnection calls GetOrInitEPOServiceSetup(), which inserts the setup record from inside the OnRegisterServiceConnection subscriber when no row exists. This event runs while the Service Connections list is being populated, so simply rendering that page now performs a database write and can fail for sessions without insert permission on EPO Service Setup CZL. Keep the subscriber read-only: treat a missing setup record as disabled, or move first-time initialization to an explicit setup flow/page instead of the subscriber.

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


fields
{
field(1; "Primary Key"; Code[10])

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 new "EPO Service Setup CZL" table declares table-level DataClassification = SystemMetadata and relies on it cascading to the Normal fields "Primary Key", "Limit Response Time", and Enabled instead of setting an explicit field-level DataClassification on each. AppSourceCop AS0016 requires an explicit field-level DataClassification on every Normal field; relying on the table default is non-compliant even though the field "Open Form Endpoint" itself correctly declares CustomerContent explicitly.

Knowledge:

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

OpenFormUriTok: Label 'epo_podani?otevriFormular=1', Locked = true;
ShowEPOServiceSetupLbl: Label 'Show EPO Service Setup';

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

src/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/EPOAPIMgtCZL.Codeunit.al contains a second, empty var block immediately before TryGetFormUrl(). Remove the redundant block so the object has a single meaningful declaration section; leaving an empty declaration block adds noise and makes the code look accidentally incomplete.

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

ServiceConnection.InsertServiceConnection(
ServiceConnection, EPOServiceSetupRecordRef.RecordId, EPOServiceSetupCZL.TableCaption(), EPOServiceSetupCZL."Open Form Endpoint", Page::"EPO Service Setup CZL");
end;
} No newline at end of file

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

src/Apps/CZ/CoreLocalizationPack/app/Src/Codeunits/EPOAPIMgtCZL.Codeunit.al is checked in without a trailing newline. Add the final newline so the file follows the usual source-text convention and avoids needless end-of-file diff noise in later edits.

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


RestClient.Initialize();
RestClient.SetTimeOut(Timeout);
HttpResponseMessage := RestClient.Post(RequestUri, RequestHttpContent);

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

The new EPO API wrapper makes an outbound RestClient.Post call and raises an error on non-success responses, but the failure path emits no Session.LogMessage/Session.LogError telemetry. That leaves production EPO outages and HTTP failures invisible in telemetry; add a stable failure event before raising the error, including the endpoint/result details and an appropriate scope/verbosity.

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

GetOrInitEPOServiceSetup();

HttpContent := HttpContent.Create(Content);
TrySend(EPOServiceSetupCZL."Open Form Endpoint", EPOServiceSetupCZL."Limit Response Time", HttpContent, ResponseHttpContent);

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

The new EPO POST flow assumes every successful response is XML with a top-level URL node: it parses GetContent().AsXmlDocument() and immediately dereferences SelectSingleNode('URL', ...) without checking the payload shape first. Because the endpoint is now configurable, a misconfigured URL or an upstream HTML/XML error page can fail here with an opaque XML/node error instead of a clear service-response message. Validate the response format and the presence of the URL element before dereferencing it, and raise an explicit error when the endpoint returns an unexpected payload.

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

@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Agentic PR Review - Round 2

Recommendation: Request Changes

What this PR does

This PR moves the Czech EPO endpoint to a configurable setup record and registers it as a Service Connection for AB#644746. The new commits try to default the setup and add consent when the service is enabled, but the first-use path is still not safe: the codeunit creates a blank setup record without running the insert trigger, and the submit flow now ignores a failed try function. That means the default endpoint can still be missing, and a failed submission can continue into archive and hyperlink code.

Status of previous suggestions
ID Title Status Author response
S1 Setup defaults are not reliable Not addressed No reply found. GetOrInitEPOServiceSetup() still uses Insert() without running OnInsert, so it can create a setup record without the default endpoint.
S2 Missing regression test for first use Not addressed No reply found. The PR still has no test file changes, and the first-use setup path remains untested.
New observations (commits since round 1)

S3 - Extra var section breaks the object
Remove the second global �ar line in EPOAPIMgtCZL.Codeunit.al before TryGetFormUrl. It has no variables under it and sits directly before an attribute, so the object should not compile.

S4 - Try function result is ignored
Check the return value from EPOAPIMgt.TryGetFormUrl(XmlDocumentSubmission, FormUrl) and raise GetLastErrorText() when it fails. Without that check, a disabled service or failed HTTP call can continue into archive and hyperlink code with an empty response or URL.

Risk assessment and necessity

Risk: This area submits Czech VAT reports to an external tax service and archives both the request and response, so wrong error handling or a blank endpoint can affect statutory reporting. The new Service Connection path also runs outside the setup page, so it must not create a half-initialized setup record.

Necessity: The gov.cz endpoint migration is a valid and important bug fix, and the linked Bug explains the external URL change. The scope is justified, but the current implementation still needs changes before it is safe to merge.


[AI-PR-REVIEW] version=1 system=github pr=9857 round=2 by=alexei-dobriansky at=2026-08-03T17:12:01.953Z lastSha=3abc23b04f0b875564107722d306bde176dd464b suggestions=S1:notaddressed,S2:notaddressed,S3:new,S4:new parentRound=1

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

Labels

Finance GitHub request for Finance area

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants