diff --git a/sf_maintenance/__manifest__.py b/sf_maintenance/__manifest__.py
index cec0b7e3..595a5d25 100644
--- a/sf_maintenance/__manifest__.py
+++ b/sf_maintenance/__manifest__.py
@@ -10,7 +10,9 @@
'data': [
'security/group_security.xml',
'security/ir.model.access.csv',
+ 'security/ir_rule_data.xml',
'views/maintenance_logs_views.xml',
+ 'views/maintenance_equipment_oee_views.xml',
'views/maintenance_views.xml',
'views/equipment_maintenance_standards_views.xml',
'views/maintenance_request_views.xml',
diff --git a/sf_maintenance/models/__init__.py b/sf_maintenance/models/__init__.py
index 0e06b132..b177eb3c 100644
--- a/sf_maintenance/models/__init__.py
+++ b/sf_maintenance/models/__init__.py
@@ -1,5 +1,6 @@
# -*-coding:utf-8-*-
from . import sf_maintenance
+from . import sf_maintenance_oee
from . import sf_maintenance_logs
from . import sf_equipment_maintenance_standards
from . import sf_maintenance_requests
diff --git a/sf_maintenance/models/sf_equipment_maintenance_standards.py b/sf_maintenance/models/sf_equipment_maintenance_standards.py
index 92a94c0e..388199da 100644
--- a/sf_maintenance/models/sf_equipment_maintenance_standards.py
+++ b/sf_maintenance/models/sf_equipment_maintenance_standards.py
@@ -86,7 +86,7 @@ class SfSaintenanceStandards(models.Model):
images = fields.One2many('maintenance.standard.image', 'standard_id', string='反馈图片')
maintenance_request_ids = fields.Many2many('maintenance.request', string='维保计划')
Period = fields.Integer('周期/频次(天)')
- remark = fields.Char('备注说明')
+ remark = fields.Char('维保记录')
class MaintenanceStandardImage(models.Model):
diff --git a/sf_maintenance/models/sf_maintenance.py b/sf_maintenance/models/sf_maintenance.py
index b09fb373..a99dd363 100644
--- a/sf_maintenance/models/sf_maintenance.py
+++ b/sf_maintenance/models/sf_maintenance.py
@@ -17,12 +17,30 @@ class SfMaintenanceEquipmentCategory(models.Model):
equipment_type_code = fields.Char('简写')
+class SfMaintenanceEquipmentAGVLog(models.Model):
+ _name = 'maintenance.equipment.agv.log'
+ _description = 'AGV运行日志'
+
+ run_type = fields.Char('任务类型')
+ run_code = fields.Char('任务指令代码')
+ run_first = fields.Char('任务起点')
+ production_line = fields.Char('目的生产线')
+ run_last = fields.Char('任务终点')
+ workorder = fields.Char('工件编码/任务单号')
+ time = fields.Datetime('日期/事件')
+ state = fields.Char('事件/状体')
+ equipment_id = fields.Many2one('maintenance.equipment', '设备')
+
+
class SfMaintenanceEquipment(models.Model):
_inherit = 'maintenance.equipment'
_description = '设备'
crea_url = "/api/machine_tool/create"
+
+ #AGV运行日志
+ agv_logs = fields.One2many('maintenance.equipment.agv.log', 'equipment_id', string='AGV运行日志')
# 1212修改后的字段
number_of_axles = fields.Selection(
[("三轴", "三轴"), ("四轴", "四轴"), ("五轴", "五轴"), ("六轴", "六轴")],
@@ -139,7 +157,7 @@ class SfMaintenanceEquipment(models.Model):
record.equipment_type = record.category_id.equipment_type
code = fields.Char('行业编码')
- name = fields.Char('机台号')
+ name = fields.Char('机台号', required=False)
knife_type = fields.Selection(
[("BT40", "BT40"), ("BT30", "BT30"), ("BT50", "BT50")],
default="", string="刀把类型")
@@ -160,8 +178,9 @@ class SfMaintenanceEquipment(models.Model):
type_id = fields.Many2one('sf.machine_tool.type', '型号')
state = fields.Selection(
- [("正常", "正常"), ("故障", "故障"), ("不可用", "不可用")],
+ [("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"),("空闲", "空闲"),("封存(报废)", "封存(报废)")],
default='正常', string="机床状态")
+ run_time = fields.Char('总运行时长')
# 0606新增字段
machine_tool_picture = fields.Binary('图片')
heightened_way = fields.Selection([
@@ -193,23 +212,25 @@ class SfMaintenanceEquipment(models.Model):
# 多个型号对应一个机床
machine_tool_id = fields.Many2one('sf.machine_tool', '机床')
sf_maintenance_logs_ids = fields.One2many('sf.maintenance.logs', 'maintenance_equipment_id', '设备故障日志')
+ equipment_oee_ids = fields.One2many('maintenance.equipment.oee', 'equipment_id', '设备OEE')
- def name_get(self):
- result = []
- for parameter in self:
- if parameter.code:
- name = parameter.name + '-' + parameter.code
- else:
- name = parameter.name
- result.append((parameter.id, name))
- return result
+ # def name_get(self):
+ # result = []
+ # for parameter in self:
+ # if parameter.code:
+ # name = parameter.name + '-' + parameter.code
+ # else:
+ # name = parameter.name
+ # result.append((parameter.id, name))
+ # return result
@api.model
def create(self, vals):
# 在创建设备之前执行一些自定义逻辑
equipment = super(SfMaintenanceEquipment, self).create(vals)
- equipment.name = equipment.MTcode + '#' + equipment.category_id.name
+ if equipment.category_id:
+ equipment.name = equipment.MTcode + '#' + equipment.category_id.name
# 在创建设备之后执行一些自定义逻辑
# ...
@@ -449,7 +470,7 @@ class SfMaintenanceEquipment(models.Model):
sf_secret_key = sf_sync_config['sf_secret_key']
headers = Common.get_headers(self, token, sf_secret_key)
strurl = sf_sync_config['sf_url'] + self.crea_url
- objs_all = self.env['maintenance.equipment'].search([('MTcode', '=', self.MTcode)])
+ objs_all = self.env['maintenance.equipment'].search([('id', '=', self.id)])
machine_tool_list = []
if objs_all:
for item in objs_all:
@@ -552,7 +573,7 @@ class SfMaintenanceEquipment(models.Model):
kw = json.dumps(machine_tool_list, ensure_ascii=False)
r = requests.post(strurl, json={}, data={'kw': kw, 'token': token}, headers=headers)
ret = r.json()
- self.code = ret['message']
+ self.code = ret['data']
self.state_zc = "已注册"
if r == 200:
return "机床注册成功"
diff --git a/sf_maintenance/models/sf_maintenance_logs.py b/sf_maintenance/models/sf_maintenance_logs.py
index 5c798754..2dc26f7e 100644
--- a/sf_maintenance/models/sf_maintenance_logs.py
+++ b/sf_maintenance/models/sf_maintenance_logs.py
@@ -11,6 +11,7 @@ class SfMaintenanceLogs(models.Model):
type = fields.Selection([('type1', '类型1'), ('type2', '类型2')], string='类型')
brand = fields.Many2one('sf.machine.brand', related='maintenance_equipment_id.brand_id', string='品牌')
maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='设备')
+ maintenance_equipment_oee_id = fields.Many2one('maintenance.equipment.oee', string='设备oee')
code_location = fields.Char(string='编码位置')
fault_type = fields.Selection(
[('电气类', '电气类'), ('机械类', '机械类'), ('程序类', '程序类'), ('系统类', '系统类')], string='故障类型')
@@ -26,3 +27,4 @@ class SfMaintenanceLogs(models.Model):
recovery_time = fields.Datetime(string='复原时间')
fault_duration = fields.Float(string='故障时长')
note = fields.Text(string='备注')
+ active = fields.Boolean('Active', default=True)
diff --git a/sf_maintenance/models/sf_maintenance_oee.py b/sf_maintenance/models/sf_maintenance_oee.py
new file mode 100644
index 00000000..6d76ffbe
--- /dev/null
+++ b/sf_maintenance/models/sf_maintenance_oee.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+from odoo import api, fields, models, _
+
+
+class SfMaintenanceEquipmentOEE(models.Model):
+ _name = 'maintenance.equipment.oee'
+ _description = '设备OEE'
+
+ name = fields.Char('设备oee')
+ equipment_id = fields.Many2one('maintenance.equipment', '设备',
+ domain="[('category_id.equipment_type', '=', '机床'),('state_zc', '=', '已注册')]")
+ type_id = fields.Many2one('sf.machine_tool.type', '型号', related='equipment_id.type_id')
+ machine_tool_picture = fields.Binary('设备图片', related='equipment_id.machine_tool_picture')
+ state = fields.Selection(
+ [("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"), ("空闲", "空闲"),
+ ("封存(报废)", "封存(报废)")],
+ default='正常', string="机床状态", related='equipment_id.state')
+ run_time = fields.Float('正常运行总时长(h)')
+ equipment_time = fields.Float('总时长(h)')
+ done_nums = fields.Integer('累计加工总件数')
+ utilization_rate = fields.Char('开动率')
+ fault_time = fields.Float('故障停机总时长(h)')
+ fault_nums = fields.Integer('故障次数')
+ sf_maintenance_logs_ids = fields.One2many('sf.maintenance.logs', 'maintenance_equipment_oee_id', '设备故障日志',
+ related='equipment_id.sf_maintenance_logs_ids')
+ oee_logs = fields.One2many('maintenance.equipment.oee.logs', 'equipment_oee_id', string='运行日志')
+
+ def name_get(self):
+ result = []
+ for parameter in self:
+ if parameter.equipment_id:
+ name = parameter.equipment_id.name
+ result.append((parameter.id, name))
+ return result
+
+
+class SfMaintenanceEquipmentOEELog(models.Model):
+ _name = 'maintenance.equipment.oee.logs'
+ _description = '设备运行日志'
+
+ name = fields.Char('运行日志')
+ run_time = fields.Datetime('时间')
+ state = fields.Selection([("开机", "开机"), ("关机", "关机"), ("等待", "等待"), ("开始加工", "开始加工"),
+ ("结束加工", "结束加工"), ("故障", "故障"),
+ ("检修", "检修"), ("保养", "保养")], default="", string="事件/状态")
+ workorder_id = fields.Char('加工订单')
+ time = fields.Char('持续时长')
+ color = fields.Char('颜色', default=1)
+ equipment_oee_id = fields.Many2one('maintenance.equipment.oee', '设备OEE')
diff --git a/sf_maintenance/security/ir.model.access.csv b/sf_maintenance/security/ir.model.access.csv
index 4f693af2..18ede6d7 100644
--- a/sf_maintenance/security/ir.model.access.csv
+++ b/sf_maintenance/security/ir.model.access.csv
@@ -1,14 +1,33 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_equipment_maintenance_standards,equipment_maintenance_standards,model_equipment_maintenance_standards,sf_group_equipment_user,1,1,1,1
-access_sf_maintenance_logs,sf_maintenance_logs,model_sf_maintenance_logs,sf_group_equipment_user,1,1,1,1
-access_maintenance_equipment,maintenance_equipment,model_maintenance_equipment,sf_group_equipment_user,1,1,1,1
-access_maintenance_standards,maintenance_standards,model_maintenance_standards,sf_group_equipment_user,1,1,1,1
-access_maintenance_standard_image,maintenance_standard_image,model_maintenance_standard_image,sf_group_equipment_user,1,1,1,1
-access_sf_robot_axis_num,sf_robot_axis_num,model_sf_robot_axis_num,sf_group_equipment_user,1,1,1,1
+access_equipment_maintenance_standards,equipment_maintenance_standards,model_equipment_maintenance_standards,sf_group_equipment_user,1,1,1,0
+access_sf_maintenance_logs,sf_maintenance_logs,model_sf_maintenance_logs,sf_group_equipment_user,1,0,0,0
+access_sf_maintenance_logs,sf_maintenance_logs,model_sf_maintenance_logs,sf_group_equipment_manager,1,1,1,0
+access_maintenance_equipment,maintenance_equipment,model_maintenance_equipment,sf_group_equipment_user,1,0,0,0
+access_maintenance_equipment,maintenance_equipment,model_maintenance_equipment,sf_group_equipment_manager,1,1,1,0
+access_maintenance_equipment_oee,maintenance_equipment_oee,model_maintenance_equipment_oee,sf_group_equipment_user,1,0,0,0
+access_maintenance_equipment_oee,maintenance_equipment_oee,model_maintenance_equipment_oee,sf_group_equipment_manager,1,1,1,0
+access_maintenance_equipment_oee,maintenance_equipment_oee,model_maintenance_equipment_oee,base.group_user,1,1,1,1
+access_maintenance_equipment_oee_logs,maintenance_equipment_oee_logs,model_maintenance_equipment_oee_logs,sf_group_equipment_user,1,0,0,0
+access_maintenance_equipment_oee_logs,maintenance_equipment_oee_logs,model_maintenance_equipment_oee_logs,sf_group_equipment_manager,1,1,1,0
+access_maintenance_equipment_oee_logs,maintenance_equipment_oee_logs,model_maintenance_equipment_oee_logs,base.group_user,1,1,1,1
+access_maintenance_standards,maintenance_standards,model_maintenance_standards,sf_group_equipment_user,1,0,0,0
+access_maintenance_standards,maintenance_standards,model_maintenance_standards,sf_group_equipment_manager,1,1,1,0
+access_maintenance_standard_image,maintenance_standard_image,model_maintenance_standard_image,sf_group_equipment_user,1,0,0,0
+access_maintenance_standard_image,maintenance_standard_image,model_maintenance_standard_image,sf_group_equipment_manager,1,1,1,0
+access_sf_robot_axis_num,sf_robot_axis_num,model_sf_robot_axis_num,sf_group_equipment_user,1,0,0,0
+access_sf_robot_axis_num,sf_robot_axis_num,model_sf_robot_axis_num,sf_group_equipment_manager,1,1,1,0
+access_maintenance_equipment_agv_log,maintenance_equipment_agv_log,model_maintenance_equipment_agv_log,sf_group_equipment_user,1,0,0,0
+access_maintenance_equipment_agv_log,maintenance_equipment_agv_log,model_maintenance_equipment_agv_log,sf_group_equipment_manager,1,1,1,0
+access_maintenance_equipment_agv_log,maintenance_equipment_agv_log,model_maintenance_equipment_agv_log,base.group_user,1,1,1,1
-access_maintenance_request,maintenance.request,maintenance.model_maintenance_request,sf_base.group_plan_dispatch,1,0,0,0
-access_maintenance_equipment,maintenance_equipment,model_maintenance_equipment,sf_base.group_plan_dispatch,1,0,0,0
-access_sf_maintenance_logs,sf_maintenance_logs,model_sf_maintenance_logs,sf_base.group_plan_dispatch,1,0,0,0
-access_maintenance_standard_image,maintenance_standard_image,model_maintenance_standard_image,sf_base.group_plan_dispatch,1,0,0,0
-access_equipment_maintenance_standards,equipment_maintenance_standards,model_equipment_maintenance_standards,sf_base.group_plan_dispatch,1,0,0,0
\ No newline at end of file
+access_maintenance_system_user,equipment.request system user,maintenance.model_maintenance_request,base.group_user,1,0,0,0
+
+access_maintenance_equipment_group_plan_dispatch,maintenance.equipment,maintenance.model_maintenance_equipment,sf_base.group_plan_dispatch,1,0,0,0
+access_maintenance_equipment_oee_group_plan_dispatch,maintenance_equipment_oee,model_maintenance_equipment_oee,sf_base.group_plan_dispatch,1,0,0,0
+access_sf_maintenance_logs_group_plan_dispatch,sf_maintenance_logs,model_sf_maintenance_logs,sf_base.group_plan_dispatch,1,0,0,0
+access_maintenance_standard_image_group_plan_dispatch,maintenance_standard_image,model_maintenance_standard_image,sf_base.group_plan_dispatch,1,0,0,0
+access_equipment_maintenance_standards_group_plan_dispatch,equipment_maintenance_standards,model_equipment_maintenance_standards,sf_base.group_plan_dispatch,1,0,0,0
+access_maintenance_standards_group_plan_dispatch,maintenance_standards,model_maintenance_standards,sf_base.group_plan_dispatch,1,0,0,0
+
+access_sf_robot_axis_num_group_plan_dispatch,sf.robot.axis.num,model_sf_robot_axis_num,sf_base.group_plan_dispatch,1,0,0,0
\ No newline at end of file
diff --git a/sf_maintenance/security/ir_rule_data.xml b/sf_maintenance/security/ir_rule_data.xml
new file mode 100644
index 00000000..411afb45
--- /dev/null
+++ b/sf_maintenance/security/ir_rule_data.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ Maintenance Equipment Plan Dispatch Rule
+
+
+
+ True
+ False
+ False
+ False
+
+
+
+
+ Maintenance Request Plan Dispatch Rule
+
+
+
+ True
+ False
+ False
+ False
+
+
+
+
diff --git a/sf_maintenance/views/maintenance_equipment_category_views.xml b/sf_maintenance/views/maintenance_equipment_category_views.xml
index fa9c571c..2cdb47a3 100644
--- a/sf_maintenance/views/maintenance_equipment_category_views.xml
+++ b/sf_maintenance/views/maintenance_equipment_category_views.xml
@@ -18,7 +18,7 @@
-
+
diff --git a/sf_maintenance/views/maintenance_equipment_oee_views.xml b/sf_maintenance/views/maintenance_equipment_oee_views.xml
new file mode 100644
index 00000000..091e3c47
--- /dev/null
+++ b/sf_maintenance/views/maintenance_equipment_oee_views.xml
@@ -0,0 +1,132 @@
+
+
+
+
+
+ maintenance.oee.tree
+ maintenance.equipment.oee
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ maintenance.oee.form
+ maintenance.equipment.oee
+
+
+
+
+
+
+
+ maintenance.oee.search
+ maintenance.equipment.oee
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 设备OEE
+ ir.actions.act_window
+ maintenance.equipment.oee
+
+ tree,form
+
+
+
+ 设备OEE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sf_maintenance/views/maintenance_logs_views.xml b/sf_maintenance/views/maintenance_logs_views.xml
index a4e8d605..087f6ffb 100644
--- a/sf_maintenance/views/maintenance_logs_views.xml
+++ b/sf_maintenance/views/maintenance_logs_views.xml
@@ -8,7 +8,6 @@
-
@@ -105,9 +104,10 @@
- 设备故障日志
+ 设备故障日志
ir.actions.act_window
sf.maintenance.logs
+
tree,form
@@ -117,6 +117,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sf_maintenance/views/maintenance_views.xml b/sf_maintenance/views/maintenance_views.xml
index ccf333ba..125a86c0 100644
--- a/sf_maintenance/views/maintenance_views.xml
+++ b/sf_maintenance/views/maintenance_views.xml
@@ -27,11 +27,19 @@
+
+
+
@@ -48,7 +56,7 @@
-
+
@@ -56,21 +64,25 @@
domain="[('brand_id', '=', brand_id)]"/>
+
-
+
-
-
@@ -114,22 +126,26 @@
-
-
-
-
-
+
@@ -176,58 +192,74 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -912,28 +944,30 @@
-
+
-
+
-
-
-
-
-
+
+
+
+
+
-
+
-
+
-
-
-
-
-
+
+
+
+
+
diff --git a/sf_manufacturing/__init__.py b/sf_manufacturing/__init__.py
index 0650744f..48d99043 100644
--- a/sf_manufacturing/__init__.py
+++ b/sf_manufacturing/__init__.py
@@ -1 +1,3 @@
from . import models
+from . import controllers
+from . import wizard
diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py
index 85e71a5d..6a122097 100644
--- a/sf_manufacturing/__manifest__.py
+++ b/sf_manufacturing/__manifest__.py
@@ -15,7 +15,9 @@
'data/stock_data.xml',
'security/group_security.xml',
'security/ir.model.access.csv',
+ 'wizard/workpiece_delivery_views.xml',
'views/mrp_views_menus.xml',
+ 'views/stock_lot_views.xml',
'views/mrp_production_addional_change.xml',
'views/mrp_routing_workcenter_view.xml',
'views/production_line_view.xml',
diff --git a/sf_manufacturing/controllers/__init__.py b/sf_manufacturing/controllers/__init__.py
new file mode 100644
index 00000000..e046e49f
--- /dev/null
+++ b/sf_manufacturing/controllers/__init__.py
@@ -0,0 +1 @@
+from . import controllers
diff --git a/sf_manufacturing/controllers/controllers.py b/sf_manufacturing/controllers/controllers.py
new file mode 100644
index 00000000..d75fbe69
--- /dev/null
+++ b/sf_manufacturing/controllers/controllers.py
@@ -0,0 +1,217 @@
+# -*- coding: utf-8 -*-
+import logging
+import json
+from odoo import http
+from odoo.http import request
+
+
+class Manufacturing_Connect(http.Controller):
+
+ @http.route('/AutoDeviceApi/GetWoInfo', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
+ cors="*")
+ def get_Work_Info(self, **kw):
+ """
+ 自动化传递工单号获取工单信息
+ :param kw:
+ :return:
+ """
+ logging.info('get_Work_Info:%s' % kw)
+ try:
+ res = {'Succeed': True, 'Datas': []}
+ datas = request.httprequest.data
+ ret = json.loads(datas)
+ logging.info('RfidCode:%s' % ret['RfidCode'])
+ workorder = request.env['mrp.workorder'].sudo().search(
+ [('rfid_code', '=', ret['RfidCode']), ('routing_type', '=', '装夹预调')])
+ if workorder:
+ for item in workorder:
+ res['Datas'].append({
+ 'BillId': item.production_id.name,
+ 'ProductionLine': item.production_line,
+ 'CraftName': item.name,
+ 'Quantity': 1,
+ 'MaterialId': item.product_id.default_code,
+ 'MaterialName': item.product_id.name,
+ 'Spec': '%s×%s×%s' % (item.move_raw_ids.materiel_length, item.move_raw_ids.materiel_width,
+ item.move_raw_ids.materiel_height),
+ 'Material': item.product_id.materials_type_id.name
+ })
+ except Exception as e:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
+ logging.info('get_Work_Info error:%s' % e)
+ return json.JSONEncoder().encode(res)
+
+ @http.route('/AutoDeviceApi/GetShiftPlan', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
+ cors="*")
+ def get_ShiftPlan(self, **kw):
+ """
+ 自动化每天获取机台日计划
+ :param kw:
+ :return:
+ """
+ logging.info('get_ShiftPlan:%s' % kw)
+ try:
+ res = {'Succeed': True, 'Datas': []}
+ datas = request.httprequest.data
+ ret = json.loads(datas)
+ ret = json.loads(ret['result'])
+ logging.info('RfidCode:%s' % ret)
+ workorder = request.env['mrp.workorder'].sudo().search([('name', '=', ret['ProductionLine'])])
+ if workorder:
+ for item in workorder:
+ date_planned_start = ''
+ date_planned_finished = ''
+ if item.date_planned_start is not False:
+ planned_start = item.date_planned_start.strftime("%Y-%m-%d %H:%M:%S")
+ date_planned_start = request.env['sf.sync.common'].sudo().get_add_time(planned_start)
+ if item.date_planned_finished is not False:
+ planned_finished = item.date_planned_finished.strftime("%Y-%m-%d %H:%M:%S")
+ date_planned_finished = request.env['sf.sync.common'].sudo().get_add_time(planned_finished)
+ res['Datas'].append({
+ 'BillId': item.production_id.name,
+ 'RfidCode': item.RfidCode,
+ 'CraftName': item.name,
+ 'Quantity': 1,
+ 'WortkStart': date_planned_start,
+ 'WorkEnd': date_planned_finished,
+ 'MaterialId': item.product_id.default_code,
+ 'MaterialName': item.product_id.name,
+ # 'Spec':item.mat,
+ 'Material': item.materials_type_id.name
+ })
+ except Exception as e:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
+ logging.info('get_ShiftPlan error:%s' % e)
+ return json.JSONEncoder().encode(res)
+
+ @http.route('/AutoDeviceApi/QcCheck', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
+ cors="*")
+ def get_qcCheck(self, **kw):
+ """
+ 工件预调(前置三元检测)
+ 1、前置三元检测在产线外:三元检测设备把测量信息上传给MES,
+ MES生成检测定位数据。中控系统传递RFID编号给MES获取测量偏置结果。(来源为三元检测工单上的字段)
+ :param kw:
+ :return:
+ """
+ logging.info('get_qcCheck:%s' % kw)
+ try:
+ res = {'Succeed': True, 'Datas': []}
+ datas = request.httprequest.data
+ ret = json.loads(datas)
+ ret = json.loads(ret['result'])
+ logging.info('RfidCode:%s' % ret)
+ workorder = request.env['mrp.workorder'].sudo().search([('routing_type', '=', '前置三元定位检测')])
+ if workorder:
+ for item in workorder:
+ res['Datas'].append({
+ 'XOffset': item.production_id.name,
+ 'YOffset': item.RfidCode,
+ 'ZOffet': item.name,
+ 'COffset': 1
+ })
+ except Exception as e:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
+ logging.info('get_qcCheck error:%s' % e)
+ return json.JSONEncoder().encode(res)
+
+ @http.route('/AutoDeviceApi/FeedBackStart', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
+ cors="*")
+ def button_Work_START(self, **kw):
+ """
+ 工单任务开始
+ :param kw:
+ :return:
+ """
+ logging.info('button_Work_START:%s' % kw)
+ try:
+ res = {'Succeed': True, 'Datas': []}
+ datas = request.httprequest.data
+ ret = json.loads(datas)
+ if not ret['BillId']:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传制造订单号'}
+ return json.JSONEncoder().encode(res)
+ if not ret['CraftId']:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传工序名称'}
+ return json.JSONEncoder().encode(res)
+ if not ret['DeviceId']:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传设备号'}
+ return json.JSONEncoder().encode(res)
+ production_id = ret['BillId']
+ routing_type = ret['CraftId']
+ workorder = request.env['mrp.workorder'].sudo().search(
+ [('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
+ workorder.button_start()
+ except Exception as e:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
+ logging.info('button_Work_START error:%s' % e)
+ return json.JSONEncoder().encode(res)
+
+ @http.route('/AutoDeviceApi/FeedBackEnd', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
+ cors="*")
+ def button_Work_End(self, **kw):
+ """
+ 工单任务结束
+ :param kw:
+ :return:
+ """
+ logging.info('button_Work_End:%s' % kw)
+ try:
+ res = {'Succeed': True, 'Datas': []}
+ datas = request.httprequest.data
+ ret = json.loads(datas)
+ if not ret['BillId']:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传制造订单号'}
+ return json.JSONEncoder().encode(res)
+ if not ret['CraftId']:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传工序名称'}
+ return json.JSONEncoder().encode(res)
+ if not ret['DeviceId']:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传设备号'}
+ return json.JSONEncoder().encode(res)
+ production_id = ret['BillId']
+ routing_type = ret['CraftId']
+ workorder = request.env['mrp.workorder'].sudo().search(
+ [('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
+ workorder.button_finish()
+ except Exception as e:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
+ logging.info('button_Work_End error:%s' % e)
+ return json.JSONEncoder().encode(res)
+
+ @http.route('/AutoDeviceApi/QcCheck', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
+ cors="*")
+ def Workorder_QcCheck(self, **kw):
+ """
+ 零件质检
+ :param kw:
+ :return:
+ """
+ logging.info('Workorder_QcCheck:%s' % kw)
+ try:
+ res = {'Succeed': True, 'Datas': []}
+ datas = request.httprequest.data
+ ret = json.loads(datas)
+ if not ret['BillId']:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传制造订单号'}
+ return json.JSONEncoder().encode(res)
+ if not ret['CraftId']:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传工序名称'}
+ return json.JSONEncoder().encode(res)
+ if not ret['DeviceId']:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传设备号'}
+ return json.JSONEncoder().encode(res)
+ if not ret['Quality']:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传检测结果'}
+ return json.JSONEncoder().encode(res)
+ if not ret['ReportPaht']:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': '未传检查报告文件(地址)'}
+ return json.JSONEncoder().encode(res)
+ production_id = ret['BillId']
+ routing_type = ret['CraftId']
+ request.env['mrp.workorder'].sudo().search(
+ [('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
+ except Exception as e:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
+ logging.info('Workorder_QcCheck error:%s' % e)
+ return json.JSONEncoder().encode(res)
diff --git a/sf_manufacturing/data/stock_data.xml b/sf_manufacturing/data/stock_data.xml
index 74d02b4a..6bd0fe53 100644
--- a/sf_manufacturing/data/stock_data.xml
+++ b/sf_manufacturing/data/stock_data.xml
@@ -1,6 +1,13 @@
+
+ 工序编码规则
+ mrp.routing.workcenter
+ 4
+
+
+
YourCompany Sequence ocout
WH/OCOUT/
diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py
index 4b15299d..7c4915c1 100644
--- a/sf_manufacturing/models/mrp_production.py
+++ b/sf_manufacturing/models/mrp_production.py
@@ -1,6 +1,12 @@
# -*- 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
+from odoo.tools import float_compare, float_round, float_is_zero, format_datetime
class MrpProduction(models.Model):
@@ -12,11 +18,80 @@ class MrpProduction(models.Model):
maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests")
request_ids = fields.One2many('maintenance.request', 'production_id')
model_file = fields.Binary('模型文件', related='product_id.model_file')
- schedule_state = fields.Selection([('未排', '未排'), ('已排', '已排')],
+ schedule_state = fields.Selection([('未排', '未排'), ('已排', '已排'), ('已完成', '已完成')],
string='排程状态', default='未排')
+ # state = fields.Selection(selection_add=[
+ # ('pending_scheduling', '待排程'),
+ # ('pending_processing', '待加工'),
+ # ('completed', '已完工')
+ # ])
+ state = fields.Selection([
+ ('draft', 'Draft'),
+ ('confirmed', 'Confirmed'),
+ ('progress', '待排程'),
+ ('pending_processing', '待加工'),
+ ('completed', '已完工'),
+ ('to_close', 'To Close'),
+ ('done', 'Done'),
+ ('cancel', 'Cancelled')], string='State',
+ compute='_compute_state', copy=False, index=True, readonly=True,
+ store=True, tracking=True,
+ help=" * Draft: The MO is not confirmed yet.\n"
+ " * Confirmed: The MO is confirmed, the stock rules and the reordering of the components are trigerred.\n"
+ " * In Progress: The production has started (on the MO or on the WO).\n"
+ " * To Close: The production is done, the MO has to be closed.\n"
+ " * Done: The MO is closed, the stock moves are posted. \n"
+ " * Cancelled: The MO has been cancelled, can't be confirmed anymore.")
+
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模型文件")
+ production_line_id = fields.Many2one('sf.production.line', string='生产线')
+ plan_start_processing_time = fields.Datetime('计划开始加工时间')
+
+
+ @api.depends(
+ 'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state',
+ 'workorder_ids.state', 'product_qty', 'qty_producing', 'schedule_state')
+ def _compute_state(self):
+ for production in self:
+ if not production.state or not production.product_uom_id:
+ production.state = 'draft'
+ elif production.state == 'cancel' or (production.move_finished_ids and all(
+ move.state == 'cancel' for move in production.move_finished_ids)):
+ production.state = 'cancel'
+ elif (
+ production.state == 'done'
+ or (production.move_raw_ids and all(
+ move.state in ('cancel', 'done') for move in production.move_raw_ids))
+ and all(move.state in ('cancel', 'done') for move in production.move_finished_ids)
+ ):
+ production.state = 'done'
+ elif production.workorder_ids and all(
+ wo_state in ('done', 'cancel') for wo_state in production.workorder_ids.mapped('state')):
+ production.state = 'to_close'
+ elif not production.workorder_ids and float_compare(production.qty_producing, production.product_qty,
+ precision_rounding=production.product_uom_id.rounding) >= 0:
+ production.state = 'to_close'
+ elif any(wo_state in ('progress', 'done') for wo_state in production.workorder_ids.mapped('state')):
+ production.state = 'progress'
+ elif production.product_uom_id and not float_is_zero(production.qty_producing,
+ precision_rounding=production.product_uom_id.rounding):
+ production.state = 'progress'
+ elif any(not float_is_zero(move.quantity_done,
+ precision_rounding=move.product_uom.rounding or move.product_id.uom_id.rounding)
+ for move in production.move_raw_ids):
+ production.state = 'progress'
+
+ # 新添加的状态逻辑
+ if production.state == 'progress' and production.schedule_state == '已排':
+ production.state = 'pending_processing'
+ elif production.state == 'progress' and production.schedule_state == '已完成':
+ production.state = 'completed'
def action_check(self):
"""
@@ -47,6 +122,47 @@ 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 +250,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(','))
@@ -144,9 +261,6 @@ class MrpProduction(models.Model):
)
i += 1
for route in product_routing_workcenter:
- if i == 1 and route.routing_type == '获取CNC加工程序':
- workorders_values.append(
- self.env['mrp.workorder'].json_workorder_str('', production, route))
if route.is_repeat is True:
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(k, production, route))
@@ -339,10 +453,10 @@ class MrpProduction(models.Model):
for route in routingworkcenter:
- if route.routing_type == '后置三元质量检测':
- workorders_values.append(
- self.env['mrp.workorder'].json_workorder_str1(k, production, route)
- )
+ # if route.routing_type == '后置三元质量检测':
+ # workorders_values.append(
+ # self.env['mrp.workorder'].json_workorder_str1(k, production, route)
+ # )
if route.routing_type == 'CNC加工':
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str1(k, production, route))
@@ -364,12 +478,104 @@ class MrpProduction(models.Model):
for work in rec.workorder_ids:
work.sequence = current_sequence
current_sequence += 1
- if work.name == '获取CNC加工程序':
- work.button_start()
- work.fetchCNC()
+ # if work.name == '获取CNC加工程序':
+ # work.button_start()
+ # #work.fetchCNC()
+ # work.button_finish()
# 创建工单并进行排序
def _create_workorder(self):
self._create_workorder3()
self._reset_work_order_sequence()
return True
+
+ # 修改标记已完成方法
+ def button_mark_done1(self):
+ self._button_mark_done_sanity_checks()
+
+ if not self.env.context.get('button_mark_done_production_ids'):
+ self = self.with_context(button_mark_done_production_ids=self.ids)
+ res = self._pre_button_mark_done()
+ if res is not True:
+ return res
+
+ if self.env.context.get('mo_ids_to_backorder'):
+ productions_to_backorder = self.browse(self.env.context['mo_ids_to_backorder'])
+ productions_not_to_backorder = self - productions_to_backorder
+ else:
+ productions_not_to_backorder = self
+ productions_to_backorder = self.env['mrp.production']
+
+ backorders = productions_to_backorder and productions_to_backorder._split_productions()
+ backorders = backorders - productions_to_backorder
+
+ productions_not_to_backorder._post_inventory(cancel_backorder=True)
+ productions_to_backorder._post_inventory(cancel_backorder=True)
+
+ # if completed products make other confirmed/partially_available moves available, assign them
+ done_move_finished_ids = (
+ productions_to_backorder.move_finished_ids | productions_not_to_backorder.move_finished_ids).filtered(
+ lambda m: m.state == 'done')
+ done_move_finished_ids._trigger_assign()
+
+ # Moves without quantity done are not posted => set them as done instead of canceling. In
+ # case the user edits the MO later on and sets some consumed quantity on those, we do not
+ # want the move lines to be canceled.
+ (productions_not_to_backorder.move_raw_ids | productions_not_to_backorder.move_finished_ids).filtered(
+ lambda x: x.state not in ('done', 'cancel')).write({
+ 'state': 'done',
+ 'product_uom_qty': 0.0,
+ })
+
+ for production in self:
+ production.write({
+ 'date_finished': fields.Datetime.now(),
+ 'product_qty': production.qty_produced,
+ 'priority': '0',
+ 'is_locked': True,
+ 'state': 'done',
+ })
+
+ for workorder in self.workorder_ids.filtered(lambda w: w.state not in ('done', 'cancel')):
+ workorder.duration_expected = workorder._get_duration_expected()
+
+ if not backorders:
+ if self.env.context.get('from_workorder'):
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'mrp.production',
+ 'views': [[self.env.ref('mrp.mrp_production_form_view').id, 'form']],
+ 'res_id': self.id,
+ 'target': 'main',
+ }
+ if self.user_has_groups(
+ 'mrp.group_mrp_reception_report') and self.picking_type_id.auto_show_reception_report:
+ lines = self.move_finished_ids.filtered(lambda
+ m: m.product_id.type == 'product' and m.state != 'cancel' and m.quantity_done and not m.move_dest_ids)
+ if lines:
+ if any(mo.show_allocation for mo in self):
+ action = self.action_view_reception_report()
+ return action
+ return True
+ context = self.env.context.copy()
+ context = {k: v for k, v in context.items() if not k.startswith('default_')}
+ for k, v in context.items():
+ if k.startswith('skip_'):
+ context[k] = False
+ action = {
+ 'res_model': 'mrp.production',
+ 'type': 'ir.actions.act_window',
+ 'context': dict(context, mo_ids_to_backorder=None, button_mark_done_production_ids=None)
+ }
+ if len(backorders) == 1:
+ action.update({
+ 'view_mode': 'form',
+ 'res_id': backorders[0].id,
+ })
+ else:
+ action.update({
+ 'name': _("Backorder MO"),
+ 'domain': [('id', 'in', backorders.ids)],
+ 'view_mode': 'tree,form',
+ })
+ return action
diff --git a/sf_manufacturing/models/mrp_routing_workcenter.py b/sf_manufacturing/models/mrp_routing_workcenter.py
index 807dfbb5..8bb9733b 100644
--- a/sf_manufacturing/models/mrp_routing_workcenter.py
+++ b/sf_manufacturing/models/mrp_routing_workcenter.py
@@ -1,16 +1,17 @@
import logging
-from odoo import fields, models
+from odoo import fields, models, api
+from odoo.exceptions import UserError
class ResMrpRoutingWorkcenter(models.Model):
_inherit = 'mrp.routing.workcenter'
routing_type = fields.Selection([
- ('获取CNC加工程序', '获取CNC加工程序'),
- ('装夹', '装夹'),
- ('前置三元定位检测', '前置三元定位检测'),
+ # ('获取CNC加工程序', '获取CNC加工程序'),
+ ('装夹预调', '装夹预调'),
+ # ('前置三元定位检测', '前置三元定位检测'),
('CNC加工', 'CNC加工'),
- ('后置三元质量检测', '后置三元质量检测'),
+ # ('后置三元质量检测', '后置三元质量检测'),
('解除装夹', '解除装夹'),
('切割', '切割'),
('表面工艺', '表面工艺')
@@ -21,13 +22,17 @@ class ResMrpRoutingWorkcenter(models.Model):
bom_id = fields.Many2one('mrp.bom', required=False)
surface_technics_id = fields.Many2one('sf.production.process', string="表面工艺")
+ def generate_code(self):
+ return self.env['ir.sequence'].next_by_code('mrp.routing.workcenter')
+
+ code = fields.Char('编码', default=generate_code)
+
# 获得当前登陆者公司
def get_company_id(self):
self.company_id = self.env.user.company_id.id
company_id = fields.Many2one('res.company', compute="get_company_id", related=False)
-
# 排产的时候, 根据坯料的长宽高比对一下机床的最大加工尺寸.不符合就不要分配给这个加工中心(机床).
# 工单对应的工作中心,根据工序中的工作中心去匹配,
# 如果只配置了一个工作中心,则默认采用该工作中心;
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..e4db6346 100644
--- a/sf_manufacturing/models/mrp_workorder.py
+++ b/sf_manufacturing/models/mrp_workorder.py
@@ -31,11 +31,11 @@ class ResMrpWorkOrder(models.Model):
processing_panel = fields.Char('加工面')
sequence = fields.Integer(string='工序')
routing_type = fields.Selection([
- ('获取CNC加工程序', '获取CNC加工程序'),
- ('装夹', '装夹'),
- ('前置三元定位检测', '前置三元定位检测'),
+ # ('获取CNC加工程序', '获取CNC加工程序'),
+ ('装夹预调', '装夹预调'),
+ # ('前置三元定位检测', '前置三元定位检测'),
('CNC加工', 'CNC加工'),
- ('后置三元质量检测', '后置三元质量检测'),
+ # ('后置三元质量检测', '后置三元质量检测'),
('解除装夹', '解除装夹'),
('切割', '切割'), ('表面工艺', '表面工艺')
], string="工序类型")
@@ -122,22 +122,28 @@ class ResMrpWorkOrder(models.Model):
chuck_type_id = fields.Char(string="卡盘类型")
chuck_model_id = fields.Char(string="卡盘型号")
tray_serial_number = fields.Char(string="托盘序列号")
- tray_name = fields.Char(string="托盘名称")
+ tray_product_id = fields.Many2one('product.product', string="托盘名称")
tray_brand_id = fields.Many2one('sf.machine.brand', string="托盘品牌")
- tray_type_id = fields.Char(string="托盘类型")
- tray_model_id = fields.Char(string="托盘型号")
+ tray_type_id = fields.Many2one('sf.fixture.material', string="托盘类型")
+ tray_model_id = fields.Many2one('sf.fixture.model', string="托盘型号")
total_wight = fields.Float(string="总重量")
maximum_carrying_weight = fields.Char(string="最大承载重量[kg]")
maximum_clamping_force = fields.Char(string="最大夹持力[n]")
production_line = fields.Char(string="生产线")
preset_program_information = fields.Char(string="预调程序信息")
+ workpiece_delivery_ids = fields.One2many('sf.workpiece.delivery', 'workorder_id', '工件配送')
+ is_delivery = fields.Boolean('是否配送完成', default=False)
+ rfid_code = fields.Char('RFID')
@api.onchange('is_ok')
def _onchange_inspection_user_id(self):
"""
检测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):
@@ -192,30 +198,41 @@ class ResMrpWorkOrder(models.Model):
work = workorder.production_id.workorder_ids
work.compensation_value_x = eval(self.material_center_point)[0]
work.compensation_value_y = eval(self.material_center_point)[1]
+ workorder.button_finish()
except:
raise UserError("参数计算有误")
+ def button_workpiece_delivery(self):
+ if self.routing_type == '装夹预调':
+ for item in self.workpiece_delivery_ids:
+ if not item.feeder_station_start:
+ raise UserError('【工件配送】明细中请输入起点接驳站')
+ # if not item.workpiece_code:
+ # raise UserError('请对【同运工件】进行扫描')
+ else:
+ item.write({'task_delivery_time': fields.Datetime.now(), 'status': '待配送'})
+
# 拼接工单对象属性值
def json_workorder_str(self, k, production, route):
# 计算预计时长duration_expected
if route.routing_type == '切割':
duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
[('name', '=', '切割')]).time_cycle
- elif route.routing_type == '获取CNC加工程序':
+ # elif route.routing_type == '获取CNC加工程序':
+ # duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
+ # [('name', '=', '获取CNC加工程序')]).time_cycle
+ elif route.routing_type == '装夹预调':
duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
- [('name', '=', '获取CNC加工程序')]).time_cycle
- elif route.routing_type == '工件装夹':
- duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
- [('name', '=', '工件装夹')]).time_cycle
- elif route.routing_type == '前置三元定位检测':
- duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
- [('name', '=', '前置三元定位检测')]).time_cycle
+ [('name', '=', '装夹预调')]).time_cycle
+ # elif route.routing_type == '前置三元定位检测':
+ # duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
+ # [('name', '=', '前置三元定位检测')]).time_cycle
elif route.routing_type == 'CNC加工':
duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
[('name', '=', 'CNC加工')]).time_cycle
- elif route.routing_type == '后置三元质量检测':
- duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
- [('name', '=', '后置三元质量检测')]).time_cycle
+ # elif route.routing_type == '后置三元质量检测':
+ # duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
+ # [('name', '=', '后置三元质量检测')]).time_cycle
elif route.routing_type == '解除装夹':
duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
[('name', '=', '解除装夹')]).time_cycle
@@ -229,7 +246,7 @@ class ResMrpWorkOrder(models.Model):
'processing_panel': k,
'quality_point_ids': route.route_workcenter_id.quality_point_ids,
'routing_type': route.routing_type,
- 'work_state': '' if not route.routing_type == '获取CNC加工程序' else '待发起',
+ 'work_state': '待发起',
'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids,
route.routing_type,
production.product_id),
@@ -237,7 +254,9 @@ class ResMrpWorkOrder(models.Model):
'date_planned_finished': False,
'duration_expected': duration_expected,
'duration': 0,
-
+ 'workpiece_delivery_ids': False if not route.routing_type == '装夹预调' else self.env[
+ 'sf.workpiece.delivery'].create(
+ {'production_id': production.id})
}]
return workorders_values_str
@@ -447,7 +466,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')
@@ -492,7 +511,7 @@ class ResMrpWorkOrder(models.Model):
# 重写工单开始按钮方法
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
# 外协出库单,从“正在等待”变为“就绪”状态
if self.is_subcontract is True:
@@ -548,6 +567,9 @@ class ResMrpWorkOrder(models.Model):
raise UserError(_('请先完成上一步工单'))
def button_finish(self):
+ if self.routing_type == '装夹预调':
+ if not self.material_center_point and self.X_deviation_angle > 0:
+ raise UserError("请对前置三元检测定位参数进行计算定位")
if self.picking_out_id:
picking_out = self.env['stock.picking'].search([('id', '=', self.picking_out_id.id)])
if picking_out.workorder_out_id:
@@ -571,6 +593,15 @@ 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.button_mark_done1()
+ # self.production_id.state = 'done'
class CNCprocessing(models.Model):
@@ -581,6 +612,7 @@ class CNCprocessing(models.Model):
cnc_id = fields.Many2one('ir.attachment')
sequence_number = fields.Char('序号')
program_name = fields.Char('程序名')
+ functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型')
cutting_tool_name = fields.Char('刀具名称')
cutting_tool_no = fields.Char('刀号')
processing_type = fields.Char('加工类型')
@@ -592,6 +624,7 @@ class CNCprocessing(models.Model):
estimated_processing_time = fields.Char('预计加工时间')
remark = fields.Text('备注')
workorder_id = fields.Many2one('mrp.workorder', string="工单")
+ production_id = fields.Many2one('mrp.production', string="制造订单")
button_state = fields.Boolean(string='是否已经下发')
# mrs下发编程单创建CNC加工
@@ -601,6 +634,8 @@ class CNCprocessing(models.Model):
workorder = self.env['mrp.workorder'].search([('production_id.name', '=', ret['production_order_no']),
('processing_panel', '=', obj['processing_panel']),
('routing_type', '=', 'CNC加工')])
+ logging.info('workorder:%s' % workorder)
+ logging.info('obj:%s' % obj)
cnc_processing = self.env['sf.cnc.processing'].create({
'workorder_id': workorder.id,
'sequence_number': obj['sequence_number'],
@@ -616,19 +651,19 @@ class CNCprocessing(models.Model):
'estimated_processing_time': obj['estimated_processing_time'],
'remark': obj['remark']
})
- self.get_cnc_processing_file(ret['folder_name'], cnc_processing, workorder.processing_panel)
- cnc_workorder.state = 'done'
+ cnc_processing.get_cnc_processing_file(ret['folder_name'], cnc_processing, workorder.processing_panel)
+ # 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):
logging.info('folder_name:%s' % folder_name)
serverdir = os.path.join('/tmp', folder_name, 'return', processing_panel)
logging.info('serverdir:%s' % serverdir)
- for root, files in os.walk(serverdir):
+ for root, dirs, files in os.walk(serverdir):
for f in files:
logging.info('f:%s' % f)
if os.path.splitext(f)[1] == ".pdf":
@@ -663,6 +698,7 @@ class CNCprocessing(models.Model):
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), ftp_resconfig['ftp_user'],
ftp_resconfig['ftp_password'])
download_state = ftp.download_file_tree(remotepath, serverdir)
+ logging.info('download_state:%s' % download_state)
return download_state
# 将nc文件存到attach的datas里
@@ -703,51 +739,107 @@ class SfWorkOrderBarcodes(models.Model):
_name = "mrp.workorder"
_inherit = ["mrp.workorder", "barcodes.barcode_events_mixin"]
- # def on_barcode_scanned(self, barcode):
- # workorder = self.env['mrp.workorder'].browse(self.ids)
- # if "*" not in barcode:
- # if self.routing_type == '装夹':
- # tray_code = self.env['sf.tray'].search([('code', '=', barcode)])
- # self.tray_code = tray_code.code
- # self.tray_id = workorder.gettray_auto(barcode)
- # elif self.routing_type == '前置三元定位检测':
- # print('我是前置三元检测')
- # logging.info('我是前置三元检测')
- # elif self.routing_type == 'CNC加工':
- # if barcode == 'UP-ALL':
- # print("我是一键合并下发")
- # logging.info('我是一键合并下发')
- # self.up_merge_all()
- # else:
- # print('CNC加工')
- # # print(barcode)
- # # a = self.env['sf.tray'].search([('code', '=', barcode)])
- # # print(a)
- # # # workorder_obj = self.env['mrp.workorder'].search([('tray_code', '=', barcode)], limit=1)
- # # workorder_obj = self.env['mrp.workorder'].search([('tray_code', '=', barcode)])
- # # e = workorder_obj.id
- # # print(workorder_obj)
- # # action = {
- # # 'name': '工单',
- # # 'type': 'ir.actions.act_window',
- # # # 'view_type': 'form',
- # # 'view_mode': 'form',
- # # 'res_model': 'mrp.workorder',
- # # 'view_id': self.env.ref('mrp.mrp_production_workorder_form_view_inherit').id,
- # # # 'res_id': workorder_obj.id,
- # # 'res_id': 1023,
- # # 'target': 'current',
- # # # 'context': self.env.context,
- # # # 'flags': {'initial_mode': 'edit'},
- # # }
- # # return action
- #
- # elif self.routing_type == '后置三元质量检测':
- # print('后置三元检测')
- # elif self.routing_type == '解除装夹':
- # print("我是解除装夹")
- # else:
- # pass
- #
- # else:
- # self.pro_code_ok = workorder.pro_code_is_ok(barcode)
+ def on_barcode_scanned(self, barcode):
+ workorder = self.env['mrp.workorder'].browse(self.ids)
+ # workorder = self.env['mrp.workorder'].search(
+ # [('routing_type', '=', '装夹预调'), ('production_id', '=', self.production_id.id)])
+ if workorder:
+ if workorder.routing_type == '装夹预调':
+ stock_move_line = self.env['stock.move.line'].search([('lot_name', '=', barcode)])
+ if stock_move_line.product_id.categ_type == '夹具':
+ workorder.write({
+ 'tray_serial_number': stock_move_line.lot_name,
+ 'tray_product_id': stock_move_line.product_id.id,
+ 'tray_brand_id': stock_move_line.product_id.brand_id.id,
+ 'tray_type_id': stock_move_line.product_id.fixture_material_id.id,
+ 'tray_model_id': stock_move_line.product_id.fixture_model_id.id
+ })
+ workorder.button_start()
+ # return {
+ # 'type': 'ir.actions.act_window',
+ # 'res_model': 'mrp.workorder',
+ # 'view_mode': 'form',
+ # 'domain': [('id', 'in', workorder.id)],
+ # 'target': 'current'
+ # }
+ else:
+ embryo_stock_lot = self.env['stock.lot'].search([('name', '=', barcode)])
+ if embryo_stock_lot:
+ embryo_stock_move_line = self.env['stock.move.line'].search(
+ [('product_id', '=', embryo_stock_lot.product_id.id),
+ ('reference', '=', workorder.production_id.name),
+ ('lot_id', '=', embryo_stock_lot.id),
+ ('product_category_name', '=', '坯料')])
+ if embryo_stock_move_line:
+ bom_production = self.env['mrp.production'].search(
+ [('product_id', '=', embryo_stock_lot.product_id.id),
+ ('origin', '=', workorder.production_id.name)], limit=1, order='id asc')
+ workpiece_delivery = self.env['sf.workpiece.delivery'].search(
+ [('workorder_id', '=', workorder.id)], limit=1, order='id asc')
+ if workpiece_delivery:
+ embryo_workpiece_code = workpiece_delivery.workpiece_code
+ if bom_production:
+ if workpiece_delivery.workpiece_code and bom_production.name not in \
+ workpiece_delivery.workpiece_code:
+ embryo_workpiece_code = workpiece_delivery.workpiece_code + ',' + \
+ bom_production.name
+ if not workpiece_delivery.workpiece_code:
+ embryo_workpiece_code = bom_production.name
+ workpiece_delivery.write({'workpiece_code': embryo_workpiece_code})
+ else:
+ raise UserError('工件生产线不一致,请重新确认')
+
+
+class WorkPieceDelivery(models.Model):
+ _name = "sf.workpiece.delivery"
+ _description = '工件配送'
+
+ workorder_id = fields.Many2one('mrp.workorder', 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',
+ string='目的生产线', readonly=True,
+ store=True)
+ plan_start_processing_time = fields.Datetime('计划开始加工时间', readonly=True)
+ workpiece_code = fields.Char('同运工件编码')
+ feeder_station_start = fields.Char('起点接驳站')
+ feeder_station_destination = fields.Char('目的接驳站')
+ task_delivery_time = fields.Datetime('任务下发时间')
+ task_completion_time = fields.Datetime('任务完成时间')
+ delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration')
+ status = fields.Selection(
+ [('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态',
+ default='待下发')
+
+ # 工件配送
+ def button_delivery(self):
+ if self.status == '待下发':
+ return {
+ 'name': _('确认'),
+ 'type': 'ir.actions.act_window',
+ 'view_mode': 'form',
+ 'res_model': 'sf.workpiece.delivery.wizard',
+ 'target': 'new',
+ 'context': {
+ 'default_delivery_id': self.id,
+ }}
+ else:
+ raise UserError('状态为【待下发】的工件记录可进行配送')
+
+ # 配送至avg小车
+ def _delivery_avg(self):
+ self.write({'task_delivery_time': fields.Datetime.now(), 'status': '待配送'})
+
+ @api.depends('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')
+ def _compute_delivery_duration(self):
+ for obj in self:
+ if obj.task_delivery_time and obj.task_completion_time:
+ obj.delivery_duration = round(
+ (obj.task_completion_time - obj.task_delivery_time).total_seconds() / 60.0, 2)
+ else:
+ obj.delivery_duration = 0.0
diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py
index 3233e674..550ca7ad 100644
--- a/sf_manufacturing/models/product_template.py
+++ b/sf_manufacturing/models/product_template.py
@@ -62,7 +62,6 @@ class ResProductMo(models.Model):
tool_thickness = fields.Float('厚度(mm)')
tool_weight = fields.Float('重量(kg)')
tool_hardness = fields.Integer('硬度(hrc)')
-
coating_material = fields.Char('涂层材质')
# 整体式刀具特有字段
cutting_tool_total_length = fields.Float('总长度(mm)', digits=(6, 1))
@@ -97,8 +96,8 @@ class ResProductMo(models.Model):
handle_type_id = fields.Many2one('maintenance.equipment.image', '柄部类型', domain=[('type', '=', '柄部类型')])
cutting_direction_ids = fields.Many2many('maintenance.equipment.image', 'rel_cutting_product_template',
'走刀方向', domain=[('type', '=', '走刀方向')])
- suitable_coolant_ids = fields.Many2many('maintenance.equipment.image', 'rel_coolant_product_template',
- '适合冷却液', domain=[('type', '=', '冷却液')])
+ suitable_coolant_ids = fields.Many2many('maintenance.equipment.image', 'rel_coolants_product_template',
+ '适合冷却方式', domain=[('type', '=', '冷却方式')])
compaction_way_id = fields.Many2one('maintenance.equipment.image',
'压紧方式', domain=[('type', '=', '压紧方式')])
@@ -202,8 +201,6 @@ class ResProductMo(models.Model):
self.feed_per_tooth_ids = self.cutting_tool_model_id.feed_per_tooth_ids.filtered(
lambda r: int(r.blade_diameter) == int(self.specification_id.blade_diameter))
elif self.cutting_tool_type == '夹头':
- self.cutting_tool_clamping_length = self.specification_id.clamping_length
- self.cutting_tool_clamping_tolerance = self.specification_id.clamping_tolerance
self.cutting_tool_clamping_diameter_min = self.specification_id.min_clamping_diameter
self.cutting_tool_clamping_diameter_min = self.specification_id.max_clamping_diameter
self.cutting_tool_clamping_way = self.specification_id.clamping_mode
@@ -214,7 +211,7 @@ class ResProductMo(models.Model):
self.cutting_tool_jump_accuracy = self.specification_id.run_out_accuracy
self.cutting_tool_max_load_capacity = self.specification_id.max_load_capacity
self.cutting_tool_er_size_model = self.specification_id.er_size_model
- self.cutting_tool_handle_ids = self.cutting_tool_model_id.handle_ids
+ self.cutting_tool_handle_id = self.cutting_tool_model_id.handle_id.id
self.cooling_suit_type_ids = self.specification_id.cooling_jacket
elif self.cutting_tool_type == '刀片':
self.cutting_tool_total_length = self.specification_id.total_length
@@ -228,14 +225,12 @@ class ResProductMo(models.Model):
self.cutting_tool_inscribed_circle_tolerance = self.specification_id.inscribed_circle_tolerance
self.cutting_tool_install_aperture_diameter = self.specification_id.install_aperture_diameter
self.cutting_tool_chip_breaker_groove = self.specification_id.chip_breaker_groove
- # self.cutting_tool_cut_depth_max = self.specification_id.blade_blade_number
+ self.cutting_tool_chip_breaker_type_code = self.specification_id.chip_breaker_type_code
self.cutting_tool_blade_blade_number = self.specification_id.blade_blade_number
self.cutting_tool_blade_width = self.specification_id.blade_width
self.cutting_tool_rear_angle = self.specification_id.relief_angle
self.cutting_tool_main_included_angle = self.specification_id.main_included_angle
self.cutting_tool_top_angle = self.specification_id.top_angle
- self.cutting_tool_blade_tip_dip_angle = self.specification_id.blade_tip_dip_angle
- self.cutting_tool_side_cutting_edge_angle = self.specification_id.side_cutting_edge_angle
self.cutting_tool_pitch = self.specification_id.pitch
self.cutting_tool_bladed_teeth_model = self.specification_id.blade_teeth_model
self.cutting_tool_thickness_tolerance = self.specification_id.thickness_tolerance
@@ -257,13 +252,20 @@ class ResProductMo(models.Model):
self.cutting_tool_inscribed_circle_tolerance = self.specification_id.inscribed_circle_tolerance
self.cutting_tool_install_aperture_diameter = self.specification_id.install_aperture_diameter
self.cutting_tool_chip_breaker_groove = self.specification_id.chip_breaker_groove
- # self.cutting_tool_cut_depth_max = self.specification_id.blade_blade_number
+ self.cutting_tool_chip_breaker_type_code = self.specification_id.chip_breaker_type_code
self.cutting_tool_blade_blade_number = self.specification_id.blade_blade_number
self.cutting_tool_blade_width = self.specification_id.blade_width
self.cutting_tool_rear_angle = self.specification_id.relief_angle
self.cutting_tool_main_included_angle = self.specification_id.main_included_angle
self.cutting_tool_top_angle = self.specification_id.top_angle
- self.cutting_tool_blade_tip_dip_angle = self.specification_id.blade_tip_dip_angle
+ self.cutting_tool_screw = self.specification_id.screw
+ self.cutting_tool_wrench = self.specification_id.spanner
+ self.cutting_tool_blade_id = self.specification_id.blade_id.id
+ self.cutting_tool_is_cooling_hole = self.specification_id.is_cooling_hole
+ self.cutting_tool_locating_slot_code = self.specification_id.locating_slot_code
+ self.cutting_tool_install_blade_tip_num = self.specification_id.install_blade_tip_num
+ self.cutting_tool_installing_structure = self.specification_id.installing_structure
+ self.cutting_tool_cut_depth_max = self.specification_id.cut_depth_max
if self.cutting_tool_type == '刀盘':
self.cutting_tool_blade_length = self.specification_id.blade_length
self.cutting_tool_cutter_head_diameter = self.specification_id.cutter_head_diameter
@@ -272,17 +274,27 @@ class ResProductMo(models.Model):
self.cutting_tool_knife_head_height = self.specification_id.knife_head_height
self.cutting_tool_knife_head_width = self.specification_id.knife_head_width
self.cutting_tool_knife_head_length = self.specification_id.knife_head_length
+ self.cutting_tool_tool_shim = self.specification_id.tool_shim
+ self.cutting_tool_cotter_pin = self.specification_id.cotter_pin
+ self.cutting_tool_pressing_plate = self.specification_id.pressing_plate
elif self.cutting_tool_type == '刀柄':
self.cutting_tool_total_length = self.specification_id.total_length
- self.cutting_tool_standard_speed = self.specification_id.standard_rotate_speed
self.cutting_tool_speed_max = self.specification_id.max_rotate_speed
self.cutting_tool_change_time = self.specification_id.tool_changing_time
self.cutting_tool_total_length = self.specification_id.total_length
self.cutting_tool_clamping_diameter_max = self.specification_id.max_clamping_diameter
self.cutting_tool_clamping_diameter_min = self.specification_id.min_clamping_diameter
self.cutting_tool_flange_length = self.specification_id.flange_shank_length
- self.cutting_tool_shank_outer_diameter = self.specification_id.handle_external_diameter
- self.cutting_tool_shank_inner_diameter = self.specification_id.handle_inside_diameter
+ self.cutting_tool_flange_diameter = self.specification_id.flange_diameter
+ self.cutting_tool_fit_chuck_size = self.specification_id.fit_chuck_size
+ self.cutting_tool_dynamic_balance_class = self.specification_id.dynamic_balance_class
+ self.cutting_tool_is_high_speed_cutting = self.specification_id.is_quick_cutting
+ self.cutting_tool_is_safety_lock = self.specification_id.is_safe_lock
+ self.cutting_tool_fit_nut_model = self.specification_id.nut
+ self.cutting_tool_wrench = self.specification_id.spanner
+ self.cutting_tool_chuck_id = self.specification_id.chuck_id.id
+ self.cutting_tool_jump_accuracy = self.specification_id.diameter_slip_accuracy
+ self.cutting_tool_taper_shank_model = self.specification_id.taper_shank_model
self.suitable_machining_method_ids = [(6, 0, [])] if not \
self.cutting_tool_model_id.suitable_machining_method_ids \
else [(6, 0, self.cutting_tool_model_id.suitable_machining_method_ids.ids)]
@@ -350,12 +362,12 @@ class ResProductMo(models.Model):
raise ValidationError("请选择压紧方式")
if self.cutting_tool_type == '刀片':
if not self.suitable_coolant_ids:
- raise ValidationError("请选择适合冷却液")
+ raise ValidationError("请选择适合冷却方式")
elif self.cutting_tool_type == '整体式刀具':
if not self.handle_type_id:
raise ValidationError("请选择柄部类型")
if not self.suitable_coolant_ids:
- raise ValidationError("请选择适合冷却液")
+ raise ValidationError("请选择适合冷却方式")
if not self.suitable_machining_method_ids:
raise ValidationError("请选择适合加工方式")
if not self.blade_tip_characteristics_id:
@@ -369,11 +381,8 @@ class ResProductMo(models.Model):
cutting_tool_rear_angle = fields.Integer('后角(°)')
cutting_tool_main_included_angle = fields.Integer('主偏角(°)')
# 适用夹头型号可以多选
- cutting_tool_chuck_ids = fields.Many2many(
+ cutting_tool_chuck_id = fields.Many2one(
'sf.cutting_tool.standard.library',
- relation='product_cutting_tool_library_handle_chuck_rel',
- column1='model_id_1',
- column2='model_id_2',
domain="[('cutting_tool_type', '=', '夹头')]",
string='适用夹头型号')
# 刀片参数
@@ -384,6 +393,7 @@ class ResProductMo(models.Model):
cutting_tool_install_aperture_diameter = fields.Float('安装孔直径(mm)')
cutting_tool_chip_breaker_groove = fields.Selection([('无', '无'), ('单面', '单面'), ('双面', '双面')],
string='有无断屑槽')
+ cutting_tool_chip_breaker_type_code = fields.Char('断屑槽型代号')
cutting_tool_bladed_teeth_model = fields.Selection(
[('无', '无'), ('V牙型', 'V牙型'), ('米制全牙型', '米制全牙型'), ('美制全牙型', '美制全牙型'),
('惠氏全牙型', '惠氏全牙型'), ('BSPT全牙型', 'BSPT全牙型'), ('NPT全牙型', 'NPT全牙型'),
@@ -395,8 +405,6 @@ class ResProductMo(models.Model):
('7', '7'), ('8', '8'), ('9', '9'), ('10', '10')],
string='刀片的刃数(个)')
- cutting_tool_blade_tip_dip_angle = fields.Integer('刀尖倾角(°)')
- cutting_tool_side_cutting_edge_angle = fields.Integer('侧切削角(°)')
cutting_tool_thread_model = fields.Selection([('无', '无'), ('外螺纹', '外螺纹'), ('内螺纹', '内螺纹')],
string='螺纹类型')
cutting_tool_thread_num = fields.Float('每英寸螺纹数(tpi)')
@@ -429,13 +437,10 @@ class ResProductMo(models.Model):
cutting_tool_blade_diameter = fields.Float('刃径/刃部直径(mm)')
cutting_tool_cutter_arbor_diameter = fields.Float('刀杆直径(mm)')
cutting_tool_min_machining_aperture = fields.Integer('最小加工孔径(mm)')
- cutting_tool_install_blade_tip_num = fields.Integer('可装刀片数/齿数(个)', size=20)
+ cutting_tool_install_blade_tip_num = fields.Integer('可装刀片数/齿数(个)')
cutting_tool_installing_structure = fields.Char('安装结构', size=20)
- cutting_tool_blade_ids = fields.Many2many(
+ cutting_tool_blade_id = fields.Many2one(
'sf.cutting_tool.standard.library',
- relation='product_cutting_tool_library_pad_blade_rel',
- column1='model_id_1',
- column2='model_id_2',
domain="[('cutting_tool_type', '=', '刀片')]",
string='适用刀片型号' # 使用空列表作为默认值
)
@@ -451,24 +456,22 @@ class ResProductMo(models.Model):
cutting_tool_interface_diameter = fields.Float('接口直径(mm)')
# 刀柄参数
- cutting_tool_shank_outer_diameter = fields.Float('柄部外径(mm)')
- cutting_tool_shank_inner_diameter = fields.Float('柄部内径(mm)')
- cutting_tool_clamping_length = fields.Float('夹持长度(mm)')
- cutting_tool_clamping_tolerance = fields.Float('夹持公差(mm)')
cutting_tool_clamping_diameter_max = fields.Float('最大夹持直径')
cutting_tool_clamping_diameter_min = fields.Float('最小夹持直径')
cutting_tool_flange_length = fields.Float('法兰柄长(mm)')
cutting_tool_flange_diameter = fields.Float('法兰直径(mm)')
- cutting_tool_is_rough_finish = fields.Boolean('可粗加工', default=False)
- cutting_tool_is_finish = fields.Boolean('可精加工', default=False)
- cutting_tool_is_drill_hole = fields.Boolean('可钻孔', default=False)
cutting_tool_is_safety_lock = fields.Boolean('有无安全锁', default=False)
cutting_tool_is_high_speed_cutting = fields.Boolean('可高速切削', default=False)
cutting_tool_change_time = fields.Integer('换刀时间(s)')
cutting_tool_clamping_way = fields.Char('夹持方式')
+ cutting_tool_fit_chuck_size = fields.Char('适配夹头尺寸')
+ cutting_tool_taper_shank_model = fields.Char('锥柄型号')
cutting_tool_standard_speed = fields.Integer('标准转速(n/min)')
cutting_tool_speed_max = fields.Integer('最大转速(n/min)')
cutting_tool_cooling_type = fields.Char('冷却类型')
+ cutting_tool_dynamic_balance_class = fields.Char('动平衡等级')
+ cutting_tool_fit_nut_model = fields.Char('适用锁紧螺母型号')
+
# 夹头参数
cutting_tool_taper = fields.Integer('锥度(°)')
cutting_tool_top_diameter = fields.Float('顶部直径')
@@ -476,38 +479,22 @@ class ResProductMo(models.Model):
cutting_tool_inner_diameter = fields.Float('内径(mm)')
cooling_suit_type_ids = fields.Char('适用冷却套型号')
cutting_tool_max_load_capacity = fields.Float('最大负载能力(kg)')
- cutting_tool_er_size_model = fields.Char('ER尺寸型号')
- cutting_tool_handle_ids = fields.Many2many(
+ cutting_tool_er_size_model = fields.Char('尺寸型号')
+ # cutting_tool_handle_ids = fields.Many2many(
+ # 'sf.cutting_tool.standard.library',
+ # relation='product_cutting_tool_library_chuck_handle_rel',
+ # column1='model_id_1',
+ # column2='model_id_2',
+ # domain="[('cutting_tool_type', '=', '刀柄')]",
+ # string='适用刀柄型号'
+ # )
+
+ cutting_tool_handle_id = fields.Many2one(
'sf.cutting_tool.standard.library',
- relation='product_cutting_tool_library_chuck_handle_rel',
- column1='model_id_1',
- column2='model_id_2',
domain="[('cutting_tool_type', '=', '刀柄')]",
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='未注册')
@@ -533,48 +520,12 @@ class ResProductMo(models.Model):
if self.tool_thickness > 1000000:
raise ValidationError("厚度不能超过1000000")
- @api.constrains('fixture_clamp_workpiece_length_max')
- def _check_fixture_clamp_workpiece_length_max_size(self):
- if self.fixture_clamp_workpiece_length_max > 1000000:
- raise ValidationError("夹持工件长度MAX不能超过1000000")
-
- @api.constrains('fixture_clamp_workpiece_width_max')
- def _check_fixture_clamp_workpiece_width_max_size(self):
- if self.fixture_clamp_workpiece_width_max > 1000000:
- raise ValidationError("夹持工件宽度MAX不能超过1000000")
-
- @api.constrains('fixture_clamp_workpiece_height_max')
- def _check_fixture_clamp_workpiece_height_max_size(self):
- if self.fixture_clamp_workpiece_height_max > 1000000:
- raise ValidationError("夹持工件高度MAX不能超过1000000")
-
- @api.constrains('fixture_maximum_clamping_force')
- def _check_fixture_maximum_clamping_force_size(self):
- if self.fixture_maximum_clamping_force > 100000000:
- raise ValidationError("最大夹持力不能超过100000000")
-
- @api.constrains('fixture_through_hole_size')
- def _check_fixture_through_hole_size_size(self):
- if self.fixture_through_hole_size > 1000000:
- raise ValidationError("过孔大小不能超过1000000")
-
- @api.constrains('fixture_screw_size')
- def _check_fixture_through_hole_size_size(self):
- if self.fixture_screw_size > 1000000:
- raise ValidationError("螺牙大小不能超过1000000")
-
def _json_apply_machine_tool_type_item_code(self, item):
code_arr = []
for i in item.product_id.fixture_apply_machine_tool_type_ids:
code_arr.append(i.code)
return code_arr
- def _json_chuck_item_code(self, item):
- code_arr = []
- for i in item.product_id.cutting_tool_chuck_ids:
- code_arr.append(i.code)
- return code_arr
-
def _json_cutter_bar_item_code(self, item):
code_arr = []
for i in item.product_id.cutting_tool_cutter_bar_ids:
@@ -587,18 +538,6 @@ class ResProductMo(models.Model):
code_arr.append(i.code)
return code_arr
- def _json_blade_item_code(self, item):
- code_arr = []
- for i in item.product_id.cutting_tool_blade_ids:
- code_arr.append(i.code)
- return code_arr
-
- def _json_handle_item_code(self, item):
- code_arr = []
- for i in item.product_id.cutting_tool_handle_ids:
- code_arr.append(i.code)
- return code_arr
-
def _get_ids(self, param):
type_ids = []
if not param:
@@ -614,42 +553,6 @@ class ResProductMo(models.Model):
self.detailed_type = 'product'
self.sale_ok = False
- @api.onchange('fixture_material_id')
- def _onchange_fixture_material_id(self):
- for item in self:
- if item.fixture_material_id.id != item.fixture_model_id.fixture_material_id.id:
- item.fixture_model_id = False
-
- @api.onchange('fixture_model_id')
- def _onchange_fixture_model_id(self):
- for item in self:
- if self.fixture_material_type in ['气动夹具', '转接板(锁板)夹具', '磁吸夹具', '虎钳夹具', '零点卡盘']:
- item.brand_id = item.fixture_model_id.brand_id.id
- item.fixture_multi_mounting_type_id = item.fixture_model_id.multi_mounting_type_id.id
- item.fixture_model_file = item.fixture_model_id.model_file
- item.tool_length = item.fixture_model_id.length
- item.tool_width = item.fixture_model_id.width
- item.tool_height = item.fixture_model_id.height
- item.tool_weight = item.fixture_model_id.weight
- item.materials_type_id = item.fixture_model_id.materials_model_id.id
- item.fixture_maximum_carrying_weight = item.fixture_model_id.maximum_carrying_weight
- item.fixture_maximum_clamping_force = item.fixture_model_id.maximum_clamping_force
- if self.fixture_material_type in ['零点卡盘', '转接板(锁板)夹具']:
- item.fixture_clamping_way = item.fixture_model_id.clamping_way
- item.fixture_port_type = item.fixture_model_id.port_type
- if self.fixture_material_type in ['气动夹具', '转接板(锁板)夹具', '磁吸夹具']:
- item.fixture_driving_way = item.fixture_model_id.driving_way
- if self.fixture_material_type in ['气动夹具', '磁吸夹具', '虎钳夹具', '零点卡盘']:
- item.fixture_through_hole_size = item.fixture_model_id.through_hole_size
- item.fixture_screw_size = item.fixture_model_id.screw_size
- if self.fixture_material_type in ['气动夹具', '转接板(锁板)夹具', '磁吸夹具', '虎钳夹具']:
- item.fixture_clamp_workpiece_length_max = item.fixture_model_id.clamp_workpiece_length_max
- item.fixture_clamp_workpiece_width_max = item.fixture_model_id.clamp_workpiece_width_max
- item.fixture_clamp_workpiece_height_max = item.fixture_model_id.clamp_workpiece_height_max
- item.fixture_clamp_workpiece_diameter_max = item.fixture_model_id.clamp_workpiece_diameter_max
- item.fixture_apply_machine_tool_type_ids = self._get_ids(
- item.fixture_model_id.apply_machine_tool_type_ids)
-
def _get_volume_uom_id_from_ir_config_parameter(self):
product_length_in_feet_param = self.env['ir.config_parameter'].sudo().get_param('product.volume_in_cubic_feet')
if product_length_in_feet_param == '1':
@@ -826,6 +729,121 @@ 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="夹具物料")
+ fixture_material_type = fields.Char(string="夹具物料类型", related='fixture_material_id.name')
+ multi_mounting_type_id = fields.Many2one('sf.multi_mounting.type', string="联装类型")
+ model_file = fields.Binary(string="3D模型图")
+
+ # 夹具物料基本参数
+ 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 = '设备'
@@ -852,6 +870,11 @@ class SfMaintenanceEquipmentTool(models.Model):
_description = '机床刀位'
equipment_id = fields.Many2one('maintenance.equipment', string='设备')
+
+ code = fields.Char('机床刀位号')
+ name = fields.Char('刀位号', compute='_compute_name')
+
+ # 待删除字段
product_template_id = fields.Many2one('product.template', string='功能刀具名称',
domain="[('categ_type', '=', '刀具')]")
image_1920 = fields.Binary('图片', related='product_template_id.image_1920')
@@ -864,9 +887,6 @@ class SfMaintenanceEquipmentTool(models.Model):
life_value_max = fields.Char('最大寿命值')
alarm_value = fields.Char('报警值')
used_value = fields.Char('已使用值')
- code = fields.Char('机床刀位号')
-
- name = fields.Char('', compute='_compute_name')
@api.depends('code')
def _compute_name(self):
diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py
index 4f2c43f3..5cb51953 100644
--- a/sf_manufacturing/models/stock.py
+++ b/sf_manufacturing/models/stock.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import base64
+import qrcode
from collections import defaultdict, namedtuple
import logging
import json
@@ -12,6 +13,7 @@ from odoo.tools import float_compare
from odoo.addons.stock.models.stock_rule import ProcurementException
from odoo.addons.sf_base.commons.common import Common
from odoo.exceptions import UserError
+from io import BytesIO
class StockRule(models.Model):
@@ -202,8 +204,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,
@@ -265,6 +266,60 @@ class ProductionLot(models.Model):
return "%s-%s-%03d" % (product.cutting_tool_model_id.code, now, 1)
return "%s-%03d" % (product.name, 1)
+ qr_code_image = fields.Binary(string='二维码', compute='_generate_qr_code')
+
+ @api.depends('name')
+ def _generate_qr_code(self):
+ for record in self:
+ # Generate QR code
+ qr = qrcode.QRCode(
+ version=1,
+ error_correction=qrcode.constants.ERROR_CORRECT_L,
+ box_size=10,
+ border=4,
+ )
+ qr.add_data(record.name)
+ qr.make(fit=True)
+ qr_image = qr.make_image(fill_color="black", back_color="white")
+
+ # Encode the image data in base64
+ image_stream = BytesIO()
+ qr_image.save(image_stream, format="PNG")
+ encoded_image = base64.b64encode(image_stream.getvalue())
+
+ record.qr_code_image = encoded_image
+
+ def print_qr_code(self):
+ self.ensure_one() # 确保这个方法只为一个记录调用
+ # if not self.lot_id:
+ # raise UserError("没有找到序列号。")
+ # 假设_lot_qr_code方法已经生成了二维码并保存在字段中
+ qr_code_data = self.qr_code_image
+ if not qr_code_data:
+ raise UserError("没有找到二维码数据。")
+
+ # 生成下载链接或直接触发下载
+ # 此处的实现依赖于你的具体需求,以下是触发下载的一种示例
+ attachment = self.env['ir.attachment'].sudo().create({
+ 'datas': self.qr_code_image,
+ 'type': 'binary',
+ 'description': '二维码图片',
+ 'name': self.name + '.png',
+ # 'res_id': invoice.id,
+ # 'res_model': 'stock.picking',
+ 'public': True,
+ 'mimetype': 'application/x-png',
+ # 'model_name': 'stock.picking',
+ })
+ # 返回附件的下载链接
+ download_url = '/web/content/%s?download=true' % attachment.id
+ base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
+ return {
+ 'type': 'ir.actions.act_url',
+ 'url': str(base_url) + download_url,
+ 'target': 'self',
+ }
+
class StockPicking(models.Model):
_inherit = 'stock.picking'
@@ -360,7 +415,6 @@ class ReStockMove(models.Model):
materiel_height = fields.Float(string='物料高度', digits=(16, 4))
def _get_new_picking_values_Res(self, item, sorted_workorders, rescode):
- logging.info('new_picking-rescode: %s' % rescode)
return {
'name': self.env['stock.picking']._get_name_Res(rescode),
'origin': item.name,
@@ -374,167 +428,21 @@ class ReStockMove(models.Model):
'state': 'confirmed',
}
- # 将采购到的夹具注册到Cloud
- def _register_fixture(self):
- create_url = '/api/factory_fixture_material/create'
- config = self.env['res.config.settings'].get_values()
- headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
- strurl = config['sf_url'] + create_url
- for item in self:
- val = {
- 'token': config['token'],
- 'name': item.product_id.name,
- 'brand_code': self.env['sf.machine.brand'].search([('id', '=', item.product_id.brand_id.id)]).code,
- 'fixture_material_code': self.env['sf.fixture.material'].search(
- [('id', '=', item.product_id.fixture_material_id.id)]).code,
- 'fixture_multi_mounting_type_code': self.env['sf.multi_mounting.type'].search(
- [('id', '=', item.product_id.fixture_multi_mounting_type_id.id)]).code,
- 'fixture_materials_type_code': self.env['sf.materials.model'].search(
- [('id', '=', item.product_id.materials_type_id.id)]).materials_no,
- 'fixture_clamping_way': item.product_id.fixture_clamping_way,
- 'fixture_port_type': item.product_id.fixture_port_type,
- 'fixture_length': item.product_id.tool_length,
- 'fixture_width': item.product_id.tool_width,
- 'fixture_height': item.product_id.tool_height,
- 'fixture_weight': item.product_id.tool_weight,
- 'fixture_amount': int(item.quantity_done),
- 'fixture_model_file': '' if not item.product_id.fixture_model_file else base64.b64encode(
- item.product_id.fixture_model_file).decode(
- 'utf-8'),
- 'fixture_clamp_workpiece_length_max': item.product_id.fixture_clamp_workpiece_length_max,
- 'fixture_clamp_workpiece_width_max': item.product_id.fixture_clamp_workpiece_width_max,
- 'fixture_clamp_workpiece_height_max': item.product_id.fixture_clamp_workpiece_height_max,
- 'fixture_clamp_workpiece_diameter_max': item.product_id.fixture_clamp_workpiece_diameter_max,
- 'fixture_maximum_carrying_weight': item.product_id.fixture_maximum_carrying_weight,
- 'fixture_maximum_clamping_force': item.product_id.fixture_maximum_clamping_force,
- 'fixture_driving_way': '' if not item.product_id.fixture_driving_way
- else item.product_id.fixture_driving_way,
- 'fixture_apply_machine_tool_type_codes': self.env[
- 'product.template']._json_apply_machine_tool_type_item_code(item),
- 'fixture_through_hole_size': item.product_id.fixture_through_hole_size,
- 'fixture_screw_size': item.product_id.fixture_screw_size,
- }
- try:
- if item.product_id.industry_code:
- val['industry_code'] = item.product_id.industry_code
- ret = requests.post(strurl, json={}, data=val, headers=headers)
- ret = ret.json()
- if ret['status'] == 200:
- if not item.product_id.industry_code:
- item.product_id.write({'register_state': '已注册', 'industry_code': ret['industry_code']})
- else:
- item.product_id.write({'register_state': '已注册'})
- else:
- item.product_id.write({'register_state': '注册失败'})
- except Exception as e:
- raise UserError("注册夹具到云端失败,请联系管理员!")
-
- # 将采购到的刀具注册到Cloud
- def _register_cutting_tool(self):
- create_url = '/api/factory_cutting_tool_material/create'
- config = self.env['res.config.settings'].get_values()
- headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
- strurl = config['sf_url'] + create_url
- for item in self:
- val = {
- 'token': config['token'],
- 'name': item.product_id.name,
- 'brand_code': self.env['sf.machine.brand'].search([('id', '=', item.product_id.brand_id.id)]).code,
- 'cutting_tool_material_code': self.env['sf.cutting.tool.material'].search(
- [('id', '=', item.product_id.cutting_tool_material_id.id)]).code,
- 'cutting_tool_type_code': self.env['sf.cutting.tool.type'].search(
- [('id', '=', item.product_id.cutting_tool_type_id.id)]).code,
- 'material_model_code': self.env['sf.materials.model'].search(
- [('id', '=', item.product_id.materials_type_id.id)]).materials_no,
- 'tool_length': item.product_id.tool_length,
- 'tool_width': item.product_id.tool_width,
- 'tool_height': item.product_id.tool_height,
- 'tool_thickness': item.product_id.tool_thickness,
- 'tool_weight': item.product_id.tool_weight,
- 'tool_hardness': item.product_id.tool_hardness,
- 'coating_material': item.product_id.coating_material,
- 'amount': int(item.quantity_done),
- # 'model_file': '' if not item.product_id.fixture_model_file else base64.b64encode(
- # item.product_id.fixture_model_file).decode(
- # 'utf-8'),
- 'total_length': item.product_id.cutting_tool_total_length,
- 'shank_length': item.product_id.cutting_tool_shank_length,
- 'blade_length': item.product_id.cutting_tool_blade_length,
- 'neck_length': item.product_id.cutting_tool_neck_length,
- 'neck_diameter': item.product_id.cutting_tool_neck_diameter,
- 'shank_diameter': item.product_id.cutting_tool_shank_diameter,
- 'blade_tip_diameter': item.product_id.cutting_tool_blade_tip_diameter,
- 'blade_tip_taper': item.product_id.cutting_tool_blade_tip_taper,
- 'blade_helix_angle': item.product_id.cutting_tool_blade_helix_angle,
- 'blade_type': item.product_id.cutting_tool_blade_type,
- 'coarse_medium_fine': '' if item.product_id.cutting_tool_coarse_medium_fine is False
- else item.product_id.cutting_tool_coarse_medium_fine,
- 'run_out_accuracy_max': item.product_id.cutting_tool_run_out_accuracy_max,
- 'run_out_accuracy_min': item.product_id.cutting_tool_run_out_accuracy_min,
- 'head_diameter': item.product_id.cutting_tool_head_diameter,
- 'diameter': item.product_id.cutting_tool_diameter,
- 'blade_number': '' if item.product_id.cutting_tool_blade_number is False
- else item.product_id.cutting_tool_blade_number,
- 'front_angle': item.product_id.cutting_tool_front_angle,
- 'rear_angle': item.product_id.cutting_tool_rear_angle,
- 'main_included_angle': item.product_id.cutting_tool_main_included_angle,
- 'chuck_codes': self.env['product.template']._json_chuck_item_code(item),
- 'cutter_bar_codes': self.env['product.template']._json_cutter_bar_item_code(item),
- 'cutter_pad_codes': self.env['product.template']._json_cutter_pad_item_code(item),
- 'blade_codes': self.env['product.template']._json_blade_item_code(item),
- 'handle_codes': self.env['product.template']._json_handle_item_code(item),
- 'nut': item.product_id.cutting_tool_nut,
- 'top_angle': item.product_id.cutting_tool_top_angle,
- 'jump_accuracy': item.product_id.cutting_tool_jump_accuracy,
- 'working_hardness': item.product_id.cutting_tool_working_hardness,
- 'blade_diameter': item.product_id.cutting_tool_blade_diameter,
- 'wrench': item.product_id.cutting_tool_wrench,
- 'accuracy_level': item.product_id.cutting_tool_accuracy_level,
- 'clamping_way': item.product_id.cutting_tool_clamping_way,
- 'clamping_length': item.product_id.cutting_tool_clamping_length,
- 'clamping_tolerance': item.product_id.cutting_tool_clamping_tolerance,
- 'diameter_max': item.product_id.cutting_tool_diameter_max,
- 'clamping_diameter_min': item.product_id.cutting_tool_clamping_diameter_min,
- 'clamping_diameter_max': item.product_id.cutting_tool_clamping_diameter_max,
- 'detection_accuracy_max': item.product_id.cutting_tool_detection_accuracy_max,
- 'detection_accuracy_min': item.product_id.cutting_tool_detection_accuracy_min,
- 'is_rough_finish': item.product_id.cutting_tool_is_rough_finish,
- 'is_finish': item.product_id.cutting_tool_is_finish,
- 'is_drill_hole': item.product_id.cutting_tool_is_drill_hole,
- 'is_safety_lock': item.product_id.cutting_tool_is_safety_lock,
- 'is_high_speed_cutting': item.product_id.cutting_tool_is_high_speed_cutting,
- 'dynamic_balance_class': item.product_id.cutting_tool_dynamic_balance_class,
- 'change_time': item.product_id.cutting_tool_change_time,
- 'standard_speed': item.product_id.cutting_tool_standard_speed,
- 'speed_max': item.product_id.cutting_tool_speed_max,
- 'cooling_type': item.product_id.cutting_tool_cooling_type,
- 'body_accuracy': item.product_id.cutting_tool_body_accuracy,
- 'apply_lock_nut_model': item.product_id.apply_lock_nut_model,
- 'apply_lock_wrench_model': item.product_id.apply_lock_wrench_model,
- 'tool_taper': item.product_id.cutting_tool_taper,
- 'flange_length': item.product_id.cutting_tool_flange_length,
- 'flange_diameter': item.product_id.cutting_tool_flange_diameter,
- 'outer_diameter': item.product_id.cutting_tool_outer_diameter,
- 'inner_diameter': item.product_id.cutting_tool_inner_diameter,
- 'cooling_suit_type_ids': item.product_id.cooling_suit_type_ids,
- 'er_size_model': item.product_id.cutting_tool_er_size_model,
- 'image': '' if not item.product_id.image_1920 else
- base64.b64encode(item.product_id.image_1920).decode('utf-8'),
- }
- try:
- if item.product_id.industry_code:
- val['industry_code'] = item.product_id.industry_code
- ret = requests.post(strurl, json={}, data=val, headers=headers)
- ret = ret.json()
- if ret['status'] == 200:
- if not item.product_id.industry_code:
- item.product_id.write({'register_state': '已注册', 'industry_code': ret['industry_code']})
- else:
- item.product_id.write({'register_state': '已注册'})
- else:
- item.product_id.write({'register_state': '注册失败'})
- except Exception as e:
- raise UserError("注册刀具到云端失败,请联系管理员!")
+ def print_serial_numbers(self):
+ if not self.next_serial:
+ raise UserError(_("请先分配序列号再进行打印"))
+ label_data = []
+ for item in self.move_line_ids:
+ label_data.append({
+ 'item_id': item.id,
+ })
+ if label_data:
+ report_template = self.env.ref('stock.label_package_template')
+ res = report_template.report_action(label_data)
+ res['id'] = report_template.id
+ return res
+ else:
+ raise UserError(_("没有可打印的标签数据"))
class ReStockQuant(models.Model):
diff --git a/sf_manufacturing/security/ir.model.access.csv b/sf_manufacturing/security/ir.model.access.csv
index 313c4567..fb218c88 100644
--- a/sf_manufacturing/security/ir.model.access.csv
+++ b/sf_manufacturing/security/ir.model.access.csv
@@ -3,13 +3,16 @@ access_sf_cnc_processing,sf_cnc_processing,model_sf_cnc_processing,sf_base.group
access_sf_cnc_processing_manager,sf_cnc_processing,model_sf_cnc_processing,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_model_type,sf_model_type,model_sf_model_type,sf_base.group_sf_mrp_user,1,0,0,0
access_sf_model_type_manager,sf_model_type,model_sf_model_type,sf_base.group_sf_mrp_manager,1,1,1,0
+access_sf_model_type_group_sale_director,sf_model_type_group_sale_director,model_sf_model_type,sf_base.group_sale_director,1,0,0,0
+access_sf_model_type_group_purchase_director,sf_model_type_group_purchase_director,model_sf_model_type,sf_base.group_purchase_director,1,0,0,0
+access_sf_model_type_group_plan_director,sf_model_type_group_plan_director,model_sf_model_type,sf_base.group_plan_director,1,0,0,0
access_sf_product_model_type_routing_sort,sf_product_model_type_routing_sort,model_sf_product_model_type_routing_sort,sf_base.group_sf_mrp_user,1,0,0,0
access_sf_product_model_type_routing_sort_manager,sf_product_model_type_routing_sort,model_sf_product_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_embryo_model_type_routing_sort,sf_embryo_model_type_routing_sort,model_sf_embryo_model_type_routing_sort,sf_base.group_sf_mrp_user,1,0,0,0
-access_sf_embryo_model_type_routing_sort_manager,sf_embryo_model_type_routing_sort,model_sf_embryo_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,1
+access_sf_embryo_model_type_routing_sort_manager,sf_embryo_model_type_routing_sort,model_sf_embryo_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_surface_technics_model_type_routing_sort,sf_surface_technics_model_type_routing_sort,model_sf_surface_technics_model_type_routing_sort,sf_base.group_sf_mrp_user,1,0,0,0
access_sf_surface_technics_model_type_routing_sort_manager,sf_surface_technics_model_type_routing_sort,model_sf_surface_technics_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,0
-access_sf_production_line,sf.production.line,model_sf_production_line,sf_base.group_sf_mrp_user,1,0,0,0
+access_sf_production_line,sf.production.line,model_sf_production_line,sf_base.group_sf_mrp_user,1,1,1,0
access_sf_production_line_manager,sf.production.line,model_sf_production_line,sf_base.group_sf_mrp_manager,1,1,1,0
access_maintenance_equipment_tool,maintenance_equipment_tool,model_maintenance_equipment_tool,sf_base.group_sf_mrp_user,1,0,0,0
access_maintenance_equipment_tool_manager,maintenance_equipment_tool,model_maintenance_equipment_tool,sf_base.group_sf_mrp_manager,1,1,1,0
@@ -22,7 +25,12 @@ access_mrp_workcenter,mrp_workcenter,model_mrp_workcenter,sf_base.group_sf_mrp_u
access_mrp_workcenter_manager,mrp_workcenter,model_mrp_workcenter,sf_base.group_sf_mrp_manager,1,1,1,0
access_mrp_workcenter_productivity,mrp_workcenter_productivity,model_mrp_workcenter_productivity,sf_base.group_sf_mrp_user,1,0,0,0
access_mrp_workcenter_productivity_manager,mrp_workcenter_productivity,model_mrp_workcenter_productivity,sf_base.group_sf_mrp_manager,1,1,1,0
+access_sf_workpiece_delivery_group_sf_order_user,sf_workpiece_delivery_group_sf_order_user,model_sf_workpiece_delivery,sf_base.group_sf_order_user,1,1,0,0
+access_sf_workpiece_delivery_group_sf_equipment_user,sf_workpiece_delivery_group_sf_equipment_user,model_sf_workpiece_delivery,sf_base.group_sf_equipment_user,1,1,0,0
+access_sf_workpiece_delivery_manager,sf_workpiece_delivery,model_sf_workpiece_delivery,sf_base.group_sf_mrp_manager,1,1,0,0
+access_sf_workpiece_delivery_admin,sf_workpiece_delivery_admin,model_sf_workpiece_delivery,base.group_system,1,1,1,0
+access_sf_workpiece_delivery_wizard_group_sf_order_user,sf_workpiece_delivery_wizard_group_sf_order_user,model_sf_workpiece_delivery_wizard,sf_base.group_sf_order_user,1,1,1,0
access_mrp_workcenter_productivity_loss_manager,mrp.workcenter.productivity.loss,mrp.model_mrp_workcenter_productivity_loss,sf_base.group_sf_mrp_user,1,1,1,0
access_mrp_workcenter_productivity_loss,mrp.workcenter.productivity.loss,mrp.model_mrp_workcenter_productivity_loss,sf_base.group_sf_mrp_user,1,0,0,0
access_mrp_workcenter_productivity_loss_type,mrp.workcenter.productivity.loss.type,mrp.model_mrp_workcenter_productivity_loss_type,sf_base.group_sf_mrp_user,1,0,0,0
@@ -37,12 +45,16 @@ access_mrp_workcenter_manager,mrp.workcenter.manager,mrp.model_mrp_workcenter,sf
access_mrp_routing_workcenter_manager,mrp.routing.workcenter.manager,mrp.model_mrp_routing_workcenter,sf_base.group_sf_mrp_user,1,1,1,0
access_mrp_bom_manager,mrp.bom.manager,mrp.model_mrp_bom,sf_base.group_sf_mrp_user,1,1,1,0
access_mrp_bom_line_manager,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_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_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,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_product_product_user,product.product user,product.model_product_product,sf_base.group_sf_mrp_user,1,0,0,0
access_product_template_user,product.template user,product.model_product_template,sf_base.group_sf_mrp_user,1,0,0,0
access_uom_uom_user,uom.uom user,uom.model_uom_uom,sf_base.group_sf_mrp_user,1,0,0,0
-access_product_supplierinfo_user,product.supplierinfo user,product.model_product_supplierinfo,sf_base.group_sf_mrp_user,1,1,1,0
+access_product_supplierinfo_user,product.supplierinfo user,product.model_product_supplierinfo,sf_base.group_sf_mrp_user,1,0,0,0
access_res_partner,res.partner,base.model_res_partner,sf_base.group_sf_mrp_user,1,0,0,0
access_mrp_workorder_mrp_user,mrp.workorder.user,mrp.model_mrp_workorder,sf_base.group_sf_mrp_user,1,1,1,0
access_mrp_workorder_mrp_manager,mrp.workorder,mrp.model_mrp_workorder,sf_base.group_sf_mrp_user,1,1,1,0
@@ -87,14 +99,18 @@ access_mrp_production_split,access.mrp.production.split,mrp.model_mrp_production
access_mrp_production_split_line,access.mrp.production.split.line,mrp.model_mrp_production_split_line,sf_base.group_sf_mrp_user,1,1,1,0
access_mrp_workcenter_capacity_manager,mrp.workcenter.capacity.manager,mrp.model_mrp_workcenter_capacity,sf_base.group_sf_mrp_user,1,1,1,0
-access_mrp_production,mrp_production,model_mrp_production,sf_base.group_plan_dispatch,1,1,1,0
+
+access_mrp_production_group_plan_dispatch,mrp_production,model_mrp_production,sf_base.group_plan_dispatch,1,0,0,0
access_mrp_workorder,mrp_workorder,model_mrp_workorder,sf_base.group_plan_dispatch,1,1,1,0
-access_sf_production_line,sf.production.line,model_sf_production_line,sf_base.group_plan_dispatch,1,1,1,0
+access_sf_production_line_group_plan_dispatch,sf.production.line,model_sf_production_line,sf_base.group_plan_dispatch,1,0,0,0
+access_sf_production_line_group_plan_director,sf.production.line,model_sf_production_line,sf_base.group_plan_director,1,1,1,0
+access_sf_production_line,sf.production.line,model_sf_production_line,sf_maintenance.sf_group_equipment_user,1,1,1,0
access_mrp_workcenter,mrp_workcenter,model_mrp_workcenter,sf_base.group_plan_dispatch,1,1,1,0
access_mrp_bom,mrp.bom,mrp.model_mrp_bom,sf_base.group_plan_dispatch,1,1,1,0
access_mrp_bom_line,mrp.bom.line,mrp.model_mrp_bom_line,sf_base.group_plan_dispatch,1,0,0,0
access_mrp_unbuild,mrp.unbuild,mrp.model_mrp_unbuild,sf_base.group_plan_dispatch,1,1,1,0
-access_stock_scrap,stock.scrap,stock.model_stock_scrap,sf_base.group_plan_dispatch,1,1,1,0
+access_stock_scrap_group_plan_dispatch,stock.scrap,stock.model_stock_scrap,sf_base.group_plan_dispatch,1,0,0,0
+
access_sf_model_type,sf.model.type,model_sf_model_type,sf_base.group_plan_dispatch,1,1,1,0
access_mrp_routing_workcenter,mrp.routing.workcenter,mrp.model_mrp_routing_workcenter,sf_base.group_plan_dispatch,1,1,1,0
access_mrp_document,mrp.document,mrp.model_mrp_document,sf_base.group_plan_dispatch,1,0,0,0
@@ -106,4 +122,5 @@ access_sf_cnc_processing,sf.cnc.processing,model_sf_cnc_processing,sf_base.group
-access_mrp_workcenter_productivity,mrp.workcenter.productivity,mrp.model_mrp_workcenter_productivity,sf_base.group_plan_dispatch,1,0,0,0
\ No newline at end of file
+access_mrp_workcenter_productivity,mrp.workcenter.productivity,mrp.model_mrp_workcenter_productivity,sf_base.group_plan_dispatch,1,0,0,0
+access_maintenance_equipment_tool_group_plan_dispatch,maintenance.equipment.tool,sf_manufacturing.model_maintenance_equipment_tool,sf_base.group_plan_dispatch,1,0,0,0
diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml
index 3727bb10..b93ad455 100644
--- a/sf_manufacturing/views/mrp_production_addional_change.xml
+++ b/sf_manufacturing/views/mrp_production_addional_change.xml
@@ -18,19 +18,21 @@
-
+
-
+
-
-
-
-
+
+
+
+
@@ -39,58 +41,315 @@
+ attrs="{'invisible': [('state', 'not in', ['confirmed', 'progress'])]}"
+ optional="hide"
+ decoration-success="reservation_state == 'assigned' or components_availability_state == 'available'"
+ decoration-warning="reservation_state != 'assigned' and components_availability_state in ('expected', 'available')"
+ decoration-danger="reservation_state != 'assigned' and components_availability_state == 'late'"/>
-
-
-
-
+
+
+
+
-
+
+
custom.mrp.production.form
mrp.production
-
-
-
-
-
-
-
+
+ draft,confirmed,progress,pending_processing,completed,done
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sf.mrp.production.workorder.tree.editable
+ mrp.workorder
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ =======
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sf.mrp.production.tree
+ mrp.production
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
custom.mrp.production.select
@@ -106,24 +365,24 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
custom.Product.template.product.kanban
product.template
@@ -131,44 +390,52 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 规格:
+
+
+
[ ]
+
+
+
+
+ Variants
-
-
-
-
- 规格:
-
-
[ ]
-
-
- Variants
-
-
-
-
-
-
-
+
+
+
diff --git a/sf_manufacturing/views/mrp_routing_workcenter_view.xml b/sf_manufacturing/views/mrp_routing_workcenter_view.xml
index d0db3a7b..5ab745db 100644
--- a/sf_manufacturing/views/mrp_routing_workcenter_view.xml
+++ b/sf_manufacturing/views/mrp_routing_workcenter_view.xml
@@ -6,6 +6,9 @@
mrp.routing.workcenter
+
+
+
mrp.production
-
-
-
+
+
+
mrp.production
-
-
-
+
+
+
+
+ ('is_user_working', '!=', False),('user_permissions','=',False)]}"
+ 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'), ('is_user_working', '=', False)]}"/>
+ groups="sf_base.group_sf_mrp_user"
+ attrs="{'invisible': ['|', '|','|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'),('user_permissions','=',False),('state','=','done')]}"/>
+ groups="sf_base.group_sf_mrp_user"
+ attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('state','=','done')]}"/>
+
+
-
+
@@ -162,11 +171,13 @@
+ attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
+ attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
+ attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
+
@@ -219,7 +230,7 @@
-
+
@@ -229,11 +240,12 @@
-
-
-
-
-
+
+
+
+
+
+
@@ -241,10 +253,7 @@
placeholder="如有预调程序信息请在此处输入....."/>
-
-
-
-
+
左面:
@@ -393,12 +402,41 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -424,32 +462,18 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
@@ -479,14 +503,68 @@
[('schedule_state', '=', '已排')]
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+ 工件配送
+ sf.workpiece.delivery
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 工件配送
+ sf.workpiece.delivery
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 工件配送
+ sf.workpiece.delivery
+ tree,search
+
diff --git a/sf_manufacturing/views/sf_maintenance_equipment.xml b/sf_manufacturing/views/sf_maintenance_equipment.xml
index a2d9437d..b398f994 100644
--- a/sf_manufacturing/views/sf_maintenance_equipment.xml
+++ b/sf_manufacturing/views/sf_maintenance_equipment.xml
@@ -1,7 +1,7 @@
-
+ 设备增加刀具库位table
sf_manufacturing_equipment.form
maintenance.equipment
@@ -13,17 +13,6 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/sf_manufacturing/views/stock_lot_views.xml b/sf_manufacturing/views/stock_lot_views.xml
new file mode 100644
index 00000000..f637d401
--- /dev/null
+++ b/sf_manufacturing/views/stock_lot_views.xml
@@ -0,0 +1,18 @@
+
+
+
+ stock.lot.form.quality
+ stock.lot
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sf_manufacturing/views/stock_picking_view.xml b/sf_manufacturing/views/stock_picking_view.xml
index a287fbec..13bb12c2 100644
--- a/sf_manufacturing/views/stock_picking_view.xml
+++ b/sf_manufacturing/views/stock_picking_view.xml
@@ -1,6 +1,17 @@
+
+ stock.move.operations.form.inherit.sf
+ stock.move
+
+
+
+
+
+
+
+
stock.picking.form.inherit.sf
stock.picking
diff --git a/sf_manufacturing/wizard/__init__.py b/sf_manufacturing/wizard/__init__.py
new file mode 100644
index 00000000..5cfab982
--- /dev/null
+++ b/sf_manufacturing/wizard/__init__.py
@@ -0,0 +1 @@
+from . import workpiece_delivery_wizard
diff --git a/sf_manufacturing/wizard/workpiece_delivery_views.xml b/sf_manufacturing/wizard/workpiece_delivery_views.xml
new file mode 100644
index 00000000..96e1d4ff
--- /dev/null
+++ b/sf_manufacturing/wizard/workpiece_delivery_views.xml
@@ -0,0 +1,27 @@
+
+
+
+ sf.workpiece.delivery.wizard.form.view
+ sf.workpiece.delivery.wizard
+
+
+
+
+
+
+ 工件配送向导
+ sf.workpiece.delivery.wizard
+ form
+ new
+
+
+
\ No newline at end of file
diff --git a/sf_manufacturing/wizard/workpiece_delivery_wizard.py b/sf_manufacturing/wizard/workpiece_delivery_wizard.py
new file mode 100644
index 00000000..d990e307
--- /dev/null
+++ b/sf_manufacturing/wizard/workpiece_delivery_wizard.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Part of YiZuo. See LICENSE file for full copyright and licensing details.
+from odoo.exceptions import UserError, ValidationError
+from datetime import datetime
+from odoo import models, api, fields
+
+
+class WorkpieceDeliveryWizard(models.TransientModel):
+ _name = 'sf.workpiece.delivery.wizard'
+ _description = '工件配送'
+
+ delivery_id = fields.Many2one('sf.workpiece.delivery', string='配送')
+
+ def confirm(self):
+ self.delivery_id._delivery_avg()
+
diff --git a/sf_mrs_connect/controllers/controllers.py b/sf_mrs_connect/controllers/controllers.py
index a6a1b25f..5cd28a08 100644
--- a/sf_mrs_connect/controllers/controllers.py
+++ b/sf_mrs_connect/controllers/controllers.py
@@ -22,25 +22,28 @@ class Sf_Mrs_Connect(http.Controller):
datas = request.httprequest.data
ret = json.loads(datas)
ret = json.loads(ret['result'])
+ logging.info('下发编程单:%s' % ret)
# 查询状态为进行中且类型为获取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'])])
+ logging.info('制造订单号:%s' % cnc_production.name)
+ if cnc_production:
+ if ret['glb_file']:
+ cnc_production.glb_file = base64.b64encode(ret['glb_file'])
# 拉取所有加工面的程序文件
# i = 1
+
for r in ret['processing_panel']:
download_state = request.env['sf.cnc.processing'].with_user(
request.env.ref("base.user_admin")).download_file_tmp(
ret['folder_name'], r)
- if not download_state:
+ if download_state == 0:
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)
+ logging.info('创建cnc工单')
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/ftp_operate.py b/sf_mrs_connect/models/ftp_operate.py
index 2ef43467..341ec88e 100644
--- a/sf_mrs_connect/models/ftp_operate.py
+++ b/sf_mrs_connect/models/ftp_operate.py
@@ -35,8 +35,9 @@ class FtpController():
server = os.path.join(serverdir, file)
if file.find(".") != -1:
self.download_file(server, file)
+ return 1
except Exception:
- return False
+ return 0
# 下载指定目录下的指定文件
def download_file(self, serverfile, remotefile):
diff --git a/sf_mrs_connect/models/res_config_setting.py b/sf_mrs_connect/models/res_config_setting.py
index 91bd52c6..b15c71df 100644
--- a/sf_mrs_connect/models/res_config_setting.py
+++ b/sf_mrs_connect/models/res_config_setting.py
@@ -13,7 +13,8 @@ class ResConfigSettings(models.TransientModel):
token = fields.Char(string='TOKEN', default='b811ac06-3f00-11ed-9aed-0242ac110003')
sf_secret_key = fields.Char(string='密钥', default='wBmxej38OkErKhD6')
sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com')
- bfm_url = fields.Char(string='业务平台后端访问地址', default='https://bfm.jikimo.com')
+ agv_url = fields.Char(string='avg访问地址', default='http://IP:PORT/rcms/services/rest')
+ model_parser_url = fields.Char('特征识别路径')
ftp_host = fields.Char(string='FTP的ip')
ftp_port = fields.Char(string='FTP端口')
ftp_user = fields.Char(string='FTP用户')
@@ -33,8 +34,8 @@ class ResConfigSettings(models.TransientModel):
_logger.info("同步资源库表面工艺类别完成")
self.env['sf.production.process'].sync_all_production_process()
_logger.info("同步资源库表面工艺完成")
- # self.env['sf.processing.technology'].sync_all_processing_technology()
- # _logger.info("同步资源库加工工艺")
+ self.env['sf.processing.technology'].sync_all_processing_technology()
+ _logger.info("同步资源库加工工艺")
self.env['sf.machine.brand.tags'].sync_all_machine_brand_tags()
_logger.info("同步资源库品牌类别完成")
self.env['sf.machine.brand'].sync_all_machine_brand()
@@ -44,27 +45,36 @@ class ResConfigSettings(models.TransientModel):
self.env['sf.machine_tool.category'].sync_all_machine_tool_category()
_logger.info("同步资源库机床类型完成")
self.env['sf.production.process.parameter'].sync_all_production_process_parameter()
- _logger.info("同步刀具物料完成")
+ _logger.info("同步材料型号可选参数完成")
self.env['sf.cutting.tool.material'].sync_all_cutting_tool_material()
- _logger.info("同步刀具类型完成")
+ _logger.info("同步刀具物料完成")
self.env['sf.cutting.tool.type'].sync_all_tool_type()
- _logger.info("同步功能刀具类型完成")
+ _logger.info("同步刀具类型完成")
self.env['sf.functional.cutting.tool.model'].sync_all_functional_cutting_tool_model()
- _logger.info("同步夹具物料完成")
+ _logger.info("同步功能刀具类型完成")
self.env['sf.fixture.material'].sync_all_fixture_material()
- _logger.info("同步联装类型完成")
+ _logger.info("同步夹具物料完成")
self.env['sf.multi_mounting.type'].sync_all_multi_mounting_type()
- _logger.info("同步夹具型号完成")
+ _logger.info("同步联装类型完成")
self.env['sf.fixture.model'].sync_all_fixture_model()
- _logger.info("同步夹具型号类型完成")
+ _logger.info("同步夹具型号完成")
self.env['sf.functional.fixture.type'].sync_all_functional_fixture_type()
- _logger.info("同步功能夹具类型完成")
+ _logger.info("同步夹具型号类型完成")
self.env['sf.machine_tool.type'].sync_all_machine_tool_type()
- _logger.info("同步资源库机床型号完成")
+ _logger.info("同步功能夹具类型完成")
self.env['maintenance.equipment.image'].sync_all_maintenance_equipment_image()
_logger.info("同步能力特征库完成")
self.env['sf.cutting_tool.standard.library'].sync_all_cutting_tool_standard_library()
_logger.info("同步刀具标准库完成")
+ self.env['sf.tool.materials.basic.parameters'].sync_all_cutting_tool_basic_parameters()
+ _logger.info("同步刀具物料基本参数完成")
+ self.env['sf.cutting.width.depth'].sync_all_cutting_width_depth()
+ _logger.info("同步刀具物料切削宽度和深度完成")
+ self.env['sf.cutting.speed'].sync_all_cutting_speed()
+ _logger.info("同步刀具物料切削速度完成")
+ self.env['sf.feed.per.tooth'].sync_all_feed_per_tooth()
+ _logger.info("同步刀具物料每齿走刀量完成")
+
except Exception as e:
_logger.info("捕获错误信息:%s" % e)
raise ValidationError("数据错误导致同步失败,请联系管理员")
diff --git a/sf_mrs_connect/models/sync_common.py b/sf_mrs_connect/models/sync_common.py
index fe7bd12e..66bf6e14 100644
--- a/sf_mrs_connect/models/sync_common.py
+++ b/sf_mrs_connect/models/sync_common.py
@@ -62,6 +62,14 @@ class MrStaticResourceDataSync(models.Model):
logging.info("能力特征库已每日同步成功")
self.env['sf.cutting_tool.standard.library'].sync_cutting_tool_standard_library_yesterday()
logging.info("刀具标准库已每日同步成功")
+ self.env['sf.tool.materials.basic.parameters'].sync_cutting_tool_basic_parameters_yesterday()
+ _logger.info("同步刀具物料基本参数完成")
+ self.env['sf.cutting.width.depth'].sync_cutting_width_depth_yesterday()
+ _logger.info("同步刀具物料切削宽度和深度完成")
+ self.env['sf.cutting.speed'].sync_cutting_speed_yesterday()
+ _logger.info("同步刀具物料切削速度完成")
+ self.env['sf.feed.per.tooth'].sync_feed_per_tooth_yesterday()
+ _logger.info("同步刀具物料每齿走刀量完成")
except Exception as e:
logging.info("捕获错误信息:%s" % e)
raise ValidationError("数据错误导致同步失败,请联系管理员")
@@ -84,7 +92,8 @@ class sfProductionMaterials(models.Model):
if result['status'] == 1:
for item in result['production_materials_yesterday_list']:
if item:
- materials = self.search([("materials_no", '=', item['materials_no'])])
+ materials = self.search(
+ [("materials_no", '=', item['materials_no'], ('active', 'in', [True, False]))])
if materials:
materials.name = item['name']
materials.remark = item['remark']
@@ -110,7 +119,8 @@ class sfProductionMaterials(models.Model):
if result['status'] == 1:
for item in result['production_materials_all_list']:
if item:
- materials = self.search([("materials_no", '=', item['materials_no'])])
+ materials = self.search(
+ [("materials_no", '=', item['materials_no']), ('active', 'in', [True, False])])
if not materials:
self.create({
"name": item['name'],
@@ -142,7 +152,8 @@ class sfMaterialModel(models.Model):
if result['status'] == 1:
for item in result['materials_model_yesterday_list']:
if item:
- materials_model = self.search([("materials_no", '=', item['materials_no'])])
+ materials_model = self.search(
+ [("materials_no", '=', item['materials_no']), ('active', 'in', [True, False])])
materials = self.env['sf.production.materials'].search(
[("materials_no", '=', item['materials_id.materials_no'])])
if materials_model:
@@ -188,7 +199,8 @@ class sfMaterialModel(models.Model):
if result['status'] == 1:
for item in result['materials_model_all_list']:
if item:
- materials_model = self.search([("materials_no", '=', item['materials_no'])])
+ materials_model = self.search(
+ [("materials_no", '=', item['materials_no']), ('active', 'in', [True, False])])
materials = self.env['sf.production.materials'].search(
[("materials_no", '=', item['materials_id.materials_no'])])
if not materials_model:
@@ -248,7 +260,8 @@ class sfProductionProcessCategory(models.Model):
if result['status'] == 1:
for item in result['production_process_category_yesterday_list']:
if item:
- production_process_category = self.search([("code", '=', item['code'])])
+ production_process_category = self.search(
+ [("code", '=', item['code']), ('active', 'in', [True, False])])
if production_process_category:
production_process_category.name = item['name']
production_process_category.code = item['code']
@@ -273,7 +286,7 @@ class sfProductionProcessCategory(models.Model):
if result['status'] == 1:
for item in result['production_process_category_all_list']:
if item:
- category = self.search([("code", '=', item['code'])])
+ category = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
if not category:
self.create({
"name": item['name'],
@@ -303,17 +316,7 @@ class sfProductionProcess(models.Model):
if result['status'] == 1:
for item in result['production_process_yesterday_list']:
if item:
- brand = self.env['sf.production.process'].search(
- [("code", '=', item['code'])])
- if brand:
- brand.name = item['name'],
- brand.category_id = self.env['sf.production.process.category'].search(
- [("code", '=', item['category_code'])]).id,
- brand.code = item['code'],
- brand.remark = item['remark'],
- brand.active = item['active'],
- brand.remark = item['remark']
- production_process = self.search([("code", '=', item['code'])])
+ production_process = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
category = self.env['sf.production.process.category'].search(
[("code", '=', item['category_code'])])
if production_process:
@@ -324,8 +327,7 @@ class sfProductionProcess(models.Model):
else:
self.create({
"name": item['name'],
- "category_id": self.env['sf.production.process.category'].search(
- [("code", '=', item['category_code'])]).id,
+ "category_id": category.id,
"code": item['code'],
"remark": item['remark'],
"active": item['active'],
@@ -344,7 +346,7 @@ class sfProductionProcess(models.Model):
if result['status'] == 1:
for item in result['production_process_all_list']:
if item:
- production_process = self.search([("code", '=', item['code'])])
+ production_process = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
category = self.env['sf.production.process.category'].search(
[("code", '=', item['category_code'])])
if not production_process:
@@ -380,7 +382,8 @@ class sfProcessingTechnology(models.Model):
if result['status'] == 1:
for item in result['processing_technology_yesterday_list']:
if item:
- processing_technology = self.search([("code", '=', item['code'])])
+ processing_technology = self.search(
+ [("code", '=', item['process_encode']), ('active', 'in', [True, False])])
if processing_technology:
processing_technology.name = item['name']
processing_technology.remark = item['remark']
@@ -388,7 +391,7 @@ class sfProcessingTechnology(models.Model):
else:
self.create({
"name": item['name'],
- "code": item['code'],
+ "code": item['process_encode'],
"remark": item['remark'],
"active": item['active'],
})
@@ -406,11 +409,12 @@ class sfProcessingTechnology(models.Model):
if result['status'] == 1:
for item in result['processing_technology_all_list']:
if item:
- processing_technology = self.search([("code", '=', item['code'])])
+ processing_technology = self.search(
+ [("code", '=', item['process_encode']), ('active', 'in', [True, False])])
if not processing_technology:
self.create({
"name": item['name'],
- "code": item['code'],
+ "code": item['process_encode'],
"remark": item['remark'],
"active": item['active'],
})
@@ -488,7 +492,7 @@ class MachineControlSystem(models.Model):
if result['status'] == 1:
for item in result['machine_control_system_yesterday_list']:
if item:
- control_system = self.search([("code", '=', item['code'])])
+ control_system = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
brand = self.env['sf.machine.brand'].search([('code', '=', item['brand_id'])])
if control_system:
control_system.name = item['name']
@@ -517,7 +521,7 @@ class MachineControlSystem(models.Model):
if result['status'] == 1:
for item in result['machine_control_system_all_list']:
if item:
- control_system = self.search([("code", '=', item['code'])])
+ control_system = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
brand = self.env['sf.machine.brand'].search([('code', '=', item['brand_id'])])
if not control_system:
self.create({
@@ -551,7 +555,7 @@ class MachineBrand(models.Model):
result = json.loads(r['result'])
if result['status'] == 1:
for item in result['machine_brand_yesterday_list']:
- brand = self.search([("code", '=', item['code'])])
+ brand = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
if brand:
brand.name = item['name']
brand.image_brand = '' if not item['image_brand'] else base64.b64decode(item['image_brand'])
@@ -580,7 +584,7 @@ class MachineBrand(models.Model):
result = json.loads(r['result'])
if result['status'] == 1:
for item in result['machine_brand_all_list']:
- brand = self.search([("code", '=', item['code'])])
+ brand = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
if not brand:
self.create({
"name": item['name'],
@@ -620,7 +624,7 @@ class MachineToolType(models.Model):
else:
image = ''
taper_type_id = self.env['spindle.taper.type'].search([('name', '=', item['taper_type_id'])])
- machine_tool_type = self.search([("code", '=', item['code'])])
+ machine_tool_type = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
control_system = self.env['sf.machine.control_system'].search(
[('code', '=', item['control_system_id'])])
jg_image_id = self.env['maintenance.equipment.image'].search([('name', 'in', item['jg_image_id'])])
@@ -649,24 +653,24 @@ class MachineToolType(models.Model):
'machine_tool_picture': image,
"heightened_way": item['heightened_way'],
"workpiece_load": item['workpiece_load'],
- #"lead_screw": item['lead_screw'],
+ # "lead_screw": item['lead_screw'],
"workbench_L": item['workbench_L'],
"workbench_W": item['workbench_W'],
- #"guide_rail": item['guide_rail'],
+ # "guide_rail": item['guide_rail'],
"machine_tool_L": item['machine_tool_L'],
"machine_tool_W": item['machine_tool_W'],
"machine_tool_H": item['machine_tool_H'],
- #"feed_speed": item['feed_speed'],
- #"tool_speed": item['tool_speed'],
+ # "feed_speed": item['feed_speed'],
+ # "tool_speed": item['tool_speed'],
"distance_min": item['distance_min'],
"distance_max": item['distance_max'],
- #"taper": item['taper'],
- #"torque": item['torque'],
- #"motor_power": item['motor_power'],
+ # "taper": item['taper'],
+ # "torque": item['torque'],
+ # "motor_power": item['motor_power'],
"tool_quality_max": item['tool_quality_max'],
"tool_long_max": item['tool_long_max'],
- #"tool_diameter_max": item['tool_diameter_max'],
- #"tool_diameter_min": item['tool_diameter_min'],
+ # "tool_diameter_max": item['tool_diameter_max'],
+ # "tool_diameter_min": item['tool_diameter_min'],
"machine_tool_category": category.id,
'taper_type_id': taper_type_id.id,
"function_type": item['function_type'],
@@ -731,24 +735,24 @@ class MachineToolType(models.Model):
'machine_tool_picture': image,
"heightened_way": item['heightened_way'],
"workpiece_load": item['workpiece_load'],
- #"lead_screw": item['lead_screw'],
+ # "lead_screw": item['lead_screw'],
"workbench_L": item['workbench_L'],
"workbench_W": item['workbench_W'],
- #"guide_rail": item['guide_rail'],
+ # "guide_rail": item['guide_rail'],
"machine_tool_L": item['machine_tool_L'],
"machine_tool_W": item['machine_tool_W'],
"machine_tool_H": item['machine_tool_H'],
- #"feed_speed": item['feed_speed'],
- #"tool_speed": item['tool_speed'],
+ # "feed_speed": item['feed_speed'],
+ # "tool_speed": item['tool_speed'],
"distance_min": item['distance_min'],
"distance_max": item['distance_max'],
- #"taper": item['taper'],
- #"torque": item['torque'],
- #"motor_power": item['motor_power'],
+ # "taper": item['taper'],
+ # "torque": item['torque'],
+ # "motor_power": item['motor_power'],
"tool_quality_max": item['tool_quality_max'],
"tool_long_max": item['tool_long_max'],
- #"tool_diameter_max": item['tool_diameter_max'],
- #"tool_diameter_min": item['tool_diameter_min'],
+ # "tool_diameter_max": item['tool_diameter_max'],
+ # "tool_diameter_min": item['tool_diameter_min'],
"machine_tool_category": category.id,
'taper_type_id': taper_type_id.id,
"function_type": item['function_type'],
@@ -814,7 +818,7 @@ class MachineToolType(models.Model):
'name': item['taper_type_id']
})
- machine_tool_type = self.search([("code", '=', item['code'])])
+ machine_tool_type = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
control_system = self.env['sf.machine.control_system'].search(
[('code', '=', item['control_system_id'])])
brand = self.env['sf.machine.brand'].search([('code', '=', item['brand_id'])])
@@ -844,24 +848,24 @@ class MachineToolType(models.Model):
'machine_tool_picture': image,
"heightened_way": item['heightened_way'],
"workpiece_load": item['workpiece_load'],
- #"lead_screw": item['lead_screw'],
+ # "lead_screw": item['lead_screw'],
"workbench_L": item['workbench_L'],
"workbench_W": item['workbench_W'],
- #"guide_rail": item['guide_rail'],
+ # "guide_rail": item['guide_rail'],
"machine_tool_L": item['machine_tool_L'],
"machine_tool_W": item['machine_tool_W'],
"machine_tool_H": item['machine_tool_H'],
- #"feed_speed": item['feed_speed'],
- #"tool_speed": item['tool_speed'],
+ # "feed_speed": item['feed_speed'],
+ # "tool_speed": item['tool_speed'],
"distance_min": item['distance_min'],
"distance_max": item['distance_max'],
- #"taper": item['taper'],
- #"torque": item['torque'],
- #"motor_power": item['motor_power'],
+ # "taper": item['taper'],
+ # "torque": item['torque'],
+ # "motor_power": item['motor_power'],
"tool_quality_max": item['tool_quality_max'],
"tool_long_max": item['tool_long_max'],
- #"tool_diameter_max": item['tool_diameter_max'],
- #"tool_diameter_min": item['tool_diameter_min'],
+ # "tool_diameter_max": item['tool_diameter_max'],
+ # "tool_diameter_min": item['tool_diameter_min'],
"machine_tool_category": category.id,
'taper_type_id': taper_type_id.id,
"function_type": item['function_type'],
@@ -903,7 +907,6 @@ class MachineToolType(models.Model):
"jg_image_id": jg_image_id.ids,
"lq_image_id": lq_image_id.ids,
-
})
else:
machine_tool_type.update({
@@ -927,24 +930,24 @@ class MachineToolType(models.Model):
'machine_tool_picture': image,
"heightened_way": item['heightened_way'],
"workpiece_load": item['workpiece_load'],
- #"lead_screw": item['lead_screw'],
+ # "lead_screw": item['lead_screw'],
"workbench_L": item['workbench_L'],
"workbench_W": item['workbench_W'],
- #"guide_rail": item['guide_rail'],
+ # "guide_rail": item['guide_rail'],
"machine_tool_L": item['machine_tool_L'],
"machine_tool_W": item['machine_tool_W'],
"machine_tool_H": item['machine_tool_H'],
- #"feed_speed": item['feed_speed'],
- #"tool_speed": item['tool_speed'],
+ # "feed_speed": item['feed_speed'],
+ # "tool_speed": item['tool_speed'],
"distance_min": item['distance_min'],
"distance_max": item['distance_max'],
- #"taper": item['taper'],
- #"torque": item['torque'],
- #"motor_power": item['motor_power'],
+ # "taper": item['taper'],
+ # "torque": item['torque'],
+ # "motor_power": item['motor_power'],
"tool_quality_max": item['tool_quality_max'],
"tool_long_max": item['tool_long_max'],
- #"tool_diameter_max": item['tool_diameter_max'],
- #"tool_diameter_min": item['tool_diameter_min'],
+ # "tool_diameter_max": item['tool_diameter_max'],
+ # "tool_diameter_min": item['tool_diameter_min'],
"machine_tool_category": category.id,
'taper_type_id': taper_type_id.id,
"function_type": item['function_type'],
@@ -1006,7 +1009,7 @@ class sfProcessingOrder(models.Model):
result = json.loads(r['result'])
if result['status'] == 1:
for item in result['processing_order_yesterday_list']:
- processing_order = self.search([("id", '=', item['id'])])
+ processing_order = self.search([("id", '=', item['id']), ('active', 'in', [True, False])])
if processing_order:
processing_order.sequence = item['sequence']
else:
@@ -1026,7 +1029,7 @@ class sfProcessingOrder(models.Model):
result = json.loads(r['result'])
if result['status'] == 1:
for item in result['processing_order_all_list']:
- processing_order = self.search([("id", '=', item['id'])])
+ processing_order = self.search([("id", '=', item['id']), ('active', 'in', [True, False])])
if not processing_order:
self.create({
"sequence": item['sequence'],
@@ -1053,7 +1056,8 @@ class sfProductionProcessParameter(models.Model):
if result['status'] == 1:
for item in result['mrs_production_process_parameter_yesterday_list']:
if item:
- production_process_parameter = self.search([("code", '=', item['code'])])
+ production_process_parameter = self.search(
+ [("code", '=', item['code']), ('active', 'in', [True, False])])
process = self.env['sf.production.process'].search(
[('code', '=', item['process_id_code'])])
if production_process_parameter:
@@ -1086,7 +1090,7 @@ class sfProductionProcessParameter(models.Model):
for item in result['mrs_production_process_parameter_all_list']:
if item:
production_process_parameter = self.search(
- [("code", '=', item['code'])])
+ [("code", '=', item['code']), ('active', 'in', [True, False])])
process = self.env['sf.production.process'].search(
[('code', '=', item['process_id_code'])], limit=1)
if not production_process_parameter:
@@ -1123,7 +1127,7 @@ class MachineToolCategory(models.Model):
result = json.loads(r['result'])
if result['status'] == 1:
for item in result['machine_tool_category_yesterday_list']:
- machine_tool_category = self.search([("code", '=', item['code'])])
+ machine_tool_category = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
if machine_tool_category:
machine_tool_category.name = item['name']
machine_tool_category.category = item['category']
@@ -1150,7 +1154,7 @@ class MachineToolCategory(models.Model):
result = json.loads(r['result'])
if result['status'] == 1:
for item in result['machine_tool_category_all_list']:
- machine_tool_category = self.search([("code", '=', item['code'])])
+ machine_tool_category = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
if not machine_tool_category:
self.create({
"name": item['name'],
@@ -1188,7 +1192,8 @@ class sfSyncCutting_tool_Material(models.Model):
if result.get('mrs_cutting_tool_material_yesterday_list'):
for item in result['mrs_cutting_tool_material_yesterday_list']:
if item:
- cutting_tool_material = self.search([("code", '=', item['code'])])
+ cutting_tool_material = self.search(
+ [("code", '=', item['code']), ('active', 'in', [True, False])])
if not cutting_tool_material:
self.create({
"name": item['name'],
@@ -1218,7 +1223,8 @@ class sfSyncCutting_tool_Material(models.Model):
if result.get('mrs_cutting_tool_material_all_list'):
for item in result['mrs_cutting_tool_material_all_list']:
if item:
- cutting_tool_material = self.search([("code", '=', item['code'])])
+ cutting_tool_material = self.search(
+ [("code", '=', item['code']), ('active', 'in', [True, False])])
if not cutting_tool_material:
self.create({
"name": item['name'],
@@ -1255,7 +1261,8 @@ class SyncFunctionalCuttingToolModel(models.Model):
if result.get('mrs_functional_cutting_tool_model_yesterday_list'):
for item in result['mrs_functional_cutting_tool_model_yesterday_list']:
if item:
- functional_cutting_tool_model = self.search([("code", '=', item['code'])])
+ functional_cutting_tool_model = self.search(
+ [("code", '=', item['code']), ('active', 'in', [True, False])])
if not functional_cutting_tool_model:
self.create({
"name": item['name'],
@@ -1285,7 +1292,8 @@ class SyncFunctionalCuttingToolModel(models.Model):
if result.get('mrs_functional_cutting_tool_model_all_list'):
for item in result['mrs_functional_cutting_tool_model_all_list']:
if item:
- functional_cutting_tool_model = self.search([("code", '=', item['code'])])
+ functional_cutting_tool_model = self.search(
+ [("code", '=', item['code']), ('active', 'in', [True, False])])
if not functional_cutting_tool_model:
self.create({
"name": item['name'],
@@ -1322,7 +1330,7 @@ class SyncFixtureMaterial(models.Model):
if result.get('fixture_material_yesterday_list'):
for item in result['fixture_material_yesterday_list']:
if item:
- fixture_material = self.search([("code", '=', item['code'])])
+ fixture_material = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
if not fixture_material:
self.create({
"name": item['name'],
@@ -1354,7 +1362,7 @@ class SyncFixtureMaterial(models.Model):
if result.get('fixture_material_all_list'):
for item in result['fixture_material_all_list']:
if item:
- fixture_material = self.search([("code", '=', item['code'])])
+ fixture_material = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
if not fixture_material:
self.create({
"name": item['name'],
@@ -1392,7 +1400,8 @@ class SyncMulti_Mounting_Type(models.Model):
if result.get('multi_mounting_type_yesterday_list'):
for item in result['multi_mounting_type_yesterday_list']:
if item:
- multi_mounting_type = self.search([("code", '=', item['code'])])
+ multi_mounting_type = self.search(
+ [("code", '=', item['code']), ('active', 'in', [True, False])])
if not multi_mounting_type:
self.create({
"name": item['name'],
@@ -1422,7 +1431,8 @@ class SyncMulti_Mounting_Type(models.Model):
if result.get('multi_mounting_type_all_list'):
for item in result['multi_mounting_type_all_list']:
if item:
- multi_mounting_type = self.search([("code", '=', item['code'])])
+ multi_mounting_type = self.search(
+ [("code", '=', item['code']), ('active', 'in', [True, False])])
if not multi_mounting_type:
self.create({
"name": item['name'],
@@ -1458,7 +1468,40 @@ class SyncFixtureModel(models.Model):
if result.get('fixture_model_yesterday_list'):
for item in result['fixture_model_yesterday_list']:
if item:
- fixture_model = self.search([("code", '=', item['code'])])
+ fixture_model = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
+ 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'],
@@ -1468,56 +1511,46 @@ 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({
+ "zero_chuck_ids": [(5, 0, 0)],
+ "zero_tray_ids": [(5, 0, 0)],
+ "pneumatic_fixture_ids": [(5, 0, 0)],
+ "jaw_vice_fixture_ids": [(5, 0, 0)],
+ "magnet_fixture_ids": [(5, 0, 0)],
+ "adapter_board_fixture_ids": [(5, 0, 0)],
+ "scroll_chuck_ids": [(5, 0, 0)],
+ })
+ self.env['sf.fixture.materials.basic.parameters'].sudo().search(
+ [('fixture_model_id', '=', False)]).unlink()
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:
@@ -1536,7 +1569,40 @@ class SyncFixtureModel(models.Model):
if result.get('fixture_model_all_list'):
for item in result['fixture_model_all_list']:
if item:
- fixture_model = self.search([("code", '=', item['code'])])
+ fixture_model = self.search([('code', '=', item['code']), ('active', 'in', [True, False])])
+ 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'],
@@ -1546,56 +1612,46 @@ 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({
+ "zero_chuck_ids": [(5, 0, 0)],
+ "zero_tray_ids": [(5, 0, 0)],
+ "pneumatic_fixture_ids": [(5, 0, 0)],
+ "jaw_vice_fixture_ids": [(5, 0, 0)],
+ "magnet_fixture_ids": [(5, 0, 0)],
+ "adapter_board_fixture_ids": [(5, 0, 0)],
+ "scroll_chuck_ids": [(5, 0, 0)],
+ })
+ self.env['sf.fixture.materials.basic.parameters'].sudo().search(
+ [('fixture_model_id', '=', False)]).unlink()
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:
@@ -1621,7 +1677,8 @@ class SyncFunctionalFixtureType(models.Model):
if result.get('functional_fixture_type_yesterday_list'):
for item in result['functional_fixture_type_yesterday_list']:
if item:
- functional_fixture_type = self.search([("code", '=', item['code'])])
+ functional_fixture_type = self.search(
+ [("code", '=', item['code']), ('active', 'in', [True, False])])
if not functional_fixture_type:
self.create({
"name": item['name'],
@@ -1650,7 +1707,8 @@ class SyncFunctionalFixtureType(models.Model):
if result.get('functional_fixture_type_all_list'):
for item in result['functional_fixture_type_all_list']:
if item:
- functional_fixture_type = self.search([("code", '=', item['code'])])
+ functional_fixture_type = self.search(
+ [("code", '=', item['code']), ('active', 'in', [True, False])])
if not functional_fixture_type:
self.create({
"name": item['name'],
@@ -1686,7 +1744,7 @@ class SfToolType(models.Model):
if result['status'] == 1:
for item in result['mrs_cutting_tool_type_yesterday_list']:
if item:
- cutting_tool_type = self.search([("code", '=', item['code'])])
+ cutting_tool_type = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
cutting_tool_material = self.env['sf.cutting.tool.material'].search(
[("code", '=', item['cutting_tool_material_code'])])
if not cutting_tool_type:
@@ -1718,7 +1776,7 @@ class SfToolType(models.Model):
if result['status'] == 1:
for item in result['mrs_cutting_tool_type_all_list']:
if item:
- cutting_tool_type = self.search([("code", '=', item['code'])])
+ cutting_tool_type = self.search([("code", '=', item['code']), ('active', 'in', [True, False])])
cutting_tool_material = self.env['sf.cutting.tool.material'].search(
[("code", '=', item['cutting_tool_material_code'])])
if not cutting_tool_type:
@@ -1758,7 +1816,8 @@ class SfMaintenanceEquipmentImage(models.Model):
if result['status'] == 1:
for item in result['ability_feature_library_yesterday_list']:
if item:
- ability_feature_library = self.search([("name", '=', item['name'])])
+ ability_feature_library = self.search(
+ [("name", '=', item['name']), ('active', 'in', [True, False])])
if not ability_feature_library:
self.create({
"name": item['name'],
@@ -1786,7 +1845,8 @@ class SfMaintenanceEquipmentImage(models.Model):
if result['status'] == 1:
for item in result['ability_feature_library_all_list']:
if item:
- ability_feature_library = self.search([("name", '=', item['name'])])
+ ability_feature_library = self.search(
+ [("name", '=', item['name']), ('active', 'in', [True, False])])
if not ability_feature_library:
self.create({
"name": item['name'],
@@ -1819,7 +1879,7 @@ class MaterialApply(models.Model):
result = json.loads(r['result'])
if result['status'] == 1:
for item in result['material_apply_yesterday_list']:
- material_apply = self.search([("name", '=', item['name'])])
+ material_apply = self.search([("name", '=', item['name']), ('active', 'in', [True, False])])
if material_apply:
material_apply.name = item['name']
material_apply.active = item['active']
@@ -1841,7 +1901,7 @@ class MaterialApply(models.Model):
result = json.loads(r['result'])
if result['status'] == 1:
for item in result['material_apply_all_list']:
- material_apply = self.search([("name", '=', item['name'])])
+ material_apply = self.search([("name", '=', item['name']), ('active', 'in', [True, False])])
if not material_apply:
self.create({
"name": item['name'],
@@ -1869,7 +1929,7 @@ class ModelInternationalStandards(models.Model):
result = json.loads(r['result'])
if result['status'] == 1:
for item in result['mrs_international_standards_yesterday_list']:
- international_standards = self.search([("name", '=', item['name'])])
+ international_standards = self.search([("name", '=', item['name']), ('active', 'in', [True, False])])
if international_standards:
international_standards.name = item['name']
international_standards.active = item['active']
@@ -1892,7 +1952,7 @@ class ModelInternationalStandards(models.Model):
result = json.loads(r['result'])
if result['status'] == 1:
for item in result['mrs_international_standards_all_list']:
- international_standards = self.search([("name", '=', item['name'])])
+ international_standards = self.search([("name", '=', item['name']), ('active', 'in', [True, False])])
if not international_standards:
self.create({
"name": item['name'],
@@ -1906,6 +1966,242 @@ class ModelInternationalStandards(models.Model):
raise ValidationError("制造标准认证未通过")
+class CuttingSpeed(models.Model):
+ _inherit = 'sf.cutting.speed'
+ _description = '切削速度'
+ url = '/api/cutting_speed/list'
+
+ def sync_cutting_speed_yesterday(self):
+ config = self.env['res.config.settings'].get_values()
+ headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
+ strUrl = config['sf_url'] + self.url
+ r = requests.post(strUrl, json={}, data=None, headers=headers)
+ r = r.json()
+ result = json.loads(r['result'])
+ if result['status'] == 1:
+ for item in result['cutting_speed_yesterday_list']:
+ cutting_speed = self.search([("name", '=', item['name']), ('active', 'in', [True, False])])
+ if not cutting_speed:
+ self.create({
+ 'name': item['name'],
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'execution_standard_id': self.env['sf.international.standards'].search(
+ [('code', '=', item['execution_standard_code'])]).id,
+ 'material_name_id': self.env['sf.materials.model'].search(
+ [('materials_no', '=', item['material_name'])]).id,
+ 'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
+ [('name', '=', item['cutting_width_depth'])]).id,
+ 'ability_feature_library': self.env['maintenance.equipment.image'].search(
+ [('name', '=', item['ability_feature_library']), ('type', '=', '加工能力')]).id,
+ 'material_code': item['material_code'],
+ 'material_grade': item['material_grade'],
+ 'tensile_strength': item['tensile_strength'],
+ 'hardness': item['hardness'],
+ 'cutting_speed': item['cutting_speed'],
+ 'application': item['application'],
+ 'active': item['active'],
+ })
+ else:
+ if item['active'] is False:
+ item.write({'active': False})
+ else:
+ self.write({
+ 'execution_standard_id': self.env['sf.international.standards'].search(
+ [('code', '=', item['execution_standard_code'])]).id,
+ 'material_name_id': self.env['sf.materials.model'].search(
+ [('materials_no', '=', item['material_name'])]).id,
+ 'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
+ [('name', '=', item['cutting_width_depth'])]).id,
+ 'ability_feature_library': self.env['maintenance.equipment.image'].search(
+ [('name', '=', item['ability_feature_library']), ('type', '=', '加工能力')]).id,
+ 'material_code': item['material_code'],
+ 'material_grade': item['material_grade'],
+ 'tensile_strength': item['tensile_strength'],
+ 'hardness': item['hardness'],
+ 'cutting_speed': item['cutting_speed'],
+ 'application': item['application'], })
+ else:
+ raise ValidationError("切削速度认证未通过")
+
+ def sync_all_cutting_speed(self):
+ config = self.env['res.config.settings'].get_values()
+ headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
+ strUrl = config['sf_url'] + self.url
+ r = requests.post(strUrl, json={}, data=None, headers=headers)
+ r = r.json()
+ result = json.loads(r['result'])
+ if result['status'] == 1:
+ for item in result['cutting_speed_all_list']:
+ cutting_speed = self.search([("name", '=', item['name']), ('active', 'in', [True, False])])
+ if not cutting_speed:
+ self.create({
+ 'name': item['name'],
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'execution_standard_id': self.env['sf.international.standards'].search(
+ [('code', '=', item['execution_standard_code'])]).id,
+ 'material_name_id': self.env['sf.materials.model'].search(
+ [('materials_no', '=', item['material_name'])]).id,
+ 'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
+ [('name', '=', item['cutting_width_depth'])]).id,
+ 'ability_feature_library': self.env['maintenance.equipment.image'].search(
+ [('name', '=', item['ability_feature_library']), ('type', '=', '加工能力')]).id,
+ 'material_code': item['material_code'],
+ 'material_grade': item['material_grade'],
+ 'tensile_strength': item['tensile_strength'],
+ 'hardness': item['hardness'],
+ 'cutting_speed': item['cutting_speed'],
+ 'application': item['application'],
+ 'active': item['active'],
+ })
+ else:
+ if item['active'] is False:
+ item.write({'active': False})
+ else:
+ self.write({
+ 'execution_standard_id': self.env['sf.international.standards'].search(
+ [('code', '=', item['execution_standard_code'])]).id,
+ 'material_name_id': self.env['sf.materials.model'].search(
+ [('materials_no', '=', item['material_name'])]).id,
+ 'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
+ [('name', '=', item['cutting_width_depth'])]).id,
+ 'ability_feature_library': self.env['maintenance.equipment.image'].search(
+ [('name', '=', item['ability_feature_library']), ('type', '=', '加工能力')]).id,
+ 'material_code': item['material_code'],
+ 'material_grade': item['material_grade'],
+ 'tensile_strength': item['tensile_strength'],
+ 'hardness': item['hardness'],
+ 'cutting_speed': item['cutting_speed'],
+ 'application': item['application'], })
+ else:
+ raise ValidationError("切削速度认证未通过")
+
+
+class CuttingWidthDepth(models.Model):
+ _inherit = 'sf.cutting.width.depth'
+ _description = '切削宽度和深度'
+ url = '/api/cutting_width_depth/list'
+
+ def sync_cutting_width_depth_yesterday(self):
+ config = self.env['res.config.settings'].get_values()
+ headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
+ strUrl = config['sf_url'] + self.url
+ r = requests.post(strUrl, json={}, data=None, headers=headers)
+ r = r.json()
+ result = json.loads(r['result'])
+ if result['status'] == 1:
+ for item in result['cutting_width_depth_yesterday_list']:
+ cutting_width_depth = self.search([("name", '=', item['name'])])
+ if not cutting_width_depth:
+ self.create({
+ 'name': item['name'],
+ })
+ else:
+ raise ValidationError("切削宽度和深度认证未通过")
+
+ def sync_all_cutting_width_depth(self):
+ config = self.env['res.config.settings'].get_values()
+ headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
+ strUrl = config['sf_url'] + self.url
+ r = requests.post(strUrl, json={}, data=None, headers=headers)
+ r = r.json()
+ result = json.loads(r['result'])
+ if result['status'] == 1:
+ for item in result['cutting_width_depth_all_list']:
+ cutting_width_depth = self.search([("name", '=', item['name'])])
+ if not cutting_width_depth:
+ self.create({
+ 'name': item['name'],
+ })
+ else:
+ raise ValidationError("切削宽度和深度认证未通过")
+
+
+class CuttingSpeed(models.Model):
+ _inherit = 'sf.feed.per.tooth'
+ _description = '每齿走刀量'
+ url = '/api/feed_per_tooth/list'
+
+ def sync_feed_per_tooth_yesterday(self):
+ config = self.env['res.config.settings'].get_values()
+ headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
+ strUrl = config['sf_url'] + self.url
+ r = requests.post(strUrl, json={}, data=None, headers=headers)
+ r = r.json()
+ result = json.loads(r['result'])
+ if result['status'] == 1:
+ for item in result['feed_per_tooth_yesterday_list']:
+ feed_per_tooth = self.search([("name", '=', item['name']), ('active', 'in', [True, False])])
+ if not feed_per_tooth:
+ self.create({
+ 'name': item['name'],
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'materials_type_id': self.env['sf.materials.model'].search(
+ [('materials_no', '=', item['materials_type_code'])]).id,
+ 'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
+ [('name', '=', item['cutting_width_depth'])]).id,
+ 'blade_diameter': item['blade_diameter'],
+ 'feed_per_tooth': item['feed_per_tooth'],
+ 'active': item['active'],
+ })
+ else:
+ if item['active'] is False:
+ item.write({'active': False})
+ else:
+ self.write({
+ 'materials_type_id': self.env['sf.materials.model'].search(
+ [('materials_no', '=', item['materials_type_code'])]).id,
+ 'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
+ [('name', '=', item['cutting_width_depth'])]).id,
+ 'blade_diameter': item['blade_diameter'],
+ 'feed_per_tooth': item['feed_per_tooth'], })
+ else:
+ raise ValidationError("每齿走刀量认证未通过")
+
+ def sync_all_feed_per_tooth(self):
+ config = self.env['res.config.settings'].get_values()
+ headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
+ strUrl = config['sf_url'] + self.url
+ r = requests.post(strUrl, json={}, data=None, headers=headers)
+ r = r.json()
+ result = json.loads(r['result'])
+ if result['status'] == 1:
+ for item in result['feed_per_tooth_all_list']:
+ feed_per_tooth = self.search([("name", '=', item['name']), ('active', 'in', [True, False])])
+ if not feed_per_tooth:
+ self.create({
+ 'name': item['name'],
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'materials_type_id': self.env['sf.materials.model'].search(
+ [('materials_no', '=', item['materials_type_code'])]).id,
+ 'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
+ [('name', '=', item['cutting_width_depth'])]).id,
+ 'blade_diameter': item['blade_diameter'],
+ 'feed_per_tooth': item['feed_per_tooth'],
+ 'active': item['active'],
+ })
+ else:
+ if item['active'] is False:
+ item.write({'active': False})
+ else:
+ self.write({
+ 'materials_type_id': self.env['sf.materials.model'].search(
+ [('materials_no', '=', item['materials_type_code'])]).id,
+ 'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
+ [('name', '=', item['cutting_width_depth'])]).id,
+ 'blade_diameter': item['blade_diameter'],
+ 'feed_per_tooth': item['feed_per_tooth'], })
+ else:
+ raise ValidationError("每齿走刀量认证未通过")
+
+
class Cutting_tool_standard_library(models.Model):
_inherit = 'sf.cutting_tool.standard.library'
_description = '刀具标准库'
@@ -1922,7 +2218,8 @@ class Cutting_tool_standard_library(models.Model):
if result['status'] == 1:
for item in result['cutting_tool_standard_library_yesterday_list']:
cutting_tool_standard_library = self.search(
- [("code", '=', item['code'].replace("JKM", result['factory_short_name']))])
+ [("code", '=', item['code'].replace("JKM", result['factory_short_name'])),
+ ('active', 'in', [True, False])])
cutting_tool_type = self.env['sf.cutting.tool.type'].search(
[("code", '=', item['cutting_tool_type_code'])])
cutting_tool_material = self.env['sf.cutting.tool.material'].search(
@@ -1930,54 +2227,6 @@ class Cutting_tool_standard_library(models.Model):
materials_model = self.env['sf.materials.model'].search(
[("materials_no", '=', item['material_model_code'])])
brand = self.env['sf.machine.brand'].search([("code", '=', item['brand_code'])])
- integral_tool_basic_param_list = []
- for integral_tool_item in item['integral_tool_basic_parameter']:
- integral_tool_basic_param_list.append(
- self.env['sf.tool.materials.basic.parameters']._json_integral_tool_basic_param(
- integral_tool_item))
- blade_basic_param_list = []
- for blade_item in item['blade_basic_parameter']:
- blade_basic_param_list.append(
- self.env['sf.tool.materials.basic.parameters']._json_blade_basic_param(blade_item))
- cutter_arbor_basic_param_list = []
- for cutter_arbor_item in item['cutter_arbor_basic_parameter']:
- cutter_arbor_basic_param_list.append(
- self.env['sf.tool.materials.basic.parameters']._json_cutter_arbor_basic_param(
- cutter_arbor_item))
- cutter_head_basic_param_list = []
- for cutter_head_item in item['cutter_head_basic_parameter']:
- cutter_head_basic_param_list.append(
- self.env['sf.tool.materials.basic.parameters']._json_cutter_head_basic_param(cutter_head_item))
- knife_handle_basic_param_list = []
- for knife_handle_item in item['knife_handle_basic_parameter']:
- knife_handle_basic_param_list.append(
- self.env['sf.tool.materials.basic.parameters']._json_knife_handle_basic_param(
- knife_handle_item))
- chuck_basic_param_list = []
- for chuck_item in item['chuck_basic_parameter']:
- chuck_basic_param_list.append(
- self.env['sf.tool.materials.basic.parameters']._json_chuck_basic_param(chuck_item))
- cutting_speed_list = []
- for cutting_speed_item in item['cutting_speed']:
- cutting_speed_list.append(
- self.env['sf.cutting.speed']._json_cutting_speed(cutting_speed_item))
- feed_per_tooth_list = []
- for feed_per_tooth_item in item['feed_per_tooth']:
- feed_per_tooth_list.append(
- self.env['sf.feed.per.tooth']._json_feed_per_tooth(feed_per_tooth_item))
- feed_per_tooth_2_list = []
- for feed_per_tooth_2_item in item['feed_per_tooth_2']:
- feed_per_tooth_2_list.append(
- self.env['sf.feed.per.tooth']._json_feed_per_tooth(feed_per_tooth_2_item))
- feed_per_tooth_3_list = []
- for feed_per_tooth_3_item in item['feed_per_tooth_3']:
- feed_per_tooth_3_list.append(
- self.env['sf.feed.per.tooth']._json_feed_per_tooth(feed_per_tooth_3_item))
- feed_per_tooth_4_list = []
- for feed_per_tooth_4_item in item['feed_per_tooth_4']:
- feed_per_tooth_4_list.append(
- self.env['sf.feed.per.tooth']._json_feed_per_tooth(feed_per_tooth_4_item))
-
if not cutting_tool_standard_library:
self.create({
"code": item['code'].replace("JKM", result['factory_short_name']),
@@ -2001,6 +2250,10 @@ class Cutting_tool_standard_library(models.Model):
"fit_blade_shape_id": False if not item['fit_blade_shape'] else self.env[
'maintenance.equipment.image'].search(
[('name', '=', item['fit_blade_shape'])]).id,
+ "chuck_id": False if not item['chuck_code'] else self.search(
+ [('code', '=', item['chuck_code'].replace("JKM", result['factory_short_name']))]).id,
+ "handle_id": False if not item['handle_code'] else self.search(
+ [('code', '=', item['handle_code'].replace("JKM", result['factory_short_name']))]).id,
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
'suitable_machining_methods') else self.env['maintenance.equipment.image']._get_ids(
item['suitable_machining_methods']),
@@ -2014,17 +2267,6 @@ class Cutting_tool_standard_library(models.Model):
'maintenance.equipment.image']._get_ids(item['suitable_coolant']),
"compaction_way_id": self.env['maintenance.equipment.image'].search(
[('name', '=', item['compaction_way'])]).id,
- "integral_tool_basic_parameters_ids": integral_tool_basic_param_list,
- "blade_basic_parameters_ids": blade_basic_param_list,
- "cutter_bar_basic_parameters_ids": cutter_arbor_basic_param_list,
- "cutter_head_basic_parameters_ids": cutter_head_basic_param_list,
- "knife_handle_basic_parameters_ids": knife_handle_basic_param_list,
- "chuck_basic_parameters_ids": chuck_basic_param_list,
- "cutting_speed_ids": cutting_speed_list,
- "feed_per_tooth_ids": feed_per_tooth_list,
- "feed_per_tooth_ids_2": feed_per_tooth_2_list,
- "feed_per_tooth_ids_3": feed_per_tooth_3_list,
- "feed_per_tooth_ids_4": feed_per_tooth_4_list,
"is_cloud": True,
"active": item['active'],
})
@@ -2050,6 +2292,10 @@ class Cutting_tool_standard_library(models.Model):
"fit_blade_shape_id": False if not item['fit_blade_shape'] else self.env[
'maintenance.equipment.image'].search(
[('name', '=', item['fit_blade_shape'])]).id,
+ "chuck_id": False if not item['chuck_code'] else self.search(
+ [('code', '=', item['chuck_code'].replace("JKM", result['factory_short_name']))]).id,
+ "handle_id": False if not item['handle_code'] else self.search(
+ [('code', '=', item['handle_code'].replace("JKM", result['factory_short_name']))]).id,
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
'suitable_machining_methods') else self.env['maintenance.equipment.image']._get_ids(
item['suitable_machining_methods']),
@@ -2063,17 +2309,6 @@ class Cutting_tool_standard_library(models.Model):
'maintenance.equipment.image']._get_ids(item['suitable_coolant']),
"compaction_way_id": self.env['maintenance.equipment.image'].search(
[('name', '=', item['compaction_way'])]).id,
- "integral_tool_basic_parameters_ids": integral_tool_basic_param_list,
- "blade_basic_parameters_ids": blade_basic_param_list,
- "cutter_bar_basic_parameters_ids": cutter_arbor_basic_param_list,
- "cutter_head_basic_parameters_ids": cutter_head_basic_param_list,
- "knife_handle_basic_parameters_ids": knife_handle_basic_param_list,
- "chuck_basic_parameters_ids": chuck_basic_param_list,
- "cutting_speed_ids": cutting_speed_list,
- "feed_per_tooth_ids": feed_per_tooth_list,
- "feed_per_tooth_ids_2": feed_per_tooth_2_list,
- "feed_per_tooth_ids_3": feed_per_tooth_3_list,
- "feed_per_tooth_ids_4": feed_per_tooth_4_list,
"active": item['active'],
})
else:
@@ -2090,7 +2325,8 @@ class Cutting_tool_standard_library(models.Model):
if result['status'] == 1:
for item in result['cutting_tool_standard_library_all_list']:
cutting_tool_standard_library = self.search(
- [("code", '=', item['code'].replace("JKM", result['factory_short_name']))])
+ [("code", '=', item['code'].replace("JKM", result['factory_short_name'])),
+ ("active", 'in', [True, False])])
cutting_tool_type = self.env['sf.cutting.tool.type'].search(
[("code", '=', item['cutting_tool_type_code'])])
cutting_tool_material = self.env['sf.cutting.tool.material'].search(
@@ -2098,53 +2334,6 @@ class Cutting_tool_standard_library(models.Model):
materials_model = self.env['sf.materials.model'].search(
[("materials_no", '=', item['material_model_code'])])
brand = self.env['sf.machine.brand'].search([("code", '=', item['brand_code'])])
- integral_tool_basic_param_list = []
- for integral_tool_item in item['integral_tool_basic_parameter']:
- integral_tool_basic_param_list.append(
- self.env['sf.tool.materials.basic.parameters']._json_integral_tool_basic_param(
- integral_tool_item))
- blade_basic_param_list = []
- for blade_item in item['blade_basic_parameter']:
- blade_basic_param_list.append(
- self.env['sf.tool.materials.basic.parameters']._json_blade_basic_param(blade_item))
- cutter_arbor_basic_param_list = []
- for cutter_arbor_item in item['cutter_arbor_basic_parameter']:
- cutter_arbor_basic_param_list.append(
- self.env['sf.tool.materials.basic.parameters']._json_cutter_arbor_basic_param(
- cutter_arbor_item))
- cutter_head_basic_param_list = []
- for cutter_head_item in item['cutter_head_basic_parameter']:
- cutter_head_basic_param_list.append(
- self.env['sf.tool.materials.basic.parameters']._json_cutter_head_basic_param(cutter_head_item))
- knife_handle_basic_param_list = []
- for knife_handle_item in item['knife_handle_basic_parameter']:
- knife_handle_basic_param_list.append(
- self.env['sf.tool.materials.basic.parameters']._json_knife_handle_basic_param(
- knife_handle_item))
- chuck_basic_param_list = []
- for chuck_item in item['chuck_basic_parameter']:
- chuck_basic_param_list.append(
- self.env['sf.tool.materials.basic.parameters']._json_chuck_basic_param(chuck_item))
- cutting_speed_list = []
- for cutting_speed_item in item['cutting_speed']:
- cutting_speed_list.append(
- self.env['sf.cutting.speed']._json_cutting_speed(cutting_speed_item))
- feed_per_tooth_list = []
- for feed_per_tooth_item in item['feed_per_tooth']:
- feed_per_tooth_list.append(
- self.env['sf.feed.per.tooth']._json_feed_per_tooth(feed_per_tooth_item))
- feed_per_tooth_2_list = []
- for feed_per_tooth_2_item in item['feed_per_tooth_2']:
- feed_per_tooth_2_list.append(
- self.env['sf.feed.per.tooth']._json_feed_per_tooth_2(feed_per_tooth_2_item))
- feed_per_tooth_3_list = []
- for feed_per_tooth_3_item in item['feed_per_tooth_3']:
- feed_per_tooth_3_list.append(
- self.env['sf.feed.per.tooth']._json_feed_per_tooth_3(feed_per_tooth_3_item))
- feed_per_tooth_4_list = []
- for feed_per_tooth_4_item in item['feed_per_tooth_4']:
- feed_per_tooth_4_list.append(
- self.env['sf.feed.per.tooth']._json_feed_per_tooth_4(feed_per_tooth_4_item))
if not cutting_tool_standard_library:
self.create({
"code": item['code'].replace("JKM", result['factory_short_name']),
@@ -2168,6 +2357,10 @@ class Cutting_tool_standard_library(models.Model):
"fit_blade_shape_id": False if not item['fit_blade_shape'] else self.env[
'maintenance.equipment.image'].search(
[('name', '=', item['fit_blade_shape'])]).id,
+ "chuck_id": False if not item['chuck_code'] else self.search(
+ [('code', '=', item['chuck_code'].replace("JKM", result['factory_short_name']))]).id,
+ "handle_id": False if not item['handle_code'] else self.search(
+ [('code', '=', item['handle_code'].replace("JKM", result['factory_short_name']))]).id,
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
'suitable_machining_method') else self.env['maintenance.equipment.image']._get_ids(
item['suitable_machining_method']),
@@ -2181,17 +2374,6 @@ class Cutting_tool_standard_library(models.Model):
'maintenance.equipment.image']._get_ids(item['suitable_coolant']),
"compaction_way_id": self.env['maintenance.equipment.image'].search(
[('name', '=', item['compaction_way'])]).id,
- "integral_tool_basic_parameters_ids": integral_tool_basic_param_list,
- "blade_basic_parameters_ids": blade_basic_param_list,
- "cutter_bar_basic_parameters_ids": cutter_arbor_basic_param_list,
- "cutter_head_basic_parameters_ids": cutter_head_basic_param_list,
- "knife_handle_basic_parameters_ids": knife_handle_basic_param_list,
- "chuck_basic_parameters_ids": chuck_basic_param_list,
- "cutting_speed_ids": cutting_speed_list,
- "feed_per_tooth_ids": feed_per_tooth_list,
- "feed_per_tooth_ids_2": feed_per_tooth_2_list,
- "feed_per_tooth_ids_3": feed_per_tooth_3_list,
- "feed_per_tooth_ids_4": feed_per_tooth_4_list,
"is_cloud": True,
"active": item['active'],
})
@@ -2217,6 +2399,10 @@ class Cutting_tool_standard_library(models.Model):
"fit_blade_shape_id": False if not item['fit_blade_shape'] else self.env[
'maintenance.equipment.image'].search(
[('name', '=', item['fit_blade_shape'])]).id,
+ "chuck_id": False if not item['chuck_code'] else self.search(
+ [('code', '=', item['chuck_code'].replace("JKM", result['factory_short_name']))]).id,
+ "handle_id": False if not item['handle_code'] else self.search(
+ [('code', '=', item['handle_code'].replace("JKM", result['factory_short_name']))]).id,
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
'suitable_machining_methods') else self.env['maintenance.equipment.image']._get_ids(
item['suitable_machining_methods']),
@@ -2230,18 +2416,746 @@ class Cutting_tool_standard_library(models.Model):
'maintenance.equipment.image']._get_ids(item['suitable_coolant']),
"compaction_way_id": self.env['maintenance.equipment.image'].search(
[('name', '=', item['compaction_way'])]).id,
- "integral_tool_basic_parameters_ids": integral_tool_basic_param_list,
- "blade_basic_parameters_ids": blade_basic_param_list,
- "cutter_bar_basic_parameters_ids": cutter_arbor_basic_param_list,
- "cutter_head_basic_parameters_ids": cutter_head_basic_param_list,
- "knife_handle_basic_parameters_ids": knife_handle_basic_param_list,
- "chuck_basic_parameters_ids": chuck_basic_param_list,
- "cutting_speed_ids": cutting_speed_list,
- "feed_per_tooth_ids": feed_per_tooth_list,
- "feed_per_tooth_ids_2": feed_per_tooth_2_list,
- "feed_per_tooth_ids_3": feed_per_tooth_3_list,
- "feed_per_tooth_ids_4": feed_per_tooth_4_list,
"active": item['active'],
})
else:
raise ValidationError("刀具标准库认证未通过")
+
+
+class CuttingToolBasicParameters(models.Model):
+ _inherit = 'sf.tool.materials.basic.parameters'
+ _description = '刀具基本参数'
+ url = '/api/cutting_tool_basic_parameters/list'
+
+ # 同步刀具基本参数
+ def sync_all_cutting_tool_basic_parameters(self):
+ config = self.env['res.config.settings'].get_values()
+ headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
+ strUrl = config['sf_url'] + self.url
+ r = requests.post(strUrl, json={}, data=None, headers=headers)
+ r = r.json()
+ result = json.loads(r['result'])
+ if result['status'] == 1:
+ if 'basic_parameters_integral_tool' in result['cutting_tool_basic_parameters_all_list']:
+ basic_parameters_integral_tool_list = json.loads(
+ result['cutting_tool_basic_parameters_all_list']['basic_parameters_integral_tool'])
+ if basic_parameters_integral_tool_list:
+ for integral_tool_item in basic_parameters_integral_tool_list:
+ integral_tool = self.search(
+ [('code', '=', integral_tool_item['code']), ('active', 'in', [True, False])])
+ if not integral_tool:
+ self.create({
+ 'name': integral_tool_item['name'],
+ 'code': integral_tool_item['code'],
+ 'cutting_tool_type': '整体式刀具',
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', integral_tool_item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'total_length': integral_tool_item['total_length'],
+ 'blade_diameter': integral_tool_item['blade_diameter'],
+ 'blade_length': integral_tool_item['blade_length'],
+ 'blade_number': integral_tool_item['blade_number'],
+ 'neck_length': integral_tool_item['neck_length'],
+ 'neck_diameter': integral_tool_item['neck_diameter'],
+ 'handle_diameter': integral_tool_item['shank_diameter'],
+ 'handle_length': integral_tool_item['shank_length'],
+ 'blade_tip_diameter': integral_tool_item['tip_diameter'],
+ 'blade_tip_working_size': integral_tool_item['tip_handling_size'],
+ 'blade_tip_taper': integral_tool_item['knife_tip_taper'],
+ 'blade_helix_angle': integral_tool_item['blade_helix_angle'],
+ 'blade_width': integral_tool_item['blade_width'],
+ 'blade_depth': integral_tool_item['blade_depth'],
+ 'pitch': integral_tool_item['pitch'],
+ 'cutting_depth': integral_tool_item['cutting_depth_max'],
+ 'active': integral_tool_item['active'],
+ })
+ else:
+ self.write({
+ 'name': integral_tool_item['name'],
+ 'total_length': integral_tool_item['total_length'],
+ 'blade_diameter': integral_tool_item['blade_diameter'],
+ 'blade_length': integral_tool_item['blade_length'],
+ 'blade_number': integral_tool_item['blade_number'],
+ 'neck_length': integral_tool_item['neck_length'],
+ 'neck_diameter': integral_tool_item['neck_diameter'],
+ 'handle_diameter': integral_tool_item['shank_diameter'],
+ 'handle_length': integral_tool_item['shank_length'],
+ 'blade_tip_diameter': integral_tool_item['tip_diameter'],
+ 'blade_tip_working_size': integral_tool_item['tip_handling_size'],
+ 'blade_tip_taper': integral_tool_item['knife_tip_taper'],
+ 'blade_helix_angle': integral_tool_item['blade_helix_angle'],
+ 'blade_width': integral_tool_item['blade_width'],
+ 'blade_depth': integral_tool_item['blade_depth'],
+ 'pitch': integral_tool_item['pitch'],
+ 'cutting_depth': integral_tool_item['cutting_depth_max'],
+ 'active': integral_tool_item['active'],
+ })
+ if 'basic_parameters_blade' in result['cutting_tool_basic_parameters_all_list']:
+ basic_parameters_blade_list = json.loads(
+ result['cutting_tool_basic_parameters_all_list']['basic_parameters_blade'])
+ if basic_parameters_blade_list:
+ for blade_item in basic_parameters_blade_list:
+ blade = self.search([('code', '=', blade_item['code']), ('active', 'in', [True, False])])
+ if not blade:
+ self.create({
+ 'name': blade_item['name'],
+ 'code': blade_item['code'],
+ 'cutting_tool_type': '刀片',
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', blade_item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'length': blade_item['length'],
+ 'thickness': blade_item['thickness'],
+ 'cutting_blade_length': blade_item['cutting_blade_length'],
+ 'relief_angle': blade_item['relief_angle'],
+ 'blade_tip_circular_arc_radius': blade_item['radius_tip_re'],
+ 'inscribed_circle_diameter': blade_item['diameter_inner_circle'],
+ 'install_aperture_diameter': blade_item['diameter_mounting_hole'],
+ 'pitch': blade_item['pitch'],
+ 'chip_breaker_groove': blade_item['is_chip_breaker'],
+ 'chip_breaker_type_code': blade_item['chip_breaker_type_code'],
+ 'blade_teeth_model': '无' if not blade_item['blade_profile'] else blade_item[
+ 'blade_profile'],
+ 'blade_blade_number': blade_item['blade_number'],
+ 'cutting_depth': blade_item['cutting_depth_max'],
+ 'blade_width': blade_item['blade_width'],
+ 'main_included_angle': blade_item['edge_angle'],
+ 'top_angle': blade_item['top_angle'],
+ 'thread_model': '无' if not blade_item['thread_type'] else blade_item['thread_type'],
+ 'thread_num': blade_item['threads_per_inch'],
+ 'blade_tip_height_tolerance': blade_item['tip_height_tolerance'],
+ 'inscribed_circle_tolerance': blade_item['internal_circle_tolerance'],
+ 'thickness_tolerance': blade_item['thickness_tolerance'],
+ 'active': blade_item['active'],
+ })
+ else:
+ self.write({
+ 'name': integral_tool_item['name'],
+ 'length': blade_item['length'],
+ 'thickness': blade_item['thickness'],
+ 'cutting_blade_length': blade_item['cutting_blade_length'],
+ 'relief_angle': blade_item['relief_angle'],
+ 'blade_tip_circular_arc_radius': blade_item['radius_tip_re'],
+ 'inscribed_circle_diameter': blade_item['diameter_inner_circle'],
+ 'install_aperture_diameter': blade_item['diameter_mounting_hole'],
+ 'pitch': blade_item['pitch'],
+ 'chip_breaker_groove': blade_item['is_chip_breaker'],
+ 'chip_breaker_type_code': blade_item['chip_breaker_type_code'],
+ 'blade_teeth_model': '无' if not blade_item['blade_profile'] else blade_item[
+ 'blade_profile'],
+ 'blade_blade_number': blade_item['blade_number'],
+ 'cutting_depth': blade_item['cutting_depth_max'],
+ 'blade_width': blade_item['blade_width'],
+ 'main_included_angle': blade_item['edge_angle'],
+ 'top_angle': blade_item['top_angle'],
+ 'thread_model': '无' if not blade_item['thread_type'] else blade_item['thread_type'],
+ 'thread_num': blade_item['threads_per_inch'],
+ 'blade_tip_height_tolerance': blade_item['tip_height_tolerance'],
+ 'inscribed_circle_tolerance': blade_item['internal_circle_tolerance'],
+ 'thickness_tolerance': blade_item['thickness_tolerance'],
+ 'active': blade_item['active'],
+ })
+ if 'basic_parameters_chuck' in result['cutting_tool_basic_parameters_all_list']:
+ basic_parameters_chuck_list = json.loads(
+ result['cutting_tool_basic_parameters_all_list']['basic_parameters_chuck'])
+ if basic_parameters_chuck_list:
+ for chuck_item in basic_parameters_chuck_list:
+ chuck = self.search([('code', '=', chuck_item['code']), ('active', 'in', [True, False])])
+ if not chuck:
+ self.create({
+ 'name': chuck_item['name'],
+ 'code': chuck_item['code'],
+ 'cutting_tool_type': '夹头',
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', chuck_item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'er_size_model': chuck_item['size_model'],
+ 'min_clamping_diameter': chuck_item['clamping_diameter_min'],
+ 'max_clamping_diameter': chuck_item['clamping_diameter_max'],
+ 'outer_diameter': chuck_item['outer_diameter'],
+ 'inner_diameter': chuck_item['inner_diameter'],
+ 'run_out_accuracy': chuck_item['run_out_accuracy'],
+ 'total_length': chuck_item['total_length'],
+ 'taper': chuck_item['taper'],
+ 'top_diameter': chuck_item['top_diameter'],
+ 'weight': chuck_item['weight'],
+ 'max_load_capacity': chuck_item['load_capacity_max'],
+ 'cooling_jacket': chuck_item['cooling_sleeve_model'],
+ 'active': chuck_item['active'],
+ })
+ else:
+ self.write({
+ 'name': integral_tool_item['name'],
+ 'er_size_model': chuck_item['size_model'],
+ 'min_clamping_diameter': chuck_item['clamping_diameter_min'],
+ 'max_clamping_diameter': chuck_item['clamping_diameter_max'],
+ 'outer_diameter': chuck_item['outer_diameter'],
+ 'inner_diameter': chuck_item['inner_diameter'],
+ 'run_out_accuracy': chuck_item['run_out_accuracy'],
+ 'total_length': chuck_item['total_length'],
+ 'taper': chuck_item['taper'],
+ 'top_diameter': chuck_item['top_diameter'],
+ 'weight': chuck_item['weight'],
+ 'max_load_capacity': chuck_item['load_capacity_max'],
+ 'cooling_jacket': chuck_item['cooling_sleeve_model'],
+ 'active': chuck_item['active'],
+ })
+ if 'basic_parameters_cutter_arbor' in result['cutting_tool_basic_parameters_all_list']:
+ basic_parameters_cutter_arbor_list = json.loads(
+ result['cutting_tool_basic_parameters_all_list']['basic_parameters_cutter_arbor'])
+ if basic_parameters_cutter_arbor_list:
+ for cutter_arbor_item in basic_parameters_cutter_arbor_list:
+ cutter_arbor = self.search(
+ [('code', '=', cutter_arbor_item['code']), ('active', 'in', [True, False])])
+ if not cutter_arbor:
+ self.create({
+ 'name': cutter_arbor_item['name'],
+ 'code': cutter_arbor_item['code'],
+ 'cutting_tool_type': '刀杆',
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', cutter_arbor_item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'height': cutter_arbor_item['height'],
+ 'width': cutter_arbor_item['width'],
+ 'total_length': cutter_arbor_item['total_length'],
+ 'knife_head_height': cutter_arbor_item['head_length'],
+ 'knife_head_width': cutter_arbor_item['head_width'],
+ 'knife_head_length': cutter_arbor_item['head_length'],
+ 'cutter_arbor_diameter': cutter_arbor_item['arbor_diameter'],
+ 'main_included_angle': cutter_arbor_item['edge_angle'],
+ 'relief_angle': cutter_arbor_item['relief_angle'],
+ 'cutting_depth': cutter_arbor_item['cutting_depth_max'],
+ 'min_machining_aperture': cutter_arbor_item['machining_aperture_min'],
+ 'install_blade_tip_num': cutter_arbor_item['number_blade_installed'],
+ 'is_cooling_hole': cutter_arbor_item['is_cooling_hole'],
+ 'locating_slot_code': cutter_arbor_item['locator_slot_code'],
+ 'installing_structure': cutter_arbor_item['mounting_structure'],
+ 'blade_id': False if not cutter_arbor_item['fit_blade_model_code'] else self.env[
+ 'sf.cutting_tool.standard.library'].search(
+ [('code', '=', cutter_arbor_item['fit_blade_model_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
+ 'cotter_pin': cutter_arbor_item['fit_pin_model'],
+ 'pressing_plate': cutter_arbor_item['fit_plate_model'],
+ 'screw': cutter_arbor_item['fit_screw_model'],
+ 'spanner': cutter_arbor_item['fit_wrench_model'],
+ 'active': cutter_arbor_item['active'],
+ })
+ else:
+ self.write({
+ 'name': cutter_arbor_item['name'],
+ 'height': cutter_arbor_item['height'],
+ 'width': cutter_arbor_item['width'],
+ 'total_length': cutter_arbor_item['total_length'],
+ 'knife_head_height': cutter_arbor_item['head_length'],
+ 'knife_head_width': cutter_arbor_item['head_width'],
+ 'knife_head_length': cutter_arbor_item['head_length'],
+ 'cutter_arbor_diameter': cutter_arbor_item['arbor_diameter'],
+ 'main_included_angle': cutter_arbor_item['edge_angle'],
+ 'relief_angle': cutter_arbor_item['relief_angle'],
+ 'cutting_depth': cutter_arbor_item['cutting_depth_max'],
+ 'min_machining_aperture': cutter_arbor_item['machining_aperture_min'],
+ 'install_blade_tip_num': cutter_arbor_item['number_blade_installed'],
+ 'is_cooling_hole': cutter_arbor_item['is_cooling_hole'],
+ 'locating_slot_code': cutter_arbor_item['locator_slot_code'],
+ 'installing_structure': cutter_arbor_item['mounting_structure'],
+ 'blade_id': False if not cutter_arbor_item['fit_blade_model_code'] else self.env[
+ 'sf.cutting_tool.standard.library'].search(
+ [('code', '=', cutter_arbor_item['fit_blade_model_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
+ 'cotter_pin': cutter_arbor_item['fit_pin_model'],
+ 'pressing_plate': cutter_arbor_item['fit_plate_model'],
+ 'screw': cutter_arbor_item['fit_screw_model'],
+ 'spanner': cutter_arbor_item['fit_wrench_model'],
+ 'active': cutter_arbor_item['active'],
+ })
+ if 'basic_parameters_cutter_head' in result['cutting_tool_basic_parameters_all_list']:
+ basic_parameters_cutter_head_list = json.loads(
+ result['cutting_tool_basic_parameters_all_list']['basic_parameters_cutter_head'])
+ if basic_parameters_cutter_head_list:
+ for cutter_head_item in basic_parameters_cutter_head_list:
+ cutter_head = self.search(
+ [('code', '=', cutter_head_item['code']), ('active', 'in', [True, False])])
+ if not cutter_head:
+ self.create({
+ 'name': cutter_head_item['name'],
+ 'code': cutter_head_item['code'],
+ 'cutting_tool_type': '刀盘',
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', cutter_head_item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'install_blade_tip_num': cutter_head_item['number_blade_installed'],
+ 'blade_diameter': cutter_head_item['blade_diameter'],
+ 'cutter_head_diameter': cutter_head_item['cutter_diameter'],
+ 'interface_diameter': cutter_head_item['interface_diameter'],
+ 'total_length': cutter_head_item['total_length'],
+ 'blade_length': cutter_head_item['blade_length'],
+ 'cutting_depth': cutter_head_item['cutting_depth_max'],
+ 'main_included_angle': cutter_head_item['edge_angle'],
+ 'installing_structure': cutter_head_item['mounting_structure'],
+ 'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
+ 'sf.cutting_tool.standard.library'].search(
+ [('code', '=', cutter_head_item['fit_blade_model_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'screw': cutter_head_item['fit_screw_model'],
+ 'spanner': cutter_head_item['fit_wrench_model'],
+ 'is_cooling_hole': cutter_head_item['is_cooling_hole'],
+ 'locating_slot_code': cutter_head_item['locator_slot_code'],
+ 'active': cutter_head_item['active'],
+ })
+ else:
+ self.write({
+ 'name': cutter_head_item['name'],
+ 'install_blade_tip_num': cutter_head_item['number_blade_installed'],
+ 'blade_diameter': cutter_head_item['blade_diameter'],
+ 'cutter_head_diameter': cutter_head_item['cutter_diameter'],
+ 'interface_diameter': cutter_head_item['interface_diameter'],
+ 'total_length': cutter_head_item['total_length'],
+ 'blade_length': cutter_head_item['blade_length'],
+ 'cutting_depth': cutter_head_item['cutting_depth_max'],
+ 'main_included_angle': cutter_head_item['edge_angle'],
+ 'installing_structure': cutter_head_item['mounting_structure'],
+ 'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
+ 'sf.cutting_tool.standard.library'].search(
+ [('code', '=', cutter_head_item['fit_blade_model_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'screw': cutter_head_item['fit_screw_model'],
+ 'spanner': cutter_head_item['fit_wrench_model'],
+ 'is_cooling_hole': cutter_head_item['is_cooling_hole'],
+ 'locating_slot_code': cutter_head_item['locator_slot_code'],
+ 'active': cutter_head_item['active'],
+ })
+ if 'basic_parameters_knife_handle' in result['cutting_tool_basic_parameters_all_list']:
+ basic_parameters_knife_handle_list = json.loads(
+ result['cutting_tool_basic_parameters_all_list']['basic_parameters_knife_handle'])
+ if basic_parameters_knife_handle_list:
+ for knife_handle_item in basic_parameters_knife_handle_list:
+ knife_handle = self.search(
+ [('code', '=', knife_handle_item['code']), ('active', 'in', [True, False])])
+ if not knife_handle:
+ self.create({
+ 'name': knife_handle_item['name'],
+ 'code': knife_handle_item['code'],
+ 'cutting_tool_type': '刀柄',
+ 'taper_shank_model': knife_handle_item['taper_shank_model'],
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', knife_handle_item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'total_length': knife_handle_item['total_length'],
+ 'flange_shank_length': knife_handle_item['flange_length'],
+ 'flange_diameter': knife_handle_item['flange_diameter'],
+ 'shank_length': knife_handle_item['shank_length'],
+ 'shank_diameter': knife_handle_item['shank_diameter'],
+ 'min_clamping_diameter': knife_handle_item['clamping_diameter_min'],
+ 'max_clamping_diameter': knife_handle_item['clamping_diameter_max'],
+ 'clamping_mode': knife_handle_item['clamping_way'],
+ 'tool_changing_time': knife_handle_item['tool_changing_time'],
+ 'max_rotate_speed': knife_handle_item['rotate_speed_max'],
+ 'diameter_slip_accuracy': knife_handle_item['diameter_slip_accuracy'],
+ 'cooling_model': knife_handle_item['cooling_model'],
+ 'is_quick_cutting': knife_handle_item['is_quick_cutting'],
+ 'is_safe_lock': knife_handle_item['is_safe_lock'],
+ 'screw': knife_handle_item['fit_wrench_model'],
+ 'nut': knife_handle_item['fit_nut_model'],
+ 'dynamic_balance_class': knife_handle_item['dynamic_balance_class'],
+ 'active': knife_handle_item['active'],
+ })
+ else:
+ self.write({
+ 'name': knife_handle_item['name'],
+ 'taper_shank_model': knife_handle_item['taper_shank_model'],
+ 'total_length': knife_handle_item['total_length'],
+ 'flange_shank_length': knife_handle_item['flange_length'],
+ 'flange_diameter': knife_handle_item['flange_diameter'],
+ 'shank_length': knife_handle_item['shank_length'],
+ 'shank_diameter': knife_handle_item['shank_diameter'],
+ 'min_clamping_diameter': knife_handle_item['clamping_diameter_min'],
+ 'max_clamping_diameter': knife_handle_item['clamping_diameter_max'],
+ 'clamping_mode': knife_handle_item['clamping_way'],
+ 'tool_changing_time': knife_handle_item['tool_changing_time'],
+ 'max_rotate_speed': knife_handle_item['rotate_speed_max'],
+ 'diameter_slip_accuracy': knife_handle_item['diameter_slip_accuracy'],
+ 'cooling_model': knife_handle_item['cooling_model'],
+ 'is_quick_cutting': knife_handle_item['is_quick_cutting'],
+ 'is_safe_lock': knife_handle_item['is_safe_lock'],
+ 'screw': knife_handle_item['fit_wrench_model'],
+ 'nut': knife_handle_item['fit_nut_model'],
+ 'dynamic_balance_class': knife_handle_item['dynamic_balance_class'],
+ 'active': knife_handle_item['active'],
+ })
+ else:
+ raise ValidationError("刀具物料基本参数认证未通过")
+
+ def sync_cutting_tool_basic_parameters_yesterday(self):
+ config = self.env['res.config.settings'].get_values()
+ headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
+ strUrl = config['sf_url'] + self.url
+ r = requests.post(strUrl, json={}, data=None, headers=headers)
+ r = r.json()
+ result = json.loads(r['result'])
+ if result['status'] == 1:
+ if 'basic_parameters_integral_tool' in result['cutting_tool_basic_parameters_yesterday_list']:
+ basic_parameters_integral_tool_list = json.loads(
+ result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_integral_tool'])
+ if basic_parameters_integral_tool_list:
+ for integral_tool_item in basic_parameters_integral_tool_list:
+ integral_tool = self.search(
+ [('code', '=', integral_tool_item['code']), ('active', 'in', [True, False])])
+ if not integral_tool:
+ self.create({
+ 'name': integral_tool_item['name'],
+ 'code': integral_tool_item['code'],
+ 'cutting_tool_type': '整体式刀具',
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', integral_tool_item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'total_length': integral_tool_item['total_length'],
+ 'blade_diameter': integral_tool_item['blade_diameter'],
+ 'blade_length': integral_tool_item['blade_length'],
+ 'blade_number': integral_tool_item['blade_number'],
+ 'neck_length': integral_tool_item['neck_length'],
+ 'neck_diameter': integral_tool_item['neck_diameter'],
+ 'handle_diameter': integral_tool_item['shank_diameter'],
+ 'handle_length': integral_tool_item['shank_length'],
+ 'blade_tip_diameter': integral_tool_item['tip_diameter'],
+ 'blade_tip_working_size': integral_tool_item['tip_handling_size'],
+ 'blade_tip_taper': integral_tool_item['knife_tip_taper'],
+ 'blade_helix_angle': integral_tool_item['blade_helix_angle'],
+ 'blade_width': integral_tool_item['blade_width'],
+ 'blade_depth': integral_tool_item['blade_depth'],
+ 'pitch': integral_tool_item['pitch'],
+ 'cutting_depth': integral_tool_item['cutting_depth_max'],
+ 'active': integral_tool_item['active'],
+ })
+ else:
+ if integral_tool_item['active'] is False:
+ integral_tool.write({'active': False})
+ else:
+ self.write({
+ 'name': integral_tool_item['name'],
+ 'total_length': integral_tool_item['total_length'],
+ 'blade_diameter': integral_tool_item['blade_diameter'],
+ 'blade_length': integral_tool_item['blade_length'],
+ 'blade_number': integral_tool_item['blade_number'],
+ 'neck_length': integral_tool_item['neck_length'],
+ 'neck_diameter': integral_tool_item['neck_diameter'],
+ 'handle_diameter': integral_tool_item['shank_diameter'],
+ 'handle_length': integral_tool_item['shank_length'],
+ 'blade_tip_diameter': integral_tool_item['tip_diameter'],
+ 'blade_tip_working_size': integral_tool_item['tip_handling_size'],
+ 'blade_tip_taper': integral_tool_item['knife_tip_taper'],
+ 'blade_helix_angle': integral_tool_item['blade_helix_angle'],
+ 'blade_width': integral_tool_item['blade_width'],
+ 'blade_depth': integral_tool_item['blade_depth'],
+ 'pitch': integral_tool_item['pitch'],
+ 'cutting_depth': integral_tool_item['cutting_depth_max'],
+ 'active': integral_tool_item['active'],
+ })
+ if 'basic_parameters_blade' in result['cutting_tool_basic_parameters_yesterday_list']:
+ basic_parameters_blade_list = json.loads(
+ result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_blade'])
+ if basic_parameters_blade_list:
+ for blade_item in basic_parameters_blade_list:
+ blade = self.search([('code', '=', blade_item['code']), ('active', 'in', [True, False])])
+ if not blade:
+ self.create({
+ 'name': blade_item['name'],
+ 'code': blade_item['code'],
+ 'cutting_tool_type': '刀片',
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', blade_item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'length': blade_item['length'],
+ 'thickness': blade_item['thickness'],
+ 'cutting_blade_length': blade_item['cutting_blade_length'],
+ 'relief_angle': blade_item['relief_angle'],
+ 'blade_tip_circular_arc_radius': blade_item['radius_tip_re'],
+ 'inscribed_circle_diameter': blade_item['diameter_inner_circle'],
+ 'install_aperture_diameter': blade_item['diameter_mounting_hole'],
+ 'pitch': blade_item['pitch'],
+ 'chip_breaker_groove': blade_item['is_chip_breaker'],
+ 'chip_breaker_type_code': blade_item['chip_breaker_type_code'],
+ 'blade_teeth_model': '无' if not blade_item['blade_profile'] else blade_item[
+ 'blade_profile'],
+ 'blade_blade_number': blade_item['blade_number'],
+ 'cutting_depth': blade_item['cutting_depth_max'],
+ 'blade_width': blade_item['blade_width'],
+ 'main_included_angle': blade_item['edge_angle'],
+ 'top_angle': blade_item['top_angle'],
+ 'thread_model': '无' if not blade_item['thread_type'] else blade_item['thread_type'],
+ 'thread_num': blade_item['threads_per_inch'],
+ 'blade_tip_height_tolerance': blade_item['tip_height_tolerance'],
+ 'inscribed_circle_tolerance': blade_item['internal_circle_tolerance'],
+ 'thickness_tolerance': blade_item['thickness_tolerance'],
+ 'active': blade_item['active'],
+ })
+ else:
+ if blade_item['active'] is False:
+ blade.write({'active': False})
+ else:
+ self.write({
+ 'name': blade_item['name'],
+ 'length': blade_item['length'],
+ 'thickness': blade_item['thickness'],
+ 'cutting_blade_length': blade_item['cutting_blade_length'],
+ 'relief_angle': blade_item['relief_angle'],
+ 'blade_tip_circular_arc_radius': blade_item['radius_tip_re'],
+ 'inscribed_circle_diameter': blade_item['diameter_inner_circle'],
+ 'install_aperture_diameter': blade_item['diameter_mounting_hole'],
+ 'pitch': blade_item['pitch'],
+ 'chip_breaker_groove': blade_item['is_chip_breaker'],
+ 'chip_breaker_type_code': blade_item['chip_breaker_type_code'],
+ 'blade_teeth_model': '无' if not blade_item['blade_profile'] else blade_item[
+ 'blade_profile'],
+ 'blade_blade_number': blade_item['blade_number'],
+ 'cutting_depth': blade_item['cutting_depth_max'],
+ 'blade_width': blade_item['blade_width'],
+ 'main_included_angle': blade_item['edge_angle'],
+ 'top_angle': blade_item['top_angle'],
+ 'thread_model': '无' if not blade_item['thread_type'] else blade_item[
+ 'thread_type'],
+ 'thread_num': blade_item['threads_per_inch'],
+ 'blade_tip_height_tolerance': blade_item['tip_height_tolerance'],
+ 'inscribed_circle_tolerance': blade_item['internal_circle_tolerance'],
+ 'thickness_tolerance': blade_item['thickness_tolerance'],
+ })
+ if 'basic_parameters_chuck' in result['cutting_tool_basic_parameters_yesterday_list']:
+ basic_parameters_chuck_list = json.loads(
+ result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_chuck'])
+ if basic_parameters_chuck_list:
+ for chuck_item in basic_parameters_chuck_list:
+ chuck = self.search([('code', '=', chuck_item['code']), ('active', 'in', [True, False])])
+ if not chuck:
+ self.create({
+ 'name': chuck_item['name'],
+ 'code': chuck_item['code'],
+ 'cutting_tool_type': '夹头',
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', chuck_item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'er_size_model': chuck_item['size_model'],
+ 'min_clamping_diameter': chuck_item['clamping_diameter_min'],
+ 'max_clamping_diameter': chuck_item['clamping_diameter_max'],
+ 'outer_diameter': chuck_item['outer_diameter'],
+ 'inner_diameter': chuck_item['inner_diameter'],
+ 'run_out_accuracy': chuck_item['run_out_accuracy'],
+ 'total_length': chuck_item['total_length'],
+ 'taper': chuck_item['taper'],
+ 'top_diameter': chuck_item['top_diameter'],
+ 'weight': chuck_item['weight'],
+ 'max_load_capacity': chuck_item['load_capacity_max'],
+ 'cooling_jacket': chuck_item['cooling_sleeve_model'],
+ 'active': chuck_item['active'],
+ })
+ else:
+ if chuck_item['active'] is False:
+ chuck.write({'active': False})
+ else:
+ self.write({
+ 'name': chuck_item['name'],
+ 'er_size_model': chuck_item['size_model'],
+ 'min_clamping_diameter': chuck_item['clamping_diameter_min'],
+ 'max_clamping_diameter': chuck_item['clamping_diameter_max'],
+ 'outer_diameter': chuck_item['outer_diameter'],
+ 'inner_diameter': chuck_item['inner_diameter'],
+ 'run_out_accuracy': chuck_item['run_out_accuracy'],
+ 'total_length': chuck_item['total_length'],
+ 'taper': chuck_item['taper'],
+ 'top_diameter': chuck_item['top_diameter'],
+ 'weight': chuck_item['weight'],
+ 'max_load_capacity': chuck_item['load_capacity_max'],
+ 'cooling_jacket': chuck_item['cooling_sleeve_model'],
+ })
+ if 'basic_parameters_cutter_arbor' in result['cutting_tool_basic_parameters_yesterday_list']:
+ basic_parameters_cutter_arbor_list = json.loads(
+ result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_arbor'])
+ if basic_parameters_cutter_arbor_list:
+ for cutter_arbor_item in basic_parameters_cutter_arbor_list:
+ cutter_arbor = self.search(
+ [('code', '=', cutter_arbor_item['code']), ('active', 'in', [True, False])])
+ if not cutter_arbor:
+ self.create({
+ 'name': cutter_arbor_item['name'],
+ 'code': cutter_arbor_item['code'],
+ 'cutting_tool_type': '刀杆',
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', cutter_arbor_item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'height': cutter_arbor_item['height'],
+ 'width': cutter_arbor_item['width'],
+ 'total_length': cutter_arbor_item['total_length'],
+ 'knife_head_height': cutter_arbor_item['head_length'],
+ 'knife_head_width': cutter_arbor_item['head_width'],
+ 'knife_head_length': cutter_arbor_item['head_length'],
+ 'cutter_arbor_diameter': cutter_arbor_item['arbor_diameter'],
+ 'main_included_angle': cutter_arbor_item['edge_angle'],
+ 'relief_angle': cutter_arbor_item['relief_angle'],
+ 'cutting_depth': cutter_arbor_item['cutting_depth_max'],
+ 'min_machining_aperture': cutter_arbor_item['machining_aperture_min'],
+ 'install_blade_tip_num': cutter_arbor_item['number_blade_installed'],
+ 'is_cooling_hole': cutter_arbor_item['is_cooling_hole'],
+ 'locating_slot_code': cutter_arbor_item['locator_slot_code'],
+ 'installing_structure': cutter_arbor_item['mounting_structure'],
+ 'blade_id': False if not cutter_arbor_item['fit_blade_model_code'] else self.env[
+ 'sf.cutting_tool.standard.library'].search(
+ [('code', '=', cutter_arbor_item['fit_blade_model_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
+ 'cotter_pin': cutter_arbor_item['fit_pin_model'],
+ 'pressing_plate': cutter_arbor_item['fit_plate_model'],
+ 'screw': cutter_arbor_item['fit_screw_model'],
+ 'spanner': cutter_arbor_item['fit_wrench_model'],
+ 'active': cutter_arbor_item['active'],
+ })
+ else:
+ if cutter_arbor_item['active'] is False:
+ cutter_arbor.write({'active': False})
+ else:
+ self.write({
+ 'name': cutter_arbor_item['name'],
+ 'height': cutter_arbor_item['height'],
+ 'width': cutter_arbor_item['width'],
+ 'total_length': cutter_arbor_item['total_length'],
+ 'knife_head_height': cutter_arbor_item['head_length'],
+ 'knife_head_width': cutter_arbor_item['head_width'],
+ 'knife_head_length': cutter_arbor_item['head_length'],
+ 'cutter_arbor_diameter': cutter_arbor_item['arbor_diameter'],
+ 'main_included_angle': cutter_arbor_item['edge_angle'],
+ 'relief_angle': cutter_arbor_item['relief_angle'],
+ 'cutting_depth': cutter_arbor_item['cutting_depth_max'],
+ 'min_machining_aperture': cutter_arbor_item['machining_aperture_min'],
+ 'install_blade_tip_num': cutter_arbor_item['number_blade_installed'],
+ 'is_cooling_hole': cutter_arbor_item['is_cooling_hole'],
+ 'locating_slot_code': cutter_arbor_item['locator_slot_code'],
+ 'installing_structure': cutter_arbor_item['mounting_structure'],
+ 'blade_id': False if not cutter_arbor_item['fit_blade_model_code'] else self.env[
+ 'sf.cutting_tool.standard.library'].search(
+ [('code', '=', cutter_arbor_item['fit_blade_model_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
+ 'cotter_pin': cutter_arbor_item['fit_pin_model'],
+ 'pressing_plate': cutter_arbor_item['fit_plate_model'],
+ 'screw': cutter_arbor_item['fit_screw_model'],
+ 'spanner': cutter_arbor_item['fit_wrench_model'],
+ })
+ if 'basic_parameters_cutter_head' in result['cutting_tool_basic_parameters_yesterday_list']:
+ basic_parameters_cutter_head_list = json.loads(
+ result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head'])
+ if basic_parameters_cutter_head_list:
+ for cutter_head_item in basic_parameters_cutter_head_list:
+ cutter_head = self.search(
+ [('code', '=', cutter_head_item['code']), ('active', 'in', [True, False])])
+ if not cutter_head:
+ self.create({
+ 'name': cutter_head_item['name'],
+ 'code': cutter_head_item['code'],
+ 'cutting_tool_type': '刀盘',
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', cutter_head_item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'install_blade_tip_num': cutter_head_item['number_blade_installed'],
+ 'blade_diameter': cutter_head_item['blade_diameter'],
+ 'cutter_head_diameter': cutter_head_item['cutter_diameter'],
+ 'interface_diameter': cutter_head_item['interface_diameter'],
+ 'total_length': cutter_head_item['total_length'],
+ 'blade_length': cutter_head_item['blade_length'],
+ 'cutting_depth': cutter_head_item['cutting_depth_max'],
+ 'main_included_angle': cutter_head_item['edge_angle'],
+ 'installing_structure': cutter_head_item['mounting_structure'],
+ 'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
+ 'sf.cutting_tool.standard.library'].search(
+ [('code', '=', cutter_head_item['fit_blade_model_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'screw': cutter_head_item['fit_screw_model'],
+ 'spanner': cutter_head_item['fit_wrench_model'],
+ 'is_cooling_hole': cutter_head_item['is_cooling_hole'],
+ 'locating_slot_code': cutter_head_item['locator_slot_code'],
+ 'active': cutter_head_item['active'],
+ })
+ else:
+ if cutter_head_item['active'] is False:
+ cutter_head.write({'active': False})
+ else:
+ self.write({
+ 'name': cutter_head_item['name'],
+ 'install_blade_tip_num': cutter_head_item['number_blade_installed'],
+ 'blade_diameter': cutter_head_item['blade_diameter'],
+ 'cutter_head_diameter': cutter_head_item['cutter_diameter'],
+ 'interface_diameter': cutter_head_item['interface_diameter'],
+ 'total_length': cutter_head_item['total_length'],
+ 'blade_length': cutter_head_item['blade_length'],
+ 'cutting_depth': cutter_head_item['cutting_depth_max'],
+ 'main_included_angle': cutter_head_item['edge_angle'],
+ 'installing_structure': cutter_head_item['mounting_structure'],
+ 'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
+ 'sf.cutting_tool.standard.library'].search(
+ [('code', '=', cutter_head_item['fit_blade_model_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'screw': cutter_head_item['fit_screw_model'],
+ 'spanner': cutter_head_item['fit_wrench_model'],
+ 'is_cooling_hole': cutter_head_item['is_cooling_hole'],
+ 'locating_slot_code': cutter_head_item['locator_slot_code'],
+ })
+ if 'basic_parameters_knife_handle' in result['cutting_tool_basic_parameters_yesterday_list']:
+ basic_parameters_knife_handle_list = json.loads(
+ result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_knife_handle'])
+ if basic_parameters_knife_handle_list:
+ for knife_handle_item in basic_parameters_knife_handle_list:
+ knife_handle = self.search(
+ [('code', '=', knife_handle_item['code']), ('active', 'in', [True, False])])
+ if not knife_handle:
+ self.create({
+ 'name': knife_handle_item['name'],
+ 'code': knife_handle_item['code'],
+ 'cutting_tool_type': '刀柄',
+ 'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
+ [('code', '=', knife_handle_item['standard_library_code'].replace("JKM", result[
+ 'factory_short_name']))]).id,
+ 'total_length': knife_handle_item['total_length'],
+ 'taper_shank_model': knife_handle_item['taper_shank_model'],
+ 'flange_shank_length': knife_handle_item['flange_length'],
+ 'flange_diameter': knife_handle_item['flange_diameter'],
+ 'shank_length': knife_handle_item['shank_length'],
+ 'shank_diameter': knife_handle_item['shank_diameter'],
+ 'min_clamping_diameter': knife_handle_item['clamping_diameter_min'],
+ 'max_clamping_diameter': knife_handle_item['clamping_diameter_max'],
+ 'clamping_mode': knife_handle_item['clamping_way'],
+ 'tool_changing_time': knife_handle_item['tool_changing_time'],
+ 'max_rotate_speed': knife_handle_item['rotate_speed_max'],
+ 'diameter_slip_accuracy': knife_handle_item['diameter_slip_accuracy'],
+ 'cooling_model': knife_handle_item['cooling_model'],
+ 'is_quick_cutting': knife_handle_item['is_quick_cutting'],
+ 'is_safe_lock': knife_handle_item['is_safe_lock'],
+ 'screw': knife_handle_item['fit_wrench_model'],
+ 'nut': knife_handle_item['fit_nut_model'],
+ 'dynamic_balance_class': knife_handle_item['dynamic_balance_class'],
+ 'active': knife_handle_item['active'],
+ })
+ else:
+ if knife_handle_item['active'] is False:
+ knife_handle.write({'active': False})
+ else:
+ self.write({
+ 'name': knife_handle_item['name'],
+ 'total_length': knife_handle_item['total_length'],
+ 'taper_shank_model': knife_handle_item['taper_shank_model'],
+ 'flange_shank_length': knife_handle_item['flange_length'],
+ 'flange_diameter': knife_handle_item['flange_diameter'],
+ 'shank_length': knife_handle_item['shank_length'],
+ 'shank_diameter': knife_handle_item['shank_diameter'],
+ 'min_clamping_diameter': knife_handle_item['clamping_diameter_min'],
+ 'max_clamping_diameter': knife_handle_item['clamping_diameter_max'],
+ 'clamping_mode': knife_handle_item['clamping_way'],
+ 'tool_changing_time': knife_handle_item['tool_changing_time'],
+ 'max_rotate_speed': knife_handle_item['rotate_speed_max'],
+ 'diameter_slip_accuracy': knife_handle_item['diameter_slip_accuracy'],
+ 'cooling_model': knife_handle_item['cooling_model'],
+ 'is_quick_cutting': knife_handle_item['is_quick_cutting'],
+ 'is_safe_lock': knife_handle_item['is_safe_lock'],
+ 'screw': knife_handle_item['fit_wrench_model'],
+ 'nut': knife_handle_item['fit_nut_model'],
+ 'dynamic_balance_class': knife_handle_item['dynamic_balance_class'],
+ })
+ else:
+ raise ValidationError("刀具物料基本参数认证未通过")
diff --git a/sf_mrs_connect/views/res_config_settings_views.xml b/sf_mrs_connect/views/res_config_settings_views.xml
index bc829b2f..08812f23 100644
--- a/sf_mrs_connect/views/res_config_settings_views.xml
+++ b/sf_mrs_connect/views/res_config_settings_views.xml
@@ -8,8 +8,8 @@
-
同步参数配置
-
+
云平台参数配置
+
@@ -36,7 +36,7 @@
FTP参数配置
-
+
-
业务平台参数配置
-
+
特征识别参数配置
+
diff --git a/sf_plan/__init__.py b/sf_plan/__init__.py
index 8134f974..52497701 100644
--- a/sf_plan/__init__.py
+++ b/sf_plan/__init__.py
@@ -2,3 +2,4 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
+from . import wizard
diff --git a/sf_plan/__manifest__.py b/sf_plan/__manifest__.py
index 257400d3..c14b40ed 100644
--- a/sf_plan/__manifest__.py
+++ b/sf_plan/__manifest__.py
@@ -17,8 +17,10 @@
'data': [
'security/ir.model.access.csv',
# 'security/rules.xml',
+ 'wizard/action_plan_some.xml',
'views/view.xml',
- 'views/change_manufactuing.xml'
+ # 'views/change_manufactuing.xml',
+
],
'assets': {
diff --git a/sf_plan/models/custom_plan.py b/sf_plan/models/custom_plan.py
index 075c7e21..d1a82501 100644
--- a/sf_plan/models/custom_plan.py
+++ b/sf_plan/models/custom_plan.py
@@ -12,14 +12,30 @@ class sf_production_plan(models.Model):
_name = 'sf.production.plan'
_description = 'sf_production_plan'
_inherit = ['mail.thread']
- _order = 'create_date desc'
+ # _order = 'state desc, write_date desc'
state = fields.Selection([
('draft', '待排程'),
('done', '已排程'),
- ('processing', '已加工'),
+ ('processing', '加工中'),
('finished', '已完成')
], string='工单状态', tracking=True)
+
+ state_order = fields.Integer(compute='_compute_state_order', store=True)
+
+ @api.depends('state')
+ def _compute_state_order(self):
+ order_mapping = {
+ 'draft': 1,
+ 'done': 2,
+ 'processing': 3,
+ 'finished': 4
+ }
+ for record in self:
+ record.state_order = order_mapping.get(record.state, 0)
+
+ _order = 'state_order asc, write_date desc'
+
name = fields.Char(string='工单编号')
active = fields.Boolean(string='已归档', default=True)
# selected = fields.Boolean(default=False)
@@ -51,6 +67,17 @@ class sf_production_plan(models.Model):
sequence = fields.Integer(string='序号', copy=False, readonly=True, index=True)
current_operation_name = fields.Char(string='当前工序名称', size=64, default='生产计划')
+ @api.onchange('production_line_id')
+ def _compute_production_line_id(self):
+ for item in self:
+ item.sudo().production_id.production_line_id = item.production_line_id.id
+ item.sudo().production_id.plan_start_processing_time = item.date_planned_start
+
+ @api.onchange('state')
+ def _onchange_state(self):
+ if self.state == 'finished':
+ self.production_id.schedule_state = '已完成'
+
# @api.model
# def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
# """
@@ -153,40 +180,50 @@ 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 = '已排'
+ record.sudo().production_id.schedule_state = '已排'
+ # self.env['sale.order'].browse(record.production_id.origin).schedule_status = 'to process'
+ sale_obj = self.env['sale.order'].search([('name', '=', record.origin)])
+ if 'S' in sale_obj.name:
+ sale_obj.schedule_status = 'to process'
+ 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'].sudo().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):
"""
@@ -194,7 +231,7 @@ class sf_production_plan(models.Model):
"""
sequence = workorder_id_list.index(item.id) - 1
# 计算CNC加工之前工单的开始结束时间
- for i in range(sequence):
+ for i in range(1 if sequence == 0 else sequence):
current_workorder_id = (item.id - (i + 1))
current_workorder_obj = self.env['mrp.workorder'].sudo().search(
[('id', '=', current_workorder_id)])
@@ -247,8 +284,13 @@ class sf_production_plan(models.Model):
def cancel_production_schedule(self):
self.date_planned_finished = False
self.state = 'draft'
+ self.production_line_id = False
aa = self.env['mrp.production'].sudo().search([('name', '=', self.name)])
aa.schedule_state = '未排'
+ # self.env['sale.order'].browse(record.production_id.origin).schedule_status = 'to shedule'
+ sale_obj = self.env['sale.order'].search([('name', '=', self.origin)])
+ if 'S' in sale_obj.name:
+ sale_obj.schedule_status = 'to schedule'
return self.date_planned_finished
def liucheng_cs(self):
@@ -288,33 +330,6 @@ class sf_production_plan(models.Model):
raise UserError(e)
-# # sf生产排程
-# class sf_produce_plan(models.Model):
-# _name = 'sf.produce.plan'
-# _description = 'sf生产排程'
-
-# # 重写create方法,使得创建坯料预制排程时,如果给出了计划结束时间,则计划开始时间为计划结束时间减去坯料预制时间
-# @api.model
-# def create(self, vals):
-# # 评估结束时间
-# vals['plan_end_time'] = self._get_plan_end_time(vals['plan_start_time'], vals['quantity'])
-# return super(sf_pl_plan, self).create(vals)
-
-# # 当不设置计划结束时间时,增加计算计划结束时间的方法
-# @api.onchange('plan_start_time', 'quantity')
-# def _onchange_plan_start_time(self):
-# if self.plan_start_time and self.quantity:
-# self.plan_end_time = self._get_plan_end_time(self.plan_start_time, self.quantity)
-#
-# # 计算计划结束时间
-# def _get_plan_end_time(self, plan_start_time, quantity):
-# # 坯料预制时间
-# pl_time = 0.5
-# # 计划结束时间 = 计划开始时间 + 坯料预制时间
-# plan_end_time = plan_start_time + pl_time
-# return plan_end_time
-#
-
# 机台作业计划
class machine_work_schedule(models.Model):
_name = 'sf.machine.schedule'
diff --git a/sf_plan/security/ir.model.access.csv b/sf_plan/security/ir.model.access.csv
index 3123afe9..a17f2683 100644
--- a/sf_plan/security/ir.model.access.csv
+++ b/sf_plan/security/ir.model.access.csv
@@ -1,3 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sf_production_plan,sf.production.plan,model_sf_production_plan,base.group_user,1,0,0,0
-access_sf_production_plan_for_dispatch,sf.production.plan for dispatch,model_sf_production_plan,sf_base.group_plan_dispatch,1,1,1,0
+access_sf_production_plan_for_dispatch,sf.production.plan for dispatch,model_sf_production_plan,sf_base.group_plan_dispatch,1,1,0,0
+
+access_sf_action_plan_all_wizard,sf.action.plan.all.wizard,model_sf_action_plan_all_wizard,base.group_user,1,1,1,1
\ No newline at end of file
diff --git a/sf_plan/views/change_manufactuing.xml b/sf_plan/views/change_manufactuing.xml
index 26ac88fc..d6d01ce9 100644
--- a/sf_plan/views/change_manufactuing.xml
+++ b/sf_plan/views/change_manufactuing.xml
@@ -10,10 +10,11 @@
-
-
-
-
+
+
+
+
@@ -27,32 +28,33 @@
-
-
-
-
+
+
+
+
-
- custom.product.template.form
- product.template
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
custom.mrp.bom.form
mrp.bom
@@ -62,10 +64,12 @@
@@ -81,10 +85,12 @@
@@ -100,10 +106,12 @@
@@ -119,10 +127,12 @@
@@ -138,10 +148,12 @@
@@ -157,10 +169,12 @@
diff --git a/sf_plan/views/view.xml b/sf_plan/views/view.xml
index fbca7218..dfaa1ca8 100644
--- a/sf_plan/views/view.xml
+++ b/sf_plan/views/view.xml
@@ -5,8 +5,16 @@
sf.production.plan.tree
sf.production.plan
+
-
+
+
@@ -15,8 +23,12 @@
-
-
+
+
@@ -27,14 +39,17 @@
-
+
sf.production.plan.search
sf.production.plan
@@ -146,7 +161,7 @@
default_scale="day"
scales="day,week,month,year"
precision="{'day': 'hour:quarter', 'week': 'day:half', 'month': 'day', 'year': 'month:quarter'}">
-
+
@@ -186,65 +201,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
sf.machine.schedule.tree
sf.machine.schedule
@@ -263,7 +219,7 @@
gantt,tree,form
-
+
制造订单生产计划
ir.actions.act_window
@@ -279,11 +235,11 @@
groups="sf_base.group_plan_dispatch"
/>
-
-
-
-
-
+
+
+
+
+
制造订单
@@ -300,17 +256,17 @@
-
+
机台作业计划
ir.actions.act_window
sf.machine.schedule
tree
- 暂无机台作业计划
+ 暂无机台作业计划
- 跟进请求的处理,并且和合作者沟通。
+ 跟进请求的处理,并且和合作者沟通。
@@ -322,13 +278,21 @@
action="mrp_custom_action"
parent="sf_production_plan_menu"
/>
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/sf_plan/wizard/__init__.py b/sf_plan/wizard/__init__.py
new file mode 100644
index 00000000..1dd0edf6
--- /dev/null
+++ b/sf_plan/wizard/__init__.py
@@ -0,0 +1 @@
+from . import action_plan_some
diff --git a/sf_plan/wizard/action_plan_some.py b/sf_plan/wizard/action_plan_some.py
new file mode 100644
index 00000000..7078efae
--- /dev/null
+++ b/sf_plan/wizard/action_plan_some.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+import base64
+import logging
+import os
+from datetime import datetime
+from odoo import fields, models
+# from odoo.exceptions import ValidationError
+from odoo.exceptions import UserError
+
+_logger = logging.getLogger(__name__)
+
+
+class Action_Plan_All_Wizard(models.TransientModel):
+ _name = 'sf.action.plan.all.wizard'
+ _description = u'排程向导'
+
+ # 选择生产线
+ production_line_id = fields.Many2one('sf.production.line', string=u'生产线', required=True)
+
+ # 接收传递过来的计划ID
+ plan_ids = fields.Many2many('sf.production.plan', string=u'计划ID')
+
+ # 确认排程按钮
+ def action_plan_all(self):
+ # 使用传递过来的计划ID
+ temp_plan_ids = self.plan_ids
+ # 在这里添加您的逻辑来处理这些ID
+ for plan in temp_plan_ids:
+ # 处理每个计划
+ # 比如更新计划状态、分配资源等
+ # 示例:plan.state = 'scheduled'
+ print('处理计划:', plan.id)
+ # 拿到计划对象
+ plan_obj = self.env['sf.production.plan'].browse(plan.id)
+ plan_obj.production_line_id = self.production_line_id.id
+ plan_obj.do_production_schedule()
+ # plan_obj.state = 'done'
+ print('处理计划:', plan.id, '完成')
+
+ # # 获取当前生产线
+ # production_line_id = self.production_line_id
+ # # 获取当前生产线的所有生产订单
+ # production_order_ids = self.env['mrp.production'].search([('production_line_id', '=', production_line_id.id)])
+ # # 获取当前生产线的所有生产订单的id
+ # production_order_id_list = []
+ # for production_order_id in production_order_ids:
+ # production_order_id_list.append(production_order_id.id)
+ # # 获取当前生产线的所有生产订单的排程状态
+ # production_order_plan_state_list = []
+ # for production_order_id in production_order_ids:
+ # production_order_plan_state_list.append(production_order_id.plan_state)
+ # # 如果当前生产线的所有生产订单的排程状态都是已排程,则报错
+ # if all(production_order_plan_state == '已排程' for production_order_plan_state in production_order_plan_state_list):
+ # raise UserError('当前生产线的所有生产订单都已排程,请勿重复排程!')
+ # # 如果当前生产线的所有生产订单的排程状态都是未排程,则报错
+ # if all(production_order_plan_state == '未排程' for production_order_plan_state in production_order_plan_state_list):
+ # raise UserError('当前生产线的所有生产订单都未排程,请先排程!')
+ # # 如果当前生产线的所有生产订单的排程状态都是已完成,则报错
+ # if all(production_order_plan_state == '已完成' for production_order_plan_state in production_order_plan_state_list):
+ # raise UserError('当前生产线的所有生产订单都已完成,请勿重复排程!')
+ # # 如果当前生产线的所有生产订单的排程状态都是已取消,则报错
+ # if all(production_order_plan_state == '已取消' for production_order_plan_state in production_order_plan_state_list):
+ # raise UserError('当前生产线的所有生产订单都已取消,请勿重复排程!')
+ # # 如果当前生产线的所有生产订单的排程状态都是已暂停,则报错
+ # if all(production_order_plan_state == '已暂停' for production_order_plan_state in production
diff --git a/sf_plan/wizard/action_plan_some.xml b/sf_plan/wizard/action_plan_some.xml
new file mode 100644
index 00000000..2c52658a
--- /dev/null
+++ b/sf_plan/wizard/action_plan_some.xml
@@ -0,0 +1,31 @@
+
+
+
+ 选择生产线
+ sf.action.plan.all.wizard
+
+
+
+
+
+ 请选择要排程的生产线
+ ir.actions.act_window
+
+ sf.action.plan.all.wizard
+ form
+
+ new
+ {'default_plan_ids': active_ids}
+
+
+
+
\ No newline at end of file
diff --git a/sf_plan_management/i18n/zh_CN.po b/sf_plan_management/i18n/zh_CN.po
index 1b311da9..086067ab 100644
--- a/sf_plan_management/i18n/zh_CN.po
+++ b/sf_plan_management/i18n/zh_CN.po
@@ -55392,7 +55392,7 @@ msgstr "覆盖作者EMail"
#: model_terms:ir.ui.view,arch_db:mrp.mrp_bom_form_view
#: model_terms:ir.ui.view,arch_db:stock.view_stock_rules_report
msgid "Overview"
-msgstr "概述"
+msgstr "驾驶舱"
#. module: base
#: model:ir.model.fields,field_description:base.field_base_language_import__overwrite
@@ -112590,7 +112590,7 @@ msgstr ""
#: model:ir.model,name:sf_manufacturing.model_mrp_production
#: model:ir.ui.menu,name:sf_plan.mrp_custom_menu
msgid "制造订单"
-msgstr "生产订单"
+msgstr "制造订单"
#. module: sf_plan
#: model:ir.actions.act_window,name:sf_plan.sf_production_plan_action
@@ -114487,6 +114487,11 @@ msgstr ""
msgid "径跳精度(mm)"
msgstr ""
+#. module: sf_manufacturing
+#: model:ir.model.fields.selection,name:sf_manufacturing.selection__mrp_production__state__progress
+msgid "待排程"
+msgstr "待排程"
+
#. module: sf_base
#: model:ir.model.fields,field_description:sf_base.field_sf_cutting_tool_model__jump_accuracy
msgid "径跳精度(um)"
@@ -116186,7 +116191,7 @@ msgstr ""
#: model:ir.actions.act_window,name:sf_manufacturing.mrp_workcenter_kanban_action1
#: model:ir.ui.menu,name:sf_manufacturing.menu_mrp_dashboard
msgid "生产线驾驶舱"
-msgstr ""
+msgstr "生产线驾驶舱"
#. module: sf_warehouse
#: model_terms:ir.ui.view,arch_db:sf_warehouse.view_location_form_sf_inherit
diff --git a/sf_quality/models/__init__.py b/sf_quality/models/__init__.py
index 79a87b7d..71468786 100644
--- a/sf_quality/models/__init__.py
+++ b/sf_quality/models/__init__.py
@@ -2,3 +2,4 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import custom_quality
+from . import quality
diff --git a/sf_quality/models/quality.py b/sf_quality/models/quality.py
new file mode 100644
index 00000000..18b24daa
--- /dev/null
+++ b/sf_quality/models/quality.py
@@ -0,0 +1,34 @@
+import json
+import requests
+from odoo import fields, models, api
+from odoo.exceptions import ValidationError
+from odoo.addons.sf_base.commons.common import Common
+
+
+class QualityCheck(models.Model):
+ _inherit = "quality.check"
+ _description = '零件特采'
+
+ # ==========零件特采接口==========
+ def _register_tool_groups(self):
+ create_url = '/AutoDeviceApi/ModSpecial'
+ sf_sync_config = self.env['res.config.settings'].get_values()
+ token = sf_sync_config['token']
+ sf_secret_key = sf_sync_config['sf_secret_key']
+ headers = Common.get_headers(self, token, sf_secret_key)
+ strurl = sf_sync_config['sf_url'] + create_url
+ val = {
+ 'RfidCode': None,
+ }
+ kw = json.dumps(val, ensure_ascii=False)
+ r = requests.post(strurl, json={}, data={'kw': kw, 'token': token}, headers=headers)
+ ret = r.json()
+ if r == 200:
+ return "零件特采发送成功"
+ else:
+ raise ValidationError("零件特采发送失败")
+
+ # @api.onchange('quality_state')
+ # def _onchange_quality_state(self):
+ # if self.quality_state in ['pass', 'fail']:
+ # self._register_tool_groups()
diff --git a/sf_quality/security/ir.model.access.csv b/sf_quality/security/ir.model.access.csv
index a26c135b..4374715d 100644
--- a/sf_quality/security/ir.model.access.csv
+++ b/sf_quality/security/ir.model.access.csv
@@ -1,6 +1,6 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_quality_point_group_quality,quality_point_group_quality,quality.model_quality_point,sf_base.group_quality,1,1,1,0
-access_quality_point_group_quality_director,quality_point_group_quality_director,quality.model_quality_point,sf_base.group_quality_director,1,1,0,0
+access_quality_point_group_quality_director,quality_point_group_quality_director,quality.model_quality_point,sf_base.group_quality_director,1,1,1,0
access_quality_point_group_plan_dispatch,quality_point_group_plan_dispatch,quality.model_quality_point,sf_base.group_plan_dispatch,1,0,0,0
access_quality_point_group_plan_director,quality_point_group_plan_director,quality.model_quality_point,sf_base.group_plan_director,1,0,0,0
access_quality_point_group_sf_equipment_user,quality_point_group_sf_equipment_user,quality.model_quality_point,sf_base.group_sf_equipment_user,1,0,0,0
@@ -12,6 +12,8 @@ access_quality_check_group_quality,quality_check_group_quality,quality.model_qua
access_quality_check_group_quality_director,quality_check_group_quality_director,quality.model_quality_check,sf_base.group_quality_director,1,1,1,0
access_quality_check_group_plan_dispatch,quality_check_group_plan_dispatch,quality.model_quality_check,sf_base.group_plan_dispatch,1,0,0,0
access_quality_check_group_plan_director,quality_check_group_plan_director,quality.model_quality_check,sf_base.group_plan_director,1,0,0,0
+access_quality_check_group_purchase,quality_check_group_purchase,quality.model_quality_check,sf_base.group_purchase,1,0,0,0
+access_quality_check_group_purchase_director,quality_check_group_purchase_director,quality.model_quality_check,sf_base.group_purchase_director,1,0,0,0
access_quality_check_group_sf_equipment_user,quality_check_group_sf_equipment_user,quality.model_quality_check,sf_base.group_sf_equipment_user,1,0,0,0
access_quality_check_group_sf_tool_user,quality_check_group_sf_tool_user,quality.model_quality_check,sf_base.group_sf_tool_user,1,0,0,0
access_quality_check_group_sf_order_user,quality_check_group_sf_order_user,quality.model_quality_check,sf_base.group_sf_order_user,1,0,0,0
@@ -30,8 +32,8 @@ access_quality_alert_group_sf_mrp_manager,quality_alert_group_sf_mrp_manager,qua
access_quality_alert_group_equipment_user,quality_alert_group_equipment_user,quality.model_quality_alert,sf_maintenance.sf_group_equipment_user,1,0,0,0
access_quality_alert_group_equipment_manager,quality_alert_group_equipment_manager,quality.model_quality_alert,sf_maintenance.sf_group_equipment_manager,1,0,0,0
-access_quality_alert_team_group_quality,quality_alert_team_group_quality,quality.model_quality_alert_team,sf_base.group_quality,1,1,1,0
-access_quality_alert_team_group_quality_director,quality_alert_team_group_quality_director,quality.model_quality_alert_team,sf_base.group_quality_director,1,1,0,0
+access_quality_alert_team_group_quality,quality_alert_team_group_quality,quality.model_quality_alert_team,sf_base.group_quality,1,0,0,0
+access_quality_alert_team_group_quality_director,quality_alert_team_group_quality_director,quality.model_quality_alert_team,sf_base.group_quality_director,1,1,1,0
access_quality_alert_team_group_plan_dispatch,quality_alert_team_group_plan_dispatch,quality.model_quality_alert_team,sf_base.group_plan_dispatch,1,0,0,0
access_quality_alert_team_group_plan_director,quality_alert_team_group_plan_director,quality.model_quality_alert_team,sf_base.group_plan_director,1,0,0,0
access_quality_alert_team_group_sf_equipment_user,quality_alert_team_group_sf_equipment_user,quality.model_quality_alert_team,sf_base.group_sf_equipment_user,1,0,0,0
@@ -51,18 +53,21 @@ access_product_template_group_equipment_user,product_template_group_equipment_us
access_product_template_group_equipment_manager,product_template_group_equipment_manager,product.model_product_template,sf_maintenance.sf_group_equipment_manager,1,0,0,0
access_quality_alert_stage_group_quality,quality_alert_stage_group_quality,quality.model_quality_alert_stage,sf_base.group_quality,1,0,0,0
-access_quality_alert_stage_group_quality_director,quality_alert_stage_group_quality_director,quality.model_quality_alert_stage,sf_base.group_quality_director,1,0,0,0
+access_quality_alert_stage_group_quality_director,quality_alert_stage_group_quality_director,quality.model_quality_alert_stage,sf_base.group_quality_director,1,1,1,0
access_quality_point_test_type_group_quality,quality_point_test_type_group_quality,quality.model_quality_point_test_type,sf_base.group_quality,1,0,0,0
access_quality_point_test_type_group_quality_director,quality_point_test_type_group_quality_director,quality.model_quality_point_test_type,sf_base.group_quality_director,1,0,0,0
access_quality_tag_group_quality,quality_tag_group_quality,quality.model_quality_tag,sf_base.group_quality,1,0,0,0
-access_quality_tag_group_quality_director,quality_tag_group_quality_director,quality.model_quality_tag,sf_base.group_quality_director,1,0,0,0
+access_quality_tag_group_quality_director,quality_tag_group_quality_director,quality.model_quality_tag,sf_base.group_quality_director,1,1,1,0
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
+
+access_stock_move_group_quality,stock_move_group_quality,stock.model_stock_move,sf_base.group_quality,1,1,0,0
+access_stock_move_group_quality_director,stock_move_group_quality_director,stock.model_stock_move,sf_base.group_quality_director,1,1,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/models/__init__.py b/sf_sale/models/__init__.py
index d8b09a48..99b143c7 100644
--- a/sf_sale/models/__init__.py
+++ b/sf_sale/models/__init__.py
@@ -1,3 +1,6 @@
from . import sale_order
from . import quick_easy_order
from . import auto_quatotion_common
+from . import parser_and_calculate_work_time
+from . import preload_datas_functions
+
diff --git a/sf_sale/models/auto_quatotion_common.py b/sf_sale/models/auto_quatotion_common.py
index 10b83aed..104cd50c 100644
--- a/sf_sale/models/auto_quatotion_common.py
+++ b/sf_sale/models/auto_quatotion_common.py
@@ -8,6 +8,7 @@ __author__ = 'jinling.yang'
_logger = logging.getLogger(__name__)
+
class AutoQuatotion(models.Model):
_name = 'sf.auto_quatotion.common'
_description = u'自动报价公用类'
diff --git a/sf_sale/models/feature.sqlite b/sf_sale/models/feature.sqlite
deleted file mode 100644
index e69de29b..00000000
diff --git a/sf_sale/models/parser_and_calculate_work_time.py b/sf_sale/models/parser_and_calculate_work_time.py
new file mode 100644
index 00000000..f5abcb7f
--- /dev/null
+++ b/sf_sale/models/parser_and_calculate_work_time.py
@@ -0,0 +1,472 @@
+import time
+# import pandas as pd
+from lxml import etree
+from collections import Counter
+from . import preload_datas_functions as preload
+
+
+# import preload_datas_functions as preload
+
+
+class FeatureParser:
+ """
+ 解析Feature.xml文件
+ """
+
+ def __init__(self, xml_file):
+ self.root = etree.parse(xml_file).getroot()
+ self.size = self._get_size()
+ self.holes = self._get_holes()
+ self.slots = self._get_slot()
+ self.open_slots = self._get_open_slot()
+ self.vectors = self._get_vectors()
+
+ def _get_size(self):
+ size = self.root.find('Size')
+ return {
+ 'length': float(size.get('Length')),
+ 'width': float(size.get('Width')),
+ 'height': float(size.get('Height'))
+ }
+
+ def _get_vectors(self):
+ vectors = {}
+ for item in self.root.findall('.//Item'):
+ vector = item.find('Vector')
+ if vector is not None:
+ key = (vector.get('i'), vector.get('j'), vector.get('k'))
+ vectors[key] = vectors.get(key, 0) + 1
+ return vectors
+
+ def get_vector_counts(self):
+ return len(self.vectors)
+
+ def _get_holes(self):
+ holes = []
+ hole_element = self.root.find('Hole')
+ if hole_element is not None:
+ for item in self.root.find('Hole').iter('Item'):
+ hole = {} # 每个hole是一个字典
+ hole['id'] = int(item.get('ID'))
+ hole['name'] = item.get('Name')
+ hole['red'] = int(item.get('Red'))
+ hole['green'] = int(item.get('Green'))
+ hole['blue'] = int(item.get('Blue'))
+ # 处理circles
+ circles = []
+ for circle in item.iter('Circle'):
+ circles.append({
+ 'x': float(circle.get('x')),
+ 'y': float(circle.get('y')),
+ 'z': float(circle.get('z')),
+ 'rad': float(circle.get('rad'))
+ })
+ hole['circles'] = circles
+
+ # 处理bottom
+ bottoms = []
+ for bottom in item.iter('Bottom'):
+ bottoms.append({
+ 'x': float(bottom.get('x')),
+ 'y': float(bottom.get('y')),
+ 'z': float(bottom.get('z')),
+ 'rad': float(bottom.get('rad'))
+ })
+ hole['bottoms'] = bottoms
+
+ # 处理vector
+ for vector in item.iter('Vector'):
+ hole['vector'] = {
+ 'i': float(vector.get('i')),
+ 'j': float(vector.get('j')),
+ 'k': float(vector.get('k'))
+ }
+
+ # 创建元组并添加到列表中
+ z_rad_tuples = []
+ max_z = None
+ non_zero_rads = set() # 使用set来存储rad值,自动去重
+ for circle in circles:
+ z = float(circle.get('z'))
+ rad = float(circle.get('rad'))
+ if max_z is None or z > max_z:
+ max_z = z
+ if rad != 0:
+ non_zero_rads.add(rad)
+ for rad in non_zero_rads:
+ z_rad_tuple = (max_z, rad)
+ z_rad_tuples.append(z_rad_tuple)
+ hole['z_rad_tuples'] = z_rad_tuples
+
+ holes.append(hole) # 添加到holes列表中
+
+ return holes
+
+ def _get_slot(self):
+ """
+ 获取slot信息
+ """
+ slots = []
+ slot_a_list = []
+ slot_element = self.root.find('Slot')
+ if slot_element is not None:
+ for item in self.root.find('Slot').iter('Item'):
+ slot = {}
+ slot['id'] = int(item.get('ID'))
+ slot['name'] = item.get('Name')
+ slot['red'] = int(item.get('Red'))
+ slot['green'] = int(item.get('Green'))
+ slot['blue'] = int(item.get('Blue'))
+ # 获取Volume和Area信息
+ volume = item.find('Volume')
+ if volume is not None:
+ slot['volume'] = float(volume.get('value'))
+
+ area = item.find('Area')
+ if area is not None:
+ slot['area'] = float(area.get('value'))
+ slot_a_list.append(slot['area'])
+ # 处理lines
+ lines = []
+ for line in item.iter('Line'):
+ lines.append({
+ 'type': line.get('Type'), # 'type' : 'line' or 'arc
+ 'x1': float(line.get('x1')),
+ 'y1': float(line.get('y1')),
+ 'z1': float(line.get('z1')),
+ 'x2': float(line.get('x2')),
+ 'y2': float(line.get('y2')),
+ 'z2': float(line.get('z2'))
+ })
+ slot['lines'] = lines
+
+ # 处理Arc
+ arcs = []
+ for arc in item.iter('Arc'):
+ arcs.append({
+ 'type': arc.get('Type'),
+ 'x1': float(arc.get('x1')),
+ 'y1': float(arc.get('y1')),
+ 'z1': float(arc.get('z1')),
+ 'x2': float(arc.get('x2')),
+ 'y2': float(arc.get('y2')),
+ 'z2': float(arc.get('z2')),
+ 'x3': float(arc.get('x3')),
+ 'y3': float(arc.get('y3')),
+ 'z3': float(arc.get('z3'))
+
+ })
+ slot['arcs'] = arcs
+ slot['a'] = slot_a_list
+ slots.append(slot)
+ return slots
+
+ def _get_open_slot(self):
+ """
+ 获取open_slot信息
+ """
+ open_slots = []
+ open_slot_v_list = []
+ open_slot_element = self.root.find('OpenSlot')
+ if open_slot_element is not None:
+ for item in self.root.find('OpenSlot').iter('Item'):
+ open_slot = {}
+ open_slot['id'] = int(item.get('ID'))
+ open_slot['name'] = item.get('Name')
+ open_slot['red'] = int(item.get('Red'))
+ open_slot['green'] = int(item.get('Green'))
+ open_slot['blue'] = int(item.get('Blue'))
+ # 获取Volume和Area信息
+ volume = item.find('Volume')
+ if volume is not None:
+ open_slot['volume'] = float(volume.get('value'))
+
+ area = item.find('Area')
+ if area is not None:
+ open_slot['area'] = float(area.get('value'))
+ # open_slot_v_list.append(round(open_slot['volume'] / open_slot['area'], 3))
+ open_slot_v_list.append(open_slot['area'])
+ # 处理lines
+ lines = []
+ for line in item.iter('Line'):
+ lines.append({
+ 'type': line.get('Type'), # 'type' : 'line' or 'arc
+ 'x1': float(line.get('x1')),
+ 'y1': float(line.get('y1')),
+ 'z1': float(line.get('z1')),
+ 'x2': float(line.get('x2')),
+ 'y2': float(line.get('y2')),
+ 'z2': float(line.get('z2'))
+ })
+ open_slot['lines'] = lines
+
+ # 处理Arc
+ arcs = []
+ for arc in item.iter('Arc'):
+ arcs.append({
+ 'type': arc.get('Type'),
+ 'x1': float(arc.get('x1')),
+ 'y1': float(arc.get('y1')),
+ 'z1': float(arc.get('z1')),
+ 'x2': float(arc.get('x2')),
+ 'y2': float(arc.get('y2')),
+ 'z2': float(arc.get('z2')),
+ 'x3': float(arc.get('x3')),
+ 'y3': float(arc.get('y3')),
+ 'z3': float(arc.get('z3'))
+
+ })
+ open_slot['arcs'] = arcs
+ open_slot['v'] = open_slot_v_list
+ open_slots.append(open_slot)
+ return open_slots
+
+
+def hole_time(parser):
+ """
+ 计算孔的工时
+ :return:
+ """
+ # 判断是否有孔
+ if parser.holes is not None:
+ # 遍历所有的孔,获取孔径和孔深度,然后调用函数查询工时
+ hole_total_time = 0
+ nums = 1
+ expand_hole = '否'
+ j_time = 0
+ j_hole_nums = 0
+ hole_nums = 0
+ for hole in parser.holes:
+ for z_rad_tuple in hole['z_rad_tuples']:
+ if (2 * z_rad_tuple[1] * z_rad_tuple[0] <= 3750) and (2 * z_rad_tuple[1] <= 25):
+ hole_nums += 1
+ # print('z_rad_tuple', z_rad_tuple)
+ per_time_minute = preload.get_suitable_hole_working_hours(preload.df_hole_duration,
+ 2 * z_rad_tuple[1],
+ z_rad_tuple[0])
+ # if per_time_minute is None:
+ # raise Exception('孔径为%s,深度为%s的孔没有找到对应的工时' % (2 * z_rad_tuple[1], z_rad_tuple[0]))
+ # print('per_time_minute', per_time_minute)
+ expand_hole_end = 0.6 if expand_hole == '是' else 1
+ per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
+ hole_total_time += per_time
+ elif (2 * z_rad_tuple[1] * z_rad_tuple[0] <= 3750) and (2 * z_rad_tuple[1] > 25):
+ hole_nums += 1
+ # print('z_rad_tuple', z_rad_tuple)
+ per_time_minute = 0.0003 * 2 * z_rad_tuple[1] * z_rad_tuple[0]
+ expand_hole_end = 0.6 if expand_hole == '是' else 1
+ per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
+ hole_total_time += per_time
+ elif 3750 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 50000:
+ hole_nums += 1
+ # print('z_rad_tuple', z_rad_tuple)
+ per_time_minute = 0.0003 * 2 * z_rad_tuple[1] * z_rad_tuple[0]
+ expand_hole_end = 0.6 if expand_hole == '是' else 1
+ per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
+ hole_total_time += per_time
+ elif 50000 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 100000:
+ hole_nums += 1
+ # print('z_rad_tuple', z_rad_tuple)
+ per_time_minute = 0.00018 * 2 * z_rad_tuple[1] * z_rad_tuple[0]
+ expand_hole_end = 0.6 if expand_hole == '是' else 1
+ per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
+ hole_total_time += per_time
+ elif 100000 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 150000:
+ hole_nums += 1
+ # print('z_rad_tuple', z_rad_tuple)
+ per_time_minute = 0.00016 * 2 * z_rad_tuple[1] * z_rad_tuple[0]
+ expand_hole_end = 0.6 if expand_hole == '是' else 1
+ per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
+ hole_total_time += per_time
+ elif 150000 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 200000:
+ hole_nums += 1
+ # print('z_rad_tuple', z_rad_tuple)
+ per_time_minute = 0.00015 * 2 * z_rad_tuple[1] * z_rad_tuple[0]
+ expand_hole_end = 0.6 if expand_hole == '是' else 1
+ per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
+ hole_total_time += per_time
+ elif 200000 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 250000:
+ hole_nums += 1
+ # print('z_rad_tuple', z_rad_tuple)
+ per_time_minute = 0.0002 * 2 * z_rad_tuple[1] * z_rad_tuple[0]
+ expand_hole_end = 0.6 if expand_hole == '是' else 1
+ per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
+ hole_total_time += per_time
+ else:
+ raise Exception('孔径为%s,深度为%s的孔没有找到对应的工时' % (2 * z_rad_tuple[1], z_rad_tuple[0]))
+
+ print('孔工时', round(hole_total_time * nums * 2) / 2)
+ print('共有%s个孔,其中%s为台阶孔' % (len(parser.holes), hole_nums - len(parser.holes)))
+ return round(hole_total_time * nums * 2) / 2
+ else:
+ return 0
+
+
+def slot_time(parser):
+ # 判断是否有槽
+ if parser.slots is not None:
+ # 遍历所有的槽,获取槽的长度,然后调用函数查询工时
+ slot_total_time = 0
+ nums = 1
+ finish_time = 0
+ process_time = 0
+ process_total_time = 0
+ slot_a = parser.slots[0]['a']
+
+ slot_a_counter = Counter(slot_a)
+ slot_a_counter_result = dict(slot_a_counter)
+
+ for i in slot_a_counter_result:
+ for slot in parser.slots:
+ if slot['area'] == i:
+ # # 计算长度(第一条线和第三条线的X轴距离)
+ # length = abs(slot['lines'][0]['y1'] - slot['lines'][2]['y1'])
+ # # 计算宽度(第一条线和第二条线的Y轴距离)
+ # width = abs(slot['lines'][1]['x1'] - slot['lines'][3]['x1'])
+ # # 计算面积
+ # area = length * width
+ # 槽深度
+ depth = round(slot['volume'] / slot['area'], 3)
+
+ # 沟通刀具暂定为12
+ finish_tool_diameter = 12
+ if 200 < slot['area'] <= 5000:
+ finish_time = 0
+
+ # 加工穴数待定(取得每一个槽的穴数和装夹次数,那这个数量?目前暂时按1来算,待有统计数据之后再说)
+ rough_part_nums = slot_a_counter_result[slot['area']]
+ rough_clamping_times = 1
+ finishi_part_nums = 1
+ finish_clamping_times = 1
+ # 调用函数计算槽的工时
+ slot_total_time = preload.get_suitable_rough_working_hours(preload.df_rough_duration, depth)
+ # if nums > 20:
+ # process_time = round(
+ # (nums * 0.6 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
+ # finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
+ # elif nums > 10:
+ # process_time = round(
+ # (nums * 0.7 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
+ # finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
+ # elif nums > 6:
+ # process_time = round(
+ # (nums * 0.8 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
+ # finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
+ # elif nums > 4:
+ # process_time = round(
+ # (nums * 0.9 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
+ # finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
+ # elif nums > 1:
+ # process_time = round(
+ # (nums * 0.95 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
+ # finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
+ # else:
+ # process_time = round(
+ # (nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
+ # finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
+ process_time = round(
+ (nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
+ finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
+ # print('slot_total_time', slot_total_time)
+ elif slot['area'] <= 200:
+ slot_total_time = 0
+ rough_part_nums = slot_a_counter_result[slot['area']]
+ rough_clamping_times = 1
+ finishi_part_nums = 1
+ finish_clamping_times = 1
+ # 调用函数计算槽的工时
+ finish_time = preload.get_suitable_finish_working_hours(preload.df_finish_duration, depth,
+ finish_tool_diameter)
+ process_time = round(
+ (nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
+ finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
+ # print('finish_time', finish_time)
+ else:
+ rough_part_nums = slot_a_counter_result[slot['area']]
+ rough_clamping_times = 1
+ finishi_part_nums = 1
+ finish_clamping_times = 1
+ process_time = round(
+ (nums * 1 * ((0.00016 * rough_part_nums + rough_clamping_times * 20) + (
+ finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
+ process_total_time += process_time
+
+ print('槽工时', process_total_time)
+ return process_total_time
+ else:
+ return 0
+
+
+def open_slot_time(parser):
+ # 判断是否有开口槽
+ if parser.open_slots is not None:
+ # 遍历所有的开口槽,获取槽宽和槽长,然后调用函数查询工时
+ open_slot_total_time = 0
+ nums = 1
+ finish_time = 0
+ open_slot_process_time = 0
+
+ open_slot_v = parser.open_slots[0]['v']
+
+ counter = Counter(open_slot_v)
+ result = dict(counter)
+
+ transiant_time = 0
+ for i in result:
+ for open_slot in parser.open_slots:
+ if open_slot['area'] == i:
+ depth = round(open_slot['volume'] / open_slot['area'], 3)
+ # 沟通刀具暂定为12
+ finish_tool_diameter = 12
+ if 200 < open_slot['area'] <= 5000:
+ finish_time = 0
+ # 加工穴数待定(取得每一个槽的穴数和装夹次数,那这个数量?目前暂时按1来算,待有统计数据之后再说)
+ rough_part_nums = result[open_slot['area']]
+ rough_clamping_times = 1
+ finishi_part_nums = 1
+ finish_clamping_times = 1
+ # 调用函数计算槽的工时
+ slot_total_time = preload.get_suitable_rough_working_hours(preload.df_rough_duration, depth)
+ open_slot_process_time = round(
+ (nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
+ finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
+ # print('slot_total_time', slot_total_time)
+ elif open_slot['area'] <= 200:
+ slot_total_time = 0
+ rough_part_nums = 1
+ rough_clamping_times = 1
+ finishi_part_nums = 1
+ finish_clamping_times = 1
+ # 调用函数计算槽的工时
+ finish_time = preload.get_suitable_finish_working_hours(preload.df_finish_duration, depth,
+ finish_tool_diameter)
+ open_slot_process_time = round(
+ (nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
+ finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
+ # print('finish_time', finish_time)
+ else:
+ rough_part_nums = 1
+ rough_clamping_times = 1
+ finishi_part_nums = 1
+ finish_clamping_times = 1
+ open_slot_process_time = round(
+ (nums * 1 * ((0.00016 * rough_part_nums + rough_clamping_times * 20) + (
+ finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
+
+ transiant_time += open_slot_process_time
+ print('开口槽工时', transiant_time)
+ return transiant_time
+ else:
+ return 0
+
+
+if __name__ == '__main__':
+ time1 = time.time()
+ parser = FeatureParser(
+ 'D:\\ccccccccccccccccccccccccccccccccccccccccccccccc\\aa\\JKM001-260.200.30_FeatureTable.xml')
+ # print('parser', parser.holes)
+ # print('parser.slots', parser.slots)
+ # print('parser.open_slots', parser.open_slots)
+ print('总工时', hole_time(parser) + slot_time(parser) + open_slot_time(parser))
+ time2 = time.time()
+ print('耗时:', time2 - time1)
diff --git a/sf_sale/models/preload_datas_functions.py b/sf_sale/models/preload_datas_functions.py
new file mode 100644
index 00000000..37035f44
--- /dev/null
+++ b/sf_sale/models/preload_datas_functions.py
@@ -0,0 +1,201 @@
+import psycopg2
+# import pandas as pd
+
+
+def load_and_convert_data(table_name, column_names):
+ connection = None
+ data = []
+
+ try:
+ # connection = psycopg2.connect(user="odoo",
+ # password="odoo",
+ # host="localhost",
+ # port="5432",
+ # database="www1")
+ connection = psycopg2.connect(user="odoo",
+ password="odoo",
+ host="120.76.195.146",
+ port="15432",
+ database="bfm_dev1")
+
+ cursor = connection.cursor()
+
+ # Construct the query string using the table name passed in
+ query = f"SELECT {', '.join(column_names)} FROM {table_name};"
+ cursor.execute(query)
+
+ # Fetch all rows from cursor
+ data = cursor.fetchall()
+
+ except (Exception, psycopg2.Error) as error:
+ print("Error fetching data from PostgreSQL table", error)
+
+ finally:
+ # Always close database connection after work done
+ if (connection):
+ cursor.close()
+ connection.close()
+
+ # Convert the list of tuples to DataFrame
+ # df = pd.DataFrame(data, columns=column_names)
+ #
+ # # Convert all string columns to float
+ # for col in df.columns:
+ # if df[col].dtype == 'object':
+ # df[col] = df[col].astype(float)
+
+ return 'df'
+
+
+def get_suitable_hole_working_hours(df, target_diameter, target_depth):
+ """
+ 从钻孔、铰孔数据中获取符合要求的最小工时
+ """
+ # df为输入的数据,target_diameter为目标孔径,target_depth为目标孔深
+
+ df_diameter_filtered = df.loc[df['hole_diameter'] >= target_diameter]
+
+ if not df_diameter_filtered.empty:
+ min_diameter = df_diameter_filtered['hole_diameter'].min()
+ df_depth_filtered = df_diameter_filtered.loc[
+ (df_diameter_filtered['hole_diameter'] == min_diameter) & (
+ df_diameter_filtered['hole_depth'] >= target_depth)]
+
+ if not df_depth_filtered.empty:
+ min_depth_row = df_depth_filtered.loc[df_depth_filtered['hole_depth'].idxmin()]
+ min_working_hours = min_depth_row['working_hours']
+ return min_working_hours
+ else:
+ print("No records found where hole_depth is bigger than the target depth")
+ return None
+ else:
+ print("No records found where hole_diameter is bigger than the target diameter")
+ return None
+
+
+def get_suitable_blank_working_hours(df, blank_height, blank_length, blank_width):
+ """
+ 从毛坯数据中获取符合要求的最小工时
+ """
+ # df为输入的数据,blank_height为目标毛坯高度,blank_length为目标毛坯长度,blank_width为目标毛坯宽度
+
+ df_height_filtered = df.loc[df['blank_height'] >= blank_height]
+
+ if not df_height_filtered.empty:
+ min_height = df_height_filtered['blank_height'].min()
+ df_length_filtered = df_height_filtered.loc[
+ (df_height_filtered['blank_height'] == min_height) & (
+ df_height_filtered['blank_length'] >= blank_length)]
+
+ if not df_length_filtered.empty:
+ min_length_row = df_length_filtered.loc[df_length_filtered['blank_length'].idxmin()]
+ min_working_hours = min_length_row['working_hours']
+ return min_working_hours
+ else:
+ print("No records found where blank_length is bigger than the target length")
+ return None
+ else:
+ print("No records found where blank_height is bigger than the target height")
+ return None
+
+
+def get_suitable_rough_working_hours(df, rough_depth):
+ """
+ 从粗加工数据中获取符合要求的最小工时
+ """
+ # df为输入的数据,rough_depth为目标粗加工深度
+
+ df_depth_filtered = df.loc[df['rough_depth'] >= rough_depth]
+
+ if not df_depth_filtered.empty:
+ min_depth_row = df_depth_filtered.loc[df_depth_filtered['rough_depth'].idxmin()]
+ min_working_hours = min_depth_row['working_hours']
+ return min_working_hours
+ else:
+ print("No records found where rough_depth is bigger than the target depth")
+ return None
+
+
+def get_suitable_finish_working_hours(df, finish_depth, finish_tool_diameter):
+ """
+ 从精加工数据中获取符合要求的最小工时
+ """
+ # df为输入的数据,finish_depth为目标精加工深度,finish_tool_diameter为目标精加工刀具直径
+
+ df_depth_filtered = df.loc[df['finish_depth'] >= finish_depth]
+
+ if not df_depth_filtered.empty:
+ min_depth = df_depth_filtered['finish_depth'].min()
+ df_tool_diameter_filtered = df_depth_filtered.loc[
+ (df_depth_filtered['finish_depth'] == min_depth) & (
+ df_depth_filtered['finish_tool_diameter'] >= finish_tool_diameter)]
+
+ if not df_tool_diameter_filtered.empty:
+ min_tool_diameter_row = df_tool_diameter_filtered.loc[
+ df_tool_diameter_filtered['finish_tool_diameter'].idxmin()]
+ min_working_hours = min_tool_diameter_row['working_hours']
+ return min_working_hours
+ else:
+ print("No records found where finish_tool_diameter is bigger than the target tool diameter")
+ return None
+ else:
+ print("No records found where finish_depth is bigger than the target depth")
+ return None
+
+
+def get_suitable_chamfer_working_hours(df, chamfer_length, chamfer_size):
+ """
+ 根据倒角长度获得倒角工时,装夹平面耗时clamping_type_plane和装夹斜面耗时clamping_type_slope
+ """
+ # df为输入的数据,chamfer_length为目标倒角长度,clamping_type_plane为目标装夹平面耗时,clamping_type_slope为目标装夹斜面耗时
+
+ df_length_filtered = df.loc[df['chamfer_length'] >= chamfer_length]
+ df_chamfer_size_filtered = df.loc[df['chamfer_size'] >= chamfer_size]
+
+ if not df_length_filtered.empty and not df_chamfer_size_filtered.empty:
+ min_length_row = df_length_filtered.loc[df_length_filtered['chamfer_length'].idxmin()]
+ min_chamfer_size_row = df_chamfer_size_filtered.loc[df_chamfer_size_filtered['chamfer_size'].idxmin()]
+ clamping_time = min_length_row['clamping_time']
+ clamping_type_plane = min_length_row['clamping_type_plane']
+ clamping_type_slope = min_length_row['clamping_type_slope']
+ coefficient = min_chamfer_size_row['coefficient']
+ return clamping_time, clamping_type_plane, clamping_type_slope, coefficient
+ else:
+ print("No records found where chamfer_length is bigger than the target length")
+ return None
+
+
+df_hole_duration = load_and_convert_data('hole_duration', ['hole_diameter', 'hole_depth', 'working_hours'])
+
+df_j_hole_duration = load_and_convert_data('j_hole_duration', ['hole_diameter', 'hole_depth', 'working_hours'])
+
+df_chamfer_duration = load_and_convert_data('chamfer_duration',
+ ['chamfer_length', 'clamping_time', 'chamfer_size', 'coefficient',
+ 'clamping_type_plane', 'clamping_type_slope'])
+
+df_blank_duration = load_and_convert_data('blank_duration',
+ ['blank_length', 'blank_width', 'blank_height', 'working_hours'])
+
+df_rough_duration = load_and_convert_data('rough_duration', ['rough_depth', 'working_hours'])
+
+df_finish_duration = load_and_convert_data('finish_duration',
+ ['finish_depth', 'finish_tool_diameter', 'working_hours'])
+
+
+if __name__ == '__main__':
+ min_working_hours = get_suitable_hole_working_hours(df_hole_duration, 24, 150)
+ print('min_working_hours', min_working_hours)
+ min_j_working_hours = get_suitable_hole_working_hours(df_j_hole_duration, 10, 15)
+ print('min_j_working_hours', min_j_working_hours)
+ min_blank_working_hours = get_suitable_blank_working_hours(df_blank_duration, 150, 300, 300)
+ print('min_blank_working_hours', min_blank_working_hours)
+ min_rough_working_hours = get_suitable_rough_working_hours(df_rough_duration, 49)
+ print('min_rough_working_hours', min_rough_working_hours)
+ min_finish_working_hours = get_suitable_finish_working_hours(df_finish_duration, 0.5, 10)
+ print('min_finish_working_hours', min_finish_working_hours)
+ clamping_time, clamping_type_plane, clamping_type_slope, coefficient = get_suitable_chamfer_working_hours(
+ df_chamfer_duration, 10, 1.5)
+ print('clamping_time', clamping_time)
+ print('clamping_type_plane', clamping_type_plane)
+ print('clamping_type_slope', clamping_type_slope)
+ print('coefficient', coefficient)
diff --git a/sf_sale/models/price.sqlite b/sf_sale/models/price.sqlite
deleted file mode 100644
index e69de29b..00000000
diff --git a/sf_sale/models/process_time.db b/sf_sale/models/process_time.db
deleted file mode 100644
index e69de29b..00000000
diff --git a/sf_sale/models/quick_easy_order.py b/sf_sale/models/quick_easy_order.py
index 3f65e1cd..2a304fe8 100644
--- a/sf_sale/models/quick_easy_order.py
+++ b/sf_sale/models/quick_easy_order.py
@@ -2,17 +2,23 @@ import logging
import base64
import hashlib
import os
+import platform
import json
from datetime import datetime
+<<<<<<< HEAD
# import requests
+=======
+import requests
+from odoo import http
+from odoo.http import request
+>>>>>>> 8695a66e3d9be860f778caba8db5500885f4548f
# from OCC.Extend.DataExchange import read_step_file
# from OCC.Extend.DataExchange import write_stl_file
from odoo import models, fields, api
from odoo.modules import get_resource_path
from odoo.exceptions import ValidationError, UserError
from odoo.addons.sf_base.commons.common import Common
-
-
+from . import parser_and_calculate_work_time as pc
@@ -34,8 +40,8 @@ class QuickEasyOrder(models.Model):
('0.03', '±0.03mm'),
('0.02', '±0.02mm'),
('0.01', '±0.01mm')], string='加工精度', default='0.10')
- material_id = fields.Many2one('sf.production.materials', '材料', compute='_compute_material_model', store=True)
- material_model_id = fields.Many2one('sf.materials.model', '型号', compute='_compute_material_model', store=True)
+ material_id = fields.Many2one('sf.production.materials', '材料')
+ material_model_id = fields.Many2one('sf.materials.model', '型号')
# process_id = fields.Many2one('sf.production.process', string='表面工艺')
parameter_ids = fields.Many2many('sf.production.process.parameter', 'process_item_order_rel', string='可选参数')
quantity = fields.Integer('数量', default=1)
@@ -77,11 +83,11 @@ class QuickEasyOrder(models.Model):
if len(item[2]) > 0:
logging.info('create-attachment:%s' % int(item[2][0]))
attachment = self.env['ir.attachment'].sudo().search([('id', '=', int(item[2][0]))])
- base64_data = base64.b64encode(attachment.datas)
- base64_datas = base64_data.decode('utf-8')
- model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
- report_path = attachment._full_path(attachment.store_fname)
- vals['model_file'] = self.transition_glb_file(report_path, model_code)
+ # base64_data = base64.b64encode(attachment.datas)
+ # base64_datas = base64_data.decode('utf-8')
+ # model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
+ # report_path = attachment._full_path(attachment.store_fname)
+ vals['model_file'] = self.model_analyze(attachment)
# logging.info('create-model_file:%s' % len(vals['model_file']))
obj = super(QuickEasyOrder, self).create(vals)
@@ -91,6 +97,147 @@ class QuickEasyOrder(models.Model):
obj.state = '待接单'
return obj
+
+ def model_analyze(self,model_attachment):
+ """
+ step模型解析,上传模型时转为web可显示的格式
+ :return:
+ """
+ config = request.env['res.config.settings'].sudo().get_values()
+ try:
+ # 获取当前操作系统
+ os_name = platform.system()
+ for item in model_attachment:
+ # 将拿到的3D模型数据存入文件
+ # 定义文件名和文件的二进制内容
+ file_name = item.name # 请将这里替换为你的文件名
+ print('file_name', file_name)
+ # base64_data = base64.b64encode(item.datas)
+ # base64_datas = base64_data.decode('utf-8')
+ binary_content = item.datas # 请将这里替换为你的文件的二进制内容
+ # binary_content从字符串转为二进制
+ binary_content = base64.b64decode(binary_content)
+ # 定义新的文件夹路径
+ # 根据操作系统不同,文件路径不同
+ path_header = '/model_parser' if os_name == 'Linux' else 'D:/model_analysis'
+ # new_folder_path = 'D:/11111final' + '/' + item['name'].split(".")[0]
+ new_folder_path = path_header + '/' + item.name.rpartition('.')[0]
+ print('new_folder_path', new_folder_path)
+ # 检查新的文件夹是否存在,如果不存在,则创建
+ if not os.path.exists(new_folder_path):
+ os.makedirs(new_folder_path)
+ # 定义新的文件路径
+ new_file_path = os.path.join(new_folder_path, file_name)
+ # 将二进制内容写入新的文件
+ with open(new_file_path, 'wb') as f:
+ f.write(binary_content)
+ # 检查文件是否已经成功写入
+ if os.path.exists(new_file_path):
+ print(f'Successfully wrote binary content to {new_file_path}')
+ else:
+ print(f'Failed to write binary content to {new_file_path}')
+ # 附件
+ # attachment = request.env['ir.attachment'].sudo().create({
+ # 'datas': item['data'].encode('utf-8'),
+ # 'type': 'binary',
+ # 'description': '模型文件',
+ # 'name': item['name'],
+ # 'public': True,
+ # 'model_name': item['name'],
+ # })
+ headers = {'Content-Type': 'application/json'}
+ # 调用写入宿主机接口
+ # url_dir = 'http://192.168.50.202:8000/create_and_write_file'
+ url_dir = config['model_parser_url'] + '/create_and_write_file'
+ data = {
+ 'folder_path': new_folder_path, # 您想要创建的文件夹路径
+ 'file_path': new_file_path, # 您想要创建的文件名
+ 'content': item['data'] # 您想要写入文件的内容
+ }
+ requests.post(url_dir, json=data, headers=headers)
+ # 调用特征包接口
+ url = config['model_parser_url'] + '/process_file'
+ payload = {
+ 'file_path': new_file_path,
+ 'dest_path': new_folder_path,
+ 'back_url': config['bfm_url']
+ }
+ response = requests.post(url, json=payload, headers=headers)
+ if response.status_code == 200:
+ print("Request was successful.")
+ print("Response: ", response.json())
+ else:
+ print("Request failed.")
+ # 特征识别
+ xml_path = new_folder_path + '/' + item.name.rpartition('.')[0] + '_FeatrueTable.XML'
+ print('xml_path', xml_path)
+ parser_obj = pc.FeatureParser(xml_path)
+ print('parser_obj', parser_obj)
+ slot = parser_obj.slots
+ print('slot', slot)
+ hole = parser_obj.holes
+ print('hole', hole)
+ size = parser_obj.size
+ print('size', size)
+ open_slot = parser_obj.open_slots
+ print('open_slot', open_slot)
+ vector = parser_obj.vectors
+ print('vector', vector)
+ print('all parcer', size)
+ try:
+ hole_time = pc.hole_time(parser_obj)
+ print('hole_time', hole_time)
+ except Exception as e:
+ return json.dumps({'code': 400, 'msg': '孔尺寸超限', 'error_msg': str(e)})
+ try:
+ slot_time = pc.slot_time(parser_obj)
+ print('slot_time', slot_time)
+ except Exception as e:
+ return json.dumps({'code': 400, 'msg': '槽尺寸超限', 'error_msg': str(e)})
+ try:
+ open_slot_time = pc.open_slot_time(parser_obj)
+ print('open_slot_time', open_slot_time)
+ except Exception as e:
+ return json.dumps({'code': 400, 'msg': '开口槽尺寸超限', 'error_msg': str(e)})
+ total_time = hole_time + slot_time + open_slot_time
+ print(hole_time, slot_time, open_slot_time)
+ print('total_time', total_time)
+ ret = {'feature_infos': [{'name': 'all_feature', 'type': '铣', 'process_time': total_time}],
+ 'boxshape': size, 'slugX': 10.0, 'slugY': 90.0, 'slugZ': 42.0,
+ 'turn_over_times': 2,
+ 'target_faces': ['A', 'B']}
+ self.model_feature = json.dumps(ret['feature_infos'], ensure_ascii=False)
+ self.model_length = size['length'] # 长 单位mm
+ self.model_width = size['width'] # 宽
+ self.model_height = size['height'] # 高
+ self.model_volume = size['length'] * size['width'] * size['height']
+ # 附件处理
+ base64_data = base64.b64encode(item.datas)
+ base64_datas = base64_data.decode('utf-8')
+ model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
+ # 读取文件
+ shapes = read_step_file(new_file_path)
+ output_file = os.path.join(new_folder_path, str(model_code) + '.stl')
+ write_stl_file(shapes, output_file, 'binary', 0.03, 0.5)
+ # 转化为glb
+ output_glb_file = os.path.join(new_folder_path, str(model_code) + '.glb')
+ util_path = get_resource_path('jikimo_gateway_api', 'static/util')
+ # 根据操作系统确定使用 'python' 还是 'python3'
+ python_cmd = 'python3' if os_name == 'Linux' else 'python'
+ print('python_cmd', python_cmd)
+ print('os_name', os_name)
+ # 使用引号包围路径
+ cmd = '%s "%s/stl2gltf.py" "%s" "%s" -b' % (python_cmd, util_path, output_file, output_glb_file)
+ logging.info(cmd)
+ os.system(cmd)
+ # 转base64
+ with open(output_glb_file, 'rb') as fileObj:
+ image_data = fileObj.read()
+ base64_data = base64.b64encode(image_data)
+ return base64_data
+ except Exception as e:
+ return UserError('模型自动报价失败,请联系管理员')
+
# 将attach的datas内容转为glb文件
def transition_glb_file(self, report_path, model_code):
shapes = read_step_file(report_path)
@@ -116,24 +263,7 @@ class QuickEasyOrder(models.Model):
raise ValidationError('只允许上传一个文件')
if item.upload_model_file:
file_attachment_id = item.upload_model_file[0]
- # 附件路径
- report_path = file_attachment_id._full_path(file_attachment_id.store_fname)
- logging.info("模型路径: %s" % report_path)
- base64_data = base64.b64encode(file_attachment_id.datas)
- base64_datas = base64_data.decode('utf-8')
- model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
- logging.info("模型编码: %s" % model_code)
- item.model_file = self.transition_glb_file(report_path, model_code)
- ret = self.feature_recognition(report_path, model_code)
- logging.info("自动报价返回值: %s" % ret)
- boxshape = ret['boxshape'].tolist()
- logging.info("自动报价boxshape: %s" % boxshape)
- logging.info('自动报价feature_infos:%s' % ret['feature_infos'])
- item.model_length = boxshape[0] # 长 单位mm
- item.model_width = boxshape[1] # 宽
- item.model_height = boxshape[2] # 高
- item.model_volume = boxshape[0] * boxshape[1] * boxshape[2]
- item.model_feature = json.dumps(ret['feature_infos'], ensure_ascii=False)
+ item.model_file = self.model_analyze(file_attachment_id)
self._get_price(item)
else:
item.model_file = False
diff --git a/sf_sale/models/sale_order.py b/sf_sale/models/sale_order.py
index 03ab0a88..d5263be8 100644
--- a/sf_sale/models/sale_order.py
+++ b/sf_sale/models/sale_order.py
@@ -7,6 +7,19 @@ from odoo.exceptions import UserError
class ReSaleOrder(models.Model):
_inherit = 'sale.order'
+ logistics_way = fields.Selection([('自提', '自提'), ('到付', '到付'), ('在线支付', '在线支付')], string='物流方式')
+ state = fields.Selection(
+ selection=[
+ ('draft', "报价"),
+ ('sent', "报价已发送"),
+ ('sale', "销售订单"),
+ ('done', "已锁定"),
+ ('cancel', '已废弃'),
+ ],
+ string="状态",
+ readonly=True, copy=False, index=True,
+ tracking=3,
+ default='draft')
deadline_of_delivery = fields.Date('订单交期', tracking=True)
person_of_delivery = fields.Char('交货人')
telephone_of_delivery = fields.Char('交货人电话号码')
@@ -37,7 +50,8 @@ class ReSaleOrder(models.Model):
'name': self.env['ir.sequence'].next_by_code('sale.order', sequence_date=now_time),
'partner_id': partner.id,
'check_status': 'approved',
- 'state': 'draft',
+ 'state': 'sale',
+ 'user_id': partner.user_id.id,
'person_of_delivery': delivery_name,
'telephone_of_delivery': delivery_telephone,
'address_of_delivery': delivery_address,
@@ -59,11 +73,12 @@ class ReSaleOrder(models.Model):
self.check_status = 'pending'
def get_customer(self):
- customer = self.env['res.partner'].search([('name', '=', '业务平台')])
+ customer = self.env['res.partner'].search([('name', '=', '业务平台')], limit=1, order='id asc')
if customer:
return customer
else:
partner = self.env['res.partner'].create({'name': '业务平台'})
+ self.env['res.users'].create({'name': '业务平台', 'partner_id': partner.id})
return partner
# 业务平台分配工厂时在创建完产品后再创建销售明细信息
@@ -79,13 +94,33 @@ class ReSaleOrder(models.Model):
'product_uom_qty': item['number'],
'model_glb_file': base64.b64decode(item['model_file']),
}
- return self.env['sale.order.line'].create(vals)
+ return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals)
+
+ @api.constrains('order_line')
+ def check_order_line(self):
+ for item in self:
+ if not item.order_line:
+ raise UserError('请选择【订单行】中的【产品】')
+ for line in item.order_line:
+ if not line.product_template_id:
+ raise UserError('请对【订单行】中的【产品】进行选择')
+ if not line.name:
+ raise UserError('请对【订单行】中的【说明】进行输入')
+ if line.product_qty == 0:
+ raise UserError('请对【订单行】中的【数量】进行输入')
+ if not line.product_uom:
+ raise UserError('请对【订单行】中的【计量单位】进行选择')
+ if line.price_unit == 0:
+ raise UserError('请对【订单行】中的【单价】进行输入')
+ if not line.tax_id:
+ raise UserError('请对【订单行】中的【税】进行选择')
class ResaleOrderLine(models.Model):
_inherit = 'sale.order.line'
model_glb_file = fields.Binary('模型的glb文件')
+ check_status = fields.Selection(related='order_id.check_status')
class RePurchaseOrder(models.Model):
@@ -93,6 +128,42 @@ class RePurchaseOrder(models.Model):
check_status = fields.Selection([('pending', '待审核'), ('approved', '已审核'), ('fail', '不通过')], '审核状态')
remark = fields.Text('备注')
+ user_id = fields.Many2one(
+ 'res.users', string='买家', index=True, tracking=True,
+ compute='_compute_user_id',
+ store=True)
+
+ def button_confirming(self):
+ self.write({'state': 'purchase', 'check_status': 'pending'})
+
+ @api.depends('partner_id')
+ def _compute_user_id(self):
+ if not self.user_id:
+ if self.partner_id:
+ self.user_id = self.partner_id.purchase_user_id.id
+ self.check_status = 'pending'
+ self.state = 'purchase'
+ else:
+ self.user_id = self.env.user.id
+
+ @api.constrains('order_line')
+ def check_order_line(self):
+ for item in self:
+ if not item.order_line:
+ raise UserError('该询价单未添加【产品】,请进行添加')
+ for line in item.order_line:
+ if not line.product_id:
+ raise UserError('【产品】未添加,请进行添加')
+ if not line.name:
+ raise UserError('请对【产品】中的【说明】进行输入')
+ if line.product_qty == 0:
+ raise UserError('请对【产品】中的【数量】进行输入')
+ if not line.product_uom:
+ raise UserError('请对【产品】中的【计量单位】进行选择')
+ if line.price_unit == 0:
+ raise UserError('请对【产品】中的【单价】进行输入')
+ if not line.taxes_id:
+ raise UserError('请对【产品】中的【税】进行选择')
def write(self, vals):
if self.env.user.has_group('sf_base.group_purchase_director'):
@@ -102,9 +173,25 @@ class RePurchaseOrder(models.Model):
return super().write(vals)
def button_confirm(self):
+<<<<<<< HEAD
self.check_status = 'pending'
res = super().button_confirm()
return res
+=======
+ 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
+>>>>>>> 8695a66e3d9be860f778caba8db5500885f4548f
class ResPartnerToSale(models.Model):
@@ -114,20 +201,20 @@ class ResPartnerToSale(models.Model):
@api.constrains('name')
def _check_name(self):
- obj = self.sudo().search([('name', '=', self.name), ('id', '!=', self.id)])
+ obj = self.sudo().search([('name', '=', self.name), ('id', '!=', self.id), ('active', '=', True)])
if obj:
raise UserError('该名称已存在,请重新输入')
@api.constrains('vat')
def _check_vat(self):
- obj = self.sudo().search([('vat', '=', self.vat), ('id', '!=', self.id)])
+ obj = self.sudo().search([('vat', '=', self.vat), ('id', '!=', self.id), ('active', '=', True)])
if obj:
raise UserError('该税ID已存在,请重新输入')
@api.constrains('email')
def _check_email(self):
if self.customer_rank > 0:
- obj = self.sudo().search([('email', '=', self.email), ('id', '!=', self.id)])
+ obj = self.sudo().search([('email', '=', self.email), ('id', '!=', self.id), ('active', '=', True)])
if obj:
raise UserError('该邮箱已存在,请重新输入')
@@ -145,31 +232,7 @@ class ResPartnerToSale(models.Model):
else:
domain = [('id', '=', False)]
return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
- return super()._name_search(name, args, operator, limit, name_get_uid)
-
- @api.onchange('user_id')
- def _get_salesman(self):
- if self.customer_rank > 0:
- self.user_id = self.env.user.id
-
- @api.onchange('purchase_user_id')
- def _get_purchaseman(self):
- if self.supplier_rank > 0:
- self.purchase_user_id = self.env.user.id
-
-
-class ResUserToSale(models.Model):
- _inherit = 'res.users'
-
- @api.model
- def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
- if self._context.get('is_sale'):
- if self.env.user.has_group('sf_base.group_sale_director'):
- domain = []
- elif self.env.user.has_group('sf_base.group_sale_salemanager'):
- domain = [('id', '=', self.env.user.id)]
- return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
- elif self._context.get('supplier_rank'):
+ elif self._context.get('is_supplier') or self.env.user.has_group('sf_base.group_purchase_director'):
if self.env.user.has_group('sf_base.group_purchase_director'):
domain = [('supplier_rank', '>', 0)]
elif self.env.user.has_group('sf_base.group_purchase'):
@@ -182,3 +245,41 @@ class ResUserToSale(models.Model):
domain = [('id', '=', False)]
return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
return super()._name_search(name, args, operator, limit, name_get_uid)
+
+ @api.onchange('user_id')
+ def _get_salesman(self):
+ if self.customer_rank > 0:
+ if self.env.user.has_group('sf_base.group_sale_salemanager'):
+ self.user_id = self.env.user.id
+
+ @api.onchange('purchase_user_id')
+ def _get_purchaseman(self):
+ if self.supplier_rank > 0:
+ if self.env.user.has_group('sf_base.group_purchase'):
+ self.purchase_user_id = self.env.user.id
+
+
+class ResUserToSale(models.Model):
+ _inherit = 'res.users'
+
+ @api.model
+ def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
+ if self._context.get('is_sale'):
+ if self.env.user.has_group('sf_base.group_sale_director'):
+ domain = []
+ elif self.env.user.has_group('sf_base.group_sale_salemanager'):
+ if self.id != self.env.user.id:
+ domain = [('id', '=', self.id)]
+ else:
+ domain = [('id', '=', self.env.user.id)]
+ return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
+ elif self._context.get('supplier_rank'):
+ if self.env.user.has_group('sf_base.group_purchase_director'):
+ domain = []
+ elif self.env.user.has_group('sf_base.group_purchase'):
+ if self.id != self.env.user.id:
+ domain = [('id', '=', self.id)]
+ else:
+ domain = [('id', '=', self.env.user.id)]
+ return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
+ return super()._name_search(name, args, operator, limit, name_get_uid)
diff --git a/sf_sale/security/group_security.xml b/sf_sale/security/group_security.xml
index 431b872b..c6af4225 100644
--- a/sf_sale/security/group_security.xml
+++ b/sf_sale/security/group_security.xml
@@ -32,7 +32,7 @@
销售经理查看自己的客户
- [('user_id','=',user.id),('customer_rank','>',0)]
+ [('user_id', '=', user.id),('customer_rank', '>', 0)]
@@ -64,8 +64,9 @@
采购总监查看所有的订单
- [(1,'=',1),('check_status','!=', False]
+ [(1,'=',1)]
+
diff --git a/sf_sale/security/ir.model.access.csv b/sf_sale/security/ir.model.access.csv
index 9489a6cc..566a7c70 100644
--- a/sf_sale/security/ir.model.access.csv
+++ b/sf_sale/security/ir.model.access.csv
@@ -1,5 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_quick_easy_order,quick_easy_order,model_quick_easy_order,base.group_system,1,1,1,1
+access_quick_easy_order,quick_easy_order,model_quick_easy_order,base.group_system,1,1,1,0
+access_quick_easy_order_group_sale_salemanager,quick_easy_order_group_sale_salemanager,model_quick_easy_order,sf_base.group_sale_salemanager,1,1,1,0
+access_quick_easy_order_group_sale_director,quick_easy_order_group_sale_director,model_quick_easy_order,sf_base.group_sale_director,1,1,1,0
access_sf_auto_quatotion_common,sf_auto_quatotion_common,model_sf_auto_quatotion_common,base.group_system,1,1,1,1
access_sale_order_manager,sale_order_manager,model_sale_order,sf_base.group_sale_salemanager,1,1,1,0
access_sale_order_director,sale_order_director,model_sale_order,sf_base.group_sale_director,1,1,1,0
@@ -12,7 +14,7 @@ access_product_product_group_sale_salemanager,product_product_group_sale_saleman
access_product_product_group_sale_director,product_product_group_sale_director,product.model_product_product,sf_base.group_sale_director,1,1,1,0
access_product_product_group_purchase,product_product_group_purchase,product.model_product_product,sf_base.group_purchase,1,0,0,0
access_product_product_group_purchase_director,product_product_group_purchase_director,product.model_product_product,sf_base.group_purchase_director,1,1,1,0
-access_product_template_group_sale_salemanager,product_product_group_sale_salemanager,product.model_product_template,sf_base.group_sale_salemanager,1,0,0,0
+access_product_template_group_sale_salemanager,product_template_group_sale_salemanager,product.model_product_template,sf_base.group_sale_salemanager,1,0,0,0
access_product_template_group_sale_director,product_template_group_sale_director,product.model_product_template,sf_base.group_sale_director,1,1,1,0
access_product_template_group_purchase,product_template_group_purchase,product.model_product_template,sf_base.group_purchase,1,0,0,0
access_product_template_group_purchase_director,product_template_group_purchase_director,product.model_product_template,sf_base.group_purchase_director,1,1,1,0
@@ -20,8 +22,8 @@ access_product_template_group_plan_dispatch,product_template_group_plan_dispatch
access_product_template_group_plan_director,product_template_group_plan_director,product.model_product_template,sf_base.group_plan_director,1,1,1,0
access_stock_picking_group_sale_salemanager,stock_picking_group_sale_salemanager,stock.model_stock_picking,sf_base.group_sale_salemanager,1,0,0,0
access_stock_picking_group_sale_director,stock_picking_group_sale_director,stock.model_stock_picking,sf_base.group_sale_director,1,0,0,0
-access_stock_picking_group_purchase,stock_picking_group_purchase,stock.model_stock_picking,sf_base.group_purchase,1,0,0,0
-access_stock_picking_group_purchase_director,stock_picking_group_purchase_director,stock.model_stock_picking,sf_base.group_purchase_director,1,0,0,0
+access_stock_picking_group_purchase,stock_picking_group_purchase,stock.model_stock_picking,sf_base.group_purchase,1,1,1,0
+access_stock_picking_group_purchase_director,stock_picking_group_purchase_director,stock.model_stock_picking,sf_base.group_purchase_director,1,1,1,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_resource_resource_group_sale_director,resource_resource_group_sale_director,resource.model_resource_resource,sf_base.group_sale_director,1,1,1,0
@@ -29,24 +31,28 @@ access_mrp_bom_group_sale_salemanager,mrp_bom_group_sale_salemanager,mrp.model_m
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_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_quality,mrp_bom_group_quality,mrp.model_mrp_bom,sf_base.group_quality,1,0,0,0
+access_mrp_bom_group_quality_director,mrp_bom_group_quality_director,mrp.model_mrp_bom,sf_base.group_quality_director,1,0,0,0
access_stock_move_group_sale_salemanager,stock_move_group_sale_salemanager,stock.model_stock_move,sf_base.group_sale_salemanager,1,0,0,0
access_stock_move_group_sale_director,stock_move_group_sale_director,stock.model_stock_move,sf_base.group_sale_director,1,0,0,0
-access_stock_move_group_purchase,stock_move_group_purchase,stock.model_stock_move,sf_base.group_purchase,1,0,0,0
-access_stock_move_group_purchase_director,stock_move_group_purchase_director,stock.model_stock_move,sf_base.group_purchase_director,1,0,0,0
+access_stock_move_group_purchase,stock_move_group_purchase,stock.model_stock_move,sf_base.group_purchase,1,1,1,0
+access_stock_move_group_purchase_director,stock_move_group_purchase_director,stock.model_stock_move,sf_base.group_purchase_director,1,1,1,0
access_stock_warehouse_orderpoint_group_sale_salemanager,stock_warehouse_orderpoint_group_sale_salemanager,stock.model_stock_warehouse_orderpoint,sf_base.group_sale_salemanager,1,0,0,0
access_stock_warehouse_orderpoint_group_sale_director,stock_warehouse_orderpoint_group_sale_director,stock.model_stock_warehouse_orderpoint,sf_base.group_sale_director,1,0,0,0
-access_stock_warehouse_orderpoint_group_purchase,stock_warehouse_orderpoint_group_purchase,stock.model_stock_warehouse_orderpoint,sf_base.group_purchase,1,0,0,0
-access_stock_warehouse_orderpoint_group_purchase_director,stock_warehouse_orderpoint_group_purchase_director,stock.model_stock_warehouse_orderpoint,sf_base.group_purchase_director,1,0,0,0
+access_stock_warehouse_orderpoint_group_purchase,stock_warehouse_orderpoint_group_purchase,stock.model_stock_warehouse_orderpoint,sf_base.group_purchase,1,1,0,0
+access_stock_warehouse_orderpoint_group_purchase_director,stock_warehouse_orderpoint_group_purchase_director,stock.model_stock_warehouse_orderpoint,sf_base.group_purchase_director,1,1,0,0
access_uom_uom_group_sale_salemanager,uom_uom_group_sale_salemanager,uom.model_uom_uom,sf_base.group_sale_salemanager,1,0,0,0
access_uom_uom_group_sale_director,uom_uom_group_sale_director,uom.model_uom_uom,sf_base.group_sale_director,1,1,1,0
access_uom_uom_group_purchase,uom_uom_group_purchase,uom.model_uom_uom,sf_base.group_purchase,1,0,0,0
-access_uom_uom_group_purchase_director,uom_uom_group_purchase_director,uom.model_uom_uom,sf_base.group_purchase_director,1,0,0,0
+access_uom_uom_group_purchase_director,uom_uom_group_purchase_director,uom.model_uom_uom,sf_base.group_purchase_director,1,1,1,0
access_uom_category_group_sale_salemanager,uom_category_group_sale_salemanager,uom.model_uom_category,sf_base.group_sale_salemanager,1,0,0,0
access_uom_category_group_sale_director,uom_category_group_sale_director,uom.model_uom_category,sf_base.group_sale_director,1,1,1,0
access_uom_category_group_purchase,uom_category_group_purchase,uom.model_uom_category,sf_base.group_purchase,1,0,0,0
-access_uom_category_group_purchase_director,uom_category_group_purchase_director,uom.model_uom_category,sf_base.group_purchase_director,1,0,0,0
+access_uom_category_group_purchase_director,uom_category_group_purchase_director,uom.model_uom_category,sf_base.group_purchase_director,1,1,1,0
access_sale_order_check_wizard_group_sale_salemanager,sale_order_check_wizard_group_sale_salemanager,model_sale_order_check_wizard,sf_base.group_sale_salemanager,1,1,1,0
access_sale_order_check_wizard_group_sale_director,sale_order_check_wizard_group_sale_director,model_sale_order_check_wizard,sf_base.group_sale_director,1,1,1,0
+access_account_move_line_group_sale_salemanager,account_move_line_group_sale_salemanager,account.model_account_move_line,sf_base.group_sale_salemanager,1,1,1,0
+access_account_move_line_group_sale_director,account_move_line_group_sale_director,account.model_account_move_line,sf_base.group_sale_director,1,1,1,0
access_account_move_line_group_purchase,account_move_line_group_purchase,account.model_account_move_line,sf_base.group_purchase,1,1,1,0
access_account_move_line_group_purchase_director,account_move_line_group_purchase_director,account.model_account_move_line,sf_base.group_purchase_director,1,1,1,0
access_res_users_group_purchase,res_user_group_purchase,model_res_users,sf_base.group_purchase,1,1,1,0
@@ -67,3 +73,20 @@ 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,1,0,0
+access_res_partner_group_sale_salemanager,res_partner_group_sale_salemanager,base.model_res_partner,sf_base.group_sale_salemanager,1,0,1,0
+access_res_partner_group_sale_director,res_partner_group_sale_director,base.model_res_partner,sf_base.group_sale_director,1,0,1,0
+access_sale_order_cancel_group_sale_salemanager,sale_order_cancel_group_sale_salemanager,sale.model_sale_order_cancel,sf_base.group_sale_salemanager,1,1,1,0
+access_sale_order_cancel_group_sale_director,sale_order_cancel_group_sale_director,sale.model_sale_order_cancel,sf_base.group_sale_director,1,1,1,0
+access_res_partner_group_purchase,res_partner_group_purchase,base.model_res_partner,sf_base.group_purchase,1,0,1,0
+access_res_partner_group_purchase_director,res_partner_group_purchase_director,base.model_res_partner,sf_base.group_purchase_director,1,0,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
+access_sale_report_group_sale_salemanager,sale_report_group_sale_salemanager,sale.model_sale_report,sf_base.group_sale_salemanager,1,0,1,0
+access_sale_report_group_sale_director,sale_report_group_sale_director,sale.model_sale_report,sf_base.group_sale_director,1,0,1,0
+access_product_supplierinfo_group_purchase_director,product.supplierinfo group_purchase_director,product.model_product_supplierinfo,sf_base.group_purchase_director,1,1,1,0
+access_product_category_group_purchase_director,product.category group_purchase_director,product.model_product_category,sf_base.group_purchase_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..6e494214
--- /dev/null
+++ b/sf_sale/static/js/setTableWidth.js
@@ -0,0 +1,29 @@
+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() + 10
+ const i = $(this).index()
+ tbody_tr.each(function () {
+ if($(this).children().length > 2) {
+ $(this).children().eq(i).css('min-width', width + 'px')
+ }
+ })
+ })
+ const resizeEvent = new Event('resize');
+ window.dispatchEvent(resizeEvent);
+}
+
+$(function () {
+ setTableWidth()
+})
+
diff --git a/sf_sale/views/purchase_order_view.xml b/sf_sale/views/purchase_order_view.xml
index 3b2d8d09..4c6e47e3 100644
--- a/sf_sale/views/purchase_order_view.xml
+++ b/sf_sale/views/purchase_order_view.xml
@@ -6,22 +6,29 @@
purchase.order
-
+
+
-
+
+
+
+
@@ -126,12 +133,23 @@
+<<<<<<< HEAD
+=======
+
+>>>>>>> 8695a66e3d9be860f778caba8db5500885f4548f
purchase.order.tree.inherit.sf
purchase.order
+<<<<<<< HEAD
+=======
+
+ check_status desc,date_approve asc
+
+
+>>>>>>> 8695a66e3d9be860f778caba8db5500885f4548f
-
+
@@ -119,6 +119,6 @@
+ groups="sales_team.group_sale_salesman,sf_base.group_sale_salemanager,sf_base.group_sale_director"/>
\ No newline at end of file
diff --git a/sf_sale/views/res_partner_view.xml b/sf_sale/views/res_partner_view.xml
index 2ab384eb..4b2d55d6 100644
--- a/sf_sale/views/res_partner_view.xml
+++ b/sf_sale/views/res_partner_view.xml
@@ -6,53 +6,95 @@
res.partner
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
1
+ {'readonly': [('id','!=', False)]}
-
+
- {'required': [('phone', '=', False)]}
+ {'required': [('phone', '=', False)],'readonly': [('id','!=', False)]}
- {'required': [('mobile', '=', False)]}
+ {'required': [('mobile', '=', False)],'readonly': [('id','!=', False)]}
- {'required': [('supplier_rank','>', 0)]}
+ {'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]}
- {'required': [('supplier_rank','>', 0)]}
+ {'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]}
- {'required': [('supplier_rank','>', 0)]}
+ {'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]}
- {'required': [('supplier_rank','>', 0)]}
+ {'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]}
+ attrs="{'required' : [('customer_rank','>', 0)]}"/>
1
-
+ {'readonly': [('id','!=', False)]}
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
-
- res.partner.property.form.inherit.sf
+
+ res.partner.account.form.inherit.sf
res.partner
@@ -61,14 +103,90 @@
widget="many2one_avatar_user"
attrs="{'required' : [('supplier_rank','>', 0)],'readonly': [('customer_rank','>', 0)]}"/>
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
-
+
+ res.partner.delivery.form.inherit.sf
+ res.partner
+
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+
+
+
+ res.partner.stock.form.inherit.sf
+ res.partner
+
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+
+
+
+ res.partner.mrp.subcontracting.form.inherit.sf
+ res.partner
+
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+
+
+
+ res.partner.purchase.form.inherit.sf
+ res.partner
+
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+
+
+
+ res.partner.team.form.inherit.sf
+ res.partner
+
+
+
+ {'readonly': [('id','!=', False)]}
+
+
+
+
+
res.partner.property.form.inherit.sf
res.partner
+
+ false
+
diff --git a/sf_sale/views/sale_order_view.xml b/sf_sale/views/sale_order_view.xml
index d1f0dfb8..e6e7e8a2 100644
--- a/sf_sale/views/sale_order_view.xml
+++ b/sf_sale/views/sale_order_view.xml
@@ -1,11 +1,62 @@
+
+ sale.order.search.inherit.sf
+ sale.order
+ primary
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 报价
+ ir.actions.act_window
+ sale.order
+
+ tree,kanban,form,calendar,pivot,graph,activity
+
+ {'search_default_my_quotation': 1}
+
+
+ Create a new quotation, the first step of a new sale!
+
+
+ Once the quotation is confirmed by the customer, it becomes a sales order.
+
+ You will be able to create an invoice and collect the payment.
+
+
+
+
+
+
+
+
+
+
+
sale.order.form.inherit.sf
sale.order
+
+
+
+ attrs="{'invisible': ['|','&',('check_status', '!=', 'approved'),('state', 'in', ['draft','cancel']),'&','&',('check_status', '=', 'approved'),('state', 'in', ['sale','cancel']),('schedule_status', 'not in', False)]}"/>
- {'invisible': ['|',('check_status', '!=', 'approved'),('schedule_status',
- 'not in', ['to schedule',False])]}
+ {'invisible': ['|','&',('state', 'in',
+ ['cancel','draft']),('check_status',
+ 'in',
+ [False,'approved']),'&','&',('check_status', '=', 'approved'),('state', 'in',
+ ['sale','cancel','draft']),('schedule_status', 'not in', False)]}
@@ -58,12 +112,11 @@
-
+
+ string="模型文件" attrs="{'readonly': [('state', 'in', ['draft'])]}"/>
{'readonly': [('state', 'in', ['cancel','sale'])]}
@@ -120,7 +173,6 @@
sale.order
-
下单日期
@@ -142,6 +194,7 @@
+ check_status desc,create_date asc
False
@@ -165,6 +218,7 @@
+ schedule_status desc,date_order asc
False
@@ -186,6 +240,9 @@
product.template
+
diff --git a/sf_tool_management/__init__.py b/sf_tool_management/__init__.py
index fb05df81..ea8e8e0b 100644
--- a/sf_tool_management/__init__.py
+++ b/sf_tool_management/__init__.py
@@ -1,6 +1,7 @@
# -*-coding:utf-8-*-
from . import models
from . import wizard
+from . import controllers
from odoo import api, SUPERUSER_ID
diff --git a/sf_tool_management/__manifest__.py b/sf_tool_management/__manifest__.py
index e334c32a..3eee245a 100644
--- a/sf_tool_management/__manifest__.py
+++ b/sf_tool_management/__manifest__.py
@@ -16,6 +16,8 @@
'security/ir.model.access.csv',
'wizard/wizard_view.xml',
'views/tool_base_views.xml',
+ 'views/mrp_workcenter_views.xml',
+ 'views/sf_maintenance_equipment.xml',
'views/menu_view.xml',
'views/tool_material_search.xml',
],
diff --git a/sf_tool_management/controllers/__init__.py b/sf_tool_management/controllers/__init__.py
new file mode 100644
index 00000000..e046e49f
--- /dev/null
+++ b/sf_tool_management/controllers/__init__.py
@@ -0,0 +1 @@
+from . import controllers
diff --git a/sf_tool_management/controllers/controllers.py b/sf_tool_management/controllers/controllers.py
new file mode 100644
index 00000000..b40abb69
--- /dev/null
+++ b/sf_tool_management/controllers/controllers.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+import logging
+import json
+import base64
+from odoo import http
+from odoo.http import request
+
+
+class Manufacturing_Connect(http.Controller):
+
+ @http.route('/AutoDeviceApi/MachineToolLibrary', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
+ cors="*")
+ def get_equipment_tool_Info(self, **kw):
+ """
+ 机床刀库实时信息
+ :param kw:
+ :return:
+ """
+ logging.info('get_equipment_tool_Info:%s' % kw)
+ try:
+ datas = request.httprequest.data
+ ret = json.loads(datas)
+ ret = json.loads(ret['result'])
+ logging.info('DeviceId:%s' % ret)
+ equipment = request.env['maintenance.equipment'].sudo().search([('name', '=', ret['DeviceId'])])
+
+ res = {'Succeed': True, 'Datas': []}
+ if equipment:
+ for item in equipment:
+ data = []
+ for equipment_tool_id in item.product_template_ids:
+ functional_tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search(
+ [('code', '=', equipment_tool_id.tool_code)])
+
+ alarm_time = None
+ if functional_tool_id.functional_tool_status == '报警':
+ alarm_time = self.env['sf.functional.tool.warning'].sudo().search(
+ [('code', '=', equipment_tool_id.tool_code)]).alarm_time
+ equipment_tool = {
+ 'RfidCode': None,
+ 'ToolId': equipment_tool_id.code,
+ 'ToolName': equipment_tool_id.functional_tool_name_id.name,
+ 'MaxLife': equipment_tool_id.life_value_max,
+ 'UseLife': equipment_tool_id.used_value,
+ 'AddDatetime': equipment_tool_id.tool_install_time,
+ 'State': functional_tool_id.functional_tool_status,
+ 'WarnDate': alarm_time if alarm_time else False
+ }
+ data.append(equipment_tool)
+ res['Datas'].append({
+ 'DeviceId': item.name,
+ 'Data': data
+ })
+ except Exception as e:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
+ logging.info('get_equipment_tool_Info error:%s' % e)
+ return json.JSONEncoder().encode(res)
+
+ @http.route('/AutoDeviceApi/ToolGroups', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
+ cors="*")
+ def get_functional_tool_groups_Info(self, **kw):
+ """
+ 刀具组接口
+ :param kw:
+ :return:
+ """
+ logging.info('get_functional_tool_groups_Info:%s' % kw)
+ try:
+ datas = request.httprequest.data
+ ret = json.loads(datas)
+ ret = json.loads(ret['result'])
+ logging.info('DeviceId:%s' % ret)
+ functional_tools = request.env['sf.functional.cutting.tool.entity'].sudo().search([])
+
+ res = {'Succeed': True, 'Datas': []}
+ if functional_tools:
+ for item in functional_tools:
+ res['Datas'].append({
+ 'GroupName': item.tool_groups_id.name,
+ 'ToolId': item.code,
+ 'ToolName': item.name
+ })
+ except Exception as e:
+ res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
+ logging.info('get_functional_tool_groups_Info error:%s' % e)
+ return json.JSONEncoder().encode(res)
\ No newline at end of file
diff --git a/sf_tool_management/models/__init__.py b/sf_tool_management/models/__init__.py
index c942dcac..98c06d41 100644
--- a/sf_tool_management/models/__init__.py
+++ b/sf_tool_management/models/__init__.py
@@ -1,4 +1,5 @@
from . import base
from . import tool_material_search
from . import maintenance_equipment
+from . import mrp_workorder
diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py
index 37c534da..ab5e0649 100644
--- a/sf_tool_management/models/base.py
+++ b/sf_tool_management/models/base.py
@@ -1,16 +1,21 @@
# -*- coding: utf-8 -*-
+import re
+import json
+import requests
from datetime import timedelta
-
-from odoo import fields, models, api
from odoo import SUPERUSER_ID
+from odoo import fields, models, api
from odoo.exceptions import ValidationError
+from odoo.addons.sf_base.commons.common import Common
class FunctionalCuttingToolEntity(models.Model):
_name = 'sf.functional.cutting.tool.entity'
_description = '功能刀具列表'
- # code = fields.Char('序列号')
+ tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id')
+ code = fields.Char('编码', related='functional_tool_name_id.code')
+ rfid = fields.Char('rfid', readonly=True)
name = fields.Char(related='functional_tool_name_id.name')
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具名称', readonly=True)
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', readonly=True)
@@ -22,7 +27,7 @@ class FunctionalCuttingToolEntity(models.Model):
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=True)
coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], string='粗/中/精', readonly=True)
new_former = fields.Selection([('0', '新'), ('1', '旧')], string='新/旧', readonly=True)
- tool_loading_length = fields.Float(strin='总长度(mm)', readonly=True)
+ tool_loading_length = fields.Float(string='总长度(mm)', readonly=True)
functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True)
effective_length = fields.Float(string='有效长(mm)', readonly=True)
tool_room_num = fields.Integer(string='刀具房数量', readonly=True)
@@ -43,13 +48,13 @@ class FunctionalCuttingToolEntity(models.Model):
if record.barcode_id.quant_ids:
for quant_id in record.barcode_id.quant_ids:
if quant_id.inventory_quantity_auto_apply > 0:
- record.current_location_id = quant_id.location_id
- record.current_location = quant_id.location_id.name
+ record.sudo().current_location_id = quant_id.location_id
+ record.sudo().current_location = quant_id.location_id.name
if record.current_location_id:
- record.get_location_num()
+ record.sudo().get_location_num()
else:
- record.current_location_id = False
- record.current_location = False
+ record.sudo().current_location_id = False
+ record.sudo().current_location = False
def get_location_num(self):
"""
@@ -107,7 +112,7 @@ class FunctionalCuttingToolEntity(models.Model):
suitable_machining_method_ids = fields.Many2many(
'maintenance.equipment.image', 'rel_machining_product_template_tool_entity', '适合加工方式',
- domain=[('type', '=', '加工能力')])
+ domain=[('type', '=', '加工能力')], compute='_compute_maintenance_equipment_image')
blade_tip_characteristics_id = fields.Many2one(
'maintenance.equipment.image', '刀尖特征',
domain=[('type', '=', '刀尖特征')])
@@ -118,30 +123,33 @@ class FunctionalCuttingToolEntity(models.Model):
'maintenance.equipment.image', 'rel_cutting_product_template_tool_entity', '走刀方向',
domain=[('type', '=', '走刀方向')])
suitable_coolant_ids = fields.Many2many(
- 'maintenance.equipment.image', 'rel_coolant_product_template_tool_entity', '适合冷却液',
- domain=[('type', '=', '冷却液')])
+ 'maintenance.equipment.image', 'rel_coolants_product_template_tool_entity', '适合冷却方式',
+ domain=[('type', '=', '冷却方式')])
@api.depends('cutting_tool_integral_model_id', 'cutting_tool_blade_model_id')
def _compute_maintenance_equipment_image(self):
for record in self:
+ print('111')
if record.cutting_tool_integral_model_id:
- record.suitable_machining_method_ids = record.cutting_tool_integral_model_id.suitable_machining_method_ids.ids
- record.blade_tip_characteristics_id = record.cutting_tool_integral_model_id.blade_tip_characteristics_id.ids
- record.handle_type_id = record.cutting_tool_integral_model_id.handle_type_id.ids
- record.cutting_direction_ids = record.cutting_tool_integral_model_id.cutting_direction_ids.ids
- record.suitable_coolant_ids = record.cutting_tool_integral_model_id.suitable_coolant_ids.ids
+ print(record.cutting_tool_integral_model_id)
+ record.sudo().suitable_machining_method_ids = record.cutting_tool_integral_model_id.suitable_machining_method_ids.ids
+ record.sudo().blade_tip_characteristics_id = record.cutting_tool_integral_model_id.blade_tip_characteristics_id.id
+ record.sudo().handle_type_id = record.cutting_tool_integral_model_id.handle_type_id.id
+ record.sudo().cutting_direction_ids = record.cutting_tool_integral_model_id.cutting_direction_ids.ids
+ record.sudo().suitable_coolant_ids = record.cutting_tool_integral_model_id.suitable_coolant_ids.ids
+ print(record.cutting_tool_integral_model_id.blade_tip_characteristics_id.ids)
elif record.cutting_tool_blade_model_id:
- record.suitable_machining_method_ids = record.cutting_tool_blade_model_id.suitable_machining_method_ids.ids
- record.blade_tip_characteristics_id = record.cutting_tool_blade_model_id.blade_tip_characteristics_id.ids
- record.handle_type_id = record.cutting_tool_blade_model_id.handle_type_id.ids
- record.cutting_direction_ids = record.cutting_tool_blade_model_id.cutting_direction_ids.ids
- record.suitable_coolant_ids = record.cutting_tool_blade_model_id.suitable_coolant_ids.ids
+ record.sudo().suitable_machining_method_ids = record.cutting_tool_blade_model_id.suitable_machining_method_ids.ids
+ record.sudo().blade_tip_characteristics_id = record.cutting_tool_blade_model_id.blade_tip_characteristics_id.id
+ record.sudo().handle_type_id = record.cutting_tool_blade_model_id.handle_type_id.id
+ record.sudo().cutting_direction_ids = record.cutting_tool_blade_model_id.cutting_direction_ids.ids
+ record.sudo().suitable_coolant_ids = record.cutting_tool_blade_model_id.suitable_coolant_ids.ids
else:
- record.suitable_machining_method_ids = []
- record.blade_tip_characteristics_id = []
- record.handle_type_id = []
- record.cutting_direction_ids = []
- record.suitable_coolant_ids = []
+ record.sudo().suitable_machining_method_ids = []
+ record.sudo().blade_tip_characteristics_id = None
+ record.sudo().handle_type_id = None
+ record.sudo().cutting_direction_ids = []
+ record.sudo().suitable_coolant_ids = []
def _get_functional_tool_model_ids(self, functional_tool_model_code):
functional_tool_model_ids = []
@@ -170,11 +178,42 @@ class FunctionalCuttingToolEntity(models.Model):
('coarse_middle_thin', '=', self.coarse_middle_thin)]
return result
+ # ==========刀具组接口==========
+ def _register_functional_tool_groups(self, obj):
+ create_url = '/AutoDeviceApi/ToolGroups'
+ sf_sync_config = self.env['res.config.settings'].get_values()
+ token = sf_sync_config['token']
+ sf_secret_key = sf_sync_config['sf_secret_key']
+ headers = Common.get_headers(obj, token, sf_secret_key)
+ strurl = sf_sync_config['sf_url'] + create_url
+ val = {
+ 'ToolName': obj.name,
+ 'GroupName': obj.tool_groups_id.name,
+ 'ToolId': obj.code
+ }
+ kw = json.dumps(val, ensure_ascii=False)
+ r = requests.post(strurl, json={}, data={'kw': kw, 'token': token}, headers=headers)
+ ret = r.json()
+ if r == 200:
+ return "刀具组发送成功"
+ else:
+ raise ValidationError("刀具组发送失败")
+
+ # @api.model_create_multi
+ # def create(self, vals):
+ # obj = super(FunctionalCuttingToolEntity, self).create(vals)
+ # # 调用刀具组接口
+ # self._register_functional_tool_groups(obj)
+ # return obj
+
class FunctionalToolWarning(models.Model):
_name = 'sf.functional.tool.warning'
_description = '功能刀具预警'
+ code = fields.Char('编码', related='functional_tool_name_id.code')
+ rfid = fields.Char('rfid', related='functional_tool_name_id.rfid')
+ tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id')
name = fields.Char('名称', invisible=True, readonly=True, related='functional_tool_name_id.name')
# 机床信息
production_line_id = fields.Many2one('sf.production.line', string='生产线',
@@ -234,6 +273,7 @@ class FunctionalToolWarning(models.Model):
class StockMoveLine(models.Model):
_inherit = 'stock.move.line'
_description = '功能刀具出入库记录'
+ _order = 'date desc'
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具名称')
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
@@ -242,6 +282,9 @@ class StockMoveLine(models.Model):
diameter = fields.Integer(string='刀具直径(mm)', related='functional_tool_name_id.functional_tool_diameter')
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', related='functional_tool_name_id.knife_tip_r_angle')
install_tool_time = fields.Datetime("刀具组装时间", related='functional_tool_name_id.tool_loading_time')
+ code = fields.Char('编码', related='functional_tool_name_id.code')
+ rfid = fields.Char('rfid', related='functional_tool_name_id.rfid')
+ tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id')
@api.model
def _read_group_functional_tool_type_id(self, categories, domain, order):
@@ -253,11 +296,12 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
_name = 'sf.real.time.distribution.of.functional.tools'
_description = '功能刀具安全库存'
- name = fields.Char('功能刀具名称')
- sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型',
+ name = fields.Char('功能刀具名称', readonly=True, compute='_compute_name')
+ tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=False, required=True)
+ sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=False,
group_expand='_read_mrs_cutting_tool_type_ids', store=True)
- diameter = fields.Integer(string='刀具直径(mm)')
- knife_tip_r_angle = fields.Float(string='刀尖R角(mm)')
+ diameter = fields.Integer(string='刀具直径(mm)', readonly=False)
+ knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=False)
tool_stock_num = fields.Integer(string='刀具房数量')
side_shelf_num = fields.Integer(string='线边刀库数量')
on_tool_stock_num = fields.Integer(string='机内刀库数量')
@@ -266,10 +310,10 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
max_stock_num = fields.Integer('最高库存量')
batch_replenishment_num = fields.Integer('批次补货量', readonly=True, compute='_compute_batch_replenishment_num')
unit = fields.Char('单位')
- image = fields.Binary('图片')
+ image = fields.Binary('图片', readonly=False)
- coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], string='粗/中/精')
- whether_standard_knife = fields.Boolean(string='是否标准刀', default=True)
+ coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], string='粗/中/精', readonly=False)
+ whether_standard_knife = fields.Boolean(string='是否标准刀', default=True, readonly=False)
# 能力特征信息
suitable_machining_method_ids = fields.Many2many(
'maintenance.equipment.image', 'rel_machining_product_template_distribution', '适合加工方式',
@@ -286,8 +330,8 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
'maintenance.equipment.image', 'rel_cutting_product_template_distribution', '走刀方向',
domain=[('type', '=', '走刀方向')], related='sf_functional_cutting_tool_entity_ids.cutting_direction_ids')
suitable_coolant_ids = fields.Many2many(
- 'maintenance.equipment.image', 'rel_coolant_product_template_distribution', '适合冷却液',
- domain=[('type', '=', '冷却液')], related='sf_functional_cutting_tool_entity_ids.suitable_coolant_ids')
+ 'maintenance.equipment.image', 'rel_coolants_product_template_distribution', '适合冷却方式',
+ domain=[('type', '=', '冷却方式')], related='sf_functional_cutting_tool_entity_ids.suitable_coolant_ids')
sf_functional_cutting_tool_entity_ids = fields.Many2many('sf.functional.cutting.tool.entity',
'sf_functional_cutting_tool_entity_ref',
@@ -296,6 +340,20 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
sf_functional_tool_assembly_ids = fields.Many2many('sf.functional.tool.assembly', 'sf_functional_tool_assembly_ref',
'功能刀具组装单', readonly=True)
+ @api.depends('tool_groups_id', 'diameter', 'knife_tip_r_angle')
+ def _compute_name(self):
+ for obj in self:
+ if obj.tool_groups_id:
+ obj.sudo().name = '%s-D%sR%s' % (obj.tool_groups_id.name, obj.diameter, obj.knife_tip_r_angle)
+ else:
+ obj.sudo().name = None
+
+ @api.constrains('min_stock_num', 'max_stock_num')
+ def _check_stock_num(self):
+ for obj in self:
+ if obj.min_stock_num > obj.max_stock_num:
+ raise ValidationError('【最低安全库存】不能高于【最高安全库存】!!!')
+
@api.model
def _read_mrs_cutting_tool_type_ids(self, categories, domain, order):
mrs_cutting_tool_type_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
@@ -306,46 +364,46 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
for tool in self:
if tool:
# 判断功能刀具组装单是否已经完成
- tool.estimate_functional_tool_assembly_ids(tool)
- tool.get_stock_num(tool)
+ tool.sudo().estimate_functional_tool_assembly_ids(tool)
+ tool.sudo().get_stock_num(tool)
# 计算当前库存量
- tool.tool_stock_total = tool.tool_stock_num + tool.side_shelf_num + tool.on_tool_stock_num
+ tool.sudo().tool_stock_total = tool.tool_stock_num + tool.side_shelf_num + tool.on_tool_stock_num
# 如果当前库存量小于最低库存量,计算批次补货量
- tool.open_batch_replenishment_num(tool)
+ tool.sudo().open_batch_replenishment_num(tool)
def open_batch_replenishment_num(self, tool):
"""
计算批次补货量
"""
if tool.tool_stock_total < tool.min_stock_num:
- tool.batch_replenishment_num = tool.max_stock_num - tool.tool_stock_total
+ tool.sudo().batch_replenishment_num = tool.max_stock_num - tool.tool_stock_total
# 根据判断创建功能刀具组装单
- if not tool.sf_functional_tool_assembly_ids:
+ if not tool.sf_functional_tool_assembly_ids and re.match(r'^\d+$', str(tool.id)):
for i in range(tool.batch_replenishment_num):
- tool.create_functional_tool_assembly()
+ tool.sudo().create_functional_tool_assembly(tool)
print(i, ": ", tool.sf_functional_tool_assembly_ids)
else:
- tool.batch_replenishment_num = 0
+ tool.sudo().batch_replenishment_num = 0
-
- def create_functional_tool_assembly(self):
+ def create_functional_tool_assembly(self, tool):
"""
创建功能刀具组装单
"""
- functional_tool_assembly = self.env['sf.functional.tool.assembly'].sudo().create({
- 'functional_tool_name': self.name,
- 'functional_tool_type_id': self.sf_cutting_tool_type_id.id,
- 'functional_tool_diameter': self.diameter,
- 'knife_tip_r_angle': self.knife_tip_r_angle,
- 'coarse_middle_thin': self.coarse_middle_thin,
+ functional_tool_assembly = tool.env['sf.functional.tool.assembly'].sudo().create({
+ 'functional_tool_name': tool.name,
+ 'functional_tool_type_id': tool.sf_cutting_tool_type_id.id,
+ 'tool_groups_id': tool.tool_groups_id.id,
+ 'functional_tool_diameter': tool.diameter,
+ 'knife_tip_r_angle': tool.knife_tip_r_angle,
+ 'coarse_middle_thin': tool.coarse_middle_thin,
'loading_task_source': '2',
'use_tool_time': fields.Datetime.now() + timedelta(hours=4),
'applicant': '系统自动',
'apply_time': fields.Datetime.now(),
- 'whether_standard_knife': self.whether_standard_knife,
+ 'whether_standard_knife': tool.whether_standard_knife,
'reason_for_applying': '安全库存',
})
- self.sf_functional_tool_assembly_ids = [(4, functional_tool_assembly.id)]
+ tool.sudo().sf_functional_tool_assembly_ids = [(4, functional_tool_assembly.id)]
def estimate_functional_tool_assembly_ids(self, tool):
"""
@@ -354,34 +412,34 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
for sf_functional_tool_assembly_id in tool.sf_functional_tool_assembly_ids:
if sf_functional_tool_assembly_id.assemble_status == '0':
return False
- tool.sf_functional_tool_assembly_ids = []
+ tool.sudo().sf_functional_tool_assembly_ids = []
def get_stock_num(self, tool):
"""
计算刀具房数量、线边刀库数量、机内刀库数量
"""
if tool:
- tool.tool_stock_num = 0
- tool.side_shelf_num = 0
- tool.on_tool_stock_num = 0
+ tool.sudo().tool_stock_num = 0
+ tool.sudo().side_shelf_num = 0
+ tool.sudo().on_tool_stock_num = 0
if tool.sf_functional_cutting_tool_entity_ids:
for cutting_tool in tool.sf_functional_cutting_tool_entity_ids:
if cutting_tool.tool_room_num > 0:
- tool.tool_stock_num += 1
+ tool.sudo().tool_stock_num += 1
elif cutting_tool.line_edge_knife_library_num > 0:
- tool.side_shelf_num += 1
+ tool.sudo().side_shelf_num += 1
elif cutting_tool.machine_knife_library_num > 0:
- tool.on_tool_stock_num += 1
+ tool.sudo().on_tool_stock_num += 1
def create_or_edit_safety_stock(self, vals, sf_functional_cutting_tool_entity_ids):
"""
根据传入的信息新增或者更新功能刀具安全库存的信息
"""
- # 根据功能刀具名称、直径或尖刀R角、粗/中/精查询该功能刀具是否已经存在
+ # 根据功能刀具名称、刀具组、直径或尖刀R角、粗/中/精查询该功能刀具是否已经存在
record = self.env['sf.real.time.distribution.of.functional.tools'].search(
[('name', '=', vals['name']), ('sf_cutting_tool_type_id', '=', vals['sf_cutting_tool_type_id']),
('diameter', '=', vals['diameter']), ('knife_tip_r_angle', '=', vals['knife_tip_r_angle']),
- ('coarse_middle_thin', '=', vals['coarse_middle_thin'])])
+ ('coarse_middle_thin', '=', vals['coarse_middle_thin']), ('tool_groups_id', '=', vals['tool_groups_id'])])
if len(record) > 0:
for obj in record:
obj.write({'sf_functional_cutting_tool_entity_ids': [(4, sf_functional_cutting_tool_entity_ids.id)]})
@@ -389,6 +447,15 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
vals['sf_functional_cutting_tool_entity_ids'] = sf_functional_cutting_tool_entity_ids.ids
self.env['sf.real.time.distribution.of.functional.tools'].create(vals)
+ status_create = fields.Boolean('是否是新增状态', default=True)
+
+ @api.model_create_multi
+ def create(self, vals_list):
+ for vals in vals_list:
+ vals['status_create'] = False
+ records = super(RealTimeDistributionOfFunctionalTools, self).create(vals_list)
+ return records
+
class MachineTableToolChangingApply(models.Model):
_name = 'sf.machine.table.tool.changing.apply'
@@ -406,10 +473,13 @@ class MachineTableToolChangingApply(models.Model):
cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号', readonly=True,
required=True, domain="[('equipment_id', '=', maintenance_equipment_id)]")
# 功能刀具信息
+ code = fields.Char('编码', related='functional_tool_name_id.code')
+ tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id')
functional_tool_name = fields.Char(string='刀具名称', related='functional_tool_name_id.name', store=True)
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', store=True,
domain=[('product_id.name', '=', '功能刀具')],
related='functional_tool_name_id.barcode_id')
+ rfid = fields.Char('rfid', related='functional_tool_name_id.rfid')
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', domain=[('assemble_status', '=', '1')],
string='功能刀具名称')
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
@@ -436,7 +506,7 @@ class MachineTableToolChangingApply(models.Model):
reason_for_applying = fields.Char(string='申请原因', readonly=True)
remark = fields.Char(string='备注说明', readonly=False)
- status = fields.Selection([('0', '未操作'), ('1', '已换刀申请'), ('2', '已转移'), ('3', '已组装')],
+ status = fields.Selection([('0', '未操作'), ('1', '已申请换刀'), ('2', '已转移'), ('3', '已组装')],
string='操作状态', default='0')
sf_functional_tool_assembly_id = fields.Many2one('sf.functional.tool.assembly', '功能刀具组装单', readonly=True)
@@ -445,21 +515,21 @@ class MachineTableToolChangingApply(models.Model):
def _compute_functional_tool_status(self):
for record in self:
if record.alarm_value < record.used_value:
- record.functional_tool_status = '报警'
+ record.sudo().functional_tool_status = '报警'
else:
- record.functional_tool_status = '正常'
+ record.sudo().functional_tool_status = '正常'
@api.depends('maintenance_equipment_id')
def _compute_machine_table_type_id(self):
for record in self:
if record:
- record.production_line_id = record.maintenance_equipment_id.production_line_id.id
- record.machine_table_type_id = record.maintenance_equipment_id.category_id.id
- record.machine_tool_code = record.maintenance_equipment_id.code
+ record.sudo().production_line_id = record.maintenance_equipment_id.production_line_id.id
+ record.sudo().machine_table_type_id = record.maintenance_equipment_id.category_id.id
+ record.sudo().machine_tool_code = record.maintenance_equipment_id.code
else:
- record.production_line_id = None
- record.machine_table_type_id = None
- record.machine_tool_code = None
+ record.sudo().production_line_id = None
+ record.sudo().machine_table_type_id = None
+ record.sudo().machine_tool_code = None
@api.constrains("cutter_spacing_code_id")
def _check_cutter_spacing_code_id(self):
@@ -559,16 +629,16 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
_name = 'sf.cam.work.order.program.knife.plan'
_description = 'CAM工单程序用刀计划'
- name = fields.Char(string='工单任务编号', readonly=False)
- cam_procedure_code = fields.Char(string='CAM程序编号', readonly=False)
- cam_cutter_spacing_code = fields.Char(string='CAM刀位号', readonly=False)
+ name = fields.Char('工单任务编号')
+ cam_procedure_code = fields.Char('程序名')
+ filename = fields.Char('文件')
+ cam_cutter_spacing_code = fields.Char('刀号')
tool_position_interface_type = fields.Selection(
[('BT刀柄式', 'BT刀柄式'), ('SK刀柄式', 'SK刀柄式'), ('HSK刀柄式', 'HSK刀柄式'),
('CAT刀柄式', 'CAT刀柄式'), ('ISO刀盘式', 'ISO刀盘式'), ('DIN刀盘式', 'DIN刀盘式'),
('直装固定式', '直装固定式')], string='刀位接口型号')
- production_line_id = fields.Many2one('sf.production.line', string='生产线', readonly=False,
- group_expand='_read_group_names')
- machine_table_name_id = fields.Many2one('maintenance.equipment', string='机床名称', readonly=False,
+ production_line_id = fields.Many2one('sf.production.line', string='生产线', group_expand='_read_group_names')
+ machine_table_name_id = fields.Many2one('maintenance.equipment', string='机床名称',
domain="[('production_line_id', '=', production_line_id)]")
machine_table_name = fields.Char(string='机台号', readonly=True, related='machine_table_name_id.name')
cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号', required=True,
@@ -581,11 +651,12 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号',
domain=[('product_id.name', '=', '功能刀具')])
- functional_tool_name = fields.Char(string='功能刀具名称', required=True)
+ functional_tool_name = fields.Char(string='功能刀具名称', compute='_compute_functional_tool_name')
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=False)
+ tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组')
diameter = fields.Integer(string='刀具直径(mm)', readonly=False)
tool_included_angle = fields.Float(string='刀尖R角(mm)', readonly=False)
- tool_loading_length = fields.Float(strin='总长度(mm)', readonly=False)
+ tool_loading_length = fields.Float(string='总长度(mm)', readonly=False)
extension_length = fields.Float(string='伸出长(mm)')
effective_length = fields.Float(string='有效长(mm)')
new_former = fields.Selection([('0', '新'), ('1', '旧')], string='新/旧', readonly=False, default='0')
@@ -594,12 +665,28 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
L_D = fields.Float(string='L/D值', readonly=False)
clearance_length = fields.Float(string='避空长(mm)', readonly=False)
required_cutting_time = fields.Integer(string='需切削时长', readonly=False)
+ process_type = fields.Char('加工类型')
+ margin_x_y = fields.Float('余量_X/Y')
+ margin_z = fields.Float('余量_Z')
+ finish_depth = fields.Float('加工深度')
+ shank_model = fields.Char('刀柄型号')
+ estimated_processing_time = fields.Char('预计加工时间')
plan_execute_status = fields.Selection([('0', '待下发'), ('1', '执行中'), ('2', '已完成')],
string='计划执行状态', default='0', readonly=False)
sf_functional_tool_assembly_id = fields.Many2one('sf.functional.tool.assembly', '功能刀具组装', readonly=True)
+ @api.depends('diameter', 'tool_included_angle', 'tool_groups_id')
+ def _compute_functional_tool_name(self):
+ for obj in self:
+ if obj.tool_groups_id:
+ obj.functional_tool_name = '%s-D%sR%s' % (
+ obj.tool_groups_id.name, obj.diameter,
+ obj.tool_included_angle)
+ else:
+ obj.functional_tool_name = None
+
@api.model
def _read_group_names(self, categories, domain, order):
names = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
@@ -611,27 +698,34 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
:return:
"""
record = self.env['sf.functional.tool.assembly'].create({
- 'barcode_id': self.barcode_id.id,
- 'functional_tool_name_id': self.functional_tool_name_id.id,
+ 'functional_tool_name': self.functional_tool_name,
'functional_tool_type_id': self.functional_tool_type_id.id,
+ 'tool_groups_id': self.tool_groups_id.id,
'functional_tool_diameter': self.diameter,
- 'functional_tool_length': self.tool_loading_length,
- 'loading_task_source': '0',
- 'coarse_middle_thin': None,
- 'tool_loading_length': None,
- 'applicant': self.env.user.name,
- 'reason_for_applying': self.reason_for_applying,
- 'use_tool_time': self.need_knife_time,
+ 'knife_tip_r_angle': self.tool_included_angle,
+ 'tool_loading_length': self.tool_loading_length,
+ 'functional_tool_length': self.extension_length,
+ 'effective_length': self.effective_length,
+ 'whether_standard_knife': self.whether_standard_knife,
+ 'coarse_middle_thin': self.coarse_middle_thin,
+ 'new_former': self.new_former,
+ 'production_line_name_id': self.production_line_id.id,
'machine_tool_name_id': self.machine_table_name_id.id,
- 'machine_tool_code': self.cam_procedure_code,
- 'cutter_spacing_code': self.cam_cutter_spacing_code,
+ 'cutter_spacing_code_id': self.env['maintenance.equipment.tool'].sudo().search(
+ [('code', '=', self.cam_cutter_spacing_code), ('equipment_id', '=', self.machine_table_name_id.id)]).id,
+
+ 'loading_task_source': '0',
+ 'applicant': self.env.user.name,
+ 'use_tool_time': self.need_knife_time,
+ 'reason_for_applying': '工单用刀',
+
'sf_cam_work_order_program_knife_plan_id': self.id
})
self.sf_functional_tool_assembly_id = record.id
# 将计划执行状态改为执行中
self.env['sf.cam.work.order.program.knife.plan'].search(
- [('barcode_id', '=', self.barcode_id.id)]).write(
+ [('name', '=', self.name), ('functional_tool_name', '=', self.functional_tool_name)]).write(
{'plan_execute_status': '1',
'applicant': self.env.user.name})
@@ -641,16 +735,50 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
:return:
"""
self.env['sf.functional.tool.assembly'].search(
- [('barcode_id', '=', self.barcode_id.id),
+ [('assembly_order_code', '=', self.sf_functional_tool_assembly_id.assembly_order_code),
('loading_task_source', '=', '0')]).unlink()
# 将计划执行状态改为待执行,同时清除申请人、功能刀具组装字段数据
self.env['sf.cam.work.order.program.knife.plan'].search(
- [('barcode_id', '=', self.barcode_id.id)]).write(
+ [('name', '=', self.name), ('functional_tool_name', '=', self.functional_tool_name)]).write(
{'plan_execute_status': '0',
'applicant': None,
'sf_functional_tool_assembly_id': None})
+ def create_cam_work_plan(self, cnc_processing):
+ """
+ 根据传入的工单信息,查询是否有需要的功能刀具,如果没有则生成CAM工单程序用刀计划
+ """
+ status = False
+ if cnc_processing.functional_tool_type_id and cnc_processing.cutting_tool_name:
+ functional_tools = self.env['sf.real.time.distribution.of.functional.tools'].sudo().search(
+ [('sf_cutting_tool_type_id', '=', cnc_processing.functional_tool_type_id.id),
+ ('name', '=', cnc_processing.cutting_tool_name)])
+ if functional_tools:
+ for functional_tool in functional_tools:
+ if functional_tool.on_tool_stock_num == 0:
+ # self.env['sf.cnc.processing'].register_cnc_processing(cnc_processing)
+ if functional_tool.tool_stock_num == 0 and functional_tool.side_shelf_num == 0:
+ status = True
+ else:
+ status = True
+ if status:
+ self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
+ 'name': cnc_processing.workorder_id.production_id.name,
+ 'cam_procedure_code': cnc_processing.program_name,
+ 'filename': cnc_processing.cnc_id.name,
+ 'functional_tool_type_id': cnc_processing.functional_tool_type_id.id,
+ 'functional_tool_name': cnc_processing.cutting_tool_name,
+ 'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
+ 'process_type': cnc_processing.processing_type,
+ 'margin_x_y': float(cnc_processing.margin_x_y),
+ 'margin_z': float(cnc_processing.margin_z),
+ 'finish_depth': float(cnc_processing.depth_of_processing_z),
+ 'extension_length': float(cnc_processing.cutting_tool_extension_length),
+ 'shank_model': cnc_processing.cutting_tool_handle_type,
+ 'estimated_processing_time': cnc_processing.estimated_processing_time,
+ })
+
class FunctionalToolAssembly(models.Model):
_name = 'sf.functional.tool.assembly'
@@ -662,8 +790,11 @@ class FunctionalToolAssembly(models.Model):
for obj in self:
obj.name = obj.after_assembly_functional_tool_name
+ code = fields.Char('功能刀具编码', readonly=True)
+ rfid = fields.Char('rfid', readonly=True)
+ tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=True)
name = fields.Char(string='名称', readonly=True, compute='_compute_name')
- assembly_order_code = fields.Char(string='编码', readonly=True)
+ assembly_order_code = fields.Char(string='组装单编码', readonly=True)
functional_tool_name_id = fields.Many2one('product.product', string='功能刀具', readonly=True)
functional_tool_name = fields.Char(string='功能刀具名称', readonly=True)
@@ -673,7 +804,7 @@ class FunctionalToolAssembly(models.Model):
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=True)
coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], string='粗/中/精', readonly=True)
new_former = fields.Selection([('0', '新'), ('1', '旧')], string='新/旧', readonly=True)
- tool_loading_length = fields.Float(strin='总长度(mm)', readonly=True)
+ tool_loading_length = fields.Float(string='总长度(mm)', readonly=True)
functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True)
effective_length = fields.Float(string='有效长(mm)', readonly=True)
loading_task_source = fields.Selection([('0', 'CAM装刀'), ('1', '机台换刀'), ('2', '按库存组装')],
@@ -776,7 +907,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)
@@ -825,18 +956,6 @@ class FunctionalToolAssembly(models.Model):
return functional_tool
return False
- def automated_assembly(self):
- """
- todo 自动组装
- :return:
- """
-
- def automatic_printing_of_QR_code(self):
- """
- todo 自动打印二维码
- :return:
- """
-
def assemble_single_print(self):
"""
todo 组装单打印
diff --git a/sf_tool_management/models/maintenance_equipment.py b/sf_tool_management/models/maintenance_equipment.py
index f5371a3f..4b5fe89e 100644
--- a/sf_tool_management/models/maintenance_equipment.py
+++ b/sf_tool_management/models/maintenance_equipment.py
@@ -1,9 +1,23 @@
-from odoo import models, api
+from odoo import models, api, fields
+from odoo.exceptions import ValidationError
class SfMaintenanceEquipmentTool(models.Model):
_inherit = 'maintenance.equipment.tool'
+ functional_tool_name_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具名称')
+
+ image = fields.Binary('图片', related='functional_tool_name_id.image')
+ tool_code = fields.Char('功能刀具编码', related='functional_tool_name_id.code')
+ functional_tool_type = fields.Char('功能刀具类型', related='functional_tool_name_id.sf_cutting_tool_type_id.name')
+ tool_groups = fields.Char('刀具组', related='functional_tool_name_id.tool_groups_id.name')
+ diameter = fields.Integer('直径(mm)', related='functional_tool_name_id.functional_tool_diameter')
+ knife_tip_r_angle = fields.Float('刀尖R角(mm)', related='functional_tool_name_id.knife_tip_r_angle')
+ life_value_max = fields.Integer('最大寿命值(min)', related='functional_tool_name_id.max_lifetime_value')
+ alarm_value = fields.Integer('报警值(min)', related='functional_tool_name_id.alarm_value')
+ used_value = fields.Integer('已使用值(min)', related='functional_tool_name_id.used_value')
+ tool_install_time = fields.Datetime('机内装刀时间')
+
@api.model_create_multi
def create(self, vals_list):
tools = super().create(vals_list)
@@ -13,3 +27,68 @@ class SfMaintenanceEquipmentTool(models.Model):
'cutter_spacing_code_id': tool.id
})
return tools
+
+
+class StockLot(models.Model):
+ _inherit = 'stock.lot'
+
+ tool_material_search_id = fields.Many2one('sf.tool.material.search', string='刀具物料搜索')
+ tool_material_status = fields.Selection([('可用', '可用'), ('在用', '在用'), ('报废', '报废')], string='状态',
+ compute='_compute_tool_material_status')
+
+ @api.depends('quant_ids')
+ def _compute_tool_material_status(self):
+ for record in self:
+ if record:
+ if record.quant_ids[-1].location_id.name == '刀具组装位置':
+ record.tool_material_status = '在用'
+ else:
+ record.tool_material_status = '可用'
+
+ @api.model
+ def name_search(self, name='', args=None, operator='ilike', limit=100):
+ # 调用父类的name_search方法
+ records = super(StockLot, self).name_search(name=name, args=args, operator=operator, limit=limit)
+ if records:
+ return records
+ else:
+ # 在调用父类方法之后执行自定义逻辑
+ self.tool_verify(args, name)
+ return records
+
+ def tool_verify(self, args, name):
+ # 刀具物料验证
+ if 5 >= len(args) > 3:
+ objs = self.search([('name', '=', name), ('quant_ids.location_id.name', 'in', ['刀具房']),
+ ('quant_ids.quantity', '>', 0)])
+ if args[2][2] in ['整体式刀具', '刀片', '刀杆', '刀盘', '刀柄', '夹头']:
+ if objs.product_id.categ_id.name == '刀具':
+ raise ValidationError('这是【%s】物料,请扫入正确的【%s】物料!!!' % (
+ objs.product_id.cutting_tool_material_id.name, args[2][2]))
+
+ @api.model_create_multi
+ def create(self, vals_list):
+ records = super(StockLot, self).create(vals_list)
+ for record in records:
+ if record.product_id.categ_id.name == '刀具':
+ tool_material_search = self.env['sf.tool.material.search'].sudo().search(
+ [('cutting_tool_material_id', '=', record.product_id.cutting_tool_material_id.id),
+ ('cutting_tool_standard_library_id', '=', record.product_id.cutting_tool_model_id.id),
+ ('specification_id', '=', record.product_id.specification_id.id)])
+ if tool_material_search:
+ record.tool_material_search_id = tool_material_search
+ return records
+
+
+class ProductProduct(models.Model):
+ _inherit = 'product.product'
+
+ @api.model_create_multi
+ def create(self, vals_list):
+ records = super(ProductProduct, self).create(vals_list)
+ for record in records:
+ if record.categ_id.name == '刀具':
+ self.env['sf.tool.material.search'].sudo().create({
+ 'product_id': record.id
+ })
+ return records
diff --git a/sf_tool_management/models/mrp_workorder.py b/sf_tool_management/models/mrp_workorder.py
new file mode 100644
index 00000000..90fe9393
--- /dev/null
+++ b/sf_tool_management/models/mrp_workorder.py
@@ -0,0 +1,47 @@
+import json
+import requests
+from odoo import fields, models, api
+from odoo.exceptions import ValidationError
+from odoo.addons.sf_base.commons.common import Common
+
+
+class CNCprocessing(models.Model):
+ _inherit = 'sf.cnc.processing'
+ _description = 'CNC加工用刀检测'
+
+ # ==========MES装刀指令接口==========
+ def register_cnc_processing(self, cnc_processing):
+ create_url = '/AutoDeviceApi/MESToolLoadingInstruction'
+ sf_sync_config = self.env['res.config.settings'].get_values()
+ token = sf_sync_config['token']
+ sf_secret_key = sf_sync_config['sf_secret_key']
+ headers = Common.get_headers(self, token, sf_secret_key)
+ strurl = sf_sync_config['sf_url'] + create_url
+ val = {
+ 'DeviceId': cnc_processing.workorder_id.machine_tool_name,
+ 'RfidCode': None,
+ 'ToolId': cnc_processing.cutting_tool_no
+ }
+ kw = json.dumps(val, ensure_ascii=False)
+ r = requests.post(strurl, json={}, data={'kw': kw, 'token': token}, headers=headers)
+ ret = r.json()
+ if r == 200:
+ return "MES装刀指令发送成功"
+ else:
+ raise ValidationError("MES装刀指令发送失败")
+
+ @api.model_create_multi
+ def create(self, vals):
+ obj = super(CNCprocessing, self).create(vals)
+ # 调用CAM工单程序用刀计划创建方法
+ self.env['sf.cam.work.order.program.knife.plan'].create_cam_work_plan(obj)
+ return obj
+
+
+class MrpWorkCenter(models.Model):
+ _inherit = 'mrp.workcenter'
+
+ def action_tool_order(self):
+ action = self.env.ref('sf_tool_management.sf_functional_tool_assembly_view_act')
+ result = action.read()[0]
+ return result
diff --git a/sf_tool_management/models/tool_material_search.py b/sf_tool_management/models/tool_material_search.py
index 1dc48322..a5498c80 100644
--- a/sf_tool_management/models/tool_material_search.py
+++ b/sf_tool_management/models/tool_material_search.py
@@ -5,7 +5,7 @@ from odoo import fields, models, api, SUPERUSER_ID
# from odoo.exceptions import ValidationError
-# 刀具物料搜索
+# 刀具物料搜索(待删除)
class SfToolMaterialSearch(models.Model):
_name = 'sf.tool.material.search'
_description = '刀具物料搜索'
@@ -108,8 +108,8 @@ class SfToolMaterialSearch(models.Model):
'rel_cutting_product_template_material_search', '走刀方向',
domain=[('type', '=', '走刀方向')])
suitable_coolant_ids = fields.Many2many('maintenance.equipment.image',
- 'rel_coolant_product_template_material_search', '适合冷却液',
- domain=[('type', '=', '冷却液')])
+ 'rel_coolants_product_template_material_search', '适合冷却方式',
+ domain=[('type', '=', '冷却方式')])
cutting_speed_ids = fields.Many2many('sf.cutting.speed', string='切削速度Vc')
feed_per_tooth_ids = fields.Many2many('sf.feed.per.tooth', 'rel_feed_per_tooth_ids', '每齿走刀量fz')
@@ -302,3 +302,55 @@ class SfToolMaterialSearch(models.Model):
warehouse_area = fields.Char('库区')
warehouse_location = fields.Char('库位')
three_d_model = fields.Many2one('ir.attachment', '3D模型')
+
+
+class ToolMaterial(models.Model):
+ _name = 'sf.tool.material.search'
+ _description = '刀具物料搜索'
+
+ product_id = fields.Many2one('product.product', string='刀具物料产品')
+
+ name = fields.Char('名称', related='product_id.name')
+ cutting_tool_material_id = fields.Many2one('sf.cutting.tool.material', '刀具物料',
+ related='product_id.cutting_tool_material_id',
+ store=True,
+ group_expand='_read_group_cutting_tool_material_id')
+ tool_material_name = fields.Char('物料名称', related='product_id.cutting_tool_material_id.name')
+ cutting_tool_standard_library_id = fields.Many2one('sf.cutting_tool.standard.library', '刀具型号',
+ related='product_id.cutting_tool_model_id')
+ specification_id = fields.Many2one('sf.tool.materials.basic.parameters', '规格',
+ related='product_id.specification_id')
+ image = fields.Binary('图片', related='product_id.image_1920')
+ number = fields.Integer('总数量', readonly=True, compute='_compute_number')
+ usable_num = fields.Integer('可用数量', readonly=True)
+ have_been_used_num = fields.Integer('在用数量', readonly=True)
+ scrap_num = fields.Integer('报废数量', readonly=True)
+
+ barcode_ids = fields.One2many('stock.lot', 'tool_material_search_id', string='序列号', readonly=True)
+
+ @api.depends('barcode_ids')
+ def _compute_number(self):
+ usable_num = 0
+ have_been_used_num = 0
+ scrap_num = 0
+ for record in self:
+ if record.barcode_ids:
+ record.number = len(record.barcode_ids)
+ for barcode_id in record.barcode_ids:
+ if barcode_id.quant_ids[-1].location_id.name == '刀具组装位置':
+ have_been_used_num = have_been_used_num + 1
+ else:
+ usable_num = usable_num + 1
+ record.usable_num = usable_num
+ record.have_been_used_num = have_been_used_num
+ record.scrap_num = scrap_num
+ else:
+ record.number = 0
+ record.usable_num = 0
+ record.have_been_used_num = 0
+ record.scrap_num = 0
+
+ @api.model
+ def _read_group_cutting_tool_material_id(self, categories, domain, order):
+ cutting_tool_material_id = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
+ return categories.browse(cutting_tool_material_id)
diff --git a/sf_tool_management/security/ir.model.access.csv b/sf_tool_management/security/ir.model.access.csv
index cc72f699..91eebb6f 100644
--- a/sf_tool_management/security/ir.model.access.csv
+++ b/sf_tool_management/security/ir.model.access.csv
@@ -1,20 +1,34 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_sf_functional_cutting_tool_entity,sf.functional.cutting.tool.entity,model_sf_functional_cutting_tool_entity,base.group_user,1,1,1,1
-access_sf_functional_tool_warning,sf.functional.tool.warning,model_sf_functional_tool_warning,base.group_user,1,1,1,1
-access_sf_real_time_distribution_of_functional_tools,sf.real.time.distribution.of.functional.tools,model_sf_real_time_distribution_of_functional_tools,base.group_user,1,1,1,1
+access_sf_functional_cutting_tool_entity,sf.functional.cutting.tool.entity,model_sf_functional_cutting_tool_entity,sf_base.group_sf_tool_user,1,1,1,0
+access_sf_functional_tool_warning,sf.functional.tool.warning,model_sf_functional_tool_warning,sf_base.group_sf_tool_user,1,1,1,0
+access_sf_real_time_distribution_of_functional_tools,sf.real.time.distribution.of.functional.tools,model_sf_real_time_distribution_of_functional_tools,sf_base.group_sf_tool_user,1,1,1,0
-access_sf_cam_work_order_program_knife_plan,sf.cam.work.order.program.knife.plan,model_sf_cam_work_order_program_knife_plan,base.group_user,1,1,1,1
-access_sf_machine_table_tool_changing_apply,sf.machine.table.tool.changing.apply,model_sf_machine_table_tool_changing_apply,base.group_user,1,1,1,1
+access_sf_cam_work_order_program_knife_plan,sf.cam.work.order.program.knife.plan,model_sf_cam_work_order_program_knife_plan,sf_base.group_sf_tool_user,1,1,1,0
+access_sf_machine_table_tool_changing_apply,sf.machine.table.tool.changing.apply,model_sf_machine_table_tool_changing_apply,sf_base.group_sf_tool_user,1,1,1,0
-access_sf_tool_change_requirement_information,sf.tool.change.requirement.information,model_sf_tool_change_requirement_information,base.group_user,1,1,1,1
-access_sf_tool_transfer_request_information,sf.tool.transfer.request.information,model_sf_tool_transfer_request_information,base.group_user,1,1,1,1
-
-access_sf_functional_tool_assembly,sf.functional.tool.assembly,model_sf_functional_tool_assembly,base.group_user,1,1,1,1
-access_sf_functional_tool_assembly_order,sf.functional.tool.assembly.order,model_sf_functional_tool_assembly_order,base.group_user,1,1,1,1
-access_sf_tool_material_search,sf.tool.material.search,model_sf_tool_material_search,base.group_user,1,1,1,1
-
+access_sf_tool_change_requirement_information,sf.tool.change.requirement.information,model_sf_tool_change_requirement_information,sf_base.group_sf_tool_user,1,1,1,0
+access_sf_tool_transfer_request_information,sf.tool.transfer.request.information,model_sf_tool_transfer_request_information,sf_base.group_sf_tool_user,1,1,1,0
+access_sf_functional_tool_assembly,sf.functional.tool.assembly,model_sf_functional_tool_assembly,sf_base.group_sf_tool_user,1,1,1,0
+access_sf_functional_tool_assembly_order,sf.functional.tool.assembly.order,model_sf_functional_tool_assembly_order,sf_base.group_sf_tool_user,1,1,1,0
+access_sf_tool_material_search,sf.tool.material.search,model_sf_tool_material_search,sf_base.group_sf_tool_user,1,1,1,0
+
+
+access_sf_functional_cutting_tool_entity_group_plan_dispatch,sf.functional.cutting.tool.entity,model_sf_functional_cutting_tool_entity,sf_base.group_plan_dispatch,1,0,0,0
+access_sf_functional_tool_warning_group_plan_dispatch,sf.functional.tool.warning,model_sf_functional_tool_warning,sf_base.group_plan_dispatch,1,0,0,0
+access_sf_real_time_distribution_of_functional_tools_group_plan_dispatch,sf.real.time.distribution.of.functional.tools,model_sf_real_time_distribution_of_functional_tools,sf_base.group_plan_dispatch,1,0,0,0
+
+access_sf_cam_work_order_program_knife_plan_group_plan_dispatch,sf.cam.work.order.program.knife.plan,model_sf_cam_work_order_program_knife_plan,sf_base.group_plan_dispatch,1,0,0,0
+access_sf_machine_table_tool_changing_apply_group_plan_dispatch,sf.machine.table.tool.changing.apply,model_sf_machine_table_tool_changing_apply,sf_base.group_plan_dispatch,1,0,0,0
+
+
+access_sf_tool_change_requirement_information_group_plan_dispatch,sf.tool.change.requirement.information,model_sf_tool_change_requirement_information,sf_base.group_plan_dispatch,1,0,0,0
+access_sf_tool_transfer_request_information_group_plan_dispatch,sf.tool.transfer.request.information,model_sf_tool_transfer_request_information,sf_base.group_plan_dispatch,1,0,0,0
+
+access_sf_functional_tool_assembly_group_plan_dispatch,sf.functional.tool.assembly,model_sf_functional_tool_assembly,sf_base.group_plan_dispatch,1,0,0,0
+access_sf_functional_tool_assembly_order_group_plan_dispatch,sf.functional.tool.assembly.order,model_sf_functional_tool_assembly_order,sf_base.group_plan_dispatch,1,0,0,0
+access_sf_tool_material_search_group_plan_dispatch,sf.tool.material.search,model_sf_tool_material_search,sf_base.group_plan_dispatch,1,0,0,0
diff --git a/sf_tool_management/static/src/change.scss b/sf_tool_management/static/src/change.scss
index 40fdcc8e..4c857c8c 100644
--- a/sf_tool_management/static/src/change.scss
+++ b/sf_tool_management/static/src/change.scss
@@ -8,4 +8,10 @@
.modal-content .o_list_button {
-}
\ No newline at end of file
+}
+
+.o_form_view .o_field_widget .o_list_renderer {
+ width: 100%!important;
+ margin:0 auto;
+ overflow: auto;
+}
diff --git a/sf_tool_management/views/mrp_workcenter_views.xml b/sf_tool_management/views/mrp_workcenter_views.xml
new file mode 100644
index 00000000..dcc52f7b
--- /dev/null
+++ b/sf_tool_management/views/mrp_workcenter_views.xml
@@ -0,0 +1,33 @@
+
+
+
+ mrp.workcenter.kanban.tool
+ mrp.workcenter
+
+
+
+
+
+
+
+
+
+
+ 安排订单
+
+
+
+
+
+
+ 工单
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sf_tool_management/views/sf_maintenance_equipment.xml b/sf_tool_management/views/sf_maintenance_equipment.xml
new file mode 100644
index 00000000..fd863a84
--- /dev/null
+++ b/sf_tool_management/views/sf_maintenance_equipment.xml
@@ -0,0 +1,32 @@
+
+
+
+
+ sf_manufacturing_equipment.form
+ maintenance.equipment
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 01779a2d..2d5cdf63 100644
--- a/sf_tool_management/views/tool_base_views.xml
+++ b/sf_tool_management/views/tool_base_views.xml
@@ -7,9 +7,11 @@
sf.functional.cutting.tool.entity
-
+
+
+
@@ -42,7 +44,7 @@
-
@@ -52,7 +54,7 @@
-
@@ -62,7 +64,7 @@
-
@@ -75,14 +77,17 @@
-
+
+
+
+
+ domain="[('id','=',blade_tip_characteristics_id)]"/>
+ domain="[('id','=',handle_type_id)]"/>
@@ -130,7 +135,7 @@
-
+
@@ -175,6 +180,7 @@
+
@@ -221,7 +227,8 @@
-
+
+
@@ -247,6 +254,7 @@
+
@@ -284,9 +292,10 @@
功能刀具安全库存
sf.real.time.distribution.of.functional.tools
-
+
+
@@ -306,26 +315,35 @@
功能刀具安全库存
sf.real.time.distribution.of.functional.tools
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -124,10 +219,12 @@
shelf.location.search
sf.shelf.location
-
+
-
+
+
+
@@ -135,11 +232,11 @@
- 货架货位
+ 货位看板
ir.actions.act_window
sf.shelf.location
kanban,form
- [('location_type', '=', '货位'),('check_state','=','enable')]
+
@@ -161,7 +258,7 @@
groups="sf_warehouse.group_sf_stock_user"/>
- 货架货位
+ 货位
ir.actions.act_window
sf.shelf.location
tree,form
@@ -184,8 +281,8 @@
-
diff --git a/sf_warehouse/views/view.xml b/sf_warehouse/views/view.xml
index e4a2ea85..39d5a8c0 100644
--- a/sf_warehouse/views/view.xml
+++ b/sf_warehouse/views/view.xml
@@ -175,17 +175,17 @@
-
- stock.location.tree.sf.inherit
- stock.location
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -206,17 +206,17 @@
-
- stock.warehouse.tree.sf.inherit
- stock.warehouse
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -238,17 +238,17 @@
-
- stock.route.tree.sf.inherit
- stock.route
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -269,17 +269,17 @@
-
- stock.rule.tree.sf.inherit
- stock.rule
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -300,198 +300,198 @@
-
- stock.picking.type.tree.sf.inherit
- stock.picking.type
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
- product.category.form.sf.inherit
- product.category
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
- product.category.tree.sf.inherit
- product.category
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
- uom.category.form.sf.inherit
- uom.category
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
- uom.category.tree.sf.inherit
- uom.category
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
- barcode.nomenclature.form.sf.inherit
- barcode.nomenclature
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
- barcode.nomenclature.tree.sf.inherit
- barcode.nomenclature
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
- stock.putaway.rule.tree.sf.inherit
- stock.putaway.rule
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- stock.warehouse.orderpoint.tree.sf.inherit
- stock.warehouse.orderpoint
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- stock.quant.tree.sf.inherit
- stock.quant
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- stock.scrap.form.sf.inherit
- stock.scrap
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
- stock.scrap.tree.sf.inherit
- stock.scrap
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spiffy_theme_backend/.idea/spiffy_theme_backend.iml b/spiffy_theme_backend/.idea/spiffy_theme_backend.iml
deleted file mode 100644
index d0876a78..00000000
--- a/spiffy_theme_backend/.idea/spiffy_theme_backend.iml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/stock_barcode/models/stock_move_line.py b/stock_barcode/models/stock_move_line.py
index 8c369685..bfbcd221 100644
--- a/stock_barcode/models/stock_move_line.py
+++ b/stock_barcode/models/stock_move_line.py
@@ -13,20 +13,23 @@ class StockMoveLine(models.Model):
picking_location_dest_id = fields.Many2one(related='picking_id.location_dest_id')
product_stock_quant_ids = fields.One2many('stock.quant', compute='_compute_product_stock_quant_ids')
product_packaging_id = fields.Many2one(related='move_id.product_packaging_id')
- product_packaging_uom_qty = fields.Float('Packaging Quantity', compute='_compute_product_packaging_uom_qty', help="Quantity of the Packaging in the UoM of the Stock Move Line.")
+ product_packaging_uom_qty = fields.Float('Packaging Quantity', compute='_compute_product_packaging_uom_qty',
+ help="Quantity of the Packaging in the UoM of the Stock Move Line.")
is_completed = fields.Boolean(compute='_compute_is_completed', help="Check if the quantity done matches the demand")
@api.depends('product_id', 'product_id.stock_quant_ids')
def _compute_product_stock_quant_ids(self):
for line in self:
- line.product_stock_quant_ids = line.product_id.stock_quant_ids.filtered(lambda q: q.company_id in self.env.companies and q.location_id.usage == 'internal')
+ line.product_stock_quant_ids = line.product_id.stock_quant_ids.filtered(
+ lambda q: q.company_id in self.env.companies and q.location_id.usage == 'internal')
def _compute_dummy_id(self):
self.dummy_id = ''
def _compute_product_packaging_uom_qty(self):
for sml in self:
- sml.product_packaging_uom_qty = sml.product_packaging_id.product_uom_id._compute_quantity(sml.product_packaging_id.qty, sml.product_uom_id)
+ sml.product_packaging_uom_qty = sml.product_packaging_id.product_uom_id._compute_quantity(
+ sml.product_packaging_id.qty, sml.product_uom_id)
@api.depends('qty_done')
def _compute_is_completed(self):
diff --git a/stock_barcode/views/stock_move_line_views.xml b/stock_barcode/views/stock_move_line_views.xml
index b311abb6..581bdb38 100644
--- a/stock_barcode/views/stock_move_line_views.xml
+++ b/stock_barcode/views/stock_move_line_views.xml
@@ -1,201 +1,236 @@
+
+ stock.move.line.operations.tree.inherit
+ stock.move.line
+
+
+
+
+
+
+
+
+
+
-
- stock.product.selector
- stock.move.line
- 1000
-
-
-
-
-
-
-
-
-
-
+
+ stock.product.selector
+ stock.move.line
+ 1000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ Delete
+
+
-
-
- Delete
-
-
-
-
-
-
+
+
+
-
- stock.barcode.quant.kanban
- stock.quant
- 1000
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ stock.barcode.quant.kanban
+ stock.quant
+ 1000
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
-
- stock.quant.kanban.barcode
- stock.quant
- 1000
-
-
-
-
-
-
-
+
+ stock.quant.kanban.barcode
+ stock.quant
+ 1000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
- stock_barcode.quant.tree.inherit
- stock.quant
-
- primary
-
-
- UoM
- show
-
-
- hide
-
-
- hide
-
-
-
+
+ stock_barcode.quant.tree.inherit
+ stock.quant
+
+ primary
+
+
+ UoM
+ show
+
+
+ hide
+
+
+ hide
+
+
+
diff --git a/stock_barcode/views/stock_picking_views.xml b/stock_barcode/views/stock_picking_views.xml
index d61de200..d516844c 100644
--- a/stock_barcode/views/stock_picking_views.xml
+++ b/stock_barcode/views/stock_picking_views.xml
@@ -1,181 +1,174 @@
-
-
- stock.move.line.operations.tree.inherit
- stock.move.line
-
-
-
-
-
-
-
- {'barcode_events': True}
- field_float_scannable
-
-
-
+
+
+
+ stock.move.line.kanban.inherited
+ stock.move.line
+
+
+
+
+
+
+
+
+
+
-
- stock.move.line.kanban.inherited
- stock.move.line
-
-
-
-
-
-
-
-
-
-
-
-
- stock.picking.form.view.barcode
- stock.picking
- 1000
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ stock.picking.form.view.barcode
+ stock.picking
+ 1000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- Open picking form
- stock.picking
- form
- {
- 'res_id': active_id,
- }
-
-
+
+ Open picking form
+ stock.picking
+ form
+ {
+ 'res_id': active_id,
+ }
+
+
-
- stock.picking.view.kanban.barcode
- stock.picking
-
-
+
+ stock.picking.view.kanban.barcode
+ stock.picking
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
- Operation Types
- stock.picking.type
-
-
-
-
-
-
-
+
+ Operation Types
+ stock.picking.type
+
+
+
+
+
+
+
-
- Operation Types
- stock.picking.type
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ Operation Types
+ stock.picking.type
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+