From 4792bd0d8df3993fcaeb19990dff0398c7a51d96 Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Thu, 29 Jan 2026 08:51:57 +0700 Subject: [PATCH] feat: Default company ID for quality checks and refactor lot assignment to use `lot_ids` while preserving quality state. --- models/quality_check.py | 96 ++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/models/quality_check.py b/models/quality_check.py index 3c9d47c..424534c 100755 --- a/models/quality_check.py +++ b/models/quality_check.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from odoo import models, api, fields +from odoo import models, api, fields, Command class QualityCheck(models.Model): @@ -53,9 +53,45 @@ class QualityCheck(models.Model): self.ensure_one() return self._is_receipt_operation() + @api.model + def default_get(self, fields_list): + defaults = super(QualityCheck, self).default_get(fields_list) + if 'company_id' not in defaults: + picking_id = defaults.get('picking_id') or self.env.context.get('default_picking_id') + if picking_id: + picking = self.env['stock.picking'].browse(picking_id) + if picking.company_id: + defaults['company_id'] = picking.company_id.id + return defaults + + @api.model_create_multi + def create(self, vals_list): + """ + Override create to ensure company_id is set. + Prioritizes: + 1. Explicitly passed value (in vals) + 2. Picking's company (if picking_id is available) + 3. Context default_company_id + 4. Current user's company (env.company) + """ + for vals in vals_list: + if not vals.get('company_id'): + # Try to get from picking + picking_id = vals.get('picking_id') or self.env.context.get('default_picking_id') + if picking_id: + picking = self.env['stock.picking'].browse(picking_id) + if picking.company_id: + vals['company_id'] = picking.company_id.id + + # If still missing, check context or use current environment company + if not vals.get('company_id'): + vals['company_id'] = self.env.context.get('default_company_id') or self.env.company.id + + return super(QualityCheck, self).create(vals_list) + def write(self, vals): """ - Override write to prevent state reset when lot_id is updated on receipt operations. + Override write to prevent state reset when lot_ids is updated on receipt operations. """ # Store current states before write for receipt operations state_data = {} @@ -79,6 +115,7 @@ class QualityCheck(models.Model): stored = state_data[record.id] if record.quality_state != stored['quality_state']: # Use SQL to restore state without triggering write again + # Using formatted SQL for safety self.env.cr.execute( """ UPDATE quality_check @@ -102,32 +139,10 @@ class QualityCheck(models.Model): # Always update lot_line_id qc.lot_line_id = qc.move_line_id.lot_id - # Check if we should update lot_id + # Check if we should update lot_ids if qc.lot_line_id and qc._update_lot_from_lot_line(): - # For receipt operations, preserve the state - if qc._should_preserve_state(): - # Store current state before updating lot_id - current_state = qc.quality_state - - # Directly update lot_id field in database without triggering ORM - if current_state != 'none': - # Use SQL to update lot_id while preserving state - self.env.cr.execute( - """ - UPDATE quality_check - SET lot_id = %s - WHERE id = %s AND quality_state = %s - """, - (qc.lot_line_id.id if qc.lot_line_id else None, qc.id, current_state) - ) - # Invalidate cache for lot_id only - qc.invalidate_recordset(['lot_id']) - else: - # If state is 'none', use normal assignment - qc.lot_id = qc.lot_line_id - else: - # For non-receipt operations, use standard behavior - qc.lot_id = qc.lot_line_id + # Update lot_ids (ORM handles Many2many) + qc.lot_ids = [Command.set([qc.lot_line_id.id])] def _update_lot_from_lot_line(self): """ @@ -164,7 +179,7 @@ class QualityCheck(models.Model): def _update_lot_from_move_line_manual(self, lot_id): """ - Manually update the lot_id field while preserving the current quality check state. + Manually update the lot_ids field while preserving the current quality check state. This method is called from stock.move.line when a lot number is assigned or changed on receipt operations. @@ -173,28 +188,13 @@ class QualityCheck(models.Model): """ self.ensure_one() - # Store the current quality state before updating lot_id - current_state = self.quality_state - current_user = self.user_id - current_control_date = self.control_date + # Update lot_ids. The write override will handle state preservation. + vals = {'lot_ids': [Command.set([lot_id])] if lot_id else [Command.clear()]} - # Use context flag to preserve state during write - self.with_context(quality_check_preserve_state=True).sudo().write({'lot_id': lot_id}) + # Use context flag to preserve state during write (though write logic checks _should_preserve_state) + self.with_context(quality_check_preserve_state=True).sudo().write(vals) - # Force restore the quality state if it was changed during the write - if current_state != 'none': - # Use direct SQL update to avoid triggering any compute methods - self.env.cr.execute( - """ - UPDATE quality_check - SET quality_state = %s, user_id = %s, control_date = %s - WHERE id = %s - """, - (current_state, current_user.id if current_user else None, - current_control_date, self.id) - ) - # Invalidate cache to ensure the updated values are reflected - self.invalidate_recordset(['quality_state', 'user_id', 'control_date']) + # Redundant SQL restore removed as write() already handles it. def _is_to_do(self, checkable_products, check_picked=False): """