diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/stock/models/stock_production_lot.py | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/stock/models/stock_production_lot.py')
| -rw-r--r-- | addons/stock/models/stock_production_lot.py | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/addons/stock/models/stock_production_lot.py b/addons/stock/models/stock_production_lot.py new file mode 100644 index 00000000..e311ad3d --- /dev/null +++ b/addons/stock/models/stock_production_lot.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError + + +class ProductionLot(models.Model): + _name = 'stock.production.lot' + _inherit = ['mail.thread', 'mail.activity.mixin'] + _description = 'Lot/Serial' + _check_company_auto = True + + name = fields.Char( + 'Lot/Serial Number', default=lambda self: self.env['ir.sequence'].next_by_code('stock.lot.serial'), + required=True, help="Unique Lot/Serial Number") + ref = fields.Char('Internal Reference', help="Internal reference number in case it differs from the manufacturer's lot/serial number") + product_id = fields.Many2one( + 'product.product', 'Product', + domain=lambda self: self._domain_product_id(), required=True, check_company=True) + product_uom_id = fields.Many2one( + 'uom.uom', 'Unit of Measure', + related='product_id.uom_id', store=True, readonly=False) + quant_ids = fields.One2many('stock.quant', 'lot_id', 'Quants', readonly=True) + product_qty = fields.Float('Quantity', compute='_product_qty') + note = fields.Html(string='Description') + display_complete = fields.Boolean(compute='_compute_display_complete') + company_id = fields.Many2one('res.company', 'Company', required=True, store=True, index=True) + + @api.constrains('name', 'product_id', 'company_id') + def _check_unique_lot(self): + domain = [('product_id', 'in', self.product_id.ids), + ('company_id', 'in', self.company_id.ids), + ('name', 'in', self.mapped('name'))] + fields = ['company_id', 'product_id', 'name'] + groupby = ['company_id', 'product_id', 'name'] + records = self.read_group(domain, fields, groupby, lazy=False) + error_message_lines = [] + for rec in records: + if rec['__count'] != 1: + product_name = self.env['product.product'].browse(rec['product_id'][0]).display_name + error_message_lines.append(_(" - Product: %s, Serial Number: %s", product_name, rec['name'])) + if error_message_lines: + raise ValidationError(_('The combination of serial number and product must be unique across a company.\nFollowing combination contains duplicates:\n') + '\n'.join(error_message_lines)) + + def _domain_product_id(self): + domain = [ + "('tracking', '!=', 'none')", + "('type', '=', 'product')", + "'|'", + "('company_id', '=', False)", + "('company_id', '=', company_id)" + ] + if self.env.context.get('default_product_tmpl_id'): + domain.insert(0, + ("('product_tmpl_id', '=', %s)" % self.env.context['default_product_tmpl_id']) + ) + return '[' + ', '.join(domain) + ']' + + def _check_create(self): + active_picking_id = self.env.context.get('active_picking_id', False) + if active_picking_id: + picking_id = self.env['stock.picking'].browse(active_picking_id) + if picking_id and not picking_id.picking_type_id.use_create_lots: + raise UserError(_('You are not allowed to create a lot or serial number with this operation type. To change this, go on the operation type and tick the box "Create New Lots/Serial Numbers".')) + + @api.depends('name') + def _compute_display_complete(self): + """ Defines if we want to display all fields in the stock.production.lot form view. + It will if the record exists (`id` set) or if we precised it into the context. + This compute depends on field `name` because as it has always a default value, it'll be + always triggered. + """ + for prod_lot in self: + prod_lot.display_complete = prod_lot.id or self._context.get('display_complete') + + @api.model_create_multi + def create(self, vals_list): + self._check_create() + return super(ProductionLot, self).create(vals_list) + + def write(self, vals): + if 'company_id' in vals: + for lot in self: + if lot.company_id.id != vals['company_id']: + raise UserError(_("Changing the company of this record is forbidden at this point, you should rather archive it and create a new one.")) + if 'product_id' in vals and any(vals['product_id'] != lot.product_id.id for lot in self): + move_lines = self.env['stock.move.line'].search([('lot_id', 'in', self.ids), ('product_id', '!=', vals['product_id'])]) + if move_lines: + raise UserError(_( + 'You are not allowed to change the product linked to a serial or lot number ' + 'if some stock moves have already been created with that number. ' + 'This would lead to inconsistencies in your stock.' + )) + return super(ProductionLot, self).write(vals) + + @api.depends('quant_ids', 'quant_ids.quantity') + def _product_qty(self): + for lot in self: + # We only care for the quants in internal or transit locations. + quants = lot.quant_ids.filtered(lambda q: q.location_id.usage == 'internal' or (q.location_id.usage == 'transit' and q.location_id.company_id)) + lot.product_qty = sum(quants.mapped('quantity')) + + def action_lot_open_quants(self): + self = self.with_context(search_default_lot_id=self.id, create=False) + if self.user_has_groups('stock.group_stock_manager'): + self = self.with_context(inventory_mode=True) + return self.env['stock.quant']._get_quants_action() |
