import logging from datetime import timedelta, datetime, date from odoo import api, fields, models, _ from odoo.exceptions import ValidationError class ShelfLocation(models.Model): _inherit = 'sf.shelf.location' tool_rfid = fields.Char('Rfid', compute='_compute_tool', store=True) tool_name_id = fields.Many2one('sf.functional.cutting.tool.entity', string='功能刀具名称', compute='_compute_tool', store=True) @api.depends('product_id') def _compute_tool(self): for item in self: if item.product_id: if item.product_id.categ_id.name == '功能刀具': tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search( [('barcode_id', '=', item.product_sn_id.id)]) if tool_id: item.tool_rfid = tool_id.rfid item.tool_name_id = tool_id.id continue item.tool_rfid = '' item.tool_name_id = False class StockMoveLine(models.Model): _inherit = 'stock.move.line' @api.model_create_multi def create(self, vals_list): records = super(StockMoveLine, self).create(vals_list) move_lines = records.filtered(lambda a: a.product_id.categ_id.name == '功能刀具' and a.state == 'done') if move_lines: # 校验是否为功能刀具移动历史 self.button_function_tool_use_verify(move_lines) return records def button_function_tool_use_verify(self, move_lines): """ 对所有从【刀具房】到【制造前】的功能刀具进行校验(校验是否为制造订单所缺的刀) """ location_id = self.env['stock.location'].search([('name', '=', '刀具房')]) location_dest_id = self.env['stock.location'].search([('name', '=', '制造前')]) line_ids = move_lines.filtered( lambda a: a.location_id == location_id and a.location_dest_id == location_dest_id) for line_id in line_ids: if line_id.lot_id: self.env['sf.functional.cutting.tool.entity'].sudo().search( [('barcode_id', '=', line_id.lot_id.id), ('functional_tool_status', '=', '正常')]).cnc_function_tool_use_verify() class StockPicking(models.Model): _inherit = 'stock.picking' def button_validate(self): res = super().button_validate() move_lines = self.move_line_ids.filtered(lambda a: a.product_id.categ_id.name == '功能刀具') if move_lines: self.env['stock.move.line'].sudo().button_function_tool_use_verify(move_lines) return res def create_tool_stocking_picking(self, stock_lot, obj): """ 创建功能刀具组装入库单 """ # 获取名称为刀具组装入库的作业类型 picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '刀具组装入库')]) # 创建刀具组装入库单 picking_id = self.env['stock.picking'].create({ 'name': self._get_name_stock(picking_type_id), 'picking_type_id': picking_type_id.id, 'location_id': picking_type_id.default_location_src_id.id, 'location_dest_id': picking_type_id.default_location_dest_id.id, 'origin': obj.assembly_order_code }) # 创建作业详情对象记录,并绑定到刀具组装入库单 self.env['stock.move.line'].create({ 'picking_id': picking_id.id, 'product_id': stock_lot.product_id.id, 'location_id': picking_id.location_id.id, 'location_dest_id': picking_id.location_dest_id.id, 'lot_id': stock_lot.id, 'install_tool_time': fields.Datetime.now(), 'qty_done': 1, 'functional_tool_name_id': obj.id, 'functional_tool_type_id': obj.functional_tool_type_id.id, 'diameter': obj.after_assembly_functional_tool_diameter, 'knife_tip_r_angle': obj.after_assembly_knife_tip_r_angle, 'code': obj.code, 'rfid': obj.rfid, 'functional_tool_name': obj.after_assembly_functional_tool_name, 'tool_groups_id': obj.tool_groups_id.id }) # 将刀具组装入库单的状态更改为就绪 picking_id.action_confirm() picking_id.button_validate() def _get_name_stock(self, picking_type_id): name = picking_type_id.sequence_id.prefix + str( datetime.strptime(str(fields.Date.today()), "%Y-%m-%d").strftime("%Y%m%d")) stock_id = self.env['stock.picking'].sudo().search( [('name', 'like', name), ('picking_type_id', '=', picking_type_id.id)], limit=1, order="id desc" ) if not stock_id: num = "%03d" % 1 else: m = int(stock_id.name[-3:]) + 1 num = "%03d" % m return name + str(num) def create_tool_stocking_picking1(self, obj): """ 创建刀具物料出库单 """ # 获取名称为内部调拨的作业类型 picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '内部调拨')]) # 创建刀具物料出库单 picking_id = self.env['stock.picking'].create({ 'name': self._get_name_stock1(picking_type_id), 'picking_type_id': picking_type_id.id, 'location_id': self.env['stock.location'].search([('name', '=', '刀具房')]).id, 'location_dest_id': self.env['stock.location'].search([('name', '=', '刀具组装位置')]).id, 'origin': obj.assembly_order_code }) # =============刀具物料出库=================== stock_move_id = self.env['stock.move'] datas = {'data': [], 'picking_id': picking_id} if obj.handle_code_id: # 修改刀柄序列号状态为【在用】 obj.handle_code_id.sudo().write({'tool_material_status': '在用'}) datas['data'].append( {'current_location_id': self.env['sf.shelf.location'], 'lot_id': obj.handle_code_id}) if obj.integral_product_id: datas['data'].append( {'current_location_id': obj.integral_freight_barcode_id, 'lot_id': obj.integral_freight_lot_id.lot_id}) if obj.blade_product_id: datas['data'].append( {'current_location_id': obj.blade_freight_barcode_id, 'lot_id': obj.blade_freight_lot_id.lot_id}) if obj.bar_product_id: datas['data'].append( {'current_location_id': obj.bar_freight_barcode_id, 'lot_id': obj.bar_freight_lot_id.lot_id}) if obj.pad_product_id: datas['data'].append( {'current_location_id': obj.pad_freight_barcode_id, 'lot_id': obj.pad_freight_lot_id.lot_id}) if obj.chuck_product_id: datas['data'].append( {'current_location_id': obj.chuck_freight_barcode_id, 'lot_id': obj.chuck_freight_lot_id.lot_id}) # 创建刀具物料出库库存移动记录 stock_move_id.create_tool_material_stock_moves(datas) # 将刀具物料出库库单的状态更改为就绪 picking_id.action_confirm() # 修改刀具物料出库移动历史记录 stock_move_id.write_tool_material_stock_move_lines(datas) # 设置数量,并验证完成 picking_id.action_set_quantities_to_reservation() picking_id.button_validate() logging.info(f'刀具物料调拨单状态:{picking_id.state}') def _get_name_stock1(self, picking_type_id): name = f'{picking_type_id.sequence_id.prefix}DJ/{date.today().strftime("%y")}' stock_id = self.env['stock.picking'].sudo().search( [('name', 'like', name), ('picking_type_id', '=', picking_type_id.id)], limit=1, order="id desc" ) if not stock_id: num = "%05d" % 1 else: m = int(stock_id.name[-5:]) + 1 num = "%05d" % m return name + str(num) class StockMove(models.Model): _inherit = 'stock.move' def create_tool_material_stock_moves(self, datas): picking_id = datas['picking_id'] data = datas['data'] stock_move_ids = [] for res in data: if res: # 创建库存移动记录 stock_move_id = self.env['stock.move'].sudo().create({ 'name': picking_id.name, 'picking_id': picking_id.id, 'product_id': res['lot_id'].product_id.id, 'location_id': picking_id.location_id.id, 'location_dest_id': picking_id.location_dest_id.id, 'product_uom_qty': 1.00, 'reserved_availability': 1.00 }) stock_move_ids.append(stock_move_id) return stock_move_ids def write_tool_material_stock_move_lines(self, datas): picking_id = datas['picking_id'] data = datas['data'] move_line_ids = picking_id.move_line_ids for move_line_id in move_line_ids: for res in data: if move_line_id.lot_id.product_id == res['lot_id'].product_id: move_line_id.write({ 'current_location_id': res.get('current_location_id').id, 'lot_id': res.get('lot_id').id }) return True class ProductProduct(models.Model): _inherit = 'product.product' def create_assemble_warehouse_receipt(self, obj): """ 创建功能刀具批次/序列号记录 """ product_id = self.env['product.product'].search([('categ_type', '=', '功能刀具'), ('tracking', '=', 'serial')]) if not product_id: logging.info('没有搜索到功能刀具产品:%s' % product_id) raise ValidationError('没有找到按唯一序列号追溯的功能刀具产品信息!') stock_lot = self.env['stock.lot'].create({ 'name': self.get_stock_lot_name(obj), 'product_id': product_id[0].id, 'company_id': self.env.company.id }) return stock_lot def get_stock_lot_name(self, obj): """ 生成功能刀具序列号 """ company = obj.cutting_tool_cutterhandle_model_id.code.split('-', 1)[0] new_time = datetime.strptime(str(fields.Date.today()), "%Y-%m-%d").strftime("%Y%m%d") code = '%s-GNDJ-%s-%s' % (company, obj.after_assembly_functional_tool_type_id.code, new_time) stock_lot_id = self.env['stock.lot'].sudo().search( [('name', 'like', code)], limit=1, order="id desc") if not stock_lot_id: num = "%03d" % 1 else: m = int(stock_lot_id.name[-3:]) + 1 num = "%03d" % m return '%s-%s' % (code, num) class SfShelfLocationLot(models.Model): _inherit = 'sf.shelf.location.lot'