1.快速订单新增特征识别路径字段
2.修复销售经理和销售总监看不到快速订单菜单 3.优化系统设置页面,新增特征识别路径展示,去掉重复的业务平台参数配置展示 4.快速订单去掉老版本的特征识别的代码及包,新增最新的特征识别方法
This commit is contained in:
@@ -8,14 +8,14 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//div[hasclass('app_settings_block')]/div" position="before">
|
<xpath expr="//div[hasclass('app_settings_block')]/div" position="before">
|
||||||
<div>
|
<div>
|
||||||
<h2>bfm环境配置</h2>
|
<h2>业务平台参数配置</h2>
|
||||||
<div class="row mt16 o_settings_container" id="jd_api">
|
<div class="row mt16 o_settings_container" id="jd_api">
|
||||||
<div class="col-12 col-lg-6 o_setting_box">
|
<div class="col-12 col-lg-6 o_setting_box">
|
||||||
<div class="o_setting_left_pane"/>
|
<div class="o_setting_left_pane"/>
|
||||||
<div class="o_setting_right_pane">
|
<div class="o_setting_right_pane">
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
<label for="bfm_url"/>
|
<label for="bfm_url" />
|
||||||
<field name="bfm_url"/>
|
<field name="bfm_url" string="访问地址"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- </div> -->
|
<!-- </div> -->
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
token = fields.Char(string='TOKEN', default='b811ac06-3f00-11ed-9aed-0242ac110003')
|
token = fields.Char(string='TOKEN', default='b811ac06-3f00-11ed-9aed-0242ac110003')
|
||||||
sf_secret_key = fields.Char(string='密钥', default='wBmxej38OkErKhD6')
|
sf_secret_key = fields.Char(string='密钥', default='wBmxej38OkErKhD6')
|
||||||
sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com')
|
sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com')
|
||||||
bfm_url = fields.Char(string='业务平台后端访问地址', default='https://bfm.jikimo.com')
|
|
||||||
agv_url = fields.Char(string='avg访问地址', default='http://IP:PORT/rcms/services/rest')
|
agv_url = fields.Char(string='avg访问地址', default='http://IP:PORT/rcms/services/rest')
|
||||||
|
model_parser_url = fields.Char('特征识别路径')
|
||||||
ftp_host = fields.Char(string='FTP的ip')
|
ftp_host = fields.Char(string='FTP的ip')
|
||||||
ftp_port = fields.Char(string='FTP端口')
|
ftp_port = fields.Char(string='FTP端口')
|
||||||
ftp_user = fields.Char(string='FTP用户')
|
ftp_user = fields.Char(string='FTP用户')
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//div[hasclass('app_settings_block')]/div" position="before">
|
<xpath expr="//div[hasclass('app_settings_block')]/div" position="before">
|
||||||
<div>
|
<div>
|
||||||
<h2>同步参数配置</h2>
|
<h2>云平台参数配置</h2>
|
||||||
<div class="row mt16 o_settings_container" id="pay_api">
|
<div class="row mt16 o_settings_container">
|
||||||
<div class="col-12 col-lg-6 o_setting_box">
|
<div class="col-12 col-lg-6 o_setting_box">
|
||||||
<div class="o_setting_left_pane"/>
|
<div class="o_setting_left_pane"/>
|
||||||
<div class="o_setting_right_pane">
|
<div class="o_setting_right_pane">
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2>FTP参数配置</h2>
|
<h2>FTP参数配置</h2>
|
||||||
<div class="row mt16 o_settings_container" id="pay_api">
|
<div class="row mt16 o_settings_container">
|
||||||
<div class="col-12 col-lg-6 o_setting_box">
|
<div class="col-12 col-lg-6 o_setting_box">
|
||||||
<div class="o_setting_left_pane"/>
|
<div class="o_setting_left_pane"/>
|
||||||
<div class="o_setting_right_pane">
|
<div class="o_setting_right_pane">
|
||||||
@@ -61,14 +61,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2>业务平台参数配置</h2>
|
<h2>特征识别参数配置</h2>
|
||||||
<div class="row mt16 o_settings_container" id="pay_api">
|
<div class="row mt16 o_settings_container">
|
||||||
<div class="col-12 col-lg-6 o_setting_box">
|
<div class="col-12 col-lg-6 o_setting_box">
|
||||||
<div class="o_setting_left_pane"/>
|
<div class="o_setting_left_pane"/>
|
||||||
<div class="o_setting_right_pane">
|
<div class="o_setting_right_pane">
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
<label for="bfm_url" string="访问地址"/>
|
<label for="model_parser_url" string="访问地址"/>
|
||||||
<field name="bfm_url"/>
|
<field name="model_parser_url"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
from . import sale_order
|
from . import sale_order
|
||||||
from . import quick_easy_order
|
from . import quick_easy_order
|
||||||
from . import auto_quatotion_common
|
from . import auto_quatotion_common
|
||||||
|
from . import parser_and_calculate_work_time
|
||||||
|
from . import preload_datas_functions
|
||||||
|
|
||||||
|
|||||||
472
sf_sale/models/parser_and_calculate_work_time.py
Normal file
472
sf_sale/models/parser_and_calculate_work_time.py
Normal file
@@ -0,0 +1,472 @@
|
|||||||
|
import time
|
||||||
|
# import pandas as pd
|
||||||
|
from lxml import etree
|
||||||
|
from collections import Counter
|
||||||
|
from . import preload_datas_functions as preload
|
||||||
|
|
||||||
|
|
||||||
|
# import preload_datas_functions as preload
|
||||||
|
|
||||||
|
|
||||||
|
class FeatureParser:
|
||||||
|
"""
|
||||||
|
解析Feature.xml文件
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, xml_file):
|
||||||
|
self.root = etree.parse(xml_file).getroot()
|
||||||
|
self.size = self._get_size()
|
||||||
|
self.holes = self._get_holes()
|
||||||
|
self.slots = self._get_slot()
|
||||||
|
self.open_slots = self._get_open_slot()
|
||||||
|
self.vectors = self._get_vectors()
|
||||||
|
|
||||||
|
def _get_size(self):
|
||||||
|
size = self.root.find('Size')
|
||||||
|
return {
|
||||||
|
'length': float(size.get('Length')),
|
||||||
|
'width': float(size.get('Width')),
|
||||||
|
'height': float(size.get('Height'))
|
||||||
|
}
|
||||||
|
|
||||||
|
def _get_vectors(self):
|
||||||
|
vectors = {}
|
||||||
|
for item in self.root.findall('.//Item'):
|
||||||
|
vector = item.find('Vector')
|
||||||
|
if vector is not None:
|
||||||
|
key = (vector.get('i'), vector.get('j'), vector.get('k'))
|
||||||
|
vectors[key] = vectors.get(key, 0) + 1
|
||||||
|
return vectors
|
||||||
|
|
||||||
|
def get_vector_counts(self):
|
||||||
|
return len(self.vectors)
|
||||||
|
|
||||||
|
def _get_holes(self):
|
||||||
|
holes = []
|
||||||
|
hole_element = self.root.find('Hole')
|
||||||
|
if hole_element is not None:
|
||||||
|
for item in self.root.find('Hole').iter('Item'):
|
||||||
|
hole = {} # 每个hole是一个字典
|
||||||
|
hole['id'] = int(item.get('ID'))
|
||||||
|
hole['name'] = item.get('Name')
|
||||||
|
hole['red'] = int(item.get('Red'))
|
||||||
|
hole['green'] = int(item.get('Green'))
|
||||||
|
hole['blue'] = int(item.get('Blue'))
|
||||||
|
# 处理circles
|
||||||
|
circles = []
|
||||||
|
for circle in item.iter('Circle'):
|
||||||
|
circles.append({
|
||||||
|
'x': float(circle.get('x')),
|
||||||
|
'y': float(circle.get('y')),
|
||||||
|
'z': float(circle.get('z')),
|
||||||
|
'rad': float(circle.get('rad'))
|
||||||
|
})
|
||||||
|
hole['circles'] = circles
|
||||||
|
|
||||||
|
# 处理bottom
|
||||||
|
bottoms = []
|
||||||
|
for bottom in item.iter('Bottom'):
|
||||||
|
bottoms.append({
|
||||||
|
'x': float(bottom.get('x')),
|
||||||
|
'y': float(bottom.get('y')),
|
||||||
|
'z': float(bottom.get('z')),
|
||||||
|
'rad': float(bottom.get('rad'))
|
||||||
|
})
|
||||||
|
hole['bottoms'] = bottoms
|
||||||
|
|
||||||
|
# 处理vector
|
||||||
|
for vector in item.iter('Vector'):
|
||||||
|
hole['vector'] = {
|
||||||
|
'i': float(vector.get('i')),
|
||||||
|
'j': float(vector.get('j')),
|
||||||
|
'k': float(vector.get('k'))
|
||||||
|
}
|
||||||
|
|
||||||
|
# 创建元组并添加到列表中
|
||||||
|
z_rad_tuples = []
|
||||||
|
max_z = None
|
||||||
|
non_zero_rads = set() # 使用set来存储rad值,自动去重
|
||||||
|
for circle in circles:
|
||||||
|
z = float(circle.get('z'))
|
||||||
|
rad = float(circle.get('rad'))
|
||||||
|
if max_z is None or z > max_z:
|
||||||
|
max_z = z
|
||||||
|
if rad != 0:
|
||||||
|
non_zero_rads.add(rad)
|
||||||
|
for rad in non_zero_rads:
|
||||||
|
z_rad_tuple = (max_z, rad)
|
||||||
|
z_rad_tuples.append(z_rad_tuple)
|
||||||
|
hole['z_rad_tuples'] = z_rad_tuples
|
||||||
|
|
||||||
|
holes.append(hole) # 添加到holes列表中
|
||||||
|
|
||||||
|
return holes
|
||||||
|
|
||||||
|
def _get_slot(self):
|
||||||
|
"""
|
||||||
|
获取slot信息
|
||||||
|
"""
|
||||||
|
slots = []
|
||||||
|
slot_a_list = []
|
||||||
|
slot_element = self.root.find('Slot')
|
||||||
|
if slot_element is not None:
|
||||||
|
for item in self.root.find('Slot').iter('Item'):
|
||||||
|
slot = {}
|
||||||
|
slot['id'] = int(item.get('ID'))
|
||||||
|
slot['name'] = item.get('Name')
|
||||||
|
slot['red'] = int(item.get('Red'))
|
||||||
|
slot['green'] = int(item.get('Green'))
|
||||||
|
slot['blue'] = int(item.get('Blue'))
|
||||||
|
# 获取Volume和Area信息
|
||||||
|
volume = item.find('Volume')
|
||||||
|
if volume is not None:
|
||||||
|
slot['volume'] = float(volume.get('value'))
|
||||||
|
|
||||||
|
area = item.find('Area')
|
||||||
|
if area is not None:
|
||||||
|
slot['area'] = float(area.get('value'))
|
||||||
|
slot_a_list.append(slot['area'])
|
||||||
|
# 处理lines
|
||||||
|
lines = []
|
||||||
|
for line in item.iter('Line'):
|
||||||
|
lines.append({
|
||||||
|
'type': line.get('Type'), # 'type' : 'line' or 'arc
|
||||||
|
'x1': float(line.get('x1')),
|
||||||
|
'y1': float(line.get('y1')),
|
||||||
|
'z1': float(line.get('z1')),
|
||||||
|
'x2': float(line.get('x2')),
|
||||||
|
'y2': float(line.get('y2')),
|
||||||
|
'z2': float(line.get('z2'))
|
||||||
|
})
|
||||||
|
slot['lines'] = lines
|
||||||
|
|
||||||
|
# 处理Arc
|
||||||
|
arcs = []
|
||||||
|
for arc in item.iter('Arc'):
|
||||||
|
arcs.append({
|
||||||
|
'type': arc.get('Type'),
|
||||||
|
'x1': float(arc.get('x1')),
|
||||||
|
'y1': float(arc.get('y1')),
|
||||||
|
'z1': float(arc.get('z1')),
|
||||||
|
'x2': float(arc.get('x2')),
|
||||||
|
'y2': float(arc.get('y2')),
|
||||||
|
'z2': float(arc.get('z2')),
|
||||||
|
'x3': float(arc.get('x3')),
|
||||||
|
'y3': float(arc.get('y3')),
|
||||||
|
'z3': float(arc.get('z3'))
|
||||||
|
|
||||||
|
})
|
||||||
|
slot['arcs'] = arcs
|
||||||
|
slot['a'] = slot_a_list
|
||||||
|
slots.append(slot)
|
||||||
|
return slots
|
||||||
|
|
||||||
|
def _get_open_slot(self):
|
||||||
|
"""
|
||||||
|
获取open_slot信息
|
||||||
|
"""
|
||||||
|
open_slots = []
|
||||||
|
open_slot_v_list = []
|
||||||
|
open_slot_element = self.root.find('OpenSlot')
|
||||||
|
if open_slot_element is not None:
|
||||||
|
for item in self.root.find('OpenSlot').iter('Item'):
|
||||||
|
open_slot = {}
|
||||||
|
open_slot['id'] = int(item.get('ID'))
|
||||||
|
open_slot['name'] = item.get('Name')
|
||||||
|
open_slot['red'] = int(item.get('Red'))
|
||||||
|
open_slot['green'] = int(item.get('Green'))
|
||||||
|
open_slot['blue'] = int(item.get('Blue'))
|
||||||
|
# 获取Volume和Area信息
|
||||||
|
volume = item.find('Volume')
|
||||||
|
if volume is not None:
|
||||||
|
open_slot['volume'] = float(volume.get('value'))
|
||||||
|
|
||||||
|
area = item.find('Area')
|
||||||
|
if area is not None:
|
||||||
|
open_slot['area'] = float(area.get('value'))
|
||||||
|
# open_slot_v_list.append(round(open_slot['volume'] / open_slot['area'], 3))
|
||||||
|
open_slot_v_list.append(open_slot['area'])
|
||||||
|
# 处理lines
|
||||||
|
lines = []
|
||||||
|
for line in item.iter('Line'):
|
||||||
|
lines.append({
|
||||||
|
'type': line.get('Type'), # 'type' : 'line' or 'arc
|
||||||
|
'x1': float(line.get('x1')),
|
||||||
|
'y1': float(line.get('y1')),
|
||||||
|
'z1': float(line.get('z1')),
|
||||||
|
'x2': float(line.get('x2')),
|
||||||
|
'y2': float(line.get('y2')),
|
||||||
|
'z2': float(line.get('z2'))
|
||||||
|
})
|
||||||
|
open_slot['lines'] = lines
|
||||||
|
|
||||||
|
# 处理Arc
|
||||||
|
arcs = []
|
||||||
|
for arc in item.iter('Arc'):
|
||||||
|
arcs.append({
|
||||||
|
'type': arc.get('Type'),
|
||||||
|
'x1': float(arc.get('x1')),
|
||||||
|
'y1': float(arc.get('y1')),
|
||||||
|
'z1': float(arc.get('z1')),
|
||||||
|
'x2': float(arc.get('x2')),
|
||||||
|
'y2': float(arc.get('y2')),
|
||||||
|
'z2': float(arc.get('z2')),
|
||||||
|
'x3': float(arc.get('x3')),
|
||||||
|
'y3': float(arc.get('y3')),
|
||||||
|
'z3': float(arc.get('z3'))
|
||||||
|
|
||||||
|
})
|
||||||
|
open_slot['arcs'] = arcs
|
||||||
|
open_slot['v'] = open_slot_v_list
|
||||||
|
open_slots.append(open_slot)
|
||||||
|
return open_slots
|
||||||
|
|
||||||
|
|
||||||
|
def hole_time(parser):
|
||||||
|
"""
|
||||||
|
计算孔的工时
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# 判断是否有孔
|
||||||
|
if parser.holes is not None:
|
||||||
|
# 遍历所有的孔,获取孔径和孔深度,然后调用函数查询工时
|
||||||
|
hole_total_time = 0
|
||||||
|
nums = 1
|
||||||
|
expand_hole = '否'
|
||||||
|
j_time = 0
|
||||||
|
j_hole_nums = 0
|
||||||
|
hole_nums = 0
|
||||||
|
for hole in parser.holes:
|
||||||
|
for z_rad_tuple in hole['z_rad_tuples']:
|
||||||
|
if (2 * z_rad_tuple[1] * z_rad_tuple[0] <= 3750) and (2 * z_rad_tuple[1] <= 25):
|
||||||
|
hole_nums += 1
|
||||||
|
# print('z_rad_tuple', z_rad_tuple)
|
||||||
|
per_time_minute = preload.get_suitable_hole_working_hours(preload.df_hole_duration,
|
||||||
|
2 * z_rad_tuple[1],
|
||||||
|
z_rad_tuple[0])
|
||||||
|
# if per_time_minute is None:
|
||||||
|
# raise Exception('孔径为%s,深度为%s的孔没有找到对应的工时' % (2 * z_rad_tuple[1], z_rad_tuple[0]))
|
||||||
|
# print('per_time_minute', per_time_minute)
|
||||||
|
expand_hole_end = 0.6 if expand_hole == '是' else 1
|
||||||
|
per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
|
||||||
|
hole_total_time += per_time
|
||||||
|
elif (2 * z_rad_tuple[1] * z_rad_tuple[0] <= 3750) and (2 * z_rad_tuple[1] > 25):
|
||||||
|
hole_nums += 1
|
||||||
|
# print('z_rad_tuple', z_rad_tuple)
|
||||||
|
per_time_minute = 0.0003 * 2 * z_rad_tuple[1] * z_rad_tuple[0]
|
||||||
|
expand_hole_end = 0.6 if expand_hole == '是' else 1
|
||||||
|
per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
|
||||||
|
hole_total_time += per_time
|
||||||
|
elif 3750 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 50000:
|
||||||
|
hole_nums += 1
|
||||||
|
# print('z_rad_tuple', z_rad_tuple)
|
||||||
|
per_time_minute = 0.0003 * 2 * z_rad_tuple[1] * z_rad_tuple[0]
|
||||||
|
expand_hole_end = 0.6 if expand_hole == '是' else 1
|
||||||
|
per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
|
||||||
|
hole_total_time += per_time
|
||||||
|
elif 50000 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 100000:
|
||||||
|
hole_nums += 1
|
||||||
|
# print('z_rad_tuple', z_rad_tuple)
|
||||||
|
per_time_minute = 0.00018 * 2 * z_rad_tuple[1] * z_rad_tuple[0]
|
||||||
|
expand_hole_end = 0.6 if expand_hole == '是' else 1
|
||||||
|
per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
|
||||||
|
hole_total_time += per_time
|
||||||
|
elif 100000 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 150000:
|
||||||
|
hole_nums += 1
|
||||||
|
# print('z_rad_tuple', z_rad_tuple)
|
||||||
|
per_time_minute = 0.00016 * 2 * z_rad_tuple[1] * z_rad_tuple[0]
|
||||||
|
expand_hole_end = 0.6 if expand_hole == '是' else 1
|
||||||
|
per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
|
||||||
|
hole_total_time += per_time
|
||||||
|
elif 150000 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 200000:
|
||||||
|
hole_nums += 1
|
||||||
|
# print('z_rad_tuple', z_rad_tuple)
|
||||||
|
per_time_minute = 0.00015 * 2 * z_rad_tuple[1] * z_rad_tuple[0]
|
||||||
|
expand_hole_end = 0.6 if expand_hole == '是' else 1
|
||||||
|
per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
|
||||||
|
hole_total_time += per_time
|
||||||
|
elif 200000 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 250000:
|
||||||
|
hole_nums += 1
|
||||||
|
# print('z_rad_tuple', z_rad_tuple)
|
||||||
|
per_time_minute = 0.0002 * 2 * z_rad_tuple[1] * z_rad_tuple[0]
|
||||||
|
expand_hole_end = 0.6 if expand_hole == '是' else 1
|
||||||
|
per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60
|
||||||
|
hole_total_time += per_time
|
||||||
|
else:
|
||||||
|
raise Exception('孔径为%s,深度为%s的孔没有找到对应的工时' % (2 * z_rad_tuple[1], z_rad_tuple[0]))
|
||||||
|
|
||||||
|
print('孔工时', round(hole_total_time * nums * 2) / 2)
|
||||||
|
print('共有%s个孔,其中%s为台阶孔' % (len(parser.holes), hole_nums - len(parser.holes)))
|
||||||
|
return round(hole_total_time * nums * 2) / 2
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def slot_time(parser):
|
||||||
|
# 判断是否有槽
|
||||||
|
if parser.slots is not None:
|
||||||
|
# 遍历所有的槽,获取槽的长度,然后调用函数查询工时
|
||||||
|
slot_total_time = 0
|
||||||
|
nums = 1
|
||||||
|
finish_time = 0
|
||||||
|
process_time = 0
|
||||||
|
process_total_time = 0
|
||||||
|
slot_a = parser.slots[0]['a']
|
||||||
|
|
||||||
|
slot_a_counter = Counter(slot_a)
|
||||||
|
slot_a_counter_result = dict(slot_a_counter)
|
||||||
|
|
||||||
|
for i in slot_a_counter_result:
|
||||||
|
for slot in parser.slots:
|
||||||
|
if slot['area'] == i:
|
||||||
|
# # 计算长度(第一条线和第三条线的X轴距离)
|
||||||
|
# length = abs(slot['lines'][0]['y1'] - slot['lines'][2]['y1'])
|
||||||
|
# # 计算宽度(第一条线和第二条线的Y轴距离)
|
||||||
|
# width = abs(slot['lines'][1]['x1'] - slot['lines'][3]['x1'])
|
||||||
|
# # 计算面积
|
||||||
|
# area = length * width
|
||||||
|
# 槽深度
|
||||||
|
depth = round(slot['volume'] / slot['area'], 3)
|
||||||
|
|
||||||
|
# 沟通刀具暂定为12
|
||||||
|
finish_tool_diameter = 12
|
||||||
|
if 200 < slot['area'] <= 5000:
|
||||||
|
finish_time = 0
|
||||||
|
|
||||||
|
# 加工穴数待定(取得每一个槽的穴数和装夹次数,那这个数量?目前暂时按1来算,待有统计数据之后再说)
|
||||||
|
rough_part_nums = slot_a_counter_result[slot['area']]
|
||||||
|
rough_clamping_times = 1
|
||||||
|
finishi_part_nums = 1
|
||||||
|
finish_clamping_times = 1
|
||||||
|
# 调用函数计算槽的工时
|
||||||
|
slot_total_time = preload.get_suitable_rough_working_hours(preload.df_rough_duration, depth)
|
||||||
|
# if nums > 20:
|
||||||
|
# process_time = round(
|
||||||
|
# (nums * 0.6 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
|
||||||
|
# finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
|
||||||
|
# elif nums > 10:
|
||||||
|
# process_time = round(
|
||||||
|
# (nums * 0.7 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
|
||||||
|
# finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
|
||||||
|
# elif nums > 6:
|
||||||
|
# process_time = round(
|
||||||
|
# (nums * 0.8 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
|
||||||
|
# finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
|
||||||
|
# elif nums > 4:
|
||||||
|
# process_time = round(
|
||||||
|
# (nums * 0.9 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
|
||||||
|
# finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
|
||||||
|
# elif nums > 1:
|
||||||
|
# process_time = round(
|
||||||
|
# (nums * 0.95 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
|
||||||
|
# finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
|
||||||
|
# else:
|
||||||
|
# process_time = round(
|
||||||
|
# (nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
|
||||||
|
# finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
|
||||||
|
process_time = round(
|
||||||
|
(nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
|
||||||
|
finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
|
||||||
|
# print('slot_total_time', slot_total_time)
|
||||||
|
elif slot['area'] <= 200:
|
||||||
|
slot_total_time = 0
|
||||||
|
rough_part_nums = slot_a_counter_result[slot['area']]
|
||||||
|
rough_clamping_times = 1
|
||||||
|
finishi_part_nums = 1
|
||||||
|
finish_clamping_times = 1
|
||||||
|
# 调用函数计算槽的工时
|
||||||
|
finish_time = preload.get_suitable_finish_working_hours(preload.df_finish_duration, depth,
|
||||||
|
finish_tool_diameter)
|
||||||
|
process_time = round(
|
||||||
|
(nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
|
||||||
|
finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
|
||||||
|
# print('finish_time', finish_time)
|
||||||
|
else:
|
||||||
|
rough_part_nums = slot_a_counter_result[slot['area']]
|
||||||
|
rough_clamping_times = 1
|
||||||
|
finishi_part_nums = 1
|
||||||
|
finish_clamping_times = 1
|
||||||
|
process_time = round(
|
||||||
|
(nums * 1 * ((0.00016 * rough_part_nums + rough_clamping_times * 20) + (
|
||||||
|
finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
|
||||||
|
process_total_time += process_time
|
||||||
|
|
||||||
|
print('槽工时', process_total_time)
|
||||||
|
return process_total_time
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def open_slot_time(parser):
|
||||||
|
# 判断是否有开口槽
|
||||||
|
if parser.open_slots is not None:
|
||||||
|
# 遍历所有的开口槽,获取槽宽和槽长,然后调用函数查询工时
|
||||||
|
open_slot_total_time = 0
|
||||||
|
nums = 1
|
||||||
|
finish_time = 0
|
||||||
|
open_slot_process_time = 0
|
||||||
|
|
||||||
|
open_slot_v = parser.open_slots[0]['v']
|
||||||
|
|
||||||
|
counter = Counter(open_slot_v)
|
||||||
|
result = dict(counter)
|
||||||
|
|
||||||
|
transiant_time = 0
|
||||||
|
for i in result:
|
||||||
|
for open_slot in parser.open_slots:
|
||||||
|
if open_slot['area'] == i:
|
||||||
|
depth = round(open_slot['volume'] / open_slot['area'], 3)
|
||||||
|
# 沟通刀具暂定为12
|
||||||
|
finish_tool_diameter = 12
|
||||||
|
if 200 < open_slot['area'] <= 5000:
|
||||||
|
finish_time = 0
|
||||||
|
# 加工穴数待定(取得每一个槽的穴数和装夹次数,那这个数量?目前暂时按1来算,待有统计数据之后再说)
|
||||||
|
rough_part_nums = result[open_slot['area']]
|
||||||
|
rough_clamping_times = 1
|
||||||
|
finishi_part_nums = 1
|
||||||
|
finish_clamping_times = 1
|
||||||
|
# 调用函数计算槽的工时
|
||||||
|
slot_total_time = preload.get_suitable_rough_working_hours(preload.df_rough_duration, depth)
|
||||||
|
open_slot_process_time = round(
|
||||||
|
(nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
|
||||||
|
finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
|
||||||
|
# print('slot_total_time', slot_total_time)
|
||||||
|
elif open_slot['area'] <= 200:
|
||||||
|
slot_total_time = 0
|
||||||
|
rough_part_nums = 1
|
||||||
|
rough_clamping_times = 1
|
||||||
|
finishi_part_nums = 1
|
||||||
|
finish_clamping_times = 1
|
||||||
|
# 调用函数计算槽的工时
|
||||||
|
finish_time = preload.get_suitable_finish_working_hours(preload.df_finish_duration, depth,
|
||||||
|
finish_tool_diameter)
|
||||||
|
open_slot_process_time = round(
|
||||||
|
(nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + (
|
||||||
|
finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
|
||||||
|
# print('finish_time', finish_time)
|
||||||
|
else:
|
||||||
|
rough_part_nums = 1
|
||||||
|
rough_clamping_times = 1
|
||||||
|
finishi_part_nums = 1
|
||||||
|
finish_clamping_times = 1
|
||||||
|
open_slot_process_time = round(
|
||||||
|
(nums * 1 * ((0.00016 * rough_part_nums + rough_clamping_times * 20) + (
|
||||||
|
finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2
|
||||||
|
|
||||||
|
transiant_time += open_slot_process_time
|
||||||
|
print('开口槽工时', transiant_time)
|
||||||
|
return transiant_time
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
time1 = time.time()
|
||||||
|
parser = FeatureParser(
|
||||||
|
'D:\\ccccccccccccccccccccccccccccccccccccccccccccccc\\aa\\JKM001-260.200.30_FeatureTable.xml')
|
||||||
|
# print('parser', parser.holes)
|
||||||
|
# print('parser.slots', parser.slots)
|
||||||
|
# print('parser.open_slots', parser.open_slots)
|
||||||
|
print('总工时', hole_time(parser) + slot_time(parser) + open_slot_time(parser))
|
||||||
|
time2 = time.time()
|
||||||
|
print('耗时:', time2 - time1)
|
||||||
201
sf_sale/models/preload_datas_functions.py
Normal file
201
sf_sale/models/preload_datas_functions.py
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
import psycopg2
|
||||||
|
# import pandas as pd
|
||||||
|
|
||||||
|
|
||||||
|
def load_and_convert_data(table_name, column_names):
|
||||||
|
connection = None
|
||||||
|
data = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
# connection = psycopg2.connect(user="odoo",
|
||||||
|
# password="odoo",
|
||||||
|
# host="localhost",
|
||||||
|
# port="5432",
|
||||||
|
# database="www1")
|
||||||
|
connection = psycopg2.connect(user="odoo",
|
||||||
|
password="odoo",
|
||||||
|
host="120.76.195.146",
|
||||||
|
port="15432",
|
||||||
|
database="bfm_dev1")
|
||||||
|
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
# Construct the query string using the table name passed in
|
||||||
|
query = f"SELECT {', '.join(column_names)} FROM {table_name};"
|
||||||
|
cursor.execute(query)
|
||||||
|
|
||||||
|
# Fetch all rows from cursor
|
||||||
|
data = cursor.fetchall()
|
||||||
|
|
||||||
|
except (Exception, psycopg2.Error) as error:
|
||||||
|
print("Error fetching data from PostgreSQL table", error)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Always close database connection after work done
|
||||||
|
if (connection):
|
||||||
|
cursor.close()
|
||||||
|
connection.close()
|
||||||
|
|
||||||
|
# Convert the list of tuples to DataFrame
|
||||||
|
# df = pd.DataFrame(data, columns=column_names)
|
||||||
|
#
|
||||||
|
# # Convert all string columns to float
|
||||||
|
# for col in df.columns:
|
||||||
|
# if df[col].dtype == 'object':
|
||||||
|
# df[col] = df[col].astype(float)
|
||||||
|
|
||||||
|
return 'df'
|
||||||
|
|
||||||
|
|
||||||
|
def get_suitable_hole_working_hours(df, target_diameter, target_depth):
|
||||||
|
"""
|
||||||
|
从钻孔、铰孔数据中获取符合要求的最小工时
|
||||||
|
"""
|
||||||
|
# df为输入的数据,target_diameter为目标孔径,target_depth为目标孔深
|
||||||
|
|
||||||
|
df_diameter_filtered = df.loc[df['hole_diameter'] >= target_diameter]
|
||||||
|
|
||||||
|
if not df_diameter_filtered.empty:
|
||||||
|
min_diameter = df_diameter_filtered['hole_diameter'].min()
|
||||||
|
df_depth_filtered = df_diameter_filtered.loc[
|
||||||
|
(df_diameter_filtered['hole_diameter'] == min_diameter) & (
|
||||||
|
df_diameter_filtered['hole_depth'] >= target_depth)]
|
||||||
|
|
||||||
|
if not df_depth_filtered.empty:
|
||||||
|
min_depth_row = df_depth_filtered.loc[df_depth_filtered['hole_depth'].idxmin()]
|
||||||
|
min_working_hours = min_depth_row['working_hours']
|
||||||
|
return min_working_hours
|
||||||
|
else:
|
||||||
|
print("No records found where hole_depth is bigger than the target depth")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
print("No records found where hole_diameter is bigger than the target diameter")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_suitable_blank_working_hours(df, blank_height, blank_length, blank_width):
|
||||||
|
"""
|
||||||
|
从毛坯数据中获取符合要求的最小工时
|
||||||
|
"""
|
||||||
|
# df为输入的数据,blank_height为目标毛坯高度,blank_length为目标毛坯长度,blank_width为目标毛坯宽度
|
||||||
|
|
||||||
|
df_height_filtered = df.loc[df['blank_height'] >= blank_height]
|
||||||
|
|
||||||
|
if not df_height_filtered.empty:
|
||||||
|
min_height = df_height_filtered['blank_height'].min()
|
||||||
|
df_length_filtered = df_height_filtered.loc[
|
||||||
|
(df_height_filtered['blank_height'] == min_height) & (
|
||||||
|
df_height_filtered['blank_length'] >= blank_length)]
|
||||||
|
|
||||||
|
if not df_length_filtered.empty:
|
||||||
|
min_length_row = df_length_filtered.loc[df_length_filtered['blank_length'].idxmin()]
|
||||||
|
min_working_hours = min_length_row['working_hours']
|
||||||
|
return min_working_hours
|
||||||
|
else:
|
||||||
|
print("No records found where blank_length is bigger than the target length")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
print("No records found where blank_height is bigger than the target height")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_suitable_rough_working_hours(df, rough_depth):
|
||||||
|
"""
|
||||||
|
从粗加工数据中获取符合要求的最小工时
|
||||||
|
"""
|
||||||
|
# df为输入的数据,rough_depth为目标粗加工深度
|
||||||
|
|
||||||
|
df_depth_filtered = df.loc[df['rough_depth'] >= rough_depth]
|
||||||
|
|
||||||
|
if not df_depth_filtered.empty:
|
||||||
|
min_depth_row = df_depth_filtered.loc[df_depth_filtered['rough_depth'].idxmin()]
|
||||||
|
min_working_hours = min_depth_row['working_hours']
|
||||||
|
return min_working_hours
|
||||||
|
else:
|
||||||
|
print("No records found where rough_depth is bigger than the target depth")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_suitable_finish_working_hours(df, finish_depth, finish_tool_diameter):
|
||||||
|
"""
|
||||||
|
从精加工数据中获取符合要求的最小工时
|
||||||
|
"""
|
||||||
|
# df为输入的数据,finish_depth为目标精加工深度,finish_tool_diameter为目标精加工刀具直径
|
||||||
|
|
||||||
|
df_depth_filtered = df.loc[df['finish_depth'] >= finish_depth]
|
||||||
|
|
||||||
|
if not df_depth_filtered.empty:
|
||||||
|
min_depth = df_depth_filtered['finish_depth'].min()
|
||||||
|
df_tool_diameter_filtered = df_depth_filtered.loc[
|
||||||
|
(df_depth_filtered['finish_depth'] == min_depth) & (
|
||||||
|
df_depth_filtered['finish_tool_diameter'] >= finish_tool_diameter)]
|
||||||
|
|
||||||
|
if not df_tool_diameter_filtered.empty:
|
||||||
|
min_tool_diameter_row = df_tool_diameter_filtered.loc[
|
||||||
|
df_tool_diameter_filtered['finish_tool_diameter'].idxmin()]
|
||||||
|
min_working_hours = min_tool_diameter_row['working_hours']
|
||||||
|
return min_working_hours
|
||||||
|
else:
|
||||||
|
print("No records found where finish_tool_diameter is bigger than the target tool diameter")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
print("No records found where finish_depth is bigger than the target depth")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_suitable_chamfer_working_hours(df, chamfer_length, chamfer_size):
|
||||||
|
"""
|
||||||
|
根据倒角长度获得倒角工时,装夹平面耗时clamping_type_plane和装夹斜面耗时clamping_type_slope
|
||||||
|
"""
|
||||||
|
# df为输入的数据,chamfer_length为目标倒角长度,clamping_type_plane为目标装夹平面耗时,clamping_type_slope为目标装夹斜面耗时
|
||||||
|
|
||||||
|
df_length_filtered = df.loc[df['chamfer_length'] >= chamfer_length]
|
||||||
|
df_chamfer_size_filtered = df.loc[df['chamfer_size'] >= chamfer_size]
|
||||||
|
|
||||||
|
if not df_length_filtered.empty and not df_chamfer_size_filtered.empty:
|
||||||
|
min_length_row = df_length_filtered.loc[df_length_filtered['chamfer_length'].idxmin()]
|
||||||
|
min_chamfer_size_row = df_chamfer_size_filtered.loc[df_chamfer_size_filtered['chamfer_size'].idxmin()]
|
||||||
|
clamping_time = min_length_row['clamping_time']
|
||||||
|
clamping_type_plane = min_length_row['clamping_type_plane']
|
||||||
|
clamping_type_slope = min_length_row['clamping_type_slope']
|
||||||
|
coefficient = min_chamfer_size_row['coefficient']
|
||||||
|
return clamping_time, clamping_type_plane, clamping_type_slope, coefficient
|
||||||
|
else:
|
||||||
|
print("No records found where chamfer_length is bigger than the target length")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
df_hole_duration = load_and_convert_data('hole_duration', ['hole_diameter', 'hole_depth', 'working_hours'])
|
||||||
|
|
||||||
|
df_j_hole_duration = load_and_convert_data('j_hole_duration', ['hole_diameter', 'hole_depth', 'working_hours'])
|
||||||
|
|
||||||
|
df_chamfer_duration = load_and_convert_data('chamfer_duration',
|
||||||
|
['chamfer_length', 'clamping_time', 'chamfer_size', 'coefficient',
|
||||||
|
'clamping_type_plane', 'clamping_type_slope'])
|
||||||
|
|
||||||
|
df_blank_duration = load_and_convert_data('blank_duration',
|
||||||
|
['blank_length', 'blank_width', 'blank_height', 'working_hours'])
|
||||||
|
|
||||||
|
df_rough_duration = load_and_convert_data('rough_duration', ['rough_depth', 'working_hours'])
|
||||||
|
|
||||||
|
df_finish_duration = load_and_convert_data('finish_duration',
|
||||||
|
['finish_depth', 'finish_tool_diameter', 'working_hours'])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
min_working_hours = get_suitable_hole_working_hours(df_hole_duration, 24, 150)
|
||||||
|
print('min_working_hours', min_working_hours)
|
||||||
|
min_j_working_hours = get_suitable_hole_working_hours(df_j_hole_duration, 10, 15)
|
||||||
|
print('min_j_working_hours', min_j_working_hours)
|
||||||
|
min_blank_working_hours = get_suitable_blank_working_hours(df_blank_duration, 150, 300, 300)
|
||||||
|
print('min_blank_working_hours', min_blank_working_hours)
|
||||||
|
min_rough_working_hours = get_suitable_rough_working_hours(df_rough_duration, 49)
|
||||||
|
print('min_rough_working_hours', min_rough_working_hours)
|
||||||
|
min_finish_working_hours = get_suitable_finish_working_hours(df_finish_duration, 0.5, 10)
|
||||||
|
print('min_finish_working_hours', min_finish_working_hours)
|
||||||
|
clamping_time, clamping_type_plane, clamping_type_slope, coefficient = get_suitable_chamfer_working_hours(
|
||||||
|
df_chamfer_duration, 10, 1.5)
|
||||||
|
print('clamping_time', clamping_time)
|
||||||
|
print('clamping_type_plane', clamping_type_plane)
|
||||||
|
print('clamping_type_slope', clamping_type_slope)
|
||||||
|
print('coefficient', coefficient)
|
||||||
@@ -2,17 +2,19 @@ import logging
|
|||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
|
import platform
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import requests
|
import requests
|
||||||
from OCC.Extend.DataExchange import read_step_file
|
from odoo import http
|
||||||
from OCC.Extend.DataExchange import write_stl_file
|
from odoo.http import request
|
||||||
|
# from OCC.Extend.DataExchange import read_step_file
|
||||||
|
# from OCC.Extend.DataExchange import write_stl_file
|
||||||
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
|
||||||
from odoo.addons.sf_base.commons.common import Common
|
from odoo.addons.sf_base.commons.common import Common
|
||||||
|
from . import parser_and_calculate_work_time as pc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -77,11 +79,11 @@ class QuickEasyOrder(models.Model):
|
|||||||
if len(item[2]) > 0:
|
if len(item[2]) > 0:
|
||||||
logging.info('create-attachment:%s' % int(item[2][0]))
|
logging.info('create-attachment:%s' % int(item[2][0]))
|
||||||
attachment = self.env['ir.attachment'].sudo().search([('id', '=', int(item[2][0]))])
|
attachment = self.env['ir.attachment'].sudo().search([('id', '=', int(item[2][0]))])
|
||||||
base64_data = base64.b64encode(attachment.datas)
|
# base64_data = base64.b64encode(attachment.datas)
|
||||||
base64_datas = base64_data.decode('utf-8')
|
# base64_datas = base64_data.decode('utf-8')
|
||||||
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
# model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||||
report_path = attachment._full_path(attachment.store_fname)
|
# report_path = attachment._full_path(attachment.store_fname)
|
||||||
vals['model_file'] = self.transition_glb_file(report_path, model_code)
|
vals['model_file'] = self.model_analyze(attachment)
|
||||||
# logging.info('create-model_file:%s' % len(vals['model_file']))
|
# logging.info('create-model_file:%s' % len(vals['model_file']))
|
||||||
|
|
||||||
obj = super(QuickEasyOrder, self).create(vals)
|
obj = super(QuickEasyOrder, self).create(vals)
|
||||||
@@ -91,6 +93,147 @@ class QuickEasyOrder(models.Model):
|
|||||||
obj.state = '待接单'
|
obj.state = '待接单'
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
def model_analyze(self,model_attachment):
|
||||||
|
"""
|
||||||
|
step模型解析,上传模型时转为web可显示的格式
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
config = request.env['res.config.settings'].sudo().get_values()
|
||||||
|
try:
|
||||||
|
# 获取当前操作系统
|
||||||
|
os_name = platform.system()
|
||||||
|
for item in model_attachment:
|
||||||
|
# 将拿到的3D模型数据存入文件
|
||||||
|
# 定义文件名和文件的二进制内容
|
||||||
|
file_name = item.name # 请将这里替换为你的文件名
|
||||||
|
print('file_name', file_name)
|
||||||
|
# base64_data = base64.b64encode(item.datas)
|
||||||
|
# base64_datas = base64_data.decode('utf-8')
|
||||||
|
binary_content = item.datas # 请将这里替换为你的文件的二进制内容
|
||||||
|
# binary_content从字符串转为二进制
|
||||||
|
binary_content = base64.b64decode(binary_content)
|
||||||
|
# 定义新的文件夹路径
|
||||||
|
# 根据操作系统不同,文件路径不同
|
||||||
|
path_header = '/model_parser' if os_name == 'Linux' else 'D:/model_analysis'
|
||||||
|
# new_folder_path = 'D:/11111final' + '/' + item['name'].split(".")[0]
|
||||||
|
new_folder_path = path_header + '/' + item.name.rpartition('.')[0]
|
||||||
|
print('new_folder_path', new_folder_path)
|
||||||
|
# 检查新的文件夹是否存在,如果不存在,则创建
|
||||||
|
if not os.path.exists(new_folder_path):
|
||||||
|
os.makedirs(new_folder_path)
|
||||||
|
# 定义新的文件路径
|
||||||
|
new_file_path = os.path.join(new_folder_path, file_name)
|
||||||
|
# 将二进制内容写入新的文件
|
||||||
|
with open(new_file_path, 'wb') as f:
|
||||||
|
f.write(binary_content)
|
||||||
|
# 检查文件是否已经成功写入
|
||||||
|
if os.path.exists(new_file_path):
|
||||||
|
print(f'Successfully wrote binary content to {new_file_path}')
|
||||||
|
else:
|
||||||
|
print(f'Failed to write binary content to {new_file_path}')
|
||||||
|
# 附件
|
||||||
|
# attachment = request.env['ir.attachment'].sudo().create({
|
||||||
|
# 'datas': item['data'].encode('utf-8'),
|
||||||
|
# 'type': 'binary',
|
||||||
|
# 'description': '模型文件',
|
||||||
|
# 'name': item['name'],
|
||||||
|
# 'public': True,
|
||||||
|
# 'model_name': item['name'],
|
||||||
|
# })
|
||||||
|
headers = {'Content-Type': 'application/json'}
|
||||||
|
# 调用写入宿主机接口
|
||||||
|
# url_dir = 'http://192.168.50.202:8000/create_and_write_file'
|
||||||
|
url_dir = config['model_parser_url'] + '/create_and_write_file'
|
||||||
|
data = {
|
||||||
|
'folder_path': new_folder_path, # 您想要创建的文件夹路径
|
||||||
|
'file_path': new_file_path, # 您想要创建的文件名
|
||||||
|
'content': item['data'] # 您想要写入文件的内容
|
||||||
|
}
|
||||||
|
requests.post(url_dir, json=data, headers=headers)
|
||||||
|
# 调用特征包接口
|
||||||
|
url = config['model_parser_url'] + '/process_file'
|
||||||
|
payload = {
|
||||||
|
'file_path': new_file_path,
|
||||||
|
'dest_path': new_folder_path,
|
||||||
|
'back_url': config['bfm_url']
|
||||||
|
}
|
||||||
|
response = requests.post(url, json=payload, headers=headers)
|
||||||
|
if response.status_code == 200:
|
||||||
|
print("Request was successful.")
|
||||||
|
print("Response: ", response.json())
|
||||||
|
else:
|
||||||
|
print("Request failed.")
|
||||||
|
# 特征识别
|
||||||
|
xml_path = new_folder_path + '/' + item.name.rpartition('.')[0] + '_FeatrueTable.XML'
|
||||||
|
print('xml_path', xml_path)
|
||||||
|
parser_obj = pc.FeatureParser(xml_path)
|
||||||
|
print('parser_obj', parser_obj)
|
||||||
|
slot = parser_obj.slots
|
||||||
|
print('slot', slot)
|
||||||
|
hole = parser_obj.holes
|
||||||
|
print('hole', hole)
|
||||||
|
size = parser_obj.size
|
||||||
|
print('size', size)
|
||||||
|
open_slot = parser_obj.open_slots
|
||||||
|
print('open_slot', open_slot)
|
||||||
|
vector = parser_obj.vectors
|
||||||
|
print('vector', vector)
|
||||||
|
print('all parcer', size)
|
||||||
|
try:
|
||||||
|
hole_time = pc.hole_time(parser_obj)
|
||||||
|
print('hole_time', hole_time)
|
||||||
|
except Exception as e:
|
||||||
|
return json.dumps({'code': 400, 'msg': '孔尺寸超限', 'error_msg': str(e)})
|
||||||
|
try:
|
||||||
|
slot_time = pc.slot_time(parser_obj)
|
||||||
|
print('slot_time', slot_time)
|
||||||
|
except Exception as e:
|
||||||
|
return json.dumps({'code': 400, 'msg': '槽尺寸超限', 'error_msg': str(e)})
|
||||||
|
try:
|
||||||
|
open_slot_time = pc.open_slot_time(parser_obj)
|
||||||
|
print('open_slot_time', open_slot_time)
|
||||||
|
except Exception as e:
|
||||||
|
return json.dumps({'code': 400, 'msg': '开口槽尺寸超限', 'error_msg': str(e)})
|
||||||
|
total_time = hole_time + slot_time + open_slot_time
|
||||||
|
print(hole_time, slot_time, open_slot_time)
|
||||||
|
print('total_time', total_time)
|
||||||
|
ret = {'feature_infos': [{'name': 'all_feature', 'type': '铣', 'process_time': total_time}],
|
||||||
|
'boxshape': size, 'slugX': 10.0, 'slugY': 90.0, 'slugZ': 42.0,
|
||||||
|
'turn_over_times': 2,
|
||||||
|
'target_faces': ['A', 'B']}
|
||||||
|
self.model_feature = json.dumps(ret['feature_infos'], ensure_ascii=False)
|
||||||
|
self.model_length = size['length'] # 长 单位mm
|
||||||
|
self.model_width = size['width'] # 宽
|
||||||
|
self.model_height = size['height'] # 高
|
||||||
|
self.model_volume = size['length'] * size['width'] * size['height']
|
||||||
|
# 附件处理
|
||||||
|
base64_data = base64.b64encode(item.datas)
|
||||||
|
base64_datas = base64_data.decode('utf-8')
|
||||||
|
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||||
|
# 读取文件
|
||||||
|
shapes = read_step_file(new_file_path)
|
||||||
|
output_file = os.path.join(new_folder_path, str(model_code) + '.stl')
|
||||||
|
write_stl_file(shapes, output_file, 'binary', 0.03, 0.5)
|
||||||
|
# 转化为glb
|
||||||
|
output_glb_file = os.path.join(new_folder_path, str(model_code) + '.glb')
|
||||||
|
util_path = get_resource_path('jikimo_gateway_api', 'static/util')
|
||||||
|
# 根据操作系统确定使用 'python' 还是 'python3'
|
||||||
|
python_cmd = 'python3' if os_name == 'Linux' else 'python'
|
||||||
|
print('python_cmd', python_cmd)
|
||||||
|
print('os_name', os_name)
|
||||||
|
# 使用引号包围路径
|
||||||
|
cmd = '%s "%s/stl2gltf.py" "%s" "%s" -b' % (python_cmd, util_path, output_file, output_glb_file)
|
||||||
|
logging.info(cmd)
|
||||||
|
os.system(cmd)
|
||||||
|
# 转base64
|
||||||
|
with open(output_glb_file, 'rb') as fileObj:
|
||||||
|
image_data = fileObj.read()
|
||||||
|
base64_data = base64.b64encode(image_data)
|
||||||
|
return base64_data
|
||||||
|
except Exception as e:
|
||||||
|
return UserError('模型自动报价失败,请联系管理员')
|
||||||
|
|
||||||
# 将attach的datas内容转为glb文件
|
# 将attach的datas内容转为glb文件
|
||||||
def transition_glb_file(self, report_path, model_code):
|
def transition_glb_file(self, report_path, model_code):
|
||||||
shapes = read_step_file(report_path)
|
shapes = read_step_file(report_path)
|
||||||
@@ -116,24 +259,7 @@ class QuickEasyOrder(models.Model):
|
|||||||
raise ValidationError('只允许上传一个文件')
|
raise ValidationError('只允许上传一个文件')
|
||||||
if item.upload_model_file:
|
if item.upload_model_file:
|
||||||
file_attachment_id = item.upload_model_file[0]
|
file_attachment_id = item.upload_model_file[0]
|
||||||
# 附件路径
|
item.model_file = self.model_analyze(file_attachment_id)
|
||||||
report_path = file_attachment_id._full_path(file_attachment_id.store_fname)
|
|
||||||
logging.info("模型路径: %s" % report_path)
|
|
||||||
base64_data = base64.b64encode(file_attachment_id.datas)
|
|
||||||
base64_datas = base64_data.decode('utf-8')
|
|
||||||
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
|
||||||
logging.info("模型编码: %s" % model_code)
|
|
||||||
item.model_file = self.transition_glb_file(report_path, model_code)
|
|
||||||
ret = self.feature_recognition(report_path, model_code)
|
|
||||||
logging.info("自动报价返回值: %s" % ret)
|
|
||||||
boxshape = ret['boxshape'].tolist()
|
|
||||||
logging.info("自动报价boxshape: %s" % boxshape)
|
|
||||||
logging.info('自动报价feature_infos:%s' % ret['feature_infos'])
|
|
||||||
item.model_length = boxshape[0] # 长 单位mm
|
|
||||||
item.model_width = boxshape[1] # 宽
|
|
||||||
item.model_height = boxshape[2] # 高
|
|
||||||
item.model_volume = boxshape[0] * boxshape[1] * boxshape[2]
|
|
||||||
item.model_feature = json.dumps(ret['feature_infos'], ensure_ascii=False)
|
|
||||||
self._get_price(item)
|
self._get_price(item)
|
||||||
else:
|
else:
|
||||||
item.model_file = False
|
item.model_file = False
|
||||||
|
|||||||
@@ -1,5 +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,1
|
access_quick_easy_order,quick_easy_order,model_quick_easy_order,base.group_system,1,1,1,0
|
||||||
|
access_quick_easy_order_group_sale_salemanager,quick_easy_order_group_sale_salemanager,model_quick_easy_order,sf_base.group_sale_salemanager,1,1,1,0
|
||||||
|
access_quick_easy_order_group_sale_director,quick_easy_order_group_sale_director,model_quick_easy_order,sf_base.group_sale_director,1,1,1,0
|
||||||
access_sf_auto_quatotion_common,sf_auto_quatotion_common,model_sf_auto_quatotion_common,base.group_system,1,1,1,1
|
access_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
|
||||||
|
|||||||
|
Reference in New Issue
Block a user