198 lines
8.4 KiB
Python
198 lines
8.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from odoo import models, api, fields
|
|
|
|
|
|
class QualityCheck(models.Model):
|
|
_inherit = 'quality.check'
|
|
|
|
# Add a context flag to track when we're preserving state
|
|
_preserve_state_context_key = 'quality_check_preserve_state'
|
|
|
|
def _is_receipt_operation(self):
|
|
"""
|
|
Check if the current quality check is part of a receipt operation.
|
|
Receipt operations are identified by picking_type_code == 'incoming'.
|
|
|
|
This method implements robust operation type identification with multiple
|
|
fallback paths to ensure reliable detection across different scenarios.
|
|
|
|
Returns:
|
|
bool: True if this is a receipt operation, False otherwise
|
|
"""
|
|
self.ensure_one()
|
|
|
|
# Primary check: picking_type_code through the picking
|
|
if self.picking_id and self.picking_id.picking_type_id:
|
|
return self.picking_id.picking_type_id.code == 'incoming'
|
|
|
|
# Fallback 1: check through move_line_id if picking_id is not available
|
|
if self.move_line_id:
|
|
if self.move_line_id.picking_id and self.move_line_id.picking_id.picking_type_id:
|
|
return self.move_line_id.picking_id.picking_type_id.code == 'incoming'
|
|
|
|
# Fallback 2: check through move_id.picking_type_id
|
|
if self.move_line_id.move_id and self.move_line_id.move_id.picking_type_id:
|
|
return self.move_line_id.move_id.picking_type_id.code == 'incoming'
|
|
|
|
# Fallback 3: check through move_id if available
|
|
if hasattr(self, 'move_id') and self.move_id and self.move_id.picking_type_id:
|
|
return self.move_id.picking_type_id.code == 'incoming'
|
|
|
|
# Default: not a receipt operation if we can't determine the type
|
|
return False
|
|
|
|
def _should_preserve_state(self):
|
|
"""
|
|
Determine if the quality check state should be preserved during lot assignment.
|
|
State preservation applies only to receipt operations.
|
|
|
|
Returns:
|
|
bool: True if state should be preserved, False otherwise
|
|
"""
|
|
self.ensure_one()
|
|
return self._is_receipt_operation()
|
|
|
|
def write(self, vals):
|
|
"""
|
|
Override write to prevent state reset when lot_id is updated on receipt operations.
|
|
"""
|
|
# Store current states before write for receipt operations
|
|
state_data = {}
|
|
for record in self:
|
|
if record._should_preserve_state() and record.quality_state != 'none':
|
|
# Only preserve if we're not explicitly changing the quality_state
|
|
if 'quality_state' not in vals:
|
|
state_data[record.id] = {
|
|
'quality_state': record.quality_state,
|
|
'user_id': record.user_id.id if record.user_id else False,
|
|
'control_date': record.control_date,
|
|
}
|
|
|
|
# Perform the write
|
|
result = super(QualityCheck, self).write(vals)
|
|
|
|
# Restore states if they were changed
|
|
if state_data:
|
|
for record in self:
|
|
if record.id in state_data:
|
|
stored = state_data[record.id]
|
|
if record.quality_state != stored['quality_state']:
|
|
# Use SQL to restore state without triggering write again
|
|
self.env.cr.execute(
|
|
"""
|
|
UPDATE quality_check
|
|
SET quality_state = %s, user_id = %s, control_date = %s
|
|
WHERE id = %s
|
|
""",
|
|
(stored['quality_state'], stored['user_id'],
|
|
stored['control_date'], record.id)
|
|
)
|
|
record.invalidate_recordset(['quality_state', 'user_id', 'control_date'])
|
|
|
|
return result
|
|
|
|
@api.depends('move_line_id.lot_id')
|
|
def _compute_lot_line_id(self):
|
|
"""
|
|
Override the compute method to preserve quality check state during lot updates.
|
|
This prevents the state from being reset when lot numbers are assigned.
|
|
"""
|
|
for qc in self:
|
|
# Always update lot_line_id
|
|
qc.lot_line_id = qc.move_line_id.lot_id
|
|
|
|
# Check if we should update lot_id
|
|
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
|
|
|
|
def _update_lot_from_lot_line(self):
|
|
"""
|
|
Override the standard method from quality_control module.
|
|
This method is called by _compute_lot_line_id to determine if the lot_id
|
|
should be automatically updated from the move_line_id.lot_id.
|
|
|
|
For receipt operations, we return True to allow the update, but we handle
|
|
state preservation in the overridden _compute_lot_line_id method.
|
|
|
|
For non-receipt operations, we preserve standard Odoo behavior.
|
|
|
|
Returns:
|
|
bool: True to allow lot update (state preservation handled separately)
|
|
"""
|
|
self.ensure_one()
|
|
|
|
# Always return True to allow lot updates
|
|
# State preservation is handled in _compute_lot_line_id
|
|
return super(QualityCheck, self)._update_lot_from_lot_line()
|
|
|
|
def _check_to_unlink(self):
|
|
"""
|
|
Override to prevent deletion of completed quality checks on receipt operations.
|
|
"""
|
|
self.ensure_one()
|
|
|
|
# For receipt operations with completed quality checks, prevent deletion
|
|
if self._should_preserve_state() and self.quality_state != 'none':
|
|
return False
|
|
|
|
# For other cases, use standard behavior
|
|
return super(QualityCheck, self)._check_to_unlink()
|
|
|
|
def _update_lot_from_move_line_manual(self, lot_id):
|
|
"""
|
|
Manually update the lot_id 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.
|
|
|
|
Args:
|
|
lot_id: The ID of the lot to assign (or False to clear)
|
|
"""
|
|
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
|
|
|
|
# Use context flag to preserve state during write
|
|
self.with_context(quality_check_preserve_state=True).sudo().write({'lot_id': lot_id})
|
|
|
|
# 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'])
|