Skip to content

Add-Expense-VAT-settings-to-Contoso-demo-tool - #10990

Open
Alexander Yakunin (Alexander-Ya) wants to merge 10 commits into
mainfrom
bugs/Add-Expense-VAT-settings-to-Contoso-demo-tool
Open

Add-Expense-VAT-settings-to-Contoso-demo-tool#10990
Alexander Yakunin (Alexander-Ya) wants to merge 10 commits into
mainfrom
bugs/Add-Expense-VAT-settings-to-Contoso-demo-tool

Conversation

@Alexander-Ya

@Alexander-Ya Alexander Yakunin (Alexander-Ya) commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

What & why

Linked work

Fixes AB#648889

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 (required — be specific: scenarios, commands, screenshots for UI changes)

Risk & compatibility

@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 1

Recommendation: Request Changes

What this PR does

The change wires Expense VAT rate creation into the Contoso demo module and shortens the room service subcategory code so it matches the demo subcategory code. This should let demo data create VAT product posting groups, VAT posting setup, and default VAT settings for Expense Agent categories.

The room service code alignment looks correct. The demo module call is not enough, though, because the VAT rate code depends on the Expense Agent setup already having a default VAT business posting group. The existing setup helper fills that default and records that VAT rates were applied, but the new direct codeunit call bypasses both parts.

Problem-solution fit

Fit: Partial

The change adds VAT rates to demo master data, but it does not apply the full setup state that the VAT flow needs. A demo company can still be left without the default VAT business posting group used by agent-created VAT specifications.

Suggestions

S1 (🔴 High): Use the setup helper for VAT defaults
The new Codeunit.Run(Codeunit::"Create Expense VAT Rates") call can run while Default VAT Bus. Posting Group is still blank. Then the rates are created for the wrong VAT business group, and later agent VAT specifications can fail because the setup default is missing. Please call the setup helper that sets the default VAT business posting group and applies the rates, or set the same setup fields before creating the rates.

Risk assessment and necessity

Risk: This affects Contoso Expense Agent demo setup and VAT posting setup. If the default VAT business group is missing or the rates are created against a blank group, demo expenses can fail VAT specification insertion or use incomplete VAT setup.

Necessity: The feature is needed so demo data includes the VAT settings used by Expense Agent. The scope is right, but it needs to use the setup path that creates a complete configuration.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=10990 round=1 by=alexei-dobriansky at=2026-09-03T13:19:05Z lastSha=5f3deb0c85aea1fa0c3d7d31629931138413f152 reviewKey=f811cd4c966c2366c67878d898ddd3eedf222740779544efe51900e7e93a7753 suggestions=S1@43fb032b

procedure InsertDefaultRates()
var
CompanyInfo: Record "Company Information";
GLAccount: Record "G/L Account";

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

InsertDefaultRates() no longer guarantees the VAT purchase account exists: the old fallback EXPENSE VAT account creation was removed, and the procedure now resolves rate-specific accounts by name before writing VAT posting setup rows. Any existing caller of this published procedure that relied on the old side effect can now fail unless it is updated to precreate those accounts. Preserve the old behavior for InsertDefaultRates() or introduce a new entry point for the rate-specific-account flow and keep the old procedure backward-compatible.

Agent judgement — not directly backed by a BCQuality knowledge article.

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

end;
end;

local procedure GetPurchaseVATAccount(VATPercent: Decimal): 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\ —\ Data\ Modeling}$

The new purchase-VAT-account lookup resolves G/L Account by names like Expense VAT 20 %, but the main app no longer creates any matching account on its own. CreateCountryVATRatesDefaults and Create Expense Categories can run in regular installations without the demo-data app, so this lookup returns no record and VAT Posting Setup is seeded with no valid purchase VAT account. Keep the VAT-account provisioning self-contained in the main app, or fail with an explicit guard instead of depending on demo-data accounts to exist.

Agent judgement — not directly backed by a BCQuality knowledge article.

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

var
GLAccount: Record "G/L Account";
begin
GLAccount.SetRange(Name, GetExpenseVATAccountName(VATPercent));

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

GetPurchaseVATAccount filters G/L Account by Name and Account Type and then returns FindFirst(). Because Name is not a unique key, multiple posting accounts can satisfy this filter and the code will silently bind VAT posting setup to whichever record happens to come first on the current key. Use a unique identifier for the account, or explicitly detect and reject zero-or-multiple matches before returning an account number.

Agent judgement — not directly backed by a BCQuality knowledge article.

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

@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 2

Recommendation: Request Changes

What this PR does

The latest changes set the default VAT business posting group before running Expense VAT rate creation, add demo G/L accounts for Expense VAT rates, and align hotel subcategory codes used by the VAT setup.

The earlier ordering issue is addressed for the demo module. However, the shared VAT rate code now looks up G/L accounts that are created by the demo data path, while the same codeunit is also used by app setup/default-settings flows. Those non-demo flows can still fail before VAT rates are created.

Status of previous suggestions
ID Title Status Author response
S1 Use the setup helper for VAT defaults Addressed The default VAT business posting group is now set before the VAT rates run.
New observations (commits since round 1)

S2 (🔴 High): Default setup can fail without demo VAT accounts
This app codeunit is also called from default settings and category setup, where the new Contoso demo G/L accounts may not exist. FindFirst() can stop setup before VAT rates are created. Keep the demo account lookup inside the demo path, or handle/create a safe account for the app setup path.

Risk assessment and necessity

Risk: This affects shared Expense Agent VAT default setup, not only Contoso demo data. If the required G/L account is missing, the default VAT rate creation can fail before any VAT setup is created.

Necessity: The change is needed so demo data has Expense VAT settings, but the app-level VAT setup must remain independent from demo-only G/L account creation.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=10990 round=2 by=alexei-dobriansky at=2026-09-04T10:39:16Z lastSha=8eb909658ea4601617ff59c25f044cadf8177af6 reviewKey=68f73a8c5f4ac328d1251ecfa306cdbe29fd3dc41e3dcab64ef112d0a1600944 suggestions=S1@43fb032b:addressed,S2@46d2b2a1:new parentRound=1

@github-actions

This comment was marked as spam.

@github-actions

This comment was marked as spam.

@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 3

Recommendation: Request Changes

What this PR does

The latest commit adds an IsVATCountry() helper and uses it to skip Expense VAT demo setup for Sales Tax companies. That direction is useful, but it does not close the open setup failure.

The shared Create Expense VAT Rates code still resolves purchase VAT accounts by finding demo-created G/L accounts. That codeunit is also run from app setup/default-settings flows, where those demo accounts may not exist. The new gate also introduces a second failure path because it reads the Contoso setup record with Get() before some callers reach their existing safe missing-record exit.

Status of previous suggestions
ID Title Status Author response
S1 Use the setup helper for VAT defaults Addressed The default VAT business posting group is now set before the VAT rates run.
S2 Default setup can fail without demo VAT accounts Not addressed No response. The latest commit adds a Sales Tax gate, but the app setup/default-settings path still depends on demo G/L accounts.
New observations (commits since round 2)

S3 (🔴 High): VAT country check can stop setup early
IsVATCountry() calls ContosoCoffeeDemoDataSetup.Get() without handling a missing setup record. Two callers now run this check before their own safe Get()/exit logic, so setup can fail earlier instead of being skipped. Return false when the setup record is missing, or keep the safe Get() before this check.

Risk assessment and necessity

Risk: This still affects Expense Agent VAT default setup and Contoso demo VAT setup. If the required G/L account or setup record is missing, VAT rate creation can stop before the settings are created.

Necessity: The change is needed so demo data has the Expense VAT settings used by Expense Agent. Without it, the workaround is manual VAT setup after demo data creation, but the implementation must keep shared setup paths independent from demo-only records.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=10990 round=3 by=alexei-dobriansky at=2026-09-04T13:59:32Z lastSha=34d309ca58a38c6f06f6fde6cf265a77ddd8cfd7 reviewKey=790fb6f4da22492f477819cdf3c9a3cccc98bd64bb84cbc5a49303b88da7d7b5 suggestions=S1@43fb032b:addressed,S2@46d2b2a1:notaddressed,S3@0c60792c:new parentRound=2

var
GLAccount: Record "G/L Account";
begin
GLAccount.SetRange(Name, GetExpenseVATAccountName(VATPercent));

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

GetPurchaseVATAccount resolves the purchase VAT account by filtering "G/L Account" on Name and then taking the first posting account. Name is editable and not unique, so this can bind VAT Posting Setup to the wrong ledger account as soon as a seeded account is renamed or another posting account happens to share the same caption. Resolve these VAT accounts through a stable identifier such as the account No. (or a persisted mapping) instead of SetRange(Name, ...).

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

AddSubcategorySeed(TempSubcategory, XROOMSERVICETxt, XHOTELSTxt, XHotelRoomServiceDescTxt, XSubRoomServicePostingTxt, true, false);
AddSubcategorySeed(TempSubcategory, XPARKINGTxt, XHOTELSTxt, XHotelParkingDescTxt, XSubHotelParkingPostingTxt, true, false);
AddSubcategorySeed(TempSubcategory, XOTHERTxt, XHOTELSTxt, XHotelOtherDescTxt, XSubOtherPostingTxt, true, false);
AddSubcategorySeed(TempSubcategory, XHOTELPARKTxt, XHOTELSTxt, XHotelParkingDescTxt, XSubHotelParkingPostingTxt, true, 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{🟡\ Medium\ Severity\ —\ Upgrade}$

This PR renames Locked=true subcategory codes that are seeded as part of the primary key of "Expense Subcategory" under HOTELS (PARKING -> HOTEL-PARK, OTHER -> HOTELOTHER in CreateExpenseCategories.Codeunit.al; and demo-data ROOM-SER -> ROOM-SERVICE in CreateExpenseSubCategories.Codeunit.al), and CreateExpenseVATRates.Codeunit.al's per-country seed lists were switched to reference the new codes, but no Subtype = Upgrade codeunit renames the old rows for companies that already ran setup with the previous codes. Create Expense Categories also skips reseeding subcategories once a category exists, so an environment seeded before this change would keep the stale keys while later code (VAT-rate lookups by CategoryCode/SubcategoryCode) expects the new ones. The Expense Agent app is currently versioned/labelled '(Preview)', which limits how many real installs could already hold the old codes, so the practical urgency is lower than a GA product would warrant — but the gap should be closed with an upgrade codeunit (or a documented statement that no pre-existing installs use the old codes) before this ships to broader preview/GA audiences.

Knowledge:

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

@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 4

Recommendation: Request Changes

What this PR does

The latest commit changes the demo Expense VAT G/L accounts so they no longer use a fixed G/L account subcategory. That makes the demo-account creation path less dependent on country-specific account-category setup, but it does not close the open setup failures.

The shared VAT rate setup still finds purchase VAT accounts by looking for demo-created G/L accounts. That shared setup can run from default-settings flows where those demo accounts are not guaranteed to exist. The VAT-country guard also still reads the Contoso setup record without handling a missing record.

Status of previous suggestions
ID Title Status Author response
S1 Use the setup helper for VAT defaults Addressed The default VAT business posting group is set before the VAT rates run.
S2 Default setup can fail without demo VAT accounts Not addressed The latest commit only changes the demo G/L account subcategory. Create Expense VAT Rates still calls GetPurchaseVATAccount() and can fail when shared setup runs before the demo accounts exist.
S3 VAT country check can stop setup early Not addressed No change was made to IsVATCountry(). It still calls Get() before callers reach their own missing-record guard.
New observations (commits since round 3)

None. The only new hunk changes the Expense VAT G/L account subcategory, and I did not find a new issue in that change.

Risk assessment and necessity

Risk: This still affects Expense Agent VAT default setup and Contoso demo VAT setup. If the needed G/L account or setup record is missing, VAT rate creation can stop before the settings are created. The demo-data G/L account publisher was checked; the remaining risk is in the shared setup path, not in the publisher timing.

Necessity: The change is needed so demo data has the Expense VAT settings used by Expense Agent. Without it, the workaround is manual VAT setup after demo data creation, but the implementation must keep shared setup paths independent from demo-only records.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=10990 round=4 by=alexei-dobriansky at=2026-09-04T19:14:59Z lastSha=238b4bbeddc9ac7126df93f8344084854bdd55a0 reviewKey=6998b994bbc0fa183070d61df3142ebaec3bc04334cbdc6e917dd106e8e3a065 suggestions=S1@43fb032b:addressed,S2@46d2b2a1:notaddressed,S3@0c60792c:notaddressed parentRound=3

end;
end;

local procedure GetPurchaseVATAccount(VATPercent: Decimal): 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}$

IMPACT NOTE: this would be major/blocker in a knowledge-backed rule, but is capped to minor as an agent finding. CreateExpenseVATRates.Codeunit.al (app/src/Setup, a production code path invoked from ExpenseAgentSetup.CreateCountryVATRatesDefaults, independent of any demo data) previously always guaranteed a 'Purchase VAT Account' by creating/using a virtual 'EXPENSE VAT' G/L account inline. The PR removes that unconditional creation and replaces it with GetPurchaseVATAccount(), which looks up a G/L Account by Name = 'Expense VAT %' via GLAccount.SetRange/FindFirst and only assigns 'Purchase VAT Account' when a match is found (PurchaseVATAccountNo <> ''). Those named accounts are only ever created by CreateExpenseGLAccount.Codeunit.al under the 'demo data' folder (via AddExpenseVATAccountsForLocalization/InsertExpenseVATAccounts), which only runs as part of the Contoso Demo Data module pipeline. For a real (non-demo) tenant enabling Expense Agent, CreateCountryVATRatesDefaults creates new VAT Posting Setup rows via InsertRate with 'Purchase VAT Account' left blank, because no matching G/L account will exist. This is a functional regression versus current behavior for production customers who do not load Contoso demo data. Recommend keeping a fallback that creates or assigns a default Purchase VAT Account when GetPurchaseVATAccount finds nothing, so production VAT Posting Setup rows are never left without a Purchase VAT Account.

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

AccountNo := 5650;
foreach VATRate in VATRates do begin
if AccountNo > 5659 then
Error(ExpenseVATAccountRangeExceededErr, ContosoCoffeeDemoDataSetup."Country/Region Code");

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

This range-overflow guard in demo-data setup is an internal invariant, but it raises a plain client-visible Error. Use ErrorInfo with ErrorType::Internal so the detailed message is kept for telemetry while the user sees a generic failure.

Knowledge:

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

@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 5

Recommendation: Request Changes

What this PR does

The latest commit changes the missing purchase VAT account path so a missing rate-specific G/L account no longer stops VAT rate setup immediately. It now skips the Purchase VAT Account assignment when no matching account exists.

That prevents one runtime error, but it still does not make the shared setup path complete. The code can create VAT Posting Setup rows without a purchase VAT account in non-demo setup flows, and the VAT-country guard still reads the demo setup record before callers can safely exit when that record is missing.

Status of previous suggestions
ID Title Status Author response
S1 Use the setup helper for VAT defaults Addressed The default VAT business posting group is set before the VAT rates run.
S2 Default setup can fail without demo VAT accounts Not addressed The latest commit avoids the immediate missing-account error, but Create Expense VAT Rates can still create VAT Posting Setup without a Purchase VAT Account when the demo G/L accounts do not exist.
S3 VAT country check can stop setup early Not addressed No change was made to IsVATCountry(). It still calls Get() before callers reach their own missing-record guard.
New observations (commits since round 4)

None. The latest hunk only changes how a missing purchase VAT account is handled, and that is covered by the still-open S2 finding.

Risk assessment and necessity

Risk: This still affects Expense Agent VAT default setup and Contoso demo VAT setup. If the shared setup creates VAT Posting Setup rows without a purchase VAT account, later expense posting that uses those VAT groups can fail or post incomplete VAT setup. If the demo setup record is missing, IsVATCountry() can still stop setup before the callers' safe missing-record checks run.

Necessity: The change is needed so demo data has the Expense VAT settings used by Expense Agent. Without it, the workaround is manual VAT setup after demo data creation, but the implementation must keep shared setup paths independent from demo-only records and must skip safely when demo setup is absent.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=10990 round=5 by=alexei-dobriansky at=2026-09-05T19:04:03Z lastSha=dee71fc795c60b68151897be132f27074f22b238 reviewKey=bde4830e5cfb394f2ce76cef2fc55168dfb1b0f9af504a8060ef892ad4f55e0b suggestions=S1@43fb032b:addressed,S2@46d2b2a1:notaddressed,S3@0c60792c:notaddressed parentRound=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 ExpenseManagement Team: Finance GitHub request for Finance area

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants