Configuring products and price lists in Dynamics 365 is complicated and time-consuming. I wanted to create a process to quickly migrate this data from one environment to the next. I had about 100 products, 40 product bundles, and 25 price lists to migrate into a production environment. I did not have any product hierarchies, notes, sales literature, competitors, or discounts so I thought this would be an easy migration. I first attempted to use the Configuration Migration Tool provided by Microsoft, but I quickly discovered that transferring product bundles isn’t supported.
I attempted to import the records myself using the Import Wizard in Dynamics. The key to my approach required a Logic App in Azure (or a Flow in Power Automate) to export the Product Association data that links the product to the product bundle. I had to make some changes once I imported the data to set the default price list and update the statuses of the products, but I avoided fully recreating the products manually, which would have taken me much longer.
First, export data for the following entities from the source Dynamics environment:
- Unit Group
- Price List
- Product (exclude the product bundle products)
- Product Bundles (only the product bundle products)
- Price List Item
When I exported the data, I created a view for each entity that contained all of the fields (columns) available for that entity. If necessary, write conditions for the view to limit the records desired. For example, for products, I had two views. One view of only the products and one view of only the product bundles. Export each entity’s data to an Excel spreadsheet and then convert each file to CSV format.
The Product Association data was more complicated to export. I wanted to look up products by Product ID on import instead of by name, but when I tried to add the Product ID field for the product and the product bundle to the view, I could only access the Product ID for the product bundle. I worked around this limitation by creating a simple Logic App, but a Flow would also work. With a few actions, I queried for the data I wanted, created an object containing the values I needed, and output a CSV file that I import into my new Dynamics environment. Manually run the Logic App once you create it to generate your file for import.
The steps needed for the Logic App:
- Use a recurrence trigger with any interval and frequency. You’ll manually trigger the logic app so the timings don’t matter here. I set my recurrence for a long time between runs in case I forget to disable my logic app and it runs in the future.
- Initialize an array variable to collect your data objects.
- List the Product Association records.
- For each product association record, retrieve the product and the product bundle records. These steps will be wrapped in a for each action automatically when you add dynamic content from the list record step. You could also retrieve these by expanding the list step in #3 and parsing out the data.
- Append a JSON object to the array containing the data you want in your export file.
The code below shows more details about where each piece of data comes from for the object created in this action.
- Pass the array of data into the create CSV table action and create an output file. I output my file to blob storage.
This is the complete Flow collapsed down.
Once you have all the data exported, follow the steps below to import the data into your target Dynamics environment using the Import Wizard. Map the fields in the exported file to the matching field for import. While importing, I ignored fields created on, created by, etc. that weren’t important to preserve in my target environment.
- Import the Unit Groups.
- Import the Units.
- Import the Price Lists.
- Import the Products. Map the Status and Status Reason fields to be set to “Active” for all imported products.
- Import the Product bundles. Map the Status and Status Reason fields to be set to “Draft” for all imported product bundles.
- Import the Product Associations. Map the ProductID source field to the Associated Product lookup field and the ProductBundleID source field to the Product lookup field. Map the Status and Status Reason fields to be set to “Draft” for all imported product bundles.
- Import the Price List Items. Map the Price List Name field to the Price List lookup field. Map the Product ID to the Product lookup field instead of the mapping that is automatically generated for the Product lookup field. Set the Process ID field to ignore.
- After importing, link any default price lists to the products. Change each product or product bundle to the correct Status in the following order:
- Activate the product bundles.
- Retire any retired product bundles.
- Retire any retired products.