AGV任务调度开发
This commit is contained in:
@@ -41,7 +41,8 @@
|
||||
'web.assets_backend': [
|
||||
'sf_manufacturing/static/src/xml/kanban_change.xml',
|
||||
'sf_manufacturing/static/src/js/kanban_change.js',
|
||||
'sf_manufacturing/static/src/scss/kanban_change.scss'
|
||||
'sf_manufacturing/static/src/scss/kanban_change.scss',
|
||||
'sf_manufacturing/static/src/xml/button_show_on_tree.xml',
|
||||
]
|
||||
|
||||
},
|
||||
|
||||
@@ -450,9 +450,8 @@ class Manufacturing_Connect(http.Controller):
|
||||
if 'DeviceId' in ret:
|
||||
logging.info('DeviceId:%s' % ret['DeviceId'])
|
||||
if 'IsComplete' in ret:
|
||||
first_rfid_code = None
|
||||
production_ids = []
|
||||
workpiece_validate = True
|
||||
rfid_codes = []
|
||||
workorder_ids = []
|
||||
if ret['IsComplete'] is True or ret['IsComplete'] is False:
|
||||
for i in range(1, 5):
|
||||
logging.info('F-RfidCode:%s' % i)
|
||||
@@ -460,7 +459,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
rfid_code = ret[f'RfidCode{i}']
|
||||
logging.info('RfidCode:%s' % rfid_code)
|
||||
if rfid_code is not None:
|
||||
first_rfid_code = first_rfid_code or rfid_code
|
||||
rfid_codes.append(rfid_code)
|
||||
domain = [
|
||||
('rfid_code', '=', rfid_code),
|
||||
('routing_type', '=', 'CNC加工'), ('state', '!=', 'rework')
|
||||
@@ -468,7 +467,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
workorder = request.env['mrp.workorder'].sudo().search(domain, order='id asc')
|
||||
if workorder:
|
||||
for order in workorder:
|
||||
production_ids.append(order.production_id.id)
|
||||
workorder_ids.append(order.id)
|
||||
if order.production_line_state == '待上产线':
|
||||
logging.info(
|
||||
'工单产线状态:%s' % order.production_line_state)
|
||||
@@ -487,19 +486,27 @@ class Manufacturing_Connect(http.Controller):
|
||||
# workpiece_delivery.write({'is_manual_work': True})
|
||||
# 下发
|
||||
else:
|
||||
workpiece_validate = False
|
||||
res = {'Succeed': False, 'ErrorCode': 204,
|
||||
'Error': 'DeviceId为%s没有对应的已配送工件数据' % ret['DeviceId']}
|
||||
if ret['IsComplete'] is True:
|
||||
# 将RFID_CODE对应的工件配送单对应的AGV任务调度状态设置为已配送
|
||||
request.env['sf.workpiece.delivery'].sudo().search(
|
||||
[('rfid_code', '=', first_rfid_code)]).agv_scheduling_id.write({'state': '已配送'})
|
||||
# workorder_id = request.env['mrp.workorder'].sudo().search([
|
||||
# ('rfid_code', 'in', rfid_codes),
|
||||
# ('routing_type', '=', '装夹预调'), ('state', '!=', 'rework')
|
||||
# ])
|
||||
# workorder_id.agv_scheduling_ids.finish_scheduling()
|
||||
# 将工件配送单状态设置为已配送
|
||||
request.env['sf.workpiece.delivery'].sudo().search([
|
||||
('rfid_code', 'in', rfid_codes),
|
||||
('type', '=', '上产线'),
|
||||
('status', '=', '已下发')
|
||||
]).write({'state': '已配送'})
|
||||
# 向AGV任务调度下发运送空料架任务
|
||||
productions = request.env['mrp.production'].sudo().search([('id', 'in', production_ids)])
|
||||
# 获取设备ID对应的接驳站配置
|
||||
agv_site = request.env['sf.agv.site'].sudo().search(
|
||||
[('name', '=', ret['DeviceId'])], limit=1)
|
||||
request.env['sf.agv.scheduling'].add_scheduling(agv_site.id, '运送空料架', productions)
|
||||
workorders = request.env['mrp.workorder'].browse(workorder_ids)
|
||||
request.env['sf.agv.scheduling'].add_scheduling(agv_site.id, '运送空料架', workorders)
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '未传IsComplete字段'}
|
||||
else:
|
||||
@@ -511,7 +518,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('AGVToProduct error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@http.route('/AutoDeviceApi/AGVDownProduct', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/AGVDownProduct', type='json', auth='public', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def AGVDownProduct(self, **kw):
|
||||
"""
|
||||
@@ -530,7 +537,8 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('ret:%s' % ret)
|
||||
if 'DeviceId' in ret:
|
||||
logging.info('DeviceId:%s' % ret['DeviceId'])
|
||||
delivery_Arr = []
|
||||
# delivery_Arr = []
|
||||
workorder_ids = []
|
||||
if 'IsComplete' in ret:
|
||||
if ret['IsComplete'] is True or ret['IsComplete'] is False:
|
||||
for i in range(1, 5):
|
||||
@@ -546,6 +554,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
workorder = request.env['mrp.workorder'].sudo().search(domain, order='id asc')
|
||||
if workorder:
|
||||
for order in workorder:
|
||||
workorder_ids.append(order.id)
|
||||
if order.production_line_state == '已上产线':
|
||||
logging.info(
|
||||
'工单产线状态:%s' % order.production_line_state)
|
||||
@@ -555,33 +564,42 @@ class Manufacturing_Connect(http.Controller):
|
||||
if panel_workorder:
|
||||
panel_workorder.write({'production_line_state': '已下产线'})
|
||||
workorder.write({'state': 'to be detected'})
|
||||
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
|
||||
[
|
||||
('rfid_code', '=', rfid_code), ('type', '=', '下产线'),
|
||||
('production_id', '=', order.production_id.id),
|
||||
('workorder_id', '=', order.id),
|
||||
('workorder_state', '=', 'done')])
|
||||
if workpiece_delivery:
|
||||
delivery_Arr.append(workpiece_delivery.id)
|
||||
# workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
|
||||
# [
|
||||
# ('rfid_code', '=', rfid_code), ('type', '=', '下产线'),
|
||||
# ('production_id', '=', order.production_id.id),
|
||||
# ('workorder_id', '=', order.id),
|
||||
# ('workorder_state', '=', 'done')])
|
||||
# if workpiece_delivery:
|
||||
# delivery_Arr.append(workpiece_delivery.id)
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 204,
|
||||
'Error': 'DeviceId为%s没有对应的已配送工件数据' % ret['DeviceId']}
|
||||
if delivery_Arr:
|
||||
logging.info('delivery_Arr:%s' % delivery_Arr)
|
||||
delivery_workpiece = request.env['sf.workpiece.delivery'].sudo().search(
|
||||
[('id', 'in', delivery_Arr)])
|
||||
if delivery_workpiece:
|
||||
logging.info('开始向agv下发下产线任务')
|
||||
agv_site = request.env['sf.agv.site'].sudo().search([])
|
||||
if agv_site:
|
||||
has_site = agv_site.update_site_state()
|
||||
if has_site is True:
|
||||
is_free = delivery_workpiece._check_avgsite_state()
|
||||
if is_free is True:
|
||||
delivery_workpiece._delivery_avg()
|
||||
logging.info('agv下发下产线任务下发完成')
|
||||
# if delivery_Arr:
|
||||
# logging.info('delivery_Arr:%s' % delivery_Arr)
|
||||
# delivery_workpiece = request.env['sf.workpiece.delivery'].sudo().search(
|
||||
# [('id', 'in', delivery_Arr)])
|
||||
# if delivery_workpiece:
|
||||
# logging.info('开始向agv下发下产线任务')
|
||||
# agv_site = request.env['sf.agv.site'].sudo().search([])
|
||||
# if agv_site:
|
||||
# has_site = agv_site.update_site_state()
|
||||
# if has_site is True:
|
||||
# is_free = delivery_workpiece._check_avgsite_state()
|
||||
# if is_free is True:
|
||||
# delivery_workpiece._delivery_avg()
|
||||
# logging.info('agv下发下产线任务下发完成')
|
||||
if ret['IsComplete'] is True:
|
||||
# 向AGV任务调度下发下产线任务
|
||||
# 获取设备ID对应的接驳站配置
|
||||
agv_site = request.env['sf.agv.site'].sudo().search(
|
||||
[('name', '=', ret['DeviceId'])], limit=1)
|
||||
workorders = request.env['mrp.workorder'].browse(workorder_ids)
|
||||
request.env['sf.agv.scheduling'].add_scheduling(agv_site.id, '下产线', workorders)
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '未传IsComplete字段'}
|
||||
except RepeatTaskException as e:
|
||||
logging.info('AGVToProduct error:%s' % e)
|
||||
except Exception as e:
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
|
||||
logging.info('AGVDownProduct error:%s' % e)
|
||||
@@ -640,7 +658,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('ret:%s' % ret)
|
||||
if 'DeviceId' in ret and 'AtHome' in ret:
|
||||
logging.info('DeviceId:%s, AtHome:%s' % (ret['DeviceId'], ret['AtHome']))
|
||||
request.env['sf.agv.site'].update_site_state(ret['DeviceId'], ret['AtHome'])
|
||||
request.env['sf.agv.site'].update_site_state({ret['DeviceId']: '占用' if ret['AtHome'] else '空闲'})
|
||||
except Exception as e:
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': str(e)}
|
||||
logging.info('AGVDownProduct error:%s' % e)
|
||||
|
||||
@@ -31,8 +31,7 @@ class AgvScheduling(models.Model):
|
||||
('配送中', '配送中'),
|
||||
('已配送', '已配送'),
|
||||
('已取消', '已取消')], string='状态', default='待下发', tracking=True)
|
||||
workorder_ids = fields.One2many('mrp.workorder', string='关联工单')
|
||||
delivery_workpieces = fields.Char('配送工件', required=True, index=True)
|
||||
workorder_ids = fields.Many2many('mrp.workorder', 'sf_agv_scheduling_mrp_workorder_ref', string='关联工单')
|
||||
task_create_time = fields.Datetime('任务创建时间')
|
||||
task_delivery_time = fields.Datetime('任务下发时间')
|
||||
task_completion_time = fields.Datetime('任务完成时间')
|
||||
@@ -41,13 +40,12 @@ class AgvScheduling(models.Model):
|
||||
@api.depends('agv_route_type')
|
||||
def _compute_delivery_workpieces(self):
|
||||
for record in self:
|
||||
record.delivery_workpieces = '、'.join(record.workorder_ids.mapped('production_id.name'))
|
||||
if record.agv_route_type == '运送空料架':
|
||||
record.delivery_workpieces_display = '/'
|
||||
record.delivery_workpieces = '/'
|
||||
else:
|
||||
record.delivery_workpieces_display = record.delivery_workpieces
|
||||
record.delivery_workpieces = '、'.join(record.workorder_ids.mapped('production_id.name'))
|
||||
|
||||
delivery_workpieces_display = fields.Char('配送工件', compute=_compute_delivery_workpieces)
|
||||
delivery_workpieces = fields.Char('配送工件', compute=_compute_delivery_workpieces)
|
||||
|
||||
@api.depends('task_completion_time', 'task_delivery_time')
|
||||
def _compute_task_duration(self):
|
||||
@@ -64,28 +62,35 @@ class AgvScheduling(models.Model):
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code('sf.agv.scheduling') or _('New')
|
||||
return super().create(vals_list)
|
||||
|
||||
def add_scheduling(self, agv_start_site_id, agv_route_type, productions, deliveries=None):
|
||||
""" add_scheduling(agv_start_site_id, agv_route_type, productions, deliveries) -> agv_scheduling
|
||||
def add_scheduling(self, agv_start_site_id, agv_route_type, workorders):
|
||||
""" add_scheduling(agv_start_site_id, agv_route_type, workorders) -> agv_scheduling
|
||||
新增AGV调度
|
||||
params:
|
||||
agv_start_site_id: AGV起点接驳站ID
|
||||
agv_route_type: AGV任务类型
|
||||
productions: 制造订单
|
||||
deliveries: 工件配送单
|
||||
workorders: 工单
|
||||
"""
|
||||
# 如果存在配送工件完全相同的AGV调度任务,则不新增
|
||||
if self.sudo().search([
|
||||
('delivery_workpieces', '=', '、'.join(productions.mapped('name'))),
|
||||
if not workorders:
|
||||
raise UserError(_('工单不能为空'))
|
||||
# 如果存在相同任务类型工单的AGV调度任务,则提示错误
|
||||
agv_scheduling = self.sudo().search([
|
||||
('workorder_ids', 'in', workorders.ids),
|
||||
('agv_route_type', '=', agv_route_type),
|
||||
('state', 'in', ['待下发', '配送中'])
|
||||
], limit=1):
|
||||
raise RepeatTaskException('已存在相同的AGV调度任务,请勿重复下发!')
|
||||
], limit=1)
|
||||
if agv_scheduling:
|
||||
# 计算agv_scheduling.workorder_ids与workorders的交集
|
||||
repetitive_workorders = agv_scheduling.workorder_ids & workorders
|
||||
raise RepeatTaskException(
|
||||
'制造订单号【%s】已存在与【%s】AGV调度任务,请勿重复下发!' %
|
||||
(','.join(repetitive_workorders.mapped('production_id.name')), agv_scheduling.name)
|
||||
)
|
||||
|
||||
vals = {
|
||||
'start_site_id': agv_start_site_id,
|
||||
'agv_route_type': agv_route_type,
|
||||
'delivery_workpieces': '、'.join(productions.mapped('name')),
|
||||
'workpiece_delivery_ids': deliveries.mapped('id') if deliveries else [],
|
||||
'workorder_ids': workorders.ids,
|
||||
# 'workpiece_delivery_ids': deliveries.mapped('id') if deliveries else [],
|
||||
'task_create_time': fields.Datetime.now()
|
||||
}
|
||||
# 如果只有唯一任务路线,则自动赋予终点接驳站跟任务名称
|
||||
@@ -95,26 +100,52 @@ class AgvScheduling(models.Model):
|
||||
])
|
||||
if len(agv_routes) == 1:
|
||||
vals.update({'end_site_id': agv_routes[0].end_site_id.id, 'agv_route_name': agv_routes[0].name})
|
||||
else:
|
||||
# 判断终点接驳站是否为空闲
|
||||
idle_routes = agv_routes.filtered(lambda r: r.end_site_id.state == '空闲')
|
||||
if idle_routes:
|
||||
# 将空闲的路线按照终点接驳站名称排序
|
||||
idle_routes = sorted(idle_routes, key=lambda r: r.end_site_id.name)
|
||||
vals.update({'end_site_id': idle_routes[0].end_site_id.id, 'agv_route_name': idle_routes[0].name})
|
||||
try:
|
||||
dispatch = self.env['sf.agv.scheduling'].sudo().create(vals)
|
||||
scheduling = self.env['sf.agv.scheduling'].sudo().create(vals)
|
||||
# 触发空闲接驳站状态更新,触发新任务下发
|
||||
if scheduling.end_site_id.state == '空闲':
|
||||
scheduling.dispatch_scheduling(scheduling.end_site_id.id, scheduling.end_site_id.state)
|
||||
|
||||
except Exception as e:
|
||||
_logger.error('添加AGV调度任务失败: %s', e)
|
||||
raise UserError(_('添加AGV调度任务失败: %s', e))
|
||||
|
||||
return dispatch
|
||||
return scheduling
|
||||
|
||||
def on_site_state_change(self, agv_site_id, agv_site_state):
|
||||
agv_schedulings = self.env['sf.agv.scheduling'].sudo().search([('state', '=', '待下发')], order='id asc')
|
||||
for scheduling in agv_schedulings:
|
||||
if scheduling.end_site_id.id == agv_site_id and scheduling.site_state == '空闲':
|
||||
"""
|
||||
响应AGV接驳站站点状态变化
|
||||
params:
|
||||
agv_site_id: 接驳站ID
|
||||
agv_site_state: 站点状态('空闲', '占用')
|
||||
"""
|
||||
if agv_site_state == '空闲':
|
||||
# 查询终点接驳站为agv_site_id的AGV路线
|
||||
task_routes = self.env['sf.agv.task.route'].sudo().search([('end_site_id', '=', agv_site_id)])
|
||||
agv_scheduling = self.env['sf.agv.scheduling'].sudo().search(
|
||||
[('state', '=', '待下发'), ('agv_route_type', 'in', task_routes.mapped('route_type'))],
|
||||
order='id asc',
|
||||
limit=1
|
||||
)
|
||||
# 下发AGV调度任务并修改接驳站状态为占用
|
||||
# self._delivery_avg()
|
||||
# 修改AGV调度任务信息
|
||||
scheduling.state = '配送中'
|
||||
scheduling.task_delivery_time = fields.Datetime.now()
|
||||
scheduling.site_state = agv_site_state
|
||||
agv_scheduling.dispatch_scheduling(agv_site_id, agv_site_state)
|
||||
# 更新接驳站状态
|
||||
self.env['sf.agv.site'].update_site_state(scheduling.end_site_id.name, True)
|
||||
self.env['sf.agv.site'].update_site_state({agv_scheduling.end_site_id.name: '占用'}, False)
|
||||
else:
|
||||
# 如果终点接驳站变为占用,则认为任务完成
|
||||
agv_scheduling = self.env['sf.agv.scheduling'].sudo().search(
|
||||
[('state', '=', '配送中'), ('end_site_id', '=', agv_site_id)],
|
||||
order='id asc',
|
||||
limit=1
|
||||
)
|
||||
agv_scheduling.finish_scheduling()
|
||||
|
||||
def _delivery_avg(self):
|
||||
config = self.env['res.config.settings'].get_values()
|
||||
@@ -190,3 +221,36 @@ class AgvScheduling(models.Model):
|
||||
if rec.state != '待下发':
|
||||
raise UserError('只有待下发状态的AGV调度任务才能取消!')
|
||||
rec.state = '已取消'
|
||||
|
||||
def finish_scheduling(self):
|
||||
"""
|
||||
完成调度任务
|
||||
"""
|
||||
for rec in self:
|
||||
if rec.state != '配送中':
|
||||
return False
|
||||
rec.state = '已配送'
|
||||
rec.task_completion_time = fields.Datetime.now()
|
||||
|
||||
def dispatch_scheduling(self, agv_end_site_id, agv_site_state):
|
||||
"""
|
||||
下发调度任务
|
||||
"""
|
||||
for rec in self:
|
||||
if rec.state != '待下发':
|
||||
return False
|
||||
# rec._delivery_avg()
|
||||
rec.state = '配送中'
|
||||
rec.task_delivery_time = fields.Datetime.now()
|
||||
rec.site_state = agv_site_state
|
||||
rec.end_site_id = agv_end_site_id
|
||||
|
||||
|
||||
class ResMrpWorkOrder(models.Model):
|
||||
_inherit = 'mrp.workorder'
|
||||
|
||||
agv_scheduling_ids = fields.Many2many(
|
||||
'sf.agv.scheduling',
|
||||
'sf_agv_scheduling_mrp_workorder_ref',
|
||||
string='AGV调度',
|
||||
domain=[('state', '!=', '已取消')])
|
||||
|
||||
@@ -5,6 +5,8 @@ import time
|
||||
from odoo import fields, models, api
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AgvSetting(models.Model):
|
||||
_name = 'sf.agv.site'
|
||||
@@ -57,13 +59,22 @@ class AgvSetting(models.Model):
|
||||
# logging.error('工件配送-请求中控接口错误: %s', e)
|
||||
# return False
|
||||
|
||||
def update_site_state(self, agv_site_name, is_occupy):
|
||||
if agv_site_name:
|
||||
def update_site_state(self, agv_site_state_arr, notify=True):
|
||||
"""
|
||||
更新接驳站状态
|
||||
params:
|
||||
agv_site_state_arr: {'A01': '空闲', 'B01': '占用'}
|
||||
notify: 是否通知调度(非中控发起的状态改变不触发调度任务)
|
||||
"""
|
||||
if isinstance(agv_site_state_arr, dict):
|
||||
for agv_site_name, is_occupy in agv_site_state_arr.items():
|
||||
agv_site = self.env['sf.agv.site'].sudo().search([('name', '=', agv_site_name)])
|
||||
if agv_site:
|
||||
agv_site.state = '占用' if is_occupy else '空闲'
|
||||
agv_site.state = is_occupy
|
||||
if notify:
|
||||
self.env['sf.agv.scheduling'].on_site_state_change(agv_site.id, agv_site.state)
|
||||
else:
|
||||
_logger.error("更新失败:接驳站站点错误!%s" % agv_site_name)
|
||||
raise UserError("更新失败:接驳站站点错误!")
|
||||
|
||||
|
||||
|
||||
@@ -1089,6 +1089,8 @@ class ResMrpWorkOrder(models.Model):
|
||||
record.process_state = '待加工'
|
||||
# record.write({'process_state': '待加工'})
|
||||
record.production_id.process_state = '待加工'
|
||||
# 生成工件配送单
|
||||
record.workpiece_delivery_ids = record._json_workpiece_delivery_list()
|
||||
if record.routing_type == 'CNC加工':
|
||||
record.process_state = '待解除装夹'
|
||||
# record.write({'process_state': '待加工'})
|
||||
@@ -1190,8 +1192,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
raw_move.write({'state': 'done'})
|
||||
record.production_id.button_mark_done1()
|
||||
# record.production_id.state = 'done'
|
||||
# 生成工件配送单
|
||||
record.workpiece_delivery_ids = record._json_workpiece_delivery_list()
|
||||
|
||||
|
||||
# 将FTP的检测报告文件下载到临时目录
|
||||
def download_reportfile_tmp(self, workorder, reportpath):
|
||||
@@ -1495,7 +1496,7 @@ class SfWorkOrderBarcodes(models.Model):
|
||||
|
||||
class WorkPieceDelivery(models.Model):
|
||||
_name = "sf.workpiece.delivery"
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin', "barcodes.barcode_events_mixin"]
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_description = '工件配送'
|
||||
|
||||
name = fields.Char('单据编码')
|
||||
@@ -1573,12 +1574,12 @@ class WorkPieceDelivery(models.Model):
|
||||
|
||||
# 工件配送
|
||||
def button_delivery(self):
|
||||
delivery_ids = []
|
||||
# delivery_ids = []
|
||||
production_ids = []
|
||||
workorder_ids = []
|
||||
is_cnc_down = 0
|
||||
is_not_production_line = 0
|
||||
same_production_line_id = None
|
||||
same_route_id = None
|
||||
production_type = '上产线'
|
||||
max_num = 4 # 最大配送数量
|
||||
if len(self) > max_num:
|
||||
@@ -1593,13 +1594,13 @@ class WorkPieceDelivery(models.Model):
|
||||
if item.is_cnc_program_down is False:
|
||||
is_cnc_down += 1
|
||||
if is_cnc_down == 0 and is_not_production_line == 0:
|
||||
delivery_ids.append(item.id)
|
||||
# delivery_ids.append(item.id)
|
||||
production_ids.append(item.production_id.id)
|
||||
workorder_ids.append(item.workorder_id.id)
|
||||
if is_cnc_down >= 1:
|
||||
raise UserError('您所选择制造订单的【CNC程序】暂未下发,请在程序下发后再进行配送')
|
||||
if is_not_production_line >= 1:
|
||||
raise UserError('您所选择制造订单的【目的生产线】不一致,请重新确认')
|
||||
if delivery_ids:
|
||||
return {
|
||||
'name': _('确认'),
|
||||
'type': 'ir.actions.act_window',
|
||||
@@ -1607,9 +1608,10 @@ class WorkPieceDelivery(models.Model):
|
||||
'res_model': 'sf.workpiece.delivery.wizard',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_delivery_ids': [(6, 0, delivery_ids)],
|
||||
# 'default_delivery_ids': [(6, 0, delivery_ids)],
|
||||
'default_production_ids': [(6, 0, production_ids)],
|
||||
'default_type': production_type,
|
||||
'default_workorder_ids': [(6, 0, workorder_ids)],
|
||||
}}
|
||||
|
||||
|
||||
@@ -1716,11 +1718,6 @@ class WorkPieceDelivery(models.Model):
|
||||
else:
|
||||
obj.delivery_duration = 0.0
|
||||
|
||||
# agv调度单
|
||||
agv_scheduling_id = fields.Many2one('sf.agv.scheduling', 'agv调度单')
|
||||
|
||||
def on_barcode_scanned(self, barcode):
|
||||
logging.info('Rfid:%s' % barcode)
|
||||
|
||||
|
||||
class CMMprogram(models.Model):
|
||||
|
||||
24
sf_manufacturing/static/src/xml/button_show_on_tree.xml
Normal file
24
sf_manufacturing/static/src/xml/button_show_on_tree.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="sf_manufacturing.button_show" t-inherit="web.ListView.Buttons" t-inherit-mode="extension" owl="1">
|
||||
<xpath expr="//div/t[@t-if='nbSelected']" position="after">
|
||||
<t t-elif="!nbSelected">
|
||||
<t t-foreach="archInfo.headerButtons" t-as="button" t-key="button.id">
|
||||
<t t-if="button.modifiers.force_show">
|
||||
<ListViewHeaderButton
|
||||
list="model.root"
|
||||
clickParams="button.clickParams"
|
||||
defaultRank="button.defaultRank"
|
||||
domain="props.domain"
|
||||
icon="button.icon"
|
||||
string="button.string"
|
||||
title="button.title"
|
||||
className="button.className+' ms-2'"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</xpath>
|
||||
|
||||
</t>
|
||||
</templates>
|
||||
@@ -18,7 +18,7 @@
|
||||
<field name="start_site_id"/>
|
||||
<field name="end_site_id"/>
|
||||
<field name="site_state"/>
|
||||
<field name="delivery_workpieces_display"/>
|
||||
<field name="delivery_workpieces"/>
|
||||
<field name="task_create_time" readonly="1"/>
|
||||
<field name="task_delivery_time" readonly="1"/>
|
||||
<field name="task_completion_time" readonly="1"/>
|
||||
|
||||
@@ -631,7 +631,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<tree string="工件配送" class="center" create="0" delete="0">
|
||||
<header>
|
||||
<button name="button_delivery" type="object" string="配送" class="oe_highlight"/>
|
||||
<button name="button_delivery" type="object" string="配送" class="btn-primary" attrs="{'force_show':1}"/>
|
||||
</header>
|
||||
<field name="status" widget="badge"
|
||||
decoration-success="status == '已配送'"
|
||||
|
||||
@@ -4,18 +4,14 @@
|
||||
<field name="name">sf.workpiece.delivery.wizard.form.view</field>
|
||||
<field name="model">sf.workpiece.delivery.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<form class="no_auto_focus">
|
||||
<sheet>
|
||||
<field name="delivery_ids" invisible="True"/>
|
||||
<field name="workorder_id" invisible="True"/>
|
||||
<!-- <field name="delivery_ids" invisible="True"/>-->
|
||||
<field name="workorder_ids" invisible="True"/>
|
||||
<field name="type" invisible="True"/>
|
||||
<field name="_barcode_scanned" widget="barcode_handler"/>
|
||||
<group col="1">
|
||||
<field name="production_ids" readonly="1" widget="many2many_tags" string="制造订单号"/>
|
||||
<div class="o_address_format">
|
||||
<lable for="rfid_code"></lable>
|
||||
<field name="rfid_code" class="o_address_zip"/>
|
||||
<button name="recognize_production" string="识别" type="object" class="oe_highlight"/>
|
||||
</div>
|
||||
<field name="type" readonly="1"/>
|
||||
<field name="feeder_station_start_id" options="{'no_create': True}" required="1"/>
|
||||
<field name="workcenter_id" options="{'no_create': True}"/>
|
||||
|
||||
@@ -8,11 +8,12 @@ from odoo import models, api, fields, _
|
||||
|
||||
class WorkpieceDeliveryWizard(models.TransientModel):
|
||||
_name = 'sf.workpiece.delivery.wizard'
|
||||
_inherit = ["barcodes.barcode_events_mixin"]
|
||||
_description = '工件配送'
|
||||
|
||||
delivery_ids = fields.Many2many('sf.workpiece.delivery', string='配送')
|
||||
# delivery_ids = fields.Many2many('sf.workpiece.delivery', string='配送')
|
||||
rfid_code = fields.Char('rfid码')
|
||||
workorder_id = fields.Many2one('mrp.workorder', string='工单')
|
||||
workorder_ids = fields.Many2many('mrp.workorder', string='工单')
|
||||
production_ids = fields.Many2many('mrp.production', string='制造订单号')
|
||||
destination_production_line_id = fields.Many2one('sf.production.line', '目的生产线')
|
||||
route_id = fields.Many2one('sf.agv.task.route', '任务路线', domain=[('route_type', 'in', ['上产线', '下产线'])])
|
||||
@@ -51,9 +52,9 @@ class WorkpieceDeliveryWizard(models.TransientModel):
|
||||
|
||||
def confirm(self):
|
||||
try:
|
||||
if self.workorder_id:
|
||||
self.workorder_id.workpiece_delivery_ids[0].agv_scheduling_id()
|
||||
else:
|
||||
# if self.workorder_id:
|
||||
# self.workorder_id.workpiece_delivery_ids[0].agv_scheduling_id()
|
||||
# else:
|
||||
is_not_production_line = 0
|
||||
same_production_line_id = None
|
||||
notsame_production_line_arr = []
|
||||
@@ -66,14 +67,12 @@ class WorkpieceDeliveryWizard(models.TransientModel):
|
||||
if is_not_production_line >= 1:
|
||||
raise UserError('制造订单号为%s的目的生产线不一致' % notsame_production_line_str)
|
||||
else:
|
||||
# self.delivery_ids._delivery_avg()
|
||||
agv_scheduling_id = self.env['sf.agv.scheduling'].add_scheduling(
|
||||
self.env['sf.agv.scheduling'].add_scheduling(
|
||||
agv_start_site_id=self.feeder_station_start_id.id,
|
||||
agv_route_type=self.type,
|
||||
productions=self.production_ids,
|
||||
deliveries=self.delivery_ids
|
||||
workorders=self.workorder_ids,
|
||||
)
|
||||
self.delivery_ids.agv_scheduling_id = agv_scheduling_id
|
||||
|
||||
except Exception as e:
|
||||
logging.info('工件配送任务下发失败:%s' % e)
|
||||
raise UserError('工件配送任务下发失败:%s' % e)
|
||||
@@ -122,3 +121,18 @@ class WorkpieceDeliveryWizard(models.TransientModel):
|
||||
if self.route_id:
|
||||
self.feeder_station_start_id = self.route_id.start_site_id.id
|
||||
self.feeder_station_destination_id = self.route_id.end_site_id.id
|
||||
|
||||
def on_barcode_scanned(self, barcode):
|
||||
workorder = self.env['mrp.workorder'].search(
|
||||
[('production_line_state', '=', '待上产线'), ('rfid_code', '=', barcode),
|
||||
('state', '=', 'done')])
|
||||
if workorder:
|
||||
if len(self.production_ids) > 0 and workorder.production_line_id.id != self.production_ids[0].production_line_id.id:
|
||||
raise UserError('该rfid对应的制造订单号为%s的目的生产线不一致' % workorder.production_id.name)
|
||||
|
||||
# 将对象添加到对应的同模型且是多对多类型里
|
||||
self.production_ids |= workorder.production_id
|
||||
self.workorder_ids |= workorder
|
||||
else:
|
||||
raise UserError('该rfid码对应的工单不存在')
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user