diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index e2ef6dbe..ba0c6751 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -27,6 +27,7 @@ 'wizard/production_technology_re_adjust_wizard_views.xml', 'wizard/mrp_workorder_batch_replan_wizard_views.xml', 'wizard/sf_programming_reason_views.xml', + 'wizard/sale_order_cancel_views.xml', 'views/mrp_views_menus.xml', 'views/agv_scheduling_views.xml', 'views/stock_lot_views.xml', diff --git a/sf_manufacturing/models/sale_order.py b/sf_manufacturing/models/sale_order.py index e31faf1c..1b94f07f 100644 --- a/sf_manufacturing/models/sale_order.py +++ b/sf_manufacturing/models/sale_order.py @@ -149,6 +149,23 @@ class SaleOrder(models.Model): product_bom_purchase.with_user(self.env.ref("base.user_admin")).bom_create_line_has( purchase_embryo) return super(SaleOrder, self).action_confirm() + + def action_show_cancel_wizard(self): + wizard = self.env['sf.sale.order.cancel.wizard'].create({ + 'order_id': self.id, + }) + + # 创建关联单据行 + self.env['sf.sale.order.cancel.line'].create_from_order(wizard.id, self) + + return { + 'name': '取消销售订单', + 'type': 'ir.actions.act_window', + 'res_model': 'sf.sale.order.cancel.wizard', + 'view_mode': 'form', + 'target': 'new', + 'res_id': wizard.id, + } class SaleOrderLine(models.Model): _inherit = 'sale.order.line' diff --git a/sf_manufacturing/security/ir.model.access.csv b/sf_manufacturing/security/ir.model.access.csv index e8c1882f..246cce63 100644 --- a/sf_manufacturing/security/ir.model.access.csv +++ b/sf_manufacturing/security/ir.model.access.csv @@ -192,3 +192,5 @@ access_sf_programming_reason,sf_programming_reason,model_sf_programming_reason,b access_sf_programming_record,sf_programming_record,model_sf_programming_record,base.group_user,1,1,1,0 access_sf_work_individuation_page,sf_work_individuation_page,model_sf_work_individuation_page,sf_base.group_sf_mrp_user,1,1,1,0 access_sf_work_individuation_page_group_plan_dispatch,sf_work_individuation_page_group_plan_dispatch,model_sf_work_individuation_page,sf_base.group_plan_dispatch,1,1,0,0 +access_sf_sale_order_cancel_wizard,sf_sale_order_cancel_wizard,model_sf_sale_order_cancel_wizard,sf_base.group_sf_order_user,1,1,1,0 +access_sf_sale_order_cancel_line,sf_sale_order_cancel_line,model_sf_sale_order_cancel_line,sf_base.group_sf_order_user,1,1,1,0 \ 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 aa5bfaa0..e17c1546 100644 --- a/sf_manufacturing/views/sale_order_views.xml +++ b/sf_manufacturing/views/sale_order_views.xml @@ -27,10 +27,20 @@ {'invisible': [('state', 'not in', ['draft', 'supply method', 'sale', 'processing'])]} + 警告:取消操作将不可逆,是否确定要取消该单据? {'invisible': ['|','&',('check_status', '!=', 'approved'),('state', 'in', ['draft','cancel','supply method']),'&',('check_status', '=', 'approved'),('state', 'in', ['sale','cancel','supply method'])]} + + + + diff --git a/sf_manufacturing/wizard/__init__.py b/sf_manufacturing/wizard/__init__.py index 6a0af9e5..7a2541c3 100644 --- a/sf_manufacturing/wizard/__init__.py +++ b/sf_manufacturing/wizard/__init__.py @@ -5,3 +5,4 @@ from . import production_technology_wizard from . import production_technology_re_adjust_wizard from . import mrp_workorder_batch_replan_wizard from . import sf_programming_reason +from . import sale_order_cancel diff --git a/sf_manufacturing/wizard/sale_order_cancel.py b/sf_manufacturing/wizard/sale_order_cancel.py new file mode 100644 index 00000000..223c75d8 --- /dev/null +++ b/sf_manufacturing/wizard/sale_order_cancel.py @@ -0,0 +1,103 @@ +from odoo import models, fields, api + +class SFSaleOrderCancelWizard(models.TransientModel): + _name = 'sf.sale.order.cancel.wizard' + _description = '销售订单取消向导' + + order_id = fields.Many2one('sale.order', string='销售订单') + related_docs = fields.One2many('sf.sale.order.cancel.line', 'wizard_id', string='相关单据') + + @api.model + def default_get(self, fields_list): + defaults = super().default_get(fields_list) + if self._context.get('active_id'): + order = self.env['sale.order'].browse(self._context.get('active_id')) + defaults['order_id'] = order.id + # 创建向导时自动创建关联单据行 + wizard = self.create(defaults) + self.env['sf.sale.order.cancel.line'].create_from_order(wizard.id, order) + defaults['related_docs'] = wizard.related_docs.ids + return defaults + + def action_confirm_cancel(self): + self.ensure_one() + return self.order_id.action_cancel() + +class SFSaleOrderCancelLine(models.TransientModel): + _name = 'sf.sale.order.cancel.line' + _description = '销售订单取消行' + + wizard_id = fields.Many2one('sf.sale.order.cancel.wizard') + sequence = fields.Integer('序号') + category = fields.Char('大类') + doc_name = fields.Char('单据名称') + operation_type = fields.Char('作业类型') + doc_number = fields.Char('单据编号') + line_number = fields.Char('行号') + product_name = fields.Char('产品名称') + quantity = fields.Float('数量') + doc_state = fields.Char('单据状态') + cancel_reason = fields.Char('禁止取消原因') + + @api.model + def create_from_order(self, wizard_id, order): + sequence = 1 + lines = [] + + # 检查销售订单 + if order.invoice_ids: + for invoice in order.invoice_ids: + vals = { + 'wizard_id': wizard_id, + 'sequence': sequence, + 'category': '销售', + 'doc_name': '销售订单', + 'operation_type': '销售', + 'doc_number': invoice.name, + 'product_name': invoice.product_id.name, + 'quantity': invoice.quantity, + 'doc_state': invoice.state, + 'cancel_reason': '已有异动' if invoice.state != 'draft' else '' + } + lines.append(self.create(vals)) + sequence += 1 + + # 检查交货单 + if order.picking_ids: + for picking in order.picking_ids: + vals = { + 'wizard_id': wizard_id, + 'sequence': sequence, + 'category': '库存', + 'doc_name': '交货单', + 'operation_type': '调拨', + 'doc_number': picking.name, + 'product_name': picking.product_id.name if picking.product_id else '', + 'quantity': picking.product_qty if hasattr(picking, 'product_qty') else 0, + 'doc_state': picking.state, + 'cancel_reason': '已有异动' if picking.state not in ['draft', 'cancel', 'waiting'] else '' + } + lines.append(self.create(vals)) + sequence += 1 + + # 检查制造订单 + manufacturing_orders = self.env['mrp.production'].search([ + ('origin', '=', order.name) + ]) + for mo in manufacturing_orders: + vals = { + 'wizard_id': wizard_id, + 'sequence': sequence, + 'category': '制造', + 'doc_name': '制造订单', + 'operation_type': '制造', + 'doc_number': mo.name, + 'product_name': mo.product_id.name, + 'quantity': mo.product_qty, + 'doc_state': mo.state, + 'cancel_reason': '已有异动' if mo.state not in ['draft', 'cancel'] else '' + } + lines.append(self.create(vals)) + sequence += 1 + + return lines \ No newline at end of file diff --git a/sf_manufacturing/wizard/sale_order_cancel_views.xml b/sf_manufacturing/wizard/sale_order_cancel_views.xml new file mode 100644 index 00000000..0adf0081 --- /dev/null +++ b/sf_manufacturing/wizard/sale_order_cancel_views.xml @@ -0,0 +1,42 @@ + + + + sf.sale.order.cancel.wizard.form + sf.sale.order.cancel.wizard + + + + + + + 弹窗描述: + 1) 若无异动,描述为: 确认所有下游单据全部取消? + 2) 若有异动,描述为: 部分或全部下游单据存在异动,无法取消,详情如下: + + + + + + + + + + + + + + + + + + + + \ No newline at end of file