[MIG] mrp_bom_version: Migration to 16.0

This commit is contained in:
Kay K. Cross
2024-10-18 11:55:17 +02:00
parent c15be7dac5
commit a90ab95717
12 changed files with 243 additions and 269 deletions

View File

@@ -36,8 +36,17 @@ jobs:
matrix: matrix:
include: include:
- container: ghcr.io/oca/oca-ci/py3.10-odoo16.0:latest - container: ghcr.io/oca/oca-ci/py3.10-odoo16.0:latest
include: "mrp_bom_version"
name: test with Odoo name: test with Odoo
- container: ghcr.io/oca/oca-ci/py3.10-ocb16.0:latest - container: ghcr.io/oca/oca-ci/py3.10-ocb16.0:latest
include: "mrp_bom_version"
name: test with OCB
makepot: "true"
- container: ghcr.io/oca/oca-ci/py3.10-odoo16.0:latest
exclude: "mrp_bom_version"
name: test with Odoo
- container: ghcr.io/oca/oca-ci/py3.10-ocb16.0:latest
exclude: "mrp_bom_version"
name: test with OCB name: test with OCB
makepot: "true" makepot: "true"
services: services:
@@ -49,6 +58,9 @@ jobs:
POSTGRES_DB: odoo POSTGRES_DB: odoo
ports: ports:
- 5432:5432 - 5432:5432
env:
INCLUDE: "${{ matrix.include }}"
EXCLUDE: "${{ matrix.exclude }}"
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:

View File

@@ -5,7 +5,7 @@
{ {
"name": "MRP - BoM version", "name": "MRP - BoM version",
"summary": "BoM versioning", "summary": "BoM versioning",
"version": "8.0.1.0.0", "version": "16.0.1.0.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "OdooMRP team," "author": "OdooMRP team,"
"AvanzOSC," "AvanzOSC,"

View File

@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<openerp> <odoo>
<data>
<record id="mt_active" model="mail.message.subtype"> <record id="mt_active" model="mail.message.subtype">
<field name="name">MRP BoM Active</field> <field name="name">MRP BoM Active</field>
<field name="res_model">mrp.bom</field> <field name="res_model">mrp.bom</field>
<field name="default" eval="False" /> <field name="default" eval="False" />
<field name="description">MRP BoM Active</field> <field name="description">MRP BoM Active</field>
</record> </record>
</data> </odoo>
</openerp>

View File

@@ -1,28 +1,21 @@
# (c) 2015 Oihane Crucelaegui - AvanzOSC # (c) 2015 Oihane Crucelaegui - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from openerp import api, fields, models from odoo import api, fields, models
from openerp.tools import config from odoo.tools import config
class MrpBom(models.Model): class MrpBom(models.Model):
_inherit = "mrp.bom" _inherit = "mrp.bom"
_track = { def _compute_old_versions(self):
"state": { for bom in self:
"mrp_bom_version.mt_active": lambda self, cr, uid, obj, ctx=None: obj.state parent = bom.parent_bom
== "active",
},
}
@api.one
def _get_old_versions(self):
parent = self.parent_bom
old_version = self.env["mrp.bom"] old_version = self.env["mrp.bom"]
while parent: while parent:
old_version += parent old_version |= parent
parent = parent.parent_bom parent = parent.parent_bom
self.old_versions = old_version bom.old_versions = [(6, 0, old_version.ids)]
def _default_active(self): def _default_active(self):
"""Needed for preserving normal flow when testing other modules.""" """Needed for preserving normal flow when testing other modules."""
@@ -41,14 +34,14 @@ class MrpBom(models.Model):
active = fields.Boolean( active = fields.Boolean(
default=_default_active, readonly=True, states={"draft": [("readonly", False)]} default=_default_active, readonly=True, states={"draft": [("readonly", False)]}
) )
historical_date = fields.Date(string="Historical Date", readonly=True) historical_date = fields.Date(readonly=True, copy=False)
state = fields.Selection( state = fields.Selection(
selection=[ selection=[
("draft", "Draft"), ("draft", "Draft"),
("active", "Active"), ("active", "Active"),
("historical", "Historical"), ("historical", "Historical"),
], ],
string="State", string="Status",
index=True, index=True,
readonly=True, readonly=True,
default=_default_state, default=_default_state,
@@ -59,23 +52,23 @@ class MrpBom(models.Model):
) )
product_id = fields.Many2one(readonly=True, states={"draft": [("readonly", False)]}) product_id = fields.Many2one(readonly=True, states={"draft": [("readonly", False)]})
product_qty = fields.Float(readonly=True, states={"draft": [("readonly", False)]}) product_qty = fields.Float(readonly=True, states={"draft": [("readonly", False)]})
name = fields.Char(states={"historical": [("readonly", True)]})
code = fields.Char(states={"historical": [("readonly", True)]}) code = fields.Char(states={"historical": [("readonly", True)]})
type = fields.Selection(states={"historical": [("readonly", True)]}) type = fields.Selection(states={"historical": [("readonly", True)]})
company_id = fields.Many2one(states={"historical": [("readonly", True)]}) company_id = fields.Many2one(states={"historical": [("readonly", True)]})
product_uom = fields.Many2one(states={"historical": [("readonly", True)]}) product_uom_id = fields.Many2one(states={"historical": [("readonly", True)]})
routing_id = fields.Many2one(readonly=True, states={"draft": [("readonly", False)]})
bom_line_ids = fields.One2many( bom_line_ids = fields.One2many(
readonly=True, states={"draft": [("readonly", False)]} readonly=True, states={"draft": [("readonly", False)]}
) )
position = fields.Char(states={"historical": [("readonly", True)]}) byproduct_ids = fields.One2many(
date_start = fields.Date(states={"historical": [("readonly", True)]}) readonly=True, states={"draft": [("readonly", False)]}
date_stop = fields.Date(states={"historical": [("readonly", True)]}) )
property_ids = fields.Many2many(states={"historical": [("readonly", True)]}) sequence = fields.Integer(states={"historical": [("readonly", True)]})
product_rounding = fields.Float(states={"historical": [("readonly", True)]}) operation_ids = fields.One2many(
product_efficiency = fields.Float(states={"historical": [("readonly", True)]}) readonly=True, states={"draft": [("readonly", False)]}
message_follower_ids = fields.Many2many(states={"historical": [("readonly", True)]}) )
message_ids = fields.One2many(states={"historical": [("readonly", True)]}) ready_to_produce = fields.Selection(states={"historical": [("readonly", True)]})
picking_type_id = fields.Many2one(states={"historical": [("readonly", True)]})
consumption = fields.Selection(states={"historical": [("readonly", True)]})
version = fields.Integer( version = fields.Integer(
states={"historical": [("readonly", True)]}, copy=False, default=1 states={"historical": [("readonly", True)]}, copy=False, default=1
) )
@@ -83,20 +76,24 @@ class MrpBom(models.Model):
comodel_name="mrp.bom", string="Parent BoM", copy=False comodel_name="mrp.bom", string="Parent BoM", copy=False
) )
old_versions = fields.Many2many( old_versions = fields.Many2many(
comodel_name="mrp.bom", string="Old Versions", compute="_get_old_versions" comodel_name="mrp.bom", compute="_compute_old_versions"
) )
@api.multi def _track_subtype(self, init_values):
if "state" in init_values and self.state == "active":
return self.env.ref("mrp_bom_version.mt_active")
return super()._track_subtype(init_values)
def button_draft(self): def button_draft(self):
active_draft = self.env["mrp.config.settings"]._get_parameter("active.draft") get_param = self.env["ir.config_parameter"].sudo().get_param
active_draft = get_param("mrp_bom_version.active_draft")
self.write( self.write(
{ {
"active": active_draft and active_draft.value or False, "active": active_draft,
"state": "draft", "state": "draft",
} }
) )
@api.multi
def button_new_version(self): def button_new_version(self):
self.ensure_one() self.ensure_one()
new_bom = self._copy_bom() new_bom = self._copy_bom()
@@ -111,21 +108,20 @@ class MrpBom(models.Model):
} }
def _copy_bom(self): def _copy_bom(self):
active_draft = self.env["mrp.config.settings"]._get_parameter("active.draft") get_param = self.env["ir.config_parameter"].sudo().get_param
active_draft = get_param("mrp_bom_version.active_draft")
new_bom = self.copy( new_bom = self.copy(
{ {
"version": self.version + 1, "version": self.version + 1,
"active": active_draft and active_draft.value or False, "active": active_draft,
"parent_bom": self.id, "parent_bom": self.id,
} }
) )
return new_bom return new_bom
@api.multi
def button_activate(self): def button_activate(self):
self.write({"active": True, "state": "active"}) self.write({"active": True, "state": "active"})
@api.multi
def button_historical(self): def button_historical(self):
self.write( self.write(
{ {
@@ -135,39 +131,35 @@ class MrpBom(models.Model):
} }
) )
def search( @api.model
self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False def search(self, args, offset=0, limit=None, order=None, count=False):
):
"""Add search argument for field type if the context says so. This """Add search argument for field type if the context says so. This
should be in old API because context argument is not the last one. should be in old API because context argument is not the last one.
""" """
if context is None: search_state = self.env.context.get("state", False)
context = {}
search_state = context.get("state", False)
if search_state: if search_state:
args += [("state", "=", search_state)] args += [("state", "=", search_state)]
return super(MrpBom, self).search( return super().search(
cr,
uid,
args, args,
offset=offset, offset=offset,
limit=limit, limit=limit,
order=order, order=order,
context=context,
count=count, count=count,
) )
@api.model @api.model
def _bom_find(self, product_tmpl_id=None, product_id=None, properties=None): def _bom_find(self, products, picking_type=None, company_id=False, bom_type=False):
"""Finds BoM for particular product and product uom. """Find the first BoM for each products
@param product_tmpl_id: Selected product.
@param product_uom: Unit of measure of a product. :param products: `product.product` recordset
@param properties: List of related properties. :return: One bom (or empty recordset `mrp.bom` if none find)
@return: False or BoM id. by product (`product.product` record)
:rtype: defaultdict(`lambda: self.env['mrp.bom']`)
""" """
bom_id = super(MrpBom, self.with_context(state="active"))._bom_find( bom_id = super(MrpBom, self.with_context(state="active"))._bom_find(
product_tmpl_id=product_tmpl_id, products,
product_id=product_id, picking_type=picking_type,
properties=properties, company_id=company_id,
bom_type=bom_type,
) )
return bom_id return bom_id

View File

@@ -1,11 +1,11 @@
# (c) 2015 Oihane Crucelaegui - AvanzOSC # (c) 2015 Oihane Crucelaegui - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from openerp import api, fields, models from odoo import fields, models
class MrpConfigSettings(models.TransientModel): class MrpConfigSettings(models.TransientModel):
_inherit = "mrp.config.settings" _inherit = "res.config.settings"
group_mrp_bom_version = fields.Boolean( group_mrp_bom_version = fields.Boolean(
string="Allow to re-edit BoMs", string="Allow to re-edit BoMs",
@@ -16,34 +16,5 @@ class MrpConfigSettings(models.TransientModel):
string="Keep re-editing BoM active", string="Keep re-editing BoM active",
help="This will allow you to define if those BoM passed back to draft" help="This will allow you to define if those BoM passed back to draft"
" are still activated or not", " are still activated or not",
config_parameter="mrp_bom_version.active_draft",
) )
def _get_parameter(self, key, default=False):
param_obj = self.env["ir.config_parameter"]
rec = param_obj.search([("key", "=", key)])
return rec or default
def _write_or_create_param(self, key, value):
param_obj = self.env["ir.config_parameter"]
rec = self._get_parameter(key)
if rec:
if not value:
rec.unlink()
else:
rec.value = value
elif value:
param_obj.create({"key": key, "value": value})
@api.multi
def get_default_parameters(self):
def get_value(key, default=""):
rec = self._get_parameter(key)
return rec and rec.value or default
return {
"active_draft": get_value("active.draft", False),
}
@api.multi
def set_parameters(self):
self._write_or_create_param("active.draft", self.active_draft)

View File

@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<openerp> <odoo noupdate="1">
<data noupdate="1">
<record id="group_mrp_bom_version" model="res.groups"> <record id="group_mrp_bom_version" model="res.groups">
<field name="name">MRP BoM version</field> <field name="name">MRP BoM version</field>
<field name="category_id" ref="base.module_category_hidden" /> <field name="category_id" ref="base.module_category_hidden" />
</record> </record>
</data> </odoo>
</openerp>

View File

@@ -1,26 +1,27 @@
# (c) 2015 Alfredo de la Fuente - AvanzOSC # (c) 2015 Alfredo de la Fuente - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
import openerp.tests.common as common import odoo.tests as common
class TestMrpBomVersion(common.TransactionCase): class TestMrpBomVersion(common.TransactionCase):
def setUp(self): @classmethod
super(TestMrpBomVersion, self).setUp() def setUpClass(cls):
self.parameter_model = self.env["ir.config_parameter"] super(TestMrpBomVersion, cls).setUpClass()
self.bom_model = self.env["mrp.bom"].with_context(test_mrp_bom_version=True) cls.parameter_model = cls.env["ir.config_parameter"].sudo()
self.company = self.env.ref("base.main_company") cls.bom_model = cls.env["mrp.bom"].with_context(test_mrp_bom_version=True)
cls.company = cls.env.ref("base.main_company")
vals = { vals = {
"company_id": self.company.id, "company_id": cls.company.id,
"product_tmpl_id": self.env.ref( "product_tmpl_id": cls.env.ref(
"product.product_product_11_product_template" "product.product_product_11_product_template"
).id, ).id,
"bom_line_ids": [ "bom_line_ids": [
(0, 0, {"product_id": self.env.ref("product.product_product_5").id}), (0, 0, {"product_id": cls.env.ref("product.product_product_5").id}),
(0, 0, {"product_id": self.env.ref("product.product_product_6").id}), (0, 0, {"product_id": cls.env.ref("product.product_product_6").id}),
], ],
} }
self.mrp_bom = self.bom_model.create(vals) cls.mrp_bom = cls.bom_model.create(vals)
def test_mrp_bom(self): def test_mrp_bom(self):
self.assertEqual( self.assertEqual(
@@ -49,7 +50,7 @@ class TestMrpBomVersion(common.TransactionCase):
self.assertFalse(self.mrp_bom.active, "Check must be False") self.assertFalse(self.mrp_bom.active, "Check must be False")
def test_mrp_bom_back2draft_active(self): def test_mrp_bom_back2draft_active(self):
self.parameter_model.create({"key": "active.draft", "value": True}) self.parameter_model.set_param("mrp_bom_version.active_draft", True)
self.mrp_bom.button_activate() self.mrp_bom.button_activate()
self.mrp_bom.button_draft() self.mrp_bom.button_draft()
self.assertTrue(self.mrp_bom.active, "Check must be True, as set in parameters") self.assertTrue(self.mrp_bom.active, "Check must be True, as set in parameters")
@@ -65,7 +66,11 @@ class TestMrpBomVersion(common.TransactionCase):
"historical", "historical",
"Incorrect state, it must have been historified", "Incorrect state, it must have been historified",
) )
new_boms = self.bom_model.search([("parent_bom", "=", self.mrp_bom.id)]) new_boms = self.bom_model.with_context(active_test=False).search(
[
("parent_bom", "=", self.mrp_bom.id),
]
)
for new_bom in new_boms: for new_bom in new_boms:
self.assertEqual( self.assertEqual(
new_bom.version, new_bom.version,

View File

@@ -1,62 +1,50 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<openerp> <odoo>
<data>
<record model="ir.actions.act_window" id="mrp.mrp_bom_form_action"> <record model="ir.actions.act_window" id="mrp.mrp_bom_form_action">
<field name="domain">['|',('active','=',True),('active','=',False)]</field> <field name="domain">['|',('active','=',True),('active','=',False)]</field>
</record> </record>
<record id="mrp.mrp_bom_tree_parent_view" model="ir.ui.view">
<field name="name">mrp.bom.tree</field>
<field name="model">mrp.bom</field>
<field name="arch" type="xml">
<tree>
<field name="name" />
<field name="code" />
<field name="sequence" />
</tree>
</field>
</record>
<record model="ir.ui.view" id="mrp_bom_version_tree_view"> <record model="ir.ui.view" id="mrp_bom_version_tree_view">
<field name="name">mrp.bom.version.tree</field>
<field name="model">mrp.bom</field> <field name="model">mrp.bom</field>
<field name="inherit_id" ref="mrp.mrp_bom_tree_parent_view" /> <field name="inherit_id" ref="mrp.mrp_bom_tree_view" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="name" position="after"> <tree position="attributes">
<field name="active" /> <attribute name="decoration-muted">not active</attribute>
</tree>
<field name="code" position="after">
<field name="version" /> <field name="version" />
<field name="state" /> <field name="state" />
<field name="historical_date" /> <field name="historical_date" />
<button <button
name="button_draft" name="button_draft"
type="object" type="object"
string="Draft" title="Draft"
groups="mrp_bom_version.group_mrp_bom_version" groups="mrp_bom_version.group_mrp_bom_version"
attrs="{'invisible':[('state','!=','active')]}" attrs="{'invisible':[('state','!=','active')]}"
icon="terp-document-new" icon="fa-plus-square"
/> />
<button <button
name="button_activate" name="button_activate"
type="object" type="object"
string="Activate" title="Activate"
attrs="{'invisible':[('state','not in',(False, 'draft'))]}" attrs="{'invisible':[('state','not in',(False, 'draft'))]}"
icon="terp-camera_test" icon="fa-check-square"
confirm="You will activate the BoM. If you haven't set a route yet, then you won't be able to do it after this. Are you sure you want to proceed?" confirm="You will activate the BoM, then you won't be able to edit it after this. Are you sure you want to proceed?"
/> />
<button <button
name="button_new_version" name="button_new_version"
type="object" type="object"
string="New version" title="New version"
attrs="{'invisible':[('state','==','historical')]}" attrs="{'invisible':[('state','==','historical')]}"
icon="gtk-execute" icon="fa-gears"
confirm="You are going to create a new version of this BoM. Are you sure?" confirm="You are going to create a new version of this BoM. Are you sure?"
/> />
<button <button
name="button_historical" name="button_historical"
type="object" type="object"
string="Historical" title="Historical"
attrs="{'invisible':[('state','!=','active')]}" attrs="{'invisible':[('state','!=','active')]}"
icon="gtk-convert" icon="fa-history"
confirm="You are going to historize an BoM. Doing, not be able to unlock it unless you make a copy. Are you sure you want to proceed?" confirm="You are going to historize an BoM. Doing, not be able to unlock it unless you make a copy. Are you sure you want to proceed?"
/> />
</field> </field>
@@ -64,11 +52,10 @@
</record> </record>
<record model="ir.ui.view" id="mrp_bom_version_form_view"> <record model="ir.ui.view" id="mrp_bom_version_form_view">
<field name="name">mrp.bom.version.form</field>
<field name="model">mrp.bom</field> <field name="model">mrp.bom</field>
<field name="inherit_id" ref="mrp.mrp_bom_form_view" /> <field name="inherit_id" ref="mrp.mrp_bom_form_view" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//form/group" position="before"> <sheet position="before">
<header> <header>
<button <button
name="button_draft" name="button_draft"
@@ -84,13 +71,13 @@
string="Activate" string="Activate"
attrs="{'invisible':[('state','not in',(False, 'draft'))]}" attrs="{'invisible':[('state','not in',(False, 'draft'))]}"
class="oe_highlight" class="oe_highlight"
confirm="You will activate the BoM. If you haven't set a route yet, then you won't be able to do it after this. Are you sure you want to proceed?" confirm="YYou will activate the BoM, then you won't be able to edit it after this. Are you sure you want to proceed?"
/> />
<button <button
name="button_new_version" name="button_new_version"
type="object" type="object"
string="New version" string="New version"
attrs="{'invisible':[('state','==','historical')]}" attrs="{'invisible':[('state','=','historical')]}"
class="oe_highlight" class="oe_highlight"
confirm="You are going to create a new version of this BoM. Are you sure?" confirm="You are going to create a new version of this BoM. Are you sure?"
/> />
@@ -108,8 +95,8 @@
statusbar_visible="draft,active,historical" statusbar_visible="draft,active,historical"
/> />
</header> </header>
</xpath> </sheet>
<field name="company_id" position="after"> <field name="company_id" position="before">
<field name="version" /> <field name="version" />
<field <field
name="historical_date" name="historical_date"
@@ -125,36 +112,33 @@
</record> </record>
<record model="ir.ui.view" id="mrp_bom_version_search_view"> <record model="ir.ui.view" id="mrp_bom_version_search_view">
<field name="name">mrp.bom.version.search</field>
<field name="model">mrp.bom</field> <field name="model">mrp.bom</field>
<field name="inherit_id" ref="mrp.view_mrp_bom_filter" /> <field name="inherit_id" ref="mrp.view_mrp_bom_filter" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="name" position="after"> <filter name="normal" position="before">
<field name="active" />
<field name="state" /> <field name="state" />
</field> </filter>
<group string="Group By..." position="before"> <filter name="inactive" position="before">
<filter <filter
string="Active" string="Active"
domain="[('active','=',True)]" domain="[('active','=',True)]"
name="is_active_filter" name="is_active_filter"
/> />
<filter </filter>
string="Inactive" <filter name="default_unit_of_measure" position="after">
domain="[('active','=',False)]"
name="is_inactive_filter"
/>
</group>
<group string="Group By..." position="inside">
<filter <filter
string="Active" string="Active"
name="group_active"
domain="[]" domain="[]"
context="{'group_by':'active'}" context="{'group_by':'active'}"
/> />
<filter string="State" domain="[]" context="{'group_by':'state'}" /> <filter
</group> string="Status"
name="group_state"
domain="[]"
context="{'group_by':'state'}"
/>
</filter>
</field> </field>
</record> </record>
</odoo>
</data>
</openerp>

View File

@@ -1,22 +1,37 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<openerp> <odoo>
<data>
<record model="ir.ui.view" id="mrp_config_settings_versioning"> <record model="ir.ui.view" id="mrp_config_settings_versioning">
<field name="name">mrp.config.settings.versioning</field> <field name="model">res.config.settings</field>
<field name="model">mrp.config.settings</field> <field name="inherit_id" ref="mrp.res_config_settings_view_form" />
<field name="inherit_id" ref="mrp.view_mrp_config" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='module_mrp_repair']/.." position="after"> <div id="mrp_reception_report" position="after">
<div> <div class="col-12 col-lg-6 o_setting_box" id="mrp_bom_version">
<field name="group_mrp_bom_version" class="oe_inline" /> <div class="o_setting_left_pane">
<field name="group_mrp_bom_version" />
</div>
<div class="o_setting_right_pane">
<label for="group_mrp_bom_version" /> <label for="group_mrp_bom_version" />
<div class="text-muted">
Allow to re-edit BoMs
</div> </div>
<div attrs="{'invisible': [('group_mrp_bom_version', '=', False)]}"> <div
<field name="active_draft" class="oe_inline" /> class="row mt-2"
attrs="{'invisible': [('group_mrp_bom_version','=',False)]}"
>
<field
name="active_draft"
class="col flex-grow-0 ml16 mr0 pe-2"
/>
<div class="col ps-0">
<label for="active_draft" /> <label for="active_draft" />
<div class="text-muted">
Keep re-editing BoM active
</div>
</div>
</div>
</div>
</div>
</div> </div>
</xpath>
</field> </field>
</record> </record>
</data> </odoo>
</openerp>

View File

@@ -0,0 +1 @@
../../../../mrp_bom_version

View File

@@ -1 +0,0 @@
__import__('pkg_resources').declare_namespace(__name__)

View File

@@ -1 +0,0 @@
../../../mrp_bom_version