Retail assortments and planned orders extensions

Microsoft have created an excellent description of this in the Assortment management doc-page. Retail assortments are essential to define what products that should be available across retail channels. Assigning a product to an assortment, will assign the product to the stores that have the assortment. This makes it possible to sell the product in the store.

But there is something missing, and that is to use assortments for replenishment and procurement. Retailers want the master planning to only suggest procurement and transfers on products that belongs to the stores assortments. You can control requirement parameters per warehouse, but there is no standard way to use the assortment to control the generation of planned orders.

This blog post is to show how to make a very small extension that allows you to make sure that only products that belongs to a stores assortment will generate planned orders. The solution I will make use of is to look into how the product lifecycle state functionality is working, and extend this with an assortment planning parameter. I have called this parameter “Is lifecycle state active for assortment procurement

What it will do, is to validate if a product is in the assortment of the store, and if it is, then the product will be requirement calculated and will generate planned orders. If the product is not in the assortment of the store, that no planned orders will be generated.

To make this happen, I needed to create 4 extensions. The three first is adding a new field on the product lifecycle form.  For an experienced developer this is easy to create, and no need to spend time on in this this blog-post.

The real fun is how to manage and control the planned order generation. This happens in in an extension to the ReqSetupDim class.  Here there is a lookup to the assortment on the product, and checks if the store have this assortment.  If not, then the masterplanning will not generate any planned orders. I therefore create an extention class and use the new method wrapping/CoC feature to add some additional code.

///
<summary>
/// Contains extension methods for the ReqSetupDim class.
/// </summary>

[ExtensionOf(classStr(ReqSetupDim))]
final class ReqSetupDim_extension
{

    ///
<summary>
    /// Validates if a product should be assortment planned
    /// </summary>

    /// The parm of the ReqSetupDim class.
    /// false if the product is not assortment planned; otherwise, return default value.
    public boolean  mustReqBeCreated(InventDim _inventDimComplete)
    {
        Boolean ret = next mustReqBeCreated(_inventDimComplete);

        if (ret)
        {
            if (inventdim.InventLocationId)
            {
                InventTable                 inventtable;
                EcoResProductLifecycleState ecoResProductLifecycleState;

                //Fetching fields from  inventtable
                select firstonly ProductLifecycleStateId, Product from  inventtable where inventtable.ItemId == this.itemId();

                //validating if the product is active for planning and that also assortment planning is enabled.
                select firstonly RecId from ecoResProductLifecycleState
                        where   ecoResProductLifecycleState.IsActiveForAssortmentPlanning == true
                            &amp;&amp;  ecoResProductLifecycleState.IsActiveForPlanning == true
                            &amp;&amp;  ecoResProductLifecycleState.StateId == inventtable.ProductLifecycleStateId;

                if(ecoResProductLifecycleState)
                {
                    RetailStoreTable                    store;
                    EcoResProduct                       product;
                    RetailAssortmentLookup              assortmentLookupInclude;
                    RetailAssortmentLookup              assortmentLookupExclude;

                    RetailAssortmentLookupChannelGroup  assortmentLookupChannelGroupInclude;
                    RetailAssortmentLookupChannelGroup  assortmentLookupChannelGroupExclude;

                    //Finding OMOperatingUnitID from the inventlocationId
                    while select firstonly OMOperatingUnitID from store
                        where store.inventlocation == inventdim.InventLocationId
                    {
                        //Check if the product is in the assortment of the store in question
                        select RecId from product
                            where product.RecId == inventtable.product
                        exists join assortmentLookupInclude
                            where   assortmentLookupInclude.ProductId == product.RecId
                                &amp;&amp;  assortmentLookupInclude.lineType == RetailAssortmentExcludeIncludeType::Include
                        exists join assortmentLookupChannelGroupInclude
                                where   assortmentLookupChannelGroupInclude.OMOperatingUnitId == store.OMOperatingUnitID
                                    &amp;&amp;  assortmentLookupChannelGroupInclude.AssortmentId == assortmentLookupInclude.AssortmentId
                        notexists join assortmentLookupExclude
                            where   assortmentLookupExclude.ProductId == product.RecId
                                &amp;&amp;  assortmentLookupExclude.lineType == RetailAssortmentExcludeIncludeType::Exclude
                        exists join assortmentLookupChannelGroupExclude
                            where   assortmentLookupChannelGroupExclude.OMOperatingUnitId == store.OMOperatingUnitID
                                &amp;&amp;  assortmentLookupChannelGroupExclude.AssortmentId == assortmentLookupExclude.AssortmentId;

                        if (!product)
                        {
                            ret = false; //The product does NOT belong to the stores assortment, and should not be planned
                        }
                    }
                }
            }
        }
        return ret;
    }
}

I also have code to restrict creation of manual purchase orders, and where simular code can be used, but let’s hope that Microsoft can further extend standard Dynamics 365 with assortment based procurement planning.

Copy with pride, and let’s hope next year will give us 365 more opertunities.

POS Invoice Pay – #Dyn365F&O

A very nice omnichannel capability made available in Dynamics 365 version 8.1, is the ability for customers to pay their invoices directly in the POS. A scenario is that a customer is allowed to purchase “on-account” and then later pay all the invoices. Let’s say that the customer is in a hotel, and allows the customers to buy food, drinks and services throughout the stay. At the end of the stay the customer pays for all the services at the reception. Like “pay-before-your-leave”.

There is no requirement that the goods have to be sold on a POS. It is fully omnichannel capable. So, the orders can be created in the call-center, WEB or in stores. I would like to share this with you and how you can set it up in the Contoso demo data set. If you open the functionality profiles, you will find the possibility to enable paying:

  • Sales order invoice
  • Free text invoice
  • Project invoice (Yes! Even project invoices!)
  • Sales order credit note

The next thing you need to do is to add a “Sales invoice” – button to the transaction screen. (I’m using Houston store, and button grid F2T2)

This will add a sales invoice button to the POS design, that allows for paying invoices in POS.

The next thing is to create a POS transaction/order. First select a customer (like Karen), and then use the on-account button to sell the goods.

On the payment screen you can say how much you would like to put on account, and you also see that the credit limit and balance is available.

The next step requires that the there are some periodic batch jobs, that needs to run;

1. Run the “P-job”, to fetch the transactions from the channel database.

2. Run the “Calculate statement” (manually or in batch)

3. Run the “Post statement” (This process will create the sales order and the invoice)

!Make sure the statement is posted and invoiced before continuing!

The option you now have is to continue to the process in Dynamics 365, and create an automatic sending of the invoice to the customer through print management, or have the customer come to the “reception” and pay for the goods directly.

To pay the order, select the Karen customer, and use the Sales Invoice button.

If you have done all right, you should find the invoice in the list now. (If you have enabled aggregation in the parameters, you will have a single invoice per customer)

I can then select the invoice (or multiple), and pay it using cash, card, loyalty (And even on-account again)

This opens up for some very nice omnichannel processes, and I hope that Microsoft invests further in this. It would be nice to actually see the actual lines on the invoices that is being paid, and to even print-out the invoice if the customer requires this. Also I suggest that for retailers, use the modern report possibility to make the invoice look awesome.

Take care friends, and thanks for all your support and encouragement!

A quick look at download Retail distribution jobs (CDX)

Commerce Data Exchange (CDX) is a system that transfers data between the Dynamics 365 F&O headquarters database based and retail channels databases(RSSU/Offline database). The retail channels databases can the cloud based “default” channel database, the RSSU database and offline databases that is on the MPOS devices. If the look at the following figure from Microsoft docs, this blog post is explaining how to practically understand this.

What data is sent to the channel/offline databases?

In the retail menus you will find 2 menu items; Scheduler
jobs
and scheduler subjobs. Here the different data that can be sent is defined.

When setting up Dynamics 365 the first time, Microsoft have defined a set to ready to use scheduler jobs that get’s automatically created by the “initialize” menu item, as described here.

Scheduler jobs is a collection of the tables that should be sent, and sub jobs contains the actual mapping between D365 F&O and channel database fields. As seen in the next picture, the fields on the table CustTable in D365 is mapped towards the AX.CUSTTABLE in the channel database.

To explore what is/can be transferred, then explore the Scheduler jobs and scheduler subjobs.

Can I see what data is actually sent to the channel/offline databases?

Yes you can! In the retail menu, you should be able to find a Commerce Data Exchange, and a menu item named “Download sessions”.

Here you should see all data that is sent to the channel databases, and here there are a menu item names “Download file”.

This will download a Zip file, that contains CSV files, that corresponds to the Scheduler
jobs
and scheduler subjobs.

You can open this file in Excel to see the actual contents. (I have a few hidden columns and formatted the excel sheet to look better). So this means you can see the actual data being sent to the RSSU/Offline channel database.

All distribution jobs can be set up as batch jobs with different execution reoccurrence. If you want to make it simple but execute download distribution job 9999 to run every 30 minutes. If you have a more complex setup and need to better control when data is sent, then make separate distribution batch-jobs so that you can send new data to the channel databases in periods when there are less loads in the retail channels.

Too much data is sent to the channel databases/offline database and the MPOS is slow?

Retail is using change tracking, and this makes sure that only new and updated records is sent. This makes sure that amount of data is minimized. There is an important parameter, that controls how often a FULL distribution should be executed. By default it is 2 days. If you have lots of products and customers, we see that this generates very large distribution jobs with millions of records that will be distributed. By setting this to Zero, this will not happen. Very large distributions can cripple your POS’es, and your users will complain that the system is slow, or they get strange database errors. In version 8.1.3 it is expected to be changed to default to zero, meaning that full datasets will not be distributed automatically.

Change tracking seams not to be working?

As you may know, Dynamics 365 have also added the possibility to add change tracking on data entities when using BOYD. I have experienced that adjusting this affect the retail requirement for change tracking. If this happens, please use the Initialize retail scheduler to set this right again.

Missing upload transactions from your channel databases?

In some rare cases it have been experienced that there are missing transactions in D365, compared to what the POS is showing. The trick to resent all transactions is the following:

Run script: “delete crt.TableReplicationLog” in the RSSU DB. And the next P job will sync all transactions from RSSU DB (include missing ones).

 

Using Cloud POS as your retail mobile device

Handheld functionality for retailers is a question I get a lot. Then typical in the area of counting, replenishment, receive and daily POS operations. In version 8.1 Microsoft have taken a small step forward to make it easier to use any handheld device that supports a common browser. Because Cloud POS (CPOS) runs in a browser, the application isn’t installed on the device. Instead, the browser accesses the application code from the CPOS server. CPOS can’t directly access POS hardware or work in an offline state.

What Microsoft have done is to make the CPOS change according to the screen size, to work more effectively on your device. To make it simple, I just want to show you how it looks on my iPhone.

Step 1: Direct your browser towards the URL of where the CPOS is located. In LCS you will find the URL here:

Step 2: Activate your POS on mobile device by selecting store and register, and log in

Step 3: Log into CPOS and start using it. Here are some sample screens from my iPhone, where I count an item using CPOS.

You can also “simulate” this in your PC browser, but just reducing the size of your browser window before you log into CPOS. Here I’m showing the inventory lookup in CPOS.

What I would love to see more of is:

– Barcode scanning support using camera

– The ability to create replenishment/purchase orders in CPOS

– More receive capabilities like ASN/Pallet receive etc.

– Improved browser functionality (like back-forward browsing etc)

To me it seems clear that we will see additional improvements in CPOS, making it the preferred mobile platform for Dynamics 365 for Retail. As we get a little, I hope to see more of this as Microsoft is definitely investing in this area. In our own customer projects we will be developing more and more functionality using RTS (Real Time Service calls) to add more features to be used together with CPOS.

To take this to the next level, please also check evaluate to create a hybrid app, that incorporate CPOS in a app friendly way. Sources say that this will also allow us to build extensions like camera barcode scanning

The direction is right and my prediction for the future is that: Mobile Retail device = CPOS.

Focus18 – EMEA – London

The User Groups for Dynamics 365, AX, CRM, BC/NAV, and Power BI road-trip named Focus is arriving to Europe and is making a stop in London from 5-6 September, 2018 featuring dive deep sessions covering advanced topics on D365 Finance and Operations and Customer Engagement. Additionally, specific topics to the Retail space including modern POS, inventory management, sales orders, ecommerce, credit card processing and more. This is great stuff!

It is a privilege for me to participate and present together with great MVP’s, Microsoft experts and the Dynamics 365 community. If you want to check out my sessions, I will have the following sessions:

Deep dive into retail pricing and discounts. 

This session is about what product sales price and discount options that exists in Dynamics 365 for Retail – “out-of-the-box”.  With actual and real examples of how to implement and maintain your retail prices.

 

Learn, Try, Buy for Retailers.

The “Learn, Try and Buy for Retailers” is an accelerated onboarding approach that enables you to evaluate if a cloud enabled Dynamics 365 for Retail is the right direction, and to be able to learn as much as possible prior to performing a business- and solution analysis. This is available for agile and iterative approaches, and this sessions shows why buying a small Dynamics 365 license is an affordable investment to purchase before scope of implementation have been defined. Using VSTS (Visual Studio Team Services) is a central topic in this session.

Power BI and Retail.  How to get the numbers.

This sessions shows how to publish retail transactions into a Azure SQL database or CDS(Common Data Services), and then analyze the retail sales in Power BI.

Check out https://www.focusemea.com/locations/london as there are many other very interesting sessions.

 

See you in London!

 

 

MSDYN365FO: Automate repetitive tasks – the easy way

Here the other day, I got the task of posting a few thousand Retail Kit orders / BOM-Journals because they failed at the first time. I started, and managed to manually post 50 journals before my fingers got cramps and I started to feel dizzy. I could not multiselect the journals and post them, so I had to manually click “post” on each journal.

I surely sent a SR to Microsoft explaining that this should be easier in standard, and that SR is in process. But it will probably end up as a “As-Designed” state, or “post it to ideas.microsoft.com”.

But there is an easier low-tech way to solving this. Just install a Mouse-ghost app, and it will repeat the task for you. So I used the app “Mouse Recorder Premium” to post all the 1300 journals, and it went smoothly. Just record the clicks and then repeat for a 1000 times.

To make sure I did not “lock” my PC while this was performing, I started the task in a Hyper-V VM, and then it can run in the background.

That’s today’s small trick to get rid of repetitive tasks