8
How to build/customize a POS service assembly Overview Microsoft Dynamics AX setup includes SDK samples for Retail. These can be installed by selecting Retail SDK as part of the Microsoft Dynamics AX setup. The Retail SDK samples are installed in the Retail SDK\POS Plug-ins folder, under the current user’s Documents folder, as shown below:

How to Customize a POS Service Assembly

Embed Size (px)

DESCRIPTION

How to Customize a POS Service Assembly

Citation preview

Page 1: How to Customize a POS Service Assembly

How to build/customize a POS service assembly

OverviewMicrosoft Dynamics AX setup includes SDK samples for Retail. These can be installed by selecting Retail SDK as part of the Microsoft Dynamics AX setup.

The Retail SDK samples are installed in the Retail SDK\POS Plug-ins folder, under the current user’s Documents folder, as shown below:

Page 2: How to Customize a POS Service Assembly

The installed files include sample projects for individual Services and Triggers, as well as a Tutorials folder with additional documentation and in-depth samples.

Project and referencesIncluded in the sample folders are Visual Studio project (*.csproj) and solution (*.sln) files. The Services.sln file contains samples for all services exposed for customization.

The primary reference needed by a customized service (or trigger) implementation is:

Microsoft.Dynamics.Retail.Pos.Contracts (Microsoft.Dynamics.Retail.Pos.Contracts.dll)

This assembly contains definitions for all the interfaces exposed in the Retail SDK, and is included in the POS Plug-ins folder.

Additional assemblies may be required and can be found in the Microsoft Dynamics AX for Retail install folder, or other install locations for 3rd party assemblies.

Page 3: How to Customize a POS Service Assembly

Implementing the IService interface(s)

In order to implement a service (or trigger) there are two basic requirements:

1. Create a class that implements the service’s Contract.2. Annotate the class with the Export attribute.

Service and Trigger interfaces are defined in the Contracts assembly (Microsoft.Dynamics.Retail.Pos.Contracts), for example: IApplication, IBarcode, IBlankOperations, etc. Implement the interface as you would any normal .NET interface. Visual Studio’s ‘Implement Interface Explicitly’ menu action can automatically stub out the interface methods.

Once the interface has been declared and implemented, the class must also be annotated with an attribute that identifies it as an assembly that exports customized Retail SDK implementations. Without this attribute, the custom assembly will not be loaded into POS at run-time.

The required attribute is:

Page 4: How to Customize a POS Service Assembly

System.ComponentModel.Composition.ExportAttribute

The argument for the attribute is the type of the contract interface that the class implements. See example below:

Example:

using System.ComponentModel.Composition;using Microsoft.Dynamics.Retail.Pos.Contracts;using Microsoft.Dynamics.Retail.Pos.Contracts.BusinessObjects;using Microsoft.Dynamics.Retail.Pos.Contracts.DataEntity;using Microsoft.Dynamics.Retail.Pos.Contracts.Services;

namespace Microsoft.Dynamics.Retail.Pos.BlankOperations{

[Export(typeof(IBlankOperations))] public sealed class BlankOperations : IBlankOperations { [Import] public IApplication Application { get; set; }

#region IBlankOperations Members public void BlankOperation(IBlankOperationInfo operationInfo, IPosTransaction posTransaction) { // Application.RunOperation(PosisOperations.LogOff, null); } #endregion }}

Building the assemblyBuild the solution using Visual Studio according to the desired configuration, debug or retail.

Deploying the assemblyBefore deploying the new assembly, exit/stop any instances of POS.exe that may be running. In most cases POS only supports loading a single instance of a service at a time (triggers are an exception). As such, there can only be a single .dll in the search path that implements the given service interface. If you are replacing an existing service, then at this point it is recommended that you back-up the old/existing version (for example, given an existing service .dll named ‘foo.dll’, rename it to ‘foo.dll.bak’).

Copy the newly built .dll from the build location (eg, .\bin\debug\i386\...) to the [%PosClient%\Services] folder, and then restart POS.exe.

Appendix I – IBlankOperation interface

Page 5: How to Customize a POS Service Assembly

Implementing IBlankOperation.Execute() methodImplement the IBlankOperation service, overriding the BlankOperation method as desired. See below for example:

public void BlankOperation(IBlankOperationInfo operationInfo, IPosTransaction posTransaction)

{// This country check can be removed when customizing the BlankOperations service.if (Functions.CountryRegion == SupportedCountryRegion.BR

|| Functions.CountryRegion == SupportedCountryRegion.HU){

return;}

StringBuilder comment = new StringBuilder(128);comment.AppendFormat("Operation Id: %0" operationInfo.OperationId);comment.AppendLine();comment.AppendFormat("Parameter: %0", operationInfo.Parameter); using (LSRetailPosis.POSProcesses.frmMessage dialog = new

LSRetailPosis.POSProcesses.frmMessage(comment.ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error))

{LSRetailPosis.POSProcesses.POSFormsManager.ShowPOSForm(dialog);

}

// Set this property to true when your operation is handledoperationInfo.OperationHandled = true;

// Other examples:

// Add an item to the transaction// Application.RunOperation(PosisOperations.ItemSale, "<ItemId>");

// Logoff// Application.RunOperation(PosisOperations.LogOff, null);

}

Creating a POS buttonCreate a new button of type ‘Blank Operation’

Set the display text.

Set the operation info content, which is passed to the IBlankOperation service implementation.

Appendix II – Transaction Service

Adding a new Transaction Service method in AXAdd a new method to the AX class RetailTransactionServiceEx. Methods in the RetailTransactionService and RetailTransactionServiceEx classes are both callable by the Transaction Service. However the RetailTransactionService class contains methods that are used by the core POS solution, and they, along

Page 6: How to Customize a POS Service Assembly

with the class itself, may change due to product upgrades and successive releases. Because of this, it is recommended that custom solutions add new methods to only the RetailTransactionServiceEx class.

Add a new method to RetailTransactionServiceEx class. In order to be compatible with Transaction Service, the new method must conform to the following rules:

Scope of ‘public static’ Return type of ‘container’

o The first element of the container MUST be a bool to indicate success/failure.o The second element of the container MUST be a string, containing an optional messageo The remaining elements may be used for any return data/results.o Example:

[true, “Success!”, …] Parameters should be primitive types.

/// <summary>/// An echo method that respond with a container of the first ten string parameters/// </summary>/// <returns>/// A container of the first 10 parameters/// </returns>public static container echoRequest(str parameter0 = “”, str parameter1 = “”, str parameter2 = “”, str parameter3 = “”, str parameter4 = “”, str parameter5 = “”, str parameter6 = “”, str parameter7 = “”, str parameter8 = “”, str parameter9 = “”){ container results = [true, 'Successful.']; container parameters; str parameter; int i;

// Append all the rest of parameters if available. parameters = [parameter0, parameter1, parameter2, parameter3, parameter4, parameter5, parameter6, parameter7, parameter8, parameter9];

for(i = 1; i <= conLen(parameters); i++) { parameter = conPeek(parameters, i);

if(parameter) { results += parameter; } } return results;}

Page 7: How to Customize a POS Service Assembly

Calling the new Transaction Service method from POSNow that a Transaction Service method has been created in AX, it may now be called from POS using the ITransactionService contract.

Excerpt from ITransactionServices contract:

/// <summary>/// Invoke an extension method from AX./// </summary>/// <param name="methodName">Name of the method.</param>/// <param name="parameters">The parameters.</param>/// <returns>/// Result as readonly collection of objects if TS enabled, null otherwise./// </returns>ReadOnlyCollection<object> InvokeExtension(string methodName, params object[] parameters);

This example calls the “echoRequest” method that was created above. Note that the arguments for the AX method are passed as a params collection.

public void CallTransactionService(){ try { ReadOnlyCollection<object> containerArray;

ITransactionService service = PosApplication.Instance.TransactionServices;

// Call the new TS method containerArray = service.InvokeExtension("echoRequest", “0”, “1”, “2”, “3”);

//Note that AX containers are 1-based, so the first element is at index 1. bool retValue = (bool)containerArray[1]; string comment = containerArray[2].ToString();

Debug.WriteLine("Results:"); for (int i = 1; i < containerArray.Count; i++) { Debug.WriteLine(containerArray[i]); } } catch (Exception ex) { LSRetailPosis.ApplicationExceptionHandler.HandleException(this.ToString(), ex); throw; }}