Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/CodexaCP/DG_APK/llms.txt

Use this file to discover all available pages before exploring further.

Item Inquiry is the first production module to surface UHF RFID reads in Dragon Guard Handheld. An operator can point the scan gun at any tagged item and instantly see its warehouse identity — item number, description, stock status, and bin location — without typing a single character. The RFID path is fully additive: barcode search and manual text entry continue to work exactly as before, and the screen never blocks when RFID hardware is unavailable or a tag is unregistered.
Do not assume EPC equals ItemNo. An EPC is a unique 96-bit tag identifier encoded on the physical label. It is mapped to a Dragon Guard item through the RFID registry, which may link one EPC to a specific serialized unit, a pallet, or a bin. Always resolve the EPC through GET /api/rfid/tags/resolve/{epc} and read ItemNo from the response — never use the raw EPC value as an item search key.

Flow

1

Operator opens Item Inquiry and selects a scan mode

When the Item Inquiry screen loads, it calls RfidHandheldContextService.GetContextAsync("item-inquiry") to retrieve the module’s RFID context (cached after the first fetch). The result drives which modes are offered in the mode picker:
  • Barcode — keyboard-wedge only. No RFID hardware is activated.
  • RFID (RfidSingle or RfidInventory) — UHF only; available when context.CanUseRfid is true.
  • Hybrid — keyboard-wedge + UHF simultaneously; available when context.CanUseRfid is true.
After a mode is selected, the view model calls:
scanCaptureService.ApplyRfidPolicy(
    context.CanUseRfid,
    context.CanOperateWithoutRfid,
    context.RfidHardwareStatus);

await scanCaptureService.StartSessionAsync(
    new ScanSessionRequest(selectedMode, "Item Inquiry"),
    cancellationToken);
If RFID is unavailable and CanOperateWithoutRfid is true, StartSessionAsync automatically downgrades to Barcode mode and fires ErrorOccurred with a non-blocking status message. The operator can continue working.
2

IScanCaptureService.TagObserved fires with EPC

The RFID adapter emits a TagObservedEventArgs containing a ScanResult for each distinct EPC the hardware reads. The view model subscribes to this event during initialization and unsubscribes when the page disappears.
_scanCaptureService.TagObserved += OnTagObserved;
The ScanResult delivered here has:
result.ScanType        // "RFID"
result.Epc             // normalized upper-case EPC hex string, e.g. "E2003412012345678901234A"
result.NormalizedValue // same as Epc for RFID results
result.Mode            // ScanMode.RfidSingle | RfidInventory | Hybrid
result.Rssi            // signal strength in dBm, or null
result.DisplayRssi     // safe string: Rssi.ToString() or "-"
The view model updates the UI with the operator feedback string “RFID EPC captured.” as soon as the event fires, before the resolve call completes.
3

ViewModel calls GET /api/rfid/tags/resolve/{epc}

The view model immediately calls the RFID tag resolve endpoint using the raw EPC from the event:
// endpoint: GET /api/rfid/tags/resolve/{epc}
var resolved = await itemService.ResolveRfidTagAsync(result.Epc);
The backend looks up the EPC in the RFID registry and returns an RfidTagResolveDto:
namespace Handheld.Models;

public class RfidTagResolveDto
{
    public string  Epc             { get; set; } = string.Empty;
    public string  ObjectType      { get; set; } = string.Empty;
    public string  Status          { get; set; } = string.Empty;
    public Guid?   ItemId          { get; set; }
    public string  ItemNo          { get; set; } = string.Empty;
    public string  ItemDescription { get; set; } = string.Empty;
    public decimal Quantity        { get; set; }
    public string  LocationCode    { get; set; } = string.Empty;
    public string  BinCode         { get; set; } = string.Empty;
    public bool    IsResolved      { get; set; }
    public bool    IsActive        { get; set; }
    public string  Message         { get; set; } = string.Empty;
}
RfidTagResolveDto.ItemNo is the Dragon Guard item number associated with this EPC in the registry. It is a business key, not a derived value from the EPC itself. ItemId is the internal GUID for the registry record.
4

EPC resolved — display item details

When resolved.IsResolved is true, the view model populates the inquiry card with the fields from the resolve response:
FieldDisplayed as
ItemNoItem number heading
ItemDescriptionItem name / description
ObjectTypeTag object type (e.g. "ITEM", "BIN")
StatusRegistration status
QuantityRegistered quantity
LocationCodeWarehouse location (shown when non-empty)
BinCodeBin position (shown when non-empty)
The operator feedback string changes to “RFID EPC resolved.”If resolved.ItemNo is present, the view model proceeds to Step 5 to fetch the full stock summary.
5

ItemNo present — fetch full stock summary

When the resolve response includes a non-empty ItemNo, the view model reuses the standard item inquiry endpoint to populate the stock summary list:
// endpoint: GET /api/items/inquiry?itemNo={itemNo}&...
var stockSummary = await itemService.GetItemInquiryAsync(resolved.ItemNo, cancellationToken);
This is the same call path used by barcode and manual search. The displayed stock summary (quantities by location, bin, lot, etc.) is identical regardless of how the item was identified.
Barcode and manual text search always use GET /api/items/inquiry directly — they never go through the RFID resolve endpoint. The resolve path is exclusive to RFID and Hybrid mode tag events.
6

EPC not registered — show controlled message

When the backend returns IsResolved = false (the EPC exists as a read but has no registry entry), the view model shows the controlled message:
EPC leido, pero aun no esta registrado como item.
The operator feedback string is “RFID EPC not registered.” The inquiry form remains open and fully functional for barcode or manual lookup. No error state is set on the screen.

Operator Feedback Strings

The view model maps every outcome to a short status string displayed in the scan result area:
SituationFeedback string
Barcode keyboard-wedge readBarcode captured.
RFID tag seen by hardwareRFID EPC captured.
Backend resolved EPC to itemRFID EPC resolved.
EPC not in registryRFID EPC not registered.
Network or API failure during resolveRFID resolve failed.

Graceful Degradation

The RFID path is designed to be a transparent enhancement, not a dependency. The following table shows how each failure scenario resolves without disabling the inquiry screen:
FailureBehaviour
CanUseRfid = false + CanOperateWithoutRfid = trueStartSessionAsync downgrades to Barcode mode, fires ErrorOccurred with a non-blocking message. Barcode and manual search work normally.
CanUseRfid = false + CanOperateWithoutRfid = falseStartSessionAsync fires ErrorOccurred and does not start a session. Screen stays open; operator can retry or use a different mode.
RfidHandheldContextService backend unreachableReturns RfidHandheldContextDto.Fallback(module): CanUseRfid = false, CanOperateWithoutRfid = true. RFID is silently disabled; barcode/manual inquiry unaffected.
GET /api/rfid/tags/resolve/{epc} transport failureView model catches the exception, sets feedback to "RFID resolve failed.", does not change IsSessionActive. Operator can scan again or switch to barcode.
IsResolved = falseControlled message shown. No exception, no disabled state.
Never call StopSessionAsync or navigate away from the screen as a response to an RFID resolve failure. Resolve failures are soft — the hardware session should remain active so the operator can rescan or try a different tag.

RfidHandheldContextService Context Fields

The context fetched for the "item-inquiry" module is a RfidHandheldContextDto. The fields most relevant to Item Inquiry are:
public sealed class RfidHandheldContextDto
{
    public bool   CanUseRfid              { get; init; }
    public bool   CanOperateWithoutRfid   { get; init; }
    public bool   CanFallbackToBarcode    { get; init; }
    public bool   CanFallbackToManual     { get; init; }
    public string RfidHardwareStatus      { get; init; } // READY | NO_RFID_PROFILE | ...
    public bool   RfidEnabledForModule    { get; init; }
    public string EffectiveMode           { get; init; }
    public RfidEffectivePolicyContextDto  Policy        { get; init; }
    public RfidEffectiveDeviceProfileContextDto DeviceProfile { get; init; }
}
The embedded RfidEffectivePolicyContextDto governs duplicate suppression and read limits during the session:
public sealed class RfidEffectivePolicyContextDto
{
    public int  DuplicateReadWindowSeconds { get; init; } // 0 = no deduplication
    public int? MaxReadsPerOperation       { get; init; } // null = unlimited
    public bool AllowBarcodeFallback       { get; init; }
    public bool AllowManualFallback        { get; init; }
    public bool BlockOnUnknownTag          { get; init; }
    public bool BlockOnInactiveTag         { get; init; }
    public string UnknownTagBehavior       { get; init; } // "ALLOW" | "WARN" | "BLOCK" | "REGISTER"
    public string DuplicateTagBehavior     { get; init; } // "ALLOW" | "WARN" | "BLOCK"
}
DuplicateReadWindowSeconds > 0 means the same EPC will not fire TagObserved again until the window has elapsed. This prevents the view model from issuing redundant resolve calls when the operator holds the trigger over a tag in inventory mode. The context is fetched once and cached by RfidHandheldContextService. It remains valid for the lifetime of the operator’s session. Call ClearCache() if policy or device registration changes at runtime (e.g. after a settings sync).

Build docs developers (and LLMs) love