Accept Merge Request #1061: (feature/优化制造订单报废流程 -> develop)

Merge Request: 优化部分制造订单报废流程

Created By: @杨金灵
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @杨金灵
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1061
This commit is contained in:
杨金灵
2024-06-05 15:53:56 +08:00
committed by Coding
6 changed files with 113 additions and 55 deletions

View File

@@ -215,7 +215,7 @@ class Manufacturing_Connect(http.Controller):
if workorder.state != 'progress': if workorder.state != 'progress':
res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单未开始'} res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单未开始'}
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
workorder.button_finish() workorder.write({'date_finished': datetime.now()})
# workorder.process_state = '待解除装夹' # workorder.process_state = '待解除装夹'
# workorder.sudo().production_id.process_state = '待解除装夹' # workorder.sudo().production_id.process_state = '待解除装夹'

View File

@@ -77,6 +77,7 @@ class MrpProduction(models.Model):
part_drawing = fields.Binary('零件图纸') part_drawing = fields.Binary('零件图纸')
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
rework_production = fields.Many2one('mrp.production', string='返工的制造订单')
@api.depends( @api.depends(
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state', 'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state',
@@ -154,8 +155,30 @@ class MrpProduction(models.Model):
for production in self: for production in self:
production.maintenance_count = len(production.request_ids) production.maintenance_count = len(production.request_ids)
# 制造订单报废:编程单更新
def updateCNC(self):
try:
res = {'production_no': self.name, 'programming_no': self.programming_no,
'order_no': self.origin}
logging.info('res=%s:' % res)
configsettings = self.env['res.config.settings'].get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/intelligent_programming/update_intelligent_programmings'
config_url = configsettings['sf_url'] + url
res['token'] = configsettings['token']
ret = requests.post(config_url, json={}, data=res, headers=config_header)
ret = ret.json()
logging.info('updateCNC-ret:%s' % ret)
if ret['status'] == 1:
self.write({'work_state': '已编程'})
else:
raise UserError(ret['message'])
except Exception as e:
logging.info('updateCNC error:%s' % e)
raise UserError("更新程单失败,请联系管理员")
# cnc程序获取 # cnc程序获取
def fetchCNC(self, production_names): def fetchCNC(self, production_names, scrap_production):
cnc = self.env['mrp.production'].search([('id', '=', self.id)]) cnc = self.env['mrp.production'].search([('id', '=', self.id)])
quick_order = self.env['quick.easy.order'].search( quick_order = self.env['quick.easy.order'].search(
[('name', '=', cnc.product_id.default_code.rsplit('-', 1)[0])]) [('name', '=', cnc.product_id.default_code.rsplit('-', 1)[0])])
@@ -171,6 +194,8 @@ class MrpProduction(models.Model):
'production_no': production_names, 'production_no': production_names,
'machine_tool_code': '', 'machine_tool_code': '',
'product_name': cnc.product_id.name, 'product_name': cnc.product_id.name,
'remanufacture_type': '' if not scrap_production else scrap_production.workorder_ids.filtered(
lambda b: b.routing_type == "CNC加工").test_results,
'model_code': cnc.product_id.model_code, 'model_code': cnc.product_id.model_code,
'material_code': self.env['sf.production.materials'].search( 'material_code': self.env['sf.production.materials'].search(
[('id', '=', cnc.product_id.materials_id.id)]).materials_no, [('id', '=', cnc.product_id.materials_id.id)]).materials_no,
@@ -268,7 +293,7 @@ class MrpProduction(models.Model):
# 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制; # 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制;
# 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心; # 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心;
def _create_workorder3(self): def _create_workorder3(self, is_fetchcnc=False, scrap_production=False):
# 根据product_id对self进行分组 # 根据product_id对self进行分组
grouped_product_ids = {k: list(g) for k, g in groupby(self, key=lambda x: x.product_id.id)} grouped_product_ids = {k: list(g) for k, g in groupby(self, key=lambda x: x.product_id.id)}
# 初始化一个字典来存储每个product_id对应的生产订单名称列表 # 初始化一个字典来存储每个product_id对应的生产订单名称列表
@@ -311,11 +336,16 @@ class MrpProduction(models.Model):
production_programming = self.search( production_programming = self.search(
[('product_id.id', '=', production.product_id.id), ('origin', '=', production.origin)], [('product_id.id', '=', production.product_id.id), ('origin', '=', production.origin)],
limit=1, order='id asc') limit=1, order='id asc')
if not production_programming.programming_no: if not production_programming.programming_no or (is_fetchcnc is True and scrap_production):
production.fetchCNC(', '.join(product_id_to_production_names[production.product_id.id])) # 制造订单报废/返工也需重新编程
if (is_fetchcnc is True and scrap_production) or (
is_fetchcnc is False and scrap_production):
production.fetchCNC(', '.join(product_id_to_production_names[production.product_id.id]),
scrap_production)
else: else:
production.write({'programming_no': production_programming.programming_no, production.write({'programming_no': production_programming.programming_no,
'programming_state': '已编程' if production_programming.programming_state == '已编程' else '编程中'}) 'programming_state': '编程中'})
# # 根据加工面板的面数及对应的工序模板生成工单 # # 根据加工面板的面数及对应的工序模板生成工单
i = 0 i = 0
processing_panel_len = len(production.product_id.model_processing_panel.split(',')) processing_panel_len = len(production.product_id.model_processing_panel.split(','))
@@ -527,8 +557,8 @@ class MrpProduction(models.Model):
# work.button_finish() # work.button_finish()
# 创建工单并进行排序 # 创建工单并进行排序
def _create_workorder(self): def _create_workorder(self, is_fetchcnc=False, scrap_production=False):
self._create_workorder3() self._create_workorder3(is_fetchcnc=is_fetchcnc, scrap_production=scrap_production)
self._reset_work_order_sequence() self._reset_work_order_sequence()
return True return True

View File

@@ -199,7 +199,12 @@ class ResMrpWorkOrder(models.Model):
production_line_state = fields.Selection(related='production_id.production_line_state', production_line_state = fields.Selection(related='production_id.production_line_state',
string='上/下产线', store=True) string='上/下产线', store=True)
detection_report = fields.Binary('检测报告', readonly=True) detection_report = fields.Binary('检测报告', readonly=True)
is_remanufacture = fields.Boolean(string='是否重新生成制造订单', default=True) is_remanufacture = fields.Boolean(string='重新生成制造订单', default=False)
is_fetchcnc = fields.Boolean(string='重新获取NC程序', default=False)
reason = fields.Selection(
[("programming", "编程"), ("clamping", "返工"), ("cutter", "刀具"), ("operate computer", "操机"),
("technology", "工艺"), ("customer redrawing", "客户改图"), ("other", "其他"), ], string="原因")
detailed_reason = fields.Text('详细原因')
@api.onchange('rfid_code') @api.onchange('rfid_code')
def _onchange(self): def _onchange(self):
@@ -672,14 +677,14 @@ class ResMrpWorkOrder(models.Model):
""" """
重新生成制造订单或者重新生成工单 重新生成制造订单或者重新生成工单
""" """
if self.test_results == '报废': if self.test_results in ['返工', '报废']:
values = self.env['mrp.production'].create_production1_values(self.production_id) values = self.env['mrp.production'].create_production1_values(self.production_id)
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company( productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(
self.production_id.company_id).create( self.production_id.company_id).create(
values) values)
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) # self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
productions._create_workorder() productions._create_workorder(is_fetchcnc=self.is_fetchcnc, scrap_production=self.production_id)
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \ productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
( (
p.move_dest_ids.procure_method != 'make_to_order' and p.move_dest_ids.procure_method != 'make_to_order' and
@@ -761,6 +766,7 @@ class ResMrpWorkOrder(models.Model):
sale_order = self.env['sale.order'].sudo().search([('name', '=', productions.origin)]) sale_order = self.env['sale.order'].sudo().search([('name', '=', productions.origin)])
if sale_order: if sale_order:
sale_order.mrp_production_ids |= productions
# sale_order.write({'schedule_status': 'to schedule'}) # sale_order.write({'schedule_status': 'to schedule'})
self.env['sf.production.plan'].sudo().with_company(self.production_id.company_id).create({ self.env['sf.production.plan'].sudo().with_company(self.production_id.company_id).create({
'name': productions.name, 'name': productions.name,
@@ -772,13 +778,13 @@ class ResMrpWorkOrder(models.Model):
'product_id': productions.product_id.id, 'product_id': productions.product_id.id,
'state': 'draft', 'state': 'draft',
}) })
if self.test_results == '返工': # if self.test_results == '返工':
productions = self.production_id # productions = self.production_id
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) # # self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
# self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) # # self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
productions._create_workorder2(self.processing_panel) # productions._create_workorder2(self.processing_panel)
else: # else:
self.results = '合格' # self.results = '合格'
def json_workorder_str1(self, k, production, route): def json_workorder_str1(self, k, production, route):
workorders_values_str = [0, '', { workorders_values_str = [0, '', {
@@ -803,29 +809,28 @@ class ResMrpWorkOrder(models.Model):
}] }]
return workorders_values_str return workorders_values_str
@api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state') # @api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state')
def _compute_state(self): # def _compute_state(self):
super(ResMrpWorkOrder, self)._compute_state() # super(ResMrpWorkOrder, self)._compute_state()
for item in self: # for item in self:
scrap_workorder = self.env['mrp.workorder'].search( # print(item.name)
[('production_id', '=', item.production_id.id), ('routing_type', '=', 'CNC加工'), # print(item.state)
('state', '=', 'done'), ('is_remanufacture', '=', True)]) # print(item.is_remanufacture)
print(item.name) # scrap_workorder = self.env['mrp.workorder'].search(
print(item.state) # [('production_id', '=', item.production_id.id), ('routing_type', '=', 'CNC加工'),
if item.name == 'CNC加工(返工)' and item.state not in ['ready', 'progress', 'done']: # ('state', '=', 'done'), ('test_results', 'in', ['返工', '报废'])])
item.state = 'ready' # print(scrap_workorder)
if item.routing_type == '解除装夹': # # if item.routing_type == 'CNC加工' and item.state in ['done'] and item.test_results in ['返工', '报废']:
last_workorder = self.env['mrp.workorder'].search( # if item.routing_type == '解除装夹':
[('production_id', '=', item.production_id.id), ('name', '=', 'CNC加工(返工)'), # if scrap_workorder and item.state not in ['cancel']:
('state', '!=', 'done')]) # item.state = 'cancel'
if item.state != 'pending': # elif item.routing_type == '表面工艺':
if last_workorder: # if scrap_workorder:
item.state = 'pending' # stock_move = self.env['stock.move'].search(
if scrap_workorder: # [('origin', '=', item.production_id.name)])
item.state = 'cancel' # stock_move.write({'state': 'cancel'})
elif item.routing_type == '表面工艺': # item.picking_ids.write({'state': 'cancel'})
if scrap_workorder: # item.state = 'cancel'
item.state = 'cancel'
# 重写工单开始按钮方法 # 重写工单开始按钮方法
def button_start(self): def button_start(self):
@@ -982,6 +987,7 @@ class ResMrpWorkOrder(models.Model):
raise UserError( raise UserError(
'请先在产品中配置表面工艺为%s相关的外协服务产品' % item.surface_technics_parameters_id.name) '请先在产品中配置表面工艺为%s相关的外协服务产品' % item.surface_technics_parameters_id.name)
tem_date_planned_finished = record.date_planned_finished tem_date_planned_finished = record.date_planned_finished
tem_date_finished = record.date_finished
logging.info('routing_type:%s' % record.routing_type) logging.info('routing_type:%s' % record.routing_type)
super().button_finish() super().button_finish()
logging.info('date_planned_finished:%s' % record.date_planned_finished) logging.info('date_planned_finished:%s' % record.date_planned_finished)
@@ -990,8 +996,15 @@ class ResMrpWorkOrder(models.Model):
record.write({ record.write({
'date_planned_finished': tem_date_planned_finished # 保持原值 'date_planned_finished': tem_date_planned_finished # 保持原值
}) })
if record.routing_type == 'CNC加工':
record.write({
'date_finished': tem_date_finished # 保持原值
})
if record.routing_type == 'CNC加工' and record.test_results in ['返工', '报废']: if record.routing_type == 'CNC加工' and record.test_results in ['返工', '报废']:
record.recreateManufacturingOrWorkerOrder() record.production_id.action_cancel()
record.production_id.workorder_ids.write({'rfid_code': False, 'rfid_code_old': record.rfid_code})
if record.is_remanufacture is True:
record.recreateManufacturingOrWorkerOrder()
is_production_id = True is_production_id = True
for workorder in record.production_id.workorder_ids: for workorder in record.production_id.workorder_ids:
if workorder.state != 'done': if workorder.state != 'done':
@@ -1132,19 +1145,27 @@ class CNCprocessing(models.Model):
# 根据程序名和加工面匹配到ftp里对应的Nc程序名,可优化为根据cnc_processing.program_path进行匹配 # 根据程序名和加工面匹配到ftp里对应的Nc程序名,可优化为根据cnc_processing.program_path进行匹配
def get_cnc_processing_file(self, serverdir, cnc_processing, program_path): def get_cnc_processing_file(self, serverdir, cnc_processing, program_path):
logging.info('serverdir:%s' % serverdir) logging.info('serverdir:%s' % serverdir)
logging.info('cnc_processing:%s' % cnc_processing)
for root, dirs, files in os.walk(serverdir): for root, dirs, files in os.walk(serverdir):
for f in files: for f in files:
logging.info('splitext(f):%s' % os.path.splitext(f)[1])
if os.path.splitext(f)[1] == ".pdf": if os.path.splitext(f)[1] == ".pdf":
full_path = os.path.join(serverdir, root, f) full_path = os.path.join(serverdir, root, f)
if full_path is not False: logging.info('full_path:%s' % full_path)
if not cnc_processing.workorder_id.cnc_worksheet: logging.info('routing_type:%s' % cnc_processing.workorder_id.routing_type)
cnc_processing.workorder_id.cnc_worksheet = base64.b64encode( logging.info('cnc_worksheet:%s' % cnc_processing.workorder_id.cnc_worksheet)
open(full_path, 'rb').read()) # with open(full_path, 'rb') as pdf_file:
else: # file_content = pdf_file.read()
if f in program_path: # cnc_processing.workorder_id.cnc_worksheet = base64.b64encode(file_content)
# if cnc_processing.program_name == f.split('.')[0]: if not cnc_processing.workorder_id.cnc_worksheet:
cnc_file_path = os.path.join(serverdir, root, f) logging.info('full_path111555:%s' % full_path)
self.write_file(cnc_file_path, cnc_processing) cnc_processing.workorder_id.cnc_worksheet = base64.b64encode(
open(full_path, 'rb').read())
else:
if f in program_path:
# if cnc_processing.program_name == f.split('.')[0]:
cnc_file_path = os.path.join(serverdir, root, f)
self.write_file(cnc_file_path, cnc_processing)
# 创建附件(nc文件) # 创建附件(nc文件)
def attachment_create(self, name, data): def attachment_create(self, name, data):

View File

@@ -207,7 +207,7 @@ class StockRule(models.Model):
''' '''
创建工单 创建工单
''' '''
productions._create_workorder() productions._create_workorder(is_fetchcnc=False, scrap_production=False)
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \ productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
( (
@@ -631,8 +631,8 @@ class ReStockMove(models.Model):
'reserved_uom_qty': 1.0, 'reserved_uom_qty': 1.0,
'lot_id': purchase.picking_ids.move_line_ids.lot_id.id, 'lot_id': purchase.picking_ids.move_line_ids.lot_id.id,
'company_id': self.company_id.id, 'company_id': self.company_id.id,
'workorder_id': '' if not sorted_workorders else sorted_workorders.id, # 'workorder_id': '' if not sorted_workorders else sorted_workorders.id,
'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id, # 'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id,
'state': 'assigned', 'state': 'assigned',
} }

View File

@@ -214,7 +214,7 @@
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
<field name="functional_fixture_type_id" <field name="functional_fixture_type_id"
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
<field name="rfid_code" force_save="1" readonly="1" cache="True" <field name="rfid_code" cache="True"
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/> attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/> <field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
</group> </group>
@@ -478,6 +478,11 @@
<group> <group>
<field name="test_results" attrs='{"invisible":[("results","!=",False)]}'/> <field name="test_results" attrs='{"invisible":[("results","!=",False)]}'/>
<field name="is_remanufacture" attrs='{"invisible":[("test_results","!=","报废")]}'/> <field name="is_remanufacture" attrs='{"invisible":[("test_results","!=","报废")]}'/>
<field name="is_fetchcnc"
attrs='{"invisible":["|",("test_results","=","合格"),("is_remanufacture","=",False)]}'/>
<field name="reason"
attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")]}'/>
<field name="detailed_reason" attrs='{"invisible":[("test_results","=","合格")]}'/>
<field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/> <field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>
<field name="detection_report" attrs='{"invisible":[("results","!=",False)]}' <field name="detection_report" attrs='{"invisible":[("results","!=",False)]}'
widget="pdf_viewer"/> widget="pdf_viewer"/>

View File

@@ -46,6 +46,8 @@ class FtpController():
os.makedirs(serverdir) os.makedirs(serverdir)
try: try:
logging.info("进入FTP目录 ") logging.info("进入FTP目录 ")
self.ftp.pwd()
logging.info('当前目录:%s' % self.ftp.pwd())
logging.info('目录:%s' % target_dir) logging.info('目录:%s' % target_dir)
target_dir1 = target_dir.split('/') target_dir1 = target_dir.split('/')
logging.info('目录1:%s' % target_dir1[1]) logging.info('目录1:%s' % target_dir1[1])