Sunteți pe pagina 1din 7

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 users Documents folder, as shown below:

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 references


Included 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.

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 services 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 Studios 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:

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 using using using using System.ComponentModel.Composition; Microsoft.Dynamics.Retail.Pos.Contracts; Microsoft.Dynamics.Retail.Pos.Contracts.BusinessObjects; Microsoft.Dynamics.Retail.Pos.Contracts.DataEntity; 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 assembly


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

Deploying the assembly


Before 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

Implementing IBlankOperation.Execute() method


Implement 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 handled operationInfo.OperationHandled = true; // Other examples: // Add an item to the transaction // Application.RunOperation(PosisOperations.ItemSale, "<ItemId>"); // Logoff // Application.RunOperation(PosisOperations.LogOff, null); }

Creating a POS button


Create 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 AX
Add 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

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 message o 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; }

Calling the new Transaction Service method from POS


Now 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; } }

S-ar putea să vă placă și