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/__manifest__.py b/sf_message/__manifest__.py index 8178973b..fcfcba8f 100644 --- a/sf_message/__manifest__.py +++ b/sf_message/__manifest__.py @@ -11,13 +11,15 @@ """, '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', 'data/template_data.xml', 'security/ir.model.access.csv', 'views/mrp_workorder_views.xml', + 'views/purchase_order_view.xml', ], 'test': [ ], diff --git a/sf_message/controllers/main.py b/sf_message/controllers/main.py index 11e776dc..5b94f50a 100644 --- a/sf_message/controllers/main.py +++ b/sf_message/controllers/main.py @@ -4,10 +4,12 @@ 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__) + class MessageSfMrsConnect(Sf_Mrs_Connect): @http.route('/api/cnc_processing/create', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, @@ -37,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 @@ -51,10 +60,26 @@ 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: 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..8a95f525 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 + 调拨入库 @@ -47,7 +56,7 @@ 工单已下发通知 - mrp.workorder + mrp.production @@ -106,5 +115,40 @@ 设备故障 sf.maintenance.logs + + + 待排程 + mrp.production + + + + 委外加工采购单提醒 + purchase.order + + + + 外购订单采购单提醒 + purchase.order + + + + 工序外协采购单通知 + purchase.order + + + + 工序外协发料通知 + 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 beb37771..e1ba0a93 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}}) 事项:请确认是否接单。 @@ -72,14 +72,14 @@ markdown normal ### 坯料发料提醒: -单号:产品[{{product_id}}]({{request_url}}) -事项:共{{number}}个生产发料单待确认处理 +单号:发料单[{{name}}]({{request_url}}) +事项:请确认坯料发料单并处理 工单已下发通知 - - mrp.workorder + + mrp.production markdown normal @@ -275,5 +275,119 @@ 机台号:[{{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}}个制造订单待排程。 + + + + + 委外加工采购单提醒 + + purchase.order + + markdown + normal + ### 委外加工采购通知: +单号:委外加工采购单[{{name}}]({{request_url}}) +事项:请确认委外采购单并处理。 + + + + 外购订单采购单提醒 + + purchase.order + + markdown + normal + ### 外购订单采购通知: +单号:外购采购单[{{name}}]({{request_url}}) +事项:请确认外购采购单并处理。 + + + + 工序外协采购单通知 + + purchase.order + + markdown + normal + ### 工序外协采购单通知: +单号:工序外协采购,产品[{{name}}]({{url}}) +事项:请确认{{num}}个工序外协采购单并处理。 + + + + 工序外协发料通知 + + mrp.production + + markdown + normal + ### 工序外协发料提醒: +单号:产品[{{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/__init__.py b/sf_message/models/__init__.py index 0b9c9ad6..1e659c52 100644 --- a/sf_message/models/__init__.py +++ b/sf_message/models/__init__.py @@ -10,3 +10,5 @@ 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 +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 a60f2161..d9dd0f1b 100644 --- a/sf_message/models/sf_message_mrp_production.py +++ b/sf_message/models/sf_message_mrp_production.py @@ -14,19 +14,24 @@ 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): 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 @@ -40,18 +45,92 @@ 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))]) + 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 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 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') + 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 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) # 拼接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.ref('mrp.menu_mrp_root').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_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_mrp_production_wizard.py b/sf_message/models/sf_message_mrp_production_wizard.py new file mode 100644 index 00000000..0defae7e --- /dev/null +++ b/sf_message/models/sf_message_mrp_production_wizard.py @@ -0,0 +1,23 @@ +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): + 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..7375eba6 100644 --- a/sf_message/models/sf_message_purchase.py +++ b/sf_message/models/sf_message_purchase.py @@ -8,20 +8,62 @@ 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 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')] + action_id = self.env.ref("sf_message.purchase_form_warning_action").id + else: + domain = [('delivery_warning', '=', 'overdue')] + action_id = self.env.ref("sf_message.purchase_form_overdue_action").id + 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') + menu_id = self.env.ref('purchase.menu_purchase_form_action').id + url_with_id = f"{url}/web#view_type=list&action={action_id}&menu_id={menu_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: + 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): url = self.env['ir.config_parameter'].get_param('web.base.url') action_id = self.env.ref('purchase.purchase_form_action').id - menu_id = self.env['ir.model.data'].search([('name', '=', 'module_website_payment')]).id + menu_id = self.env.ref('purchase.menu_purchase_form_action').id # 查询参数 params = {'id': id, 'menu_id': menu_id, 'action': action_id, 'model': 'purchase.order', @@ -31,3 +73,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_message/models/sf_message_sale.py b/sf_message/models/sf_message_sale.py index 58d1a021..4200ea72 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() @@ -29,19 +18,34 @@ class SFMessageSale(models.Model): purchase_order_id = [] if picking_ids: for picking_id in picking_ids: + 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 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('坯料采购提醒') + 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) 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) diff --git a/sf_message/models/sf_message_stock_picking.py b/sf_message/models/sf_message_stock_picking.py index 6e80c670..5d15d34a 100644 --- a/sf_message/models/sf_message_stock_picking.py +++ b/sf_message/models/sf_message_stock_picking.py @@ -12,26 +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.check_in == '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 == '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 @@ -49,26 +66,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.ref('stock.menu_stock_root').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 +95,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 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', '=', '已排')]) diff --git a/sf_message/views/purchase_order_view.xml b/sf_message/views/purchase_order_view.xml new file mode 100644 index 00000000..3000d576 --- /dev/null +++ b/sf_message/views/purchase_order_view.xml @@ -0,0 +1,46 @@ + + + + 采购订单 + ir.actions.act_window + purchase.order + tree,kanban,form,pivot,graph,calendar,activity + + [('state','in',('purchase', 'done'))] + + {'search_default_filter_order_warning':1} + + + 还没有采购订单, 我们先创建一个! + + + 当您下单到您的供应商,确定您的询价它会变成采购订单. + + + + + + 采购订单 + ir.actions.act_window + purchase.order + tree,kanban,form,pivot,graph,calendar,activity + + [('state','in',('purchase', 'done'))] + + {'search_default_filter_order_overdue':1} + + + 还没有采购订单, 我们先创建一个! + + + 当您下单到您的供应商,确定您的询价它会变成采购订单. + + + + \ No newline at end of file diff --git a/sf_sale/__manifest__.py b/sf_sale/__manifest__.py index 0ca6457c..e824240e 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 d41b0e0d..58c04388 100644 --- a/sf_sale/models/sale_order.py +++ b/sf_sale/models/sale_order.py @@ -318,6 +318,10 @@ class RePurchaseOrder(models.Model): continue purchase.origin_sale_id = False + delivery_warning = fields.Selection([('normal', '正常'), ('warning', '预警'), ('overdue', '已逾期')], + string='交期状态', + tracking=True) + @api.depends('partner_id') def _compute_user_id(self): if not self.user_id: @@ -399,6 +403,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 PurchaseOrderLine(models.Model): _inherit = 'purchase.order.line' diff --git a/sf_sale/views/purchase_order_view.xml b/sf_sale/views/purchase_order_view.xml index bb2b957b..7ca612b2 100644 --- a/sf_sale/views/purchase_order_view.xml +++ b/sf_sale/views/purchase_order_view.xml @@ -234,6 +234,8 @@ date_approve asc + delivery_warning == 'warning' + delivery_warning == 'overdue' hide @@ -248,6 +250,7 @@ + purchase_order_list_name @@ -255,6 +258,21 @@ + + purchase.order.search.inherit.sf + purchase.order + + + + + + + + + + + purchase.order.list.select.inherit.sf purchase.order
+ 还没有采购订单, 我们先创建一个! +
+ 当您下单到您的供应商,确定您的询价它会变成采购订单. +