Best Python code snippet using fMBT_python
stock_move.py
Source:stock_move.py  
...957            'picking_id': self.picking_id.id,958            'price_unit': self.price_unit,959        }960        return vals961    def _create_extra_move(self):962        """ If the quantity done on a move exceeds its quantity todo, this method will create an963        extra move attached to a (potentially split) move line. If the previous condition is not964        met, it'll return an empty recordset.965        966        The rationale for the creation of an extra move is the application of a potential push967        rule that will handle the extra quantities.968        """969        extra_move = self970        rounding = self.product_uom.rounding971        # moves created after the picking is assigned do not have `product_uom_qty`, but we shouldn't create extra moves for them972        if float_compare(self.quantity_done, self.product_uom_qty, precision_rounding=rounding) > 0:973            # create the extra moves974            extra_move_quantity = float_round(975                self.quantity_done - self.product_uom_qty,976                precision_rounding=rounding,977                rounding_method='HALF-UP')978            extra_move_vals = self._prepare_extra_move_vals(extra_move_quantity)979            extra_move = self.copy(default=extra_move_vals)980            if extra_move.picking_id:981                extra_move = extra_move._action_confirm(merge_into=self)982            else:983                extra_move = extra_move._action_confirm()984            # link it to some move lines. We don't need to do it for move since they should be merged.985            if self.exists() and not self.picking_id:986                for move_line in self.move_line_ids.filtered(lambda ml: ml.qty_done):987                    if float_compare(move_line.qty_done, extra_move_quantity, precision_rounding=rounding) <= 0:988                        # move this move line to our extra move989                        move_line.move_id = extra_move.id990                        extra_move_quantity -= move_line.qty_done991                    else:992                        # split this move line and assign the new part to our extra move993                        quantity_split = float_round(994                            move_line.qty_done - extra_move_quantity,995                            precision_rounding=self.product_uom.rounding,996                            rounding_method='UP')997                        move_line.qty_done = quantity_split998                        move_line.copy(default={'move_id': extra_move.id, 'qty_done': extra_move_quantity, 'product_uom_qty': 0})999                        extra_move_quantity -= extra_move_quantity1000                    if extra_move_quantity == 0.0:1001                        break1002        return extra_move1003    def _unreserve_initial_demand(self, new_move):1004        pass1005    def _action_done(self):1006        self.filtered(lambda move: move.state == 'draft')._action_confirm()  # MRP allows scrapping draft moves1007        moves = self.exists().filtered(lambda x: x.state not in ('done', 'cancel'))1008        moves_todo = self.env['stock.move']1009        # Cancel moves where necessary ; we should do it before creating the extra moves because1010        # this operation could trigger a merge of moves.1011        for move in moves:1012            if move.quantity_done <= 0:1013                if float_compare(move.product_uom_qty, 0.0, precision_rounding=move.product_uom.rounding) == 0:1014                    move._action_cancel()1015        # Create extra moves where necessary1016        for move in moves:1017            if move.state == 'cancel' or move.quantity_done <= 0:1018                continue1019            # extra move will not be merged in mrp1020            if not move.picking_id:1021                moves_todo |= move1022            moves_todo |= move._create_extra_move()1023        # Split moves where necessary and move quants1024        for move in moves_todo:1025            # To know whether we need to create a backorder or not, round to the general product's1026            # decimal precision and not the product's UOM.1027            rounding = self.env['decimal.precision'].precision_get('Product Unit of Measure')1028            if float_compare(move.quantity_done, move.product_uom_qty, precision_digits=rounding) < 0:1029                # Need to do some kind of conversion here1030                qty_split = move.product_uom._compute_quantity(move.product_uom_qty - move.quantity_done, move.product_id.uom_id, rounding_method='HALF-UP')1031                new_move = move._split(qty_split)1032                for move_line in move.move_line_ids:1033                    if move_line.product_qty and move_line.qty_done:1034                        # FIXME: there will be an issue if the move was partially available1035                        # By decreasing `product_qty`, we free the reservation.1036                        # FIXME: if qty_done > product_qty, this could raise if nothing is in stock...ChessEngine.py
Source:ChessEngine.py  
...200							if moves[i].isEnpassantMove:201								capturedcol = moves[i].endCol202								capturedrow = moves[i].endRow+1 if self.whitetoMove else moves[i].endRow-1203								if not (capturedrow,capturedcol) in validSquares:204									moves.remove(moves[i])205							else:206								moves.remove(moves[i]) 207			else: #double check208				self.getKingMoves(kingRow,kingCol,moves)209		else: #not in check, so all moves are fine210			moves = self.getAllPossibleMoves()211212		if len(moves) == 0:213			if self.inCheck:214				self.checkMate = True215			else:216				self.staleMate = True217		else:218			self.checkMate = False219			self.staleMate = False220		221		return moves # Not gonna worry about chccks/pins right now222	223	224	'''225	All Moves without considering checks226	'''227	def getAllPossibleMoves(self):228		moves = []229		for r in range(len(self.board)): # Number of rows230			for c in range(len(self.board[r])): # Number of columns in giving row231				turn = self.board[r][c][0]232				if (turn == 'w' and self.whitetoMove) or (turn == 'b' and not self.whitetoMove):233					piece = self.board[r][c][1]234					self.moveFunctions[piece](r,c,moves) # call the appropriate move function based on the piece type235		return moves236237	'''238	Get all the pawn moves for the pawn located at row, col and add moves to list239	'''240	def getPawnMoves(self, r, c, moves):241		piecePinned = False242		pinDirection = ()243		for i in range(len(self.pins)-1,-1,-1):244			if self.pins[i][0] == r and self.pins[i][1] == c:245				piecePinned = True246				pinDirection = (self.pins[i][2],self.pins[i][3])247				self.pins.remove(self.pins[i])248				break249250		if self.whitetoMove:251			moveAmount  = -1252			startRow = 6253			enemyColor = 'b'254			kingRow,kingCol = self.whiteKingLocation255		else:256			moveAmount= 1257			startRow = 1258			enemyColor = 'w'259			kingRow,kingCol = self.blackKingLocation260261		if self.board[r+moveAmount][c] == "--": # 1 square move262			if not piecePinned or pinDirection == (moveAmount,0):263				moves.append(Move((r,c),(r+moveAmount,c),self.board))264				if r==startRow and self.board[r+2*moveAmount][c] == "--":265					moves.append(Move((r,c),(r+2*moveAmount,c),self.board))266		# captures267		if c-1 >=0 : # capture to the left268			if not piecePinned or pinDirection == (moveAmount,-1):269				if self.board[r+moveAmount][c-1][0] == enemyColor:270					moves.append(Move((r,c),(r+moveAmount,c-1),self.board))271				if (r+moveAmount,c-1) == self.enpassantPossible:272					attackingPiece = blockingPiece = False273					if kingRow == r:274						if kingCol < c: #king is left of the pawn275							# inside btw king and pawn: outside range btw pawn order276							insideRange = range(kingCol+1,c-1)277							outsideRange = range(c+1,8)278						else: # king is right of the pawn279							insideRange = range(kingCol-1,c,-1)280							outsideRange = range(c-2,-1,-1)281282						for i in insideRange:283							if self.board[r][i] != "--": #some other piece, beside the en-passant pawn, blocks284								blockingPiece = True285						for i in outsideRange:286							square = self.board[r][i]287							if square[0] == enemyColor and (square[1]=='R' or square[1] == 'Q'):288								attackingPiece = True289							elif square != "--":290								blockingPiece = True291					292					if not attackingPiece or blockingPiece:293						moves.append(Move((r,c),(r+moveAmount,c-1),self.board,isEnpassantMove=True))294295		if c+1 <= 7:296			if not piecePinned or pinDirection == (moveAmount,1):297				if self.board[r+moveAmount][c+1][0] == enemyColor:298					moves.append(Move((r,c),(r+moveAmount,c+1),self.board))299				if (r+moveAmount,c+1) == self.enpassantPossible:300					attackingPiece = blockingPiece = False301					if kingRow == r:302						if kingCol < c: #king is left of the pawn303							# inside btw king and pawn: outside range btw pawn order304							insideRange = range(kingCol+1,c)305							outsideRange = range(c+2,8)306						else: # king is right of the pawn307							insideRange = range(kingCol-1,c+1,-1)308							outsideRange = range(c-1,-1,-1)309310						for i in insideRange:311							if self.board[r][i] != "--": #some other piece, beside the en-passant pawn, blocks312								blockingPiece = True313						for i in outsideRange:314							square = self.board[r][i]315							if square[0] == enemyColor and (square[1]=='R' or square[1] == 'Q'):316								attackingPiece = True317							elif square != "--":318								blockingPiece = True319					320					if not attackingPiece or blockingPiece:321						moves.append(Move((r,c),(r+moveAmount,c+1),self.board,isEnpassantMove=True))322		#add pawn promotion later323324325	# Get Rook Moves326	def getRookMoves(self, r, c, moves):327		piecePinned = False328		pinDirection = ()329		for i in range(len(self.pins)-1,-1,-1):330			if self.pins[i][0] == r and self.pins[i][1] == c:331				piecePinned = True332				pinDirection = (self.pins[i][2],self.pins[i][3])333				if self.board[r][c][1] != 'Q':334					self.pins.remove(self.pins[i])335				break336337		directions = ((-1,0),(0,-1),(1,0),(0,1)) #up,left,down,right338		enemyColor = "b" if self.whitetoMove else "w"339		for d in directions:340			for i in range(1,8):341				endRow = r + d[0]*i;342				endCol = c + d[1]*i;343				if 0 <= endRow < 8 and 0 <= endCol < 8: #on board344					if not piecePinned or pinDirection == d or pinDirection == (-d[0],-d[1]):345						endPiece = self.board[endRow][endCol]346						if endPiece == "--": # empty space, valid347							moves.append(Move((r,c),(endRow,endCol),self.board))348						elif endPiece[0] == enemyColor: # enemy piece349							moves.append(Move((r,c),(endRow,endCol),self.board))350							break351						else: # same color piece352							break353				else: #off board354					break355356	# Get Knight Moves357	def getKnightMoves(self, r, c, moves):358		piecePinned = False359		for i in range(len(self.pins)-1,-1,-1):360			if self.pins[i][0] == r and self.pins[i][1] == c:361				piecePinned = True362				self.pins.remove(self.pins[i])363				break364365		KnightMoves = ((-2,-1),(-2,1),(-1,-2),(-1,2),(1,-2),(1,2),(2,-1),(2,1))366		allyColor = "w" if self.whitetoMove else "b"367		for m in KnightMoves:368			endRow = r + m[0]369			endCol = c + m[1]370			if 0 <= endRow < 8 and 0 <=endCol < 8:371				if not piecePinned:372					endPiece = self.board[endRow][endCol]373					if endPiece[0] != allyColor:374						moves.append(Move((r,c),(endRow,endCol),self.board))375		376377	def getBishopMoves(self, r, c, moves):378		piecePinned = False379		pinDirection = ()380		for i in range(len(self.pins)-1,-1,-1):381			if self.pins[i][0] == r and self.pins[i][1] == c:382				piecePinned = True383				pinDirection = (self.pins[i][2],self.pins[i][3])384				self.pins.remove(self.pins[i])385				break386387		directions = ((-1,-1),(-1,1),(1,-1),(1,1))388		enemyColor = "b" if self.whitetoMove else "w"389		for d in directions:390			for i in range(1,8):391				endRow = r + d[0]*i;392				endCol = c + d[1]*i;393				if 0 <= endRow < 8 and 0 <= endCol < 8: #on board394					if not piecePinned or pinDirection == d or pinDirection == (-d[0],-d[1]):395						endPiece = self.board[endRow][endCol]396						if endPiece == "--": # empty space, valid397							moves.append(Move((r,c),(endRow,endCol),self.board))398						elif endPiece[0] == enemyColor: # enemy piece
...stock_traceability.py
Source:stock_traceability.py  
...147    def _quantity_to_str(self, from_uom, to_uom, qty):148        """ workaround to apply the float rounding logic of t-esc on data prepared server side """149        qty = from_uom._compute_quantity(qty, to_uom, rounding_method='HALF-UP')150        return self.env['ir.qweb.field.float'].value_to_html(qty, {'decimal_precision': 'Product Unit of Measure'})151    def make_dict_move(self, level, parent_id, move_line, stream=False, unfoldable=False):152        res_model, res_id, ref = self.get_links(move_line)153        data = [{154            'level': level,155            'unfoldable': unfoldable,156            'date': move_line.move_id.date,157            'parent_id': parent_id,158            'model_id': move_line.id,159            'model':'stock.move.line',160            'product_id': move_line.product_id.display_name,161            'product_qty_uom': "%s %s" % (self._quantity_to_str(move_line.product_uom_id, move_line.product_id.uom_id, move_line.qty_done), move_line.product_id.uom_id.name),162            'location': move_line.location_id.name + ' -> ' + move_line.location_dest_id.name,163            'reference_id': ref,164            'res_id': res_id,165            'stream': stream,166            'res_model': res_model}]167        return data168    def make_dict_head(self, level, parent_id, model=False, stream=False, move_line=False):169        data = []170        if model == 'stock.move.line':171            data = [{172                'level': level,173                'unfoldable': True,174                'date': move_line.move_id.date,175                'model_id': move_line.id,176                'parent_id': parent_id,177                'model': model or 'stock.move.line',178                'product_id': move_line.product_id.display_name,179                'lot_id': move_line.lot_id.name,180                'product_qty_uom': "%s %s" % (self._quantity_to_str(move_line.product_uom_id, move_line.product_id.uom_id, move_line.qty_done), move_line.product_id.uom_id.name),181                'location': move_line.location_dest_id.name,182                'stream': stream,183                'reference_id': False}]184        elif model == 'stock.quant':185            data = [{186                'level': level,187                'unfoldable': True,188                'date': move_line.write_date,189                'model_id': move_line.id,190                'parent_id': parent_id,191                'model': model or 'stock.quant',192                'product_id': move_line.product_id.display_name,193                'lot_id': move_line.lot_id.name,194                'product_qty_uom': "%s %s" % (self._quantity_to_str(move_line.product_uom_id, move_line.product_id.uom_id, move_line.quantity), move_line.product_id.uom_id.name),195                'location': move_line.location_id.name,196                'stream': stream,197                'reference_id': False}]198        return data199    @api.model200    def upstream_traceability(self, level, stream=False, line_id=False, model=False, model_obj=False, parent_quant=False):201        final_vals =[]202        if model == 'stock.move.line':203            moves = self.get_move_lines_upstream(model_obj)204        elif model == 'stock.quant':205            moves = self.env['stock.move.line'].search([206                ('location_dest_id', '=', model_obj.location_id.id),207                ('lot_id', '=', model_obj.lot_id.id),208                ('date', '<=', model_obj.write_date),209                ('state', '=', 'done'),210            ])211            moves |= self.get_move_lines_upstream(moves)212        for move in moves:213            unfoldable = False214            if move.consume_line_ids:215                unfoldable = True216            final_vals += self.make_dict_move(level, stream=stream, parent_id=line_id, move_line=move, unfoldable=unfoldable)217        return final_vals218    @api.model219    def downstream_traceability(self, level, stream=False, line_id=False, model=False, model_obj=False, parent_quant=False):220        final_vals = []221        if model == 'stock.move.line':222            moves = self.get_move_lines_downstream(model_obj)223        elif model == 'stock.quant':224            moves = self.env['stock.move.line'].search([225                ('location_id', '=', model_obj.location_id.id),226                ('lot_id', '=', model_obj.lot_id.id),227                ('date', '>=', model_obj.write_date),228                ('state', '=', 'done'),229            ])230            moves |= self.get_move_lines_downstream(moves)231        for move in moves:232            unfoldable = False233            if move.produce_line_ids:234                unfoldable = True235            final_vals += self.make_dict_move(level, stream=stream, parent_id=line_id, move_line=move, unfoldable=unfoldable)236        return final_vals237    @api.model238    def final_vals_to_lines(self, final_vals, level):239        lines = []240        for data in final_vals:241            lines.append({242                'id': autoIncrement(),243                'model': data['model'],244                'model_id': data['model_id'],245                'stream': data['stream'] or 'upstream',246                'parent_id': data['parent_id'],247                'parent_quant': data.get('parent_quant', False),248                'type': 'line',249                'reference': data.get('reference_id', False),250                'res_id': data.get('res_id', False),251                'res_model': data.get('res_model', False),252                'name': _(data.get('lot_id', False)),253                'columns': [data.get('reference_id', False) or data.get('product_id', False),254                            data.get('lot_id', False),255                            data.get('date', False),256                            data.get('product_qty_uom', 0),257                            data.get('location', False)],258                'level': level,259                'unfoldable': data['unfoldable'],260            })261        return lines262    @api.model263    def _lines(self, line_id=None, model_id=False, model=False, level=0, parent_quant=False, stream=False, obj_ids=[], **kw):264        final_vals = []265        if model and line_id:266            model_obj = self.env[model].browse(model_id)267            if stream == "downstream":268                final_vals += self.downstream_traceability(level, stream='downstream', line_id=line_id, model=model, model_obj=model_obj, parent_quant=parent_quant)269                if model == 'stock.move.line':270                    if model_obj.produce_line_ids:271                        final_vals += self.get_produced_or_consumed_vals(model_obj.produce_line_ids, level, model=model, stream=stream, parent_id=line_id)272                    else:273                        final_vals = self.make_dict_move(level, stream=stream, parent_id=line_id,move_line=model_obj) + final_vals274            else:275                final_vals += self.upstream_traceability(level, stream='upstream', line_id=line_id, model=model, model_obj=model_obj, parent_quant=parent_quant)276                if model == 'stock.move.line':277                    if model_obj.consume_line_ids:278                        final_vals += self.get_produced_or_consumed_vals(model_obj.consume_line_ids, level, model=model, stream=stream, parent_id=line_id)279                    else:280                        final_vals = self.make_dict_move(level, stream=stream, parent_id=line_id, move_line=model_obj) + final_vals281        else:282            for move_line in obj_ids:283                final_vals += self.make_dict_head(level, stream=stream, parent_id=line_id, model=model or 'stock.pack.operation', move_line=move_line)284        return final_vals285    @api.model286    def get_produced_or_consumed_vals(self, move_lines, level, model, stream, parent_id):287        final_vals = []288        for line in move_lines:289            final_vals += self.make_dict_head(level, model=model, stream=stream, parent_id=parent_id, move_line=line)290        return final_vals291    def get_pdf_lines(self, line_data=[]):292        final_vals = []293        lines = []294        for line in line_data:295            model = self.env[line['model_name']].browse(line['model_id'])296            if line.get('unfoldable'):297                    final_vals += self.make_dict_head(line['level'], model=line['model_name'], parent_id=line['id'], move_line=model)298            else:299                if line['model_name'] == 'stock.move.line':300                    final_vals += self.make_dict_move(line['level'], parent_id=line['id'], move_line=model)301        for data in final_vals:302            lines.append({303                'id': autoIncrement(),304                'model': data['model'],305                'model_id': data['model_id'],306                'parent_id': data['parent_id'],307                'stream': "%s" % (data['stream']),308                'type': 'line',309                'name': _(data.get('lot_id')),310                'columns': [data.get('reference_id') or data.get('product_id'),311                            data.get('lot_id'),312                            data.get('date'),313                            data.get('product_qty_uom', 0),314                            data.get('location')],...mrp_product_produce.py
Source:mrp_product_produce.py  
1# -*- coding: utf-8 -*-2# Part of Odoo. See LICENSE file for full copyright and licensing details.3from collections import Counter4from datetime import datetime5from odoo import api, fields, models, _6from odoo.addons import decimal_precision as dp7from odoo.exceptions import UserError, ValidationError8from odoo.tools import float_compare, float_round9class MrpProductProduce(models.TransientModel):10    _name = "mrp.product.produce"11    _description = "Record Production"12    @api.model13    def default_get(self, fields):14        res = super(MrpProductProduce, self).default_get(fields)15        if self._context and self._context.get('active_id'):16            production = self.env['mrp.production'].browse(self._context['active_id'])17            serial_finished = (production.product_id.tracking == 'serial')18            if serial_finished:19                todo_quantity = 1.020            else:21                main_product_moves = production.move_finished_ids.filtered(lambda x: x.product_id.id == production.product_id.id)22                todo_quantity = production.product_qty - sum(main_product_moves.mapped('quantity_done'))23                todo_quantity = todo_quantity if (todo_quantity > 0) else 024            if 'production_id' in fields:25                res['production_id'] = production.id26            if 'product_id' in fields:27                res['product_id'] = production.product_id.id28            if 'product_uom_id' in fields:29                res['product_uom_id'] = production.product_uom_id.id30            if 'serial' in fields:31                res['serial'] = bool(serial_finished)32            if 'product_qty' in fields:33                res['product_qty'] = todo_quantity34            if 'produce_line_ids' in fields:35                lines = []36                for move in production.move_raw_ids.filtered(lambda x: (x.product_id.tracking != 'none') and x.state not in ('done', 'cancel') and x.bom_line_id):37                    qty_to_consume = float_round(todo_quantity / move.bom_line_id.bom_id.product_qty * move.bom_line_id.product_qty,38                                                 precision_rounding=move.product_uom.rounding, rounding_method="UP")39                    for move_line in move.move_line_ids:40                        if float_compare(qty_to_consume, 0.0, precision_rounding=move.product_uom.rounding) <= 0:41                            break42                        if move_line.lot_produced_id or float_compare(move_line.product_uom_qty, move_line.qty_done, precision_rounding=move.product_uom.rounding) <= 0:43                            continue44                        to_consume_in_line = min(qty_to_consume, move_line.product_uom_qty)45                        lines.append({46                            'move_id': move.id,47                            'qty_to_consume': to_consume_in_line,48                            'qty_done': 0.0,49                            'lot_id': move_line.lot_id.id,50                            'product_uom_id': move.product_uom.id,51                            'product_id': move.product_id.id,52                        })53                        qty_to_consume -= to_consume_in_line54                    if float_compare(qty_to_consume, 0.0, precision_rounding=move.product_uom.rounding) > 0:55                        if move.product_id.tracking == 'serial':56                            while float_compare(qty_to_consume, 0.0, precision_rounding=move.product_uom.rounding) > 0:57                                lines.append({58                                    'move_id': move.id,59                                    'qty_to_consume': 1,60                                    'qty_done': 0.0,61                                    'product_uom_id': move.product_uom.id,62                                    'product_id': move.product_id.id,63                                })64                                qty_to_consume -= 165                        else:66                            lines.append({67                                'move_id': move.id,68                                'qty_to_consume': qty_to_consume,69                                'qty_done': 0.0,70                                'product_uom_id': move.product_uom.id,71                                'product_id': move.product_id.id,72                            })73                res['produce_line_ids'] = [(0, 0, x) for x in lines]74        return res75    serial = fields.Boolean('Requires Serial')76    production_id = fields.Many2one('mrp.production', 'Production')77    product_id = fields.Many2one('product.product', 'Product')78    product_qty = fields.Float(string='Quantity', digits=dp.get_precision('Product Unit of Measure'), required=True)79    product_uom_id = fields.Many2one('product.uom', 'Unit of Measure')80    lot_id = fields.Many2one('stock.production.lot', string='Lot')81    produce_line_ids = fields.One2many('mrp.product.produce.line', 'product_produce_id', string='Product to Track')82    product_tracking = fields.Selection(related="product_id.tracking")83    @api.multi84    def do_produce(self):85        # Nothing to do for lots since values are created using default data (stock.move.lots)86        quantity = self.product_qty87        if float_compare(quantity, 0, precision_rounding=self.product_uom_id.rounding) <= 0:88            raise UserError(_("The production order for '%s' has no quantity specified") % self.product_id.display_name)89        for move in self.production_id.move_raw_ids:90            # TODO currently not possible to guess if the user updated quantity by hand or automatically by the produce wizard.91            if move.product_id.tracking == 'none' and move.state not in ('done', 'cancel') and move.unit_factor:92                rounding = move.product_uom.rounding93                if self.product_id.tracking != 'none':94                    qty_to_add = float_round(quantity * move.unit_factor, precision_rounding=rounding)95                    move._generate_consumed_move_line(qty_to_add, self.lot_id)96                elif len(move._get_move_lines()) < 2:97                    move.quantity_done += float_round(quantity * move.unit_factor, precision_rounding=rounding)98                else:99                    move._set_quantity_done(quantity * move.unit_factor)100        for move in self.production_id.move_finished_ids:101            if move.product_id.tracking == 'none' and move.state not in ('done', 'cancel'):102                rounding = move.product_uom.rounding103                if move.product_id.id == self.production_id.product_id.id:104                    move.quantity_done += float_round(quantity, precision_rounding=rounding)105                elif move.unit_factor:106                    # byproducts handling107                    move.quantity_done += float_round(quantity * move.unit_factor, precision_rounding=rounding)108        self.check_finished_move_lots()109        if self.production_id.state == 'confirmed':110            self.production_id.write({111                'state': 'progress',112                'date_start': datetime.now(),113            })114        return {'type': 'ir.actions.act_window_close'}115    @api.multi116    def check_finished_move_lots(self):117        produce_move = self.production_id.move_finished_ids.filtered(lambda x: x.product_id == self.product_id and x.state not in ('done', 'cancel'))118        if produce_move and produce_move.product_id.tracking != 'none':119            if not self.lot_id:120                raise UserError(_('You need to provide a lot for the finished product'))121            existing_move_line = produce_move.move_line_ids.filtered(lambda x: x.lot_id == self.lot_id)122            if existing_move_line:123                if self.product_id.tracking == 'serial':124                    raise UserError(_('You cannot produce the same serial number twice.'))125                existing_move_line.product_uom_qty += self.product_qty126                existing_move_line.qty_done += self.product_qty127            else:128                vals = {129                  'move_id': produce_move.id,130                  'product_id': produce_move.product_id.id,131                  'production_id': self.production_id.id,132                  'product_uom_qty': self.product_qty,133                  'product_uom_id': produce_move.product_uom.id,134                  'qty_done': self.product_qty,135                  'lot_id': self.lot_id.id,136                  'location_id': produce_move.location_id.id,137                  'location_dest_id': produce_move.location_dest_id.id,138                }139                self.env['stock.move.line'].create(vals)140        for pl in self.produce_line_ids:141            if pl.qty_done:142                if not pl.lot_id:143                    raise UserError(_('Please enter a lot or serial number for %s !' % pl.product_id.name))144                if not pl.move_id:145                    # Find move_id that would match146                    move_id = self.production_id.move_raw_ids.filtered(lambda x: x.product_id == pl.product_id and x.state not in ('done', 'cancel'))147                    if move_id:148                        pl.move_id = move_id149                    else:150                        # create a move and put it in there151                        order = self.production_id152                        pl.move_id = self.env['stock.move'].create({153                                    'name': order.name,154                                    'product_id': pl.product_id.id,155                                    'product_uom': pl.product_uom_id.id,156                                    'location_id': order.location_src_id.id,157                                    'location_dest_id': self.product_id.property_stock_production.id,158                                    'raw_material_production_id': order.id,159                                    'group_id': order.procurement_group_id.id,160                                    'origin': order.name,161                                    'state': 'confirmed'})162                pl.move_id._generate_consumed_move_line(pl.qty_done, self.lot_id, lot=pl.lot_id)163        return True164class MrpProductProduceLine(models.TransientModel):165    _name = "mrp.product.produce.line"166    _description = "Record Production Line"167    product_produce_id = fields.Many2one('mrp.product.produce')168    product_id = fields.Many2one('product.product', 'Product')169    lot_id = fields.Many2one('stock.production.lot', 'Lot')170    qty_to_consume = fields.Float('To Consume', digits=dp.get_precision('Product Unit of Measure'))171    product_uom_id = fields.Many2one('product.uom', 'Unit of Measure')172    qty_done = fields.Float('Done', digits=dp.get_precision('Product Unit of Measure'))173    move_id = fields.Many2one('stock.move')174    @api.onchange('lot_id')175    def _onchange_lot_id(self):176        """ When the user is encoding a produce line for a tracked product, we apply some logic to177        help him. This onchange will automatically switch `qty_done` to 1.0.178        """179        res = {}180        if self.product_id.tracking == 'serial':181            self.qty_done = 1182        return res183    @api.onchange('qty_done')184    def _onchange_qty_done(self):185        """ When the user is encoding a produce line for a tracked product, we apply some logic to186        help him. This onchange will warn him if he set `qty_done` to a non-supported value.187        """188        res = {}189        if self.product_id.tracking == 'serial':190            if float_compare(self.qty_done, 1.0, precision_rounding=self.move_id.product_id.uom_id.rounding) != 0:191                message = _('You can only process 1.0 %s for products with unique serial number.') % self.product_id.uom_id.name192                res['warning'] = {'title': _('Warning'), 'message': message}193        return res194    @api.onchange('product_id')195    def _onchange_product_id(self):...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
