Retail Extensibility in Dynamics AX 2012 R3 CU8 (CRT, RetailServer, MPOS) Part 1


Overview

The following document will teach some of the basic steps needed to carry out a simple customization.  There are quite a few moving parts that use different technologies; even with a simple customization as this sample. Also, some of the tricks shown below can help you to simplify the development mechanics and actually focus on the task at hand: “extending the Retail Solution”.

Attached is a zip file that includes all new and changed files of the sample.

The steps are carried out on the VM image that can be requested via LCS (https://lcs.dynamics.com/Logon/Index) which most partners have access to (Contoso sample).  Alternatively, PartnerSource (https://mbs.microsoft.com/partnersource/northamerica/) can be used to download the VM as well. Make sure you get the CU8 version.

It is recommended to review some of the online resources around the Retail solution, either now or during the processes of following this blog (https://technet.microsoft.com/en-us/library/jj710398.aspx).

This blog will focus on a very simple customization, since this is part 1. The basics reviewed in this blog are:

-          Extend the CRT by writing a new CRT service (no existing Retail SDK code change)

-          Extend RetailServer by writing a new customer action

-          Make MPOS UI design changes in AX and push them to the store

-          Extend MPOS by using the new RetailServer/CRT functionality from the UI

 

A future blog will cover topics and suggestions for changing existing CRT code.  Stay tuned for that.

This sample customization will update the MPOS terminal to look up a “cross-loyalty discount”. Assume for a moment that our company allows to apply loyalty discounts from another external company.  That discount must be looked up (by sending the phone number as an Id), presented to the MPOS operator and if he/she chooses applied to the current transaction.  See the screen shots below for the UI flow:

 

All changes are being made under the login contoso\emmah. If you use a different account, or different demo data altogether please adjust the below steps accordingly.

 

High-level steps

The following steps need to be carried out:

 Setup the Retail SDK CU8 for development

  1. Prepare MPOS to be run from Visual Studio from unchanged SDK code
  2. Activate the MPOS device
  3. Add a new operation and screen layout button to MPOS
  4. Customize MPOS source code
  5. Add new CRT service and register it with RetailServer
  6. Add new RetailServer action and register it with RetailServer
  7. Test
During steps 4, 5 and 6, code changes need to be made. Not all code that needs to be written is added to the text. In order to explain the code changes, the text refers to the files in the zip file.

Detailed steps

 

Setup the Retail SDK CU8 for development

Main point here is to keep a backup of the original “Retail SDK CU8” folder so we can later roll back or diff against. In my case, the original SDK folder is under the Administrator user’s Documents folder.

-          Open a Visual Studio x86 Native tools Command prompt as administrator

-          Mkdir "C:\Users\emmah\Documents\Retail SDK CU8"

-          Cd "C:\Users\emmah\Documents\Retail SDK CU8"

-          robocopy "C:\Users\Administrator\Documents\Retail SDK CU8" "C:\Users\emmah\Documents\Retail SDK CU8" /E

 

This new folder is now the place to carry out the changes (the work folder). Note, that in a real development environment, it is advised to use source control solutions like TFS, Git, or others.

 

Prepare MPOS to be run from Visual Studio from unchanged SDK code

 

-          Open MPOS solution in Visual Studio 2013 (C:\Users\emmah\Documents\Retail SDK CU8\POS Clients\Windows\C1\Pos.sln)

-          Change target dropdown to “Simulator”

-          Build and run in the debugger with F5

-          If you get error about MPOS already being installed, see Issues list at the end of this document.  Once solved, hitting F5 in VS should bring up MPOS

-          "Device activation" screen should be shown

 

Activate the MPOS device

 

Now find out which Channel Database RetailServer is configured to use. In inetmgr, browse to RetailServer, hit "Explore", open the web.config file and inspect the ConnectionString. In my case, it is using “RetailHoustonStore”.

 

Look up which channel is used (USRT/Retail/Setup/Retail Scheduler/Channel integration/Channel Database):

 

 Look up which registers are available (USRT/Retail/Common/Retail Channels/Retail Stores/Open Houston)

And look up of devices already exist (USRT/Retail/Setup/Devices)

I will be re-using the HOUSTON-3 device that is in pending state. Off course, it is also possible to create a new one.

 

Find RetailServer url for device activation by looking up inetmgr configuration, find port, etc. For CU8, the RetailServer url on my machine looks like this:

 

http://ax2012r2a.contoso.com:35080/RetailServer/v1

 

Here I am using the operator with Id 000160 and password 123.

Hitting the “Activate” button should continue to the "Sign in" screen

Carry out a dummy transaction to verify all is good. 

 

Note that the device we chose earlier does now show up as activated in AX:

Now that we have verified all is working, we are ready to extend the code. Stop debugger to quickly stop MPOS without having to log off.

Add a new operation and screen layout button to MPOS

 

In AX, add a new POS operation (USRT/Retail/Setup/POS/Operations) 

In the details for the HOUSTON store, find what the screen layout is (USRT/Retail/Common/Retail Channels/Retail Stores/HOUSTON/Screen Layout). In my case, the screen layout for the "Modern POS for Windows" application type is "FABCSH16:9".

Note: Screen layout may also be assigned to a specific register or cashier. In this example, the whole store uses the same layout.

In AX, add new button to the transaction screen 1 (USRT/Retail/Setup/POS/Screen layouts/ FabMGR16:9/Actions/Designer), name it "Cross Loyalty discount lookup"

Associate the button with the operation (in Designer/right click on button/Button properties)

In AX, run 1090 job (USRT/Retail/Periodic/Data distribution/Distribution schedule/1090/Run now)

 

In AX, verify that the job succeeded (USRT/Retail/Inquiries/CDX/Download sessions/Process Status message)

 

Launch MPOS with F5, log back on. You should see the new button in the transaction screen 1

Click the button. It will say "Operation is not supported". Makes sense, as MPOS does not know about the operation or how to handle it…

Customize MPOS source code

Unzip the “Retail SDK CU8 - Extensibility Sample 1.zip” file ontop of you “Retail Sdk CU8” work folder. This will update a few files (for MPOS, and adds the code for the CRT and RetailServer customization).

 

The main code changes in MPOS are:

-          In the Framework folder (generic for any client):

  • New activity to call out to RetailServer
  • New operation and operation handler for the whole UI flow (asking user, calling out to RetailServer, asking user for confirmation, applying total discount).
  • Register the new operation handler

-          In the C1 folder (MPOS specific):

  • In CartView.ts, making sure the discount is displayed/refreshed
  • Activity implementation

 

In Visual Studio, clean the whole solution, then rebuild and test with F5.

 

Now, hit the "Cross loyalty discount lookup" button again. At this point, you will see that the new MPOS sample code is being used. A new dialog pops asking to enter the loyalty number

 

If you type a phone number, and hit OK, you will get an error. Why? 

 

The reason is that we have not customized RetailServer yet, and MPOS is making the call to the not yet existing action.  You can clearly see by using tools like Fiddler, that the POST request to "http://ax2012r2a.contoso.com:35080/RetailServer/v1/Customers/GetCrossLoyaltyCardAction" fails with a 404 (Not Found).

 

Add new CRT service and register it with RetailServer

A CRT service is a small, single task (as opposed to a workflow, which is composed of multiple tasks).  To accomplish this simple task, all we need to write a function that takes the loyalty number (phone number) and returns a discount. In a real-world system, that function would call another process, web service or similar to get that information. In this sample code, we will have the value hard coded for a few phone numbers.

We need to implement a request class, a response class and the service (the source code with full VS project is part of the zipped folder)

    [DataContract]
public sealed class GetCrossLoyaltyCardRequest : Request
{
/// <summary>
/// Gets or sets the loyalty card number
/// </summary>
[DataMember]
public string LoyaltyCardNumber { get; set; }
}
    public sealed class GetCrossLoyaltyCardResponse : Response
{
/// <summary>
/// Gets or sets the calculated discount value.
/// </summary>
public decimal Discount { get; set; }
}
    public class GetCrossLoyaltyCardService : IRequestHandler
 

The above code adds a simple new CRT service. Note, that another customization approach is to edit existing functionality that is part of the Retail SDK.  However, it is suggested to extend the CRT by adding new code instead of existing. It will help to make a potential upgrade to a future version of the SDK easier (a future blog is planned to show some best practices around how and where to write your Retail customizations).

In order to register a new CRT dll with the host, in this case RetailServer, you must edit the commerceruntime.config file, that is in the binary location of the host. Use inetmgr again to find the binary location of RetailServer as you did earlier. 

The Visual Studio projects for both the CRT and RetailServer extensions include 2 MSBuild files that make referencing external files and deploying the target files easier. I highly recommend to use some similar approaches in your own development process (not for production deployment). 

The first include file, pre.settings is included at the top of each project. It allows to adjust the RetailServer binary path:

The second include file, post.targets is included at the bottom of each project. It needs to be included into any project that needs to “deploy” the newly built binary into RetailServer’s binary folder:

Note: Since the AfterBuild MSBuild target needs to be able to write to the RetailServer binary folder, Visual Studio has to be started elevated (run as Adminstrator).

Add new RetailServer action and register it with RetailServer

 

    [Export(typeof(IEdmModelFactory))]
[ComVisible(false)]
public class ExtendedEdmModelFactory : CommerceModelFactory
{

/// <summary>
/// Builds entity sets.
/// </summary>
protected override void BuildActions()
{
base.BuildActions();
var var1 = CommerceModelFactory.BindEntitySetAction<Customer>("GetCrossLoyaltyCardAction");
var1.Parameter<string>("LoyaltyCardNumber");
var1.Returns<decimal>();
}
}
[ExtendedController("Customers")]
[CommerceAuthorization(AllowedRetailRoles = new string[] { CommerceRoles.Employee }, CheckRetailOperation = false)]
public class NewEntitiesController : CustomersController
{
[HttpPost]
public decimal GetCrossLoyaltyCardAction(ODataActionParameters parameters)
{
CommerceRuntime runtime = CommerceRuntimeManager.Runtime;
GetCrossLoyaltyCardResponse resp = runtime.Execute<GetCrossLoyaltyCardResponse>(new GetCrossLoyaltyCardRequest() { LoyaltyCardNumber = (string)parameters["LoyaltyCardNumber"] }, null);
return resp.Discount;
}
}

 

The above code extends the CustomersController class by adding a new action called GetCrossLoyaltyAction.  By doing this, the final Url that MPOS uses is:

http://ax2012r2a.contoso.com:35080/RetailServer/v1/Customers/GetCrossLoyaltyCardAction

It makes sense for this sample to extend the CustomersController. In other cases, you may need to add your own custom controller class.

In order to register a new RetailServer dll, you must edit the Web.config file, that is in the root of the RetailServer web application path. Use inetmgr again to find the location. 

 

Test

 

Run through MPOS. Add a new item. Hit the new button, enter a made up phone number. See it returning 0. Enter "425-999-3333" and see it returning 3. 

 

In fiddler we can see the request and response with valid values:

 

Issues and solutions:

If you cannot run MPOS from the Pos.sln file because it is already installed, uninstall the app first. This link may also be helpful: http://blogs.msdn.com/b/wsdevsol/archive/2013/01/28/registration-of-the-app-failed-another-user-has-already-installed-a-packaged-version-of-this-app-an-unpackaged-version-cannot-replace-this.aspx

 

 

Thanks,

Andreas

 

Original link: http://blogs.msdn.com/b/axsa/archive/2015/02/17/extensibility-in-dynamics-ax-2012-r3-cu8-crt-retailserver-mpos-part-1.aspx (go back to it for zip file download...)

 

 

Retail SDK CU8 - Extensibility Sample 1.zip

Comments (16)

  1. Simon Williams says:

    Very in depth example – thanks.

    Did you plan to follow this up?

  2. If you have any other ideas for the next future blogs, please ping me here. I will try to cover the most requested items first.

  3. Hi Andreas says:

    I am trying to extend modern POS. When I am trying to activate the modern POS through VS 2013 , it is showing that device cannot be activated but it is activating in the AX.

    But it is not going to sign in page also.

    Can you please help me on this.

  4. Manish Acharya says:

    I am trying to extend modern POS. When I am trying to activate the modern POS through VS 2013 , it is showing that device cannot be activated but it is activating in the AX.

    But it is not going to sign in page also.

    Can you please help me on this.

  5. Ali Sanan says:

    Try after setting device status PENDING in AX.

  6. Manish Acharya says:

    Hi Ali,

    It is not related to the Pending Status in AX. The problem was that I have Modern POS package installed in my development machine. Thats y it was not running from Code.

    I have unistalled the package and it is working fine now.

    Thanks for your reply

  7. pradipta says:

    hi, is it possible to customize MPOS to such a extent to include the purchase functionality in the POS.sln

  8. Yasir says:

    How do you apply discounts to the current transaction and updates this in the cart.In order to do this where we have to do the customization.You have not mentioned this scenario  here.

  9. Tahoor says:

    Dear all,

    I am using AX 2012 R3 CU 9.

    I have installed Retail Modern POS and activated register HOUSTON-3 successfully.

    When I try to run Retail Modern POS app, I got error "Application Error".

    In event viewer,no show any error

    I have make sure to fill screen layout ID and visual profile.

    I am using user that has role "Retail Operation Manager" and make sure this user is a member of POSUsers.

    How to solve this issue? Please help.

    Thank you.

  10. Win says:

    Dear all,

    I tried according your steps.But i facing this error when i request the data  

    This service doesn't support OData requests in the form '~/entityset/action'

    How to solve this issue?

  11. Manish says:

    Hi Win,

    This is because the request you are sending from MPOS is not finding the correct match..Check the name of your parameters or name of your methods which you created in Retail Server and CRT.

  12. Waldemar Pross says:

    It would be nice to see how to call same services as MPOS is calling, using a PHP or Java client!

  13. Hitesh Manglani says:

    Hi Andreas,

    Is it possible for you to show how to extend the transaction lines, since it seems that the transaction is stored as a blob in the Database so extensibility seems different than the other entities like Customer.

  14. Hussain says:

    Hi,

    Can anybody tell me about changing in already existing entity that reflects from channel db or store database to view? for instance taking an example of suspended transaction, i want to show additional column on the screen of suspended transaction what i did is add the column in crt.SalesTransaction, and also update dbo.SalesTransaction and crt.CartsView in store db. I have also modify views where i can see the new added column. However the problem is connecting these two from view to database. I have seen both blogs Part 1 and Part 2 but couldn't succeed because it is not about adding new field in AX and than Store DB it is only about adding a new field in store db and than reflecting the changes on view.

    Thanks in advance

  15. Sergey Pikhulya says:

    to Hussain:

    See if this can help you: community.dynamics.com/…/188632

Skip to main content