Your Guide to Efficiently Setting Up Dynamics 365 Commerce Cloud POS
Setting Up Dynamics 365 Commerce Cloud POS: A Comprehensive Guide
1) Initiate the process by obtaining the Dynamics commerce scale unit from the GitHub repository. You can find it at the following address:
https://github.com/microsoft/Dynamics365Commerce.ScaleUnit
2) Before proceeding further, verify your Finance and Operations (FnO) version to ensure compatibility with the scale unit.
3) Download the appropriate release corresponding to your FnO version.
4) To create an ideal environment for the setup, download and install the necessary SDKs and runtimes, including:
a. sdk-2.1.202-windows-x64-installer
b. sdk-2.1.513-windows-x64-installer
c. runtime-2.0.9-windows-x64-installer
d. runtime-2.1.17-windows-x64-installer
g. TypeScript
version 2.2.2
5) Unzip the
downloaded repository, and move this to K drive with some meaning full name.
6) Browse and open
the scale unit in Visual Studio 19.
7) Now Clean the projects
by removing sample artifacts.
a. For Chanel
Database delete the SQL script
b. For Commerce
Runtime delete all the artifacts/Folder except DefinePosExtensionTrigger.cs file
in the Triggers folder.
c. For POS delete
all the folders.
8) Update DefinePosExtensionTrigger.cs
file in the Commerce Runtime project with the Extension name.
9) Update the
manifest.json file in the POS project.
10) In the POS
project, create a folder that is named SearchExtension.
11) In the SearchExtension folder,
create a folder that is named ViewExtensions.
12) In the ViewExtensions folder,
create a folder named Search.
13) In the Search folder,
create a Typescript file that is named CustomCustomerSearchColumns.ts.
14) In the CustomCustomerSearchColumns.ts file,
add the following import statements to import the relevant entities
and context.
import { ICustomerSearchColumn } from "PosApi/Extend/Views/SearchView";
import { ICustomColumnsContext } from "PosApi/Extend/Views/CustomListColumns";
import { ProxyEntities } from "PosApi/Entities";
15) Add the
existing column and the custom column to the file.
export default (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: context.resources.getString("string_4"),
computeValue: (row: ProxyEntities.GlobalCustomer): string => { return row.FullAddress; },
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
}
];
};
16) You will now
add the resource file for the localization of the column name. In the SearchExtension folder,
create a folder that is named Resources.
17) In the Resources folder,
create a folder named Strings.
18) In the Strings folder,
create a folder named en-US.
19) In the en-us folder,
create a file that is named resources.resjson.
20) In the resources.resjson file,
add the following code.
{
//========================
Sample View extensions strings. ========================
"string_0" : "Quick compare
products",
"_string_0.comment" : "Product search
page app bar command label.",
"string_1" : "View customer
summary",
"_string_1.comment" : "Customer search
page app bar command label.",
//========================
Column names. ========================
"string_2" : "ACCOUNT
NUMBER_CUSTOMIZED",
"_string_2.comment" : "Customer search
column name.",
"string_3" : "NAME",
"_string_3.comment" : "Customer search
column name.",
"string_4" : "ADDRESS",
"_string_4.comment" : "Customer search
column name.",
"string_5" : "CONTACT
EMAIL",
"_string_5.comment" : "Customer search
column name.",
"string_7" : "PHONE
NUMBER",
"_string_7.comment" : "Customer search
column name."
}
21) In the SearchExtension folder,
create a folder that is named DialogSample.
22) In the DialogSample folder,
create a TypeScript file that is named MessageDialog.ts.
23) In the MessageDialog.ts file,
add the following import statements to import the relevant entities
and context.
import { ShowMessageDialogClientRequest,
ShowMessageDialogClientResponse, IMessageDialogOptions } from "PosApi/Consume/Dialogs";
import { IExtensionContext } from "PosApi/Framework/ExtensionContext";
import { ClientEntities } from "PosApi/Entities";
24) Create a class
that is named MessageDialog.
export default class MessageDialog {}
25) In the MessageDialog class,
add the following show method.
public static show(context: IExtensionContext, message: string): Promise<void> {
let promise: Promise<void> = new Promise<void>((resolve: ()
=> void, reject: (reason?: any) => void) =>
{
let messageDialogOptions:
IMessageDialogOptions = {
title: "Extension Message Dialog",
message:
message,
showCloseX: true, // this property will return "Close" as
result when "X" is clicked to close dialog.
button1: {
id: "Button1Close",
label: "OK",
result: "OKResult"
},
button2: {
id: "Button2Cancel",
label: "Cancel",
result: "CancelResult"
}
};
let dialogRequest:
ShowMessageDialogClientRequest<ShowMessageDialogClientResponse> =
new
ShowMessageDialogClientRequest<ShowMessageDialogClientResponse>(messageDialogOptions);
context.runtime.executeAsync(dialogRequest).then((
result:
ClientEntities.ICancelableDataResult<ShowMessageDialogClientResponse>)
=> {
if (!result.canceled) {
context.logger.logInformational("MessageDialog result: " +
result.data.result.dialogResult);
resolve();
}
}).catch((reason: any) => {
context.logger.logError(JSON.stringify(reason));
reject(reason);
});
});
return promise;
}
26) You will now
add a custom app bar button in the search view to open a dialog box that
contains details about the selected customer. In the ViewExtensions folder,
create a Typescript file that is named ViewCustomerSummaryCommand.ts.
27) In the ViewCustomerSummaryCommand.ts file,
add the following import statements to import the relevant entities
and context.
import { ProxyEntities } from "PosApi/Entities";
import { ArrayExtensions, ObjectExtensions } from "PosApi/TypeExtensions";
import { IExtensionCommandContext } from "PosApi/Extend/Views/AppBarCommands";
import * as SearchView from "PosApi/Extend/Views/SearchView";
import MessageDialog from "../../Controls/DialogSample/MessageDialog";
28) Create a class
that is named ViewCustomerSummaryCommand, and extend it from CustomerSearchExtensionCommandBase.
export default class ViewCustomerSummaryCommand extends
SearchView.CustomerSearchExtensionCommandBase {}
29) In the ViewCustomerSummaryCommand class,
declare a private variable to capture the results when searching for the
selected customer.
private _customerSearchResults:
ProxyEntities.GlobalCustomer[];
30) Add the
class constructor method to initialize and clear the search handler.
constructor(context:
IExtensionCommandContext<SearchView.ICustomerSearchToExtensionCommandMessageTypeMap>)
{
super(context);
this.id = "viewCustomerSummaryCommand";
this.label = context.resources.getString("string_1");
this.extraClass = "iconLightningBolt";
this._customerSearchResults
= [];
this.searchResultsSelectedHandler
= (data: SearchView.CustomerSearchSearchResultSelectedData): void => {
this._customerSearchResults
= data.customers;
this.canExecute = true;
};
this.searchResultSelectionClearedHandler
= (): void => {
this._customerSearchResults
= [];
this.canExecute = false;
};
}
31) Add the init method
to initialize the visible property.
protected init(state:
SearchView.ICustomerSearchExtensionCommandState): void {
this.isVisible = true;
}
32) Add the execute method
to handle the app button click handler. The execute method reads the
data for the selected customer from the handler and shows it in a simple dialog
box.
protected execute(): void {
let customer:
ProxyEntities.GlobalCustomer = ArrayExtensions.firstOrUndefined(this._customerSearchResults);
if
(!ObjectExtensions.isNullOrUndefined(customer)) {
let message: string = "Customer
Account: " + (customer.AccountNumber || "") + " | ";
message += "Name: " + customer.FullName +
" | ";
message += "Phone Number: " + customer.Phone + " | ";
message += "Email Address: " + customer.Email;
MessageDialog.show(this.context, message);
}
}
33) The whole code
sample should look like this.
import { ProxyEntities } from "PosApi/Entities";
import { ArrayExtensions, ObjectExtensions } from "PosApi/TypeExtensions";
import { IExtensionCommandContext } from "PosApi/Extend/Views/AppBarCommands";
import * as SearchView from "PosApi/Extend/Views/SearchView";
import MessageDialog from "../../DialogSample/MessageDialog";
export default class ViewCustomerSummaryCommand extends
SearchView.CustomerSearchExtensionCommandBase {
private _customerSearchResults:
ProxyEntities.GlobalCustomer[];
/**
* Creates
a new instance of the ViewCustomerSummaryCommand class.
* @param
{IExtensionCommandContext<CustomerDetailsView.ICustomerSearchToExtensionCommandMessageTypeMap>}
context The command context.
*
@remarks The command context contains APIs through which a command can
communicate with POS.
*/
constructor(context:
IExtensionCommandContext<SearchView.ICustomerSearchToExtensionCommandMessageTypeMap>)
{
super(context);
this.id = "viewCustomerSummaryCommand";
this.label =
context.resources.getString("string_1");
this.extraClass = "iconLightningBolt";
this._customerSearchResults
= [];
this.searchResultsSelectedHandler
= (data: SearchView.CustomerSearchSearchResultSelectedData): void => {
this._customerSearchResults
= data.customers;
this.canExecute = true;
};
this.searchResultSelectionClearedHandler
= (): void => {
this._customerSearchResults
= [];
this.canExecute = false;
};
}
/**
*
Initializes the command.
* @param
{CustomerDetailsView.ICustomerDetailsExtensionCommandState} state The state
used to initialize the command.
*/
protected init(state:
SearchView.ICustomerSearchExtensionCommandState): void {
this.isVisible = true;
}
/**
*
Executes the command.
*/
protected execute(): void {
let customer:
ProxyEntities.GlobalCustomer = ArrayExtensions.firstOrUndefined(this._customerSearchResults);
if
(!ObjectExtensions.isNullOrUndefined(customer)) {
let message: string = "Customer
Account: " + (customer.AccountNumber || "") + " | ";
message += "Name: " + customer.FullName +
" | ";
message += "Phone Number: " + customer.Phone + " | ";
message += "Email Address: " + customer.Email;
MessageDialog.show(this.context, message);
}
}
}
34) In the SearchExtension folder,
create a JSON file that is named manifest.json.
35) In the manifest.json file,
add the following code.
{
"$schema": "../manifestSchema.json",
"name": "Pos_Extensibility_Samples",
"publisher": "Microsoft",
"version": "7.2.0",
"minimumPosVersion": "7.2.0.0",
"components": {
"resources": {
"supportedUICultures": [ "en-US" ],
"fallbackUICulture": "en-US",
"culturesDirectoryPath": "Resources/Strings
",
"stringResourcesFileName": "resources.resjson",
"cultureInfoOverridesFilePath": "Resources/cultureInfoOverrides.json"
},
"extend": {
"views": {
"SearchView": {
"customerAppBarCommands": [ { "modulePath": "ViewExtensions/Search/ViewCustomerSummaryCommand" } ],
"customerListConfiguration": { "modulePath": "ViewExtensions/Search/CustomCustomerSearchColumns" }
}
}
}
}
}
36) In the POS.Extensions project,
open the extensions.json file, and update it with SearchExtension samples,
so that the POS includes this extension at runtime.
{
"extensionPackages": [
{
"baseUrl": "SampleExtensions2"
},
{
"baseUrl": "SearchExtension"
}
]
}
37) In the tsconfig.json file,
comment out the extension package folders in the exclude list. The POS uses
this file to include or exclude the extension. By default, the list contains
the whole excluded extensions list. To include an extension as part of the POS,
add the name of the extension folder, and comment out the extension in the
exclude list, as shown here.
"exclude": [
"SampleExtensions"
//"SampleExtensions2",
//"SearchExtension"
],
38) Try to Rebuild
the whole solution, this step is tricky you might need to install other runtimes.
39) 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”
40) Open CommerceRuntime.Ext.config
file and add the following line in the composition tag.
<add source="assembly" value="CommerceRuntime" />
41) Now deploy the extension
on the dev machine by copying the code.
From:
”..\..\
ScaleUnit\bin\Debug\netstandard2.0\CloudScaleUnitExtensionPackage\RetailCloudPOS\Code\Extensions”
To: “K:\RetailCloudPos\WebRoot\Extensions”
42) Browse Cloud
POS and have a view of your created extension.
Comments
Post a Comment