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

# Conflicts:
#	sf_manufacturing/models/mrp_workorder.py
This commit is contained in:
mgw
2024-05-09 09:25:19 +08:00
36 changed files with 713 additions and 260 deletions

View File

@@ -4,7 +4,7 @@ csv_internal_sep = ,
data_dir = /var/lib/odoo data_dir = /var/lib/odoo
db_host = 172.17.0.2 db_host = 172.17.0.2
db_maxconn = 64 db_maxconn = 64
db_name = sf_t2cs_003 db_name = sf_t_0430
db_password = sf db_password = sf
db_port = 5432 db_port = 5432
db_sslmode = prefer db_sslmode = prefer

View File

@@ -11,7 +11,8 @@ access_sf_machine_control_system,sf_machine_control_system,model_sf_machine_cont
access_sf_machine_control_system_admin,sf_machine_control_system_admin,model_sf_machine_control_system,base.group_system,1,1,1,0 access_sf_machine_control_system_admin,sf_machine_control_system_admin,model_sf_machine_control_system,base.group_system,1,1,1,0
access_sf_production_process_group_sale_director,sf_production_process_group_sale_director,model_sf_production_process,sf_base.group_sale_director,1,0,0,0 access_sf_production_process_group_sale_director,sf_production_process_group_sale_director,model_sf_production_process,sf_base.group_sale_director,1,0,0,0
access_sf_production_process_group_sale_salemanager,sf_production_process_group_sale_salemanager,model_sf_production_process,sf_base.group_sale_salemanager,1,0,0,0 access_sf_production_process_group_sale_salemanager,sf_production_process_group_sale_salemanager,model_sf_production_process,sf_base.group_sale_salemanager,1,0,0,0
access_res_partner_category_group_sale_salemanager,res_partner_category_group_sale_salemanager,base.model_res_partner_category,sf_base.group_sale_salemanager,1,0,1,0
access_res_partner_category_group_sale_director,res_partner_category_group_sale_director,base.model_res_partner_category,sf_base.group_sale_director,1,0,1,0
access_sf_production_process,sf_production_process,model_sf_production_process,base.group_user,1,1,1,0 access_sf_production_process,sf_production_process,model_sf_production_process,base.group_user,1,1,1,0
access_sf_production_process_admin,sf_production_process_admin,model_sf_production_process,base.group_system,1,1,1,0 access_sf_production_process_admin,sf_production_process_admin,model_sf_production_process,base.group_system,1,1,1,0
access_sf_production_materials,sf_production_materials,model_sf_production_materials,base.group_user,1,1,1,0 access_sf_production_materials,sf_production_materials,model_sf_production_materials,base.group_user,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
11 access_sf_machine_control_system_admin sf_machine_control_system_admin model_sf_machine_control_system base.group_system 1 1 1 0
12 access_sf_production_process_group_sale_director sf_production_process_group_sale_director model_sf_production_process sf_base.group_sale_director 1 0 0 0
13 access_sf_production_process_group_sale_salemanager sf_production_process_group_sale_salemanager model_sf_production_process sf_base.group_sale_salemanager 1 0 0 0
14 access_sf_production_process access_res_partner_category_group_sale_salemanager sf_production_process res_partner_category_group_sale_salemanager model_sf_production_process base.model_res_partner_category base.group_user sf_base.group_sale_salemanager 1 1 0 1 0
15 access_res_partner_category_group_sale_director res_partner_category_group_sale_director base.model_res_partner_category sf_base.group_sale_director 1 0 1 0
16 access_sf_production_process_admin access_sf_production_process sf_production_process_admin sf_production_process model_sf_production_process base.group_system base.group_user 1 1 1 0
17 access_sf_production_materials access_sf_production_process_admin sf_production_materials sf_production_process_admin model_sf_production_materials model_sf_production_process base.group_user base.group_system 1 1 1 0
18 access_sf_production_materials_group_sale_director access_sf_production_materials sf_production_materials_group_sale_director sf_production_materials model_sf_production_materials sf_base.group_sale_director base.group_user 1 0 1 0 1 0

View File

@@ -37,7 +37,7 @@ class ResMrpBomMo(models.Model):
'product_qty': 1, 'product_qty': 1,
'product_uom_id': 1 'product_uom_id': 1
} }
return self.env['mrp.bom.line'].create(vals) return self.env['mrp.bom.line'].sudo().create(vals)
# 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品后再次进行创建bom # 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品后再次进行创建bom
def bom_create(self, product, bom_type, product_type): def bom_create(self, product, bom_type, product_type):
@@ -64,7 +64,7 @@ class ResMrpBomMo(models.Model):
qty = 1 qty = 1
if round(embryo.volume * raw_bom_line.materials_type_id.density / 1000000) > 1: if round(embryo.volume * raw_bom_line.materials_type_id.density / 1000000) > 1:
qty = round(embryo.volume * raw_bom_line.materials_type_id.density / 1000000) qty = round(embryo.volume * raw_bom_line.materials_type_id.density / 1000000)
bom_line = self.env['mrp.bom.line'].create({ bom_line = self.env['mrp.bom.line'].sudo().create({
'bom_id': self.id, 'bom_id': self.id,
'product_id': raw_bom_line.id, 'product_id': raw_bom_line.id,
'product_tmpl_id': raw_bom_line.product_tmpl_id.id, 'product_tmpl_id': raw_bom_line.product_tmpl_id.id,

View File

@@ -13,6 +13,7 @@
'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse'], 'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse'],
'data': [ 'data': [
'data/stock_data.xml', 'data/stock_data.xml',
'data/empty_racks_data.xml',
'security/group_security.xml', 'security/group_security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'wizard/workpiece_delivery_views.xml', 'wizard/workpiece_delivery_views.xml',

View File

@@ -8,7 +8,7 @@ from odoo.http import request
class Manufacturing_Connect(http.Controller): class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/GetWoInfo', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, @http.route('/AutoDeviceApi/GetWoInfo', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*") cors="*")
def get_Work_Info(self, **kw): def get_Work_Info(self, **kw):
""" """
@@ -21,6 +21,8 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True, 'Datas': []} res = {'Succeed': True, 'Datas': []}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/GetWoInfo'})
logging.info('RfidCode:%s' % ret['RfidCode']) logging.info('RfidCode:%s' % ret['RfidCode'])
if 'RfidCode' in ret: if 'RfidCode' in ret:
workorder = request.env['mrp.workorder'].sudo().search([('rfid_code', '=', ret['RfidCode'])]) workorder = request.env['mrp.workorder'].sudo().search([('rfid_code', '=', ret['RfidCode'])])
@@ -60,6 +62,8 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True, 'Datas': []} res = {'Succeed': True, 'Datas': []}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/GetShiftPlan'})
if 'ProductionLine' in ret: if 'ProductionLine' in ret:
workorder_ids = request.env['mrp.workorder'].sudo().get_plan_workorder(ret['ProductionLine']) workorder_ids = request.env['mrp.workorder'].sudo().get_plan_workorder(ret['ProductionLine'])
else: else:
@@ -113,6 +117,8 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True, 'Datas': []} res = {'Succeed': True, 'Datas': []}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/QcCheck'})
logging.info('RfidCode:%s' % ret['RfidCode']) logging.info('RfidCode:%s' % ret['RfidCode'])
if 'RfidCode' in ret: if 'RfidCode' in ret:
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
@@ -150,6 +156,8 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True, 'Datas': ['工单已开始']} res = {'Succeed': True, 'Datas': ['工单已开始']}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/FeedBackStart'})
production_id = ret['BillId'] production_id = ret['BillId']
routing_type = ret['CraftId'] routing_type = ret['CraftId']
equipment_id = ret["DeviceId"] equipment_id = ret["DeviceId"]
@@ -193,6 +201,8 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True, 'Datas': ['工单已结束']} res = {'Succeed': True, 'Datas': ['工单已结束']}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/FeedBackEnd'})
production_id = ret['BillId'] production_id = ret['BillId']
routing_type = ret['CraftId'] routing_type = ret['CraftId']
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
@@ -237,6 +247,8 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True} res = {'Succeed': True}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/PartQualityInspect'})
production_id = ret['BillId'] production_id = ret['BillId']
routing_type = ret['CraftId'] routing_type = ret['CraftId']
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
@@ -293,6 +305,8 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True, 'Datas': []} res = {'Succeed': True, 'Datas': []}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/CMMProgDolod'})
if 'RfidCode' in ret: if 'RfidCode' in ret:
logging.info('RfidCode:%s' % ret['RfidCode']) logging.info('RfidCode:%s' % ret['RfidCode'])
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
@@ -331,6 +345,8 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True, 'Datas': []} res = {'Succeed': True, 'Datas': []}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/NCProgDolod'})
if 'RfidCode' in ret: if 'RfidCode' in ret:
logging.info('RfidCode:%s' % ret['RfidCode']) logging.info('RfidCode:%s' % ret['RfidCode'])
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
@@ -370,6 +386,8 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True, 'Datas': []} res = {'Succeed': True, 'Datas': []}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/LocationChange'})
logging.info('LocationChange_ret===========:%s' % ret) logging.info('LocationChange_ret===========:%s' % ret)
RfidCode = ret['RfidCode'] RfidCode = ret['RfidCode']
ChangeType = ret['ChangeType'] ChangeType = ret['ChangeType']
@@ -426,11 +444,13 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True} res = {'Succeed': True}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/AGVToProduct'})
logging.info('ret:%s' % ret) logging.info('ret:%s' % ret)
if 'DeviceId' in ret: if 'DeviceId' in ret:
logging.info('DeviceId:%s' % ret['DeviceId']) logging.info('DeviceId:%s' % ret['DeviceId'])
if 'IsComplete' in ret: if 'IsComplete' in ret:
if ret['IsComplete'] is True: if ret['IsComplete'] is True or ret['IsComplete'] is False:
for i in range(1, 5): for i in range(1, 5):
logging.info('F-RfidCode:%s' % i) logging.info('F-RfidCode:%s' % i)
if f'RfidCode{i}' in ret: if f'RfidCode{i}' in ret:
@@ -477,12 +497,14 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True} res = {'Succeed': True}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/AGVDownProduct'})
logging.info('ret:%s' % ret) logging.info('ret:%s' % ret)
if 'DeviceId' in ret: if 'DeviceId' in ret:
logging.info('DeviceId:%s' % ret['DeviceId']) logging.info('DeviceId:%s' % ret['DeviceId'])
delivery_Arr = [] delivery_Arr = []
if 'IsComplete' in ret: if 'IsComplete' in ret:
if ret['IsComplete'] is True: if ret['IsComplete'] is True or ret['IsComplete'] is False:
for i in range(1, 5): for i in range(1, 5):
logging.info('F-RfidCode:%s' % i) logging.info('F-RfidCode:%s' % i)
if f'RfidCode{i}' in ret: if f'RfidCode{i}' in ret:
@@ -538,6 +560,8 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True} res = {'Succeed': True}
datas = request.httprequest.data datas = request.httprequest.data
ret = json.loads(datas) ret = json.loads(datas)
request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/EquipmentBaseCoordinate'})
if 'DeviceId' in ret: if 'DeviceId' in ret:
equipment = request.env['maintenance.equipment'].sudo().search('name', '=', ret['DeviceId']) equipment = request.env['maintenance.equipment'].sudo().search('name', '=', ret['DeviceId'])
if equipment: if equipment:

View File

@@ -28,7 +28,7 @@ class Workpiece(http.Controller):
req_codes = ret['reqCode'].split(',') req_codes = ret['reqCode'].split(',')
for req_code in req_codes: for req_code in req_codes:
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
[('delivery_num', '=', req_code.strip()), ('task_completion_time', '=', False)]) [('name', '=', req_code.strip()), ('task_completion_time', '=', False)])
if workpiece_delivery: if workpiece_delivery:
workpiece_delivery.write({'status': '已配送', 'task_completion_time': datetime.now()}) workpiece_delivery.write({'status': '已配送', 'task_completion_time': datetime.now()})
else: else:

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="sequence_workpiece_delivery" model="ir.sequence">
<field name="name">工件配送</field>
<field name="code">sf.workpiece.delivery</field>
<field name="prefix">WDO%(year)s%(month)s%(day)s</field>
<field name="padding">4</field>
<field name="company_id" eval="False"/>
</record>
<record id="workpiece_delivery_empty_racks_1" model="sf.workpiece.delivery">
<field name="name">运送空料架路线:C01-A01</field>
<field name="type">运送空料架</field>
<field name="route_id"
search="[('start_site_id.name','=','C01'),('end_site_id.name','=','A01')]"/>
<field name="feeder_station_start_id" search="[('name','=','C01')]"/>
<field name="feeder_station_destination_id" search="[('name','=','A01')]"/>
</record>
<record id="workpiece_delivery_empty_racks_2" model="sf.workpiece.delivery">
<field name="name">运送空料架路线:B01-B02</field>
<field name="type">运送空料架</field>
<field name="route_id"
search="[('start_site_id.name','=','B01'),('end_site_id.name','=','B02')]"/>
<field name="feeder_station_start_id" search="[('name','=','B01')]"/>
<field name="feeder_station_destination_id" search="[('name','=','B02')]"/>
</record>
<record id="workpiece_delivery_empty_racks_3" model="sf.workpiece.delivery">
<field name="name">运送空料架路线:B01-A01</field>
<field name="type">运送空料架</field>
<field name="route_id"
search="[('start_site_id.name','=','B01'),('end_site_id.name','=','A01')]"/>
<field name="feeder_station_start_id" search="[('name','=','B01')]"/>
<field name="feeder_station_destination_id" search="[('name','=','A01')]"/>
</record>
<record id="workpiece_delivery_empty_racks_4" model="sf.workpiece.delivery">
<field name="name">运送空料架路线:C01-B02</field>
<field name="type">运送空料架</field>
<field name="route_id"
search="[('start_site_id.name','=','C01'),('end_site_id.name','=','B02')]"/>
<field name="feeder_station_start_id" search="[('name','=','C01')]"/>
<field name="feeder_station_destination_id" search="[('name','=','B02')]"/>
</record>
</data>
</odoo>

View File

@@ -32,6 +32,8 @@ class AgvSetting(models.Model):
if da['DeviceId'] == item.name: if da['DeviceId'] == item.name:
if da['AtHome'] is True: if da['AtHome'] is True:
item.state = '占用' item.state = '占用'
else:
item.state = '空闲'
class AgvTaskRoute(models.Model): class AgvTaskRoute(models.Model):
@@ -40,15 +42,20 @@ class AgvTaskRoute(models.Model):
name = fields.Char('名称') name = fields.Char('名称')
type = fields.Selection([ type = fields.Selection([
('F01', '搬运'), ], string='类型', default="F01") ('F01', '搬运'), ], string='任务类型', default="F01")
route_type = fields.Selection([
('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型')
start_site_id = fields.Many2one('sf.agv.site', '起点接驳站位置编号') start_site_id = fields.Many2one('sf.agv.site', '起点接驳站位置编号')
end_site_id = fields.Many2one('sf.agv.site', '终点接驳站位置编号') end_site_id = fields.Many2one('sf.agv.site', '终点接驳站位置编号')
destination_production_line_id = fields.Many2one('sf.production.line', '目的生产线') destination_production_line_id = fields.Many2one('sf.production.line', '目的生产线')
priority = fields.Selection([ active = fields.Boolean('有效', default=True)
('0', '正常'),
('1', ''),
('2', ''), class Center_controlInterfaceLog(models.Model):
('3', ''), _name = 'center_control.interface.log'
('4', '紧急'), _description = '中控接口调用日志'
], string='优先级', default='0')
name = fields.Char('接口名称')
content = fields.Char('接口内容')
interface_call_date = fields.Datetime("调用时间", default=fields.Datetime.now, readonly=True)
active = fields.Boolean('有效', default=True) active = fields.Boolean('有效', default=True)

View File

@@ -56,8 +56,9 @@ class MrpProduction(models.Model):
glb_file = fields.Binary("glb模型文件") glb_file = fields.Binary("glb模型文件")
production_line_id = fields.Many2one('sf.production.line', string='生产线') production_line_id = fields.Many2one('sf.production.line', string='生产线')
plan_start_processing_time = fields.Datetime('计划开始加工时间') plan_start_processing_time = fields.Datetime('计划开始加工时间')
production_line_state = fields.Selection([('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')], production_line_state = fields.Selection(
string='/下产线', default='待上产线') [('待上产线', '待上产线'), ('已上产线', '上产线'), ('已下产线', '已下产线')],
string='上/下产线', default='待上产线')
# 工序状态 # 工序状态
# Todo 研究下用法 # Todo 研究下用法
process_state = fields.Selection([ process_state = fields.Selection([
@@ -114,7 +115,7 @@ class MrpProduction(models.Model):
# production.state = 'pending_processing' # production.state = 'pending_processing'
production.state = 'pending_cam' production.state = 'pending_cam'
if production.state == 'progress' and production.schedule_state == '已排' and production.process_state == '待加工': if production.state == 'progress' and production.schedule_state == '已排' and production.process_state == '待加工':
# if production.state == 'pending_cam' and production.process_state == '待加工': # if production.state == 'pending_cam' and production.process_state == '待加工':
production.state = 'pending_processing' production.state = 'pending_processing'
elif production.state == 'progress' and production.process_state == '待解除装夹': elif production.state == 'progress' and production.process_state == '待解除装夹':
production.state = 'pending_era_cam' production.state = 'pending_era_cam'
@@ -262,10 +263,14 @@ class MrpProduction(models.Model):
# 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心; # 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心;
def _create_workorder3(self): def _create_workorder3(self):
programming_no = None
product_id_new = None
for production in self: for production in self:
if not production.bom_id or not production.product_id: if not production.bom_id or not production.product_id:
continue continue
workorders_values = [] workorders_values = []
if product_id_new is None:
product_id_new = production.product_id
product_qty = production.product_uom_id._compute_quantity(production.product_qty, product_qty = production.product_uom_id._compute_quantity(production.product_qty,
production.bom_id.product_uom_id) production.bom_id.product_uom_id)
@@ -290,7 +295,14 @@ class MrpProduction(models.Model):
'state': 'pending', 'state': 'pending',
}] }]
if production.product_id.categ_id.type == '成品': if production.product_id.categ_id.type == '成品':
production.fetchCNC() if programming_no is None:
production.fetchCNC()
programming_no = production.programming_no
else:
if production.product_id == product_id_new:
if not production.programming_no:
production.write({'programming_no': programming_no, '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(','))

View File

@@ -180,6 +180,11 @@ class ResMrpWorkOrder(models.Model):
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=True)
@api.onchange('rfid_code')
def _onchange(self):
if self.rfid_code and self.state == 'progress':
self.workpiece_delivery_ids[0].write({'rfid_code': self.rfid_code})
def get_plan_workorder(self, production_line): def get_plan_workorder(self, production_line):
tomorrow = (date.today() + timedelta(days=+1)).strftime("%Y-%m-%d") tomorrow = (date.today() + timedelta(days=+1)).strftime("%Y-%m-%d")
tomorrow_start = tomorrow + ' 00:00:00' tomorrow_start = tomorrow + ' 00:00:00'
@@ -422,19 +427,22 @@ class ResMrpWorkOrder(models.Model):
if not item.route_id: if not item.route_id:
raise UserError('【工件配送】明细中请选择【任务路线】') raise UserError('【工件配送】明细中请选择【任务路线】')
else: else:
if item.is_cnc_program_down is True: if self.state == 'done':
if item.status == '待下发': if item.is_cnc_program_down is True:
return { if item.status == '待下发':
'name': _('确认'), return {
'type': 'ir.actions.act_window', 'name': _('确认'),
'view_mode': 'form', 'type': 'ir.actions.act_window',
'res_model': 'sf.workpiece.delivery.wizard', 'view_mode': 'form',
'target': 'new', 'res_model': 'sf.workpiece.delivery.wizard',
'context': { 'target': 'new',
'default_workorder_id': self.id, 'context': {
}} 'default_workorder_id': self.id,
}}
else:
raise UserError(_("该制造订单还未下发CNC程序单无法进行工件配送"))
else: else:
raise UserError(_("制造订单还未下发CNC程序单,无法进行工件配送")) raise UserError(_("工单暂未完成,无法进行工件配送"))
# 拼接工单对象属性值 # 拼接工单对象属性值
def json_workorder_str(self, k, production, route): def json_workorder_str(self, k, production, route):
@@ -485,9 +493,8 @@ class ResMrpWorkOrder(models.Model):
def _json_workpiece_delivery_list(self, production): def _json_workpiece_delivery_list(self, production):
return [ return [
[0, '', {'production_id': production.id, 'type': '上产线', 'delivery_num': '%s-%s' % (production.name, 1)}], [0, '', {'production_id': production.id, 'type': '上产线'}],
[0, '', [0, '', {'production_id': production.id, 'type': '下产线'}]]
{'production_id': production.id, 'type': '下产线', 'delivery_num': '%s-%s' % (production.name, 2)}]]
# 拼接工单对象属性值(表面工艺) # 拼接工单对象属性值(表面工艺)
def _json_workorder_surface_process_str(self, production, route, process_parameter, supplier_id): def _json_workorder_surface_process_str(self, production, route, process_parameter, supplier_id):
@@ -632,6 +639,33 @@ class ResMrpWorkOrder(models.Model):
# 'domain': [('production_id', '=', self.id)], # 'domain': [('production_id', '=', self.id)],
# 'target':'new' # 'target':'new'
# } # }
@api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state')
def _compute_state(self):
for workorder in self:
if workorder.routing_type == '装夹预调':
if not workorder.cnc_ids:
workorder.state = 'waiting'
else:
for item in workorder.cnc_ids:
functional_cutting_tool = self.env['sf.functional.cutting.tool.entity'].search(
[('tool_name_id.name', '=', item.cutting_tool_name)])
if not functional_cutting_tool:
workorder.state = 'waiting'
if workorder.state == 'pending':
if all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
workorder.state = 'ready' if workorder.production_id.reservation_state == 'assigned' else 'waiting'
continue
if workorder.state not in ('waiting', 'ready'):
continue
if not all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
workorder.state = 'pending'
continue
if workorder.production_id.reservation_state not in ('waiting', 'confirmed', 'assigned'):
continue
if workorder.production_id.reservation_state == 'assigned' and workorder.state == 'waiting':
workorder.state = 'ready'
elif workorder.production_id.reservation_state != 'assigned' and workorder.state == 'ready':
workorder.state = 'waiting'
def recreateManufacturingOrWorkerOrder(self): def recreateManufacturingOrWorkerOrder(self):
""" """
@@ -701,7 +735,18 @@ class ResMrpWorkOrder(models.Model):
def button_start(self): def button_start(self):
if self.routing_type == '装夹预调' and self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name: if self.routing_type == '装夹预调' and self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name:
self.pro_code = self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name self.pro_code = self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name
if self.routing_type == '装夹预调':
cnc_workorder = self.search(
[('production_id', '=', self.production_id.id), ('routing_type', '=', 'CNC加工')],
limit=1, order='id asc')
if not cnc_workorder:
raise UserError(_('该制造订单还未下发CNC程序请稍后再试'))
else:
for item in cnc_workorder.cnc_ids:
functional_cutting_tool = self.env['sf.functional.cutting.tool.entity'].search(
[('tool_name_id.name', '=', item.cutting_tool_name)])
if not functional_cutting_tool:
raise UserError(_('该制造订单的CNC程序为%s没有对应的功能刀具' % item.cutting_tool_name))
if self.routing_type == '解除装夹': if self.routing_type == '解除装夹':
''' '''
记录开始时间 记录开始时间
@@ -919,6 +964,9 @@ class CNCprocessing(models.Model):
if workpiece_delivery: if workpiece_delivery:
for item in workpiece_delivery: for item in workpiece_delivery:
item.is_cnc_program_down = True item.is_cnc_program_down = True
if item.workorder_id.state == 'waiting':
item.workorder_id.state = 'ready'
# cnc_workorder.time_ids.date_end = datetime.now() # cnc_workorder.time_ids.date_end = datetime.now()
# cnc_workorder.button_finish() # cnc_workorder.button_finish()
@@ -1005,9 +1053,13 @@ class SfWorkOrderBarcodes(models.Model):
workorder = self.env['mrp.workorder'].browse(self.ids) workorder = self.env['mrp.workorder'].browse(self.ids)
# workorder_preset = self.env['mrp.workorder'].search( # workorder_preset = self.env['mrp.workorder'].search(
# [('routing_type', '=', '装夹预调'), ('rfid_code', '=', barcode)]) # [('routing_type', '=', '装夹预调'), ('rfid_code', '=', barcode)])
workorder_old = self.env['mrp.workorder'].search([('rfid_code', '=', barcode)]) workorder_olds = self.env['mrp.workorder'].search(
if workorder_old: [('routing_type', '=', '装夹预调'), ('rfid_code', '=', barcode)])
raise UserError('该托盘已绑定【%s】制造订单,请先解除绑定!!!' % workorder_old.production_id.name) if workorder_olds:
name = ''
for workorder in workorder_olds:
name = '%s %s' % (name, workorder.production_id.name)
raise UserError('该托盘已绑定【%s】制造订单,请先解除绑定!!!' % name)
if workorder: if workorder:
if workorder.routing_type == '装夹预调': if workorder.routing_type == '装夹预调':
if workorder.state in ['done']: if workorder.state in ['done']:
@@ -1035,6 +1087,8 @@ class SfWorkOrderBarcodes(models.Model):
for item in workorder_rfid: for item in workorder_rfid:
item.write({'rfid_code': barcode}) item.write({'rfid_code': barcode})
logging.info("Rfid绑定成功") logging.info("Rfid绑定成功")
else:
raise UserError('该Rfid【%s】绑定的是【%s】, 不是托盘!!!' % (barcode, lot.product_id.name))
self.process_state = '待检测' self.process_state = '待检测'
self.date_start = datetime.now() self.date_start = datetime.now()
else: else:
@@ -1094,12 +1148,12 @@ class WorkPieceDelivery(models.Model):
_name = "sf.workpiece.delivery" _name = "sf.workpiece.delivery"
_description = '工件配送' _description = '工件配送'
delivery_num = fields.Char('工件配送编码') name = fields.Char('单据编号')
workorder_id = fields.Many2one('mrp.workorder', string='工单', readonly=True) workorder_id = fields.Many2one('mrp.workorder', string='工单', readonly=True)
workorder_state = fields.Selection(related='workorder_id.state', string='工单状态')
rfid_code = fields.Char(related='workorder_id.rfid_code', string='rfid码', store=True)
production_id = fields.Many2one('mrp.production', string='制造订单号', readonly=True) production_id = fields.Many2one('mrp.production', string='制造订单号', readonly=True)
production_line_id = fields.Many2one('sf.production.line', compute='_compute_production_line_id', production_line_id = fields.Many2one('sf.production.line', string='目的生产线')
string='目的生产线', readonly=True,
store=True)
plan_start_processing_time = fields.Datetime('计划开始加工时间', readonly=True) plan_start_processing_time = fields.Datetime('计划开始加工时间', readonly=True)
route_id = fields.Many2one('sf.agv.task.route', '任务路线') route_id = fields.Many2one('sf.agv.task.route', '任务路线')
@@ -1113,9 +1167,24 @@ class WorkPieceDelivery(models.Model):
status = fields.Selection( status = fields.Selection(
[('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态', default='待下发') [('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态', default='待下发')
is_cnc_program_down = fields.Boolean('程序是否下发', default=False) is_cnc_program_down = fields.Boolean('程序是否下发', default=False)
active = fields.Boolean(string="有效", default=True)
# @api.model @api.model
# def create(self, vals): def create(self, vals):
if vals.get('name', '/') == '/' or vals.get('name', '/') is False:
vals['name'] = self.env['ir.sequence'].next_by_code('sf.workpiece.delivery') or '/'
obj = super(WorkPieceDelivery, self).create(vals)
return obj
def action_delivery_history(self):
return {
'name': _('配送历史'),
'type': 'ir.actions.act_window',
'view_mode': 'tree',
'res_model': 'sf.workpiece.delivery',
'view_id': self.env.ref('sf_manufacturing.sf_workpiece_delivery_empty_racks_tree').id,
'domain': [('type', '=', '运送空料架'), ('route_id', '=', self.route_id.id), ('name', 'ilike', 'WDO')]
}
@api.onchange('route_id') @api.onchange('route_id')
def onchange_route(self): def onchange_route(self):
@@ -1126,6 +1195,7 @@ class WorkPieceDelivery(models.Model):
# 工件配送 # 工件配送
def button_delivery(self): def button_delivery(self):
delivery_ids = [] delivery_ids = []
production_ids = []
is_cnc_down = 0 is_cnc_down = 0
is_not_production_line = 0 is_not_production_line = 0
is_not_route = 0 is_not_route = 0
@@ -1136,29 +1206,44 @@ class WorkPieceDelivery(models.Model):
num = 0 num = 0
for item in self: for item in self:
num += 1 num += 1
if num > 4:
raise UserError('仅限于配送1-4个制造订单请重新选择')
if item.route_id:
if same_route_id is None:
same_route_id = item.route_id.id
if item.route_id.id != same_route_id:
is_not_route += 1
else:
raise UserError('请选择【任务路线】再进行配送')
if production_type is None: if production_type is None:
production_type = item.type production_type = item.type
if production_type != item.type: if item.type == "运送空料架":
raise UserError('请选择类型为%s的制造订单进行配送' % production_type) if num >= 2:
if down_status != item.status: raise UserError('仅选择一条路线进行配送,请重新选择')
raise UserError('请选择状态为【待下发】的制造订单进行配送') else:
if same_production_line_id is None: delivery_ids.append(item.id)
same_production_line_id = item.production_line_id.id else:
if item.production_line_id.id != same_production_line_id: if num > 4:
is_not_production_line += 1 raise UserError('仅限于配送1-4个制造订单请重新选择')
if item.is_cnc_program_down is False: if item.status in ['待配送', '已配送']:
is_cnc_down += 1 raise UserError('请选择状态为【待下发】的制造订单进行配送')
if is_cnc_down == 0 and is_not_production_line == 0 and is_not_route == 0: if item.route_id:
delivery_ids.append(item.id) if same_route_id is None:
same_route_id = item.route_id.id
if item.route_id.id != same_route_id:
is_not_route += 1
else:
raise UserError('请选择【任务路线】再进行配送')
if production_type != item.type:
raise UserError('请选择类型为%s的制造订单进行配送' % production_type)
if down_status != item.status:
up_workpiece = self.search([('type', '=', '上产线'), ('production_id', '=', item.production_id),
('status', '=', '待下发')])
if up_workpiece:
raise UserError('您所选择的制造订单暂未上产线,请在上产线后再进行配送')
else:
raise UserError('请选择状态为【待下发】的制造订单进行配送')
if same_production_line_id is None:
same_production_line_id = item.production_line_id.id
if item.production_line_id.id != same_production_line_id:
is_not_production_line += 1
if item.is_cnc_program_down is False:
is_cnc_down += 1
if is_cnc_down == 0 and is_not_production_line == 0 and is_not_route == 0:
delivery_ids.append(item.id)
production_ids.append(item.production_id.id)
if is_cnc_down >= 1: if is_cnc_down >= 1:
raise UserError('您所选择制造订单的【CNC程序】暂未下发请在程序下发后再进行配送') raise UserError('您所选择制造订单的【CNC程序】暂未下发请在程序下发后再进行配送')
if is_not_production_line >= 1: if is_not_production_line >= 1:
@@ -1176,9 +1261,17 @@ class WorkPieceDelivery(models.Model):
'target': 'new', 'target': 'new',
'context': { 'context': {
'default_delivery_ids': [(6, 0, delivery_ids)], 'default_delivery_ids': [(6, 0, delivery_ids)],
'default_production_ids': [(6, 0, production_ids)],
'default_destination_production_line_id': same_production_line_id,
'default_route_id': same_route_id,
'default_type': production_type,
}} }}
else: else:
raise UserError("您所选择制造订单的【任务路线】的【终点接驳站】已占用,请在该接驳站空闲时进行配送") if self.type == '运送空料架':
raise UserError("您所选择的【任务路线】的【终点接驳站】已占用,请在该接驳站空闲时进行配送")
else:
raise UserError(
"您所选择制造订单的【任务路线】的【终点接驳站】已占用,请在该接驳站空闲时或选择其他路线进行配送")
# 验证agv站点是否可用 # 验证agv站点是否可用
def _check_avgsite_state(self): def _check_avgsite_state(self):
@@ -1187,15 +1280,18 @@ class WorkPieceDelivery(models.Model):
if agv_site: if agv_site:
agv_site.update_site_state() agv_site.update_site_state()
for item in self: for item in self:
if item.type in ["上产线", "下产线"]: logging.info('工件配送-起点状态:%s-%s' % (
logging.info('工件配送-起点状态:%s-%s' % ( item.feeder_station_start_id.name, item.feeder_station_start_id.state))
item.feeder_station_start_id.name, item.feeder_station_start_id.state)) logging.info('工件配送-终点状态:%s-%s' % (
logging.info('工件配送-终点状态:%s-%s' % ( item.feeder_station_destination_id.name, item.feeder_station_destination_id.state))
item.feeder_station_destination_id.name, item.feeder_station_destination_id.state)) if item.type in ['上产线', '下产线']:
if ( if (
item.feeder_station_start_id.state == '占用' and item.feeder_station_destination_id.state == '空闲') or ( item.feeder_station_start_id.state == '占用' and item.feeder_station_destination_id.state == '空闲') or (
item.feeder_station_start_id.state == '空闲' and item.feeder_station_destination_id.state == '空闲'): item.feeder_station_start_id.state == '空闲' and item.feeder_station_destination_id.state == '空闲'):
is_free = True is_free = True
else:
if item.feeder_station_destination_id.state == '空闲':
is_free = True
logging.info('is_free:%s' % is_free) logging.info('is_free:%s' % is_free)
return is_free return is_free
@@ -1206,12 +1302,23 @@ class WorkPieceDelivery(models.Model):
delivery_Arr = [] delivery_Arr = []
feeder_station_start = None feeder_station_start = None
feeder_station_destination = None feeder_station_destination = None
route_id = None
for item in self: for item in self:
if feeder_station_start is None: delivery_Arr.append(item.name)
feeder_station_start = item.feeder_station_start_id.name if item.type in ['上产线', '下产线']:
if feeder_station_destination is None: if route_id is None:
feeder_station_destination = item.feeder_station_destination_id.name route_id = item.route_id.id
delivery_Arr.append(item.delivery_num) if feeder_station_start is None:
feeder_station_start = item.feeder_station_start_id.name
if feeder_station_destination is None:
feeder_station_destination = item.feeder_station_destination_id.name
item.route_id = route_id
else:
self = self.create(
{'name': self.env['ir.sequence'].next_by_code('sf.workpiece.delivery'),
'route_id': self.route_id.id,
'feeder_station_start_id': self.feeder_station_start_id.id,
'feeder_station_destination_id': self.feeder_station_destination_id.id})
delivery_str = ','.join(map(str, delivery_Arr)) delivery_str = ','.join(map(str, delivery_Arr))
if feeder_station_start is not None: if feeder_station_start is not None:
positionCode_Arr.append({ positionCode_Arr.append({
@@ -1240,24 +1347,19 @@ class WorkPieceDelivery(models.Model):
req_codes = ret['reqCode'].split(',') req_codes = ret['reqCode'].split(',')
for delivery_item in self: for delivery_item in self:
for req_code in req_codes: for req_code in req_codes:
if delivery_item.delivery_num == req_code.strip(): if delivery_item.name == req_code.strip():
logging.info('delivery_num:%s' % delivery_item.delivery_num) logging.info('delivery_item-name:%s' % delivery_item.name)
delivery_item.write({ delivery_item.write({
'task_delivery_time': fields.Datetime.now(), 'task_delivery_time': fields.Datetime.now(),
'status': '待配送' 'status': '待配送'
}) })
delivery_item.workorder_id.write({'is_delivery': True}) if delivery_item == "上产线":
delivery_item.workorder_id.write({'is_delivery': True})
else: else:
raise UserError(ret['message']) raise UserError(ret['message'])
except Exception as e: except Exception as e:
logging.info('config-e:%s' % e) logging.info('config-e:%s' % e)
raise UserError("工件配送请求agv失败") raise UserError("工件配送请求agv失败:%s" % e)
@api.onchange('production_id.production_line_id')
def _compute_production_line_id(self):
if self.production_id.production_line_id:
self.production_line_id = self.production_id.production_line_id.id
self.plan_start_processing_time = self.production_id.plan_start_processing_time
@api.depends('task_delivery_time', 'task_completion_time') @api.depends('task_delivery_time', 'task_completion_time')
def _compute_delivery_duration(self): def _compute_delivery_duration(self):

View File

@@ -399,7 +399,7 @@ class ResProductMo(models.Model):
cutting_speed_ids = fields.One2many('sf.cutting.speed', 'product_template_id', string='切削速度Vc') cutting_speed_ids = fields.One2many('sf.cutting.speed', 'product_template_id', string='切削速度Vc')
feed_per_tooth_ids = fields.One2many('sf.feed.per.tooth', 'product_template_id', string='每齿走刀量fz') feed_per_tooth_ids = fields.One2many('sf.feed.per.tooth', 'product_template_id', string='每齿走刀量fz')
cutting_tool_diameter = fields.Float('直径(mm)') cutting_tool_diameter = fields.Float('刀具直径(mm)')
cutting_tool_rear_angle = fields.Integer('后角(°)') cutting_tool_rear_angle = fields.Integer('后角(°)')
cutting_tool_main_included_angle = fields.Integer('主偏角(°)') cutting_tool_main_included_angle = fields.Integer('主偏角(°)')
# 适用夹头型号可以多选 # 适用夹头型号可以多选

View File

@@ -52,8 +52,8 @@ access_mrp_bom_manager_group_sf_mrp_user,mrp.bom.manager,mrp.model_mrp_bom,sf_ba
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_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_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
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 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
access_mrp_production_stock_worker,mrp.production stock_worker,mrp.model_mrp_production,stock.group_stock_user,1,0,0,0 access_mrp_production_stock_worker,mrp.production stock_worker,mrp.model_mrp_production,stock.group_stock_user,1,0,0,0
access_product_product_user_group_sf_mrp_user,product.product user,product.model_product_product,sf_base.group_sf_mrp_user,1,0,0,0 access_product_product_user_group_sf_mrp_user,product.product user,product.model_product_product,sf_base.group_sf_mrp_user,1,0,0,0
@@ -132,4 +132,5 @@ access_maintenance_equipment_tool_group_plan_dispatch,maintenance.equipment.tool
access_sf_workpiece_delivery_group_plan_dispatch,sf.workpiece.delivery,sf_manufacturing.model_sf_workpiece_delivery,sf_base.group_plan_dispatch,1,0,0,0 access_sf_workpiece_delivery_group_plan_dispatch,sf.workpiece.delivery,sf_manufacturing.model_sf_workpiece_delivery,sf_base.group_plan_dispatch,1,0,0,0
access_sf_agv_site_group_sf_order_user,sf_agv_site_group_sf_order_user,model_sf_agv_site,sf_base.group_sf_order_user,1,1,1,0 access_sf_agv_site_group_sf_order_user,sf_agv_site_group_sf_order_user,model_sf_agv_site,sf_base.group_sf_order_user,1,1,1,0
access_sf_agv_task_route_group_sf_order_user,sf_agv_task_route_group_sf_order_user,model_sf_agv_task_route,sf_base.group_sf_order_user,1,1,1,0 access_sf_agv_task_route_group_sf_order_user,sf_agv_task_route_group_sf_order_user,model_sf_agv_task_route,sf_base.group_sf_order_user,1,1,1,0
access_center_control_interface_log_admin,center_control_interface_log_admin,model_center_control_interface_log,base.group_system,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_group_plan_director mrp_bom_line_group_plan_director mrp.model_mrp_bom_line sf_base.group_plan_director 1 1 1 0
53 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
54 access_mrp_bom_line_group_purchase_director access_mrp_bom_line_group_sale_salemanager mrp_bom_line_group_purchase_director mrp_bom_line_group_sale_salemanager mrp.model_mrp_bom_line sf_base.group_purchase_director sf_base.group_sale_salemanager 1 1 0 1 0
55 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
56 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
access_mrp_production_stock_worker mrp.production stock_worker mrp.model_mrp_production stock.group_stock_user 1 0 0 0
57 access_product_product_user_group_sf_mrp_user access_mrp_production_stock_worker product.product user mrp.production stock_worker product.model_product_product mrp.model_mrp_production sf_base.group_sf_mrp_user stock.group_stock_user 1 0 0 0
58 access_product_template_user_group_sf_mrp_user access_product_product_user_group_sf_mrp_user product.template user product.product user product.model_product_template product.model_product_product sf_base.group_sf_mrp_user 1 0 0 0
59 access_uom_uom_user access_product_template_user_group_sf_mrp_user uom.uom user_group_sf_mrp_user product.template user uom.model_uom_uom product.model_product_template sf_base.group_sf_mrp_user 1 0 0 0
132
133
134
135
136

View File

@@ -34,7 +34,8 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree editable="bottom"> <tree editable="bottom">
<field name="name" required="1"/> <field name="name" required="1"/>
<field name="type" readonly="1"/> <field name="type" readonly="1" string="任务类型"/>
<field name="route_type" string="类型"/>
<field name="start_site_id" required="1" options="{'no_create': True}" string="起点接驳站"/> <field name="start_site_id" required="1" options="{'no_create': True}" string="起点接驳站"/>
<field name="end_site_id" required="1" options="{'no_create': True}" string="终点接驳站"/> <field name="end_site_id" required="1" options="{'no_create': True}" string="终点接驳站"/>
<field name="destination_production_line_id" required="1" options="{'no_create': True}"/> <field name="destination_production_line_id" required="1" options="{'no_create': True}"/>
@@ -54,4 +55,36 @@
sequence="13" sequence="13"
action="action_agv_task_route_form"/> action="action_agv_task_route_form"/>
</data> </data>
<record model="ir.ui.view" id="center_control_interface_logging_tree_view">
<field name="model">center_control.interface.log</field>
<field name="arch" type="xml">
<tree string="Logs" create="0" edit="0" delete="0">
<field name="name"/>
<field name="content"/>
<field name="interface_call_date"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="center_control_interface_logging_search_view">
<field name="model">center_control.interface.log</field>
<field name="arch" type="xml">
<search string="Logs">
<field name="name"/>
<group expand="0" string="分组">
<field name="interface_call_date"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="center_control_interface_logging_act">
<field name="name">中控调用日志</field>
<field name="res_model">center_control.interface.log</field>
<field name="view_mode">tree</field>
</record>
<menuitem parent="base.next_id_9" id="center_control_interface_logging_menu"
action="center_control_interface_logging_act"/>
</odoo> </odoo>

View File

@@ -78,13 +78,14 @@
<field name="programming_no" readonly="1"/> <field name="programming_no" readonly="1"/>
<field name="work_state" invisible="1"/> <field name="work_state" invisible="1"/>
<field name="schedule_state" invisible='1'/> <field name="schedule_state" invisible='1'/>
<field name="manual_quotation" readonly="1"/>
<field name="programming_state" readonly="1"/> <field name="programming_state" readonly="1"/>
<field name="production_line_id" readonly="1"/>
</xpath> </xpath>
<xpath expr="//field[@name='user_id']" position="before"> <xpath expr="//field[@name='user_id']" position="before">
<field name="plan_start_processing_time" readonly="1"/> <field name="plan_start_processing_time" readonly="1"/>
</xpath> </xpath>
<xpath expr="//field[@name='user_id']" position="after"> <xpath expr="//field[@name='user_id']" position="after">
<field name="production_line_id" readonly="1"/>
<field name="production_line_state" readonly="1"/> <field name="production_line_state" readonly="1"/>
<field name="part_number"/> <field name="part_number"/>
<field name="part_drawing"/> <field name="part_drawing"/>
@@ -258,6 +259,18 @@
</field> </field>
</record> </record>
<record id="product_template_search_view_manual_quotation" model="ir.ui.view">
<field name="name">product.template.search</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_search_view"/>
<field name="arch" type="xml">
<xpath expr="//filter[@name='consumable']" position="after">
<separator/>
<filter string="人工编程" name="manual_quotation" domain="[('manual_quotation', '=', True)]"/>
</xpath>
</field>
</record>
<!-- 工单的操作按钮只让制造用户可见 --> <!-- 工单的操作按钮只让制造用户可见 -->
<record id="sf_mrp_production_workorder_tree_editable_view" model="ir.ui.view"> <record id="sf_mrp_production_workorder_tree_editable_view" model="ir.ui.view">
<field name="name">sf.mrp.production.workorder.tree.editable</field> <field name="name">sf.mrp.production.workorder.tree.editable</field>
@@ -380,7 +393,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//search" position="inside"> <xpath expr="//search" position="inside">
<searchpanel class="account_root"> <searchpanel class="account_root">
<field name="state" icon="fa-filter"/> <field name="state" icon="fa-filter" enable_counters="1"/>
</searchpanel> </searchpanel>
</xpath> </xpath>
<filter name='todo' position="replace"/> <filter name='todo' position="replace"/>

View File

@@ -43,7 +43,7 @@
<attribute name="attrs">{'invisible': <attribute name="attrs">{'invisible':
['|',("user_permissions","=",False),("name","=","获取CNC加工程序")]} ['|',("user_permissions","=",False),("name","=","获取CNC加工程序")]}
</attribute> </attribute>
<!-- <attribute name="string">停工</attribute> --> <!-- <attribute name="string">停工</attribute> -->
</xpath> </xpath>
<xpath expr="//button[@name='action_open_wizard']" position="attributes"> <xpath expr="//button[@name='action_open_wizard']" position="attributes">
<attribute name="invisible">1</attribute> <attribute name="invisible">1</attribute>
@@ -111,36 +111,38 @@
<field name='name' invisible="1"/> <field name='name' invisible="1"/>
<field name='is_delivery' invisible="1"/> <field name='is_delivery' invisible="1"/>
<!-- 工单form页面的开始停工按钮等 --> <!-- 工单form页面的开始停工按钮等 -->
<!-- <button name="button_start" type="object" string="开始" class="btn-success" --> <!-- <button name="button_start" type="object" string="开始" class="btn-success" -->
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'not in', ('pending_processing', 'pending_cam', 'pending_era_cam')), ('state','!=','ready'), ('routing_type', 'not in', ('装夹预调', 'CNC加工', '解除装夹'))]}" --> <!-- attrs="{'invisible': ['|', '|', ('production_state', 'not in', ('pending_processing', 'pending_cam', 'pending_era_cam')), ('state','!=','ready'), ('routing_type', 'not in', ('装夹预调', 'CNC加工', '解除装夹'))]}" -->
<!-- groups="sf_base.group_sf_mrp_user"/> --> <!-- groups="sf_base.group_sf_mrp_user"/> -->
<!-- <button name="button_pending" type="object" string="暂停" class="btn-warning" --> <!-- <button name="button_pending" type="object" string="暂停" class="btn-warning" -->
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'not in', ('pending_processing', 'pending_cam', 'pending_era_cam')), ('state','!=','progress'), ('routing_type', 'not in', ('装夹预调', 'CNC加工', '解除装夹'))]}" --> <!-- attrs="{'invisible': ['|', '|', ('production_state', 'not in', ('pending_processing', 'pending_cam', 'pending_era_cam')), ('state','!=','progress'), ('routing_type', 'not in', ('装夹预调', 'CNC加工', '解除装夹'))]}" -->
<!-- groups="sf_base.group_sf_mrp_user"/> --> <!-- groups="sf_base.group_sf_mrp_user"/> -->
<!-- <button name="button_finish" type="object" string="完成" class="btn-success" --> <!-- <button name="button_finish" type="object" string="完成" class="btn-success" -->
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'not in', ('pending_processing', 'pending_cam', 'pending_era_cam')), ('state','!=','progress'), ('routing_type', 'not in', ('装夹预调', 'CNC加工', '解除装夹'))]}" --> <!-- attrs="{'invisible': ['|', '|', ('production_state', 'not in', ('pending_processing', 'pending_cam', 'pending_era_cam')), ('state','!=','progress'), ('routing_type', 'not in', ('装夹预调', 'CNC加工', '解除装夹'))]}" -->
<!-- groups="sf_base.group_sf_mrp_user" confirm="是否确认完工"/> --> <!-- groups="sf_base.group_sf_mrp_user" confirm="是否确认完工"/> -->
<button name="button_start" type="object" string="开始" class="btn-success" <button name="button_start" type="object" string="开始" class="btn-success"
attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=', False)]}"/> attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=', False)]}"/>
<button name="button_pending" type="object" string="暂停" class="btn-warning" <button name="button_pending" type="object" string="暂停" class="btn-warning"
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/> attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
<button name="button_finish" type="object" string="完成" class="btn-success" <button name="button_finish" type="object" string="完成" class="btn-success" confirm="是否确认完工"
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/> attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
<button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="阻塞" context="{'default_workcenter_id': workcenter_id}" class="btn-danger" <button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="阻塞"
attrs="{'invisible': ['|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked')]}"/> context="{'default_workcenter_id': workcenter_id}" class="btn-danger"
<button name="button_unblock" type="object" string="取消阻塞" context="{'default_workcenter_id': workcenter_id}" class="btn-danger" attrs="{'invisible': ['|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked')]}"/>
attrs="{'invisible': ['|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked')]}"/> <button name="button_unblock" type="object" string="取消阻塞"
context="{'default_workcenter_id': workcenter_id}" class="btn-danger"
attrs="{'invisible': ['|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked')]}"/>
<!-- <button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="停工" --> <!-- <button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="停工" -->
<!-- context="{'default_workcenter_id': workcenter_id}" class="btn-danger" --> <!-- context="{'default_workcenter_id': workcenter_id}" class="btn-danger" -->
<!-- groups="sf_base.group_sf_mrp_user" --> <!-- groups="sf_base.group_sf_mrp_user" -->
<!-- attrs="{'invisible': ['|', ('production_state', '!=', 'pending_processing'), ('state','!=','progress')]}"/> --> <!-- attrs="{'invisible': ['|', ('production_state', '!=', 'pending_processing'), ('state','!=','progress')]}"/> -->
<!-- <button name="button_unblock" type="object" string="Unblock" --> <!-- <button name="button_unblock" type="object" string="Unblock" -->
<!-- context="{'default_workcenter_id': workcenter_id}" class="btn-danger" --> <!-- context="{'default_workcenter_id': workcenter_id}" class="btn-danger" -->
<!-- groups="sf_base.group_sf_mrp_user" --> <!-- groups="sf_base.group_sf_mrp_user" -->
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('state','=','done')]}"/> --> <!-- attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('state','=','done')]}"/> -->
<button name="button_workpiece_delivery" type="object" string="工件配送" class="btn-primary" <button name="button_workpiece_delivery" type="object" string="工件配送" class="btn-primary"
attrs="{'invisible': ['|',('routing_type','!=','装夹预调'),('is_delivery','=',True)]}"/> attrs="{'invisible': ['|',('routing_type','!=','装夹预调'),('is_delivery','=',True)]}"/>
@@ -196,6 +198,8 @@
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/> attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="equipment_id" <field name="equipment_id"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/> attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="production_line_id"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="production_line_state" <field name="production_line_state"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/> attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="functional_fixture_id" <field name="functional_fixture_id"
@@ -602,13 +606,13 @@
decoration-warning="status == '待下发'" decoration-warning="status == '待下发'"
decoration-danger="status == '待配送'"/> decoration-danger="status == '待配送'"/>
<field name="production_id"/> <field name="production_id"/>
<field name="type"/> <field name="type" readonly="1"/>
<!-- <field name="delivery_num" />-->
<field name="production_line_id" options="{'no_create': True}"/> <field name="production_line_id" options="{'no_create': True}"/>
<field name="route_id" options="{'no_create': True}"/> <field name="route_id" options="{'no_create': True}"/>
<field name="feeder_station_start_id" readonly="1" force_save="1"/> <field name="feeder_station_start_id" readonly="1" force_save="1"/>
<field name="feeder_station_destination_id" readonly="1" force_save="1"/> <field name="feeder_station_destination_id" readonly="1" force_save="1"/>
<field name="is_cnc_program_down" readonly="1"/> <field name="is_cnc_program_down" readonly="1"/>
<!-- <field name="rfid_code"/>-->
<field name="task_delivery_time" readonly="1"/> <field name="task_delivery_time" readonly="1"/>
<field name="task_completion_time" readonly="1"/> <field name="task_completion_time" readonly="1"/>
<field name="delivery_duration" widget="float_time"/> <field name="delivery_duration" widget="float_time"/>
@@ -621,9 +625,9 @@
<field name="model">sf.workpiece.delivery</field> <field name="model">sf.workpiece.delivery</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="工件配送"> <search string="工件配送">
<filter string="待下发" name="on_down" domain="[('status', '=', '待下发'),('type','=',['上产线'])]"/> <filter string="上产线" name="on_up" domain="[('type', '=', '上产线')]"/>
<filter string="产线" name="down" domain="[('type', '=', '产线')]"/> <filter string="产线" name="on_down" domain="[('type', '=', '产线' )]"/>
<filter string="下产线" name="up" domain="[('type', '=', '下产线')]"/> <field name="rfid_code"/>
<field name="production_id"/> <field name="production_id"/>
<field name="feeder_station_start_id"/> <field name="feeder_station_start_id"/>
<field name="production_line_id"/> <field name="production_line_id"/>
@@ -644,9 +648,68 @@
<field name="name">工件配送</field> <field name="name">工件配送</field>
<field name="res_model">sf.workpiece.delivery</field> <field name="res_model">sf.workpiece.delivery</field>
<field name="search_view_id" ref="sf_workpiece_delivery_search"/> <field name="search_view_id" ref="sf_workpiece_delivery_search"/>
<field name="context">{'search_default_on_down':1}</field> <field name="context">{'search_default_on_up':1}</field>
<field name="view_mode">tree,search</field> <field name="view_mode">tree,search</field>
<field name="domain">[('type','in',['上产线','下产线'])]</field> <field name="domain">[('type','in',['上产线','下产线']),('workorder_state','=','done')]</field>
</record>
<!--=========================================运送空料架列表======================================-->
<record id="sf_workpiece_delivery_empty_racks_template_tree" model="ir.ui.view">
<field name="name">空料架配送</field>
<field name="model">sf.workpiece.delivery</field>
<field name="arch" type="xml">
<tree string="工件配送" class="center" create="0" edit="0" delete="0">
<header>
<button name="button_delivery" type="object" string="配送" class="oe_highlight"/>
</header>
<field name="name" string="路线名称" readonly="1"/>
<field name="route_id" options="{'no_create': True}"/>
<field name="feeder_station_start_id" readonly="1"/>
<field name="feeder_station_destination_id" readonly="1"/>
<button name="action_delivery_history" type="object" class="btn btn-link text-info" icon="fa-history"
string="历史"/>
</tree>
</field>
</record>
<record id="sf_workpiece_delivery_empty_racks_tree" model="ir.ui.view">
<field name="name">空料架配送</field>
<field name="model">sf.workpiece.delivery</field>
<field name="arch" type="xml">
<tree string="运送空料架" class="center" create="0" delete="0" edit="0">
<field name="status"/>
<field name="route_id"/>
<field name="feeder_station_start_id"/>
<field name="feeder_station_destination_id"/>
<field name="task_delivery_time"/>
<field name="task_completion_time"/>
<field name="delivery_duration" widget="float_time"/>
</tree>
</field>
</record>
<record id="sf_workpiece_delivery_empty_racks_search" model="ir.ui.view">
<field name="name">空料架配送</field>
<field name="model">sf.workpiece.delivery</field>
<field name="arch" type="xml">
<search string="运送空料架">
<field name="route_id"/>
<field name="feeder_station_start_id"/>
<field name="feeder_station_destination_id"/>
</search>
</field>
</record>
<record id="sf_workpiece_delivery_empty_racks_act" model="ir.actions.act_window">
<field name="name">空料架配送</field>
<field name="res_model">sf.workpiece.delivery</field>
<field name="view_id" ref="sf_workpiece_delivery_empty_racks_template_tree"/>
<field name="search_view_id" ref="sf_workpiece_delivery_empty_racks_search"/>
<field name="view_mode">tree</field>
<field name="domain">[('type','in',['运送空料架']),('name','not ilike','WDO')]</field>
</record> </record>
</odoo> </odoo>

View File

@@ -5,13 +5,32 @@
<field name="model">sf.workpiece.delivery.wizard</field> <field name="model">sf.workpiece.delivery.wizard</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<sheet>
<field name="delivery_ids" invisible="True"/> <field name="delivery_ids" invisible="True"/>
<field name="workorder_id" invisible="True"/> <field name="workorder_id" invisible="True"/>
<div>是否确定配送?</div> <field name="type" invisible="True"/>
<footer> <group attrs="{'invisible': [('type', 'in', ['运送空料架'])]}">
<button string="确认" name="confirm" type="object" class="oe_highlight"/> <field name="production_ids" readonly="1" widget="many2many_tags" string="制造订单号"/>
<button string="取消" class="btn btn-secondary" special="cancel"/> <div class="o_address_format">
</footer> <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="destination_production_line_id" readonly="1"/>
<field name="route_id"/>
</group>
<group attrs="{'invisible': [('type', 'in', ['运送空料架'])]}">
<field name="feeder_station_start_id" focesave="1" readonly="1"/>
<field name="feeder_station_destination_id" focesave="1" readonly="1"/>
</group>
<div attrs="{'invisible': [('type', 'in', ['上产线','下产线'])]}">
是否确定配送
</div>
<footer>
<button string="配送" name="confirm" type="object" class="oe_highlight"/>
<button string="取消" class="btn btn-secondary" special="cancel"/>
</footer>
</sheet>
</form> </form>
</field> </field>
</record> </record>

View File

@@ -2,7 +2,7 @@
# Part of YiZuo. See LICENSE file for full copyright and licensing details. # Part of YiZuo. See LICENSE file for full copyright and licensing details.
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, _
class WorkpieceDeliveryWizard(models.TransientModel): class WorkpieceDeliveryWizard(models.TransientModel):
@@ -10,10 +10,74 @@ class WorkpieceDeliveryWizard(models.TransientModel):
_description = '工件配送' _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_id = fields.Many2one('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', ['上产线', '下产线'])])
feeder_station_start_id = fields.Many2one('sf.agv.site', '起点接驳站')
feeder_station_destination_id = fields.Many2one('sf.agv.site', '目的接驳站')
type = fields.Selection(
[('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型')
def confirm(self): def confirm(self):
if self.type != '运送空料架':
if not self.route_id:
raise UserError('请选择路线')
if self.workorder_id: if self.workorder_id:
self.workorder_id.workpiece_delivery_ids[0]._delivery_avg() self.workorder_id.workpiece_delivery_ids[0]._delivery_avg()
else: else:
self.delivery_ids._delivery_avg() is_not_production_line = 0
same_production_line_id = None
notsame_production_line_arr = []
for item in self.production_ids:
if same_production_line_id is None:
same_production_line_id = item.production_line_id.id
if item.production_line_id.id != same_production_line_id:
notsame_production_line_arr.append(item.name)
notsame_production_line_str = ','.join(map(str, notsame_production_line_arr))
if is_not_production_line >= 1:
raise UserError('制造订单号为%s的目的生产线不一致' % notsame_production_line_str)
else:
self.delivery_ids._delivery_avg()
def recognize_production(self):
# production_ids = []
# delivery_ids = []
if len(self.production_ids) > 4:
raise UserError('只能配送四个制造订单')
else:
if self.rfid_code:
wd = self.env['sf.workpiece.delivery'].search(
[('type', '=', self.delivery_ids[0].type), ('rfid_code', '=', self.rfid_code),
('status', '=', self.delivery_ids[0].status)])
if wd:
if wd.production_line_id.id == self.delivery_ids[0].production_line_id.id:
# production_ids.append(wd.production_id)
# delivery_ids.append(wd.id)
# 将对象添加到对应的同模型且是多对多类型里
self.production_ids |= wd.production_id
self.delivery_ids |= wd
self.rfid_code = False
# self.production_ids = [(6, 0, production_ids)]
# self.delivery_ids = [(6, 0, delivery_ids)]
else:
raise UserError('该rfid对应的制造订单号为%s的目的生产线不一致' % wd.production_id.name)
return {
'name': _('确认'),
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'sf.workpiece.delivery.wizard',
'target': 'new',
'context': {
'default_delivery_ids': [(6, 0, self.delivery_ids.ids)],
'default_production_ids': [(6, 0, self.production_ids.ids)],
'default_route_id': self.delivery_ids[0].route_id.id,
'default_type': self.delivery_ids[0].type
}}
@api.onchange('route_id')
def onchange_route(self):
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

View File

@@ -84,7 +84,8 @@ class sf_production_plan(models.Model):
item.sudo().production_id.production_line_id = item.production_line_id.id item.sudo().production_id.production_line_id = item.production_line_id.id
item.sudo().production_id.workorder_ids.filtered( item.sudo().production_id.workorder_ids.filtered(
lambda b: b.routing_type == "装夹预调").workpiece_delivery_ids.write( lambda b: b.routing_type == "装夹预调").workpiece_delivery_ids.write(
{'production_line_id': item.production_line_id.id}) {'production_line_id': item.production_line_id.id,
'plan_start_processing_time': item.plan_start_processing_time})
# item.sudo().production_id.plan_start_processing_time = item.date_planned_start # item.sudo().production_id.plan_start_processing_time = item.date_planned_start
# @api.onchange('state') # @api.onchange('state')

View File

@@ -306,6 +306,14 @@
action="sf_manufacturing.sf_workpiece_delivery_act" action="sf_manufacturing.sf_workpiece_delivery_act"
parent="mrp.menu_mrp_manufacturing" parent="mrp.menu_mrp_manufacturing"
/> />
<menuitem
id="sf_workpiece_delivery__empty_racks_menu"
name="空料架配送"
sequence="11"
action="sf_manufacturing.sf_workpiece_delivery_empty_racks_act"
parent="mrp.menu_mrp_manufacturing"
/>
<!-- <menuitem --> <!-- <menuitem -->
<!-- id="sale_custom_menu" --> <!-- id="sale_custom_menu" -->
<!-- name="报价单" --> <!-- name="报价单" -->

View File

@@ -17,7 +17,6 @@ from odoo.addons.sf_base.commons.common import Common
from . import parser_and_calculate_work_time as pc from . import parser_and_calculate_work_time as pc
class QuickEasyOrder(models.Model): class QuickEasyOrder(models.Model):
_name = 'quick.easy.order' _name = 'quick.easy.order'
_description = '简易下单' _description = '简易下单'
@@ -55,6 +54,7 @@ class QuickEasyOrder(models.Model):
('success', '成功'), ('success', '成功'),
('fail', '失败')], string='模型上色状态') ('fail', '失败')], string='模型上色状态')
processing_time = fields.Integer('加工时长(min)') processing_time = fields.Integer('加工时长(min)')
sale_order_id = fields.Many2one('sale.order', '销售订单号')
@api.depends('unit_price', 'quantity') @api.depends('unit_price', 'quantity')
def _compute_total_amount(self): def _compute_total_amount(self):
@@ -89,7 +89,8 @@ class QuickEasyOrder(models.Model):
obj = super(QuickEasyOrder, self).create(vals) obj = super(QuickEasyOrder, self).create(vals)
# self.model_coloring(obj) # self.model_coloring(obj)
logging.info('---------开始派单到工厂-------') logging.info('---------开始派单到工厂-------')
self.distribute_to_factory(obj) sale_order = self.distribute_to_factory(obj)
obj.sale_order_id = sale_order.id
obj.state = '待接单' obj.state = '待接单'
return obj return obj

View File

@@ -51,6 +51,7 @@ class QuickEasyOrder(models.Model):
('success', '成功'), ('success', '成功'),
('fail', '失败')], string='模型上色状态') ('fail', '失败')], string='模型上色状态')
processing_time = fields.Integer('加工时长(min)') processing_time = fields.Integer('加工时长(min)')
sale_order_id = fields.Many2one('sale.order', '销售订单号')
@api.depends('unit_price', 'quantity') @api.depends('unit_price', 'quantity')
def _compute_total_amount(self): def _compute_total_amount(self):
@@ -79,12 +80,12 @@ class QuickEasyOrder(models.Model):
base64_datas = base64_data.decode('utf-8') base64_datas = base64_data.decode('utf-8')
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest() model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
report_path = attachment._full_path(attachment.store_fname) report_path = attachment._full_path(attachment.store_fname)
vals['model_file'] = self.transition_glb_file(report_path, model_code)
obj = super(QuickEasyOrder, self).create(vals) obj = super(QuickEasyOrder, self).create(vals)
logging.info('---------向cloud生成模型库记录-------') logging.info('---------向cloud生成模型库记录-------')
self.model_coloring(obj) self.model_coloring(obj)
logging.info('---------开始派单到工厂-------') logging.info('---------开始派单到工厂-------')
self.distribute_to_factory(obj) sale_order = self.distribute_to_factory(obj)
obj.sale_order_id = sale_order.id
obj.state = '待接单' obj.state = '待接单'
return obj return obj
@@ -264,6 +265,7 @@ class QuickEasyOrder(models.Model):
product_bom_purchase = self.env['mrp.bom'].bom_create(product, 'normal', False) product_bom_purchase = self.env['mrp.bom'].bom_create(product, 'normal', False)
product_bom_purchase.bom_create_line_has(purchase_embryo) product_bom_purchase.bom_create_line_has(purchase_embryo)
order_id.with_user(self.env.ref("base.user_admin")).sale_order_create_line(product, item) order_id.with_user(self.env.ref("base.user_admin")).sale_order_create_line(product, item)
return order_id
except Exception as e: except Exception as e:
# self.cr.rollback() # self.cr.rollback()
return UserError('工厂创建销售订单和产品失败,请联系管理员') return UserError('工厂创建销售订单和产品失败,请联系管理员')

View File

@@ -85,9 +85,9 @@ class ReSaleOrder(models.Model):
self.check_status = 'pending' self.check_status = 'pending'
def get_customer(self): def get_customer(self):
partner_tag = self.env['res.partner.category'].search([('name', '=', '业务平台')], limit=1, order='id asc') partner_tag = self.env['res.partner.category'].sudo().search([('name', '=', '业务平台')], limit=1, order='id asc')
if not partner_tag: if not partner_tag:
partner_tag = self.env['res.partner.category'].create({'name': '平台客户'}) partner_tag = self.env['res.partner.category'].sudo().create({'name': '平台客户'})
customer = self.env['res.partner'].search([('name', '=', '业务平台')], limit=1, order='id asc') customer = self.env['res.partner'].search([('name', '=', '业务平台')], limit=1, order='id asc')
if customer: if customer:
if not customer.vat: if not customer.vat:
@@ -141,6 +141,19 @@ class ResaleOrderLine(models.Model):
model_glb_file = fields.Binary('模型的glb文件') model_glb_file = fields.Binary('模型的glb文件')
check_status = fields.Selection(related='order_id.check_status') check_status = fields.Selection(related='order_id.check_status')
@api.onchange('product_id')
def _compute_model_glb_file(self):
for line in self:
if line.product_template_id:
if not line.model_glb_file:
line.update({
'model_glb_file': line.product_id.product_tmpl_id.model_file,
})
if not line.price_unit:
line.update({
'price_unit': line.product_id.product_tmpl_id.list_price,
})
class ProductTemplate(models.Model): class ProductTemplate(models.Model):
_inherit = 'product.template' _inherit = 'product.template'
@@ -151,23 +164,18 @@ class ProductTemplate(models.Model):
class RePurchaseOrder(models.Model): class RePurchaseOrder(models.Model):
_inherit = 'purchase.order' _inherit = 'purchase.order'
check_status = fields.Selection([('pending', '待审核'), ('approved', '已审核'), ('fail', '不通过')], '审核状态')
remark = fields.Text('备注') remark = fields.Text('备注')
user_id = fields.Many2one( user_id = fields.Many2one(
'res.users', string='买家', index=True, tracking=True, 'res.users', string='买家', index=True, tracking=True,
compute='_compute_user_id', compute='_compute_user_id',
store=True) store=True)
def button_confirming(self):
self.write({'state': 'purchase', 'check_status': 'pending'})
@api.depends('partner_id') @api.depends('partner_id')
def _compute_user_id(self): def _compute_user_id(self):
if not self.user_id: if not self.user_id:
if self.partner_id: if self.partner_id:
self.user_id = self.partner_id.purchase_user_id.id self.user_id = self.partner_id.purchase_user_id.id
self.check_status = 'pending' # self.state = 'purchase'
self.state = 'purchase'
else: else:
self.user_id = self.env.user.id self.user_id = self.env.user.id
@@ -190,28 +198,6 @@ class RePurchaseOrder(models.Model):
if not line.taxes_id: if not line.taxes_id:
raise UserError('请对【产品】中的【税】进行选择') raise UserError('请对【产品】中的【税】进行选择')
def write(self, vals):
if self.env.user.has_group('sf_base.group_purchase_director'):
if vals.get('check_status'):
if vals['check_status'] in ('pending', False):
vals['check_status'] = 'approved'
return super().write(vals)
def button_confirm(self):
for order in self:
if order.state not in ['draft', 'sent', 'purchase']:
continue
order.order_line._validate_analytic_distribution()
order._add_supplier_to_product()
# Deal with double validation process
if order._approval_allowed():
order.button_approve()
else:
order.write({'state': 'to approve'})
if order.partner_id not in order.message_partner_ids:
order.message_subscribe([order.partner_id.id])
return True
@api.onchange('order_line') @api.onchange('order_line')
def _onchange_order_line(self): def _onchange_order_line(self):
for order in self: for order in self:

View File

@@ -99,6 +99,26 @@
<field name="perm_read" eval="1"/> <field name="perm_read" eval="1"/>
<field name="perm_write" eval="1"/> <field name="perm_write" eval="1"/>
<field name="perm_create" eval="1"/> <field name="perm_create" eval="1"/>
</record>
<record model="ir.rule" id="quick_easy_order_rule_salemanager">
<field name="name">销售经理只可以查看本人的快速订单</field>
<field name="model_id" ref="model_quick_easy_order"/>
<field name="domain_force">[('create_uid', '=',user.id)]</field>
<field name="groups" eval="[(4, ref('sf_base.group_sale_salemanager'))]"/>
<field name="perm_read" eval="1"/>
<field name="perm_write" eval="0"/>
<field name="perm_create" eval="0"/>
</record>
<record model="ir.rule" id="quick_easy_order_rule_director">
<field name="name">销售总监查看所有快速订单</field>
<field name="model_id" ref="model_quick_easy_order"/>
<field name="domain_force">[(1,'=',1)]</field>
<field name="groups" eval="[(4, ref('sf_base.group_sale_director'))]"/>
<field name="perm_read" eval="1"/>
<field name="perm_write" eval="1"/>
<field name="perm_create" eval="1"/>
</record> </record>
</data> </data>
</odoo> </odoo>

View File

@@ -32,8 +32,8 @@ access_stock_picking_group_quality_director,stock_picking_group_quality_director
access_account_move_group_sale_salemanager,account_move_group_sale_salemanager,account.model_account_move,sf_base.group_sale_salemanager,1,0,0,0 access_account_move_group_sale_salemanager,account_move_group_sale_salemanager,account.model_account_move,sf_base.group_sale_salemanager,1,0,0,0
access_account_move_group_sale_director,account_move_group_sale_director,account.model_account_move,sf_base.group_sale_director,1,0,0,0 access_account_move_group_sale_director,account_move_group_sale_director,account.model_account_move,sf_base.group_sale_director,1,0,0,0
access_resource_resource_group_sale_director,resource_resource_group_sale_director,resource.model_resource_resource,sf_base.group_sale_director,1,1,1,0 access_resource_resource_group_sale_director,resource_resource_group_sale_director,resource.model_resource_resource,sf_base.group_sale_director,1,1,1,0
access_mrp_bom_group_sale_salemanager,mrp_bom_group_sale_salemanager,mrp.model_mrp_bom,sf_base.group_sale_salemanager,1,0,0,0 access_mrp_bom_group_sale_salemanager,mrp_bom_group_sale_salemanager,mrp.model_mrp_bom,sf_base.group_sale_salemanager,1,0,1,0
access_mrp_bom_group_sale_director,mrp_bom_group_sale_director,mrp.model_mrp_bom,sf_base.group_sale_director,1,0,0,0 access_mrp_bom_group_sale_director,mrp_bom_group_sale_director,mrp.model_mrp_bom,sf_base.group_sale_director,1,0,1,0
access_mrp_bom_group_purchase,mrp_bom_group_purchase,mrp.model_mrp_bom,sf_base.group_purchase,1,0,0,0 access_mrp_bom_group_purchase,mrp_bom_group_purchase,mrp.model_mrp_bom,sf_base.group_purchase,1,0,0,0
access_mrp_bom_group_purchase_director,mrp_bom_group_purchase_director,mrp.model_mrp_bom,sf_base.group_purchase_director,1,0,0,0 access_mrp_bom_group_purchase_director,mrp_bom_group_purchase_director,mrp.model_mrp_bom,sf_base.group_purchase_director,1,0,0,0
access_mrp_bom_group_quality,mrp_bom_group_quality,mrp.model_mrp_bom,sf_base.group_quality,1,0,0,0 access_mrp_bom_group_quality,mrp_bom_group_quality,mrp.model_mrp_bom,sf_base.group_quality,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
32 access_account_move_group_sale_director account_move_group_sale_director account.model_account_move sf_base.group_sale_director 1 0 0 0
33 access_resource_resource_group_sale_director resource_resource_group_sale_director resource.model_resource_resource sf_base.group_sale_director 1 1 1 0
34 access_mrp_bom_group_sale_salemanager mrp_bom_group_sale_salemanager mrp.model_mrp_bom sf_base.group_sale_salemanager 1 0 0 1 0
35 access_mrp_bom_group_sale_director mrp_bom_group_sale_director mrp.model_mrp_bom sf_base.group_sale_director 1 0 0 1 0
36 access_mrp_bom_group_purchase mrp_bom_group_purchase mrp.model_mrp_bom sf_base.group_purchase 1 0 0 0
37 access_mrp_bom_group_purchase_director mrp_bom_group_purchase_director mrp.model_mrp_bom sf_base.group_purchase_director 1 0 0 0
38 access_mrp_bom_group_quality mrp_bom_group_quality mrp.model_mrp_bom sf_base.group_quality 1 0 0 0
39 access_mrp_bom_group_quality_director mrp_bom_group_quality_director mrp.model_mrp_bom sf_base.group_quality_director 1 0 0 0

View File

@@ -8,28 +8,15 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="partner_id" position="replace"> <field name="partner_id" position="replace">
<field name="partner_id" widget="res_partner_many2one" context="{'is_supplier': True }"/> <field name="partner_id" widget="res_partner_many2one" context="{'is_supplier': True }"/>
<field name="check_status" invisible="1"/>
</field> </field>
<field name="currency_id" position="after"> <field name="currency_id" position="after">
<field name="remark" attrs="{'readonly': ['&amp;',('state', 'in', ['purchase']),('check_status','in', <field name="remark" attrs="{'readonly': [('state', 'in', ['purchase'])]}"/>
['pending','approved'])]}"/>
</field> </field>
<xpath expr="//form/header/button[@name='action_rfq_send'][1]" position="after">
<button name="sf_sale.action_purchase_order_check_wizard" string="审核" type="action"
context="{'default_order_id':active_id}" groups="sf_base.group_purchase_director"
attrs="{'invisible': ['&amp;',('check_status','in', ['approved','fail']),('state', 'in', ['purchase','draft'])]}"
class="oe_highlight"/>
</xpath>
<xpath expr="//form/header/button[@name='button_confirm'][2]" position="replace"> <xpath expr="//form/header/button[@name='button_confirm'][2]" position="replace">
<button name="button_confirm" type="object" context="{'validate_analytic': True}" <button name="button_confirm" type="object" context="{'validate_analytic': True}"
string="确认订单" id="draft_confirm" string="确认订单" id="draft_confirm"
groups="sf_base.group_purchase,sf_base.group_purchase_director" groups="sf_base.group_purchase,sf_base.group_purchase_director"
attrs="{'invisible': ['|','&amp;','&amp;', ('state', 'in', ['purchase','draft']), ('check_status', 'in', ['approved']), ('date_approve', '!=', False),'&amp;', '&amp;',('state', 'in', ['purchase', 'draft']),('check_status', 'in', [False, 'pending', 'fail']),('date_approve', '=', False)]}" attrs="{'invisible': [('state', 'in', ['purchase'])]}"
/>
<button name="button_confirming" type="object"
string="确认订单" groups="sf_base.group_purchase,sf_base.group_purchase_director"
attrs="{'invisible': ['&amp;',('check_status','!=', False),('state', 'not in', ['draft','send'])]}"
/> />
</xpath> </xpath>
<xpath expr="//form/header/button[@name='action_rfq_send'][1]" position="replace"> <xpath expr="//form/header/button[@name='action_rfq_send'][1]" position="replace">
@@ -93,43 +80,35 @@
<attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute> <attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute>
</xpath> </xpath>
<xpath expr="//field[@name='order_line']" position="attributes"> <xpath expr="//field[@name='order_line']" position="attributes">
<attribute name="attrs">{'readonly': ['&amp;',('state', 'in', ['purchase']),('check_status','in', <attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
['approved'])]}
</attribute> </attribute>
</xpath> </xpath>
<field name="partner_ref" position="attributes"> <field name="partner_ref" position="attributes">
<attribute name="attrs">{'readonly': ['&amp;',('state', 'in', ['purchase']),('check_status','in', <attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
['pending','approved'])]}
</attribute> </attribute>
</field> </field>
<field name="date_planned" position="attributes"> <field name="date_planned" position="attributes">
<attribute name="attrs">{'readonly': ['&amp;',('state', 'in', ['purchase']),('check_status','in', <attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
['pending','approved'])]}
</attribute> </attribute>
</field> </field>
<field name="receipt_reminder_email" position="attributes"> <field name="receipt_reminder_email" position="attributes">
<attribute name="attrs">{'readonly': ['&amp;',('state', 'in', ['purchase']),('check_status','in', <attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
['pending','approved'])]}
</attribute> </attribute>
</field> </field>
<field name="user_id" position="attributes"> <field name="user_id" position="attributes">
<attribute name="attrs">{'readonly': ['&amp;',('state', 'in', ['purchase']),('check_status','in', <attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
['pending','approved'])]}
</attribute> </attribute>
</field> </field>
<field name="origin" position="attributes"> <field name="origin" position="attributes">
<attribute name="attrs">{'readonly': ['&amp;',('state', 'in', ['purchase']),('check_status','in', <attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
['pending','approved'])]}
</attribute> </attribute>
</field> </field>
<field name="payment_term_id" position="attributes"> <field name="payment_term_id" position="attributes">
<attribute name="attrs">{'readonly': ['&amp;',('state', 'in', ['purchase']),('check_status','in', <attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
['pending','approved'])]}
</attribute> </attribute>
</field> </field>
<field name="fiscal_position_id" position="attributes"> <field name="fiscal_position_id" position="attributes">
<attribute name="attrs">{'readonly': ['&amp;',('state', 'in', ['purchase']),('check_status','in', <attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
['pending','approved'])]}
</attribute> </attribute>
</field> </field>
</field> </field>
@@ -153,13 +132,10 @@
<field name="inherit_id" ref="purchase_stock.purchase_order_view_form_inherit"/> <field name="inherit_id" ref="purchase_stock.purchase_order_view_form_inherit"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="incoterm_id" position="attributes"> <field name="incoterm_id" position="attributes">
<attribute name="attrs">{'readonly': ['&amp;',('state', 'in', ['purchase']),('check_status','in', <attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}</attribute>
['pending','approved'])]}
</attribute>
</field> </field>
<field name="incoterm_location" position="attributes"> <field name="incoterm_location" position="attributes">
<attribute name="attrs">{'readonly': ['&amp;',('state', 'in', ['purchase']),('check_status','in', <attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
['pending','approved'])]}
</attribute> </attribute>
</field> </field>
</field> </field>
@@ -171,14 +147,8 @@
<field name="inherit_id" ref="purchase.purchase_order_view_tree"/> <field name="inherit_id" ref="purchase.purchase_order_view_tree"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree position="attributes"> <tree position="attributes">
<attribute name="default_order">check_status desc,date_approve asc</attribute> <attribute name="default_order">date_approve asc</attribute>
</tree> </tree>
<field name="amount_total" position="after">
<field name="check_status" widget="badge"
decoration-success="check_status == 'approved'"
decoration-warning="check_status == 'pending'"
decoration-danger="check_status == 'fail'"/>
</field>
</field> </field>
</record> </record>

View File

@@ -26,6 +26,7 @@
<field name="quantity"/> <field name="quantity"/>
<field name="unit_price"/> <field name="unit_price"/>
<field name="price"/> <field name="price"/>
<field name="sale_order_id"/>
<field name="create_uid" string="创建人"/> <field name="create_uid" string="创建人"/>
<field name="create_date" string="创建时间"/> <field name="create_date" string="创建时间"/>
<field optional="hide" name="delivery_time"/> <field optional="hide" name="delivery_time"/>
@@ -78,6 +79,8 @@
<field name="quantity" options="{'format': false}"/> <field name="quantity" options="{'format': false}"/>
<field name="unit_price"/> <field name="unit_price"/>
<field name="price" options="{'format': false}"/> <field name="price" options="{'format': false}"/>
<field name="sale_order_id"
attrs='{"invisible": [("sale_order_id","=",False)],"readonly": [("sale_order_id","!=",False)]}'/>
</group> </group>
</group> </group>
</sheet> </sheet>

View File

@@ -19,9 +19,9 @@
'views/functional_tool_views.xml', 'views/functional_tool_views.xml',
'views/mrp_workcenter_views.xml', 'views/mrp_workcenter_views.xml',
'views/sf_maintenance_equipment.xml', 'views/sf_maintenance_equipment.xml',
'views/menu_view.xml',
'views/tool_material_search.xml', 'views/tool_material_search.xml',
'views/fixture_material_search_views.xml', 'views/fixture_material_search_views.xml',
'views/menu_view.xml',
'data/tool_data.xml', 'data/tool_data.xml',
], ],
'demo': [ 'demo': [

View File

@@ -345,7 +345,7 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
# 创建装刀请求 # 创建装刀请求
knife_plan.apply_for_tooling() knife_plan.apply_for_tooling()
else: else:
logging.info('功能刀具【%s】满足CNC用刀需求') logging.info('功能刀具【%s】满足CNC用刀需求' % cnc_processing.cutting_tool_name)
class FunctionalToolAssembly(models.Model): class FunctionalToolAssembly(models.Model):
@@ -769,6 +769,15 @@ class FunctionalToolDismantle(models.Model):
chuck_freight_id = fields.Many2one('sf.shelf.location', '夹头目标货位', chuck_freight_id = fields.Many2one('sf.shelf.location', '夹头目标货位',
domain="[('product_id', 'in', (chuck_product_id, False))]") domain="[('product_id', 'in', (chuck_product_id, False))]")
@api.onchange('functional_tool_id')
def _onchange_freight(self):
for item in self:
item.integral_freight_id = False
item.blade_freight_id = False
item.bar_freight_id = False
item.pad_freight_id = False
item.chuck_freight_id = False
@api.depends('functional_tool_id') @api.depends('functional_tool_id')
def _compute_functional_tool_num(self): def _compute_functional_tool_num(self):
for item in self: for item in self:
@@ -807,10 +816,12 @@ class FunctionalToolDismantle(models.Model):
raise ValidationError('Rfid为【%s】的功能刀具已经拆解,请勿重复操作!' % self.functional_tool_id.rfid_dismantle) raise ValidationError('Rfid为【%s】的功能刀具已经拆解,请勿重复操作!' % self.functional_tool_id.rfid_dismantle)
location = self.env['stock.location'].search([('name', '=', '刀具组装位置')]) location = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
location_dest = self.env['stock.location'].search([('name', '=', '刀具房')]) location_dest = self.env['stock.location'].search([('name', '=', '刀具房')])
# =================刀柄是否报废拆解======= # =================刀柄是否[报废]拆解=======
location_dest_scrap = self.env['stock.location'].search([('name', '=', 'Scrap')]) location_dest_scrap = self.env['stock.location'].search([('name', '=', 'Scrap')])
if self.handle_rfid: if self.handle_rfid:
lot = self.env['stock.lot'].sudo().search([('rfid', '=', self.handle_rfid)]) lot = self.env['stock.lot'].sudo().search([('rfid', '=', self.handle_rfid)])
if not lot:
raise ValidationError('Rfid为【%s】的功能刀具序列号不存在!' % self.handle_rfid)
functional_tool_assembly = self.functional_tool_id.functional_tool_name_id functional_tool_assembly = self.functional_tool_id.functional_tool_name_id
if self.scrap_boolean: if self.scrap_boolean:
# 刀柄报废 入库到Scrap # 刀柄报废 入库到Scrap
@@ -820,34 +831,34 @@ class FunctionalToolDismantle(models.Model):
# 刀柄不报废 入库到刀具房 # 刀柄不报废 入库到刀具房
lot.create_stock_quant(location, location_dest, functional_tool_assembly.id, '功能刀具拆解', lot.create_stock_quant(location, location_dest, functional_tool_assembly.id, '功能刀具拆解',
functional_tool_assembly, functional_tool_assembly.tool_groups_id) functional_tool_assembly, functional_tool_assembly.tool_groups_id)
# ==============功能刀具报废拆解================ # ==============功能刀具[报废]拆解================
if self.dismantle_cause in ['寿命到期报废', '崩刀报废']: if self.dismantle_cause in ['寿命到期报废', '崩刀报废']:
# 除刀柄外物料报废 入库到Scrap # 除刀柄外物料报废 入库到Scrap
if self.integral_freight_id: if self.integral_product_id:
self.integral_product_id.dismantle_stock_moves(False, location, location_dest_scrap) self.integral_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
elif self.blade_freight_id: elif self.blade_product_id:
self.blade_product_id.dismantle_stock_moves(False, location, location_dest_scrap) self.blade_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
if self.bar_freight_id: if self.bar_product_id:
self.bar_product_id.dismantle_stock_moves(False, location, location_dest_scrap) self.bar_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
elif self.pad_freight_id: elif self.pad_product_id:
self.pad_product_id.dismantle_stock_moves(False, location, location_dest_scrap) self.pad_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
if self.chuck_freight_id: if self.chuck_product_id:
self.chuck_product_id.dismantle_stock_moves(False, location, location_dest_scrap) self.chuck_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
# ===========功能刀具磨削拆解============== # ===========功能刀具[磨削]拆解==============
elif self.dismantle_cause in ['刀具需磨削']: elif self.dismantle_cause in ['刀具需磨削']:
location_dest = self.env['stock.location'].search([('name', '=', '磨削房')]) location_dest = self.env['stock.location'].search([('name', '=', '磨削房')])
# 除刀柄外物料拆解 入库到具体库位 # 除刀柄外物料拆解 入库到具体库位
if self.integral_freight_id: if self.integral_product_id:
self.integral_product_id.dismantle_stock_moves(False, location, location_dest) self.integral_product_id.dismantle_stock_moves(False, location, location_dest)
elif self.blade_freight_id: elif self.blade_product_id:
self.blade_product_id.dismantle_stock_moves(False, location, location_dest) self.blade_product_id.dismantle_stock_moves(False, location, location_dest)
if self.bar_freight_id: if self.bar_product_id:
self.bar_product_id.dismantle_stock_moves(False, location, location_dest) self.bar_product_id.dismantle_stock_moves(False, location, location_dest)
elif self.pad_freight_id: elif self.pad_product_id:
self.pad_product_id.dismantle_stock_moves(False, location, location_dest) self.pad_product_id.dismantle_stock_moves(False, location, location_dest)
if self.chuck_freight_id: if self.chuck_product_id:
self.chuck_product_id.dismantle_stock_moves(False, location, location_dest) self.chuck_product_id.dismantle_stock_moves(False, location, location_dest)
# ==============功能刀具更换拆解============== # ==============功能刀具[更换]拆解==============
elif self.dismantle_cause in ['更换为其他刀具']: elif self.dismantle_cause in ['更换为其他刀具']:
# 除刀柄外物料拆解 入库到具体库位 # 除刀柄外物料拆解 入库到具体库位
if self.integral_freight_id: if self.integral_freight_id:
@@ -875,7 +886,7 @@ class FunctionalToolDismantle(models.Model):
'rfid': '', 'rfid': '',
'state': '已拆解' 'state': '已拆解'
}) })
logging.info('刀具拆解成功!') logging.info('%s刀具拆解成功!' % self.name)
class ProductProduct(models.Model): class ProductProduct(models.Model):
@@ -895,12 +906,12 @@ class ProductProduct(models.Model):
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', shelf_location_barcode)]) location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', shelf_location_barcode)])
location.product_num = location.product_num + 1 location.product_num = location.product_num + 1
else: else:
location = False location = self.env['sf.shelf.location']
# 创建移动历史记录 # 创建移动历史记录
stock_move_line_id = self.env['stock.move.line'].sudo().create({ stock_move_line_id = self.env['stock.move.line'].sudo().create({
'product_id': self.id, 'product_id': self.id,
'move_id': stock_move_id.id, 'move_id': stock_move_id.id,
'current_location_id': location.id or False, 'current_location_id': location.id,
'install_tool_time': fields.Datetime.now(), 'install_tool_time': fields.Datetime.now(),
'qty_done': 1.0, 'qty_done': 1.0,
'state': 'done', 'state': 'done',

View File

@@ -61,6 +61,7 @@
<field name="barcode_ids"> <field name="barcode_ids">
<tree create="0"> <tree create="0">
<field name="name"/> <field name="name"/>
<field name="rfid"/>
<field name="tool_material_status"/> <field name="tool_material_status"/>
<!-- <button string="序列号注册" name="enroll_fixture_material_stock" type="object"--> <!-- <button string="序列号注册" name="enroll_fixture_material_stock" type="object"-->
<!-- class="btn-primary"/>--> <!-- class="btn-primary"/>-->
@@ -94,12 +95,4 @@
<field name="res_model">sf.fixture.material.search</field> <field name="res_model">sf.fixture.material.search</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
</record> </record>
<menuitem
sequence="25"
name="夹具物料查询"
id="menu_sf_fixture_material_search"
action="action_sf_fixture_material_search"
parent="menu_sf_fixture"
/>
</odoo> </odoo>

View File

@@ -120,5 +120,13 @@
parent="menu_sf_tool_material" parent="menu_sf_tool_material"
/> />
<menuitem
sequence="25"
name="夹具物料查询"
id="menu_sf_fixture_material_search"
action="action_sf_fixture_material_search"
parent="menu_sf_fixture"
/>
</data> </data>
</odoo> </odoo>

View File

@@ -846,7 +846,8 @@
attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])], 'readonly': [('state', '=', '已拆解')]}"/> attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])], 'readonly': [('state', '=', '已拆解')]}"/>
</group> </group>
</group> </group>
<group string="夹头" attrs="{'invisible': [('chuck_product_id', '=', False)]}"> <group string="夹头"
attrs="{'invisible': [('chuck_product_id', '=', False)]}">
<group> <group>
<field name="chuck_product_id" string="名称"/> <field name="chuck_product_id" string="名称"/>
<field name="chuck_type_id" string="型号"/> <field name="chuck_type_id" string="型号"/>
@@ -855,7 +856,8 @@
<group> <group>
<field name="chuck_freight_id" string="目标货位" <field name="chuck_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}" options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')]}"/> attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')],
'required': [('chuck_product_id', '!=', False),('dismantle_cause', 'in', ['更换为其他刀具'])]}"/>
</group> </group>
</group> </group>
</group> </group>
@@ -869,7 +871,8 @@
<group> <group>
<field name="integral_freight_id" string="目标货位" <field name="integral_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}" options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')]}"/> attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')],
'required': [('integral_product_id', '!=', False),('dismantle_cause', 'in', ['更换为其他刀具'])]}"/>
</group> </group>
</group> </group>
@@ -884,7 +887,8 @@
<group> <group>
<field name="blade_freight_id" string="目标货位" <field name="blade_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}" options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')]}"/> attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')],
'required': [('blade_product_id', '!=', False),('dismantle_cause', 'in', ['更换为其他刀具'])]}"/>
</group> </group>
</group> </group>
<group string="刀杆" attrs="{'invisible': [('bar_product_id', '=', False)]}"> <group string="刀杆" attrs="{'invisible': [('bar_product_id', '=', False)]}">
@@ -896,7 +900,8 @@
<group> <group>
<field name="bar_freight_id" string="目标货位" <field name="bar_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}" options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')]}"/> attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')],
'required': [('bar_product_id', '!=', False),('dismantle_cause', 'in', ['更换为其他刀具'])]}"/>
</group> </group>
</group> </group>
<group string="刀盘" attrs="{'invisible': [('pad_product_id', '=', False)]}"> <group string="刀盘" attrs="{'invisible': [('pad_product_id', '=', False)]}">
@@ -908,7 +913,8 @@
<group> <group>
<field name="pad_freight_id" string="目标货位" <field name="pad_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}" options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')]}"/> attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')],
'required': [('pad_product_id', '!=', False), ('dismantle_cause', 'in', ['更换为其他刀具'])]}"/>
</group> </group>
</group> </group>
</group> </group>
@@ -944,7 +950,5 @@
<field name="search_view_id" ref="sf_functional_tool_dismantle_search"/> <field name="search_view_id" ref="sf_functional_tool_dismantle_search"/>
<field name="context">{'search_default_no_dismantle_state':1}</field> <field name="context">{'search_default_no_dismantle_state':1}</field>
</record> </record>
</data> </data>
</odoo> </odoo>

View File

@@ -61,6 +61,7 @@
<field name="barcode_ids"> <field name="barcode_ids">
<tree> <tree>
<field name="name"/> <field name="name"/>
<field name="rfid"/>
<field name="tool_material_status"/> <field name="tool_material_status"/>
<!-- <button name="enroll_tool_material_stock" string="序列号注册" type="object" class="btn-primary"/>--> <!-- <button name="enroll_tool_material_stock" string="序列号注册" type="object" class="btn-primary"/>-->
</tree> </tree>

View File

@@ -246,9 +246,20 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
if self.integral_freight_barcode: if self.integral_freight_barcode:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.integral_freight_barcode)]) location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.integral_freight_barcode)])
if location: if location:
self.integral_product_id = location.product_id.id if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else:
material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '整体式刀具':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.integral_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是整体式刀具,请重新选择!' % (
location.barcode, location.product_id.name))
else: else:
self.integral_product_id = False raise ValidationError('编码为【%s】的货位不存在!' % self.integral_freight_barcode)
# ===============刀片型号==================== # ===============刀片型号====================
blade_freight_barcode = fields.Char('刀片货位') blade_freight_barcode = fields.Char('刀片货位')
@@ -265,9 +276,20 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
if self.blade_freight_barcode: if self.blade_freight_barcode:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.blade_freight_barcode)]) location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.blade_freight_barcode)])
if location: if location:
self.blade_product_id = location.product_id.id if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else:
material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '刀片':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.blade_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是刀片,请重新选择!' % (
location.barcode, location.product_id.name))
else: else:
self.blade_product_id = False raise ValidationError('编码为【%s】的货位不存在!' % self.blade_freight_barcode)
# ====================刀杆型号================== # ====================刀杆型号==================
bar_freight_barcode = fields.Char('刀杆货位') bar_freight_barcode = fields.Char('刀杆货位')
@@ -284,9 +306,20 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
if self.bar_freight_barcode: if self.bar_freight_barcode:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.bar_freight_barcode)]) location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.bar_freight_barcode)])
if location: if location:
self.bar_product_id = location.product_id.id if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else:
material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '刀杆':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.bar_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是刀杆,请重新选择!' % (
location.barcode, location.product_id.name))
else: else:
self.bar_product_id = False raise ValidationError('编码为【%s】的货位不存在!' % self.bar_freight_barcode)
# ===============刀盘型号=================== # ===============刀盘型号===================
pad_freight_barcode = fields.Char('刀盘货位') pad_freight_barcode = fields.Char('刀盘货位')
@@ -303,9 +336,20 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
if self.pad_freight_barcode: if self.pad_freight_barcode:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.pad_freight_barcode)]) location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.pad_freight_barcode)])
if location: if location:
self.pad_product_id = location.product_id.id if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else:
material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '刀盘':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.pad_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是刀盘,请重新选择!' % (
location.barcode, location.product_id.name))
else: else:
self.pad_product_id = False raise ValidationError('编码为【%s】的货位不存在!' % self.pad_freight_barcode)
# ================刀柄型号=============== # ================刀柄型号===============
handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_rfid') handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_rfid')
@@ -342,12 +386,22 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
if self.chuck_freight_barcode: if self.chuck_freight_barcode:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.chuck_freight_barcode)]) location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.chuck_freight_barcode)])
if location: if location:
self.chuck_product_id = location.product_id.id if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else:
material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '夹头':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.chuck_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是夹头,请重新选择!' % (
location.barcode, location.product_id.name))
else: else:
self.chuck_product_id = False raise ValidationError('编码为【%s】的货位不存在!' % self.chuck_freight_barcode)
# ======================================== # ========================================
def on_barcode_scanned(self, barcode): def on_barcode_scanned(self, barcode):
""" """
智能工厂组装单处扫码绑定刀具物料 智能工厂组装单处扫码绑定刀具物料

View File

@@ -838,7 +838,7 @@ class Sf_stock_move_line(models.Model):
if obj: if obj:
obj.product_id = record.product_id.id obj.product_id = record.product_id.id
# obj.location_status = '占用' # obj.location_status = '占用'
obj.product_num += record.reserved_uom_qty obj.product_num += record.qty_done
@api.onchange('destination_location_id') @api.onchange('destination_location_id')
def _check_destination_location_id(self): def _check_destination_location_id(self):

View File

@@ -136,6 +136,8 @@ access_sf_shelf_location_wizard_group_plan_dispatch,sf_shelf_location_wizard_gro
access_sf_shelf_location_wizard_group_sf_stock_user_group_sf_stock_user,sf_shelf_location_wizard_group_sf_stock_user_group_sf_stock_user,model_sf_shelf_location_wizard,sf_warehouse.group_sf_stock_user,1,0,0,0 access_sf_shelf_location_wizard_group_sf_stock_user_group_sf_stock_user,sf_shelf_location_wizard_group_sf_stock_user_group_sf_stock_user,model_sf_shelf_location_wizard,sf_warehouse.group_sf_stock_user,1,0,0,0
access_sf_shelf_location_wizard_group_sf_stock_manager,sf_shelf_location_wizard_group_sf_stock_manager,model_sf_shelf_location_wizard,sf_warehouse.group_sf_stock_manager,1,1,1,0 access_sf_shelf_location_wizard_group_sf_stock_manager,sf_shelf_location_wizard_group_sf_stock_manager,model_sf_shelf_location_wizard,sf_warehouse.group_sf_stock_manager,1,1,1,0
access_sf_shelf_location_group_sf_tool_user,sf.shelf.location.group_sf_tool_user,model_sf_shelf_location,sf_base.group_sf_tool_user,1,1,0,0
access_sf_shelf_group_user,sf.shelf.location.group_user,model_sf_shelf_location,base.group_user,1,1,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
136
137
138
139
140
141
142
143

View File

@@ -246,6 +246,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="货位"> <search string="货位">
<field name="barcode"/> <field name="barcode"/>
<field name="product_id"/>
<searchpanel class="account_root"> <searchpanel class="account_root">
<!-- <field name="location_type" icon="fa-filter"/> --> <!-- <field name="location_type" icon="fa-filter"/> -->
<!-- <field name="location_id" select="multi" icon="fa-filter"/> --> <!-- <field name="location_id" select="multi" icon="fa-filter"/> -->