From a09e370ec5e54311e925206b89ae003dcd6a7082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Voet=20=28ryv=29?= Date: Mon, 16 Mar 2020 10:25:25 +0000 Subject: [PATCH] [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 --- .../barcodes/models/barcode_nomenclature.py | 216 ++++++++++-------- addons/barcodes/models/barcode_rule.py | 27 +-- .../barcodes/static/src/js/barcode_parser.js | 139 +++++------ .../static/tests/barcode_parser_tests.js | 12 +- .../tests/test_barcode_nomenclature.py | 11 +- 5 files changed, 209 insertions(+), 196 deletions(-) diff --git a/addons/barcodes/models/barcode_nomenclature.py b/addons/barcodes/models/barcode_nomenclature.py index 1cf5ca0cfe7..c72e2ac6c5a 100644 --- a/addons/barcodes/models/barcode_nomenclature.py +++ b/addons/barcodes/models/barcode_nomenclature.py @@ -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'] diff --git a/addons/barcodes/models/barcode_rule.py b/addons/barcodes/models/barcode_rule.py index 113d294042e..448ab800108 100644 --- a/addons/barcodes/models/barcode_rule.py +++ b/addons/barcodes/models/barcode_rule.py @@ -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)) diff --git a/addons/barcodes/static/src/js/barcode_parser.js b/addons/barcodes/static/src/js/barcode_parser.js index 3077f650fae..dcf6472d43a 100644 --- a/addons/barcodes/static/src/js/barcode_parser.js +++ b/addons/barcodes/static/src/js/barcode_parser.js @@ -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] !== '^') { diff --git a/addons/barcodes/static/tests/barcode_parser_tests.js b/addons/barcodes/static/tests/barcode_parser_tests.js index 76ed7e2e2e5..f468eeb963d 100644 --- a/addons/barcodes/static/tests/barcode_parser_tests.js +++ b/addons/barcodes/static/tests/barcode_parser_tests.js @@ -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); }); }); }); diff --git a/addons/barcodes/tests/test_barcode_nomenclature.py b/addons/barcodes/tests/test_barcode_nomenclature.py index b747d9ab765..98f7a555473 100644 --- a/addons/barcodes/tests/test_barcode_nomenclature.py +++ b/addons/barcodes/tests/test_barcode_nomenclature.py @@ -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.