Skip to content

navipartner/ean-box-event-example

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Guide: Implementing Custom EAN Box Events in a PTE Extension

This guide explains how to create cuPTEm POS Input Box (EAN Box) events in a Per-Tenant Extension (PTE) for NP Retail.

Overview

The POS Input Box system allows you to define cuPTEm actions that trigger when specific barcode patterns are scanned at the POS. This is achieved by:

  1. Registering an EAN Box Event - Subscribe to DiscoverEanBoxEvents
  2. Validating barcode patterns - Subscribe to SetEanBoxEventInScope
  3. Implementing the workflow - Create a codeunit implementing NPR IPOS Workflow

Prerequisites

  • PTE extension with dependency on NP Retail
  • Object ID range allocated for your extension
  • Basic understanding of AL development

Architecture

┌─────────────────┐     ┌──────────────────────┐     ┌─────────────────┐
│  Barcode Scan   │────▶│  EAN Box Handler     │────▶│  Your POS       │
│  (e.g. 4*B123)  │     │  (SetEanBoxEventIn-  │     │  Action/        │
│                 │     │   Scope validation)  │     │  Workflow       │
└─────────────────┘     └──────────────────────┘     └─────────────────┘

Step-by-Step Implementation

Step 1: Create the Enum Extension

Extend the NPR POS Workflow enum to register your new action.

enumextension 65001 "PTE POS Workflow" extends "NPR POS Workflow"
{
    value(65001; ITEM_REF_QTY)
    {
        Caption = 'ITEM_REF_QTY', Locked = true, MaxLength = 20;
        Implementation = "NPR IPOS Workflow" = "PTE POS Action: Item Ref Qty";
    }
}

Important: Use an ID from your allocated range.

Step 2: Create the Main Workflow Codeunit

This codeunit implements NPR IPOS Workflow and handles:

  • Action registration with parameters
  • Workflow execution
  • EAN Box event subscriptions
codeunit 65001 "PTE POS Action: Item Ref Qty" implements "NPR IPOS Workflow"
{
    Access = Internal;

    var
        ActionDescriptionLbl: Label 'Insert Item by Reference with Quantity (format: qty*reference)';

    // === WORKFLOW REGISTRATION ===
    procedure Register(WorkflowConfig: Codeunit "NPR POS Workflow Config")
    var
        ParamBarcode_CptLbl: Label 'Barcode';
        ParamBarcode_DescLbl: Label 'Barcode in format qty*reference';
        ItemReference: Record "Item Reference";
    begin
        WorkflowConfig.AddActionDescription(ActionDescriptionLbl);
        WorkflowConfig.AddJavascript(GetActionScript());
        WorkflowConfig.AddTextParameter('barcode', '', ParamBarcode_CptLbl, ParamBarcode_DescLbl);
        WorkflowConfig.AddLabel('Barcode', Format(ItemReference."Reference Type"::"Bar Code"));
    end;

    // === WORKFLOW EXECUTION ===
    procedure RunWorkflow(Step: Text; Context: Codeunit "NPR POS JSON Helper";
        FrontEnd: Codeunit "NPR POS Front End Management"; Sale: Codeunit "NPR POS Sale";
        SaleLine: Codeunit "NPR POS Sale Line"; PaymentLine: Codeunit "NPR POS Payment Line";
        Setup: Codeunit "NPR POS Setup")
    begin
        case Step of
            'InsertItemRefQty':
                FrontEnd.WorkflowResponse(InsertItemRefQty(Context));
        end;
    end;

    // Your business logic here...
}

Step 3: Subscribe to DiscoverEanBoxEvents

This registers your event so it appears in the POS Input Box Setup.

[EventSubscriber(ObjectType::Codeunit, Codeunit::"NPR POS Input Box Setup Mgt.",
    'DiscoverEanBoxEvents', '', true, true)]
local procedure DiscoverEanBoxEvents(var EanBoxEvent: Record "NPR Ean Box Event")
var
    ItemReference: Record "Item Reference";
begin
    if not EanBoxEvent.Get(EventCodeItemRefQty()) then begin
        EanBoxEvent.Init();
        EanBoxEvent.Code := EventCodeItemRefQty();  // e.g., 'ITEMREFQTY'
        EanBoxEvent."Module Name" := CopyStr(ItemReference.TableCaption, 1, MaxStrLen(EanBoxEvent."Module Name"));
        EanBoxEvent.Description := CopyStr(ActionDescriptionLbl, 1, MaxStrLen(EanBoxEvent.Description));
        EanBoxEvent."Action Code" := CopyStr(ActionCode(), 1, MaxStrLen(EanBoxEvent."Action Code"));
        EanBoxEvent."POS View" := EanBoxEvent."POS View"::Sale;
        EanBoxEvent."Event Codeunit" := CurrCodeunitId();
        EanBoxEvent.Insert(true);
    end;
end;

local procedure EventCodeItemRefQty(): Code[20]
begin
    exit('ITEMREFQTY');
end;

local procedure ActionCode(): Code[20]
begin
    exit(Format(Enum::"NPR POS Workflow"::ITEM_REF_QTY));
end;

local procedure CurrCodeunitId(): Integer
begin
    exit(Codeunit::"PTE POS Action: Item Ref Qty");
end;

Key points:

  • The EanBoxEvent record is passed by reference from npcore, so you CAN insert into this internal table
  • "Action Code" must match your enum value formatted as text
  • "Event Codeunit" should be your codeunit ID

Step 4: Subscribe to SetEanBoxEventInScope

This validates whether your event should handle a given barcode. Return InScope := true if your event can process this barcode.

[EventSubscriber(ObjectType::Codeunit, Codeunit::"NPR POS Input Box Evt Handler",
    'SetEanBoxEventInScope', '', true, true)]
local procedure SetEanBoxEventInScopeItemRefQty(EanBoxSetupEvent: Record "NPR Ean Box Setup Event";
    EanBoxValue: Text; var InScope: Boolean)
var
    ItemReference: Record "Item Reference";
    Quantity: Decimal;
    RefNo: Text;
begin
    // Only handle our event
    if EanBoxSetupEvent."Event Code" <> EventCodeItemRefQty() then
        exit;

    // Validate barcode format (e.g., "4*B123")
    if not ParseBarcodeFormat(EanBoxValue, Quantity, RefNo) then
        exit;

    // Validate the reference exists
    if not FindItemReferenceByCode(RefNo, ItemReference) then
        exit;

    // This event can handle this barcode
    InScope := true;
end;

Important:

  • Always check EanBoxSetupEvent."Event Code" first - multiple events may subscribe
  • Do NOT access NPR Ean Box Parameter table directly (it's internal)
  • Keep validation fast - this runs for every enabled event on every scan

Step 5: Subscribe to OnInitEanBoxParameters (Optional)

Configure which parameters receive the scanned barcode value.

[EventSubscriber(ObjectType::Codeunit, Codeunit::"NPR POS Input Box Setup Mgt.",
    'OnInitEanBoxParameters', '', true, true)]
local procedure OnInitEanBoxParameters(var Sender: Codeunit "NPR POS Input Box Setup Mgt.";
    EanBoxEvent: Record "NPR Ean Box Event")
begin
    case EanBoxEvent.Code of
        EventCodeItemRefQty():
            // 'barcode' parameter receives the scanned value, non-editable by user
            Sender.SetNonEditableParameterValues(EanBoxEvent, 'barcode', true, '');
    end;
end;

Step 6: Create the JavaScript

Create a .js file with the frontend logic:

let main = async ({ workflow, captions, parameters }) => {
    let barcode;

    if (parameters.barcode) {
        barcode = parameters.barcode;
    } else {
        barcode = await popup.input({ caption: captions.Barcode });
        if (barcode === null) {
            return " ";
        }
    }

    // Call backend to process the barcode
    const { workflowName, itemno, itemQuantity, itemIdentifierType } =
        await workflow.respond("InsertItemRefQty", { BarCode: barcode });

    // Run the ITEM workflow with the resolved values
    await workflow.run(workflowName, {
        parameters: {
            itemNo: itemno,
            itemQuantity: itemQuantity,
            itemIdentifierType: itemIdentifierType
        }
    });
};

Then minify and include in your AL file:

local procedure GetActionScript(): Text
begin
    exit(
//###NPR_INJECT_FROM_FILE:POSActionItemRefQty.js###
'let main=async({workflow:e,captions:a,parameters:t})=>{...minified code...};'
    );
end;

Step 7: Create Business Logic Codeunit

Separate your business logic for cleaner code:

codeunit 65002 "PTE POS Action: Item Ref Qty B"
{
    Access = Internal;

    procedure FindItemReferenceByCode(RefNo: Text; var ItemReference: Record "Item Reference"): Boolean
    begin
        if RefNo = '' then
            exit(false);

        ItemReference.SetCurrentKey("Reference Type", "Reference No.");
        ItemReference.SetRange("Reference Type", ItemReference."Reference Type"::"Bar Code");
        ItemReference.SetRange("Reference No.", UpperCase(RefNo));
        ItemReference.SetLoadFields("Item No.", "Variant Code", "Unit of Measure", "Reference No.", "Reference Type");

        exit(ItemReference.FindFirst());
    end;
}

Complete Example: qty*reference Format

This example handles barcodes like 4*B123 (4 units of item reference B123):

Parsing Logic

local procedure ParseBarcodeFormat(Barcode: Text; var Quantity: Decimal; var RefNo: Text): Boolean
var
    StarPos: Integer;
    QtyPart: Text;
begin
    StarPos := StrPos(Barcode, '*');
    if StarPos < 2 then
        exit(false);  // Must have at least 1 char before *
    if StarPos >= StrLen(Barcode) then
        exit(false);  // Must have chars after *

    QtyPart := CopyStr(Barcode, 1, StarPos - 1);
    RefNo := CopyStr(Barcode, StarPos + 1);

    if not Evaluate(Quantity, QtyPart) then
        exit(false);
    if Quantity <= 0 then
        exit(false);

    exit(true);
end;

Workflow Response

local procedure InsertItemRefQty(Context: Codeunit "NPR POS JSON Helper") Response: JsonObject
var
    ItemReference: Record "Item Reference";
    Barcode: Text;
    Quantity: Decimal;
    RefNo: Text;
begin
    Barcode := Context.GetString('BarCode');

    if not ParseBarcodeFormat(Barcode, Quantity, RefNo) then
        Error('Invalid barcode format. Expected: quantity*reference (e.g., 4*B123)');

    if not FindItemReferenceByCode(RefNo, ItemReference) then
        Error('Item Reference not found');

    Response.Add('workflowName', 'ITEM');
    Response.Add('itemno', ItemReference."Reference No.");
    Response.Add('itemQuantity', Quantity);
    Response.Add('itemIdentifierType', 1); // 1 = ItemCrossReference
end;

Calling Existing Workflows

You can call built-in NP Retail workflows from your action:

Workflow itemIdentifierType Description
ITEM 0 = ItemNo Direct Item No lookup
ITEM 1 = ItemCrossReference Item Reference (Bar Code) lookup
ITEM 2 = ItemSearch Search by description
ITEM 3 = SerialNoItemCrossReference Serial number lookup
ITEM 4 = ItemGtin GTIN lookup

Setup Instructions for End Users

After deploying the PTE:

  1. Search for "POS Input Box Setup" in BC
  2. Select the relevant setup (e.g., "SALE")
  3. Find your new event (e.g., "ITEMREFQTY")
  4. Set Enabled = Yes
  5. Configure Priority if needed (lower = higher priority)

Limitations

  • Cannot directly access NPR Ean Box Parameter table (Access = Internal)
  • Must use pattern-based validation in SetEanBoxEventInScope instead of reading configured parameters
  • JavaScript must be minified inline in AL code

Troubleshooting

Event not appearing in setup

  • Verify DiscoverEanBoxEvents subscriber is correctly implemented
  • Check that EanBoxEvent.Insert(true) is called
  • Ensure the event code is unique (max 20 characters)

Event not triggering

  • Verify SetEanBoxEventInScope sets InScope := true for your barcode pattern
  • Check that the event is enabled in POS Input Box Setup
  • Ensure your event code check matches exactly

Workflow errors

  • Check FrontEnd.WorkflowResponse() is called with valid JsonObject
  • Verify JavaScript workflow.respond() step name matches AL RunWorkflow case

File Structure

src/
├── POSActionItemRefQty.Codeunit.al    # Main workflow implementation
├── POSActionItemRefQtyB.Codeunit.al   # Business logic
├── POSWorkflow.EnumExt.al             # Enum extension
└── POSActionItemRefQty.js             # JavaScript source (readable)

References

  • NP Retail POS Action examples in npcore
  • NPR POS Input Box Setup Mgt. codeunit
  • NPR POS Input Box Evt Handler codeunit
  • NPR IPOS Workflow interface

About

EAN Box Event Example

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors