From 1da3989fa302a2f515bd624bdb406c5feee2ad34 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Tue, 17 Dec 2024 11:34:24 +0800 Subject: [PATCH 01/44] =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/__manifest__.py | 2 +- sf_message/controllers/main.py | 16 ++++++++ sf_message/data/bussiness_node.xml | 14 +++++++ sf_message/data/template_data.xml | 41 ++++++++++++++++++- sf_message/models/__init__.py | 1 + .../models/sf_message_mrp_production.py | 32 +++++++++++++++ .../sf_message_mrp_production_wizard.py | 17 ++++++++ sf_message/models/sf_message_sale.py | 34 ++++++++------- 8 files changed, 141 insertions(+), 16 deletions(-) create mode 100644 sf_message/models/sf_message_mrp_production_wizard.py diff --git a/sf_message/__manifest__.py b/sf_message/__manifest__.py index 8178973b..9181b422 100644 --- a/sf_message/__manifest__.py +++ b/sf_message/__manifest__.py @@ -11,7 +11,7 @@ """, 'category': 'sf', 'website': 'https://www.sf.jikimo.com', - 'depends': ['sale', 'purchase', 'sf_plan', 'jikimo_message_notify', 'stock', 'sf_quality', 'mrp'], + 'depends': ['sale', 'purchase', 'sf_plan', 'jikimo_message_notify', 'stock', 'sf_quality', 'mrp','sf_manufacturing'], 'data': [ 'data/bussiness_node.xml', 'data/cron_data.xml', diff --git a/sf_message/controllers/main.py b/sf_message/controllers/main.py index 11e776dc..9537417e 100644 --- a/sf_message/controllers/main.py +++ b/sf_message/controllers/main.py @@ -4,6 +4,7 @@ import logging from odoo import http from odoo.http import request from odoo.addons.sf_mrs_connect.controllers.controllers import Sf_Mrs_Connect +from odoo.addons.sf_bf_connect.controllers.controllers import Sf_Bf_Connect from odoo.addons.sf_base.commons.common import Common _logger = logging.getLogger(__name__) @@ -58,3 +59,18 @@ class MessageSfMrsConnect(Sf_Mrs_Connect): res = {'code': 400, 'message': '设备故障信息推送失败', 'error': str(e)} return json.JSONEncoder().encode(res) + +class MessageSfBfConnect(Sf_Bf_Connect): + @http.route('/api/bfm_process_order/list', type='http', auth='sf_token', methods=['GET', 'POST'], csrf=False, + cors="*") + def get_bfm_process_order_list(self, **kw): + res = super(MessageSfBfConnect, self).get_bfm_process_order_list(**kw) + response_data = json.loads(res.data.decode('utf-8')) + if response_data['status'] == 1: + try: + _logger.info('已进入待接单消息推送:%s' % response_data) + sale_order = request.env['sale.order'].sudo().search([('name', '=', response_data['factory_order_no'])]) + sale_order.add_queue('待接单') + except Exception as e: + logging.info('add_queue error:%s' % e) + return res diff --git a/sf_message/data/bussiness_node.xml b/sf_message/data/bussiness_node.xml index a00ed056..925dc505 100644 --- a/sf_message/data/bussiness_node.xml +++ b/sf_message/data/bussiness_node.xml @@ -22,6 +22,15 @@ sale.order + + 待确认供货方式 + sale.order + + + + 待确认加工路线 + mrp.production + 调拨入库 @@ -106,5 +115,10 @@ 设备故障 sf.maintenance.logs + + + 待排程 + mrp.production + \ No newline at end of file diff --git a/sf_message/data/template_data.xml b/sf_message/data/template_data.xml index beb37771..acaf363f 100644 --- a/sf_message/data/template_data.xml +++ b/sf_message/data/template_data.xml @@ -10,7 +10,7 @@ markdown normal ### 待接单提醒: -单号:销售订单[{{name}}]({{url}}) +单号:询价单[{{name}}]({{url}}) 事项:请确认是否接单。 @@ -275,5 +275,44 @@ 机台号:[{{maintenance_equipment_id.name}}]({{url}}) 事项:{{create_date}}故障报警 + + + 待确认供货方式 + + sale.order + + markdown + normal + ### 待确认供货方式提醒: +单号:销售订单[{{name}}]({{url}}) +事项:请确认供货方式。 + + + + + 待确认加工路线 + + mrp.production + + markdown + normal + ### 待确认加工路线提醒: +单号:产品[{{name}}]({{url}}) +事项:有{{production_num}}个制造订单需要确认加工路线。 + + + + + 待排程 + + mrp.production + + markdown + normal + ### 待排程提醒: +单号:产品[{{name}}]({{url}}) +事项:有{{production_num}}个制造订单待排程。 + + \ No newline at end of file diff --git a/sf_message/models/__init__.py b/sf_message/models/__init__.py index 0b9c9ad6..b9cc5079 100644 --- a/sf_message/models/__init__.py +++ b/sf_message/models/__init__.py @@ -10,3 +10,4 @@ from . import sf_message_functional_tool_dismantle from . import sf_message_mrp_production from . import sf_message_quality_cnc_test from . import sf_message_maintenance_logs +from . import sf_message_mrp_production_wizard diff --git a/sf_message/models/sf_message_mrp_production.py b/sf_message/models/sf_message_mrp_production.py index a60f2161..fed30ae9 100644 --- a/sf_message/models/sf_message_mrp_production.py +++ b/sf_message/models/sf_message_mrp_production.py @@ -27,6 +27,7 @@ class SFMessageMrpProduction(models.Model): # 获取发送消息内容 def _get_message(self, message_queue_ids): contents = [] + unique_products = set() for message_queue_id in message_queue_ids: if message_queue_id.message_template_id.name == '生产完工入库提醒': content = message_queue_id.message_template_id.content @@ -40,6 +41,37 @@ class SFMessageMrpProduction(models.Model): content = content.replace('{{name}}', stock_picking_sfp.name).replace( '{{sale_order_name}}', mrp_production.origin).replace('{{request_url}}', url) contents.append(content) + if message_queue_id.message_template_id.name == '待确认加工路线': + content = message_queue_id.message_template_id.content + mrp_production = self.env['mrp.production'].sudo().search([('id', '=', int(message_queue_id.res_id))]) + production_num = self.env['mrp.production'].sudo().search_count( + [('product_id', '=', mrp_production.product_id.id), ('state', '=', 'technology_to_confirmed')]) + if production_num >= 1: + url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + action_id = self.env.ref('mrp.mrp_production_action').id + url_with_id = f"{url}/web#view_type=list&action={action_id}" + content = (content.replace('{{name}}', mrp_production.product_id.name) + .replace('{{url}}', url_with_id) + .replace('{{production_num}}', str(production_num))) + contents.append(content) + if message_queue_id.message_template_id.name == '待排程': + content = message_queue_id.message_template_id.content + mrp_production = self.env['mrp.production'].sudo().search([('id', '=', int(message_queue_id.res_id))]) + unique_products.add(mrp_production.product_id.id) + if unique_products: + content_info = content + for products_id in unique_products: + product_name = self.env['product.product'].sudo().search([('id', '=', products_id)]).name + production_num = self.env['mrp.production'].sudo().search_count( + [('product_id', '=', products_id), ('state', '=', 'confirmed')]) + if production_num >= 1: + url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + action_id = self.env.ref('sf_plan.sf_production_plan_action1').id + url_with_id = f"{url}/web#view_type=list&action={action_id}" + new_content = (content_info.replace('{{name}}', product_name) + .replace('{{url}}', url_with_id) + .replace('{{production_num}}', str(production_num))) + contents.append(new_content) logging.info('生产完工入库提醒: %s' % contents) return contents diff --git a/sf_message/models/sf_message_mrp_production_wizard.py b/sf_message/models/sf_message_mrp_production_wizard.py new file mode 100644 index 00000000..c98152d3 --- /dev/null +++ b/sf_message/models/sf_message_mrp_production_wizard.py @@ -0,0 +1,17 @@ +import logging +from odoo import models, fields, api, _ + + +class SFMessageMrpProductionWizard(models.TransientModel): + _name = 'sf.production.technology.wizard' + _description = "制造订单工艺确认向导" + _inherit = ['sf.production.technology.wizard', 'jikimo.message.dispatch'] + + def confirm(self): + super(SFMessageMrpProductionWizard, self).confirm() + try: + for production_info in self.production_id: + if production_info.state == 'confirmed': + production_info.add_queue('待排程') + except Exception as e: + logging.info('add_queue待排程 error:%s' % e) diff --git a/sf_message/models/sf_message_sale.py b/sf_message/models/sf_message_sale.py index 58d1a021..c96c845b 100644 --- a/sf_message/models/sf_message_sale.py +++ b/sf_message/models/sf_message_sale.py @@ -8,17 +8,6 @@ class SFMessageSale(models.Model): _name = 'sale.order' _inherit = ['sale.order', 'jikimo.message.dispatch'] - @api.model_create_multi - def create(self, vals_list): - res = super(SFMessageSale, self).create(vals_list) - if res: - try: - logging.info('add_queue res:%s' % res) - res.add_queue('待接单') - except Exception as e: - logging.info('add_queue error:%s' % e) - return res - # 确认接单 def action_confirm(self): res = super(SFMessageSale, self).action_confirm() @@ -27,21 +16,36 @@ class SFMessageSale(models.Model): self.add_queue('确认接单') picking_ids = self.mrp_production_ids purchase_order_id = [] + unique_products = set() if picking_ids: for picking_id in picking_ids: + unique_products.add(picking_id.product_id.id) 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'].sudo().search([('id', 'in', purchase_order_id)]) + purchase_order_list = self.env['purchase.order'].sudo().search( + [('id', 'in', purchase_order_id)]) for purchase_order_info in purchase_order_list: purchase_order_info.add_queue('坯料采购提醒') + if unique_products: + for product_id in unique_products: + production_info = self.env['mrp.production'].sudo().search( + [('product_id', '=', product_id)], limit=1, order='id') + production_info.add_queue('待确认加工路线') except Exception as e: logging.info('add_queue error:%s' % e) logging.info('action_confirm res:%s' % res) return res + def confirm_to_supply_method(self): + super(SFMessageSale, self).confirm_to_supply_method() + try: + self.add_queue('待确认供货方式') + except Exception as e: + logging.info('add_queue待确认供货方式 error:%s' % e) + # 继承并重写jikimo.message.dispatch的_get_message() def _get_message(self, message_queue_ids): contents = [] @@ -53,9 +57,11 @@ class SFMessageSale(models.Model): time_range = timedelta(minutes=2) i = 0 for item in message_queue_ids: - if item.message_template_id.bussiness_node_id.name == '待接单': + if item.message_template_id.bussiness_node_id.name in ('待接单', '待确认供货方式'): content = super(SFMessageSale, self)._get_message(item) - action_id = self.env.ref('sale.action_quotations_with_onboarding').id + action_id = self.env.ref('sale.action_quotations_with_onboarding').id \ + if item.message_template_id.bussiness_node_id.name == '待接单' \ + else self.env.ref('sale.action_orders').id url_with_id = f"{url}/web#id={item.res_id}&view_type=form&action={action_id}" content = content[0].replace('{{url}}', url_with_id) contents.append(content) From d7a25580d197ba844d6204378b2878a29c226f13 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Tue, 17 Dec 2024 14:42:15 +0800 Subject: [PATCH 02/44] =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/models/__init__.py | 1 + .../models/sf_message_mrp_production.py | 49 ++++++++++--------- ...sf_message_mrp_production_adjust_wizard.py | 17 +++++++ sf_message/models/sf_message_sale.py | 8 +-- 4 files changed, 45 insertions(+), 30 deletions(-) create mode 100644 sf_message/models/sf_message_mrp_production_adjust_wizard.py diff --git a/sf_message/models/__init__.py b/sf_message/models/__init__.py index b9cc5079..1e659c52 100644 --- a/sf_message/models/__init__.py +++ b/sf_message/models/__init__.py @@ -11,3 +11,4 @@ from . import sf_message_mrp_production from . import sf_message_quality_cnc_test from . import sf_message_maintenance_logs from . import sf_message_mrp_production_wizard +from . import sf_message_mrp_production_adjust_wizard diff --git a/sf_message/models/sf_message_mrp_production.py b/sf_message/models/sf_message_mrp_production.py index fed30ae9..00748511 100644 --- a/sf_message/models/sf_message_mrp_production.py +++ b/sf_message/models/sf_message_mrp_production.py @@ -28,6 +28,7 @@ class SFMessageMrpProduction(models.Model): def _get_message(self, message_queue_ids): contents = [] unique_products = set() + technology_to_confirmed = set() for message_queue_id in message_queue_ids: if message_queue_id.message_template_id.name == '生产完工入库提醒': content = message_queue_id.message_template_id.content @@ -44,37 +45,39 @@ class SFMessageMrpProduction(models.Model): if message_queue_id.message_template_id.name == '待确认加工路线': content = message_queue_id.message_template_id.content mrp_production = self.env['mrp.production'].sudo().search([('id', '=', int(message_queue_id.res_id))]) - production_num = self.env['mrp.production'].sudo().search_count( - [('product_id', '=', mrp_production.product_id.id), ('state', '=', 'technology_to_confirmed')]) - if production_num >= 1: - url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') - action_id = self.env.ref('mrp.mrp_production_action').id - url_with_id = f"{url}/web#view_type=list&action={action_id}" - content = (content.replace('{{name}}', mrp_production.product_id.name) - .replace('{{url}}', url_with_id) - .replace('{{production_num}}', str(production_num))) - contents.append(content) + technology_to_confirmed.add(mrp_production.product_id.id) if message_queue_id.message_template_id.name == '待排程': content = message_queue_id.message_template_id.content mrp_production = self.env['mrp.production'].sudo().search([('id', '=', int(message_queue_id.res_id))]) unique_products.add(mrp_production.product_id.id) if unique_products: - content_info = content - for products_id in unique_products: - product_name = self.env['product.product'].sudo().search([('id', '=', products_id)]).name - production_num = self.env['mrp.production'].sudo().search_count( - [('product_id', '=', products_id), ('state', '=', 'confirmed')]) - if production_num >= 1: - url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') - action_id = self.env.ref('sf_plan.sf_production_plan_action1').id - url_with_id = f"{url}/web#view_type=list&action={action_id}" - new_content = (content_info.replace('{{name}}', product_name) - .replace('{{url}}', url_with_id) - .replace('{{production_num}}', str(production_num))) - contents.append(new_content) + unique_products_contents = self.get_production_info(content, unique_products, 'confirmed', + 'sf_plan.sf_production_plan_action1') + contents.extend(unique_products_contents) + if technology_to_confirmed: + technology_to_confirmed_contents = self.get_production_info(content, technology_to_confirmed, + 'technology_to_confirmed', + 'mrp.mrp_production_action') + contents.extend(technology_to_confirmed_contents) logging.info('生产完工入库提醒: %s' % contents) return contents + def get_production_info(self, content, product_ids, state, action_id): + contents = [] + for products_id in product_ids: + product_name = self.env['product.product'].sudo().search([('id', '=', products_id)]).name + production_num = self.env['mrp.production'].sudo().search_count( + [('product_id', '=', products_id), ('state', '=', state)]) + if production_num >= 1: + url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + action_id = self.env.ref(action_id).id + url_with_id = f"{url}/web#view_type=list&action={action_id}" + new_content = (content.replace('{{name}}', product_name) + .replace('{{url}}', url_with_id) + .replace('{{production_num}}', str(production_num))) + contents.append(new_content) + return contents + def request_url(self, id): url = self.env['ir.config_parameter'].get_param('web.base.url') action_id = self.env.ref('stock.action_picking_tree_all').id diff --git a/sf_message/models/sf_message_mrp_production_adjust_wizard.py b/sf_message/models/sf_message_mrp_production_adjust_wizard.py new file mode 100644 index 00000000..224b845f --- /dev/null +++ b/sf_message/models/sf_message_mrp_production_adjust_wizard.py @@ -0,0 +1,17 @@ +import logging +from odoo import models, fields, api, _ + + +class SFMessageMrpProductionAdjustWizard(models.TransientModel): + _name = 'sf.production.technology.re_adjust.wizard' + _description = "制造订单工艺调整" + _inherit = ['sf.production.technology.re_adjust.wizard', 'jikimo.message.dispatch'] + + def confirm(self): + super(SFMessageMrpProductionAdjustWizard, self).confirm() + try: + for production_info in self.production_id: + if production_info.state == 'technology_to_confirmed': + production_info.add_queue('待确认加工路线') + except Exception as e: + logging.info('add_queue待确认加工路线 error:%s' % e) diff --git a/sf_message/models/sf_message_sale.py b/sf_message/models/sf_message_sale.py index c96c845b..a76468dd 100644 --- a/sf_message/models/sf_message_sale.py +++ b/sf_message/models/sf_message_sale.py @@ -16,10 +16,9 @@ class SFMessageSale(models.Model): self.add_queue('确认接单') picking_ids = self.mrp_production_ids purchase_order_id = [] - unique_products = set() if picking_ids: for picking_id in picking_ids: - unique_products.add(picking_id.product_id.id) + picking_id.add_queue('待确认加工路线') 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 @@ -29,11 +28,6 @@ class SFMessageSale(models.Model): [('id', 'in', purchase_order_id)]) for purchase_order_info in purchase_order_list: purchase_order_info.add_queue('坯料采购提醒') - if unique_products: - for product_id in unique_products: - production_info = self.env['mrp.production'].sudo().search( - [('product_id', '=', product_id)], limit=1, order='id') - production_info.add_queue('待确认加工路线') except Exception as e: logging.info('add_queue error:%s' % e) logging.info('action_confirm res:%s' % res) From 42444e6c8358a440b2a8fbce2d0d4433ba751388 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Tue, 17 Dec 2024 17:21:36 +0800 Subject: [PATCH 03/44] =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/data/template_data.xml | 4 +- sf_message/models/sf_message_stock_picking.py | 39 +++++-------------- 2 files changed, 11 insertions(+), 32 deletions(-) diff --git a/sf_message/data/template_data.xml b/sf_message/data/template_data.xml index acaf363f..bcc12441 100644 --- a/sf_message/data/template_data.xml +++ b/sf_message/data/template_data.xml @@ -72,8 +72,8 @@ markdown normal ### 坯料发料提醒: -单号:产品[{{product_id}}]({{request_url}}) -事项:共{{number}}个生产发料单待确认处理 +单号:发料单[{{name}}]({{request_url}}) +事项:请确认坯料发料单并处理 diff --git a/sf_message/models/sf_message_stock_picking.py b/sf_message/models/sf_message_stock_picking.py index 6e80c670..38a6fc16 100644 --- a/sf_message/models/sf_message_stock_picking.py +++ b/sf_message/models/sf_message_stock_picking.py @@ -49,26 +49,18 @@ class SFMessageStockPicking(models.Model): def _get_message(self, message_queue_ids): 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'].sudo().search([('id', '=', int(message_queue_id.res_id))]) - mrp_production_info = self.env['mrp.production'].sudo().search( - [('name', '=', stock_picking_line.origin)]) - mrp_production_list = self.env['mrp.production'].sudo().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: - url = self.request_url() - content = content.replace('{{product_id}}', mrp_production_info.product_id.name).replace( - '{{number}}', str(i)).replace('{{request_url}}', url) - product_id.append(mrp_production_info.product_id.id) + stock_picking_line = self.env['stock.picking'].sudo().search( + [('id', '=', int(message_queue_id.res_id))]) + if stock_picking_line.state == 'assigned': + url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + action_id = self.env.ref('stock.action_picking_tree_ready').id + menu_id = self.env['ir.model.data'].sudo().search([('name', '=', 'module_theme_treehouse')]).id + url_with_id = f"{url}/web#view_type=form&action={action_id}&menu_id={menu_id}&id={stock_picking_line.id}" + content = content.replace('{{name}}', stock_picking_line.name).replace( + '{{request_url}}', url_with_id) contents.append(content) elif message_queue_id.message_template_id.name == '订单发货提醒': content = self.deal_stock_picking_sfp(message_queue_id) @@ -86,19 +78,6 @@ class SFMessageStockPicking(models.Model): else: return super(SFMessageStockPicking, self).get_special_url(id, tmplate_name, special_name, model_id) - def request_url(self): - url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') - action_id = self.env.ref('stock.stock_picking_type_action').id - menu_id = self.env['ir.model.data'].sudo().search([('name', '=', 'module_theme_treehouse')]).id - # 查询参数 - params = {'menu_id': menu_id, 'action': action_id, 'model': 'stock.picking', - 'view_type': 'kanban'} - # 拼接查询参数 - query_string = urlencode(params) - # 拼接URL - full_url = url + "/web#" + query_string - return full_url - def request_url1(self, id): url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') action_id = self.env.ref('stock.action_picking_tree_all').id From 79d188fb5c7a099502e849cf32d982904befe48a Mon Sep 17 00:00:00 2001 From: guanhuan Date: Wed, 18 Dec 2024 16:26:28 +0800 Subject: [PATCH 04/44] =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wizard/production_technology_wizard.py | 1 + sf_message/data/bussiness_node.xml | 15 ++++++++ sf_message/data/template_data.xml | 36 +++++++++++++++++++ .../sf_message_mrp_production_wizard.py | 8 ++++- sf_message/models/sf_message_purchase.py | 29 ++++++++++++++- sf_message/models/sf_message_sale.py | 6 ++++ 6 files changed, 93 insertions(+), 2 deletions(-) diff --git a/sf_manufacturing/wizard/production_technology_wizard.py b/sf_manufacturing/wizard/production_technology_wizard.py index e5976aaa..6e91e053 100644 --- a/sf_manufacturing/wizard/production_technology_wizard.py +++ b/sf_manufacturing/wizard/production_technology_wizard.py @@ -116,3 +116,4 @@ class ProductionTechnologyWizard(models.TransientModel): if workorder[0].state in ['pending']: if workorder[0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程': workorder[0].state = 'waiting' + return productions diff --git a/sf_message/data/bussiness_node.xml b/sf_message/data/bussiness_node.xml index 925dc505..8864beda 100644 --- a/sf_message/data/bussiness_node.xml +++ b/sf_message/data/bussiness_node.xml @@ -120,5 +120,20 @@ 待排程 mrp.production + + + 委外加工采购单提醒 + purchase.order + + + + 外购订单采购单提醒 + purchase.order + + + + 工序外协采购单通知 + purchase.order + \ No newline at end of file diff --git a/sf_message/data/template_data.xml b/sf_message/data/template_data.xml index bcc12441..b7e19a7b 100644 --- a/sf_message/data/template_data.xml +++ b/sf_message/data/template_data.xml @@ -314,5 +314,41 @@ 事项:有{{production_num}}个制造订单待排程。 + + + 委外加工采购单提醒 + + purchase.order + + markdown + normal + ### 委外加工采购通知: +单号:委外加工采购单[{{name}}]({{request_url}}) +事项:请确认委外采购单并处理。 + + + + 外购订单采购单提醒 + + purchase.order + + markdown + normal + ### 外购订单采购通知: +单号:外购采购单[{{name}}]({{request_url}}) +事项:请确认外购采购单并处理。 + + + + 工序外协采购单通知 + + purchase.order + + markdown + normal + ### 工序外协采购单通知: +单号:工序外协采购单产品[{{name}}]({{url}}) +事项:有{{num}}个工序外协采购单需要确认。 + \ No newline at end of file diff --git a/sf_message/models/sf_message_mrp_production_wizard.py b/sf_message/models/sf_message_mrp_production_wizard.py index c98152d3..0defae7e 100644 --- a/sf_message/models/sf_message_mrp_production_wizard.py +++ b/sf_message/models/sf_message_mrp_production_wizard.py @@ -8,10 +8,16 @@ class SFMessageMrpProductionWizard(models.TransientModel): _inherit = ['sf.production.technology.wizard', 'jikimo.message.dispatch'] def confirm(self): - super(SFMessageMrpProductionWizard, self).confirm() + productions = super(SFMessageMrpProductionWizard, self).confirm() try: for production_info in self.production_id: if production_info.state == 'confirmed': production_info.add_queue('待排程') + for production_id in productions: + workorder_ids = production_id.workorder_ids.filtered( + lambda p: p.routing_type == '表面工艺' and p.state != 'cancel') + for workorder_id in workorder_ids: + purchase_orders_id = workorder_id._get_surface_technics_purchase_ids() + purchase_orders_id.add_queue('工序外协采购单通知') except Exception as e: logging.info('add_queue待排程 error:%s' % e) diff --git a/sf_message/models/sf_message_purchase.py b/sf_message/models/sf_message_purchase.py index e3fe269f..3f1c4709 100644 --- a/sf_message/models/sf_message_purchase.py +++ b/sf_message/models/sf_message_purchase.py @@ -8,14 +8,41 @@ class SFMessagePurchase(models.Model): def _get_message(self, message_queue_ids): contents = [] + process_outsourcing = set() for message_queue_id in message_queue_ids: - if message_queue_id.message_template_id.name == '坯料采购提醒': + if message_queue_id.message_template_id.name in ( + '坯料采购提醒', '委外加工采购单提醒', '外购订单采购单提醒'): content = message_queue_id.message_template_id.content url = self.request_url(int(message_queue_id.res_id)) purchase_order_line = self.env['purchase.order'].search([('id', '=', int(message_queue_id.res_id))]) content = content.replace('{{name}}', purchase_order_line.name).replace( '{{request_url}}', url) contents.append(content) + if message_queue_id.message_template_id.name == '工序外协采购单通知': + content = message_queue_id.message_template_id.content + purchase_order_line = self.env['purchase.order'].sudo().search( + [('id', '=', int(message_queue_id.res_id))]) + mrp_production = self.env['mrp.production'].sudo().search([('name', '=', purchase_order_line.origin)]) + process_outsourcing.add(mrp_production.product_id.id) + if process_outsourcing: + content_info = content + for products_id in process_outsourcing: + production_num = 0 + product_name = self.env['product.product'].sudo().search([('id', '=', products_id)]).name + production_list = self.env['mrp.production'].sudo().search( + [('product_id', '=', products_id), ('state', '=', 'confirmed')]) + for production_info in production_list: + workorder_ids = len(production_info.workorder_ids.filtered( + lambda p: p.routing_type == '表面工艺' and p.state != 'cancel')) + production_num += workorder_ids + if production_num >= 1: + url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + action_id = self.env.ref('purchase.purchase_form_action').id + url_with_id = f"{url}/web#view_type=list&action={action_id}" + new_content = (content_info.replace('{{name}}', product_name) + .replace('{{url}}', url_with_id) + .replace('{{num}}', str(production_num))) + contents.append(new_content) return contents def request_url(self, id): diff --git a/sf_message/models/sf_message_sale.py b/sf_message/models/sf_message_sale.py index a76468dd..4200ea72 100644 --- a/sf_message/models/sf_message_sale.py +++ b/sf_message/models/sf_message_sale.py @@ -28,6 +28,12 @@ class SFMessageSale(models.Model): [('id', 'in', purchase_order_id)]) for purchase_order_info in purchase_order_list: purchase_order_info.add_queue('坯料采购提醒') + purchase_order_ids = self.order_line.purchase_line_ids.order_id | self.procurement_group_id.stock_move_ids.created_purchase_line_id.order_id | self.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id + for purchase_order_id in purchase_order_ids: + if purchase_order_id.purchase_type == 'consignment': + purchase_order_id.add_queue('委外加工采购单提醒') + if purchase_order_id.purchase_type == 'standard': + purchase_order_id.add_queue('外购订单采购单提醒') except Exception as e: logging.info('add_queue error:%s' % e) logging.info('action_confirm res:%s' % res) From 5eda4427df26745432ea096471561dca7de2f2cb Mon Sep 17 00:00:00 2001 From: guanhuan Date: Thu, 19 Dec 2024 13:09:20 +0800 Subject: [PATCH 05/44] =?UTF-8?q?=E6=B6=88=E6=81=AF=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 | 5 +++++ sf_message/data/template_data.xml | 16 ++++++++++++++-- sf_message/models/sf_message_mrp_production.py | 18 +++++++++++++++++- sf_message/models/sf_message_stock_picking.py | 12 +++++++++++- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/sf_message/data/bussiness_node.xml b/sf_message/data/bussiness_node.xml index 8864beda..b273fab1 100644 --- a/sf_message/data/bussiness_node.xml +++ b/sf_message/data/bussiness_node.xml @@ -135,5 +135,10 @@ 工序外协采购单通知 purchase.order + + + 工序外协发料通知 + mrp.production + \ No newline at end of file diff --git a/sf_message/data/template_data.xml b/sf_message/data/template_data.xml index b7e19a7b..e9aee4bb 100644 --- a/sf_message/data/template_data.xml +++ b/sf_message/data/template_data.xml @@ -347,8 +347,20 @@ markdown normal ### 工序外协采购单通知: -单号:工序外协采购单产品[{{name}}]({{url}}) -事项:有{{num}}个工序外协采购单需要确认。 +单号:工序外协采购,产品[{{name}}]({{url}}) +事项:请确认{{num}}个工序外协采购单并处理。 + + + + 工序外协发料通知 + + mrp.production + + markdown + normal + ### 工序外协发料提醒: +单号:产品[{{name}}]({{url}})发料单 +事项:请确认{{num}}个工序外协发料单并发料处理。 \ No newline at end of file diff --git a/sf_message/models/sf_message_mrp_production.py b/sf_message/models/sf_message_mrp_production.py index 00748511..37509e52 100644 --- a/sf_message/models/sf_message_mrp_production.py +++ b/sf_message/models/sf_message_mrp_production.py @@ -50,6 +50,22 @@ class SFMessageMrpProduction(models.Model): content = message_queue_id.message_template_id.content mrp_production = self.env['mrp.production'].sudo().search([('id', '=', int(message_queue_id.res_id))]) unique_products.add(mrp_production.product_id.id) + if message_queue_id.message_template_id.name == '工序外协发料通知': + content = message_queue_id.message_template_id.content + mrp_production = self.env['mrp.production'].sudo().search([('id', '=', int(message_queue_id.res_id))]) + mrp_production_list = self.env['mrp.production'].sudo().search( + [('product_id', '=', mrp_production.product_id.id)]) + mrp_production_names = mrp_production_list.mapped('name') + stock_picking_num = self.env['stock.picking'].sudo().search_count( + [('origin', 'in', mrp_production_names), ('state', '=', 'assigned')]) + if stock_picking_num >= 1: + url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + action_id = self.env.ref('stock.action_picking_tree_ready').id + url_with_id = f"{url}/web#view_type=list&action={action_id}" + content = content.replace('{{name}}', mrp_production.product_id.name).replace('{{url}}', + url_with_id).replace( + '{{num}}', str(stock_picking_num)) + contents.append(content) if unique_products: unique_products_contents = self.get_production_info(content, unique_products, 'confirmed', 'sf_plan.sf_production_plan_action1') @@ -83,7 +99,7 @@ class SFMessageMrpProduction(models.Model): action_id = self.env.ref('stock.action_picking_tree_all').id menu_id = self.env['ir.model.data'].search([('name', '=', 'module_theme_treehouse')]).id # 查询参数 - params = {'id': id, 'menu_id': menu_id, 'action': action_id, 'model': 'mrp.production', + params = {'id': id, 'menu_id': menu_id, 'action': action_id, 'model': 'mrp.production', 'view_type': 'form'} # 拼接查询参数 query_string = urlencode(params) diff --git a/sf_message/models/sf_message_stock_picking.py b/sf_message/models/sf_message_stock_picking.py index 38a6fc16..4637941b 100644 --- a/sf_message/models/sf_message_stock_picking.py +++ b/sf_message/models/sf_message_stock_picking.py @@ -21,7 +21,7 @@ class SFMessageStockPicking(models.Model): def _compute_state(self): super(SFMessageStockPicking, self)._compute_state() for record in self: - if record.state == 'assigned' and record.check_in == 'PC': + if record.state == 'assigned' and record.picking_type_id.sequence_code == 'PC': record.add_queue('坯料发料提醒') if record.picking_type_id.sequence_code == 'SFP' and record.state == 'done': @@ -32,6 +32,16 @@ class SFMessageStockPicking(models.Model): stock_picking_send = self.env["jikimo.message.queue"].sudo().search([('res_id', '=', record.id)]) if not stock_picking_send: record.add_queue('订单发货提醒') + if record.picking_type_id.sequence_code == 'OCOUT' and record.state == 'assigned': + mrp_production = self.env['mrp.production'].sudo().search([('name', '=', record.origin)]) + production_list = self.env['mrp.production'].sudo().search( + [('product_id', '=', mrp_production.product_id.id)]) + manufacturing_order_names = production_list.mapped('name') + stock_picking_list = self.env['stock.picking'].sudo().search( + [('origin', 'in', manufacturing_order_names), ('picking_type_id.sequence_code', '=', 'OCOUT')]) + all_ready_or_done = all(picking.state in ['assigned', 'done'] for picking in stock_picking_list) + if all_ready_or_done: + mrp_production.add_queue('工序外协发料通知') def deal_stock_picking_sfp(self, message_queue_id): # 处理订单发货提醒 content = None From 72bf8ad01191f89e7adc2eda1f005c9910b7557b Mon Sep 17 00:00:00 2001 From: guanhuan Date: Thu, 19 Dec 2024 14:36:16 +0800 Subject: [PATCH 06/44] =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_message/controllers/main.py | 13 ++++- sf_message/data/bussiness_node.xml | 2 +- sf_message/data/template_data.xml | 4 +- .../models/sf_message_mrp_production.py | 46 +++++++++++++--- sf_message/models/sf_message_stock_picking.py | 55 +++++++++++-------- sf_message/models/sf_message_template.py | 1 + sf_message/models/sf_message_workorder.py | 40 +------------- 7 files changed, 84 insertions(+), 77 deletions(-) diff --git a/sf_message/controllers/main.py b/sf_message/controllers/main.py index 9537417e..5b94f50a 100644 --- a/sf_message/controllers/main.py +++ b/sf_message/controllers/main.py @@ -9,6 +9,7 @@ from odoo.addons.sf_base.commons.common import Common _logger = logging.getLogger(__name__) + class MessageSfMrsConnect(Sf_Mrs_Connect): @http.route('/api/cnc_processing/create', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, @@ -38,9 +39,16 @@ class MessageSfMrsConnect(Sf_Mrs_Connect): _logger.info('无效用刀异常消息推送接口:%s' % ret) except Exception as e: _logger.info('无效用刀异常消息推送接口:%s' % e) + + try: + productions = request.env['mrp.production'].sudo().search([('id', '=', res.get('production_ids')[0])]) + productions.add_queue('工单已下发通知') + except Exception as e: + _logger.info('工单已下发通知异常:%s' % e) return json.JSONEncoder().encode(res) - @http.route('/api/maintenance_logs/notify', type='json', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") + @http.route('/api/maintenance_logs/notify', type='json', auth='public', methods=['GET', 'POST'], csrf=False, + cors="*") def maintenance_logs_notify(self, **kw): res = {'code': 200, 'message': '设备故障日志信息推送成功'} datas = request.httprequest.data @@ -52,7 +60,8 @@ class MessageSfMrsConnect(Sf_Mrs_Connect): try: if not isinstance(log_id, list): log_id = [log_id] - maintenance_logs = request.env['sf.maintenance.logs'].sudo().search([('id', 'in', [int(id) for id in log_id])]) + maintenance_logs = request.env['sf.maintenance.logs'].sudo().search( + [('id', 'in', [int(id) for id in log_id])]) if maintenance_logs: maintenance_logs.add_queue('设备故障') except Exception as e: diff --git a/sf_message/data/bussiness_node.xml b/sf_message/data/bussiness_node.xml index b273fab1..cff79873 100644 --- a/sf_message/data/bussiness_node.xml +++ b/sf_message/data/bussiness_node.xml @@ -56,7 +56,7 @@ 工单已下发通知 - mrp.workorder + mrp.production diff --git a/sf_message/data/template_data.xml b/sf_message/data/template_data.xml index e9aee4bb..42256ce6 100644 --- a/sf_message/data/template_data.xml +++ b/sf_message/data/template_data.xml @@ -78,8 +78,8 @@ 工单已下发通知 - - mrp.workorder + + mrp.production markdown normal diff --git a/sf_message/models/sf_message_mrp_production.py b/sf_message/models/sf_message_mrp_production.py index 37509e52..94c8297e 100644 --- a/sf_message/models/sf_message_mrp_production.py +++ b/sf_message/models/sf_message_mrp_production.py @@ -14,15 +14,18 @@ class SFMessageMrpProduction(models.Model): 'workorder_ids.state', 'product_qty', 'qty_producing') def _compute_state(self): super(SFMessageMrpProduction, self)._compute_state() - for record in self: - if record.state in ['scrap', 'done']: - # 查询制造订单下的所有未完成的生产订单 - mrp_production = record.env['mrp.production'].search( - [('origin', '=', record.origin), ('state', 'not in', ['scrap', 'done'])]) - if not mrp_production: - mrp_production_queue = self.env["jikimo.message.queue"].search([('res_id', '=', record.id)]) - if not mrp_production_queue: - record.add_queue('生产完工入库提醒') + try: + for record in self: + if record.state in ['scrap', 'done']: + # 查询制造订单下的所有未完成的生产订单 + mrp_production = record.env['mrp.production'].search( + [('origin', '=', record.origin), ('state', 'not in', ['scrap', 'done'])]) + if not mrp_production: + mrp_production_queue = self.env["jikimo.message.queue"].search([('res_id', '=', record.id)]) + if not mrp_production_queue: + record.add_queue('生产完工入库提醒') + except Exception as e: + logging.info('add_queue生产完工入库提醒 error:%s' % e) # 获取发送消息内容 def _get_message(self, message_queue_ids): @@ -66,6 +69,17 @@ class SFMessageMrpProduction(models.Model): url_with_id).replace( '{{num}}', str(stock_picking_num)) contents.append(content) + if message_queue_id.message_template_id.name == '工单已下发通知': + content = message_queue_id.message_template_id.content + mrp_production = self.env['mrp.production'].sudo().search([('id', '=', int(message_queue_id.res_id))]) + production_num = self.env['mrp.production'].sudo().search_count( + [('product_id', '=', mrp_production.product_id.id)]) + if production_num >= 1: + url = self.get_request_url() + content = content.replace('{{product_id}}', mrp_production.product_id.name).replace( + '{{number}}', str(production_num)).replace( + '{{request_url}}', url) + contents.append(content) if unique_products: unique_products_contents = self.get_production_info(content, unique_products, 'confirmed', 'sf_plan.sf_production_plan_action1') @@ -106,3 +120,17 @@ class SFMessageMrpProduction(models.Model): # 拼接URL full_url = url + "/web#" + query_string return full_url + + def get_request_url(self): + url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + action_id = self.env.ref('sf_message.mrp_workorder_issued_action').id + menu_id = self.env['ir.model.data'].sudo().search([('name', '=', 'module_stock_dropshipping')]).id + active_id = self.env['mrp.workcenter'].sudo().search([('name', '=', '工件装夹中心')]).id + # 查询参数 + params = {'menu_id': menu_id, 'action': action_id, 'model': 'mrp.workorder', + 'view_type': 'list', 'active_id': active_id} + # 拼接查询参数 + query_string = urlencode(params) + # 拼接URL + full_url = url + "/web#" + query_string + return full_url diff --git a/sf_message/models/sf_message_stock_picking.py b/sf_message/models/sf_message_stock_picking.py index 4637941b..b3e1868e 100644 --- a/sf_message/models/sf_message_stock_picking.py +++ b/sf_message/models/sf_message_stock_picking.py @@ -12,36 +12,43 @@ class SFMessageStockPicking(models.Model): @api.model_create_multi def create(self, vals): result = super(SFMessageStockPicking, self).create(vals) - for obj in result: - if obj.location_id.name == '进货' and obj.location_dest_id.name == '刀具房': - obj.add_queue('调拨入库') + try: + for obj in result: + if obj.location_id.name == '进货' and obj.location_dest_id.name == '刀具房': + obj.add_queue('调拨入库') + except Exception as e: + logging.info('add_queue调拨入库 error:%s' % e) return result @api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id') def _compute_state(self): super(SFMessageStockPicking, self)._compute_state() - for record in self: - if record.state == 'assigned' and record.picking_type_id.sequence_code == 'PC': - record.add_queue('坯料发料提醒') + try: + for record in self: + if record.state == 'assigned' and record.picking_type_id.sequence_code == 'PC': + record.add_queue('坯料发料提醒') - if record.picking_type_id.sequence_code == 'SFP' and record.state == 'done': - stock_picking_sfp = record.env['stock.picking'].search( - [('origin', '=', record.origin), ('state', '!=', 'done'), - ('picking_type_id.sequence_code', '=', 'SFP')]) - if not stock_picking_sfp: - stock_picking_send = self.env["jikimo.message.queue"].sudo().search([('res_id', '=', record.id)]) - if not stock_picking_send: - record.add_queue('订单发货提醒') - if record.picking_type_id.sequence_code == 'OCOUT' and record.state == 'assigned': - mrp_production = self.env['mrp.production'].sudo().search([('name', '=', record.origin)]) - production_list = self.env['mrp.production'].sudo().search( - [('product_id', '=', mrp_production.product_id.id)]) - manufacturing_order_names = production_list.mapped('name') - stock_picking_list = self.env['stock.picking'].sudo().search( - [('origin', 'in', manufacturing_order_names), ('picking_type_id.sequence_code', '=', 'OCOUT')]) - all_ready_or_done = all(picking.state in ['assigned', 'done'] for picking in stock_picking_list) - if all_ready_or_done: - mrp_production.add_queue('工序外协发料通知') + if record.picking_type_id.sequence_code == 'SFP' and record.state == 'done': + stock_picking_sfp = record.env['stock.picking'].search( + [('origin', '=', record.origin), ('state', '!=', 'done'), + ('picking_type_id.sequence_code', '=', 'SFP')]) + if not stock_picking_sfp: + stock_picking_send = self.env["jikimo.message.queue"].sudo().search( + [('res_id', '=', record.id)]) + if not stock_picking_send: + record.add_queue('订单发货提醒') + if record.picking_type_id.sequence_code == 'OCOUT' and record.state == 'assigned': + mrp_production = self.env['mrp.production'].sudo().search([('name', '=', record.origin)]) + production_list = self.env['mrp.production'].sudo().search( + [('product_id', '=', mrp_production.product_id.id)]) + manufacturing_order_names = production_list.mapped('name') + stock_picking_list = self.env['stock.picking'].sudo().search( + [('origin', 'in', manufacturing_order_names), ('picking_type_id.sequence_code', '=', 'OCOUT')]) + all_ready_or_done = all(picking.state in ['assigned', 'done'] for picking in stock_picking_list) + if all_ready_or_done: + mrp_production.add_queue('工序外协发料通知') + except Exception as e: + logging.info('add_queue_compute_state error:%s' % e) def deal_stock_picking_sfp(self, message_queue_id): # 处理订单发货提醒 content = None diff --git a/sf_message/models/sf_message_template.py b/sf_message/models/sf_message_template.py index 8d1a2b9d..87328849 100644 --- a/sf_message/models/sf_message_template.py +++ b/sf_message/models/sf_message_template.py @@ -16,4 +16,5 @@ class SfMessageTemplate(models.Model): res.append('mrp.workorder') res.append('sf.maintenance.logs') res.append('quality.cnc.test') + res.append('mrp.production') return res diff --git a/sf_message/models/sf_message_workorder.py b/sf_message/models/sf_message_workorder.py index d5186797..c604534d 100644 --- a/sf_message/models/sf_message_workorder.py +++ b/sf_message/models/sf_message_workorder.py @@ -12,19 +12,8 @@ class SFMessageWork(models.Model): _name = 'mrp.workorder' _inherit = ['mrp.workorder', 'jikimo.message.dispatch'] - @api.depends('production_availability', 'blocked_by_workorder_ids.state', 'production_id.tool_state') - def _compute_state(self): - super(SFMessageWork, self)._compute_state() - for workorder in self: - if workorder.state == 'ready' and workorder.routing_type == '装夹预调': - jikimo_message_queue = self.env['jikimo.message.queue'].sudo().search( - [('res_id', '=', workorder.id), ("message_status", "=", "pending")]) - if not jikimo_message_queue: - workorder.add_queue('工单已下发通知') - def _get_message(self, message_queue_ids): contents = [] - product_id = [] bussiness_node = None url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') current_time_strf = datetime.now().strftime("%Y-%m-%d %H:%M:%S") @@ -37,20 +26,7 @@ class SFMessageWork(models.Model): } i = 0 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'].sudo().search([('id', '=', int(message_queue_id.res_id))]) - mrp_workorder_list = self.env['mrp.workorder'].sudo().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: - url = self.request_url() - content = content.replace('{{product_id}}', mrp_workorder_line.product_id.name).replace( - '{{number}}', str(len(mrp_workorder_list))).replace( - '{{request_url}}', url) - product_id.append(mrp_workorder_line.product_id.id) - contents.append(content) - elif message_queue_id.message_template_id.name in template_names['预警'] + template_names['已逾期']: + if message_queue_id.message_template_id.name in template_names['预警'] + template_names['已逾期']: item = message_queue_id.message_template_id bussiness_node = item.bussiness_node_id.name for reminder_time in item.reminder_time_ids: @@ -95,20 +71,6 @@ class SFMessageWork(models.Model): contents.append(content) return contents - def request_url(self): - url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') - action_id = self.env.ref('sf_message.mrp_workorder_issued_action').id - menu_id = self.env['ir.model.data'].sudo().search([('name', '=', 'module_stock_dropshipping')]).id - active_id = self.env['mrp.workcenter'].sudo().search([('name', '=', '工件装夹中心')]).id - # 查询参数 - params = {'menu_id': menu_id, 'action': action_id, 'model': 'mrp.workorder', - 'view_type': 'list', 'active_id': active_id} - # 拼接查询参数 - query_string = urlencode(params) - # 拼接URL - full_url = url + "/web#" + query_string - return full_url - def _overdue_or_warning_func(self): workorders = self.env['mrp.workorder'].search( [("state", "in", ["ready", "progress", "to be detected"]), ('schedule_state', '=', '已排')]) From 9d883d112cb008c2614bce66b3cc7411ebd30e03 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Fri, 20 Dec 2024 13:51:11 +0800 Subject: [PATCH 07/44] =?UTF-8?q?=E6=B6=88=E6=81=AF=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 | 10 +++++++ sf_message/data/template_data.xml | 27 +++++++++++++++++ sf_message/models/sf_message_purchase.py | 37 ++++++++++++++++++++++++ sf_sale/__manifest__.py | 1 + sf_sale/data/cron_data.xml | 16 ++++++++++ sf_sale/models/sale_order.py | 27 +++++++++++++++++ 6 files changed, 118 insertions(+) create mode 100644 sf_sale/data/cron_data.xml diff --git a/sf_message/data/bussiness_node.xml b/sf_message/data/bussiness_node.xml index cff79873..8a95f525 100644 --- a/sf_message/data/bussiness_node.xml +++ b/sf_message/data/bussiness_node.xml @@ -140,5 +140,15 @@ 工序外协发料通知 mrp.production + + + 采购订单预警提醒 + purchase.order + + + + 采购单已逾期提醒 + purchase.order + \ No newline at end of file diff --git a/sf_message/data/template_data.xml b/sf_message/data/template_data.xml index 42256ce6..e1ba0a93 100644 --- a/sf_message/data/template_data.xml +++ b/sf_message/data/template_data.xml @@ -362,5 +362,32 @@ 单号:产品[{{name}}]({{url}})发料单 事项:请确认{{num}}个工序外协发料单并发料处理。 + + + + 采购订单预警提醒 + + purchase.order + + markdown + timing + normal + ### 采购订单预警提醒 +事项:[共有{{num}}个采购订单有逾期风险]({{url}}) + + + + + 采购单已逾期提醒 + + purchase.order + + markdown + timing + normal + ### 采购单已逾期提醒 +事项:[共有{{num}}个采购订单已逾期]({{url}}) + + \ No newline at end of file diff --git a/sf_message/models/sf_message_purchase.py b/sf_message/models/sf_message_purchase.py index 3f1c4709..b9505414 100644 --- a/sf_message/models/sf_message_purchase.py +++ b/sf_message/models/sf_message_purchase.py @@ -24,6 +24,19 @@ class SFMessagePurchase(models.Model): [('id', '=', int(message_queue_id.res_id))]) mrp_production = self.env['mrp.production'].sudo().search([('name', '=', purchase_order_line.origin)]) process_outsourcing.add(mrp_production.product_id.id) + if message_queue_id.message_template_id.name in ('采购订单预警提醒', '采购单已逾期提醒'): + content = message_queue_id.message_template_id.content + if message_queue_id.message_template_id.name == '采购订单预警提醒': + domain = [('delivery_warning', '=', 'warning')] + else: + domain = [('delivery_warning', '=', 'overdue')] + purchase_order_num = self.env['purchase.order'].sudo().search_count(domain) + if purchase_order_num >= 1: + url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + action_id = self.env.ref("purchase.purchase_form_action").id + url_with_id = f"{url}/web#view_type=list&action={action_id}" + content = content.replace('{{url}}', url_with_id).replace('{{num}}', str(purchase_order_num)) + contents.append(content) if process_outsourcing: content_info = content for products_id in process_outsourcing: @@ -58,3 +71,27 @@ class SFMessagePurchase(models.Model): # 拼接URL full_url = url + "/web#" + query_string return full_url + + def _overdue_or_warning_func(self): + last_overdue_order, last_warning_order = super(SFMessagePurchase, self)._overdue_or_warning_func() + if last_overdue_order: + business_node_id = self.env.ref('sf_message.template_purchase_order_overdue').id + purchase_order_has = self._get_message_queue(business_node_id) + if not purchase_order_has: + last_overdue_order.add_queue("采购单已逾期提醒") + if last_warning_order: + business_node_id = self.env.ref('sf_message.template_purchase_order_warning').id + purchase_order_has = self._get_message_queue(business_node_id) + if not purchase_order_has: + last_warning_order.add_queue("采购订单预警提醒") + + def _get_message_queue(self, business_node_id): + message_template = self.env["jikimo.message.template"].sudo().search([ + ("model", "=", self._name), + ("bussiness_node_id", "=", business_node_id) + ], limit=1) + purchase_order_has = self.env['jikimo.message.queue'].sudo().search([ + ('message_status', '=', 'pending'), + ('message_template_id', '=', message_template.id) + ]) + return purchase_order_has diff --git a/sf_sale/__manifest__.py b/sf_sale/__manifest__.py index 45c95030..12d50f5f 100644 --- a/sf_sale/__manifest__.py +++ b/sf_sale/__manifest__.py @@ -16,6 +16,7 @@ 'security/ir.model.access.csv', 'wizard/sale_order_wizard_views.xml', 'wizard/purchase_order_wizard_views.xml', + 'data/cron_data.xml', 'views/sale_team.xml', 'views/sale_order_view.xml', 'views/res_partner_view.xml', diff --git a/sf_sale/data/cron_data.xml b/sf_sale/data/cron_data.xml new file mode 100644 index 00000000..3a1d2ea7 --- /dev/null +++ b/sf_sale/data/cron_data.xml @@ -0,0 +1,16 @@ + + + + 检查采购单是否已逾期预警和逾期 + + code + model._overdue_or_warning_func() + 10 + minutes + -1 + + + + + + \ No newline at end of file diff --git a/sf_sale/models/sale_order.py b/sf_sale/models/sale_order.py index ca851fc6..492c0316 100644 --- a/sf_sale/models/sale_order.py +++ b/sf_sale/models/sale_order.py @@ -1,8 +1,10 @@ import datetime import base64 +import logging from odoo import Command from odoo import models, fields, api, _ from odoo.exceptions import UserError, ValidationError +from datetime import datetime, timedelta READONLY_FIELD_STATES = { state: [('readonly', True)] @@ -218,6 +220,10 @@ class RePurchaseOrder(models.Model): purchase_type = fields.Selection([('standard', '标准采购'), ('consignment', '委外加工')], string='采购类型', default='standard') + delivery_warning = fields.Selection([('normal', '正常'), ('warning', '预警'), ('overdue', '已逾期')], + string='交期状态', + tracking=True) + @api.depends('partner_id') def _compute_user_id(self): if not self.user_id: @@ -299,6 +305,27 @@ class RePurchaseOrder(models.Model): return result + # # 采购订单逾期预警和已逾期 + def _overdue_or_warning_func(self): + purchase_order = self.sudo().search( + [('state', 'in', ['purchase']), ('date_planned', '!=', False), + ('receipt_status', 'in', ('partial', 'pending'))]) + last_overdue_order = None + last_warning_order = None + for item in purchase_order: + current_time = datetime.now() + if item.date_planned <= current_time: # 已逾期 + item.delivery_warning = 'overdue' + last_overdue_order = item + elif (item.date_planned - current_time).total_seconds() < 48 * 3600: # 预警 + item.delivery_warning = 'warning' + last_warning_order = item + purchase_order_done = self.sudo().search([('state', 'in', ['purchase']), ('receipt_status', '=', 'full')]) + purchase_order_overdue = purchase_order_done.filtered(lambda x: x.delivery_warning in ['overdue', 'warning']) + if purchase_order_overdue: + purchase_order_overdue.write({'delivery_warning': 'normal'}) + return last_overdue_order, last_warning_order + class ResPartnerToSale(models.Model): _inherit = 'res.partner' From bf227e3e92dee81b00f2cc57719f9a410b797b66 Mon Sep 17 00:00:00 2001 From: guanhuan Date: Fri, 20 Dec 2024 14:33:23 +0800 Subject: [PATCH 08/44] =?UTF-8?q?=E4=BA=A4=E6=9C=9F=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_sale/views/purchase_order_view.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sf_sale/views/purchase_order_view.xml b/sf_sale/views/purchase_order_view.xml index 23c71a1f..0c02e41d 100644 --- a/sf_sale/views/purchase_order_view.xml +++ b/sf_sale/views/purchase_order_view.xml @@ -200,7 +200,27 @@ date_approve asc + delivery_warning == 'warning' + delivery_warning == 'overdue' + + + + + + + + purchase.order.search.inherit.sf + purchase.order + + + + + + + + From 41096c9c6503a1ecd5a47c5623dada8ea07f02b1 Mon Sep 17 00:00:00 2001 From: liaodanlong Date: Fri, 20 Dec 2024 14:55:04 +0800 Subject: [PATCH 09/44] =?UTF-8?q?=E9=9B=B6=E4=BB=B6=E5=9B=BE=E5=8F=B7?= =?UTF-8?q?=E9=9B=B6=E4=BB=B6=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/__manifest__.py | 1 + sf_manufacturing/models/__init__.py | 1 + sf_manufacturing/models/product_template.py | 5 ++-- sf_manufacturing/models/purchase_order.py | 7 +++++ sf_manufacturing/models/sale_order.py | 2 +- .../views/mrp_production_addional_change.xml | 3 ++ sf_manufacturing/views/mrp_workorder_view.xml | 2 ++ .../views/purchase_order_view.xml | 15 ++++++++++ sf_manufacturing/views/sale_order_views.xml | 4 +++ sf_plan/models/custom_plan.py | 3 +- sf_plan/views/view.xml | 2 ++ sf_quality/views/quality_cnc_test_view.xml | 3 +- sf_sale/models/sale_order.py | 5 ++-- sf_sale/views/purchase_order_view.xml | 28 ++++++++++--------- sf_sale/views/sale_order_view.xml | 1 + 15 files changed, 61 insertions(+), 21 deletions(-) create mode 100644 sf_manufacturing/models/purchase_order.py create mode 100644 sf_manufacturing/views/purchase_order_view.xml diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index 904aac56..936afaaf 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -40,6 +40,7 @@ 'views/res_config_settings_views.xml', 'views/sale_order_views.xml', 'views/mrp_workorder_batch_replan.xml', + 'views/purchase_order_view.xml', ], 'assets': { diff --git a/sf_manufacturing/models/__init__.py b/sf_manufacturing/models/__init__.py index 9f77d841..c4d8ad94 100644 --- a/sf_manufacturing/models/__init__.py +++ b/sf_manufacturing/models/__init__.py @@ -15,3 +15,4 @@ from . import sf_technology_design from . import sf_production_common from . import sale_order from . import quick_easy_order +from . import purchase_order \ No newline at end of file diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py index 460fd994..4b927596 100644 --- a/sf_manufacturing/models/product_template.py +++ b/sf_manufacturing/models/product_template.py @@ -774,11 +774,10 @@ class ResProductMo(models.Model): # bfm下单 manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) - part_number = fields.Char(string='零件图号', readonly=True) machining_drawings = fields.Binary('2D加工图纸', readonly=True) quality_standard = fields.Binary('质检标准', readonly=True) part_name = fields.Char(string='零件名称', readonly=True) - + part_number = fields.Char(string='零件图号', readonly=True) @api.constrains('tool_length') def _check_tool_length_size(self): if self.tool_length > 1000000: @@ -892,7 +891,7 @@ class ResProductMo(models.Model): 'machining_drawings': '' if not item['machining_drawings'] else base64.b64decode( item['machining_drawings']), 'quality_standard': '' if not item['quality_standard'] else base64.b64decode(item['quality_standard']), - 'part_name': item['part_name'], + 'part_name': item.get('part_name') or '', } tax_id = self.env['account.tax'].sudo().search( [('type_tax_use', '=', 'sale'), ('amount', '=', item.get('tax')), ('price_include', '=', 'True')]) diff --git a/sf_manufacturing/models/purchase_order.py b/sf_manufacturing/models/purchase_order.py new file mode 100644 index 00000000..52095fc7 --- /dev/null +++ b/sf_manufacturing/models/purchase_order.py @@ -0,0 +1,7 @@ +import logging +from odoo import models, fields, api + +_logger = logging.getLogger(__name__) +class PurchaseOrderLine(models.Model): + _inherit = 'purchase.order.line' + part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True) diff --git a/sf_manufacturing/models/sale_order.py b/sf_manufacturing/models/sale_order.py index 5d318141..e31faf1c 100644 --- a/sf_manufacturing/models/sale_order.py +++ b/sf_manufacturing/models/sale_order.py @@ -152,7 +152,7 @@ class SaleOrder(models.Model): class SaleOrderLine(models.Model): _inherit = 'sale.order.line' - + part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True) # 供货方式 supply_method = fields.Selection([ ('automation', "自动化产线加工"), diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml index d08ff81f..c9856cb8 100644 --- a/sf_manufacturing/views/mrp_production_addional_change.xml +++ b/sf_manufacturing/views/mrp_production_addional_change.xml @@ -18,9 +18,12 @@ + + + + + diff --git a/sf_manufacturing/views/purchase_order_view.xml b/sf_manufacturing/views/purchase_order_view.xml new file mode 100644 index 00000000..5fbd7bd1 --- /dev/null +++ b/sf_manufacturing/views/purchase_order_view.xml @@ -0,0 +1,15 @@ + + + + + purchase.order.form.inherit.sf + purchase.order + + + + + + + + + \ No newline at end of file diff --git a/sf_manufacturing/views/sale_order_views.xml b/sf_manufacturing/views/sale_order_views.xml index 49cc752f..8e1d1061 100644 --- a/sf_manufacturing/views/sale_order_views.xml +++ b/sf_manufacturing/views/sale_order_views.xml @@ -18,6 +18,10 @@ + + + + {'invisible': [('state', '!=', 'draft')]} diff --git a/sf_plan/models/custom_plan.py b/sf_plan/models/custom_plan.py index 6ee1d3ee..5f4003da 100644 --- a/sf_plan/models/custom_plan.py +++ b/sf_plan/models/custom_plan.py @@ -13,7 +13,8 @@ class sf_production_plan(models.Model): _description = 'sf_production_plan' _inherit = ['mail.thread'] # _order = 'state desc, write_date desc' - + part_name = fields.Char('零件名称', related='product_id.part_name', readonly=True) + part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True) state = fields.Selection([ ('draft', '待排程'), ('done', '已排程'), diff --git a/sf_plan/views/view.xml b/sf_plan/views/view.xml index 47e1dd54..09bd790c 100644 --- a/sf_plan/views/view.xml +++ b/sf_plan/views/view.xml @@ -17,6 +17,8 @@ decoration-danger="state == 'finished'"/> + + diff --git a/sf_quality/views/quality_cnc_test_view.xml b/sf_quality/views/quality_cnc_test_view.xml index 29cab866..d2d37686 100644 --- a/sf_quality/views/quality_cnc_test_view.xml +++ b/sf_quality/views/quality_cnc_test_view.xml @@ -18,7 +18,8 @@ - + +