diff --git a/sf_base/models/base.py b/sf_base/models/base.py index 5762822e..a6e1d4cc 100644 --- a/sf_base/models/base.py +++ b/sf_base/models/base.py @@ -77,6 +77,7 @@ class MachineTool(models.Model): b_axis = fields.Integer('B轴') c_axis = fields.Integer('C轴') remark = fields.Text('备注') + is_binding = fields.Boolean('是否绑定机床', default=False) precision = fields.Float('加工精度') control_system_id = fields.Many2one('sf.machine.control_system', string="控制系统") diff --git a/sf_bf_connect/controllers/controllers.py b/sf_bf_connect/controllers/controllers.py index 4b352dcf..5227592f 100644 --- a/sf_bf_connect/controllers/controllers.py +++ b/sf_bf_connect/controllers/controllers.py @@ -8,7 +8,7 @@ from odoo.http import request class Sf_Bf_Connect(http.Controller): - @http.route('/api/bfm_process_order/list', type='json', auth='none', methods=['GET', 'POST'], csrf=False, + @http.route('/api/bfm_process_order/list', type='http', auth='none', methods=['GET', 'POST'], csrf=False, cors="*") def get_bfm_process_order_list(self, **kw): """ @@ -19,9 +19,9 @@ class Sf_Bf_Connect(http.Controller): res = {'status': 1, 'factory_order_no': ''} logging.info('get_bfm_process_order_list:%s' % kw) try: - datas = request.httprequest.data - ret = json.loads(datas) - ret = json.loads(ret['result']) + # datas = request.httprequest.data + # ret = json.loads(datas) + # ret = json.loads(ret['result']) product_id = request.env.ref('sf_dlm.product_template_sf').sudo() logging.info('product_id:%s' % product_id) self_machining_id = request.env.ref('sf_dlm.product_embryo_sf_self_machining').sudo() @@ -30,13 +30,20 @@ class Sf_Bf_Connect(http.Controller): company_id = request.env.ref('base.main_company').sudo() user_id = request.env.ref('base.user_admin').sudo() logging.info('user_id:%s' % user_id) + bfm_process_order_list = json.loads(kw['bfm_process_order_list']) order_id = request.env['sale.order'].with_user(request.env.ref("base.user_admin")).sale_order_create( - company_id, ret['delivery_name'], ret['delivery_telephone'], ret['delivery_address'], - ret['delivery_end_date'], user_id) + company_id, kw['delivery_name'], kw['delivery_telephone'], kw['delivery_address'], + kw['delivery_end_date'], user_id) i = 1 - for item in ret['bfm_process_order_list']: + for item in bfm_process_order_list: + # product_has = request.env['product.template'].with_user(request.env.ref("base.user_admin")).search([('barcode','=', item['barcode'])]) + # if product_has: + # logging.info('product_has:%s' % product_has) + # logging.info('barcode:%s' % item['barcode']) + # order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product_has, item) + # else: product = request.env['product.template'].sudo().product_create(product_id, item, order_id, - ret['order_number'], i) + kw['order_number'], i) # order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item) logging.info('order_id:%s' % order_id) logging.info('product:%s' % product) @@ -57,7 +64,7 @@ class Sf_Bf_Connect(http.Controller): # 创建胚料的bom self_machining_bom = request.env['mrp.bom'].with_user( request.env.ref("base.user_admin")).bom_create( - self_machining_embryo, 'normal') + self_machining_embryo, 'normal', False) # 创建胚料里bom的组件 self_machining_bom.with_user(request.env.ref("base.user_admin")).bom_create_line( self_machining_embryo) @@ -95,9 +102,8 @@ class Sf_Bf_Connect(http.Controller): product_bom_purchase.with_user(request.env.ref("base.user_admin")).bom_create_line_has( purchase_embryo) order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item) - i += 1 + i += 1 res['factory_order_no'] = order_id.name - return json.JSONEncoder().encode(res) except Exception as e: logging.info('get_bfm_process_order_list error:%s' % e) res['status'] = -1 diff --git a/sf_dlm/__manifest__.py b/sf_dlm/__manifest__.py index 3400d984..27518d9f 100644 --- a/sf_dlm/__manifest__.py +++ b/sf_dlm/__manifest__.py @@ -10,7 +10,7 @@ """, 'category': 'sf', 'website': 'https://www.sf.jikimo.com', - 'depends': ['mrp', 'base', 'sf_manufacturing', 'purchase', 'mrp_subcontracting'], + 'depends': ['mrp', 'base', 'sf_manufacturing', 'web_widget_model_viewer', 'purchase', 'mrp_subcontracting'], 'data': [ 'data/product_data.xml', 'views/product_template_view.xml' diff --git a/sf_dlm/data/product_data.xml b/sf_dlm/data/product_data.xml index e3ecbfae..aad3714c 100644 --- a/sf_dlm/data/product_data.xml +++ b/sf_dlm/data/product_data.xml @@ -15,7 +15,7 @@ 原材料 - + CNC加工产品模板 @@ -31,7 +31,7 @@ serial - + 胚料自加工模板 @@ -48,7 +48,7 @@ - + 胚料外协加工模板 @@ -63,7 +63,7 @@ serial - + 胚料采购模板 diff --git a/sf_dlm/models/product_template.py b/sf_dlm/models/product_template.py index 25420671..885e0c26 100644 --- a/sf_dlm/models/product_template.py +++ b/sf_dlm/models/product_template.py @@ -1,12 +1,16 @@ from odoo import models, fields, api from odoo.exceptions import ValidationError import logging - +import base64 +import os +from OCC.Extend.DataExchange import read_step_file, write_stl_file +from odoo.modules import get_resource_path class ResProductTemplate(models.Model): _inherit = 'product.template' # 模型的长,宽,高,体积,精度,材料 + model_name = fields.Char('模型名称') model_long = fields.Float('模型长[mm]', digits=(16, 3)) model_width = fields.Float('模型宽[mm]', digits=(16, 3)) model_height = fields.Float('模型高[mm]', digits=(16, 3)) @@ -29,6 +33,8 @@ class ResProductTemplate(models.Model): materials_id = fields.Many2one('sf.production.materials', string='材料') materials_type_id = fields.Many2one('sf.materials.model', string='材料型号') single_manufacturing = fields.Boolean(string="单个制造") + upload_model_file = fields.Many2many('ir.attachment', 'upload_model_file_attachment_ref', string='上传模型文件') + model_file = fields.Binary('模型文件') # 胚料的库存路线设置 # def _get_routes(self, route_type): @@ -53,20 +59,28 @@ class ResProductTemplate(models.Model): # 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品 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 + 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' % (order_id.name, i), - 'model_long': item['model_long'], - 'model_width': item['model_width'], - 'model_height': item['model_height'], + '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), 'model_type_id': 1, - 'model_machining_precision': item['model_machining_precision'], - 'model_processing_panel': 'R,U', + # 'model_machining_precision': item['model_machining_precision'], + 'model_processing_panel': 'A', + 'model_machining_precision': '±0.10mm', 'length': item['model_long'], 'width': item['model_width'], 'height': item['model_height'], - 'volume': (item['model_long'] * item['model_width'] * item['model_height']), - # 'model_price': item['price'], + 'volume': item['model_long'] * item['model_width'] * item['model_height'], + 'model_file': base64.b64decode(item['model_file']), + 'model_name': attachment.name, + 'upload_model_file': [(6, 0, [attachment.id])], # 'single_manufacturing': True, 'list_price': item['price'], # 'categ_id': self.env.ref('sf_dlm.product_category_finished_sf').id, @@ -74,38 +88,51 @@ class ResProductTemplate(models.Model): [('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_id': self.env['sf.production.process'].search( - # [('process_encode', '=', item['surface_process_code'])]).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, 'model_remark': item['remark'], 'default_code': '%s-%s' % (order_number, i), - 'barcode': item['barcode'], + #'barcode': item['barcode'], 'active': True, # 'route_ids': self._get_routes('') } copy_product_id.sudo().write(vals) - # product_id.active = False + print(len(copy_product_id.model_file)) + product_id.product_tmpl_id.active = False return copy_product_id + def attachment_create(self, name, data): + attachment = self.env['ir.attachment'].create({ + 'datas': base64.b64decode(data), + 'type': 'binary', + 'description': '模型文件', + 'name': name + }) + return attachment + # 创建胚料 def no_bom_product_create(self, product_id, item, order_id, route_type): 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 + 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' % ( order_id.name, materials_id.name, materials_type_id.name, item['model_long'], item['model_width'], item['model_height']), - 'length': item['model_long'], - 'width': item['model_width'], - 'height': item['model_height'], - 'volume': item['model_long'] * item['model_width'] * item['model_height'], + '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), # 'model_price': item['price'], 'list_price': item['price'], 'materials_id': materials_id.id, @@ -131,22 +158,32 @@ class ResProductTemplate(models.Model): logging.info('no_bom_copy_product_id-seller_ids-vals:%s' % no_bom_copy_product_id.seller_ids) no_bom_copy_product_id.write(vals) logging.info('no_bom_copy_product_id-vals:%s' % vals) - # product_id.active = False + product_id.product_tmpl_id.active = False return no_bom_copy_product_id - # 根据模型类型默认给模型的长高宽加配置的长度; - @api.onchange('model_type_id') - def add_product_size(self): - if not self.model_type_id: - return - model_type = self.env['sf.model.type'].search( - [('id', '=', self.model_type_id.id), ('embryo_tolerance', '=', True)]) - if model_type: - self.model_long = self.model_long + 1 - self.model_width = self.model_width + 1 - self.model_height = self.model_width + 1 - else: - return + @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] + item.model_name = file_attachment_id.name + # 附件路径 + report_path = file_attachment_id._full_path(file_attachment_id.store_fname) + shapes = read_step_file(report_path) + output_file = get_resource_path('sf_dlm', 'static/file', 'out.stl') + write_stl_file(shapes, output_file, 'binary', 0.03, 0.5) + # 转化为glb + output_glb_file = get_resource_path('sf_dlm', 'static/file', 'out.glb') + util_path = get_resource_path('sf_dlm', 'static/util') + cmd = 'python %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) + item.model_file = base64_data class ResMrpBom(models.Model): diff --git a/sf_dlm/static/file/out.glb b/sf_dlm/static/file/out.glb new file mode 100644 index 00000000..c4a6352b Binary files /dev/null and b/sf_dlm/static/file/out.glb differ diff --git a/sf_dlm/static/file/out.stl b/sf_dlm/static/file/out.stl new file mode 100644 index 00000000..4f8b834a Binary files /dev/null and b/sf_dlm/static/file/out.stl differ diff --git a/sf_dlm/static/util/stl2gltf.py b/sf_dlm/static/util/stl2gltf.py new file mode 100644 index 00000000..1bdcc942 --- /dev/null +++ b/sf_dlm/static/util/stl2gltf.py @@ -0,0 +1,277 @@ +import os + +def stl_to_gltf(binary_stl_path, out_path, is_binary): + import struct + + gltf2 = ''' +{ + "scenes" : [ + { + "nodes" : [ 0 ] + } + ], + "nodes" : [ + { + "mesh" : 0 + } + ], + "meshes" : [ + { + "primitives" : [ { + "attributes" : { + "POSITION" : 1 + }, + "indices" : 0 + } ] + } + ], + "buffers" : [ + { + %s + "byteLength" : %d + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteOffset" : 0, + "byteLength" : %d, + "target" : 34963 + }, + { + "buffer" : 0, + "byteOffset" : %d, + "byteLength" : %d, + "target" : 34962 + } + ], + "accessors" : [ + { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5125, + "count" : %d, + "type" : "SCALAR", + "max" : [ %d ], + "min" : [ 0 ] + }, + { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : %d, + "type" : "VEC3", + "min" : [%f, %f, %f], + "max" : [%f, %f, %f] + } + ], + "asset" : { + "version" : "2.0" + } +} +''' + + header_bytes = 80 + unsigned_long_int_bytes = 4 + float_bytes = 4 + vec3_bytes = 4 * 3 + spacer_bytes = 2 + num_vertices_in_face = 3 + + vertices = {} + indices = [] + + if not is_binary: + out_bin = os.path.join(out_path, "out.bin") + out_gltf = os.path.join(out_path, "out.gltf") + else: + out_bin = out_path + + unpack_face = struct.Struct("<12fH").unpack + face_bytes = float_bytes*12 + 2 + + with open(path_to_stl, "rb") as f: + f.seek(header_bytes) # skip 80 bytes headers + + num_faces_bytes = f.read(unsigned_long_int_bytes) + number_faces = struct.unpack(" maxx: maxx = x + if y < miny: miny = y + if y > maxy: maxy = y + if z < minz: minz = z + if z > maxz: maxz = z + + # f.seek(spacer_bytes, 1) # skip the spacer + + number_vertices = len(vertices) + vertices_bytelength = number_vertices * vec3_bytes # each vec3 has 3 floats, each float is 4 bytes + unpadded_indices_bytelength = number_vertices * unsigned_long_int_bytes + + out_number_vertices = len(vertices) + out_number_indices = len(indices) + + unpadded_indices_bytelength = out_number_indices * unsigned_long_int_bytes + indices_bytelength = (unpadded_indices_bytelength + 3) & ~3 + + out_bin_bytelength = vertices_bytelength + indices_bytelength + + if is_binary: + out_bin_uir = "" + else: + out_bin_uir = '"uri": "out.bin",' + + gltf2 = gltf2 % ( out_bin_uir, + #buffer + out_bin_bytelength, + + # bufferViews[0] + indices_bytelength, + + # bufferViews[1] + indices_bytelength, + vertices_bytelength, + + # accessors[0] + out_number_indices, + out_number_vertices - 1, + + # accessors[1] + out_number_vertices, + minx, miny, minz, + maxx, maxy, maxz + ) + + glb_out = bytearray() + if is_binary: + gltf2 = gltf2.replace(" ", "") + gltf2 = gltf2.replace("\n", "") + + scene = bytearray(gltf2.encode()) + + scene_len = len(scene) + padded_scene_len = (scene_len + 3) & ~3 + body_offset = padded_scene_len + 12 + 8 + + file_len = body_offset + out_bin_bytelength + 8 + + # 12-byte header + glb_out.extend(struct.pack(' 3: + is_binary = True + else: + is_binary = False + + if out_path.lower().endswith(".glb"): + print("Use binary mode since output file has glb extension") + is_binary = True + else: + if is_binary: + print("output file should have glb extension but not %s", out_path) + + if not os.path.exists(path_to_stl): + print("stl file does not exists %s" % path_to_stl) + + if not is_binary: + if not os.path.isdir(out_path): + os.mkdir(out_path) + + stl_to_gltf(path_to_stl, out_path, is_binary) \ No newline at end of file diff --git a/sf_dlm/views/product_template_view.xml b/sf_dlm/views/product_template_view.xml index f363f0b2..c563f728 100644 --- a/sf_dlm/views/product_template_view.xml +++ b/sf_dlm/views/product_template_view.xml @@ -6,7 +6,13 @@ product.template + + + + + + @@ -101,8 +107,8 @@ - + diff --git a/sf_manufacturing/models/model_type.py b/sf_manufacturing/models/model_type.py index bdc5fc78..ecc4b7af 100644 --- a/sf_manufacturing/models/model_type.py +++ b/sf_manufacturing/models/model_type.py @@ -6,7 +6,7 @@ class ModelType(models.Model): _description = '模型类型' name = fields.Char('名称') - embryo_tolerance = fields.Boolean('胚料的容余量', default=False) + embryo_tolerance = fields.Integer('胚料的容余量') routing_tmpl_ids = fields.One2many('sf.model.type.routing.sort', 'model_type_id', '工序模板') diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 55cd0ca4..036bf969 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -from odoo import api, fields, models,_ - +from odoo import api, fields, models, _ class MrpProduction(models.Model): @@ -10,6 +9,8 @@ class MrpProduction(models.Model): tray_ids = fields.One2many('sf.tray', 'production_id', string="托盘") maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests") request_ids = fields.One2many('maintenance.request', 'production_id') + # model_file = fields.Binary('模型文件', related='product_id.model_file') + # model_information = fields.Char('模型信息', related='product_id.model_information') @api.depends('request_ids') def _compute_maintenance_count(self): @@ -130,6 +131,9 @@ class MrpProduction(models.Model): 'location_src_id': production.location_src_id.id, 'location_dest_id': production.location_dest_id.id, 'bom_id': production.bom_id.id, + 'model_file': base64.b64decode(production.product_id.model_file), + 'model_information': '%s/%s' % ( + production.product_id.model_processing_panel, production.product_id.materials_id.name), 'date_deadline': production.date_deadline, 'date_planned_start': production.date_planned_start, 'date_planned_finished': production.date_planned_finished, diff --git a/sf_manufacturing/models/mrp_workcenter.py b/sf_manufacturing/models/mrp_workcenter.py index ad7a0419..db7db216 100644 --- a/sf_manufacturing/models/mrp_workcenter.py +++ b/sf_manufacturing/models/mrp_workcenter.py @@ -7,6 +7,12 @@ class ResWorkcenter(models.Model): _inherit = "mrp.workcenter" machine_tool_id = fields.Many2one('sf.machine_tool', '机床') + @api.onchange('machine_tool_id') + def get_machine_tool_is_binding(self): + print('1111111') + for item in self: + item.machine_tool_id.is_binding = False + equipment_ids = fields.One2many( 'maintenance.equipment', 'workcenter_id', string="Maintenance Equipment", check_company=True) diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 2fb49715..a478438f 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -29,6 +29,8 @@ class ResMrpWorkOrder(models.Model): ('后置三元质量检测', '后置三元质量检测'), ('解除装夹', '解除装夹'), ], string="工序类型") + programming_no = fields.Char('编程单号') + is_programming = fields.Boolean('是否编程', default=False) cnc_worksheet = fields.Binary( '工作指令', readonly=True) material_center_point = fields.Char(string='配料中心点') @@ -245,20 +247,21 @@ class ResMrpWorkOrder(models.Model): 'embryo_long': cnc.product_id.bom_ids.bom_line_ids.product_id.length, 'embryo_height': cnc.product_id.bom_ids.bom_line_ids.product_id.height, 'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width, - 'order_no': cnc.production_id.origin - # 'factory_code': self.env.user.company_id.partner_id. + 'order_no': cnc.production_id.origin, + 'user': self.env.user.name, + 'model_file': base64.b64encode(cnc.product_id.model_file).decode('utf-8') } logging.info('res:%s' % res) configsettings = self.env['res.config.settings'].get_values() config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key']) url = '/api/intelligent_programming/create' config_url = configsettings['sf_url'] + url - res_str = json.dumps(res) - ret = requests.post(config_url, json={"result": res_str}, data=None, headers=config_header) + # res_str = json.dumps(res) + ret = requests.post(config_url, json={}, data=res, headers=config_header) ret = ret.json() result = json.loads(ret['result']) if result['status'] == 1: - return self.write({'state': 'progress'}) + return self.write({'programming_no': result['programming_no'], 'is_programming': True}) def json_workorder_str1(self, k, production, route): workorders_values_str = [0, '', { @@ -341,13 +344,13 @@ class CNCprocessing(models.Model): depth_of_processing_z = fields.Char('加工深度(Z)') cutting_tool_extension_length = fields.Char('刀具伸出长度') cutting_tool_handle_type = fields.Char('刀柄型号') - estimated_processing_time = fields.Datetime('预计加工时间') + estimated_processing_time = fields.Char('预计加工时间') remark = fields.Text('备注') workorder_id = fields.Many2one('mrp.workorder', string="工单") # mrs下发编程单创建CNC加工 def cnc_processing_create(self, obj): - workorder = self.env['mrp.workorder'].search([('production_id.name', '=', obj['manufacturing_order_no']), + workorder = self.env['mrp.workorder'].search([('production_id.name', '=', obj['production_order_no']), ('processing_panel', '=', obj['processing_panel']), ('routing_type', '=', 'CNC加工')]) vals = { diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index cf1433f7..487f69ed 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -74,13 +74,17 @@ class StockRule(models.Model): Procurement = namedtuple('Procurement', ['product_id', 'product_qty', 'product_uom', 'location_id', 'name', 'origin', 'company_id', - 'values']) + 'values', 'model_file', + 'model_information']) s = Procurement(product_id=item[0].product_id, product_qty=1.0, product_uom=item[0].product_uom, location_id=item[0].location_id, name=item[0].name, origin=item[0].origin, company_id=item[0].company_id, values=item[0].values, + model_file=base64.b64decode(item[0].product_id.model_file), + model_information='%s/%s' % (item[0].product_id.model_processing_panel, + item[0].product_id.materials_id.name), ) item1 = list(item) item1[0] = s diff --git a/sf_manufacturing/models/tray.py b/sf_manufacturing/models/tray.py index 08906217..bdea35c4 100644 --- a/sf_manufacturing/models/tray.py +++ b/sf_manufacturing/models/tray.py @@ -3,7 +3,7 @@ import base64 from io import BytesIO from odoo import api, fields, models, SUPERUSER_ID, _ -from pystrich.code128 import Code128Encoder +# from pystrich.code128 import Code128Encoder class Tray(models.Model): diff --git a/sf_manufacturing/views/model_type_view.xml b/sf_manufacturing/views/model_type_view.xml index 58fd70be..58d1bf94 100644 --- a/sf_manufacturing/views/model_type_view.xml +++ b/sf_manufacturing/views/model_type_view.xml @@ -31,7 +31,7 @@
- + diff --git a/sf_manufacturing/views/mrp_workcenter_views.xml b/sf_manufacturing/views/mrp_workcenter_views.xml index 11777e58..d500e3b6 100644 --- a/sf_manufacturing/views/mrp_workcenter_views.xml +++ b/sf_manufacturing/views/mrp_workcenter_views.xml @@ -81,7 +81,7 @@ - + diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml index 9049f5d2..60ba9a8b 100644 --- a/sf_manufacturing/views/mrp_workorder_view.xml +++ b/sf_manufacturing/views/mrp_workorder_view.xml @@ -57,6 +57,10 @@ mrp.workorder + + +
@@ -73,10 +77,10 @@ -
-
+
+
@@ -222,25 +226,25 @@ - +
-
+
-
-
-
-
+
+
+
+
diff --git a/sf_mrs_connect/controllers/controllers.py b/sf_mrs_connect/controllers/controllers.py index 969cdeb2..76fc34c5 100644 --- a/sf_mrs_connect/controllers/controllers.py +++ b/sf_mrs_connect/controllers/controllers.py @@ -32,20 +32,32 @@ class Sf_Mrs_Connect(http.Controller): logging.info('model_code:%s' % model_code) server_dir = cnc.with_user(request.env.ref("base.user_admin")).download_file_tmp(model_code, processing_panel) - cnc_file_path = os.path.join('/', server_dir, cnc.program_name + '.nc') - logging.info('cnc_file_path:%s' % cnc_file_path) - cnc.with_user(request.env.ref("base.user_admin")).write_file(cnc_file_path, cnc) - logging.info('get_cnc_processing_create:%s' % '111111111111111') - # for root, dirs, files in os.walk(server_dir): - # for f in files: - # if os.path.splitext(f)[1] == ".pdf": - # pdf_path = os.path.splitext(file)[1] + '.PDF' - # - # if pdf_path != False: - # if not cnc.workorder_id.cnc_worksheet: - # cnc.workorder_id.cnc_worksheet = base64.b64encode(open(cnc_pdf_path, 'rb').read()) - # else: - # logging.info('break:%s' % 'break') - # break + # cnc_file_path = os.path.join('/', server_dir, cnc.program_name + '.nc') + # logging.info('cnc_file_path:%s' % cnc_file_path) + # cnc.with_user(request.env.ref("base.user_admin")).write_file(cnc_file_path, cnc) + logging.info('server_dir:%s' % server_dir) + for root, dirs, files in os.walk(server_dir): + for f in files: + logging.info('f:%s' % f) + logging.info('f[0]:%s' % f.split('.')[0]) + if os.path.splitext(f)[1] == ".pdf": + full_path = os.path.join(server_dir, root, f) + logging.info('pdf:%s' % full_path) + if full_path != False: + if not cnc.workorder_id.cnc_worksheet: + cnc.workorder_id.cnc_worksheet = base64.b64encode(open(full_path, 'rb').read()) + else: + logging.info('break:%s' % 'break') + continue + else: + logging.info('cnc.program_name:%s' % cnc.program_name) + if cnc.program_name == f.split('.')[0]: + logging.info('f[0]:%s' % f[0]) + cnc_file_path = os.path.join(server_dir, root, f) + logging.info('cnc_file_path:%s' % cnc_file_path) + cnc.with_user(request.env.ref("base.user_admin")).write_file(cnc_file_path, cnc) + else: + continue + except Exception as e: logging.info('get_cnc_processing_create error:%s' % e) diff --git a/sf_mrs_connect/models/ftp_operate.py b/sf_mrs_connect/models/ftp_operate.py index a71ee83f..655c50e6 100644 --- a/sf_mrs_connect/models/ftp_operate.py +++ b/sf_mrs_connect/models/ftp_operate.py @@ -25,15 +25,16 @@ class FtpController(): # 下载目录下的文件 def download_file_tree(self, target_dir, serverdir): - self.ftp.cwd(target_dir) # 切换工作路径 if not os.path.exists(serverdir): os.makedirs(serverdir) - remotenames = self.ftp.nlst() - for file in remotenames: - server = os.path.join(serverdir, file) - if file.find(".") != -1: - self.download_file(server, file) - return + self.ftp.cwd(target_dir) # 切换工作路径 + remotenames = self.ftp.nlst() + for file in remotenames: + server = os.path.join(serverdir, file) + if file.find(".") != -1: + self.download_file(server, file) + else: + return # 下载指定目录下的指定文件 def download_file(self, serverfile, remotefile): diff --git a/sf_sale/models/sale_order.py b/sf_sale/models/sale_order.py index 9bf6f2b1..899e2126 100644 --- a/sf_sale/models/sale_order.py +++ b/sf_sale/models/sale_order.py @@ -44,6 +44,7 @@ class ReSaleOrder(models.Model): product.model_machining_precision, product.materials_id.name), 'price_unit': product.list_price, + 'route_id': product.route_ids, 'product_uom_qty': item['number'] } return self.env['sale.order.line'].create(vals) diff --git a/web_widget_model_viewer/README.rst b/web_widget_model_viewer/README.rst new file mode 100644 index 00000000..82cacf22 --- /dev/null +++ b/web_widget_model_viewer/README.rst @@ -0,0 +1,126 @@ +=================== +Model viewer widget +=================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github + :target: https://github.com/OCA/web/tree/14.0/web_widget_model_viewer + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-14-0/web-14-0-web_widget_model_viewer + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/162/14.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +```` is a web component that makes rendering interactive 3D models - optionally in AR - easy to do, on as many browsers and devices as possible. ```` strives to give you great defaults for rendering quality and performance. + +See `source repository `_ and `documentation `_. + +The model to load is a GLTF 2.0 file format. + +See ``_ and GLTF overview: + +.. figure:: https://raw.githubusercontent.com/OCA/web/14.0/web_widget_model_viewer/static/img/gltfOverview.png + +Many engine developers have already started transitioning to glTF 2.0 to reap performance, portability and quality benefits, including BabylonJS, three.js, Cesium, Sketchfab, and xeogl and instant3Dhub engines. glTF 2.0 is also seeing industry support by companies such as Adobe, Google, Marmoset, Microsoft, NVIDIA, Oculus, UX3D, and more as well as prominent universities such as, University of Pennsylvania and Sapienza University of Rome. + +"example" directory contains the GLB file of a chair, that is rendered in the following way: + +.. figure:: https://raw.githubusercontent.com/OCA/web/14.0/web_widget_model_viewer/static/img/Eames_Lounge_Chair.gif + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Add ``widget="model_viewer"`` to your binary field in form view. Optionally you can set ``style`` and ``max_upload_size`` (in MB) attributes. + +Changelog +========= + +14.0.1.0.0 (2021-10-07) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] v14 + +12.0.2.0.0 (2020-07-14) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [IMP] fullscreen and view redesign + +12.0.1.0.0 (2020-07-10) +~~~~~~~~~~~~~~~~~~~~~~~ + +* Start of the history. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* TAKOBI +* Openindustry.it + +Contributors +~~~~~~~~~~~~ + +* Lorenzo Battistini (https://takobi.online) +* Andrea Piovesana (https://openindustry.it) +* Marco Colombo (https://phi.technology) + +Other credits +~~~~~~~~~~~~~ + +Chair © Copyright 2020 Shopify Inc., licensed under CC-BY-4.0. + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-eLBati| image:: https://github.com/eLBati.png?size=40px + :target: https://github.com/eLBati + :alt: eLBati + +Current `maintainer `__: + +|maintainer-eLBati| + +This module is part of the `OCA/web `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/web_widget_model_viewer/__init__.py b/web_widget_model_viewer/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/web_widget_model_viewer/__manifest__.py b/web_widget_model_viewer/__manifest__.py new file mode 100644 index 00000000..342b9538 --- /dev/null +++ b/web_widget_model_viewer/__manifest__.py @@ -0,0 +1,33 @@ +# Copyright 2020 Andrea Piovesana @ Openindustry.it +# Copyright 2020 Lorenzo Battistini @ TAKOBI +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Model viewer widget", + "summary": "Easily display interactive 3D models on the web & in AR", + "version": "14.0.1.0.0", + "development_status": "Beta", + "category": "Web", + "website": "https://github.com/OCA/web", + "author": "TAKOBI, Openindustry.it, Odoo Community Association (OCA)", + "maintainers": ["eLBati"], + "license": "AGPL-3", + "depends": [ + "web", + ], + 'assets': { + 'web.assets_qweb': [ + "/web_widget_model_viewer/static/src/xml/*.xml", + ], + 'web.assets_backend': [ + '/web_widget_model_viewer/static/src/js/web_widget_model_viewer.js', + ], + }, + "data": [ + "views/assets.xml", + ], + "qweb": [ + + ], + "application": False, + "installable": True, +} diff --git a/web_widget_model_viewer/example/Chair.glb b/web_widget_model_viewer/example/Chair.glb new file mode 100644 index 00000000..d1a9bb0a Binary files /dev/null and b/web_widget_model_viewer/example/Chair.glb differ diff --git a/web_widget_model_viewer/example/chair.png b/web_widget_model_viewer/example/chair.png new file mode 100644 index 00000000..e3ddf31c Binary files /dev/null and b/web_widget_model_viewer/example/chair.png differ diff --git a/web_widget_model_viewer/i18n/ca.po b/web_widget_model_viewer/i18n/ca.po new file mode 100644 index 00000000..58fc7e59 --- /dev/null +++ b/web_widget_model_viewer/i18n/ca.po @@ -0,0 +1,67 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_widget_model_viewer +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-02-17 13:45+0000\n" +"Last-Translator: claudiagn \n" +"Language-Team: none\n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/js/web_widget_model_viewer.js:59 +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:26 +#, python-format +msgid "3D model" +msgstr "Model 3D" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:8 +#, python-format +msgid "Clear" +msgstr "Clar" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/js/web_widget_model_viewer.js:59 +#, python-format +msgid "Could not display the selected model." +msgstr "No s'ha pogut mostrar el model seleccionat." + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:7 +#, python-format +msgid "Edit" +msgstr "Editar" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:28 +#, python-format +msgid "Fullscreen" +msgstr "Pantalla completa" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:10 +#, python-format +msgid "Uploading..." +msgstr "Pujant..." + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:28 +#, python-format +msgid "View fullscreen" +msgstr "Veure pantalla completa" diff --git a/web_widget_model_viewer/i18n/es.po b/web_widget_model_viewer/i18n/es.po new file mode 100644 index 00000000..c5a55533 --- /dev/null +++ b/web_widget_model_viewer/i18n/es.po @@ -0,0 +1,67 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_widget_model_viewer +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-09-16 14:00+0000\n" +"Last-Translator: claudiagn \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/js/web_widget_model_viewer.js:59 +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:26 +#, python-format +msgid "3D model" +msgstr "Modelo 3D" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:8 +#, python-format +msgid "Clear" +msgstr "Claro" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/js/web_widget_model_viewer.js:59 +#, python-format +msgid "Could not display the selected model." +msgstr "No se pudo mostrar el modelo seleccionado." + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:7 +#, python-format +msgid "Edit" +msgstr "Editar" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:28 +#, python-format +msgid "Fullscreen" +msgstr "Pantalla completa" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:10 +#, python-format +msgid "Uploading..." +msgstr "Subiendo..." + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:28 +#, python-format +msgid "View fullscreen" +msgstr "Ver pantalla completa" diff --git a/web_widget_model_viewer/i18n/pt_BR.po b/web_widget_model_viewer/i18n/pt_BR.po new file mode 100644 index 00000000..7a53dde5 --- /dev/null +++ b/web_widget_model_viewer/i18n/pt_BR.po @@ -0,0 +1,65 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_widget_model_viewer +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/js/web_widget_model_viewer.js:59 +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:26 +#, python-format +msgid "3D model" +msgstr "" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:8 +#, python-format +msgid "Clear" +msgstr "" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/js/web_widget_model_viewer.js:59 +#, python-format +msgid "Could not display the selected model." +msgstr "" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:7 +#, python-format +msgid "Edit" +msgstr "" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:28 +#, python-format +msgid "Fullscreen" +msgstr "" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:10 +#, python-format +msgid "Uploading..." +msgstr "" + +#. module: web_widget_model_viewer +#. openerp-web +#: code:addons/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml:28 +#, python-format +msgid "View fullscreen" +msgstr "" diff --git a/web_widget_model_viewer/readme/CONTRIBUTORS.rst b/web_widget_model_viewer/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..7d946daf --- /dev/null +++ b/web_widget_model_viewer/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Lorenzo Battistini (https://takobi.online) +* Andrea Piovesana (https://openindustry.it) +* Marco Colombo (https://phi.technology) diff --git a/web_widget_model_viewer/readme/CREDITS.rst b/web_widget_model_viewer/readme/CREDITS.rst new file mode 100644 index 00000000..f7db4618 --- /dev/null +++ b/web_widget_model_viewer/readme/CREDITS.rst @@ -0,0 +1 @@ +Chair © Copyright 2020 Shopify Inc., licensed under CC-BY-4.0. diff --git a/web_widget_model_viewer/readme/DESCRIPTION.rst b/web_widget_model_viewer/readme/DESCRIPTION.rst new file mode 100644 index 00000000..ca410f1a --- /dev/null +++ b/web_widget_model_viewer/readme/DESCRIPTION.rst @@ -0,0 +1,15 @@ +```` is a web component that makes rendering interactive 3D models - optionally in AR - easy to do, on as many browsers and devices as possible. ```` strives to give you great defaults for rendering quality and performance. + +See `source repository `_ and `documentation `_. + +The model to load is a GLTF 2.0 file format. + +See ``_ and GLTF overview: + +.. figure:: ../static/img/gltfOverview.png + +Many engine developers have already started transitioning to glTF 2.0 to reap performance, portability and quality benefits, including BabylonJS, three.js, Cesium, Sketchfab, and xeogl and instant3Dhub engines. glTF 2.0 is also seeing industry support by companies such as Adobe, Google, Marmoset, Microsoft, NVIDIA, Oculus, UX3D, and more as well as prominent universities such as, University of Pennsylvania and Sapienza University of Rome. + +"example" directory contains the GLB file of a chair, that is rendered in the following way: + +.. figure:: ../static/img/Eames_Lounge_Chair.gif diff --git a/web_widget_model_viewer/readme/HISTORY.rst b/web_widget_model_viewer/readme/HISTORY.rst new file mode 100644 index 00000000..8c0d1df2 --- /dev/null +++ b/web_widget_model_viewer/readme/HISTORY.rst @@ -0,0 +1,14 @@ +14.0.1.0.0 (2021-10-07) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] v14 + +12.0.2.0.0 (2020-07-14) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [IMP] fullscreen and view redesign + +12.0.1.0.0 (2020-07-10) +~~~~~~~~~~~~~~~~~~~~~~~ + +* Start of the history. diff --git a/web_widget_model_viewer/readme/USAGE.rst b/web_widget_model_viewer/readme/USAGE.rst new file mode 100644 index 00000000..d249c04c --- /dev/null +++ b/web_widget_model_viewer/readme/USAGE.rst @@ -0,0 +1 @@ +Add ``widget="model_viewer"`` to your binary field in form view. Optionally you can set ``style`` and ``max_upload_size`` (in MB) attributes. diff --git a/web_widget_model_viewer/static/description/icon.png b/web_widget_model_viewer/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/web_widget_model_viewer/static/description/icon.png differ diff --git a/web_widget_model_viewer/static/description/index.html b/web_widget_model_viewer/static/description/index.html new file mode 100644 index 00000000..335cca09 --- /dev/null +++ b/web_widget_model_viewer/static/description/index.html @@ -0,0 +1,472 @@ + + + + + + +Model viewer widget + + + +
+

Model viewer widget

+ + +

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runbot

+

<model-viewer> is a web component that makes rendering interactive 3D models - optionally in AR - easy to do, on as many browsers and devices as possible. <model-viewer> strives to give you great defaults for rendering quality and performance.

+

See source repository and documentation.

+

The model to load is a GLTF 2.0 file format.

+

See https://www.khronos.org/gltf/ and GLTF overview:

+
+https://raw.githubusercontent.com/OCA/web/14.0/web_widget_model_viewer/static/img/gltfOverview.png +
+

Many engine developers have already started transitioning to glTF 2.0 to reap performance, portability and quality benefits, including BabylonJS, three.js, Cesium, Sketchfab, and xeogl and instant3Dhub engines. glTF 2.0 is also seeing industry support by companies such as Adobe, Google, Marmoset, Microsoft, NVIDIA, Oculus, UX3D, and more as well as prominent universities such as, University of Pennsylvania and Sapienza University of Rome.

+

“example” directory contains the GLB file of a chair, that is rendered in the following way:

+
+https://raw.githubusercontent.com/OCA/web/14.0/web_widget_model_viewer/static/img/Eames_Lounge_Chair.gif +
+

Table of contents

+ +
+

Usage

+

Add widget="model_viewer" to your binary field in form view. Optionally you can set style and max_upload_size (in MB) attributes.

+
+
+

Changelog

+
+

14.0.1.0.0 (2021-10-07)

+
    +
  • [MIG] v14
  • +
+
+
+

12.0.2.0.0 (2020-07-14)

+
    +
  • [IMP] fullscreen and view redesign
  • +
+
+
+

12.0.1.0.0 (2020-07-10)

+
    +
  • Start of the history.
  • +
+
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • TAKOBI
  • +
  • Openindustry.it
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+

Chair © Copyright 2020 Shopify Inc., licensed under CC-BY-4.0.

+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

eLBati

+

This module is part of the OCA/web project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/web_widget_model_viewer/static/img/Eames_Lounge_Chair.gif b/web_widget_model_viewer/static/img/Eames_Lounge_Chair.gif new file mode 100644 index 00000000..8d049e34 Binary files /dev/null and b/web_widget_model_viewer/static/img/Eames_Lounge_Chair.gif differ diff --git a/web_widget_model_viewer/static/img/gltfOverview.png b/web_widget_model_viewer/static/img/gltfOverview.png new file mode 100644 index 00000000..6a5bb613 Binary files /dev/null and b/web_widget_model_viewer/static/img/gltfOverview.png differ diff --git a/web_widget_model_viewer/static/src/js/web_widget_model_viewer.js b/web_widget_model_viewer/static/src/js/web_widget_model_viewer.js new file mode 100644 index 00000000..356060b6 --- /dev/null +++ b/web_widget_model_viewer/static/src/js/web_widget_model_viewer.js @@ -0,0 +1,114 @@ +// Copyright 2020 Lorenzo Battistini @ TAKOBI +// Copyright 2020 Andrea Piovesana @ Openindustry.it +odoo.define("web_widget_model_viewer.FieldBinaryModelViewer", function (require) { + "use strict"; + + var BasicFields = require("web.basic_fields"); + var core = require("web.core"); + var registry = require("web.field_registry"); + var session = require("web.session"); + var utils = require("web.utils"); + var _t = core._t; + var qweb = core.qweb; + + var FieldBinaryModelViewer = BasicFields.FieldBinaryFile.extend({ + template: "FieldBinaryModelViewer", + events: _.extend({}, BasicFields.FieldBinaryFile.prototype.events, { + click: function () { + if (this.mode === "readonly") { + this.trigger_up("bounce_edit"); + } + }, + "click #model-viewer-fullscreen": "fullscreen", + }), + supportedFieldTypes: ["binary"], + init: function () { + this._super.apply(this, arguments); + var max_upload_size = this.attrs.max_upload_size; + if (max_upload_size) { + this.max_upload_size = parseInt(max_upload_size, 10) * 1024 * 1024; + } else { + // 250M + this.max_upload_size = 250 * 1024 * 1024; + } + }, + _render: function () { + var self = this; + var url = ""; + if (this.value) { + if (utils.is_bin_size(this.value)) { + url = session.url("/web/content", { + model: this.model, + id: JSON.stringify(this.res_id), + field: this.name, + }); + } else { + url = "data:model/gltf-binary;base64," + this.value; + } + } + var $glb = $( + qweb.render("FieldBinaryModelViewer-glb", {widget: this, url: url}) + ); + var style = this.attrs.style; + if (style) { + $glb.attr("style", style); + } + this.$("> model-viewer").remove(); + this.$el.prepend($glb); + $glb.on("error", function () { + self._clearFile(); + $glb.attr("src", ""); + self.do_warn( + _t("3D model"), + _t("Could not display the selected model.") + ); + }); + }, + /* eslint-disable complexity */ + fullscreen: function (ev) { + var isFullscreenAvailable = + document.fullscreenEnabled || + document.mozFullScreenEnabled || + document.webkitFullscreenEnabled || + document.msFullscreenEnabled || + false; + var modelViewerElem = ev.target.parentElement.parentElement.parentElement; + if (isFullscreenAvailable) { + var fullscreenElement = + document.fullscreenElement || + document.mozFullScreenElement || + document.webkitFullscreenElement || + document.msFullscreenElement; + if (fullscreenElement) { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.mozCancelFullScreen) { + /* Firefox */ + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { + /* Chrome, Safari and Opera */ + document.webkitExitFullscreen(); + } else if (document.msExitFullscreen) { + /* IE/Edge */ + document.msExitFullscreen(); + } + } else if (modelViewerElem.requestFullscreen) { + modelViewerElem.requestFullscreen(); + } else if (modelViewerElem.mozRequestFullScreen) { + /* Firefox */ + modelViewerElem.mozRequestFullScreen(); + } else if (modelViewerElem.webkitRequestFullscreen) { + /* Chrome, Safari and Opera */ + modelViewerElem.webkitRequestFullscreen(); + } else if (modelViewerElem.msRequestFullscreen) { + /* IE/Edge */ + modelViewerElem.msRequestFullscreen(); + } + } else { + console.error("ERROR : full screen not supported by web browser"); + } + }, + }); + + registry.add("model_viewer", FieldBinaryModelViewer); +}); diff --git a/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml b/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml new file mode 100644 index 00000000..91314103 --- /dev/null +++ b/web_widget_model_viewer/static/src/xml/web_widget_model_viewer.xml @@ -0,0 +1,57 @@ + + + +
+ +
+
+
+
+
+ + +
+ + + +
+ + + + + + +
+
+
diff --git a/web_widget_model_viewer/views/assets.xml b/web_widget_model_viewer/views/assets.xml new file mode 100644 index 00000000..855f4a3e --- /dev/null +++ b/web_widget_model_viewer/views/assets.xml @@ -0,0 +1,27 @@ + + +