diff --git a/sale_order_batch/__init__.py b/sale_order_batch/__init__.py index 0650744..9b42961 100644 --- a/sale_order_batch/__init__.py +++ b/sale_order_batch/__init__.py @@ -1 +1,2 @@ from . import models +from . import wizard diff --git a/sale_order_batch/__manifest__.py b/sale_order_batch/__manifest__.py index dd180ad..d0457a5 100644 --- a/sale_order_batch/__manifest__.py +++ b/sale_order_batch/__manifest__.py @@ -7,13 +7,14 @@ "version": "16.0.2.3.0", "depends": ["sale", "product"], "data": [ - "data/ir_sequence_data.xml", + "security/ir.model.access.csv", + "security/ir_rules.xml", "views/sale_order_batch_views.xml", "views/sale_order_batch_product_views.xml", "views/sale_order_views.xml", "views/sale_menus.xml", - "security/ir.model.access.csv", - "security/ir_rules.xml", + "wizard/sale_order_batch_cancel_wizard.xml", + "data/ir_sequence_data.xml", ], "license": "LGPL-3", } diff --git a/sale_order_batch/models/sale_order.py b/sale_order_batch/models/sale_order.py index 05994a2..6d67058 100644 --- a/sale_order_batch/models/sale_order.py +++ b/sale_order_batch/models/sale_order.py @@ -11,6 +11,10 @@ class SaleOrder(models.Model): check_company=True, domain="[('state','!=','closed')]", ) + batch_state = fields.Selection( + related="batch_id.state", + string="Batch State", + ) def _get_current_batch(self): """ diff --git a/sale_order_batch/models/sale_order_batch.py b/sale_order_batch/models/sale_order_batch.py index ad0150e..beb61bb 100644 --- a/sale_order_batch/models/sale_order_batch.py +++ b/sale_order_batch/models/sale_order_batch.py @@ -1,4 +1,5 @@ from odoo import _, api, fields, models +from odoo.exceptions import UserError from odoo.addons.sale.models.sale_order import INVOICE_STATUS @@ -185,13 +186,37 @@ class SaleOrderBatch(models.Model): return True def action_cancel(self): - for batch in self: - orders = batch.sale_order_ids - # use _action_cancel to skip the wizzard - # ToDo: Implement wizard logic - orders._action_cancel() - batch.update({"state": "cancel"}) - return True + cancel_warning = self._show_cancel_wizard() + if cancel_warning: + self.ensure_one() + return { + "name": _("Cancel %s", self.name), + "view_mode": "form", + "type": "ir.actions.act_window", + "res_model": "sale.order.batch.cancel.wizard", + "target": "new", + "context": {"active_ids": self.ids}, + } + else: + self._action_cancel() + + def _action_cancel(self): + orders = self.mapped("sale_order_ids") + # use _action_cancel to skip the wizzard + orders._action_cancel() + self.write({"state": "cancel"}) + + def _show_cancel_wizard(self): + """Decide whether the sale.order.batch.cancel wizard should be shown to cancel specified orders. + + :return: True if there is any non-draft order in the given orders + :rtype: bool + """ + + if self.env.context.get("disable_cancel_warning"): + return False + batch_orders = self.mapped("sale_order_ids") + return any(order._show_cancel_wizard() for order in batch_orders) def action_open(self): for batch in self: @@ -210,3 +235,29 @@ class SaleOrderBatch(models.Model): "sale.order.batch" ) or _("New") return super().create(vals_list) + + +class SaleOrderBatchCancelWizard(models.TransientModel): + _name = "sale.order.batch.cancel.wizard" + _description = "Sale Order Batch Cancel Wizard" + + def action_cancel(self): + batches = self.env["sale.order.batch"].browse(self._context["active_ids"]) + for batch in batches: + orders = batch.sale_order_ids + # Warn if any sale order is not in draft + not_draft_orders = orders.filtered(lambda o: o.state != "draft") + if not_draft_orders: + raise UserError( + _( + "You can only cancel batches where all sale orders are in draft state." + ) + ) + # use _action_cancel to skip the wizzard + # ToDo: Implement wizard logic + orders._action_cancel() + batch.update({"state": "cancel"}) + return True + + def action_discard(self): + return {"type": "ir.actions.act_window_close"} diff --git a/sale_order_batch/security/ir.model.access.csv b/sale_order_batch/security/ir.model.access.csv index 1de6396..14868b2 100644 --- a/sale_order_batch/security/ir.model.access.csv +++ b/sale_order_batch/security/ir.model.access.csv @@ -3,3 +3,4 @@ access_sale_order_batch_invoicing_payments,sale.order.batch,model_sale_order_bat access_sale_order_batch,sale.order.batch,model_sale_order_batch,sales_team.group_sale_salesman,1,1,1,0 access_sale_order_batch_manager,sale.order.batch.manager,model_sale_order_batch,sales_team.group_sale_manager,1,1,1,1 access_sale_order_batch_product,sale.order.batch.product,model_sale_order_batch_product,sales_team.group_sale_salesman,1,1,1,1 +sale_order_batch.access_sale_order_batch_cancel_wizard,access_sale_order_batch_cancel_wizard,sale_order_batch.model_sale_order_batch_cancel_wizard,base.group_user,1,1,1,1 diff --git a/sale_order_batch/views/sale_order_batch_views.xml b/sale_order_batch/views/sale_order_batch_views.xml index 40f239c..bebe390 100644 --- a/sale_order_batch/views/sale_order_batch_views.xml +++ b/sale_order_batch/views/sale_order_batch_views.xml @@ -10,6 +10,13 @@ + - + + + + + + sale.order.batch.quotation.tree + sale.order.batch + + + + + + + + @@ -140,6 +167,7 @@ + @@ -148,13 +176,20 @@ + @@ -214,6 +249,7 @@ ir.actions.act_window sale.order.batch tree,form,activity + {'search_default_filter_batch_open': 1} @@ -222,6 +258,7 @@ ir.actions.act_window sale.order.batch tree,form,activity + {'search_default_filter_batch_finished': 1} diff --git a/sale_order_batch/wizard/__init__.py b/sale_order_batch/wizard/__init__.py new file mode 100644 index 0000000..56c3dec --- /dev/null +++ b/sale_order_batch/wizard/__init__.py @@ -0,0 +1 @@ +from . import sale_order_batch_cancel_wizard diff --git a/sale_order_batch/wizard/sale_order_batch_cancel_wizard.py b/sale_order_batch/wizard/sale_order_batch_cancel_wizard.py new file mode 100644 index 0000000..56333e3 --- /dev/null +++ b/sale_order_batch/wizard/sale_order_batch_cancel_wizard.py @@ -0,0 +1,34 @@ +from odoo import api, fields, models + + +class SaleOrderBatchCancelWizard(models.TransientModel): + _name = "sale.order.batch.cancel.wizard" + _description = "Cancel Sale Order Batch Confirmation" + + batch_ids = fields.Many2many( + comodel_name="sale.order.batch", + string="Batches to Cancel", + default=lambda self: self.env["sale.order.batch"].browse( + self.env.context.get("active_ids", []) + ), + ) + + order_ids = fields.Many2many( + comodel_name="sale.order", + string="Orders to Cancel", + compute="_compute_order_ids", + ) + + @api.depends("batch_ids") + def _compute_order_ids(self): + for record in self: + batches = record.batch_ids + record.order_ids = batches.mapped("sale_order_ids") + + def action_cancel(self): + batches = self.batch_ids + batches._action_cancel() + return {"type": "ir.actions.act_window_close"} + + def action_discard(self): + return {"type": "ir.actions.act_window_close"} diff --git a/sale_order_batch/wizard/sale_order_batch_cancel_wizard.xml b/sale_order_batch/wizard/sale_order_batch_cancel_wizard.xml new file mode 100644 index 0000000..9609fba --- /dev/null +++ b/sale_order_batch/wizard/sale_order_batch_cancel_wizard.xml @@ -0,0 +1,24 @@ + + + sale.order.batch.cancel.wizard.form + sale.order.batch.cancel.wizard + + + + + Are you sure you want to cancel this order? + + + + + + + + + + + +