from odoo import api, fields, models class ProductTemplate(models.Model): _inherit = 'product.template' lot_sequence_id = fields.Many2one( 'ir.sequence', string='Serial/Lot Numbers Sequence', domain=[('code', '=', 'stock.lot.serial')], help='Technical Field: The Ir.Sequence record that is used to generate serial/lot numbers for this product' ) serial_prefix_format = fields.Char( 'Custom Lot/Serial', compute='_compute_serial_prefix_format', inverse='_inverse_serial_prefix_format', help='Set a prefix to generate serial/lot numbers automatically when receiving or producing this product. ' 'Use % codes like %(y)s for year, %(month)s for month, etc.' ) next_serial = fields.Char( 'Next Number', compute='_compute_next_serial', help='The next serial/lot number to be generated for this product' ) @api.depends('lot_sequence_id', 'lot_sequence_id.prefix') def _compute_serial_prefix_format(self): for template in self: template.serial_prefix_format = template.lot_sequence_id.prefix or "" def _inverse_serial_prefix_format(self): valid_sequences = self.env['ir.sequence'].search([('prefix', 'in', self.mapped('serial_prefix_format'))]) sequences_by_prefix = {seq.prefix: seq for seq in valid_sequences} for template in self: if template.serial_prefix_format: if template.serial_prefix_format in sequences_by_prefix: template.lot_sequence_id = sequences_by_prefix[template.serial_prefix_format] else: # Create a new sequence with the given prefix new_sequence = self.env['ir.sequence'].create({ 'name': f'{template.name} Serial Sequence', 'code': 'stock.lot.serial', 'prefix': template.serial_prefix_format, 'padding': 7, 'company_id': False, # Global sequence to avoid cross-company conflicts }) template.lot_sequence_id = new_sequence sequences_by_prefix[template.serial_prefix_format] = new_sequence else: # Reset to default if no prefix template.lot_sequence_id = self.env.ref('stock.sequence_production_lots', raise_if_not_found=False) @api.depends('serial_prefix_format', 'lot_sequence_id') def _compute_next_serial(self): from datetime import datetime for template in self: if template.lot_sequence_id: seq = template.lot_sequence_id # Build the interpolation dictionary for date formatting now = datetime.now() interpolation_dict = { 'year': now.strftime('%Y'), 'y': now.strftime('%y'), 'month': now.strftime('%m'), 'day': now.strftime('%d'), 'doy': now.strftime('%j'), 'woy': now.strftime('%W'), 'weekday': now.strftime('%w'), 'h24': now.strftime('%H'), 'h12': now.strftime('%I'), 'min': now.strftime('%M'), 'sec': now.strftime('%S'), } # Format prefix and suffix with date codes try: prefix = (seq.prefix or '') % interpolation_dict if seq.prefix else '' except (KeyError, ValueError): prefix = seq.prefix or '' try: suffix = (seq.suffix or '') % interpolation_dict if seq.suffix else '' except (KeyError, ValueError): suffix = seq.suffix or '' template.next_serial = '{}{:0{}d}{}'.format( prefix, seq.number_next_actual, seq.padding, suffix ) else: template.next_serial = '00001'