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.
 
 
 
 
 

138 lines
6.5 KiB

# -*- coding: utf-8 -*-
from odoo import api, fields, models,_
from odoo.tools.float_utils import float_compare
from odoo.exceptions import UserError
class StockPicking(models.Model):
_inherit = "stock.picking"
@api.depends('move_lines')
def _compute_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)
@api.multi
def quality_alert_action(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], [])
# choose the view_mode accordingly
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_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_alert', string='Quality Alerts', default=0)
alert_ids = fields.Many2many('quality.alert', compute='_compute_alert', string='Quality Alerts', copy=False)
@api.multi
def generate_quality_alert(self):
'''
This function generates quality alerts for the products mentioned in move_lines of 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_lines:
measures = quality_measure.search([('product_id', '=', move.product_id.id), ('trigger_time', '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,
})
@api.multi
def action_confirm(self):
if self.alert_count == 0:
self.generate_quality_alert()
res = super(StockPicking, self).action_confirm()
return res
@api.multi
def force_assign(self):
if self.alert_count == 0:
self.generate_quality_alert()
res = super(StockPicking, self).force_assign()
return res
@api.multi
def do_transfer(self):
""" If no pack operation, we do simple action_done of the picking.
Otherwise, do the pack operations. """
# TDE CLEAN ME: reclean me, please
self._create_lots_for_picking()
no_pack_op_pickings = self.filtered(lambda picking: not picking.pack_operation_ids)
no_pack_op_pickings.action_done()
other_pickings = self - no_pack_op_pickings
for picking in other_pickings:
need_rereserve, all_op_processed = picking.picking_recompute_remaining_quantities()
todo_moves = self.env['stock.move']
toassign_moves = self.env['stock.move']
# create extra moves in the picking (unexpected product moves coming from pack operations)
if not all_op_processed:
todo_moves |= picking._create_extra_moves()
if need_rereserve or not all_op_processed:
moves_reassign = any(x.origin_returned_move_id or x.move_orig_ids for x in picking.move_lines if
x.state not in ['done', 'cancel'])
if moves_reassign and picking.location_id.usage not in ("supplier", "production", "inventory"):
# unnecessary to assign other quants than those involved with pack operations as they will be unreserved anyways.
picking.with_context(reserve_only_ops=True, no_state_change=True).rereserve_quants(
move_ids=picking.move_lines.ids)
picking.do_recompute_remaining_quantities()
# split move lines if needed
for move in picking.move_lines:
rounding = move.product_id.uom_id.rounding
remaining_qty = move.remaining_qty
if move.state in ('done', 'cancel'):
# ignore stock moves cancelled or already done
continue
elif move.state == 'draft':
toassign_moves |= move
if float_compare(remaining_qty, 0, precision_rounding=rounding) == 0:
if move.state in ('draft', 'assigned', 'confirmed'):
todo_moves |= move
elif float_compare(remaining_qty, 0, precision_rounding=rounding) > 0 and float_compare(remaining_qty, move.product_qty, precision_rounding=rounding) < 0:
# TDE FIXME: shoudl probably return a move - check for no track key, by the way
new_move_id = move.split(remaining_qty)
new_move = self.env['stock.move'].with_context(mail_notrack=True).browse(new_move_id)
todo_moves |= move
# Assign move as it was assigned before
toassign_moves |= new_move
# TDE FIXME: do_only_split does not seem used anymore
if todo_moves and not self.env.context.get('do_only_split'):
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()
elif self.env.context.get('do_only_split'):
picking = picking.with_context(split=todo_moves.ids)
picking._create_backorder()
return True