You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
6.4 KiB
147 lines
6.4 KiB
# -*- coding: utf-8 -*-
|
|
###############################################################################
|
|
#
|
|
# Cybrosys Technologies Pvt. Ltd.
|
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<http://www.cybrosys.com>).
|
|
# Author: Dhanya B(<https://www.cybrosys.com>)
|
|
#
|
|
# This program is free software: you can modify
|
|
# it under the terms of the GNU Affero General Public License (AGPL) as
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
###############################################################################
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class StockPicking(models.Model):
|
|
_inherit = "stock.picking"
|
|
|
|
@api.depends('move_ids')
|
|
def _compute_quality_alert(self):
|
|
'''
|
|
This function computes the number of
|
|
quality alerts generated from given picking.
|
|
'''
|
|
for picking in self:
|
|
alerts = self.env['quality.alert'].search(
|
|
[('picking_id', '=', picking.id)])
|
|
picking.alert_ids = alerts
|
|
picking.alert_count = len(alerts)
|
|
|
|
def action_quality_alert(self):
|
|
"""This function returns an action that
|
|
display existing quality alerts generated
|
|
from a given picking."""
|
|
action = self.env.ref('quality_assurance.quality_alert_action')
|
|
result = action.read()[0]
|
|
# override the context to get rid of the default filtering on picking type
|
|
result.pop('id', None)
|
|
result['context'] = {}
|
|
alert_ids = sum([picking.alert_ids.ids for picking in self], [])
|
|
if len(alert_ids) > 1:
|
|
result['domain'] = "[('id','in',[" + ','.join(
|
|
map(str, alert_ids)) + "])]"
|
|
elif len(alert_ids) == 1:
|
|
res = self.env.ref('quality_assurance.quality_alert_view_form',
|
|
False)
|
|
result['views'] = [(res and res.id or False, 'form')]
|
|
result['res_id'] = alert_ids and alert_ids[0] or False
|
|
return result
|
|
|
|
alert_count = fields.Integer(compute='_compute_quality_alert',
|
|
string='Quality Alerts', default=0)
|
|
alert_ids = fields.Many2many('quality.alert',
|
|
compute='_compute_quality_alert',
|
|
string='Quality Alerts', copy=False)
|
|
|
|
def generate_quality_alert(self):
|
|
"""
|
|
This function generates quality alerts for the products mentioned in
|
|
`move_ids` of the given picking and also have quality measures configured.
|
|
"""
|
|
quality_alert = self.env['quality.alert']
|
|
quality_measure = self.env['quality.measure']
|
|
for move in self.move_ids:
|
|
measures = quality_measure.search([
|
|
('product_id', '=', move.product_id.id),
|
|
('picking_type_ids', 'in', self.picking_type_id.id)
|
|
])
|
|
if measures:
|
|
quality_alert.create({
|
|
'name': self.env['ir.sequence'].next_by_code(
|
|
'quality.alert') or _('New'),
|
|
'product_id': move.product_id.id,
|
|
'picking_id': self.id,
|
|
'origin': self.name,
|
|
'company_id': self.company_id.id,
|
|
})
|
|
|
|
def action_confirm(self):
|
|
"""If `alert_count` is zero, it triggers the `generate_quality_alert` method
|
|
before proceeding with the standard `action_confirm` behavior."""
|
|
if self.alert_count == 0:
|
|
self.generate_quality_alert()
|
|
return super(StockPicking, self).action_confirm()
|
|
|
|
def force_assign(self):
|
|
"""Forces the assignment of stock picking.
|
|
If `alert_count` is zero, it triggers the `generate_quality_alert` method
|
|
before proceeding with the standard `force_assign` behavior.
|
|
"""
|
|
if self.alert_count == 0:
|
|
self.generate_quality_alert()
|
|
return super(StockPicking, self).force_assign()
|
|
|
|
def _action_done(self):
|
|
"""Changes picking state to done by processing the Stock Moves of
|
|
the Picking
|
|
Normally that happens when the button "Done" is pressed on a
|
|
Picking view.
|
|
@return: True
|
|
"""
|
|
todo_moves = self.mapped('move_ids').filtered(
|
|
lambda self: self.state in ['draft', 'partially_available',
|
|
'assigned', 'confirmed'])
|
|
# Check if there are ops not linked to moves yet
|
|
for pick in self:
|
|
for ops in pick.move_line_ids.filtered(lambda x: not x.move_id):
|
|
# Search move with this product
|
|
moves = pick.move_ids.filtered(
|
|
lambda x: x.product_id == ops.product_id)
|
|
if moves:
|
|
ops.move_id = moves[0].id
|
|
else:
|
|
new_move = self.env['stock.move'].create({
|
|
'name': _('New Move:') + ops.product_id.display_name,
|
|
'product_id': ops.product_id.id,
|
|
'product_uom_qty': ops.qty_done,
|
|
'product_uom': ops.product_uom_id.id,
|
|
'location_id': pick.location_id.id,
|
|
'location_dest_id': pick.location_dest_id.id,
|
|
'picking_id': pick.id,
|
|
})
|
|
ops.move_id = new_move.id
|
|
new_move._action_confirm()
|
|
todo_moves |= new_move
|
|
for move in todo_moves:
|
|
alerts = self.env['quality.alert'].search(
|
|
[('picking_id', '=', self.id),
|
|
('product_id', '=', move.product_id.id)])
|
|
for alert in alerts:
|
|
if alert.final_status == 'wait':
|
|
raise UserError(_('There are items still in quality test'))
|
|
if alert.final_status == 'fail':
|
|
raise UserError(_('There are items failed in quality test'))
|
|
todo_moves._action_done()
|
|
self.write({'date_done': fields.Datetime.now()})
|
|
return True
|
|
|