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

# Conflicts:
#	sf_manufacturing/models/mrp_production.py
#	sf_manufacturing/views/mrp_workorder_view.xml
This commit is contained in:
mgw
2024-04-23 10:56:57 +08:00
39 changed files with 713 additions and 260 deletions

View File

@@ -131,6 +131,22 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
dom.addClass('addRequired') dom.addClass('addRequired')
} }
}) })
try {
const dom = this.tableRef.el
if(dom ) {
const tfoot = $(dom).children('tfoot')
const tbooy = $(dom).children('tbody')
if(tfoot.length) {
const tfoot_tr = tfoot.children().eq(0)
const tbody_tr = tbooy.children().eq(0)
if(tfoot_tr.children().length < tbody_tr.children().length) {
tfoot_tr.prepend('<td class="prepend">')
}
}
}
} catch (e) {
console.log(e)
}
} }
}) })

View File

@@ -488,4 +488,7 @@ div:has(.o_required_modifier) > label::before {
left: 0; left: 0;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
}
.o_list_renderer .o_list_table tfoot .o_list_number {
text-align: left;
} }

View File

@@ -9,16 +9,25 @@ access_sf_machine_brand_tags,sf_machine_brand_tags,model_sf_machine_brand_tags,b
access_sf_machine_brand_tags_admin,sf_machine_brand_tags_admin,model_sf_machine_brand_tags,base.group_system,1,1,1,0 access_sf_machine_brand_tags_admin,sf_machine_brand_tags_admin,model_sf_machine_brand_tags,base.group_system,1,1,1,0
access_sf_machine_control_system,sf_machine_control_system,model_sf_machine_control_system,base.group_user,1,1,1,0 access_sf_machine_control_system,sf_machine_control_system,model_sf_machine_control_system,base.group_user,1,1,1,0
access_sf_machine_control_system_admin,sf_machine_control_system_admin,model_sf_machine_control_system,base.group_system,1,1,1,0 access_sf_machine_control_system_admin,sf_machine_control_system_admin,model_sf_machine_control_system,base.group_system,1,1,1,0
access_sf_production_process_group_sale_director,sf_production_process_group_sale_director,model_sf_production_process,sf_base.group_sale_director,1,0,0,0
access_sf_production_process_group_sale_salemanager,sf_production_process_group_sale_salemanager,model_sf_production_process,sf_base.group_sale_salemanager,1,0,0,0
access_sf_production_process,sf_production_process,model_sf_production_process,base.group_user,1,1,1,0 access_sf_production_process,sf_production_process,model_sf_production_process,base.group_user,1,1,1,0
access_sf_production_process_admin,sf_production_process_admin,model_sf_production_process,base.group_system,1,1,1,0 access_sf_production_process_admin,sf_production_process_admin,model_sf_production_process,base.group_system,1,1,1,0
access_sf_production_materials,sf_production_materials,model_sf_production_materials,base.group_user,1,1,1,0 access_sf_production_materials,sf_production_materials,model_sf_production_materials,base.group_user,1,1,1,0
access_sf_production_materials_group_sale_director,sf_production_materials_group_sale_director,model_sf_production_materials,sf_base.group_sale_director,1,0,0,0
access_sf_production_materials_group_sale_salemanager,sf_production_materials_group_sale_salemanager,model_sf_production_materials,sf_base.group_sale_salemanager,1,0,0,0
access_sf_production_materials_admin,sf_production_materials_admin,model_sf_production_materials,base.group_system,1,1,1,0 access_sf_production_materials_admin,sf_production_materials_admin,model_sf_production_materials,base.group_system,1,1,1,0
access_sf_materials_model,sf_materials_model,model_sf_materials_model,base.group_user,1,1,1,0 access_sf_materials_model,sf_materials_model,model_sf_materials_model,base.group_user,1,1,1,0
access_sf_materials_model_admin,sf_materials_model_admin,model_sf_materials_model,base.group_system,1,1,1,0 access_sf_materials_model_admin,sf_materials_model_admin,model_sf_materials_model,base.group_system,1,1,1,0
access_sf_supplier_sort,sf_supplier_sort,model_sf_supplier_sort,base.group_user,1,1,1,0 access_sf_supplier_sort,sf_supplier_sort,model_sf_supplier_sort,base.group_user,1,1,1,0
access_sf_supplier_sort_admin,sf_supplier_sort_admin,model_sf_supplier_sort,base.group_system,1,1,1,0 access_sf_supplier_sort_admin,sf_supplier_sort_admin,model_sf_supplier_sort,base.group_system,1,1,1,0
access_sf_production_process_parameter,sf_production_process_parameter,model_sf_production_process_parameter,base.group_user,1,1,1,0 access_sf_production_process_parameter,sf_production_process_parameter,model_sf_production_process_parameter,base.group_user,1,1,1,0
access_sf_production_process_parameter_group_sale_director,sf_production_process_parameter_group_sale_director,model_sf_production_process_parameter,sf_base.group_sale_director,1,0,0,0
access_sf_production_process_parameter_group_sale_salemanager,sf_production_process_parameter_group_sale_salemanager,model_sf_production_process_parameter,sf_base.group_sale_salemanager,1,0,0,0
access_sf_production_process_parameter_group_plan_director,sf_production_process_parameter_group_plan_director,model_sf_production_process_parameter,sf_base.group_plan_director,1,0,0,0 access_sf_production_process_parameter_group_plan_director,sf_production_process_parameter_group_plan_director,model_sf_production_process_parameter,sf_base.group_plan_director,1,0,0,0
access_sf_production_process_parameter_group_purchase_director,sf_production_process_parameter_group_purchase_director,model_sf_production_process_parameter,sf_base.group_purchase_director,1,0,0,0 access_sf_production_process_parameter_group_purchase_director,sf_production_process_parameter_group_purchase_director,model_sf_production_process_parameter,sf_base.group_purchase_director,1,0,0,0
access_sf_production_process_parameter_group_sale_director,sf_production_process_parameter_group_sale_director,model_sf_production_process_parameter,sf_base.group_sale_director,1,0,0,0 access_sf_production_process_parameter_group_sale_director,sf_production_process_parameter_group_sale_director,model_sf_production_process_parameter,sf_base.group_sale_director,1,0,0,0
@@ -101,6 +110,10 @@ access_sf_production_materials_group_plan_director,sf_production_materials_group
access_sf_production_materials_group_purchase_director,sf_production_materials_group_purchase_director,model_sf_production_materials,sf_base.group_purchase_director,1,1,0,0 access_sf_production_materials_group_purchase_director,sf_production_materials_group_purchase_director,model_sf_production_materials,sf_base.group_purchase_director,1,1,0,0
access_sf_production_materials_group_sale_director,sf_production_materials_group_sale_director,model_sf_production_materials,sf_base.group_sale_director,1,1,0,0 access_sf_production_materials_group_sale_director,sf_production_materials_group_sale_director,model_sf_production_materials,sf_base.group_sale_director,1,1,0,0
access_sf_materials_model,sf_materials_model,model_sf_materials_model,sf_base.group_sf_mrp_user,1,0,0,0 access_sf_materials_model,sf_materials_model,model_sf_materials_model,sf_base.group_sf_mrp_user,1,0,0,0
access_sf_materials_model_group_sale_salemanager,sf_materials_model_group_sale_salemanager,model_sf_materials_model,sf_base.group_sale_salemanager,1,0,0,0
access_sf_materials_model_group_sale_director,sf_materials_model_group_sale_director,model_sf_materials_model,sf_base.group_sale_director,1,0,0,0
access_sf_materials_model_group_plan_director,sf_materials_model_group_plan_director,model_sf_materials_model,sf_base.group_plan_director,1,0,0,0 access_sf_materials_model_group_plan_director,sf_materials_model_group_plan_director,model_sf_materials_model,sf_base.group_plan_director,1,0,0,0
access_sf_materials_model_group_purchase_director,sf_materials_model_group_purchase_director,model_sf_materials_model,sf_base.group_purchase_director,1,0,0,0 access_sf_materials_model_group_purchase_director,sf_materials_model_group_purchase_director,model_sf_materials_model,sf_base.group_purchase_director,1,0,0,0
access_sf_materials_model_group_sale_director,sf_materials_model_group_sale_director,model_sf_materials_model,sf_base.group_sale_director,1,0,0,0 access_sf_materials_model_group_sale_director,sf_materials_model_group_sale_director,model_sf_materials_model,sf_base.group_sale_director,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
9 access_sf_machine_brand_tags_admin sf_machine_brand_tags_admin model_sf_machine_brand_tags base.group_system 1 1 1 0
10 access_sf_machine_control_system sf_machine_control_system model_sf_machine_control_system base.group_user 1 1 1 0
11 access_sf_machine_control_system_admin sf_machine_control_system_admin model_sf_machine_control_system base.group_system 1 1 1 0
12 access_sf_production_process_group_sale_director sf_production_process_group_sale_director model_sf_production_process sf_base.group_sale_director 1 0 0 0
13 access_sf_production_process_group_sale_salemanager sf_production_process_group_sale_salemanager model_sf_production_process sf_base.group_sale_salemanager 1 0 0 0
14 access_sf_production_process sf_production_process model_sf_production_process base.group_user 1 1 1 0
15 access_sf_production_process_admin sf_production_process_admin model_sf_production_process base.group_system 1 1 1 0
16 access_sf_production_materials sf_production_materials model_sf_production_materials base.group_user 1 1 1 0
17 access_sf_production_materials_admin access_sf_production_materials_group_sale_director sf_production_materials_admin sf_production_materials_group_sale_director model_sf_production_materials base.group_system sf_base.group_sale_director 1 1 0 1 0 0
18 access_sf_production_materials_group_sale_salemanager sf_production_materials_group_sale_salemanager model_sf_production_materials sf_base.group_sale_salemanager 1 0 0 0
19 access_sf_production_materials_admin sf_production_materials_admin model_sf_production_materials base.group_system 1 1 1 0
20 access_sf_materials_model sf_materials_model model_sf_materials_model base.group_user 1 1 1 0
21 access_sf_materials_model access_sf_materials_model_admin sf_materials_model sf_materials_model_admin model_sf_materials_model base.group_user base.group_system 1 1 1 0
22 access_sf_materials_model_admin access_sf_supplier_sort sf_materials_model_admin sf_supplier_sort model_sf_materials_model model_sf_supplier_sort base.group_system base.group_user 1 1 1 0
23 access_sf_supplier_sort access_sf_supplier_sort_admin sf_supplier_sort sf_supplier_sort_admin model_sf_supplier_sort base.group_user base.group_system 1 1 1 0
24 access_sf_supplier_sort_admin access_sf_production_process_parameter sf_supplier_sort_admin sf_production_process_parameter model_sf_supplier_sort model_sf_production_process_parameter base.group_system base.group_user 1 1 1 0
25 access_sf_production_process_parameter access_sf_production_process_parameter_group_sale_director sf_production_process_parameter sf_production_process_parameter_group_sale_director model_sf_production_process_parameter base.group_user sf_base.group_sale_director 1 1 0 1 0 0
26 access_sf_production_process_parameter_group_plan_director access_sf_production_process_parameter_group_sale_salemanager sf_production_process_parameter_group_plan_director sf_production_process_parameter_group_sale_salemanager model_sf_production_process_parameter sf_base.group_plan_director sf_base.group_sale_salemanager 1 0 0 0
27 access_sf_production_process_parameter_group_plan_director sf_production_process_parameter_group_plan_director model_sf_production_process_parameter sf_base.group_plan_director 1 0 0 0
28 access_sf_production_process_parameter_group_purchase_director sf_production_process_parameter_group_purchase_director model_sf_production_process_parameter sf_base.group_purchase_director 1 0 0 0
29 access_sf_production_process_parameter_group_sale_director sf_production_process_parameter_group_sale_director model_sf_production_process_parameter sf_base.group_sale_director 1 0 0 0
30 access_sf_production_process_parameter_admin sf_production_process_parameter_admin model_sf_production_process_parameter base.group_system 1 1 1 0
31 access_sf_production_process_parameter_group_purchase_director access_sf_production_process_category sf_production_process_parameter_group_purchase_director sf_production_process_category model_sf_production_process_parameter model_sf_production_process_category sf_base.group_purchase_director base.group_user 1 0 1 0 1 0
32 access_sf_production_process_parameter_group_sale_director access_sf_production_process_category_admin sf_production_process_parameter_group_sale_director sf_production_process_category_admin model_sf_production_process_parameter model_sf_production_process_category sf_base.group_sale_director base.group_system 1 0 1 0 1 0
33 access_sf_production_process_parameter_admin access_sf_machine_tool_category sf_production_process_parameter_admin sf_machine_tool_category model_sf_production_process_parameter model_sf_machine_tool_category base.group_system base.group_user 1 1 1 0
110 access_sf_materials_model access_sf_materials_model_group_plan_director sf_materials_model sf_materials_model_group_plan_director model_sf_materials_model sf_base.group_sf_mrp_user sf_base.group_plan_director 1 0 0 0
111 access_sf_materials_model_group_plan_director access_sf_materials_model_group_purchase_director sf_materials_model_group_plan_director sf_materials_model_group_purchase_director model_sf_materials_model sf_base.group_plan_director sf_base.group_purchase_director 1 0 0 0
112 access_sf_materials_model_group_purchase_director access_sf_materials_model_group_sale_director sf_materials_model_group_purchase_director sf_materials_model_group_sale_director model_sf_materials_model sf_base.group_purchase_director sf_base.group_sale_director 1 0 0 0
113 access_sf_supplier_sort sf_supplier_sort model_sf_supplier_sort sf_base.group_sf_mrp_user 1 0 0 0
114 access_sf_production_process_parameter sf_production_process_parameter model_sf_production_process_parameter sf_base.group_sf_mrp_user 1 0 0 0
115 access_sf_production_process_category sf_production_process_category model_sf_production_process_category sf_base.group_sf_mrp_user 1 0 0 0
116 access_sf_machine_tool_category sf_machine_tool_category model_sf_machine_tool_category sf_base.group_sf_mrp_user 1 0 0 0
117 access_sf_materials_model_group_sale_director access_sf_cutting_tool_material_group_purchase_director sf_materials_model_group_sale_director sf_cutting_tool_material_group_purchase_director model_sf_materials_model model_sf_cutting_tool_material sf_base.group_sale_director sf_base.group_purchase_director 1 0 0 1 0
118 access_sf_supplier_sort access_sf_cutting_tool_material_group_sale_director sf_supplier_sort sf_cutting_tool_material_group_sale_director model_sf_supplier_sort model_sf_cutting_tool_material sf_base.group_sf_mrp_user sf_base.group_sale_director 1 0 0 1 0
119 access_sf_production_process_parameter access_sf_cutting_tool_material_group_plan_director sf_production_process_parameter sf_cutting_tool_material_group_plan_director model_sf_production_process_parameter model_sf_cutting_tool_material sf_base.group_sf_mrp_user sf_base.group_plan_director 1 0 0 1 0

View File

@@ -10,6 +10,7 @@
<field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/> <field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/>
<field name='is_bfm' invisible="1"/> <field name='is_bfm' invisible="1"/>
<field name='categ_type' invisible="1"/> <field name='categ_type' invisible="1"/>
<field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/>
<field name="upload_model_file" <field name="upload_model_file"
widget="many2many_binary" widget="many2many_binary"
attrs="{'invisible': ['|', '|',('categ_type', '!=', '成品'),('categ_type', '=', False),('is_bfm','=', True)]}"/> attrs="{'invisible': ['|', '|',('categ_type', '!=', '成品'),('categ_type', '=', False),('is_bfm','=', True)]}"/>

View File

@@ -24,6 +24,7 @@
'views/mrp_workcenter_views.xml', 'views/mrp_workcenter_views.xml',
'views/mrp_workorder_view.xml', 'views/mrp_workorder_view.xml',
'views/model_type_view.xml', 'views/model_type_view.xml',
'views/agv_setting_views.xml',
'views/sf_maintenance_equipment.xml', 'views/sf_maintenance_equipment.xml',
], ],

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging import logging
import json import json
from datetime import datetime
from odoo import http from odoo import http
from odoo.http import request from odoo.http import request
@@ -114,7 +115,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('RfidCode:%s' % ret['RfidCode']) logging.info('RfidCode:%s' % ret['RfidCode'])
if 'RfidCode' in ret: if 'RfidCode' in ret:
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
[('routing_type', '=', '装夹预调'), ('rfid_code', '=', ret['RfidCode'])]) [('routing_type', '=', '装夹预调'), ('rfid_code', '=', ret['RfidCode'])], limit=1, order='id asc')
if workorder: if workorder:
for item in workorder: for item in workorder:
if item.material_center_point: if item.material_center_point:
@@ -122,8 +123,8 @@ class Manufacturing_Connect(http.Controller):
res['Datas'].append({ res['Datas'].append({
'XOffset': 0 if not item.material_center_point else offset[0], 'XOffset': 0 if not item.material_center_point else offset[0],
'YOffset': 0 if not item.material_center_point else offset[1], 'YOffset': 0 if not item.material_center_point else offset[1],
'ZOffet': 0 if not item.material_center_point else offset[2], 'ZOffset': 0 if not item.material_center_point else offset[2],
'COffset': 0 if not item.X_deviation_angle else item.X_deviation_angle, 'COffset': 0,
'Coordinate': 'G54' 'Coordinate': 'G54'
}) })
else: else:
@@ -432,14 +433,15 @@ class Manufacturing_Connect(http.Controller):
if 'DeviceId' in ret: if 'DeviceId' in ret:
logging.info('DeviceId:%s' % ret['DeviceId']) logging.info('DeviceId:%s' % ret['DeviceId'])
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
[('feeder_station_destination', '=', ret['DeviceId'])]) [('feeder_station_start_id.name', '=', ret['DeviceId']),
('status', '=', '待配送')], limit=1, order='id asc')
if workpiece_delivery: if workpiece_delivery:
for wd in workpiece_delivery: for wd in workpiece_delivery:
logging.info('wd.workorder_id:%s' % wd.workorder_id.name) logging.info('wd.production_id:%s' % wd.production_id.name)
if wd.workorder_id.state == 'done' and wd.production_id.production_line_state == '待上产线': if wd.workorder_id.state == 'done' and wd.production_id.production_line_state == '待上产线':
logging.info('wd.production_id:%s' % wd.production_id.name)
logging.info('wd.production_line_state:%s' % wd.production_id.production_line_state) logging.info('wd.production_line_state:%s' % wd.production_id.production_line_state)
wd.production_id.write({'production_line_state': '已上产线'}) wd.production_id.write({'production_line_state': '已上产线'})
wd.write({'production_line_state': '已上产线'})
else: else:
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '该DeviceId没有对应的工件配送数据'} res = {'Succeed': False, 'ErrorCode': 203, 'Error': '该DeviceId没有对应的工件配送数据'}
else: else:
@@ -466,14 +468,28 @@ class Manufacturing_Connect(http.Controller):
if 'DeviceId' in ret: if 'DeviceId' in ret:
logging.info('DeviceId:%s' % ret['DeviceId']) logging.info('DeviceId:%s' % ret['DeviceId'])
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
[('feeder_station_destination', '=', ret['DeviceId'])]) [('feeder_station_destination_id.name', '=', ret['DeviceId']),
('status', '=', '待配送')], limit=1, order='id asc')
if workpiece_delivery: if workpiece_delivery:
for wd in workpiece_delivery: for wd in workpiece_delivery:
logging.info('wd.workorder_id:%s' % wd.workorder_id.name) logging.info('wd.production_id:%s' % wd.production_id.name)
if wd.workorder_id.state == 'done' and wd.production_id.production_line_state == '已上产线': if wd.workorder_id.state == 'done' and wd.production_id.production_line_state == '已上产线':
logging.info('wd.production_id:%s' % wd.production_id.name)
logging.info('wd.production_line_state:%s' % wd.production_id.production_line_state) logging.info('wd.production_line_state:%s' % wd.production_id.production_line_state)
workpiece_delivery_off = request.env['sf.workpiece.delivery'].sudo().create({
'production_id': wd.production_id.id,
'feeder_station_start_id': workpiece_delivery.feeder_station_start_id.id,
'feeder_station_destination_id': '',
'workorder_id': workpiece_delivery.workorder_id.id,
'workpiece_code': workpiece_delivery.workpiece_code,
'production_line_id': workpiece_delivery.production_line_id.id,
'task_delivery_time': datetime.now(),
'production_line_state': '已下产线'
})
wd.production_id.write({'production_line_state': '已下产线'}) wd.production_id.write({'production_line_state': '已下产线'})
logging.info('开始向agv下发下产线任务')
workpiece_delivery_off._delivery_avg()
logging.info('agv下发下产线任务已配送')
else: else:
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '该DeviceId没有对应的工件配送数据'} res = {'Succeed': False, 'ErrorCode': 203, 'Error': '该DeviceId没有对应的工件配送数据'}
else: else:
@@ -482,3 +498,35 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
logging.info('AGVDownProduct error:%s' % e) logging.info('AGVDownProduct error:%s' % e)
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
@http.route('/AutoDeviceApi/EquipmentBaseCoordinate', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
def PutEquipmentBaseCoordinate(self, **kw):
"""
获取机床基坐标
:param kw:
:return:
"""
logging.info('PutEquipmentBaseCoordinate:%s' % kw)
try:
res = {'Succeed': True}
datas = request.httprequest.data
ret = json.loads(datas)
if 'DeviceId' in ret:
equipment = request.env['maintenance.equipment'].sudo().search('name', '=', ret['DeviceId'])
if equipment:
equipment.sudo().write({
'base_coordinate_fixture_model_id': ret['base_coordinate_fixture_model_id'],
'base_coordinate_g_coordinate': ret['base_coordinate_g_coordinate'],
'base_coordinate_x': ret['base_coordinate_x'],
'base_coordinate_y': ret['base_coordinate_y'],
'base_coordinate_z': ret['base_coordinate_z'],
})
else:
res = {'Succeed': False, 'ErrorCode': 203, 'Error': 'DeviceId为%s的设备不存在!' % ret['DeviceId']}
else:
res = {'Succeed': False, 'ErrorCode': 201, 'Error': '未传DeviceId字段'}
except Exception as e:
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
logging.info('AGVDownProduct error:%s' % e)
return json.JSONEncoder().encode(res)

View File

@@ -25,7 +25,7 @@ class Workpiece(http.Controller):
if 'method' in ret: if 'method' in ret:
if ret['method'] == 'end': if ret['method'] == 'end':
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
[('production_id.name', '=', ret['reqCode'])]) [('production_id.name', '=', ret['reqCode']), ('agv_task_code'), '=', ret['taskCode']])
if workpiece_delivery: if workpiece_delivery:
workpiece_delivery.write({'status': '已配送', 'task_completion_time': ret['reqTime']}) workpiece_delivery.write({'status': '已配送', 'task_completion_time': ret['reqTime']})
else: else:

View File

@@ -8,3 +8,4 @@ from . import mrp_routing_workcenter
from . import stock from . import stock
from . import res_user from . import res_user
from . import production_line_base from . import production_line_base
from . import agv_setting

View File

@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
from odoo import fields, models
class AgvSetting(models.Model):
_name = 'sf.agv.site'
_description = 'agv站点'
number = fields.Integer('序号')
name = fields.Char('位置编号')
owning_region = fields.Char('所属区域')
state = fields.Selection([
('占用', '占用'),
('空闲', '空闲')], string='状态')
divide_the_work = fields.Char('主要分工')
class AgvTaskRoute(models.Model):
_name = 'sf.agv.task.route'
_description = 'agv任务路线'
name = fields.Char('名称')
type = fields.Selection([
('F01', '搬运'), ], string='类型', default="F01")
start_site_id = fields.Many2one('sf.agv.site', '起点接驳站位置编号')
end_site_id = fields.Many2one('sf.agv.site', '终点接驳站位置编号')
destination_production_line_id = fields.Many2one('sf.production.line', '目的生产线')
priority = fields.Selection([
('0', '正常'),
('1', ''),
('2', ''),
('3', ''),
('4', '紧急'),
], string='优先级', default='0')
active = fields.Boolean('有效', default=True)

View File

@@ -74,6 +74,8 @@ class MrpProduction(models.Model):
# 上传零件图纸 # 上传零件图纸
part_drawing = fields.Binary('零件图纸') part_drawing = fields.Binary('零件图纸')
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
@api.depends( @api.depends(
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state', 'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state',
'workorder_ids.state', 'product_qty', 'qty_producing', 'schedule_state') 'workorder_ids.state', 'product_qty', 'qty_producing', 'schedule_state')
@@ -152,6 +154,15 @@ class MrpProduction(models.Model):
# cnc程序获取 # cnc程序获取
def fetchCNC(self): def fetchCNC(self):
cnc = self.env['mrp.production'].search([('id', '=', self.id)]) cnc = self.env['mrp.production'].search([('id', '=', self.id)])
quick_order = self.env['quick.easy.order'].search(
[('name', '=', cnc.product_id.default_code.rsplit('-', 1)[0])])
programme_way = False
if cnc.manual_quotation is True:
programme_way = 'manual operation'
else:
programme_way = 'auto'
if quick_order:
programme_way = 'manual operation'
try: try:
res = {'model_code': '' if not cnc.product_id.model_code else cnc.product_id.model_code, res = {'model_code': '' if not cnc.product_id.model_code else cnc.product_id.model_code,
'production_no': cnc.name, 'production_no': cnc.name,
@@ -166,8 +177,9 @@ class MrpProduction(models.Model):
'embryo_height': cnc.product_id.bom_ids.bom_line_ids.product_id.height, '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, 'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width,
'order_no': cnc.origin, 'order_no': cnc.origin,
'model_order_no': cnc.product_id.default_code.rsplit(' -', 1)[0], 'model_order_no': cnc.product_id.default_code,
'user': cnc.env.user.name, 'user': cnc.env.user.name,
'programme_way': programme_way,
'model_file': '' if not cnc.product_id.model_file else base64.b64encode( 'model_file': '' if not cnc.product_id.model_file else base64.b64encode(
cnc.product_id.model_file).decode('utf-8') cnc.product_id.model_file).decode('utf-8')
} }

View File

@@ -46,6 +46,8 @@ class ResMrpWorkOrder(models.Model):
], string="工序类型") ], string="工序类型")
results = fields.Char('结果') results = fields.Char('结果')
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
@api.onchange('users_ids') @api.onchange('users_ids')
def get_user_permissions(self): def get_user_permissions(self):
uid = self.env.uid uid = self.env.uid
@@ -414,21 +416,24 @@ class ResMrpWorkOrder(models.Model):
def button_workpiece_delivery(self): def button_workpiece_delivery(self):
if self.routing_type == '装夹预调': if self.routing_type == '装夹预调':
for item in self.workpiece_delivery_ids: for item in self.workpiece_delivery_ids:
if not item.feeder_station_start: if not item.route_id:
raise UserError('【工件配送】明细中请输入起点接驳站') raise UserError('【工件配送】明细中请选择【任务路线】')
# if not item.workpiece_code: # if not item.workpiece_code:
# raise UserError('请对【同运工件】进行扫描') # raise UserError('请对【同运工件】进行扫描')
else: else:
if item.status == '下发': if self.cnc_program_down_state == '下发':
return { if item.status == '待下发':
'name': _('确认'), return {
'type': 'ir.actions.act_window', 'name': _('确认'),
'view_mode': 'form', 'type': 'ir.actions.act_window',
'res_model': 'sf.workpiece.delivery.wizard', 'view_mode': 'form',
'target': 'new', 'res_model': 'sf.workpiece.delivery.wizard',
'context': { 'target': 'new',
'default_workorder_id': self.id, 'context': {
}} 'default_workorder_id': self.id,
}}
else:
raise UserError(_("该制造订单还未下发CNC程序单无法进行工件配送"))
# 拼接工单对象属性值 # 拼接工单对象属性值
def json_workorder_str(self, k, production, route): def json_workorder_str(self, k, production, route):
@@ -666,47 +671,6 @@ class ResMrpWorkOrder(models.Model):
else: else:
self.results = '合格' self.results = '合格'
# cnc程序获取
def fetchCNC(self):
try:
cnc = self.env['mrp.workorder'].search(
[('routing_type', '=', 'CNC加工'), ('production_id', '=', self.production_id.id)], limit=1)
res = {'model_code': '' if not cnc.product_id.model_code else cnc.product_id.model_code,
'production_no': self.production_id.name,
'machine_tool_code': cnc.workcenter_id.equipment_id.code,
'material_code': cnc.env['sf.production.materials'].search(
[('id', '=', cnc.product_id.materials_id.id)]).materials_no,
'material_type_code': cnc.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.production_id.origin,
'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')
}
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_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 json_workorder_str1(self, k, production, route): def json_workorder_str1(self, k, production, route):
workorders_values_str = [0, '', { workorders_values_str = [0, '', {
'product_uom_id': production.product_uom_id.id, 'product_uom_id': production.product_uom_id.id,
@@ -839,7 +803,7 @@ class ResMrpWorkOrder(models.Model):
production_no_ftp = reportpath.split('/') production_no_ftp = reportpath.split('/')
production_no = workorder.production_id.name.replace('/', '_') production_no = workorder.production_id.name.replace('/', '_')
# ftp地址 # ftp地址
remotepath = os.path.join('/', production_no_ftp[1], 'detection') remotepath = os.path.join('/NC', production_no_ftp[1], 'detection')
logging.info('ftp地址:%s' % remotepath) logging.info('ftp地址:%s' % remotepath)
if reportpath.find(production_no) != -1: if reportpath.find(production_no) != -1:
# 服务器内临时地址 # 服务器内临时地址
@@ -918,7 +882,7 @@ class CNCprocessing(models.Model):
'cutting_tool_handle_type': obj['cutting_tool_handle_type'], 'cutting_tool_handle_type': obj['cutting_tool_handle_type'],
'estimated_processing_time': obj['estimated_processing_time'], 'estimated_processing_time': obj['estimated_processing_time'],
'remark': obj['remark'], 'remark': obj['remark'],
'program_path': program_path.replace('/tmp', '') 'program_path': program_path.replace('/tmp', '/home/ftp/ftp_root/NC')
}) })
cnc_processing.get_cnc_processing_file(program_path_tmp, cnc_processing, program_path) cnc_processing.get_cnc_processing_file(program_path_tmp, cnc_processing, program_path)
# cnc_workorder.state = 'done' # cnc_workorder.state = 'done'
@@ -957,7 +921,7 @@ class CNCprocessing(models.Model):
# 将FTP的nc文件下载到临时目录 # 将FTP的nc文件下载到临时目录
def download_file_tmp(self, production_no, processing_panel): def download_file_tmp(self, production_no, processing_panel):
remotepath = os.path.join('/', production_no, 'return', processing_panel) remotepath = os.path.join('/NC', production_no, 'return', processing_panel)
serverdir = os.path.join('/tmp', production_no, 'return', processing_panel) serverdir = os.path.join('/tmp', production_no, 'return', processing_panel)
ftp_resconfig = self.env['res.config.settings'].get_values() ftp_resconfig = self.env['res.config.settings'].get_values()
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), ftp_resconfig['ftp_user'], ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), ftp_resconfig['ftp_user'],
@@ -1010,9 +974,9 @@ class SfWorkOrderBarcodes(models.Model):
workorder = self.env['mrp.workorder'].browse(self.ids) workorder = self.env['mrp.workorder'].browse(self.ids)
# workorder = self.env['mrp.workorder'].search( # workorder = self.env['mrp.workorder'].search(
# [('routing_type', '=', '装夹预调'), ('production_id', '=', self.production_id.id)]) # [('routing_type', '=', '装夹预调'), ('production_id', '=', self.production_id.id)])
# workorder_old = self.env['mrp.workorder'].search([('rfid_code', '=', barcode)]) workorder_old = self.env['mrp.workorder'].search([('rfid_code', '=', barcode)])
# if workorder_old: if workorder_old:
# raise UserError('该托盘已绑定工件,请先解除绑定!!!') raise UserError('该托盘已绑定工件,请先解除绑定!!!')
if workorder: if workorder:
if workorder.routing_type == '装夹预调': if workorder.routing_type == '装夹预调':
if workorder.state in ['done']: if workorder.state in ['done']:
@@ -1073,7 +1037,7 @@ class SfWorkOrderBarcodes(models.Model):
for item in workorder_rfid: for item in workorder_rfid:
if item.state == "progress": if item.state == "progress":
item.write({'rfid_code': barcode}) item.write({'rfid_code': barcode})
# raise UserError('该托盘信息不存在!!!') raise UserError('该托盘信息不存在!!!')
# stock_move_line = self.env['stock.move.line'].search([('lot_name', '=', barcode)]) # stock_move_line = self.env['stock.move.line'].search([('lot_name', '=', barcode)])
# if stock_move_line.product_id.categ_type == '夹具': # if stock_move_line.product_id.categ_type == '夹具':
# workorder.write({ # workorder.write({
@@ -1136,48 +1100,71 @@ class WorkPieceDelivery(models.Model):
store=True) store=True)
plan_start_processing_time = fields.Datetime('计划开始加工时间', readonly=True) plan_start_processing_time = fields.Datetime('计划开始加工时间', readonly=True)
workpiece_code = fields.Char('同运工件编码') workpiece_code = fields.Char('同运工件编码')
feeder_station_start = fields.Char('起点接驳站') route_id = fields.Many2one('sf.agv.task.route', '任务路线')
feeder_station_destination = fields.Char('目的接驳站') feeder_station_start_id = fields.Many2one('sf.agv.site', '起点接驳站')
feeder_station_destination_id = fields.Many2one('sf.agv.site', '目的接驳站')
task_delivery_time = fields.Datetime('任务下发时间') task_delivery_time = fields.Datetime('任务下发时间')
task_completion_time = fields.Datetime('任务完成时间') task_completion_time = fields.Datetime('任务完成时间')
delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration') delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration')
status = fields.Selection( status = fields.Selection(
[('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态', [('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态',
default='待下发') default='待下发')
production_line_state = fields.Selection(
[('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')],
string='上/下产线', default='待上产线')
cnc_program_down_state = fields.Selection([('待下发', '待下发'), ('已下发', '已下发')],
string='CNC程序下发状态', default='待下发')
agv_task_code = fields.Char('agv任务单号')
@api.onchange('route_id')
def onchage_route(self):
if self.route_id:
self.feeder_station_start_id = self.route_id.start_site_id
self.feeder_station_destination_id = self.route_id.end_site_id
# 工件配送 # 工件配送
def button_delivery(self): def button_delivery(self):
if self.status == '待下发': if self.cnc_program_down_state == '待下发':
return { if self.route_id:
'name': _('确认'), if self.status == '待下发':
'type': 'ir.actions.act_window', return {
'view_mode': 'form', 'name': _('确认'),
'res_model': 'sf.workpiece.delivery.wizard', 'type': 'ir.actions.act_window',
'target': 'new', 'view_mode': 'form',
'context': { 'res_model': 'sf.workpiece.delivery.wizard',
'default_delivery_id': self.id, 'target': 'new',
}} 'context': {
'default_delivery_id': self.id,
}}
else:
raise UserError('状态为【待下发】的工件记录可进行配送')
else:
raise UserError('请选择任务路线再进行配送')
else: else:
raise UserError('状态为【待下发】的工件记录可进行配送') raise UserError(_("该制造订单还未下发CNC程序单,无法进行工件配送"))
# 配送至avg小车 # 配送至avg小车
def _delivery_avg(self): def _delivery_avg(self):
config = self.env['res.config.settings'].get_values() config = self.env['res.config.settings'].get_values()
agv_site = self.env['res.agv.site'].search([])
positionCode_Arr = [] positionCode_Arr = []
if agv_site: if self.feeder_station_start_id:
for item in agv_site: positionCode_Arr.append({
positionCode_Arr.append({ 'positionCode': self.feeder_station_start_id.name,
'positionCode': item.content, 'code': '00'
'code': item.type })
}) if self.feeder_station_destination_id:
positionCode_Arr.append({
'positionCode': self.feeder_station_destination_id.name,
'code': '00'
})
res = {'reqCode': self.production_id.name, 'reqTime': '', 'clientCode': '', 'tokenCode': '', res = {'reqCode': self.production_id.name, 'reqTime': '', 'clientCode': '', 'tokenCode': '',
'taskTyp': config['task_type_no'], 'ctnrTyp': '', 'ctnrCode': '', 'wbCode': config['wbcode'], 'taskTyp': 'F01', 'ctnrTyp': '', 'ctnrCode': '', 'wbCode': config['wbcode'],
'positionCodePath': positionCode_Arr, 'positionCodePath': positionCode_Arr,
'podCode': '', 'podCode': '',
'podDir': '', 'materialLot': '', 'priority': '', 'taskCode': '', 'agvCode': '', 'materialLot': '', 'podDir': '', 'materialLot': '', 'priority': '', 'taskCode': '', 'agvCode': '', 'materialLot': '',
'data': ''} 'data': ''}
try: try:
config['agv_rcs_url'] = 'http://172.16.10.114:8182/rcms/services/rest/hikRpcService/genAgvSchedulingTask'
logging.info('AGV请求路径:%s' % config['agv_rcs_url']) logging.info('AGV请求路径:%s' % config['agv_rcs_url'])
logging.info('AGV-json:%s' % res) logging.info('AGV-json:%s' % res)
headers = {'Content-Type': 'application/json'} headers = {'Content-Type': 'application/json'}
@@ -1186,14 +1173,15 @@ class WorkPieceDelivery(models.Model):
logging.info('config-ret:%s' % ret) logging.info('config-ret:%s' % ret)
if ret['code'] == 0: if ret['code'] == 0:
if self.production_id.name == ret['reqCode']: if self.production_id.name == ret['reqCode']:
self.write({'task_delivery_time': fields.Datetime.now(), 'status': '待配送'}) self.write(
{'task_delivery_time': fields.Datetime.now(), 'status': '待配送', 'agv_task_code': ret['data']})
else: else:
raise UserError(ret['message']) raise UserError(ret['message'])
except Exception as e: except Exception as e:
logging.info('config-e:%s' % e) logging.info('config-e:%s' % e)
raise UserError("工件配送请求agv失败") raise UserError("工件配送请求agv失败")
@api.depends('production_id.production_line_id') @api.onchange('production_id.production_line_id')
def _compute_production_line_id(self): def _compute_production_line_id(self):
if self.production_id.production_line_id: if self.production_id.production_line_id:
self.production_line_id = self.production_id.production_line_id.id self.production_line_id = self.production_id.production_line_id.id

View File

@@ -1,14 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging import logging
import requests
import base64 import base64
import hashlib import hashlib
import os import os
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.modules import get_resource_path from odoo.modules import get_resource_path
from OCC.Extend.DataExchange import read_step_file # from OCC.Extend.DataExchange import read_step_file
from OCC.Extend.DataExchange import write_stl_file # from OCC.Extend.DataExchange import write_stl_file
class ResProductMo(models.Model): class ResProductMo(models.Model):
@@ -522,6 +522,9 @@ class ResProductMo(models.Model):
string='注册状态', default='未注册') string='注册状态', default='未注册')
industry_code = fields.Char('行业编码', readonly=True) industry_code = fields.Char('行业编码', readonly=True)
# bfm下单
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
@api.constrains('tool_length') @api.constrains('tool_length')
def _check_tool_length_size(self): def _check_tool_length_size(self):
if self.tool_length > 1000000: if self.tool_length > 1000000:
@@ -616,6 +619,7 @@ class ResProductMo(models.Model):
'process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']), 'process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']),
'model_remark': item['remark'], 'model_remark': item['remark'],
'default_code': '%s-%s' % (order_number, i), 'default_code': '%s-%s' % (order_number, i),
'manual_quotation': item['manual_quotation'] or False,
'active': True, 'active': True,
} }
copy_product_id.sudo().write(vals) copy_product_id.sudo().write(vals)
@@ -889,6 +893,33 @@ class SfMaintenanceEquipmentAndProductTemplate(models.Model):
vals.append(res) vals.append(res)
return vals[0] return vals[0]
base_coordinate_fixture_model_id = fields.Many2one('sf.fixture.model', '基坐标卡盘型号',
domain=[('fixture_material_id', '=', '零点卡盘')])
base_coordinate_g_coordinate = fields.Char('G坐标')
base_coordinate_x = fields.Float('x轴', digits=(12, 3))
base_coordinate_y = fields.Float('y轴', digits=(12, 3))
base_coordinate_z = fields.Float('z轴', digits=(12, 3))
# ==========获取机床基坐标接口==========
def get_equipment_base_coordinate(self):
headers = {'Authorization': 'Ba F2CF5DCC-1A00-4234-9E95-65603F70CC8A'}
crea_url = "https://x24467i973.zicp.fun/AutoDeviceApi/EquipmentBaseCoordinate"
params = {"DeviceId": self.name}
r = requests.get(crea_url, params=params, headers=headers)
ret = r.json()
logging.info('register_equipment_tool:%s' % ret)
self.write({
'base_coordinate_fixture_model_id': ret['base_coordinate_fixture_model_id'],
'base_coordinate_g_coordinate': ret['base_coordinate_g_coordinate'],
'base_coordinate_x': ret['base_coordinate_x'],
'base_coordinate_y': ret['base_coordinate_y'],
'base_coordinate_z': ret['base_coordinate_z'],
})
if ret['Succeed']:
return "机床基坐标获取成功"
else:
raise ValidationError("机床基坐标获取失败")
class SfMaintenanceEquipmentTool(models.Model): class SfMaintenanceEquipmentTool(models.Model):
_name = 'maintenance.equipment.tool' _name = 'maintenance.equipment.tool'

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -129,4 +129,7 @@ access_sf_cmm_program_group_plan_dispatch,sf_cmm_program_group_plan_dispatch,mod
access_mrp_workcenter_productivity,mrp.workcenter.productivity,mrp.model_mrp_workcenter_productivity,sf_base.group_plan_dispatch,1,0,0,0 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 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
access_sf_workpiece_delivery_group_plan_dispatch,sf.workpiece.delivery,sf_manufacturing.model_sf_workpiece_delivery,sf_base.group_plan_dispatch,1,0,0,0 access_sf_workpiece_delivery_group_plan_dispatch,sf.workpiece.delivery,sf_manufacturing.model_sf_workpiece_delivery,sf_base.group_plan_dispatch,1,0,0,0
access_sf_agv_site_group_sf_order_user,sf_agv_site_group_sf_order_user,model_sf_agv_site,sf_base.group_sf_order_user,1,1,1,0
access_sf_agv_task_route_group_sf_order_user,sf_agv_task_route_group_sf_order_user,model_sf_agv_task_route,sf_base.group_sf_order_user,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
129
130
131
132
133
134
135

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- agv站点 -->
<record id="view_agv_site_tree" model="ir.ui.view">
<field name="name">agv站点</field>
<field name="model">sf.agv.site</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="number" required="1"/>
<field name="name" required="1"/>
<field name="owning_region" required="1"/>
<field name="state" required="1"/>
<field name="divide_the_work" required="1"/>
</tree>
</field>
</record>
<record id="action_agv_site_form" model="ir.actions.act_window">
<field name="name">AGV站点</field>
<field name="res_model">sf.agv.site</field>
<field name="view_mode">tree</field>
</record>
<menuitem id="menu_action_agv_site"
parent="sf_base.menu_sf_base"
name="AGV站点"
sequence="12"
action="action_agv_site_form"/>
<!-- agv任务路线 -->
<record id="view_agv_task_route_tree" model="ir.ui.view">
<field name="name">AGV任务路线</field>
<field name="model">sf.agv.task.route</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="name" required="1"/>
<field name="type" readonly="1"/>
<field name="start_site_id" required="1" options="{'no_create': True}" string="起点接驳站"/>
<field name="end_site_id" required="1" options="{'no_create': True}" string="终点接驳站"/>
<field name="destination_production_line_id" required="1" options="{'no_create': True}"/>
<field name="priority" widget="priority"/>
</tree>
</field>
</record>
<record id="action_agv_task_route_form" model="ir.actions.act_window">
<field name="name">AGV任务路线</field>
<field name="res_model">sf.agv.task.route</field>
<field name="view_mode">tree</field>
</record>
<menuitem id="menu_action_agv_task_route"
parent="sf_base.menu_sf_base"
name="AGV任务路线"
sequence="13"
action="action_agv_task_route_form"/>
</data>
</odoo>

View File

@@ -211,12 +211,12 @@
<field name="programming_state" readonly="1" <field name="programming_state" readonly="1"
attrs='{"invisible": [("programming_no","=",False)]}'/> attrs='{"invisible": [("programming_no","=",False)]}'/>
</group> </group>
<group> <!-- <group>-->
<div class="col-12 col-lg-6 o_setting_box" style="white-space: nowrap"> <!-- <div class="col-12 col-lg-6 o_setting_box" style="white-space: nowrap">-->
<button type="object" class="oe_highlight" name="fetchCNC" string="获取CNC程序代码" <!-- <button type="object" class="oe_highlight" name="fetchCNC" string="获取CNC程序代码"-->
/> <!-- />-->
</div> <!-- </div>-->
</group> <!-- </group>-->
</page> </page>
</xpath> </xpath>
<!-- <page string="Components" name="components">--> <!-- <page string="Components" name="components">-->
@@ -430,8 +430,10 @@
<tree editable="bottom"> <tree editable="bottom">
<field name="production_id" invisible="1"/> <field name="production_id" invisible="1"/>
<field name="workpiece_code"/> <field name="workpiece_code"/>
<field name="feeder_station_start" force_save="1"/> <field name="route_id" options="{'no_create': True}"/>
<field name="feeder_station_destination" force_save="1"/> <field name="feeder_station_start_id" readonly="1" force_save="1"/>
<field name="feeder_station_destination_id" readonly="1" force_save="1"/>
<field name="cnc_program_down_state" readonly="1"/>
<field name="production_line_id"/> <field name="production_line_id"/>
<field name="task_delivery_time" readonly="1"/> <field name="task_delivery_time" readonly="1"/>
<field name="task_completion_time" readonly="1"/> <field name="task_completion_time" readonly="1"/>
@@ -573,7 +575,7 @@
<field name="name">工件配送</field> <field name="name">工件配送</field>
<field name="model">sf.workpiece.delivery</field> <field name="model">sf.workpiece.delivery</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="工件配送"> <tree string="工件配送" editable="bottom" class="center" create="0" delete="0">
<header> <header>
<button name="button_delivery" type="object" string="配送" class="oe_highlight"/> <button name="button_delivery" type="object" string="配送" class="oe_highlight"/>
</header> </header>
@@ -583,11 +585,13 @@
decoration-danger="status == '待配送'"/> decoration-danger="status == '待配送'"/>
<field name="production_id" string="工件编码"/> <field name="production_id" string="工件编码"/>
<field name="workpiece_code"/> <field name="workpiece_code"/>
<field name="production_line_id"/> <field name="production_line_id" options="{'no_create': True}"/>
<field name="feeder_station_start"/> <field name="route_id" options="{'no_create': True}"/>
<field name="feeder_station_destination"/> <field name="feeder_station_start_id" readonly="1" force_save="1"/>
<field name="task_delivery_time"/> <field name="feeder_station_destination_id" readonly="1" force_save="1"/>
<field name="task_completion_time"/> <field name="cnc_program_down_state" readonly="1"/>
<field name="task_delivery_time" readonly="1"/>
<field name="task_completion_time" readonly="1"/>
<field name="delivery_duration" widget="float_time"/> <field name="delivery_duration" widget="float_time"/>
</tree> </tree>
</field> </field>
@@ -600,16 +604,19 @@
<search string="工件配送"> <search string="工件配送">
<field name="production_id"/> <field name="production_id"/>
<field name="workpiece_code"/> <field name="workpiece_code"/>
<field name="feeder_station_start"/> <field name="feeder_station_start_id"/>
<field name="production_line_id"/> <field name="production_line_id"/>
<field name="task_delivery_time"/> <field name="task_delivery_time"/>
<field name="feeder_station_destination"/> <field name="feeder_station_destination_id"/>
<field name="task_completion_time"/> <field name="task_completion_time"/>
<field name="delivery_duration"/> <field name="delivery_duration"/>
<field name="status"/> <field name="status"/>
<searchpanel> <searchpanel>
<field name="production_line_id" icon="fa-building" enable_counters="1"/> <field name="production_line_id" icon="fa-building" enable_counters="1"/>
<field name="status" icon="fa-building" enable_counters="1"/> <field name="status" icon="fa-building" enable_counters="1"/>
<field name="production_line_state" icon="fa-building" enable_counters="1"/>
<field name="cnc_program_down_state" icon="fa-building" enable_counters="1"/>
</searchpanel> </searchpanel>
</search> </search>
</field> </field>

View File

@@ -1,23 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
设备增加刀具库位table <!-- 设备增加刀具库位table-->
<record id="sf_manufacturing_hr_equipment_view_form" model="ir.ui.view"> <record id="sf_manufacturing_hr_equipment_view_form" model="ir.ui.view">
<field name="name">sf_manufacturing_equipment.form</field> <field name="name">sf_manufacturing_equipment.form</field>
<field name="model">maintenance.equipment</field> <field name="model">maintenance.equipment</field>
<field name="inherit_id" ref="sf_maintenance.sf_hr_equipment_view_form"/> <field name="inherit_id" ref="sf_maintenance.sf_hr_equipment_view_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//page[@name='sf_equipment']" position="after"> <xpath expr="//page[@name='sf_equipment']" position="after">
<page string="标准刀库" name="sf_equipment_product_template" <page string="机床基坐标" name="sf_equipment_base_coordinate"
attrs="{'invisible': [('equipment_type', '!=', '机床')]}"> attrs="{'invisible': [('equipment_type', '!=', '机床')]}">
<field name = 'product_template_ids' > <button name="get_equipment_base_coordinate" string="获取基坐标数据" type="object"
<tree editable='bottom'> class="oe_highlight"/>
<field name="code"/> <separator invisible="0"/>
</tree> <group>
</field> <group>
</page> <field name="base_coordinate_fixture_model_id" options="{'no_create': True}"/>
</xpath> <field name="base_coordinate_g_coordinate"/>
</field> <field name="base_coordinate_x"/>
</record> <field name="base_coordinate_y"/>
<field name="base_coordinate_z"/>
</group>
</group>
</page>
<page string="标准刀库" name="sf_equipment_product_template"
attrs="{'invisible': [('equipment_type', '!=', '机床')]}">
<field name='product_template_ids'>
<tree editable='bottom'>
<field name="code"/>
</tree>
</field>
</page>
</xpath>
</field>
</record>
</odoo> </odoo>

View File

@@ -5,14 +5,18 @@
<field name="model">sf.workpiece.delivery.wizard</field> <field name="model">sf.workpiece.delivery.wizard</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<field name="delivery_id" invisible="True"/> <group>
<field name="workorder_id" invisible="True"/> <field name="delivery_id" invisible="True"/>
<field name="workorder_id" invisible="True"/>
<field name="route_id" required="1" options="{'no_create': True}"/>
</group>
<div> <div>
是否确定配送? <field name="is_ok"/>
确认上述信息正确无误.
</div> </div>
<footer> <footer>
<button string="确认" name="confirm" type="object" class="oe_highlight"/> <button string="确认配送" name="confirm" type="object" class="oe_highlight"
attrs="{'invisible':[('is_ok','=',False)]}"/>
<button string="取消" class="btn btn-secondary" special="cancel"/> <button string="取消" class="btn btn-secondary" special="cancel"/>
</footer> </footer>
</form> </form>

View File

@@ -11,10 +11,11 @@ class WorkpieceDeliveryWizard(models.TransientModel):
delivery_id = fields.Many2one('sf.workpiece.delivery', string='配送') delivery_id = fields.Many2one('sf.workpiece.delivery', string='配送')
workorder_id = fields.Many2one('mrp.workorder', string='工单') workorder_id = fields.Many2one('mrp.workorder', string='工单')
route_id = fields.Many2one('sf.agv.task.route', '任务路线')
is_ok = fields.Boolean('确认上述信息正确无误.')
def confirm(self): def confirm(self):
if self.workorder_id: if self.workorder_id:
self.workorder_id.workpiece_delivery_ids._delivery_avg() self.workorder_id.workpiece_delivery_ids._delivery_avg()
else: else:
self.delivery_id._delivery_avg() self.delivery_id._delivery_avg()

View File

@@ -37,8 +37,16 @@ class FtpController():
os.makedirs(serverdir) os.makedirs(serverdir)
try: try:
logging.info("进入FTP目录 ") logging.info("进入FTP目录 ")
self.ftp.cwd(target_dir) # 切换工作路径 logging.info('目录:%s' % target_dir)
logging.info('FTP目录:%s' % target_dir) target_dir1 = target_dir.split('/')
logging.info('目录1:%s' % target_dir1[1])
self.ftp.cwd(target_dir1[1]) # 切换工作路径
logging.info('目录2:%s' % target_dir1[2])
self.ftp.cwd(target_dir1[2]) # 切换工作路径
logging.info('目录3:%s' % target_dir1[3])
self.ftp.cwd(target_dir1[3]) # 切换工作路径
logging.info('目录4:%s' % target_dir1[4])
self.ftp.cwd(target_dir1[4]) # 切换工作路径
remotenames = self.ftp.nlst() remotenames = self.ftp.nlst()
logging.info('FTP目录文件:%s' % remotenames) logging.info('FTP目录文件:%s' % remotenames)
for file in remotenames: for file in remotenames:
@@ -48,6 +56,9 @@ class FtpController():
return 1 return 1
except Exception: except Exception:
return 0 return 0
finally:
self.ftp.quit()
logging.info("ftp已关闭")
# 下载目录下的检测文件 # 下载目录下的检测文件
def download_reportfile_tree(self, target_dir, serverdir, reportpath): def download_reportfile_tree(self, target_dir, serverdir, reportpath):
@@ -61,6 +72,8 @@ class FtpController():
self.ftp.cwd(target_dir1[1]) # 切换工作路径 self.ftp.cwd(target_dir1[1]) # 切换工作路径
logging.info('目录2:%s' % target_dir1[2]) logging.info('目录2:%s' % target_dir1[2])
self.ftp.cwd(target_dir1[2]) # 切换工作路径 self.ftp.cwd(target_dir1[2]) # 切换工作路径
logging.info('目录2:%s' % target_dir1[3])
self.ftp.cwd(target_dir1[3]) # 切换工作路径
remotenames = self.ftp.nlst() remotenames = self.ftp.nlst()
logging.info('FTP目录检测报告文件:%s' % remotenames) logging.info('FTP目录检测报告文件:%s' % remotenames)
for filename in remotenames: for filename in remotenames:

View File

@@ -15,6 +15,8 @@ class ResConfigSettings(models.TransientModel):
sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com') sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com')
agv_rcs_url = fields.Char(string='avg_rcs访问地址', agv_rcs_url = fields.Char(string='avg_rcs访问地址',
default='http://172.16.10.114:8182/rcms/services/rest/hikRpcService/genAgvSchedulingTask') default='http://172.16.10.114:8182/rcms/services/rest/hikRpcService/genAgvSchedulingTask')
center_control_url = fields.Char(string='中控访问地址',
default='http://172.16.21.50:8001')
wbcode = fields.Char('地码') wbcode = fields.Char('地码')
agv_code = fields.Char(string='agv编号') agv_code = fields.Char(string='agv编号')
task_type_no = fields.Char('任务单类型编号') task_type_no = fields.Char('任务单类型编号')
@@ -99,7 +101,7 @@ class ResConfigSettings(models.TransientModel):
agv_rcs_url = config.get_param('agv_rcs_url', default='') agv_rcs_url = config.get_param('agv_rcs_url', default='')
wbcode = config.get_param('wbcode', default='') wbcode = config.get_param('wbcode', default='')
agv_code = config.get_param('agv_code', default='') agv_code = config.get_param('agv_code', default='')
task_type_no = config.get_param('task_type_no', default='') center_control_url = config.get_param('center_control_url', default='')
ftp_host = config.get_param('ftp_host', default='') ftp_host = config.get_param('ftp_host', default='')
ftp_port = config.get_param('ftp_port', default='') ftp_port = config.get_param('ftp_port', default='')
ftp_user = config.get_param('ftp_user', default='') ftp_user = config.get_param('ftp_user', default='')
@@ -112,7 +114,7 @@ class ResConfigSettings(models.TransientModel):
agv_rcs_url=agv_rcs_url, agv_rcs_url=agv_rcs_url,
wbcode=wbcode, wbcode=wbcode,
agv_code=agv_code, agv_code=agv_code,
task_type_no=task_type_no, center_control_url=center_control_url,
ftp_host=ftp_host, ftp_host=ftp_host,
ftp_port=ftp_port, ftp_port=ftp_port,
ftp_user=ftp_user, ftp_user=ftp_user,
@@ -129,16 +131,8 @@ class ResConfigSettings(models.TransientModel):
ir_config.set_param("agv_rcs_url", self.agv_rcs_url or "") ir_config.set_param("agv_rcs_url", self.agv_rcs_url or "")
ir_config.set_param("wbcode", self.wbcode or "") ir_config.set_param("wbcode", self.wbcode or "")
ir_config.set_param("agv_code", self.agv_code or "") ir_config.set_param("agv_code", self.agv_code or "")
ir_config.set_param("task_type_no", self.task_type_no or "") ir_config.set_param("center_control_url", self.center_control_url or "")
ir_config.set_param("ftp_host", self.ftp_host or "") ir_config.set_param("ftp_host", self.ftp_host or "")
ir_config.set_param("ftp_port", self.ftp_port or "") ir_config.set_param("ftp_port", self.ftp_port or "")
ir_config.set_param("ftp_user", self.ftp_user or "") ir_config.set_param("ftp_user", self.ftp_user or "")
ir_config.set_param("ftp_password", self.ftp_password or "") ir_config.set_param("ftp_password", self.ftp_password or "")
class ResAgvSite(models.Model):
_name = 'res.agv.site'
_description = 'agv站点'
type = fields.Selection([('00', '位置编号'), ('01', '库区编号'), ('02', '货架编号')], '类型')
content = fields.Char('内容')

View File

@@ -2375,6 +2375,7 @@ class CuttingToolBasicParameters(models.Model):
r = requests.post(strUrl, json={}, data=None, headers=headers) r = requests.post(strUrl, json={}, data=None, headers=headers)
r = r.json() r = r.json()
result = json.loads(r['result']) result = json.loads(r['result'])
logging.info(result)
if result['status'] == 1: if result['status'] == 1:
if 'basic_parameters_integral_tool' in result['cutting_tool_basic_parameters_all_list']: if 'basic_parameters_integral_tool' in result['cutting_tool_basic_parameters_all_list']:
if result['cutting_tool_basic_parameters_all_list']['basic_parameters_integral_tool']: if result['cutting_tool_basic_parameters_all_list']['basic_parameters_integral_tool']:

View File

@@ -1,6 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sf_static_resource_datasync,sf_static_resource_datasync,model_sf_static_resource_datasync,base.group_user,1,1,1,1 access_sf_static_resource_datasync,sf_static_resource_datasync,model_sf_static_resource_datasync,base.group_user,1,1,1,1
access_res_agv_site,access_res_agv_site,model_res_agv_site,base.group_system,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sf_static_resource_datasync sf_static_resource_datasync model_sf_static_resource_datasync base.group_user 1 1 1 1
access_res_agv_site access_res_agv_site model_res_agv_site base.group_system 1 1 1 1
3
4
5

View File

@@ -1,26 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<data> <data>
<record id="view_agv_site_tree" model="ir.ui.view">
<field name="name">agv站点集合</field>
<field name="model">res.agv.site</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="type"/>
<field name="content"/>
</tree>
</field>
</record>
<record id="action_agv_site_form" model="ir.actions.act_window">
<field name="name">站点集合</field>
<field name="res_model">res.agv.site</field>
<field name="view_mode">tree</field>
</record>
<menuitem id="menu_action_agv_site_form" action="sf_mrs_connect.action_agv_site_form" name="站点集合"
sequence="11"/>
<record id="res_config_settings_view_form_sf_sync" model="ir.ui.view"> <record id="res_config_settings_view_form_sf_sync" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.sf_sync</field> <field name="name">res.config.settings.view.form.inherit.sf_sync</field>
<field name="model">res.config.settings</field> <field name="model">res.config.settings</field>
@@ -104,10 +84,6 @@
<label for="agv_rcs_url" string="访问地址"/> <label for="agv_rcs_url" string="访问地址"/>
<field name="agv_rcs_url"/> <field name="agv_rcs_url"/>
</div> </div>
<div class="text-muted">
<label for="task_type_no"/>
<field name="task_type_no"/>
</div>
<div class="text-muted"> <div class="text-muted">
<label for="agv_code" string="车辆编号"/> <label for="agv_code" string="车辆编号"/>
<field name="agv_code"/> <field name="agv_code"/>
@@ -116,9 +92,19 @@
<label for="wbcode"/> <label for="wbcode"/>
<field name="wbcode"/> <field name="wbcode"/>
</div> </div>
<div class="mt8"> </div>
<button type="action" name="%(sf_mrs_connect.action_agv_site_form)d" </div>
string="站点集合" class="btn-link" icon="fa-arrow-right"/> </div>
</div>
<div>
<h2>中控参数配置</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<div class="text-muted">
<label for="center_control_url" string="访问地址"/>
<field name="center_control_url"/>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,12 +1,14 @@
import logging import logging
import base64 import base64
import hashlib import hashlib
import requests
import os import os
from datetime import datetime from datetime import datetime
from stl import mesh from stl import mesh
# from OCC.Core.GProp import GProp_GProps # from OCC.Core.GProp import GProp_GProps
from OCC.Extend.DataExchange import read_step_file # from OCC.Extend.DataExchange import read_step_file
from OCC.Extend.DataExchange import write_stl_file # from OCC.Extend.DataExchange import write_stl_file
from odoo.addons.sf_base.commons.common import Common
from odoo import models, fields, api from odoo import models, fields, api
from odoo.modules import get_resource_path from odoo.modules import get_resource_path
from odoo.exceptions import ValidationError, UserError from odoo.exceptions import ValidationError, UserError
@@ -79,6 +81,8 @@ class QuickEasyOrder(models.Model):
report_path = attachment._full_path(attachment.store_fname) report_path = attachment._full_path(attachment.store_fname)
vals['model_file'] = self.transition_glb_file(report_path, model_code) vals['model_file'] = self.transition_glb_file(report_path, model_code)
obj = super(QuickEasyOrder, self).create(vals) obj = super(QuickEasyOrder, self).create(vals)
logging.info('---------向cloud生成模型库记录-------')
self.model_coloring(obj)
logging.info('---------开始派单到工厂-------') logging.info('---------开始派单到工厂-------')
self.distribute_to_factory(obj) self.distribute_to_factory(obj)
obj.state = '待接单' obj.state = '待接单'
@@ -124,18 +128,18 @@ class QuickEasyOrder(models.Model):
# # print(volume) # # print(volume)
# item.model_volume = volume # item.model_volume = volume
# # 长宽高/体积 # # 长宽高/体积
# output_file = os.path.join('C:/Users/43484/Desktop/机企猫工作文档', str(library_of_models.code) + '.stl') # output_file = os.path.join('C:/Users/43484/Desktop/机企猫工作文档', str(model_code) + '.stl')
output_file = os.path.join('/tmp', str(model_code) + '.stl') output_file = os.path.join('/tmp', str(model_code) + '.stl')
your_mesh = mesh.Mesh.from_file(output_file) # your_mesh = mesh.Mesh.from_file(output_file)
volume, cog, inertia = your_mesh.get_mass_properties() # volume, cog, inertia = your_mesh.get_mass_properties()
xyz = (your_mesh.max_ - your_mesh.min_) # xyz = (your_mesh.max_ - your_mesh.min_)
item.model_length = xyz[0] # 长 单位mm # item.model_length = xyz[0] # 长 单位mm
item.model_width = xyz[1] # 宽 # item.model_width = xyz[1] # 宽
item.model_height = xyz[2] # 高 # item.model_height = xyz[2] # 高
item.model_volume = volume # item.model_volume = volume
write_stl_file(shapes, output_file, 'binary', 0.03, 0.5) write_stl_file(shapes, output_file, 'binary', 0.03, 0.5)
# 转化为glb # 转化为glb
# output_glb_file = os.path.join('C:/Users/43484/Desktop/机企猫工作文档', str(library_of_models.code) + '.glb') # output_glb_file = os.path.join('C:/Users/43484/Desktop/机企猫工作文档', str(model_code) + '.glb')
output_glb_file = os.path.join('/tmp', str(model_code) + '.glb') output_glb_file = os.path.join('/tmp', str(model_code) + '.glb')
util_path = get_resource_path('sf_base', 'static/util') util_path = get_resource_path('sf_base', 'static/util')
cmd = 'python3 %s/stl2gltf.py %s %s -b' % (util_path, output_file, output_glb_file) cmd = 'python3 %s/stl2gltf.py %s %s -b' % (util_path, output_file, output_glb_file)
@@ -185,6 +189,7 @@ class QuickEasyOrder(models.Model):
'number': item.quantity, 'number': item.quantity,
'total_amount': item.price, 'total_amount': item.price,
'remark': '', 'remark': '',
'manual_quotation': True,
'barcode': barcode 'barcode': barcode
}) })
# res['bfm_process_order_list'] = json.dumps(res['bfm_process_order_list']) # res['bfm_process_order_list'] = json.dumps(res['bfm_process_order_list'])
@@ -262,3 +267,45 @@ class QuickEasyOrder(models.Model):
except Exception as e: except Exception as e:
# self.cr.rollback() # self.cr.rollback()
return UserError('工厂创建销售订单和产品失败,请联系管理员') return UserError('工厂创建销售订单和产品失败,请联系管理员')
# 模型上色
def model_coloring(self, order):
url = '/api/library_of_models/create'
config = self.env['res.config.settings'].get_values()
config_header = Common.get_headers(self, config['token'], config['sf_secret_key'])
logging.info('order: %s' % order.name)
if order:
attachment = order.upload_model_file[0]
base64_data = base64.b64encode(attachment.datas)
base64_datas = base64_data.decode('utf-8')
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
logging.info('model_file-size: %s' % len(order.model_file))
logging.info('attachment.datas-size: %s' % len(attachment.datas))
vals = {
'programme_way': 'manual operation',
'model_code': model_code,
'model_data': base64.b64decode(attachment.datas),
'model_color_data': '',
'model_name': attachment.name,
'model_long': order.model_length,
'model_width': order.model_width,
'model_height': order.model_height,
'model_volume': order.model_volume,
'model_color_path': '/tmp/' + str(model_code) + ".step",
'model_order_no': '%s-%s' % (order.name, 1),
'remark': '订单号:%s 客户:%s' % (order.name, order.customer_id.name)
}
try:
ret = requests.post((config['sf_url'] + url), json={}, data=vals, headers=config_header,
timeout=60)
ret = ret.json()
# result = json.loads(ret['result'])
if ret['status'] == 1:
self.model_color_state = 'success'
else:
self.model_color_state = 'fail'
raise UserError(ret['message'])
except Exception as e:
self.model_color_state = 'fail'
raise UserError("模型上色失败")

View File

@@ -142,6 +142,12 @@ class ResaleOrderLine(models.Model):
check_status = fields.Selection(related='order_id.check_status') check_status = fields.Selection(related='order_id.check_status')
class ProductTemplate(models.Model):
_inherit = 'product.template'
manual_quotation = fields.Boolean('人工编程', default=False)
class RePurchaseOrder(models.Model): class RePurchaseOrder(models.Model):
_inherit = 'purchase.order' _inherit = 'purchase.order'

View File

@@ -1,7 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink 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,0 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,0,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,0,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_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_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 access_sale_order_director,sale_order_director,model_sale_order,sf_base.group_sale_director,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_quick_easy_order quick_easy_order model_quick_easy_order base.group_system 1 1 1 0
3 access_quick_easy_order_group_sale_salemanager quick_easy_order_group_sale_salemanager model_quick_easy_order sf_base.group_sale_salemanager 1 0 1 1 0
4 access_quick_easy_order_group_sale_director quick_easy_order_group_sale_director model_quick_easy_order sf_base.group_sale_director 1 0 1 1 0
5 access_sf_auto_quatotion_common sf_auto_quatotion_common model_sf_auto_quatotion_common base.group_system 1 1 1 1
6 access_sale_order_manager sale_order_manager model_sale_order sf_base.group_sale_salemanager 1 1 1 0
7 access_sale_order_director sale_order_director model_sale_order sf_base.group_sale_director 1 1 1 0

View File

@@ -48,7 +48,7 @@
<group> <group>
<group> <group>
<field name="customer_id" context="{'is_customer': True }" <field name="customer_id" context="{'is_customer': True }"
options="{'no_create': True}"/> options="{'no_create': True}" required="1"/>
<field name="upload_model_file" widget="many2many_binary"/> <field name="upload_model_file" widget="many2many_binary"/>
<field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1" <field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1"
attrs="{'invisible': [('model_file', '=', False)]}"/> attrs="{'invisible': [('model_file', '=', False)]}"/>
@@ -68,12 +68,12 @@
</div> </div>
<field name="model_volume" attrs="{'invisible': [('model_file', '=', False)]}" <field name="model_volume" attrs="{'invisible': [('model_file', '=', False)]}"
options="{'format': false}"/> options="{'format': false}"/>
<field name="material_id" options="{'no_create': True}"/> <field name="material_id" options="{'no_create': True}" required="1"/>
<field name="material_model_id" options="{'no_create': True}"/> <field name="material_model_id" options="{'no_create': True}" required="1"/>
<!-- <field name="process_id"/>--> <!-- <field name="process_id"/>-->
<field name="parameter_ids" widget="many2many_tags" string="表面工艺参数" <field name="parameter_ids" widget="many2many_tags" string="表面工艺参数"
options="{'no_create': True}"/> options="{'no_create': True}" required="1"/>
<field name="machining_precision"/> <field name="machining_precision" required="1"/>
<field name="processing_time"/> <field name="processing_time"/>
<field name="quantity" options="{'format': false}"/> <field name="quantity" options="{'format': false}"/>
<field name="unit_price"/> <field name="unit_price"/>

View File

@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging
from datetime import timedelta from datetime import timedelta
from odoo import SUPERUSER_ID from odoo import SUPERUSER_ID
from odoo import fields, models, api from odoo import fields, models, api
@@ -191,7 +193,7 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
machine_table_name_id = fields.Many2one('maintenance.equipment', string='机床名称', machine_table_name_id = fields.Many2one('maintenance.equipment', string='机床名称',
domain="[('production_line_id', '=', production_line_id)]") domain="[('production_line_id', '=', production_line_id)]")
machine_table_name = fields.Char(string='机台号', readonly=True, related='machine_table_name_id.name') 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, cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号',
domain="[('equipment_id', '=', machine_table_name_id)]") domain="[('equipment_id', '=', machine_table_name_id)]")
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True) whether_standard_knife = fields.Boolean(string='是否标准刀', default=True)
need_knife_time = fields.Datetime(string='用刀时间', readonly=False) need_knife_time = fields.Datetime(string='用刀时间', readonly=False)
@@ -201,19 +203,20 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号',
domain=[('product_id.name', '=', '功能刀具')]) domain=[('product_id.name', '=', '功能刀具')])
functional_tool_name = fields.Char(string='功能刀具名称', compute='_compute_functional_tool_name') functional_tool_name = fields.Char(string='功能刀具名称', readonly=True)
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=False) functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型',
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组') compute='_compute_tool_number', store=True)
diameter = fields.Integer(string='刀具直径(mm)', readonly=False) tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', compute='_compute_tool_number', store=True)
tool_included_angle = fields.Float(string='尖R角(mm)', readonly=False) diameter = fields.Integer(string='具直径(mm)', compute='_compute_tool_number', store=True)
tool_loading_length = fields.Float(string='总长度(mm)', readonly=False) tool_included_angle = fields.Float(string='刀尖R角(mm)', compute='_compute_tool_number', store=True)
tool_loading_length = fields.Float(string='总长度(mm)', compute='_compute_tool_number', store=True)
extension_length = fields.Float(string='伸出长(mm)') extension_length = fields.Float(string='伸出长(mm)')
effective_length = fields.Float(string='有效长(mm)') effective_length = fields.Float(string='有效长(mm)')
new_former = fields.Selection([('0', ''), ('1', '')], string='新/旧', readonly=False, default='0') new_former = fields.Selection([('0', ''), ('1', '')], string='新/旧', readonly=False, default='0')
coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], default='3', coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], default='3',
string='粗/中/精', readonly=False) string='粗/中/精', readonly=False)
L_D = fields.Float(string='L/D值', readonly=False) L_D = fields.Float(string='L/D值', readonly=False)
clearance_length = fields.Float(string='避空长(mm)', readonly=False) clearance_length = fields.Float(string='避空长(mm)', compute='_compute_tool_number', store=True)
required_cutting_time = fields.Integer(string='需切削时长', readonly=False) required_cutting_time = fields.Integer(string='需切削时长', readonly=False)
process_type = fields.Char('加工类型') process_type = fields.Char('加工类型')
margin_x_y = fields.Float('余量_X/Y') margin_x_y = fields.Float('余量_X/Y')
@@ -229,15 +232,24 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
active = fields.Boolean(string='已归档', default=True) active = fields.Boolean(string='已归档', default=True)
@api.depends('diameter', 'tool_included_angle', 'tool_groups_id') @api.depends('functional_tool_name')
def _compute_functional_tool_name(self): def _compute_tool_number(self):
for obj in self: for item in self:
if obj.tool_groups_id: inventory = self.env['sf.tool.inventory'].sudo().search([('name', '=', item.functional_tool_name)])
obj.functional_tool_name = '%s-D%sR%s' % ( if inventory:
obj.tool_groups_id.name, obj.diameter, item.functional_tool_type_id = inventory.functional_cutting_tool_model_id.id
obj.tool_included_angle) item.tool_groups_id = inventory.tool_groups_id.id
item.diameter = int(inventory.diameter)
item.tool_included_angle = inventory.angle
item.tool_loading_length = inventory.tool_length
item.clearance_length = inventory.blade_length
else: else:
obj.functional_tool_name = None item.functional_tool_type_id = False
item.tool_groups_id = False
item.diameter = 0
item.tool_included_angle = 0
item.tool_loading_length = 0
item.clearance_length = 0
@api.model @api.model
def _read_group_names(self, categories, domain, order): def _read_group_names(self, categories, domain, order):
@@ -311,10 +323,9 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划 根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划
""" """
status = False status = False
if cnc_processing.functional_tool_type_id and cnc_processing.cutting_tool_name: if cnc_processing.cutting_tool_name:
functional_tools = self.env['sf.real.time.distribution.of.functional.tools'].sudo().search( 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)])
('name', '=', cnc_processing.cutting_tool_name)])
if functional_tools: if functional_tools:
for functional_tool in functional_tools: for functional_tool in functional_tools:
if functional_tool.on_tool_stock_num == 0: if functional_tool.on_tool_stock_num == 0:
@@ -327,7 +338,6 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
'name': cnc_processing.workorder_id.production_id.name, 'name': cnc_processing.workorder_id.production_id.name,
'cam_procedure_code': cnc_processing.program_name, 'cam_procedure_code': cnc_processing.program_name,
'filename': cnc_processing.cnc_id.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, 'functional_tool_name': cnc_processing.cutting_tool_name,
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no, 'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
'process_type': cnc_processing.processing_type, 'process_type': cnc_processing.processing_type,
@@ -338,8 +348,11 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
'shank_model': cnc_processing.cutting_tool_handle_type, 'shank_model': cnc_processing.cutting_tool_handle_type,
'estimated_processing_time': cnc_processing.estimated_processing_time, 'estimated_processing_time': cnc_processing.estimated_processing_time,
}) })
logging.info('CAM工单程序用刀计划创建成功')
# 创建装刀请求 # 创建装刀请求
knife_plan.apply_for_tooling() knife_plan.apply_for_tooling()
else:
logging.info('功能刀具【%s】满足CNC用刀需求')
class FunctionalToolAssembly(models.Model): class FunctionalToolAssembly(models.Model):
@@ -409,11 +422,12 @@ class FunctionalToolAssembly(models.Model):
@api.depends('integral_freight_barcode') @api.depends('integral_freight_barcode')
def _compute_integral_product_id(self): def _compute_integral_product_id(self):
for item in self: for item in self:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.integral_freight_barcode)]) if item.integral_freight_barcode:
if location: location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.integral_freight_barcode)])
item.integral_product_id = location.product_id.id if location:
else: item.integral_product_id = location.product_id.id
item.integral_product_id = False else:
item.integral_product_id = False
# =================刀片型号============= # =================刀片型号=============
blade_freight_barcode = fields.Char('刀片货位') blade_freight_barcode = fields.Char('刀片货位')
@@ -428,11 +442,12 @@ class FunctionalToolAssembly(models.Model):
@api.depends('blade_freight_barcode') @api.depends('blade_freight_barcode')
def _compute_blade_product_id(self): def _compute_blade_product_id(self):
for item in self: for item in self:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.blade_freight_barcode)]) if item.integral_freight_barcode:
if location: location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.blade_freight_barcode)])
item.blade_product_id = location.product_id.id if location:
else: item.blade_product_id = location.product_id.id
item.blade_product_id = False else:
item.blade_product_id = False
# ==============刀杆型号================ # ==============刀杆型号================
bar_freight_barcode = fields.Char('刀杆货位') bar_freight_barcode = fields.Char('刀杆货位')
@@ -447,11 +462,12 @@ class FunctionalToolAssembly(models.Model):
@api.depends('bar_freight_barcode') @api.depends('bar_freight_barcode')
def _compute_bar_product_id(self): def _compute_bar_product_id(self):
for item in self: for item in self:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.bar_freight_barcode)]) if item.integral_freight_barcode:
if location: location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.bar_freight_barcode)])
item.bar_product_id = location.product_id.id if location:
else: item.bar_product_id = location.product_id.id
item.bar_product_id = False else:
item.bar_product_id = False
# =============刀盘型号================ # =============刀盘型号================
pad_freight_barcode = fields.Char('刀盘货位') pad_freight_barcode = fields.Char('刀盘货位')
@@ -466,11 +482,12 @@ class FunctionalToolAssembly(models.Model):
@api.depends('pad_freight_barcode') @api.depends('pad_freight_barcode')
def _compute_pad_product_id(self): def _compute_pad_product_id(self):
for item in self: for item in self:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.pad_freight_barcode)]) if item.integral_freight_barcode:
if location: location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.pad_freight_barcode)])
item.pad_product_id = location.product_id.id if location:
else: item.pad_product_id = location.product_id.id
item.pad_product_id = False else:
item.pad_product_id = False
# ==============刀柄型号============== # ==============刀柄型号==============
handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_handle_product_id', store=True) handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_handle_product_id', store=True)
@@ -506,11 +523,12 @@ class FunctionalToolAssembly(models.Model):
@api.depends('chuck_freight_barcode') @api.depends('chuck_freight_barcode')
def _compute_chuck_product_id(self): def _compute_chuck_product_id(self):
for item in self: for item in self:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.chuck_freight_barcode)]) if item.integral_freight_barcode:
if location: location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.chuck_freight_barcode)])
item.chuck_product_id = location.product_id.id if location:
else: item.chuck_product_id = location.product_id.id
item.chuck_product_id = False else:
item.chuck_product_id = False
# ==================待删除字段================== # ==================待删除字段==================
blade_name = fields.Char('') blade_name = fields.Char('')

View File

@@ -36,6 +36,7 @@ class CNCprocessing(models.Model):
obj = super(CNCprocessing, self).create(vals) obj = super(CNCprocessing, self).create(vals)
# 调用CAM工单程序用刀计划创建方法 # 调用CAM工单程序用刀计划创建方法
self.env['sf.cam.work.order.program.knife.plan'].create_cam_work_plan(obj) self.env['sf.cam.work.order.program.knife.plan'].create_cam_work_plan(obj)
logging.info('成功调用CAM工单程序用刀计划创建方法')
return obj return obj

View File

@@ -1,2 +1,3 @@
# -*-coding:utf-8-*- # -*-coding:utf-8-*-
from . import models from . import models
from . import wizard

View File

@@ -15,6 +15,7 @@
'data/ir_cron_data.xml', 'data/ir_cron_data.xml',
'security/sf_stock_security.xml', 'security/sf_stock_security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'wizard/wizard_view.xml',
'views/view.xml', 'views/view.xml',
'views/shelf_location.xml', 'views/shelf_location.xml',
'views/change_stock_move_views.xml', 'views/change_stock_move_views.xml',

View File

@@ -191,6 +191,7 @@ class SfLocation(models.Model):
# return res # return res
# 生成货位 # 生成货位
def create_location(self): def create_location(self):
""" """
当仓库类型为货架时,自动生成其下面的货位,数量为货架层数*层数容量 当仓库类型为货架时,自动生成其下面的货位,数量为货架层数*层数容量
@@ -429,7 +430,6 @@ class ShelfLocation(models.Model):
} }
return action return action
# # 仓库类别selection库区、库位、货位 # # 仓库类别selection库区、库位、货位
# location_type = fields.Selection([ # location_type = fields.Selection([
# ('货架', '货架'), # ('货架', '货架'),
@@ -516,6 +516,19 @@ class ShelfLocation(models.Model):
else: else:
raise UserError("该库位无产品") raise UserError("该库位无产品")
@api.model_create_multi
def create(self, vals_list):
# 编码重复校验
barcode_list = []
for val in vals_list:
location = self.search([('barcode', '=', val['barcode'])])
if location:
barcode_list.append(val['name'])
if barcode_list:
raise UserError("货位编码【%s】存在重复" % barcode_list)
records = super(ShelfLocation, self).create(vals_list)
return records
class Sf_stock_move_line(models.Model): class Sf_stock_move_line(models.Model):
_name = 'stock.move.line' _name = 'stock.move.line'
@@ -531,7 +544,7 @@ class Sf_stock_move_line(models.Model):
current_product_id = fields.Integer(compute='_compute_location_dest_id_value', store=True) current_product_id = fields.Integer(compute='_compute_location_dest_id_value', store=True)
there_is_no_sn = fields.Boolean('是否有序列号', default=False) there_is_no_sn = fields.Boolean('是否有序列号', default=False)
rfid = fields.Char('Rfid', readonly=True) rfid = fields.Char('Rfid')
rfid_barcode = fields.Char('Rfid', compute='_compute_rfid') rfid_barcode = fields.Char('Rfid', compute='_compute_rfid')
@api.depends('lot_id') @api.depends('lot_id')
@@ -812,35 +825,39 @@ class Sf_stock_move_line(models.Model):
destination_location_id = fields.Many2one( destination_location_id = fields.Many2one(
'sf.shelf.location', string='目标货位') 'sf.shelf.location', string='目标货位')
@api.onchange('destination_location_id') def compute_destination_location_id(self):
def _compute_destination_location_id(self):
for record in self: for record in self:
obj = self.env['sf.shelf.location'].search([('name', '=',
self.destination_location_id.name)])
if record.lot_id: if record.lot_id:
shelf_location_obj = self.env['sf.shelf.location'].search( shelf_location_obj = self.env['sf.shelf.location'].search(
[('product_sn_id', '=', record.lot_id.id)]) [('product_sn_id', '=', record.lot_id.id)])
if shelf_location_obj: if shelf_location_obj:
shelf_location_obj.product_sn_id = False shelf_location_obj.product_sn_id = False
# obj = self.env['sf.shelf.location'].search([('location_id', '=',
# self.destination_location_id.id)])
obj = self.env['sf.shelf.location'].search([('name', '=',
self.destination_location_id.name)])
if obj: if obj:
obj.product_sn_id = record.lot_id.id obj.product_sn_id = record.lot_id.id
else:
pass
else: else:
obj = self.env['sf.shelf.location'].search([('name', '=',
self.destination_location_id.name)])
if obj: if obj:
obj.product_sn_id = record.lot_id.id obj.product_sn_id = record.lot_id.id
else: else:
obj = self.env['sf.shelf.location'].search([('name', '=',
self.destination_location_id.name)])
if obj: if obj:
obj.product_id = record.product_id.id obj.product_id = record.product_id.id
# obj.location_status = '占用' # obj.location_status = '占用'
obj.product_num += record.reserved_uom_qty obj.product_num += record.reserved_uom_qty
@api.onchange('destination_location_id')
def _check_destination_location_id(self):
for item in self:
if item:
i = 0
barcode = item.destination_location_id.barcode
for line in item.picking_id.move_line_ids_without_package:
if barcode and barcode == line.destination_location_id.barcode:
i += 1
if i > 1:
raise ValidationError(
'%s】货位已经被占用,请重新选择!!!' % item.destination_location_id.barcode)
class SfStockPicking(models.Model): class SfStockPicking(models.Model):
_inherit = 'stock.picking' _inherit = 'stock.picking'
@@ -863,12 +880,15 @@ class SfStockPicking(models.Model):
res = super(SfStockPicking, self).button_validate() res = super(SfStockPicking, self).button_validate()
for line in self.move_line_ids: for line in self.move_line_ids:
if line: if line:
# 调用入库方法进行入库
line.compute_destination_location_id()
if line.current_location_id: if line.current_location_id:
if line.current_location_id.product_sn_id: if line.current_location_id.product_sn_id:
line.current_location_id.product_sn_id = False line.current_location_id.product_sn_id = False
# line.current_location_id.location_status = '空闲' # line.current_location_id.location_status = '空闲'
line.current_location_id.product_num = 0 line.current_location_id.product_num = 0
# 对入库作业的刀柄和托盘进行Rfid绑定校验
for move in self.move_ids: for move in self.move_ids:
if move and move.product_id.cutting_tool_material_id.name == '刀柄' or '托盘' in ( if move and move.product_id.cutting_tool_material_id.name == '刀柄' or '托盘' in (
move.product_id.fixture_material_id.name or ''): move.product_id.fixture_material_id.name or ''):

View File

@@ -132,6 +132,9 @@ access_sf_cutting_tool_material_group_sf_stock_manager,sf_cutting_tool_material_
access_sf_cutting_tool_standard_library_group_sf_stock_manager,sf_cutting_tool_standard_library_group_sf_stock_manager,sf_base.model_sf_cutting_tool_standard_library,sf_warehouse.group_sf_stock_manager,1,0,1,0 access_sf_cutting_tool_standard_library_group_sf_stock_manager,sf_cutting_tool_standard_library_group_sf_stock_manager,sf_base.model_sf_cutting_tool_standard_library,sf_warehouse.group_sf_stock_manager,1,0,1,0
access_sf_tool_materials_basic_parameters_group_sf_stock_manager,sf_tool_materials_basic_parameters_group_sf_stock_manager,sf_base.model_sf_tool_materials_basic_parameters,sf_warehouse.group_sf_stock_manager,1,0,1,0 access_sf_tool_materials_basic_parameters_group_sf_stock_manager,sf_tool_materials_basic_parameters_group_sf_stock_manager,sf_base.model_sf_tool_materials_basic_parameters,sf_warehouse.group_sf_stock_manager,1,0,1,0
access_sf_shelf_location_wizard_group_plan_dispatch,sf_shelf_location_wizard_group_plan_dispatch,model_sf_shelf_location_wizard,sf_base.group_plan_dispatch,1,0,0,0
access_sf_shelf_location_wizard_group_sf_stock_user_group_sf_stock_user,sf_shelf_location_wizard_group_sf_stock_user_group_sf_stock_user,model_sf_shelf_location_wizard,sf_warehouse.group_sf_stock_user,1,0,0,0
access_sf_shelf_location_wizard_group_sf_stock_manager,sf_shelf_location_wizard_group_sf_stock_manager,model_sf_shelf_location_wizard,sf_warehouse.group_sf_stock_manager,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
132
133
134
135
136
137
138
139
140

View File

@@ -19,7 +19,7 @@
<!-- ]"/> --> <!-- ]"/> -->
<field name="destination_location_id" domain="[('location_id', '=', location_dest_id_value), '|', <field name="destination_location_id" domain="[('location_id', '=', location_dest_id_value), '|',
('location_status', '=', '空闲'), ('product_id', '=', current_product_id), ('product_sn_id', ('location_status', '=', '空闲'), ('product_id', '=', current_product_id), ('product_sn_id',
'=', there_is_no_sn)]"/> '=', there_is_no_sn)]" options="{'no_create': True,'no_create_edit':True}"/>
<field name="rfid_barcode" string="Rfid"/> <field name="rfid_barcode" string="Rfid"/>
<!-- <field name="location_dest_id_product_type"/> --> <!-- <field name="location_dest_id_product_type"/> -->

View File

@@ -126,9 +126,19 @@
<field name="name">Shelf Location form</field> <field name="name">Shelf Location form</field>
<field name="model">sf.shelf.location</field> <field name="model">sf.shelf.location</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Shelf Location"> <form string="Shelf Location" create="0">
<header> <header>
<button string="货位变更"
name="%(sf_warehouse.sf_shelf_location_wizard_act)d"
type="action"
context="{'default_name':name,
'default_current_name':name,
'default_current_shelf_id':shelf_id,
'default_current_location_id':location_id,
'default_current_barcode':barcode,
'default_current_product_id':product_id,
}"
class="btn-primary" attrs="{'invisible':[('location_status','!=','占用')]}"/>
<field name="location_status" invisible="1"/> <field name="location_status" invisible="1"/>
<button string="禁用货位" name="action_location_status_disable" type="object" <button string="禁用货位" name="action_location_status_disable" type="object"
class="oe_highlight" class="oe_highlight"
@@ -155,11 +165,11 @@
</button> </button>
</div> </div>
<group> <group>
<field name="barcode"/> <field name="barcode" readonly="1"/>
<field name="name"/> <field name="name" readonly="1"/>
<field name="shelf_id"/> <field name="shelf_id" readonly="1"/>
<field name="location_id"/> <field name="location_id" readonly="1"/>
<field name="product_sn_id"/> <field name="product_sn_id" options="{'no_create': True}"/>
<field name="product_id"/> <field name="product_id"/>
<field name="product_num" readonly="1"/> <field name="product_num" readonly="1"/>
<field name="location_status"/> <field name="location_status"/>
@@ -175,7 +185,7 @@
<field name="name">shelf.location.kanban</field> <field name="name">shelf.location.kanban</field>
<field name="model">sf.shelf.location</field> <field name="model">sf.shelf.location</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<kanban class="o_kanban_mobile" js_class="custom_kanban"> <kanban class="o_kanban_mobile" js_class="custom_kanban" create="0">
<templates> <templates>
<t t-name="kanban-box"> <t t-name="kanban-box">
<div t-attf-class="oe_kanban_card oe_kanban_global_click <div t-attf-class="oe_kanban_card oe_kanban_global_click
@@ -235,6 +245,7 @@
<field name="model">sf.shelf.location</field> <field name="model">sf.shelf.location</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="货位"> <search string="货位">
<field name="barcode"/>
<searchpanel class="account_root"> <searchpanel class="account_root">
<!-- <field name="location_type" icon="fa-filter"/> --> <!-- <field name="location_type" icon="fa-filter"/> -->
<!-- <field name="location_id" select="multi" icon="fa-filter"/> --> <!-- <field name="location_id" select="multi" icon="fa-filter"/> -->

View File

@@ -0,0 +1 @@
from . import wizard

View File

@@ -0,0 +1,64 @@
from odoo import fields, models, api
from odoo.exceptions import UserError, ValidationError
class ShelfLocationWizard(models.TransientModel):
_name = 'sf.shelf.location.wizard'
_description = '货位变更'
name = fields.Char('')
current_location_id = fields.Many2one('stock.location', string='所属库区', readonly=True)
current_shelf_id = fields.Many2one('sf.shelf', string='当前货架', readonly=True)
current_barcode = fields.Char('当前货位编码', readonly=True)
current_name = fields.Char('当前货位名称', readonly=True)
current_product_id = fields.Many2one('product.product', string='产品', readonly=True)
destination_shelf_id = fields.Many2one('sf.shelf', string='目标货架', compute='_compute_destination_name')
destination_barcode_id = fields.Many2one('sf.shelf.location', string='目标货位编码', required=True,
domain="")
destination_name = fields.Char('目标货位名称', compute='_compute_destination_name')
def return_domain(self):
val = [('location_status', '=', '空闲')]
if self.current_product_id:
val = ['|', ('location_status', '=', '空闲'), ('product_id', '=', self.current_product_id)]
if self.destination_shelf_id:
val.append(('shelf_id', '=', self.destination_shelf_id))
return "%s" % val
@api.depends('destination_barcode_id')
def _compute_destination_name(self):
if self.destination_barcode_id:
self.destination_name = self.destination_barcode_id.name
self.destination_shelf_id = self.destination_barcode_id.shelf_id.id
else:
self.destination_name = ''
self.destination_shelf_id = False
#
# @api.onchange('destination_barcode_id')
# def _onchange_destination_shelf_id(self):
# if self.destination_barcode_id:
# self.destination_shelf_id = self.destination_barcode_id.shelf_id.id
def confirm_the_change(self):
shelf_location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.current_barcode)])
# 变更货位
if self.destination_barcode_id and shelf_location:
if self.destination_barcode_id.product_id and self.destination_barcode_id.product_id == shelf_location.product_id and not self.destination_barcode_id.product_sn_id:
self.destination_barcode_id.product_num += shelf_location.product_num
else:
self.destination_barcode_id.product_sn_id = shelf_location.product_sn_id.id
self.destination_barcode_id.product_id = shelf_location.product_id.id
self.destination_barcode_id.product_num = shelf_location.product_num
shelf_location.product_sn_id = False
shelf_location.product_id = False
shelf_location.product_num = 0
else:
raise ValidationError('目标货位出错,请联系管理员!')
# 关闭弹出窗口
return {'type': 'ir.actions.act_window_close'}

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="sf_shelf_location_wizard_form" model="ir.ui.view">
<field name="name">货位变更</field>
<field name="model">sf.shelf.location.wizard</field>
<field name="arch" type="xml">
<form string="货位变更">
<sheet>
<group>
<group string="初始货位">
<group>
<field name="current_location_id"/>
<field name="current_shelf_id" string="货架"/>
<field name="current_barcode" string="编码"/>
<field name="current_name" string="名称"/>
</group>
</group>
<group string="目标货位">
<group>
<field name="current_location_id"/>
<field name="destination_shelf_id" string="货架" options="{'no_create': True}"
placeholder="请选择目标货架"/>
<field name="destination_barcode_id" string="编码" options="{'no_create': True}"
placeholder="请选择目标货位"
domain="['|', ('location_status', '=', '空闲'), ('product_id', '=', current_product_id)]"/>
<field name="destination_name" string="名称"/>
<field name="current_product_id" invisible="1"/>
</group>
</group>
</group>
</sheet>
<footer>
<button string="确定" name="confirm_the_change" type="object" class="btn-primary"
confirm="是否确认变更货位"/>
<button string="取消" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="sf_shelf_location_wizard_act" model="ir.actions.act_window">
<field name="name">货位变更</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sf.shelf.location.wizard</field>
<field name="view_mode">form</field>
<field name="view_id" ref="sf_shelf_location_wizard_form"/>
<field name="target">new</field>
</record>
</odoo>