How-to: Create External POS Commands for LS Central

POS Command

In this blog post I show how-to create External POS Commands for LS Central, and introduce a snippet to make this task repeatable.

External POS commands allow you to extend LS Central functionality by creating Codeunits that can be run via POS buttons or actions.

Before you get started, you might want to find out how-to run LS Central in a Docker container.

The high-level tasks are as follows:

  • Create a Codeunit to contain our new POS Command module.
  • Write the POS Command logic in a procedure.
  • Add code to register the module and POS command(s).
  • Register the new POS command module in LS Central.

To view the POS commands within Business Central, open the POS Commands list:

POS Command

As we can see above, POS commands have a Function Code which is used to call the command and a field Function Type which can be either:

  • POS Internal – Don’t specify a codeunit, these are used internally (hard-coded) within LS Central
  • POS External – Allow you to specify a Codeunit to extend LS Central functionality

We’re going to be focusing on External POS commands, which we can see from the filtered External POS Commands List:

External POS Commands

The listed POS Commands can be assigned to buttons on the POS, POS Actions or called directly in AL code.

Create a POS Command Codeunit

POS Command Codeunits follow a pattern:

  • Must have the TableNo property set to “POS Menu Line”.
  • OnRun() handles the registration event.
  • OnRun() handles command invocation with a case statement.

The OnRun trigger of our Codeunit will need to handle one of two scenarios: either the Codeunit is being registered, or a command is being invoked:

if Rec."Registration Mode" then
Register(Rec)
else
case Rec.Command of
GetHelloWorldCommand():
HelloWorld();
end;

To register our new module and external POS command we need to make use of the “POS Command Registration” Codeunit, which contains two procedures we’ll need:

  • RegisterModule – used to store the module information:
    • Module – A code for your Codeunit Module (Code[20]).
    • Description – A description of the module (Text[50]).
    • Codeunit – The Codeunit Object Id being registered.
  • RegisterExtCommand – used to register each of the commands in our module:
    • FunctionCode – A code for the POS Command being registered (Code[20]).
    • Description – A description of the POS command (Text[50]).
    • Codeunit – The Object Id of the Codeunit containing the POS command.
    • ParameterType – The parameter data type, an option field on the POS Command table. 0 for no parameter.
    • Module – The code of the module the POS command belongs to.
    • BackGrFading – Boolean to fade the POS background when this command runs.
local procedure Register(var POSMenuLine: Record "POS Menu Line")
var
POSCommandReg: Codeunit "POS Command Registration";
ModuleDescription: Label 'DanKinsella.blog - Demo';
HelloWorldCommandDesc: Label 'Say hello to the cashier.';
begin
// Register the module:
POSCommandReg.RegisterModule(GetModuleCode(), ModuleDescription, Codeunit::"LS POS Command Demo");
// Register the command, as many lines as there are commands in the Codeunit:
POSCommandReg.RegisterExtCommand(GetHelloWorldCommand(), HelloWorldCommandDesc, Codeunit::"LS POS Command Demo", 0, GetModuleCode(), true);
POSMenuLine."Registration Mode" := false;
end;

When a POS command is being requested, the OnRun() trigger is invoked with the “POS Menu Line” record’s Command field holding the FunctionCode of our POS command. We use a case statement to determine which (if any) procedure within our Codeunit to run:

case Rec.Command of
GetHelloWorldCommand():
HelloWorld();
end;
procedure HelloWorld()
var
HelloWorldMsg: Label 'Hello World!';
begin
Message(HelloWorldMsg);
end;

As a personal preference, I like to encapsulate the FunctionCode for each POS command and the Module code value in procedures:

procedure GetModuleCode() : Code[20]
var
ModuleCode: Label 'DANKINSELLA.BLOG', Locked = true;
begin
exit(ModuleCode);
end;
procedure GetHelloWorldCommand() : Code[20]
var
HelloWorldCommand: Label 'HELLOWORLD', locked = true;
begin
exit(HelloWorldCommand);
end;

It’s good practice not to enter literal text values into code generally, but I also find it useful to be able to retrieve these codes in certain circumstances. Note I’ve added the locked parameter to the Label constants, this is to stop the code value being translated. The code should stay the same for consistency, whatever the language used.

Register the POS Command

Before we can use our new POS command module we’ll need to register it within LS Central. This is done from the External POS Commands page:

Register POS Command

Filter to our new Codeunit and hit OK:

Select POS Command Codeunit

Check our new POS command is registered:

Registered POS command

Note: Every time you add a new POS command to your module Codeunit you’ll need to re-register.

Get the full demo Codeunit on GitHub.

Get the Visual Studio Code snippet here.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.