Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化

This commit is contained in:
mgw
2024-11-29 11:24:50 +08:00
12 changed files with 215 additions and 176 deletions

View File

@@ -43,6 +43,8 @@ class SaleOrder(models.Model):
# 复制成品模板上的属性 # 复制成品模板上的属性
line.product_id.product_tmpl_id.copy_template(product_template_id) line.product_id.product_tmpl_id.copy_template(product_template_id)
# 将模板上的single_manufacturing属性复制到成品上
line.product_id.single_manufacturing = product_template_id.single_manufacturing
order_id = self order_id = self
product = line.product_id product = line.product_id

View File

@@ -309,7 +309,8 @@ class MrpProduction(models.Model):
for move in production.move_raw_ids if move.product_id): for move in production.move_raw_ids if move.product_id):
production.state = 'progress' production.state = 'progress'
# 新添加的状态逻辑 # 新添加的状态逻辑
if production.state in ['to_close', 'progress', 'technology_to_confirmed'] and production.schedule_state == '未排': if production.state in ['to_close', 'progress',
'technology_to_confirmed'] and production.schedule_state == '未排':
if not production.workorder_ids or production.is_adjust is True: if not production.workorder_ids or production.is_adjust is True:
production.state = 'technology_to_confirmed' production.state = 'technology_to_confirmed'
else: else:
@@ -331,6 +332,9 @@ class MrpProduction(models.Model):
production.state = 'pending_cam' production.state = 'pending_cam'
if production.is_rework is True: if production.is_rework is True:
production.state = 'rework' production.state = 'rework'
if (production.state == 'rework' and production.tool_state == '0'
and production.schedule_state == '已排' and production.is_rework is False):
production.state = 'pending_cam'
# if production.state == 'pending_cam': # if production.state == 'pending_cam':
# if all(wo_state in 'done' for wo_state in production.workorder_ids.mapped('state')): # if all(wo_state in 'done' for wo_state in production.workorder_ids.mapped('state')):
# production.state = 'done' # production.state = 'done'
@@ -845,15 +849,20 @@ class MrpProduction(models.Model):
purchase_order = self.env['purchase.order'].search( purchase_order = self.env['purchase.order'].search(
[('state', '=', 'draft'), ('origin', '=', item.name), [('state', '=', 'draft'), ('origin', '=', item.name),
('purchase_type', '=', 'consignment')]) ('purchase_type', '=', 'consignment')])
for line in purchase_order.order_line: server_template = self.env['product.template'].search(
server_template = self.env['product.template'].search( [('server_product_process_parameters_id', '=',
[('server_product_process_parameters_id', '=', workorder.surface_technics_parameters_id.id), workorder.surface_technics_parameters_id.id),
('detailed_type', '=', 'service')]) ('detailed_type', '=', 'service')])
purchase_order_line = self.env['purchase.order.line'].search( for po in purchase_order:
[('product_id', '=', server_template.product_variant_id.id), ('id', '=', line.id), for line in po.order_line:
('product_qty', '=', 1)], limit=1, order='id desc') if line.product_id == server_template.product_variant_id:
if purchase_order_line: continue
line.unlink() if server_template.server_product_process_parameters_id != line.product_id.server_product_process_parameters_id:
purchase_order_line = self.env['purchase.order.line'].search(
[('product_id', '=', server_template.product_variant_id.id), ('id', '=', line.id),
('product_qty', '=', 1)], limit=1, order='id desc')
if purchase_order_line:
line.unlink()
def _reset_work_order_sequence(self): def _reset_work_order_sequence(self):
""" """
@@ -894,8 +903,6 @@ class MrpProduction(models.Model):
for cw in cancel_work_ids: for cw in cancel_work_ids:
cw.sequence = sequence + 1 cw.sequence = sequence + 1
def _reset_work_order_sequence_1(self): def _reset_work_order_sequence_1(self):
""" """
工单工序排序方法(旧) 工单工序排序方法(旧)

View File

@@ -1097,8 +1097,7 @@ class ResMrpWorkOrder(models.Model):
# ================= 如果制造订单刀具状态为[无效刀、缺刀] 或者 制造订单状态为[返工]========================== # ================= 如果制造订单刀具状态为[无效刀、缺刀] 或者 制造订单状态为[返工]==========================
if (workorder.production_id.tool_state in ['1', '2'] or workorder.production_id.state == 'rework' if (workorder.production_id.tool_state in ['1', '2'] or workorder.production_id.state == 'rework'
or workorder.production_id.schedule_state != '已排' or workorder.production_id.schedule_state != '已排'
or len( or workorder.production_id.reservation_state not in ['assigned']
workorder.production_id.picking_ids.filtered(lambda w: w.state not in ['done', 'cancel'])) != 0
or workorder.production_id.workorder_ids.filtered( or workorder.production_id.workorder_ids.filtered(
lambda wk: wk.sequence == workorder.sequence - 1).test_results in ['报废', '返工']): lambda wk: wk.sequence == workorder.sequence - 1).test_results in ['报废', '返工']):
if workorder.state != 'waiting': if workorder.state != 'waiting':
@@ -1247,10 +1246,14 @@ class ResMrpWorkOrder(models.Model):
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
('location_dest_id', '=', self.env['stock.location'].search( ('location_dest_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id), [('barcode', 'ilike', 'VL-SPOC')]).id),
('origin', '=', self.production_id.name)]) ('origin', '=', self.production_id.name), ('state', 'not in', ['cancel', 'done'])])
if move_out.state != 'done': for mo in move_out:
move_out.write({'state': 'assigned', 'production_id': False}) pick = self.env['stock.picking'].search([('id', '=', mo.picking_id.id), ('name', 'ilike', 'OCOUT'),
self.env['stock.move.line'].create(move_out.get_move_line(self.production_id, self)) ('partner_id', '=', self.supplier_id.id)])
if pick:
if mo.state != 'done':
mo.write({'state': 'assigned', 'production_id': False})
self.env['stock.move.line'].create(mo.get_move_line(self.production_id, self))
# move_out._action_assign() # move_out._action_assign()
if self.state == 'waiting' or self.state == 'ready' or self.state == 'progress': if self.state == 'waiting' or self.state == 'ready' or self.state == 'progress':

View File

@@ -859,12 +859,12 @@ class ResProductMo(models.Model):
raise UserError('请先配置模型类型内的坯料冗余') raise UserError('请先配置模型类型内的坯料冗余')
vals = { vals = {
'name': '%s-%s-%s' % ('P', order_id.name, i), 'name': '%s-%s-%s' % ('P', order_id.name, i),
'model_long': item['model_long'] + embryo_redundancy_id.long, 'model_long': self.format_float(item['model_long'] + embryo_redundancy_id.long),
'model_width': item['model_width'] + embryo_redundancy_id.width, 'model_width': self.format_float(item['model_width'] + embryo_redundancy_id.width),
'model_height': item['model_height'] + embryo_redundancy_id.height, 'model_height': self.format_float(item['model_height'] + embryo_redundancy_id.height),
'model_volume': (item['model_long'] + embryo_redundancy_id.long) * ( 'model_volume': self.format_float((item['model_long'] + embryo_redundancy_id.long) * (
item['model_width'] + embryo_redundancy_id.width) * ( item['model_width'] + embryo_redundancy_id.width) * (
item['model_height'] + embryo_redundancy_id.height), item['model_height'] + embryo_redundancy_id.height)),
'product_model_type_id': model_type.id, 'product_model_type_id': model_type.id,
'model_processing_panel': item['processing_panel_detail'], 'model_processing_panel': item['processing_panel_detail'],
'model_machining_precision': item['model_machining_precision'], 'model_machining_precision': item['model_machining_precision'],
@@ -884,7 +884,7 @@ class ResProductMo(models.Model):
'model_process_parameters_ids': [(6, 0, [])] if not item.get( 'model_process_parameters_ids': [(6, 0, [])] if not item.get(
'process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']), 'process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']),
'model_remark': item['remark'], 'model_remark': item['remark'],
'single_manufacturing': False, 'single_manufacturing': True,
'default_code': '%s-%s' % (order_number, i), 'default_code': '%s-%s' % (order_number, i),
'manual_quotation': item['manual_quotation'] or False, 'manual_quotation': item['manual_quotation'] or False,
'part_number': item.get('part_number') or '', 'part_number': item.get('part_number') or '',
@@ -907,6 +907,20 @@ class ResProductMo(models.Model):
self.attachment_update(item['quality_standard_name'], copy_product_id.product_tmpl_id.id, self.attachment_update(item['quality_standard_name'], copy_product_id.product_tmpl_id.id,
'quality_standard', item['quality_standard_mimetype']) 'quality_standard', item['quality_standard_mimetype'])
return copy_product_id return copy_product_id
def format_float(self, value):
# 将浮点数转换为字符串
value_str = str(value)
# 检查小数点的位置
if '.' in value_str:
# 获取小数部分
decimal_part = value_str.split('.')[1]
# 判断小数位数是否超过2位
if len(decimal_part) > 2:
# 超过2位则保留2位小数
return "{:.2f}".format(value)
# 否则保持原来的位数
return float(value_str)
def _get_ids(self, param): def _get_ids(self, param):
type_ids = [] type_ids = []

View File

@@ -290,7 +290,7 @@ class StockRule(models.Model):
else: else:
mrp_production = production mrp_production = production
# if sale_order: # if sale_order:
# sale_order.write({'schedule_status': 'to schedule'}) # sale_order.write({'schedule_status': 'to schedule'})
self.env['sf.production.plan'].sudo().with_company(company_id).create({ self.env['sf.production.plan'].sudo().with_company(company_id).create({
'name': production.name, 'name': production.name,
'order_deadline': sale_order.deadline_of_delivery, 'order_deadline': sale_order.deadline_of_delivery,
@@ -301,7 +301,6 @@ class StockRule(models.Model):
'product_id': production.product_id.id, 'product_id': production.product_id.id,
'state': 'draft', 'state': 'draft',
}) })
technology_design_values = []
all_production = productions all_production = productions
grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)} grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)}
# 初始化一个字典来存储每个product_id对应的生产订单名称列表 # 初始化一个字典来存储每个product_id对应的生产订单名称列表
@@ -311,6 +310,7 @@ class StockRule(models.Model):
# 为同一个product_id创建一个生产订单名称列表 # 为同一个product_id创建一个生产订单名称列表
product_id_to_production_names[product_id] = [production.name for production in all_production] product_id_to_production_names[product_id] = [production.name for production in all_production]
for production_item in productions: for production_item in productions:
technology_design_values = []
production_programming = self.env['mrp.production'].search( production_programming = self.env['mrp.production'].search(
[('product_id.id', '=', production_item.product_id.id), [('product_id.id', '=', production_item.product_id.id),
('origin', '=', production_item.origin)], ('origin', '=', production_item.origin)],
@@ -318,77 +318,76 @@ class StockRule(models.Model):
if production_item.product_id.id in product_id_to_production_names: if production_item.product_id.id in product_id_to_production_names:
# 同一个产品多个制造订单对应一个编程单和模型库 # 同一个产品多个制造订单对应一个编程单和模型库
# 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递 # 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递
if not production_item.programming_no and production.production_type == '自动化产线加工': if not production_item.programming_no and production_item.production_type == '自动化产线加工':
if not production_programming.programming_no: if not production_programming.programming_no:
production_item.fetchCNC( production_item.fetchCNC(
', '.join(product_id_to_production_names[production_item.product_id.id])) ', '.join(product_id_to_production_names[production_item.product_id.id]))
else: else:
production_item.write({'programming_no': production_programming.programming_no, production_item.write({'programming_no': production_programming.programming_no,
'programming_state': '编程中'}) 'programming_state': '编程中'})
if not technology_design_values: i = 0
i = 0 if production_item.product_id.categ_id.type == '成品':
if production_item.product_id.categ_id.type == '成品': # 根据加工面板的面数及成品工序模板生成工序设计
# 根据加工面板的面数及成品工序模板生成工序设计 if production_item.production_type == '自动化产线加工':
if production_item.production_type == '自动化产线加工': model = 'sf.product.model.type.routing.sort'
model = 'sf.product.model.type.routing.sort' domain = [
domain = [ ('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)]
('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)] else:
else: model = 'sf.manual.product.model.type.routing.sort'
model = 'sf.manual.product.model.type.routing.sort' domain = [('manual_product_model_type_id', '=',
domain = [('manual_product_model_type_id', '=', production_item.product_id.product_model_type_id.id)]
production_item.product_id.product_model_type_id.id)] product_routing_workcenter = self.env[model].search(domain, order='sequence asc')
product_routing_workcenter = self.env[model].search(domain, order='sequence asc') if production_item.production_type == '自动化产线加工':
if production_item.production_type == '自动化产线加工': for k in (production_item.product_id.model_processing_panel.split(',')):
for k in (production_item.product_id.model_processing_panel.split(',')):
for route in product_routing_workcenter:
i += 1
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(k, route, i, False))
else:
for route in product_routing_workcenter: for route in product_routing_workcenter:
i += 1 i += 1
technology_design_values.append( technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(False, route, i, False)) self.env['sf.technology.design'].json_technology_design_str(k, route, i, False))
elif production_item.product_id.categ_id.type == '坯料': else:
embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search( for route in product_routing_workcenter:
[('embryo_model_type_id', '=', production_item.product_id.embryo_model_type_id.id)],
order='sequence asc'
)
for route_embryo in embryo_routing_workcenter:
i += 1 i += 1
technology_design_values.append( technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(False, route_embryo, i, self.env['sf.technology.design'].json_technology_design_str(False, route, i, False))
False)) elif production_item.product_id.categ_id.type == '坯料':
surface_technics_arr = [] embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search(
route_workcenter_arr = [] [('embryo_model_type_id', '=', production_item.product_id.embryo_model_type_id.id)],
for item in production_item.product_id.product_model_type_id.surface_technics_routing_tmpl_ids: order='sequence asc'
if item.route_workcenter_id.surface_technics_id.id: )
for process_param in production_item.product_id.model_process_parameters_ids: for route_embryo in embryo_routing_workcenter:
if item.route_workcenter_id.surface_technics_id == process_param.process_id: i += 1
surface_technics_arr.append( technology_design_values.append(
item.route_workcenter_id.surface_technics_id.id) self.env['sf.technology.design'].json_technology_design_str(False, route_embryo, i,
route_workcenter_arr.append(item.route_workcenter_id.id) False))
if surface_technics_arr: surface_technics_arr = []
production_process = self.env['sf.production.process'].search( route_workcenter_arr = []
[('id', 'in', surface_technics_arr)], for item in production_item.product_id.product_model_type_id.surface_technics_routing_tmpl_ids:
order='sequence asc' if item.route_workcenter_id.surface_technics_id.id:
) for process_param in production_item.product_id.model_process_parameters_ids:
for p in production_process: if item.route_workcenter_id.surface_technics_id == process_param.process_id:
logging.info('production_process:%s' % p.name) surface_technics_arr.append(
process_parameter = production_item.product_id.model_process_parameters_ids.filtered( item.route_workcenter_id.surface_technics_id.id)
lambda pm: pm.process_id.id == p.id) route_workcenter_arr.append(item.route_workcenter_id.id)
if process_parameter: if surface_technics_arr:
i += 1 production_process = self.env['sf.production.process'].search(
route_production_process = self.env[ [('id', 'in', surface_technics_arr)],
'mrp.routing.workcenter'].search( order='sequence asc'
[('surface_technics_id', '=', p.id), )
('id', 'in', route_workcenter_arr)]) for p in production_process:
technology_design_values.append( logging.info('production_process:%s' % p.name)
self.env['sf.technology.design'].json_technology_design_str(False, process_parameter = production_item.product_id.model_process_parameters_ids.filtered(
route_production_process, lambda pm: pm.process_id.id == p.id)
i, if process_parameter:
process_parameter)) i += 1
productions.technology_design_ids = technology_design_values route_production_process = self.env[
'mrp.routing.workcenter'].search(
[('surface_technics_id', '=', p.id),
('id', 'in', route_workcenter_arr)])
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(False,
route_production_process,
i,
process_parameter))
production_item.technology_design_ids = technology_design_values
productions.write({'state': 'technology_to_confirmed'}) productions.write({'state': 'technology_to_confirmed'})
return True return True
@@ -424,6 +423,8 @@ class ProductionLot(models.Model):
"""Generate `lot_names` from a string.""" """Generate `lot_names` from a string."""
if first_lot.__contains__(display_name): if first_lot.__contains__(display_name):
first_lot = first_lot[(len(display_name) + 1):] first_lot = first_lot[(len(display_name) + 1):]
else:
first_lot = first_lot[-3:]
# We look if the first lot contains at least one digit. # We look if the first lot contains at least one digit.
caught_initial_number = regex_findall(r"\d+", first_lot) caught_initial_number = regex_findall(r"\d+", first_lot)
@@ -634,39 +635,24 @@ class StockPicking(models.Model):
return '%s%s' % (rescode, num) return '%s%s' % (rescode, num)
def button_validate(self): def button_validate(self):
if self.picking_type_id.barcode == 'OCOUT': res = super().button_validate()
move_out = self.env['stock.move'].search( if res is True and self.picking_type_id.sequence_code == 'OCOUT':
[('location_id', '=', self.env['stock.location'].search( # if self.id == move_out.picking_id.id:
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), # if move_out.move_line_ids.workorder_id.state == 'progress':
('location_dest_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id),
('origin', '=', self.origin)])
move_in = self.env['stock.move'].search( move_in = self.env['stock.move'].search(
[('location_dest_id', '=', self.env['stock.location'].search( [('location_dest_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
('location_id', '=', self.env['stock.location'].search( ('location_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id), [('barcode', 'ilike', 'VL-SPOC')]).id),
('origin', '=', self.origin), ('picking_id', '=', self.id)]) ('origin', '=', self.origin), ('state', 'not in', ['cancel', 'done'])])
if self.location_id == move_in.location_id and self.location_dest_id == move_in.location_dest_id: production = self.env['mrp.production'].search([('name', '=', self.origin)])
if move_out.origin == move_in.origin: for mi in move_in:
move_in.write({'production_id': False}) pick = self.env['stock.picking'].search([('id', '=', mi.picking_id.id), ('name', 'ilike', 'OCIN'),
if move_out.picking_id.state != 'done': ('partner_id', '=', self.partner_id.id)])
raise UserError( if pick:
_('该入库单对应的单号为%s的出库单还未完成,不能进行验证操作!' % move_out.picking_id.name)) if mi.state != 'done':
res = super().button_validate() mi.write({'state': 'assigned'})
if res is True and self.picking_type_id.barcode == 'OCIN': self.env['stock.move.line'].create(mi.get_move_line(production, None))
if self.id == move_out.picking_id.id:
# if move_out.move_line_ids.workorder_id.state == 'progress':
move_in = self.env['stock.move'].search(
[('location_dest_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
('location_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id),
('origin', '=', self.origin)])
production = self.env['mrp.production'].search([('name', '=', self.origin)])
if move_in.state != 'done':
move_in.write({'state': 'assigned'})
self.env['stock.move.line'].create(move_in.get_move_line(production, None))
return res return res

View File

@@ -31,7 +31,7 @@
<form string="模型类型"> <form string="模型类型">
<group> <group>
<field name="name" required="1"/> <field name="name" required="1"/>
<field name="embryo_tolerance_id" required="1" string="坯料容余(mm)"/> <field name="embryo_tolerance_id" required="1"/>
</group> </group>
<group> <group>
<field name='product_routing_tmpl_ids'> <field name='product_routing_tmpl_ids'>

View File

@@ -51,5 +51,10 @@
</xpath> </xpath>
</field> </field>
</record> </record>
<record id="stock.action_picking_tree_all" model="ir.actions.act_window">
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('stock.vpicktree')})]"/>
</record>
</data> </data>
</odoo> </odoo>

View File

@@ -83,7 +83,7 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
workorder.picking_ids.write({'state': 'cancel'}) workorder.picking_ids.write({'state': 'cancel'})
workorder.picking_ids.move_ids.write({'state': 'cancel'}) workorder.picking_ids.move_ids.write({'state': 'cancel'})
purchase_order = self.env['purchase.order'].search( purchase_order = self.env['purchase.order'].search(
[('origin', '=', workorder.production_id.origin)]) [('origin', '=', workorder.production_id.name)])
for line in purchase_order.order_line: for line in purchase_order.order_line:
if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id: if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id:
purchase_order.write({'state': 'cancel'}) purchase_order.write({'state': 'cancel'})
@@ -104,6 +104,7 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
self.env['mrp.workorder'].json_workorder_str(special.production_id, special)) self.env['mrp.workorder'].json_workorder_str(special.production_id, special))
special.production_id.write({'workorder_ids': workorders_values}) special.production_id.write({'workorder_ids': workorders_values})
else: else:
logging.info(workorder.blocked_by_workorder_ids)
if len(workorder.blocked_by_workorder_ids) > 1: if len(workorder.blocked_by_workorder_ids) > 1:
if workorder.sequence == 1: if workorder.sequence == 1:
workorder.blocked_by_workorder_ids = None workorder.blocked_by_workorder_ids = None

View File

@@ -80,7 +80,7 @@ class ProductionTechnologyWizard(models.TransientModel):
workorder.picking_ids.write({'state': 'cancel'}) workorder.picking_ids.write({'state': 'cancel'})
workorder.picking_ids.move_ids.write({'state': 'cancel'}) workorder.picking_ids.move_ids.write({'state': 'cancel'})
purchase_order = self.env['purchase.order'].search( purchase_order = self.env['purchase.order'].search(
[('origin', '=', workorder.production_id.origin)]) [('origin', '=', workorder.production_id.name)])
for line in purchase_order.order_line: for line in purchase_order.order_line:
if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id: if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id:
purchase_order.write({'state': 'cancel'}) purchase_order.write({'state': 'cancel'})

View File

@@ -4,6 +4,7 @@ import logging
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
from datetime import datetime from datetime import datetime
from odoo import models, api, fields, _ from odoo import models, api, fields, _
from odoo.tools import groupby
class ReworkWizard(models.TransientModel): class ReworkWizard(models.TransientModel):
@@ -37,6 +38,30 @@ class ReworkWizard(models.TransientModel):
tool_state = fields.Selection(string='功能刀具状态', related='production_id.tool_state') tool_state = fields.Selection(string='功能刀具状态', related='production_id.tool_state')
@api.onchange('hidden_workorder_ids')
def _onchange_hidden_workorder_ids(self):
for item in self:
if item.hidden_workorder_ids not in ['', None, False]:
hidden_workorder_list = item.hidden_workorder_ids.split(',')
# 获取加工面对应需要返工的工单
rw_ids = item.workorder_ids.filtered(
lambda w: str(w.ids[0]) in hidden_workorder_list and w.processing_panel not in ['', None, False])
grouped_rw_ids = {key: list(group) for key, group in groupby(rw_ids, key=lambda w: w.processing_panel)}
for panel, panel_rw_ids in grouped_rw_ids.items():
work_ids = item.workorder_ids.filtered(lambda w: w.state == 'done' and w.processing_panel == panel)
if len(work_ids) == 3 and len(panel_rw_ids) != 3:
for work_id in work_ids:
if work_id not in panel_rw_ids:
hidden_workorder_list.append(str(work_id.ids[0]))
elif len(work_ids) == 2 and len(panel_rw_ids) < 2 and panel_rw_ids[0].name == 'CNC加工':
if rw_ids.filtered(lambda w: (w.sequence < panel_rw_ids[0].sequence
and w.processing_panel != panel_rw_ids[0].processing_panel)):
hidden_workorder_list.append(str(work_ids.filtered(
lambda w: (w.processing_panel == panel_rw_ids[0].processing_panel
and w.name == '装夹预调')).ids[0]))
hidden_workorder_list.sort()
item.hidden_workorder_ids = ','.join(hidden_workorder_list)
def confirm(self): def confirm(self):
if self.routing_type in ['装夹预调', 'CNC加工']: if self.routing_type in ['装夹预调', 'CNC加工']:
self.is_clamp_measure = False self.is_clamp_measure = False
@@ -58,16 +83,16 @@ class ReworkWizard(models.TransientModel):
# 1、当制造订单内ZM面的工单都已完成时返工勾选工序时只能勾选上ZM面的所有工序进行返工 # 1、当制造订单内ZM面的工单都已完成时返工勾选工序时只能勾选上ZM面的所有工序进行返工
# 2、当FM工单在CNC工单进行选择返工并将已全部完成的ZM面工序全部勾选上时FM工单上所有的已完成的工单装夹预调工单也必须进行勾选 # 2、当FM工单在CNC工单进行选择返工并将已全部完成的ZM面工序全部勾选上时FM工单上所有的已完成的工单装夹预调工单也必须进行勾选
# 获取已完成的标准工单 # 获取已完成的标准工单
done_normative_workorder_ids = self.workorder_ids.filtered( # done_normative_workorder_ids = self.workorder_ids.filtered(
lambda w: w.state == 'done' and w.processing_panel is not False) # lambda w: w.state == 'done' and w.processing_panel is not False)
# 获取需要返工的标准工单 # # 获取需要返工的标准工单
rework_normative_workorder_ids = rework_workorder_ids.filtered( # rework_normative_workorder_ids = rework_workorder_ids.filtered(
lambda w: w.processing_panel is not False) # lambda w: w.processing_panel is not False)
if rework_normative_workorder_ids: # if rework_normative_workorder_ids:
for rw in rework_normative_workorder_ids: # for rw in rework_normative_workorder_ids:
if len(done_normative_workorder_ids.filtered( # if len(done_normative_workorder_ids.filtered(
lambda w: w.processing_panel == rw.processing_panel)) == 3: # lambda w: w.processing_panel == rw.processing_panel)) == 3:
pass # pass
else: else:
raise ValidationError('请选择返工工单!!!') raise ValidationError('请选择返工工单!!!')
if rework_workorder_ids: if rework_workorder_ids:

View File

@@ -232,41 +232,38 @@ class sf_production_plan(models.Model):
raise ValidationError("未选择生产线") raise ValidationError("未选择生产线")
else: else:
# 自动化产线加工 # 自动化产线加工
if record.production_id.production_type == '自动化产线加工': if record.production_id.workorder_ids:
if record.production_id.workorder_ids: # 自动化产线加工
last_cnc_start = record.date_planned_start if record.date_planned_start else datetime.now() if record.production_id.production_type == '自动化产线加工':
for item in record.production_id.workorder_ids: # 找到第一张CNC加工工单
if item.name == 'CNC加工': first_cnc_workorder = record.production_id.workorder_ids.filtered(lambda x: x.name == 'CNC加工')[0]
# 将同一个面的所有工单筛选出来 date_start = record.date_planned_start if record.date_planned_start else datetime.now()
workorder_list = record.production_id.workorder_ids.filtered(lambda x: x.processing_panel == item.processing_panel) routing_workcenter = first_cnc_workorder.technology_design_id.route_id
routing_workcenter = record.env['mrp.routing.workcenter'].sudo().search( # 设置一个小的开始时间
[('name', '=', 'CNC加工')], limit=1) first_cnc_workorder.date_planned_start = datetime.now() - timedelta(days=100)
# 设置一个小的开始时间 first_cnc_workorder.date_planned_finished = date_start + timedelta(
item.date_planned_start = datetime.now() - timedelta(days=100) minutes=routing_workcenter.time_cycle + routing_workcenter.reserved_duration)
item.date_planned_finished = last_cnc_start + timedelta( first_cnc_workorder.date_planned_start = date_start
minutes=routing_workcenter.time_cycle) record.sudo().production_id.plan_start_processing_time = first_cnc_workorder.date_planned_start
item.date_planned_start = last_cnc_start first_cnc_workorder.duration_expected = routing_workcenter.time_cycle + routing_workcenter.reserved_duration
record.sudo().production_id.plan_start_processing_time = item.date_planned_start record.calculate_plan_time(first_cnc_workorder, record.production_id.workorder_ids)
item.duration_expected = routing_workcenter.time_cycle # 找到最后一张CNC加工工单
pre_duration , next_duration = record.calculate_plan_time(item, workorder_list) last_cnc_workorder = record.production_id.workorder_ids.filtered(lambda x: x.name == 'CNC加工')[-1]
record.date_planned_finished = item.date_planned_finished record.date_planned_finished = last_cnc_workorder.date_planned_finished
# 计算下一个cnc工单的开始时间 else:
last_cnc_start = workorder_list[-1].date_planned_finished + timedelta(minutes=pre_duration) # 人工线下加工只排第一张工单
# 没有工单也能排程
else:
# 人工线下加工只排第一张工单
if record.production_id.workorder_ids:
item = record.production_id.workorder_ids[0] item = record.production_id.workorder_ids[0]
last_wo_start = record.date_planned_start if record.date_planned_start else datetime.now() wo_start = record.date_planned_start if record.date_planned_start else datetime.now()
routing_workcenter = record.env['mrp.routing.workcenter'].sudo().search( routing_workcenter = item.technology_design_id.route_id
[('name', '=', item.routing_type)], limit=1)
item.date_planned_start = datetime.now() - timedelta(days=100) item.date_planned_start = datetime.now() - timedelta(days=100)
item.date_planned_finished = last_wo_start + timedelta( item.date_planned_finished = wo_start + timedelta(
minutes=routing_workcenter.time_cycle) minutes=routing_workcenter.time_cycle + routing_workcenter.reserved_duration)
item.date_planned_start = last_wo_start item.date_planned_start = wo_start
record.sudo().production_id.plan_start_processing_time = item.date_planned_start record.sudo().production_id.plan_start_processing_time = item.date_planned_start
item.duration_expected = routing_workcenter.time_cycle item.duration_expected = routing_workcenter.time_cycle + routing_workcenter.reserved_duration
record.calculate_plan_time(item, item) record.calculate_plan_time(item, record.production_id.workorder_ids)
last_cnc_workorder = record.production_id.workorder_ids[-1]
record.date_planned_finished = last_cnc_workorder.date_planned_finished
record.state = 'done' record.state = 'done'
# record.production_id.schedule_state = '已排' # record.production_id.schedule_state = '已排'
record.sudo().production_id.schedule_state = '已排' record.sudo().production_id.schedule_state = '已排'
@@ -322,44 +319,40 @@ class sf_production_plan(models.Model):
def calculate_plan_time(self, item, workorder_list): def calculate_plan_time(self, item, workorder_list):
""" """
根据CNC工单的时间去计算之前的其他工单的开始结束时间 根据CNC工单的时间去计算之前的其他工单的开始结束时间
param:
item: 基准工单(根据该工单的开始结束时间去计算其他工单的开始结束时间)
workorder_list: 需排程的工单列表
""" """
item_position = 0 item_position = 0
for index, workorder in enumerate(workorder_list): for index, workorder in enumerate(workorder_list):
if workorder.id == item.id: if workorder.id == item.id:
item_position = index item_position = index
break break
routing_workcenters = self.env['mrp.routing.workcenter'].sudo().search([])
# 记录所有前序工序时长
previous_workorder_duration = 0
for i in range(item_position, -1, -1): for i in range(item_position, -1, -1):
if i < 1: if i < 1:
break break
current_workorder = workorder_list[i] current_workorder = workorder_list[i]
next_workorder = workorder_list[i - 1] next_workorder = workorder_list[i - 1]
routing_workcenter = routing_workcenters.filtered(lambda x: x.name == next_workorder.name)[0] routing_workcenter = next_workorder.technology_design_id.route_id
# 设置一个小的开始时间 # 设置一个小的开始时间
next_workorder.date_planned_start = datetime.now() - timedelta(days=100) next_workorder.date_planned_start = datetime.now() - timedelta(days=100)
next_workorder.date_planned_finished = current_workorder.date_planned_start next_workorder.date_planned_finished = current_workorder.date_planned_start
next_workorder.date_planned_start = next_workorder.date_planned_finished - timedelta( next_workorder.date_planned_start = next_workorder.date_planned_finished - timedelta(
minutes=routing_workcenter.time_cycle) minutes=routing_workcenter.time_cycle + routing_workcenter.reserved_duration)
next_workorder.duration_expected = routing_workcenter.time_cycle next_workorder.duration_expected = routing_workcenter.time_cycle + routing_workcenter.reserved_duration
previous_workorder_duration += routing_workcenter.time_cycle
# 记录所有后续工序时长
next_workorder_duration = 0
for i in range(item_position, len(workorder_list) - 1): for i in range(item_position, len(workorder_list) - 1):
if i > len(workorder_list) - 1: if i > len(workorder_list) - 1:
break break
current_workorder = workorder_list[i] current_workorder = workorder_list[i]
next_workorder = workorder_list[i + 1] next_workorder = workorder_list[i + 1]
routing_workcenter = routing_workcenters.filtered(lambda x: x.name == next_workorder.name)[0] routing_workcenter = next_workorder.technology_design_id.route_id
# 设置一个小的开始时间 # 设置一个小的开始时间
next_workorder.date_planned_start = datetime.now() - timedelta(days=100) next_workorder.date_planned_start = datetime.now() - timedelta(days=100)
next_workorder.date_planned_finished = current_workorder.date_planned_finished + timedelta( next_workorder.date_planned_finished = current_workorder.date_planned_finished + timedelta(
minutes=routing_workcenter.time_cycle) minutes=routing_workcenter.time_cycle + routing_workcenter.reserved_duration)
next_workorder.date_planned_start = current_workorder.date_planned_finished next_workorder.date_planned_start = current_workorder.date_planned_finished
next_workorder.duration_expected = routing_workcenter.time_cycle next_workorder.duration_expected = routing_workcenter.time_cycle + routing_workcenter.reserved_duration
next_workorder_duration += routing_workcenter.time_cycle
return previous_workorder_duration, next_workorder_duration
def calculate_plan_time_after(self, item, workorder_id_list): def calculate_plan_time_after(self, item, workorder_id_list):
""" """

View File

@@ -265,17 +265,20 @@ class RePurchaseOrder(models.Model):
})) }))
for purchase in purchase_order: for purchase in purchase_order:
for po in purchase.order_line: for po in purchase.order_line:
if server_template.server_product_process_parameters_id == pp.surface_technics_parameters_id: if po.product_id == server_template.product_variant_id:
continue
if server_template.server_product_process_parameters_id != po.product_id.server_product_process_parameters_id:
purchase_order_line = self.env['purchase.order.line'].search( purchase_order_line = self.env['purchase.order.line'].search(
[('product_id', '=', server_template.product_variant_id.id), [('product_id', '=', server_template.product_variant_id.id),
('product_qty', '=', 1.0), ('id', '=', po.id)], limit=1, ('product_qty', '=', 1.0), ('id', '=', purchase.id)], limit=1,
order='id desc') order='id desc')
if not purchase_order_line and purchase not in purchase_order: if not purchase_order_line:
server_product_process.append((0, 0, { server_product_process.append((0, 0, {
'product_id': server_template.product_variant_id.id, 'product_id': server_template.product_variant_id.id,
'product_qty': 1, 'product_qty': 1,
'product_uom': server_template.uom_id.id 'product_uom': server_template.uom_id.id
})) }))
if server_product_process: if server_product_process:
self.env['purchase.order'].sudo().create({ self.env['purchase.order'].sudo().create({
'partner_id': server_template.seller_ids[0].partner_id.id, 'partner_id': server_template.seller_ids[0].partner_id.id,