From 315ca029b8d59677abc3e0a00ed9df2074b5ea2f Mon Sep 17 00:00:00 2001 From: AaronHForgeFlow Date: Thu, 1 Aug 2024 17:55:17 +0200 Subject: [PATCH] [ADD] rma_repair_put_away: glue module between rma_repair & rma_put_away When not using rma_put_away you can define push rules anyway to move the products to the repair location, and those transfers count as rma repair transfers if you install and use rma_put_away then the rma repair transfers are the ones from the putaway moves Before this commit there is a dependency issue because the rma_repair code is using a field declared in the rma_put_away, this commit fixes that issue [IMP] rma_repair_put_away: added tests --- rma_repair/models/rma_order.py | 2 +- .../wizards/rma_order_line_make_repair.py | 6 +- rma_repair_put_away/README.rst | 31 ++++ rma_repair_put_away/__init__.py | 2 + rma_repair_put_away/__manifest__.py | 14 ++ rma_repair_put_away/models/__init__.py | 2 + rma_repair_put_away/models/rma_order.py | 31 ++++ rma_repair_put_away/models/rma_order_line.py | 33 ++++ rma_repair_put_away/tests/__init__.py | 1 + .../tests/test_rma_repair_put_away.py | 144 ++++++++++++++++++ rma_repair_put_away/wizards/__init__.py | 1 + .../wizards/rma_order_line_make_repair.py | 14 ++ .../odoo/addons/rma_repair_put_away | 1 + setup/rma_repair_put_away/setup.py | 6 + 14 files changed, 286 insertions(+), 2 deletions(-) create mode 100644 rma_repair_put_away/README.rst create mode 100644 rma_repair_put_away/__init__.py create mode 100644 rma_repair_put_away/__manifest__.py create mode 100644 rma_repair_put_away/models/__init__.py create mode 100644 rma_repair_put_away/models/rma_order.py create mode 100644 rma_repair_put_away/models/rma_order_line.py create mode 100644 rma_repair_put_away/tests/__init__.py create mode 100644 rma_repair_put_away/tests/test_rma_repair_put_away.py create mode 100644 rma_repair_put_away/wizards/__init__.py create mode 100644 rma_repair_put_away/wizards/rma_order_line_make_repair.py create mode 120000 setup/rma_repair_put_away/odoo/addons/rma_repair_put_away create mode 100644 setup/rma_repair_put_away/setup.py diff --git a/rma_repair/models/rma_order.py b/rma_repair/models/rma_order.py index 1f0cb9510..9cfbe46e9 100644 --- a/rma_repair/models/rma_order.py +++ b/rma_repair/models/rma_order.py @@ -16,7 +16,7 @@ def _compute_repair_transfer_count(self): for order in self: pickings = ( order.mapped("rma_line_ids.move_ids") - .filtered(lambda m: m.is_rma_put_away) + .filtered(lambda m: m.is_rma_repair_transfer) .mapped("picking_id") ) order.repair_transfer_count = len(pickings) diff --git a/rma_repair/wizards/rma_order_line_make_repair.py b/rma_repair/wizards/rma_order_line_make_repair.py index 8905f1865..363293a1c 100644 --- a/rma_repair/wizards/rma_order_line_make_repair.py +++ b/rma_repair/wizards/rma_order_line_make_repair.py @@ -49,6 +49,9 @@ def default_get(self, fields_list): res["item_ids"] = items return res + def create_repair_procurement_condition_applies(self, rma_line, repair): + return rma_line.location_id != repair.location_id + def make_repair_order(self): self.ensure_one() res = [] @@ -58,10 +61,11 @@ def make_repair_order(self): data = item._prepare_repair_order(rma_line) repair = repair_obj.create(data) res.append(repair.id) - if rma_line.location_id != repair.location_id: + if self.create_repair_procurement_condition_applies(rma_line, repair): item._run_procurement( rma_line.operation_id.repair_route_id, repair.location_id ) + return { "domain": [("id", "in", res)], "name": _("Repairs"), diff --git a/rma_repair_put_away/README.rst b/rma_repair_put_away/README.rst new file mode 100644 index 000000000..53fae7583 --- /dev/null +++ b/rma_repair_put_away/README.rst @@ -0,0 +1,31 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :alt: License LGPL-3 + +=================== +RMA Repair Put Away +=================== + +Glue module between rma_repair & rma_put_away + +When not using rma_put_away you can define push rules anyway to move the products +to the repair location, and those transfers count as rma repair transfers + +If you install and use rma_put_away then the rma repair transfers are the ones +from the putaway moves + + +Credits +======= + +Contributors +------------ + +* Jordi Ballester Alomar +* David Jimenez +* Aaron Henriquez + + +Maintainer +---------- + +This module is maintained by ForgeFlow diff --git a/rma_repair_put_away/__init__.py b/rma_repair_put_away/__init__.py new file mode 100644 index 000000000..aee8895e7 --- /dev/null +++ b/rma_repair_put_away/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/rma_repair_put_away/__manifest__.py b/rma_repair_put_away/__manifest__.py new file mode 100644 index 000000000..2c7cf258e --- /dev/null +++ b/rma_repair_put_away/__manifest__.py @@ -0,0 +1,14 @@ +# Copyright 2024 ForgeFlow S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "RMA Repair Put Away", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "category": "RMA", + "summary": "RMA repairs with Put away", + "author": "ForgeFlow", + "website": "https://github.com/ForgeFlow/stock-rma", + "depends": ["rma_repair", "rma_put_away"], + "installable": True, + "auto_install": True, +} diff --git a/rma_repair_put_away/models/__init__.py b/rma_repair_put_away/models/__init__.py new file mode 100644 index 000000000..1bbd239db --- /dev/null +++ b/rma_repair_put_away/models/__init__.py @@ -0,0 +1,2 @@ +from . import rma_order +from . import rma_order_line diff --git a/rma_repair_put_away/models/rma_order.py b/rma_repair_put_away/models/rma_order.py new file mode 100644 index 000000000..fd7583ef6 --- /dev/null +++ b/rma_repair_put_away/models/rma_order.py @@ -0,0 +1,31 @@ +# Copyright 2024 ForgeFlow S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class RmaOrder(models.Model): + _inherit = "rma.order" + + def _compute_repair_transfer_count(self): + res = super()._compute_repair_transfer_count() + for order in self: + pickings = ( + order.mapped("rma_line_ids.move_ids") + .filtered(lambda m: m.is_rma_put_away) + .mapped("picking_id") + ) + order.repair_transfer_count = len(pickings) + return res + + def action_view_repair_transfers(self): + super()._compute_repair_transfer_count() + self.ensure_one() + action = self.env.ref("stock.action_picking_tree_all") + result = action.sudo().read()[0] + pickings = self.env["stock.picking"] + for line in self.rma_line_ids: + pickings |= line.move_ids.filtered(lambda m: m.is_rma_put_away).mapped( + "picking_id" + ) + return self._view_shipments(result, pickings) diff --git a/rma_repair_put_away/models/rma_order_line.py b/rma_repair_put_away/models/rma_order_line.py new file mode 100644 index 000000000..500bc0558 --- /dev/null +++ b/rma_repair_put_away/models/rma_order_line.py @@ -0,0 +1,33 @@ +# Copyright 2024 ForgeFlow S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class RmaOrderLine(models.Model): + _inherit = "rma.order.line" + + def _compute_repair_transfer_count(self): + for line in self: + pickings = line.move_ids.filtered(lambda m: m.is_rma_put_away).mapped( + "picking_id" + ) + line.repair_transfer_count = len(pickings) + + def action_view_repair_transfers(self): + super().action_view_repair_transfers() + action = self.env.ref("stock.action_picking_tree_all") + result = action.sudo().read()[0] + pickings = self.env["stock.picking"] + for line in self: + pickings |= line.move_ids.filtered(lambda m: m.is_rma_put_away).mapped( + "picking_id" + ) + # choose the view_mode accordingly + if len(pickings) != 1: + result["domain"] = "[('id', 'in', " + str(pickings.ids) + ")]" + elif len(pickings) == 1: + res = self.env.ref("stock.view_picking_form", False) + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = pickings.ids[0] + return result diff --git a/rma_repair_put_away/tests/__init__.py b/rma_repair_put_away/tests/__init__.py new file mode 100644 index 000000000..667738966 --- /dev/null +++ b/rma_repair_put_away/tests/__init__.py @@ -0,0 +1 @@ +from . import test_rma_repair_put_away diff --git a/rma_repair_put_away/tests/test_rma_repair_put_away.py b/rma_repair_put_away/tests/test_rma_repair_put_away.py new file mode 100644 index 000000000..965790050 --- /dev/null +++ b/rma_repair_put_away/tests/test_rma_repair_put_away.py @@ -0,0 +1,144 @@ +# Copyright 2024 ForgeFlow S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo.tests import common + + +class TestRmaRepairPutAway(common.SingleTransactionCase): + @classmethod + def setUpClass(cls): + super(TestRmaRepairPutAway, cls).setUpClass() + + cls.rma_obj = cls.env["rma.order"] + cls.rma_make_picking = cls.env["rma_make_picking.wizard"] + cls.rma_line_obj = cls.env["rma.order.line"] + cls.rma_op_obj = cls.env["rma.operation"] + cls.rma_make_put_away_wiz = cls.env["rma_make_put_away.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.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.put_away_loc = cls.env["stock.location"].create( + { + "name": "WH Repair Location", + "location_id": cls.wh.view_location_id.id, + } + ) + # define the push rule for the putaway + cls.repair_route = cls.env["stock.route"].create( + { + "name": "Transfer RMA to Repair", + "rma_selectable": True, + "sequence": 10, + } + ) + cls.env["stock.rule"].create( + { + "name": "Transfer", + "route_id": cls.repair_route.id, + "location_src_id": cls.stock_rma_location.id, + "location_dest_id": cls.put_away_loc.id, + "action": "pull", + "picking_type_id": cls.wh.int_type_id.id, + "warehouse_id": cls.wh.id, + "procure_method": "make_to_stock", + } + ) + + cls.rma_group = cls.rma_obj.create({"partner_id": cls.customer1.id}) + + cls.operation_1 = cls.rma_op_obj.create( + { + "code": "TEST", + "name": "Repair afer receive", + "type": "customer", + "receipt_policy": "ordered", + "repair_type": "received", + "put_away_policy": "received", + "in_route_id": cls.rma_route_cust.id, + "out_route_id": cls.rma_route_cust.id, + "repair_location_id": cls.stock_rma_location.id, + "repair_route_id": cls.repair_route.id, + "put_away_route_id": cls.repair_route.id, + "put_away_location_id": cls.put_away_loc.id, + } + ) + + def test_01_rma_repair_put_away(self): + """Check the putaway repair transfers are seen and counted + in the RMA""" + 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() + wizard = self.rma_make_put_away_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": self.put_away_loc.id, + "qty_to_put_away": rma.qty_to_put_away, + "uom_id": rma.uom_id.id, + }, + ], + } + ).create({}) + action = wizard.action_create_put_away() + picking_id = action["res_id"] + action_view_repair = rma.action_view_repair_transfers() + self.assertEqual(action_view_repair["res_id"], picking_id) + self.assertEqual(rma.repair_transfer_count, 1) diff --git a/rma_repair_put_away/wizards/__init__.py b/rma_repair_put_away/wizards/__init__.py new file mode 100644 index 000000000..5ca2b8133 --- /dev/null +++ b/rma_repair_put_away/wizards/__init__.py @@ -0,0 +1 @@ +from . import rma_order_line_make_repair diff --git a/rma_repair_put_away/wizards/rma_order_line_make_repair.py b/rma_repair_put_away/wizards/rma_order_line_make_repair.py new file mode 100644 index 000000000..91ad9379d --- /dev/null +++ b/rma_repair_put_away/wizards/rma_order_line_make_repair.py @@ -0,0 +1,14 @@ +# Copyright 2024 ForgeFlow S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class RmaLineMakeRepair(models.TransientModel): + _inherit = "rma.order.line.make.repair" + + def create_repair_procurement_condition_applies(self, rma_line, repair): + res = super().create_repair_procurement_condition_applies(rma_line, repair) + if rma_line.operation_id.put_away_location_id: + return rma_line.operation_id.put_away_location_id != repair.location_id + return res diff --git a/setup/rma_repair_put_away/odoo/addons/rma_repair_put_away b/setup/rma_repair_put_away/odoo/addons/rma_repair_put_away new file mode 120000 index 000000000..5dbd93521 --- /dev/null +++ b/setup/rma_repair_put_away/odoo/addons/rma_repair_put_away @@ -0,0 +1 @@ +../../../../rma_repair_put_away \ No newline at end of file diff --git a/setup/rma_repair_put_away/setup.py b/setup/rma_repair_put_away/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/rma_repair_put_away/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)