Monday, 8 December 2014

Barcode with BI publisher report


Step#1 Local Machine Font Setup
 
Install the font on the local machine where XML template is being developed.
For barcode I have used font C39P24DmTt (V100025_.TTF)
Download the font and place it under windows font directory (C:\WINNT\Fonts)
Step#2 Assign the barcode font to the field in XML template
 
Add a placeholder and change the font of it to C39P24DmTt, place the asterix (*) in prefix and suffix to the barcode field.
 
Step#3 uploading the font on server
 
A.   Font file creation
Login to BI publisher responsibility
Under Administration tab -> Font Files ->Create Font file
Name the font file as C39P24DmTtand upload the TTF file.
 
 
B.   Create Font Mapping
Login to BI publisher responsibility
Under Administration tab ->Font Mapping->Create Font Mapping
 
C.   assigning the font to the report template
Login to BI publisher responsibility
Templates -> Open the template of the concurrent program you wanted to put barcode -> Click on the edit configuration on the right corner You will see all the configurable options 



Finally run the report you shall see the barcode is being shown on the field

                          XML Publisher report handling special characters


XML Publisher report handling special characters 
Problem definition- The standard report runs fine when the output format is "Text" but errors out when it "XML".  The XML is generated partially with error message like “The XML page cannot be displayed or Authentication failed.

Solution-
Open the underlying RDF file and update the below value as
<?xml version="1.0" encoding="ISO-8859-1"?>
Once changed save the report , migrate it and test the XML output.


                                                      Code 128 Barcode with XML Publisher

Step#1 XML Tags and template 
 
Create or use existing oracle reports concurrent program. Change the output format under concurrent program definition to XML, run the concurrent program and get the XML tags. Map the RTF based on the XML tags generated.

Step#2 Getting barcode fonts 
 
For barcode I have used Code 128 from IDAutomation (you can download from their site)
After installing the font on local machine assign one of the IDAutomation font to the field in RTF template (for example an order number and font can be eg: IDAutomationSC128M)

Step#3 Barcode font reading by handheld or scanner 
 
To make the barcode to be read by scanner, the encoder java code provided by vendor has to be compiled and convert it into a java class file.
A.      Below is the class code save the code in a notepad and rename it as BarcodeUtil.java
B.      Move the class file with EBSO file structure, put it under JAVA_TOP ($JAVA_TOP/oracle/apps/xdo/template/rtf/util)
C.      Compile the Java file with .class file as
$ cd $JAVA_TOP/oracle/apps/xdo/template/rtf/util  
$ javac -g BarcodeUtil.java  This command will generate the class file as BarcodeUtil.class.

package oracle.apps.xdo.template.rtf.util;

import java.util.Hashtable;
import java.lang.reflect.Method;
import oracle.apps.xdo.template.rtf.util.XDOBarcodeEncoder;
import oracle.apps.xdo.common.log.Logger;


public class BarcodeUtil  implements XDOBarcodeEncoder{

  // This is the barcode vendor id that is used in the register vendor field and format-barcode fields
  public static final String BARCODE_VENDOR_ID = "XMLPBarVendor";
 
  // The hastable is used to store references to the encoding methods
  public static final Hashtable ENCODERS = new Hashtable(10);

  // The BarcodeUtil class needs to be instantiated
  public static final BarcodeUtil mUtility = new BarcodeUtil();

/* This is the main code that is executed in the class, it is loading the methods  for the encoding into the hashtable. In this case we are loading the three code128  encoding methods we have created. */ 

  static {
     try {
      Class[] clazz = new Class[] { "".getClass() }  ;    
      ENCODERS.put("code128a",mUtility.getClass().getMethod("code128a", clazz));
      ENCODERS.put("code128b",mUtility.getClass().getMethod("code128b", clazz));
      ENCODERS.put("code128c",mUtility.getClass().getMethod("code128c", clazz));
     } catch (Exception e) {
      Logger.log(e,5);
    }
  }

// The getVendorID method is called from the template layer at runtime to ensure the correct encoding method are used

    public final String getVendorID(){
        return BARCODE_VENDOR_ID;
    }

 // The isSupported method is called to ensure that the encoding method called from the template is actually present in this class. If not then XMLP will report this in the log.
    public final boolean isSupported(String s){
        if(s != null)
            return ENCODERS.containsKey(s.trim().toLowerCase());
        else
            return false;
    }


// The encode method is called to then call the appropriate encoding method, in this example the code128a/b/c methods.
   public final String encode(String s, String s1)  {
        if(s != null && s1 != null){
            try{
                Method method = (Method)ENCODERS.get(s1.trim().toLowerCase());
                if(method != null)
                    return (String)method.invoke(this, new Object[] {s});
                else
                    return s;
            }
            catch(Exception exception){
                  Logger.log(exception,5);
            }
            return s;
         }
                                                 else
             return s;
     }

  /** Algorithm for Code128a */

  public static final String code128a( String DataToEncode ){

    char C128_Start = (char)203;
    char C128_Stop = (char)206;
    String Printable_string = "";
    char CurrentChar;
    int CurrentValue=0;
    int weightedTotal=0;
    int CheckDigitValue=0;
    char C128_CheckDigit='w';
    DataToEncode = DataToEncode.trim();
    weightedTotal = ((int)C128_Start) - 100;

    for( int i = 1; i <= DataToEncode.length(); i++ )
      {

            //get the value of each character
            CurrentChar = DataToEncode.charAt(i-1);
            if( ((int)CurrentChar) < 135 )
              CurrentValue = ((int)CurrentChar) - 32;
            if( ((int)CurrentChar) > 134 )

              CurrentValue = ((int)CurrentChar) - 100;
            CurrentValue = CurrentValue * i;
            weightedTotal = weightedTotal + CurrentValue;

      }

    //divide the WeightedTotal by 103 and get the remainder,
    //this is the CheckDigitValue
    CheckDigitValue = weightedTotal % 103;
    if( (CheckDigitValue < 95) && (CheckDigitValue > 0) )
      C128_CheckDigit = (char)(CheckDigitValue + 32);
    if( CheckDigitValue > 94 )
      C128_CheckDigit = (char)(CheckDigitValue + 100);
    if( CheckDigitValue == 0 ){
      C128_CheckDigit = (char)194;

    }

     Printable_string = C128_Start + DataToEncode + C128_CheckDigit + C128_Stop + " ";
    return Printable_string;

  }

  /** Algorithm for Code128b */
  public static final String code128b( String DataToEncode ){

    char C128_Start = (char)204;
    char C128_Stop = (char)206;
    String Printable_string = "";
    char CurrentChar;
    int CurrentValue=0;
    int weightedTotal=0;
    int CheckDigitValue=0;
    char C128_CheckDigit='w';

    DataToEncode = DataToEncode.trim();
    weightedTotal = ((int)C128_Start) - 100;
    for( int i = 1; i <= DataToEncode.length(); i++ ){

            //get the value of each character

            CurrentChar = DataToEncode.charAt(i-1);

            if( ((int)CurrentChar) < 135 )

              CurrentValue = ((int)CurrentChar) - 32;

            if( ((int)CurrentChar) > 134 )
              CurrentValue = ((int)CurrentChar) - 100;
              CurrentValue = CurrentValue * i;
              weightedTotal = weightedTotal + CurrentValue;

      }

    //divide the WeightedTotal by 103 and get the remainder,

    //this is the CheckDigitValue
    CheckDigitValue = weightedTotal % 103;
    if( (CheckDigitValue < 95) && (CheckDigitValue > 0) )
      C128_CheckDigit = (char)(CheckDigitValue + 32);
    if( CheckDigitValue > 94 )
      C128_CheckDigit = (char)(CheckDigitValue + 100);
    if( CheckDigitValue == 0 ){
      C128_CheckDigit = (char)194;
    }

    Printable_string = C128_Start + DataToEncode + C128_CheckDigit + C128_Stop + " ";
    return Printable_string;
  }

  /** Algorithm for Code128c **/

  public static final String code128c( String s ){
    char C128_Start = (char)205;
    char C128_Stop = (char)206;
    String Printable_string = "";
    String DataToPrint = "";
    String OnlyCorrectData = "";
    int i=1;
    int CurrentChar=0;
    int CurrentValue=0;
    int weightedTotal=0;
    int CheckDigitValue=0;
    char C128_CheckDigit='w';
    DataToPrint = "";
    s = s.trim();
    for(i = 1; i <= s.length(); i++ ){
            //Add only numbers to OnlyCorrectData string
            CurrentChar = (int)s.charAt(i-1);
            if((CurrentChar < 58) && (CurrentChar > 47))
              {
                OnlyCorrectData = OnlyCorrectData + (char)s.charAt(i-1);
              }
      }
    s = OnlyCorrectData;
    //Check for an even number of digits, add 0 if not even
    if( (s.length() % 2) == 1 )
      {
            s = "0" + s;

      }
    //<;<<< Calculate Modulo 103 Check Digit and generate DataToPrint >>>>
    //Set WeightedTotal to the Code 128 value of the start character
    weightedTotal = ((int)C128_Start) - 100;
    int WeightValue = 1;
    for( i = 1; i <= s.length(); i += 2 ){
            //Get the value of each number pair (ex: 5 and 6 = 5*10+6 =56)
            //And assign the ASCII values to DataToPrint
            CurrentChar = ((((int)s.charAt(i-1))-48)*10) + (((int)s.charAt(i))-48);
            if((CurrentChar < 95) && (CurrentChar  > 0))
              DataToPrint = DataToPrint + (char)(CurrentChar + 32);
            if( CurrentChar > 94 )
              DataToPrint = DataToPrint + (char)(CurrentChar + 100);
            if( CurrentChar == 0)
              DataToPrint = DataToPrint + (char)194;
            //multiply by the weighting character
            //add the values together to get the weighted total
            weightedTotal = weightedTotal + (CurrentChar * WeightValue);
            WeightValue = WeightValue + 1;
      }

    //divide the WeightedTotal by 103 and get the remainder,this is the CheckDigitValue
    CheckDigitValue = weightedTotal % 103;
    if((CheckDigitValue < 95) && (CheckDigitValue > 0))
      C128_CheckDigit = (char)(CheckDigitValue + 32);
    if( CheckDigitValue > 94 )
      C128_CheckDigit = (char)(CheckDigitValue + 100);
    if( CheckDigitValue == 0 ){
      C128_CheckDigit = (char)194;
    }
    Printable_string = C128_Start + DataToPrint + C128_CheckDigit + C128_Stop + " ";
    Logger.log(Printable_string,5);
    return Printable_string;
  }
}

Step#4 referring the class file (BarcodeUtil.class) within the RTF template
Place an empty field at the start and place below tag into it
<?register-barcode-vendor:'oracle.apps.xdo.template.rtf.util.BarcodeUtil';'XMLPBarVendor'?>
Note:- Please note the inner path for the class we moved (oracle/apps/xdo/template/rtf/util) after JAVA_TOP is the same as we are using above oracle.apps.xdo.template.rtf.util


Step#5 Barcode font assignment
Open your RTF and make the changes as shown below
Barcode font as any ID font (I have used IDAutomationC128M)
Click on Barcode field and place <?format-barcode:NAME;'code128a';'XMLPBarVendor'?> 
Where order number is my barcode data field.


Step#6 uploading the font on server
 
Login to BI publisher responsibility
Under Administration tab à Font Files àCreate Font file
Name the font file as IDAutomationSC128M and upload the TTF file.


 
Step#7 Font Mapping
Login to BI publisher responsibility
Under Administration tab à Font Mappings àCreate Font Mapping set
You can create font mapping set for each individual IDautomation font you have uploaded in previous step

Step#8 assigning the font to the report template
Login to BI publisher responsibility
Templates à Open the template of the concurrent program you wanted to put barcode à Click on the edit configuration on the right corner
You will see all the configurable options 
Click on FO Processing and expand it
Update the Font mapping set to the set you have created for example its IDAutomationC128M
 When you run the repot now it should generate the barcode and if you can print it and scan the barcode it should be readable by the scanner.

1 comment:

  1. Regards
    Sridevi Koduru (Senior Oracle Apps Trainer Oracleappstechnical.com)
    LinkedIn profile - https://in.linkedin.com/in/sridevi-koduru-9b876a8b
    Please Contact for One to One Online Training on Oracle Apps Technical, Financials, SCM, Oracle Manufacturing, BI Publisher, OAF, ADF, SQL, PL/SQL, D2K at sridevikoduru@oracleappstechnical.com | +91 - 9581017828.

    ReplyDelete