Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/刀具管理加粗字段调整及界面布局优化

This commit is contained in:
yuxianghui
2023-08-28 10:00:57 +08:00
38 changed files with 1134 additions and 351 deletions

View File

@@ -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',

View File

@@ -7,3 +7,5 @@ from . import functional_fixture

View File

@@ -312,7 +312,8 @@ class MachineToolType(models.Model):
machine_tool_type_ids = []
for item in machine_tool_type_code:
machine_tool_type = self.search([('code', '=', item)])
machine_tool_type_ids.append(machine_tool_type.id)
if machine_tool_type:
machine_tool_type_ids.append(machine_tool_type.id)
return [(6, 0, machine_tool_type_ids)]

View File

@@ -26,7 +26,6 @@ class FixtureModel(models.Model):
_name = 'sf.fixture.model'
_description = "夹具型号"
code = fields.Char(string='编码')
name = fields.Char(string="名称", size=15)
fixture_material_id = fields.Many2one('sf.fixture.material', string="夹具物料", )
fixture_material_type = fields.Char(string="夹具物料类型", related='fixture_material_id.name', store=True)
@@ -53,10 +52,38 @@ class FixtureModel(models.Model):
screw_size = fields.Integer(string="螺牙大小[mm]", size=6)
active = fields.Boolean('有效', default=True)
# @api.model
# def create(self, vals):
# obj = super(FixtureModel, self).create(vals)
# return obj
def _get_code(self, fixture_model_type_code):
fixture_model = self.env['sf.fixture.model'].sudo().search(
[('code', 'ilike', fixture_model_type_code)],
limit=1,
order="id desc")
if not fixture_model:
num = "%03d" % 1
else:
m = int(fixture_model.code[-3:]) + 1
num = "%03d" % m
return "%s%s" % (fixture_model_type_code, num)
code = fields.Char(string='编码', readonly=True)
def _onchange_fixture_material_id(self, fixture_material_id):
if fixture_material_id:
if fixture_material_id.name == "气动夹具":
code = self._get_code("JKM-C-JJWL-QDJJ-")
elif fixture_material_id.name == "转接板(锁板)夹具":
code = self._get_code("JKM-C-JJWL-ZJBJJ-")
elif fixture_material_id.name == "磁吸夹具":
code = self._get_code("JKM-C-JJWL-CXJJ-")
elif fixture_material_id.name == "虎钳夹具":
code = self._get_code("JKM-C-JJWL-HQJJ-")
else:
code = self._get_code("JKM-C-JJWL-LDKP-")
return code
@api.model
def create(self, vals):
obj = super(FixtureModel, self).create(vals)
if obj.fixture_material_id:
code = self._onchange_fixture_material_id(obj.fixture_material_id)
obj.code = code
return obj

View File

@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
from odoo import fields, models, api
# from datetime import datetime
# from odoo.exceptions import ValidationError
@@ -95,7 +97,6 @@ class CuttingToolModel(models.Model):
_description = '刀具型号'
name = fields.Char('名称')
code = fields.Char('编码')
cutting_tool_material_id = fields.Many2one('sf.cutting.tool.material', string='刀具物料')
cutting_tool_type = fields.Char(string="刀具物料类型", related='cutting_tool_material_id.name', store=True)
cutting_tool_type_id = fields.Many2one('sf.cutting.tool.type', string='刀具类型',
@@ -177,12 +178,43 @@ class CuttingToolModel(models.Model):
)
active = fields.Boolean('有效', default=True)
# @api.model
# def create(self, vals):
# if vals.get('name', '/') == '/' or vals.get('name', '/') is False:
# vals['name'] = '/'
# obj = super(CuttingToolModel, self).create(vals)
# return obj
def _get_code(self, cutting_tool_type_code):
cutting_tool_model = self.search(
[('code', 'ilike', cutting_tool_type_code)],
limit=1,
order="id desc")
if not cutting_tool_model:
num = "%03d" % 1
else:
m = int(cutting_tool_model.code[-3:]) + 1
num = "%03d" % m
return "%s%s" % (cutting_tool_type_code, num)
code = fields.Char(string='编码', readonly=True)
def _onchange_cutting_tool_material_id(self, cutting_tool_material_id):
if cutting_tool_material_id:
if cutting_tool_material_id.name == "整体式刀具":
code = self._get_code("JKM-T-DJWL-ZTDJ-")
elif cutting_tool_material_id.name == "刀片":
code = self._get_code("JKM-T-DJWL-DPIA-")
elif cutting_tool_material_id.name == "刀杆":
code = self._get_code("JKM-T-DJWL-DGAN-")
elif cutting_tool_material_id.name == "刀盘":
code = self._get_code("JKM-T-DJWL-DPAN-")
elif cutting_tool_material_id.name == "夹头":
code = self._get_code("JKM-T-DJWL-DJIA-")
else:
code = self._get_code("JKM-T-DJWL-DBIN-")
return code
@api.model
def create(self, vals):
obj = super(CuttingToolModel, self).create(vals)
if obj.cutting_tool_material_id:
code = self._onchange_cutting_tool_material_id(obj.cutting_tool_material_id)
obj.code = code
return obj
# 刀具类型

View File

@@ -8,27 +8,34 @@
white-space: nowrap;
}
div:has(.o_required_modifier)>label::before {
div:has(.o_required_modifier) > label::before {
content: '*' !important;
color: red !important;
padding: 0 4px !important;
vertical-align: top !important;
font-size: 1.5rem !important;
}
.my-image div {
width: 100px !important;
height: 130px !important;
}
.my-image div {
width: 110px !important;
height: 110px !important;
}
.add_flex {
padding: 5px 0;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.maintenance_name {
font-weight: bold;
}
.o_kanban_renderer .o_kanban_record .o_kanban_record_has_image_fill .o_kanban_image_fill_left {
flex:unset !important;
flex: unset !important;
}
.o_kanban_renderer .o_kanban_record .o_kanban_record_bottom {
margin-top: 5px;
display: inline !important;
@@ -36,4 +43,80 @@ div:has(.o_required_modifier)>label::before {
td.o_required_modifier {
display: table-cell !important;
}
.show_state {
display: flex;
flex-direction: column;
position: absolute;
top: 0;
bottom: 0;
right: 8px;
margin: auto;
height: 34px;
}
.show_state > div {
width: 12px;
height: 12px;
border: 1px solid #000
}
.show_state > div:nth-child(2) {
border-top: none;
border-bottom: none;
}
.oe_kanban_card.kanban_color_2 {
background-color: #FF4343 !important;
color: #fff;
}
.oe_kanban_card.kanban_color_1 {
background-color: #27FEA9 !important;
opacity: 0.7;
color: #fff;
}
.oe_kanban_card.kanban_color_3 {
background-color: rgb(255, 150, 0) !important;
color: #fff;
}
.my-image img {
width: 100%;
height: 100%;
}
.color_1 {
background-color: #27FEA9;
}
.color_2 {
background-color: #FF4343;
}
.color_3 {
background-color: rgb(255, 150, 0);
}
.font_color_1 {
color: rgb(0, 183, 0);
}
.font_color_2 {
color: #FF4343;
}
.font_color_3 {
color: rgb(255, 150, 0);
}
.o_kanban_card_header_title {
font-size: 15px;
}
.o_kanban_record_bottom {
font-family: '华文中宋';
//font-weight: bold;
}

View File

@@ -29,8 +29,8 @@
<field name="code"/>
<field name="name"/>
<field name="tag_ids" widget="many2many_tags" optional="hide"/>
<field name="remark"/>
<field name="image_brand" widget="image"/>
<field name="remark"/>
</tree>
</field>
</record>
@@ -95,8 +95,8 @@
<field name="name" string="名称"/>
<field name="machine_tool_category"/>
<field name="brand_id"/>
<field name="remark"/>
<field name="machine_tool_picture" widget="image"/>
<field name="remark"/>
</tree>
</field>
</record>

View File

@@ -163,7 +163,7 @@
<field name="name">夹具型号</field>
<field name="model">sf.fixture.model</field>
<field name="arch" type="xml">
<tree string="夹具型号" create="0" edit="0" delete="1">
<tree string="夹具型号" create="0" edit="0" delete="1">
<field name="code"/>
<field name="name" string="名称"/>
<field name="brand_id"/>
@@ -177,11 +177,11 @@
<field name="name">夹具型号</field>
<field name="model">sf.fixture.model</field>
<field name="arch" type="xml">
<form string="夹具型号" create="0" edit="0" delete="1" >
<form string="夹具型号" create="0" edit="0" delete="1">
<sheet>
<div class="oe_title">
<h1>
<field name="name" />
<field name="name"/>
</h1>
</div>
<group>
@@ -229,7 +229,8 @@
attrs='{"invisible": [("fixture_material_type","!=",("转接板(锁板)夹具"))]}'/>
<field name="driving_way"
attrs='{"invisible": [("fixture_material_type","not in",("虎钳夹具","零点卡盘"))]}'/>
<field name="apply_machine_tool_type_ids" widget="many2many_tags" options="{'no_create': True}"
<field name="apply_machine_tool_type_ids" widget="many2many_tags"
options="{'no_create': True}"
attrs='{"invisible": [("fixture_material_type","!=",("零点卡盘"))]}'/>
</group>
<group>

View File

@@ -32,10 +32,10 @@
name="功能夹具类型"
sequence="3"
/>
<menuitem id="menu_sf_functional_fixture"
parent="menu_sf_fixture"
action="sf_functional_fixture_view_act"
name="功能夹具"
<!-- <menuitem id="menu_sf_functional_fixture"-->
<!-- parent="menu_sf_fixture"-->
<!-- action="sf_functional_fixture_view_act"-->
<!-- name="功能夹具"-->
sequence="4"
/>
</odoo>

View File

@@ -109,13 +109,13 @@
</record>
<!-- 功能刀具 -->
<menuitem
id="menu_sf_functional_cutting_tool"
parent="menu_sf_base"
name="功能刀具"
sequence="3"
action="action_sf_functional_cutting_tool"
/>
<!-- <menuitem-->
<!-- id="menu_sf_functional_cutting_tool"-->
<!-- parent="menu_sf_base"-->
<!-- name="功能刀具"-->
<!-- sequence="3"-->
<!-- action="action_sf_functional_cutting_tool"-->
<!-- />-->
<!-- 刀具物料 -->
<menuitem
id="menu_sf_cutting_tool_material"

View File

@@ -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"-->
<!-- 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>

View File

@@ -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)

View File

@@ -1,5 +1,5 @@
from . import product_template
from. import product_supplierinfo
# from . import product_template
from . import product_supplierinfo

View File

@@ -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):

View File

@@ -6,7 +6,7 @@
<field name="model">product.template</field>
<field name="inherit_id" ref="sale.product_template_form_view"/>
<field name="arch" type="xml">
<field name="detailed_type" position="before">
<field name="list_price" position="before">
<field name='categ_type' invisible="1"/>
<field name="upload_model_file"
widget="many2many_binary"
@@ -15,6 +15,7 @@
attrs="{'invisible': ['|','|', ('categ_type', '!=', '成品'),('categ_type', '=', False),('model_file', '=', False)]}"/>
</field>
<field name="invoice_policy" position="after">
<!-- <field name='categ_id'/>-->
<field name='cutting_tool_type' invisible="1"/>
<field name="fixture_material_type" invisible="1"/>
<field name="embryo_model_type_id" string="模型类型"
@@ -29,13 +30,18 @@
attrs="{'invisible': ['|',('categ_type', '!=', '表面工艺'),('categ_type', '=', False)]}"/>
<field name="cutting_tool_material_id" attrs="{'invisible': [('categ_type', '!=', '刀具')]}"/>
<field name="cutting_tool_model_id"
context="{'default_cutting_tool_material_id': cutting_tool_material_id,'default_cutting_tool_type_id': cutting_tool_type_id}"
attrs="{'invisible': [('categ_type', '!=', '刀具')]}"
domain="[('cutting_tool_material_id','=',cutting_tool_material_id)]"/>
<field name="fixture_material_id" attrs="{'invisible': [('categ_type', '!=', '夹具')]}"/>
<field name="fixture_model_id" string="型号"
context="{'default_fixture_material_id': fixture_material_id,'default_multi_mounting_type_id': fixture_multi_mounting_type_id}"
attrs="{'invisible': [('categ_type', '!=', '夹具')]}"
domain="[('fixture_material_id','=',fixture_material_id)]"/>
</field>
<!-- <field name="categ_id" position="replace">-->
<!-- <field name='categ_id' invisible="1"/>-->
<!-- </field>-->
<xpath expr="//label[@for='volume']" position="before">
<label for="length" string="尺寸"
attrs="{'invisible':[('product_variant_count', '>', 1), ('is_product_variant', '=', False)]}"/>

View File

@@ -58,6 +58,14 @@ class SfSaintenanceStandards(models.Model):
maintenance_standards = fields.Char('维保标准')
equipment_maintenance_standards_id = fields.Many2one('equipment.maintenance.standards', string='设备维保标准')
maintenance_request_id = fields.Many2one('maintenance.request', string='设备维保计划')
images = fields.One2many('maintenance.standard.image', 'standard_id', string='反馈图片')
class MaintenanceStandardImage(models.Model):
_name = 'maintenance.standard.image'
image = fields.Binary(string='维保图片')
standard_id = fields.Many2one('maintenance.standards', string='Standard')

View File

@@ -25,7 +25,7 @@ class SfMaintenanceEquipmentCategory(models.Model):
if not record.equipment_maintenance_id:
record.equipment_maintenance_id = False
maintenance_standards = fields.One2many('maintenance.standards','maintenance_request_id', string='维保标准')
maintenance_standards = fields.One2many('maintenance.standards', 'maintenance_request_id', string='维保标准')
@api.constrains('equipment_maintenance_id')
def _check_equipment_maintenance_id(self):

View File

@@ -3,7 +3,7 @@ access_equipment_maintenance_standards,equipment_maintenance_standards,model_equ
access_sf_maintenance_logs,sf_maintenance_logs,model_sf_maintenance_logs,base.group_user,1,1,1,1
access_maintenance_equipment,maintenance_equipment,model_maintenance_equipment,base.group_user,1,1,1,1
access_maintenance_standards,maintenance_standards,model_maintenance_standards,base.group_user,1,1,1,1
access_maintenance_standard_image,maintenance_standard_image,model_maintenance_standard_image,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
3 access_sf_maintenance_logs sf_maintenance_logs model_sf_maintenance_logs base.group_user 1 1 1 1
4 access_maintenance_equipment maintenance_equipment model_maintenance_equipment base.group_user 1 1 1 1
5 access_maintenance_standards maintenance_standards model_maintenance_standards base.group_user 1 1 1 1
6 access_maintenance_standard_image maintenance_standard_image model_maintenance_standard_image base.group_user 1 1 1 1
7
8
9

View File

@@ -8,8 +8,10 @@
<field name="inherit_id" ref="maintenance.hr_equipment_request_view_form"/>
<field name="arch" type="xml">
<xpath expr="//button[@name='archive_equipment_request']" position="before">
<button name="confirm_maintenance" string="确认维保计划" type="object" class="btn-primary" attrs="{'invisible': [('stage_id', '!=', 1)]}" />
<button name="confirm_maintenance_done" string="标记已完成" type="object" class="btn-primary" attrs="{'invisible': [('stage_id', '!=', 2)]}" />
<button name="confirm_maintenance" string="确认维保计划" type="object" class="btn-primary"
attrs="{'invisible': [('stage_id', '!=', 1)]}"/>
<button name="confirm_maintenance_done" string="标记已完成" type="object" class="btn-primary"
attrs="{'invisible': [('stage_id', '!=', 2)]}"/>
</xpath>
<xpath expr="//field[@name='maintenance_type']" position="replace">
<field name="sf_maintenance_type" widget="radio"/>
@@ -20,12 +22,13 @@
<notebook>
<page string="维保标准" attrs="{'invisible': [('equipment_maintenance_id', '=', False)]}">
<field name="maintenance_standards" widget="ony2many">
<tree editable="bottom">
<field name="name"/>
<field name="maintenance_standards"/>
</tree>
</field>
<field name="maintenance_standards" widget="ony2many">
<tree>
<field name="name"/>
<field name="maintenance_standards"/>
<field name="images"/>
</tree>
</field>
</page>
</notebook>
@@ -45,7 +48,7 @@
<field name="context">{'default_user_id': uid}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
添加维保计划
添加维保计划
</p>
<p>
跟进请求的处理,并且和合作者沟通。
@@ -66,5 +69,32 @@
<field name="active" eval="False"/>
</record>
<!-- 维保项目表单视图-->
<record id="view_maintenance_standards_form" model="ir.ui.view">
<field name="name">maintenance.standards.form</field>
<field name="model">maintenance.standards</field>
<field name="arch" type="xml">
<form string="设备维保项目">
<sheet>
<group>
<field name="name"/>
<field name="maintenance_standards"/>
</group>
<notebook>
<page string="上传图片">
<field name="images" widget="one2many">
<tree editable="bottom">
<field name="image" widget="image" options="{'size': [100, 100], 'click enlarge': True}"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
</odoo>

View File

@@ -26,12 +26,12 @@
</header>
</xpath>
<xpath expr="//page[@name='maintenance']" position="attributes">
<attribute name="string">维保</attribute>
<attribute name="string">维保</attribute>
</xpath>
<xpath expr="//field[@name='maintenance_count']" position="attributes">
<attribute name="string">维保</attribute>
<attribute name="string">维保</attribute>
</xpath>
<!-- <field string="Maintenance" name="maintenance_count" widget="statinfo"/>-->
<!-- <field string="Maintenance" name="maintenance_count" widget="statinfo"/>-->
<xpath expr="//div[@name='button_box']" position="inside">
<button name="%(action_maintenance_logs)d"
@@ -284,12 +284,11 @@
<field name="machine_tool_picture"/>
</xpath>
<xpath expr="//templates" position="inside">
<xpath expr="//templates" position="inside">
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_global_click o_kanban_record_has_image_fill o_hr_kanban_record oe_kanban_card oe_kanban_global_click
#{record.state.raw_value == '正常' ? 'kanban_color_1' : ''}
#{record.state.raw_value == '故障' ? 'kanban_color_2' : ''}
#{record.state.raw_value == '不可用' ? 'kanban_color_3' : ''}">
<div t-attf-class="oe_kanban_global_click o_kanban_record_has_image_fill o_hr_kanban_record oe_kanban_card oe_kanban_global_click">
<field name="machine_tool_picture" class="o_kanban_image_fill_left d-block my-image"
preview_image="image_128" widget="image"/>
@@ -304,7 +303,13 @@
<div class="o_kanban_record_bottom state_zc">
<field name="state_zc"/>
</div>
<div class="o_kanban_record_bottom state_zc">
<div class="o_kanban_record_bottom state_zc">
<field name="technician_user_id"/>
</div>
<div class="o_kanban_record_bottom state_zc"
t-attf-class="#{record.state.raw_value == '正常' ? 'font_color_1' : ''}
#{record.state.raw_value == '故障' ? 'font_color_2' : ''}
#{record.state.raw_value == '不可用' ? 'font_color_3' : ''}">
<field name="state"/>
</div>
<!-- <div class="o_kanban_record_bottom">-->
@@ -313,7 +318,12 @@
<!-- <field name="supplier_id"/>-->
<!-- </div>-->
</div>
<div class="show_state" t-attf-class="oe_kanban_global_click o_kanban_record_has_image_fill o_hr_kanban_record oe_kanban_card oe_kanban_global_click
">
<div t-attf-class="#{record.state.raw_value == '正常' ? 'color_1' : ''}"></div>
<div t-attf-class="#{record.state.raw_value == '故障' ? 'color_2' : ''}"></div>
<div t-attf-class="#{record.state.raw_value == '不可用' ? 'color_3' : ''}"></div>
</div>
</div>
</t>
</xpath>

View File

@@ -9,7 +9,6 @@ class ResWorkcenter(models.Model):
# 生产线显示
production_line_show = fields.Char(string='生产线')
equipment_id = fields.Many2one('maintenance.equipment', string='设备')
machine_tool_id = fields.Many2one('sf.machine_tool', string='机床')
production_line_id = fields.Many2one('sf.production.line', string='生产线')
is_process_outsourcing = fields.Boolean('工艺外协')
@@ -19,6 +18,12 @@ class ResWorkcenter(models.Model):
'maintenance.equipment', string="设备",
check_company=True)
equipment_status = fields.Selection(
[("正常", "正常"), ("故障", "故障"), ("不可用", "不可用")],
string="设备状态", related='equipment_id.state')
equipment_image = fields.Binary('设备图片', related='equipment_id.machine_tool_picture')
# 查询工艺外协加工中心
def get_process_outsourcing_workcenter(self):
outsourcing_workcenter = self.env['mrp.workcenter'].search([('is_process_outsourcing', '=', True)])

View File

@@ -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

View File

@@ -24,19 +24,28 @@
</field>
</record>
<!-- <record id="mrp_workcenter_view_kanban_inherit_workorder" model="ir.ui.view">-->
<!-- <field name="name">mrp.workcenter.view.kanban.inherit.mrp.workorder</field>-->
<!-- <field name="model">mrp.workcenter</field>-->
<!-- <field name="inherit_id" ref="mrp.mrp_workcenter_kanban"/>-->
<!-- <field name="arch" type="xml">-->
<!-- &lt;!&ndash; Desktop view &ndash;&gt;-->
<!-- <xpath expr="//div[@name='o_wo']" position="inside">-->
<!-- <button class="btn btn-secondary fa fa-desktop" name="action_work_order" type="object"-->
<!-- context="{'search_default_ready': 1, 'search_default_progress': 1, 'search_default_pending': 1, 'desktop_list_view': 1, 'search_default_workcenter_id': active_id}"-->
<!-- title="Work orders" aria-label="Work orders"/>-->
<!-- </xpath>-->
<!-- </field>-->
<!-- </record>-->
<record id="mrp_workcenter_view_kanban_inherit_workorder" model="ir.ui.view">
<field name="name">mrp.workcenter.view.kanban.inherit.mrp.workorder</field>
<field name="model">mrp.workcenter</field>
<field name="inherit_id" ref="mrp.mrp_workcenter_kanban"/>
<field name="arch" type="xml">
<!-- Desktop view -->
<xpath expr='(//field[@name="name"])[1]' position="after">
<field name="equipment_status" />
<field name="equipment_image" />
</xpath>
<xpath expr='(//field[@name="name"])[2]' position="after">
<field name="equipment_status" />
<field name="equipment_image" widget="image" />
</xpath>
</field>
</record>
<!-- override to change the no content image -->
<record id="mrp.action_work_orders" model="ir.actions.act_window">
@@ -90,6 +99,7 @@
<field name="arch" type="xml">
<xpath expr="//field[@name='company_id']" position="after">
<field name="users_ids" widget="many2many_tags" string="可操作用户"/>
<field name="equipment_status"/>
</xpath>
<xpath expr="//field[@name='alternative_workcenter_ids']" position="after">
<field name="production_line_id"/>

View File

@@ -13,6 +13,7 @@ class ResConfigSettings(models.TransientModel):
token = fields.Char(string='TOKEN', default='b811ac06-3f00-11ed-9aed-0242ac110003')
sf_secret_key = fields.Char(string='密钥', default='wBmxej38OkErKhD6')
sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com')
bfm_url = fields.Char(string='业务平台后端访问地址', default='https://bfm.jikimo.com')
ftp_host = fields.Char(string='FTP的ip')
ftp_port = fields.Char(string='FTP端口')
ftp_user = fields.Char(string='FTP用户')
@@ -81,6 +82,7 @@ class ResConfigSettings(models.TransientModel):
token = config.get_param('token', default='')
sf_secret_key = config.get_param('sf_secret_key', default='')
sf_url = config.get_param('sf_url', default='')
bfm_url = config.get_param('bfm_url', default='')
ftp_host = config.get_param('ftp_host', default='')
ftp_port = config.get_param('ftp_port', default='')
ftp_user = config.get_param('ftp_user', default='')
@@ -90,6 +92,7 @@ class ResConfigSettings(models.TransientModel):
token=token,
sf_secret_key=sf_secret_key,
sf_url=sf_url,
bfm_url=bfm_url,
ftp_host=ftp_host,
ftp_port=ftp_port,
ftp_user=ftp_user,
@@ -103,6 +106,7 @@ class ResConfigSettings(models.TransientModel):
ir_config.set_param("token", self.token or "")
ir_config.set_param("sf_secret_key", self.sf_secret_key or "")
ir_config.set_param("sf_url", self.sf_url or "")
ir_config.set_param("bfm_url", self.bfm_url or "")
ir_config.set_param("ftp_host", self.ftp_host or "")
ir_config.set_param("ftp_port", self.ftp_port or "")
ir_config.set_param("ftp_user", self.ftp_user or "")

View File

@@ -1525,7 +1525,7 @@ class SyncFixtureModel(models.Model):
[('materials_no', '=', item['materials_model_code'])]).id,
"driving_way": item['driving_way'],
"apply_machine_tool_type_ids": self.env['sf.machine_tool.type'].sudo()._get_ids(
item['apply_machine_tool_type_code']).id,
item['apply_machine_tool_type_code']),
"through_hole_size": item['through_hole_size'],
"screw_size": item['screw_size'],
"active": item['active'],
@@ -1555,7 +1555,7 @@ class SyncFixtureModel(models.Model):
[('materials_no', '=', item['materials_model_code'])]).id,
"driving_way": item['driving_way'],
"apply_machine_tool_type_ids": self.env['sf.machine_tool.type'].sudo()._get_ids(
item['apply_machine_tool_type_code']).id,
item['apply_machine_tool_type_code']),
"through_hole_size": item['through_hole_size'],
"screw_size": item['screw_size'],
"active": item['active'],
@@ -1607,7 +1607,7 @@ class SyncFixtureModel(models.Model):
[('materials_no', '=', item['materials_model_code'])]).id,
"driving_way": item['driving_way'],
"apply_machine_tool_type_ids": self.env['sf.machine_tool.type'].sudo()._get_ids(
item['apply_machine_tool_type_code']).id,
item['apply_machine_tool_type_code']),
"through_hole_size": item['through_hole_size'],
"screw_size": item['screw_size'],
"active": item['active'],
@@ -1637,7 +1637,7 @@ class SyncFixtureModel(models.Model):
[('materials_no', '=', item['materials_model_code'])]).id,
"driving_way": item['driving_way'],
"apply_machine_tool_type_ids": self.env['sf.machine_tool.type'].sudo()._get_ids(
item['apply_machine_tool_type_code']).id,
item['apply_machine_tool_type_code']),
"through_hole_size": item['through_hole_size'],
"screw_size": item['screw_size'],
"active": item['active'],

View File

@@ -60,6 +60,20 @@
</div>
</div>
</div>
<div>
<h2>业务平台参数配置</h2>
<div class="row mt16 o_settings_container" id="pay_api">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<div class="text-muted">
<label for="bfm_url" string="访问地址"/>
<field name="bfm_url"/>
</div>
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>

View File

@@ -10,9 +10,12 @@
""",
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': ['sale', 'sale_management', 'web_widget_model_viewer'],
'depends': ['sale_management', 'web_widget_model_viewer',],
'data': [
'views/sale_order_view.xml'
'security/group_security.xml',
'security/ir.model.access.csv',
'views/sale_order_view.xml',
'views/quick_easy_order_view.xml'
],
'demo': [
],

View File

@@ -1 +1,5 @@
from. import sale_order
from . import sale_order
from . import quick_easy_order
from . import auto_quatotion_common

View File

@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
import logging
from odoo.modules import get_resource_path
from odoo import fields, models, api
from quatotion import readSql, feature_recognize, auto_quatotion
__author__ = 'jinling.yang'
_logger = logging.getLogger(__name__)
class AutoQuatotion(models.Model):
_name = 'sf.auto_quatotion.common'
_description = u'自动报价公用类'
# 获取feature.sqlite的地址
def get_feature_full_path(self):
return get_resource_path('sf_sale', 'models', 'feature.sqlite')
# 获取price.sqlite的地址
def get_price_full_path(self):
return get_resource_path('sf_sale', 'models', 'price.sqlite')
# 获取price.sqlite的地址
def get_process_time_db_path(self):
return get_resource_path('sf_sale', 'models', 'process_time.db')
def get_auto_quatotion(self, stp_url, feature_full_path, process_time_db_path, model_code):
'''
通过打包好的.so库
以调用autoQuatotion库中Quatotion类
初始化后调用类的analyseShape方法对模型文件进行价格预测
'''
# 初始化自动报价类(输入特征数据库和加工时间数据库)
reader = auto_quatotion.Quatotion(feature_full_path, process_time_db_path)
# 获取价格、加工时间、尺寸、XYZ、翻面次数
feature_info = reader.analyseShape(stp_url, InfoJson={})
return feature_info

Binary file not shown.

BIN
sf_sale/models/price.sqlite Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,280 @@
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):
_name = 'quick.easy.order'
_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('加工面', default='A')
model_feature = 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='加工精度', 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('数量', 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='模型文件')
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)
model_color_state = fields.Selection([
('success', '成功'),
('fail', '失败')], string='模型上色状态')
@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']))
obj = super(QuickEasyOrder, self).create(vals)
self.model_coloring()
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('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
# 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)
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)
else:
item.model_file = False
item.model_feature = False
item.model_length = 0
item.model_width = 0
item.model_height = 0
item.model_volume = 0
def distribute_to_factory(self, obj):
"""
派单到工厂
:return:
"""
web_base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url', default='')
logging.info("web_base_url: %s" % web_base_url)
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': item.model_length,
'model_width': item.model_width,
'model_height': item.model_height,
'model_volume': item.model_volume,
'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("分配工厂失败,请联系管理员")
# 特征识别
def feature_recognition(self, report_path, model_code):
feature_path = self.env['sf.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['sf.auto_quatotion.common'].sudo().get_process_time_db_path()
ret = self.env['sf.auto_quatotion.common'].sudo().get_auto_quatotion(report_path, feature_path,
process_time_db_path,
model_code)
return ret
# 模型上色
def model_coloring(self):
url = '/api/library_of_models/create'
config = self.env['res.config.settings'].get_values()
config_header = Common.get_headers(self, config['token'], config['sf_secret_key'])
order = self.search([('id', '=', self.id)])
logging.info('order: %s' % order.name)
if order:
attachment = order.upload_model_file[0]
base64_data = base64.b64encode(attachment.datas)
base64_datas = base64_data.decode('utf-8')
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
logging.info('model_file-size: %s' % len(order.model_file))
logging.info('attachment.datas-size: %s' % len(attachment.datas))
vals = {
'model_code': model_code,
'model_data': base64_data,
'model_name': attachment.name,
'model_long': order.model_length,
'model_width': order.model_width,
'model_height': order.model_height,
'model_volume': order.model_volume,
'model_order_no': order.name,
'remark': '订单号:%s 客户:%s' % (order.name, order.customer_id.name)
}
try:
ret = requests.post((config['sf_url'] + url), json={}, data=vals, headers=config_header,
timeout=60)
ret = ret.json()
# result = json.loads(ret['result'])
if ret['status'] == 1:
order.model_color_state = 'success'
else:
order.model_color_state = 'fail'
raise UserError(ret['message'])
except Exception as e:
order.model_color_state = 'fail'
raise UserError("模型上色失败")
# 自动报价
def _get_price(self, order):
url = '/api/automatic_quotes'
config = self.env['res.config.settings'].sudo().get_values()
config_header = Common.get_headers(self, config['token'], config['sf_secret_key'])
logging.info("报价接口..........% s" % order.name)
try:
if order:
vals = {}
# mrs合作伙伴token
vals['token'] = config['token']
vals['accuracy'] = order.machining_precision
vals['number'] = order.quantity
vals['process_code'] = 0
vals['texture_code'] = order.material_model_id.code
vals['delivery_days'] = 15
if order.model_file:
attachment = self.env['ir.attachment'].sudo().search(
[('id', '=', order.upload_model_file[0])])
vals['attachment_id'] = attachment.id
else:
vals['attachment_id'] = ''
vals['feature_infos'] = order.model_feature
vals['model_long'] = order.model_length
vals['model_width'] = order.model_width
vals['model_height'] = order.model_height
logging.info('vals:%s' % vals)
ret = requests.post((config['sf_url'] + url), json={}, data=vals, headers=config_header)
result = json.dumps(json.loads(ret.text), ensure_ascii=False, indent=4, separators=(',', ':'))
logging.info('报价接口返回:%s' % result)
price_result = json.loads(result)
# random.randint(0, 10000)
order.write({'price': price_result.get('price')})
else:
raise UserError("订单不存在")
except Exception as e:
if ret['status'] != 1:
raise UserError(e)
else:
raise UserError("自动报价失败,请联系管理员")

View File

@@ -0,0 +1,4 @@
<odoo>
<data>
</data>
</odoo>

View 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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_quick_easy_order quick_easy_order model_quick_easy_order base.group_user 1 1 1 1

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<record id="sequence_quick_easy_order" model="ir.sequence">
<field name="name">快速订单编码规则</field>
<field name="code">quick.easy.order</field>
<field name="prefix">FP-%(year)s-%(month)s%(day)s-</field>
<field name="padding">4</field>
</record>
# ---------- 快速订单 ------------
<record model="ir.ui.view" id="tree_quick_easy_order_view">
<field name="name">tree.quick.easy.order</field>
<field name="model">quick.easy.order</field>
<field name="arch" type="xml">
<tree string="快速订单">
<field optional="show" name="name" string="订单号"/>
<field optional="show" name="customer_id" string="客户"/>
<field optional="show" name="material_id"/>
<field optional="show" name="material_model_id"/>
<field optional="show" name="process_id"/>
<field optional="show" name="quantity"/>
<field optional="show" name="price"/>
<field optional="hide" name="delivery_time"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="form_quick_easy_order_view">
<field name="name">form.quick.easy.order</field>
<field name="model">quick.easy.order</field>
<field name="arch" type="xml">
<form string="快速订单">
<sheet>
<h1>
<field name="name" readonly="True"/>
</h1>
<group>
<group>
<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" 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)]}"/>
<label for="model_length" string="尺寸(mm)"
attrs='{"invisible": [("model_file","=",False)]}'/>
<div class="test_model"
attrs='{"invisible": [("model_file","=",False)]}'>
<label for="model_length" string="长"/>
<field name="model_length" class="o_address_zip"
options="{'format': false}"/>
<label for="model_width" string="宽"/>
<field name="model_width" class="o_address_zip"
options="{'format': false}"/>
<label for="model_height" string="高"/>
<field name="model_height" class="o_address_zip"
options="{'format': false}"/>
</div>
<field name="model_volume" attrs="{'invisible': [('model_file', '=', False)]}"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="search_quick_easy_order_view">
<field name="name">search.quick.easy.order</field>
<field name="model">quick.easy.order</field>
<field name="arch" type="xml">
<search string="快速订单">
<field name="name" string="模糊搜索"
filter_domain="['|', ('name', 'ilike', self), '|', ('receive_name', 'ilike', self),'|', ('receive_phone', 'ilike', self),('customer_id', 'ilike', self)]"/>
<separator/>
<field name="customer_id"/>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_quick_easy_order">
<field name="name">快速订单</field>
<field name="res_model">quick.easy.order</field>
<field name="view_mode">tree,form</field>
<field name="domain">[]</field>
<field name="context">{}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
[快速订单] 还没有哦!点左上角的[创建]按钮,沙发归你了!
</p>
<p>
</p>
</field>
</record>
<!-- <menuitem id="res_partner_menu"-->
<!-- action="account.res_partner_action_customer"-->
<!-- groups="sales_team.group_sale_salesman"-->
<!-- sequence="40"/>-->
<menuitem sequence="21" name="快速订单" id="menu_quick_easy_order"
action="action_quick_easy_order"
parent="sale.sale_order_menu"
groups="sales_team.group_sale_salesman"/>
</data>
</odoo>

View File

@@ -1,14 +1,14 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { _lt } from "@web/core/l10n/translation";
import { standardFieldProps } from "@web/views/fields/standard_field_props";
import { useInputField } from "@web/views/fields/input_field_hook";
import { FileUploader } from "@web/views/fields/file_handler";
import { session } from "@web/session";
import { useService } from "@web/core/utils/hooks";
import { isBinarySize } from "@web/core/utils/binary";
import { download } from "@web/core/network/download";
import {registry} from "@web/core/registry";
import {_lt} from "@web/core/l10n/translation";
import {standardFieldProps} from "@web/views/fields/standard_field_props";
import {useInputField} from "@web/views/fields/input_field_hook";
import {FileUploader} from "@web/views/fields/file_handler";
import {session} from "@web/session";
import {useService} from "@web/core/utils/hooks";
import {isBinarySize} from "@web/core/utils/binary";
import {download} from "@web/core/network/download";
import utils from 'web.utils';
import core from 'web.core';
@@ -16,13 +16,14 @@ import rpc from 'web.rpc';
var QWeb = core.qweb;
import { Component, onWillUpdateProps, useState, useRef, useEffect } from "@odoo/owl";
import {Component, onWillUpdateProps, useState, useRef, useEffect} from "@odoo/owl";
export class StepViewer extends Component {
setup() {
this.props.url = this.formatUrl();
}
formatUrl(){
formatUrl() {
var url = '';
if (this.props.value) {
if (this.props.value.slice(-1) == 'b' && !isNaN(this.props.value.split(' ')[0])) {
@@ -30,23 +31,27 @@ export class StepViewer extends Component {
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'].replace('http://', 'https://') +'/web/content/'+url_props['model']+'/'+url_props['id']+'/'+url_props['field']+'?download=true'
field: this.props.name
}
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)
console.log('url111111', url)
return url
} else {
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";
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";
}
} else {
var oImg = document.getElementsByClassName('test')[0]
console.log(oImg)
}
}
}
}
StepViewer.template = "web_widget_model_viewer.BinaryField3d";
@@ -56,10 +61,10 @@ StepViewer.supportedTypes = ["binary"];
StepViewer.props = {
...standardFieldProps,
url: { type: String, optional: true },
url: {type: String, optional: true},
};
StepViewer.extractProps = ({ attrs }) => {
StepViewer.extractProps = ({attrs}) => {
return {
url: attrs.options.url,
};

View File

@@ -2,37 +2,42 @@
<templates xml:space="preserve">
<t t-name="web_widget_model_viewer.BinaryField3d" owl="1">
<model-viewer
t-att-src='props.url'
name="3D model"
alt="3D model"
auto-rotate="1"
camera-controls="1"
style ="background-color: #0D1D54;"
>
<t t-if="props.value">
<model-viewer
t-att-src='props.url'
name="3D model"
alt="3D model"
auto-rotate="1"
camera-controls="1"
style="background-color: #0D1D54;"
>
<!-- <div class="text-center mt-4 mb-4 mr-4">-->
<!-- <span-->
<!-- id="model-viewer-fullscreen"-->
<!-- title="View fullscreen"-->
<!-- role="img"-->
<!-- aria-label="Fullscreen"-->
<!-- >-->
<!-- <i class="fa fa-arrows-alt fa-2x"/>-->
<!-- </span>-->
<!-- </div>-->
</model-viewer>
<!-- <model-viewer-->
<!-- src='/jikimo_model_viewer/static/src/js/3d_viewer/test.glb'-->
<!-- name="Test 3D model"-->
<!-- alt="Test 3D model"-->
<!-- auto-rotate="1"-->
<!-- camera-controls="1"-->
<!-- />-->
<!-- <span-->
<!-- id="model-viewer-fullscreen"-->
<!-- title="View fullscreen"-->
<!-- role="img"-->
<!-- aria-label="Fullscreen"-->
<!-- >-->
<!-- <i class="fa fa-arrows-alt fa-2x"/>-->
<!-- </span>-->
<!-- </div>-->
</model-viewer>
</t>
<t t-if="!props.value">
<div style="color:#D23F3A">当前制造订单暂无模型</div>
</t>
<!-- <model-viewer-->
<!-- src='/jikimo_model_viewer/static/src/js/3d_viewer/test.glb'-->
<!-- name="Test 3D model"-->
<!-- alt="Test 3D model"-->
<!-- auto-rotate="1"-->
<!-- camera-controls="1"-->
<!-- />-->
<script type="module"
src="/web_widget_model_viewer/static/src/lib/model-viewer.min.js">
src="/web_widget_model_viewer/static/src/lib/model-viewer.min.js">
</script>
</t>