diff --git a/sf_bf_connect/models/process_status.py b/sf_bf_connect/models/process_status.py index 09fecfae..69eb84f1 100644 --- a/sf_bf_connect/models/process_status.py +++ b/sf_bf_connect/models/process_status.py @@ -36,6 +36,8 @@ class StatusChange(models.Model): # 使用super()来调用原始方法(在本例中为'sale.order'模型的'action_confirm'方法) try: res = super(StatusChange, self).action_confirm() + # 修改销售订单状态为【加工中】 + self.write({'state': 'processing'}) logging.info('原生方法返回结果:%s' % res) # 原有方法执行后,进行额外的操作(如调用外部API) process_start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') 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/mrp_production.py b/sf_manufacturing/models/mrp_production.py index d440d5bc..0ddd3631 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -769,7 +769,8 @@ class MrpProduction(models.Model): }] if production.product_id.categ_id.type in ['成品', '坯料']: # # 根据工序设计生成工单 - for route in production.technology_design_ids: + technology_design_ids = sorted(production.technology_design_ids, key=lambda x: x.sequence) + for route in technology_design_ids: workorder_has = self.env['mrp.workorder'].search( [('technology_design_id', '=', route.id), ('production_id', '=', production.id)]) if not workorder_has: @@ -963,10 +964,11 @@ class MrpProduction(models.Model): work_ids = workorder_ids.filtered(lambda item: item.sequence == 0) # 对工单进行逐个插入 for work_id in work_ids: - for order_id in rec.workorder_ids.filtered(lambda item: item.sequence > 0): - if work_id.name == order_id.name and work_id.processing_panel == order_id.processing_panel: - work_id.sequence = order_id.sequence + 1 - break + order_rework_ids = rec.workorder_ids.filtered( + lambda item: (item.sequence > 0 and work_id.name == item.name + and work_id.processing_panel == item.processing_panel)) + order_rework_ids = sorted(order_rework_ids, key=lambda item: item.sequence, reverse=True) + work_id.sequence = order_rework_ids[0].sequence + 1 # 对该工单之后的工单工序进行加一 work_order_ids = rec.workorder_ids.filtered( lambda item: item.sequence >= work_id.sequence and item.id != work_id.id) diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 52fa30c8..410f8d1b 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -138,7 +138,8 @@ class ResMrpWorkOrder(models.Model): is_subcontract = fields.Boolean(string='是否外协') surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数") - picking_ids = fields.Many2many('stock.picking', string='外协出入库单', compute='_compute_surface_technics_picking_ids') + picking_ids = fields.Many2many('stock.picking', string='外协出入库单', + compute='_compute_surface_technics_picking_ids') purchase_id = fields.Many2many('purchase.order', string='外协采购单') surface_technics_picking_count = fields.Integer("外协出入库", compute='_compute_surface_technics_picking_ids') @@ -327,7 +328,7 @@ class ResMrpWorkOrder(models.Model): 'view_mode': 'form', } return result - + def _get_surface_technics_purchase_ids(self): domain = [('origin', '=', self.production_id.name), ('purchase_type', '=', 'consignment')] purchase_orders = self.env['purchase.order'].search(domain) @@ -1429,6 +1430,8 @@ class ResMrpWorkOrder(models.Model): rfid_code = workorder.rfid_code workorder.write({'rfid_code_old': rfid_code, 'rfid_code': False}) + self.env['stock.lot'].sudo().search([('rfid', '=', rfid_code)]).write( + {'tool_material_status': '可用'}) if workorder.rfid_code: raise ValidationError(f'【{workorder.name}】工单解绑失败,请重新点击完成按钮!!!') # workorder.rfid_code_old = rfid_code @@ -1567,7 +1570,7 @@ class ResMrpWorkOrder(models.Model): 'default_confirm_button': '确认解除', # 'default_feeder_station_start_id': feeder_station_start_id, }} - + move_subcontract_workorder_ids = fields.One2many('stock.move', 'subcontract_workorder_id', string='组件') @@ -1778,6 +1781,7 @@ class SfWorkOrderBarcodes(models.Model): if workorder_rfid: for item in workorder_rfid: item.write({'rfid_code': barcode}) + lot.sudo().write({'tool_material_status': '在用'}) logging.info("Rfid[%s]绑定成功!!!" % barcode) else: raise UserError('该Rfid【%s】绑定的是【%s】, 不是托盘!!!' % (barcode, lot.product_id.name)) 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 index e54e96bf..1ffed728 100644 --- a/sf_manufacturing/models/purchase_order.py +++ b/sf_manufacturing/models/purchase_order.py @@ -10,7 +10,6 @@ from odoo.tools import OrderedSet # _get_surface_technics_purchase_ids class PurchaseOrder(models.Model): _inherit = 'purchase.order' - def button_confirm(self): super().button_confirm() workorders = self.env['mrp.workorder'].search([('purchase_id', '=', self.id)]) @@ -29,3 +28,6 @@ class PurchaseOrder(models.Model): if not mo.move_line_ids: self.env['stock.move.line'].create(mo.get_move_line(workorder.production_id, workorder)) return True +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 3cc8e587..8113ddae 100644 --- a/sf_manufacturing/models/sale_order.py +++ b/sf_manufacturing/models/sale_order.py @@ -196,7 +196,7 @@ class SaleOrder(models.Model): return new_picking 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..567930dd 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/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml index 1a2682be..7fc2e8c5 100644 --- a/sf_manufacturing/views/mrp_workorder_view.xml +++ b/sf_manufacturing/views/mrp_workorder_view.xml @@ -29,6 +29,8 @@ + + @@ -53,10 +55,7 @@ - {'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft', - 'done', - 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done','rework', 'cancel')), - ('is_user_working', '!=', False),("user_permissions","=",False),("name","in",("CNC加工","解除装夹"))]} + {'invisible': [('state', '!=', 'ready')]} @@ -174,9 +173,9 @@ + attrs="{'invisible': [('state', '!=', 'ready')]}"/> + attrs="{'invisible': [('state', '!=', 'ready')]}"/> + + + + 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_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_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 @@ - + + + + + 检查采购单是否已逾期预警和逾期 + + 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 2e99de70..2958ce00 100644 --- a/sf_sale/models/sale_order.py +++ b/sf_sale/models/sale_order.py @@ -225,7 +225,8 @@ class ReSaleOrder(models.Model): class ResaleOrderLine(models.Model): _inherit = 'sale.order.line' - + # part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True) + part_name = fields.Char('零件名称', related='product_id.part_name', readonly=True) model_glb_file = fields.Binary('模型的glb文件', compute='_compute_model_glb_file', store=True) # product_template_id = fields.Many2one( # string="产品", @@ -281,13 +282,29 @@ class RePurchaseOrder(models.Model): store=True) purchase_type = fields.Selection( - [('standard', '标准采购'), ('consignment', '委外加工'), ('outsourcing', '工序外协'), ('outside', '外购订单')], - string='采购类型', default='standard') + [('standard', '标准采购'), ('consignment', '工序外协'), ('outsourcing', '委外加工'), ('outside', '外购订单')], + string='采购类型', default='standard', store=True, compute='_compute_purchase_type') origin_sale_id = fields.Many2one('sale.order', string='销售订单号', compute='_compute_origin_sale_id') + @api.depends('origin') + def _compute_purchase_type(self): + for purchase in self: + order_id = self.env['sale.order'].sudo().search([('name', '=', purchase.origin)]) + if order_id: + product_list = [line.product_id.id for line in purchase.order_line] + for order_line in order_id.order_line: + if order_line.supply_method == 'purchase': + if order_line.product_id.id in product_list: + purchase.purchase_type = 'outside' + break + elif order_line.supply_method == 'outsourcing': + if order_line.product_id.id in product_list: + purchase.purchase_type = 'outsourcing' + break + @api.depends('order_line.move_dest_ids.group_id.mrp_production_ids', - 'order_line.move_ids.move_dest_ids.group_id.mrp_production_ids') + 'order_line.move_ids.move_dest_ids.group_id.mrp_production_ids', 'origin') def _compute_origin_sale_id(self): for purchase in self: productions_ids = purchase._get_mrp_productions() @@ -295,8 +312,16 @@ class RePurchaseOrder(models.Model): if productions_ids[0].sale_order_id: purchase.origin_sale_id = productions_ids[0].sale_order_id.id continue + order_id = self.env['sale.order'].sudo().search([('name', '=', purchase.origin)]) + if order_id: + purchase.origin_sale_id = order_id.id + 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: @@ -378,12 +403,33 @@ 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' part_name = fields.Char('零件名称', related='product_id.part_name', readonly=True) - + # part_number = fields.Char('零件图号',related='product_id.part_number', readonly=True) class ResPartnerToSale(models.Model): _inherit = 'res.partner' diff --git a/sf_sale/views/purchase_order_view.xml b/sf_sale/views/purchase_order_view.xml index ccdee1d0..be35d8a2 100644 --- a/sf_sale/views/purchase_order_view.xml +++ b/sf_sale/views/purchase_order_view.xml @@ -16,10 +16,11 @@ - + string="接收产品" class="oe_highlight" type="object" + attrs="{'invisible': ['|', '|' , ('is_shipped', '=', True), ('state','not in', ('purchase','done')), ('incoming_picking_count', '=', 0)]}" + data-hotkey="y" groups="stock.group_stock_user"/> + 1 @@ -134,7 +135,8 @@ hide - + + 报价截止日期 @@ -168,11 +170,11 @@ - + - + @@ -232,6 +234,8 @@ date_approve asc + delivery_warning == 'warning' + delivery_warning == 'overdue' hide @@ -246,6 +250,7 @@ + purchase_order_list_name @@ -253,6 +258,21 @@ + + purchase.order.search.inherit.sf + purchase.order + + + + + + + + + + + purchase.order.list.select.inherit.sf purchase.order @@ -261,12 +281,12 @@ - - - - - - + + + + + + diff --git a/sf_sale/views/sale_order_view.xml b/sf_sale/views/sale_order_view.xml index d6247823..0de2287b 100644 --- a/sf_sale/views/sale_order_view.xml +++ b/sf_sale/views/sale_order_view.xml @@ -103,6 +103,7 @@ + diff --git a/sf_tool_management/models/maintenance_equipment.py b/sf_tool_management/models/maintenance_equipment.py index 18142e24..5da56016 100644 --- a/sf_tool_management/models/maintenance_equipment.py +++ b/sf_tool_management/models/maintenance_equipment.py @@ -126,7 +126,7 @@ class StockLot(models.Model): tool_material_search_id = fields.Many2one('sf.tool.material.search', string='刀具物料搜索') fixture_material_search_id = fields.Many2one('sf.fixture.material.search', string='夹具物料搜索') tool_material_status = fields.Selection( - [('未入库', '未入库'), ('可用', '可用'), ('在用', '在用'), ('报废', '报废')], string='状态', + [('未入库', '未入库'), ('可用', '可用'), ('在用', '空闲'), ('报废', '报废')], string='状态', compute='_compute_tool_material_status', store=True) @api.depends('quant_ids')
+ 还没有采购订单, 我们先创建一个! +
+ 当您下单到您的供应商,确定您的询价它会变成采购订单. +