This guide explains how to create cuPTEm POS Input Box (EAN Box) events in a Per-Tenant Extension (PTE) for NP Retail.
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:
- Registering an EAN Box Event - Subscribe to
DiscoverEanBoxEvents - Validating barcode patterns - Subscribe to
SetEanBoxEventInScope - Implementing the workflow - Create a codeunit implementing
NPR IPOS Workflow
- PTE extension with dependency on NP Retail
- Object ID range allocated for your extension
- Basic understanding of AL development
┌─────────────────┐ ┌──────────────────────┐ ┌─────────────────┐
│ Barcode Scan │────▶│ EAN Box Handler │────▶│ Your POS │
│ (e.g. 4*B123) │ │ (SetEanBoxEventIn- │ │ Action/ │
│ │ │ Scope validation) │ │ Workflow │
└─────────────────┘ └──────────────────────┘ └─────────────────┘
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.
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...
}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
EanBoxEventrecord 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
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 Parametertable directly (it's internal) - Keep validation fast - this runs for every enabled event on every scan
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;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;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;
}This example handles barcodes like 4*B123 (4 units of item reference B123):
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;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;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 |
After deploying the PTE:
- Search for "POS Input Box Setup" in BC
- Select the relevant setup (e.g., "SALE")
- Find your new event (e.g., "ITEMREFQTY")
- Set Enabled = Yes
- Configure Priority if needed (lower = higher priority)
- Cannot directly access
NPR Ean Box Parametertable (Access = Internal) - Must use pattern-based validation in
SetEanBoxEventInScopeinstead of reading configured parameters - JavaScript must be minified inline in AL code
- Verify
DiscoverEanBoxEventssubscriber is correctly implemented - Check that
EanBoxEvent.Insert(true)is called - Ensure the event code is unique (max 20 characters)
- Verify
SetEanBoxEventInScopesetsInScope := truefor your barcode pattern - Check that the event is enabled in POS Input Box Setup
- Ensure your event code check matches exactly
- Check
FrontEnd.WorkflowResponse()is called with valid JsonObject - Verify JavaScript
workflow.respond()step name matches ALRunWorkflowcase
src/
├── POSActionItemRefQty.Codeunit.al # Main workflow implementation
├── POSActionItemRefQtyB.Codeunit.al # Business logic
├── POSWorkflow.EnumExt.al # Enum extension
└── POSActionItemRefQty.js # JavaScript source (readable)
- NP Retail POS Action examples in npcore
NPR POS Input Box Setup Mgt.codeunitNPR POS Input Box Evt HandlercodeunitNPR IPOS Workflowinterface