View source | Discuss this page | Page history | Printable version   

POS - Reading variable measure barcode


Code snippet

Name: POS - Reading variable measure barcode
Version: POS 2.30
Author: Jens Winberg


Currently OpenBravo POS cannot read a variable EAN code that includes information about Item in different format according to GTIN specification. For example an EAN barcode might include product price product has been weighted on a scale in the shop. A barcode might also include the weight of the product. In both cases OpenBravo POS should be able to find the correct product from the product registry and apply the correct price on the sales line.

This solution has to be adapted for local/country specific rules. This example is an implementation for Finnish GS1 rules, where a variable measure bar code can consist of:

0 2 R R R R R R R R R R C

2 0 I I I I M M P P, P P C

2 1 I I I I M M P P P, P C

2 2 I I I I M M P P P P C

2 3 I I I I M M W, W W W C

2 4 I I I I M M W W, W W C

2 5 I I I I M M W W W, W C

2 8 R R R R R P P P, P P C

Where: R = Retailer assigned, M = Manuf. assigned, V = Verifier digit, W = Weight, I = MO assigned, IM = Manuf. ID for special product ass. by MO, P = Price N = Pieces/Other


Information about GTIN-13 barcodes: [1]

Use of 02 and 20 to 29 Codes in GS1 Europe Countries: [2]

1. In (com.openbravo.pos.forms) add method:

        public final ProductInfoExt getProductInfoByShortCode(String sCode) throws BasicException {
        return (ProductInfoExt) new PreparedSentence(s
              "FROM PRODUCTS WHERE SUBSTRING( CODE, 3, 6 ) = ?"
            , SerializerWriteString.INSTANCE
            , ProductInfoExt.getSerializerRead()).find(sCode.substring(2, 8));

Change method getProductInfoByCode so that it looks like this:

    public final ProductInfoExt getProductInfoByCode(String sCode) throws BasicException {
        if (sCode.length() == 13 && (sCode.startsWith("2") || sCode.startsWith("02"))) return  getProductInfoByShortCode(sCode);
        else {
        return (ProductInfoExt) new PreparedSentence(s
              "FROM PRODUCTS WHERE CODE = ?"
            , SerializerWriteString.INSTANCE
            , ProductInfoExt.getSerializerRead()).find(sCode);

2. In (com.openbravo.pos.sales) uncomment part of code and add the part that extracts information from the barcode. This functionality will have to be adapted according to country specific rules (see references).

		/* START uncommenting part for implementation of variable measure barcode
                else if (sCode.length() == 13 && sCode.startsWith("250")) {
                    // barcode of the other machine
                    ProductInfoExt oProduct = new ProductInfoExt(); // Es un ticket
                    oProduct.setReference(null); // para que no se grabe
                    oProduct.setName("Ticket " + sCode.substring(3, 7));
                    oProduct.setPriceSell(Double.parseDouble(sCode.substring(7, 12)) / 100);
                    oProduct.setTaxCategoryID(((TaxCategoryInfo) taxcategoriesmodel.getSelectedItem()).getID());
                    // Se anade directamente una unidad con el precio y todo
                    addTicketLine(oProduct, 1.0, includeTaxes(oProduct.getTaxCategoryID(), oProduct.getPriceSell()));
                } else if (sCode.length() == 13 && sCode.startsWith("210")) {
                    // barcode of a weigth product
                    incProductByCodePrice(sCode.substring(0, 7), Double.parseDouble(sCode.substring(7, 12)) / 100);
                * STOP uncommenting part for implementation of variable measure barcode
                //start implementation of variable barcode
                else if ((sCode.length() == 13) && sCode.startsWith("2") || sCode.startsWith("02")) {
                    try {
                        ProductInfoExt oProduct = dlSales.getProductInfoByCode(sCode);
                        if (oProduct == null) {
                            new MessageInf(MessageInf.SGN_WARNING, AppLocal.getIntString("message.noproduct")).show(this);
                        } else {
                            //set properties for product so we can use them directly using scripts in OpenBravo POS resources
                            oProduct.setProperty("product.barcode", sCode); 
                            //get the price based on the barcode
                            double dPriceSell = oProduct.getPriceSell(); //default price for product
                            double weight = 0; //used if barcode includes weight of product
                            String sVariableTypePrefix = sCode.substring(0, 2);
                            String sVariableNum =  sCode.substring(8, 12);
                            if      (sVariableTypePrefix.equals("20")) dPriceSell = Double.parseDouble(sVariableNum) / 100; //Price with two decimals
                            else if (sVariableTypePrefix.equals("21")) dPriceSell = Double.parseDouble(sVariableNum) / 10; //Price with one decimals
                            else if (sVariableTypePrefix.equals("22")) dPriceSell = Double.parseDouble(sVariableNum); //Price with no decimals
                            else if (sVariableTypePrefix.equals("23")) weight = Double.parseDouble(sVariableNum) / 1000; //Weight in kg with three decimals (e.g. 1,234 kg)
                            else if (sVariableTypePrefix.equals("24")) weight = Double.parseDouble(sVariableNum) / 100; //Weight in kg with two decimals (e.g. 12,34 kg)
                            else if (sVariableTypePrefix.equals("25")) weight = Double.parseDouble(sVariableNum) / 10; //Weight in kg with one decimals (e.g. 123,4 kg)
                            if ((sVariableTypePrefix.equals("20")) || (sVariableTypePrefix.equals("21")) || (sVariableTypePrefix.equals("22"))) {
                                //price in barcode already includes taxes so remove tax from dPriceSell to avoid doublication of tax
                                TaxInfo tax = taxeslogic.getTaxInfo(oProduct.getTaxCategoryID(),  m_oTicket.getDate(), m_oTicket.getCustomer());
                                dPriceSell = dPriceSell / (1.0 + tax.getRate());
                                oProduct.setProperty("product.price", Double.toString(dPriceSell));
                            } else if ((sVariableTypePrefix.equals("23")) || (sVariableTypePrefix.equals("24")) || (sVariableTypePrefix.equals("25"))) {
                                dPriceSell = weight * oProduct.getPriceSell();
                                oProduct.setProperty("product.weight", Double.toString(weight));
                            if (m_jaddtax.isSelected()) {
                                TaxInfo tax = taxeslogic.getTaxInfo(oProduct.getTaxCategoryID(),  m_oTicket.getDate(), m_oTicket.getCustomer());
                                addTicketLine(oProduct, 1.0, dPriceSell / (1.0 + tax.getRate()));
                            } else {
                                addTicketLine(oProduct, 1.0, dPriceSell);
                    } catch (BasicException eData) {
                        new MessageInf(eData).show(this);

3. In you probably noticed that product properties were added to the product. These properties can easily be used in dynamic scripts in OpenBravo POS, e.g. if you want to print the weight of the product on the ticket after the name follow these steps: In Resources => Ticket.Buttons add: <event key="ticket.change" code="event.change"/>

In Resources => add resource "event.change" with following code:

import com.openbravo.pos.ticket.TicketLineInfo;
index = sales.getSelectedIndex();
if (index != -1) {
	line = ticket.getLine(index);
	String barcode = line.getProperty("product.barcode","");
	String price = line.getProperty("product.price","");
	String weight = line.getProperty("product.weight","");
	if (weight != "") line.setProperty("", "" + line.getProperty("") + " (" + weight + " kg)");

This will print the name of the product and its weight on the receipt e.g. "Banana (1,75 kg)"


The product with a variable measure barcode must exist in the product registry (database) with a barcode of length 13 (EAN 13).

The correct way to store variable measure barcodes would normally be 2 3 I I I I M M 0 0 0 0 C (example: 2378215700007). I.e. 0 (zero) in place of weight, and I I I I M M representing the six characters of the product code.

This solution however does also allow storing specific item barcodes in registry (with weight or price).

For example: 2378215712802 (weight 1,28 kg)

When another item with the same product number but different weight is scanned through the POS, the product will be correctly identified and the correct weight will be extracted from the barcode. The six characters representing product number in this example is “782157”. So the barcode 2378215715001 will be identified against either 2378215700007 or 2378215712802 in the product registry (database).

Retrieved from ""

This page has been accessed 20,903 times. This page was last modified on 15 February 2011, at 12:04. Content is available under Creative Commons Attribution-ShareAlike 2.5 Spain License.