-
+
@@ -178,7 +179,7 @@
-
+
diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py
index 4b15299d..809462a9 100644
--- a/sf_manufacturing/models/mrp_production.py
+++ b/sf_manufacturing/models/mrp_production.py
@@ -1,6 +1,11 @@
# -*- coding: utf-8 -*-
+import base64
+import logging
import re
+import requests
from odoo import api, fields, models, _
+from odoo.exceptions import UserError
+from odoo.addons.sf_base.commons.common import Common
class MrpProduction(models.Model):
@@ -17,6 +22,10 @@ class MrpProduction(models.Model):
check_status = fields.Boolean(string='启用状态', default=False, readonly=True)
active = fields.Boolean(string='已归档', default=True)
+ programming_no = fields.Char('编程单号')
+ work_state = fields.Char('业务状态')
+ programming_state = fields.Char('编程状态')
+ glb_file = fields.Binary("glb模型文件")
def action_check(self):
"""
@@ -47,6 +56,48 @@ class MrpProduction(models.Model):
for production in self:
production.maintenance_count = len(production.request_ids)
+ # cnc程序获取
+ def fetchCNC(self):
+ cnc = self.env['mrp.production'].search([('id', '=', self.id)])
+ try:
+ res = {'model_code': '' if not cnc.product_id.model_code else cnc.product_id.model_code,
+ 'production_no': cnc.name,
+ 'machine_tool_code': "",
+ 'material_code': self.env['sf.production.materials'].search(
+ [('id', '=', cnc.product_id.materials_id.id)]).materials_no,
+ 'material_type_code': self.env['sf.materials.model'].search(
+ [('id', '=', cnc.product_id.materials_type_id.id)]).materials_no,
+ 'machining_processing_panel': cnc.product_id.model_processing_panel,
+ 'machining_precision': cnc.product_id.model_machining_precision,
+ 'embryo_long': cnc.product_id.bom_ids.bom_line_ids.product_id.length,
+ 'embryo_height': cnc.product_id.bom_ids.bom_line_ids.product_id.height,
+ 'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width,
+ 'order_no': cnc.origin,
+ 'model_order_no': cnc.product_id.default_code.rsplit(' -', 1)[0],
+ 'user': cnc.env.user.name,
+ 'model_file': '' if not cnc.product_id.model_file else base64.b64encode(
+ cnc.product_id.model_file).decode('utf-8')
+ }
+ logging.info('res:%s' % res)
+ configsettings = self.env['res.config.settings'].get_values()
+ config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
+ url = '/api/intelligent_programming/create'
+ config_url = configsettings['sf_url'] + url
+ res['token'] = configsettings['token']
+ # res_str = json.dumps(res)
+ ret = requests.post(config_url, json={}, data=res, headers=config_header)
+ ret = ret.json()
+ logging.info('fetchCNC-ret:%s' % ret)
+ if ret['status'] == 1:
+ self.write(
+ {'programming_no': ret['programming_no'], 'programming_state': '编程中', 'work_state': '编程中'})
+ else:
+ raise UserError(ret['message'])
+ except Exception as e:
+ logging.info('fetchCNC error:%s' % e)
+ raise UserError("cnc程序获取编程单失败,请联系管理员")
+
+
# 维修模块按钮
def button_maintenance_req(self):
self.ensure_one()
@@ -134,6 +185,7 @@ class MrpProduction(models.Model):
'state': 'pending',
}]
if production.product_id.categ_id.type == '成品':
+ production.fetchCNC()
# 根据加工面板的面数及对应的工序模板生成工单
i = 0
processing_panel_len = len(production.product_id.model_processing_panel.split(','))
@@ -366,7 +418,8 @@ class MrpProduction(models.Model):
current_sequence += 1
if work.name == '获取CNC加工程序':
work.button_start()
- work.fetchCNC()
+ #work.fetchCNC()
+ work.button_finish()
# 创建工单并进行排序
def _create_workorder(self):
diff --git a/sf_manufacturing/models/mrp_workcenter.py b/sf_manufacturing/models/mrp_workcenter.py
index ca30d259..7d70ae5e 100644
--- a/sf_manufacturing/models/mrp_workcenter.py
+++ b/sf_manufacturing/models/mrp_workcenter.py
@@ -22,7 +22,7 @@ class ResWorkcenter(models.Model):
equipment_status = fields.Selection(
- [("正常", "正常"), ("故障", "故障"), ("不可用", "不可用")],
+ [("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"),("空闲", "空闲"),("封存(报废)", "封存(报废)")],
string="设备状态", related='equipment_id.state')
# @api.depends('equipment_id')
diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py
index 1edbb62f..53307af7 100644
--- a/sf_manufacturing/models/mrp_workorder.py
+++ b/sf_manufacturing/models/mrp_workorder.py
@@ -137,7 +137,10 @@ class ResMrpWorkOrder(models.Model):
"""
检测is_ok(是否合格)被修改的话,就将当前用户赋值给inspection_user_id
"""
- self.inspection_user_id = self.env.user.id
+ if not self.inspection_user_id:
+ self.inspection_user_id = self.env.user.id
+ else:
+ self.inspection_user_id = False
@api.onchange('functional_fixture_id')
def _onchange_functional_fixture_id(self):
@@ -447,7 +450,7 @@ class ResMrpWorkOrder(models.Model):
'embryo_height': cnc.product_id.bom_ids.bom_line_ids.product_id.height,
'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width,
'order_no': cnc.production_id.origin,
- 'model_order_no': cnc.product_id.default_code.rsplit('-', 1)[0],
+ 'model_order_no': cnc.product_id.default_code.rsplit(' -', 1)[0],
'user': self.env.user.name,
'model_file': '' if not cnc.product_id.model_file else base64.b64encode(
cnc.product_id.model_file).decode('utf-8')
@@ -571,6 +574,18 @@ class ResMrpWorkOrder(models.Model):
'order_line': order_line_ids,
})
super().button_finish()
+ is_production_id = True
+ for workorder in self.production_id.workorder_ids:
+ if workorder.state != 'done':
+ is_production_id = False
+ if is_production_id == True and self.name == '解除装夹':
+ for move_raw_id in self.production_id.move_raw_ids:
+ move_raw_id.quantity_done = move_raw_id.product_uom_qty
+ self.production_id.state = 'done'
+
+
+
+
class CNCprocessing(models.Model):
@@ -592,6 +607,7 @@ class CNCprocessing(models.Model):
estimated_processing_time = fields.Char('预计加工时间')
remark = fields.Text('备注')
workorder_id = fields.Many2one('mrp.workorder', string="工单")
+ workorder_id = fields.Many2one('mrp.production', string="制造定单")
button_state = fields.Boolean(string='是否已经下发')
# mrs下发编程单创建CNC加工
@@ -617,11 +633,11 @@ class CNCprocessing(models.Model):
'remark': obj['remark']
})
self.get_cnc_processing_file(ret['folder_name'], cnc_processing, workorder.processing_panel)
- cnc_workorder.state = 'done'
+ # cnc_workorder.state = 'done'
cnc_workorder.work_state = '已编程'
cnc_workorder.programming_state = '已编程'
- cnc_workorder.time_ids.date_end = datetime.now()
- cnc_workorder.button_finish()
+ # cnc_workorder.time_ids.date_end = datetime.now()
+ # cnc_workorder.button_finish()
# 根据程序名和加工面匹配到ftp里对应的Nc程序名
def get_cnc_processing_file(self, folder_name, cnc_processing, processing_panel):
diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py
index 13383a10..115fdc86 100644
--- a/sf_manufacturing/models/product_template.py
+++ b/sf_manufacturing/models/product_template.py
@@ -486,28 +486,6 @@ class ResProductMo(models.Model):
string='适用刀柄型号'
)
- # 夹具参数
- fixture_material_id = fields.Many2one('sf.fixture.material', string="夹具物料")
- fixture_model_id = fields.Many2one('sf.fixture.model', string="夹具型号")
- fixture_material_type = fields.Char(string="夹具物料类型", related='fixture_material_id.name')
- fixture_multi_mounting_type_id = fields.Many2one('sf.multi_mounting.type', string="联装类型")
- fixture_clamping_way = fields.Char(string="装夹方式")
- fixture_port_type = fields.Char(string="接口类型")
- fixture_model_file = fields.Binary(string="3D模型图")
-
- fixture_clamp_workpiece_length_max = fields.Integer(string="夹持工件长度max(mm)")
- fixture_clamp_workpiece_width_max = fields.Integer(string="夹持工件宽度max(mm)")
- fixture_clamp_workpiece_height_max = fields.Integer(string="夹持工件高度max(mm)")
- fixture_clamp_workpiece_diameter_max = fields.Float(string="夹持工件直径max(mm)", digits=(16, 6))
-
- fixture_maximum_carrying_weight = fields.Float(string="最大承载重量(kg)", digits=(16, 4))
- fixture_maximum_clamping_force = fields.Integer(string="最大夹持力(n)")
- fixture_driving_way = fields.Char(string="驱动方式")
- fixture_apply_machine_tool_type_ids = fields.Many2many('sf.machine_tool.type', 'rel_product_machine_tool_type',
- string="适用机床型号")
- fixture_through_hole_size = fields.Integer(string="过孔大小(mm)")
- fixture_screw_size = fields.Integer(string="螺牙大小(mm)")
-
# 注册状态
register_state = fields.Selection([('未注册', '未注册'), ('已注册', '已注册'), ('注册失败', '注册失败')],
string='注册状态', default='未注册')
@@ -826,6 +804,124 @@ class ResProductMo(models.Model):
return base64_data
+class ResProductFixture(models.Model):
+ _inherit = 'product.template'
+ _description = '夹具产品信息'
+
+ fixture_model_id = fields.Many2one('sf.fixture.model', '夹具型号')
+ specification_fixture_id = fields.Many2one('sf.fixture.materials.basic.parameters', '夹具规格')
+
+ fixture_material_id = fields.Many2one('sf.fixture.material', string="夹具物料", required=True)
+ fixture_material_type = fields.Char(string="夹具物料类型", related='fixture_material_id.name')
+ multi_mounting_type_id = fields.Many2one('sf.multi_mounting.type', string="联装类型", required=True)
+ model_file = fields.Binary(string="3D模型图")
+
+ # 夹具物料基本参数
+ # length = fields.Float('长度(mm)', digits=(16, 2))
+ # width = fields.Float('宽度(mm)', digits=(16, 2))
+ # height = fields.Float('高度(mm)', digits=(16, 2))
+ diameter = fields.Float('直径(mm)', digits=(16, 2))
+
+ # '零点卡盘' 字段
+ weight = fields.Float('重量(mm)', digits=(16, 2))
+ orientation_dish_diameter = fields.Float('定位盘直径(mm)', digits=(16, 2))
+ clamping_diameter = fields.Float('装夹直径(mm)', digits=(16, 2))
+ clamping_num = fields.Selection([('1', '1'), ('2', '2'), ('4', '4'), ('6', '6'), ('8', '8')], string='装夹单元数')
+ chucking_power_max = fields.Float('最大夹持力(KN)', digits=(16, 2))
+ repeated_positioning_accuracy = fields.Char('重复定位精度(mm)', size=20)
+ boolean_transposing_hole = fields.Boolean('是否有转位孔')
+ unlocking_method = fields.Selection(
+ [('手动', '手动'), ('气动', '气动'), ('液压', '液压'), ('电动', '电动'), ('其他', '其他')], string='解锁方式')
+ boolean_chip_blowing_function = fields.Boolean('是否有吹屑功能')
+ carrying_capacity_max = fields.Float('最大承载重量(kg)', digits=(16, 2))
+ rigidity = fields.Integer('硬度HRC')
+ materials_model_id = fields.Many2one('sf.materials.model', '夹具材质')
+ machine_tool_type_id = fields.Many2one('sf.machine_tool.type', '适用机床型号')
+
+ # ’零点托盘‘ 字段
+ connector_diameter = fields.Selection([('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('8', '8')],
+ string='连接头直径(mm)')
+ way_to_install = fields.Selection(
+ [('接口式', '接口式'), ('螺栓固定', '螺栓固定'), ('磁吸式', '磁吸式'), ('其他', '其他')], string='安装方式')
+ type_of_drive = fields.Selection(
+ [('气动式', '气动式'), ('液压式', '液压式'), ('机械式', '机械式'), ('电动式', '电动式'), ('其他', '其他')],
+ string='驱动方式')
+
+ # ’气动夹具‘ 字段
+ gripper_length_min = fields.Float('夹持工件最小长度(mm)', digits=(16, 2))
+ gripper_width_min = fields.Float('夹持工件最小宽度(mm)', digits=(16, 2))
+ gripper_height_min = fields.Float('夹持工件最小高度(mm)', digits=(16, 2))
+ gripper_diameter_min = fields.Float('夹持工件最小直径(mm)', digits=(16, 2))
+ gripper_length_max = fields.Float('夹持工件最大长度(mm)', digits=(16, 2))
+ gripper_width_max = fields.Float('夹持工件最大宽度(mm)', digits=(16, 2))
+ gripper_height_max = fields.Float('夹持工件最大高度(mm)', digits=(16, 2))
+ gripper_diameter_max = fields.Float('夹持工件最大直径(mm)', digits=(16, 2))
+ rated_air_pressure = fields.Float('额定气压(Mpa)', digits=(16, 2))
+ interface_materials_model_id = fields.Many2one('sf.materials.model', '接口类型')
+
+ # ‘虎钳夹具' 字段
+ transverse_groove = fields.Float('横向配合槽n(mm)', digits=(16, 2))
+ longitudinal_fitting_groove = fields.Float('纵向配合槽l(mm)', digits=(16, 2))
+
+ # '磁吸夹具' 字段
+ height_tolerance_value = fields.Char('高度公差(mm)')
+ rated_adsorption_force = fields.Float('额定吸附力(N/cm²)', digits=(16, 2))
+ magnetic_field_height = fields.Float('磁场高度(mm)', digits=(16, 2))
+ magnetic_pole_plate_grinding_allowance = fields.Float('磁极板磨削余量(mm)', digits=(16, 2))
+
+ # '转接板(锁板)夹具' 字段
+ screw_size = fields.Float('螺牙大小(mm)', digits=(16, 2))
+ via_hole_diameter = fields.Float('过孔直径(mm)', digits=(16, 2))
+
+ # '三爪卡盘' 字段
+ mounting_hole_depth = fields.Float('安装孔深度(mm)', digits=(16, 2))
+ centering_diameter = fields.Float('定心直径(mm)', digits=(16, 2))
+
+ @api.onchange('specification_fixture_id')
+ def _onchange_specification_fixture_id(self):
+ if self.specification_fixture_id:
+ self.length = self.specification_fixture_id.length
+ self.width = self.specification_fixture_id.width
+ self.height = self.specification_fixture_id.height
+ self.weight = self.specification_fixture_id.weight
+ self.diameter = self.specification_fixture_id.diameter
+ self.orientation_dish_diameter = self.specification_fixture_id.orientation_dish_diameter
+ self.clamping_diameter = self.specification_fixture_id.clamping_diameter
+ self.clamping_num = self.specification_fixture_id.clamping_num
+ self.chucking_power_max = self.specification_fixture_id.chucking_power_max
+ self.repeated_positioning_accuracy = self.specification_fixture_id.repeated_positioning_accuracy
+ self.boolean_transposing_hole = self.specification_fixture_id.boolean_transposing_hole
+ self.unlocking_method = self.specification_fixture_id.unlocking_method
+ self.boolean_chip_blowing_function = self.specification_fixture_id.boolean_chip_blowing_function
+ self.carrying_capacity_max = self.specification_fixture_id.carrying_capacity_max
+ self.rigidity = self.specification_fixture_id.rigidity
+ self.materials_model_id = self.specification_fixture_id.materials_model_id
+ self.machine_tool_type_id = self.specification_fixture_id.machine_tool_type_id
+ self.connector_diameter = self.specification_fixture_id.connector_diameter
+ self.way_to_install = self.specification_fixture_id.way_to_install
+ self.type_of_drive = self.specification_fixture_id.type_of_drive
+ self.gripper_length_min = self.specification_fixture_id.gripper_length_min
+ self.gripper_width_min = self.specification_fixture_id.gripper_width_min
+ self.gripper_height_min = self.specification_fixture_id.gripper_height_min
+ self.gripper_diameter_min = self.specification_fixture_id.gripper_diameter_min
+ self.gripper_length_max = self.specification_fixture_id.gripper_length_max
+ self.gripper_width_max = self.specification_fixture_id.gripper_width_max
+ self.gripper_height_max = self.specification_fixture_id.gripper_height_max
+ self.gripper_diameter_max = self.specification_fixture_id.gripper_diameter_max
+ self.rated_air_pressure = self.specification_fixture_id.rated_air_pressure
+ self.interface_materials_model_id = self.specification_fixture_id.interface_materials_model_id
+ self.transverse_groove = self.specification_fixture_id.transverse_groove
+ self.longitudinal_fitting_groove = self.specification_fixture_id.longitudinal_fitting_groove
+ self.height_tolerance_value = self.specification_fixture_id.height_tolerance_value
+ self.rated_adsorption_force = self.specification_fixture_id.rated_adsorption_force
+ self.magnetic_field_height = self.specification_fixture_id.magnetic_field_height
+ self.magnetic_pole_plate_grinding_allowance = self.specification_fixture_id.magnetic_pole_plate_grinding_allowance
+ self.screw_size = self.specification_fixture_id.screw_size
+ self.via_hole_diameter = self.specification_fixture_id.via_hole_diameter
+ self.mounting_hole_depth = self.specification_fixture_id.mounting_hole_depth
+ self.centering_diameter = self.specification_fixture_id.centering_diameter
+
+
class SfMaintenanceEquipmentAndProductTemplate(models.Model):
_inherit = 'maintenance.equipment'
_description = '设备'
diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py
index 4f2c43f3..27edc40f 100644
--- a/sf_manufacturing/models/stock.py
+++ b/sf_manufacturing/models/stock.py
@@ -202,8 +202,7 @@ class StockRule(models.Model):
sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)])
if sale_order:
sale_order.write({'schedule_status': 'to schedule'})
- self.env['sf.production.plan'].sudo().with_company(company_id). \
- create({
+ self.env['sf.production.plan'].sudo().with_company(company_id).create({
'name': production.name,
'order_deadline': sale_order.deadline_of_delivery,
'production_id': production.id,
diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml
index 3727bb10..bddb5236 100644
--- a/sf_manufacturing/views/mrp_production_addional_change.xml
+++ b/sf_manufacturing/views/mrp_production_addional_change.xml
@@ -66,6 +66,11 @@
+
+
+
+
+
diff --git a/sf_mrs_connect/controllers/controllers.py b/sf_mrs_connect/controllers/controllers.py
index a6a1b25f..bb6fd591 100644
--- a/sf_mrs_connect/controllers/controllers.py
+++ b/sf_mrs_connect/controllers/controllers.py
@@ -23,12 +23,11 @@ class Sf_Mrs_Connect(http.Controller):
ret = json.loads(datas)
ret = json.loads(ret['result'])
# 查询状态为进行中且类型为获取CNC加工程序的工单
- cnc_workorder = request.env['mrp.workorder'].with_user(
- request.env.ref("base.user_admin")).search([('production_id.name', '=', ret['production_order_no']),
- ('routing_type', '=', '获取CNC加工程序'),
- ('state', '=', 'progress')])
- if cnc_workorder:
- cnc_workorder.glb_file = base64.b64encode(ret['glb_file'])
+ cnc_production = request.env['mrp.production'].with_user(
+ request.env.ref("base.user_admin")).search([('name', '=', ret['production_order_no'])])
+ if cnc_production:
+ if ret['glb_file']:
+ cnc_production.glb_file = base64.b64encode(ret['glb_file'])
# 拉取所有加工面的程序文件
# i = 1
for r in ret['processing_panel']:
@@ -37,10 +36,10 @@ class Sf_Mrs_Connect(http.Controller):
ret['folder_name'], r)
if not download_state:
res['status'] = -2
- res['message'] = '制造订单号为%s的CNC程序文件从FTP拉取失败' % (cnc_workorder.production_id.name)
+ res['message'] = '制造订单号为%s的CNC程序文件从FTP拉取失败' % (cnc_production.name)
return json.JSONEncoder().encode(res)
request.env['sf.cnc.processing'].with_user(
- request.env.ref("base.user_admin")).cnc_processing_create(cnc_workorder, ret)
+ request.env.ref("base.user_admin")).cnc_processing_create(cnc_production, ret)
return json.JSONEncoder().encode(res)
else:
res = {'status': 0, 'message': '该制造订单暂未开始'}
diff --git a/sf_mrs_connect/models/sync_common.py b/sf_mrs_connect/models/sync_common.py
index 95856dee..18fb0001 100644
--- a/sf_mrs_connect/models/sync_common.py
+++ b/sf_mrs_connect/models/sync_common.py
@@ -1466,6 +1466,39 @@ class SyncFixtureModel(models.Model):
for item in result['fixture_model_yesterday_list']:
if item:
fixture_model = self.search([("code", '=', item['code'])])
+ zero_chuck_list = []
+ for zero_chuck_id in item['zero_chuck_ids']:
+ zero_chuck_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_zero_chuck_param(zero_chuck_id))
+ zero_tray_list = []
+ for zero_tray_id in item['zero_tray_ids']:
+ zero_tray_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_zero_tray_param(zero_tray_id))
+ pneumatic_fixture_list = []
+ for pneumatic_fixture_id in item['pneumatic_fixture_ids']:
+ pneumatic_fixture_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_pneumatic_fixture_param(
+ pneumatic_fixture_id))
+ jaw_vice_fixture_list = []
+ for jaw_vice_fixture_id in item['jaw_vice_fixture_ids']:
+ jaw_vice_fixture_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_jaw_vice_fixture_param(
+ jaw_vice_fixture_id))
+ magnet_fixture_list = []
+ for magnet_fixture_id in item['magnet_fixture_ids']:
+ magnet_fixture_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_magnet_fixture_param(
+ magnet_fixture_id))
+ adapter_board_fixture_list = []
+ for adapter_board_fixture_id in item['adapter_board_fixture_ids']:
+ adapter_board_fixture_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_adapter_board_fixture_param(
+ adapter_board_fixture_id))
+ scroll_chuck_list = []
+ for scroll_chuck_id in item['scroll_chuck_ids']:
+ scroll_chuck_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_scroll_chuck_param(
+ scroll_chuck_id))
if not fixture_model:
self.create({
"name": item['name'],
@@ -1475,56 +1508,35 @@ class SyncFixtureModel(models.Model):
"multi_mounting_type_id": self.env['sf.multi_mounting.type'].search(
[('code', '=', item['multi_mounting_type_code'])]).id,
"brand_id": self.env['sf.machine.brand'].search([('code', '=', item['brand_code'])]).id,
- "clamping_way": item['clamping_way'],
- "port_type": item['port_type'],
"model_file": '' if not item['model_file'] else base64.b64decode(item['model_file']),
- "length": item['length'],
- "width": item['width'],
- "height": item['height'],
- "weight": item['weight'],
- "clamp_workpiece_length_max": item['clamp_workpiece_length_max'],
- "clamp_workpiece_width_max": item['clamp_workpiece_width_max'],
- "clamp_workpiece_height_max": item['clamp_workpiece_height_max'],
- "clamp_workpiece_diameter_max": item['clamp_workpiece_diameter_max'],
- "maximum_carrying_weight": item['maximum_carrying_weight'],
- "maximum_clamping_force": item['maximum_clamping_force'],
- "materials_model_id": self.env['sf.materials.model'].search(
- [('materials_no', '=', item['materials_model_code'])]).id,
- "driving_way": item['driving_way'],
- "apply_machine_tool_type_ids": self.env['sf.machine_tool.type'].sudo()._get_ids(
- item['apply_machine_tool_type_code']),
- "through_hole_size": item['through_hole_size'],
- "screw_size": item['screw_size'],
+ "zero_chuck_ids": zero_chuck_list,
+ "zero_tray_ids": zero_tray_list,
+ "pneumatic_fixture_ids": pneumatic_fixture_list,
+ "jaw_vice_fixture_ids": jaw_vice_fixture_list,
+ "magnet_fixture_ids": magnet_fixture_list,
+ "adapter_board_fixture_ids": adapter_board_fixture_list,
+ "scroll_chuck_ids": scroll_chuck_list,
+ "status": item['status'],
"active": item['active'],
})
else:
fixture_model.write({
"name": item['name'],
+ "code": item['code'],
"fixture_material_id": self.env['sf.fixture.material'].search(
[('code', '=', item['fixture_material_code'])]).id,
"multi_mounting_type_id": self.env['sf.multi_mounting.type'].search(
[('code', '=', item['multi_mounting_type_code'])]).id,
"brand_id": self.env['sf.machine.brand'].search([('code', '=', item['brand_code'])]).id,
- "clamping_way": item['clamping_way'],
- "port_type": item['port_type'],
"model_file": '' if not item['model_file'] else base64.b64decode(item['model_file']),
- "length": item['length'],
- "width": item['width'],
- "height": item['height'],
- "weight": item['weight'],
- "clamp_workpiece_length_max": item['clamp_workpiece_length_max'],
- "clamp_workpiece_width_max": item['clamp_workpiece_width_max'],
- "clamp_workpiece_height_max": item['clamp_workpiece_height_max'],
- "clamp_workpiece_diameter_max": item['clamp_workpiece_diameter_max'],
- "maximum_carrying_weight": item['maximum_carrying_weight'],
- "maximum_clamping_force": item['maximum_clamping_force'],
- "materials_model_id": self.env['sf.materials.model'].search(
- [('materials_no', '=', item['materials_model_code'])]).id,
- "driving_way": item['driving_way'],
- "apply_machine_tool_type_ids": self.env['sf.machine_tool.type'].sudo()._get_ids(
- item['apply_machine_tool_type_code']),
- "through_hole_size": item['through_hole_size'],
- "screw_size": item['screw_size'],
+ "zero_chuck_ids": zero_chuck_list,
+ "zero_tray_ids": zero_tray_list,
+ "pneumatic_fixture_ids": pneumatic_fixture_list,
+ "jaw_vice_fixture_ids": jaw_vice_fixture_list,
+ "magnet_fixture_ids": magnet_fixture_list,
+ "adapter_board_fixture_ids": adapter_board_fixture_list,
+ "scroll_chuck_ids": scroll_chuck_list,
+ "status": item['status'],
"active": item['active'],
})
else:
@@ -1544,6 +1556,39 @@ class SyncFixtureModel(models.Model):
for item in result['fixture_model_all_list']:
if item:
fixture_model = self.search([("code", '=', item['code'])])
+ zero_chuck_list = []
+ for zero_chuck_id in item['zero_chuck_ids']:
+ zero_chuck_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_zero_chuck_param(zero_chuck_id))
+ zero_tray_list = []
+ for zero_tray_id in item['zero_tray_ids']:
+ zero_tray_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_zero_tray_param(zero_tray_id))
+ pneumatic_fixture_list = []
+ for pneumatic_fixture_id in item['pneumatic_fixture_ids']:
+ pneumatic_fixture_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_pneumatic_fixture_param(
+ pneumatic_fixture_id))
+ jaw_vice_fixture_list = []
+ for jaw_vice_fixture_id in item['jaw_vice_fixture_ids']:
+ jaw_vice_fixture_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_jaw_vice_fixture_param(
+ jaw_vice_fixture_id))
+ magnet_fixture_list = []
+ for magnet_fixture_id in item['magnet_fixture_ids']:
+ magnet_fixture_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_magnet_fixture_param(
+ magnet_fixture_id))
+ adapter_board_fixture_list = []
+ for adapter_board_fixture_id in item['adapter_board_fixture_ids']:
+ adapter_board_fixture_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_adapter_board_fixture_param(
+ adapter_board_fixture_id))
+ scroll_chuck_list = []
+ for scroll_chuck_id in item['scroll_chuck_ids']:
+ scroll_chuck_list.append(
+ self.env['sf.fixture.materials.basic.parameters']._json_scroll_chuck_param(
+ scroll_chuck_id))
if not fixture_model:
self.create({
"name": item['name'],
@@ -1553,56 +1598,35 @@ class SyncFixtureModel(models.Model):
"multi_mounting_type_id": self.env['sf.multi_mounting.type'].search(
[('code', '=', item['multi_mounting_type_code'])]).id,
"brand_id": self.env['sf.machine.brand'].search([('code', '=', item['brand_code'])]).id,
- "clamping_way": item['clamping_way'],
- "port_type": item['port_type'],
"model_file": '' if not item['model_file'] else base64.b64decode(item['model_file']),
- "length": item['length'],
- "width": item['width'],
- "height": item['height'],
- "weight": item['weight'],
- "clamp_workpiece_length_max": item['clamp_workpiece_length_max'],
- "clamp_workpiece_width_max": item['clamp_workpiece_width_max'],
- "clamp_workpiece_height_max": item['clamp_workpiece_height_max'],
- "clamp_workpiece_diameter_max": item['clamp_workpiece_diameter_max'],
- "maximum_carrying_weight": item['maximum_carrying_weight'],
- "maximum_clamping_force": item['maximum_clamping_force'],
- "materials_model_id": self.env['sf.materials.model'].search(
- [('materials_no', '=', item['materials_model_code'])]).id,
- "driving_way": item['driving_way'],
- "apply_machine_tool_type_ids": self.env['sf.machine_tool.type'].sudo()._get_ids(
- item['apply_machine_tool_type_code']),
- "through_hole_size": item['through_hole_size'],
- "screw_size": item['screw_size'],
+ "zero_chuck_ids": zero_chuck_list,
+ "zero_tray_ids": zero_tray_list,
+ "pneumatic_fixture_ids": pneumatic_fixture_list,
+ "jaw_vice_fixture_ids": jaw_vice_fixture_list,
+ "magnet_fixture_ids": magnet_fixture_list,
+ "adapter_board_fixture_ids": adapter_board_fixture_list,
+ "scroll_chuck_ids": scroll_chuck_list,
+ "status": item['status'],
"active": item['active'],
})
else:
fixture_model.write({
"name": item['name'],
+ "code": item['code'],
"fixture_material_id": self.env['sf.fixture.material'].search(
[('code', '=', item['fixture_material_code'])]).id,
"multi_mounting_type_id": self.env['sf.multi_mounting.type'].search(
[('code', '=', item['multi_mounting_type_code'])]).id,
"brand_id": self.env['sf.machine.brand'].search([('code', '=', item['brand_code'])]).id,
- "clamping_way": item['clamping_way'],
- "port_type": item['port_type'],
"model_file": '' if not item['model_file'] else base64.b64decode(item['model_file']),
- "length": item['length'],
- "width": item['width'],
- "height": item['height'],
- "weight": item['weight'],
- "clamp_workpiece_length_max": item['clamp_workpiece_length_max'],
- "clamp_workpiece_width_max": item['clamp_workpiece_width_max'],
- "clamp_workpiece_height_max": item['clamp_workpiece_height_max'],
- "clamp_workpiece_diameter_max": item['clamp_workpiece_diameter_max'],
- "maximum_carrying_weight": item['maximum_carrying_weight'],
- "maximum_clamping_force": item['maximum_clamping_force'],
- "materials_model_id": self.env['sf.materials.model'].search(
- [('materials_no', '=', item['materials_model_code'])]).id,
- "driving_way": item['driving_way'],
- "apply_machine_tool_type_ids": self.env['sf.machine_tool.type'].sudo()._get_ids(
- item['apply_machine_tool_type_code']),
- "through_hole_size": item['through_hole_size'],
- "screw_size": item['screw_size'],
+ "zero_chuck_ids": zero_chuck_list,
+ "zero_tray_ids": zero_tray_list,
+ "pneumatic_fixture_ids": pneumatic_fixture_list,
+ "jaw_vice_fixture_ids": jaw_vice_fixture_list,
+ "magnet_fixture_ids": magnet_fixture_list,
+ "adapter_board_fixture_ids": adapter_board_fixture_list,
+ "scroll_chuck_ids": scroll_chuck_list,
+ "status": item['status'],
"active": item['active'],
})
else:
diff --git a/sf_plan/models/custom_plan.py b/sf_plan/models/custom_plan.py
index 075c7e21..a60af7f3 100644
--- a/sf_plan/models/custom_plan.py
+++ b/sf_plan/models/custom_plan.py
@@ -153,40 +153,45 @@ class sf_production_plan(models.Model):
"""
排程方法
"""
- if not self.production_line_id:
- raise ValidationError("未选择生产线")
- else:
- workorder_id_list = self.production_id.workorder_ids.ids
- if self.production_id.workorder_ids:
- for item in self.production_id.workorder_ids:
- if item.name == 'CNC加工':
- item.date_planned_finished = datetime.now() + timedelta(days=100)
- item.date_planned_start = self.date_planned_start
- item.date_planned_finished = item.date_planned_start + timedelta(
- minutes=self.env['mrp.routing.workcenter'].sudo().search(
- [('name', '=', 'CNC加工')]).time_cycle)
- item.duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
- [('name', '=', 'CNC加工')]).time_cycle
- self.calculate_plan_time_before(item, workorder_id_list)
- self.calculate_plan_time_after(item, workorder_id_list)
- self.date_planned_start, self.date_planned_finished = \
- item.date_planned_start, item.date_planned_finished
- self.state = 'done'
- self.production_id.schedule_state = '已排'
- # self.production_id.date_planned_start = self.date_planned_start
- # self.production_id.date_planned_finished = self.date_planned_finished
+ for record in self:
+ if not record.production_line_id:
+ raise ValidationError("未选择生产线")
else:
- raise ValidationError("未找到工单")
- # self.date_planned_finished = self.date_planned_start + timedelta(days=3)
- # self.state = 'done'
- return {
- 'name': '排程甘特图',
- 'type': 'ir.actions.act_window',
- 'res_model': 'sf.production.plan', # 要跳转的模型名称
- # 要显示的视图类型,可以是'form', 'tree', 'kanban', 'graph', 'calendar', 'pivot'等
- 'view_mode': 'gantt,tree,form',
- 'target': 'current', # 跳转的目标窗口,可以是'current'或'new'
- }
+ workorder_id_list = record.production_id.workorder_ids.ids
+ if record.production_id.workorder_ids:
+ for item in record.production_id.workorder_ids:
+ if item.name == 'CNC加工':
+ item.date_planned_finished = datetime.now() + timedelta(days=100)
+ item.date_planned_start = record.date_planned_start
+ item.date_planned_finished = item.date_planned_start + timedelta(
+ minutes=record.env['mrp.routing.workcenter'].sudo().search(
+ [('name', '=', 'CNC加工')]).time_cycle)
+ item.duration_expected = record.env['mrp.routing.workcenter'].sudo().search(
+ [('name', '=', 'CNC加工')]).time_cycle
+ record.calculate_plan_time_before(item, workorder_id_list)
+ record.calculate_plan_time_after(item, workorder_id_list)
+ record.date_planned_start, record.date_planned_finished = \
+ item.date_planned_start, item.date_planned_finished
+ record.state = 'done'
+ record.production_id.schedule_state = '已排'
+ mrp_production_ids = record.production_id._get_children().ids
+ print('mrp_production_ids', mrp_production_ids)
+ for i in mrp_production_ids:
+ record.env['mrp.production'].browse(i).schedule_state = '已排'
+ # record.production_id.date_planned_start = record.date_planned_start
+ # record.production_id.date_planned_finished = record.date_planned_finished
+ else:
+ raise ValidationError("未找到工单")
+ # record.date_planned_finished = record.date_planned_start + timedelta(days=3)
+ # record.state = 'done'
+ return {
+ 'name': '排程甘特图',
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'sf.production.plan', # 要跳转的模型名称
+ # 要显示的视图类型,可以是'form', 'tree', 'kanban', 'graph', 'calendar', 'pivot'等
+ 'view_mode': 'gantt,tree,form',
+ 'target': 'current', # 跳转的目标窗口,可以是'current'或'new'
+ }
def calculate_plan_time_before(self, item, workorder_id_list):
"""
diff --git a/sf_plan/views/view.xml b/sf_plan/views/view.xml
index fbca7218..c1bdf5fe 100644
--- a/sf_plan/views/view.xml
+++ b/sf_plan/views/view.xml
@@ -5,7 +5,10 @@
sf.production.plan.tree
sf.production.plan
-
+
+
diff --git a/sf_quality/security/ir.model.access.csv b/sf_quality/security/ir.model.access.csv
index dbcd31ee..8e91f577 100644
--- a/sf_quality/security/ir.model.access.csv
+++ b/sf_quality/security/ir.model.access.csv
@@ -62,7 +62,6 @@ access_quality_tag_group_quality_director,quality_tag_group_quality_director,qua
access_quality_reason_type_group_quality,quality_reason_group_quality,quality.model_quality_reason,sf_base.group_quality,1,0,0,0
access_quality_reason_type_group_quality_director,quality_reason_group_quality_director,quality.model_quality_reason,sf_base.group_quality_director,1,0,0,0
-
-
+access_quality_alert_stage,quality.alert.stage,quality.model_quality_alert_stage,sf_base.group_plan_dispatch,1,0,0,0
diff --git a/sf_sale/__manifest__.py b/sf_sale/__manifest__.py
index ba6a99db..6d340058 100644
--- a/sf_sale/__manifest__.py
+++ b/sf_sale/__manifest__.py
@@ -22,6 +22,11 @@
'views/purchase_order_view.xml',
'views/quick_easy_order_view.xml'
],
+ 'assets': {
+ 'web.assets_backend': [
+ 'sf_sale/static/js/setTableWidth.js',
+ ]
+ },
'demo': [
],
'qweb': [
diff --git a/sf_sale/security/ir.model.access.csv b/sf_sale/security/ir.model.access.csv
index 682d6531..569c146f 100644
--- a/sf_sale/security/ir.model.access.csv
+++ b/sf_sale/security/ir.model.access.csv
@@ -69,8 +69,11 @@ access_purchase_order_wizard_group_purchase,purchase_order_wizard_group_purchase
access_purchase_order_wizard_group_purchase_director,purchase_order_wizard_group_purchase_director,model_purchase_order_wizard,sf_base.group_purchase_director,1,1,1,0
access_crm_tag_group_sale_salemanager,crm_tag_group_sale_salemanager,sales_team.model_crm_tag,sf_base.group_sale_salemanager,1,0,0,0
access_crm_tag_group_sale_director,crm_tag_group_sale_director,sales_team.model_crm_tag,sf_base.group_sale_director,1,1,1,0
+
+access_sale_order,sale.order,sale.model_sale_order,sf_base.group_plan_dispatch,1,0,0,0
access_res_partner_group_purchase,res_partner_group_purchase,base.model_res_partner,sf_base.group_purchase,1,1,1,0
access_res_partner_group_purchase_director,res_partner_group_purchase_director,base.model_res_partner,sf_base.group_purchase_director,1,1,1,0
access_sale_advance_payment_inv_group_sale_salemanager,sale_advance_payment_inv_group_sale_salemanager,sale.model_sale_advance_payment_inv,sf_base.group_sale_salemanager,1,1,1,0
access_sale_advance_payment_inv_group_sale_director,sale_advance_payment_inv_group_sale_director,sale.model_sale_advance_payment_inv,sf_base.group_sale_director,1,1,1,0
+
diff --git a/sf_sale/static/js/setTableWidth.js b/sf_sale/static/js/setTableWidth.js
new file mode 100644
index 00000000..7cae3950
--- /dev/null
+++ b/sf_sale/static/js/setTableWidth.js
@@ -0,0 +1,28 @@
+function setTableWidth() {
+ let timer = null
+ const dom = $('.o_list_renderer ')
+ if(!dom.length) {
+ timer = setTimeout(setTableWidth, 500)
+ return
+ }
+ const widthTest = ''
+ $('body').append(widthTest)
+ clearTimeout(timer)
+ const tbody_tr = dom.find('tbody').children('tr')
+ dom.find('thead').children('tr').children().each(function () {
+ $('#widthTest').text($(this).text())
+ const width = $('#widthTest').width()
+ const i = $(this).index()
+ console.log(111)
+ tbody_tr.each(function () {
+ if($(this).children().length > 2) {
+ $(this).children().eq(i).css('min-width', width + 'px')
+ }
+ })
+ })
+}
+
+$(function () {
+ setTableWidth()
+})
+
diff --git a/sf_tool_management/__manifest__.py b/sf_tool_management/__manifest__.py
index e334c32a..c56f9463 100644
--- a/sf_tool_management/__manifest__.py
+++ b/sf_tool_management/__manifest__.py
@@ -27,6 +27,8 @@
'web.assets_qweb': [
],
'web.assets_backend': [
+ 'sf_tool_management/static/src/change.scss'
+
]
},
diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py
index 9f5721a5..80ac3811 100644
--- a/sf_tool_management/models/base.py
+++ b/sf_tool_management/models/base.py
@@ -791,7 +791,7 @@ class FunctionalToolAssembly(models.Model):
L_D_number = fields.Float(string='L/D值(mm)', readonly=True)
hiding_length = fields.Float(string='避空长(mm)', readonly=True)
- functional_tool_cutting_type = fields.Char(string='功能刀具切削类型', readonly=False)
+ # functional_tool_cutting_type = fields.Char(string='功能刀具切削类型', readonly=False)
tool_loading_person = fields.Char(string='装刀人', readonly=True)
tool_loading_time = fields.Datetime(string='装刀时间', readonly=True)
remark = fields.Char(string='备注说明', readonly=True)
diff --git a/sf_tool_management/static/src/change.scss b/sf_tool_management/static/src/change.scss
index 40fdcc8e..a4e64f97 100644
--- a/sf_tool_management/static/src/change.scss
+++ b/sf_tool_management/static/src/change.scss
@@ -8,4 +8,14 @@
.modal-content .o_list_button {
+}
+
+.o_form_view .o_field_widget .o_list_renderer {
+ width: calc(100% - 64px) !important;
+ margin:0 auto;
+ overflow: auto;
+}
+
+.o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector).o_list_number {
+ text-align: left;
}
\ No newline at end of file
diff --git a/sf_tool_management/views/tool_base_views.xml b/sf_tool_management/views/tool_base_views.xml
index 42bb103b..62c0f0eb 100644
--- a/sf_tool_management/views/tool_base_views.xml
+++ b/sf_tool_management/views/tool_base_views.xml
@@ -878,7 +878,7 @@
-
+
@@ -937,7 +936,6 @@
'default_new_former':new_former,
'default_use_tool_time':use_tool_time,
'default_reason_for_applying':reason_for_applying,
- 'default_functional_tool_cutting_type':functional_tool_cutting_type,
}"
attrs="{'invisible': [('assemble_status', '!=', '0')]}"
class="btn-primary"/>
@@ -1116,7 +1114,7 @@
-
+
diff --git a/sf_tool_management/wizard/wizard.py b/sf_tool_management/wizard/wizard.py
index f98da62e..a8b10fd1 100644
--- a/sf_tool_management/wizard/wizard.py
+++ b/sf_tool_management/wizard/wizard.py
@@ -330,7 +330,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
L_D_number = fields.Float(string='L/D值(mm)', compute='_compute_l_d_number')
hiding_length = fields.Float(string='避空长(mm)')
- functional_tool_cutting_type = fields.Char(string='功能刀具切削类型', readonly=False)
+ # functional_tool_cutting_type = fields.Char(string='功能刀具切削类型', readonly=False)
@api.onchange('integral_code_id')
def _onchange_after_assembly_functional_tool_diameter(self):
diff --git a/sf_tool_management/wizard/wizard_view.xml b/sf_tool_management/wizard/wizard_view.xml
index 7b3d2ab5..7586a513 100644
--- a/sf_tool_management/wizard/wizard_view.xml
+++ b/sf_tool_management/wizard/wizard_view.xml
@@ -190,7 +190,7 @@
-
+
diff --git a/sf_warehouse/security/ir.model.access.csv b/sf_warehouse/security/ir.model.access.csv
index 2367fbd7..b5954085 100644
--- a/sf_warehouse/security/ir.model.access.csv
+++ b/sf_warehouse/security/ir.model.access.csv
@@ -1,4 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+
access_sf_shelf_location,sf.shelf.location,model_sf_shelf_location,sf_warehouse.group_sf_stock_user,1,1,1,0
access_procurement_group,procurement.group,stock.model_procurement_group,base.group_user,1,1,1,0
@@ -95,17 +96,20 @@ access_stock_lot_label_layout_user,lot.label.layout.user,stock.model_lot_label_l
access_stock_replenish_option,stock.replenishment.option,stock.model_stock_replenishment_option,sf_warehouse.group_sf_stock_user,1,1,1,0
access_mrp_production,mrp.production,mrp.model_mrp_production,sf_warehouse.group_sf_stock_user,1,1,1,0
-access_sf_shelf_location,sf.shelf.location,model_sf_shelf_location,sf_base.group_plan_dispatch,1,0,0,0
-access_stock_move,stock.move,stock.model_stock_move,sf_base.group_plan_dispatch,1,0,0,0
+access_sf_shelf_location_group_plan_dispatch,sf.shelf.location,model_sf_shelf_location,sf_base.group_plan_dispatch,1,1,0,0
+access_stock_move,stock.move,stock.model_stock_move,sf_base.group_plan_dispatch,1,1,1,0
access_stock_scrap_user,stock.scrap.user,stock.model_stock_scrap,sf_base.group_plan_dispatch,1,0,0,0
access_stock_scrap_manager,stock.scrap.manager,stock.model_stock_scrap,sf_base.group_plan_dispatch,1,0,0,0
access_stock_picking,stock.picking,stock.model_stock_picking,sf_base.group_plan_dispatch,1,0,0,0
-access_stock_lot,stock.lot,stock.model_stock_lot,sf_base.group_plan_dispatch,1,1,1,0
-access_stock_warehouse_orderpoint,stock.warehouse.orderpoint,stock.model_stock_warehouse_orderpoint,sf_base.group_plan_dispatch,1,0,0,0
-access_stock_quant,stock.quant,stock.model_stock_quant,sf_base.group_plan_dispatch,1,0,0,0
+access_stock_lot_group_plan_dispatch,stock.lot,stock.model_stock_lot,sf_base.group_plan_dispatch,1,0,0,0
+access_stock_lot_group_plan_director,stock.lot,stock.model_stock_lot,sf_base.group_plan_director,1,1,1,0
+access_stock_warehouse_orderpoint,stock.warehouse.orderpoint,stock.model_stock_warehouse_orderpoint,sf_base.group_plan_dispatch,1,1,0,0
+access_stock_quant,stock.quant,stock.model_stock_quant,sf_base.group_plan_dispatch,1,1,1,0
-access_product_product,product.product,product.model_product_product,sf_base.group_plan_dispatch,1,1,1,0
-access_product_template,product.template,product.model_product_template,sf_base.group_plan_dispatch,1,1,1,0
+access_product_product,product.product,product.model_product_product,sf_base.group_plan_dispatch,1,0,0,0
+access_product_template,product.template,product.model_product_template,sf_base.group_plan_dispatch,1,0,0,0
+access_product_product,product.product,product.model_product_product,sf_base.group_plan_director,1,1,1,0
+access_product_template,product.template,product.model_product_template,sf_base.group_plan_director,1,1,1,0
access_stock_inventory_conflict,stock.inventory.conflict,stock.model_stock_inventory_conflict,sf_base.group_plan_dispatch,1,0,0,0
access_stock_inventory_warning,stock.inventory.warning,stock.model_stock_inventory_warning,sf_base.group_plan_dispatch,1,0,0,0