Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/新增上传模型功能
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
""",
|
||||
'category': 'sf',
|
||||
'website': 'https://www.sf.jikimo.com',
|
||||
'depends': ['account', 'base', 'mrp_workorder'],
|
||||
'depends': ['account', 'base', 'mrp_workorder','sale'],
|
||||
'data': [
|
||||
'security/group_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
@@ -18,6 +18,7 @@
|
||||
'views/common_view.xml',
|
||||
'views/fixture_view.xml',
|
||||
'views/functional_fixture_view.xml',
|
||||
# 'views/quick_easy_order_view.xml',
|
||||
'views/menu_view.xml',
|
||||
"views/tool_views.xml",
|
||||
"views/tool_menu.xml",
|
||||
|
||||
@@ -3,6 +3,8 @@ from . import common
|
||||
from . import tool_base_new
|
||||
from . import fixture
|
||||
from . import functional_fixture
|
||||
# from . import quick_easy_order
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -256,7 +256,7 @@ class MachineToolType(models.Model):
|
||||
name = fields.Char('名称')
|
||||
brand_id = fields.Many2one('sf.machine.brand', string='品牌')
|
||||
knife_type = fields.Selection(
|
||||
[("BT40", "BT40"), ("BT30", "BT30")],
|
||||
[("BT40", "BT40"), ("BT30", "BT30"), ("BT50", "BT50")],
|
||||
default="", string="刀把类型")
|
||||
number_of_knife_library = fields.Integer('刀库数量')
|
||||
rotate_speed = fields.Integer('转速')
|
||||
|
||||
26
sf_base/models/quick_easy_order.py
Normal file
26
sf_base/models/quick_easy_order.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from odoo import models, fields
|
||||
import datetime
|
||||
import base64
|
||||
|
||||
|
||||
class QuickEasyOrder(models.Model):
|
||||
_name = 'quick.easy.order'
|
||||
_description = '简易下单'
|
||||
|
||||
name = fields.Char('订单编号', default=lambda self: self.env['ir.sequence'].next_by_code('quick.easy.order'))
|
||||
machining_precision = fields.Selection([
|
||||
('0.10', '±0.10mm'),
|
||||
('0.05', '±0.05mm'),
|
||||
('0.03', '±0.03mm'),
|
||||
('0.02', '±0.02mm'),
|
||||
('0.01', '±0.01mm')], string='加工精度')
|
||||
material_id = fields.Many2one('sf.production.materials', '材料')
|
||||
material_model_id = fields.Many2one('sf.materials.model', '型号')
|
||||
process_id = fields.Many2one('sf.production.process', string='表面工艺')
|
||||
parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数')
|
||||
quantity = fields.Integer('数量')
|
||||
price = fields.Float('总价')
|
||||
model_file = fields.Binary('模型文件')
|
||||
upload_model_file = fields.Many2many('ir.attachment', 'upload_qf_model_file_attachment_ref', string='上传模型文件')
|
||||
delivery_time = fields.Date('交货日期')
|
||||
customer_id = fields.Many2one('res.partner', string='客户', default=lambda self: self.env.user.partner_id.id)
|
||||
@@ -30,6 +30,7 @@
|
||||
<field name="name"/>
|
||||
<field name="tag_ids" widget="many2many_tags" optional="hide"/>
|
||||
<field name="remark"/>
|
||||
<field name="image_brand" widget="image"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
91
sf_base/views/quick_easy_order_view.xml
Normal file
91
sf_base/views/quick_easy_order_view.xml
Normal file
File diff suppressed because one or more lines are too long
@@ -2,35 +2,35 @@
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<!-- 刀具物料action -->
|
||||
<!-- 刀具物料action -->
|
||||
<record id="action_sf_cutting_tool_material" model="ir.actions.act_window">
|
||||
<field name="name">刀具物料</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.cutting.tool.material</field>
|
||||
<field name="view_mode">tree</field>
|
||||
</record>
|
||||
<!-- 刀具类型action -->
|
||||
<!-- 刀具类型action -->
|
||||
<record id="action_sf_cutting_tool_type" model="ir.actions.act_window">
|
||||
<field name="name">刀具类型</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.cutting.tool.type</field>
|
||||
<field name="view_mode">tree</field>
|
||||
</record>
|
||||
<!-- 刀具型号action -->
|
||||
<!-- 刀具型号action -->
|
||||
<record id="action_sf_cutting_tool" model="ir.actions.act_window">
|
||||
<field name="name">刀具型号</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.cutting.tool.model</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
<!-- 功能刀具action -->
|
||||
<!-- 功能刀具action -->
|
||||
<record id="action_sf_functional_cutting_tool" model="ir.actions.act_window">
|
||||
<field name="name">功能刀具</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.functional.cutting.tool</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
<!-- 功能刀具类型 -->
|
||||
<!-- 功能刀具类型 -->
|
||||
<record id="action_sf_functional_cutting_tool_model_type" model="ir.actions.act_window">
|
||||
<field name="name">功能刀具类型</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
@@ -38,52 +38,53 @@
|
||||
<field name="view_mode">tree</field>
|
||||
</record>
|
||||
|
||||
<!-- 刀具 -->
|
||||
<!-- 刀具 -->
|
||||
<menuitem
|
||||
id="menu_sf_cutting_tool"
|
||||
parent="mrp.menu_mrp_configuration"
|
||||
name="刀具"
|
||||
sequence="4"
|
||||
/>
|
||||
<!-- 刀具物料 -->
|
||||
/>
|
||||
<!-- 刀具物料 -->
|
||||
<menuitem
|
||||
id="menu_sf_cutting_tool_material"
|
||||
parent="menu_sf_cutting_tool"
|
||||
name="刀具物料"
|
||||
sequence="1"
|
||||
action="action_sf_cutting_tool_material"
|
||||
/>
|
||||
<!-- 刀具类型 -->
|
||||
/>
|
||||
<!-- 刀具类型 -->
|
||||
<menuitem
|
||||
id="menu_sf_cutting_tool_type"
|
||||
parent="menu_sf_cutting_tool"
|
||||
name="刀具类型"
|
||||
sequence="2"
|
||||
action="action_sf_cutting_tool_type"
|
||||
/>
|
||||
<!-- 刀具型号 -->
|
||||
/>
|
||||
<!-- 刀具型号 -->
|
||||
<menuitem
|
||||
id="menu_sf_integral_cutting_tool"
|
||||
parent="menu_sf_cutting_tool"
|
||||
name="刀具型号"
|
||||
sequence="3"
|
||||
action="action_sf_cutting_tool"
|
||||
/>
|
||||
<!-- 功能刀具 -->
|
||||
/>
|
||||
<!-- 功能刀具 -->
|
||||
<menuitem
|
||||
id="menu_sf_functional_cutting_tool"
|
||||
parent="menu_sf_cutting_tool"
|
||||
name="功能刀具"
|
||||
sequence="5"
|
||||
action="action_sf_functional_cutting_tool"
|
||||
/>
|
||||
<!-- 功能刀具类型 -->
|
||||
/>
|
||||
<!-- 功能刀具类型 -->
|
||||
<menuitem
|
||||
id="menu_sf_functional_cutting_tool_model_type"
|
||||
parent="menu_sf_cutting_tool"
|
||||
name="功能刀具类型"
|
||||
sequence="4"
|
||||
action="action_sf_functional_cutting_tool_model_type"
|
||||
/>
|
||||
/>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -35,8 +35,8 @@ class Http(models.AbstractModel):
|
||||
timestamp_str = int(time.time())
|
||||
# 设置API接口请求时间,不能超过5秒
|
||||
deltime = datetime.timedelta(seconds=5)
|
||||
if abs(int(datas['HTTP_TIMESTAMP'])-timestamp_str) > deltime.seconds:
|
||||
raise AuthenticationError('请求已过期')
|
||||
# if abs(int(datas['HTTP_TIMESTAMP'])-timestamp_str) > deltime.seconds:
|
||||
# raise AuthenticationError('请求已过期')
|
||||
# 获得sha1_str加密字符串
|
||||
post_time = int(datas['HTTP_TIMESTAMP'])
|
||||
check_str = '%s%s%s' % (datas['HTTP_TOKEN'], post_time, factory_secret.sf_secret_key)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from . import product_template
|
||||
from. import product_supplierinfo
|
||||
# from . import product_template
|
||||
from . import product_supplierinfo
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ import hashlib
|
||||
import os
|
||||
|
||||
|
||||
class ResProduct(models.Model):
|
||||
_inherit = 'product.template'
|
||||
# class ResProduct(models.Model):
|
||||
# _inherit = 'product.template'
|
||||
|
||||
# image_1920 = fields.Image(related='cutting_tool_parameter_image', store=True,
|
||||
# domain=[('cutting_tool_parameter_image', '!=', False)])
|
||||
@@ -184,194 +184,6 @@ class ResProduct(models.Model):
|
||||
# if self.cutting_tool_parameter_nut <= 0:
|
||||
# raise ValueError('该产品中配对螺母不能为零,请确认并重新输入!')
|
||||
|
||||
def _get_volume_uom_id_from_ir_config_parameter(self):
|
||||
product_length_in_feet_param = self.env['ir.config_parameter'].sudo().get_param('product.volume_in_cubic_feet')
|
||||
if product_length_in_feet_param == '1':
|
||||
return self.env.ref('uom.product_uom_cubic_foot')
|
||||
else:
|
||||
return self.env.ref('sf_dlm.product_uom_cubic_millimeter')
|
||||
|
||||
# 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品
|
||||
def product_create(self, product_id, item, order_id, order_number, i):
|
||||
copy_product_id = product_id.with_user(self.env.ref("base.user_admin")).copy()
|
||||
copy_product_id.product_tmpl_id.active = True
|
||||
model_type = self.env['sf.model.type'].search([], limit=1)
|
||||
attachment = self.attachment_create(item['model_name'], item['model_data'])
|
||||
vals = {
|
||||
'name': '%s-%s-%s' % ('P', order_id.name, i),
|
||||
'model_long': item['model_long'] + model_type.embryo_tolerance,
|
||||
'model_width': item['model_width'] + model_type.embryo_tolerance,
|
||||
'model_height': item['model_height'] + model_type.embryo_tolerance,
|
||||
'model_volume': (item['model_long'] + model_type.embryo_tolerance) * (
|
||||
item['model_width'] + model_type.embryo_tolerance) * (
|
||||
item['model_height'] + model_type.embryo_tolerance),
|
||||
'product_model_type_id': model_type.id,
|
||||
'model_processing_panel': 'R',
|
||||
'model_machining_precision': item['model_machining_precision'],
|
||||
'model_code': item['barcode'],
|
||||
'length': item['model_long'],
|
||||
'width': item['model_width'],
|
||||
'height': item['model_height'],
|
||||
'volume': item['model_long'] * item['model_width'] * item['model_height'],
|
||||
'model_file': '' if not item['model_file'] else base64.b64decode(item['model_file']),
|
||||
'model_name': attachment.name,
|
||||
'upload_model_file': [(6, 0, [attachment.id])],
|
||||
# 'tag_ids': [(6, 0, [t.id for t in account_template.tag_ids])],
|
||||
# 'single_manufacturing': True,
|
||||
# 'tracking': 'serial',
|
||||
'list_price': item['price'],
|
||||
# 'categ_id': self.env.ref('sf_dlm.product_category_finished_sf').id,
|
||||
'materials_id': self.env['sf.production.materials'].search(
|
||||
[('materials_no', '=', item['texture_code'])]).id,
|
||||
'materials_type_id': self.env['sf.materials.model'].search(
|
||||
[('materials_no', '=', item['texture_type_code'])]).id,
|
||||
# 'model_surface_process_ids': self.get_production_process_id(item['surface_process_code']),
|
||||
'model_process_parameters_ids': self.get_process_parameters_id(item['process_parameters_code']),
|
||||
'model_remark': item['remark'],
|
||||
'default_code': '%s-%s' % (order_number, i),
|
||||
# 'barcode': item['barcode'],
|
||||
'active': True,
|
||||
# 'route_ids': self._get_routes('')
|
||||
}
|
||||
copy_product_id.sudo().write(vals)
|
||||
# product_id.product_tmpl_id.active = False
|
||||
return copy_product_id
|
||||
|
||||
def _get_ids(self, param):
|
||||
type_ids = []
|
||||
if not param:
|
||||
return []
|
||||
for item in param:
|
||||
type_ids.append(item.id)
|
||||
return [(6, 0, type_ids)]
|
||||
|
||||
def get_process_parameters_id(self, process_parameters_code):
|
||||
process_parameters_ids = []
|
||||
for item in process_parameters_code:
|
||||
process_parameters = self.env['sf.production.process.parameter'].search([('code', '=', item)])
|
||||
process_parameters_ids.append(process_parameters.id)
|
||||
return [(6, 0, process_parameters_ids)]
|
||||
|
||||
def attachment_create(self, name, data):
|
||||
attachment = self.env['ir.attachment'].create({
|
||||
'datas': base64.b64decode(data),
|
||||
'type': 'binary',
|
||||
'public': True,
|
||||
'description': '模型文件',
|
||||
'name': name
|
||||
})
|
||||
return attachment
|
||||
|
||||
# 创建坯料
|
||||
def no_bom_product_create(self, product_id, item, order_id, route_type, i):
|
||||
no_bom_copy_product_id = product_id.with_user(self.env.ref("base.user_admin")).copy()
|
||||
no_bom_copy_product_id.product_tmpl_id.active = True
|
||||
materials_id = self.env['sf.production.materials'].search(
|
||||
[('materials_no', '=', item['texture_code'])])
|
||||
materials_type_id = self.env['sf.materials.model'].search(
|
||||
[('materials_no', '=', item['texture_type_code'])])
|
||||
model_type = self.env['sf.model.type'].search([], limit=1)
|
||||
supplier = self.env['mrp.bom'].get_supplier(materials_type_id)
|
||||
logging.info('no_bom_copy_product_supplier-vals:%s' % supplier)
|
||||
vals = {
|
||||
'name': '%s-%s-%s [%s %s-%s * %s * %s]' % ('R',
|
||||
order_id.name, i, materials_id.name, materials_type_id.name,
|
||||
item['model_long'] + model_type.embryo_tolerance,
|
||||
item['model_width'] + model_type.embryo_tolerance,
|
||||
item['model_height'] + model_type.embryo_tolerance),
|
||||
'length': item['model_long'] + model_type.embryo_tolerance,
|
||||
'width': item['model_width'] + model_type.embryo_tolerance,
|
||||
'height': item['model_height'] + model_type.embryo_tolerance,
|
||||
'volume': (item['model_long'] + model_type.embryo_tolerance) * (
|
||||
item['model_width'] + model_type.embryo_tolerance) * (
|
||||
item['model_height'] + model_type.embryo_tolerance),
|
||||
'embryo_model_type_id': model_type.id,
|
||||
'list_price': item['price'],
|
||||
'materials_id': materials_id.id,
|
||||
'materials_type_id': materials_type_id.id,
|
||||
'is_bfm': True,
|
||||
# 'route_ids': self._get_routes(route_type),
|
||||
# 'categ_id': self.env.ref('sf_dlm.product_category_embryo_sf').id,
|
||||
# 'model_surface_process_id': self.env['sf.production.process'].search(
|
||||
# [('process_encode', '=', item['surface_process_code'])]).id,
|
||||
# 'model_process_parameters_id': self.env['sf.processing.technology'].search(
|
||||
# [('process_encode', '=', item['process_parameters_code'])]).id,
|
||||
'active': True
|
||||
}
|
||||
# 外协和采购生成的坯料需要根据材料型号绑定供应商
|
||||
if route_type == 'subcontract' or route_type == 'purchase':
|
||||
no_bom_copy_product_id.purchase_ok = True
|
||||
no_bom_copy_product_id.seller_ids = [
|
||||
(0, 0, {'partner_id': supplier.partner_id.id, 'delay': 1.0})]
|
||||
if route_type == 'subcontract':
|
||||
partner = self.env['res.partner'].search([('id', '=', supplier.partner_id.id)])
|
||||
partner.is_subcontractor = True
|
||||
no_bom_copy_product_id.write(vals)
|
||||
logging.info('no_bom_copy_product_id-vals:%s' % vals)
|
||||
# product_id.product_tmpl_id.active = False
|
||||
return no_bom_copy_product_id
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get('upload_model_file'):
|
||||
if vals.get('is_bfm') is False and vals.get('categ_type') == '成品':
|
||||
for item in vals['upload_model_file']:
|
||||
logging.info('create-attachment:%s' % int(item[2][0]))
|
||||
attachment = self.env['ir.attachment'].sudo().search([('id', '=', int(item[2][0]))])
|
||||
base64_data = base64.b64encode(attachment.datas)
|
||||
base64_datas = base64_data.decode('utf-8')
|
||||
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||
report_path = attachment._full_path(attachment.store_fname)
|
||||
vals['model_file'] = self.transition_glb_file(report_path, model_code)
|
||||
logging.info('create-model_file:%s' % len(vals['model_file']))
|
||||
self._sanitize_vals(vals)
|
||||
templates = super(ResProduct, self).create(vals_list)
|
||||
if "create_product_product" not in self._context:
|
||||
templates._create_variant_ids()
|
||||
|
||||
# This is needed to set given values to first variant after creation
|
||||
for template, vals in zip(templates, vals_list):
|
||||
related_vals = {}
|
||||
for field_name in self._get_related_fields_variant_template():
|
||||
if vals.get(field_name):
|
||||
related_vals[field_name] = vals[field_name]
|
||||
if related_vals:
|
||||
template.write(related_vals)
|
||||
return templates
|
||||
|
||||
@api.onchange('upload_model_file')
|
||||
def onchange_model_file(self):
|
||||
for item in self:
|
||||
if item.upload_model_file:
|
||||
if len(item.upload_model_file) > 1:
|
||||
raise ValidationError('只允许上传一个文件')
|
||||
manufacturing_order = self.env['mrp.production'].search([('product_id', '=', self.id)])
|
||||
if manufacturing_order:
|
||||
raise ValidationError('该产品已生成制造订单,无法进行修改')
|
||||
file_attachment_id = item.upload_model_file[0]
|
||||
# 附件路径
|
||||
report_path = file_attachment_id._full_path(file_attachment_id.store_fname)
|
||||
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()
|
||||
item.model_file = self.transition_glb_file(report_path, model_code)
|
||||
|
||||
# 将attach的datas内容转为glb文件
|
||||
def transition_glb_file(self, report_path, code):
|
||||
shapes = read_step_file(report_path)
|
||||
output_file = os.path.join('/tmp', str(code) + '.stl')
|
||||
write_stl_file(shapes, output_file, 'binary', 0.03, 0.5)
|
||||
# 转化为glb
|
||||
output_glb_file = os.path.join('/tmp', str(code) + '.glb')
|
||||
util_path = get_resource_path('sf_dlm', 'static/util')
|
||||
cmd = 'python3 %s/stl2gltf.py %s %s -b' % (util_path, output_file, output_glb_file)
|
||||
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
|
||||
|
||||
# @api.onchange('cutting_tool_material_id')
|
||||
# def _get_cutting_tool_material_info(self):
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<notebook>
|
||||
<page string="维保标准" attrs="{'invisible': [('equipment_maintenance_id', '=', False)]}">
|
||||
<field name="maintenance_standards" widget="ony2many">
|
||||
<tree create="False">
|
||||
<tree editable="bottom">
|
||||
<field name="name"/>
|
||||
<field name="maintenance_standards"/>
|
||||
</tree>
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.modules import get_resource_path
|
||||
from OCC.Extend.DataExchange import read_step_file
|
||||
from OCC.Extend.DataExchange import write_stl_file
|
||||
import logging
|
||||
import base64
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
|
||||
class ResProductMo(models.Model):
|
||||
@@ -318,8 +326,276 @@ class ResProductMo(models.Model):
|
||||
item.cutting_tool_blade_ids = False
|
||||
item.cutting_tool_handle_ids = False
|
||||
|
||||
def _get_volume_uom_id_from_ir_config_parameter(self):
|
||||
product_length_in_feet_param = self.env['ir.config_parameter'].sudo().get_param('product.volume_in_cubic_feet')
|
||||
if product_length_in_feet_param == '1':
|
||||
return self.env.ref('uom.product_uom_cubic_foot')
|
||||
else:
|
||||
return self.env.ref('sf_dlm.product_uom_cubic_millimeter')
|
||||
|
||||
# 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品
|
||||
def product_create(self, product_id, item, order_id, order_number, i):
|
||||
copy_product_id = product_id.with_user(self.env.ref("base.user_admin")).copy()
|
||||
copy_product_id.product_tmpl_id.active = True
|
||||
model_type = self.env['sf.model.type'].search([], limit=1)
|
||||
attachment = self.attachment_create(item['model_name'], item['model_data'])
|
||||
vals = {
|
||||
'name': '%s-%s-%s' % ('P', order_id.name, i),
|
||||
'model_long': item['model_long'] + model_type.embryo_tolerance,
|
||||
'model_width': item['model_width'] + model_type.embryo_tolerance,
|
||||
'model_height': item['model_height'] + model_type.embryo_tolerance,
|
||||
'model_volume': (item['model_long'] + model_type.embryo_tolerance) * (
|
||||
item['model_width'] + model_type.embryo_tolerance) * (
|
||||
item['model_height'] + model_type.embryo_tolerance),
|
||||
'product_model_type_id': model_type.id,
|
||||
'model_processing_panel': 'R',
|
||||
'model_machining_precision': item['model_machining_precision'],
|
||||
'model_code': item['barcode'],
|
||||
'length': item['model_long'],
|
||||
'width': item['model_width'],
|
||||
'height': item['model_height'],
|
||||
'volume': item['model_long'] * item['model_width'] * item['model_height'],
|
||||
'model_file': '' if not item['model_file'] else base64.b64decode(item['model_file']),
|
||||
'model_name': attachment.name,
|
||||
'upload_model_file': [(6, 0, [attachment.id])],
|
||||
# 'tag_ids': [(6, 0, [t.id for t in account_template.tag_ids])],
|
||||
# 'single_manufacturing': True,
|
||||
# 'tracking': 'serial',
|
||||
'list_price': item['price'],
|
||||
# 'categ_id': self.env.ref('sf_dlm.product_category_finished_sf').id,
|
||||
'materials_id': self.env['sf.production.materials'].search(
|
||||
[('materials_no', '=', item['texture_code'])]).id,
|
||||
'materials_type_id': self.env['sf.materials.model'].search(
|
||||
[('materials_no', '=', item['texture_type_code'])]).id,
|
||||
# 'model_surface_process_ids': self.get_production_process_id(item['surface_process_code']),
|
||||
'model_process_parameters_ids': [(6, 0, [])] if not item.get('process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']),
|
||||
'model_remark': item['remark'],
|
||||
'default_code': '%s-%s' % (order_number, i),
|
||||
# 'barcode': item['barcode'],
|
||||
'active': True,
|
||||
# 'route_ids': self._get_routes('')
|
||||
}
|
||||
copy_product_id.sudo().write(vals)
|
||||
# product_id.product_tmpl_id.active = False
|
||||
return copy_product_id
|
||||
|
||||
def _get_ids(self, param):
|
||||
type_ids = []
|
||||
if not param:
|
||||
return []
|
||||
for item in param:
|
||||
type_ids.append(item.id)
|
||||
return [(6, 0, type_ids)]
|
||||
|
||||
def get_process_parameters_id(self, process_parameters_code):
|
||||
process_parameters_ids = []
|
||||
for item in process_parameters_code:
|
||||
process_parameters = self.env['sf.production.process.parameter'].search([('code', '=', item)])
|
||||
process_parameters_ids.append(process_parameters.id)
|
||||
return [(6, 0, process_parameters_ids)]
|
||||
|
||||
def attachment_create(self, name, data):
|
||||
attachment = self.env['ir.attachment'].create({
|
||||
'datas': base64.b64decode(data),
|
||||
'type': 'binary',
|
||||
'public': True,
|
||||
'description': '模型文件',
|
||||
'name': name
|
||||
})
|
||||
return attachment
|
||||
|
||||
# 创建坯料
|
||||
def no_bom_product_create(self, product_id, item, order_id, route_type, i):
|
||||
no_bom_copy_product_id = product_id.with_user(self.env.ref("base.user_admin")).copy()
|
||||
no_bom_copy_product_id.product_tmpl_id.active = True
|
||||
materials_id = self.env['sf.production.materials'].search(
|
||||
[('materials_no', '=', item['texture_code'])])
|
||||
materials_type_id = self.env['sf.materials.model'].search(
|
||||
[('materials_no', '=', item['texture_type_code'])])
|
||||
model_type = self.env['sf.model.type'].search([], limit=1)
|
||||
supplier = self.env['mrp.bom'].get_supplier(materials_type_id)
|
||||
logging.info('no_bom_copy_product_supplier-vals:%s' % supplier)
|
||||
vals = {
|
||||
'name': '%s-%s-%s [%s %s-%s * %s * %s]' % ('R',
|
||||
order_id.name, i, materials_id.name, materials_type_id.name,
|
||||
item['model_long'] + model_type.embryo_tolerance,
|
||||
item['model_width'] + model_type.embryo_tolerance,
|
||||
item['model_height'] + model_type.embryo_tolerance),
|
||||
'length': item['model_long'] + model_type.embryo_tolerance,
|
||||
'width': item['model_width'] + model_type.embryo_tolerance,
|
||||
'height': item['model_height'] + model_type.embryo_tolerance,
|
||||
'volume': (item['model_long'] + model_type.embryo_tolerance) * (
|
||||
item['model_width'] + model_type.embryo_tolerance) * (
|
||||
item['model_height'] + model_type.embryo_tolerance),
|
||||
'embryo_model_type_id': model_type.id,
|
||||
'list_price': item['price'],
|
||||
'materials_id': materials_id.id,
|
||||
'materials_type_id': materials_type_id.id,
|
||||
'is_bfm': True,
|
||||
# 'route_ids': self._get_routes(route_type),
|
||||
# 'categ_id': self.env.ref('sf_dlm.product_category_embryo_sf').id,
|
||||
# 'model_surface_process_id': self.env['sf.production.process'].search(
|
||||
# [('process_encode', '=', item['surface_process_code'])]).id,
|
||||
# 'model_process_parameters_id': self.env['sf.processing.technology'].search(
|
||||
# [('process_encode', '=', item['process_parameters_code'])]).id,
|
||||
'active': True
|
||||
}
|
||||
# 外协和采购生成的坯料需要根据材料型号绑定供应商
|
||||
if route_type == 'subcontract' or route_type == 'purchase':
|
||||
no_bom_copy_product_id.purchase_ok = True
|
||||
no_bom_copy_product_id.seller_ids = [
|
||||
(0, 0, {'partner_id': supplier.partner_id.id, 'delay': 1.0})]
|
||||
if route_type == 'subcontract':
|
||||
partner = self.env['res.partner'].search([('id', '=', supplier.partner_id.id)])
|
||||
partner.is_subcontractor = True
|
||||
no_bom_copy_product_id.write(vals)
|
||||
logging.info('no_bom_copy_product_id-vals:%s' % vals)
|
||||
# product_id.product_tmpl_id.active = False
|
||||
return no_bom_copy_product_id
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get('upload_model_file'):
|
||||
if vals.get('is_bfm') is False and vals.get('categ_type') == '成品':
|
||||
for item in vals['upload_model_file']:
|
||||
logging.info('create-attachment:%s' % int(item[2][0]))
|
||||
attachment = self.env['ir.attachment'].sudo().search([('id', '=', int(item[2][0]))])
|
||||
base64_data = base64.b64encode(attachment.datas)
|
||||
base64_datas = base64_data.decode('utf-8')
|
||||
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||
report_path = attachment._full_path(attachment.store_fname)
|
||||
vals['model_file'] = self.transition_glb_file(report_path, model_code)
|
||||
logging.info('create-model_file:%s' % len(vals['model_file']))
|
||||
self._sanitize_vals(vals)
|
||||
templates = super(ResProductMo, self).create(vals_list)
|
||||
if "create_product_product" not in self._context:
|
||||
templates._create_variant_ids()
|
||||
|
||||
# This is needed to set given values to first variant after creation
|
||||
for template, vals in zip(templates, vals_list):
|
||||
related_vals = {}
|
||||
for field_name in self._get_related_fields_variant_template():
|
||||
if vals.get(field_name):
|
||||
related_vals[field_name] = vals[field_name]
|
||||
if related_vals:
|
||||
template.write(related_vals)
|
||||
return templates
|
||||
|
||||
@api.onchange('upload_model_file')
|
||||
def onchange_model_file(self):
|
||||
for item in self:
|
||||
if item.upload_model_file:
|
||||
if len(item.upload_model_file) > 1:
|
||||
raise ValidationError('只允许上传一个文件')
|
||||
manufacturing_order = self.env['mrp.production'].search([('product_id', '=', self.id)])
|
||||
if manufacturing_order:
|
||||
raise ValidationError('该产品已生成制造订单,无法进行修改')
|
||||
file_attachment_id = item.upload_model_file[0]
|
||||
# 附件路径
|
||||
report_path = file_attachment_id._full_path(file_attachment_id.store_fname)
|
||||
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()
|
||||
item.model_file = self.transition_glb_file(report_path, model_code)
|
||||
|
||||
# 将attach的datas内容转为glb文件
|
||||
def transition_glb_file(self, report_path, code):
|
||||
shapes = read_step_file(report_path)
|
||||
output_file = os.path.join('/tmp', str(code) + '.stl')
|
||||
write_stl_file(shapes, output_file, 'binary', 0.03, 0.5)
|
||||
# 转化为glb
|
||||
output_glb_file = os.path.join('/tmp', str(code) + '.glb')
|
||||
util_path = get_resource_path('sf_dlm', 'static/util')
|
||||
cmd = 'python3 %s/stl2gltf.py %s %s -b' % (util_path, output_file, output_glb_file)
|
||||
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
|
||||
|
||||
|
||||
class ResMrpBomMo(models.Model):
|
||||
_inherit = 'mrp.bom'
|
||||
|
||||
subcontractor_id = fields.Many2one('res.partner', string='外包商')
|
||||
|
||||
def bom_create_line_has(self, embryo):
|
||||
vals = {
|
||||
'bom_id': self.id,
|
||||
'product_id': embryo.id,
|
||||
'product_tmpl_id': embryo.product_tmpl_id.id,
|
||||
'product_qty': 1,
|
||||
'product_uom_id': 1
|
||||
}
|
||||
return self.env['mrp.bom.line'].create(vals)
|
||||
|
||||
# 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品后再次进行创建bom
|
||||
|
||||
def bom_create(self, product, bom_type, product_type):
|
||||
bom_id = self.env['mrp.bom'].create({
|
||||
'product_tmpl_id': product.product_tmpl_id.id,
|
||||
'type': bom_type,
|
||||
# 'subcontractor_id': '' or subcontract.partner_id.id,
|
||||
'product_qty': 1,
|
||||
'product_uom_id': 1
|
||||
})
|
||||
if bom_type == 'subcontract' and product_type is not False:
|
||||
subcontract = self.get_supplier(product.materials_type_id)
|
||||
bom_id.subcontractor_id = subcontract.partner_id.id
|
||||
return bom_id
|
||||
|
||||
# 坯料BOM组件:选取当前坯料原材料,
|
||||
# 然后根据当前的坯料的体积得出需要的原材料重量(立方米m³) *材料密度 * 1000 = 所需原材料重量KG(公斤)
|
||||
# 坯料所需原材料公式:当前的坯料的体积(立方米m³) *材料密度 * 1000 = 所需原材料重量KG(公斤)
|
||||
|
||||
def bom_create_line(self, embryo):
|
||||
# 选取当前坯料原材料
|
||||
raw_bom_line = self.get_raw_bom(embryo)
|
||||
if raw_bom_line:
|
||||
bom_line = self.env['mrp.bom.line'].create({
|
||||
'bom_id': self.id,
|
||||
'product_id': raw_bom_line.id,
|
||||
'product_tmpl_id': raw_bom_line.product_tmpl_id.id,
|
||||
'product_qty': round(embryo.volume * raw_bom_line.materials_type_id.density / 1000000),
|
||||
'product_uom_id': raw_bom_line.uom_id.id,
|
||||
})
|
||||
return bom_line
|
||||
else:
|
||||
return False
|
||||
|
||||
# 查询材料型号默认排第一的供应商
|
||||
|
||||
def get_supplier(self, materials_type):
|
||||
seller_id = self.env['sf.supplier.sort'].search(
|
||||
[('materials_model_id', '=', materials_type.id)],
|
||||
limit=1,
|
||||
order='sequence asc')
|
||||
return seller_id
|
||||
|
||||
# 匹配bom
|
||||
|
||||
def get_bom(self, product):
|
||||
embryo_has = self.env['product.product'].search(
|
||||
[('categ_id.type', '=', '坯料'), ('materials_type_id', '=', product.materials_type_id.id),
|
||||
('length', '>', product.length), ('width', '>', product.width),
|
||||
('height', '>', product.height), ('is_bfm', '=', False)
|
||||
],
|
||||
limit=1,
|
||||
order='volume desc'
|
||||
)
|
||||
logging.info('get_bom-vals:%s' % embryo_has)
|
||||
if embryo_has:
|
||||
rate_of_waste = ((embryo_has.volume - product.model_volume) % embryo_has.volume) * 100
|
||||
if rate_of_waste <= 20:
|
||||
return embryo_has
|
||||
else:
|
||||
return
|
||||
|
||||
# 查bom的原材料
|
||||
|
||||
def get_raw_bom(self, product):
|
||||
raw_bom = self.env['product.product'].search(
|
||||
[('categ_id.type', '=', '原材料'), ('materials_type_id', '=', product.materials_type_id.id)])
|
||||
return raw_bom
|
||||
|
||||
@@ -569,15 +569,20 @@ class MachineBrand(models.Model):
|
||||
result = json.loads(r['result'])
|
||||
if result['status'] == 1:
|
||||
for item in result['machine_brand_all_list']:
|
||||
|
||||
brand = self.env['sf.machine.brand'].search(
|
||||
[("code", '=', item['code'])])
|
||||
if not brand:
|
||||
if item.get('image_brand'):
|
||||
image = base64.b64decode(item['image_brand'])
|
||||
else:
|
||||
image = ''
|
||||
self.env['sf.machine.brand'].create({
|
||||
"id": item['id'],
|
||||
"name": item['name'],
|
||||
"code": item['code'],
|
||||
"remark": item['remark'],
|
||||
"image_brand": '' if not item['image_brand'] else base64.b64encode(item.image_brand),
|
||||
"image_brand": image,
|
||||
"tag_ids": self.env['sf.machine.brand.tags'].search(
|
||||
[("name", 'in', item['tag_ids'])]).ids
|
||||
})
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
""",
|
||||
'category': 'sf',
|
||||
'website': 'https://www.sf.jikimo.com',
|
||||
'depends': ['sale', 'sale_management', 'point_of_sale', 'web_widget_model_viewer'],
|
||||
'depends': ['sale_management', 'web_widget_model_viewer',],
|
||||
'data': [
|
||||
'security/group_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'views/sale_order_view.xml',
|
||||
'views/quick_easy_order_view.xml',
|
||||
'views/quick_easy_order_view.xml'
|
||||
],
|
||||
'demo': [
|
||||
],
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
from odoo import models, fields
|
||||
import datetime
|
||||
from odoo import models, fields, api
|
||||
from odoo.modules import get_resource_path
|
||||
from OCC.Extend.DataExchange import read_step_file
|
||||
from OCC.Extend.DataExchange import write_stl_file
|
||||
from odoo.exceptions import ValidationError, UserError
|
||||
from odoo.addons.sf_base.commons.common import Common
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import base64
|
||||
import hashlib
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
|
||||
|
||||
class QuickEasyOrder(models.Model):
|
||||
@@ -8,19 +18,166 @@ class QuickEasyOrder(models.Model):
|
||||
_description = '简易下单'
|
||||
|
||||
name = fields.Char('订单编号', default=lambda self: self.env['ir.sequence'].next_by_code('quick.easy.order'))
|
||||
model_length = fields.Float('长[mm]', digits=(16, 3))
|
||||
model_width = fields.Float('宽[mm]', digits=(16, 3))
|
||||
model_height = fields.Float('高[mm]', digits=(16, 3))
|
||||
model_volume = fields.Float('体积[mm³]', digits=(16, 3))
|
||||
model_processing_side = fields.Char('加工面')
|
||||
machining_precision = fields.Selection([
|
||||
('0.10', '±0.10mm'),
|
||||
('0.05', '±0.05mm'),
|
||||
('0.03', '±0.03mm'),
|
||||
('0.02', '±0.02mm'),
|
||||
('0.01', '±0.01mm')], string='加工精度')
|
||||
material_id = fields.Many2one('sf.production.materials', '材料')
|
||||
material_model_id = fields.Many2one('sf.materials.model', '型号')
|
||||
('0.01', '±0.01mm')], string='加工精度', default='0.10')
|
||||
material_id = fields.Many2one('sf.production.materials', '材料', compute='_compute_material_model', store=True)
|
||||
material_model_id = fields.Many2one('sf.materials.model', '型号', compute='_compute_material_model', store=True)
|
||||
process_id = fields.Many2one('sf.production.process', string='表面工艺')
|
||||
parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数')
|
||||
quantity = fields.Integer('数量')
|
||||
quantity = fields.Integer('数量', default=1)
|
||||
unit_price = fields.Float('单价')
|
||||
price = fields.Float('总价')
|
||||
model_file = fields.Binary('模型文件')
|
||||
upload_model_file = fields.Many2many('ir.attachment', 'upload_qf_model_file_attachment_ref', string='上传模型文件')
|
||||
upload_model_file = fields.Many2many('ir.attachment', 'upload_qf_model_file_attachment_ref', string='模型文件')
|
||||
delivery_time = fields.Date('交货日期')
|
||||
customer_id = fields.Many2one('res.partner', string='客户', default=lambda self: self.env.user.partner_id.id)
|
||||
state = fields.Selection([('草稿', '草稿'), ('待付款', '待付款'), ('待派单', '待派单'),
|
||||
('待接单', '待接单'), ('加工中', '加工中'),
|
||||
('物流中', '物流中'), ('已交付', '已交付')], string='订单状态', default='草稿',
|
||||
readonly=True)
|
||||
|
||||
@api.depends('material_id', 'material_model_id')
|
||||
def _compute_material_model(self):
|
||||
for item in self:
|
||||
materials = self.env['sf.production.materials'].search([], limit=1, order='id desc')
|
||||
item.material_id = materials.id
|
||||
item.material_model_id = self.env['sf.materials.model'].search(
|
||||
[('materials_id', '=', materials.id)],
|
||||
limit=1, order='id desc')
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get('upload_model_file'):
|
||||
logging.info('create-attachment:%s' % vals['upload_model_file'][0])
|
||||
for item in vals['upload_model_file']:
|
||||
print(len(item[2]))
|
||||
if len(item[2]) > 0:
|
||||
logging.info('create-attachment:%s' % int(item[2][0]))
|
||||
attachment = self.env['ir.attachment'].sudo().search([('id', '=', int(item[2][0]))])
|
||||
base64_data = base64.b64encode(attachment.datas)
|
||||
base64_datas = base64_data.decode('utf-8')
|
||||
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||
report_path = attachment._full_path(attachment.store_fname)
|
||||
vals['model_file'] = self.transition_glb_file(report_path, model_code)
|
||||
logging.info('create-model_file:%s' % len(vals['model_file']))
|
||||
feature_path = self.env['jikimo.auto_quatotion.common'].sudo().get_feature_full_path()
|
||||
# price_path = self.env['jikimo.auto_quatotion.common'].get_price_full_path()
|
||||
process_time_db_path = self.env['jikimo.auto_quatotion.common'].sudo().get_process_time_db_path()
|
||||
ret = self.env['jikimo.auto_quatotion.common'].sudo().get_auto_quatotion(report_path, feature_path,
|
||||
process_time_db_path,
|
||||
model_code)
|
||||
logging.info("自动报价返回值: %s" % ret)
|
||||
shapes = ret['boxshape'].tolist()
|
||||
logging.info("自动报价boxshape: %s" % shapes)
|
||||
target_faces = ','.join(ret['target_faces']),
|
||||
# item.price = ret['price']
|
||||
item.model_length = shapes[0] # 长 单位mm
|
||||
item.model_width = shapes[1] # 宽
|
||||
item.model_height = shapes[2] # 高
|
||||
item.model_volume = shapes[0] * shapes[1] * shapes[2]
|
||||
item.model_processing_side = target_faces[0]
|
||||
obj = super(QuickEasyOrder, self).create(vals)
|
||||
self.distribute_to_factory(obj)
|
||||
return obj
|
||||
|
||||
# 将attach的datas内容转为glb文件
|
||||
def transition_glb_file(self, report_path, model_code):
|
||||
shapes = read_step_file(report_path)
|
||||
output_file = os.path.join('C:/Users/43484/Desktop/机企猫工作文档', str(model_code) + '.stl')
|
||||
# output_file = os.path.join('/tmp', str(model_code) + '.stl')
|
||||
write_stl_file(shapes, output_file, 'binary', 0.03, 0.5)
|
||||
# 转化为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')
|
||||
util_path = get_resource_path('mrs_base', 'static/util')
|
||||
cmd = 'python3 %s/stl2gltf.py %s %s -b' % (util_path, output_file, output_glb_file)
|
||||
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
|
||||
# return False
|
||||
|
||||
@api.onchange('upload_model_file')
|
||||
def onchange_model_file(self):
|
||||
for item in self:
|
||||
if len(item.upload_model_file) > 1:
|
||||
raise ValidationError('只允许上传一个文件')
|
||||
if item.upload_model_file:
|
||||
file_attachment_id = item.upload_model_file[0]
|
||||
# 附件路径
|
||||
report_path = file_attachment_id._full_path(file_attachment_id.store_fname)
|
||||
logging.info("模型路径: %s" % report_path)
|
||||
base64_data = base64.b64encode(file_attachment_id.datas)
|
||||
base64_datas = base64_data.decode('utf-8')
|
||||
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||
logging.info("模型编码: %s" % model_code)
|
||||
item.model_file = self.transition_glb_file(report_path, model_code)
|
||||
else:
|
||||
item.model_file = False
|
||||
|
||||
def distribute_to_factory(self, obj):
|
||||
"""
|
||||
派单到工厂
|
||||
:return:
|
||||
"""
|
||||
web_base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url', default=''),
|
||||
url = '/api/bfm_process_order/list'
|
||||
res = {'order_number': obj.name, 'delivery_end_date': str(datetime.now()),
|
||||
'delivery_name': 'XXXXX', 'delivery_telephone': 'XXXXX',
|
||||
'delivery_address': 'XXXXX',
|
||||
'bfm_process_order_list': []}
|
||||
factory = self.env['res.partner'].sudo().search([], limit=1, order='id desc')
|
||||
config_header = Common.get_headers(self, factory.sf_token, factory.sf_secret_key)
|
||||
for item in obj:
|
||||
attachment = item.upload_model_file[0]
|
||||
base64_data = base64.b64encode(attachment.datas)
|
||||
base64_datas = base64_data.decode('utf-8')
|
||||
barcode = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||
logging.info('model_file-size: %s' % len(item.model_file))
|
||||
val = {
|
||||
'model_long': 100,
|
||||
'model_width': 100,
|
||||
'model_height': 100,
|
||||
'model_volume': 300,
|
||||
'model_machining_precision': item.machining_precision,
|
||||
'model_name': attachment.name,
|
||||
'model_data': base64_datas,
|
||||
'model_file': base64.b64encode(item.model_file).decode('utf-8'),
|
||||
'texture_code': item.material_id.materials_no,
|
||||
'texture_type_code': item.material_model_id.materials_no,
|
||||
# 'surface_process_code': self.env['jikimo.surface.process']._json_surface_process_code(item),
|
||||
# 'process_parameters_code': self.env['jikimo.surface.process.item']._json_surface_process_item_code(
|
||||
# item),
|
||||
'price': item.price,
|
||||
'number': item.quantity,
|
||||
'total_amount': item.price,
|
||||
'remark': '',
|
||||
'barcode': barcode
|
||||
}
|
||||
res['bfm_process_order_list'].append(val)
|
||||
res['bfm_process_order_list'] = json.dumps(res['bfm_process_order_list'])
|
||||
try:
|
||||
ret = requests.post((web_base_url[0] + url), json={}, data=res,
|
||||
headers=config_header)
|
||||
ret = ret.json()
|
||||
if ret['status'] == 1:
|
||||
self.write(
|
||||
{'state': '待接单'})
|
||||
else:
|
||||
raise UserError(ret['message'])
|
||||
except Exception as e:
|
||||
if ret['status'] != 1:
|
||||
raise UserError(e)
|
||||
else:
|
||||
raise UserError("分配工厂失败,请联系管理员")
|
||||
|
||||
4
sf_sale/security/group_security.xml
Normal file
4
sf_sale/security/group_security.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<odoo>
|
||||
<data>
|
||||
</data>
|
||||
</odoo>
|
||||
9
sf_sale/security/ir.model.access.csv
Normal file
9
sf_sale/security/ir.model.access.csv
Normal file
@@ -0,0 +1,9 @@
|
||||
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_user,1,1,1,1
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -33,21 +33,26 @@
|
||||
<field name="arch" type="xml">
|
||||
<form string="快速订单">
|
||||
<sheet>
|
||||
<label for="name"/>
|
||||
<h1>
|
||||
<field name="name" readonly="True"/>
|
||||
</h1>
|
||||
<group>
|
||||
<group>
|
||||
<field name="customer_id"/>
|
||||
<field name="material_id"/>
|
||||
<field name="customer_id" readonly="1" force_save="1"/>
|
||||
<field name="material_id" />
|
||||
<field name="material_model_id"/>
|
||||
<field name="process_id"/>
|
||||
<field name="parameter_ids"/>
|
||||
<field name="parameter_ids" widget="many2many_tags"/>
|
||||
<field name="machining_precision"/>
|
||||
<field name="quantity"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="price"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="upload_model_file" widget="many2many_binary" />
|
||||
<field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1"
|
||||
attrs="{'invisible': [('model_file', '=', False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
@@ -82,7 +87,13 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem parent="sale.sale_order_menu" sequence="99" name="上传模型" id="menu_quick_easy_order"
|
||||
action="action_quick_easy_order"/>
|
||||
<!-- <menuitem id="res_partner_menu"-->
|
||||
<!-- action="account.res_partner_action_customer"-->
|
||||
<!-- groups="sales_team.group_sale_salesman"-->
|
||||
<!-- sequence="40"/>-->
|
||||
<menuitem sequence="50" name="上传模型" id="menu_quick_easy_order"
|
||||
action="action_quick_easy_order"
|
||||
parent="sale.menu_sale_order"
|
||||
groups="sales_team.group_sale_salesman"/>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -29,12 +29,12 @@
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="name" invisible="False"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name" invisible="True"/>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="mrs_cutting_tool_type_id"/>
|
||||
|
||||
<field name="mrs_cutting_tool_integral_model_ids"
|
||||
@@ -188,12 +188,12 @@
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="name" invisible="False"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name" invisible="True"/>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="mrs_cutting_tool_type_id"/>
|
||||
|
||||
<field name="mrs_cutting_tool_integral_model_ids"
|
||||
@@ -385,12 +385,12 @@
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="name" invisible="False"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name" invisible="True"/>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="mrs_cutting_tool_type_id"/>
|
||||
|
||||
<field name="mrs_cutting_tool_integral_model_ids"
|
||||
@@ -570,12 +570,12 @@
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="name" invisible="False"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name" invisible="True"/>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="mrs_cutting_tool_type_id"/>
|
||||
|
||||
<field name="mrs_cutting_tool_integral_model_ids"
|
||||
@@ -1170,14 +1170,14 @@
|
||||
</header>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="functional_tool_code" readonly="1"/>
|
||||
<field name="name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="functional_tool_type_id"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="functional_tool_code" readonly="1"/>
|
||||
<field name="functional_tool_type_id"/>
|
||||
<field name="functional_tool_diameter"/>
|
||||
<field name="functional_tool_length"/>
|
||||
<field name="functional_tool_cutting_type"/>
|
||||
|
||||
@@ -126,12 +126,16 @@
|
||||
<field name="arch" type="xml">
|
||||
<form string="刀具物料查询">
|
||||
<sheet>
|
||||
<group string='基本信息'>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="mrs_cutting_tool_material_name" invisible="1"/>
|
||||
<field name="sequence"/>
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="mrs_cutting_tool_type_id"/>
|
||||
<field name="mrs_machine_brand_id"/>
|
||||
<!-- <field name="mrs_cutting_tool_model_id"/> -->
|
||||
@@ -143,147 +147,158 @@
|
||||
<field name="three_d_model" widget="many2one"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string='刀具库存信息'>
|
||||
<group>
|
||||
<field name="number"/>
|
||||
<field name="mrs_materials_model_id"/>
|
||||
<field name="purchase_date"/>
|
||||
<field name="purchase_batch"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="supplier"/>
|
||||
<field name="warehouse_name"/>
|
||||
<field name="warehouse_area"/>
|
||||
<field name="warehouse_location"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string='刀具库存信息'>
|
||||
<group >
|
||||
<group>
|
||||
<field name="number"/>
|
||||
<field name="mrs_materials_model_id"/>
|
||||
<field name="purchase_date"/>
|
||||
<field name="purchase_batch"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="supplier"/>
|
||||
<field name="warehouse_name"/>
|
||||
<field name="warehouse_area"/>
|
||||
<field name="warehouse_location"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="刀片信息" attrs="{'invisible': [('cutting_tool_type','!=','刀片')]}">
|
||||
<group>
|
||||
<group>
|
||||
<field name="blade_code" invisible="True"/>
|
||||
<field name="blade_length"/>
|
||||
<field name="blade_width"/>
|
||||
<field name="blade_height"/>
|
||||
<field name="blade_radius"/>
|
||||
<field name="blade_hardness"/>
|
||||
<field name="blade_accuracy"/>
|
||||
<field name="blade_coating_material_id"/>
|
||||
<field name="mrs_cutting_tool_model_blade_cutter_bar_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="blade_top_angle"/>
|
||||
<field name="blade_front_angle"/>
|
||||
<field name="blade_rear_angle"/>
|
||||
<field name="blade_main_included_angle"/>
|
||||
<field name="blade_r_angle"/>
|
||||
<field name="blade_nut"/>
|
||||
<field name="mrs_cutting_tool_model_blade_cutter_pad_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="整体式刀具信息" attrs="{'invisible': [('cutting_tool_type','!=','整体式刀具')]}">
|
||||
<group>
|
||||
<group>
|
||||
<field name="integral_code" invisible="True"/>
|
||||
<field name="integral_total_length"/>
|
||||
<field name="integral_shank_length"/>
|
||||
<field name="integral_blade_length"/>
|
||||
<field name="integral_diameter"/>
|
||||
<field name="integral_blade_number"/>
|
||||
<field name="integral_accuracy"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="integral_front_angle"/>
|
||||
<field name="integral_rear_angle"/>
|
||||
<field name="integral_main_included_angle"/>
|
||||
<field name="integral_nut"/>
|
||||
<field name="integral_hardness"/>
|
||||
<field name="integral_coating_material"/>
|
||||
<field name="integral_scope"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="刀杆信息" attrs="{'invisible': [('cutting_tool_type','!=','刀杆')]}">
|
||||
<group>
|
||||
<group>
|
||||
<field name="bar_code" invisible="True"/>
|
||||
<field name="bar_c_diameter"/>
|
||||
<field name="bar_total_length"/>
|
||||
<field name="bar_blade_number"/>
|
||||
<field name="bar_d_diameter"/>
|
||||
<field name="bar_scope"/>
|
||||
<field name="mrs_cutting_tool_model_bar_blade_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="bar_wrench"/>
|
||||
<field name="bar_screw"/>
|
||||
<field name="bar_radius"/>
|
||||
<field name="bar_accuracy"/>
|
||||
<field name="bar_hardness"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="刀盘信息" attrs="{'invisible': [('cutting_tool_type','!=','刀盘')]}">
|
||||
<group>
|
||||
<group>
|
||||
<field name="pad_code" invisible="True"/>
|
||||
<field name="pad_c_diameter"/>
|
||||
<field name="pad_total_length"/>
|
||||
<field name="pad_blade_number"/>
|
||||
<field name="pad_d_diameter"/>
|
||||
<field name="pad_scope"/>
|
||||
<field name="mrs_cutting_tool_model_pad_blade_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="pad_wrench"/>
|
||||
<field name="pad_screw"/>
|
||||
<field name="pad_radius"/>
|
||||
<field name="pad_accuracy"/>
|
||||
<field name="pad_hardness"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="刀柄信息" attrs="{'invisible': [('cutting_tool_type','!=','刀柄')]}">
|
||||
<group>
|
||||
<group>
|
||||
<field name="handle_code" invisible="True"/>
|
||||
<field name="handle_diameter"/>
|
||||
<field name="handle_flange_length"/>
|
||||
<field name="handle_flange_diameter"/>
|
||||
<field name="handle_clamping_diameter_min"/>
|
||||
<field name="handle_clamping_diameter_max"/>
|
||||
<field name="handle_clamping_range"/>
|
||||
<field name="handle_detection_accuracy"/>
|
||||
<field name="mrs_cutting_tool_model_handle_chuck_model_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="handle_jump_accuracy"/>
|
||||
<field name="handle_max_speed"/>
|
||||
<field name="handle_standard_speed"/>
|
||||
<field name="handle_weight"/>
|
||||
<field name="handle_body_accuracy"/>
|
||||
<field name="handle_nut"/>
|
||||
<field name="handle_detection_hardness"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="夹头信息" attrs="{'invisible': [('cutting_tool_type','!=','夹头')]}">
|
||||
<group>
|
||||
<group>
|
||||
<field name="chuck_code" invisible="True"/>
|
||||
<field name="chuck_clamping_diameter_min"/>
|
||||
<field name="chuck_clamping_diameter_max"/>
|
||||
<field name="chuck_diameter"/>
|
||||
<field name="chuck_inner_diameter"/>
|
||||
<field name="chuck_feature"/>
|
||||
<field name="mrs_cutting_tool_model_chuck_handle_model_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="chuck_accuracy"/>
|
||||
<field name="chuck_height"/>
|
||||
<field name="chuck_nut"/>
|
||||
<field name="chuck_clamping_range"/>
|
||||
<field name="image"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
<group>
|
||||
<field name="cutting_tool_material_name" invisible="True"/>
|
||||
<field name="cutting_tool_type" invisible="True"/>
|
||||
</group>
|
||||
<group string="刀片信息" attrs="{'invisible': [('cutting_tool_type','!=','刀片')]}">
|
||||
<group>
|
||||
<field name="blade_code" invisible="True"/>
|
||||
<field name="blade_length"/>
|
||||
<field name="blade_width"/>
|
||||
<field name="blade_height"/>
|
||||
<field name="blade_radius"/>
|
||||
<field name="blade_hardness"/>
|
||||
<field name="blade_accuracy"/>
|
||||
<field name="blade_coating_material_id"/>
|
||||
<field name="mrs_cutting_tool_model_blade_cutter_bar_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="blade_top_angle"/>
|
||||
<field name="blade_front_angle"/>
|
||||
<field name="blade_rear_angle"/>
|
||||
<field name="blade_main_included_angle"/>
|
||||
<field name="blade_r_angle"/>
|
||||
<field name="blade_nut"/>
|
||||
<field name="mrs_cutting_tool_model_blade_cutter_pad_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group string="整体式刀具信息" attrs="{'invisible': [('cutting_tool_type','!=','整体式刀具')]}">
|
||||
<group>
|
||||
<field name="integral_code" invisible="True"/>
|
||||
<field name="integral_total_length"/>
|
||||
<field name="integral_shank_length"/>
|
||||
<field name="integral_blade_length"/>
|
||||
<field name="integral_diameter"/>
|
||||
<field name="integral_blade_number"/>
|
||||
<field name="integral_accuracy"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="integral_front_angle"/>
|
||||
<field name="integral_rear_angle"/>
|
||||
<field name="integral_main_included_angle"/>
|
||||
<field name="integral_nut"/>
|
||||
<field name="integral_hardness"/>
|
||||
<field name="integral_coating_material"/>
|
||||
<field name="integral_scope"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group string="刀杆信息" attrs="{'invisible': [('cutting_tool_type','!=','刀杆')]}">
|
||||
<group>
|
||||
<field name="bar_code" invisible="True"/>
|
||||
<field name="bar_c_diameter"/>
|
||||
<field name="bar_total_length"/>
|
||||
<field name="bar_blade_number"/>
|
||||
<field name="bar_d_diameter"/>
|
||||
<field name="bar_scope"/>
|
||||
<field name="mrs_cutting_tool_model_bar_blade_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="bar_wrench"/>
|
||||
<field name="bar_screw"/>
|
||||
<field name="bar_radius"/>
|
||||
<field name="bar_accuracy"/>
|
||||
<field name="bar_hardness"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group string="刀盘信息" attrs="{'invisible': [('cutting_tool_type','!=','刀盘')]}">
|
||||
<group>
|
||||
<field name="pad_code" invisible="True"/>
|
||||
<field name="pad_c_diameter"/>
|
||||
<field name="pad_total_length"/>
|
||||
<field name="pad_blade_number"/>
|
||||
<field name="pad_d_diameter"/>
|
||||
<field name="pad_scope"/>
|
||||
<field name="mrs_cutting_tool_model_pad_blade_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="pad_wrench"/>
|
||||
<field name="pad_screw"/>
|
||||
<field name="pad_radius"/>
|
||||
<field name="pad_accuracy"/>
|
||||
<field name="pad_hardness"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group string="刀柄信息" attrs="{'invisible': [('cutting_tool_type','!=','刀柄')]}">
|
||||
<group>
|
||||
<field name="handle_code" invisible="True"/>
|
||||
<field name="handle_diameter"/>
|
||||
<field name="handle_flange_length"/>
|
||||
<field name="handle_flange_diameter"/>
|
||||
<field name="handle_clamping_diameter_min"/>
|
||||
<field name="handle_clamping_diameter_max"/>
|
||||
<field name="handle_clamping_range"/>
|
||||
<field name="handle_detection_accuracy"/>
|
||||
<field name="mrs_cutting_tool_model_handle_chuck_model_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="handle_jump_accuracy"/>
|
||||
<field name="handle_max_speed"/>
|
||||
<field name="handle_standard_speed"/>
|
||||
<field name="handle_weight"/>
|
||||
<field name="handle_body_accuracy"/>
|
||||
<field name="handle_nut"/>
|
||||
<field name="handle_detection_hardness"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group string="夹头信息" attrs="{'invisible': [('cutting_tool_type','!=','夹头')]}">
|
||||
<group>
|
||||
<field name="chuck_code" invisible="True"/>
|
||||
<field name="chuck_clamping_diameter_min"/>
|
||||
<field name="chuck_clamping_diameter_max"/>
|
||||
<field name="chuck_diameter"/>
|
||||
<field name="chuck_inner_diameter"/>
|
||||
<field name="chuck_feature"/>
|
||||
<field name="mrs_cutting_tool_model_chuck_handle_model_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="chuck_accuracy"/>
|
||||
<field name="chuck_height"/>
|
||||
<field name="chuck_nut"/>
|
||||
<field name="chuck_clamping_range"/>
|
||||
<field name="image"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
|
||||
BIN
web_widget_model_viewer/static/src/images/not_model.png
Normal file
BIN
web_widget_model_viewer/static/src/images/not_model.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
@@ -19,31 +19,34 @@ var QWeb = core.qweb;
|
||||
import { Component, onWillUpdateProps, useState, useRef, useEffect } from "@odoo/owl";
|
||||
|
||||
export class StepViewer extends Component {
|
||||
setup() {
|
||||
console.log('setup')
|
||||
setup() {
|
||||
this.props.url = this.formatUrl();
|
||||
}
|
||||
|
||||
formatUrl(){
|
||||
var url = '';
|
||||
if (this.props.value) {
|
||||
if (utils.is_bin_size(this.props.value)) {
|
||||
if (this.props.value.slice(-1) == 'b' && !isNaN(this.props.value.split(' ')[0])) {
|
||||
var url_props = {
|
||||
base_url: session['web.base.url'],
|
||||
model: this.props.record.resModel,
|
||||
id: JSON.stringify(this.props.record.data['id']),
|
||||
field: this.props.name}
|
||||
url = url_props['base_url']+'/web/content/'+url_props['model']+'/'+url_props['id']+'/'+url_props['field']+'?download=true'
|
||||
console.log('url', url)
|
||||
|
||||
url = url_props['base_url'].replace('http://', 'https://') +'/web/content/'+url_props['model']+'/'+url_props['id']+'/'+url_props['field']+'?download=true'
|
||||
// url = 'http://localhost:8069'+'/web/content/'+url_props['model']+'/'+url_props['id']+'/'+url_props['field']+'?download=true'
|
||||
console.log('url111111',url)
|
||||
return url
|
||||
} else {
|
||||
url = "data:model/gltf-binary;base64," + this.props.value;
|
||||
console.log('url222', url)
|
||||
url = "data:model/gltf-binary;base64," + this.props.value;
|
||||
console.log('url2',url)
|
||||
return url
|
||||
// localStorage.setItem('url',url)
|
||||
// let new_url = localStorage.getItem(('url'))
|
||||
// var oViewer = document.getElementsByTagName('model-viewer')[0];
|
||||
// return new_url
|
||||
// url = "web_widget_model_viewer/static/src/images/not_model.png";
|
||||
}
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
StepViewer.template = "web_widget_model_viewer.BinaryField3d";
|
||||
|
||||
Reference in New Issue
Block a user