Add barcode generation for EAN8 and EAN13 (#111, #246)

Add config option to use generation when generating barcodes for an
Generate propery barcode with configured format if item_number empty
This commit is contained in:
jekkos
2015-12-24 12:40:02 +01:00
parent c007513fc8
commit eb63f49db7
20 changed files with 188 additions and 75 deletions

View File

@@ -145,6 +145,7 @@ class Config extends Secure_area
'barcode_num_in_row'=>$this->input->post('barcode_num_in_row'),
'barcode_page_width'=>$this->input->post('barcode_page_width'),
'barcode_page_cellspacing'=>$this->input->post('barcode_page_cellspacing'),
'barcode_generate_if_empty'=>$this->input->post('barcode_generate_if_empty'),
'barcode_content'=>$this->input->post('barcode_content')
);

View File

@@ -332,21 +332,17 @@ class Items extends Secure_area implements iData_controller
$result = $this->Item->get_multiple_info($item_ids)->result_array();
$config = $this->barcode_lib->get_barcode_config();
$data['items'] = $result;
$data['barcode_config'] = $config;
// display barcodes
$this->load->view("barcode_sheet", $data);
// check the list of items to see if any item_number field is empty
foreach($result as $item)
foreach($result as &$item)
{
// update the UPC/EAN/ISBN field if empty / null with the newly generated barcode
if ($item['item_number'] == '' || $item['item_number'] == null)
if (empty($item['item_number']) && $this->Appconfig->get('barcode_generate_if_empty'))
{
// get the newly generated barcode
$item['item_number'] = $this->barcode_lib->get_new_barcode($item, $config);
$barcode_instance = Barcode_lib::barcode_instance($item, $config);
$item['item_number'] = $barcode_instance->getData();
// remove from item any suppliers table info to avoid save failure because of unknown fields
// WARNING: if suppliers table is changed this list needs to be upgraded, which makes the matter a bit tricky to maintain
unset($item['person_id']);
@@ -358,6 +354,10 @@ class Items extends Secure_area implements iData_controller
$this->Item->save($item, $item['item_id']);
}
}
$data['items'] = $result;
// display barcodes
$this->load->view("barcode_sheet", $data);
}
function bulk_edit()
@@ -497,7 +497,6 @@ class Items extends Secure_area implements iData_controller
function check_item_number()
{
$exists = $this->Item->item_number_exists($this->input->post('item_number'),$this->input->post('item_id'));
echo json_encode(array('success'=>!$exists,'message'=>$this->lang->line('items_item_number_duplicate')));
}

View File

@@ -24,6 +24,7 @@ $lang["config_barcode_second_row"] = "Row 2";
$lang["config_barcode_third_row"] = "Row 3";
$lang["config_barcode_type"] = "Barcode Type";
$lang["config_barcode_width"] = "Width (px)";
$lang["config_barcode_generate_if_empty"] = "Generate if empty";
$lang["config_company"] = "Company Name";
$lang["config_company_logo"] = "Company Logo";
$lang["config_company_required"] = "Company name is a required field";

View File

@@ -24,6 +24,7 @@ $lang["config_barcode_second_row"] = "Fila 1";
$lang["config_barcode_third_row"] = "Fila 2";
$lang["config_barcode_type"] = "Tipo de Código de Barra";
$lang["config_barcode_width"] = "Ancho (px)";
$lang["config_barcode_generate_if_empty"] = "Generate if empty";
$lang["config_company"] = "Nombre del Comercio";
$lang["config_company_logo"] = "Logotipo del Comercio";
$lang["config_company_required"] = "Nombre del Comercio es requerido";

View File

@@ -24,6 +24,7 @@ $lang["config_barcode_second_row"] = "Row 3";
$lang["config_barcode_third_row"] = "Row 4";
$lang["config_barcode_type"] = "Barcode Type";
$lang["config_barcode_width"] = "Width (px)";
$lang["config_barcode_generate_if_empty"] = "Generate if empty";
$lang["config_company"] = "Nome de l\'Entreprise";
$lang["config_company_logo"] = "Company Logo";
$lang["config_company_required"] = "Le nom d\'entreprise est requis";

View File

@@ -24,6 +24,7 @@ $lang["config_barcode_second_row"] = "Row 8";
$lang["config_barcode_third_row"] = "Row 9";
$lang["config_barcode_type"] = "Barcode Type";
$lang["config_barcode_width"] = "Width (px)";
$lang["config_barcode_generate_if_empty"] = "Generate if empty";
$lang["config_company"] = "Nama Perusahaan";
$lang["config_company_logo"] = "Company Logo";
$lang["config_company_required"] = "Nama Perusahaan wajib diisi";

View File

@@ -24,6 +24,7 @@ $lang["config_barcode_second_row"] = "Rij 2";
$lang["config_barcode_third_row"] = "Rij 3";
$lang["config_barcode_type"] = "Barcode Type";
$lang["config_barcode_width"] = "Breedte (px)";
$lang["config_barcode_generate_if_empty"] = "Genereer indien leeg";
$lang["config_company"] = "Bedrijfsnaam";
$lang["config_company_logo"] = "Logo";
$lang["config_company_required"] = "De bedrijfsnaam moet ingevuld worden";

View File

@@ -24,6 +24,7 @@ $lang["config_barcode_second_row"] = "Row 5";
$lang["config_barcode_third_row"] = "Row 6";
$lang["config_barcode_type"] = "Barcode Type";
$lang["config_barcode_width"] = "Width (px)";
$lang["config_barcode_generate_if_empty"] = "Generate if empty";
$lang["config_company"] = "Название Компании";
$lang["config_company_logo"] = "Company Logo";
$lang["config_company_required"] = "Имя Компании обязательный пробел";

View File

@@ -24,6 +24,7 @@ $lang["config_barcode_second_row"] = "แถว 2";
$lang["config_barcode_third_row"] = "แถว 3";
$lang["config_barcode_type"] = "ประเภทบาร์โค้ด";
$lang["config_barcode_width"] = "กว้าง (px)";
$lang["config_barcode_generate_if_empty"] = "Generate if empty";
$lang["config_company"] = "ชื่อร้านค้า";
$lang["config_company_logo"] = "ภาพโลโก้";
$lang["config_company_required"] = "ชื่อร้านค้าต้องกรอก";

View File

@@ -24,6 +24,7 @@ $lang["config_barcode_second_row"] = "Row 7";
$lang["config_barcode_third_row"] = "Row 8";
$lang["config_barcode_type"] = "Barcode Type";
$lang["config_barcode_width"] = "Width (px)";
$lang["config_barcode_generate_if_empty"] = "Generate if empty";
$lang["config_company"] = "Şirket Adı";
$lang["config_company_logo"] = "Company Logo";
$lang["config_company_required"] = "Şirket Adı zorunlu alandır";

View File

@@ -24,6 +24,7 @@ $lang["config_barcode_second_row"] = "Row 4";
$lang["config_barcode_third_row"] = "Row 5";
$lang["config_barcode_type"] = "Barcode Type";
$lang["config_barcode_width"] = "Width (px)";
$lang["config_barcode_generate_if_empty"] = "Generate if empty";
$lang["config_company"] = "公司名稱";
$lang["config_company_logo"] = "Company Logo";
$lang["config_company_required"] = "公司名稱為必填";

View File

@@ -38,11 +38,35 @@ class Barcode_lib
$data['barcode_num_in_row'] = $this->CI->Appconfig->get('barcode_num_in_row');
$data['barcode_page_width'] = $this->CI->Appconfig->get('barcode_page_width');
$data['barcode_page_cellspacing'] = $this->CI->Appconfig->get('barcode_page_cellspacing');
$data['barcode_generate_if_empty'] = $this->CI->Appconfig->get('barcode_generate_if_empty');
return $data;
}
private function get_barcode_instance($barcode_type='Code128')
public function validate_barcode($barcode)
{
$barcode_type = $this->CI->Appconfig->get('barcode_type');
$barcode_instance = $this->get_barcode_instance($barcode_type);
return $barcode_instance->validate($barcode);
}
public static function barcode_instance($item, $barcode_config)
{
$barcode_instance = Barcode_lib::get_barcode_instance($barcode_config['barcode_type']);
$is_valid = empty($item['item_number']) && $barcode_config['barcode_generate_if_empty'] || $barcode_instance->validate($item['item_number']);
// if barcode validation does not succeed,
if (!$is_valid)
{
$barcode_instance = Barcode_lib::get_barcode_instance();
}
$seed = Barcode_lib::barcode_seed($item, $barcode_instance, $barcode_config);
$barcode_instance->setData($seed);
return $barcode_instance;
}
private static function get_barcode_instance($barcode_type='Code128')
{
switch($barcode_type)
{
@@ -64,36 +88,41 @@ class Barcode_lib
break;
}
}
private static function barcode_seed($item, $barcode_instance, $barcode_config)
{
$seed = $barcode_config['barcode_content'] !== "id" && isset($item['item_number']) ? $item['item_number'] : $item['item_id'];
if( $barcode_config['barcode_content'] !== "id" && !empty($item['item_number']))
{
$seed = $item['item_number'];
}
else
{
if ($barcode_config['barcode_generate_if_empty'])
{
// generate barcode with the correct instance
$seed = $barcode_instance->generate($seed);
}
else
{
$seed = $item['item_id'];
}
}
return $seed;
}
private function generate_barcode($item, $barcode_config)
{
try
{
$barcode = $this->get_barcode_instance($barcode_config['barcode_type']);
$is_valid = $barcode->validate($item['item_number']);
$barcode_instance = Barcode_lib::barcode_instance($item, $barcode_config);
$barcode_instance->setQuality($barcode_config['barcode_quality']);
$barcode_instance->setDimensions($barcode_config['barcode_width'], $barcode_config['barcode_height']);
// if barcdoe validation does not succeed, then fallback to the default, which should not require specific formatting
if (!$is_valid)
{
$barcode = $this->get_barcode_instance();
}
$barcode_content = $barcode_config['barcode_content'] !== "id" && isset($item['item_number']) ? $item['item_number'] : $item['item_id'];
$barcode->setData($barcode_content);
if( $barcode_config['barcode_content'] !== "id" && isset($item['item_number']))
{
$barcode->setData($item['item_number']);
}
else
{
$barcode->setData($item['item_id']);
}
$barcode->setQuality($barcode_config['barcode_quality']);
$barcode->setDimensions($barcode_config['barcode_width'], $barcode_config['barcode_height']);
$barcode->draw();
$barcode_instance->draw();
return $barcode->base64();
return $barcode_instance->base64();
}
catch(Exception $e)
{
@@ -128,42 +157,7 @@ class Barcode_lib
}
}
public function get_new_barcode($item, $barcode_config)
{
try
{
$barcode = $this->get_barcode_instance($barcode_config['barcode_type']);
// generate a barcode only if one is not already available and we use the item_id as seed.
// This to avoid generating Barcodes out of existing Barcodes
if( $barcode_config['barcode_content'] !== "id" && isset($item['item_number']) )
{
$barcode->setData($item['item_number'], false);
return null;
}
else
{
$barcode->setData($item['item_id'], true);
$code = $barcode->getData();
// in case no new code is generated like in Code39 and Code128 return an empty string because we don't want to override it with a pure item_id
if( $code == $item['item_id'] )
{
$code = null;
}
return $code;
}
}
catch(Exception $e)
{
echo 'Caught exception: ', $e->getMessage(), "\n";
}
}
public function create_display_barcode($item, $barcode_config)
public function display_barcode($item, $barcode_config)
{
$display_table = "<table>";
$display_table .= "<tr><td align='center'>" . $this->manage_display_layout($barcode_config['barcode_first_row'], $item, $barcode_config) . "</td></tr>";

View File

@@ -16,7 +16,7 @@
<body class=<?php echo "font_".$this->barcode_lib->get_font_name($barcode_config['barcode_font']); ?>
style="font-size:<?php echo $barcode_config['barcode_font_size'] + 5; //5 is size offset for font in display label?>px">
<table cellspacing=<?php echo $barcode_config['barcode_page_cellspacing']; ?> width=<?php echo $barcode_config['barcode_page_width']."%"; ?> >
<table cellspacing=<?php echo $barcode_config['barcode_page_cellspacing']; ?> width='<?php echo $barcode_config['barcode_page_width']."%"; ?>' >
<tr>
<?php
$count = 0;
@@ -26,7 +26,7 @@
{
echo '</tr><tr>';
}
echo "<td>" . $this->barcode_lib->create_display_barcode($item, $barcode_config) . "</td>";
echo "<td>" . $this->barcode_lib->display_barcode($item, $barcode_config) . "</td>";
$count++;
}
?>

View File

@@ -84,6 +84,18 @@ abstract class BarcodeBase
{
return TRUE;
}
/**
* Generate a barcode for this implementation using the given seed.
* Default implementation returns just the seed
* @param $number The seed to generate a barcode for
* @return mixed The generated barcode
*/
public function generate($number)
{
return $number;
}
/*
* (Abstract) Draw the image
*

View File

@@ -127,6 +127,32 @@ class Ean13 extends BarcodeBase
$this->data = $data;
}
/*
* Generate EAN13 code out of a provided number
* Code taken from http://stackoverflow.com/questions/19890144/generate-valid-ean13-in-php (unknown copyright / license claims)
*
* @param number is the internal code you want to have EANed. The prefix, zero-padding and checksum are added by the function.
* @return string with complete EAN13 code
*/
public function generate($number)
{
$number = '200' . str_pad($number, 9, '0');
$weightflag = true;
$sum = 0;
// Weight for a digit in the checksum is 3, 1, 3.. starting from the last digit.
// loop backwards to make the loop length-agnostic. The same basic functionality
// will work for codes of different lengths.
for ($i = strlen($number) - 1; $i >= 0; $i--)
{
$sum += (int)$number[$i] * ($weightflag?3:1);
$weightflag = !$weightflag;
}
$number .= (10 - ($sum % 10)) % 10;
return $number;
}
public function validate($barcode)
{
// check to see if barcode is 13 digits long

View File

@@ -89,12 +89,76 @@ class Ean8 extends BarcodeBase
)
);
/*
* Calculate EAN8 or EAN13 automatically
* set $len = 8 for EAN8, $len = 13 for EAN13
*
* @param number is the internal code you want to have EANed. The prefix, zero-padding and checksum are added by the function.
* @return string with complete EAN code
*/
public function generate($number, $len = 8)
{
$barcode = $number;
if($number > -1)
{
$data_len = $len - 1;
//Padding
$barcode = str_pad($barcode, $data_len, '0', STR_PAD_LEFT);
$barcode_len = strlen($barcode);
// calculate check digit
$sum_a = 0;
for ($i = 1; $i < $data_len; $i += 2)
{
$sum_a += $barcode{$i};
}
if ($len > 12)
{
$sum_a *= 3;
}
$sum_b = 0;
for ($i = 0; $i < $data_len; $i += 2)
{
$sum_b += ($barcode{$i});
}
if ($len < 13)
{
$sum_b *= 3;
}
$r = ($sum_a + $sum_b) % 10;
if($r > 0)
{
$r = (10 - $r);
}
if (strlen($barcode) == $data_len)
{
// add check digit
$barcode .= $r;
}
elseif ($r !== intval($barcode{$data_len}))
{
// wrong checkdigit
$barcode = null;
}
}
return $barcode;
}
public function validate($barcode)
{
$ean = str_replace(array("-","/"," ","\t","\n"), "", $barcode); // make a clean ean
$len = strlen($ean);
if( !is_numeric($ean) )
if( !is_numeric($ean) || strlen($barcode) != 8 )
{
return false;
}

View File

@@ -86,6 +86,11 @@ echo form_open('config/save_barcode/',array('id'=>'barcode_config_form'));
'value'=>'number',
'checked'=>$this->config->item('barcode_content') === "number")); ?>
<?php echo $this->lang->line('config_barcode_number'); ?>
<?php echo form_checkbox(array(
'name'=>'barcode_generate_if_empty',
'value'=>'barcode_generate_if_empty',
'checked'=>$this->config->item('barcode_generate_if_empty'))); ?>
<?php echo $this->lang->line('config_barcode_generate_if_empty'); ?>
</div>
</div>

View File

@@ -3,7 +3,8 @@ ALTER TABLE `ospos_suppliers`
INSERT INTO `ospos_app_config` (`key`, `value`) VALUES
('dateformat', 'm/d/Y'),
('timeformat', 'H:i:s');
('timeformat', 'H:i:s'),
('barcode_generate_if_empty', '0');
ALTER TABLE `ospos_sales_suspended`
DROP KEY `invoice_number`;

View File

@@ -55,6 +55,7 @@ INSERT INTO `ospos_app_config` (`key`, `value`) VALUES
('barcode_num_in_row', '2'),
('barcode_page_width', '100'),
('barcode_page_cellspacing', '20'),
('barcode_generate_if_empty', '0'),
('receipt_show_taxes', '0'),
('use_invoice_template', '1'),
('invoice_email_message', 'Dear $CU, In attachment the receipt for sale $INV'),

View File

@@ -23,6 +23,7 @@ config_barcode_second_row,Rij 2,Fila 1,Row 2,Row 3,Row 4,Row 5,แถว 2,Row 7
config_barcode_third_row,Rij 3,Fila 2,Row 3,Row 4,Row 5,Row 6,แถว 3,Row 8,Row 9
config_barcode_type,Barcode Type,Tipo de Código de Barra,Barcode Type,Barcode Type,Barcode Type,Barcode Type,ประเภทบาร์โค้ด,Barcode Type,Barcode Type
config_barcode_width,Breedte (px),Ancho (px),Width (px),Width (px),Width (px),Width (px),กว้าง (px),Width (px),Width (px)
config_barcode_generate_if_empty,Genereer indien leeg,Generate if empty,Generate if empty,Generate if empty,Generate if empty,Generate if empty,Generate if empty,Generate if empty,Generate if empty
config_company,Bedrijfsnaam,Nombre del Comercio,Company Name,Nome de l\'Entreprise,公司名稱,Название Компании,ชื่อร้านค้า,Şirket Adı,Nama Perusahaan
config_company_logo,Logo,Logotipo del Comercio,Company Logo,Company Logo,Company Logo,Company Logo,ภาพโลโก้,Company Logo,Company Logo
config_company_required,De bedrijfsnaam moet ingevuld worden,Nombre del Comercio es requerido,Company name is a required field,Le nom d\'entreprise est requis,公司名稱為必填,Имя Компании обязательный пробел,ชื่อร้านค้าต้องกรอก,Şirket Adı zorunlu alandır,Nama Perusahaan wajib diisi
1 label nl-BE es en fr zh ru th tr id
23 config_barcode_third_row Rij 3 Fila 2 Row 3 Row 4 Row 5 Row 6 แถว 3 Row 8 Row 9
24 config_barcode_type Barcode Type Tipo de Código de Barra Barcode Type Barcode Type Barcode Type Barcode Type ประเภทบาร์โค้ด Barcode Type Barcode Type
25 config_barcode_width Breedte (px) Ancho (px) Width (px) Width (px) Width (px) Width (px) กว้าง (px) Width (px) Width (px)
26 config_barcode_generate_if_empty Genereer indien leeg Generate if empty Generate if empty Generate if empty Generate if empty Generate if empty Generate if empty Generate if empty Generate if empty
27 config_company Bedrijfsnaam Nombre del Comercio Company Name Nome de l\'Entreprise 公司名稱 Название Компании ชื่อร้านค้า Şirket Adı Nama Perusahaan
28 config_company_logo Logo Logotipo del Comercio Company Logo Company Logo Company Logo Company Logo ภาพโลโก้ Company Logo Company Logo
29 config_company_required De bedrijfsnaam moet ingevuld worden Nombre del Comercio es requerido Company name is a required field Le nom d\'entreprise est requis 公司名稱為必填 Имя Компании обязательный пробел ชื่อร้านค้าต้องกรอก Şirket Adı zorunlu alandır Nama Perusahaan wajib diisi