From a98271f31a612b236370d03e01ebbc0ef8d77be0 Mon Sep 17 00:00:00 2001 From: DavidJForgeFlow Date: Thu, 3 Nov 2022 10:53:57 +0100 Subject: [PATCH] [14.0][ADD] rma_scrap --- rma_scrap/README.rst | 45 +++++++ rma_scrap/__init__.py | 2 + rma_scrap/__manifest__.py | 18 +++ rma_scrap/models/__init__.py | 6 + rma_scrap/models/rma_operation.py | 24 ++++ rma_scrap/models/rma_order.py | 31 +++++ rma_scrap/models/rma_order_line.py | 106 +++++++++++++++ rma_scrap/models/stock_move.py | 20 +++ rma_scrap/models/stock_rule.py | 33 +++++ rma_scrap/models/stock_scrap.py | 23 ++++ rma_scrap/security/ir.model.access.csv | 7 + rma_scrap/tests/__init__.py | 1 + rma_scrap/tests/test_rma_scrap.py | 172 ++++++++++++++++++++++++ rma_scrap/views/rma_operation_view.xml | 34 +++++ rma_scrap/views/rma_order_line_view.xml | 51 +++++++ rma_scrap/views/rma_order_view.xml | 25 ++++ rma_scrap/wizards/__init__.py | 1 + rma_scrap/wizards/rma_make_scrap.py | 112 +++++++++++++++ rma_scrap/wizards/rma_scrap_view.xml | 72 ++++++++++ 19 files changed, 783 insertions(+) create mode 100644 rma_scrap/README.rst create mode 100644 rma_scrap/__init__.py create mode 100644 rma_scrap/__manifest__.py create mode 100644 rma_scrap/models/__init__.py create mode 100644 rma_scrap/models/rma_operation.py create mode 100644 rma_scrap/models/rma_order.py create mode 100644 rma_scrap/models/rma_order_line.py create mode 100644 rma_scrap/models/stock_move.py create mode 100644 rma_scrap/models/stock_rule.py create mode 100644 rma_scrap/models/stock_scrap.py create mode 100644 rma_scrap/security/ir.model.access.csv create mode 100644 rma_scrap/tests/__init__.py create mode 100644 rma_scrap/tests/test_rma_scrap.py create mode 100644 rma_scrap/views/rma_operation_view.xml create mode 100644 rma_scrap/views/rma_order_line_view.xml create mode 100644 rma_scrap/views/rma_order_view.xml create mode 100644 rma_scrap/wizards/__init__.py create mode 100644 rma_scrap/wizards/rma_make_scrap.py create mode 100644 rma_scrap/wizards/rma_scrap_view.xml diff --git a/rma_scrap/README.rst b/rma_scrap/README.rst new file mode 100644 index 00000000..ab2a49b9 --- /dev/null +++ b/rma_scrap/README.rst @@ -0,0 +1,45 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :alt: License LGPL-3 + +============ +RMA Scrap +============ + +This module allows you to put scrap the products. + +Configuration +============= + +Go to *RMA / Configuration / Customer Operations* and define there: + +#. The Scrap Policy +#. The default scrap destination location . + +Usage +===== + +#. Go to a Customer RMA. +#. Click on *Scrap*. +#. Indicate the quantity that you want to scrap. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* David Jimenez + + +Maintainer +---------- + +This module is maintained by ForgeFlow diff --git a/rma_scrap/__init__.py b/rma_scrap/__init__.py new file mode 100644 index 00000000..976591c9 --- /dev/null +++ b/rma_scrap/__init__.py @@ -0,0 +1,2 @@ +from . import wizards +from . import models diff --git a/rma_scrap/__manifest__.py b/rma_scrap/__manifest__.py new file mode 100644 index 00000000..e45d13e4 --- /dev/null +++ b/rma_scrap/__manifest__.py @@ -0,0 +1,18 @@ +{ + "name": "RMA Put Away", + "version": "14.0.1.0.0", + "license": "LGPL-3", + "category": "RMA", + "summary": "Allows to put away the received products in odoo", + "author": "ForgeFlow", + "website": "https://github.com/ForgeFlow/stock-rma", + "depends": ["rma"], + "data": [ + "security/ir.model.access.csv", + "views/rma_operation_view.xml", + "views/rma_order_line_view.xml", + "views/rma_order_view.xml", + "wizards/rma_scrap_view.xml", + ], + "installable": True, +} diff --git a/rma_scrap/models/__init__.py b/rma_scrap/models/__init__.py new file mode 100644 index 00000000..aac4c099 --- /dev/null +++ b/rma_scrap/models/__init__.py @@ -0,0 +1,6 @@ +from . import rma_operation +from . import stock_move +from . import stock_rule +from . import rma_order_line +from . import rma_order +from . import stock_scrap diff --git a/rma_scrap/models/rma_operation.py b/rma_scrap/models/rma_operation.py new file mode 100644 index 00000000..45c003af --- /dev/null +++ b/rma_scrap/models/rma_operation.py @@ -0,0 +1,24 @@ +# Copyright 2022 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html). + +from odoo import fields, models + + +class RmaOperation(models.Model): + _inherit = "rma.operation" + + scrap_policy = fields.Selection( + selection=[ + ("no", "Not required"), + ("ordered", "Based on Ordered Quantities"), + ("received", "Based on Received Quantities"), + ], + string="Scrap Policy", + default="no", + ) + + scrap_location_id = fields.Many2one( + comodel_name="stock.location", + string="Scrap Destination Location", + domain="[('scrap_location', '=', True), ('company_id', 'in', [company_id, False])]", + ) diff --git a/rma_scrap/models/rma_order.py b/rma_scrap/models/rma_order.py new file mode 100644 index 00000000..a38e22ac --- /dev/null +++ b/rma_scrap/models/rma_order.py @@ -0,0 +1,31 @@ +# Copyright 2022 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) +from odoo import fields, models + + +class RmaOrder(models.Model): + _inherit = "rma.order" + + def _compute_scrap_count(self): + for order in self: + moves = ( + order.mapped("rma_line_ids.move_ids") + .filtered(lambda m: m.is_rma_scrap) + .move_line_ids + ) + order.scrap_count = len(moves) + + scrap_count = fields.Integer(compute="_compute_scrap_count", string="# Scrap") + + def action_view_scrap_transfers(self): + self.ensure_one() + action = self.env.ref("stock.action_stock_scrap") + result = action.sudo().read()[0] + scraps = self.env["stock.scrap"].search([("origin", "=", self.name)]) + if len(scraps) > 1: + result["domain"] = [("id", "in", scraps.ids)] + elif len(scraps) == 1: + res = self.env.ref("stock.stock_scrap_form_view", False) + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = scraps.ids[0] + return result diff --git a/rma_scrap/models/rma_order_line.py b/rma_scrap/models/rma_order_line.py new file mode 100644 index 00000000..654af904 --- /dev/null +++ b/rma_scrap/models/rma_order_line.py @@ -0,0 +1,106 @@ +# Copyright 2022 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) +from odoo import api, fields, models + + +class RmaOrderLine(models.Model): + _inherit = "rma.order.line" + + @api.depends( + "move_ids", + "move_ids.state", + "move_ids.is_rma_scrap", + "qty_scrap", + "scrap_policy", + "product_qty", + ) + def _compute_qty_to_scrap(self): + for rec in self: + rec.qty_to_scrap = 0.0 + if rec.scrap_policy == "ordered": + rec.qty_to_scrap = rec.product_qty - rec.qty_scrap + elif rec.scrap_policy == "received": + rec.qty_to_scrap = rec.qty_received - rec.qty_scrap + + @api.depends("move_ids", "move_ids.state", "move_ids.is_rma_scrap") + def _compute_qty_in_scrap(self): + product_obj = self.env["uom.uom"] + for rec in self: + qty = 0.0 + for move in self.env["stock.scrap"].search( + [("origin", "=", rec.name), ("state", "=", "draft")] + ): + qty += product_obj._compute_quantity(move.scrap_qty, rec.uom_id) + rec.qty_in_scrap = qty + + @api.depends("move_ids", "move_ids.state", "move_ids.is_rma_scrap") + def _compute_qty_scrap(self): + product_obj = self.env["uom.uom"] + for rec in self: + qty = 0.0 + for move in rec.move_ids.filtered( + lambda m: m.state in ["done"] and m.is_rma_scrap + ): + qty += product_obj._compute_quantity(move.product_uom_qty, rec.uom_id) + rec.qty_scrap = qty + + def _compute_scrap_count(self): + for line in self: + scraps = self.env["stock.scrap"].search([("origin", "=", line.name)]) + line.scrap_count = len(scraps) + + qty_to_scrap = fields.Float( + string="Qty To Scrap", + copy=False, + digits="Product Unit of Measure", + readonly=True, + compute="_compute_qty_to_scrap", + store=True, + ) + qty_in_scrap = fields.Float( + string="Qty In Scrap", + copy=False, + digits="Product Unit of Measure", + readonly=True, + compute="_compute_qty_in_scrap", + store=True, + ) + qty_scrap = fields.Float( + string="Qty Scrap", + copy=False, + digits="Product Unit of Measure", + readonly=True, + compute="_compute_qty_scrap", + store=True, + ) + scrap_policy = fields.Selection( + selection=[ + ("no", "Not required"), + ("ordered", "Based on Ordered Quantities"), + ("received", "Based on Received Quantities"), + ], + string="Scrap Policy", + default="no", + required=True, + readonly=False, + ) + scrap_count = fields.Integer(compute="_compute_scrap_count", string="# Scraps") + + @api.onchange("operation_id") + def _onchange_operation_id(self): + res = super(RmaOrderLine, self)._onchange_operation_id() + if self.operation_id: + self.scrap_policy = self.operation_id.scrap_policy or "no" + return res + + def action_view_scrap_transfers(self): + action = self.env.ref("stock.action_stock_scrap") + result = action.sudo().read()[0] + scraps = self.env["stock.scrap"].search([("origin", "=", self.name)]) + if len(scraps) > 1: + result["domain"] = [("id", "in", scraps.ids)] + elif len(scraps) == 1: + res = self.env.ref("stock.stock_scrap_form_view", False) + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = scraps.ids[0] + return result diff --git a/rma_scrap/models/stock_move.py b/rma_scrap/models/stock_move.py new file mode 100644 index 00000000..68ddfe94 --- /dev/null +++ b/rma_scrap/models/stock_move.py @@ -0,0 +1,20 @@ +# Copyright 2022 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import fields, models + + +class StockMove(models.Model): + _inherit = "stock.move" + + is_rma_scrap = fields.Boolean( + string="Is RMA Scrap", + copy=False, + help="This Stock Move has been created from a Scrap operation in " "the RMA.", + ) + + def _is_in_out_rma_move(self, op, states, location_type): + res = super(StockMove, self)._is_in_out_rma_move(op, states, location_type) + if self.is_rma_scrap: + return False + return res diff --git a/rma_scrap/models/stock_rule.py b/rma_scrap/models/stock_rule.py new file mode 100644 index 00000000..673a41be --- /dev/null +++ b/rma_scrap/models/stock_rule.py @@ -0,0 +1,33 @@ +# Copyright 2022 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import models + + +class StockRule(models.Model): + _inherit = "stock.rule" + + def _get_stock_move_values( + self, + product_id, + product_qty, + product_uom, + location_id, + name, + origin, + company_id, + values, + ): + res = super()._get_stock_move_values( + product_id, + product_qty, + product_uom, + location_id, + name, + origin, + company_id, + values, + ) + if "is_rma_scrap" in values: + res["is_rma_scrap"] = values.get("is_rma_scrap") + return res diff --git a/rma_scrap/models/stock_scrap.py b/rma_scrap/models/stock_scrap.py new file mode 100644 index 00000000..49dd7ac9 --- /dev/null +++ b/rma_scrap/models/stock_scrap.py @@ -0,0 +1,23 @@ +# Copyright 2022 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html). + +from odoo import fields, models + + +class StockScrap(models.Model): + _inherit = "stock.scrap" + + rma_line_id = fields.Many2one("rma.order.line", string="RMA order Line") + + is_rma_scrap = fields.Boolean( + string="Is RMA Scrap", + default=False, + copy=False, + help="This Stock Move has been created from a Scrap operation in " "the RMA.", + ) + + def do_scrap(self): + super(StockScrap, self).do_scrap() + if self.is_rma_scrap: + self.move_id.is_rma_scrap = True + self.rma_line_id.move_ids |= self.move_id diff --git a/rma_scrap/security/ir.model.access.csv b/rma_scrap/security/ir.model.access.csv new file mode 100644 index 00000000..bf1466dd --- /dev/null +++ b/rma_scrap/security/ir.model.access.csv @@ -0,0 +1,7 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_rma_scrap_wizard,rma.order.manager,model_rma_make_scrap_wizard,rma.group_rma_manager,1,1,1,1 +access_rma_scrap_wizard_customer,rma.order.manager,model_rma_make_scrap_wizard,rma.group_rma_customer_user,1,1,1,1 +access_rma_scrap_wizard_supplier,rma.order.manager,model_rma_make_scrap_wizard,rma.group_rma_supplier_user,1,1,1,1 +access_rma_scrap_item_wizard,rma.order.manager,model_rma_make_scrap_item_wizard,rma.group_rma_manager,1,1,1,1 +access_rma_scrap_item_wizard_customer,rma.order.manager,model_rma_make_scrap_item_wizard,rma.group_rma_customer_user,1,1,1,1 +access_rma_scrap_item_wizard_supplier,rma.order.manager,model_rma_make_scrap_item_wizard,rma.group_rma_supplier_user,1,1,1,1 diff --git a/rma_scrap/tests/__init__.py b/rma_scrap/tests/__init__.py new file mode 100644 index 00000000..fb80229f --- /dev/null +++ b/rma_scrap/tests/__init__.py @@ -0,0 +1 @@ +from . import test_rma_scrap diff --git a/rma_scrap/tests/test_rma_scrap.py b/rma_scrap/tests/test_rma_scrap.py new file mode 100644 index 00000000..fecc34c1 --- /dev/null +++ b/rma_scrap/tests/test_rma_scrap.py @@ -0,0 +1,172 @@ +from odoo.tests import common + + +class TestRmaScrap(common.SingleTransactionCase): + @classmethod + def setUpClass(cls): + super(TestRmaScrap, cls).setUpClass() + + cls.rma_obj = cls.env["rma.order"] + cls.rma_line_obj = cls.env["rma.order.line"] + cls.rma_op_obj = cls.env["rma.operation"] + cls.rma_make_picking = cls.env["rma_make_picking.wizard"] + cls.rma_make_scrap_wiz = cls.env["rma_make_scrap.wizard"] + cls.product_obj = cls.env["product.product"] + cls.partner_obj = cls.env["res.partner"] + + cls.rma_route_cust = cls.env.ref("rma.route_rma_customer") + cls.cust_loc = cls.env.ref("stock.stock_location_customers") + + # Create customer + cls.customer1 = cls.partner_obj.create({"name": "Customer 1"}) + + # Create products + cls.product_1 = cls.product_obj.create( + {"name": "Test Product 1", "type": "product", "list_price": 100.0} + ) + cls.product_2 = cls.product_obj.create( + { + "name": "Test Product 2", + "type": "product", + "list_price": 150.0, + "tracking": "lot", + } + ) + + cls.lot = cls.env["stock.production.lot"].create( + { + "name": "Lot for tests", + "product_id": cls.product_2.id, + "company_id": cls.env.ref("base.main_company").id, + } + ) + cls.wh = cls.env.ref("stock.warehouse0") + cls.stock_rma_location = cls.wh.lot_rma_id + cls.scrap_loc = cls.env["stock.location"].create( + { + "name": "WH Scrap Location", + "location_id": cls.wh.view_location_id.id, + "scrap_location": True, + } + ) + + # Create RMA group and operation: + cls.rma_group = cls.rma_obj.create({"partner_id": cls.customer1.id}) + + cls.operation_1 = cls.rma_op_obj.create( + { + "code": "TEST1", + "name": "Operation 1", + "type": "customer", + "receipt_policy": "ordered", + "scrap_policy": "received", + "scrap_location_id": cls.scrap_loc.id, + "in_route_id": cls.rma_route_cust.id, + "out_route_id": cls.rma_route_cust.id, + } + ) + cls.operation_2 = cls.rma_op_obj.create( + { + "code": "TEST2", + "name": "Operation 2", + "type": "customer", + "receipt_policy": "ordered", + "scrap_policy": "ordered", + "scrap_location_id": cls.scrap_loc.id, + "in_route_id": cls.rma_route_cust.id, + "out_route_id": cls.rma_route_cust.id, + } + ) + + def test_01_rma_scrap_received(self): + rma = self.rma_line_obj.create( + { + "partner_id": self.customer1.id, + "product_id": self.product_1.id, + "operation_id": self.operation_1.id, + "uom_id": self.product_1.uom_id.id, + "in_route_id": self.operation_1.in_route_id.id, + "out_route_id": self.operation_1.out_route_id.id, + "in_warehouse_id": self.operation_1.in_warehouse_id.id, + "out_warehouse_id": self.operation_1.out_warehouse_id.id, + "location_id": self.stock_rma_location.id, + } + ) + rma._onchange_operation_id() + rma.action_rma_to_approve() + wizard = self.rma_make_picking.with_context( + { + "active_ids": rma.id, + "active_model": "rma.order.line", + "picking_type": "incoming", + "active_id": 1, + } + ).create({}) + wizard._create_picking() + rma._compute_qty_to_scrap() + wizard = self.rma_make_scrap_wiz.with_context( + { + "active_ids": rma.id, + "active_model": "rma.order.line", + "item_ids": [ + 0, + 0, + { + "line_id": rma.id, + "product_id": rma.product_id.id, + "product_qty": rma.product_qty, + "location_id": rma.location_id, + "qty_to_scrap": rma.qty_to_scrap, + "uom_id": rma.uom_id.id, + }, + ], + } + ).create({}) + action = wizard.action_create_scrap() + scrap = self.env["stock.scrap"].browse([action["res_id"]]) + self.assertEqual(scrap.location_id.id, self.stock_rma_location.id) + self.assertEqual(scrap.move_id.id, False) + scrap.action_validate() + move = scrap.move_id + self.assertEqual(move.product_id.id, self.product_1.id) + + def test_02_rma_scrap_ordered(self): + rma = self.rma_line_obj.create( + { + "partner_id": self.customer1.id, + "product_id": self.product_1.id, + "operation_id": self.operation_2.id, + "uom_id": self.product_1.uom_id.id, + "in_route_id": self.operation_2.in_route_id.id, + "out_route_id": self.operation_2.out_route_id.id, + "in_warehouse_id": self.operation_2.in_warehouse_id.id, + "out_warehouse_id": self.operation_2.out_warehouse_id.id, + "location_id": self.stock_rma_location.id, + } + ) + rma._onchange_operation_id() + rma.action_rma_to_approve() + rma._compute_qty_to_scrap() + wizard = self.rma_make_scrap_wiz.with_context( + { + "active_ids": rma.id, + "active_model": "rma.order.line", + "item_ids": [ + 0, + 0, + { + "line_id": rma.id, + "product_id": rma.product_id.id, + "product_qty": rma.product_qty, + "location_id": rma.location_id, + "qty_to_scrap": rma.qty_to_scrap, + "uom_id": rma.uom_id.id, + }, + ], + } + ).create({}) + action = wizard.action_create_scrap() + scrap = self.env["stock.scrap"].browse([action["res_id"]]) + self.assertEqual(scrap.location_id.id, self.stock_rma_location.id) + self.assertEqual(scrap.move_id.id, False) + self.assertTrue(scrap.action_validate()) diff --git a/rma_scrap/views/rma_operation_view.xml b/rma_scrap/views/rma_operation_view.xml new file mode 100644 index 00000000..ad00dfd5 --- /dev/null +++ b/rma_scrap/views/rma_operation_view.xml @@ -0,0 +1,34 @@ + + + + + rma.operation.tree + rma.operation + + + + + + + + + + rma.operation.form - rma_scrap + rma.operation + + + + + + + + + + + + + + diff --git a/rma_scrap/views/rma_order_line_view.xml b/rma_scrap/views/rma_order_line_view.xml new file mode 100644 index 00000000..0d6c0505 --- /dev/null +++ b/rma_scrap/views/rma_order_line_view.xml @@ -0,0 +1,51 @@ + + + + + rma.order.line.form + rma.order.line + + + + + + + + + + + + + + + + + + + rma.order.line.select - rma_scrap + rma.order.line + + + + + + + + + + + diff --git a/rma_scrap/views/rma_order_view.xml b/rma_scrap/views/rma_order_view.xml new file mode 100644 index 00000000..0b6a59ab --- /dev/null +++ b/rma_scrap/views/rma_order_view.xml @@ -0,0 +1,25 @@ + + + + rma.order.form + rma.order + + + + + + + + + + diff --git a/rma_scrap/wizards/__init__.py b/rma_scrap/wizards/__init__.py new file mode 100644 index 00000000..6d7ef8ab --- /dev/null +++ b/rma_scrap/wizards/__init__.py @@ -0,0 +1 @@ +from . import rma_make_scrap diff --git a/rma_scrap/wizards/rma_make_scrap.py b/rma_scrap/wizards/rma_make_scrap.py new file mode 100644 index 00000000..f687d995 --- /dev/null +++ b/rma_scrap/wizards/rma_make_scrap.py @@ -0,0 +1,112 @@ +# Copyright 2022 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html). + + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class RmaMakeScrap(models.TransientModel): + _name = "rma_make_scrap.wizard" + _description = "Wizard to create scrap from rma lines" + + item_ids = fields.One2many( + comodel_name="rma_make_scrap_item.wizard", + inverse_name="wiz_id", + string="Items", + ) + + @api.returns("rma.order.line") + def _prepare_item(self, line): + values = { + "product_id": line.product_id.id, + "product_qty": line.product_qty, + "location_id": line.location_id.id, + "uom_id": line.uom_id.id, + "qty_to_scrap": line.qty_to_scrap, + "line_id": line.id, + "rma_id": line.rma_id and line.rma_id.id or False, + } + return values + + @api.model + def default_get(self, fields_list): + context = self._context.copy() + res = super(RmaMakeScrap, self).default_get(fields_list) + rma_line_obj = self.env["rma.order.line"] + rma_line_ids = self.env.context["active_ids"] or [] + active_model = self.env.context["active_model"] + + if not rma_line_ids: + return res + assert active_model == "rma.order.line", "Bad context propagation" + + items = [] + lines = rma_line_obj.browse(rma_line_ids) + for line in lines: + items.append([0, 0, self._prepare_item(line)]) + res["item_ids"] = items + context.update({"items_ids": items}) + return res + + def _create_scrap(self): + scraps = [] + for item in self.item_ids: + line = item.line_id + if line.state != "approved": + raise ValidationError(_("RMA %s is not approved") % line.name) + scrap = self._prepare_scrap(item) + scraps.append(scrap) + return scraps + + def action_create_scrap(self): + self._create_scrap() + self.item_ids[0].line_id._compute_qty_in_scrap() + return self.item_ids[0].line_id.action_view_scrap_transfers() + + @api.model + def _prepare_scrap(self, item): + line = item.line_id + scrap = self.env["stock.scrap"].create( + { + "name": line.rma_id.id and line.rma_id.name or line.name, + "origin": line.name, + "product_id": item.line_id.product_id.id, + "scrap_qty": item.qty_to_scrap, + "product_uom_id": item.line_id.product_id.product_tmpl_id.uom_id.id, + "scrap_location_id": line.operation_id.scrap_location_id.id, + "rma_line_id": line.id, + "create_date": fields.Datetime.now(), + "company_id": line.company_id.id, + "is_rma_scrap": True, + "location_id": line.location_id.id, + } + ) + return scrap + + +class RmaMakeScrapItem(models.TransientModel): + _name = "rma_make_scrap_item.wizard" + _description = "Items to Scrap" + + wiz_id = fields.Many2one("rma_make_scrap.wizard", string="Wizard", required=True) + line_id = fields.Many2one( + "rma.order.line", string="RMA order Line", ondelete="cascade" + ) + rma_id = fields.Many2one("rma.order", related="line_id.rma_id", string="RMA Group") + product_id = fields.Many2one("product.product", string="Product") + product_qty = fields.Float( + related="line_id.product_qty", + string="Quantity Ordered", + copy=False, + digits="Product Unit of Measure", + ) + location_id = fields.Many2one( + "stock.location", + string="Scrap Location", + domain="[('scrap_location', '=', True)]", + ) + qty_to_scrap = fields.Float( + string="Quantity To Scrap", digits="Product Unit of Measure" + ) + uom_id = fields.Many2one("uom.uom", string="Unit of Measure") diff --git a/rma_scrap/wizards/rma_scrap_view.xml b/rma_scrap/wizards/rma_scrap_view.xml new file mode 100644 index 00000000..2f7bfe89 --- /dev/null +++ b/rma_scrap/wizards/rma_scrap_view.xml @@ -0,0 +1,72 @@ + + + + Create Scrap + rma_make_scrap.wizard + +
+ + + + + + + + + + + + +
+
+ +
+
+ + + Create Scrap + ir.actions.act_window + rma_make_scrap.wizard + form + new + + + + + + + rma.order.line.form + rma.order.line + + +
+
+
+
+