Skip to main content

WorkflowHandlerRegistry220FDW

The workflow handler registry resolves IStepHandler220FDW implementations for mobile workflows. It acts as the bridge between a workflow's configuration (stored in the Mobile Workflow 220FDW table) and the AL codeunit that contains the step logic.

Overview

  • Object type: Codeunit (73167889)
  • Access: Public
  • Namespace: Aptean.Mesh.SDUI
  • Purpose: Resolves which codeunit handles the steps for a given mobile workflow

Aptean Mesh uses a service-locator pattern for workflow handlers, similar to how MobileRPCRegistry220FDW resolves RPC services. Each workflow record stores a Resolver Codeunit ID that identifies which codeunit implements IStepHandler220FDW. At runtime, the registry fires an integration event so that the matching codeunit can return itself as the handler.

Resolution Flow

Workflow Engine

├─► WorkflowHandlerRegistry220FDW.ResolveStepHandler(State)
│ │
│ ├─► Look up Mobile Workflow 220FDW record
│ │ using State.Bundle() + State.Workflow()
│ │
│ ├─► Read "Resolver Codeunit ID" from the record
│ │
│ └─► Fire OnResolveWorkflowHandler(CodeunitId, ...)
│ │
│ └─► Subscriber sets StepHandler := this

└─► Call StepHandler.IsStepRequired / HandleStep / UndoStep

Methods

ResolveStepHandler

procedure ResolveStepHandler(
State: Codeunit MobileRPCState220FDW
) StepHandler: Interface IStepHandler220FDW

Resolves the step handler for the workflow identified in the given state object.

Parameters:

NameTypeDirectionDescription
StateCodeunit MobileRPCState220FDWvalueThe current RPC state. The registry reads State.Bundle() and State.Workflow() to look up the workflow record.

Returns: Interface IStepHandler220FDW -- the resolved step handler implementation.

Errors:

ConditionError Message
Workflow record not foundWorkflow '{WorkflowCode}' not found for App Bundle '{BundleId}'. Ensure the workflow is configured in Mobile Workflows.
No handler subscribedNo workflow handler found for workflow '{WorkflowCode}' (Resolver Codeunit ID: {CodeunitId}). Ensure the codeunit subscribes to OnResolveWorkflowHandler event.

Integration Event

OnResolveWorkflowHandler

[IntegrationEvent(false, false)]
local procedure OnResolveWorkflowHandler(
CodeunitId: Integer;
var StepHandler: Interface IStepHandler220FDW;
var IsResolved: Boolean)

Fired by the registry when it needs to resolve a workflow handler. Subscribe to this event in your codeunit to register yourself as the handler for a specific codeunit ID.

Parameters:

NameTypeDirectionDescription
CodeunitIdIntegervalueThe Resolver Codeunit ID from the Mobile Workflow 220FDW record. Compare this to your own Codeunit:: identifier.
StepHandlerInterface IStepHandler220FDWvarSet this to your codeunit instance (this) when the CodeunitId matches.
IsResolvedBooleanvarSet to true after assigning StepHandler. Check this first -- if another subscriber already resolved the handler, exit immediately.

Registration Example

The following example shows how to register a custom workflow handler. This pattern is identical to the one used by the built-in ReceiptService220FDW.

codeunit 50100 "My Workflow Handler" implements IStepHandler220FDW
{
[EventSubscriber(ObjectType::Codeunit,
Codeunit::WorkflowHandlerRegistry220FDW,
OnResolveWorkflowHandler, '', false, false)]
local procedure ResolveMyHandler(
CodeunitId: Integer;
var StepHandler: Interface IStepHandler220FDW;
var IsResolved: Boolean)
begin
// Guard: another subscriber already resolved
if IsResolved then
exit;

// Guard: this event is not for our codeunit
if CodeunitId <> Codeunit::"My Workflow Handler" then
exit;

// Register ourselves as the handler
StepHandler := this;
IsResolved := true;
end;

// Implement IStepHandler220FDW methods...
procedure IsStepRequired(
var State: Codeunit MobileRPCState220FDW;
var ItemMgt: Codeunit MobileItemMgt220FDW;
WorkflowStep: Record "Mobile Workflow Step 220FDW"): Boolean
begin
// Step-type dispatch logic
exit(true);
end;

procedure HandleStep(
var State: Codeunit MobileRPCState220FDW;
var ItemMgt: Codeunit MobileItemMgt220FDW;
WorkflowStep: Record "Mobile Workflow Step 220FDW"): Boolean
begin
// Step execution logic
exit(true);
end;

procedure UndoStep(
var State: Codeunit MobileRPCState220FDW;
var ItemMgt: Codeunit MobileItemMgt220FDW;
WorkflowStep: Record "Mobile Workflow Step 220FDW"): Boolean
begin
// Step undo logic
exit(false);
end;
}

Workflow Configuration Tables

The registry depends on two tables that define which workflows exist and what steps they contain.

Mobile Workflow 220FDW

Stores the workflow definitions for each app bundle.

FieldTypeDescription
App Bundle IDGuidForeign key to the Mobile App Bundle 220FDW table.
Workflow CodeCode[20]Unique identifier for the workflow within the bundle (e.g., RECEIPT, PUTAWAY).
DescriptionText[100]Human-readable description of the workflow's purpose.
Resolver Codeunit IDIntegerThe codeunit that implements IStepHandler220FDW for this workflow. This is the ID passed to OnResolveWorkflowHandler.

Primary key: App Bundle ID + Workflow Code

Mobile Workflow Step 220FDW

Stores the ordered steps within each workflow.

FieldTypeDescription
App Bundle IDGuidForeign key to the parent workflow's bundle.
Workflow CodeCode[20]Foreign key to the parent workflow.
SequenceIntegerExecution order within the workflow. Lower numbers execute first. Auto-assigned in increments of 10.
Step TypeEnum StepType220FDWThe type of data to capture (Bin, Item, LotNumber, Quantity, etc.).
Step Input TypeEnum StepInputType220FDWThe UI input control to display on the mobile device (Barcode, Numeric, DatePicker, Image, Choice, etc.).
InstructionText[50]The text prompt shown to the user on the mobile device.
GS1 AICode[30]GS1 Application Identifiers for barcode parsing, separated by semicolons (e.g., 01;02).

Primary key: App Bundle ID + Workflow Code + Sequence

The step table also provides helper methods:

  • SetWorkflowFilters(BundleId, WorkflowCode) -- sets filters and sorts by sequence for iteration
  • GetFirstSequence() -- returns the lowest sequence number in the current filter
  • FindByStepType(StepType) -- positions the record on the first step matching the given type

Setup in Business Central

To wire a workflow to your handler codeunit:

  1. Open Mobile App Bundles and select your bundle
  2. Open Mobile Workflows from the bundle card
  3. Create a workflow record:
    • Workflow Code -- e.g., MYWORKFLOW (must match the workflow code sent by the mobile client)
    • Resolver Codeunit ID -- e.g., 50100 (the object ID of your IStepHandler220FDW codeunit)
  4. Open Workflow Steps from the workflow card and add steps in sequence:
    • Set the Step Type (e.g., LotNumber, Quantity, Bin)
    • Set the Step Input Type for the mobile UI control
    • Optionally set an Instruction and GS1 AI identifiers

Dual Registration Pattern

Most Aptean Mesh service codeunits implement both IBCRPC220FDW (for RPC dispatch) and IStepHandler220FDW (for workflow steps) on the same codeunit. This means the codeunit subscribes to two registry events:

codeunit 50100 "My Service" implements IBCRPC220FDW, IStepHandler220FDW
{
// Register as an RPC service
[EventSubscriber(ObjectType::Codeunit,
Codeunit::MobileRPCRegistry220FDW,
OnResolveService, '', false, false)]
local procedure ResolveService(
CodeunitId: Integer;
var Service: Interface IBCRPC220FDW;
var IsServiceResolved: Boolean)
begin
if IsServiceResolved then exit;
if CodeunitId <> Codeunit::"My Service" then exit;
Service := this;
IsServiceResolved := true;
end;

// Register as a workflow handler
[EventSubscriber(ObjectType::Codeunit,
Codeunit::WorkflowHandlerRegistry220FDW,
OnResolveWorkflowHandler, '', false, false)]
local procedure ResolveWorkflowHandler(
CodeunitId: Integer;
var StepHandler: Interface IStepHandler220FDW;
var IsResolved: Boolean)
begin
if IsResolved then exit;
if CodeunitId <> Codeunit::"My Service" then exit;
StepHandler := this;
IsResolved := true;
end;

// IBCRPC220FDW implementation
procedure RPC(var State: Codeunit MobileRPCState220FDW) ResponseJson: JsonObject
begin
case State.Method() of
'Initialize':
Initialize(State);
'HandleWorkFlow':
HandleWorkFlow(State);
'UndoStep':
ProcessUndoStep(State);
end;
ResponseJson := State.Serialize();
end;

// IStepHandler220FDW implementation
procedure IsStepRequired(
var State: Codeunit MobileRPCState220FDW;
var ItemMgt: Codeunit MobileItemMgt220FDW;
WorkflowStep: Record "Mobile Workflow Step 220FDW"): Boolean
begin
// ...
end;

procedure HandleStep(
var State: Codeunit MobileRPCState220FDW;
var ItemMgt: Codeunit MobileItemMgt220FDW;
WorkflowStep: Record "Mobile Workflow Step 220FDW"): Boolean
begin
// ...
end;

procedure UndoStep(
var State: Codeunit MobileRPCState220FDW;
var ItemMgt: Codeunit MobileItemMgt220FDW;
WorkflowStep: Record "Mobile Workflow Step 220FDW"): Boolean
begin
// ...
end;
}

In this pattern, the RPC method's 'HandleWorkFlow' branch typically calls WorkflowHandlerRegistry220FDW.ResolveStepHandler(State) to obtain the handler, then iterates through the workflow steps calling IsStepRequired, HandleStep, and UndoStep as needed.

See Also