From 34280fe24b59a66f1666cab0bc3ef1ecaf66af5b Mon Sep 17 00:00:00 2001 From: guanhuan Date: Mon, 23 Sep 2024 16:43:29 +0800 Subject: [PATCH 01/34] =?UTF-8?q?=E5=9D=AF=E6=96=99=E5=8F=91=E6=96=99?= =?UTF-8?q?=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/data/bussiness_node.xml | 4 +++ sf_message/models/sf_message_stock_picking.py | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/sf_message/data/bussiness_node.xml b/sf_message/data/bussiness_node.xml index 76f3fcb7..924b669e 100644 --- a/sf_message/data/bussiness_node.xml +++ b/sf_message/data/bussiness_node.xml @@ -26,5 +26,9 @@ 坯料采购提醒 purchase.order + + 坯料发料提醒 + stock.picking + \ No newline at end of file diff --git a/sf_message/models/sf_message_stock_picking.py b/sf_message/models/sf_message_stock_picking.py index d66008f9..cabc376e 100644 --- a/sf_message/models/sf_message_stock_picking.py +++ b/sf_message/models/sf_message_stock_picking.py @@ -1,3 +1,4 @@ +import re from odoo import models, fields, api, _ @@ -11,3 +12,28 @@ class SFMessageStockPicking(models.Model): if self.location_id.name == '进货' and self.location_dest_id.name == '刀具房': self.add_queue('调拨入库') return res + + @api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id') + def _compute_state(self): + super(SFMessageStockPicking, self)._compute_state() + if self.state == 'assigned' and self.check_in == 'PC': + self.add_queue('坯料发料提醒') + + def _get_message(self, message_queue_ids): + contents = [] + product_id = [] + for message_queue_id in message_queue_ids: + if message_queue_id.message_template_id.name == '坯料发料提醒': + content = message_queue_id.message_template_id.content + stock_picking_line = self.env['stock.picking'].search([('id', '=', int(message_queue_id.res_id))]) + stock_picking_info = self.env['stock.picking'].search( + [('product_id', '=', stock_picking_line.product_id.id), ('state', '=', 'assigned'), + ('check_in', '=', 'PC')]) + if stock_picking_info and stock_picking_info.product_id.id not in product_id: + content = content.replace('{{product_id}}', stock_picking_info.product_id.name) + content = content.replace('{{number}}', str(len(stock_picking_info))) + product_id.append(stock_picking_info.product_id.id) + contents.append(content) + res = super(SFMessageStockPicking, self)._get_message(message_queue_ids) + contents.append(res) + return contents From d197fc5b9eec5038d460463c0cafd64cd4301ca0 Mon Sep 17 00:00:00 2001 From: liaodanlong Date: Mon, 23 Sep 2024 16:58:58 +0800 Subject: [PATCH 02/34] =?UTF-8?q?=E4=BF=9D=E7=95=99=E5=B0=8F=E6=95=B0?= =?UTF-8?q?=E7=82=B9=E5=90=8E=E4=B8=A4=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_mrs_connect/models/res_config_setting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_mrs_connect/models/res_config_setting.py b/sf_mrs_connect/models/res_config_setting.py index 72b04e92..6ec49f74 100644 --- a/sf_mrs_connect/models/res_config_setting.py +++ b/sf_mrs_connect/models/res_config_setting.py @@ -175,7 +175,7 @@ class ResConfigSettings(models.TransientModel): new_price = res_order_lines_map.get(str(index)) if order_line: # 修改单价 - order_line.write({'remark': new_price*order_line.product_uom_qty}) + order_line.write({'remark': round(new_price*order_line.product_uom_qty,2)}) order_price = self.env['order.price'].sudo().search([('sale_order_id', '=',need_change_sale_order.id )]) if not order_price: self.env['order.price'].sudo().create({'sale_order_id':need_change_sale_order.id}) From d52f0aed6edae14e661d14ddd88d8198762f3586 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Mon, 23 Sep 2024 17:11:53 +0800 Subject: [PATCH 03/34] =?UTF-8?q?=E5=9D=AF=E6=96=99=E5=8F=91=E6=96=99?= =?UTF-8?q?=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/models/sf_message_stock_picking.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sf_message/models/sf_message_stock_picking.py b/sf_message/models/sf_message_stock_picking.py index cabc376e..ca8d6bf4 100644 --- a/sf_message/models/sf_message_stock_picking.py +++ b/sf_message/models/sf_message_stock_picking.py @@ -5,7 +5,7 @@ from odoo import models, fields, api, _ class SFMessageStockPicking(models.Model): _name = 'stock.picking' _description = "库存调拨" - _inherit = ['stock.picking', 'jikimo.message.dispatch'] + _inherit = ['stock.picking', 'jikimo.message.dispatch'] def button_validate(self): res = super(SFMessageStockPicking, self).button_validate() @@ -34,6 +34,7 @@ class SFMessageStockPicking(models.Model): content = content.replace('{{number}}', str(len(stock_picking_info))) product_id.append(stock_picking_info.product_id.id) contents.append(content) - res = super(SFMessageStockPicking, self)._get_message(message_queue_ids) - contents.append(res) + else: + res = super(SFMessageStockPicking, self)._get_message(message_queue_id) + contents.append(res) return contents From 75b60c1ec8ca3354b1b30ba498b7962e6521515e Mon Sep 17 00:00:00 2001 From: liaodanlong Date: Mon, 23 Sep 2024 17:47:03 +0800 Subject: [PATCH 04/34] =?UTF-8?q?bom=E6=B8=85=E5=8D=95=E6=95=B4=E4=BD=93?= =?UTF-8?q?=E5=BC=8F=E5=88=80=E5=85=B7=E5=8C=B9=E9=85=8D=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_tool_management/models/jikimo_bom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_tool_management/models/jikimo_bom.py b/sf_tool_management/models/jikimo_bom.py index b5caf495..e07f0bbc 100644 --- a/sf_tool_management/models/jikimo_bom.py +++ b/sf_tool_management/models/jikimo_bom.py @@ -84,7 +84,7 @@ class jikimo_bom(models.Model): if option.name == '整体式刀具': domain = ['&'] + domain + [ - '|', + '&', # 刀具直径 ('cutting_tool_blade_diameter', '=', self.tool_inventory_id.diameter), From 378850682d966ef9004204eb35ed5764256c1327 Mon Sep 17 00:00:00 2001 From: liaodanlong Date: Mon, 23 Sep 2024 17:50:25 +0800 Subject: [PATCH 05/34] =?UTF-8?q?=E9=94=99=E8=AF=AF=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_bf_connect/models/process_status.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sf_bf_connect/models/process_status.py b/sf_bf_connect/models/process_status.py index 3bbdb5fc..1bfdd356 100644 --- a/sf_bf_connect/models/process_status.py +++ b/sf_bf_connect/models/process_status.py @@ -55,8 +55,7 @@ class StatusChange(models.Model): logging.info('接口已经执行=============') else: traceback_error = traceback.format_exc() - logging.error("bfm订单状态同步失败:%s request info %s" % traceback_error) - logging.error('/api/get/state/get_order 请求失败{}'.format(ret)) + logging.error("bfm订单状态同步失败:%s" % traceback_error) raise UserError('工厂加工同步订单状态到bfm失败') except UserError as e: traceback_error = traceback.format_exc() From 38d3a7901dea85970b9fe30bf17fc7b509d226c6 Mon Sep 17 00:00:00 2001 From: liaodanlong Date: Tue, 24 Sep 2024 10:23:09 +0800 Subject: [PATCH 06/34] =?UTF-8?q?=E5=88=80=E5=85=B7=E7=BB=84=E8=A3=85?= =?UTF-8?q?=E4=B8=8E=E6=8B=86=E8=A7=A3=E4=BF=A1=E6=81=AF=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/models/sf_message_functional_tool_assembly.py | 5 +---- sf_message/models/sf_message_functional_tool_dismantle.py | 6 +----- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/sf_message/models/sf_message_functional_tool_assembly.py b/sf_message/models/sf_message_functional_tool_assembly.py index d4e05fc0..bf745b53 100644 --- a/sf_message/models/sf_message_functional_tool_assembly.py +++ b/sf_message/models/sf_message_functional_tool_assembly.py @@ -9,10 +9,7 @@ class SFMessagefunctionalToolAssembly(models.Model): @api.model_create_multi def create(self, vals): result = super(SFMessagefunctionalToolAssembly, self).create(vals) - is_cam = False for obj in result: if obj.loading_task_source == '0' and obj.assemble_status == '0': - is_cam = True - if is_cam: - self.add_queue('功能刀具组装') + obj.add_queue('功能刀具组装') return result diff --git a/sf_message/models/sf_message_functional_tool_dismantle.py b/sf_message/models/sf_message_functional_tool_dismantle.py index dac3db28..73197f55 100644 --- a/sf_message/models/sf_message_functional_tool_dismantle.py +++ b/sf_message/models/sf_message_functional_tool_dismantle.py @@ -6,13 +6,9 @@ class SFMessagefunctionalToolDismantle(models.Model): _description = "刀具拆解单" _inherit = ['sf.functional.tool.dismantle', 'jikimo.message.dispatch'] - @api.model def create(self, vals): result = super(SFMessagefunctionalToolDismantle, self).create(vals) - is_dismantle = False for obj in result: if obj.dismantle_cause in ['寿命到期报废', '崩刀报废']and obj.state=='待拆解': - is_dismantle = True - if is_dismantle: - self.add_queue('功能刀具寿命到期') + obj.add_queue('功能刀具寿命到期') return result From 36c1c7b1705c3b39c67718acaf5ed7f304ebfed7 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Tue, 24 Sep 2024 10:56:23 +0800 Subject: [PATCH 07/34] =?UTF-8?q?=E5=8D=95=E5=B7=B2=E4=B8=8B=E5=8F=91?= =?UTF-8?q?=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/data/bussiness_node.xml | 4 +++ sf_message/models/sf_message_stock_picking.py | 21 ++++++++++----- sf_message/models/sf_message_template.py | 1 + sf_message/models/sf_message_workorder.py | 26 ++++++++++++++++++- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/sf_message/data/bussiness_node.xml b/sf_message/data/bussiness_node.xml index 924b669e..7d66e8d2 100644 --- a/sf_message/data/bussiness_node.xml +++ b/sf_message/data/bussiness_node.xml @@ -30,5 +30,9 @@ 坯料发料提醒 stock.picking + + 工单已下发通知 + mrp.workorder + \ No newline at end of file diff --git a/sf_message/models/sf_message_stock_picking.py b/sf_message/models/sf_message_stock_picking.py index ca8d6bf4..8bbe9db5 100644 --- a/sf_message/models/sf_message_stock_picking.py +++ b/sf_message/models/sf_message_stock_picking.py @@ -23,16 +23,23 @@ class SFMessageStockPicking(models.Model): contents = [] product_id = [] for message_queue_id in message_queue_ids: + i = 0 if message_queue_id.message_template_id.name == '坯料发料提醒': content = message_queue_id.message_template_id.content stock_picking_line = self.env['stock.picking'].search([('id', '=', int(message_queue_id.res_id))]) - stock_picking_info = self.env['stock.picking'].search( - [('product_id', '=', stock_picking_line.product_id.id), ('state', '=', 'assigned'), - ('check_in', '=', 'PC')]) - if stock_picking_info and stock_picking_info.product_id.id not in product_id: - content = content.replace('{{product_id}}', stock_picking_info.product_id.name) - content = content.replace('{{number}}', str(len(stock_picking_info))) - product_id.append(stock_picking_info.product_id.id) + mrp_production_info = self.env['mrp.production'].search( + [('name', '=', stock_picking_line.origin)]) + mrp_production_list = self.env['mrp.production'].search( + [('product_id', '=', mrp_production_info.product_id.id)]) + for mrp_production_line in mrp_production_list: + picking_ids = mrp_production_line.picking_ids + for picking_id in picking_ids: + if picking_id.state == 'assigned' and picking_id.check_in == 'PC': + i += 1 + if i > 0 and mrp_production_info.product_id.id not in product_id: + content = content.replace('{{product_id}}', mrp_production_info.product_id.name).replace( + '{{number}}', str(i)) + product_id.append(mrp_production_info.product_id.id) contents.append(content) else: res = super(SFMessageStockPicking, self)._get_message(message_queue_id) diff --git a/sf_message/models/sf_message_template.py b/sf_message/models/sf_message_template.py index 957b0f58..56346c27 100644 --- a/sf_message/models/sf_message_template.py +++ b/sf_message/models/sf_message_template.py @@ -13,4 +13,5 @@ class SfMessageTemplate(models.Model): res.append('sf.functional.tool.assembly') res.append('sf.functional.tool.dismantle') res.append('purchase.order') + res.append('mrp.workorder') return res diff --git a/sf_message/models/sf_message_workorder.py b/sf_message/models/sf_message_workorder.py index 626c092d..d74a663d 100644 --- a/sf_message/models/sf_message_workorder.py +++ b/sf_message/models/sf_message_workorder.py @@ -3,4 +3,28 @@ from odoo import models, fields, api, _ class SFMessageWork(models.Model): _name = 'mrp.workorder' - _inherit = ['mrp.workorder', 'jikimo.message.dispatch'] + _inherit = ['mrp.workorder', 'jikimo.message.dispatch'] + + @api.depends('production_availability', 'blocked_by_workorder_ids.state') + def _compute_state(self): + super(SFMessageWork, self)._compute_state() + if self.state == 'ready' and self.routing_type == '装夹预调': + self.add_queue('工单已下发通知') + + def _get_message(self, message_queue_ids): + contents = [] + product_id = [] + for message_queue_id in message_queue_ids: + if message_queue_id.message_template_id.name == '工单已下发通知': + content = message_queue_id.message_template_id.content + mrp_workorder_line = self.env['mrp.workorder'].search([('id', '=', int(message_queue_id.res_id))]) + mrp_workorder_list = self.env['mrp.workorder'].search( + [('product_id', '=', mrp_workorder_line.product_id.id), ('state', '=', 'ready'), + ('routing_type', '=', '装夹预调')]) + if len(mrp_workorder_list) > 0 and mrp_workorder_line.product_id.id not in product_id: + content = content.replace('{{product_id}}', mrp_workorder_line.product_id.name).replace( + '{{number}}', str(len(mrp_workorder_list))).replace( + '{{part_number}}', mrp_workorder_line.part_number if mrp_workorder_line.part_number else "") + product_id.append(mrp_workorder_line.product_id.id) + contents.append(content) + return contents From d6fdeafef613a2d910de587a4449d1d808ed29c9 Mon Sep 17 00:00:00 2001 From: hy <1298386937@qq.com> Date: Tue, 24 Sep 2024 11:14:08 +0800 Subject: [PATCH 08/34] =?UTF-8?q?=E5=88=B6=E9=80=A0-=E5=88=80=E5=85=B7?= =?UTF-8?q?=E6=A0=87=E5=87=86=E5=BA=93=E7=95=8C=E9=9D=A2=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E6=9C=89=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_base/static/src/scss/test.scss | 3 --- 1 file changed, 3 deletions(-) diff --git a/sf_base/static/src/scss/test.scss b/sf_base/static/src/scss/test.scss index c91a8a77..565e7956 100644 --- a/sf_base/static/src/scss/test.scss +++ b/sf_base/static/src/scss/test.scss @@ -159,9 +159,6 @@ td.o_required_modifier { display:inline; } .diameter{ - display: flex !important; - justify-content: flex-start !important; - align-items: center !important; } .o_address_format { display: flex !important; From 9beecab21d19b43459f567b16d7bee551d6ecf7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Tue, 24 Sep 2024 11:42:58 +0800 Subject: [PATCH 09/34] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E4=B8=8B=E5=8F=91=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/agv_scheduling.py | 25 +++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/sf_manufacturing/models/agv_scheduling.py b/sf_manufacturing/models/agv_scheduling.py index a18dc5ef..868964d5 100644 --- a/sf_manufacturing/models/agv_scheduling.py +++ b/sf_manufacturing/models/agv_scheduling.py @@ -156,17 +156,26 @@ class AgvScheduling(models.Model): if agv_site_state == '空闲': # 查询终点接驳站为agv_site_id的AGV路线 task_routes = self.env['sf.agv.task.route'].sudo().search([('end_site_id', '=', agv_site_id)]) - agv_scheduling = self.env['sf.agv.scheduling'].sudo().search( + agv_schedulings = self.env['sf.agv.scheduling'].sudo().search( [('state', '=', '待下发'), ('agv_route_type', 'in', task_routes.mapped('route_type'))], order='id asc', - limit=1 ) - task_route = task_routes.filtered( - lambda r: r.start_site_id == agv_scheduling.start_site_id and r.start_site_id == agv_scheduling.start_site_id - ) - if task_route: - # 下发AGV调度任务并修改接驳站状态为占用 - agv_scheduling.dispatch_scheduling(task_route) + for agv_scheduling in agv_schedulings: + # 找到所有起点接驳站匹配的路线 + start_matched_task_routes = task_routes.filtered( + lambda r: r.start_site_id == agv_scheduling.start_site_id + ) + # 如果调度任务有终点接驳站,找到终点接驳站匹配的路线 + if agv_scheduling.end_site_id: + matched_task_routes = start_matched_task_routes.filtered( + lambda r: r.end_site_id == agv_scheduling.end_site_id + ) + else: + matched_task_routes = start_matched_task_routes + if matched_task_routes: + # 下发AGV调度任务并修改接驳站状态为占用 + agv_scheduling.dispatch_scheduling(matched_task_routes[0]) + break; def _delivery_avg(self): config = self.env['res.config.settings'].get_values() From b986dd84733c4d0a05843ba12d44691bc2511d3a Mon Sep 17 00:00:00 2001 From: liaodanlong Date: Tue, 24 Sep 2024 14:58:32 +0800 Subject: [PATCH 10/34] =?UTF-8?q?=E5=88=80=E5=85=B7=E7=BB=84=E8=A3=85?= =?UTF-8?q?=E4=B8=8E=E6=8B=86=E8=A7=A3=E4=BF=A1=E6=81=AF=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/models/sf_message_functional_tool_dismantle.py | 1 + sf_mrs_connect/security/ir.model.access.csv | 5 +---- sf_mrs_connect/views/order_price.xml | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/sf_message/models/sf_message_functional_tool_dismantle.py b/sf_message/models/sf_message_functional_tool_dismantle.py index 73197f55..9a1a01f4 100644 --- a/sf_message/models/sf_message_functional_tool_dismantle.py +++ b/sf_message/models/sf_message_functional_tool_dismantle.py @@ -6,6 +6,7 @@ class SFMessagefunctionalToolDismantle(models.Model): _description = "刀具拆解单" _inherit = ['sf.functional.tool.dismantle', 'jikimo.message.dispatch'] + @api.model def create(self, vals): result = super(SFMessagefunctionalToolDismantle, self).create(vals) for obj in result: diff --git a/sf_mrs_connect/security/ir.model.access.csv b/sf_mrs_connect/security/ir.model.access.csv index 60d5cea5..c2212eb1 100644 --- a/sf_mrs_connect/security/ir.model.access.csv +++ b/sf_mrs_connect/security/ir.model.access.csv @@ -1,7 +1,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_sf_static_resource_datasync,sf_static_resource_datasync,model_sf_static_resource_datasync,base.group_user,1,1,1,1 -access_order_price,order.price,model_order_price,base.group_user,1,1,1,1 - - - +access_order_price,order.price,model_order_price,sf_base.group_sale_director,1,1,1,1 \ No newline at end of file diff --git a/sf_mrs_connect/views/order_price.xml b/sf_mrs_connect/views/order_price.xml index b5a9eb0f..9a44e045 100644 --- a/sf_mrs_connect/views/order_price.xml +++ b/sf_mrs_connect/views/order_price.xml @@ -8,7 +8,7 @@ From 7a8753408be9163f73de5577500717936110d783 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Tue, 24 Sep 2024 16:23:45 +0800 Subject: [PATCH 11/34] =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E8=B7=B3=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/models/sf_message_stock_picking.py | 8 +++++--- sf_message/models/sf_message_workorder.py | 5 ++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sf_message/models/sf_message_stock_picking.py b/sf_message/models/sf_message_stock_picking.py index 8bbe9db5..2eb7fe93 100644 --- a/sf_message/models/sf_message_stock_picking.py +++ b/sf_message/models/sf_message_stock_picking.py @@ -16,8 +16,9 @@ class SFMessageStockPicking(models.Model): @api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id') def _compute_state(self): super(SFMessageStockPicking, self)._compute_state() - if self.state == 'assigned' and self.check_in == 'PC': - self.add_queue('坯料发料提醒') + for record in self: + if record.state == 'assigned' and record.check_in == 'PC': + record.add_queue('坯料发料提醒') def _get_message(self, message_queue_ids): contents = [] @@ -37,8 +38,9 @@ class SFMessageStockPicking(models.Model): if picking_id.state == 'assigned' and picking_id.check_in == 'PC': i += 1 if i > 0 and mrp_production_info.product_id.id not in product_id: + url = message_queue_id.message_template_id.get_url(int(message_queue_id.res_id)) content = content.replace('{{product_id}}', mrp_production_info.product_id.name).replace( - '{{number}}', str(i)) + '{{number}}', str(i)).replace('{{request_url}}', url) product_id.append(mrp_production_info.product_id.id) contents.append(content) else: diff --git a/sf_message/models/sf_message_workorder.py b/sf_message/models/sf_message_workorder.py index d74a663d..2462b3f1 100644 --- a/sf_message/models/sf_message_workorder.py +++ b/sf_message/models/sf_message_workorder.py @@ -22,9 +22,12 @@ class SFMessageWork(models.Model): [('product_id', '=', mrp_workorder_line.product_id.id), ('state', '=', 'ready'), ('routing_type', '=', '装夹预调')]) if len(mrp_workorder_list) > 0 and mrp_workorder_line.product_id.id not in product_id: + url = message_queue_id.message_template_id.get_url(int(message_queue_id.res_id)) + "&active_id=1" content = content.replace('{{product_id}}', mrp_workorder_line.product_id.name).replace( '{{number}}', str(len(mrp_workorder_list))).replace( - '{{part_number}}', mrp_workorder_line.part_number if mrp_workorder_line.part_number else "") + '{{part_number}}', + mrp_workorder_line.part_number if mrp_workorder_line.part_number else "").replace( + '{{request_url}}', url) product_id.append(mrp_workorder_line.product_id.id) contents.append(content) return contents From 84a37a970f78752faff8d37319c793de2a800e30 Mon Sep 17 00:00:00 2001 From: liaodanlong Date: Tue, 24 Sep 2024 17:57:03 +0800 Subject: [PATCH 12/34] =?UTF-8?q?=E8=B0=83=E6=8B=A8=E5=85=A5=E5=BA=93?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/models/sf_message_stock_picking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_message/models/sf_message_stock_picking.py b/sf_message/models/sf_message_stock_picking.py index 2eb7fe93..a1611652 100644 --- a/sf_message/models/sf_message_stock_picking.py +++ b/sf_message/models/sf_message_stock_picking.py @@ -9,7 +9,7 @@ class SFMessageStockPicking(models.Model): def button_validate(self): res = super(SFMessageStockPicking, self).button_validate() - if self.location_id.name == '进货' and self.location_dest_id.name == '刀具房': + if self.location_id.name == 'Vendors' and self.location_dest_id.name == '进货': self.add_queue('调拨入库') return res From 155c5eb3298f04b1d7b0dbe3f8dabba982a6ea49 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Wed, 25 Sep 2024 10:48:35 +0800 Subject: [PATCH 13/34] =?UTF-8?q?=E5=9D=AF=E6=96=99=E9=87=87=E8=B4=AD?= =?UTF-8?q?=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/models/sf_message_purchase.py | 10 +--------- sf_message/models/sf_message_sale.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/sf_message/models/sf_message_purchase.py b/sf_message/models/sf_message_purchase.py index e9fe3956..cf0d2333 100644 --- a/sf_message/models/sf_message_purchase.py +++ b/sf_message/models/sf_message_purchase.py @@ -6,12 +6,4 @@ class SFMessagePurchase(models.Model): _name = 'purchase.order' _inherit = ['purchase.order', 'jikimo.message.dispatch'] - @api.model_create_multi - def create(self, vals_list): - res = super(SFMessagePurchase, self).create(vals_list) - if res: - try: - res.add_queue('坯料采购提醒') - except Exception as e: - logging.info('add_queue error:%s' % e) - return res + diff --git a/sf_message/models/sf_message_sale.py b/sf_message/models/sf_message_sale.py index fb9d5976..7d6cd7cd 100644 --- a/sf_message/models/sf_message_sale.py +++ b/sf_message/models/sf_message_sale.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import logging from odoo import models, fields, api, _ @@ -21,6 +22,17 @@ class SFMessageSale(models.Model): if res is True: try: self.add_queue('确认接单') + picking_ids = self.mrp_production_ids + purchase_order_id = [] + if picking_ids: + for picking_id in picking_ids: + purchase_order_ids = ( + picking_id.procurement_group_id.stock_move_ids.created_purchase_line_id.order_id | picking_id.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id).ids + purchase_order_id.extend(purchase_order_ids) + if purchase_order_id: + purchase_order_list = self.env['purchase.order'].search([('id', 'in', purchase_order_id)]) + for purchase_order_info in purchase_order_list: + purchase_order_info.add_queue('坯料采购提醒') except Exception as e: logging.info('add_queue error:%s' % e) return res From 7454297dcdc3b4d22bc21720c842f38aa0e7b7d8 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Wed, 25 Sep 2024 11:24:01 +0800 Subject: [PATCH 14/34] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E6=95=85=E9=9A=9C=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_maintenance/models/sf_maintenance_logs.py | 17 ++++++++++++++--- sf_maintenance/views/maintenance_logs_views.xml | 9 +++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/sf_maintenance/models/sf_maintenance_logs.py b/sf_maintenance/models/sf_maintenance_logs.py index 7f80e163..c1a82a1b 100644 --- a/sf_maintenance/models/sf_maintenance_logs.py +++ b/sf_maintenance/models/sf_maintenance_logs.py @@ -1,13 +1,14 @@ # -*-coding:utf-8-*- -from odoo import fields, models +from odoo import fields, models, api class SfMaintenanceLogs(models.Model): _name = 'sf.maintenance.logs' _description = '设备故障日志' + _order = 'alarm_time desc' - code = fields.Char(string='编码') - name = fields.Char(string='名称') + code = fields.Char(string='编码', readonly=True) + name = fields.Char(string='名称', compute='_compute_name') type = fields.Selection([('type1', '类型1'), ('type2', '类型2')], string='类型') brand = fields.Many2one('sf.machine.brand', related='maintenance_equipment_id.brand_id', string='品牌') maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='机台号') @@ -28,3 +29,13 @@ class SfMaintenanceLogs(models.Model): fault_duration = fields.Float(string='故障时长') note = fields.Text(string='备注') active = fields.Boolean('Active', default=True) + + @api.depends('code') + def _compute_name(self): + for record in self: + if record.code: + record.name = self.env['maintenance.equipment'].sudo().search([('code', '=', record.code), ('active', '=', True)]).name + record.maintenance_equipment_id = self.env['maintenance.equipment'].sudo().search([('code', '=', record.code), ('active', '=', True)]).id + else: + record.name = '' + diff --git a/sf_maintenance/views/maintenance_logs_views.xml b/sf_maintenance/views/maintenance_logs_views.xml index b3922595..af334fac 100644 --- a/sf_maintenance/views/maintenance_logs_views.xml +++ b/sf_maintenance/views/maintenance_logs_views.xml @@ -8,8 +8,8 @@ - - + + @@ -37,13 +37,14 @@

- +

- + + From 1e721d68bf2c4f49b05a78fbbe5a9b4a6cf25c32 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Wed, 25 Sep 2024 11:41:23 +0800 Subject: [PATCH 15/34] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=A7=86=E5=9B=BE?= =?UTF-8?q?=E4=B8=8E=E5=A2=9E=E5=8A=A0=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_maintenance/models/sf_maintenance_logs.py | 1 + sf_maintenance/views/maintenance_logs_views.xml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/sf_maintenance/models/sf_maintenance_logs.py b/sf_maintenance/models/sf_maintenance_logs.py index c1a82a1b..62672e16 100644 --- a/sf_maintenance/models/sf_maintenance_logs.py +++ b/sf_maintenance/models/sf_maintenance_logs.py @@ -10,6 +10,7 @@ class SfMaintenanceLogs(models.Model): code = fields.Char(string='编码', readonly=True) name = fields.Char(string='名称', compute='_compute_name') type = fields.Selection([('type1', '类型1'), ('type2', '类型2')], string='类型') + status = fields.Selection([('待处理', '待处理'), ('已处理', '已处理')], string='状态', default='待处理') brand = fields.Many2one('sf.machine.brand', related='maintenance_equipment_id.brand_id', string='品牌') maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='机台号') maintenance_equipment_oee_id = fields.Many2one('maintenance.equipment.oee', string='设备oee') diff --git a/sf_maintenance/views/maintenance_logs_views.xml b/sf_maintenance/views/maintenance_logs_views.xml index af334fac..43ee0ccf 100644 --- a/sf_maintenance/views/maintenance_logs_views.xml +++ b/sf_maintenance/views/maintenance_logs_views.xml @@ -58,6 +58,8 @@ + + @@ -84,6 +86,7 @@ + From b7ff8d0bd53078ca9d77fa21e0e4945eefd0670d Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Wed, 25 Sep 2024 11:52:29 +0800 Subject: [PATCH 16/34] =?UTF-8?q?=E6=B7=BB=E5=8A=A0CNC=E7=BC=BA=E5=88=80?= =?UTF-8?q?=E5=88=9B=E5=BB=BACAM=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_tool_management/models/base.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index 84460220..33ab0790 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -321,9 +321,12 @@ class CAMWorkOrderProgramKnifePlan(models.Model): # 获取编程单号 programming_no = cnc_processing.workorder_id.production_id.programming_no - if not self.env['sf.cam.work.order.program.knife.plan'].sudo().search( - [('programming_no', '=', programming_no), - ('functional_tool_name', '=', cnc_processing.cutting_tool_name)]): + logging.info(f'编程单号:{programming_no}') + cam_id = self.env['sf.cam.work.order.program.knife.plan'].sudo().search( + [('programming_no', '=', programming_no), + ('functional_tool_name', '=', cnc_processing.cutting_tool_name)]) + logging.info(f'CAM装刀计划:{cam_id}') + if not cam_id: knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({ 'name': cnc_processing.workorder_id.production_id.name, 'programming_no': programming_no, From ef17c9920cfeb3b4969f74ee33d5f84a411eea87 Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Wed, 25 Sep 2024 12:00:46 +0800 Subject: [PATCH 17/34] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=80=E5=94=AE+?= =?UTF-8?q?=E6=8E=92=E7=A8=8B=E6=B6=88=E6=81=AF=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/models/sf_message_sale.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/sf_message/models/sf_message_sale.py b/sf_message/models/sf_message_sale.py index fb9d5976..ef94b7fe 100644 --- a/sf_message/models/sf_message_sale.py +++ b/sf_message/models/sf_message_sale.py @@ -28,12 +28,20 @@ class SFMessageSale(models.Model): # 继承并重写jikimo.message.dispatch的_get_message() def _get_message(self, message_queue_ids): res = super(SFMessageSale, self)._get_message(message_queue_ids) - if message_queue_ids.message_template_id.bussiness_node_id.name == '确认接单': - # sale_order = self.env['sale.order'].search([('id', '=', message_queue_ids.model.res_id)]) - sale_order_line = self.env['sale.order.line'].search([('order_id', '=', int(message_queue_ids.res_id))]) - if len(sale_order_line) == 1: - product = sale_order_line[0].product_id.name - elif len(sale_order_line) > 1: - product = '%s...' % sale_order_line[0].product_id.name - res[0] = res[0].replace('{{product_id}}', product) + new_res = [] + processed_messages = set() # 用于跟踪已经处理过的消息 + for item in message_queue_ids: + if item.message_template_id.bussiness_node_id.name == '确认接单': + sale_order_line = self.env['sale.order.line'].search([('order_id', '=', int(item.res_id))]) + if len(sale_order_line) == 1: + product = sale_order_line[0].product_id.name + elif len(sale_order_line) > 1: + product = '%s...' % sale_order_line[0].product_id.name + for message in res: + message_text = message.replace('{{product_id}}', product) + if message_text not in processed_messages: + new_res.append(message_text) + processed_messages.add(message_text) + if new_res: + res = new_res return res From d488824e3d57c6697710d87ab0822d7d9917260c Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Wed, 25 Sep 2024 13:50:50 +0800 Subject: [PATCH 18/34] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=88=86=E9=A1=B5?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=EF=BC=9B=E5=90=88=E5=B9=B6=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E7=9B=B8=E5=90=8C=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_machine_connect/controllers/controllers.py | 150 +++++++++++++----- sf_maintenance/models/sf_maintenance_oee.py | 20 ++- .../views/maintenance_equipment_oee_views.xml | 26 ++- 3 files changed, 146 insertions(+), 50 deletions(-) diff --git a/sf_machine_connect/controllers/controllers.py b/sf_machine_connect/controllers/controllers.py index fb783666..b8f2dca6 100644 --- a/sf_machine_connect/controllers/controllers.py +++ b/sf_machine_connect/controllers/controllers.py @@ -231,6 +231,95 @@ class Sf_Dashboard_Connect(http.Controller): res['message'] = '前端请求日志数据失败,原因:%s' % e return json.dumps(res) + @http.route('/api/logs/page_data', type='http', auth='public', methods=['GET', 'POST'], + csrf=False, cors="*") + def logs_page_data(self, **kw): + """ + 拿到日志数据返回给大屏展示(支持时间戳分页) + :param kw: + :return: + """ + res = {'status': 1, 'message': '成功', 'data': {}} + logging.info('前端请求日志数据的参数为:%s' % kw) + + try: + # 连接数据库 + conn = psycopg2.connect(**db_config) + cur = conn.cursor() + + # 获取并解析传递的参数 + machine_list = ast.literal_eval(kw.get('machine_list', '[]')) + begin_time_str = kw.get('begin_time', '').strip('"') + end_time_str = kw.get('end_time', '').strip('"') + page = int(kw.get('page', 1)) # 默认页码为1 + page_size = int(kw.get('page_size', 80)) # 默认每页条数为10 + + begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S') + end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S') + + # 计算分页的 offset + offset = (page - 1) * page_size + + # 先查询符合条件的总记录数 + total_records = 0 + for item in machine_list: + count_sql = ''' + SELECT COUNT(*) + FROM device_data + WHERE device_name = %s AND time >= %s AND time <= %s; + ''' + # 执行总记录数查询 + cur.execute(count_sql, (item, begin_time, end_time)) + record_count = cur.fetchone()[0] # 获取总记录数 + total_records += record_count + + # 计算总页数 + if total_records > 0: + total_pages = (total_records + page_size - 1) // page_size # 向上取整 + else: + total_pages = 0 + + # 将总页数和总记录数返回到响应中 + res['total_records'] = total_records + res['total_pages'] = total_pages + + for item in machine_list: + sql = ''' + SELECT time, device_state, program_name + FROM device_data + WHERE device_name = %s AND time >= %s AND time <= %s + ORDER BY time DESC + LIMIT %s OFFSET %s; + ''' + # 执行SQL命令,使用参数绑定 + cur.execute(sql, (item, begin_time, end_time, page_size, offset)) + results = cur.fetchall() + + # 将数据按照 equipment_code 进行分组 + if item not in res['data']: + res['data'][item] = [] + + for result in results: + res['data'][item].append({ + 'time': result[0].strftime('%Y-%m-%d %H:%M:%S'), + 'state': result[1], + 'production_name': result[2], + }) + + return json.dumps(res) # 返回分页数据 + + except Exception as e: + logging.info('前端请求日志数据失败,原因:%s' % e) + res['status'] = -1 + res['message'] = '前端请求日志数据失败,原因:%s' % e + return json.dumps(res) + + finally: + if cur: + cur.close() + if conn: + conn.close() + # 返回CNC机床列表 @http.route('/api/CNCList', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") @@ -718,7 +807,8 @@ class Sf_Dashboard_Connect(http.Controller): 'material': material, 'dimensions': dimensions, 'order_qty': finish_order.product_qty, - 'finish_time': finish_order.actual_end_time.strftime('%Y-%m-%d %H:%M:%S') if finish_order.actual_end_time else ' ' + 'finish_time': finish_order.actual_end_time.strftime( + '%Y-%m-%d %H:%M:%S') if finish_order.actual_end_time else ' ' } done_data.append(line_dict) @@ -802,54 +892,30 @@ class Sf_Dashboard_Connect(http.Controller): """ 查询设备的异常情况 """ - res = {'status': 1, 'message': '成功', 'data': {}} + res = {'status': 1, 'message': '成功', 'data': []} logging.info('前端请求机床数据的参数为:%s' % kw) - # 连接数据库 - conn = psycopg2.connect(**db_config) - cur = conn.cursor() try: - # 获取请求的机床数据 + maintenance_logs_obj = request.env['sf.maintenance.logs'].sudo() + # # 获取请求的机床数据 # machine_list = ast.literal_eval(kw['machine_list']) - # idle_times = [] - # idle_dict = {} - # for item in machine_list: - sql = ''' - SELECT DISTINCT ON (alarm_time) alarm_time, alarm_message, system_date, system_time, alarm_repair_time - FROM device_data - WHERE alarm_time IS NOT NULL - ORDER BY alarm_time, time; + # machine_data = equipment_obj.search([('code', '=', item)]) + for log in maintenance_logs_obj.search([]): + res['data'].append({ + 'name': log.name, + 'alarm_time': log.alarm_time.strftime('%Y-%m-%d %H:%M:%S'), + 'fault_alarm_info': log.fault_alarm_info, + 'status': log.status, + 'note': log.note, + 'alarm_level': log.alarm_level + }) - ''' - # 执行SQL命令 - cur.execute(sql) - result = cur.fetchall() - # print('result', result) - - # 将查询结果转换为字典列表 - data = [] - for row in result: - record = { - 'alarm_time': row[0], - 'alarm_message': row[1], - 'system_date': row[2], - 'system_time': row[3], - 'alarm_repair_time': row[4] - } - data.append(record) - - # 将数据填充到返回结果中 - res['data'] = data - - # 返回统计结果 - return json.dumps(res, ensure_ascii=False) except Exception as e: - print(f"An error occurred: {e}") - return json.dumps(res) - finally: - cur.close() - conn.close() + logging.error(f"An error occurred: {e}") + + return json.dumps(res) + # 设备oee @http.route('/api/OEE', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") diff --git a/sf_maintenance/models/sf_maintenance_oee.py b/sf_maintenance/models/sf_maintenance_oee.py index 1a2e4f10..ee2c209c 100644 --- a/sf_maintenance/models/sf_maintenance_oee.py +++ b/sf_maintenance/models/sf_maintenance_oee.py @@ -66,11 +66,14 @@ class SfMaintenanceEquipmentOEE(models.Model): if result['status'] == 1: logs_list = result['data'][self.equipment_code] logs_detail = '' + log_state = '' for log in logs_list: - print('loooooooooooooooooooogs', log) - production_name = log['production_name'] if log['production_name'] else ' ' - logs_detail += '' + log['time'] + '' + log[ - 'state'] + '' + production_name + '' + if log['state'] != log_state: + print('loooooooooooooooooooogs', log) + production_name = log['production_name'] if log['production_name'] else ' ' + logs_detail += '' + log['time'] + '' + log[ + 'state'] + '' + production_name + '' + log_state = log['state'] # self.day_logs_detail = '' + logs_detail + '
时间事件/状态加工工单
' self.day_logs_detail = ''' @@ -119,10 +122,13 @@ class SfMaintenanceEquipmentOEE(models.Model): if result['status'] == 1: logs_list = result['data'][self.equipment_code] logs_detail = '' + log_state = '' for log in logs_list: - production_name = log['production_name'] if log['production_name'] else ' ' - logs_detail += '' + if log['state'] != log_state: + production_name = log['production_name'] if log['production_name'] else ' ' + logs_detail += '' + log_state = log['state'] # self.day_logs_detail = '
' + log['time'] + '' + log[ - 'state'] + '' + production_name + '
' + log['time'] + '' + log[ + 'state'] + '' + production_name + '
' + logs_detail + '
时间事件/状态加工工单
' self.history_logs_detail = ''' diff --git a/sf_maintenance/views/maintenance_equipment_oee_views.xml b/sf_maintenance/views/maintenance_equipment_oee_views.xml index 33749809..b798b0ab 100644 --- a/sf_maintenance/views/maintenance_equipment_oee_views.xml +++ b/sf_maintenance/views/maintenance_equipment_oee_views.xml @@ -55,7 +55,31 @@