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
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							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
							 | 
						|
								
							 |