Skip to content

Subscription Billing: respect Default Dimension Priorities on Subscription Lines#8115

Open
Franco111000 wants to merge 3 commits into
microsoft:mainfrom
Franco111000:fix-subscription-billing-dim-priorities
Open

Subscription Billing: respect Default Dimension Priorities on Subscription Lines#8115
Franco111000 wants to merge 3 commits into
microsoft:mainfrom
Franco111000:fix-subscription-billing-dim-priorities

Conversation

@Franco111000
Copy link
Copy Markdown

@Franco111000 Franco111000 commented May 12, 2026

What/why

Fixes #8084.

When a Customer Subscription Contract spawns Sales Invoices, Default Dimension
Priorities (table 354) were not respected. With priorities set as Item = 1,
Customer = 2 the resulting Sales Line still carried the Customer's dimension
value instead of the Item's.

Per the discussion with @miljance on #8084, the simple swap of GetCombinedDimensionSetID
parameter order at the merge step would fix the reported case but would also let
Sales Line defaults beat genuine Subscription Line user overrides, which is a
regression against the original design intent ("Subscription Line dimensions
should overwrite any duplicates from the default dimensions"). This PR addresses
the root cause upstream so both behaviors hold: priorities are respected during
Subscription Line creation, and Subscription Line dimensions remain authoritative
at billing time.

The bug had two compounding causes inside the Subscription Billing module:

  1. SubscriptionLine.SetDefaultDimensions called DimMgt.GetDefaultDimID(..., '', ...) with an empty Source Code, so Default Dimension Priority was never read. Only Item / G/L Account were added as dim sources, never Customer / Vendor.
  2. GetCombinedDimensionSetID is a blind last-slot-wins merge. UpdateFromCustomerContract then merged the Customer Contract dim set into the Subscription Line as slot 2, so Customer values systematically overrode whatever was on the Subscription Line.

The fix makes SubscriptionLine.SetDefaultDimensions the single priority-aware
entry point for all dim computation:

  • Passes SourceCodeSetup.Sales (Customer side) or SourceCodeSetup.Purchases (Vendor side) so Default Dimension Priority is consulted
  • Adds Customer / Vendor as a dim source from the linked Customer / Vendor Subscription Contract
  • Uses GetRecDefaultDimID with the contract's Dimension Set ID passed as InheritFromDimSetID and Database::Customer / Database::Vendor as InheritFromTableNo, mirroring the standard SalesLine.CreateDim pattern in Base App

UpdateFromCustomerContract and UpdateFromVendorContract now route through
SetDefaultDimensions instead of blind-merging the contract dim set. Same
change at the Pathway B call sites where an existing Subscription Line is
assigned to a contract (CustomerSubscriptionContract.CreateCustomerContractLineFromServiceCommitment,
VendorSubscriptionContract.CreateVendorContractLineFromServiceCommitment, and
the Import paths).

The blind merge at billing time (CreateBillingDocuments.Codeunit.al lines 264
/ 383) is intentionally left unchanged. After this fix the Subscription Line's
Dimension Set ID is already priority-resolved, so the existing "Service
Commitment wins over Sales Line" merge produces the correct result while
preserving the design intent that subscription line dimensions stay
authoritative for billing, which lines up with @miljance's clarification: "the
contract dimensions should win over any conflicting ones from the Subscription
Lines but still respecting the configured priority order."

Linked work

How I validated

  • Added a focused test RespectDefaultDimensionPrioritiesOnCustomerContractCreation in Service Comm. Dimensions. Configures Default Dim Priority Item = 1, Customer = 2 for source code Sales, gives Customer and Item conflicting values on the same dimension, asserts the resulting Subscription Line carries Item's value.
  • CI pipeline tests (will react to results after submission).

Risk & compatibility

Existing tests in ServiceCommDimensions.Codeunit.al may need adjustments if
they rely on the previous "Customer Contract dim always wins" merge order in
scenarios with overlapping dim codes. Will iterate based on CI results.

The two cross-link call sites that propagate Customer Contract dim onto
vendor-paired Subscription Lines (CustSubContractLine.DeleteRelatedVendorServiceCommDimensions,
VendSubContractLine.UpdateServiceCommitmentDimensions) are intentionally not
touched in this PR. They involve a related but distinct concern about
cross-partner dim propagation. Happy to follow up once the direction here is
settled.

Opening as draft so @miljance and the consultant can weigh in before we finalize.

…ption Lines

Fixes microsoft#8084.

SubscriptionLine.SetDefaultDimensions becomes the single priority-aware entry
point: passes SourceCodeSetup.Sales / .Purchases so Default Dimension Priority
is consulted, adds Customer / Vendor as a dim source from the linked contract,
and inherits the contract dim set via GetRecDefaultDimID. Mirrors the standard
SalesLine.CreateDim pattern in Base App.

UpdateFromCustomerContract / UpdateFromVendorContract and the other Pathway B
call sites now route through SetDefaultDimensions instead of blind-merging the
contract dim set as slot 2.

The billing-time merge at CreateBillingDocuments.Codeunit.al lines 264 / 383
is intentionally unchanged. After this fix the Subscription Line already
carries priority-resolved values, so the existing "Service Commitment wins"
merge produces the correct result while preserving the original design intent
that subscription line dimensions stay authoritative at billing.
@github-actions github-actions Bot added AL: Apps (W1) Add-on apps for W1 From Fork Pull request is coming from a fork labels May 12, 2026
@miljance
Copy link
Copy Markdown
Contributor

Looks clean and good. I think @Franco111000 is more than capable of finishing this one. From my side, this one can be converted to real PR. I would just like to run all the tests to see if any of those needs adjustment.

@Franco111000
Copy link
Copy Markdown
Author

Thanks @miljance! Converting to ready for review. Looking forward to the test results, I'll iterate on anything that needs adjustment.

@Franco111000 Franco111000 marked this pull request as ready for review May 12, 2026 13:41
@Franco111000 Franco111000 requested a review from a team as a code owner May 12, 2026 13:41
@Franco111000 Franco111000 requested a review from mirouhl May 12, 2026 13:41
@JesperSchulz JesperSchulz added the Finance GitHub request for Finance area label May 13, 2026
@miljance
Copy link
Copy Markdown
Contributor

Hi @Franco111000,

Two tests are currently failing:

ExpectEqualItemAndServiceCommitmentDimensionSetIDOnDeleteCustomerContractLine
I looked into the background for this test and the intent seems to be that when deleting a Contract Line, the dimensions for Service Commitment should exclude any dimensions that came in with the Contract. I'm not sure this behavior is actually achievable as designed - so I'm weighing whether it makes more sense to remove this test or adapt it.

TestTransferDimensionsFromServiceCommPackageToVendorServiceComm
Something appears to have broken with the changes. In the best case, the test just needs to be updated to reflect the new behavior; in the worst case, some functionality may have been unintentionally affected. Worth investigating to confirm which scenario we're in.

Can you check out and give your thoughts?

…ustom dims

Previous attempt made SubscriptionLine.SetDefaultDimensions priority-aware, but
that recomputed the Subscription Line dim from scratch and wiped any
already-present custom dimensions, e.g. the auto-insert Customer-Contract
dimension propagated via UpdateRelatedVendorServiceCommDimensions to a paired
Vendor Subscription Line.

New approach:

- Revert SetDefaultDimensions to its original Item-only behavior.
- Introduce ApplyContractDimensions on Subscription Line. It merges three slots
  via DimensionManagement.GetCombinedDimensionSetID: current SC dim,
  Contract dim, and a priority overlay built via
  DimMgt.GetTableIDsForHigherPriorities + GetRecDefaultDimID containing only
  Item / G/L Account sources that outrank the Contract partner table per
  Default Dimension Priority.
- UpdateFromCustomerContract / UpdateFromVendorContract and the Pathway B call
  sites (CreateCustomerContractLineFromServiceCommitment,
  CreateVendorContractLineFromServiceCommitment, the Import paths) now call
  ApplyContractDimensions.
- Reorders in CustSubContractLine and VendSubContractLine
  CreateServiceObjectWithServiceCommitment reverted; no longer needed.

When no Default Dim Priorities are configured (or when Customer/Vendor outrank
Item, the BC default), ApplyContractDimensions degrades to a blind merge with
the Contract dim winning on conflict, matching the previous behavior. Only the
explicit priority configuration from microsoft#8084 (Item over Customer) triggers the
overlay slot.

Adds cleanup of the Default Dimension Priority rows the new test inserts so
they do not leak to downstream tests in the suite.
@Franco111000
Copy link
Copy Markdown
Author

@miljance, both failures traced to the same cause: my first commit made SetDefaultDimensions priority-aware, but that recomputed the Subscription Line dim from scratch and wiped any custom dim already on the line (auto-insert from cross-package propagation, etc.).

Pushed a restructure:

  • SetDefaultDimensions reverted to its original Item-only behavior.
  • New ApplyContractDimensions does a 3-slot merge via GetCombinedDimensionSetID: current SC dim, Contract dim, and a priority overlay built only from sources that outrank the Contract partner table per Default Dimension Priority. When the priority table is at the BC default (Customer/Vendor outrank Item), the overlay is empty and the call degrades to the original blind merge with Contract winning, so existing tests that don't configure priorities see no behavior change. The overlay only activates when the user has explicitly flipped priorities (the [Bug][SubscriptionBilling]: Default Dimension Priorities not respected when creating Sales Invoice from Customer Subscription Contract #8084 case).
  • UpdateFromCustomerContract / UpdateFromVendorContract and the Pathway B call sites use ApplyContractDimensions.
  • Test cleanup added so the new test doesn't leak priority rows to other tests.

Could you give it another run when you have a moment?

@miljance
Copy link
Copy Markdown
Contributor

@Franco111000 PR looks good and all tests pass. The ApplyContractDimensions approach with GetTableIDsForHigherPriorities is exactly right.

Two small things I'd like addressed before merging:

  1. Duplicated source-building logicSetDefaultDimensions and ApplyContractDimensions share identical code for building the dim-source list (Invoicing Item + ServiceObject type switch). Could you extract that into a shared local procedure? - Not critical though - if you like it this way better - fine by me.

  2. Inconsistent priority handling in contract line tablesCustSubContractLine.DeleteRelatedVendorServiceCommDimensions and the equivalent in VendSubContractLine recalculate dims via SetDefaultDimensions + GetCombinedDimensionSetID, bypassing the same priority logic this PR fixes. Those should call ApplyContractDimensions instead.

Both should be straightforward to include in this PR. Let me know if anything is unclear.

…s-link procedures

Extracts the duplicated dim-source-building logic from SetDefaultDimensions and
ApplyContractDimensions into a local helper AddDefaultDimensionSources on
Subscription Line. Switches the Subscription Header lookup from an unguarded
Get (errors on missing) to a guarded if Get then (silent skip) so the helper
is safe to reuse in both contexts. No caller relies on the previous error path.

Extends the priority-aware merge to the two cross-link procedures that
previously bypassed it:

- CustSubContractLine.DeleteRelatedVendorServiceCommDimensions now applies
  ApplyContractDimensions(VendorContract.Dim, SourceCodeSetup.Purchases,
  Database::Vendor) on each paired vendor Subscription Line, so Default
  Dimension Priority for source code Purchases is honored when the customer
  contract line is deleted and the vendor lines are recomputed.
- VendSubContractLine.UpdateServiceCommitmentDimensions now applies
  ApplyContractDimensions(CustomerContract.Dim, SourceCodeSetup.Sales,
  Database::Customer) when propagating Customer Contract dim onto a paired
  Vendor Subscription Line, so the same Sales priority configuration the
  rest of the PR respects also flows through the cross-link.

Under vanilla BC priority configuration (Customer/Vendor outrank Item by
default) the overlay stays empty and the behavior remains identical to the
prior blind merge.
@Franco111000
Copy link
Copy Markdown
Author

@miljance, both done in the latest commit:

  • Extracted AddDefaultDimensionSources as a local helper on Subscription Line, used by both SetDefaultDimensions and ApplyContractDimensions. The helper uses a guarded if ServiceObject.Get then; the original SetDefaultDimensions had an unguarded Get. No caller relies on that error path, so this is a small defensive improvement.
  • CustSubContractLine.DeleteRelatedVendorServiceCommDimensions and VendSubContractLine.UpdateServiceCommitmentDimensions now call ApplyContractDimensions instead of the blind GetCombinedDimensionSetID. Source codes: Purchases + Database::Vendor on the Customer-side delete path (Vendor Contract being applied), Sales + Database::Customer on the Vendor-side cross-link path (Customer Contract being applied). Under vanilla priorities the overlay stays empty and behavior is identical to before.

Copy link
Copy Markdown
Contributor

@miljance miljance left a comment

Choose a reason for hiding this comment

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

looks great

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 Finance GitHub request for Finance area From Fork Pull request is coming from a fork

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug][SubscriptionBilling]: Default Dimension Priorities not respected when creating Sales Invoice from Customer Subscription Contract

3 participants