diff --git a/sf_base/__manifest__.py b/sf_base/__manifest__.py index 77165cde..5bd1a7b9 100644 --- a/sf_base/__manifest__.py +++ b/sf_base/__manifest__.py @@ -10,13 +10,16 @@ """, 'category': 'YZ', 'website': 'https://www.sf.jikimo.com', - 'depends': ['account', 'base', 'mrp'], + 'depends': ['account', 'base', 'mrp', 'sale', 'sf_manufacturing_orders'], 'data': [ 'security/group_security.xml', 'security/ir.model.access.csv', 'views/mrs_base_view.xml', 'views/mrs_common_view.xml', - "views/menu_view.xml" + "views/menu_view.xml", + 'views/mrp_routing_workcenter_view.xml', + 'views/sale_order_view.xml', + 'views/product_template_view.xml', ], 'demo': [ diff --git a/sf_base/data/process_data.xml b/sf_base/data/process_data.xml new file mode 100644 index 00000000..066f4e45 --- /dev/null +++ b/sf_base/data/process_data.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sf_base/data/product_data.xml b/sf_base/data/product_data.xml new file mode 100644 index 00000000..53fb6216 --- /dev/null +++ b/sf_base/data/product_data.xml @@ -0,0 +1,16 @@ + + + + + CNC加工产品模板 + + delivery + product + false + + + + false + + + \ No newline at end of file diff --git a/sf_base/models/__init__.py b/sf_base/models/__init__.py index 27b447be..1314cbdf 100644 --- a/sf_base/models/__init__.py +++ b/sf_base/models/__init__.py @@ -1,2 +1,5 @@ from. import sf_base from. import sf_common +from. import process +from. import product_template +from. import sale_order diff --git a/sf_base/models/process.py b/sf_base/models/process.py new file mode 100644 index 00000000..e6ef6348 --- /dev/null +++ b/sf_base/models/process.py @@ -0,0 +1,71 @@ +from odoo import fields, models, api + + +class ModelType(models.Model): + _name = 'sf.model.type' + _description = '模型类型' + + name = fields.Char('名称') + routing_tmpl_ids = fields.One2many('sf.model.type.routing.sort', 'model_type_id', '工序模板') + + +class ResMrpRoutingWorkcenter(models.Model): + _inherit = 'mrp.routing.workcenter' + + routing_type = fields.Selection([ + ('获取CNC加工程序', '获取CNC加工程序'), + ('装夹', '装夹'), + ('前置三元定位检测', '前置三元定位检测'), + ('CNC加工', 'CNC加工'), + ('后置三元质量检测', '后置三元质量检测'), + ('解除装夹', '解除装夹'), + ], string="工序类型") + is_repeat = fields.Boolean('重复', default=False) + workcenter_id = fields.Many2one('mrp.workcenter', required=False) + workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_route', required=True) + bom_id = fields.Many2one('mrp.bom', required=False) + + # 获得当前登陆者公司 + def get_company_id(self): + self.company_id = self.env.user.company_id.id + + company_id = fields.Many2one('res.company', compute="get_company_id", related=False) + + # 工单对应的工作中心,根据工序中的工作中心去匹配, + # 如果只配置了一个工作中心,则默认采用该工作中心; + # 如果有多个工作中心, + # 则根据该工作中心的工单个数进行分配(优先分配给工单个数最少的); + def get_workcenter(self, workcenter_ids): + if workcenter_ids: + if len(workcenter_ids) == 1: + return workcenter_ids[0] + elif len(workcenter_ids) >= 2: + # workcenter_ids_str = ','.join([str(s) for s in workcenter_ids]) + self.env.cr.execute(""" + SELECT workcenter_id FROM mrp_workorder where workcenter_id + in %s group by workcenter_id + order by count(*),workcenter_id asc limit 1 """, [tuple(workcenter_ids)]) + return self.env.cr.dictfetchall()[0].get('workcenter_id') + + +class ModelTypeRoutingSort(models.Model): + _name = 'sf.model.type.routing.sort' + _description = '工序排序' + + sequence = fields.Integer('Sequence') + route_workcenter_id = fields.Many2one('mrp.routing.workcenter') + is_repeat = fields.Boolean('重复', related='route_workcenter_id.is_repeat') + routing_type = fields.Selection([ + ('获取CNC加工程序', '获取CNC加工程序'), + ('装夹', '装夹'), + ('前置三元定位检测', '前置三元定位检测'), + ('CNC加工', 'CNC加工'), + ('后置三元质量检测', '后置三元质量检测'), + ('解除装夹', '解除装夹'), + ], string="工序类型", related='route_workcenter_id.routing_type') + workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids') + model_type_id = fields.Many2one('sf.model.type') + + _sql_constraints = [ + ('route_model_type_uniq', 'unique (route_workcenter_id,model_type_id)', '工序不能重复!') + ] diff --git a/sf_base/models/product_template.py b/sf_base/models/product_template.py new file mode 100644 index 00000000..45c46144 --- /dev/null +++ b/sf_base/models/product_template.py @@ -0,0 +1,124 @@ +from odoo import models, fields,api +from odoo.exceptions import ValidationError + + +class ResProductTemplate(models.Model): + _inherit = 'product.template' + + # 模型的长,宽,高,体积,精度,材料 + model_long = 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_precision = fields.Float('精度要求', digits=(16, 3)) + model_materials_id = fields.Many2one('mrs.production.materials', string='模型材料') + model_materials_type_id = fields.Many2one('mrs.materials.model', string='模型材料型号') + model_type_id = fields.Many2one('sf.model.type', string='模型类型') + processing_panel = fields.Char('模型加工面板') + # 胚料的长,宽,高 + embryo_long = fields.Float('胚料长[mm]', digits=(16, 3), onchange='count_embryo_size') + embryo_width = fields.Float('胚料宽[mm]', digits=(16, 3), onchange='count_embryo_size') + embryo_height = fields.Float('胚料高[mm]', digits=(16, 3), onchange='count_embryo_size') + embryo_materials_id = fields.Many2one('mrs.production.materials', string='胚料材料') + embryo_materials_type_id = fields.Many2one('mrs.materials.model', string='胚料材料型号') + + volume = fields.Float(compute='_compute_volume', store=True) + + @api.depends('embryo_long', 'embryo_width', 'embryo_height') + def _compute_volume(self): + self.volume = self.embryo_long * self.embryo_width * self.embryo_height + + # 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品 + 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 + vals = { + 'name': '%s-%s' % (order_id.name, i), + 'model_long': item['model_long'], + 'model_width': item['model_width'], + 'model_height': item['model_height'], + 'model_volume': item['model_volume'], + 'list_price': item['price'], + 'model_materials_id': self.env['mrs.production.materials'].search( + [('materials_no', '=', item['texture_code'])]).id, + 'model_materials_type_id': self.env['mrs.materials.model'].search( + [('materials_no', '=', item['texture_type_code'])]).id, + 'default_code': '%s-%s' % (order_number, i), + 'barcode': item['barcode'], + 'active': True + } + copy_product_id.sudo().write(vals) + return copy_product_id + + # 在产品上增加模型类型和加工的面(例如:A、B) , + # 并根据模型类型计算出产品的胚料尺寸; + @api.onchange('model_type_id') + def count_embryo_size(self): + if not self.model_type_id: + return + bom = self.env['product.product'].search( + [('categ_id.is_embryo', '=', True), ('product_tmpl_id', '=', self.id)], + limit=1, + order='volume desc' + ) + for item in self: + item.embryo_long = bom.embryo_long + 1 + item.embryo_width = bom.embryo_width + 1 + item.embryo_height = bom.embryo_height + 1 + + + + + +class ResProductCategory(models.Model): + _inherit = "product.category" + + is_embryo = fields.Boolean('胚料') + + +class ResMrpBom(models.Model): + _inherit = 'mrp.bom' + + # 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品后再次进行创建bom + def bom_create(self, product): + bom_id = self.env['mrp.bom'].create({ + 'product_tmpl_id': product.product_tmpl_id.id, + 'type': 'normal', + 'product_qty': 1, + 'product_uom_id': 1 + }) + return bom_id + + # 生成产品BOM匹配胚料,胚料的匹配规则: + # 一、匹配的胚料类别需要带有胚料的标签; + # 二、胚料的材料型号与生成产品的材料型号一致; + # 三、胚料的长宽高均要大于模型的长宽高; + # 四、如果匹配成功多个胚料,则选取体积最小的胚料; + def bom_create_Line(self, product): + embryo = self.env['product.product'].search( + [('categ_id.is_embryo', '=', True), ('embryo_materials_type_id', '=', product.model_materials_type_id.id), + ('embryo_long', '>', product.model_long), ('embryo_width', '>', product.model_width), + ('embryo_height', '>', product.model_height) + ], + limit=1, + order='volume desc' + ) + 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) + + + + + + + + + + + diff --git a/sf_base/models/sale_order.py b/sf_base/models/sale_order.py new file mode 100644 index 00000000..1618a4e3 --- /dev/null +++ b/sf_base/models/sale_order.py @@ -0,0 +1,34 @@ +from odoo import models, fields +from odoo.exceptions import ValidationError +import datetime + + +class ReSaleOrder(models.Model): + _inherit = 'sale.order' + + deadline_of_delivery = fields.Date('交货截止日期') + + # 业务平台分配工厂后在智能工厂先创建销售订单 + def sale_order_create(self, deadline_of_delivery, company_id): + now_time = datetime.datetime.now() + order_id = self.env['sale.order'].sudo().create({ + 'company_id': company_id.id, + 'date_order': now_time, + 'name': self.env['ir.sequence'].next_by_code('sale.order', sequence_date=now_time), + 'partner_id': 8, + 'state': 'sale', + 'user_id': 6, + 'deadline_of_delivery': deadline_of_delivery + }) + return order_id + + # 业务平台分配工厂时在创建完产品后再创建销售明细信息 + def sale_order_create_line(self, product, item): + vals = { + 'order_id': self.id, + 'product_id': product.id, + 'name': '%s/%s/%s/%s/%s' % (item['model_long'], item['model_width'], item['model_height'], item['model_volume'], product.model_materials_id.name), + 'price_unit': item['price'], + 'product_uom_qty': item['number'] + } + return self.env['sale.order.line'].create(vals) diff --git a/sf_base/models/sf_base.py b/sf_base/models/sf_base.py index 453f6eb0..d10f190e 100644 --- a/sf_base/models/sf_base.py +++ b/sf_base/models/sf_base.py @@ -247,3 +247,20 @@ class CuttingToolType(models.Model): brand_id = fields.Many2one('mrs.machine.brand', string='品牌') remark = fields.Text('备注') active = fields.Boolean('有效', default=True) + +class CNCprocessing(models.Model): + _name = 'cnc.processing' + _description = "CNC加工" + + FNo = fields.Char(string="序号") + FPGName = fields.Char(string="程序名") + FKnifeName = fields.Char(string="刀具名称") + FDNo = fields.Char(string="刀号") + FWorkType = fields.Char(string="加工类型") + FXY = fields.Char(string="余量_X/Y") + FZ = fields.Char(string="余量_Z") + FJGSD = fields.Char(string="加工深度(Z)") + FSCCD = fields.Char(string="刀具伸出长度") + FDJSpec = fields.Char(string="刀柄型号") + FJGDate = fields.Char(string="预计加工时间") + FComment = fields.Char(string="备注") diff --git a/sf_base/models/sf_common.py b/sf_base/models/sf_common.py index 0d86e593..b1abf43b 100644 --- a/sf_base/models/sf_common.py +++ b/sf_base/models/sf_common.py @@ -72,9 +72,9 @@ class Tray(models.Model): _name = 'sf.tray' _description = '托盘' - code = fields.Char('编码') + code = fields.Char('编码',copy=False) name = fields.Char('名称') state = fields.Selection( [("空闲", "空闲"), ("占用", "占用"), ("报损", "报损")], - default=" ", string="状态") + default="空闲", string="状态") active = fields.Boolean('有效', default=True) diff --git a/sf_base/security/ir.model.access.csv b/sf_base/security/ir.model.access.csv index 5b4aa249..2422ae03 100644 --- a/sf_base/security/ir.model.access.csv +++ b/sf_base/security/ir.model.access.csv @@ -13,6 +13,9 @@ access_mrs_production_materials,mrs_production_materials,model_mrs_production_ma access_mrs_materials_model,mrs_materials_model,model_mrs_materials_model,base.group_user,1,1,1,1 access_mrs_processing_technology,mrs_processing_technology,model_mrs_processing_technology,base.group_user,1,1,1,1 access_sf_tray,sf_tray,model_sf_tray,base.group_user,1,1,1,1 +access_cnc_processing,cnc_processing,model_cnc_processing,base.group_user,1,1,1,1 +access_sf_model_type,sf_model_type,model_sf_model_type,base.group_user,1,1,1,1 +access_sf_model_type_routing_sort,sf_model_type_routing_sort,model_sf_model_type_routing_sort,base.group_user,1,1,1,1 diff --git a/sf_base/views/menu_view.xml b/sf_base/views/menu_view.xml index 42c9602c..4babedb1 100644 --- a/sf_base/views/menu_view.xml +++ b/sf_base/views/menu_view.xml @@ -142,13 +142,13 @@ action="action_mrs_machine_control_system"/> - - - - - - - + diff --git a/sf_base/views/mrp_routing_workcenter_view.xml b/sf_base/views/mrp_routing_workcenter_view.xml new file mode 100644 index 00000000..e4912930 --- /dev/null +++ b/sf_base/views/mrp_routing_workcenter_view.xml @@ -0,0 +1,66 @@ + + + + #-----------------作业------------------- + + mrp.routing.workcenter.form.inherit.sf + mrp.routing.workcenter + + + + + + + + + + + + + #-----------------工单------------------- + + mrp.production.workorder.form.inherit.sf + mrp.workorder + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #-----------------制造订单里的工单------------------- + + mrp.production.workorder.tree.editable.inherit.sf + mrp.workorder + + + + + + + + + \ No newline at end of file diff --git a/sf_base/views/mrs_base_view.xml b/sf_base/views/mrs_base_view.xml index 61d57a05..4cff9e87 100644 --- a/sf_base/views/mrs_base_view.xml +++ b/sf_base/views/mrs_base_view.xml @@ -359,11 +359,11 @@
-
- + - + @@ -499,4 +500,61 @@

+ + #------------------模型类型------------------ + + + search.sf.model.type + sf.model.type + + + + + + + + + tree.sf.model.type + sf.model.type + + + + + + + + + form.sf.model.type + sf.model.type + + + + + + + + + + + + + + + + + + + 模型类型 + ir.actions.act_window + sf.model.type + tree,form + +

+ [模型类型] 还没有哦!点左上角的[创建]按钮,沙发归你了! +

+

+

+
+
\ No newline at end of file diff --git a/sf_base/views/mrs_common_view.xml b/sf_base/views/mrs_common_view.xml index 6424a6f3..748b0683 100644 --- a/sf_base/views/mrs_common_view.xml +++ b/sf_base/views/mrs_common_view.xml @@ -277,6 +277,18 @@ #------------------托盘------------------ + + 托盘 + ir.actions.act_window + sf.tray + tree,form + +

+ 创建托盘吧 +

+
+
+ sf.tray.search sf.tray @@ -309,11 +321,13 @@ sf.tray.form sf.tray +
+ +
- + - @@ -323,17 +337,6 @@ - - 托盘 - ir.actions.act_window - sf.tray - tree,form - -

- 创建托盘吧 -

-
-
\ No newline at end of file diff --git a/sf_base/views/product_template_view.xml b/sf_base/views/product_template_view.xml new file mode 100644 index 00000000..3a8c0955 --- /dev/null +++ b/sf_base/views/product_template_view.xml @@ -0,0 +1,50 @@ + + + + + product.template.form.inherit.sf + product.template + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product.category.form.inherit.sf + product.category + + + + + + + + + \ No newline at end of file diff --git a/sf_bpm_api/views/sale_order_view.xml b/sf_base/views/sale_order_view.xml similarity index 100% rename from sf_bpm_api/views/sale_order_view.xml rename to sf_base/views/sale_order_view.xml diff --git a/sf_bpm_api/__manifest__.py b/sf_bpm_api/__manifest__.py index b659bd14..daea8057 100644 --- a/sf_bpm_api/__manifest__.py +++ b/sf_bpm_api/__manifest__.py @@ -12,9 +12,7 @@ 'website': 'https://www.sf.cs.jikimo.com', 'depends': ['sale', 'sf_base'], 'data': [ - 'data/product_data.xml', - 'views/product_template_view.xml', - 'views/sale_order_view.xml' + ], 'demo': [ ], diff --git a/sf_bpm_api/models/__init__.py b/sf_bpm_api/models/__init__.py index 4c183668..1b8cfb6d 100644 --- a/sf_bpm_api/models/__init__.py +++ b/sf_bpm_api/models/__init__.py @@ -1,5 +1,3 @@ -from . import sale_order -from . import product_template from . import http from . import models diff --git a/sf_bpm_api/views/product_template_view.xml b/sf_bpm_api/views/product_template_view.xml deleted file mode 100644 index 406330e3..00000000 --- a/sf_bpm_api/views/product_template_view.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - product.template.form.inherit.sf - product.template - - - - - - - - - - - - - - - - - - - - - - - - - - - - product.category.form.inherit.sf - product.category - - - - - - - - - \ No newline at end of file diff --git a/sf_manufacturing_orders/models/__init__.py b/sf_manufacturing_orders/models/__init__.py index 3fb32983..e1f5282a 100644 --- a/sf_manufacturing_orders/models/__init__.py +++ b/sf_manufacturing_orders/models/__init__.py @@ -1 +1,2 @@ -from. import sf_production +from . import sf_production +from . import mrp_workorder diff --git a/sf_manufacturing_orders/models/mrp_workorder.py b/sf_manufacturing_orders/models/mrp_workorder.py new file mode 100644 index 00000000..ebecb097 --- /dev/null +++ b/sf_manufacturing_orders/models/mrp_workorder.py @@ -0,0 +1,23 @@ +from odoo import api, fields, models, SUPERUSER_ID, _ + + +class ResWorkcenterProductivity(models.Model): + _inherit = 'mrp.workcenter.productivity' + workcenter_id = fields.Many2one('mrp.workcenter', required=False) + + +class ResMrpWorkOrder(models.Model): + _inherit = 'mrp.workorder' + + workcenter_id = fields.Many2one('mrp.workcenter', required=False) + processing_panel = fields.Char('加工面') + routing_type = fields.Selection([ + ('获取CNC加工程序', '获取CNC加工程序'), + ('装夹', '装夹'), + ('前置三元定位检测', '前置三元定位检测'), + ('CNC加工', 'CNC加工'), + ('后置三元质量检测', '后置三元质量检测'), + ('解除装夹', '解除装夹'), + ], string="工序类型") + + diff --git a/sf_manufacturing_orders/models/sf_production.py b/sf_manufacturing_orders/models/sf_production.py index 6995005a..f976a5ba 100644 --- a/sf_manufacturing_orders/models/sf_production.py +++ b/sf_manufacturing_orders/models/sf_production.py @@ -29,10 +29,67 @@ class MrpProduction(models.Model): _inherit = 'mrp.production' _description = "制造订单" + # 重载根据工序生成工单的程序:如果产品BOM中没有工序时, + # 根据产品对应的模板类型中工序,去生成工单; + # CNC加工工序的选取规则: + # 如果自动报价有带过来预分配的机床, + # 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制; + # 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心; + + def _create_workorder(self): + for production in self: + if not production.bom_id or not production.product_id: + continue + workorders_values = [] + + product_qty = production.product_uom_id._compute_quantity(production.product_qty, + production.bom_id.product_uom_id) + exploded_boms, dummy = production.bom_id.explode(production.product_id, + product_qty / production.bom_id.product_qty, + picking_type=production.bom_id.picking_type_id) + + for bom, bom_data in exploded_boms: + # If the operations of the parent BoM and phantom BoM are the same, don't recreate work orders. + if not (bom.operation_ids and (not bom_data['parent_line'] or bom_data[ + 'parent_line'].bom_id.operation_ids != bom.operation_ids)): + continue + for operation in bom.operation_ids: + if operation._skip_operation_line(bom_data['product']): + continue + workorders_values += [{ + 'name': operation.name, + 'production_id': production.id, + 'workcenter_id': operation.workcenter_id.id, + 'product_uom_id': production.product_uom_id.id, + 'operation_id': operation.id, + 'state': 'pending', + }] + # 根据加工面板的面数及对应的工序模板生成工单 + for k in (production.product_id.processing_panel.split(',')): + for route in production.product_id.model_type_id.routing_tmpl_ids: + if route: + workorders_values_str = [0, '', { + 'product_uom_id': production.product_uom_id.id, + 'qty_producing': 0, + 'operation_id': False, + 'name': route.route_workcenter_id.name, + 'processing_panel': k, + 'routing_type': route.routing_type, + 'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids), + 'date_planned_start': False, + 'date_planned_finished': False, + 'duration_expected': 60, + 'duration': 0 + }] + workorders_values.append(workorders_values_str) + production.workorder_ids = workorders_values + for workorder in production.workorder_ids: + workorder.duration_expected = workorder._get_duration_expected() + + class StockRule(models.Model): _inherit = 'stock.rule' - @api.model def _run_pull(self, procurements): moves_values_by_company = defaultdict(list) @@ -142,6 +199,7 @@ class StockRule(models.Model): moves = self.env['stock.move'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(moves_values) # Since action_confirm launch following procurement_group we should activate it. moves._action_confirm() + return True # @api.model @@ -256,5 +314,3 @@ class StockRule(models.Model): # mo_lists.append(vals) # # return mo_lists - - diff --git a/sf_route_workcenter/__init__.py b/sf_route_workcenter/__init__.py new file mode 100644 index 00000000..87c2fd17 --- /dev/null +++ b/sf_route_workcenter/__init__.py @@ -0,0 +1,3 @@ +# -*-coding:utf-8-*- +from . import models +from . import report diff --git a/sf_route_workcenter/__manifest__.py b/sf_route_workcenter/__manifest__.py new file mode 100644 index 00000000..6cf239f2 --- /dev/null +++ b/sf_route_workcenter/__manifest__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +{ + 'name': '机企猫藏智能工厂 工序', + 'version': '1.0', + 'summary': '智能工厂工作中心工序', + 'sequence': 1, + 'description': """ +在本模块,同步资源库 + """, + 'category': 'YZ', + 'website': 'https://www.sf.cs.jikimo.com', + 'depends': ['mrp', 'sf_base','hr_holidays'], + 'data': [ + 'views/sf_tray_view.xml', + 'views/sf_workorder.xml', + 'report/sf_tray_report.xml' + ], + 'demo': [ + ], + 'qweb': [ + ], + 'installable': True, + 'application': False, + 'auto_install': False, +} diff --git a/sf_route_workcenter/models/__init__.py b/sf_route_workcenter/models/__init__.py new file mode 100644 index 00000000..94d72e99 --- /dev/null +++ b/sf_route_workcenter/models/__init__.py @@ -0,0 +1,2 @@ +# -*-coding:utf-8-*- +from . import workcenter \ No newline at end of file diff --git a/sf_route_workcenter/models/workcenter.py b/sf_route_workcenter/models/workcenter.py new file mode 100644 index 00000000..7de4f79e --- /dev/null +++ b/sf_route_workcenter/models/workcenter.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +# Part of SmartGo. See LICENSE file for full copyright and licensing details. +import base64 +import logging +import math + + + +from io import BytesIO +from odoo import api, fields, models +from pystrich.code128 import Code128Encoder + + +_logger = logging.getLogger(__name__) + + +class CNCprocessing(models.Model): + _inherit = 'cnc.processing' + _description = "CNC加工" + + workorder_id = fields.Many2one('mrp.workorder', string="工单") + + +class Tray(models.Model): + _inherit = 'sf.tray' + _description = '托盘' + qr_image = fields.Binary(string="托盘二维码", compute='compute_qr_image') + + production_id = fields.Many2one('mrp.production', string='制造订单', + related='workorder_id.production_id' + ) + workorder_id = fields.Many2one('mrp.workorder', string="工单" + ) + + @api.onchange('production_id') + def updateTrayState(self): + + if self.workorder_id != False: + self.state = '占用' + else: + self.state = '空闲' + + def unclamp(self): + self.workorder_id = False + self.production_id = False + self.state = '空闲' + + @api.depends('code') + def compute_qr_image(self): + for item in self: + if not item.code: + item.qr_image = False + continue + # 根据code动态生成二维码图片 + # qr = qrcode.QRCode( + # version=1, + # error_correction=qrcode.constants.ERROR_CORRECT_L, + # box_size=10, + # border=4, + # ) + # qr.add_data(item.code) + # qr.make(fit=True) + # img = qr.make_image() + # 生成条形码文件 + # bar = barcode.get("ean13", "123456789102", writer=ImageWriter()) + # a = bar.get_fullcode() + # b = bar.save('occ') + # 生成条形码图片 + partner_encoder = Code128Encoder(item.code) + # 转换bytes流 + temp = BytesIO() + partner_encoder.save(temp) + # img.save(temp, format='PNG') + qr_image = base64.b64encode(temp.getvalue()) + item.qr_image = qr_image + + +''' +工单绑定托盘信息 +''' + + +class MrpWorkOrder(models.Model): + _inherit = 'mrp.workorder' + _description = '工单' + + cnc_id = fields.Many2many('ir.attachment', 'cnc_attachment', string="cnc程序获取") + tray_ids = fields.One2many('sf.tray', 'workorder_id', string='托盘') + # def get_tray_info(self): + # @api.onchange('X_axis', 'Y_axis', 'Z_axis') + # def get_center_point(self): + # return 'X:%s,Y:%s,Z:%s' % (self.X_axis, self.Y_axis, self.Z_axis) + # 加工面 + # surface = fields.Selection([("前面", "前面"), ("后面", "后面"), ("左面", "左面"), ("右面", "右面"), + # ("上面", "上面")], string="加工面1") + + material_center_point = fields.Char(string='配料中心点') + X1_axis = fields.Float(string='Lx1', default=0) + Y1_axis = fields.Float(string='Ly1', default=0) + Z1_axis = fields.Float(string='Lz1', default=0) + X2_axis = fields.Float(string='Lx2', default=0) + Y2_axis = fields.Float(string='Ly2', default=0) + Z2_axis = fields.Float(string='Lz2', default=0) + X3_axis = fields.Float(string='Fx3', default=0) + Y3_axis = fields.Float(string='Fy3', default=0) + Z3_axis = fields.Float(string='Fz3', default=0) + X4_axis = fields.Float(string='Fx4', default=0) + Y4_axis = fields.Float(string='Fy4', default=0) + Z4_axis = fields.Float(string='Fz4', default=0) + X5_axis = fields.Float(string='Rx5', default=0) + Y5_axis = fields.Float(string='Ry5', default=0) + Z5_axis = fields.Float(string='Rz5', default=0) + X6_axis = fields.Float(string='Rx6', default=0) + Y6_axis = fields.Float(string='Ry6', default=0) + Z6_axis = fields.Float(string='Rz6', default=0) + X7_axis = fields.Float(string='Bx7', default=0) + Y7_axis = fields.Float(string='By7', default=0) + Z7_axis = fields.Float(string='Bz7', default=0) + X8_axis = fields.Float(string='Bx8', default=0) + Y8_axis = fields.Float(string='By8', default=0) + Z8_axis = fields.Float(string='Bz8', default=0) + X9_axis = fields.Float(string='Uz9', default=0) + Y9_axis = fields.Float(string='Uz9', default=0) + Z9_axis = fields.Float(string='Uz9', default=0) + X10_axis = fields.Float(string='Uz10', default=0) + Y10_axis = fields.Float(string='Uz10', default=0) + Z10_axis = fields.Float(string='Uz10', default=0) + + # 扫码绑定托盘方法 + def gettray(self): + return "" + #解除托盘绑定 + def unbindtray(self): + return "" + + # 计算配料中心点和与x轴倾斜度方法 + def getcenter(self): + x1 = self.X1_axis + x2 = self.X2_axis + x3 = self.X3_axis + x4 = self.X4_axis + x5 = self.X5_axis + x6 = self.X6_axis + x7 = self.X7_axis + x8 = self.X8_axis + y1 = self.Y1_axis + y2 = self.Y2_axis + y3 = self.Y3_axis + y4 = self.Y4_axis + y5 = self.Y5_axis + y6 = self.Y6_axis + y7 = self.Y7_axis + y8 = self.Y8_axis + z1 = self.Z9_axis + x0 = ((x3 - x4) * (x2 * y1 - x1 * y2) - (x1 - x2) * (x4 * y3 - x3 * y4)) / ( + (x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4)) + y0 = ((y3 - y4) * (y2 * x1 - y1 * x2) - (y1 - y2) * (y4 * x3 - y3 * x4)) / ( + (y3 - y4) * (x1 - x2) - (y1 - y2) * (x3 - x4)) + x1 = ((x7 - x8) * (x6 * y5 - x5 * y7) - (x5 - x6) * (x8 * y7 - x7 * y8)) / ( + (x7 - x8) * (y5 - y6) - (x5 - x6) * (y7 - y8)); + y1 = ((y7 - y8) * (y6 * x5 - y5 * x7) - (y5 - y6) * (y8 * x7 - y7 * x8)) / ( + (y7 - y8) * (x5 - x6) - (y5 - y6) * (x7 - x8)) + x = (x0 + x1) / 2 + y = (y0 + y1) / 2 + z = z1 / 2 + + jd = math.atan2((x7 - x8), (y7 - y8)) + jdz = jd * 180 / math.pi + print("(%s,%s)" % (x, y)) + self.material_center_point = ("(%s,%s,%s)" % (x, y, z)) + self.X_deviation_angle = jdz + + X_deviation_angle = fields.Integer(string="X轴偏差度", default=0) + + test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], string="检测结果") + + cnc_ids = fields.One2many("cnc.processing", 'workorder_id', string="CNC加工") + + # @api.depends('tray_id') + # def updateTrayState(self): + # + # for item in self: + # if item.tray_code == False: + # continue + # trayInfo = self.env['sf.tray'].sudo.search([('code', '=', item.tray_code)]) + # if trayInfo: + # trayInfo.update( + # { + # 'production_id': item.production_id, + # 'state': "占用", + # } + # ) + def recreateManufacturing(self): + return "" + + def recreateWorkerOrder(self): + return "" + + +''' +制造订单绑定托盘信息 +''' + + +class MrpProduction(models.Model): + _inherit = 'mrp.production' + _description = "制造订单" + + tray_ids = fields.One2many('sf.tray', 'production_id', string="托盘") + +class Attachment(models.Model): + _inherit = 'ir.attachment' + + cnc_model = fields.Binary('cnc文件', attachment=False) + model_name = fields.Char('模型名称') + diff --git a/sf_route_workcenter/report/sf_tray_report.xml b/sf_route_workcenter/report/sf_tray_report.xml new file mode 100644 index 00000000..d1af6676 --- /dev/null +++ b/sf_route_workcenter/report/sf_tray_report.xml @@ -0,0 +1,50 @@ + + + + + Dymo Label Sheet + + custom + 100 + 60 + Landscape + 0 + 0 + 0 + 0 + + 96 + + + + 打印条形码 + sf.tray + qweb-pdf + sf_route_workcenter.sf_tray_template + sf_route_workcenter.sf_tray_template + + report + + + + + + + + + diff --git a/sf_route_workcenter/views/sf_tray_view.xml b/sf_route_workcenter/views/sf_tray_view.xml new file mode 100644 index 00000000..753b962c --- /dev/null +++ b/sf_route_workcenter/views/sf_tray_view.xml @@ -0,0 +1,30 @@ + + + + 托盘条形码生成 + sf.tray + + + + + + + + + + +
+
+ +
+ +
+
+
+
+
+
\ No newline at end of file diff --git a/sf_route_workcenter/views/sf_workorder.xml b/sf_route_workcenter/views/sf_workorder.xml new file mode 100644 index 00000000..3371549a --- /dev/null +++ b/sf_route_workcenter/views/sf_workorder.xml @@ -0,0 +1,196 @@ + + + + + 装夹工序工单 + mrp.workorder + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ + + + + + + + + + + +
左面:
+
+
+
+
+
+
前面:
+
+
+
+
+
+
右面:
+
+
+
+
+
+
下面:
+
+
+
+
+
+
上面:
+
+
+
+
+
+ + +
+
+ + +
+ + + + + +
+ + +
+ + + + + + + + + + + + + + + +
+
+
+
+ +
+
+ +
+ + +
+
+
+ +
+ +
+
+
+
\ No newline at end of file