95 lines
4.1 KiB
Python
95 lines
4.1 KiB
Python
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' |