-
-
Notifications
You must be signed in to change notification settings - Fork 738
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
441 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import models | ||
from .hooks import post_init_hook |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Copyright 2022 Akretion (https://www.akretion.com). | ||
# @author Kévin Roche <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
{ | ||
"name": "Product Route Profile", | ||
"summary": "Add Route profile concept on product", | ||
"version": "14.0.1.0.0", | ||
"category": "Warehouse", | ||
"website": "https://github.com/OCA/stock-logistics-warehouse", | ||
"author": "Akretion, Odoo Community Association (OCA)", | ||
"maintainers": ["Kev-Roche"], | ||
"license": "AGPL-3", | ||
"application": False, | ||
"installable": True, | ||
"depends": [ | ||
"stock", | ||
], | ||
"data": [ | ||
"views/route_profile.xml", | ||
"views/product_template.xml", | ||
"security/ir.model.access.csv", | ||
], | ||
"post_init_hook": "post_init_hook", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Copyright (C) 2022 Akretion (<http://www.akretion.com>). | ||
# @author Kévin Roche <[email protected]> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from collections import defaultdict | ||
|
||
from odoo import SUPERUSER_ID, api | ||
|
||
|
||
def post_init_hook(cr, registry): | ||
def get_profile(route_ids): | ||
route_ids = tuple(set(route_ids)) | ||
profile = route2profile.get(route_ids) | ||
if not profile: | ||
profile_name = "" | ||
route_names = [ | ||
rec.name for rec in env["stock.location.route"].browse(route_ids) | ||
] | ||
profile_name = " / ".join(route_names) | ||
profile = env["route.profile"].create( | ||
{ | ||
"name": profile_name, | ||
"route_ids": [(6, 0, route_ids)], | ||
} | ||
) | ||
route2profile[route_ids] = profile | ||
return profile | ||
|
||
env = api.Environment(cr, SUPERUSER_ID, {}) | ||
query = """ | ||
SELECT product_id, array_agg(route_id) | ||
FROM stock_route_product group by product_id; | ||
""" | ||
cr.execute(query) | ||
results = cr.fetchall() | ||
route2profile = {} | ||
profile2product = defaultdict(lambda: env["product.template"]) | ||
for row in results: | ||
profile = get_profile(row[1]) | ||
profile2product[profile.id] |= env["product.template"].browse(row[0]) | ||
|
||
for profile in profile2product: | ||
profile2product[profile].write({"route_profile_id": profile}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
# Translation of Odoo Server. | ||
# This file contains the translation of the following modules: | ||
# * product_route_profile | ||
# | ||
msgid "" | ||
msgstr "" | ||
"Project-Id-Version: Odoo Server 14.0\n" | ||
"Report-Msgid-Bugs-To: \n" | ||
"POT-Creation-Date: 2022-04-27 18:10+0000\n" | ||
"PO-Revision-Date: 2022-04-27 20:13+0200\n" | ||
"Last-Translator: \n" | ||
"Language-Team: \n" | ||
"Language: fr\n" | ||
"MIME-Version: 1.0\n" | ||
"Content-Type: text/plain; charset=UTF-8\n" | ||
"Content-Transfer-Encoding: 8bit\n" | ||
"Plural-Forms: \n" | ||
"X-Generator: Poedit 3.0.1\n" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model.fields,field_description:product_route_profile.field_route_profile__create_uid | ||
msgid "Created by" | ||
msgstr "" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model.fields,field_description:product_route_profile.field_route_profile__create_date | ||
msgid "Created on" | ||
msgstr "" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model.fields,help:product_route_profile.field_product_product__route_ids | ||
#: model:ir.model.fields,help:product_route_profile.field_product_template__route_ids | ||
msgid "" | ||
"Depending on the modules installed, this will allow you to define the route of the product: whether it will be bought, " | ||
"manufactured, replenished on order, etc." | ||
msgstr "" | ||
"En fonction des modules installés, cela va vous permettre de définir les routes sur l'article: acheter, fabriquer, " | ||
"réapprovisionner sur commande, etc." | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model.fields,field_description:product_route_profile.field_product_template__display_name | ||
#: model:ir.model.fields,field_description:product_route_profile.field_route_profile__display_name | ||
msgid "Display Name" | ||
msgstr "Nom" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model.fields,field_description:product_route_profile.field_product_template__id | ||
#: model:ir.model.fields,field_description:product_route_profile.field_route_profile__id | ||
msgid "ID" | ||
msgstr "" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model.fields,field_description:product_route_profile.field_product_template____last_update | ||
#: model:ir.model.fields,field_description:product_route_profile.field_route_profile____last_update | ||
msgid "Last Modified on" | ||
msgstr "Dernière modification le" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model.fields,field_description:product_route_profile.field_route_profile__write_uid | ||
msgid "Last Updated by" | ||
msgstr "" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model.fields,field_description:product_route_profile.field_route_profile__write_date | ||
msgid "Last Updated on" | ||
msgstr "" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model.fields,field_description:product_route_profile.field_route_profile__name | ||
msgid "Name" | ||
msgstr "" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model.fields,field_description:product_route_profile.field_product_product__force_route_profile_id | ||
#: model:ir.model.fields,field_description:product_route_profile.field_product_template__force_route_profile_id | ||
msgid "Priority Route Profile" | ||
msgstr "Profil de Routes Prioritaires" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model,name:product_route_profile.model_product_template | ||
msgid "Product Template" | ||
msgstr "Modèle de produit" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model.fields,field_description:product_route_profile.field_product_product__route_profile_id | ||
#: model:ir.model.fields,field_description:product_route_profile.field_product_template__route_profile_id | ||
msgid "Route Profile" | ||
msgstr "Profil de routes" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model.fields,field_description:product_route_profile.field_product_product__route_ids | ||
#: model:ir.model.fields,field_description:product_route_profile.field_product_template__route_ids | ||
#: model:ir.model.fields,field_description:product_route_profile.field_route_profile__route_ids | ||
msgid "Routes" | ||
msgstr "Routes" | ||
|
||
#. module: product_route_profile | ||
#: model:ir.actions.act_window,name:product_route_profile.action_route_profile_form | ||
#: model:ir.ui.menu,name:product_route_profile.menu_route_profile_config | ||
#: model_terms:ir.ui.view,arch_db:product_route_profile.route_profile_form | ||
#: model_terms:ir.ui.view,arch_db:product_route_profile.route_profile_tree | ||
msgid "Routes Profiles" | ||
msgstr "Profils de Routes" | ||
|
||
#. module: product_route_profile | ||
#: model_terms:ir.actions.act_window,help:product_route_profile.action_route_profile_form | ||
msgid "" | ||
"You can define here the routes profiles that run through\n" | ||
" your warehouses and that define the flows of your products.\n" | ||
" A route profile can be set on each product as \"Route Profile\" or \"Priority Route Profile\" (company dependent)." | ||
msgstr "" | ||
"Vous pouvez définir ici les routes qui régissent les mouvements de vos produits dans vos entrepôts. \n" | ||
"Un profil de route peut être défini pour chaque produit en tant que \"Profil de Routes\" ou \"Profil de Routes Prioritaires" | ||
"\" (société dépendant)." | ||
|
||
#. module: product_route_profile | ||
#: model:ir.model,name:product_route_profile.model_route_profile | ||
msgid "route.profile" | ||
msgstr "" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import route_profile | ||
from . import product_template |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# Copyright 2022 Akretion (https://www.akretion.com). | ||
# @author Kévin Roche <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from odoo import api, fields, models | ||
|
||
|
||
class ProductTemplate(models.Model): | ||
_inherit = "product.template" | ||
|
||
route_profile_id = fields.Many2one("route.profile", string="Route Profile") | ||
force_route_profile_id = fields.Many2one( | ||
"route.profile", | ||
string="Priority Route Profile", | ||
company_dependent=True, | ||
help="If defined, the " | ||
"priority route profile will be used and will replace the " | ||
"route profile, only for this company.", | ||
) | ||
|
||
route_ids = fields.Many2many( | ||
compute="_compute_route_ids", | ||
inverse="_inverse_route_ids", | ||
search="_search_route_ids", | ||
store=False, | ||
) | ||
|
||
@api.depends("route_profile_id", "force_route_profile_id") | ||
@api.depends_context("company") | ||
def _compute_route_ids(self): | ||
for rec in self: | ||
if rec.force_route_profile_id: | ||
rec.route_ids = [(6, 0, rec.force_route_profile_id.route_ids.ids)] | ||
elif rec.route_profile_id: | ||
rec.route_ids = [(6, 0, rec.route_profile_id.route_ids.ids)] | ||
else: | ||
rec.route_ids = False | ||
|
||
def _search_route_ids(self, operator, value): | ||
return [ | ||
"|", | ||
("force_route_profile_id.route_ids", operator, value), | ||
"&", | ||
("force_route_profile_id", "=", False), | ||
("route_profile_id.route_ids", operator, value), | ||
] | ||
|
||
def _inverse_route_ids(self): | ||
profiles = self.env["route.profile"].search([]) | ||
for rec in self: | ||
for profile in profiles: | ||
if rec.route_ids == profile.route_ids: | ||
rec.route_profile_id = profile | ||
break | ||
else: | ||
vals = rec._prepare_profile() | ||
rec.route_profile_id = self.env["route.profile"].create(vals) | ||
|
||
def _prepare_profile(self): | ||
return { | ||
"name": " / ".join(self.route_ids.mapped("name")), | ||
"route_ids": [(6, 0, self.route_ids.ids)], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Copyright 2022 Akretion (https://www.akretion.com). | ||
# @author Kévin Roche <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from odoo import fields, models | ||
|
||
|
||
class RouteProfile(models.Model): | ||
_name = "route.profile" | ||
_description = "Route Profile" | ||
|
||
name = fields.Char("Name") | ||
company_id = fields.Many2one( | ||
comodel_name="res.company", | ||
default=lambda self: self.env.company.id, | ||
required=False, | ||
string="Company", | ||
) | ||
route_ids = fields.Many2many( | ||
"stock.location.route", | ||
string="Routes", | ||
domain=[("product_selectable", "=", True)], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* Kévin Roche <[email protected]> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
This module replaces the initial concept of route_ids with a new concept of "route profile", coming with a company-specific and priority route profile. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Tests of this module are running separately than the other tests. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
**Route profile** | ||
In Inventory > Configuration > Settings > Routes Profiles | ||
- Create some Route profile depending on your needs | ||
|
||
|
||
**On product** | ||
On each template product, in inventory page, we can select: | ||
- **Route Profile**: a default profile, common to all companies | ||
- **Priority Route Profile**: a profile specific to each company and priority if existing. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | ||
access_route_profile_manager,access_route_profile_manager,model_route_profile,stock.group_stock_manager,1,1,1,1 | ||
access_route_profile_user,access_route_profile_user,model_route_profile,stock.group_stock_user,1,0,0,0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import test_product_route_profile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# Copyright 2022 Akretion (https://www.akretion.com). | ||
# @author Kévin Roche <[email protected]> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from odoo.tests.common import SavepointCase | ||
|
||
|
||
class TestProductRouteProfile(SavepointCase): | ||
@classmethod | ||
def setUpClass(cls): | ||
super(TestProductRouteProfile, cls).setUpClass() | ||
|
||
cls.company_bis = cls.env["res.company"].create( | ||
{ | ||
"name": "company 2", | ||
"parent_id": cls.env.ref("base.main_company").id, | ||
} | ||
) | ||
|
||
cls.route_1 = cls.env.ref("stock.route_warehouse0_mto") | ||
cls.route_1.active = True | ||
cls.route_2 = cls.route_1.copy({"name": "route 2"}) | ||
|
||
cls.route_profile_1 = cls.env["route.profile"].create( | ||
{ | ||
"name": "profile 1", | ||
"route_ids": [(6, 0, [cls.route_1.id])], | ||
} | ||
) | ||
cls.route_profile_2 = cls.env["route.profile"].create( | ||
{ | ||
"name": "profile 2", | ||
"route_ids": [(6, 0, [cls.route_2.id])], | ||
} | ||
) | ||
|
||
cls.product = cls.env["product.template"].create( | ||
{ | ||
"name": "Template 1", | ||
"company_id": False, | ||
} | ||
) | ||
|
||
def test_1_route_profile(self): | ||
self.product.route_profile_id = self.route_profile_1.id | ||
self.assertEqual(self.product.route_ids, self.route_profile_1.route_ids) | ||
# In other company, no change | ||
self.assertEqual( | ||
self.product.with_company(self.company_bis).route_ids, | ||
self.route_profile_1.route_ids, | ||
) | ||
|
||
def test_2_force_route_profile(self): | ||
self.product.route_profile_id = self.route_profile_1.id | ||
self.product.with_company( | ||
self.env.company | ||
).force_route_profile_id = self.route_profile_2.id | ||
self.assertEqual( | ||
self.product.with_company(self.env.company).route_ids, | ||
self.route_profile_2.route_ids, | ||
) | ||
# In other company, no change | ||
self.assertEqual( | ||
self.product.with_company(self.company_bis).route_ids, | ||
self.route_profile_1.route_ids, | ||
) | ||
# Return to route_profile_id if no force_route_profile_id | ||
self.product.with_company(self.env.company).force_route_profile_id = False | ||
self.assertEqual( | ||
self.product.with_company(self.env.company).route_ids, | ||
self.route_profile_1.route_ids, | ||
) |
Oops, something went wrong.