Skip to content

Uptake/rename license configurations#6404

Open
BenPlunk wants to merge 12 commits into
microsoft:mainfrom
BenPlunk:uptake/rename-license-configurations
Open

Uptake/rename license configurations#6404
BenPlunk wants to merge 12 commits into
microsoft:mainfrom
BenPlunk:uptake/rename-license-configurations

Conversation

@BenPlunk
Copy link
Copy Markdown

@BenPlunk BenPlunk commented Feb 3, 2026

Summary

  • Updated Codeunit 9056 “Plan Installer” to insert the new plan and plan configuration display names.
  • Implemented upgrade function for updating existing plan names and inserting new ones
  • Replaced all hard coded references to old plan names

Work Item(s)

Fixes #6403
AB#582117

BenPlunk and others added 4 commits January 12, 2026 14:41
@BenPlunk BenPlunk requested a review from a team as a code owner February 3, 2026 03:41
@github-actions github-actions Bot added AL: System Application From Fork Pull request is coming from a fork labels Feb 3, 2026
@JesperSchulz JesperSchulz added the Integration GitHub request for Integration area label Feb 3, 2026
Comment thread src/System Application/App/Azure AD Plan/src/PlanUpgrade.Codeunit.al Outdated
Comment thread src/System Application/App/Azure AD Plan/src/PlanInstaller.Codeunit.al Outdated
Comment thread src/System Application/App/Azure AD Plan/src/PlanInstaller.Codeunit.al Outdated
@github-actions github-actions Bot added the Linked Issue is linked to a Azure Boards work item label Feb 23, 2026
@github-actions github-actions Bot added this to the Version 28.0 milestone Feb 23, 2026
@aholstrup1 aholstrup1 modified the milestones: Version 28.0, Version 29.0 Feb 25, 2026
Copy link
Copy Markdown
Contributor

@stkillen stkillen left a comment

Choose a reason for hiding this comment

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

A couple of comments below. Additionally, we need a PR for BaseApp to replace any usages of old functions.

Comment thread src/System Application/App/Azure AD Plan/src/PlanIds.Codeunit.al
Comment thread src/System Application/App/Azure AD Plan/src/PlanIds.Codeunit.al
Comment thread src/System Application/App/Azure AD Plan/src/PlanInstaller.Codeunit.al Outdated
@BenPlunk
Copy link
Copy Markdown
Author

BenPlunk commented Mar 3, 2026

A couple of comments below. Additionally, we need a PR for BaseApp to replace any usages of old functions.

New Base app PR to update old references https://github.com/microsoft/BusinessCentralApps/pull/1828

WaelAbuSeada
WaelAbuSeada previously approved these changes Mar 3, 2026
Copy link
Copy Markdown
Contributor

@stkillen stkillen left a comment

Choose a reason for hiding this comment

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

Looking at Joost's comments earlier, we should match the regular plan names with the new delegated plan names. Added suggestions for the two plans and then we should rename in upgrade as well.

Comment thread src/System Application/App/Azure AD Plan/src/PlanInstaller.Codeunit.al Outdated
Comment thread src/System Application/App/Azure AD Plan/src/PlanInstaller.Codeunit.al Outdated
stkillen
stkillen previously approved these changes Mar 4, 2026
JesperSchulz
JesperSchulz previously approved these changes Mar 5, 2026
@JesperSchulz
Copy link
Copy Markdown
Contributor

Build fails with: AA0139 Possible overflow assigning 'Text' to 'Text[50]'

Copilot AI review requested due to automatic review settings April 23, 2026 00:25
@BenPlunk BenPlunk dismissed stale reviews from JesperSchulz and stkillen via 0040471 April 23, 2026 00:25
@BenPlunk
Copy link
Copy Markdown
Author

Build fails with: AA0139 Possible overflow assigning 'Text' to 'Text[50]'

Resolved

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates Azure AD plan (license) naming and IDs to align delegated/admin plan display names with Microsoft Entra role naming, including an upgrade path to rename existing plans and updating references across the app and tests.

Changes:

  • Updates plan installation to create plans with new display names (and new/renamed PlanIds accessors).
  • Adds an upgrade step intended to rename delegated/admin plans during upgrade.
  • Updates tests and delegated/admin detection logic to use the renamed plans.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
src/System Application/Test/Azure AD Plan/src/PlanConfigurationE2ETest.Codeunit.al Updates E2E test expectations and setup for renamed delegated plan.
src/System Application/Test/Azure AD Plan/src/AzureADPlanTests.Codeunit.al Updates multiple plan-assignment tests to use renamed delegated/admin plans.
src/System Application/App/Azure AD User Management/src/User sync/AzureADUserSyncImpl.Codeunit.al Updates comments describing admin plan combinations during sync.
src/System Application/App/Azure AD User Management/src/AzureADUserMgmtImpl.Codeunit.al Updates delegated-user detection logic to use renamed plan IDs.
src/System Application/App/Azure AD Plan/src/User Details/PlanUserDetails.Codeunit.al Updates “Is Delegated” derivation to use renamed plan IDs.
src/System Application/App/Azure AD Plan/src/PlanUpgradeTag.Codeunit.al Adds a new upgrade tag accessor for the delegated/admin rename upgrade.
src/System Application/App/Azure AD Plan/src/PlanUpgrade.Codeunit.al Adds/executes a new upgrade routine to rename delegated/admin plans; updates rename logging/classification.
src/System Application/App/Azure AD Plan/src/PlanInstaller.Codeunit.al Updates initial plan creation to insert new display names and IDs.
src/System Application/App/Azure AD Plan/src/PlanIds.Codeunit.al Introduces new PlanIds accessors and obsoletes older ones for renamed delegated plans.
src/System Application/App/Azure AD Plan/src/AzureADPlanImpl.Codeunit.al Updates delegated-role assignment/admin checks to use renamed plan IDs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

RenameOrCreatePlan(PlanIds.GetPremiumISVPlanId(), 'Dynamics 365 Business Central Premium - Embedded');
RenameOrCreatePlan(PlanIds.GetViralSignupPlanId(), 'Dynamics 365 Business Central for IWs');
RenameOrCreatePlan(PlanIds.GetDelegatedAdminPlanId(), 'Delegated Admin agent - Partner');
RenameOrCreatePlan(PlanIds.GetGlobalAdminPlanId(), 'Delegated Admin agent - Partner');
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

RenamePlansAndDeleteOldPlans renames 'Delegated Admin agent - Partner' using PlanIds.GetGlobalAdminPlanId(). That GUID corresponds to the Global Administrator plan, not the delegated admin plan (DelegatedAdminGUIDTxt). This will rename the wrong plan during upgrade. Use PlanIds.GetDelegatedGlobalAdminPlanId() for the delegated plan rename.

Suggested change
RenameOrCreatePlan(PlanIds.GetGlobalAdminPlanId(), 'Delegated Admin agent - Partner');
RenameOrCreatePlan(PlanIds.GetDelegatedGlobalAdminPlanId(), 'Delegated Admin agent - Partner');

Copilot uses AI. Check for mistakes.
case true of
AzureADGraphUser.IsUserDelegatedAdmin():
PlanId := PlanIds.GetDelegatedAdminPlanId();
PlanId := PlanIds.GetGlobalAdminPlanId();
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

Delegated admins are being assigned PlanIds.GetGlobalAdminPlanId() here. GetGlobalAdminPlanId() is the tenant Global Administrator role GUID, not the delegated admin plan GUID (DelegatedAdminGUIDTxt). This will assign the wrong plan to delegated admins and can grant/track the wrong entitlements. Use PlanIds.GetDelegatedGlobalAdminPlanId() for the delegated-admin path.

Suggested change
PlanId := PlanIds.GetGlobalAdminPlanId();
PlanId := PlanIds.GetDelegatedGlobalAdminPlanId();

Copilot uses AI. Check for mistakes.
Comment on lines +409 to +419
AzureADPlanTestLibraries.CreatePlan(PlanIds.GetGlobalAdminPlanId(), 'Delegated Global Administrator', 9022, '7584DDCA-27B8-E911-BB26-000D3A2B005C');

// [Given] The plan is not assigned to the current user
LibraryAssert.IsFalse(UserPlan.Get(PlanIds.GetDelegatedAdminPlanId(), UserSID), 'Plan should not be assigned to user');
LibraryAssert.IsFalse(UserPlan.Get(PlanIds.GetGlobalAdminPlanId(), UserSID), 'Plan should not be assigned to user');

// [Given] The current user is a delegated admin
BindSubscription(AzureADUserTestLibrary);
AzureADUserTestLibrary.SetIsUserDelegatedAdmin(true);

// [Given] The plan configuration for the plan is not customized
LibraryAssert.IsFalse(PlanConfiguration.IsCustomized(PlanIds.GetDelegatedAdminPlanId()), 'Plan configuration should not be customized');
LibraryAssert.IsFalse(PlanConfiguration.IsCustomized(PlanIds.GetGlobalAdminPlanId()), 'Plan configuration should not be customized');
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

Same issue as earlier in this file: this scenario uses GetGlobalAdminPlanId() for the delegated plan. Please switch to GetDelegatedGlobalAdminPlanId() so the test validates delegated-role behavior without conflating it with the real Global Administrator plan.

Copilot uses AI. Check for mistakes.
Comment on lines +463 to +473
AzureADPlanTestLibraries.CreatePlan(PlanIds.GetGlobalAdminPlanId(), 'Delegated Global Administrator', 9022, '7584DDCA-27B8-E911-BB26-000D3A2B005C');

// [Given] The plan is not assigned to the current user
LibraryAssert.IsFalse(UserPlan.Get(PlanIds.GetDelegatedAdminPlanId(), UserSID), 'Plan should not be assigned to user');
LibraryAssert.IsFalse(UserPlan.Get(PlanIds.GetGlobalAdminPlanId(), UserSID), 'Plan should not be assigned to user');

// [Given] The current user is not a delegated admin
BindSubscription(AzureADUserTestLibrary);
AzureADUserTestLibrary.SetIsUserDelegatedAdmin(false);

// [Given] The plan configuration for the plan is not customized
LibraryAssert.IsFalse(PlanConfiguration.IsCustomized(PlanIds.GetDelegatedAdminPlanId()), 'Plan configuration should not be customized');
LibraryAssert.IsFalse(PlanConfiguration.IsCustomized(PlanIds.GetGlobalAdminPlanId()), 'Plan configuration should not be customized');
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

Same issue as earlier in this file: this scenario uses GetGlobalAdminPlanId() for the delegated plan and will pass even if delegated admins are incorrectly mapped to the Global Administrator plan. Use GetDelegatedGlobalAdminPlanId() for the delegated admin plan ID.

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +59
/// <summary>
/// Returns the rename delegated admin plans upgrade tag.
/// </summary>
/// <returns>The rename delegated admin plans upgrade tag.</returns>
internal procedure GetRenameDelegatedAdminPlansUpgradeTag(): Code[250]
begin
exit('MS-582117-RenameDelegatedAdminPlans-20260128');
end;
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

This new upgrade tag is referenced from Plan Upgrade via HasUpgradeTag/SetUpgradeTag, but it isn't added to RegisterPerDatabaseTags() in this codeunit. Please register it there as well; otherwise the tag list is incomplete and the upgrade tag framework may not preserve/report it correctly.

Copilot uses AI. Check for mistakes.
Comment on lines +117 to +118
RenameOrCreatePlan(PlanIds.GetD365BCAdminPlanId(), 'Delegated Dynamics 365 Business Central Administrator');
RenameOrCreatePlan(PlanIds.GetGlobalAdminPlanId(), 'Delegated Global Administrator');
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

RenameDelegatedAdminPlans renames GetGlobalAdminPlanId() twice (to 'Global Administrator' and then to 'Delegated Global Administrator'). The second rename should target the delegated admin plan GUID (GetDelegatedGlobalAdminPlanId()), otherwise it will overwrite the global admin plan name and never rename the delegated plan. Also note that 'Delegated Dynamics 365 Business Central Administrator' exceeds the Plan.Name length (50) and will be truncated by CopyStr, so the resulting display name will not match the intended role name.

Suggested change
RenameOrCreatePlan(PlanIds.GetD365BCAdminPlanId(), 'Delegated Dynamics 365 Business Central Administrator');
RenameOrCreatePlan(PlanIds.GetGlobalAdminPlanId(), 'Delegated Global Administrator');
RenameOrCreatePlan(PlanIds.GetD365BCAdminPlanId(), 'Delegated D365 Business Central Administrator');
RenameOrCreatePlan(PlanIds.GetDelegatedGlobalAdminPlanId(), 'Delegated Global Administrator');

Copilot uses AI. Check for mistakes.
Comment on lines +141 to +148
/// <summary>
/// Returns the ID for the Delegated BC Admin agent - Partner plan.
/// </summary>
/// <returns>The ID for the Delegated BC Admin agent - Partner plan.</returns>
procedure GetD365BCAdminPlanId(): Guid
begin
exit(BCAdminPartnerGUIDTxt);
end;
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

The doc comments for GetD365BCAdminPlanId() still refer to the old delegated plan naming ('Delegated BC Admin agent - Partner'). Please update the summary/returns text to match the new delegated BC admin display name introduced in this PR (and keep it consistent with Plan Installer / upgrade naming).

Copilot uses AI. Check for mistakes.
exit(
IsPlanAssignedToUser(PlanIds.GetGlobalAdminPlanId(), SecurityID)
or IsPlanAssignedToUser(PlanIds.GetDelegatedAdminPlanId(), SecurityID)
or IsPlanAssignedToUser(PlanIds.GetGlobalAdminPlanId(), SecurityID)
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

IsUserAdmin now checks GetGlobalAdminPlanId() twice, which makes the second condition redundant and drops the delegated-admin check that previously existed. Replace the duplicate with IsPlanAssignedToUser(PlanIds.GetDelegatedGlobalAdminPlanId(), SecurityID) (or the appropriate delegated plan ID) so delegated admins are still treated as admins when intended.

Suggested change
or IsPlanAssignedToUser(PlanIds.GetGlobalAdminPlanId(), SecurityID)
or IsPlanAssignedToUser(PlanIds.GetDelegatedGlobalAdminPlanId(), SecurityID)

Copilot uses AI. Check for mistakes.
Comment on lines +43 to +44
PlanConfigurationLibrary.AddConfiguration(PlanIds.GetGlobalAdminPlanId(), false);
PlanConfiguration.AddDefaultPermissionSetToPlan(PlanIds.GetGlobalAdminPlanId(), 'SUPER', NullGuid, 0);
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

PlanIds.GetGlobalAdminPlanId() is the Entra Global Administrator role GUID, not the delegated admin plan GUID ({000...007}). Using it here will create a configuration for the wrong plan, and the page will show 'Global Administrator' rather than 'Delegated Global Administrator'. Use PlanIds.GetDelegatedGlobalAdminPlanId() for the delegated plan throughout this test setup.

Suggested change
PlanConfigurationLibrary.AddConfiguration(PlanIds.GetGlobalAdminPlanId(), false);
PlanConfiguration.AddDefaultPermissionSetToPlan(PlanIds.GetGlobalAdminPlanId(), 'SUPER', NullGuid, 0);
PlanConfigurationLibrary.AddConfiguration(PlanIds.GetDelegatedGlobalAdminPlanId(), false);
PlanConfiguration.AddDefaultPermissionSetToPlan(PlanIds.GetDelegatedGlobalAdminPlanId(), 'SUPER', NullGuid, 0);

Copilot uses AI. Check for mistakes.
Comment on lines +348 to +358
AzureADPlanTestLibraries.CreatePlan(PlanIds.GetGlobalAdminPlanId(), 'Delegated Global Administrator', 9022, '7584DDCA-27B8-E911-BB26-000D3A2B005C');

// [Given] The plan is not assigned to the current user
LibraryAssert.IsFalse(UserPlan.Get(PlanIds.GetDelegatedAdminPlanId(), UserSID), 'Plan should not be assigned to user');
LibraryAssert.IsFalse(UserPlan.Get(PlanIds.GetGlobalAdminPlanId(), UserSID), 'Plan should not be assigned to user');

// [Given] The current user is a delegated admin
BindSubscription(AzureADUserTestLibrary);
AzureADUserTestLibrary.SetIsUserDelegatedAdmin(true);

// [Given] The plan configuration for the plan is not customized
LibraryAssert.IsFalse(PlanConfiguration.IsCustomized(PlanIds.GetDelegatedAdminPlanId()), 'Plan configuration should not be customized');
LibraryAssert.IsFalse(PlanConfiguration.IsCustomized(PlanIds.GetGlobalAdminPlanId()), 'Plan configuration should not be customized');
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

These tests now create/assert a plan named 'Delegated Global Administrator' using GetGlobalAdminPlanId(). That GUID represents the non-delegated Global Administrator role ({62e9...}) and will hide regressions where delegated admins are mapped to the wrong plan. Use PlanIds.GetDelegatedGlobalAdminPlanId() for the delegated plan ID, and keep GetGlobalAdminPlanId() reserved for the actual Global Administrator plan.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AL: System Application From Fork Pull request is coming from a fork Integration GitHub request for Integration area Linked Issue is linked to a Azure Boards work item

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BC Idea]: Rename Licenses/License Configurations to match Entra role names

9 participants