[REF] barcodes: refactor check digit computation
To prepare gs1-128 feature, refactors the check digit computation. Also, does some cleanings: - Removes unusused check_ean method; - Converts comments into docstrings; - Makes needed changes to avoid linter errors (PEP 8). task-1968113 Co-authored-by: ryv-odoo<ryv@odoo.com>
This commit is contained in:
committed by
svs-odoo
parent
d1abf31fb4
commit
a09e370ec5
@@ -1,163 +1,177 @@
|
||||
import logging
|
||||
import re
|
||||
|
||||
from odoo import models, fields
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
UPC_EAN_CONVERSIONS = [
|
||||
('none','Never'),
|
||||
('ean2upc','EAN-13 to UPC-A'),
|
||||
('upc2ean','UPC-A to EAN-13'),
|
||||
('always','Always'),
|
||||
('none', 'Never'),
|
||||
('ean2upc', 'EAN-13 to UPC-A'),
|
||||
('upc2ean', 'UPC-A to EAN-13'),
|
||||
('always', 'Always'),
|
||||
]
|
||||
|
||||
|
||||
class BarcodeNomenclature(models.Model):
|
||||
_name = 'barcode.nomenclature'
|
||||
_description = 'Barcode Nomenclature'
|
||||
|
||||
name = fields.Char(string='Barcode Nomenclature', size=32, required=True, help='An internal identification of the barcode nomenclature')
|
||||
rule_ids = fields.One2many('barcode.rule', 'barcode_nomenclature_id', string='Rules', help='The list of barcode rules')
|
||||
upc_ean_conv = fields.Selection(UPC_EAN_CONVERSIONS, string='UPC/EAN Conversion', required=True, default='always',
|
||||
upc_ean_conv = fields.Selection(
|
||||
UPC_EAN_CONVERSIONS, string='UPC/EAN Conversion', required=True, default='always',
|
||||
help="UPC Codes can be converted to EAN by prefixing them with a zero. This setting determines if a UPC/EAN barcode should be automatically converted in one way or another when trying to match a rule with the other encoding.")
|
||||
|
||||
# returns the checksum of the ean13, or -1 if the ean has not the correct length, ean must be a string
|
||||
def ean_checksum(self, ean):
|
||||
code = list(ean)
|
||||
if len(code) != 13:
|
||||
return -1
|
||||
@api.model
|
||||
def get_barcode_check_digit(self, numeric_barcode):
|
||||
""" Computes and returns the barcode check digit. The used algorithm
|
||||
follows the GTIN specifications and can be used by all compatible
|
||||
barcode nomenclature, like as EAN-8, EAN-12 (UPC-A) or EAN-13.
|
||||
|
||||
https://www.gs1.org/sites/default/files/docs/barcodes/GS1_General_Specifications.pdf
|
||||
https://www.gs1.org/services/how-calculate-check-digit-manually
|
||||
|
||||
:param numeric_barcode: the barcode to verify/recompute the check digit
|
||||
:type numeric_barcode: str
|
||||
:return: the number corresponding to the right check digit
|
||||
:rtype: int
|
||||
"""
|
||||
# Multiply value of each position by
|
||||
# N1 N2 N3 N4 N5 N6 N7 N8 N9 N10 N11 N12 N13 N14 N15 N16 N17 N18
|
||||
# x3 X1 x3 x1 x3 x1 x3 x1 x3 x1 x3 x1 x3 x1 x3 x1 x3 CHECKSUM
|
||||
oddsum = evensum = total = 0
|
||||
code = code[:-1] # Remove checksum
|
||||
for i in range(len(code)):
|
||||
code = numeric_barcode[-2::-1] # Remove the check digit and reverse the barcode.
|
||||
# The CHECKSUM digit is removed because it will be recomputed and it must not interfer with
|
||||
# the computation. Also, the barcode is inverted, so the barcode length doesn't matter.
|
||||
# Otherwise, the digits' group (even or odd) could be different according to the barcode length.
|
||||
for i, digit in enumerate(code):
|
||||
if i % 2 == 0:
|
||||
evensum += int(code[i])
|
||||
evensum += int(digit)
|
||||
else:
|
||||
oddsum += int(code[i])
|
||||
total = oddsum * 3 + evensum
|
||||
return int((10 - total % 10) % 10)
|
||||
oddsum += int(digit)
|
||||
total = evensum * 3 + oddsum
|
||||
return (10 - total % 10) % 10
|
||||
|
||||
# returns the checksum of the ean8, or -1 if the ean has not the correct length, ean must be a string
|
||||
def ean8_checksum(self,ean):
|
||||
code = list(ean)
|
||||
if len(code) != 8:
|
||||
return -1
|
||||
|
||||
sum1 = int(ean[1]) + int(ean[3]) + int(ean[5])
|
||||
sum2 = int(ean[0]) + int(ean[2]) + int(ean[4]) + int(ean[6])
|
||||
total = sum1 + 3 * sum2
|
||||
return int((10 - total % 10) % 10)
|
||||
|
||||
# returns true if the barcode is a valid EAN barcode
|
||||
def check_ean(self, ean):
|
||||
return re.match("^\d+$", ean) and self.ean_checksum(ean) == int(ean[-1])
|
||||
|
||||
# returns true if the barcode string is encoded with the provided encoding.
|
||||
@api.model
|
||||
def check_encoding(self, barcode, encoding):
|
||||
if encoding == 'ean13':
|
||||
return len(barcode) == 13 and re.match("^\d+$", barcode) and self.ean_checksum(barcode) == int(barcode[-1])
|
||||
elif encoding == 'ean8':
|
||||
return len(barcode) == 8 and re.match("^\d+$", barcode) and self.ean8_checksum(barcode) == int(barcode[-1])
|
||||
elif encoding == 'upca':
|
||||
return len(barcode) == 12 and re.match("^\d+$", barcode) and self.ean_checksum("0"+barcode) == int(barcode[-1])
|
||||
elif encoding == 'any':
|
||||
""" Checks if the given barcode is correctly encoded.
|
||||
|
||||
:return: True if the barcode string is encoded with the provided encoding.
|
||||
:rtype: bool
|
||||
"""
|
||||
if encoding == "any":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
barcode_sizes = {
|
||||
'ean8': 8,
|
||||
'ean13': 13,
|
||||
'upca': 12,
|
||||
}
|
||||
barcode_size = barcode_sizes[encoding]
|
||||
return len(barcode) == barcode_size and re.match(r"^\d+$", barcode) and self.get_barcode_check_digit(barcode) == int(barcode[-1])
|
||||
|
||||
|
||||
# Returns a valid zero padded ean13 from an ean prefix. the ean prefix must be a string.
|
||||
@api.model
|
||||
def sanitize_ean(self, ean):
|
||||
ean = ean[0:13]
|
||||
ean = ean + (13-len(ean))*'0'
|
||||
return ean[0:12] + str(self.ean_checksum(ean))
|
||||
""" Returns a valid zero padded EAN-13 from an EAN prefix.
|
||||
|
||||
# Returns a valid zero padded UPC-A from a UPC-A prefix. the UPC-A prefix must be a string.
|
||||
:type ean: str
|
||||
"""
|
||||
ean = ean[0:13].zfill(13)
|
||||
return ean[0:-1] + str(self.get_barcode_check_digit(ean))
|
||||
|
||||
@api.model
|
||||
def sanitize_upc(self, upc):
|
||||
return self.sanitize_ean('0'+upc)[1:]
|
||||
""" Returns a valid zero padded UPC-A from a UPC-A prefix.
|
||||
|
||||
:type upc: str
|
||||
"""
|
||||
return self.sanitize_ean('0' + upc)[1:]
|
||||
|
||||
# Checks if barcode matches the pattern
|
||||
# Additionaly retrieves the optional numerical content in barcode
|
||||
# Returns an object containing:
|
||||
# - value: the numerical value encoded in the barcode (0 if no value encoded)
|
||||
# - base_code: the barcode in which numerical content is replaced by 0's
|
||||
# - match: boolean
|
||||
def match_pattern(self, barcode, pattern):
|
||||
"""Checks barcode matches the pattern and retrieves the optional numeric value in barcode.
|
||||
|
||||
:param barcode:
|
||||
:type barcode: str
|
||||
:param pattern:
|
||||
:type pattern: str
|
||||
:return: an object containing:
|
||||
- value: the numerical value encoded in the barcode (0 if no value encoded)
|
||||
- base_code: the barcode in which numerical content is replaced by 0's
|
||||
- match: boolean
|
||||
:rtype: dict
|
||||
"""
|
||||
match = {
|
||||
"value": 0,
|
||||
"base_code": barcode,
|
||||
"match": False,
|
||||
'value': 0,
|
||||
'base_code': barcode,
|
||||
'match': False,
|
||||
}
|
||||
|
||||
barcode = barcode.replace("\\", "\\\\").replace("{", '\{').replace("}", "\}").replace(".", "\.")
|
||||
numerical_content = re.search("[{][N]*[D]*[}]", pattern) # look for numerical content in pattern
|
||||
barcode = barcode.replace('\\', '\\\\').replace('{', '\\{').replace('}', '\\}').replace('.', '\\.')
|
||||
numerical_content = re.search("[{][N]*[D]*[}]", pattern) # look for numerical content in pattern
|
||||
|
||||
if numerical_content: # the pattern encodes a numerical content
|
||||
num_start = numerical_content.start() # start index of numerical content
|
||||
num_end = numerical_content.end() # end index of numerical content
|
||||
value_string = barcode[num_start:num_end-2] # numerical content in barcode
|
||||
if numerical_content: # the pattern encodes a numerical content
|
||||
num_start = numerical_content.start() # start index of numerical content
|
||||
num_end = numerical_content.end() # end index of numerical content
|
||||
value_string = barcode[num_start:num_end - 2] # numerical content in barcode
|
||||
|
||||
whole_part_match = re.search("[{][N]*[D}]", numerical_content.group()) # looks for whole part of numerical content
|
||||
decimal_part_match = re.search("[{N][D]*[}]", numerical_content.group()) # looks for decimal part
|
||||
whole_part = value_string[:whole_part_match.end()-2] # retrieve whole part of numerical content in barcode
|
||||
decimal_part = "0." + value_string[decimal_part_match.start():decimal_part_match.end()-1] # retrieve decimal part
|
||||
whole_part_match = re.search("[{][N]*[D}]", numerical_content.group()) # looks for whole part of numerical content
|
||||
decimal_part_match = re.search("[{N][D]*[}]", numerical_content.group()) # looks for decimal part
|
||||
whole_part = value_string[:whole_part_match.end() - 2] # retrieve whole part of numerical content in barcode
|
||||
decimal_part = "0." + value_string[decimal_part_match.start():decimal_part_match.end() - 1] # retrieve decimal part
|
||||
if whole_part == '':
|
||||
whole_part = '0'
|
||||
match['value'] = int(whole_part) + float(decimal_part)
|
||||
|
||||
match['base_code'] = barcode[:num_start] + (num_end-num_start-2)*"0" + barcode[num_end-2:] # replace numerical content by 0's in barcode
|
||||
match['base_code'] = match['base_code'].replace("\\\\", "\\").replace("\{", "{").replace("\}","}").replace("\.",".")
|
||||
pattern = pattern[:num_start] + (num_end-num_start-2)*"0" + pattern[num_end:] # replace numerical content by 0's in pattern to match
|
||||
match['base_code'] = barcode[:num_start] + (num_end - num_start - 2) * "0" + barcode[num_end - 2:] # replace numerical content by 0's in barcode
|
||||
match['base_code'] = match['base_code'].replace("\\\\", "\\").replace("\\{", "{").replace("\\}", "}").replace("\\.", ".")
|
||||
pattern = pattern[:num_start] + (num_end - num_start - 2) * "0" + pattern[num_end:] # replace numerical content by 0's in pattern to match
|
||||
|
||||
match['match'] = re.match(pattern, match['base_code'][:len(pattern)])
|
||||
|
||||
return match
|
||||
|
||||
# Attempts to interpret an barcode (string encoding a barcode)
|
||||
# It will return an object containing various information about the barcode.
|
||||
# most importantly :
|
||||
# - code : the barcode
|
||||
# - type : the type of the barcode:
|
||||
# - value : if the id encodes a numerical value, it will be put there
|
||||
# - base_code : the barcode code with all the encoding parts set to zero; the one put on
|
||||
# the product in the backend
|
||||
def parse_barcode(self, barcode):
|
||||
""" Attempts to interpret and parse a barcode.
|
||||
|
||||
:param barcode:
|
||||
:type barcode: str
|
||||
:return: A object containing various information about the barcode, like as:
|
||||
- code: the barcode
|
||||
- type: the barcode's type
|
||||
- value: if the id encodes a numerical value, it will be put there
|
||||
- base_code: the barcode code with all the encoding parts set to
|
||||
zero; the one put on the product in the backend
|
||||
:rtype: dict
|
||||
"""
|
||||
parsed_result = {
|
||||
'encoding': '',
|
||||
'type': 'error',
|
||||
'code': barcode,
|
||||
'base_code': barcode,
|
||||
'encoding': '',
|
||||
'type': 'error',
|
||||
'code': barcode,
|
||||
'base_code': barcode,
|
||||
'value': 0,
|
||||
}
|
||||
|
||||
rules = []
|
||||
for rule in self.rule_ids:
|
||||
rules.append({'type': rule.type, 'encoding': rule.encoding, 'sequence': rule.sequence, 'pattern': rule.pattern, 'alias': rule.alias})
|
||||
|
||||
for rule in rules:
|
||||
cur_barcode = barcode
|
||||
if rule['encoding'] == 'ean13' and self.check_encoding(barcode,'upca') and self.upc_ean_conv in ['upc2ean','always']:
|
||||
cur_barcode = '0'+cur_barcode
|
||||
elif rule['encoding'] == 'upca' and self.check_encoding(barcode,'ean13') and barcode[0] == '0' and self.upc_ean_conv in ['ean2upc','always']:
|
||||
if rule.encoding == 'ean13' and self.check_encoding(barcode, 'upca') and self.upc_ean_conv in ['upc2ean', 'always']:
|
||||
cur_barcode = '0' + cur_barcode
|
||||
elif rule.encoding == 'upca' and self.check_encoding(barcode, 'ean13') and barcode[0] == '0' and self.upc_ean_conv in ['ean2upc', 'always']:
|
||||
cur_barcode = cur_barcode[1:]
|
||||
|
||||
if not self.check_encoding(barcode,rule['encoding']):
|
||||
if not self.check_encoding(barcode, rule.encoding):
|
||||
continue
|
||||
|
||||
match = self.match_pattern(cur_barcode, rule['pattern'])
|
||||
match = self.match_pattern(cur_barcode, rule.pattern)
|
||||
if match['match']:
|
||||
if rule['type'] == 'alias':
|
||||
barcode = rule['alias']
|
||||
if rule.type == 'alias':
|
||||
barcode = rule.alias
|
||||
parsed_result['code'] = barcode
|
||||
else:
|
||||
parsed_result['encoding'] = rule['encoding']
|
||||
parsed_result['type'] = rule['type']
|
||||
parsed_result['encoding'] = rule.encoding
|
||||
parsed_result['type'] = rule.type
|
||||
parsed_result['value'] = match['value']
|
||||
parsed_result['code'] = cur_barcode
|
||||
if rule['encoding'] == "ean13":
|
||||
if rule.encoding == "ean13":
|
||||
parsed_result['base_code'] = self.sanitize_ean(match['base_code'])
|
||||
elif rule['encoding'] == "upca":
|
||||
elif rule.encoding == "upca":
|
||||
parsed_result['base_code'] = self.sanitize_upc(match['base_code'])
|
||||
else:
|
||||
parsed_result['base_code'] = match['base_code']
|
||||
|
||||
@@ -7,30 +7,31 @@ from odoo.exceptions import ValidationError
|
||||
class BarcodeRule(models.Model):
|
||||
_name = 'barcode.rule'
|
||||
_description = 'Barcode Rule'
|
||||
_order = 'sequence asc'
|
||||
|
||||
_order = 'sequence asc, id'
|
||||
|
||||
name = fields.Char(string='Rule Name', size=32, required=True, help='An internal identification for this barcode nomenclature rule')
|
||||
barcode_nomenclature_id = fields.Many2one('barcode.nomenclature', string='Barcode Nomenclature')
|
||||
sequence = fields.Integer(string='Sequence', help='Used to order rules such that rules with a smaller sequence match first')
|
||||
encoding = fields.Selection([
|
||||
('any', 'Any'),
|
||||
('ean13', 'EAN-13'),
|
||||
('ean8', 'EAN-8'),
|
||||
('upca', 'UPC-A'),
|
||||
], string='Encoding', required=True, default='any', help='This rule will apply only if the barcode is encoded with the specified encoding')
|
||||
type = fields.Selection([
|
||||
encoding = fields.Selection(
|
||||
string='Encoding', required=True, default='any', selection=[
|
||||
('any', 'Any'),
|
||||
('ean13', 'EAN-13'),
|
||||
('ean8', 'EAN-8'),
|
||||
('upca', 'UPC-A'),
|
||||
], help='This rule will apply only if the barcode is encoded with the specified encoding')
|
||||
type = fields.Selection(
|
||||
string='Type', required=True, selection=[
|
||||
('alias', 'Alias'),
|
||||
('product', 'Unit Product')
|
||||
], string='Type', required=True, default='product')
|
||||
('product', 'Unit Product'),
|
||||
], default='product')
|
||||
pattern = fields.Char(string='Barcode Pattern', size=32, help="The barcode matching pattern", required=True, default='.*')
|
||||
alias = fields.Char(string='Alias', size=32, default='0', help='The matched pattern will alias to this barcode', required=True)
|
||||
|
||||
@api.constrains('pattern')
|
||||
def _check_pattern(self):
|
||||
for rule in self:
|
||||
p = rule.pattern.replace("\\\\", "X").replace("\{", "X").replace("\}", "X")
|
||||
findall = re.findall("[{]|[}]", p) # p does not contain escaped { or }
|
||||
p = rule.pattern.replace('\\\\', 'X').replace('\\{', 'X').replace('\\}', 'X')
|
||||
findall = re.findall("[{]|[}]", p) # p does not contain escaped { or }
|
||||
if len(findall) == 2:
|
||||
if not re.search("[{][N]*[D]*[}]", p):
|
||||
raise ValidationError(_("There is a syntax error in the barcode pattern %(pattern)s: braces can only contain N's followed by D's.", pattern=rule.pattern))
|
||||
|
||||
@@ -50,76 +50,77 @@ var BarcodeParser = Class.extend({
|
||||
return this.loaded;
|
||||
},
|
||||
|
||||
// returns the checksum of the ean13, or -1 if the ean has not the correct length, ean must be a string
|
||||
ean_checksum: function(ean){
|
||||
var code = ean.split('');
|
||||
if(code.length !== 13){
|
||||
return -1;
|
||||
}
|
||||
var oddsum = 0, evensum = 0, total = 0;
|
||||
code = code.reverse().splice(1);
|
||||
for(var i = 0; i < code.length; i++){
|
||||
if(i % 2 === 0){
|
||||
oddsum += Number(code[i]);
|
||||
}else{
|
||||
evensum += Number(code[i]);
|
||||
/**
|
||||
* This algorithm is identical for all fixed length numeric GS1 data structures.
|
||||
*
|
||||
* It is also valid for EAN-8, EAN-12 (UPC-A), EAN-13 check digit after sanitizing.
|
||||
* https://www.gs1.org/sites/default/files/docs/barcodes/GS1_General_Specifications.pdf
|
||||
*
|
||||
* @param {String} numericBarcode Need to have a length of 18
|
||||
* @returns {number} Check Digit
|
||||
*/
|
||||
get_barcode_check_digit(numericBarcode) {
|
||||
let oddsum = 0, evensum = 0, total = 0;
|
||||
// Reverses the barcode to be sure each digit will be in the right place
|
||||
// regardless the barcode length.
|
||||
const code = numericBarcode.split('').reverse();
|
||||
// Removes the last barcode digit (should not be took in account for its own computing).
|
||||
code.shift();
|
||||
|
||||
// Multiply value of each position by
|
||||
// N1 N2 N3 N4 N5 N6 N7 N8 N9 N10 N11 N12 N13 N14 N15 N16 N17 N18
|
||||
// x3 X1 x3 x1 x3 x1 x3 x1 x3 x1 x3 x1 x3 x1 x3 x1 x3 CHECK_DIGIT
|
||||
for (let i = 0; i < code.length; i++) {
|
||||
if (i % 2 === 0) {
|
||||
evensum += parseInt(code[i]);
|
||||
} else {
|
||||
oddsum += parseInt(code[i]);
|
||||
}
|
||||
}
|
||||
total = oddsum * 3 + evensum;
|
||||
return Number((10 - total % 10) % 10);
|
||||
total = evensum * 3 + oddsum;
|
||||
return (10 - total % 10) % 10;
|
||||
},
|
||||
|
||||
// returns the checksum of the ean8, or -1 if the ean has not the correct length, ean must be a string
|
||||
ean8_checksum: function(ean){
|
||||
var code = ean.split('');
|
||||
if (code.length !== 8) {
|
||||
return -1;
|
||||
}
|
||||
var sum1 = Number(code[1]) + Number(code[3]) + Number(code[5]);
|
||||
var sum2 = Number(code[0]) + Number(code[2]) + Number(code[4]) + Number(code[6]);
|
||||
var total = sum1 + 3 * sum2;
|
||||
return Number((10 - total % 10) % 10);
|
||||
},
|
||||
|
||||
|
||||
// returns true if the ean is a valid EAN barcode number by checking the control digit.
|
||||
// ean must be a string
|
||||
check_ean: function(ean){
|
||||
return /^\d+$/.test(ean) && this.ean_checksum(ean) === Number(ean[ean.length-1]);
|
||||
},
|
||||
|
||||
// returns true if the barcode string is encoded with the provided encoding.
|
||||
/**
|
||||
* Checks if the barcode string is encoded with the provided encoding.
|
||||
*
|
||||
* @param {String} barcode
|
||||
* @param {String} encoding could be 'any' (no encoding rules), 'ean8', 'upca' or 'ean13'
|
||||
* @returns {boolean}
|
||||
*/
|
||||
check_encoding: function(barcode, encoding) {
|
||||
var len = barcode.length;
|
||||
var allnum = /^\d+$/.test(barcode);
|
||||
var check = Number(barcode[len-1]);
|
||||
|
||||
if (encoding === 'ean13') {
|
||||
return len === 13 && allnum && this.ean_checksum(barcode) === check;
|
||||
} else if (encoding === 'ean8') {
|
||||
return len === 8 && allnum && this.ean8_checksum(barcode) === check;
|
||||
} else if (encoding === 'upca') {
|
||||
return len === 12 && allnum && this.ean_checksum('0'+barcode) === check;
|
||||
} else if (encoding === 'any') {
|
||||
if (encoding === 'any') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
const barcodeSizes = {
|
||||
ean8: 8,
|
||||
ean13: 13,
|
||||
upca: 12,
|
||||
};
|
||||
return barcode.length === barcodeSizes[encoding] && /^\d+$/.test(barcode) &&
|
||||
this.get_barcode_check_digit(barcode) === parseInt(barcode[barcode.length - 1]);
|
||||
},
|
||||
|
||||
// returns a valid zero padded ean13 from an ean prefix. the ean prefix must be a string.
|
||||
/**
|
||||
* Sanitizes a EAN-13 prefix by padding it with chars zero.
|
||||
*
|
||||
* @param {String} ean
|
||||
* @returns {String}
|
||||
*/
|
||||
sanitize_ean: function(ean){
|
||||
ean = ean.substr(0,13);
|
||||
|
||||
for(var n = 0, count = (13 - ean.length); n < count; n++){
|
||||
ean = '0' + ean;
|
||||
}
|
||||
return ean.substr(0,12) + this.ean_checksum(ean);
|
||||
ean = ean.substr(0, 13);
|
||||
ean = "0".repeat(13 - ean.length) + ean;
|
||||
return ean.substr(0, 12) + this.get_barcode_check_digit(ean);
|
||||
},
|
||||
|
||||
// Returns a valid zero padded UPC-A from a UPC-A prefix. the UPC-A prefix must be a string.
|
||||
/**
|
||||
* Sanitizes a UPC-A prefix by padding it with chars zero.
|
||||
*
|
||||
* @param {String} upc
|
||||
* @returns {String}
|
||||
*/
|
||||
sanitize_upc: function(upc) {
|
||||
return this.sanitize_ean('0'+upc).substr(1,12);
|
||||
return this.sanitize_ean(upc).substr(1, 12);
|
||||
},
|
||||
|
||||
// Checks if barcode matches the pattern
|
||||
@@ -149,33 +150,33 @@ var BarcodeParser = Class.extend({
|
||||
if (whole_part === ''){
|
||||
whole_part = '0';
|
||||
}
|
||||
match['value'] = parseInt(whole_part) + parseFloat(decimal_part);
|
||||
match.value = parseInt(whole_part) + parseFloat(decimal_part);
|
||||
|
||||
// replace numerical content by 0's in barcode and pattern
|
||||
match['base_code'] = barcode.substr(0,num_start);
|
||||
var base_pattern = pattern.substr(0,num_start);
|
||||
match.base_code = barcode.substr(0, num_start);
|
||||
base_pattern = pattern.substr(0, num_start);
|
||||
for(var i=0;i<(num_length-2);i++) {
|
||||
match['base_code'] += "0";
|
||||
match.base_code += "0";
|
||||
base_pattern += "0";
|
||||
}
|
||||
match['base_code'] += barcode.substr(num_start+num_length-2,barcode.length-1);
|
||||
base_pattern += pattern.substr(num_start+num_length,pattern.length-1);
|
||||
match.base_code += barcode.substr(num_start + num_length - 2, barcode.length - 1);
|
||||
base_pattern += pattern.substr(num_start + num_length, pattern.length - 1);
|
||||
|
||||
match['base_code'] = match['base_code']
|
||||
match.base_code = match.base_code
|
||||
.replace("\\\\", "\\")
|
||||
.replace("\{", "{")
|
||||
.replace("\}","}")
|
||||
.replace("\.",".");
|
||||
|
||||
var base_code = match.base_code.split('')
|
||||
var base_code = match.base_code.split('');
|
||||
if (encoding === 'ean13') {
|
||||
base_code[12] = '' + this.ean_checksum(match.base_code);
|
||||
base_code[12] = '' + this.get_barcode_check_digit(match.base_code);
|
||||
} else if (encoding === 'ean8') {
|
||||
base_code[7] = '' + this.ean8_checksum(match.base_code);
|
||||
base_code[7] = '' + this.get_barcode_check_digit(match.base_code);
|
||||
} else if (encoding === 'upca') {
|
||||
base_code[11] = '' + this.ean_checksum('0' + match.base_code);
|
||||
base_code[11] = '' + this.get_barcode_check_digit(match.base_code);
|
||||
}
|
||||
match.base_code = base_code.join('')
|
||||
match.base_code = base_code.join('');
|
||||
}
|
||||
|
||||
if (base_pattern[0] !== '^') {
|
||||
|
||||
@@ -41,17 +41,17 @@ QUnit.module('Barcode Parser', {
|
||||
await barcodeNomenclature.loaded;
|
||||
|
||||
let ean8 = "87111125";
|
||||
assert.equal(barcodeNomenclature.ean8_checksum(ean8, 'ean8'), ean8.charAt(ean8.length - 1));
|
||||
assert.equal(barcodeNomenclature.get_barcode_check_digit(ean8), ean8[ean8.length - 1]);
|
||||
ean8 = "4725992";
|
||||
assert.equal(barcodeNomenclature.ean8_checksum(ean8 + "0", 'ean8'), 8);
|
||||
assert.equal(barcodeNomenclature.get_barcode_check_digit(ean8 + "0"), 8);
|
||||
let ean13 = "1234567891231";
|
||||
assert.equal(barcodeNomenclature.ean_checksum(ean13, 'ean13'), ean13.charAt(ean13.length - 1));
|
||||
assert.equal(barcodeNomenclature.get_barcode_check_digit(ean13), ean13[ean13.length - 1]);
|
||||
ean13 = "962434754318";
|
||||
assert.equal(barcodeNomenclature.ean_checksum(ean13 + "0", 'ean13'), 4);
|
||||
assert.equal(barcodeNomenclature.get_barcode_check_digit(ean13 + "0"), 4);
|
||||
let utca = "692771981161";
|
||||
assert.equal(barcodeNomenclature.ean_checksum("0" + utca, 'upca'), utca.charAt(utca.length - 1));
|
||||
assert.equal(barcodeNomenclature.get_barcode_check_digit(utca), utca[utca.length - 1]);
|
||||
utca = "71679131569";
|
||||
assert.equal(barcodeNomenclature.ean_checksum("0" + utca + "0", 'upca'), 7);
|
||||
assert.equal(barcodeNomenclature.get_barcode_check_digit(utca + "0"), 7);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,15 +12,12 @@ class TestBarcodeNomenclature(common.TransactionCase):
|
||||
'name': 'Barcode Nomenclature Test',
|
||||
})
|
||||
|
||||
def test_ean8_checksum(self):
|
||||
def test_barcode_check_digit(self):
|
||||
barcode_nomenclature = self.env['barcode.nomenclature']
|
||||
ean8 = "87111125"
|
||||
checksum = barcode_nomenclature.ean8_checksum(ean8)
|
||||
self.assertEqual(checksum, int(ean8[-1]))
|
||||
checksum = barcode_nomenclature.ean8_checksum("8711112")
|
||||
self.assertEqual(checksum, -1)
|
||||
checksum = barcode_nomenclature.ean8_checksum("871111256")
|
||||
self.assertEqual(checksum, -1)
|
||||
self.assertEqual(barcode_nomenclature.get_barcode_check_digit("0" * 10 + ean8), int(ean8[-1]))
|
||||
ean13 = "1234567891231"
|
||||
self.assertEqual(barcode_nomenclature.get_barcode_check_digit("0" * 5 + ean13), int(ean13[-1]))
|
||||
|
||||
def test_barcode_nomenclature_parse_barcode_ean8_01(self):
|
||||
""" Parses some barcodes with a simple EAN-8 barcode rule and checks the result.
|
||||
|
||||
Reference in New Issue
Block a user