# -*- coding: utf-8 -*- # Copyright (C) 2014 GRAP (http://www.grap.coop) # Copyright (C) 2016-Today GRAP (http://www.lalouve.net) # @author: Sylvain LE GAL (https://twitter.com/legalsylvain) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import barcode from openerp import models, fields, api, exceptions class barcode_generate_mixin(models.AbstractModel): _name = 'barcode.generate.mixin' # Column Section barcode_rule_id = fields.Many2one( string='Barcode Rule', comodel_name='barcode.rule') barcode_base = fields.Char(string='Barcode Base') # Constrains Section @api.multi @api.constrains('barcode_base') def _constrains_barcode_base(self): for item in self: if item.barcode_base and not item.barcode_base.isdigit(): raise exceptions.Warning(_("Barcode Base should be numeric")) # View Section @api.multi def generate_base(self): for item in self: padding = item.barcode_rule_id.pattern.count('.') generic_code = self._get_custom_barcode(item) if generic_code: generic_code = generic_code.replace( '.' * padding, '_' * padding) reserved_barcodes = self.search([('barcode', 'ilike', generic_code)]).mapped('barcode') next_base = str(self._get_next_integer_base( item, generic_code, reserved_barcodes)).rjust(padding, '0') item.barcode_base = next_base @api.multi def generate_barcode(self): for item in self: padding = item.barcode_rule_id.pattern.count('.') full_base = str(item.barcode_base).rjust(padding, '0') custom_code = self._get_custom_barcode(item) if custom_code: custom_code = custom_code.replace('.' * padding, full_base) barcode_class = barcode.get_barcode_class( item.barcode_rule_id.encoding) item.barcode = barcode_class(custom_code) @api.multi def generate_base_barcode(self): for item in self: if not item.barcode_base: item.generate_base() item.generate_barcode() # Custom Section @api.model def _get_next_integer_base(self, item, generic_code, reserved_barcodes): """Given a list of reserved_barcodes, This will return the next" base barcode. By default, return the max barcode base + 1. Overload / Overwrite this function to provide custom behaviour. (specially, fill gaps functionnality). generic_code should have the '_' pattern. """ if not reserved_barcodes: return 1 max_barcode = sorted(reserved_barcodes)[len(reserved_barcodes) - 1] begin = generic_code.find('_') end = begin + generic_code.count('_') return int(max_barcode[begin:end]) + 1 @api.model def _get_custom_barcode(self, item): """ if the pattern is '23.....{NNNDD}' this function will return '23.....00000' """ if not item.barcode_rule_id: return False # Define barcode custom_code = item.barcode_rule_id.pattern custom_code = custom_code.replace('{', '').replace('}', '') custom_code = custom_code.replace( 'D', self._get_replacement_char('D')) return custom_code.replace( 'N', self._get_replacement_char('N')) @api.model def _get_replacement_char(self, char): """ Can be overload by inheritance Define wich character will be used instead of the 'N' or the 'D' char, present in the pattern of the barcode_rule_id """ return '0'