From f9e092d510342ff7441e745094a6bff6c47853df Mon Sep 17 00:00:00 2001 From: andrea Date: Mon, 22 Apr 2024 09:54:31 +0200 Subject: [PATCH] [17.0][MIG] stock_reserve_sale: migration to V17 --- stock_reserve_sale/README.rst | 2 +- stock_reserve_sale/__manifest__.py | 2 +- stock_reserve_sale/model/sale.py | 49 ++++++------------- stock_reserve_sale/model/sale_order_line.py | 43 +++++++--------- stock_reserve_sale/model/stock_reserve.py | 13 ++--- .../static/description/index.html | 2 +- stock_reserve_sale/view/sale.xml | 36 ++++++-------- .../wizard/sale_stock_reserve.py | 27 +++++----- 8 files changed, 66 insertions(+), 108 deletions(-) diff --git a/stock_reserve_sale/README.rst b/stock_reserve_sale/README.rst index b9debbb7d997..e9e8ac1196cb 100644 --- a/stock_reserve_sale/README.rst +++ b/stock_reserve_sale/README.rst @@ -7,7 +7,7 @@ Stock Reserve Sales !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:c8bff29850116b499cd76c5813113489be840f32653162635c18d9a691dbf78e + !! source digest: sha256:0252821802e05031e45ee21a476cc66bcbac1af5de9e9d01fe240cd460e49ea2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/stock_reserve_sale/__manifest__.py b/stock_reserve_sale/__manifest__.py index df87f5059b81..b9aa86c67da1 100644 --- a/stock_reserve_sale/__manifest__.py +++ b/stock_reserve_sale/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). { "name": "Stock Reserve Sales", - "version": "16.0.1.0.0", + "version": "17.0.1.0.0", "author": "Camptocamp, Odoo Community Association (OCA)", "category": "Warehouse", "license": "AGPL-3", diff --git a/stock_reserve_sale/model/sale.py b/stock_reserve_sale/model/sale.py index 403cb9dcab3a..a6301aa61dd4 100644 --- a/stock_reserve_sale/model/sale.py +++ b/stock_reserve_sale/model/sale.py @@ -2,7 +2,6 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from odoo import api, fields, models from odoo.exceptions import UserError -from odoo.osv import expression from odoo.tools.translate import _ _LINE_KEYS = ["product_id", "product_uom_qty"] @@ -31,50 +30,34 @@ def _compute_stock_reservation(self): has_stock_reservation = fields.Boolean( compute="_compute_stock_reservation", readonly=True, - multi="stock_reservation", store=True, string="Has Stock Reservations", ) is_stock_reservable = fields.Boolean( compute="_compute_stock_reservation", readonly=True, - multi="stock_reservation", store=True, string="Can Have Stock Reservations", ) reserves_count = fields.Integer(compute="_compute_reserves_count") - all_lines_reserved = fields.Boolean( - compute="_compute_reserves_count", store=True, default=False - ) + all_lines_reserved = fields.Boolean(compute="_compute_reserves_count", store=False) def release_all_stock_reservation(self): - line_ids = [line.id for order in self for line in order.order_line] - lines = self.order_line.browse(line_ids) + lines = self.mapped("order_line") lines.release_stock_reservation() return True def _compute_reserves_count(self): - reserve_ids = self.env["stock.reservation"]._read_group( - domain=expression.AND( - [ - [("sale_id", "in", self.ids)], - ] - ), - fields=["sale_id"], - groupby=["sale_id"], - ) - lines = self.order_line.filtered( - lambda l: l.product_id.detailed_type != "service" + reserves = self.env["stock.reservation"].search( + [("sale_id", "in", self.ids)], ) for order in self: - if reserve_ids: - order.reserves_count = reserve_ids[0]["sale_id_count"] - else: - order.reserves_count = 0 - if order.reserves_count == len(lines): - order.all_lines_reserved = True - else: - order.all_lines_reserved = False + lines = order.order_line.filtered( + lambda ln: ln.product_id.detailed_type != "service" + ) + reserves_count = len(reserves.filtered(lambda rsv, order: rsv.sale_id == order)) + order.reserves_count = reserves_count + order.all_lines_reserved = bool(reserves_count == len(lines)) def action_view_reserves_products(self): action = self.env["ir.actions.act_window"]._for_xml_id( @@ -85,14 +68,11 @@ def action_view_reserves_products(self): return action def action_view_reserves_stock_picking(self): - stock_picking = "" action = self.env["ir.actions.actions"]._for_xml_id( "stock.action_picking_tree_all" ) - stock_picking = ( - self.env["stock.picking"] - .search([("origin", "=", self.name)]) - .filtered(lambda a: a.state not in "cancel") + stock_picking = self.env["stock.picking"].search( + [("origin", "=", self.name), ("state", "!=", "cancel")], limit=1 ) if stock_picking: view_id = self.env.ref("stock.view_picking_form").id @@ -133,7 +113,7 @@ def get_message(self, old_vals, new_vals): old_product = old_vals["product_id"].display_name new_product = ProductProduct.browse(new_vals["product_id"]).display_name body += _("
Product: ") - body += "{} → {}
".format(old_product, new_product) + body += f"{old_product} → {new_product}" if "product_uom_qty" in new_vals: if "product_id" not in new_vals: body += _("
Product: %s") % ( @@ -152,9 +132,8 @@ def unlink(self): if order.has_stock_reservation: raise UserError( _( - "Sale Order %s has some reserved lines.\n" + f"Sale Order {order.name} has some reserved lines.\n" "Please unreserve this lines before delete the order." ) - % (order.name) ) return super().unlink() diff --git a/stock_reserve_sale/model/sale_order_line.py b/stock_reserve_sale/model/sale_order_line.py index 01de402cfb60..8072e5c68626 100644 --- a/stock_reserve_sale/model/sale_order_line.py +++ b/stock_reserve_sale/model/sale_order_line.py @@ -2,13 +2,21 @@ # Copyright 2023 - Hugo Córdoba - FactorLibre - (hugo.cordoba@factorlibre.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from odoo import api, fields, models -from odoo.exceptions import UserError, except_orm +from odoo.exceptions import UserError from odoo.tools.translate import _ class SaleOrderLine(models.Model): _inherit = "sale.order.line" + reservation_ids = fields.One2many( + "stock.reservation", "sale_line_id", string="Stock Reservation", copy=False + ) + is_stock_reservable = fields.Boolean( + compute="_compute_is_stock_reservable", readonly=True, string="Can be reserved" + ) + is_readonly = fields.Boolean(compute="_compute_is_readonly", store=False) + def _get_line_rule(self): """Get applicable rule for this product Reproduce get suitable rule from procurement @@ -16,9 +24,7 @@ def _get_line_rule(self): """ StockRule = self.env["stock.rule"] product = self.product_id - product_route_ids = [ - x.id for x in product.route_ids + product.categ_id.total_route_ids - ] + product_route_ids = (product.route_ids + product.categ_id.total_route_ids).ids rules = StockRule.search( [("route_id", "in", product_route_ids)], order="route_sequence, sequence", @@ -26,18 +32,15 @@ def _get_line_rule(self): ) if not rules: warehouse = self.order_id.warehouse_id - wh_routes = warehouse.route_ids - wh_route_ids = [route.id for route in wh_routes] + wh_route_ids = warehouse.route_ids.ids domain = [ "|", ("warehouse_id", "=", warehouse.id), ("warehouse_id", "=", False), ("route_id", "in", wh_route_ids), ] - rules = StockRule.search(domain, order="route_sequence, sequence") - if rules: - fields.first(rules) - return False + rules = StockRule.search(domain, order="route_sequence, sequence", limit=1) + return rules def _get_procure_method(self): """Get procure_method depending on product routes""" @@ -69,17 +72,8 @@ def _compute_is_readonly(self): len(line.reservation_ids) > 0 or line.order_id.state != "draft" ) - reservation_ids = fields.One2many( - "stock.reservation", "sale_line_id", string="Stock Reservation", copy=False - ) - is_stock_reservable = fields.Boolean( - compute="_compute_is_stock_reservable", readonly=True, string="Can be reserved" - ) - is_readonly = fields.Boolean(compute="_compute_is_readonly", store=False) - def release_stock_reservation(self): - reserv_ids = [reserv.id for line in self for reserv in line.reservation_ids] - reservations = self.env["stock.reservation"].browse(reserv_ids) + reservations = self.reservation_ids reservations.release_reserve() return True @@ -93,8 +87,7 @@ def write(self, vals): for line in self: if not line.reservation_ids: continue - raise except_orm( - _("Error"), + raise UserError( _( "You cannot change the product or unit of measure " "of lines with a stock reservation. " @@ -108,8 +101,7 @@ def write(self, vals): if not line.reservation_ids: continue if len(line.reservation_ids) > 1: - raise except_orm( - _("Error"), + raise UserError( _( "Several stock reservations are linked with the " "line. Impossible to adjust their quantity. " @@ -130,10 +122,9 @@ def unlink(self): if line.reservation_ids: raise UserError( _( - "Sale order line '['%(order_name)s'] '%(line_name)s'' has a " + f"Sale order line '['{line.order_id.name}'] '{line.name}' has a " "related reservation.\n" "Please unreserve this line before delete the line" ) - % {"order_name": line.order_id.name, "line_name": line.name} ) return super().unlink() diff --git a/stock_reserve_sale/model/stock_reserve.py b/stock_reserve_sale/model/stock_reserve.py index 591489ee1f37..4e839846cb12 100644 --- a/stock_reserve_sale/model/stock_reserve.py +++ b/stock_reserve_sale/model/stock_reserve.py @@ -14,22 +14,19 @@ class StockReservation(models.Model): ) def release_reserve(self): - for rec in self: - rec.sale_line_id = False + self.update({"sale_line_id": False}) return super().release_reserve() def action_view_reserves_stock_picking_reservation(self): - stock_picking = "" + stock_picking = self.env["stock.picking"] action = self.env["ir.actions.actions"]._for_xml_id( "stock.action_picking_tree_all" ) if self.sale_id: - stock_picking = ( - self.env["stock.picking"] - .search([("origin", "=", self.sale_id.name)]) - .filtered(lambda a: a.state not in "cancel") + stock_picking = self.env["stock.picking"].search( + [("origin", "=", self.sale_id.name), ("state", "!=", "cancel")], limit=1 ) if stock_picking: view_id = self.env.ref("stock.view_picking_form").id action.update(views=[(view_id, "form")], res_id=stock_picking.id) - return action + return action diff --git a/stock_reserve_sale/static/description/index.html b/stock_reserve_sale/static/description/index.html index a15219cced86..82c44a43b1d4 100644 --- a/stock_reserve_sale/static/description/index.html +++ b/stock_reserve_sale/static/description/index.html @@ -367,7 +367,7 @@

Stock Reserve Sales

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:c8bff29850116b499cd76c5813113489be840f32653162635c18d9a691dbf78e +!! source digest: sha256:0252821802e05031e45ee21a476cc66bcbac1af5de9e9d01fe240cd460e49ea2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/stock-logistics-warehouse Translate me on Weblate Try me on Runboat

Allows to create stock reservations for quotation lines before the diff --git a/stock_reserve_sale/view/sale.xml b/stock_reserve_sale/view/sale.xml index d2c537d407fa..bb7e3d2c0998 100644 --- a/stock_reserve_sale/view/sale.xml +++ b/stock_reserve_sale/view/sale.xml @@ -12,7 +12,7 @@ type="object" name="action_view_reserves_products" icon="fa-lock" - attrs="{'invisible': [('reserves_count', '=', 0)]}" + invisible="reserves_count == 0" > @@ -24,7 +24,7 @@ type="object" name="action_view_reserves_stock_picking" icon="fa-truck" - attrs="{'invisible': ['|', ('reserves_count', '=', 0),('state', '!=', 'draft')]}" + invisible="reserves_count == 0 or state != 'draft'" /> @@ -49,15 +49,13 @@ name="%(action_sale_stock_reserve)d" type="action" string="Reserve Stock" - attrs="{'invisible': ['|', ('reservation_ids', '!=', []), - ('state', '!=', 'draft')]}" + invisible="reservation_ids or state != 'draft'" />