Hi guys,
Last few days have been really tiring for me doing this particular task.
Requirement:
Barcode labels have to be printed from AX2012 for a particular work using a Thermal barcode printer.
Label size:2.48in X 0.91in
This may seem to be an easy solution but in reality, this may make your head spin.
Solution provided: SSRS report
Challenge faced: As the label size is landscape mode when you try to print the label from SSRS report, it prints the label tilting it to 90 degrees to the left. This is due to the label printer drivers as far as I could find out through google.
Also, there is a limitation in SSRS which automatically converts the mode to portrait or landscape based on the dimensions you provide for the report. So both these individual limitations make it impossible to print a rectangle label.
Solution provided 2: AX report
The challenge faced: This had seemed to be the best approach as the report renders itself as per the default printer settings. So when we were printing then it was coming out perfect and was scannable too. But the issue came when we were printing from different machines, it was not scannable!! This had me wondering that what could be the issue cause the labels from my machines (scannable) and other machines (not scannable) were exactly same.
The barcode font that we were using was IDAUTOMATIONHC39M which is of Code39 type and we got to know that Code39 expands the barcode horizontally and vertically. The universally best barcode is to use Code128.
Finally what had worked:
Solution provided 3: Direct printing using PRN file
Now this was really interesting as I had never done anything of this regard yet. So first I got a prn (TSC programmed) file. Then googled and got the solution to do so.
The challenge faced: PRN files hit directly to the printer by using printer name/IP address. In our case, the printer and AX were in different domains and we were sharing them through remote desktop. So when you share a printer through RDP then the name of the printer "TSC ME240" gets a suffix of "TSC ME240 redirected 23" and hence the PRN command from AX was not able to find the printer "TSC ME240".
Solution: Put printer on Public IP
We had to put the printer on public IP and add it to the server with the same name by a fresh installation of printer drivers and avoid redirecting.
The Task:
1. Got the PRN from the Printer vendor.
2. Create a table for storing the PRN code similar to WHSDocumentRoutingLayout. Fields: LayoutId, Description, PrinterName, DefaultConfig, PRNCode
3. Write a find, findByDefault method.
4. Create a form for the same table.
5. Create a new layout, mark it default and define the TSC/ZPL code in the form.
Below code is in TSC programming langauge in this case for TSC label printers:
<xpml><page quantity='0' pitch='23.1 mm'></xpml>SIZE 61.7 mm, 23.1 mm
GAP 3 mm, 0 mm
DIRECTION 0,0
REFERENCE 0,0
OFFSET 0 mm
SET PEEL OFF
SET CUTTER OFF
SET PARTIAL_CUTTER OFF
<xpml></page></xpml><xpml><page quantity='1' pitch='23.1 mm'></xpml>SET TEAR ON
CLS
BARCODE 462,117,"128M",27,0,180,2,4,"OIDPIDBarcode"
CODEPAGE 1252
TEXT 440,83,"0",180,12,12,"EcomOrderProductId"
TEXT 449,158,"0",180,12,10,"ItemId"
TEXT 463,44,"0",180,8,10,"ItemName"
PRINT 1,1
<xpml></page></xpml><xpml><end/></xpml>
6. Now, create a class "WHSBarcodePrinting" with the following methods:
class WHSBarcodePrinting
{
RecordSortedList list;
}
Last few days have been really tiring for me doing this particular task.
Requirement:
Barcode labels have to be printed from AX2012 for a particular work using a Thermal barcode printer.
Label size:2.48in X 0.91in
This may seem to be an easy solution but in reality, this may make your head spin.
Solution provided: SSRS report
Challenge faced: As the label size is landscape mode when you try to print the label from SSRS report, it prints the label tilting it to 90 degrees to the left. This is due to the label printer drivers as far as I could find out through google.
Also, there is a limitation in SSRS which automatically converts the mode to portrait or landscape based on the dimensions you provide for the report. So both these individual limitations make it impossible to print a rectangle label.
Solution provided 2: AX report
The challenge faced: This had seemed to be the best approach as the report renders itself as per the default printer settings. So when we were printing then it was coming out perfect and was scannable too. But the issue came when we were printing from different machines, it was not scannable!! This had me wondering that what could be the issue cause the labels from my machines (scannable) and other machines (not scannable) were exactly same.
The barcode font that we were using was IDAUTOMATIONHC39M which is of Code39 type and we got to know that Code39 expands the barcode horizontally and vertically. The universally best barcode is to use Code128.
Finally what had worked:
Solution provided 3: Direct printing using PRN file
Now this was really interesting as I had never done anything of this regard yet. So first I got a prn (TSC programmed) file. Then googled and got the solution to do so.
The challenge faced: PRN files hit directly to the printer by using printer name/IP address. In our case, the printer and AX were in different domains and we were sharing them through remote desktop. So when you share a printer through RDP then the name of the printer "TSC ME240" gets a suffix of "TSC ME240 redirected 23" and hence the PRN command from AX was not able to find the printer "TSC ME240".
Solution: Put printer on Public IP
We had to put the printer on public IP and add it to the server with the same name by a fresh installation of printer drivers and avoid redirecting.
The Task:
1. Got the PRN from the Printer vendor.
2. Create a table for storing the PRN code similar to WHSDocumentRoutingLayout. Fields: LayoutId, Description, PrinterName, DefaultConfig, PRNCode
3. Write a find, findByDefault method.
4. Create a form for the same table.
5. Create a new layout, mark it default and define the TSC/ZPL code in the form.
Below code is in TSC programming langauge in this case for TSC label printers:
<xpml><page quantity='0' pitch='23.1 mm'></xpml>SIZE 61.7 mm, 23.1 mm
GAP 3 mm, 0 mm
DIRECTION 0,0
REFERENCE 0,0
OFFSET 0 mm
SET PEEL OFF
SET CUTTER OFF
SET PARTIAL_CUTTER OFF
<xpml></page></xpml><xpml><page quantity='1' pitch='23.1 mm'></xpml>SET TEAR ON
CLS
BARCODE 462,117,"128M",27,0,180,2,4,"OIDPIDBarcode"
CODEPAGE 1252
TEXT 440,83,"0",180,12,12,"EcomOrderProductId"
TEXT 449,158,"0",180,12,10,"ItemId"
TEXT 463,44,"0",180,8,10,"ItemName"
PRINT 1,1
<xpml></page></xpml><xpml><end/></xpml>
6. Now, create a class "WHSBarcodePrinting" with the following methods:
- Class declaration
class WHSBarcodePrinting
{
RecordSortedList list;
}
- initMenuFields - To read the fields to which needs to be printed.
RecordSortedList initMenuFields()
{
TmpSysTableField tmpField;
DictField dictField;
DictTable dictTable = new DictTable(tableNum(WHSWorkLine));
int length = dictTable.fieldCnt();
int i;
for (i = 1; i <= length; ++i)
{
dictField = new DictField(tableNum(WHSWorkLine), dictTable.fieldCnt2Id(i));
if (!dictField.isSystem() || !dictField.visible() && dictField.name() == 'ItemId' || dictField.name() == 'EcomOrderProductId')
{
tmpField.FieldId = dictField.id();
tmpField.FieldName = dictField.name();
tmpField.FieldLabel = dictField.label();
list.ins(tmpField);
}
}
return list;
}
- new
public void new()
{
list = new RecordSortedList(tableNum(TmpSysTableField));
list.sortOrder(fieldNum(TmpSysTableField, FieldLabel));
this.initMenuFields();
}
- printDocument - To get the final string command to be sent to the printer.
public boolean printDocument(PrinterName _printerName, WHSLayoutId _layoutId, WHSWorkLine _label)
{
str finalStr;
boolean ret;
finalStr = this.translate(WHSBarcodePrintingSetup::find(_layoutId).zpl, _label);
Microsoft.Dynamics.AX.WHS.DeviceCom.Printer::SendStringToPrinter(_printerName, finalStr);
return ret;
}
- translate - Reading the PRN code and replacing the variable with Ax table values to be printed on label.
str translate(str _inputStr, WHSWorkLine _label)
{
TmpSysTableField tmpField;
FieldLabel label;
str outputStr;
outputStr = _inputStr;
list.first(tmpField);
while (tmpField.FieldLabel != '')
{
outputStr = strReplace(outputStr, strFmt('%1', tmpField.FieldName), _label.(tmpField.FieldId));
outputStr = strReplace(outputStr, 'ItemName', _label.displayItemName());
outputStr = strReplace(outputStr, 'OIDPIDBarcode', "!105" + subStr(_label.EcomOrderProductId, 0, 8) + "!100" +
subStr(_label.EcomOrderProductId, 9, 3) + "!099" + subStr(_label.EcomOrderProductId, 12, strLen(_label.EcomOrderProductId)));
label = tmpField.FieldLabel;
tmpField.clear();
list.next(tmpField);
if (label == tmpField.FieldLabel)
{
break;
}
}
return outputStr;
}
- main - Filtering the records for which label has to be printed.
static void main(Args _args)
{
WHSBarcodePrinting barcodePrint = new WHSBarcodePrinting();
PrinterName printerName;
WHSWorkTable whsWorkTable;
WHSWorkLine whsWorkLine;
WHSBarcodePrintingSetup barcodeSetup;
WHSLayoutId layoutId;
barcodeSetup = WHSBarcodePrintingSetup::findByDefault(NoYes::Yes);
printerName = barcodeSetup.PrinterName;
layoutId = barcodeSetup.LayoutId;
barcodePrint.initMenuFields();
if (_args.record() && _args.record().TableId == tableNum(WHSWorkTable))
{
whsWorkTable = _args.record();
if (whsWorkTable.WorkTransType == WHSWorkTransType::Sales && (whsWorkTable.WorkStatus != WHSWorkStatus::Cancelled
|| whsWorkTable.WorkStatus != WHSWorkStatus::Skipped))
{
while select ItemId, EcomOrderProductId from whsWorkLine
order by whsWorkLine.WMSLocationId, whsWorkLine.ItemId
where whsWorkLine.WorkId == whsWorkTable.WorkId
&& whsWorkLine.WorkType == WHSWorkType::Pick
{
barcodePrint.printDocument(printerName, layoutId, whsWorkLine);
}
}
}
else if (_args.record() && _args.record().TableId == tableNum(WHSWorkLine))
{
whsWorkLine = _args.record();
barcodePrint.printDocument(printerName, layoutId, whsWorkLine);
}
else
{
throw error('This command must be run from a Work Id.');
}
}
Pheww!! After all this you will be able to print the labels comfortably which are readable by any scanner. :)
Reference: http://jhodge65.blogspot.in/2015/03/zebra-printer-label-printing-with.html
c# code
ReplyDeleteplease given c# code
ReplyDeleteHi Suresh, I did not use C# for this. But you can use the same logic used in class WHSBarcodePrinting and convert it in C#.
ReplyDeleteThis comment has been removed by the author.
ReplyDelete