Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/修复外协出入库单

This commit is contained in:
jinling.yang
2024-11-28 16:01:11 +08:00
9 changed files with 86 additions and 56 deletions

View File

@@ -331,6 +331,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'
@@ -353,6 +356,7 @@ class MrpProduction(models.Model):
if production.tool_state == '2': if production.tool_state == '2':
production.state = 'rework' production.state = 'rework'
# 退回调整 # 退回调整
def technology_back_adjust(self): def technology_back_adjust(self):
process_parameters = [] process_parameters = []

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

View File

@@ -318,7 +318,7 @@ 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]))

View File

@@ -52,6 +52,7 @@ access_mrp_routing_workcenter_manager_group_sf_mrp_user,mrp.routing.workcenter.m
access_mrp_bom_manager_group_sf_mrp_user,mrp.bom.manager,mrp.model_mrp_bom,sf_base.group_sf_mrp_user,1,1,1,0 access_mrp_bom_manager_group_sf_mrp_user,mrp.bom.manager,mrp.model_mrp_bom,sf_base.group_sf_mrp_user,1,1,1,0
access_mrp_bom_line_manager_group_sf_mrp_user,mrp.bom.line.manager,mrp.model_mrp_bom_line,sf_base.group_sf_mrp_user,1,1,1,0 access_mrp_bom_line_manager_group_sf_mrp_user,mrp.bom.line.manager,mrp.model_mrp_bom_line,sf_base.group_sf_mrp_user,1,1,1,0
access_mrp_bom_line_group_plan_director,mrp_bom_line_group_plan_director,mrp.model_mrp_bom_line,sf_base.group_plan_director,1,1,1,0 access_mrp_bom_line_group_plan_director,mrp_bom_line_group_plan_director,mrp.model_mrp_bom_line,sf_base.group_plan_director,1,1,1,0
access_mrp_bom_line_group_sf_stock_user,mrp_bom_line_group_sf_stock_user,mrp.model_mrp_bom_line,sf_base.group_sf_stock_user,1,1,1,0
access_mrp_bom_line_group_sale_director,mrp_bom_line_group_sale_director,mrp.model_mrp_bom_line,sf_base.group_sale_director,1,1,1,0 access_mrp_bom_line_group_sale_director,mrp_bom_line_group_sale_director,mrp.model_mrp_bom_line,sf_base.group_sale_director,1,1,1,0
access_mrp_bom_line_group_sale_salemanager,mrp_bom_line_group_sale_salemanager,mrp.model_mrp_bom_line,sf_base.group_sale_salemanager,1,0,1,0 access_mrp_bom_line_group_sale_salemanager,mrp_bom_line_group_sale_salemanager,mrp.model_mrp_bom_line,sf_base.group_sale_salemanager,1,0,1,0
access_mrp_bom_line_group_purchase_director,mrp_bom_line_group_purchase_director,mrp.model_mrp_bom_line,sf_base.group_purchase_director,1,1,1,0 access_mrp_bom_line_group_purchase_director,mrp_bom_line_group_purchase_director,mrp.model_mrp_bom_line,sf_base.group_purchase_director,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
52 access_mrp_bom_line_manager_group_sf_mrp_user mrp.bom.line.manager mrp.model_mrp_bom_line sf_base.group_sf_mrp_user 1 1 1 0
53 access_mrp_bom_line_group_plan_director mrp_bom_line_group_plan_director mrp.model_mrp_bom_line sf_base.group_plan_director 1 1 1 0
54 access_mrp_bom_line_group_sale_director access_mrp_bom_line_group_sf_stock_user mrp_bom_line_group_sale_director mrp_bom_line_group_sf_stock_user mrp.model_mrp_bom_line sf_base.group_sale_director sf_base.group_sf_stock_user 1 1 1 0
55 access_mrp_bom_line_group_sale_director mrp_bom_line_group_sale_director mrp.model_mrp_bom_line sf_base.group_sale_director 1 1 1 0
56 access_mrp_bom_line_group_sale_salemanager mrp_bom_line_group_sale_salemanager mrp.model_mrp_bom_line sf_base.group_sale_salemanager 1 0 1 0
57 access_mrp_bom_line_group_purchase_director mrp_bom_line_group_purchase_director mrp.model_mrp_bom_line sf_base.group_purchase_director 1 1 1 0
58 access_mrp_bom_byproduct_manager_group_sf_mrp_user mrp.bom.byproduct manager mrp.model_mrp_bom_byproduct sf_base.group_sf_mrp_user 1 1 1 0

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

@@ -745,5 +745,12 @@
groups="sf_base.group_plan_dispatch,sf_base.group_sf_mrp_manager" groups="sf_base.group_plan_dispatch,sf_base.group_sf_mrp_manager"
sequence="1"/> sequence="1"/>
<menuitem id="stock_picking_type_menu"
name="驾驶舱"
parent="stock.menu_stock_root"
action="stock.stock_picking_type_action"
groups="sf_base.group_sf_stock_user"
sequence="0"/>
</data> </data>
</odoo> </odoo>

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)
item.date_planned_finished = last_cnc_start + timedelta(
minutes=routing_workcenter.time_cycle)
item.date_planned_start = last_cnc_start
record.sudo().production_id.plan_start_processing_time = item.date_planned_start
item.duration_expected = routing_workcenter.time_cycle
pre_duration , next_duration = record.calculate_plan_time(item, workorder_list)
record.date_planned_finished = item.date_planned_finished
# 计算下一个cnc工单的开始时间
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]
last_wo_start = record.date_planned_start if record.date_planned_start else datetime.now()
routing_workcenter = record.env['mrp.routing.workcenter'].sudo().search(
[('name', '=', item.routing_type)], limit=1)
item.date_planned_start = datetime.now() - timedelta(days=100)
item.date_planned_finished = last_wo_start + timedelta(
minutes=routing_workcenter.time_cycle) minutes=routing_workcenter.time_cycle)
item.date_planned_start = last_wo_start first_cnc_workorder.date_planned_start = date_start
record.sudo().production_id.plan_start_processing_time = first_cnc_workorder.date_planned_start
first_cnc_workorder.duration_expected = routing_workcenter.time_cycle
record.calculate_plan_time(first_cnc_workorder, record.production_id.workorder_ids)
# 找到最后一张CNC加工工单
last_cnc_workorder = record.production_id.workorder_ids.filtered(lambda x: x.name == 'CNC加工')[-1]
record.date_planned_finished = last_cnc_workorder.date_planned_finished
else:
# 人工线下加工只排第一张工单
item = record.production_id.workorder_ids[0]
wo_start = record.date_planned_start if record.date_planned_start else datetime.now()
routing_workcenter = item.technology_design_id.route_id
item.date_planned_start = datetime.now() - timedelta(days=100)
item.date_planned_finished = wo_start + timedelta(
minutes=routing_workcenter.time_cycle)
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
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)
next_workorder.duration_expected = routing_workcenter.time_cycle next_workorder.duration_expected = routing_workcenter.time_cycle
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)
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
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

@@ -11,6 +11,7 @@ access_quality_point_group_sf_mrp_manager,quality_point_group_sf_mrp_manager,qua
access_quality_check_group_quality,quality_check_group_quality,quality.model_quality_check,sf_base.group_quality,1,1,1,0 access_quality_check_group_quality,quality_check_group_quality,quality.model_quality_check,sf_base.group_quality,1,1,1,0
access_quality_check_group_quality_director,quality_check_group_quality_director,quality.model_quality_check,sf_base.group_quality_director,1,1,1,0 access_quality_check_group_quality_director,quality_check_group_quality_director,quality.model_quality_check,sf_base.group_quality_director,1,1,1,0
access_quality_check_group_plan_dispatch,quality_check_group_plan_dispatch,quality.model_quality_check,sf_base.group_plan_dispatch,1,0,0,0 access_quality_check_group_plan_dispatch,quality_check_group_plan_dispatch,quality.model_quality_check,sf_base.group_plan_dispatch,1,0,0,0
access_quality_check_group_sf_stock_user,quality_check_group_sf_stock_user,quality.model_quality_check,sf_base.group_sf_stock_user,1,0,0,0
access_quality_check_group_plan_director,quality_check_group_plan_director,quality.model_quality_check,sf_base.group_plan_director,1,0,0,0 access_quality_check_group_plan_director,quality_check_group_plan_director,quality.model_quality_check,sf_base.group_plan_director,1,0,0,0
access_quality_check_group_purchase,quality_check_group_purchase,quality.model_quality_check,sf_base.group_purchase,1,0,0,0 access_quality_check_group_purchase,quality_check_group_purchase,quality.model_quality_check,sf_base.group_purchase,1,0,0,0
access_quality_check_group_purchase_director,quality_check_group_purchase_director,quality.model_quality_check,sf_base.group_purchase_director,1,0,0,0 access_quality_check_group_purchase_director,quality_check_group_purchase_director,quality.model_quality_check,sf_base.group_purchase_director,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
11 access_quality_check_group_quality_director quality_check_group_quality_director quality.model_quality_check sf_base.group_quality_director 1 1 1 0
12 access_quality_check_group_plan_dispatch quality_check_group_plan_dispatch quality.model_quality_check sf_base.group_plan_dispatch 1 0 0 0
13 access_quality_check_group_plan_director access_quality_check_group_sf_stock_user quality_check_group_plan_director quality_check_group_sf_stock_user quality.model_quality_check sf_base.group_plan_director sf_base.group_sf_stock_user 1 0 0 0
14 access_quality_check_group_plan_director quality_check_group_plan_director quality.model_quality_check sf_base.group_plan_director 1 0 0 0
15 access_quality_check_group_purchase quality_check_group_purchase quality.model_quality_check sf_base.group_purchase 1 0 0 0
16 access_quality_check_group_purchase_director quality_check_group_purchase_director quality.model_quality_check sf_base.group_purchase_director 1 0 0 0
17 access_quality_check_group_sf_equipment_user quality_check_group_sf_equipment_user quality.model_quality_check sf_base.group_sf_equipment_user 1 0 0 0