Hi, Readers.
Today I would like to talk about how to add a Scan Barcode action and scan multiple/Continious scanning in Business Central Saas (Cloud).
In Business Central 2023 wave 2 (BC23): Print and scan barcodes (No customization), we briefly discussed how to print and scan barcodes (No customization) in Business Central.
The simplest way to provide barcode scanning capability in the mobile app is by adding a barcode scanning button on a field that starts the barcode scanner capability of the device’s camera.
This scanning is highly efficient and responsive. Once a barcode is scanned, its value is entered in the field on the page, and the focus moves to the next quick-entry field on the page.
To enable the barcode scanning button on a field, set the ExtendedDatatype property to Barcode. You can set ExtendedDatatype on either the field in the table or page. The property instructs the mobile client to display the barcode button when the page is opened on a supported device. For example,
tableextension 50111 ItemExt extends Item
{
fields
{
field(50100; ItemBarcode; Text[50])
{
Caption = 'Item Barcode';
ExtendedDatatype = Barcode;
}
}
}
pageextension 50111 ItemCardExt extends "Item Card"
{
layout
{
addafter(Description)
{
field(ItemBarcode; Rec.ItemBarcode)
{
ApplicationArea = All;
Caption = 'Item Barcode';
ToolTip = 'Item Barcode';
}
}
}
}Regarding AL action and Barcode event, they were only available in the On-Pre version at that time.
For example, in page 6510 “Item Tracking Lines”:
In Business Central 2023 wave 2 (BC23):
DotNet Data Type:
The really great news is that version 24 introduced barcode scanning APIs based on control add-ins to replace the .NET-based APIs.
CameraBarcodeScannerProviderAddIn: The control add-in for the camera barcode scanner provider.
This means we can add scan barcode actions and multiple scanning functions to our own extensions🎆🎉🎊.
The following code example shows how to invoke barcode scanning using the CameraBarcodeScannerProviderAddIn control add-in. More details: Invoke barcode scanning using control add-in API
page 50100 "Camera Barcode Scanner"
{
PageType = Card;
ApplicationArea = All;
Caption = 'Camera Barcode Scanner Sample';
layout
{
area(Content)
{
// Declare the user control based on the CameraBarcodeScannerProviderAddIn control add-in
usercontrol(BarcodeControl; CameraBarcodeScannerProviderAddIn) // Step 1
{
ApplicationArea = All;
// The ControlAddInReady event is raised when the control add-in is ready to be used.
trigger ControlAddInReady(IsSupported: Boolean)
begin
// Set the CameraBarcodeScannerAvailable variable to the value of the IsSupported parameter
CameraBarcodeScannerAvailable := IsSupported; // Step 2
end;
// The BarcodeAvailable event is raised when a barcode is available.
trigger BarcodeAvailable(Barcode: Text; Format: Text)
begin
Message(Barcode);// Step 4
// Continious scanning
// CurrPage.BarcodeControl.RequestBarcodeAsync(); // Step 5
end;
// The BarcodeFailure event is raised on a failure
trigger BarcodeFailure(Reason: Enum BarcodeFailure)
begin
case Reason of
Reason::Cancel:
Message('Canceled');
Reason::NoBarcode:
Message('No Barcode');
Reason::Error:
Message('Error');
end;
end;
}
}
}
actions
{
area(Processing)
{
action(ScanBarcode)
{
ApplicationArea = All;
trigger OnAction()
begin
// Request a barcode
CurrPage.BarcodeControl.RequestBarcodeAsync(); // Step 3
end;
}
}
}
var
CameraBarcodeScannerAvailable: Boolean;
}Let’s do a specific test. First, let’s look at an example of a single scan (I simply added the promoted properties to the action).
The scanned results are displayed on the page as a message.
page 50100 "Camera Barcode Scanner"
{
PageType = Card;
ApplicationArea = All;
Caption = 'Camera Barcode Scanner Sample';
UsageCategory = Administration;
layout
{
area(Content)
{
// Declare the user control based on the CameraBarcodeScannerProviderAddIn control add-in
usercontrol(BarcodeControl; CameraBarcodeScannerProviderAddIn) // Step 1
{
ApplicationArea = All;
// The ControlAddInReady event is raised when the control add-in is ready to be used.
trigger ControlAddInReady(IsSupported: Boolean)
begin
// Set the CameraBarcodeScannerAvailable variable to the value of the IsSupported parameter
CameraBarcodeScannerAvailable := IsSupported; // Step 2
end;
// The BarcodeAvailable event is raised when a barcode is available.
trigger BarcodeAvailable(Barcode: Text; Format: Text)
begin
Message(Barcode);// Step 4
// Continious scanning
//CurrPage.BarcodeControl.RequestBarcodeAsync(); // Step 5
end;
// The BarcodeFailure event is raised on a failure
trigger BarcodeFailure(Reason: Enum BarcodeFailure)
begin
case Reason of
Reason::Cancel:
Message('Canceled');
Reason::NoBarcode:
Message('No Barcode');
Reason::Error:
Message('Error');
end;
end;
}
}
}
actions
{
area(Processing)
{
action(ScanBarcode)
{
ApplicationArea = All;
Promoted = true;
PromotedCategory = Process;
Caption = 'Scan Barcode';
trigger OnAction()
begin
// Request a barcode
CurrPage.BarcodeControl.RequestBarcodeAsync(); // Step 3
end;
}
}
}
var
CameraBarcodeScannerAvailable: Boolean;
}Test:
Test video:
Enabling multiple scans is also very simple; just remove the comments from step 5 in the sample.
PS: There are two other overload functions available; you can refer to the standard code.
Test code:
page 50100 "Camera Barcode Scanner"
{
PageType = Card;
ApplicationArea = All;
Caption = 'Camera Barcode Scanner Sample';
UsageCategory = Administration;
layout
{
area(Content)
{
// Declare the user control based on the CameraBarcodeScannerProviderAddIn control add-in
usercontrol(BarcodeControl; CameraBarcodeScannerProviderAddIn) // Step 1
{
ApplicationArea = All;
// The ControlAddInReady event is raised when the control add-in is ready to be used.
trigger ControlAddInReady(IsSupported: Boolean)
begin
// Set the CameraBarcodeScannerAvailable variable to the value of the IsSupported parameter
CameraBarcodeScannerAvailable := IsSupported; // Step 2
end;
// The BarcodeAvailable event is raised when a barcode is available.
trigger BarcodeAvailable(Barcode: Text; Format: Text)
begin
Message(Barcode);// Step 4
// Continious scanning
CurrPage.BarcodeControl.RequestBarcodeAsync(); // Step 5
end;
// The BarcodeFailure event is raised on a failure
trigger BarcodeFailure(Reason: Enum BarcodeFailure)
begin
case Reason of
Reason::Cancel:
Message('Canceled');
Reason::NoBarcode:
Message('No Barcode');
Reason::Error:
Message('Error');
end;
end;
}
}
}
actions
{
area(Processing)
{
action(ScanBarcode)
{
ApplicationArea = All;
Promoted = true;
PromotedCategory = Process;
Caption = 'Scan Barcode';
trigger OnAction()
begin
// Request a barcode
CurrPage.BarcodeControl.RequestBarcodeAsync(); // Step 3
end;
}
}
}
var
CameraBarcodeScannerAvailable: Boolean;
}Test video: Sometimes it displays the previous result, I’m not sure if it’s a bug.🤔Maybe it’s just a problem with my phone.
Let’s look at a practical example: add a scan action to the Sales Order page to scan the Lot No. and add the corresponding item number for the Lot No. to sales lines. (Since there’s no standard function to print the item number’s barcode, I used Lot No.)
Test video:
Great, this method can accomplish many things. Give it a try!!!😁
Source code: Github (Please note that the source code is for reference only, you can improve it according to your own needs)
pageextension 50128 SalesOrderExt extends "Sales Order"
{
layout
{
addbefore(General)
{
// Declare the user control based on the CameraBarcodeScannerProviderAddIn control add-in
usercontrol(BarcodeControl; CameraBarcodeScannerProviderAddIn) // Step 1
{
ApplicationArea = All;
// The ControlAddInReady event is raised when the control add-in is ready to be used.
trigger ControlAddInReady(IsSupported: Boolean)
begin
// Set the CameraBarcodeScannerAvailable variable to the value of the IsSupported parameter
CameraBarcodeScannerAvailable := IsSupported; // Step 2
end;
// The BarcodeAvailable event is raised when a barcode is available.
trigger BarcodeAvailable(Barcode: Text; Format: Text)
var
SalesLine: Record "Sales Line";
LotNoInfo: Record "Lot No. Information";
begin
//Message(Barcode);// Step 4
LotNoInfo.Reset();
LotNoInfo.SetRange("Lot No.", Barcode);
if LotNoInfo.FindFirst() then begin
SalesLine.Init();
SalesLine.Validate("Document Type", Rec."Document Type");
SalesLine.Validate("Document No.", Rec."No.");
SalesLine.Validate("Line No.", GetSalesLineLastLineNo(Rec) + 10000);
SalesLine.Validate("Type", SalesLine.Type::Item);
SalesLine.Validate("No.", LotNoInfo."Item No.");
SalesLine.Validate("Quantity", 1);
SalesLine.Insert(true);
end else
Message('Lot No. %1 not found.', Barcode);
// Continious scanning
CurrPage.BarcodeControl.RequestBarcodeAsync(); // Step 5
end;
// The BarcodeFailure event is raised on a failure
trigger BarcodeFailure(Reason: Enum BarcodeFailure)
begin
case Reason of
Reason::Cancel:
Message('Canceled');
Reason::NoBarcode:
Message('No Barcode');
Reason::Error:
Message('Error');
end;
end;
}
}
}
actions
{
addbefore(Post)
{
action(ScanBarcode)
{
ApplicationArea = All;
Promoted = true;
PromotedCategory = Process;
Caption = 'Scan Barcode';
Image = ViewDocumentLine;
trigger OnAction()
begin
// Request a barcode
CurrPage.BarcodeControl.RequestBarcodeAsync(); // Step 3
end;
}
}
}
var
CameraBarcodeScannerAvailable: Boolean;
local procedure GetSalesLineLastLineNo(var SalesHeader: Record "Sales Header"): Integer
var
SalesLine: Record "Sales Line";
begin
SalesLine.Reset();
SalesLine.SetRange("Document Type", SalesHeader."Document Type");
SalesLine.SetRange("Document No.", SalesHeader."No.");
SalesLine.SetCurrentKey("Line No.");
if SalesLine.FindLast() then
exit(SalesLine."Line No.");
exit(0);
end;
}PS: You can still use the .NET-based APIs but the control add-in APIs are the recommended way to implement barcode scanning capability going forward.
END
Hope this will help.
Thanks for reading.
ZHU
コメント