<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Patrick Mouwen — PMN Consulting</title><description>Architecture notes on Dynamics 365 Commerce, D365 ERP, Power Platform and D365/Azure integration.</description><link>https://patrickmouwen.com/</link><language>en</language><item><title>D365 Commerce CSU V47/9.57 Unofficial Release Notes</title><link>https://patrickmouwen.com/blog/d365-commerce-csu-unofficial-release-notes-v9-57-10-0-47/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/d365-commerce-csu-unofficial-release-notes-v9-57-10-0-47/</guid><description>Unofficial release notes for D365 Commerce CSU V47/9.57, read assembly by assembly — what changed in the code, the APIs and the flight keys.</description><pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you work with D365 Commerce — as an architect, developer, ISV, or integration specialist — you know the feeling. A new version drops, the official docs give you the feature headlines, and then you&amp;#39;re left figuring out the rest: what actually changed in the code and APIs? Which schemas gained new fields? What are those new flight keys doing? Where is the product really heading?&lt;/p&gt;
&lt;p&gt;That&amp;#39;s exactly why I started publishing these unofficial Commerce CSU release notes.&lt;/p&gt;
&lt;p&gt;Every release, I pull apart the Commerce Scale Unit: decompile the assemblies, diff the OpenAPI specs, trace the new code paths, and map it all to what Microsoft shared about the release. The goal is simple — give the community the technical depth that doesn&amp;#39;t exist anywhere else.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve been building on Commerce CSU since around 2015. Over 650 APIs, B2C and B2B, headless and POS — this platform is deep, and it deserves documentation that matches.&lt;/p&gt;
&lt;p&gt;This edition — V9.57 / 10.0.47 — is the most architecturally significant release I&amp;#39;ve analyzed. Here&amp;#39;s what&amp;#39;s inside.&lt;/p&gt;
&lt;p&gt;𝘛𝘩𝘪𝘴 𝘢𝘳𝘵𝘪𝘤𝘭𝘦 𝘳𝘦𝘧𝘭𝘦𝘤𝘵𝘴 𝘮𝘺 𝘪𝘯𝘥𝘦𝘱𝘦𝘯𝘥𝘦𝘯𝘵 𝘵𝘦𝘤𝘩𝘯𝘪𝘤𝘢𝘭 𝘢𝘯𝘢𝘭𝘺𝘴𝘪𝘴 𝘰𝘧 𝘴𝘰𝘧𝘵𝘸𝘢𝘳𝘦 𝘢𝘳𝘵𝘪𝘧𝘢𝘤𝘵𝘴. 𝘐𝘵 𝘪𝘴 𝘯𝘰𝘵 𝘦𝘯𝘥𝘰𝘳𝘴𝘦𝘥 𝘣𝘺 𝘰𝘳 𝘢𝘧𝘧𝘪𝘭𝘪𝘢𝘵𝘦𝘥 𝘸𝘪𝘵𝘩 𝘔𝘪𝘤𝘳𝘰𝘴𝘰𝘧𝘵. 𝘍𝘶𝘭𝘭 𝘥𝘪𝘴𝘤𝘭𝘢𝘪𝘮𝘦𝘳 𝘢𝘵 𝘵𝘩𝘦 𝘦𝘯𝘥 𝘰𝘧 𝘵𝘩𝘪𝘴 𝘢𝘳𝘵𝘪𝘤𝘭𝘦.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/d365-commerce-csu-unofficial-release-notes-v9-57-10-0-47/1775116795528-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;A-Overview of this Release&lt;/h2&gt;
&lt;p&gt;The 9.57 / 10.0.47 Release is defined by 3 architectural shifts: the arrival of MCP (Model Context Protocol) as a first-class CSU endpoint, a fundamental identity model change for B2B Commerce, and the continued maturation of the headless payment and POS modernization story.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/d365-commerce-csu-unofficial-release-notes-v9-57-10-0-47/1775117543162-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The headline is the MCP server embedded directly into the CSU. Microsoft has shipped an MCP endpoint (still in private preview!) with API key authentication, structured tool definitions, and logging. It exposes Commerce capabilities (product search, cart management, payment link creation) to AI agents and agentic platforms. This is not a bolt-on: the CSU now ships with ModelContextProtocol assemblies, AI Abstractions, and Server-Sent Events transport. If you are building agentic commerce experiences — conversational shopping, AI-assisted ordering, or any scenario where an LLM needs to interact with Commerce business logic — the infrastructure is now in the box and ready to be enabled.&lt;/p&gt;
&lt;p&gt;The second major shift is the B2B multi-outlet model. Commerce is moving from Customer (Person) type to Contact type for B2B buyers. This is a deep, pervasive change: ContactPersonId now flows through Cart, SalesOrder, security checks, and the entire cart-to-order lifecycle. New APIs support contact retrieval, identity linking, and organization-level catalog access. A feature flag (RetailB2BContactMultiOutletOrderingFeature) gates the rollout, and migration scripts are being provided — but this is a one-way street once enabled. If you are in B2B Commerce, this is the most impactful change to your data model in years.&lt;/p&gt;
&lt;p&gt;Third, the POS modernization journey reaches the product listing page, product detail page, and transaction page — all now migrated to React and Fluent UI. What makes this release different from a typical UI refresh is the API surface behind it: eight new VisualProfile flags give you register-level control over which insights (inventory, discounts, product suggestions) are surfaced, and a new promotion evaluation endpoint (GetAvailablePromotionsByTransactionJson) lets the React front-end evaluate discount eligibility without a full server-side cart round-trip.&lt;/p&gt;
&lt;p&gt;Alongside these three themes, the Unified Pricing engine (GUP) receives its heaviest investment yet (10 new flight keys), the cross-legal entity inventory story lands with a dedicated API for multi-company store search, and the telemetry stack gets a complete overhaul — moving from the older infrastructure to Azure Data Explorer / Kusto-based observability.&lt;/p&gt;
&lt;h2&gt;B-Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;V9.57 Commerce CSU API explorer (React control with filter/search): &amp;lt;/tools/csu-api-explorer-v57.html&amp;gt;&lt;/li&gt;
&lt;li&gt;V9.57 full Swagger/OpenAPI spec (direct download): &amp;lt;/tools/9.57.26071.1.json&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;C — API and Schema Changes&lt;/h2&gt;
&lt;h3&gt;C.1 New APIs&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/d365-commerce-csu-unofficial-release-notes-v9-57-10-0-47/1775116944631-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;C.2 Removed APIs&lt;/h3&gt;
&lt;p&gt;None.&lt;/p&gt;
&lt;h3&gt;C.3 Data Model Changes&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/d365-commerce-csu-unofficial-release-notes-v9-57-10-0-47/1775117003247-3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3.1 B2B Multi-Outlet/Contact model&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cart and SalesOrder gained ContactPersonId — this is the primary identifier linking a transaction to the specific B2B contact who placed it, distinct from the organization customer account.&lt;/li&gt;
&lt;li&gt;BusinessPartner gained OrganizationCustomerAccountNumber, Addresses[], and SpendingLimit — enriching the organization-level entity with account resolution and spending governance data.&lt;/li&gt;
&lt;li&gt;BusinessPartnerUser gained ContactPersonId, IsEnabled, OrganizationCustomerAccountNumber, and Phone — the user entity now bridges to the Contact model with explicit activation state and org-level tracing.&lt;/li&gt;
&lt;li&gt;New entity: BusinessPartnerContact (PartyRecordId, IsActivated, FirstName, LastName) — a lightweight Contact representation used by the GetContact API.&lt;/li&gt;
&lt;li&gt;New entity: LinkToExistingDirPartyResult (PartyRecordId, ExternalIdentityLinkRecordId, FirstName, LastName, EmailAddress) — the result of identity-to-party linking during migration.&lt;/li&gt;
&lt;li&gt;New security claim: ContactPersonIdClaimType added to the claims system — the Contact identity is now a first-class authentication claim alongside CustomerId and StaffId.&lt;/li&gt;
&lt;li&gt;New role: &amp;quot;BusinessPartnerContact&amp;quot; added as a recognized principal role.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;𝐋𝐢𝐤𝐞𝐥𝐲 𝐢𝐧𝐭𝐞𝐧𝐭: This is the API and data model surface for the fundamental B2B identity shift from Customer (Person) to Contact. A single contact can buy for multiple organizations, orders are created against the organization account (not the individual), and pricing/credit limits/catalogs are driven by the organization. The migration path (CreateLinkToExistingParty) ensures existing B2B users retain their external identity mappings when transitioning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3.2 Cross-Legal Entity Inventory&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OrgUnitLocation gained DataAreaId — stores and warehouses now carry their legal entity identifier in the API surface.&lt;/li&gt;
&lt;li&gt;OrgUnitAvailabilitySearchCriteria gained DataAreaIds[] — the search criteria can now specify which legal entities to include.&lt;/li&gt;
&lt;li&gt;New feature flag: CrossCompanyInventoryLookupFeatureName gates the capability.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;𝐋𝐢𝐤𝐞𝐥𝐲 𝐢𝐧𝐭𝐞𝐧𝐭: Enables POS users to see inventory across legal entities in the same fulfillment group. Backed by Inventory Visibility Service (IVS). This may be extended to e-commerce, DOM cross-LE fulfillment with intercompany orders, and decoupled ICO lifecycle in the future.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3.3 Asynchronous payments/Pay-by-link&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AsynchronousPaymentParameters gained ReturnUrl and ShopperLocale — supporting proper redirect-based payment flows and locale-aware payment page rendering.&lt;/li&gt;
&lt;li&gt;CreatePaymentLinkParameters gained the same ReturnUrl and ShopperLocale fields.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;𝐋𝐢𝐤𝐞𝐥𝐲 𝐢𝐧𝐭𝐞𝐧𝐭: Continuation of the V46 async payment maturation. ReturnUrl enables proper redirect-back after payment completion (critical for QR code / pay-by-link flows where the customer completes payment on a different device or browser). ShopperLocale ensures the payment page renders in the customer&amp;#39;s language — directly supporting the Adyen connector QR code feature announced for 10.0.47&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3.4 POS Modernization - VisualProfile feature flags&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;VisualProfile gained eight new nullable boolean flags:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ShowDimensionPickerEnabled&lt;/li&gt;
&lt;li&gt;ShowInlineQtyDiscountMsgEnabled&lt;/li&gt;
&lt;li&gt;ShowNearbyInventoryEnabled&lt;/li&gt;
&lt;li&gt;ShowProductSuggestionsEnabled&lt;/li&gt;
&lt;li&gt;ShowQuantityDiscountCaptionsEnabled&lt;/li&gt;
&lt;li&gt;ShowQuantityDiscountsEnabled&lt;/li&gt;
&lt;li&gt;ShowStockCountAndAvailabilityEnabled&lt;/li&gt;
&lt;li&gt;ShowThresholdDiscountBarEnabled&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Where it shows up: All endpoints that return VisualProfile (device configuration, register setup).&lt;/p&gt;
&lt;p&gt;𝐋𝐢𝐤𝐞𝐥𝐲 𝐢𝐧𝐭𝐞𝐧𝐭: These are the register-level feature flags for the React/Fluent UI POS modernization. Each flag controls a specific insight or UI element on the modernized search results, PDP, or transaction pages. This gives retailers fine-grained control over rollout — you can enable inventory insights for one register while keeping it off for others, allowing a phased transition and A/B testing of the new experience.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3.5 Self-Checkout Language Selection&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DeviceConfiguration gained EnableLanguageSelectionOnSelfCheckoutWelcomePage (boolean), SecondaryLanguages (string[]), and OfflineSQLiteDbExport (boolean).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Where it shows up: Device configuration endpoints.&lt;/p&gt;
&lt;p&gt;𝐋𝐢𝐤𝐞𝐥𝐲 𝐢𝐧𝐭𝐞𝐧𝐭: EnableLanguageSelectionOnSelfCheckoutWelcomePage and SecondaryLanguages power the multilingual self-checkout experience. The customer can switch language on the welcome screen, and all UI elements update instantly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3.6 Address Purposes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Address entity gained AddressPurposes (IList of AddressPurpose) — enriching addresses with their associated purpose values (Business, Delivery, Home, etc.).&lt;/p&gt;
&lt;p&gt;Where it shows up: This is the single most widespread change in the diff by surface area — virtually every endpoint that returns an Address object now includes AddressPurposes. The change is controlled by the UseLogisticsLocationMultiRoleTypesFlight.&lt;/p&gt;
&lt;p&gt;𝐋𝐢𝐤𝐞𝐥𝐲 𝐢𝐧𝐭𝐞𝐧𝐭: Addresses can serve multiple purposes simultaneously. Previously, purpose was inferred or required separate lookups. Now it&amp;#39;s inline — improving address selection logic for delivery, invoicing, and B2B scenarios where a single address may serve both business and delivery purposes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3.7 Unified Pricing - PricingComponentCodeConcurrencyMode&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;New enum PricingComponentCodeConcurrencyMode with values: None, Compounded, BestPrice, NeverCompound.&lt;/p&gt;
&lt;p&gt;Where it shows up: In the pricing engine&amp;#39;s price adjustment evaluation pipeline, controlling how pricing components interact across priorities.&lt;/p&gt;
&lt;p&gt;𝐋𝐢𝐤𝐞𝐥𝐲 𝐢𝐧𝐭𝐞𝐧𝐭: Extends the GUP concurrency model with a NeverCompound mode — allowing pricing rules to explicitly prevent compounding with other adjustments. This is part of the broader Unified Pricing maturation that includes fixed price adjustment support, tender discounts, multi-currency conversion, and enhanced concurrency modeling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3.8 MCP Infrastructure&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;New schema McpException (extends CommerceException) — the first appearance of MCP error handling in the CSU&amp;#39;s public schema.&lt;/p&gt;
&lt;p&gt;Where it shows up: Not exposed as an endpoint in the OData Swagger — the MCP server runs on a separate /mcp endpoint using Server-Sent Events (SSE) transport.&lt;/p&gt;
&lt;p&gt;𝐋𝐢𝐤𝐞𝐥𝐲 𝐢𝐧𝐭𝐞𝐧𝐭: While the MCP endpoint itself is not part of the OData API surface, the exception type landing in the public schema signals that MCP is now a supported, (soon) production-grade component of the CSU. See Section D for the full MCP code analysis.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3.9 Telemetry&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;EnvironmentConfiguration gained ClientKustoTelemetryKey, HardwareStationKustoTelemetryKey, and KustoTelemetryEndpoint.&lt;/p&gt;
&lt;p&gt;Where it shows up: Environment configuration endpoints.&lt;/p&gt;
&lt;p&gt;𝐋𝐢𝐤𝐞𝐥𝐲 𝐢𝐧𝐭𝐞𝐧𝐭: The CSU is moving to Azure Data Explorer (Kusto) based telemetry. A new Microsoft.Dynamics.Retail.Diagnostics.Kusto assembly ships with V47, alongside Microsoft Unified Telemetry libraries. This replaces the older telemetry infrastructure with direct Kusto ingestion — enabling richer, queryable observability for Commerce operations.&lt;/p&gt;
&lt;h3&gt;D —Code Changes&lt;/h3&gt;
&lt;p&gt;This section goes beyond the API surface and examines changes in the decompiled CSU assemblies (the actual Commerce Scale Unit runtime code). 287 assemblies in V47 vs 265 in V46.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/d365-commerce-csu-unofficial-release-notes-v9-57-10-0-47/1775118473697-4.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;D.1 MCP Server - Full implementation in the box&lt;/h3&gt;
&lt;p&gt;The most significant code-level finding. The CSU now ships with a complete MCP (Model Context Protocol) server implementation embedded directly in Microsoft.Dynamics.Retail.RetailServerLibrary.AspNetCore.&lt;/p&gt;
&lt;p&gt;New namespaces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Microsoft.Dynamics.Retail.RetailServerLibrary.Mcp&lt;/li&gt;
&lt;li&gt;.Mcp.Configuration&lt;/li&gt;
&lt;li&gt;.Mcp.Contracts&lt;/li&gt;
&lt;li&gt;.Mcp.Converter / .Converters&lt;/li&gt;
&lt;li&gt;.Mcp.Exceptions&lt;/li&gt;
&lt;li&gt;.Mcp.Middlewares&lt;/li&gt;
&lt;li&gt;.Mcp.Tools&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Three tool classes ship out of the box (may be extended):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/d365-commerce-csu-unofficial-release-notes-v9-57-10-0-47/1775118491968-5.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Configuration via app settings:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/d365-commerce-csu-unofficial-release-notes-v9-57-10-0-47/1775118515099-6.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;𝐒𝐞𝐜𝐮𝐫𝐢𝐭𝐲: Full API key authentication middleware (McpApiKeyAuthenticationMiddleware) with named client support. Comprehensive structured logging via McpEvents enum covering authentication, tool call lifecycle, and errors.&lt;/p&gt;
&lt;p&gt;𝐄𝐫𝐫𝐨𝐫 𝐡𝐚𝐧𝐝𝐥𝐢𝐧𝐠: Custom McpException with domain-specific error codes: InvalidChannelId, InvalidCartId, InvalidProductId, InvalidQuantity, CartLineNotFound, CustomerNameRequired, EmailRequired, StreetRequired, CityRequired, StateRequired, ZipCodeRequired, CountryOrRegionCodeRequired, CartHasNoLines, CartMissingShippingAddress, DeliveryModeRequired, DeliveryModeDescriptionNotFound, CartOperationRetryFailed.&lt;/p&gt;
&lt;p&gt;𝐍𝐞𝐰 𝐚𝐬𝐬𝐞𝐦𝐛𝐥𝐢𝐞𝐬 𝐬𝐮𝐩𝐩𝐨𝐫𝐭𝐢𝐧𝐠 𝐌𝐂𝐏: ModelContextProtocol, ModelContextProtocol.Core, ModelContextProtocol.AspNetCore, Microsoft.Extensions.AI.Abstractions , &lt;a href=&quot;http://System.Net&quot;&gt;System.Net&lt;/a&gt;.ServerSentEvents.&lt;/p&gt;
&lt;h3&gt;D.2 B2B Contact Model - Deep Pervasive Implementation&lt;/h3&gt;
&lt;p&gt;10+ new data request types span the full data access layer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GetBusinessPartnerContactByContactPartyDataRequest&lt;/li&gt;
&lt;li&gt;GetBusinessPartnerContactByContactPersonIdDataRequest&lt;/li&gt;
&lt;li&gt;GetBusinessPartnerContactByEmailDataRequest&lt;/li&gt;
&lt;li&gt;GetBusinessPartnerContactByExternalIdentityDataRequest&lt;/li&gt;
&lt;li&gt;GetBusinessPartnersByContactPartyDataRequest&lt;/li&gt;
&lt;li&gt;GetBusinessPartnerUserByContactPersonIdDataRequest&lt;/li&gt;
&lt;li&gt;GetBusinessPartnerUserByOrganizationCustomerAndContactPartyDataRequest&lt;/li&gt;
&lt;li&gt;GetBusinessPartnerCatalogsByContactPersonIdDataRequest&lt;/li&gt;
&lt;li&gt;GetBusinessPartnerByOrganizationCustomerAccountNumberDataRequest&lt;/li&gt;
&lt;li&gt;CreateLinkToExistingPartyDataRequest&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The feature flag 𝐑𝐞𝐭𝐚𝐢𝐥𝐁2𝐁𝐂𝐨𝐧𝐭𝐚𝐜𝐭𝐌𝐮𝐥𝐭𝐢𝐎𝐮𝐭𝐥𝐞𝐭𝐎𝐫𝐝𝐞𝐫𝐢𝐧𝐠𝐅𝐞𝐚𝐭𝐮𝐫𝐞𝐍𝐚𝐦𝐞 is checked throughout the codebase — customer service, security, workflow, and catalog resolution all branch between the old Person path and the new Contact path. Cart access security now validates ContactPersonId as a third dimension alongside CustomerId and StaffId.&lt;/p&gt;
&lt;h3&gt;D.3 Bing Search Removed&lt;/h3&gt;
&lt;p&gt;Microsoft.Dynamics.Commerce.Runtime.SearchServices.Bing assembly has been removed from V47. Product search is now exclusively handled by Azure Search / Azure AI Search.&lt;/p&gt;
&lt;h3&gt;D.4 Telemetry Stack Overhaul&lt;/h3&gt;
&lt;p&gt;New assembly: Microsoft.Dynamics.Retail.Diagnostics.Kusto — a Kusto logger implementation for Retail components. Accompanied by 6 Microsoft Unified Telemetry assemblies (Microsoft.Unified.Telemetry, .OpenTelemetrySink, .ContractsAndContextProviders, Microsoft.Office.Telemetry.EventFlags, Microsoft.Office.PrivacyGuard). This is a platform-level shift to structured, Kusto-queryable telemetry.&lt;/p&gt;
&lt;h3&gt;D.5 Unified Pricing Engine - Significant Evolution&lt;/h3&gt;
&lt;p&gt;Key code-level changes in the pricing engine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New PricingComponentCodeConcurrencyMode with NeverCompound support&lt;/li&gt;
&lt;li&gt;GetAttributeTenderDiscounts method added — GUP now supports tender-type (payment-method) discounts via ReadGlobalUnifiedPricingTenderDiscounts&lt;/li&gt;
&lt;li&gt;New GetBasePriceTypeDataRequest/Response — base price type resolution by price tree name&lt;/li&gt;
&lt;li&gt;Generic currency support with exchange rate type conversion — multi-currency pricing across legal entities&lt;/li&gt;
&lt;li&gt;Fixed price adjustment support (OfferPrice method) gated by GUPSupportFixedPriceAdjustmentFlight&lt;/li&gt;
&lt;li&gt;Unit of measure conversion caching for price adjustments&lt;/li&gt;
&lt;li&gt;Enhanced discount header amount currency conversion&lt;/li&gt;
&lt;li&gt;V2 sproc for non-coupon discount category lookups (performance)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;E-New Flight Keys&lt;/h2&gt;
&lt;p&gt;Microsoft implements new CSU flight keys with every new CSU version. These undocumented flight keys steer specific CSU behavior. V9.57/10.0.47 adds 29 new flight keys (picking up from the last V46 key at index 151).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/d365-commerce-csu-unofficial-release-notes-v9-57-10-0-47/1775123062247-7.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/d365-commerce-csu-unofficial-release-notes-v9-57-10-0-47/1775123077878-8.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/d365-commerce-csu-unofficial-release-notes-v9-57-10-0-47/1775123090080-9.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;F - Disclaimer&lt;/h2&gt;
&lt;p&gt;The content of this article represents my independent technical analysis and personal interpretation of publicly available software artefacts. It is not endorsed by, affiliated with, or authorised by Microsoft Corporation. Nothing in this article constitutes official Microsoft documentation, guidance, or product commitments.&lt;/p&gt;
&lt;p&gt;All findings are derived from analysis of the software and public documentation. Feature descriptions, presumable use cases, and &amp;quot;likely intent&amp;quot; assessments reflect my professional opinion based on observable code and API changes — they may not reflect Microsoft&amp;#39;s actual design intent, planned behaviour, or final implementation.&lt;/p&gt;
&lt;p&gt;Information regarding features described as preview, private preview, or roadmap items is subject to change at Microsoft&amp;#39;s sole discretion and should not be relied upon for planning, purchasing, or architectural decisions.&lt;/p&gt;
&lt;p&gt;This article is provided for informational and educational purposes only, on an &amp;quot;as-is&amp;quot; basis without warranties of any kind, express or implied. The author assumes no liability for any direct, indirect, incidental, or consequential damages arising from the use of or reliance on the information contained herein, including but not limited to damages resulting from technical decisions, implementation choices, or system behaviour based on this content.&lt;/p&gt;
&lt;p&gt;For authoritative product information, consult Microsoft&amp;#39;s official documentation at &lt;a href=&quot;https://learn.microsoft.com&quot;&gt;learn.microsoft.com&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>Technicaldev</category></item><item><title>The middle layer is 50% of your transformation</title><link>https://patrickmouwen.com/blog/middle-layer-50-your-transformation/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/middle-layer-50-your-transformation/</guid><description>What a detour into food certification taught me about ERP, monoliths and agentic AI — and why the middle layer carries half the transformation.</description><pubDate>Thu, 26 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;What a detour into food certification taught me about ERP, monoliths, and agentic AI&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I spend most of my time in Retail, Wholesale, Manufacturing, and Supply Chain. Dynamics 365, Commerce platforms, Enterprise architectures, Integration architectures — that’s my world. So when I recently took on a project in professional services — specifically in the Testing, Inspection &amp;amp; Certification (TIC) industry — I expected a completely different landscape.&lt;/p&gt;
&lt;p&gt;What I found instead was remarkably familiar.&lt;/p&gt;
&lt;p&gt;Within a day of research, I recognised the same architectural patterns, the same monolithic constraints, and the same integration challenges I’ve been solving in Retail and Manufacturing for years. And the solutions? Almost identical.&lt;/p&gt;
&lt;p&gt;That’s worth writing about, because I think there’s a broader lesson here for anyone struggling with the question of how to make their Enterprise Architecture Agentic AI ready.&lt;/p&gt;
&lt;h2&gt;The monolith that everyone trusts&lt;/h2&gt;
&lt;p&gt;In the TIC world, certification bodies rely on a specialised ERP system to manage the full lifecycle of audits, inspections, and certifications. Think of it as the equivalent of Dynamics F&amp;amp;O or SAP, but built specifically for testing and certification workflows.&lt;/p&gt;
&lt;p&gt;This system is deeply trusted. It’s the single version of the truth. It’s 100% auditable. The organisation’s accreditation depends on it. People have built their careers around it. The former CEO introduced it. It has decades of credibility.&lt;/p&gt;
&lt;p&gt;Sound familiar? That’s exactly how enterprises describe their ERP. And for good reason — these systems are reliable, comprehensive, and proven. They earn their monolithic status through years of delivering on their core promise: be the system of record.&lt;/p&gt;
&lt;h2&gt;The problem: monoliths don’t speak event&lt;/h2&gt;
&lt;p&gt;Here’s where it gets interesting. The TIC industry is being disrupted by scheme owners — the organisations that define certification standards — launching their own modern cloud platforms with comprehensive REST APIs. These new platforms support headless execution, event-driven workflows, and full lifecycle management via API.&lt;/p&gt;
&lt;p&gt;But the trusted monolith at the heart of the certification body? It exposes a basic CRUD API layer. No webhooks. No event notifications. No publish/subscribe. No way to say “tell me when a quote gets approved” and have the system push that notification/&lt;/p&gt;
&lt;p&gt;And that’s a problem, because the future everyone is talking about — Agentic AI — lives and breathes on deterministic, event-driven APIs. An AI agent that needs to “check if the quote was approved, then trigger the planning workflow, then notify the auditor” cannot poll a CRUD endpoint every five minutes and hope for the best. It needs events. It needs a contract. It needs MCP.&lt;/p&gt;
&lt;h2&gt;The middle layer: where transformation actually happens&lt;/h2&gt;
&lt;p&gt;Here’s the insight I keep seeing confirmed, now across two completely different industries: the transformation isn’t in the monolith. It’s in the layer &lt;em&gt;between&lt;/em&gt; the monoliths.&lt;/p&gt;
&lt;p&gt;Many implementation partners still think that ERP (or TIC platform, or CRM) is &lt;strong&gt;70–80%&lt;/strong&gt; of a transformation program. My experience says it’s shifting. The middle layer — the operational data platform with workflow orchestration and AI enablement — is becoming &lt;strong&gt;50%&lt;/strong&gt; of the programme. And growing.&lt;/p&gt;
&lt;p&gt;What does this middle layer look like in practice?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/middle-layer-50-your-transformation/1774536468452-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;1. Data Layer: an operational database — not a data warehouse&lt;/h3&gt;
&lt;p&gt;Extract the relevant entities and status changes from the monolith on a regular schedule. Not a full canonical model for BI. Not a data lake. A focused, pragmatic operational database that stores only what’s needed for cross-system integration: business partners, work orders, approvals, key identifiers, status timestamps.&lt;/p&gt;
&lt;p&gt;The key insight: if your monolith can’t emit events, you construct the events yourself by detecting state changes in the extracted data. A quotation that moved from “draft” to “accepted” between two extraction cycles? That’s an event. A work order that changed status from “in review” to “approved”? That’s a trigger. You don’t need the monolith to tell you — you can see it in the data.&lt;/p&gt;
&lt;h3&gt;2. Workflow Layer: a workflow orchestration layer&lt;/h3&gt;
&lt;p&gt;Logic Apps, Power Automate, Azure Functions, Service Bus — whatever your stack, the orchestration layer sits on top of the operational database and reacts to the constructed events. When it detects that a quote was approved, it calls the external platform’s API to register the client. When a certification decision is made, it pushes the outcome to the scheme owner’s registry.&lt;/p&gt;
&lt;p&gt;This is where business process logic lives — not in the monolith (which is too rigid) and not in the external platform (which you don’t control). The orchestration layer is yours. You own it, you design it, you evolve it.&lt;/p&gt;
&lt;h3&gt;3. Action Layer: An MCP surface for agentic AI&lt;/h3&gt;
&lt;p&gt;If your monolith’s CRUD APIs are exposed through &lt;strong&gt;Azure API management,&lt;/strong&gt; they can be wrapped as MCP-enabled tool endpoints. Combined with CRM, F&amp;amp;O, and external platform endpoints on the same gateway, you create a unified tool surface for AI agents.&lt;/p&gt;
&lt;p&gt;Suddenly, a Copilot agent can query a client’s certification status from the TIC system, check their outstanding invoices in F&amp;amp;O, look up their contact history in CRM, and draft a follow-up — all through one protocol. The monolith doesn’t need to be rebuilt. It just needs to be accessible.&lt;/p&gt;
&lt;h3&gt;4. Intelligence layer: the brains for the &amp;#39;feedback loop&amp;#39;&lt;/h3&gt;
&lt;p&gt;Here’s where it comes together. Relevant operational data flows in, is combined with BI insights and AI powered predictive analytics, actions are distilled, and with MCP those actions are executed across systems. Collect, analyse, act — all through the middle layer.&lt;/p&gt;
&lt;p&gt;Over time, fewer and fewer employees will work in the monoliths - They operate in the middle layer instead, relying on Agentic AI being the &amp;#39;strings&amp;#39; to direct the System of record &amp;#39;puppets&amp;#39;.&lt;/p&gt;
&lt;h2&gt;The shift: let monoliths be monoliths&lt;/h2&gt;
&lt;p&gt;I know that sounds circular, but hear me out. For decades, we’ve expected our ERP to be everything: system of record, workflow engine, reporting tool, collaboration platform, and now AI host. That’s too much weight for any monolith.&lt;/p&gt;
&lt;p&gt;The shift I see — confirmed in retail, manufacturing, and now in TIC — is that monoliths are settling into what they’re actually good at: being the trusted, auditable, comprehensive system of record. They keep their robustness. They keep their reputation. They keep their regulatory compliance.&lt;/p&gt;
&lt;p&gt;But the workflow-oriented tooling, the approval flows, the cross-system orchestration, the AI-enabled intelligence — that doesn’t need to be built inside the monolith. It lives in the middle layer. And increasingly, it’s the middle layer that users actually interact with day to day.&lt;/p&gt;
&lt;p&gt;The result? Fewer users logging into ERP. Fewer users logging into the TIC platform. These systems become the trusted archive, the system of record. The middle layer becomes the operational face — where work gets done, decisions get made, and AI agents collaborate with humans.&lt;/p&gt;
&lt;p&gt;Agentic AI acts as the &lt;strong&gt;strings&lt;/strong&gt; to direct the &lt;strong&gt;puppets&lt;/strong&gt;, the &lt;strong&gt;systems of record&lt;/strong&gt; which now become &lt;strong&gt;systems of action&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/middle-layer-50-your-transformation/1774533157269-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Best of all worlds&lt;/h2&gt;
&lt;p&gt;This isn’t a replacement strategy. It’s an augmentation strategy. The monolith retains its strengths. The middle layer compensates for its limitations. And the organisation gets an architecture that’s ready for agentic AI without ripping out the systems everyone trusts.&lt;/p&gt;
&lt;p&gt;I found it striking that a step into a completely different industry confirmed what I’ve been seeing in retail and commerce for years. The same monolithic patterns. The same CRUD API constraints. The same event-driven gaps. And the same solution: build the middle layer, make it intelligent, and let the monoliths do what they do best.&lt;/p&gt;
&lt;p&gt;If your organisation is asking “how do we make our architecture agentic AI ready?” — the answer probably isn’t “replace the ERP.” or to put your software vendor under pressure. It’s &lt;strong&gt;build the layer between your systems&lt;/strong&gt;. That’s where 50% of your transformation lives. And that’s where the future is being built.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
</content:encoded><category>Commerce</category></item><item><title>Designing Headless Commerce Starts with Data — Not Apps</title><link>https://patrickmouwen.com/blog/designing-headless-commerce-starts-data-apps/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/designing-headless-commerce-starts-data-apps/</guid><description>Headless apps hold no data and no local logic. The hard part is not the journey — it is getting the right data, at the right quality, from the backend.</description><pubDate>Wed, 04 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It doesn’t matter if I speak to e-commerce gurus or leaders in App development, they all say the same: the difficulty is not making the Apps or customer journeys. The difficulty is in getting the &lt;strong&gt;right data&lt;/strong&gt;, in the &lt;strong&gt;right quality&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This is even more urgent in &lt;em&gt;&lt;strong&gt;Headless&lt;/strong&gt;&lt;/em&gt; setups. Headless Apps do not have &lt;em&gt;any&lt;/em&gt; data or local business logic. They live by data and services from backend systems like Dynamics 365 ERP and Dynamics 365 CE (CRM).&lt;/p&gt;
&lt;p&gt;In this blog post, we’ll see how we can overcome these hurdles.&lt;/p&gt;
&lt;h2&gt;Hurdle 1 – Exposing the right data right&lt;/h2&gt;
&lt;p&gt;In the ideal world, &lt;strong&gt;UX designers&lt;/strong&gt; are in the lead when Apps, portals or any customer oriented systems are built. Side note here is that I recommend to &lt;em&gt;converge&lt;/em&gt; customer and employee oriented apps, but let’s put that aside. In how many Dynamics 365 implementation projects are UX designers in the lead when it comes to customer oriented scenarios? I didn’t come across many in my 20-year career.&lt;/p&gt;
&lt;p&gt;Let’s revert the question. &lt;em&gt;How&lt;/em&gt; can we put UX designers in the lead?&lt;/p&gt;
&lt;p&gt;My answer:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Start with the journey.&lt;/strong&gt; Let the UX designers design the optimal customer journey first and &lt;em&gt;then&lt;/em&gt; map to Data and Services. Not the other way around. Literally map a wireframe to APIs. Please note that this requires your API providers to be very experienced in &lt;em&gt;both&lt;/em&gt; the &lt;strong&gt;backend system&lt;/strong&gt; (like D365 ERP) &lt;em&gt;and&lt;/em&gt; &lt;strong&gt;API domain&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/designing-headless-commerce-starts-data-apps/1770242578347-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Enterprise API library&lt;/strong&gt;. Publish core/key APIs in an enterprise API library. Ideally even before wireframe design begins. My best practice as I already described in my &lt;a href=&quot;/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/&quot;&gt;blog post in 2022&lt;/a&gt;: describe your D365 APIs in the OpenAPI standard and publish them on &lt;strong&gt;Azure API Management&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/designing-headless-commerce-starts-data-apps/1770242217417-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Publish the OpenAPI specifications&lt;/strong&gt;. Use APIM Developer portal or Swagger portal to deliver the API specs to your App/portal developers. See some examples below which combine APIs based on D365 Commerce and D365 ERP:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Composite APIs&lt;/strong&gt;. In many cases, UX designers design grids with &lt;strong&gt;data which is exposed by multiple APIs&lt;/strong&gt;. For example, Sales order line information combined with product data. My best practice: combine them in a &lt;em&gt;composite&lt;/em&gt; API to make life easier for the developers. The “individual” APIs and “composites” can co-exist in your API library!&lt;/p&gt;
&lt;p&gt;With the wireframe mappings and documented APIs in the bag, frontend developers can now automatically generate code to consume the APIs. This will allow them to &lt;strong&gt;autonomously&lt;/strong&gt; support your UX designers!&lt;/p&gt;
&lt;h2&gt;Hurdle 2 – Exposing data in the right quality&lt;/h2&gt;
&lt;p&gt;If your PDM/PIM data does not contain the right product descriptions, categorizations or translations, it can negatively impact your customer experience. No matter how strong your UX/customer journey is designed and implemented. In headless Apps, frontend journeys may even get broken returning no data at all!&lt;/p&gt;
&lt;p&gt;So, the key question is: how can we guarantee data quality? My best practices:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Identify your critical data&lt;/strong&gt;. Identify backend setup and master data which is critical for your customer journeys. You can easily derive them from your wireframe/API mappings. Map these requirements back to the data and processes in D365 ERP and CRM or other backend Apps.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/designing-headless-commerce-starts-data-apps/1770242316886-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Prevent errors by a strong process foundation&lt;/strong&gt;. Educate the responsible business owners properly. Make them understand what the impact of their actions is on data quality.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/designing-headless-commerce-starts-data-apps/1770242370711-3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Deploy a Data Quality framework&lt;/strong&gt;. Utilize &lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/data-platform/azure-synapse-link-synapse&quot;&gt;Synapse link&lt;/a&gt; or &lt;a href=&quot;https://learn.microsoft.com/en-us/power-apps/maker/data-platform/azure-synapse-link-view-in-fabric&quot;&gt;Fabric link&lt;/a&gt; to export your data to Azure Data Lake. Use Azure Data Factory to process the data and identify errors and warnings. Write these errors and warnings into tables. Surface the errors and warnings in Power BI Reports. This is your feedback loop into #2, the BAU processes in your organization.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/designing-headless-commerce-starts-data-apps/1770242497245-4.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Deploy a Data Quality agent&lt;/strong&gt;. Let Data Quality agents work with the errors and warnings to assist your users to resolve the error. Agents could suggest data actions, such as unpublishing items from assortments if they are missing critical data or prices. As a next step, Agents could even resolve the actual issues utilizing &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/copilot/copilot-mcp&quot;&gt;&lt;strong&gt;Dynamics 365 MCP server&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;About the Author&lt;/h2&gt;
&lt;p&gt;The further I progress in my career, the more I see that the most successful IT projects aren’t feature driven. The most successful projects have a holistic view, acknowledging that downstream success can depend on upstream quality and structure.&lt;/p&gt;
&lt;p&gt;Connect with me directly on &lt;a href=&quot;https://www.linkedin.com/in/patrickmouwen/&quot;&gt;LinkedIn&lt;/a&gt; if you want to know more.&lt;/p&gt;
</content:encoded><category>Headless Commerce</category></item><item><title>A language trick for headless commerce</title><link>https://patrickmouwen.com/blog/language-trick-headless-commerce/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/language-trick-headless-commerce/</guid><description>An undocumented Accept-Language header changes what Commerce CSU returns — translated product names, delivery options and search results in headless.</description><pubDate>Fri, 23 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you follow my quarterly unofficial release notes for D365 Commerce CSU (example &lt;a href=&quot;https://www.linkedin.com/pulse/commerce-csu-v95610046-january-2026-patrick-mouwen-ahdle?trackingId=UAu9Xbn3TXuTuLKn%2BFtg0Q%3D%3D&amp;lipi=urn%3Ali%3Apage%3Ad_flagship3_profile_view_base%3BnUwKjtnSRoCDdg6rmGG%2BJg%3D%3D&quot;&gt;link&lt;/a&gt;), you&amp;#39;ve probably found a link to my website which hosts the latest &lt;a href=&quot;/community-tools/&quot;&gt;OpenAPI documentation&lt;/a&gt; for the &lt;strong&gt;650 Commerce CSU APIs&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/language-trick-headless-commerce/1769191006194-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In a truly headless environment, you&amp;#39;d want some of these APIs to adapt content based on user language. For example, when a customer user clicks a language flag in a portal to change from English to German, you&amp;#39;d want the content to return product names or mode of delivery descriptions in German, right?&lt;/p&gt;
&lt;p&gt;If you look into the API request definitions, you&amp;#39;ll find &lt;em&gt;language&lt;/em&gt; related properties in &lt;em&gt;some&lt;/em&gt; of the APIs. But what the Microsoft documentation doesn&amp;#39;t tell you is that passing an &lt;strong&gt;Accept-Language&lt;/strong&gt; header actually steers the response content - That&amp;#39;s our hidden gem for today.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;What CSU does with Accept-Language&lt;/h3&gt;
&lt;p&gt;When you add the header, CSU will return certain translated values in that language (when translations exist and are synchronized to the channel DB).&lt;/p&gt;
&lt;p&gt;Example request with &lt;strong&gt;Accept-Language&lt;/strong&gt; header:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/language-trick-headless-commerce/1769201471095-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This header sets &lt;strong&gt;RequestContext.Language&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It reads the &lt;strong&gt;Accept-Language&lt;/strong&gt; header&lt;/li&gt;
&lt;li&gt;Takes the &lt;strong&gt;first&lt;/strong&gt; language entry&lt;/li&gt;
&lt;li&gt;If the header is missing or null, Commerce CSU sets RequestContext.Language as per the channel&amp;#39;s (online store&amp;#39;s) default language&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;Example 1: Country/region names translated in shipping APIs&lt;/h3&gt;
&lt;p&gt;If you maintain &lt;strong&gt;country/region translations&lt;/strong&gt; in D365 (Address setup &amp;gt; Country/region &amp;gt; Translations), CSU can return the translated short/long names when you pass Accept-Language.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;API example&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /Commerce/GetCountryRegionsForShipping&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Behavior&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With Accept-Language: the response returns country/region ShortName and LongName in German (if translations exist).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a clean way to avoid translation work in your frontend.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Example 2: Mode of delivery descriptions translated (with a gotcha)&lt;/h3&gt;
&lt;p&gt;Mode of delivery: you cannot translate the code, but you can translate the description. CSU applies those translations when Accept-Language is set.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Works for&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /Commerce/GetDeliveryOptions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /Commerce/Carts(&amp;#39;{Retail_CartId}&amp;#39;)/GetDeliveryOptions&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Does NOT work for&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /Commerce/OrgUnits/GetChannelDeliveryOptions&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Gotcha (important):&lt;/strong&gt; If you configure Mode of delivery translations in D365, define translations for &lt;strong&gt;all languages, including the default online store language&lt;/strong&gt;. Otherwise, when the Accept-Language header is missing and CSU will fall back to the default language (which is missing a translation), CSU will pick the “first available translation record” in an unexpected language.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Example 3: Product search and Accept-Language (subtle but useful)&lt;/h3&gt;
&lt;p&gt;This is where things get interesting. CSU product search isn’t “one engine”. Different endpoints behave differently with language:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Products/Search&lt;/code&gt; and &lt;code&gt;SearchByText&lt;/code&gt; do &lt;strong&gt;not&lt;/strong&gt; support searching in another language than the channel default.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SearchByCriteria&lt;/code&gt; can search in a non-default channel language if set in the request body. Note: this language needs to be listed under languages on the online store setup in D365 ERP to make this work.&lt;/li&gt;
&lt;li&gt;With Accept-Language on &lt;code&gt;SearchByCriteria&lt;/code&gt;, attribute/search condition evaluation runs against the online store&amp;#39;s default language &lt;em&gt;and&lt;/em&gt; the Accept-Language language (if different), while &lt;strong&gt;Product Name/Description are returned in the&lt;/strong&gt; Accept-Language language.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Concrete example&lt;/strong&gt; For a channel with default language en-us, using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /Commerce/Products/SearchByCriteria&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Accept-Language: de&lt;/li&gt;
&lt;li&gt;Search condition: &amp;quot;Brush&amp;quot; (default language) or &amp;quot;Bürste&amp;quot; (Accept-Language) — both work&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Result: both search conditions return the same product, with &lt;code&gt;Name&lt;/code&gt; and &lt;code&gt;Description&lt;/code&gt; in German — &amp;quot;Bürste-CB 4-reihig Kunststoffkopf 600&amp;quot;. Attribute values will also be translated into the Accept-Language (de) if translations exist.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/language-trick-headless-commerce/1769203083595-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Why I’m sharing this&lt;/h3&gt;
&lt;p&gt;Because this is the kind of thing that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;improves customer experience immediately,&lt;/li&gt;
&lt;li&gt;reduces frontend translation complexity,&lt;/li&gt;
&lt;li&gt;and is easy to miss if you only test with default channel language.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’re building headless Commerce on CSU, add Accept-Language to your test scripts and see where it changes your responses.&lt;/p&gt;
</content:encoded><category>Headless Commerce</category></item><item><title>Commerce CSU V9.56/10.0.46 - January 2026</title><link>https://patrickmouwen.com/blog/commerce-csu-v9-56-10-0-46/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/commerce-csu-v9-56-10-0-46/</guid><description>Unofficial release notes for Commerce CSU V9.56/10.0.46, January 2026 — asynchronous payments, external gift cards and connector extensibility.</description><pubDate>Fri, 16 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For anyone new in this field: &lt;strong&gt;D365 Commerce CSU&lt;/strong&gt; is shipped as part of D365 ERP. It comes with 650 APIs out of the box which enable the use of ERP and CRM data and business logic in B2C and B2B commerce.&lt;/p&gt;
&lt;p&gt;I have been using Commerce CSU for integration scenarios since its early days around 2015. I am sharing my knowledge to enable anyone to use Commerce CSU effectively for their B2C and B2B Commerce applications (e-commerce, POS, Customer Service etc.)&lt;/p&gt;
&lt;p&gt;In that context, I am publishing these unofficial D365 Commerce CSU Release Notes with any upcoming new Dynamics 365 ERP and Commerce platform Release.&lt;/p&gt;
&lt;h3&gt;A-Release Note Details&lt;/h3&gt;
&lt;p&gt;These release notes are applicable to the following CSU and D365 ERP version:&lt;/p&gt;
&lt;p&gt;This release (9.56 / 10.0.46) is a clear step toward more &lt;strong&gt;modern, resilient checkout and payment experiences&lt;/strong&gt;—especially for headless and eCommerce scenarios where payment completion doesn’t always happen instantly.&lt;/p&gt;
&lt;p&gt;The biggest shift is the platform maturing around &lt;strong&gt;asynchronous payments&lt;/strong&gt;: think Pay-by-Link, redirect-based flows, and webhook-driven confirmations. The data model now carries clearer indicators of what has been paid, what is still pending, and how payment state should be interpreted during checkout—making it easier to build reliable customer journeys even when the payment outcome arrives later.&lt;/p&gt;
&lt;p&gt;Alongside that, there’s a noticeable emphasis on &lt;strong&gt;operational robustness&lt;/strong&gt;. Cart processing gains stronger concurrency safeguards to reduce “double actions” and conflicting updates during payment-in-flight situations—exactly the kind of hardening that matters in high-volume retail and self-checkout patterns.&lt;/p&gt;
&lt;p&gt;There are also improvements aimed at &lt;strong&gt;traceability and reconciliation&lt;/strong&gt; in payment-adjacent flows, including richer reference data for third-party gift card scenarios, which helps with auditing, customer support, and recovery when external providers are involved.&lt;/p&gt;
&lt;p&gt;Finally, the release includes smaller but meaningful enhancements for &lt;strong&gt;store operations efficiency&lt;/strong&gt;, reducing friction in staff-related workflows and improving performance where bulk lookups are common.&lt;/p&gt;
&lt;p&gt;Overall: if you’re building or extending Commerce experiences beyond the standard storefront—especially headless—this version is worth attention because it strengthens the foundation for payment modernization, better observability, and fewer edge-case failures at checkout.&lt;/p&gt;
&lt;h3&gt;B-Downloads for your convenience&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Latest V9.56 CSU full interface specification in OpenAPI/Swagger format: &lt;a href=&quot;/resources/commerce/V9.56-API-Roles.xlsx&quot;&gt;Link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Lestest V9.56 Overview of required Commerce Roles for all nearly 800 APIs: &lt;a href=&quot;/resources/commerce/V9.56-API-Roles-V2.xlsx&quot;&gt;Link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;C-API and Schema Changes compared to the previous version 9.55/V10.0.45&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;C.1 New APIs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-56-10-0-46/1768555206813-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.2 Removed APIs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;None&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3 Data Model Changes&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;1) Asynchronous payments&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What changed:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cart and SalesOrder payloads gained &lt;strong&gt;async-payment-aware totals/flags&lt;/strong&gt;: AmountPaidWithAsynchronousPayments, IsRequiredAmountPaidInclAsynchronousPayments)&lt;/li&gt;
&lt;li&gt;AsynchronousPayments[] gained new &lt;strong&gt;tracking/typing fields&lt;/strong&gt; (AsynchronousPaymentStatusValue, ExtensibleAsynchronousPaymentTypeValue, ServiceAccountId) plus a &lt;strong&gt;default&lt;/strong&gt; change (AsynchronousPaymentTypeValue 1 → null).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Where it shows up:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;POST /Carts/CreateAsynchronousPayment&lt;/li&gt;
&lt;li&gt;GET /SalesOrders/GetSalesTransactionCheckoutResultByTransactionId&lt;/li&gt;
&lt;li&gt;Many Cart-returning operations now include the same fields&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Likely intent.&lt;/strong&gt; This is the API surface for &lt;strong&gt;asynchronous payment support for headless and eCommerce:&lt;/strong&gt; initiate an async payment (CreateAsynchronousPayment), handle notifications, and track checkout status to completion (GetSalesTransactionCheckoutResultByTransactionId). This is part of the pay-by-link / delayed completion scenarios and automatic cancellation if payment isn’t completed.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;2) External gift cards&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What changed:&lt;/strong&gt; Line-level ThirdPartyGiftCardInfo gained TransactionReferenceData and the change appears on CartLine shapes across many cart mutation/read APIs (and any sales-line/order-history shapes that include the same object).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Where it shows up:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;POST /Carts({id})/AddPreprocessedTenderLine&lt;/li&gt;
&lt;li&gt;POST/Carts({id})/UpdateCartLines&lt;/li&gt;
&lt;li&gt;Any Cart-returning operation that returns CartLines repeats the same block&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Likely intent:&lt;/strong&gt; supports &lt;strong&gt;external gift cards&lt;/strong&gt; (provider-integrated) alongside internal gift cards. A new TransactionReferenceData field fits the need to carry &lt;strong&gt;provider reference/trace/audit data&lt;/strong&gt; for reconciliation, customer support, reversals, retries, and “prove what happened” scenarios typical of third-party gift card flows.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;3) Payments connector extensibility&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What changed:&lt;/strong&gt; PaymentMerchantInformation gained ConnectorCustomSettings, repeated across endpoints that return Cart.MerchantProperties[] (again, many cart APIs).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Where it shows up:&lt;/strong&gt; Appears alongside other Cart schema changes in cart-returning endpoints, e.g.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;POST /Carts({id})/OverrideCartLinePrice&lt;/li&gt;
&lt;li&gt;POST/Carts({id})/OverrideCharge&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Likely intent:&lt;/strong&gt; A generic “custom settings” bag is a common pattern to expose &lt;strong&gt;connector-specific configuration&lt;/strong&gt; without forcing new first-class fields per PSP/provider.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.4 New flight keys&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Microsoft implements new CSU flight keys with every new CSU version. These undocumented flight keys steer specific CSU behavior. Here is a list of the latest keys for V9.56/V10.0.46&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-56-10-0-46/1768560082720-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Based on our analysis of the code, the flight keys appear to be used as follows:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-56-10-0-46/1768572217842-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-56-10-0-46/1768572246086-3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-56-10-0-46/1768572273744-4.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-56-10-0-46/1768572287360-5.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-56-10-0-46/1768572294516-6.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-56-10-0-46/1768572302139-7.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-56-10-0-46/1768572312283-8.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-56-10-0-46/1768572326389-9.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Disclaimer&lt;/h2&gt;
&lt;p&gt;The content of this article represents my independent technical analysis and personal interpretation of publicly available software artefacts. It is not endorsed by, affiliated with, or authorised by Microsoft Corporation. Nothing in this article constitutes official Microsoft documentation, guidance, or product commitments.&lt;/p&gt;
&lt;p&gt;All findings are derived from analysis of the software and public documentation. Feature descriptions, presumable use cases, and &amp;quot;likely intent&amp;quot; assessments reflect my professional opinion based on observable code and API changes — they may not reflect Microsoft&amp;#39;s actual design intent, planned behaviour, or final implementation.&lt;/p&gt;
&lt;p&gt;Information regarding features described as preview, private preview, or roadmap items is subject to change at Microsoft&amp;#39;s sole discretion and should not be relied upon for planning, purchasing, or architectural decisions. This article describes the product as at the date of publication above.&lt;/p&gt;
&lt;p&gt;This article is provided for informational and educational purposes only, on an &amp;quot;as-is&amp;quot; basis without warranties of any kind, express or implied. The author assumes no liability for any direct, indirect, incidental, or consequential damages arising from the use of or reliance on the information contained herein.&lt;/p&gt;
&lt;p&gt;For authoritative product information, consult Microsoft&amp;#39;s official documentation at &lt;a href=&quot;https://learn.microsoft.com&quot;&gt;learn.microsoft.com&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>Commerce CSU</category></item><item><title>How can we optimize performance of D365 APIs for use in headless environments?</title><link>https://patrickmouwen.com/blog/how-can-we-optimize-performance-d365-apis-use-headless/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/how-can-we-optimize-performance-d365-apis-use-headless/</guid><description>D365 F&amp;O and Dataverse APIs are often too slow or too unpredictable for real-time headless use. Where the time goes, and what to do about it.</description><pubDate>Thu, 08 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;D365 F&amp;amp;O APIs and Dataverse APIs are usually not a great fit for headless environments. Not because they &lt;em&gt;don’t work&lt;/em&gt; — but because their performance is often not stable or predictable enough for real-time use cases like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Webshops&lt;/li&gt;
&lt;li&gt;Customer service applications&lt;/li&gt;
&lt;li&gt;Custom frontends&lt;/li&gt;
&lt;li&gt;Mobile apps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In many scenarios, response times are simply too slow — or worse — inconsistent. Ironically, this affects not only custom-built apps, but also Microsoft’s own solutions that rely on these APIs, such as D365 e-commerce 🤔.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;“But Commerce APIs are designed for this… right?”&lt;/h3&gt;
&lt;p&gt;Yes — Commerce APIs are the exception.&lt;/p&gt;
&lt;p&gt;They are built for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;high-frequency calls&lt;/li&gt;
&lt;li&gt;carts, pricing, checkout&lt;/li&gt;
&lt;li&gt;POS and online scenarios&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But even Commerce APIs can suffer from a familiar problem: ⚠️ &lt;strong&gt;After a few minutes of inactivity, performance can suddenly drop — sometimes becoming 3× slower.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Welcome to the world of &lt;strong&gt;cold APIs&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;⚠️The real challenge: SaaS means limited control&lt;/h3&gt;
&lt;p&gt;Here’s the uncomfortable truth:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;D365 ERP, Dataverse, and Commerce are SaaS platforms&lt;/li&gt;
&lt;li&gt;We don’t control the infrastructure&lt;/li&gt;
&lt;li&gt;We can barely influence allocated resources&lt;/li&gt;
&lt;li&gt;We cannot “just tune the server”&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;And then there’s an even bigger issue…&lt;/h3&gt;
&lt;p&gt;Many APIs don’t just read data — they &lt;em&gt;do&lt;/em&gt; things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create orders&lt;/li&gt;
&lt;li&gt;Update addresses&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We don’t want to pollute the database just to keep an API warm.&lt;/p&gt;
&lt;p&gt;So the question becomes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;How do you keep D365 APIs warm even if they actually mutate data?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3&gt;🔑Suggested approach for D365 Finance &amp;amp; SCM (ERP)&lt;/h3&gt;
&lt;p&gt;❌ Avoid using D365 ERP APIs for headless scenarios whenever possible.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;Preferred alternatives:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use Commerce CSU APIs, or&lt;/li&gt;
&lt;li&gt;Use a custom data cache with a custom API layer that periodically synchronizes with the D365 ERP database &lt;em&gt;(conceptually, this is exactly what Commerce CSU already is — although it contains many APIs with complex business logic).&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;📊 &lt;strong&gt;Before go-live:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure sufficient telemetry and evidence is in place to properly scale a D365 ERP environment for integrations - This is a fundamental condition for API performance.&lt;/li&gt;
&lt;li&gt;To achieve this, it is strongly recommended to simulate real-life business processes in a Tier-4 / performance test environment&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;🚦 &lt;strong&gt;Prevent&lt;/strong&gt; throttling and rate-limit issues at all cost**:**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Carefully distribute data loads across different resources in advance&lt;/li&gt;
&lt;li&gt;Use tools such as Azure API Management (APIM) to shape and control traffic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;⚙️ If D365 ERP APIs are still required, and the baseline scaling prerequisites have been met by Microsoft, follow the strategy below to maximize API performance. OData APIs and Custom APIs, both require a different approach (see picture below):&lt;/p&gt;
&lt;p&gt;✅ For OData end points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable the OData metadata cache at AOS startup (introduced with PU32) to avoid cold starts to build metadata cache.&lt;/li&gt;
&lt;li&gt;Raise throttling priorities to ensure sufficient resource allocation.&lt;/li&gt;
&lt;li&gt;To keep GET requests warm at deeper levels (Data and Business Logic), leverage periodic requests. Common pitfall here is that a node may be warmed up which is not used for business critical API requests later, so optimize frequency of the &amp;quot;keep warm&amp;quot; requests to avoid this.&lt;/li&gt;
&lt;li&gt;To keep PATCH/POST requests warm at deeper levels (Data and Business Logic), create a dedicated WarmUp endpoint if data access and business logic routes are different than the GET operation for the respective Data Entity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ For Custom end points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To keep the caching level warm, Create a WarmUp endpoint to warm up the Service Group (JIT, metadata, caches).&lt;/li&gt;
&lt;li&gt;Raise throttling priorities to ensure sufficient resource allocation.&lt;/li&gt;
&lt;li&gt;If API performance is not sufficient yet, enhance the &amp;quot;WarmUp&amp;quot; endpoint by implementing code to trigger query paths and business logic which is triggered by the actual endpoint as well. Introduce roll back or other patterns to stay as close to the real paths without creating actual data.&lt;/li&gt;
&lt;li&gt;As mentioned before common pitfall with periodc &amp;quot;keep warm&amp;quot; requests is that a node may be warmed up which is not used for business critical API requests later, so optimize frequency of the &amp;quot;keep warm&amp;quot; requests to avoid this.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/how-can-we-optimize-performance-d365-apis-use-headless/1767910562042-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;🔑 Suggested approach for Dataverse: a very different story&lt;/h3&gt;
&lt;p&gt;Dataverse behaves fundamentally differently from D365 ERP:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;👉 Metadata is platform-wide cached&lt;/li&gt;
&lt;li&gt;👉 First calls are rarely significantly slower&lt;/li&gt;
&lt;li&gt;👉 Performance is often better, but also less predictable&lt;/li&gt;
&lt;li&gt;👉 Conceptually, there is no real difference between OData and “Custom APIs”&lt;/li&gt;
&lt;li&gt;👉 Stricter API limits apply&lt;/li&gt;
&lt;li&gt;👉 “Keep-warm” calls often hurt more than they help&lt;/li&gt;
&lt;li&gt;👉 No concept of service group warm-up like in ERP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;: More “SaaS” than D365 ERP, making performance stability harder to enforce and guarantee.&lt;/p&gt;
&lt;h3&gt;Recommended Dataverse strategy&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;1️⃣ Make plugins cold-start friendly&lt;/li&gt;
&lt;li&gt;2️⃣ Prefer asynchronous patterns&lt;/li&gt;
&lt;li&gt;3️⃣ If performance stability is critical:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👉 Introduce a custom staging database (e.g. Cosmos DB) + Expose via a custom API layer on top&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;🔑 Suggested approach for Commerce CSU&lt;/h3&gt;
&lt;p&gt;Commerce APIs are already optimized for headless usage — but tuning may still be required.&lt;/p&gt;
&lt;h3&gt;Best practices&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Scale out with multiple scale units for large implementations &lt;em&gt;(cost increase is often surprisingly modest: ~12–30%)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Keep Commerce data lean and efficient: avoid the use of catalogs, deeply nested large category structures and unnecessary assortment sizes.&lt;/li&gt;
&lt;li&gt;Prefer IV (Inventory Visibility) over channel-side inventory sync, especially in case of large stock files.&lt;/li&gt;
&lt;li&gt;Reduce synchronous RTS usage via parameterization (use channel db to HQ synch patterns instead)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Warming strategies&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Slow GETs → one periodic &amp;quot;keep warm&amp;quot; request every ~10 minutes is often enough&lt;/li&gt;
&lt;li&gt;Many nodes? Similar issue as we saw with D365 ERP → Increase frequency to 2–5 minutes&lt;/li&gt;
&lt;li&gt;Slow POSTs? 👉 Last resort: custom warm-up endpoints that touch deeper CRT and data layers used by the real operation&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;🔑 Your low-code helper: the “keep-warm” Logic App&lt;/h3&gt;
&lt;p&gt;If the performance of your D365 ERP and Commerce APIs can be sufficiently improved by keeping the API warm through periodically triggering an endpoint—either directly or indirectly via a “WarmUp” endpoint—it can be very useful to implement this using a Logic App.&lt;/p&gt;
&lt;p&gt;First, because it is an easy-to-maintain and easy-to-understand low-code solution, and second, because it is simple to configure:&lt;/p&gt;
&lt;p&gt;1️⃣ Recurrence can be configured directly in the Logic App&lt;/p&gt;
&lt;p&gt;2️⃣ If the Logic App interacts with endpoints that are abstracted through Azure API Management, you can avoid using service connections altogether — making the Logic App easy to deploy and move between environments&lt;/p&gt;
&lt;p&gt;3️⃣ Sample payloads can be maintained externally, for example in files or storage accounts, and reused by the Logic App &lt;em&gt;(effectively decoupling data from logic)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Below is an example of such a Logic App:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/how-can-we-optimize-performance-d365-apis-use-headless/1767912462584-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Final thought — and an open question&lt;/h3&gt;
&lt;p&gt;I’m convinced many people in the D365 community have &lt;strong&gt;great ideas and best practices&lt;/strong&gt; around this topic.&lt;/p&gt;
&lt;p&gt;👉 &lt;strong&gt;How do you handle API performance in headless scenarios?&lt;/strong&gt; 👉 &lt;strong&gt;What patterns have worked — or failed — for you?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let’s share experiences.&lt;/p&gt;
</content:encoded><category>Headless Commerce</category></item><item><title>Is there an API-first alternative for Dual Write?</title><link>https://patrickmouwen.com/blog/is-there-an-api-first-alternative-for-dual-write/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/is-there-an-api-first-alternative-for-dual-write/</guid><description>Does quote-to-order really need Dual Write, or can an API-first pattern answer the same question without synchronising data between D365 apps?</description><pubDate>Thu, 08 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is a question which has been bugging me for the last three years.&lt;/p&gt;
&lt;p&gt;Every time I read a Microsoft Learn article article about &lt;strong&gt;D365 SCM&lt;/strong&gt; or &lt;strong&gt;D365 CE&lt;/strong&gt; being the &lt;em&gt;price master&lt;/em&gt; (&lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/fin-ops/data-entities/pricing-engine&quot;&gt;example&lt;/a&gt;), I catch myself thinking halfway:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Really? Isn’t there an easier way?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here’s what we’re doing today:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;1️⃣ The process (e.g. quote-to-order) runs in &lt;strong&gt;system A – D365 CE&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;2️⃣ System A asks &lt;strong&gt;system B – D365 SCM&lt;/strong&gt; to recalculate pricing&lt;/li&gt;
&lt;li&gt;3️⃣ The recalculation happens in B&lt;/li&gt;
&lt;li&gt;4️⃣ System B syncs the data back to A&lt;/li&gt;
&lt;li&gt;5️⃣ The process continues… hopefully&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But what if something fails halfway?&lt;/p&gt;
&lt;p&gt;⚠️ What if the recalculation (step 3) throws an error?&lt;/p&gt;
&lt;p&gt;⚠️ Or the data sync (step 4) doesn’t bring back &lt;em&gt;all&lt;/em&gt; price components — discounts, attribute pricing, shipping charges, minimum-order fees, overrides?&lt;/p&gt;
&lt;p&gt;Couldn’t we do this faster, cleaner, and more reliably?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760985941415.png&quot; alt=&quot;Article content&quot;&gt;&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;My suggestion:&lt;/strong&gt; &lt;em&gt;API-first&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Let CE call SCM’s pricing engine directly in real time — no sync, no waiting, no partial data. You get a single, complete response containing every price component. Instant feedback, fewer moving parts, and a process that never pauses “mid-flow.”. But that’s theory? Can it work in reality?&lt;/p&gt;
&lt;h2&gt;An API-First Approach&lt;/h2&gt;
&lt;p&gt;Let’s explore the approach: there’s &lt;strong&gt;no data sync&lt;/strong&gt; between &lt;strong&gt;D365 CE&lt;/strong&gt; and &lt;strong&gt;D365 ERP&lt;/strong&gt;. Instead, &lt;strong&gt;quote or order lines&lt;/strong&gt; in CE are sent to an &lt;strong&gt;API endpoint&lt;/strong&gt; that returns a &lt;strong&gt;detailed pricing breakdown&lt;/strong&gt; — typically within &lt;strong&gt;500–750 ms&lt;/strong&gt; ⚡.&lt;/p&gt;
&lt;p&gt;CE can trigger this in multiple ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;as an &lt;strong&gt;in-process (background)&lt;/strong&gt; flow, automatically invoked when a quote line is added, updated, or deleted,&lt;/li&gt;
&lt;li&gt;or more explicitly via a &lt;strong&gt;JavaScript-enabled “Recalculate Pricing” button&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But the real question is… 👉 &lt;strong&gt;What’s behind that API endpoint?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760988646606.png&quot;&gt;&lt;img src=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760988646606.png&quot; alt=&quot;Article content&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D365 SCM OData and custom APIs&lt;/strong&gt; aren’t known for stable, high-volume performance. They work fine for batch integrations, but for &lt;strong&gt;consistent real-time request/response patterns&lt;/strong&gt;, they often fall short. There are many reasons — complex data models, non-optimized joins, limited caching — but the bottom line is: ⚠️ it’s very hard to make them truly performant consistently, especially under high volume.&lt;/p&gt;
&lt;p&gt;By contrast, the &lt;strong&gt;D365 Commerce APIs&lt;/strong&gt; are &lt;strong&gt;built for speed and consistency&lt;/strong&gt;. They’re optimized for high-frequency scenarios like online cart operations and POS transactions, where performance must be predictable.&lt;/p&gt;
&lt;p&gt;Even better: the &lt;strong&gt;Commerce Cart APIs&lt;/strong&gt; support both the &lt;strong&gt;existing SCM pricing engine&lt;/strong&gt; &lt;em&gt;and&lt;/em&gt; the &lt;strong&gt;new Unified Pricing&lt;/strong&gt; model — built on the same Commerce pricing foundation, now enhanced with &lt;strong&gt;attribute-based pricing&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;SCM and Unified Pricing API for Quote to Order&lt;/h3&gt;
&lt;p&gt;So, to explore the options, I decided to develop a &lt;strong&gt;single API endpoint&lt;/strong&gt;, implemented via an &lt;strong&gt;Azure Logic App&lt;/strong&gt;, which &lt;strong&gt;wraps several existing D365 Commerce APIs&lt;/strong&gt; into one cohesive call.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create Cart&lt;/li&gt;
&lt;li&gt;Add Cart Line&lt;/li&gt;
&lt;li&gt;&lt;Placeholder for adding shipping address and mode of delivery in the future&gt;&lt;/li&gt;
&lt;li&gt;Delete Cart&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760989223140.png&quot;&gt;&lt;img src=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760989223140.png&quot; alt=&quot;Article content&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The API requires a very simple request body:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760989605566.png&quot; alt=&quot;Article content&quot;&gt;&lt;/p&gt;
&lt;p&gt;But it returns full pricing, including gross pricing, net pricing, shipping charges, minimum order fee, taxes, customers discounts, attribute based discounts etc. – Just a snippet:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760989549208.png&quot;&gt;&lt;img src=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760989549208.png&quot; alt=&quot;Article content&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;No data sync. No duplication of logic. Just a &lt;strong&gt;question&lt;/strong&gt; and a &lt;strong&gt;fast, detailed answer&lt;/strong&gt; — so the Quote-to-Order process can simply continue. ✅ No process breaks. ✅ No endless loading spinners.&lt;/p&gt;
&lt;p&gt;But wait… doesn’t &lt;strong&gt;Commerce&lt;/strong&gt; require a &lt;strong&gt;Channel&lt;/strong&gt; and an &lt;strong&gt;OUN (Operating Unit Number)&lt;/strong&gt; to function? Can it really work with just a &lt;strong&gt;customer&lt;/strong&gt; and &lt;strong&gt;quote lines&lt;/strong&gt; as input? 🤔&lt;/p&gt;
&lt;h3&gt;How to “hide” the Commerce channel concept for Dataverse&lt;/h3&gt;
&lt;p&gt;By implementing a very simple &lt;strong&gt;Default&lt;/strong&gt; flag on the channel in the &lt;strong&gt;Customer hierarchy&lt;/strong&gt; form in D365 SCM, we can relate a B2B customer to 1 default channel in D365 SCM:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760989962231.png&quot;&gt;&lt;img src=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760989962231.png&quot; alt=&quot;Article content&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We can then accept the B2B customer as header parameter in the request from Dataverse, as opposed to the OUN (=Commerce channel):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760990055322.png&quot; alt=&quot;Article content&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Benefits&lt;/h3&gt;
&lt;p&gt;In my view, this &lt;strong&gt;API-first approach&lt;/strong&gt; offers &lt;strong&gt;significant advantages over Dual Write&lt;/strong&gt;, especially for the &lt;em&gt;“Better Together”&lt;/em&gt; stories between &lt;strong&gt;D365 Dataverse&lt;/strong&gt; (CE, Sales, Field Service, IOM, etc.) and &lt;strong&gt;D365 SCM&lt;/strong&gt; — where large data volumes and complex business logic come into play.&lt;/p&gt;
&lt;p&gt;If you count how many &lt;strong&gt;data entities&lt;/strong&gt; need to sync through Dual Write just to make &lt;strong&gt;advanced pricing details&lt;/strong&gt; flow between the two ecosystems… you’d quickly see how fragile and maintenance-heavy that becomes.&lt;/p&gt;
&lt;p&gt;To make it concrete, the table below summarizes the &lt;strong&gt;most relevant benefits of API-first vs. Dual Write&lt;/strong&gt; for this scenario 👇&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760990821351.png&quot;&gt;&lt;img src=&quot;/images/blog/is-there-an-api-first-alternative-for-dual-write/1760990821351.png&quot; alt=&quot;Article content&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Further optimization&lt;/h3&gt;
&lt;p&gt;The Logic App which I pragmatically built for my prototype is a so called &lt;em&gt;Composite API&lt;/em&gt;: it wraps multiple standard Commerce APIs into 1 endpoint. There are platforms which do this wrapping more efficiently at run time than a Logic App. An example is &lt;a href=&quot;https://fastapi.tiangolo.com/&quot;&gt;FastAPI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another optimization would be to implement api-key authorization between Dataverse and D365 SCM. The ideal platform for this is &lt;a href=&quot;https://azure.microsoft.com/en-us/products/api-management&quot;&gt;Azure API Management&lt;/a&gt;. APIM can abstract Commerce CSU App or Customer based authorization and work securely with api-key towards Dataverse for simplification (which is easier to implement between the systems).&lt;/p&gt;
&lt;p&gt;If you’re interested in this &lt;strong&gt;API-first&lt;/strong&gt; approach, feel free to get in touch via &lt;a href=&quot;/contact&quot;&gt;patrickmouwen.com/contact&lt;/a&gt;. I specialise in API-driven integration between D365 SCM, Dataverse, Commerce and third-party systems.&lt;/p&gt;
</content:encoded><category>Functional</category></item><item><title>Commerce CSU V9.55/10.0.45 - September 2025</title><link>https://patrickmouwen.com/blog/commerce-csu-v9-55-10-0-45/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/commerce-csu-v9-55-10-0-45/</guid><description>Unofficial release notes for Commerce CSU V9.55/10.0.45, September 2025 — refund permissions, payment notifications and Azure Maps at channel level.</description><pubDate>Wed, 17 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For anyone new in this field: &lt;strong&gt;D365 Commerce CSU&lt;/strong&gt; is shipped as part of D365 ERP. It comes with 650 APIs out of the box which enables the use of ERP and CRM data and business logic in B2C and B2B commerce.&lt;/p&gt;
&lt;p&gt;I have been using Commerce CSU for integration scenarios since its early days around 2015. I am sharing my knowledge to enable anyone to use Commerce CSU effectively for their B2C and B2B Commerce applications (e-commerce, POS, Customer Service etc.)&lt;/p&gt;
&lt;p&gt;In that context, I am publishing these unofficial D365 Commerce CSU Release Notes with any upcoming new Dynamics 365 ERP and Commerce platform Release.&lt;/p&gt;
&lt;h3&gt;A-Release Note Details&lt;/h3&gt;
&lt;p&gt;These release notes are applicable to the following CSU and D365 ERP version:&lt;/p&gt;
&lt;p&gt;This new version (&lt;strong&gt;9.55.25240.5 / 10.0.45&lt;/strong&gt;) doubles down on &lt;strong&gt;payments and checkout hardening&lt;/strong&gt;— Changes pivot around five themes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;External/third-party gift cards after payment:&lt;/strong&gt; new line-level fields on (e.g., approval and tender type) show up across &lt;strong&gt;/Carts&lt;/strong&gt;, &lt;strong&gt;/SalesOrders&lt;/strong&gt;, and related reads—enabling the “issue/fund only after payment succeeds” design that’s critical for SCO and fraud control.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Guest checkout control via API:&lt;/strong&gt; &lt;strong&gt;/Carts/GetConfiguration&lt;/strong&gt; now reflects the &lt;strong&gt;Allow anonymous checkout&lt;/strong&gt; switch, aligning headless flows with your Online Functionality Profile.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Payment notification clarity:&lt;/strong&gt; &lt;strong&gt;/PaymentNotifications&lt;/strong&gt; surfaces a normalized processing status, making webhook-driven flows (including &lt;strong&gt;Pay by link&lt;/strong&gt;) easier to reconcile and automate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Refund usability:&lt;/strong&gt; expanded &lt;strong&gt;EmployeePermissions&lt;/strong&gt; support showing all refund methods (when policy allows), reducing manager overrides in return flows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Maps at channel level:&lt;/strong&gt; &lt;strong&gt;/OrgUnits/GetOrgUnitConfiguration&lt;/strong&gt; adds flags/keys so Store Locator, address suggest, and POS scenarios can move off Bing Maps (discontinued) cleanly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-55-10-0-45/1758120924133-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pay by link:&lt;/strong&gt; if you’re using the out-of-box &lt;strong&gt;Adyen&lt;/strong&gt; connector, these API updates complement that journey: notifications carry clearer status for Dataverse-backed processing, checkout settings are enforced consistently across headless vs. storefront, and post-payment gift-card issuance avoids value creation before funds clear.&lt;/p&gt;
&lt;h3&gt;B-Downloads for your convenience&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Latest V9.55 CSU full interface specification in OpenAPI/Swagger format: &lt;a href=&quot;/tools/9.55.25240.5.json&quot;&gt;Link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Lestest V9.55 Overview of required Commerce Roles for all nearly 800 APIs: &lt;a href=&quot;/resources/commerce/V9.55-API-Roles.xlsx&quot;&gt;Link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;C-API and Schema Changes compared to the previous version 9.54/V10.0.44&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;C.1 New APIs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;None&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.2 Removed APIs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;None&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3 Data Model Changes&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;1) External gift cards: new flags on line-level ThirdPartyGiftCardInfo&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What changed (multiple APIs):&lt;/strong&gt; gained and in cart/sales-line schemas. &lt;strong&gt;Likely intent:&lt;/strong&gt; enable the “fund gift cards &lt;em&gt;after&lt;/em&gt; payment is completed” design and surface the card’s tender type + approval state through the API (important for POS/SCO flows and fraud/risk controls).&lt;/p&gt;
&lt;h2&gt;2) Guest checkout hardening: CartConfiguration.AllowAnonymousCheckout&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What changed:&lt;/strong&gt; adds (returned by ). &lt;strong&gt;Likely intent:&lt;/strong&gt; close the loophole where &lt;strong&gt;guest checkout could be invoked via APIs&lt;/strong&gt; even if the storefront didn’t show it—making the API honor the Online Functionality Profile setting.&lt;/p&gt;
&lt;h2&gt;3) Refund policy usability: EmployeePermissions.AllowAllRefundPaymMethods&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What changed:&lt;/strong&gt; adds across &lt;strong&gt;Employees&lt;/strong&gt; endpoints (, , and ). &lt;strong&gt;Likely intent:&lt;/strong&gt; if a channel return policy hides certain payment methods and “Manager override” is on, &lt;strong&gt;authorized non-managers&lt;/strong&gt; can still “Show all refund options” and finish the return—removing the manager dependency. This landed with &lt;strong&gt;10.0.44&lt;/strong&gt; but is now reflected in the API surface.&lt;/p&gt;
&lt;h2&gt;4) Payment notifications: ProcessingStatusValue&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What changed:&lt;/strong&gt; adds to the entity and query shapes; / enums extended to include it; CRUD and updated accordingly. &lt;strong&gt;Likely intent:&lt;/strong&gt; expose a &lt;strong&gt;normalized processing status&lt;/strong&gt; on payment notifications for sorting/filtering and operational reconciliation (e.g., async gateway callbacks or retries).&lt;/p&gt;
&lt;h2&gt;5) Azure Maps enablement at channel level: ChannelConfiguration.AzureMapsEnabled/AzureMapsApiKey&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What changed:&lt;/strong&gt; extends with and . &lt;strong&gt;Likely intent:&lt;/strong&gt; support Bing Maps retirement by allowing &lt;strong&gt;Azure Maps&lt;/strong&gt; for Store Locator, BOPIS, address autosuggest, etc., and for POS scenarios.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.4 New flight keys&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Microsoft implements new CSU flight keys with every new CSU version. These undocumented flight keys steer specific CSU behavior. Here is a list of the latest keys for V9.55/V10.0.45.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-55-10-0-45/1758120174111-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Based on our analysis of the code, the flight keys appear to be used as follows:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-55-10-0-45/1758120262167-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-55-10-0-45/1758120279269-3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-55-10-0-45/1758120323336-4.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-55-10-0-45/1758120297215-5.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-55-10-0-45/1758120327615-6.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Disclaimer&lt;/h2&gt;
&lt;p&gt;The content of this article represents my independent technical analysis and personal interpretation of publicly available software artefacts. It is not endorsed by, affiliated with, or authorised by Microsoft Corporation. Nothing in this article constitutes official Microsoft documentation, guidance, or product commitments.&lt;/p&gt;
&lt;p&gt;All findings are derived from analysis of the software and public documentation. Feature descriptions, presumable use cases, and &amp;quot;likely intent&amp;quot; assessments reflect my professional opinion based on observable code and API changes — they may not reflect Microsoft&amp;#39;s actual design intent, planned behaviour, or final implementation.&lt;/p&gt;
&lt;p&gt;Information regarding features described as preview, private preview, or roadmap items is subject to change at Microsoft&amp;#39;s sole discretion and should not be relied upon for planning, purchasing, or architectural decisions. This article describes the product as at the date of publication above.&lt;/p&gt;
&lt;p&gt;This article is provided for informational and educational purposes only, on an &amp;quot;as-is&amp;quot; basis without warranties of any kind, express or implied. The author assumes no liability for any direct, indirect, incidental, or consequential damages arising from the use of or reliance on the information contained herein.&lt;/p&gt;
&lt;p&gt;For authoritative product information, consult Microsoft&amp;#39;s official documentation at &lt;a href=&quot;https://learn.microsoft.com&quot;&gt;learn.microsoft.com&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>Commerce CSU</category></item><item><title>🧩 Unlocking True Headless B2B Commerce with D365 — Without Customizing the Core</title><link>https://patrickmouwen.com/blog/unlocking-true-headless-b2b-commerce-d365-creative-without/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/unlocking-true-headless-b2b-commerce-d365-creative-without/</guid><description>The D365 Commerce data model is rooted in individual customer accounts. How to support multi-organisation B2B journeys without customising the core.</description><pubDate>Fri, 27 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Dynamics 365 Commerce&lt;/strong&gt; has matured into a strong platform for both B2C and B2B scenarios. Yet for organizations aiming to build a &lt;strong&gt;headless B2B strategy&lt;/strong&gt;, there’s a fundamental limitation: the data model is rooted in individual customer accounts. For modern B2B journeys involving multiple organizations and users, this creates real challenges.&lt;/p&gt;
&lt;p&gt;At &lt;strong&gt;365Connect&lt;/strong&gt;, we’ve faced this first-hand. Instead of fighting against the platform, we developed an approach that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⚡ Works &lt;strong&gt;without core customizations&lt;/strong&gt; to D365 Commerce&lt;/li&gt;
&lt;li&gt;📦 Keeps the &lt;strong&gt;standard Commerce APIs&lt;/strong&gt; fully intact&lt;/li&gt;
&lt;li&gt;🌍 Enables &lt;strong&gt;modern B2B use cases&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;🚧 The Core Challenge: Identity vs. Organization&lt;/h3&gt;
&lt;p&gt;In the out-of-the-box D365 Commerce model, every user is tied to an individual customer account. Transactions are recorded on that account, with the B2B customer only referenced as an &lt;em&gt;invoice account&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Collaboration within the same B2B organization is difficult&lt;/li&gt;
&lt;li&gt;Transacting on behalf of different legal entities is complex&lt;/li&gt;
&lt;li&gt;Headless orchestration between frontends and ERP is limited&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;💡 Our Approach&lt;/h3&gt;
&lt;p&gt;The current &lt;strong&gt;person customer/B2B customer data model&lt;/strong&gt; is a challenge here. I&amp;#39;ve seen heavy customizations in the market to change the model to contact- and B2B organisation-based which hits the core foundation of the Customer context in D365 CSU.&lt;/p&gt;
&lt;p&gt;We decided to leverage a creative solution which does &lt;em&gt;not impact core CSU functionality&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The solution capitalizes on having 1 enterprise identity account (=person customer) per B2B organization which is shared across the identities (=B2B users). This 1:N association is realized in the standard &lt;strong&gt;RetailExternalIdentityToCustomerMap&lt;/strong&gt; table.&lt;/p&gt;
&lt;p&gt;By developing a custom CSU endpoint (&lt;strong&gt;/Commerce/TSFCActivateOrganization&lt;/strong&gt;) working against the &lt;strong&gt;RetailExternalIdentityToCustomerMap&lt;/strong&gt;, the online shop frontend is in control to bind a logged-in user (identity) to another organization from the online shop&amp;#39;s front end. This is truly headless and &lt;strong&gt;unlocks true Order on behalf for B2B organizations&lt;/strong&gt; where 1 buyer can now work on behalf of multiple organizations (like subsidiaries of the same organization).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/unlocking-true-headless-b2b-commerce-d365-creative-without/1760620886491-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;One difficult hurdle we faced here was the fact that the customer context is cached for 5 minutes (hard coded in an area which cannot be extended). So, even though the logged-in user had switched to a different organization, the customer context still continued to use the original context for 5 minutes. We resolved this by implementing a request handler for the &lt;strong&gt;GetCommerceIdentityByExternalIdentityServiceRequest&lt;/strong&gt; and override it with our own custom caching.&lt;/p&gt;
&lt;p&gt;Upon standard sales transaction to order conversion in D365 ERP, the person customer account is swapped by the actual B2B account (by look up via the Customer Hierarchy) before the order is created.&lt;/p&gt;
&lt;p&gt;This end-to-end works very well and covers &lt;em&gt;all&lt;/em&gt; beforementioned B2B requirements without hitting any core CSU code. As such, this solution component, together with a few other tweaks, is a &lt;strong&gt;game changer&lt;/strong&gt; &lt;strong&gt;for using D365 Commerce CSU in the B2B market.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;✔ Zero custom code in the core ✔ ERP receives clean and correct customer assignments ✔ Headless architecture stays lean and flexible ✔ Works with Microsoft D365 frontends as well as third-party apps&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;🎯 Why This Matters for B2B Commerce Leaders&lt;/h3&gt;
&lt;p&gt;As more enterprises embrace &lt;strong&gt;composable commerce&lt;/strong&gt; and &lt;strong&gt;API-first architectures&lt;/strong&gt;, the last thing they want is heavy customization in their core systems.&lt;/p&gt;
&lt;p&gt;With our approach, B2B leaders can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;👥 Empower employees to place orders on behalf of multiple organizations&lt;/li&gt;
&lt;li&gt;🛒 Enable collaboration through shared carts&lt;/li&gt;
&lt;li&gt;🔗 Support dealers and partners in B2B2B models&lt;/li&gt;
&lt;li&gt;📈 Accelerate innovation while keeping upgrade paths safe&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;🤝 An Open Invitation to Microsoft&lt;/h3&gt;
&lt;p&gt;We see Microsoft investing heavily in headless, composable, and AI-driven Commerce. Our solution shows that even foundational gaps can be addressed — by understanding the platform deeply and applying it creatively rather than customizing it.&lt;/p&gt;
&lt;p&gt;We invite Microsoft and partners to join us in scaling this approach, and making D365 Commerce the most adaptable platform for headless B2B commerce in the market.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;🧭 Let’s Talk&lt;/h3&gt;
&lt;p&gt;Are you a &lt;strong&gt;B2B commerce leader&lt;/strong&gt;, &lt;strong&gt;Microsoft architect&lt;/strong&gt;, or &lt;strong&gt;ISV&lt;/strong&gt; struggling with these challenges?&lt;/p&gt;
&lt;p&gt;🔗 Get in touch via &lt;a href=&quot;/contact&quot;&gt;patrickmouwen.com/contact&lt;/a&gt;. Happy to help you unlock the full potential of headless B2B Commerce with D365 — without unnecessary complexity.&lt;/p&gt;
</content:encoded><category>Headless Commerce</category></item><item><title>Commerce CSU V9.54/10.0.44 - June 2025</title><link>https://patrickmouwen.com/blog/commerce-csu-v9-54-10-0-44/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/commerce-csu-v9-54-10-0-44/</guid><description>Unofficial release notes for Commerce CSU V9.54/10.0.44, June 2025 — API and schema changes, plus the flight keys steering CSU behaviour.</description><pubDate>Thu, 26 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For anyone new in this field: &lt;strong&gt;D365 Commerce CSU&lt;/strong&gt; is shipped as part of D365 ERP and comes with 650 APIs out of the box for use in B2C and B2B commerce.&lt;/p&gt;
&lt;p&gt;I have been using Commerce CSU for integration scenarios since its early days around 2015. I am sharing my knowledge to enable anyone to use Commerce CSU effectively for their B2C and B2B Commerce integration scenarios (e-commerce, POS, Customer Service etc.)&lt;/p&gt;
&lt;p&gt;In that context, I am publishing these unofficial D365 Commerce CSU Release Notes with any upcoming new Dynamics 365 ERP and Commerce platform Release.&lt;/p&gt;
&lt;h3&gt;A-Release Note Details&lt;/h3&gt;
&lt;p&gt;These release notes are applicable to the following CSU and D365 ERP versions:&lt;/p&gt;
&lt;p&gt;This CSU API release seems to focus on the latest &lt;em&gt;Pay by link&lt;/em&gt; feature, which is availablefor the out-of-box Adyen payment connector. See more details &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/pay-by-link-overview&quot;&gt;here on Microsoft learn&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-54-10-0-44/1750954956682-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The Pay by link feature is based on the following components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Payment notification service which is triggered from an Adyen webhook, sent to a Dataverse endpoint&lt;/li&gt;
&lt;li&gt;The Dataverse endpoint is set up in the Commerce shared parameters&lt;/li&gt;
&lt;li&gt;Features &amp;quot;Payment notifications&amp;quot;, &amp;quot;Pay by link payment&amp;quot;, &amp;quot;Enhanced wallet support&amp;quot; and &amp;quot;Payment improvements&amp;quot; to be enabled in D365 ERP&lt;/li&gt;
&lt;li&gt;APIs which handle Payment notifications and Payment link&lt;/li&gt;
&lt;li&gt;Pay by link button in the POS&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;B-Downloads for your convenience&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Latest V9.54 CSU full interface specification in OpenAPI/Swagger format: &lt;a href=&quot;/community-tools/&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lestest V9.54 Overview of required Commerce Roles for all nearly 800 APIs: &lt;a href=&quot;/resources/commerce/V9.54-API-Roles.xlsx&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;C-API and Schema Changes compared to the previous version 9.53/V10.0.43&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;C.1 New APIs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Related to Payment notifications:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-54-10-0-44/1750953805363-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;For creating and maintaining a payment link:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-54-10-0-44/1750953894194-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-54-10-0-44/1750953921137-3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-54-10-0-44/1750953965021-4.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-54-10-0-44/1750954006340-5.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.2 Removed APIs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;None&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3 Data Model Changes&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New property &lt;strong&gt;AsynchronousPayments&lt;/strong&gt; on API requests and responses which work against Carts and SalesOrders&lt;/li&gt;
&lt;li&gt;New property &lt;strong&gt;LoyaltyGroup]/LoyaltyProgramNextTierStatus&lt;/strong&gt; on POST /Commerce/GetCustomerLoyaltyCards, /Commerce/ScanResults APIs and POST /Commerce/GetLoyaltyCard&lt;/li&gt;
&lt;li&gt;New property &lt;strong&gt;IsUnifiedPaymentExperienceDisabled&lt;/strong&gt; on GET /Commerce/GetDeviceConfiguration()&lt;/li&gt;
&lt;li&gt;New property &lt;strong&gt;CardInteractionConfigurations&lt;/strong&gt; on GET /Commerce/GetTenderTypes()&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;C.4 New flight keys&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Microsoft implements new CSU flight keys with every new CSU version. These undocumented flight keys steer specific CSU behavior. Here is a list of the latest keys:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-54-10-0-44/1750955497148-6.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Disclaimer&lt;/h2&gt;
&lt;p&gt;The content of this article represents my independent technical analysis and personal interpretation of publicly available software artefacts. It is not endorsed by, affiliated with, or authorised by Microsoft Corporation. Nothing in this article constitutes official Microsoft documentation, guidance, or product commitments.&lt;/p&gt;
&lt;p&gt;All findings are derived from analysis of the software and public documentation. Feature descriptions, presumable use cases, and &amp;quot;likely intent&amp;quot; assessments reflect my professional opinion based on observable code and API changes — they may not reflect Microsoft&amp;#39;s actual design intent, planned behaviour, or final implementation.&lt;/p&gt;
&lt;p&gt;Information regarding features described as preview, private preview, or roadmap items is subject to change at Microsoft&amp;#39;s sole discretion and should not be relied upon for planning, purchasing, or architectural decisions. This article describes the product as at the date of publication above.&lt;/p&gt;
&lt;p&gt;This article is provided for informational and educational purposes only, on an &amp;quot;as-is&amp;quot; basis without warranties of any kind, express or implied. The author assumes no liability for any direct, indirect, incidental, or consequential damages arising from the use of or reliance on the information contained herein.&lt;/p&gt;
&lt;p&gt;For authoritative product information, consult Microsoft&amp;#39;s official documentation at &lt;a href=&quot;https://learn.microsoft.com&quot;&gt;learn.microsoft.com&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>Commerce CSU</category></item><item><title>Commerce CSU V9.53/10.0.43 - March 2025</title><link>https://patrickmouwen.com/blog/commerce-csu-v9-53-10-0-43/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/commerce-csu-v9-53-10-0-43/</guid><description>Unofficial release notes for Commerce CSU V9.53/10.0.43, March 2025 — the API and schema changes that matter for e-commerce integration.</description><pubDate>Thu, 20 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For anyone new in this field: &lt;strong&gt;Commerce CSU&lt;/strong&gt; is shipped as part of D365 ERP and can seamlessly &lt;a href=&quot;https://www.linkedin.com/pulse/case-1-d365-erp-cannot-backend-your-headless-solution-patrick-mouwen-yjjse/&quot;&gt;integrate&lt;/a&gt; any Professional App, Social commerce, e-commerce or POS solution with D365 ERP.&lt;/p&gt;
&lt;p&gt;I have been using Commerce CSU for integration scenarios since its early days around 2015. My mission is to empower anyone to use Commerce CSU effectively for their integration scenarios. Therefore, I will publish these unofficial CSU Release Notes with any upcoming new Dynamics 365 ERP and Commerce platform Release.&lt;/p&gt;
&lt;h3&gt;A-Release Note Details&lt;/h3&gt;
&lt;p&gt;These These release notes apply to the following CSU and D365 ERP version:&lt;/p&gt;
&lt;h3&gt;B-Downloads for your convenience&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Latest V9.53 CSU full interface specification in OpenAPI/Swagger format: &lt;a href=&quot;/community-tools/&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lestest V9.53 Overview of required Commerce Roles for all nearly 800 APIs: &lt;a href=&quot;/resources/commerce/V9.53-API-Roles.xlsx&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;C-For the Techies: API and Model Changes compared to the previous version 9.52/V10.0.42&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;C.1 New APIs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There&amp;#39;s one in the works, but not fully implemented yet:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-53-10-0-43/1742500798670-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This API seems to control a stored procedure to ensure post-processing for specific tables after the CDX synch between HQ and CSU DB has run.&lt;/p&gt;
&lt;p&gt;For example, if tables like ECORESPRODUCTCATEGORY or RETAILPRODUCTATTRIBUTESLOOKUP are affected by the data synch between HQ and CSU database, then return policies are updated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.2 Removed APIs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;None&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3 Data Model Changes&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Property &lt;strong&gt;AllowedMinimumDaysForRequestDelivery&lt;/strong&gt; is added to Microsoft.Dynamics.Commerce.Runtime.DataModel.CartConfiguration&lt;/li&gt;
&lt;li&gt;Property &lt;strong&gt;AllowedMaximumDaysForRequestDelivery&lt;/strong&gt; is added to Microsoft.Dynamics.Commerce.Runtime.DataModel.CartConfiguration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These properties are maintained in the Online store functionality profile in D365 ERP:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-53-10-0-43/1742501272700-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.4 New flight keys&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Microsoft implements new CSU flight keys with every new CSU version. These undocumented flight keys steer specific CSU behavior. Here is a list of the latest keys:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-53-10-0-43/1742501545405-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;D-Sources&lt;/h3&gt;
&lt;p&gt;With my Team, I have developed a couple of tools to collect the information above for you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Automation to extract the OpenAPI specification from the latest Commerce CSU package&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automation to compare the OpenAPI specification with a previous OpenAPI specification and identify any changes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automation to parse the latest DLL with D365 Commerce OData end points and extract role identification from the DLL:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;E-About the Author&lt;/h3&gt;
&lt;p&gt;I&amp;#39;ve been integrating non-Microsoft e-commerce solutions with D365 ERP and CRM since the early days of AX for Retail in 2009. Already back in 2015, I connected an E-commerce platform to D365 ERP by a &lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/&quot;&gt;&lt;strong&gt;predecessor of the current D365 Commerce CSU&lt;/strong&gt;&lt;/a&gt; for the first time.&lt;/p&gt;
&lt;p&gt;Get in touch via &lt;a href=&quot;/contact&quot;&gt;patrickmouwen.com/contact&lt;/a&gt; if you need help in implementing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://microsoft.com/en-us/dynamics-365/products/commerce&quot;&gt;&lt;strong&gt;D365 Commerce&lt;/strong&gt;&lt;/a&gt; on top of ERP including &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/store-commerce&quot;&gt;&lt;strong&gt;D365 Store Commerce App&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/b2b/set-up-b2b-site&quot;&gt;&lt;strong&gt;D365 e-commerce&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Customizing/Extending D365 Commerce, &lt;a href=&quot;https://www.microsoft.com/en-us/dynamics-365/products/commerce#tabs-pill-bar-oc81bf_tab5&quot;&gt;&lt;strong&gt;CSU&lt;/strong&gt;&lt;/a&gt;, Store Commerce App and e-commerce&lt;/li&gt;
&lt;li&gt;B2C and B2B Headless Commerce/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;B2C and B2B Commerce Platform/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;Customer Service operation based on D365 ERP and D365 CE data utilizing Commerce CSU&lt;/li&gt;
&lt;li&gt;Social Commerce/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;Professional App (React.JS)/D365 ERP integrations utilizing Commerce CSU&lt;/li&gt;
&lt;li&gt;POS/ERP integration&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Disclaimer&lt;/h2&gt;
&lt;p&gt;The content of this article represents my independent technical analysis and personal interpretation of publicly available software artefacts. It is not endorsed by, affiliated with, or authorised by Microsoft Corporation. Nothing in this article constitutes official Microsoft documentation, guidance, or product commitments.&lt;/p&gt;
&lt;p&gt;All findings are derived from analysis of the software and public documentation. Feature descriptions, presumable use cases, and &amp;quot;likely intent&amp;quot; assessments reflect my professional opinion based on observable code and API changes — they may not reflect Microsoft&amp;#39;s actual design intent, planned behaviour, or final implementation.&lt;/p&gt;
&lt;p&gt;Information regarding features described as preview, private preview, or roadmap items is subject to change at Microsoft&amp;#39;s sole discretion and should not be relied upon for planning, purchasing, or architectural decisions. This article describes the product as at the date of publication above.&lt;/p&gt;
&lt;p&gt;This article is provided for informational and educational purposes only, on an &amp;quot;as-is&amp;quot; basis without warranties of any kind, express or implied. The author assumes no liability for any direct, indirect, incidental, or consequential damages arising from the use of or reliance on the information contained herein.&lt;/p&gt;
&lt;p&gt;For authoritative product information, consult Microsoft&amp;#39;s official documentation at &lt;a href=&quot;https://learn.microsoft.com&quot;&gt;learn.microsoft.com&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>Commerce CSU</category></item><item><title>Case #3: Why using Commerce CSU for Headless Commerce beats custom-built Solutions</title><link>https://patrickmouwen.com/blog/case-3-why-using-commerce-csu-headless-beats-solutions/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/case-3-why-using-commerce-csu-headless-beats-solutions/</guid><description>Why Commerce CSU beats a custom build for exposing D365 ERP data to headless e-commerce, compared against the more traditional approaches.</description><pubDate>Fri, 14 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this series of blog posts I&amp;#39;ll share insights, strategies, and proven solutions to address the most common roadblocks and challenges in connecting non-Microsoft e-commerce to D365 ERP.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Today&amp;#39;s Case&lt;/h3&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this blog post, we&amp;#39;ll take a look at the benefits of using Commerce CSU to expose D365 ERP data for Headless e-commerce solutions. We&amp;#39;ll do this by comparing with more traditional custom approaches.&lt;/p&gt;
&lt;p&gt;To take an honest approach, we must first distinct the various types of e-commerce solutions:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-3-why-using-commerce-csu-headless-beats-solutions/1741356848315-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Traditional Commerce Platforms&lt;/strong&gt;: In traditional Commerce platforms, the frontend (user interface) and backend (server, database) are tightly integrated. Backend systems like D365 ERP often deliver data to the platform by periodic data sync and receive transactions via periodic data sync.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Headless Commerce:&lt;/strong&gt; Headless commerce decouples the UX frontend from the backend. Backend systems like D365 ERP could deliver their product, pricing, attribute, payment, order history and other data by direct API connectivity if performance allows that.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hybrid&lt;/strong&gt;: combines elements of both traditional and headless architectures. Businesses might use a traditional platform for core e-commerce functionalities while integrating headless solutions for specific channels or services. Backend systems like D365 ERP could deliver their data by direct API connectivity, data synch or a combination.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Traditionally, companies implemented more monolithic commerce platforms to benefit from its &amp;#39;all-in-one&amp;#39; nature. The platforms were connected to backend systems like D365 ERP and CRM by data synch.&lt;/p&gt;
&lt;p&gt;Over the last 5 years, the benefits of more monolith platforms have been challenged fundamentally by the following trends:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Shift in Consumer behavior&lt;/strong&gt;: Shoppers demand seamless omnichannel experiences, AI-driven personalization, and flexible business models (subscriptions, marketplaces), which platform monoliths struggle to support.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Digital Touchpoints&lt;/strong&gt; – A traditional website is no longer spearheading sales. Sales is happening via a variety of digital touch points like mobile apps, social commerce (TikTok, Instagram etc), marketplaces, AI chatbots and agents and smart devices (like fridges which can re-order). This requires a headless architecture which enables brands to &lt;strong&gt;s&lt;/strong&gt;erve all these touchpoints from a single backend by exposing APIs, whereas traditional commerce platforms struggle because they were built for a single-channel experience (usually web-based).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI &amp;amp; Automation Require API-First Integration&lt;/strong&gt; – AI-powered search, recommendations, and automated workflows need real-time data access, which rigid, monolithic architectures cannot efficiently provide.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regulatory &amp;amp; Security Pressures Have Increased&lt;/strong&gt; – Compliance with GDPR, CCPA, and PSD2 is complex, and traditional platforms require costly updates to stay compliant, whereas headless solutions can lean on backend systems like D365 ERP which are already compliant.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because of these trends, headless commerce is quickly winning ground over traditional commerce platforms, both in B2C and B2B.&lt;/p&gt;
&lt;h2&gt;The role of D365 Commerce CSU&lt;/h2&gt;
&lt;p&gt;I&amp;#39;ve been working in the domain of D365 Business Applications and Commerce for more than 15 years. If I take an honest look at this domain I can only conclude that D365 ERP and Dataverse (baseline for D365 CE, Customer Service etc) are &lt;em&gt;not suitable&lt;/em&gt; to serve Headless Commerce solutions. This is exactly the reason why so many partners and customers have developed a wide variety of &lt;em&gt;custom&lt;/em&gt; services and solutions to integrate D365 ERP and CRM/Customer Insights with e-commerce solutions.&lt;/p&gt;
&lt;p&gt;In most cases, these efforts hit hard walls like:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Excessive CAPEX investment&lt;/strong&gt;: most available D365 ERP and Dataverse APIs are Create, Read, Update, Delete (CRUD), but headless commerce requires business-process APIs for areas like Cart management (pricing, promotions, taxes, shipping), Real-time inventory availability (e.g., ATP calculations, warehouse fulfillment) and AI-driven product search and recommendations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Poor performance&lt;/strong&gt;: standard D365 ERP OData APIs and Dataverse APIs are not designed for high-throughput, low-latency e-commerce transactions. APIs are often batch-oriented, making them inefficient for real-time customer interactions (e.g., live cart updates, checkout). Dataverse throttling and API rate limits can block high-volume requests, making it unsuitable for peak traffic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lack of omnichannel focus:&lt;/strong&gt; the solution if often architected to serve only a single channel or digital touchpoint.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Dynamics 365 includes a built-in headless architecture that enables direct use of Dataverse and D365 ERP data in headless frontends. This architecture is designed to support own &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/online-store-overview&quot;&gt;D365 e-commerce&lt;/a&gt; and &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/store-commerce-capabilities&quot;&gt;D365 Store Commerce&lt;/a&gt; (POS) solutions, making it a robust and well-suited backend for any headless commerce frontend.&lt;/p&gt;
&lt;p&gt;This picture outlines the architecture which is part of the standard D365 offering:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-3-why-using-commerce-csu-headless-beats-solutions/1741966067682-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Dual Write&lt;/strong&gt;: Data can be synched bidirectionally between Dataverse and D365 ERP in real time by using &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/data-entities/dual-write/dual-write-overview&quot;&gt;Dual Write&lt;/a&gt;. D365 ERP comes with D365 headless commerce engine (CSU) which consists of a database, microservices and OData API layer with 650 APIs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. D365 headless commerce engine&lt;/strong&gt;: Synching data from Dataverse (via Dual Write) and D365 ERP to the CSU database is out-of-box available bi-directional and near-real time (usually with synch intervals between 1 and 3 minutes**).**&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Headless commerce architecture&lt;/strong&gt;: The CSU database acts as a &lt;em&gt;local data cache&lt;/em&gt;. It is also possible to deploy multiple CSUs which keep &lt;em&gt;latency&lt;/em&gt; to the digital touch points low. Operating on top of the local data cache and microservices architecture, the 650 APIs are performant enough to &lt;em&gt;directly serve as backend&lt;/em&gt; for headless commerce. The APIs include commerce specific APIs which are not available in D365 ERP or Dataverse, but which operate directly &lt;em&gt;on top&lt;/em&gt; of master data, setup and parameters in D365 ERP and Dataverse. Examples are Cart APIs and APIs which expose &lt;a href=&quot;https://www.microsoft.com/en-us/dynamics-365/blog/it-professional/2024/10/17/introducing-unified-pricing-management-a-revolutionary-approach-to-attribute-based-pricing/&quot;&gt;Unified Pricing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Additional services&lt;/strong&gt;. Dataverse Apps and D365 ERP struggle to provide a performant search experience across Inventory, Products and Customers. D365 Commerce headless engine resolves this by teaming up with Azure AI powered search. For example, D365 ERP Product and Attribute information is indexed in Azure AI Search (formerly known as Cognitive search) which is utilized by the &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/cloud-powered-search-overview&quot;&gt;Commerce Product Search APIs&lt;/a&gt; directly. D365 Commerce CSU also integrates with Customer Insights utilizing Microsoft Copilot and &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/supply-chain/inventory/inventory-visibility&quot;&gt;Inventory Visibility.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Ready-for-use integration&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The 650 APIs provided by the D365 headless commerce engine (CSU) are ready-for-use. &lt;a href=&quot;/community-tools/&quot;&gt;Here on my website&lt;/a&gt; you can find a list of all available APIs presented in Swagger UI.&lt;/p&gt;
&lt;h3&gt;Preliminary conclusions&lt;/h3&gt;
&lt;p&gt;An article like this can never outline &lt;em&gt;all&lt;/em&gt; arguments why D365 commerce headless engine is such a treasure for quick development of high performant and rich frontends for any digital commerce touch point in headless architectires.&lt;/p&gt;
&lt;p&gt;But by highlighting just a few benefits compared to custom integration solutions based on D365 ERP and Dataverse, I hope I could convey my personal experience that the use of d365 commerce headless engine will &lt;em&gt;always beat&lt;/em&gt; any other custom solution. Whether looking from the angle of efficient investment, time-to-market, omnichannel strategy, scalability or performance, D365 commerce headless engine is &lt;em&gt;always&lt;/em&gt; a better alternative than a custom solution.&lt;/p&gt;
&lt;p&gt;However, all of these benefits would all be wiped out in one sweep if D365 headless commere engine would not be &lt;em&gt;affordable&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So, before jumping into final conclusions, let&amp;#39;s first address this often-heard argument against the use of D365 Commerce headless engine.&lt;/p&gt;
&lt;h3&gt;Is D365 Commerce CSU affordable?&lt;/h3&gt;
&lt;p&gt;To answer this question, let&amp;#39;s first align on some fundamental assumptions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ERP Backend licensing&lt;/strong&gt;. Deploying Commerce CSUs requires an organization to have 20 Commerce backend licenses. Standard ERP (Finance/Supply Chain) licenses can often be swapped for 20 Commerce licenses against no additional cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Headless licensing and headless use&lt;/strong&gt;. Commerce CSU was originally developed for D365 e-commerce and D365 Store Commerce App. So, license-wise you either pay for deploying x number of devices running Store Commerce App or D365 e-commerce. If you want to use the D365 headless commerce engine (CSU) for headless frontends, the licensing does not map neatly onto either model, so it becomes a commercial conversation rather than a list price. Treat it as negotiable and get it costed early: it is an architectural assumption with a material price attached, and it should be tested before it becomes a commitment. Note that this licence cost grants access to your ERP and Dataverse data for hundreds or thousands of customers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Non-headless use.&lt;/strong&gt; Integrating D365 ERP and Dataverse with more traditional monolith platforms is a totally different ball game than headless architectures. The platforms often come with significant investment due to the proclaimed &amp;quot;all-in-one&amp;quot; nature and integrations are also relatively costly as they involve asynchronous data flows and often complex data mappings and custom business logic (for example for pricing and inventory calculations). Due to this high investment level for platform and integrations, there is often no budget left for d365 headless commerce engine (CSU). Therefore, this article only focuses on the cost for &lt;em&gt;headless&lt;/em&gt; e-commerce architectures, which many companies in B2C and B2B commerce transition to at the moment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Affordable cost per Order (CPO):&lt;/strong&gt; Total cost of an order including operational and IT related OPEX is often measured as % of Average Order Value (AOV). A portion of the CPO/AOV % will be contributed to OPEX for maintaining the headless commerce solution (frontend and backend). It&amp;#39;s always arbitrary, but from what I&amp;#39;ve seen in my projects over the last 10 years, an affordable CPO/AOV % for a B2C front- and backend is about &lt;strong&gt;0.5-1% for B2C&lt;/strong&gt; (as AOV and margins are lower) and &lt;strong&gt;1-2% for B2B&lt;/strong&gt;. If we split the cost for frontend and backend functions in two halfs, then an affordable CPO for backend integration would be about &lt;strong&gt;0.2-0.5% for B2C&lt;/strong&gt; and &lt;strong&gt;0.5-1% for B2B&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AOV ranges&lt;/strong&gt;: B2C businesses usually operate in lower Average Order Value (AOV) ranges than B2B organizations. B2C businesses mostly stay within USD 50-250 range where B2B AOVs are often between USD 500 and USD 2000.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, with this in mind, I&amp;#39;ve used AI tools to calculate different price points based on the licensing model for D365 headless commerce engine (CSU) - See &lt;a href=&quot;https://www.licensingschool.co.uk/wp-content/uploads/2025/03/Dynamics-365-Licensing-Guide-March-2025.pdf&quot;&gt;licensing guide March 2025&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I calculated the price points by the following assumptions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AOV for B2B in USD: 49 - 100 - 250 - 750 - 1000 - 1500 - 2500 - 4000 - 7500&lt;/li&gt;
&lt;li&gt;AOV for B2C in USD: 25 - 50 - 100 - 150 - 250 - 750 - 1000 - 1500 - 2500&lt;/li&gt;
&lt;li&gt;Transactional volume for B2B per year: 2500 - 5000 - 10000 - 25000 - 50000 - 75000 - 100000 - 150000 - 250000&lt;/li&gt;
&lt;li&gt;Transactional volume for B2C per year: 10000 - 25000 - 50000 - 100000 - 200000 - 500000 - 750000 - 1000000 - 2500000&lt;/li&gt;
&lt;li&gt;Color coding B2B in CPO/AOV % for headless backend: red: 1.5 - 100 | amber 1-1.5 | light green 0.5-1 | green 0-0.5&lt;/li&gt;
&lt;li&gt;Color coding B2C in CPO/AOV % for headless backend: red: 1 - 100 | amber 0.5-1 | light green 0.2-0.5 | green 0-0.2&lt;/li&gt;
&lt;li&gt;Applied discount against standard list price for D365 headless commerce: 55%&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Outcome for B2C:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-3-why-using-commerce-csu-headless-beats-solutions/1741969928276-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Outcome for B2B:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-3-why-using-commerce-csu-headless-beats-solutions/1741970196416-3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;Although assumptions about affordable CPO/AOV % for headless backend licensing are always arbitrary, I think above matrix at least gives a good overview of percentages of license cost vs Average Order Value (AOV) per order.&lt;/p&gt;
&lt;p&gt;What becomes clear from the overviews is that D365 headless commerce engine becomes more and more affordable with either rising volume, rising AOV or both.&lt;/p&gt;
&lt;p&gt;In B2C context, a total annual transactional volume of ~500.000 orders (~1370 per day) against a 50-100 AOV already gives you very affordable license cost.&lt;/p&gt;
&lt;p&gt;In B2B context, an AOV of 250-1000 already comes with very affordable license cost at low volumes (5000-10000 orders per year).&lt;/p&gt;
&lt;p&gt;if your Business does not meet these thresholds, you may try to convince Microsoft to give you a higher discount for headless use, especially when your organization has a hybrid strategy or other strategy which keeps API requests against the CSU lower than average.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;About the Author&lt;/h2&gt;
&lt;p&gt;I&amp;#39;ve been integrating non-Microsoft e-commerce solutions with D365 ERP and CRM since the early days of AX for Retail in 2009. Already back in 2015, I connected an E-commerce platform to D365 ERP by a &lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/&quot;&gt;&lt;strong&gt;predecessor of the current D365 Commerce CSU&lt;/strong&gt;&lt;/a&gt; for the first time.&lt;/p&gt;
&lt;p&gt;Get in touch via &lt;a href=&quot;/contact&quot;&gt;patrickmouwen.com/contact&lt;/a&gt; if you need help in implementing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://microsoft.com/en-us/dynamics-365/products/commerce&quot;&gt;&lt;strong&gt;D365 Commerce&lt;/strong&gt;&lt;/a&gt; on top of ERP including &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/store-commerce&quot;&gt;&lt;strong&gt;D365 Store Commerce App&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/b2b/set-up-b2b-site&quot;&gt;&lt;strong&gt;D365 e-commerce&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Customizing/Extending D365 Commerce, &lt;a href=&quot;https://www.microsoft.com/en-us/dynamics-365/products/commerce#tabs-pill-bar-oc81bf_tab5&quot;&gt;&lt;strong&gt;CSU&lt;/strong&gt;&lt;/a&gt;, Store Commerce App and e-commerce&lt;/li&gt;
&lt;li&gt;B2C and B2B Headless Commerce/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;B2C and B2B Commerce Platform/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;Customer Service operation based on D365 ERP and D365 CE data utilizing Commerce CSU&lt;/li&gt;
&lt;li&gt;Social Commerce/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;Professional App (React.JS)/D365 ERP integrations utilizing Commerce CSU&lt;/li&gt;
&lt;li&gt;POS/ERP integration&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Headless Commerce</category></item><item><title>Case #2: Can customer account login on your non-Microsoft e-commerce website grant you access to D365 ERP data?</title><link>https://patrickmouwen.com/blog/case-2-can-your-e-commerce-account-login-grant-you-access/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/case-2-can-your-e-commerce-account-login-grant-you-access/</guid><description>Can an existing e-commerce account login authenticate B2B users straight into D365 ERP data? Case #2 on integrating non-Microsoft e-commerce.</description><pubDate>Fri, 22 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this series of blog posts I&amp;#39;ll share insights, strategies, and proven solutions to address the most common roadblocks and challenges in connecting non-Microsoft e-commerce to D365 ERP.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Today&amp;#39;s Case&lt;/h3&gt;
&lt;h3&gt;Q&amp;amp;A&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Question raised by the customer: is there a way to directly authenticate our B2B users to access D365 ERP data, just by using their existing login to the e-commerce website?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Short answer: YES! the D365 CSU APIs shipped with D365 ERP support this scenario out-of-the-box. Read on to see how..&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;External user login to ERP data&lt;/h2&gt;
&lt;p&gt;e-commerce frontends often have out-of-the-box user account management. In a B2B context, these users are also linked to an organization. Ideally for a seamless user experience, customer log-in would allow your E-SHOP to authenticate directly against D365 ERP data. It would even be better if the ERP data is scoped to the authenticated customer - In other words: that the single customer login in the e-commerce frontend triggers the ERP data to be filtered and narrowed-down to products the customer is allowed to see, with specific pricing reflecting the terms and agreements with the customer.&lt;/p&gt;
&lt;p&gt;This is all possible out-of-the-box as shown in the diagram below. The trick is to link the authentication provider&amp;#39;s unique identity for a customer to a user and organization in D365 (in B2B world) or customer account in D365 (in B2C world). This setup is then synched to the &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/retail-server-architecture&quot;&gt;D365 Commerce CSU&lt;/a&gt; as per standard &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/define-retail-channel-communications-cdx&quot;&gt;batch jobs&lt;/a&gt;, so the CSU is ready to grant customer users access to ERP.&lt;/p&gt;
&lt;p&gt;Now, when the user logs into the authentication provider embedded in an E-SHOP page, the E-SHOP will receive a token which contains the unique identity of the customer user which was mapped in ERP and now available in CSU. This allows the CSU to re-validate the token, look up the customer user and organization (B2B) or Customer account (B2C) and grant access to local data in CSU or directly into ERP via a real time connection from CSU. We&amp;#39;ll take a deeper dive into these 5 steps below. We&amp;#39;ll take the example of a user who logs into a non-Microsoft e-commerce site with Google account. Please note that this will also work with &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/active-directory-b2c/overview&quot;&gt;Azure B2C&lt;/a&gt; as well as any Open ID CONNECT compatible identity provider such as LinkedIn, Microsoft hotmail, Facebook, &lt;a href=&quot;https://auth0.com/&quot;&gt;Auth0&lt;/a&gt; etc.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-2-can-your-e-commerce-account-login-grant-you-access/1732273108821-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Step 1: Setup the Authentication provider [in our case: Google]&lt;/h3&gt;
&lt;p&gt;Note: prerequisites for below are to have login details of an existing Google account available and &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/provisioning-guide#commerce-preview-environment-support&quot;&gt;have deployed a CSU&lt;/a&gt; in case of a sandbox. In case of a DEV-box, the built-in Retail Server will act as CSU.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1A: Setup Google Application&lt;/strong&gt; to authenticate against D365:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open &lt;a href=&quot;https://console.cloud.google.com/&quot;&gt;https://console.cloud.google.com/&lt;/a&gt; and login with your google account.&lt;/li&gt;
&lt;li&gt;Navigate to APIs and Services&lt;/li&gt;
&lt;li&gt;Go to the Credentials page&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Create Credentials&amp;quot; and select &amp;quot;OAuth 2.0 Client ID&amp;quot;&lt;/li&gt;
&lt;li&gt;Configure the consent screen if you haven&amp;#39;t done so already&lt;/li&gt;
&lt;li&gt;Set the application type to &amp;quot;Web application&amp;quot;&lt;/li&gt;
&lt;li&gt;Add &lt;a href=&quot;https://oauth.pstmn.io/v1/callback&quot;&gt;https://oauth.pstmn.io/v1/callback&lt;/a&gt; to the Authorized redirect URIs&lt;/li&gt;
&lt;li&gt;Save and note down the &lt;strong&gt;Client ID&lt;/strong&gt; and &lt;strong&gt;Client Secret&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;1B: retrieve unique identity token representing your customer user&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open a tool to construct and send API requests, such as Postman&lt;/li&gt;
&lt;li&gt;Construct a new API request with URL = &lt;a href=&quot;https://accounts.google.com/o/oauth2/v2/auth&quot;&gt;https://accounts.google.com/o/oauth2/v2/auth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The rest of the URL will be constructed by the Query Params you&amp;#39;ll fill in (see picture below)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-2-can-your-e-commerce-account-login-grant-you-access/1732273795571-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do not fire the request from within Postman or other tool you&amp;#39;re using, but copy the full URL into a web browser&lt;/li&gt;
&lt;li&gt;Login with your Google account&lt;/li&gt;
&lt;li&gt;Copy the code after &amp;quot;code=&amp;quot; and before &amp;quot;&amp;amp;scope&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-2-can-your-e-commerce-account-login-grant-you-access/1732273986375-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;URI decode this code via &lt;a href=&quot;https://www.urldecoder.org/&quot;&gt;https://www.urldecoder.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Construct another request in Postman to get an ID token with the Authorization code: POST &lt;a href=&quot;https://oauth2.googleapis.com/token&quot;&gt;https://oauth2.googleapis.com/token&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-2-can-your-e-commerce-account-login-grant-you-access/1732274201571-3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This will retrieve an id_token - Copy it as indicated in the picture:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-2-can-your-e-commerce-account-login-grant-you-access/1732274342001-4.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to &lt;a href=&quot;http://jwt.io&quot;&gt;jwt.io&lt;/a&gt; and paste the id_token&lt;/li&gt;
&lt;li&gt;Note down the values for &lt;strong&gt;Iss, Aud&lt;/strong&gt; and &lt;strong&gt;Sub&lt;/strong&gt; - You&amp;#39;ll need them in step 2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-2-can-your-e-commerce-account-login-grant-you-access/1732276648790-5.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Explanation:&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 2: Setup D365 ERP&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;2A - Setup identity provider&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Commerce Shared Parameters &amp;gt; Identity providers&lt;/strong&gt; in D365 ERP&lt;/li&gt;
&lt;li&gt;Create a new &lt;strong&gt;Issuer&lt;/strong&gt; record: &lt;strong&gt;Type&lt;/strong&gt; = Open ID Connect - Fill in the value for &lt;strong&gt;Iss&lt;/strong&gt; which you noted down in step 1B - &lt;strong&gt;Name&lt;/strong&gt; can be anything&lt;/li&gt;
&lt;li&gt;Create a new &lt;strong&gt;relying parties&lt;/strong&gt; record underneath the new Issuer record**:** paste ClientID from step 1A and set &lt;strong&gt;Type&lt;/strong&gt; = Public and &lt;strong&gt;UserType&lt;/strong&gt; = Customer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-2-can-your-e-commerce-account-login-grant-you-access/1732276362920-6.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2B - Setup for B2C and B2B&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a new person type of customer account representing the user&lt;/li&gt;
&lt;li&gt;Ensure the E-mail address of the customer account matches your Google e-mail address&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2C - Setup a B2B customer hierarchy&lt;/strong&gt; (only required for B2B)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Customer hierarchies&lt;/strong&gt; form in D365 ERP&lt;/li&gt;
&lt;li&gt;Create a new hierarchy&lt;/li&gt;
&lt;li&gt;Ensure to configure the customer account from step 2B as a user for the organization and also ensure to list the desired online channel(s) the customer user should have access to&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2D - Link Identity provider&amp;#39;s identity to a Customer user&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Follow the steps in this &lt;a href=&quot;https://www.linkedin.com/pulse/understanding-dynamics-365-headless-commerce-role-febin-chiramel-szdbf/?trackingId=2FnXDKo4D%2FllJo9hyr2eHQ%3D%3D&quot;&gt;blog post by Febin Chiramel&lt;/a&gt; to create a new record in the &lt;strong&gt;RETAILEXTERNALIDTOCUSTOMERMAP&lt;/strong&gt; table with Excel.&lt;/li&gt;
&lt;li&gt;This record will link the Issuer&amp;#39;s identity to the customer account created in step 2B. Use the &lt;strong&gt;Sub&lt;/strong&gt; value you noted in step 1B for this.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 3: Synch the ERP setup to the CSU&lt;/h3&gt;
&lt;p&gt;Open the &lt;strong&gt;Distribution schedule&lt;/strong&gt; form in D365 and run jobs 1010 and 1110 to synch the new customer and related identity provider setup to the CSU&lt;/p&gt;
&lt;h3&gt;Step 4: Login to your Google account on the E-commerce platform&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;By now, your frontend development partner should have seamlessly made the Google login window available via a web page in your E-commerce platform, so the manual work in step 1B should no longer be necessary.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Step 5: Retrieve D365 ERP Data in real time and scoped to the authenticated customer!&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Once the id_token is retrieved by the non-Microsoft e-commerce solution, the token can be used for any subsequent interaction between the frontend and D365 CSU. This is done by putting the token into &lt;strong&gt;Authorization&lt;/strong&gt; header of any API request to the CSU:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-2-can-your-e-commerce-account-login-grant-you-access/1732277649906-7.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The CSU will now re-validate the token by the local identity provider details in the CSU database which you set up in ERP in step 2.&lt;/li&gt;
&lt;li&gt;Once the token is validated successfully, D365 will lookup the customer account by the user identity and &lt;em&gt;&lt;strong&gt;will contextualize any request against the customer who logged in&lt;/strong&gt;&lt;/em&gt; (!). So for example, a &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/pricing-apis#getactiveprices&quot;&gt;&lt;strong&gt;GetActivePrices&lt;/strong&gt;&lt;/a&gt; request will retrieve pricing details (such affiliation pricing) based on the context of the customer who logged in 👍👍👍!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-2-can-your-e-commerce-account-login-grant-you-access/1732277756738-8.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;All too complex?&lt;/h2&gt;
&lt;p&gt;This may seem a bit overwhelming or too complex to some of you. That&amp;#39;s why I founded my company 365CONNECT in 2022. Within this company we packaged all our knowledge and experience into a standard Product and Setup offering which makes it very easy to onboard and start using the D365 CSU. See &lt;em&gt;About the Author&lt;/em&gt; below.&lt;/p&gt;
&lt;h2&gt;Licensing and Pricing considerations&lt;/h2&gt;
&lt;p&gt;A most-heard complaint in the D365 ecosystem in &lt;a href=&quot;https://www.linkedin.com/pulse/case-1-d365-erp-cannot-backend-your-headless-solution-patrick-mouwen-yjjse&quot;&gt;using D365 CSU&lt;/a&gt; for connecting non-Microsoft e-commerce to D365 is about the pricing of the CSU. But what if you take into the equasion that your say 800 B2B customer users actually all need access to your ERP data, as this data is directly accessible in the e-commerce frontend? A classical user licensing model would not work here. That&amp;#39;s why Microsoft put up a CSU licensing model based on transactional volume and average order volume (AOV). So if your transactional volume and AOV remain constant while your Customer user base grows to 1200 users, you will not pay anything more. I think that&amp;#39;s quite fair. We&amp;#39;ll further zoom into licensing and pricing in an upcoming blog post.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;About the Author&lt;/h2&gt;
&lt;p&gt;I&amp;#39;ve been integrating non-Microsoft e-commerce solutions with D365 ERP and CRM since the early days of AX for Retail in 2009. Already back in 2015, I connected an E-commerce platform to D365 ERP by a &lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/&quot;&gt;&lt;strong&gt;predecessor of the current D365 Commerce CSU&lt;/strong&gt;&lt;/a&gt; for the first time.&lt;/p&gt;
&lt;p&gt;Get in touch via &lt;a href=&quot;/contact&quot;&gt;patrickmouwen.com/contact&lt;/a&gt; if you need help in implementing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://microsoft.com/en-us/dynamics-365/products/commerce&quot;&gt;&lt;strong&gt;D365 Commerce&lt;/strong&gt;&lt;/a&gt; on top of ERP including &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/store-commerce&quot;&gt;&lt;strong&gt;D365 Store Commerce App&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/b2b/set-up-b2b-site&quot;&gt;&lt;strong&gt;D365 e-commerce&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Customizing/Extending D365 Commerce, &lt;a href=&quot;https://www.microsoft.com/en-us/dynamics-365/products/commerce#tabs-pill-bar-oc81bf_tab5&quot;&gt;&lt;strong&gt;CSU&lt;/strong&gt;&lt;/a&gt;, Store Commerce App and e-commerce&lt;/li&gt;
&lt;li&gt;B2C and B2B Headless Commerce/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;B2C and B2B Commerce Platform/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;Customer Service operation based on D365 ERP and D365 CE data utilizing Commerce CSU&lt;/li&gt;
&lt;li&gt;Social Commerce/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;Professional App (React.JS)/D365 ERP integrations utilizing Commerce CSU&lt;/li&gt;
&lt;li&gt;POS/ERP integration&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Headless Commerce</category></item><item><title>Case #1: D365 ERP cannot be the backend for your headless e-commerce solution.. Right?</title><link>https://patrickmouwen.com/blog/case-1-d365-erp-cannot-backend-your-headless-solution/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/case-1-d365-erp-cannot-backend-your-headless-solution/</guid><description>Can a headless frontend connect directly to D365 ERP without synchronising data? Case #1 in a series on integrating non-Microsoft e-commerce.</description><pubDate>Fri, 15 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this series of blog posts I&amp;#39;ll share insights, strategies, and proven solutions to address the most common roadblocks and challenges in connecting non-Microsoft e-commerce to D365 ERP.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Today&amp;#39;s Case&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-1-d365-erp-cannot-backend-your-headless-solution/1731593667039-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Q&amp;amp;A&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Question raised by the customer: is there really no way to directly connect my headless frontend to D365 ERP? I do not want to synch data since this is costly, incurs latency and leads to issues related to data inconsistency and regulatory compliance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Short answer: There &lt;em&gt;is&lt;/em&gt; a way to do this! The out-of-box APIs shipped with D365 ERP are not suitable to support this like the partner indicates. However, D365 ERP comes with an Add-on called D365 Commerce CSU which is designed to be the desired scalable backend API layer for your headless e-commerce solution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;How D365 ERP can practically be the API backend for your headless e-commerce solution&lt;/h2&gt;
&lt;p&gt;The Online-Only Retailer will be using D365 ERP in a lot of process domains like Purchasing, Stock Management, Warehousing, Order Management and Finance. All data collected in these areas can be synched out-of-box to the D365 Commerce CSU local database in near-real time (1-5 minutes of recurrence). Some of this data is even available in real time. The dark balloons under &lt;em&gt;backend&lt;/em&gt; in the picture below represent this data.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-1-d365-erp-cannot-backend-your-headless-solution/1731596299459-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;When the Commerce license key, which is included as part of D365 ERP, is enabled, suddenly way more data functionality for your headless e-commerce solution is made availale in ERP (represented by the green balloons in the picture above). The following picture provides a more comprehensive overview of this data and functionality. We&amp;#39;ll briefly discuss the additional functionality and data.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-1-d365-erp-cannot-backend-your-headless-solution/1731597036203-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Additional Backend functions&lt;/strong&gt;. In the ERP backend, Commerce oriented functions are suddenly enabled in various modules - Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;omnichannel tokenized payments: &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/commerce-payments&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Maintaining a navigation hierarchy for your headless frontend: &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/create-channel-hierarchy&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AI powered search in your headless frontend: &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/cloud-powered-search-overview&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Item warranty: &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/extended-warranty&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. Making this functionality and data available&lt;/strong&gt;. All of this data and functionality can be synched to the Commerce CSU as per an out-of-box synch framework. Data in different areas can be synched with different frequency, depending on required actuality. In many cases, there is also a real time alternative available in case your frontend requires real time data to be presented to the customer. Vice versa, new Orders coming in from the headless frontend are synched from CSU to ERP out-of-box as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Commerce CSU APIs&lt;/strong&gt;. Where D365 ERP has an API layer which is mostly Data oriented (to read, write, delete and update data), the Commerce CSU API is packed with Business logic. This means that the CSU APIs can calculate prices, recognizes customer, channel and legal entity context and even integrates out-of-box with various AI functions like Azure AI Search for products and Product Recommendation service.&lt;/p&gt;
&lt;p&gt;In upcoming blog posts, I will explain how to benefit from the APIs in a variety of domains such as Inventory management, Pricing Management and Product Management.&lt;/p&gt;
&lt;h3&gt;Advanced Scenarios&lt;/h3&gt;
&lt;p&gt;Different Businesses require different setups. And headless e-commerce setups may differ by nature as well. Below we&amp;#39;ll take it one level deeper looking at 3 advanced headless scenarios and how D365 Commerce CSU can support these.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scenario #1&lt;/strong&gt;: our Online-only Retailer expands to Asia and Americas&lt;/p&gt;
&lt;p&gt;When expanding their Business to the Americas, the Retailers wants to keep latency to a minimum. To accommodate this, multiple CSUs can be deployed. For example, one in Europe and one somewhere in the American region. D365 ERP still allows &lt;em&gt;all&lt;/em&gt; data to be synched to both CSUs or the company can make a selection of the data per CSU.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-1-d365-erp-cannot-backend-your-headless-solution/1731599648865-3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scenario #2&lt;/strong&gt;: our Online-only Retailer decides to implement a Progressive Web app&lt;/p&gt;
&lt;p&gt;A Progressive Web App (PWA) is a type of web application designed to provide a fast, reliable, and engaging user experience similar to that of native mobile apps, but accessible directly from the browser. To minimize latency, web traffic is to be routed from client to backend API layer directly. But sensitive data should be routed server to server. By utilizing &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/retail-server-customer-consumer-api&quot;&gt;API roles&lt;/a&gt; which are embedded in D365 CSU out-of-box, both scenarios can be mitigated: the &lt;strong&gt;Customer&lt;/strong&gt; role is suitable for authenticating an individual shopper. The &lt;strong&gt;Application&lt;/strong&gt; role is suitable for securing server to server communication. We’ll explore both roles in upcoming blog posts in this series.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scenario #3&lt;/strong&gt;: our Online-only Retailer requires API performance under 100 ms&lt;/p&gt;
&lt;p&gt;If CSU API performance is not sufficient for some frontend journey components, the customer may choose to implement an in-memory cache. This can either cache CSU requests for quick re-use in subsequent frontend interaction (option 1 in below picture) or can be sourced from D365 ERP by custom batch jobs (option 2 in below picture). This can lead to a hybrid setup where most headless e-commerce components are directly sourced via the Commerce CSU and others indirectly via the in-memory cache.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/case-1-d365-erp-cannot-backend-your-headless-solution/1731599685799-4.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;About the Author&lt;/h2&gt;
&lt;p&gt;I&amp;#39;ve been integrating non-Microsoft e-commerce solutions with D365 ERP and CRM since the early days of AX for Retail in 2009. Already back in 2015, I connected an E-commerce platform to D365 ERP by a &lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/&quot;&gt;&lt;strong&gt;predecessor of the current D365 Commerce CSU&lt;/strong&gt;&lt;/a&gt; for the first time.&lt;/p&gt;
&lt;p&gt;Get in touch via &lt;a href=&quot;/contact&quot;&gt;patrickmouwen.com/contact&lt;/a&gt; if you need help in implementing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://microsoft.com/en-us/dynamics-365/products/commerce&quot;&gt;&lt;strong&gt;D365 Commerce&lt;/strong&gt;&lt;/a&gt; on top of ERP including &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/store-commerce&quot;&gt;&lt;strong&gt;D365 Store Commerce App&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/b2b/set-up-b2b-site&quot;&gt;&lt;strong&gt;D365 e-commerce&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Customizing/Extending D365 Commerce, &lt;a href=&quot;https://www.microsoft.com/en-us/dynamics-365/products/commerce#tabs-pill-bar-oc81bf_tab5&quot;&gt;&lt;strong&gt;CSU&lt;/strong&gt;&lt;/a&gt;, Store Commerce App and e-commerce&lt;/li&gt;
&lt;li&gt;B2C and B2B Headless Commerce/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;B2C and B2B Commerce Platform/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;Customer Service operation based on D365 ERP and D365 CE data utilizing Commerce CSU&lt;/li&gt;
&lt;li&gt;Social Commerce/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;Professional App (React.JS)/D365 ERP integrations utilizing Commerce CSU&lt;/li&gt;
&lt;li&gt;POS/ERP integration&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Headless Commerce</category></item><item><title>Commerce CSU V9.51/10.0.41 - November 2024</title><link>https://patrickmouwen.com/blog/commerce-csu-v9-51-10-0-41/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/commerce-csu-v9-51-10-0-41/</guid><description>Unofficial release notes for Commerce CSU V9.51/10.0.41, November 2024 — the API and schema changes that matter for e-commerce integration.</description><pubDate>Wed, 13 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For anyone new in this field: &lt;strong&gt;Commerce CSU&lt;/strong&gt; is shipped as part of D365 ERP and can seamlessly integrate non-Microsoft e-commerce with D365 ERP:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-51-10-0-41/1731496473842-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I have been using Commerce CSU for e-commerce integrations since its early days around 2015. My mission is to empower you and your organization to use Commerce CSU effectively for your B2C and B2B e-commerce integrations. Therefore, I will publish these unofficial CSU Release Notes with any upcoming new Release.&lt;/p&gt;
&lt;h2&gt;A-Release Note Details&lt;/h2&gt;
&lt;p&gt;These Release notes are applicable for the following CSU and D365 ERP version:&lt;/p&gt;
&lt;h3&gt;B-Downloads for your convenience&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Latest V9.51 CSU full interface specification in OpenAPI/Swagger format: &lt;a href=&quot;/community-tools/&quot;&gt;Link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-51-10-0-41/1731499736334-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A snippet of the more than 350 APIs in Commerce CSU&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lestest V9.51 Overview of required Commerce Roles per API: &lt;a href=&quot;/resources/commerce/V9.51-API-Roles.xlsx&quot;&gt;Link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-51-10-0-41/1731499782277-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A snippet of the role identification for the more than 350 APIs&lt;/p&gt;
&lt;h3&gt;C-For the Techies: API and Model Changes compared to the previous version 9.50/V10.0.40&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;C.1 New APIs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;None&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.2 Removed APIs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;None&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C.3 Data Model Changes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-51-10-0-41/1731498735397-3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Comments&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Change #3 - DisplayNonRetailOrdersInEcommerceOrderHistory&lt;/strong&gt;: is a new parameter in D365 ERP backend &amp;gt; &lt;strong&gt;Commerce Parameters&lt;/strong&gt; - It displays or hides Orders which have been created with the Supply Chain Pricing engine as opposed to the Commerce Pricing engine:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/commerce-csu-v9-51-10-0-41/1731498827641-4.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;D-About the Author&lt;/h3&gt;
&lt;p&gt;I&amp;#39;ve been integrating non-Microsoft e-commerce solutions with D365 ERP and CRM since the early days of AX for Retail in 2009. Already back in 2015, I connected an E-commerce platform to D365 ERP by a &lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/&quot;&gt;&lt;strong&gt;predecessor of the current D365 Commerce CSU&lt;/strong&gt;&lt;/a&gt; for the first time.&lt;/p&gt;
&lt;p&gt;Get in touch via &lt;a href=&quot;/contact&quot;&gt;patrickmouwen.com/contact&lt;/a&gt; if you need help in implementing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://microsoft.com/en-us/dynamics-365/products/commerce&quot;&gt;&lt;strong&gt;D365 Commerce&lt;/strong&gt;&lt;/a&gt; on top of ERP including &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/store-commerce&quot;&gt;&lt;strong&gt;D365 Store Commerce App&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/b2b/set-up-b2b-site&quot;&gt;&lt;strong&gt;D365 e-commerce&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Customizing/Extending D365 Commerce, &lt;a href=&quot;https://www.microsoft.com/en-us/dynamics-365/products/commerce#tabs-pill-bar-oc81bf_tab5&quot;&gt;&lt;strong&gt;CSU&lt;/strong&gt;&lt;/a&gt;, Store Commerce App and e-commerce&lt;/li&gt;
&lt;li&gt;B2C and B2B Headless Commerce/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;B2C and B2B Commerce Platform/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;Customer Service operation based on D365 ERP and D365 CE data utilizing Commerce CSU&lt;/li&gt;
&lt;li&gt;Social Commerce/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;Professional App (React.JS)/D365 ERP integrations utilizing Commerce CSU&lt;/li&gt;
&lt;li&gt;POS/ERP integration&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Disclaimer&lt;/h2&gt;
&lt;p&gt;The content of this article represents my independent technical analysis and personal interpretation of publicly available software artefacts. It is not endorsed by, affiliated with, or authorised by Microsoft Corporation. Nothing in this article constitutes official Microsoft documentation, guidance, or product commitments.&lt;/p&gt;
&lt;p&gt;All findings are derived from analysis of the software and public documentation. Feature descriptions, presumable use cases, and &amp;quot;likely intent&amp;quot; assessments reflect my professional opinion based on observable code and API changes — they may not reflect Microsoft&amp;#39;s actual design intent, planned behaviour, or final implementation.&lt;/p&gt;
&lt;p&gt;Information regarding features described as preview, private preview, or roadmap items is subject to change at Microsoft&amp;#39;s sole discretion and should not be relied upon for planning, purchasing, or architectural decisions. This article describes the product as at the date of publication above.&lt;/p&gt;
&lt;p&gt;This article is provided for informational and educational purposes only, on an &amp;quot;as-is&amp;quot; basis without warranties of any kind, express or implied. The author assumes no liability for any direct, indirect, incidental, or consequential damages arising from the use of or reliance on the information contained herein.&lt;/p&gt;
&lt;p&gt;For authoritative product information, consult Microsoft&amp;#39;s official documentation at &lt;a href=&quot;https://learn.microsoft.com&quot;&gt;learn.microsoft.com&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>Commerce CSU</category></item><item><title>What is new: D365 Commerce CSU</title><link>https://patrickmouwen.com/blog/whats-new-d365-commerce-csu/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/whats-new-d365-commerce-csu/</guid><description>An unofficial what&apos;s-new for the D365 Commerce Cloud Scale Unit APIs, written because no official Microsoft release notes exist for them.</description><pubDate>Mon, 22 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;There are no official Microsoft Release Notes on the latest D365 Commerce (Retail) Cloud Scale Unit (CSU) APIs. Since more and more companies are starting to use these APIs for integrating external e-commerce websites with D365 ERP, I think the community may appreciate some &amp;#39;unofficial&amp;#39; Commerce CSU &amp;quot;WHAT&amp;#39;S NEW&amp;quot; 😎.&lt;/p&gt;
&lt;p&gt;Besides that, the &amp;#39;official&amp;#39; list of APIs is not really kept up-to-date &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/retail-server-customer-consumer-api&quot;&gt;here on Microsoft learn&lt;/a&gt;, so below you&amp;#39;ll find links to the latest API documentation, an up-to-date list of all APIs and what role they&amp;#39;re designed for (Customer = website, Employee/Device = store, Application = server-to-server).&lt;/p&gt;
&lt;h2&gt;Release notes | Latest version&lt;/h2&gt;
&lt;p&gt;The latest Commerce CSU version which is used for the Release notes here is:&lt;/p&gt;
&lt;p&gt;The version is compared with 9.49 (10.0.39).&lt;/p&gt;
&lt;h3&gt;Removed APIs&lt;/h3&gt;
&lt;p&gt;/Commerce/GetOrdersByStore&lt;/p&gt;
&lt;p&gt;/Commerce/GetPickUpOrdersByStore&lt;/p&gt;
&lt;h3&gt;New APIs&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/whats-new-d365-commerce-csu/1721657288264-0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note on Roles vs Use&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Anonymous/Customer/BusinessPartner = e-commerce&lt;/li&gt;
&lt;li&gt;Employee/Device = In-store&lt;/li&gt;
&lt;li&gt;Application = Server-to-Server&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As per this list, it becomes clear that Microsoft is investing to expose &lt;strong&gt;Copilot/ERP backend generated summary information through the CSU&lt;/strong&gt;. Unfortunately, this is currently only designed for use in-store (role = employee), but it should be possible to extend this.&lt;/p&gt;
&lt;h3&gt;Data Model changes&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/whats-new-d365-commerce-csu/1721658074325-1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The list above demonstrates investment in the following areas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Self checkout POS (in-store): &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/store-commerce-self-check-out&quot;&gt;more detail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Copilot Summaries: &lt;a href=&quot;https://www.youtube.com/watch?v=uJJjDW_cZAE&quot;&gt;more detail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;New search criteria for stock availability&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Relevant links&lt;/h2&gt;
&lt;p&gt;All Commerce APIs and roles (V9.50) in Excel: &lt;a href=&quot;/resources/commerce/V9.50-All-CSU-APIs-and-Roles.xlsx&quot;&gt;link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/whats-new-d365-commerce-csu/1721669348545-2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Full Commerce API documentation (V9.50): &lt;a href=&quot;/community-tools/&quot;&gt;link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/whats-new-d365-commerce-csu/1721669389845-3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;About the Author&lt;/h2&gt;
&lt;p&gt;I&amp;#39;ve been integrating non-Microsoft e-commerce solutions with D365 ERP and CRM since the early days of AX for Retail in 2009. Already back in 2015, I connected an E-commerce platform to D365 ERP by a &lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/&quot;&gt;&lt;strong&gt;predecessor of the current D365 Commerce CSU&lt;/strong&gt;&lt;/a&gt; for the first time.&lt;/p&gt;
&lt;p&gt;Get in touch via &lt;a href=&quot;/contact&quot;&gt;patrickmouwen.com/contact&lt;/a&gt; if you need help in implementing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://microsoft.com/en-us/dynamics-365/products/commerce&quot;&gt;&lt;strong&gt;D365 Commerce&lt;/strong&gt;&lt;/a&gt; on top of ERP including &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/store-commerce&quot;&gt;&lt;strong&gt;D365 Store Commerce App&lt;/strong&gt;&lt;/a&gt; and &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/b2b/set-up-b2b-site&quot;&gt;&lt;strong&gt;D365 e-commerce&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Customizing/Extending D365 Commerce, &lt;a href=&quot;https://www.microsoft.com/en-us/dynamics-365/products/commerce#tabs-pill-bar-oc81bf_tab5&quot;&gt;&lt;strong&gt;CSU&lt;/strong&gt;&lt;/a&gt;, Store Commerce App and e-commerce&lt;/li&gt;
&lt;li&gt;B2C and B2B Headless Commerce/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;B2C and B2B Commerce Platform/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;Customer Service operation based on D365 ERP and D365 CE data utilizing Commerce CSU&lt;/li&gt;
&lt;li&gt;Social Commerce/D365 ERP integrations via Commerce CSU&lt;/li&gt;
&lt;li&gt;Professional App (React.JS)/D365 ERP integrations utilizing Commerce CSU&lt;/li&gt;
&lt;li&gt;POS/ERP integration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Contact me on LinkedIn for more details: &lt;a href=&quot;https://www.linkedin.com/in/patrickmouwen/&quot;&gt;https://www.linkedin.com/in/patrickmouwen/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Disclaimer&lt;/h2&gt;
&lt;p&gt;The content of this article represents my independent technical analysis and personal interpretation of publicly available software artefacts. It is not endorsed by, affiliated with, or authorised by Microsoft Corporation. Nothing in this article constitutes official Microsoft documentation, guidance, or product commitments.&lt;/p&gt;
&lt;p&gt;All findings are derived from analysis of the software and public documentation. Feature descriptions, presumable use cases, and &amp;quot;likely intent&amp;quot; assessments reflect my professional opinion based on observable code and API changes — they may not reflect Microsoft&amp;#39;s actual design intent, planned behaviour, or final implementation.&lt;/p&gt;
&lt;p&gt;Information regarding features described as preview, private preview, or roadmap items is subject to change at Microsoft&amp;#39;s sole discretion and should not be relied upon for planning, purchasing, or architectural decisions. This article describes the product as at the date of publication above.&lt;/p&gt;
&lt;p&gt;This article is provided for informational and educational purposes only, on an &amp;quot;as-is&amp;quot; basis without warranties of any kind, express or implied. The author assumes no liability for any direct, indirect, incidental, or consequential damages arising from the use of or reliance on the information contained herein.&lt;/p&gt;
&lt;p&gt;For authoritative product information, consult Microsoft&amp;#39;s official documentation at &lt;a href=&quot;https://learn.microsoft.com&quot;&gt;learn.microsoft.com&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>Commerce</category></item><item><title>Reconciling Adyen vs D365 Payment Transactions</title><link>https://patrickmouwen.com/blog/reconciling-adyen-vs-d365-payment-transactions/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/reconciling-adyen-vs-d365-payment-transactions/</guid><description>Adyen and D365 each record evidence of the same payment. How to reconcile the two sides, and what to do when they disagree.</description><pubDate>Thu, 12 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;D365 F&amp;amp;O/Commerce offers an out-of-box &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/adyen-connector?tabs=10-0-31&quot;&gt;Adyen payment connector&lt;/a&gt; for use In-Store (“card present/card not present”), in Call centers or Online (“card not present”). When payments are physically captured through this connector, both ‘sides’ (Adyen and D365) capture ‘evidence’ for the physical transaction. In many situations it can be hepful to reconcile this ‘evidence’. For example, when a third-party e-commerce solution and &lt;a href=&quot;https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/store-commerce&quot;&gt;D365 Store Commerce App&lt;/a&gt; both go through an Adyen Merchant account, when payments have been captured offline (so by manually inputting an amount on the Adyen payment device) or simply to proof that all Payments and related Sales have made it into D365 F&amp;amp;O HQ.&lt;/p&gt;
&lt;p&gt;In this blog post I’ll describe how you can reconcile the Payment transactions between Adyen and D365 F&amp;amp;O.&lt;/p&gt;
&lt;p&gt;Read the full story here in my &lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:activity:7118231027935756288/&quot;&gt;Linkedin article&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/reconciling-adyen-vs-d365-payment-transactions/Reconciliation-1.png&quot;&gt;&lt;img src=&quot;/images/blog/reconciling-adyen-vs-d365-payment-transactions/Reconciliation-1-1024x593.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>Functional</category></item><item><title>D365 Commerce + IOM = SUPERPOWER!</title><link>https://patrickmouwen.com/blog/d365-commerce-iom-superpower/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/d365-commerce-iom-superpower/</guid><description>A recorded demonstration of D365 Commerce and Intelligent Order Management working together across one integrated order scenario.</description><pubDate>Fri, 29 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;div style=&quot;position:relative;padding-bottom:56.25%;height:0;overflow:hidden;margin:6px 0 28px;border-radius:12px;border:1px solid #D5DEE8&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/bEuNQkt2qjM?start=527&quot; title=&quot;D365 Commerce + IOM = SUPERPOWER!&quot; loading=&quot;lazy&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen style=&quot;position:absolute;top:0;left:0;width:100%;height:100%;border:0&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;Microsoft Intelligent Order Management (IOM) is a powerful solution for effectively orchestrating Order Fulfillment scenarios.&lt;/p&gt;
&lt;p&gt;D365 Commerce is D365 Finance &amp;amp; Operations plus the Headless commerce engine with more than 400+ Commerce APIs and a local database which is installed on a separate Retail Cloud Scale Unit.&lt;/p&gt;
&lt;p&gt;The combination of IOM + D365 Commerce offers next level capabilities for any Retail Enterprise 🚀.&lt;/p&gt;
&lt;p&gt;In below video I’ll demonstrate an integrated scenario in which Orders from an E-commerce platform are orchestrated in IOM and fulfilled via D365 Commerce.&lt;/p&gt;
</content:encoded><category>Functional</category></item><item><title>Why I am a fan of a Single Company setup for Retailers in D365 F&amp;O</title><link>https://patrickmouwen.com/blog/why-i-am-a-fan-of-a-single-company-setup-for-retailers-in-d365-fo/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/why-i-am-a-fan-of-a-single-company-setup-for-retailers-in-d365-fo/</guid><description>Why a single-company setup in D365 F&amp;O suits retailers: brand experience should not be interrupted by legal entity boundaries.</description><pubDate>Fri, 29 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Implementing D365 F&amp;amp;O requires some specific Design considerations when it comes to Retail organizations. A Retail company is not simply organized by Legal entities which transact with each other and 3rd parties. A Retailer has one or more brands to protect. Consumers expect the same brand experience anywhere anytime. This experience cannot have interference from legal entity boundaries or the way an ERP system is configured.&lt;/p&gt;
&lt;p&gt;Too often, I see D365 F&amp;amp;O Solution Architects and Consultants automatically translate a Retailer&amp;#39;s subsidiaries to companies in D365 F&amp;amp;O. Even if this does not align with the way the Retailer is organized (central backoffices) and/or their logistics model is setup (hub and spoke). But first and foremost, it can shatter Supply Chain and Order fulfillment into pieces and significantly raise operational complexity and overhead with detrimental impact on the Customer Journey..&lt;/p&gt;
&lt;p&gt;Is there an alternative???&lt;/p&gt;
&lt;h2&gt;The Retailer&amp;#39;s dilemma: Vertical walls vs Horizontal freedom&lt;/h2&gt;
&lt;p&gt;Retail organisations reduce financial risk by slicing their operation into legal entities organized by brand, specific activities and/or jurisdiction. In doing so, If any of the activities are underperforming potentially causing a bankruptcy, it can never bring down the complete enterprise.&lt;/p&gt;
&lt;p&gt;At the same time, Retail companies require boundless operation to effectively manage their supply chain from Purchasing to Retail and to provide a consistent high-quality experience to their consumers, regardless of brand, country or specific store.&lt;/p&gt;
&lt;p&gt;These 2 powers of ‘vertical structure’ vs ‘horizontal freedom’ brings a field of tension in typical cross-border Retail Businesses which is most prevalent in Retail Businesses with brick-and-mortar (stores) and/or service activities.&lt;/p&gt;
&lt;p&gt;When defining the Financial setup in D365 F&amp;amp;O for these Retail companies, most Dynamics partners translate the company structure 1:1 based on classical in-operation intercompany postings (1# in the picture below) and then try to make the best out of the ‘horizontal freedom’ dimension (#2 in the picture below).&lt;/p&gt;
&lt;!-- IMAGE vertical-vs-horizontal MISSING — was on media.licdn.com (expired). Recover from the LinkedIn article, save as /images/blog/why-i-am-a-fan-of-a-single-company-setup-for-retailers-in-d365-fo/vertical-vs-horizontal.png, then replace this comment with:  ![Vertical structure vs horizontal freedom](/images/blog/why-i-am-a-fan-of-a-single-company-setup-for-retailers-in-d365-fo/vertical-vs-horizontal.png) --&gt;&lt;p&gt;It is perfectly understandable to choose this path since any Solution must be legally and fiscally compliant. However, this comes with a price as it shatters the Supply chain and Order Fulfillment into pieces. Stitching these together to enable effective management of the Supply chain and seamless Customer journey is complex and costly.&lt;/p&gt;
&lt;h2&gt;Shattering Order Fulfillment into pieces?&lt;/h2&gt;
&lt;p&gt;Retail companies are often legally organised along the following lines:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Holding company: often stock holding company, so responsible for buying and stock (re)distribution - Sometimes e-commerce activities are also operated from this company&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Brand holding: parent company for all brand specific activity&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Selling company per brand/country: this company holds all sales activities like store sales, online sales&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Service company per brand/country: this company holds all field service activities like on-site advisory, installations, repairs etc.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Often this legal entity structure (or similar structure) is translated into a &amp;#39;classic&amp;#39; Intercompany structure in D365 F&amp;amp;O. In other words: each Legal Entity is reflected by a company in D365 F&amp;amp;O and every transaction between these companies is reflected by an additional Intercompany Sales Order/Purchase order pair (=IC PO/SO). Relatively straightforward Business processes can then suddenly become utterly complex to manage.&lt;/p&gt;
&lt;!-- IMAGE example-business-process MISSING — was on media.licdn.com (expired). Recover from the LinkedIn article, save as /images/blog/why-i-am-a-fan-of-a-single-company-setup-for-retailers-in-d365-fo/example-business-process.png, then replace this comment with:  ![Example Retail Business Process](/images/blog/why-i-am-a-fan-of-a-single-company-setup-for-retailers-in-d365-fo/example-business-process.png) --&gt;&lt;p&gt;&lt;em&gt;Example Retail Business Process.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this example, a consumer places an in-store order for a Make-To-Order item (such as a bespoke closet or suit). The item is to be purchased from a supplier and then shipped to the consumer, in this case by cross docking via a main warehouse.&lt;/p&gt;
&lt;p&gt;D365 F&amp;amp;O (including Commerce) is not too strong when it comes to managing more complex Fulfillment journeys. For these cases I would definitely recommend D365 Commerce/F&amp;amp;O to Team up with D365 Intelligent Order Management (=OMS). See for example my video on the combination of IOM and D365 Commerce. With a &amp;quot;classic&amp;quot; intercompany setup, the Fulfillment journey is even more complicated due to the additional ICO SO/PO pairs.&lt;/p&gt;
&lt;p&gt;In this example, not 1 SO (Sales Order) with related PO (Purchase order) and TO (Transfer Order) is to be managed, but 3  SOs, 3 POs and 1 TO. And there are more complexities like the fact that stock is only available in Legal Entity 2 (the main holding) where we&amp;#39;d like to reserve stock from the main Sales order in Legal Entity 1. Even if D365 Intelligent Order Management (IOM) would be used here, IOM would have to manage and monitor multiple &amp;#39;overhead&amp;#39; intercompany documents. This compromises &amp;quot;Keeping the Promise&amp;quot; which raises complexity in OMS implementation and OMS operation.&lt;/p&gt;
&lt;p&gt;Beyond all this impact on the Fulfillment journey, there are more considerations which urge to look for an alternative set up. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Rapid D365 F&amp;amp;O DB growth by ICO transactions. Customers now pay for this DB footprint!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Impact on Customer journey: Only Legal Entity 1 in the example is aware of the Consumer - The consumer does not exist and is not known in Legal Entity 2 or 3.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Customisations for IC processes. Some fundamental requirements for effective Order Fulfillment and Order Management are not compatible in a D365 F&amp;amp;O intercompany context. These will require (heavy) customisations in D365 F&amp;amp;O increasing implementation risk and Project implementation cost.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Organizational alignment: Retail organizations often have a central Backoffice per group of countries (=Region). These backoffices have to manage pieces of the Fulfillment chain across multiple D365F&amp;amp;O companies which is not ideal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Margin: in an Intercompany Setup, margin components (like landed cost, shipping cost and fulfillment cost in general) are not sitting in 1 D365 F&amp;amp;O company. Of course, this can be stitched together in (for example) the BI domain, but some stakeholders prefer to see all cost components in their financial records.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can probably come up with more downsides yourself!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Finding an Alternative Setup in D365 F&amp;amp;O&lt;/h2&gt;
&lt;p&gt;First let&amp;#39;s set a goal.. In the ideal world, we&amp;#39;d keep things as SIMPLE as possible. For a Retailer this would mean an all-in-one company setup in D365 F&amp;amp;O which hosts their Full Operation, from buying to order fulfillment. It would also mean to have no in-operation intercompany transactions, but post-operation intercompany postings, aggregated as per desired level (i.e. transactions condensed daily, monthly or quarterly).&lt;/p&gt;
&lt;p&gt;But how is this possible while still addressing all specific Financial Requirements the enterprise may have AND being fully compliant with legal and fiscal regulations...?&lt;/p&gt;
&lt;p&gt;Lets keep some typical Financial, Legal and Fiscal requirements in mind when trying to find an alternative for the &amp;quot;classic&amp;quot; intercompany setup:&lt;/p&gt;
&lt;!-- IMAGE financial-legal-fiscal-requirements MISSING — was on media.licdn.com (expired). Recover from the LinkedIn article, save as /images/blog/why-i-am-a-fan-of-a-single-company-setup-for-retailers-in-d365-fo/financial-legal-fiscal-requirements.png, then replace this comment with:  ![Typical Financial, Legal and Fiscal requirements](/images/blog/why-i-am-a-fan-of-a-single-company-setup-for-retailers-in-d365-fo/financial-legal-fiscal-requirements.png) --&gt;&lt;p&gt;&lt;em&gt;Typical Financial, Legal and Fiscal requirements.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;The D365 F&amp;amp;O Single &amp;quot;OPCO&amp;quot; (Operating Company)&lt;/h2&gt;
&lt;p&gt;My best shot to realise the Single company goal and being compliant with Financial, Legal and Financial requirements is the so called &amp;quot;OPCO&amp;quot; (Operating Company) concept.&lt;/p&gt;
&lt;p&gt;In this company all &amp;#39;normal&amp;#39; legal entities are reflected by D365 F&amp;amp;O companies, but they do not have direct intercompany relationships. Instead, the full Retail Operation is happening in the OPCO, a company in D365 F&amp;amp;O which does not represent a real-life Legal Entity.&lt;/p&gt;
&lt;p&gt;Characteristics of the OPCO&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Financial Dimension Values. All transactions in the OPCO are stamped with Financial dimension values which at least represent Brand, Cost center and Legal Entity. Non-D365 Commerce consultants may be surprised by the D365 Commerce out-of-box capability to allow inheritance of  financial dimension values from Retail channel to Sales order/Sales order line. This auto-stamps the right Brand and Legal Entity for any Sale. Knowing these details on any Transaction will also allow to print a Brand and even Channel specific invoice and receipt if required. Since this information baseline provides full traceability and accountability, there is a solid fiscal and legal foundation for invoicing the consumer from the OPCO.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Statutory Reporting. Intrastat, VAT declaration, EU Sales list and other statutory reporting are directly created from the OPCO. The 2022 introduced functionality to report for multiple VAT registrations from 1 company is utilized for this - This is now supported for many European countries. See Microsoft Learning.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Intercompany transactions. IC Transactions are posted POST-Operation from OPCO to the actual Legal Entities. This is done by setting up Intercompany Accounting and Ledger allocations which automatically offset post OPCO financial transactions to the actual Legal Entity by main account/financial dimension rules. So for example, financial postings on OPCO revenue accounts can be broken out to various postings to the ledgers of the actual legal entity, so  a P&amp;amp;L can be viewed from that Legal Entity.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OPCO = Stock holding company. Optionally the OPCO is the Stock holding company itself, so all companies in D365 F&amp;amp;O align with real-life Legal Entities.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multi-currency. The OPCO can cover jurisdictions with different primary currencies. D365 F&amp;amp;O is dual-currency system since a few years now, so this should also not be a deal breaker if the number of primary currencies does not exceed 2.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Challenges&lt;/h2&gt;
&lt;p&gt;The Single Company/&amp;quot;OPCO&amp;quot; concept is often quickly wiped off the table by hardened D365 F&amp;amp;O Consultants and Solution Architects. This is often because they have done their intercompany transaction routine for so many years that they do not even consider other options. In other cases, it&amp;#39;s because they don&amp;#39;t know how to overcome the following 2 most-heard obstacles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Localization. The DataAreaId (=company identifier) in D365 F&amp;amp;O is not only used in tables, to slice Data into Legal Entity specific buckets or shared buckets. The Legal Entity is also used to trigger locale (=jurisdiction) specific code. In most cases, this code is triggered for groups of countries which have similar legal context, such as the following regions: BeNeLux, DACH, Scandinavia, Ireland/GB and Eastern Europe. My rule of thumb is to have 1 OPCO for each of these regions. This also aligns with the Retailer&amp;#39;s organization and Logistics model in most cases: when a Retailer operates in BeNeLux (Belgium-Netherlands-Luxemburg) and expands brick-and-mortar (store operation) into DACH (Germany-Austria-Switzerland), often a new local (DACH) organization and logistics hub is set up for that region:&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- IMAGE regional-opco-model MISSING — was on media.licdn.com (expired). Recover from the LinkedIn article, save as /images/blog/why-i-am-a-fan-of-a-single-company-setup-for-retailers-in-d365-fo/regional-opco-model.png, then replace this comment with:  ![One OPCO per region](/images/blog/why-i-am-a-fan-of-a-single-company-setup-for-retailers-in-d365-fo/regional-opco-model.png) --&gt;&lt;ul&gt;
&lt;li&gt;Subledger traceability. Especially financial auditors and controllers have the requirement to be able to click from the Legal Entity&amp;#39;s General ledger to the OPCO&amp;#39;s General ledger and Subledger. If the OPCO&amp;gt;Legal Entity intercompany accounting postings are condensed, this cannot be arranged on a 1:1 transactional basis. In that case, click-through capability is to be arranged by (minor) customization, for example by clicking from a single non-OPCO General ledger entry into multiple OPCO subledger transaction.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Final words&lt;/h2&gt;
&lt;p&gt;Every Solution Design choice should always be made in the specific context of an Enterprise. On top of that, a Project stakeholder will always be able to find a weak point in any Design Decision. But in our profession as an IT Architect it should not be the aim to pick the best option in a specific domain. The aim is to pick the best option Cross-Domain, where the overall score/value of the Solution as a whole is the highest possible.&lt;/p&gt;
&lt;p&gt;I hope this post inspired you to look beyond &amp;#39;proven Design paths&amp;#39; which may not represent the best Overall score.&lt;/p&gt;
&lt;p&gt;In case of Retail organizations, the decision for a Single company setup or small group of OPCOs instead of 20+ or even 100+ companies in D365 F&amp;amp;O is more than fundamental: it can be the difference between a highly successful Transformation Program and a Program which technically succeeds but is considered a pain in the a** by the Retail Operation!&lt;/p&gt;
</content:encoded><category>Functional</category></item><item><title>D365 F&amp;O/Commerce interfacing via Azure API Management: My Best Practices</title><link>https://patrickmouwen.com/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/</guid><description>Best practices for putting Azure API Management in front of D365 F&amp;O OData and Commerce Scale Unit interfacing — and when it earns its place.</description><pubDate>Mon, 28 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I am seeing more and more customers and partners who actively promote the use of Azure API Management for D365 F&amp;amp;O backend and/or D365 Commerce Scale Unit OData interfacing. See for example, this &lt;a href=&quot;https://ariste.info/en/2022/02/azure-api-management-dynamics-365-fo/&quot;&gt;blog post by Adrià Ariste Santacreu&lt;/a&gt;. However, there’s still a significant number of customers and partners who shrug their shoulders while thinking: “Why would we use it when we can interface ‘directly’?”. In this blog post I’ll address this question by sharing my best personal best practices in using Azure API Management for D365 F&amp;amp;O backend and/or D365 Commerce Scale Unit OData interfacing. But before sharing the best practices, we first have to explode the myth that interfacing via Azure API Management (APIM) would not be DIRECT.. 😉.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;1 –&lt;/strong&gt; The role of Azure API Management in D365 F&amp;amp;O interfacing&lt;/h2&gt;
&lt;p&gt;Imagine a car which is driving from A to B every day. In order to keep it on the road it’s needs to be fueled, maintained and cleaned. When this handling is done, the car is grounded and cannot move from A to B. How cool would it be if the car could drive through an advanced car wash where the fueling, maintenance and cleaning could be done while keeping it’s pace and direction on its way to B. This is actually what Azure API Management (&lt;strong&gt;APIM&lt;/strong&gt;) is about: consider APIM as a &lt;strong&gt;gateway&lt;/strong&gt; (a &lt;strong&gt;tunnel&lt;/strong&gt; – see Figure 1 below) which interface requests are routed through on their way to a backend system.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-7.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-7-1024x521.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 1&lt;/strong&gt;: Client to D365 F&amp;amp;O traffic going through the APIM tunnel&lt;br&gt;Source: &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/api-management/api-management-key-concepts&quot;&gt;Microsoft Docs&lt;/a&gt; (edited)&lt;/p&gt;
&lt;p&gt;While passing through the APIM &lt;strong&gt;gateway&lt;/strong&gt;, ‘Value Added Services’ are applied to the ‘vehicle’ (=the request). These ‘VAS’ hardly slow down the vehicle, often only by about 25-100ms. These ‘VAS’ are the policies which are applied to either the incoming request, request to the backend (the 2nd part of the tunnel) and/or the equivalent responses which are routed through the same tunnel. So is the call from the client to D365 F&amp;amp;O still &lt;strong&gt;DIRECT&lt;/strong&gt;? I’d say &lt;strong&gt;YES&lt;/strong&gt;.. its only running through a tunnel of ‘VAS’… 😉.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;2 –&lt;/strong&gt; Why using APIM with D365 F&amp;amp;O?&lt;/h2&gt;
&lt;p&gt;For many reasons.. Let’s start by taking a few basic principles of interfacing: first &lt;strong&gt;Authentication&lt;/strong&gt;. Clients which interact with D365 F&amp;amp;O can be very different in nature. Often it’s a non-Microsoft system backed by a partner who is not used to Microsoft platform standards. Take for example an e-commerce system and partner. It sounds strange to many but I’ve met a significant number of partners who are only used to interface with API Keys and Certificates and had never implemented oAuth 2.0 authentication before. D365 F&amp;amp;O would force them into oAuth 2.0 authentication which may take longer than usual for them to adopt. With APIM, APIM can take care of the authentication to D365 F&amp;amp;O, independent from the Client to APIM authentication.&lt;/p&gt;
&lt;p&gt;Another example is &lt;strong&gt;Error handling&lt;/strong&gt;.. Imagine if 20 different systems interact with D365 F&amp;amp;O where each of them has their own standard in error handling. We want STANDARDISATION and CENTRALISATION of error handling. We don’t want system A sending us e-mails when interaction with D365 F&amp;amp;O runs into an issue, system B offering an error on a management portal and system C not even surfacing an error (we have to find out in D365 F&amp;amp;O that we’re missing data..). With APIM, we can configure APIM to report errors to &lt;strong&gt;Azure App Insights&lt;/strong&gt; which can source as a baseline for centralised error management.&lt;/p&gt;
&lt;p&gt;My last example is &lt;strong&gt;API documentation&lt;/strong&gt;. As we all know, neither the &lt;strong&gt;D365 F&amp;amp;O backend OData&lt;/strong&gt; end points nor the &lt;strong&gt;D365 Commerce Retail Server OData&lt;/strong&gt; end points are OpenAPI or Swagger documented. When we configure APIs with their Operations in APIM, we can include all properties of the APIs including sample requests and all possible status code/response body pairs:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-8.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-8-1024x541.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure 2&lt;/strong&gt;: Azure API Management: define possible Status codes and Responses&lt;/p&gt;
&lt;p&gt;These properties are automatically published to a Developer portal with all information about our APIs. We can empower IT Partners and other stakeholders to become self-sufficient in consuming our APIs by allowing them access to the portal information for some or all APIs we’ve technically documented in APIM:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-14.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-14-1024x565.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the next section I’ll share my personal best practices. I’ll already tell you this: you’ll be able to distill a lot of benefits for use in D365 F&amp;amp;O/D365 Commerce Scale Unit interface scenarios from them.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;3 –&lt;/strong&gt; My best practices in using APIM for D365 F&amp;amp;O and D365 Commerce Scale Unit integrations&lt;/h2&gt;
&lt;p&gt;There are many things to share in regards to APIM specific best practices. Below categorisation is narrowed down to my personal best practices in using APIM for &lt;strong&gt;D365 F&amp;amp;O&lt;/strong&gt; and &lt;strong&gt;Commerce OData&lt;/strong&gt; endpoint integrations specifically:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#anchor-abstraction&quot;&gt;A&lt;strong&gt;bstraction&lt;/strong&gt;&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;Backend system&lt;/li&gt;
&lt;li&gt;Environment&lt;/li&gt;
&lt;li&gt;Template parameters&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#anchor-security&quot;&gt;Security&lt;/a&gt;&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Template parameters&lt;/li&gt;
&lt;li&gt;Strip query parameters&lt;/li&gt;
&lt;li&gt;Mask backend URL&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#anchor-authentication&quot;&gt;Authentication&lt;/a&gt;&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Decouple client to APIM vs APIM to backend authentication&lt;/li&gt;
&lt;li&gt;Auto rotate, cache and re-use oAuth2.0 bearer tokens&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#anchor-performance&quot;&gt;Performance&lt;/a&gt;&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Retry policy&lt;/li&gt;
&lt;li&gt;Caching&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#anchor-flexibility&quot;&gt;Flexibility&lt;/a&gt;&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Re-pointing clients to another D365 environment in under 10 seconds&lt;/li&gt;
&lt;li&gt;Using APIM end points as opposed to the D365 F&amp;amp;O connector in Power Automate or Power Apps&lt;/li&gt;
&lt;li&gt;API Versioning&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#anchor-apidocumentation&quot;&gt;API Documentation&lt;/a&gt;&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Developer portal&lt;/li&gt;
&lt;li&gt;Documentation in Power Automate – Logic Apps – Power Apps&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;3.1 – Abstraction&lt;/h3&gt;
&lt;p&gt;Azure API Management acts as a facade, a shell, for your system end points – If implemented well, this shell actually turns your technical &lt;strong&gt;end points&lt;/strong&gt; into organizational &lt;strong&gt;Services&lt;/strong&gt; which can easily be consumed by internal users, internal applications and partner applications. This is achieved as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;External clients can become system agnostic:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Clients no longer have to bother &lt;em&gt;which Application&lt;/em&gt; a particular function originates from. Instead, the clients can directly start to consume the functions. In other words: it allows a Service Oriented Architecture (SOA).&lt;/li&gt;
&lt;li&gt;In the case of D365 F&amp;amp;O and Commerce, APIs can be exposed as &lt;strong&gt;Services&lt;/strong&gt; which can easily be consumed by any App, Power Automate Flow or Backend system. These Services can be organized as per organizational standards similar to defining a custom namespace in a .NET library:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-1024x557.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;External clients can become system agnostic&lt;/strong&gt; (&lt;em&gt;continued&lt;/em&gt;)&lt;ul&gt;
&lt;li&gt;When organising your end points as &lt;strong&gt;Services&lt;/strong&gt;, the backend system becomes irrelevant. You could replace the endpoint by an updated endpoint or endpoint from another system and your client wouldn’t even notice it. So from client perspective a D365 specific &lt;strong&gt;GET&lt;/strong&gt; &lt;strong&gt;{D365 environment}/data/CustomerPostalAddresses&lt;/strong&gt; call is replaced by a generic &lt;strong&gt;GET {customername}.azure-api.net/customers/getcustomeraddresses&lt;/strong&gt;. For D365 F&amp;amp;O, this can be achieved by implementing below redirect policy on the particular API &lt;strong&gt;Operation&lt;/strong&gt; in APIM:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Policy&lt;/strong&gt;: set backend URL suffix&lt;/p&gt;
&lt;p&gt;API &amp;gt; Specific Operation &amp;gt; Inbound -&amp;gt; rewrite-uri&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;inbound&amp;gt;
        &amp;lt;base /&amp;gt;
        &amp;lt;rewrite-uri template=&amp;quot;/CustomerPostalAddresses?$filter=CustomerAccountNumber eq &amp;amp;apos;{CustomerAccount}&amp;amp;apos; and dataAreaId eq &amp;amp;apos;{Company}&amp;amp;apos;&amp;amp;amp;cross-company=true&amp;quot; copy-unmatched-params=&amp;quot;false&amp;quot; /&amp;gt;
&amp;lt;/inbound&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;External clients can become environment agnostic:&lt;/strong&gt; clients no longer have to bother &lt;em&gt;where&lt;/em&gt; a particular function comes from. Instead, the clients can directly start to consume the functions. Client requests can be re-directed to another environment by an APIM config change in seconds.&lt;ul&gt;
&lt;li&gt;This can be achieved by configuring a &lt;strong&gt;Named Value&lt;/strong&gt; in APIM in conjunction with a Policy – In this case I put the policy on the API’s &lt;strong&gt;All Operations&lt;/strong&gt; so it applies for all Operations for a particular API (here: D365 F&amp;amp;O entity &lt;strong&gt;Customers&lt;/strong&gt;):&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Named Value&lt;/strong&gt;: D365 F&amp;amp;O backend URL or D365 Retail Server URL&lt;/p&gt;
&lt;p&gt;APIM &amp;gt; APIs &amp;gt; Named Values&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-1.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-1.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Policy:&lt;/strong&gt; set backend base URL&lt;/p&gt;
&lt;p&gt;API &amp;gt; All operations &amp;gt; Inbound -&amp;gt; set-backend-service base-url&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;policies&amp;gt;
&amp;lt;inbound&amp;gt;
	&amp;lt;base/&amp;gt;
	&amp;lt;set-backend-service base-url=&amp;quot;{{D365OPSEnvironment}}/data&amp;quot;/&amp;gt;
&amp;lt;/inbound&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;strong&gt;Requests and request parameters can be simplified&lt;/strong&gt;. For example, when searching for a customer address in D365 F&amp;amp;O, an OData call can become very complex when searching by multiple columns. In APIM, the most common searches can be standardised by defining multiple API operations which offer different sets of criteria. For example:&lt;ul&gt;
&lt;li&gt;API Operation 1: getaddresses -&amp;gt; Allows searching by street, city and zip code&lt;/li&gt;
&lt;li&gt;API Operation 2: getcustomeraddresses -&amp;gt; Allows searching by customer account&lt;/li&gt;
&lt;li&gt;Each specific Operation offers specific search options (APIM: &lt;strong&gt;Template parameters&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;The formatting of these search options can be simplified for the user, for example:&lt;ul&gt;
&lt;li&gt;D365 F&amp;amp;O request:&lt;br&gt;/CustomerPostalAddresses?&lt;strong&gt;$filter=CustomerAccountNumber%20eq%20’CUST0155148’%20and%20AddressLocationRoles%20eq%20’*Delivery*’&amp;amp;cross-company=true&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Same request to D365 F&amp;amp;O via APIM:&lt;br&gt;/customers/getcustomeraddresses**?customeraccount=CUST0155148&amp;amp;company=CMP**&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This can be achieved by defining the respective Template Parameters on the API Operation in conjunction with the Rewrite URL policy as presented under point 2 above:&lt;ul&gt;
&lt;li&gt;Having these template parameters defined is also handy when using the &lt;strong&gt;Test&lt;/strong&gt; feature in APIM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-2.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-2-1024x597.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;3.2 – Security&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Template Parameters + Strip off any additional parameters&lt;/strong&gt;: the use of Template Parameters as shown under 3.1 point 4 is a strong security measure when combined with a policy to strip off any additional query parameters – For example, if a GET type of API Operation is defined to only allow searching for Customer addresses by Customer account, APIM will not forward criteria which would not comply with this even if the respective backend system like D365 F&amp;amp;O supports it (e.g. Customer name). In doing so, only clients which are aware of actual Account number can fire a search request. A hacker firing calls by potential Customer names will not even be forwarded to the backend as such.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Policy&lt;/strong&gt;: Strip off Query parameters&lt;/p&gt;
&lt;p&gt;API operation &amp;gt; Inbound &amp;gt; Rewrite-URI Policy -&amp;gt; copy-unmatched-parms=false&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;policies&amp;gt;
    &amp;lt;inbound&amp;gt;
        &amp;lt;base /&amp;gt;
        &amp;lt;rewrite-uri template=&amp;quot;/CustomerPostalAddresses?$filter=CustomerAccountNumber eq &amp;amp;apos;{CustomerAccount}&amp;amp;apos; and dataAreaId eq &amp;amp;apos;{Company}&amp;amp;apos;&amp;amp;amp;cross-company=true&amp;quot; copy-unmatched-params=&amp;quot;false&amp;quot; /&amp;gt;
    &amp;lt;/inbound&amp;gt;
    &amp;lt;backend&amp;gt;
        &amp;lt;base /&amp;gt;
    &amp;lt;/backend&amp;gt;
    &amp;lt;outbound&amp;gt;
        &amp;lt;base /&amp;gt;
    &amp;lt;/outbound&amp;gt;
    &amp;lt;on-error&amp;gt;
        &amp;lt;base /&amp;gt;
    &amp;lt;/on-error&amp;gt;
&amp;lt;/policies&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Mask backend URL&lt;/strong&gt;: when a call is fired to D365 F&amp;amp;O and Commerce, both return the URL of D365 F&amp;amp;O and the Retail server in the response. For security reasons, we don’t want the base URL to be exposed to the client as this might enable a malicious client to fire a request to the backend directly. With the following policy any base URL in the response is replaced by the &lt;strong&gt;APIM base URL&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Policy&lt;/strong&gt;: mask backend URL&lt;/p&gt;
&lt;p&gt;API &amp;gt; All operations &amp;gt; Outbound -&amp;gt; redirect-content-urls&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;outbound&amp;gt;
	&amp;lt;base /&amp;gt;
	&amp;lt;redirect-content-urls /&amp;gt;
&amp;lt;/outbound&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when D365 F&amp;amp;O or Retail Server return a response, the respective backend URL is replaced by the &lt;strong&gt;APIM base URL&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
	&amp;quot;@odata.context&amp;quot;: &amp;quot;https://myAPIM.azure-api.net/Customers/$metadata#CustomerPostalAddresses&amp;quot;,
	&amp;quot;value&amp;quot;: [
		{
			&amp;quot;@odata.etag&amp;quot;: &amp;quot;W/\&amp;quot;JzEsNTYzNzgwNjA3Nic=\&amp;quot;&amp;quot;,
			&amp;quot;dataAreaId&amp;quot;: &amp;quot;COMP&amp;quot;,
			&amp;quot;CustomerAccountNumber&amp;quot;: &amp;quot;CUST0155148&amp;quot;,
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.3 – Authentication&lt;/h3&gt;
&lt;p&gt;APIM can take care of the authentication to the backend system. This has a couple of benefits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Security:&lt;/strong&gt; sensitive security information is not distributed outside Azure:&lt;ul&gt;
&lt;li&gt;Decoupling &lt;strong&gt;Client to APIM&lt;/strong&gt; and &lt;strong&gt;APIM to Backend&lt;/strong&gt; authentication saves you from having to distribute sensitive information like a Client ID/Passphrase to a client application.&lt;/li&gt;
&lt;li&gt;It is even possible to setup oAuth 2.0 (Client ID/Passphrase) to APIM and separate oAuth 2.0 (Client ID/Passphrase) from APIM to D365 F&amp;amp;O or Commerce Cloud Scale Unit – In this way the access to D365 resources via APIM can be authenticated differently per client. Vice versa, a client can have 1 identity/login for all resources (D365 and non-D365) in your tenant. In other words: a client could login to all relevant resources on your tenant by a single APP ID/Passphrase even though one or more backend systems would not support oAuth 2.0 (!).&lt;/li&gt;
&lt;li&gt;In case a client connects to APIM via API-Key, the API-Key in the request can be stripped off to not come through to the backend system. This ensures the API-Key cannot be intercepted beyond APIM and then be re-used in a new client request:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Policy&lt;/strong&gt;: strip API-Key header off request to backend&lt;/p&gt;
&lt;p&gt;API &amp;gt; All operations &amp;gt; Inbound -&amp;gt; set-header -&amp;gt; “delete”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;inbound&amp;gt;
        &amp;lt;base /&amp;gt;
        &amp;lt;set-header name=&amp;quot;API-Key&amp;quot; exists-action=&amp;quot;delete&amp;quot; /&amp;gt;
    &amp;lt;/inbound&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Background rotation, caching and rotation of oAuth2.0 bearer token:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;When APIM is used to authenticate to the D365 backend or D365 Commerce Cloud Scale Unit independent from client authentication, the token for accessing the backend can be cached and auto rotated for faster response times.&lt;/li&gt;
&lt;li&gt;This can be achieved by a combination of a parameter for &lt;strong&gt;Token life time&lt;/strong&gt; and inbound policy&lt;/li&gt;
&lt;li&gt;Note: the bearer token is always specific for a resource – Hence, my best practice is to save the token into cache by &lt;strong&gt;Environment name&lt;/strong&gt; – In doing so, the token is automatically refreshed when APIM is redirected to another D365 environment&lt;/li&gt;
&lt;li&gt;Note 2: I often save the Client ID and secret in &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/key-vault/&quot;&gt;&lt;strong&gt;Azure Key vault&lt;/strong&gt;&lt;/a&gt; and use that reference in the respective Named value (see column Key vault name below)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Named Value:&lt;/strong&gt; Client ID – Secret – Environment – Environment name -Token life time&lt;/p&gt;
&lt;p&gt;APIM &amp;gt; APIs &amp;gt; Named Values -&amp;gt; Token life time setting 20 minutes = 1200 seconds&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-4.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-4.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Policy&lt;/strong&gt;: fetch oAuth2.0 token, cache and re-use&lt;/p&gt;
&lt;p&gt;API &amp;gt; All operations &amp;gt; Inbound -&amp;gt;&lt;br&gt;send-request&lt;br&gt;set-header&lt;br&gt;cache-store-value&lt;br&gt;cache-lookup-value&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;inbound&amp;gt;
        &amp;lt;base /&amp;gt;
        
        &amp;lt;cache-lookup-value key=&amp;quot;{{D365OpsEnvironmentName}}-token-{{ClientId}}&amp;quot; variable-name=&amp;quot;bearerToken&amp;quot; /&amp;gt;
        &amp;lt;choose&amp;gt;
            
            &amp;lt;when condition=&amp;quot;@(!context.Variables.ContainsKey(&amp;quot;bearerToken&amp;quot;))&amp;quot;&amp;gt;
                &amp;lt;send-request mode=&amp;quot;new&amp;quot; response-variable-name=&amp;quot;oauthResponse&amp;quot; timeout=&amp;quot;20&amp;quot; ignore-error=&amp;quot;false&amp;quot;&amp;gt;
                    &amp;lt;set-url&amp;gt;{{AuthorizationServer}}&amp;lt;/set-url&amp;gt;
                    &amp;lt;set-method&amp;gt;POST&amp;lt;/set-method&amp;gt;
                    &amp;lt;set-header name=&amp;quot;Content-Type&amp;quot; exists-action=&amp;quot;override&amp;quot;&amp;gt;
                        &amp;lt;value&amp;gt;application/x-www-form-urlencoded&amp;lt;/value&amp;gt;
                    &amp;lt;/set-header&amp;gt;
                    &amp;lt;set-body&amp;gt;@(&amp;quot;grant_type=client_credentials&amp;amp;client_id={{ClientId}}&amp;amp;client_secret={{ClientSecret}}&amp;amp;resource={{D365OPSEnvironment}}&amp;quot;)&amp;lt;/set-body&amp;gt;
                &amp;lt;/send-request&amp;gt;
                
                &amp;lt;set-variable name=&amp;quot;accessToken&amp;quot; value=&amp;quot;@((string)((IResponse)context.Variables[&amp;quot;oauthResponse&amp;quot;]).Body.As&amp;lt;JObject&amp;gt;()[&amp;quot;access_token&amp;quot;])&amp;quot; /&amp;gt;
                &amp;lt;cache-store-value key=&amp;quot;{{D365OpsEnvironmentName}}-token-{{ClientId}}&amp;quot; value=&amp;quot;@((string)context.Variables[&amp;quot;accessToken&amp;quot;])&amp;quot; duration=&amp;quot;{{TokenLifeTimeSeconds}}&amp;quot; /&amp;gt;
                &amp;lt;set-header name=&amp;quot;Authorization&amp;quot; exists-action=&amp;quot;override&amp;quot;&amp;gt;
                    &amp;lt;value&amp;gt;@(&amp;quot;bearer &amp;quot; + (string)context.Variables[&amp;quot;accessToken&amp;quot;])&amp;lt;/value&amp;gt;
                &amp;lt;/set-header&amp;gt;
            &amp;lt;/when&amp;gt;
            
            &amp;lt;otherwise&amp;gt;
                &amp;lt;set-header name=&amp;quot;Authorization&amp;quot; exists-action=&amp;quot;override&amp;quot;&amp;gt;
                    &amp;lt;value&amp;gt;@(&amp;quot;bearer &amp;quot; + (string)context.Variables[&amp;quot;bearerToken&amp;quot;])&amp;lt;/value&amp;gt;
                &amp;lt;/set-header&amp;gt;
            &amp;lt;/otherwise&amp;gt;
        &amp;lt;/choose&amp;gt;
    &amp;lt;/inbound&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.4 – Performance&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Retry policy:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;I actually do not prefer to let APIM handle retries to backend systems:&lt;ul&gt;
&lt;li&gt;Requests which can take a long time (say &amp;gt; 10 seconds) may even take longer when initial attempts fail. This can push the client into a time out window.&lt;/li&gt;
&lt;li&gt;Most 3rd parties have their own retry policies incorporated into their API framework. This is for the client to stay in full control over any call.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If your client application framework does not support re-try policies or you’d like to utilise the advanced options APIM offers for retries, you can enable a retry policy in APIM as per below example:&lt;ul&gt;
&lt;li&gt;Note: after V10.0.13 D365 F&amp;amp;O has throttling enabled for OData requests&lt;/li&gt;
&lt;li&gt;As part of this framework, D365 F&amp;amp;O will return status code 429 “Too many requests” in case of request overkill. So we can put a retry condition on that status code to diversify the re-try settings per status code (!):&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Policy&lt;/strong&gt;: retry requests to backend systems&lt;/p&gt;
&lt;p&gt;API &amp;gt; All operations &amp;gt; Outbound -&amp;gt; retry&lt;br&gt;Note: I would recommend to put the count and interval variables in Named values, so an update to the named value applies to all API operations at once&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt; &amp;lt;outbound&amp;gt;
        &amp;lt;retry condition=&amp;quot;@(context.Response.StatusCode == 429)&amp;quot; count=&amp;quot;3&amp;quot; interval=&amp;quot;10&amp;quot; max-interval=&amp;quot;&amp;quot; delta=&amp;quot;&amp;quot; first-fast-retry=&amp;quot;false&amp;quot; /&amp;gt;
 &amp;lt;/outbound&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Caching&lt;/strong&gt;: responses can be cached&lt;ul&gt;
&lt;li&gt;If a client application is firing the same request within a certain timeframe, APIM can return a cached response as opposed to forwarding the call to the backend system again&lt;/li&gt;
&lt;li&gt;I’ve used this pattern in an &lt;strong&gt;e-commerce to D365 Commerce&lt;/strong&gt; integration scenario: customers tend to click back and forth between pages which can lead to re-loading of the same data multiple times. Returning cached responses was very useful here to &lt;strong&gt;reduce load times and number of calls&lt;/strong&gt; to the D365 Cloud Scale Unit.&lt;/li&gt;
&lt;li&gt;A cached response takes about 45-50ms to be returned to the client, so it leads to improved performance in repetitive scenarios&lt;/li&gt;
&lt;li&gt;Here’s how to implement it:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Named Value&lt;/strong&gt;: time window to cache a response for&lt;/p&gt;
&lt;p&gt;APIM &amp;gt; APIs &amp;gt; Named Values -&amp;gt; Caching duration&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Policy&lt;/strong&gt;: cache a response and return it from cache&lt;/p&gt;
&lt;p&gt;API &amp;gt; All operations &amp;gt; Outbound -&amp;gt; cache-store&lt;br&gt;API &amp;gt; All operations &amp;gt; Inbound -&amp;gt; cache-lookup-value&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;inbound&amp;gt;
        &amp;lt;base /&amp;gt;
        &amp;lt;cache-lookup-value key=&amp;quot;{{D365OpsEnvironmentName}}-token-{{ClientId}}&amp;quot; variable-name=&amp;quot;bearerToken&amp;quot; /&amp;gt;
    &amp;lt;/inbound&amp;gt;
    &amp;lt;outbound&amp;gt;
        &amp;lt;base /&amp;gt;
        &amp;lt;cache-store duration=&amp;quot;{{CachingDurationInSeconds}}&amp;quot; /&amp;gt;
    &amp;lt;/outbound&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.5 – Flexibility&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Re-pointing to another environment:&lt;/strong&gt; since APIM allows client applications to consume Services backend system agnostic, client apps can be linked up with a different backend system without downtime.&lt;ul&gt;
&lt;li&gt;When implemented as descibed under &lt;a href=&quot;#anchor-abstraction&quot;&gt;#1 Abstraction&lt;/a&gt; above, re-pointing is just a matter of changing the value for parameters &lt;strong&gt;D365OPSEnvironment&lt;/strong&gt; and &lt;strong&gt;D365OPSEnvironmentName&lt;/strong&gt;. Since APIM won’t find a bearer token for that Environment name, it will retrieve a new one automatically.&lt;/li&gt;
&lt;li&gt;With this, it’s easy to re-point a TEST e-commerce website from a D365 F&amp;amp;O DEV box to a sandbox for example&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using APIM end points in Power Automate, Logic App and Power Apps as opposed to the D365 F&amp;amp;O connector&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;The D365 F&amp;amp;O connector for Power Automate/Logic Apps simplifies integration scenarios for non-techies&lt;/li&gt;
&lt;li&gt;However, using the connector is not too simple due the requirement to come up with the right entity key pairs in update/insert/delete scenarios&lt;/li&gt;
&lt;li&gt;In addition, using the connector requires a &lt;strong&gt;User based data connection&lt;/strong&gt; where APP based authentication might be preferred&lt;/li&gt;
&lt;li&gt;Using an APIM endpoint as opposed to the D365 F&amp;amp;O connector saves a data connection in the Flow or Logic App orchestration – This makes it more ‘lightweight’ and easier to export/migrate, for example to another tenant&lt;/li&gt;
&lt;li&gt;See below how to create a HTTP request to a D365 F&amp;amp;O OData endpoint to fetch all the address information for a customer via APIM as per the setup described in this blog post – For authentication to APIM, API Key is defined – APIM authenticates to D365 F&amp;amp;O by bearer token as described under &lt;a href=&quot;#anchor-authentication&quot;&gt;#4 – Authentication&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-5.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-5.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;Version your APIs&lt;/strong&gt;: when in Production it’s important to have the ability to quickly jump over from one API version to another for patching purposes while staying risk-free. To achieve this you can enable versioning on any API:&lt;ul&gt;
&lt;li&gt;Enable versioning by choosing the option &lt;strong&gt;Add version&lt;/strong&gt; on any of your APIs (see picture below)&lt;/li&gt;
&lt;li&gt;Now, your client application can easily jump over to a new/patched version of your API by a simple URL change: e.g. switching from {APIM URL}/customers/getcustomeraddresses to {APIM URL}/customers/&lt;strong&gt;V2&lt;/strong&gt;/getcustomeraddresses&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-6.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-6.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;6 – API Documentation&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Developer portal:&lt;/strong&gt; Both D365 F&amp;amp;O OData and D365 Commerce Cloud Scale Unit OData interface frameworks lack OpenAPI/Swagger documentation:&lt;ul&gt;
&lt;li&gt;To fill this gap, Microsoft ship &lt;a href=&quot;https://github.com/MicrosoftDocs/dynamics-365-unified-operations-public/blob/main/articles/commerce/dev-itpro/typescript-proxy-retail-pos.md&quot;&gt;proxy clients for D365 Commerce OData&lt;/a&gt; and &lt;a href=&quot;https://docs.microsoft.com/en-us/odata/client/code-generation-tool&quot;&gt;OData V4 Client Code Generator tool for Visual Studio&lt;/a&gt; which can be used to generate a Client proxy for the D365 F&amp;amp;O backend OData service&lt;/li&gt;
&lt;li&gt;However, these proxies only allow &lt;em&gt;&lt;strong&gt;Programmatic Integration&lt;/strong&gt;&lt;/em&gt; and are more generic tools which may lack some detail&lt;/li&gt;
&lt;li&gt;When a D365 F&amp;amp;O or D365 Commerce API is described in APIM in terms of template parameters, header parameters, request body, potential status codes etc., this information is automatically published to the APIM Developer portal&lt;/li&gt;
&lt;li&gt;The Developer portal can be fully customised and customer branded, similar to SharePoint sites&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internal and external users&lt;/strong&gt; can be authenticated (either via e-mail/password or AAD user login) to access all or a subset of APIs so they become &lt;strong&gt;sulf-sufficient&lt;/strong&gt; in consuming them:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Azure API Management Developer portal&lt;/strong&gt;: available APIs after login&lt;/p&gt;
&lt;p&gt;APIM &amp;gt; Portal overview &amp;gt; Developer portal&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-7.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-7-1024x640.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Azure API Management Developer portal&lt;/strong&gt;: API details&lt;/p&gt;
&lt;p&gt;APIM &amp;gt; Portal overview &amp;gt; Developer portal&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-9.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-9-1024x565.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Azure API Management Developer portal&lt;/strong&gt;: Export to WADL, OpenAPI v2 or v3&lt;/p&gt;
&lt;p&gt;APIM &amp;gt; Portal overview &amp;gt; Developer portal&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-10.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-10.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Documentation in Power Automate – Logic Apps – Power Apps:&lt;/strong&gt; APIM APIs can be exported as Power Connector so the API documentation is also available in Power Automate, Logic Apps and Power Apps:&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;APIM: export as Power connector&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;API &amp;gt; Create Power Connector&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-11.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-11-1024x840.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Power Automate – Logic App – Power Apps&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;List of APIs pulled from APIM definitions&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-12.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-12-1024x1007.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Power Automate – Logic Apps – Power Apps&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Custom APIM based connector with PIM documentation&lt;br&gt;Note: the connector only requires API-Key authentication to APIM as per the respective definition in APIM&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-13.png&quot;&gt;&lt;img src=&quot;/images/blog/my-best-practices-for-d365fo-d365commerce-interfacing-via-apim/image-13-1024x615.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;4 – Final words&lt;/h2&gt;
&lt;p&gt;I hope this blog post inspired you to explore the use of Azure API Management for D365 F&amp;amp;O and D365 Commerce interfacing and more. I think APIM can be useful in many scenarios. Fortunately, the cost are relatively low. A customer can already deploy a Production environment for a monthly cost of just over &lt;a href=&quot;https://azure.microsoft.com/en-us/pricing/details/api-management/?&amp;ef_id=CjwKCAiAvaGRBhBlEiwAiY-yMN3qu4fjq91MqbwPlx6l7msSJyg8DCxHNoBBYA55bWcwWkv4h1337hoCIDcQAvD_BwE:G:s&amp;OCID=AID2200221_SEM_CjwKCAiAvaGRBhBlEiwAiY-yMN3qu4fjq91MqbwPlx6l7msSJyg8DCxHNoBBYA55bWcwWkv4h1337hoCIDcQAvD_BwE:G:s&amp;gclid=CjwKCAiAvaGRBhBlEiwAiY-yMN3qu4fjq91MqbwPlx6l7msSJyg8DCxHNoBBYA55bWcwWkv4h1337hoCIDcQAvD_BwE&quot;&gt;150 dollar per month&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Warm regards,&lt;br&gt;Patrick Mouwen&lt;br&gt;03.09.2022&lt;/p&gt;
</content:encoded><category>D365 Technical</category></item><item><title>How to save your D365 F&amp;O customer some money</title><link>https://patrickmouwen.com/blog/how-to-save-your-d365fo-customer-some-money/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/how-to-save-your-d365fo-customer-some-money/</guid><description>How D365 F&amp;O cloud-hosted Build and DEV environments are deployed through LCS, and where the Azure subscription setup can reduce the bill.</description><pubDate>Wed, 23 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In most projects, customers and partners are deploying Build and DEV boxes from LCS\Cloud hosted environments. These utilise multiple Azure resources such as storage accounts, virtual network and virtual machines. In many cases, the LCS environment is working against only 1 Azure subscription which is eventually used to host the PROD environment as well. If this is the case, you can potentially save your customer quite some money. In this blog post, we’ll see how much and how!&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;1 –&lt;/strong&gt; How much money can your customer save on Azure consumption?&lt;/h2&gt;
&lt;p&gt;Open Chrome and open the Azure pricing calculator: &lt;a href=&quot;https://azure.microsoft.com/en-us/pricing/calculator&quot;&gt;https://azure.microsoft.com/en-us/pricing/calculator&lt;/a&gt;. Now select &lt;strong&gt;Virtual Machine&lt;/strong&gt; and pick 1 virtual machines with the following specs (which is default in LCS):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Instance&lt;/strong&gt;: D13 – 8vCPU – 56GB- 400 GB&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tier&lt;/strong&gt;: Standard HDD&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disk Size&lt;/strong&gt;: 3xS15: 256GiB&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virtual Machines&lt;/strong&gt;: 1&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Pick the following details for calculating the monthly cost against standard Azure pricing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Number of hours&lt;/strong&gt;: 176 hours (22 work days x 8 hours)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Region&lt;/strong&gt;: North Europe [prices vary per data center]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pay as you go&lt;/strong&gt; is yes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compute payment options&lt;/strong&gt; is monthly&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Total cost for this set will be about &lt;strong&gt;205.11 dollar&lt;/strong&gt; for 1 virtual machine (you’ll often have 5 or more!):&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/how-to-save-your-d365fo-customer-some-money/image-1.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-save-your-d365fo-customer-some-money/image-1.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now scroll all the way down to &lt;strong&gt;SHOW DEV/TEST PRICING&lt;/strong&gt; and flip this to yes. Now the cost comes at 169.73 dollar for a single VM, a &lt;strong&gt;17.3%&lt;/strong&gt; cost saving compared to non-discounted standard Azure pricing:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/how-to-save-your-d365fo-customer-some-money/image-5.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-save-your-d365fo-customer-some-money/image-5-1024x423.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As you can see there’s no saving on the Disk storage which is a fixed cost which you’ll have to pay even when the VM is switched off. However, since the Virtual Machine is the highest cost, the discount will be higher the more hours the machine will be running. For example, when you select &lt;strong&gt;One year reserved&lt;/strong&gt; equal to yes (which means full time continuous running for a year, similar to a sandbox), the total cost is 476.28 dollar as opposed to 744.92 dollar, a saving of &lt;strong&gt;36%.&lt;/strong&gt; &lt;strong&gt;Three years reserved&lt;/strong&gt; (3 years of full time running) gives you a monthly cost of 331.20 dollar versus 599.84 dollar, a &lt;strong&gt;45%&lt;/strong&gt; saving.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;2 – How to setup Azure and LCS to utilise the discounted pricing&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When you open your the details for a Subscription on Azure portal, you’ll notice the Offer ID:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/how-to-save-your-d365fo-customer-some-money/image-4.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-save-your-d365fo-customer-some-money/image-4.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This Offer ID indicates the type of Offer that is related to a Subscription. Offers often either represent monthly credit or discounted rates. In the example above the Offer ID is a Partner Action Pack offering 85 Euro credit per month against non-discounted rates. You can find all available Offers &lt;a href=&quot;https://azure.microsoft.com/en-us/support/legal/offer-details/&quot;&gt;here&lt;/a&gt;. Note that subscription can only have 1 activated at a time, but a tenant can have multiple subscriptions.&lt;/p&gt;
&lt;p&gt;Two of these offers qualify for the discounted rates (see &lt;a href=&quot;https://azure.microsoft.com/en-us/pricing/dev-test/#overview&quot;&gt;here&lt;/a&gt;):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/offers/ms-azr-0023p/&quot;&gt;Offer 0023P&lt;/a&gt; –&lt;/strong&gt; Pay-As-You-Go Dev/Test: for customers who do not have an Enterprise Agreement&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/offers/ms-azr-0148p/&quot;&gt;Offer 0148P&lt;/a&gt; –&lt;/strong&gt; Enterprise Dev/Test: for customers who do have an Enterprise Agreement&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Both these Offers provide discounted rates for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Virtual Machines [D365 cloud hosted environments!]&lt;/li&gt;
&lt;li&gt;SQL Database&lt;/li&gt;
&lt;li&gt;SQL Managed Instance&lt;/li&gt;
&lt;li&gt;HD Insight&lt;/li&gt;
&lt;li&gt;App Service&lt;/li&gt;
&lt;li&gt;Logic Apps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s what you need to do to activate the discount for D365 F&amp;amp;O cloud hosted environments:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create AAD Account&lt;/strong&gt;: create an AAD account for the owner of the subscription who will also become the admin of the D365 F&amp;amp;O cloud hosted environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual Studio Subscription&lt;/strong&gt;: Link a Visual Studio Subscription to this AAD account. A Visual Studio Subscription Professional comes at &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms.vs-professional-monthly#pricing&quot;&gt;45 dollars per month&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activate the DEV/TST pricing&lt;/strong&gt;: open the link to to the Offers mentioned above and click &lt;strong&gt;Activate&lt;/strong&gt;. This will require you to login with the AAD account which you have defined to become the owner of the Subscription with discounted rates. Note: activation automatically creates the subscription in the tenant which relates to the AAD account. So you should be able to see the Subscription in Azure portal with the respective Offer ID attached to it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grant the AAD Account owner access to the Life Cycle Services (LCS) project&lt;/strong&gt; where you want to deploy new Cloud Hosted D365 F&amp;amp;O environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Link the discounted Subscription to Life Cycle Services (LCS)&lt;/strong&gt;: follow the standard procedure described in &lt;a href=&quot;https://docs.microsoft.com/en-us/dynamics365/project-operations/environment/resource-add-azure-subscription-lcs-project&quot;&gt;this Microsoft docs page&lt;/a&gt; to link the new discounted subscription to LCS. Note: you can link multiple subscriptions to LCS.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now when you deploy a new D365 F&amp;amp;O environment in your LCS &amp;gt; Cloud Hosted Environments, you’ll be able to pick the discounted subscription [ensure you’re logged as the subscription owner who will become the admin of the environment]:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/how-to-save-your-d365fo-customer-some-money/image-6.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-save-your-d365fo-customer-some-money/image-6.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hopefully this discounted setup will allow you to enjoy working with the D365 family of Products even more 🎉!&lt;/p&gt;
&lt;p&gt;Patrick&lt;/p&gt;
&lt;p&gt;“Reflect upon your present blessings, of which every man has plenty; not on your past misfortunes, of which all men have some.” &lt;em&gt;Charles Dickens&lt;/em&gt;&lt;/p&gt;
</content:encoded><category>D365 Technical</category></item><item><title>How to Unlock Many Hidden D365 Retail Features!</title><link>https://patrickmouwen.com/blog/how-to-unlock-hidden-d365-commerce-features/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/how-to-unlock-hidden-d365-commerce-features/</guid><description>One Version in theory is not One Version in practice. Licence keys, parameters, SysFlighting and Feature Management, and what each unlocks.</description><pubDate>Mon, 11 May 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ever since D365 Finance &amp;amp; Operations V10, we’re in the Managed Updates model which aligns all Customers on a similar Platform Version – It’s the so called “One Version” strategy which brings a lot of benefits. But is there really ONE VERSION in reality? We have License keys, Parameter modules, &lt;a href=&quot;https://kurthatlevik.com/2019/03/07/dynamics-365fo-enabling-new-hidden-functionality-sysflighting/&quot;&gt;SysFlighting&lt;/a&gt; and &lt;strong&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/fin-ops/get-started/feature-management/feature-management-overview&quot;&gt;Feature Management&lt;/a&gt;&lt;/strong&gt; which already contains 250+ Features in V10.0.11 PEAP. Did you all enable them? If you sum all these parameters, D365 Finops installations can fundamentally differ even if the underlying Platform version is similar.&lt;/p&gt;
&lt;p&gt;Now with D365 Retail (Commerce) there is yet another variable – A relatively new Retail/Commerce Parameter area which is controlling Retail functionality behind the scenes… In this blog post we’ll dig out all the Features that can be enabled from here. Fellow Functional and Technical D365 Retail/Commerce consultants sit tight: this area is likely to become more and important in the future. It can also be really helpful for your own customisations.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;1 – Commerce Configuration Parameters – Introduction&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;If you open D365 Commerce and you navigate to &lt;strong&gt;Commerce Parameters&lt;/strong&gt; &amp;gt; &lt;strong&gt;Configuration Parameters&lt;/strong&gt; you end up in an area which seems rather boring:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Commerce-Configuration-Parameters.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Commerce-Configuration-Parameters-1024x557.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But it’s actually the opposite: this is the place where unexpected magic can be unleashed. Maybe you remember the .INI files from the old days or the .config files in web applications – This is the place where you can set any parameter and parameter value in OPEN TEXT. So imagine you’re coding your own new Retail Feature and you’re implementing new magical Business Logic to enhance Omni-Channel Retail in 3 flavours: “Legacy”, “Full Retail” and “Ultimate Retail”. However, the “Ultimate Retail” flavour takes you months to build and you only want to enable it for a few special customers who will beta test it. It’s actually your little secret. In your X++ code, you then code a reference to evaluate a new Value &lt;em&gt;MySecretRetailFeature&lt;/em&gt; in the Configuration Parameters grid with the 3 possible values “Legacy”, “Full Retail” and “Ultimate Retail”. Default is “Full Retail”, so all customers silently work by this setting. You don’t need to bother about implementing a new custom tab “My Customisation” with a new dropdown which is visible for all customers. Instead, you’ve just built your own secret Retail Flight Key (!).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/Open-Text-D365-Retail-Parameter.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/Open-Text-D365-Retail-Parameter-1-1024x304.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you look into the X++ code in D365 Commerce you’ll find Retail flight keys which are implemented by Microsoft behind the scenes. But we fellow D365 Commerce fanatics live in a special world: The D365 Retail/Commerce world. So OUR Flight Keys can even have more footprint as we have the ability to ship them to the Channel Database sourcing D365 Commerce Run Time (CRT). From there they can control behaviour of D365 POS, the Commerce Frontend and &lt;a href=&quot;/blog/the-power-of-the-d365-retail-apis-crt-part-i-the-basics/&quot;&gt;Retail API connected third-party applications&lt;/a&gt;. The shipment of the parameters happens through the &lt;strong&gt;RetailConfigurationParameters&lt;/strong&gt; subjob which sits in the &lt;strong&gt;1110 Global configuration&lt;/strong&gt; Scheduler job:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-RetailConfigurationParameters-Subjob.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-RetailConfigurationParameters-Subjob-1024x644.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this blog post we’ll take a look at all the features which are exposed in this area, both in the D365 Backend as well as Commerce Run Time (CRT). Only a few of them are documented. Before we dive into more detail, here’s an example of a Retail Flight Key that is actually documented (&lt;a href=&quot;https://docs.microsoft.com/en-us/dynamics365/commerce/sync-product-ratings&quot;&gt;Microsoft Docs&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FEATURE&lt;/strong&gt;: Enable the ability to see Product Ratings and Reviews on the D365 POS&lt;br&gt;&lt;strong&gt;CONTEXT&lt;/strong&gt; (&lt;a href=&quot;https://docs.microsoft.com/en-us/dynamics365/commerce/ratings-reviews-overview&quot;&gt;Microsoft Docs&lt;/a&gt;): Product Rating and Reviews can be captured in the Commerce Storefront and made available in-store to serve the interaction between Store associates and Customers (for example aided by a dual screen POS).&lt;/p&gt;
&lt;p&gt;This feature can be enabled by inputting the following Flight Key: &lt;strong&gt;RatingsAndReviews.EnableProductRatingsForRetailStores&lt;/strong&gt;=true&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/RatingsAndReviews.EnableProductRatingsForRetailStores-1024x724.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;2 – List of ‘Hidden’ D365 Retail/Commerce Features&lt;/strong&gt;: D365 Backend&lt;/h2&gt;
&lt;p&gt;If you want to inquire all Retail Flight Keys developed by Microsoft which can be unlocked through the &lt;strong&gt;Commerce Parameters &amp;gt; Configuration Parameters&lt;/strong&gt; form, then do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &lt;strong&gt;D365 AOT&lt;/strong&gt; in Visual Studio&lt;/li&gt;
&lt;li&gt;Search for “&lt;strong&gt;featurecontrol&lt;/strong&gt;“&lt;/li&gt;
&lt;li&gt;Select one of the classes -&amp;gt; Right mouse button -&amp;gt; &lt;strong&gt;View code&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Scroll all the way up to the top of the code which lists the Flight Keys as constants:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/RetailFeatureControl-1024x283.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;See below an overview of all Flight Keys I could find in D365 V10.0.11 PEAP in applying this approach – Before you dive into this list please note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Column “&lt;strong&gt;Default&lt;/strong&gt;” indicates what the default setting is if the key is not set at all. In some place this is commented in code. Please note that the comment in code may be wrong compared to actual behaviour. I have not tested this (!).&lt;/li&gt;
&lt;li&gt;Note that for Flight Keys that are used in the D365 backend, a string to int conversion is taking place when the Parameter value is read from the table. So to &lt;em&gt;enable&lt;/em&gt; a Flight Key the word “true” is to be inputted and “false” for &lt;em&gt;disabling&lt;/em&gt;. D365 Commerce Run Time (see section 3 in this blog post) expects integer values 0 or 1 (!). So this is also how you can distinct HQ vs Commerce Run Time (CRT) related Flight Keys :):&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/Flight-Keys-D365-Backend-vs-CRT.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/Flight-Keys-D365-Backend-vs-CRT-1-1024x380.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Overview&lt;/strong&gt; | Retail &amp;amp; Commerce Flight Keys in the D365 Finance &amp;amp; Operations Backend&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-DOM.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-DOM-1024x287.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-CDX.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-CDX-1024x454.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Crossdocking.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Crossdocking-1024x139.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Customer-Order.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Customer-Order-1024x139.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Customer-Search.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Customer-Search-1024x139.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Commerce-Orders.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Commerce-Orders-1024x378.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Purchase-Orders.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Purchase-Orders-1024x322.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Settle-Customer-Order.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Settle-Customer-Order-1024x137.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Retail-Statement.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-Retail-Statement-883x1024.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-WHS-and-Inventory.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-Flight-Keys-WHS-and-Inventory-1024x137.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;3 – List of ‘Hidden’ D365 Retail/Commerce Features&lt;/strong&gt;: D365 Commerce Run Time (CRT)&lt;/h2&gt;
&lt;p&gt;As stated before, Retail Configuration Parameters (Retail Flight Keys) can be set in the &lt;strong&gt;Retail Parameters&lt;/strong&gt; form in the D365 Finance &amp;amp; Operations back end and then shipped to the Channel Database by the 1110 Distribution Schedule. From there, &lt;strong&gt;D365 Commerce Run Time&lt;/strong&gt; can use them to control operation in POS, Commerce Storefront or any other App. if you’re unfamiliar with the CRT Architecture principle, then I’d recommend you to read my &lt;a href=&quot;/blog/the-power-of-the-d365-retail-apis-crt-part-i-the-basics/&quot;&gt;blog post on the Basics of the D365 Retail and Commerce APIs&lt;/a&gt;. As will become clear below, Microsoft have already implemented the use of the Flight Keys in CRT in quite a lot of places and this is growing with every new D365 Release (!).&lt;/p&gt;
&lt;p&gt;It’s pretty easy to find all the use of the Retail Configuration Parameters (the ‘hidden’ Retail Flight Keys’) inside CRT if you take my &lt;a href=&quot;/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/&quot;&gt;‘Engine Room’ approach&lt;/a&gt; – For the Tech interested – Note: this is similar to finding an X++ reference for a table/form in the AOT:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open .NET Reflector as described in the &lt;a href=&quot;/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/&quot;&gt;blog post&lt;/a&gt; and ensure to operate it against the latest CRT DLLs.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Microsoft.Dynamics.Commerce.Runtime.Entities &amp;gt; Microsoft.Dynamics.Commerce.Runtime.DataModel -&amp;gt; RetailConfigurationParameter&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-CRT-RetailConfigurationParameter.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-CRT-RetailConfigurationParameter-1024x428.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Select &lt;strong&gt;RetailConfigurationParameters&lt;/strong&gt; -&amp;gt; click right mouse button and select &lt;strong&gt;Analyze&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Expand the tree structure and expand the child element &lt;strong&gt;Used By&lt;/strong&gt; – Now all the references are listed:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-CRT-RetailConfigurationParameter-References.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-CRT-RetailConfigurationParameter-References-1024x372.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I’ve inspected these references and listed the actual parameter key/value pairs below. Please note again that I have tested only some of these parameters.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Overview&lt;/strong&gt; | Retail &amp;amp; Commerce Flight Keys in D365 Retail CRT&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-Transactions-1.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-Transactions-1-1024x403.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-Price-Calculation.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-Price-Calculation-1024x248.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-Tax-Calculation.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-Tax-Calculation-1024x153.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-Picking-and-Receiving.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-Picking-and-Receiving-1024x186.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-Product-Ratings-and-Reviews.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-Product-Ratings-and-Reviews-1024x186.png&quot; alt=&quot;Retail Configuration Parameters&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-Product-Search.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-Product-Search-1024x153.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-POS-Receipt-Printing-1.png&quot;&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/D365-Retail-CRT-Flight-Keys-POS-Receipt-Printing-1-1024x153.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;4 – Closing Words&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Working myself down the lists above, I’ve discovered some really interesting Flight Keys – I’ve already applied some of them in my current project. Each of the Flight Keys is really a story in itself and testing can be time consuming. So please share your experience if you get to test any of them or find new ones in upcoming versions.&lt;/p&gt;
&lt;p&gt;Note: While applying some of the Flight Keys I found a small bug in the use of the Flight Keys: some of the Flight key values exceed 60 characters while the Value column in &lt;strong&gt;Commerce Parameters &amp;gt; Configuration Parameters&lt;/strong&gt; only allows for 60 characters. Even though this leads to truncation, the parameter is still picked up by D365 Finops. Microsoft is likely to fix the truncation in V10.0.13:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/how-to-unlock-hidden-d365-commerce-features/LCSS-ISSUE-Flight-Key-exceeds-60-characters-1024x449.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I hope this article inspired you to get even more out of you D365 Commerce implementation!&lt;/p&gt;
</content:encoded><category>Technicalint</category></item><item><title>D365 Retail APIs Part III: How to use the Retail APIs from Power Automate (Flow) and Logic App</title><link>https://patrickmouwen.com/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/</guid><description>How to construct a request to the D365 Retail APIs, and call them step by step from Power Automate and Logic Apps.</description><pubDate>Thu, 02 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;After walking through the overall D365 Retail API Architecture in part I and II of this series on the D365 Retail APIs, it’s now time to enable anyone to actually use the Retail APIs. To allow this, this blog post will contain all details on how to construct a request to most of the 400 out-of-box D365 Retail APIs – Beyond that, I’ve included a step-by-step instruction on how to use any of the Retail APIs from Microsoft Power Automate (Flow).&lt;/p&gt;
&lt;p&gt;But before we can really get things rolling, we first need to apply some additional D365 setup and we need to choose the right security pattern. So that’s where I’ll start this blog post.&lt;/p&gt;
&lt;p&gt;Note: to effectively consume the content of this blog post, please ensure to familiarise with the content of &lt;a href=&quot;/blog/the-power-of-the-d365-retail-apis-crt-part-i-the-basics/&quot;&gt;Part I&lt;/a&gt; and &lt;a href=&quot;/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/&quot;&gt;Part II&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;1 – Security&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In Retail world, we’re utilising a variety of sales channels which are operated by a variety of users: in general, 3 types of users can be recognised:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Employees&lt;/strong&gt;: in-store POS systems and Call Center applications are operated by Retail employees.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Named consumers&lt;/strong&gt;: consumers unveiling details on their identity (name, address etc.) while making purchases via Social media, e-com platforms, consumer apps etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Anonymous consumers&lt;/strong&gt;: guests making purchases without consent on saving information about their identity&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Looking at privacy and data security in general, it is crucial to restrict access to the 400+ D365 Retail API end points for use by each of the 3 categories of users. For example, we certainly do not want the guest visitors on our e-com website to be able to retrieve information from other customers on loyalty points, purchasing history or product recommendations. At the same time, we don’t want our self-checkout consumers to apply manual discounts :). In summary, we need a mechanism to make our Retail end points (which are the gateways to our Data and Business logic) available to only those users who are allowed to use them.&lt;/p&gt;
&lt;p&gt;If you look inside Retail Server as we’ve done in &lt;a href=&quot;/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/&quot;&gt;Part II&lt;/a&gt;, you’ll find that each of these end points have a special attribute called “CommerceAuthorization” (see picture 1 below). This attribute basically lists the 1 or multiple “Commerce Roles” which are allowed to use the endpoint.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/CommerceAuthorization-Attribute.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/CommerceAuthorization-Attribute-1024x409.png&quot; alt=&quot;D365 Retail Server CommerceAuthorization Attribute&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Picture 1&lt;/strong&gt; – CommerceAuthorization Attribute on a Retail Server OData endpoint&lt;/p&gt;
&lt;p&gt;These “Commerce Roles” are very much in line with the user groups we acknowledged earlier:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Role 1 – Anonymous&lt;/strong&gt;: this role represents our anonymous customers. It will be of no surprise that only a few D365 Retail APIs are exposed to be used anonymously&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Role 2 – Customer&lt;/strong&gt;: this role represents our named consumers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Role 3 – Employee&lt;/strong&gt;: this role represents our Retail staff&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Role 4 – Application&lt;/strong&gt;: this generic role is designed for third-party applications which do not operate on behalf of a specific user (Customer or Employee)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Picture 2 below depicts the purpose of Commerce Roles in a bit more detail. As you can see in this picture, every D365 Retail API is enabled for 1 or multiple roles. Since the &lt;em&gt;Customer&lt;/em&gt; and &lt;em&gt;Employee&lt;/em&gt; role are built around a known identity (from a consumer or staff member respectively), both roles build upon the use of &lt;em&gt;&lt;a href=&quot;https://auth0.com/docs/tokens/id-tokens&quot;&gt;ID Tokens&lt;/a&gt;&lt;/em&gt;. In short, ID tokens contain encrypted details on a person’s identity (name, account number etc.) In case of Employees (in-store!) the encrypted ID Token contains the Employee number and Password which we know are used for logging into MPOS/CPOS.&lt;/p&gt;
&lt;p&gt;Last but not least, picture 2 highlights the Commerce Role &lt;em&gt;Application&lt;/em&gt;. This is the role we’ll focus on in the remainder of this blog post as it can be used for integrating any third-party application (e-com platforms, third-party POS systems, Apps etc.). As visible in picture 2, the Application role works by &lt;em&gt;Access tokens&lt;/em&gt;. This is exactly the type of authentication most of you will recognise from the very commonly used D365 F&amp;amp;O (backend) APIs. Remember: similar to the D365 F&amp;amp;O backend APIs, the D365 Retail APIs are also based on OData, so there’s not much of a difference on how to consume them as you will see below.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/D365-Retail-Server-Authentication_1080.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/D365-Retail-Server-Authentication_1080-1024x388.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Picture 2&lt;/strong&gt; – The purpose of Commerce Roles&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;2 – Azure Setup&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In order to allow an external application to make requests to the D365 Retail APIs, we need to register the application in our Azure Active Directory (1) and allow access to D365 for this application (2). Let’s start with the Azure side of things. Here’s how to register the application:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 1 –&lt;/strong&gt; Register the Application&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open &lt;a href=&quot;https://portal.azure.com&quot;&gt;Azure portal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Azure Active Directory &amp;gt; App Registrations&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New registration&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Enter the following details (note: &lt;strong&gt;Name&lt;/strong&gt; can be the name of your application such as the name of the e-commerce platform, App etc.) and save these details&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Create-AAD-Web-Registration.jpg&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Create-AAD-Web-Registration-1024x686.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 2&lt;/strong&gt; –Create and Copy App Secret&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Azure Active Directory &amp;gt; App Registrations&lt;/strong&gt; -&amp;gt; Click on the App you registered in step 1&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Certificates and secrets&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Create a new client secret as per below picture&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Copy to clipboard&lt;/strong&gt; icon to copy the Secret&lt;/li&gt;
&lt;li&gt;Paste the Secret in a safe place, for example a OneNote page – You’ll need it later&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Create-AAD-App-Secret.jpg&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Create-AAD-App-Secret-1024x538.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Copy-AAD-App-Secret-scaled.jpg&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Copy-AAD-App-Secret-1024x482.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 3&lt;/strong&gt; –Create and Copy App Secret&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Azure Active Directory &amp;gt; App Registrations&lt;/strong&gt; -&amp;gt; Click on the App you registered in step 1&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Overview&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Copy the &lt;strong&gt;Application (client) ID&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Copy the &lt;strong&gt;Directory (tenant) ID&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Paste both IDs in a safe place, for example a OneNote page – You’ll need them later&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Copy-AAD-Tenant-ID-and-Application-ID.jpg&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Copy-AAD-Tenant-ID-and-Application-ID-1024x505.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;3 – D365 Setup&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;STEP 1&lt;/strong&gt; –Register the Identity Provider in Retail Shared Parameters&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Retail &amp;gt; Channel Setup &amp;gt; Channel Profiles&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Copy the &lt;strong&gt;Retail Server URL&lt;/strong&gt; &lt;em&gt;without&lt;/em&gt; the /Commerce suffix&lt;/li&gt;
&lt;li&gt;Keep a note of this URL, for example on a OneNote page – You’ll need it below&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Retail &amp;gt; Heaquarter Setup &amp;gt; Parameters &amp;gt; Retail Shared Parameters&lt;/strong&gt; -&amp;gt; Tab &lt;strong&gt;Identity providers&lt;/strong&gt; – Create the entries as shown in the picture below:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IDENTITY PROVIDERS &amp;gt; Issuer&lt;/strong&gt;: Please note the / behind the URL so &lt;a href=&quot;https://sts.windows.net/&quot;&gt;https://sts.windows.net/&lt;/a&gt;&lt;tenant ID&gt;/ – Paste the tenant ID as copied in Azure Setup -&amp;gt; Step 3 above&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RELYING PARTIES &amp;gt; ClientID&lt;/strong&gt;: paste the Application ID as copied in Azure Setup -&amp;gt; Step 3 above&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SERVER RESOURCE IDS&amp;gt;Server Resource ID&lt;/strong&gt;: paste the Retail Server URL which you copied from the &lt;strong&gt;Channel Profiles&lt;/strong&gt; form&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Register-Identity-Provider-in-Retail-Shared-Parameters.jpg&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Register-Identity-Provider-in-Retail-Shared-Parameters-1024x675.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 2&lt;/strong&gt; –Assign security permissions to the Application&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to &lt;strong&gt;System administration &amp;gt; Setup &amp;gt; Azure Active Directory applications&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Create a new record and paste the Application ID as copied in Azure Setup -&amp;gt; Step 3 above&lt;/li&gt;
&lt;li&gt;Select a user account for the Application – Please note that the user should have sufficient privileges for the operations the external Application should be able to perform against D365.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;STEP 3&lt;/strong&gt; – Synchronise the Setup to the Retail channel Database&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Retail &amp;gt; Retail IT &amp;gt; Distribution schedule&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Run the &lt;strong&gt;1110&lt;/strong&gt; (Global configuration) schedule&lt;/li&gt;
&lt;li&gt;Note: in some rare cases I’ve come across it was needed to run the 9999 job&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;4 – Request format&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Now the Setup on Azure and D365 is done, we’re ready to make the D365 Retail APIs work for us.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 1&lt;/strong&gt; – Request an Access Token&lt;/p&gt;
&lt;p&gt;Request format:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/AAD-Access-Token.jpg&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/AAD-Access-Token-1024x355.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;{{Tenant ID}}: paste the Tenant ID as copied in Azure Setup -&amp;gt; Step 3 above&lt;/li&gt;
&lt;li&gt;{{Azure Application ID}}: paste the Application ID as copied in Azure Setup -&amp;gt; Step 3 above&lt;/li&gt;
&lt;li&gt;{{Application secret}}: paste the Application secret as copied in Azure Setup -&amp;gt; Step 2 above&lt;/li&gt;
&lt;li&gt;{{Retail Server URL}}: paste the Retail Server URL as copied in D365 Setup -&amp;gt; Step 1 above&lt;/li&gt;
&lt;li&gt;The access_token value from the response is to be passed as Authorization header value in the actual request (see step 2 below)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;STEP 2&lt;/strong&gt; – Make the Request to Retail Server – Example: create a customer into D365 backend via the Retail APIs&lt;/p&gt;
&lt;p&gt;Request format:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Retail-API-Create-Customer-Request.jpg&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Retail-API-Create-Customer-Request.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;{{D365 Retail URL}}: paste the Retail Server URL as copied in D365 Setup -&amp;gt; Step 1 above&lt;/li&gt;
&lt;li&gt;{{access token}}: copy/paste the value from the access_token entry in the Body response from step 1&lt;/li&gt;
&lt;li&gt;{{retail channel operating unit}}: copy/paste the &lt;strong&gt;Retail channel number&lt;/strong&gt; representing the Store or Online store. You can find this number on the &lt;strong&gt;Organization administration &amp;gt; Organizations &amp;gt; Operating units&lt;/strong&gt; form in D365 F&amp;amp;O. For example: 052 represents the Houston store.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;5 – Postman Setup&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;To kick-start you on using the D365 Retail APIs, I’ve packaged above Request into a ready-to-go Postman setup. Follow below steps to get it rolling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 1&lt;/strong&gt; – Download and Installation&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.getpostman.com/downloads/&quot;&gt;Download&lt;/a&gt; and install the Postman client&lt;/li&gt;
&lt;li&gt;Download the Postman Environment and Request Collection I have prepared for you from my &lt;a href=&quot;https://patrickmouwen-my.sharepoint.com/:f:/p/contact/EhicUn6UqOxHiQG7uaj1eJkBWewQPWqOXVhMr_OvC9c4VQ?e=TSahjW&quot;&gt;OneDrive&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Open Postman and click &lt;strong&gt;File&amp;gt;Import&lt;/strong&gt; – Click &lt;strong&gt;Choose files&lt;/strong&gt; and select the 2 files as downloaded from my OneDrive: &lt;em&gt;D365 Retail APIs Part III – Environment.postman_environment&lt;/em&gt; and &lt;em&gt;D365 Retail APIs Part III – Requests.postman_collection&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;STEP 2&lt;/strong&gt; – Fill out the Environment variables&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the top right, set &lt;em&gt;D365 Retail APIs Part III – Environment&lt;/em&gt; as the active environment&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Manage environments&lt;/strong&gt; icon&lt;/li&gt;
&lt;li&gt;Click on &lt;em&gt;D365 Retail APIs Part III – Environmen&lt;/em&gt;t&lt;/li&gt;
&lt;li&gt;Fill out the values which are specific to your environment (See Azure Setup and D365 Setup above) for the entries starting with &lt;em&gt;Input your..&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Update&lt;/strong&gt; to save the new values&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Postman-Manage-environments-scaled.jpg&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Postman-Manage-environments-1024x176.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 3&lt;/strong&gt; – Create a Customer via the Retail APIs&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Expand the Postman collection &lt;em&gt;D365 Retail APIs Part III – Requests&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Select the POST Get AAD Token operation&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Send&lt;/strong&gt; button on the right hand side&lt;/li&gt;
&lt;li&gt;Verify you have a Body response which is similar to the response in the picture below&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Postman-AAD-Token-Request-scaled.jpg&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Postman-AAD-Token-Request-1024x613.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Expand the subfolder &lt;em&gt;D365 Retail APIs&lt;/em&gt; in the &lt;em&gt;D365 Retail APIs Part III – Requests&lt;/em&gt; Postman collection&lt;/li&gt;
&lt;li&gt;Select the POST Customers\CreateCustomer operation&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Body&lt;/strong&gt; on the right hand side and optionally update the values such as the name for the customer&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Send&lt;/strong&gt; button on the right hand side&lt;/li&gt;
&lt;li&gt;Verify that the Body response returns all the details for the account which was newly created – You’ll find this account in the &lt;strong&gt;Accounts receivable&amp;gt;Customers&amp;gt;All Customers&lt;/strong&gt; form in D365 F&amp;amp;O&lt;/li&gt;
&lt;li&gt;When inquiring the new Customer account you’ll find out that many properties such as the Sales tax group, Address book, Credit limit etc. are all populated while you did not input them. This is the heavy lifting done by the standard Retail Business logic which is sitting behind the Retail API. As per this logic, many properties are inherited from the default customer account as configured on the respective Store or Online store. This is a big advantage of using the D365 Retail APIs as over the standard D365 F&amp;amp;O Data Entities: if you use these, you’ll have to fill out almost every single property for the customer which is very time consuming (as it’s “re-inventing the wheel!”). With the Retail APIs, Microsoft have done most of the ’thinking’ for you which also guarantees you’re 100% compatible with the path the D365 Retail product is heading.&lt;/li&gt;
&lt;li&gt;Note: the first time a request to Retail Server is fired in a DEV box, it needs to ‘warm boot’, so the request will take a couple of seconds as opposed to the normal duration of about 150 milliseconds.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;6 – Using the D365 Retail APIs with Power Automate (Flow)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Now we know how to consume the Retail APIs which have the &lt;em&gt;Application&lt;/em&gt; CommerceRole (read: are suitable for interaction with third-party applications), I’ll know show you how to directly consume the D365 Retail APIs from Microsoft Power Automate (Flow). This will enable you to easily use the Retail APIs in Microsoft Power Apps and will simplify your D365 Retail integration experience.&lt;/p&gt;
&lt;p&gt;In my &lt;a href=&quot;/blog/the-power-of-the-d365-retail-apis-crt-part-i-the-basics/&quot;&gt;first blog post on the D365 Retail APIs&lt;/a&gt; I included this &lt;a href=&quot;https://youtu.be/--d-FiXz1nY&quot;&gt;video&lt;/a&gt; which demonstrates the use of the D365 Retail APIs by creating customers into D365 F&amp;amp;O from an Office 365 Form. Below I’ll show you step by step how to set this up in Office 365 Forms and Microsoft Power Automate. Here’s an overview of the Architecture:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/O365-Form-to-D365-FO-Customer.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/O365-Form-to-D365-FO-Customer-1024x576.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Part 1-3 of this Architecture will be detailed in the steps below. Part 4 and 5 have been detailed in previous blog posts on this topic. Please note that the Office 365 form is linked up with the D365 Retail APIs via 2 Flows as opposed to 1: I have separated the Flow steps which are to request the Access token and to fire the request to D365 into a separate Flow (the &lt;em&gt;Abstraction Flow&lt;/em&gt;), so this can be re-used to work with any other client (other than the Office 365 form in this example). Please be aware that we first have to create the &lt;em&gt;Abstraction Flow&lt;/em&gt; (Part 3) so we can call it from the &lt;em&gt;Orchestration Flow&lt;/em&gt; (Part 2).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 1&lt;/strong&gt; – Create Office 365 Form&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to Office 365 Forms: &lt;a href=&quot;https://forms.office.com/Pages/DesignPage.aspx&quot;&gt;https://forms.office.com/Pages/DesignPage.aspx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New form&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Create the form as per the picture below – Please ensure the dropdowns/radio buttons for questions 3-5 actually reflect the values in the subtitle for the question (these match with the D365 Contoso data set)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Office-365-Form-scaled.jpg&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Office-365-Form-1024x528.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 2&lt;/strong&gt; – Create the Abstraction Flow&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate to Microsoft Power Automate: &lt;a href=&quot;https://emea.flow.microsoft.com/&quot;&gt;https://emea.flow.microsoft.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Solution&amp;gt;New Solution&lt;/strong&gt; and input and save details for the new Solution&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New&amp;gt;New Flow&lt;/strong&gt; to start a new Flow – name this Flow &lt;strong&gt;Retail API_Orchestration&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Build and save the following Flow:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-1.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-1.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
&amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,
&amp;quot;properties&amp;quot;: {
&amp;quot;Phone&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
},
&amp;quot;Email&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
},
&amp;quot;FirstName&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
},
&amp;quot;LastName&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
},
&amp;quot;CustomerGroup&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
},
&amp;quot;CurrencyCode&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
},
&amp;quot;Operating Unit&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
}
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-2.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-2-1024x288.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Input the value for your Azure Tenant ID&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-3.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-3-1024x286.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Input the value for your Application Secret&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-4.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-4.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Input the following formula: replace(replace(variables(‘Secret’),’+’,’%2B’),’=’,’%3D’)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-5.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-5-1024x289.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Input the value for your Azure Application ID&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-6.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-6-1024x287.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Input your Retail Server URL&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-7.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-7.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-8.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-8.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
&amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,
&amp;quot;properties&amp;quot;: {
&amp;quot;token_type&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
},
&amp;quot;expires_in&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
},
&amp;quot;ext_expires_in&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
},
&amp;quot;expires_on&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
},
&amp;quot;not_before&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
},
&amp;quot;resource&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
},
&amp;quot;access_token&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;
}
}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-9.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-9.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &amp;quot;Phone&amp;quot;: &amp;quot;@{triggerBody()?[&amp;#39;Phone&amp;#39;]}&amp;quot;,
  &amp;quot;Email&amp;quot;: &amp;quot;@{triggerBody()?[&amp;#39;Email&amp;#39;]}&amp;quot;,
  &amp;quot;FirstName&amp;quot;: &amp;quot;@{triggerBody()?[&amp;#39;FirstName&amp;#39;]}&amp;quot;,
  &amp;quot;LastName&amp;quot;: &amp;quot;@{triggerBody()?[&amp;#39;LastName&amp;#39;]}&amp;quot;,
  &amp;quot;CustomerTypeValue&amp;quot;: 1,
  &amp;quot;Language&amp;quot;: &amp;quot;en-us&amp;quot;,
  &amp;quot;CustomerGroup&amp;quot;: &amp;quot;@{triggerBody()?[&amp;#39;CustomerGroup&amp;#39;]}&amp;quot;,
  &amp;quot;CurrencyCode&amp;quot;: &amp;quot;@{triggerBody()?[&amp;#39;CurrencyCode&amp;#39;]}&amp;quot;,
  &amp;quot;ReceiptSettings&amp;quot;: 0,
  &amp;quot;ReceiptEmail&amp;quot;: &amp;quot;@{triggerBody()?[&amp;#39;Email&amp;#39;]}&amp;quot;,
  &amp;quot;Addresses&amp;quot;: [],
  &amp;quot;Attributes&amp;quot;: []
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-10.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Abstraction-Flow-Step-10.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 3&lt;/strong&gt; – Create the Orchestration Flow&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Return to the Solution you created earlier&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New&amp;gt;New Flow&lt;/strong&gt; to start a new Flow – name this Flow &lt;strong&gt;Retail API_Office 365&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Build and save the following Flow:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Orchestration-Flow-Step-1.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Orchestration-Flow-Step-1.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Note: select the Office 365 Form that you created in step 1&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Orchestration-Flow-Step-2.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Orchestration-Flow-Step-2.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;
&lt;a href=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Orchestration-Flow-Step-3.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-iii-how-to-use-the-d365-retail-apis/Orchestration-Flow-Step-3-1009x1024.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After saving the Abstraction Flow in Step 2, you can copy the URI (URL where this Flow is hosted) – Input this into the URI field&lt;br&gt;Note: do not forget Content-Type=application/json – It is mandatory when calling an endpoint which represents another Flow&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &amp;quot;Phone&amp;quot;: &amp;quot;&amp;quot;,
  &amp;quot;Email&amp;quot;: &amp;quot;@{outputs(&amp;#39;Get_response_details&amp;#39;)?[&amp;#39;body/responder&amp;#39;]}&amp;quot;,
  &amp;quot;FirstName&amp;quot;: &amp;quot;@{outputs(&amp;#39;Get_response_details&amp;#39;)?[&amp;#39;body/reba91af4c50648c4a9a872a441d9a4be&amp;#39;]}&amp;quot;,
  &amp;quot;LastName&amp;quot;: &amp;quot;@{outputs(&amp;#39;Get_response_details&amp;#39;)?[&amp;#39;body/r733d0622029b45e8a860d22fac487e79&amp;#39;]}&amp;quot;,
  &amp;quot;CustomerGroup&amp;quot;: &amp;quot;@{outputs(&amp;#39;Get_response_details&amp;#39;)?[&amp;#39;body/r66eb983cdf354a2ca941b3fc6ac457f4&amp;#39;]}&amp;quot;,
  &amp;quot;CurrencyCode&amp;quot;: &amp;quot;@{outputs(&amp;#39;Get_response_details&amp;#39;)?[&amp;#39;body/r4d4605397f064fb491135d22fc4abcda&amp;#39;]}&amp;quot;,
  &amp;quot;Operating Unit&amp;quot;: &amp;quot;@{outputs(&amp;#39;Get_response_details&amp;#39;)?[&amp;#39;body/r220e4dbf5e4445628734a9c249494375&amp;#39;]}&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;strong&gt;7 – Final Words&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;I hope the length of this blog post did not discourage you to get started using the D365 Retail APIs. I can tell you from experience that when you reach the point that you’re getting the feeling of Mastering the Retail APIs, you’ll be blown away by the Power and endless Opportunities of this Treasure. You’ll wake up with new ideas on how to use them everyday. Power Apps, Power BI, Power Automate, Power… RETAIL!&lt;/p&gt;
</content:encoded><category>Technicalint</category></item><item><title>D365 Retail APIs Part II: How to know exactly what happens inside D365 Retail</title><link>https://patrickmouwen.com/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/</guid><description>How to see exactly what happens inside D365 Retail, using prototyping and the Retail APIs to understand the product before designing against it.</description><pubDate>Fri, 13 Dec 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In any of our D365 Implementation Projects, &lt;em&gt;Solution Prototyping&lt;/em&gt; is one of the most important aspects of the implementation. On the one hand this Prototyping serves a common Requirement to find a solution which stays closest to &lt;em&gt;Standard&lt;/em&gt; D365 – A Requirement often raised by small to medium sized Retailers. On the other hand, Prototyping let us fully &lt;em&gt;understand&lt;/em&gt; D365 Retail which allows us to write the best designs for &lt;em&gt;Custom&lt;/em&gt; solutions – An exercise which is often required for the bigger Retailers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Solution Prototyping&lt;/em&gt; is most commonly done from &lt;strong&gt;‘&lt;em&gt;Sea level&lt;/em&gt;‘&lt;/strong&gt;: by setting up D365 Retail in different ways to support variations to a Process which are then evaluated (often in playbacks to Business key users) against Process maps and related Requirements. I think this is a very good and effective way to make progress in a project while still making the right Design Decisions.&lt;/p&gt;
&lt;p&gt;However, there are cases in which this ‘Sea level’ approach is either very time consuming or not giving you the confidence that you’ve completely bottomed out the D365 Retail capabilities to support a certain process. You probably recognise this from working on complex Processes which are Retail/Omni related, D365 MPOS/commerce customisations or Retail Integrations. For these cases, you need another approach which I’ve named the &lt;strong&gt;‘&lt;em&gt;Engine Room&lt;/em&gt;‘&lt;/strong&gt; approach: this approach first descends into the ‘Engine Room’ of D365 for Retail to know exactly what happens there before you work yourself up to ‘Sea level’ again to pick the best Solution for your Use Case. In this blog post, I’ll unveil all the tricks to be able to do this quickly and effectively.&lt;/p&gt;
&lt;p&gt;Note: please ensure to familiarise with the D365 Retail API Architecture as per &lt;a href=&quot;/blog/the-power-of-the-d365-retail-apis-crt-part-i-the-basics/&quot;&gt;Part I of this series on D365 Retail APIs&lt;/a&gt; before you read any further.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;1 – Approach&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Picture 1 below depicts my ‘Engine Room’ approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Trick 1&lt;/strong&gt; – IIS Setup and Fiddler : we’re going to make a modification to the IIS/authentication to allow to intercept all traffic between all D365 Retail IIS Services with &lt;a href=&quot;https://www.telerik.com/download/fiddler&quot;&gt;Fiddler&lt;/a&gt; – See this &lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/D365-Retail-IIS-Services.png&quot;&gt;picture&lt;/a&gt; on the D365 Retail supporting IIS services you’ll typically find on a D365 F&amp;amp;O DEV box.&lt;ul&gt;
&lt;li&gt;A. The D365 Commerce and D365 SharePoint Online store &amp;gt;&amp;gt; TO &amp;gt;&amp;gt; D365 Retail Server&lt;/li&gt;
&lt;li&gt;B. D365 Cloud POS (CPOS) to &amp;gt;&amp;gt; TO &amp;gt;&amp;gt; D365 Retail Server (note: this can also be done without the trick – see blog post by our Retail Champion Kurt Hatlevik &lt;a href=&quot;https://kurthatlevik.com/2019/08/26/analyzing-clound-pos-performance-in-dynamics-365-for-retail/&quot;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;C. D365 Retail Server &amp;gt;&amp;gt; TO &amp;gt;&amp;gt; D365 Real Time Service (RTS)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trick 2&lt;/strong&gt;: .NET Reflector: we’ll install .NET Reflector to be able to look inside D365 Retail Server, Commerce Run Time (CRT) and all related portable Retail Business Logic&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D365 AOT&lt;/strong&gt;: we’ll use Visual Studio/AOT (no tricks needed here :)) to look into the D365 backend Real Time Service class logic hit by D365 Retail Server&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D365 X++&lt;/strong&gt;: Debugging: optionally we can debug the D365 code beyond the RTS classes to know what’s happening further down the road in D365 (Business as usual ;-))&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/Approach_1080.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/Approach_1080-1024x576.png&quot; alt=&quot;Inside D365 Retail&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Picure 1&lt;/strong&gt;: the ‘Engine Room’ approach&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;2 – Setup&lt;/strong&gt;&lt;/h2&gt;
&lt;h4&gt;&lt;strong&gt;2.1 – Trick 1: IIS Setup and Fiddler&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;&lt;em&gt;Note: only a apply this trick on a D365 DEV box!&lt;/em&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;#&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Step&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Reference&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;RDP into the D365 VM&lt;/td&gt;
&lt;td&gt;Use the admin account + password available through LCS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Follow these steps to install (if not already installed) and configure Fiddler on the VM.&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/resources/downloads/Fiddler-Installation-and-Setup.pdf&quot;&gt;Link&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Open Internet Information Services (IIS)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Navigate to the &lt;strong&gt;Application Pool&lt;/strong&gt; for Retail Server &amp;gt; &lt;strong&gt;Advanced settings&lt;/strong&gt; -&amp;gt; Change &lt;strong&gt;Identity&lt;/strong&gt; from “Network Service” to the admin account (requires password to be entered).     Note: this is the admin account which is available for the environment on LCS and which is used to RDP into the environment&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/Pic1.png&quot;&gt;IIS Settings&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;If you’re working with CPOS, this is sufficient to be able to intercept all end-to-end CPOS&amp;gt;Retail Server&amp;gt;RTS traffic.&lt;/td&gt;
&lt;td&gt;If you’re working with the SharePoint or Commerce storefront, then repeat step 4 for the &lt;strong&gt;Application Pool representing the storefront&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;I’d recommend to reboot the environment after above steps&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h4&gt;&lt;strong&gt;2.2 – Trick 2: Install and Setup .NET Reflector&lt;/strong&gt;&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;#&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Step&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Reference&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;RDP into the D365 VM&lt;/td&gt;
&lt;td&gt;RDP with the admin account + password available through LCS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Download and install .NET Reflector (run as Administrator)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.red-gate.com/dynamic/products/dotnet-development/reflector/download&quot;&gt;Link&lt;/a&gt; Note: this tool is not free, but has a 14-day trial – I prefer the standalone edition – There’s also an Add-In for Visual Studio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Open Internet Information Services (IIS) – Navigate to &lt;strong&gt;Sites&lt;/strong&gt; and select RetailServer. Click right mouse button &amp;gt; &lt;strong&gt;Explore&lt;/strong&gt;.  This will open Windows Explorer for the folder which hosts the RetailServer website&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Double click on the &lt;strong&gt;Bin&lt;/strong&gt; folder and copy the path to the folder&lt;/td&gt;
&lt;td&gt;e.g. K:\RetailServer\WebRoot\bin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Open .NET Reflector and click &lt;strong&gt;File &amp;gt; Open Assembly&lt;/strong&gt; – Paste the path to the RetailServer folder as copied in the previous step into the &lt;strong&gt;File name&lt;/strong&gt; textbox. Click &lt;strong&gt;Open&lt;/strong&gt; to open the path&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Select one of the DLLs and click &lt;CTRL&gt;&lt;A&gt; to select all DLLs – Click &lt;strong&gt;Open&lt;/strong&gt; to open the DLLS&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Navigate to the following entry:  &lt;code&gt;Microsoft.Dynamics.&lt;/code&gt; &lt;code&gt;Retail.RetailServer\&lt;/code&gt;  &lt;code&gt;Microsoft.Dynamics.&lt;/code&gt; &lt;code&gt;Retail.RetailServerLibrary\&lt;/code&gt;  &lt;code&gt;Microsoft.Dynamics.Retail. RetailServerLibrary.ODATAControllers&lt;/code&gt;.   This entry represents the Retail Sever “External mailbox” (Retail OData end points) – You’ll recognise all Retail operations here!  This will always be your starting point for any analysis, so keep this entry in mind (!)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/D365-Retail-ODATA-endpoints.png&quot;&gt;D365 Retail OData endpoints&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;3 – Analyse a Real-life example: create a Customer through the D365 Retail APIs&lt;/h2&gt;
&lt;p&gt;In &lt;a href=&quot;/blog/the-power-of-the-d365-retail-apis-crt-part-i-the-basics/&quot;&gt;Part I of this series on D365 Retail APIs&lt;/a&gt; I used Microsoft Forms to create a Customer into the D365 backend utilising the D365 Retail APIs in real time. Now, we’ll dive into the &lt;strong&gt;‘&lt;em&gt;&lt;strong&gt;&lt;strong&gt;Engine Room&lt;/strong&gt;&lt;/strong&gt;&lt;/em&gt;‘&lt;/strong&gt; of for this process of customer creation. As you’ll see this will unveil all aspects of Customer sign up including how the Retail Setup and Parameters in the D365 backend guide this process.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;3.1 Intercept the D365 Retail communication with Fiddler&lt;/strong&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Ensure to have Fiddler and .NET Reflector open (open as Administrator).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fire up a D365 Retail Cloud POS and navigate to &lt;strong&gt;Current Transaction &amp;gt; Add Customer &amp;gt; Create new Customer&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clear all sessions from Fiddler&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fill out the customer details and hit the &lt;strong&gt;Save&lt;/strong&gt; button&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wait until the customer is fully saved and then open Fiddler – Inquire the following results:  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CPOS &amp;gt;&amp;gt; TO &amp;gt;&amp;gt; Retail Server communication&lt;/strong&gt;&lt;br&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/Retail-Server-Create-Customer.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/Retail-Server-Create-Customer.png&quot; alt=&quot;Retail Server - Create Customer&quot;&gt;&lt;/a&gt;  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Retail Server &amp;gt;&amp;gt; TO &amp;gt;&amp;gt; RTS communication&lt;/strong&gt; (note: this version D365 V10.0.8 PEAP)&lt;br&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/RTS-Create-Customer.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/RTS-Create-Customer.png&quot; alt=&quot;RTS - Create Customer&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We can derive the following information from the Fiddler input:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPOS is making a request to &lt;Retail Server URL&gt;/commerce/customer in JSON format&lt;/li&gt;
&lt;li&gt;Retail Server is making a request to &lt;D365 SOAP URL&gt;/Services/RetailCDXRealTimeService in XML format&lt;/li&gt;
&lt;li&gt;RTS The SOAP service forwards the request to the RetailTransactionService.NewCustomerExt2 method in D365 X++&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;&lt;strong&gt;3.2 Analyse what happens within Retail Server&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Now we have all the entry points for analysis, let’s dive into related Retail Server Business Logic underpinning the request from Cloud Pos to Retail Server:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open .NET Reflector and the Retail Server DLLs as explained in paragraph 2&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Navigate to the &lt;em&gt;Customers&lt;/em&gt; OData Controller:  &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/D365-Retail-ODATA-Create-Customer.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/D365-Retail-ODATA-Create-Customer.png&quot; alt=&quot;D365 Retail OData - Create Customer&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now let’s follow the ’trail’ 😉 – Click on &lt;strong&gt;this.customerManager.CreateCustomer&lt;/strong&gt; – This will bring us into the &lt;strong&gt;Commerce Run Rime&lt;/strong&gt; (CRT) area.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As you can see here, a request is created to a Workflow (a series of Retail Services) – From here we can inquire all ‘Customer Create’ Business Logic as sitting on D365 Retail CRT  &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/D365-Retail-CRT-Workflow-Create-Customer.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/D365-Retail-CRT-Workflow-Create-Customer.png&quot; alt=&quot;D365 Retail CRT Workflow - Create Customer&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We can derive the following conclusions from inquiring this Business Logic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If the Channel is an Online store then Retail Server is reading the setting whether to create an Asynchronous (offline) customer from the &lt;strong&gt;Online store -&amp;gt; Functionality profile&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if the Channel is a Store then Retail Server is reading the setting whether to create an Asynchronous (offline) customer from the &lt;strong&gt;Retail store -&amp;gt; Functionality profile&lt;/strong&gt;  &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/Functionality-Profile.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/Functionality-Profile.png&quot; alt=&quot;D365 Retail Functionality Profile&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After determining whether to create an Offline customer as per the previous step (in Contoso: No=create a customer in Real time), the CRT Workflow fires a &lt;strong&gt;saveCustomerServiceRequest&lt;/strong&gt;: if the Customer Account is to be created Asynchronously (offline), then a customer Account number is generated locally and the customer is created into the local Retail database via a Data service (eventually a stored procedure). If the Customer Account is created Synchronously (real time), then a request is fired to D365 backend RTS. As we already know from our previous Fiddler analyses, this is the flow that is followed for the Houston Store (our example here) in the standard Contoso data set. Fiddler showed that the actual D365 method that is hit in the D365 backend is &lt;strong&gt;RetailTransactionService.newCustomerExt2.&lt;/strong&gt; Let’s take a look in there in the next section!  &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/D365-CRT-Save-Customer.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/D365-CRT-Save-Customer.png&quot; alt=&quot;D365 CRT - Save Customer&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;&lt;strong&gt;3.3 Analyse what happens within D365 (Retail) Backend&lt;/strong&gt;&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open &lt;strong&gt;Visual Studio -&amp;gt; D365 AOT&lt;/strong&gt; on the D365 DEV Box&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Navigate to &lt;strong&gt;RetailTransactionService.newCustomerExt2&lt;/strong&gt; – As we can read in the comments for this method, this method also supports Extension properties (=custom customer properties in CPOS/Retail Server in case it’s not sufficient to work with the standard Customer Attributes)  &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/RTS-Create-Customer-method.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/RTS-Create-Customer-method.png&quot; alt=&quot;D365 RTS - Create Customer method&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Let’s follow the ’trail’ (call stack) from here into &lt;strong&gt;RetailTransactionServiceCustomers.newCustomerExt&lt;/strong&gt; -&amp;gt; &lt;strong&gt;RetailTransactionService.newCustomer&lt;/strong&gt; -&amp;gt; &lt;strong&gt;RetailTransactioServiceCustomer.newCustomer&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Here we find a treasure of Retail Business Logic for creating a customer into the D365 backend – For example, many customer properties are defaulted from the Standard Retail customer which is configured on the Respective channel.  &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/RTS-Customer-Customer-Business-Logic.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/RTS-Customer-Customer-Business-Logic.png&quot; alt=&quot;RTS Customer - Customer Business Logic&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Feel free to follow the trail deeper into D365!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;&lt;strong&gt;4 – Some last words…&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;For the ones who are ‘lost in the woods’ after reading this long blog post, see below an overview of the full E2E ‘Call stack’ for creating a Customer into D365 backend in real time… Yeah.. this WHOLE process happens under &lt;strong&gt;200ms&lt;/strong&gt; once the Retail Server and Real Time Service are ‘warm booted’… I think it’s simply amazing. What a master piece of art Microsoft have created here !  &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/Create-Customer-CallStack_1080.png&quot;&gt;&lt;img src=&quot;/images/blog/d365-retail-apis-part-ii-how-to-know-exactly-what-happens-inside-d365-retail/Create-Customer-CallStack_1080.png&quot; alt=&quot;Create Customer - CallStack&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I hope this blog posts give you a kick start in performing any &lt;em&gt;&lt;strong&gt;‘Engine Room’ analysis&lt;/strong&gt;&lt;/em&gt; against D365 Retail. I always learn a lot on how things are really done inside D365 retail when I follow this approach!&lt;/p&gt;
</content:encoded><category>Technicalint</category></item><item><title>The Power of the D365 Retail APIs/CRT – Part I: The Basics</title><link>https://patrickmouwen.com/blog/the-power-of-the-d365-retail-apis-crt-part-i-the-basics/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/the-power-of-the-d365-retail-apis-crt-part-i-the-basics/</guid><description>An overview of the D365 Retail API and CRT architecture, with an example showing what these out-of-box interfaces make possible.</description><pubDate>Fri, 06 Dec 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Did you know that D365 for Retail contains more than 400 out-of-box Retail APIs (for the non-techies: interfaces) ranging from Loyalty management, Gift card management, Omni order management to Stock counting and Retail Logistics? These interfaces allow you to easily integrate with any third-party systems like e-commerce platforms, POS systems and Consumer Apps. It also allows you to quickly enrich your Retail Solution with handy Power Apps, for example for in-store Goods receipt, Stock counting, Labelling or Clienteling.&lt;/p&gt;
&lt;p&gt;Unfortunately I still notice that many Customers and Partners do not consider the Retail APIs in their designs, which goes around all the ‘free’ Retail Business Logic which comes with them. Instead, Customers and Partners start a custom coding exercise (re-inventing the wheel!) which often &lt;em&gt;limits&lt;/em&gt; rather than empowers the omnichannel capabilities of D365.&lt;/p&gt;
&lt;p&gt;This is all mainly caused by the lack of documentation – It’s time to change that! In this series of blog posts we’ll explore the Power of the Retail API’s so we can all benefit from them by using them to enhance the Retail experience for the Retail Businesses we serve. As we need the non-techies on this journey, I’ll try to make it understandable for all of us. Making the right Architectural decisions starts with a good understanding of the solution. So let’s dive into that first!&lt;/p&gt;
&lt;h2&gt;1 – &lt;strong&gt;D365 Retail API Architecture explained&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;D365 Retail comes with 3 major components – Below description is a little bit technical, but it’s good to keep these components in mind for a better understanding of the main picture (picture 1) below:  &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/the-power-of-the-d365-retail-apis-crt-part-i-the-basics/D365-Retail-APIs.png&quot;&gt;&lt;img src=&quot;/images/blog/the-power-of-the-d365-retail-apis-crt-part-i-the-basics/D365-Retail-APIs-1024x502.png&quot; alt=&quot;D365 Retail APIs&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let’s go through each element in the picture, step-by-step:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The Letter&lt;/strong&gt;. An app (e.g. a POS system, e-commerce platform or Power App) can send a request to 1 of the 400+ D365 Retail end points. This request can be to &lt;em&gt;Request&lt;/em&gt; information such as the loyalty balance of a customer or to &lt;em&gt;Send&lt;/em&gt; information.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The public Mailbox&lt;/strong&gt;. Metaphorically you can compare this request with a letter which is dropped into a mailbox. The mailbox in this case is the OData endpoint of Retail Server (&lt;strong&gt;1A&lt;/strong&gt;). It’s a public mailbox, so any App can drop letters in there. But there are 2 prerequisites which need to be met to allow this: the App needs to be a registered ‘member’ in the Receiver’s domain and the App must have received a pre-authorisation code (token) which needs to be sent with the letter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Internal Mailbox&lt;/strong&gt;. Once successfully received in the public (OData) Retail Server mailbox, the letter (request) is forwarded to an internal mailbox: a specific Commerce Run Time (CRT) operation (&lt;strong&gt;1B&lt;/strong&gt;). This CRT operation is responsible for processing the letter.  In order to get this done, the CRT operation contacts 1 or multiple Retail Services (&lt;strong&gt;1C&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Processing of the letter&lt;/strong&gt;. The Retail Services work with subcontractors. There are 2 types of subcontractors: Data services which can read/write information from/to the local Retail Database or Remote Data services which can receive/send information from/to the D365 backend. The Retail Services have been instructed (programmed) to contact either of the subcontractors or both subcontractors to process a certain letter (request). For example, a letter to update the Loyalty Balance for a customer is forwarded to the D365 backend (since other Apps should work against the latest balance) whereas a new customer is created both in the local Retail Database &lt;em&gt;and&lt;/em&gt; forwarded to the D365 Backend. In some case the Retail Service has to read specific parameter settings first to determine which subcontractor to forward the work to. These parameters have been set in D365 backend but are locally available for the Retail Services after sync to the local Retail Database. For example, a parameter which controls whether e-com orders are created into the local Retail database (and from there synched to D365 backend in bulk) or whether these orders are forwarded to the D365 backend in real time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Another Public mailbox&lt;/strong&gt;. Remote Data Service ‘Subcontractors’ will drop the original letter in the Public mailbox of the D365 Backend: a SOAP mailbox, often referred to as &lt;em&gt;Real Time Service&lt;/em&gt; (&lt;strong&gt;2A&lt;/strong&gt;). This mailbox has a trust relationship with the Remote Data Service ‘subcontractor’ which is confirmed by a certificate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Another Internal mailbox&lt;/strong&gt;. Very much similar to the way Retail Server is organized, the agent looking after the Real Time Service mailbox, forwards the letter to an internal mailbox for processing: the RetailTransactionService class in the D365 Backend (&lt;strong&gt;2B&lt;/strong&gt;). From there, Retail Services in the D365 backend take care of the actual processing which ties into many standard D365 (Retail) classes packed with Business Logic (&lt;strong&gt;2C&lt;/strong&gt; and &lt;strong&gt;2D&lt;/strong&gt;). For example in case of customer creation, these services will include the customer in the address book of the Retail channel, assign Retail affiliations and Customer attributes. In other words: even though not all this information was part of the original letter, the Retail Services ensure the letter is processed in line with D365 (Retail) Parameters settings and Retail Business Logic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Response&lt;/strong&gt;. As a sender of a letter, you’d love to get a response on your respect, right? This is organized as follows: whenever an exception occurs somewhere across the chain of ‘middlemen’ subcontractors as described above, the exception is written into a response letter which is returned to the sender (the App) following the chain in reverse order. If no exceptions occur, the original letter will reach it’s final destination. There, a response letter is written which is an in-depth response on the actual request, for example a response letter full of information on a newly created customer. Similar to what happens in case of an exception, the response letter is returned to sender following the chain in reverse order.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;2. Teaser&lt;/h2&gt;
&lt;p&gt;In below video I am trying to illustrate how powerful the Retail APIs can be. In the video, I am using Microsoft Forms (an Office 365 App) to capture information as part of an imaginary Customer Sign up process. Power Automate picks up the information and forwards it to D365 Retail Server to create the customer in the D365 backend in real time. As you will see in the video, the standard D365 Retail Business logic is fully utilized here as if the customer was captured on D365 MPOS: for example, the new customer is automatically included in the Retail channel’s address book.&lt;/p&gt;
&lt;h2&gt;3. The potential&lt;/h2&gt;
&lt;p&gt;The left Table below provides a break down of the Retail areas the 400+ Retail APIs apply to. A significant number of these APIs are built to provide &lt;em&gt;real time&lt;/em&gt; data exchange with the D365 backend. The right table below presents the Retail areas for which &lt;em&gt;real time&lt;/em&gt; connectivity to the D365 backend is supported.&lt;br&gt;&lt;img src=&quot;/images/blog/the-power-of-the-d365-retail-apis-crt-part-i-the-basics/Overview-of-D365-Retail-APIs.png&quot; alt=&quot;Overview of D365 Retail APIs&quot;&gt;&lt;br&gt;Looking at the functional breadth of the Retail APIs and the video in this blog post, I hope you’re inspired to think about all the opportunities provided by the D365 Retail APIs. In upcoming blog posts on this topic, we’ll make deeper dives into the various aspects of these Retail APIs so we can all use this knowledge to further enrich the D365 Retail experience for our customers.&lt;/p&gt;
</content:encoded><category>Technicalint</category></item><item><title>Advanced RSAT I: How to run D365 RSAT from MS FLOW</title><link>https://patrickmouwen.com/blog/run-d365-rsat-from-microsoft-flow/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/run-d365-rsat-from-microsoft-flow/</guid><description>Advanced RSAT, part I: a recorded walkthrough of triggering D365 RSAT test automation from Microsoft Flow.</description><pubDate>Thu, 26 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;div style=&quot;position:relative;padding-bottom:56.25%;height:0;overflow:hidden;margin:6px 0 28px;border-radius:12px;border:1px solid #D5DEE8&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/GlEd2LyFqPg&quot; title=&quot;Advanced RSAT I — run D365 RSAT from Microsoft Flow&quot; loading=&quot;lazy&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen style=&quot;position:absolute;top:0;left:0;width:100%;height:100%;border:0&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;We’re now in the new world of D365 “OneVersion” – A world in which we can benefit from continuous Microsoft investment without having to re-implement ERP ever again. But the new world also requires a solid Regression Testing Strategy to control the cost for consuming new updates. Here’s where Microsoft stepped in giving us the Regression Suite Automation Tool (RSAT). Although this tool is a good starting point, anyone who ever worked with RSAT will probably recognise one or more of the following limitations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I don’t want to go into a VM to run test cases!&lt;/li&gt;
&lt;li&gt;How can I test my D365 interfaces???&lt;/li&gt;
&lt;li&gt;How can I run multiple test cases/test suites in parallel (in other words: multi threaded)??&lt;/li&gt;
&lt;li&gt;I don’t want my chained tests to be scripted in Powershell, but in Azure DevOps (low code/no code solution!)&lt;/li&gt;
&lt;li&gt;How can I run mixed tests of process and interface? – e.g. to support E2E scenarios like: my e-com platform creates a sales order through an interface into D365 which is Released to warehouse through RSAT?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can of course wait for Microsoft to come up with solutions to overcome these limitations. In my case, I decided to accept the challenge to leverage the Power Platform to fill the gaps. In this series of blog posts I’ll gradually tackle each of the above limitations one by one.&lt;/p&gt;
&lt;p&gt;Key step in the overall solution is to find a way to move away from executing our D365 test cases directly from the RSAT tool and to bring this into a higher control layer with broader capabilities than RSAT alone… Please welcome an RSAT connector for Microsoft Flow!&lt;/p&gt;
&lt;p&gt;Get started with the QuickStart Guide I published on my OneDrive:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patrickmouwen-my.sharepoint.com/:b:/p/contact/Ebnvx0OR_mFPsnMqHZBFQN8BiAmehDVTl7oeCpLrdnHHsw?e=xwmi45&quot;&gt;https://patrickmouwen-my.sharepoint.com/:b:/p/contact/Ebnvx0OR_mFPsnMqHZBFQN8BiAmehDVTl7oeCpLrdnHHsw?e=xwmi45&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>Technicalint</category></item><item><title>Advanced RSAT II: How to run D365 RSAT directly from Azure DevOps</title><link>https://patrickmouwen.com/blog/run-d365-rsat-from-azuredevops/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/run-d365-rsat-from-azuredevops/</guid><description>Advanced RSAT, part II: a recorded walkthrough of running D365 RSAT test automation directly from Azure DevOps.</description><pubDate>Wed, 25 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;div style=&quot;position:relative;padding-bottom:56.25%;height:0;overflow:hidden;margin:6px 0 28px;border-radius:12px;border:1px solid #D5DEE8&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/CEcKsLMXQrA&quot; title=&quot;Advanced RSAT II — run D365 RSAT from Azure DevOps&quot; loading=&quot;lazy&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen style=&quot;position:absolute;top:0;left:0;width:100%;height:100%;border:0&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;Now that we’ve constructed a ‘RSAT connector for Microsoft Flow’ in &lt;a href=&quot;/blog/run-d365-rsat-from-microsoft-flow/&quot;&gt;Part I of this Series&lt;/a&gt;, we have lots of new opportunities offered by the Microsoft Power Platform to push our Test Automation in D365 to a new level.&lt;/p&gt;
&lt;p&gt;In below video I’ll demonstrate how toggling the State of an Azure DevOps Test Suite to “&lt;strong&gt;Run RSAT&lt;/strong&gt;” triggers MS Flow to iterate through the Test Cases in the Test Suite and let RSAT execute the Test Cases (D365 Task Guides) in the background. MS Flow will wait until RSAT execution is finished to send an e-mail to notify that RSAT execution is done. The e-mail will have the logs from the RSAT execution as attachments.&lt;/p&gt;
&lt;p&gt;See my &lt;a href=&quot;https://patrickmouwen-my.sharepoint.com/:f:/p/contact/Es5ssvKymQxMjQ_4vmt8c0oB2tJkK4t6qnaW79rMtfkt2g?e=D6uwy1&quot;&gt;OneDrive&lt;/a&gt; for the Flow which is used in the video.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: I didn’t manage to import this Flow package into another tenant than the tenant where the Flow was originally built – MS Flow complaints about a problem with the authorisation against Azure DevOps – So you may have to amend the packaged (zipped) json definition of the Flow to allow import. Please share an updated .zip file if you manage to make amendments to the packaged .json definition which allows import.&lt;/em&gt;&lt;/p&gt;
</content:encoded><category>Technicalint</category></item><item><title>Identify Configuration differences across D365 F&amp;O environments</title><link>https://patrickmouwen.com/blog/d365fo-identify-config-differences-across-environments/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/d365fo-identify-config-differences-across-environments/</guid><description>How to find configuration drift between D365 F&amp;O environments before cutover turns undocumented UAT changes into production issues.</description><pubDate>Tue, 11 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;hr&gt;
&lt;p&gt;We’ve all seen it many times in our projects.. Being under pressure to close these last P1 and P2 bugs by making some quick config changes in UAT, we forget to keep a record of what we did and to bring this into our Golden Config environment. And then, after cutover to Production, our users are confronted with the same issues as before.. How great would it be if we can prevent this with an extra ‘lock on the door’?&lt;/p&gt;
&lt;h2&gt;Dynamics Versions&lt;/h2&gt;
&lt;p&gt;The method of comparing configuration between D365FO environments as described below is utilizing D365 Data Management capabilities. If you’re still working with AX2012 you’d also be able to apply most of it with DIXF.&lt;/p&gt;
&lt;h2&gt;How it’s done&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;STEP 1:&lt;/strong&gt; Represent your critical configuration areas in a D365 Data Template&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;We all know our ‘sensitive’ setup areas which can give real trouble when not 100% identical in the various D365FO environments – Areas such as Financial dimension values, Tax setup and module parameters. To have a good starting point for your Config ‘lock on the door’, ensure to represent these areas by Data Entities in a D365 &lt;a href=&quot;https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/data-entities/configuration-data-templates&quot;&gt;Data Template&lt;/a&gt; which you could for example name “D365_Setup_Compare”:&lt;a href=&quot;/images/blog/d365fo-identify-config-differences-across-environments/D365FO-Data-Template.png&quot;&gt;&lt;img src=&quot;/images/blog/d365fo-identify-config-differences-across-environments/D365FO-Data-Template.png&quot; alt=&quot;D365FO Data Template&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Export this template into a SharePoint library for easy re-use and version control.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;STEP 2:&lt;/strong&gt; Create Export Data Projects in your D365FO environments&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Create an Export Data Project on the basis of the Data Template from SharePoint and pick “XML Element” and “Data Package” for the output format. As per best practice, suffix the Data Project with the name of the environment for easy identification later. Note that in case you have many D365 FO environments to continuously apply updated Data Templates to, you could consider &lt;a href=&quot;https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/data-entities/data-task-automation&quot;&gt;Data Task Automation.&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;/images/blog/d365fo-identify-config-differences-across-environments/D365FO-Export-Setup-Data-1.png&quot;&gt;&lt;img src=&quot;/images/blog/d365fo-identify-config-differences-across-environments/D365FO-Export-Setup-Data-1.png&quot; alt=&quot;D365FO Export Setup Data&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;STEP 3&lt;/strong&gt;: Save the files in a central location&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Create a folder structure in a central location. If you use SharePoint as a baseline, then open the respective Document Library in OneDrive to allow sync to local folders. Then, run the Export Data Projects in the various D365FO environments, download the packages and extract them into the folder structure:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365fo-identify-config-differences-across-environments/Setup-Compare-Folder-structure.png&quot;&gt;&lt;img src=&quot;/images/blog/d365fo-identify-config-differences-across-environments/Setup-Compare-Folder-structure.png&quot; alt=&quot;Setup Compare Folder structure&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;STEP 4&lt;/strong&gt;: Install and configure Altova diffdog&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;To quickly compare Configuration from D365FO environments by the XML files we’ve exported, I prefer using a tool called &lt;a href=&quot;https://www.altova.com/diffdog&quot;&gt;Altova diffdog&lt;/a&gt;. Although the tool is not free (one-time EUR109/USD139 for a license), I think it’s worth the investment looking at the excellent way this tool highlights any differences at a glance – We’ll come to that below. First, download and install the tool (on a trial license) and configure as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Click File&amp;gt;Compare Directories and select the directories to compare&lt;/li&gt;
&lt;li&gt;Tick Compare as XML and untick Quick to let Diffdog perform a detailed comparison of the files in the directories – This is done in seconds&lt;/li&gt;
&lt;li&gt;The tool then highlights the differences as per color coding as you can see in the example below.&lt;/li&gt;
&lt;li&gt;Click File&amp;gt;Save as and define a file name which is representative for the comparison, such as “D365 UAT vs PROD”. In this way, you can have multiple comparisons open as different tabs in Diffdog.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/d365fo-identify-config-differences-across-environments/Altova-DiffDog-Compare-XML.png&quot;&gt;&lt;img src=&quot;/images/blog/d365fo-identify-config-differences-across-environments/Altova-DiffDog-Compare-XML.png&quot; alt=&quot;Altova DiffDog Compare XML&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A click on any of the colored rows which represent differences, will give you the details. Switch to &lt;strong&gt;Grid View&lt;/strong&gt; for the best experience:&lt;a href=&quot;/images/blog/d365fo-identify-config-differences-across-environments/Altova-DiffDog-Visualise-XML-Differences.png&quot;&gt;&lt;img src=&quot;/images/blog/d365fo-identify-config-differences-across-environments/Altova-DiffDog-Visualise-XML-Differences.png&quot; alt=&quot;Altova DiffDog Visualize XML Differences&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Further ideas&lt;/h2&gt;
&lt;p&gt;If you want to make this a fully automated process which is re-usable for any other project, I’d recommend the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Utilise &lt;a href=&quot;https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/data-entities/data-task-automation&quot;&gt;&lt;strong&gt;D365 Data Task Automation&lt;/strong&gt;&lt;/a&gt; to automate the creation of “D365_Setup_Compare” Data Projects and their Data Entities representing core Setup Areas to compare. In this way, you can centrally maintain your project definitions in your LCS Shared Asset Library for easy re-use in all your Projects.&lt;/li&gt;
&lt;li&gt;Introduce automatic updates of the XML files in the SharePoint folder by setting up &lt;a href=&quot;https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/data-entities/recurring-integrations&quot;&gt;&lt;strong&gt;D365 Recurring Data jobs&lt;/strong&gt;&lt;/a&gt; for the “D365_Setup_Compare” Data projects and configuration of a Microsoft Flow to automatically dequeue, download and unzip the content of the packages into your central SharePoint folder.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Hope this ‘lock on the door’ saves us all a lot of frustration..!&lt;/p&gt;
&lt;p&gt;Patrick&lt;/p&gt;
</content:encoded><category>Functional</category></item><item><title>Dynamics 365 CRM and ERP interaction</title><link>https://patrickmouwen.com/blog/dynamics-365-crm-and-erp-interaction/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/dynamics-365-crm-and-erp-interaction/</guid><description>Where the Dynamics 365 CRM and ERP integration still needs design work, and how to make the two products behave as one.</description><pubDate>Thu, 28 Dec 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Overlooking many recent Dynamics 365 implementations, it seems that Microsoft’s marketing strategy of ‘marrying’ Dynamics AX and CRM into one Dynamics 365 family is paying off. More and more customers are choosing for the package deal of Operations and Sales. However, as always, the marketing machine is ahead of the troops: with the current state of the integration of the products, we need to be creative in order to make the two systems feel like one.&lt;/p&gt;
&lt;p&gt;In this blog post I’ll unveil an effective way to let Microsoft Dynamics 365 for Sales (CRM) interact with Microsoft Dynamics 365 for Finance and Operations (ERP)…&lt;/p&gt;
&lt;h2&gt;&lt;/h2&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Most of us will have some affinity with the &lt;strong&gt;Common Data Service&lt;/strong&gt;, which can also be used to &lt;a href=&quot;https://docs.microsoft.com/en-us/common-data-service/entity-reference/dynamics-365-integration&quot;&gt;exchange data between Dynamics 365 for Sales (CRM) and Dynamics 365 for Finance and Operations (ERP)&lt;/a&gt;. However, first of all Common Data Service does not offer real time capabilities at the moment of publishing this blog post. Second, this information exchange happens &lt;em&gt;behind the scenes&lt;/em&gt; (on data/service level). But in order to make D365S and D365FO feel like one system, we need a different kind of interaction. An interaction which builds upon &lt;em&gt;real time&lt;/em&gt;exchange of information and which builds upon data interaction on &lt;em&gt;form level&lt;/em&gt;: creating a new D365FO sales order from D365S should offer an experience which is close to ‘native’ D365FO experience.&lt;/p&gt;
&lt;h2&gt;Concepts for CRM and ERP interaction&lt;/h2&gt;
&lt;p&gt;In a recent project context, the customer was looking to emphasize D365S as master system for Customer management and Customer interaction and to emphasize D365FO as their selling system. Therefore, all users were envisioned to work from a 360 degree customer dashboard in D365S which was also &lt;a href=&quot;https://en.wikipedia.org/wiki/Computer_telephony_integration&quot;&gt;CTI&lt;/a&gt; enabled (=telephone integrated). Customer interaction in D365S &lt;em&gt;could&lt;/em&gt; result in offering a quotation or direct sales which then required to bring the user into the D365FO sphere. In order to make this a seamless experience for the user, we evaluated two concepts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Hub-2-Hub: in this concept, the user has one “Open in Call center” button which opens the D365FO &lt;strong&gt;Customer Service&lt;/strong&gt; form &lt;em&gt;for the Customer Account currently selected in D365S&lt;/em&gt;. This &lt;strong&gt;Customer service&lt;/strong&gt; form then offers the out-of-the-box D365FO features to create or edit an existing sales order or return order (quotation was added by minor modification).&lt;br&gt;&lt;a href=&quot;/images/blog/dynamics-365-crm-and-erp-interaction/ERP_CRM_Hub-2-Hub_1920.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-365-crm-and-erp-interaction/ERP_CRM_Hub-2-Hub_1920.jpg&quot; alt=&quot;D365S D365FO Interaction Hub-2-Hub&quot;&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;See this concept in action (example):&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Master-Slave: in this concept, the user working from D365S has direct access into the D365FO quick create forms for creating new sales orders and quotations and into the D365FO details forms allowing direct modifications to sales order or quotation. In this project context, we also decided to map the D365FO order holds to D365S tasks. This allowed Call Center agents to spot any order exceptions in D365S (for example missing payments), tackle that exception with the customer and then remove the respective hold by one click into D365FO.&lt;br&gt;&lt;a href=&quot;/images/blog/dynamics-365-crm-and-erp-interaction/ERP_CRM_Master-Slave_1920.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-365-crm-and-erp-interaction/ERP_CRM_Master-Slave_1920.jpg&quot; alt=&quot;D365FO D365S Master-Slave&quot;&gt;&lt;/a&gt;See this concept in action (new order):&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;See this concept in action (new quotation from opportunity):&lt;/p&gt;
&lt;p&gt;In both concepts, the data modified or newly created in D365FO is synched back to D365S through the standard CDS templates currently available. So after some minutes, the 360 degree customer dashboard in D365S reflects these changes at next visit of the customer Account. In a few scenarios, the current non-real time CDS behavior was not sufficient to support the business scenario: for example, new customer accounts created in D365S are required to be available in D365FO straight away. Otherwise the quick create form for quotation or sales order creation in D365FO cannot be pre-filled for the customer which was just created in D365S (Master-Slave concept) and the Customer Service form in D365FO cannot be pre-filtered for the that new customer (Hub-2-Hub concept). So here we had to implement real time Azure LogicApp integration to get to the desired result (no further details in this blog post).&lt;/p&gt;
&lt;h2&gt;The trick: how to realize the interaction on &lt;em&gt;form level&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;The ’trick’ to make D365S to D365FO form level interaction possible is to utilize the relative freedom we have to leverage custom URL parts (suffixes) in D365FO. A typical D365FO URL for opening the Sales order form looks like this: &lt;em&gt;https://&lt;CustomerSpecific&gt;.sandbox.ax.dynamics.com/?mi=MCRCustomerService&amp;amp;cmp=&lt;Company&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is the URL that was opened from D365S in the Master-Slave\Create quote scenario:&lt;br&gt;&lt;em&gt;https://&lt;CustomerSpecific&gt;.sandbox.ax.dynamics.com/?mi=MCRCustomerService&amp;amp;cmp=&lt;Company&gt;&amp;amp;customerid=575342&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As you can see, both the D365S Account number (kept in synch with D365FO Customer account through LogicApp) is passed through to D365FO by a custom URL suffix. You need two minor modifications to make this work:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A JavaScript enabled button in D365S (in the previous example the “Create quote” button). The JavaScript code is hosted as a &lt;strong&gt;Web resource&lt;/strong&gt; which holds the function to construct the full D365FO URL for a given button click (see simple example below).&lt;/li&gt;
&lt;li&gt;X++ code in D365FO to interpret the custom URL part: form event handler extension on the form Initialize event which does the following (in this example):&lt;ul&gt;
&lt;li&gt;Reading the “customerid=&lt;value&gt;” section in the URL&lt;/li&gt;
&lt;li&gt;Finding the associated customer record in the CustTable&lt;/li&gt;
&lt;li&gt;Setting the active customer in the Customer service form to this customer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;D365S Web resource with JScript:&lt;a href=&quot;/images/blog/dynamics-365-crm-and-erp-interaction/D365FO_D365S_Interaction_JavaScript_Enabled_Button.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-365-crm-and-erp-interaction/D365FO_D365S_Interaction_JavaScript_Enabled_Button.png&quot; alt=&quot;D365FO D365S Interaction JavaScript Enabled Button&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;D365FO X++ code:&lt;br&gt;&lt;a href=&quot;/images/blog/dynamics-365-crm-and-erp-interaction/D365FO_D365S_Interaction_X_Code.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-365-crm-and-erp-interaction/D365FO_D365S_Interaction_X_Code.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Due to the Azure AD enabled Single-Sign-On for D365S and D365FO, the D365FO client will open in about 2 seconds after clicking the JavaScript enabled button (the first time is always a bit slower due to caching). And given the Master-Slave 1-click approach which is similar to intra-D365FO behavior, most users will perceive this as ‘seamless’.&lt;/p&gt;
&lt;h2&gt;Evaluation of the concepts&lt;/h2&gt;
&lt;p&gt;I prefer the Master-Slave approach over the Hub-2-Hub approach for the following reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;With the Hub-2-Hub approach, it is not possible to pass parameter values which concern &lt;em&gt;new&lt;/em&gt; records. A good example here is the D365S to D365FO new quotation flow (see Master-Slave picture above). In this context, it is critical to pass the D365S &lt;strong&gt;Opportunity ID&lt;/strong&gt; to D365FO and store it on the new Quotation record created in D365FO. Only then this new Quotation record can, after making it a D365S record through CDS synch, be linked to the original Opportunity record in D365S (which prevents breaking integrity in D365S).&lt;/li&gt;
&lt;li&gt;The Master-Slave approach emphasizes a true distinction in &lt;em&gt;ownership&lt;/em&gt; of the Customer entity – This provides clarity to the users that they should always start their process in the D365S 360 degree Customer dashboard. By offering direct access from D365S to all selling features in D365FO, access to the customer related forms can also be minimized and/or reduced to view-only. This simplifies the use of both systems for average users.&lt;/li&gt;
&lt;li&gt;The Master-Slave concept saves the user clicks compares to the Hub-2-Hub approach.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The strongest point of the Hub-2-Hub approach is that it minimizes customization. But I think looking at the minimal development effort required to implement the Master-Slave concept, this does not outweigh the negative arguments listed above.&lt;/p&gt;
&lt;h2&gt;Evaluation of the overall solution&lt;/h2&gt;
&lt;p&gt;Although this solution was well received by the customer in this particular project context, there are some critical notes to make:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The solution presented in this blog post relies on the fact that the D365FO Kernel allows inclusion of custom URL parameters. Since this may change in the future (malicious code may also be triggered in this way!), this is a true weak spot.&lt;/li&gt;
&lt;li&gt;Ideally the base part of the URL is not hard coded in JScript but is retrieved dynamically based on an ‘Active environment’ parameter set in D365S.&lt;/li&gt;
&lt;li&gt;It could be considered to make the parameter name (in the example above: “customerid”) configurable by a parameter. This could also avoid potential conflicts with new ‘Kernel’ parameters Microsoft might introduce. On the other hand, if the custom URL suffixes are regarded as a “service”, this would vote against this “configurable” approach.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I hope this inspires you in your creative thinking! At least it inspired me.. Special thanks to &lt;a href=&quot;https://www.linkedin.com/in/dynamicsaxbusiness/&quot;&gt;Stefan Ebert&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/georg-braun-a0329724/&quot;&gt;Georg Braun&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/markus-bl%C3%A4ssle-293952105/&quot;&gt;Markus Blässle&lt;/a&gt; for their creative input to make this happen!&lt;/p&gt;
&lt;p&gt;Happy DAX’ing and happy New Year!&lt;/p&gt;
&lt;p&gt;Patrick&lt;/p&gt;
</content:encoded><category>Functional</category></item><item><title>1yr with AX7 Data Management – My top 12 learnings</title><link>https://patrickmouwen.com/blog/1yr-with-ax7-data-management-my-top-12-learnings/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/1yr-with-ax7-data-management-my-top-12-learnings/</guid><description>Twelve learnings from a year of working with AX7 Data Management on live projects — data entities, entity stores and what the documentation leaves out.</description><pubDate>Tue, 11 Oct 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We’re so used to the speed of current evolvements around Microsoft Dynamics AX (or should I say Dynamics 365 ;-)), that most of us who are interested in integrations have familiarized themselves for long with concepts like data entities and entity stores. In this blog post, I would like to go beyond the ‘obvious’ by sharing 1 year of personal project experience in working with AX7 Data Management.&lt;/p&gt;
&lt;p&gt;To enable you to quickly scan this blog post according to your own points of interest, I have listed my experiences in a top 10-alike pattern in random order.&lt;/p&gt;
&lt;h2&gt;One year with AX7 Data Management: My top 12 learnings&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;How to be really sure that code changes have been effectuated for data entities&lt;/strong&gt;&lt;br&gt;I’ve seen a lot of situations where a data entity, after updating the code for an AX7 data entity, showed unexpected behavior. In most cases, the people releasing the software had not forgotten to click the &lt;strong&gt;Refresh data entities&lt;/strong&gt; button in the AX7 Data Management’s &lt;strong&gt;Framework parameters&lt;/strong&gt; after release. As it turned out, this is not always sufficient. I apply the following procedure which never failed me so far:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delete the mappings on data projects which build upon the data entities to be refreshed (this is required for step 2).&lt;br&gt;• Note: in a typical project, multiple data projects may exist building upon a single data entity. This table browser query will help you find the respective data projects quickly: &lt;em&gt;https://&lt;Your AX7 environment&gt;/Default.htm?mi=SysTableBrowser&amp;amp;prt=initial&amp;amp;cmp=&lt;Company&gt;&amp;amp;tablename=DMFDefinitionGroupEntity&amp;amp;limitednav=true&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delete all the data entities from the Data entities list which are software updated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now refresh data entities through System administration &amp;gt; Workspaces &amp;gt; Data management &amp;gt; Framework parameters &amp;gt; Refresh data entities. The deleted entities will re-appear.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Re-create the mappings w you deleted earlier.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/1.-Delete-AX7-data-entities.jpg&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/1.-Delete-AX7-data-entities.jpg&quot; alt=&quot;Delete AX7 data entities&quot;&gt;&lt;/a&gt;2. &lt;strong&gt;Public cloud versus OneBox behavior&lt;/strong&gt;&lt;br&gt;Most DEV environments and even TEST environments will be based on OneBox installations. This is either a local VM with all AX7 components running on premise through Azure authentication or similar VM hosted on Azure. The differences in behavior between these SQL Server OneBox environments and Azure SQL powered Public Cloud environments are decreasing by the minute due to bug fixes and general advancements. But, be careful here. Do not expect that your Public Cloud environment will 1:1 behave like your TEST environment did before. Be on the safe side and reserve some time and budget for regression testing when taking the step from TST to UAT environment. I’ve seen SSIS errors on Public Cloud environments which never occurred in a TEST environment.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom interface tables based on event triggers as an alternative for outbound business logic&lt;/strong&gt;&lt;br&gt;It seems obvious to leverage the out-of-the-box SQL change tracking capabilities when only updated or new records are to be shipped. It also seems obvious to implement business logic at interface run time. But do not make these decisions too quickly. Weigh all the pros and cons of the different options as there are more options with the framework than you think. For example, in my project I faced a scenario in which it was a requirement to ship out all unique AX7 barcodes to a legacy system. So all new unique barcodes were to be gathered from a multi-company situation (barcodes are company-specific) and additional business logic was needed to gather additional information. I could have leveraged SQL change tracking and implement outbound business logic. But that would have made the interface fairly slow. Instead, I implemented business logic on event basis: whenever a barcode was inserted, business logic evaluated the cross-company uniqueness of the barcode, gathered the additional meta data and inserted this data into a custom interface table when evaluated positively. The result: fast interface export.&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/2.-Custom-interface-table-based-on-event-trigger.jpg&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/2.-Custom-interface-table-based-on-event-trigger.jpg&quot; alt=&quot;Custom interface table based on event trigger&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Management-by-exception and 1-click troubleshooting&lt;/strong&gt;&lt;br&gt;While building experience with AX7 Data Management, my customer quickly came up with feedback that they expected a dashboard showing all exceptions and 1-click troubleshooting capabilities. So I analyzed their requirements versus the current AX7 Data Management capabilities by creating a diagram highlighting the steps required to troubleshoot the most common scenarios:&lt;br&gt;&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/3.-Diagram-of-troubleshooting-in-AX7-Data-Management.jpg&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/3.-Diagram-of-troubleshooting-in-AX7-Data-Management.jpg&quot; alt=&quot;Diagram of troubleshooting in AX7 Data Management&quot;&gt;&lt;/a&gt;&lt;br&gt;My main conclusions:&lt;br&gt;• It requires a minimum of 3 clicks to retrieve the cause of an error.&lt;br&gt;• There’s no form in the AX7 Data Management area which allows for creating personalized tiles to show interface exceptions.&lt;br&gt;• The &lt;strong&gt;Recent runs&lt;/strong&gt; tabbed list on the &lt;strong&gt;IT data management&lt;/strong&gt; workspace does not provide a complete overview of meta data – Some critical information is missing, for example:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;The list does not show the number of records in the source file, so it is difficult to identify source to staging errors.&lt;/li&gt;
&lt;li&gt;The list only shows the status for the data job run as a whole, but often a job run concerns multiple data entities, which all have their own individual status.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;• It is not possible to retrieve the original file name in case a file has been uploaded through the Data Management API. Therefore, it is not possible to trace an (erroneous) data job run back to the original uploaded file.&lt;/p&gt;
&lt;p&gt;So I decided to design a new parent-child inquiry form which shows all possible meta data for all interface runs:&lt;br&gt;&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/4.-Custom-AX7-data-management-interface-job-execution-details-form.jpg&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/4.-Custom-AX7-data-management-interface-job-execution-details-form.jpg&quot; alt=&quot;4. Custom AX7 data management interface job execution details form&quot;&gt;&lt;/a&gt;&lt;br&gt;As it is an inquiry form, the user has the ability to create a personalized filter on a single interface, group of interfaces in any status or group of statuses. As per standard AX7 functionality, the filter can be turned into a tile which can be placed on any workspace and pinned to the main dashboard:&lt;br&gt;&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/5.-AX7-Data-Management-interface-exceptions.png&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/5.-AX7-Data-Management-interface-exceptions.png&quot; alt=&quot;AX7 Data Management interface exceptions&quot;&gt;&lt;/a&gt;&lt;br&gt;So in case an exception occurs, a tile highlighting interface exceptions will show value 1 or higher after refresh. This is the trigger for a system administrator to take action. A click on the tile will directly show the exception in the interface form. By the meta data in the form the system administrator will have a good sense about a possible cause, so he can perform a direct click to the relevant error log (execution log or staging table log). So it will only require 2 clicks to inquire the cause of any error. The challenge here then is to get the number of exceptions down to 0 again after fixing the issue and re-running the respective data job.. ;-).&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;&lt;strong&gt;Staging table errors in outbound interfaces&lt;/strong&gt;&lt;br&gt;Some of you might question why it would be needed to set &lt;strong&gt;Skip staging&lt;/strong&gt; to false on a data project – In other words: to utilize the staging table in an outbound interface process. Well.. it is a requirement if you need to run business logic in your outbound interface.&lt;br&gt;Although you need to be careful with the implementation of business logic in outbound interfaces, as this can significantly degcrease the performance of your outbound interface, there are scenarios in which you really need it. For those scenarios you need to be aware that outbound staging to target processes handle errors in a different manner than inbound staging to target processes:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Inbound processes perform validations against standard or custom AX7 business logic. In case of errors, the respective staging record goes into error status and import for the particular record is withheld.&lt;/li&gt;
&lt;li&gt;In outbound processes, custom business logic may put the record into error status, but the export is NOT withheld. AX7 is designed to output the records AS-IS, independent from the status of the record in the staging table.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So if you want to have your outbound staging to target process behave in a similar fashion as your inbound equivalents, here’s my recommendation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implement business logic to validate your data for output as you’d do in an inbound process. So promote your staging records to the status as required.&lt;/li&gt;
&lt;li&gt;Implement a routine to delete all the staging table records which are in error state. This will ensure only records which pass your validations are outputted (if you want to allow any output in case of errors).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a result of this deletion, errors are thrown at &lt;strong&gt;Execution log&lt;/strong&gt; level instead of staging table level:&lt;br&gt;&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/6.-Outbound-staging-errors.jpg&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/6.-Outbound-staging-errors.jpg&quot; alt=&quot;Outbound staging errors&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;&lt;strong&gt;Leveraging the power of XSLT transformations&lt;/strong&gt;&lt;br&gt;In many outbound interface scenarios, AX7 will have to output columns in a certain order or output specific column names. This can all be handled by using sample files in your data project. But if you need more complex transformations, AX7 offers the ability to leverage XSLT transformations. And these can be really powerful. Some examples:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Transform root node and main child node names to reflect the required XML schema. In this example the root node “Document” is transformed to “ItemCatalog” and the child node “&lt;EntityTechnicalName&gt;”&amp;gt; is transformed to “InventTable”.&lt;br&gt;&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/XSLT1.png&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/XSLT1.png&quot; alt=&quot;AX7 Data Management Example XSLT&quot;&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sort all XML elements and values in the output XML alphabetically:&lt;br&gt;&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/XSLT2.png&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/XSLT2.png&quot; alt=&quot;AX7 Data Management Example XSLT&quot;&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Minimize non-auto mappings on a data project&lt;/strong&gt;&lt;br&gt;When I architecting the various interfaces in my project, I was very keen on including value conversions, default values and other transformations in my data project mappings to provide some flexibility for future adjustments. However, I started to lose enthusiasm when I found out that default values and conversions were not allowed for enums. I even decided to completely push all possible transformations to third-party systems when I found out that mappings cannot be migrated at all. Background here is that with every update on a data entity, you might have to do a lot of manual re-mapping across different environments (DEV, TST, UAT) – see learning 1 above.&lt;br&gt;Interesting in this context is that if you open the manifest.xml file from a zipped data package, you hit upon the placeholders for the mappings and transformations. But they’re simply not populated as per the current functionality:&lt;br&gt;&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/7.-Work-package-content.jpg&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/7.-Work-package-content.jpg&quot; alt=&quot;Work package content&quot;&gt;&lt;/a&gt;&lt;br&gt;Therefore, I’d advice (for now) to reduce the use of sample files (non-auto column mappings), default values, transformations and value conversions to a minimum.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Be careful with LOAD PROJECT!&lt;/strong&gt;&lt;br&gt;In most demos I have seen concerning AX7 Data Management, interface imports and exports are always run through the data project’s &lt;strong&gt;Load Project&lt;/strong&gt; feature (System administration &amp;gt; Workspaces -&amp;gt; Select data project &amp;gt; Load project). But what they never tell you in those demos is that this feature can completely screw up your interface mapping without you being aware of it. Some examples:&lt;br&gt;• In case of a component entity, using the Load Project feature will have your child entity mapping removed from the mapping if the child entity is not in the upload file.&lt;br&gt;• If you deleted an auto mapped column from the interface mapping on purpose, the deleted mapping will have been re-created automatically if you upload the file through the Load Project feature.&lt;br&gt;• The Load Project feature will cause a mapping for a particular field to be removed if the field was originally mapped but no longer exists in the source file uploaded.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Hence my recommendation for running interfaces manually is as follow:&lt;br&gt;• Only allow system administrators who know what they’re doing to run interfaces manually through the LOAD PROJECT feature.&lt;br&gt;• Align the third-party software version, samples files used for unit/functional testing and AX7 data entity software version. This will reduce the risk on issues in the Load Project scenario:&lt;br&gt;&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/8.-AX7-Data-Management-Align-software-versions.jpg&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/8.-AX7-Data-Management-Align-software-versions.jpg&quot; alt=&quot;AX7 Data Management - Align software versions&quot;&gt;&lt;/a&gt;&lt;br&gt;• Teach all other users to run interfaces manually through either of the following methods which will never affect the interface mapping:&lt;br&gt;a. The &lt;strong&gt;Run Project&lt;/strong&gt; feature.&lt;br&gt;b. A setup which allows users to drop files in folders which are uploaded and processed through the Data Management API.&lt;/p&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Export data entity field characteristics&lt;/strong&gt;&lt;br&gt;In any integration scenario it is critical to have clear agreement about the interface mapping including the responsibility for data transformations. I always use the following structure for architecting my integrations:&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/9.-Source-to-Target-mapping.jpg&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/9.-Source-to-Target-mapping.jpg&quot; alt=&quot;Source to Target mapping&quot;&gt;&lt;/a&gt;&lt;br&gt;In order to quickly populate the template with the main characteristics of all the data fields in the respective AX7 data entity (field length, field type etc.) I use the following table browser URL: &lt;em&gt;&lt;Your AX7 environment&gt;/Default.htm?mi=SysTableBrowser&amp;amp;prt=initial&amp;amp;cmp=&lt;Company&gt;&amp;amp;tablename=DMFDefinitionGroupEntityXMLFields&amp;amp;limitednav=true&lt;/em&gt; &lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/10.-Data-entity-field-properties.jpg&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/10.-Data-entity-field-properties.jpg&quot; alt=&quot;Data entity field properties&quot;&gt;&lt;/a&gt;  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deprecation of multiple value separator&lt;/strong&gt;&lt;br&gt;In previous versions of AX, a ‘multi-value separator’ (for example “,”) could be defined to allow multiple values in 1 column to be imported/exported. In AX7 this is no longer needed due to ‘normalization’ of the list of data entities. A typical example of the classical multi-value import was for example the store/address book association. In AX7, this association is created through a separate data entity “Retail store address book”:&lt;br&gt;&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/11.-Normalization-of-data-entities.jpg&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/11.-Normalization-of-data-entities.jpg&quot; alt=&quot;Normalization of data entities&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Load monitoring&lt;/strong&gt;&lt;br&gt;By enabling the processing monitoring job on the Recurring data job.. &lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/12.-Enable-process-monitoring-batch-job.png&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/12.-Enable-process-monitoring-batch-job.png&quot; alt=&quot;Enable process monitoring batch job&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;..the Queue trend is populated:&lt;br&gt;&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/13.-Inquire-AX7-Data-Management-queue-trend.png&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/13.-Inquire-AX7-Data-Management-queue-trend.png&quot; alt=&quot;Inquire AX7 Data Management queue trend&quot;&gt;&lt;/a&gt;This enables you to inquire the load and adjust the frequency of the processing job – In case of high Peaks, ensure to run the interface more often to reduce the load per job run:&lt;br&gt;&lt;a href=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/14.-AX7-Data-Management-queue-trend.png&quot;&gt;&lt;img src=&quot;/images/blog/1yr-with-ax7-data-management-my-top-12-learnings/14.-AX7-Data-Management-queue-trend-300x234.png&quot; alt=&quot;AX7 Data Management queue trend&quot;&gt;&lt;/a&gt;&lt;br&gt;12. &lt;strong&gt;Staging table fields versus data source fields&lt;/strong&gt;&lt;br&gt;While architecting interfaces it is important to be aware of the relevance of the difference in scope of data between a data entity and its staging table. For example, you may choose to include additional tables and fields for filtering on the data to be exported, but you may not want to make this data available for export.&lt;/p&gt;
</content:encoded><category>Technicalint</category></item><item><title>AX7 – My top 12 highlights</title><link>https://patrickmouwen.com/blog/ax7-my-top-12-highlights/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/ax7-my-top-12-highlights/</guid><description>Twelve highlights from the AX7 technical conference, and why the release turned out to be far more than a new UI over AX2012 code.</description><pubDate>Sat, 27 Feb 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I onboarded the AX7 technical conference this week with the impression that AX7 was ‘just’ a new UI exposing AX2012R3CU9 code on a new platform with some adjustments to ‘make it work’ on the new Azure platform. But already after the first keynote I felt embarrassed about my initial thoughts which quickly made place for respect and amaze for this enormous leap in technology.&lt;/p&gt;
&lt;p&gt;I can only compare the way Dynamics AX has developed in the last 10 years with a boxing game: initially, the boxers tease and challenge each other by some quick targeted moves. But the game really takes off when one of them finds his ‘punch’ (say with the release of AX2012) The opponent is driven towards the corner of the boxing arena and receives punch after punch, each punch having bigger impact. I think AX7 is at the core of this ‘momentum’. In this blog I’ll share the main ‘punches’ and my personal interpretation of what’s going on. If you want to dig deeper then visit the publicly available &lt;a href=&quot;https://ax.help.dynamics.com/en/&quot;&gt;AX7 wiki.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;AX7: my top 12 highlights&lt;/h2&gt;
&lt;p&gt;1.       &lt;strong&gt;AX7 is a true Saas/Paas platform leveraging the Azure platform natively&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the literal words of Mike Ehrenberg, AX7 is not a ‘lift-and-shift’ of AX2012R3CU9: simply shifting the on premise platform to the cloud, as many competitors have done. Instead, Microsoft managed to separate the AX7 application layer and platform layer which allows AX7 to run on native Azure technology. So the many future Azure enhancements ahead will directly impact AX7 positively. With SQL Server, this was an exciting journey as only from CTP6 Microsoft was able to run SQL Server natively on an Azure VM.&lt;/p&gt;
&lt;p&gt;2.       &lt;strong&gt;AX7 is Microsoft-wide achievement&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When Steve Jobs and Bill Gates ignited Silicon Valley with their innovations, they could achieve a lot with a very small team of people. Now with AX7, the AX7 ‘pyramid’ is constructed from many already giant pyramids, ranging from SQL Server technology to Azure to BI technology. Each ‘pyramid’ has its own big team of experts. It’s amazing how Microsoft has managed to blend all these broad specialisms into the AX7 product.&lt;/p&gt;
&lt;p&gt;3.       &lt;strong&gt;With the AX7 release is not incorporating new technology but driving new technology&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With AX7 being a cloud-first platform fully in line with Microsoft CEO Satya Nadella’s focus for service orientation, The new Dynamics is now fully in the spotlights within Microsoft. Beyond that, AX7 is on a path where it drives the other Microsoft teams to enhance, instead of ‘just’ incorporating existing technologies in new releases. A good example is real time analytics. With the market demand for real-time analytics, AX had to move away from non-real time data warehousing and SSAS technologies in favor of the new read-only secondary database (replicated in seconds) and AX entity database (replicated in minutes). Instead, AX required new technology to allow true real-time analytics. This technology was found in new SQL Server 2016 in-memory technology, leveraging indexing on columns instead of the conventional row-based indexing.&lt;/p&gt;
&lt;p&gt;4.       &lt;strong&gt;Enriching AX functionality exactly according to market demand&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AX7 has been developed with more customer, partner and ISV involvement than ever. But that’s something that could have been done 10 years ago. The new thing here is that telemetry data is collected from actual AX7 usage. Based on already available data up to the recent RTW release, Microsoft has been able to identify exactly which areas of AX are used most and which areas have been customized most. This enables targeting all available development capacity spot on. Can you imagine what will happen if AX7 is enrolled to thousands of customers worldwide?&lt;/p&gt;
&lt;p&gt;5.       &lt;strong&gt;The visible part of the iceberg is getting smaller&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With the release of AX7, the production environment will no longer be accessible by customers or partners. Microsoft ‘frees’ the customers and partners from the responsibility to maintain this environment, to apply patches and – again in the words of Mike Ehrenberg – to allow the partners and customers to focus more on unleashing the potential of the software for their respective business instead of being bothered by ‘low-value’ activities. I prefer to use the metaphor of an iceberg in the water to express what is going on: the part of the iceberg which is really visible and tangible (the part above the water) gets smaller and smaller and the part under water bigger and bigger. In other words: less effort and ‘hassle’ against maximum value and service.&lt;/p&gt;
&lt;p&gt;6.       &lt;strong&gt;AX7 resolves many implementation pain points&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With AX7 Microsoft truly expresses an ongoing focus for shortening the AX implementation cycle. Many pain points are now solved by Microsoft:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fast code deployment: the application code base has now been split up in multiple models. Code can now be compiled and deployed in smaller chunks and in a much faster way.&lt;/li&gt;
&lt;li&gt;Easier code upgrades: the conventional ‘layering’ option is still there, but custom code can now be implemented as an extension (applicable to not all but many AOT elements). As such, the extension is completely segregated from the out-of-the-box code base, which makes customizations much more flexible, especially regarding future upgrade scenarios.&lt;/li&gt;
&lt;li&gt;Shipping of configuration data among environments: with so called data packages (a collection of data entities which are an aggregated collection of tables and views), sets of data can easily be shipped across different environments. Optionally the data in the data package can be edited in Excel prior to deployment as the data package is physically nothing more than a zipped collection of Excel files added up with a header and manifest XML. So called ‘process data packages’ can even associate a data package with a specific process in the LCS process library. You can have a new sales order posted in a brand new originally empty environment in minutes.&lt;/li&gt;
&lt;li&gt;Multi-purpose task recorder: the new task recorder can record tasks in AX not only to train people on any task in the software (including interactive guided clicking), but can also be used to automate testing. The recorded tasks (including the data captured) can be made part of new software builds to automatically regression test the build before deployment.&lt;/li&gt;
&lt;li&gt;Retail: activation of a cloud-POS or mPOS device can now be done through an easy-to-use wizard. As there’s only 1 channel database for all your channels in the new cloud topology, the wizard preopulates the channel database URL and also the stores the device can be associated for (based on the Azure AAD user &amp;gt; worker &amp;gt; store address book &amp;gt; store association).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;7.       &lt;strong&gt;Life Cycle Services (LCS) is no longer a recommendation but a requirement&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In many ways adoption of life cycle services can no longer be avoided. Some scenarios to highlight this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As AX7 no longer provides access to production environments, the telemetry LCS offers is crucial in identifying issues. Then consecutively, LCS is leveraged to quickly deploy a representative environment, load relevant reference test data and simulate the issue with a task recording.&lt;/li&gt;
&lt;li&gt;Data packages and other assets are all stored in the LCS Asset Library. LCS is the central repository for storage and deployment across the various environments. LCS has a hierarchical structure: a ‘corporate’ section which allows re-using ‘assets’ among different projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;8.       &lt;strong&gt;Support 2.0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AX7 re-defines the way you can support your users. Having your users record the issue they face through the task recorder is one thing. Being able to create a ticket from AX7 which is directly converted into a Visual Studio work item for the support engineer is another thing. But the earth shaking thing here is the available telemetry for the support engineer: as AX7 continuously logs system performance and system activity along the way, the work item is automatically enriched with a ‘snapshot’ of the state of the system at the time the issue occurred: what browser did the user utilize, what batch jobs were running, what was the user doing exactly etc.&lt;/p&gt;
&lt;p&gt;9.       &lt;strong&gt;Business process orientation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Although I think the business process repository on LCS could be organized and incorporated in a better way, the AX7 UI offers a brilliant new way its application functionality is exposed to the business users: workspaces. Conceptually the workspaces have many similarities with the good old role centers: tiles are the new cues, tabbed lists are the old enterprise portal enabled listpages (although the new ‘tab’ structure is very handy) and charts and links can be embedded as role center offered (although far more sophisticated now). However, a user can now be offered a numerous number of workspaces, all supporting a specific set of tasks related to a process the user is affiliated with. The set of workspaces together forms the user’s dashboard.&lt;/p&gt;
&lt;p&gt;10.   &lt;strong&gt;New features&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OK, they might have become a bit less prominent because of the other hot topics mentioned, but AX7 still offers some great new features – a glimpse of the less prominent features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Finance: cross company general journal entry: creating and posting journals without having to switch companies.&lt;/li&gt;
&lt;li&gt;Retail: being able to download updates to mPOS from the device form directly (self-service installer). Process: a new update is made available by IT and a store manager can download and run the update package locally in the store.&lt;/li&gt;
&lt;li&gt;Enterprise search and ribbon search: just type ALT+G to open enterprise search and then type “U C”. AX7 will come up with “Unit Conversion” immediately – one click and you’re in the form. You can even navigate to other pages by simply changing the URL. Type ALT+Q and you can search for a specific function in the ribbon, regardless of the tab group the function belongs to.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;11.   &lt;strong&gt;The cloud: a new way of thinking&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With the actual AX7 cloud release you have to be aware that basic on-premise functions have suddenly become a challenge. Here’s a shortlist of challenges and the way Microsoft managed to tackle those:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Accessing on-premise files and folders is not possible from the cloud: AX can no longer poll on-premise folders and pull-in files for processing, for example in recurring integration scenarios. Instead, files have to be pushed into the cloud. Here’s how: Microsoft has exposed an API which allows a source system to push a file into Azure blob storage accompanied by an enqueuing message which flags a recurring AX batch job that there’s a file to be processed. Microsoft will ship an application to do the enqueuing (and similar dequeuing for exports) on behalf of the source (or target) application. This application will be able to work with processing folders (IN, ERROR, COMPLETED etc.) as many customers were used to with the DIXF batch job (see this &lt;a href=&quot;https://kurthatlevik.wordpress.com/2015/08/21/dax2012r3cu9-dixf-automate-importexport-without-customizations/&quot;&gt;blog post by Kurt Hatlevik&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Printing on local network printers is not possible from the cloud. Again, we need an on-premise pull mechanism here. For this case Microsoft will ship a ‘document routing agent’ which will query an Azure queue for messages which contain meta data for new documents to be printed (stored in Azure blob storage). Network printers can be configured on a specific form in AX7 which will allow the Azure queue message to contain meta data which printer the ‘document routing agent should send the document to.&lt;/li&gt;
&lt;li&gt;Hot keys: the different browsers have different reserved hot keys. To stay as much in line as possible with current hot keys users are familiar with, Microsoft had to be creative. For example, the ‘new record’ hot key CTRL+N has now been replaced by ALT+N, which is still pretty familiar for hot key addicts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;12.   &lt;strong&gt;Relatively low threshold for adopting AX7&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It’s a challenge to develop and release a new product which involves so many paradigm shifts. But it’s pretty handsome if you manage to make the adoption of the new product still relatively easy – very important when it comes to minimizing costs for existing partners to make the shift and minimizing costs for customers to upgrade. Why I do consider the AX7 adoption to be relatively easy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Developers will have to embrace Visual Studio, the AOT is re-arranged a bit and developers have to get used to work with the extensions and file based code and packages. But X++ is rather untouched (only enriched at some points) and for those who have some Visual Studio experience, a lot of ‘new’ things is actually common to .NET/Visual Studio in general.&lt;/li&gt;
&lt;li&gt;Yes, the cloud environment requires a new way of thinking as stated in the latter point, but many things will be managed by Microsoft ‘under water’. As always, understanding the concept is much easier than having to become a specialist in an area.&lt;/li&gt;
&lt;li&gt;With the earlier CTPs operating the new AX7 UI was a bit different than the familiar AX2012 navigation. But with RTW the similarities are very clear again. The area pages are back in town for those who worship them, form dynalinking (selecting a different record in the listpage is reflected in a details form) is working flawlessly and the good old ribbon and favorites are still there.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I hope this post inspired you to embrace the new AX7 features without any fear to make the jump.&lt;/p&gt;
&lt;p&gt;Happy renewed DAX’ing.&lt;/p&gt;
&lt;p&gt;Patrick&lt;/p&gt;
</content:encoded><category>Functional</category></item><item><title>Dynamics AX Retail: how to automate processes and interfaces in a combined way</title><link>https://patrickmouwen.com/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/</guid><description>How to combine standard Dynamics AX components so that business processes and the interfaces around them run automatically as one flow.</description><pubDate>Wed, 23 Dec 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Business processes and interfaces often go hand in hand: it’s often either a business event triggering an interface or a business event following up on incoming interface data. For example: automatically creating pick orders and updating the related order statuses in the e-commerce frontend. In our aim for maximum comfort for both the business user as well as the system administrator, how can we automate this type of business events and interfaces in a combined way?&lt;/p&gt;
&lt;p&gt;In this blog post I’ll boil the necessary standard AX ingredients into a configuration which allows you to reach this goal. I’ll also show you how to leverage this configuration to completely automate the following example flows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flow 1: importing transactions from a (third-party) sales channel, converting the transactions to sales orders and sending an acknowledgement to the channel that the order import was successful or unsuccessful.&lt;/li&gt;
&lt;li&gt;Flow 2: updating the on hand stock for the different channels and sending the stock levels to the sales channels.&lt;/li&gt;
&lt;li&gt;Flow 3: creating picking lists for the incoming orders and informing the sales channel on the ‘picking’ status.&lt;br&gt;When you have this running, it’s like simulating a factory with Lego: when your order pickers come in in the morning they’ll find the picking lists on the printer; the sales channels can work with the latest stock levels and order statuses and by leveraging role center your system administrator sits in his control room waiting for any exception to occur which requires intervention – Sounds almost like a real factory… right?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Example scenario&lt;/h2&gt;
&lt;p&gt;Below you find an overview of the example scenario for this blog post with the 3 flows mentioned – I highlighted the manual and automated tasks in blue/red respectively and painted processes and interfaces as solid lines/dotted lines respectively.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/1.-Dynamics-AX-Retail-Automate-process-and-interfaces.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/1.-Dynamics-AX-Retail-Automate-process-and-interfaces.jpg&quot; alt=&quot;Dynamics AX Retail - Automate process and interfaces&quot;&gt;&lt;/a&gt;In this particular example, the (third-party) sales channel has some specific requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It requires to receive an acknowledgement if sales order creation in AX was successful or not.&lt;/li&gt;
&lt;li&gt;It requires to receive stock updates at least every 5 minutes.&lt;/li&gt;
&lt;li&gt;It requires to receive information that the picking process for the items has started. This information is then available in the customer’s ‘My account’ section on the online store and is sent to the customer by SMS.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;AX ingredients to automate&lt;/h2&gt;
&lt;p&gt;The ones of you with AX/Retail background will probably recognize how the different tasks in the example scenario can be supported by standard AX/Retail batch jobs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The interface flows 1A, 1C, 2B and 3B can be supported by &lt;strong&gt;Retail Distribution Schedules&lt;/strong&gt; (&lt;strong&gt;Retail &amp;gt; Periodic &amp;gt; Data distribution &amp;gt; Distribution schedule&lt;/strong&gt;), although they might have to be custom configured. The distribution schedules are to be configured as batch jobs.&lt;/li&gt;
&lt;li&gt;The transaction to sales order conversion can be supported by the &lt;strong&gt;Synchronize online orders&lt;/strong&gt; batch job for e-commerce (&lt;strong&gt;Retail &amp;gt; Periodic &amp;gt; Synchronize online orders&lt;/strong&gt;) or the &lt;strong&gt;Post statement&lt;/strong&gt; batch job (&lt;strong&gt;Retail &amp;gt; Periodic &amp;gt; POS posting &amp;gt; Post statement&lt;/strong&gt;) for POS. In this case we work with the Synchronize online orders batch job as in the example scenario we have to pick order placed at the online store.&lt;/li&gt;
&lt;li&gt;Creating pick orders can be automated in multiple ways but in this case we leverage the &lt;strong&gt;Picking workbench&lt;/strong&gt; (&lt;strong&gt;Inventory management &amp;gt; Periodic &amp;gt; Picking workbench &amp;gt; Picking workbench&lt;/strong&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Important to notice here on the side is that both the &lt;strong&gt;Synchronize online orders&lt;/strong&gt; batch job as well as the &lt;strong&gt;Picking workbench&lt;/strong&gt; will try to reserve items automatically, independent from the settings in the &lt;strong&gt;Accounts Receivable parameters&lt;/strong&gt; &lt;strong&gt;(&amp;gt; General &amp;gt; Sales &amp;gt; Reservation&lt;/strong&gt;) which might be on &lt;strong&gt;Manual&lt;/strong&gt;. For this reason, and for the reason that picking will be tied to one specific point of time (for example 7AM),  as opposed to the other batch tasks which will run periodically throughout the day, the 3 different ‘flows’ (combinations of business event and interface) are to be scheduled in their own frequency. This also provides the opportunity for an order manager to allocate additional on hand stock to fulfill open order requirements which failed to claim stock at import before the picking workbench runs automatically.&lt;/p&gt;
&lt;p&gt;So… from helicopter perspective AX has a pretty good coverage, right? But we need to bundle the automated tasks in 3 groups which can be scheduled in their own frequency, instead of having to manage 7 batch jobs which are to be aligned in timing individually. How do we organize that?&lt;/p&gt;
&lt;h2&gt;Towards a solution&lt;/h2&gt;
&lt;p&gt;From the requirements stated above we can distill that we need the following configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 batch jobs for flow 1 and 2, to be scheduled periodically with high frequency (for example every 5 minutes)&lt;/li&gt;
&lt;li&gt;1 batch job for flow 3, to be scheduled periodically with low frequency (once or twice a day at fixed points of time)&lt;/li&gt;
&lt;li&gt;Multiple batch tasks per batch job, to be run sequentially.&lt;/li&gt;
&lt;li&gt;Custom distribution schedules to support our interface flows, to be run as batch tasks. Assumption: we leverage standard &lt;strong&gt;AX/Retail CDX&lt;/strong&gt; for interfacing, so we ship data in/out through the &lt;strong&gt;AX channel database&lt;/strong&gt; for the sales channel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Point 4 can be covered by defining new or updated &lt;strong&gt;Distribution schedules&lt;/strong&gt; supported by new or updated &lt;strong&gt;scheduler job&lt;/strong&gt; definitions. As an example for element 3A (Send pick status/information) of the example scenario above:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/2.-Distribution-schedule-Pick-order.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/2.-Distribution-schedule-Pick-order.jpg&quot; alt=&quot;Distribution schedule - Pick order&quot;&gt;&lt;/a&gt;Points 1 and 2 are covered by the standard AX batch framework (&lt;strong&gt;System administration &amp;gt; Inquiries &amp;gt; Batch jobs &amp;gt; Batch jobs&lt;/strong&gt;) which offers the ability to define standard recurrence patterns. Example batch job for flow 3:&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/3.-Batch-job.png&quot; alt=&quot;Batch job&quot;&gt;The difficulty in is point 3. For being able to schedule the batch jobs as separate batch tasks under the umbrella of one batch job, three things need to be arranged:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Customization part 1: batch class adjustment. The respective business logic is to be enabled for running as a batch task. In AX 2012 R3 there are two main ways of developing batch classes:&lt;ul&gt;
&lt;li&gt;Through extending the &lt;strong&gt;RunBaseBatch&lt;/strong&gt; framework: the ‘classical’ framework.&lt;/li&gt;
&lt;li&gt;Through extending the &lt;strong&gt;SysOperation&lt;/strong&gt; framework: the framework introduced with AX 2012 which is recommended by Microsoft.&lt;br&gt;All current Retail batch jobs (my reference version: AX2012R3CU8) (still) rely on the RunBaseBatch framework. In this framework, batch classes can be enabled for running as batch tasks by setting the CanGoBatchJournal method to return TRUE – Here’s an example for the RetailCDXScheduleRunner which contains the business logic for running the Distribution schedules in batch:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/4.-CanGoBatchJournal-example.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/4.-CanGoBatchJournal-example.png&quot; alt=&quot;CanGoBatchJournal example&quot;&gt;&lt;/a&gt;Note: if this method is not added or returns FALSE, the batch class is simply not selectable as batch task under a batch job.&lt;br&gt;Note 2: you may have noticed that for some Retail batch jobs, Microsoft has added the &lt;strong&gt;CanGoBatchJournal&lt;/strong&gt; method in AX 2012 R3.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Customization part 2: passing parameters to the batch task. As a batch class is sometimes built upon an existing form which is designed to pass parameters to the batch class (in the example above: a parameter which indicates which distribution schedule to run), it is not always possible to set the right parameters in the context of the batch job configuration form. See below for an example of this issue: the &lt;strong&gt;Distribution schedule&lt;/strong&gt; form (&lt;strong&gt;Retail &amp;gt; Periodic &amp;gt; Data distribution &amp;gt; Distribution schedule&lt;/strong&gt;) passes the selected distribution schedule as a parameter to the batch form when configuring a batch job. In the &lt;strong&gt;Batch tasks&lt;/strong&gt; form (&lt;strong&gt;System administration &amp;gt; Inquiries &amp;gt; Batch jobs &amp;gt; View tasks&lt;/strong&gt;; see figure below), this parameter cannot be set (only consulted). So in areas where the batch class parameterization relies on existing forms, some controls and business logic have to be added to enable the batch class to receive the right parameter values.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/5.-Distribution-schedule-Run-as-batch-job.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/5.-Distribution-schedule-Run-as-batch-job.png&quot; alt=&quot;Distribution schedule - Run as batch job&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/6.-Parameter-on-batch-task.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/6.-Parameter-on-batch-task.png&quot; alt=&quot;Parameter on batch task&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Additional configuration. In our example scenario as described above, we have to enforce the tasks to run sequentially. But how? Standard AX provides some tools here:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Batch task conditions&lt;/strong&gt;. On the batch task we can configure AX to run task 2 after successfully finishing task 1. Here’s an example for our flow 3 above:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/7.-Batch-task-conditions.png.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/7.-Batch-task-conditions.png.jpg&quot; alt=&quot;Batch task conditions.png&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Server configuration&lt;/strong&gt;. When applying batch task conditions you’ll notice that some batch tasks (for example a Retail Distribution schedule) create subtasks which cannot be conditioned. So if Task 1 creates a subtask 1a, then task 2 could already start running in a separate (parallel) thread. Therefore, to force AX to run the main tasks sequentially, the number of threads on the batch Server configuration (System administration &amp;gt; Setup &amp;gt; System &amp;gt; Server configuration should be put down to 1 – Note that &lt;strong&gt;Maximum batch threads&lt;/strong&gt; indicates the number of tasks AX can potentially execute &lt;em&gt;in parallel per batch job&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/8.-Server-configuration.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/8.-Server-configuration.jpg&quot; alt=&quot;Server configuration&quot;&gt;&lt;/a&gt;Note: the batch tasks which are to be enforced to run sequentially, need to be allocated to the batch server with &lt;strong&gt;Maximum batch threads&lt;/strong&gt; = 1 setting specifically:&lt;br&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/10.-Allocate-batch-task-to-batch-group.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/10.-Allocate-batch-task-to-batch-group.jpg&quot; alt=&quot;Allocate batch task to batch group&quot;&gt;&lt;/a&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/9.-Batch-framework.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/9.-Batch-framework.png&quot; alt=&quot;Batch framework&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Customization part 3&lt;/strong&gt;. Even with the configuration under point 2 we are still not fully sure tasks will run sequentially. Some tasks are running in CIL (Common Intermediate Language) and cannot be checked for completion by AX; AX considers the tasks to be done when handed over to CIL and will use the thread for the next task. In other words: neither batch task conditions nor server configuration will work. In the example of task 1 being executed in CIL, the only thing I could think of was to implement a pause to make sure task 1 is finished before task 2 takes off. I’ve built this ‘pause’ in the form of a custom batch enabled class which allows me to set a number of seconds of pause before continuing to the next task – it’s not ideal, but with some testing it does its job perfectly. Here’s the code in the run method of the RunBaseBatch based &lt;strong&gt;BatchPause&lt;/strong&gt; class (parameter: secondsPause):&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;public void run()&lt;br&gt;{&lt;br&gt;int i;&lt;br&gt;;&lt;br&gt;try&lt;br&gt;{&lt;br&gt;i=sleep(secondsPause*1000);&lt;br&gt;}&lt;br&gt;catch(Exception::Deadlock)&lt;br&gt;{&lt;br&gt;retry;&lt;br&gt;}&lt;br&gt;catch(Exception::UpdateConflict)&lt;br&gt;{&lt;br&gt;throw Exception::UpdateConflict;&lt;br&gt;}&lt;br&gt;catch&lt;br&gt;{&lt;br&gt;throw Exception::Error;&lt;br&gt;}&lt;br&gt;}&lt;/p&gt;
&lt;p&gt;This business logic can then be used in the form of an additional batch task to pause the batch job for the number of seconds specified; here’s is an example for flow 1:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/11.-Batch-job-pause.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/11.-Batch-job-pause.jpg&quot; alt=&quot;Batch job - pause&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;The cherry on the cake&lt;/h2&gt;
&lt;p&gt;Configuring the batch framework as described above adds another level of abstraction to the already powerful Retail CDX management framework in the Retail module. But when you top it off with a dedicated role center configuration, you can make a serious step towards &lt;em&gt;Management by exception&lt;/em&gt; across the board. To stay with the example above, at business side you could implement an ‘exception cue’ for all orders which could not be directly fulfilled at import (flow 1A):&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/12.-AX-role-center-Business-Management-by-exception.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/12.-AX-role-center-Business-Management-by-exception.jpg&quot; alt=&quot;AX role center - Business - Management by exception&quot;&gt;&lt;/a&gt;&lt;br&gt;At IT management side you could implement an ‘exception cue’ for all (Retail) batch jobs errors. Clicking this cue will allow you to quickly descend into more details and solve the errors quickly and effectively:&lt;a href=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/13.-AX-role-center-Batch-jobs-Management-by-exception.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/13.-AX-role-center-Batch-jobs-Management-by-exception.jpg&quot; alt=&quot;AX role center - Batch jobs - Management by exception&quot;&gt;&lt;/a&gt;&lt;br&gt;I hope this has given you an impression on how you can create sets of interrelated automated tasks, whether having a business or integration background, to simplify the management of your complete solution and maximize comfort for your business and IT users.&lt;/p&gt;
&lt;p&gt;Happy DAX’ing and happy holidays!&lt;/p&gt;
&lt;p&gt;Patrick&lt;/p&gt;
</content:encoded><category>Process</category></item><item><title>Financial dimensions on web orders vs non-Retail orders</title><link>https://patrickmouwen.com/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/</guid><description>Why financial dimension values differ between B2C web orders and non-Retail B2B orders in the same company, and what that breaks at invoicing.</description><pubDate>Tue, 27 Oct 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Say we have non-Retail B2B sales and B2C weborders in 1 company. We sell the same items through these channels. We expect the financial dimension values for the same financial dimensions to appear on our order lines but… they differ between these scenarios… HUH?&lt;a href=&quot;/images/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/1.-Microsoft-Dynamics-AX-Financial-dimensions-on-sales-order.jpg&quot;&gt;&lt;img src=&quot;/images/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/1.-Microsoft-Dynamics-AX-Financial-dimensions-on-sales-order.jpg&quot; alt=&quot;Microsoft Dynamics AX Financial dimensions on sales order&quot;&gt;&lt;/a&gt;And at invoicing we get stuck (posting is cancelled) as in the B2C scenario we miss a mandatory financial dimension value CostCenter… ARGGGGG!&lt;/p&gt;
&lt;h2&gt;Cause&lt;/h2&gt;
&lt;p&gt;For the cause of this issue we have to dig into the way the financial dimensions are inherited in each scenario. Here’s what happens in both scenarios:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/2.-Microsoft-Dynamics-AX-Financial-dimension-inheritance.jpg&quot;&gt;&lt;img src=&quot;/images/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/2.-Microsoft-Dynamics-AX-Financial-dimension-inheritance.jpg&quot; alt=&quot;Microsoft Dynamics AX Financial dimension inheritance&quot;&gt;&lt;/a&gt;In both scenarios the sales order header inherits its financial dimension values from a main entity: in the Retail web order scenario that’s the Retail channel, whereas the customer is the main entity in the non-Retail sales scenario (criterion for ‘being’ a non-Retail sales order: &lt;strong&gt;RetailSalesTable.RetailOrder == NoYes::No&lt;/strong&gt;). This difference makes sense as in the Retail scenario you might want to keep track of the sales channel your actual sale originated from.&lt;/p&gt;
&lt;p&gt;But there’s one major difference between the scenarios when it comes to sales order header to sales order line inheritance: in the non-Retail case, the financial dimension values on the sales order header and item level are both (&lt;em&gt;AND&lt;/em&gt;) inherited to the sales order line. In the Retail web order case it’s a case of &lt;em&gt;OR&lt;/em&gt;: if the item contains default dimension values, then these are copied to the sales order level, otherwise the sales order line inherits the sales order header dimension values.&lt;/p&gt;
&lt;h2&gt;Solution&lt;/h2&gt;
&lt;p&gt;For non-Retail sales, the inheritance happens as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;\Classes\SalesLineType\InitFromSalesTable&lt;/strong&gt; (inherit from SO header to SO line):&lt;br&gt;&lt;a href=&quot;/images/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/4.-Inherit-dimension-values-from-sales-order-to-sales-line.jpg&quot;&gt;&lt;img src=&quot;/images/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/4.-Inherit-dimension-values-from-sales-order-to-sales-line.jpg&quot; alt=&quot;Inherit dimension values from sales order to sales line&quot;&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;\Classes\SalesLineType\InitFromInventTable&lt;/strong&gt; (inherit from item to SO line):&lt;a href=&quot;/images/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/3.-Inherit-dimension-values-from-item-to-sales-line.jpg&quot;&gt;&lt;img src=&quot;/images/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/3.-Inherit-dimension-values-from-item-to-sales-line.jpg&quot; alt=&quot;Inherit dimension values from item to sales line&quot;&gt;&lt;/a&gt;&lt;br&gt;So, the actual magic is in the &lt;strong&gt;salesLine.mergeDimension&lt;/strong&gt; method. Here’s where the &lt;em&gt;AND&lt;/em&gt; card is played.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In my customer’s scenario it was important to align the two cases so the &lt;strong&gt;Account structures&lt;/strong&gt; setup in &lt;strong&gt;General ledger&lt;/strong&gt; could be consistent in terms of mandatory financial dimensions. Therefore I decided to apply the merge to the Retail web order area as well – It also makes the situation more consistent in general. For the Retail web orders the financial dimension values are set as part of the &lt;strong&gt;Retail &amp;gt; Periodic &amp;gt; Synchronize online orders&lt;/strong&gt; batch job. The applied business logic resides in the &lt;strong&gt;RetailOrderManager::createEachOrderLine&lt;/strong&gt; method. So in order to align the cases I only needed to call the &lt;em&gt;Merge&lt;/em&gt; functionality in this context as well. A change of only 2 lines of code:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/5.-Inherit-dimension-values-from-sales-order-and-item.jpg&quot;&gt;&lt;img src=&quot;/images/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/5.-Inherit-dimension-values-from-sales-order-and-item.jpg&quot; alt=&quot;Inherit dimension values from sales order and item&quot;&gt;&lt;/a&gt;&lt;br&gt;One last addition to this: if you look at how financial dimensions are set on customer orders (created from Retail POS through Real Time Service) and sales orders which are created through Retail POS statement posting, then we see another variant (&lt;strong&gt;RetailOrderManager::mergeOrderDefaultDimension&lt;/strong&gt;):&lt;br&gt;&lt;a href=&quot;/images/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/6.-Inherit-dimension-values-for-customer-order.png&quot;&gt;&lt;img src=&quot;/images/blog/financial-dimensions-on-web-orders-vs-non-retail-orders/6.-Inherit-dimension-values-for-customer-order.png&quot; alt=&quot;Inherit dimension values for customer order&quot;&gt;&lt;/a&gt;In this context, financial dimensions are set on sales order &lt;em&gt;header&lt;/em&gt; level as a hierarchical merge of even 4 dimensions: customer, Retail store, Retail terminal and worker. You’d better be aware of all these variants when setting up AX financially ;-).&lt;/p&gt;
&lt;p&gt;Happy DAX’ing!&lt;/p&gt;
&lt;p&gt;Patrick&lt;/p&gt;
</content:encoded><category>Functional</category></item><item><title>Dynamics AX Retail third-party POS and e-commerce integration – Control dashboard</title><link>https://patrickmouwen.com/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/</guid><description>A control dashboard for Dynamics AX Retail third-party integration, built on the standard download and upload session forms.</description><pubDate>Sun, 18 Oct 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In my main &lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/&quot;&gt;blog post&lt;/a&gt; regarding Dynamics AX Retail/third-party integration I mentioned leveraging Real Time Service to allow middleware (like Microsoft BizTalk) and third-party systems to report to AX on the results of their actions. As the meta data is written into the standard Dynamics AX Retail &lt;strong&gt;download sessions&lt;/strong&gt; and &lt;strong&gt;upload sessions&lt;/strong&gt; forms, these forms will now serve system administrators to have visibility and control even beyond their the Dynamics AX Retail CDX landscape (CDX -&amp;gt; see rectangle in the middle, beyond CDX -&amp;gt; bottom rectangle):&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/1.-Microsoft-Dynamics-AX-Retail-CDX-meta-data.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/1.-Microsoft-Dynamics-AX-Retail-CDX-meta-data.png&quot; alt=&quot;Microsoft Dynamics AX Retail - CDX meta data&quot;&gt;&lt;/a&gt;&lt;br&gt;In this blog I’ll provide the X++ source code to enable this and I’ll mention some tiny features I added to the &lt;strong&gt;download sessions&lt;/strong&gt; and &lt;strong&gt;upload sessions&lt;/strong&gt; forms to maximize control on our third-party integration. First I’ll introduce you to the topic by explaining a bit more on how to extend Real Time Service for access from third-party systems.&lt;/p&gt;
&lt;h2&gt;How to extend Real Time Service&lt;/h2&gt;
&lt;p&gt;What I like most about Real Time Service is that it provides a single-point-of-access to any method in AX from the outside world. With ‘single-point-of-access’ I mean that with Real Time Service we don’t need to expose an endless number of services if for example we want to get customer information, create a customer and cancel an order – we can stick to 1 service only as the AX method we want to call into through the service is a parameter on the service. So if we want to create a customer in AX we tell the service to invoke the &lt;strong&gt;RetailTransactionService::newCustomer&lt;/strong&gt; method and we provide the service with the input parameters the respective method in AX expects:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/2.-Microsoft-Dynamics-AX-Retail-RTS-XML.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/2.-Microsoft-Dynamics-AX-Retail-RTS-XML.png&quot; alt=&quot;Microsoft Dynamics AX Retail - RTS XML&quot;&gt;&lt;/a&gt;&lt;em&gt;Message for calling the Real Time Service (newCustomer method) = The “sender”&lt;/em&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/3.-Microsoft-Dynamics-AX-Retail-RTS-customization.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/3.-Microsoft-Dynamics-AX-Retail-RTS-customization.png&quot; alt=&quot;Microsoft Dynamics AX Retail - RTS customization&quot;&gt;&lt;/a&gt;&lt;em&gt;AX HQ newCustomer method = The “receiver”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So basically you can call into any method in AX from third-party systems just by passing the right parameters and sending the information in the right message format. In a later blog I’ll provide more details in this particular area – for now I stick to mentioning some basic ‘rules of play’:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Real Time Service is designed to call into the &lt;strong&gt;RetailTransactionService&lt;/strong&gt; and &lt;strong&gt;RetailTransactionServiceEx&lt;/strong&gt; classes in AX by default. Although even this is configurable in the web.config file of the RealTimeService application on IIS, I’d stick to this standard. In practice this will never block you from leveraging any method in AX. Just follow the path Microsoft is on since the AX 2012 R3 release, to leverage the methods in the RetailTransactionService and RetailTransactionServiceEx classes only as ‘gateway’ to other classes not including any business logic in itself. It basically comes down to the following structure (see left hand side):&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/4.-Microsoft-Dynamics-AX-Retail-RTS-architecture.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/4.-Microsoft-Dynamics-AX-Retail-RTS-architecture.jpg&quot; alt=&quot;Microsoft Dynamics AX Retail - RTS architecture&quot;&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Before going into customization, carefully check the richness of the current &lt;strong&gt;RetailTransactionService&lt;/strong&gt; class first. Microsoft has exposed more than 100 Retail related methods packed with business logic through this class. So the most common Retail operations (which are normally exposed to the native AX channels ;-)) are available. In general, it’s easy to expose existing business logic by just creating a custom ‘gateway’ method to call into existing business logic. So rule of thumb should be that minimal coding is required, otherwise you might have chosen the wrong path.&lt;/li&gt;
&lt;li&gt;Put all custom (‘gateway’) methods in the &lt;strong&gt;RetailTransactionServiceEx&lt;/strong&gt; classes. Invoking these methods is nothing different than invoking the methods in the &lt;strong&gt;RetailTransactionService&lt;/strong&gt; class except for replacing the node &lt;strong&gt;InvokeMethod&lt;/strong&gt; by &lt;strong&gt;InvokeExtensionMethod&lt;/strong&gt; in the example XML above.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Custom RetailTransactionServiceEx:: newRetailCDXMetaDataRecord&lt;/h2&gt;
&lt;p&gt;With this custom method (see source code below), both Retail &amp;gt; Inquiries &amp;gt; Commerce data exchange &amp;gt; Upload sessions and Download sessions table/forms are served. This is directed by the downloadMessage boolean field which is 1 (true) if the respective interface flow is a download flow (AX -&amp;gt; native AX/third-party) and 0 (false) if the respective interface flow is an upload flow (naïve AX/third-party). The artifacts prefixed with ‘pmo’ are discussed in the next section of this blog. First I’ll list you the input/output variables for the method – the array element type indicates what the type of parameter is that your XML message to Real Time Service requires for the variable. Note for the X++ code that I included many validations to ensure errors are not raised due to XML variable type to AX variable type conversion issues.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/5.-Table1.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/5.-Table1.png&quot; alt=&quot;5. Table1&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/6.-Table2.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/6.-Table2.png&quot; alt=&quot;6. Table2&quot;&gt;&lt;/a&gt;&lt;em&gt;/// &lt;summary&gt;&lt;br&gt;/// Method is added by PMOU (16.06.2015)&lt;br&gt;/// Method is used for creating a RetailCDXDataStoreSession record which reflects CDX meta data&lt;br&gt;/// BizTalk leverages the method to report on the result of its part of the AX/third-party channel interface chain&lt;br&gt;/// In doing so, system administrators have complete visibility and control across the complete interface chain including integration to third-party channels&lt;br&gt;/// &lt;/summary&gt;&lt;br&gt;/// &lt;returns&gt;&lt;br&gt;/// Container with entity keys&lt;br&gt;/// &lt;/returns&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;public&lt;/strong&gt;&lt;br&gt;&lt;strong&gt;static&lt;/strong&gt;&lt;br&gt;&lt;strong&gt;container&lt;/strong&gt; newRetailCDXMetaDataRecord(&lt;strong&gt;boolean&lt;/strong&gt; downloadMessage,&lt;br&gt;RetailCDXSharePath         sDataFileOutputPath,&lt;br&gt;RetailCDXDataGroupRefRecId     sDatagroupRecId,&lt;br&gt;RetailConnJobId         sJobId,&lt;br&gt;RetailCDXRowsAffected         sRowsAffected,&lt;br&gt;RetailCDXScheduleRefRecId     sScheduleRecId,&lt;br&gt;RetailCDXSessionNumber     sSessionNumber,&lt;br&gt;RetailCDXDownloadSessionStatus     sDownloadStatus,&lt;br&gt;pmoRetailCDXLinkedSessionRefRecId     sdsLinkedSessionRecId,&lt;br&gt;RetailCDXDataStoreRefRecId     sdsDataStoreRecId,&lt;br&gt;&lt;strong&gt;str&lt;/strong&gt;         sdsDateApplied,&lt;br&gt;&lt;strong&gt;str&lt;/strong&gt;         sdsDateDownloaded,&lt;br&gt;&lt;strong&gt;str&lt;/strong&gt;         sdsDateRequested,&lt;br&gt;RetailCDXMonDataSyncMessage     sdsMessage,&lt;br&gt;RetailCDXDownloadSessionStatus     sdsDownloadStatus,&lt;br&gt;RetailCDXCheckSum     uCheckSum,&lt;br&gt;RetailCDXDataStoreRefRecId     uDataStoreRecId,&lt;br&gt;&lt;strong&gt;str&lt;/strong&gt;         uDateCreated,&lt;br&gt;&lt;strong&gt;str&lt;/strong&gt;         uDateUploaded,&lt;br&gt;RetailCDXFileSize         uFileSize,&lt;br&gt;RetailCDXHqUploadSessionID     uHQUploadSessionId,&lt;br&gt;RetailConnJobId         uJobId,&lt;br&gt;RetailCDXMonDataSyncMessage     uMessage,&lt;br&gt;RetailCDXUploadSessionRerun     uRerun,&lt;br&gt;RetailCDXSessionNumber     uRerunForSessionId,&lt;br&gt;RetailCDXRowsAffected     uRowsAffected,&lt;br&gt;RetailCDXScheduleRefRecId     uScheduleRecId,&lt;br&gt;RetailCDXUploadSessionStatus     uUploadStatus,&lt;br&gt;RetailCDXTryCount         uTryCount,&lt;br&gt;RetailCDXPacketFilePath     uUploadPath,&lt;br&gt;RetailCDXSessionNumber     uUploadSessionId,&lt;br&gt;pmoRetailCDXLinkedSessionRefRecId     uLinkedSessionRecId,&lt;br&gt;pmoRetailCDXDataSource     uDataSource)&lt;br&gt;{&lt;br&gt; &lt;strong&gt;boolean&lt;/strong&gt;         success = &lt;strong&gt;false&lt;/strong&gt;;&lt;br&gt; &lt;strong&gt;str&lt;/strong&gt;             error = ”;&lt;br&gt;Counter         infologline = infolog.num();&lt;br&gt;&lt;strong&gt;int&lt;/strong&gt;             fromLine;&lt;br&gt;&lt;strong&gt;str&lt;/strong&gt;             xmlResult = ”;&lt;br&gt;&lt;strong&gt;container&lt;/strong&gt;         tmpResult;&lt;br&gt;RetailCDXDownloadSessionRefRecId     downloadSessionRecId;&lt;br&gt;RetailCDXDownloadSession     retailCDXDownloadSession;&lt;br&gt;retailCDXDownloadSessionDataStore     retailCDXDownloadSessionDataStore;&lt;br&gt;RetailCDXUploadSession     retailCDXUploadSession;&lt;br&gt;RetailCDXUploadSessionLog     retailCDXUploadSessionLog;&lt;br&gt;RefRecId         sessionRecId;&lt;br&gt;RetailCDXDateApplied         sdsdateAppliedUTC; &lt;em&gt;//UTCDateTime&lt;/em&gt; RetailCDXDateDownloaded     sdsdateDownloadedUTC; &lt;em&gt;//UTCDateTime&lt;/em&gt; RetailCDXDateRequested     sdsdateRequestedUTC; &lt;em&gt;//UTCDateTime&lt;/em&gt; RetailCDXDateCreated         udateCreatedUTC; &lt;em&gt;//UTCDateTime&lt;/em&gt; RetailCDXDateUploaded     udateUploadedUTC; &lt;em&gt;//UTCDateTime&lt;/em&gt;&lt;br&gt;&lt;strong&gt;try&lt;/strong&gt; {&lt;br&gt;fromLine = Global::infologLine();&lt;br&gt;&lt;em&gt;// Validate if this is an AX inbound or outbound flow&lt;/em&gt;&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (downloadMessage == &lt;strong&gt;true&lt;/strong&gt;)&lt;br&gt;{&lt;br&gt;&lt;em&gt;// If SessionNumber is 0 then create a new session&lt;/em&gt;&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (ssessionNumber == &lt;strong&gt;0&lt;/strong&gt;)&lt;br&gt;{&lt;br&gt;ssessionNumber = RetailCDXSessionIDGenerator::getNextSession();&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (ssessionNumber &amp;gt; &lt;strong&gt;0&lt;/strong&gt; &amp;amp;&amp;amp; sjobId &amp;amp;&amp;amp; sdatagroupRecId &amp;amp;&amp;amp; sdsdataStoreRecId)&lt;br&gt;{&lt;br&gt;&lt;em&gt;// Populate table RetailCDXDownloadSession&lt;/em&gt;&lt;br&gt;&lt;strong&gt;ttsBegin&lt;/strong&gt;;&lt;br&gt;retailCDXDownloadSession.clear();&lt;br&gt;retailCDXDownloadSession.initValue();&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (sDataFileOutputPath)&lt;br&gt;{&lt;br&gt;retailCDXDownloadSession.DataFileOutputPath = sDataFileOutputPath;&lt;br&gt;}&lt;br&gt;retailCDXDownloadSession.DataGroup = sdatagroupRecId;&lt;br&gt;retailCDXDownloadSession.JobID = sjobId;&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (srowsAffected &amp;gt; &lt;strong&gt;0&lt;/strong&gt;)&lt;br&gt;{&lt;br&gt;retailCDXDownloadSession.RowsAffected = srowsaffected;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (sscheduleRecId)&lt;br&gt;{&lt;br&gt;retailCDXDownloadSession.Schedule = sscheduleRecId;&lt;br&gt;}&lt;br&gt;retailCDXDownloadSession.Session = ssessionNumber;&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (sdownloadStatus)&lt;br&gt;{&lt;br&gt;retailCDXDownloadSession.Status = sdownloadStatus;&lt;br&gt;}&lt;br&gt;retailCDXDownloadSession.insert();&lt;br&gt;sessionRecId = retailCDXDownloadSession.RecId;&lt;br&gt;&lt;strong&gt;ttsCommit&lt;/strong&gt;;&lt;br&gt;&lt;em&gt;// Populate table retailCDXDownloadSessionDataStore&lt;/em&gt;&lt;br&gt;&lt;strong&gt;ttsBegin&lt;/strong&gt;;&lt;br&gt;retailCDXDownloadSessionDataStore.clear();&lt;br&gt;retailCDXDownloadSessionDataStore.initValue();&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (sdslinkedSessionRecId)&lt;br&gt;{&lt;br&gt;retailCDXDownloadSessionDataStore.pmoLinkedSession = sdslinkedSessionRecId;&lt;br&gt;}&lt;br&gt;retailCDXDownloadSessionDataStore.DataStore = sdsdataStoreRecId;&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (sdsdateApplied)&lt;br&gt;{&lt;br&gt;sdsdateAppliedUTC = &lt;strong&gt;str2datetime&lt;/strong&gt;(sdsdateApplied,&lt;strong&gt;123&lt;/strong&gt;);&lt;br&gt;retailCDXDownloadSessionDataStore.DateApplied = sdsdateAppliedUTC;&lt;br&gt;}&lt;br&gt;retailCDXDownloadSessionDataStore.Session = sessionRecId;&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (sdsdateDownloaded)&lt;br&gt;{&lt;br&gt;sdsdateDownloadedUTC = &lt;strong&gt;str2datetime&lt;/strong&gt;(sdsdateDownloaded,&lt;strong&gt;123&lt;/strong&gt;);&lt;br&gt;retailCDXDownloadSessionDataStore.DateDownloaded = sdsdateDownloadedUTC;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (sdsdateRequested)&lt;br&gt;{&lt;br&gt;sdsdateRequestedUTC = &lt;strong&gt;str2datetime&lt;/strong&gt;(sdsdateRequested,&lt;strong&gt;123&lt;/strong&gt;);&lt;br&gt;retailCDXDownloadSessionDataStore.dateRequested = sdsdateRequestedUTC;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (sdsmessage)&lt;br&gt;{&lt;br&gt;retailCDXDownloadSessionDataStore.Message = sdsmessage;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (sdsdownloadStatus)&lt;br&gt;{&lt;br&gt;retailCDXDownloadSessionDataStore.Status = sdsdownloadStatus;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uDataSource)&lt;br&gt;{&lt;br&gt;retailCDXDownloadSessionDataStore.pmoDataSource = uDataSource;&lt;br&gt;}&lt;br&gt;retailCDXDownloadSessionDataStore.insert();&lt;br&gt;&lt;strong&gt;ttsCommit&lt;/strong&gt;;&lt;br&gt;success = &lt;strong&gt;true&lt;/strong&gt;;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;else&lt;/strong&gt; {&lt;br&gt;error = ‘@PMO17’;&lt;br&gt;success = &lt;strong&gt;false&lt;/strong&gt;;&lt;br&gt;}&lt;br&gt;}&lt;br&gt;&lt;strong&gt;else&lt;/strong&gt; {&lt;br&gt;&lt;em&gt;// If SessionNumber is 0 then create a new session&lt;/em&gt;&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uUploadSessionId == &lt;strong&gt;0&lt;/strong&gt;)&lt;br&gt;{&lt;br&gt;&lt;em&gt;// The upload session is synched from AsyncServerHeadOffice\dbo.UPLOADSESSION, so a new session ID should not interfere with the SQL ID range&lt;/em&gt; uUploadSessionId = RetailCDXUploadSession::getNextBizTalkSession();&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uUploadSessionId &amp;gt; &lt;strong&gt;0&lt;/strong&gt; &amp;amp;&amp;amp; uJobId &amp;amp;&amp;amp; uDataStoreRecId)&lt;br&gt;{&lt;br&gt;&lt;em&gt;// Populate table RetailCDXUploadSession&lt;/em&gt;&lt;br&gt;&lt;strong&gt;ttsBegin&lt;/strong&gt;;&lt;br&gt;retailCDXUploadSession.clear();&lt;br&gt;retailCDXUploadSession.initValue();&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uUploadPath)&lt;br&gt;{&lt;br&gt;retailCDXUploadSession.UploadPath = uUploadPath;&lt;br&gt;}&lt;br&gt;retailCDXUploadSession.DataStore = uDataStoreRecId;&lt;br&gt;retailCDXUploadSession.JobId = uJobId;&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uRowsAffected &amp;gt; &lt;strong&gt;0&lt;/strong&gt;)&lt;br&gt;{&lt;br&gt;retailCDXUploadSession.RowsAffected = uRowsAffected;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uScheduleRecId)&lt;br&gt;{&lt;br&gt;retailCDXUploadSession.Schedule = uScheduleRecId;&lt;br&gt;}&lt;br&gt;retailCDXUploadSession.UploadSessionId = uUploadSessionId;&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uUploadStatus)&lt;br&gt;{&lt;br&gt;retailCDXUploadSession.Status = uUploadStatus;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uCheckSum)&lt;br&gt;{&lt;br&gt;retailCDXUploadSession.CheckSum = uCheckSum;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uDateCreated)&lt;br&gt;{&lt;br&gt;uDateCreatedUTC = &lt;strong&gt;str2datetime&lt;/strong&gt;(uDateCreated,&lt;strong&gt;123&lt;/strong&gt;);&lt;br&gt;retailCDXUploadSession.DateCreated = uDateCreatedUTC;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uDateUploaded)&lt;br&gt;{&lt;br&gt;uDateUploadedUTC = &lt;strong&gt;str2datetime&lt;/strong&gt;(uDateUploaded,&lt;strong&gt;123&lt;/strong&gt;);&lt;br&gt;retailCDXUploadSession.DateUploaded = uDateUploadedUTC;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uFileSize)&lt;br&gt;{&lt;br&gt;retailCDXUploadSession.FileSize = uFileSize;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uHQUploadSessionId)&lt;br&gt;{&lt;br&gt;retailCDXUploadSession.HqUploadSessionId = uHQUploadSessionId;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uMessage)&lt;br&gt;{&lt;br&gt;retailCDXUploadSession.Message = uMessage;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uTryCount &amp;gt; &lt;strong&gt;0&lt;/strong&gt;)&lt;br&gt;{&lt;br&gt;retailCDXUploadSession.TryCount= uTryCount;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uRerun &amp;gt; &lt;strong&gt;0&lt;/strong&gt;)&lt;br&gt;{&lt;br&gt;retailCDXUploadSession.Rerun= uRerun;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uRerunForSessionId)&lt;br&gt;{&lt;br&gt;retailCDXUploadSession.RerunFor = uRerunForSessionId;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uDataSource)&lt;br&gt;{&lt;br&gt;retailCDXUploadSession.pmoDataSource = uDataSource;&lt;br&gt;}&lt;br&gt;retailCDXUploadSession.insert();&lt;br&gt;&lt;strong&gt;ttsCommit&lt;/strong&gt;;&lt;br&gt;&lt;em&gt;// Populate table RetailCDXUploadSessionLog&lt;/em&gt;&lt;br&gt;&lt;strong&gt;ttsBegin&lt;/strong&gt;;&lt;br&gt;retailCDXUploadSessionLog.clear();&lt;br&gt;retailCDXUploadSessionLog.initValue();&lt;br&gt;retailCDXUploadSessionLog.DataStore = uDataStoreRecId;&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uDateCreated)&lt;br&gt;{&lt;br&gt;uDateCreatedUTC = &lt;strong&gt;str2datetime&lt;/strong&gt;(uDateCreated,&lt;strong&gt;123&lt;/strong&gt;);&lt;br&gt;retailCDXUploadSessionLog.DateCreated = uDateCreatedUTC;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uMessage)&lt;br&gt;{&lt;br&gt;retailCDXUploadSessionLog.Message = uMessage;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;if&lt;/strong&gt; (uUploadStatus)&lt;br&gt;{&lt;br&gt;retailCDXUploadSessionLog.Status = uUploadStatus;&lt;br&gt;}&lt;br&gt;retailCDXUploadSessionLog.UploadSessionId = uUploadSessionId;&lt;br&gt;retailCDXUploadSessionLog.insert();&lt;br&gt;&lt;strong&gt;ttsCommit&lt;/strong&gt;;&lt;br&gt;success = &lt;strong&gt;true&lt;/strong&gt;;&lt;br&gt;}&lt;br&gt;&lt;strong&gt;else&lt;/strong&gt; {&lt;br&gt;error = ‘@PMO17’;&lt;br&gt;success = &lt;strong&gt;false&lt;/strong&gt;;&lt;br&gt;}&lt;br&gt;}&lt;br&gt;}&lt;br&gt;&lt;strong&gt;catch&lt;/strong&gt;(Exception::Error)&lt;br&gt;{&lt;br&gt;&lt;strong&gt;ttsabort&lt;/strong&gt;;&lt;br&gt;error = RetailTransactionService::getInfologMessages(fromLine);&lt;br&gt;RetailTracer::Error(‘RetailTransactionServiceEx’,&lt;strong&gt;funcName&lt;/strong&gt;(),error);&lt;br&gt;success = &lt;strong&gt;false&lt;/strong&gt;;&lt;br&gt;}&lt;br&gt;tmpResult = [success, error];&lt;br&gt;&lt;strong&gt;return&lt;/strong&gt; tmpResult;&lt;br&gt;}&lt;/p&gt;
&lt;h2&gt;Enhancements to the Download session and Upload session form&lt;/h2&gt;
&lt;p&gt;In the &lt;strong&gt;Upload session&lt;/strong&gt; form, the &lt;strong&gt;Message&lt;/strong&gt; field is not visible by default. As this field will contain any positive or negative feedback from our middleware or third-party system, this is the first thing to change:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/4.-Microsoft-Dynamics-AX-Retail-Upload-sessions-customization.jpg.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/4.-Microsoft-Dynamics-AX-Retail-Upload-sessions-customization.jpg.png&quot; alt=&quot;Microsoft Dynamics AX Retail - Upload sessions customization.jpg&quot;&gt;&lt;/a&gt;As shown in the picture, in both &lt;strong&gt;Upload&lt;/strong&gt; and &lt;strong&gt;Download&lt;/strong&gt; session form I’ve added the Origin field which indicates which link of the interface chain is reporting to us (see second column). Last but not least I’ve added a &lt;em&gt;Linked download session&lt;/em&gt; field to the &lt;strong&gt;Download session&lt;/strong&gt; form which shows which session (read: record in the Download session form) the current record followed up on. In this way, you can easy filter the form to have all the meta data as reported by the different chains of the complete interface flow in one overview.&lt;br&gt;I hope this has shown you how powerful Dynamics AX for Retail can also be leveraged for third-party sales channel integrations.&lt;/p&gt;
&lt;p&gt;Happy DAX’ing!&lt;br&gt;Patrick&lt;/p&gt;
&lt;h2&gt;&lt;/h2&gt;
</content:encoded><category>Technicaldev</category></item><item><title>Dynamics AX Retail third-party POS and e-commerce integration – Solution Design</title><link>https://patrickmouwen.com/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/</guid><description>How to hook middleware into Dynamics AX Retail for third-party POS and e-commerce, without compromising the integrity of Retail CDX.</description><pubDate>Sun, 18 Oct 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So here’s the challenge… we have Retail CDX up-and-running… &lt;em&gt;how do we hook up any middleware to integrate with third-party POS systems, e-commerce and other sales channels&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;Hmmm… let me add one nuance here which we might overlook: how do we hook up middleware &lt;em&gt;without touching the integrity&lt;/em&gt; of Retail CDX?&lt;/p&gt;
&lt;p&gt;In order to answer this question I think it’s good to shortly refresh our minds about Retail CDX. Then we’ll take a look at my solution for both the batch processing as well as transactional types of interfacing.&lt;/p&gt;
&lt;h2&gt;Standard AX/Retail CDX&lt;/h2&gt;
&lt;p&gt;Dynamics AX Retail CDX builds upon the principle that data should efficiently be distributed to decentral sales systems like POS systems. This efficiency should maximize data actuality in the sales system, even in low bandwidth environments and even when large datasets (for example products) are exchanged. This principle is relevant as a sales system should have the highest possible uptime and therefore should never be directly dependent on interfaces with central systems for its day-to-day operations. Further, Retail CDX is designed for enterprise environments where multiple sales systems are to be served from 1 or multiple AX instances with a variety of time zones, currencies, local tax requirements etc. Keep this in mind when looking at CDX overview picture below which only shows a 1 AX instance/1 sales channel situation.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/1.-Blogging-drawings-Retail-CDX.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/1.-Blogging-drawings-Retail-CDX.jpg&quot; alt=&quot;Standard Microsoft Dynamics AX Retail CDX&quot;&gt;&lt;/a&gt;&lt;em&gt;So what exactly is the flow of things within the CDX landscape&lt;/em&gt;?&lt;br&gt;For the batch processing side of the landscape, it’s basically all about the AX database, channel database and two ‘helpers’ to ship the data over between the two databases: a central helper (&lt;strong&gt;Async server&lt;/strong&gt;; HQ side) and a local helper (&lt;strong&gt;Async client&lt;/strong&gt;; channel side). The helpers only do something when they receive instructions. After receiving instructions, they do their job and write a standardized report on their job (meta data) back into their own meta databases. In addition, the local helper also reports his meta data to the central server helper, so all local meta data about everything happening in the CDX landscape can be synched back into AX by the &lt;strong&gt;Retail &amp;gt; Periodic &amp;gt; Data distribution &amp;gt; Process status messages&lt;/strong&gt; batch job.&lt;/p&gt;
&lt;p&gt;To be more precise:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;AX hands over an instruction to download information to the central helper.&lt;/li&gt;
&lt;li&gt;The central helper contacts the AOS which is the gateway to the AX database , downloads the required data, serializes that data into XML files, wraps these XML files into 1 &lt;strong&gt;binary file&lt;/strong&gt; and outputs that file to a working folder which was configured in AX and synched to the central helper’s interface meta database as part of the CDX setup.&lt;/li&gt;
&lt;li&gt;The local helper periodically requests the central helper if there any new instructions to be executed. The frequency for this request is defined in the &lt;strong&gt;Async server profile&lt;/strong&gt; configuration in AX. In case of any data to be shipped, the central helper responds with a download instruction including a reference to the working folders. The local helper then writes this instruction into its interface meta database, executes the instruction (downloads the binary file), unpackages the binary file into XML files, de-serializes the XML files, injects the content of the files into the channel database, writes meta data about this operation into the interface meta database and reports the same information to the central helper (which the central helper writes into its own interface meta database).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Hooking up middleware: batch processing (non-real time)&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;So the actual transport of data between AX and the channel databases is done by XML files?&lt;/em&gt;&lt;br&gt;YES – let’s take a short look into those files (note: you can use the tool DDPACKVIEW for this) – the example here is the 1000 scheduler job for currencies:&lt;br&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/2.-CDX-XML-content.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/2.-CDX-XML-content.png&quot; alt=&quot;CDX XML content&quot;&gt;&lt;/a&gt;As you can see the binary ‘package’ contains 1 header XML file and multiple XML files with data. The header XML files indicates which XML files containing data (‘data files’) are attached in the binary package and which operations should take place for the different data files (delete or insert/update). The data files ‘just’ contains the data to be deleted or inserted/updated:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/3.-CDX-XML-content-2.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/3.-CDX-XML-content-2.png&quot; alt=&quot;CDX XML content&quot;&gt;&lt;/a&gt;As you can conclude from the “ax.” prefix of the tables, the files and data 1:1 reflect the target Retail channel database schema and data in AX, which is recognizable from the &lt;strong&gt;RecId&lt;/strong&gt; value for the currency table. This is because we picked the AX 2012 R3 Retail channel schema for this example, where channel database schema and AX database schema are perfectly matched.&lt;/p&gt;
&lt;p&gt;S&lt;em&gt;o why wouldn’t we just skip the channel database in the architecture and let middleware intercept and process the binary file with XML files?&lt;/em&gt;&lt;br&gt;I didn’t choose that path for the following reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The AX/channel database integration is proven technology which goes well back into the history of the LS Retail solution (say 15 years ago). So ‘decoupling’ the binary file transfer from this architecture will impose project risks.&lt;/li&gt;
&lt;li&gt;Some scheduler jobs (like the 1040 – product) ship over 80 XML files. Processing these quantities of XML files for 1 flow will impact performance negatively. Middleware specialists rather integrate through SQL server than through XML files as SQL server is faster and provides more technical opportunities for integration.&lt;/li&gt;
&lt;li&gt;By using the CDX XML files within the middleware orchestration, we have to make the middleware aware of the AX data model in some way, while the AX channel database offers many out-of-the-box views and stored procedures which can be leveraged as an access gateway for the middleware solution.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Details of the solution for batch processing&lt;/h2&gt;
&lt;p&gt;So instead, I chose to hook up BizTalk to the channel database. But &lt;em&gt;how could I trigger BizTalk to perform action without impacting the standard AX/Retail CDX integrity&lt;/em&gt;? To answer this question we need to cover the same dimensions which are covered by the standard AX/Retail Scheduler: WHEN, WHAT, WHERE. The &lt;em&gt;WHEN&lt;/em&gt; refers to the &lt;em&gt;trigger&lt;/em&gt; for the middleware solution to take action. Let’s take the example of a BizTalk application which is functionally linked to the 1000 scheduler job run in AX and technically to the local client’s helper for a specific channel. I took the following conditions as criteria for BizTalk to start taking action:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[Async client meta database].dbo.DownloadSession.JobId = [Job ID BizTalk application is designed for]&lt;/li&gt;
&lt;li&gt;[Async client meta database].dbo.DownloadSession.Status = ‘4’ (=Applied)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words: the BizTalk applications is continuously monitoring the local helper’s interface meta database for in-scope channel database changes which have been confirmed by the local helper.&lt;/p&gt;
&lt;p&gt;But at this point in time the BizTalk application does not have a clue yet about the &lt;em&gt;WHAT&lt;/em&gt; yet: &lt;em&gt;what data has been changed exactly&lt;/em&gt;? In order to answer this question I decided to imitate the behavior of the trigger to ship data on HQ side: &lt;strong&gt;SQL change tracking&lt;/strong&gt;. See my other &lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/&quot;&gt;blog post&lt;/a&gt; for more details if you’re interested in this feature. Bottom line, a similar SQL change tracking mechanism has been be applied to the SQL database. BizTalk builds upon stored procedures which confront data from one more standard AX channel database tables/views or custom views with change tracking. Here’s an example for a stock availability flow:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/4.-SP-Item-Availability.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/4.-SP-Item-Availability.png&quot; alt=&quot;Microsoft Dynamics AX Retail channel database stored procedure&quot;&gt;&lt;/a&gt;The core table which triggers BizTalk to create an output file for the third-party system is the &lt;strong&gt;RETAILINVENTAVAILBILITY&lt;/strong&gt; table (see directly behind the CHANGETABLE statement in the picture above). But the trigger can easily be on more tables and/or individual columns. Be aware that this is dependent on the requirements of the target third-party system.&lt;/p&gt;
&lt;p&gt;So our situation is now as depicted below: a BizTalk application is monitoring the local helper’s interface meta database to spot for in-scope data changes. If this is the case, then the application fires a stored procedure to the channel database to check if the changes are relevant for the target system.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/5.-Blogging-drawings-Retail-CDX-and-BT.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/5.-Blogging-drawings-Retail-CDX-and-BT.jpg&quot; alt=&quot;Microsoft Dynamics AX Retail BizTalk integration design&quot;&gt;&lt;/a&gt;So.. say we have a situation where our BizTalk application has identified relevant data changes.. But how does the application know which system to deliver this data to:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/6.-Blogging-drawings-Retail-3rd-party.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/6.-Blogging-drawings-Retail-3rd-party.jpg&quot; alt=&quot;Microsoft Dynamics AX Retail BizTalk integration design&quot;&gt;&lt;/a&gt;The customer where I implemented this solution had over 20 e-commerce instances across the globe and different types of topologies varying from a central BizTalk instance/regional AX instance situation to a regional BizTalk/local AX instance situation. In that situation the &lt;em&gt;WHERE&lt;/em&gt; question goes beyond the target system only. It’s about HOW to implement flexibility across the whole architecture as a whole. What if the customer decides to move a channel database to another server or if the central/regional topology is changed into a regional/regional topology? We cannot simply hard code all the server names, database instance names and service addresses into BizTalk. That would mean a redeployment of many applications if something is changed in the infrastructure landscape.&lt;/p&gt;
&lt;p&gt;Analyzing these needs and looking over the powerful tools we have in hand with Retail CDX I came to an out-of-the-box solution. I decided to define BizTalk as a &lt;strong&gt;Retail store&lt;/strong&gt; in AX and create a custom &lt;strong&gt;scheduler job 9000&lt;/strong&gt; (by configuration ;-)) to ship all technical/infrastructure related channel meta data to a special &lt;strong&gt;AXBizTalkConfiguration&lt;/strong&gt; database, which is technically nothing more than the channel database for the virtual BizTalk channel. I only needed to add fields to AX reflecting the location of the third-party system, &lt;strong&gt;Async client&lt;/strong&gt; database and meta database instance name:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/7.-Channel-database-customization.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/7.-Channel-database-customization.png&quot; alt=&quot;Microsoft Dynamics AX Retail channel database customization&quot;&gt;&lt;/a&gt;Then in the AXBizTalkConfiguration a special view returns all the characteristics from the channels which would have had to be hard coded otherwise:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/8.-AXBizTalkConfiguration.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/8.-AXBizTalkConfiguration.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;The information from the view is consumed by the BizTalk application at run time and utilized until the application is restarted. This prevents hard coding and having to republish BizTalk applications over and over again in case of changes. See my blog post &lt;em&gt;Agility&lt;/em&gt; (blog post will follow) for more details if you’re interested in this feature.&lt;/p&gt;
&lt;p&gt;So.. We’ve now made BizTalk aware of WHERE to deliver the output information in an agile way. Here’s the full solution overview including triggers:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/Microsoft-Dynamics-AX-Retail-3rd-party-POS-and-E-commerce-integration-design.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/Microsoft-Dynamics-AX-Retail-3rd-party-POS-and-E-commerce-integration-design.jpg&quot; alt=&quot;Microsoft Dynamics AX Retail third-party POS and e-commerce integration design&quot;&gt;&lt;/a&gt;Before we go along the triggers in the landscape, there’s one feature left unspoken. As we’ve seen for CDX, all local helpers indirectly report the results of their actions back into AX. This provides us the means to control the CDX landscape from our one and only AX headquarters.&lt;br&gt;When it comes to integration, everybody who has some practical experience in this area knows the by far biggest vexation in this area: FINGER POINTING :(. This is often a clear indication that either frameworks for efficient maintenance are missing or clear procedures for problem solving or the worst of all… both. So the best way to avoid this is to hook up both BizTalk and the third-party systems to existing CDX meta data framework – Let all systems in the landscape report the results of their interface related actions back to AX. In order to offer a standardized entry point for this I’ve leveraged Real Time Service to directly write into the standard AX/Retail &lt;strong&gt;Inquiries &amp;gt; Commerce data exchange &amp;gt; Upload sessions/download sessions&lt;/strong&gt; forms. The result looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/10.-Download-sessions.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/10.-Download-sessions.jpg&quot; alt=&quot;Microsoft Dynamics AX Retail Download sessions customization&quot;&gt;&lt;/a&gt;We can follow the chain of interface links up till its destination and easily intervene in case of any issues! See my blog post &lt;em&gt;&lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/&quot;&gt;Control dashboard&lt;/a&gt;&lt;/em&gt; for more details if you’re interested in this feature. So let’s get back to our main solution above again and consider each and every trigger in the interface landscape:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trigger 1: batch job in AX initiating the (potential) transfer of data to the channel database. Frequency: to be determined by the business.&lt;/li&gt;
&lt;li&gt;Trigger 2: The local helper (&lt;strong&gt;Async client&lt;/strong&gt;) requesting the central helper for new instructions. Frequency: as configured in the respective &lt;strong&gt;Async server profile&lt;/strong&gt; in AX. Common setting: 1 minute or immediate.&lt;/li&gt;
&lt;li&gt;Trigger 3: a BizTalk process polling for in-scope data changes. Frequency: immediate.&lt;/li&gt;
&lt;li&gt;Trigger 4: a BizTalk process transforming source to target data and delivering this data. Frequency: immediate&lt;/li&gt;
&lt;li&gt;Trigger 5: a BizTalk pocess reporting back to AX on the result of its actions. Frequency: immediate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So from this trigger landscape we can conclude that all links in the chain ‘follow’ the AX frequency: when the business decides to ship out products (&lt;strong&gt;1040 scheduler job&lt;/strong&gt;) with a frequency of once an hour, the rest of the interface chain will follow… if the target system (the ‘unidentified’ trigger 6) supports this as well… For the upload flow (third-party to AX) this is no issue as the frequency of the AX pull job will still decide the ultimate frequency of data exchange. My advice: configure all the other interface links on ‘immediate’, so AX has full control over the frequency across the complete landscape.&lt;/p&gt;
&lt;h2&gt;Hooking up middleware: transactional information exchange (real time)&lt;/h2&gt;
&lt;p&gt;Most of you will be familiar with request/response mechanisms. But For the sake of completeness I’d like to spend a few more words on the transactional information exchange through Real Time Service as well. Most important to notice here is that I leveraged Real Time Service not only when timing or direct response was a requirement for an interface flow. Actually I weighed with every flow design where standard AX/Retail CDX could offer the best fit, independent from the type of interfacing on third-party system side. For example, I faced a situation where the third-party system sent customer data to BizTalk in a batch processing manner. But for my AX side it was better to leverage the standard AX/Retail &lt;strong&gt;RetailTransactionServiceCustomer::newCustomer&lt;/strong&gt; method instead of trying to implement a new pull flow for batch processing customer records.&lt;/p&gt;
&lt;p&gt;Further, I also applied the CDX meta data service call through Real Time Service (you know.. To report on the result of interface actions) to the real time flows. This gives a nice ‘ping-pong’ effect where the responses of 1 or multiple service calls are reported back to AX by another service call:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/11.-RTS-CDX-Meta-data-call.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/11.-RTS-CDX-Meta-data-call.png&quot; alt=&quot;Microsoft Dynamics AX Retail RTS CDX meta data&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;To conclude this overview of a Dynamics AX/Retail CDX based solution for third-party sales channel integration, I’d like to stress the comfort this solution brings to your day-to-day use of standard AX/Retail. Within AX you’ll be able to handle a third-party sales channel as a ‘normal’ AX Retail store or Online store. This means that also conceptually you can fully leverage standard AX/Retail to support your third-party sales channels:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/12.-Blogging-drawings-AX-Channel-concept.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/12.-Blogging-drawings-AX-Channel-concept.jpg&quot; alt=&quot;Microsoft Dynamics AX Retail channel concept&quot;&gt;&lt;/a&gt;You’ll even be able to create data groups which contain both native as well as third-party channels.&lt;/p&gt;
&lt;p&gt;Some of you will argue here: yeah nice, but what about price calculations in the third-party channels or tax calculations?? For the native AX POS and online store, we have Retail server which manages to bring the same pricing logic to the local native AX sales channel as we have available on HQ – what about the third-party sales channels?? As I might spend another blog on this topic in the future, my answer for now is simple: either integrate your third-party channels also with Retail server or Real time service or limit your AX/Retail configuration options (for example for discount structures) based on what you third-party sales channels can support. In this latter case, my recommendation would always be to minimize the footprint of your sales channels and maximize the footprint of AX. It’s not for no reason that AX supports many localizations – you don’t want to re-implement all those localizations in your sales channels when rolling out your third-party system worldwide ;-).&lt;/p&gt;
&lt;p&gt;Happy DAX’ing!&lt;br&gt;Patrick&lt;/p&gt;
</content:encoded><category>Technicalint</category></item><item><title>Dynamics AX Retail third-party POS and e-commerce integration – Trigger mechanism</title><link>https://patrickmouwen.com/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/</guid><description>The trigger mechanism behind Dynamics AX Retail third-party integration — how change tracking on the AX HQ side signals middleware to act.</description><pubDate>Sun, 18 Oct 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In my main &lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/&quot;&gt;blog post&lt;/a&gt; regarding Dynamics AX Retail third-party sales channel integration I presented the mechanism to trigger BizTalk to take action after an AX scheduler job run. In this blog I’ll provide some more details on this particular topic. Let me first explain how the &lt;strong&gt;change tracking&lt;/strong&gt; mechanism is leveraged on AX HQ side and let’s then take a closer look on how change tracking can be leveraged on the channel database and &lt;strong&gt;Async client database&lt;/strong&gt; for use by middleware like Microsoft BizTalk.&lt;/p&gt;
&lt;h2&gt;Change tracking on AX HQ&lt;/h2&gt;
&lt;p&gt;On AX HQ the &lt;strong&gt;Generate classes&lt;/strong&gt; button on the &lt;strong&gt;Retail &amp;gt; Setup &amp;gt; Retail scheduler&amp;gt; Retail channel schema&lt;/strong&gt; form runs business logic in the &lt;strong&gt;RetailCDXCodeGen&lt;/strong&gt; class. One of the steps is here is to enable change tracking for all tables reflected by the subjobs in AX – this saves us the time of having to enable change tracking on SQL level itself (thanks MSFT ;-)). Another step is to create queries for each table which is defined as a subjob (&lt;strong&gt;Retail &amp;gt; Setup &amp;gt; Retail scheduler &amp;gt; Scheduler subjobs&lt;/strong&gt;). Here’s what such a query looks like for the standard AX currency table (source: &lt;strong&gt;RetailCDXChangeTrackingSQL&lt;/strong&gt; table):&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/SQL.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/SQL.jpg&quot; alt=&quot;SQL&quot;&gt;&lt;/a&gt;As you can see in the &lt;strong&gt;CHANGETABLE&lt;/strong&gt; and &lt;strong&gt;CHANGE_TRACKING_IS_COLUMN_IN_MASK&lt;/strong&gt; statement, this query enables AX to list the records for which any of the indicated fields (columns) in the Currency table has been updated for a particular change tracking version (passed through with the &lt;strong&gt;%2&lt;/strong&gt; parameter). So when a scheduler job runs, AX does the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AX selects the set of tables which is relevant for the particular job run (here: the 1000 – Currency).&lt;/li&gt;
&lt;li&gt;AX gathers the changes for these tables since the last change tracking version which has been addressed in the last job run. Note: this change tracking version is visible as ‘row version’ under &lt;strong&gt;Retail &amp;gt; Periodic &amp;gt; Data distribution &amp;gt; Distribution schedule &amp;gt; [Select schedule] &amp;gt; [History button in ribbon]&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/1.-Microsoft-Dynamics-Retail-Last-sync-version.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/1.-Microsoft-Dynamics-Retail-Last-sync-version.png&quot; alt=&quot;Microsoft Dynamics Retail - Last sync version&quot;&gt;&lt;/a&gt;Important here is that SQL Server does not keep change tracking history forever as this might expand the database size disproportionally in case of high-transactional use of AX. So to limit the number of transactions, SQL Server works with a retention period which can be set on the database properties in SQL Server:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/2.-Microsoft-Dynamics-Retail-Change-tracking.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/2.-Microsoft-Dynamics-Retail-Change-tracking.png&quot; alt=&quot;Microsoft Dynamics Retail - Change tracking&quot;&gt;&lt;/a&gt;&lt;br&gt;The default &lt;strong&gt;retention period&lt;/strong&gt; is 2 days. If the retention period is exceeded (read: if a particular job has not been running once in 2 days), AX has no other option than to run a full synch for the particular flow since the change tracking history is not completely available anymore. You’ll receive the following infolog in AX when running the scheduler job:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The change tracking information related to scheduler job &lt;Job ID&gt; and data group &lt;Data group&gt; are only partially available, due to the AX database change tracking retention period setting. A complete snapshot of data will be generated instead.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Be careful with this… your target system might only be designed to receive changes and not the full load. What if your &lt;strong&gt;1040 – Product&lt;/strong&gt; flow would ship out its 150.000 items in the channel’s assortment… So be aware of this function when designing your specific interface flows.&lt;/p&gt;
&lt;p&gt;Another point to consider is the ability to trigger a full sync manually. In AX 2012 R2 we had our A-jobs (forcing to synch changes only) and &lt;strong&gt;N-jobs&lt;/strong&gt; (forcing a full sync). In R3 the N-jobs seem to have been removed from the scene, but that’s not really the case. In fact, a full data sync can still be triggered from the &lt;strong&gt;Retail &amp;gt; Setup &amp;gt; Channel integration &amp;gt; Channel database&lt;/strong&gt; form:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/3.-Microsoft-Dynamics-Retail-Full-sync.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/3.-Microsoft-Dynamics-Retail-Full-sync.png&quot; alt=&quot;Microsoft Dynamics Retail - Full sync&quot;&gt;&lt;/a&gt;&lt;br&gt;So train your system administrators to handle these features in a way which suits your interface designs.&lt;/p&gt;
&lt;h2&gt;Change tracking on Async client and Channel database&lt;/h2&gt;
&lt;p&gt;As mentioned in my main &lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/&quot;&gt;blog post&lt;/a&gt; regarding Dynamics AX Retail third-party sales integration, the following conditions should be met before BizTalk actually starts doing something:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[Async client meta database].dbo.DownloadSession.JobId = [Job ID one of the BizTalk applications is designed for to process&lt;/li&gt;
&lt;li&gt;[Async client meta database].dbo.DownloadSession.Status = ‘4’ (=Applied)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This might for example be the actual situation in the Async client database:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/4.-Microsoft-Dynamics-Retail-Async-client-database.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/4.-Microsoft-Dynamics-Retail-Async-client-database.png&quot; alt=&quot;Microsoft Dynamics Retail - Async client database&quot;&gt;&lt;/a&gt;&lt;br&gt;As each job ID will trigger a different output flow to the third-party system, the job IDs are coupled with a specialized BizTalk process each. However, to avoid having them all polling on the &lt;strong&gt;dbo.DownloadSession&lt;/strong&gt;, a generic BizTalk process is taking care of that task. It’s this process that triggers another BizTalk process to handle the respective Job ID subsequently. In order for this generic BizTalk process to keep track of the records it has triggered specific BizTalk processes for, change tracking is enabled for the &lt;strong&gt;dbo.DownloadSession&lt;/strong&gt; table. So after each query cycle, BizTalk writes the last change tracking version for the &lt;strong&gt;dbo.DownloadSession&lt;/strong&gt; table into its own local administration. So at each cycle new records can easily be identified and validated. Filtering the records by both the criteria mentioned above and change tracking is done by stored procedure.&lt;/p&gt;
&lt;p&gt;A similar mechanism has been applied to the channel database. Let’s take an example to illustrate that. Say we have two custom scheduler jobs in AX with job IDs 8000 and 8010 respectively. These jobs ship data for the following tables:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/5.-Table1.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/5.-Table1.jpg&quot; alt=&quot;5. Table1&quot;&gt;&lt;/a&gt;But only the following tables are supposed to eventually trigger output to be shipped to the third-party system:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/6.-Table2.jpg&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/6.-Table2.jpg&quot; alt=&quot;6. Table2&quot;&gt;&lt;/a&gt;Say that we update 1 record in table 1 within AX and 1 record in table 6 within AX. We run both 8000 and 8010 jobs for our channel, so we have CDX shipping the updates over to the related channel database and writing meta data records into the related &lt;strong&gt;Async client&lt;/strong&gt; database. Consequently, middleware (in this example: BizTalk) kicks in to process the data to third-party. The full flow of things in this layer is pictured in the following overview:&lt;/p&gt;
&lt;p&gt;BizTalk process #1 spots new finished job runs (status = 4) for both flows and triggers BizTalk processes #2 and #3 to figure out if there’s actual data to be shipped to the third-party system. Similar to the Async client change tracking mechanism, BizTalk processes #2 and #3 inquire the latest change tracking versions for their respective job runs. For both job runs this is #9000 in this example, but it could have easily been different for each of the flows.&lt;/p&gt;
&lt;p&gt;So BizTalk process #2 runs a stored procedure to only have a recordset returned which addresses all changes later than version #9000 and changes to table 1 only. Example:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/8.-Microsoft-Dynamics-AX-Retail-BizTalk-integration-Stored-procedure.png&quot;&gt;&lt;img src=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/8.-Microsoft-Dynamics-AX-Retail-BizTalk-integration-Stored-procedure.png&quot; alt=&quot;Microsoft Dynamics AX Retail BizTalk integration - Stored procedure&quot;&gt;&lt;/a&gt;In this example, &lt;strong&gt;biztalk.[PMOCHANNELITEMSAVAILABILITVIEW]&lt;/strong&gt; returns the dataset which is the baseline for the output to the third-party system. The standard AX/Retail table &lt;strong&gt;ax.RETAILINVENTAVAILABILITY&lt;/strong&gt; is indicated as the &lt;strong&gt;CHANGETABLE&lt;/strong&gt; (=table 1 in our example) and &lt;strong&gt;@LastSyncVer&lt;/strong&gt; indicates the last change tracking version for this job run (version #9000 in our example). So if this stored procedure returns any data, then BizTalk process #2 will have work to do to transform and hand over the data to the third-party system. After successful processing, BizTalk process #2 registers a combination of Job ID and last processed change tracking version (#9001) in its administration to avoid any duplicate output in next processing cycles.&lt;/p&gt;
&lt;p&gt;Process #3 has still the job ID 8010/change tracking version #9000 combination in his administration. So the same original change to table 1 can still trigger process #3 to process his output for the third-party system.&lt;/p&gt;
&lt;p&gt;I hope this blog has given you a better insight of how you can trigger a middleware solution on top of standard AX/Retail CDX.&lt;/p&gt;
&lt;p&gt;Happy DAX’ing!&lt;br&gt;Patrick&lt;/p&gt;
</content:encoded><category>Technicalint</category></item><item><title>Dynamics AX Retail third-party POS and e-commerce integration – Introduction</title><link>https://patrickmouwen.com/blog/integrating-dynamics-ax-2012-r3-retail-with-3rd-party-sales-channels-introduction/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/integrating-dynamics-ax-2012-r3-retail-with-3rd-party-sales-channels-introduction/</guid><description>An introduction to integrating Dynamics AX 2012 R3 Retail with third-party POS and e-commerce platforms — and why so little had been written about it.</description><pubDate>Sun, 18 Oct 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;With the ongoing hunt for implementing ‘omnichannel strategies’ by Retail companies and the booming Microsoft Dynamics AX market, there must be a huge demand for integrating Microsoft Dynamics AX Retail with third-party POS and third-party e-commerce platforms. But when I google the internet for keywords like “AX 2012”, “Integration”, “third-party”, “POS” and “e-commerce”, there are not too many hits. And if I find any hits, discussions quickly seem to head for the same solution: &lt;strong&gt;AIF&lt;/strong&gt; (Application Integration Framework).&lt;/p&gt;
&lt;p&gt;In my vision leveraging AIF in the Dynamics AX Retail area is a missed opportunity. To prove this and to provide more information regarding Dynamics AX Retail/third-party integration in general, I’ve decided to write a series of blogs regarding this topic. In this &lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/&quot;&gt;blog post&lt;/a&gt; you can find the solution which I’ve recently implemented for a globally operating Retailer based on: Standard AX Retail&lt;strong&gt;CDX&lt;/strong&gt; (Commerce Data Exchange). Here’s a &lt;a href=&quot;/images/blog/dynamics-ax-retail-3rd-party-integration-solution-based-on-cdx-biztalk/Microsoft-Dynamics-AX-Retail-3rd-party-POS-and-E-commerce-integration-design.jpg&quot;&gt;picture&lt;/a&gt; of the entire architecture as described in the blog.&lt;/p&gt;
&lt;p&gt;And in these blog posts you’ll find more related details:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-trigger-mechanism/&quot;&gt;Dynamics AX Retail third-party integration – Trigger mechanism&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;/blog/dynamics-ax-retail-how-to-automate-processes-and-interfaces-in-a-combined-way/&quot;&gt;Dynamics AX Retail third-party integration – Automate process AND data exchange&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;/blog/dynamics-ax-retail-3rd-party-integration-control-dashboard/&quot;&gt;Dynamics AX Retail third-party integration – Control dashboard&lt;/a&gt;&lt;br&gt;Dynamics AX Retail third-party integration – Agility (blog post will follow later)&lt;/p&gt;
&lt;p&gt;I hope this series of blogs will help to create more interaction on this topic online and inspire fellow DAX’ers around the globe to fully leverage the potential of Dynamics AX Retail. Last but not least I’d like to thank BizTalk specialist &lt;a href=&quot;https://www.linkedin.com/profile/view?id=AAkAAACcqX8BKyIou2BcKnvaL-j4wFbaEXZITDo&amp;authType=NAME_SEARCH&amp;authToken=83m9&amp;locale=en_US&amp;trk=tyah&amp;trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A10267007%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1445078277558%2Ctas%3Asimon%20rivas&quot;&gt;Simon Emmanuel Rivas&lt;/a&gt; for his valuable contributions to the design I’ll present in my blogs.&lt;/p&gt;
&lt;p&gt;Happy DAX’ing!&lt;br&gt;Patrick&lt;/p&gt;
</content:encoded><category>Functional</category></item><item><title>Dynamics AX methodology: complex integration designs – How to keep overview</title><link>https://patrickmouwen.com/blog/methodology-complex-integration-designs-how-to-keep-overview/</link><guid isPermaLink="true">https://patrickmouwen.com/blog/methodology-complex-integration-designs-how-to-keep-overview/</guid><description>A way to document integration designs that span several systems, so the solution stays comprehensible as the project grows around it.</description><pubDate>Sun, 18 Oct 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Some people hate it.. some people cherish it as a means to eternalize their brilliant designs… DOCUMENTING. One way or the other, in the bigger projects you can easily fill up a local library with all the paper produced. That’s why a good solution design is crucial in these projects. If such a design covers 1 system like AX, it’s easier to come to a holistic view on the desired solution. But what if your solution spans across multiple systems, all requiring some installation, configuration and customization. &lt;em&gt;How do you keep the overview without getting lost in the details?&lt;/em&gt; For this situation your solution design needs an extra helper: the &lt;strong&gt;UML sequence diagram&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/methodology-complex-integration-designs-how-to-keep-overview/1.-Microsoft-Dynamics-AX-Methodology-Documentation.png&quot;&gt;&lt;img src=&quot;/images/blog/methodology-complex-integration-designs-how-to-keep-overview/1.-Microsoft-Dynamics-AX-Methodology-Documentation.png&quot; alt=&quot;Microsoft Dynamics AX Methodology - Documentation&quot;&gt;&lt;/a&gt;&lt;br&gt;In this blog I’ll publish you my personalized “UML Sequence Digram +”. It doesn’t ‘just’ show the sequence of flows as a UML Sequence Diagram typically does, but it highlights all of the following elements which together form your entire solution:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installation elements (highlighted in brown)&lt;/li&gt;
&lt;li&gt;Configuration elements (highlighted in red)&lt;/li&gt;
&lt;li&gt;Customized elements (highlighted in purple)&lt;/li&gt;
&lt;li&gt;Interface elements (highlighted in green)&lt;/li&gt;
&lt;li&gt;Business tasks and automated process tasks (highlighted in blue)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below you find two examples of the “UML Sequence Diagram +”, 1 for deploying the integration of a third-party online store with Dynamics AX 2012 R3 Retail and 1 for a specific interface flow of this integration (the item price flow).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/methodology-complex-integration-designs-how-to-keep-overview/2.-Microsoft-Dynamics-AX-Channel-configuration.jpg&quot;&gt;&lt;img src=&quot;/images/blog/methodology-complex-integration-designs-how-to-keep-overview/2.-Microsoft-Dynamics-AX-Channel-configuration.jpg&quot; alt=&quot;Microsoft Dynamics AX - Channel configuration&quot;&gt;&lt;/a&gt;Example 1: deployment of a third-party sales channel&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/methodology-complex-integration-designs-how-to-keep-overview/3.-Microsoft-Dynamics-AX-3rd-party-POS-E-commerce-integration-Pricing.jpg&quot;&gt;&lt;img src=&quot;/images/blog/methodology-complex-integration-designs-how-to-keep-overview/3.-Microsoft-Dynamics-AX-3rd-party-POS-E-commerce-integration-Pricing.jpg&quot; alt=&quot;Microsoft Dynamics AX third-party POS e-commerce integration - Pricing&quot;&gt;&lt;/a&gt;Example 2: update price flow&lt;/p&gt;
&lt;p&gt;The advantage of this diagram is that when you’re fully into the process of shaping and prototyping your solution, you can quickly keep your documentation in sync by only adding elements to the diagram with a specific ID and meta data. How? The UML Sequence Diagram is a Visio template (&lt;a href=&quot;https://onedrive.live.com/redir?resid=79255561C5EDE5D5!23937&amp;authkey=!H1FDGTagvjs%24&amp;ithint=folder%2cvsdm&quot;&gt;download link&lt;/a&gt;) which is baselined by a connected Excel template (&lt;a href=&quot;https://onedrive.live.com/redir?resid=79255561C5EDE5D5!23937&amp;authkey=!H1FDGTagvjs%24&amp;ithint=folder%2cvsdm&quot;&gt;download link&lt;/a&gt;). In this Excel template you create the elements and all meta data which you want to store for the elements. If you want to change the name of your element you can do it quickly in Excel – the Visio template is only for having the graphical overview of all the elements. I also have the habit of saving screenshots to a file location with the ID of the element and a suffix number (in case of multiple screenshots per element).&lt;br&gt;The templates are especially helpful in agile projects and environments where customer requirements tend to change on daily basis. You can postpone the moment on which you descend into fully detailed installation guides, setup guides etc. until you have confirmation from the customer about your design and/or prototype. And if you chose your level of meta data registration well enough, you have collected just enough details to provide very thorough documentation without the risk on leaving out any details.&lt;br&gt;All the related final documentation will follow the structure of the UML sequence diagram. Here’s an example for an installation guide (&lt;a href=&quot;https://onedrive.live.com/redir?resid=79255561C5EDE5D5!23937&amp;authkey=!H1FDGTagvjs%24&amp;ithint=folder%2cvsdm&quot;&gt;download link&lt;/a&gt;) which fits to example 1 above – Note the element IDs between parentheses:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/images/blog/methodology-complex-integration-designs-how-to-keep-overview/4.-AX-Documentation.png&quot;&gt;&lt;img src=&quot;/images/blog/methodology-complex-integration-designs-how-to-keep-overview/4.-AX-Documentation.png&quot; alt=&quot;AX Documentation&quot;&gt;&lt;/a&gt;&lt;br&gt;This approach also saves people from having to dig through a linear document in order to find what they want to know. They can identify the specific element which they’re interested in and quickly descend into the right document and element section by the color of the element and the ID of the element.&lt;/p&gt;
&lt;p&gt;I hope this will help you improving the overall quality of your documentation and managing your document libraries in general.&lt;/p&gt;
&lt;p&gt;Happy DAX’ing!&lt;br&gt;Patrick&lt;/p&gt;
</content:encoded><category>Ax Methodology</category></item></channel></rss>