Most organizations in Dynamics 365 Finance & Operations (D365 F&O) are constrained by the standard organizational hierarchy options: Business Unit, Cost Center, Department, and a few others. However, many enterprises—particularly those with complex geographic structures, multiple divisions, or zone-based operations—find these standard options insufficient for their business model.
This blog post demonstrates how to extend D365 F&O with custom operating unit types such as Division, Region, and Zone. These custom types can be used throughout the system: in organizational hierarchies, as financial dimensions in Chart of Accounts structures, and in transactions.
Problem Statement
Organizations with complex organizational structures face significant challenges:
- Limited Hierarchy Options: Standard D365 F&O does not provide Division, Region, or Zone as built-in operating unit types
- Dimensional Reporting Gaps: Cannot easily report on geographic or divisional profitability without workarounds
- Transaction Dimensioning: Cannot use custom organizational structures in financial dimension hierarchies
- Data Integration Issues: No native Excel or DMF support for importing/exporting custom organizational structures
- Workaround Overhead: Forced to create redundant dimensions, duplicate hierarchies, or implement complex customizations
The Challenge:
- A multi-division enterprise wants to report divisional P&L
- A geographic company needs regional performance analysis
- A zone-based distributor requires zone-level transaction tracking
- Without native support, all of this requires complex customizations and workarounds
Solution Overview
This comprehensive implementation provides a complete, production-ready solution that adds three new operating unit types to your D365 F&O system:
- Division - For organizational division structures
- Operating Region - For geographic region organization
- Zone - For zone-based operations
The solution uses five core components working together seamlessly:
- Enum Extension - Extends OMOperatingUnitType with new values
- Data Entities - Enable Excel add-in and DMF integration
- Staging Tables - Support bulk import/export operations
- Menu Items - Provide user interface access
- Dimension Views - Make custom types available in Chart of Accounts
Architecture & Components
The implementation follows a layered architecture where each component builds upon the previous:
Enum Extension (OMOperatingUnitType)
↓
Data Entities (Fox_OMDivisionEntity, Fox_OMOperatingRegionEntity, Fox_OMZoneEntity)
↓
Staging Tables (Fox_OMDivisionStaging, Fox_OMOperatingRegionStaging, FoxOMZoneStaging)
↓
Menu Items (Fox_OMDivision, Fox_OMOperatingRegion, Fox_OMZone)
↓
Dimension Views (Fox_DimAttributeOMDivisionView, Fox_DimAttributeOMOperatingRegionView, Fox_DimAttributeOMZoneView)
"Custom operating unit types extend D365 F&O's organizational capabilities without disrupting standard functionality."
Step 1: Enum Extension - Define Operating Unit Types
The foundation starts with extending the
OMOperatingUnitType enumeration to include your custom operating unit types. This enum is the single source of truth that drives all subsequent components.Creating the Enum Extension
Enum Extension
OMOperatingUnitType.Fox_ExtensionAdd the three enum values:
| Value Name | Label | Purpose |
|---|---|---|
| OMDivision | @SYS40992 | Represents organizational divisions |
| OMOperatingRegion | @SYS109262 | Represents geographic regions |
| OMZone | @WAX:FieldZone | Represents operational zones |
Key Configuration Points:
Using existing system labels ensures:
- Consistency across the system
- Proper multilingual support (labels stored in label files)
- Alignment with standard D365 terminology
Step 2: Data Entities - Enable Excel and DMF Integration
Data entities are the bridge between your operating units and external systems. They enable:
- Excel add-in functionality for end-user access
- Data Management Framework (DMF) bulk import/export
- OData API access for integrations
- Change tracking for incremental updates
Creating Data Entities in Visual Studio
Create three Data Entities:
For Division:
- Name:
Fox_OMDivisionEntity - Primary Data Source:
OMOperatingUnittable - In Properties:
- Label: @SYS40992 (Division label)
- IsPublic: Yes
- DataManagementEnabled: Yes
- DataManagementStagingTable: Fox_OMDivisionStaging
- PublicCollectionName: Divisions
- PublicEntityName: Division
Adding Methods to Fox_OMDivisionEntity
registerDivisionEntity() Method:
This method registers the Division entity with the Office menu items system, making it available in Excel add-in.
x++/// <summary> /// Registers this entity with the Office menu items system /// Makes it available in Excel add-in and on the OMOperatingUnit form /// </summary> [SubscribesTo(classStr(OMOperatingUnitEntityDelegates), delegateStr(OMOperatingUnitEntityDelegates, registerOperatingUnitEntities))] public static void registerDivisionEntity(List _entityList) { _entityList.addEnd(tableStr(Fox_OMDivisionEntity)); }
How It Works:
- Uses the SubscribesTo attribute to subscribe to the
registerOperatingUnitEntitiesdelegate - When OMOperatingUnit form initializes, this method is automatically called
- Adds the Division entity to the list of available Office menu items
- Users can then access the entity via Excel add-in without any additional configuration
defaultCTQuery() Method:
This is the change tracking query that enables incremental DMF updates. It identifies which Division operating units have changed since the last export.
x++/// <summary> /// Change tracking query for DMF incremental updates /// Identifies changed Division operating units since last export /// </summary> /// <returns>Query that represents Division data sources</returns> public static Query defaultCTQuery() { Query q = new Query(); // Root data source: DirPartyTable (party master records) QueryBuildDataSource dirPartyQBDS = q.addDataSource(tableNum(DirPartyTable)); dirPartyQBDS = DirPartyBaseEntity::addChangeTrackingDataSourcesForDirPartyChildren(dirPartyQBDS); // Add postal address change tracking LogisticsPostalAddressBaseEntity::addChangeTrackingDataSourcesForAddressBase( dirPartyQBDS, fieldNum(DirPartyTable, PrimaryAddressLocation), false ); // Join to OMOperatingUnit and filter by Division type QueryBuildDataSource qbdOMOperatingUnit = dirPartyQBDS.addDataSource(tableNum(OMOperatingUnit)); qbdOMOperatingUnit.addLink(fieldNum(DirPartyTable, PartyNumber), fieldNum(OMOperatingUnit, PartyNumber)); // CRITICAL: Filter to only Division type operating units qbdOMOperatingUnit.addRange(fieldNum(OMOperatingUnit, OMOperatingUnitType)) .value(queryValue(OMOperatingUnitType::OMDivision)); // Add DUNS number tracking (standard for operating units) QueryBuildDataSource qbdDunNumber = qbdOMOperatingUnit.addDataSource(tableNum(DirDunsNumber)); qbdDunNumber.addLink(fieldNum(OMOperatingUnit, DunsNumberRecId), fieldNum(DirDunsNumber, RecId)); return q; }
Key Components:
| Component | Purpose |
|---|---|
| DirPartyTable | Root data source containing organization party data |
| addChangeTrackingDataSourcesForDirPartyChildren() | Enables change tracking on party children |
| LogisticsPostalAddressBaseEntity::addChangeTrackingDataSourcesForAddressBase() | Tracks address changes |
| OMOperatingUnit Join | Links party to operating unit |
| addRange(OMOperatingUnitType) | Filters to Division type only |
| DirDunsNumber | Tracks DUNS number association |
Change Tracking Benefits:
- Only exports changed records since last run
- Significantly reduces export file size
- Improves performance for large datasets
- Essential for high-frequency data synchronization
Operating Region Entity
Create Fox_OMOperatingRegionEntity: Same configuration as Division, with these properties:
- Label: @SYS109262 (Region label)
- DataManagementStagingTable: Fox_OMOperatingRegionStaging
- PublicCollectionName: Regions
- PublicEntityName: Region
Add similar methods:
- registerOperatingRegionEntity() - Same pattern as Division, but registers
Fox_OMOperatingRegionEntity - defaultCTQuery() - Same structure as Division, but change the range filter:
x++
qbdOMOperatingUnit.addRange(fieldNum(OMOperatingUnit, OMOperatingUnitType)) .value(queryValue(OMOperatingUnitType::OMOperatingRegion));
Zone Entity
Create Fox_OMZoneEntity: Same configuration as Division, with these properties:
- Label: @WAX:FieldZone (Zone label)
- DataManagementStagingTable: Fox_OMZoneStaging
- PublicCollectionName: Zones
- PublicEntityName: Zone
Add similar methods:
- registerZoneEntity() - Same pattern as Division, but registers
Fox_OMZoneEntity - defaultCTQuery() - Same structure as Division, but change the range filter:
x++
qbdOMOperatingUnit.addRange(fieldNum(OMOperatingUnit, OMOperatingUnitType)) .value(queryValue(OMOperatingUnitType::OMZone));
Data Entity Configuration Summary
Key Entity Features Explained:
- SubscribesTo Delegate: Registers entity in Office menus automatically
- defaultCTQuery(): Enables change tracking for efficient DMF operations
- DataManagementEnabled: Allows bulk import/export
- DataManagementStagingTable: Links to corresponding staging table
- PublicCollectionName/EntityName: OData naming for API access
- IsPublic: Yes (makes visible in Data Management workspace)
Step 3: Staging Tables - DMF Support
Staging tables are intermediate storage used by the Data Management Framework to validate, store, and process data during import/export operations.
Adding Staging Tables methods
For three Staging Tables:
For Division:
- Name:
Fox_OMDivisionStaging - In Properties:
- TableGroup: Staging
- SaveDataPerCompany: No (shared across all companies)
- PrimaryIndex: StagingIdx
- ReplacementKey: StagingIdx
Add Standard Fields to Division Staging Table:
| Field Name | Type | Length | Purpose |
|---|---|---|---|
| RecId | int64 | - | Auto-generated primary key |
| OMOperatingUnitNumber | String | 20 | Division code being imported |
| Name | String | 60 | Division name |
| IsProcessed | Enum (NoYes) | - | DMF processing status |
| TransferStatus | Enum | - | Validation status |
mapDivisionStaging() Method
Add this method to the staging table class:
x++/// <summary> /// Maps Division staging records to operating units /// Validates data and transfers to OMOperatingUnit on successful validation /// </summary> public static void mapDivisionStaging() { Fox_OMDivisionStaging staging; OMOperatingUnit operatingUnit; // Select unprocessed records select forUpdate staging where staging.IsProcessed == NoYes::No; while (staging) { // Create new operating unit operatingUnit.clear(); operatingUnit.OMOperatingUnitNumber = staging.OMOperatingUnitNumber; operatingUnit.Name = staging.Name; operatingUnit.OMOperatingUnitType = OMDivision; operatingUnit.insert(); // Mark as processed staging.IsProcessed = NoYes::Yes; staging.TransferStatus = TransferStatus::Successful; staging.update(); next staging; } }
Process Flow:
- DMF validates staging table records
- mapDivisionStaging() executes on marked records
- Data transfers to OMOperatingUnit with OMDivision type
- Staging records marked as "Processed" and "Successful"
Operating Region Staging Table
Create Fox_OMOperatingRegionStaging: Same configuration as Division Staging:
- TableGroup: Staging
- SaveDataPerCompany: No
- Add same fields: OMOperatingUnitNumber, Name, IsProcessed, TransferStatus
Add mapOperatingRegionStaging() method - Same structure as
mapDivisionStaging(), but change:x++operatingUnit.OMOperatingUnitType = OMOperatingRegion; // Instead of OMDivision
Zone Staging Table
Create Fox_OMZoneStaging: Same configuration as Division Staging:
- TableGroup: Staging
- SaveDataPerCompany: No
- Add same fields: OMOperatingUnitNumber, Name, IsProcessed, TransferStatus
Add mapZoneStaging() method - Same structure as
mapDivisionStaging(), but change:x++operatingUnit.OMOperatingUnitType = OMZone; // Instead of OMDivision
Staging Table Configuration Summary
Key Properties:
- TableGroup: Must be "Staging" (indicates DMF staging table)
- SaveDataPerCompany: No (shared across all companies)
- PrimaryIndex/ReplacementKey: StagingIdx (standard DMF pattern)
Data Management Framework Processing Order:
- User imports CSV/Excel data using Data Management workspace
- Data loads into staging tables (Fox_OMDivisionStaging, Fox_OMOperatingRegionStaging, Fox_OMZoneStaging)
- User reviews data in staging forms for corrections
- Mapping execution calls mapDivisionStaging(), mapOperatingRegionStaging(), mapZoneStaging()
- Data validates against business rules
- Valid records transfer to OMOperatingUnit with correct type
- Staging records marked as "Processed" for audit trail
Benefits of This Approach:
- ✓ Separation of concerns (Division/Region/Zone can be imported separately)
- ✓ Audit trail maintained in staging tables
- ✓ Data validation before production insert
- ✓ Rollback capability if errors detected
Step 4: Menu Items - User Interface Access
Menu items expose your operating units in the D365 UI, allowing users to access and manage custom operating units.
Creating Menu Items
Create three Display Menu Items:
For Division:
- Name:
Fox_OMDivision - In Properties:
- Label: @SYS40992 (Division label)
- Object: OMOperatingUnit (the form to open)
- EnumParameter: OMDivision (from your enum extension)
- EnumTypeParameter: OMOperatingUnitType (the enum type)
- MaintainUserLicense: Enterprise
- ViewUserLicense: Universal
How the Menu Item Works:
- EnumParameter value filters records in OMOperatingUnit form to show only Division type
- MaintainUserLicense determines who can create/edit Divisions
- ViewUserLicense determines who can view Divisions (usually broader)
- When user clicks "Division" menu item, D365 opens OMOperatingUnit form pre-filtered to Division type
Key Parameters Explained:
| Parameter | Value | Purpose |
|---|---|---|
| EnumParameter | OMDivision | Identifies Division operating unit type |
| EnumTypeParameter | OMOperatingUnitType | The enum extension being targeted |
| Object | OMOperatingUnit | Form opened when menu item clicked |
| MaintainUserLicense | Enterprise | Required to create/edit Divisions |
| ViewUserLicense | Universal | Sufficient to view Divisions |
Operating Region Menu Item
Create Fox_OMOperatingRegion: Same configuration as Division, but change:
- Label: @SYS109262 (Region label)
- EnumParameter: OMOperatingRegion (instead of OMDivision)
Zone Menu Item
Create Fox_OMZone: Same configuration as Division, but change:
- Label: @WAX:FieldZone (Zone label)
- EnumParameter: OMZone (instead of OMDivision)
Menu Item Integration in Navigation
Add to Module Menu:
- Navigate to View → Application Explorer
- Search for
Organization Administrationmenu - Right-click → Edit → Add Menu Items
- Add Fox_OMDivision, Fox_OMOperatingRegion, Fox_OMZone
Expected Navigation Structure:
Organization Administration
├─ Setup
│ ├─ Organization
│ │ ├─ Division [Fox_OMDivision]
│ │ ├─ Operating Region [Fox_OMOperatingRegion]
│ │ └─ Zone [Fox_OMZone]
Benefits of This Approach:
- ✓ Intuitive user interface with separate menus for each level
- ✓ Licensing enforces data modification restrictions
- ✓ Seamless integration with OMOperatingUnit form
- ✓ No custom forms required - reuses standard D365 forms
- ✓ Single form with enum filtering = minimal maintenance
Step 5: Dimension Views - Financial Dimensioning
This is the most critical component. Dimension views make your custom operating units available as financial dimensions in Chart of Accounts structures, enabling transactional dimensioning and reporting.
Creating Dimension Views in Visual Studio
Create three Views:
For Division:
- Name:
Fox_DimAttributeOMDivisionView - Primary Data Source: OMOperatingUnit
- In Properties:
- Label: @SYS40992 (Division label)
- SingularLabel: @SYS40992
- TitleField1: OMOperatingUnitNumber
- TitleField2: Name
Dimension View Data Sources Configuration
For the Division View:
-
Add OMOperatingUnit as primary data source
-
Add DirPartyTable as related data source
- Relation: Join on RecId
- Purpose: Retrieves organization name for display
-
Add a Range Filter on OMOperatingUnit:
- Field: OMOperatingUnitType
- Value: OMDivision (your custom enum value)
- Purpose: Only shows Division type units
registerDimensionEnabledTypeIdentifier() Method
Add this critical method to the view class:
x++/// <summary> /// Registers this view as a dimension-enabled type /// Makes Division operating units available in Chart of Accounts structure /// </summary> [SubscribesTo(classstr(DimensionEnabledType), delegatestr(DimensionEnabledType, registerDimensionEnabledTypeIdentifiersDelegate))] public static void registerDimensionEnabledTypeIdentifier(DimensionIEnabledType _dimensionEnabledType) { _dimensionEnabledType.registerViewIdentifier(tablestr(Fox_DimAttributeOMDivisionView)); }
How It Works:
- Subscribes to the
registerDimensionEnabledTypeIdentifiersDelegateon application startup - Registers the view as a dimension-enabled type
- D365 automatically makes this view available when configuring account structures
- Users can then add Division as a segment in Chart of Accounts without any additional setup
Key Benefits:
- ✓ Automatic discovery by D365 framework
- ✓ No manual configuration needed
- ✓ Works with all standard accounting features
- ✓ Enables transaction-level dimensioning
Add View Fields
In the Designer, add three fields:
| Field Name | Data Field | Data Source | Purpose |
|---|---|---|---|
| Key | RecId | OMOperatingUnit | Unique identifier |
| Value | OMOperatingUnitNumber | OMOperatingUnit | Dimension code |
| Name | Name | DirPartyTable | Display name |
Add Indexes for Performance
Add two indexes to optimize lookups:
Index 1: ValueIdx
- Field: Value (OMOperatingUnitNumber)
- Purpose: Fast code lookup when users type a dimension value
- AllowDuplicates: No
Index 2: NameIdx
- Field: Name
- Purpose: Fast lookup by organization name in dropdowns
- AllowDuplicates: Yes
Operating Region Dimension View
Create Fox_DimAttributeOMOperatingRegionView: Same configuration as Division, with these changes:
- Label: @SYS109262
- Range Filter: Set OMOperatingUnitType = OMOperatingRegion
Add similar method and fields:
- registerDimensionEnabledTypeIdentifier() - Same pattern, register
Fox_DimAttributeOMOperatingRegionView - Fields: Key, Value, Name (same as Division)
- Indexes: ValueIdx, NameIdx (same as Division)
Zone Dimension View
Create Fox_DimAttributeOMZoneView: Same configuration as Division, with these changes:
- Label: @WAX:FieldZone
- Range Filter: Set OMOperatingUnitType = OMZone
Add similar method and fields:
- registerDimensionEnabledTypeIdentifier() - Same pattern, register
Fox_DimAttributeOMZoneView - Fields: Key, Value, Name (same as Division)
- Indexes: ValueIdx, NameIdx (same as Division)
Dimension Views Summary
Key Architecture Points:
| Component | Configuration |
|---|---|
| Primary Data Source | OMOperatingUnit table |
| Related Data Source | DirPartyTable (for names) |
| Range Filter | Filter by OMOperatingUnitType |
| Fields | Key (RecId), Value (Code), Name (Display) |
| Indexes | ValueIdx (code lookup), NameIdx (name lookup) |
| Delegate Method | registerDimensionEnabledTypeIdentifier() |
How Dimension Views Enable Financial Dimensioning:
- Each view registers itself on application startup
- D365 discovers all dimension-enabled views automatically
- Users can add Division/Region/Zone to Chart of Accounts structures
- Journal entries can then use Division, Region, Zone codes as dimension values
- Dimension values are looked up using the view fields (Value, Name)
- Indexes ensure fast performance even with large datasets
Performance Benefits:
- ValueIdx ensures fast code lookup (typical user entry path)
- NameIdx ensures fast name lookup (dropdown searches)
- Both indexes optimized for the specific enum type
- No cross-table scans needed for dimension lookups
Deployment & Configuration
Build the Solution
Creating Operating Units
Navigate to: Organization Administration > Setup > Operating Units > [Division/Region/Zone]
- Click New
- Enter the operating unit name (e.g., "Sales Division", "North America", "East Zone")
- Enter the operating unit number (e.g., "DIV-001", "REG-NA", "ZONE-E")
- Configure address and party information
- Save the record
Configuring Financial Dimensions
Navigate to: General Ledger > Chart of Accounts > Configure Account Structures
- Click New
- Add a segment:
- Select Fox_DimAttributeOMDivisionView (or Region/Zone)
- The view will appear in the dropdown automatically
- Define account structure rules
- Activate the structure
Users can now enter custom operating unit values in journal entries, purchase orders, and other transactional documents.
Benefits & Business Value
Organizational Flexibility
- Structure organizations exactly as needed without artificial constraints
- Support complex geographic hierarchies or divisional models
- Enable matrix organizations with multiple dimension options
Financial Reporting
- Multi-level organizational reporting by Division, Region, or Zone
- Flexible cost center and profit center analysis
- Geographic performance tracking
Operational Efficiency
- Native Excel bulk operations via add-in
- Standard DMF framework for data integration
- No custom workarounds or redundant dimensions
System Consistency
- Uses standard D365 patterns and conventions
- Integrates seamlessly with existing organization hierarchy
- Maintains data integrity and audit trails
Conclusion
Custom operating unit types provide a powerful, production-ready way to extend D365 F&O's organizational hierarchy and financial dimensioning capabilities. By implementing Division, Region, and Zone operating unit types, organizations can:
✓ Align D365 F&O structure with actual business organization
✓ Enable multi-level dimensional reporting
✓ Use custom types in Chart of Accounts structures
✓ Support bulk operations via Excel and DMF
✓ Reduce complexity and eliminate workarounds
✓ Enable multi-level dimensional reporting
✓ Use custom types in Chart of Accounts structures
✓ Support bulk operations via Excel and DMF
✓ Reduce complexity and eliminate workarounds
This implementation follows D365 F&O best practices and leverages proven architectural patterns used in standard system components.