From 5e71656ce4d17448cbdd57b786cbf22d2cf35148 Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Wed, 17 Mar 2021 18:01:17 +0100 Subject: [PATCH] [14.0][IMP] repair_stock_move: use standard reservation engine. * Reserve moves in the same way it is done in other entities (pickings, MO's...). * Also give flexibility by alowing to easily force availability. * Other minor changes. * Set module as alpha. --- repair_stock_move/README.rst | 92 ++++ repair_stock_move/__init__.py | 4 - repair_stock_move/__manifest__.py | 4 +- repair_stock_move/hooks.py | 23 - repair_stock_move/models/repair_line.py | 16 +- repair_stock_move/models/repair_order.py | 220 +++++---- repair_stock_move/models/stock_move.py | 1 + .../{README => readme}/CONTRIBUTORS.rst | 1 + .../{README => readme}/DESCRIPTION.rst | 2 +- .../{README => readme}/USAGE.rst | 1 - .../static/description/index.html | 438 ++++++++++++++++++ .../tests/test_repair_stock_move.py | 22 +- .../views/repair_order_views.xml | 22 +- 13 files changed, 677 insertions(+), 169 deletions(-) create mode 100644 repair_stock_move/README.rst delete mode 100644 repair_stock_move/hooks.py rename repair_stock_move/{README => readme}/CONTRIBUTORS.rst (53%) rename repair_stock_move/{README => readme}/DESCRIPTION.rst (100%) rename repair_stock_move/{README => readme}/USAGE.rst (97%) create mode 100644 repair_stock_move/static/description/index.html diff --git a/repair_stock_move/README.rst b/repair_stock_move/README.rst new file mode 100644 index 000000000..cc49782fd --- /dev/null +++ b/repair_stock_move/README.rst @@ -0,0 +1,92 @@ +================= +Repair Stock Move +================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fmanufacture-lightgray.png?logo=github + :target: https://github.com/OCA/manufacture/tree/14.0/repair_stock_move + :alt: OCA/manufacture +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/manufacture-14-0/manufacture-14-0-repair_stock_move + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/129/14.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +The purpose of this module is to modify the behaviour of the repair standard module. Achieving more flexibility in a repair process. + +The first change that it applies is the modification of the creation of stock moves in the repair flow: + +* Confirm Repair: creates draft stock moves on confirmation of the repair order. +* Start Repair: confirms the stock moves. +* End Repair: completes the stock moves and ends the repair order. + +Another feature which this module includes is that it allows to add components during all the different stages of the repair process, which adjusts better to the needs of some businesses. + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Follow the Odoo standard repair module flow. + +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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* ForgeFlow + +Contributors +~~~~~~~~~~~~ + +* Mateu Griful +* Lois Rilo + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/manufacture `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/repair_stock_move/__init__.py b/repair_stock_move/__init__.py index 0a185fc16..0650744f6 100644 --- a/repair_stock_move/__init__.py +++ b/repair_stock_move/__init__.py @@ -1,5 +1 @@ -# Copyright (C) 2017-20 ForgeFlow S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - from . import models -from .hooks import post_load_hook diff --git a/repair_stock_move/__manifest__.py b/repair_stock_move/__manifest__.py index ed2dd9e5d..0a8ae65d4 100644 --- a/repair_stock_move/__manifest__.py +++ b/repair_stock_move/__manifest__.py @@ -4,8 +4,9 @@ { "name": "Repair Stock Move", "version": "14.0.1.0.0", + "development_status": "Alpha", "license": "LGPL-3", - "category": "RMA", + "category": "Repair", "summary": "Ongoing Repair Stock Moves Definition in odoo", "author": "ForgeFlow, Odoo Community Association (OCA)", "website": "https://github.com/OCA/manufacture", @@ -13,7 +14,6 @@ "data": [ "views/repair_order_views.xml", ], - "post_load": "post_load_hook", "installable": True, "application": False, } diff --git a/repair_stock_move/hooks.py b/repair_stock_move/hooks.py deleted file mode 100644 index ec18663e0..000000000 --- a/repair_stock_move/hooks.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2021 ForgeFlow, S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). - -from odoo.addons.repair.models.repair import Repair - - -# flake8: noqa: C901 -def post_load_hook(): - def action_repair_end_new(self): - self.write({"repaired": True}) - self.move_id._action_assign() - self.move_id._action_done() - for operation in self.operations: - operation.move_id._action_assign() - operation.move_id._action_done() - vals = {"state": "done"} - if not self.invoice_id and self.invoice_method == "after_repair": - vals["state"] = "2binvoiced" - self.write(vals) - - if not hasattr(Repair, "action_repair_end_original"): - Repair.action_repair_end_original = Repair.action_repair_end - Repair.action_repair_end = action_repair_end_new diff --git a/repair_stock_move/models/repair_line.py b/repair_stock_move/models/repair_line.py index e21f1febb..02f6bc053 100644 --- a/repair_stock_move/models/repair_line.py +++ b/repair_stock_move/models/repair_line.py @@ -24,6 +24,7 @@ class RepairLine(models.Model): "location_id": self.location_id.id, "location_dest_id": self.location_dest_id.id, "repair_id": self.repair_id.id, + "repair_line_id": self.id, "origin": self.repair_id.name, "company_id": self.company_id.id, } @@ -35,16 +36,19 @@ class RepairLine(models.Model): res = super().create(vals) if res and res.repair_id.state == "confirmed": move = res.create_stock_move() + move._action_confirm() res.move_id = move - move._set_quantity_done(res.product_uom_qty) if res and res.repair_id.state == "under_repair": move = res.create_stock_move() move._action_confirm() - move._set_quantity_done(res.product_uom_qty) + move._action_assign() res.move_id = move return res - def unlink(self): - for rec in self: - rec.move_id.unlink() - return super().unlink() + @api.onchange("product_id") + def _onchange_location(self): + if self.state == "draft": + self.location_id = self.repair_id.location_id + + # TODO: write qty - update stock move. + # TODO: default repair location in repair lines. diff --git a/repair_stock_move/models/repair_order.py b/repair_stock_move/models/repair_order.py index a73683723..aaabfde46 100644 --- a/repair_stock_move/models/repair_order.py +++ b/repair_stock_move/models/repair_order.py @@ -1,8 +1,8 @@ # Copyright (C) 2021 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from odoo import _, fields, models -from odoo.exceptions import ValidationError +from odoo import _, api, fields, models +from odoo.exceptions import UserError from odoo.tools import float_compare @@ -13,12 +13,14 @@ class RepairOrder(models.Model): comodel_name="stock.move", inverse_name="repair_id", ) + show_check_availability = fields.Boolean( + compute="_compute_show_check_availability", + help="Technical field used to compute whether the button " + "'Check Availability' should be displayed.", + ) + ignore_availability = fields.Boolean() + # Make "Parts" editable in more states. operations = fields.One2many( - comodel_name="repair.line", - inverse_name="repair_id", - string="Parts", - copy=True, - readonly=True, states={ "draft": [("readonly", False)], "confirmed": [("readonly", False)], @@ -26,27 +28,7 @@ class RepairOrder(models.Model): "ready": [("readonly", False)], }, ) - - product_qty = fields.Float( - "Product Quantity", - default=1.0, - digits="Product Unit of Measure", - readonly=True, - required=True, - states={ - "draft": [("readonly", False)], - "confirmed": [("readonly", False)], - "under_repair": [("readonly", False)], - "ready": [("readonly", False)], - }, - ) - fees_lines = fields.One2many( - comodel_name="repair.fee", - inverse_name="repair_id", - string="Operations", - copy=True, - readonly=True, states={ "draft": [("readonly", False)], "confirmed": [("readonly", False)], @@ -55,40 +37,76 @@ class RepairOrder(models.Model): }, ) - def action_validate(self): - res = super().action_validate() - self._check_company() - self.operations._check_company() - self.fees_lines._check_company() - res = {} - precision = self.env["decimal.precision"].precision_get( - "Product Unit of Measure" - ) - Move = self.env["stock.move"] - for repair in self: - # Try to create move with the appropriate owner - owner_id = False - available_qty_owner = self.env["stock.quant"]._get_available_quantity( - repair.product_id, - repair.location_id, - repair.lot_id, - strict=True, + @api.depends("state") + def _compute_show_check_availability(self): + for rec in self: + rec.show_check_availability = ( + any( + move.state in ("waiting", "confirmed", "partially_available") + and float_compare( + move.product_uom_qty, + 0, + precision_rounding=move.product_uom.rounding, + ) + for move in rec.stock_move_ids + ) + and not rec.ignore_availability ) - if available_qty_owner <= 0.0: - raise ValidationError( - _("There is no stock of product: ") + repair.product_id.display_name - ) - if ( - float_compare( - available_qty_owner, repair.product_qty, precision_digits=precision - ) - >= 0 - ): - owner_id = repair.partner_id.id + def _create_repair_stock_move(self): + self.ensure_one() + return self.env["stock.move"].create( + { + "name": self.name, + "product_id": self.product_id.id, + "product_uom": self.product_uom.id or self.product_id.uom_id.id, + "product_uom_qty": self.product_qty, + "partner_id": self.address_id.id, + "location_id": self.location_id.id, + "location_dest_id": self.location_id.id, + "repair_id": self.id, + "origin": self.name, + "company_id": self.company_id.id, + } + ) + + def action_repair_confirm(self): + res = super().action_repair_confirm() + for repair in self: moves = self.env["stock.move"] for operation in repair.operations: move = operation.create_stock_move() + moves |= move + operation.write({"move_id": move.id}) + move = repair._create_repair_stock_move() + repair.move_id = move + self.mapped("stock_move_ids")._action_confirm() + return res + + def action_assign(self): + self.filtered(lambda r: r.state == "draft").action_repair_start() + moves = self.mapped("stock_move_ids") + moves = moves.filtered( + lambda move: move.state not in ("draft", "cancel", "done") + ) + if not moves: + raise UserError(_("Nothing to check the availability for.")) + moves._action_assign() + return True + + def action_repair_start(self): + res = super().action_repair_start() + self.mapped("stock_move_ids")._action_assign() + return res + + def action_force_availability(self): + self.write({"ignore_availability": True}) + + def _force_qty_done_in_repair_lines(self): + for operation in self.mapped("operations"): + for move in operation.stock_move_ids: + if move.state not in ["confirmed", "waiting", "partially_available"]: + continue product_qty = move.product_uom._compute_quantity( operation.product_uom_qty, move.product_id.uom_id, @@ -101,69 +119,19 @@ class RepairOrder(models.Model): strict=False, ) move._update_reserved_quantity( - product_qty, + product_qty - move.reserved_availability, available_quantity, move.location_id, lot_id=operation.lot_id, strict=False, ) move._set_quantity_done(operation.product_uom_qty) - if operation.lot_id: move.move_line_ids.lot_id = operation.lot_id - moves |= move - operation.write({"move_id": move.id, "state": "draft"}) - move = Move.create( - { - "name": repair.name, - "product_id": repair.product_id.id, - "product_uom": repair.product_uom.id or repair.product_id.uom_id.id, - "product_uom_qty": repair.product_qty, - "partner_id": repair.address_id.id, - "location_id": repair.location_id.id, - "location_dest_id": repair.location_id.id, - "move_line_ids": [ - ( - 0, - 0, - { - "product_id": repair.product_id.id, - "lot_id": repair.lot_id.id, - "product_uom_qty": 0, # bypass reservation here - "product_uom_id": repair.product_uom.id - or repair.product_id.uom_id.id, - "qty_done": repair.product_qty, - "package_id": False, - "result_package_id": False, - "owner_id": owner_id, - "location_id": repair.location_id.id, # TODO:ownerstuff - "company_id": repair.company_id.id, - "location_dest_id": repair.location_id.id, - }, - ) - ], - "repair_id": repair.id, - "origin": repair.name, - "company_id": repair.company_id.id, - } - ) - consumed_lines = moves.mapped("move_line_ids") - produced_lines = move.move_line_ids - moves |= move - produced_lines.write({"consume_line_ids": [(6, 0, consumed_lines.ids)]}) - res[repair.id] = move.id - repair.move_id = move - return res - - def action_repair_start(self): - super().action_repair_start() - (self.move_id | self.operations.mapped("move_id"))._action_confirm() - def action_open_stock_moves(self): self.ensure_one() - stock_move_ids = self.move_id.ids + self.operations.move_id.ids - domain = [("id", "in", stock_move_ids)] + domain = [("id", "in", self.mapped("stock_move_ids").ids)] action = { "name": _("Stock Moves"), "view_type": "tree", @@ -176,9 +144,33 @@ class RepairOrder(models.Model): return action def action_repair_cancel(self): - if self.move_id.state != "draft" or self.operations: - raise ValidationError( - _("Unable to cancel repair order due to already generated stock moves.") - ) - else: - super().action_repair_cancel() + self.mapped("stock_move_ids")._action_cancel() + return super().action_repair_cancel() + + def action_repair_end(self): + if any(r.show_check_availability for r in self): + raise UserError(_("Some related stock moves are not available.")) + # I can not everything has been reserved. + self._force_qty_done_in_repair_lines() + for repair in self: + operation_moves = repair.mapped("operations.move_id") + if operation_moves: + consumed_lines = operation_moves.mapped("move_line_ids") + produced_lines = repair.move_id.move_line_ids + operation_moves |= repair.move_id + produced_lines.write({"consume_line_ids": [(6, 0, consumed_lines.ids)]}) + + self.move_id._set_quantity_done(self.move_id.product_uom_qty) + self.move_id._action_done() + for move in self.mapped("operations.move_id"): + move._set_quantity_done(move.product_uom_qty) + move._action_done() + return super().action_repair_end() + + def action_repair_done(self): + self.ensure_one() + if self.stock_move_ids: + # With this module this should always be the case, so this is + # effectively overriding the method. + return {self.id: self.move_id.id} + return super().action_repair_done() diff --git a/repair_stock_move/models/stock_move.py b/repair_stock_move/models/stock_move.py index 88f6f3e9f..bd08333ab 100644 --- a/repair_stock_move/models/stock_move.py +++ b/repair_stock_move/models/stock_move.py @@ -10,4 +10,5 @@ class StockMove(models.Model): repair_line_id = fields.Many2one( comodel_name="repair.line", string="Repair Line", + ondelete="cascade", ) diff --git a/repair_stock_move/README/CONTRIBUTORS.rst b/repair_stock_move/readme/CONTRIBUTORS.rst similarity index 53% rename from repair_stock_move/README/CONTRIBUTORS.rst rename to repair_stock_move/readme/CONTRIBUTORS.rst index d9a0f8120..087dd2923 100644 --- a/repair_stock_move/README/CONTRIBUTORS.rst +++ b/repair_stock_move/readme/CONTRIBUTORS.rst @@ -1 +1,2 @@ * Mateu Griful +* Lois Rilo diff --git a/repair_stock_move/README/DESCRIPTION.rst b/repair_stock_move/readme/DESCRIPTION.rst similarity index 100% rename from repair_stock_move/README/DESCRIPTION.rst rename to repair_stock_move/readme/DESCRIPTION.rst index cd1fccfba..f46cb2408 100644 --- a/repair_stock_move/README/DESCRIPTION.rst +++ b/repair_stock_move/readme/DESCRIPTION.rst @@ -1,9 +1,9 @@ The purpose of this module is to modify the behaviour of the repair standard module. Achieving more flexibility in a repair process. The first change that it applies is the modification of the creation of stock moves in the repair flow: + * Confirm Repair: creates draft stock moves on confirmation of the repair order. * Start Repair: confirms the stock moves. * End Repair: completes the stock moves and ends the repair order. Another feature which this module includes is that it allows to add components during all the different stages of the repair process, which adjusts better to the needs of some businesses. - diff --git a/repair_stock_move/README/USAGE.rst b/repair_stock_move/readme/USAGE.rst similarity index 97% rename from repair_stock_move/README/USAGE.rst rename to repair_stock_move/readme/USAGE.rst index 6a28bb3e0..3009b22a1 100644 --- a/repair_stock_move/README/USAGE.rst +++ b/repair_stock_move/readme/USAGE.rst @@ -1,2 +1 @@ Follow the Odoo standard repair module flow. - diff --git a/repair_stock_move/static/description/index.html b/repair_stock_move/static/description/index.html new file mode 100644 index 000000000..999f4399a --- /dev/null +++ b/repair_stock_move/static/description/index.html @@ -0,0 +1,438 @@ + + + + + + +Repair Stock Move + + + +
+

Repair Stock Move

+ + +

Alpha License: LGPL-3 OCA/manufacture Translate me on Weblate Try me on Runbot

+

The purpose of this module is to modify the behaviour of the repair standard module. Achieving more flexibility in a repair process.

+

The first change that it applies is the modification of the creation of stock moves in the repair flow:

+
    +
  • Confirm Repair: creates draft stock moves on confirmation of the repair order.
  • +
  • Start Repair: confirms the stock moves.
  • +
  • End Repair: completes the stock moves and ends the repair order.
  • +
+

Another feature which this module includes is that it allows to add components during all the different stages of the repair process, which adjusts better to the needs of some businesses.

+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

Table of contents

+ +
+

Usage

+

Follow the Odoo standard repair module flow.

+
+
+

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.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • ForgeFlow
  • +
+
+ +
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/manufacture project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/repair_stock_move/tests/test_repair_stock_move.py b/repair_stock_move/tests/test_repair_stock_move.py index 4d0ab8d53..df365458c 100644 --- a/repair_stock_move/tests/test_repair_stock_move.py +++ b/repair_stock_move/tests/test_repair_stock_move.py @@ -55,6 +55,7 @@ class TestRepairStockMove(common.SavepointCase): ) # Repair Orders + dest_loc_id = cls.product_1.property_stock_production.id cls.repair1 = cls.env["repair.order"].create( { "address_id": cls.res_partner_address_1.id, @@ -70,9 +71,9 @@ class TestRepairStockMove(common.SavepointCase): 0, 0, { - "location_dest_id": cls.product_1.property_stock_production.id, + "location_dest_id": dest_loc_id, "location_id": cls.stock_location_14.id, - "name": cls.product_1.get_product_multiline_description_sale(), + "name": cls.product_1.display_name, "product_id": cls.product_2.id, "product_uom": cls.env.ref("uom.product_uom_unit").id, "product_uom_qty": 1.0, @@ -88,7 +89,7 @@ class TestRepairStockMove(common.SavepointCase): 0, 0, { - "name": cls.service.get_product_multiline_description_sale(), + "name": cls.service.display_name, "product_id": cls.service.id, "product_uom_qty": 1.0, "product_uom": cls.env.ref("uom.product_uom_unit").id, @@ -106,19 +107,6 @@ class TestRepairStockMove(common.SavepointCase): def test_stock_move_state(self): # Validate Repair Order self.repair1.action_validate() - self.assertEqual( - self.repair1.move_id.state, - "draft", - "Generated stock move state should be draft", - ) - for operation in self.repair1.operations: - self.assertEqual( - operation.move_id.state, - "draft", - "Generated stock move state should be draft", - ) - # Start Repair - self.repair1.action_repair_start() self.assertEqual( self.repair1.move_id.state, "confirmed", @@ -130,6 +118,8 @@ class TestRepairStockMove(common.SavepointCase): "confirmed", "Generated stock move state should be confirmed", ) + # Start Repair + self.repair1.action_repair_start() # End Repair self.repair1.action_repair_end() self.assertEqual( diff --git a/repair_stock_move/views/repair_order_views.xml b/repair_stock_move/views/repair_order_views.xml index 303ccb7a6..50c79df5b 100644 --- a/repair_stock_move/views/repair_order_views.xml +++ b/repair_stock_move/views/repair_order_views.xml @@ -6,8 +6,26 @@ repair.order - - +
+
+ +