How to Extend Customer List View adding Custom Field on Dynamics 365 Retails & Commerce POS

Pre-Requisite

1.     Visual Studio 19

2.     SQL Server

3.     Scale Unit project from GitHub repository

( https://github.com/microsoft/Dynamics365Commerce.ScaleUnit ).

4.    Verify you version and download as per match.



1.      Download and Install SDK’s and runtime.

·        sdk-2.1.513-windows-x64-installer

·        runtime-2.1.17-windows-x64-installer

·        .NET Core 3.1 SDK

·        Windows SDK (10.0.10586.0)

·        .NET 6.0 Runtime

·        .NET Core 6.0 Runtime

2.     After installation of sdk and runtime.

3.    Copy you scale unit project from download to Service Volume (k)



Development

1.     Create MS Dynamics 365 FO project and add custom field on CustTable and Form.

 



     2.     Result



3.   Add same custom field on ax.Custtable with script. 

4.   ALTER  TABL ax.CustTable  Add  RefNoEx nvarchar(510)  Default  ('').

5.     Now link this field with the acutal field. Add Resource file with XML.



XML Code

<RetailCdxSeedData  Name="AX7"  ChannelDBSchema="ext ChannelDBMajorVersion="7">

<Subjobs>

<!--Adding  additiona column t (existingRetailTransactionTabl an want t pul i bac t HQ.Fo uploa subjobs seth OverrideTarge propert to   "false" a ilustrate below Thi wil telCD t us th tabl define b TargetTableNam an TargetTableSchem aextensio tabl o thi subjob.-->


<Subjob  Id="CUSTTABLE"  TargetTableName  ="CUSTTABLETargetTableSchema="ax AxTableName="CUSTTABLE IsUpload="falseOverrideTarget="false">

    <ScheduledByJobs>

        <ScheduledByJob>1010</ScheduledByJob>

    </ScheduledByJobs>

<AxFields>


<!--If  yo notic th existin column ar noliste her i th <Field tag it' becaus th existin field ar alreadmappe i th mai RetailCdxSeedDat resourc file w onl ad th delt here.

-->


<Field  Name="RefNoExt"/></AxFields>

</Subjob>

</Subjobs>

</RetailCdxSeedData>


6.     Now add handler class





HandlerClass - Code

internal  final  clas HandlerClass

{

[SubscribesTo(classstr(RetailCDXSeedDataBase)delegateStr(RetailCDXSeedDataBase,  registerCDXSeedDataExtension))]

public  static  voi RetailCDXSeedDataBase_registerSeedDataExtension(storgSeedDataResource,  List  resource)

{

if  (orgSeedDataResource  = classStr(RetailCDXSeedDataAX7))

{

resource.addEnd(resourceStr(CustomColumnCustTable_AX7));

}

}

}

  

7.     Now build the project and after that you have to run this job.



8.     Now open this form and select AX7 go to channel tables and search ax.CustTable.






9.     Now run full sync to update data from HQ to Channel. It will take some time to sync data.




10.  Now you can see the data in table.

     11.  Open Scale Unit Project from Service Volume (K) and build it. After                             successful build add CustomCustomerSearchColumns.ts.




CustomCustomerSearchColumns.ts - Code

import  {  ICustomerSearchColumn  }  from  "PosApi/Extend/Views/SearchView";

import  {  ICustomColumnsContext  }  from  "PosApi/Extend/Views/CustomListColumns"; import  {  ProxyEntities  }  from  "PosApi/Entities";

export  defaul(context:  ICustomColumnsContext):  ICustomerSearchColumn[]  =>  { return  [

{

title:  context.resources.getString("string_2"),

computeValue:  (row:  ProxyEntities.GlobalCustomer):  string  =>  { return  row.AccountNumber;  },

ratio:  15,

collapseOrder:  5,

minWidth:  120

},

{ 

title:  context.resources.getString("string_3"),

computeValue:  (row:  ProxyEntities.GlobalCustomer):  string  =>  {

return  row.FullName;  },

ratio:  20,

collapseOrder:  4,

minWidth:  200

}, {

title:  "Ref  No  Ext",

//title:  context.resources.getString("string_4"), computeValue:  (row:  ProxyEntities.GlobalCustomer):  string  =>  {

return  row.ExtensionProperties.filter(p  =>  p.Key  === "RefNoExt")[0].Value.StringValue  as  string;  },

ratio:  25,

collapseOrder:  1,

minWidth:  200

}, {

title:  context.resources.getString("string_5"),

computeValue:  (row:  ProxyEntities.GlobalCustomer):  string  =>  {

return  row.Email;  },

ratio:  20,

collapseOrder:  2,

minWidth:  200

}, {

title:  context.resources.getString("string_7"),

computeValue:  (row:  ProxyEntities.GlobalCustomer):  string  =>  {

return  row.Phone;  },

ratio:  20,

collapseOrder:  3,

minWidth:  120

}

];

};


12.  Register class in manifest.json

 

13.  Open ChannelDataServiceRequestTrigger.cs and add your code.




 ChannelDataServiceRequestTrigger.cs - Code

namespace  Contoso.CommerceRuntime.Triggers

{

using  Microsoft.Dynamics.Commerce.Runtime; using  Microsoft.Dynamics.Commerce.Runtime.Data;

using  Microsoft.Dynamics.Commerce.Runtime.DataModel;

using  Microsoft.Dynamics.Commerce.Runtime.DataServices.Messages; using  Microsoft.Dynamics.Commerce.Runtime.Messages;

using  System;

using  System.Collections.Generic; using  System.Linq;

using  System.Threading.Tasks;

public  class  ChannelDataServiceRequestTrigger  :  IRequestTriggerAsync

{

public  static  readonly  string  PropertyKey  = "ExtConfigurationParameters";

 

///  <summary>

///  Gets  the  supported  requests  for  this  trigger.

///  </summary>

public  IEnumerable<Type>  SupportedRequestTypes

{

get

{

return  new  Type[]

{

typeof(GetChannelConfigurationDataRequest), typeof(SearchCustomersDataRequest)

};

}

}

 

///  <summary>

///  Pre  trigger  code.

///  </summary>

///  <paraname="request">The  request.</param

public  Task  OnExecuting(Request  request)

{

//  It's  only  stub  to  handle  async  signatur

return  Task.CompletedTask;

}

///  <summary>

///  Post  request  trigger

///  </summary>

///  <paraname="request">request</param>

///  <paraname="response">response</param>

public  async  Task  OnExecuted(Request  request,  Response  response)

{

switch  (request)

{

case  GetChannelConfigurationDataRequest  originalRequest: var  data  =  response  as

SingleEntityDataServiceResponse<ChannelConfiguration>;

if  (data  !=  null  &&  data.Entity  !=  null  && data.Entity.GetProperty(PropertyKey)  ==  null)

{

//  In  this  example,  we  just  put  the  configuration parameters  as  part  of  channelConfiguration  property.

var  configurationParameters  =  (await request.RequestContext.ExecuteAsync<EntityDataServiceResponse<RetailConfigurati onParameter>>(new GetConfigurationParametersDataRequest(originalRequest.ChannelId)).ConfigureAwai t(false)).ToList();

//  The  reason  we  need  a  lock  here  because  of  thread-safety.

//  ChannelConfiguration  is  an  object  required  in  moscrt  request,  and  we  cached  in  memory  on  the  underlying  ChannelDataService.

//  In  case  there  is  concurrent  crt  request,  without lock  here,  it  will  modify  against  the  same  ChannelConfiguration  and  will  result as  100%  CPU  usage  in  worst  case.

//  NOTE:  both  SetProperty  and  ExtensionProperties  are not  thread-safe.

//  NOTE:  same  situation  for  DeviceConfiguration,  in which  it  is  also  required  in  most  crt  request  and  is  cached  in  underlying DataService.

lock  (data.Entity)

{

if  (data.Entity.GetProperty(PropertyKey)  ==  null)

{

data.Entity.SetProperty(PropertyKey,

configurationParameters);

}

}

}

break;

case  SearchCustomersDataRequest getCustomerSearchResultsDataRequest:

var res = (EntityDataServiceResponse<GlobalCustomer>)response;

foreach  (var  item  in  res)

{

string  value  "";

var  databaseContext  =  new DatabaseContext(request.RequestContext);

ParameterSet  configurationDataParameters  =  new ParameterSet 

{

["@AccountNum"]  =  item.AccountNumber

}; 

//Get  tender  type  Id  for  tokenized  tender  line  frodatabase

var  configurationDataSet  await  databaseContext

.ExecuteQueryDataSetAsync("SELECT  REFNOEXT  from ax.CUSTTABLE  where  ACCOUNTNUM  =  @AccountNum",  configurationDataParameters);

if  (configurationDataSet.Tables[0].Rows.Count  >  0)

{

value  =  configurationDataSet.Tables[0].Rows[0][0as  string;

}

item.ExtensionProperties.Add(new  CommerceProperty()

{

Key  =  "RefNoExt", Value  =  value

});

}

break; default:

throw  new  NotSupportedException($"Request '{request.GetType()}'  is  not  supported.");

}

}

}

}


14.  Rebuild the whole solution.

15.  Once the build is compiled successfully Now copy the commerce runtime library. CommerceRuntime.dll

From: “..\..\CommerceRuntime\bin\Debug\netstandard2.0” 

To: “K:\RetailServer\WebRoot\bin\Ext”




16.  Open CommerceRuntime.Ext.config file and add the following line in the composition tag.

<add source="assembly" value="CommerceRuntime" />



17.  Now deploy the extension on the dev machine by copying the code.

From:..\..\ScaleUnit\bin\Debug\netstandard2.0\CloudScaleUnitExtensionPackage\RetailClou dPOS\Code\Extensions”

To: “K:\RetailCloudPos\WebRoot\Extensions”

 

18.  Now login to pos and go to setting to check package




19.  Now go to customer








Comments