mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[ADD] module: product_route_profile
This commit is contained in:
2
product_route_profile/__init__.py
Normal file
2
product_route_profile/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from . import models
|
||||||
|
from .hooks import post_init_hook
|
||||||
25
product_route_profile/__manifest__.py
Normal file
25
product_route_profile/__manifest__.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Copyright 2022 Akretion (https://www.akretion.com).
|
||||||
|
# @author Kévin Roche <kevin.roche@akretion.com>
|
||||||
|
# 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",
|
||||||
|
}
|
||||||
43
product_route_profile/hooks.py
Normal file
43
product_route_profile/hooks.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Copyright (C) 2022 Akretion (<http://www.akretion.com>).
|
||||||
|
# @author Kévin Roche <kevin.roche@akretion.com>
|
||||||
|
# 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})
|
||||||
119
product_route_profile/i18n/fr.po
Normal file
119
product_route_profile/i18n/fr.po
Normal file
@@ -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 ""
|
||||||
2
product_route_profile/models/__init__.py
Normal file
2
product_route_profile/models/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from . import route_profile
|
||||||
|
from . import product_template
|
||||||
63
product_route_profile/models/product_template.py
Normal file
63
product_route_profile/models/product_template.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Copyright 2022 Akretion (https://www.akretion.com).
|
||||||
|
# @author Kévin Roche <kevin.roche@akretion.com>
|
||||||
|
# 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)],
|
||||||
|
}
|
||||||
23
product_route_profile/models/route_profile.py
Normal file
23
product_route_profile/models/route_profile.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Copyright 2022 Akretion (https://www.akretion.com).
|
||||||
|
# @author Kévin Roche <kevin.roche@akretion.com>
|
||||||
|
# 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)],
|
||||||
|
)
|
||||||
1
product_route_profile/readme/CONTRIBUTORS.rst
Normal file
1
product_route_profile/readme/CONTRIBUTORS.rst
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* Kévin Roche <kevin.roche@akretion.com>
|
||||||
1
product_route_profile/readme/DESCRIPTION.rst
Normal file
1
product_route_profile/readme/DESCRIPTION.rst
Normal file
@@ -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.
|
||||||
1
product_route_profile/readme/ROADMAP.rst
Normal file
1
product_route_profile/readme/ROADMAP.rst
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Tests of this module are running separately than the other tests.
|
||||||
9
product_route_profile/readme/USAGE.rst
Normal file
9
product_route_profile/readme/USAGE.rst
Normal file
@@ -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.
|
||||||
3
product_route_profile/security/ir.model.access.csv
Normal file
3
product_route_profile/security/ir.model.access.csv
Normal file
@@ -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
|
||||||
|
1
product_route_profile/tests/__init__.py
Normal file
1
product_route_profile/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import test_product_route_profile
|
||||||
72
product_route_profile/tests/test_product_route_profile.py
Normal file
72
product_route_profile/tests/test_product_route_profile.py
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# Copyright 2022 Akretion (https://www.akretion.com).
|
||||||
|
# @author Kévin Roche <kevin.roche@akretion.com>
|
||||||
|
# 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,
|
||||||
|
)
|
||||||
26
product_route_profile/views/product_template.xml
Normal file
26
product_route_profile/views/product_template.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!-- Copyright (C) 2022 Akretion (<http://www.akretion.com>).
|
||||||
|
@author Kévin Roche <kevin.roche@akretion.com>
|
||||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||||
|
<odoo>
|
||||||
|
<record id="view_template_route_profile_form" model="ir.ui.view">
|
||||||
|
<field name="name">product.template.route.profile.form</field>
|
||||||
|
<field name="model">product.template</field>
|
||||||
|
<field name="inherit_id" ref="product.product_template_form_view" />
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//field[@name='route_ids']/parent::div" position="attributes">
|
||||||
|
<attribute name="attrs">{'invisible': True}</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//group[@name='operations']" position="inside">
|
||||||
|
<field
|
||||||
|
name="route_profile_id"
|
||||||
|
attrs="{'invisible': [('type', 'in', ['service', 'digital'])]}"
|
||||||
|
/>
|
||||||
|
<field
|
||||||
|
name="force_route_profile_id"
|
||||||
|
attrs="{'invisible': [('type', 'in', ['service', 'digital'])]}"
|
||||||
|
/>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
50
product_route_profile/views/route_profile.xml
Normal file
50
product_route_profile/views/route_profile.xml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!-- Copyright (C) 2022 Akretion (<http://www.akretion.com>).
|
||||||
|
@author Kévin Roche <kevin.roche@akretion.com>
|
||||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||||
|
<odoo>
|
||||||
|
<record id="route_profile_tree" model="ir.ui.view">
|
||||||
|
<field name="name">route.profile.tree</field>
|
||||||
|
<field name="model">route.profile</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree string="Routes Profiles">
|
||||||
|
<field name="name" />
|
||||||
|
<field name="route_ids" widget="many2many_tags" />
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<record id="route_profile_form" model="ir.ui.view">
|
||||||
|
<field name="name">route.profile.form</field>
|
||||||
|
<field name="model">route.profile</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form>
|
||||||
|
<group string="Routes Profiles">
|
||||||
|
<field name="name" />
|
||||||
|
<field name="route_ids" widget="many2many_checkboxes" />
|
||||||
|
</group>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<record id="action_route_profile_form" model="ir.actions.act_window">
|
||||||
|
<field name="name">Routes Profiles</field>
|
||||||
|
<field name="res_model">route.profile</field>
|
||||||
|
<field name="type">ir.actions.act_window</field>
|
||||||
|
<field name="view_mode">tree,form</field>
|
||||||
|
<field name="view_id" ref="route_profile_tree" />
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p>
|
||||||
|
You can define here the routes profiles that run through
|
||||||
|
your warehouses and that define the flows of your products.
|
||||||
|
A route profile can be set on each product as "Route Profile" or "Priority Route Profile" (company dependent).
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<menuitem
|
||||||
|
id="menu_route_profile_config"
|
||||||
|
action="action_route_profile_form"
|
||||||
|
name="Routes Profiles"
|
||||||
|
parent="stock.menu_warehouse_config"
|
||||||
|
sequence="4"
|
||||||
|
groups="stock.group_adv_location"
|
||||||
|
/>
|
||||||
|
</odoo>
|
||||||
1
setup/product_route_profile/odoo/addons/product_route_profile
Symbolic link
1
setup/product_route_profile/odoo/addons/product_route_profile
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../../../../product_route_profile
|
||||||
6
setup/product_route_profile/setup.py
Normal file
6
setup/product_route_profile/setup.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import setuptools
|
||||||
|
|
||||||
|
setuptools.setup(
|
||||||
|
setup_requires=['setuptools-odoo'],
|
||||||
|
odoo_addon=True,
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user